From b96d23ec698fdc1fdf904e5547d9abb6354eef5c Mon Sep 17 00:00:00 2001 From: Michal Malý Date: Wed, 18 Feb 2015 17:59:21 +0100 Subject: HID: hid-lg4ff: Export the real wheel model and supported alternate modes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Display the real wheel model and supported alternate modes through sysfs. This applies only to multimode wheels. Signed-off-by: Michal Malý Tested-by: Simon Wood Signed-off-by: Jiri Kosina --- .../ABI/testing/sysfs-driver-hid-logitech-lg4ff | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff b/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff index 167d9032b970..60f24a1d8119 100644 --- a/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff +++ b/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff @@ -5,3 +5,23 @@ Contact: Michal Malý Description: Display minimum, maximum and current range of the steering wheel. Writing a value within min and max boundaries sets the range of the wheel. + +What: /sys/bus/hid/drivers/logitech//alternate_modes +Date: Feb 2015 +KernelVersion: 4.1 +Contact: Michal Malý +Description: Displays a set of alternate modes supported by a wheel. Each + mode is listed as follows: + Tag: Mode Name + Currently active mode is marked with an asterisk. List also + contains an abstract item "native" which always denotes the + native mode of the wheel. + +What: /sys/bus/hid/drivers/logitech//real_id +Date: Feb 2015 +KernelVersion: 4.1 +Contact: Michal Malý +Description: Displays the real model of the wheel regardless of any + alternate mode the wheel might be switched to. + It is a read-only value. + This entry is not created for devices that have only one mode. -- cgit v1.2.3-59-g8ed1b From f31a2de3fe3680223a0dc93e484c491cc09473d3 Mon Sep 17 00:00:00 2001 From: Michal Malý Date: Wed, 18 Feb 2015 17:59:23 +0100 Subject: HID: hid-lg4ff: Allow switching of Logitech gaming wheels between compatibility modes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow switching of Logitech gaming wheels between available compatibility modes through sysfs. This only applies to multimode wheels. Signed-off-by: Michal Malý Tested-by: Simon Wood Signed-off-by: Jiri Kosina --- .../ABI/testing/sysfs-driver-hid-logitech-lg4ff | 27 ++- drivers/hid/hid-lg4ff.c | 204 ++++++++++++++++++--- 2 files changed, 201 insertions(+), 30 deletions(-) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff b/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff index 60f24a1d8119..b3f6a2ac5007 100644 --- a/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff +++ b/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff @@ -15,7 +15,32 @@ Description: Displays a set of alternate modes supported by a wheel. Each Tag: Mode Name Currently active mode is marked with an asterisk. List also contains an abstract item "native" which always denotes the - native mode of the wheel. + native mode of the wheel. Echoing the mode tag switches the + wheel into the corresponding mode. Depending on the exact model + of the wheel not all listed modes might always be selectable. + If a wheel cannot be switched into the desired mode, -EINVAL + is returned accompanied with an explanatory message in the + kernel log. + This entry is not created for devices that have only one mode. + + Currently supported mode switches: + Driving Force Pro: + DF-EX --> DFP + + G25: + DF-EX --> DFP --> G25 + + G27: + DF-EX <*> DFP <-> G25 <-> G27 + DF-EX <*--------> G25 <-> G27 + DF-EX <*----------------> G27 + + DFGT: + DF-EX <*> DFP <-> DFGT + DF-EX <*--------> DFGT + + * hid_logitech module must be loaded with lg4ff_no_autoswitch=1 + parameter set in order for the switch to DF-EX mode to work. What: /sys/bus/hid/drivers/logitech//real_id Date: Feb 2015 diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c index dd307724965f..854982be3194 100644 --- a/drivers/hid/hid-lg4ff.c +++ b/drivers/hid/hid-lg4ff.c @@ -201,26 +201,47 @@ static const struct lg4ff_wheel_ident_checklist lg4ff_main_checklist = { }; /* Compatibility mode switching commands */ -static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_dfp = { - 1, - {0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00} +/* EXT_CMD9 - Understood by G27 and DFGT */ +static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext09_dfex = { + 2, + {0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, /* Revert mode upon USB reset */ + 0xf8, 0x09, 0x00, 0x01, 0x00, 0x00, 0x00} /* Switch mode to DF-EX with detach */ }; -static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_dfgt = { +static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext09_dfp = { 2, - {0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1st command */ - 0xf8, 0x09, 0x03, 0x01, 0x00, 0x00, 0x00} /* 2nd command */ + {0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, /* Revert mode upon USB reset */ + 0xf8, 0x09, 0x01, 0x01, 0x00, 0x00, 0x00} /* Switch mode to DFP with detach */ }; -static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_g25 = { - 1, - {0xf8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00} +static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext09_g25 = { + 2, + {0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, /* Revert mode upon USB reset */ + 0xf8, 0x09, 0x02, 0x01, 0x00, 0x00, 0x00} /* Switch mode to G25 with detach */ }; -static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_g27 = { +static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext09_dfgt = { 2, - {0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1st command */ - 0xf8, 0x09, 0x04, 0x01, 0x00, 0x00, 0x00} /* 2nd command */ + {0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, /* Revert mode upon USB reset */ + 0xf8, 0x09, 0x03, 0x01, 0x00, 0x00, 0x00} /* Switch mode to DFGT with detach */ +}; + +static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext09_g27 = { + 2, + {0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, /* Revert mode upon USB reset */ + 0xf8, 0x09, 0x04, 0x01, 0x00, 0x00, 0x00} /* Switch mode to G27 with detach */ +}; + +/* EXT_CMD1 - Understood by DFP, G25, G27 and DFGT */ +static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext01_dfp = { + 1, + {0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00} +}; + +/* EXT_CMD16 - Understood by G25 and G27 */ +static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext16_g25 = { + 1, + {0xf8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00} }; /* Recalculates X axis value accordingly to currently selected range */ @@ -489,6 +510,63 @@ static void hid_lg4ff_set_range_dfp(struct hid_device *hid, __u16 range) hid_hw_request(hid, report, HID_REQ_SET_REPORT); } +static const struct lg4ff_compat_mode_switch *lg4ff_get_mode_switch_command(const u16 real_product_id, const u16 target_product_id) +{ + switch (real_product_id) { + case USB_DEVICE_ID_LOGITECH_DFP_WHEEL: + switch (target_product_id) { + case USB_DEVICE_ID_LOGITECH_DFP_WHEEL: + return &lg4ff_mode_switch_ext01_dfp; + /* DFP can only be switched to its native mode */ + default: + return NULL; + } + break; + case USB_DEVICE_ID_LOGITECH_G25_WHEEL: + switch (target_product_id) { + case USB_DEVICE_ID_LOGITECH_DFP_WHEEL: + return &lg4ff_mode_switch_ext01_dfp; + case USB_DEVICE_ID_LOGITECH_G25_WHEEL: + return &lg4ff_mode_switch_ext16_g25; + /* G25 can only be switched to DFP mode or its native mode */ + default: + return NULL; + } + break; + case USB_DEVICE_ID_LOGITECH_G27_WHEEL: + switch (target_product_id) { + case USB_DEVICE_ID_LOGITECH_WHEEL: + return &lg4ff_mode_switch_ext09_dfex; + case USB_DEVICE_ID_LOGITECH_DFP_WHEEL: + return &lg4ff_mode_switch_ext09_dfp; + case USB_DEVICE_ID_LOGITECH_G25_WHEEL: + return &lg4ff_mode_switch_ext09_g25; + case USB_DEVICE_ID_LOGITECH_G27_WHEEL: + return &lg4ff_mode_switch_ext09_g27; + /* G27 can only be switched to DF-EX, DFP, G25 or its native mode */ + default: + return NULL; + } + break; + case USB_DEVICE_ID_LOGITECH_DFGT_WHEEL: + switch (target_product_id) { + case USB_DEVICE_ID_LOGITECH_WHEEL: + return &lg4ff_mode_switch_ext09_dfex; + case USB_DEVICE_ID_LOGITECH_DFP_WHEEL: + return &lg4ff_mode_switch_ext09_dfp; + case USB_DEVICE_ID_LOGITECH_DFGT_WHEEL: + return &lg4ff_mode_switch_ext09_dfgt; + /* DFGT can only be switched to DF-EX, DFP or its native mode */ + default: + return NULL; + } + break; + /* No other wheels have multiple modes */ + default: + return NULL; + } +} + static int lg4ff_switch_compatibility_mode(struct hid_device *hid, const struct lg4ff_compat_mode_switch *s) { struct usb_device *usbdev = hid_to_usb_dev(hid); @@ -558,7 +636,87 @@ static ssize_t lg4ff_alternate_modes_show(struct device *dev, struct device_attr static ssize_t lg4ff_alternate_modes_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - return -ENOSYS; + struct hid_device *hid = to_hid_device(dev); + struct lg4ff_device_entry *entry; + struct lg_drv_data *drv_data; + const struct lg4ff_compat_mode_switch *s; + u16 target_product_id = 0; + int i, ret; + char *lbuf; + + drv_data = hid_get_drvdata(hid); + if (!drv_data) { + hid_err(hid, "Private driver data not found!\n"); + return -EINVAL; + } + + entry = drv_data->device_props; + if (!entry) { + hid_err(hid, "Device properties not found!\n"); + return -EINVAL; + } + + /* Allow \n at the end of the input parameter */ + lbuf = kasprintf(GFP_KERNEL, "%s", buf); + if (!lbuf) + return -ENOMEM; + + i = strlen(lbuf); + if (lbuf[i-1] == '\n') { + if (i == 1) { + kfree(lbuf); + return -EINVAL; + } + lbuf[i-1] = '\0'; + } + + for (i = 0; i < LG4FF_MODE_MAX_IDX; i++) { + const u16 mode_product_id = lg4ff_alternate_modes[i].product_id; + const char *tag = lg4ff_alternate_modes[i].tag; + + if (entry->alternate_modes & BIT(i)) { + if (!strcmp(tag, lbuf)) { + if (!mode_product_id) + target_product_id = entry->real_product_id; + else + target_product_id = mode_product_id; + break; + } + } + } + + if (i == LG4FF_MODE_MAX_IDX) { + hid_info(hid, "Requested mode \"%s\" is not supported by the device\n", lbuf); + kfree(lbuf); + return -EINVAL; + } + kfree(lbuf); /* Not needed anymore */ + + if (target_product_id == entry->product_id) /* Nothing to do */ + return count; + + /* Automatic switching has to be disabled for the switch to DF-EX mode to work correctly */ + if (target_product_id == USB_DEVICE_ID_LOGITECH_WHEEL && !lg4ff_no_autoswitch) { + hid_info(hid, "\"%s\" cannot be switched to \"DF-EX\" mode. Load the \"hid_logitech\" module with \"lg4ff_no_autoswitch=1\" parameter set and try again\n", + entry->real_name); + return -EINVAL; + } + + /* Take care of hardware limitations */ + if ((entry->real_product_id == USB_DEVICE_ID_LOGITECH_DFP_WHEEL || entry->real_product_id == USB_DEVICE_ID_LOGITECH_G25_WHEEL) && + entry->product_id > target_product_id) { + hid_info(hid, "\"%s\" cannot be switched back into \"%s\" mode\n", entry->real_name, lg4ff_alternate_modes[i].name); + return -EINVAL; + } + + s = lg4ff_get_mode_switch_command(entry->real_product_id, target_product_id); + if (!s) { + hid_err(hid, "Invalid target product ID %X\n", target_product_id); + return -EINVAL; + } + + ret = lg4ff_switch_compatibility_mode(hid, s); + return (ret == 0 ? count : ret); } static DEVICE_ATTR(alternate_modes, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, lg4ff_alternate_modes_show, lg4ff_alternate_modes_store); @@ -783,7 +941,8 @@ static u16 lg4ff_identify_multimode_wheel(struct hid_device *hid, const u16 repo } } - /* No match found. This is an unknown wheel model, do not touch it */ + /* No match found. This is either Driving Force or an unknown + * wheel model, do not touch it */ dbg_hid("Wheel with bcdDevice %X was not recognized as multimode wheel, leaving in its current mode\n", bcdDevice); return 0; } @@ -806,22 +965,9 @@ static int lg4ff_handle_multimode_wheel(struct hid_device *hid, u16 *real_produc if (reported_product_id == USB_DEVICE_ID_LOGITECH_WHEEL && reported_product_id != *real_product_id && !lg4ff_no_autoswitch) { - const struct lg4ff_compat_mode_switch *s; + const struct lg4ff_compat_mode_switch *s = lg4ff_get_mode_switch_command(*real_product_id, *real_product_id); - switch (*real_product_id) { - case USB_DEVICE_ID_LOGITECH_DFP_WHEEL: - s = &lg4ff_mode_switch_dfp; - break; - case USB_DEVICE_ID_LOGITECH_G25_WHEEL: - s = &lg4ff_mode_switch_g25; - break; - case USB_DEVICE_ID_LOGITECH_G27_WHEEL: - s = &lg4ff_mode_switch_g27; - break; - case USB_DEVICE_ID_LOGITECH_DFGT_WHEEL: - s = &lg4ff_mode_switch_dfgt; - break; - default: + if (!s) { hid_err(hid, "Invalid product id %X\n", *real_product_id); return LG4FF_MMODE_NOT_MULTIMODE; } -- cgit v1.2.3-59-g8ed1b From 0eac092d8307db61d320f77f9fce40e60b4ffa89 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Tue, 20 Jan 2015 17:40:43 +0100 Subject: Documentation/acpi/einj: Correct and streamline text Streamline and simplify formulations, improve formatting and extend the injection example in the error injection write up for users which we carry in Documentation/. Add a paragraph about checking for EINJ support and expand the ACPI5.0 memory errors section, as requested by Tony. Acked-by: Tony Luck Link: http://lkml.kernel.org/r/1422553845-30717-1-git-send-email-bp@alien8.de Signed-off-by: Borislav Petkov --- Documentation/acpi/apei/einj.txt | 196 ++++++++++++++++++++++++--------------- 1 file changed, 122 insertions(+), 74 deletions(-) (limited to 'Documentation') diff --git a/Documentation/acpi/apei/einj.txt b/Documentation/acpi/apei/einj.txt index f51861bcb07b..e550c8b98139 100644 --- a/Documentation/acpi/apei/einj.txt +++ b/Documentation/acpi/apei/einj.txt @@ -1,129 +1,177 @@ APEI Error INJection ~~~~~~~~~~~~~~~~~~~~ -EINJ provides a hardware error injection mechanism -It is very useful for debugging and testing of other APEI and RAS features. +EINJ provides a hardware error injection mechanism. It is very useful +for debugging and testing APEI and RAS features in general. -To use EINJ, make sure the following are enabled in your kernel +You need to check whether your BIOS supports EINJ first. For that, look +for early boot messages similar to this one: + +ACPI: EINJ 0x000000007370A000 000150 (v01 INTEL 00000001 INTL 00000001) + +which shows that the BIOS is exposing an EINJ table - it is the +mechanism through which the injection is done. + +Alternatively, look in /sys/firmware/acpi/tables for an "EINJ" file, +which is a different representation of the same thing. + +It doesn't necessarily mean that EINJ is not supported if those above +don't exist: before you give up, go into BIOS setup to see if the BIOS +has an option to enable error injection. Look for something called WHEA +or similar. Often, you need to enable an ACPI5 support option prior, in +order to see the APEI,EINJ,... functionality supported and exposed by +the BIOS menu. + +To use EINJ, make sure the following are options enabled in your kernel configuration: CONFIG_DEBUG_FS CONFIG_ACPI_APEI CONFIG_ACPI_APEI_EINJ -The user interface of EINJ is debug file system, under the -directory apei/einj. The following files are provided. +The EINJ user interface is in /apei/einj. + +The following files belong to it: - available_error_type - Reading this file returns the error injection capability of the - platform, that is, which error types are supported. The error type - definition is as follow, the left field is the error type value, the - right field is error description. - - 0x00000001 Processor Correctable - 0x00000002 Processor Uncorrectable non-fatal - 0x00000004 Processor Uncorrectable fatal - 0x00000008 Memory Correctable - 0x00000010 Memory Uncorrectable non-fatal - 0x00000020 Memory Uncorrectable fatal - 0x00000040 PCI Express Correctable - 0x00000080 PCI Express Uncorrectable fatal - 0x00000100 PCI Express Uncorrectable non-fatal - 0x00000200 Platform Correctable - 0x00000400 Platform Uncorrectable non-fatal - 0x00000800 Platform Uncorrectable fatal - - The format of file contents are as above, except there are only the - available error type lines. + + This file shows which error types are supported: + + Error Type Value Error Description + ================ ================= + 0x00000001 Processor Correctable + 0x00000002 Processor Uncorrectable non-fatal + 0x00000004 Processor Uncorrectable fatal + 0x00000008 Memory Correctable + 0x00000010 Memory Uncorrectable non-fatal + 0x00000020 Memory Uncorrectable fatal + 0x00000040 PCI Express Correctable + 0x00000080 PCI Express Uncorrectable fatal + 0x00000100 PCI Express Uncorrectable non-fatal + 0x00000200 Platform Correctable + 0x00000400 Platform Uncorrectable non-fatal + 0x00000800 Platform Uncorrectable fatal + + The format of the file contents are as above, except present are only + the available error types. - error_type - This file is used to set the error type value. The error type value - is defined in "available_error_type" description. + + Set the value of the error type being injected. Possible error types + are defined in the file available_error_type above. - error_inject - Write any integer to this file to trigger the error - injection. Before this, please specify all necessary error - parameters. + + Write any integer to this file to trigger the error injection. Make + sure you have specified all necessary error parameters, i.e. this + write should be the last step when injecting errors. - flags - Present for kernel version 3.13 and above. Used to specify which - of param{1..4} are valid and should be used by BIOS during injection. - Value is a bitmask as specified in ACPI5.0 spec for the + + Present for kernel versions 3.13 and above. Used to specify which + of param{1..4} are valid and should be used by the firmware during + injection. Value is a bitmask as specified in ACPI5.0 spec for the SET_ERROR_TYPE_WITH_ADDRESS data structure: - Bit 0 - Processor APIC field valid (see param3 below) - Bit 1 - Memory address and mask valid (param1 and param2) - Bit 2 - PCIe (seg,bus,dev,fn) valid (param4 below) - If set to zero, legacy behaviour is used where the type of injection - specifies just one bit set, and param1 is multiplexed. + + Bit 0 - Processor APIC field valid (see param3 below). + Bit 1 - Memory address and mask valid (param1 and param2). + Bit 2 - PCIe (seg,bus,dev,fn) valid (see param4 below). + + If set to zero, legacy behavior is mimicked where the type of + injection specifies just one bit set, and param1 is multiplexed. - param1 - This file is used to set the first error parameter value. Effect of - parameter depends on error_type specified. For example, if error - type is memory related type, the param1 should be a valid physical - memory address. [Unless "flag" is set - see above] + + This file is used to set the first error parameter value. Its effect + depends on the error type specified in error_type. For example, if + error type is memory related type, the param1 should be a valid + physical memory address. [Unless "flag" is set - see above] - param2 - This file is used to set the second error parameter value. Effect of - parameter depends on error_type specified. For example, if error - type is memory related type, the param2 should be a physical memory - address mask. Linux requires page or narrower granularity, say, - 0xfffffffffffff000. + + Same use as param1 above. For example, if error type is of memory + related type, then param2 should be a physical memory address mask. + Linux requires page or narrower granularity, say, 0xfffffffffffff000. - param3 - Used when the 0x1 bit is set in "flag" to specify the APIC id + + Used when the 0x1 bit is set in "flags" to specify the APIC id - param4 - Used when the 0x4 bit is set in "flag" to specify target PCIe device + Used when the 0x4 bit is set in "flags" to specify target PCIe device - notrigger - The EINJ mechanism is a two step process. First inject the error, then - perform some actions to trigger it. Setting "notrigger" to 1 skips the - trigger phase, which *may* allow the user to cause the error in some other - context by a simple access to the cpu, memory location, or device that is - the target of the error injection. Whether this actually works depends - on what operations the BIOS actually includes in the trigger phase. - -BIOS versions based in the ACPI 4.0 specification have limited options -to control where the errors are injected. Your BIOS may support an -extension (enabled with the param_extension=1 module parameter, or -boot command line einj.param_extension=1). This allows the address -and mask for memory injections to be specified by the param1 and -param2 files in apei/einj. - -BIOS versions using the ACPI 5.0 specification have more control over -the target of the injection. For processor related errors (type 0x1, -0x2 and 0x4) the APICID of the target should be provided using the -param1 file in apei/einj. For memory errors (type 0x8, 0x10 and 0x20) -the address is set using param1 with a mask in param2 (0x0 is equivalent -to all ones). For PCI express errors (type 0x40, 0x80 and 0x100) the -segment, bus, device and function are specified using param1: + + The error injection mechanism is a two-step process. First inject the + error, then perform some actions to trigger it. Setting "notrigger" + to 1 skips the trigger phase, which *may* allow the user to cause the + error in some other context by a simple access to the CPU, memory + location, or device that is the target of the error injection. Whether + this actually works depends on what operations the BIOS actually + includes in the trigger phase. + +BIOS versions based on the ACPI 4.0 specification have limited options +in controlling where the errors are injected. Your BIOS may support an +extension (enabled with the param_extension=1 module parameter, or boot +command line einj.param_extension=1). This allows the address and mask +for memory injections to be specified by the param1 and param2 files in +apei/einj. + +BIOS versions based on the ACPI 5.0 specification have more control over +the target of the injection. For processor-related errors (type 0x1, 0x2 +and 0x4), you can set flags to 0x3 (param3 for bit 0, and param1 and +param2 for bit 1) so that you have more information added to the error +signature being injected. The actual data passed is this: + + memory_address = param1; + memory_address_range = param2; + apicid = param3; + pcie_sbdf = param4; + +For memory errors (type 0x8, 0x10 and 0x20) the address is set using +param1 with a mask in param2 (0x0 is equivalent to all ones). For PCI +express errors (type 0x40, 0x80 and 0x100) the segment, bus, device and +function are specified using param1: 31 24 23 16 15 11 10 8 7 0 +-------------------------------------------------+ | segment | bus | device | function | reserved | +-------------------------------------------------+ -An ACPI 5.0 BIOS may also allow vendor specific errors to be injected. +Anyway, you get the idea, if there's doubt just take a look at the code +in drivers/acpi/apei/einj.c. + +An ACPI 5.0 BIOS may also allow vendor-specific errors to be injected. In this case a file named vendor will contain identifying information from the BIOS that hopefully will allow an application wishing to use -the vendor specific extension to tell that they are running on a BIOS +the vendor-specific extension to tell that they are running on a BIOS that supports it. All vendor extensions have the 0x80000000 bit set in error_type. A file vendor_flags controls the interpretation of param1 and param2 (1 = PROCESSOR, 2 = MEMORY, 4 = PCI). See your BIOS vendor documentation for details (and expect changes to this API if vendors creativity in using this feature expands beyond our expectations). -Example: + +An error injection example: + # cd /sys/kernel/debug/apei/einj # cat available_error_type # See which errors can be injected 0x00000002 Processor Uncorrectable non-fatal 0x00000008 Memory Correctable 0x00000010 Memory Uncorrectable non-fatal # echo 0x12345000 > param1 # Set memory address for injection -# echo 0xfffffffffffff000 > param2 # Mask - anywhere in this page +# echo $((-1 << 12)) > param2 # Mask 0xfffffffffffff000 - anywhere in this page # echo 0x8 > error_type # Choose correctable memory error # echo 1 > error_inject # Inject now +You should see something like this in dmesg: + +[22715.830801] EDAC sbridge MC3: HANDLING MCE MEMORY ERROR +[22715.834759] EDAC sbridge MC3: CPU 0: Machine Check Event: 0 Bank 7: 8c00004000010090 +[22715.834759] EDAC sbridge MC3: TSC 0 +[22715.834759] EDAC sbridge MC3: ADDR 12345000 EDAC sbridge MC3: MISC 144780c86 +[22715.834759] EDAC sbridge MC3: PROCESSOR 0:306e7 TIME 1422553404 SOCKET 0 APIC 0 +[22716.616173] EDAC MC3: 1 CE memory read error on CPU_SrcID#0_Channel#0_DIMM#0 (channel:0 slot:0 page:0x12345 offset:0x0 grain:32 syndrome:0x0 - area:DRAM err_code:0001:0090 socket:0 channel_mask:1 rank:0) For more information about EINJ, please refer to ACPI specification version 4.0, section 17.5 and ACPI 5.0, section 18.6. -- cgit v1.2.3-59-g8ed1b From 229d043096ea8e58829d37d35767afeac15997f5 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 13 Feb 2015 15:14:03 -0600 Subject: ALSA: core: selection of audio_tstamp type and accuracy reports Audio timestamps can be extracted from sample counters, wall clocks, PHC clocks (Ethernet AVB), on-demand synchronized snapshots. This patch provides the ability to report timestamping capabilities, select timestamp types and retrieve timestamp accuracy, if supported. Details can be found in Documentations/sound/alsa/timestamping.txt This functionality is introduced by reclaiming the reserved_aligned field introduced by commit9c7066aef4a5eb8e4063de28f06c508bf6f2963a in snd_pcm_status to provide userspace with selection/query capabilities. Additional driver_tstamp and audio_tstamp_accuracy fields are also added. snd_pcm_mmap_status remains a read-only structure with only the audio timestamp value accessible from user space. The selection of audio timestamp type is done through snd_pcm_status only This commit does not impact ABI and does not impact the default behavior. By default audio timestamp is aligned with hw_pointer and reports the DMA position. Backwards compatibility is handled by using the HDAudio wall clock for playback and the hw_ptr for all other cases. For timestamp selection a new STATUS_EXT ioctl is introduced with read/write parameters. Alsa-lib will be modified to make use of STATUS_EXT. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/timestamping.txt | 200 ++++++++++++++++++++++++++++++ include/sound/pcm.h | 60 +++++++++ include/uapi/sound/asound.h | 34 ++++- 3 files changed, 290 insertions(+), 4 deletions(-) create mode 100644 Documentation/sound/alsa/timestamping.txt (limited to 'Documentation') diff --git a/Documentation/sound/alsa/timestamping.txt b/Documentation/sound/alsa/timestamping.txt new file mode 100644 index 000000000000..0b191a23f534 --- /dev/null +++ b/Documentation/sound/alsa/timestamping.txt @@ -0,0 +1,200 @@ +The ALSA API can provide two different system timestamps: + +- Trigger_tstamp is the system time snapshot taken when the .trigger +callback is invoked. This snapshot is taken by the ALSA core in the +general case, but specific hardware may have synchronization +capabilities or conversely may only be able to provide a correct +estimate with a delay. In the latter two cases, the low-level driver +is responsible for updating the trigger_tstamp at the most appropriate +and precise moment. Applications should not rely solely on the first +trigger_tstamp but update their internal calculations if the driver +provides a refined estimate with a delay. + +- tstamp is the current system timestamp updated during the last +event or application query. +The difference (tstamp - trigger_tstamp) defines the elapsed time. + +The ALSA API provides reports two basic pieces of information, avail +and delay, which combined with the trigger and current system +timestamps allow for applications to keep track of the 'fullness' of +the ring buffer and the amount of queued samples. + +The use of these different pointers and time information depends on +the application needs: + +- 'avail' reports how much can be written in the ring buffer +- 'delay' reports the time it will take to hear a new sample after all +queued samples have been played out. + +When timestamps are enabled, the avail/delay information is reported +along with a snapshot of system time. Applications can select from +CLOCK_REALTIME (NTP corrections including going backwards), +CLOCK_MONOTONIC (NTP corrections but never going backwards), +CLOCK_MONOTIC_RAW (without NTP corrections) and change the mode +dynamically with sw_params + + +The ALSA API also provide an audio_tstamp which reflects the passage +of time as measured by different components of audio hardware. In +ascii-art, this could be represented as follows (for the playback +case): + + +--------------------------------------------------------------> time + ^ ^ ^ ^ ^ + | | | | | + analog link dma app FullBuffer + time time time time time + | | | | | + |< codec delay >|<--hw delay-->||<---avail->| + |<----------------- delay---------------------->| | + |<----ring buffer length---->| + +The analog time is taken at the last stage of the playback, as close +as possible to the actual transducer + +The link time is taken at the output of the SOC/chipset as the samples +are pushed on a link. The link time can be directly measured if +supported in hardware by sample counters or wallclocks (e.g. with +HDAudio 24MHz or PTP clock for networked solutions) or indirectly +estimated (e.g. with the frame counter in USB). + +The DMA time is measured using counters - typically the least reliable +of all measurements due to the bursty natured of DMA transfers. + +The app time corresponds to the time tracked by an application after +writing in the ring buffer. + +The application can query what the hardware supports, define which +audio time it wants reported by selecting the relevant settings in +audio_tstamp_config fields, get an estimate of the timestamp +accuracy. It can also request the delay-to-analog be included in the +measurement. Direct access to the link time is very interesting on +platforms that provide an embedded DSP; measuring directly the link +time with dedicated hardware, possibly synchronized with system time, +removes the need to keep track of internal DSP processing times and +latency. + +In case the application requests an audio tstamp that is not supported +in hardware/low-level driver, the type is overridden as DEFAULT and the +timestamp will report the DMA time based on the hw_pointer value. + +For backwards compatibility with previous implementations that did not +provide timestamp selection, with a zero-valued COMPAT timestamp type +the results will default to the HDAudio wall clock for playback +streams and to the DMA time (hw_ptr) in all other cases. + +The audio timestamp accuracy can be returned to user-space, so that +appropriate decisions are made: + +- for dma time (default), the granularity of the transfers can be + inferred from the steps between updates and in turn provide + information on how much the application pointer can be rewound + safely. + +- the link time can be used to track long-term drifts between audio + and system time using the (tstamp-trigger_tstamp)/audio_tstamp + ratio, the precision helps define how much smoothing/low-pass + filtering is required. The link time can be either reset on startup + or reported as is (the latter being useful to compare progress of + different streams - but may require the wallclock to be always + running and not wrap-around during idle periods). If supported in + hardware, the absolute link time could also be used to define a + precise start time (patches WIP) + +- including the delay in the audio timestamp may + counter-intuitively not increase the precision of timestamps, e.g. if a + codec includes variable-latency DSP processing or a chain of + hardware components the delay is typically not known with precision. + +The accuracy is reported in nanosecond units (using an unsigned 32-bit +word), which gives a max precision of 4.29s, more than enough for +audio applications... + +Due to the varied nature of timestamping needs, even for a single +application, the audio_tstamp_config can be changed dynamically. In +the STATUS ioctl, the parameters are read-only and do not allow for +any application selection. To work around this limitation without +impacting legacy applications, a new STATUS_EXT ioctl is introduced +with read/write parameters. ALSA-lib will be modified to make use of +STATUS_EXT and effectively deprecate STATUS. + +The ALSA API only allows for a single audio timestamp to be reported +at a time. This is a conscious design decision, reading the audio +timestamps from hardware registers or from IPC takes time, the more +timestamps are read the more imprecise the combined measurements +are. To avoid any interpretation issues, a single (system, audio) +timestamp is reported. Applications that need different timestamps +will be required to issue multiple queries and perform an +interpolation of the results + +In some hardware-specific configuration, the system timestamp is +latched by a low-level audio subsytem, and the information provided +back to the driver. Due to potential delays in the communication with +the hardware, there is a risk of misalignment with the avail and delay +information. To make sure applications are not confused, a +driver_timestamp field is added in the snd_pcm_status structure; this +timestamp shows when the information is put together by the driver +before returning from the STATUS and STATUS_EXT ioctl. in most cases +this driver_timestamp will be identical to the regular system tstamp. + +Examples of typestamping with HDaudio: + +1. DMA timestamp, no compensation for DMA+analog delay +$ ./audio_time -p --ts_type=1 +playback: systime: 341121338 nsec, audio time 342000000 nsec, systime delta -878662 +playback: systime: 426236663 nsec, audio time 427187500 nsec, systime delta -950837 +playback: systime: 597080580 nsec, audio time 598000000 nsec, systime delta -919420 +playback: systime: 682059782 nsec, audio time 683020833 nsec, systime delta -961051 +playback: systime: 852896415 nsec, audio time 853854166 nsec, systime delta -957751 +playback: systime: 937903344 nsec, audio time 938854166 nsec, systime delta -950822 + +2. DMA timestamp, compensation for DMA+analog delay +$ ./audio_time -p --ts_type=1 -d +playback: systime: 341053347 nsec, audio time 341062500 nsec, systime delta -9153 +playback: systime: 426072447 nsec, audio time 426062500 nsec, systime delta 9947 +playback: systime: 596899518 nsec, audio time 596895833 nsec, systime delta 3685 +playback: systime: 681915317 nsec, audio time 681916666 nsec, systime delta -1349 +playback: systime: 852741306 nsec, audio time 852750000 nsec, systime delta -8694 + +3. link timestamp, compensation for DMA+analog delay +$ ./audio_time -p --ts_type=2 -d +playback: systime: 341060004 nsec, audio time 341062791 nsec, systime delta -2787 +playback: systime: 426242074 nsec, audio time 426244875 nsec, systime delta -2801 +playback: systime: 597080992 nsec, audio time 597084583 nsec, systime delta -3591 +playback: systime: 682084512 nsec, audio time 682088291 nsec, systime delta -3779 +playback: systime: 852936229 nsec, audio time 852940916 nsec, systime delta -4687 +playback: systime: 938107562 nsec, audio time 938112708 nsec, systime delta -5146 + +Example 1 shows that the timestamp at the DMA level is close to 1ms +ahead of the actual playback time (as a side time this sort of +measurement can help define rewind safeguards). Compensating for the +DMA-link delay in example 2 helps remove the hardware buffering abut +the information is still very jittery, with up to one sample of +error. In example 3 where the timestamps are measured with the link +wallclock, the timestamps show a monotonic behavior and a lower +dispersion. + +Example 3 and 4 are with USB audio class. Example 3 shows a high +offset between audio time and system time due to buffering. Example 4 +shows how compensating for the delay exposes a 1ms accuracy (due to +the use of the frame counter by the driver) + +Example 3: DMA timestamp, no compensation for delay, delta of ~5ms +$ ./audio_time -p -Dhw:1 -t1 +playback: systime: 120174019 nsec, audio time 125000000 nsec, systime delta -4825981 +playback: systime: 245041136 nsec, audio time 250000000 nsec, systime delta -4958864 +playback: systime: 370106088 nsec, audio time 375000000 nsec, systime delta -4893912 +playback: systime: 495040065 nsec, audio time 500000000 nsec, systime delta -4959935 +playback: systime: 620038179 nsec, audio time 625000000 nsec, systime delta -4961821 +playback: systime: 745087741 nsec, audio time 750000000 nsec, systime delta -4912259 +playback: systime: 870037336 nsec, audio time 875000000 nsec, systime delta -4962664 + +Example 4: DMA timestamp, compensation for delay, delay of ~1ms +$ ./audio_time -p -Dhw:1 -t1 -d +playback: systime: 120190520 nsec, audio time 120000000 nsec, systime delta 190520 +playback: systime: 245036740 nsec, audio time 244000000 nsec, systime delta 1036740 +playback: systime: 370034081 nsec, audio time 369000000 nsec, systime delta 1034081 +playback: systime: 495159907 nsec, audio time 494000000 nsec, systime delta 1159907 +playback: systime: 620098824 nsec, audio time 619000000 nsec, systime delta 1098824 +playback: systime: 745031847 nsec, audio time 744000000 nsec, systime delta 1031847 diff --git a/include/sound/pcm.h b/include/sound/pcm.h index c0ddb7e69c28..60f0e48f7905 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -60,6 +60,9 @@ struct snd_pcm_hardware { struct snd_pcm_substream; +struct snd_pcm_audio_tstamp_config; /* definitions further down */ +struct snd_pcm_audio_tstamp_report; + struct snd_pcm_ops { int (*open)(struct snd_pcm_substream *substream); int (*close)(struct snd_pcm_substream *substream); @@ -281,6 +284,58 @@ struct snd_pcm_hw_constraint_ranges { struct snd_pcm_hwptr_log; +/* + * userspace-provided audio timestamp config to kernel, + * structure is for internal use only and filled with dedicated unpack routine + */ +struct snd_pcm_audio_tstamp_config { + /* 5 of max 16 bits used */ + u32 type_requested:4; + u32 report_delay:1; /* add total delay to A/D or D/A */ +}; + +static inline void snd_pcm_unpack_audio_tstamp_config(__u32 data, + struct snd_pcm_audio_tstamp_config *config) +{ + config->type_requested = data & 0xF; + config->report_delay = (data >> 4) & 1; +} + +/* + * kernel-provided audio timestamp report to user-space + * structure is for internal use only and read by dedicated pack routine + */ +struct snd_pcm_audio_tstamp_report { + /* 6 of max 16 bits used for bit-fields */ + + /* for backwards compatibility */ + u32 valid:1; + + /* actual type if hardware could not support requested timestamp */ + u32 actual_type:4; + + /* accuracy represented in ns units */ + u32 accuracy_report:1; /* 0 if accuracy unknown, 1 if accuracy field is valid */ + u32 accuracy; /* up to 4.29s, will be packed in separate field */ +}; + +static inline void snd_pcm_pack_audio_tstamp_report(__u32 *data, __u32 *accuracy, + const struct snd_pcm_audio_tstamp_report *report) +{ + u32 tmp; + + tmp = report->accuracy_report; + tmp <<= 4; + tmp |= report->actual_type; + tmp <<= 1; + tmp |= report->valid; + + *data &= 0xffff; /* zero-clear MSBs */ + *data |= (tmp << 16); + *accuracy = report->accuracy; +} + + struct snd_pcm_runtime { /* -- Status -- */ struct snd_pcm_substream *trigger_master; @@ -361,6 +416,11 @@ struct snd_pcm_runtime { struct snd_dma_buffer *dma_buffer_p; /* allocated buffer */ + /* -- audio timestamp config -- */ + struct snd_pcm_audio_tstamp_config audio_tstamp_config; + struct snd_pcm_audio_tstamp_report audio_tstamp_report; + struct timespec driver_tstamp; + #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) /* -- OSS things -- */ struct snd_pcm_oss_runtime oss; diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h index 0e88e7a0f0eb..acef4e4d2735 100644 --- a/include/uapi/sound/asound.h +++ b/include/uapi/sound/asound.h @@ -267,10 +267,17 @@ typedef int __bitwise snd_pcm_subformat_t; #define SNDRV_PCM_INFO_JOINT_DUPLEX 0x00200000 /* playback and capture stream are somewhat correlated */ #define SNDRV_PCM_INFO_SYNC_START 0x00400000 /* pcm support some kind of sync go */ #define SNDRV_PCM_INFO_NO_PERIOD_WAKEUP 0x00800000 /* period wakeup can be disabled */ -#define SNDRV_PCM_INFO_HAS_WALL_CLOCK 0x01000000 /* has audio wall clock for audio/system time sync */ +#define SNDRV_PCM_INFO_HAS_WALL_CLOCK 0x01000000 /* (Deprecated)has audio wall clock for audio/system time sync */ +#define SNDRV_PCM_INFO_HAS_LINK_ATIME 0x01000000 /* report hardware link audio time, reset on startup */ +#define SNDRV_PCM_INFO_HAS_LINK_ABSOLUTE_ATIME 0x02000000 /* report absolute hardware link audio time, not reset on startup */ +#define SNDRV_PCM_INFO_HAS_LINK_ESTIMATED_ATIME 0x04000000 /* report estimated link audio time */ +#define SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME 0x08000000 /* report synchronized audio/system time */ + #define SNDRV_PCM_INFO_DRAIN_TRIGGER 0x40000000 /* internal kernel flag - trigger in drain */ #define SNDRV_PCM_INFO_FIFO_IN_FRAMES 0x80000000 /* internal kernel flag - FIFO size is in frames */ + + typedef int __bitwise snd_pcm_state_t; #define SNDRV_PCM_STATE_OPEN ((__force snd_pcm_state_t) 0) /* stream is open */ #define SNDRV_PCM_STATE_SETUP ((__force snd_pcm_state_t) 1) /* stream has a setup */ @@ -408,6 +415,22 @@ struct snd_pcm_channel_info { unsigned int step; /* samples distance in bits */ }; +enum { + /* + * first definition for backwards compatibility only, + * maps to wallclock/link time for HDAudio playback and DEFAULT/DMA time for everything else + */ + SNDRV_PCM_AUDIO_TSTAMP_TYPE_COMPAT = 0, + + /* timestamp definitions */ + SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT = 1, /* DMA time, reported as per hw_ptr */ + SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK = 2, /* link time reported by sample or wallclock counter, reset on startup */ + SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_ABSOLUTE = 3, /* link time reported by sample or wallclock counter, not reset on startup */ + SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_ESTIMATED = 4, /* link time estimated indirectly */ + SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED = 5, /* link time synchronized with system time */ + SNDRV_PCM_AUDIO_TSTAMP_TYPE_LAST = SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED +}; + struct snd_pcm_status { snd_pcm_state_t state; /* stream state */ struct timespec trigger_tstamp; /* time when stream was started/stopped/paused */ @@ -419,9 +442,11 @@ struct snd_pcm_status { snd_pcm_uframes_t avail_max; /* max frames available on hw since last status */ snd_pcm_uframes_t overrange; /* count of ADC (capture) overrange detections from last status */ snd_pcm_state_t suspended_state; /* suspended stream state */ - __u32 reserved_alignment; /* must be filled with zero */ - struct timespec audio_tstamp; /* from sample counter or wall clock */ - unsigned char reserved[56-sizeof(struct timespec)]; /* must be filled with zero */ + __u32 audio_tstamp_data; /* needed for 64-bit alignment, used for configs/report to/from userspace */ + struct timespec audio_tstamp; /* sample counter, wall clock, PHC or on-demand sync'ed */ + struct timespec driver_tstamp; /* useful in case reference system tstamp is reported with delay */ + __u32 audio_tstamp_accuracy; /* in ns units, only valid if indicated in audio_tstamp_data */ + unsigned char reserved[52-2*sizeof(struct timespec)]; /* must be filled with zero */ }; struct snd_pcm_mmap_status { @@ -534,6 +559,7 @@ enum { #define SNDRV_PCM_IOCTL_DELAY _IOR('A', 0x21, snd_pcm_sframes_t) #define SNDRV_PCM_IOCTL_HWSYNC _IO('A', 0x22) #define SNDRV_PCM_IOCTL_SYNC_PTR _IOWR('A', 0x23, struct snd_pcm_sync_ptr) +#define SNDRV_PCM_IOCTL_STATUS_EXT _IOWR('A', 0x24, struct snd_pcm_status) #define SNDRV_PCM_IOCTL_CHANNEL_INFO _IOR('A', 0x32, struct snd_pcm_channel_info) #define SNDRV_PCM_IOCTL_PREPARE _IO('A', 0x40) #define SNDRV_PCM_IOCTL_RESET _IO('A', 0x41) -- cgit v1.2.3-59-g8ed1b From a877417ed4368b51f57e879b52793260981ddcaa Mon Sep 17 00:00:00 2001 From: Olivier Gay Date: Tue, 17 Feb 2015 14:00:03 +0100 Subject: HID: expose country code in sysfs This commit exposes in sysfs the HID country code that is stored in the country member of hid_device structure. It identifies the country code of localized hardware. For example some keyboards use it to exhibit the language of the key layout. It helps the upper layer to identify the localized hardware and setup the correct language to use. For USB HID devices the country code comes for the HID descriptor and for Bluetooth HID devices it is the HIDCountryCode attribute from the SDP database. Signed-off-by: Olivier Gay Signed-off-by: Jiri Kosina --- Documentation/ABI/testing/sysfs-driver-hid | 10 ++++++++++ drivers/hid/hid-core.c | 20 ++++++++++++++++++++ 2 files changed, 30 insertions(+) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-driver-hid b/Documentation/ABI/testing/sysfs-driver-hid index b6490e14fe83..48942cacb0bf 100644 --- a/Documentation/ABI/testing/sysfs-driver-hid +++ b/Documentation/ABI/testing/sysfs-driver-hid @@ -8,3 +8,13 @@ Description: When read, this file returns the device's raw binary HID report descriptor. This file cannot be written. Users: HIDAPI library (http://www.signal11.us/oss/hidapi) + +What: For USB devices : /sys/bus/usb/devices/-:./::./country + For BT devices : /sys/class/bluetooth/hci/::./country + Symlink : /sys/class/hidraw/hidraw/device/country +Date: February 2015 +KernelVersion: 3.19 +Contact: Olivier Gay +Description: When read, this file returns the hex integer value in ASCII + of the device's HID country code (e.g. 21 for US). + This file cannot be written. diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index db4fb6e1cc5b..4bae0f598ff8 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1562,12 +1562,26 @@ read_report_descriptor(struct file *filp, struct kobject *kobj, return count; } +static ssize_t +show_country(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + + return sprintf(buf, "%02x\n", hdev->country & 0xff); +} + static struct bin_attribute dev_bin_attr_report_desc = { .attr = { .name = "report_descriptor", .mode = 0444 }, .read = read_report_descriptor, .size = HID_MAX_DESCRIPTOR_SIZE, }; +static struct device_attribute dev_attr_country = { + .attr = { .name = "country", .mode = 0444 }, + .show = show_country, +}; + int hid_connect(struct hid_device *hdev, unsigned int connect_mask) { static const char *types[] = { "Device", "Pointer", "Mouse", "Device", @@ -1646,6 +1660,11 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask) bus = ""; } + ret = device_create_file(&hdev->dev, &dev_attr_country); + if (ret) + hid_warn(hdev, + "can't create sysfs country code attribute err: %d\n", ret); + ret = device_create_bin_file(&hdev->dev, &dev_bin_attr_report_desc); if (ret) hid_warn(hdev, @@ -1661,6 +1680,7 @@ EXPORT_SYMBOL_GPL(hid_connect); void hid_disconnect(struct hid_device *hdev) { + device_remove_file(&hdev->dev, &dev_attr_country); device_remove_bin_file(&hdev->dev, &dev_bin_attr_report_desc); if (hdev->claimed & HID_CLAIMED_INPUT) hidinput_disconnect(hdev); -- cgit v1.2.3-59-g8ed1b From 98e688f4054c2e9624c8e4666b985bde5e7e1660 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Tue, 24 Feb 2015 02:31:13 +0000 Subject: pktgen: Delete the original date from documentation This has been updated quite a few times since 2004, and git can keep track of the actual date for us. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- Documentation/networking/pktgen.txt | 2 -- 1 file changed, 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/pktgen.txt b/Documentation/networking/pktgen.txt index 6915c6b27869..560c84ba9abd 100644 --- a/Documentation/networking/pktgen.txt +++ b/Documentation/networking/pktgen.txt @@ -3,8 +3,6 @@ HOWTO for the linux packet generator ------------------------------------ -Date: 041221 - Enable CONFIG_NET_PKTGEN to compile and build pktgen.o either in kernel or as module. Module is preferred. insmod pktgen if needed. Once running pktgen creates a thread on each CPU where each thread has affinity to its CPU. -- cgit v1.2.3-59-g8ed1b From ca5b542ccee76e58407c3529f39974d382124093 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Tue, 24 Feb 2015 02:31:52 +0000 Subject: pktgen: Fix grammar errors and some poor wording in documentation Thanks to Rob Jones for suggesting some of the changes. Cc: Rob Jones Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- Documentation/networking/pktgen.txt | 56 ++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 26 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/pktgen.txt b/Documentation/networking/pktgen.txt index 560c84ba9abd..fa0ad87e6597 100644 --- a/Documentation/networking/pktgen.txt +++ b/Documentation/networking/pktgen.txt @@ -3,11 +3,11 @@ HOWTO for the linux packet generator ------------------------------------ -Enable CONFIG_NET_PKTGEN to compile and build pktgen.o either in kernel -or as module. Module is preferred. insmod pktgen if needed. Once running -pktgen creates a thread on each CPU where each thread has affinity to its CPU. -Monitoring and controlling is done via /proc. Easiest to select a suitable -a sample script and configure. +Enable CONFIG_NET_PKTGEN to compile and build pktgen.o either in-kernel +or as a module. A module is preferred; insmod pktgen if needed. Once +running, pktgen creates a thread for each CPU with affinity to that CPU. +Monitoring and controlling is done via /proc. It is easiest to select a +suitable sample script and configure that. On a dual CPU: @@ -25,7 +25,7 @@ For monitoring and control pktgen creates: Tuning NIC for max performance ============================== -The default NIC setting are (likely) not tuned for pktgen's artificial +The default NIC settings are (likely) not tuned for pktgen's artificial overload type of benchmarking, as this could hurt the normal use-case. Specifically increasing the TX ring buffer in the NIC: @@ -33,20 +33,20 @@ Specifically increasing the TX ring buffer in the NIC: A larger TX ring can improve pktgen's performance, while it can hurt in the general case, 1) because the TX ring buffer might get larger -than the CPUs L1/L2 cache, 2) because it allow more queueing in the +than the CPU's L1/L2 cache, 2) because it allows more queueing in the NIC HW layer (which is bad for bufferbloat). -One should be careful to conclude, that packets/descriptors in the HW +One should hesitate to conclude that packets/descriptors in the HW TX ring cause delay. Drivers usually delay cleaning up the -ring-buffers (for various performance reasons), thus packets stalling -the TX ring, might just be waiting for cleanup. +ring-buffers for various performance reasons, and packets stalling +the TX ring might just be waiting for cleanup. -This cleanup issues is specifically the case, for the driver ixgbe -(Intel 82599 chip). This driver (ixgbe) combine TX+RX ring cleanups, +This cleanup issue is specifically the case for the driver ixgbe +(Intel 82599 chip). This driver (ixgbe) combines TX+RX ring cleanups, and the cleanup interval is affected by the ethtool --coalesce setting of parameter "rx-usecs". -For ixgbe use e.g "30" resulting in approx 33K interrupts/sec (1/30*10^6): +For ixgbe use e.g. "30" resulting in approx 33K interrupts/sec (1/30*10^6): # ethtool -C ethX rx-usecs 30 @@ -58,15 +58,16 @@ Running: Stopped: eth1 Result: OK: max_before_softirq=10000 -Most important the devices assigned to thread. Note! A device can only belong -to one thread. +Most important are the devices assigned to the thread. Note that a +device can only belong to one thread. Viewing devices =============== -Parm section holds configured info. Current hold running stats. -Result is printed after run or after interruption. Example: +The Params section holds configured information. The Current section +holds running statistics. The Result is printed after a run or after +interruption. Example: /proc/net/pktgen/eth1 @@ -91,7 +92,8 @@ Result: OK: 13101142(c12220741+d880401) usec, 10000000 (60byte,0frags) Configuring threads and devices ================================ -This is done via the /proc interface easiest done via pgset in the scripts +This is done via the /proc interface, and most easily done via pgset in +the scripts. Examples: @@ -193,7 +195,8 @@ Examples: Example scripts =============== -A collection of small tutorial scripts for pktgen is in examples dir. +A collection of small tutorial scripts for pktgen is in the examples +directory: pktgen.conf-1-1 # 1 CPU 1 dev pktgen.conf-1-2 # 1 CPU 2 dev @@ -204,25 +207,26 @@ pktgen.conf-1-1-ip6 # 1 CPU 1 dev ipv6 pktgen.conf-1-1-ip6-rdos # 1 CPU 1 dev ipv6 w. route DoS pktgen.conf-1-1-flows # 1 CPU 1 dev multiple flows. -Run in shell: ./pktgen.conf-X-Y It does all the setup including sending. +Run in shell: ./pktgen.conf-X-Y +This does all the setup including sending. Interrupt affinity =================== -Note when adding devices to a specific CPU there good idea to also assign -/proc/irq/XX/smp_affinity so the TX-interrupts gets bound to the same CPU. -as this reduces cache bouncing when freeing skb's. +Note that when adding devices to a specific CPU it is a good idea to +also assign /proc/irq/XX/smp_affinity so that the TX interrupts are bound +to the same CPU. This reduces cache bouncing when freeing skbs. Enable IPsec ============ -Default IPsec transformation with ESP encapsulation plus Transport mode -could be enabled by simply setting: +Default IPsec transformation with ESP encapsulation plus transport mode +can be enabled by simply setting: pgset "flag IPSEC" pgset "flows 1" To avoid breaking existing testbed scripts for using AH type and tunnel mode, -user could use "pgset spi SPI_VALUE" to specify which formal of transformation +you can use "pgset spi SPI_VALUE" to specify which transformation mode to employ. -- cgit v1.2.3-59-g8ed1b From 7c95a9d962f9ffdf02a3d82a6ae108c254a29122 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Tue, 24 Feb 2015 02:32:07 +0000 Subject: samples/pktgen: Add sample scripts for pktgen facility These are Robert Olsson's samples which used to be available from but currently are not. Change the documentation to refer to these consistently as 'sample scripts', matching the directory name used here. Cc: Robert Olsson Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- Documentation/networking/pktgen.txt | 12 ++--- samples/pktgen/pktgen.conf-1-1 | 66 ++++++++++++++++++++++++++ samples/pktgen/pktgen.conf-1-1-flows | 74 +++++++++++++++++++++++++++++ samples/pktgen/pktgen.conf-1-1-ip6 | 67 +++++++++++++++++++++++++++ samples/pktgen/pktgen.conf-1-1-ip6-rdos | 70 ++++++++++++++++++++++++++++ samples/pktgen/pktgen.conf-1-1-rdos | 71 ++++++++++++++++++++++++++++ samples/pktgen/pktgen.conf-1-2 | 76 ++++++++++++++++++++++++++++++ samples/pktgen/pktgen.conf-2-1 | 72 +++++++++++++++++++++++++++++ samples/pktgen/pktgen.conf-2-2 | 82 +++++++++++++++++++++++++++++++++ 9 files changed, 584 insertions(+), 6 deletions(-) create mode 100755 samples/pktgen/pktgen.conf-1-1 create mode 100755 samples/pktgen/pktgen.conf-1-1-flows create mode 100755 samples/pktgen/pktgen.conf-1-1-ip6 create mode 100755 samples/pktgen/pktgen.conf-1-1-ip6-rdos create mode 100755 samples/pktgen/pktgen.conf-1-1-rdos create mode 100755 samples/pktgen/pktgen.conf-1-2 create mode 100755 samples/pktgen/pktgen.conf-2-1 create mode 100755 samples/pktgen/pktgen.conf-2-2 (limited to 'Documentation') diff --git a/Documentation/networking/pktgen.txt b/Documentation/networking/pktgen.txt index fa0ad87e6597..24c6dc100e02 100644 --- a/Documentation/networking/pktgen.txt +++ b/Documentation/networking/pktgen.txt @@ -92,8 +92,8 @@ Result: OK: 13101142(c12220741+d880401) usec, 10000000 (60byte,0frags) Configuring threads and devices ================================ -This is done via the /proc interface, and most easily done via pgset in -the scripts. +This is done via the /proc interface, and most easily done via pgset +as defined in the sample scripts. Examples: @@ -192,11 +192,11 @@ Examples: pgset "rate 300M" set rate to 300 Mb/s pgset "ratep 1000000" set rate to 1Mpps -Example scripts -=============== +Sample scripts +============== -A collection of small tutorial scripts for pktgen is in the examples -directory: +A collection of small tutorial scripts for pktgen is in the +samples/pktgen directory: pktgen.conf-1-1 # 1 CPU 1 dev pktgen.conf-1-2 # 1 CPU 2 dev diff --git a/samples/pktgen/pktgen.conf-1-1 b/samples/pktgen/pktgen.conf-1-1 new file mode 100755 index 000000000000..5d30f836ca3e --- /dev/null +++ b/samples/pktgen/pktgen.conf-1-1 @@ -0,0 +1,66 @@ +#! /bin/sh + +#modprobe pktgen + + +function pgset() { + local result + + echo $1 > $PGDEV + + result=`cat $PGDEV | fgrep "Result: OK:"` + if [ "$result" = "" ]; then + cat $PGDEV | fgrep Result: + fi +} + +function pg() { + echo inject > $PGDEV + cat $PGDEV +} + +# Config Start Here ----------------------------------------------------------- + + +# thread config +# Each CPU has own thread. Two CPU exammple. We add eth1, eth2 respectivly. + +PGDEV=/proc/net/pktgen/kpktgend_0 + echo "Removing all devices" + pgset "rem_device_all" + echo "Adding eth1" + pgset "add_device eth1" + echo "Setting max_before_softirq 10000" + pgset "max_before_softirq 10000" + + +# device config +# delay 0 means maximum speed. + +CLONE_SKB="clone_skb 1000000" +# NIC adds 4 bytes CRC +PKT_SIZE="pkt_size 60" + +# COUNT 0 means forever +#COUNT="count 0" +COUNT="count 10000000" +DELAY="delay 0" + +PGDEV=/proc/net/pktgen/eth1 + echo "Configuring $PGDEV" + pgset "$COUNT" + pgset "$CLONE_SKB" + pgset "$PKT_SIZE" + pgset "$DELAY" + pgset "dst 10.10.11.2" + pgset "dst_mac 00:04:23:08:91:dc" + + +# Time to run +PGDEV=/proc/net/pktgen/pgctrl + + echo "Running... ctrl^C to stop" + pgset "start" + echo "Done" + +# Result can be vieved in /proc/net/pktgen/eth1 diff --git a/samples/pktgen/pktgen.conf-1-1-flows b/samples/pktgen/pktgen.conf-1-1-flows new file mode 100755 index 000000000000..88a01b7d3531 --- /dev/null +++ b/samples/pktgen/pktgen.conf-1-1-flows @@ -0,0 +1,74 @@ +#! /bin/sh + +#modprobe pktgen + + +function pgset() { + local result + + echo $1 > $PGDEV + + result=`cat $PGDEV | fgrep "Result: OK:"` + if [ "$result" = "" ]; then + cat $PGDEV | fgrep Result: + fi +} + +function pg() { + echo inject > $PGDEV + cat $PGDEV +} + +# Config Start Here ----------------------------------------------------------- + + +# thread config +# Each CPU has own thread. Two CPU exammple. We add eth1, eth2 respectivly. + +PGDEV=/proc/net/pktgen/kpktgend_0 + echo "Removing all devices" + pgset "rem_device_all" + echo "Adding eth1" + pgset "add_device eth1" + echo "Setting max_before_softirq 10000" + pgset "max_before_softirq 10000" + + +# device config +# delay 0 +# We need to do alloc for every skb since we cannot clone here. + +CLONE_SKB="clone_skb 0" +# NIC adds 4 bytes CRC +PKT_SIZE="pkt_size 60" + +# COUNT 0 means forever +#COUNT="count 0" +COUNT="count 10000000" +DELAY="delay 0" + +PGDEV=/proc/net/pktgen/eth1 + echo "Configuring $PGDEV" + pgset "$COUNT" + pgset "$CLONE_SKB" + pgset "$PKT_SIZE" + pgset "$DELAY" + # Random address with in the min-max range + pgset "flag IPDST_RND" + pgset "dst_min 10.0.0.0" + pgset "dst_max 10.255.255.255" + + # 8k Concurrent flows at 4 pkts + pgset "flows 8192" + pgset "flowlen 4" + + pgset "dst_mac 00:04:23:08:91:dc" + +# Time to run +PGDEV=/proc/net/pktgen/pgctrl + + echo "Running... ctrl^C to stop" + pgset "start" + echo "Done" + +# Result can be vieved in /proc/net/pktgen/eth1 diff --git a/samples/pktgen/pktgen.conf-1-1-ip6 b/samples/pktgen/pktgen.conf-1-1-ip6 new file mode 100755 index 000000000000..752f112bd9e6 --- /dev/null +++ b/samples/pktgen/pktgen.conf-1-1-ip6 @@ -0,0 +1,67 @@ +#! /bin/sh + +#modprobe pktgen + + +function pgset() { + local result + + echo $1 > $PGDEV + + result=`cat $PGDEV | fgrep "Result: OK:"` + if [ "$result" = "" ]; then + cat $PGDEV | fgrep Result: + fi +} + +function pg() { + echo inject > $PGDEV + cat $PGDEV +} + +# Config Start Here ----------------------------------------------------------- + + +# thread config +# Each CPU has own thread. Two CPU exammple. We add eth1, eth2 respectivly. +# IPv6. Note increase in minimal packet length + +PGDEV=/proc/net/pktgen/kpktgend_0 + echo "Removing all devices" + pgset "rem_device_all" + echo "Adding eth1" + pgset "add_device eth1" + echo "Setting max_before_softirq 10000" + pgset "max_before_softirq 10000" + + +# device config +# delay 0 + +CLONE_SKB="clone_skb 1000000" +# NIC adds 4 bytes CRC +PKT_SIZE="pkt_size 66" + +# COUNT 0 means forever +#COUNT="count 0" +COUNT="count 10000000" +DELAY="delay 0" + +PGDEV=/proc/net/pktgen/eth1 + echo "Configuring $PGDEV" + pgset "$COUNT" + pgset "$CLONE_SKB" + pgset "$PKT_SIZE" + pgset "$DELAY" + pgset "dst6 fec0::1" + pgset "src6 fec0::2" + pgset "dst_mac 00:04:23:08:91:dc" + +# Time to run +PGDEV=/proc/net/pktgen/pgctrl + + echo "Running... ctrl^C to stop" + pgset "start" + echo "Done" + +# Result can be vieved in /proc/net/pktgen/eth1 diff --git a/samples/pktgen/pktgen.conf-1-1-ip6-rdos b/samples/pktgen/pktgen.conf-1-1-ip6-rdos new file mode 100755 index 000000000000..fd364277e43f --- /dev/null +++ b/samples/pktgen/pktgen.conf-1-1-ip6-rdos @@ -0,0 +1,70 @@ +#! /bin/sh + +#modprobe pktgen + + +function pgset() { + local result + + echo $1 > $PGDEV + + result=`cat $PGDEV | fgrep "Result: OK:"` + if [ "$result" = "" ]; then + cat $PGDEV | fgrep Result: + fi +} + +function pg() { + echo inject > $PGDEV + cat $PGDEV +} + +# Config Start Here ----------------------------------------------------------- + + +# thread config +# Each CPU has own thread. Two CPU exammple. We add eth1, eth2 respectivly. +# IPv6. Note increase in minimal packet length + +PGDEV=/proc/net/pktgen/kpktgend_0 + echo "Removing all devices" + pgset "rem_device_all" + echo "Adding eth1" + pgset "add_device eth1" + echo "Setting max_before_softirq 10000" + pgset "max_before_softirq 10000" + + +# device config +# delay 0 means maximum speed. + +# We need to do alloc for every skb since we cannot clone here. +CLONE_SKB="clone_skb 0" + +# NIC adds 4 bytes CRC +PKT_SIZE="pkt_size 66" + +# COUNT 0 means forever +#COUNT="count 0" +COUNT="count 10000000" +DELAY="delay 0" + +PGDEV=/proc/net/pktgen/eth1 + echo "Configuring $PGDEV" + pgset "$COUNT" + pgset "$CLONE_SKB" + pgset "$PKT_SIZE" + pgset "$DELAY" + pgset "dst6_min fec0::1" + pgset "dst6_max fec0::FFFF:FFFF" + + pgset "dst_mac 00:04:23:08:91:dc" + +# Time to run +PGDEV=/proc/net/pktgen/pgctrl + + echo "Running... ctrl^C to stop" + pgset "start" + echo "Done" + +# Result can be vieved in /proc/net/pktgen/eth1 diff --git a/samples/pktgen/pktgen.conf-1-1-rdos b/samples/pktgen/pktgen.conf-1-1-rdos new file mode 100755 index 000000000000..bc81fa319243 --- /dev/null +++ b/samples/pktgen/pktgen.conf-1-1-rdos @@ -0,0 +1,71 @@ +#! /bin/sh + +#modprobe pktgen + + +function pgset() { + local result + + echo $1 > $PGDEV + + result=`cat $PGDEV | fgrep "Result: OK:"` + if [ "$result" = "" ]; then + cat $PGDEV | fgrep Result: + fi +} + +function pg() { + echo inject > $PGDEV + cat $PGDEV +} + +# Config Start Here ----------------------------------------------------------- + + +# thread config +# Each CPU has own thread. Two CPU exammple. We add eth1, eth2 respectivly. + +PGDEV=/proc/net/pktgen/kpktgend_0 + echo "Removing all devices" + pgset "rem_device_all" + echo "Adding eth1" + pgset "add_device eth1" + echo "Setting max_before_softirq 10000" + pgset "max_before_softirq 10000" + + +# device config +# delay 0 + +# We need to do alloc for every skb since we cannot clone here. + +CLONE_SKB="clone_skb 0" +# NIC adds 4 bytes CRC +PKT_SIZE="pkt_size 60" + +# COUNT 0 means forever +#COUNT="count 0" +COUNT="count 10000000" +DELAY="delay 0" + +PGDEV=/proc/net/pktgen/eth1 + echo "Configuring $PGDEV" + pgset "$COUNT" + pgset "$CLONE_SKB" + pgset "$PKT_SIZE" + pgset "$DELAY" + # Random address with in the min-max range + pgset "flag IPDST_RND" + pgset "dst_min 10.0.0.0" + pgset "dst_max 10.255.255.255" + + pgset "dst_mac 00:04:23:08:91:dc" + +# Time to run +PGDEV=/proc/net/pktgen/pgctrl + + echo "Running... ctrl^C to stop" + pgset "start" + echo "Done" + +# Result can be vieved in /proc/net/pktgen/eth1 diff --git a/samples/pktgen/pktgen.conf-1-2 b/samples/pktgen/pktgen.conf-1-2 new file mode 100755 index 000000000000..f99b88673860 --- /dev/null +++ b/samples/pktgen/pktgen.conf-1-2 @@ -0,0 +1,76 @@ +#! /bin/sh + +#modprobe pktgen + + +function pgset() { + local result + + echo $1 > $PGDEV + + result=`cat $PGDEV | fgrep "Result: OK:"` + if [ "$result" = "" ]; then + cat $PGDEV | fgrep Result: + fi +} + +function pg() { + echo inject > $PGDEV + cat $PGDEV +} + +# Config Start Here ----------------------------------------------------------- + + +# thread config +# One CPU means one thread. One CPU exammple. We add eth1, eth2 respectivly. + +PGDEV=/proc/net/pktgen/kpktgend_0 + echo "Removing all devices" + pgset "rem_device_all" + echo "Adding eth1" + pgset "add_device eth1" + echo "Adding eth2" + pgset "add_device eth2" + echo "Setting max_before_softirq 10000" + pgset "max_before_softirq 10000" + + +# device config +# delay 0 means maximum speed. + +CLONE_SKB="clone_skb 1000000" +# NIC adds 4 bytes CRC +PKT_SIZE="pkt_size 60" + +# COUNT 0 means forever +#COUNT="count 0" +COUNT="count 10000000" +DELAY="delay 0" + +PGDEV=/proc/net/pktgen/eth1 + echo "Configuring $PGDEV" + pgset "$COUNT" + pgset "$CLONE_SKB" + pgset "$PKT_SIZE" + pgset "$DELAY" + pgset "dst 10.10.11.2" + pgset "dst_mac 00:04:23:08:91:dc" + +PGDEV=/proc/net/pktgen/eth2 + echo "Configuring $PGDEV" + pgset "$COUNT" + pgset "$CLONE_SKB" + pgset "$PKT_SIZE" + pgset "$DELAY" + pgset "dst 192.168.2.2" + pgset "dst_mac 00:04:23:08:91:de" + +# Time to run +PGDEV=/proc/net/pktgen/pgctrl + + echo "Running... ctrl^C to stop" + pgset "start" + echo "Done" + +# Result can be vieved in /proc/net/pktgen/eth[1,2] diff --git a/samples/pktgen/pktgen.conf-2-1 b/samples/pktgen/pktgen.conf-2-1 new file mode 100755 index 000000000000..845d7bf1609a --- /dev/null +++ b/samples/pktgen/pktgen.conf-2-1 @@ -0,0 +1,72 @@ +#! /bin/sh + +#modprobe pktgen + + +function pgset() { + local result + + echo $1 > $PGDEV + + result=`cat $PGDEV | fgrep "Result: OK:"` + if [ "$result" = "" ]; then + cat $PGDEV | fgrep Result: + fi +} + +function pg() { + echo inject > $PGDEV + cat $PGDEV +} + +# Config Start Here ----------------------------------------------------------- + + +# thread config +# Each CPU has own thread. Two CPU exammple. We add eth1, eth2 respectivly. + +PGDEV=/proc/net/pktgen/kpktgend_0 + echo "Removing all devices" + pgset "rem_device_all" + echo "Adding eth1" + pgset "add_device eth1" + echo "Setting max_before_softirq 10000" + pgset "max_before_softirq 10000" + +# We need to remove old config since we dont use this thread. We can only +# one NIC on one CPU due to affinity reasons. + +PGDEV=/proc/net/pktgen/kpktgend_1 + echo "Removing all devices" + pgset "rem_device_all" + +# device config +# delay 0 means maximum speed. + +CLONE_SKB="clone_skb 1000000" +# NIC adds 4 bytes CRC +PKT_SIZE="pkt_size 60" + +# COUNT 0 means forever +#COUNT="count 0" +COUNT="count 10000000" +DELAY="delay 0" + +PGDEV=/proc/net/pktgen/eth1 + echo "Configuring $PGDEV" + pgset "$COUNT" + pgset "$CLONE_SKB" + pgset "$PKT_SIZE" + pgset "$DELAY" + pgset "dst 10.10.11.2" + pgset "dst_mac 00:04:23:08:91:dc" + + +# Time to run +PGDEV=/proc/net/pktgen/pgctrl + + echo "Running... ctrl^C to stop" + pgset "start" + echo "Done" + +# Result can be vieved in /proc/net/pktgen/eth1 diff --git a/samples/pktgen/pktgen.conf-2-2 b/samples/pktgen/pktgen.conf-2-2 new file mode 100755 index 000000000000..7ce86470a3a9 --- /dev/null +++ b/samples/pktgen/pktgen.conf-2-2 @@ -0,0 +1,82 @@ +#! /bin/sh + +#modprobe pktgen + + +function pgset() { + local result + + echo $1 > $PGDEV + + result=`cat $PGDEV | fgrep "Result: OK:"` + if [ "$result" = "" ]; then + cat $PGDEV | fgrep Result: + fi +} + +function pg() { + echo inject > $PGDEV + cat $PGDEV +} + +# Config Start Here ----------------------------------------------------------- + + +# thread config +# Each CPU has own thread. Two CPU exammple. We add eth1, eth2 respectivly. + +PGDEV=/proc/net/pktgen/kpktgend_0 + echo "Removing all devices" + pgset "rem_device_all" + echo "Adding eth1" + pgset "add_device eth1" + echo "Setting max_before_softirq 10000" + pgset "max_before_softirq 10000" + +PGDEV=/proc/net/pktgen/kpktgend_1 + echo "Removing all devices" + pgset "rem_device_all" + echo "Adding eth2" + pgset "add_device eth2" + echo "Setting max_before_softirq 10000" + pgset "max_before_softirq 10000" + + +# device config +# delay 0 means maximum speed. + +CLONE_SKB="clone_skb 1000000" +# NIC adds 4 bytes CRC +PKT_SIZE="pkt_size 60" + +# COUNT 0 means forever +#COUNT="count 0" +COUNT="count 10000000" +DELAY="delay 0" + +PGDEV=/proc/net/pktgen/eth1 + echo "Configuring $PGDEV" + pgset "$COUNT" + pgset "$CLONE_SKB" + pgset "$PKT_SIZE" + pgset "$DELAY" + pgset "dst 10.10.11.2" + pgset "dst_mac 00:04:23:08:91:dc" + +PGDEV=/proc/net/pktgen/eth2 + echo "Configuring $PGDEV" + pgset "$COUNT" + pgset "$CLONE_SKB" + pgset "$PKT_SIZE" + pgset "$DELAY" + pgset "dst 192.168.2.2" + pgset "dst_mac 00:04:23:08:91:de" + +# Time to run +PGDEV=/proc/net/pktgen/pgctrl + + echo "Running... ctrl^C to stop" + pgset "start" + echo "Done" + +# Result can be vieved in /proc/net/pktgen/eth[1,2] -- cgit v1.2.3-59-g8ed1b From 4e081e0cbdf850366d28ddb77afba2031b26d933 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Tue, 24 Feb 2015 02:33:29 +0000 Subject: pktgen: Correct documentation of module name and command Drop the '.o' suffix so this text properly covers both the built-in and modular cases. 'insmod pktgen' obviously won't work; the command should be modprobe. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- Documentation/networking/pktgen.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/pktgen.txt b/Documentation/networking/pktgen.txt index 24c6dc100e02..0344f1d45b37 100644 --- a/Documentation/networking/pktgen.txt +++ b/Documentation/networking/pktgen.txt @@ -3,8 +3,8 @@ HOWTO for the linux packet generator ------------------------------------ -Enable CONFIG_NET_PKTGEN to compile and build pktgen.o either in-kernel -or as a module. A module is preferred; insmod pktgen if needed. Once +Enable CONFIG_NET_PKTGEN to compile and build pktgen either in-kernel +or as a module. A module is preferred; modprobe pktgen if needed. Once running, pktgen creates a thread for each CPU with affinity to that CPU. Monitoring and controlling is done via /proc. It is easiest to select a suitable sample script and configure that. -- cgit v1.2.3-59-g8ed1b From d752c364571743d696c2a54a449ce77550c35ac5 Mon Sep 17 00:00:00 2001 From: Marcelo Ricardo Leitner Date: Mon, 23 Feb 2015 15:02:34 -0300 Subject: ipvs: allow rescheduling of new connections when port reuse is detected Currently, when TCP/SCTP port reusing happens, IPVS will find the old entry and use it for the new one, behaving like a forced persistence. But if you consider a cluster with a heavy load of small connections, such reuse will happen often and may lead to a not optimal load balancing and might prevent a new node from getting a fair load. This patch introduces a new sysctl, conn_reuse_mode, that allows controlling how to proceed when port reuse is detected. The default value will allow rescheduling of new connections only if the old entry was in TIME_WAIT state for TCP or CLOSED for SCTP. Signed-off-by: Marcelo Ricardo Leitner Signed-off-by: Julian Anastasov Signed-off-by: Simon Horman --- Documentation/networking/ipvs-sysctl.txt | 21 ++++++++++++++++++++ include/net/ip_vs.h | 11 +++++++++++ net/netfilter/ipvs/ip_vs_core.c | 33 ++++++++++++++++++++++++++++---- net/netfilter/ipvs/ip_vs_ctl.c | 8 ++++++++ net/netfilter/ipvs/ip_vs_sync.c | 21 ++++++++++++++++++-- 5 files changed, 88 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/ipvs-sysctl.txt b/Documentation/networking/ipvs-sysctl.txt index 7a3c04729591..3ba709531adb 100644 --- a/Documentation/networking/ipvs-sysctl.txt +++ b/Documentation/networking/ipvs-sysctl.txt @@ -22,6 +22,27 @@ backup_only - BOOLEAN If set, disable the director function while the server is in backup mode to avoid packet loops for DR/TUN methods. +conn_reuse_mode - INTEGER + 1 - default + + Controls how ipvs will deal with connections that are detected + port reuse. It is a bitmap, with the values being: + + 0: disable any special handling on port reuse. The new + connection will be delivered to the same real server that was + servicing the previous connection. This will effectively + disable expire_nodest_conn. + + bit 1: enable rescheduling of new connections when it is safe. + That is, whenever expire_nodest_conn and for TCP sockets, when + the connection is in TIME_WAIT state (which is only possible if + you use NAT mode). + + bit 2: it is bit 1 plus, for TCP connections, when connections + are in FIN_WAIT state, as this is the last state seen by load + balancer in Direct Routing mode. This bit helps on adding new + real servers to a very busy cluster. + conntrack - BOOLEAN 0 - disabled (default) not 0 - enabled diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h index a627fe690c19..20fd23398537 100644 --- a/include/net/ip_vs.h +++ b/include/net/ip_vs.h @@ -941,6 +941,7 @@ struct netns_ipvs { int sysctl_nat_icmp_send; int sysctl_pmtu_disc; int sysctl_backup_only; + int sysctl_conn_reuse_mode; /* ip_vs_lblc */ int sysctl_lblc_expiration; @@ -1059,6 +1060,11 @@ static inline int sysctl_backup_only(struct netns_ipvs *ipvs) ipvs->sysctl_backup_only; } +static inline int sysctl_conn_reuse_mode(struct netns_ipvs *ipvs) +{ + return ipvs->sysctl_conn_reuse_mode; +} + #else static inline int sysctl_sync_threshold(struct netns_ipvs *ipvs) @@ -1126,6 +1132,11 @@ static inline int sysctl_backup_only(struct netns_ipvs *ipvs) return 0; } +static inline int sysctl_conn_reuse_mode(struct netns_ipvs *ipvs) +{ + return 1; +} + #endif /* IPVS core functions diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index c9470c86308f..6103ab933c5b 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c @@ -1042,6 +1042,26 @@ static inline bool is_new_conn(const struct sk_buff *skb, } } +static inline bool is_new_conn_expected(const struct ip_vs_conn *cp, + int conn_reuse_mode) +{ + /* Controlled (FTP DATA or persistence)? */ + if (cp->control) + return false; + + switch (cp->protocol) { + case IPPROTO_TCP: + return (cp->state == IP_VS_TCP_S_TIME_WAIT) || + ((conn_reuse_mode & 2) && + (cp->state == IP_VS_TCP_S_FIN_WAIT) && + (cp->flags & IP_VS_CONN_F_NOOUTPUT)); + case IPPROTO_SCTP: + return cp->state == IP_VS_SCTP_S_CLOSED; + default: + return false; + } +} + /* Handle response packets: rewrite addresses and send away... */ static unsigned int @@ -1580,6 +1600,7 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af) struct ip_vs_conn *cp; int ret, pkts; struct netns_ipvs *ipvs; + int conn_reuse_mode; /* Already marked as IPVS request or reply? */ if (skb->ipvs_property) @@ -1648,10 +1669,14 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af) */ cp = pp->conn_in_get(af, skb, &iph, 0); - if (unlikely(sysctl_expire_nodest_conn(ipvs)) && cp && cp->dest && - unlikely(!atomic_read(&cp->dest->weight)) && !iph.fragoffs && - is_new_conn(skb, &iph)) { - ip_vs_conn_expire_now(cp); + conn_reuse_mode = sysctl_conn_reuse_mode(ipvs); + if (conn_reuse_mode && !iph.fragoffs && + is_new_conn(skb, &iph) && cp && + ((unlikely(sysctl_expire_nodest_conn(ipvs)) && cp->dest && + unlikely(!atomic_read(&cp->dest->weight))) || + unlikely(is_new_conn_expected(cp, conn_reuse_mode)))) { + if (!atomic_read(&cp->n_control)) + ip_vs_conn_expire_now(cp); __ip_vs_conn_put(cp); cp = NULL; } diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index 6fd60059faf0..76cc9ffd87fa 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -1823,6 +1823,12 @@ static struct ctl_table vs_vars[] = { .mode = 0644, .proc_handler = proc_dointvec, }, + { + .procname = "conn_reuse_mode", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, #ifdef CONFIG_IP_VS_DEBUG { .procname = "debug_level", @@ -3790,6 +3796,8 @@ static int __net_init ip_vs_control_net_init_sysctl(struct net *net) ipvs->sysctl_pmtu_disc = 1; tbl[idx++].data = &ipvs->sysctl_pmtu_disc; tbl[idx++].data = &ipvs->sysctl_backup_only; + ipvs->sysctl_conn_reuse_mode = 1; + tbl[idx++].data = &ipvs->sysctl_conn_reuse_mode; ipvs->sysctl_hdr = register_net_sysctl(net, "net/ipv4/vs", tbl); diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c index c47ffd7a0a70..f96229cdb6e1 100644 --- a/net/netfilter/ipvs/ip_vs_sync.c +++ b/net/netfilter/ipvs/ip_vs_sync.c @@ -845,10 +845,27 @@ static void ip_vs_proc_conn(struct net *net, struct ip_vs_conn_param *param, struct ip_vs_conn *cp; struct netns_ipvs *ipvs = net_ipvs(net); - if (!(flags & IP_VS_CONN_F_TEMPLATE)) + if (!(flags & IP_VS_CONN_F_TEMPLATE)) { cp = ip_vs_conn_in_get(param); - else + if (cp && ((cp->dport != dport) || + !ip_vs_addr_equal(cp->daf, &cp->daddr, daddr))) { + if (!(flags & IP_VS_CONN_F_INACTIVE)) { + ip_vs_conn_expire_now(cp); + __ip_vs_conn_put(cp); + cp = NULL; + } else { + /* This is the expiration message for the + * connection that was already replaced, so we + * just ignore it. + */ + __ip_vs_conn_put(cp); + kfree(param->pe_data); + return; + } + } + } else { cp = ip_vs_ct_in_get(param); + } if (cp) { /* Free pe_data */ -- cgit v1.2.3-59-g8ed1b From adcf30bf832bb87d9b44d067b50ac7ed13c99528 Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Wed, 18 Feb 2015 14:08:30 +0000 Subject: iio: da9150: Add DT binding documentation for GPADC Signed-off-by: Adam Thomson Acked-by: Jonathan Cameron Signed-off-by: Sebastian Reichel --- .../devicetree/bindings/iio/adc/da9150-gpadc.txt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/da9150-gpadc.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/iio/adc/da9150-gpadc.txt b/Documentation/devicetree/bindings/iio/adc/da9150-gpadc.txt new file mode 100644 index 000000000000..c07228da92ac --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/da9150-gpadc.txt @@ -0,0 +1,16 @@ +Dialog Semiconductor DA9150 IIO GPADC bindings + +Required properties: +- compatible: "dlg,da9150-gpadc" for DA9150 IIO GPADC +- #io-channel-cells: Should be set to <1> + (See Documentation/devicetree/bindings/iio/iio-bindings.txt for further info) + +For further information on GPADC channels, see device datasheet. + + +Example: + + gpadc: da9150-gpadc { + compatible = "dlg,da9150-gpadc"; + #io-channel-cells = <1>; + }; -- cgit v1.2.3-59-g8ed1b From 1da9790cbd0bc853f6053e59523b6fe6f6e21d78 Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Wed, 18 Feb 2015 14:08:34 +0000 Subject: power: da9150: Add DT binding documentation for charger Signed-off-by: Adam Thomson Signed-off-by: Sebastian Reichel --- .../devicetree/bindings/power/da9150-charger.txt | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 Documentation/devicetree/bindings/power/da9150-charger.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/power/da9150-charger.txt b/Documentation/devicetree/bindings/power/da9150-charger.txt new file mode 100644 index 000000000000..f3906663c454 --- /dev/null +++ b/Documentation/devicetree/bindings/power/da9150-charger.txt @@ -0,0 +1,26 @@ +Dialog Semiconductor DA9150 Charger Power Supply bindings + +Required properties: +- compatible: "dlg,da9150-charger" for DA9150 Charger Power Supply + +Optional properties: +- io-channels: List of phandle and IIO specifier pairs +- io-channel-names: List of channel names used by charger + ["CHAN_IBUS", "CHAN_VBUS", "CHAN_TJUNC", "CHAN_VBAT"] + (See Documentation/devicetree/bindings/iio/iio-bindings.txt for further info) + + +Example: + + da9150-charger { + compatible = "dlg,da9150-charger"; + + io-channels = <&gpadc 0>, + <&gpadc 2>, + <&gpadc 8>, + <&gpadc 5>; + io-channel-names = "CHAN_IBUS", + "CHAN_VBUS", + "CHAN_TJUNC", + "CHAN_VBAT"; + }; -- cgit v1.2.3-59-g8ed1b From 1d4a9c17d4d204a159139361e8d4db7f9f267879 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Sun, 22 Feb 2015 21:16:49 -0800 Subject: PM / sleep: add configurable delay for pm_test When CONFIG_PM_DEBUG=y, we provide a sysfs file (/sys/power/pm_test) for selecting one of a few suspend test modes, where rather than entering a full suspend state, the kernel will perform some subset of suspend steps, wait 5 seconds, and then resume back to normal operation. This mode is useful for (among other things) observing the state of the system just before entering a sleep mode, for debugging or analysis purposes. However, a constant 5 second wait is not sufficient for some sorts of analysis; for example, on an SoC, one might want to use external tools to probe the power states of various on-chip controllers or clocks. This patch turns this 5 second delay into a configurable module parameter, so users can determine how long to wait in this pseudo-suspend state before resuming the system. Example (wait 30 seconds); # echo 30 > /sys/module/suspend/parameters/pm_test_delay # echo core > /sys/power/pm_test # time echo mem > /sys/power/state ... [ 17.583625] suspend debug: Waiting for 30 second(s). ... real 0m30.381s user 0m0.017s sys 0m0.080s Signed-off-by: Brian Norris Acked-by: Pavel Machek Reviewed-by: Kevin Cernekee Acked-by: Florian Fainelli Signed-off-by: Rafael J. Wysocki --- Documentation/kernel-parameters.txt | 7 +++++++ Documentation/power/basic-pm-debugging.txt | 10 ++++++---- kernel/power/suspend.c | 13 +++++++++++-- 3 files changed, 24 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index bfcb1a62a7b4..8b1fa5e129ac 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -3462,6 +3462,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted. improve throughput, but will also increase the amount of memory reserved for use by the client. + suspend.pm_test_delay= + [SUSPEND] + Sets the number of seconds to remain in a suspend test + mode before resuming the system (see + /sys/power/pm_test). Only available when CONFIG_PM_DEBUG + is set. Default value is 5. + swapaccount=[0|1] [KNL] Enable accounting of swap in memory resource controller if no parameter or 1 is given or disable diff --git a/Documentation/power/basic-pm-debugging.txt b/Documentation/power/basic-pm-debugging.txt index edeecd447d23..b96098ccfe69 100644 --- a/Documentation/power/basic-pm-debugging.txt +++ b/Documentation/power/basic-pm-debugging.txt @@ -75,12 +75,14 @@ you should do the following: # echo platform > /sys/power/disk # echo disk > /sys/power/state -Then, the kernel will try to freeze processes, suspend devices, wait 5 seconds, -resume devices and thaw processes. If "platform" is written to +Then, the kernel will try to freeze processes, suspend devices, wait a few +seconds (5 by default, but configurable by the suspend.pm_test_delay module +parameter), resume devices and thaw processes. If "platform" is written to /sys/power/pm_test , then after suspending devices the kernel will additionally invoke the global control methods (eg. ACPI global control methods) used to -prepare the platform firmware for hibernation. Next, it will wait 5 seconds and -invoke the platform (eg. ACPI) global methods used to cancel hibernation etc. +prepare the platform firmware for hibernation. Next, it will wait a +configurable number of seconds and invoke the platform (eg. ACPI) global +methods used to cancel hibernation etc. Writing "none" to /sys/power/pm_test causes the kernel to switch to the normal hibernation/suspend operations. Also, when open for reading, /sys/power/pm_test diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index b7d6b3a721b1..8d7a1ef72758 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "power.h" @@ -233,12 +234,20 @@ static bool platform_suspend_again(suspend_state_t state) suspend_ops->suspend_again() : false; } +#ifdef CONFIG_PM_DEBUG +static unsigned int pm_test_delay = 5; +module_param(pm_test_delay, uint, 0644); +MODULE_PARM_DESC(pm_test_delay, + "Number of seconds to wait before resuming from suspend test"); +#endif + static int suspend_test(int level) { #ifdef CONFIG_PM_DEBUG if (pm_test_level == level) { - printk(KERN_INFO "suspend debug: Waiting for 5 seconds.\n"); - mdelay(5000); + printk(KERN_INFO "suspend debug: Waiting for %d second(s).\n", + pm_test_delay); + mdelay(pm_test_delay * 1000); return 1; } #endif /* !CONFIG_PM_DEBUG */ -- cgit v1.2.3-59-g8ed1b From c4ac37193eccd941ff53da561d815bdabf591d31 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Sat, 17 Jan 2015 15:21:23 +0000 Subject: Documentation: devicetree: arizona: Add bindings for WM8280 Signed-off-by: Richard Fitzgerald Signed-off-by: Charles Keepax Signed-off-by: Lee Jones --- Documentation/devicetree/bindings/mfd/arizona.txt | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mfd/arizona.txt b/Documentation/devicetree/bindings/mfd/arizona.txt index 7bd1273f571a..87c878b1a17b 100644 --- a/Documentation/devicetree/bindings/mfd/arizona.txt +++ b/Documentation/devicetree/bindings/mfd/arizona.txt @@ -8,6 +8,7 @@ Required properties: - compatible : One of the following chip-specific strings: "wlf,wm5102" "wlf,wm5110" + "wlf,wm8280" "wlf,wm8997" - reg : I2C slave address when connected using I2C, chip select number when using SPI. @@ -26,10 +27,16 @@ Required properties: - #gpio-cells : Must be 2. The first cell is the pin number and the second cell is used to specify optional parameters (currently unused). - - AVDD-supply, DBVDD1-supply, DBVDD2-supply, DBVDD3-supply (wm5102, wm5110), - CPVDD-supply, SPKVDDL-supply (wm5102, wm5110), SPKVDDR-supply (wm5102, - wm5110), SPKVDD-supply (wm8997) : Power supplies for the device, as covered - in Documentation/devicetree/bindings/regulator/regulator.txt + - AVDD-supply, DBVDD1-supply, CPVDD-supply : Power supplies for the device, + as covered in Documentation/devicetree/bindings/regulator/regulator.txt + + - DBVDD2-supply, DBVDD3-supply : Additional databus power supplies (wm5102, + wm5110, wm8280) + + - SPKVDDL-supply, SPKVDDR-supply : Speaker driver power supplies (wm5102, + wm5110, wm8280) + + - SPKVDD-supply : Speaker driver power supply (wm8997) Optional properties: -- cgit v1.2.3-59-g8ed1b From d2af1ad73e7a22ed3e04374896fee0eb300c05c3 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 20 Jan 2015 23:54:59 -0800 Subject: documentation: Update rcutree.kthread_prio for grace-period kthread use Now that the rcutree.kthread_prio kernel boot parameter also controls the priority of the grace-period kthreads, update the documentation to reflect this change. Signed-off-by: Paul E. McKenney --- Documentation/kernel-parameters.txt | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index bfcb1a62a7b4..d913e3b4bf0d 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -2991,11 +2991,15 @@ bytes respectively. Such letter suffixes can also be entirely omitted. value is one, and maximum value is HZ. rcutree.kthread_prio= [KNL,BOOT] - Set the SCHED_FIFO priority of the RCU - per-CPU kthreads (rcuc/N). This value is also - used for the priority of the RCU boost threads - (rcub/N). Valid values are 1-99 and the default - is 1 (the least-favored priority). + Set the SCHED_FIFO priority of the RCU per-CPU + kthreads (rcuc/N). This value is also used for + the priority of the RCU boost threads (rcub/N) + and for the RCU grace-period kthreads (rcu_bh, + rcu_preempt, and rcu_sched). If RCU_BOOST is + set, valid values are 1-99 and the default is 1 + (the least-favored priority). Otherwise, when + RCU_BOOST is not set, valid values are 0-99 and + the default is zero (non-realtime operation). rcutree.rcu_nocb_leader_stride= [KNL] Set the number of NOCB kthread groups, which -- cgit v1.2.3-59-g8ed1b From 89bf5d82ed451f02329bbbb06ac365e96b18804d Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sat, 24 Jan 2015 22:24:14 -0800 Subject: documentation: Update based on on-demand vmstat workers Now that the on-demand vmstat workers commit is in mainline, it is possible to eliminate vmstat_update()-induced OS jitter. This commit updates the documentation accordingly. Signed-off-by: Paul E. McKenney --- Documentation/kernel-per-CPU-kthreads.txt | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'Documentation') diff --git a/Documentation/kernel-per-CPU-kthreads.txt b/Documentation/kernel-per-CPU-kthreads.txt index f3cd299fcc41..81fe051c4447 100644 --- a/Documentation/kernel-per-CPU-kthreads.txt +++ b/Documentation/kernel-per-CPU-kthreads.txt @@ -190,14 +190,16 @@ To reduce its OS jitter, do any of the following: on each CPU, including cs_dbs_timer() and od_dbs_timer(). WARNING: Please check your CPU specifications to make sure that this is safe on your particular system. - d. It is not possible to entirely get rid of OS jitter - from vmstat_update() on CONFIG_SMP=y systems, but you - can decrease its frequency by writing a large value - to /proc/sys/vm/stat_interval. The default value is - HZ, for an interval of one second. Of course, larger - values will make your virtual-memory statistics update - more slowly. Of course, you can also run your workload - at a real-time priority, thus preempting vmstat_update(), + d. As of v3.18, Christoph Lameter's on-demand vmstat workers + commit prevents OS jitter due to vmstat_update() on + CONFIG_SMP=y systems. Before v3.18, is not possible + to entirely get rid of the OS jitter, but you can + decrease its frequency by writing a large value to + /proc/sys/vm/stat_interval. The default value is HZ, + for an interval of one second. Of course, larger values + will make your virtual-memory statistics update more + slowly. Of course, you can also run your workload at + a real-time priority, thus preempting vmstat_update(), but if your workload is CPU-bound, this is a bad idea. However, there is an RFC patch from Christoph Lameter (based on an earlier one from Gilad Ben-Yossef) that -- cgit v1.2.3-59-g8ed1b From c25197841efe53258abb22cfd894a729a272edf9 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sun, 25 Jan 2015 11:28:28 -0800 Subject: documentation: Update NO_HZ_FULL interaction with POSIX timers POSIX timers are no longer starved on adaptive-ticks CPUs. Instead, they prevent affected CPUs from entering adaptive-ticks mode. This commit therefore updates the NO_HZ.txt documentation. Signed-off-by: Paul E. McKenney --- Documentation/timers/NO_HZ.txt | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'Documentation') diff --git a/Documentation/timers/NO_HZ.txt b/Documentation/timers/NO_HZ.txt index cca122f25120..6eaf576294f3 100644 --- a/Documentation/timers/NO_HZ.txt +++ b/Documentation/timers/NO_HZ.txt @@ -158,13 +158,9 @@ not come for free: to the need to inform kernel subsystems (such as RCU) about the change in mode. -3. POSIX CPU timers on adaptive-tick CPUs may miss their deadlines - (perhaps indefinitely) because they currently rely on - scheduling-tick interrupts. This will likely be fixed in - one of two ways: (1) Prevent CPUs with POSIX CPU timers from - entering adaptive-tick mode, or (2) Use hrtimers or other - adaptive-ticks-immune mechanism to cause the POSIX CPU timer to - fire properly. +3. POSIX CPU timers prevent CPUs from entering adaptive-tick mode. + Real-time applications needing to take actions based on CPU time + consumption need to use other means of doing so. 4. If there are more perf events pending than the hardware can accommodate, they are normally round-robined so as to collect -- cgit v1.2.3-59-g8ed1b From f1360570f420b8b122e7f1cccf456ff7133a3007 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sun, 25 Jan 2015 11:48:18 -0800 Subject: documentation: Update per-CPU kthreads documentation Signed-off-by: Paul E. McKenney --- Documentation/kernel-per-CPU-kthreads.txt | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/kernel-per-CPU-kthreads.txt b/Documentation/kernel-per-CPU-kthreads.txt index 81fe051c4447..f4cbfe0ba108 100644 --- a/Documentation/kernel-per-CPU-kthreads.txt +++ b/Documentation/kernel-per-CPU-kthreads.txt @@ -205,7 +205,9 @@ To reduce its OS jitter, do any of the following: (based on an earlier one from Gilad Ben-Yossef) that reduces or even eliminates vmstat overhead for some workloads at https://lkml.org/lkml/2013/9/4/379. - e. If running on high-end powerpc servers, build with + e. Boot with "elevator=noop" to avoid workqueue use by + the block layer. + f. If running on high-end powerpc servers, build with CONFIG_PPC_RTAS_DAEMON=n. This prevents the RTAS daemon from running on each CPU every second or so. (This will require editing Kconfig files and will defeat @@ -213,12 +215,12 @@ To reduce its OS jitter, do any of the following: due to the rtas_event_scan() function. WARNING: Please check your CPU specifications to make sure that this is safe on your particular system. - f. If running on Cell Processor, build your kernel with + g. If running on Cell Processor, build your kernel with CBE_CPUFREQ_SPU_GOVERNOR=n to avoid OS jitter from spu_gov_work(). WARNING: Please check your CPU specifications to make sure that this is safe on your particular system. - g. If running on PowerMAC, build your kernel with + h. If running on PowerMAC, build your kernel with CONFIG_PMAC_RACKMETER=n to disable the CPU-meter, avoiding OS jitter from rackmeter_do_timer(). @@ -260,8 +262,12 @@ Purpose: Detect software lockups on each CPU. To reduce its OS jitter, do at least one of the following: 1. Build with CONFIG_LOCKUP_DETECTOR=n, which will prevent these kthreads from being created in the first place. -2. Echo a zero to /proc/sys/kernel/watchdog to disable the +2. Boot with "nosoftlockup=0", which will also prevent these kthreads + from being created. Other related watchdog and softlockup boot + parameters may be found in Documentation/kernel-parameters.txt + and Documentation/watchdog/watchdog-parameters.txt. +3. Echo a zero to /proc/sys/kernel/watchdog to disable the watchdog timer. -3. Echo a large number of /proc/sys/kernel/watchdog_thresh in +4. Echo a large number of /proc/sys/kernel/watchdog_thresh in order to reduce the frequency of OS jitter due to the watchdog timer down to a level that is acceptable for your workload. -- cgit v1.2.3-59-g8ed1b From daf1aab9acfaaded09f53fa91dfe6e4e6926ec39 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 2 Feb 2015 08:08:25 -0800 Subject: documentation: Clarify memory-barrier semantics of atomic operations All value-returning atomic read-modify-write operations must provide full memory-barrier semantics on both sides of the operation. This commit clarifies the documentation to make it clear that these memory-barrier semantics are provided by the operations themselves, not by their callers. Reported-by: Peter Hurley Signed-off-by: Paul E. McKenney --- Documentation/atomic_ops.txt | 45 ++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) (limited to 'Documentation') diff --git a/Documentation/atomic_ops.txt b/Documentation/atomic_ops.txt index 183e41bdcb69..dab6da3382d9 100644 --- a/Documentation/atomic_ops.txt +++ b/Documentation/atomic_ops.txt @@ -201,11 +201,11 @@ These routines add 1 and subtract 1, respectively, from the given atomic_t and return the new counter value after the operation is performed. -Unlike the above routines, it is required that explicit memory -barriers are performed before and after the operation. It must be -done such that all memory operations before and after the atomic -operation calls are strongly ordered with respect to the atomic -operation itself. +Unlike the above routines, it is required that these primitives +include explicit memory barriers that are performed before and after +the operation. It must be done such that all memory operations before +and after the atomic operation calls are strongly ordered with respect +to the atomic operation itself. For example, it should behave as if a smp_mb() call existed both before and after the atomic operation. @@ -233,21 +233,21 @@ These two routines increment and decrement by 1, respectively, the given atomic counter. They return a boolean indicating whether the resulting counter value was zero or not. -It requires explicit memory barrier semantics around the operation as -above. +Again, these primitives provide explicit memory barrier semantics around +the atomic operation. int atomic_sub_and_test(int i, atomic_t *v); This is identical to atomic_dec_and_test() except that an explicit -decrement is given instead of the implicit "1". It requires explicit -memory barrier semantics around the operation. +decrement is given instead of the implicit "1". This primitive must +provide explicit memory barrier semantics around the operation. int atomic_add_negative(int i, atomic_t *v); -The given increment is added to the given atomic counter value. A -boolean is return which indicates whether the resulting counter value -is negative. It requires explicit memory barrier semantics around the -operation. +The given increment is added to the given atomic counter value. A boolean +is return which indicates whether the resulting counter value is negative. +This primitive must provide explicit memory barrier semantics around +the operation. Then: @@ -257,7 +257,7 @@ This performs an atomic exchange operation on the atomic variable v, setting the given new value. It returns the old value that the atomic variable v had just before the operation. -atomic_xchg requires explicit memory barriers around the operation. +atomic_xchg must provide explicit memory barriers around the operation. int atomic_cmpxchg(atomic_t *v, int old, int new); @@ -266,7 +266,7 @@ with the given old and new values. Like all atomic_xxx operations, atomic_cmpxchg will only satisfy its atomicity semantics as long as all other accesses of *v are performed through atomic_xxx operations. -atomic_cmpxchg requires explicit memory barriers around the operation. +atomic_cmpxchg must provide explicit memory barriers around the operation. The semantics for atomic_cmpxchg are the same as those defined for 'cas' below. @@ -279,8 +279,8 @@ If the atomic value v is not equal to u, this function adds a to v, and returns non zero. If v is equal to u then it returns zero. This is done as an atomic operation. -atomic_add_unless requires explicit memory barriers around the operation -unless it fails (returns 0). +atomic_add_unless must provide explicit memory barriers around the +operation unless it fails (returns 0). atomic_inc_not_zero, equivalent to atomic_add_unless(v, 1, 0) @@ -460,9 +460,9 @@ the return value into an int. There are other places where things like this occur as well. These routines, like the atomic_t counter operations returning values, -require explicit memory barrier semantics around their execution. All -memory operations before the atomic bit operation call must be made -visible globally before the atomic bit operation is made visible. +must provide explicit memory barrier semantics around their execution. +All memory operations before the atomic bit operation call must be +made visible globally before the atomic bit operation is made visible. Likewise, the atomic bit operation must be visible globally before any subsequent memory operation is made visible. For example: @@ -536,8 +536,9 @@ except that two underscores are prefixed to the interface name. These non-atomic variants also do not require any special memory barrier semantics. -The routines xchg() and cmpxchg() need the same exact memory barriers -as the atomic and bit operations returning values. +The routines xchg() and cmpxchg() must provide the same exact +memory-barrier semantics as the atomic and bit operations returning +values. Spinlocks and rwlocks have memory barrier expectations as well. The rule to follow is simple: -- cgit v1.2.3-59-g8ed1b From ff382810590e7182a1482a225965d6943e61699c Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 17 Feb 2015 10:00:06 -0800 Subject: documentation: Clarify control-dependency pairing This commit explicitly states that control dependencies pair normally with other barriers, and gives an example of such pairing. Reported-by: Peter Zijlstra Signed-off-by: Paul E. McKenney Acked-by: Peter Zijlstra (Intel) --- Documentation/memory-barriers.txt | 42 +++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 13 deletions(-) (limited to 'Documentation') diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt index ca2387ef27ab..6974f1c2b4e1 100644 --- a/Documentation/memory-barriers.txt +++ b/Documentation/memory-barriers.txt @@ -592,9 +592,9 @@ See also the subsection on "Cache Coherency" for a more thorough example. CONTROL DEPENDENCIES -------------------- -A control dependency requires a full read memory barrier, not simply a data -dependency barrier to make it work correctly. Consider the following bit of -code: +A load-load control dependency requires a full read memory barrier, not +simply a data dependency barrier to make it work correctly. Consider the +following bit of code: q = ACCESS_ONCE(a); if (q) { @@ -615,14 +615,15 @@ case what's actually required is: } However, stores are not speculated. This means that ordering -is- provided -in the following example: +for load-store control dependencies, as in the following example: q = ACCESS_ONCE(a); if (q) { ACCESS_ONCE(b) = p; } -Please note that ACCESS_ONCE() is not optional! Without the +Control dependencies pair normally with other types of barriers. +That said, please note that ACCESS_ONCE() is not optional! Without the ACCESS_ONCE(), might combine the load from 'a' with other loads from 'a', and the store to 'b' with other stores to 'b', with possible highly counterintuitive effects on ordering. @@ -813,6 +814,8 @@ In summary: barrier() can help to preserve your control dependency. Please see the Compiler Barrier section for more information. + (*) Control dependencies pair normally with other types of barriers. + (*) Control dependencies do -not- provide transitivity. If you need transitivity, use smp_mb(). @@ -823,14 +826,14 @@ SMP BARRIER PAIRING When dealing with CPU-CPU interactions, certain types of memory barrier should always be paired. A lack of appropriate pairing is almost certainly an error. -General barriers pair with each other, though they also pair with -most other types of barriers, albeit without transitivity. An acquire -barrier pairs with a release barrier, but both may also pair with other -barriers, including of course general barriers. A write barrier pairs -with a data dependency barrier, an acquire barrier, a release barrier, -a read barrier, or a general barrier. Similarly a read barrier or a -data dependency barrier pairs with a write barrier, an acquire barrier, -a release barrier, or a general barrier: +General barriers pair with each other, though they also pair with most +other types of barriers, albeit without transitivity. An acquire barrier +pairs with a release barrier, but both may also pair with other barriers, +including of course general barriers. A write barrier pairs with a data +dependency barrier, a control dependency, an acquire barrier, a release +barrier, a read barrier, or a general barrier. Similarly a read barrier, +control dependency, or a data dependency barrier pairs with a write +barrier, an acquire barrier, a release barrier, or a general barrier: CPU 1 CPU 2 =============== =============== @@ -850,6 +853,19 @@ Or: y = *x; +Or even: + + CPU 1 CPU 2 + =============== =============================== + r1 = ACCESS_ONCE(y); + + ACCESS_ONCE(y) = 1; if (r2 = ACCESS_ONCE(x)) { + + ACCESS_ONCE(y) = 1; + } + + assert(r1 == 0 || r2 == 0); + Basically, the read barrier always has to be there, even though it can be of the "weaker" type. -- cgit v1.2.3-59-g8ed1b From ccdaeb2b176f7db491a6f8e8b1c51f9393525f7d Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Fri, 27 Feb 2015 09:58:26 +0100 Subject: at86rf230: add support for external xtal trim This patch adds support for setting the xtal trim register. Some at86rf2xx transceiver boards needs fine tuning the xtal capacitor. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- .../bindings/net/ieee802154/at86rf230.txt | 3 ++ drivers/net/ieee802154/at86rf230.c | 54 ++++++++++++++++++++-- include/linux/spi/at86rf230.h | 1 + 3 files changed, 54 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/ieee802154/at86rf230.txt b/Documentation/devicetree/bindings/net/ieee802154/at86rf230.txt index d3bbdded4cbe..1ae5100fea14 100644 --- a/Documentation/devicetree/bindings/net/ieee802154/at86rf230.txt +++ b/Documentation/devicetree/bindings/net/ieee802154/at86rf230.txt @@ -11,6 +11,8 @@ Required properties: Optional properties: - reset-gpio: GPIO spec for the rstn pin - sleep-gpio: GPIO spec for the slp_tr pin + - xtal-trim: u8 value for fine tuning the internal capacitance + arrays of xtal pins: 0 = +0 pF, 0xf = +4.5 pF Example: @@ -20,4 +22,5 @@ Example: reg = <0>; interrupts = <19 1>; interrupt-parent = <&gpio3>; + xtal-trim = /bits/ 8 <0x06>; }; diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 9888b7ff24bc..c1323e5cdd0c 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -1315,7 +1315,7 @@ static struct at86rf2xx_chip_data at86rf212_data = { .get_desense_steps = at86rf212_get_desens_steps }; -static int at86rf230_hw_init(struct at86rf230_local *lp) +static int at86rf230_hw_init(struct at86rf230_local *lp, u8 xtal_trim) { int rc, irq_type, irq_pol = IRQ_ACTIVE_HIGH; unsigned int dvdd; @@ -1362,6 +1362,45 @@ static int at86rf230_hw_init(struct at86rf230_local *lp) usleep_range(lp->data->t_sleep_cycle, lp->data->t_sleep_cycle + 100); + /* xtal_trim value is calculated by: + * CL = 0.5 * (CX + CTRIM + CPAR) + * + * whereas: + * CL = capacitor of used crystal + * CX = connected capacitors at xtal pins + * CPAR = in all at86rf2xx datasheets this is a constant value 3 pF, + * but this is different on each board setup. You need to fine + * tuning this value via CTRIM. + * CTRIM = variable capacitor setting. Resolution is 0.3 pF range is + * 0 pF upto 4.5 pF. + * + * Examples: + * atben transceiver: + * + * CL = 8 pF + * CX = 12 pF + * CPAR = 3 pF (We assume the magic constant from datasheet) + * CTRIM = 0.9 pF + * + * (12+0.9+3)/2 = 7.95 which is nearly at 8 pF + * + * xtal_trim = 0x3 + * + * openlabs transceiver: + * + * CL = 16 pF + * CX = 22 pF + * CPAR = 3 pF (We assume the magic constant from datasheet) + * CTRIM = 4.5 pF + * + * (22+4.5+3)/2 = 14.75 which is the nearest value to 16 pF + * + * xtal_trim = 0xf + */ + rc = at86rf230_write_subreg(lp, SR_XTAL_TRIM, xtal_trim); + if (rc) + return rc; + rc = at86rf230_read_subreg(lp, SR_DVDD_OK, &dvdd); if (rc) return rc; @@ -1378,9 +1417,11 @@ static int at86rf230_hw_init(struct at86rf230_local *lp) } static int -at86rf230_get_pdata(struct spi_device *spi, int *rstn, int *slp_tr) +at86rf230_get_pdata(struct spi_device *spi, int *rstn, int *slp_tr, + u8 *xtal_trim) { struct at86rf230_platform_data *pdata = spi->dev.platform_data; + int ret; if (!IS_ENABLED(CONFIG_OF) || !spi->dev.of_node) { if (!pdata) @@ -1388,11 +1429,15 @@ at86rf230_get_pdata(struct spi_device *spi, int *rstn, int *slp_tr) *rstn = pdata->rstn; *slp_tr = pdata->slp_tr; + *xtal_trim = pdata->xtal_trim; return 0; } *rstn = of_get_named_gpio(spi->dev.of_node, "reset-gpio", 0); *slp_tr = of_get_named_gpio(spi->dev.of_node, "sleep-gpio", 0); + ret = of_property_read_u8(spi->dev.of_node, "xtal-trim", xtal_trim); + if (ret < 0 && ret != -EINVAL) + return ret; return 0; } @@ -1505,13 +1550,14 @@ static int at86rf230_probe(struct spi_device *spi) struct at86rf230_local *lp; unsigned int status; int rc, irq_type, rstn, slp_tr; + u8 xtal_trim; if (!spi->irq) { dev_err(&spi->dev, "no IRQ specified\n"); return -EINVAL; } - rc = at86rf230_get_pdata(spi, &rstn, &slp_tr); + rc = at86rf230_get_pdata(spi, &rstn, &slp_tr, &xtal_trim); if (rc < 0) { dev_err(&spi->dev, "failed to parse platform_data: %d\n", rc); return rc; @@ -1570,7 +1616,7 @@ static int at86rf230_probe(struct spi_device *spi) spi_set_drvdata(spi, lp); - rc = at86rf230_hw_init(lp); + rc = at86rf230_hw_init(lp, xtal_trim); if (rc) goto free_dev; diff --git a/include/linux/spi/at86rf230.h b/include/linux/spi/at86rf230.h index cd519a11c2c6..b63fe6f5fdc8 100644 --- a/include/linux/spi/at86rf230.h +++ b/include/linux/spi/at86rf230.h @@ -22,6 +22,7 @@ struct at86rf230_platform_data { int rstn; int slp_tr; int dig2; + u8 xtal_trim; }; #endif -- cgit v1.2.3-59-g8ed1b From c91799c50a14137ecee6d60d2f1d9ab8bc895e52 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Fri, 27 Feb 2015 09:58:30 +0100 Subject: at86rf230: add warning if edge-triggered irq While testing I experience a deadlock while using the at86rf233 on a raspberry pi. The reason was an edge triggered gpio irq because the irq triggered while irq was disabled. This issue doesn't happend on a level triggered irq because the irq will hit after calling enable_irq. This patch adds a warning that it's not recommended to use a edge-triggered irq type. Also change the examples to high-level irqtype. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- Documentation/devicetree/bindings/net/ieee802154/at86rf230.txt | 5 +++-- drivers/net/ieee802154/at86rf230.c | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/ieee802154/at86rf230.txt b/Documentation/devicetree/bindings/net/ieee802154/at86rf230.txt index 1ae5100fea14..168f1be50912 100644 --- a/Documentation/devicetree/bindings/net/ieee802154/at86rf230.txt +++ b/Documentation/devicetree/bindings/net/ieee802154/at86rf230.txt @@ -6,7 +6,8 @@ Required properties: - spi-max-frequency: maximal bus speed, should be set to 7500000 depends sync or async operation mode - reg: the chipselect index - - interrupts: the interrupt generated by the device + - interrupts: the interrupt generated by the device. Non high-level + can occur deadlocks while handling isr. Optional properties: - reset-gpio: GPIO spec for the rstn pin @@ -20,7 +21,7 @@ Example: compatible = "atmel,at86rf231"; spi-max-frequency = <7500000>; reg = <0>; - interrupts = <19 1>; + interrupts = <19 4>; interrupt-parent = <&gpio3>; xtal-trim = /bits/ 8 <0x06>; }; diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index c7a30ce71dcf..1d438bc54189 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -1321,6 +1321,10 @@ static int at86rf230_hw_init(struct at86rf230_local *lp, u8 xtal_trim) return rc; irq_type = irq_get_trigger_type(lp->spi->irq); + if (irq_type == IRQ_TYPE_EDGE_RISING || + irq_type == IRQ_TYPE_EDGE_FALLING) + dev_warn(&lp->spi->dev, + "Using edge triggered irq's are not recommended!\n"); if (irq_type == IRQ_TYPE_EDGE_FALLING || irq_type == IRQ_TYPE_LEVEL_LOW) irq_pol = IRQ_ACTIVE_LOW; -- cgit v1.2.3-59-g8ed1b From dce12391d70d24d428def2f5fc600a3b1f791ca6 Mon Sep 17 00:00:00 2001 From: Gregory Fong Date: Tue, 3 Feb 2015 18:49:26 -0800 Subject: Documentation: arm: Update for DT-only platforms The documentation specified that a machine type is mandatory and made that assumption in a few places. However, for DT-only platforms, the current advice is that no machine type should be registered, so update accordingly. Signed-off-by: Gregory Fong Signed-off-by: Jonathan Corbet --- Documentation/arm/Booting | 9 +++++++-- Documentation/arm/README | 15 +++++++++++---- 2 files changed, 18 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/arm/Booting b/Documentation/arm/Booting index 371814a36719..83c1df2fc758 100644 --- a/Documentation/arm/Booting +++ b/Documentation/arm/Booting @@ -58,13 +58,18 @@ serial format options as described in -------------------------- Existing boot loaders: OPTIONAL -New boot loaders: MANDATORY +New boot loaders: MANDATORY except for DT-only platforms The boot loader should detect the machine type its running on by some method. Whether this is a hard coded value or some algorithm that looks at the connected hardware is beyond the scope of this document. The boot loader must ultimately be able to provide a MACH_TYPE_xxx -value to the kernel. (see linux/arch/arm/tools/mach-types). +value to the kernel. (see linux/arch/arm/tools/mach-types). This +should be passed to the kernel in register r1. + +For DT-only platforms, the machine type will be determined by device +tree. set the machine type to all ones (~0). This is not strictly +necessary, but assures that it will not match any existing types. 4. Setup boot data ------------------ diff --git a/Documentation/arm/README b/Documentation/arm/README index aea34095cdcf..9d1e5b2c92e6 100644 --- a/Documentation/arm/README +++ b/Documentation/arm/README @@ -185,13 +185,20 @@ Kernel entry (head.S) board devices are used, or the device is setup, and provides that machine specific "personality." - This fine-grained machine specific selection is controlled by the machine - type ID, which acts both as a run-time and a compile-time code selection - method. + For platforms that support device tree (DT), the machine selection is + controlled at runtime by passing the device tree blob to the kernel. At + compile-time, support for the machine type must be selected. This allows for + a single multiplatform kernel build to be used for several machine types. - You can register a new machine via the web site at: + For platforms that do not use device tree, this machine selection is + controlled by the machine type ID, which acts both as a run-time and a + compile-time code selection method. You can register a new machine via the + web site at: + Note: Please do not register a machine type for DT-only platforms. If your + platform is DT-only, you do not need a registered machine type. + --- Russell King (15/03/2004) -- cgit v1.2.3-59-g8ed1b From 696156f03f97aa3be4ec5f8d85ff3465bbf404fe Mon Sep 17 00:00:00 2001 From: Pavel Kretov Date: Mon, 16 Feb 2015 20:26:17 +0300 Subject: Documentation/CodingStyle: fix tab-spaces mixture Coding style description has a irregular mixture of tabs and spaces in two places which is bad by any means and can possibly hurt somebody's sense of beauty. Signed-off-by: Pavel Kretov Signed-off-by: Jonathan Corbet --- Documentation/CodingStyle | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/CodingStyle b/Documentation/CodingStyle index 449a8a19fc21..6e0b7b99df18 100644 --- a/Documentation/CodingStyle +++ b/Documentation/CodingStyle @@ -13,7 +13,7 @@ and NOT read it. Burn them, it's a great symbolic gesture. Anyway, here goes: - Chapter 1: Indentation + Chapter 1: Indentation Tabs are 8 characters, and thus indentations are also 8 characters. There are heretic movements that try to make indentations 4 (or even 2!) @@ -503,9 +503,9 @@ values. To do the latter, you can stick the following in your .emacs file: (defun c-lineup-arglist-tabs-only (ignored) "Line up argument lists by tabs, not spaces" (let* ((anchor (c-langelem-pos c-syntactic-element)) - (column (c-langelem-2nd-pos c-syntactic-element)) - (offset (- (1+ column) anchor)) - (steps (floor offset c-basic-offset))) + (column (c-langelem-2nd-pos c-syntactic-element)) + (offset (- (1+ column) anchor)) + (steps (floor offset c-basic-offset))) (* (max steps 1) c-basic-offset))) -- cgit v1.2.3-59-g8ed1b From 09677e0ff8a115162cfa763b7ad2d753f11fce9f Mon Sep 17 00:00:00 2001 From: Pavel Kretov Date: Mon, 16 Feb 2015 20:26:18 +0300 Subject: Documentation/CodingStyle: improve text layout Try to make coding style documentation look a bit more readable and consistent with the following: - indent every code example in C to first tab-stop; - surround every code example with empty lines, both top and bottom; - remove empty lines where text looked way too spare; - do not indent examples in elisp and kconfig; - do not do any non-whitespace changes. Signed-off-by: Pavel Kretov Signed-off-by: Jonathan Corbet --- Documentation/CodingStyle | 141 +++++++++++++++++++++++----------------------- 1 file changed, 72 insertions(+), 69 deletions(-) (limited to 'Documentation') diff --git a/Documentation/CodingStyle b/Documentation/CodingStyle index 6e0b7b99df18..e55accfca276 100644 --- a/Documentation/CodingStyle +++ b/Documentation/CodingStyle @@ -56,7 +56,6 @@ instead of "double-indenting" the "case" labels. E.g.: break; } - Don't put multiple statements on a single line unless you have something to hide: @@ -156,25 +155,25 @@ comments on. Do not unnecessarily use braces where a single statement will do. -if (condition) - action(); + if (condition) + action(); and -if (condition) - do_this(); -else - do_that(); + if (condition) + do_this(); + else + do_that(); This does not apply if only one branch of a conditional statement is a single statement; in the latter case use braces in both branches: -if (condition) { - do_this(); - do_that(); -} else { - otherwise(); -} + if (condition) { + do_this(); + do_that(); + } else { + otherwise(); + } 3.1: Spaces @@ -186,8 +185,11 @@ although they are not required in the language, as in: "sizeof info" after "struct fileinfo info;" is declared). So use a space after these keywords: + if, switch, case, for, do, while + but not with sizeof, typeof, alignof, or __attribute__. E.g., + s = sizeof(struct file); Do not add spaces around (inside) parenthesized expressions. This example is @@ -209,12 +211,15 @@ such as any of these: = + - < > * / % | & ^ <= >= == != ? : but no space after unary operators: + & * + - ~ ! sizeof typeof alignof __attribute__ defined no space before the postfix increment & decrement unary operators: + ++ -- no space after the prefix increment & decrement unary operators: + ++ -- and no space around the '.' and "->" structure member operators. @@ -268,13 +273,11 @@ See chapter 6 (Functions). Chapter 5: Typedefs Please don't use things like "vps_t". - It's a _mistake_ to use typedef for structures and pointers. When you see a vps_t a; in the source, what does it mean? - In contrast, if it says struct virtual_container *a; @@ -372,11 +375,11 @@ In source files, separate functions with one blank line. If the function is exported, the EXPORT* macro for it should follow immediately after the closing function brace line. E.g.: -int system_is_up(void) -{ - return system_state == SYSTEM_RUNNING; -} -EXPORT_SYMBOL(system_is_up); + int system_is_up(void) + { + return system_state == SYSTEM_RUNNING; + } + EXPORT_SYMBOL(system_is_up); In function prototypes, include parameter names with their data types. Although this is not required by the C language, it is preferred in Linux @@ -405,34 +408,34 @@ The rationale for using gotos is: modifications are prevented - saves the compiler work to optimize redundant code away ;) -int fun(int a) -{ - int result = 0; - char *buffer; - - buffer = kmalloc(SIZE, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - if (condition1) { - while (loop1) { - ... + int fun(int a) + { + int result = 0; + char *buffer; + + buffer = kmalloc(SIZE, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + if (condition1) { + while (loop1) { + ... + } + result = 1; + goto out_buffer; } - result = 1; - goto out_buffer; + ... + out_buffer: + kfree(buffer); + return result; } - ... -out_buffer: - kfree(buffer); - return result; -} A common type of bug to be aware of it "one err bugs" which look like this: -err: - kfree(foo->bar); - kfree(foo); - return ret; + err: + kfree(foo->bar); + kfree(foo); + return ret; The bug in this code is that on some exit paths "foo" is NULL. Normally the fix for this is to split it up into two error labels "err_bar:" and "err_foo:". @@ -612,7 +615,7 @@ have a reference count on it, you almost certainly have a bug. Names of macros defining constants and labels in enums are capitalized. -#define CONSTANT 0x12345 + #define CONSTANT 0x12345 Enums are preferred when defining several related constants. @@ -623,28 +626,28 @@ Generally, inline functions are preferable to macros resembling functions. Macros with multiple statements should be enclosed in a do - while block: -#define macrofun(a, b, c) \ - do { \ - if (a == 5) \ - do_this(b, c); \ - } while (0) + #define macrofun(a, b, c) \ + do { \ + if (a == 5) \ + do_this(b, c); \ + } while (0) Things to avoid when using macros: 1) macros that affect control flow: -#define FOO(x) \ - do { \ - if (blah(x) < 0) \ - return -EBUGGERED; \ - } while(0) + #define FOO(x) \ + do { \ + if (blah(x) < 0) \ + return -EBUGGERED; \ + } while(0) is a _very_ bad idea. It looks like a function call but exits the "calling" function; don't break the internal parsers of those who will read the code. 2) macros that depend on having a local variable with a magic name: -#define FOO(val) bar(index, val) + #define FOO(val) bar(index, val) might look like a good thing, but it's confusing as hell when one reads the code and it's prone to breakage from seemingly innocent changes. @@ -656,8 +659,8 @@ bite you if somebody e.g. turns FOO into an inline function. must enclose the expression in parentheses. Beware of similar issues with macros using parameters. -#define CONSTANT 0x4000 -#define CONSTEXP (CONSTANT | 3) + #define CONSTANT 0x4000 + #define CONSTEXP (CONSTANT | 3) The cpp manual deals with macros exhaustively. The gcc internals manual also covers RTL which is used frequently with assembly language in the kernel. @@ -796,11 +799,11 @@ you should use, rather than explicitly coding some variant of them yourself. For example, if you need to calculate the length of an array, take advantage of the macro - #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) Similarly, if you need to calculate the size of some structure member, use - #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f)) + #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f)) There are also min() and max() macros that do strict type checking if you need them. Feel free to peruse that header file to see what else is already @@ -813,19 +816,19 @@ Some editors can interpret configuration information embedded in source files, indicated with special markers. For example, emacs interprets lines marked like this: --*- mode: c -*- + -*- mode: c -*- Or like this: -/* -Local Variables: -compile-command: "gcc -DMAGIC_DEBUG_FLAG foo.c" -End: -*/ + /* + Local Variables: + compile-command: "gcc -DMAGIC_DEBUG_FLAG foo.c" + End: + */ Vim interprets markers that look like this: -/* vim:set sw=8 noet */ + /* vim:set sw=8 noet */ Do not include any of these in source files. People have their own personal editor configurations, and your source files should not override them. This @@ -902,9 +905,9 @@ At the end of any non-trivial #if or #ifdef block (more than a few lines), place a comment after the #endif on the same line, noting the conditional expression used. For instance: -#ifdef CONFIG_SOMETHING -... -#endif /* CONFIG_SOMETHING */ + #ifdef CONFIG_SOMETHING + ... + #endif /* CONFIG_SOMETHING */ Appendix I: References -- cgit v1.2.3-59-g8ed1b From 433b89cfb40f6bb6e6b6c899d06e40dd4f2ed100 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 22 Feb 2015 00:18:49 +0100 Subject: Doc/memory-hotplug.txt: corrections and callback function prototype Documentation/memory-hotplug.txt describes that a callback function can be added to the notification chain by calling hotplug_memory_notifier(). The function prototype of the callback function is mssing. This missing information is added by the patch. The description of the arguments of the callback function is reworked. The constants for the event types are corrected. The possible return values are explained. Signed-off-by: Heinrich Schuchardt Signed-off-by: Jonathan Corbet --- Documentation/memory-hotplug.txt | 45 +++++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 10 deletions(-) (limited to 'Documentation') diff --git a/Documentation/memory-hotplug.txt b/Documentation/memory-hotplug.txt index ea03abfc97e9..c5a064508a3c 100644 --- a/Documentation/memory-hotplug.txt +++ b/Documentation/memory-hotplug.txt @@ -359,38 +359,51 @@ Need more implementation yet.... -------------------------------- 8. Memory hotplug event notifier -------------------------------- -Memory hotplug has event notifier. There are 6 types of notification. +Hotplugging events are sent to a notification queue. -MEMORY_GOING_ONLINE +There are six types of notification defined in include/linux/memory.h: + +MEM_GOING_ONLINE Generated before new memory becomes available in order to be able to prepare subsystems to handle memory. The page allocator is still unable to allocate from the new memory. -MEMORY_CANCEL_ONLINE +MEM_CANCEL_ONLINE Generated if MEMORY_GOING_ONLINE fails. -MEMORY_ONLINE +MEM_ONLINE Generated when memory has successfully brought online. The callback may allocate pages from the new memory. -MEMORY_GOING_OFFLINE +MEM_GOING_OFFLINE Generated to begin the process of offlining memory. Allocations are no longer possible from the memory but some of the memory to be offlined is still in use. The callback can be used to free memory known to a subsystem from the indicated memory block. -MEMORY_CANCEL_OFFLINE +MEM_CANCEL_OFFLINE Generated if MEMORY_GOING_OFFLINE fails. Memory is available again from the memory block that we attempted to offline. -MEMORY_OFFLINE +MEM_OFFLINE Generated after offlining memory is complete. -A callback routine can be registered by +A callback routine can be registered by calling + hotplug_memory_notifier(callback_func, priority) -The second argument of callback function (action) is event types of above. -The third argument is passed by pointer of struct memory_notify. +Callback functions with higher values of priority are called before callback +functions with lower values. + +A callback function must have the following prototype: + + int callback_func( + struct notifier_block *self, unsigned long action, void *arg); + +The first argument of the callback function (self) is a pointer to the block +of the notifier chain that points to the callback function itself. +The second argument (action) is one of the event types described above. +The third argument (arg) passes a pointer of struct memory_notify. struct memory_notify { unsigned long start_pfn; @@ -412,6 +425,18 @@ node loses all memory. If this is -1, then nodemask status is not changed. If status_changed_nid* >= 0, callback should create/discard structures for the node if necessary. +The callback routine shall return one of the values +NOTIFY_DONE, NOTIFY_OK, NOTIFY_BAD, NOTIFY_STOP +defined in include/linux/notifier.h + +NOTIFY_DONE and NOTIFY_OK have no effect on the further processing. + +NOTIFY_BAD is used as response to the MEM_GOING_ONLINE, MEM_GOING_OFFLINE, +MEM_ONLINE, or MEM_OFFLINE action to cancel hotplugging. It stops +further processing of the notification queue. + +NOTIFY_STOP stops further processing of the notification queue. + -------------- 9. Future Work -------------- -- cgit v1.2.3-59-g8ed1b From 3a4562f756617b4b210fc487bfe23853a450d3c1 Mon Sep 17 00:00:00 2001 From: Tomeu Vizoso Date: Thu, 12 Feb 2015 09:41:56 +0100 Subject: ASoC: tegra: Add sink for the internal mic to tegra_max98090 Also adds a control for the pin of the internal mic, so userspace can apply policy when the state of the external mic jack changes. Signed-off-by: Tomeu Vizoso Acked-by: Stephen Warren Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max98090.txt | 1 + sound/soc/tegra/tegra_max98090.c | 2 ++ 2 files changed, 3 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max98090.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max98090.txt index c949abc2992f..c3495beba358 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max98090.txt +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max98090.txt @@ -18,6 +18,7 @@ Required properties: * Headphones * Speakers * Mic Jack + * Int Mic - nvidia,i2s-controller : The phandle of the Tegra I2S controller that's connected to the CODEC. diff --git a/sound/soc/tegra/tegra_max98090.c b/sound/soc/tegra/tegra_max98090.c index 8df71a436f11..29ea87cd852e 100644 --- a/sound/soc/tegra/tegra_max98090.c +++ b/sound/soc/tegra/tegra_max98090.c @@ -133,11 +133,13 @@ static const struct snd_soc_dapm_widget tegra_max98090_dapm_widgets[] = { SND_SOC_DAPM_HP("Headphones", NULL), SND_SOC_DAPM_SPK("Speakers", NULL), SND_SOC_DAPM_MIC("Mic Jack", NULL), + SND_SOC_DAPM_MIC("Int Mic", NULL), }; static const struct snd_kcontrol_new tegra_max98090_controls[] = { SOC_DAPM_PIN_SWITCH("Headphones"), SOC_DAPM_PIN_SWITCH("Speakers"), + SOC_DAPM_PIN_SWITCH("Int Mic"), }; static int tegra_max98090_asoc_init(struct snd_soc_pcm_runtime *rtd) -- cgit v1.2.3-59-g8ed1b From 0cd1b0c3adaac2f9e8b5d2e739bf63a42fbf7ff2 Mon Sep 17 00:00:00 2001 From: Olliver Schinagl Date: Wed, 21 Jan 2015 13:33:47 -0800 Subject: leds: Let the binding document example for leds-gpio follow the gpio bindings In the gpio bindings documents it is requested to use the marco's in include/dt-bindings/gpio/gpio.h whenever possible. The gpios in the led drivers don't seem to form an exception, so update the example in the document bindings. Signed-off-by: Olliver Schinagl Acked-by: Rob Herring Acked-by: Linus Walleij Signed-off-by: Bryan Wu --- Documentation/devicetree/bindings/leds/leds-gpio.txt | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/leds/leds-gpio.txt b/Documentation/devicetree/bindings/leds/leds-gpio.txt index f77148f372ea..fea1ebfe24a9 100644 --- a/Documentation/devicetree/bindings/leds/leds-gpio.txt +++ b/Documentation/devicetree/bindings/leds/leds-gpio.txt @@ -26,16 +26,18 @@ LED sub-node properties: Examples: +#include + leds { compatible = "gpio-leds"; hdd { label = "IDE Activity"; - gpios = <&mcu_pio 0 1>; /* Active low */ + gpios = <&mcu_pio 0 GPIO_ACTIVE_LOW>; linux,default-trigger = "ide-disk"; }; fault { - gpios = <&mcu_pio 1 0>; + gpios = <&mcu_pio 1 GPIO_ACTIVE_HIGH>; /* Keep LED on if BIOS detected hardware fault */ default-state = "keep"; }; @@ -44,11 +46,11 @@ leds { run-control { compatible = "gpio-leds"; red { - gpios = <&mpc8572 6 0>; + gpios = <&mpc8572 6 GPIO_ACTIVE_HIGH>; default-state = "off"; }; green { - gpios = <&mpc8572 7 0>; + gpios = <&mpc8572 7 GPIO_ACTIVE_HIGH>; default-state = "on"; }; }; @@ -57,7 +59,7 @@ leds { compatible = "gpio-leds"; charger-led { - gpios = <&gpio1 2 0>; + gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>; linux,default-trigger = "max8903-charger-charging"; retain-state-suspended; }; -- cgit v1.2.3-59-g8ed1b From 0c7e67a928ac5328d30a0638adec771511dc7074 Mon Sep 17 00:00:00 2001 From: Scott Branden Date: Sat, 28 Feb 2015 13:33:30 -0800 Subject: Input: add driver for Broadcom keypad controller Broadcom Keypad controller is used to interface a SoC with a matrix-type keypad device. The keypad controller supports multiple row and column lines. A key can be placed at each intersection of a unique row and a unique column. The keypad controller can sense a key-press and key-release and report the event using an interrupt to the CPU. Reviewed-by: Ray Jui Signed-off-by: Scott Branden Signed-off-by: Dmitry Torokhov --- .../devicetree/bindings/input/brcm,bcm-keypad.txt | 108 +++++ drivers/input/keyboard/Kconfig | 11 + drivers/input/keyboard/Makefile | 1 + drivers/input/keyboard/bcm-keypad.c | 458 +++++++++++++++++++++ 4 files changed, 578 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt create mode 100644 drivers/input/keyboard/bcm-keypad.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt b/Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt new file mode 100644 index 000000000000..b77f50bd6403 --- /dev/null +++ b/Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt @@ -0,0 +1,108 @@ +* Broadcom Keypad Controller device tree bindings + +Broadcom Keypad controller is used to interface a SoC with a matrix-type +keypad device. The keypad controller supports multiple row and column lines. +A key can be placed at each intersection of a unique row and a unique column. +The keypad controller can sense a key-press and key-release and report the +event using a interrupt to the cpu. + +This binding is based on the matrix-keymap binding with the following +changes: + +keypad,num-rows and keypad,num-columns are required. + +Required SoC Specific Properties: +- compatible: should be "brcm,bcm-keypad" + +- reg: physical base address of the controller and length of memory mapped + region. + +- interrupts: The interrupt number to the cpu. + +Board Specific Properties: +- keypad,num-rows: Number of row lines connected to the keypad + controller. + +- keypad,num-columns: Number of column lines connected to the + keypad controller. + +- col-debounce-filter-period: The debounce period for the Column filter. + + KEYPAD_DEBOUNCE_1_ms = 0 + KEYPAD_DEBOUNCE_2_ms = 1 + KEYPAD_DEBOUNCE_4_ms = 2 + KEYPAD_DEBOUNCE_8_ms = 3 + KEYPAD_DEBOUNCE_16_ms = 4 + KEYPAD_DEBOUNCE_32_ms = 5 + KEYPAD_DEBOUNCE_64_ms = 6 + KEYPAD_DEBOUNCE_128_ms = 7 + +- status-debounce-filter-period: The debounce period for the Status filter. + + KEYPAD_DEBOUNCE_1_ms = 0 + KEYPAD_DEBOUNCE_2_ms = 1 + KEYPAD_DEBOUNCE_4_ms = 2 + KEYPAD_DEBOUNCE_8_ms = 3 + KEYPAD_DEBOUNCE_16_ms = 4 + KEYPAD_DEBOUNCE_32_ms = 5 + KEYPAD_DEBOUNCE_64_ms = 6 + KEYPAD_DEBOUNCE_128_ms = 7 + +- row-output-enabled: An optional property indicating whether the row or + column is being used as output. If specified the row is being used + as the output. Else defaults to column. + +- pull-up-enabled: An optional property indicating the Keypad scan mode. + If specified implies the keypad scan pull-up has been enabled. + +- autorepeat: Boolean, Enable auto repeat feature of Linux input + subsystem (optional). + +- linux,keymap: The keymap for keys as described in the binding document + devicetree/bindings/input/matrix-keymap.txt. + +Example: +#include "dt-bindings/input/input.h" + +/ { + keypad: keypad@180ac000 { + /* Required SoC specific properties */ + compatible = "brcm,bcm-keypad"; + + /* Required Board specific properties */ + keypad,num-rows = <5>; + keypad,num-columns = <5>; + status = "okay"; + + linux,keymap = ; + + /* Optional board specific properties */ + col-debounce-filter-period = <5>; + row-output-enabled; + pull-up-enabled; + + }; +}; diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index a89ba7cb96f1..17de1dcac637 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -686,4 +686,15 @@ config KEYBOARD_CAP11XX To compile this driver as a module, choose M here: the module will be called cap11xx. +config KEYBOARD_BCM + tristate "Broadcom keypad driver" + depends on OF && HAVE_CLK + select INPUT_MATRIXKMAP + default ARCH_BCM_CYGNUS + help + Say Y here if you want to use Broadcom keypad. + + To compile this driver as a module, choose M here: the + module will be called bcm-keypad. + endif diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 470767884bd8..a648f6c6bbfa 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_KEYBOARD_ADP5589) += adp5589-keys.o obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o +obj-$(CONFIG_KEYBOARD_BCM) += bcm-keypad.o obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o obj-$(CONFIG_KEYBOARD_CAP11XX) += cap11xx.o obj-$(CONFIG_KEYBOARD_CLPS711X) += clps711x-keypad.o diff --git a/drivers/input/keyboard/bcm-keypad.c b/drivers/input/keyboard/bcm-keypad.c new file mode 100644 index 000000000000..86a8b723ae15 --- /dev/null +++ b/drivers/input/keyboard/bcm-keypad.c @@ -0,0 +1,458 @@ +/* + * Copyright (C) 2014 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEFAULT_CLK_HZ 31250 +#define MAX_ROWS 8 +#define MAX_COLS 8 + +/* Register/field definitions */ +#define KPCR_OFFSET 0x00000080 +#define KPCR_MODE 0x00000002 +#define KPCR_MODE_SHIFT 1 +#define KPCR_MODE_MASK 1 +#define KPCR_ENABLE 0x00000001 +#define KPCR_STATUSFILTERENABLE 0x00008000 +#define KPCR_STATUSFILTERTYPE_SHIFT 12 +#define KPCR_COLFILTERENABLE 0x00000800 +#define KPCR_COLFILTERTYPE_SHIFT 8 +#define KPCR_ROWWIDTH_SHIFT 20 +#define KPCR_COLUMNWIDTH_SHIFT 16 + +#define KPIOR_OFFSET 0x00000084 +#define KPIOR_ROWOCONTRL_SHIFT 24 +#define KPIOR_ROWOCONTRL_MASK 0xFF000000 +#define KPIOR_COLUMNOCONTRL_SHIFT 16 +#define KPIOR_COLUMNOCONTRL_MASK 0x00FF0000 +#define KPIOR_COLUMN_IO_DATA_SHIFT 0 + +#define KPEMR0_OFFSET 0x00000090 +#define KPEMR1_OFFSET 0x00000094 +#define KPEMR2_OFFSET 0x00000098 +#define KPEMR3_OFFSET 0x0000009C +#define KPEMR_EDGETYPE_BOTH 3 + +#define KPSSR0_OFFSET 0x000000A0 +#define KPSSR1_OFFSET 0x000000A4 +#define KPSSRN_OFFSET(reg_n) (KPSSR0_OFFSET + 4 * (reg_n)) +#define KPIMR0_OFFSET 0x000000B0 +#define KPIMR1_OFFSET 0x000000B4 +#define KPICR0_OFFSET 0x000000B8 +#define KPICR1_OFFSET 0x000000BC +#define KPICRN_OFFSET(reg_n) (KPICR0_OFFSET + 4 * (reg_n)) +#define KPISR0_OFFSET 0x000000C0 +#define KPISR1_OFFSET 0x000000C4 + +#define KPCR_STATUSFILTERTYPE_MAX 7 +#define KPCR_COLFILTERTYPE_MAX 7 + +/* Macros to determine the row/column from a bit that is set in SSR0/1. */ +#define BIT_TO_ROW_SSRN(bit_nr, reg_n) (((bit_nr) >> 3) + 4 * (reg_n)) +#define BIT_TO_COL(bit_nr) ((bit_nr) % 8) + +/* Structure representing various run-time entities */ +struct bcm_kp { + void __iomem *base; + int irq; + struct clk *clk; + struct input_dev *input_dev; + unsigned long last_state[2]; + unsigned int n_rows; + unsigned int n_cols; + u32 kpcr; + u32 kpior; + u32 kpemr; + u32 imr0_val; + u32 imr1_val; +}; + +/* + * Returns the keycode from the input device keymap given the row and + * column. + */ +static int bcm_kp_get_keycode(struct bcm_kp *kp, int row, int col) +{ + unsigned int row_shift = get_count_order(kp->n_cols); + unsigned short *keymap = kp->input_dev->keycode; + + return keymap[MATRIX_SCAN_CODE(row, col, row_shift)]; +} + +static void bcm_kp_report_keys(struct bcm_kp *kp, int reg_num, int pull_mode) +{ + unsigned long state, change; + int bit_nr; + int key_press; + int row, col; + unsigned int keycode; + + /* Clear interrupts */ + writel(0xFFFFFFFF, kp->base + KPICRN_OFFSET(reg_num)); + + state = readl(kp->base + KPSSRN_OFFSET(reg_num)); + change = kp->last_state[reg_num] ^ state; + kp->last_state[reg_num] = state; + + for_each_set_bit(bit_nr, &change, BITS_PER_LONG) { + key_press = state & BIT(bit_nr); + /* The meaning of SSR register depends on pull mode. */ + key_press = pull_mode ? !key_press : key_press; + row = BIT_TO_ROW_SSRN(bit_nr, reg_num); + col = BIT_TO_COL(bit_nr); + keycode = bcm_kp_get_keycode(kp, row, col); + input_report_key(kp->input_dev, keycode, key_press); + } +} + +static irqreturn_t bcm_kp_isr_thread(int irq, void *dev_id) +{ + struct bcm_kp *kp = dev_id; + int pull_mode = (kp->kpcr >> KPCR_MODE_SHIFT) & KPCR_MODE_MASK; + int reg_num; + + for (reg_num = 0; reg_num <= 1; reg_num++) + bcm_kp_report_keys(kp, reg_num, pull_mode); + + input_sync(kp->input_dev); + + return IRQ_HANDLED; +} + +static int bcm_kp_start(struct bcm_kp *kp) +{ + int error; + + if (kp->clk) { + error = clk_prepare_enable(kp->clk); + if (error) + return error; + } + + writel(kp->kpior, kp->base + KPIOR_OFFSET); + + writel(kp->imr0_val, kp->base + KPIMR0_OFFSET); + writel(kp->imr1_val, kp->base + KPIMR1_OFFSET); + + writel(kp->kpemr, kp->base + KPEMR0_OFFSET); + writel(kp->kpemr, kp->base + KPEMR1_OFFSET); + writel(kp->kpemr, kp->base + KPEMR2_OFFSET); + writel(kp->kpemr, kp->base + KPEMR3_OFFSET); + + writel(0xFFFFFFFF, kp->base + KPICR0_OFFSET); + writel(0xFFFFFFFF, kp->base + KPICR1_OFFSET); + + kp->last_state[0] = readl(kp->base + KPSSR0_OFFSET); + kp->last_state[0] = readl(kp->base + KPSSR1_OFFSET); + + writel(kp->kpcr | KPCR_ENABLE, kp->base + KPCR_OFFSET); + + return 0; +} + +static void bcm_kp_stop(const struct bcm_kp *kp) +{ + u32 val; + + val = readl(kp->base + KPCR_OFFSET); + val &= ~KPCR_ENABLE; + writel(0, kp->base + KPCR_OFFSET); + writel(0, kp->base + KPIMR0_OFFSET); + writel(0, kp->base + KPIMR1_OFFSET); + writel(0xFFFFFFFF, kp->base + KPICR0_OFFSET); + writel(0xFFFFFFFF, kp->base + KPICR1_OFFSET); + + if (kp->clk) + clk_disable_unprepare(kp->clk); +} + +static int bcm_kp_open(struct input_dev *dev) +{ + struct bcm_kp *kp = input_get_drvdata(dev); + + return bcm_kp_start(kp); +} + +static void bcm_kp_close(struct input_dev *dev) +{ + struct bcm_kp *kp = input_get_drvdata(dev); + + bcm_kp_stop(kp); +} + +static int bcm_kp_matrix_key_parse_dt(struct bcm_kp *kp) +{ + struct device *dev = kp->input_dev->dev.parent; + struct device_node *np = dev->of_node; + int error; + unsigned int dt_val; + unsigned int i; + unsigned int num_rows, col_mask, rows_set; + + /* Initialize the KPCR Keypad Configuration Register */ + kp->kpcr = KPCR_STATUSFILTERENABLE | KPCR_COLFILTERENABLE; + + error = matrix_keypad_parse_of_params(dev, &kp->n_rows, &kp->n_cols); + if (error) { + dev_err(dev, "failed to parse kp params\n"); + return error; + } + + /* Set row width for the ASIC block. */ + kp->kpcr |= (kp->n_rows - 1) << KPCR_ROWWIDTH_SHIFT; + + /* Set column width for the ASIC block. */ + kp->kpcr |= (kp->n_cols - 1) << KPCR_COLUMNWIDTH_SHIFT; + + /* Configure the IMR registers */ + + /* + * IMR registers contain interrupt enable bits for 8x8 matrix + * IMR0 register format: + * IMR1 register format: + */ + col_mask = (1 << (kp->n_cols)) - 1; + num_rows = kp->n_rows; + + /* Set column bits in rows 0 to 3 in IMR0 */ + kp->imr0_val = col_mask; + + rows_set = 1; + while (--num_rows && rows_set++ < 4) + kp->imr0_val |= kp->imr0_val << MAX_COLS; + + /* Set column bits in rows 4 to 7 in IMR1 */ + kp->imr1_val = 0; + if (num_rows) { + kp->imr1_val = col_mask; + while (--num_rows) + kp->imr1_val |= kp->imr1_val << MAX_COLS; + } + + /* Initialize the KPEMR Keypress Edge Mode Registers */ + /* Trigger on both edges */ + kp->kpemr = 0; + for (i = 0; i <= 30; i += 2) + kp->kpemr |= (KPEMR_EDGETYPE_BOTH << i); + + /* + * Obtain the Status filter debounce value and verify against the + * possible values specified in the DT binding. + */ + of_property_read_u32(np, "status-debounce-filter-period", &dt_val); + + if (dt_val > KPCR_STATUSFILTERTYPE_MAX) { + dev_err(dev, "Invalid Status filter debounce value %d\n", + dt_val); + return -EINVAL; + } + + kp->kpcr |= dt_val << KPCR_STATUSFILTERTYPE_SHIFT; + + /* + * Obtain the Column filter debounce value and verify against the + * possible values specified in the DT binding. + */ + of_property_read_u32(np, "col-debounce-filter-period", &dt_val); + + if (dt_val > KPCR_COLFILTERTYPE_MAX) { + dev_err(dev, "Invalid Column filter debounce value %d\n", + dt_val); + return -EINVAL; + } + + kp->kpcr |= dt_val << KPCR_COLFILTERTYPE_SHIFT; + + /* + * Determine between the row and column, + * which should be configured as output. + */ + if (of_property_read_bool(np, "row-output-enabled")) { + /* + * Set RowOContrl or ColumnOContrl in KPIOR + * to the number of pins to drive as outputs + */ + kp->kpior = ((1 << kp->n_rows) - 1) << + KPIOR_ROWOCONTRL_SHIFT; + } else { + kp->kpior = ((1 << kp->n_cols) - 1) << + KPIOR_COLUMNOCONTRL_SHIFT; + } + + /* + * Determine if the scan pull up needs to be enabled + */ + if (of_property_read_bool(np, "pull-up-enabled")) + kp->kpcr |= KPCR_MODE; + + dev_dbg(dev, "n_rows=%d n_col=%d kpcr=%x kpior=%x kpemr=%x\n", + kp->n_rows, kp->n_cols, + kp->kpcr, kp->kpior, kp->kpemr); + + return 0; +} + + +static int bcm_kp_probe(struct platform_device *pdev) +{ + struct bcm_kp *kp; + struct input_dev *input_dev; + struct resource *res; + int error; + + kp = devm_kzalloc(&pdev->dev, sizeof(*kp), GFP_KERNEL); + if (!kp) + return -ENOMEM; + + input_dev = devm_input_allocate_device(&pdev->dev); + if (!input_dev) { + dev_err(&pdev->dev, "failed to allocate the input device\n"); + return -ENOMEM; + } + + __set_bit(EV_KEY, input_dev->evbit); + + /* Enable auto repeat feature of Linux input subsystem */ + if (of_property_read_bool(pdev->dev.of_node, "autorepeat")) + __set_bit(EV_REP, input_dev->evbit); + + input_dev->name = pdev->name; + input_dev->phys = "keypad/input0"; + input_dev->dev.parent = &pdev->dev; + input_dev->open = bcm_kp_open; + input_dev->close = bcm_kp_close; + + input_dev->id.bustype = BUS_HOST; + input_dev->id.vendor = 0x0001; + input_dev->id.product = 0x0001; + input_dev->id.version = 0x0100; + + input_set_drvdata(input_dev, kp); + + kp->input_dev = input_dev; + + platform_set_drvdata(pdev, kp); + + error = bcm_kp_matrix_key_parse_dt(kp); + if (error) + return error; + + error = matrix_keypad_build_keymap(NULL, NULL, + kp->n_rows, kp->n_cols, + NULL, input_dev); + if (error) { + dev_err(&pdev->dev, "failed to build keymap\n"); + return error; + } + + /* Get the KEYPAD base address */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "Missing keypad base address resource\n"); + return -ENODEV; + } + + kp->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(kp->base)) + return PTR_ERR(kp->base); + + /* Enable clock */ + kp->clk = devm_clk_get(&pdev->dev, "peri_clk"); + if (IS_ERR(kp->clk)) { + error = PTR_ERR(kp->clk); + if (error != -ENOENT) { + if (error != -EPROBE_DEFER) + dev_err(&pdev->dev, "Failed to get clock\n"); + return error; + } + dev_dbg(&pdev->dev, + "No clock specified. Assuming it's enabled\n"); + kp->clk = NULL; + } else { + unsigned int desired_rate; + long actual_rate; + + error = of_property_read_u32(pdev->dev.of_node, + "clock-frequency", &desired_rate); + if (error < 0) + desired_rate = DEFAULT_CLK_HZ; + + actual_rate = clk_round_rate(kp->clk, desired_rate); + if (actual_rate <= 0) + return -EINVAL; + + error = clk_set_rate(kp->clk, actual_rate); + if (error) + return error; + + error = clk_prepare_enable(kp->clk); + if (error) + return error; + } + + /* Put the kp into a known sane state */ + bcm_kp_stop(kp); + + kp->irq = platform_get_irq(pdev, 0); + if (kp->irq < 0) { + dev_err(&pdev->dev, "no IRQ specified\n"); + return -EINVAL; + } + + error = devm_request_threaded_irq(&pdev->dev, kp->irq, + NULL, bcm_kp_isr_thread, + IRQF_ONESHOT, pdev->name, kp); + if (error) { + dev_err(&pdev->dev, "failed to request IRQ\n"); + return error; + } + + error = input_register_device(input_dev); + if (error) { + dev_err(&pdev->dev, "failed to register input device\n"); + return error; + } + + return 0; +} + +static const struct of_device_id bcm_kp_of_match[] = { + { .compatible = "brcm,bcm-keypad" }, + { }, +}; +MODULE_DEVICE_TABLE(of, bcm_kp_of_match); + +static struct platform_driver bcm_kp_device_driver = { + .probe = bcm_kp_probe, + .driver = { + .name = "bcm-keypad", + .of_match_table = of_match_ptr(bcm_kp_of_match), + } +}; + +module_platform_driver(bcm_kp_device_driver); + +MODULE_AUTHOR("Broadcom Corporation"); +MODULE_DESCRIPTION("BCM Keypad Driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-59-g8ed1b From 49010336290f4e3e4249c43bff1a1ff065c8f94e Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 25 Feb 2015 15:37:13 +0000 Subject: mfd: arizona: Move useful defines into a dt-binding include Move parts of linux/mfd/arizona/pdata.h and gpio.h into a new file in the dt-binding directory for use by device tree bindings. This also makes gpio.h redundant so remove it in the process. Signed-off-by: Charles Keepax Acked-by: Mark Brown Acked-by: Rob Herring Signed-off-by: Lee Jones --- Documentation/devicetree/bindings/mfd/arizona.txt | 20 ++--- include/dt-bindings/mfd/arizona.h | 93 ++++++++++++++++++++++ include/linux/mfd/arizona/gpio.h | 96 ----------------------- include/linux/mfd/arizona/pdata.h | 22 +----- sound/soc/codecs/arizona.c | 1 - 5 files changed, 105 insertions(+), 127 deletions(-) create mode 100644 include/dt-bindings/mfd/arizona.h delete mode 100644 include/linux/mfd/arizona/gpio.h (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mfd/arizona.txt b/Documentation/devicetree/bindings/mfd/arizona.txt index 87c878b1a17b..af8646ffc336 100644 --- a/Documentation/devicetree/bindings/mfd/arizona.txt +++ b/Documentation/devicetree/bindings/mfd/arizona.txt @@ -43,11 +43,11 @@ Optional properties: - wlf,reset : GPIO specifier for the GPIO controlling /RESET - wlf,ldoena : GPIO specifier for the GPIO controlling LDOENA - - wlf,gpio-defaults : A list of GPIO configuration register values. If - absent, no configuration of these registers is performed. If any - entry has a value that is out of range for a 16 bit register then - the chip default will be used. If present exactly five values must - be specified. + - wlf,gpio-defaults : A list of GPIO configuration register values. Defines + for the appropriate values can found in . If + absent, no configuration of these registers is performed. If any entry has + a value that is out of range for a 16 bit register then the chip default + will be used. If present exactly five values must be specified. - wlf,inmode : A list of INn_MODE register values, where n is the number of input signals. Valid values are 0 (Differential), 1 (Single-ended) and @@ -80,10 +80,10 @@ codec: wm5102@1a { #gpio-cells = <2>; wlf,gpio-defaults = < - 0x00000000 /* AIF1TXLRCLK */ - 0xffffffff - 0xffffffff - 0xffffffff - 0xffffffff + ARIZONA_GP_FN_TXLRCLK + ARIZONA_GP_DEFAULT + ARIZONA_GP_DEFAULT + ARIZONA_GP_DEFAULT + ARIZONA_GP_DEFAULT >; }; diff --git a/include/dt-bindings/mfd/arizona.h b/include/dt-bindings/mfd/arizona.h new file mode 100644 index 000000000000..c7af7c7ef793 --- /dev/null +++ b/include/dt-bindings/mfd/arizona.h @@ -0,0 +1,93 @@ +/* + * Device Tree defines for Arizona devices + * + * Copyright 2015 Cirrus Logic Inc. + * + * Author: Charles Keepax + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _DT_BINDINGS_MFD_ARIZONA_H +#define _DT_BINDINGS_MFD_ARIZONA_H + +/* GPIO Function Definitions */ +#define ARIZONA_GP_FN_TXLRCLK 0x00 +#define ARIZONA_GP_FN_GPIO 0x01 +#define ARIZONA_GP_FN_IRQ1 0x02 +#define ARIZONA_GP_FN_IRQ2 0x03 +#define ARIZONA_GP_FN_OPCLK 0x04 +#define ARIZONA_GP_FN_FLL1_OUT 0x05 +#define ARIZONA_GP_FN_FLL2_OUT 0x06 +#define ARIZONA_GP_FN_PWM1 0x08 +#define ARIZONA_GP_FN_PWM2 0x09 +#define ARIZONA_GP_FN_SYSCLK_UNDERCLOCKED 0x0A +#define ARIZONA_GP_FN_ASYNCCLK_UNDERCLOCKED 0x0B +#define ARIZONA_GP_FN_FLL1_LOCK 0x0C +#define ARIZONA_GP_FN_FLL2_LOCK 0x0D +#define ARIZONA_GP_FN_FLL1_CLOCK_OK 0x0F +#define ARIZONA_GP_FN_FLL2_CLOCK_OK 0x10 +#define ARIZONA_GP_FN_HEADPHONE_DET 0x12 +#define ARIZONA_GP_FN_MIC_DET 0x13 +#define ARIZONA_GP_FN_WSEQ_STATUS 0x15 +#define ARIZONA_GP_FN_CIF_ADDRESS_ERROR 0x16 +#define ARIZONA_GP_FN_ASRC1_LOCK 0x1A +#define ARIZONA_GP_FN_ASRC2_LOCK 0x1B +#define ARIZONA_GP_FN_ASRC_CONFIG_ERROR 0x1C +#define ARIZONA_GP_FN_DRC1_SIGNAL_DETECT 0x1D +#define ARIZONA_GP_FN_DRC1_ANTICLIP 0x1E +#define ARIZONA_GP_FN_DRC1_DECAY 0x1F +#define ARIZONA_GP_FN_DRC1_NOISE 0x20 +#define ARIZONA_GP_FN_DRC1_QUICK_RELEASE 0x21 +#define ARIZONA_GP_FN_DRC2_SIGNAL_DETECT 0x22 +#define ARIZONA_GP_FN_DRC2_ANTICLIP 0x23 +#define ARIZONA_GP_FN_DRC2_DECAY 0x24 +#define ARIZONA_GP_FN_DRC2_NOISE 0x25 +#define ARIZONA_GP_FN_DRC2_QUICK_RELEASE 0x26 +#define ARIZONA_GP_FN_MIXER_DROPPED_SAMPLE 0x27 +#define ARIZONA_GP_FN_AIF1_CONFIG_ERROR 0x28 +#define ARIZONA_GP_FN_AIF2_CONFIG_ERROR 0x29 +#define ARIZONA_GP_FN_AIF3_CONFIG_ERROR 0x2A +#define ARIZONA_GP_FN_SPK_TEMP_SHUTDOWN 0x2B +#define ARIZONA_GP_FN_SPK_TEMP_WARNING 0x2C +#define ARIZONA_GP_FN_UNDERCLOCKED 0x2D +#define ARIZONA_GP_FN_OVERCLOCKED 0x2E +#define ARIZONA_GP_FN_DSP_IRQ1 0x35 +#define ARIZONA_GP_FN_DSP_IRQ2 0x36 +#define ARIZONA_GP_FN_ASYNC_OPCLK 0x3D +#define ARIZONA_GP_FN_BOOT_DONE 0x44 +#define ARIZONA_GP_FN_DSP1_RAM_READY 0x45 +#define ARIZONA_GP_FN_SYSCLK_ENA_STATUS 0x4B +#define ARIZONA_GP_FN_ASYNCCLK_ENA_STATUS 0x4C + +/* GPIO Configuration Bits */ +#define ARIZONA_GPN_DIR 0x8000 +#define ARIZONA_GPN_PU 0x4000 +#define ARIZONA_GPN_PD 0x2000 +#define ARIZONA_GPN_LVL 0x0800 +#define ARIZONA_GPN_POL 0x0400 +#define ARIZONA_GPN_OP_CFG 0x0200 +#define ARIZONA_GPN_DB 0x0100 + +/* Provide some defines for the most common configs */ +#define ARIZONA_GP_DEFAULT 0xffffffff +#define ARIZONA_GP_OUTPUT (ARIZONA_GP_FN_GPIO) +#define ARIZONA_GP_INPUT (ARIZONA_GP_FN_GPIO | \ + ARIZONA_GPN_DIR) + +#define ARIZONA_32KZ_MCLK1 1 +#define ARIZONA_32KZ_MCLK2 2 +#define ARIZONA_32KZ_NONE 3 + +#define ARIZONA_DMIC_MICVDD 0 +#define ARIZONA_DMIC_MICBIAS1 1 +#define ARIZONA_DMIC_MICBIAS2 2 +#define ARIZONA_DMIC_MICBIAS3 3 + +#define ARIZONA_INMODE_DIFF 0 +#define ARIZONA_INMODE_SE 1 +#define ARIZONA_INMODE_DMIC 2 + +#endif diff --git a/include/linux/mfd/arizona/gpio.h b/include/linux/mfd/arizona/gpio.h deleted file mode 100644 index d2146bb74f89..000000000000 --- a/include/linux/mfd/arizona/gpio.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * GPIO configuration for Arizona devices - * - * Copyright 2013 Wolfson Microelectronics. PLC. - * - * Author: Charles Keepax - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef _ARIZONA_GPIO_H -#define _ARIZONA_GPIO_H - -#define ARIZONA_GP_FN_TXLRCLK 0x00 -#define ARIZONA_GP_FN_GPIO 0x01 -#define ARIZONA_GP_FN_IRQ1 0x02 -#define ARIZONA_GP_FN_IRQ2 0x03 -#define ARIZONA_GP_FN_OPCLK 0x04 -#define ARIZONA_GP_FN_FLL1_OUT 0x05 -#define ARIZONA_GP_FN_FLL2_OUT 0x06 -#define ARIZONA_GP_FN_PWM1 0x08 -#define ARIZONA_GP_FN_PWM2 0x09 -#define ARIZONA_GP_FN_SYSCLK_UNDERCLOCKED 0x0A -#define ARIZONA_GP_FN_ASYNCCLK_UNDERCLOCKED 0x0B -#define ARIZONA_GP_FN_FLL1_LOCK 0x0C -#define ARIZONA_GP_FN_FLL2_LOCK 0x0D -#define ARIZONA_GP_FN_FLL1_CLOCK_OK 0x0F -#define ARIZONA_GP_FN_FLL2_CLOCK_OK 0x10 -#define ARIZONA_GP_FN_HEADPHONE_DET 0x12 -#define ARIZONA_GP_FN_MIC_DET 0x13 -#define ARIZONA_GP_FN_WSEQ_STATUS 0x15 -#define ARIZONA_GP_FN_CIF_ADDRESS_ERROR 0x16 -#define ARIZONA_GP_FN_ASRC1_LOCK 0x1A -#define ARIZONA_GP_FN_ASRC2_LOCK 0x1B -#define ARIZONA_GP_FN_ASRC_CONFIG_ERROR 0x1C -#define ARIZONA_GP_FN_DRC1_SIGNAL_DETECT 0x1D -#define ARIZONA_GP_FN_DRC1_ANTICLIP 0x1E -#define ARIZONA_GP_FN_DRC1_DECAY 0x1F -#define ARIZONA_GP_FN_DRC1_NOISE 0x20 -#define ARIZONA_GP_FN_DRC1_QUICK_RELEASE 0x21 -#define ARIZONA_GP_FN_DRC2_SIGNAL_DETECT 0x22 -#define ARIZONA_GP_FN_DRC2_ANTICLIP 0x23 -#define ARIZONA_GP_FN_DRC2_DECAY 0x24 -#define ARIZONA_GP_FN_DRC2_NOISE 0x25 -#define ARIZONA_GP_FN_DRC2_QUICK_RELEASE 0x26 -#define ARIZONA_GP_FN_MIXER_DROPPED_SAMPLE 0x27 -#define ARIZONA_GP_FN_AIF1_CONFIG_ERROR 0x28 -#define ARIZONA_GP_FN_AIF2_CONFIG_ERROR 0x29 -#define ARIZONA_GP_FN_AIF3_CONFIG_ERROR 0x2A -#define ARIZONA_GP_FN_SPK_TEMP_SHUTDOWN 0x2B -#define ARIZONA_GP_FN_SPK_TEMP_WARNING 0x2C -#define ARIZONA_GP_FN_UNDERCLOCKED 0x2D -#define ARIZONA_GP_FN_OVERCLOCKED 0x2E -#define ARIZONA_GP_FN_DSP_IRQ1 0x35 -#define ARIZONA_GP_FN_DSP_IRQ2 0x36 -#define ARIZONA_GP_FN_ASYNC_OPCLK 0x3D -#define ARIZONA_GP_FN_BOOT_DONE 0x44 -#define ARIZONA_GP_FN_DSP1_RAM_READY 0x45 -#define ARIZONA_GP_FN_SYSCLK_ENA_STATUS 0x4B -#define ARIZONA_GP_FN_ASYNCCLK_ENA_STATUS 0x4C - -#define ARIZONA_GPN_DIR 0x8000 /* GPN_DIR */ -#define ARIZONA_GPN_DIR_MASK 0x8000 /* GPN_DIR */ -#define ARIZONA_GPN_DIR_SHIFT 15 /* GPN_DIR */ -#define ARIZONA_GPN_DIR_WIDTH 1 /* GPN_DIR */ -#define ARIZONA_GPN_PU 0x4000 /* GPN_PU */ -#define ARIZONA_GPN_PU_MASK 0x4000 /* GPN_PU */ -#define ARIZONA_GPN_PU_SHIFT 14 /* GPN_PU */ -#define ARIZONA_GPN_PU_WIDTH 1 /* GPN_PU */ -#define ARIZONA_GPN_PD 0x2000 /* GPN_PD */ -#define ARIZONA_GPN_PD_MASK 0x2000 /* GPN_PD */ -#define ARIZONA_GPN_PD_SHIFT 13 /* GPN_PD */ -#define ARIZONA_GPN_PD_WIDTH 1 /* GPN_PD */ -#define ARIZONA_GPN_LVL 0x0800 /* GPN_LVL */ -#define ARIZONA_GPN_LVL_MASK 0x0800 /* GPN_LVL */ -#define ARIZONA_GPN_LVL_SHIFT 11 /* GPN_LVL */ -#define ARIZONA_GPN_LVL_WIDTH 1 /* GPN_LVL */ -#define ARIZONA_GPN_POL 0x0400 /* GPN_POL */ -#define ARIZONA_GPN_POL_MASK 0x0400 /* GPN_POL */ -#define ARIZONA_GPN_POL_SHIFT 10 /* GPN_POL */ -#define ARIZONA_GPN_POL_WIDTH 1 /* GPN_POL */ -#define ARIZONA_GPN_OP_CFG 0x0200 /* GPN_OP_CFG */ -#define ARIZONA_GPN_OP_CFG_MASK 0x0200 /* GPN_OP_CFG */ -#define ARIZONA_GPN_OP_CFG_SHIFT 9 /* GPN_OP_CFG */ -#define ARIZONA_GPN_OP_CFG_WIDTH 1 /* GPN_OP_CFG */ -#define ARIZONA_GPN_DB 0x0100 /* GPN_DB */ -#define ARIZONA_GPN_DB_MASK 0x0100 /* GPN_DB */ -#define ARIZONA_GPN_DB_SHIFT 8 /* GPN_DB */ -#define ARIZONA_GPN_DB_WIDTH 1 /* GPN_DB */ -#define ARIZONA_GPN_FN_MASK 0x007F /* GPN_DB */ -#define ARIZONA_GPN_FN_SHIFT 0 /* GPN_DB */ -#define ARIZONA_GPN_FN_WIDTH 7 /* GPN_DB */ - -#endif diff --git a/include/linux/mfd/arizona/pdata.h b/include/linux/mfd/arizona/pdata.h index 4578c72c9b86..48fe31356605 100644 --- a/include/linux/mfd/arizona/pdata.h +++ b/include/linux/mfd/arizona/pdata.h @@ -11,31 +11,26 @@ #ifndef _ARIZONA_PDATA_H #define _ARIZONA_PDATA_H -#define ARIZONA_GPN_DIR 0x8000 /* GPN_DIR */ +#include + #define ARIZONA_GPN_DIR_MASK 0x8000 /* GPN_DIR */ #define ARIZONA_GPN_DIR_SHIFT 15 /* GPN_DIR */ #define ARIZONA_GPN_DIR_WIDTH 1 /* GPN_DIR */ -#define ARIZONA_GPN_PU 0x4000 /* GPN_PU */ #define ARIZONA_GPN_PU_MASK 0x4000 /* GPN_PU */ #define ARIZONA_GPN_PU_SHIFT 14 /* GPN_PU */ #define ARIZONA_GPN_PU_WIDTH 1 /* GPN_PU */ -#define ARIZONA_GPN_PD 0x2000 /* GPN_PD */ #define ARIZONA_GPN_PD_MASK 0x2000 /* GPN_PD */ #define ARIZONA_GPN_PD_SHIFT 13 /* GPN_PD */ #define ARIZONA_GPN_PD_WIDTH 1 /* GPN_PD */ -#define ARIZONA_GPN_LVL 0x0800 /* GPN_LVL */ #define ARIZONA_GPN_LVL_MASK 0x0800 /* GPN_LVL */ #define ARIZONA_GPN_LVL_SHIFT 11 /* GPN_LVL */ #define ARIZONA_GPN_LVL_WIDTH 1 /* GPN_LVL */ -#define ARIZONA_GPN_POL 0x0400 /* GPN_POL */ #define ARIZONA_GPN_POL_MASK 0x0400 /* GPN_POL */ #define ARIZONA_GPN_POL_SHIFT 10 /* GPN_POL */ #define ARIZONA_GPN_POL_WIDTH 1 /* GPN_POL */ -#define ARIZONA_GPN_OP_CFG 0x0200 /* GPN_OP_CFG */ #define ARIZONA_GPN_OP_CFG_MASK 0x0200 /* GPN_OP_CFG */ #define ARIZONA_GPN_OP_CFG_SHIFT 9 /* GPN_OP_CFG */ #define ARIZONA_GPN_OP_CFG_WIDTH 1 /* GPN_OP_CFG */ -#define ARIZONA_GPN_DB 0x0100 /* GPN_DB */ #define ARIZONA_GPN_DB_MASK 0x0100 /* GPN_DB */ #define ARIZONA_GPN_DB_SHIFT 8 /* GPN_DB */ #define ARIZONA_GPN_DB_WIDTH 1 /* GPN_DB */ @@ -45,23 +40,10 @@ #define ARIZONA_MAX_GPIO 5 -#define ARIZONA_32KZ_MCLK1 1 -#define ARIZONA_32KZ_MCLK2 2 -#define ARIZONA_32KZ_NONE 3 - #define ARIZONA_MAX_INPUT 4 -#define ARIZONA_DMIC_MICVDD 0 -#define ARIZONA_DMIC_MICBIAS1 1 -#define ARIZONA_DMIC_MICBIAS2 2 -#define ARIZONA_DMIC_MICBIAS3 3 - #define ARIZONA_MAX_MICBIAS 3 -#define ARIZONA_INMODE_DIFF 0 -#define ARIZONA_INMODE_SE 1 -#define ARIZONA_INMODE_DMIC 2 - #define ARIZONA_MAX_OUTPUT 6 #define ARIZONA_MAX_AIF 3 diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index baf7b36aaaa4..95d31d6291ac 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -19,7 +19,6 @@ #include #include -#include #include #include "arizona.h" -- cgit v1.2.3-59-g8ed1b From 97e4a7a21edf5901c8cd60715c81b880b7a3be12 Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Wed, 18 Feb 2015 14:08:26 +0000 Subject: mfd: da9150: Add DT binding documentation for core Signed-off-by: Adam Thomson Signed-off-by: Lee Jones --- Documentation/devicetree/bindings/mfd/da9150.txt | 43 ++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 Documentation/devicetree/bindings/mfd/da9150.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mfd/da9150.txt b/Documentation/devicetree/bindings/mfd/da9150.txt new file mode 100644 index 000000000000..d0588eaa0d71 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/da9150.txt @@ -0,0 +1,43 @@ +Dialog Semiconductor DA9150 Combined Charger/Fuel-Gauge MFD bindings + +DA9150 consists of a group of sub-devices: + +Device Description +------ ----------- +da9150-gpadc : General Purpose ADC +da9150-charger : Battery Charger + +====== + +Required properties: +- compatible : Should be "dlg,da9150" +- reg: Specifies the I2C slave address +- interrupt-parent: Specifies the phandle of the interrupt controller to which + the IRQs from da9150 are delivered to. +- interrupts: IRQ line info for da9150 chip. +- interrupt-controller: da9150 has internal IRQs (own IRQ domain). + (See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt for + further information relating to interrupt properties) + +Sub-devices: +- da9150-gpadc: See Documentation/devicetree/bindings/iio/adc/da9150-gpadc.txt +- da9150-charger: See Documentation/devicetree/bindings/power/da9150-charger.txt + + +Example: + + charger_fg: da9150@58 { + compatible = "dlg,da9150"; + reg = <0x58>; + interrupt-parent = <&gpio6>; + interrupts = <11 IRQ_TYPE_LEVEL_LOW>; + interrupt-controller; + + gpadc: da9150-gpadc { + ... + }; + + da9150-charger { + ... + }; + }; -- cgit v1.2.3-59-g8ed1b From 8967215954a50947fbd9c2996232548bf6dd9062 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Thu, 5 Feb 2015 17:55:51 +0800 Subject: f2fs: add a mount option for rb-tree extent cache This patch adds a mount option 'extent_cache' in f2fs. It is try to use a rb-tree based extent cache to cache more mapping information with less memory if this option is set, otherwise we will use the original one extent info cache. Suggested-by: Changman Lee Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- Documentation/filesystems/f2fs.txt | 4 ++++ fs/f2fs/f2fs.h | 1 + fs/f2fs/super.c | 7 +++++++ 3 files changed, 12 insertions(+) (limited to 'Documentation') diff --git a/Documentation/filesystems/f2fs.txt b/Documentation/filesystems/f2fs.txt index dac11d7fef27..48e2123c2582 100644 --- a/Documentation/filesystems/f2fs.txt +++ b/Documentation/filesystems/f2fs.txt @@ -140,6 +140,10 @@ nobarrier This option can be used if underlying storage guarantees fastboot This option is used when a system wants to reduce mount time as much as possible, even though normal performance can be sacrificed. +extent_cache Enable an extent cache based on rb-tree, it can cache + as many as extent which map between contiguous logical + address and physical address per inode, resulting in + increasing the cache hit ratio. ================================================================================ DEBUGFS ENTRIES diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index a0af10dad871..759fbaaa6ca1 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -50,6 +50,7 @@ #define F2FS_MOUNT_FLUSH_MERGE 0x00000400 #define F2FS_MOUNT_NOBARRIER 0x00000800 #define F2FS_MOUNT_FASTBOOT 0x00001000 +#define F2FS_MOUNT_EXTENT_CACHE 0x00002000 #define clear_opt(sbi, option) (sbi->mount_opt.opt &= ~F2FS_MOUNT_##option) #define set_opt(sbi, option) (sbi->mount_opt.opt |= F2FS_MOUNT_##option) diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 4e9aad451593..3ce4d7c9a29d 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -57,6 +57,7 @@ enum { Opt_flush_merge, Opt_nobarrier, Opt_fastboot, + Opt_extent_cache, Opt_err, }; @@ -78,6 +79,7 @@ static match_table_t f2fs_tokens = { {Opt_flush_merge, "flush_merge"}, {Opt_nobarrier, "nobarrier"}, {Opt_fastboot, "fastboot"}, + {Opt_extent_cache, "extent_cache"}, {Opt_err, NULL}, }; @@ -367,6 +369,9 @@ static int parse_options(struct super_block *sb, char *options) case Opt_fastboot: set_opt(sbi, FASTBOOT); break; + case Opt_extent_cache: + set_opt(sbi, EXTENT_CACHE); + break; default: f2fs_msg(sb, KERN_ERR, "Unrecognized mount option \"%s\" or missing value", @@ -599,6 +604,8 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) seq_puts(seq, ",nobarrier"); if (test_opt(sbi, FASTBOOT)) seq_puts(seq, ",fastboot"); + if (test_opt(sbi, EXTENT_CACHE)) + seq_puts(seq, ",extent_cache"); seq_printf(seq, ",active_logs=%u", sbi->active_logs); return 0; -- cgit v1.2.3-59-g8ed1b From f1f5bc30f5726ff28fa1b263edcd805cced84a07 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Wed, 18 Feb 2015 15:13:59 +0000 Subject: irqchip: st: Add documentation for STi based syscfg IRQs Signed-off-by: Lee Jones Link: https://lkml.kernel.org/r/1424272444-16230-4-git-send-email-lee.jones@linaro.org Signed-off-by: Jason Cooper --- .../interrupt-controller/st,sti-irq-syscfg.txt | 35 ++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/st,sti-irq-syscfg.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/interrupt-controller/st,sti-irq-syscfg.txt b/Documentation/devicetree/bindings/interrupt-controller/st,sti-irq-syscfg.txt new file mode 100644 index 000000000000..ced6014061a3 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/st,sti-irq-syscfg.txt @@ -0,0 +1,35 @@ +STMicroelectronics STi System Configuration Controlled IRQs +----------------------------------------------------------- + +On STi based systems; External, CTI (Core Sight), PMU (Performance Management), +and PL310 L2 Cache IRQs are controlled using System Configuration registers. +This driver is used to unmask them prior to use. + +Required properties: +- compatible : Should be set to one of: + "st,stih415-irq-syscfg" + "st,stih416-irq-syscfg" + "st,stih407-irq-syscfg" + "st,stid127-irq-syscfg" +- st,syscfg : Phandle to Cortex-A9 IRQ system config registers +- st,irq-device : Array of IRQs to enable - should be 2 in length +- st,fiq-device : Array of FIQs to enable - should be 2 in length + +Optional properties: +- st,invert-ext : External IRQs can be inverted at will. This property inverts + these IRQs using bitwise logic. A number of defines have been + provided for convenience: + ST_IRQ_SYSCFG_EXT_1_INV + ST_IRQ_SYSCFG_EXT_2_INV + ST_IRQ_SYSCFG_EXT_3_INV +Example: + +irq-syscfg { + compatible = "st,stih416-irq-syscfg"; + st,syscfg = <&syscfg_cpu>; + st,irq-device = , + ; + st,fiq-device = , + ; + st,invert-ext = <(ST_IRQ_SYSCFG_EXT_1_INV | ST_IRQ_SYSCFG_EXT_3_INV)>; +}; -- cgit v1.2.3-59-g8ed1b From 7720c01f3f590116882e251f13c7e1d5602f8643 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 3 Mar 2015 19:11:20 -0600 Subject: mpls: Add a sysctl to control the size of the mpls label table This sysctl gives two benefits. By defaulting the table size to 0 mpls even when compiled in and enabled defaults to not forwarding any packets. This prevents unpleasant surprises for users. The other benefit is that as mpls labels are allocated locally a dense table a small dense label table may be used which saves memory and is extremely simple and efficient to implement. This sysctl allows userspace to choose the restrictions on the label table size userspace applications need to cope with. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- Documentation/networking/mpls-sysctl.txt | 20 +++++ include/net/netns/mpls.h | 2 + net/mpls/af_mpls.c | 146 +++++++++++++++++++++++++++++++ 3 files changed, 168 insertions(+) create mode 100644 Documentation/networking/mpls-sysctl.txt (limited to 'Documentation') diff --git a/Documentation/networking/mpls-sysctl.txt b/Documentation/networking/mpls-sysctl.txt new file mode 100644 index 000000000000..639ddf0ece9b --- /dev/null +++ b/Documentation/networking/mpls-sysctl.txt @@ -0,0 +1,20 @@ +/proc/sys/net/mpls/* Variables: + +platform_labels - INTEGER + Number of entries in the platform label table. It is not + possible to configure forwarding for label values equal to or + greater than the number of platform labels. + + A dense utliziation of the entries in the platform label table + is possible and expected aas the platform labels are locally + allocated. + + If the number of platform label table entries is set to 0 no + label will be recognized by the kernel and mpls forwarding + will be disabled. + + Reducing this value will remove all label routing entries that + no longer fit in the table. + + Possible values: 0 - 1048575 + Default: 0 diff --git a/include/net/netns/mpls.h b/include/net/netns/mpls.h index f90aaf8d4f89..d29203651c01 100644 --- a/include/net/netns/mpls.h +++ b/include/net/netns/mpls.h @@ -6,10 +6,12 @@ #define __NETNS_MPLS_H__ struct mpls_route; +struct ctl_table_header; struct netns_mpls { size_t platform_labels; struct mpls_route __rcu * __rcu *platform_label; + struct ctl_table_header *ctl; }; #endif /* __NETNS_MPLS_H__ */ diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c index 924377736b2a..b097125dfa33 100644 --- a/net/mpls/af_mpls.c +++ b/net/mpls/af_mpls.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -31,6 +32,9 @@ struct mpls_route { /* next hop label forwarding entry */ u8 rt_via[0]; }; +static int zero = 0; +static int label_limit = (1 << 20) - 1; + static struct mpls_route *mpls_route_input_rcu(struct net *net, unsigned index) { struct mpls_route *rt = NULL; @@ -273,18 +277,160 @@ static struct notifier_block mpls_dev_notifier = { .notifier_call = mpls_dev_notify, }; +static int resize_platform_label_table(struct net *net, size_t limit) +{ + size_t size = sizeof(struct mpls_route *) * limit; + size_t old_limit; + size_t cp_size; + struct mpls_route __rcu **labels = NULL, **old; + struct mpls_route *rt0 = NULL, *rt2 = NULL; + unsigned index; + + if (size) { + labels = kzalloc(size, GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY); + if (!labels) + labels = vzalloc(size); + + if (!labels) + goto nolabels; + } + + /* In case the predefined labels need to be populated */ + if (limit > LABEL_IPV4_EXPLICIT_NULL) { + struct net_device *lo = net->loopback_dev; + rt0 = mpls_rt_alloc(lo->addr_len); + if (!rt0) + goto nort0; + rt0->rt_dev = lo; + rt0->rt_protocol = RTPROT_KERNEL; + rt0->rt_via_family = AF_PACKET; + memcpy(rt0->rt_via, lo->dev_addr, lo->addr_len); + } + if (limit > LABEL_IPV6_EXPLICIT_NULL) { + struct net_device *lo = net->loopback_dev; + rt2 = mpls_rt_alloc(lo->addr_len); + if (!rt2) + goto nort2; + rt2->rt_dev = lo; + rt2->rt_protocol = RTPROT_KERNEL; + rt2->rt_via_family = AF_PACKET; + memcpy(rt2->rt_via, lo->dev_addr, lo->addr_len); + } + + rtnl_lock(); + /* Remember the original table */ + old = net->mpls.platform_label; + old_limit = net->mpls.platform_labels; + + /* Free any labels beyond the new table */ + for (index = limit; index < old_limit; index++) + mpls_route_update(net, index, NULL, NULL, NULL); + + /* Copy over the old labels */ + cp_size = size; + if (old_limit < limit) + cp_size = old_limit * sizeof(struct mpls_route *); + + memcpy(labels, old, cp_size); + + /* If needed set the predefined labels */ + if ((old_limit <= LABEL_IPV6_EXPLICIT_NULL) && + (limit > LABEL_IPV6_EXPLICIT_NULL)) { + labels[LABEL_IPV6_EXPLICIT_NULL] = rt2; + rt2 = NULL; + } + + if ((old_limit <= LABEL_IPV4_EXPLICIT_NULL) && + (limit > LABEL_IPV4_EXPLICIT_NULL)) { + labels[LABEL_IPV4_EXPLICIT_NULL] = rt0; + rt0 = NULL; + } + + /* Update the global pointers */ + net->mpls.platform_labels = limit; + net->mpls.platform_label = labels; + + rtnl_unlock(); + + mpls_rt_free(rt2); + mpls_rt_free(rt0); + + if (old) { + synchronize_rcu(); + kvfree(old); + } + return 0; + +nort2: + mpls_rt_free(rt0); +nort0: + kvfree(labels); +nolabels: + return -ENOMEM; +} + +static int mpls_platform_labels(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + struct net *net = table->data; + int platform_labels = net->mpls.platform_labels; + int ret; + struct ctl_table tmp = { + .procname = table->procname, + .data = &platform_labels, + .maxlen = sizeof(int), + .mode = table->mode, + .extra1 = &zero, + .extra2 = &label_limit, + }; + + ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos); + + if (write && ret == 0) + ret = resize_platform_label_table(net, platform_labels); + + return ret; +} + +static struct ctl_table mpls_table[] = { + { + .procname = "platform_labels", + .data = NULL, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = mpls_platform_labels, + }, + { } +}; + static int mpls_net_init(struct net *net) { + struct ctl_table *table; + net->mpls.platform_labels = 0; net->mpls.platform_label = NULL; + table = kmemdup(mpls_table, sizeof(mpls_table), GFP_KERNEL); + if (table == NULL) + return -ENOMEM; + + table[0].data = net; + net->mpls.ctl = register_net_sysctl(net, "net/mpls", table); + if (net->mpls.ctl == NULL) + return -ENOMEM; + return 0; } static void mpls_net_exit(struct net *net) { + struct ctl_table *table; unsigned int index; + table = net->mpls.ctl->ctl_table_arg; + unregister_net_sysctl_table(net->mpls.ctl); + kfree(table); + /* An rcu grace period haselapsed since there was a device in * the network namespace (and thus the last in fqlight packet) * left this network namespace. This is because -- cgit v1.2.3-59-g8ed1b From d3591df3fada3f4cd6cf60f0f56e87744749018d Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Sun, 22 Feb 2015 13:15:30 +0100 Subject: mfd: dt-bindings: Add bindings for the MediaTek MT6397 PMIC Signed-off-by: Sascha Hauer Signed-off-by: Lee Jones --- Documentation/devicetree/bindings/mfd/mt6397.txt | 70 ++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 Documentation/devicetree/bindings/mfd/mt6397.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mfd/mt6397.txt b/Documentation/devicetree/bindings/mfd/mt6397.txt new file mode 100644 index 000000000000..15043e652699 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/mt6397.txt @@ -0,0 +1,70 @@ +MediaTek MT6397 Multifunction Device Driver + +MT6397 is a multifunction device with the following sub modules: +- Regulator +- RTC +- Audio codec +- GPIO +- Clock + +It is interfaced to host controller using SPI interface by a proprietary hardware +called PMIC wrapper or pwrap. MT6397 MFD is a child device of pwrap. +See the following for pwarp node definitions: +Documentation/devicetree/bindings/soc/pwrap.txt + +This document describes the binding for MFD device and its sub module. + +Required properties: +compatible: "mediatek,mt6397" + +Optional subnodes: + +- rtc + Required properties: + - compatible: "mediatek,mt6397-rtc" +- regulators + Required properties: + - compatible: "mediatek,mt6397-regulator" + see Documentation/devicetree/bindings/regulator/mt6397-regulator.txt +- codec + Required properties: + - compatible: "mediatek,mt6397-codec" +- clk + Required properties: + - compatible: "mediatek,mt6397-clk" + +Example: + pwrap: pwrap@1000f000 { + compatible = "mediatek,mt8135-pwrap"; + + ... + + pmic { + compatible = "mediatek,mt6397"; + + codec: mt6397codec { + compatible = "mediatek,mt6397-codec"; + }; + + regulators { + compatible = "mediatek,mt6397-regulator"; + + mt6397_vpca15_reg: buck_vpca15 { + regulator-compatible = "buck_vpca15"; + regulator-name = "vpca15"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <1400000>; + regulator-ramp-delay = <12500>; + regulator-always-on; + }; + + mt6397_vgp4_reg: ldo_vgp4 { + regulator-compatible = "ldo_vgp4"; + regulator-name = "vgp4"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <218>; + }; + }; + }; + }; -- cgit v1.2.3-59-g8ed1b From 7b24d97f16f561cc90eab1658100598d54a414fd Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Fri, 27 Feb 2015 20:00:00 +0100 Subject: crypto: doc - describe internal structure The kernel crypto API has many indirections which warrant a description as otherwise one can get easily lost. The description explains the layers of the kernel crypto API based on examples. Signed-off-by: Stephan Mueller Signed-off-by: Herbert Xu --- Documentation/DocBook/crypto-API.tmpl | 264 ++++++++++++++++++++++++++++++++++ 1 file changed, 264 insertions(+) (limited to 'Documentation') diff --git a/Documentation/DocBook/crypto-API.tmpl b/Documentation/DocBook/crypto-API.tmpl index 04a8c24ead47..33f63cfc00ca 100644 --- a/Documentation/DocBook/crypto-API.tmpl +++ b/Documentation/DocBook/crypto-API.tmpl @@ -509,6 +509,270 @@ select it due to the used type and mask field. + + Internal Structure of Kernel Crypto API + + + The kernel crypto API has an internal structure where a cipher + implementation may use many layers and indirections. This section + shall help to clarify how the kernel crypto API uses + various components to implement the complete cipher. + + + + The following subsections explain the internal structure based + on existing cipher implementations. The first section addresses + the most complex scenario where all other scenarios form a logical + subset. + + + Generic AEAD Cipher Structure + + + The following ASCII art decomposes the kernel crypto API layers + when using the AEAD cipher with the automated IV generation. The + shown example is used by the IPSEC layer. + + + + For other use cases of AEAD ciphers, the ASCII art applies as + well, but the caller may not use the GIVCIPHER interface. In + this case, the caller must generate the IV. + + + + The depicted example decomposes the AEAD cipher of GCM(AES) based + on the generic C implementations (gcm.c, aes-generic.c, ctr.c, + ghash-generic.c, seqiv.c). The generic implementation serves as an + example showing the complete logic of the kernel crypto API. + + + + It is possible that some streamlined cipher implementations (like + AES-NI) provide implementations merging aspects which in the view + of the kernel crypto API cannot be decomposed into layers any more. + In case of the AES-NI implementation, the CTR mode, the GHASH + implementation and the AES cipher are all merged into one cipher + implementation registered with the kernel crypto API. In this case, + the concept described by the following ASCII art applies too. However, + the decomposition of GCM into the individual sub-components + by the kernel crypto API is not done any more. + + + + Each block in the following ASCII art is an independent cipher + instance obtained from the kernel crypto API. Each block + is accessed by the caller or by other blocks using the API functions + defined by the kernel crypto API for the cipher implementation type. + + + + The blocks below indicate the cipher type as well as the specific + logic implemented in the cipher. + + + + The ASCII art picture also indicates the call structure, i.e. who + calls which component. The arrows point to the invoked block + where the caller uses the API applicable to the cipher type + specified for the block. + + + + + + + + The following call sequence is applicable when the IPSEC layer + triggers an encryption operation with the esp_output function. During + configuration, the administrator set up the use of rfc4106(gcm(aes)) as + the cipher for ESP. The following call sequence is now depicted in the + ASCII art above: + + + + + + esp_output() invokes crypto_aead_givencrypt() to trigger an encryption + operation of the GIVCIPHER implementation. + + + + In case of GCM, the SEQIV implementation is registered as GIVCIPHER + in crypto_rfc4106_alloc(). + + + + The SEQIV performs its operation to generate an IV where the core + function is seqiv_geniv(). + + + + + + Now, SEQIV uses the AEAD API function calls to invoke the associated + AEAD cipher. In our case, during the instantiation of SEQIV, the + cipher handle for GCM is provided to SEQIV. This means that SEQIV + invokes AEAD cipher operations with the GCM cipher handle. + + + + During instantiation of the GCM handle, the CTR(AES) and GHASH + ciphers are instantiated. The cipher handles for CTR(AES) and GHASH + are retained for later use. + + + + The GCM implementation is responsible to invoke the CTR mode AES and + the GHASH cipher in the right manner to implement the GCM + specification. + + + + + + The GCM AEAD cipher type implementation now invokes the ABLKCIPHER API + with the instantiated CTR(AES) cipher handle. + + + + During instantiation of the CTR(AES) cipher, the CIPHER type + implementation of AES is instantiated. The cipher handle for AES is + retained. + + + + That means that the ABLKCIPHER implementation of CTR(AES) only + implements the CTR block chaining mode. After performing the block + chaining operation, the CIPHER implementation of AES is invoked. + + + + + + The ABLKCIPHER of CTR(AES) now invokes the CIPHER API with the AES + cipher handle to encrypt one block. + + + + + + The GCM AEAD implementation also invokes the GHASH cipher + implementation via the AHASH API. + + + + + + When the IPSEC layer triggers the esp_input() function, the same call + sequence is followed with the only difference that the operation starts + with step (2). + + + + Generic Block Cipher Structure + + Generic block ciphers follow the same concept as depicted with the ASCII + art picture above. + + + + For example, CBC(AES) is implemented with cbc.c, and aes-generic.c. The + ASCII art picture above applies as well with the difference that only + step (4) is used and the ABLKCIPHER block chaining mode is CBC. + + + + Generic Keyed Message Digest Structure + + Keyed message digest implementations again follow the same concept as + depicted in the ASCII art picture above. + + + + For example, HMAC(SHA256) is implemented with hmac.c and + sha256_generic.c. The following ASCII art illustrates the + implementation: + + + + + + + + The following call sequence is applicable when a caller triggers + an HMAC operation: + + + + + + The AHASH API functions are invoked by the caller. The HMAC + implementation performs its operation as needed. + + + + During initialization of the HMAC cipher, the SHASH cipher type of + SHA256 is instantiated. The cipher handle for the SHA256 instance is + retained. + + + + At one time, the HMAC implementation requires a SHA256 operation + where the SHA256 cipher handle is used. + + + + + + The HMAC instance now invokes the SHASH API with the SHA256 + cipher handle to calculate the message digest. + + + + + Developing Cipher Algorithms -- cgit v1.2.3-59-g8ed1b From 6b516a1093006a39368dd11a5396be5bb00c99df Mon Sep 17 00:00:00 2001 From: Benoit Parrot Date: Mon, 2 Feb 2015 11:44:45 -0600 Subject: gpio: Document GPIO hogging mechanism Add GPIO hogging documentation to gpio.txt Signed-off-by: Benoit Parrot Reviewed-by: Alexandre Courbot Signed-off-by: Linus Walleij --- Documentation/devicetree/bindings/gpio/gpio.txt | 30 +++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/gpio/gpio.txt b/Documentation/devicetree/bindings/gpio/gpio.txt index f7a158d85862..5788d5cf1252 100644 --- a/Documentation/devicetree/bindings/gpio/gpio.txt +++ b/Documentation/devicetree/bindings/gpio/gpio.txt @@ -116,6 +116,29 @@ Every GPIO controller node must contain both an empty "gpio-controller" property, and a #gpio-cells integer property, which indicates the number of cells in a gpio-specifier. +The GPIO chip may contain GPIO hog definitions. GPIO hogging is a mechanism +providing automatic GPIO request and configuration as part of the +gpio-controller's driver probe function. + +Each GPIO hog definition is represented as a child node of the GPIO controller. +Required properties: +- gpio-hog: A property specifying that this child node represent a GPIO hog. +- gpios: Store the GPIO information (id, flags, ...). Shall contain the + number of cells specified in its parent node (GPIO controller + node). +Only one of the following properties scanned in the order shown below. +This means that when multiple properties are present they will be searched +in the order presented below and the first match is taken as the intended +configuration. +- input: A property specifying to set the GPIO direction as input. +- output-low A property specifying to set the GPIO direction as output with + the value low. +- output-high A property specifying to set the GPIO direction as output with + the value high. + +Optional properties: +- line-name: The GPIO label name. If not present the node name is used. + Example of two SOC GPIO banks defined as gpio-controller nodes: qe_pio_a: gpio-controller@1400 { @@ -123,6 +146,13 @@ Example of two SOC GPIO banks defined as gpio-controller nodes: reg = <0x1400 0x18>; gpio-controller; #gpio-cells = <2>; + + line_b { + gpio-hog; + gpios = <6 0>; + output-low; + line-name = "foo-bar-gpio"; + }; }; qe_pio_e: gpio-controller@1460 { -- cgit v1.2.3-59-g8ed1b From 668585273246f67b0cdafa30dd2da2047a2e1290 Mon Sep 17 00:00:00 2001 From: Rojhalat Ibrahim Date: Wed, 11 Feb 2015 17:27:58 +0100 Subject: gpiolib: add gpiod_get_array and gpiod_put_array functions Introduce new functions for conveniently obtaining and disposing of an entire array of GPIOs with one function call. ACPI parts tested by Mika Westerberg, DT parts tested by Rojhalat Ibrahim. Change log: v5: move the ACPI functions to gpiolib-acpi.c v4: - use shorter names for members of struct gpio_descs - rename lut_gpio_count to platform_gpio_count for clarity - add check for successful memory allocation - use ERR_CAST() v3: - rebase on current linux-gpio devel branch - fix ACPI GPIO counting - allow for zero-sized arrays - make the flags argument mandatory for the new functions - clarify documentation v2: change interface Suggested-by: Alexandre Courbot Signed-off-by: Rojhalat Ibrahim Reviewed-by: Alexandre Courbot Reviewed-by: Mika Westerberg Tested-by: Mika Westerberg Tested-by: Rojhalat Ibrahim Signed-off-by: Linus Walleij --- Documentation/gpio/consumer.txt | 33 ++++++++- drivers/gpio/gpiolib-acpi.c | 84 +++++++++++++++++++++++ drivers/gpio/gpiolib.c | 145 ++++++++++++++++++++++++++++++++++++++++ drivers/gpio/gpiolib.h | 7 ++ include/linux/gpio/consumer.h | 46 +++++++++++++ 5 files changed, 312 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/gpio/consumer.txt b/Documentation/gpio/consumer.txt index d85fbae451ea..2924f2ffcd91 100644 --- a/Documentation/gpio/consumer.txt +++ b/Documentation/gpio/consumer.txt @@ -58,7 +58,6 @@ pattern where a GPIO is optional, the gpiod_get_optional() and gpiod_get_index_optional() functions can be used. These functions return NULL instead of -ENOENT if no GPIO has been assigned to the requested function: - struct gpio_desc *gpiod_get_optional(struct device *dev, const char *con_id, enum gpiod_flags flags) @@ -68,6 +67,27 @@ instead of -ENOENT if no GPIO has been assigned to the requested function: unsigned int index, enum gpiod_flags flags) +For a function using multiple GPIOs all of those can be obtained with one call: + + struct gpio_descs *gpiod_get_array(struct device *dev, + const char *con_id, + enum gpiod_flags flags) + +This function returns a struct gpio_descs which contains an array of +descriptors: + + struct gpio_descs { + unsigned int ndescs; + struct gpio_desc *desc[]; + } + +The following function returns NULL instead of -ENOENT if no GPIOs have been +assigned to the requested function: + + struct gpio_descs *gpiod_get_array_optional(struct device *dev, + const char *con_id, + enum gpiod_flags flags) + Device-managed variants of these functions are also defined: struct gpio_desc *devm_gpiod_get(struct device *dev, const char *con_id, @@ -91,8 +111,15 @@ A GPIO descriptor can be disposed of using the gpiod_put() function: void gpiod_put(struct gpio_desc *desc) -It is strictly forbidden to use a descriptor after calling this function. The -device-managed variant is, unsurprisingly: +For an array of GPIOs this function can be used: + + void gpiod_put_array(struct gpio_descs *descs) + +It is strictly forbidden to use a descriptor after calling these functions. +It is also not allowed to individually release descriptors (using gpiod_put()) +from an array acquired with gpiod_get_array(). + +The device-managed variant is, unsurprisingly: void devm_gpiod_put(struct device *dev, struct gpio_desc *desc) diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index c0929d938ced..c4919966453d 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -712,3 +712,87 @@ void acpi_gpiochip_remove(struct gpio_chip *chip) acpi_detach_data(handle, acpi_gpio_chip_dh); kfree(acpi_gpio); } + +static unsigned int acpi_gpio_package_count(const union acpi_object *obj) +{ + const union acpi_object *element = obj->package.elements; + const union acpi_object *end = element + obj->package.count; + unsigned int count = 0; + + while (element < end) { + if (element->type == ACPI_TYPE_LOCAL_REFERENCE) + count++; + + element++; + } + return count; +} + +static int acpi_find_gpio_count(struct acpi_resource *ares, void *data) +{ + unsigned int *count = data; + + if (ares->type == ACPI_RESOURCE_TYPE_GPIO) + *count += ares->data.gpio.pin_table_length; + + return 1; +} + +/** + * acpi_gpio_count - return the number of GPIOs associated with a + * device / function or -ENOENT if no GPIO has been + * assigned to the requested function. + * @dev: GPIO consumer, can be NULL for system-global GPIOs + * @con_id: function within the GPIO consumer + */ +int acpi_gpio_count(struct device *dev, const char *con_id) +{ + struct acpi_device *adev = ACPI_COMPANION(dev); + const union acpi_object *obj; + const struct acpi_gpio_mapping *gm; + int count = -ENOENT; + int ret; + char propname[32]; + unsigned int i; + + /* Try first from _DSD */ + for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) { + if (con_id && strcmp(con_id, "gpios")) + snprintf(propname, sizeof(propname), "%s-%s", + con_id, gpio_suffixes[i]); + else + snprintf(propname, sizeof(propname), "%s", + gpio_suffixes[i]); + + ret = acpi_dev_get_property(adev, propname, ACPI_TYPE_ANY, + &obj); + if (ret == 0) { + if (obj->type == ACPI_TYPE_LOCAL_REFERENCE) + count = 1; + else if (obj->type == ACPI_TYPE_PACKAGE) + count = acpi_gpio_package_count(obj); + } else if (adev->driver_gpios) { + for (gm = adev->driver_gpios; gm->name; gm++) + if (strcmp(propname, gm->name) == 0) { + count = gm->size; + break; + } + } + if (count >= 0) + break; + } + + /* Then from plain _CRS GPIOs */ + if (count < 0) { + struct list_head resource_list; + unsigned int crs_count = 0; + + INIT_LIST_HEAD(&resource_list); + acpi_dev_get_resources(adev, &resource_list, + acpi_find_gpio_count, &crs_count); + acpi_dev_free_resource_list(&resource_list); + if (crs_count > 0) + count = crs_count; + } + return count; +} diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 2f8296c021e5..3d5b85a7dcdf 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1806,6 +1806,70 @@ static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, return desc; } +static int dt_gpio_count(struct device *dev, const char *con_id) +{ + int ret; + char propname[32]; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) { + if (con_id) + snprintf(propname, sizeof(propname), "%s-%s", + con_id, gpio_suffixes[i]); + else + snprintf(propname, sizeof(propname), "%s", + gpio_suffixes[i]); + + ret = of_gpio_named_count(dev->of_node, propname); + if (ret >= 0) + break; + } + return ret; +} + +static int platform_gpio_count(struct device *dev, const char *con_id) +{ + struct gpiod_lookup_table *table; + struct gpiod_lookup *p; + unsigned int count = 0; + + table = gpiod_find_lookup_table(dev); + if (!table) + return -ENOENT; + + for (p = &table->table[0]; p->chip_label; p++) { + if ((con_id && p->con_id && !strcmp(con_id, p->con_id)) || + (!con_id && !p->con_id)) + count++; + } + if (!count) + return -ENOENT; + + return count; +} + +/** + * gpiod_count - return the number of GPIOs associated with a device / function + * or -ENOENT if no GPIO has been assigned to the requested function + * @dev: GPIO consumer, can be NULL for system-global GPIOs + * @con_id: function within the GPIO consumer + */ +int gpiod_count(struct device *dev, const char *con_id) +{ + int count = -ENOENT; + + if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node) + count = dt_gpio_count(dev, con_id); + else if (IS_ENABLED(CONFIG_ACPI) && dev && ACPI_HANDLE(dev)) + count = acpi_gpio_count(dev, con_id); + + if (count < 0) + count = platform_gpio_count(dev, con_id); + + return count; +} +EXPORT_SYMBOL_GPL(gpiod_count); + /** * gpiod_get - obtain a GPIO for a given GPIO function * @dev: GPIO consumer, can be NULL for system-global GPIOs @@ -2089,6 +2153,72 @@ static void gpiochip_free_hogs(struct gpio_chip *chip) } } +/** + * gpiod_get_array - obtain multiple GPIOs from a multi-index GPIO function + * @dev: GPIO consumer, can be NULL for system-global GPIOs + * @con_id: function within the GPIO consumer + * @flags: optional GPIO initialization flags + * + * This function acquires all the GPIOs defined under a given function. + * + * Return a struct gpio_descs containing an array of descriptors, -ENOENT if + * no GPIO has been assigned to the requested function, or another IS_ERR() + * code if an error occurred while trying to acquire the GPIOs. + */ +struct gpio_descs *__must_check gpiod_get_array(struct device *dev, + const char *con_id, + enum gpiod_flags flags) +{ + struct gpio_desc *desc; + struct gpio_descs *descs; + int count; + + count = gpiod_count(dev, con_id); + if (count < 0) + return ERR_PTR(count); + + descs = kzalloc(sizeof(*descs) + sizeof(descs->desc[0]) * count, + GFP_KERNEL); + if (!descs) + return ERR_PTR(-ENOMEM); + + for (descs->ndescs = 0; descs->ndescs < count; ) { + desc = gpiod_get_index(dev, con_id, descs->ndescs, flags); + if (IS_ERR(desc)) { + gpiod_put_array(descs); + return ERR_CAST(desc); + } + descs->desc[descs->ndescs] = desc; + descs->ndescs++; + } + return descs; +} +EXPORT_SYMBOL_GPL(gpiod_get_array); + +/** + * gpiod_get_array_optional - obtain multiple GPIOs from a multi-index GPIO + * function + * @dev: GPIO consumer, can be NULL for system-global GPIOs + * @con_id: function within the GPIO consumer + * @flags: optional GPIO initialization flags + * + * This is equivalent to gpiod_get_array(), except that when no GPIO was + * assigned to the requested function it will return NULL. + */ +struct gpio_descs *__must_check gpiod_get_array_optional(struct device *dev, + const char *con_id, + enum gpiod_flags flags) +{ + struct gpio_descs *descs; + + descs = gpiod_get_array(dev, con_id, flags); + if (IS_ERR(descs) && (PTR_ERR(descs) == -ENOENT)) + return NULL; + + return descs; +} +EXPORT_SYMBOL_GPL(gpiod_get_array_optional); + /** * gpiod_put - dispose of a GPIO descriptor * @desc: GPIO descriptor to dispose of @@ -2101,6 +2231,21 @@ void gpiod_put(struct gpio_desc *desc) } EXPORT_SYMBOL_GPL(gpiod_put); +/** + * gpiod_put_array - dispose of multiple GPIO descriptors + * @descs: struct gpio_descs containing an array of descriptors + */ +void gpiod_put_array(struct gpio_descs *descs) +{ + unsigned int i; + + for (i = 0; i < descs->ndescs; i++) + gpiod_put(descs->desc[i]); + + kfree(descs); +} +EXPORT_SYMBOL_GPL(gpiod_put_array); + #ifdef CONFIG_DEBUG_FS static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip) diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index 205dd12659c0..54bc5ec91398 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -40,6 +40,8 @@ void acpi_gpiochip_free_interrupts(struct gpio_chip *chip); struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev, const char *propname, int index, struct acpi_gpio_info *info); + +int acpi_gpio_count(struct device *dev, const char *con_id); #else static inline void acpi_gpiochip_add(struct gpio_chip *chip) { } static inline void acpi_gpiochip_remove(struct gpio_chip *chip) { } @@ -56,6 +58,11 @@ acpi_get_gpiod_by_index(struct acpi_device *adev, const char *propname, { return ERR_PTR(-ENOSYS); } + +static inline int acpi_gpio_count(struct device *dev, const char *con_id) +{ + return -ENODEV; +} #endif struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np, diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h index ed20759229eb..33eb52fd0932 100644 --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h @@ -16,6 +16,15 @@ struct device; */ struct gpio_desc; +/** + * Struct containing an array of descriptors that can be obtained using + * gpiod_get_array(). + */ +struct gpio_descs { + unsigned int ndescs; + struct gpio_desc *desc[]; +}; + #define GPIOD_FLAGS_BIT_DIR_SET BIT(0) #define GPIOD_FLAGS_BIT_DIR_OUT BIT(1) #define GPIOD_FLAGS_BIT_DIR_VAL BIT(2) @@ -34,6 +43,9 @@ enum gpiod_flags { #ifdef CONFIG_GPIOLIB +/* Return the number of GPIOs associated with a device / function */ +int gpiod_count(struct device *dev, const char *con_id); + /* Acquire and dispose GPIOs */ struct gpio_desc *__must_check __gpiod_get(struct device *dev, const char *con_id, @@ -49,7 +61,14 @@ struct gpio_desc *__must_check __gpiod_get_index_optional(struct device *dev, const char *con_id, unsigned int index, enum gpiod_flags flags); +struct gpio_descs *__must_check gpiod_get_array(struct device *dev, + const char *con_id, + enum gpiod_flags flags); +struct gpio_descs *__must_check gpiod_get_array_optional(struct device *dev, + const char *con_id, + enum gpiod_flags flags); void gpiod_put(struct gpio_desc *desc); +void gpiod_put_array(struct gpio_descs *descs); struct gpio_desc *__must_check __devm_gpiod_get(struct device *dev, const char *con_id, @@ -114,6 +133,11 @@ struct gpio_desc *devm_get_gpiod_from_child(struct device *dev, struct fwnode_handle *child); #else /* CONFIG_GPIOLIB */ +static inline int gpiod_count(struct device *dev, const char *con_id) +{ + return 0; +} + static inline struct gpio_desc *__must_check __gpiod_get(struct device *dev, const char *con_id, enum gpiod_flags flags) @@ -143,6 +167,20 @@ __gpiod_get_index_optional(struct device *dev, const char *con_id, return ERR_PTR(-ENOSYS); } +static inline struct gpio_descs *__must_check +gpiod_get_array(struct device *dev, const char *con_id, + enum gpiod_flags flags) +{ + return ERR_PTR(-ENOSYS); +} + +static inline struct gpio_descs *__must_check +gpiod_get_array_optional(struct device *dev, const char *con_id, + enum gpiod_flags flags) +{ + return ERR_PTR(-ENOSYS); +} + static inline void gpiod_put(struct gpio_desc *desc) { might_sleep(); @@ -151,6 +189,14 @@ static inline void gpiod_put(struct gpio_desc *desc) WARN_ON(1); } +static inline void gpiod_put_array(struct gpio_descs *descs) +{ + might_sleep(); + + /* GPIO can never have been requested */ + WARN_ON(1); +} + static inline struct gpio_desc *__must_check __devm_gpiod_get(struct device *dev, const char *con_id, -- cgit v1.2.3-59-g8ed1b From 331758eef83620eef3f21289f0f44aba094d0503 Mon Sep 17 00:00:00 2001 From: Rojhalat Ibrahim Date: Wed, 11 Feb 2015 17:28:02 +0100 Subject: gpiolib: add devm_gpiod_get_array and devm_gpiod_put_array functions Add device managed variants of gpiod_get_array() / gpiod_put_array() functions for conveniently obtaining and disposing of an entire array of GPIOs with one function call. Signed-off-by: Rojhalat Ibrahim Reviewed-by: Alexandre Courbot Signed-off-by: Linus Walleij --- Documentation/gpio/consumer.txt | 14 ++++++- drivers/gpio/devres.c | 89 +++++++++++++++++++++++++++++++++++++++++ include/linux/gpio/consumer.h | 30 ++++++++++++++ 3 files changed, 131 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/gpio/consumer.txt b/Documentation/gpio/consumer.txt index 2924f2ffcd91..d29a9725c9e5 100644 --- a/Documentation/gpio/consumer.txt +++ b/Documentation/gpio/consumer.txt @@ -102,11 +102,19 @@ Device-managed variants of these functions are also defined: const char *con_id, enum gpiod_flags flags) - struct gpio_desc * devm_gpiod_get_index_optional(struct device *dev, + struct gpio_desc *devm_gpiod_get_index_optional(struct device *dev, const char *con_id, unsigned int index, enum gpiod_flags flags) + struct gpio_descs *devm_gpiod_get_array(struct device *dev, + const char *con_id, + enum gpiod_flags flags) + + struct gpio_descs *devm_gpiod_get_array_optional(struct device *dev, + const char *con_id, + enum gpiod_flags flags) + A GPIO descriptor can be disposed of using the gpiod_put() function: void gpiod_put(struct gpio_desc *desc) @@ -119,10 +127,12 @@ It is strictly forbidden to use a descriptor after calling these functions. It is also not allowed to individually release descriptors (using gpiod_put()) from an array acquired with gpiod_get_array(). -The device-managed variant is, unsurprisingly: +The device-managed variants are, unsurprisingly: void devm_gpiod_put(struct device *dev, struct gpio_desc *desc) + void devm_gpiod_put_array(struct device *dev, struct gpio_descs *descs) + Using GPIOs =========== diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c index 12c2082f968e..ec24da2418b3 100644 --- a/drivers/gpio/devres.c +++ b/drivers/gpio/devres.c @@ -35,6 +35,20 @@ static int devm_gpiod_match(struct device *dev, void *res, void *data) return *this == *gpio; } +static void devm_gpiod_release_array(struct device *dev, void *res) +{ + struct gpio_descs **descs = res; + + gpiod_put_array(*descs); +} + +static int devm_gpiod_match_array(struct device *dev, void *res, void *data) +{ + struct gpio_descs **this = res, **gpios = data; + + return *this == *gpios; +} + /** * devm_gpiod_get - Resource-managed gpiod_get() * @dev: GPIO consumer @@ -185,6 +199,66 @@ struct gpio_desc *__must_check __devm_gpiod_get_index_optional(struct device *de } EXPORT_SYMBOL(__devm_gpiod_get_index_optional); +/** + * devm_gpiod_get_array - Resource-managed gpiod_get_array() + * @dev: GPIO consumer + * @con_id: function within the GPIO consumer + * @flags: optional GPIO initialization flags + * + * Managed gpiod_get_array(). GPIO descriptors returned from this function are + * automatically disposed on driver detach. See gpiod_get_array() for detailed + * information about behavior and return values. + */ +struct gpio_descs *__must_check devm_gpiod_get_array(struct device *dev, + const char *con_id, + enum gpiod_flags flags) +{ + struct gpio_descs **dr; + struct gpio_descs *descs; + + dr = devres_alloc(devm_gpiod_release_array, + sizeof(struct gpio_descs *), GFP_KERNEL); + if (!dr) + return ERR_PTR(-ENOMEM); + + descs = gpiod_get_array(dev, con_id, flags); + if (IS_ERR(descs)) { + devres_free(dr); + return descs; + } + + *dr = descs; + devres_add(dev, dr); + + return descs; +} +EXPORT_SYMBOL(devm_gpiod_get_array); + +/** + * devm_gpiod_get_array_optional - Resource-managed gpiod_get_array_optional() + * @dev: GPIO consumer + * @con_id: function within the GPIO consumer + * @flags: optional GPIO initialization flags + * + * Managed gpiod_get_array_optional(). GPIO descriptors returned from this + * function are automatically disposed on driver detach. + * See gpiod_get_array_optional() for detailed information about behavior and + * return values. + */ +struct gpio_descs *__must_check +devm_gpiod_get_array_optional(struct device *dev, const char *con_id, + enum gpiod_flags flags) +{ + struct gpio_descs *descs; + + descs = devm_gpiod_get_array(dev, con_id, flags); + if (IS_ERR(descs) && (PTR_ERR(descs) == -ENOENT)) + return NULL; + + return descs; +} +EXPORT_SYMBOL(devm_gpiod_get_array_optional); + /** * devm_gpiod_put - Resource-managed gpiod_put() * @desc: GPIO descriptor to dispose of @@ -200,6 +274,21 @@ void devm_gpiod_put(struct device *dev, struct gpio_desc *desc) } EXPORT_SYMBOL(devm_gpiod_put); +/** + * devm_gpiod_put_array - Resource-managed gpiod_put_array() + * @descs: GPIO descriptor array to dispose of + * + * Dispose of an array of GPIO descriptors obtained with devm_gpiod_get_array(). + * Normally this function will not be called as the GPIOs will be disposed of + * by the resource management code. + */ +void devm_gpiod_put_array(struct device *dev, struct gpio_descs *descs) +{ + WARN_ON(devres_release(dev, devm_gpiod_release_array, + devm_gpiod_match_array, &descs)); +} +EXPORT_SYMBOL(devm_gpiod_put_array); + diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h index 33eb52fd0932..3a7c9ffd5ab9 100644 --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h @@ -83,7 +83,14 @@ struct gpio_desc *__must_check __devm_gpiod_get_optional(struct device *dev, struct gpio_desc *__must_check __devm_gpiod_get_index_optional(struct device *dev, const char *con_id, unsigned int index, enum gpiod_flags flags); +struct gpio_descs *__must_check devm_gpiod_get_array(struct device *dev, + const char *con_id, + enum gpiod_flags flags); +struct gpio_descs *__must_check +devm_gpiod_get_array_optional(struct device *dev, const char *con_id, + enum gpiod_flags flags); void devm_gpiod_put(struct device *dev, struct gpio_desc *desc); +void devm_gpiod_put_array(struct device *dev, struct gpio_descs *descs); int gpiod_get_direction(struct gpio_desc *desc); int gpiod_direction_input(struct gpio_desc *desc); @@ -228,6 +235,20 @@ __devm_gpiod_get_index_optional(struct device *dev, const char *con_id, return ERR_PTR(-ENOSYS); } +static inline struct gpio_descs *__must_check +devm_gpiod_get_array(struct device *dev, const char *con_id, + enum gpiod_flags flags) +{ + return ERR_PTR(-ENOSYS); +} + +static inline struct gpio_descs *__must_check +devm_gpiod_get_array_optional(struct device *dev, const char *con_id, + enum gpiod_flags flags) +{ + return ERR_PTR(-ENOSYS); +} + static inline void devm_gpiod_put(struct device *dev, struct gpio_desc *desc) { might_sleep(); @@ -236,6 +257,15 @@ static inline void devm_gpiod_put(struct device *dev, struct gpio_desc *desc) WARN_ON(1); } +static inline void devm_gpiod_put_array(struct device *dev, + struct gpio_descs *descs) +{ + might_sleep(); + + /* GPIO can never have been requested */ + WARN_ON(1); +} + static inline int gpiod_get_direction(const struct gpio_desc *desc) { -- cgit v1.2.3-59-g8ed1b From 45ad3e67f663af3f7988552165e8b8ebddde0ac7 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 5 Mar 2015 15:42:51 +0000 Subject: ASoC: wm8804: Update DT binding document to cover regulator supplies Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/wm8804.txt | 3 +++ 1 file changed, 3 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/wm8804.txt b/Documentation/devicetree/bindings/sound/wm8804.txt index 4d3a56f38adc..10ef07606b84 100644 --- a/Documentation/devicetree/bindings/sound/wm8804.txt +++ b/Documentation/devicetree/bindings/sound/wm8804.txt @@ -10,6 +10,9 @@ Required properties: - reg : the I2C address of the device for I2C, the chip select number for SPI. + - PVDD-supply, DVDD-supply : Power supplies for the device, as covered + in Documentation/devicetree/bindings/regulator/regulator.txt + Example: codec: wm8804@1a { -- cgit v1.2.3-59-g8ed1b From 7f43a87e06e2f19892ff3f278e0181cbf9901b15 Mon Sep 17 00:00:00 2001 From: Matt Porter Date: Wed, 4 Mar 2015 14:12:58 -0500 Subject: spi: fsl-imx-cspi: add explicit compatible strings and required clock properties The fsl-imx-cspi binding contains language indicating compatible strings to be used that is not valid for all supported parts e.g. Should be "fsl,-cspi" or "fsl,-ecspi". Fix this by enumerating the set of valid compatible strings. The binding is also missing the clocks/clock-names properties so document these and the two required ipg and per clocks. Signed-off-by: Matt Porter Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/fsl-imx-cspi.txt | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/spi/fsl-imx-cspi.txt b/Documentation/devicetree/bindings/spi/fsl-imx-cspi.txt index aad527b357a0..523341a0e113 100644 --- a/Documentation/devicetree/bindings/spi/fsl-imx-cspi.txt +++ b/Documentation/devicetree/bindings/spi/fsl-imx-cspi.txt @@ -2,11 +2,21 @@ (CSPI/eCSPI) for i.MX Required properties: -- compatible : Should be "fsl,-cspi" or "fsl,-ecspi" +- compatible : + - "fsl,imx1-cspi" for SPI compatible with the one integrated on i.MX1 + - "fsl,imx21-cspi" for SPI compatible with the one integrated on i.MX21 + - "fsl,imx27-cspi" for SPI compatible with the one integrated on i.MX27 + - "fsl,imx31-cspi" for SPI compatible with the one integrated on i.MX31 + - "fsl,imx35-cspi" for SPI compatible with the one integrated on i.MX35 + - "fsl,imx51-ecspi" for SPI compatible with the one integrated on i.MX51 - reg : Offset and length of the register set for the device - interrupts : Should contain CSPI/eCSPI interrupt - fsl,spi-num-chipselects : Contains the number of the chipselect - cs-gpios : Specifies the gpio pins to be used for chipselects. +- clocks : Clock specifiers for both ipg and per clocks. +- clock-names : Clock names should include both "ipg" and "per" +See the clock consumer binding, + Documentation/devicetree/bindings/clock/clock-bindings.txt - dmas: DMA specifiers for tx and rx dma. See the DMA client binding, Documentation/devicetree/bindings/dma/dma.txt - dma-names: DMA request names should include "tx" and "rx" if present. -- cgit v1.2.3-59-g8ed1b From 8dd72c42d38e62b82d7e3c47173b502d851c48ad Mon Sep 17 00:00:00 2001 From: Kenneth Westfield Date: Tue, 3 Mar 2015 16:21:51 -0800 Subject: ASoC: qcom: Document LPASS CPU bindings Add documentation to the sound directory of the device-tree bindings for the QTi LPASS CPU DAI device. Signed-off-by: Kenneth Westfield Acked-by: Banajit Goswami Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/qcom,lpass-cpu.txt | 49 ++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt b/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt new file mode 100644 index 000000000000..e7c6e9321863 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt @@ -0,0 +1,49 @@ +* Qualcomm Technologies LPASS CPU DAI + +This node models the Qualcomm Technologies Low-Power Audio SubSystem (LPASS). + +Required properties: + +- compatible : "qcom,lpass-cpu" +- clocks : Must contain an entry for each entry in clock-names. +- clock-names : A list which must include the following entries: + * "ahbix-clk" + * "mi2s-osr-clk" + * "mi2s-bit-clk" +- interrupts : Must contain an entry for each entry in + interrupt-names. +- interrupt-names : A list which must include the following entries: + * "lpass-irq-lpaif" +- pinctrl-N : One property must exist for each entry in + pinctrl-names. See ../pinctrl/pinctrl-bindings.txt + for details of the property values. +- pinctrl-names : Must contain a "default" entry. +- reg : Must contain an address for each entry in reg-names. +- reg-names : A list which must include the following entries: + * "lpass-lpaif" + +Required subnodes: + +- qcom,adsp : Audio DSP sub-node + +Optional Audio DSP subnode properties: + +- status : "disabled" indicates the adsp is not available. + +Example: + +lpass@28100000 { + compatible = "qcom,lpass-cpu"; + clocks = <&lcc AHBIX_CLK>, <&lcc MI2S_OSR_CLK>, <&lcc MI2S_BIT_CLK>; + clock-names = "ahbix-clk", "mi2s-osr-clk", "mi2s-bit-clk"; + interrupts = <0 85 1>; + interrupt-names = "lpass-irq-lpaif"; + pinctrl-names = "default", "idle"; + pinctrl-0 = <&mi2s_default>; + pinctrl-1 = <&mi2s_idle>; + reg = <0x28100000 0x10000>; + reg-names = "lpass-lpaif"; + qcom,adsp { + status = "disabled"; + }; +}; -- cgit v1.2.3-59-g8ed1b From d8bf368d0631d4bc2612d8bf2e4e8e74e620d0cc Mon Sep 17 00:00:00 2001 From: Valentin Rothberg Date: Thu, 5 Mar 2015 15:23:08 +0100 Subject: genirq: Remove the deprecated 'IRQF_DISABLED' request_irq() flag entirely The IRQF_DISABLED flag is a NOOP and has been scheduled for removal since Linux v2.6.36 by commit 6932bf37bed4 ("genirq: Remove IRQF_DISABLED from core code"). According to commit e58aa3d2d0cc ("genirq: Run irq handlers with interrupts disabled"), running IRQ handlers with interrupts enabled can cause stack overflows when the interrupt line of the issuing device is still active. This patch ends the grace period for IRQF_DISABLED (i.e., SA_INTERRUPT in older versions of Linux) and removes the definition and all remaining usages of this flag. There's still a few non-functional references left in the kernel source: - The bigger hunk in Documentation/scsi/ncr53c8xx.txt is removed entirely as IRQF_DISABLED is gone now; the usage in older kernel versions (including the old SA_INTERRUPT flag) should be discouraged. The trouble of using IRQF_SHARED is a general problem and not specific to any driver. - I left the reference in Documentation/PCI/MSI-HOWTO.txt untouched since it has already been removed in linux-next. - All remaining references are changelogs that I suggest to keep. Signed-off-by: Valentin Rothberg Cc: Afzal Mohammed Cc: Arnd Bergmann Cc: Brian Norris Cc: Christoph Hellwig Cc: Dan Carpenter Cc: David Woodhouse Cc: Ewan Milne Cc: Eyal Perry Cc: Felipe Balbi Cc: Greg Kroah-Hartman Cc: H. Peter Anvin Cc: Hannes Reinecke Cc: Hongliang Tao Cc: Huacai Chen Cc: Jiri Kosina Cc: Jonathan Corbet Cc: Keerthy Cc: Laurent Pinchart Cc: Linus Torvalds Cc: Nishanth Menon Cc: Paul Bolle Cc: Peter Ujfalusi Cc: Peter Zijlstra Cc: Quentin Lambert Cc: Rajendra Nayak Cc: Ralf Baechle Cc: Santosh Shilimkar Cc: Sricharan R Cc: Thomas Gleixner Cc: Tony Lindgren Cc: Zhou Wang Cc: iss_storagedev@hp.com Cc: linux-mips@linux-mips.org Cc: linux-mtd@lists.infradead.org Link: http://lkml.kernel.org/r/1425565425-12604-1-git-send-email-valentinrothberg@gmail.com Signed-off-by: Ingo Molnar --- Documentation/scsi/ncr53c8xx.txt | 25 ------------------------- Documentation/scsi/tmscsim.txt | 4 ---- arch/mips/loongson/loongson-3/hpet.c | 2 +- drivers/block/cpqarray.c | 4 ++-- drivers/bus/omap_l3_noc.c | 4 ++-- drivers/bus/omap_l3_smx.c | 10 ++++------ drivers/mtd/nand/hisi504_nand.c | 3 +-- drivers/usb/isp1760/isp1760-core.c | 3 +-- drivers/usb/isp1760/isp1760-udc.c | 4 ++-- include/linux/interrupt.h | 3 --- 10 files changed, 13 insertions(+), 49 deletions(-) (limited to 'Documentation') diff --git a/Documentation/scsi/ncr53c8xx.txt b/Documentation/scsi/ncr53c8xx.txt index 1d508dcbf859..8586efff1e99 100644 --- a/Documentation/scsi/ncr53c8xx.txt +++ b/Documentation/scsi/ncr53c8xx.txt @@ -786,7 +786,6 @@ port address 0x1400. irqm:1 same as initial settings (assumed BIOS settings) irqm:2 always totem pole irqm:0x10 driver will not use IRQF_SHARED flag when requesting irq - irqm:0x20 driver will not use IRQF_DISABLED flag when requesting irq (Bits 0x10 and 0x20 can be combined with hardware irq mode option) @@ -1231,30 +1230,6 @@ they only refer to system buffers that are well aligned. So, a work around may only be needed under Linux when a scatter/gather list is not used and when the SCSI DATA IN phase is reentered after a phase mismatch. -14.5 IRQ sharing problems - -When an IRQ is shared by devices that are handled by different drivers, it -may happen that one driver complains about the request of the IRQ having -failed. Inder Linux-2.0, this may be due to one driver having requested the -IRQ using the IRQF_DISABLED flag but some other having requested the same IRQ -without this flag. Under both Linux-2.0 and linux-2.2, this may be caused by -one driver not having requested the IRQ with the IRQF_SHARED flag. - -By default, the ncr53c8xx and sym53c8xx drivers request IRQs with both the -IRQF_DISABLED and the IRQF_SHARED flag under Linux-2.0 and with only the IRQF_SHARED -flag under Linux-2.2. - -Under Linux-2.0, you can disable use of IRQF_DISABLED flag from the boot -command line by using the following option: - - ncr53c8xx=irqm:0x20 (for the generic ncr53c8xx driver) - sym53c8xx=irqm:0x20 (for the sym53c8xx driver) - -If this does not fix the problem, then you may want to check how all other -drivers are requesting the IRQ and report the problem. Note that if at least -a single driver does not request the IRQ with the IRQF_SHARED flag (share IRQ), -then the request of the IRQ obviously will not succeed for all the drivers. - 15. SCSI problem troubleshooting 15.1 Problem tracking diff --git a/Documentation/scsi/tmscsim.txt b/Documentation/scsi/tmscsim.txt index 0810132772a8..0e0322bf0020 100644 --- a/Documentation/scsi/tmscsim.txt +++ b/Documentation/scsi/tmscsim.txt @@ -107,10 +107,6 @@ produced errors and started to corrupt my disks. So don't do that! A 37.50 MHz PCI bus works for me, though, but I don't recommend using higher clocks than the 33.33 MHz being in the PCI spec. -If you want to share the IRQ with another device and the driver refuses to -do so, you might succeed with changing the DC390_IRQ type in tmscsim.c to -IRQF_SHARED | IRQF_DISABLED. - 3.Features ---------- diff --git a/arch/mips/loongson/loongson-3/hpet.c b/arch/mips/loongson/loongson-3/hpet.c index e898d68668a9..5c21cd3bd339 100644 --- a/arch/mips/loongson/loongson-3/hpet.c +++ b/arch/mips/loongson/loongson-3/hpet.c @@ -162,7 +162,7 @@ static irqreturn_t hpet_irq_handler(int irq, void *data) static struct irqaction hpet_irq = { .handler = hpet_irq_handler, - .flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_TIMER, + .flags = IRQF_NOBALANCING | IRQF_TIMER, .name = "hpet", }; diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c index 2b9440384536..f749df9e15cd 100644 --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -405,8 +405,8 @@ static int cpqarray_register_ctlr(int i, struct pci_dev *pdev) goto Enomem4; } hba[i]->access.set_intr_mask(hba[i], 0); - if (request_irq(hba[i]->intr, do_ida_intr, - IRQF_DISABLED|IRQF_SHARED, hba[i]->devname, hba[i])) + if (request_irq(hba[i]->intr, do_ida_intr, IRQF_SHARED, + hba[i]->devname, hba[i])) { printk(KERN_ERR "cpqarray: Unable to get irq %d for %s\n", hba[i]->intr, hba[i]->devname); diff --git a/drivers/bus/omap_l3_noc.c b/drivers/bus/omap_l3_noc.c index 029bc73de001..11f7982cbdb3 100644 --- a/drivers/bus/omap_l3_noc.c +++ b/drivers/bus/omap_l3_noc.c @@ -284,7 +284,7 @@ static int omap_l3_probe(struct platform_device *pdev) */ l3->debug_irq = platform_get_irq(pdev, 0); ret = devm_request_irq(l3->dev, l3->debug_irq, l3_interrupt_handler, - IRQF_DISABLED, "l3-dbg-irq", l3); + 0x0, "l3-dbg-irq", l3); if (ret) { dev_err(l3->dev, "request_irq failed for %d\n", l3->debug_irq); @@ -293,7 +293,7 @@ static int omap_l3_probe(struct platform_device *pdev) l3->app_irq = platform_get_irq(pdev, 1); ret = devm_request_irq(l3->dev, l3->app_irq, l3_interrupt_handler, - IRQF_DISABLED, "l3-app-irq", l3); + 0x0, "l3-app-irq", l3); if (ret) dev_err(l3->dev, "request_irq failed for %d\n", l3->app_irq); diff --git a/drivers/bus/omap_l3_smx.c b/drivers/bus/omap_l3_smx.c index 597fdaee7315..360a5c0a4ee0 100644 --- a/drivers/bus/omap_l3_smx.c +++ b/drivers/bus/omap_l3_smx.c @@ -251,18 +251,16 @@ static int omap3_l3_probe(struct platform_device *pdev) } l3->debug_irq = platform_get_irq(pdev, 0); - ret = request_irq(l3->debug_irq, omap3_l3_app_irq, - IRQF_DISABLED | IRQF_TRIGGER_RISING, - "l3-debug-irq", l3); + ret = request_irq(l3->debug_irq, omap3_l3_app_irq, IRQF_TRIGGER_RISING, + "l3-debug-irq", l3); if (ret) { dev_err(&pdev->dev, "couldn't request debug irq\n"); goto err1; } l3->app_irq = platform_get_irq(pdev, 1); - ret = request_irq(l3->app_irq, omap3_l3_app_irq, - IRQF_DISABLED | IRQF_TRIGGER_RISING, - "l3-app-irq", l3); + ret = request_irq(l3->app_irq, omap3_l3_app_irq, IRQF_TRIGGER_RISING, + "l3-app-irq", l3); if (ret) { dev_err(&pdev->dev, "couldn't request app irq\n"); goto err2; diff --git a/drivers/mtd/nand/hisi504_nand.c b/drivers/mtd/nand/hisi504_nand.c index 289ad3ac3e80..8dcc7b8fee40 100644 --- a/drivers/mtd/nand/hisi504_nand.c +++ b/drivers/mtd/nand/hisi504_nand.c @@ -758,8 +758,7 @@ static int hisi_nfc_probe(struct platform_device *pdev) hisi_nfc_host_init(host); - ret = devm_request_irq(dev, irq, hinfc_irq_handle, IRQF_DISABLED, - "nandc", host); + ret = devm_request_irq(dev, irq, hinfc_irq_handle, 0x0, "nandc", host); if (ret) { dev_err(dev, "failed to request IRQ\n"); goto err_res; diff --git a/drivers/usb/isp1760/isp1760-core.c b/drivers/usb/isp1760/isp1760-core.c index b9827556455f..5c37f40f6122 100644 --- a/drivers/usb/isp1760/isp1760-core.c +++ b/drivers/usb/isp1760/isp1760-core.c @@ -151,8 +151,7 @@ int isp1760_register(struct resource *mem, int irq, unsigned long irqflags, } if (IS_ENABLED(CONFIG_USB_ISP1761_UDC) && !udc_disabled) { - ret = isp1760_udc_register(isp, irq, irqflags | IRQF_SHARED | - IRQF_DISABLED); + ret = isp1760_udc_register(isp, irq, irqflags | IRQF_SHARED); if (ret < 0) { isp1760_hcd_unregister(&isp->hcd); return ret; diff --git a/drivers/usb/isp1760/isp1760-udc.c b/drivers/usb/isp1760/isp1760-udc.c index 9612d7990565..0b46ff01299f 100644 --- a/drivers/usb/isp1760/isp1760-udc.c +++ b/drivers/usb/isp1760/isp1760-udc.c @@ -1451,8 +1451,8 @@ int isp1760_udc_register(struct isp1760_device *isp, int irq, sprintf(udc->irqname, "%s (udc)", devname); - ret = request_irq(irq, isp1760_udc_irq, IRQF_SHARED | IRQF_DISABLED | - irqflags, udc->irqname, udc); + ret = request_irq(irq, isp1760_udc_irq, IRQF_SHARED | irqflags, + udc->irqname, udc); if (ret < 0) goto error; diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 3bb01b9a379c..2cee1761c77d 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -39,8 +39,6 @@ * These flags used only by the kernel as part of the * irq handling routines. * - * IRQF_DISABLED - keep irqs disabled when calling the action handler. - * DEPRECATED. This flag is a NOOP and scheduled to be removed * IRQF_SHARED - allow sharing the irq among several devices * IRQF_PROBE_SHARED - set by callers when they expect sharing mismatches to occur * IRQF_TIMER - Flag to mark this interrupt as timer interrupt @@ -58,7 +56,6 @@ * IRQF_EARLY_RESUME - Resume IRQ early during syscore instead of at device * resume time. */ -#define IRQF_DISABLED 0x00000020 #define IRQF_SHARED 0x00000080 #define IRQF_PROBE_SHARED 0x00000100 #define __IRQF_TIMER 0x00000200 -- cgit v1.2.3-59-g8ed1b From 259d317f8d584503c5e3c43bbb96d80149390939 Mon Sep 17 00:00:00 2001 From: Scott Branden Date: Wed, 4 Mar 2015 12:42:13 -0800 Subject: hwrng: iproc-rng200 - Add device tree bindings Documents the IPROC random number generator device tree bindings used in some Broadcom chipsets. Reviewed-by: Ray Jui Signed-off-by: Scott Branden Signed-off-by: Herbert Xu --- .../devicetree/bindings/hwrng/brcm,iproc-rng200.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 Documentation/devicetree/bindings/hwrng/brcm,iproc-rng200.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/hwrng/brcm,iproc-rng200.txt b/Documentation/devicetree/bindings/hwrng/brcm,iproc-rng200.txt new file mode 100644 index 000000000000..e25a456664b9 --- /dev/null +++ b/Documentation/devicetree/bindings/hwrng/brcm,iproc-rng200.txt @@ -0,0 +1,12 @@ +HWRNG support for the iproc-rng200 driver + +Required properties: +- compatible : "brcm,iproc-rng200" +- reg : base address and size of control register block + +Example: + +rng { + compatible = "brcm,iproc-rng200"; + reg = <0x18032000 0x28>; +}; -- cgit v1.2.3-59-g8ed1b From 68c557501b008515cb86c9a36c75f4e82e14a819 Mon Sep 17 00:00:00 2001 From: Eric Farman Date: Mon, 9 Jun 2014 10:57:26 -0400 Subject: KVM: s390: Allocate and save/restore vector registers Define and allocate space for both the host and guest views of the vector registers for a given vcpu. The 32 vector registers occupy 128 bits each (512 bytes total), but architecturally are paired with 512 additional bytes of reserved space for future expansion. The kvm_sync_regs structs containing the registers are union'ed with 1024 bytes of padding in the common kvm_run struct. The addition of 1024 bytes of new register information clearly exceeds the existing union, so an expansion of that padding is required. When changing environments, we need to appropriately save and restore the vector registers viewed by both the host and guest, into and out of the sync_regs space. The floating point registers overlay the upper half of vector registers 0-15, so there's a bit of data duplication here that needs to be carefully avoided. Signed-off-by: Eric Farman Reviewed-by: Thomas Huth Acked-by: Christian Borntraeger Signed-off-by: Christian Borntraeger --- Documentation/virtual/kvm/api.txt | 10 ++++++++++ arch/s390/include/asm/kvm_host.h | 10 +++++++++- arch/s390/include/uapi/asm/kvm.h | 4 ++++ arch/s390/kvm/kvm-s390.c | 39 +++++++++++++++++++++++++++++++++------ include/uapi/linux/kvm.h | 3 ++- 5 files changed, 58 insertions(+), 8 deletions(-) (limited to 'Documentation') diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index b112efc816f1..ee47998ec368 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -3248,3 +3248,13 @@ All other orders will be handled completely in user space. Only privileged operation exceptions will be checked for in the kernel (or even in the hardware prior to interception). If this capability is not enabled, the old way of handling SIGP orders is used (partially in kernel and user space). + +7.3 KVM_CAP_S390_VECTOR_REGISTERS + +Architectures: s390 +Parameters: none +Returns: 0 on success, negative value on error + +Allows use of the vector registers introduced with z13 processor, and +provides for the synchronization between host and user space. Will +return -EINVAL if the machine does not support vectors. diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h index f407bbf5ee94..3449a388b169 100644 --- a/arch/s390/include/asm/kvm_host.h +++ b/arch/s390/include/asm/kvm_host.h @@ -183,11 +183,17 @@ struct kvm_s390_itdb { __u8 data[256]; } __packed; +struct kvm_s390_vregs { + __vector128 vrs[32]; + __u8 reserved200[512]; /* for future vector expansion */ +} __packed; + struct sie_page { struct kvm_s390_sie_block sie_block; __u8 reserved200[1024]; /* 0x0200 */ struct kvm_s390_itdb itdb; /* 0x0600 */ - __u8 reserved700[2304]; /* 0x0700 */ + __u8 reserved700[1280]; /* 0x0700 */ + struct kvm_s390_vregs vregs; /* 0x0c00 */ } __packed; struct kvm_vcpu_stat { @@ -465,6 +471,7 @@ struct kvm_vcpu_arch { s390_fp_regs host_fpregs; unsigned int host_acrs[NUM_ACRS]; s390_fp_regs guest_fpregs; + struct kvm_s390_vregs *host_vregs; struct kvm_s390_local_interrupt local_int; struct hrtimer ckc_timer; struct kvm_s390_pgm_info pgm; @@ -551,6 +558,7 @@ struct kvm_arch{ int css_support; int use_irqchip; int use_cmma; + int use_vectors; int user_cpu_state_ctrl; int user_sigp; struct s390_io_adapter *adapters[MAX_S390_IO_ADAPTERS]; diff --git a/arch/s390/include/uapi/asm/kvm.h b/arch/s390/include/uapi/asm/kvm.h index 9c77e60b9a26..ef1a5fcc6c66 100644 --- a/arch/s390/include/uapi/asm/kvm.h +++ b/arch/s390/include/uapi/asm/kvm.h @@ -150,6 +150,7 @@ struct kvm_guest_debug_arch { #define KVM_SYNC_CRS (1UL << 3) #define KVM_SYNC_ARCH0 (1UL << 4) #define KVM_SYNC_PFAULT (1UL << 5) +#define KVM_SYNC_VRS (1UL << 6) /* definition of registers in kvm_run */ struct kvm_sync_regs { __u64 prefix; /* prefix register */ @@ -164,6 +165,9 @@ struct kvm_sync_regs { __u64 pft; /* pfault token [PFAULT] */ __u64 pfs; /* pfault select [PFAULT] */ __u64 pfc; /* pfault compare [PFAULT] */ + __u64 vrs[32][2]; /* vector registers */ + __u8 reserved[512]; /* for future vector expansion */ + __u32 fpc; /* only valid with vector registers */ }; #define KVM_REG_S390_TODPR (KVM_REG_S390 | KVM_REG_SIZE_U32 | 0x1) diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index f3517e716fa4..a8fe3ab76d68 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -185,6 +185,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_S390_COW: r = MACHINE_HAS_ESOP; break; + case KVM_CAP_S390_VECTOR_REGISTERS: + r = MACHINE_HAS_VX; + break; default: r = 0; } @@ -265,6 +268,10 @@ static int kvm_vm_ioctl_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap) kvm->arch.user_sigp = 1; r = 0; break; + case KVM_CAP_S390_VECTOR_REGISTERS: + kvm->arch.use_vectors = MACHINE_HAS_VX; + r = MACHINE_HAS_VX ? 0 : -EINVAL; + break; default: r = -EINVAL; break; @@ -942,6 +949,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) kvm->arch.css_support = 0; kvm->arch.use_irqchip = 0; + kvm->arch.use_vectors = 0; kvm->arch.epoch = 0; spin_lock_init(&kvm->arch.start_stop_lock); @@ -1035,6 +1043,8 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) KVM_SYNC_CRS | KVM_SYNC_ARCH0 | KVM_SYNC_PFAULT; + if (test_kvm_facility(vcpu->kvm, 129)) + vcpu->run->kvm_valid_regs |= KVM_SYNC_VRS; if (kvm_is_ucontrol(vcpu->kvm)) return __kvm_ucontrol_vcpu_init(vcpu); @@ -1045,10 +1055,18 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) { save_fp_ctl(&vcpu->arch.host_fpregs.fpc); - save_fp_regs(vcpu->arch.host_fpregs.fprs); + if (vcpu->kvm->arch.use_vectors) + save_vx_regs((__vector128 *)&vcpu->arch.host_vregs->vrs); + else + save_fp_regs(vcpu->arch.host_fpregs.fprs); save_access_regs(vcpu->arch.host_acrs); - restore_fp_ctl(&vcpu->arch.guest_fpregs.fpc); - restore_fp_regs(vcpu->arch.guest_fpregs.fprs); + if (vcpu->kvm->arch.use_vectors) { + restore_fp_ctl(&vcpu->run->s.regs.fpc); + restore_vx_regs((__vector128 *)&vcpu->run->s.regs.vrs); + } else { + restore_fp_ctl(&vcpu->arch.guest_fpregs.fpc); + restore_fp_regs(vcpu->arch.guest_fpregs.fprs); + } restore_access_regs(vcpu->run->s.regs.acrs); gmap_enable(vcpu->arch.gmap); atomic_set_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags); @@ -1058,11 +1076,19 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) { atomic_clear_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags); gmap_disable(vcpu->arch.gmap); - save_fp_ctl(&vcpu->arch.guest_fpregs.fpc); - save_fp_regs(vcpu->arch.guest_fpregs.fprs); + if (vcpu->kvm->arch.use_vectors) { + save_fp_ctl(&vcpu->run->s.regs.fpc); + save_vx_regs((__vector128 *)&vcpu->run->s.regs.vrs); + } else { + save_fp_ctl(&vcpu->arch.guest_fpregs.fpc); + save_fp_regs(vcpu->arch.guest_fpregs.fprs); + } save_access_regs(vcpu->run->s.regs.acrs); restore_fp_ctl(&vcpu->arch.host_fpregs.fpc); - restore_fp_regs(vcpu->arch.host_fpregs.fprs); + if (vcpu->kvm->arch.use_vectors) + restore_vx_regs((__vector128 *)&vcpu->arch.host_vregs->vrs); + else + restore_fp_regs(vcpu->arch.host_fpregs.fprs); restore_access_regs(vcpu->arch.host_acrs); } @@ -1196,6 +1222,7 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, vcpu->arch.sie_block = &sie_page->sie_block; vcpu->arch.sie_block->itdba = (unsigned long) &sie_page->itdb; + vcpu->arch.host_vregs = &sie_page->vregs; vcpu->arch.sie_block->icpua = id; if (!kvm_is_ucontrol(kvm)) { diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 805570650062..82634a492fe0 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -324,7 +324,7 @@ struct kvm_run { __u64 kvm_dirty_regs; union { struct kvm_sync_regs regs; - char padding[1024]; + char padding[2048]; } s; }; @@ -760,6 +760,7 @@ struct kvm_ppc_smmu_info { #define KVM_CAP_PPC_ENABLE_HCALL 104 #define KVM_CAP_CHECK_EXTENSION_VM 105 #define KVM_CAP_S390_USER_SIGP 106 +#define KVM_CAP_S390_VECTOR_REGISTERS 107 #ifdef KVM_CAP_IRQ_ROUTING -- cgit v1.2.3-59-g8ed1b From df3a950e4e7386027fc174566aa5c24781297be8 Mon Sep 17 00:00:00 2001 From: Zubair Lutfullah Kakakhel Date: Fri, 27 Feb 2015 17:04:04 +0000 Subject: regulator: act8865: Add act8600 support This patch adds act8600 support to the act8865 driver. VBUS and USB charger supported by this chip can be added later Tested on MIPS Creator CI20 Signed-off-by: Zubair Lutfullah Kakakhel Signed-off-by: Mark Brown --- .../bindings/regulator/act8865-regulator.txt | 5 +- drivers/regulator/act8865-regulator.c | 120 ++++++++++++++++++++- include/linux/regulator/act8865.h | 14 +++ 3 files changed, 137 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/regulator/act8865-regulator.txt b/Documentation/devicetree/bindings/regulator/act8865-regulator.txt index dad6358074ac..e170df2357df 100644 --- a/Documentation/devicetree/bindings/regulator/act8865-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/act8865-regulator.txt @@ -2,7 +2,7 @@ ACT88xx regulators ------------------- Required properties: -- compatible: "active-semi,act8846" or "active-semi,act8865" +- compatible: "active-semi,act8846" or "active-semi,act8865" or "active-semi,act8600" - reg: I2C slave address Optional properties: @@ -16,6 +16,9 @@ The valid names for regulators are: REG1, REG2, REG3, REG4, REG5, REG6, REG7, REG8, REG9, REG10, REG11, REG12 - for act8865: DCDC_REG1, DCDC_REG2, DCDC_REG3, LDO_REG1, LDO_REG2, LDO_REG3, LDO_REG4. + - for act8600: + DCDC_REG1, DCDC_REG2, DCDC_REG3, SUDCDC_REG4, LDO_REG5, LDO_REG6, LDO_REG7, + LDO_REG8, LDO_REG9, LDO_REG10, Example: -------- diff --git a/drivers/regulator/act8865-regulator.c b/drivers/regulator/act8865-regulator.c index 9eec453b745d..3781f6e289d8 100644 --- a/drivers/regulator/act8865-regulator.c +++ b/drivers/regulator/act8865-regulator.c @@ -28,6 +28,35 @@ #include #include +/* + * ACT8600 Global Register Map. + */ +#define ACT8600_SYS_MODE 0x00 +#define ACT8600_SYS_CTRL 0x01 +#define ACT8600_DCDC1_VSET 0x10 +#define ACT8600_DCDC1_CTRL 0x12 +#define ACT8600_DCDC2_VSET 0x20 +#define ACT8600_DCDC2_CTRL 0x22 +#define ACT8600_DCDC3_VSET 0x30 +#define ACT8600_DCDC3_CTRL 0x32 +#define ACT8600_SUDCDC4_VSET 0x40 +#define ACT8600_SUDCDC4_CTRL 0x41 +#define ACT8600_LDO5_VSET 0x50 +#define ACT8600_LDO5_CTRL 0x51 +#define ACT8600_LDO6_VSET 0x60 +#define ACT8600_LDO6_CTRL 0x61 +#define ACT8600_LDO7_VSET 0x70 +#define ACT8600_LDO7_CTRL 0x71 +#define ACT8600_LDO8_VSET 0x80 +#define ACT8600_LDO8_CTRL 0x81 +#define ACT8600_LDO910_CTRL 0x91 +#define ACT8600_APCH0 0xA1 +#define ACT8600_APCH1 0xA8 +#define ACT8600_APCH2 0xA9 +#define ACT8600_APCH_STAT 0xAA +#define ACT8600_OTG0 0xB0 +#define ACT8600_OTG1 0xB2 + /* * ACT8846 Global Register Map. */ @@ -94,10 +123,15 @@ #define ACT8865_ENA 0x80 /* ON - [7] */ #define ACT8865_VSEL_MASK 0x3F /* VSET - [5:0] */ + +#define ACT8600_LDO10_ENA 0x40 /* ON - [6] */ +#define ACT8600_SUDCDC_VSEL_MASK 0xFF /* SUDCDC VSET - [7:0] */ + /* * ACT8865 voltage number */ #define ACT8865_VOLTAGE_NUM 64 +#define ACT8600_SUDCDC_VOLTAGE_NUM 255 struct act8865 { struct regmap *regmap; @@ -116,6 +150,13 @@ static const struct regulator_linear_range act8865_voltage_ranges[] = { REGULATOR_LINEAR_RANGE(2400000, 48, 63, 100000), }; +static const struct regulator_linear_range act8600_sudcdc_voltage_ranges[] = { + REGULATOR_LINEAR_RANGE(3000000, 0, 63, 0), + REGULATOR_LINEAR_RANGE(3000000, 64, 159, 100000), + REGULATOR_LINEAR_RANGE(12600000, 160, 191, 200000), + REGULATOR_LINEAR_RANGE(19000000, 191, 255, 400000), +}; + static struct regulator_ops act8865_ops = { .list_voltage = regulator_list_voltage_linear_range, .map_voltage = regulator_map_voltage_linear_range, @@ -126,6 +167,12 @@ static struct regulator_ops act8865_ops = { .is_enabled = regulator_is_enabled_regmap, }; +static struct regulator_ops act8865_ldo_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, +}; + #define ACT88xx_REG(_name, _family, _id, _vsel_reg) \ [_family##_ID_##_id] = { \ .name = _name, \ @@ -142,6 +189,52 @@ static struct regulator_ops act8865_ops = { .owner = THIS_MODULE, \ } +static const struct regulator_desc act8600_regulators[] = { + ACT88xx_REG("DCDC1", ACT8600, DCDC1, VSET), + ACT88xx_REG("DCDC2", ACT8600, DCDC2, VSET), + ACT88xx_REG("DCDC3", ACT8600, DCDC3, VSET), + { + .name = "SUDCDC_REG4", + .id = ACT8600_ID_SUDCDC4, + .ops = &act8865_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = ACT8600_SUDCDC_VOLTAGE_NUM, + .linear_ranges = act8600_sudcdc_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(act8600_sudcdc_voltage_ranges), + .vsel_reg = ACT8600_SUDCDC4_VSET, + .vsel_mask = ACT8600_SUDCDC_VSEL_MASK, + .enable_reg = ACT8600_SUDCDC4_CTRL, + .enable_mask = ACT8865_ENA, + .owner = THIS_MODULE, + }, + ACT88xx_REG("LDO5", ACT8600, LDO5, VSET), + ACT88xx_REG("LDO6", ACT8600, LDO6, VSET), + ACT88xx_REG("LDO7", ACT8600, LDO7, VSET), + ACT88xx_REG("LDO8", ACT8600, LDO8, VSET), + { + .name = "LDO_REG9", + .id = ACT8600_ID_LDO9, + .ops = &act8865_ldo_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = 1, + .fixed_uV = 1800000, + .enable_reg = ACT8600_LDO910_CTRL, + .enable_mask = ACT8865_ENA, + .owner = THIS_MODULE, + }, + { + .name = "LDO_REG10", + .id = ACT8600_ID_LDO10, + .ops = &act8865_ldo_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = 1, + .fixed_uV = 1200000, + .enable_reg = ACT8600_LDO910_CTRL, + .enable_mask = ACT8600_LDO10_ENA, + .owner = THIS_MODULE, + }, +}; + static const struct regulator_desc act8846_regulators[] = { ACT88xx_REG("REG1", ACT8846, REG1, VSET), ACT88xx_REG("REG2", ACT8846, REG2, VSET0), @@ -169,6 +262,7 @@ static const struct regulator_desc act8865_regulators[] = { #ifdef CONFIG_OF static const struct of_device_id act8865_dt_ids[] = { + { .compatible = "active-semi,act8600", .data = (void *)ACT8600 }, { .compatible = "active-semi,act8846", .data = (void *)ACT8846 }, { .compatible = "active-semi,act8865", .data = (void *)ACT8865 }, { } @@ -200,6 +294,19 @@ static struct of_regulator_match act8865_matches[] = { [ACT8865_ID_LDO4] = { .name = "LDO_REG4"}, }; +static struct of_regulator_match act8600_matches[] = { + [ACT8600_ID_DCDC1] = { .name = "DCDC_REG1"}, + [ACT8600_ID_DCDC2] = { .name = "DCDC_REG2"}, + [ACT8600_ID_DCDC3] = { .name = "DCDC_REG3"}, + [ACT8600_ID_SUDCDC4] = { .name = "SUDCDC_REG4"}, + [ACT8600_ID_LDO5] = { .name = "LDO_REG5"}, + [ACT8600_ID_LDO6] = { .name = "LDO_REG6"}, + [ACT8600_ID_LDO7] = { .name = "LDO_REG7"}, + [ACT8600_ID_LDO8] = { .name = "LDO_REG8"}, + [ACT8600_ID_LDO9] = { .name = "LDO_REG9"}, + [ACT8600_ID_LDO10] = { .name = "LDO_REG10"}, +}; + static int act8865_pdata_from_dt(struct device *dev, struct device_node **of_node, struct act8865_platform_data *pdata, @@ -217,6 +324,10 @@ static int act8865_pdata_from_dt(struct device *dev, } switch (type) { + case ACT8600: + matches = act8600_matches; + num_matches = ARRAY_SIZE(act8600_matches); + break; case ACT8846: matches = act8846_matches; num_matches = ARRAY_SIZE(act8846_matches); @@ -317,6 +428,12 @@ static int act8865_pmic_probe(struct i2c_client *client, } switch (type) { + case ACT8600: + regulators = act8600_regulators; + num_regulators = ARRAY_SIZE(act8600_regulators); + off_reg = -1; + off_mask = -1; + break; case ACT8846: regulators = act8846_regulators; num_regulators = ARRAY_SIZE(act8846_regulators); @@ -366,7 +483,7 @@ static int act8865_pmic_probe(struct i2c_client *client, } if (of_device_is_system_power_controller(dev->of_node)) { - if (!pm_power_off) { + if (!pm_power_off && (off_reg > 0)) { act8865_i2c_client = client; act8865->off_reg = off_reg; act8865->off_mask = off_mask; @@ -402,6 +519,7 @@ static int act8865_pmic_probe(struct i2c_client *client, } static const struct i2c_device_id act8865_ids[] = { + { .name = "act8600", .driver_data = ACT8600 }, { .name = "act8846", .driver_data = ACT8846 }, { .name = "act8865", .driver_data = ACT8865 }, { }, diff --git a/include/linux/regulator/act8865.h b/include/linux/regulator/act8865.h index b6c4909b33af..15fa8f2d35c9 100644 --- a/include/linux/regulator/act8865.h +++ b/include/linux/regulator/act8865.h @@ -18,6 +18,19 @@ #include +enum { + ACT8600_ID_DCDC1, + ACT8600_ID_DCDC2, + ACT8600_ID_DCDC3, + ACT8600_ID_SUDCDC4, + ACT8600_ID_LDO5, + ACT8600_ID_LDO6, + ACT8600_ID_LDO7, + ACT8600_ID_LDO8, + ACT8600_ID_LDO9, + ACT8600_ID_LDO10, +}; + enum { ACT8865_ID_DCDC1, ACT8865_ID_DCDC2, @@ -46,6 +59,7 @@ enum { }; enum { + ACT8600, ACT8865, ACT8846, }; -- cgit v1.2.3-59-g8ed1b From fab42760843734a82b6b2d1241ca44f375a686eb Mon Sep 17 00:00:00 2001 From: Fan Du Date: Fri, 6 Mar 2015 11:18:25 +0800 Subject: ipv4: Documenting two sysctls for tcp PMTU probe Namely tcp_probe_interval to control how often to restart a probe. And tcp_probe_threshold to control when stop the probing in respect to the width of search range in bytes Signed-off-by: Fan Du Signed-off-by: David S. Miller --- Documentation/networking/ip-sysctl.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'Documentation') diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index 1b8c964b0d17..4412f695a62f 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -388,6 +388,16 @@ tcp_mtu_probing - INTEGER 1 - Disabled by default, enabled when an ICMP black hole detected 2 - Always enabled, use initial MSS of tcp_base_mss. +tcp_probe_interval - INTEGER + Controls how often to start TCP Packetization-Layer Path MTU + Discovery reprobe. The default is reprobing every 10 minutes as + per RFC4821. + +tcp_probe_threshold - INTEGER + Controls when TCP Packetization-Layer Path MTU Discovery probing + will stop in respect to the width of search range in bytes. Default + is 8 bytes. + tcp_no_metrics_save - BOOLEAN By default, TCP saves various connection metrics in the route cache when the connection closes, so that connections established in the -- cgit v1.2.3-59-g8ed1b From 771d8f1b178e7e09fcc641fccd48852958dbc329 Mon Sep 17 00:00:00 2001 From: Aleksei Mamlin Date: Fri, 6 Mar 2015 16:43:38 -0800 Subject: Input: goodix - add device tree support This change adds device tree support and binding information for Goodix GT9xx series touchscreen controller. It also adds support for 5-finger chips, like GT911 and GT912, which can be found on ARM tablets, such as Wexler TAB7200 and MSI Primo73. Datasheets can be found here: https://drive.google.com/folderview?id=0BxCVOQS3ZymGfmJyY2RKbE5XbVlKNlktVTlwV0lxNEdxd2dzeWZER094cmJPVnMxN1F0Yzg&usp=sharing Signed-off-by: Aleksei Mamlin Reviewed-by: Bastien Nocera Signed-off-by: Dmitry Torokhov --- .../bindings/input/touchscreen/goodix.txt | 29 ++++++++++++++++++++++ .../devicetree/bindings/vendor-prefixes.txt | 1 + drivers/input/touchscreen/Kconfig | 5 ++-- drivers/input/touchscreen/goodix.c | 21 +++++++++++++++- 4 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 Documentation/devicetree/bindings/input/touchscreen/goodix.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/input/touchscreen/goodix.txt b/Documentation/devicetree/bindings/input/touchscreen/goodix.txt new file mode 100644 index 000000000000..8ba98eec765b --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/goodix.txt @@ -0,0 +1,29 @@ +Device tree bindings for Goodix GT9xx series touchscreen controller + +Required properties: + + - compatible : Should be "goodix,gt911" + or "goodix,gt9110" + or "goodix,gt912" + or "goodix,gt927" + or "goodix,gt9271" + or "goodix,gt928" + or "goodix,gt967" + - reg : I2C address of the chip. Should be 0x5d or 0x14 + - interrupt-parent : Interrupt controller to which the chip is connected + - interrupts : Interrupt to which the chip is connected + +Example: + + i2c@00000000 { + /* ... */ + + gt928@5d { + compatible = "goodix,gt928"; + reg = <0x5d>; + interrupt-parent = <&gpio>; + interrupts = <0 0>; + }; + + /* ... */ + }; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 96a17541391e..943ed01f9fe5 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -65,6 +65,7 @@ gef GE Fanuc Intelligent Platforms Embedded Systems, Inc. geniatech Geniatech, Inc. globalscale Globalscale Technologies, Inc. gmt Global Mixed-mode Technology, Inc. +goodix Shenzhen Huiding Technology Co., Ltd. google Google, Inc. gumstix Gumstix, Inc. gw Gateworks Corporation diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 58917525126e..2adf7244b025 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -297,11 +297,12 @@ config TOUCHSCREEN_FUJITSU config TOUCHSCREEN_GOODIX tristate "Goodix I2C touchscreen" - depends on I2C && ACPI + depends on I2C help Say Y here if you have the Goodix touchscreen (such as one installed in Onda v975w tablets) connected to your - system. + system. It also supports 5-finger chip models, which can be + found on ARM tablets, like Wexler TAB7200 and MSI Primo73. If unsure, say N. diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c index 3ab7232ac1af..3af16984d57c 100644 --- a/drivers/input/touchscreen/goodix.c +++ b/drivers/input/touchscreen/goodix.c @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include struct goodix_ts_data { @@ -375,11 +377,27 @@ static const struct i2c_device_id goodix_ts_id[] = { { } }; +#ifdef CONFIG_ACPI static const struct acpi_device_id goodix_acpi_match[] = { { "GDIX1001", 0 }, { } }; MODULE_DEVICE_TABLE(acpi, goodix_acpi_match); +#endif + +#ifdef CONFIG_OF +static const struct of_device_id goodix_of_match[] = { + { .compatible = "goodix,gt911" }, + { .compatible = "goodix,gt9110" }, + { .compatible = "goodix,gt912" }, + { .compatible = "goodix,gt927" }, + { .compatible = "goodix,gt9271" }, + { .compatible = "goodix,gt928" }, + { .compatible = "goodix,gt967" }, + { } +}; +MODULE_DEVICE_TABLE(of, goodix_of_match); +#endif static struct i2c_driver goodix_ts_driver = { .probe = goodix_ts_probe, @@ -387,7 +405,8 @@ static struct i2c_driver goodix_ts_driver = { .driver = { .name = "Goodix-TS", .owner = THIS_MODULE, - .acpi_match_table = goodix_acpi_match, + .acpi_match_table = ACPI_PTR(goodix_acpi_match), + .of_match_table = of_match_ptr(goodix_of_match), }, }; module_i2c_driver(goodix_ts_driver); -- cgit v1.2.3-59-g8ed1b From 902cb3afab8d4c924376de51ec5c02d171992914 Mon Sep 17 00:00:00 2001 From: Sébastien Szymanski Date: Fri, 6 Mar 2015 16:49:38 -0800 Subject: Input: add support for Semtech SX8654 I2C touchscreen controller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sébastien Szymanski Signed-off-by: Dmitry Torokhov --- .../bindings/input/touchscreen/sx8654.txt | 16 ++ drivers/input/touchscreen/Kconfig | 11 + drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/sx8654.c | 286 +++++++++++++++++++++ 4 files changed, 314 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/touchscreen/sx8654.txt create mode 100644 drivers/input/touchscreen/sx8654.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/input/touchscreen/sx8654.txt b/Documentation/devicetree/bindings/input/touchscreen/sx8654.txt new file mode 100644 index 000000000000..5aaa6b3aa90c --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/sx8654.txt @@ -0,0 +1,16 @@ +* Semtech SX8654 I2C Touchscreen Controller + +Required properties: +- compatible: must be "semtech,sx8654" +- reg: i2c slave address +- interrupt-parent: the phandle for the interrupt controller +- interrupts: touch controller interrupt + +Example: + + sx8654@48 { + compatible = "semtech,sx8654"; + reg = <0x48>; + interrupt-parent = <&gpio6>; + interrupts = <3 IRQ_TYPE_EDGE_FALLING>; + }; diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 2adf7244b025..2310d863a6f1 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -962,6 +962,17 @@ config TOUCHSCREEN_SUR40 To compile this driver as a module, choose M here: the module will be called sur40. +config TOUCHSCREEN_SX8654 + tristate "Semtech SX8654 touchscreen" + depends on I2C + help + Say Y here if you have a Semtech SX8654 touchscreen controller. + + If unsure, say N + + To compile this driver as a module, choose M here: the + module will be called sx8654. + config TOUCHSCREEN_TPS6507X tristate "TPS6507x based touchscreens" depends on I2C diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 0242fea2102a..a06a752966fe 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -79,5 +79,6 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_ATMEL) += atmel-wm97xx.o obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o +obj-$(CONFIG_TOUCHSCREEN_SX8654) += sx8654.o obj-$(CONFIG_TOUCHSCREEN_TPS6507X) += tps6507x-ts.o obj-$(CONFIG_TOUCHSCREEN_ZFORCE) += zforce_ts.o diff --git a/drivers/input/touchscreen/sx8654.c b/drivers/input/touchscreen/sx8654.c new file mode 100644 index 000000000000..8e531ac0ecde --- /dev/null +++ b/drivers/input/touchscreen/sx8654.c @@ -0,0 +1,286 @@ +/* + * Driver for Semtech SX8654 I2C touchscreen controller. + * + * Copyright (c) 2015 Armadeus Systems + * Sébastien Szymanski + * + * Using code from: + * - sx865x.c + * Copyright (c) 2013 U-MoBo Srl + * Pierluigi Passaro + * - sx8650.c + * Copyright (c) 2009 Wayne Roberts + * - tsc2007.c + * Copyright (c) 2008 Kwangwoo Lee + * - ads7846.c + * Copyright (c) 2005 David Brownell + * Copyright (c) 2006 Nokia Corporation + * - corgi_ts.c + * Copyright (C) 2004-2005 Richard Purdie + * - omap_ts.[hc], ads7846.h, ts_osk.c + * Copyright (C) 2002 MontaVista Software + * Copyright (C) 2004 Texas Instruments + * Copyright (C) 2005 Dirk Behme + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include + +/* register addresses */ +#define I2C_REG_TOUCH0 0x00 +#define I2C_REG_TOUCH1 0x01 +#define I2C_REG_CHANMASK 0x04 +#define I2C_REG_IRQMASK 0x22 +#define I2C_REG_IRQSRC 0x23 +#define I2C_REG_SOFTRESET 0x3f + +/* commands */ +#define CMD_READ_REGISTER 0x40 +#define CMD_MANUAL 0xc0 +#define CMD_PENTRG 0xe0 + +/* value for I2C_REG_SOFTRESET */ +#define SOFTRESET_VALUE 0xde + +/* bits for I2C_REG_IRQSRC */ +#define IRQ_PENTOUCH_TOUCHCONVDONE 0x08 +#define IRQ_PENRELEASE 0x04 + +/* bits for RegTouch1 */ +#define CONDIRQ 0x20 +#define FILT_7SA 0x03 + +/* bits for I2C_REG_CHANMASK */ +#define CONV_X 0x80 +#define CONV_Y 0x40 + +/* coordinates rate: higher nibble of CTRL0 register */ +#define RATE_MANUAL 0x00 +#define RATE_5000CPS 0xf0 + +/* power delay: lower nibble of CTRL0 register */ +#define POWDLY_1_1MS 0x0b + +#define MAX_12BIT ((1 << 12) - 1) + +struct sx8654 { + struct input_dev *input; + struct i2c_client *client; +}; + +static irqreturn_t sx8654_irq(int irq, void *handle) +{ + struct sx8654 *sx8654 = handle; + u8 irqsrc; + u8 data[4]; + unsigned int x, y; + int retval; + + irqsrc = i2c_smbus_read_byte_data(sx8654->client, + CMD_READ_REGISTER | I2C_REG_IRQSRC); + dev_dbg(&sx8654->client->dev, "irqsrc = 0x%x", irqsrc); + + if (irqsrc < 0) + goto out; + + if (irqsrc & IRQ_PENRELEASE) { + dev_dbg(&sx8654->client->dev, "pen release interrupt"); + + input_report_key(sx8654->input, BTN_TOUCH, 0); + input_sync(sx8654->input); + } + + if (irqsrc & IRQ_PENTOUCH_TOUCHCONVDONE) { + dev_dbg(&sx8654->client->dev, "pen touch interrupt"); + + retval = i2c_master_recv(sx8654->client, data, sizeof(data)); + if (retval != sizeof(data)) + goto out; + + /* invalid data */ + if (unlikely(data[0] & 0x80 || data[2] & 0x80)) + goto out; + + x = ((data[0] & 0xf) << 8) | (data[1]); + y = ((data[2] & 0xf) << 8) | (data[3]); + + input_report_abs(sx8654->input, ABS_X, x); + input_report_abs(sx8654->input, ABS_Y, y); + input_report_key(sx8654->input, BTN_TOUCH, 1); + input_sync(sx8654->input); + + dev_dbg(&sx8654->client->dev, "point(%4d,%4d)\n", x, y); + } + +out: + return IRQ_HANDLED; +} + +static int sx8654_open(struct input_dev *dev) +{ + struct sx8654 *sx8654 = input_get_drvdata(dev); + struct i2c_client *client = sx8654->client; + int error; + + /* enable pen trigger mode */ + error = i2c_smbus_write_byte_data(client, I2C_REG_TOUCH0, + RATE_5000CPS | POWDLY_1_1MS); + if (error) { + dev_err(&client->dev, "writing to I2C_REG_TOUCH0 failed"); + return error; + } + + error = i2c_smbus_write_byte(client, CMD_PENTRG); + if (error) { + dev_err(&client->dev, "writing command CMD_PENTRG failed"); + return error; + } + + enable_irq(client->irq); + + return 0; +} + +static void sx8654_close(struct input_dev *dev) +{ + struct sx8654 *sx8654 = input_get_drvdata(dev); + struct i2c_client *client = sx8654->client; + int error; + + disable_irq(client->irq); + + /* enable manual mode mode */ + error = i2c_smbus_write_byte(client, CMD_MANUAL); + if (error) { + dev_err(&client->dev, "writing command CMD_MANUAL failed"); + return; + } + + error = i2c_smbus_write_byte_data(client, I2C_REG_TOUCH0, 0); + if (error) { + dev_err(&client->dev, "writing to I2C_REG_TOUCH0 failed"); + return; + } +} + +static int sx8654_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct sx8654 *sx8654; + struct input_dev *input; + int error; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_READ_WORD_DATA)) + return -ENXIO; + + sx8654 = devm_kzalloc(&client->dev, sizeof(*sx8654), GFP_KERNEL); + if (!sx8654) + return -ENOMEM; + + input = devm_input_allocate_device(&client->dev); + if (!sx8654) + return -ENOMEM; + + input->name = "SX8654 I2C Touchscreen"; + input->id.bustype = BUS_I2C; + input->dev.parent = &client->dev; + input->open = sx8654_open; + input->close = sx8654_close; + + __set_bit(INPUT_PROP_DIRECT, input->propbit); + input_set_capability(input, EV_KEY, BTN_TOUCH); + input_set_abs_params(input, ABS_X, 0, MAX_12BIT, 0, 0); + input_set_abs_params(input, ABS_Y, 0, MAX_12BIT, 0, 0); + + sx8654->client = client; + sx8654->input = input; + + input_set_drvdata(sx8654->input, sx8654); + + error = i2c_smbus_write_byte_data(client, I2C_REG_SOFTRESET, + SOFTRESET_VALUE); + if (error) { + dev_err(&client->dev, "writing softreset value failed"); + return error; + } + + error = i2c_smbus_write_byte_data(client, I2C_REG_CHANMASK, + CONV_X | CONV_Y); + if (error) { + dev_err(&client->dev, "writing to I2C_REG_CHANMASK failed"); + return error; + } + + error = i2c_smbus_write_byte_data(client, I2C_REG_IRQMASK, + IRQ_PENTOUCH_TOUCHCONVDONE | + IRQ_PENRELEASE); + if (error) { + dev_err(&client->dev, "writing to I2C_REG_IRQMASK failed"); + return error; + } + + error = i2c_smbus_write_byte_data(client, I2C_REG_TOUCH1, + CONDIRQ | FILT_7SA); + if (error) { + dev_err(&client->dev, "writing to I2C_REG_TOUCH1 failed"); + return error; + } + + error = devm_request_threaded_irq(&client->dev, client->irq, + NULL, sx8654_irq, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + client->name, sx8654); + if (error) { + dev_err(&client->dev, + "Failed to enable IRQ %d, error: %d\n", + client->irq, error); + return error; + } + + /* Disable the IRQ, we'll enable it in sx8654_open() */ + disable_irq(client->irq); + + error = input_register_device(sx8654->input); + if (error) + return error; + + i2c_set_clientdata(client, sx8654); + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id sx8654_of_match[] = { + { .compatible = "semtech,sx8654", }, + { }, +}; +MODULE_DEVICE_TABLE(of, sx8654_of_match); +#endif + +static const struct i2c_device_id sx8654_id_table[] = { + { "semtech_sx8654", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, sx8654_id_table); + +static struct i2c_driver sx8654_driver = { + .driver = { + .name = "sx8654", + .of_match_table = of_match_ptr(sx8654_of_match), + }, + .id_table = sx8654_id_table, + .probe = sx8654_probe, +}; +module_i2c_driver(sx8654_driver); + +MODULE_AUTHOR("Sébastien Szymanski "); +MODULE_DESCRIPTION("Semtech SX8654 I2C Touchscreen Driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-59-g8ed1b From 612762e82ae6058d69b4ce734598491bf030afe7 Mon Sep 17 00:00:00 2001 From: Andy Gross Date: Wed, 4 Mar 2015 12:02:05 +0200 Subject: spi: qup: Add DMA capabilities This patch adds DMA capabilities to the spi-qup driver. If DMA channels are present, the QUP will use DMA instead of block mode for transfers to/from SPI peripherals for transactions larger than the length of a block. Signed-off-by: Andy Gross Signed-off-by: Stanimir Varbanov Reviewed-by: Ivan T. Ivanov --- .../devicetree/bindings/spi/qcom,spi-qup.txt | 8 + drivers/spi/spi-qup.c | 336 +++++++++++++++++++-- 2 files changed, 312 insertions(+), 32 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/spi/qcom,spi-qup.txt b/Documentation/devicetree/bindings/spi/qcom,spi-qup.txt index e2c88df2cc15..5c090771c016 100644 --- a/Documentation/devicetree/bindings/spi/qcom,spi-qup.txt +++ b/Documentation/devicetree/bindings/spi/qcom,spi-qup.txt @@ -33,6 +33,11 @@ Optional properties: nodes. If unspecified, a single SPI device without a chip select can be used. +- dmas: Two DMA channel specifiers following the convention outlined + in bindings/dma/dma.txt +- dma-names: Names for the dma channels, if present. There must be at + least one channel named "tx" for transmit and named "rx" for + receive. SPI slave nodes must be children of the SPI master node and can contain properties described in Documentation/devicetree/bindings/spi/spi-bus.txt @@ -51,6 +56,9 @@ Example: clocks = <&gcc GCC_BLSP2_QUP2_SPI_APPS_CLK>, <&gcc GCC_BLSP2_AHB_CLK>; clock-names = "core", "iface"; + dmas = <&blsp1_bam 13>, <&blsp1_bam 12>; + dma-names = "rx", "tx"; + pinctrl-names = "default"; pinctrl-0 = <&spi8_default>; diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c index ff9cdbdb6672..4b5fc4d67b6e 100644 --- a/drivers/spi/spi-qup.c +++ b/drivers/spi/spi-qup.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include #define QUP_CONFIG 0x0000 #define QUP_STATE 0x0004 @@ -116,6 +118,8 @@ #define SPI_NUM_CHIPSELECTS 4 +#define SPI_MAX_DMA_XFER (SZ_64K - 64) + /* high speed mode is when bus rate is greater then 26MHz */ #define SPI_HS_MIN_RATE 26000000 #define SPI_MAX_RATE 50000000 @@ -140,9 +144,14 @@ struct spi_qup { struct completion done; int error; int w_size; /* bytes per SPI word */ + int n_words; int tx_bytes; int rx_bytes; int qup_v1; + + int use_dma; + struct dma_slave_config rx_conf; + struct dma_slave_config tx_conf; }; @@ -198,7 +207,6 @@ static int spi_qup_set_state(struct spi_qup *controller, u32 state) return 0; } - static void spi_qup_fifo_read(struct spi_qup *controller, struct spi_transfer *xfer) { @@ -266,6 +274,107 @@ static void spi_qup_fifo_write(struct spi_qup *controller, } } +static void spi_qup_dma_done(void *data) +{ + struct spi_qup *qup = data; + + complete(&qup->done); +} + +static int spi_qup_prep_sg(struct spi_master *master, struct spi_transfer *xfer, + enum dma_transfer_direction dir, + dma_async_tx_callback callback) +{ + struct spi_qup *qup = spi_master_get_devdata(master); + unsigned long flags = DMA_PREP_INTERRUPT | DMA_PREP_FENCE; + struct dma_async_tx_descriptor *desc; + struct scatterlist *sgl; + struct dma_chan *chan; + dma_cookie_t cookie; + unsigned int nents; + + if (dir == DMA_MEM_TO_DEV) { + chan = master->dma_tx; + nents = xfer->tx_sg.nents; + sgl = xfer->tx_sg.sgl; + } else { + chan = master->dma_rx; + nents = xfer->rx_sg.nents; + sgl = xfer->rx_sg.sgl; + } + + desc = dmaengine_prep_slave_sg(chan, sgl, nents, dir, flags); + if (!desc) + return -EINVAL; + + desc->callback = callback; + desc->callback_param = qup; + + cookie = dmaengine_submit(desc); + + return dma_submit_error(cookie); +} + +static void spi_qup_dma_terminate(struct spi_master *master, + struct spi_transfer *xfer) +{ + if (xfer->tx_buf) + dmaengine_terminate_all(master->dma_tx); + if (xfer->rx_buf) + dmaengine_terminate_all(master->dma_rx); +} + +static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer) +{ + dma_async_tx_callback rx_done = NULL, tx_done = NULL; + int ret; + + if (xfer->rx_buf) + rx_done = spi_qup_dma_done; + else if (xfer->tx_buf) + tx_done = spi_qup_dma_done; + + if (xfer->rx_buf) { + ret = spi_qup_prep_sg(master, xfer, DMA_DEV_TO_MEM, rx_done); + if (ret) + return ret; + + dma_async_issue_pending(master->dma_rx); + } + + if (xfer->tx_buf) { + ret = spi_qup_prep_sg(master, xfer, DMA_MEM_TO_DEV, tx_done); + if (ret) + return ret; + + dma_async_issue_pending(master->dma_tx); + } + + return 0; +} + +static int spi_qup_do_pio(struct spi_master *master, struct spi_transfer *xfer) +{ + struct spi_qup *qup = spi_master_get_devdata(master); + int ret; + + ret = spi_qup_set_state(qup, QUP_STATE_RUN); + if (ret) { + dev_warn(qup->dev, "cannot set RUN state\n"); + return ret; + } + + ret = spi_qup_set_state(qup, QUP_STATE_PAUSE); + if (ret) { + dev_warn(qup->dev, "cannot set PAUSE state\n"); + return ret; + } + + spi_qup_fifo_write(qup, xfer); + + return 0; +} + static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id) { struct spi_qup *controller = dev_id; @@ -315,11 +424,13 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id) error = -EIO; } - if (opflags & QUP_OP_IN_SERVICE_FLAG) - spi_qup_fifo_read(controller, xfer); + if (!controller->use_dma) { + if (opflags & QUP_OP_IN_SERVICE_FLAG) + spi_qup_fifo_read(controller, xfer); - if (opflags & QUP_OP_OUT_SERVICE_FLAG) - spi_qup_fifo_write(controller, xfer); + if (opflags & QUP_OP_OUT_SERVICE_FLAG) + spi_qup_fifo_write(controller, xfer); + } spin_lock_irqsave(&controller->lock, flags); controller->error = error; @@ -332,13 +443,35 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id) return IRQ_HANDLED; } +static u32 +spi_qup_get_mode(struct spi_master *master, struct spi_transfer *xfer) +{ + struct spi_qup *qup = spi_master_get_devdata(master); + u32 mode; + + qup->w_size = 4; + + if (xfer->bits_per_word <= 8) + qup->w_size = 1; + else if (xfer->bits_per_word <= 16) + qup->w_size = 2; + + qup->n_words = xfer->len / qup->w_size; + + if (qup->n_words <= (qup->in_fifo_sz / sizeof(u32))) + mode = QUP_IO_M_MODE_FIFO; + else + mode = QUP_IO_M_MODE_BLOCK; + + return mode; +} /* set clock freq ... bits per word */ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer) { struct spi_qup *controller = spi_master_get_devdata(spi->master); u32 config, iomode, mode, control; - int ret, n_words, w_size; + int ret, n_words; if (spi->mode & SPI_LOOP && xfer->len > controller->in_fifo_sz) { dev_err(controller->dev, "too big size for loopback %d > %d\n", @@ -358,35 +491,54 @@ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer) return -EIO; } - w_size = 4; - if (xfer->bits_per_word <= 8) - w_size = 1; - else if (xfer->bits_per_word <= 16) - w_size = 2; - - n_words = xfer->len / w_size; - controller->w_size = w_size; + mode = spi_qup_get_mode(spi->master, xfer); + n_words = controller->n_words; - if (n_words <= (controller->in_fifo_sz / sizeof(u32))) { - mode = QUP_IO_M_MODE_FIFO; + if (mode == QUP_IO_M_MODE_FIFO) { writel_relaxed(n_words, controller->base + QUP_MX_READ_CNT); writel_relaxed(n_words, controller->base + QUP_MX_WRITE_CNT); /* must be zero for FIFO */ writel_relaxed(0, controller->base + QUP_MX_INPUT_CNT); writel_relaxed(0, controller->base + QUP_MX_OUTPUT_CNT); - } else { - mode = QUP_IO_M_MODE_BLOCK; + } else if (!controller->use_dma) { writel_relaxed(n_words, controller->base + QUP_MX_INPUT_CNT); writel_relaxed(n_words, controller->base + QUP_MX_OUTPUT_CNT); /* must be zero for BLOCK and BAM */ writel_relaxed(0, controller->base + QUP_MX_READ_CNT); writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT); + } else { + mode = QUP_IO_M_MODE_BAM; + writel_relaxed(0, controller->base + QUP_MX_READ_CNT); + writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT); + + if (!controller->qup_v1) { + void __iomem *input_cnt; + + input_cnt = controller->base + QUP_MX_INPUT_CNT; + /* + * for DMA transfers, both QUP_MX_INPUT_CNT and + * QUP_MX_OUTPUT_CNT must be zero to all cases but one. + * That case is a non-balanced transfer when there is + * only a rx_buf. + */ + if (xfer->tx_buf) + writel_relaxed(0, input_cnt); + else + writel_relaxed(n_words, input_cnt); + + writel_relaxed(0, controller->base + QUP_MX_OUTPUT_CNT); + } } iomode = readl_relaxed(controller->base + QUP_IO_M_MODES); /* Set input and output transfer mode */ iomode &= ~(QUP_IO_M_INPUT_MODE_MASK | QUP_IO_M_OUTPUT_MODE_MASK); - iomode &= ~(QUP_IO_M_PACK_EN | QUP_IO_M_UNPACK_EN); + + if (!controller->use_dma) + iomode &= ~(QUP_IO_M_PACK_EN | QUP_IO_M_UNPACK_EN); + else + iomode |= QUP_IO_M_PACK_EN | QUP_IO_M_UNPACK_EN; + iomode |= (mode << QUP_IO_M_OUTPUT_MODE_MASK_SHIFT); iomode |= (mode << QUP_IO_M_INPUT_MODE_MASK_SHIFT); @@ -428,11 +580,31 @@ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer) config &= ~(QUP_CONFIG_NO_INPUT | QUP_CONFIG_NO_OUTPUT | QUP_CONFIG_N); config |= xfer->bits_per_word - 1; config |= QUP_CONFIG_SPI_MODE; + + if (controller->use_dma) { + if (!xfer->tx_buf) + config |= QUP_CONFIG_NO_OUTPUT; + if (!xfer->rx_buf) + config |= QUP_CONFIG_NO_INPUT; + } + writel_relaxed(config, controller->base + QUP_CONFIG); /* only write to OPERATIONAL_MASK when register is present */ - if (!controller->qup_v1) - writel_relaxed(0, controller->base + QUP_OPERATIONAL_MASK); + if (!controller->qup_v1) { + u32 mask = 0; + + /* + * mask INPUT and OUTPUT service flags to prevent IRQs on FIFO + * status change in BAM mode + */ + + if (mode == QUP_IO_M_MODE_BAM) + mask = QUP_OP_IN_SERVICE_FLAG | QUP_OP_OUT_SERVICE_FLAG; + + writel_relaxed(mask, controller->base + QUP_OPERATIONAL_MASK); + } + return 0; } @@ -461,17 +633,13 @@ static int spi_qup_transfer_one(struct spi_master *master, controller->tx_bytes = 0; spin_unlock_irqrestore(&controller->lock, flags); - if (spi_qup_set_state(controller, QUP_STATE_RUN)) { - dev_warn(controller->dev, "cannot set RUN state\n"); - goto exit; - } + if (controller->use_dma) + ret = spi_qup_do_dma(master, xfer); + else + ret = spi_qup_do_pio(master, xfer); - if (spi_qup_set_state(controller, QUP_STATE_PAUSE)) { - dev_warn(controller->dev, "cannot set PAUSE state\n"); + if (ret) goto exit; - } - - spi_qup_fifo_write(controller, xfer); if (spi_qup_set_state(controller, QUP_STATE_RUN)) { dev_warn(controller->dev, "cannot set EXECUTE state\n"); @@ -480,6 +648,7 @@ static int spi_qup_transfer_one(struct spi_master *master, if (!wait_for_completion_timeout(&controller->done, timeout)) ret = -ETIMEDOUT; + exit: spi_qup_set_state(controller, QUP_STATE_RESET); spin_lock_irqsave(&controller->lock, flags); @@ -487,6 +656,97 @@ exit: if (!ret) ret = controller->error; spin_unlock_irqrestore(&controller->lock, flags); + + if (ret && controller->use_dma) + spi_qup_dma_terminate(master, xfer); + + return ret; +} + +static bool spi_qup_can_dma(struct spi_master *master, struct spi_device *spi, + struct spi_transfer *xfer) +{ + struct spi_qup *qup = spi_master_get_devdata(master); + size_t dma_align = dma_get_cache_alignment(); + u32 mode; + + qup->use_dma = 0; + + if (xfer->rx_buf && (xfer->len % qup->in_blk_sz || + IS_ERR_OR_NULL(master->dma_rx) || + !IS_ALIGNED((size_t)xfer->rx_buf, dma_align))) + return false; + + if (xfer->tx_buf && (xfer->len % qup->out_blk_sz || + IS_ERR_OR_NULL(master->dma_tx) || + !IS_ALIGNED((size_t)xfer->tx_buf, dma_align))) + return false; + + mode = spi_qup_get_mode(master, xfer); + if (mode == QUP_IO_M_MODE_FIFO) + return false; + + qup->use_dma = 1; + + return true; +} + +static void spi_qup_release_dma(struct spi_master *master) +{ + if (!IS_ERR_OR_NULL(master->dma_rx)) + dma_release_channel(master->dma_rx); + if (!IS_ERR_OR_NULL(master->dma_tx)) + dma_release_channel(master->dma_tx); +} + +static int spi_qup_init_dma(struct spi_master *master, resource_size_t base) +{ + struct spi_qup *spi = spi_master_get_devdata(master); + struct dma_slave_config *rx_conf = &spi->rx_conf, + *tx_conf = &spi->tx_conf; + struct device *dev = spi->dev; + int ret; + + /* allocate dma resources, if available */ + master->dma_rx = dma_request_slave_channel_reason(dev, "rx"); + if (IS_ERR(master->dma_rx)) + return PTR_ERR(master->dma_rx); + + master->dma_tx = dma_request_slave_channel_reason(dev, "tx"); + if (IS_ERR(master->dma_tx)) { + ret = PTR_ERR(master->dma_tx); + goto err_tx; + } + + /* set DMA parameters */ + rx_conf->direction = DMA_DEV_TO_MEM; + rx_conf->device_fc = 1; + rx_conf->src_addr = base + QUP_INPUT_FIFO; + rx_conf->src_maxburst = spi->in_blk_sz; + + tx_conf->direction = DMA_MEM_TO_DEV; + tx_conf->device_fc = 1; + tx_conf->dst_addr = base + QUP_OUTPUT_FIFO; + tx_conf->dst_maxburst = spi->out_blk_sz; + + ret = dmaengine_slave_config(master->dma_rx, rx_conf); + if (ret) { + dev_err(dev, "failed to configure RX channel\n"); + goto err; + } + + ret = dmaengine_slave_config(master->dma_tx, tx_conf); + if (ret) { + dev_err(dev, "failed to configure TX channel\n"); + goto err; + } + + return 0; + +err: + dma_release_channel(master->dma_tx); +err_tx: + dma_release_channel(master->dma_rx); return ret; } @@ -562,6 +822,8 @@ static int spi_qup_probe(struct platform_device *pdev) master->transfer_one = spi_qup_transfer_one; master->dev.of_node = pdev->dev.of_node; master->auto_runtime_pm = true; + master->dma_alignment = dma_get_cache_alignment(); + master->max_dma_len = SPI_MAX_DMA_XFER; platform_set_drvdata(pdev, master); @@ -573,6 +835,12 @@ static int spi_qup_probe(struct platform_device *pdev) controller->cclk = cclk; controller->irq = irq; + ret = spi_qup_init_dma(master, res->start); + if (ret == -EPROBE_DEFER) + goto error; + else if (!ret) + master->can_dma = spi_qup_can_dma; + /* set v1 flag if device is version 1 */ if (of_device_is_compatible(dev->of_node, "qcom,spi-qup-v1.1.1")) controller->qup_v1 = 1; @@ -609,7 +877,7 @@ static int spi_qup_probe(struct platform_device *pdev) ret = spi_qup_set_state(controller, QUP_STATE_RESET); if (ret) { dev_err(dev, "cannot set RESET state\n"); - goto error; + goto error_dma; } writel_relaxed(0, base + QUP_OPERATIONAL); @@ -633,7 +901,7 @@ static int spi_qup_probe(struct platform_device *pdev) ret = devm_request_irq(dev, irq, spi_qup_qup_irq, IRQF_TRIGGER_HIGH, pdev->name, controller); if (ret) - goto error; + goto error_dma; pm_runtime_set_autosuspend_delay(dev, MSEC_PER_SEC); pm_runtime_use_autosuspend(dev); @@ -648,6 +916,8 @@ static int spi_qup_probe(struct platform_device *pdev) disable_pm: pm_runtime_disable(&pdev->dev); +error_dma: + spi_qup_release_dma(master); error: clk_disable_unprepare(cclk); clk_disable_unprepare(iclk); @@ -739,6 +1009,8 @@ static int spi_qup_remove(struct platform_device *pdev) if (ret) return ret; + spi_qup_release_dma(master); + clk_disable_unprepare(controller->cclk); clk_disable_unprepare(controller->iclk); -- cgit v1.2.3-59-g8ed1b From 5cf4f68672856dcbca883b460aee4ee5bfbeafb0 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 20 Feb 2015 10:31:55 +0000 Subject: ASoC: rsnd: add sample code of rcar_sound,src irq cfcefe01265cbaf5ca7209226d043b07bfa8b587 (ASoC: rsnd: add recovery support for under/over flow error on SRC) added SRC recovery support which needs IRQ. This patch adds SRC irq sample code on DT bingdings text Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/renesas,rsnd.txt | 40 ++++++++++++++++------ 1 file changed, 30 insertions(+), 10 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt index 2dd690bc19cc..87e0fc2ce399 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt @@ -53,16 +53,36 @@ rcar_sound: rcar_sound@ec500000 { }; rcar_sound,src { - src0: src@0 { }; - src1: src@1 { }; - src2: src@2 { }; - src3: src@3 { }; - src4: src@4 { }; - src5: src@5 { }; - src6: src@6 { }; - src7: src@7 { }; - src8: src@8 { }; - src9: src@9 { }; + src0: src@0 { + interrupts = <0 352 IRQ_TYPE_LEVEL_HIGH>; + }; + src1: src@1 { + interrupts = <0 353 IRQ_TYPE_LEVEL_HIGH>; + }; + src2: src@2 { + interrupts = <0 354 IRQ_TYPE_LEVEL_HIGH>; + }; + src3: src@3 { + interrupts = <0 355 IRQ_TYPE_LEVEL_HIGH>; + }; + src4: src@4 { + interrupts = <0 356 IRQ_TYPE_LEVEL_HIGH>; + }; + src5: src@5 { + interrupts = <0 357 IRQ_TYPE_LEVEL_HIGH>; + }; + src6: src@6 { + interrupts = <0 358 IRQ_TYPE_LEVEL_HIGH>; + }; + src7: src@7 { + interrupts = <0 359 IRQ_TYPE_LEVEL_HIGH>; + }; + src8: src@8 { + interrupts = <0 360 IRQ_TYPE_LEVEL_HIGH>; + }; + src9: src@9 { + interrupts = <0 361 IRQ_TYPE_LEVEL_HIGH>; + }; }; rcar_sound,ssi { -- cgit v1.2.3-59-g8ed1b From bb02714fe5f198c0f07a8039ebcc636c1bffbc03 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 20 Feb 2015 10:32:15 +0000 Subject: ASoC: rsnd: add sample code of missing clocks Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/renesas,rsnd.txt | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt index 87e0fc2ce399..503967ba39db 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt @@ -47,6 +47,27 @@ rcar_sound: rcar_sound@ec500000 { <0 0xec540000 0 0x1000>, /* SSIU */ <0 0xec541000 0 0x1280>; /* SSI */ + clocks = <&mstp10_clks R8A7790_CLK_SSI_ALL>, + <&mstp10_clks R8A7790_CLK_SSI9>, <&mstp10_clks R8A7790_CLK_SSI8>, + <&mstp10_clks R8A7790_CLK_SSI7>, <&mstp10_clks R8A7790_CLK_SSI6>, + <&mstp10_clks R8A7790_CLK_SSI5>, <&mstp10_clks R8A7790_CLK_SSI4>, + <&mstp10_clks R8A7790_CLK_SSI3>, <&mstp10_clks R8A7790_CLK_SSI2>, + <&mstp10_clks R8A7790_CLK_SSI1>, <&mstp10_clks R8A7790_CLK_SSI0>, + <&mstp10_clks R8A7790_CLK_SCU_SRC9>, <&mstp10_clks R8A7790_CLK_SCU_SRC8>, + <&mstp10_clks R8A7790_CLK_SCU_SRC7>, <&mstp10_clks R8A7790_CLK_SCU_SRC6>, + <&mstp10_clks R8A7790_CLK_SCU_SRC5>, <&mstp10_clks R8A7790_CLK_SCU_SRC4>, + <&mstp10_clks R8A7790_CLK_SCU_SRC3>, <&mstp10_clks R8A7790_CLK_SCU_SRC2>, + <&mstp10_clks R8A7790_CLK_SCU_SRC1>, <&mstp10_clks R8A7790_CLK_SCU_SRC0>, + <&mstp10_clks R8A7790_CLK_SCU_DVC0>, <&mstp10_clks R8A7790_CLK_SCU_DVC1>, + <&audio_clk_a>, <&audio_clk_b>, <&audio_clk_c>, <&m2_clk>; + clock-names = "ssi-all", + "ssi.9", "ssi.8", "ssi.7", "ssi.6", "ssi.5", + "ssi.4", "ssi.3", "ssi.2", "ssi.1", "ssi.0", + "src.9", "src.8", "src.7", "src.6", "src.5", + "src.4", "src.3", "src.2", "src.1", "src.0", + "dvc.0", "dvc.1", + "clk_a", "clk_b", "clk_c", "clk_i"; + rcar_sound,dvc { dvc0: dvc@0 { }; dvc1: dvc@1 { }; -- cgit v1.2.3-59-g8ed1b From e80a2fb18bc7dca116ec623dc909f07c5e505349 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 20 Feb 2015 10:32:49 +0000 Subject: ASoC: rsnd: add sample code of dma entry rsnd driver supports Audio DMAC (via DMAEngine) / Audio DMAC peri peri (via rsnd driver) now. This patch adds DT binding sample code on DT binging text Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/renesas,rsnd.txt | 60 ++++++++++++++++++++-- 1 file changed, 57 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt index 503967ba39db..6e660d4f3631 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt @@ -29,9 +29,17 @@ SSI subnode properties: - shared-pin : if shared clock pin - pio-transfer : use PIO transfer mode - no-busif : BUSIF is not ussed when [mem -> SSI] via DMA case +- dma : Should contain Audio DMAC entry +- dma-names : SSI case "rx" (=playback), "tx" (=capture) + SSIU case "rxu" (=playback), "txu" (=capture) SRC subnode properties: -no properties at this point +- dma : Should contain Audio DMAC entry +- dma-names : "rx" (=playback), "tx" (=capture) + +DVC subnode properties: +- dma : Should contain Audio DMAC entry +- dma-names : "tx" (=playback/capture) DAI subnode properties: - playback : list of playback modules @@ -69,73 +77,119 @@ rcar_sound: rcar_sound@ec500000 { "clk_a", "clk_b", "clk_c", "clk_i"; rcar_sound,dvc { - dvc0: dvc@0 { }; - dvc1: dvc@1 { }; + dvc0: dvc@0 { + dmas = <&audma0 0xbc>; + dma-names = "tx"; + }; + dvc1: dvc@1 { + dmas = <&audma0 0xbe>; + dma-names = "tx"; + }; }; rcar_sound,src { src0: src@0 { interrupts = <0 352 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x85>, <&audma1 0x9a>; + dma-names = "rx", "tx"; }; src1: src@1 { interrupts = <0 353 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x87>, <&audma1 0x9c>; + dma-names = "rx", "tx"; }; src2: src@2 { interrupts = <0 354 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x89>, <&audma1 0x9e>; + dma-names = "rx", "tx"; }; src3: src@3 { interrupts = <0 355 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x8b>, <&audma1 0xa0>; + dma-names = "rx", "tx"; }; src4: src@4 { interrupts = <0 356 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x8d>, <&audma1 0xb0>; + dma-names = "rx", "tx"; }; src5: src@5 { interrupts = <0 357 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x8f>, <&audma1 0xb2>; + dma-names = "rx", "tx"; }; src6: src@6 { interrupts = <0 358 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x91>, <&audma1 0xb4>; + dma-names = "rx", "tx"; }; src7: src@7 { interrupts = <0 359 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x93>, <&audma1 0xb6>; + dma-names = "rx", "tx"; }; src8: src@8 { interrupts = <0 360 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x95>, <&audma1 0xb8>; + dma-names = "rx", "tx"; }; src9: src@9 { interrupts = <0 361 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x97>, <&audma1 0xba>; + dma-names = "rx", "tx"; }; }; rcar_sound,ssi { ssi0: ssi@0 { interrupts = <0 370 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x01>, <&audma1 0x02>, <&audma0 0x15>, <&audma1 0x16>; + dma-names = "rx", "tx", "rxu", "txu"; }; ssi1: ssi@1 { interrupts = <0 371 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x03>, <&audma1 0x04>, <&audma0 0x49>, <&audma1 0x4a>; + dma-names = "rx", "tx", "rxu", "txu"; }; ssi2: ssi@2 { interrupts = <0 372 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x05>, <&audma1 0x06>, <&audma0 0x63>, <&audma1 0x64>; + dma-names = "rx", "tx", "rxu", "txu"; }; ssi3: ssi@3 { interrupts = <0 373 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x07>, <&audma1 0x08>, <&audma0 0x6f>, <&audma1 0x70>; + dma-names = "rx", "tx", "rxu", "txu"; }; ssi4: ssi@4 { interrupts = <0 374 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x09>, <&audma1 0x0a>, <&audma0 0x71>, <&audma1 0x72>; + dma-names = "rx", "tx", "rxu", "txu"; }; ssi5: ssi@5 { interrupts = <0 375 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x0b>, <&audma1 0x0c>, <&audma0 0x73>, <&audma1 0x74>; + dma-names = "rx", "tx", "rxu", "txu"; }; ssi6: ssi@6 { interrupts = <0 376 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x0d>, <&audma1 0x0e>, <&audma0 0x75>, <&audma1 0x76>; + dma-names = "rx", "tx", "rxu", "txu"; }; ssi7: ssi@7 { interrupts = <0 377 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x0f>, <&audma1 0x10>, <&audma0 0x79>, <&audma1 0x7a>; + dma-names = "rx", "tx", "rxu", "txu"; }; ssi8: ssi@8 { interrupts = <0 378 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x11>, <&audma1 0x12>, <&audma0 0x7b>, <&audma1 0x7c>; + dma-names = "rx", "tx", "rxu", "txu"; }; ssi9: ssi@9 { interrupts = <0 379 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x13>, <&audma1 0x14>, <&audma0 0x7d>, <&audma1 0x7e>; + dma-names = "rx", "tx", "rxu", "txu"; }; }; -- cgit v1.2.3-59-g8ed1b From d3b1c0badbc86c034af55704ea88c1e656b402fe Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 20 Feb 2015 10:33:09 +0000 Subject: ASoC: rsnd: add sample code of reg-names Current rsnd driver supports reg-names, and Audio DMAC peri peri. This patch adds sample code for it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/renesas,rsnd.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt index 6e660d4f3631..f316ce1f214a 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt @@ -53,7 +53,9 @@ rcar_sound: rcar_sound@ec500000 { reg = <0 0xec500000 0 0x1000>, /* SCU */ <0 0xec5a0000 0 0x100>, /* ADG */ <0 0xec540000 0 0x1000>, /* SSIU */ - <0 0xec541000 0 0x1280>; /* SSI */ + <0 0xec541000 0 0x1280>, /* SSI */ + <0 0xec740000 0 0x200>; /* Audio DMAC peri peri*/ + reg-names = "scu", "adg", "ssiu", "ssi", "audmapp"; clocks = <&mstp10_clks R8A7790_CLK_SSI_ALL>, <&mstp10_clks R8A7790_CLK_SSI9>, <&mstp10_clks R8A7790_CLK_SSI8>, -- cgit v1.2.3-59-g8ed1b From c8b263cc03eaaa324c9222474191e6d849cb6dda Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Sat, 7 Mar 2015 16:33:53 +0100 Subject: regulator: act8865: add input supply handling The act88600/act8846/act8865 regulators have a number of input supplies supplying the individual regulators. This may even be recursively like on most Rockchip boards using the act8846 where REG4 is most of the time connected to the inl1-supply. Therefore add the ability to specify the input supplies for the individual inputs. The input-names are taken from the datasheets of act8600, act8846 and act8865. On the act8600 some regulators do not have separate input supplies. Signed-off-by: Heiko Stuebner Signed-off-by: Mark Brown --- .../bindings/regulator/act8865-regulator.txt | 22 +++++++++ drivers/regulator/act8865-regulator.c | 55 +++++++++++----------- 2 files changed, 50 insertions(+), 27 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/regulator/act8865-regulator.txt b/Documentation/devicetree/bindings/regulator/act8865-regulator.txt index e170df2357df..e91485d11241 100644 --- a/Documentation/devicetree/bindings/regulator/act8865-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/act8865-regulator.txt @@ -9,6 +9,28 @@ Optional properties: - system-power-controller: Telling whether or not this pmic is controlling the system power. See Documentation/devicetree/bindings/power/power-controller.txt . +Optional input supply properties: +- for act8600: + - vp1-supply: The input supply for DCDC_REG1 + - vp2-supply: The input supply for DCDC_REG2 + - vp3-supply: The input supply for DCDC_REG3 + - inl-supply: The input supply for LDO_REG5, LDO_REG6, LDO_REG7 and LDO_REG8 + SUDCDC_REG4, LDO_REG9 and LDO_REG10 do not have separate supplies. +- for act8846: + - vp1-supply: The input supply for REG1 + - vp2-supply: The input supply for REG2 + - vp3-supply: The input supply for REG3 + - vp4-supply: The input supply for REG4 + - inl1-supply: The input supply for REG5, REG6 and REG7 + - inl2-supply: The input supply for REG8 and LDO_REG9 + - inl3-supply: The input supply for REG10, REG11 and REG12 +- for act8865: + - vp1-supply: The input supply for DCDC_REG1 + - vp2-supply: The input supply for DCDC_REG2 + - vp3-supply: The input supply for DCDC_REG3 + - inl45-supply: The input supply for LDO_REG1 and LDO_REG2 + - inl67-supply: The input supply for LDO_REG3 and LDO_REG4 + Any standard regulator properties can be used to configure the single regulator. The valid names for regulators are: diff --git a/drivers/regulator/act8865-regulator.c b/drivers/regulator/act8865-regulator.c index 3781f6e289d8..2ff73d72ca34 100644 --- a/drivers/regulator/act8865-regulator.c +++ b/drivers/regulator/act8865-regulator.c @@ -173,9 +173,10 @@ static struct regulator_ops act8865_ldo_ops = { .is_enabled = regulator_is_enabled_regmap, }; -#define ACT88xx_REG(_name, _family, _id, _vsel_reg) \ +#define ACT88xx_REG(_name, _family, _id, _vsel_reg, _supply) \ [_family##_ID_##_id] = { \ .name = _name, \ + .supply_name = _supply, \ .id = _family##_ID_##_id, \ .type = REGULATOR_VOLTAGE, \ .ops = &act8865_ops, \ @@ -190,9 +191,9 @@ static struct regulator_ops act8865_ldo_ops = { } static const struct regulator_desc act8600_regulators[] = { - ACT88xx_REG("DCDC1", ACT8600, DCDC1, VSET), - ACT88xx_REG("DCDC2", ACT8600, DCDC2, VSET), - ACT88xx_REG("DCDC3", ACT8600, DCDC3, VSET), + ACT88xx_REG("DCDC1", ACT8600, DCDC1, VSET, "vp1"), + ACT88xx_REG("DCDC2", ACT8600, DCDC2, VSET, "vp2"), + ACT88xx_REG("DCDC3", ACT8600, DCDC3, VSET, "vp3"), { .name = "SUDCDC_REG4", .id = ACT8600_ID_SUDCDC4, @@ -207,10 +208,10 @@ static const struct regulator_desc act8600_regulators[] = { .enable_mask = ACT8865_ENA, .owner = THIS_MODULE, }, - ACT88xx_REG("LDO5", ACT8600, LDO5, VSET), - ACT88xx_REG("LDO6", ACT8600, LDO6, VSET), - ACT88xx_REG("LDO7", ACT8600, LDO7, VSET), - ACT88xx_REG("LDO8", ACT8600, LDO8, VSET), + ACT88xx_REG("LDO5", ACT8600, LDO5, VSET, "inl"), + ACT88xx_REG("LDO6", ACT8600, LDO6, VSET, "inl"), + ACT88xx_REG("LDO7", ACT8600, LDO7, VSET, "inl"), + ACT88xx_REG("LDO8", ACT8600, LDO8, VSET, "inl"), { .name = "LDO_REG9", .id = ACT8600_ID_LDO9, @@ -236,28 +237,28 @@ static const struct regulator_desc act8600_regulators[] = { }; static const struct regulator_desc act8846_regulators[] = { - ACT88xx_REG("REG1", ACT8846, REG1, VSET), - ACT88xx_REG("REG2", ACT8846, REG2, VSET0), - ACT88xx_REG("REG3", ACT8846, REG3, VSET0), - ACT88xx_REG("REG4", ACT8846, REG4, VSET0), - ACT88xx_REG("REG5", ACT8846, REG5, VSET), - ACT88xx_REG("REG6", ACT8846, REG6, VSET), - ACT88xx_REG("REG7", ACT8846, REG7, VSET), - ACT88xx_REG("REG8", ACT8846, REG8, VSET), - ACT88xx_REG("REG9", ACT8846, REG9, VSET), - ACT88xx_REG("REG10", ACT8846, REG10, VSET), - ACT88xx_REG("REG11", ACT8846, REG11, VSET), - ACT88xx_REG("REG12", ACT8846, REG12, VSET), + ACT88xx_REG("REG1", ACT8846, REG1, VSET, "vp1"), + ACT88xx_REG("REG2", ACT8846, REG2, VSET0, "vp2"), + ACT88xx_REG("REG3", ACT8846, REG3, VSET0, "vp3"), + ACT88xx_REG("REG4", ACT8846, REG4, VSET0, "vp4"), + ACT88xx_REG("REG5", ACT8846, REG5, VSET, "inl1"), + ACT88xx_REG("REG6", ACT8846, REG6, VSET, "inl1"), + ACT88xx_REG("REG7", ACT8846, REG7, VSET, "inl1"), + ACT88xx_REG("REG8", ACT8846, REG8, VSET, "inl2"), + ACT88xx_REG("REG9", ACT8846, REG9, VSET, "inl2"), + ACT88xx_REG("REG10", ACT8846, REG10, VSET, "inl3"), + ACT88xx_REG("REG11", ACT8846, REG11, VSET, "inl3"), + ACT88xx_REG("REG12", ACT8846, REG12, VSET, "inl3"), }; static const struct regulator_desc act8865_regulators[] = { - ACT88xx_REG("DCDC_REG1", ACT8865, DCDC1, VSET1), - ACT88xx_REG("DCDC_REG2", ACT8865, DCDC2, VSET1), - ACT88xx_REG("DCDC_REG3", ACT8865, DCDC3, VSET1), - ACT88xx_REG("LDO_REG1", ACT8865, LDO1, VSET), - ACT88xx_REG("LDO_REG2", ACT8865, LDO2, VSET), - ACT88xx_REG("LDO_REG3", ACT8865, LDO3, VSET), - ACT88xx_REG("LDO_REG4", ACT8865, LDO4, VSET), + ACT88xx_REG("DCDC_REG1", ACT8865, DCDC1, VSET1, "vp1"), + ACT88xx_REG("DCDC_REG2", ACT8865, DCDC2, VSET1, "vp2"), + ACT88xx_REG("DCDC_REG3", ACT8865, DCDC3, VSET1, "vp3"), + ACT88xx_REG("LDO_REG1", ACT8865, LDO1, VSET, "inl45"), + ACT88xx_REG("LDO_REG2", ACT8865, LDO2, VSET, "inl45"), + ACT88xx_REG("LDO_REG3", ACT8865, LDO3, VSET, "inl67"), + ACT88xx_REG("LDO_REG4", ACT8865, LDO4, VSET, "inl67"), }; #ifdef CONFIG_OF -- cgit v1.2.3-59-g8ed1b From 4fd9bbc6e0713a0106a7771b639a963f4b2411c6 Mon Sep 17 00:00:00 2001 From: Tien Hock Loh Date: Tue, 24 Feb 2015 01:53:02 -0800 Subject: drivers/gpio: Altera soft IP GPIO driver device tree binding Adds a new driver device tree binding for Altera soft GPIO IP Signed-off-by: Tien Hock Loh Signed-off-by: Linus Walleij --- .../devicetree/bindings/gpio/gpio-altera.txt | 43 ++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpio/gpio-altera.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/gpio/gpio-altera.txt b/Documentation/devicetree/bindings/gpio/gpio-altera.txt new file mode 100644 index 000000000000..12f50149e1ed --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio-altera.txt @@ -0,0 +1,43 @@ +Altera GPIO controller bindings + +Required properties: +- compatible: + - "altr,pio-1.0" +- reg: Physical base address and length of the controller's registers. +- #gpio-cells : Should be 2 + - The first cell is the gpio offset number. + - The second cell is reserved and is currently unused. +- gpio-controller : Marks the device node as a GPIO controller. +- interrupt-controller: Mark the device node as an interrupt controller +- #interrupt-cells : Should be 1. The interrupt type is fixed in the hardware. + - The first cell is the GPIO offset number within the GPIO controller. +- interrupts: Specify the interrupt. +- altr,interrupt-trigger: Specifies the interrupt trigger type the GPIO + hardware is synthesized. This field is required if the Altera GPIO controller + used has IRQ enabled as the interrupt type is not software controlled, + but hardware synthesized. Required if GPIO is used as an interrupt + controller. The value is defined in + Only the following flags are supported: + IRQ_TYPE_EDGE_RISING + IRQ_TYPE_EDGE_FALLING + IRQ_TYPE_EDGE_BOTH + IRQ_TYPE_LEVEL_HIGH + +Optional properties: +- altr,ngpio: Width of the GPIO bank. This defines how many pins the + GPIO device has. Ranges between 1-32. Optional and defaults to 32 if not + specified. + +Example: + +gpio_altr: gpio@0xff200000 { + compatible = "altr,pio-1.0"; + reg = <0xff200000 0x10>; + interrupts = <0 45 4>; + altr,ngpio = <32>; + altr,interrupt-trigger = ; + #gpio-cells = <2>; + gpio-controller; + #interrupt-cells = <1>; + interrupt-controller; +}; -- cgit v1.2.3-59-g8ed1b From 4a073175392df3aa84fabca5a1bde47f36677d69 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Sun, 1 Mar 2015 23:41:28 +0100 Subject: irqchip: vf610-mscm: Add Vybrid MSCM bindings Add binding documentation for CPU configuration and interrupt router submodule of the Miscellaneous System Control Module. The MSCM is used in all variants of Freescale Vybrid SoC's. Acked-by: Marc Zyngier Signed-off-by: Stefan Agner Link: https://lkml.kernel.org/r/1425249689-32354-3-git-send-email-stefan@agner.ch Signed-off-by: Jason Cooper --- .../arm/freescale/fsl,vf610-mscm-cpucfg.txt | 14 +++++++++ .../bindings/arm/freescale/fsl,vf610-mscm-ir.txt | 33 ++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/freescale/fsl,vf610-mscm-cpucfg.txt create mode 100644 Documentation/devicetree/bindings/arm/freescale/fsl,vf610-mscm-ir.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/freescale/fsl,vf610-mscm-cpucfg.txt b/Documentation/devicetree/bindings/arm/freescale/fsl,vf610-mscm-cpucfg.txt new file mode 100644 index 000000000000..44aa3c451ccf --- /dev/null +++ b/Documentation/devicetree/bindings/arm/freescale/fsl,vf610-mscm-cpucfg.txt @@ -0,0 +1,14 @@ +Freescale Vybrid Miscellaneous System Control - CPU Configuration + +The MSCM IP contains multiple sub modules, this binding describes the first +block of registers which contains CPU configuration information. + +Required properties: +- compatible: "fsl,vf610-mscm-cpucfg", "syscon" +- reg: the register range of the MSCM CPU configuration registers + +Example: + mscm_cpucfg: cpucfg@40001000 { + compatible = "fsl,vf610-mscm-cpucfg", "syscon"; + reg = <0x40001000 0x800>; + } diff --git a/Documentation/devicetree/bindings/arm/freescale/fsl,vf610-mscm-ir.txt b/Documentation/devicetree/bindings/arm/freescale/fsl,vf610-mscm-ir.txt new file mode 100644 index 000000000000..669808b2af49 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/freescale/fsl,vf610-mscm-ir.txt @@ -0,0 +1,33 @@ +Freescale Vybrid Miscellaneous System Control - Interrupt Router + +The MSCM IP contains multiple sub modules, this binding describes the second +block of registers which control the interrupt router. The interrupt router +allows to configure the recipient of each peripheral interrupt. Furthermore +it controls the directed processor interrupts. The module is available in all +Vybrid SoC's but is only really useful in dual core configurations (VF6xx +which comes with a Cortex-A5/Cortex-M4 combination). + +Required properties: +- compatible: "fsl,vf610-mscm-ir" +- reg: the register range of the MSCM Interrupt Router +- fsl,cpucfg: The handle to the MSCM CPU configuration node, required + to get the current CPU ID +- interrupt-controller: Identifies the node as an interrupt controller +- #interrupt-cells: Two cells, interrupt number and cells. + The hardware interrupt number according to interrupt + assignment of the interrupt router is required. + Flags get passed only when using GIC as parent. Flags + encoding as documented by the GIC bindings. +- interrupt-parent: Should be the phandle for the interrupt controller of + the CPU the device tree is intended to be used on. This + is either the node of the GIC or NVIC controller. + +Example: + mscm_ir: interrupt-controller@40001800 { + compatible = "fsl,vf610-mscm-ir"; + reg = <0x40001800 0x400>; + fsl,cpucfg = <&mscm_cpucfg>; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&intc>; + } -- cgit v1.2.3-59-g8ed1b From 47875e81476bda8a9bd4875eb281b46e33027d42 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 8 Mar 2015 14:56:37 +0100 Subject: spi: Use PM ops instead of legacy suspend/resume New drivers should use PM ops instead of the legacy suspend/resume callbacks. Update the SPI device driver guide to reflect this. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- Documentation/spi/spi-summary | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/spi/spi-summary b/Documentation/spi/spi-summary index d29734bff28c..d1824b399b2d 100644 --- a/Documentation/spi/spi-summary +++ b/Documentation/spi/spi-summary @@ -342,12 +342,11 @@ SPI protocol drivers somewhat resemble platform device drivers: .driver = { .name = "CHIP", .owner = THIS_MODULE, + .pm = &CHIP_pm_ops, }, .probe = CHIP_probe, .remove = CHIP_remove, - .suspend = CHIP_suspend, - .resume = CHIP_resume, }; The driver core will automatically attempt to bind this driver to any SPI -- cgit v1.2.3-59-g8ed1b From 91c68a7c1d92b48287f2f3111a9b09b26a263d3f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 8 Mar 2015 14:12:41 -0700 Subject: Input: sun4i-ts - A10 (sun4i) has a different temperature curve Testing has revealed that the temperature in the rtp controller of the A10 (sun4i) SoC has a different curve then on the A13 (sun5i) and later models. Add a new sun5i-a13-ts compatible to differentiate the newer models and set the curve based on the compatible string. The new curve is still not ideal on all A10-s, that seems to have to do with there being a large spread between different A10-s out there, the new curve us based on callibration results on 4 completely different models: raw min raw max temp min temp max stepsize offset Tong Zhang's hackberry 2402 2680 45.0 80.0 0.125 -255.3 Hansg's Cubieboard 2207 2300 36.0 45.0 0.096 -175.8 Olliver's lime 1 (*): 2258 2537 48.3 87.1 0.139 -265.7 Olliver's lime 2 (*): 2222 2486 46.7 91.7 0.170 -331.0 *) from: http://linux-sunxi.org/Temperature_Calibration Average all 4: 0.133 -257.0 Average without outliers (middle 2): 0.132 -261.0 Since it is better to slightly overreport the temperature this patch uses the average of all 4 as curve. This fixes the temperature reported on the A10 being much higher then expected. Reported-by: Tong Zhang Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov --- .../devicetree/bindings/input/touchscreen/sun4i.txt | 3 ++- drivers/input/touchscreen/sun4i-ts.c | 16 +++++++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/input/touchscreen/sun4i.txt b/Documentation/devicetree/bindings/input/touchscreen/sun4i.txt index 433332d3b2ba..d59d25281e9f 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/sun4i.txt +++ b/Documentation/devicetree/bindings/input/touchscreen/sun4i.txt @@ -2,7 +2,8 @@ sun4i resistive touchscreen controller -------------------------------------- Required properties: - - compatible: "allwinner,sun4i-a10-ts" or "allwinner,sun6i-a31-ts" + - compatible: "allwinner,sun4i-a10-ts", "allwinner,sun5i-a13-ts" or + "allwinner,sun6i-a31-ts" - reg: mmio address range of the chip - interrupts: interrupt to which the chip is connected - #thermal-sensor-cells: shall be 0 diff --git a/drivers/input/touchscreen/sun4i-ts.c b/drivers/input/touchscreen/sun4i-ts.c index b93a28b955fd..66ccd5af537d 100644 --- a/drivers/input/touchscreen/sun4i-ts.c +++ b/drivers/input/touchscreen/sun4i-ts.c @@ -258,6 +258,15 @@ static int sun4i_ts_probe(struct platform_device *pdev) /* Allwinner SDK has temperature = -271 + (value / 6) (C) */ ts->temp_offset = 1626; ts->temp_step = 167; + } else if (of_device_is_compatible(np, "allwinner,sun4i-a10-ts")) { + /* + * The A10 temperature sensor has quite a wide spread, these + * parameters are based on the averaging of the calibration + * results of 4 completely different boards, with a spread of + * temp_step from 96 - 170 and temp_offset from 1758 - 3310. + */ + ts->temp_offset = 2570; + ts->temp_step = 133; } else { /* * The user manuals do not contain the formula for calculating @@ -330,10 +339,10 @@ static int sun4i_ts_probe(struct platform_device *pdev) * finally enable tp mode. */ reg = STYLUS_UP_DEBOUN(5) | STYLUS_UP_DEBOUN_EN(1); - if (of_device_is_compatible(np, "allwinner,sun4i-a10-ts")) - reg |= TP_MODE_EN(1); - else + if (of_device_is_compatible(np, "allwinner,sun6i-a31-ts")) reg |= SUN6I_TP_MODE_EN(1); + else + reg |= TP_MODE_EN(1); writel(reg, ts->base + TP_CTRL1); /* @@ -383,6 +392,7 @@ static int sun4i_ts_remove(struct platform_device *pdev) static const struct of_device_id sun4i_ts_of_match[] = { { .compatible = "allwinner,sun4i-a10-ts", }, + { .compatible = "allwinner,sun5i-a13-ts", }, { .compatible = "allwinner,sun6i-a31-ts", }, { /* sentinel */ } }; -- cgit v1.2.3-59-g8ed1b From 008a5b07f1b4beab1004ac799f449b59a45af8e9 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Sun, 8 Mar 2015 11:48:49 -0700 Subject: neterion: remove reference to ifconfig Remove reference to obsolete ifconfig command. MTU can be changed with ip command instead. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- Documentation/networking/s2io.txt | 2 +- Documentation/networking/vxge.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/s2io.txt b/Documentation/networking/s2io.txt index d2a9f43b5546..0362a42f7cf4 100644 --- a/Documentation/networking/s2io.txt +++ b/Documentation/networking/s2io.txt @@ -38,7 +38,7 @@ The corresponding adapter's LED will blink multiple times. 3. Features supported: a. Jumbo frames. Xframe I/II supports MTU up to 9600 bytes, -modifiable using ifconfig command. +modifiable using ip command. b. Offloads. Supports checksum offload(TCP/UDP/IP) on transmit and receive, TSO. diff --git a/Documentation/networking/vxge.txt b/Documentation/networking/vxge.txt index bb76c667a476..abfec245f97c 100644 --- a/Documentation/networking/vxge.txt +++ b/Documentation/networking/vxge.txt @@ -39,7 +39,7 @@ iii) PCI-SIG's I/O Virtualization iv) Jumbo frames X3100 Series supports MTU up to 9600 bytes, modifiable using - ifconfig command. + ip command. v) Offloads supported: (Enabled by default) Checksum offload (TCP/UDP/IP) on transmit and receive paths -- cgit v1.2.3-59-g8ed1b From fc6c6c2b8a2e1fbaa9e864af62c873dae15420ea Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Sat, 7 Mar 2015 07:37:06 +0100 Subject: net/macb: Update DT bindings documentation Add missing "cdns,at91sam9260-macb", "atmel,sama5d3-gem" and "atmel,sama5d4-gem" compatible strings. Signed-off-by: Boris Brezillon Reviewed-by: Alexandre Belloni Acked-by: Nicolas Ferre Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/macb.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/macb.txt b/Documentation/devicetree/bindings/net/macb.txt index aaa696414f57..ba19d671e808 100644 --- a/Documentation/devicetree/bindings/net/macb.txt +++ b/Documentation/devicetree/bindings/net/macb.txt @@ -2,10 +2,13 @@ Required properties: - compatible: Should be "cdns,[-]{macb|gem}" - Use "cdns,at91sam9260-macb" Atmel at91sam9260 and at91sam9263 SoCs. + Use "cdns,at91sam9260-macb" for Atmel at91sam9 SoCs or the 10/100Mbit IP + available on sama5d3 SoCs. Use "cdns,at32ap7000-macb" for other 10/100 usage or use the generic form: "cdns,macb". Use "cdns,pc302-gem" for Picochip picoXcell pc302 and later devices based on the Cadence GEM, or the generic form: "cdns,gem". + Use "cdns,sama5d3-gem" for the Gigabit IP available on Atmel sama5d3 SoCs. + Use "cdns,sama5d4-gem" for the Gigabit IP available on Atmel sama5d4 SoCs. - reg: Address and length of the register set for the device - interrupts: Should contain macb interrupt - phy-mode: See ethernet.txt file in the same directory. -- cgit v1.2.3-59-g8ed1b From dbe5fe7e1b3b3632bef2c09964a5f5505de4d744 Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Fri, 6 Mar 2015 21:34:22 +0100 Subject: crypto: doc - AEAD / RNG AF_ALG interface The patch moves the information provided in Documentation/crypto/crypto-API-userspace.txt into a separate chapter in the kernel crypto API DocBook. Some corrections are applied (such as removing a reference to Netlink when the AF_ALG socket is referred to). In addition, the AEAD and RNG interface description is now added. Also, a brief description of the zero-copy interface with an example code snippet is provided. Signed-off-by: Stephan Mueller Signed-off-by: Herbert Xu --- Documentation/DocBook/crypto-API.tmpl | 596 ++++++++++++++++++++++++++ Documentation/crypto/crypto-API-userspace.txt | 205 --------- 2 files changed, 596 insertions(+), 205 deletions(-) delete mode 100644 Documentation/crypto/crypto-API-userspace.txt (limited to 'Documentation') diff --git a/Documentation/DocBook/crypto-API.tmpl b/Documentation/DocBook/crypto-API.tmpl index 33f63cfc00ca..efc8d90a9a3f 100644 --- a/Documentation/DocBook/crypto-API.tmpl +++ b/Documentation/DocBook/crypto-API.tmpl @@ -1072,6 +1072,602 @@ kernel crypto API | Caller + User Space Interface + Introduction + + The concepts of the kernel crypto API visible to kernel space is fully + applicable to the user space interface as well. Therefore, the kernel + crypto API high level discussion for the in-kernel use cases applies + here as well. + + + + The major difference, however, is that user space can only act as a + consumer and never as a provider of a transformation or cipher algorithm. + + + + The following covers the user space interface exported by the kernel + crypto API. A working example of this description is libkcapi that + can be obtained from [1]. That library can be used by user space + applications that require cryptographic services from the kernel. + + + + Some details of the in-kernel kernel crypto API aspects do not + apply to user space, however. This includes the difference between + synchronous and asynchronous invocations. The user space API call + is fully synchronous. + + + + [1] http://www.chronox.de/libkcapi.html + + + + + User Space API General Remarks + + The kernel crypto API is accessible from user space. Currently, + the following ciphers are accessible: + + + + + Message digest including keyed message digest (HMAC, CMAC) + + + + Symmetric ciphers + + + + AEAD ciphers + + + + Random Number Generators + + + + + The interface is provided via socket type using the type AF_ALG. + In addition, the setsockopt option type is SOL_ALG. In case the + user space header files do not export these flags yet, use the + following macros: + + + +#ifndef AF_ALG +#define AF_ALG 38 +#endif +#ifndef SOL_ALG +#define SOL_ALG 279 +#endif + + + + A cipher is accessed with the same name as done for the in-kernel + API calls. This includes the generic vs. unique naming schema for + ciphers as well as the enforcement of priorities for generic names. + + + + To interact with the kernel crypto API, a socket must be + created by the user space application. User space invokes the cipher + operation with the send()/write() system call family. The result of the + cipher operation is obtained with the read()/recv() system call family. + + + + The following API calls assume that the socket descriptor + is already opened by the user space application and discusses only + the kernel crypto API specific invocations. + + + + To initialize the socket interface, the following sequence has to + be performed by the consumer: + + + + + + Create a socket of type AF_ALG with the struct sockaddr_alg + parameter specified below for the different cipher types. + + + + + + Invoke bind with the socket descriptor + + + + + + Invoke accept with the socket descriptor. The accept system call + returns a new file descriptor that is to be used to interact with + the particular cipher instance. When invoking send/write or recv/read + system calls to send data to the kernel or obtain data from the + kernel, the file descriptor returned by accept must be used. + + + + + + In-place Cipher operation + + Just like the in-kernel operation of the kernel crypto API, the user + space interface allows the cipher operation in-place. That means that + the input buffer used for the send/write system call and the output + buffer used by the read/recv system call may be one and the same. + This is of particular interest for symmetric cipher operations where a + copying of the output data to its final destination can be avoided. + + + + If a consumer on the other hand wants to maintain the plaintext and + the ciphertext in different memory locations, all a consumer needs + to do is to provide different memory pointers for the encryption and + decryption operation. + + + + Message Digest API + + The message digest type to be used for the cipher operation is + selected when invoking the bind syscall. bind requires the caller + to provide a filled struct sockaddr data structure. This data + structure must be filled as follows: + + + +struct sockaddr_alg sa = { + .salg_family = AF_ALG, + .salg_type = "hash", /* this selects the hash logic in the kernel */ + .salg_name = "sha1" /* this is the cipher name */ +}; + + + + The salg_type value "hash" applies to message digests and keyed + message digests. Though, a keyed message digest is referenced by + the appropriate salg_name. Please see below for the setsockopt + interface that explains how the key can be set for a keyed message + digest. + + + + Using the send() system call, the application provides the data that + should be processed with the message digest. The send system call + allows the following flags to be specified: + + + + + + MSG_MORE: If this flag is set, the send system call acts like a + message digest update function where the final hash is not + yet calculated. If the flag is not set, the send system call + calculates the final message digest immediately. + + + + + + With the recv() system call, the application can read the message + digest from the kernel crypto API. If the buffer is too small for the + message digest, the flag MSG_TRUNC is set by the kernel. + + + + In order to set a message digest key, the calling application must use + the setsockopt() option of ALG_SET_KEY. If the key is not set the HMAC + operation is performed without the initial HMAC state change caused by + the key. + + + + Symmetric Cipher API + + The operation is very similar to the message digest discussion. + During initialization, the struct sockaddr data structure must be + filled as follows: + + + +struct sockaddr_alg sa = { + .salg_family = AF_ALG, + .salg_type = "skcipher", /* this selects the symmetric cipher */ + .salg_name = "cbc(aes)" /* this is the cipher name */ +}; + + + + Before data can be sent to the kernel using the write/send system + call family, the consumer must set the key. The key setting is + described with the setsockopt invocation below. + + + + Using the sendmsg() system call, the application provides the data that should be processed for encryption or decryption. In addition, the IV is + specified with the data structure provided by the sendmsg() system call. + + + + The sendmsg system call parameter of struct msghdr is embedded into the + struct cmsghdr data structure. See recv(2) and cmsg(3) for more + information on how the cmsghdr data structure is used together with the + send/recv system call family. That cmsghdr data structure holds the + following information specified with a separate header instances: + + + + + + specification of the cipher operation type with one of these flags: + + + + ALG_OP_ENCRYPT - encryption of data + + + ALG_OP_DECRYPT - decryption of data + + + + + + + specification of the IV information marked with the flag ALG_SET_IV + + + + + + The send system call family allows the following flag to be specified: + + + + + + MSG_MORE: If this flag is set, the send system call acts like a + cipher update function where more input data is expected + with a subsequent invocation of the send system call. + + + + + + Note: The kernel reports -EINVAL for any unexpected data. The caller + must make sure that all data matches the constraints given in + /proc/crypto for the selected cipher. + + + + With the recv() system call, the application can read the result of + the cipher operation from the kernel crypto API. The output buffer + must be at least as large as to hold all blocks of the encrypted or + decrypted data. If the output data size is smaller, only as many + blocks are returned that fit into that output buffer size. + + + + AEAD Cipher API + + The operation is very similar to the symmetric cipher discussion. + During initialization, the struct sockaddr data structure must be + filled as follows: + + + +struct sockaddr_alg sa = { + .salg_family = AF_ALG, + .salg_type = "aead", /* this selects the symmetric cipher */ + .salg_name = "gcm(aes)" /* this is the cipher name */ +}; + + + + Before data can be sent to the kernel using the write/send system + call family, the consumer must set the key. The key setting is + described with the setsockopt invocation below. + + + + In addition, before data can be sent to the kernel using the + write/send system call family, the consumer must set the authentication + tag size. To set the authentication tag size, the caller must use the + setsockopt invocation described below. + + + + Using the sendmsg() system call, the application provides the data that should be processed for encryption or decryption. In addition, the IV is + specified with the data structure provided by the sendmsg() system call. + + + + The sendmsg system call parameter of struct msghdr is embedded into the + struct cmsghdr data structure. See recv(2) and cmsg(3) for more + information on how the cmsghdr data structure is used together with the + send/recv system call family. That cmsghdr data structure holds the + following information specified with a separate header instances: + + + + + + specification of the cipher operation type with one of these flags: + + + + ALG_OP_ENCRYPT - encryption of data + + + ALG_OP_DECRYPT - decryption of data + + + + + + + specification of the IV information marked with the flag ALG_SET_IV + + + + + + specification of the associated authentication data (AAD) with the + flag ALG_SET_AEAD_ASSOCLEN. The AAD is sent to the kernel together + with the plaintext / ciphertext. See below for the memory structure. + + + + + + The send system call family allows the following flag to be specified: + + + + + + MSG_MORE: If this flag is set, the send system call acts like a + cipher update function where more input data is expected + with a subsequent invocation of the send system call. + + + + + + Note: The kernel reports -EINVAL for any unexpected data. The caller + must make sure that all data matches the constraints given in + /proc/crypto for the selected cipher. + + + + With the recv() system call, the application can read the result of + the cipher operation from the kernel crypto API. The output buffer + must be at least as large as defined with the memory structure below. + If the output data size is smaller, the cipher operation is not performed. + + + + The authenticated decryption operation may indicate an integrity error. + Such breach in integrity is marked with the -EBADMSG error code. + + + AEAD Memory Structure + + The AEAD cipher operates with the following information that + is communicated between user and kernel space as one data stream: + + + + + plaintext or ciphertext + + + + associated authentication data (AAD) + + + + authentication tag + + + + + The sizes of the AAD and the authentication tag are provided with + the sendmsg and setsockopt calls (see there). As the kernel knows + the size of the entire data stream, the kernel is now able to + calculate the right offsets of the data components in the data + stream. + + + + The user space caller must arrange the aforementioned information + in the following order: + + + + + + AEAD encryption input: AAD || plaintext + + + + + + AEAD decryption input: AAD || ciphertext || authentication tag + + + + + + The output buffer the user space caller provides must be at least as + large to hold the following data: + + + + + + AEAD encryption output: ciphertext || authentication tag + + + + + + AEAD decryption output: plaintext + + + + + + + Random Number Generator API + + Again, the operation is very similar to the other APIs. + During initialization, the struct sockaddr data structure must be + filled as follows: + + + +struct sockaddr_alg sa = { + .salg_family = AF_ALG, + .salg_type = "rng", /* this selects the symmetric cipher */ + .salg_name = "drbg_nopr_sha256" /* this is the cipher name */ +}; + + + + Depending on the RNG type, the RNG must be seeded. The seed is provided + using the setsockopt interface to set the key. For example, the + ansi_cprng requires a seed. The DRBGs do not require a seed, but + may be seeded. + + + + Using the read()/recvmsg() system calls, random numbers can be obtained. + The kernel generates at most 128 bytes in one call. If user space + requires more data, multiple calls to read()/recvmsg() must be made. + + + + WARNING: The user space caller may invoke the initially mentioned + accept system call multiple times. In this case, the returned file + descriptors have the same state. + + + + + Zero-Copy Interface + + In addition to the send/write/read/recv system call familty, the AF_ALG + interface can be accessed with the zero-copy interface of splice/vmsplice. + As the name indicates, the kernel tries to avoid a copy operation into + kernel space. + + + + The zero-copy operation requires data to be aligned at the page boundary. + Non-aligned data can be used as well, but may require more operations of + the kernel which would defeat the speed gains obtained from the zero-copy + interface. + + + + The system-interent limit for the size of one zero-copy operation is + 16 pages. If more data is to be sent to AF_ALG, user space must slice + the input into segments with a maximum size of 16 pages. + + + + Zero-copy can be used with the following code example (a complete working + example is provided with libkcapi): + + + +int pipes[2]; + +pipe(pipes); +/* input data in iov */ +vmsplice(pipes[1], iov, iovlen, SPLICE_F_GIFT); +/* opfd is the file descriptor returned from accept() system call */ +splice(pipes[0], NULL, opfd, NULL, ret, 0); +read(opfd, out, outlen); + + + + + Setsockopt Interface + + In addition to the read/recv and send/write system call handling + to send and retrieve data subject to the cipher operation, a consumer + also needs to set the additional information for the cipher operation. + This additional information is set using the setsockopt system call + that must be invoked with the file descriptor of the open cipher + (i.e. the file descriptor returned by the accept system call). + + + + Each setsockopt invocation must use the level SOL_ALG. + + + + The setsockopt interface allows setting the following data using + the mentioned optname: + + + + + + ALG_SET_KEY -- Setting the key. Key setting is applicable to: + + + + the skcipher cipher type (symmetric ciphers) + + + the hash cipher type (keyed message digests) + + + the AEAD cipher type + + + the RNG cipher type to provide the seed + + + + + + + ALG_SET_AEAD_AUTHSIZE -- Setting the authentication tag size + for AEAD ciphers. For a encryption operation, the authentication + tag of the given size will be generated. For a decryption operation, + the provided ciphertext is assumed to contain an authentication tag + of the given size (see section about AEAD memory layout below). + + + + + + + User space API example + + Please see [1] for libkcapi which provides an easy-to-use wrapper + around the aforementioned Netlink kernel interface. [1] also contains + a test application that invokes all libkcapi API calls. + + + + [1] http://www.chronox.de/libkcapi.html + + + + + + Programming Interface Block Cipher Context Data Structures !Pinclude/linux/crypto.h Block Cipher Context Data Structures diff --git a/Documentation/crypto/crypto-API-userspace.txt b/Documentation/crypto/crypto-API-userspace.txt deleted file mode 100644 index ac619cd90300..000000000000 --- a/Documentation/crypto/crypto-API-userspace.txt +++ /dev/null @@ -1,205 +0,0 @@ -Introduction -============ - -The concepts of the kernel crypto API visible to kernel space is fully -applicable to the user space interface as well. Therefore, the kernel crypto API -high level discussion for the in-kernel use cases applies here as well. - -The major difference, however, is that user space can only act as a consumer -and never as a provider of a transformation or cipher algorithm. - -The following covers the user space interface exported by the kernel crypto -API. A working example of this description is libkcapi that can be obtained from -[1]. That library can be used by user space applications that require -cryptographic services from the kernel. - -Some details of the in-kernel kernel crypto API aspects do not -apply to user space, however. This includes the difference between synchronous -and asynchronous invocations. The user space API call is fully synchronous. -In addition, only a subset of all cipher types are available as documented -below. - - -User space API general remarks -============================== - -The kernel crypto API is accessible from user space. Currently, the following -ciphers are accessible: - - * Message digest including keyed message digest (HMAC, CMAC) - - * Symmetric ciphers - -Note, AEAD ciphers are currently not supported via the symmetric cipher -interface. - -The interface is provided via Netlink using the type AF_ALG. In addition, the -setsockopt option type is SOL_ALG. In case the user space header files do not -export these flags yet, use the following macros: - -#ifndef AF_ALG -#define AF_ALG 38 -#endif -#ifndef SOL_ALG -#define SOL_ALG 279 -#endif - -A cipher is accessed with the same name as done for the in-kernel API calls. -This includes the generic vs. unique naming schema for ciphers as well as the -enforcement of priorities for generic names. - -To interact with the kernel crypto API, a Netlink socket must be created by -the user space application. User space invokes the cipher operation with the -send/write system call family. The result of the cipher operation is obtained -with the read/recv system call family. - -The following API calls assume that the Netlink socket descriptor is already -opened by the user space application and discusses only the kernel crypto API -specific invocations. - -To initialize a Netlink interface, the following sequence has to be performed -by the consumer: - - 1. Create a socket of type AF_ALG with the struct sockaddr_alg parameter - specified below for the different cipher types. - - 2. Invoke bind with the socket descriptor - - 3. Invoke accept with the socket descriptor. The accept system call - returns a new file descriptor that is to be used to interact with - the particular cipher instance. When invoking send/write or recv/read - system calls to send data to the kernel or obtain data from the - kernel, the file descriptor returned by accept must be used. - -In-place cipher operation -========================= - -Just like the in-kernel operation of the kernel crypto API, the user space -interface allows the cipher operation in-place. That means that the input buffer -used for the send/write system call and the output buffer used by the read/recv -system call may be one and the same. This is of particular interest for -symmetric cipher operations where a copying of the output data to its final -destination can be avoided. - -If a consumer on the other hand wants to maintain the plaintext and the -ciphertext in different memory locations, all a consumer needs to do is to -provide different memory pointers for the encryption and decryption operation. - -Message digest API -================== - -The message digest type to be used for the cipher operation is selected when -invoking the bind syscall. bind requires the caller to provide a filled -struct sockaddr data structure. This data structure must be filled as follows: - -struct sockaddr_alg sa = { - .salg_family = AF_ALG, - .salg_type = "hash", /* this selects the hash logic in the kernel */ - .salg_name = "sha1" /* this is the cipher name */ -}; - -The salg_type value "hash" applies to message digests and keyed message digests. -Though, a keyed message digest is referenced by the appropriate salg_name. -Please see below for the setsockopt interface that explains how the key can be -set for a keyed message digest. - -Using the send() system call, the application provides the data that should be -processed with the message digest. The send system call allows the following -flags to be specified: - - * MSG_MORE: If this flag is set, the send system call acts like a - message digest update function where the final hash is not - yet calculated. If the flag is not set, the send system call - calculates the final message digest immediately. - -With the recv() system call, the application can read the message digest from -the kernel crypto API. If the buffer is too small for the message digest, the -flag MSG_TRUNC is set by the kernel. - -In order to set a message digest key, the calling application must use the -setsockopt() option of ALG_SET_KEY. If the key is not set the HMAC operation is -performed without the initial HMAC state change caused by the key. - - -Symmetric cipher API -==================== - -The operation is very similar to the message digest discussion. During -initialization, the struct sockaddr data structure must be filled as follows: - -struct sockaddr_alg sa = { - .salg_family = AF_ALG, - .salg_type = "skcipher", /* this selects the symmetric cipher */ - .salg_name = "cbc(aes)" /* this is the cipher name */ -}; - -Before data can be sent to the kernel using the write/send system call family, -the consumer must set the key. The key setting is described with the setsockopt -invocation below. - -Using the sendmsg() system call, the application provides the data that should -be processed for encryption or decryption. In addition, the IV is specified -with the data structure provided by the sendmsg() system call. - -The sendmsg system call parameter of struct msghdr is embedded into the -struct cmsghdr data structure. See recv(2) and cmsg(3) for more information -on how the cmsghdr data structure is used together with the send/recv system -call family. That cmsghdr data structure holds the following information -specified with a separate header instances: - - * specification of the cipher operation type with one of these flags: - ALG_OP_ENCRYPT - encryption of data - ALG_OP_DECRYPT - decryption of data - - * specification of the IV information marked with the flag ALG_SET_IV - -The send system call family allows the following flag to be specified: - - * MSG_MORE: If this flag is set, the send system call acts like a - cipher update function where more input data is expected - with a subsequent invocation of the send system call. - -Note: The kernel reports -EINVAL for any unexpected data. The caller must -make sure that all data matches the constraints given in /proc/crypto for the -selected cipher. - -With the recv() system call, the application can read the result of the -cipher operation from the kernel crypto API. The output buffer must be at least -as large as to hold all blocks of the encrypted or decrypted data. If the output -data size is smaller, only as many blocks are returned that fit into that -output buffer size. - -Setsockopt interface -==================== - -In addition to the read/recv and send/write system call handling to send and -retrieve data subject to the cipher operation, a consumer also needs to set -the additional information for the cipher operation. This additional information -is set using the setsockopt system call that must be invoked with the file -descriptor of the open cipher (i.e. the file descriptor returned by the -accept system call). - -Each setsockopt invocation must use the level SOL_ALG. - -The setsockopt interface allows setting the following data using the mentioned -optname: - - * ALG_SET_KEY -- Setting the key. Key setting is applicable to: - - - the skcipher cipher type (symmetric ciphers) - - - the hash cipher type (keyed message digests) - -User space API example -====================== - -Please see [1] for libkcapi which provides an easy-to-use wrapper around the -aforementioned Netlink kernel interface. [1] also contains a test application -that invokes all libkcapi API calls. - -[1] http://www.chronox.de/libkcapi.html - -Author -====== - -Stephan Mueller -- cgit v1.2.3-59-g8ed1b From d24fc643b5cfb4fdb0d1bd569e1a2e128c0bf311 Mon Sep 17 00:00:00 2001 From: Angelo Compagnucci Date: Sun, 8 Mar 2015 14:36:58 +0100 Subject: iio: ti-adc128s052: Add DT binding documentation Adding binding documentation for Texas Instruments' ADC128S052 ADC chip. Signed-off-by: Angelo Compagnucci Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/adc/ti-adc128s052.txt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/ti-adc128s052.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/iio/adc/ti-adc128s052.txt b/Documentation/devicetree/bindings/iio/adc/ti-adc128s052.txt new file mode 100644 index 000000000000..42ca7deec97d --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/ti-adc128s052.txt @@ -0,0 +1,18 @@ +* Texas Instruments' ADC128S052 ADC chip + +Required properties: + - compatible: Should be "ti,adc128s052" + - reg: spi chip select number for the device + - vref-supply: The regulator supply for ADC reference voltage + +Recommended properties: + - spi-max-frequency: Definition as per + Documentation/devicetree/bindings/spi/spi-bus.txt + +Example: +adc@0 { + compatible = "ti,adc128s052"; + reg = <0>; + vref-supply = <&vdd_supply>; + spi-max-frequency = <1000000>; +}; -- cgit v1.2.3-59-g8ed1b From 4a428bf3d92385f27cbb15bef90754027ba4f2d9 Mon Sep 17 00:00:00 2001 From: Angelo Compagnucci Date: Sun, 8 Mar 2015 14:37:23 +0100 Subject: iio: mcp3422: Add DT binding documentation Adding binding documentation for ADC MCP3422. Signed-off-by: Angelo Compagnucci Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/adc/mcp3422.txt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/mcp3422.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/iio/adc/mcp3422.txt b/Documentation/devicetree/bindings/iio/adc/mcp3422.txt new file mode 100644 index 000000000000..333139cc0bfb --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/mcp3422.txt @@ -0,0 +1,17 @@ +* Microchip mcp3422/3/4/6/7/8 chip family (ADC) + +Required properties: + - compatible: Should be + "microchip,mcp3422" or + "microchip,mcp3423" or + "microchip,mcp3424" or + "microchip,mcp3426" or + "microchip,mcp3427" or + "microchip,mcp3428" + - reg: I2C address for the device + +Example: +adc@0 { + compatible = "microchip,mcp3424"; + reg = <0x68>; +}; -- cgit v1.2.3-59-g8ed1b From d1bd4867b0959d5221dc528ccf60c8534aae865d Mon Sep 17 00:00:00 2001 From: Martin Fuzzey Date: Thu, 19 Feb 2015 15:16:04 +0100 Subject: iio: doc: Describe scale attributes for event thresholds Signed-off-by: Martin Fuzzey Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 9a70c31619ea..923070934228 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -661,6 +661,24 @@ Description: value is in raw device units or in processed units (as _raw and _input do on sysfs direct channel read attributes). +What: /sys/.../events/in_accel_scale +What: /sys/.../events/in_accel_peak_scale +What: /sys/.../events/in_anglvel_scale +What: /sys/.../events/in_magn_scale +What: /sys/.../events/in_rot_from_north_magnetic_scale +What: /sys/.../events/in_rot_from_north_true_scale +What: /sys/.../events/in_voltage_scale +What: /sys/.../events/in_voltage_supply_scale +What: /sys/.../events/in_temp_scale +What: /sys/.../events/in_illuminance_scale +What: /sys/.../events/in_proximity_scale +KernelVersion: 3.21 +Contact: linux-iio@vger.kernel.org +Description: + Specifies the conversion factor from the standard units + to device specific units used to set the event trigger + threshold. + What: /sys/.../events/in_accel_x_thresh_rising_hysteresis What: /sys/.../events/in_accel_x_thresh_falling_hysteresis What: /sys/.../events/in_accel_x_thresh_either_hysteresis -- cgit v1.2.3-59-g8ed1b From 39521090e93671c01fbc50d47b6422c2b0aa63b1 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Wed, 4 Mar 2015 11:50:29 +0800 Subject: gpio: mrvl: documentation: trivial: fix typo fix typo in the document. Signed-off-by: Josh Wu Signed-off-by: Linus Walleij --- Documentation/devicetree/bindings/gpio/mrvl-gpio.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt b/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt index 67a2e4e414a5..98d198396956 100644 --- a/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt +++ b/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt @@ -12,7 +12,7 @@ Required properties: gpio_mux. - interrupt-names : Should be the names of irq resources. Each interrupt uses its own interrupt name, so there should be as many interrupt names - as referenced interrups. + as referenced interrupts. - interrupt-controller : Identifies the node as an interrupt controller. - #interrupt-cells: Specifies the number of cells needed to encode an interrupt source. -- cgit v1.2.3-59-g8ed1b From de3b696542d3e0fb897149680821dae480c314af Mon Sep 17 00:00:00 2001 From: Rojhalat Ibrahim Date: Thu, 5 Mar 2015 14:36:36 +0100 Subject: extend documentation for gpiod_set_array() functions Extend the documentation for the gpiod_set_array() functions and elaborate a bit on possible use cases. Signed-off-by: Rojhalat Ibrahim Signed-off-by: Linus Walleij --- Documentation/gpio/consumer.txt | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'Documentation') diff --git a/Documentation/gpio/consumer.txt b/Documentation/gpio/consumer.txt index d29a9725c9e5..c21c1313f09e 100644 --- a/Documentation/gpio/consumer.txt +++ b/Documentation/gpio/consumer.txt @@ -259,6 +259,26 @@ GPIOs belonging to the same bank or chip simultaneously if supported by the corresponding chip driver. In that case a significantly improved performance can be expected. If simultaneous setting is not possible the GPIOs will be set sequentially. + +The gpiod_set_array() functions take three arguments: + * array_size - the number of array elements + * desc_array - an array of GPIO descriptors + * value_array - an array of values to assign to the GPIOs + +The descriptor array can be obtained using the gpiod_get_array() function +or one of its variants. If the group of descriptors returned by that function +matches the desired group of GPIOs, those GPIOs can be set by simply using +the struct gpio_descs returned by gpiod_get_array(): + + struct gpio_descs *my_gpio_descs = gpiod_get_array(...); + gpiod_set_array(my_gpio_descs->ndescs, my_gpio_descs->desc, + my_gpio_values); + +It is also possible to set a completely arbitrary array of descriptors. The +descriptors may be obtained using any combination of gpiod_get() and +gpiod_get_array(). Afterwards the array of descriptors has to be setup +manually before it can be used with gpiod_set_array(). + Note that for optimal performance GPIOs belonging to the same chip should be contiguous within the array of descriptors. -- cgit v1.2.3-59-g8ed1b From 7bc32d298b0b597a0a8a6527c9929fac68524d4a Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 17 Jan 2015 14:10:24 -0800 Subject: hwmon: (it87) Add support for IT8781F IT8781F is mostly compatible to IT8782F. Major difference is that it only supports four instead of six UART channels, and therefore does not share the uart6 pins. Reviewed-by: Jean Delvare Signed-off-by: Guenter Roeck --- Documentation/hwmon/it87 | 22 +++++++++++++--------- drivers/hwmon/Kconfig | 4 ++-- drivers/hwmon/it87.c | 32 ++++++++++++++++++++++++-------- 3 files changed, 39 insertions(+), 19 deletions(-) (limited to 'Documentation') diff --git a/Documentation/hwmon/it87 b/Documentation/hwmon/it87 index fe80e9adebfa..8e192fff10f4 100644 --- a/Documentation/hwmon/it87 +++ b/Documentation/hwmon/it87 @@ -42,6 +42,10 @@ Supported chips: Prefix: 'it8772' Addresses scanned: from Super I/O config space (8 I/O ports) Datasheet: Not publicly available + * IT8781F + Prefix: 'it8781' + Addresses scanned: from Super I/O config space (8 I/O ports) + Datasheet: Not publicly available * IT8782F Prefix: 'it8782' Addresses scanned: from Super I/O config space (8 I/O ports) @@ -96,7 +100,7 @@ Description This driver implements support for the IT8603E, IT8623E, IT8705F, IT8712F, IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E, IT8771E, -IT8772E, IT8782F, IT8783E/F, and SiS950 chips. +IT8772E, IT8781F, IT8782F, IT8783E/F, and SiS950 chips. These chips are 'Super I/O chips', supporting floppy disks, infrared ports, joysticks and other miscellaneous stuff. For hardware monitoring, they @@ -120,11 +124,11 @@ The IT8716F, IT8718F, IT8720F, IT8721F/IT8758E and later IT8712F revisions have support for 2 additional fans. The additional fans are supported by the driver. -The IT8716F, IT8718F, IT8720F, IT8721F/IT8758E, IT8782F, IT8783E/F, and late -IT8712F and IT8705F also have optional 16-bit tachometer counters for fans 1 to -3. This is better (no more fan clock divider mess) but not compatible with the -older chips and revisions. The 16-bit tachometer mode is enabled by the driver -when one of the above chips is detected. +The IT8716F, IT8718F, IT8720F, IT8721F/IT8758E, IT8781F, IT8782F, IT8783E/F, +and late IT8712F and IT8705F also have optional 16-bit tachometer counters +for fans 1 to 3. This is better (no more fan clock divider mess) but not +compatible with the older chips and revisions. The 16-bit tachometer mode +is enabled by the driver when one of the above chips is detected. The IT8726F is just bit enhanced IT8716F with additional hardware for AMD power sequencing. Therefore the chip will appear as IT8716F @@ -156,10 +160,10 @@ inputs can measure voltages between 0 and 4.08 volts, with a resolution of 0.016 volt (except IT8603E, IT8721F/IT8758E and IT8728F: 0.012 volt.) The battery voltage in8 does not have limit registers. -On the IT8603E, IT8721F/IT8758E, IT8782F, and IT8783E/F, some voltage inputs -are internal and scaled inside the chip: +On the IT8603E, IT8721F/IT8758E, IT8781F, IT8782F, and IT8783E/F, some +voltage inputs are internal and scaled inside the chip: * in3 (optional) -* in7 (optional for IT8782F and IT8783E/F) +* in7 (optional for IT8781F, IT8782F, and IT8783E/F) * in8 (always) * in9 (relevant for IT8603E only) The driver handles this transparently so user-space doesn't have to care. diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 110fade9cb74..f5fc54e24fea 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -599,8 +599,8 @@ config SENSORS_IT87 help If you say yes here you get support for ITE IT8705F, IT8712F, IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E, - IT8771E, IT8772E, IT8782F, IT8783E/F and IT8603E sensor chips, - and the SiS950 clone. + IT8771E, IT8772E, IT8781F, IT8782F, IT8783E/F and IT8603E + sensor chips, and the SiS950 clone. This driver can also be built as a module. If so, the module will be called it87. diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index 409116c52cc5..ed25e4bab978 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -23,6 +23,7 @@ * IT8758E Super I/O chip w/LPC interface * IT8771E Super I/O chip w/LPC interface * IT8772E Super I/O chip w/LPC interface + * IT8781F Super I/O chip w/LPC interface * IT8782F Super I/O chip w/LPC interface * IT8783E/F Super I/O chip w/LPC interface * Sis950 A clone of the IT8705F @@ -66,7 +67,7 @@ #define DRVNAME "it87" enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8771, - it8772, it8782, it8783, it8603 }; + it8772, it8781, it8782, it8783, it8603 }; static unsigned short force_id; module_param(force_id, ushort, 0); @@ -146,6 +147,7 @@ static inline void superio_exit(void) #define IT8728F_DEVID 0x8728 #define IT8771E_DEVID 0x8771 #define IT8772E_DEVID 0x8772 +#define IT8781F_DEVID 0x8781 #define IT8782F_DEVID 0x8782 #define IT8783E_DEVID 0x8783 #define IT8603E_DEVID 0x8603 @@ -307,6 +309,12 @@ static const struct it87_devices it87_devices[] = { /* 16 bit fans (HWSensors4, OHM) */ .peci_mask = 0x07, }, + [it8781] = { + .name = "it8781", + .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET + | FEAT_TEMP_OLD_PECI, + .old_peci_mask = 0x4, + }, [it8782] = { .name = "it8782", .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET @@ -1761,6 +1769,9 @@ static int __init it87_find(unsigned short *address, case IT8772E_DEVID: sio_data->type = it8772; break; + case IT8781F_DEVID: + sio_data->type = it8781; + break; case IT8782F_DEVID: sio_data->type = it8782; break; @@ -1919,10 +1930,11 @@ static int __init it87_find(unsigned short *address, reg = superio_inb(IT87_SIO_GPIO3_REG); if (sio_data->type == it8721 || sio_data->type == it8728 || sio_data->type == it8771 || sio_data->type == it8772 || - sio_data->type == it8782) { + sio_data->type == it8781 || sio_data->type == it8782) { /* - * IT8721F/IT8758E, and IT8782F don't have VID pins - * at all, not sure about the IT8728F and compatibles. + * IT8721F/IT8758E, IT8728F, IT8772F, IT8781F, and + * IT8782F don't have VID pins at all, not sure about + * the IT8771F. */ sio_data->skip_vid = 1; } else { @@ -2147,7 +2159,8 @@ static int it87_probe(struct platform_device *pdev) data->in_scaled |= (1 << 8); /* in8 is Vbat */ if (sio_data->internal & (1 << 3)) data->in_scaled |= (1 << 9); /* in9 is AVCC */ - } else if (sio_data->type == it8782 || sio_data->type == it8783) { + } else if (sio_data->type == it8781 || sio_data->type == it8782 || + sio_data->type == it8783) { if (sio_data->internal & (1 << 0)) data->in_scaled |= (1 << 3); /* in3 is VCC5V */ if (sio_data->internal & (1 << 1)) @@ -2460,9 +2473,12 @@ static void it87_init_device(struct platform_device *pdev) it87_write_value(data, IT87_REG_FAN_16BIT, tmp | 0x07); } - /* IT8705F, IT8782F, and IT8783E/F only support three fans. */ - if (data->type != it87 && data->type != it8782 && - data->type != it8783) { + /* + * IT8705F, IT8781F, IT8782F, and IT8783E/F only support + * three fans. + */ + if (data->type != it87 && data->type != it8781 && + data->type != it8782 && data->type != it8783) { if (tmp & (1 << 4)) data->has_fan |= (1 << 3); /* fan4 enabled */ if (tmp & (1 << 5)) -- cgit v1.2.3-59-g8ed1b From 0ea2f1db8e6888029b781bbaf68547e2e0996402 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 1 Feb 2015 17:20:38 -0800 Subject: hwmon: (jc42) Add support for additional IDT temperature sensors TS3000GB0 has a new device ID (0x2913). Since IDT's datasheets suggest that the upper 8 bit of the device ID reflect the chip ID and the lower 8 bit reflect the version number, modify the code to accept all chips with ID 0x29xx. Also add support for TS3001 and TSE2004. Some of the datasheets for older chips are no longer available from the IDT web site, so replace explicit links in the documentation with a generic note. Reviewed-by: Jean Delvare Signed-off-by: Guenter Roeck --- Documentation/hwmon/jc42 | 8 +++----- drivers/hwmon/Kconfig | 2 +- drivers/hwmon/jc42.c | 16 ++++++++++------ 3 files changed, 14 insertions(+), 12 deletions(-) (limited to 'Documentation') diff --git a/Documentation/hwmon/jc42 b/Documentation/hwmon/jc42 index f3893f7440de..f7f1830a2566 100644 --- a/Documentation/hwmon/jc42 +++ b/Documentation/hwmon/jc42 @@ -11,12 +11,10 @@ Supported chips: http://www.atmel.com/Images/doc8711.pdf http://www.atmel.com/Images/Atmel-8852-SEEPROM-AT30TSE002A-Datasheet.pdf http://www.atmel.com/Images/Atmel-8868-DTS-AT30TSE004A-Datasheet.pdf - * IDT TSE2002B3, TSE2002GB2, TS3000B3, TS3000GB2 + * IDT TSE2002B3, TSE2002GB2, TSE2004GB2, TS3000B3, TS3000GB0, TS3000GB2, + TS3001GB2 Datasheets: - http://www.idt.com/sites/default/files/documents/IDT_TSE2002B3C_DST_20100512_120303152056.pdf - http://www.idt.com/sites/default/files/documents/IDT_TSE2002GB2A1_DST_20111107_120303145914.pdf - http://www.idt.com/sites/default/files/documents/IDT_TS3000B3A_DST_20101129_120303152013.pdf - http://www.idt.com/sites/default/files/documents/IDT_TS3000GB2A1_DST_20111104_120303151012.pdf + Available from IDT web site * Maxim MAX6604 Datasheets: http://datasheets.maxim-ic.com/en/ds/MAX6604.pdf diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index f5fc54e24fea..e96c0ebaaceb 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -624,7 +624,7 @@ config SENSORS_JC42 mobile devices and servers. Support will include, but not be limited to, ADT7408, AT30TS00, CAT34TS02, CAT6095, MAX6604, MCP9804, MCP9805, MCP98242, MCP98243, MCP98244, MCP9843, SE97, SE98, STTS424(E), - STTS2002, STTS3000, TSE2002B3, TSE2002GB2, TS3000B3, and TS3000GB2. + STTS2002, STTS3000, TSE2002, TSE2004, TS3000, and TS3001. This driver can also be built as a module. If so, the module will be called jc42. diff --git a/drivers/hwmon/jc42.c b/drivers/hwmon/jc42.c index 996bdfd5cf25..9887d3224a86 100644 --- a/drivers/hwmon/jc42.c +++ b/drivers/hwmon/jc42.c @@ -87,11 +87,14 @@ static const unsigned short normal_i2c[] = { #define AT30TSE004_DEVID_MASK 0xffff /* IDT */ -#define TS3000B3_DEVID 0x2903 /* Also matches TSE2002B3 */ -#define TS3000B3_DEVID_MASK 0xffff +#define TSE2004_DEVID 0x2200 +#define TSE2004_DEVID_MASK 0xff00 -#define TS3000GB2_DEVID 0x2912 /* Also matches TSE2002GB2 */ -#define TS3000GB2_DEVID_MASK 0xffff +#define TS3000_DEVID 0x2900 /* Also matches TSE2002 */ +#define TS3000_DEVID_MASK 0xff00 + +#define TS3001_DEVID 0x3000 +#define TS3001_DEVID_MASK 0xff00 /* Maxim */ #define MAX6604_DEVID 0x3e00 @@ -152,8 +155,9 @@ static struct jc42_chips jc42_chips[] = { { ADT_MANID, ADT7408_DEVID, ADT7408_DEVID_MASK }, { ATMEL_MANID, AT30TS00_DEVID, AT30TS00_DEVID_MASK }, { ATMEL_MANID2, AT30TSE004_DEVID, AT30TSE004_DEVID_MASK }, - { IDT_MANID, TS3000B3_DEVID, TS3000B3_DEVID_MASK }, - { IDT_MANID, TS3000GB2_DEVID, TS3000GB2_DEVID_MASK }, + { IDT_MANID, TSE2004_DEVID, TSE2004_DEVID_MASK }, + { IDT_MANID, TS3000_DEVID, TS3000_DEVID_MASK }, + { IDT_MANID, TS3001_DEVID, TS3001_DEVID_MASK }, { MAX_MANID, MAX6604_DEVID, MAX6604_DEVID_MASK }, { MCP_MANID, MCP9804_DEVID, MCP9804_DEVID_MASK }, { MCP_MANID, MCP98242_DEVID, MCP98242_DEVID_MASK }, -- cgit v1.2.3-59-g8ed1b From a0c1424acb16326d9b741be8db7a3e776fc28b19 Mon Sep 17 00:00:00 2001 From: Thomas Lorblanches Date: Fri, 13 Feb 2015 13:19:06 +0100 Subject: hwmon: (it87) Add support for IT8786E IT8786E is mostly compatible with IT8771 / IT8772. Parameters determined by testing various combinations. Reviewed-by: Jean Delvare Signed-off-by: Thomas Lorblanches [Guenter Roeck: merged from github, addressed review comments] Signed-off-by: Guenter Roeck --- Documentation/hwmon/it87 | 6 +++++- drivers/hwmon/Kconfig | 4 ++-- drivers/hwmon/it87.c | 22 ++++++++++++++++------ 3 files changed, 23 insertions(+), 9 deletions(-) (limited to 'Documentation') diff --git a/Documentation/hwmon/it87 b/Documentation/hwmon/it87 index 8e192fff10f4..19fbe775ae10 100644 --- a/Documentation/hwmon/it87 +++ b/Documentation/hwmon/it87 @@ -54,6 +54,10 @@ Supported chips: Prefix: 'it8783' Addresses scanned: from Super I/O config space (8 I/O ports) Datasheet: Not publicly available + * IT8786E + Prefix: 'it8786' + Addresses scanned: from Super I/O config space (8 I/O ports) + Datasheet: Not publicly available * SiS950 [clone of IT8705F] Prefix: 'it87' Addresses scanned: from Super I/O config space (8 I/O ports) @@ -100,7 +104,7 @@ Description This driver implements support for the IT8603E, IT8623E, IT8705F, IT8712F, IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E, IT8771E, -IT8772E, IT8781F, IT8782F, IT8783E/F, and SiS950 chips. +IT8772E, IT8781F, IT8782F, IT8783E/F, IT8786E, and SiS950 chips. These chips are 'Super I/O chips', supporting floppy disks, infrared ports, joysticks and other miscellaneous stuff. For hardware monitoring, they diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index e96c0ebaaceb..4b40ea79b20f 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -599,8 +599,8 @@ config SENSORS_IT87 help If you say yes here you get support for ITE IT8705F, IT8712F, IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E, - IT8771E, IT8772E, IT8781F, IT8782F, IT8783E/F and IT8603E - sensor chips, and the SiS950 clone. + IT8771E, IT8772E, IT8781F, IT8782F, IT8783E/F, IT8786E, + and IT8603E sensor chips, and the SiS950 clone. This driver can also be built as a module. If so, the module will be called it87. diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index 9ca10a73aee8..691067bbe07c 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -26,6 +26,7 @@ * IT8781F Super I/O chip w/LPC interface * IT8782F Super I/O chip w/LPC interface * IT8783E/F Super I/O chip w/LPC interface + * IT8786E Super I/O chip w/LPC interface * Sis950 A clone of the IT8705F * * Copyright (C) 2001 Chris Gauthron @@ -67,7 +68,7 @@ #define DRVNAME "it87" enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8771, - it8772, it8781, it8782, it8783, it8603 }; + it8772, it8781, it8782, it8783, it8786, it8603 }; static unsigned short force_id; module_param(force_id, ushort, 0); @@ -150,6 +151,7 @@ static inline void superio_exit(void) #define IT8781F_DEVID 0x8781 #define IT8782F_DEVID 0x8782 #define IT8783E_DEVID 0x8783 +#define IT8786E_DEVID 0x8786 #define IT8603E_DEVID 0x8603 #define IT8623E_DEVID 0x8623 #define IT87_ACT_REG 0x30 @@ -335,6 +337,12 @@ static const struct it87_devices it87_devices[] = { | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG, .old_peci_mask = 0x4, }, + [it8786] = { + .name = "it8786", + .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS + | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI, + .peci_mask = 0x07, + }, [it8603] = { .name = "it8603", .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS @@ -1789,6 +1797,9 @@ static int __init it87_find(unsigned short *address, case IT8783E_DEVID: sio_data->type = it8783; break; + case IT8786E_DEVID: + sio_data->type = it8786; + break; case IT8603E_DEVID: case IT8623E_DEVID: sio_data->type = it8603; @@ -1816,8 +1827,8 @@ static int __init it87_find(unsigned short *address, sio_data->revision = superio_inb(DEVREV) & 0x0f; pr_info("Found IT%04x%c chip at 0x%x, revision %d\n", chip_type, chip_type == 0x8771 || chip_type == 0x8772 || - chip_type == 0x8603 ? 'E' : 'F', *address, - sio_data->revision); + chip_type == 0x8786 || chip_type == 0x8603 ? 'E' : 'F', + *address, sio_data->revision); /* in8 (Vbat) is always internal */ sio_data->internal = (1 << 2); @@ -1987,9 +1998,8 @@ static int __init it87_find(unsigned short *address, if (reg & (1 << 0)) sio_data->internal |= (1 << 0); if ((reg & (1 << 1)) || sio_data->type == it8721 || - sio_data->type == it8728 || - sio_data->type == it8771 || - sio_data->type == it8772) + sio_data->type == it8728 || sio_data->type == it8771 || + sio_data->type == it8772 || sio_data->type == it8786) sio_data->internal |= (1 << 1); /* -- cgit v1.2.3-59-g8ed1b From 9c947d25c96ec93485d60f7b783403d518c1418d Mon Sep 17 00:00:00 2001 From: "Vadim V. Vlasov" Date: Fri, 27 Feb 2015 16:16:00 +0300 Subject: hwmon: Add Nuvoton NCT7904 hwmon driver The NCT7904D is a hardware monitor supporting up to 20 voltage sensors, internal temperature sensor, Intel PECI and AMD SB-TSI CPU temperature interface, up to 12 fan tachometer inputs, up to 4 fan control channels with SmartFan. Signed-off-by: Vadim V. Vlasov [Guenter Roeck: Fixed whitespace errors, dropped redundant comment] Signed-off-by: Guenter Roeck --- Documentation/hwmon/nct7904 | 60 +++++ drivers/hwmon/Kconfig | 10 + drivers/hwmon/Makefile | 1 + drivers/hwmon/nct7904.c | 592 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 663 insertions(+) create mode 100644 Documentation/hwmon/nct7904 create mode 100644 drivers/hwmon/nct7904.c (limited to 'Documentation') diff --git a/Documentation/hwmon/nct7904 b/Documentation/hwmon/nct7904 new file mode 100644 index 000000000000..014f112e2a14 --- /dev/null +++ b/Documentation/hwmon/nct7904 @@ -0,0 +1,60 @@ +Kernel driver nct7904 +==================== + +Supported chip: + * Nuvoton NCT7904D + Prefix: nct7904 + Addresses: I2C 0x2d, 0x2e + Datasheet: Publicly available at Nuvoton website + http://www.nuvoton.com/ + +Author: Vadim V. Vlasov + + +Description +----------- + +The NCT7904D is a hardware monitor supporting up to 20 voltage sensors, +internal temperature sensor, Intel PECI and AMD SB-TSI CPU temperature +interface, up to 12 fan tachometer inputs, up to 4 fan control channels +with SmartFan. + + +Sysfs entries +------------- + +Currently, the driver supports only the following features: + +in[1-20]_input Input voltage measurements (mV) + +fan[1-12]_input Fan tachometer measurements (rpm) + +temp1_input Local temperature (1/1000 degree, + 0.125 degree resolution) + +temp[2-9]_input CPU temperatures (1/1000 degree, + 0.125 degree resolution) + +fan[1-4]_mode R/W, 0/1 for manual or SmartFan mode + Setting SmartFan mode is supported only if it has been + previously configured by BIOS (or configuration EEPROM) + +fan[1-4]_pwm R/O in SmartFan mode, R/W in manual control mode + +The driver checks sensor control registers and does not export the sensors +that are not enabled. Anyway, a sensor that is enabled may actually be not +connected and thus provide zero readings. + + +Limitations +----------- + +The following features are not supported in current version: + + - SmartFan control + - Watchdog + - GPIO + - external temperature sensors + - SMI + - min/max values + - many other... diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 4b40ea79b20f..2a5dd697c142 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1145,6 +1145,16 @@ config SENSORS_NCT7802 This driver can also be built as a module. If so, the module will be called nct7802. +config SENSORS_NCT7904 + tristate "Nuvoton NCT7904" + depends on I2C + help + If you say yes here you get support for the Nuvoton NCT7904 + hardware monitoring chip, including manual fan speed control. + + This driver can also be built as a module. If so, the module + will be called nct7904. + config SENSORS_PCF8591 tristate "Philips PCF8591 ADC/DAC" depends on I2C diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 6c941472e707..b4a40f17e2aa 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -120,6 +120,7 @@ obj-$(CONFIG_SENSORS_MENF21BMC_HWMON) += menf21bmc_hwmon.o obj-$(CONFIG_SENSORS_NCT6683) += nct6683.o obj-$(CONFIG_SENSORS_NCT6775) += nct6775.o obj-$(CONFIG_SENSORS_NCT7802) += nct7802.o +obj-$(CONFIG_SENSORS_NCT7904) += nct7904.o obj-$(CONFIG_SENSORS_NTC_THERMISTOR) += ntc_thermistor.o obj-$(CONFIG_SENSORS_PC87360) += pc87360.o obj-$(CONFIG_SENSORS_PC87427) += pc87427.o diff --git a/drivers/hwmon/nct7904.c b/drivers/hwmon/nct7904.c new file mode 100644 index 000000000000..eaa8234e21d0 --- /dev/null +++ b/drivers/hwmon/nct7904.c @@ -0,0 +1,592 @@ +/* + * nct7904.c - driver for Nuvoton NCT7904D. + * + * Copyright (c) 2015 Kontron + * Author: Vadim V. Vlasov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define VENDOR_ID_REG 0x7A /* Any bank */ +#define NUVOTON_ID 0x50 +#define CHIP_ID_REG 0x7B /* Any bank */ +#define NCT7904_ID 0xC5 +#define DEVICE_ID_REG 0x7C /* Any bank */ + +#define BANK_SEL_REG 0xFF +#define BANK_0 0x00 +#define BANK_1 0x01 +#define BANK_2 0x02 +#define BANK_3 0x03 +#define BANK_4 0x04 +#define BANK_MAX 0x04 + +#define FANIN_MAX 12 /* Counted from 1 */ +#define VSEN_MAX 21 /* VSEN1..14, 3VDD, VBAT, V3VSB, + LTD (not a voltage), VSEN17..19 */ +#define FANCTL_MAX 4 /* Counted from 1 */ +#define TCPU_MAX 8 /* Counted from 1 */ +#define TEMP_MAX 4 /* Counted from 1 */ + +#define VT_ADC_CTRL0_REG 0x20 /* Bank 0 */ +#define VT_ADC_CTRL1_REG 0x21 /* Bank 0 */ +#define VT_ADC_CTRL2_REG 0x22 /* Bank 0 */ +#define FANIN_CTRL0_REG 0x24 +#define FANIN_CTRL1_REG 0x25 +#define DTS_T_CTRL0_REG 0x26 +#define DTS_T_CTRL1_REG 0x27 +#define VT_ADC_MD_REG 0x2E + +#define VSEN1_HV_REG 0x40 /* Bank 0; 2 regs (HV/LV) per sensor */ +#define TEMP_CH1_HV_REG 0x42 /* Bank 0; same as VSEN2_HV */ +#define LTD_HV_REG 0x62 /* Bank 0; 2 regs in VSEN range */ +#define FANIN1_HV_REG 0x80 /* Bank 0; 2 regs (HV/LV) per sensor */ +#define T_CPU1_HV_REG 0xA0 /* Bank 0; 2 regs (HV/LV) per sensor */ + +#define PRTS_REG 0x03 /* Bank 2 */ +#define FANCTL1_FMR_REG 0x00 /* Bank 3; 1 reg per channel */ +#define FANCTL1_OUT_REG 0x10 /* Bank 3; 1 reg per channel */ + +static const unsigned short normal_i2c[] = { + 0x2d, 0x2e, I2C_CLIENT_END +}; + +struct nct7904_data { + struct i2c_client *client; + struct mutex bank_lock; + int bank_sel; + u32 fanin_mask; + u32 vsen_mask; + u32 tcpu_mask; + u8 fan_mode[FANCTL_MAX]; +}; + +/* Access functions */ +static int nct7904_bank_lock(struct nct7904_data *data, unsigned bank) +{ + int ret; + + mutex_lock(&data->bank_lock); + if (data->bank_sel == bank) + return 0; + ret = i2c_smbus_write_byte_data(data->client, BANK_SEL_REG, bank); + if (ret == 0) + data->bank_sel = bank; + else + data->bank_sel = -1; + return ret; +} + +static inline void nct7904_bank_release(struct nct7904_data *data) +{ + mutex_unlock(&data->bank_lock); +} + +/* Read 1-byte register. Returns unsigned reg or -ERRNO on error. */ +static int nct7904_read_reg(struct nct7904_data *data, + unsigned bank, unsigned reg) +{ + struct i2c_client *client = data->client; + int ret; + + ret = nct7904_bank_lock(data, bank); + if (ret == 0) + ret = i2c_smbus_read_byte_data(client, reg); + + nct7904_bank_release(data); + return ret; +} + +/* + * Read 2-byte register. Returns register in big-endian format or + * -ERRNO on error. + */ +static int nct7904_read_reg16(struct nct7904_data *data, + unsigned bank, unsigned reg) +{ + struct i2c_client *client = data->client; + int ret, hi; + + ret = nct7904_bank_lock(data, bank); + if (ret == 0) { + ret = i2c_smbus_read_byte_data(client, reg); + if (ret >= 0) { + hi = ret; + ret = i2c_smbus_read_byte_data(client, reg + 1); + if (ret >= 0) + ret |= hi << 8; + } + } + + nct7904_bank_release(data); + return ret; +} + +/* Write 1-byte register. Returns 0 or -ERRNO on error. */ +static int nct7904_write_reg(struct nct7904_data *data, + unsigned bank, unsigned reg, u8 val) +{ + struct i2c_client *client = data->client; + int ret; + + ret = nct7904_bank_lock(data, bank); + if (ret == 0) + ret = i2c_smbus_write_byte_data(client, reg, val); + + nct7904_bank_release(data); + return ret; +} + +/* FANIN ATTR */ +static ssize_t show_fan(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct nct7904_data *data = dev_get_drvdata(dev); + int ret; + unsigned cnt, rpm; + + ret = nct7904_read_reg16(data, BANK_0, FANIN1_HV_REG + index * 2); + if (ret < 0) + return ret; + cnt = ((ret & 0xff00) >> 3) | (ret & 0x1f); + if (cnt == 0x1fff) + rpm = 0; + else + rpm = 1350000 / cnt; + return sprintf(buf, "%u\n", rpm); +} + +static umode_t nct7904_fanin_is_visible(struct kobject *kobj, + struct attribute *a, int n) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct nct7904_data *data = dev_get_drvdata(dev); + + if (data->fanin_mask & (1 << n)) + return a->mode; + return 0; +} + +static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0); +static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1); +static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2); +static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3); +static SENSOR_DEVICE_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 4); +static SENSOR_DEVICE_ATTR(fan6_input, S_IRUGO, show_fan, NULL, 5); +static SENSOR_DEVICE_ATTR(fan7_input, S_IRUGO, show_fan, NULL, 6); +static SENSOR_DEVICE_ATTR(fan8_input, S_IRUGO, show_fan, NULL, 7); +static SENSOR_DEVICE_ATTR(fan9_input, S_IRUGO, show_fan, NULL, 8); +static SENSOR_DEVICE_ATTR(fan10_input, S_IRUGO, show_fan, NULL, 9); +static SENSOR_DEVICE_ATTR(fan11_input, S_IRUGO, show_fan, NULL, 10); +static SENSOR_DEVICE_ATTR(fan12_input, S_IRUGO, show_fan, NULL, 11); + +static struct attribute *nct7904_fanin_attrs[] = { + &sensor_dev_attr_fan1_input.dev_attr.attr, + &sensor_dev_attr_fan2_input.dev_attr.attr, + &sensor_dev_attr_fan3_input.dev_attr.attr, + &sensor_dev_attr_fan4_input.dev_attr.attr, + &sensor_dev_attr_fan5_input.dev_attr.attr, + &sensor_dev_attr_fan6_input.dev_attr.attr, + &sensor_dev_attr_fan7_input.dev_attr.attr, + &sensor_dev_attr_fan8_input.dev_attr.attr, + &sensor_dev_attr_fan9_input.dev_attr.attr, + &sensor_dev_attr_fan10_input.dev_attr.attr, + &sensor_dev_attr_fan11_input.dev_attr.attr, + &sensor_dev_attr_fan12_input.dev_attr.attr, + NULL +}; + +static const struct attribute_group nct7904_fanin_group = { + .attrs = nct7904_fanin_attrs, + .is_visible = nct7904_fanin_is_visible, +}; + +/* VSEN ATTR */ +static ssize_t show_voltage(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct nct7904_data *data = dev_get_drvdata(dev); + int ret; + int volt; + + ret = nct7904_read_reg16(data, BANK_0, VSEN1_HV_REG + index * 2); + if (ret < 0) + return ret; + volt = ((ret & 0xff00) >> 5) | (ret & 0x7); + if (index < 14) + volt *= 2; /* 0.002V scale */ + else + volt *= 6; /* 0.006V scale */ + + return sprintf(buf, "%d\n", volt); +} + +static ssize_t show_ltemp(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct nct7904_data *data = dev_get_drvdata(dev); + int ret; + int temp; + + ret = nct7904_read_reg16(data, BANK_0, LTD_HV_REG); + if (ret < 0) + return ret; + temp = ((ret & 0xff00) >> 5) | (ret & 0x7); + temp = sign_extend32(temp, 10) * 125; + + return sprintf(buf, "%d\n", temp); +} + +static umode_t nct7904_vsen_is_visible(struct kobject *kobj, + struct attribute *a, int n) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct nct7904_data *data = dev_get_drvdata(dev); + + if (data->vsen_mask & (1 << n)) + return a->mode; + return 0; +} + +static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_voltage, NULL, 0); +static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_voltage, NULL, 1); +static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_voltage, NULL, 2); +static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_voltage, NULL, 3); +static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_voltage, NULL, 4); +static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_voltage, NULL, 5); +static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, show_voltage, NULL, 6); +static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, show_voltage, NULL, 7); +static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, show_voltage, NULL, 8); +static SENSOR_DEVICE_ATTR(in10_input, S_IRUGO, show_voltage, NULL, 9); +static SENSOR_DEVICE_ATTR(in11_input, S_IRUGO, show_voltage, NULL, 10); +static SENSOR_DEVICE_ATTR(in12_input, S_IRUGO, show_voltage, NULL, 11); +static SENSOR_DEVICE_ATTR(in13_input, S_IRUGO, show_voltage, NULL, 12); +static SENSOR_DEVICE_ATTR(in14_input, S_IRUGO, show_voltage, NULL, 13); +/* + * Next 3 voltage sensors have specific names in the Nuvoton doc + * (3VDD, VBAT, 3VSB) but we use vacant numbers for them. + */ +static SENSOR_DEVICE_ATTR(in15_input, S_IRUGO, show_voltage, NULL, 14); +static SENSOR_DEVICE_ATTR(in16_input, S_IRUGO, show_voltage, NULL, 15); +static SENSOR_DEVICE_ATTR(in20_input, S_IRUGO, show_voltage, NULL, 16); +/* This is not a voltage, but a local temperature sensor. */ +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_ltemp, NULL, 0); +static SENSOR_DEVICE_ATTR(in17_input, S_IRUGO, show_voltage, NULL, 18); +static SENSOR_DEVICE_ATTR(in18_input, S_IRUGO, show_voltage, NULL, 19); +static SENSOR_DEVICE_ATTR(in19_input, S_IRUGO, show_voltage, NULL, 20); + +static struct attribute *nct7904_vsen_attrs[] = { + &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_in2_input.dev_attr.attr, + &sensor_dev_attr_in3_input.dev_attr.attr, + &sensor_dev_attr_in4_input.dev_attr.attr, + &sensor_dev_attr_in5_input.dev_attr.attr, + &sensor_dev_attr_in6_input.dev_attr.attr, + &sensor_dev_attr_in7_input.dev_attr.attr, + &sensor_dev_attr_in8_input.dev_attr.attr, + &sensor_dev_attr_in9_input.dev_attr.attr, + &sensor_dev_attr_in10_input.dev_attr.attr, + &sensor_dev_attr_in11_input.dev_attr.attr, + &sensor_dev_attr_in12_input.dev_attr.attr, + &sensor_dev_attr_in13_input.dev_attr.attr, + &sensor_dev_attr_in14_input.dev_attr.attr, + &sensor_dev_attr_in15_input.dev_attr.attr, + &sensor_dev_attr_in16_input.dev_attr.attr, + &sensor_dev_attr_in20_input.dev_attr.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_in17_input.dev_attr.attr, + &sensor_dev_attr_in18_input.dev_attr.attr, + &sensor_dev_attr_in19_input.dev_attr.attr, + NULL +}; + +static const struct attribute_group nct7904_vsen_group = { + .attrs = nct7904_vsen_attrs, + .is_visible = nct7904_vsen_is_visible, +}; + +/* CPU_TEMP ATTR */ +static ssize_t show_tcpu(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct nct7904_data *data = dev_get_drvdata(dev); + int ret; + int temp; + + ret = nct7904_read_reg16(data, BANK_0, T_CPU1_HV_REG + index * 2); + if (ret < 0) + return ret; + + temp = ((ret & 0xff00) >> 5) | (ret & 0x7); + temp = sign_extend32(temp, 10) * 125; + return sprintf(buf, "%d\n", temp); +} + +static umode_t nct7904_tcpu_is_visible(struct kobject *kobj, + struct attribute *a, int n) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct nct7904_data *data = dev_get_drvdata(dev); + + if (data->tcpu_mask & (1 << n)) + return a->mode; + return 0; +} + +/* "temp1_input" reserved for local temp */ +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_tcpu, NULL, 0); +static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_tcpu, NULL, 1); +static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_tcpu, NULL, 2); +static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, show_tcpu, NULL, 3); +static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO, show_tcpu, NULL, 4); +static SENSOR_DEVICE_ATTR(temp7_input, S_IRUGO, show_tcpu, NULL, 5); +static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO, show_tcpu, NULL, 6); +static SENSOR_DEVICE_ATTR(temp9_input, S_IRUGO, show_tcpu, NULL, 7); + +static struct attribute *nct7904_tcpu_attrs[] = { + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp3_input.dev_attr.attr, + &sensor_dev_attr_temp4_input.dev_attr.attr, + &sensor_dev_attr_temp5_input.dev_attr.attr, + &sensor_dev_attr_temp6_input.dev_attr.attr, + &sensor_dev_attr_temp7_input.dev_attr.attr, + &sensor_dev_attr_temp8_input.dev_attr.attr, + &sensor_dev_attr_temp9_input.dev_attr.attr, + NULL +}; + +static const struct attribute_group nct7904_tcpu_group = { + .attrs = nct7904_tcpu_attrs, + .is_visible = nct7904_tcpu_is_visible, +}; + +/* PWM ATTR */ +static ssize_t store_pwm(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct nct7904_data *data = dev_get_drvdata(dev); + unsigned long val; + int ret; + + if (kstrtoul(buf, 10, &val) < 0) + return -EINVAL; + if (val > 255) + return -EINVAL; + + ret = nct7904_write_reg(data, BANK_3, FANCTL1_OUT_REG + index, val); + + return ret ? ret : count; +} + +static ssize_t show_pwm(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct nct7904_data *data = dev_get_drvdata(dev); + int val; + + val = nct7904_read_reg(data, BANK_3, FANCTL1_OUT_REG + index); + if (val < 0) + return val; + + return sprintf(buf, "%d\n", val); +} + +static ssize_t store_mode(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct nct7904_data *data = dev_get_drvdata(dev); + unsigned long val; + int ret; + + if (kstrtoul(buf, 10, &val) < 0) + return -EINVAL; + if (val > 1 || (val && !data->fan_mode[index])) + return -EINVAL; + + ret = nct7904_write_reg(data, BANK_3, FANCTL1_FMR_REG + index, + val ? data->fan_mode[index] : 0); + + return ret ? ret : count; +} + +/* Return 0 for manual mode or 1 for SmartFan mode */ +static ssize_t show_mode(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct nct7904_data *data = dev_get_drvdata(dev); + int val; + + val = nct7904_read_reg(data, BANK_3, FANCTL1_FMR_REG + index); + if (val < 0) + return val; + + return sprintf(buf, "%d\n", val ? 1 : 0); +} + +/* 2 attributes per channel: pwm and mode */ +static SENSOR_DEVICE_ATTR(fan1_pwm, S_IRUGO | S_IWUSR, + show_pwm, store_pwm, 0); +static SENSOR_DEVICE_ATTR(fan1_mode, S_IRUGO | S_IWUSR, + show_mode, store_mode, 0); +static SENSOR_DEVICE_ATTR(fan2_pwm, S_IRUGO | S_IWUSR, + show_pwm, store_pwm, 1); +static SENSOR_DEVICE_ATTR(fan2_mode, S_IRUGO | S_IWUSR, + show_mode, store_mode, 1); +static SENSOR_DEVICE_ATTR(fan3_pwm, S_IRUGO | S_IWUSR, + show_pwm, store_pwm, 2); +static SENSOR_DEVICE_ATTR(fan3_mode, S_IRUGO | S_IWUSR, + show_mode, store_mode, 2); +static SENSOR_DEVICE_ATTR(fan4_pwm, S_IRUGO | S_IWUSR, + show_pwm, store_pwm, 3); +static SENSOR_DEVICE_ATTR(fan4_mode, S_IRUGO | S_IWUSR, + show_mode, store_mode, 3); + +static struct attribute *nct7904_fanctl_attrs[] = { + &sensor_dev_attr_fan1_pwm.dev_attr.attr, + &sensor_dev_attr_fan1_mode.dev_attr.attr, + &sensor_dev_attr_fan2_pwm.dev_attr.attr, + &sensor_dev_attr_fan2_mode.dev_attr.attr, + &sensor_dev_attr_fan3_pwm.dev_attr.attr, + &sensor_dev_attr_fan3_mode.dev_attr.attr, + &sensor_dev_attr_fan4_pwm.dev_attr.attr, + &sensor_dev_attr_fan4_mode.dev_attr.attr, + NULL +}; + +static const struct attribute_group nct7904_fanctl_group = { + .attrs = nct7904_fanctl_attrs, +}; + +static const struct attribute_group *nct7904_groups[] = { + &nct7904_fanin_group, + &nct7904_vsen_group, + &nct7904_tcpu_group, + &nct7904_fanctl_group, + NULL +}; + +/* Return 0 if detection is successful, -ENODEV otherwise */ +static int nct7904_detect(struct i2c_client *client, + struct i2c_board_info *info) +{ + struct i2c_adapter *adapter = client->adapter; + + if (!i2c_check_functionality(adapter, + I2C_FUNC_SMBUS_READ_BYTE | + I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) + return -ENODEV; + + /* Determine the chip type. */ + if (i2c_smbus_read_byte_data(client, VENDOR_ID_REG) != NUVOTON_ID || + i2c_smbus_read_byte_data(client, CHIP_ID_REG) != NCT7904_ID || + (i2c_smbus_read_byte_data(client, DEVICE_ID_REG) & 0xf0) != 0x50) + return -ENODEV; + + strlcpy(info->type, "nct7904", I2C_NAME_SIZE); + + return 0; +} + +static int nct7904_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct nct7904_data *data; + struct device *hwmon_dev; + struct device *dev = &client->dev; + int ret, i; + u32 mask; + + data = devm_kzalloc(dev, sizeof(struct nct7904_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->client = client; + mutex_init(&data->bank_lock); + data->bank_sel = -1; + + /* Setup sensor groups. */ + /* FANIN attributes */ + ret = nct7904_read_reg16(data, BANK_0, FANIN_CTRL0_REG); + if (ret < 0) + return ret; + data->fanin_mask = (ret >> 8) | ((ret & 0xff) << 8); + + /* + * VSEN attributes + * + * Note: voltage sensors overlap with external temperature + * sensors. So, if we ever decide to support the latter + * we will have to adjust 'vsen_mask' accordingly. + */ + mask = 0; + ret = nct7904_read_reg16(data, BANK_0, VT_ADC_CTRL0_REG); + if (ret >= 0) + mask = (ret >> 8) | ((ret & 0xff) << 8); + ret = nct7904_read_reg(data, BANK_0, VT_ADC_CTRL2_REG); + if (ret >= 0) + mask |= (ret << 16); + data->vsen_mask = mask; + + /* CPU_TEMP attributes */ + ret = nct7904_read_reg16(data, BANK_0, DTS_T_CTRL0_REG); + if (ret < 0) + return ret; + data->tcpu_mask = ((ret >> 8) & 0xf) | ((ret & 0xf) << 4); + + for (i = 0; i < FANCTL_MAX; i++) { + ret = nct7904_read_reg(data, BANK_3, FANCTL1_FMR_REG + i); + if (ret < 0) + return ret; + data->fan_mode[i] = ret; + } + + hwmon_dev = + devm_hwmon_device_register_with_groups(dev, client->name, data, + nct7904_groups); + return PTR_ERR_OR_ZERO(hwmon_dev); +} + +static const struct i2c_device_id nct7904_id[] = { + {"nct7904", 0}, + {} +}; + +static struct i2c_driver nct7904_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "nct7904", + }, + .probe = nct7904_probe, + .id_table = nct7904_id, + .detect = nct7904_detect, + .address_list = normal_i2c, +}; + +module_i2c_driver(nct7904_driver); + +MODULE_AUTHOR("Vadim V. Vlasov "); +MODULE_DESCRIPTION("Hwmon driver for NUVOTON NCT7904"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-59-g8ed1b From 73ef85f42da2df8b567fea109c67ed53db937bcc Mon Sep 17 00:00:00 2001 From: Simon Guinot Date: Wed, 25 Feb 2015 18:58:19 +0100 Subject: hwmon: (gpio-fan) allow to use alarm support alone from DT On some boards, such as the LaCie 2Big Network v2 or 2Big NAS (based on Marvell Kirkwood SoCs), an I2C fan controller is used but the alarm signal is wired to a separate GPIO. Unfortunately, the gpio-fan driver can't be used to handle GPIO alarm alone from DT: an error is returned if the "gpios" DT property is missing. This patch allows to use the gpio-fan driver even if the "alarm-gpios" DT property is defined alone. Signed-off-by: Simon Guinot Signed-off-by: Guenter Roeck --- .../devicetree/bindings/gpio/gpio-fan.txt | 6 ++- drivers/hwmon/gpio-fan.c | 44 +++++++++++----------- 2 files changed, 27 insertions(+), 23 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/gpio/gpio-fan.txt b/Documentation/devicetree/bindings/gpio/gpio-fan.txt index 2dd457a3469a..f996d428f132 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-fan.txt +++ b/Documentation/devicetree/bindings/gpio/gpio-fan.txt @@ -2,16 +2,18 @@ Bindings for fan connected to GPIO lines Required properties: - compatible : "gpio-fan" + +Optional properties: - gpios: Specifies the pins that map to bits in the control value, ordered MSB-->LSB. - gpio-fan,speed-map: A mapping of possible fan RPM speeds and the control value that should be set to achieve them. This array must have the RPM values in ascending order. - -Optional properties: - alarm-gpios: This pin going active indicates something is wrong with the fan, and a udev event will be fired. +Note: At least one the "gpios" or "alarm-gpios" properties must be set. + Examples: gpio_fan { diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c index 36abf814b8c7..c241f5b0b7cf 100644 --- a/drivers/hwmon/gpio-fan.c +++ b/drivers/hwmon/gpio-fan.c @@ -404,10 +404,32 @@ static int gpio_fan_get_of_pdata(struct device *dev, node = dev->of_node; + /* Alarm GPIO if one exists */ + if (of_gpio_named_count(node, "alarm-gpios") > 0) { + struct gpio_fan_alarm *alarm; + int val; + enum of_gpio_flags flags; + + alarm = devm_kzalloc(dev, sizeof(struct gpio_fan_alarm), + GFP_KERNEL); + if (!alarm) + return -ENOMEM; + + val = of_get_named_gpio_flags(node, "alarm-gpios", 0, &flags); + if (val < 0) + return val; + alarm->gpio = val; + alarm->active_low = flags & OF_GPIO_ACTIVE_LOW; + + pdata->alarm = alarm; + } + /* Fill GPIO pin array */ pdata->num_ctrl = of_gpio_count(node); if (pdata->num_ctrl <= 0) { - dev_err(dev, "gpios DT property empty / missing"); + if (pdata->alarm) + return 0; + dev_err(dev, "DT properties empty / missing"); return -ENODEV; } ctrl = devm_kzalloc(dev, pdata->num_ctrl * sizeof(unsigned), @@ -460,26 +482,6 @@ static int gpio_fan_get_of_pdata(struct device *dev, } pdata->speed = speed; - /* Alarm GPIO if one exists */ - if (of_gpio_named_count(node, "alarm-gpios") > 0) { - struct gpio_fan_alarm *alarm; - int val; - enum of_gpio_flags flags; - - alarm = devm_kzalloc(dev, sizeof(struct gpio_fan_alarm), - GFP_KERNEL); - if (!alarm) - return -ENOMEM; - - val = of_get_named_gpio_flags(node, "alarm-gpios", 0, &flags); - if (val < 0) - return val; - alarm->gpio = val; - alarm->active_low = flags & OF_GPIO_ACTIVE_LOW; - - pdata->alarm = alarm; - } - return 0; } -- cgit v1.2.3-59-g8ed1b From b5cf88e46badea6d600d8515edea23814e03444d Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Thu, 8 Jan 2015 12:05:03 -0600 Subject: (gpio-fan): Add thermal control hooks Allow gpio-fan to be used as thermal cooling device for platforms that use GPIO maps to control fans. As part of this change, we make the shutdown and remove logic the same as well. Signed-off-by: Nishanth Menon Acked-by: Eduardo Valentin Signed-off-by: Guenter Roeck --- .../devicetree/bindings/gpio/gpio-fan.txt | 13 ++++ drivers/hwmon/gpio-fan.c | 83 ++++++++++++++++++++-- 2 files changed, 89 insertions(+), 7 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/gpio/gpio-fan.txt b/Documentation/devicetree/bindings/gpio/gpio-fan.txt index f996d428f132..439a7430fc68 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-fan.txt +++ b/Documentation/devicetree/bindings/gpio/gpio-fan.txt @@ -11,6 +11,9 @@ Optional properties: must have the RPM values in ascending order. - alarm-gpios: This pin going active indicates something is wrong with the fan, and a udev event will be fired. +- cooling-cells: If used as a cooling device, must be <2> + Also see: Documentation/devicetree/bindings/thermal/thermal.txt + min and max states are derived from the speed-map of the fan. Note: At least one the "gpios" or "alarm-gpios" properties must be set. @@ -25,3 +28,13 @@ Examples: 6000 2>; alarm-gpios = <&gpio1 15 1>; }; + gpio_fan_cool: gpio_fan { + compatible = "gpio-fan"; + gpios = <&gpio2 14 1 + &gpio2 13 1>; + gpio-fan,speed-map = <0 0>, + <3000 1>, + <6000 2>; + alarm-gpios = <&gpio2 15 1>; + #cooling-cells = <2>; /* min followed by max */ + }; diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c index c241f5b0b7cf..632b8e3ff5bf 100644 --- a/drivers/hwmon/gpio-fan.c +++ b/drivers/hwmon/gpio-fan.c @@ -34,10 +34,13 @@ #include #include #include +#include struct gpio_fan_data { struct platform_device *pdev; struct device *hwmon_dev; + /* Cooling device if any */ + struct thermal_cooling_device *cdev; struct mutex lock; /* lock GPIOs operations. */ int num_ctrl; unsigned *ctrl; @@ -387,6 +390,53 @@ static int fan_ctrl_init(struct gpio_fan_data *fan_data, return 0; } +static int gpio_fan_get_max_state(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + struct gpio_fan_data *fan_data = cdev->devdata; + + if (!fan_data) + return -EINVAL; + + *state = fan_data->num_speed - 1; + return 0; +} + +static int gpio_fan_get_cur_state(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + struct gpio_fan_data *fan_data = cdev->devdata; + int r; + + if (!fan_data) + return -EINVAL; + + r = get_fan_speed_index(fan_data); + if (r < 0) + return r; + + *state = r; + return 0; +} + +static int gpio_fan_set_cur_state(struct thermal_cooling_device *cdev, + unsigned long state) +{ + struct gpio_fan_data *fan_data = cdev->devdata; + + if (!fan_data) + return -EINVAL; + + set_fan_speed(fan_data, state); + return 0; +} + +static const struct thermal_cooling_device_ops gpio_fan_cool_ops = { + .get_max_state = gpio_fan_get_max_state, + .get_cur_state = gpio_fan_get_cur_state, + .set_cur_state = gpio_fan_set_cur_state, +}; + #ifdef CONFIG_OF_GPIO /* * Translate OpenFirmware node properties into platform_data @@ -497,6 +547,11 @@ static int gpio_fan_probe(struct platform_device *pdev) struct gpio_fan_data *fan_data; struct gpio_fan_platform_data *pdata = dev_get_platdata(&pdev->dev); + fan_data = devm_kzalloc(&pdev->dev, sizeof(struct gpio_fan_data), + GFP_KERNEL); + if (!fan_data) + return -ENOMEM; + #ifdef CONFIG_OF_GPIO if (!pdata) { pdata = devm_kzalloc(&pdev->dev, @@ -508,17 +563,20 @@ static int gpio_fan_probe(struct platform_device *pdev) err = gpio_fan_get_of_pdata(&pdev->dev, pdata); if (err) return err; + /* Optional cooling device register for Device tree platforms */ + fan_data->cdev = + thermal_of_cooling_device_register(pdev->dev.of_node, + "gpio-fan", fan_data, + &gpio_fan_cool_ops); } #else /* CONFIG_OF_GPIO */ if (!pdata) return -EINVAL; + /* Optional cooling device register for non Device tree platforms */ + fan_data->cdev = thermal_cooling_device_register("gpio-fan", fan_data, + &gpio_fan_cool_ops); #endif /* CONFIG_OF_GPIO */ - fan_data = devm_kzalloc(&pdev->dev, sizeof(struct gpio_fan_data), - GFP_KERNEL); - if (!fan_data) - return -ENOMEM; - fan_data->pdev = pdev; platform_set_drvdata(pdev, fan_data); mutex_init(&fan_data->lock); @@ -552,12 +610,22 @@ static int gpio_fan_probe(struct platform_device *pdev) return 0; } -static void gpio_fan_shutdown(struct platform_device *pdev) +static int gpio_fan_remove(struct platform_device *pdev) { - struct gpio_fan_data *fan_data = dev_get_drvdata(&pdev->dev); + struct gpio_fan_data *fan_data = platform_get_drvdata(pdev); + + if (!IS_ERR(fan_data->cdev)) + thermal_cooling_device_unregister(fan_data->cdev); if (fan_data->ctrl) set_fan_speed(fan_data, 0); + + return 0; +} + +static void gpio_fan_shutdown(struct platform_device *pdev) +{ + gpio_fan_remove(pdev); } #ifdef CONFIG_PM_SLEEP @@ -591,6 +659,7 @@ static SIMPLE_DEV_PM_OPS(gpio_fan_pm, gpio_fan_suspend, gpio_fan_resume); static struct platform_driver gpio_fan_driver = { .probe = gpio_fan_probe, + .remove = gpio_fan_remove, .shutdown = gpio_fan_shutdown, .driver = { .name = "gpio-fan", -- cgit v1.2.3-59-g8ed1b From af033612351b1850492ed7edbdbab4f9a869266f Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Tue, 3 Mar 2015 15:41:06 +0100 Subject: devicetree: bindings: add Device Tree bindings for Armada 39x pin-muxing controller This commit adds the Device Tree binding documentation to describe the pin-muxing controller of the Marvell Armada 39x processors. Two variants are supported for the moment: the 88F6920 (Armada 390) and 88F6928 (Armada 398). Signed-off-by: Thomas Petazzoni Signed-off-by: Linus Walleij --- .../pinctrl/marvell,armada-39x-pinctrl.txt | 78 ++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 Documentation/devicetree/bindings/pinctrl/marvell,armada-39x-pinctrl.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/pinctrl/marvell,armada-39x-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/marvell,armada-39x-pinctrl.txt new file mode 100644 index 000000000000..5b1a9dc004f4 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/marvell,armada-39x-pinctrl.txt @@ -0,0 +1,78 @@ +* Marvell Armada 39x SoC pinctrl driver for mpp + +Please refer to marvell,mvebu-pinctrl.txt in this directory for common binding +part and usage. + +Required properties: +- compatible: "marvell,88f6920-pinctrl", "marvell,88f6928-pinctrl" + depending on the specific variant of the SoC being used. +- reg: register specifier of MPP registers + +Available mpp pins/groups and functions: +Note: brackets (x) are not part of the mpp name for marvell,function and given +only for more detailed description in this document. + +name pins functions +================================================================================ +mpp0 0 gpio, ua0(rxd) +mpp1 1 gpio, ua0(txd) +mpp2 2 gpio, i2c0(sck) +mpp3 3 gpio, i2c0(sda) +mpp4 4 gpio, ua1(txd), ua0(rts), smi(mdc) +mpp5 5 gpio, ua1(rxd), ua0(cts), smi(mdio) +mpp6 6 gpio, dev(cs3), xsmi(mdio) +mpp7 7 gpio, dev(ad9), xsmi(mdc) +mpp8 8 gpio, dev(ad10), ptp(trig) +mpp9 9 gpio, dev(ad11), ptp(clk) +mpp10 10 gpio, dev(ad12), ptp(event) +mpp11 11 gpio, dev(ad13), led(clk) +mpp12 12 gpio, pcie0(rstout), dev(ad14), led(stb) +mpp13 13 gpio, dev(ad15), led(data) +mpp14 14 gpio, m(vtt), dev(wen1), ua1(txd) +mpp15 15 gpio, pcie0(rstout), spi0(mosi), i2c1(sck) +mpp16 16 gpio, m(decc), spi0(miso), i2c1(sda) +mpp17 17 gpio, ua1(rxd), spi0(sck), smi(mdio) +mpp18 18 gpio, ua1(txd), spi0(cs0), i2c2(sck) +mpp19 19 gpio, sata1(present) [1], ua0(cts), ua1(rxd), i2c2(sda) +mpp20 20 gpio, sata0(present) [1], ua0(rts), ua1(txd), smi(mdc) +mpp21 21 gpio, spi0(cs1), sata0(present) [1], sd(cmd), dev(bootcs), ge(rxd0) +mpp22 22 gpio, spi0(mosi), dev(ad0) +mpp23 23 gpio, spi0(sck), dev(ad2) +mpp24 24 gpio, spi0(miso), ua0(cts), ua1(rxd), sd(d4), dev(readyn) +mpp25 25 gpio, spi0(cs0), ua0(rts), ua1(txd), sd(d5), dev(cs0) +mpp26 26 gpio, spi0(cs2), i2c1(sck), sd(d6), dev(cs1) +mpp27 27 gpio, spi0(cs3), i2c1(sda), sd(d7), dev(cs2), ge(txclkout) +mpp28 28 gpio, sd(clk), dev(ad5), ge(txd0) +mpp29 29 gpio, dev(ale0), ge(txd1) +mpp30 30 gpio, dev(oen), ge(txd2) +mpp31 31 gpio, dev(ale1), ge(txd3) +mpp32 32 gpio, dev(wen0), ge(txctl) +mpp33 33 gpio, m(decc), dev(ad3) +mpp34 34 gpio, dev(ad1) +mpp35 35 gpio, ref(clk), dev(a1) +mpp36 36 gpio, dev(a0) +mpp37 37 gpio, sd(d3), dev(ad8), ge(rxclk) +mpp38 38 gpio, ref(clk), sd(d0), dev(ad4), ge(rxd1) +mpp39 39 gpio, i2c1(sck), ua0(cts), sd(d1), dev(a2), ge(rxd2) +mpp40 40 gpio, i2c1(sda), ua0(rts), sd(d2), dev(ad6), ge(rxd3) +mpp41 41 gpio, ua1(rxd), ua0(cts), spi1(cs3), dev(burstn), nd(rbn0), ge(rxctl) +mpp42 42 gpio, ua1(txd), ua0(rts), dev(ad7) +mpp43 43 gpio, pcie0(clkreq), m(vtt), m(decc), spi1(cs2), dev(clkout), nd(rbn1) +mpp44 44 gpio, sata0(present) [1], sata1(present) [1], led(clk) +mpp45 45 gpio, ref(clk), pcie0(rstout), ua1(rxd) +mpp46 46 gpio, ref(clk), pcie0(rstout), ua1(txd), led(stb) +mpp47 47 gpio, sata0(present) [1], sata1(present) [1], led(data) +mpp48 48 gpio, sata0(present) [1], m(vtt), tdm(pclk) [1], audio(mclk) [1], sd(d4), pcie0(clkreq), ua1(txd) +mpp49 49 gpio, tdm(fsync) [1], audio(lrclk) [1], sd(d5), ua2(rxd) +mpp50 50 gpio, pcie0(rstout), tdm(drx) [1], audio(extclk) [1], sd(cmd), ua2(rxd) +mpp51 51 gpio, tdm(dtx) [1], audio(sdo) [1], m(decc), ua2(txd) +mpp52 52 gpio, pcie0(rstout), tdm(intn) [1], audio(sdi) [1], sd(d6), i2c3(sck) +mpp53 53 gpio, sata1(present) [1], sata0(present) [1], tdm(rstn) [1], audio(bclk) [1], sd(d7), i2c3(sda) +mpp54 54 gpio, sata0(present) [1], sata1(present) [1], pcie0(rstout), sd(d3), ua3(txd) +mpp55 55 gpio, ua1(cts), spi1(cs1), sd(d0), ua1(rxd), ua3(rxd) +mpp56 56 gpio, ua1(rts), m(decc), spi1(mosi), ua1(txd) +mpp57 57 gpio, spi1(sck), sd(clk), ua1(txd) +mpp58 58 gpio, i2c1(sck), pcie2(clkreq), spi1(miso), sd(d1), ua1(rxd) +mpp59 59 gpio, pcie0(rstout), i2c1(sda), spi1(cs0), sd(d2) + +[1]: only available on 88F6928 -- cgit v1.2.3-59-g8ed1b From 9184f756908ace8213099f21870b07491a7138a9 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Tue, 24 Feb 2015 14:00:51 -0700 Subject: pinctrl: tegra: add a driver for Tegra210 Tegra210's pinmux supports a different set of pins/options than earlier SoCs, so requires its own driver (well, table of pin-specific data). Cc: devicetree@vger.kernel.org Signed-off-by: Stephen Warren Tested-by: Alexandre Courbot Signed-off-by: Linus Walleij --- .../bindings/pinctrl/nvidia,tegra210-pinmux.txt | 166 ++ drivers/pinctrl/Kconfig | 4 + drivers/pinctrl/Makefile | 1 + drivers/pinctrl/pinctrl-tegra210.c | 1588 ++++++++++++++++++++ 4 files changed, 1759 insertions(+) create mode 100644 Documentation/devicetree/bindings/pinctrl/nvidia,tegra210-pinmux.txt create mode 100644 drivers/pinctrl/pinctrl-tegra210.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra210-pinmux.txt b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra210-pinmux.txt new file mode 100644 index 000000000000..a62d82d5fbe9 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra210-pinmux.txt @@ -0,0 +1,166 @@ +NVIDIA Tegra210 pinmux controller + +Required properties: +- compatible: "nvidia,tegra210-pinmux" +- reg: Should contain a list of base address and size pairs for: + - first entry: The APB_MISC_GP_*_PADCTRL registers (pad control) + - second entry: The PINMUX_AUX_* registers (pinmux) + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +Tegra's pin configuration nodes act as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those pin(s)/group(s), and various pin configuration +parameters, such as pull-up, tristate, drive strength, etc. + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Each subnode only affects those parameters that are explicitly listed. In +other words, a subnode that lists a mux function but no pin configuration +parameters implies no information about any pin configuration parameters. +Similarly, a pin subnode that describes a pullup parameter implies no +information about e.g. the mux function or tristate parameter. For this +reason, even seemingly boolean values are actually tristates in this binding: +unspecified, off, or on. Unspecified is represented as an absent property, +and off/on are represented as integer values 0 and 1. + +See the TRM to determine which properties and values apply to each pin/group. +Macro values for property values are defined in +include/dt-binding/pinctrl/pinctrl-tegra.h. + +Required subnode-properties: +- nvidia,pins : An array of strings. Each string contains the name of a pin or + group. Valid values for these names are listed below. + +Optional subnode-properties: +- nvidia,function: A string containing the name of the function to mux to the + pin or group. +- nvidia,pull: Integer, representing the pull-down/up to apply to the pin. + 0: none, 1: down, 2: up. +- nvidia,tristate: Integer. + 0: drive, 1: tristate. +- nvidia,enable-input: Integer. Enable the pin's input path. + enable :TEGRA_PIN_ENABLE0 and + disable or output only: TEGRA_PIN_DISABLE. +- nvidia,open-drain: Integer. + enable: TEGRA_PIN_ENABLE. + disable: TEGRA_PIN_DISABLE. +- nvidia,lock: Integer. Lock the pin configuration against further changes + until reset. + enable: TEGRA_PIN_ENABLE. + disable: TEGRA_PIN_DISABLE. +- nvidia,io-hv: Integer. Select high-voltage receivers. + normal: TEGRA_PIN_DISABLE + high: TEGRA_PIN_ENABLE +- nvidia,high-speed-mode: Integer. Enable high speed mode the pins. + normal: TEGRA_PIN_DISABLE + high: TEGRA_PIN_ENABLE +- nvidia,schmitt: Integer. Enables Schmitt Trigger on the input. + normal: TEGRA_PIN_DISABLE + high: TEGRA_PIN_ENABLE +- nvidia,drive-type: Integer. Valid range 0...3. +- nvidia,pull-down-strength: Integer. Controls drive strength. 0 is weakest. + The range of valid values depends on the pingroup. See "CAL_DRVDN" in the + Tegra TRM. +- nvidia,pull-up-strength: Integer. Controls drive strength. 0 is weakest. + The range of valid values depends on the pingroup. See "CAL_DRVUP" in the + Tegra TRM. +- nvidia,slew-rate-rising: Integer. Controls rising signal slew rate. 0 is + fastest. The range of valid values depends on the pingroup. See + "DRVDN_SLWR" in the Tegra TRM. +- nvidia,slew-rate-falling: Integer. Controls falling signal slew rate. 0 is + fastest. The range of valid values depends on the pingroup. See + "DRVUP_SLWF" in the Tegra TRM. + +Valid values for pin and group names (nvidia,pin) are: + + Mux groups: + + These correspond to Tegra PINMUX_AUX_* (pinmux) registers. Any property + that exists in those registers may be set for the following pin names. + + In Tegra210, many pins also have a dedicated APB_MISC_GP_*_PADCTRL + register. Where that is true, and property that exists in that register + may also be set on the following pin names. + + als_prox_int_px3, ap_ready_pv5, ap_wake_bt_ph3, ap_wake_nfc_ph7, + aud_mclk_pbb0, batt_bcl, bt_rst_ph4, bt_wake_ap_ph5, button_home_py1, + button_power_on_px5, button_slide_sw_py0, button_vol_down_px7, + button_vol_up_px6, cam1_mclk_ps0, cam1_pwdn_ps7, cam1_strobe_pt1, + cam2_mclk_ps1, cam2_pwdn_pt0, cam_af_en_ps5, cam_flash_en_ps6, + cam_i2c_scl_ps2, cam_i2c_sda_ps3, cam_rst_ps4cam_rst_ps4, clk_32k_in, + clk_32k_out_py5, clk_req, core_pwr_req, cpu_pwr_req, dap1_din_pb1, + dap1_dout_pb2, dap1_fs_pb0, dap1_sclk_pb3, dap2_din_paa2, dap2_dout_paa3, + dap2_fs_paa0, dap2_sclk_paa1, dap4_din_pj5, dap4_dout_pj6, dap4_fs_pj4, + dap4_sclk_pj7, dmic1_clk_pe0, dmic1_dat_pe1, dmic2_clk_pe2, dmic2_dat_pe3, + dmic3_clk_pe4, dmic3_dat_pe5, dp_hpd0_pcc6, dvfs_clk_pbb2, dvfs_pwm_pbb1, + gen1_i2c_scl_pj1, gen1_i2c_sda_pj0, gen2_i2c_scl_pj2, gen2_i2c_sda_pj3, + gen3_i2c_scl_pf0, gen3_i2c_sda_pf1, gpio_x1_aud_pbb3, gpio_x3_aud_pbb4, + gps_en_pi2, gps_rst_pi3, hdmi_cec_pcc0, hdmi_int_dp_hpd_pcc1, jtag_rtck, + lcd_bl_en_pv1, lcd_bl_pwm_pv0, lcd_gpio1_pv3, lcd_gpio2_pv4, lcd_rst_pv2, + lcd_te_py2, modem_wake_ap_px0, motion_int_px2, nfc_en_pi0, nfc_int_pi1, + pa6, pcc7, pe6, pe7, pex_l0_clkreq_n_pa1, pex_l0_rst_n_pa0, + pex_l1_clkreq_n_pa4, pex_l1_rst_n_pa3, pex_wake_n_pa2, ph6, pk0, pk1, pk2, + pk3, pk4, pk5, pk6, pk7, pl0, pl1, pwr_i2c_scl_py3, pwr_i2c_sda_py4, + pwr_int_n, pz0, pz1, pz2, pz3, pz4, pz5, qspi_cs_n_pee1, qspi_io0_pee2, + qspi_io1_pee3, qspi_io2_pee4, qspi_io3_pee5, qspi_sck_pee0, + sata_led_active_pa5, sdmmc1_clk_pm0, sdmmc1_cmd_pm1, sdmmc1_dat0_pm5, + sdmmc1_dat1_pm4, sdmmc1_dat2_pm3, sdmmc1_dat3_pm2, sdmmc3_clk_pp0, + sdmmc3_cmd_pp1, sdmmc3_dat0_pp5, sdmmc3_dat1_pp4, sdmmc3_dat2_pp3, + sdmmc3_dat3_pp2, shutdown, spdif_in_pcc3, spdif_out_pcc2, spi1_cs0_pc3, + spi1_cs1_pc4, spi1_miso_pc1, spi1_mosi_pc0, spi1_sck_pc2, spi2_cs0_pb7, + spi2_cs1_pdd0, spi2_miso_pb5, spi2_mosi_pb4, spi2_sck_pb6, spi4_cs0_pc6, + spi4_miso_pd0, spi4_mosi_pc7, spi4_sck_pc5, temp_alert_px4, touch_clk_pv7, + touch_int_px1, touch_rst_pv6, uart1_cts_pu3, uart1_rts_pu2, uart1_rx_pu1, + uart1_tx_pu0, uart2_cts_pg3, uart2_rts_pg2, uart2_rx_pg1, uart2_tx_pg0, + uart3_cts_pd4, uart3_rts_pd3, uart3_rx_pd2, uart3_tx_pd1, uart4_cts_pi7, + uart4_rts_pi6, uart4_rx_pi5, uart4_tx_pi4, usb_vbus_en0_pcc4, + usb_vbus_en1_pcc5, wifi_en_ph0, wifi_rst_ph1, wifi_wake_ap_ph2 + + Drive groups: + + These correspond to the Tegra APB_MISC_GP_*_PADCTRL (pad control) + registers. Note that where one of these registers controls a single pin + for which a PINMUX_AUX_* exists, see the list above for the pin name to + use when configuring the pinmux. + + pa6, pcc7, pe6, pe7, ph6, pk0, pk1, pk2, pk3, pk4, pk5, pk6, pk7, pl0, pl1, + pz0, pz1, pz2, pz3, pz4, pz5, sdmmc1, sdmmc2, sdmmc3, sdmmc4 + +Valid values for nvidia,functions are: + + aud, bcl, blink, ccla, cec, cldvfs, clk, core, cpu, displaya, displayb, + dmic1, dmic2, dmic3, dp, dtv, extperiph3, i2c1, i2c2, i2c3, i2cpmu, i2cvi, + i2s1, i2s2, i2s3, i2s4a, i2s4b, i2s5a, i2s5b, iqc0, iqc1, jtag, pe, pe0, + pe1, pmi, pwm0, pwm1, pwm2, pwm3, qspi, rsvd0, rsvd1, rsvd2, rsvd3, sata, + sdmmc1, sdmmc3, shutdown, soc, sor0, sor1, spdif, spi1, spi2, spi3, spi4, + sys, touch, uart, uarta, uartb, uartc, uartd, usb, vgp1, vgp2, vgp3, vgp4, + vgp5, vgp6, vimclk, vimclk2 + +Example: + + pinmux: pinmux@70000800 { + compatible = "nvidia,tegra210-pinmux"; + reg = <0x0 0x700008d4 0x0 0x2a8>, /* Pad control registers */ + <0x0 0x70003000 0x0 0x1000>; /* Mux registers */ + + pinctrl-names = "boot"; + pinctrl-0 = <&state_boot>; + + state_boot: pinmux { + gen1_i2c_scl_pj1 { + nvidia,pins = "gen1_i2c_scl_pj1", + nvidia,function = "i2c1"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + nvidia,open-drain = ; + nvidia,io-hv = ; + }; + }; + }; +}; diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index ee9f44ad7f02..17b7f6ac8b25 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -154,6 +154,10 @@ config PINCTRL_TEGRA124 bool select PINCTRL_TEGRA +config PINCTRL_TEGRA210 + bool + select PINCTRL_TEGRA + config PINCTRL_TEGRA_XUSB def_bool y if ARCH_TEGRA select GENERIC_PHY diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 0475206dd600..9b4d6c7f4277 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_PINCTRL_TEGRA20) += pinctrl-tegra20.o obj-$(CONFIG_PINCTRL_TEGRA30) += pinctrl-tegra30.o obj-$(CONFIG_PINCTRL_TEGRA114) += pinctrl-tegra114.o obj-$(CONFIG_PINCTRL_TEGRA124) += pinctrl-tegra124.o +obj-$(CONFIG_PINCTRL_TEGRA210) += pinctrl-tegra210.o obj-$(CONFIG_PINCTRL_TEGRA_XUSB) += pinctrl-tegra-xusb.o obj-$(CONFIG_PINCTRL_TZ1090) += pinctrl-tz1090.o obj-$(CONFIG_PINCTRL_TZ1090_PDC) += pinctrl-tz1090-pdc.o diff --git a/drivers/pinctrl/pinctrl-tegra210.c b/drivers/pinctrl/pinctrl-tegra210.c new file mode 100644 index 000000000000..252b464901c0 --- /dev/null +++ b/drivers/pinctrl/pinctrl-tegra210.c @@ -0,0 +1,1588 @@ +/* + * Pinctrl data for the NVIDIA Tegra210 pinmux + * + * Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include +#include +#include +#include +#include + +#include "pinctrl-tegra.h" + +/* + * Most pins affected by the pinmux can also be GPIOs. Define these first. + * These must match how the GPIO driver names/numbers its pins. + */ +#define _GPIO(offset) (offset) + +#define TEGRA_PIN_PEX_L0_RST_N_PA0 _GPIO(0) +#define TEGRA_PIN_PEX_L0_CLKREQ_N_PA1 _GPIO(1) +#define TEGRA_PIN_PEX_WAKE_N_PA2 _GPIO(2) +#define TEGRA_PIN_PEX_L1_RST_N_PA3 _GPIO(3) +#define TEGRA_PIN_PEX_L1_CLKREQ_N_PA4 _GPIO(4) +#define TEGRA_PIN_SATA_LED_ACTIVE_PA5 _GPIO(5) +#define TEGRA_PIN_PA6 _GPIO(6) +#define TEGRA_PIN_DAP1_FS_PB0 _GPIO(8) +#define TEGRA_PIN_DAP1_DIN_PB1 _GPIO(9) +#define TEGRA_PIN_DAP1_DOUT_PB2 _GPIO(10) +#define TEGRA_PIN_DAP1_SCLK_PB3 _GPIO(11) +#define TEGRA_PIN_SPI2_MOSI_PB4 _GPIO(12) +#define TEGRA_PIN_SPI2_MISO_PB5 _GPIO(13) +#define TEGRA_PIN_SPI2_SCK_PB6 _GPIO(14) +#define TEGRA_PIN_SPI2_CS0_PB7 _GPIO(15) +#define TEGRA_PIN_SPI1_MOSI_PC0 _GPIO(16) +#define TEGRA_PIN_SPI1_MISO_PC1 _GPIO(17) +#define TEGRA_PIN_SPI1_SCK_PC2 _GPIO(18) +#define TEGRA_PIN_SPI1_CS0_PC3 _GPIO(19) +#define TEGRA_PIN_SPI1_CS1_PC4 _GPIO(20) +#define TEGRA_PIN_SPI4_SCK_PC5 _GPIO(21) +#define TEGRA_PIN_SPI4_CS0_PC6 _GPIO(22) +#define TEGRA_PIN_SPI4_MOSI_PC7 _GPIO(23) +#define TEGRA_PIN_SPI4_MISO_PD0 _GPIO(24) +#define TEGRA_PIN_UART3_TX_PD1 _GPIO(25) +#define TEGRA_PIN_UART3_RX_PD2 _GPIO(26) +#define TEGRA_PIN_UART3_RTS_PD3 _GPIO(27) +#define TEGRA_PIN_UART3_CTS_PD4 _GPIO(28) +#define TEGRA_PIN_DMIC1_CLK_PE0 _GPIO(32) +#define TEGRA_PIN_DMIC1_DAT_PE1 _GPIO(33) +#define TEGRA_PIN_DMIC2_CLK_PE2 _GPIO(34) +#define TEGRA_PIN_DMIC2_DAT_PE3 _GPIO(35) +#define TEGRA_PIN_DMIC3_CLK_PE4 _GPIO(36) +#define TEGRA_PIN_DMIC3_DAT_PE5 _GPIO(37) +#define TEGRA_PIN_PE6 _GPIO(38) +#define TEGRA_PIN_PE7 _GPIO(39) +#define TEGRA_PIN_GEN3_I2C_SCL_PF0 _GPIO(40) +#define TEGRA_PIN_GEN3_I2C_SDA_PF1 _GPIO(41) +#define TEGRA_PIN_UART2_TX_PG0 _GPIO(48) +#define TEGRA_PIN_UART2_RX_PG1 _GPIO(49) +#define TEGRA_PIN_UART2_RTS_PG2 _GPIO(50) +#define TEGRA_PIN_UART2_CTS_PG3 _GPIO(51) +#define TEGRA_PIN_WIFI_EN_PH0 _GPIO(56) +#define TEGRA_PIN_WIFI_RST_PH1 _GPIO(57) +#define TEGRA_PIN_WIFI_WAKE_AP_PH2 _GPIO(58) +#define TEGRA_PIN_AP_WAKE_BT_PH3 _GPIO(59) +#define TEGRA_PIN_BT_RST_PH4 _GPIO(60) +#define TEGRA_PIN_BT_WAKE_AP_PH5 _GPIO(61) +#define TEGRA_PIN_PH6 _GPIO(62) +#define TEGRA_PIN_AP_WAKE_NFC_PH7 _GPIO(63) +#define TEGRA_PIN_NFC_EN_PI0 _GPIO(64) +#define TEGRA_PIN_NFC_INT_PI1 _GPIO(65) +#define TEGRA_PIN_GPS_EN_PI2 _GPIO(66) +#define TEGRA_PIN_GPS_RST_PI3 _GPIO(67) +#define TEGRA_PIN_UART4_TX_PI4 _GPIO(68) +#define TEGRA_PIN_UART4_RX_PI5 _GPIO(69) +#define TEGRA_PIN_UART4_RTS_PI6 _GPIO(70) +#define TEGRA_PIN_UART4_CTS_PI7 _GPIO(71) +#define TEGRA_PIN_GEN1_I2C_SDA_PJ0 _GPIO(72) +#define TEGRA_PIN_GEN1_I2C_SCL_PJ1 _GPIO(73) +#define TEGRA_PIN_GEN2_I2C_SCL_PJ2 _GPIO(74) +#define TEGRA_PIN_GEN2_I2C_SDA_PJ3 _GPIO(75) +#define TEGRA_PIN_DAP4_FS_PJ4 _GPIO(76) +#define TEGRA_PIN_DAP4_DIN_PJ5 _GPIO(77) +#define TEGRA_PIN_DAP4_DOUT_PJ6 _GPIO(78) +#define TEGRA_PIN_DAP4_SCLK_PJ7 _GPIO(79) +#define TEGRA_PIN_PK0 _GPIO(80) +#define TEGRA_PIN_PK1 _GPIO(81) +#define TEGRA_PIN_PK2 _GPIO(82) +#define TEGRA_PIN_PK3 _GPIO(83) +#define TEGRA_PIN_PK4 _GPIO(84) +#define TEGRA_PIN_PK5 _GPIO(85) +#define TEGRA_PIN_PK6 _GPIO(86) +#define TEGRA_PIN_PK7 _GPIO(87) +#define TEGRA_PIN_PL0 _GPIO(88) +#define TEGRA_PIN_PL1 _GPIO(89) +#define TEGRA_PIN_SDMMC1_CLK_PM0 _GPIO(96) +#define TEGRA_PIN_SDMMC1_CMD_PM1 _GPIO(97) +#define TEGRA_PIN_SDMMC1_DAT3_PM2 _GPIO(98) +#define TEGRA_PIN_SDMMC1_DAT2_PM3 _GPIO(99) +#define TEGRA_PIN_SDMMC1_DAT1_PM4 _GPIO(100) +#define TEGRA_PIN_SDMMC1_DAT0_PM5 _GPIO(101) +#define TEGRA_PIN_SDMMC3_CLK_PP0 _GPIO(120) +#define TEGRA_PIN_SDMMC3_CMD_PP1 _GPIO(121) +#define TEGRA_PIN_SDMMC3_DAT3_PP2 _GPIO(122) +#define TEGRA_PIN_SDMMC3_DAT2_PP3 _GPIO(123) +#define TEGRA_PIN_SDMMC3_DAT1_PP4 _GPIO(124) +#define TEGRA_PIN_SDMMC3_DAT0_PP5 _GPIO(125) +#define TEGRA_PIN_CAM1_MCLK_PS0 _GPIO(144) +#define TEGRA_PIN_CAM2_MCLK_PS1 _GPIO(145) +#define TEGRA_PIN_CAM_I2C_SCL_PS2 _GPIO(146) +#define TEGRA_PIN_CAM_I2C_SDA_PS3 _GPIO(147) +#define TEGRA_PIN_CAM_RST_PS4 _GPIO(148) +#define TEGRA_PIN_CAM_AF_EN_PS5 _GPIO(149) +#define TEGRA_PIN_CAM_FLASH_EN_PS6 _GPIO(150) +#define TEGRA_PIN_CAM1_PWDN_PS7 _GPIO(151) +#define TEGRA_PIN_CAM2_PWDN_PT0 _GPIO(152) +#define TEGRA_PIN_CAM1_STROBE_PT1 _GPIO(153) +#define TEGRA_PIN_UART1_TX_PU0 _GPIO(160) +#define TEGRA_PIN_UART1_RX_PU1 _GPIO(161) +#define TEGRA_PIN_UART1_RTS_PU2 _GPIO(162) +#define TEGRA_PIN_UART1_CTS_PU3 _GPIO(163) +#define TEGRA_PIN_LCD_BL_PWM_PV0 _GPIO(168) +#define TEGRA_PIN_LCD_BL_EN_PV1 _GPIO(169) +#define TEGRA_PIN_LCD_RST_PV2 _GPIO(170) +#define TEGRA_PIN_LCD_GPIO1_PV3 _GPIO(171) +#define TEGRA_PIN_LCD_GPIO2_PV4 _GPIO(172) +#define TEGRA_PIN_AP_READY_PV5 _GPIO(173) +#define TEGRA_PIN_TOUCH_RST_PV6 _GPIO(174) +#define TEGRA_PIN_TOUCH_CLK_PV7 _GPIO(175) +#define TEGRA_PIN_MODEM_WAKE_AP_PX0 _GPIO(184) +#define TEGRA_PIN_TOUCH_INT_PX1 _GPIO(185) +#define TEGRA_PIN_MOTION_INT_PX2 _GPIO(186) +#define TEGRA_PIN_ALS_PROX_INT_PX3 _GPIO(187) +#define TEGRA_PIN_TEMP_ALERT_PX4 _GPIO(188) +#define TEGRA_PIN_BUTTON_POWER_ON_PX5 _GPIO(189) +#define TEGRA_PIN_BUTTON_VOL_UP_PX6 _GPIO(190) +#define TEGRA_PIN_BUTTON_VOL_DOWN_PX7 _GPIO(191) +#define TEGRA_PIN_BUTTON_SLIDE_SW_PY0 _GPIO(192) +#define TEGRA_PIN_BUTTON_HOME_PY1 _GPIO(193) +#define TEGRA_PIN_LCD_TE_PY2 _GPIO(194) +#define TEGRA_PIN_PWR_I2C_SCL_PY3 _GPIO(195) +#define TEGRA_PIN_PWR_I2C_SDA_PY4 _GPIO(196) +#define TEGRA_PIN_CLK_32K_OUT_PY5 _GPIO(197) +#define TEGRA_PIN_PZ0 _GPIO(200) +#define TEGRA_PIN_PZ1 _GPIO(201) +#define TEGRA_PIN_PZ2 _GPIO(202) +#define TEGRA_PIN_PZ3 _GPIO(203) +#define TEGRA_PIN_PZ4 _GPIO(204) +#define TEGRA_PIN_PZ5 _GPIO(205) +#define TEGRA_PIN_DAP2_FS_PAA0 _GPIO(208) +#define TEGRA_PIN_DAP2_SCLK_PAA1 _GPIO(209) +#define TEGRA_PIN_DAP2_DIN_PAA2 _GPIO(210) +#define TEGRA_PIN_DAP2_DOUT_PAA3 _GPIO(211) +#define TEGRA_PIN_AUD_MCLK_PBB0 _GPIO(216) +#define TEGRA_PIN_DVFS_PWM_PBB1 _GPIO(217) +#define TEGRA_PIN_DVFS_CLK_PBB2 _GPIO(218) +#define TEGRA_PIN_GPIO_X1_AUD_PBB3 _GPIO(219) +#define TEGRA_PIN_GPIO_X3_AUD_PBB4 _GPIO(220) +#define TEGRA_PIN_HDMI_CEC_PCC0 _GPIO(224) +#define TEGRA_PIN_HDMI_INT_DP_HPD_PCC1 _GPIO(225) +#define TEGRA_PIN_SPDIF_OUT_PCC2 _GPIO(226) +#define TEGRA_PIN_SPDIF_IN_PCC3 _GPIO(227) +#define TEGRA_PIN_USB_VBUS_EN0_PCC4 _GPIO(228) +#define TEGRA_PIN_USB_VBUS_EN1_PCC5 _GPIO(229) +#define TEGRA_PIN_DP_HPD0_PCC6 _GPIO(230) +#define TEGRA_PIN_PCC7 _GPIO(231) +#define TEGRA_PIN_SPI2_CS1_PDD0 _GPIO(232) +#define TEGRA_PIN_QSPI_SCK_PEE0 _GPIO(240) +#define TEGRA_PIN_QSPI_CS_N_PEE1 _GPIO(241) +#define TEGRA_PIN_QSPI_IO0_PEE2 _GPIO(242) +#define TEGRA_PIN_QSPI_IO1_PEE3 _GPIO(243) +#define TEGRA_PIN_QSPI_IO2_PEE4 _GPIO(244) +#define TEGRA_PIN_QSPI_IO3_PEE5 _GPIO(245) + +/* All non-GPIO pins follow */ +#define NUM_GPIOS (TEGRA_PIN_QSPI_IO3_PEE5 + 1) +#define _PIN(offset) (NUM_GPIOS + (offset)) + +/* Non-GPIO pins */ +#define TEGRA_PIN_CORE_PWR_REQ _PIN(0) +#define TEGRA_PIN_CPU_PWR_REQ _PIN(1) +#define TEGRA_PIN_PWR_INT_N _PIN(2) +#define TEGRA_PIN_CLK_32K_IN _PIN(3) +#define TEGRA_PIN_JTAG_RTCK _PIN(4) +#define TEGRA_PIN_BATT_BCL _PIN(5) +#define TEGRA_PIN_CLK_REQ _PIN(6) +#define TEGRA_PIN_SHUTDOWN _PIN(7) + +static const struct pinctrl_pin_desc tegra210_pins[] = { + PINCTRL_PIN(TEGRA_PIN_PEX_L0_RST_N_PA0, "PEX_L0_RST_N PA0"), + PINCTRL_PIN(TEGRA_PIN_PEX_L0_CLKREQ_N_PA1, "PEX_L0_CLKREQ_N PA1"), + PINCTRL_PIN(TEGRA_PIN_PEX_WAKE_N_PA2, "PEX_WAKE_N PA2"), + PINCTRL_PIN(TEGRA_PIN_PEX_L1_RST_N_PA3, "PEX_L1_RST_N PA3"), + PINCTRL_PIN(TEGRA_PIN_PEX_L1_CLKREQ_N_PA4, "PEX_L1_CLKREQ_N PA4"), + PINCTRL_PIN(TEGRA_PIN_SATA_LED_ACTIVE_PA5, "SATA_LED_ACTIVE PA5"), + PINCTRL_PIN(TEGRA_PIN_PA6, "PA6"), + PINCTRL_PIN(TEGRA_PIN_DAP1_FS_PB0, "DAP1_FS PB0"), + PINCTRL_PIN(TEGRA_PIN_DAP1_DIN_PB1, "DAP1_DIN PB1"), + PINCTRL_PIN(TEGRA_PIN_DAP1_DOUT_PB2, "DAP1_DOUT PB2"), + PINCTRL_PIN(TEGRA_PIN_DAP1_SCLK_PB3, "DAP1_SCLK PB3"), + PINCTRL_PIN(TEGRA_PIN_SPI2_MOSI_PB4, "SPI2_MOSI PB4"), + PINCTRL_PIN(TEGRA_PIN_SPI2_MISO_PB5, "SPI2_MISO PB5"), + PINCTRL_PIN(TEGRA_PIN_SPI2_SCK_PB6, "SPI2_SCK PB6"), + PINCTRL_PIN(TEGRA_PIN_SPI2_CS0_PB7, "SPI2_CS0 PB7"), + PINCTRL_PIN(TEGRA_PIN_SPI1_MOSI_PC0, "SPI1_MOSI PC0"), + PINCTRL_PIN(TEGRA_PIN_SPI1_MISO_PC1, "SPI1_MISO PC1"), + PINCTRL_PIN(TEGRA_PIN_SPI1_SCK_PC2, "SPI1_SCK PC2"), + PINCTRL_PIN(TEGRA_PIN_SPI1_CS0_PC3, "SPI1_CS0 PC3"), + PINCTRL_PIN(TEGRA_PIN_SPI1_CS1_PC4, "SPI1_CS1 PC4"), + PINCTRL_PIN(TEGRA_PIN_SPI4_SCK_PC5, "SPI4_SCK PC5"), + PINCTRL_PIN(TEGRA_PIN_SPI4_CS0_PC6, "SPI4_CS0 PC6"), + PINCTRL_PIN(TEGRA_PIN_SPI4_MOSI_PC7, "SPI4_MOSI PC7"), + PINCTRL_PIN(TEGRA_PIN_SPI4_MISO_PD0, "SPI4_MISO PD0"), + PINCTRL_PIN(TEGRA_PIN_UART3_TX_PD1, "UART3_TX PD1"), + PINCTRL_PIN(TEGRA_PIN_UART3_RX_PD2, "UART3_RX PD2"), + PINCTRL_PIN(TEGRA_PIN_UART3_RTS_PD3, "UART3_RTS PD3"), + PINCTRL_PIN(TEGRA_PIN_UART3_CTS_PD4, "UART3_CTS PD4"), + PINCTRL_PIN(TEGRA_PIN_DMIC1_CLK_PE0, "DMIC1_CLK PE0"), + PINCTRL_PIN(TEGRA_PIN_DMIC1_DAT_PE1, "DMIC1_DAT PE1"), + PINCTRL_PIN(TEGRA_PIN_DMIC2_CLK_PE2, "DMIC2_CLK PE2"), + PINCTRL_PIN(TEGRA_PIN_DMIC2_DAT_PE3, "DMIC2_DAT PE3"), + PINCTRL_PIN(TEGRA_PIN_DMIC3_CLK_PE4, "DMIC3_CLK PE4"), + PINCTRL_PIN(TEGRA_PIN_DMIC3_DAT_PE5, "DMIC3_DAT PE5"), + PINCTRL_PIN(TEGRA_PIN_PE6, "PE6"), + PINCTRL_PIN(TEGRA_PIN_PE7, "PE7"), + PINCTRL_PIN(TEGRA_PIN_GEN3_I2C_SCL_PF0, "GEN3_I2C_SCL PF0"), + PINCTRL_PIN(TEGRA_PIN_GEN3_I2C_SDA_PF1, "GEN3_I2C_SDA PF1"), + PINCTRL_PIN(TEGRA_PIN_UART2_TX_PG0, "UART2_TX PG0"), + PINCTRL_PIN(TEGRA_PIN_UART2_RX_PG1, "UART2_RX PG1"), + PINCTRL_PIN(TEGRA_PIN_UART2_RTS_PG2, "UART2_RTS PG2"), + PINCTRL_PIN(TEGRA_PIN_UART2_CTS_PG3, "UART2_CTS PG3"), + PINCTRL_PIN(TEGRA_PIN_WIFI_EN_PH0, "WIFI_EN PH0"), + PINCTRL_PIN(TEGRA_PIN_WIFI_RST_PH1, "WIFI_RST PH1"), + PINCTRL_PIN(TEGRA_PIN_WIFI_WAKE_AP_PH2, "WIFI_WAKE_AP PH2"), + PINCTRL_PIN(TEGRA_PIN_AP_WAKE_BT_PH3, "AP_WAKE_BT PH3"), + PINCTRL_PIN(TEGRA_PIN_BT_RST_PH4, "BT_RST PH4"), + PINCTRL_PIN(TEGRA_PIN_BT_WAKE_AP_PH5, "BT_WAKE_AP PH5"), + PINCTRL_PIN(TEGRA_PIN_PH6, "PH6"), + PINCTRL_PIN(TEGRA_PIN_AP_WAKE_NFC_PH7, "AP_WAKE_NFC PH7"), + PINCTRL_PIN(TEGRA_PIN_NFC_EN_PI0, "NFC_EN PI0"), + PINCTRL_PIN(TEGRA_PIN_NFC_INT_PI1, "NFC_INT PI1"), + PINCTRL_PIN(TEGRA_PIN_GPS_EN_PI2, "GPS_EN PI2"), + PINCTRL_PIN(TEGRA_PIN_GPS_RST_PI3, "GPS_RST PI3"), + PINCTRL_PIN(TEGRA_PIN_UART4_TX_PI4, "UART4_TX PI4"), + PINCTRL_PIN(TEGRA_PIN_UART4_RX_PI5, "UART4_RX PI5"), + PINCTRL_PIN(TEGRA_PIN_UART4_RTS_PI6, "UART4_RTS PI6"), + PINCTRL_PIN(TEGRA_PIN_UART4_CTS_PI7, "UART4_CTS PI7"), + PINCTRL_PIN(TEGRA_PIN_GEN1_I2C_SDA_PJ0, "GEN1_I2C_SDA PJ0"), + PINCTRL_PIN(TEGRA_PIN_GEN1_I2C_SCL_PJ1, "GEN1_I2C_SCL PJ1"), + PINCTRL_PIN(TEGRA_PIN_GEN2_I2C_SCL_PJ2, "GEN2_I2C_SCL PJ2"), + PINCTRL_PIN(TEGRA_PIN_GEN2_I2C_SDA_PJ3, "GEN2_I2C_SDA PJ3"), + PINCTRL_PIN(TEGRA_PIN_DAP4_FS_PJ4, "DAP4_FS PJ4"), + PINCTRL_PIN(TEGRA_PIN_DAP4_DIN_PJ5, "DAP4_DIN PJ5"), + PINCTRL_PIN(TEGRA_PIN_DAP4_DOUT_PJ6, "DAP4_DOUT PJ6"), + PINCTRL_PIN(TEGRA_PIN_DAP4_SCLK_PJ7, "DAP4_SCLK PJ7"), + PINCTRL_PIN(TEGRA_PIN_PK0, "PK0"), + PINCTRL_PIN(TEGRA_PIN_PK1, "PK1"), + PINCTRL_PIN(TEGRA_PIN_PK2, "PK2"), + PINCTRL_PIN(TEGRA_PIN_PK3, "PK3"), + PINCTRL_PIN(TEGRA_PIN_PK4, "PK4"), + PINCTRL_PIN(TEGRA_PIN_PK5, "PK5"), + PINCTRL_PIN(TEGRA_PIN_PK6, "PK6"), + PINCTRL_PIN(TEGRA_PIN_PK7, "PK7"), + PINCTRL_PIN(TEGRA_PIN_PL0, "PL0"), + PINCTRL_PIN(TEGRA_PIN_PL1, "PL1"), + PINCTRL_PIN(TEGRA_PIN_SDMMC1_CLK_PM0, "SDMMC1_CLK PM0"), + PINCTRL_PIN(TEGRA_PIN_SDMMC1_CMD_PM1, "SDMMC1_CMD PM1"), + PINCTRL_PIN(TEGRA_PIN_SDMMC1_DAT3_PM2, "SDMMC1_DAT3 PM2"), + PINCTRL_PIN(TEGRA_PIN_SDMMC1_DAT2_PM3, "SDMMC1_DAT2 PM3"), + PINCTRL_PIN(TEGRA_PIN_SDMMC1_DAT1_PM4, "SDMMC1_DAT1 PM4"), + PINCTRL_PIN(TEGRA_PIN_SDMMC1_DAT0_PM5, "SDMMC1_DAT0 PM5"), + PINCTRL_PIN(TEGRA_PIN_SDMMC3_CLK_PP0, "SDMMC3_CLK PP0"), + PINCTRL_PIN(TEGRA_PIN_SDMMC3_CMD_PP1, "SDMMC3_CMD PP1"), + PINCTRL_PIN(TEGRA_PIN_SDMMC3_DAT3_PP2, "SDMMC3_DAT3 PP2"), + PINCTRL_PIN(TEGRA_PIN_SDMMC3_DAT2_PP3, "SDMMC3_DAT2 PP3"), + PINCTRL_PIN(TEGRA_PIN_SDMMC3_DAT1_PP4, "SDMMC3_DAT1 PP4"), + PINCTRL_PIN(TEGRA_PIN_SDMMC3_DAT0_PP5, "SDMMC3_DAT0 PP5"), + PINCTRL_PIN(TEGRA_PIN_CAM1_MCLK_PS0, "CAM1_MCLK PS0"), + PINCTRL_PIN(TEGRA_PIN_CAM2_MCLK_PS1, "CAM2_MCLK PS1"), + PINCTRL_PIN(TEGRA_PIN_CAM_I2C_SCL_PS2, "CAM_I2C_SCL PS2"), + PINCTRL_PIN(TEGRA_PIN_CAM_I2C_SDA_PS3, "CAM_I2C_SDA PS3"), + PINCTRL_PIN(TEGRA_PIN_CAM_RST_PS4, "CAM_RST PS4"), + PINCTRL_PIN(TEGRA_PIN_CAM_AF_EN_PS5, "CAM_AF_EN PS5"), + PINCTRL_PIN(TEGRA_PIN_CAM_FLASH_EN_PS6, "CAM_FLASH_EN PS6"), + PINCTRL_PIN(TEGRA_PIN_CAM1_PWDN_PS7, "CAM1_PWDN PS7"), + PINCTRL_PIN(TEGRA_PIN_CAM2_PWDN_PT0, "CAM2_PWDN PT0"), + PINCTRL_PIN(TEGRA_PIN_CAM1_STROBE_PT1, "CAM1_STROBE PT1"), + PINCTRL_PIN(TEGRA_PIN_UART1_TX_PU0, "UART1_TX PU0"), + PINCTRL_PIN(TEGRA_PIN_UART1_RX_PU1, "UART1_RX PU1"), + PINCTRL_PIN(TEGRA_PIN_UART1_RTS_PU2, "UART1_RTS PU2"), + PINCTRL_PIN(TEGRA_PIN_UART1_CTS_PU3, "UART1_CTS PU3"), + PINCTRL_PIN(TEGRA_PIN_LCD_BL_PWM_PV0, "LCD_BL_PWM PV0"), + PINCTRL_PIN(TEGRA_PIN_LCD_BL_EN_PV1, "LCD_BL_EN PV1"), + PINCTRL_PIN(TEGRA_PIN_LCD_RST_PV2, "LCD_RST PV2"), + PINCTRL_PIN(TEGRA_PIN_LCD_GPIO1_PV3, "LCD_GPIO1 PV3"), + PINCTRL_PIN(TEGRA_PIN_LCD_GPIO2_PV4, "LCD_GPIO2 PV4"), + PINCTRL_PIN(TEGRA_PIN_AP_READY_PV5, "AP_READY PV5"), + PINCTRL_PIN(TEGRA_PIN_TOUCH_RST_PV6, "TOUCH_RST PV6"), + PINCTRL_PIN(TEGRA_PIN_TOUCH_CLK_PV7, "TOUCH_CLK PV7"), + PINCTRL_PIN(TEGRA_PIN_MODEM_WAKE_AP_PX0, "MODEM_WAKE_AP PX0"), + PINCTRL_PIN(TEGRA_PIN_TOUCH_INT_PX1, "TOUCH_INT PX1"), + PINCTRL_PIN(TEGRA_PIN_MOTION_INT_PX2, "MOTION_INT PX2"), + PINCTRL_PIN(TEGRA_PIN_ALS_PROX_INT_PX3, "ALS_PROX_INT PX3"), + PINCTRL_PIN(TEGRA_PIN_TEMP_ALERT_PX4, "TEMP_ALERT PX4"), + PINCTRL_PIN(TEGRA_PIN_BUTTON_POWER_ON_PX5, "BUTTON_POWER_ON PX5"), + PINCTRL_PIN(TEGRA_PIN_BUTTON_VOL_UP_PX6, "BUTTON_VOL_UP PX6"), + PINCTRL_PIN(TEGRA_PIN_BUTTON_VOL_DOWN_PX7, "BUTTON_VOL_DOWN PX7"), + PINCTRL_PIN(TEGRA_PIN_BUTTON_SLIDE_SW_PY0, "BUTTON_SLIDE_SW PY0"), + PINCTRL_PIN(TEGRA_PIN_BUTTON_HOME_PY1, "BUTTON_HOME PY1"), + PINCTRL_PIN(TEGRA_PIN_LCD_TE_PY2, "LCD_TE PY2"), + PINCTRL_PIN(TEGRA_PIN_PWR_I2C_SCL_PY3, "PWR_I2C_SCL PY3"), + PINCTRL_PIN(TEGRA_PIN_PWR_I2C_SDA_PY4, "PWR_I2C_SDA PY4"), + PINCTRL_PIN(TEGRA_PIN_CLK_32K_OUT_PY5, "CLK_32K_OUT PY5"), + PINCTRL_PIN(TEGRA_PIN_PZ0, "PZ0"), + PINCTRL_PIN(TEGRA_PIN_PZ1, "PZ1"), + PINCTRL_PIN(TEGRA_PIN_PZ2, "PZ2"), + PINCTRL_PIN(TEGRA_PIN_PZ3, "PZ3"), + PINCTRL_PIN(TEGRA_PIN_PZ4, "PZ4"), + PINCTRL_PIN(TEGRA_PIN_PZ5, "PZ5"), + PINCTRL_PIN(TEGRA_PIN_DAP2_FS_PAA0, "DAP2_FS PAA0"), + PINCTRL_PIN(TEGRA_PIN_DAP2_SCLK_PAA1, "DAP2_SCLK PAA1"), + PINCTRL_PIN(TEGRA_PIN_DAP2_DIN_PAA2, "DAP2_DIN PAA2"), + PINCTRL_PIN(TEGRA_PIN_DAP2_DOUT_PAA3, "DAP2_DOUT PAA3"), + PINCTRL_PIN(TEGRA_PIN_AUD_MCLK_PBB0, "AUD_MCLK PBB0"), + PINCTRL_PIN(TEGRA_PIN_DVFS_PWM_PBB1, "DVFS_PWM PBB1"), + PINCTRL_PIN(TEGRA_PIN_DVFS_CLK_PBB2, "DVFS_CLK PBB2"), + PINCTRL_PIN(TEGRA_PIN_GPIO_X1_AUD_PBB3, "GPIO_X1_AUD PBB3"), + PINCTRL_PIN(TEGRA_PIN_GPIO_X3_AUD_PBB4, "GPIO_X3_AUD PBB4"), + PINCTRL_PIN(TEGRA_PIN_HDMI_CEC_PCC0, "HDMI_CEC PCC0"), + PINCTRL_PIN(TEGRA_PIN_HDMI_INT_DP_HPD_PCC1, "HDMI_INT_DP_HPD PCC1"), + PINCTRL_PIN(TEGRA_PIN_SPDIF_OUT_PCC2, "SPDIF_OUT PCC2"), + PINCTRL_PIN(TEGRA_PIN_SPDIF_IN_PCC3, "SPDIF_IN PCC3"), + PINCTRL_PIN(TEGRA_PIN_USB_VBUS_EN0_PCC4, "USB_VBUS_EN0 PCC4"), + PINCTRL_PIN(TEGRA_PIN_USB_VBUS_EN1_PCC5, "USB_VBUS_EN1 PCC5"), + PINCTRL_PIN(TEGRA_PIN_DP_HPD0_PCC6, "DP_HPD0 PCC6"), + PINCTRL_PIN(TEGRA_PIN_PCC7, "PCC7"), + PINCTRL_PIN(TEGRA_PIN_SPI2_CS1_PDD0, "SPI2_CS1 PDD0"), + PINCTRL_PIN(TEGRA_PIN_QSPI_SCK_PEE0, "QSPI_SCK PEE0"), + PINCTRL_PIN(TEGRA_PIN_QSPI_CS_N_PEE1, "QSPI_CS_N PEE1"), + PINCTRL_PIN(TEGRA_PIN_QSPI_IO0_PEE2, "QSPI_IO0 PEE2"), + PINCTRL_PIN(TEGRA_PIN_QSPI_IO1_PEE3, "QSPI_IO1 PEE3"), + PINCTRL_PIN(TEGRA_PIN_QSPI_IO2_PEE4, "QSPI_IO2 PEE4"), + PINCTRL_PIN(TEGRA_PIN_QSPI_IO3_PEE5, "QSPI_IO3 PEE5"), + PINCTRL_PIN(TEGRA_PIN_CORE_PWR_REQ, "CORE_PWR_REQ"), + PINCTRL_PIN(TEGRA_PIN_CPU_PWR_REQ, "CPU_PWR_REQ"), + PINCTRL_PIN(TEGRA_PIN_PWR_INT_N, "PWR_INT_N"), + PINCTRL_PIN(TEGRA_PIN_CLK_32K_IN, "CLK_32K_IN"), + PINCTRL_PIN(TEGRA_PIN_JTAG_RTCK, "JTAG_RTCK"), + PINCTRL_PIN(TEGRA_PIN_BATT_BCL, "BATT_BCL"), + PINCTRL_PIN(TEGRA_PIN_CLK_REQ, "CLK_REQ"), + PINCTRL_PIN(TEGRA_PIN_SHUTDOWN, "SHUTDOWN"), +}; + +static const unsigned pex_l0_rst_n_pa0_pins[] = { + TEGRA_PIN_PEX_L0_RST_N_PA0, +}; + +static const unsigned pex_l0_clkreq_n_pa1_pins[] = { + TEGRA_PIN_PEX_L0_CLKREQ_N_PA1, +}; + +static const unsigned pex_wake_n_pa2_pins[] = { + TEGRA_PIN_PEX_WAKE_N_PA2, +}; + +static const unsigned pex_l1_rst_n_pa3_pins[] = { + TEGRA_PIN_PEX_L1_RST_N_PA3, +}; + +static const unsigned pex_l1_clkreq_n_pa4_pins[] = { + TEGRA_PIN_PEX_L1_CLKREQ_N_PA4, +}; + +static const unsigned sata_led_active_pa5_pins[] = { + TEGRA_PIN_SATA_LED_ACTIVE_PA5, +}; + +static const unsigned pa6_pins[] = { + TEGRA_PIN_PA6, +}; + +static const unsigned dap1_fs_pb0_pins[] = { + TEGRA_PIN_DAP1_FS_PB0, +}; + +static const unsigned dap1_din_pb1_pins[] = { + TEGRA_PIN_DAP1_DIN_PB1, +}; + +static const unsigned dap1_dout_pb2_pins[] = { + TEGRA_PIN_DAP1_DOUT_PB2, +}; + +static const unsigned dap1_sclk_pb3_pins[] = { + TEGRA_PIN_DAP1_SCLK_PB3, +}; + +static const unsigned spi2_mosi_pb4_pins[] = { + TEGRA_PIN_SPI2_MOSI_PB4, +}; + +static const unsigned spi2_miso_pb5_pins[] = { + TEGRA_PIN_SPI2_MISO_PB5, +}; + +static const unsigned spi2_sck_pb6_pins[] = { + TEGRA_PIN_SPI2_SCK_PB6, +}; + +static const unsigned spi2_cs0_pb7_pins[] = { + TEGRA_PIN_SPI2_CS0_PB7, +}; + +static const unsigned spi1_mosi_pc0_pins[] = { + TEGRA_PIN_SPI1_MOSI_PC0, +}; + +static const unsigned spi1_miso_pc1_pins[] = { + TEGRA_PIN_SPI1_MISO_PC1, +}; + +static const unsigned spi1_sck_pc2_pins[] = { + TEGRA_PIN_SPI1_SCK_PC2, +}; + +static const unsigned spi1_cs0_pc3_pins[] = { + TEGRA_PIN_SPI1_CS0_PC3, +}; + +static const unsigned spi1_cs1_pc4_pins[] = { + TEGRA_PIN_SPI1_CS1_PC4, +}; + +static const unsigned spi4_sck_pc5_pins[] = { + TEGRA_PIN_SPI4_SCK_PC5, +}; + +static const unsigned spi4_cs0_pc6_pins[] = { + TEGRA_PIN_SPI4_CS0_PC6, +}; + +static const unsigned spi4_mosi_pc7_pins[] = { + TEGRA_PIN_SPI4_MOSI_PC7, +}; + +static const unsigned spi4_miso_pd0_pins[] = { + TEGRA_PIN_SPI4_MISO_PD0, +}; + +static const unsigned uart3_tx_pd1_pins[] = { + TEGRA_PIN_UART3_TX_PD1, +}; + +static const unsigned uart3_rx_pd2_pins[] = { + TEGRA_PIN_UART3_RX_PD2, +}; + +static const unsigned uart3_rts_pd3_pins[] = { + TEGRA_PIN_UART3_RTS_PD3, +}; + +static const unsigned uart3_cts_pd4_pins[] = { + TEGRA_PIN_UART3_CTS_PD4, +}; + +static const unsigned dmic1_clk_pe0_pins[] = { + TEGRA_PIN_DMIC1_CLK_PE0, +}; + +static const unsigned dmic1_dat_pe1_pins[] = { + TEGRA_PIN_DMIC1_DAT_PE1, +}; + +static const unsigned dmic2_clk_pe2_pins[] = { + TEGRA_PIN_DMIC2_CLK_PE2, +}; + +static const unsigned dmic2_dat_pe3_pins[] = { + TEGRA_PIN_DMIC2_DAT_PE3, +}; + +static const unsigned dmic3_clk_pe4_pins[] = { + TEGRA_PIN_DMIC3_CLK_PE4, +}; + +static const unsigned dmic3_dat_pe5_pins[] = { + TEGRA_PIN_DMIC3_DAT_PE5, +}; + +static const unsigned pe6_pins[] = { + TEGRA_PIN_PE6, +}; + +static const unsigned pe7_pins[] = { + TEGRA_PIN_PE7, +}; + +static const unsigned gen3_i2c_scl_pf0_pins[] = { + TEGRA_PIN_GEN3_I2C_SCL_PF0, +}; + +static const unsigned gen3_i2c_sda_pf1_pins[] = { + TEGRA_PIN_GEN3_I2C_SDA_PF1, +}; + +static const unsigned uart2_tx_pg0_pins[] = { + TEGRA_PIN_UART2_TX_PG0, +}; + +static const unsigned uart2_rx_pg1_pins[] = { + TEGRA_PIN_UART2_RX_PG1, +}; + +static const unsigned uart2_rts_pg2_pins[] = { + TEGRA_PIN_UART2_RTS_PG2, +}; + +static const unsigned uart2_cts_pg3_pins[] = { + TEGRA_PIN_UART2_CTS_PG3, +}; + +static const unsigned wifi_en_ph0_pins[] = { + TEGRA_PIN_WIFI_EN_PH0, +}; + +static const unsigned wifi_rst_ph1_pins[] = { + TEGRA_PIN_WIFI_RST_PH1, +}; + +static const unsigned wifi_wake_ap_ph2_pins[] = { + TEGRA_PIN_WIFI_WAKE_AP_PH2, +}; + +static const unsigned ap_wake_bt_ph3_pins[] = { + TEGRA_PIN_AP_WAKE_BT_PH3, +}; + +static const unsigned bt_rst_ph4_pins[] = { + TEGRA_PIN_BT_RST_PH4, +}; + +static const unsigned bt_wake_ap_ph5_pins[] = { + TEGRA_PIN_BT_WAKE_AP_PH5, +}; + +static const unsigned ph6_pins[] = { + TEGRA_PIN_PH6, +}; + +static const unsigned ap_wake_nfc_ph7_pins[] = { + TEGRA_PIN_AP_WAKE_NFC_PH7, +}; + +static const unsigned nfc_en_pi0_pins[] = { + TEGRA_PIN_NFC_EN_PI0, +}; + +static const unsigned nfc_int_pi1_pins[] = { + TEGRA_PIN_NFC_INT_PI1, +}; + +static const unsigned gps_en_pi2_pins[] = { + TEGRA_PIN_GPS_EN_PI2, +}; + +static const unsigned gps_rst_pi3_pins[] = { + TEGRA_PIN_GPS_RST_PI3, +}; + +static const unsigned uart4_tx_pi4_pins[] = { + TEGRA_PIN_UART4_TX_PI4, +}; + +static const unsigned uart4_rx_pi5_pins[] = { + TEGRA_PIN_UART4_RX_PI5, +}; + +static const unsigned uart4_rts_pi6_pins[] = { + TEGRA_PIN_UART4_RTS_PI6, +}; + +static const unsigned uart4_cts_pi7_pins[] = { + TEGRA_PIN_UART4_CTS_PI7, +}; + +static const unsigned gen1_i2c_sda_pj0_pins[] = { + TEGRA_PIN_GEN1_I2C_SDA_PJ0, +}; + +static const unsigned gen1_i2c_scl_pj1_pins[] = { + TEGRA_PIN_GEN1_I2C_SCL_PJ1, +}; + +static const unsigned gen2_i2c_scl_pj2_pins[] = { + TEGRA_PIN_GEN2_I2C_SCL_PJ2, +}; + +static const unsigned gen2_i2c_sda_pj3_pins[] = { + TEGRA_PIN_GEN2_I2C_SDA_PJ3, +}; + +static const unsigned dap4_fs_pj4_pins[] = { + TEGRA_PIN_DAP4_FS_PJ4, +}; + +static const unsigned dap4_din_pj5_pins[] = { + TEGRA_PIN_DAP4_DIN_PJ5, +}; + +static const unsigned dap4_dout_pj6_pins[] = { + TEGRA_PIN_DAP4_DOUT_PJ6, +}; + +static const unsigned dap4_sclk_pj7_pins[] = { + TEGRA_PIN_DAP4_SCLK_PJ7, +}; + +static const unsigned pk0_pins[] = { + TEGRA_PIN_PK0, +}; + +static const unsigned pk1_pins[] = { + TEGRA_PIN_PK1, +}; + +static const unsigned pk2_pins[] = { + TEGRA_PIN_PK2, +}; + +static const unsigned pk3_pins[] = { + TEGRA_PIN_PK3, +}; + +static const unsigned pk4_pins[] = { + TEGRA_PIN_PK4, +}; + +static const unsigned pk5_pins[] = { + TEGRA_PIN_PK5, +}; + +static const unsigned pk6_pins[] = { + TEGRA_PIN_PK6, +}; + +static const unsigned pk7_pins[] = { + TEGRA_PIN_PK7, +}; + +static const unsigned pl0_pins[] = { + TEGRA_PIN_PL0, +}; + +static const unsigned pl1_pins[] = { + TEGRA_PIN_PL1, +}; + +static const unsigned sdmmc1_clk_pm0_pins[] = { + TEGRA_PIN_SDMMC1_CLK_PM0, +}; + +static const unsigned sdmmc1_cmd_pm1_pins[] = { + TEGRA_PIN_SDMMC1_CMD_PM1, +}; + +static const unsigned sdmmc1_dat3_pm2_pins[] = { + TEGRA_PIN_SDMMC1_DAT3_PM2, +}; + +static const unsigned sdmmc1_dat2_pm3_pins[] = { + TEGRA_PIN_SDMMC1_DAT2_PM3, +}; + +static const unsigned sdmmc1_dat1_pm4_pins[] = { + TEGRA_PIN_SDMMC1_DAT1_PM4, +}; + +static const unsigned sdmmc1_dat0_pm5_pins[] = { + TEGRA_PIN_SDMMC1_DAT0_PM5, +}; + +static const unsigned sdmmc3_clk_pp0_pins[] = { + TEGRA_PIN_SDMMC3_CLK_PP0, +}; + +static const unsigned sdmmc3_cmd_pp1_pins[] = { + TEGRA_PIN_SDMMC3_CMD_PP1, +}; + +static const unsigned sdmmc3_dat3_pp2_pins[] = { + TEGRA_PIN_SDMMC3_DAT3_PP2, +}; + +static const unsigned sdmmc3_dat2_pp3_pins[] = { + TEGRA_PIN_SDMMC3_DAT2_PP3, +}; + +static const unsigned sdmmc3_dat1_pp4_pins[] = { + TEGRA_PIN_SDMMC3_DAT1_PP4, +}; + +static const unsigned sdmmc3_dat0_pp5_pins[] = { + TEGRA_PIN_SDMMC3_DAT0_PP5, +}; + +static const unsigned cam1_mclk_ps0_pins[] = { + TEGRA_PIN_CAM1_MCLK_PS0, +}; + +static const unsigned cam2_mclk_ps1_pins[] = { + TEGRA_PIN_CAM2_MCLK_PS1, +}; + +static const unsigned cam_i2c_scl_ps2_pins[] = { + TEGRA_PIN_CAM_I2C_SCL_PS2, +}; + +static const unsigned cam_i2c_sda_ps3_pins[] = { + TEGRA_PIN_CAM_I2C_SDA_PS3, +}; + +static const unsigned cam_rst_ps4_pins[] = { + TEGRA_PIN_CAM_RST_PS4, +}; + +static const unsigned cam_af_en_ps5_pins[] = { + TEGRA_PIN_CAM_AF_EN_PS5, +}; + +static const unsigned cam_flash_en_ps6_pins[] = { + TEGRA_PIN_CAM_FLASH_EN_PS6, +}; + +static const unsigned cam1_pwdn_ps7_pins[] = { + TEGRA_PIN_CAM1_PWDN_PS7, +}; + +static const unsigned cam2_pwdn_pt0_pins[] = { + TEGRA_PIN_CAM2_PWDN_PT0, +}; + +static const unsigned cam1_strobe_pt1_pins[] = { + TEGRA_PIN_CAM1_STROBE_PT1, +}; + +static const unsigned uart1_tx_pu0_pins[] = { + TEGRA_PIN_UART1_TX_PU0, +}; + +static const unsigned uart1_rx_pu1_pins[] = { + TEGRA_PIN_UART1_RX_PU1, +}; + +static const unsigned uart1_rts_pu2_pins[] = { + TEGRA_PIN_UART1_RTS_PU2, +}; + +static const unsigned uart1_cts_pu3_pins[] = { + TEGRA_PIN_UART1_CTS_PU3, +}; + +static const unsigned lcd_bl_pwm_pv0_pins[] = { + TEGRA_PIN_LCD_BL_PWM_PV0, +}; + +static const unsigned lcd_bl_en_pv1_pins[] = { + TEGRA_PIN_LCD_BL_EN_PV1, +}; + +static const unsigned lcd_rst_pv2_pins[] = { + TEGRA_PIN_LCD_RST_PV2, +}; + +static const unsigned lcd_gpio1_pv3_pins[] = { + TEGRA_PIN_LCD_GPIO1_PV3, +}; + +static const unsigned lcd_gpio2_pv4_pins[] = { + TEGRA_PIN_LCD_GPIO2_PV4, +}; + +static const unsigned ap_ready_pv5_pins[] = { + TEGRA_PIN_AP_READY_PV5, +}; + +static const unsigned touch_rst_pv6_pins[] = { + TEGRA_PIN_TOUCH_RST_PV6, +}; + +static const unsigned touch_clk_pv7_pins[] = { + TEGRA_PIN_TOUCH_CLK_PV7, +}; + +static const unsigned modem_wake_ap_px0_pins[] = { + TEGRA_PIN_MODEM_WAKE_AP_PX0, +}; + +static const unsigned touch_int_px1_pins[] = { + TEGRA_PIN_TOUCH_INT_PX1, +}; + +static const unsigned motion_int_px2_pins[] = { + TEGRA_PIN_MOTION_INT_PX2, +}; + +static const unsigned als_prox_int_px3_pins[] = { + TEGRA_PIN_ALS_PROX_INT_PX3, +}; + +static const unsigned temp_alert_px4_pins[] = { + TEGRA_PIN_TEMP_ALERT_PX4, +}; + +static const unsigned button_power_on_px5_pins[] = { + TEGRA_PIN_BUTTON_POWER_ON_PX5, +}; + +static const unsigned button_vol_up_px6_pins[] = { + TEGRA_PIN_BUTTON_VOL_UP_PX6, +}; + +static const unsigned button_vol_down_px7_pins[] = { + TEGRA_PIN_BUTTON_VOL_DOWN_PX7, +}; + +static const unsigned button_slide_sw_py0_pins[] = { + TEGRA_PIN_BUTTON_SLIDE_SW_PY0, +}; + +static const unsigned button_home_py1_pins[] = { + TEGRA_PIN_BUTTON_HOME_PY1, +}; + +static const unsigned lcd_te_py2_pins[] = { + TEGRA_PIN_LCD_TE_PY2, +}; + +static const unsigned pwr_i2c_scl_py3_pins[] = { + TEGRA_PIN_PWR_I2C_SCL_PY3, +}; + +static const unsigned pwr_i2c_sda_py4_pins[] = { + TEGRA_PIN_PWR_I2C_SDA_PY4, +}; + +static const unsigned clk_32k_out_py5_pins[] = { + TEGRA_PIN_CLK_32K_OUT_PY5, +}; + +static const unsigned pz0_pins[] = { + TEGRA_PIN_PZ0, +}; + +static const unsigned pz1_pins[] = { + TEGRA_PIN_PZ1, +}; + +static const unsigned pz2_pins[] = { + TEGRA_PIN_PZ2, +}; + +static const unsigned pz3_pins[] = { + TEGRA_PIN_PZ3, +}; + +static const unsigned pz4_pins[] = { + TEGRA_PIN_PZ4, +}; + +static const unsigned pz5_pins[] = { + TEGRA_PIN_PZ5, +}; + +static const unsigned dap2_fs_paa0_pins[] = { + TEGRA_PIN_DAP2_FS_PAA0, +}; + +static const unsigned dap2_sclk_paa1_pins[] = { + TEGRA_PIN_DAP2_SCLK_PAA1, +}; + +static const unsigned dap2_din_paa2_pins[] = { + TEGRA_PIN_DAP2_DIN_PAA2, +}; + +static const unsigned dap2_dout_paa3_pins[] = { + TEGRA_PIN_DAP2_DOUT_PAA3, +}; + +static const unsigned aud_mclk_pbb0_pins[] = { + TEGRA_PIN_AUD_MCLK_PBB0, +}; + +static const unsigned dvfs_pwm_pbb1_pins[] = { + TEGRA_PIN_DVFS_PWM_PBB1, +}; + +static const unsigned dvfs_clk_pbb2_pins[] = { + TEGRA_PIN_DVFS_CLK_PBB2, +}; + +static const unsigned gpio_x1_aud_pbb3_pins[] = { + TEGRA_PIN_GPIO_X1_AUD_PBB3, +}; + +static const unsigned gpio_x3_aud_pbb4_pins[] = { + TEGRA_PIN_GPIO_X3_AUD_PBB4, +}; + +static const unsigned hdmi_cec_pcc0_pins[] = { + TEGRA_PIN_HDMI_CEC_PCC0, +}; + +static const unsigned hdmi_int_dp_hpd_pcc1_pins[] = { + TEGRA_PIN_HDMI_INT_DP_HPD_PCC1, +}; + +static const unsigned spdif_out_pcc2_pins[] = { + TEGRA_PIN_SPDIF_OUT_PCC2, +}; + +static const unsigned spdif_in_pcc3_pins[] = { + TEGRA_PIN_SPDIF_IN_PCC3, +}; + +static const unsigned usb_vbus_en0_pcc4_pins[] = { + TEGRA_PIN_USB_VBUS_EN0_PCC4, +}; + +static const unsigned usb_vbus_en1_pcc5_pins[] = { + TEGRA_PIN_USB_VBUS_EN1_PCC5, +}; + +static const unsigned dp_hpd0_pcc6_pins[] = { + TEGRA_PIN_DP_HPD0_PCC6, +}; + +static const unsigned pcc7_pins[] = { + TEGRA_PIN_PCC7, +}; + +static const unsigned spi2_cs1_pdd0_pins[] = { + TEGRA_PIN_SPI2_CS1_PDD0, +}; + +static const unsigned qspi_sck_pee0_pins[] = { + TEGRA_PIN_QSPI_SCK_PEE0, +}; + +static const unsigned qspi_cs_n_pee1_pins[] = { + TEGRA_PIN_QSPI_CS_N_PEE1, +}; + +static const unsigned qspi_io0_pee2_pins[] = { + TEGRA_PIN_QSPI_IO0_PEE2, +}; + +static const unsigned qspi_io1_pee3_pins[] = { + TEGRA_PIN_QSPI_IO1_PEE3, +}; + +static const unsigned qspi_io2_pee4_pins[] = { + TEGRA_PIN_QSPI_IO2_PEE4, +}; + +static const unsigned qspi_io3_pee5_pins[] = { + TEGRA_PIN_QSPI_IO3_PEE5, +}; + +static const unsigned core_pwr_req_pins[] = { + TEGRA_PIN_CORE_PWR_REQ, +}; + +static const unsigned cpu_pwr_req_pins[] = { + TEGRA_PIN_CPU_PWR_REQ, +}; + +static const unsigned pwr_int_n_pins[] = { + TEGRA_PIN_PWR_INT_N, +}; + +static const unsigned clk_32k_in_pins[] = { + TEGRA_PIN_CLK_32K_IN, +}; + +static const unsigned jtag_rtck_pins[] = { + TEGRA_PIN_JTAG_RTCK, +}; + +static const unsigned batt_bcl_pins[] = { + TEGRA_PIN_BATT_BCL, +}; + +static const unsigned clk_req_pins[] = { + TEGRA_PIN_CLK_REQ, +}; + +static const unsigned shutdown_pins[] = { + TEGRA_PIN_SHUTDOWN, +}; + +static const unsigned drive_pa6_pins[] = { + TEGRA_PIN_PA6, +}; + +static const unsigned drive_pcc7_pins[] = { + TEGRA_PIN_PCC7, +}; + +static const unsigned drive_pe6_pins[] = { + TEGRA_PIN_PE6, +}; + +static const unsigned drive_pe7_pins[] = { + TEGRA_PIN_PE7, +}; + +static const unsigned drive_ph6_pins[] = { + TEGRA_PIN_PH6, +}; + +static const unsigned drive_pk0_pins[] = { + TEGRA_PIN_PK0, +}; + +static const unsigned drive_pk1_pins[] = { + TEGRA_PIN_PK1, +}; + +static const unsigned drive_pk2_pins[] = { + TEGRA_PIN_PK2, +}; + +static const unsigned drive_pk3_pins[] = { + TEGRA_PIN_PK3, +}; + +static const unsigned drive_pk4_pins[] = { + TEGRA_PIN_PK4, +}; + +static const unsigned drive_pk5_pins[] = { + TEGRA_PIN_PK5, +}; + +static const unsigned drive_pk6_pins[] = { + TEGRA_PIN_PK6, +}; + +static const unsigned drive_pk7_pins[] = { + TEGRA_PIN_PK7, +}; + +static const unsigned drive_pl0_pins[] = { + TEGRA_PIN_PL0, +}; + +static const unsigned drive_pl1_pins[] = { + TEGRA_PIN_PL1, +}; + +static const unsigned drive_pz0_pins[] = { + TEGRA_PIN_PZ0, +}; + +static const unsigned drive_pz1_pins[] = { + TEGRA_PIN_PZ1, +}; + +static const unsigned drive_pz2_pins[] = { + TEGRA_PIN_PZ2, +}; + +static const unsigned drive_pz3_pins[] = { + TEGRA_PIN_PZ3, +}; + +static const unsigned drive_pz4_pins[] = { + TEGRA_PIN_PZ4, +}; + +static const unsigned drive_pz5_pins[] = { + TEGRA_PIN_PZ5, +}; + +static const unsigned drive_sdmmc1_pins[] = { + TEGRA_PIN_SDMMC1_CLK_PM0, + TEGRA_PIN_SDMMC1_CMD_PM1, + TEGRA_PIN_SDMMC1_DAT3_PM2, + TEGRA_PIN_SDMMC1_DAT2_PM3, + TEGRA_PIN_SDMMC1_DAT1_PM4, + TEGRA_PIN_SDMMC1_DAT0_PM5, +}; + +static const unsigned drive_sdmmc2_pins[] = { +}; + +static const unsigned drive_sdmmc3_pins[] = { + TEGRA_PIN_SDMMC3_CLK_PP0, + TEGRA_PIN_SDMMC3_CMD_PP1, + TEGRA_PIN_SDMMC3_DAT3_PP2, + TEGRA_PIN_SDMMC3_DAT2_PP3, + TEGRA_PIN_SDMMC3_DAT1_PP4, + TEGRA_PIN_SDMMC3_DAT0_PP5, +}; + +static const unsigned drive_sdmmc4_pins[] = { +}; + +enum tegra_mux { + TEGRA_MUX_AUD, + TEGRA_MUX_BCL, + TEGRA_MUX_BLINK, + TEGRA_MUX_CCLA, + TEGRA_MUX_CEC, + TEGRA_MUX_CLDVFS, + TEGRA_MUX_CLK, + TEGRA_MUX_CORE, + TEGRA_MUX_CPU, + TEGRA_MUX_DISPLAYA, + TEGRA_MUX_DISPLAYB, + TEGRA_MUX_DMIC1, + TEGRA_MUX_DMIC2, + TEGRA_MUX_DMIC3, + TEGRA_MUX_DP, + TEGRA_MUX_DTV, + TEGRA_MUX_EXTPERIPH3, + TEGRA_MUX_I2C1, + TEGRA_MUX_I2C2, + TEGRA_MUX_I2C3, + TEGRA_MUX_I2CPMU, + TEGRA_MUX_I2CVI, + TEGRA_MUX_I2S1, + TEGRA_MUX_I2S2, + TEGRA_MUX_I2S3, + TEGRA_MUX_I2S4A, + TEGRA_MUX_I2S4B, + TEGRA_MUX_I2S5A, + TEGRA_MUX_I2S5B, + TEGRA_MUX_IQC0, + TEGRA_MUX_IQC1, + TEGRA_MUX_JTAG, + TEGRA_MUX_PE, + TEGRA_MUX_PE0, + TEGRA_MUX_PE1, + TEGRA_MUX_PMI, + TEGRA_MUX_PWM0, + TEGRA_MUX_PWM1, + TEGRA_MUX_PWM2, + TEGRA_MUX_PWM3, + TEGRA_MUX_QSPI, + TEGRA_MUX_RSVD0, + TEGRA_MUX_RSVD1, + TEGRA_MUX_RSVD2, + TEGRA_MUX_RSVD3, + TEGRA_MUX_SATA, + TEGRA_MUX_SDMMC1, + TEGRA_MUX_SDMMC3, + TEGRA_MUX_SHUTDOWN, + TEGRA_MUX_SOC, + TEGRA_MUX_SOR0, + TEGRA_MUX_SOR1, + TEGRA_MUX_SPDIF, + TEGRA_MUX_SPI1, + TEGRA_MUX_SPI2, + TEGRA_MUX_SPI3, + TEGRA_MUX_SPI4, + TEGRA_MUX_SYS, + TEGRA_MUX_TOUCH, + TEGRA_MUX_UART, + TEGRA_MUX_UARTA, + TEGRA_MUX_UARTB, + TEGRA_MUX_UARTC, + TEGRA_MUX_UARTD, + TEGRA_MUX_USB, + TEGRA_MUX_VGP1, + TEGRA_MUX_VGP2, + TEGRA_MUX_VGP3, + TEGRA_MUX_VGP4, + TEGRA_MUX_VGP5, + TEGRA_MUX_VGP6, + TEGRA_MUX_VIMCLK, + TEGRA_MUX_VIMCLK2, +}; + +#define FUNCTION(fname) \ + { \ + .name = #fname, \ + } + +static struct tegra_function tegra210_functions[] = { + FUNCTION(aud), + FUNCTION(bcl), + FUNCTION(blink), + FUNCTION(ccla), + FUNCTION(cec), + FUNCTION(cldvfs), + FUNCTION(clk), + FUNCTION(core), + FUNCTION(cpu), + FUNCTION(displaya), + FUNCTION(displayb), + FUNCTION(dmic1), + FUNCTION(dmic2), + FUNCTION(dmic3), + FUNCTION(dp), + FUNCTION(dtv), + FUNCTION(extperiph3), + FUNCTION(i2c1), + FUNCTION(i2c2), + FUNCTION(i2c3), + FUNCTION(i2cpmu), + FUNCTION(i2cvi), + FUNCTION(i2s1), + FUNCTION(i2s2), + FUNCTION(i2s3), + FUNCTION(i2s4a), + FUNCTION(i2s4b), + FUNCTION(i2s5a), + FUNCTION(i2s5b), + FUNCTION(iqc0), + FUNCTION(iqc1), + FUNCTION(jtag), + FUNCTION(pe), + FUNCTION(pe0), + FUNCTION(pe1), + FUNCTION(pmi), + FUNCTION(pwm0), + FUNCTION(pwm1), + FUNCTION(pwm2), + FUNCTION(pwm3), + FUNCTION(qspi), + FUNCTION(rsvd0), + FUNCTION(rsvd1), + FUNCTION(rsvd2), + FUNCTION(rsvd3), + FUNCTION(sata), + FUNCTION(sdmmc1), + FUNCTION(sdmmc3), + FUNCTION(shutdown), + FUNCTION(soc), + FUNCTION(sor0), + FUNCTION(sor1), + FUNCTION(spdif), + FUNCTION(spi1), + FUNCTION(spi2), + FUNCTION(spi3), + FUNCTION(spi4), + FUNCTION(sys), + FUNCTION(touch), + FUNCTION(uart), + FUNCTION(uarta), + FUNCTION(uartb), + FUNCTION(uartc), + FUNCTION(uartd), + FUNCTION(usb), + FUNCTION(vgp1), + FUNCTION(vgp2), + FUNCTION(vgp3), + FUNCTION(vgp4), + FUNCTION(vgp5), + FUNCTION(vgp6), + FUNCTION(vimclk), + FUNCTION(vimclk2), +}; + +#define DRV_PINGROUP_REG_A 0x8d4 /* bank 0 */ +#define PINGROUP_REG_A 0x3000 /* bank 1 */ + +#define DRV_PINGROUP_REG(r) ((r) - DRV_PINGROUP_REG_A) +#define PINGROUP_REG(r) ((r) - PINGROUP_REG_A) + +#define PINGROUP_BIT_Y(b) (b) +#define PINGROUP_BIT_N(b) (-1) + +#define PINGROUP(pg_name, f0, f1, f2, f3, r, hsm, drvtype, e_io_hv, \ + rdrv, drvdn_b, drvdn_w, drvup_b, drvup_w, slwr_b, \ + slwr_w, slwf_b, slwf_w) \ + { \ + .name = #pg_name, \ + .pins = pg_name##_pins, \ + .npins = ARRAY_SIZE(pg_name##_pins), \ + .funcs = { \ + TEGRA_MUX_##f0, \ + TEGRA_MUX_##f1, \ + TEGRA_MUX_##f2, \ + TEGRA_MUX_##f3, \ + }, \ + .mux_reg = PINGROUP_REG(r), \ + .mux_bank = 1, \ + .mux_bit = 0, \ + .pupd_reg = PINGROUP_REG(r), \ + .pupd_bank = 1, \ + .pupd_bit = 2, \ + .tri_reg = PINGROUP_REG(r), \ + .tri_bank = 1, \ + .tri_bit = 4, \ + .einput_bit = 6, \ + .odrain_bit = 11, \ + .lock_bit = 7, \ + .ioreset_bit = -1, \ + .rcv_sel_bit = PINGROUP_BIT_##e_io_hv(10), \ + .hsm_bit = PINGROUP_BIT_##hsm(9), \ + .schmitt_bit = 12, \ + .drvtype_bit = PINGROUP_BIT_##drvtype(13), \ + .drv_reg = DRV_PINGROUP_REG(rdrv), \ + .drv_bank = 0, \ + .lpmd_bit = -1, \ + .drvdn_bit = drvdn_b, \ + .drvdn_width = drvdn_w, \ + .drvup_bit = drvup_b, \ + .drvup_width = drvup_w, \ + .slwr_bit = slwr_b, \ + .slwr_width = slwr_w, \ + .slwf_bit = slwf_b, \ + .slwf_width = slwf_w, \ + } + +#define DRV_PINGROUP(pg_name, r, drvdn_b, drvdn_w, drvup_b, drvup_w, \ + slwr_b, slwr_w, slwf_b, slwf_w) \ + { \ + .name = "drive_" #pg_name, \ + .pins = drive_##pg_name##_pins, \ + .npins = ARRAY_SIZE(drive_##pg_name##_pins), \ + .mux_reg = -1, \ + .pupd_reg = -1, \ + .tri_reg = -1, \ + .einput_bit = -1, \ + .odrain_bit = -1, \ + .lock_bit = -1, \ + .ioreset_bit = -1, \ + .rcv_sel_bit = -1, \ + .drv_reg = DRV_PINGROUP_REG(r), \ + .drv_bank = 0, \ + .hsm_bit = -1, \ + .schmitt_bit = -1, \ + .lpmd_bit = -1, \ + .drvdn_bit = drvdn_b, \ + .drvdn_width = drvdn_w, \ + .drvup_bit = drvup_b, \ + .drvup_width = drvup_w, \ + .slwr_bit = slwr_b, \ + .slwr_width = slwr_w, \ + .slwf_bit = slwf_b, \ + .slwf_width = slwf_w, \ + .drvtype_bit = -1, \ + } + +static const struct tegra_pingroup tegra210_groups[] = { + /* pg_name, f0, f1, f2, f3, r, hsm, drvtype, e_io_hv, rdrv, drvdn_b, drvdn_w, drvup_b, drvup_w, slwr_b, slwr_w, slwf_b, slwf_w */ + PINGROUP(sdmmc1_clk_pm0, SDMMC1, RSVD1, RSVD2, RSVD3, 0x3000, Y, Y, N, -1, -1, -1, -1, -1, -1, -1, -1, -1), + PINGROUP(sdmmc1_cmd_pm1, SDMMC1, SPI3, RSVD2, RSVD3, 0x3004, Y, Y, N, -1, -1, -1, -1, -1, -1, -1, -1, -1), + PINGROUP(sdmmc1_dat3_pm2, SDMMC1, SPI3, RSVD2, RSVD3, 0x3008, Y, Y, N, -1, -1, -1, -1, -1, -1, -1, -1, -1), + PINGROUP(sdmmc1_dat2_pm3, SDMMC1, SPI3, RSVD2, RSVD3, 0x300c, Y, Y, N, -1, -1, -1, -1, -1, -1, -1, -1, -1), + PINGROUP(sdmmc1_dat1_pm4, SDMMC1, SPI3, RSVD2, RSVD3, 0x3010, Y, Y, N, -1, -1, -1, -1, -1, -1, -1, -1, -1), + PINGROUP(sdmmc1_dat0_pm5, SDMMC1, RSVD1, RSVD2, RSVD3, 0x3014, Y, Y, N, -1, -1, -1, -1, -1, -1, -1, -1, -1), + PINGROUP(sdmmc3_clk_pp0, SDMMC3, RSVD1, RSVD2, RSVD3, 0x301c, Y, Y, N, -1, -1, -1, -1, -1, -1, -1, -1, -1), + PINGROUP(sdmmc3_cmd_pp1, SDMMC3, RSVD1, RSVD2, RSVD3, 0x3020, Y, Y, N, -1, -1, -1, -1, -1, -1, -1, -1, -1), + PINGROUP(sdmmc3_dat0_pp5, SDMMC3, RSVD1, RSVD2, RSVD3, 0x3024, Y, Y, N, -1, -1, -1, -1, -1, -1, -1, -1, -1), + PINGROUP(sdmmc3_dat1_pp4, SDMMC3, RSVD1, RSVD2, RSVD3, 0x3028, Y, Y, N, -1, -1, -1, -1, -1, -1, -1, -1, -1), + PINGROUP(sdmmc3_dat2_pp3, SDMMC3, RSVD1, RSVD2, RSVD3, 0x302c, Y, Y, N, -1, -1, -1, -1, -1, -1, -1, -1, -1), + PINGROUP(sdmmc3_dat3_pp2, SDMMC3, RSVD1, RSVD2, RSVD3, 0x3030, Y, Y, N, -1, -1, -1, -1, -1, -1, -1, -1, -1), + PINGROUP(pex_l0_rst_n_pa0, PE0, RSVD1, RSVD2, RSVD3, 0x3038, N, N, Y, 0xa5c, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(pex_l0_clkreq_n_pa1, PE0, RSVD1, RSVD2, RSVD3, 0x303c, N, N, Y, 0xa58, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(pex_wake_n_pa2, PE, RSVD1, RSVD2, RSVD3, 0x3040, N, N, Y, 0xa68, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(pex_l1_rst_n_pa3, PE1, RSVD1, RSVD2, RSVD3, 0x3044, N, N, Y, 0xa64, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(pex_l1_clkreq_n_pa4, PE1, RSVD1, RSVD2, RSVD3, 0x3048, N, N, Y, 0xa60, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(sata_led_active_pa5, SATA, RSVD1, RSVD2, RSVD3, 0x304c, N, N, N, 0xa94, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(spi1_mosi_pc0, SPI1, RSVD1, RSVD2, RSVD3, 0x3050, Y, Y, N, 0xae0, -1, -1, -1, -1, 28, 2, 30, 2), + PINGROUP(spi1_miso_pc1, SPI1, RSVD1, RSVD2, RSVD3, 0x3054, Y, Y, N, 0xadc, -1, -1, -1, -1, 28, 2, 30, 2), + PINGROUP(spi1_sck_pc2, SPI1, RSVD1, RSVD2, RSVD3, 0x3058, Y, Y, N, 0xae4, -1, -1, -1, -1, 28, 2, 30, 2), + PINGROUP(spi1_cs0_pc3, SPI1, RSVD1, RSVD2, RSVD3, 0x305c, Y, Y, N, 0xad4, -1, -1, -1, -1, 28, 2, 30, 2), + PINGROUP(spi1_cs1_pc4, SPI1, RSVD1, RSVD2, RSVD3, 0x3060, Y, Y, N, 0xad8, -1, -1, -1, -1, 28, 2, 30, 2), + PINGROUP(spi2_mosi_pb4, SPI2, DTV, RSVD2, RSVD3, 0x3064, Y, Y, N, 0xaf4, -1, -1, -1, -1, 28, 2, 30, 2), + PINGROUP(spi2_miso_pb5, SPI2, DTV, RSVD2, RSVD3, 0x3068, Y, Y, N, 0xaf0, -1, -1, -1, -1, 28, 2, 30, 2), + PINGROUP(spi2_sck_pb6, SPI2, DTV, RSVD2, RSVD3, 0x306c, Y, Y, N, 0xaf8, -1, -1, -1, -1, 28, 2, 30, 2), + PINGROUP(spi2_cs0_pb7, SPI2, DTV, RSVD2, RSVD3, 0x3070, Y, Y, N, 0xae8, -1, -1, -1, -1, 28, 2, 30, 2), + PINGROUP(spi2_cs1_pdd0, SPI2, RSVD1, RSVD2, RSVD3, 0x3074, Y, Y, N, 0xaec, -1, -1, -1, -1, 28, 2, 30, 2), + PINGROUP(spi4_mosi_pc7, SPI4, RSVD1, RSVD2, RSVD3, 0x3078, Y, Y, N, 0xb04, -1, -1, -1, -1, 28, 2, 30, 2), + PINGROUP(spi4_miso_pd0, SPI4, RSVD1, RSVD2, RSVD3, 0x307c, Y, Y, N, 0xb00, -1, -1, -1, -1, 28, 2, 30, 2), + PINGROUP(spi4_sck_pc5, SPI4, RSVD1, RSVD2, RSVD3, 0x3080, Y, Y, N, 0xb08, -1, -1, -1, -1, 28, 2, 30, 2), + PINGROUP(spi4_cs0_pc6, SPI4, RSVD1, RSVD2, RSVD3, 0x3084, Y, Y, N, 0xafc, -1, -1, -1, -1, 28, 2, 30, 2), + PINGROUP(qspi_sck_pee0, QSPI, RSVD1, RSVD2, RSVD3, 0x3088, Y, Y, N, 0xa90, -1, -1, -1, -1, 28, 2, 30, 2), + PINGROUP(qspi_cs_n_pee1, QSPI, RSVD1, RSVD2, RSVD3, 0x308c, Y, Y, N, -1, -1, -1, -1, -1, -1, -1, -1, -1), + PINGROUP(qspi_io0_pee2, QSPI, RSVD1, RSVD2, RSVD3, 0x3090, Y, Y, N, -1, -1, -1, -1, -1, -1, -1, -1, -1), + PINGROUP(qspi_io1_pee3, QSPI, RSVD1, RSVD2, RSVD3, 0x3094, Y, Y, N, -1, -1, -1, -1, -1, -1, -1, -1, -1), + PINGROUP(qspi_io2_pee4, QSPI, RSVD1, RSVD2, RSVD3, 0x3098, Y, Y, N, -1, -1, -1, -1, -1, -1, -1, -1, -1), + PINGROUP(qspi_io3_pee5, QSPI, RSVD1, RSVD2, RSVD3, 0x309c, Y, Y, N, -1, -1, -1, -1, -1, -1, -1, -1, -1), + PINGROUP(dmic1_clk_pe0, DMIC1, I2S3, RSVD2, RSVD3, 0x30a4, N, N, N, 0x984, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(dmic1_dat_pe1, DMIC1, I2S3, RSVD2, RSVD3, 0x30a8, N, N, N, 0x988, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(dmic2_clk_pe2, DMIC2, I2S3, RSVD2, RSVD3, 0x30ac, N, N, N, 0x98c, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(dmic2_dat_pe3, DMIC2, I2S3, RSVD2, RSVD3, 0x30b0, N, N, N, 0x990, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(dmic3_clk_pe4, DMIC3, I2S5A, RSVD2, RSVD3, 0x30b4, N, N, N, 0x994, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(dmic3_dat_pe5, DMIC3, I2S5A, RSVD2, RSVD3, 0x30b8, N, N, N, 0x998, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(gen1_i2c_scl_pj1, I2C1, RSVD1, RSVD2, RSVD3, 0x30bc, N, N, Y, 0x9a8, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(gen1_i2c_sda_pj0, I2C1, RSVD1, RSVD2, RSVD3, 0x30c0, N, N, Y, 0x9ac, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(gen2_i2c_scl_pj2, I2C2, RSVD1, RSVD2, RSVD3, 0x30c4, N, N, Y, 0x9b0, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(gen2_i2c_sda_pj3, I2C2, RSVD1, RSVD2, RSVD3, 0x30c8, N, N, Y, 0x9b4, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(gen3_i2c_scl_pf0, I2C3, RSVD1, RSVD2, RSVD3, 0x30cc, N, N, Y, 0x9b8, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(gen3_i2c_sda_pf1, I2C3, RSVD1, RSVD2, RSVD3, 0x30d0, N, N, Y, 0x9bc, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(cam_i2c_scl_ps2, I2C3, I2CVI, RSVD2, RSVD3, 0x30d4, N, N, Y, 0x934, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(cam_i2c_sda_ps3, I2C3, I2CVI, RSVD2, RSVD3, 0x30d8, N, N, Y, 0x938, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(pwr_i2c_scl_py3, I2CPMU, RSVD1, RSVD2, RSVD3, 0x30dc, N, N, Y, 0xa6c, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(pwr_i2c_sda_py4, I2CPMU, RSVD1, RSVD2, RSVD3, 0x30e0, N, N, Y, 0xa70, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(uart1_tx_pu0, UARTA, RSVD1, RSVD2, RSVD3, 0x30e4, N, N, N, 0xb28, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(uart1_rx_pu1, UARTA, RSVD1, RSVD2, RSVD3, 0x30e8, N, N, N, 0xb24, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(uart1_rts_pu2, UARTA, RSVD1, RSVD2, RSVD3, 0x30ec, N, N, N, 0xb20, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(uart1_cts_pu3, UARTA, RSVD1, RSVD2, RSVD3, 0x30f0, N, N, N, 0xb1c, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(uart2_tx_pg0, UARTB, I2S4A, SPDIF, UART, 0x30f4, N, N, N, 0xb38, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(uart2_rx_pg1, UARTB, I2S4A, SPDIF, UART, 0x30f8, N, N, N, 0xb34, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(uart2_rts_pg2, UARTB, I2S4A, RSVD2, UART, 0x30fc, N, N, N, 0xb30, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(uart2_cts_pg3, UARTB, I2S4A, RSVD2, UART, 0x3100, N, N, N, 0xb2c, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(uart3_tx_pd1, UARTC, SPI4, RSVD2, RSVD3, 0x3104, N, N, N, 0xb48, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(uart3_rx_pd2, UARTC, SPI4, RSVD2, RSVD3, 0x3108, N, N, N, 0xb44, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(uart3_rts_pd3, UARTC, SPI4, RSVD2, RSVD3, 0x310c, N, N, N, 0xb40, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(uart3_cts_pd4, UARTC, SPI4, RSVD2, RSVD3, 0x3110, N, N, N, 0xb3c, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(uart4_tx_pi4, UARTD, UART, RSVD2, RSVD3, 0x3114, N, N, N, 0xb58, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(uart4_rx_pi5, UARTD, UART, RSVD2, RSVD3, 0x3118, N, N, N, 0xb54, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(uart4_rts_pi6, UARTD, UART, RSVD2, RSVD3, 0x311c, N, N, N, 0xb50, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(uart4_cts_pi7, UARTD, UART, RSVD2, RSVD3, 0x3120, N, N, N, 0xb4c, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(dap1_fs_pb0, I2S1, RSVD1, RSVD2, RSVD3, 0x3124, Y, Y, N, 0x95c, -1, -1, -1, -1, 28, 2, 30, 2), + PINGROUP(dap1_din_pb1, I2S1, RSVD1, RSVD2, RSVD3, 0x3128, Y, Y, N, 0x954, -1, -1, -1, -1, 28, 2, 30, 2), + PINGROUP(dap1_dout_pb2, I2S1, RSVD1, RSVD2, RSVD3, 0x312c, Y, Y, N, 0x958, -1, -1, -1, -1, 28, 2, 30, 2), + PINGROUP(dap1_sclk_pb3, I2S1, RSVD1, RSVD2, RSVD3, 0x3130, Y, Y, N, 0x960, -1, -1, -1, -1, 28, 2, 30, 2), + PINGROUP(dap2_fs_paa0, I2S2, RSVD1, RSVD2, RSVD3, 0x3134, Y, Y, N, 0x96c, -1, -1, -1, -1, 28, 2, 30, 2), + PINGROUP(dap2_din_paa2, I2S2, RSVD1, RSVD2, RSVD3, 0x3138, Y, Y, N, 0x964, -1, -1, -1, -1, 28, 2, 30, 2), + PINGROUP(dap2_dout_paa3, I2S2, RSVD1, RSVD2, RSVD3, 0x313c, Y, Y, N, 0x968, -1, -1, -1, -1, 28, 2, 30, 2), + PINGROUP(dap2_sclk_paa1, I2S2, RSVD1, RSVD2, RSVD3, 0x3140, Y, Y, N, 0x970, -1, -1, -1, -1, 28, 2, 30, 2), + PINGROUP(dap4_fs_pj4, I2S4B, RSVD1, RSVD2, RSVD3, 0x3144, N, N, N, 0x97c, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(dap4_din_pj5, I2S4B, RSVD1, RSVD2, RSVD3, 0x3148, N, N, N, 0x974, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(dap4_dout_pj6, I2S4B, RSVD1, RSVD2, RSVD3, 0x314c, N, N, N, 0x978, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(dap4_sclk_pj7, I2S4B, RSVD1, RSVD2, RSVD3, 0x3150, N, N, N, 0x980, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(cam1_mclk_ps0, EXTPERIPH3, RSVD1, RSVD2, RSVD3, 0x3154, N, N, N, 0x918, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(cam2_mclk_ps1, EXTPERIPH3, RSVD1, RSVD2, RSVD3, 0x3158, N, N, N, 0x924, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(jtag_rtck, JTAG, RSVD1, RSVD2, RSVD3, 0x315c, N, N, N, 0xa2c, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(clk_32k_in, CLK, RSVD1, RSVD2, RSVD3, 0x3160, N, N, N, 0x940, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(clk_32k_out_py5, SOC, BLINK, RSVD2, RSVD3, 0x3164, N, N, N, 0x944, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(batt_bcl, BCL, RSVD1, RSVD2, RSVD3, 0x3168, N, N, Y, 0x8f8, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(clk_req, SYS, RSVD1, RSVD2, RSVD3, 0x316c, N, N, N, 0x948, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(cpu_pwr_req, CPU, RSVD1, RSVD2, RSVD3, 0x3170, N, N, N, 0x950, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(pwr_int_n, PMI, RSVD1, RSVD2, RSVD3, 0x3174, N, N, N, 0xa74, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(shutdown, SHUTDOWN, RSVD1, RSVD2, RSVD3, 0x3178, N, N, N, 0xac8, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(core_pwr_req, CORE, RSVD1, RSVD2, RSVD3, 0x317c, N, N, N, 0x94c, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(aud_mclk_pbb0, AUD, RSVD1, RSVD2, RSVD3, 0x3180, N, N, N, 0x8f4, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(dvfs_pwm_pbb1, RSVD0, CLDVFS, SPI3, RSVD3, 0x3184, N, N, N, 0x9a4, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(dvfs_clk_pbb2, RSVD0, CLDVFS, SPI3, RSVD3, 0x3188, N, N, N, 0x9a0, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(gpio_x1_aud_pbb3, RSVD0, RSVD1, SPI3, RSVD3, 0x318c, N, N, N, 0xa14, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(gpio_x3_aud_pbb4, RSVD0, RSVD1, SPI3, RSVD3, 0x3190, N, N, N, 0xa18, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(pcc7, RSVD0, RSVD1, RSVD2, RSVD3, 0x3194, N, N, Y, -1, -1, -1, -1, -1, -1, -1, -1, -1), + PINGROUP(hdmi_cec_pcc0, CEC, RSVD1, RSVD2, RSVD3, 0x3198, N, N, Y, 0xa24, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(hdmi_int_dp_hpd_pcc1, DP, RSVD1, RSVD2, RSVD3, 0x319c, N, N, Y, 0xa28, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(spdif_out_pcc2, SPDIF, RSVD1, RSVD2, RSVD3, 0x31a0, N, N, N, 0xad0, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(spdif_in_pcc3, SPDIF, RSVD1, RSVD2, RSVD3, 0x31a4, N, N, N, 0xacc, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(usb_vbus_en0_pcc4, USB, RSVD1, RSVD2, RSVD3, 0x31a8, N, N, Y, 0xb5c, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(usb_vbus_en1_pcc5, USB, RSVD1, RSVD2, RSVD3, 0x31ac, N, N, Y, 0xb60, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(dp_hpd0_pcc6, DP, RSVD1, RSVD2, RSVD3, 0x31b0, N, N, N, 0x99c, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(wifi_en_ph0, RSVD0, RSVD1, RSVD2, RSVD3, 0x31b4, N, N, N, 0xb64, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(wifi_rst_ph1, RSVD0, RSVD1, RSVD2, RSVD3, 0x31b8, N, N, N, 0xb68, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(wifi_wake_ap_ph2, RSVD0, RSVD1, RSVD2, RSVD3, 0x31bc, N, N, N, 0xb6c, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(ap_wake_bt_ph3, RSVD0, UARTB, SPDIF, RSVD3, 0x31c0, N, N, N, 0x8ec, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(bt_rst_ph4, RSVD0, UARTB, SPDIF, RSVD3, 0x31c4, N, N, N, 0x8fc, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(bt_wake_ap_ph5, RSVD0, RSVD1, RSVD2, RSVD3, 0x31c8, N, N, N, 0x900, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(ap_wake_nfc_ph7, RSVD0, RSVD1, RSVD2, RSVD3, 0x31cc, N, N, N, 0x8f0, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(nfc_en_pi0, RSVD0, RSVD1, RSVD2, RSVD3, 0x31d0, N, N, N, 0xa50, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(nfc_int_pi1, RSVD0, RSVD1, RSVD2, RSVD3, 0x31d4, N, N, N, 0xa54, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(gps_en_pi2, RSVD0, RSVD1, RSVD2, RSVD3, 0x31d8, N, N, N, 0xa1c, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(gps_rst_pi3, RSVD0, RSVD1, RSVD2, RSVD3, 0x31dc, N, N, N, 0xa20, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(cam_rst_ps4, VGP1, RSVD1, RSVD2, RSVD3, 0x31e0, N, N, N, 0x93c, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(cam_af_en_ps5, VIMCLK, VGP2, RSVD2, RSVD3, 0x31e4, N, N, N, 0x92c, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(cam_flash_en_ps6, VIMCLK, VGP3, RSVD2, RSVD3, 0x31e8, N, N, N, 0x930, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(cam1_pwdn_ps7, VGP4, RSVD1, RSVD2, RSVD3, 0x31ec, N, N, N, 0x91c, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(cam2_pwdn_pt0, VGP5, RSVD1, RSVD2, RSVD3, 0x31f0, N, N, N, 0x928, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(cam1_strobe_pt1, VGP6, RSVD1, RSVD2, RSVD3, 0x31f4, N, N, N, 0x920, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(lcd_te_py2, DISPLAYA, RSVD1, RSVD2, RSVD3, 0x31f8, N, N, N, 0xa44, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(lcd_bl_pwm_pv0, DISPLAYA, PWM0, SOR0, RSVD3, 0x31fc, N, N, N, 0xa34, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(lcd_bl_en_pv1, RSVD0, RSVD1, RSVD2, RSVD3, 0x3200, N, N, N, 0xa30, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(lcd_rst_pv2, RSVD0, RSVD1, RSVD2, RSVD3, 0x3204, N, N, N, 0xa40, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(lcd_gpio1_pv3, DISPLAYB, RSVD1, RSVD2, RSVD3, 0x3208, N, N, N, 0xa38, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(lcd_gpio2_pv4, DISPLAYB, PWM1, RSVD2, SOR1, 0x320c, N, N, N, 0xa3c, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(ap_ready_pv5, RSVD0, RSVD1, RSVD2, RSVD3, 0x3210, N, N, N, 0x8e8, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(touch_rst_pv6, RSVD0, RSVD1, RSVD2, RSVD3, 0x3214, N, N, N, 0xb18, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(touch_clk_pv7, TOUCH, RSVD1, RSVD2, RSVD3, 0x3218, N, N, N, 0xb10, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(modem_wake_ap_px0, RSVD0, RSVD1, RSVD2, RSVD3, 0x321c, N, N, N, 0xa48, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(touch_int_px1, RSVD0, RSVD1, RSVD2, RSVD3, 0x3220, N, N, N, 0xb14, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(motion_int_px2, RSVD0, RSVD1, RSVD2, RSVD3, 0x3224, N, N, N, 0xa4c, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(als_prox_int_px3, RSVD0, RSVD1, RSVD2, RSVD3, 0x3228, N, N, N, 0x8e4, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(temp_alert_px4, RSVD0, RSVD1, RSVD2, RSVD3, 0x322c, N, N, N, 0xb0c, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(button_power_on_px5, RSVD0, RSVD1, RSVD2, RSVD3, 0x3230, N, N, N, 0x908, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(button_vol_up_px6, RSVD0, RSVD1, RSVD2, RSVD3, 0x3234, N, N, N, 0x914, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(button_vol_down_px7, RSVD0, RSVD1, RSVD2, RSVD3, 0x3238, N, N, N, 0x910, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(button_slide_sw_py0, RSVD0, RSVD1, RSVD2, RSVD3, 0x323c, N, N, N, 0x90c, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(button_home_py1, RSVD0, RSVD1, RSVD2, RSVD3, 0x3240, N, N, N, 0x904, 12, 5, 20, 5, -1, -1, -1, -1), + PINGROUP(pa6, SATA, RSVD1, RSVD2, RSVD3, 0x3244, N, N, N, -1, -1, -1, -1, -1, -1, -1, -1, -1), + PINGROUP(pe6, RSVD0, I2S5A, PWM2, RSVD3, 0x3248, N, N, N, -1, -1, -1, -1, -1, -1, -1, -1, -1), + PINGROUP(pe7, RSVD0, I2S5A, PWM3, RSVD3, 0x324c, N, N, N, -1, -1, -1, -1, -1, -1, -1, -1, -1), + PINGROUP(ph6, RSVD0, RSVD1, RSVD2, RSVD3, 0x3250, N, N, N, -1, -1, -1, -1, -1, -1, -1, -1, -1), + PINGROUP(pk0, IQC0, I2S5B, RSVD2, RSVD3, 0x3254, Y, Y, N, -1, -1, -1, -1, -1, -1, -1, -1, -1), + PINGROUP(pk1, IQC0, I2S5B, RSVD2, RSVD3, 0x3258, Y, Y, N, -1, -1, -1, -1, -1, -1, -1, -1, -1), + PINGROUP(pk2, IQC0, I2S5B, RSVD2, RSVD3, 0x325c, Y, Y, N, -1, -1, -1, -1, -1, -1, -1, -1, -1), + PINGROUP(pk3, IQC0, I2S5B, RSVD2, RSVD3, 0x3260, Y, Y, N, -1, -1, -1, -1, -1, -1, -1, -1, -1), + PINGROUP(pk4, IQC1, RSVD1, RSVD2, RSVD3, 0x3264, Y, Y, N, -1, -1, -1, -1, -1, -1, -1, -1, -1), + PINGROUP(pk5, IQC1, RSVD1, RSVD2, RSVD3, 0x3268, Y, Y, N, -1, -1, -1, -1, -1, -1, -1, -1, -1), + PINGROUP(pk6, IQC1, RSVD1, RSVD2, RSVD3, 0x326c, Y, Y, N, -1, -1, -1, -1, -1, -1, -1, -1, -1), + PINGROUP(pk7, IQC1, RSVD1, RSVD2, RSVD3, 0x3270, Y, Y, N, -1, -1, -1, -1, -1, -1, -1, -1, -1), + PINGROUP(pl0, RSVD0, RSVD1, RSVD2, RSVD3, 0x3274, Y, Y, N, -1, -1, -1, -1, -1, -1, -1, -1, -1), + PINGROUP(pl1, SOC, RSVD1, RSVD2, RSVD3, 0x3278, Y, Y, N, -1, -1, -1, -1, -1, -1, -1, -1, -1), + PINGROUP(pz0, VIMCLK2, RSVD1, RSVD2, RSVD3, 0x327c, N, N, N, -1, -1, -1, -1, -1, -1, -1, -1, -1), + PINGROUP(pz1, VIMCLK2, SDMMC1, RSVD2, RSVD3, 0x3280, N, N, N, -1, -1, -1, -1, -1, -1, -1, -1, -1), + PINGROUP(pz2, SDMMC3, CCLA, RSVD2, RSVD3, 0x3284, N, N, N, -1, -1, -1, -1, -1, -1, -1, -1, -1), + PINGROUP(pz3, SDMMC3, RSVD1, RSVD2, RSVD3, 0x3288, N, N, N, -1, -1, -1, -1, -1, -1, -1, -1, -1), + PINGROUP(pz4, SDMMC1, RSVD1, RSVD2, RSVD3, 0x328c, N, N, N, -1, -1, -1, -1, -1, -1, -1, -1, -1), + PINGROUP(pz5, SOC, RSVD1, RSVD2, RSVD3, 0x3290, N, N, N, -1, -1, -1, -1, -1, -1, -1, -1, -1), + + /* pg_name, r, drvdn_b, drvdn_w, drvup_b, drvup_w, slwr_b, slwr_w, slwf_b, slwf_w */ + DRV_PINGROUP(pa6, 0x9c0, 12, 5, 20, 5, -1, -1, -1, -1), + DRV_PINGROUP(pcc7, 0x9c4, 12, 5, 20, 5, -1, -1, -1, -1), + DRV_PINGROUP(pe6, 0x9c8, 12, 5, 20, 5, -1, -1, -1, -1), + DRV_PINGROUP(pe7, 0x9cc, 12, 5, 20, 5, -1, -1, -1, -1), + DRV_PINGROUP(ph6, 0x9d0, 12, 5, 20, 5, -1, -1, -1, -1), + DRV_PINGROUP(pk0, 0x9d4, -1, -1, -1, -1, 28, 2, 30, 2), + DRV_PINGROUP(pk1, 0x9d8, -1, -1, -1, -1, 28, 2, 30, 2), + DRV_PINGROUP(pk2, 0x9dc, -1, -1, -1, -1, 28, 2, 30, 2), + DRV_PINGROUP(pk3, 0x9e0, -1, -1, -1, -1, 28, 2, 30, 2), + DRV_PINGROUP(pk4, 0x9e4, -1, -1, -1, -1, 28, 2, 30, 2), + DRV_PINGROUP(pk5, 0x9e8, -1, -1, -1, -1, 28, 2, 30, 2), + DRV_PINGROUP(pk6, 0x9ec, -1, -1, -1, -1, 28, 2, 30, 2), + DRV_PINGROUP(pk7, 0x9f0, -1, -1, -1, -1, 28, 2, 30, 2), + DRV_PINGROUP(pl0, 0x9f4, -1, -1, -1, -1, 28, 2, 30, 2), + DRV_PINGROUP(pl1, 0x9f8, -1, -1, -1, -1, 28, 2, 30, 2), + DRV_PINGROUP(pz0, 0x9fc, 12, 7, 20, 7, -1, -1, -1, -1), + DRV_PINGROUP(pz1, 0xa00, 12, 7, 20, 7, -1, -1, -1, -1), + DRV_PINGROUP(pz2, 0xa04, 12, 7, 20, 7, -1, -1, -1, -1), + DRV_PINGROUP(pz3, 0xa08, 12, 7, 20, 7, -1, -1, -1, -1), + DRV_PINGROUP(pz4, 0xa0c, 12, 7, 20, 7, -1, -1, -1, -1), + DRV_PINGROUP(pz5, 0xa10, 12, 7, 20, 7, -1, -1, -1, -1), + DRV_PINGROUP(sdmmc1, 0xa98, 12, 7, 20, 7, 28, 2, 30, 2), + DRV_PINGROUP(sdmmc2, 0xa9c, 2, 6, 8, 6, 28, 2, 30, 2), + DRV_PINGROUP(sdmmc3, 0xab0, 12, 7, 20, 7, 28, 2, 30, 2), + DRV_PINGROUP(sdmmc4, 0xab4, 2, 6, 8, 6, 28, 2, 30, 2), +}; + +static const struct tegra_pinctrl_soc_data tegra210_pinctrl = { + .ngpios = NUM_GPIOS, + .pins = tegra210_pins, + .npins = ARRAY_SIZE(tegra210_pins), + .functions = tegra210_functions, + .nfunctions = ARRAY_SIZE(tegra210_functions), + .groups = tegra210_groups, + .ngroups = ARRAY_SIZE(tegra210_groups), + .hsm_in_mux = true, + .schmitt_in_mux = true, + .drvtype_in_mux = true, +}; + +static int tegra210_pinctrl_probe(struct platform_device *pdev) +{ + return tegra_pinctrl_probe(pdev, &tegra210_pinctrl); +} + +static const struct of_device_id tegra210_pinctrl_of_match[] = { + { .compatible = "nvidia,tegra210-pinmux", }, + { }, +}; +MODULE_DEVICE_TABLE(of, tegra210_pinctrl_of_match); + +static struct platform_driver tegra210_pinctrl_driver = { + .driver = { + .name = "tegra210-pinctrl", + .of_match_table = tegra210_pinctrl_of_match, + }, + .probe = tegra210_pinctrl_probe, + .remove = tegra_pinctrl_remove, +}; +module_platform_driver(tegra210_pinctrl_driver); + +MODULE_AUTHOR("NVIDIA"); +MODULE_DESCRIPTION("NVIDIA Tegra210 pinctrl driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-59-g8ed1b From 939417bd8b909ae34a3b2106531594f5115eaea5 Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Mon, 2 Mar 2015 16:55:02 +0200 Subject: pinctrl: remove maxpin from documentation struct pinctrl_desc does not contain the maxpin member since commit 0d2006bbf0 (pinctrl: remove unnecessary max pin number). Fixes: 0d2006bbf0 ('pinctrl: remove unnecessary max pin number') Signed-off-by: Baruch Siach Signed-off-by: Linus Walleij --- Documentation/pinctrl.txt | 1 - 1 file changed, 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/pinctrl.txt b/Documentation/pinctrl.txt index b8f2147b96dd..348a8af8d06c 100644 --- a/Documentation/pinctrl.txt +++ b/Documentation/pinctrl.txt @@ -72,7 +72,6 @@ static struct pinctrl_desc foo_desc = { .name = "foo", .pins = foo_pins, .npins = ARRAY_SIZE(foo_pins), - .maxpin = 63, .owner = THIS_MODULE, }; -- cgit v1.2.3-59-g8ed1b From 967beb2e87771411e08467152e3d9f1c3ae73a67 Mon Sep 17 00:00:00 2001 From: Zubair Lutfullah Kakakhel Date: Mon, 9 Mar 2015 12:11:08 +0000 Subject: ASoC: jz4740: Add jz4780 support The jz4780 and jz4740 have very similar i2s blocks. The slight difference is in Rx/Tx fifos. And the bitclocks for input/output are different. This patch adds jz4780 support to the driver Signed-off-by: Zubair Lutfullah Kakakhel Acked-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- .../bindings/sound/ingenic,jz4740-i2s.txt | 2 +- sound/soc/jz4740/jz4740-i2s.c | 84 +++++++++++++++++++--- 2 files changed, 75 insertions(+), 11 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/ingenic,jz4740-i2s.txt b/Documentation/devicetree/bindings/sound/ingenic,jz4740-i2s.txt index b41433386e2f..b623d50004fb 100644 --- a/Documentation/devicetree/bindings/sound/ingenic,jz4740-i2s.txt +++ b/Documentation/devicetree/bindings/sound/ingenic,jz4740-i2s.txt @@ -1,7 +1,7 @@ Ingenic JZ4740 I2S controller Required properties: -- compatible : "ingenic,jz4740-i2s" +- compatible : "ingenic,jz4740-i2s" or "ingenic,jz4780-i2s" - reg : I2S registers location and length - clocks : AIC and I2S PLL clock specifiers. - clock-names: "aic" and "i2s" diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c index 07f77815a586..b05fb1c1a848 100644 --- a/sound/soc/jz4740/jz4740-i2s.c +++ b/sound/soc/jz4740/jz4740-i2s.c @@ -58,6 +58,12 @@ #define JZ_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET 12 #define JZ_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET 8 +#define JZ4780_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET 24 +#define JZ4780_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET 16 +#define JZ4780_AIC_CONF_FIFO_RX_THRESHOLD_MASK \ + (0xf << JZ4780_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET) +#define JZ4780_AIC_CONF_FIFO_TX_THRESHOLD_MASK \ + (0x1f << JZ4780_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET) #define JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_MASK (0x7 << 19) #define JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_MASK (0x7 << 16) @@ -79,6 +85,7 @@ #define JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_OFFSET 16 #define JZ_AIC_I2S_FMT_DISABLE_BIT_CLK BIT(12) +#define JZ_AIC_I2S_FMT_DISABLE_BIT_ICLK BIT(13) #define JZ_AIC_I2S_FMT_ENABLE_SYS_CLK BIT(4) #define JZ_AIC_I2S_FMT_MSB BIT(0) @@ -87,6 +94,13 @@ #define JZ_AIC_CLK_DIV_MASK 0xf #define I2SDIV_DV_SHIFT 8 #define I2SDIV_DV_MASK (0xf << I2SDIV_DV_SHIFT) +#define I2SDIV_IDV_SHIFT 8 +#define I2SDIV_IDV_MASK (0xf << I2SDIV_IDV_SHIFT) + +enum jz47xx_i2s_version { + JZ_I2S_JZ4740, + JZ_I2S_JZ4780, +}; struct jz4740_i2s { struct resource *mem; @@ -98,6 +112,8 @@ struct jz4740_i2s { struct snd_dmaengine_dai_dma_data playback_dma_data; struct snd_dmaengine_dai_dma_data capture_dma_data; + + enum jz47xx_i2s_version version; }; static inline uint32_t jz4740_i2s_read(const struct jz4740_i2s *i2s, @@ -267,13 +283,22 @@ static int jz4740_i2s_hw_params(struct snd_pcm_substream *substream, ctrl |= JZ_AIC_CTRL_MONO_TO_STEREO; else ctrl &= ~JZ_AIC_CTRL_MONO_TO_STEREO; + + div_reg &= ~I2SDIV_DV_MASK; + div_reg |= (div - 1) << I2SDIV_DV_SHIFT; } else { ctrl &= ~JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_MASK; ctrl |= sample_size << JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_OFFSET; + + if (i2s->version >= JZ_I2S_JZ4780) { + div_reg &= ~I2SDIV_IDV_MASK; + div_reg |= (div - 1) << I2SDIV_IDV_SHIFT; + } else { + div_reg &= ~I2SDIV_DV_MASK; + div_reg |= (div - 1) << I2SDIV_DV_SHIFT; + } } - div_reg &= ~I2SDIV_DV_MASK; - div_reg |= (div - 1) << I2SDIV_DV_SHIFT; jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl); jz4740_i2s_write(i2s, JZ_REG_AIC_CLK_DIV, div_reg); @@ -369,11 +394,19 @@ static int jz4740_i2s_dai_probe(struct snd_soc_dai *dai) snd_soc_dai_init_dma_data(dai, &i2s->playback_dma_data, &i2s->capture_dma_data); - conf = (7 << JZ_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET) | - (8 << JZ_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET) | - JZ_AIC_CONF_OVERFLOW_PLAY_LAST | - JZ_AIC_CONF_I2S | - JZ_AIC_CONF_INTERNAL_CODEC; + if (i2s->version >= JZ_I2S_JZ4780) { + conf = (7 << JZ4780_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET) | + (8 << JZ4780_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET) | + JZ_AIC_CONF_OVERFLOW_PLAY_LAST | + JZ_AIC_CONF_I2S | + JZ_AIC_CONF_INTERNAL_CODEC; + } else { + conf = (7 << JZ_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET) | + (8 << JZ_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET) | + JZ_AIC_CONF_OVERFLOW_PLAY_LAST | + JZ_AIC_CONF_I2S | + JZ_AIC_CONF_INTERNAL_CODEC; + } jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, JZ_AIC_CONF_RESET); jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf); @@ -422,13 +455,34 @@ static struct snd_soc_dai_driver jz4740_i2s_dai = { .resume = jz4740_i2s_resume, }; +static struct snd_soc_dai_driver jz4780_i2s_dai = { + .probe = jz4740_i2s_dai_probe, + .remove = jz4740_i2s_dai_remove, + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = JZ4740_I2S_FMTS, + }, + .capture = { + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = JZ4740_I2S_FMTS, + }, + .ops = &jz4740_i2s_dai_ops, + .suspend = jz4740_i2s_suspend, + .resume = jz4740_i2s_resume, +}; + static const struct snd_soc_component_driver jz4740_i2s_component = { .name = "jz4740-i2s", }; #ifdef CONFIG_OF static const struct of_device_id jz4740_of_matches[] = { - { .compatible = "ingenic,jz4740-i2s" }, + { .compatible = "ingenic,jz4740-i2s", .data = (void *)JZ_I2S_JZ4740 }, + { .compatible = "ingenic,jz4780-i2s", .data = (void *)JZ_I2S_JZ4780 }, { /* sentinel */ } }; #endif @@ -438,11 +492,16 @@ static int jz4740_i2s_dev_probe(struct platform_device *pdev) struct jz4740_i2s *i2s; struct resource *mem; int ret; + const struct of_device_id *match; i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL); if (!i2s) return -ENOMEM; + match = of_match_device(jz4740_of_matches, &pdev->dev); + if (match) + i2s->version = (enum jz47xx_i2s_version)match->data; + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); i2s->base = devm_ioremap_resource(&pdev->dev, mem); if (IS_ERR(i2s->base)) @@ -460,8 +519,13 @@ static int jz4740_i2s_dev_probe(struct platform_device *pdev) platform_set_drvdata(pdev, i2s); - ret = devm_snd_soc_register_component(&pdev->dev, - &jz4740_i2s_component, &jz4740_i2s_dai, 1); + if (i2s->version == JZ_I2S_JZ4780) + ret = devm_snd_soc_register_component(&pdev->dev, + &jz4740_i2s_component, &jz4780_i2s_dai, 1); + else + ret = devm_snd_soc_register_component(&pdev->dev, + &jz4740_i2s_component, &jz4740_i2s_dai, 1); + if (ret) return ret; -- cgit v1.2.3-59-g8ed1b From e39ce48f5362df9f87400b4909a6fb0f51b109ac Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 11 Feb 2015 19:35:27 -0800 Subject: regulator: Rename regulator_set_optimum_mode Rename the regulator_set_optimum_mode() function regulator_set_load() to better represent what's going on. Signed-off-by: Bjorn Andersson Signed-off-by: Mark Brown --- Documentation/power/regulator/consumer.txt | 2 +- drivers/regulator/core.c | 8 ++++---- include/linux/regulator/consumer.h | 12 +++++++++--- 3 files changed, 14 insertions(+), 8 deletions(-) (limited to 'Documentation') diff --git a/Documentation/power/regulator/consumer.txt b/Documentation/power/regulator/consumer.txt index 8afb236ca765..e51564c1a140 100644 --- a/Documentation/power/regulator/consumer.txt +++ b/Documentation/power/regulator/consumer.txt @@ -137,7 +137,7 @@ Indirect operating mode control. Consumer drivers can request a change in their supply regulator operating mode by calling :- -int regulator_set_optimum_mode(struct regulator *regulator, int load_uA); +int regulator_set_load(struct regulator *regulator, int load_uA); This will cause the core to recalculate the total load on the regulator (based on all its consumers) and change operating mode (if necessary and permitted) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index b899947d839d..03088f9c3d4f 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2994,7 +2994,7 @@ unsigned int regulator_get_mode(struct regulator *regulator) EXPORT_SYMBOL_GPL(regulator_get_mode); /** - * regulator_set_optimum_mode - set regulator optimum operating mode + * regulator_set_load - set regulator load * @regulator: regulator source * @uA_load: load current * @@ -3017,9 +3017,9 @@ EXPORT_SYMBOL_GPL(regulator_get_mode); * DRMS will sum the total requested load on the regulator and change * to the most efficient operating mode if platform constraints allow. * - * Returns the new regulator mode or error. + * On error a negative errno is returned. */ -int regulator_set_optimum_mode(struct regulator *regulator, int uA_load) +int regulator_set_load(struct regulator *regulator, int uA_load) { struct regulator_dev *rdev = regulator->rdev; int ret; @@ -3031,7 +3031,7 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load) return ret; } -EXPORT_SYMBOL_GPL(regulator_set_optimum_mode); +EXPORT_SYMBOL_GPL(regulator_set_load); /** * regulator_allow_bypass - allow the regulator to go into bypass mode diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h index d17e1ff7ad01..6d4e9d2289f0 100644 --- a/include/linux/regulator/consumer.h +++ b/include/linux/regulator/consumer.h @@ -238,7 +238,7 @@ int regulator_get_current_limit(struct regulator *regulator); int regulator_set_mode(struct regulator *regulator, unsigned int mode); unsigned int regulator_get_mode(struct regulator *regulator); -int regulator_set_optimum_mode(struct regulator *regulator, int load_uA); +int regulator_set_load(struct regulator *regulator, int load_uA); int regulator_allow_bypass(struct regulator *regulator, bool allow); @@ -479,8 +479,7 @@ static inline unsigned int regulator_get_mode(struct regulator *regulator) return REGULATOR_MODE_NORMAL; } -static inline int regulator_set_optimum_mode(struct regulator *regulator, - int load_uA) +static inline int regulator_set_load(struct regulator *regulator, int load_uA) { return REGULATOR_MODE_NORMAL; } @@ -555,4 +554,11 @@ static inline int regulator_is_supported_voltage_tol(struct regulator *regulator target_uV + tol_uV); } +/* TEMP: Wrapper to keep bisectability */ +static inline int regulator_set_optimum_mode(struct regulator *regulator, + int load_uA) +{ + return regulator_set_load(regulator, load_uA); +} + #endif -- cgit v1.2.3-59-g8ed1b From ca1bb4ee4c3a017bb66840d11d5efdf4e8f3f66d Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Mon, 23 Feb 2015 16:11:41 -0800 Subject: leds: Introduce devres helper for led_classdev_register (cooloney@gmail.com: add _unregister function into the document) Suggested-by: Stephen Boyd Signed-off-by: Bjorn Andersson Signed-off-by: Bryan Wu --- Documentation/driver-model/devres.txt | 4 +++ drivers/leds/led-class.c | 57 +++++++++++++++++++++++++++++++++++ include/linux/leds.h | 4 +++ 3 files changed, 65 insertions(+) (limited to 'Documentation') diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt index 6d1e8eeb5990..e1e2bbd7a404 100644 --- a/Documentation/driver-model/devres.txt +++ b/Documentation/driver-model/devres.txt @@ -289,6 +289,10 @@ IRQ devm_request_irq() devm_request_threaded_irq() +LED + devm_led_classdev_register() + devm_led_classdev_unregister() + MDIO devm_mdiobus_alloc() devm_mdiobus_alloc_size() diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index 795ec994c663..768d33a79881 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -288,6 +288,63 @@ void led_classdev_unregister(struct led_classdev *led_cdev) } EXPORT_SYMBOL_GPL(led_classdev_unregister); +static void devm_led_classdev_release(struct device *dev, void *res) +{ + led_classdev_unregister(*(struct led_classdev **)res); +} + +/** + * devm_led_classdev_register - resource managed led_classdev_register() + * @parent: The device to register. + * @led_cdev: the led_classdev structure for this device. + */ +int devm_led_classdev_register(struct device *parent, + struct led_classdev *led_cdev) +{ + struct led_classdev **dr; + int rc; + + dr = devres_alloc(devm_led_classdev_release, sizeof(*dr), GFP_KERNEL); + if (!dr) + return -ENOMEM; + + rc = led_classdev_register(parent, led_cdev); + if (rc) { + devres_free(dr); + return rc; + } + + *dr = led_cdev; + devres_add(parent, dr); + + return 0; +} +EXPORT_SYMBOL_GPL(devm_led_classdev_register); + +static int devm_led_classdev_match(struct device *dev, void *res, void *data) +{ + struct led_cdev **p = res; + + if (WARN_ON(!p || !*p)) + return 0; + + return *p == data; +} + +/** + * devm_led_classdev_unregister() - resource managed led_classdev_unregister() + * @parent: The device to unregister. + * @led_cdev: the led_classdev structure for this device. + */ +void devm_led_classdev_unregister(struct device *dev, + struct led_classdev *led_cdev) +{ + WARN_ON(devres_release(dev, + devm_led_classdev_release, + devm_led_classdev_match, led_cdev)); +} +EXPORT_SYMBOL_GPL(devm_led_classdev_unregister); + static int __init leds_init(void) { leds_class = class_create(THIS_MODULE, "leds"); diff --git a/include/linux/leds.h b/include/linux/leds.h index f70f84f35674..ed634279062e 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h @@ -105,7 +105,11 @@ struct led_classdev { extern int led_classdev_register(struct device *parent, struct led_classdev *led_cdev); +extern int devm_led_classdev_register(struct device *parent, + struct led_classdev *led_cdev); extern void led_classdev_unregister(struct led_classdev *led_cdev); +extern void devm_led_classdev_unregister(struct device *parent, + struct led_classdev *led_cdev); extern void led_classdev_suspend(struct led_classdev *led_cdev); extern void led_classdev_resume(struct led_classdev *led_cdev); -- cgit v1.2.3-59-g8ed1b From 9c4a8e138cfe2cc7262d5d2224162add5632b546 Mon Sep 17 00:00:00 2001 From: Jacek Anaszewski Date: Wed, 4 Mar 2015 08:14:23 -0800 Subject: leds: flash: document sysfs interface Add a documentation of LED Flash class specific sysfs attributes. Signed-off-by: Jacek Anaszewski Acked-by: Kyungmin Park Cc: Richard Purdie Signed-off-by: Bryan Wu --- Documentation/ABI/testing/sysfs-class-led-flash | 80 +++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-class-led-flash (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-class-led-flash b/Documentation/ABI/testing/sysfs-class-led-flash new file mode 100644 index 000000000000..220a0270b47b --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-led-flash @@ -0,0 +1,80 @@ +What: /sys/class/leds//flash_brightness +Date: March 2015 +KernelVersion: 4.0 +Contact: Jacek Anaszewski +Description: read/write + Set the brightness of this LED in the flash strobe mode, in + microamperes. The file is created only for the flash LED devices + that support setting flash brightness. + + The value is between 0 and + /sys/class/leds//max_flash_brightness. + +What: /sys/class/leds//max_flash_brightness +Date: March 2015 +KernelVersion: 4.0 +Contact: Jacek Anaszewski +Description: read only + Maximum brightness level for this LED in the flash strobe mode, + in microamperes. + +What: /sys/class/leds//flash_timeout +Date: March 2015 +KernelVersion: 4.0 +Contact: Jacek Anaszewski +Description: read/write + Hardware timeout for flash, in microseconds. The flash strobe + is stopped after this period of time has passed from the start + of the strobe. The file is created only for the flash LED + devices that support setting flash timeout. + +What: /sys/class/leds//max_flash_timeout +Date: March 2015 +KernelVersion: 4.0 +Contact: Jacek Anaszewski +Description: read only + Maximum flash timeout for this LED, in microseconds. + +What: /sys/class/leds//flash_strobe +Date: March 2015 +KernelVersion: 4.0 +Contact: Jacek Anaszewski +Description: read/write + Flash strobe state. When written with 1 it triggers flash strobe + and when written with 0 it turns the flash off. + + On read 1 means that flash is currently strobing and 0 means + that flash is off. + +What: /sys/class/leds//flash_fault +Date: March 2015 +KernelVersion: 4.0 +Contact: Jacek Anaszewski +Description: read only + Space separated list of flash faults that may have occurred. + Flash faults are re-read after strobing the flash. Possible + flash faults: + + * led-over-voltage - flash controller voltage to the flash LED + has exceeded the limit specific to the flash controller + * flash-timeout-exceeded - the flash strobe was still on when + the timeout set by the user has expired; not all flash + controllers may set this in all such conditions + * controller-over-temperature - the flash controller has + overheated + * controller-short-circuit - the short circuit protection + of the flash controller has been triggered + * led-power-supply-over-current - current in the LED power + supply has exceeded the limit specific to the flash + controller + * indicator-led-fault - the flash controller has detected + a short or open circuit condition on the indicator LED + * led-under-voltage - flash controller voltage to the flash + LED has been below the minimum limit specific to + the flash + * controller-under-voltage - the input voltage of the flash + controller is below the limit under which strobing the + flash at full current will not be possible; + the condition persists until this flag is no longer set + * led-over-temperature - the temperature of the LED has exceeded + its allowed upper limit -- cgit v1.2.3-59-g8ed1b From f6ad395bad57dcd15c6423715d15d91363a62ae8 Mon Sep 17 00:00:00 2001 From: Jacek Anaszewski Date: Wed, 4 Mar 2015 08:14:24 -0800 Subject: Documentation: leds: Add description of LED Flash class extension The documentation being added contains overall description of the LED Flash Class and the related sysfs attributes. Signed-off-by: Jacek Anaszewski Acked-by: Kyungmin Park Cc: Richard Purdie Signed-off-by: Bryan Wu --- Documentation/leds/leds-class-flash.txt | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 Documentation/leds/leds-class-flash.txt (limited to 'Documentation') diff --git a/Documentation/leds/leds-class-flash.txt b/Documentation/leds/leds-class-flash.txt new file mode 100644 index 000000000000..19bb67355424 --- /dev/null +++ b/Documentation/leds/leds-class-flash.txt @@ -0,0 +1,22 @@ + +Flash LED handling under Linux +============================== + +Some LED devices provide two modes - torch and flash. In the LED subsystem +those modes are supported by LED class (see Documentation/leds/leds-class.txt) +and LED Flash class respectively. The torch mode related features are enabled +by default and the flash ones only if a driver declares it by setting +LED_DEV_CAP_FLASH flag. + +In order to enable the support for flash LEDs CONFIG_LEDS_CLASS_FLASH symbol +must be defined in the kernel config. A LED Flash class driver must be +registered in the LED subsystem with led_classdev_flash_register function. + +Following sysfs attributes are exposed for controlling flash LED devices: +(see Documentation/ABI/testing/sysfs-class-led-flash) + - flash_brightness + - max_flash_brightness + - flash_timeout + - max_flash_timeout + - flash_strobe + - flash_fault -- cgit v1.2.3-59-g8ed1b From eac68e8f979b82d257eea0a4bbcda7b169d330bf Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Mon, 9 Mar 2015 15:06:12 +0100 Subject: usb: dwc3: make LPM configurable in DT This patch removes "Enable USB3 LPM Capability" option from Kconfig and adds snps,usb3_lpm_capable devicetree property instead of it. USB3 LPM (Link Power Management) capability is hardware property, and it's platform dependent, so if our hardware supports this feature, we want rather to configure it in devicetree than having it as Kconfig option. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- Documentation/devicetree/bindings/usb/dwc3.txt | 1 + drivers/usb/dwc3/Kconfig | 7 ------- drivers/usb/dwc3/core.c | 3 +++ drivers/usb/dwc3/core.h | 2 ++ drivers/usb/dwc3/host.c | 4 +--- drivers/usb/dwc3/platform_data.h | 1 + 6 files changed, 8 insertions(+), 10 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt index cd7f0454e13a..5cc364309edb 100644 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ b/Documentation/devicetree/bindings/usb/dwc3.txt @@ -14,6 +14,7 @@ Optional properties: - phys: from the *Generic PHY* bindings - phy-names: from the *Generic PHY* bindings - tx-fifo-resize: determines if the FIFO *has* to be reallocated. + - snps,usb3_lpm_capable: determines if platform is USB3 LPM capable - snps,disable_scramble_quirk: true when SW should disable data scrambling. Only really useful for FPGA builds. - snps,has-lpm-erratum: true when DWC3 was configured with LPM Erratum enabled diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index edbf9c85af7e..827c4f80379f 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -104,11 +104,4 @@ config USB_DWC3_DEBUG help Say Y here to enable debugging messages on DWC3 Driver. -config DWC3_HOST_USB3_LPM_ENABLE - bool "Enable USB3 LPM Capability" - depends on USB_DWC3_HOST=y || USB_DWC3_DUAL_ROLE=y - default n - help - Select this when you want to enable USB3 LPM with dwc3 xhci host. - endif diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index cd59e919e27e..2bbab3d86fff 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -804,6 +804,8 @@ static int dwc3_probe(struct platform_device *pdev) "snps,is-utmi-l1-suspend"); of_property_read_u8(node, "snps,hird-threshold", &hird_threshold); + dwc->usb3_lpm_capable = of_property_read_bool(node, + "snps,usb3_lpm_capable"); dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize"); @@ -844,6 +846,7 @@ static int dwc3_probe(struct platform_device *pdev) hird_threshold = pdata->hird_threshold; dwc->needs_fifo_resize = pdata->tx_fifo_resize; + dwc->usb3_lpm_capable = pdata->usb3_lpm_capable; dwc->dr_mode = pdata->dr_mode; dwc->disable_scramble_quirk = pdata->disable_scramble_quirk; diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index d201910b892f..fdab715a0631 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -689,6 +689,7 @@ struct dwc3_scratchpad_array { * @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround * @start_config_issued: true when StartConfig command has been issued * @three_stage_setup: set if we perform a three phase setup + * @usb3_lpm_capable: set if hadrware supports Link Power Management * @disable_scramble_quirk: set if we enable the disable scramble quirk * @u2exit_lfps_quirk: set if we enable u2exit lfps quirk * @u2ss_inp3_quirk: set if we enable P3 OK for U2/SS Inactive quirk @@ -812,6 +813,7 @@ struct dwc3 { unsigned setup_packet_pending:1; unsigned start_config_issued:1; unsigned three_stage_setup:1; + unsigned usb3_lpm_capable:1; unsigned disable_scramble_quirk:1; unsigned u2exit_lfps_quirk:1; diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c index 12bfd3c5405e..c679f63783ae 100644 --- a/drivers/usb/dwc3/host.c +++ b/drivers/usb/dwc3/host.c @@ -49,9 +49,7 @@ int dwc3_host_init(struct dwc3 *dwc) memset(&pdata, 0, sizeof(pdata)); -#ifdef CONFIG_DWC3_HOST_USB3_LPM_ENABLE - pdata.usb3_lpm_capable = 1; -#endif + pdata.usb3_lpm_capable = dwc->usb3_lpm_capable; ret = platform_device_add_data(xhci, &pdata, sizeof(pdata)); if (ret) { diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h index a3a3b6d5668c..a2bd464be828 100644 --- a/drivers/usb/dwc3/platform_data.h +++ b/drivers/usb/dwc3/platform_data.h @@ -24,6 +24,7 @@ struct dwc3_platform_data { enum usb_device_speed maximum_speed; enum usb_dr_mode dr_mode; bool tx_fifo_resize; + bool usb3_lpm_capable; unsigned is_utmi_l1_suspend:1; u8 hird_threshold; -- cgit v1.2.3-59-g8ed1b From ee1cd515e889d222f5a7397fead0a9db1214edea Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Tue, 3 Mar 2015 10:52:32 +0100 Subject: usb: gadget: printer: add configfs support Add support for configfs interface so that f_printer can be used as a component of usb gadgets composed with it. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Felipe Balbi --- .../ABI/testing/configfs-usb-gadget-printer | 9 ++ Documentation/usb/gadget-testing.txt | 47 ++++++++ drivers/usb/gadget/Kconfig | 13 +++ drivers/usb/gadget/function/f_printer.c | 130 ++++++++++++++++++++- drivers/usb/gadget/function/u_printer.h | 7 ++ 5 files changed, 204 insertions(+), 2 deletions(-) create mode 100644 Documentation/ABI/testing/configfs-usb-gadget-printer (limited to 'Documentation') diff --git a/Documentation/ABI/testing/configfs-usb-gadget-printer b/Documentation/ABI/testing/configfs-usb-gadget-printer new file mode 100644 index 000000000000..6b0714e3c605 --- /dev/null +++ b/Documentation/ABI/testing/configfs-usb-gadget-printer @@ -0,0 +1,9 @@ +What: /config/usb-gadget/gadget/functions/printer.name +Date: Apr 2015 +KernelVersion: 4.1 +Description: + The attributes: + + pnp_string - Data to be passed to the host in pnp string + q_len - Number of requests per endpoint + diff --git a/Documentation/usb/gadget-testing.txt b/Documentation/usb/gadget-testing.txt index 076ac7ba7f93..f45b2bf4b41d 100644 --- a/Documentation/usb/gadget-testing.txt +++ b/Documentation/usb/gadget-testing.txt @@ -19,6 +19,7 @@ provided by gadgets. 16. UAC1 function 17. UAC2 function 18. UVC function +19. PRINTER function 1. ACM function @@ -726,3 +727,49 @@ with these patches: http://www.spinics.net/lists/linux-usb/msg99220.html host: luvcview -f yuv + +19. PRINTER function +==================== + +The function is provided by usb_f_printer.ko module. + +Function-specific configfs interface +------------------------------------ + +The function name to use when creating the function directory is "printer". +The printer function provides these attributes in its function directory: + + pnp_string - Data to be passed to the host in pnp string + q_len - Number of requests per endpoint + +Testing the PRINTER function +---------------------------- + +The most basic testing: + +device: run the gadget +# ls -l /devices/virtual/usb_printer_gadget/ + +should show g_printer. + +If udev is active, then /dev/g_printer should appear automatically. + +host: + +If udev is active, then e.g. /dev/usb/lp0 should appear. + +host->device transmission: + +device: +# cat /dev/g_printer +host: +# cat > /dev/usb/lp0 + +device->host transmission: + +# cat > /dev/g_printer +host: +# cat /dev/usb/lp0 + +More advanced testing can be done with the prn_example +described in Documentation/usb/gadget-printer.txt. diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 9d507cf98f94..3bb0e67fded2 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -437,6 +437,19 @@ config USB_CONFIGFS_F_UVC device. It provides a userspace API to process UVC control requests and stream video data to the host. +config USB_CONFIGFS_F_PRINTER + bool "Printer function" + select USB_F_PRINTER + help + The Printer function channels data between the USB host and a + userspace program driving the print engine. The user space + program reads and writes the device file /dev/g_printer to + receive or send printer data. It can use ioctl calls to + the device file to get or set printer status. + + For more information, see Documentation/usb/gadget_printer.txt + which includes sample code for accessing the device file. + source "drivers/usb/gadget/legacy/Kconfig" endchoice diff --git a/drivers/usb/gadget/function/f_printer.c b/drivers/usb/gadget/function/f_printer.c index 7afe17d76f17..757fcf070013 100644 --- a/drivers/usb/gadget/function/f_printer.c +++ b/drivers/usb/gadget/function/f_printer.c @@ -1140,6 +1140,117 @@ static void printer_func_disable(struct usb_function *f) spin_unlock_irqrestore(&dev->lock, flags); } +static inline struct f_printer_opts +*to_f_printer_opts(struct config_item *item) +{ + return container_of(to_config_group(item), struct f_printer_opts, + func_inst.group); +} + +CONFIGFS_ATTR_STRUCT(f_printer_opts); +CONFIGFS_ATTR_OPS(f_printer_opts); + +static void printer_attr_release(struct config_item *item) +{ + struct f_printer_opts *opts = to_f_printer_opts(item); + + usb_put_function_instance(&opts->func_inst); +} + +static struct configfs_item_operations printer_item_ops = { + .release = printer_attr_release, + .show_attribute = f_printer_opts_attr_show, + .store_attribute = f_printer_opts_attr_store, +}; + +static ssize_t f_printer_opts_pnp_string_show(struct f_printer_opts *opts, + char *page) +{ + int result; + + mutex_lock(&opts->lock); + result = strlcpy(page, opts->pnp_string + 2, PNP_STRING_LEN - 2); + mutex_unlock(&opts->lock); + + return result; +} + +static ssize_t f_printer_opts_pnp_string_store(struct f_printer_opts *opts, + const char *page, size_t len) +{ + int result, l; + + mutex_lock(&opts->lock); + result = strlcpy(opts->pnp_string + 2, page, PNP_STRING_LEN - 2); + l = strlen(opts->pnp_string + 2) + 2; + opts->pnp_string[0] = (l >> 8) & 0xFF; + opts->pnp_string[1] = l & 0xFF; + mutex_unlock(&opts->lock); + + return result; +} + +static struct f_printer_opts_attribute f_printer_opts_pnp_string = + __CONFIGFS_ATTR(pnp_string, S_IRUGO | S_IWUSR, + f_printer_opts_pnp_string_show, + f_printer_opts_pnp_string_store); + +static ssize_t f_printer_opts_q_len_show(struct f_printer_opts *opts, + char *page) +{ + int result; + + mutex_lock(&opts->lock); + result = sprintf(page, "%d\n", opts->q_len); + mutex_unlock(&opts->lock); + + return result; +} + +static ssize_t f_printer_opts_q_len_store(struct f_printer_opts *opts, + const char *page, size_t len) +{ + int ret; + u16 num; + + mutex_lock(&opts->lock); + if (opts->refcnt) { + ret = -EBUSY; + goto end; + } + + ret = kstrtou16(page, 0, &num); + if (ret) + goto end; + + if (num > 65535) { + ret = -EINVAL; + goto end; + } + + opts->q_len = (unsigned)num; + ret = len; +end: + mutex_unlock(&opts->lock); + return ret; +} + +static struct f_printer_opts_attribute f_printer_opts_q_len = + __CONFIGFS_ATTR(q_len, S_IRUGO | S_IWUSR, f_printer_opts_q_len_show, + f_printer_opts_q_len_store); + +static struct configfs_attribute *printer_attrs[] = { + &f_printer_opts_pnp_string.attr, + &f_printer_opts_q_len.attr, + NULL, +}; + +static struct config_item_type printer_func_type = { + .ct_item_ops = &printer_item_ops, + .ct_attrs = printer_attrs, + .ct_owner = THIS_MODULE, +}; + static inline int gprinter_get_minor(void) { return ida_simple_get(&printer_ida, 0, 0, GFP_KERNEL); @@ -1180,6 +1291,7 @@ static struct usb_function_instance *gprinter_alloc_inst(void) if (!opts) return ERR_PTR(-ENOMEM); + mutex_init(&opts->lock); opts->func_inst.free_func_inst = gprinter_free_inst; ret = &opts->func_inst; @@ -1201,6 +1313,8 @@ static struct usb_function_instance *gprinter_alloc_inst(void) if (idr_is_empty(&printer_ida.idr)) gprinter_cleanup(); } + config_group_init_type_name(&opts->func_inst.group, "", + &printer_func_type); unlock: mutex_unlock(&printer_ida_lock); @@ -1210,8 +1324,13 @@ unlock: static void gprinter_free(struct usb_function *f) { struct printer_dev *dev = func_to_printer(f); + struct f_printer_opts *opts; + opts = container_of(f->fi, struct f_printer_opts, func_inst); kfree(dev); + mutex_lock(&opts->lock); + --opts->refcnt; + mutex_unlock(&opts->lock); } static void printer_func_unbind(struct usb_configuration *c, @@ -1265,16 +1384,23 @@ static struct usb_function *gprinter_alloc(struct usb_function_instance *fi) opts = container_of(fi, struct f_printer_opts, func_inst); - if (opts->minor >= minors) + mutex_lock(&opts->lock); + if (opts->minor >= minors) { + mutex_unlock(&opts->lock); return ERR_PTR(-ENOENT); + } dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) + if (!dev) { + mutex_unlock(&opts->lock); return ERR_PTR(-ENOMEM); + } + ++opts->refcnt; dev->minor = opts->minor; dev->pnp_string = opts->pnp_string; dev->q_len = opts->q_len; + mutex_unlock(&opts->lock); dev->function.name = "printer"; dev->function.bind = printer_func_bind; diff --git a/drivers/usb/gadget/function/u_printer.h b/drivers/usb/gadget/function/u_printer.h index b2338cacdfe4..0e2c49d4274e 100644 --- a/drivers/usb/gadget/function/u_printer.h +++ b/drivers/usb/gadget/function/u_printer.h @@ -25,6 +25,13 @@ struct f_printer_opts { int minor; char pnp_string[PNP_STRING_LEN]; unsigned q_len; + + /* + * Protect the data from concurrent access by read/write + * and create symlink/remove symlink + */ + struct mutex lock; + int refcnt; }; #endif /* U_PRINTER_H */ -- cgit v1.2.3-59-g8ed1b From b78ce7ed54093e5e63d4f5d7cbdc3f7d42ebbd5c Mon Sep 17 00:00:00 2001 From: Adrian Remonda Date: Tue, 10 Mar 2015 16:12:30 -0400 Subject: spi: spidev_test: Cleaned hexadecimal dump Signed-off-by: Adrian Remonda Signed-off-by: Mark Brown --- Documentation/spi/spidev_test.c | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/spi/spidev_test.c b/Documentation/spi/spidev_test.c index 3a2f9d59edab..9cb09184a3d6 100644 --- a/Documentation/spi/spidev_test.c +++ b/Documentation/spi/spidev_test.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -35,6 +36,33 @@ static uint8_t bits = 8; static uint32_t speed = 500000; static uint16_t delay; +static void hex_dump(const void *src, size_t length, size_t line_size, char *prefix) +{ + int i = 0; + const unsigned char *address = src; + const unsigned char *line = address; + unsigned char c; + + printf("%s | ", prefix); + while (length-- > 0) { + printf("%02X ", *address++); + if (!(++i % line_size) || (length == 0 && i % line_size)) { + if (length == 0) { + while (i++ % line_size) + printf("__ "); + } + printf(" | "); /* right close */ + while (line < address) { + c = *line++; + printf("%c", (c < 33 || c == 255) ? 0x2E : c); + } + printf("\n"); + if (length > 0) + printf("%s | ", prefix); + } + } +} + static void transfer(int fd) { int ret; @@ -76,12 +104,7 @@ static void transfer(int fd) if (ret < 1) pabort("can't send spi message"); - for (ret = 0; ret < ARRAY_SIZE(tx); ret++) { - if (!(ret % 6)) - puts(""); - printf("%.2X ", rx[ret]); - } - puts(""); + hex_dump(rx, ARRAY_SIZE(rx), 32, "RX"); } static void print_usage(const char *prog) -- cgit v1.2.3-59-g8ed1b From 31a5c5a72b90e074bd2377ada2bdfd506801ed72 Mon Sep 17 00:00:00 2001 From: Adrian Remonda Date: Tue, 10 Mar 2015 16:12:31 -0400 Subject: spi: spidev_test: Added verbose output Signed-off-by: Adrian Remonda Signed-off-by: Mark Brown --- Documentation/spi/spidev_test.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/spi/spidev_test.c b/Documentation/spi/spidev_test.c index 9cb09184a3d6..4b6a3803638b 100644 --- a/Documentation/spi/spidev_test.c +++ b/Documentation/spi/spidev_test.c @@ -35,6 +35,7 @@ static uint32_t mode; static uint8_t bits = 8; static uint32_t speed = 500000; static uint16_t delay; +static int verbose; static void hex_dump(const void *src, size_t length, size_t line_size, char *prefix) { @@ -104,6 +105,8 @@ static void transfer(int fd) if (ret < 1) pabort("can't send spi message"); + if (verbose) + hex_dump(tx, ARRAY_SIZE(tx), 32, "TX"); hex_dump(rx, ARRAY_SIZE(rx), 32, "RX"); } @@ -120,6 +123,7 @@ static void print_usage(const char *prog) " -L --lsb least significant bit first\n" " -C --cs-high chip select active high\n" " -3 --3wire SI/SO signals shared\n" + " -v --verbose Verbose (show tx buffer)\n" " -N --no-cs no chip select\n" " -R --ready slave pulls low to pause\n" " -2 --dual dual transfer\n" @@ -144,12 +148,13 @@ static void parse_opts(int argc, char *argv[]) { "no-cs", 0, 0, 'N' }, { "ready", 0, 0, 'R' }, { "dual", 0, 0, '2' }, + { "verbose", 0, 0, 'v' }, { "quad", 0, 0, '4' }, { NULL, 0, 0, 0 }, }; int c; - c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR24", lopts, NULL); + c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR24:v", lopts, NULL); if (c == -1) break; @@ -188,6 +193,9 @@ static void parse_opts(int argc, char *argv[]) case 'N': mode |= SPI_NO_CS; break; + case 'v': + verbose = 1; + break; case 'R': mode |= SPI_READY; break; -- cgit v1.2.3-59-g8ed1b From 30061915be6e3a2c2a4bc4f22a229d4eb7b7cc65 Mon Sep 17 00:00:00 2001 From: Adrian Remonda Date: Tue, 10 Mar 2015 16:12:32 -0400 Subject: spi: spidev_test: Added input buffer from the terminal Signed-off-by: Adrian Remonda Signed-off-by: Mark Brown --- Documentation/spi/spidev_test.c | 76 ++++++++++++++++++++++++++++++++--------- 1 file changed, 60 insertions(+), 16 deletions(-) (limited to 'Documentation') diff --git a/Documentation/spi/spidev_test.c b/Documentation/spi/spidev_test.c index 4b6a3803638b..94f574b0fdb2 100644 --- a/Documentation/spi/spidev_test.c +++ b/Documentation/spi/spidev_test.c @@ -37,6 +37,18 @@ static uint32_t speed = 500000; static uint16_t delay; static int verbose; +uint8_t default_tx[] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x95, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0x0D, +}; + +uint8_t default_rx[ARRAY_SIZE(default_tx)] = {0, }; +char *input_tx; + static void hex_dump(const void *src, size_t length, size_t line_size, char *prefix) { int i = 0; @@ -64,23 +76,38 @@ static void hex_dump(const void *src, size_t length, size_t line_size, char *pre } } -static void transfer(int fd) +/* + * Unescape - process hexadecimal escape character + * converts shell input "\x23" -> 0x23 + */ +int unespcape(char *_dst, char *_src, size_t len) +{ + int ret = 0; + char *src = _src; + char *dst = _dst; + unsigned int ch; + + while (*src) { + if (*src == '\\' && *(src+1) == 'x') { + sscanf(src + 2, "%2x", &ch); + src += 4; + *dst++ = (unsigned char)ch; + } else { + *dst++ = *src++; + } + ret++; + } + return ret; +} + +static void transfer(int fd, uint8_t const *tx, uint8_t const *rx, size_t len) { int ret; - uint8_t tx[] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x40, 0x00, 0x00, 0x00, 0x00, 0x95, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xDE, 0xAD, 0xBE, 0xEF, 0xBA, 0xAD, - 0xF0, 0x0D, - }; - uint8_t rx[ARRAY_SIZE(tx)] = {0, }; + struct spi_ioc_transfer tr = { .tx_buf = (unsigned long)tx, .rx_buf = (unsigned long)rx, - .len = ARRAY_SIZE(tx), + .len = len, .delay_usecs = delay, .speed_hz = speed, .bits_per_word = bits, @@ -106,8 +133,8 @@ static void transfer(int fd) pabort("can't send spi message"); if (verbose) - hex_dump(tx, ARRAY_SIZE(tx), 32, "TX"); - hex_dump(rx, ARRAY_SIZE(rx), 32, "RX"); + hex_dump(tx, len, 32, "TX"); + hex_dump(rx, len, 32, "RX"); } static void print_usage(const char *prog) @@ -124,6 +151,7 @@ static void print_usage(const char *prog) " -C --cs-high chip select active high\n" " -3 --3wire SI/SO signals shared\n" " -v --verbose Verbose (show tx buffer)\n" + " -p Send data (e.g. \"1234\\xde\\xad\")\n" " -N --no-cs no chip select\n" " -R --ready slave pulls low to pause\n" " -2 --dual dual transfer\n" @@ -154,7 +182,7 @@ static void parse_opts(int argc, char *argv[]) }; int c; - c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR24:v", lopts, NULL); + c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR24p:v", lopts, NULL); if (c == -1) break; @@ -199,6 +227,9 @@ static void parse_opts(int argc, char *argv[]) case 'R': mode |= SPI_READY; break; + case 'p': + input_tx = optarg; + break; case '2': mode |= SPI_TX_DUAL; break; @@ -222,6 +253,9 @@ int main(int argc, char *argv[]) { int ret = 0; int fd; + uint8_t *tx; + uint8_t *rx; + int size; parse_opts(argc, argv); @@ -266,7 +300,17 @@ int main(int argc, char *argv[]) printf("bits per word: %d\n", bits); printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000); - transfer(fd); + if (input_tx) { + size = strlen(input_tx+1); + tx = malloc(size); + rx = malloc(size); + size = unespcape((char *)tx, input_tx, size); + transfer(fd, tx, rx, size); + free(rx); + free(tx); + } else { + transfer(fd, default_tx, default_rx, sizeof(default_tx)); + } close(fd); -- cgit v1.2.3-59-g8ed1b From 1ff2765182d1969947dfb50f4e42ebd7e83699fd Mon Sep 17 00:00:00 2001 From: Anish Kumar Date: Mon, 9 Mar 2015 15:50:34 -0700 Subject: ASoC: Add max98925 codec driver Signed-off-by: Anish Kumar Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/max98925.txt | 22 + sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/max98925.c | 655 ++++++++++++++++ sound/soc/codecs/max98925.h | 832 +++++++++++++++++++++ 5 files changed, 1515 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/max98925.txt create mode 100644 sound/soc/codecs/max98925.c create mode 100644 sound/soc/codecs/max98925.h (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/max98925.txt b/Documentation/devicetree/bindings/sound/max98925.txt new file mode 100644 index 000000000000..27be63e2aa0d --- /dev/null +++ b/Documentation/devicetree/bindings/sound/max98925.txt @@ -0,0 +1,22 @@ +max98925 audio CODEC + +This device supports I2C. + +Required properties: + + - compatible : "maxim,max98925" + + - vmon-slot-no : slot number used to send voltage information + + - imon-slot-no : slot number used to send current information + + - reg : the I2C address of the device for I2C + +Example: + +codec: max98925@1a { + compatible = "maxim,max98925"; + vmon-slot-no = <0>; + imon-slot-no = <2>; + reg = <0x1a>; +}; diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index ea9f0e31f9d4..0ccce5a1f4fa 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -70,6 +70,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_MAX98090 if I2C select SND_SOC_MAX98095 if I2C select SND_SOC_MAX98357A if GPIOLIB + select SND_SOC_MAX98925 if I2C select SND_SOC_MAX9850 if I2C select SND_SOC_MAX9768 if I2C select SND_SOC_MAX9877 if I2C @@ -460,6 +461,9 @@ config SND_SOC_MAX98095 config SND_SOC_MAX98357A tristate +config SND_SOC_MAX98925 + tristate + config SND_SOC_MAX9850 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 69b8666d187a..333ee3a4efa1 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -65,6 +65,7 @@ snd-soc-max98088-objs := max98088.o snd-soc-max98090-objs := max98090.o snd-soc-max98095-objs := max98095.o snd-soc-max98357a-objs := max98357a.o +snd-soc-max98925-objs := max98925.o snd-soc-max9850-objs := max9850.o snd-soc-mc13783-objs := mc13783.o snd-soc-ml26124-objs := ml26124.o @@ -247,6 +248,7 @@ obj-$(CONFIG_SND_SOC_MAX98088) += snd-soc-max98088.o obj-$(CONFIG_SND_SOC_MAX98090) += snd-soc-max98090.o obj-$(CONFIG_SND_SOC_MAX98095) += snd-soc-max98095.o obj-$(CONFIG_SND_SOC_MAX98357A) += snd-soc-max98357a.o +obj-$(CONFIG_SND_SOC_MAX98925) += snd-soc-max98925.o obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o diff --git a/sound/soc/codecs/max98925.c b/sound/soc/codecs/max98925.c new file mode 100644 index 000000000000..74f4f0b60108 --- /dev/null +++ b/sound/soc/codecs/max98925.c @@ -0,0 +1,655 @@ +/* + * max98925.c -- ALSA SoC Stereo MAX98925 driver + * Copyright 2013-15 Maxim Integrated Products + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "max98925.h" + +static const char *const dai_text[] = { + "Left", "Right", "LeftRight", "LeftRightDiv2", +}; + +static const char * const max98925_boost_voltage_text[] = { + "8.5V", "8.25V", "8.0V", "7.75V", "7.5V", "7.25V", "7.0V", "6.75V", + "6.5V", "6.5V", "6.5V", "6.5V", "6.5V", "6.5V", "6.5V", "6.5V" +}; + +static SOC_ENUM_SINGLE_DECL(max98925_boost_voltage, + MAX98925_CONFIGURATION, M98925_BST_VOUT_SHIFT, + max98925_boost_voltage_text); + +static const char *const hpf_text[] = { + "Disable", "DC Block", "100Hz", "200Hz", "400Hz", "800Hz", +}; + +static struct reg_default max98925_reg[] = { + { 0x0B, 0x00 }, /* IRQ Enable0 */ + { 0x0C, 0x00 }, /* IRQ Enable1 */ + { 0x0D, 0x00 }, /* IRQ Enable2 */ + { 0x0E, 0x00 }, /* IRQ Clear0 */ + { 0x0F, 0x00 }, /* IRQ Clear1 */ + { 0x10, 0x00 }, /* IRQ Clear2 */ + { 0x11, 0xC0 }, /* Map0 */ + { 0x12, 0x00 }, /* Map1 */ + { 0x13, 0x00 }, /* Map2 */ + { 0x14, 0xF0 }, /* Map3 */ + { 0x15, 0x00 }, /* Map4 */ + { 0x16, 0xAB }, /* Map5 */ + { 0x17, 0x89 }, /* Map6 */ + { 0x18, 0x00 }, /* Map7 */ + { 0x19, 0x00 }, /* Map8 */ + { 0x1A, 0x06 }, /* DAI Clock Mode 1 */ + { 0x1B, 0xC0 }, /* DAI Clock Mode 2 */ + { 0x1C, 0x00 }, /* DAI Clock Divider Denominator MSBs */ + { 0x1D, 0x00 }, /* DAI Clock Divider Denominator LSBs */ + { 0x1E, 0xF0 }, /* DAI Clock Divider Numerator MSBs */ + { 0x1F, 0x00 }, /* DAI Clock Divider Numerator LSBs */ + { 0x20, 0x50 }, /* Format */ + { 0x21, 0x00 }, /* TDM Slot Select */ + { 0x22, 0x00 }, /* DOUT Configuration VMON */ + { 0x23, 0x00 }, /* DOUT Configuration IMON */ + { 0x24, 0x00 }, /* DOUT Configuration VBAT */ + { 0x25, 0x00 }, /* DOUT Configuration VBST */ + { 0x26, 0x00 }, /* DOUT Configuration FLAG */ + { 0x27, 0xFF }, /* DOUT HiZ Configuration 1 */ + { 0x28, 0xFF }, /* DOUT HiZ Configuration 2 */ + { 0x29, 0xFF }, /* DOUT HiZ Configuration 3 */ + { 0x2A, 0xFF }, /* DOUT HiZ Configuration 4 */ + { 0x2B, 0x02 }, /* DOUT Drive Strength */ + { 0x2C, 0x90 }, /* Filters */ + { 0x2D, 0x00 }, /* Gain */ + { 0x2E, 0x02 }, /* Gain Ramping */ + { 0x2F, 0x00 }, /* Speaker Amplifier */ + { 0x30, 0x0A }, /* Threshold */ + { 0x31, 0x00 }, /* ALC Attack */ + { 0x32, 0x80 }, /* ALC Atten and Release */ + { 0x33, 0x00 }, /* ALC Infinite Hold Release */ + { 0x34, 0x92 }, /* ALC Configuration */ + { 0x35, 0x01 }, /* Boost Converter */ + { 0x36, 0x00 }, /* Block Enable */ + { 0x37, 0x00 }, /* Configuration */ + { 0x38, 0x00 }, /* Global Enable */ + { 0x3A, 0x00 }, /* Boost Limiter */ +}; + +static const struct soc_enum max98925_dai_enum = + SOC_ENUM_SINGLE(MAX98925_GAIN, 5, ARRAY_SIZE(dai_text), dai_text); + +static const struct soc_enum max98925_hpf_enum = + SOC_ENUM_SINGLE(MAX98925_FILTERS, 0, ARRAY_SIZE(hpf_text), hpf_text); + +static const struct snd_kcontrol_new max98925_hpf_sel_mux = + SOC_DAPM_ENUM("Rc Filter MUX Mux", max98925_hpf_enum); + +static const struct snd_kcontrol_new max98925_dai_sel_mux = + SOC_DAPM_ENUM("DAI IN MUX Mux", max98925_dai_enum); + +static int max98925_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + regmap_update_bits(max98925->regmap, + MAX98925_BLOCK_ENABLE, + M98925_BST_EN_MASK | + M98925_ADC_IMON_EN_MASK | M98925_ADC_VMON_EN_MASK, + M98925_BST_EN_MASK | + M98925_ADC_IMON_EN_MASK | M98925_ADC_VMON_EN_MASK); + break; + case SND_SOC_DAPM_POST_PMD: + regmap_update_bits(max98925->regmap, + MAX98925_BLOCK_ENABLE, M98925_BST_EN_MASK | + M98925_ADC_IMON_EN_MASK | M98925_ADC_VMON_EN_MASK, 0); + break; + default: + return 0; + } + return 0; +} + +static const struct snd_soc_dapm_widget max98925_dapm_widgets[] = { + SND_SOC_DAPM_AIF_IN("DAI_OUT", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_MUX("DAI IN MUX", SND_SOC_NOPM, 0, 0, + &max98925_dai_sel_mux), + SND_SOC_DAPM_MUX("Rc Filter MUX", SND_SOC_NOPM, 0, 0, + &max98925_hpf_sel_mux), + SND_SOC_DAPM_DAC_E("Amp Enable", NULL, MAX98925_BLOCK_ENABLE, + M98925_SPK_EN_SHIFT, 0, max98925_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("Global Enable", MAX98925_GLOBAL_ENABLE, + M98925_EN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_OUTPUT("BE_OUT"), +}; + +static const struct snd_soc_dapm_route max98925_audio_map[] = { + {"DAI IN MUX", "Left", "DAI_OUT"}, + {"DAI IN MUX", "Right", "DAI_OUT"}, + {"DAI IN MUX", "LeftRight", "DAI_OUT"}, + {"DAI IN MUX", "LeftRightDiv2", "DAI_OUT"}, + {"Rc Filter MUX", "Disable", "DAI IN MUX"}, + {"Rc Filter MUX", "DC Block", "DAI IN MUX"}, + {"Rc Filter MUX", "100Hz", "DAI IN MUX"}, + {"Rc Filter MUX", "200Hz", "DAI IN MUX"}, + {"Rc Filter MUX", "400Hz", "DAI IN MUX"}, + {"Rc Filter MUX", "800Hz", "DAI IN MUX"}, + {"Amp Enable", NULL, "Rc Filter MUX"}, + {"BE_OUT", NULL, "Amp Enable"}, + {"BE_OUT", NULL, "Global Enable"}, +}; + +static bool max98925_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MAX98925_VBAT_DATA: + case MAX98925_VBST_DATA: + case MAX98925_LIVE_STATUS0: + case MAX98925_LIVE_STATUS1: + case MAX98925_LIVE_STATUS2: + case MAX98925_STATE0: + case MAX98925_STATE1: + case MAX98925_STATE2: + case MAX98925_FLAG0: + case MAX98925_FLAG1: + case MAX98925_FLAG2: + case MAX98925_REV_VERSION: + return true; + default: + return false; + } +} + +static bool max98925_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MAX98925_IRQ_CLEAR0: + case MAX98925_IRQ_CLEAR1: + case MAX98925_IRQ_CLEAR2: + case MAX98925_ALC_HOLD_RLS: + return false; + default: + return true; + } +} + +DECLARE_TLV_DB_SCALE(max98925_spk_tlv, -600, 100, 0); + +static const struct snd_kcontrol_new max98925_snd_controls[] = { + SOC_SINGLE_TLV("Speaker Volume", MAX98925_GAIN, + M98925_SPK_GAIN_SHIFT, (1<= rate) { + *value = rate_table[i].sr; + *n = rate_table[i].divisors[clock][0]; + *m = rate_table[i].divisors[clock][1]; + ret = 0; + break; + } + } + dev_dbg(codec->dev, "%s: sample rate is %d, returning %d\n", + __func__, rate_table[i].rate, *value); + return ret; +} + +static void max98925_set_sense_data(struct max98925_priv *max98925) +{ + /* set VMON slots */ + regmap_update_bits(max98925->regmap, + MAX98925_DOUT_CFG_VMON, + M98925_DAI_VMON_EN_MASK, M98925_DAI_VMON_EN_MASK); + regmap_update_bits(max98925->regmap, + MAX98925_DOUT_CFG_VMON, + M98925_DAI_VMON_SLOT_MASK, + max98925->v_slot << M98925_DAI_VMON_SLOT_SHIFT); + /* set IMON slots */ + regmap_update_bits(max98925->regmap, + MAX98925_DOUT_CFG_IMON, + M98925_DAI_IMON_EN_MASK, M98925_DAI_IMON_EN_MASK); + regmap_update_bits(max98925->regmap, + MAX98925_DOUT_CFG_IMON, + M98925_DAI_IMON_SLOT_MASK, + max98925->i_slot << M98925_DAI_IMON_SLOT_SHIFT); +} + +static int max98925_dai_set_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec); + unsigned int invert = 0; + + dev_dbg(codec->dev, "%s: fmt 0x%08X\n", __func__, fmt); + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + /* set DAI to slave mode */ + regmap_update_bits(max98925->regmap, + MAX98925_DAI_CLK_MODE2, + M98925_DAI_MAS_MASK, 0); + max98925_set_sense_data(max98925); + break; + case SND_SOC_DAIFMT_CBM_CFM: + /* + * set left channel DAI to master mode, + * right channel always slave + */ + regmap_update_bits(max98925->regmap, + MAX98925_DAI_CLK_MODE2, + M98925_DAI_MAS_MASK, M98925_DAI_MAS_MASK); + break; + case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_CBM_CFS: + default: + dev_err(codec->dev, "DAI clock mode unsupported"); + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_NB_IF: + invert = M98925_DAI_WCI_MASK; + break; + case SND_SOC_DAIFMT_IB_NF: + invert = M98925_DAI_BCI_MASK; + break; + case SND_SOC_DAIFMT_IB_IF: + invert = M98925_DAI_BCI_MASK | M98925_DAI_WCI_MASK; + break; + default: + dev_err(codec->dev, "DAI invert mode unsupported"); + return -EINVAL; + } + + regmap_update_bits(max98925->regmap, MAX98925_FORMAT, + M98925_DAI_BCI_MASK | M98925_DAI_BCI_MASK, invert); + return 0; +} + +static int max98925_set_clock(struct max98925_priv *max98925, + struct snd_pcm_hw_params *params) +{ + unsigned int dai_sr = 0, clock, mdll, n, m; + struct snd_soc_codec *codec = max98925->codec; + int rate = params_rate(params); + /* BCLK/LRCLK ratio calculation */ + int blr_clk_ratio = params_channels(params) * max98925->ch_size; + + switch (blr_clk_ratio) { + case 32: + regmap_update_bits(max98925->regmap, + MAX98925_DAI_CLK_MODE2, + M98925_DAI_BSEL_MASK, M98925_DAI_BSEL_32); + break; + case 48: + regmap_update_bits(max98925->regmap, + MAX98925_DAI_CLK_MODE2, + M98925_DAI_BSEL_MASK, M98925_DAI_BSEL_48); + break; + case 64: + regmap_update_bits(max98925->regmap, + MAX98925_DAI_CLK_MODE2, + M98925_DAI_BSEL_MASK, M98925_DAI_BSEL_64); + break; + default: + return -EINVAL; + } + + switch (max98925->sysclk) { + case 6000000: + clock = 0; + mdll = M98925_MDLL_MULT_MCLKx16; + break; + case 11289600: + clock = 1; + mdll = M98925_MDLL_MULT_MCLKx8; + break; + case 12000000: + clock = 0; + mdll = M98925_MDLL_MULT_MCLKx8; + break; + case 12288000: + clock = 2; + mdll = M98925_MDLL_MULT_MCLKx8; + break; + default: + dev_info(max98925->codec->dev, "unsupported sysclk %d\n", + max98925->sysclk); + return -EINVAL; + } + + if (max98925_rate_value(codec, rate, clock, &dai_sr, &n, &m)) + return -EINVAL; + + /* set DAI_SR to correct LRCLK frequency */ + regmap_update_bits(max98925->regmap, + MAX98925_DAI_CLK_MODE2, + M98925_DAI_SR_MASK, dai_sr << M98925_DAI_SR_SHIFT); + /* set DAI m divider */ + regmap_write(max98925->regmap, + MAX98925_DAI_CLK_DIV_M_MSBS, m >> 8); + regmap_write(max98925->regmap, + MAX98925_DAI_CLK_DIV_M_LSBS, m & 0xFF); + /* set DAI n divider */ + regmap_write(max98925->regmap, + MAX98925_DAI_CLK_DIV_N_MSBS, n >> 8); + regmap_write(max98925->regmap, + MAX98925_DAI_CLK_DIV_N_LSBS, n & 0xFF); + /* set MDLL */ + regmap_update_bits(max98925->regmap, MAX98925_DAI_CLK_MODE1, + M98925_MDLL_MULT_MASK, mdll << M98925_MDLL_MULT_SHIFT); + return 0; +} + +static int max98925_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec); + + switch (snd_pcm_format_width(params_format(params))) { + case 16: + regmap_update_bits(max98925->regmap, + MAX98925_FORMAT, + M98925_DAI_CHANSZ_MASK, M98925_DAI_CHANSZ_16); + max98925->ch_size = 16; + break; + case 24: + regmap_update_bits(max98925->regmap, + MAX98925_FORMAT, + M98925_DAI_CHANSZ_MASK, M98925_DAI_CHANSZ_32); + max98925->ch_size = 32; + break; + case 32: + regmap_update_bits(max98925->regmap, + MAX98925_FORMAT, + M98925_DAI_CHANSZ_MASK, M98925_DAI_CHANSZ_32); + max98925->ch_size = 32; + break; + default: + pr_err("%s: format unsupported %d", + __func__, params_format(params)); + return -EINVAL; + } + dev_dbg(codec->dev, "%s: format supported %d", + __func__, params_format(params)); + return max98925_set_clock(max98925, params); +} + +static int max98925_dai_set_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec); + + switch (clk_id) { + case 0: + /* use MCLK for Left channel, right channel always BCLK */ + regmap_update_bits(max98925->regmap, + MAX98925_DAI_CLK_MODE1, + M98925_DAI_CLK_SOURCE_MASK, 0); + break; + case 1: + /* configure dai clock source to BCLK instead of MCLK */ + regmap_update_bits(max98925->regmap, + MAX98925_DAI_CLK_MODE1, + M98925_DAI_CLK_SOURCE_MASK, + M98925_DAI_CLK_SOURCE_MASK); + break; + default: + return -EINVAL; + } + max98925->sysclk = freq; + return 0; +} + +#define MAX98925_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_ops max98925_dai_ops = { + .set_sysclk = max98925_dai_set_sysclk, + .set_fmt = max98925_dai_set_fmt, + .hw_params = max98925_dai_hw_params, +}; + +static struct snd_soc_dai_driver max98925_dai[] = { + { + .name = "max98925-aif1", + .playback = { + .stream_name = "HiFi Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = MAX98925_FORMATS, + }, + .capture = { + .stream_name = "HiFi Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = MAX98925_FORMATS, + }, + .ops = &max98925_dai_ops, + } +}; + +static int max98925_probe(struct snd_soc_codec *codec) +{ + struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec); + + max98925->codec = codec; + codec->control_data = max98925->regmap; + regmap_write(max98925->regmap, MAX98925_GLOBAL_ENABLE, 0x00); + /* It's not the default but we need to set DAI_DLY */ + regmap_write(max98925->regmap, + MAX98925_FORMAT, M98925_DAI_DLY_MASK); + regmap_write(max98925->regmap, MAX98925_TDM_SLOT_SELECT, 0xC8); + regmap_write(max98925->regmap, MAX98925_DOUT_HIZ_CFG1, 0xFF); + regmap_write(max98925->regmap, MAX98925_DOUT_HIZ_CFG2, 0xFF); + regmap_write(max98925->regmap, MAX98925_DOUT_HIZ_CFG3, 0xFF); + regmap_write(max98925->regmap, MAX98925_DOUT_HIZ_CFG4, 0xF0); + regmap_write(max98925->regmap, MAX98925_FILTERS, 0xD8); + regmap_write(max98925->regmap, MAX98925_ALC_CONFIGURATION, 0xF8); + regmap_write(max98925->regmap, MAX98925_CONFIGURATION, 0xF0); + /* Disable ALC muting */ + regmap_write(max98925->regmap, MAX98925_BOOST_LIMITER, 0xF8); + return 0; +} + +static struct snd_soc_codec_driver soc_codec_dev_max98925 = { + .probe = max98925_probe, + .controls = max98925_snd_controls, + .num_controls = ARRAY_SIZE(max98925_snd_controls), + .dapm_routes = max98925_audio_map, + .num_dapm_routes = ARRAY_SIZE(max98925_audio_map), + .dapm_widgets = max98925_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(max98925_dapm_widgets), +}; + +static struct regmap_config max98925_regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = MAX98925_REV_VERSION, + .reg_defaults = max98925_reg, + .num_reg_defaults = ARRAY_SIZE(max98925_reg), + .volatile_reg = max98925_volatile_register, + .readable_reg = max98925_readable_register, + .cache_type = REGCACHE_RBTREE, +}; + +static int max98925_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + int ret, reg; + u32 value; + struct max98925_priv *max98925; + + max98925 = devm_kzalloc(&i2c->dev, + sizeof(*max98925), GFP_KERNEL); + if (!max98925) + return -ENOMEM; + + i2c_set_clientdata(i2c, max98925); + max98925->regmap = devm_regmap_init_i2c(i2c, &max98925_regmap); + if (IS_ERR(max98925->regmap)) { + ret = PTR_ERR(max98925->regmap); + dev_err(&i2c->dev, + "Failed to allocate regmap: %d\n", ret); + goto err_out; + } + + if (!of_property_read_u32(i2c->dev.of_node, "vmon-slot-no", &value)) { + if (value > M98925_DAI_VMON_SLOT_1E_1F) { + dev_err(&i2c->dev, "vmon slot number is wrong:\n"); + return -EINVAL; + } + max98925->v_slot = value; + } + if (!of_property_read_u32(i2c->dev.of_node, "imon-slot-no", &value)) { + if (value > M98925_DAI_IMON_SLOT_1E_1F) { + dev_err(&i2c->dev, "imon slot number is wrong:\n"); + return -EINVAL; + } + max98925->i_slot = value; + } + ret = regmap_read(max98925->regmap, + MAX98925_REV_VERSION, ®); + if ((ret < 0) || + ((reg != MAX98925_VERSION) && + (reg != MAX98925_VERSION1))) { + dev_err(&i2c->dev, + "device initialization error (%d 0x%02X)\n", + ret, reg); + goto err_out; + } + dev_info(&i2c->dev, "device version 0x%02X\n", reg); + + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_max98925, + max98925_dai, ARRAY_SIZE(max98925_dai)); + if (ret < 0) + dev_err(&i2c->dev, + "Failed to register codec: %d\n", ret); +err_out: + return ret; +} + +static int max98925_i2c_remove(struct i2c_client *client) +{ + snd_soc_unregister_codec(&client->dev); + return 0; +} + +static const struct i2c_device_id max98925_i2c_id[] = { + { "max98925", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, max98925_i2c_id); + +static const struct of_device_id max98925_of_match[] = { + { .compatible = "maxim,max98925", }, + { } +}; +MODULE_DEVICE_TABLE(of, max98925_of_match); + +static struct i2c_driver max98925_i2c_driver = { + .driver = { + .name = "max98925", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(max98925_of_match), + .pm = NULL, + }, + .probe = max98925_i2c_probe, + .remove = max98925_i2c_remove, + .id_table = max98925_i2c_id, +}; + +module_i2c_driver(max98925_i2c_driver) + +MODULE_DESCRIPTION("ALSA SoC MAX98925 driver"); +MODULE_AUTHOR("Ralph Birt , Anish kumar "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/max98925.h b/sound/soc/codecs/max98925.h new file mode 100644 index 000000000000..3783248f2780 --- /dev/null +++ b/sound/soc/codecs/max98925.h @@ -0,0 +1,832 @@ +/* + * max98925.h -- MAX98925 ALSA SoC Audio driver + * + * Copyright 2013-2015 Maxim Integrated Products + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _MAX98925_H +#define _MAX98925_H + +#define MAX98925_VERSION 0x51 +#define MAX98925_VERSION1 0x80 +#define MAX98925_VBAT_DATA 0x00 +#define MAX98925_VBST_DATA 0x01 +#define MAX98925_LIVE_STATUS0 0x02 +#define MAX98925_LIVE_STATUS1 0x03 +#define MAX98925_LIVE_STATUS2 0x04 +#define MAX98925_STATE0 0x05 +#define MAX98925_STATE1 0x06 +#define MAX98925_STATE2 0x07 +#define MAX98925_FLAG0 0x08 +#define MAX98925_FLAG1 0x09 +#define MAX98925_FLAG2 0x0A +#define MAX98925_IRQ_ENABLE0 0x0B +#define MAX98925_IRQ_ENABLE1 0x0C +#define MAX98925_IRQ_ENABLE2 0x0D +#define MAX98925_IRQ_CLEAR0 0x0E +#define MAX98925_IRQ_CLEAR1 0x0F +#define MAX98925_IRQ_CLEAR2 0x10 +#define MAX98925_MAP0 0x11 +#define MAX98925_MAP1 0x12 +#define MAX98925_MAP2 0x13 +#define MAX98925_MAP3 0x14 +#define MAX98925_MAP4 0x15 +#define MAX98925_MAP5 0x16 +#define MAX98925_MAP6 0x17 +#define MAX98925_MAP7 0x18 +#define MAX98925_MAP8 0x19 +#define MAX98925_DAI_CLK_MODE1 0x1A +#define MAX98925_DAI_CLK_MODE2 0x1B +#define MAX98925_DAI_CLK_DIV_M_MSBS 0x1C +#define MAX98925_DAI_CLK_DIV_M_LSBS 0x1D +#define MAX98925_DAI_CLK_DIV_N_MSBS 0x1E +#define MAX98925_DAI_CLK_DIV_N_LSBS 0x1F +#define MAX98925_FORMAT 0x20 +#define MAX98925_TDM_SLOT_SELECT 0x21 +#define MAX98925_DOUT_CFG_VMON 0x22 +#define MAX98925_DOUT_CFG_IMON 0x23 +#define MAX98925_DOUT_CFG_VBAT 0x24 +#define MAX98925_DOUT_CFG_VBST 0x25 +#define MAX98925_DOUT_CFG_FLAG 0x26 +#define MAX98925_DOUT_HIZ_CFG1 0x27 +#define MAX98925_DOUT_HIZ_CFG2 0x28 +#define MAX98925_DOUT_HIZ_CFG3 0x29 +#define MAX98925_DOUT_HIZ_CFG4 0x2A +#define MAX98925_DOUT_DRV_STRENGTH 0x2B +#define MAX98925_FILTERS 0x2C +#define MAX98925_GAIN 0x2D +#define MAX98925_GAIN_RAMPING 0x2E +#define MAX98925_SPK_AMP 0x2F +#define MAX98925_THRESHOLD 0x30 +#define MAX98925_ALC_ATTACK 0x31 +#define MAX98925_ALC_ATTEN_RLS 0x32 +#define MAX98925_ALC_HOLD_RLS 0x33 +#define MAX98925_ALC_CONFIGURATION 0x34 +#define MAX98925_BOOST_CONVERTER 0x35 +#define MAX98925_BLOCK_ENABLE 0x36 +#define MAX98925_CONFIGURATION 0x37 +#define MAX98925_GLOBAL_ENABLE 0x38 +#define MAX98925_BOOST_LIMITER 0x3A +#define MAX98925_REV_VERSION 0xFF + +#define MAX98925_REG_CNT (MAX98925_R03A_BOOST_LIMITER+1) + +/* MAX98925 Register Bit Fields */ + +/* MAX98925_R002_LIVE_STATUS0 */ +#define M98925_THERMWARN_STATUS_MASK (1<<3) +#define M98925_THERMWARN_STATUS_SHIFT 3 +#define M98925_THERMWARN_STATUS_WIDTH 1 +#define M98925_THERMSHDN_STATUS_MASK (1<<1) +#define M98925_THERMSHDN_STATUS_SHIFT 1 +#define M98925_THERMSHDN_STATUS_WIDTH 1 + +/* MAX98925_R003_LIVE_STATUS1 */ +#define M98925_SPKCURNT_STATUS_MASK (1<<5) +#define M98925_SPKCURNT_STATUS_SHIFT 5 +#define M98925_SPKCURNT_STATUS_WIDTH 1 +#define M98925_WATCHFAIL_STATUS_MASK (1<<4) +#define M98925_WATCHFAIL_STATUS_SHIFT 4 +#define M98925_WATCHFAIL_STATUS_WIDTH 1 +#define M98925_ALCINFH_STATUS_MASK (1<<3) +#define M98925_ALCINFH_STATUS_SHIFT 3 +#define M98925_ALCINFH_STATUS_WIDTH 1 +#define M98925_ALCACT_STATUS_MASK (1<<2) +#define M98925_ALCACT_STATUS_SHIFT 2 +#define M98925_ALCACT_STATUS_WIDTH 1 +#define M98925_ALCMUT_STATUS_MASK (1<<1) +#define M98925_ALCMUT_STATUS_SHIFT 1 +#define M98925_ALCMUT_STATUS_WIDTH 1 +#define M98925_ACLP_STATUS_MASK (1<<0) +#define M98925_ACLP_STATUS_SHIFT 0 +#define M98925_ACLP_STATUS_WIDTH 1 + +/* MAX98925_R004_LIVE_STATUS2 */ +#define M98925_SLOTOVRN_STATUS_MASK (1<<6) +#define M98925_SLOTOVRN_STATUS_SHIFT 6 +#define M98925_SLOTOVRN_STATUS_WIDTH 1 +#define M98925_INVALSLOT_STATUS_MASK (1<<5) +#define M98925_INVALSLOT_STATUS_SHIFT 5 +#define M98925_INVALSLOT_STATUS_WIDTH 1 +#define M98925_SLOTCNFLT_STATUS_MASK (1<<4) +#define M98925_SLOTCNFLT_STATUS_SHIFT 4 +#define M98925_SLOTCNFLT_STATUS_WIDTH 1 +#define M98925_VBSTOVFL_STATUS_MASK (1<<3) +#define M98925_VBSTOVFL_STATUS_SHIFT 3 +#define M98925_VBSTOVFL_STATUS_WIDTH 1 +#define M98925_VBATOVFL_STATUS_MASK (1<<2) +#define M98925_VBATOVFL_STATUS_SHIFT 2 +#define M98925_VBATOVFL_STATUS_WIDTH 1 +#define M98925_IMONOVFL_STATUS_MASK (1<<1) +#define M98925_IMONOVFL_STATUS_SHIFT 1 +#define M98925_IMONOVFL_STATUS_WIDTH 1 +#define M98925_VMONOVFL_STATUS_MASK (1<<0) +#define M98925_VMONOVFL_STATUS_SHIFT 0 +#define M98925_VMONOVFL_STATUS_WIDTH 1 + +/* MAX98925_R005_STATE0 */ +#define M98925_THERMWARN_END_STATE_MASK (1<<3) +#define M98925_THERMWARN_END_STATE_SHIFT 3 +#define M98925_THERMWARN_END_STATE_WIDTH 1 +#define M98925_THERMWARN_BGN_STATE_MASK (1<<2) +#define M98925_THERMWARN_BGN_STATE_SHIFT 1 +#define M98925_THERMWARN_BGN_STATE_WIDTH 1 +#define M98925_THERMSHDN_END_STATE_MASK (1<<1) +#define M98925_THERMSHDN_END_STATE_SHIFT 1 +#define M98925_THERMSHDN_END_STATE_WIDTH 1 +#define M98925_THERMSHDN_BGN_STATE_MASK (1<<0) +#define M98925_THERMSHDN_BGN_STATE_SHIFT 0 +#define M98925_THERMSHDN_BGN_STATE_WIDTH 1 + +/* MAX98925_R006_STATE1 */ +#define M98925_SPRCURNT_STATE_MASK (1<<5) +#define M98925_SPRCURNT_STATE_SHIFT 5 +#define M98925_SPRCURNT_STATE_WIDTH 1 +#define M98925_WATCHFAIL_STATE_MASK (1<<4) +#define M98925_WATCHFAIL_STATE_SHIFT 4 +#define M98925_WATCHFAIL_STATE_WIDTH 1 +#define M98925_ALCINFH_STATE_MASK (1<<3) +#define M98925_ALCINFH_STATE_SHIFT 3 +#define M98925_ALCINFH_STATE_WIDTH 1 +#define M98925_ALCACT_STATE_MASK (1<<2) +#define M98925_ALCACT_STATE_SHIFT 2 +#define M98925_ALCACT_STATE_WIDTH 1 +#define M98925_ALCMUT_STATE_MASK (1<<1) +#define M98925_ALCMUT_STATE_SHIFT 1 +#define M98925_ALCMUT_STATE_WIDTH 1 +#define M98925_ALCP_STATE_MASK (1<<0) +#define M98925_ALCP_STATE_SHIFT 0 +#define M98925_ALCP_STATE_WIDTH 1 + +/* MAX98925_R007_STATE2 */ +#define M98925_SLOTOVRN_STATE_MASK (1<<6) +#define M98925_SLOTOVRN_STATE_SHIFT 6 +#define M98925_SLOTOVRN_STATE_WIDTH 1 +#define M98925_INVALSLOT_STATE_MASK (1<<5) +#define M98925_INVALSLOT_STATE_SHIFT 5 +#define M98925_INVALSLOT_STATE_WIDTH 1 +#define M98925_SLOTCNFLT_STATE_MASK (1<<4) +#define M98925_SLOTCNFLT_STATE_SHIFT 4 +#define M98925_SLOTCNFLT_STATE_WIDTH 1 +#define M98925_VBSTOVFL_STATE_MASK (1<<3) +#define M98925_VBSTOVFL_STATE_SHIFT 3 +#define M98925_VBSTOVFL_STATE_WIDTH 1 +#define M98925_VBATOVFL_STATE_MASK (1<<2) +#define M98925_VBATOVFL_STATE_SHIFT 2 +#define M98925_VBATOVFL_STATE_WIDTH 1 +#define M98925_IMONOVFL_STATE_MASK (1<<1) +#define M98925_IMONOVFL_STATE_SHIFT 1 +#define M98925_IMONOVFL_STATE_WIDTH 1 +#define M98925_VMONOVFL_STATE_MASK (1<<0) +#define M98925_VMONOVFL_STATE_SHIFT 0 +#define M98925_VMONOVFL_STATE_WIDTH 1 + +/* MAX98925_R008_FLAG0 */ +#define M98925_THERMWARN_END_FLAG_MASK (1<<3) +#define M98925_THERMWARN_END_FLAG_SHIFT 3 +#define M98925_THERMWARN_END_FLAG_WIDTH 1 +#define M98925_THERMWARN_BGN_FLAG_MASK (1<<2) +#define M98925_THERMWARN_BGN_FLAG_SHIFT 2 +#define M98925_THERMWARN_BGN_FLAG_WIDTH 1 +#define M98925_THERMSHDN_END_FLAG_MASK (1<<1) +#define M98925_THERMSHDN_END_FLAG_SHIFT 1 +#define M98925_THERMSHDN_END_FLAG_WIDTH 1 +#define M98925_THERMSHDN_BGN_FLAG_MASK (1<<0) +#define M98925_THERMSHDN_BGN_FLAG_SHIFT 0 +#define M98925_THERMSHDN_BGN_FLAG_WIDTH 1 + +/* MAX98925_R009_FLAG1 */ +#define M98925_SPKCURNT_FLAG_MASK (1<<5) +#define M98925_SPKCURNT_FLAG_SHIFT 5 +#define M98925_SPKCURNT_FLAG_WIDTH 1 +#define M98925_WATCHFAIL_FLAG_MASK (1<<4) +#define M98925_WATCHFAIL_FLAG_SHIFT 4 +#define M98925_WATCHFAIL_FLAG_WIDTH 1 +#define M98925_ALCINFH_FLAG_MASK (1<<3) +#define M98925_ALCINFH_FLAG_SHIFT 3 +#define M98925_ALCINFH_FLAG_WIDTH 1 +#define M98925_ALCACT_FLAG_MASK (1<<2) +#define M98925_ALCACT_FLAG_SHIFT 2 +#define M98925_ALCACT_FLAG_WIDTH 1 +#define M98925_ALCMUT_FLAG_MASK (1<<1) +#define M98925_ALCMUT_FLAG_SHIFT 1 +#define M98925_ALCMUT_FLAG_WIDTH 1 +#define M98925_ALCP_FLAG_MASK (1<<0) +#define M98925_ALCP_FLAG_SHIFT 0 +#define M98925_ALCP_FLAG_WIDTH 1 + +/* MAX98925_R00A_FLAG2 */ +#define M98925_SLOTOVRN_FLAG_MASK (1<<6) +#define M98925_SLOTOVRN_FLAG_SHIFT 6 +#define M98925_SLOTOVRN_FLAG_WIDTH 1 +#define M98925_INVALSLOT_FLAG_MASK (1<<5) +#define M98925_INVALSLOT_FLAG_SHIFT 5 +#define M98925_INVALSLOT_FLAG_WIDTH 1 +#define M98925_SLOTCNFLT_FLAG_MASK (1<<4) +#define M98925_SLOTCNFLT_FLAG_SHIFT 4 +#define M98925_SLOTCNFLT_FLAG_WIDTH 1 +#define M98925_VBSTOVFL_FLAG_MASK (1<<3) +#define M98925_VBSTOVFL_FLAG_SHIFT 3 +#define M98925_VBSTOVFL_FLAG_WIDTH 1 +#define M98925_VBATOVFL_FLAG_MASK (1<<2) +#define M98925_VBATOVFL_FLAG_SHIFT 2 +#define M98925_VBATOVFL_FLAG_WIDTH 1 +#define M98925_IMONOVFL_FLAG_MASK (1<<1) +#define M98925_IMONOVFL_FLAG_SHIFT 1 +#define M98925_IMONOVFL_FLAG_WIDTH 1 +#define M98925_VMONOVFL_FLAG_MASK (1<<0) +#define M98925_VMONOVFL_FLAG_SHIFT 0 +#define M98925_VMONOVFL_FLAG_WIDTH 1 + +/* MAX98925_R00B_IRQ_ENABLE0 */ +#define M98925_THERMWARN_END_EN_MASK (1<<3) +#define M98925_THERMWARN_END_EN_SHIFT 3 +#define M98925_THERMWARN_END_EN_WIDTH 1 +#define M98925_THERMWARN_BGN_EN_MASK (1<<2) +#define M98925_THERMWARN_BGN_EN_SHIFT 2 +#define M98925_THERMWARN_BGN_EN_WIDTH 1 +#define M98925_THERMSHDN_END_EN_MASK (1<<1) +#define M98925_THERMSHDN_END_EN_SHIFT 1 +#define M98925_THERMSHDN_END_EN_WIDTH 1 +#define M98925_THERMSHDN_BGN_EN_MASK (1<<0) +#define M98925_THERMSHDN_BGN_EN_SHIFT 0 +#define M98925_THERMSHDN_BGN_EN_WIDTH 1 + +/* MAX98925_R00C_IRQ_ENABLE1 */ +#define M98925_SPKCURNT_EN_MASK (1<<5) +#define M98925_SPKCURNT_EN_SHIFT 5 +#define M98925_SPKCURNT_EN_WIDTH 1 +#define M98925_WATCHFAIL_EN_MASK (1<<4) +#define M98925_WATCHFAIL_EN_SHIFT 4 +#define M98925_WATCHFAIL_EN_WIDTH 1 +#define M98925_ALCINFH_EN_MASK (1<<3) +#define M98925_ALCINFH_EN_SHIFT 3 +#define M98925_ALCINFH_EN_WIDTH 1 +#define M98925_ALCACT_EN_MASK (1<<2) +#define M98925_ALCACT_EN_SHIFT 2 +#define M98925_ALCACT_EN_WIDTH 1 +#define M98925_ALCMUT_EN_MASK (1<<1) +#define M98925_ALCMUT_EN_SHIFT 1 +#define M98925_ALCMUT_EN_WIDTH 1 +#define M98925_ALCP_EN_MASK (1<<0) +#define M98925_ALCP_EN_SHIFT 0 +#define M98925_ALCP_EN_WIDTH 1 + +/* MAX98925_R00D_IRQ_ENABLE2 */ +#define M98925_SLOTOVRN_EN_MASK (1<<6) +#define M98925_SLOTOVRN_EN_SHIFT 6 +#define M98925_SLOTOVRN_EN_WIDTH 1 +#define M98925_INVALSLOT_EN_MASK (1<<5) +#define M98925_INVALSLOT_EN_SHIFT 5 +#define M98925_INVALSLOT_EN_WIDTH 1 +#define M98925_SLOTCNFLT_EN_MASK (1<<4) +#define M98925_SLOTCNFLT_EN_SHIFT 4 +#define M98925_SLOTCNFLT_EN_WIDTH 1 +#define M98925_VBSTOVFL_EN_MASK (1<<3) +#define M98925_VBSTOVFL_EN_SHIFT 3 +#define M98925_VBSTOVFL_EN_WIDTH 1 +#define M98925_VBATOVFL_EN_MASK (1<<2) +#define M98925_VBATOVFL_EN_SHIFT 2 +#define M98925_VBATOVFL_EN_WIDTH 1 +#define M98925_IMONOVFL_EN_MASK (1<<1) +#define M98925_IMONOVFL_EN_SHIFT 1 +#define M98925_IMONOVFL_EN_WIDTH 1 +#define M98925_VMONOVFL_EN_MASK (1<<0) +#define M98925_VMONOVFL_EN_SHIFT 0 +#define M98925_VMONOVFL_EN_WIDTH 1 + +/* MAX98925_R00E_IRQ_CLEAR0 */ +#define M98925_THERMWARN_END_CLR_MASK (1<<3) +#define M98925_THERMWARN_END_CLR_SHIFT 3 +#define M98925_THERMWARN_END_CLR_WIDTH 1 +#define M98925_THERMWARN_BGN_CLR_MASK (1<<2) +#define M98925_THERMWARN_BGN_CLR_SHIFT 2 +#define M98925_THERMWARN_BGN_CLR_WIDTH 1 +#define M98925_THERMSHDN_END_CLR_MASK (1<<1) +#define M98925_THERMSHDN_END_CLR_SHIFT 1 +#define M98925_THERMSHDN_END_CLR_WIDTH 1 +#define M98925_THERMSHDN_BGN_CLR_MASK (1<<0) +#define M98925_THERMSHDN_BGN_CLR_SHIFT 0 +#define M98925_THERMSHDN_BGN_CLR_WIDTH 1 + +/* MAX98925_R00F_IRQ_CLEAR1 */ +#define M98925_SPKCURNT_CLR_MASK (1<<5) +#define M98925_SPKCURNT_CLR_SHIFT 5 +#define M98925_SPKCURNT_CLR_WIDTH 1 +#define M98925_WATCHFAIL_CLR_MASK (1<<4) +#define M98925_WATCHFAIL_CLR_SHIFT 4 +#define M98925_WATCHFAIL_CLR_WIDTH 1 +#define M98925_ALCINFH_CLR_MASK (1<<3) +#define M98925_ALCINFH_CLR_SHIFT 3 +#define M98925_ALCINFH_CLR_WIDTH 1 +#define M98925_ALCACT_CLR_MASK (1<<2) +#define M98925_ALCACT_CLR_SHIFT 2 +#define M98925_ALCACT_CLR_WIDTH 1 +#define M98925_ALCMUT_CLR_MASK (1<<1) +#define M98925_ALCMUT_CLR_SHIFT 1 +#define M98925_ALCMUT_CLR_WIDTH 1 +#define M98925_ALCP_CLR_MASK (1<<0) +#define M98925_ALCP_CLR_SHIFT 0 +#define M98925_ALCP_CLR_WIDTH 1 + +/* MAX98925_R010_IRQ_CLEAR2 */ +#define M98925_SLOTOVRN_CLR_MASK (1<<6) +#define M98925_SLOTOVRN_CLR_SHIFT 6 +#define M98925_SLOTOVRN_CLR_WIDTH 1 +#define M98925_INVALSLOT_CLR_MASK (1<<5) +#define M98925_INVALSLOT_CLR_SHIFT 5 +#define M98925_INVALSLOT_CLR_WIDTH 1 +#define M98925_SLOTCNFLT_CLR_MASK (1<<4) +#define M98925_SLOTCNFLT_CLR_SHIFT 4 +#define M98925_SLOTCNFLT_CLR_WIDTH 1 +#define M98925_VBSTOVFL_CLR_MASK (1<<3) +#define M98925_VBSTOVFL_CLR_SHIFT 3 +#define M98925_VBSTOVFL_CLR_WIDTH 1 +#define M98925_VBATOVFL_CLR_MASK (1<<2) +#define M98925_VBATOVFL_CLR_SHIFT 2 +#define M98925_VBATOVFL_CLR_WIDTH 1 +#define M98925_IMONOVFL_CLR_MASK (1<<1) +#define M98925_IMONOVFL_CLR_SHIFT 1 +#define M98925_IMONOVFL_CLR_WIDTH 1 +#define M98925_VMONOVFL_CLR_MASK (1<<0) +#define M98925_VMONOVFL_CLR_SHIFT 0 +#define M98925_VMONOVFL_CLR_WIDTH 1 + +/* MAX98925_R011_MAP0 */ +#define M98925_ER_THERMWARN_EN_MASK (1<<7) +#define M98925_ER_THERMWARN_EN_SHIFT 7 +#define M98925_ER_THERMWARN_EN_WIDTH 1 +#define M98925_ER_THERMWARN_MAP_MASK (0x07<<4) +#define M98925_ER_THERMWARN_MAP_SHIFT 4 +#define M98925_ER_THERMWARN_MAP_WIDTH 3 + +/* MAX98925_R012_MAP1 */ +#define M98925_ER_ALCMUT_EN_MASK (1<<7) +#define M98925_ER_ALCMUT_EN_SHIFT 7 +#define M98925_ER_ALCMUT_EN_WIDTH 1 +#define M98925_ER_ALCMUT_MAP_MASK (0x07<<4) +#define M98925_ER_ALCMUT_MAP_SHIFT 4 +#define M98925_ER_ALCMUT_MAP_WIDTH 3 +#define M98925_ER_ALCP_EN_MASK (1<<3) +#define M98925_ER_ALCP_EN_SHIFT 3 +#define M98925_ER_ALCP_EN_WIDTH 1 +#define M98925_ER_ALCP_MAP_MASK (0x07<<0) +#define M98925_ER_ALCP_MAP_SHIFT 0 +#define M98925_ER_ALCP_MAP_WIDTH 3 + +/* MAX98925_R013_MAP2 */ +#define M98925_ER_ALCINFH_EN_MASK (1<<7) +#define M98925_ER_ALCINFH_EN_SHIFT 7 +#define M98925_ER_ALCINFH_EN_WIDTH 1 +#define M98925_ER_ALCINFH_MAP_MASK (0x07<<4) +#define M98925_ER_ALCINFH_MAP_SHIFT 4 +#define M98925_ER_ALCINFH_MAP_WIDTH 3 +#define M98925_ER_ALCACT_EN_MASK (1<<3) +#define M98925_ER_ALCACT_EN_SHIFT 3 +#define M98925_ER_ALCACT_EN_WIDTH 1 +#define M98925_ER_ALCACT_MAP_MASK (0x07<<0) +#define M98925_ER_ALCACT_MAP_SHIFT 0 +#define M98925_ER_ALCACT_MAP_WIDTH 3 + +/* MAX98925_R014_MAP3 */ +#define M98925_ER_SPKCURNT_EN_MASK (1<<7) +#define M98925_ER_SPKCURNT_EN_SHIFT 7 +#define M98925_ER_SPKCURNT_EN_WIDTH 1 +#define M98925_ER_SPKCURNT_MAP_MASK (0x07<<4) +#define M98925_ER_SPKCURNT_MAP_SHIFT 4 +#define M98925_ER_SPKCURNT_MAP_WIDTH 3 + +/* MAX98925_R015_MAP4 */ +/* RESERVED */ + +/* MAX98925_R016_MAP5 */ +#define M98925_ER_IMONOVFL_EN_MASK (1<<7) +#define M98925_ER_IMONOVFL_EN_SHIFT 7 +#define M98925_ER_IMONOVFL_EN_WIDTH 1 +#define M98925_ER_IMONOVFL_MAP_MASK (0x07<<4) +#define M98925_ER_IMONOVFL_MAP_SHIFT 4 +#define M98925_ER_IMONOVFL_MAP_WIDTH 3 +#define M98925_ER_VMONOVFL_EN_MASK (1<<3) +#define M98925_ER_VMONOVFL_EN_SHIFT 3 +#define M98925_ER_VMONOVFL_EN_WIDTH 1 +#define M98925_ER_VMONOVFL_MAP_MASK (0x07<<0) +#define M98925_ER_VMONOVFL_MAP_SHIFT 0 +#define M98925_ER_VMONOVFL_MAP_WIDTH 3 + +/* MAX98925_R017_MAP6 */ +#define M98925_ER_VBSTOVFL_EN_MASK (1<<7) +#define M98925_ER_VBSTOVFL_EN_SHIFT 7 +#define M98925_ER_VBSTOVFL_EN_WIDTH 1 +#define M98925_ER_VBSTOVFL_MAP_MASK (0x07<<4) +#define M98925_ER_VBSTOVFL_MAP_SHIFT 4 +#define M98925_ER_VBSTOVFL_MAP_WIDTH 3 +#define M98925_ER_VBATOVFL_EN_MASK (1<<3) +#define M98925_ER_VBATOVFL_EN_SHIFT 3 +#define M98925_ER_VBATOVFL_EN_WIDTH 1 +#define M98925_ER_VBATOVFL_MAP_MASK (0x07<<0) +#define M98925_ER_VBATOVFL_MAP_SHIFT 0 +#define M98925_ER_VBATOVFL_MAP_WIDTH 3 + +/* MAX98925_R018_MAP7 */ +#define M98925_ER_INVALSLOT_EN_MASK (1<<7) +#define M98925_ER_INVALSLOT_EN_SHIFT 7 +#define M98925_ER_INVALSLOT_EN_WIDTH 1 +#define M98925_ER_INVALSLOT_MAP_MASK (0x07<<4) +#define M98925_ER_INVALSLOT_MAP_SHIFT 4 +#define M98925_ER_INVALSLOT_MAP_WIDTH 3 +#define M98925_ER_SLOTCNFLT_EN_MASK (1<<3) +#define M98925_ER_SLOTCNFLT_EN_SHIFT 3 +#define M98925_ER_SLOTCNFLT_EN_WIDTH 1 +#define M98925_ER_SLOTCNFLT_MAP_MASK (0x07<<0) +#define M98925_ER_SLOTCNFLT_MAP_SHIFT 0 +#define M98925_ER_SLOTCNFLT_MAP_WIDTH 3 + +/* MAX98925_R019_MAP8 */ +#define M98925_ER_SLOTOVRN_EN_MASK (1<<3) +#define M98925_ER_SLOTOVRN_EN_SHIFT 3 +#define M98925_ER_SLOTOVRN_EN_WIDTH 1 +#define M98925_ER_SLOTOVRN_MAP_MASK (0x07<<0) +#define M98925_ER_SLOTOVRN_MAP_SHIFT 0 +#define M98925_ER_SLOTOVRN_MAP_WIDTH 3 + +/* MAX98925_R01A_DAI_CLK_MODE1 */ +#define M98925_DAI_CLK_SOURCE_MASK (1<<6) +#define M98925_DAI_CLK_SOURCE_SHIFT 6 +#define M98925_DAI_CLK_SOURCE_WIDTH 1 +#define M98925_MDLL_MULT_MASK (0x0F<<0) +#define M98925_MDLL_MULT_SHIFT 0 +#define M98925_MDLL_MULT_WIDTH 4 + +#define M98925_MDLL_MULT_MCLKx8 6 +#define M98925_MDLL_MULT_MCLKx16 8 + +/* MAX98925_R01B_DAI_CLK_MODE2 */ +#define M98925_DAI_SR_MASK (0x0F<<4) +#define M98925_DAI_SR_SHIFT 4 +#define M98925_DAI_SR_WIDTH 4 +#define M98925_DAI_MAS_MASK (1<<3) +#define M98925_DAI_MAS_SHIFT 3 +#define M98925_DAI_MAS_WIDTH 1 +#define M98925_DAI_BSEL_MASK (0x07<<0) +#define M98925_DAI_BSEL_SHIFT 0 +#define M98925_DAI_BSEL_WIDTH 3 + +#define M98925_DAI_BSEL_32 (0 << M98925_DAI_BSEL_SHIFT) +#define M98925_DAI_BSEL_48 (1 << M98925_DAI_BSEL_SHIFT) +#define M98925_DAI_BSEL_64 (2 << M98925_DAI_BSEL_SHIFT) +#define M98925_DAI_BSEL_256 (6 << M98925_DAI_BSEL_SHIFT) + +/* MAX98925_R01C_DAI_CLK_DIV_M_MSBS */ +#define M98925_DAI_M_MSBS_MASK (0xFF<<0) +#define M98925_DAI_M_MSBS_SHIFT 0 +#define M98925_DAI_M_MSBS_WIDTH 8 + +/* MAX98925_R01D_DAI_CLK_DIV_M_LSBS */ +#define M98925_DAI_M_LSBS_MASK (0xFF<<0) +#define M98925_DAI_M_LSBS_SHIFT 0 +#define M98925_DAI_M_LSBS_WIDTH 8 + +/* MAX98925_R01E_DAI_CLK_DIV_N_MSBS */ +#define M98925_DAI_N_MSBS_MASK (0x7F<<0) +#define M98925_DAI_N_MSBS_SHIFT 0 +#define M98925_DAI_N_MSBS_WIDTH 7 + +/* MAX98925_R01F_DAI_CLK_DIV_N_LSBS */ +#define M98925_DAI_N_LSBS_MASK (0xFF<<0) +#define M98925_DAI_N_LSBS_SHIFT 0 +#define M98925_DAI_N_LSBS_WIDTH 8 + +/* MAX98925_R020_FORMAT */ +#define M98925_DAI_CHANSZ_MASK (0x03<<6) +#define M98925_DAI_CHANSZ_SHIFT 6 +#define M98925_DAI_CHANSZ_WIDTH 2 +#define M98925_DAI_EXTBCLK_HIZ_MASK (1<<4) +#define M98925_DAI_EXTBCLK_HIZ_SHIFT 4 +#define M98925_DAI_EXTBCLK_HIZ_WIDTH 1 +#define M98925_DAI_WCI_MASK (1<<3) +#define M98925_DAI_WCI_SHIFT 3 +#define M98925_DAI_WCI_WIDTH 1 +#define M98925_DAI_BCI_MASK (1<<2) +#define M98925_DAI_BCI_SHIFT 2 +#define M98925_DAI_BCI_WIDTH 1 +#define M98925_DAI_DLY_MASK (1<<1) +#define M98925_DAI_DLY_SHIFT 1 +#define M98925_DAI_DLY_WIDTH 1 +#define M98925_DAI_TDM_MASK (1<<0) +#define M98925_DAI_TDM_SHIFT 0 +#define M98925_DAI_TDM_WIDTH 1 + +#define M98925_DAI_CHANSZ_16 (1 << M98925_DAI_CHANSZ_SHIFT) +#define M98925_DAI_CHANSZ_24 (2 << M98925_DAI_CHANSZ_SHIFT) +#define M98925_DAI_CHANSZ_32 (3 << M98925_DAI_CHANSZ_SHIFT) + +/* MAX98925_R021_TDM_SLOT_SELECT */ +#define M98925_DAI_DO_EN_MASK (1<<7) +#define M98925_DAI_DO_EN_SHIFT 7 +#define M98925_DAI_DO_EN_WIDTH 1 +#define M98925_DAI_DIN_EN_MASK (1<<6) +#define M98925_DAI_DIN_EN_SHIFT 6 +#define M98925_DAI_DIN_EN_WIDTH 1 +#define M98925_DAI_INR_SOURCE_MASK (0x07<<3) +#define M98925_DAI_INR_SOURCE_SHIFT 3 +#define M98925_DAI_INR_SOURCE_WIDTH 3 +#define M98925_DAI_INL_SOURCE_MASK (0x07<<0) +#define M98925_DAI_INL_SOURCE_SHIFT 0 +#define M98925_DAI_INL_SOURCE_WIDTH 3 + +/* MAX98925_R022_DOUT_CFG_VMON */ +#define M98925_DAI_VMON_EN_MASK (1<<5) +#define M98925_DAI_VMON_EN_SHIFT 5 +#define M98925_DAI_VMON_EN_WIDTH 1 +#define M98925_DAI_VMON_SLOT_MASK (0x1F<<0) +#define M98925_DAI_VMON_SLOT_SHIFT 0 +#define M98925_DAI_VMON_SLOT_WIDTH 5 + +#define M98925_DAI_VMON_SLOT_00_01 (0 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_01_02 (1 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_02_03 (2 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_03_04 (3 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_04_05 (4 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_05_06 (5 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_06_07 (6 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_07_08 (7 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_08_09 (8 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_09_0A (9 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_0A_0B (10 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_0B_0C (11 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_0C_0D (12 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_0D_0E (13 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_0E_0F (14 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_0F_10 (15 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_10_11 (16 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_11_12 (17 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_12_13 (18 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_13_14 (19 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_14_15 (20 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_15_16 (21 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_16_17 (22 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_17_18 (23 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_18_19 (24 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_19_1A (25 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_1A_1B (26 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_1B_1C (27 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_1C_1D (28 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_1D_1E (29 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_1E_1F (30 << M98925_DAI_VMON_SLOT_SHIFT) + +/* MAX98925_R023_DOUT_CFG_IMON */ +#define M98925_DAI_IMON_EN_MASK (1<<5) +#define M98925_DAI_IMON_EN_SHIFT 5 +#define M98925_DAI_IMON_EN_WIDTH 1 +#define M98925_DAI_IMON_SLOT_MASK (0x1F<<0) +#define M98925_DAI_IMON_SLOT_SHIFT 0 +#define M98925_DAI_IMON_SLOT_WIDTH 5 + +#define M98925_DAI_IMON_SLOT_00_01 (0 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_01_02 (1 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_02_03 (2 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_03_04 (3 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_04_05 (4 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_05_06 (5 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_06_07 (6 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_07_08 (7 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_08_09 (8 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_09_0A (9 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_0A_0B (10 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_0B_0C (11 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_0C_0D (12 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_0D_0E (13 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_0E_0F (14 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_0F_10 (15 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_10_11 (16 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_11_12 (17 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_12_13 (18 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_13_14 (19 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_14_15 (20 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_15_16 (21 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_16_17 (22 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_17_18 (23 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_18_19 (24 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_19_1A (25 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_1A_1B (26 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_1B_1C (27 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_1C_1D (28 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_1D_1E (29 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_1E_1F (30 << M98925_DAI_IMON_SLOT_SHIFT) + +/* MAX98925_R024_DOUT_CFG_VBAT */ +#define M98925_DAI_VBAT_EN_MASK (1<<5) +#define M98925_DAI_VBAT_EN_SHIFT 5 +#define M98925_DAI_VBAT_EN_WIDTH 1 +#define M98925_DAI_VBAT_SLOT_MASK (0x1F<<0) +#define M98925_DAI_VBAT_SLOT_SHIFT 0 +#define M98925_DAI_VBAT_SLOT_WIDTH 5 + +/* MAX98925_R025_DOUT_CFG_VBST */ +#define M98925_DAI_VBST_EN_MASK (1<<5) +#define M98925_DAI_VBST_EN_SHIFT 5 +#define M98925_DAI_VBST_EN_WIDTH 1 +#define M98925_DAI_VBST_SLOT_MASK (0x1F<<0) +#define M98925_DAI_VBST_SLOT_SHIFT 0 +#define M98925_DAI_VBST_SLOT_WIDTH 5 + +/* MAX98925_R026_DOUT_CFG_FLAG */ +#define M98925_DAI_FLAG_EN_MASK (1<<5) +#define M98925_DAI_FLAG_EN_SHIFT 5 +#define M98925_DAI_FLAG_EN_WIDTH 1 +#define M98925_DAI_FLAG_SLOT_MASK (0x1F<<0) +#define M98925_DAI_FLAG_SLOT_SHIFT 0 +#define M98925_DAI_FLAG_SLOT_WIDTH 5 + +/* MAX98925_R027_DOUT_HIZ_CFG1 */ +#define M98925_DAI_SLOT_HIZ_CFG1_MASK (0xFF<<0) +#define M98925_DAI_SLOT_HIZ_CFG1_SHIFT 0 +#define M98925_DAI_SLOT_HIZ_CFG1_WIDTH 8 + +/* MAX98925_R028_DOUT_HIZ_CFG2 */ +#define M98925_DAI_SLOT_HIZ_CFG2_MASK (0xFF<<0) +#define M98925_DAI_SLOT_HIZ_CFG2_SHIFT 0 +#define M98925_DAI_SLOT_HIZ_CFG2_WIDTH 8 + +/* MAX98925_R029_DOUT_HIZ_CFG3 */ +#define M98925_DAI_SLOT_HIZ_CFG3_MASK (0xFF<<0) +#define M98925_DAI_SLOT_HIZ_CFG3_SHIFT 0 +#define M98925_DAI_SLOT_HIZ_CFG3_WIDTH 8 + +/* MAX98925_R02A_DOUT_HIZ_CFG4 */ +#define M98925_DAI_SLOT_HIZ_CFG4_MASK (0xFF<<0) +#define M98925_DAI_SLOT_HIZ_CFG4_SHIFT 0 +#define M98925_DAI_SLOT_HIZ_CFG4_WIDTH 8 + +/* MAX98925_R02B_DOUT_DRV_STRENGTH */ +#define M98925_DAI_OUT_DRIVE_MASK (0x03<<0) +#define M98925_DAI_OUT_DRIVE_SHIFT 0 +#define M98925_DAI_OUT_DRIVE_WIDTH 2 + +/* MAX98925_R02C_FILTERS */ +#define M98925_ADC_DITHER_EN_MASK (1<<7) +#define M98925_ADC_DITHER_EN_SHIFT 7 +#define M98925_ADC_DITHER_EN_WIDTH 1 +#define M98925_IV_DCB_EN_MASK (1<<6) +#define M98925_IV_DCB_EN_SHIFT 6 +#define M98925_IV_DCB_EN_WIDTH 1 +#define M98925_DAC_DITHER_EN_MASK (1<<4) +#define M98925_DAC_DITHER_EN_SHIFT 4 +#define M98925_DAC_DITHER_EN_WIDTH 1 +#define M98925_DAC_FILTER_MODE_MASK (1<<3) +#define M98925_DAC_FILTER_MODE_SHIFT 3 +#define M98925_DAC_FILTER_MODE_WIDTH 1 +#define M98925_DAC_HPF_MASK (0x07<<0) +#define M98925_DAC_HPF_SHIFT 0 +#define M98925_DAC_HPF_WIDTH 3 +#define M98925_DAC_HPF_DISABLE (0 << M98925_DAC_HPF_SHIFT) +#define M98925_DAC_HPF_DC_BLOCK (1 << M98925_DAC_HPF_SHIFT) +#define M98925_DAC_HPF_EN_100 (2 << M98925_DAC_HPF_SHIFT) +#define M98925_DAC_HPF_EN_200 (3 << M98925_DAC_HPF_SHIFT) +#define M98925_DAC_HPF_EN_400 (4 << M98925_DAC_HPF_SHIFT) +#define M98925_DAC_HPF_EN_800 (5 << M98925_DAC_HPF_SHIFT) + +/* MAX98925_R02D_GAIN */ +#define M98925_DAC_IN_SEL_MASK (0x03<<5) +#define M98925_DAC_IN_SEL_SHIFT 5 +#define M98925_DAC_IN_SEL_WIDTH 2 +#define M98925_SPK_GAIN_MASK (0x1F<<0) +#define M98925_SPK_GAIN_SHIFT 0 +#define M98925_SPK_GAIN_WIDTH 5 + +#define M98925_DAC_IN_SEL_LEFT_DAI (0 << M98925_DAC_IN_SEL_SHIFT) +#define M98925_DAC_IN_SEL_RIGHT_DAI (1 << M98925_DAC_IN_SEL_SHIFT) +#define M98925_DAC_IN_SEL_SUMMED_DAI (2 << M98925_DAC_IN_SEL_SHIFT) +#define M98925_DAC_IN_SEL_DIV2_SUMMED_DAI (3 << M98925_DAC_IN_SEL_SHIFT) + +/* MAX98925_R02E_GAIN_RAMPING */ +#define M98925_SPK_RMP_EN_MASK (1<<1) +#define M98925_SPK_RMP_EN_SHIFT 1 +#define M98925_SPK_RMP_EN_WIDTH 1 +#define M98925_SPK_ZCD_EN_MASK (1<<0) +#define M98925_SPK_ZCD_EN_SHIFT 0 +#define M98925_SPK_ZCD_EN_WIDTH 1 + +/* MAX98925_R02F_SPK_AMP */ +#define M98925_SPK_MODE_MASK (1<<0) +#define M98925_SPK_MODE_SHIFT 0 +#define M98925_SPK_MODE_WIDTH 1 + +/* MAX98925_R030_THRESHOLD */ +#define M98925_ALC_EN_MASK (1<<5) +#define M98925_ALC_EN_SHIFT 5 +#define M98925_ALC_EN_WIDTH 1 +#define M98925_ALC_TH_MASK (0x1F<<0) +#define M98925_ALC_TH_SHIFT 0 +#define M98925_ALC_TH_WIDTH 5 + +/* MAX98925_R031_ALC_ATTACK */ +#define M98925_ALC_ATK_STEP_MASK (0x0F<<4) +#define M98925_ALC_ATK_STEP_SHIFT 4 +#define M98925_ALC_ATK_STEP_WIDTH 4 +#define M98925_ALC_ATK_RATE_MASK (0x7<<0) +#define M98925_ALC_ATK_RATE_SHIFT 0 +#define M98925_ALC_ATK_RATE_WIDTH 3 + +/* MAX98925_R032_ALC_ATTEN_RLS */ +#define M98925_ALC_MAX_ATTEN_MASK (0x0F<<4) +#define M98925_ALC_MAX_ATTEN_SHIFT 4 +#define M98925_ALC_MAX_ATTEN_WIDTH 4 +#define M98925_ALC_RLS_RATE_MASK (0x7<<0) +#define M98925_ALC_RLS_RATE_SHIFT 0 +#define M98925_ALC_RLS_RATE_WIDTH 3 + +/* MAX98925_R033_ALC_HOLD_RLS */ +#define M98925_ALC_RLS_TGR_MASK (1<<0) +#define M98925_ALC_RLS_TGR_SHIFT 0 +#define M98925_ALC_RLS_TGR_WIDTH 1 + +/* MAX98925_R034_ALC_CONFIGURATION */ +#define M98925_ALC_MUTE_EN_MASK (1<<7) +#define M98925_ALC_MUTE_EN_SHIFT 7 +#define M98925_ALC_MUTE_EN_WIDTH 1 +#define M98925_ALC_MUTE_DLY_MASK (0x07<<4) +#define M98925_ALC_MUTE_DLY_SHIFT 4 +#define M98925_ALC_MUTE_DLY_WIDTH 3 +#define M98925_ALC_RLS_DBT_MASK (0x07<<0) +#define M98925_ALC_RLS_DBT_SHIFT 0 +#define M98925_ALC_RLS_DBT_WIDTH 3 + +/* MAX98925_R035_BOOST_CONVERTER */ +#define M98925_BST_SYNC_MASK (1<<7) +#define M98925_BST_SYNC_SHIFT 7 +#define M98925_BST_SYNC_WIDTH 1 +#define M98925_BST_PHASE_MASK (0x03<<4) +#define M98925_BST_PHASE_SHIFT 4 +#define M98925_BST_PHASE_WIDTH 2 +#define M98925_BST_SKIP_MODE_MASK (0x03<<0) +#define M98925_BST_SKIP_MODE_SHIFT 0 +#define M98925_BST_SKIP_MODE_WIDTH 2 + +/* MAX98925_R036_BLOCK_ENABLE */ +#define M98925_BST_EN_MASK (1<<7) +#define M98925_BST_EN_SHIFT 7 +#define M98925_BST_EN_WIDTH 1 +#define M98925_WATCH_EN_MASK (1<<6) +#define M98925_WATCH_EN_SHIFT 6 +#define M98925_WATCH_EN_WIDTH 1 +#define M98925_CLKMON_EN_MASK (1<<5) +#define M98925_CLKMON_EN_SHIFT 5 +#define M98925_CLKMON_EN_WIDTH 1 +#define M98925_SPK_EN_MASK (1<<4) +#define M98925_SPK_EN_SHIFT 4 +#define M98925_SPK_EN_WIDTH 1 +#define M98925_ADC_VBST_EN_MASK (1<<3) +#define M98925_ADC_VBST_EN_SHIFT 3 +#define M98925_ADC_VBST_EN_WIDTH 1 +#define M98925_ADC_VBAT_EN_MASK (1<<2) +#define M98925_ADC_VBAT_EN_SHIFT 2 +#define M98925_ADC_VBAT_EN_WIDTH 1 +#define M98925_ADC_IMON_EN_MASK (1<<1) +#define M98925_ADC_IMON_EN_SHIFT 1 +#define M98925_ADC_IMON_EN_WIDTH 1 +#define M98925_ADC_VMON_EN_MASK (1<<0) +#define M98925_ADC_VMON_EN_SHIFT 0 +#define M98925_ADC_VMON_EN_WIDTH 1 + +/* MAX98925_R037_CONFIGURATION */ +#define M98925_BST_VOUT_MASK (0x0F<<4) +#define M98925_BST_VOUT_SHIFT 4 +#define M98925_BST_VOUT_WIDTH 4 +#define M98925_THERMWARN_LEVEL_MASK (0x03<<2) +#define M98925_THERMWARN_LEVEL_SHIFT 2 +#define M98925_THERMWARN_LEVEL_WIDTH 2 +#define M98925_WATCH_TIME_MASK (0x03<<0) +#define M98925_WATCH_TIME_SHIFT 0 +#define M98925_WATCH_TIME_WIDTH 2 + +/* MAX98925_R038_GLOBAL_ENABLE */ +#define M98925_EN_MASK (1<<7) +#define M98925_EN_SHIFT 7 +#define M98925_EN_WIDTH 1 + +/* MAX98925_R03A_BOOST_LIMITER */ +#define M98925_BST_ILIM_MASK (0x1F<<3) +#define M98925_BST_ILIM_SHIFT 3 +#define M98925_BST_ILIM_WIDTH 5 + +/* MAX98925_R0FF_VERSION */ +#define M98925_REV_ID_MASK (0xFF<<0) +#define M98925_REV_ID_SHIFT 0 +#define M98925_REV_ID_WIDTH 8 + +struct max98925_priv { + struct regmap *regmap; + struct snd_soc_codec *codec; + struct max98925_pdata *pdata; + unsigned int sysclk; + unsigned int v_slot; + unsigned int i_slot; + unsigned int spk_gain; + unsigned int ch_size; +}; +#endif -- cgit v1.2.3-59-g8ed1b From 37745d281069682d901f00c0121949a7d224195f Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 22 Jan 2015 18:24:08 -0800 Subject: rcu: Provide diagnostic option to slow down grace-period initialization Grace-period initialization normally proceeds quite quickly, so that it is very difficult to reproduce races against grace-period initialization. This commit therefore allows grace-period initialization to be artificially slowed down, increasing race-reproduction probability. A pair of new Kconfig parameters are provided, CONFIG_RCU_TORTURE_TEST_SLOW_INIT to enable the slowdowns, and CONFIG_RCU_TORTURE_TEST_SLOW_INIT_DELAY to specify the number of jiffies of slowdown to apply. A boot-time parameter named rcutree.gp_init_delay allows boot-time delay to be specified. By default, no delay will be applied even if CONFIG_RCU_TORTURE_TEST_SLOW_INIT is set. Signed-off-by: Paul E. McKenney --- Documentation/kernel-parameters.txt | 6 ++++++ kernel/rcu/tree.c | 10 ++++++++++ lib/Kconfig.debug | 24 ++++++++++++++++++++++++ 3 files changed, 40 insertions(+) (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index bfcb1a62a7b4..94de410ec341 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -2968,6 +2968,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted. Set maximum number of finished RCU callbacks to process in one batch. + rcutree.gp_init_delay= [KNL] + Set the number of jiffies to delay each step of + RCU grace-period initialization. This only has + effect when CONFIG_RCU_TORTURE_TEST_SLOW_INIT is + set. + rcutree.rcu_fanout_leaf= [KNL] Increase the number of CPUs assigned to each leaf rcu_node structure. Useful for very large diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 3b7e4133ca99..b42001fd55fb 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -160,6 +160,12 @@ static void invoke_rcu_callbacks(struct rcu_state *rsp, struct rcu_data *rdp); static int kthread_prio = CONFIG_RCU_KTHREAD_PRIO; module_param(kthread_prio, int, 0644); +/* Delay in jiffies for grace-period initialization delays. */ +static int gp_init_delay = IS_ENABLED(CONFIG_RCU_TORTURE_TEST_SLOW_INIT) + ? CONFIG_RCU_TORTURE_TEST_SLOW_INIT_DELAY + : 0; +module_param(gp_init_delay, int, 0644); + /* * Track the rcutorture test sequence number and the update version * number within a given test. The rcutorture_testseq is incremented @@ -1769,6 +1775,10 @@ static int rcu_gp_init(struct rcu_state *rsp) raw_spin_unlock_irq(&rnp->lock); cond_resched_rcu_qs(); ACCESS_ONCE(rsp->gp_activity) = jiffies; + if (IS_ENABLED(CONFIG_RCU_TORTURE_TEST_SLOW_INIT) && + gp_init_delay > 0 && + !(rsp->gpnum % (rcu_num_nodes * 10))) + schedule_timeout_uninterruptible(gp_init_delay); } mutex_unlock(&rsp->onoff_mutex); diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index c5cefb3c009c..feee8dab441e 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -1257,6 +1257,30 @@ config RCU_TORTURE_TEST_RUNNABLE Say N here if you want the RCU torture tests to start only after being manually enabled via /proc. +config RCU_TORTURE_TEST_SLOW_INIT + bool "Slow down RCU grace-period initialization to expose races" + depends on RCU_TORTURE_TEST + help + This option makes grace-period initialization block for a + few jiffies between initializing each pair of consecutive + rcu_node structures. This helps to expose races involving + grace-period initialization, in other words, it makes your + kernel less stable. It can also greatly increase grace-period + latency, especially on systems with large numbers of CPUs. + This is useful when torture-testing RCU, but in almost no + other circumstance. + + Say Y here if you want your system to crash and hang more often. + Say N if you want a sane system. + +config RCU_TORTURE_TEST_SLOW_INIT_DELAY + int "How much to slow down RCU grace-period initialization" + range 0 5 + default 0 + help + This option specifies the number of jiffies to wait between + each rcu_node structure initialization. + config RCU_CPU_STALL_TIMEOUT int "RCU CPU stall timeout in seconds" depends on RCU_STALL_COMMON -- cgit v1.2.3-59-g8ed1b From ccd173c541e7d3c864730e334dac36a8b6487a25 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 3 Mar 2015 15:04:54 +0000 Subject: mfd: arizona: Add DT binding documentation for DMIC reference voltages Signed-off-by: Charles Keepax Signed-off-by: Lee Jones --- Documentation/devicetree/bindings/mfd/arizona.txt | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mfd/arizona.txt b/Documentation/devicetree/bindings/mfd/arizona.txt index af8646ffc336..7665aa95979f 100644 --- a/Documentation/devicetree/bindings/mfd/arizona.txt +++ b/Documentation/devicetree/bindings/mfd/arizona.txt @@ -56,6 +56,12 @@ Optional properties: input singals. If values less than the number of input signals, elements that has not been specifed are set to 0 by default. + - wlf,dmic-ref : DMIC reference voltage source for each input, can be + selected from either MICVDD or one of the MICBIAS's, defines + (ARIZONA_DMIC_xxxx) are provided in . If + present, the number of values should be less than or equal to the + number of inputs, unspecified inputs will use the chip default. + - DCVDD-supply, MICVDD-supply : Power supplies, only need to be specified if they are being externally supplied. As covered in Documentation/devicetree/bindings/regulator/regulator.txt -- cgit v1.2.3-59-g8ed1b From beedfad3e98967b3525f7a83d559ee244c3d44c4 Mon Sep 17 00:00:00 2001 From: Gyungoh Yoo Date: Fri, 27 Feb 2015 15:42:23 +0900 Subject: devicetree: Add new SKY81452 mfd binding Signed-off-by: Gyungoh Yoo Signed-off-by: Lee Jones --- Documentation/devicetree/bindings/mfd/sky81452.txt | 35 ++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 Documentation/devicetree/bindings/mfd/sky81452.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mfd/sky81452.txt b/Documentation/devicetree/bindings/mfd/sky81452.txt new file mode 100644 index 000000000000..35181794aa24 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/sky81452.txt @@ -0,0 +1,35 @@ +SKY81452 bindings + +Required properties: +- compatible : Must be "skyworks,sky81452" +- reg : I2C slave address + +Required child nodes: +- backlight : container node for backlight following the binding + in video/backlight/sky81452-backlight.txt +- regulator : container node for regulators following the binding + in regulator/sky81452-regulator.txt + +Example: + + sky81452@2c { + compatible = "skyworks,sky81452"; + reg = <0x2c>; + + backlight { + compatible = "skyworks,sky81452-backlight"; + name = "pwm-backlight"; + led-sources = <0 1 2 3 6>; + skyworks,ignore-pwm; + skyworks,phase-shift; + skyworks,current-limit = <2300>; + }; + + regulator { + lout { + regulator-name = "sky81452-lout"; + regulator-min-microvolt = <4500000>; + regulator-max-microvolt = <8000000>; + }; + }; + }; -- cgit v1.2.3-59-g8ed1b From 1144d9e916ee9c8b6138489ad646cdbd2514d1af Mon Sep 17 00:00:00 2001 From: Gyungoh Yoo Date: Fri, 27 Feb 2015 15:42:24 +0900 Subject: devicetree: Add new SKY81452 backlight binding Signed-off-by: Gyungoh Yoo Acked-by: Bryan Wu Signed-off-by: Lee Jones --- .../video/backlight/sky81452-backlight.txt | 29 ++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 Documentation/devicetree/bindings/video/backlight/sky81452-backlight.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/video/backlight/sky81452-backlight.txt b/Documentation/devicetree/bindings/video/backlight/sky81452-backlight.txt new file mode 100644 index 000000000000..8bf2940f54bc --- /dev/null +++ b/Documentation/devicetree/bindings/video/backlight/sky81452-backlight.txt @@ -0,0 +1,29 @@ +SKY81452-backlight bindings + +Required properties: +- compatible : Must be "skyworks,sky81452-backlight" + +Optional properties: +- name : Name of backlight device. Default is 'lcd-backlight'. +- gpios : GPIO to use to EN pin. + See Documentation/devicetree/bindings/gpio/gpio.txt +- led-sources : List of enabled channels from 0 to 5. + See Documentation/devicetree/bindings/leds/common.txt +- skyworks,ignore-pwm : Ignore both PWM input +- skyworks,dpwm-mode : Enable DPWM dimming mode, otherwise Analog dimming. +- skyworks,phase-shift : Enable phase shift mode +- skyworks,short-detection-threshold-volt + : It should be one of 4, 5, 6 and 7V. +- skyworks,current-limit-mA + : It should be 2300mA or 2750mA. + +Example: + + backlight { + compatible = "skyworks,sky81452-backlight"; + name = "pwm-backlight"; + led-sources = <0 1 2 5>; + skyworks,ignore-pwm; + skyworks,phase-shift; + skyworks,current-limit-mA = <2300>; + }; -- cgit v1.2.3-59-g8ed1b From acca486331e953f409639925e79d29fccb6963a7 Mon Sep 17 00:00:00 2001 From: Gyungoh Yoo Date: Fri, 27 Feb 2015 15:42:25 +0900 Subject: devicetree: Add vendor prefix for Skyworks Solutions, Inc. Signed-off-by: Gyungoh Yoo Signed-off-by: Lee Jones --- Documentation/devicetree/bindings/vendor-prefixes.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 389ca1347a77..c4fe9cc64162 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -165,6 +165,7 @@ sii Seiko Instruments, Inc. silergy Silergy Corp. sirf SiRF Technology, Inc. sitronix Sitronix Technology Corporation +skyworks Skyworks Solutions, Inc. smsc Standard Microsystems Corporation snps Synopsys, Inc. solidrun SolidRun -- cgit v1.2.3-59-g8ed1b From 7faff71bc94eb598328d315a37486f23d5febdf0 Mon Sep 17 00:00:00 2001 From: Gyungoh Yoo Date: Fri, 27 Feb 2015 15:42:26 +0900 Subject: devicetree: Add SKY81452 to the Trivial Devices list Signed-off-by: Gyungoh Yoo Signed-off-by: Lee Jones --- Documentation/devicetree/bindings/i2c/trivial-devices.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/i2c/trivial-devices.txt b/Documentation/devicetree/bindings/i2c/trivial-devices.txt index aaa8325004d2..003bd77b4595 100644 --- a/Documentation/devicetree/bindings/i2c/trivial-devices.txt +++ b/Documentation/devicetree/bindings/i2c/trivial-devices.txt @@ -89,6 +89,7 @@ ricoh,rv5c386 I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC ricoh,rv5c387a I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC samsung,24ad0xd1 S524AD0XF1 (128K/256K-bit Serial EEPROM for Low Power) sii,s35390a 2-wire CMOS real-time clock +skyworks,sky81452 Skyworks SKY81452: Six-Channel White LED Driver with Touch Panel Bias Supply st-micro,24c256 i2c serial eeprom (24cxx) stm,m41t00 Serial Access TIMEKEEPER stm,m41t62 Serial real-time clock (RTC) with alarm -- cgit v1.2.3-59-g8ed1b From ef64d3f7393776f310dedc96fd79399946a52612 Mon Sep 17 00:00:00 2001 From: Søren Andersen Date: Tue, 10 Mar 2015 22:14:57 +0100 Subject: dt-bindings Help for MCP ADCs Signed-off-by: Soeren Andersen Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/adc/mcp320x.txt | 30 ++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/mcp320x.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/iio/adc/mcp320x.txt b/Documentation/devicetree/bindings/iio/adc/mcp320x.txt new file mode 100644 index 000000000000..b85184391b78 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/mcp320x.txt @@ -0,0 +1,30 @@ +* Microchip Analog to Digital Converter (ADC) + +The node for this driver must be a child node of a SPI controller, hence +all mandatory properties described in + + Documentation/devicetree/bindings/spi/spi-bus.txt + +must be specified. + +Required properties: + - compatible: Must be one of the following, depending on the + model: + "mcp3001" + "mcp3002" + "mcp3004" + "mcp3008" + "mcp3201" + "mcp3202" + "mcp3204" + "mcp3208" + + +Examples: +spi_controller { + mcp3x0x@0 { + compatible = "mcp3002"; + reg = <0>; + spi-max-frequency = <1000000>; + }; +}; -- cgit v1.2.3-59-g8ed1b From 174178fed338edba66ab9580af0c5d9e1a4e5019 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Wed, 4 Mar 2015 11:14:36 +0100 Subject: KVM: arm/arm64: add irqfd support This patch enables irqfd on arm/arm64. Both irqfd and resamplefd are supported. Injection is implemented in vgic.c without routing. This patch enables CONFIG_HAVE_KVM_EVENTFD and CONFIG_HAVE_KVM_IRQFD. KVM_CAP_IRQFD is now advertised. KVM_CAP_IRQFD_RESAMPLE capability automatically is advertised as soon as CONFIG_HAVE_KVM_IRQFD is set. Irqfd injection is restricted to SPI. The rationale behind not supporting PPI irqfd injection is that any device using a PPI would be a private-to-the-CPU device (timer for instance), so its state would have to be context-switched along with the VCPU and would require in-kernel wiring anyhow. It is not a relevant use case for irqfds. Signed-off-by: Eric Auger Reviewed-by: Christoffer Dall Acked-by: Marc Zyngier Signed-off-by: Christoffer Dall --- Documentation/virtual/kvm/api.txt | 6 ++++- arch/arm/include/uapi/asm/kvm.h | 3 +++ arch/arm/kvm/Kconfig | 2 ++ arch/arm/kvm/Makefile | 2 +- arch/arm/kvm/arm.c | 1 + arch/arm64/include/uapi/asm/kvm.h | 3 +++ arch/arm64/kvm/Kconfig | 2 ++ arch/arm64/kvm/Makefile | 2 +- virt/kvm/arm/vgic.c | 48 +++++++++++++++++++++++++++++++++++++++ 9 files changed, 66 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index b112efc816f1..b265d8e50be0 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -2234,7 +2234,7 @@ into the hash PTE second double word). 4.75 KVM_IRQFD Capability: KVM_CAP_IRQFD -Architectures: x86 s390 +Architectures: x86 s390 arm arm64 Type: vm ioctl Parameters: struct kvm_irqfd (in) Returns: 0 on success, -1 on error @@ -2260,6 +2260,10 @@ Note that closing the resamplefd is not sufficient to disable the irqfd. The KVM_IRQFD_FLAG_RESAMPLE is only necessary on assignment and need not be specified with KVM_IRQFD_FLAG_DEASSIGN. +On ARM/ARM64, the gsi field in the kvm_irqfd struct specifies the Shared +Peripheral Interrupt (SPI) index, such that the GIC interrupt ID is +given by gsi + 32. + 4.76 KVM_PPC_ALLOCATE_HTAB Capability: KVM_CAP_PPC_ALLOC_HTAB diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h index 0db25bc32864..2499867dd0d8 100644 --- a/arch/arm/include/uapi/asm/kvm.h +++ b/arch/arm/include/uapi/asm/kvm.h @@ -198,6 +198,9 @@ struct kvm_arch_memory_slot { /* Highest supported SPI, from VGIC_NR_IRQS */ #define KVM_ARM_IRQ_GIC_MAX 127 +/* One single KVM irqchip, ie. the VGIC */ +#define KVM_NR_IRQCHIPS 1 + /* PSCI interface */ #define KVM_PSCI_FN_BASE 0x95c1ba5e #define KVM_PSCI_FN(n) (KVM_PSCI_FN_BASE + (n)) diff --git a/arch/arm/kvm/Kconfig b/arch/arm/kvm/Kconfig index 83a448e8192b..f1f79d104309 100644 --- a/arch/arm/kvm/Kconfig +++ b/arch/arm/kvm/Kconfig @@ -28,6 +28,8 @@ config KVM select KVM_GENERIC_DIRTYLOG_READ_PROTECT select SRCU select MMU_NOTIFIER + select HAVE_KVM_EVENTFD + select HAVE_KVM_IRQFD depends on ARM_VIRT_EXT && ARM_LPAE && ARM_ARCH_TIMER ---help--- Support hosting virtualized guest machines. diff --git a/arch/arm/kvm/Makefile b/arch/arm/kvm/Makefile index 60be7be4c824..a093bf125ca8 100644 --- a/arch/arm/kvm/Makefile +++ b/arch/arm/kvm/Makefile @@ -15,7 +15,7 @@ AFLAGS_init.o := -Wa,-march=armv7-a$(plus_virt) AFLAGS_interrupts.o := -Wa,-march=armv7-a$(plus_virt) KVM := ../../../virt/kvm -kvm-arm-y = $(KVM)/kvm_main.o $(KVM)/coalesced_mmio.o +kvm-arm-y = $(KVM)/kvm_main.o $(KVM)/coalesced_mmio.o $(KVM)/eventfd.o obj-y += kvm-arm.o init.o interrupts.o obj-y += arm.o handle_exit.o guest.o mmu.o emulate.o reset.o diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index 5e893ebb9de7..cc96619f10a4 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -171,6 +171,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) int r; switch (ext) { case KVM_CAP_IRQCHIP: + case KVM_CAP_IRQFD: case KVM_CAP_DEVICE_CTRL: case KVM_CAP_USER_MEMORY: case KVM_CAP_SYNC_MMU: diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h index 3ef77a466018..c154c0b7eb60 100644 --- a/arch/arm64/include/uapi/asm/kvm.h +++ b/arch/arm64/include/uapi/asm/kvm.h @@ -191,6 +191,9 @@ struct kvm_arch_memory_slot { /* Highest supported SPI, from VGIC_NR_IRQS */ #define KVM_ARM_IRQ_GIC_MAX 127 +/* One single KVM irqchip, ie. the VGIC */ +#define KVM_NR_IRQCHIPS 1 + /* PSCI interface */ #define KVM_PSCI_FN_BASE 0x95c1ba5e #define KVM_PSCI_FN(n) (KVM_PSCI_FN_BASE + (n)) diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig index 05f56ce6ee70..5105e297ed5f 100644 --- a/arch/arm64/kvm/Kconfig +++ b/arch/arm64/kvm/Kconfig @@ -28,6 +28,8 @@ config KVM select KVM_ARM_HOST select KVM_GENERIC_DIRTYLOG_READ_PROTECT select SRCU + select HAVE_KVM_EVENTFD + select HAVE_KVM_IRQFD ---help--- Support hosting virtualized guest machines. diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile index c92b26abc691..b22c6360a324 100644 --- a/arch/arm64/kvm/Makefile +++ b/arch/arm64/kvm/Makefile @@ -11,7 +11,7 @@ ARM=../../../arch/arm/kvm obj-$(CONFIG_KVM_ARM_HOST) += kvm.o -kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/kvm_main.o $(KVM)/coalesced_mmio.o +kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/kvm_main.o $(KVM)/coalesced_mmio.o $(KVM)/eventfd.o kvm-$(CONFIG_KVM_ARM_HOST) += $(ARM)/arm.o $(ARM)/mmu.o $(ARM)/mmio.o kvm-$(CONFIG_KVM_ARM_HOST) += $(ARM)/psci.o $(ARM)/perf.o diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c index 897c849305db..c000e978c1fb 100644 --- a/virt/kvm/arm/vgic.c +++ b/virt/kvm/arm/vgic.c @@ -31,6 +31,7 @@ #include #include #include +#include /* * How the whole thing works (courtesy of Christoffer Dall): @@ -1083,6 +1084,7 @@ static bool vgic_process_maintenance(struct kvm_vcpu *vcpu) u32 status = vgic_get_interrupt_status(vcpu); struct vgic_dist *dist = &vcpu->kvm->arch.vgic; bool level_pending = false; + struct kvm *kvm = vcpu->kvm; kvm_debug("STATUS = %08x\n", status); @@ -1118,6 +1120,17 @@ static bool vgic_process_maintenance(struct kvm_vcpu *vcpu) */ vgic_dist_irq_clear_soft_pend(vcpu, vlr.irq); + /* + * kvm_notify_acked_irq calls kvm_set_irq() + * to reset the IRQ level. Need to release the + * lock for kvm_set_irq to grab it. + */ + spin_unlock(&dist->lock); + + kvm_notify_acked_irq(kvm, 0, + vlr.irq - VGIC_NR_PRIVATE_IRQS); + spin_lock(&dist->lock); + /* Any additional pending interrupt? */ if (vgic_dist_irq_get_level(vcpu, vlr.irq)) { vgic_cpu_irq_set(vcpu, vlr.irq); @@ -1913,3 +1926,38 @@ out_free_irq: free_percpu_irq(vgic->maint_irq, kvm_get_running_vcpus()); return ret; } + +int kvm_irq_map_gsi(struct kvm *kvm, + struct kvm_kernel_irq_routing_entry *entries, + int gsi) +{ + return gsi; +} + +int kvm_irq_map_chip_pin(struct kvm *kvm, unsigned irqchip, unsigned pin) +{ + return pin; +} + +int kvm_set_irq(struct kvm *kvm, int irq_source_id, + u32 irq, int level, bool line_status) +{ + unsigned int spi = irq + VGIC_NR_PRIVATE_IRQS; + + trace_kvm_set_irq(irq, level, irq_source_id); + + BUG_ON(!vgic_initialized(kvm)); + + if (spi > kvm->arch.vgic.nr_irqs) + return -EINVAL; + return kvm_vgic_inject_irq(kvm, 0, spi, level); + +} + +/* MSI not implemented yet */ +int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, + struct kvm *kvm, int irq_source_id, + int level, bool line_status) +{ + return 0; +} -- cgit v1.2.3-59-g8ed1b From 7a96b78464bd8ba72c1c3095c543c1402db59e35 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Thu, 12 Mar 2015 15:35:18 +0900 Subject: usb: renesas_usbhs: add the channel number in dma-names To connect the channel of USB-DMAC to USBHS DnFIFO number, this patch adds this channel/FIFO number in dma-names. Otherwise, this driver needs to add analysis code for device tree. Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi --- .../devicetree/bindings/usb/renesas_usbhs.txt | 5 ++++- drivers/usb/renesas_usbhs/fifo.c | 20 +++++++++++++------- 2 files changed, 17 insertions(+), 8 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/usb/renesas_usbhs.txt b/Documentation/devicetree/bindings/usb/renesas_usbhs.txt index 61b045b6d50e..dc2a18f0b3a1 100644 --- a/Documentation/devicetree/bindings/usb/renesas_usbhs.txt +++ b/Documentation/devicetree/bindings/usb/renesas_usbhs.txt @@ -15,7 +15,10 @@ Optional properties: - phys: phandle + phy specifier pair - phy-names: must be "usb" - dmas: Must contain a list of references to DMA specifiers. - - dma-names : Must contain a list of DMA names, "tx" or "rx". + - dma-names : Must contain a list of DMA names: + - tx0 ... tx + - rx0 ... rx + - This means DnFIFO in USBHS module. Example: usbhs: usb@e6590000 { diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c index d891bff39d66..28d10eb432d5 100644 --- a/drivers/usb/renesas_usbhs/fifo.c +++ b/drivers/usb/renesas_usbhs/fifo.c @@ -1069,23 +1069,29 @@ static void usbhsf_dma_init_pdev(struct usbhs_fifo *fifo) &fifo->rx_slave); } -static void usbhsf_dma_init_dt(struct device *dev, struct usbhs_fifo *fifo) +static void usbhsf_dma_init_dt(struct device *dev, struct usbhs_fifo *fifo, + int channel) { - fifo->tx_chan = dma_request_slave_channel_reason(dev, "tx"); + char name[16]; + + snprintf(name, sizeof(name), "tx%d", channel); + fifo->tx_chan = dma_request_slave_channel_reason(dev, name); if (IS_ERR(fifo->tx_chan)) fifo->tx_chan = NULL; - fifo->rx_chan = dma_request_slave_channel_reason(dev, "rx"); + + snprintf(name, sizeof(name), "rx%d", channel); + fifo->rx_chan = dma_request_slave_channel_reason(dev, name); if (IS_ERR(fifo->rx_chan)) fifo->rx_chan = NULL; } -static void usbhsf_dma_init(struct usbhs_priv *priv, - struct usbhs_fifo *fifo) +static void usbhsf_dma_init(struct usbhs_priv *priv, struct usbhs_fifo *fifo, + int channel) { struct device *dev = usbhs_priv_to_dev(priv); if (dev->of_node) - usbhsf_dma_init_dt(dev, fifo); + usbhsf_dma_init_dt(dev, fifo, channel); else usbhsf_dma_init_pdev(fifo); @@ -1231,7 +1237,7 @@ do { \ usbhs_get_dparam(priv, d##channel##_tx_id); \ fifo->rx_slave.shdma_slave.slave_id = \ usbhs_get_dparam(priv, d##channel##_rx_id); \ - usbhsf_dma_init(priv, fifo); \ + usbhsf_dma_init(priv, fifo, channel); \ } while (0) #define USBHS_DFIFO_INIT(priv, fifo, channel) \ -- cgit v1.2.3-59-g8ed1b From ecccf0cc722f40e0dcc97872e7a960765119a256 Mon Sep 17 00:00:00 2001 From: Alex Bennée Date: Fri, 13 Mar 2015 17:02:52 +0000 Subject: arm/arm64: KVM: export VCPU power state via MP_STATE ioctl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To cleanly restore an SMP VM we need to ensure that the current pause state of each vcpu is correctly recorded. Things could get confused if the CPU starts running after migration restore completes when it was paused before it state was captured. We use the existing KVM_GET/SET_MP_STATE ioctl to do this. The arm/arm64 interface is a lot simpler as the only valid states are KVM_MP_STATE_RUNNABLE and KVM_MP_STATE_STOPPED. Signed-off-by: Alex Bennée Signed-off-by: Christoffer Dall --- Documentation/virtual/kvm/api.txt | 16 ++++++++++++---- arch/arm/kvm/arm.c | 21 +++++++++++++++++++-- 2 files changed, 31 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index b265d8e50be0..71d10d7d141e 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -997,7 +997,7 @@ for vm-wide capabilities. 4.38 KVM_GET_MP_STATE Capability: KVM_CAP_MP_STATE -Architectures: x86, s390 +Architectures: x86, s390, arm, arm64 Type: vcpu ioctl Parameters: struct kvm_mp_state (out) Returns: 0 on success; -1 on error @@ -1011,7 +1011,7 @@ uniprocessor guests). Possible values are: - - KVM_MP_STATE_RUNNABLE: the vcpu is currently running [x86] + - KVM_MP_STATE_RUNNABLE: the vcpu is currently running [x86,arm/arm64] - KVM_MP_STATE_UNINITIALIZED: the vcpu is an application processor (AP) which has not yet received an INIT signal [x86] - KVM_MP_STATE_INIT_RECEIVED: the vcpu has received an INIT signal, and is @@ -1020,7 +1020,7 @@ Possible values are: is waiting for an interrupt [x86] - KVM_MP_STATE_SIPI_RECEIVED: the vcpu has just received a SIPI (vector accessible via KVM_GET_VCPU_EVENTS) [x86] - - KVM_MP_STATE_STOPPED: the vcpu is stopped [s390] + - KVM_MP_STATE_STOPPED: the vcpu is stopped [s390,arm/arm64] - KVM_MP_STATE_CHECK_STOP: the vcpu is in a special error state [s390] - KVM_MP_STATE_OPERATING: the vcpu is operating (running or halted) [s390] @@ -1031,11 +1031,15 @@ On x86, this ioctl is only useful after KVM_CREATE_IRQCHIP. Without an in-kernel irqchip, the multiprocessing state must be maintained by userspace on these architectures. +For arm/arm64: + +The only states that are valid are KVM_MP_STATE_STOPPED and +KVM_MP_STATE_RUNNABLE which reflect if the vcpu is paused or not. 4.39 KVM_SET_MP_STATE Capability: KVM_CAP_MP_STATE -Architectures: x86, s390 +Architectures: x86, s390, arm, arm64 Type: vcpu ioctl Parameters: struct kvm_mp_state (in) Returns: 0 on success; -1 on error @@ -1047,6 +1051,10 @@ On x86, this ioctl is only useful after KVM_CREATE_IRQCHIP. Without an in-kernel irqchip, the multiprocessing state must be maintained by userspace on these architectures. +For arm/arm64: + +The only states that are valid are KVM_MP_STATE_STOPPED and +KVM_MP_STATE_RUNNABLE which reflect if the vcpu should be paused or not. 4.40 KVM_SET_IDENTITY_MAP_ADDR diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index cc96619f10a4..9a5f057a97a3 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -180,6 +180,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_ARM_PSCI: case KVM_CAP_ARM_PSCI_0_2: case KVM_CAP_READONLY_MEM: + case KVM_CAP_MP_STATE: r = 1; break; case KVM_CAP_COALESCED_MMIO: @@ -310,13 +311,29 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu, struct kvm_mp_state *mp_state) { - return -EINVAL; + if (vcpu->arch.pause) + mp_state->mp_state = KVM_MP_STATE_STOPPED; + else + mp_state->mp_state = KVM_MP_STATE_RUNNABLE; + + return 0; } int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu, struct kvm_mp_state *mp_state) { - return -EINVAL; + switch (mp_state->mp_state) { + case KVM_MP_STATE_RUNNABLE: + vcpu->arch.pause = false; + break; + case KVM_MP_STATE_STOPPED: + vcpu->arch.pause = true; + break; + default: + return -EINVAL; + } + + return 0; } /** -- cgit v1.2.3-59-g8ed1b From d5d7c4af759be386d45e21f6758fb516d0c1c165 Mon Sep 17 00:00:00 2001 From: Darshana Padmadas Date: Fri, 13 Mar 2015 21:06:58 +0530 Subject: iio: Add ABI documentation for in_magn offset value This patch adds ABI documentation entries for in_magn_offset. There is one user, hid-sensor-magn-3d in drivers/iio/magnetometer. Signed-off-by: Darshana Padmadas Reviewed-by: Daniel Baluta Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 923070934228..0b62e649a77a 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -253,6 +253,7 @@ What: /sys/bus/iio/devices/iio:deviceX/in_temp_offset What: /sys/bus/iio/devices/iio:deviceX/in_pressureY_offset What: /sys/bus/iio/devices/iio:deviceX/in_pressure_offset What: /sys/bus/iio/devices/iio:deviceX/in_humidityrelative_offset +What: /sys/bus/iio/devices/iio:deviceX/in_magn_offset KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org Description: -- cgit v1.2.3-59-g8ed1b From 1fad034c636cb57686f778d1c80513acbdaf8ec5 Mon Sep 17 00:00:00 2001 From: Haneen Mohammed Date: Thu, 12 Mar 2015 18:52:50 +0300 Subject: iio: Add ABI documentation for proximity scan_elements This patch adds ABI documentation entries for in_proximity_en, in_proximity_type, and in_proximity_index in the scan_elements directory. At least one user for these is present, the AS3935 Franklin lightning sensor. Signed-off-by: Haneen Mohammed Reviewed-by: Daniel Baluta Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 3 +++ 1 file changed, 3 insertions(+) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 0b62e649a77a..406b610633b9 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -1016,6 +1016,7 @@ What: /sys/.../iio:deviceX/scan_elements/in_incli_y_en What: /sys/.../iio:deviceX/scan_elements/in_pressureY_en What: /sys/.../iio:deviceX/scan_elements/in_pressure_en What: /sys/.../iio:deviceX/scan_elements/in_rot_quaternion_en +What: /sys/.../iio:deviceX/scan_elements/in_proximity_en KernelVersion: 2.6.37 Contact: linux-iio@vger.kernel.org Description: @@ -1032,6 +1033,7 @@ What: /sys/.../iio:deviceX/scan_elements/in_timestamp_type What: /sys/.../iio:deviceX/scan_elements/in_pressureY_type What: /sys/.../iio:deviceX/scan_elements/in_pressure_type What: /sys/.../iio:deviceX/scan_elements/in_rot_quaternion_type +What: /sys/.../iio:deviceX/scan_elements/in_proximity_type KernelVersion: 2.6.37 Contact: linux-iio@vger.kernel.org Description: @@ -1083,6 +1085,7 @@ What: /sys/.../iio:deviceX/scan_elements/in_timestamp_index What: /sys/.../iio:deviceX/scan_elements/in_pressureY_index What: /sys/.../iio:deviceX/scan_elements/in_pressure_index What: /sys/.../iio:deviceX/scan_elements/in_rot_quaternion_index +What: /sys/.../iio:deviceX/scan_elements/in_proximity_index KernelVersion: 2.6.37 Contact: linux-iio@vger.kernel.org Description: -- cgit v1.2.3-59-g8ed1b From 40dbbfb5e49c9317a24111bb71151090e8ea95e8 Mon Sep 17 00:00:00 2001 From: Haneen Mohammed Date: Thu, 12 Mar 2015 21:26:00 +0300 Subject: iio : Add ABI documentation for thresh falling/rising value in accel This patch adds ABI documentation entries for in_accel_thresh_falling_value, and in_accel_thresh_rising_value in /events. There is at least one user for these, lis3l02dq in accel. Signed-off-by: Haneen Mohammed Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 2 ++ 1 file changed, 2 insertions(+) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 406b610633b9..6be17c2c5c65 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -613,6 +613,8 @@ Description: a given event type is enabled a future point (and not those for whatever event was previously enabled). +What: /sys/.../events/in_accel_thresh_rising_value +What: /sys/.../events/in_accel_thresh_falling_value What: /sys/.../events/in_accel_x_raw_thresh_rising_value What: /sys/.../events/in_accel_x_raw_thresh_falling_value What: /sys/.../events/in_accel_y_raw_thresh_rising_value -- cgit v1.2.3-59-g8ed1b From f6f53169ead6c9604b4358ccc7e0568d7bba2941 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 11 Mar 2015 15:43:02 +0000 Subject: DT: tegra: add binding for the legacy interrupt controller Signed-off-by: Marc Zyngier Link: https://lkml.kernel.org/r/1426088583-15097-6-git-send-email-marc.zyngier@arm.com Signed-off-by: Jason Cooper --- .../interrupt-controller/nvidia,tegra-ictlr.txt | 43 ++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/nvidia,tegra-ictlr.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/interrupt-controller/nvidia,tegra-ictlr.txt b/Documentation/devicetree/bindings/interrupt-controller/nvidia,tegra-ictlr.txt new file mode 100644 index 000000000000..1099fe0788fa --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/nvidia,tegra-ictlr.txt @@ -0,0 +1,43 @@ +NVIDIA Legacy Interrupt Controller + +All Tegra SoCs contain a legacy interrupt controller that routes +interrupts to the GIC, and also serves as a wakeup source. It is also +referred to as "ictlr", hence the name of the binding. + +The HW block exposes a number of interrupt controllers, each +implementing a set of 32 interrupts. + +Required properties: + +- compatible : should be: "nvidia,tegra-ictlr". The LIC on + subsequent SoCs remained backwards-compatible with Tegra30, so on + Tegra generations later than Tegra30 the compatible value should + include "nvidia,tegra30-ictlr". +- reg : Specifies base physical address and size of the registers. + Each controller must be described separately (Tegra20 has 4 of them, + whereas Tegra30 and later have 5" +- interrupt-controller : Identifies the node as an interrupt controller. +- #interrupt-cells : Specifies the number of cells needed to encode an + interrupt source. The value must be 3. +- interrupt-parent : a phandle to the GIC these interrupts are routed + to. + +Notes: + +- Because this HW ultimately routes interrupts to the GIC, the + interrupt specifier must be that of the GIC. +- Only SPIs can use the ictlr as an interrupt parent. SGIs and PPIs + are explicitly forbidden. + +Example: + + ictlr: interrupt-controller@60004000 { + compatible = "nvidia,tegra20-ictlr", "nvidia,tegra-ictlr"; + reg = <0x60004000 64>, + <0x60004100 64>, + <0x60004200 64>, + <0x60004300 64>; + interrupt-controller; + #interrupt-cells = <3>; + interrupt-parent = <&intc>; + }; -- cgit v1.2.3-59-g8ed1b From 1e7449ba67506b84f23dbd4a0667c09184df1368 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 11 Mar 2015 15:43:45 +0000 Subject: DT: update ti,irq-crossbar binding Make it look like a real interrupt controller. Acked-by: Tony Lindgren Signed-off-by: Marc Zyngier Link: https://lkml.kernel.org/r/1426088629-15377-4-git-send-email-marc.zyngier@arm.com Signed-off-by: Jason Cooper --- .../devicetree/bindings/arm/omap/crossbar.txt | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/omap/crossbar.txt b/Documentation/devicetree/bindings/arm/omap/crossbar.txt index 4139db353d0a..a9b28d74d902 100644 --- a/Documentation/devicetree/bindings/arm/omap/crossbar.txt +++ b/Documentation/devicetree/bindings/arm/omap/crossbar.txt @@ -9,7 +9,9 @@ inputs. Required properties: - compatible : Should be "ti,irq-crossbar" - reg: Base address and the size of the crossbar registers. -- ti,max-irqs: Total number of irqs available at the interrupt controller. +- interrupt-controller: indicates that this block is an interrupt controller. +- interrupt-parent: the interrupt controller this block is connected to. +- ti,max-irqs: Total number of irqs available at the parent interrupt controller. - ti,max-crossbar-sources: Maximum number of crossbar sources that can be routed. - ti,reg-size: Size of a individual register in bytes. Every individual register is assumed to be of same size. Valid sizes are 1, 2, 4. @@ -27,13 +29,13 @@ Optional properties: when the interrupt controller irq is unused (when not provided, default is 0) Examples: - crossbar_mpu: @4a020000 { + crossbar_mpu: crossbar@4a002a48 { compatible = "ti,irq-crossbar"; reg = <0x4a002a48 0x130>; ti,max-irqs = <160>; ti,max-crossbar-sources = <400>; ti,reg-size = <2>; - ti,irqs-reserved = <0 1 2 3 5 6 131 132 139 140>; + ti,irqs-reserved = <0 1 2 3 5 6 131 132>; ti,irqs-skip = <10 133 139 140>; }; @@ -44,10 +46,6 @@ Documentation/devicetree/bindings/arm/gic.txt for further details. An interrupt consumer on an SoC using crossbar will use: interrupts = -When the request number is between 0 to that described by -"ti,max-crossbar-sources", it is assumed to be a crossbar mapping. If the -request_number is greater than "ti,max-crossbar-sources", then it is mapped as a -quirky hardware mapping direct to GIC. Example: device_x@0x4a023000 { @@ -55,9 +53,3 @@ Example: interrupts = ; ... }; - - device_y@0x4a033000 { - /* Direct mapped GIC SPI 1 used */ - interrupts = ; - ... - }; -- cgit v1.2.3-59-g8ed1b From 994dd8a3283cd332801ccbe099b2517e8b7055d0 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 11 Mar 2015 15:43:47 +0000 Subject: DT: arm,gic: kill arm,routable-irqs Nobody will regret it. Acked-by: Tony Lindgren Signed-off-by: Marc Zyngier Link: https://lkml.kernel.org/r/1426088629-15377-6-git-send-email-marc.zyngier@arm.com Signed-off-by: Jason Cooper --- Documentation/devicetree/bindings/arm/gic.txt | 6 ------ 1 file changed, 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/gic.txt b/Documentation/devicetree/bindings/arm/gic.txt index c97484b73e72..1e0d21201d3a 100644 --- a/Documentation/devicetree/bindings/arm/gic.txt +++ b/Documentation/devicetree/bindings/arm/gic.txt @@ -56,11 +56,6 @@ Optional regions, used when the GIC doesn't have banked registers. The offset is cpu-offset * cpu-nr. -- arm,routable-irqs : Total number of gic irq inputs which are not directly - connected from the peripherals, but are routed dynamically - by a crossbar/multiplexer preceding the GIC. The GIC irq - input line is assigned dynamically when the corresponding - peripheral's crossbar line is mapped. Example: intc: interrupt-controller@fff11000 { @@ -68,7 +63,6 @@ Example: #interrupt-cells = <3>; #address-cells = <1>; interrupt-controller; - arm,routable-irqs = <160>; reg = <0xfff11000 0x1000>, <0xfff10100 0x100>; }; -- cgit v1.2.3-59-g8ed1b From 918d98db8c97c01e538e6438e18a69cbceeb5ec6 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 11 Mar 2015 15:43:48 +0000 Subject: DT: omap4/5: add binding for the wake-up generator Add a binding for the OMAP4/5 wake-up generator, which acts as an interrupt controller feeding into the GIC. Acked-by: Tony Lindgren Signed-off-by: Marc Zyngier Link: https://lkml.kernel.org/r/1426088629-15377-7-git-send-email-marc.zyngier@arm.com Signed-off-by: Jason Cooper --- .../interrupt-controller/ti,omap4-wugen-mpu | 33 ++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/ti,omap4-wugen-mpu (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/interrupt-controller/ti,omap4-wugen-mpu b/Documentation/devicetree/bindings/interrupt-controller/ti,omap4-wugen-mpu new file mode 100644 index 000000000000..43effa0a4fe7 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/ti,omap4-wugen-mpu @@ -0,0 +1,33 @@ +TI OMAP4 Wake-up Generator + +All TI OMAP4/5 (and their derivatives) an interrupt controller that +routes interrupts to the GIC, and also serves as a wakeup source. It +is also referred to as "WUGEN-MPU", hence the name of the binding. + +Reguired properties: + +- compatible : should contain at least "ti,omap4-wugen-mpu" or + "ti,omap5-wugen-mpu" +- reg : Specifies base physical address and size of the registers. +- interrupt-controller : Identifies the node as an interrupt controller. +- #interrupt-cells : Specifies the number of cells needed to encode an + interrupt source. The value must be 3. +- interrupt-parent : a phandle to the GIC these interrupts are routed + to. + +Notes: + +- Because this HW ultimately routes interrupts to the GIC, the + interrupt specifier must be that of the GIC. +- Only SPIs can use the WUGEN as an interrupt parent. SGIs and PPIs + are explicitly forbiden. + +Example: + + wakeupgen: interrupt-controller@48281000 { + compatible = "ti,omap5-wugen-mpu", "ti,omap4-wugen-mpu"; + interrupt-controller; + #interrupt-cells = <3>; + reg = <0x48281000 0x1000>; + interrupt-parent = <&gic>; + }; -- cgit v1.2.3-59-g8ed1b From 5986ac4fcb451160acdc8bf3a0b81ac9a72b3251 Mon Sep 17 00:00:00 2001 From: James Hartley Date: Thu, 12 Mar 2015 23:17:27 +0000 Subject: Documentation: crypto: Add DT binding info for the img hw hash accelerator This adds the binding documentation for the Imagination Technologies hash accelerator that provides hardware acceleration for SHA1/SHA224/SHA256/MD5 hashes. This hardware will be present in the upcoming pistachio SoC. Signed-off-by: James Hartley Reviewed-by: Andrew Bresticker Signed-off-by: Herbert Xu --- .../devicetree/bindings/crypto/img-hash.txt | 27 ++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 Documentation/devicetree/bindings/crypto/img-hash.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/crypto/img-hash.txt b/Documentation/devicetree/bindings/crypto/img-hash.txt new file mode 100644 index 000000000000..91a3d757d641 --- /dev/null +++ b/Documentation/devicetree/bindings/crypto/img-hash.txt @@ -0,0 +1,27 @@ +Imagination Technologies hardware hash accelerator + +The hash accelerator provides hardware hashing acceleration for +SHA1, SHA224, SHA256 and MD5 hashes + +Required properties: + +- compatible : "img,hash-accelerator" +- reg : Offset and length of the register set for the module, and the DMA port +- interrupts : The designated IRQ line for the hashing module. +- dmas : DMA specifier as per Documentation/devicetree/bindings/dma/dma.txt +- dma-names : Should be "tx" +- clocks : Clock specifiers +- clock-names : "sys" Used to clock the hash block registers + "hash" Used to clock data through the accelerator + +Example: + + hash: hash@18149600 { + compatible = "img,hash-accelerator"; + reg = <0x18149600 0x100>, <0x18101100 0x4>; + interrupts = ; + dmas = <&dma 8 0xffffffff 0>; + dma-names = "tx"; + clocks = <&cr_periph SYS_CLK_HASH>, <&clk_periph PERIPH_CLK_ROM>; + clock-names = "sys", "hash"; + }; -- cgit v1.2.3-59-g8ed1b From 97a33ced310ab9bdb16699c2c64b28f29de0a23d Mon Sep 17 00:00:00 2001 From: Kenneth Westfield Date: Fri, 13 Mar 2015 00:54:16 -0700 Subject: ASoC: qcom: Change qcom,adsp in LPASS CPU bindings Change the representation of the audio DSP, in the LPASS CPU bindings description, from a required subnode to an optional phandle. Signed-off-by: Kenneth Westfield Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt b/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt index e7c6e9321863..e00732dac939 100644 --- a/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt +++ b/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt @@ -22,13 +22,9 @@ Required properties: - reg-names : A list which must include the following entries: * "lpass-lpaif" -Required subnodes: +Optional properties: -- qcom,adsp : Audio DSP sub-node - -Optional Audio DSP subnode properties: - -- status : "disabled" indicates the adsp is not available. +- qcom,adsp : Phandle for the audio DSP node Example: @@ -43,7 +39,5 @@ lpass@28100000 { pinctrl-1 = <&mi2s_idle>; reg = <0x28100000 0x10000>; reg-names = "lpass-lpaif"; - qcom,adsp { - status = "disabled"; - }; + qcom,adsp = <&adsp>; }; -- cgit v1.2.3-59-g8ed1b From 81ddc01d56d773eed414b5c1a7f1dba1db35f538 Mon Sep 17 00:00:00 2001 From: Kenneth Westfield Date: Fri, 13 Mar 2015 01:01:04 -0700 Subject: ASoC: qcom: Document Storm bindings Add documentation to the sound directory of the device-tree bindings for the soundcard of the Storm board. Signed-off-by: Kenneth Westfield Acked-by: Banajit Goswami Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/storm.txt | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/storm.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/storm.txt b/Documentation/devicetree/bindings/sound/storm.txt new file mode 100644 index 000000000000..062a4c185fa9 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/storm.txt @@ -0,0 +1,23 @@ +* Sound complex for Storm boards + +Models a soundcard for Storm boards with the Qualcomm Technologies IPQ806x SOC +connected to a MAX98357A DAC via I2S. + +Required properties: + +- compatible : "google,storm-audio" +- cpu : Phandle of the CPU DAI +- codec : Phandle of the codec DAI + +Optional properties: + +- qcom,model : The user-visible name of this sound card. + +Example: + +sound { + compatible = "google,storm-audio"; + qcom,model = "ipq806x-storm"; + cpu = <&lpass_cpu>; + codec = <&max98357a>; +}; -- cgit v1.2.3-59-g8ed1b From ee23d66af9219dfe2407a9b08ef9a165dbe6f994 Mon Sep 17 00:00:00 2001 From: Jassi Brar Date: Thu, 26 Jun 2014 19:09:42 +0530 Subject: mailbox: arm_mhu: add driver for ARM MHU controller Add driver for the ARM Primecell Message-Handling-Unit(MHU) controller. Signed-off-by: Jassi Brar Signed-off-by: Andy Green Signed-off-by: Vincent Yang Signed-off-by: Tetsuya Nuriya --- .../devicetree/bindings/mailbox/arm-mhu.txt | 43 +++++ drivers/mailbox/Kconfig | 9 + drivers/mailbox/Makefile | 2 + drivers/mailbox/arm_mhu.c | 195 +++++++++++++++++++++ 4 files changed, 249 insertions(+) create mode 100644 Documentation/devicetree/bindings/mailbox/arm-mhu.txt create mode 100644 drivers/mailbox/arm_mhu.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mailbox/arm-mhu.txt b/Documentation/devicetree/bindings/mailbox/arm-mhu.txt new file mode 100644 index 000000000000..4971f03f0b33 --- /dev/null +++ b/Documentation/devicetree/bindings/mailbox/arm-mhu.txt @@ -0,0 +1,43 @@ +ARM MHU Mailbox Driver +====================== + +The ARM's Message-Handling-Unit (MHU) is a mailbox controller that has +3 independent channels/links to communicate with remote processor(s). + MHU links are hardwired on a platform. A link raises interrupt for any +received data. However, there is no specified way of knowing if the sent +data has been read by the remote. This driver assumes the sender polls +STAT register and the remote clears it after having read the data. +The last channel is specified to be a 'Secure' resource, hence can't be +used by Linux running NS. + +Mailbox Device Node: +==================== + +Required properties: +-------------------- +- compatible: Shall be "arm,mhu" & "arm,primecell" +- reg: Contains the mailbox register address range (base + address and length) +- #mbox-cells Shall be 1 - the index of the channel needed. +- interrupts: Contains the interrupt information corresponding to + each of the 3 links of MHU. + +Example: +-------- + + mhu: mailbox@2b1f0000 { + #mbox-cells = <1>; + compatible = "arm,mhu", "arm,primecell"; + reg = <0 0x2b1f0000 0x1000>; + interrupts = <0 36 4>, /* LP-NonSecure */ + <0 35 4>, /* HP-NonSecure */ + <0 37 4>; /* Secure */ + clocks = <&clock 0 2 1>; + clock-names = "apb_pclk"; + }; + + mhu_client: scb@2e000000 { + compatible = "fujitsu,mb86s70-scb-1.0"; + reg = <0 0x2e000000 0x4000>; + mboxes = <&mhu 1>; /* HP-NonSecure */ + }; diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index 84325f267acf..84b0a2d74d60 100644 --- a/drivers/mailbox/Kconfig +++ b/drivers/mailbox/Kconfig @@ -6,6 +6,15 @@ menuconfig MAILBOX signals. Say Y if your platform supports hardware mailboxes. if MAILBOX + +config ARM_MHU + tristate "ARM MHU Mailbox" + depends on ARM_AMBA + help + Say Y here if you want to build the ARM MHU controller driver. + The controller has 3 mailbox channels, the last of which can be + used in Secure mode only. + config PL320_MBOX bool "ARM PL320 Mailbox" depends on ARM_AMBA diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index 2e79231154cf..b18201e97e29 100644 --- a/drivers/mailbox/Makefile +++ b/drivers/mailbox/Makefile @@ -2,6 +2,8 @@ obj-$(CONFIG_MAILBOX) += mailbox.o +obj-$(CONFIG_ARM_MHU) += arm_mhu.o + obj-$(CONFIG_PL320_MBOX) += pl320-ipc.o obj-$(CONFIG_OMAP2PLUS_MBOX) += omap-mailbox.o diff --git a/drivers/mailbox/arm_mhu.c b/drivers/mailbox/arm_mhu.c new file mode 100644 index 000000000000..ac693c635357 --- /dev/null +++ b/drivers/mailbox/arm_mhu.c @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2013-2015 Fujitsu Semiconductor Ltd. + * Copyright (C) 2015 Linaro Ltd. + * Author: Jassi Brar + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define INTR_STAT_OFS 0x0 +#define INTR_SET_OFS 0x8 +#define INTR_CLR_OFS 0x10 + +#define MHU_LP_OFFSET 0x0 +#define MHU_HP_OFFSET 0x20 +#define MHU_SEC_OFFSET 0x200 +#define TX_REG_OFFSET 0x100 + +#define MHU_CHANS 3 + +struct mhu_link { + unsigned irq; + void __iomem *tx_reg; + void __iomem *rx_reg; +}; + +struct arm_mhu { + void __iomem *base; + struct mhu_link mlink[MHU_CHANS]; + struct mbox_chan chan[MHU_CHANS]; + struct mbox_controller mbox; +}; + +static irqreturn_t mhu_rx_interrupt(int irq, void *p) +{ + struct mbox_chan *chan = p; + struct mhu_link *mlink = chan->con_priv; + u32 val; + + val = readl_relaxed(mlink->rx_reg + INTR_STAT_OFS); + if (!val) + return IRQ_NONE; + + mbox_chan_received_data(chan, (void *)&val); + + writel_relaxed(val, mlink->rx_reg + INTR_CLR_OFS); + + return IRQ_HANDLED; +} + +static bool mhu_last_tx_done(struct mbox_chan *chan) +{ + struct mhu_link *mlink = chan->con_priv; + u32 val = readl_relaxed(mlink->tx_reg + INTR_STAT_OFS); + + return (val == 0); +} + +static int mhu_send_data(struct mbox_chan *chan, void *data) +{ + struct mhu_link *mlink = chan->con_priv; + u32 *arg = data; + + writel_relaxed(*arg, mlink->tx_reg + INTR_SET_OFS); + + return 0; +} + +static int mhu_startup(struct mbox_chan *chan) +{ + struct mhu_link *mlink = chan->con_priv; + u32 val; + int ret; + + val = readl_relaxed(mlink->tx_reg + INTR_STAT_OFS); + writel_relaxed(val, mlink->tx_reg + INTR_CLR_OFS); + + ret = request_irq(mlink->irq, mhu_rx_interrupt, + IRQF_SHARED, "mhu_link", chan); + if (ret) { + dev_err(chan->mbox->dev, + "Unable to aquire IRQ %d\n", mlink->irq); + return ret; + } + + return 0; +} + +static void mhu_shutdown(struct mbox_chan *chan) +{ + struct mhu_link *mlink = chan->con_priv; + + free_irq(mlink->irq, chan); +} + +static struct mbox_chan_ops mhu_ops = { + .send_data = mhu_send_data, + .startup = mhu_startup, + .shutdown = mhu_shutdown, + .last_tx_done = mhu_last_tx_done, +}; + +static int mhu_probe(struct amba_device *adev, const struct amba_id *id) +{ + int i, err; + struct arm_mhu *mhu; + struct device *dev = &adev->dev; + int mhu_reg[MHU_CHANS] = {MHU_LP_OFFSET, MHU_HP_OFFSET, MHU_SEC_OFFSET}; + + /* Allocate memory for device */ + mhu = devm_kzalloc(dev, sizeof(*mhu), GFP_KERNEL); + if (!mhu) + return -ENOMEM; + + mhu->base = devm_ioremap_resource(dev, &adev->res); + if (IS_ERR(mhu->base)) { + dev_err(dev, "ioremap failed\n"); + return PTR_ERR(mhu->base); + } + + for (i = 0; i < MHU_CHANS; i++) { + mhu->chan[i].con_priv = &mhu->mlink[i]; + mhu->mlink[i].irq = adev->irq[i]; + mhu->mlink[i].rx_reg = mhu->base + mhu_reg[i]; + mhu->mlink[i].tx_reg = mhu->mlink[i].rx_reg + TX_REG_OFFSET; + } + + mhu->mbox.dev = dev; + mhu->mbox.chans = &mhu->chan[0]; + mhu->mbox.num_chans = MHU_CHANS; + mhu->mbox.ops = &mhu_ops; + mhu->mbox.txdone_irq = false; + mhu->mbox.txdone_poll = true; + mhu->mbox.txpoll_period = 10; + + amba_set_drvdata(adev, mhu); + + err = mbox_controller_register(&mhu->mbox); + if (err) { + dev_err(dev, "Failed to register mailboxes %d\n", err); + return err; + } + + dev_info(dev, "ARM MHU Mailbox registered\n"); + return 0; +} + +static int mhu_remove(struct amba_device *adev) +{ + struct arm_mhu *mhu = amba_get_drvdata(adev); + + mbox_controller_unregister(&mhu->mbox); + + return 0; +} + +static struct amba_id mhu_ids[] = { + { + .id = 0x1bb098, + .mask = 0xffffff, + }, + { 0, 0 }, +}; +MODULE_DEVICE_TABLE(amba, mhu_ids); + +static struct amba_driver arm_mhu_driver = { + .drv = { + .name = "mhu", + }, + .id_table = mhu_ids, + .probe = mhu_probe, + .remove = mhu_remove, +}; +module_amba_driver(arm_mhu_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("ARM MHU Driver"); +MODULE_AUTHOR("Jassi Brar "); -- cgit v1.2.3-59-g8ed1b From 41408c28f283b49202ae374b1c42bc8e9b33a048 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 6 Feb 2015 15:01:21 +0100 Subject: KVM: s390: Add MEMOP ioctls for reading/writing guest memory On s390, we've got to make sure to hold the IPTE lock while accessing logical memory. So let's add an ioctl for reading and writing logical memory to provide this feature for userspace, too. The maximum transfer size of this call is limited to 64kB to prevent that the guest can trigger huge copy_from/to_user transfers. QEMU currently only requests up to one or two pages so far, so 16*4kB seems to be a reasonable limit here. Signed-off-by: Thomas Huth Signed-off-by: Christian Borntraeger --- Documentation/virtual/kvm/api.txt | 46 ++++++++++++++++++++++++ arch/s390/kvm/gaccess.c | 22 ++++++++++++ arch/s390/kvm/gaccess.h | 2 ++ arch/s390/kvm/kvm-s390.c | 74 +++++++++++++++++++++++++++++++++++++++ include/uapi/linux/kvm.h | 21 +++++++++++ 5 files changed, 165 insertions(+) (limited to 'Documentation') diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index ee47998ec368..281179d92a28 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -2716,6 +2716,52 @@ The fields in each entry are defined as follows: eax, ebx, ecx, edx: the values returned by the cpuid instruction for this function/index combination +4.89 KVM_S390_MEM_OP + +Capability: KVM_CAP_S390_MEM_OP +Architectures: s390 +Type: vcpu ioctl +Parameters: struct kvm_s390_mem_op (in) +Returns: = 0 on success, + < 0 on generic error (e.g. -EFAULT or -ENOMEM), + > 0 if an exception occurred while walking the page tables + +Read or write data from/to the logical (virtual) memory of a VPCU. + +Parameters are specified via the following structure: + +struct kvm_s390_mem_op { + __u64 gaddr; /* the guest address */ + __u64 flags; /* flags */ + __u32 size; /* amount of bytes */ + __u32 op; /* type of operation */ + __u64 buf; /* buffer in userspace */ + __u8 ar; /* the access register number */ + __u8 reserved[31]; /* should be set to 0 */ +}; + +The type of operation is specified in the "op" field. It is either +KVM_S390_MEMOP_LOGICAL_READ for reading from logical memory space or +KVM_S390_MEMOP_LOGICAL_WRITE for writing to logical memory space. The +KVM_S390_MEMOP_F_CHECK_ONLY flag can be set in the "flags" field to check +whether the corresponding memory access would create an access exception +(without touching the data in the memory at the destination). In case an +access exception occurred while walking the MMU tables of the guest, the +ioctl returns a positive error number to indicate the type of exception. +This exception is also raised directly at the corresponding VCPU if the +flag KVM_S390_MEMOP_F_INJECT_EXCEPTION is set in the "flags" field. + +The start address of the memory region has to be specified in the "gaddr" +field, and the length of the region in the "size" field. "buf" is the buffer +supplied by the userspace application where the read data should be written +to for KVM_S390_MEMOP_LOGICAL_READ, or where the data that should be written +is stored for a KVM_S390_MEMOP_LOGICAL_WRITE. "buf" is unused and can be NULL +when KVM_S390_MEMOP_F_CHECK_ONLY is specified. "ar" designates the access +register number to be used. + +The "reserved" field is meant for future extensions. It is not used by +KVM with the currently defined set of flags. + 5. The kvm_run structure ------------------------ diff --git a/arch/s390/kvm/gaccess.c b/arch/s390/kvm/gaccess.c index ea38d716e24d..a7559f7207df 100644 --- a/arch/s390/kvm/gaccess.c +++ b/arch/s390/kvm/gaccess.c @@ -863,6 +863,28 @@ int guest_translate_address(struct kvm_vcpu *vcpu, unsigned long gva, ar_t ar, return rc; } +/** + * check_gva_range - test a range of guest virtual addresses for accessibility + */ +int check_gva_range(struct kvm_vcpu *vcpu, unsigned long gva, ar_t ar, + unsigned long length, int is_write) +{ + unsigned long gpa; + unsigned long currlen; + int rc = 0; + + ipte_lock(vcpu); + while (length > 0 && !rc) { + currlen = min(length, PAGE_SIZE - (gva % PAGE_SIZE)); + rc = guest_translate_address(vcpu, gva, ar, &gpa, is_write); + gva += currlen; + length -= currlen; + } + ipte_unlock(vcpu); + + return rc; +} + /** * kvm_s390_check_low_addr_prot_real - check for low-address protection * @gra: Guest real address diff --git a/arch/s390/kvm/gaccess.h b/arch/s390/kvm/gaccess.h index 835e557dabf4..ef03726cc661 100644 --- a/arch/s390/kvm/gaccess.h +++ b/arch/s390/kvm/gaccess.h @@ -157,6 +157,8 @@ int read_guest_lc(struct kvm_vcpu *vcpu, unsigned long gra, void *data, int guest_translate_address(struct kvm_vcpu *vcpu, unsigned long gva, ar_t ar, unsigned long *gpa, int write); +int check_gva_range(struct kvm_vcpu *vcpu, unsigned long gva, ar_t ar, + unsigned long length, int is_write); int access_guest(struct kvm_vcpu *vcpu, unsigned long ga, ar_t ar, void *data, unsigned long len, int write); diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 610e90afadf2..b7ecef98b668 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,8 @@ #include "trace.h" #include "trace-s390.h" +#define MEM_OP_MAX_SIZE 65536 /* Maximum transfer size for KVM_S390_MEM_OP */ + #define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU struct kvm_stats_debugfs_item debugfs_entries[] = { @@ -177,6 +180,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_S390_USER_SIGP: r = 1; break; + case KVM_CAP_S390_MEM_OP: + r = MEM_OP_MAX_SIZE; + break; case KVM_CAP_NR_VCPUS: case KVM_CAP_MAX_VCPUS: r = KVM_MAX_VCPUS; @@ -2185,6 +2191,65 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, return r; } +static long kvm_s390_guest_mem_op(struct kvm_vcpu *vcpu, + struct kvm_s390_mem_op *mop) +{ + void __user *uaddr = (void __user *)mop->buf; + void *tmpbuf = NULL; + int r, srcu_idx; + const u64 supported_flags = KVM_S390_MEMOP_F_INJECT_EXCEPTION + | KVM_S390_MEMOP_F_CHECK_ONLY; + + if (mop->flags & ~supported_flags) + return -EINVAL; + + if (mop->size > MEM_OP_MAX_SIZE) + return -E2BIG; + + if (!(mop->flags & KVM_S390_MEMOP_F_CHECK_ONLY)) { + tmpbuf = vmalloc(mop->size); + if (!tmpbuf) + return -ENOMEM; + } + + srcu_idx = srcu_read_lock(&vcpu->kvm->srcu); + + switch (mop->op) { + case KVM_S390_MEMOP_LOGICAL_READ: + if (mop->flags & KVM_S390_MEMOP_F_CHECK_ONLY) { + r = check_gva_range(vcpu, mop->gaddr, mop->ar, mop->size, false); + break; + } + r = read_guest(vcpu, mop->gaddr, mop->ar, tmpbuf, mop->size); + if (r == 0) { + if (copy_to_user(uaddr, tmpbuf, mop->size)) + r = -EFAULT; + } + break; + case KVM_S390_MEMOP_LOGICAL_WRITE: + if (mop->flags & KVM_S390_MEMOP_F_CHECK_ONLY) { + r = check_gva_range(vcpu, mop->gaddr, mop->ar, mop->size, true); + break; + } + if (copy_from_user(tmpbuf, uaddr, mop->size)) { + r = -EFAULT; + break; + } + r = write_guest(vcpu, mop->gaddr, mop->ar, tmpbuf, mop->size); + break; + default: + r = -EINVAL; + } + + srcu_read_unlock(&vcpu->kvm->srcu, srcu_idx); + + if (r > 0 && (mop->flags & KVM_S390_MEMOP_F_INJECT_EXCEPTION) != 0) + kvm_s390_inject_prog_irq(vcpu, &vcpu->arch.pgm); + + vfree(tmpbuf); + return r; +} + long kvm_arch_vcpu_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { @@ -2284,6 +2349,15 @@ long kvm_arch_vcpu_ioctl(struct file *filp, r = kvm_vcpu_ioctl_enable_cap(vcpu, &cap); break; } + case KVM_S390_MEM_OP: { + struct kvm_s390_mem_op mem_op; + + if (copy_from_user(&mem_op, argp, sizeof(mem_op)) == 0) + r = kvm_s390_guest_mem_op(vcpu, &mem_op); + else + r = -EFAULT; + break; + } default: r = -ENOTTY; } diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 82634a492fe0..0e16f2c9f0de 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -365,6 +365,24 @@ struct kvm_translation { __u8 pad[5]; }; +/* for KVM_S390_MEM_OP */ +struct kvm_s390_mem_op { + /* in */ + __u64 gaddr; /* the guest address */ + __u64 flags; /* flags */ + __u32 size; /* amount of bytes */ + __u32 op; /* type of operation */ + __u64 buf; /* buffer in userspace */ + __u8 ar; /* the access register number */ + __u8 reserved[31]; /* should be set to 0 */ +}; +/* types for kvm_s390_mem_op->op */ +#define KVM_S390_MEMOP_LOGICAL_READ 0 +#define KVM_S390_MEMOP_LOGICAL_WRITE 1 +/* flags for kvm_s390_mem_op->flags */ +#define KVM_S390_MEMOP_F_CHECK_ONLY (1ULL << 0) +#define KVM_S390_MEMOP_F_INJECT_EXCEPTION (1ULL << 1) + /* for KVM_INTERRUPT */ struct kvm_interrupt { /* in */ @@ -761,6 +779,7 @@ struct kvm_ppc_smmu_info { #define KVM_CAP_CHECK_EXTENSION_VM 105 #define KVM_CAP_S390_USER_SIGP 106 #define KVM_CAP_S390_VECTOR_REGISTERS 107 +#define KVM_CAP_S390_MEM_OP 108 #ifdef KVM_CAP_IRQ_ROUTING @@ -1136,6 +1155,8 @@ struct kvm_s390_ucas_mapping { #define KVM_ARM_VCPU_INIT _IOW(KVMIO, 0xae, struct kvm_vcpu_init) #define KVM_ARM_PREFERRED_TARGET _IOR(KVMIO, 0xaf, struct kvm_vcpu_init) #define KVM_GET_REG_LIST _IOWR(KVMIO, 0xb0, struct kvm_reg_list) +/* Available with KVM_CAP_S390_MEM_OP */ +#define KVM_S390_MEM_OP _IOW(KVMIO, 0xb1, struct kvm_s390_mem_op) #define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0) #define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1) -- cgit v1.2.3-59-g8ed1b From e44fc8c9dab215ac0e398622a05574cffd5f5184 Mon Sep 17 00:00:00 2001 From: Ekaterina Tumanova Date: Fri, 30 Jan 2015 16:55:56 +0100 Subject: KVM: s390: introduce post handlers for STSI The Store System Information (STSI) instruction currently collects all information it relays to the caller in the kernel. Some information, however, is only available in user space. An example of this is the guest name: The kernel always sets "KVMGuest", but user space knows the actual guest name. This patch introduces a new exit, KVM_EXIT_S390_STSI, guarded by a capability that can be enabled by user space if it wants to be able to insert such data. User space will be provided with the target buffer and the requested STSI function code. Reviewed-by: Eric Farman Reviewed-by: Christian Borntraeger Signed-off-by: Ekaterina Tumanova Signed-off-by: Christian Borntraeger --- Documentation/virtual/kvm/api.txt | 28 ++++++++++++++++++++++++++++ arch/s390/include/asm/kvm_host.h | 1 + arch/s390/kvm/kvm-s390.c | 5 +++++ arch/s390/kvm/priv.c | 17 ++++++++++++++++- include/uapi/linux/kvm.h | 11 +++++++++++ 5 files changed, 61 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 281179d92a28..c1fcb7a3c125 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -3304,3 +3304,31 @@ Returns: 0 on success, negative value on error Allows use of the vector registers introduced with z13 processor, and provides for the synchronization between host and user space. Will return -EINVAL if the machine does not support vectors. + +7.4 KVM_CAP_S390_USER_STSI + +Architectures: s390 +Parameters: none + +This capability allows post-handlers for the STSI instruction. After +initial handling in the kernel, KVM exits to user space with +KVM_EXIT_S390_STSI to allow user space to insert further data. + +Before exiting to userspace, kvm handlers should fill in s390_stsi field of +vcpu->run: +struct { + __u64 addr; + __u8 ar; + __u8 reserved; + __u8 fc; + __u8 sel1; + __u16 sel2; +} s390_stsi; + +@addr - guest address of STSI SYSIB +@fc - function code +@sel1 - selector 1 +@sel2 - selector 2 +@ar - access register number + +KVM handlers should exit to userspace with rc = -EREMOTE. diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h index 347a3333d618..2356a8c660b3 100644 --- a/arch/s390/include/asm/kvm_host.h +++ b/arch/s390/include/asm/kvm_host.h @@ -565,6 +565,7 @@ struct kvm_arch{ int use_vectors; int user_cpu_state_ctrl; int user_sigp; + int user_stsi; struct s390_io_adapter *adapters[MAX_S390_IO_ADAPTERS]; wait_queue_head_t ipte_wq; int ipte_lock_count; diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index b7ecef98b668..fdfa10662700 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -178,6 +178,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_VM_ATTRIBUTES: case KVM_CAP_MP_STATE: case KVM_CAP_S390_USER_SIGP: + case KVM_CAP_S390_USER_STSI: r = 1; break; case KVM_CAP_S390_MEM_OP: @@ -280,6 +281,10 @@ static int kvm_vm_ioctl_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap) kvm->arch.use_vectors = MACHINE_HAS_VX; r = MACHINE_HAS_VX ? 0 : -EINVAL; break; + case KVM_CAP_S390_USER_STSI: + kvm->arch.user_stsi = 1; + r = 0; + break; default: r = -EINVAL; break; diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c index f4fe02e84326..5e4658d20c77 100644 --- a/arch/s390/kvm/priv.c +++ b/arch/s390/kvm/priv.c @@ -496,6 +496,17 @@ static void handle_stsi_3_2_2(struct kvm_vcpu *vcpu, struct sysinfo_3_2_2 *mem) ASCEBC(mem->vm[0].cpi, 16); } +static void insert_stsi_usr_data(struct kvm_vcpu *vcpu, u64 addr, ar_t ar, + u8 fc, u8 sel1, u16 sel2) +{ + vcpu->run->exit_reason = KVM_EXIT_S390_STSI; + vcpu->run->s390_stsi.addr = addr; + vcpu->run->s390_stsi.ar = ar; + vcpu->run->s390_stsi.fc = fc; + vcpu->run->s390_stsi.sel1 = sel1; + vcpu->run->s390_stsi.sel2 = sel2; +} + static int handle_stsi(struct kvm_vcpu *vcpu) { int fc = (vcpu->run->s.regs.gprs[0] & 0xf0000000) >> 28; @@ -556,11 +567,15 @@ static int handle_stsi(struct kvm_vcpu *vcpu) rc = kvm_s390_inject_prog_cond(vcpu, rc); goto out; } + if (vcpu->kvm->arch.user_stsi) { + insert_stsi_usr_data(vcpu, operand2, ar, fc, sel1, sel2); + rc = -EREMOTE; + } trace_kvm_s390_handle_stsi(vcpu, fc, sel1, sel2, operand2); free_page(mem); kvm_s390_set_psw_cc(vcpu, 0); vcpu->run->s.regs.gprs[0] = 0; - return 0; + return rc; out_no_data: kvm_s390_set_psw_cc(vcpu, 3); out: diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 0e16f2c9f0de..57445ef88097 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -172,6 +172,7 @@ struct kvm_pit_config { #define KVM_EXIT_S390_TSCH 22 #define KVM_EXIT_EPR 23 #define KVM_EXIT_SYSTEM_EVENT 24 +#define KVM_EXIT_S390_STSI 25 /* For KVM_EXIT_INTERNAL_ERROR */ /* Emulate instruction failed. */ @@ -309,6 +310,15 @@ struct kvm_run { __u32 type; __u64 flags; } system_event; + /* KVM_EXIT_S390_STSI */ + struct { + __u64 addr; + __u8 ar; + __u8 reserved; + __u8 fc; + __u8 sel1; + __u16 sel2; + } s390_stsi; /* Fix the size of the union. */ char padding[256]; }; @@ -780,6 +790,7 @@ struct kvm_ppc_smmu_info { #define KVM_CAP_S390_USER_SIGP 106 #define KVM_CAP_S390_VECTOR_REGISTERS 107 #define KVM_CAP_S390_MEM_OP 108 +#define KVM_CAP_S390_USER_STSI 109 #ifdef KVM_CAP_IRQ_ROUTING -- cgit v1.2.3-59-g8ed1b From 30ee2a984f07b00895e0e01d78859b3aff9307c7 Mon Sep 17 00:00:00 2001 From: "Jason J. Herne" Date: Tue, 23 Sep 2014 09:23:01 -0400 Subject: KVM: s390: Create ioctl for Getting/Setting guest storage keys Provide the KVM_S390_GET_SKEYS and KVM_S390_SET_SKEYS ioctl which can be used to get/set guest storage keys. This functionality is needed for live migration of s390 guests that use storage keys. Signed-off-by: Jason J. Herne Reviewed-by: David Hildenbrand Signed-off-by: Christian Borntraeger --- Documentation/virtual/kvm/api.txt | 58 ++++++++++++++++++ arch/s390/kvm/kvm-s390.c | 123 ++++++++++++++++++++++++++++++++++++++ include/uapi/linux/kvm.h | 14 +++++ 3 files changed, 195 insertions(+) (limited to 'Documentation') diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index c1fcb7a3c125..0d7fc66289a0 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -2762,6 +2762,64 @@ register number to be used. The "reserved" field is meant for future extensions. It is not used by KVM with the currently defined set of flags. +4.90 KVM_S390_GET_SKEYS + +Capability: KVM_CAP_S390_SKEYS +Architectures: s390 +Type: vm ioctl +Parameters: struct kvm_s390_skeys +Returns: 0 on success, KVM_S390_GET_KEYS_NONE if guest is not using storage + keys, negative value on error + +This ioctl is used to get guest storage key values on the s390 +architecture. The ioctl takes parameters via the kvm_s390_skeys struct. + +struct kvm_s390_skeys { + __u64 start_gfn; + __u64 count; + __u64 skeydata_addr; + __u32 flags; + __u32 reserved[9]; +}; + +The start_gfn field is the number of the first guest frame whose storage keys +you want to get. + +The count field is the number of consecutive frames (starting from start_gfn) +whose storage keys to get. The count field must be at least 1 and the maximum +allowed value is defined as KVM_S390_SKEYS_ALLOC_MAX. Values outside this range +will cause the ioctl to return -EINVAL. + +The skeydata_addr field is the address to a buffer large enough to hold count +bytes. This buffer will be filled with storage key data by the ioctl. + +4.91 KVM_S390_SET_SKEYS + +Capability: KVM_CAP_S390_SKEYS +Architectures: s390 +Type: vm ioctl +Parameters: struct kvm_s390_skeys +Returns: 0 on success, negative value on error + +This ioctl is used to set guest storage key values on the s390 +architecture. The ioctl takes parameters via the kvm_s390_skeys struct. +See section on KVM_S390_GET_SKEYS for struct definition. + +The start_gfn field is the number of the first guest frame whose storage keys +you want to set. + +The count field is the number of consecutive frames (starting from start_gfn) +whose storage keys to get. The count field must be at least 1 and the maximum +allowed value is defined as KVM_S390_SKEYS_ALLOC_MAX. Values outside this range +will cause the ioctl to return -EINVAL. + +The skeydata_addr field is the address to a buffer containing count bytes of +storage keys. Each byte in the buffer will be set as the storage key for a +single frame starting at start_gfn for count frames. + +Note: If any architecturally invalid key value is found in the given data then +the ioctl will return -EINVAL. + 5. The kvm_run structure ------------------------ diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index fdfa10662700..0dc22baa0a57 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -179,6 +179,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_MP_STATE: case KVM_CAP_S390_USER_SIGP: case KVM_CAP_S390_USER_STSI: + case KVM_CAP_S390_SKEYS: r = 1; break; case KVM_CAP_S390_MEM_OP: @@ -729,6 +730,108 @@ static int kvm_s390_vm_has_attr(struct kvm *kvm, struct kvm_device_attr *attr) return ret; } +static long kvm_s390_get_skeys(struct kvm *kvm, struct kvm_s390_skeys *args) +{ + uint8_t *keys; + uint64_t hva; + unsigned long curkey; + int i, r = 0; + + if (args->flags != 0) + return -EINVAL; + + /* Is this guest using storage keys? */ + if (!mm_use_skey(current->mm)) + return KVM_S390_GET_SKEYS_NONE; + + /* Enforce sane limit on memory allocation */ + if (args->count < 1 || args->count > KVM_S390_SKEYS_MAX) + return -EINVAL; + + keys = kmalloc_array(args->count, sizeof(uint8_t), + GFP_KERNEL | __GFP_NOWARN); + if (!keys) + keys = vmalloc(sizeof(uint8_t) * args->count); + if (!keys) + return -ENOMEM; + + for (i = 0; i < args->count; i++) { + hva = gfn_to_hva(kvm, args->start_gfn + i); + if (kvm_is_error_hva(hva)) { + r = -EFAULT; + goto out; + } + + curkey = get_guest_storage_key(current->mm, hva); + if (IS_ERR_VALUE(curkey)) { + r = curkey; + goto out; + } + keys[i] = curkey; + } + + r = copy_to_user((uint8_t __user *)args->skeydata_addr, keys, + sizeof(uint8_t) * args->count); + if (r) + r = -EFAULT; +out: + kvfree(keys); + return r; +} + +static long kvm_s390_set_skeys(struct kvm *kvm, struct kvm_s390_skeys *args) +{ + uint8_t *keys; + uint64_t hva; + int i, r = 0; + + if (args->flags != 0) + return -EINVAL; + + /* Enforce sane limit on memory allocation */ + if (args->count < 1 || args->count > KVM_S390_SKEYS_MAX) + return -EINVAL; + + keys = kmalloc_array(args->count, sizeof(uint8_t), + GFP_KERNEL | __GFP_NOWARN); + if (!keys) + keys = vmalloc(sizeof(uint8_t) * args->count); + if (!keys) + return -ENOMEM; + + r = copy_from_user(keys, (uint8_t __user *)args->skeydata_addr, + sizeof(uint8_t) * args->count); + if (r) { + r = -EFAULT; + goto out; + } + + /* Enable storage key handling for the guest */ + s390_enable_skey(); + + for (i = 0; i < args->count; i++) { + hva = gfn_to_hva(kvm, args->start_gfn + i); + if (kvm_is_error_hva(hva)) { + r = -EFAULT; + goto out; + } + + /* Lowest order bit is reserved */ + if (keys[i] & 0x01) { + r = -EINVAL; + goto out; + } + + r = set_guest_storage_key(current->mm, hva, + (unsigned long)keys[i], 0); + if (r) + goto out; + } +out: + kvfree(keys); + return r; +} + long kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { @@ -788,6 +891,26 @@ long kvm_arch_vm_ioctl(struct file *filp, r = kvm_s390_vm_has_attr(kvm, &attr); break; } + case KVM_S390_GET_SKEYS: { + struct kvm_s390_skeys args; + + r = -EFAULT; + if (copy_from_user(&args, argp, + sizeof(struct kvm_s390_skeys))) + break; + r = kvm_s390_get_skeys(kvm, &args); + break; + } + case KVM_S390_SET_SKEYS: { + struct kvm_s390_skeys args; + + r = -EFAULT; + if (copy_from_user(&args, argp, + sizeof(struct kvm_s390_skeys))) + break; + r = kvm_s390_set_skeys(kvm, &args); + break; + } default: r = -ENOTTY; } diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 57445ef88097..1162ef7a3fa1 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -147,6 +147,16 @@ struct kvm_pit_config { #define KVM_PIT_SPEAKER_DUMMY 1 +struct kvm_s390_skeys { + __u64 start_gfn; + __u64 count; + __u64 skeydata_addr; + __u32 flags; + __u32 reserved[9]; +}; +#define KVM_S390_GET_SKEYS_NONE 1 +#define KVM_S390_SKEYS_MAX 1048576 + #define KVM_EXIT_UNKNOWN 0 #define KVM_EXIT_EXCEPTION 1 #define KVM_EXIT_IO 2 @@ -791,6 +801,7 @@ struct kvm_ppc_smmu_info { #define KVM_CAP_S390_VECTOR_REGISTERS 107 #define KVM_CAP_S390_MEM_OP 108 #define KVM_CAP_S390_USER_STSI 109 +#define KVM_CAP_S390_SKEYS 110 #ifdef KVM_CAP_IRQ_ROUTING @@ -1168,6 +1179,9 @@ struct kvm_s390_ucas_mapping { #define KVM_GET_REG_LIST _IOWR(KVMIO, 0xb0, struct kvm_reg_list) /* Available with KVM_CAP_S390_MEM_OP */ #define KVM_S390_MEM_OP _IOW(KVMIO, 0xb1, struct kvm_s390_mem_op) +/* Available with KVM_CAP_S390_SKEYS */ +#define KVM_S390_GET_SKEYS _IOW(KVMIO, 0xb2, struct kvm_s390_skeys) +#define KVM_S390_SET_SKEYS _IOW(KVMIO, 0xb3, struct kvm_s390_skeys) #define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0) #define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1) -- cgit v1.2.3-59-g8ed1b From 341e42c4e3f97af9bbeada64c3e1a41f65ce086a Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 27 Feb 2015 16:11:35 -0800 Subject: ARM: perf: Add support for Scorpion PMUs Scorpion supports a set of local performance monitor event selection registers (LPM) sitting behind a cp15 based interface that extend the architected PMU events to include Scorpion CPU and Venum VFP specific events. To use these events the user is expected to program the lpm register with the event code shifted into the group they care about and then point the PMNx event at that region+group combo by writing a LPMn_GROUPx event. Add support for this hardware. Note: the raw event number is a pure software construct that allows us to map the multi-dimensional number space of regions, groups, and event codes into a flat event number space suitable for use by the perf framework. This is based on code originally written by Sheetal Sahasrabudhe, Ashwin Chaugule, and Neil Leeder [1]. [1] https://www.codeaurora.org/cgit/quic/la/kernel/msm/tree/arch/arm/kernel/perf_event_msm.c?h=msm-3.4 Cc: Mark Rutland Cc: Neil Leeder Cc: Ashwin Chaugule Cc: Sheetal Sahasrabudhe Cc: Signed-off-by: Stephen Boyd Signed-off-by: Will Deacon --- Documentation/devicetree/bindings/arm/pmu.txt | 2 + arch/arm/kernel/perf_event_cpu.c | 2 + arch/arm/kernel/perf_event_v7.c | 414 ++++++++++++++++++++++++++ 3 files changed, 418 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/pmu.txt b/Documentation/devicetree/bindings/arm/pmu.txt index 75ef91d08f3b..6e54a9d88b7a 100644 --- a/Documentation/devicetree/bindings/arm/pmu.txt +++ b/Documentation/devicetree/bindings/arm/pmu.txt @@ -18,6 +18,8 @@ Required properties: "arm,arm11mpcore-pmu" "arm,arm1176-pmu" "arm,arm1136-pmu" + "qcom,scorpion-pmu" + "qcom,scorpion-mp-pmu" "qcom,krait-pmu" - interrupts : 1 combined interrupt or 1 per core. If the interrupt is a per-cpu interrupt (PPI) then 1 interrupt should be specified. diff --git a/arch/arm/kernel/perf_event_cpu.c b/arch/arm/kernel/perf_event_cpu.c index 61b53c46edfa..7eb86e294c68 100644 --- a/arch/arm/kernel/perf_event_cpu.c +++ b/arch/arm/kernel/perf_event_cpu.c @@ -243,6 +243,8 @@ static const struct of_device_id cpu_pmu_of_device_ids[] = { {.compatible = "arm,arm1176-pmu", .data = armv6_1176_pmu_init}, {.compatible = "arm,arm1136-pmu", .data = armv6_1136_pmu_init}, {.compatible = "qcom,krait-pmu", .data = krait_pmu_init}, + {.compatible = "qcom,scorpion-pmu", .data = scorpion_pmu_init}, + {.compatible = "qcom,scorpion-mp-pmu", .data = scorpion_mp_pmu_init}, {}, }; diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c index fae6c4ea52e8..f4207a4dcb01 100644 --- a/arch/arm/kernel/perf_event_v7.c +++ b/arch/arm/kernel/perf_event_v7.c @@ -140,6 +140,23 @@ enum krait_perf_types { KRAIT_PERFCTR_L1_DTLB_ACCESS = 0x12210, }; +/* ARMv7 Scorpion specific event types */ +enum scorpion_perf_types { + SCORPION_LPM0_GROUP0 = 0x4c, + SCORPION_LPM1_GROUP0 = 0x50, + SCORPION_LPM2_GROUP0 = 0x54, + SCORPION_L2LPM_GROUP0 = 0x58, + SCORPION_VLPM_GROUP0 = 0x5c, + + SCORPION_ICACHE_ACCESS = 0x10053, + SCORPION_ICACHE_MISS = 0x10052, + + SCORPION_DTLB_ACCESS = 0x12013, + SCORPION_DTLB_MISS = 0x12012, + + SCORPION_ITLB_MISS = 0x12021, +}; + /* * Cortex-A8 HW events mapping * @@ -481,6 +498,49 @@ static const unsigned krait_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] [C(BPU)][C(OP_WRITE)][C(RESULT_MISS)] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, }; +/* + * Scorpion HW events mapping + */ +static const unsigned scorpion_perf_map[PERF_COUNT_HW_MAX] = { + PERF_MAP_ALL_UNSUPPORTED, + [PERF_COUNT_HW_CPU_CYCLES] = ARMV7_PERFCTR_CPU_CYCLES, + [PERF_COUNT_HW_INSTRUCTIONS] = ARMV7_PERFCTR_INSTR_EXECUTED, + [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = ARMV7_PERFCTR_PC_WRITE, + [PERF_COUNT_HW_BRANCH_MISSES] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, + [PERF_COUNT_HW_BUS_CYCLES] = ARMV7_PERFCTR_CLOCK_CYCLES, +}; + +static const unsigned scorpion_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] + [PERF_COUNT_HW_CACHE_OP_MAX] + [PERF_COUNT_HW_CACHE_RESULT_MAX] = { + PERF_CACHE_MAP_ALL_UNSUPPORTED, + /* + * The performance counters don't differentiate between read and write + * accesses/misses so this isn't strictly correct, but it's the best we + * can do. Writes and reads get combined. + */ + [C(L1D)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_DCACHE_ACCESS, + [C(L1D)][C(OP_READ)][C(RESULT_MISS)] = ARMV7_PERFCTR_L1_DCACHE_REFILL, + [C(L1D)][C(OP_WRITE)][C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_DCACHE_ACCESS, + [C(L1D)][C(OP_WRITE)][C(RESULT_MISS)] = ARMV7_PERFCTR_L1_DCACHE_REFILL, + [C(L1I)][C(OP_READ)][C(RESULT_ACCESS)] = SCORPION_ICACHE_ACCESS, + [C(L1I)][C(OP_READ)][C(RESULT_MISS)] = SCORPION_ICACHE_MISS, + /* + * Only ITLB misses and DTLB refills are supported. If users want the + * DTLB refills misses a raw counter must be used. + */ + [C(DTLB)][C(OP_READ)][C(RESULT_ACCESS)] = SCORPION_DTLB_ACCESS, + [C(DTLB)][C(OP_READ)][C(RESULT_MISS)] = SCORPION_DTLB_MISS, + [C(DTLB)][C(OP_WRITE)][C(RESULT_ACCESS)] = SCORPION_DTLB_ACCESS, + [C(DTLB)][C(OP_WRITE)][C(RESULT_MISS)] = SCORPION_DTLB_MISS, + [C(ITLB)][C(OP_READ)][C(RESULT_MISS)] = SCORPION_ITLB_MISS, + [C(ITLB)][C(OP_WRITE)][C(RESULT_MISS)] = SCORPION_ITLB_MISS, + [C(BPU)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_BRANCH_PRED, + [C(BPU)][C(OP_READ)][C(RESULT_MISS)] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, + [C(BPU)][C(OP_WRITE)][C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_BRANCH_PRED, + [C(BPU)][C(OP_WRITE)][C(RESULT_MISS)] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, +}; + /* * Perf Events' indices */ @@ -976,6 +1036,12 @@ static int krait_map_event_no_branch(struct perf_event *event) &krait_perf_cache_map, 0xFFFFF); } +static int scorpion_map_event(struct perf_event *event) +{ + return armpmu_map_event(event, &scorpion_perf_map, + &scorpion_perf_cache_map, 0xFFFFF); +} + static void armv7pmu_init(struct arm_pmu *cpu_pmu) { cpu_pmu->handle_irq = armv7pmu_handle_irq; @@ -1451,6 +1517,344 @@ static int krait_pmu_init(struct arm_pmu *cpu_pmu) cpu_pmu->clear_event_idx = krait_pmu_clear_event_idx; return 0; } + +/* + * Scorpion Local Performance Monitor Register (LPMn) + * + * 31 30 24 16 8 0 + * +--------------------------------+ + * LPM0 | EN | CC | CC | CC | CC | N = 1, R = 0 + * +--------------------------------+ + * LPM1 | EN | CC | CC | CC | CC | N = 1, R = 1 + * +--------------------------------+ + * LPM2 | EN | CC | CC | CC | CC | N = 1, R = 2 + * +--------------------------------+ + * L2LPM | EN | CC | CC | CC | CC | N = 1, R = 3 + * +--------------------------------+ + * VLPM | EN | CC | CC | CC | CC | N = 2, R = ? + * +--------------------------------+ + * EN | G=3 | G=2 | G=1 | G=0 + * + * + * Event Encoding: + * + * hwc->config_base = 0xNRCCG + * + * N = prefix, 1 for Scorpion CPU (LPMn/L2LPM), 2 for Venum VFP (VLPM) + * R = region register + * CC = class of events the group G is choosing from + * G = group or particular event + * + * Example: 0x12021 is a Scorpion CPU event in LPM2's group 1 with code 2 + * + * A region (R) corresponds to a piece of the CPU (execution unit, instruction + * unit, etc.) while the event code (CC) corresponds to a particular class of + * events (interrupts for example). An event code is broken down into + * groups (G) that can be mapped into the PMU (irq, fiqs, and irq+fiqs for + * example). + */ + +static u32 scorpion_read_pmresrn(int n) +{ + u32 val; + + switch (n) { + case 0: + asm volatile("mrc p15, 0, %0, c15, c0, 0" : "=r" (val)); + break; + case 1: + asm volatile("mrc p15, 1, %0, c15, c0, 0" : "=r" (val)); + break; + case 2: + asm volatile("mrc p15, 2, %0, c15, c0, 0" : "=r" (val)); + break; + case 3: + asm volatile("mrc p15, 3, %0, c15, c2, 0" : "=r" (val)); + break; + default: + BUG(); /* Should be validated in scorpion_pmu_get_event_idx() */ + } + + return val; +} + +static void scorpion_write_pmresrn(int n, u32 val) +{ + switch (n) { + case 0: + asm volatile("mcr p15, 0, %0, c15, c0, 0" : : "r" (val)); + break; + case 1: + asm volatile("mcr p15, 1, %0, c15, c0, 0" : : "r" (val)); + break; + case 2: + asm volatile("mcr p15, 2, %0, c15, c0, 0" : : "r" (val)); + break; + case 3: + asm volatile("mcr p15, 3, %0, c15, c2, 0" : : "r" (val)); + break; + default: + BUG(); /* Should be validated in scorpion_pmu_get_event_idx() */ + } +} + +static u32 scorpion_get_pmresrn_event(unsigned int region) +{ + static const u32 pmresrn_table[] = { SCORPION_LPM0_GROUP0, + SCORPION_LPM1_GROUP0, + SCORPION_LPM2_GROUP0, + SCORPION_L2LPM_GROUP0 }; + return pmresrn_table[region]; +} + +static void scorpion_evt_setup(int idx, u32 config_base) +{ + u32 val; + u32 mask; + u32 vval, fval; + unsigned int region = EVENT_REGION(config_base); + unsigned int group = EVENT_GROUP(config_base); + unsigned int code = EVENT_CODE(config_base); + unsigned int group_shift; + bool venum_event = EVENT_VENUM(config_base); + + group_shift = group * 8; + mask = 0xff << group_shift; + + /* Configure evtsel for the region and group */ + if (venum_event) + val = SCORPION_VLPM_GROUP0; + else + val = scorpion_get_pmresrn_event(region); + val += group; + /* Mix in mode-exclusion bits */ + val |= config_base & (ARMV7_EXCLUDE_USER | ARMV7_EXCLUDE_PL1); + armv7_pmnc_write_evtsel(idx, val); + + asm volatile("mcr p15, 0, %0, c9, c15, 0" : : "r" (0)); + + if (venum_event) { + venum_pre_pmresr(&vval, &fval); + val = venum_read_pmresr(); + val &= ~mask; + val |= code << group_shift; + val |= PMRESRn_EN; + venum_write_pmresr(val); + venum_post_pmresr(vval, fval); + } else { + val = scorpion_read_pmresrn(region); + val &= ~mask; + val |= code << group_shift; + val |= PMRESRn_EN; + scorpion_write_pmresrn(region, val); + } +} + +static void scorpion_clearpmu(u32 config_base) +{ + u32 val; + u32 vval, fval; + unsigned int region = EVENT_REGION(config_base); + unsigned int group = EVENT_GROUP(config_base); + bool venum_event = EVENT_VENUM(config_base); + + if (venum_event) { + venum_pre_pmresr(&vval, &fval); + val = venum_read_pmresr(); + val = clear_pmresrn_group(val, group); + venum_write_pmresr(val); + venum_post_pmresr(vval, fval); + } else { + val = scorpion_read_pmresrn(region); + val = clear_pmresrn_group(val, group); + scorpion_write_pmresrn(region, val); + } +} + +static void scorpion_pmu_disable_event(struct perf_event *event) +{ + unsigned long flags; + struct hw_perf_event *hwc = &event->hw; + int idx = hwc->idx; + struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu); + struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events); + + /* Disable counter and interrupt */ + raw_spin_lock_irqsave(&events->pmu_lock, flags); + + /* Disable counter */ + armv7_pmnc_disable_counter(idx); + + /* + * Clear pmresr code (if destined for PMNx counters) + */ + if (hwc->config_base & KRAIT_EVENT_MASK) + scorpion_clearpmu(hwc->config_base); + + /* Disable interrupt for this counter */ + armv7_pmnc_disable_intens(idx); + + raw_spin_unlock_irqrestore(&events->pmu_lock, flags); +} + +static void scorpion_pmu_enable_event(struct perf_event *event) +{ + unsigned long flags; + struct hw_perf_event *hwc = &event->hw; + int idx = hwc->idx; + struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu); + struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events); + + /* + * Enable counter and interrupt, and set the counter to count + * the event that we're interested in. + */ + raw_spin_lock_irqsave(&events->pmu_lock, flags); + + /* Disable counter */ + armv7_pmnc_disable_counter(idx); + + /* + * Set event (if destined for PMNx counters) + * We don't set the event for the cycle counter because we + * don't have the ability to perform event filtering. + */ + if (hwc->config_base & KRAIT_EVENT_MASK) + scorpion_evt_setup(idx, hwc->config_base); + else if (idx != ARMV7_IDX_CYCLE_COUNTER) + armv7_pmnc_write_evtsel(idx, hwc->config_base); + + /* Enable interrupt for this counter */ + armv7_pmnc_enable_intens(idx); + + /* Enable counter */ + armv7_pmnc_enable_counter(idx); + + raw_spin_unlock_irqrestore(&events->pmu_lock, flags); +} + +static void scorpion_pmu_reset(void *info) +{ + u32 vval, fval; + struct arm_pmu *cpu_pmu = info; + u32 idx, nb_cnt = cpu_pmu->num_events; + + armv7pmu_reset(info); + + /* Clear all pmresrs */ + scorpion_write_pmresrn(0, 0); + scorpion_write_pmresrn(1, 0); + scorpion_write_pmresrn(2, 0); + scorpion_write_pmresrn(3, 0); + + venum_pre_pmresr(&vval, &fval); + venum_write_pmresr(0); + venum_post_pmresr(vval, fval); + + /* Reset PMxEVNCTCR to sane default */ + for (idx = ARMV7_IDX_CYCLE_COUNTER; idx < nb_cnt; ++idx) { + armv7_pmnc_select_counter(idx); + asm volatile("mcr p15, 0, %0, c9, c15, 0" : : "r" (0)); + } +} + +static int scorpion_event_to_bit(struct perf_event *event, unsigned int region, + unsigned int group) +{ + int bit; + struct hw_perf_event *hwc = &event->hw; + struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu); + + if (hwc->config_base & VENUM_EVENT) + bit = SCORPION_VLPM_GROUP0; + else + bit = scorpion_get_pmresrn_event(region); + bit -= scorpion_get_pmresrn_event(0); + bit += group; + /* + * Lower bits are reserved for use by the counters (see + * armv7pmu_get_event_idx() for more info) + */ + bit += ARMV7_IDX_COUNTER_LAST(cpu_pmu) + 1; + + return bit; +} + +/* + * We check for column exclusion constraints here. + * Two events cant use the same group within a pmresr register. + */ +static int scorpion_pmu_get_event_idx(struct pmu_hw_events *cpuc, + struct perf_event *event) +{ + int idx; + int bit = -1; + struct hw_perf_event *hwc = &event->hw; + unsigned int region = EVENT_REGION(hwc->config_base); + unsigned int group = EVENT_GROUP(hwc->config_base); + bool venum_event = EVENT_VENUM(hwc->config_base); + bool scorpion_event = EVENT_CPU(hwc->config_base); + + if (venum_event || scorpion_event) { + /* Ignore invalid events */ + if (group > 3 || region > 3) + return -EINVAL; + + bit = scorpion_event_to_bit(event, region, group); + if (test_and_set_bit(bit, cpuc->used_mask)) + return -EAGAIN; + } + + idx = armv7pmu_get_event_idx(cpuc, event); + if (idx < 0 && bit >= 0) + clear_bit(bit, cpuc->used_mask); + + return idx; +} + +static void scorpion_pmu_clear_event_idx(struct pmu_hw_events *cpuc, + struct perf_event *event) +{ + int bit; + struct hw_perf_event *hwc = &event->hw; + unsigned int region = EVENT_REGION(hwc->config_base); + unsigned int group = EVENT_GROUP(hwc->config_base); + bool venum_event = EVENT_VENUM(hwc->config_base); + bool scorpion_event = EVENT_CPU(hwc->config_base); + + if (venum_event || scorpion_event) { + bit = scorpion_event_to_bit(event, region, group); + clear_bit(bit, cpuc->used_mask); + } +} + +static int scorpion_pmu_init(struct arm_pmu *cpu_pmu) +{ + armv7pmu_init(cpu_pmu); + cpu_pmu->name = "armv7_scorpion"; + cpu_pmu->map_event = scorpion_map_event; + cpu_pmu->num_events = armv7_read_num_pmnc_events(); + cpu_pmu->reset = scorpion_pmu_reset; + cpu_pmu->enable = scorpion_pmu_enable_event; + cpu_pmu->disable = scorpion_pmu_disable_event; + cpu_pmu->get_event_idx = scorpion_pmu_get_event_idx; + cpu_pmu->clear_event_idx = scorpion_pmu_clear_event_idx; + return 0; +} + +static int scorpion_mp_pmu_init(struct arm_pmu *cpu_pmu) +{ + armv7pmu_init(cpu_pmu); + cpu_pmu->name = "armv7_scorpion_mp"; + cpu_pmu->map_event = scorpion_map_event; + cpu_pmu->num_events = armv7_read_num_pmnc_events(); + cpu_pmu->reset = scorpion_pmu_reset; + cpu_pmu->enable = scorpion_pmu_enable_event; + cpu_pmu->disable = scorpion_pmu_disable_event; + cpu_pmu->get_event_idx = scorpion_pmu_get_event_idx; + cpu_pmu->clear_event_idx = scorpion_pmu_clear_event_idx; + return 0; +} #else static inline int armv7_a8_pmu_init(struct arm_pmu *cpu_pmu) { @@ -1491,4 +1895,14 @@ static inline int krait_pmu_init(struct arm_pmu *cpu_pmu) { return -ENODEV; } + +static inline int scorpion_pmu_init(struct arm_pmu *cpu_pmu) +{ + return -ENODEV; +} + +static inline int scorpion_mp_pmu_init(struct arm_pmu *cpu_pmu) +{ + return -ENODEV; +} #endif /* CONFIG_CPU_V7 */ -- cgit v1.2.3-59-g8ed1b From 3e16de16fa2ac54de6a62a9776dcb52a9f57b516 Mon Sep 17 00:00:00 2001 From: Ray Jui Date: Wed, 4 Mar 2015 16:35:50 -0800 Subject: pinctrl: Broadcom Cygnus pinctrl device tree binding Device tree binding documentation for Broadcom Cygnus IOMUX driver Signed-off-by: Ray Jui Reviewed-by: Scott Branden Signed-off-by: Linus Walleij --- .../bindings/pinctrl/brcm,cygnus-pinmux.txt | 132 +++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 Documentation/devicetree/bindings/pinctrl/brcm,cygnus-pinmux.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/pinctrl/brcm,cygnus-pinmux.txt b/Documentation/devicetree/bindings/pinctrl/brcm,cygnus-pinmux.txt new file mode 100644 index 000000000000..3600d5c6c4d7 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/brcm,cygnus-pinmux.txt @@ -0,0 +1,132 @@ +Broadcom Cygnus IOMUX Controller + +The Cygnus IOMUX controller supports group based mux configuration. In +addition, certain pins can be muxed to GPIO function individually. + +Required properties: + +- compatible: + Must be "brcm,cygnus-pinmux" + +- reg: + Define the base and range of the I/O address space that contains the Cygnus +IOMUX registers + +Properties in subnodes: + +- function: + The mux function to select + +- groups: + The list of groups to select with a given function + +For more details, refer to +Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt + +For example: + + pinmux: pinmux@0x0301d0c8 { + compatible = "brcm,cygnus-pinmux"; + reg = <0x0301d0c8 0x1b0>; + + pinctrl-names = "default"; + pinctrl-0 = <&i2s0_default>; + + i2s0_default: i2s0_default { + mux { + function = "i2s0"; + groups = "i2s0_0_grp", "i2s0_1_grp"; + }; + }; + }; + +List of supported functions and groups in Cygnus: + +"i2s0": "i2s0_0_grp", "i2s0_1_grp" + +"i2s1": "i2s1_0_grp", "i2s1_1_grp" + +"i2s2": "i2s2_0_grp", "i2s2_1_grp", "i2s2_2_grp", "i2s2_3_grp", "i2s2_4_grp" + +"spdif": "spdif_grp" + +"pwm0": "pwm0_grp" + +"pwm1": "pwm1_grp" + +"pwm2": "pwm2_grp" + +"pwm3": "pwm3_grp" + +"pwm4": "pwm4_grp" + +"pwm5": "pwm5_grp" + +"key": "key0_grp", "key1_grp", "key2_grp", "key3_grp", "key4_grp", "key5_grp", +"key6_grp", "key7_grp", "key8_grp", "key9_grp", "key10_grp", "key11_grp", +"key12_grp", "key13_grp", "key14_grp", "key15_grp" + +"audio_dte": "audio_dte0_grp", "audio_dte1_grp", "audio_dte2_grp", "audio_dte3_grp" + +"smart_card0": "smart_card0_grp", "smart_card0_fcb_grp" + +"smart_card1": "smart_card1_grp", "smart_card1_fcb_grp" + +"spi0": "spi0_grp" + +"spi1": "spi1_grp" + +"spi2": "spi2_grp" + +"spi3": "spi3_grp" + +"spi4": "spi4_0_grp", "spi4_1_grp" + +"spi5": "spi5_grp" + +"sw_led0": "sw_led0_0_grp", "sw_led0_1_grp" + +"sw_led1": "sw_led1_grp" + +"sw_led2": "sw_led2_0_grp", "sw_led2_1_grp" + +"d1w": "d1w_grp" + +"lcd": "lcd_grp" + +"sram": "sram_0_grp", "sram_1_grp" + +"uart0": "uart0_grp" + +"uart1": "uart1_grp", "uart1_dte_grp" + +"uart2": "uart2_grp" + +"uart3": "uart3_grp" + +"uart4": "uart4_grp" + +"qspi": "qspi_0_grp", "qspi_1_grp" + +"nand": "nand_grp" + +"sdio0": "sdio0_grp", "sdio0_cd_grp", "sdio0_mmc_grp" + +"sdio1": "sdio1_data_0_grp", "sdio1_data_1_grp", "sdio1_cd_grp", +"sdio1_led_grp", "sdio1_mmc_grp" + +"can0": "can0_grp" + +"can1": "can1_grp" + +"cam": "cam_led_grp", "cam_0_grp", "cam_1_grp" + +"bsc1": "bsc1_grp" + +"pcie_clkreq": "pcie_clkreq_grp" + +"usb0_oc": "usb0_oc_grp" + +"usb1_oc": "usb1_oc_grp" + +"usb2_oc": "usb2_oc_grp" -- cgit v1.2.3-59-g8ed1b From ddac96118f3d2c28813ba98cda79c1e29a902e02 Mon Sep 17 00:00:00 2001 From: Hongzhou Yang Date: Wed, 21 Jan 2015 13:28:14 +0800 Subject: pinctrl: dt-bindings: Add pinctrl bindings for mt65xx/mt81xx. Add devicetree bindings for Mediatek SoC pinctrl driver. Signed-off-by: Hongzhou Yang Acked-by: Sascha Hauer Signed-off-by: Linus Walleij --- .../devicetree/bindings/pinctrl/pinctrl-mt65xx.txt | 145 +++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 Documentation/devicetree/bindings/pinctrl/pinctrl-mt65xx.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-mt65xx.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-mt65xx.txt new file mode 100644 index 000000000000..5868a0f7255d --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-mt65xx.txt @@ -0,0 +1,145 @@ +* Mediatek MT65XX Pin Controller + +The Mediatek's Pin controller is used to control SoC pins. + +Required properties: +- compatible: value should be either of the following. + (a) "mediatek,mt8135-pinctrl", compatible with mt8135 pinctrl. +- mediatek,pctl-regmap: Should be a phandle of the syscfg node. +- pins-are-numbered: Specify the subnodes are using numbered pinmux to + specify pins. +- gpio-controller : Marks the device node as a gpio controller. +- #gpio-cells: number of cells in GPIO specifier. Since the generic GPIO + binding is used, the amount of cells must be specified as 2. See the below + mentioned gpio binding representation for description of particular cells. + + Eg: <&pio 6 0> + <[phandle of the gpio controller node] + [line number within the gpio controller] + [flags]> + + Values for gpio specifier: + - Line number: is a value between 0 to 202. + - Flags: bit field of flags, as defined in . + Only the following flags are supported: + 0 - GPIO_ACTIVE_HIGH + 1 - GPIO_ACTIVE_LOW +- reg: physicall address base for EINT registers +- interrupt-controller: Marks the device node as an interrupt controller +- #interrupt-cells: Should be two. +- interrupts : The interrupt outputs from the controller. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices. + +Subnode format +A pinctrl node should contain at least one subnodes representing the +pinctrl groups available on the machine. Each subnode will list the +pins it needs, and how they should be configured, with regard to muxer +configuration, pullups, drive strength, input enable/disable and input schmitt. + + node { + pinmux = ; + GENERIC_PINCONFIG; + }; + +Required properties: +- pinmux: integer array, represents gpio pin number and mux setting. + Supported pin number and mux varies for different SoCs, and are defined + as macros in boot/dts/-pinfunc.h directly. + +Optional properties: +- GENERIC_PINCONFIG: is the generic pinconfig options to use, bias-disable, + bias-pull-down, bias-pull-up, input-enable, input-disable, output-low, output-high, + input-schmitt-enable, input-schmitt-disable and drive-strength are valid. + + Some special pins have extra pull up strength, there are R0 and R1 pull-up + resistors available, but for user, it's only need to set R1R0 as 00, 01, 10 or 11. + So when config bias-pull-up, it support arguments for those special pins. + Some macros have been defined for this usage, such as MTK_PUPD_SET_R1R0_00. + See dt-bindings/pinctrl/mt65xx.h. + + When config drive-strength, it can support some arguments, such as + MTK_DRIVE_4mA, MTK_DRIVE_6mA, etc. See dt-bindings/pinctrl/mt65xx.h. + +Examples: + +#include "mt8135-pinfunc.h" + +... +{ + syscfg_pctl_a: syscfg_pctl_a@10005000 { + compatible = "mediatek,mt8135-pctl-a-syscfg", "syscon"; + reg = <0 0x10005000 0 0x1000>; + }; + + syscfg_pctl_b: syscfg_pctl_b@1020C020 { + compatible = "mediatek,mt8135-pctl-b-syscfg", "syscon"; + reg = <0 0x1020C020 0 0x1000>; + }; + + pinctrl@01c20800 { + compatible = "mediatek,mt8135-pinctrl"; + reg = <0 0x1000B000 0 0x1000>; + mediatek,pctl-regmap = <&syscfg_pctl_a &syscfg_pctl_b>; + pins-are-numbered; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = , + , + ; + + i2c0_pins_a: i2c0@0 { + pins1 { + pinmux = , + ; + bias-disable; + }; + }; + + i2c1_pins_a: i2c1@0 { + pins { + pinmux = , + ; + bias-pull-up = <55>; + }; + }; + + i2c2_pins_a: i2c2@0 { + pins1 { + pinmux = ; + bias-pull-down; + }; + + pins2 { + pinmux = ; + bias-pull-up; + }; + }; + + i2c3_pins_a: i2c3@0 { + pins1 { + pinmux = , + ; + bias-pull-up = <55>; + }; + + pins2 { + pinmux = , + ; + output-low; + bias-pull-up = <55>; + }; + + pins3 { + pinmux = , + ; + drive-strength = <32>; + }; + }; + + ... + } +}; -- cgit v1.2.3-59-g8ed1b From 260463d4921468b9c0c018695ab09b3c2d15345b Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Sun, 8 Mar 2015 10:51:45 +0200 Subject: pinctrl: remove enable/disable callbacks from documentation Commit 03e9f0cac5d (pinctrl: clean up after enable refactoring) updated the documentation to remove mention of disable(), and rename enable() to set_mux(). One in-text mention was forgotten. Fix this. Fixes: 03e9f0cac5d ('pinctrl: clean up after enable refactoring') Signed-off-by: Baruch Siach Signed-off-by: Linus Walleij --- Documentation/pinctrl.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/pinctrl.txt b/Documentation/pinctrl.txt index 348a8af8d06c..73fe71f5555d 100644 --- a/Documentation/pinctrl.txt +++ b/Documentation/pinctrl.txt @@ -569,9 +569,8 @@ is possible to perform the requested mux setting, poke the hardware so that this happens. Pinmux drivers are required to supply a few callback functions, some are -optional. Usually the enable() and disable() functions are implemented, -writing values into some certain registers to activate a certain mux setting -for a certain pin. +optional. Usually the set_mux() function is implemented, writing values into +some certain registers to activate a certain mux setting for a certain pin. A simple driver for the above example will work by setting bits 0, 1, 2, 3 or 4 into some register named MUX to select a certain function with a certain -- cgit v1.2.3-59-g8ed1b From b18104c00089c73f2b70790765d40424a4f9b65f Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Sun, 8 Mar 2015 10:51:46 +0200 Subject: pinctrl: remove doc mention of the enable/disable API This API has changed in commit 6e5e959dde0 (pinctrl: API changes to support multiple states per device). Fixes: 6e5e959dde0 ('pinctrl: API changes to support multiple states per device') Cc: Stephen Warren Signed-off-by: Baruch Siach Signed-off-by: Linus Walleij --- Documentation/pinctrl.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/pinctrl.txt b/Documentation/pinctrl.txt index 73fe71f5555d..8d92fc1a73a3 100644 --- a/Documentation/pinctrl.txt +++ b/Documentation/pinctrl.txt @@ -1264,7 +1264,7 @@ The semantics of the pinctrl APIs are: Usually the pin control core handled the get/put pair and call out to the device drivers bookkeeping operations, like checking available functions and -the associated pins, whereas the enable/disable pass on to the pin controller +the associated pins, whereas select_state pass on to the pin controller driver which takes care of activating and/or deactivating the mux setting by quickly poking some registers. @@ -1361,8 +1361,9 @@ function, but with different named in the mapping as described under "Advanced mapping" above. So that for an SPI device, we have two states named "pos-A" and "pos-B". -This snippet first muxes the function in the pins defined by group A, enables -it, disables and releases it, and muxes it in on the pins defined by group B: +This snippet first initializes a state object for both groups (in foo_probe()), +then muxes the function in the pins defined by group A, and finally muxes it in +on the pins defined by group B: #include -- cgit v1.2.3-59-g8ed1b From c58e031d73af7373c91a97b75841dbf4114e532e Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Sun, 8 Mar 2015 12:03:05 +0200 Subject: pinctrl: staticise example code funcs/structs Make the example code consistent wrt local function and struct definitions. Signed-off-by: Baruch Siach Signed-off-by: Linus Walleij --- Documentation/pinctrl.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/pinctrl.txt b/Documentation/pinctrl.txt index 8d92fc1a73a3..5e9909c8c8a8 100644 --- a/Documentation/pinctrl.txt +++ b/Documentation/pinctrl.txt @@ -681,12 +681,12 @@ static const struct foo_pmx_func foo_functions[] = { }, }; -int foo_get_functions_count(struct pinctrl_dev *pctldev) +static int foo_get_functions_count(struct pinctrl_dev *pctldev) { return ARRAY_SIZE(foo_functions); } -const char *foo_get_fname(struct pinctrl_dev *pctldev, unsigned selector) +static const char *foo_get_fname(struct pinctrl_dev *pctldev, unsigned selector) { return foo_functions[selector].name; } @@ -700,7 +700,7 @@ static int foo_get_groups(struct pinctrl_dev *pctldev, unsigned selector, return 0; } -int foo_set_mux(struct pinctrl_dev *pctldev, unsigned selector, +static int foo_set_mux(struct pinctrl_dev *pctldev, unsigned selector, unsigned group) { u8 regbit = (1 << selector + group); @@ -709,7 +709,7 @@ int foo_set_mux(struct pinctrl_dev *pctldev, unsigned selector, return 0; } -struct pinmux_ops foo_pmxops = { +static struct pinmux_ops foo_pmxops = { .get_functions_count = foo_get_functions_count, .get_function_name = foo_get_fname, .get_function_groups = foo_get_groups, -- cgit v1.2.3-59-g8ed1b From 2dffad825f0bbba16590cfaebb1ec3672b6919d3 Mon Sep 17 00:00:00 2001 From: Ray Jui Date: Mon, 9 Mar 2015 13:44:59 -0700 Subject: pinctrl: Cygnus: define Broadcom Cygnus GPIO/PINCONF binding Document the GPIO/PINCONF device tree binding for Broadcom Cygnus SoC Signed-off-by: Ray Jui Reviewed-by: Scott Branden Signed-off-by: Linus Walleij --- .../bindings/pinctrl/brcm,cygnus-gpio.txt | 98 ++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 Documentation/devicetree/bindings/pinctrl/brcm,cygnus-gpio.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/pinctrl/brcm,cygnus-gpio.txt b/Documentation/devicetree/bindings/pinctrl/brcm,cygnus-gpio.txt new file mode 100644 index 000000000000..6540ca56be5e --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/brcm,cygnus-gpio.txt @@ -0,0 +1,98 @@ +Broadcom Cygnus GPIO/PINCONF Controller + +Required properties: + +- compatible: + Must be "brcm,cygnus-ccm-gpio", "brcm,cygnus-asiu-gpio", or + "brcm,cygnus-crmu-gpio" + +- reg: + Define the base and range of the I/O address space that contains the Cygnus +GPIO/PINCONF controller registers + +- #gpio-cells: + Must be two. The first cell is the GPIO pin number (within the +controller's pin space) and the second cell is used for the following: + bit[0]: polarity (0 for active high and 1 for active low) + +- gpio-controller: + Specifies that the node is a GPIO controller + +Optional properties: + +- interrupts: + Interrupt ID + +- interrupt-controller: + Specifies that the node is an interrupt controller + +- pinmux: + Specifies the phandle to the IOMUX device, where pins can be individually +muxed to GPIO + +Supported generic PINCONF properties in child nodes: + +- pins: + The list of pins (within the controller's own pin space) that properties +in the node apply to. Pin names are "gpio-" + +- bias-disable: + Disable pin bias + +- bias-pull-up: + Enable internal pull up resistor + +- bias-pull-down: + Enable internal pull down resistor + +- drive-strength: + Valid drive strength values include 2, 4, 6, 8, 10, 12, 14, 16 (mA) + +Example: + gpio_ccm: gpio@1800a000 { + compatible = "brcm,cygnus-ccm-gpio"; + reg = <0x1800a000 0x50>, + <0x0301d164 0x20>; + #gpio-cells = <2>; + gpio-controller; + interrupts = ; + interrupt-controller; + + touch_pins: touch_pins { + pwr: pwr { + pins = "gpio-0"; + drive-strength = <16>; + }; + + event: event { + pins = "gpio-1"; + bias-pull-up; + }; + }; + }; + + gpio_asiu: gpio@180a5000 { + compatible = "brcm,cygnus-asiu-gpio"; + reg = <0x180a5000 0x668>; + #gpio-cells = <2>; + gpio-controller; + interrupts = ; + interrupt-controller; + }; + + /* + * Touchscreen that uses the CCM GPIO 0 and 1 + */ + tsc { + ... + ... + gpio-pwr = <&gpio_ccm 0 0>; + gpio-event = <&gpio_ccm 1 0>; + }; + + /* Bluetooth that uses the ASIU GPIO 5, with polarity inverted */ + bluetooth { + ... + ... + bcm,rfkill-bank-sel = <&gpio_asiu 5 1> + } -- cgit v1.2.3-59-g8ed1b From 838d030bda9e2da5f9dcf7251f4e117c6258cb2f Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Mon, 9 Mar 2015 19:20:30 +0200 Subject: pinctrl: fix example .get_group_pins implementation signature The callback function signature has changed in commit a5818a8bd0 (pinctrl: get_group_pins() const fixes) Fixes: a5818a8bd0 ('pinctrl: get_group_pins() const fixes') Cc: Stephen Warren Signed-off-by: Baruch Siach Signed-off-by: Linus Walleij --- Documentation/pinctrl.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/pinctrl.txt b/Documentation/pinctrl.txt index 5e9909c8c8a8..a9b47163bb5d 100644 --- a/Documentation/pinctrl.txt +++ b/Documentation/pinctrl.txt @@ -163,8 +163,8 @@ static const char *foo_get_group_name(struct pinctrl_dev *pctldev, } static int foo_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector, - unsigned ** const pins, - unsigned * const num_pins) + const unsigned **pins, + unsigned *num_pins) { *pins = (unsigned *) foo_groups[selector].pins; *num_pins = foo_groups[selector].num_pins; -- cgit v1.2.3-59-g8ed1b From f5efed8090aaafda22cd9b0cf81e0cdf41e03976 Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Mon, 9 Mar 2015 21:56:39 +0200 Subject: pinctrl: dt-binding: fix typo Signed-off-by: Baruch Siach Signed-off-by: Linus Walleij --- Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt index 47d84b6ee91b..950580c92448 100644 --- a/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt +++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt @@ -38,7 +38,7 @@ property exists to define the pin configuration. Each state may also be assigned a name. When names are used, another property exists to map from those names to the integer IDs. -Each client device's own binding determines the set of states the must be +Each client device's own binding determines the set of states that must be defined in its device tree node, and whether to define the set of state IDs that must be provided, or whether to define the set of state names that must be provided. -- cgit v1.2.3-59-g8ed1b From 56b858dfad9b97aea88f9fe87b1468ddaf154c94 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Tue, 17 Mar 2015 12:40:12 +0200 Subject: ACPI: Update GPIO documentation to mention _DSD Make sure that the ACPI enumeration.txt provides latest information on how to describe and retrieve GPIOs now that we can take advantage of _DSD device properties. Signed-off-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- Documentation/acpi/enumeration.txt | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/acpi/enumeration.txt b/Documentation/acpi/enumeration.txt index 9b121a569ab4..750401f91341 100644 --- a/Documentation/acpi/enumeration.txt +++ b/Documentation/acpi/enumeration.txt @@ -254,8 +254,13 @@ GPIO support ~~~~~~~~~~~~ ACPI 5 introduced two new resources to describe GPIO connections: GpioIo and GpioInt. These resources are used be used to pass GPIO numbers used by -the device to the driver. For example: +the device to the driver. ACPI 5.1 extended this with _DSD (Device +Specific Data) which made it possible to name the GPIOs among other things. +For example: + +Device (DEV) +{ Method (_CRS, 0, NotSerialized) { Name (SBUF, ResourceTemplate() @@ -285,6 +290,18 @@ the device to the driver. For example: Return (SBUF) } + // ACPI 5.1 _DSD used for naming the GPIOs + Name (_DSD, Package () + { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () + { + Package () {"power-gpios", Package() {^DEV, 0, 0, 0 }}, + Package () {"irq-gpios", Package() {^DEV, 1, 0, 0 }}, + } + }) + ... + These GPIO numbers are controller relative and path "\\_SB.PCI0.GPI0" specifies the path to the controller. In order to use these GPIOs in Linux we need to translate them to the corresponding Linux GPIO descriptors. @@ -300,11 +317,11 @@ a code like this: struct gpio_desc *irq_desc, *power_desc; - irq_desc = gpiod_get_index(dev, NULL, 1); + irq_desc = gpiod_get(dev, "irq"); if (IS_ERR(irq_desc)) /* handle error */ - power_desc = gpiod_get_index(dev, NULL, 0); + power_desc = gpiod_get(dev, "power"); if (IS_ERR(power_desc)) /* handle error */ @@ -313,6 +330,9 @@ a code like this: There are also devm_* versions of these functions which release the descriptors once the device is released. +See Documentation/acpi/gpio-properties.txt for more information about the +_DSD binding related to GPIOs. + MFD devices ~~~~~~~~~~~ The MFD devices register their children as platform devices. For the child -- cgit v1.2.3-59-g8ed1b From 5757bfe51e53f8ae6e201310a830b207c5a64e02 Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Sun, 15 Mar 2015 08:55:15 +0200 Subject: pinctrl: dt-binding: fix generic pinmux/pinconf examples pinconf_generic_dt_node_to_map() scans only subnodes of the pinctrl-0 pahndle, not the referenced node itself. Change the example nodes to match. Signed-off-by: Baruch Siach Signed-off-by: Linus Walleij --- .../bindings/pinctrl/pinctrl-bindings.txt | 30 ++++++++++++++-------- 1 file changed, 20 insertions(+), 10 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt index 950580c92448..e9ebe5d35835 100644 --- a/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt +++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt @@ -137,12 +137,16 @@ groups - the list of groups to select with this function Example: state_0_node_a { - function = "uart0"; - groups = "u0rxtx", "u0rtscts"; + uart0 { + function = "uart0"; + groups = "u0rxtx", "u0rtscts"; + }; }; state_1_node_a { - function = "spi0"; - groups = "spi0pins"; + spi0 { + function = "spi0"; + groups = "spi0pins"; + }; }; == Generic pin configuration node content == @@ -188,16 +192,22 @@ slew-rate - set the slew rate For example: state_0_node_a { - pins = "GPIO0_AJ5", "GPIO2_AH4"; /* CTS+RXD */ - bias-pull-up; + cts_rxd { + pins = "GPIO0_AJ5", "GPIO2_AH4"; /* CTS+RXD */ + bias-pull-up; + }; }; state_1_node_a { - pins = "GPIO1_AJ3", "GPIO3_AH3"; /* RTS+TXD */ - output-high; + rts_txd { + pins = "GPIO1_AJ3", "GPIO3_AH3"; /* RTS+TXD */ + output-high; + }; }; state_2_node_a { - group = "foo-group"; - bias-pull-up; + foo { + group = "foo-group"; + bias-pull-up; + }; }; Some of the generic properties take arguments. For those that do, the -- cgit v1.2.3-59-g8ed1b From 01e3ad863fc0f15b802c8a5247e1c252bd04f429 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Wed, 11 Feb 2015 12:44:50 +0800 Subject: doc: usb: chipidea: add usb wakeup enable example Add the example for how to enable USB as system wakeup source. Signed-off-by: Peter Chen Signed-off-by: Greg Kroah-Hartman --- Documentation/usb/chipidea.txt | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'Documentation') diff --git a/Documentation/usb/chipidea.txt b/Documentation/usb/chipidea.txt index 995c8bca40e2..3f848c1f2940 100644 --- a/Documentation/usb/chipidea.txt +++ b/Documentation/usb/chipidea.txt @@ -69,3 +69,24 @@ cat /sys/kernel/debug/ci_hdrc.0/registers ---------------------- "On-The-Go and Embedded Host Supplement to the USB Revision 2.0 Specification July 27, 2012 Revision 2.0 version 1.1a" + +2. How to enable USB as system wakeup source +----------------------------------- +Below is the example for how to enable USB as system wakeup source +at imx6 platform. + +2.1 Enable core's wakeup +echo enabled > /sys/bus/platform/devices/ci_hdrc.0/power/wakeup +2.2 Enable glue layer's wakeup +echo enabled > /sys/bus/platform/devices/2184000.usb/power/wakeup +2.3 Enable PHY's wakeup (optional) +echo enabled > /sys/bus/platform/devices/20c9000.usbphy/power/wakeup +2.4 Enable roothub's wakeup +echo enabled > /sys/bus/usb/devices/usb1/power/wakeup +2.5 Enable related device's wakeup +echo enabled > /sys/bus/usb/devices/1-1/power/wakeup + +If the system has only one usb port, and you want usb wakeup at this port, you +can use below script to enable usb wakeup. +for i in $(find /sys -name wakeup | grep usb);do echo enabled > $i;done; + -- cgit v1.2.3-59-g8ed1b From b0e04f852ac1fffa85b73842e60125d68cd095df Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Wed, 11 Feb 2015 12:44:52 +0800 Subject: doc: usb: usbmisc-imx: add imx6sx compatible string Add compatible string for imx6sx-usbmisc. Signed-off-by: Peter Chen Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/usbmisc-imx.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/usb/usbmisc-imx.txt b/Documentation/devicetree/bindings/usb/usbmisc-imx.txt index c101a4b17131..3539d4e7d23e 100644 --- a/Documentation/devicetree/bindings/usb/usbmisc-imx.txt +++ b/Documentation/devicetree/bindings/usb/usbmisc-imx.txt @@ -5,6 +5,7 @@ Required properties: - compatible: Should be one of below: "fsl,imx6q-usbmisc" for imx6q "fsl,vf610-usbmisc" for Vybrid vf610 + "fsl,imx6sx-usbmisc" for imx6sx - reg: Should contain registers location and length Examples: -- cgit v1.2.3-59-g8ed1b From c2bc6e11bb945e3b10f07bf4b00525ccdc9fc440 Mon Sep 17 00:00:00 2001 From: Keyur Chudgar Date: Tue, 17 Mar 2015 11:27:11 -0700 Subject: Documentation: dtb: Add port-id field for APM X-Gene ethernet Signed-off-by: Keyur Chudgar Signed-off-by: Iyappan Subramanian Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/apm-xgene-enet.txt | 2 ++ 1 file changed, 2 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/apm-xgene-enet.txt b/Documentation/devicetree/bindings/net/apm-xgene-enet.txt index 6151999c5dca..dc7961b33076 100644 --- a/Documentation/devicetree/bindings/net/apm-xgene-enet.txt +++ b/Documentation/devicetree/bindings/net/apm-xgene-enet.txt @@ -15,6 +15,7 @@ Required properties for all the ethernet interfaces: - "ring_csr": Descriptor ring control and status register address space - "ring_cmd": Descriptor ring command register address space - interrupts: Ethernet main interrupt +- port-id: Port number (0 or 1) - clocks: Reference to the clock entry. - local-mac-address: MAC address assigned to this device - phy-connection-type: Interface type between ethernet device and PHY device @@ -49,6 +50,7 @@ Example: <0x0 0X10000000 0x0 0X200>; reg-names = "enet_csr", "ring_csr", "ring_cmd"; interrupts = <0x0 0x3c 0x4>; + port-id = <0>; clocks = <&menetclk 0>; local-mac-address = [00 01 73 00 00 01]; phy-connection-type = "rgmii"; -- cgit v1.2.3-59-g8ed1b From f0b7d43c8a28155f50adb087a563cfc97566e477 Mon Sep 17 00:00:00 2001 From: Brad Campbell Date: Tue, 17 Mar 2015 16:25:46 -0400 Subject: cc2520: Add support for CC2591 amplifier. The TI CC2521 is an RF power amplifier that is designed to interface with the CC2520. Conveniently, it directly interfaces with the CC2520 and does not require any pins to be connected to a microcontroller/processor. Adding a CC2591 increases the CC2520's range, which is useful for border router and other wall-powered applications. Using the CC2591 with the CC2520 requires configuring the CC2520 GPIOs that are connected to the CC2591 to correctly set the CC2591 into TX and RX modes. Further, TI recommends that the CC2520_TXPOWER and CC2520_AGCCTRL1 registers are set differently to maximize the CC2591's performance. These settings are covered in TI Application Note AN065. This patch adds an optional `amplified` field to the cc2520 entry in the device tree. If present, the CC2520 will be configured to operate with a CC2591. The expected pin mapping is: CC2520 GPIO0 --> CC2591 EN CC2520 GPIO5 --> CC2591 PAEN Signed-off-by: Brad Campbell Acked-by: Varka Bhadram Signed-off-by: Marcel Holtmann --- .../devicetree/bindings/net/ieee802154/cc2520.txt | 4 ++ drivers/net/ieee802154/cc2520.c | 55 ++++++++++++++++++---- include/linux/spi/cc2520.h | 1 + 3 files changed, 52 insertions(+), 8 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/ieee802154/cc2520.txt b/Documentation/devicetree/bindings/net/ieee802154/cc2520.txt index 0071883c08d8..fb6d49f184ed 100644 --- a/Documentation/devicetree/bindings/net/ieee802154/cc2520.txt +++ b/Documentation/devicetree/bindings/net/ieee802154/cc2520.txt @@ -13,11 +13,15 @@ Required properties: - cca-gpio: GPIO spec for the CCA pin - vreg-gpio: GPIO spec for the VREG pin - reset-gpio: GPIO spec for the RESET pin +Optional properties: + - amplified: include if the CC2520 is connected to a CC2591 amplifier + Example: cc2520@0 { compatible = "ti,cc2520"; reg = <0>; spi-max-frequency = <4000000>; + amplified; pinctrl-names = "default"; pinctrl-0 = <&cc2520_cape_pins>; fifo-gpio = <&gpio1 18 0>; diff --git a/drivers/net/ieee802154/cc2520.c b/drivers/net/ieee802154/cc2520.c index 233b6c6017d4..f833b8bb6663 100644 --- a/drivers/net/ieee802154/cc2520.c +++ b/drivers/net/ieee802154/cc2520.c @@ -738,6 +738,8 @@ static int cc2520_get_platform_data(struct spi_device *spi, pdata->vreg = of_get_named_gpio(np, "vreg-gpio", 0); pdata->reset = of_get_named_gpio(np, "reset-gpio", 0); + pdata->amplified = of_property_read_bool(np, "amplified"); + return 0; } @@ -746,6 +748,11 @@ static int cc2520_hw_init(struct cc2520_private *priv) u8 status = 0, state = 0xff; int ret; int timeout = 100; + struct cc2520_platform_data pdata; + + ret = cc2520_get_platform_data(priv->spi, &pdata); + if (ret) + goto err_ret; ret = cc2520_read_register(priv, CC2520_FSMSTAT1, &state); if (ret) @@ -768,11 +775,47 @@ static int cc2520_hw_init(struct cc2520_private *priv) dev_vdbg(&priv->spi->dev, "oscillator brought up\n"); - /* Registers default value: section 28.1 in Datasheet */ - ret = cc2520_write_register(priv, CC2520_TXPOWER, 0xF7); - if (ret) - goto err_ret; + /* If the CC2520 is connected to a CC2591 amplifier, we must both + * configure GPIOs on the CC2520 to correctly configure the CC2591 + * and change a couple settings of the CC2520 to work with the + * amplifier. See section 8 page 17 of TI application note AN065. + * http://www.ti.com/lit/an/swra229a/swra229a.pdf + */ + if (pdata.amplified) { + ret = cc2520_write_register(priv, CC2520_TXPOWER, 0xF9); + if (ret) + goto err_ret; + ret = cc2520_write_register(priv, CC2520_AGCCTRL1, 0x16); + if (ret) + goto err_ret; + + ret = cc2520_write_register(priv, CC2520_GPIOCTRL0, 0x46); + if (ret) + goto err_ret; + + ret = cc2520_write_register(priv, CC2520_GPIOCTRL5, 0x47); + if (ret) + goto err_ret; + + ret = cc2520_write_register(priv, CC2520_GPIOPOLARITY, 0x1e); + if (ret) + goto err_ret; + + ret = cc2520_write_register(priv, CC2520_TXCTRL, 0xc1); + if (ret) + goto err_ret; + } else { + ret = cc2520_write_register(priv, CC2520_TXPOWER, 0xF7); + if (ret) + goto err_ret; + + ret = cc2520_write_register(priv, CC2520_AGCCTRL1, 0x11); + if (ret) + goto err_ret; + } + + /* Registers default value: section 28.1 in Datasheet */ ret = cc2520_write_register(priv, CC2520_CCACTRL0, 0x1A); if (ret) goto err_ret; @@ -797,10 +840,6 @@ static int cc2520_hw_init(struct cc2520_private *priv) if (ret) goto err_ret; - ret = cc2520_write_register(priv, CC2520_AGCCTRL1, 0x11); - if (ret) - goto err_ret; - ret = cc2520_write_register(priv, CC2520_ADCTEST0, 0x10); if (ret) goto err_ret; diff --git a/include/linux/spi/cc2520.h b/include/linux/spi/cc2520.h index 85b8ee67e937..e741e8baad92 100644 --- a/include/linux/spi/cc2520.h +++ b/include/linux/spi/cc2520.h @@ -21,6 +21,7 @@ struct cc2520_platform_data { int sfd; int reset; int vreg; + bool amplified; }; #endif -- cgit v1.2.3-59-g8ed1b From d4ad0759cdb1c2d0971801f8876365dddea56695 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 11 Mar 2015 15:44:53 +0000 Subject: DT: exynos: update PMU binding Document the fact that some Exynos PMUs are capable of acting as an interrupt controller. Signed-off-by: Marc Zyngier Link: https://lkml.kernel.org/r/1426088693-15724-3-git-send-email-marc.zyngier@arm.com Signed-off-by: Jason Cooper --- Documentation/devicetree/bindings/arm/samsung/pmu.txt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/samsung/pmu.txt b/Documentation/devicetree/bindings/arm/samsung/pmu.txt index 67b211381f2b..2d6356d8daf4 100644 --- a/Documentation/devicetree/bindings/arm/samsung/pmu.txt +++ b/Documentation/devicetree/bindings/arm/samsung/pmu.txt @@ -29,10 +29,27 @@ Properties: - clocks : list of phandles and specifiers to all input clocks listed in clock-names property. +Optional properties: + +Some PMUs are capable of behaving as an interrupt controller (mostly +to wake up a suspended PMU). In which case, they can have the +following properties: + +- interrupt-controller: indicate that said PMU is an interrupt controller + +- #interrupt-cells: must be identical to the that of the parent interrupt + controller. + +- interrupt-parent: a phandle indicating which interrupt controller + this PMU signals interrupts to. + Example : pmu_system_controller: system-controller@10040000 { compatible = "samsung,exynos5250-pmu", "syscon"; reg = <0x10040000 0x5000>; + interrupt-controller; + #interrupt-cells = <3>; + interrupt-parent = <&gic>; #clock-cells = <1>; clock-names = "clkout0", "clkout1", "clkout2", "clkout3", "clkout4", "clkout8", "clkout9"; -- cgit v1.2.3-59-g8ed1b From 822b3b2ebfff8e9b3d006086c527738a7ca00cd0 Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Wed, 18 Mar 2015 14:57:33 +0200 Subject: net: Add max rate tx queue attribute This adds a tx_maxrate attribute to the tx queue sysfs entry allowing for max-rate limiting. Along with DCB-ETS and BQL this provides another knob to tune queue performance. The limit units are Mbps. By default it is disabled. To disable the rate limitation after it has been set for a queue, it should be set to zero. Signed-off-by: John Fastabend Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- Documentation/ABI/testing/sysfs-class-net-queues | 8 +++ Documentation/networking/scaling.txt | 9 ++++ include/linux/netdevice.h | 8 +++ net/core/net-sysfs.c | 67 +++++++++++++++++++----- 4 files changed, 80 insertions(+), 12 deletions(-) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-class-net-queues b/Documentation/ABI/testing/sysfs-class-net-queues index 5e9aeb91d355..0c0df91b1516 100644 --- a/Documentation/ABI/testing/sysfs-class-net-queues +++ b/Documentation/ABI/testing/sysfs-class-net-queues @@ -24,6 +24,14 @@ Description: Indicates the number of transmit timeout events seen by this network interface transmit queue. +What: /sys/class//queues/tx-/tx_maxrate +Date: March 2015 +KernelVersion: 4.1 +Contact: netdev@vger.kernel.org +Description: + A Mbps max-rate set for the queue, a value of zero means disabled, + default is disabled. + What: /sys/class//queues/tx-/xps_cpus Date: November 2010 KernelVersion: 2.6.38 diff --git a/Documentation/networking/scaling.txt b/Documentation/networking/scaling.txt index 99ca40e8e810..cbfac0949635 100644 --- a/Documentation/networking/scaling.txt +++ b/Documentation/networking/scaling.txt @@ -421,6 +421,15 @@ best CPUs to share a given queue are probably those that share the cache with the CPU that processes transmit completions for that queue (transmit interrupts). +Per TX Queue rate limitation: +============================= + +These are rate-limitation mechanisms implemented by HW, where currently +a max-rate attribute is supported, by setting a Mbps value to + +/sys/class/net//queues/tx-/tx_maxrate + +A value of zero means disabled, and this is the default. Further Information =================== diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index dd1d069758be..76c5de4978a8 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -587,6 +587,7 @@ struct netdev_queue { #ifdef CONFIG_BQL struct dql dql; #endif + unsigned long tx_maxrate; } ____cacheline_aligned_in_smp; static inline int netdev_queue_numa_node_read(const struct netdev_queue *q) @@ -1022,6 +1023,10 @@ typedef u16 (*select_queue_fallback_t)(struct net_device *dev, * be otherwise expressed by feature flags. The check is called with * the set of features that the stack has calculated and it returns * those the driver believes to be appropriate. + * int (*ndo_set_tx_maxrate)(struct net_device *dev, + * int queue_index, u32 maxrate); + * Called when a user wants to set a max-rate limitation of specific + * TX queue. */ struct net_device_ops { int (*ndo_init)(struct net_device *dev); @@ -1178,6 +1183,9 @@ struct net_device_ops { netdev_features_t (*ndo_features_check) (struct sk_buff *skb, struct net_device *dev, netdev_features_t features); + int (*ndo_set_tx_maxrate)(struct net_device *dev, + int queue_index, + u32 maxrate); }; /** diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index cf30620a88e1..7e58bd7ec232 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -951,6 +951,60 @@ static ssize_t show_trans_timeout(struct netdev_queue *queue, return sprintf(buf, "%lu", trans_timeout); } +#ifdef CONFIG_XPS +static inline unsigned int get_netdev_queue_index(struct netdev_queue *queue) +{ + struct net_device *dev = queue->dev; + int i; + + for (i = 0; i < dev->num_tx_queues; i++) + if (queue == &dev->_tx[i]) + break; + + BUG_ON(i >= dev->num_tx_queues); + + return i; +} + +static ssize_t show_tx_maxrate(struct netdev_queue *queue, + struct netdev_queue_attribute *attribute, + char *buf) +{ + return sprintf(buf, "%lu\n", queue->tx_maxrate); +} + +static ssize_t set_tx_maxrate(struct netdev_queue *queue, + struct netdev_queue_attribute *attribute, + const char *buf, size_t len) +{ + struct net_device *dev = queue->dev; + int err, index = get_netdev_queue_index(queue); + u32 rate = 0; + + err = kstrtou32(buf, 10, &rate); + if (err < 0) + return err; + + if (!rtnl_trylock()) + return restart_syscall(); + + err = -EOPNOTSUPP; + if (dev->netdev_ops->ndo_set_tx_maxrate) + err = dev->netdev_ops->ndo_set_tx_maxrate(dev, index, rate); + + rtnl_unlock(); + if (!err) { + queue->tx_maxrate = rate; + return len; + } + return err; +} + +static struct netdev_queue_attribute queue_tx_maxrate = + __ATTR(tx_maxrate, S_IRUGO | S_IWUSR, + show_tx_maxrate, set_tx_maxrate); +#endif + static struct netdev_queue_attribute queue_trans_timeout = __ATTR(tx_timeout, S_IRUGO, show_trans_timeout, NULL); @@ -1065,18 +1119,6 @@ static struct attribute_group dql_group = { #endif /* CONFIG_BQL */ #ifdef CONFIG_XPS -static unsigned int get_netdev_queue_index(struct netdev_queue *queue) -{ - struct net_device *dev = queue->dev; - unsigned int i; - - i = queue - dev->_tx; - BUG_ON(i >= dev->num_tx_queues); - - return i; -} - - static ssize_t show_xps_map(struct netdev_queue *queue, struct netdev_queue_attribute *attribute, char *buf) { @@ -1153,6 +1195,7 @@ static struct attribute *netdev_queue_default_attrs[] = { &queue_trans_timeout.attr, #ifdef CONFIG_XPS &xps_cpus_attribute.attr, + &queue_tx_maxrate.attr, #endif NULL }; -- cgit v1.2.3-59-g8ed1b From 92a2c6b26b72a65714e8433bb0ee2ad1866df5cf Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Sun, 8 Mar 2015 11:17:16 +0100 Subject: tpm/st33zp24/dts/st33zp24-spi: Add dts documentation for st33zp24 spi phy Reviewed-by: Jason Gunthorpe Signed-off-by: Christophe Ricard Signed-off-by: Peter Huewe --- .../bindings/security/tpm/st33zp24-spi.txt | 34 ++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 Documentation/devicetree/bindings/security/tpm/st33zp24-spi.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/security/tpm/st33zp24-spi.txt b/Documentation/devicetree/bindings/security/tpm/st33zp24-spi.txt new file mode 100644 index 000000000000..158b0165e01c --- /dev/null +++ b/Documentation/devicetree/bindings/security/tpm/st33zp24-spi.txt @@ -0,0 +1,34 @@ +* STMicroelectronics SAS. ST33ZP24 TPM SoC + +Required properties: +- compatible: Should be "st,st33zp24-spi". +- spi-max-frequency: Maximum SPI frequency (<= 10000000). + +Optional ST33ZP24 Properties: +- interrupt-parent: phandle for the interrupt gpio controller +- interrupts: GPIO interrupt to which the chip is connected +- lpcpd-gpios: Output GPIO pin used for ST33ZP24 power management D1/D2 state. +If set, power must be present when the platform is going into sleep/hibernate mode. + +Optional SoC Specific Properties: +- pinctrl-names: Contains only one value - "default". +- pintctrl-0: Specifies the pin control groups used for this controller. + +Example (for ARM-based BeagleBoard xM with ST33ZP24 on SPI4): + +&mcspi4 { + + status = "okay"; + + st33zp24@0 { + + compatible = "st,st33zp24-spi"; + + spi-max-frequency = <10000000>; + + interrupt-parent = <&gpio5>; + interrupts = <7 IRQ_TYPE_LEVEL_HIGH>; + + lpcpd-gpios = <&gpio5 15 GPIO_ACTIVE_HIGH>; + }; +}; -- cgit v1.2.3-59-g8ed1b From db24a9044ee191c397dcd1c6574f56d67d7c8df5 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Tue, 17 Mar 2015 20:23:15 -0600 Subject: net: add support for phys_port_name Similar to port id allow netdevices to specify port names and export the name via sysfs. Drivers can implement the netdevice operation to assist udev in having sane default names for the devices using the rule: $ cat /etc/udev/rules.d/80-net-setup-link.rules SUBSYSTEM=="net", ACTION=="add", ATTR{phys_port_name}!="", NAME="$attr{phys_port_name}" Use of phys_name versus phys_id was suggested-by Jiri Pirko. Signed-off-by: David Ahern Acked-by: Jiri Pirko Acked-by: Scott Feldman Signed-off-by: David S. Miller --- Documentation/ABI/testing/sysfs-class-net | 8 ++++++++ include/linux/netdevice.h | 4 ++++ include/uapi/linux/if_link.h | 1 + net/core/dev.c | 18 ++++++++++++++++++ net/core/net-sysfs.c | 23 +++++++++++++++++++++++ net/core/rtnetlink.c | 21 +++++++++++++++++++++ 6 files changed, 75 insertions(+) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-class-net b/Documentation/ABI/testing/sysfs-class-net index beb8ec4dabbc..5ecfd72ba684 100644 --- a/Documentation/ABI/testing/sysfs-class-net +++ b/Documentation/ABI/testing/sysfs-class-net @@ -188,6 +188,14 @@ Description: Indicates the interface unique physical port identifier within the NIC, as a string. +What: /sys/class/net//phys_port_name +Date: March 2015 +KernelVersion: 4.0 +Contact: netdev@vger.kernel.org +Description: + Indicates the interface physical port name within the NIC, + as a string. + What: /sys/class/net//speed Date: October 2009 KernelVersion: 2.6.33 diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 76c5de4978a8..ec8f9b5f6500 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1164,6 +1164,8 @@ struct net_device_ops { bool new_carrier); int (*ndo_get_phys_port_id)(struct net_device *dev, struct netdev_phys_item_id *ppid); + int (*ndo_get_phys_port_name)(struct net_device *dev, + char *name, size_t len); void (*ndo_add_vxlan_port)(struct net_device *dev, sa_family_t sa_family, __be16 port); @@ -2947,6 +2949,8 @@ int dev_set_mac_address(struct net_device *, struct sockaddr *); int dev_change_carrier(struct net_device *, bool new_carrier); int dev_get_phys_port_id(struct net_device *dev, struct netdev_phys_item_id *ppid); +int dev_get_phys_port_name(struct net_device *dev, + char *name, size_t len); struct sk_buff *validate_xmit_skb_list(struct sk_buff *skb, struct net_device *dev); struct sk_buff *dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, struct netdev_queue *txq, int *ret); diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 756436e1ce89..7158fd00a109 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -147,6 +147,7 @@ enum { IFLA_CARRIER_CHANGES, IFLA_PHYS_SWITCH_ID, IFLA_LINK_NETNSID, + IFLA_PHYS_PORT_NAME, __IFLA_MAX }; diff --git a/net/core/dev.c b/net/core/dev.c index 39fe369b46ad..a1f24151db5b 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5911,6 +5911,24 @@ int dev_get_phys_port_id(struct net_device *dev, } EXPORT_SYMBOL(dev_get_phys_port_id); +/** + * dev_get_phys_port_name - Get device physical port name + * @dev: device + * @name: port name + * + * Get device physical port name + */ +int dev_get_phys_port_name(struct net_device *dev, + char *name, size_t len) +{ + const struct net_device_ops *ops = dev->netdev_ops; + + if (!ops->ndo_get_phys_port_name) + return -EOPNOTSUPP; + return ops->ndo_get_phys_port_name(dev, name, len); +} +EXPORT_SYMBOL(dev_get_phys_port_name); + /** * dev_new_index - allocate an ifindex * @net: the applicable net namespace diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 7e58bd7ec232..cc5cf689809c 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -418,6 +418,28 @@ static ssize_t phys_port_id_show(struct device *dev, } static DEVICE_ATTR_RO(phys_port_id); +static ssize_t phys_port_name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct net_device *netdev = to_net_dev(dev); + ssize_t ret = -EINVAL; + + if (!rtnl_trylock()) + return restart_syscall(); + + if (dev_isalive(netdev)) { + char name[IFNAMSIZ]; + + ret = dev_get_phys_port_name(netdev, name, sizeof(name)); + if (!ret) + ret = sprintf(buf, "%s\n", name); + } + rtnl_unlock(); + + return ret; +} +static DEVICE_ATTR_RO(phys_port_name); + static ssize_t phys_switch_id_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -465,6 +487,7 @@ static struct attribute *net_class_attrs[] = { &dev_attr_tx_queue_len.attr, &dev_attr_gro_flush_timeout.attr, &dev_attr_phys_port_id.attr, + &dev_attr_phys_port_name.attr, &dev_attr_phys_switch_id.attr, NULL, }; diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 25b4b5d23485..6abe634c666c 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -982,6 +982,24 @@ static int rtnl_phys_port_id_fill(struct sk_buff *skb, struct net_device *dev) return 0; } +static int rtnl_phys_port_name_fill(struct sk_buff *skb, struct net_device *dev) +{ + char name[IFNAMSIZ]; + int err; + + err = dev_get_phys_port_name(dev, name, sizeof(name)); + if (err) { + if (err == -EOPNOTSUPP) + return 0; + return err; + } + + if (nla_put(skb, IFLA_PHYS_PORT_NAME, strlen(name), name)) + return -EMSGSIZE; + + return 0; +} + static int rtnl_phys_switch_id_fill(struct sk_buff *skb, struct net_device *dev) { int err; @@ -1072,6 +1090,9 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, if (rtnl_phys_port_id_fill(skb, dev)) goto nla_put_failure; + if (rtnl_phys_port_name_fill(skb, dev)) + goto nla_put_failure; + if (rtnl_phys_switch_id_fill(skb, dev)) goto nla_put_failure; -- cgit v1.2.3-59-g8ed1b From 34ebe933417e16f46bc30ea77a66e7f30d0cf0f8 Mon Sep 17 00:00:00 2001 From: Rik van Riel Date: Mon, 9 Mar 2015 12:12:10 -0400 Subject: cpuset, isolcpus: document relationship between cpusets & isolcpus Document the subtly changed relationship between cpusets and isolcpus. Turns out the old documentation did not match the code... Signed-off-by: Rik van Riel Suggested-by: Peter Zijlstra Acked-by: Zefan Li Signed-off-by: Tejun Heo --- Documentation/cgroups/cpusets.txt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/cgroups/cpusets.txt b/Documentation/cgroups/cpusets.txt index f2235a162529..fdf7dff3f607 100644 --- a/Documentation/cgroups/cpusets.txt +++ b/Documentation/cgroups/cpusets.txt @@ -392,8 +392,10 @@ Put simply, it costs less to balance between two smaller sched domains than one big one, but doing so means that overloads in one of the two domains won't be load balanced to the other one. -By default, there is one sched domain covering all CPUs, except those -marked isolated using the kernel boot time "isolcpus=" argument. +By default, there is one sched domain covering all CPUs, including those +marked isolated using the kernel boot time "isolcpus=" argument. However, +the isolated CPUs will not participate in load balancing, and will not +have tasks running on them unless explicitly assigned. This default load balancing across all CPUs is not well suited for the following two situations: @@ -465,6 +467,10 @@ such partially load balanced cpusets, as they may be artificially constrained to some subset of the CPUs allowed to them, for lack of load balancing to the other CPUs. +CPUs in "cpuset.isolcpus" were excluded from load balancing by the +isolcpus= kernel boot option, and will never be load balanced regardless +of the value of "cpuset.sched_load_balance" in any cpuset. + 1.7.1 sched_load_balance implementation details. ------------------------------------------------ -- cgit v1.2.3-59-g8ed1b From ad4a6ebeffd2767bdcdec9e1acea7ffc00d5be2d Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Wed, 25 Feb 2015 20:30:22 +0900 Subject: doc/input : Fix typos in Documentation/input This patch fix spelling typos in Documentations/input. Signed-off-by: Masanari Iida Acked-by: Randy Dunlap Signed-off-by: Jonathan Corbet --- Documentation/input/alps.txt | 4 ++-- Documentation/input/event-codes.txt | 2 +- Documentation/input/gpio-tilt.txt | 2 +- Documentation/input/iforce-protocol.txt | 2 +- Documentation/input/walkera0701.txt | 2 +- Documentation/input/yealink.txt | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) (limited to 'Documentation') diff --git a/Documentation/input/alps.txt b/Documentation/input/alps.txt index a63e5e013a8c..b9ecf9965b4c 100644 --- a/Documentation/input/alps.txt +++ b/Documentation/input/alps.txt @@ -58,7 +58,7 @@ To exit command mode, PSMOUSE_CMD_SETSTREAM (EA) is sent to the touchpad. While in command mode, register addresses can be set by first sending a specific command, either EC for v3 devices or F5 for v4 devices. Then the address is sent one nibble at a time, where each nibble is encoded as a -command with optional data. This enoding differs slightly between the v3 and +command with optional data. This encoding differs slightly between the v3 and v4 protocols. Once an address has been set, the addressed register can be read by sending @@ -131,7 +131,7 @@ ALPS Absolute Mode - Protocol Version 3 --------------------------------------- ALPS protocol version 3 has three different packet formats. The first two are -associated with touchpad events, and the third is associatd with trackstick +associated with touchpad events, and the third is associated with trackstick events. The first type is the touchpad position packet. diff --git a/Documentation/input/event-codes.txt b/Documentation/input/event-codes.txt index c587a966413e..d92eae36b43a 100644 --- a/Documentation/input/event-codes.txt +++ b/Documentation/input/event-codes.txt @@ -229,7 +229,7 @@ such device to feedback. EV_PWR: ---------- EV_PWR events are a special type of event used specifically for power -mangement. Its usage is not well defined. To be addressed later. +management. Its usage is not well defined. To be addressed later. Device properties: ================= diff --git a/Documentation/input/gpio-tilt.txt b/Documentation/input/gpio-tilt.txt index 06d60c3ff5e7..2cdfd9bcb1af 100644 --- a/Documentation/input/gpio-tilt.txt +++ b/Documentation/input/gpio-tilt.txt @@ -28,7 +28,7 @@ Example: -------- Example configuration for a single TS1003 tilt switch that rotates around -one axis in 4 steps and emitts the current tilt via two GPIOs. +one axis in 4 steps and emits the current tilt via two GPIOs. static int sg060_tilt_enable(struct device *dev) { /* code to enable the sensors */ diff --git a/Documentation/input/iforce-protocol.txt b/Documentation/input/iforce-protocol.txt index 2d5fbfd6023e..66287151c54a 100644 --- a/Documentation/input/iforce-protocol.txt +++ b/Documentation/input/iforce-protocol.txt @@ -97,7 +97,7 @@ LEN= 0e *** Attack and fade *** OP= 02 LEN= 08 -00-01 Address where to store the parameteres +00-01 Address where to store the parameters 02-03 Duration of attack (little endian encoding, in ms) 04 Level at end of attack. Signed byte. 05-06 Duration of fade. diff --git a/Documentation/input/walkera0701.txt b/Documentation/input/walkera0701.txt index 561385d38482..49e3ac60dcef 100644 --- a/Documentation/input/walkera0701.txt +++ b/Documentation/input/walkera0701.txt @@ -91,7 +91,7 @@ absolute binary value. (10 bits per channel). Next nibble is checksum for first ten nibbles. Next nibbles 12 .. 21 represents four channels (not all channels can be -directly controlled from TX). Binary representations ar the same as in first +directly controlled from TX). Binary representations are the same as in first four channels. In nibbles 22 and 23 is a special magic number. Nibble 24 is checksum for nibbles 12..23. diff --git a/Documentation/input/yealink.txt b/Documentation/input/yealink.txt index 5360e434486c..8277b76ec506 100644 --- a/Documentation/input/yealink.txt +++ b/Documentation/input/yealink.txt @@ -93,7 +93,7 @@ Format description: Format specifier '8' : Generic 7 segment digit with individual addressable segments - Reduced capability 7 segm digit, when segments are hard wired together. + Reduced capability 7 segment digit, when segments are hard wired together. '1' : 2 segments digit only able to produce a 1. 'e' : Most significant day of the month digit, able to produce at least 1 2 3. -- cgit v1.2.3-59-g8ed1b From d0724961552f2b7da89e4b822b985f3c9fd13b79 Mon Sep 17 00:00:00 2001 From: Wang Long Date: Thu, 26 Feb 2015 03:28:25 +0000 Subject: Documentation: add print bitmap description as the commit: "lib/vsprintf: implement bitmap printing through '%*pb[l]'" add an easy way to print bitmaps. so printk-formats.txt should reflect it. Signed-off-by: Wang Long Acked-by: Tejun Heo Signed-off-by: Jonathan Corbet --- Documentation/printk-formats.txt | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'Documentation') diff --git a/Documentation/printk-formats.txt b/Documentation/printk-formats.txt index 5a615c14f75d..255a061e4309 100644 --- a/Documentation/printk-formats.txt +++ b/Documentation/printk-formats.txt @@ -239,6 +239,15 @@ s64 SHOULD be printed with %lld/%llx: printk("%lld", s64_var); +bitmap and its derivatives such as cpumask and nodemask: + + %*pb 0779 + %*pbl 0,3-6,8-10 + + For printing bitmap and its derivatives such as cpumask and nodemask, + %*pb output the bitmap with field width as the number of bits and %*pbl + output the bitmap as range list with field width as the number of bits. + If is dependent on a config option for its size (e.g., sector_t, blkcnt_t) or is architecture-dependent for its size (e.g., tcflag_t), use a format specifier of its largest possible type and explicitly cast to it. -- cgit v1.2.3-59-g8ed1b From 9ddfa69fb073081882505a4f69d3f0c344d9bcaf Mon Sep 17 00:00:00 2001 From: Ebru Akagunduz Date: Thu, 26 Feb 2015 23:34:36 +0200 Subject: doc: add information about max_ptes_none max_ptes_none specifies how many extra small pages (that are not already mapped) can be allocated when collapsing a group of small pages into one large page. /sys/kernel/mm/transparent_hugepage/khugepaged/max_ptes_none A higher value leads to use additional memory for programs. A lower value leads to gain less thp performance. Value of max_ptes_none can waste cpu time very little, you can ignore it. Signed-off-by: Ebru Akagunduz Reviewed-by: Rik van Riel Signed-off-by: Jonathan Corbet --- Documentation/vm/transhuge.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'Documentation') diff --git a/Documentation/vm/transhuge.txt b/Documentation/vm/transhuge.txt index 6b31cfbe2a9a..8143b9e8373d 100644 --- a/Documentation/vm/transhuge.txt +++ b/Documentation/vm/transhuge.txt @@ -159,6 +159,17 @@ for each pass: /sys/kernel/mm/transparent_hugepage/khugepaged/full_scans +max_ptes_none specifies how many extra small pages (that are +not already mapped) can be allocated when collapsing a group +of small pages into one large page. + +/sys/kernel/mm/transparent_hugepage/khugepaged/max_ptes_none + +A higher value leads to use additional memory for programs. +A lower value leads to gain less thp performance. Value of +max_ptes_none can waste cpu time very little, you can +ignore it. + == Boot parameter == You can change the sysfs boot time defaults of Transparent Hugepage -- cgit v1.2.3-59-g8ed1b From 2f9d7389b5e243abd0c42995a703c4f7cf535af4 Mon Sep 17 00:00:00 2001 From: Valentin Rothberg Date: Fri, 27 Feb 2015 12:55:16 +0100 Subject: MSI-HOWTO.txt: remove reference on IRQF_DISABLED The IRQF_DISABLED is a NOOP and scheduled to be removed. According to Ingo Molnar in commit e58aa3d2d0cc01ad8d6f7f640a0670433f794922 (genirq: Run irq handlers with interrupts disabled), running IRQ handlers with interrupts enabled can cause stack overflows when the interrupt line of the issuing device is still active. This patch removes IRQF_DISABLED from this documentation. It was mentioned to be a solution to avoid deadlocks when a device uses multiple interrupts. As the flag is a NOOP this solution does not work anymore. Signed-off-by: Valentin Rothberg Signed-off-by: Jonathan Corbet --- Documentation/PCI/MSI-HOWTO.txt | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) (limited to 'Documentation') diff --git a/Documentation/PCI/MSI-HOWTO.txt b/Documentation/PCI/MSI-HOWTO.txt index 0d920d54536d..63def8ef546d 100644 --- a/Documentation/PCI/MSI-HOWTO.txt +++ b/Documentation/PCI/MSI-HOWTO.txt @@ -501,18 +501,9 @@ necessary to disable interrupts (Linux guarantees the same interrupt will not be re-entered). If a device uses multiple interrupts, the driver must disable interrupts while the lock is held. If the device sends a different interrupt, the driver will deadlock trying to recursively -acquire the spinlock. - -There are two solutions. The first is to take the lock with -spin_lock_irqsave() or spin_lock_irq() (see -Documentation/DocBook/kernel-locking). The second is to specify -IRQF_DISABLED to request_irq() so that the kernel runs the entire -interrupt routine with interrupts disabled. - -If your MSI interrupt routine does not hold the lock for the whole time -it is running, the first solution may be best. The second solution is -normally preferred as it avoids making two transitions from interrupt -disabled to enabled and back again. +acquire the spinlock. Such deadlocks can be avoided by using +spin_lock_irqsave() or spin_lock_irq() which disable local interrupts +and acquire the lock (see Documentation/DocBook/kernel-locking). 4.6 How to tell whether MSI/MSI-X is enabled on a device -- cgit v1.2.3-59-g8ed1b From d181b71c3ef4f9b5edaf61125715d697540eca62 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Tue, 24 Feb 2015 15:26:06 +0100 Subject: doc: printk-formats: Fix %pU description The documentation and the code disagrees; fix the former. Signed-off-by: Rasmus Villemoes Signed-off-by: Jonathan Corbet --- Documentation/printk-formats.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/printk-formats.txt b/Documentation/printk-formats.txt index 255a061e4309..87f10424bb28 100644 --- a/Documentation/printk-formats.txt +++ b/Documentation/printk-formats.txt @@ -204,7 +204,7 @@ UUID/GUID addresses: lower ('l') or upper case ('L') hex characters - and big endian order in lower ('b') or upper case ('B') hex characters. - Where no additional specifiers are used the default little endian + Where no additional specifiers are used the default big endian order with lower case hex characters will be printed. dentry names: -- cgit v1.2.3-59-g8ed1b From 8243338058b078b1c0a2892ba02f41f91e47e348 Mon Sep 17 00:00:00 2001 From: Sheng Yong Date: Mon, 2 Mar 2015 02:20:45 +0000 Subject: mem-hotplug: fix typo in Documentation/memory-hotplug.txt Fix a trivial typo in Documentation/memory-hotplug.txt. Signed-off-by: Sheng Yong Signed-off-by: Jonathan Corbet --- Documentation/memory-hotplug.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/memory-hotplug.txt b/Documentation/memory-hotplug.txt index c5a064508a3c..ce2cfcf35c27 100644 --- a/Documentation/memory-hotplug.txt +++ b/Documentation/memory-hotplug.txt @@ -149,7 +149,7 @@ For example, assume 1GiB memory block size. A device for a memory starting at (0x100000000 / 1Gib = 4) This device covers address range [0x100000000 ... 0x140000000) -Under each memory block, you can see 4 files: +Under each memory block, you can see 5 files: /sys/devices/system/memory/memoryXXX/phys_index /sys/devices/system/memory/memoryXXX/phys_device -- cgit v1.2.3-59-g8ed1b From 09207bae60370011ce80866c37ae59f1397eea6d Mon Sep 17 00:00:00 2001 From: Wang Long Date: Mon, 2 Mar 2015 07:28:40 +0000 Subject: Documentation: update the CONFIG_DEBUG_PAGEALLOC description The CONFIG_DEBUG_PAGEALLOC option now is located under "Kernel hacking" / "Memory Debugging" / "Debug page memory allocations". so we should update the description in kmemcheck.txt. Signed-off-by: Wang Long Signed-off-by: Jonathan Corbet --- Documentation/kmemcheck.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/kmemcheck.txt b/Documentation/kmemcheck.txt index a41bdebbe87b..80aae85d8da6 100644 --- a/Documentation/kmemcheck.txt +++ b/Documentation/kmemcheck.txt @@ -82,8 +82,8 @@ menu to even appear in "menuconfig". These are: o CONFIG_DEBUG_PAGEALLOC=n - This option is located under "Kernel hacking" / "Debug page memory - allocations". + This option is located under "Kernel hacking" / "Memory Debugging" + / "Debug page memory allocations". In addition, I highly recommend turning on CONFIG_DEBUG_INFO=y. This is also located under "Kernel hacking". With this, you will be able to get line number -- cgit v1.2.3-59-g8ed1b From 80b6f38be29ad12abc30148211558384196a8b1f Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 3 Mar 2015 11:07:15 +0100 Subject: Documentation: i2o: remove duplicate documentation We can remove the i2o documentation because a) the subsystem has been moved to staging with commit 2cbf7fe2d5d32a (i2o: move to staging) anyhow and b) the here removed files are present in the subsystem directory again. There, README even has an additional paragraph and the ioctl docs only differ in whitespaces. Well... Signed-off-by: Wolfram Sang Signed-off-by: Jonathan Corbet --- Documentation/i2o/README | 63 -------- Documentation/i2o/ioctl | 394 ----------------------------------------------- 2 files changed, 457 deletions(-) delete mode 100644 Documentation/i2o/README delete mode 100644 Documentation/i2o/ioctl (limited to 'Documentation') diff --git a/Documentation/i2o/README b/Documentation/i2o/README deleted file mode 100644 index ee91e2626ff0..000000000000 --- a/Documentation/i2o/README +++ /dev/null @@ -1,63 +0,0 @@ - - Linux I2O Support (c) Copyright 1999 Red Hat Software - and others. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version - 2 of the License, or (at your option) any later version. - -AUTHORS (so far) - -Alan Cox, Building Number Three Ltd. - Core code, SCSI and Block OSMs - -Steve Ralston, LSI Logic Corp. - Debugging SCSI and Block OSM - -Deepak Saxena, Intel Corp. - Various core/block extensions - /proc interface, bug fixes - Ioctl interfaces for control - Debugging LAN OSM - -Philip Rumpf - Fixed assorted dumb SMP locking bugs - -Juha Sievanen, University of Helsinki Finland - LAN OSM code - /proc interface to LAN class - Bug fixes - Core code extensions - -Auvo Häkkinen, University of Helsinki Finland - LAN OSM code - /Proc interface to LAN class - Bug fixes - Core code extensions - -Taneli Vähäkangas, University of Helsinki Finland - Fixes to i2o_config - -CREDITS - - This work was made possible by - -Red Hat Software - Funding for the Building #3 part of the project - -Symbios Logic (Now LSI) - Host adapters, hints, known to work platforms when I hit - compatibility problems - -BoxHill Corporation - Loan of initial FibreChannel disk array used for development work. - -European Commission - Funding the work done by the University of Helsinki - -SysKonnect - Loan of FDDI and Gigabit Ethernet cards - -ASUSTeK - Loan of I2O motherboard diff --git a/Documentation/i2o/ioctl b/Documentation/i2o/ioctl deleted file mode 100644 index 27c3c5493116..000000000000 --- a/Documentation/i2o/ioctl +++ /dev/null @@ -1,394 +0,0 @@ - -Linux I2O User Space Interface -rev 0.3 - 04/20/99 - -============================================================================= -Originally written by Deepak Saxena(deepak@plexity.net) -Currently maintained by Deepak Saxena(deepak@plexity.net) -============================================================================= - -I. Introduction - -The Linux I2O subsystem provides a set of ioctl() commands that can be -utilized by user space applications to communicate with IOPs and devices -on individual IOPs. This document defines the specific ioctl() commands -that are available to the user and provides examples of their uses. - -This document assumes the reader is familiar with or has access to the -I2O specification as no I2O message parameters are outlined. For information -on the specification, see http://www.i2osig.org - -This document and the I2O user space interface are currently maintained -by Deepak Saxena. Please send all comments, errata, and bug fixes to -deepak@csociety.purdue.edu - -II. IOP Access - -Access to the I2O subsystem is provided through the device file named -/dev/i2o/ctl. This file is a character file with major number 10 and minor -number 166. It can be created through the following command: - - mknod /dev/i2o/ctl c 10 166 - -III. Determining the IOP Count - - SYNOPSIS - - ioctl(fd, I2OGETIOPS, int *count); - - u8 count[MAX_I2O_CONTROLLERS]; - - DESCRIPTION - - This function returns the system's active IOP table. count should - point to a buffer containing MAX_I2O_CONTROLLERS entries. Upon - returning, each entry will contain a non-zero value if the given - IOP unit is active, and NULL if it is inactive or non-existent. - - RETURN VALUE. - - Returns 0 if no errors occur, and -1 otherwise. If an error occurs, - errno is set appropriately: - - EFAULT Invalid user space pointer was passed - -IV. Getting Hardware Resource Table - - SYNOPSIS - - ioctl(fd, I2OHRTGET, struct i2o_cmd_hrt *hrt); - - struct i2o_cmd_hrtlct - { - u32 iop; /* IOP unit number */ - void *resbuf; /* Buffer for result */ - u32 *reslen; /* Buffer length in bytes */ - }; - - DESCRIPTION - - This function returns the Hardware Resource Table of the IOP specified - by hrt->iop in the buffer pointed to by hrt->resbuf. The actual size of - the data is written into *(hrt->reslen). - - RETURNS - - This function returns 0 if no errors occur. If an error occurs, -1 - is returned and errno is set appropriately: - - EFAULT Invalid user space pointer was passed - ENXIO Invalid IOP number - ENOBUFS Buffer not large enough. If this occurs, the required - buffer length is written into *(hrt->reslen) - -V. Getting Logical Configuration Table - - SYNOPSIS - - ioctl(fd, I2OLCTGET, struct i2o_cmd_lct *lct); - - struct i2o_cmd_hrtlct - { - u32 iop; /* IOP unit number */ - void *resbuf; /* Buffer for result */ - u32 *reslen; /* Buffer length in bytes */ - }; - - DESCRIPTION - - This function returns the Logical Configuration Table of the IOP specified - by lct->iop in the buffer pointed to by lct->resbuf. The actual size of - the data is written into *(lct->reslen). - - RETURNS - - This function returns 0 if no errors occur. If an error occurs, -1 - is returned and errno is set appropriately: - - EFAULT Invalid user space pointer was passed - ENXIO Invalid IOP number - ENOBUFS Buffer not large enough. If this occurs, the required - buffer length is written into *(lct->reslen) - -VI. Setting Parameters - - SYNOPSIS - - ioctl(fd, I2OPARMSET, struct i2o_parm_setget *ops); - - struct i2o_cmd_psetget - { - u32 iop; /* IOP unit number */ - u32 tid; /* Target device TID */ - void *opbuf; /* Operation List buffer */ - u32 oplen; /* Operation List buffer length in bytes */ - void *resbuf; /* Result List buffer */ - u32 *reslen; /* Result List buffer length in bytes */ - }; - - DESCRIPTION - - This function posts a UtilParamsSet message to the device identified - by ops->iop and ops->tid. The operation list for the message is - sent through the ops->opbuf buffer, and the result list is written - into the buffer pointed to by ops->resbuf. The number of bytes - written is placed into *(ops->reslen). - - RETURNS - - The return value is the size in bytes of the data written into - ops->resbuf if no errors occur. If an error occurs, -1 is returned - and errno is set appropriately: - - EFAULT Invalid user space pointer was passed - ENXIO Invalid IOP number - ENOBUFS Buffer not large enough. If this occurs, the required - buffer length is written into *(ops->reslen) - ETIMEDOUT Timeout waiting for reply message - ENOMEM Kernel memory allocation error - - A return value of 0 does not mean that the value was actually - changed properly on the IOP. The user should check the result - list to determine the specific status of the transaction. - -VII. Getting Parameters - - SYNOPSIS - - ioctl(fd, I2OPARMGET, struct i2o_parm_setget *ops); - - struct i2o_parm_setget - { - u32 iop; /* IOP unit number */ - u32 tid; /* Target device TID */ - void *opbuf; /* Operation List buffer */ - u32 oplen; /* Operation List buffer length in bytes */ - void *resbuf; /* Result List buffer */ - u32 *reslen; /* Result List buffer length in bytes */ - }; - - DESCRIPTION - - This function posts a UtilParamsGet message to the device identified - by ops->iop and ops->tid. The operation list for the message is - sent through the ops->opbuf buffer, and the result list is written - into the buffer pointed to by ops->resbuf. The actual size of data - written is placed into *(ops->reslen). - - RETURNS - - EFAULT Invalid user space pointer was passed - ENXIO Invalid IOP number - ENOBUFS Buffer not large enough. If this occurs, the required - buffer length is written into *(ops->reslen) - ETIMEDOUT Timeout waiting for reply message - ENOMEM Kernel memory allocation error - - A return value of 0 does not mean that the value was actually - properly retrieved. The user should check the result list - to determine the specific status of the transaction. - -VIII. Downloading Software - - SYNOPSIS - - ioctl(fd, I2OSWDL, struct i2o_sw_xfer *sw); - - struct i2o_sw_xfer - { - u32 iop; /* IOP unit number */ - u8 flags; /* DownloadFlags field */ - u8 sw_type; /* Software type */ - u32 sw_id; /* Software ID */ - void *buf; /* Pointer to software buffer */ - u32 *swlen; /* Length of software buffer */ - u32 *maxfrag; /* Number of fragments */ - u32 *curfrag; /* Current fragment number */ - }; - - DESCRIPTION - - This function downloads a software fragment pointed by sw->buf - to the iop identified by sw->iop. The DownloadFlags, SwID, SwType - and SwSize fields of the ExecSwDownload message are filled in with - the values of sw->flags, sw->sw_id, sw->sw_type and *(sw->swlen). - - The fragments _must_ be sent in order and be 8K in size. The last - fragment _may_ be shorter, however. The kernel will compute its - size based on information in the sw->swlen field. - - Please note that SW transfers can take a long time. - - RETURNS - - This function returns 0 no errors occur. If an error occurs, -1 - is returned and errno is set appropriately: - - EFAULT Invalid user space pointer was passed - ENXIO Invalid IOP number - ETIMEDOUT Timeout waiting for reply message - ENOMEM Kernel memory allocation error - -IX. Uploading Software - - SYNOPSIS - - ioctl(fd, I2OSWUL, struct i2o_sw_xfer *sw); - - struct i2o_sw_xfer - { - u32 iop; /* IOP unit number */ - u8 flags; /* UploadFlags */ - u8 sw_type; /* Software type */ - u32 sw_id; /* Software ID */ - void *buf; /* Pointer to software buffer */ - u32 *swlen; /* Length of software buffer */ - u32 *maxfrag; /* Number of fragments */ - u32 *curfrag; /* Current fragment number */ - }; - - DESCRIPTION - - This function uploads a software fragment from the IOP identified - by sw->iop, sw->sw_type, sw->sw_id and optionally sw->swlen fields. - The UploadFlags, SwID, SwType and SwSize fields of the ExecSwUpload - message are filled in with the values of sw->flags, sw->sw_id, - sw->sw_type and *(sw->swlen). - - The fragments _must_ be requested in order and be 8K in size. The - user is responsible for allocating memory pointed by sw->buf. The - last fragment _may_ be shorter. - - Please note that SW transfers can take a long time. - - RETURNS - - This function returns 0 if no errors occur. If an error occurs, -1 - is returned and errno is set appropriately: - - EFAULT Invalid user space pointer was passed - ENXIO Invalid IOP number - ETIMEDOUT Timeout waiting for reply message - ENOMEM Kernel memory allocation error - -X. Removing Software - - SYNOPSIS - - ioctl(fd, I2OSWDEL, struct i2o_sw_xfer *sw); - - struct i2o_sw_xfer - { - u32 iop; /* IOP unit number */ - u8 flags; /* RemoveFlags */ - u8 sw_type; /* Software type */ - u32 sw_id; /* Software ID */ - void *buf; /* Unused */ - u32 *swlen; /* Length of the software data */ - u32 *maxfrag; /* Unused */ - u32 *curfrag; /* Unused */ - }; - - DESCRIPTION - - This function removes software from the IOP identified by sw->iop. - The RemoveFlags, SwID, SwType and SwSize fields of the ExecSwRemove message - are filled in with the values of sw->flags, sw->sw_id, sw->sw_type and - *(sw->swlen). Give zero in *(sw->len) if the value is unknown. IOP uses - *(sw->swlen) value to verify correct identication of the module to remove. - The actual size of the module is written into *(sw->swlen). - - RETURNS - - This function returns 0 if no errors occur. If an error occurs, -1 - is returned and errno is set appropriately: - - EFAULT Invalid user space pointer was passed - ENXIO Invalid IOP number - ETIMEDOUT Timeout waiting for reply message - ENOMEM Kernel memory allocation error - -X. Validating Configuration - - SYNOPSIS - - ioctl(fd, I2OVALIDATE, int *iop); - u32 iop; - - DESCRIPTION - - This function posts an ExecConfigValidate message to the controller - identified by iop. This message indicates that the current - configuration is accepted. The iop changes the status of suspect drivers - to valid and may delete old drivers from its store. - - RETURNS - - This function returns 0 if no erro occur. If an error occurs, -1 is - returned and errno is set appropriately: - - ETIMEDOUT Timeout waiting for reply message - ENXIO Invalid IOP number - -XI. Configuration Dialog - - SYNOPSIS - - ioctl(fd, I2OHTML, struct i2o_html *htquery); - struct i2o_html - { - u32 iop; /* IOP unit number */ - u32 tid; /* Target device ID */ - u32 page; /* HTML page */ - void *resbuf; /* Buffer for reply HTML page */ - u32 *reslen; /* Length in bytes of reply buffer */ - void *qbuf; /* Pointer to HTTP query string */ - u32 qlen; /* Length in bytes of query string buffer */ - }; - - DESCRIPTION - - This function posts an UtilConfigDialog message to the device identified - by htquery->iop and htquery->tid. The requested HTML page number is - provided by the htquery->page field, and the resultant data is stored - in the buffer pointed to by htquery->resbuf. If there is an HTTP query - string that is to be sent to the device, it should be sent in the buffer - pointed to by htquery->qbuf. If there is no query string, this field - should be set to NULL. The actual size of the reply received is written - into *(htquery->reslen). - - RETURNS - - This function returns 0 if no error occur. If an error occurs, -1 - is returned and errno is set appropriately: - - EFAULT Invalid user space pointer was passed - ENXIO Invalid IOP number - ENOBUFS Buffer not large enough. If this occurs, the required - buffer length is written into *(ops->reslen) - ETIMEDOUT Timeout waiting for reply message - ENOMEM Kernel memory allocation error - -XII. Events - - In the process of determining this. Current idea is to have use - the select() interface to allow user apps to periodically poll - the /dev/i2o/ctl device for events. When select() notifies the user - that an event is available, the user would call read() to retrieve - a list of all the events that are pending for the specific device. - -============================================================================= -Revision History -============================================================================= - -Rev 0.1 - 04/01/99 -- Initial revision - -Rev 0.2 - 04/06/99 -- Changed return values to match UNIX ioctl() standard. Only return values - are 0 and -1. All errors are reported through errno. -- Added summary of proposed possible event interfaces - -Rev 0.3 - 04/20/99 -- Changed all ioctls() to use pointers to user data instead of actual data -- Updated error values to match the code -- cgit v1.2.3-59-g8ed1b From 080684c88ac194dffee4228bb073af61b67ebfaf Mon Sep 17 00:00:00 2001 From: Li Bin Date: Thu, 5 Mar 2015 09:48:31 +0800 Subject: kprobes: Update Documentation/kprobes.txt The patch 125e564("Move Kconfig.instrumentation to arch/Kconfig and init/Kconfig") had removed the "Instrumentation Support" menu, and the configurations under this had be moved to "General setup". Update Documentation/kprobes.txt to reflect this change. Signed-off-by: Li Bin Acked-by: Masami Hiramatsu Signed-off-by: Jonathan Corbet --- Documentation/kprobes.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/kprobes.txt b/Documentation/kprobes.txt index 1488b6525eb6..1f9b3e2b98ae 100644 --- a/Documentation/kprobes.txt +++ b/Documentation/kprobes.txt @@ -305,8 +305,8 @@ architectures: 3. Configuring Kprobes When configuring the kernel using make menuconfig/xconfig/oldconfig, -ensure that CONFIG_KPROBES is set to "y". Under "Instrumentation -Support", look for "Kprobes". +ensure that CONFIG_KPROBES is set to "y". Under "General setup", look +for "Kprobes". So that you can load and unload Kprobes-based instrumentation modules, make sure "Loadable module support" (CONFIG_MODULES) and "Module -- cgit v1.2.3-59-g8ed1b From d50ca07863eb42ab5acb11ae6b2241c3db875061 Mon Sep 17 00:00:00 2001 From: Giedrius Statkevičius Date: Mon, 9 Mar 2015 03:53:45 +0200 Subject: Documentation/email-clients.txt: Fix one grammar mistake, add extra info about TB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix one grammar mistake (Allows->Allow) and add extra information about the external editor add-on of Thunderbird: the developer must make sure that their editor doesn't fork (IOW it mustn't return before closing) thus they should be careful how they configure the addon. Furthermore, add a tip how to do it with gvim. Signed-off-by: Giedrius Statkevičius [jc: some minor wording/formatting tweaks] Signed-off-by: Jonathan Corbet --- Documentation/email-clients.txt | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/email-clients.txt b/Documentation/email-clients.txt index eede6088f978..c7d49b885559 100644 --- a/Documentation/email-clients.txt +++ b/Documentation/email-clients.txt @@ -211,7 +211,7 @@ Thunderbird (GUI) Thunderbird is an Outlook clone that likes to mangle text, but there are ways to coerce it into behaving. -- Allows use of an external editor: +- Allow use of an external editor: The easiest thing to do with Thunderbird and patches is to use an "external editor" extension and then just use your favorite $EDITOR for reading/merging patches into the body text. To do this, download @@ -219,6 +219,15 @@ to coerce it into behaving. View->Toolbars->Customize... and finally just click on it when in the Compose dialog. + Please note that "external editor" requires that your editor must not + fork, or in other words, the editor must not return before closing. + You may have to pass additional flags or change the settings of your + editor. Most notably if you are using gvim then you must pass the -f + option to gvim by putting "/usr/bin/gvim -f" (if the binary is in + /usr/bin) to the text editor field in "external editor" settings. If you + are using some other editor then please read its manual to find out how + to do this. + To beat some sense out of the internal editor, do this: - Edit your Thunderbird config settings so that it won't use format=flowed. -- cgit v1.2.3-59-g8ed1b From 8962786ce3d91003bdd3f7c6bda2ee3641d66770 Mon Sep 17 00:00:00 2001 From: "Leonid V. Fedorenchik" Date: Fri, 13 Mar 2015 23:53:22 +0300 Subject: Documentation: Remove mentioning of block barriers Remove mentioning of block barriers since they were removed. Reviewed-by: Christoph Hellwig Signed-off-by: Leonid V. Fedorenchik Signed-off-by: Jonathan Corbet --- Documentation/block/biodoc.txt | 36 +++++++++--------------------------- 1 file changed, 9 insertions(+), 27 deletions(-) (limited to 'Documentation') diff --git a/Documentation/block/biodoc.txt b/Documentation/block/biodoc.txt index 5aabc08de811..fd12c0d835fd 100644 --- a/Documentation/block/biodoc.txt +++ b/Documentation/block/biodoc.txt @@ -48,8 +48,7 @@ Description of Contents: - Highmem I/O support - I/O scheduler modularization 1.2 Tuning based on high level requirements/capabilities - 1.2.1 I/O Barriers - 1.2.2 Request Priority/Latency + 1.2.1 Request Priority/Latency 1.3 Direct access/bypass to lower layers for diagnostics and special device operations 1.3.1 Pre-built commands @@ -255,29 +254,12 @@ some control over i/o ordering. What kind of support exists at the generic block layer for this ? The flags and rw fields in the bio structure can be used for some tuning -from above e.g indicating that an i/o is just a readahead request, or for -marking barrier requests (discussed next), or priority settings (currently -unused). As far as user applications are concerned they would need an -additional mechanism either via open flags or ioctls, or some other upper -level mechanism to communicate such settings to block. - -1.2.1 I/O Barriers - -There is a way to enforce strict ordering for i/os through barriers. -All requests before a barrier point must be serviced before the barrier -request and any other requests arriving after the barrier will not be -serviced until after the barrier has completed. This is useful for higher -level control on write ordering, e.g flushing a log of committed updates -to disk before the corresponding updates themselves. - -A flag in the bio structure, BIO_BARRIER is used to identify a barrier i/o. -The generic i/o scheduler would make sure that it places the barrier request and -all other requests coming after it after all the previous requests in the -queue. Barriers may be implemented in different ways depending on the -driver. For more details regarding I/O barriers, please read barrier.txt -in this directory. - -1.2.2 Request Priority/Latency +from above e.g indicating that an i/o is just a readahead request, or priority +settings (currently unused). As far as user applications are concerned they +would need an additional mechanism either via open flags or ioctls, or some +other upper level mechanism to communicate such settings to block. + +1.2.1 Request Priority/Latency Todo/Under discussion: Arjan's proposed request priority scheme allows higher levels some broad @@ -906,8 +888,8 @@ queue and specific I/O schedulers. Unless stated otherwise, elevator is used to refer to both parts and I/O scheduler to specific I/O schedulers. Block layer implements generic dispatch queue in block/*.c. -The generic dispatch queue is responsible for properly ordering barrier -requests, requeueing, handling non-fs requests and all other subtleties. +The generic dispatch queue is responsible for requeueing, handling non-fs +requests and all other subtleties. Specific I/O schedulers are responsible for ordering normal filesystem requests. They can also choose to delay certain requests to improve -- cgit v1.2.3-59-g8ed1b From 9ceae1da5027818b4dfd95e4a43fb52552c5fffb Mon Sep 17 00:00:00 2001 From: Liviu Dudau Date: Mon, 16 Mar 2015 18:24:46 +0000 Subject: Documentation: drm: Use '->' when describing access through pointers. The documentation is trying to describe accessing a field through a pointer, but it is using '-<' instead of '->'. Fix that. Signed-off-by: Liviu Dudau Signed-off-by: Jonathan Corbet --- Documentation/DocBook/drm.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 03f1985a4bd1..0cad3ce957ff 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -1293,7 +1293,7 @@ int max_width, max_height; If a page flip can be successfully scheduled the driver must set the - drm_crtc-<fb field to the new framebuffer pointed to + drm_crtc->fb field to the new framebuffer pointed to by fb. This is important so that the reference counting on framebuffers stays balanced. -- cgit v1.2.3-59-g8ed1b From 654d2e7cd18b8acc4e2accdcc0c1eadb8d786722 Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Thu, 19 Mar 2015 00:29:30 +0900 Subject: doc:pci: Fix typo in Documentation/PCI This patch fix spelling typo in Documentation/PCI. Signed-off-by: Masanari Iida Signed-off-by: Jonathan Corbet --- Documentation/PCI/MSI-HOWTO.txt | 6 +++--- Documentation/PCI/pci-error-recovery.txt | 2 +- Documentation/PCI/pcieaer-howto.txt | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/PCI/MSI-HOWTO.txt b/Documentation/PCI/MSI-HOWTO.txt index 63def8ef546d..1179850f453c 100644 --- a/Documentation/PCI/MSI-HOWTO.txt +++ b/Documentation/PCI/MSI-HOWTO.txt @@ -353,7 +353,7 @@ retry: rc = pci_enable_msix_range(adapter->pdev, adapter->msix_entries, maxvec, maxvec); /* - * -ENOSPC is the only error code allowed to be analized + * -ENOSPC is the only error code allowed to be analyzed */ if (rc == -ENOSPC) { if (maxvec == 1) @@ -370,7 +370,7 @@ retry: return rc; } -Note how pci_enable_msix_range() return value is analized for a fallback - +Note how pci_enable_msix_range() return value is analyzed for a fallback - any error code other than -ENOSPC indicates a fatal error and should not be retried. @@ -486,7 +486,7 @@ during development. If your device supports both MSI-X and MSI capabilities, you should use the MSI-X facilities in preference to the MSI facilities. As mentioned above, MSI-X supports any number of interrupts between 1 and 2048. -In constrast, MSI is restricted to a maximum of 32 interrupts (and +In contrast, MSI is restricted to a maximum of 32 interrupts (and must be a power of two). In addition, the MSI interrupt vectors must be allocated consecutively, so the system might not be able to allocate as many vectors for MSI as it could for MSI-X. On some platforms, MSI diff --git a/Documentation/PCI/pci-error-recovery.txt b/Documentation/PCI/pci-error-recovery.txt index 898ded24510d..ac26869c7db4 100644 --- a/Documentation/PCI/pci-error-recovery.txt +++ b/Documentation/PCI/pci-error-recovery.txt @@ -256,7 +256,7 @@ STEP 4: Slot Reset ------------------ In response to a return value of PCI_ERS_RESULT_NEED_RESET, the -the platform will peform a slot reset on the requesting PCI device(s). +the platform will perform a slot reset on the requesting PCI device(s). The actual steps taken by a platform to perform a slot reset will be platform-dependent. Upon completion of slot reset, the platform will call the device slot_reset() callback. diff --git a/Documentation/PCI/pcieaer-howto.txt b/Documentation/PCI/pcieaer-howto.txt index 26d3d945c3c2..b4987c0bcb20 100644 --- a/Documentation/PCI/pcieaer-howto.txt +++ b/Documentation/PCI/pcieaer-howto.txt @@ -66,8 +66,8 @@ hardware (mostly chipsets) has root ports that cannot obtain the reporting source ID. nosourceid=n by default. 2.3 AER error output -When a PCI-E AER error is captured, an error message will be outputed to -console. If it's a correctable error, it is outputed as a warning. +When a PCI-E AER error is captured, an error message will be outputted to +console. If it's a correctable error, it is outputted as a warning. Otherwise, it is printed as an error. So users could choose different log level to filter out correctable error messages. -- cgit v1.2.3-59-g8ed1b From 967b1307b69b8ada8b331e01046ad1ef83742e99 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 20 Mar 2015 18:21:03 +0100 Subject: ALSA: hda - Rename power_mgmt flag with power_save_node David suggested that the name "power_mgmt" is too ambiguous. Rename the flag with a bit clearer one "power_save_node". Also, add the corresponding description to HD-Audio.txt, too. Reported-by: David Henningsson Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/HD-Audio.txt | 6 +++++- sound/pci/hda/hda_codec.h | 2 +- sound/pci/hda/hda_generic.c | 30 +++++++++++++++--------------- sound/pci/hda/patch_sigmatel.c | 8 ++++---- sound/pci/hda/patch_via.c | 12 ++++++------ 5 files changed, 31 insertions(+), 27 deletions(-) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt index 42a0a39b77e6..e7193aac669c 100644 --- a/Documentation/sound/alsa/HD-Audio.txt +++ b/Documentation/sound/alsa/HD-Audio.txt @@ -466,7 +466,11 @@ The generic parser supports the following hints: - add_jack_modes (bool): add "xxx Jack Mode" enum controls to each I/O jack for allowing to change the headphone amp and mic bias VREF capabilities -- power_down_unused (bool): power down the unused widgets +- power_save_node (bool): advanced power management for each widget, + controlling the power sate (D0/D3) of each widget node depending on + the actual pin and stream states +- power_down_unused (bool): power down the unused widgets, a subset of + power_save_node, and will be dropped in future - add_hp_mic (bool): add the headphone to capture source if possible - hp_mic_detect (bool): enable/disable the hp/mic shared input for a single built-in mic case; default true diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 148e84ce61cf..ccf355d4a8fa 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -371,7 +371,7 @@ struct hda_codec { unsigned int cached_write:1; /* write only to caches */ unsigned int dp_mst:1; /* support DP1.2 Multi-stream transport */ unsigned int dump_coef:1; /* dump processing coefs in codec proc file */ - unsigned int power_mgmt:1; /* advanced PM for each widget */ + unsigned int power_save_node:1; /* advanced PM for each widget */ #ifdef CONFIG_PM unsigned int d3_stop_clk:1; /* support D3 operation without BCLK */ atomic_t in_pm; /* suspend/resume being performed */ diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 1cafcbb9d391..0ef2459cd05f 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -140,9 +140,9 @@ static void parse_user_hints(struct hda_codec *codec) val = snd_hda_get_bool_hint(codec, "single_adc_amp"); if (val >= 0) codec->single_adc_amp = !!val; - val = snd_hda_get_bool_hint(codec, "power_mgmt"); + val = snd_hda_get_bool_hint(codec, "power_save_node"); if (val >= 0) - codec->power_mgmt = !!val; + codec->power_save_node = !!val; val = snd_hda_get_bool_hint(codec, "auto_mute"); if (val >= 0) @@ -661,7 +661,7 @@ static bool is_active_nid(struct hda_codec *codec, hda_nid_t nid, struct nid_path *path = snd_array_elem(&spec->paths, n); if (!path->active) continue; - if (codec->power_mgmt) { + if (codec->power_save_node) { if (!path->stream_enabled) continue; /* ignore unplugged paths except for DAC/ADC */ @@ -879,8 +879,8 @@ void snd_hda_activate_path(struct hda_codec *codec, struct nid_path *path, path->active = false; /* make sure the widget is powered up */ - if (enable && (spec->power_down_unused || codec->power_mgmt)) - path_power_update(codec, path, codec->power_mgmt); + if (enable && (spec->power_down_unused || codec->power_save_node)) + path_power_update(codec, path, codec->power_save_node); for (i = path->depth - 1; i >= 0; i--) { hda_nid_t nid = path->path[i]; @@ -905,7 +905,7 @@ static void path_power_down_sync(struct hda_codec *codec, struct nid_path *path) { struct hda_gen_spec *spec = codec->spec; - if (!(spec->power_down_unused || codec->power_mgmt) || path->active) + if (!(spec->power_down_unused || codec->power_save_node) || path->active) return; sync_power_state_change(codec, path_power_update(codec, path, true)); } @@ -3981,7 +3981,7 @@ static hda_nid_t set_pin_power_jack(struct hda_codec *codec, hda_nid_t pin, { bool on; - if (!codec->power_mgmt) + if (!codec->power_save_node) return 0; on = snd_hda_jack_detect_state(codec, pin) != HDA_JACK_NOT_PRESENT; @@ -4038,7 +4038,7 @@ static void add_all_pin_power_ctls(struct hda_codec *codec, bool on) struct auto_pin_cfg *cfg = &spec->autocfg; int i; - if (!codec->power_mgmt) + if (!codec->power_save_node) return; add_pin_power_ctls(codec, cfg->line_outs, cfg->line_out_pins, on); if (cfg->line_out_type != AUTO_PIN_HP_OUT) @@ -4067,7 +4067,7 @@ static void sync_all_pin_power_ctls(struct hda_codec *codec) struct auto_pin_cfg *cfg = &spec->autocfg; int i; - if (!codec->power_mgmt) + if (!codec->power_save_node) return; sync_pin_power_ctls(codec, cfg->line_outs, cfg->line_out_pins); if (cfg->line_out_type != AUTO_PIN_HP_OUT) @@ -4111,7 +4111,7 @@ static int add_fake_beep_paths(struct hda_codec *codec) hda_nid_t nid = spec->beep_nid; int err; - if (!codec->power_mgmt || !nid) + if (!codec->power_save_node || !nid) return 0; err = add_fake_paths(codec, nid, cfg->line_outs, cfg->line_out_pins); if (err < 0) @@ -4233,7 +4233,7 @@ static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins, } set_pin_eapd(codec, nid, !mute); - if (codec->power_mgmt) { + if (codec->power_save_node) { bool on = !mute; if (on) on = snd_hda_jack_detect_state(codec, nid) @@ -4741,11 +4741,11 @@ static void mute_all_mixer_nid(struct hda_codec *codec, hda_nid_t mix) * @nid: audio widget * @on: power on/off flag * - * Set this in patch_ops.stream_pm. Only valid with power_mgmt flag. + * Set this in patch_ops.stream_pm. Only valid with power_save_node flag. */ void snd_hda_gen_stream_pm(struct hda_codec *codec, hda_nid_t nid, bool on) { - if (codec->power_mgmt) + if (codec->power_save_node) set_path_power(codec, nid, -1, on); } EXPORT_SYMBOL_GPL(snd_hda_gen_stream_pm); @@ -4916,14 +4916,14 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec, dig_only: parse_digital(codec); - if (spec->power_down_unused || codec->power_mgmt) + if (spec->power_down_unused || codec->power_save_node) codec->power_filter = snd_hda_gen_path_power_filter; if (!spec->no_analog && spec->beep_nid) { err = snd_hda_attach_beep_device(codec, spec->beep_nid); if (err < 0) return err; - if (codec->beep && codec->power_mgmt) { + if (codec->beep && codec->power_save_node) { err = add_fake_beep_paths(codec); if (err < 0) return err; diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 7e531d5cde51..5b7c173adcb8 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -4494,7 +4494,7 @@ static int patch_stac92hd73xx(struct hda_codec *codec) return err; spec = codec->spec; - codec->power_mgmt = 1; + codec->power_save_node = 1; spec->linear_tone_beep = 0; spec->gen.mixer_nid = 0x1d; spec->have_spdif_mux = 1; @@ -4600,7 +4600,7 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) codec->epss = 0; /* longer delay needed for D3 */ spec = codec->spec; - codec->power_mgmt = 1; + codec->power_save_node = 1; spec->linear_tone_beep = 0; spec->gen.own_eapd_ctl = 1; spec->gen.power_down_unused = 1; @@ -4650,7 +4650,7 @@ static int patch_stac92hd95(struct hda_codec *codec) codec->epss = 0; /* longer delay needed for D3 */ spec = codec->spec; - codec->power_mgmt = 1; + codec->power_save_node = 1; spec->linear_tone_beep = 0; spec->gen.own_eapd_ctl = 1; spec->gen.power_down_unused = 1; @@ -4692,7 +4692,7 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) return err; spec = codec->spec; - codec->power_mgmt = 1; + codec->power_save_node = 1; spec->linear_tone_beep = 0; spec->gen.own_eapd_ctl = 1; spec->gen.power_down_unused = 1; diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index d5d1dca4f11b..485663bb9101 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -133,7 +133,7 @@ static struct via_spec *via_new_spec(struct hda_codec *codec) spec->gen.keep_eapd_on = 1; spec->gen.pcm_playback_hook = via_playback_pcm_hook; spec->gen.add_stereo_mix_input = HDA_HINT_STEREO_MIX_AUTO; - codec->power_mgmt = 1; + codec->power_save_node = 1; spec->gen.power_down_unused = 1; return spec; } @@ -236,7 +236,7 @@ static int via_pin_power_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - ucontrol->value.enumerated.item[0] = codec->power_mgmt; + ucontrol->value.enumerated.item[0] = codec->power_save_node; return 0; } @@ -247,9 +247,9 @@ static int via_pin_power_ctl_put(struct snd_kcontrol *kcontrol, struct via_spec *spec = codec->spec; bool val = !!ucontrol->value.enumerated.item[0]; - if (val == codec->power_mgmt) + if (val == codec->power_save_node) return 0; - codec->power_mgmt = val; + codec->power_save_node = val; spec->gen.power_down_unused = val; analog_low_current_mode(codec); return 1; @@ -295,7 +295,7 @@ static void __analog_low_current_mode(struct hda_codec *codec, bool force) bool enable; unsigned int verb, parm; - if (!codec->power_mgmt) + if (!codec->power_save_node) enable = false; else enable = is_aa_path_mute(codec) && !spec->gen.active_streams; @@ -517,7 +517,7 @@ static int via_parse_auto_config(struct hda_codec *codec) return err; /* disable widget PM at start for compatibility */ - codec->power_mgmt = 0; + codec->power_save_node = 0; spec->gen.power_down_unused = 0; return 0; } -- cgit v1.2.3-59-g8ed1b From 89c69d3ce5ff0d1d73c19ff0b53268e3325cb3ef Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki/吉藤英明 Date: Thu, 19 Mar 2015 22:42:04 +0900 Subject: net: neighbour: Document {mcast, ucast}_solicit, mcast_resolicit. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- Documentation/networking/ip-sysctl.txt | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index 4412f695a62f..6c07c2b36909 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -1126,11 +1126,23 @@ arp_accept - BOOLEAN gratuitous arp frame, the arp table will be updated regardless if this setting is on or off. +mcast_solicit - INTEGER + The maximum number of multicast probes in INCOMPLETE state, + when the associated hardware address is unknown. Defaults + to 3. + +ucast_solicit - INTEGER + The maximum number of unicast probes in PROBE state, when + the hardware address is being reconfirmed. Defaults to 3. app_solicit - INTEGER The maximum number of probes to send to the user space ARP daemon via netlink before dropping back to multicast probes (see - mcast_solicit). Defaults to 0. + mcast_resolicit). Defaults to 0. + +mcast_resolicit - INTEGER + The maximum number of multicast probes after unicast and + app probes in PROBE state. Defaults to 0. disable_policy - BOOLEAN Disable IPSEC policy (SPD) for this interface -- cgit v1.2.3-59-g8ed1b From 21e0e0ddda5be2905ca163cab2da5bb1880a790c Mon Sep 17 00:00:00 2001 From: "Karicheri, Muralidharan" Date: Fri, 20 Mar 2015 16:11:22 -0400 Subject: net: netcp: use separate reg region for individual ethss modules Ethss has multiple modules within the sub system - switch sub system - sgmii - mdio - switch module NetCP driver re-uses existing davinci mdio driver. It requires to have its own register region to map the reg space. So restructure the code to use separate reg region for the individual modules it manages. Use range property to define register space of NetCP and use reg property to define individual reg spaces. So MDIO will have its own reg space to map. This is a pre-requisite to enable MDIO driver for NetCP. Signed-off-by: Murali Karicheri Signed-off-by: WingMan Kwok CC: "David S. Miller" CC: Mugunthan V N CC: "Lad, Prabhakar" CC: Grygorii Strashko CC: Christoph Jaeger CC: Lokesh Vutla CC: Markus Pargmann CC: Kumar Gala CC: Ian Campbell CC: Mark Rutland CC: Pawel Moll CC: Rob Herring Signed-off-by: David S. Miller --- .../devicetree/bindings/net/keystone-netcp.txt | 16 +-- drivers/net/ethernet/ti/netcp_ethss.c | 130 +++++++++++++++------ 2 files changed, 102 insertions(+), 44 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/keystone-netcp.txt b/Documentation/devicetree/bindings/net/keystone-netcp.txt index f9c07710478d..8368abdd5a34 100644 --- a/Documentation/devicetree/bindings/net/keystone-netcp.txt +++ b/Documentation/devicetree/bindings/net/keystone-netcp.txt @@ -49,6 +49,7 @@ Required properties: - compatible: Should be "ti,netcp-1.0" - clocks: phandle to the reference clocks for the subsystem. - dma-id: Navigator packet dma instance id. +- ranges: address range of NetCP (includes, Ethernet SS, PA and SA) Optional properties: - reg: register location and the size for the following register @@ -66,8 +67,10 @@ Required properties: - label: Must be "netcp-gbe" for 1Gb & "netcp-xgbe" for 10Gb. - reg: register location and the size for the following register regions in the specified order. - - subsystem registers - - serdes registers + - switch subsystem registers + - sgmii port3/4 module registers (only for NetCP 1.4) + - switch module registers + - serdes registers (only for 10G) - tx-channel: the navigator packet dma channel name for tx. - tx-queue: the navigator queue number associated with the tx dma channel. - interfaces: specification for each of the switch port to be registered as a @@ -120,14 +123,13 @@ Optional properties: Example binding: -netcp: netcp@2090000 { +netcp: netcp@2000000 { reg = <0x2620110 0x8>; reg-names = "efuse"; compatible = "ti,netcp-1.0"; #address-cells = <1>; #size-cells = <1>; - ranges; - + ranges = <0 0x2000000 0xfffff>; clocks = <&papllclk>, <&clkcpgmac>, <&chipclk12>; dma-coherent; /* big-endian; */ @@ -137,9 +139,9 @@ netcp: netcp@2090000 { #address-cells = <1>; #size-cells = <1>; ranges; - gbe@0x2090000 { + gbe@90000 { label = "netcp-gbe"; - reg = <0x2090000 0xf00>; + reg = <0x90000 0x300>, <0x90400 0x400>, <0x90800 0x700>; /* enable-ale; */ tx-queue = <648>; tx-channel = <8>; diff --git a/drivers/net/ethernet/ti/netcp_ethss.c b/drivers/net/ethernet/ti/netcp_ethss.c index 2be90a57b595..42592b8fc344 100644 --- a/drivers/net/ethernet/ti/netcp_ethss.c +++ b/drivers/net/ethernet/ti/netcp_ethss.c @@ -40,15 +40,18 @@ #define GBE_MODULE_NAME "netcp-gbe" #define GBE_SS_VERSION_14 0x4ed21104 +#define GBE_SS_REG_INDEX 0 +#define GBE_SGMII34_REG_INDEX 1 +#define GBE_SM_REG_INDEX 2 +/* offset relative to base of GBE_SS_REG_INDEX */ #define GBE13_SGMII_MODULE_OFFSET 0x100 -#define GBE13_SGMII34_MODULE_OFFSET 0x400 -#define GBE13_SWITCH_MODULE_OFFSET 0x800 -#define GBE13_HOST_PORT_OFFSET 0x834 -#define GBE13_SLAVE_PORT_OFFSET 0x860 -#define GBE13_EMAC_OFFSET 0x900 -#define GBE13_SLAVE_PORT2_OFFSET 0xa00 -#define GBE13_HW_STATS_OFFSET 0xb00 -#define GBE13_ALE_OFFSET 0xe00 +/* offset relative to base of GBE_SM_REG_INDEX */ +#define GBE13_HOST_PORT_OFFSET 0x34 +#define GBE13_SLAVE_PORT_OFFSET 0x60 +#define GBE13_EMAC_OFFSET 0x100 +#define GBE13_SLAVE_PORT2_OFFSET 0x200 +#define GBE13_HW_STATS_OFFSET 0x300 +#define GBE13_ALE_OFFSET 0x600 #define GBE13_HOST_PORT_NUM 0 #define GBE13_NUM_SLAVES 4 #define GBE13_NUM_ALE_PORTS (GBE13_NUM_SLAVES + 1) @@ -58,14 +61,18 @@ #define XGBE_MODULE_NAME "netcp-xgbe" #define XGBE_SS_VERSION_10 0x4ee42100 -#define XGBE_SERDES_REG_INDEX 1 +#define XGBE_SS_REG_INDEX 0 +#define XGBE_SM_REG_INDEX 1 +#define XGBE_SERDES_REG_INDEX 2 + +/* offset relative to base of XGBE_SS_REG_INDEX */ #define XGBE10_SGMII_MODULE_OFFSET 0x100 -#define XGBE10_SWITCH_MODULE_OFFSET 0x1000 -#define XGBE10_HOST_PORT_OFFSET 0x1034 -#define XGBE10_SLAVE_PORT_OFFSET 0x1064 -#define XGBE10_EMAC_OFFSET 0x1400 -#define XGBE10_ALE_OFFSET 0x1700 -#define XGBE10_HW_STATS_OFFSET 0x1800 +/* offset relative to base of XGBE_SM_REG_INDEX */ +#define XGBE10_HOST_PORT_OFFSET 0x34 +#define XGBE10_SLAVE_PORT_OFFSET 0x64 +#define XGBE10_EMAC_OFFSET 0x400 +#define XGBE10_ALE_OFFSET 0x700 +#define XGBE10_HW_STATS_OFFSET 0x800 #define XGBE10_HOST_PORT_NUM 0 #define XGBE10_NUM_SLAVES 2 #define XGBE10_NUM_ALE_PORTS (XGBE10_NUM_SLAVES + 1) @@ -1579,9 +1586,9 @@ static int init_slave(struct gbe_priv *gbe_dev, struct gbe_slave *slave, else if (gbe_dev->ss_version == XGBE_SS_VERSION_10) emac_reg_ofs = XGBE10_EMAC_OFFSET; - slave->port_regs = gbe_dev->ss_regs + port_reg_ofs + + slave->port_regs = gbe_dev->switch_regs + port_reg_ofs + (0x30 * port_reg_num); - slave->emac_regs = gbe_dev->ss_regs + emac_reg_ofs + + slave->emac_regs = gbe_dev->switch_regs + emac_reg_ofs + (0x40 * slave->slave_num); if (gbe_dev->ss_version == GBE_SS_VERSION_14) { @@ -1732,22 +1739,39 @@ static int set_xgbe_ethss10_priv(struct gbe_priv *gbe_dev, ret = of_address_to_resource(node, 0, &res); if (ret) { - dev_err(gbe_dev->dev, "Can't translate of node(%s) address for xgbe subsystem regs\n", - node->name); + dev_err(gbe_dev->dev, + "Can't xlate xgbe of node(%s) ss address at %d\n", + node->name, XGBE_SS_REG_INDEX); return ret; } regs = devm_ioremap_resource(gbe_dev->dev, &res); if (IS_ERR(regs)) { - dev_err(gbe_dev->dev, "Failed to map xgbe register base\n"); + dev_err(gbe_dev->dev, "Failed to map xgbe ss register base\n"); return PTR_ERR(regs); } gbe_dev->ss_regs = regs; + ret = of_address_to_resource(node, XGBE_SM_REG_INDEX, &res); + if (ret) { + dev_err(gbe_dev->dev, + "Can't xlate xgbe of node(%s) sm address at %d\n", + node->name, XGBE_SM_REG_INDEX); + return ret; + } + + regs = devm_ioremap_resource(gbe_dev->dev, &res); + if (IS_ERR(regs)) { + dev_err(gbe_dev->dev, "Failed to map xgbe sm register base\n"); + return PTR_ERR(regs); + } + gbe_dev->switch_regs = regs; + ret = of_address_to_resource(node, XGBE_SERDES_REG_INDEX, &res); if (ret) { - dev_err(gbe_dev->dev, "Can't translate of node(%s) address for xgbe serdes regs\n", - node->name); + dev_err(gbe_dev->dev, + "Can't xlate xgbe serdes of node(%s) address at %d\n", + node->name, XGBE_SERDES_REG_INDEX); return ret; } @@ -1770,11 +1794,10 @@ static int set_xgbe_ethss10_priv(struct gbe_priv *gbe_dev, gbe_dev->ss_version = XGBE_SS_VERSION_10; gbe_dev->sgmii_port_regs = gbe_dev->ss_regs + XGBE10_SGMII_MODULE_OFFSET; - gbe_dev->switch_regs = gbe_dev->ss_regs + XGBE10_SWITCH_MODULE_OFFSET; gbe_dev->host_port_regs = gbe_dev->ss_regs + XGBE10_HOST_PORT_OFFSET; for (i = 0; i < XGBE10_NUM_HW_STATS_MOD; i++) - gbe_dev->hw_stats_regs[i] = gbe_dev->ss_regs + + gbe_dev->hw_stats_regs[i] = gbe_dev->switch_regs + XGBE10_HW_STATS_OFFSET + (GBE_HW_STATS_REG_MAP_SZ * i); gbe_dev->ale_reg = gbe_dev->ss_regs + XGBE10_ALE_OFFSET; @@ -1809,10 +1832,11 @@ static int get_gbe_resource_version(struct gbe_priv *gbe_dev, void __iomem *regs; int ret; - ret = of_address_to_resource(node, 0, &res); + ret = of_address_to_resource(node, GBE_SS_REG_INDEX, &res); if (ret) { - dev_err(gbe_dev->dev, "Can't translate of node(%s) address\n", - node->name); + dev_err(gbe_dev->dev, + "Can't translate of node(%s) of gbe ss address at %d\n", + node->name, GBE_SS_REG_INDEX); return ret; } @@ -1829,8 +1853,41 @@ static int get_gbe_resource_version(struct gbe_priv *gbe_dev, static int set_gbe_ethss14_priv(struct gbe_priv *gbe_dev, struct device_node *node) { + struct resource res; void __iomem *regs; - int i; + int i, ret; + + ret = of_address_to_resource(node, GBE_SGMII34_REG_INDEX, &res); + if (ret) { + dev_err(gbe_dev->dev, + "Can't translate of gbe node(%s) address at index %d\n", + node->name, GBE_SGMII34_REG_INDEX); + return ret; + } + + regs = devm_ioremap_resource(gbe_dev->dev, &res); + if (IS_ERR(regs)) { + dev_err(gbe_dev->dev, + "Failed to map gbe sgmii port34 register base\n"); + return PTR_ERR(regs); + } + gbe_dev->sgmii_port34_regs = regs; + + ret = of_address_to_resource(node, GBE_SM_REG_INDEX, &res); + if (ret) { + dev_err(gbe_dev->dev, + "Can't translate of gbe node(%s) address at index %d\n", + node->name, GBE_SM_REG_INDEX); + return ret; + } + + regs = devm_ioremap_resource(gbe_dev->dev, &res); + if (IS_ERR(regs)) { + dev_err(gbe_dev->dev, + "Failed to map gbe switch module register base\n"); + return PTR_ERR(regs); + } + gbe_dev->switch_regs = regs; gbe_dev->hw_stats = devm_kzalloc(gbe_dev->dev, GBE13_NUM_HW_STAT_ENTRIES * @@ -1841,17 +1898,16 @@ static int set_gbe_ethss14_priv(struct gbe_priv *gbe_dev, return -ENOMEM; } - regs = gbe_dev->ss_regs; - gbe_dev->sgmii_port_regs = regs + GBE13_SGMII_MODULE_OFFSET; - gbe_dev->sgmii_port34_regs = regs + GBE13_SGMII34_MODULE_OFFSET; - gbe_dev->switch_regs = regs + GBE13_SWITCH_MODULE_OFFSET; - gbe_dev->host_port_regs = regs + GBE13_HOST_PORT_OFFSET; + gbe_dev->sgmii_port_regs = gbe_dev->ss_regs + GBE13_SGMII_MODULE_OFFSET; + gbe_dev->host_port_regs = gbe_dev->switch_regs + GBE13_HOST_PORT_OFFSET; - for (i = 0; i < GBE13_NUM_HW_STATS_MOD; i++) - gbe_dev->hw_stats_regs[i] = regs + GBE13_HW_STATS_OFFSET + - (GBE_HW_STATS_REG_MAP_SZ * i); + for (i = 0; i < GBE13_NUM_HW_STATS_MOD; i++) { + gbe_dev->hw_stats_regs[i] = + gbe_dev->switch_regs + GBE13_HW_STATS_OFFSET + + (GBE_HW_STATS_REG_MAP_SZ * i); + } - gbe_dev->ale_reg = regs + GBE13_ALE_OFFSET; + gbe_dev->ale_reg = gbe_dev->switch_regs + GBE13_ALE_OFFSET; gbe_dev->ale_ports = GBE13_NUM_ALE_PORTS; gbe_dev->host_port = GBE13_HOST_PORT_NUM; gbe_dev->ale_entries = GBE13_NUM_ALE_ENTRIES; -- cgit v1.2.3-59-g8ed1b From 9a391c7ba7dcfc64754140ce13d5fc55d149531a Mon Sep 17 00:00:00 2001 From: WingMan Kwok Date: Fri, 20 Mar 2015 16:11:25 -0400 Subject: net: netcp: ethss: enhancement to support NetCP 1.5 ethss NetCP 1.5 available on newer K2 SoCs such as K2E and K2L introduced 3 variants of the ethss subsystem, 9 port, 5 port and 2 port. These have one host port towards the CPU and N external slave ports. To customize the driver for these new ethss sub systems, multiple compatibility strings are introduced. Currently some of parameters that are different on different variants such as number of ALE ports, stats modules and number of ports are defined through constants. These are now changed to variables in gbe_priv data that get set based on the compatibility string. This is required as there are no hardware identification registers available to distinguish among the variants of NetCP 1.5 ethss. However there is identification register available to differentiate between NetCP 1.4 vs NetCP 1.5 and the same is made use of in the code to differentiate them. For more reading on the details of this peripheral, please refer to the User Guide available at http://www.ti.com/lit/pdf/spruhz3 Signed-off-by: Murali Karicheri Signed-off-by: WingMan Kwok CC: "David S. Miller" CC: Mugunthan V N CC: "Lad, Prabhakar" CC: Grygorii Strashko CC: Christoph Jaeger CC: Lokesh Vutla CC: Markus Pargmann CC: Kumar Gala CC: Ian Campbell CC: Mark Rutland CC: Pawel Moll CC: Rob Herring Signed-off-by: David S. Miller --- .../devicetree/bindings/net/keystone-netcp.txt | 18 + drivers/net/ethernet/ti/netcp_ethss.c | 920 ++++++++++++++++++++- 2 files changed, 902 insertions(+), 36 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/keystone-netcp.txt b/Documentation/devicetree/bindings/net/keystone-netcp.txt index 8368abdd5a34..d0e6fa38f335 100644 --- a/Documentation/devicetree/bindings/net/keystone-netcp.txt +++ b/Documentation/devicetree/bindings/net/keystone-netcp.txt @@ -65,12 +65,30 @@ NetCP device properties: Device specification for NetCP sub-modules. 1Gb/10Gb (gbe/xgbe) ethernet switch sub-module specifications. Required properties: - label: Must be "netcp-gbe" for 1Gb & "netcp-xgbe" for 10Gb. +- compatible: Must be one of below:- + "ti,netcp-gbe" for 1GbE on NetCP 1.4 + "ti,netcp-gbe-5" for 1GbE N NetCP 1.5 (N=5) + "ti,netcp-gbe-9" for 1GbE N NetCP 1.5 (N=9) + "ti,netcp-gbe-2" for 1GbE N NetCP 1.5 (N=2) + "ti,netcp-xgbe" for 10 GbE + - reg: register location and the size for the following register regions in the specified order. - switch subsystem registers - sgmii port3/4 module registers (only for NetCP 1.4) - switch module registers - serdes registers (only for 10G) + + NetCP 1.4 ethss, here is the order + index #0 - switch subsystem registers + index #1 - sgmii port3/4 module registers + index #2 - switch module registers + + NetCP 1.5 ethss 9 port, 5 port and 2 port + index #0 - switch subsystem registers + index #1 - switch module registers + index #2 - serdes registers + - tx-channel: the navigator packet dma channel name for tx. - tx-queue: the navigator queue number associated with the tx dma channel. - interfaces: specification for each of the switch port to be registered as a diff --git a/drivers/net/ethernet/ti/netcp_ethss.c b/drivers/net/ethernet/ti/netcp_ethss.c index f8f3be3fd59f..2bef655279f3 100644 --- a/drivers/net/ethernet/ti/netcp_ethss.c +++ b/drivers/net/ethernet/ti/netcp_ethss.c @@ -53,10 +53,31 @@ #define GBE13_HW_STATS_OFFSET 0x300 #define GBE13_ALE_OFFSET 0x600 #define GBE13_HOST_PORT_NUM 0 -#define GBE13_NUM_SLAVES 4 -#define GBE13_NUM_ALE_PORTS (GBE13_NUM_SLAVES + 1) #define GBE13_NUM_ALE_ENTRIES 1024 +/* 1G Ethernet NU SS defines */ +#define GBENU_MODULE_NAME "netcp-gbenu" +#define GBE_SS_ID_NU 0x4ee6 +#define GBE_SS_ID_2U 0x4ee8 + +#define IS_SS_ID_MU(d) \ + ((GBE_IDENT((d)->ss_version) == GBE_SS_ID_NU) || \ + (GBE_IDENT((d)->ss_version) == GBE_SS_ID_2U)) + +#define IS_SS_ID_NU(d) \ + (GBE_IDENT((d)->ss_version) == GBE_SS_ID_NU) + +#define GBENU_SS_REG_INDEX 0 +#define GBENU_SM_REG_INDEX 1 +#define GBENU_SGMII_MODULE_OFFSET 0x100 +#define GBENU_HOST_PORT_OFFSET 0x1000 +#define GBENU_SLAVE_PORT_OFFSET 0x2000 +#define GBENU_EMAC_OFFSET 0x2330 +#define GBENU_HW_STATS_OFFSET 0x1a000 +#define GBENU_ALE_OFFSET 0x1e000 +#define GBENU_HOST_PORT_NUM 0 +#define GBENU_NUM_ALE_ENTRIES 1024 + /* 10G Ethernet SS defines */ #define XGBE_MODULE_NAME "netcp-xgbe" #define XGBE_SS_VERSION_10 0x4ee42100 @@ -74,8 +95,6 @@ #define XGBE10_ALE_OFFSET 0x700 #define XGBE10_HW_STATS_OFFSET 0x800 #define XGBE10_HOST_PORT_NUM 0 -#define XGBE10_NUM_SLAVES 2 -#define XGBE10_NUM_ALE_PORTS (XGBE10_NUM_SLAVES + 1) #define XGBE10_NUM_ALE_ENTRIES 1024 #define GBE_TIMER_INTERVAL (HZ / 2) @@ -95,7 +114,7 @@ #define MACSL_FULLDUPLEX BIT(0) #define GBE_CTL_P0_ENABLE BIT(2) -#define GBE_REG_VAL_STAT_ENABLE_ALL 0xff +#define GBE13_REG_VAL_STAT_ENABLE_ALL 0xff #define XGBE_REG_VAL_STAT_ENABLE_ALL 0xf #define GBE_STATS_CD_SEL BIT(28) @@ -115,11 +134,20 @@ #define GBE_STATSC_MODULE 2 #define GBE_STATSD_MODULE 3 +#define GBENU_STATS0_MODULE 0 +#define GBENU_STATS1_MODULE 1 +#define GBENU_STATS2_MODULE 2 +#define GBENU_STATS3_MODULE 3 +#define GBENU_STATS4_MODULE 4 +#define GBENU_STATS5_MODULE 5 +#define GBENU_STATS6_MODULE 6 +#define GBENU_STATS7_MODULE 7 +#define GBENU_STATS8_MODULE 8 + #define XGBE_STATS0_MODULE 0 #define XGBE_STATS1_MODULE 1 #define XGBE_STATS2_MODULE 2 -#define MAX_SLAVES GBE13_NUM_SLAVES /* s: 0-based slave_port */ #define SGMII_BASE(s) \ (((s) < 2) ? gbe_dev->sgmii_port_regs : gbe_dev->sgmii_port34_regs) @@ -132,10 +160,14 @@ #define GBE_SET_REG_OFS(p, rb, rn) p->rb##_ofs.rn = \ offsetof(struct gbe##_##rb, rn) +#define GBENU_SET_REG_OFS(p, rb, rn) p->rb##_ofs.rn = \ + offsetof(struct gbenu##_##rb, rn) #define XGBE_SET_REG_OFS(p, rb, rn) p->rb##_ofs.rn = \ offsetof(struct xgbe##_##rb, rn) #define GBE_REG_ADDR(p, rb, rn) (p->rb + p->rb##_ofs.rn) +#define HOST_TX_PRI_MAP_DEFAULT 0x00000000 + struct xgbe_ss_regs { u32 id_ver; u32 synce_count; @@ -265,6 +297,192 @@ struct xgbe_hw_stats { #define XGBE10_NUM_STAT_ENTRIES (sizeof(struct xgbe_hw_stats)/sizeof(u32)) +struct gbenu_ss_regs { + u32 id_ver; + u32 synce_count; /* NU */ + u32 synce_mux; /* NU */ + u32 control; /* 2U */ + u32 __rsvd_0[2]; /* 2U */ + u32 rgmii_status; /* 2U */ + u32 ss_status; /* 2U */ +}; + +struct gbenu_switch_regs { + u32 id_ver; + u32 control; + u32 __rsvd_0[2]; + u32 emcontrol; + u32 stat_port_en; + u32 ptype; /* NU */ + u32 soft_idle; + u32 thru_rate; /* NU */ + u32 gap_thresh; /* NU */ + u32 tx_start_wds; /* NU */ + u32 eee_prescale; /* 2U */ + u32 tx_g_oflow_thresh_set; /* NU */ + u32 tx_g_oflow_thresh_clr; /* NU */ + u32 tx_g_buf_thresh_set_l; /* NU */ + u32 tx_g_buf_thresh_set_h; /* NU */ + u32 tx_g_buf_thresh_clr_l; /* NU */ + u32 tx_g_buf_thresh_clr_h; /* NU */ +}; + +struct gbenu_port_regs { + u32 __rsvd_0; + u32 control; + u32 max_blks; /* 2U */ + u32 mem_align1; + u32 blk_cnt; + u32 port_vlan; + u32 tx_pri_map; /* NU */ + u32 pri_ctl; /* 2U */ + u32 rx_pri_map; + u32 rx_maxlen; + u32 tx_blks_pri; /* NU */ + u32 __rsvd_1; + u32 idle2lpi; /* 2U */ + u32 lpi2idle; /* 2U */ + u32 eee_status; /* 2U */ + u32 __rsvd_2; + u32 __rsvd_3[176]; /* NU: more to add */ + u32 __rsvd_4[2]; + u32 sa_lo; + u32 sa_hi; + u32 ts_ctl; + u32 ts_seq_ltype; + u32 ts_vlan; + u32 ts_ctl_ltype2; + u32 ts_ctl2; +}; + +struct gbenu_host_port_regs { + u32 __rsvd_0; + u32 control; + u32 flow_id_offset; /* 2U */ + u32 __rsvd_1; + u32 blk_cnt; + u32 port_vlan; + u32 tx_pri_map; /* NU */ + u32 pri_ctl; + u32 rx_pri_map; + u32 rx_maxlen; + u32 tx_blks_pri; /* NU */ + u32 __rsvd_2; + u32 idle2lpi; /* 2U */ + u32 lpi2wake; /* 2U */ + u32 eee_status; /* 2U */ + u32 __rsvd_3; + u32 __rsvd_4[184]; /* NU */ + u32 host_blks_pri; /* NU */ +}; + +struct gbenu_emac_regs { + u32 mac_control; + u32 mac_status; + u32 soft_reset; + u32 boff_test; + u32 rx_pause; + u32 __rsvd_0[11]; /* NU */ + u32 tx_pause; + u32 __rsvd_1[11]; /* NU */ + u32 em_control; + u32 tx_gap; +}; + +/* Some hw stat regs are applicable to slave port only. + * This is handled by gbenu_et_stats struct. Also some + * are for SS version NU and some are for 2U. + */ +struct gbenu_hw_stats { + u32 rx_good_frames; + u32 rx_broadcast_frames; + u32 rx_multicast_frames; + u32 rx_pause_frames; /* slave */ + u32 rx_crc_errors; + u32 rx_align_code_errors; /* slave */ + u32 rx_oversized_frames; + u32 rx_jabber_frames; /* slave */ + u32 rx_undersized_frames; + u32 rx_fragments; /* slave */ + u32 ale_drop; + u32 ale_overrun_drop; + u32 rx_bytes; + u32 tx_good_frames; + u32 tx_broadcast_frames; + u32 tx_multicast_frames; + u32 tx_pause_frames; /* slave */ + u32 tx_deferred_frames; /* slave */ + u32 tx_collision_frames; /* slave */ + u32 tx_single_coll_frames; /* slave */ + u32 tx_mult_coll_frames; /* slave */ + u32 tx_excessive_collisions; /* slave */ + u32 tx_late_collisions; /* slave */ + u32 rx_ipg_error; /* slave 10G only */ + u32 tx_carrier_sense_errors; /* slave */ + u32 tx_bytes; + u32 tx_64B_frames; + u32 tx_65_to_127B_frames; + u32 tx_128_to_255B_frames; + u32 tx_256_to_511B_frames; + u32 tx_512_to_1023B_frames; + u32 tx_1024B_frames; + u32 net_bytes; + u32 rx_bottom_fifo_drop; + u32 rx_port_mask_drop; + u32 rx_top_fifo_drop; + u32 ale_rate_limit_drop; + u32 ale_vid_ingress_drop; + u32 ale_da_eq_sa_drop; + u32 __rsvd_0[3]; + u32 ale_unknown_ucast; + u32 ale_unknown_ucast_bytes; + u32 ale_unknown_mcast; + u32 ale_unknown_mcast_bytes; + u32 ale_unknown_bcast; + u32 ale_unknown_bcast_bytes; + u32 ale_pol_match; + u32 ale_pol_match_red; /* NU */ + u32 ale_pol_match_yellow; /* NU */ + u32 __rsvd_1[44]; + u32 tx_mem_protect_err; + /* following NU only */ + u32 tx_pri0; + u32 tx_pri1; + u32 tx_pri2; + u32 tx_pri3; + u32 tx_pri4; + u32 tx_pri5; + u32 tx_pri6; + u32 tx_pri7; + u32 tx_pri0_bcnt; + u32 tx_pri1_bcnt; + u32 tx_pri2_bcnt; + u32 tx_pri3_bcnt; + u32 tx_pri4_bcnt; + u32 tx_pri5_bcnt; + u32 tx_pri6_bcnt; + u32 tx_pri7_bcnt; + u32 tx_pri0_drop; + u32 tx_pri1_drop; + u32 tx_pri2_drop; + u32 tx_pri3_drop; + u32 tx_pri4_drop; + u32 tx_pri5_drop; + u32 tx_pri6_drop; + u32 tx_pri7_drop; + u32 tx_pri0_drop_bcnt; + u32 tx_pri1_drop_bcnt; + u32 tx_pri2_drop_bcnt; + u32 tx_pri3_drop_bcnt; + u32 tx_pri4_drop_bcnt; + u32 tx_pri5_drop_bcnt; + u32 tx_pri6_drop_bcnt; + u32 tx_pri7_drop_bcnt; +}; + +#define GBENU_NUM_HW_STAT_ENTRIES (sizeof(struct gbenu_hw_stats) / sizeof(u32)) +#define GBENU_HW_STATS_REG_MAP_SZ 0x200 + struct gbe_ss_regs { u32 id_ver; u32 synce_count; @@ -323,6 +541,7 @@ struct gbe_port_regs_ofs { u16 ts_vlan; u16 ts_ctl_ltype2; u16 ts_ctl2; + u16 rx_maxlen; /* 2U, NU */ }; struct gbe_host_port_regs { @@ -397,9 +616,7 @@ struct gbe_hw_stats { }; #define GBE13_NUM_HW_STAT_ENTRIES (sizeof(struct gbe_hw_stats)/sizeof(u32)) -#define GBE13_NUM_HW_STATS_MOD 2 -#define XGBE10_NUM_HW_STATS_MOD 3 -#define GBE_MAX_HW_STAT_MODS 3 +#define GBE_MAX_HW_STAT_MODS 9 #define GBE_HW_STATS_REG_MAP_SZ 0x100 struct gbe_slave { @@ -427,11 +644,14 @@ struct gbe_priv { u32 ale_entries; u32 ale_ports; bool enable_ale; + u8 max_num_slaves; + u8 max_num_ports; /* max_num_slaves + 1 */ struct netcp_tx_pipe tx_pipe; int host_port; u32 rx_packet_max; u32 ss_version; + u32 stats_en_mask; void __iomem *ss_regs; void __iomem *switch_regs; @@ -653,6 +873,488 @@ static const struct netcp_ethtool_stat gbe13_et_stats[] = { GBE_STATSD_INFO(rx_dma_overruns), }; +/* This is the size of entries in GBENU_STATS_HOST */ +#define GBENU_ET_STATS_HOST_SIZE 33 + +#define GBENU_STATS_HOST(field) \ +{ \ + "GBE_HOST:"#field, GBENU_STATS0_MODULE, \ + FIELD_SIZEOF(struct gbenu_hw_stats, field), \ + offsetof(struct gbenu_hw_stats, field) \ +} + +/* This is the size of entries in GBENU_STATS_HOST */ +#define GBENU_ET_STATS_PORT_SIZE 46 + +#define GBENU_STATS_P1(field) \ +{ \ + "GBE_P1:"#field, GBENU_STATS1_MODULE, \ + FIELD_SIZEOF(struct gbenu_hw_stats, field), \ + offsetof(struct gbenu_hw_stats, field) \ +} + +#define GBENU_STATS_P2(field) \ +{ \ + "GBE_P2:"#field, GBENU_STATS2_MODULE, \ + FIELD_SIZEOF(struct gbenu_hw_stats, field), \ + offsetof(struct gbenu_hw_stats, field) \ +} + +#define GBENU_STATS_P3(field) \ +{ \ + "GBE_P3:"#field, GBENU_STATS3_MODULE, \ + FIELD_SIZEOF(struct gbenu_hw_stats, field), \ + offsetof(struct gbenu_hw_stats, field) \ +} + +#define GBENU_STATS_P4(field) \ +{ \ + "GBE_P4:"#field, GBENU_STATS4_MODULE, \ + FIELD_SIZEOF(struct gbenu_hw_stats, field), \ + offsetof(struct gbenu_hw_stats, field) \ +} + +#define GBENU_STATS_P5(field) \ +{ \ + "GBE_P5:"#field, GBENU_STATS5_MODULE, \ + FIELD_SIZEOF(struct gbenu_hw_stats, field), \ + offsetof(struct gbenu_hw_stats, field) \ +} + +#define GBENU_STATS_P6(field) \ +{ \ + "GBE_P6:"#field, GBENU_STATS6_MODULE, \ + FIELD_SIZEOF(struct gbenu_hw_stats, field), \ + offsetof(struct gbenu_hw_stats, field) \ +} + +#define GBENU_STATS_P7(field) \ +{ \ + "GBE_P7:"#field, GBENU_STATS7_MODULE, \ + FIELD_SIZEOF(struct gbenu_hw_stats, field), \ + offsetof(struct gbenu_hw_stats, field) \ +} + +#define GBENU_STATS_P8(field) \ +{ \ + "GBE_P8:"#field, GBENU_STATS8_MODULE, \ + FIELD_SIZEOF(struct gbenu_hw_stats, field), \ + offsetof(struct gbenu_hw_stats, field) \ +} + +static const struct netcp_ethtool_stat gbenu_et_stats[] = { + /* GBENU Host Module */ + GBENU_STATS_HOST(rx_good_frames), + GBENU_STATS_HOST(rx_broadcast_frames), + GBENU_STATS_HOST(rx_multicast_frames), + GBENU_STATS_HOST(rx_crc_errors), + GBENU_STATS_HOST(rx_oversized_frames), + GBENU_STATS_HOST(rx_undersized_frames), + GBENU_STATS_HOST(ale_drop), + GBENU_STATS_HOST(ale_overrun_drop), + GBENU_STATS_HOST(rx_bytes), + GBENU_STATS_HOST(tx_good_frames), + GBENU_STATS_HOST(tx_broadcast_frames), + GBENU_STATS_HOST(tx_multicast_frames), + GBENU_STATS_HOST(tx_bytes), + GBENU_STATS_HOST(tx_64B_frames), + GBENU_STATS_HOST(tx_65_to_127B_frames), + GBENU_STATS_HOST(tx_128_to_255B_frames), + GBENU_STATS_HOST(tx_256_to_511B_frames), + GBENU_STATS_HOST(tx_512_to_1023B_frames), + GBENU_STATS_HOST(tx_1024B_frames), + GBENU_STATS_HOST(net_bytes), + GBENU_STATS_HOST(rx_bottom_fifo_drop), + GBENU_STATS_HOST(rx_port_mask_drop), + GBENU_STATS_HOST(rx_top_fifo_drop), + GBENU_STATS_HOST(ale_rate_limit_drop), + GBENU_STATS_HOST(ale_vid_ingress_drop), + GBENU_STATS_HOST(ale_da_eq_sa_drop), + GBENU_STATS_HOST(ale_unknown_ucast), + GBENU_STATS_HOST(ale_unknown_ucast_bytes), + GBENU_STATS_HOST(ale_unknown_mcast), + GBENU_STATS_HOST(ale_unknown_mcast_bytes), + GBENU_STATS_HOST(ale_unknown_bcast), + GBENU_STATS_HOST(ale_unknown_bcast_bytes), + GBENU_STATS_HOST(tx_mem_protect_err), + /* GBENU Module 1 */ + GBENU_STATS_P1(rx_good_frames), + GBENU_STATS_P1(rx_broadcast_frames), + GBENU_STATS_P1(rx_multicast_frames), + GBENU_STATS_P1(rx_pause_frames), + GBENU_STATS_P1(rx_crc_errors), + GBENU_STATS_P1(rx_align_code_errors), + GBENU_STATS_P1(rx_oversized_frames), + GBENU_STATS_P1(rx_jabber_frames), + GBENU_STATS_P1(rx_undersized_frames), + GBENU_STATS_P1(rx_fragments), + GBENU_STATS_P1(ale_drop), + GBENU_STATS_P1(ale_overrun_drop), + GBENU_STATS_P1(rx_bytes), + GBENU_STATS_P1(tx_good_frames), + GBENU_STATS_P1(tx_broadcast_frames), + GBENU_STATS_P1(tx_multicast_frames), + GBENU_STATS_P1(tx_pause_frames), + GBENU_STATS_P1(tx_deferred_frames), + GBENU_STATS_P1(tx_collision_frames), + GBENU_STATS_P1(tx_single_coll_frames), + GBENU_STATS_P1(tx_mult_coll_frames), + GBENU_STATS_P1(tx_excessive_collisions), + GBENU_STATS_P1(tx_late_collisions), + GBENU_STATS_P1(rx_ipg_error), + GBENU_STATS_P1(tx_carrier_sense_errors), + GBENU_STATS_P1(tx_bytes), + GBENU_STATS_P1(tx_64B_frames), + GBENU_STATS_P1(tx_65_to_127B_frames), + GBENU_STATS_P1(tx_128_to_255B_frames), + GBENU_STATS_P1(tx_256_to_511B_frames), + GBENU_STATS_P1(tx_512_to_1023B_frames), + GBENU_STATS_P1(tx_1024B_frames), + GBENU_STATS_P1(net_bytes), + GBENU_STATS_P1(rx_bottom_fifo_drop), + GBENU_STATS_P1(rx_port_mask_drop), + GBENU_STATS_P1(rx_top_fifo_drop), + GBENU_STATS_P1(ale_rate_limit_drop), + GBENU_STATS_P1(ale_vid_ingress_drop), + GBENU_STATS_P1(ale_da_eq_sa_drop), + GBENU_STATS_P1(ale_unknown_ucast), + GBENU_STATS_P1(ale_unknown_ucast_bytes), + GBENU_STATS_P1(ale_unknown_mcast), + GBENU_STATS_P1(ale_unknown_mcast_bytes), + GBENU_STATS_P1(ale_unknown_bcast), + GBENU_STATS_P1(ale_unknown_bcast_bytes), + GBENU_STATS_P1(tx_mem_protect_err), + /* GBENU Module 2 */ + GBENU_STATS_P2(rx_good_frames), + GBENU_STATS_P2(rx_broadcast_frames), + GBENU_STATS_P2(rx_multicast_frames), + GBENU_STATS_P2(rx_pause_frames), + GBENU_STATS_P2(rx_crc_errors), + GBENU_STATS_P2(rx_align_code_errors), + GBENU_STATS_P2(rx_oversized_frames), + GBENU_STATS_P2(rx_jabber_frames), + GBENU_STATS_P2(rx_undersized_frames), + GBENU_STATS_P2(rx_fragments), + GBENU_STATS_P2(ale_drop), + GBENU_STATS_P2(ale_overrun_drop), + GBENU_STATS_P2(rx_bytes), + GBENU_STATS_P2(tx_good_frames), + GBENU_STATS_P2(tx_broadcast_frames), + GBENU_STATS_P2(tx_multicast_frames), + GBENU_STATS_P2(tx_pause_frames), + GBENU_STATS_P2(tx_deferred_frames), + GBENU_STATS_P2(tx_collision_frames), + GBENU_STATS_P2(tx_single_coll_frames), + GBENU_STATS_P2(tx_mult_coll_frames), + GBENU_STATS_P2(tx_excessive_collisions), + GBENU_STATS_P2(tx_late_collisions), + GBENU_STATS_P2(rx_ipg_error), + GBENU_STATS_P2(tx_carrier_sense_errors), + GBENU_STATS_P2(tx_bytes), + GBENU_STATS_P2(tx_64B_frames), + GBENU_STATS_P2(tx_65_to_127B_frames), + GBENU_STATS_P2(tx_128_to_255B_frames), + GBENU_STATS_P2(tx_256_to_511B_frames), + GBENU_STATS_P2(tx_512_to_1023B_frames), + GBENU_STATS_P2(tx_1024B_frames), + GBENU_STATS_P2(net_bytes), + GBENU_STATS_P2(rx_bottom_fifo_drop), + GBENU_STATS_P2(rx_port_mask_drop), + GBENU_STATS_P2(rx_top_fifo_drop), + GBENU_STATS_P2(ale_rate_limit_drop), + GBENU_STATS_P2(ale_vid_ingress_drop), + GBENU_STATS_P2(ale_da_eq_sa_drop), + GBENU_STATS_P2(ale_unknown_ucast), + GBENU_STATS_P2(ale_unknown_ucast_bytes), + GBENU_STATS_P2(ale_unknown_mcast), + GBENU_STATS_P2(ale_unknown_mcast_bytes), + GBENU_STATS_P2(ale_unknown_bcast), + GBENU_STATS_P2(ale_unknown_bcast_bytes), + GBENU_STATS_P2(tx_mem_protect_err), + /* GBENU Module 3 */ + GBENU_STATS_P3(rx_good_frames), + GBENU_STATS_P3(rx_broadcast_frames), + GBENU_STATS_P3(rx_multicast_frames), + GBENU_STATS_P3(rx_pause_frames), + GBENU_STATS_P3(rx_crc_errors), + GBENU_STATS_P3(rx_align_code_errors), + GBENU_STATS_P3(rx_oversized_frames), + GBENU_STATS_P3(rx_jabber_frames), + GBENU_STATS_P3(rx_undersized_frames), + GBENU_STATS_P3(rx_fragments), + GBENU_STATS_P3(ale_drop), + GBENU_STATS_P3(ale_overrun_drop), + GBENU_STATS_P3(rx_bytes), + GBENU_STATS_P3(tx_good_frames), + GBENU_STATS_P3(tx_broadcast_frames), + GBENU_STATS_P3(tx_multicast_frames), + GBENU_STATS_P3(tx_pause_frames), + GBENU_STATS_P3(tx_deferred_frames), + GBENU_STATS_P3(tx_collision_frames), + GBENU_STATS_P3(tx_single_coll_frames), + GBENU_STATS_P3(tx_mult_coll_frames), + GBENU_STATS_P3(tx_excessive_collisions), + GBENU_STATS_P3(tx_late_collisions), + GBENU_STATS_P3(rx_ipg_error), + GBENU_STATS_P3(tx_carrier_sense_errors), + GBENU_STATS_P3(tx_bytes), + GBENU_STATS_P3(tx_64B_frames), + GBENU_STATS_P3(tx_65_to_127B_frames), + GBENU_STATS_P3(tx_128_to_255B_frames), + GBENU_STATS_P3(tx_256_to_511B_frames), + GBENU_STATS_P3(tx_512_to_1023B_frames), + GBENU_STATS_P3(tx_1024B_frames), + GBENU_STATS_P3(net_bytes), + GBENU_STATS_P3(rx_bottom_fifo_drop), + GBENU_STATS_P3(rx_port_mask_drop), + GBENU_STATS_P3(rx_top_fifo_drop), + GBENU_STATS_P3(ale_rate_limit_drop), + GBENU_STATS_P3(ale_vid_ingress_drop), + GBENU_STATS_P3(ale_da_eq_sa_drop), + GBENU_STATS_P3(ale_unknown_ucast), + GBENU_STATS_P3(ale_unknown_ucast_bytes), + GBENU_STATS_P3(ale_unknown_mcast), + GBENU_STATS_P3(ale_unknown_mcast_bytes), + GBENU_STATS_P3(ale_unknown_bcast), + GBENU_STATS_P3(ale_unknown_bcast_bytes), + GBENU_STATS_P3(tx_mem_protect_err), + /* GBENU Module 4 */ + GBENU_STATS_P4(rx_good_frames), + GBENU_STATS_P4(rx_broadcast_frames), + GBENU_STATS_P4(rx_multicast_frames), + GBENU_STATS_P4(rx_pause_frames), + GBENU_STATS_P4(rx_crc_errors), + GBENU_STATS_P4(rx_align_code_errors), + GBENU_STATS_P4(rx_oversized_frames), + GBENU_STATS_P4(rx_jabber_frames), + GBENU_STATS_P4(rx_undersized_frames), + GBENU_STATS_P4(rx_fragments), + GBENU_STATS_P4(ale_drop), + GBENU_STATS_P4(ale_overrun_drop), + GBENU_STATS_P4(rx_bytes), + GBENU_STATS_P4(tx_good_frames), + GBENU_STATS_P4(tx_broadcast_frames), + GBENU_STATS_P4(tx_multicast_frames), + GBENU_STATS_P4(tx_pause_frames), + GBENU_STATS_P4(tx_deferred_frames), + GBENU_STATS_P4(tx_collision_frames), + GBENU_STATS_P4(tx_single_coll_frames), + GBENU_STATS_P4(tx_mult_coll_frames), + GBENU_STATS_P4(tx_excessive_collisions), + GBENU_STATS_P4(tx_late_collisions), + GBENU_STATS_P4(rx_ipg_error), + GBENU_STATS_P4(tx_carrier_sense_errors), + GBENU_STATS_P4(tx_bytes), + GBENU_STATS_P4(tx_64B_frames), + GBENU_STATS_P4(tx_65_to_127B_frames), + GBENU_STATS_P4(tx_128_to_255B_frames), + GBENU_STATS_P4(tx_256_to_511B_frames), + GBENU_STATS_P4(tx_512_to_1023B_frames), + GBENU_STATS_P4(tx_1024B_frames), + GBENU_STATS_P4(net_bytes), + GBENU_STATS_P4(rx_bottom_fifo_drop), + GBENU_STATS_P4(rx_port_mask_drop), + GBENU_STATS_P4(rx_top_fifo_drop), + GBENU_STATS_P4(ale_rate_limit_drop), + GBENU_STATS_P4(ale_vid_ingress_drop), + GBENU_STATS_P4(ale_da_eq_sa_drop), + GBENU_STATS_P4(ale_unknown_ucast), + GBENU_STATS_P4(ale_unknown_ucast_bytes), + GBENU_STATS_P4(ale_unknown_mcast), + GBENU_STATS_P4(ale_unknown_mcast_bytes), + GBENU_STATS_P4(ale_unknown_bcast), + GBENU_STATS_P4(ale_unknown_bcast_bytes), + GBENU_STATS_P4(tx_mem_protect_err), + /* GBENU Module 5 */ + GBENU_STATS_P5(rx_good_frames), + GBENU_STATS_P5(rx_broadcast_frames), + GBENU_STATS_P5(rx_multicast_frames), + GBENU_STATS_P5(rx_pause_frames), + GBENU_STATS_P5(rx_crc_errors), + GBENU_STATS_P5(rx_align_code_errors), + GBENU_STATS_P5(rx_oversized_frames), + GBENU_STATS_P5(rx_jabber_frames), + GBENU_STATS_P5(rx_undersized_frames), + GBENU_STATS_P5(rx_fragments), + GBENU_STATS_P5(ale_drop), + GBENU_STATS_P5(ale_overrun_drop), + GBENU_STATS_P5(rx_bytes), + GBENU_STATS_P5(tx_good_frames), + GBENU_STATS_P5(tx_broadcast_frames), + GBENU_STATS_P5(tx_multicast_frames), + GBENU_STATS_P5(tx_pause_frames), + GBENU_STATS_P5(tx_deferred_frames), + GBENU_STATS_P5(tx_collision_frames), + GBENU_STATS_P5(tx_single_coll_frames), + GBENU_STATS_P5(tx_mult_coll_frames), + GBENU_STATS_P5(tx_excessive_collisions), + GBENU_STATS_P5(tx_late_collisions), + GBENU_STATS_P5(rx_ipg_error), + GBENU_STATS_P5(tx_carrier_sense_errors), + GBENU_STATS_P5(tx_bytes), + GBENU_STATS_P5(tx_64B_frames), + GBENU_STATS_P5(tx_65_to_127B_frames), + GBENU_STATS_P5(tx_128_to_255B_frames), + GBENU_STATS_P5(tx_256_to_511B_frames), + GBENU_STATS_P5(tx_512_to_1023B_frames), + GBENU_STATS_P5(tx_1024B_frames), + GBENU_STATS_P5(net_bytes), + GBENU_STATS_P5(rx_bottom_fifo_drop), + GBENU_STATS_P5(rx_port_mask_drop), + GBENU_STATS_P5(rx_top_fifo_drop), + GBENU_STATS_P5(ale_rate_limit_drop), + GBENU_STATS_P5(ale_vid_ingress_drop), + GBENU_STATS_P5(ale_da_eq_sa_drop), + GBENU_STATS_P5(ale_unknown_ucast), + GBENU_STATS_P5(ale_unknown_ucast_bytes), + GBENU_STATS_P5(ale_unknown_mcast), + GBENU_STATS_P5(ale_unknown_mcast_bytes), + GBENU_STATS_P5(ale_unknown_bcast), + GBENU_STATS_P5(ale_unknown_bcast_bytes), + GBENU_STATS_P5(tx_mem_protect_err), + /* GBENU Module 6 */ + GBENU_STATS_P6(rx_good_frames), + GBENU_STATS_P6(rx_broadcast_frames), + GBENU_STATS_P6(rx_multicast_frames), + GBENU_STATS_P6(rx_pause_frames), + GBENU_STATS_P6(rx_crc_errors), + GBENU_STATS_P6(rx_align_code_errors), + GBENU_STATS_P6(rx_oversized_frames), + GBENU_STATS_P6(rx_jabber_frames), + GBENU_STATS_P6(rx_undersized_frames), + GBENU_STATS_P6(rx_fragments), + GBENU_STATS_P6(ale_drop), + GBENU_STATS_P6(ale_overrun_drop), + GBENU_STATS_P6(rx_bytes), + GBENU_STATS_P6(tx_good_frames), + GBENU_STATS_P6(tx_broadcast_frames), + GBENU_STATS_P6(tx_multicast_frames), + GBENU_STATS_P6(tx_pause_frames), + GBENU_STATS_P6(tx_deferred_frames), + GBENU_STATS_P6(tx_collision_frames), + GBENU_STATS_P6(tx_single_coll_frames), + GBENU_STATS_P6(tx_mult_coll_frames), + GBENU_STATS_P6(tx_excessive_collisions), + GBENU_STATS_P6(tx_late_collisions), + GBENU_STATS_P6(rx_ipg_error), + GBENU_STATS_P6(tx_carrier_sense_errors), + GBENU_STATS_P6(tx_bytes), + GBENU_STATS_P6(tx_64B_frames), + GBENU_STATS_P6(tx_65_to_127B_frames), + GBENU_STATS_P6(tx_128_to_255B_frames), + GBENU_STATS_P6(tx_256_to_511B_frames), + GBENU_STATS_P6(tx_512_to_1023B_frames), + GBENU_STATS_P6(tx_1024B_frames), + GBENU_STATS_P6(net_bytes), + GBENU_STATS_P6(rx_bottom_fifo_drop), + GBENU_STATS_P6(rx_port_mask_drop), + GBENU_STATS_P6(rx_top_fifo_drop), + GBENU_STATS_P6(ale_rate_limit_drop), + GBENU_STATS_P6(ale_vid_ingress_drop), + GBENU_STATS_P6(ale_da_eq_sa_drop), + GBENU_STATS_P6(ale_unknown_ucast), + GBENU_STATS_P6(ale_unknown_ucast_bytes), + GBENU_STATS_P6(ale_unknown_mcast), + GBENU_STATS_P6(ale_unknown_mcast_bytes), + GBENU_STATS_P6(ale_unknown_bcast), + GBENU_STATS_P6(ale_unknown_bcast_bytes), + GBENU_STATS_P6(tx_mem_protect_err), + /* GBENU Module 7 */ + GBENU_STATS_P7(rx_good_frames), + GBENU_STATS_P7(rx_broadcast_frames), + GBENU_STATS_P7(rx_multicast_frames), + GBENU_STATS_P7(rx_pause_frames), + GBENU_STATS_P7(rx_crc_errors), + GBENU_STATS_P7(rx_align_code_errors), + GBENU_STATS_P7(rx_oversized_frames), + GBENU_STATS_P7(rx_jabber_frames), + GBENU_STATS_P7(rx_undersized_frames), + GBENU_STATS_P7(rx_fragments), + GBENU_STATS_P7(ale_drop), + GBENU_STATS_P7(ale_overrun_drop), + GBENU_STATS_P7(rx_bytes), + GBENU_STATS_P7(tx_good_frames), + GBENU_STATS_P7(tx_broadcast_frames), + GBENU_STATS_P7(tx_multicast_frames), + GBENU_STATS_P7(tx_pause_frames), + GBENU_STATS_P7(tx_deferred_frames), + GBENU_STATS_P7(tx_collision_frames), + GBENU_STATS_P7(tx_single_coll_frames), + GBENU_STATS_P7(tx_mult_coll_frames), + GBENU_STATS_P7(tx_excessive_collisions), + GBENU_STATS_P7(tx_late_collisions), + GBENU_STATS_P7(rx_ipg_error), + GBENU_STATS_P7(tx_carrier_sense_errors), + GBENU_STATS_P7(tx_bytes), + GBENU_STATS_P7(tx_64B_frames), + GBENU_STATS_P7(tx_65_to_127B_frames), + GBENU_STATS_P7(tx_128_to_255B_frames), + GBENU_STATS_P7(tx_256_to_511B_frames), + GBENU_STATS_P7(tx_512_to_1023B_frames), + GBENU_STATS_P7(tx_1024B_frames), + GBENU_STATS_P7(net_bytes), + GBENU_STATS_P7(rx_bottom_fifo_drop), + GBENU_STATS_P7(rx_port_mask_drop), + GBENU_STATS_P7(rx_top_fifo_drop), + GBENU_STATS_P7(ale_rate_limit_drop), + GBENU_STATS_P7(ale_vid_ingress_drop), + GBENU_STATS_P7(ale_da_eq_sa_drop), + GBENU_STATS_P7(ale_unknown_ucast), + GBENU_STATS_P7(ale_unknown_ucast_bytes), + GBENU_STATS_P7(ale_unknown_mcast), + GBENU_STATS_P7(ale_unknown_mcast_bytes), + GBENU_STATS_P7(ale_unknown_bcast), + GBENU_STATS_P7(ale_unknown_bcast_bytes), + GBENU_STATS_P7(tx_mem_protect_err), + /* GBENU Module 8 */ + GBENU_STATS_P8(rx_good_frames), + GBENU_STATS_P8(rx_broadcast_frames), + GBENU_STATS_P8(rx_multicast_frames), + GBENU_STATS_P8(rx_pause_frames), + GBENU_STATS_P8(rx_crc_errors), + GBENU_STATS_P8(rx_align_code_errors), + GBENU_STATS_P8(rx_oversized_frames), + GBENU_STATS_P8(rx_jabber_frames), + GBENU_STATS_P8(rx_undersized_frames), + GBENU_STATS_P8(rx_fragments), + GBENU_STATS_P8(ale_drop), + GBENU_STATS_P8(ale_overrun_drop), + GBENU_STATS_P8(rx_bytes), + GBENU_STATS_P8(tx_good_frames), + GBENU_STATS_P8(tx_broadcast_frames), + GBENU_STATS_P8(tx_multicast_frames), + GBENU_STATS_P8(tx_pause_frames), + GBENU_STATS_P8(tx_deferred_frames), + GBENU_STATS_P8(tx_collision_frames), + GBENU_STATS_P8(tx_single_coll_frames), + GBENU_STATS_P8(tx_mult_coll_frames), + GBENU_STATS_P8(tx_excessive_collisions), + GBENU_STATS_P8(tx_late_collisions), + GBENU_STATS_P8(rx_ipg_error), + GBENU_STATS_P8(tx_carrier_sense_errors), + GBENU_STATS_P8(tx_bytes), + GBENU_STATS_P8(tx_64B_frames), + GBENU_STATS_P8(tx_65_to_127B_frames), + GBENU_STATS_P8(tx_128_to_255B_frames), + GBENU_STATS_P8(tx_256_to_511B_frames), + GBENU_STATS_P8(tx_512_to_1023B_frames), + GBENU_STATS_P8(tx_1024B_frames), + GBENU_STATS_P8(net_bytes), + GBENU_STATS_P8(rx_bottom_fifo_drop), + GBENU_STATS_P8(rx_port_mask_drop), + GBENU_STATS_P8(rx_top_fifo_drop), + GBENU_STATS_P8(ale_rate_limit_drop), + GBENU_STATS_P8(ale_vid_ingress_drop), + GBENU_STATS_P8(ale_da_eq_sa_drop), + GBENU_STATS_P8(ale_unknown_ucast), + GBENU_STATS_P8(ale_unknown_ucast_bytes), + GBENU_STATS_P8(ale_unknown_mcast), + GBENU_STATS_P8(ale_unknown_mcast_bytes), + GBENU_STATS_P8(ale_unknown_bcast), + GBENU_STATS_P8(ale_unknown_bcast_bytes), + GBENU_STATS_P8(tx_mem_protect_err), +}; + #define XGBE_STATS0_INFO(field) \ { \ "GBE_0:"#field, XGBE_STATS0_MODULE, \ @@ -1094,9 +1796,16 @@ static void netcp_ethss_update_link_state(struct gbe_priv *gbe_dev, if (!slave->open) return; - if (!SLAVE_LINK_IS_XGMII(slave)) - sgmii_link_state = netcp_sgmii_get_port_link(SGMII_BASE(sp), - sp); + if (!SLAVE_LINK_IS_XGMII(slave)) { + if (gbe_dev->ss_version == GBE_SS_VERSION_14) + sgmii_link_state = + netcp_sgmii_get_port_link(SGMII_BASE(sp), sp); + else + sgmii_link_state = + netcp_sgmii_get_port_link( + gbe_dev->sgmii_port_regs, sp); + } + phy_link_state = gbe_phy_link_status(slave); link_state = phy_link_state & sgmii_link_state; @@ -1165,6 +1874,7 @@ static int gbe_port_reset(struct gbe_slave *slave) static void gbe_port_config(struct gbe_priv *gbe_dev, struct gbe_slave *slave, int max_rx_len) { + void __iomem *rx_maxlen_reg; u32 xgmii_mode; if (max_rx_len > NETCP_MAX_FRAME_SIZE) @@ -1178,7 +1888,12 @@ static void gbe_port_config(struct gbe_priv *gbe_dev, struct gbe_slave *slave, writel(xgmii_mode, GBE_REG_ADDR(gbe_dev, ss_regs, control)); } - writel(max_rx_len, GBE_REG_ADDR(slave, emac_regs, rx_maxlen)); + if (IS_SS_ID_MU(gbe_dev)) + rx_maxlen_reg = GBE_REG_ADDR(slave, port_regs, rx_maxlen); + else + rx_maxlen_reg = GBE_REG_ADDR(slave, emac_regs, rx_maxlen); + + writel(max_rx_len, rx_maxlen_reg); writel(slave->mac_control, GBE_REG_ADDR(slave, emac_regs, mac_control)); } @@ -1270,6 +1985,12 @@ static int gbe_slave_open(struct gbe_intf *gbe_intf) static void gbe_init_host_port(struct gbe_priv *priv) { int bypass_en = 1; + + /* Host Tx Pri */ + if (IS_SS_ID_NU(priv)) + writel(HOST_TX_PRI_MAP_DEFAULT, + GBE_REG_ADDR(priv, host_port_regs, tx_pri_map)); + /* Max length register */ writel(NETCP_MAX_FRAME_SIZE, GBE_REG_ADDR(priv, host_port_regs, rx_maxlen)); @@ -1500,8 +2221,8 @@ static int gbe_open(void *intf_priv, struct net_device *ndev) GBE_MAJOR_VERSION(reg), GBE_MINOR_VERSION(reg), GBE_RTL_VERSION(reg), GBE_IDENT(reg)); - /* For 10G use directed to port */ - if (gbe_dev->ss_version == XGBE_SS_VERSION_10) + /* For 10G and on NetCP 1.5, use directed to port */ + if ((gbe_dev->ss_version == XGBE_SS_VERSION_10) || IS_SS_ID_MU(gbe_dev)) gbe_intf->tx_pipe.flags = SWITCH_TO_PORT_IN_TAGINFO; if (gbe_dev->enable_ale) @@ -1525,8 +2246,8 @@ static int gbe_open(void *intf_priv, struct net_device *ndev) writel(GBE_CTL_P0_ENABLE, GBE_REG_ADDR(gbe_dev, switch_regs, control)); /* All statistics enabled and STAT AB visible by default */ - writel(GBE_REG_VAL_STAT_ENABLE_ALL, GBE_REG_ADDR(gbe_dev, switch_regs, - stat_port_en)); + writel(gbe_dev->stats_en_mask, GBE_REG_ADDR(gbe_dev, switch_regs, + stat_port_en)); ret = gbe_slave_open(gbe_intf); if (ret) @@ -1563,6 +2284,7 @@ static int init_slave(struct gbe_priv *gbe_dev, struct gbe_slave *slave, { int port_reg_num; u32 port_reg_ofs, emac_reg_ofs; + u32 port_reg_blk_sz, emac_reg_blk_sz; if (of_property_read_u32(node, "slave-port", &slave->slave_num)) { dev_err(gbe_dev->dev, "missing slave-port parameter\n"); @@ -1594,23 +2316,29 @@ static int init_slave(struct gbe_priv *gbe_dev, struct gbe_slave *slave, } else { port_reg_ofs = GBE13_SLAVE_PORT_OFFSET; } + emac_reg_ofs = GBE13_EMAC_OFFSET; + port_reg_blk_sz = 0x30; + emac_reg_blk_sz = 0x40; + } else if (IS_SS_ID_MU(gbe_dev)) { + port_reg_ofs = GBENU_SLAVE_PORT_OFFSET; + emac_reg_ofs = GBENU_EMAC_OFFSET; + port_reg_blk_sz = 0x1000; + emac_reg_blk_sz = 0x1000; } else if (gbe_dev->ss_version == XGBE_SS_VERSION_10) { port_reg_ofs = XGBE10_SLAVE_PORT_OFFSET; + emac_reg_ofs = XGBE10_EMAC_OFFSET; + port_reg_blk_sz = 0x30; + emac_reg_blk_sz = 0x40; } else { dev_err(gbe_dev->dev, "unknown ethss(0x%x)\n", gbe_dev->ss_version); return -EINVAL; } - if (gbe_dev->ss_version == GBE_SS_VERSION_14) - emac_reg_ofs = GBE13_EMAC_OFFSET; - else if (gbe_dev->ss_version == XGBE_SS_VERSION_10) - emac_reg_ofs = XGBE10_EMAC_OFFSET; - slave->port_regs = gbe_dev->switch_regs + port_reg_ofs + - (0x30 * port_reg_num); + (port_reg_blk_sz * port_reg_num); slave->emac_regs = gbe_dev->switch_regs + emac_reg_ofs + - (0x40 * slave->slave_num); + (emac_reg_blk_sz * slave->slave_num); if (gbe_dev->ss_version == GBE_SS_VERSION_14) { /* Initialize slave port register offsets */ @@ -1629,6 +2357,23 @@ static int init_slave(struct gbe_priv *gbe_dev, struct gbe_slave *slave, GBE_SET_REG_OFS(slave, emac_regs, soft_reset); GBE_SET_REG_OFS(slave, emac_regs, rx_maxlen); + } else if (IS_SS_ID_MU(gbe_dev)) { + /* Initialize slave port register offsets */ + GBENU_SET_REG_OFS(slave, port_regs, port_vlan); + GBENU_SET_REG_OFS(slave, port_regs, tx_pri_map); + GBENU_SET_REG_OFS(slave, port_regs, sa_lo); + GBENU_SET_REG_OFS(slave, port_regs, sa_hi); + GBENU_SET_REG_OFS(slave, port_regs, ts_ctl); + GBENU_SET_REG_OFS(slave, port_regs, ts_seq_ltype); + GBENU_SET_REG_OFS(slave, port_regs, ts_vlan); + GBENU_SET_REG_OFS(slave, port_regs, ts_ctl_ltype2); + GBENU_SET_REG_OFS(slave, port_regs, ts_ctl2); + GBENU_SET_REG_OFS(slave, port_regs, rx_maxlen); + + /* Initialize EMAC register offsets */ + GBENU_SET_REG_OFS(slave, emac_regs, mac_control); + GBENU_SET_REG_OFS(slave, emac_regs, soft_reset); + } else if (gbe_dev->ss_version == XGBE_SS_VERSION_10) { /* Initialize slave port register offsets */ XGBE_SET_REG_OFS(slave, port_regs, port_vlan); @@ -1688,6 +2433,8 @@ static void init_secondary_ports(struct gbe_priv *gbe_dev, mac_phy_link = true; slave->open = true; + if (gbe_dev->num_slaves >= gbe_dev->max_num_slaves) + break; } /* of_phy_connect() is needed only for MAC-PHY interface */ @@ -1758,7 +2505,7 @@ static int set_xgbe_ethss10_priv(struct gbe_priv *gbe_dev, void __iomem *regs; int ret, i; - ret = of_address_to_resource(node, 0, &res); + ret = of_address_to_resource(node, XGBE_SS_REG_INDEX, &res); if (ret) { dev_err(gbe_dev->dev, "Can't xlate xgbe of node(%s) ss address at %d\n", @@ -1804,9 +2551,9 @@ static int set_xgbe_ethss10_priv(struct gbe_priv *gbe_dev, gbe_dev->xgbe_serdes_regs = regs; gbe_dev->hw_stats = devm_kzalloc(gbe_dev->dev, - XGBE10_NUM_STAT_ENTRIES * - (XGBE10_NUM_SLAVES + 1) * sizeof(u64), - GFP_KERNEL); + XGBE10_NUM_STAT_ENTRIES * + (gbe_dev->max_num_ports) * sizeof(u64), + GFP_KERNEL); if (!gbe_dev->hw_stats) { dev_err(gbe_dev->dev, "hw_stats memory allocation failed\n"); return -ENOMEM; @@ -1817,16 +2564,17 @@ static int set_xgbe_ethss10_priv(struct gbe_priv *gbe_dev, XGBE10_SGMII_MODULE_OFFSET; gbe_dev->host_port_regs = gbe_dev->ss_regs + XGBE10_HOST_PORT_OFFSET; - for (i = 0; i < XGBE10_NUM_HW_STATS_MOD; i++) + for (i = 0; i < gbe_dev->max_num_ports; i++) gbe_dev->hw_stats_regs[i] = gbe_dev->switch_regs + XGBE10_HW_STATS_OFFSET + (GBE_HW_STATS_REG_MAP_SZ * i); - gbe_dev->ale_reg = gbe_dev->ss_regs + XGBE10_ALE_OFFSET; - gbe_dev->ale_ports = XGBE10_NUM_ALE_PORTS; + gbe_dev->ale_reg = gbe_dev->switch_regs + XGBE10_ALE_OFFSET; + gbe_dev->ale_ports = gbe_dev->max_num_ports; gbe_dev->host_port = XGBE10_HOST_PORT_NUM; gbe_dev->ale_entries = XGBE10_NUM_ALE_ENTRIES; gbe_dev->et_stats = xgbe10_et_stats; gbe_dev->num_et_stats = ARRAY_SIZE(xgbe10_et_stats); + gbe_dev->stats_en_mask = (1 << (gbe_dev->max_num_ports)) - 1; /* Subsystem registers */ XGBE_SET_REG_OFS(gbe_dev, ss_regs, id_ver); @@ -1912,7 +2660,7 @@ static int set_gbe_ethss14_priv(struct gbe_priv *gbe_dev, gbe_dev->hw_stats = devm_kzalloc(gbe_dev->dev, GBE13_NUM_HW_STAT_ENTRIES * - GBE13_NUM_SLAVES * sizeof(u64), + gbe_dev->max_num_slaves * sizeof(u64), GFP_KERNEL); if (!gbe_dev->hw_stats) { dev_err(gbe_dev->dev, "hw_stats memory allocation failed\n"); @@ -1922,18 +2670,19 @@ static int set_gbe_ethss14_priv(struct gbe_priv *gbe_dev, gbe_dev->sgmii_port_regs = gbe_dev->ss_regs + GBE13_SGMII_MODULE_OFFSET; gbe_dev->host_port_regs = gbe_dev->switch_regs + GBE13_HOST_PORT_OFFSET; - for (i = 0; i < GBE13_NUM_HW_STATS_MOD; i++) { + for (i = 0; i < gbe_dev->max_num_slaves; i++) { gbe_dev->hw_stats_regs[i] = gbe_dev->switch_regs + GBE13_HW_STATS_OFFSET + (GBE_HW_STATS_REG_MAP_SZ * i); } gbe_dev->ale_reg = gbe_dev->switch_regs + GBE13_ALE_OFFSET; - gbe_dev->ale_ports = GBE13_NUM_ALE_PORTS; + gbe_dev->ale_ports = gbe_dev->max_num_ports; gbe_dev->host_port = GBE13_HOST_PORT_NUM; gbe_dev->ale_entries = GBE13_NUM_ALE_ENTRIES; gbe_dev->et_stats = gbe13_et_stats; gbe_dev->num_et_stats = ARRAY_SIZE(gbe13_et_stats); + gbe_dev->stats_en_mask = GBE13_REG_VAL_STAT_ENABLE_ALL; /* Subsystem registers */ GBE_SET_REG_OFS(gbe_dev, ss_regs, id_ver); @@ -1952,6 +2701,80 @@ static int set_gbe_ethss14_priv(struct gbe_priv *gbe_dev, return 0; } +static int set_gbenu_ethss_priv(struct gbe_priv *gbe_dev, + struct device_node *node) +{ + struct resource res; + void __iomem *regs; + int i, ret; + + gbe_dev->hw_stats = devm_kzalloc(gbe_dev->dev, + GBENU_NUM_HW_STAT_ENTRIES * + (gbe_dev->max_num_ports) * sizeof(u64), + GFP_KERNEL); + if (!gbe_dev->hw_stats) { + dev_err(gbe_dev->dev, "hw_stats memory allocation failed\n"); + return -ENOMEM; + } + + ret = of_address_to_resource(node, GBENU_SM_REG_INDEX, &res); + if (ret) { + dev_err(gbe_dev->dev, + "Can't translate of gbenu node(%s) addr at index %d\n", + node->name, GBENU_SM_REG_INDEX); + return ret; + } + + regs = devm_ioremap_resource(gbe_dev->dev, &res); + if (IS_ERR(regs)) { + dev_err(gbe_dev->dev, + "Failed to map gbenu switch module register base\n"); + return PTR_ERR(regs); + } + gbe_dev->switch_regs = regs; + + gbe_dev->sgmii_port_regs = gbe_dev->ss_regs + GBENU_SGMII_MODULE_OFFSET; + gbe_dev->host_port_regs = gbe_dev->switch_regs + GBENU_HOST_PORT_OFFSET; + + for (i = 0; i < (gbe_dev->max_num_ports); i++) + gbe_dev->hw_stats_regs[i] = gbe_dev->switch_regs + + GBENU_HW_STATS_OFFSET + (GBENU_HW_STATS_REG_MAP_SZ * i); + + gbe_dev->ale_reg = gbe_dev->switch_regs + GBENU_ALE_OFFSET; + gbe_dev->ale_ports = gbe_dev->max_num_ports; + gbe_dev->host_port = GBENU_HOST_PORT_NUM; + gbe_dev->ale_entries = GBE13_NUM_ALE_ENTRIES; + gbe_dev->et_stats = gbenu_et_stats; + gbe_dev->stats_en_mask = (1 << (gbe_dev->max_num_ports)) - 1; + + if (IS_SS_ID_NU(gbe_dev)) + gbe_dev->num_et_stats = GBENU_ET_STATS_HOST_SIZE + + (gbe_dev->max_num_slaves * GBENU_ET_STATS_PORT_SIZE); + else + gbe_dev->num_et_stats = GBENU_ET_STATS_HOST_SIZE + + GBENU_ET_STATS_PORT_SIZE; + + /* Subsystem registers */ + GBENU_SET_REG_OFS(gbe_dev, ss_regs, id_ver); + + /* Switch module registers */ + GBENU_SET_REG_OFS(gbe_dev, switch_regs, id_ver); + GBENU_SET_REG_OFS(gbe_dev, switch_regs, control); + GBENU_SET_REG_OFS(gbe_dev, switch_regs, stat_port_en); + GBENU_SET_REG_OFS(gbe_dev, switch_regs, ptype); + + /* Host port registers */ + GBENU_SET_REG_OFS(gbe_dev, host_port_regs, port_vlan); + GBENU_SET_REG_OFS(gbe_dev, host_port_regs, rx_maxlen); + + /* For NU only. 2U does not need tx_pri_map. + * NU cppi port 0 tx pkt streaming interface has (n-1)*8 egress threads + * while 2U has only 1 such thread + */ + GBENU_SET_REG_OFS(gbe_dev, host_port_regs, tx_pri_map); + return 0; +} + static int gbe_probe(struct netcp_device *netcp_device, struct device *dev, struct device_node *node, void **inst_priv) { @@ -1971,6 +2794,21 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev, if (!gbe_dev) return -ENOMEM; + if (of_device_is_compatible(node, "ti,netcp-gbe-5") || + of_device_is_compatible(node, "ti,netcp-gbe")) { + gbe_dev->max_num_slaves = 4; + } else if (of_device_is_compatible(node, "ti,netcp-gbe-9")) { + gbe_dev->max_num_slaves = 8; + } else if (of_device_is_compatible(node, "ti,netcp-gbe-2")) { + gbe_dev->max_num_slaves = 1; + } else if (of_device_is_compatible(node, "ti,netcp-xgbe")) { + gbe_dev->max_num_slaves = 2; + } else { + dev_err(dev, "device tree node for unknown device\n"); + return -EINVAL; + } + gbe_dev->max_num_ports = gbe_dev->max_num_slaves + 1; + gbe_dev->dev = dev; gbe_dev->netcp_device = netcp_device; gbe_dev->rx_packet_max = NETCP_MAX_FRAME_SIZE; @@ -2006,7 +2844,15 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev, if (ret) goto quit; - ret = set_gbe_ethss14_priv(gbe_dev, node); + dev_dbg(dev, "ss_version: 0x%08x\n", gbe_dev->ss_version); + + if (gbe_dev->ss_version == GBE_SS_VERSION_14) + ret = set_gbe_ethss14_priv(gbe_dev, node); + else if (IS_SS_ID_MU(gbe_dev)) + ret = set_gbenu_ethss_priv(gbe_dev, node); + else + ret = -ENODEV; + if (ret) goto quit; } else if (!strcmp(node->name, "xgbe")) { @@ -2046,6 +2892,8 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev, continue; } gbe_dev->num_slaves++; + if (gbe_dev->num_slaves >= gbe_dev->max_num_slaves) + break; } if (!gbe_dev->num_slaves) @@ -2054,7 +2902,7 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev, /* Initialize Secondary slave ports */ secondary_ports = of_get_child_by_name(node, "secondary-slave-ports"); INIT_LIST_HEAD(&gbe_dev->secondary_slaves); - if (secondary_ports) + if (secondary_ports && (gbe_dev->num_slaves < gbe_dev->max_num_slaves)) init_secondary_ports(gbe_dev, secondary_ports); of_node_put(secondary_ports); -- cgit v1.2.3-59-g8ed1b From 68c581d5e7d834d8e97534cafd60bd6716ee6fbc Mon Sep 17 00:00:00 2001 From: Courtney Cavin Date: Fri, 20 Mar 2015 21:45:59 -0700 Subject: Input: add Qualcomm PM8941 power key driver Signed-off-by: Courtney Cavin Signed-off-by: Bjorn Andersson Tested-by: Ivan T. Ivanov Signed-off-by: Dmitry Torokhov --- .../bindings/input/qcom,pm8941-pwrkey.txt | 43 +++ drivers/input/misc/Kconfig | 12 + drivers/input/misc/Makefile | 1 + drivers/input/misc/pm8941-pwrkey.c | 293 +++++++++++++++++++++ 4 files changed, 349 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/qcom,pm8941-pwrkey.txt create mode 100644 drivers/input/misc/pm8941-pwrkey.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/input/qcom,pm8941-pwrkey.txt b/Documentation/devicetree/bindings/input/qcom,pm8941-pwrkey.txt new file mode 100644 index 000000000000..07bf55f6e0b9 --- /dev/null +++ b/Documentation/devicetree/bindings/input/qcom,pm8941-pwrkey.txt @@ -0,0 +1,43 @@ +Qualcomm PM8941 PMIC Power Key + +PROPERTIES + +- compatible: + Usage: required + Value type: + Definition: must be one of: + "qcom,pm8941-pwrkey" + +- reg: + Usage: required + Value type: + Definition: base address of registers for block + +- interrupts: + Usage: required + Value type: + Definition: key change interrupt; The format of the specifier is + defined by the binding document describing the node's + interrupt parent. + +- debounce: + Usage: optional + Value type: + Definition: time in microseconds that key must be pressed or released + for state change interrupt to trigger. + +- bias-pull-up: + Usage: optional + Value type: + Definition: presence of this property indicates that the KPDPWR_N pin + should be configured for pull up. + +EXAMPLE + + pwrkey@800 { + compatible = "qcom,pm8941-pwrkey"; + reg = <0x800>; + interrupts = <0x0 0x8 0 IRQ_TYPE_EDGE_BOTH>; + debounce = <15625>; + bias-pull-up; + }; diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index ef542f7ad944..4436ab1b9735 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -115,6 +115,18 @@ config INPUT_PCSPKR To compile this driver as a module, choose M here: the module will be called pcspkr. +config INPUT_PM8941_PWRKEY + tristate "Qualcomm PM8941 power key support" + depends on MFD_SPMI_PMIC + help + Say Y here if you want support for the power key usually found + on boards using a Qualcomm PM8941 compatible PMIC. + + If unsure, say Y. + + To compile this driver as a module, choose M here: the module + will be called pm8941-pwrkey. + config INPUT_PM8XXX_VIBRATOR tristate "Qualcomm PM8XXX vibrator support" depends on MFD_PM8XXX diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 75b58841d5a7..78ba4c1b8532 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -50,6 +50,7 @@ obj-$(CONFIG_INPUT_PCAP) += pcap_keys.o obj-$(CONFIG_INPUT_PCF50633_PMU) += pcf50633-input.o obj-$(CONFIG_INPUT_PCF8574) += pcf8574_keypad.o obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o +obj-$(CONFIG_INPUT_PM8941_PWRKEY) += pm8941-pwrkey.o obj-$(CONFIG_INPUT_PM8XXX_VIBRATOR) += pm8xxx-vibrator.o obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY) += pmic8xxx-pwrkey.o obj-$(CONFIG_INPUT_POWERMATE) += powermate.o diff --git a/drivers/input/misc/pm8941-pwrkey.c b/drivers/input/misc/pm8941-pwrkey.c new file mode 100644 index 000000000000..867db8a91372 --- /dev/null +++ b/drivers/input/misc/pm8941-pwrkey.c @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * Copyright (c) 2014, Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PON_REV2 0x01 + +#define PON_RT_STS 0x10 +#define PON_KPDPWR_N_SET BIT(0) + +#define PON_PS_HOLD_RST_CTL 0x5a +#define PON_PS_HOLD_RST_CTL2 0x5b +#define PON_PS_HOLD_ENABLE BIT(7) +#define PON_PS_HOLD_TYPE_MASK 0x0f +#define PON_PS_HOLD_TYPE_SHUTDOWN 4 +#define PON_PS_HOLD_TYPE_HARD_RESET 7 + +#define PON_PULL_CTL 0x70 +#define PON_KPDPWR_PULL_UP BIT(1) + +#define PON_DBC_CTL 0x71 +#define PON_DBC_DELAY_MASK 0x7 + + +struct pm8941_pwrkey { + struct device *dev; + int irq; + u32 baseaddr; + struct regmap *regmap; + struct input_dev *input; + + unsigned int revision; + struct notifier_block reboot_notifier; +}; + +static int pm8941_reboot_notify(struct notifier_block *nb, + unsigned long code, void *unused) +{ + struct pm8941_pwrkey *pwrkey = container_of(nb, struct pm8941_pwrkey, + reboot_notifier); + unsigned int enable_reg; + unsigned int reset_type; + int error; + + /* PMICs with revision 0 have the enable bit in same register as ctrl */ + if (pwrkey->revision == 0) + enable_reg = PON_PS_HOLD_RST_CTL; + else + enable_reg = PON_PS_HOLD_RST_CTL2; + + error = regmap_update_bits(pwrkey->regmap, + pwrkey->baseaddr + enable_reg, + PON_PS_HOLD_ENABLE, + 0); + if (error) + dev_err(pwrkey->dev, + "unable to clear ps hold reset enable: %d\n", + error); + + /* + * Updates of PON_PS_HOLD_ENABLE requires 3 sleep cycles between + * writes. + */ + usleep_range(100, 1000); + + switch (code) { + case SYS_HALT: + case SYS_POWER_OFF: + reset_type = PON_PS_HOLD_TYPE_SHUTDOWN; + break; + case SYS_RESTART: + default: + reset_type = PON_PS_HOLD_TYPE_HARD_RESET; + break; + }; + + error = regmap_update_bits(pwrkey->regmap, + pwrkey->baseaddr + PON_PS_HOLD_RST_CTL, + PON_PS_HOLD_TYPE_MASK, + reset_type); + if (error) + dev_err(pwrkey->dev, "unable to set ps hold reset type: %d\n", + error); + + error = regmap_update_bits(pwrkey->regmap, + pwrkey->baseaddr + enable_reg, + PON_PS_HOLD_ENABLE, + PON_PS_HOLD_ENABLE); + if (error) + dev_err(pwrkey->dev, "unable to re-set enable: %d\n", error); + + return NOTIFY_DONE; +} + +static irqreturn_t pm8941_pwrkey_irq(int irq, void *_data) +{ + struct pm8941_pwrkey *pwrkey = _data; + unsigned int sts; + int error; + + error = regmap_read(pwrkey->regmap, + pwrkey->baseaddr + PON_RT_STS, &sts); + if (error) + return IRQ_HANDLED; + + input_report_key(pwrkey->input, KEY_POWER, !!(sts & PON_KPDPWR_N_SET)); + input_sync(pwrkey->input); + + return IRQ_HANDLED; +} + +static int __maybe_unused pm8941_pwrkey_suspend(struct device *dev) +{ + struct pm8941_pwrkey *pwrkey = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + enable_irq_wake(pwrkey->irq); + + return 0; +} + +static int __maybe_unused pm8941_pwrkey_resume(struct device *dev) +{ + struct pm8941_pwrkey *pwrkey = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + disable_irq_wake(pwrkey->irq); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(pm8941_pwr_key_pm_ops, + pm8941_pwrkey_suspend, pm8941_pwrkey_resume); + +static int pm8941_pwrkey_probe(struct platform_device *pdev) +{ + struct pm8941_pwrkey *pwrkey; + bool pull_up; + u32 req_delay; + int error; + + if (of_property_read_u32(pdev->dev.of_node, "debounce", &req_delay)) + req_delay = 15625; + + if (req_delay > 2000000 || req_delay == 0) { + dev_err(&pdev->dev, "invalid debounce time: %u\n", req_delay); + return -EINVAL; + } + + pull_up = of_property_read_bool(pdev->dev.of_node, "bias-pull-up"); + + pwrkey = devm_kzalloc(&pdev->dev, sizeof(*pwrkey), GFP_KERNEL); + if (!pwrkey) + return -ENOMEM; + + pwrkey->dev = &pdev->dev; + + pwrkey->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!pwrkey->regmap) { + dev_err(&pdev->dev, "failed to locate regmap\n"); + return -ENODEV; + } + + pwrkey->irq = platform_get_irq(pdev, 0); + if (pwrkey->irq < 0) { + dev_err(&pdev->dev, "failed to get irq\n"); + return pwrkey->irq; + } + + error = of_property_read_u32(pdev->dev.of_node, "reg", + &pwrkey->baseaddr); + if (error) + return error; + + error = regmap_read(pwrkey->regmap, pwrkey->baseaddr + PON_REV2, + &pwrkey->revision); + if (error) { + dev_err(&pdev->dev, "failed to set debounce: %d\n", error); + return error; + } + + pwrkey->input = devm_input_allocate_device(&pdev->dev); + if (!pwrkey->input) { + dev_dbg(&pdev->dev, "unable to allocate input device\n"); + return -ENOMEM; + } + + input_set_capability(pwrkey->input, EV_KEY, KEY_POWER); + + pwrkey->input->name = "pm8941_pwrkey"; + pwrkey->input->phys = "pm8941_pwrkey/input0"; + + req_delay = (req_delay << 6) / USEC_PER_SEC; + req_delay = ilog2(req_delay); + + error = regmap_update_bits(pwrkey->regmap, + pwrkey->baseaddr + PON_DBC_CTL, + PON_DBC_DELAY_MASK, + req_delay); + if (error) { + dev_err(&pdev->dev, "failed to set debounce: %d\n", error); + return error; + } + + error = regmap_update_bits(pwrkey->regmap, + pwrkey->baseaddr + PON_PULL_CTL, + PON_KPDPWR_PULL_UP, + pull_up ? PON_KPDPWR_PULL_UP : 0); + if (error) { + dev_err(&pdev->dev, "failed to set pull: %d\n", error); + return error; + } + + error = devm_request_threaded_irq(&pdev->dev, pwrkey->irq, + NULL, pm8941_pwrkey_irq, + IRQF_ONESHOT, + "pm8941_pwrkey", pwrkey); + if (error) { + dev_err(&pdev->dev, "failed requesting IRQ: %d\n", error); + return error; + } + + error = input_register_device(pwrkey->input); + if (error) { + dev_err(&pdev->dev, "failed to register input device: %d\n", + error); + return error; + } + + pwrkey->reboot_notifier.notifier_call = pm8941_reboot_notify, + error = register_reboot_notifier(&pwrkey->reboot_notifier); + if (error) { + dev_err(&pdev->dev, "failed to register reboot notifier: %d\n", + error); + return error; + } + + platform_set_drvdata(pdev, pwrkey); + device_init_wakeup(&pdev->dev, 1); + + return 0; +} + +static int pm8941_pwrkey_remove(struct platform_device *pdev) +{ + struct pm8941_pwrkey *pwrkey = platform_get_drvdata(pdev); + + device_init_wakeup(&pdev->dev, 0); + unregister_reboot_notifier(&pwrkey->reboot_notifier); + + return 0; +} + +static const struct of_device_id pm8941_pwr_key_id_table[] = { + { .compatible = "qcom,pm8941-pwrkey" }, + { } +}; +MODULE_DEVICE_TABLE(of, pm8941_pwr_key_id_table); + +static struct platform_driver pm8941_pwrkey_driver = { + .probe = pm8941_pwrkey_probe, + .remove = pm8941_pwrkey_remove, + .driver = { + .name = "pm8941-pwrkey", + .pm = &pm8941_pwr_key_pm_ops, + .of_match_table = of_match_ptr(pm8941_pwr_key_id_table), + }, +}; +module_platform_driver(pm8941_pwrkey_driver); + +MODULE_DESCRIPTION("PM8941 Power Key driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-59-g8ed1b From 3088ef9f5dec3d72b24dcdd33d240823ab26b432 Mon Sep 17 00:00:00 2001 From: Howard Mitchell Date: Thu, 19 Mar 2015 12:08:29 +0000 Subject: ALSA: ControlName.txt: Add 'Analogue' as a prefix for volume controls Currently 'Playback Volume' is the correct way to express an analogue volume control. However, this control name has initialisation defaults applied when using 'alsactl restore' and in some cases this is not appropriate. An example would be a control that has a selection of 0db and -6dB of gain that is intended to set the fullscale ouput voltage of a DAC. The TI pcm512x family of DAcs have such a control. In this case the device/driver reset defaults are preferred. Signed-off-by: Howard Mitchell Acked-by: Takashi Iwai Signed-off-by: Mark Brown --- Documentation/sound/alsa/ControlNames.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/ControlNames.txt b/Documentation/sound/alsa/ControlNames.txt index 79a6127863ca..3fc1cf50d28e 100644 --- a/Documentation/sound/alsa/ControlNames.txt +++ b/Documentation/sound/alsa/ControlNames.txt @@ -71,11 +71,11 @@ SOURCE: HDMI/DP (either HDMI or DisplayPort) Exceptions (deprecated): - [Digital] Capture Source - [Digital] Capture Switch (aka input gain switch) - [Digital] Capture Volume (aka input gain volume) - [Digital] Playback Switch (aka output gain switch) - [Digital] Playback Volume (aka output gain volume) + [Analogue|Digital] Capture Source + [Analogue|Digital] Capture Switch (aka input gain switch) + [Analogue|Digital] Capture Volume (aka input gain volume) + [Analogue|Digital] Playback Switch (aka output gain switch) + [Analogue|Digital] Playback Volume (aka output gain volume) Tone Control - Switch Tone Control - Bass Tone Control - Treble -- cgit v1.2.3-59-g8ed1b From 4a7a08226dd590a139e5f7835fe93f90b3beee90 Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Thu, 19 Mar 2015 13:16:46 +0200 Subject: i2c: add support for the Digicolor I2C controller The CX92755 is an SoC in the Conexant Digicolor series. The devicetree binding document describes the I2C controller on the CX92755 SoC, that is also shared by some other SoCs in the Digicolor series. The driver adds support. Signed-off-by: Baruch Siach [wsa: fixed spaces around operators] Signed-off-by: Wolfram Sang --- .../devicetree/bindings/i2c/i2c-digicolor.txt | 25 ++ drivers/i2c/busses/Kconfig | 9 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-digicolor.c | 385 +++++++++++++++++++++ 4 files changed, 420 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/i2c-digicolor.txt create mode 100644 drivers/i2c/busses/i2c-digicolor.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/i2c/i2c-digicolor.txt b/Documentation/devicetree/bindings/i2c/i2c-digicolor.txt new file mode 100644 index 000000000000..457a098d4f7e --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-digicolor.txt @@ -0,0 +1,25 @@ +Conexant Digicolor I2C controller + +Required properties: + - compatible: must be "cnxt,cx92755-i2c" + - reg: physical address and length of the device registers + - interrupts: a single interrupt specifier + - clocks: clock for the device + - #address-cells: should be <1> + - #size-cells: should be <0> + +Optional properties: +- clock-frequency: the desired I2C bus clock frequency in Hz; in + absence of this property the default value is used (100 kHz). + +Example: + + i2c: i2c@f0000120 { + compatible = "cnxt,cx92755-i2c"; + reg = <0xf0000120 0x10>; + interrupts = <28>; + clocks = <&main_clk>; + clock-frequency = <100000>; + #address-cells = <1>; + #size-cells = <0>; + }; diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 22da9c2ffa22..db09881614b7 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -485,6 +485,15 @@ config I2C_DESIGNWARE_BAYTRAIL the platform firmware controlling it. You should say Y if running on a BayTrail system using the AXP288. +config I2C_DIGICOLOR + tristate "Conexant Digicolor I2C driver" + depends on ARCH_DIGICOLOR + help + Support for Conexant Digicolor SoCs (CX92755) I2C controller driver. + + This driver can also be built as a module. If so, the module + will be called i2c-digicolor. + config I2C_EFM32 tristate "EFM32 I2C controller" depends on ARCH_EFM32 || COMPILE_TEST diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 3638feb6677e..4413f09996cb 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -45,6 +45,7 @@ i2c-designware-platform-objs := i2c-designware-platdrv.o i2c-designware-platform-$(CONFIG_I2C_DESIGNWARE_BAYTRAIL) += i2c-designware-baytrail.o obj-$(CONFIG_I2C_DESIGNWARE_PCI) += i2c-designware-pci.o i2c-designware-pci-objs := i2c-designware-pcidrv.o +obj-$(CONFIG_I2C_DIGICOLOR) += i2c-digicolor.o obj-$(CONFIG_I2C_EFM32) += i2c-efm32.o obj-$(CONFIG_I2C_EG20T) += i2c-eg20t.o obj-$(CONFIG_I2C_EXYNOS5) += i2c-exynos5.o diff --git a/drivers/i2c/busses/i2c-digicolor.c b/drivers/i2c/busses/i2c-digicolor.c new file mode 100644 index 000000000000..03f1e5549896 --- /dev/null +++ b/drivers/i2c/busses/i2c-digicolor.c @@ -0,0 +1,385 @@ +/* + * I2C bus driver for Conexant Digicolor SoCs + * + * Author: Baruch Siach + * + * Copyright (C) 2015 Paradox Innovation Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEFAULT_FREQ 100000 +#define TIMEOUT_MS 100 + +#define II_CONTROL 0x0 +#define II_CONTROL_LOCAL_RESET BIT(0) + +#define II_CLOCKTIME 0x1 + +#define II_COMMAND 0x2 +#define II_CMD_START 1 +#define II_CMD_RESTART 2 +#define II_CMD_SEND_ACK 3 +#define II_CMD_GET_ACK 6 +#define II_CMD_GET_NOACK 7 +#define II_CMD_STOP 10 +#define II_COMMAND_GO BIT(7) +#define II_COMMAND_COMPLETION_STATUS(r) (((r) >> 5) & 3) +#define II_CMD_STATUS_NORMAL 0 +#define II_CMD_STATUS_ACK_GOOD 1 +#define II_CMD_STATUS_ACK_BAD 2 +#define II_CMD_STATUS_ABORT 3 + +#define II_DATA 0x3 +#define II_INTFLAG_CLEAR 0x8 +#define II_INTENABLE 0xa + +struct dc_i2c { + struct i2c_adapter adap; + struct device *dev; + void __iomem *regs; + struct clk *clk; + unsigned int frequency; + + struct i2c_msg *msg; + unsigned int msgbuf_ptr; + int last; + spinlock_t lock; + struct completion done; + int state; + int error; +}; + +enum { + STATE_IDLE, + STATE_START, + STATE_ADDR, + STATE_WRITE, + STATE_READ, + STATE_STOP, +}; + +static void dc_i2c_cmd(struct dc_i2c *i2c, u8 cmd) +{ + writeb_relaxed(cmd | II_COMMAND_GO, i2c->regs + II_COMMAND); +} + +static u8 dc_i2c_addr_cmd(struct i2c_msg *msg) +{ + u8 addr = (msg->addr & 0x7f) << 1; + + if (msg->flags & I2C_M_RD) + addr |= 1; + + return addr; +} + +static void dc_i2c_data(struct dc_i2c *i2c, u8 data) +{ + writeb_relaxed(data, i2c->regs + II_DATA); +} + +static void dc_i2c_write_byte(struct dc_i2c *i2c, u8 byte) +{ + dc_i2c_data(i2c, byte); + dc_i2c_cmd(i2c, II_CMD_SEND_ACK); +} + +static void dc_i2c_write_buf(struct dc_i2c *i2c) +{ + dc_i2c_write_byte(i2c, i2c->msg->buf[i2c->msgbuf_ptr++]); +} + +static void dc_i2c_next_read(struct dc_i2c *i2c) +{ + bool last = (i2c->msgbuf_ptr + 1 == i2c->msg->len); + + dc_i2c_cmd(i2c, last ? II_CMD_GET_NOACK : II_CMD_GET_ACK); +} + +static void dc_i2c_stop(struct dc_i2c *i2c) +{ + i2c->state = STATE_STOP; + if (i2c->last) + dc_i2c_cmd(i2c, II_CMD_STOP); + else + complete(&i2c->done); +} + +static u8 dc_i2c_read_byte(struct dc_i2c *i2c) +{ + return readb_relaxed(i2c->regs + II_DATA); +} + +static void dc_i2c_read_buf(struct dc_i2c *i2c) +{ + i2c->msg->buf[i2c->msgbuf_ptr++] = dc_i2c_read_byte(i2c); + dc_i2c_next_read(i2c); +} + +static void dc_i2c_set_irq(struct dc_i2c *i2c, int enable) +{ + if (enable) + writeb_relaxed(1, i2c->regs + II_INTFLAG_CLEAR); + writeb_relaxed(!!enable, i2c->regs + II_INTENABLE); +} + +static int dc_i2c_cmd_status(struct dc_i2c *i2c) +{ + u8 cmd = readb_relaxed(i2c->regs + II_COMMAND); + + return II_COMMAND_COMPLETION_STATUS(cmd); +} + +static void dc_i2c_start_msg(struct dc_i2c *i2c, int first) +{ + struct i2c_msg *msg = i2c->msg; + + if (!(msg->flags & I2C_M_NOSTART)) { + i2c->state = STATE_START; + dc_i2c_cmd(i2c, first ? II_CMD_START : II_CMD_RESTART); + } else if (msg->flags & I2C_M_RD) { + i2c->state = STATE_READ; + dc_i2c_next_read(i2c); + } else { + i2c->state = STATE_WRITE; + dc_i2c_write_buf(i2c); + } +} + +static irqreturn_t dc_i2c_irq(int irq, void *dev_id) +{ + struct dc_i2c *i2c = dev_id; + int cmd_status = dc_i2c_cmd_status(i2c); + unsigned long flags; + u8 addr_cmd; + + writeb_relaxed(1, i2c->regs + II_INTFLAG_CLEAR); + + spin_lock_irqsave(&i2c->lock, flags); + + if (cmd_status == II_CMD_STATUS_ACK_BAD + || cmd_status == II_CMD_STATUS_ABORT) { + i2c->error = -EIO; + complete(&i2c->done); + goto out; + } + + switch (i2c->state) { + case STATE_START: + addr_cmd = dc_i2c_addr_cmd(i2c->msg); + dc_i2c_write_byte(i2c, addr_cmd); + i2c->state = STATE_ADDR; + break; + case STATE_ADDR: + if (i2c->msg->flags & I2C_M_RD) { + dc_i2c_next_read(i2c); + i2c->state = STATE_READ; + break; + } + i2c->state = STATE_WRITE; + /* fall through */ + case STATE_WRITE: + if (i2c->msgbuf_ptr < i2c->msg->len) + dc_i2c_write_buf(i2c); + else + dc_i2c_stop(i2c); + break; + case STATE_READ: + if (i2c->msgbuf_ptr < i2c->msg->len) + dc_i2c_read_buf(i2c); + else + dc_i2c_stop(i2c); + break; + case STATE_STOP: + i2c->state = STATE_IDLE; + complete(&i2c->done); + break; + } + +out: + spin_unlock_irqrestore(&i2c->lock, flags); + return IRQ_HANDLED; +} + +static int dc_i2c_xfer_msg(struct dc_i2c *i2c, struct i2c_msg *msg, int first, + int last) +{ + unsigned long timeout = msecs_to_jiffies(TIMEOUT_MS); + unsigned long flags; + + spin_lock_irqsave(&i2c->lock, flags); + i2c->msg = msg; + i2c->msgbuf_ptr = 0; + i2c->last = last; + i2c->error = 0; + + reinit_completion(&i2c->done); + dc_i2c_set_irq(i2c, 1); + dc_i2c_start_msg(i2c, first); + spin_unlock_irqrestore(&i2c->lock, flags); + + timeout = wait_for_completion_timeout(&i2c->done, timeout); + dc_i2c_set_irq(i2c, 0); + if (timeout == 0) { + i2c->state = STATE_IDLE; + return -ETIMEDOUT; + } + + if (i2c->error) + return i2c->error; + + return 0; +} + +static int dc_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +{ + struct dc_i2c *i2c = adap->algo_data; + int i, ret; + + for (i = 0; i < num; i++) { + ret = dc_i2c_xfer_msg(i2c, &msgs[i], i == 0, i == num - 1); + if (ret) + return ret; + } + + return num; +} + +static int dc_i2c_init_hw(struct dc_i2c *i2c) +{ + unsigned long clk_rate = clk_get_rate(i2c->clk); + unsigned int clocktime; + + writeb_relaxed(II_CONTROL_LOCAL_RESET, i2c->regs + II_CONTROL); + udelay(100); + writeb_relaxed(0, i2c->regs + II_CONTROL); + udelay(100); + + clocktime = DIV_ROUND_UP(clk_rate, 64 * i2c->frequency); + if (clocktime < 1 || clocktime > 0xff) { + dev_err(i2c->dev, "can't set bus speed of %u Hz\n", + i2c->frequency); + return -EINVAL; + } + writeb_relaxed(clocktime - 1, i2c->regs + II_CLOCKTIME); + + return 0; +} + +static u32 dc_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART; +} + +static const struct i2c_algorithm dc_i2c_algorithm = { + .master_xfer = dc_i2c_xfer, + .functionality = dc_i2c_func, +}; + +static int dc_i2c_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct dc_i2c *i2c; + struct resource *r; + int ret = 0, irq; + + i2c = devm_kzalloc(&pdev->dev, sizeof(struct dc_i2c), GFP_KERNEL); + if (!i2c) + return -ENOMEM; + + if (of_property_read_u32(pdev->dev.of_node, "clock-frequency", + &i2c->frequency)) + i2c->frequency = DEFAULT_FREQ; + + i2c->dev = &pdev->dev; + platform_set_drvdata(pdev, i2c); + + spin_lock_init(&i2c->lock); + init_completion(&i2c->done); + + i2c->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(i2c->clk)) + return PTR_ERR(i2c->clk); + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + i2c->regs = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(i2c->regs)) + return PTR_ERR(i2c->regs); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + ret = devm_request_irq(&pdev->dev, irq, dc_i2c_irq, 0, + dev_name(&pdev->dev), i2c); + if (ret < 0) + return ret; + + strlcpy(i2c->adap.name, "Conexant Digicolor I2C adapter", + sizeof(i2c->adap.name)); + i2c->adap.owner = THIS_MODULE; + i2c->adap.algo = &dc_i2c_algorithm; + i2c->adap.dev.parent = &pdev->dev; + i2c->adap.dev.of_node = np; + i2c->adap.algo_data = i2c; + + ret = dc_i2c_init_hw(i2c); + if (ret) + return ret; + + ret = clk_prepare_enable(i2c->clk); + if (ret < 0) + return ret; + + ret = i2c_add_adapter(&i2c->adap); + if (ret < 0) { + clk_unprepare(i2c->clk); + return ret; + } + + return 0; +} + +static int dc_i2c_remove(struct platform_device *pdev) +{ + struct dc_i2c *i2c = platform_get_drvdata(pdev); + + i2c_del_adapter(&i2c->adap); + clk_disable_unprepare(i2c->clk); + + return 0; +} + +static const struct of_device_id dc_i2c_match[] = { + { .compatible = "cnxt,cx92755-i2c" }, + { }, +}; + +static struct platform_driver dc_i2c_driver = { + .probe = dc_i2c_probe, + .remove = dc_i2c_remove, + .driver = { + .name = "digicolor-i2c", + .of_match_table = dc_i2c_match, + }, +}; +module_platform_driver(dc_i2c_driver); + +MODULE_AUTHOR("Baruch Siach "); +MODULE_DESCRIPTION("Conexant Digicolor I2C master driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-59-g8ed1b From 5593ce64d875d169a237e3818a4251948c901ce7 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 18 Mar 2015 19:55:57 +0100 Subject: irqchip: renesas-irqc: Add functional clock to bindings The external IRQ controller has a functional clock, which is used for power management. Document it. Fix a typo in the r8a73a4 SoC name while we're at it. Signed-off-by: Geert Uytterhoeven Reviewed-by: Simon Horman Link: https://lkml.kernel.org/r/1426704961-27322-4-git-send-email-geert+renesas@glider.be Signed-off-by: Jason Cooper --- .../devicetree/bindings/interrupt-controller/renesas,irqc.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.txt b/Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.txt index 1a88e62228e5..63633bdea7e4 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.txt @@ -4,7 +4,7 @@ Required properties: - compatible: has to be "renesas,irqc-", "renesas,irqc" as fallback. Examples with soctypes are: - - "renesas,irqc-r8a73a4" (R-Mobile AP6) + - "renesas,irqc-r8a73a4" (R-Mobile APE6) - "renesas,irqc-r8a7790" (R-Car H2) - "renesas,irqc-r8a7791" (R-Car M2-W) - "renesas,irqc-r8a7792" (R-Car V2H) @@ -12,6 +12,7 @@ Required properties: - "renesas,irqc-r8a7794" (R-Car E2) - #interrupt-cells: has to be <2>: an interrupt index and flags, as defined in interrupts.txt in this directory +- clocks: Must contain a reference to the functional clock. Optional properties: @@ -29,4 +30,5 @@ Example: <0 1 IRQ_TYPE_LEVEL_HIGH>, <0 2 IRQ_TYPE_LEVEL_HIGH>, <0 3 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp4_clks R8A7790_CLK_IRQC>; }; -- cgit v1.2.3-59-g8ed1b From 801131321a0c53052084c10144dc07a061229f3f Mon Sep 17 00:00:00 2001 From: Seungwon Jeon Date: Thu, 29 Jan 2015 08:11:57 +0530 Subject: mmc: dw_mmc: exynos: Support eMMC's HS400 mode Implements HS400 mode support for exynos host driver. This also include some updates as new mode is added. Signed-off-by: Seungwon Jeon Signed-off-by: Alim Akhtar [Alim: addressed review comments] Tested-by: Jaehoon Chung Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson --- .../devicetree/bindings/mmc/exynos-dw-mshc.txt | 7 + drivers/mmc/host/dw_mmc-exynos.c | 185 +++++++++++++++++---- drivers/mmc/host/dw_mmc-exynos.h | 19 ++- drivers/mmc/host/dw_mmc.c | 16 +- drivers/mmc/host/dw_mmc.h | 2 + 5 files changed, 195 insertions(+), 34 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt index ee4fc0576c7d..aad98442788b 100644 --- a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt +++ b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt @@ -36,6 +36,8 @@ Required Properties: in transmit mode and CIU clock phase shift value in receive mode for double data rate mode operation. Refer notes below for the order of the cells and the valid values. +* samsung,dw-mshc-hs400-timing: Specifies the value of CIU TX and RX clock phase + shift value for hs400 mode operation. Notes for the sdr-timing and ddr-timing values: @@ -50,6 +52,9 @@ Required Properties: - if CIU clock divider value is 0 (that is divide by 1), both tx and rx phase shift clocks should be 0. +* samsung,read-strobe-delay: RCLK (Data strobe) delay to control HS400 mode + (Latency value for delay line in Read path) + Required properties for a slot (Deprecated - Recommend to use one slot per host): * gpios: specifies a list of gpios used for command, clock and data bus. The @@ -82,5 +87,7 @@ Example: samsung,dw-mshc-ciu-div = <3>; samsung,dw-mshc-sdr-timing = <2 3>; samsung,dw-mshc-ddr-timing = <1 2>; + samsung,dw-mshc-hs400-timing = <0 2>; + samsung,read-strobe-delay = <90>; bus-width = <8>; }; diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c index fe32948c6114..0a56d766978f 100644 --- a/drivers/mmc/host/dw_mmc-exynos.c +++ b/drivers/mmc/host/dw_mmc-exynos.c @@ -40,7 +40,12 @@ struct dw_mci_exynos_priv_data { u8 ciu_div; u32 sdr_timing; u32 ddr_timing; + u32 hs400_timing; + u32 tuned_sample; u32 cur_speed; + u32 dqs_delay; + u32 saved_dqs_en; + u32 saved_strobe_ctrl; }; static struct dw_mci_exynos_compatible { @@ -71,6 +76,21 @@ static struct dw_mci_exynos_compatible { }, }; +static inline u8 dw_mci_exynos_get_ciu_div(struct dw_mci *host) +{ + struct dw_mci_exynos_priv_data *priv = host->priv; + + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4412) + return EXYNOS4412_FIXED_CIU_CLK_DIV; + else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4210) + return EXYNOS4210_FIXED_CIU_CLK_DIV; + else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) + return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL64)) + 1; + else + return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL)) + 1; +} + static int dw_mci_exynos_priv_init(struct dw_mci *host) { struct dw_mci_exynos_priv_data *priv = host->priv; @@ -85,6 +105,16 @@ static int dw_mci_exynos_priv_init(struct dw_mci *host) SDMMC_MPSCTRL_NON_SECURE_WRITE_BIT); } + if (priv->ctrl_type >= DW_MCI_TYPE_EXYNOS5420) { + priv->saved_strobe_ctrl = mci_readl(host, HS400_DLINE_CTRL); + priv->saved_dqs_en = mci_readl(host, HS400_DQS_EN); + priv->saved_dqs_en |= AXI_NON_BLOCKING_WR; + mci_writel(host, HS400_DQS_EN, priv->saved_dqs_en); + if (!priv->dqs_delay) + priv->dqs_delay = + DQS_CTRL_GET_RD_DELAY(priv->saved_strobe_ctrl); + } + return 0; } @@ -97,6 +127,26 @@ static int dw_mci_exynos_setup_clock(struct dw_mci *host) return 0; } +static void dw_mci_exynos_set_clksel_timing(struct dw_mci *host, u32 timing) +{ + struct dw_mci_exynos_priv_data *priv = host->priv; + u32 clksel; + + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) + clksel = mci_readl(host, CLKSEL64); + else + clksel = mci_readl(host, CLKSEL); + + clksel = (clksel & ~SDMMC_CLKSEL_TIMING_MASK) | timing; + + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) + mci_writel(host, CLKSEL64, clksel); + else + mci_writel(host, CLKSEL, clksel); +} + #ifdef CONFIG_PM_SLEEP static int dw_mci_exynos_suspend(struct device *dev) { @@ -172,30 +222,38 @@ static void dw_mci_exynos_prepare_command(struct dw_mci *host, u32 *cmdr) } } -static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios) +static void dw_mci_exynos_config_hs400(struct dw_mci *host, u32 timing) { struct dw_mci_exynos_priv_data *priv = host->priv; - unsigned int wanted = ios->clock; - unsigned long actual; - u8 div = priv->ciu_div + 1; + u32 dqs, strobe; - if (ios->timing == MMC_TIMING_MMC_DDR52) { - if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || - priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) - mci_writel(host, CLKSEL64, priv->ddr_timing); - else - mci_writel(host, CLKSEL, priv->ddr_timing); - /* Should be double rate for DDR mode */ - if (ios->bus_width == MMC_BUS_WIDTH_8) - wanted <<= 1; + /* + * Not supported to configure register + * related to HS400 + */ + if (priv->ctrl_type < DW_MCI_TYPE_EXYNOS5420) + return; + + dqs = priv->saved_dqs_en; + strobe = priv->saved_strobe_ctrl; + + if (timing == MMC_TIMING_MMC_HS400) { + dqs |= DATA_STROBE_EN; + strobe = DQS_CTRL_RD_DELAY(strobe, priv->dqs_delay); } else { - if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || - priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) - mci_writel(host, CLKSEL64, priv->sdr_timing); - else - mci_writel(host, CLKSEL, priv->sdr_timing); + dqs &= ~DATA_STROBE_EN; } + mci_writel(host, HS400_DQS_EN, dqs); + mci_writel(host, HS400_DLINE_CTRL, strobe); +} + +static void dw_mci_exynos_adjust_clock(struct dw_mci *host, unsigned int wanted) +{ + struct dw_mci_exynos_priv_data *priv = host->priv; + unsigned long actual; + u8 div; + int ret; /* * Don't care if wanted clock is zero or * ciu clock is unavailable @@ -207,17 +265,52 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios) if (wanted < EXYNOS_CCLKIN_MIN) wanted = EXYNOS_CCLKIN_MIN; - if (wanted != priv->cur_speed) { - int ret = clk_set_rate(host->ciu_clk, wanted * div); - if (ret) - dev_warn(host->dev, - "failed to set clk-rate %u error: %d\n", - wanted * div, ret); - actual = clk_get_rate(host->ciu_clk); - host->bus_hz = actual / div; - priv->cur_speed = wanted; - host->current_speed = 0; + if (wanted == priv->cur_speed) + return; + + div = dw_mci_exynos_get_ciu_div(host); + ret = clk_set_rate(host->ciu_clk, wanted * div); + if (ret) + dev_warn(host->dev, + "failed to set clk-rate %u error: %d\n", + wanted * div, ret); + actual = clk_get_rate(host->ciu_clk); + host->bus_hz = actual / div; + priv->cur_speed = wanted; + host->current_speed = 0; +} + +static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios) +{ + struct dw_mci_exynos_priv_data *priv = host->priv; + unsigned int wanted = ios->clock; + u32 timing = ios->timing, clksel; + + switch (timing) { + case MMC_TIMING_MMC_HS400: + /* Update tuned sample timing */ + clksel = SDMMC_CLKSEL_UP_SAMPLE( + priv->hs400_timing, priv->tuned_sample); + wanted <<= 1; + break; + case MMC_TIMING_MMC_DDR52: + clksel = priv->ddr_timing; + /* Should be double rate for DDR mode */ + if (ios->bus_width == MMC_BUS_WIDTH_8) + wanted <<= 1; + break; + default: + clksel = priv->sdr_timing; } + + /* Set clock timing for the requested speed mode*/ + dw_mci_exynos_set_clksel_timing(host, clksel); + + /* Configure setting for HS400 */ + dw_mci_exynos_config_hs400(host, timing); + + /* Configure clock rate */ + dw_mci_exynos_adjust_clock(host, wanted); } static int dw_mci_exynos_parse_dt(struct dw_mci *host) @@ -260,6 +353,16 @@ static int dw_mci_exynos_parse_dt(struct dw_mci *host) return ret; priv->ddr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], div); + + ret = of_property_read_u32_array(np, + "samsung,dw-mshc-hs400-timing", timing, 2); + if (!ret && of_property_read_u32(np, + "samsung,read-strobe-delay", &priv->dqs_delay)) + dev_dbg(host->dev, + "read-strobe-delay is not found, assuming usage of default value\n"); + + priv->hs400_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], + HS400_FIXED_CIU_CLK_DIV); host->priv = priv; return 0; } @@ -285,7 +388,7 @@ static inline void dw_mci_exynos_set_clksmpl(struct dw_mci *host, u8 sample) clksel = mci_readl(host, CLKSEL64); else clksel = mci_readl(host, CLKSEL); - clksel = (clksel & ~0x7) | SDMMC_CLKSEL_CCLK_SAMPLE(sample); + clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample); if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) mci_writel(host, CLKSEL64, clksel); @@ -304,13 +407,16 @@ static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host) clksel = mci_readl(host, CLKSEL64); else clksel = mci_readl(host, CLKSEL); + sample = (clksel + 1) & 0x7; - clksel = (clksel & ~0x7) | sample; + clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample); + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) mci_writel(host, CLKSEL64, clksel); else mci_writel(host, CLKSEL, clksel); + return sample; } @@ -343,6 +449,7 @@ out: static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot) { struct dw_mci *host = slot->host; + struct dw_mci_exynos_priv_data *priv = host->priv; struct mmc_host *mmc = slot->mmc; u8 start_smpl, smpl, candiates = 0; s8 found = -1; @@ -360,14 +467,27 @@ static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot) } while (start_smpl != smpl); found = dw_mci_exynos_get_best_clksmpl(candiates); - if (found >= 0) + if (found >= 0) { dw_mci_exynos_set_clksmpl(host, found); - else + priv->tuned_sample = found; + } else { ret = -EIO; + } return ret; } +int dw_mci_exynos_prepare_hs400_tuning(struct dw_mci *host, + struct mmc_ios *ios) +{ + struct dw_mci_exynos_priv_data *priv = host->priv; + + dw_mci_exynos_set_clksel_timing(host, priv->hs400_timing); + dw_mci_exynos_adjust_clock(host, (ios->clock) << 1); + + return 0; +} + /* Common capabilities of Exynos4/Exynos5 SoC */ static unsigned long exynos_dwmmc_caps[4] = { MMC_CAP_1_8V_DDR | MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23, @@ -384,6 +504,7 @@ static const struct dw_mci_drv_data exynos_drv_data = { .set_ios = dw_mci_exynos_set_ios, .parse_dt = dw_mci_exynos_parse_dt, .execute_tuning = dw_mci_exynos_execute_tuning, + .prepare_hs400_tuning = dw_mci_exynos_prepare_hs400_tuning, }; static const struct of_device_id dw_mci_exynos_match[] = { diff --git a/drivers/mmc/host/dw_mmc-exynos.h b/drivers/mmc/host/dw_mmc-exynos.h index 7872ce586b55..595c934e6166 100644 --- a/drivers/mmc/host/dw_mmc-exynos.h +++ b/drivers/mmc/host/dw_mmc-exynos.h @@ -12,20 +12,36 @@ #ifndef _DW_MMC_EXYNOS_H_ #define _DW_MMC_EXYNOS_H_ -/* Extended Register's Offset */ #define SDMMC_CLKSEL 0x09C #define SDMMC_CLKSEL64 0x0A8 +/* Extended Register's Offset */ +#define SDMMC_HS400_DQS_EN 0x180 +#define SDMMC_HS400_ASYNC_FIFO_CTRL 0x184 +#define SDMMC_HS400_DLINE_CTRL 0x188 + /* CLKSEL register defines */ #define SDMMC_CLKSEL_CCLK_SAMPLE(x) (((x) & 7) << 0) #define SDMMC_CLKSEL_CCLK_DRIVE(x) (((x) & 7) << 16) #define SDMMC_CLKSEL_CCLK_DIVIDER(x) (((x) & 7) << 24) #define SDMMC_CLKSEL_GET_DRV_WD3(x) (((x) >> 16) & 0x7) +#define SDMMC_CLKSEL_GET_DIV(x) (((x) >> 24) & 0x7) +#define SDMMC_CLKSEL_UP_SAMPLE(x, y) (((x) & ~SDMMC_CLKSEL_CCLK_SAMPLE(7)) |\ + SDMMC_CLKSEL_CCLK_SAMPLE(y)) #define SDMMC_CLKSEL_TIMING(x, y, z) (SDMMC_CLKSEL_CCLK_SAMPLE(x) | \ SDMMC_CLKSEL_CCLK_DRIVE(y) | \ SDMMC_CLKSEL_CCLK_DIVIDER(z)) +#define SDMMC_CLKSEL_TIMING_MASK SDMMC_CLKSEL_TIMING(0x7, 0x7, 0x7) #define SDMMC_CLKSEL_WAKEUP_INT BIT(11) +/* RCLK_EN register defines */ +#define DATA_STROBE_EN BIT(0) +#define AXI_NON_BLOCKING_WR BIT(7) + +/* DLINE_CTRL register defines */ +#define DQS_CTRL_RD_DELAY(x, y) (((x) & ~0x3FF) | ((y) & 0x3FF)) +#define DQS_CTRL_GET_RD_DELAY(x) ((x) & 0x3FF) + /* Protector Register */ #define SDMMC_EMMCP_BASE 0x1000 #define SDMMC_MPSECURITY (SDMMC_EMMCP_BASE + 0x0010) @@ -49,6 +65,7 @@ /* Fixed clock divider */ #define EXYNOS4210_FIXED_CIU_CLK_DIV 2 #define EXYNOS4412_FIXED_CIU_CLK_DIV 4 +#define HS400_FIXED_CIU_CLK_DIV 1 /* Minimal required clock frequency for cclkin, unit: HZ */ #define EXYNOS_CCLKIN_MIN 50000000 diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 4d2e3c2e1830..f30ef6921d08 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -1084,7 +1084,8 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) regs = mci_readl(slot->host, UHS_REG); /* DDR mode set */ - if (ios->timing == MMC_TIMING_MMC_DDR52) + if (ios->timing == MMC_TIMING_MMC_DDR52 || + ios->timing == MMC_TIMING_MMC_HS400) regs |= ((0x1 << slot->id) << 16); else regs &= ~((0x1 << slot->id) << 16); @@ -1323,6 +1324,18 @@ static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode) return err; } +int dw_mci_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct dw_mci_slot *slot = mmc_priv(mmc); + struct dw_mci *host = slot->host; + const struct dw_mci_drv_data *drv_data = host->drv_data; + + if (drv_data && drv_data->prepare_hs400_tuning) + return drv_data->prepare_hs400_tuning(host, ios); + + return 0; +} + static const struct mmc_host_ops dw_mci_ops = { .request = dw_mci_request, .pre_req = dw_mci_pre_req, @@ -1335,6 +1348,7 @@ static const struct mmc_host_ops dw_mci_ops = { .card_busy = dw_mci_card_busy, .start_signal_voltage_switch = dw_mci_switch_voltage, .init_card = dw_mci_init_card, + .prepare_hs400_tuning = dw_mci_prepare_hs400_tuning, }; static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq) diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 18c4afe683b8..d2398675fd35 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -271,5 +271,7 @@ struct dw_mci_drv_data { void (*set_ios)(struct dw_mci *host, struct mmc_ios *ios); int (*parse_dt)(struct dw_mci *host); int (*execute_tuning)(struct dw_mci_slot *slot); + int (*prepare_hs400_tuning)(struct dw_mci *host, + struct mmc_ios *ios); }; #endif /* _DW_MMC_H_ */ -- cgit v1.2.3-59-g8ed1b From 61fe2f80f82d7596c9046e90794e1675617c9a26 Mon Sep 17 00:00:00 2001 From: Scott Branden Date: Mon, 9 Feb 2015 16:06:31 -0800 Subject: mmc: sdhci-iproc: add device tree bindings Add device tree binding documentation for IPROC SDHCI driver. Acked-by: Ray Jui Signed-off-by: Corneliu Doban Signed-off-by: Scott Branden Signed-off-by: Ulf Hansson --- .../devicetree/bindings/mmc/brcm,sdhci-iproc.txt | 23 ++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 Documentation/devicetree/bindings/mmc/brcm,sdhci-iproc.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mmc/brcm,sdhci-iproc.txt b/Documentation/devicetree/bindings/mmc/brcm,sdhci-iproc.txt new file mode 100644 index 000000000000..72cc9cc95880 --- /dev/null +++ b/Documentation/devicetree/bindings/mmc/brcm,sdhci-iproc.txt @@ -0,0 +1,23 @@ +Broadcom IPROC SDHCI controller + +This file documents differences between the core properties described +by mmc.txt and the properties that represent the IPROC SDHCI controller. + +Required properties: +- compatible : Should be "brcm,sdhci-iproc-cygnus". +- clocks : The clock feeding the SDHCI controller. + +Optional properties: + - sdhci,auto-cmd12: specifies that controller should use auto CMD12. + +Example: + +sdhci0: sdhci@0x18041000 { + compatible = "brcm,sdhci-iproc-cygnus"; + reg = <0x18041000 0x100>; + interrupts = ; + clocks = <&lcpll0_clks BCM_CYGNUS_LCPLL0_SDIO_CLK>; + bus-width = <4>; + sdhci,auto-cmd12; + no-1-8-v; +}; -- cgit v1.2.3-59-g8ed1b From 4ed0e032c3cf27c6fabc154164d003c4e0ac4654 Mon Sep 17 00:00:00 2001 From: Jens Thiele Date: Mon, 23 Mar 2015 09:04:56 -0700 Subject: Input: sun4i-ts - allow controlling filter and sensitivity via DT This commit introduces two new optional device-tree properties: "tp-sensitive-adjust": adjust sensitivity of pen down detection "filter-type": select median and averaging filter The previous fixed defaults, didn't work well for the Olimex A13-LCD10TS (I have). Signed-off-by: Jens Thiele Reviewed-by: Hans de Goede Signed-off-by: Dmitry Torokhov --- .../devicetree/bindings/input/touchscreen/sun4i.txt | 19 +++++++++++++++++-- drivers/input/touchscreen/sun4i-ts.c | 20 ++++++++++++++++---- 2 files changed, 33 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/input/touchscreen/sun4i.txt b/Documentation/devicetree/bindings/input/touchscreen/sun4i.txt index d59d25281e9f..89abecd938cb 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/sun4i.txt +++ b/Documentation/devicetree/bindings/input/touchscreen/sun4i.txt @@ -9,8 +9,20 @@ Required properties: - #thermal-sensor-cells: shall be 0 Optional properties: - - allwinner,ts-attached: boolean indicating that an actual touchscreen is - attached to the controller + - allwinner,ts-attached : boolean indicating that an actual touchscreen + is attached to the controller + - allwinner,tp-sensitive-adjust : integer (4 bits) + adjust sensitivity of pen down detection + between 0 (least sensitive) and 15 + (defaults to 15) + - allwinner,filter-type : integer (2 bits) + select median and averaging filter + samples used for median / averaging filter + 0: 4/2 + 1: 5/3 + 2: 8/4 + 3: 16/8 + (defaults to 1) Example: @@ -20,4 +32,7 @@ Example: interrupts = <29>; allwinner,ts-attached; #thermal-sensor-cells = <0>; + /* sensitive/noisy touch panel */ + allwinner,tp-sensitive-adjust = <0>; + allwinner,filter-type = <3>; }; diff --git a/drivers/input/touchscreen/sun4i-ts.c b/drivers/input/touchscreen/sun4i-ts.c index 178d2efb8353..c0116994067d 100644 --- a/drivers/input/touchscreen/sun4i-ts.c +++ b/drivers/input/touchscreen/sun4i-ts.c @@ -30,6 +30,10 @@ * These kinds of heuristics are just asking for trouble (and don't belong * in the kernel). So this driver offers straight forward, reliable single * touch functionality only. + * + * s.a. A20 User Manual "1.15 TP" (Documentation/arm/sunxi/README) + * (looks like the description in the A20 User Manual v1.3 is better + * than the one in the A10 User Manual v.1.5) */ #include @@ -246,6 +250,8 @@ static int sun4i_ts_probe(struct platform_device *pdev) int error; u32 reg; bool ts_attached; + u32 tp_sensitive_adjust = 15; + u32 filter_type = 1; ts = devm_kzalloc(dev, sizeof(struct sun4i_ts_data), GFP_KERNEL); if (!ts) @@ -322,14 +328,20 @@ static int sun4i_ts_probe(struct platform_device *pdev) ts->base + TP_CTRL0); /* - * sensitive_adjust = 15 : max, which is not all that sensitive, + * tp_sensitive_adjust is an optional property * tp_mode = 0 : only x and y coordinates, as we don't use dual touch */ - writel(TP_SENSITIVE_ADJUST(15) | TP_MODE_SELECT(0), + of_property_read_u32(np, "allwinner,tp-sensitive-adjust", + &tp_sensitive_adjust); + writel(TP_SENSITIVE_ADJUST(tp_sensitive_adjust) | TP_MODE_SELECT(0), ts->base + TP_CTRL2); - /* Enable median filter, type 1 : 5/3 */ - writel(FILTER_EN(1) | FILTER_TYPE(1), ts->base + TP_CTRL3); + /* + * Enable median and averaging filter, optional property for + * filter type. + */ + of_property_read_u32(np, "allwinner,filter-type", &filter_type); + writel(FILTER_EN(1) | FILTER_TYPE(filter_type), ts->base + TP_CTRL3); /* Enable temperature measurement, period 1953 (2 seconds) */ writel(TEMP_ENABLE(1) | TEMP_PERIOD(1953), ts->base + TP_TPR); -- cgit v1.2.3-59-g8ed1b From d5ae685f15307c85c6267c5a2be9ba3d70eb3297 Mon Sep 17 00:00:00 2001 From: Jonathan Richardson Date: Sat, 21 Mar 2015 21:04:59 -0700 Subject: Input: add Broadcom iProc touchscreen driver Add initial version of the Broadcom touchscreen driver. Reviewed-by: Ray Jui Reviewed-by: Scott Branden Tested-by: Scott Branden Signed-off-by: Jonathan Richardson Signed-off-by: Dmitry Torokhov --- .../input/touchscreen/brcm,iproc-touchscreen.txt | 76 +++ drivers/input/touchscreen/Kconfig | 12 + drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/bcm_iproc_tsc.c | 522 +++++++++++++++++++++ 4 files changed, 611 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/touchscreen/brcm,iproc-touchscreen.txt create mode 100644 drivers/input/touchscreen/bcm_iproc_tsc.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/input/touchscreen/brcm,iproc-touchscreen.txt b/Documentation/devicetree/bindings/input/touchscreen/brcm,iproc-touchscreen.txt new file mode 100644 index 000000000000..34e3382a0659 --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/brcm,iproc-touchscreen.txt @@ -0,0 +1,76 @@ +* Broadcom's IPROC Touchscreen Controller + +Required properties: +- compatible: must be "brcm,iproc-touchscreen" +- reg: physical base address of the controller and length of memory mapped + region. +- clocks: The clock provided by the SOC to driver the tsc +- clock-name: name for the clock +- interrupts: The touchscreen controller's interrupt + +Optional properties: +- scanning_period: Time between scans. Each step is 1024 us. Valid 1-256. +- debounce_timeout: Each step is 512 us. Valid 0-255 +- settling_timeout: The settling duration (in ms) is the amount of time + the tsc waits to allow the voltage to settle after + turning on the drivers in detection mode. + Valid values: 0-11 + 0 = 0.008 ms + 1 = 0.01 ms + 2 = 0.02 ms + 3 = 0.04 ms + 4 = 0.08 ms + 5 = 0.16 ms + 6 = 0.32 ms + 7 = 0.64 ms + 8 = 1.28 ms + 9 = 2.56 ms + 10 = 5.12 ms + 11 = 10.24 ms +- touch_timeout: The continuous number of scan periods in which touch is + not detected before the controller returns to idle state. + Valid values 0-255. +- average_data: Number of data samples which are averaged before a final + data point is placed into the FIFO + Valid values 0-7 + 0 = 1 sample + 1 = 2 samples + 2 = 4 samples + 3 = 8 samples + 4 = 16 samples + 5 = 32 samples + 6 = 64 samples + 7 = 128 samples +- fifo_threshold: Interrupt is generated whenever the number of fifo + entries exceeds this value + Valid values 0-31 +- touchscreen-size-x: horizontal resolution of touchscreen (in pixels) +- touchscreen-size-y: vertical resolution of touchscreen (in pixels) +- touchscreen-fuzz-x: horizontal noise value of the absolute input + device (in pixels) +- touchscreen-fuzz-y: vertical noise value of the absolute input + device (in pixels) +- touchscreen-inverted-x: X axis is inverted (boolean) +- touchscreen-inverted-y: Y axis is inverted (boolean) + +Example: + + touchscreen: tsc@0x180A6000 { + compatible = "brcm,iproc-touchscreen"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x180A6000 0x40>; + clocks = <&adc_clk>; + clock-names = "tsc_clk"; + interrupts = ; + + scanning_period = <5>; + debounce_timeout = <40>; + settling_timeout = <7>; + touch_timeout = <10>; + average_data = <5>; + fifo_threshold = <1>; + /* Touchscreen is rotated 180 degrees. */ + touchscreen-inverted-x; + touchscreen-inverted-y; + }; diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 1130c4059104..a1cfe16e9a81 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -324,6 +324,18 @@ config TOUCHSCREEN_ILI210X To compile this driver as a module, choose M here: the module will be called ili210x. +config TOUCHSCREEN_IPROC + tristate "IPROC touch panel driver support" + depends on ARCH_BCM_IPROC || COMPILE_TEST + help + Say Y here if you want to add support for the IPROC touch + controller to your system. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called bcm_iproc_tsc. + config TOUCHSCREEN_S3C2410 tristate "Samsung S3C2410/generic touchscreen input driver" depends on ARCH_S3C24XX || SAMSUNG_DEV_TS diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index a06a752966fe..09c33531ab8e 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix.o obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o obj-$(CONFIG_TOUCHSCREEN_INTEL_MID) += intel-mid-touch.o +obj-$(CONFIG_TOUCHSCREEN_IPROC) += bcm_iproc_tsc.o obj-$(CONFIG_TOUCHSCREEN_LPC32XX) += lpc32xx_ts.o obj-$(CONFIG_TOUCHSCREEN_MAX11801) += max11801_ts.o obj-$(CONFIG_TOUCHSCREEN_MC13783) += mc13783_ts.o diff --git a/drivers/input/touchscreen/bcm_iproc_tsc.c b/drivers/input/touchscreen/bcm_iproc_tsc.c new file mode 100644 index 000000000000..ae460a5c93d5 --- /dev/null +++ b/drivers/input/touchscreen/bcm_iproc_tsc.c @@ -0,0 +1,522 @@ +/* +* Copyright (C) 2015 Broadcom Corporation +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation version 2. +* +* This program is distributed "as is" WITHOUT ANY WARRANTY of any +* kind, whether express or implied; without even the implied warranty +* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IPROC_TS_NAME "iproc-ts" + +#define PEN_DOWN_STATUS 1 +#define PEN_UP_STATUS 0 + +#define X_MIN 0 +#define Y_MIN 0 +#define X_MAX 0xFFF +#define Y_MAX 0xFFF + +/* Value given by controller for invalid coordinate. */ +#define INVALID_COORD 0xFFFFFFFF + +/* Register offsets */ +#define REGCTL1 0x00 +#define REGCTL2 0x04 +#define INTERRUPT_THRES 0x08 +#define INTERRUPT_MASK 0x0c + +#define INTERRUPT_STATUS 0x10 +#define CONTROLLER_STATUS 0x14 +#define FIFO_DATA 0x18 +#define FIFO_DATA_X_Y_MASK 0xFFFF +#define ANALOG_CONTROL 0x1c + +#define AUX_DATA 0x20 +#define DEBOUNCE_CNTR_STAT 0x24 +#define SCAN_CNTR_STAT 0x28 +#define REM_CNTR_STAT 0x2c + +#define SETTLING_TIMER_STAT 0x30 +#define SPARE_REG 0x34 +#define SOFT_BYPASS_CONTROL 0x38 +#define SOFT_BYPASS_DATA 0x3c + + +/* Bit values for INTERRUPT_MASK and INTERRUPT_STATUS regs */ +#define TS_PEN_INTR_MASK BIT(0) +#define TS_FIFO_INTR_MASK BIT(2) + +/* Bit values for CONTROLLER_STATUS reg1 */ +#define TS_PEN_DOWN BIT(0) + +/* Shift values for control reg1 */ +#define SCANNING_PERIOD_SHIFT 24 +#define DEBOUNCE_TIMEOUT_SHIFT 16 +#define SETTLING_TIMEOUT_SHIFT 8 +#define TOUCH_TIMEOUT_SHIFT 0 + +/* Shift values for coordinates from fifo */ +#define X_COORD_SHIFT 0 +#define Y_COORD_SHIFT 16 + +/* Bit values for REGCTL2 */ +#define TS_CONTROLLER_EN_BIT BIT(16) +#define TS_CONTROLLER_AVGDATA_SHIFT 8 +#define TS_CONTROLLER_AVGDATA_MASK (0x7 << TS_CONTROLLER_AVGDATA_SHIFT) +#define TS_CONTROLLER_PWR_LDO BIT(5) +#define TS_CONTROLLER_PWR_ADC BIT(4) +#define TS_CONTROLLER_PWR_BGP BIT(3) +#define TS_CONTROLLER_PWR_TS BIT(2) +#define TS_WIRE_MODE_BIT BIT(1) + +#define dbg_reg(dev, priv, reg) \ + dev_dbg(dev, "%20s= 0x%08x\n", #reg, readl((priv)->regs + reg)) + +struct tsc_param { + /* Each step is 1024 us. Valid 1-256 */ + u32 scanning_period; + + /* Each step is 512 us. Valid 0-255 */ + u32 debounce_timeout; + + /* + * The settling duration (in ms) is the amount of time the tsc + * waits to allow the voltage to settle after turning on the + * drivers in detection mode. Valid values: 0-11 + * 0 = 0.008 ms + * 1 = 0.01 ms + * 2 = 0.02 ms + * 3 = 0.04 ms + * 4 = 0.08 ms + * 5 = 0.16 ms + * 6 = 0.32 ms + * 7 = 0.64 ms + * 8 = 1.28 ms + * 9 = 2.56 ms + * 10 = 5.12 ms + * 11 = 10.24 ms + */ + u32 settling_timeout; + + /* touch timeout in sample counts */ + u32 touch_timeout; + + /* + * Number of data samples which are averaged before a final data point + * is placed into the FIFO + */ + u32 average_data; + + /* FIFO threshold */ + u32 fifo_threshold; + + /* Optional standard touchscreen properties. */ + u32 max_x; + u32 max_y; + u32 fuzz_x; + u32 fuzz_y; + bool invert_x; + bool invert_y; +}; + +struct iproc_ts_priv { + struct platform_device *pdev; + struct input_dev *idev; + + void __iomem *regs; + struct clk *tsc_clk; + + int pen_status; + struct tsc_param cfg_params; +}; + +/* + * Set default values the same as hardware reset values + * except for fifo_threshold with is set to 1. + */ +static const struct tsc_param iproc_default_config = { + .scanning_period = 0x5, /* 1 to 256 */ + .debounce_timeout = 0x28, /* 0 to 255 */ + .settling_timeout = 0x7, /* 0 to 11 */ + .touch_timeout = 0xa, /* 0 to 255 */ + .average_data = 5, /* entry 5 = 32 pts */ + .fifo_threshold = 1, /* 0 to 31 */ + .max_x = X_MAX, + .max_y = Y_MAX, +}; + +static void ts_reg_dump(struct iproc_ts_priv *priv) +{ + struct device *dev = &priv->pdev->dev; + + dbg_reg(dev, priv, REGCTL1); + dbg_reg(dev, priv, REGCTL2); + dbg_reg(dev, priv, INTERRUPT_THRES); + dbg_reg(dev, priv, INTERRUPT_MASK); + dbg_reg(dev, priv, INTERRUPT_STATUS); + dbg_reg(dev, priv, CONTROLLER_STATUS); + dbg_reg(dev, priv, FIFO_DATA); + dbg_reg(dev, priv, ANALOG_CONTROL); + dbg_reg(dev, priv, AUX_DATA); + dbg_reg(dev, priv, DEBOUNCE_CNTR_STAT); + dbg_reg(dev, priv, SCAN_CNTR_STAT); + dbg_reg(dev, priv, REM_CNTR_STAT); + dbg_reg(dev, priv, SETTLING_TIMER_STAT); + dbg_reg(dev, priv, SPARE_REG); + dbg_reg(dev, priv, SOFT_BYPASS_CONTROL); + dbg_reg(dev, priv, SOFT_BYPASS_DATA); +} + +static irqreturn_t iproc_touchscreen_interrupt(int irq, void *data) +{ + struct platform_device *pdev = data; + struct iproc_ts_priv *priv = platform_get_drvdata(pdev); + u32 intr_status; + u32 raw_coordinate; + u16 x; + u16 y; + int i; + bool needs_sync = false; + + intr_status = readl(priv->regs + INTERRUPT_STATUS); + intr_status &= TS_PEN_INTR_MASK | TS_FIFO_INTR_MASK; + if (intr_status == 0) + return IRQ_NONE; + + /* Clear all interrupt status bits, write-1-clear */ + writel(intr_status, priv->regs + INTERRUPT_STATUS); + + /* Pen up/down */ + if (intr_status & TS_PEN_INTR_MASK) { + if (readl(priv->regs + CONTROLLER_STATUS) & TS_PEN_DOWN) + priv->pen_status = PEN_DOWN_STATUS; + else + priv->pen_status = PEN_UP_STATUS; + + input_report_key(priv->idev, BTN_TOUCH, priv->pen_status); + needs_sync = true; + + dev_dbg(&priv->pdev->dev, + "pen up-down (%d)\n", priv->pen_status); + } + + /* coordinates in FIFO exceed the theshold */ + if (intr_status & TS_FIFO_INTR_MASK) { + for (i = 0; i < priv->cfg_params.fifo_threshold; i++) { + raw_coordinate = readl(priv->regs + FIFO_DATA); + if (raw_coordinate == INVALID_COORD) + continue; + + /* + * The x and y coordinate are 16 bits each + * with the x in the lower 16 bits and y in the + * upper 16 bits. + */ + x = (raw_coordinate >> X_COORD_SHIFT) & + FIFO_DATA_X_Y_MASK; + y = (raw_coordinate >> Y_COORD_SHIFT) & + FIFO_DATA_X_Y_MASK; + + /* We only want to retain the 12 msb of the 16 */ + x = (x >> 4) & 0x0FFF; + y = (y >> 4) & 0x0FFF; + + /* adjust x y according to lcd tsc mount angle */ + if (priv->cfg_params.invert_x) + x = priv->cfg_params.max_x - x; + + if (priv->cfg_params.invert_y) + y = priv->cfg_params.max_y - y; + + input_report_abs(priv->idev, ABS_X, x); + input_report_abs(priv->idev, ABS_Y, y); + needs_sync = true; + + dev_dbg(&priv->pdev->dev, "xy (0x%x 0x%x)\n", x, y); + } + } + + if (needs_sync) + input_sync(priv->idev); + + return IRQ_HANDLED; +} + +static int iproc_ts_start(struct input_dev *idev) +{ + struct iproc_ts_priv *priv = input_get_drvdata(idev); + u32 val; + int error; + + /* Enable clock */ + error = clk_prepare_enable(priv->tsc_clk); + if (error) { + dev_err(&priv->pdev->dev, "%s clk_prepare_enable failed %d\n", + __func__, error); + return error; + } + + /* + * Interrupt is generated when: + * FIFO reaches the int_th value, and pen event(up/down) + */ + val = TS_PEN_INTR_MASK | TS_FIFO_INTR_MASK; + writel(val, priv->regs + INTERRUPT_MASK); + + writel(priv->cfg_params.fifo_threshold, priv->regs + INTERRUPT_THRES); + + /* Initialize control reg1 */ + val = 0; + val |= priv->cfg_params.scanning_period << SCANNING_PERIOD_SHIFT; + val |= priv->cfg_params.debounce_timeout << DEBOUNCE_TIMEOUT_SHIFT; + val |= priv->cfg_params.settling_timeout << SETTLING_TIMEOUT_SHIFT; + val |= priv->cfg_params.touch_timeout << TOUCH_TIMEOUT_SHIFT; + writel(val, priv->regs + REGCTL1); + + /* Try to clear all interrupt status */ + val = readl(priv->regs + INTERRUPT_STATUS); + val |= TS_FIFO_INTR_MASK | TS_PEN_INTR_MASK; + writel(val, priv->regs + INTERRUPT_STATUS); + + /* Initialize control reg2 */ + val = readl(priv->regs + REGCTL2); + val |= TS_CONTROLLER_EN_BIT | TS_WIRE_MODE_BIT; + + val &= ~TS_CONTROLLER_AVGDATA_MASK; + val |= priv->cfg_params.average_data << TS_CONTROLLER_AVGDATA_SHIFT; + + val &= ~(TS_CONTROLLER_PWR_LDO | /* PWR up LDO */ + TS_CONTROLLER_PWR_ADC | /* PWR up ADC */ + TS_CONTROLLER_PWR_BGP | /* PWR up BGP */ + TS_CONTROLLER_PWR_TS); /* PWR up TS */ + + writel(val, priv->regs + REGCTL2); + + ts_reg_dump(priv); + + return 0; +} + +static void iproc_ts_stop(struct input_dev *dev) +{ + u32 val; + struct iproc_ts_priv *priv = input_get_drvdata(dev); + + writel(0, priv->regs + INTERRUPT_MASK); /* Disable all interrupts */ + + /* Only power down touch screen controller */ + val = readl(priv->regs + REGCTL2); + val |= TS_CONTROLLER_PWR_TS; + writel(val, priv->regs + REGCTL2); + + clk_disable(priv->tsc_clk); +} + +static int iproc_get_tsc_config(struct device *dev, struct iproc_ts_priv *priv) +{ + struct device_node *np = dev->of_node; + u32 val; + + priv->cfg_params = iproc_default_config; + + if (!np) + return 0; + + if (of_property_read_u32(np, "scanning_period", &val) >= 0) { + if (val < 1 || val > 256) { + dev_err(dev, "scanning_period (%u) must be [1-256]\n", + val); + return -EINVAL; + } + priv->cfg_params.scanning_period = val; + } + + if (of_property_read_u32(np, "debounce_timeout", &val) >= 0) { + if (val > 255) { + dev_err(dev, "debounce_timeout (%u) must be [0-255]\n", + val); + return -EINVAL; + } + priv->cfg_params.debounce_timeout = val; + } + + if (of_property_read_u32(np, "settling_timeout", &val) >= 0) { + if (val > 11) { + dev_err(dev, "settling_timeout (%u) must be [0-11]\n", + val); + return -EINVAL; + } + priv->cfg_params.settling_timeout = val; + } + + if (of_property_read_u32(np, "touch_timeout", &val) >= 0) { + if (val > 255) { + dev_err(dev, "touch_timeout (%u) must be [0-255]\n", + val); + return -EINVAL; + } + priv->cfg_params.touch_timeout = val; + } + + if (of_property_read_u32(np, "average_data", &val) >= 0) { + if (val > 8) { + dev_err(dev, "average_data (%u) must be [0-8]\n", val); + return -EINVAL; + } + priv->cfg_params.average_data = val; + } + + if (of_property_read_u32(np, "fifo_threshold", &val) >= 0) { + if (val > 31) { + dev_err(dev, "fifo_threshold (%u)) must be [0-31]\n", + val); + return -EINVAL; + } + priv->cfg_params.fifo_threshold = val; + } + + /* Parse optional properties. */ + of_property_read_u32(np, "touchscreen-size-x", &priv->cfg_params.max_x); + of_property_read_u32(np, "touchscreen-size-y", &priv->cfg_params.max_y); + + of_property_read_u32(np, "touchscreen-fuzz-x", + &priv->cfg_params.fuzz_x); + of_property_read_u32(np, "touchscreen-fuzz-y", + &priv->cfg_params.fuzz_y); + + priv->cfg_params.invert_x = + of_property_read_bool(np, "touchscreen-inverted-x"); + priv->cfg_params.invert_y = + of_property_read_bool(np, "touchscreen-inverted-y"); + + return 0; +} + +static int iproc_ts_probe(struct platform_device *pdev) +{ + struct iproc_ts_priv *priv; + struct input_dev *idev; + struct resource *res; + int irq; + int error; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + /* touchscreen controller memory mapped regs */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(priv->regs)) { + error = PTR_ERR(priv->regs); + dev_err(&pdev->dev, "unable to map I/O memory: %d\n", error); + return error; + } + + priv->tsc_clk = devm_clk_get(&pdev->dev, "tsc_clk"); + if (IS_ERR(priv->tsc_clk)) { + error = PTR_ERR(priv->tsc_clk); + dev_err(&pdev->dev, + "failed getting clock tsc_clk: %d\n", error); + return error; + } + + priv->pdev = pdev; + error = iproc_get_tsc_config(&pdev->dev, priv); + if (error) { + dev_err(&pdev->dev, "get_tsc_config failed: %d\n", error); + return error; + } + + idev = devm_input_allocate_device(&pdev->dev); + if (!idev) { + dev_err(&pdev->dev, "failed to allocate input device\n"); + return -ENOMEM; + } + + priv->idev = idev; + priv->pen_status = PEN_UP_STATUS; + + /* Set input device info */ + idev->name = IPROC_TS_NAME; + idev->dev.parent = &pdev->dev; + + idev->id.bustype = BUS_HOST; + idev->id.vendor = SERIO_UNKNOWN; + idev->id.product = 0; + idev->id.version = 0; + + idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + __set_bit(BTN_TOUCH, idev->keybit); + + input_set_abs_params(idev, ABS_X, X_MIN, priv->cfg_params.max_x, + priv->cfg_params.fuzz_x, 0); + input_set_abs_params(idev, ABS_Y, Y_MIN, priv->cfg_params.max_y, + priv->cfg_params.fuzz_y, 0); + + idev->open = iproc_ts_start; + idev->close = iproc_ts_stop; + + input_set_drvdata(idev, priv); + platform_set_drvdata(pdev, priv); + + /* get interrupt */ + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "platform_get_irq failed: %d\n", irq); + return irq; + } + + error = devm_request_irq(&pdev->dev, irq, + iproc_touchscreen_interrupt, + IRQF_SHARED, IPROC_TS_NAME, pdev); + if (error) + return error; + + error = input_register_device(priv->idev); + if (error) { + dev_err(&pdev->dev, + "failed to register input device: %d\n", error); + return error; + } + + return 0; +} + +static const struct of_device_id iproc_ts_of_match[] = { + {.compatible = "brcm,iproc-touchscreen", }, + { }, +}; +MODULE_DEVICE_TABLE(of, iproc_ts_of_match); + +static struct platform_driver iproc_ts_driver = { + .probe = iproc_ts_probe, + .driver = { + .name = IPROC_TS_NAME, + .of_match_table = of_match_ptr(iproc_ts_of_match), + }, +}; + +module_platform_driver(iproc_ts_driver); + +MODULE_DESCRIPTION("IPROC Touchscreen driver"); +MODULE_AUTHOR("Broadcom"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-59-g8ed1b From 682f048bd49449f4ab978664a7f69a44a74e3caa Mon Sep 17 00:00:00 2001 From: Alexander Drozdov Date: Mon, 23 Mar 2015 09:11:13 +0300 Subject: af_packet: pass checksum validation status to the user Introduce TP_STATUS_CSUM_VALID tp_status flag to tell the af_packet user that at least the transport header checksum has been already validated. For now, the flag may be set for incoming packets only. Signed-off-by: Alexander Drozdov Cc: Willem de Bruijn Signed-off-by: David S. Miller --- Documentation/networking/packet_mmap.txt | 13 ++++++++++--- include/uapi/linux/if_packet.h | 1 + net/packet/af_packet.c | 9 +++++++++ 3 files changed, 20 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/packet_mmap.txt b/Documentation/networking/packet_mmap.txt index a6d7cb91069e..daa015af16a0 100644 --- a/Documentation/networking/packet_mmap.txt +++ b/Documentation/networking/packet_mmap.txt @@ -440,9 +440,10 @@ and the following flags apply: +++ Capture process: from include/linux/if_packet.h - #define TP_STATUS_COPY 2 - #define TP_STATUS_LOSING 4 - #define TP_STATUS_CSUMNOTREADY 8 + #define TP_STATUS_COPY (1 << 1) + #define TP_STATUS_LOSING (1 << 2) + #define TP_STATUS_CSUMNOTREADY (1 << 3) + #define TP_STATUS_CSUM_VALID (1 << 7) TP_STATUS_COPY : This flag indicates that the frame (and associated meta information) has been truncated because it's @@ -466,6 +467,12 @@ TP_STATUS_CSUMNOTREADY: currently it's used for outgoing IP packets which reading the packet we should not try to check the checksum. +TP_STATUS_CSUM_VALID : This flag indicates that at least the transport + header checksum of the packet has been already + validated on the kernel side. If the flag is not set + then we are free to check the checksum by ourselves + provided that TP_STATUS_CSUMNOTREADY is also not set. + for convenience there are also the following defines: #define TP_STATUS_KERNEL 0 diff --git a/include/uapi/linux/if_packet.h b/include/uapi/linux/if_packet.h index da2d668b8cf1..053bd102fbe0 100644 --- a/include/uapi/linux/if_packet.h +++ b/include/uapi/linux/if_packet.h @@ -99,6 +99,7 @@ struct tpacket_auxdata { #define TP_STATUS_VLAN_VALID (1 << 4) /* auxdata has valid tp_vlan_tci */ #define TP_STATUS_BLK_TMO (1 << 5) #define TP_STATUS_VLAN_TPID_VALID (1 << 6) /* auxdata has valid tp_vlan_tpid */ +#define TP_STATUS_CSUM_VALID (1 << 7) /* Tx ring - header status */ #define TP_STATUS_AVAILABLE 0 diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 9d854c5ce0b5..5102c3cc4eec 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1924,6 +1924,10 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, if (skb->ip_summed == CHECKSUM_PARTIAL) status |= TP_STATUS_CSUMNOTREADY; + else if (skb->pkt_type != PACKET_OUTGOING && + (skb->ip_summed == CHECKSUM_COMPLETE || + skb_csum_unnecessary(skb))) + status |= TP_STATUS_CSUM_VALID; if (snaplen > res) snaplen = res; @@ -3031,6 +3035,11 @@ static int packet_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, aux.tp_status = TP_STATUS_USER; if (skb->ip_summed == CHECKSUM_PARTIAL) aux.tp_status |= TP_STATUS_CSUMNOTREADY; + else if (skb->pkt_type != PACKET_OUTGOING && + (skb->ip_summed == CHECKSUM_COMPLETE || + skb_csum_unnecessary(skb))) + aux.tp_status |= TP_STATUS_CSUM_VALID; + aux.tp_len = origlen; aux.tp_snaplen = skb->len; aux.tp_mac = 0; -- cgit v1.2.3-59-g8ed1b From 9f0761c154eaf2bf796f7e0e3431631de8d362ae Mon Sep 17 00:00:00 2001 From: Hannes Frederic Sowa Date: Mon, 23 Mar 2015 23:36:06 +0100 Subject: ipv6: add documentation for stable_secret, idgen_delay and idgen_retries knobs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Erik Kline Cc: Fernando Gont Cc: Lorenzo Colitti Cc: YOSHIFUJI Hideaki/吉藤英明 Signed-off-by: Hannes Frederic Sowa Signed-off-by: David S. Miller --- Documentation/networking/ip-sysctl.txt | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'Documentation') diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index 6c07c2b36909..071fb18dc57c 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -1220,6 +1220,17 @@ anycast_src_echo_reply - BOOLEAN FALSE: disabled Default: FALSE +idgen_delay - INTEGER + Controls the delay in seconds after which time to retry + privacy stable address generation if a DAD conflict is + detected. + Default: 1 (as specified in RFC7217) + +idgen_retries - INTEGER + Controls the number of retries to generate a stable privacy + address if a DAD conflict is detected. + Default: 3 (as specified in RFC7217) + mld_qrv - INTEGER Controls the MLD query robustness variable (see RFC3810 9.1). Default: 2 (as specified by RFC3810 9.1) @@ -1540,6 +1551,20 @@ use_optimistic - BOOLEAN 0: disabled (default) 1: enabled +stable_secret - IPv6 address + This IPv6 address will be used as a secret to generate IPv6 + addresses for link-local addresses and autoconfigured + ones. All addresses generated after setting this secret will + be stable privacy ones by default. This can be changed via the + addrgenmode ip-link. conf/default/stable_secret is used as the + secret for the namespace, the interface specific ones can + overwrite that. Writes to conf/all/stable_secret are refused. + + It is recommended to generate this secret during installation + of a system and keep it stable after that. + + By default the stable secret is unset. + icmp/*: ratelimit - INTEGER Limit the maximal rates for sending ICMPv6 packets. -- cgit v1.2.3-59-g8ed1b From 71bbf038eaa44a80dd6df0da7c708d4618172fe0 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 6 Mar 2015 11:54:08 +0000 Subject: dt: pmu: extend ARM PMU binding to allow for explicit interrupt affinity The current ARM PMU binding relies on the PMU interrupts being listed in CPU logical order, which the device-tree author simply cannot know anything about. This patch introduces a new "interrupt-affinity" property, which makes the relationship between the PMU interrupts and their corresponding CPU explicit. Acked-by: Mark Rutland Signed-off-by: Will Deacon --- Documentation/devicetree/bindings/arm/pmu.txt | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/pmu.txt b/Documentation/devicetree/bindings/arm/pmu.txt index 75ef91d08f3b..f52d05660dc9 100644 --- a/Documentation/devicetree/bindings/arm/pmu.txt +++ b/Documentation/devicetree/bindings/arm/pmu.txt @@ -24,6 +24,13 @@ Required properties: Optional properties: +- interrupt-affinity : Valid only when using SPIs, specifies a list of phandles + to CPU nodes corresponding directly to the affinity of + the SPIs listed in the interrupts property. + + This property should be present when there is more than + a single SPI. + - qcom,no-pc-write : Indicates that this PMU doesn't support the 0xc and 0xd events. -- cgit v1.2.3-59-g8ed1b From d16a33bb94f88a40a99418993849c1eb93d60de3 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 21 Mar 2015 20:39:19 -0700 Subject: Input: touchscreen DT binding - add touchscreen-swapped-x-y property On devices with a native portrait screen a landscape touchscreen / digitizer may be used, this happens e.g. on ebook readers. In this case the X and Y axis of the touchscreen are swapped compared to the screen. Add a touchscreen-swapped-x-y property which drivers can use to see if they need to swap the axis to make the touchscreen coordinates match the screen coordinates. Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov --- Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt | 2 ++ 1 file changed, 2 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt b/Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt index d8e06163c54e..ac23caf518ad 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt +++ b/Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt @@ -16,6 +16,8 @@ Optional properties for Touchscreens: controller) - touchscreen-inverted-x : X axis is inverted (boolean) - touchscreen-inverted-y : Y axis is inverted (boolean) + - touchscreen-swapped-x-y : X and Y axis are swapped (boolean) + Swapping is done after inverting the axis Deprecated properties for Touchscreens: - x-size : deprecated name for touchscreen-size-x -- cgit v1.2.3-59-g8ed1b From a93ad65d375f216025902a73ff25900d82a9de25 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 21 Mar 2015 20:40:45 -0700 Subject: Input: add support for ChipOne icn8318 based touchscreens The ChipOne icn8318 is an i2c capacitive touchscreen controller typically used in cheap android tablets, this commit adds a driver for it. Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov --- .../bindings/input/touchscreen/chipone_icn8318.txt | 46 +++ .../devicetree/bindings/vendor-prefixes.txt | 1 + MAINTAINERS | 7 + drivers/input/touchscreen/Kconfig | 13 + drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/chipone_icn8318.c | 316 +++++++++++++++++++++ 6 files changed, 384 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/touchscreen/chipone_icn8318.txt create mode 100644 drivers/input/touchscreen/chipone_icn8318.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/input/touchscreen/chipone_icn8318.txt b/Documentation/devicetree/bindings/input/touchscreen/chipone_icn8318.txt new file mode 100644 index 000000000000..d11f8d615b5d --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/chipone_icn8318.txt @@ -0,0 +1,46 @@ +* ChipOne icn8318 I2C touchscreen controller + +Required properties: + - compatible : "chipone,icn8318" + - reg : I2C slave address of the chip (0x40) + - interrupt-parent : a phandle pointing to the interrupt controller + serving the interrupt for this chip + - interrupts : interrupt specification for the icn8318 interrupt + - wake-gpios : GPIO specification for the WAKE input + - touchscreen-size-x : horizontal resolution of touchscreen (in pixels) + - touchscreen-size-y : vertical resolution of touchscreen (in pixels) + +Optional properties: + - pinctrl-names : should be "default" + - pinctrl-0: : a phandle pointing to the pin settings for the + control gpios + - touchscreen-fuzz-x : horizontal noise value of the absolute input + device (in pixels) + - touchscreen-fuzz-y : vertical noise value of the absolute input + device (in pixels) + - touchscreen-inverted-x : X axis is inverted (boolean) + - touchscreen-inverted-y : Y axis is inverted (boolean) + - touchscreen-swapped-x-y : X and Y axis are swapped (boolean) + Swapping is done after inverting the axis + +Example: + +i2c@00000000 { + /* ... */ + + chipone_icn8318@40 { + compatible = "chipone,icn8318"; + reg = <0x40>; + interrupt-parent = <&pio>; + interrupts = <9 IRQ_TYPE_EDGE_FALLING>; /* EINT9 (PG9) */ + pinctrl-names = "default"; + pinctrl-0 = <&ts_wake_pin_p66>; + wake-gpios = <&pio 1 3 GPIO_ACTIVE_HIGH>; /* PB3 */ + touchscreen-size-x = <800>; + touchscreen-size-y = <480>; + touchscreen-inverted-x; + touchscreen-swapped-x-y; + }; + + /* ... */ +}; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index c862cf94c9c8..728cd0e1b306 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -37,6 +37,7 @@ capella Capella Microsystems, Inc cavium Cavium, Inc. cdns Cadence Design Systems Inc. chipidea Chipidea, Inc +chipone ChipOne chipspark ChipSPARK chrp Common Hardware Reference Platform chunghwa Chunghwa Picture Tubes Ltd. diff --git a/MAINTAINERS b/MAINTAINERS index 358eb0105e00..0a39a2843c11 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2523,6 +2523,13 @@ L: linux-usb@vger.kernel.org S: Maintained F: drivers/usb/chipidea/ +CHIPONE ICN8318 I2C TOUCHSCREEN DRIVER +M: Hans de Goede +L: linux-input@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/input/touchscreen/chipone_icn8318.txt +F: drivers/input/touchscreen/chipone_icn8318.c + CHROME HARDWARE PLATFORM SUPPORT M: Olof Johansson S: Maintained diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index a1cfe16e9a81..547f67d65372 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -140,6 +140,19 @@ config TOUCHSCREEN_BU21013 To compile this driver as a module, choose M here: the module will be called bu21013_ts. +config TOUCHSCREEN_CHIPONE_ICN8318 + tristate "chipone icn8318 touchscreen controller" + depends on GPIOLIB + depends on I2C + depends on OF + help + Say Y here if you have a ChipOne icn8318 based I2C touchscreen. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called chipone_icn8318. + config TOUCHSCREEN_CY8CTMG110 tristate "cy8ctmg110 touchscreen" depends on I2C diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 09c33531ab8e..44deea743d02 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_TOUCHSCREEN_AR1021_I2C) += ar1021_i2c.o obj-$(CONFIG_TOUCHSCREEN_ATMEL_MXT) += atmel_mxt_ts.o obj-$(CONFIG_TOUCHSCREEN_AUO_PIXCIR) += auo-pixcir-ts.o obj-$(CONFIG_TOUCHSCREEN_BU21013) += bu21013_ts.o +obj-$(CONFIG_TOUCHSCREEN_CHIPONE_ICN8318) += chipone_icn8318.o obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110) += cy8ctmg110_ts.o obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE) += cyttsp_core.o obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C) += cyttsp_i2c.o cyttsp_i2c_common.o diff --git a/drivers/input/touchscreen/chipone_icn8318.c b/drivers/input/touchscreen/chipone_icn8318.c new file mode 100644 index 000000000000..32e9db0e04bf --- /dev/null +++ b/drivers/input/touchscreen/chipone_icn8318.c @@ -0,0 +1,316 @@ +/* + * Driver for ChipOne icn8318 i2c touchscreen controller + * + * Copyright (c) 2015 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Red Hat authors: + * Hans de Goede + */ + +#include +#include +#include +#include +#include +#include +#include + +#define ICN8318_REG_POWER 4 +#define ICN8318_REG_TOUCHDATA 16 + +#define ICN8318_POWER_ACTIVE 0 +#define ICN8318_POWER_MONITOR 1 +#define ICN8318_POWER_HIBERNATE 2 + +#define ICN8318_MAX_TOUCHES 5 + +struct icn8318_touch { + __u8 slot; + __be16 x; + __be16 y; + __u8 pressure; /* Seems more like finger width then pressure really */ + __u8 event; +/* The difference between 2 and 3 is unclear */ +#define ICN8318_EVENT_NO_DATA 1 /* No finger seen yet since wakeup */ +#define ICN8318_EVENT_UPDATE1 2 /* New or updated coordinates */ +#define ICN8318_EVENT_UPDATE2 3 /* New or updated coordinates */ +#define ICN8318_EVENT_END 4 /* Finger lifted */ +} __packed; + +struct icn8318_touch_data { + __u8 softbutton; + __u8 touch_count; + struct icn8318_touch touches[ICN8318_MAX_TOUCHES]; +} __packed; + +struct icn8318_data { + struct i2c_client *client; + struct input_dev *input; + struct gpio_desc *wake_gpio; + u32 max_x; + u32 max_y; + bool invert_x; + bool invert_y; + bool swap_x_y; +}; + +static int icn8318_read_touch_data(struct i2c_client *client, + struct icn8318_touch_data *touch_data) +{ + u8 reg = ICN8318_REG_TOUCHDATA; + struct i2c_msg msg[2] = { + { + .addr = client->addr, + .len = 1, + .buf = ® + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = sizeof(struct icn8318_touch_data), + .buf = (u8 *)touch_data + } + }; + + return i2c_transfer(client->adapter, msg, 2); +} + +static inline bool icn8318_touch_active(u8 event) +{ + return (event == ICN8318_EVENT_UPDATE1) || + (event == ICN8318_EVENT_UPDATE2); +} + +static irqreturn_t icn8318_irq(int irq, void *dev_id) +{ + struct icn8318_data *data = dev_id; + struct device *dev = &data->client->dev; + struct icn8318_touch_data touch_data; + int i, ret, x, y; + + ret = icn8318_read_touch_data(data->client, &touch_data); + if (ret < 0) { + dev_err(dev, "Error reading touch data: %d\n", ret); + return IRQ_HANDLED; + } + + if (touch_data.softbutton) { + /* + * Other data is invalid when a softbutton is pressed. + * This needs some extra devicetree bindings to map the icn8318 + * softbutton codes to evdev codes. Currently no known devices + * use this. + */ + return IRQ_HANDLED; + } + + if (touch_data.touch_count > ICN8318_MAX_TOUCHES) { + dev_warn(dev, "Too much touches %d > %d\n", + touch_data.touch_count, ICN8318_MAX_TOUCHES); + touch_data.touch_count = ICN8318_MAX_TOUCHES; + } + + for (i = 0; i < touch_data.touch_count; i++) { + struct icn8318_touch *touch = &touch_data.touches[i]; + bool act = icn8318_touch_active(touch->event); + + input_mt_slot(data->input, touch->slot); + input_mt_report_slot_state(data->input, MT_TOOL_FINGER, act); + if (!act) + continue; + + x = be16_to_cpu(touch->x); + y = be16_to_cpu(touch->y); + + if (data->invert_x) + x = data->max_x - x; + + if (data->invert_y) + y = data->max_y - y; + + if (!data->swap_x_y) { + input_event(data->input, EV_ABS, ABS_MT_POSITION_X, x); + input_event(data->input, EV_ABS, ABS_MT_POSITION_Y, y); + } else { + input_event(data->input, EV_ABS, ABS_MT_POSITION_X, y); + input_event(data->input, EV_ABS, ABS_MT_POSITION_Y, x); + } + } + + input_mt_sync_frame(data->input); + input_sync(data->input); + + return IRQ_HANDLED; +} + +static int icn8318_start(struct input_dev *dev) +{ + struct icn8318_data *data = input_get_drvdata(dev); + + enable_irq(data->client->irq); + gpiod_set_value_cansleep(data->wake_gpio, 1); + + return 0; +} + +static void icn8318_stop(struct input_dev *dev) +{ + struct icn8318_data *data = input_get_drvdata(dev); + + disable_irq(data->client->irq); + i2c_smbus_write_byte_data(data->client, ICN8318_REG_POWER, + ICN8318_POWER_HIBERNATE); + gpiod_set_value_cansleep(data->wake_gpio, 0); +} + +#ifdef CONFIG_PM_SLEEP +static int icn8318_suspend(struct device *dev) +{ + struct icn8318_data *data = i2c_get_clientdata(to_i2c_client(dev)); + + mutex_lock(&data->input->mutex); + if (data->input->users) + icn8318_stop(data->input); + mutex_unlock(&data->input->mutex); + + return 0; +} + +static int icn8318_resume(struct device *dev) +{ + struct icn8318_data *data = i2c_get_clientdata(to_i2c_client(dev)); + + mutex_lock(&data->input->mutex); + if (data->input->users) + icn8318_start(data->input); + mutex_unlock(&data->input->mutex); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(icn8318_pm_ops, icn8318_suspend, icn8318_resume); + +static int icn8318_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct device_node *np = dev->of_node; + struct icn8318_data *data; + struct input_dev *input; + u32 fuzz_x = 0, fuzz_y = 0; + int error; + + if (!client->irq) { + dev_err(dev, "Error no irq specified\n"); + return -EINVAL; + } + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->wake_gpio = devm_gpiod_get(dev, "wake", GPIOD_OUT_LOW); + if (IS_ERR(data->wake_gpio)) { + error = PTR_ERR(data->wake_gpio); + if (error != -EPROBE_DEFER) + dev_err(dev, "Error getting wake gpio: %d\n", error); + return error; + } + + if (of_property_read_u32(np, "touchscreen-size-x", &data->max_x) || + of_property_read_u32(np, "touchscreen-size-y", &data->max_y)) { + dev_err(dev, "Error touchscreen-size-x and/or -y missing\n"); + return -EINVAL; + } + + /* Optional */ + of_property_read_u32(np, "touchscreen-fuzz-x", &fuzz_x); + of_property_read_u32(np, "touchscreen-fuzz-y", &fuzz_y); + data->invert_x = of_property_read_bool(np, "touchscreen-inverted-x"); + data->invert_y = of_property_read_bool(np, "touchscreen-inverted-y"); + data->swap_x_y = of_property_read_bool(np, "touchscreen-swapped-x-y"); + + input = devm_input_allocate_device(dev); + if (!input) + return -ENOMEM; + + input->name = client->name; + input->id.bustype = BUS_I2C; + input->open = icn8318_start; + input->close = icn8318_stop; + input->dev.parent = dev; + + if (!data->swap_x_y) { + input_set_abs_params(input, ABS_MT_POSITION_X, 0, + data->max_x, fuzz_x, 0); + input_set_abs_params(input, ABS_MT_POSITION_Y, 0, + data->max_y, fuzz_y, 0); + } else { + input_set_abs_params(input, ABS_MT_POSITION_X, 0, + data->max_y, fuzz_y, 0); + input_set_abs_params(input, ABS_MT_POSITION_Y, 0, + data->max_x, fuzz_x, 0); + } + + error = input_mt_init_slots(input, ICN8318_MAX_TOUCHES, + INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); + if (error) + return error; + + data->client = client; + data->input = input; + input_set_drvdata(input, data); + + error = devm_request_threaded_irq(dev, client->irq, NULL, icn8318_irq, + IRQF_ONESHOT, client->name, data); + if (error) { + dev_err(dev, "Error requesting irq: %d\n", error); + return error; + } + + /* Stop device till opened */ + icn8318_stop(data->input); + + error = input_register_device(input); + if (error) + return error; + + i2c_set_clientdata(client, data); + + return 0; +} + +static const struct of_device_id icn8318_of_match[] = { + { .compatible = "chipone,icn8318" }, + { } +}; +MODULE_DEVICE_TABLE(of, icn8318_of_match); + +/* This is useless for OF-enabled devices, but it is needed by I2C subsystem */ +static const struct i2c_device_id icn8318_i2c_id[] = { + { }, +}; +MODULE_DEVICE_TABLE(i2c, icn8318_i2c_id); + +static struct i2c_driver icn8318_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "chipone_icn8318", + .pm = &icn8318_pm_ops, + .of_match_table = icn8318_of_match, + }, + .probe = icn8318_probe, + .id_table = icn8318_i2c_id, +}; + +module_i2c_driver(icn8318_driver); + +MODULE_DESCRIPTION("ChipOne icn8318 I2C Touchscreen Driver"); +MODULE_AUTHOR("Hans de Goede "); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-59-g8ed1b From 27cd5452476978283decb19e429e81fc6c71e74b Mon Sep 17 00:00:00 2001 From: Michal Sekletar Date: Tue, 24 Mar 2015 14:48:41 +0100 Subject: filter: introduce SKF_AD_VLAN_TPID BPF extension If vlan offloading takes place then vlan header is removed from frame and its contents, both vlan_tci and vlan_proto, is available to user space via TPACKET interface. However, only vlan_tci can be used in BPF filters. This commit introduces a new BPF extension. It makes possible to load the value of vlan_proto (vlan TPID) to register A. Support for classic BPF and eBPF is being added, analogous to skb->protocol. Cc: Daniel Borkmann Cc: Alexei Starovoitov Cc: Jiri Pirko Signed-off-by: Michal Sekletar Acked-by: Daniel Borkmann Acked-by: Alexei Starovoitov Reviewed-by: Jiri Pirko Signed-off-by: David S. Miller --- Documentation/networking/filter.txt | 3 ++- include/linux/filter.h | 1 + include/uapi/linux/bpf.h | 1 + include/uapi/linux/filter.h | 3 ++- net/core/filter.c | 17 +++++++++++++++++ tools/net/bpf_exp.l | 2 ++ tools/net/bpf_exp.y | 11 ++++++++++- 7 files changed, 35 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/filter.txt b/Documentation/networking/filter.txt index 9930ecfbb465..135581f015e1 100644 --- a/Documentation/networking/filter.txt +++ b/Documentation/networking/filter.txt @@ -280,7 +280,8 @@ Possible BPF extensions are shown in the following table: rxhash skb->hash cpu raw_smp_processor_id() vlan_tci skb_vlan_tag_get(skb) - vlan_pr skb_vlan_tag_present(skb) + vlan_avail skb_vlan_tag_present(skb) + vlan_tpid skb->vlan_proto rand prandom_u32() These extensions can also be prefixed with '#'. diff --git a/include/linux/filter.h b/include/linux/filter.h index 9ee8c67ea249..fa11b3a367be 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -454,6 +454,7 @@ static inline u16 bpf_anc_helper(const struct sock_filter *ftest) BPF_ANCILLARY(VLAN_TAG_PRESENT); BPF_ANCILLARY(PAY_OFFSET); BPF_ANCILLARY(RANDOM); + BPF_ANCILLARY(VLAN_TPID); } /* Fallthrough. */ default: diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 3dd314a45d0d..27dc4ec58840 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -182,6 +182,7 @@ struct __sk_buff { __u32 protocol; __u32 vlan_present; __u32 vlan_tci; + __u32 vlan_proto; }; #endif /* _UAPI__LINUX_BPF_H__ */ diff --git a/include/uapi/linux/filter.h b/include/uapi/linux/filter.h index 47785d5ecf17..34c7936ca114 100644 --- a/include/uapi/linux/filter.h +++ b/include/uapi/linux/filter.h @@ -77,7 +77,8 @@ struct sock_fprog { /* Required for SO_ATTACH_FILTER. */ #define SKF_AD_VLAN_TAG_PRESENT 48 #define SKF_AD_PAY_OFFSET 52 #define SKF_AD_RANDOM 56 -#define SKF_AD_MAX 60 +#define SKF_AD_VLAN_TPID 60 +#define SKF_AD_MAX 64 #define SKF_NET_OFF (-0x100000) #define SKF_LL_OFF (-0x200000) diff --git a/net/core/filter.c b/net/core/filter.c index 084eacc4d1d4..32f43c59908c 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -272,6 +272,16 @@ static bool convert_bpf_extensions(struct sock_filter *fp, insn += cnt - 1; break; + case SKF_AD_OFF + SKF_AD_VLAN_TPID: + BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, vlan_proto) != 2); + + /* A = *(u16 *) (CTX + offsetof(vlan_proto)) */ + *insn++ = BPF_LDX_MEM(BPF_H, BPF_REG_A, BPF_REG_CTX, + offsetof(struct sk_buff, vlan_proto)); + /* A = ntohs(A) [emitting a nop or swap16] */ + *insn = BPF_ENDIAN(BPF_FROM_BE, BPF_REG_A, 16); + break; + case SKF_AD_OFF + SKF_AD_PAY_OFFSET: case SKF_AD_OFF + SKF_AD_NLATTR: case SKF_AD_OFF + SKF_AD_NLATTR_NEST: @@ -1226,6 +1236,13 @@ static u32 sk_filter_convert_ctx_access(int dst_reg, int src_reg, int ctx_off, offsetof(struct sk_buff, protocol)); break; + case offsetof(struct __sk_buff, vlan_proto): + BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, vlan_proto) != 2); + + *insn++ = BPF_LDX_MEM(BPF_H, dst_reg, src_reg, + offsetof(struct sk_buff, vlan_proto)); + break; + case offsetof(struct __sk_buff, mark): return convert_skb_access(SKF_AD_MARK, dst_reg, src_reg, insn); diff --git a/tools/net/bpf_exp.l b/tools/net/bpf_exp.l index 833a96611da6..c83af3fb77de 100644 --- a/tools/net/bpf_exp.l +++ b/tools/net/bpf_exp.l @@ -92,6 +92,8 @@ extern void yyerror(const char *str); "#"?("cpu") { return K_CPU; } "#"?("vlan_tci") { return K_VLANT; } "#"?("vlan_pr") { return K_VLANP; } +"#"?("vlan_avail") { return K_VLANP; } +"#"?("vlan_tpid") { return K_VLANTPID; } "#"?("rand") { return K_RAND; } ":" { return ':'; } diff --git a/tools/net/bpf_exp.y b/tools/net/bpf_exp.y index e6306c51c26f..f8332749b44c 100644 --- a/tools/net/bpf_exp.y +++ b/tools/net/bpf_exp.y @@ -56,7 +56,7 @@ static void bpf_set_jmp_label(char *label, enum jmp_type type); %token OP_LDXI %token K_PKT_LEN K_PROTO K_TYPE K_NLATTR K_NLATTR_NEST K_MARK K_QUEUE K_HATYPE -%token K_RXHASH K_CPU K_IFIDX K_VLANT K_VLANP K_POFF K_RAND +%token K_RXHASH K_CPU K_IFIDX K_VLANT K_VLANP K_VLANTPID K_POFF K_RAND %token ':' ',' '[' ']' '(' ')' 'x' 'a' '+' 'M' '*' '&' '#' '%' @@ -167,6 +167,9 @@ ldb | OP_LDB K_RAND { bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0, SKF_AD_OFF + SKF_AD_RANDOM); } + | OP_LDB K_VLANTPID { + bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0, + SKF_AD_OFF + SKF_AD_VLAN_TPID); } ; ldh @@ -218,6 +221,9 @@ ldh | OP_LDH K_RAND { bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, SKF_AD_OFF + SKF_AD_RANDOM); } + | OP_LDH K_VLANTPID { + bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, + SKF_AD_OFF + SKF_AD_VLAN_TPID); } ; ldi @@ -274,6 +280,9 @@ ld | OP_LD K_RAND { bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, SKF_AD_OFF + SKF_AD_RANDOM); } + | OP_LD K_VLANTPID { + bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, + SKF_AD_OFF + SKF_AD_VLAN_TPID); } | OP_LD 'M' '[' number ']' { bpf_set_curr_instr(BPF_LD | BPF_MEM, 0, 0, $4); } | OP_LD '[' 'x' '+' number ']' { -- cgit v1.2.3-59-g8ed1b From 4a5fd81507eaea556e533e9ebc8a3cf31fe159d1 Mon Sep 17 00:00:00 2001 From: Prarit Bhargava Date: Mon, 23 Mar 2015 16:32:09 -0400 Subject: Documentation, split up rtc.txt into documentation and test file This patch splits rtc.txt into two separate files, one for the documentation itself, and the other for the rtctest.c file. The rtctest file is moved into the kernel tools/testing/selftests/timers directory. This will make automated testing easier. Note that the only difference in the rtc.txt file is that the location of the rtctest.c file has changed. Signed-off-by: Prarit Bhargava Acked-by: Jonathan Corbet Acked-by: John Stultz Cc: corbet@lwn.net Cc: rtc-linux@googlegroups.com Cc: linux-doc@vger.kernel.org Cc: a.zummo@towertech.it Cc: prarit@redhat.com Cc: john.stultz@linaro.org Cc: shuahkh@osg.samsung.com Signed-off-by: Shuah Khan --- Documentation/rtc.txt | 264 +------------------------------ tools/testing/selftests/timers/Makefile | 2 +- tools/testing/selftests/timers/rtctest.c | 258 ++++++++++++++++++++++++++++++ 3 files changed, 260 insertions(+), 264 deletions(-) create mode 100644 tools/testing/selftests/timers/rtctest.c (limited to 'Documentation') diff --git a/Documentation/rtc.txt b/Documentation/rtc.txt index 596b60c08b74..8446f1ea1410 100644 --- a/Documentation/rtc.txt +++ b/Documentation/rtc.txt @@ -204,266 +204,4 @@ Some common examples: * RTC_PIE_ON, RTC_PIE_OFF: These are also emulated by the generic code. -If all else fails, check out the rtc-test.c driver! - - --------------------- 8< ---------------- 8< ----------------------------- - -/* - * Real Time Clock Driver Test/Example Program - * - * Compile with: - * gcc -s -Wall -Wstrict-prototypes rtctest.c -o rtctest - * - * Copyright (C) 1996, Paul Gortmaker. - * - * Released under the GNU General Public License, version 2, - * included herein by reference. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* - * This expects the new RTC class driver framework, working with - * clocks that will often not be clones of what the PC-AT had. - * Use the command line to specify another RTC if you need one. - */ -static const char default_rtc[] = "/dev/rtc0"; - - -int main(int argc, char **argv) -{ - int i, fd, retval, irqcount = 0; - unsigned long tmp, data; - struct rtc_time rtc_tm; - const char *rtc = default_rtc; - - switch (argc) { - case 2: - rtc = argv[1]; - /* FALLTHROUGH */ - case 1: - break; - default: - fprintf(stderr, "usage: rtctest [rtcdev]\n"); - return 1; - } - - fd = open(rtc, O_RDONLY); - - if (fd == -1) { - perror(rtc); - exit(errno); - } - - fprintf(stderr, "\n\t\t\tRTC Driver Test Example.\n\n"); - - /* Turn on update interrupts (one per second) */ - retval = ioctl(fd, RTC_UIE_ON, 0); - if (retval == -1) { - if (errno == ENOTTY) { - fprintf(stderr, - "\n...Update IRQs not supported.\n"); - goto test_READ; - } - perror("RTC_UIE_ON ioctl"); - exit(errno); - } - - fprintf(stderr, "Counting 5 update (1/sec) interrupts from reading %s:", - rtc); - fflush(stderr); - for (i=1; i<6; i++) { - /* This read will block */ - retval = read(fd, &data, sizeof(unsigned long)); - if (retval == -1) { - perror("read"); - exit(errno); - } - fprintf(stderr, " %d",i); - fflush(stderr); - irqcount++; - } - - fprintf(stderr, "\nAgain, from using select(2) on /dev/rtc:"); - fflush(stderr); - for (i=1; i<6; i++) { - struct timeval tv = {5, 0}; /* 5 second timeout on select */ - fd_set readfds; - - FD_ZERO(&readfds); - FD_SET(fd, &readfds); - /* The select will wait until an RTC interrupt happens. */ - retval = select(fd+1, &readfds, NULL, NULL, &tv); - if (retval == -1) { - perror("select"); - exit(errno); - } - /* This read won't block unlike the select-less case above. */ - retval = read(fd, &data, sizeof(unsigned long)); - if (retval == -1) { - perror("read"); - exit(errno); - } - fprintf(stderr, " %d",i); - fflush(stderr); - irqcount++; - } - - /* Turn off update interrupts */ - retval = ioctl(fd, RTC_UIE_OFF, 0); - if (retval == -1) { - perror("RTC_UIE_OFF ioctl"); - exit(errno); - } - -test_READ: - /* Read the RTC time/date */ - retval = ioctl(fd, RTC_RD_TIME, &rtc_tm); - if (retval == -1) { - perror("RTC_RD_TIME ioctl"); - exit(errno); - } - - fprintf(stderr, "\n\nCurrent RTC date/time is %d-%d-%d, %02d:%02d:%02d.\n", - rtc_tm.tm_mday, rtc_tm.tm_mon + 1, rtc_tm.tm_year + 1900, - rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec); - - /* Set the alarm to 5 sec in the future, and check for rollover */ - rtc_tm.tm_sec += 5; - if (rtc_tm.tm_sec >= 60) { - rtc_tm.tm_sec %= 60; - rtc_tm.tm_min++; - } - if (rtc_tm.tm_min == 60) { - rtc_tm.tm_min = 0; - rtc_tm.tm_hour++; - } - if (rtc_tm.tm_hour == 24) - rtc_tm.tm_hour = 0; - - retval = ioctl(fd, RTC_ALM_SET, &rtc_tm); - if (retval == -1) { - if (errno == ENOTTY) { - fprintf(stderr, - "\n...Alarm IRQs not supported.\n"); - goto test_PIE; - } - perror("RTC_ALM_SET ioctl"); - exit(errno); - } - - /* Read the current alarm settings */ - retval = ioctl(fd, RTC_ALM_READ, &rtc_tm); - if (retval == -1) { - perror("RTC_ALM_READ ioctl"); - exit(errno); - } - - fprintf(stderr, "Alarm time now set to %02d:%02d:%02d.\n", - rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec); - - /* Enable alarm interrupts */ - retval = ioctl(fd, RTC_AIE_ON, 0); - if (retval == -1) { - perror("RTC_AIE_ON ioctl"); - exit(errno); - } - - fprintf(stderr, "Waiting 5 seconds for alarm..."); - fflush(stderr); - /* This blocks until the alarm ring causes an interrupt */ - retval = read(fd, &data, sizeof(unsigned long)); - if (retval == -1) { - perror("read"); - exit(errno); - } - irqcount++; - fprintf(stderr, " okay. Alarm rang.\n"); - - /* Disable alarm interrupts */ - retval = ioctl(fd, RTC_AIE_OFF, 0); - if (retval == -1) { - perror("RTC_AIE_OFF ioctl"); - exit(errno); - } - -test_PIE: - /* Read periodic IRQ rate */ - retval = ioctl(fd, RTC_IRQP_READ, &tmp); - if (retval == -1) { - /* not all RTCs support periodic IRQs */ - if (errno == ENOTTY) { - fprintf(stderr, "\nNo periodic IRQ support\n"); - goto done; - } - perror("RTC_IRQP_READ ioctl"); - exit(errno); - } - fprintf(stderr, "\nPeriodic IRQ rate is %ldHz.\n", tmp); - - fprintf(stderr, "Counting 20 interrupts at:"); - fflush(stderr); - - /* The frequencies 128Hz, 256Hz, ... 8192Hz are only allowed for root. */ - for (tmp=2; tmp<=64; tmp*=2) { - - retval = ioctl(fd, RTC_IRQP_SET, tmp); - if (retval == -1) { - /* not all RTCs can change their periodic IRQ rate */ - if (errno == ENOTTY) { - fprintf(stderr, - "\n...Periodic IRQ rate is fixed\n"); - goto done; - } - perror("RTC_IRQP_SET ioctl"); - exit(errno); - } - - fprintf(stderr, "\n%ldHz:\t", tmp); - fflush(stderr); - - /* Enable periodic interrupts */ - retval = ioctl(fd, RTC_PIE_ON, 0); - if (retval == -1) { - perror("RTC_PIE_ON ioctl"); - exit(errno); - } - - for (i=1; i<21; i++) { - /* This blocks */ - retval = read(fd, &data, sizeof(unsigned long)); - if (retval == -1) { - perror("read"); - exit(errno); - } - fprintf(stderr, " %d",i); - fflush(stderr); - irqcount++; - } - - /* Disable periodic interrupts */ - retval = ioctl(fd, RTC_PIE_OFF, 0); - if (retval == -1) { - perror("RTC_PIE_OFF ioctl"); - exit(errno); - } - } - -done: - fprintf(stderr, "\n\n\t\t\t *** Test complete ***\n"); - - close(fd); - - return 0; -} +If all else fails, check out the tools/testing/selftests/timers/rtctest.c test! diff --git a/tools/testing/selftests/timers/Makefile b/tools/testing/selftests/timers/Makefile index 670aebdb4a99..89a3f44bf355 100644 --- a/tools/testing/selftests/timers/Makefile +++ b/tools/testing/selftests/timers/Makefile @@ -6,7 +6,7 @@ LDFLAGS += -lrt -lpthread # these are all "safe" tests that don't modify # system time or require escalated privledges TEST_PROGS = posix_timers nanosleep nsleep-lat set-timer-lat mqueue-lat \ - inconsistency-check raw_skew threadtest + inconsistency-check raw_skew threadtest rtctest TEST_PROGS_EXTENDED = alarmtimer-suspend valid-adjtimex change_skew \ skew_consistency clocksource-switch leap-a-day \ diff --git a/tools/testing/selftests/timers/rtctest.c b/tools/testing/selftests/timers/rtctest.c new file mode 100644 index 000000000000..1e06f4602195 --- /dev/null +++ b/tools/testing/selftests/timers/rtctest.c @@ -0,0 +1,258 @@ +/* + * Real Time Clock Driver Test/Example Program + * + * Compile with: + * gcc -s -Wall -Wstrict-prototypes rtctest.c -o rtctest + * + * Copyright (C) 1996, Paul Gortmaker. + * + * Released under the GNU General Public License, version 2, + * included herein by reference. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* + * This expects the new RTC class driver framework, working with + * clocks that will often not be clones of what the PC-AT had. + * Use the command line to specify another RTC if you need one. + */ +static const char default_rtc[] = "/dev/rtc0"; + + +int main(int argc, char **argv) +{ + int i, fd, retval, irqcount = 0; + unsigned long tmp, data; + struct rtc_time rtc_tm; + const char *rtc = default_rtc; + + switch (argc) { + case 2: + rtc = argv[1]; + /* FALLTHROUGH */ + case 1: + break; + default: + fprintf(stderr, "usage: rtctest [rtcdev]\n"); + return 1; + } + + fd = open(rtc, O_RDONLY); + + if (fd == -1) { + perror(rtc); + exit(errno); + } + + fprintf(stderr, "\n\t\t\tRTC Driver Test Example.\n\n"); + + /* Turn on update interrupts (one per second) */ + retval = ioctl(fd, RTC_UIE_ON, 0); + if (retval == -1) { + if (errno == ENOTTY) { + fprintf(stderr, + "\n...Update IRQs not supported.\n"); + goto test_READ; + } + perror("RTC_UIE_ON ioctl"); + exit(errno); + } + + fprintf(stderr, "Counting 5 update (1/sec) interrupts from reading %s:", + rtc); + fflush(stderr); + for (i=1; i<6; i++) { + /* This read will block */ + retval = read(fd, &data, sizeof(unsigned long)); + if (retval == -1) { + perror("read"); + exit(errno); + } + fprintf(stderr, " %d",i); + fflush(stderr); + irqcount++; + } + + fprintf(stderr, "\nAgain, from using select(2) on /dev/rtc:"); + fflush(stderr); + for (i=1; i<6; i++) { + struct timeval tv = {5, 0}; /* 5 second timeout on select */ + fd_set readfds; + + FD_ZERO(&readfds); + FD_SET(fd, &readfds); + /* The select will wait until an RTC interrupt happens. */ + retval = select(fd+1, &readfds, NULL, NULL, &tv); + if (retval == -1) { + perror("select"); + exit(errno); + } + /* This read won't block unlike the select-less case above. */ + retval = read(fd, &data, sizeof(unsigned long)); + if (retval == -1) { + perror("read"); + exit(errno); + } + fprintf(stderr, " %d",i); + fflush(stderr); + irqcount++; + } + + /* Turn off update interrupts */ + retval = ioctl(fd, RTC_UIE_OFF, 0); + if (retval == -1) { + perror("RTC_UIE_OFF ioctl"); + exit(errno); + } + +test_READ: + /* Read the RTC time/date */ + retval = ioctl(fd, RTC_RD_TIME, &rtc_tm); + if (retval == -1) { + perror("RTC_RD_TIME ioctl"); + exit(errno); + } + + fprintf(stderr, "\n\nCurrent RTC date/time is %d-%d-%d, %02d:%02d:%02d.\n", + rtc_tm.tm_mday, rtc_tm.tm_mon + 1, rtc_tm.tm_year + 1900, + rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec); + + /* Set the alarm to 5 sec in the future, and check for rollover */ + rtc_tm.tm_sec += 5; + if (rtc_tm.tm_sec >= 60) { + rtc_tm.tm_sec %= 60; + rtc_tm.tm_min++; + } + if (rtc_tm.tm_min == 60) { + rtc_tm.tm_min = 0; + rtc_tm.tm_hour++; + } + if (rtc_tm.tm_hour == 24) + rtc_tm.tm_hour = 0; + + retval = ioctl(fd, RTC_ALM_SET, &rtc_tm); + if (retval == -1) { + if (errno == ENOTTY) { + fprintf(stderr, + "\n...Alarm IRQs not supported.\n"); + goto test_PIE; + } + perror("RTC_ALM_SET ioctl"); + exit(errno); + } + + /* Read the current alarm settings */ + retval = ioctl(fd, RTC_ALM_READ, &rtc_tm); + if (retval == -1) { + perror("RTC_ALM_READ ioctl"); + exit(errno); + } + + fprintf(stderr, "Alarm time now set to %02d:%02d:%02d.\n", + rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec); + + /* Enable alarm interrupts */ + retval = ioctl(fd, RTC_AIE_ON, 0); + if (retval == -1) { + perror("RTC_AIE_ON ioctl"); + exit(errno); + } + + fprintf(stderr, "Waiting 5 seconds for alarm..."); + fflush(stderr); + /* This blocks until the alarm ring causes an interrupt */ + retval = read(fd, &data, sizeof(unsigned long)); + if (retval == -1) { + perror("read"); + exit(errno); + } + irqcount++; + fprintf(stderr, " okay. Alarm rang.\n"); + + /* Disable alarm interrupts */ + retval = ioctl(fd, RTC_AIE_OFF, 0); + if (retval == -1) { + perror("RTC_AIE_OFF ioctl"); + exit(errno); + } + +test_PIE: + /* Read periodic IRQ rate */ + retval = ioctl(fd, RTC_IRQP_READ, &tmp); + if (retval == -1) { + /* not all RTCs support periodic IRQs */ + if (errno == ENOTTY) { + fprintf(stderr, "\nNo periodic IRQ support\n"); + goto done; + } + perror("RTC_IRQP_READ ioctl"); + exit(errno); + } + fprintf(stderr, "\nPeriodic IRQ rate is %ldHz.\n", tmp); + + fprintf(stderr, "Counting 20 interrupts at:"); + fflush(stderr); + + /* The frequencies 128Hz, 256Hz, ... 8192Hz are only allowed for root. */ + for (tmp=2; tmp<=64; tmp*=2) { + + retval = ioctl(fd, RTC_IRQP_SET, tmp); + if (retval == -1) { + /* not all RTCs can change their periodic IRQ rate */ + if (errno == ENOTTY) { + fprintf(stderr, + "\n...Periodic IRQ rate is fixed\n"); + goto done; + } + perror("RTC_IRQP_SET ioctl"); + exit(errno); + } + + fprintf(stderr, "\n%ldHz:\t", tmp); + fflush(stderr); + + /* Enable periodic interrupts */ + retval = ioctl(fd, RTC_PIE_ON, 0); + if (retval == -1) { + perror("RTC_PIE_ON ioctl"); + exit(errno); + } + + for (i=1; i<21; i++) { + /* This blocks */ + retval = read(fd, &data, sizeof(unsigned long)); + if (retval == -1) { + perror("read"); + exit(errno); + } + fprintf(stderr, " %d",i); + fflush(stderr); + irqcount++; + } + + /* Disable periodic interrupts */ + retval = ioctl(fd, RTC_PIE_OFF, 0); + if (retval == -1) { + perror("RTC_PIE_OFF ioctl"); + exit(errno); + } + } + +done: + fprintf(stderr, "\n\n\t\t\t *** Test complete ***\n"); + + close(fd); + + return 0; +} -- cgit v1.2.3-59-g8ed1b From 07bf2b54cd8555390cf5fced9471689ebf7fd56c Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Tue, 24 Mar 2015 14:45:04 +0100 Subject: mmc: sdhci-esdhc-imx: support voltage-range property Signed-off-by: Sascha Hauer Signed-off-by: Marc Kleine-Budde Signed-off-by: Ulf Hansson --- Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt | 4 ++++ drivers/mmc/host/sdhci-esdhc-imx.c | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt b/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt index 9046ba06c47a..415c5575cbf7 100644 --- a/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt +++ b/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt @@ -17,6 +17,10 @@ Optional properties: to select a proper data sampling window in case the clock quality is not good due to signal path is too long on the board. Please refer to eSDHC/uSDHC chapter, DLL (Delay Line) section in RM for details. +- voltage-ranges : Specify the voltage range in case there are software + transparent level shifters on the outputs of the controller. Two cells are + required, first cell specifies minimum slot voltage (mV), second cell + specifies maximum slot voltage (mV). Several ranges could be specified. Examples: diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 9cce5cf18ebc..7ee831255f50 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -864,6 +864,7 @@ static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { #ifdef CONFIG_OF static int sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, + struct sdhci_host *host, struct esdhc_platform_data *boarddata) { struct device_node *np = pdev->dev.of_node; @@ -900,11 +901,14 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, if (of_property_read_u32(np, "fsl,delay-line", &boarddata->delay_line)) boarddata->delay_line = 0; + mmc_of_parse_voltage(np, &host->ocr_mask); + return 0; } #else static inline int sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, + struct sdhci_host *host, struct esdhc_platform_data *boarddata) { return -ENODEV; @@ -999,7 +1003,7 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) host->ioaddr + ESDHC_TUNING_CTRL); boarddata = &imx_data->boarddata; - if (sdhci_esdhc_imx_probe_dt(pdev, boarddata) < 0) { + if (sdhci_esdhc_imx_probe_dt(pdev, host, boarddata) < 0) { if (!host->mmc->parent->platform_data) { dev_err(mmc_dev(host->mmc), "no board data!\n"); err = -EINVAL; -- cgit v1.2.3-59-g8ed1b From 5590f3196b293574a12be58d06d5e1120d8856ec Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 18 Feb 2015 11:25:18 +1100 Subject: drivers/core/of: Add symlink to device-tree from devices with an OF node So I've been annoyed lately with having a bunch of devices such as i2c eeproms (for use by VPDs, server world !) and other bits and pieces that I want to be able to identify from userspace, and possibly provide additional data about from FW. Basically, it boils down to correlating the sysfs device with the OF tree device node, so that user space can use device-tree info such as additional "location" or "label" (or whatever else we can come up with) propreties to identify a given device, or get some attributes of use about it, etc... Now, so far, we've done that in some subsystem in a fairly ad-hoc basis using "devspec" properties. For example, PCI creates them if it can correlate the probed device with a DT node. Some powerpc specific busses do that too. However, i2c doesn't and it would be nice to have something more generic since technically any device can have a corresponding device tree node. This patch adds an "of_node" symlink to devices that have a non-NULL dev->of_node pointer, the patch is pretty trivial and seems to work just fine for me. Signed-off-by: Benjamin Herrenschmidt Acked-by: Rob Herring Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/stable/sysfs-devices | 10 ++++++++++ drivers/base/core.c | 16 ++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 Documentation/ABI/stable/sysfs-devices (limited to 'Documentation') diff --git a/Documentation/ABI/stable/sysfs-devices b/Documentation/ABI/stable/sysfs-devices new file mode 100644 index 000000000000..43f78b88da28 --- /dev/null +++ b/Documentation/ABI/stable/sysfs-devices @@ -0,0 +1,10 @@ +# Note: This documents additional properties of any device beyond what +# is documented in Documentation/sysfs-rules.txt + +What: /sys/devices/*/of_path +Date: February 2015 +Contact: Device Tree mailing list +Description: + Any device associated with a device-tree node will have + an of_path symlink pointing to the corresponding device + node in /sys/firmware/devicetree/ diff --git a/drivers/base/core.c b/drivers/base/core.c index e0998b6b6c49..cadf165651d8 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -805,8 +805,16 @@ static void cleanup_device_parent(struct device *dev) static int device_add_class_symlinks(struct device *dev) { + struct device_node *of_node = dev_of_node(dev); int error; + if (of_node) { + error = sysfs_create_link(&dev->kobj, &of_node->kobj,"of_node"); + if (error) + dev_warn(dev, "Error %d creating of_node link\n",error); + /* An error here doesn't warrant bringing down the device */ + } + if (!dev->class) return 0; @@ -814,7 +822,7 @@ static int device_add_class_symlinks(struct device *dev) &dev->class->p->subsys.kobj, "subsystem"); if (error) - goto out; + goto out_devnode; if (dev->parent && device_is_not_partition(dev)) { error = sysfs_create_link(&dev->kobj, &dev->parent->kobj, @@ -842,12 +850,16 @@ out_device: out_subsys: sysfs_remove_link(&dev->kobj, "subsystem"); -out: +out_devnode: + sysfs_remove_link(&dev->kobj, "of_node"); return error; } static void device_remove_class_symlinks(struct device *dev) { + if (dev_of_node(dev)) + sysfs_remove_link(&dev->kobj, "of_node"); + if (!dev->class) return; -- cgit v1.2.3-59-g8ed1b From 2be608561abfcceda4b35b71a0c1ec5088bb39b9 Mon Sep 17 00:00:00 2001 From: Jaewon Kim Date: Thu, 12 Mar 2015 19:11:13 +0900 Subject: phy: exynos5-usbdrd: Add to support for Exynos5433 SoC This patch adds driver data to support for Exynos5433 SoC. The Exynos5433 has one USB3.0 Host and USB3.0 DRD(Dual Role Device). Exynos5433 is simplar to Eyxnos7 but Exynos5433 have one more USB3.0 Host controller. Signed-off-by: Jaewon Kim Signed-off-by: Kishon Vijay Abraham I --- Documentation/devicetree/bindings/phy/samsung-phy.txt | 3 ++- drivers/phy/phy-exynos5-usbdrd.c | 10 ++++++++++ include/linux/mfd/syscon/exynos5-pmu.h | 3 +++ 3 files changed, 15 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/phy/samsung-phy.txt b/Documentation/devicetree/bindings/phy/samsung-phy.txt index 91e38cfe1f8f..60c6f2a633e0 100644 --- a/Documentation/devicetree/bindings/phy/samsung-phy.txt +++ b/Documentation/devicetree/bindings/phy/samsung-phy.txt @@ -128,6 +128,7 @@ Required properties: - compatible : Should be set to one of the following supported values: - "samsung,exynos5250-usbdrd-phy" - for exynos5250 SoC, - "samsung,exynos5420-usbdrd-phy" - for exynos5420 SoC. + - "samsung,exynos5433-usbdrd-phy" - for exynos5433 SoC. - "samsung,exynos7-usbdrd-phy" - for exynos7 SoC. - reg : Register offset and length of USB DRD PHY register set; - clocks: Clock IDs array as required by the controller @@ -139,7 +140,7 @@ Required properties: PHY operations, associated by phy name. It is used to determine bit values for clock settings register. For Exynos5420 this is given as 'sclk_usbphy30' in CMU. - - optional clocks: Exynos7 SoC has now following additional + - optional clocks: Exynos5433 & Exynos7 SoC has now following additional gate clocks available: - phy_pipe: for PIPE3 phy - phy_utmi: for UTMI+ phy diff --git a/drivers/phy/phy-exynos5-usbdrd.c b/drivers/phy/phy-exynos5-usbdrd.c index 04374018425f..597e7dd3782a 100644 --- a/drivers/phy/phy-exynos5-usbdrd.c +++ b/drivers/phy/phy-exynos5-usbdrd.c @@ -624,6 +624,13 @@ static const struct exynos5_usbdrd_phy_drvdata exynos5250_usbdrd_phy = { .has_common_clk_gate = true, }; +static const struct exynos5_usbdrd_phy_drvdata exynos5433_usbdrd_phy = { + .phy_cfg = phy_cfg_exynos5, + .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL, + .pmu_offset_usbdrd1_phy = EXYNOS5433_USBHOST30_PHY_CONTROL, + .has_common_clk_gate = false, +}; + static const struct exynos5_usbdrd_phy_drvdata exynos7_usbdrd_phy = { .phy_cfg = phy_cfg_exynos5, .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL, @@ -637,6 +644,9 @@ static const struct of_device_id exynos5_usbdrd_phy_of_match[] = { }, { .compatible = "samsung,exynos5420-usbdrd-phy", .data = &exynos5420_usbdrd_phy + }, { + .compatible = "samsung,exynos5433-usbdrd-phy", + .data = &exynos5433_usbdrd_phy }, { .compatible = "samsung,exynos7-usbdrd-phy", .data = &exynos7_usbdrd_phy diff --git a/include/linux/mfd/syscon/exynos5-pmu.h b/include/linux/mfd/syscon/exynos5-pmu.h index 00ef24bf6ede..9352adc95de6 100644 --- a/include/linux/mfd/syscon/exynos5-pmu.h +++ b/include/linux/mfd/syscon/exynos5-pmu.h @@ -36,6 +36,9 @@ #define EXYNOS5420_MTCADC_PHY_CONTROL (0x724) #define EXYNOS5420_DPTX_PHY_CONTROL (0x728) +/* Exynos5433 specific register definitions */ +#define EXYNOS5433_USBHOST30_PHY_CONTROL (0x728) + #define EXYNOS5_PHY_ENABLE BIT(0) #define EXYNOS5_MIPI_PHY_S_RESETN BIT(1) -- cgit v1.2.3-59-g8ed1b From 6be88670fc59d50426f90f734a36b90e1de7d148 Mon Sep 17 00:00:00 2001 From: Clément Perrochaud Date: Mon, 9 Mar 2015 11:12:05 +0100 Subject: NFC: nxp-nci_i2c: Add I2C support to NXP NCI driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a module to the NXP-NCI driver to support NFC controllers with an I2C control interface, such as the NPC100. Signed-off-by: Clément Perrochaud Signed-off-by: Samuel Ortiz --- .../devicetree/bindings/net/nfc/nxp-nci.txt | 35 ++ drivers/nfc/nxp-nci/Kconfig | 12 + drivers/nfc/nxp-nci/Makefile | 2 + drivers/nfc/nxp-nci/i2c.c | 415 +++++++++++++++++++++ 4 files changed, 464 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/nfc/nxp-nci.txt create mode 100644 drivers/nfc/nxp-nci/i2c.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/nfc/nxp-nci.txt b/Documentation/devicetree/bindings/net/nfc/nxp-nci.txt new file mode 100644 index 000000000000..5b6cd9b3f628 --- /dev/null +++ b/Documentation/devicetree/bindings/net/nfc/nxp-nci.txt @@ -0,0 +1,35 @@ +* NXP Semiconductors NXP NCI NFC Controllers + +Required properties: +- compatible: Should be "nxp,nxp-nci-i2c". +- clock-frequency: I²C work frequency. +- reg: address on the bus +- interrupt-parent: phandle for the interrupt gpio controller +- interrupts: GPIO interrupt to which the chip is connected +- enable-gpios: Output GPIO pin used for enabling/disabling the chip +- firmware-gpios: Output GPIO pin used to enter firmware download mode + +Optional SoC Specific Properties: +- pinctrl-names: Contains only one value - "default". +- pintctrl-0: Specifies the pin control groups used for this controller. + +Example (for ARM-based BeagleBone with NPC100 NFC controller on I2C2): + +&i2c2 { + + status = "okay"; + + npc100: npc100@29 { + + compatible = "nxp,nxp-nci-i2c"; + + reg = <0x29>; + clock-frequency = <100000>; + + interrupt-parent = <&gpio1>; + interrupts = <29 GPIO_ACTIVE_HIGH>; + + enable-gpios = <&gpio0 30 GPIO_ACTIVE_HIGH>; + firmware-gpios = <&gpio0 31 GPIO_ACTIVE_HIGH>; + }; +}; diff --git a/drivers/nfc/nxp-nci/Kconfig b/drivers/nfc/nxp-nci/Kconfig index 5f60c7cf02e8..37b40612520d 100644 --- a/drivers/nfc/nxp-nci/Kconfig +++ b/drivers/nfc/nxp-nci/Kconfig @@ -11,3 +11,15 @@ config NFC_NXP_NCI To compile this driver as a module, choose m here. The module will be called nxp_nci. Say N if unsure. + +config NFC_NXP_NCI_I2C + tristate "NXP-NCI I2C support" + depends on NFC_NXP_NCI && I2C + ---help--- + This module adds support for an I2C interface to the NXP NCI + chips. + Select this if your platform is using the I2C bus. + + To compile this driver as a module, choose m here. The module will + be called nxp_nci_i2c. + Say Y if unsure. diff --git a/drivers/nfc/nxp-nci/Makefile b/drivers/nfc/nxp-nci/Makefile index 8f1e32826961..c008be30bb18 100644 --- a/drivers/nfc/nxp-nci/Makefile +++ b/drivers/nfc/nxp-nci/Makefile @@ -3,7 +3,9 @@ # nxp-nci-objs = core.o firmware.o +nxp-nci_i2c-objs = i2c.o obj-$(CONFIG_NFC_NXP_NCI) += nxp-nci.o +obj-$(CONFIG_NFC_NXP_NCI_I2C) += nxp-nci_i2c.o ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG diff --git a/drivers/nfc/nxp-nci/i2c.c b/drivers/nfc/nxp-nci/i2c.c new file mode 100644 index 000000000000..17bd67dbebf0 --- /dev/null +++ b/drivers/nfc/nxp-nci/i2c.c @@ -0,0 +1,415 @@ +/* + * I2C link layer for the NXP NCI driver + * + * Copyright (C) 2014 NXP Semiconductors All rights reserved. + * + * Authors: Clément Perrochaud + * + * Derived from PN544 device driver: + * Copyright (C) 2012 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "nxp-nci.h" + +#define NXP_NCI_I2C_DRIVER_NAME "nxp-nci_i2c" + +#define NXP_NCI_I2C_MAX_PAYLOAD 32 + +struct nxp_nci_i2c_phy { + struct i2c_client *i2c_dev; + struct nci_dev *ndev; + + unsigned int gpio_en; + unsigned int gpio_fw; + + int hard_fault; /* + * < 0 if hardware error occurred (e.g. i2c err) + * and prevents normal operation. + */ +}; + +static int nxp_nci_i2c_set_mode(void *phy_id, + enum nxp_nci_mode mode) +{ + struct nxp_nci_i2c_phy *phy = (struct nxp_nci_i2c_phy *) phy_id; + + gpio_set_value(phy->gpio_fw, (mode == NXP_NCI_MODE_FW) ? 1 : 0); + gpio_set_value(phy->gpio_en, (mode != NXP_NCI_MODE_COLD) ? 1 : 0); + usleep_range(10000, 15000); + + if (mode == NXP_NCI_MODE_COLD) + phy->hard_fault = 0; + + return 0; +} + +static int nxp_nci_i2c_write(void *phy_id, struct sk_buff *skb) +{ + int r; + struct nxp_nci_i2c_phy *phy = phy_id; + struct i2c_client *client = phy->i2c_dev; + + if (phy->hard_fault != 0) + return phy->hard_fault; + + r = i2c_master_send(client, skb->data, skb->len); + if (r == -EREMOTEIO) { + /* Retry, chip was in standby */ + usleep_range(110000, 120000); + r = i2c_master_send(client, skb->data, skb->len); + } + + if (r < 0) { + nfc_err(&client->dev, "Error %d on I2C send\n", r); + } else if (r != skb->len) { + nfc_err(&client->dev, + "Invalid length sent: %u (expected %u)\n", + r, skb->len); + r = -EREMOTEIO; + } else { + /* Success but return 0 and not number of bytes */ + r = 0; + } + + return r; +} + +static struct nxp_nci_phy_ops i2c_phy_ops = { + .set_mode = nxp_nci_i2c_set_mode, + .write = nxp_nci_i2c_write, +}; + +static int nxp_nci_i2c_fw_read(struct nxp_nci_i2c_phy *phy, + struct sk_buff **skb) +{ + struct i2c_client *client = phy->i2c_dev; + u16 header; + size_t frame_len; + int r; + + r = i2c_master_recv(client, (u8 *) &header, NXP_NCI_FW_HDR_LEN); + if (r < 0) { + goto fw_read_exit; + } else if (r != NXP_NCI_FW_HDR_LEN) { + nfc_err(&client->dev, "Incorrect header length: %u\n", r); + r = -EBADMSG; + goto fw_read_exit; + } + + frame_len = (get_unaligned_be16(&header) & NXP_NCI_FW_FRAME_LEN_MASK) + + NXP_NCI_FW_CRC_LEN; + + *skb = alloc_skb(NXP_NCI_FW_HDR_LEN + frame_len, GFP_KERNEL); + if (*skb == NULL) { + r = -ENOMEM; + goto fw_read_exit; + } + + memcpy(skb_put(*skb, NXP_NCI_FW_HDR_LEN), &header, NXP_NCI_FW_HDR_LEN); + + r = i2c_master_recv(client, skb_put(*skb, frame_len), frame_len); + if (r != frame_len) { + nfc_err(&client->dev, + "Invalid frame length: %u (expected %zu)\n", + r, frame_len); + r = -EBADMSG; + goto fw_read_exit_free_skb; + } + + return 0; + +fw_read_exit_free_skb: + kfree_skb(*skb); +fw_read_exit: + return r; +} + +static int nxp_nci_i2c_nci_read(struct nxp_nci_i2c_phy *phy, + struct sk_buff **skb) +{ + struct nci_ctrl_hdr header; /* May actually be a data header */ + struct i2c_client *client = phy->i2c_dev; + int r; + + r = i2c_master_recv(client, (u8 *) &header, NCI_CTRL_HDR_SIZE); + if (r < 0) { + goto nci_read_exit; + } else if (r != NCI_CTRL_HDR_SIZE) { + nfc_err(&client->dev, "Incorrect header length: %u\n", r); + r = -EBADMSG; + goto nci_read_exit; + } + + *skb = alloc_skb(NCI_CTRL_HDR_SIZE + header.plen, GFP_KERNEL); + if (*skb == NULL) { + r = -ENOMEM; + goto nci_read_exit; + } + + memcpy(skb_put(*skb, NCI_CTRL_HDR_SIZE), (void *) &header, + NCI_CTRL_HDR_SIZE); + + r = i2c_master_recv(client, skb_put(*skb, header.plen), header.plen); + if (r != header.plen) { + nfc_err(&client->dev, + "Invalid frame payload length: %u (expected %u)\n", + r, header.plen); + r = -EBADMSG; + goto nci_read_exit_free_skb; + } + + return 0; + +nci_read_exit_free_skb: + kfree_skb(*skb); +nci_read_exit: + return r; +} + +static irqreturn_t nxp_nci_i2c_irq_thread_fn(int irq, void *phy_id) +{ + struct nxp_nci_i2c_phy *phy = phy_id; + struct i2c_client *client; + struct nxp_nci_info *info; + + struct sk_buff *skb = NULL; + int r = 0; + + if (!phy || !phy->ndev) + goto exit_irq_none; + + client = phy->i2c_dev; + + if (!client || irq != client->irq) + goto exit_irq_none; + + info = nci_get_drvdata(phy->ndev); + + if (!info) + goto exit_irq_none; + + mutex_lock(&info->info_lock); + + if (phy->hard_fault != 0) + goto exit_irq_handled; + + switch (info->mode) { + case NXP_NCI_MODE_NCI: + r = nxp_nci_i2c_nci_read(phy, &skb); + break; + case NXP_NCI_MODE_FW: + r = nxp_nci_i2c_fw_read(phy, &skb); + break; + case NXP_NCI_MODE_COLD: + r = -EREMOTEIO; + break; + } + + if (r == -EREMOTEIO) { + phy->hard_fault = r; + skb = NULL; + } else if (r < 0) { + nfc_err(&client->dev, "Read failed with error %d\n", r); + goto exit_irq_handled; + } + + switch (info->mode) { + case NXP_NCI_MODE_NCI: + nci_recv_frame(phy->ndev, skb); + break; + case NXP_NCI_MODE_FW: + nxp_nci_fw_recv_frame(phy->ndev, skb); + break; + case NXP_NCI_MODE_COLD: + break; + } + +exit_irq_handled: + mutex_unlock(&info->info_lock); + return IRQ_HANDLED; +exit_irq_none: + WARN_ON_ONCE(1); + return IRQ_NONE; +} + +#ifdef CONFIG_OF + +static int nxp_nci_i2c_parse_devtree(struct i2c_client *client) +{ + struct nxp_nci_i2c_phy *phy = i2c_get_clientdata(client); + struct device_node *pp; + int r; + + pp = client->dev.of_node; + if (!pp) + return -ENODEV; + + r = of_get_named_gpio(pp, "enable-gpios", 0); + if (r == -EPROBE_DEFER) + r = of_get_named_gpio(pp, "enable-gpios", 0); + if (r < 0) { + nfc_err(&client->dev, "Failed to get EN gpio, error: %d\n", r); + return r; + } + phy->gpio_en = r; + + r = of_get_named_gpio(pp, "firmware-gpios", 0); + if (r == -EPROBE_DEFER) + r = of_get_named_gpio(pp, "firmware-gpios", 0); + if (r < 0) { + nfc_err(&client->dev, "Failed to get FW gpio, error: %d\n", r); + return r; + } + phy->gpio_fw = r; + + r = irq_of_parse_and_map(pp, 0); + if (r < 0) { + nfc_err(&client->dev, "Unable to get irq, error: %d\n", r); + return r; + } + client->irq = r; + + return 0; +} + +#else + +static int nxp_nci_i2c_parse_devtree(struct i2c_client *client) +{ + return -ENODEV; +} + +#endif + +static int nxp_nci_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct nxp_nci_i2c_phy *phy; + struct nxp_nci_nfc_platform_data *pdata; + int r; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + nfc_err(&client->dev, "Need I2C_FUNC_I2C\n"); + r = -ENODEV; + goto probe_exit; + } + + phy = devm_kzalloc(&client->dev, sizeof(struct nxp_nci_i2c_phy), + GFP_KERNEL); + if (!phy) { + r = -ENOMEM; + goto probe_exit; + } + + phy->i2c_dev = client; + i2c_set_clientdata(client, phy); + + pdata = client->dev.platform_data; + + if (!pdata && client->dev.of_node) { + r = nxp_nci_i2c_parse_devtree(client); + if (r < 0) { + nfc_err(&client->dev, "Failed to get DT data\n"); + goto probe_exit; + } + } else if (pdata) { + phy->gpio_en = pdata->gpio_en; + phy->gpio_fw = pdata->gpio_fw; + client->irq = pdata->irq; + } else { + nfc_err(&client->dev, "No platform data\n"); + r = -EINVAL; + goto probe_exit; + } + + r = devm_gpio_request_one(&phy->i2c_dev->dev, phy->gpio_en, + GPIOF_OUT_INIT_LOW, "nxp_nci_en"); + if (r < 0) + goto probe_exit; + + r = devm_gpio_request_one(&phy->i2c_dev->dev, phy->gpio_fw, + GPIOF_OUT_INIT_LOW, "nxp_nci_fw"); + if (r < 0) + goto probe_exit; + + r = nxp_nci_probe(phy, &client->dev, &i2c_phy_ops, + NXP_NCI_I2C_MAX_PAYLOAD, &phy->ndev); + if (r < 0) + goto probe_exit; + + r = request_threaded_irq(client->irq, NULL, + nxp_nci_i2c_irq_thread_fn, + IRQF_TRIGGER_RISING | IRQF_ONESHOT, + NXP_NCI_I2C_DRIVER_NAME, phy); + if (r < 0) + nfc_err(&client->dev, "Unable to register IRQ handler\n"); + +probe_exit: + return r; +} + +static int nxp_nci_i2c_remove(struct i2c_client *client) +{ + struct nxp_nci_i2c_phy *phy = i2c_get_clientdata(client); + + nxp_nci_remove(phy->ndev); + free_irq(client->irq, phy); + + return 0; +} + +static struct i2c_device_id nxp_nci_i2c_id_table[] = { + {"nxp-nci_i2c", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, nxp_nci_i2c_id_table); + +static const struct of_device_id of_nxp_nci_i2c_match[] = { + { .compatible = "nxp,nxp-nci-i2c", }, + {}, +}; +MODULE_DEVICE_TABLE(of, of_nxp_nci_i2c_match); + +static struct i2c_driver nxp_nci_i2c_driver = { + .driver = { + .name = NXP_NCI_I2C_DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(of_nxp_nci_i2c_match), + }, + .probe = nxp_nci_i2c_probe, + .id_table = nxp_nci_i2c_id_table, + .remove = nxp_nci_i2c_remove, +}; + +module_i2c_driver(nxp_nci_i2c_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("I2C driver for NXP NCI NFC controllers"); +MODULE_AUTHOR("Clément Perrochaud "); -- cgit v1.2.3-59-g8ed1b From 45e4372525592eafe84d8385e1e7c99a7cb23e0c Mon Sep 17 00:00:00 2001 From: Michael Opdenacker Date: Sun, 22 Mar 2015 11:35:56 -0700 Subject: DocBook media: fix broken EIA hyperlink This fixes the bibliography hyperlink to "http://www.eia.org" which now redirects to a page with a "404 Not found" error. The latest update to the document referred to is now available on the Consumer Electronics Association website. Signed-off-by: Michael Opdenacker Signed-off-by: Jonathan Corbet --- Documentation/DocBook/media/v4l/biblio.xml | 11 +++++------ Documentation/DocBook/media/v4l/dev-sliced-vbi.xml | 2 +- Documentation/DocBook/media/v4l/vidioc-g-sliced-vbi-cap.xml | 2 +- 3 files changed, 7 insertions(+), 8 deletions(-) (limited to 'Documentation') diff --git a/Documentation/DocBook/media/v4l/biblio.xml b/Documentation/DocBook/media/v4l/biblio.xml index 7ff01a23c2fe..fdee6b3f3eca 100644 --- a/Documentation/DocBook/media/v4l/biblio.xml +++ b/Documentation/DocBook/media/v4l/biblio.xml @@ -1,14 +1,13 @@ References - - EIA 608-B + + CEA 608-E - Electronic Industries Alliance (http://www.eia.org) + Consumer Electronics Association (http://www.ce.org) - EIA 608-B "Recommended Practice for Line 21 Data -Service" + CEA-608-E R-2014 "Line 21 Data Services" diff --git a/Documentation/DocBook/media/v4l/dev-sliced-vbi.xml b/Documentation/DocBook/media/v4l/dev-sliced-vbi.xml index 7a8bf3011ee9..0aec62ed2bf8 100644 --- a/Documentation/DocBook/media/v4l/dev-sliced-vbi.xml +++ b/Documentation/DocBook/media/v4l/dev-sliced-vbi.xml @@ -254,7 +254,7 @@ ETS 300 231, lsb first transmitted. V4L2_SLICED_CAPTION_525 0x1000 - + NTSC line 21, 284 (second field 21) Two bytes in transmission order, including parity bit, lsb first transmitted. diff --git a/Documentation/DocBook/media/v4l/vidioc-g-sliced-vbi-cap.xml b/Documentation/DocBook/media/v4l/vidioc-g-sliced-vbi-cap.xml index bd015d1563ff..d05623c55403 100644 --- a/Documentation/DocBook/media/v4l/vidioc-g-sliced-vbi-cap.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-sliced-vbi-cap.xml @@ -205,7 +205,7 @@ ETS 300 231, lsb first transmitted. V4L2_SLICED_CAPTION_525 0x1000 - + NTSC line 21, 284 (second field 21) Two bytes in transmission order, including parity bit, lsb first transmitted. -- cgit v1.2.3-59-g8ed1b From fdc81b7910ad5153bf257e5f7861be71f75a02ef Mon Sep 17 00:00:00 2001 From: David Daney Date: Thu, 26 Mar 2015 10:09:08 -0700 Subject: stable_kernel_rules: Add clause about specification of kernel versions to patch. Signed-off-by: David Daney Signed-off-by: Greg Kroah-Hartman --- Documentation/stable_kernel_rules.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'Documentation') diff --git a/Documentation/stable_kernel_rules.txt b/Documentation/stable_kernel_rules.txt index 02f8331edb8b..58d0ac4df946 100644 --- a/Documentation/stable_kernel_rules.txt +++ b/Documentation/stable_kernel_rules.txt @@ -81,6 +81,16 @@ format in the sign-off area: git cherry-pick fd21073 git cherry-pick +Also, some patches may have kernel version prerequisites. This can be +specified in the following format in the sign-off area: + + Cc: # 3.3.x- + + The tag has the meaning of: + git cherry-pick + + For each "-stable" tree starting with the specified version. + Following the submission: - The sender will receive an ACK when the patch has been accepted into the -- cgit v1.2.3-59-g8ed1b From 76b17e6e4923e4138ed9a4d480cba148ff239dc9 Mon Sep 17 00:00:00 2001 From: Julius Werner Date: Thu, 26 Mar 2015 16:30:25 -0700 Subject: spi/rockchip: Add device tree property to configure Rx Sample Delay We have found that we can sometimes see read failures on boards with high-capacitance SPI lines. It seems that the controller samples the Rx data line too early, and its register interface has an "Rx Sample Delay" setting to fine-tune against this issue. This patch adds a new optional device tree entry that can configure this delay in terms of nanoseconds. The kernel will calculate the best-fitting amount of parent clock ticks to program the controller with based on that. Signed-off-by: Julius Werner Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/spi-rockchip.txt | 4 ++++ drivers/spi/spi-rockchip.c | 21 +++++++++++++++++++++ 2 files changed, 25 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/spi/spi-rockchip.txt b/Documentation/devicetree/bindings/spi/spi-rockchip.txt index 467dec441c62..0c491bda4c65 100644 --- a/Documentation/devicetree/bindings/spi/spi-rockchip.txt +++ b/Documentation/devicetree/bindings/spi/spi-rockchip.txt @@ -24,6 +24,9 @@ Optional Properties: - dmas: DMA specifiers for tx and rx dma. See the DMA client binding, Documentation/devicetree/bindings/dma/dma.txt - dma-names: DMA request names should include "tx" and "rx" if present. +- rx-sample-delay-ns: nanoseconds to delay after the SCLK edge before sampling + Rx data (may need to be fine tuned for high capacitance lines). + No delay (0) by default. Example: @@ -33,6 +36,7 @@ Example: reg = <0xff110000 0x1000>; dmas = <&pdma1 11>, <&pdma1 12>; dma-names = "tx", "rx"; + rx-sample-delay-ns = <10>; #address-cells = <1>; #size-cells = <0>; interrupts = ; diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index 25003c408c92..f65384b3417f 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -179,6 +179,7 @@ struct rockchip_spi { u8 tmode; u8 bpw; u8 n_bytes; + u8 rsd_nsecs; unsigned len; u32 speed; @@ -499,6 +500,7 @@ static void rockchip_spi_config(struct rockchip_spi *rs) { u32 div = 0; u32 dmacr = 0; + int rsd = 0; u32 cr0 = (CR0_BHT_8BIT << CR0_BHT_OFFSET) | (CR0_SSD_ONE << CR0_SSD_OFFSET); @@ -528,6 +530,20 @@ static void rockchip_spi_config(struct rockchip_spi *rs) div = max_t(u32, rs->max_freq / rs->speed, 1); div = (div + 1) & 0xfffe; + /* Rx sample delay is expressed in parent clock cycles (max 3) */ + rsd = DIV_ROUND_CLOSEST(rs->rsd_nsecs * (rs->max_freq >> 8), + 1000000000 >> 8); + if (!rsd && rs->rsd_nsecs) { + pr_warn_once("rockchip-spi: %u Hz are too slow to express %u ns delay\n", + rs->max_freq, rs->rsd_nsecs); + } else if (rsd > 3) { + rsd = 3; + pr_warn_once("rockchip-spi: %u Hz are too fast to express %u ns delay, clamping at %u ns\n", + rs->max_freq, rs->rsd_nsecs, + rsd * 1000000000U / rs->max_freq); + } + cr0 |= rsd << CR0_RSD_OFFSET; + writel_relaxed(cr0, rs->regs + ROCKCHIP_SPI_CTRLR0); writel_relaxed(rs->len - 1, rs->regs + ROCKCHIP_SPI_CTRLR1); @@ -620,6 +636,7 @@ static int rockchip_spi_probe(struct platform_device *pdev) struct rockchip_spi *rs; struct spi_master *master; struct resource *mem; + u32 rsd_nsecs; master = spi_alloc_master(&pdev->dev, sizeof(struct rockchip_spi)); if (!master) @@ -671,6 +688,10 @@ static int rockchip_spi_probe(struct platform_device *pdev) rs->dev = &pdev->dev; rs->max_freq = clk_get_rate(rs->spiclk); + if (!of_property_read_u32(pdev->dev.of_node, "rx-sample-delay-ns", + &rsd_nsecs)) + rs->rsd_nsecs = rsd_nsecs; + rs->fifo_len = get_fifo_len(rs); if (!rs->fifo_len) { dev_err(&pdev->dev, "Failed to get fifo length\n"); -- cgit v1.2.3-59-g8ed1b From 52fd475042dc145284d05f86ceac66ef5ed6665c Mon Sep 17 00:00:00 2001 From: Philippe Bergheaud Date: Thu, 26 Mar 2015 11:46:56 +0100 Subject: cxl: Fix a typo in ABI documentation Fix the attribute name of the configuration record class ID. Signed-off-by: Philippe Bergheaud Signed-off-by: Michael Ellerman --- Documentation/ABI/testing/sysfs-class-cxl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-class-cxl b/Documentation/ABI/testing/sysfs-class-cxl index 3680364b4048..d46bba801aac 100644 --- a/Documentation/ABI/testing/sysfs-class-cxl +++ b/Documentation/ABI/testing/sysfs-class-cxl @@ -100,7 +100,7 @@ Description: read only Hexadecimal value of the device ID found in this AFU configuration record. -What: /sys/class/cxl//cr/vendor +What: /sys/class/cxl//cr/class Date: February 2015 Contact: linuxppc-dev@lists.ozlabs.org Description: read only -- cgit v1.2.3-59-g8ed1b From 7c6037508357b553670a713ec537b8a76941b952 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 23 Mar 2015 09:26:37 +0100 Subject: Documentation: i2c: describe the new slave mode Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- Documentation/i2c/slave-interface | 179 ++++++++++++++++++++++++++++++++++++++ Documentation/i2c/summary | 4 - 2 files changed, 179 insertions(+), 4 deletions(-) create mode 100644 Documentation/i2c/slave-interface (limited to 'Documentation') diff --git a/Documentation/i2c/slave-interface b/Documentation/i2c/slave-interface new file mode 100644 index 000000000000..389bb5d61854 --- /dev/null +++ b/Documentation/i2c/slave-interface @@ -0,0 +1,179 @@ +Linux I2C slave interface description +===================================== + +by Wolfram Sang in 2014-15 + +Linux can also be an I2C slave in case I2C controllers have slave support. +Besides this HW requirement, one also needs a software backend providing the +actual functionality. An example for this is the slave-eeprom driver, which +acts as a dual memory driver. While another I2C master on the bus can access it +like a regular EEPROM, the Linux I2C slave can access the content via sysfs and +retrieve/provide information as needed. The software backend driver and the I2C +bus driver communicate via events. Here is a small graph visualizing the data +flow and the means by which data is transported. The dotted line marks only one +example. The backend could also use e.g. a character device, be in-kernel +only, or something completely different: + + + e.g. sysfs I2C slave events I/O registers + +-----------+ v +---------+ v +--------+ v +------------+ + | Userspace +........+ Backend +-----------+ Driver +-----+ Controller | + +-----------+ +---------+ +--------+ +------------+ + | | + ----------------------------------------------------------------+-- I2C + --------------------------------------------------------------+---- Bus + +Note: Technically, there is also the I2C core between the backend and the +driver. However, at this time of writing, the layer is transparent. + + +User manual +=========== + +I2C slave backends behave like standard I2C clients. So, you can instantiate +them like described in the document 'instantiating-devices'. A quick example +for instantiating the slave-eeprom driver from userspace: + + # echo 0-0064 > /sys/bus/i2c/drivers/i2c-slave-eeprom/bind + +Each backend should come with separate documentation to describe its specific +behaviour and setup. + + +Developer manual +================ + +I2C slave events +---------------- + +The bus driver sends an event to the backend using the following function: + + ret = i2c_slave_event(client, event, &val) + +'client' describes the i2c slave device. 'event' is one of the special event +types described hereafter. 'val' holds an u8 value for the data byte to be +read/written and is thus bidirectional. The pointer to val must always be +provided even if val is not used for an event, i.e. don't use NULL here. 'ret' +is the return value from the backend. Mandatory events must be provided by the +bus drivers and must be checked for by backend drivers. + +Event types: + +* I2C_SLAVE_WRITE_REQUESTED (mandatory) + +'val': unused +'ret': always 0 + +Another I2C master wants to write data to us. This event should be sent once +our own address and the write bit was detected. The data did not arrive yet, so +there is nothing to process or return. Wakeup or initialization probably needs +to be done, though. + +* I2C_SLAVE_READ_REQUESTED (mandatory) + +'val': backend returns first byte to be sent +'ret': always 0 + +Another I2C master wants to read data from us. This event should be sent once +our own address and the read bit was detected. After returning, the bus driver +should transmit the first byte. + +* I2C_SLAVE_WRITE_RECEIVED (mandatory) + +'val': bus driver delivers received byte +'ret': 0 if the byte should be acked, some errno if the byte should be nacked + +Another I2C master has sent a byte to us which needs to be set in 'val'. If 'ret' +is zero, the bus driver should ack this byte. If 'ret' is an errno, then the byte +should be nacked. + +* I2C_SLAVE_READ_PROCESSED (mandatory) + +'val': backend returns next byte to be sent +'ret': always 0 + +The bus driver requests the next byte to be sent to another I2C master in +'val'. Important: This does not mean that the previous byte has been acked, it +only means that the previous byte is shifted out to the bus! To ensure seamless +transmission, most hardware requests the next byte when the previous one is +still shifted out. If the master sends NACK and stops reading after the byte +currently shifted out, this byte requested here is never used. It very likely +needs to be sent again on the next I2C_SLAVE_READ_REQUEST, depending a bit on +your backend, though. + +* I2C_SLAVE_STOP (mandatory) + +'val': unused +'ret': always 0 + +A stop condition was received. This can happen anytime and the backend should +reset its state machine for I2C transfers to be able to receive new requests. + + +Software backends +----------------- + +If you want to write a software backend: + +* use a standard i2c_driver and its matching mechanisms +* write the slave_callback which handles the above slave events + (best using a state machine) +* register this callback via i2c_slave_register() + +Check the i2c-slave-eeprom driver as an example. + + +Bus driver support +------------------ + +If you want to add slave support to the bus driver: + +* implement calls to register/unregister the slave and add those to the + struct i2c_algorithm. When registering, you probably need to set the i2c + slave address and enable slave specific interrupts. If you use runtime pm, you + should use pm_runtime_forbid() because your device usually needs to be powered + on always to be able to detect its slave address. When unregistering, do the + inverse of the above. + +* Catch the slave interrupts and send appropriate i2c_slave_events to the backend. + +Check the i2c-rcar driver as an example. + + +About ACK/NACK +-------------- + +It is good behaviour to always ACK the address phase, so the master knows if a +device is basically present or if it mysteriously disappeared. Using NACK to +state being busy is troublesome. SMBus demands to always ACK the address phase, +while the I2C specification is more loose on that. Most I2C controllers also +automatically ACK when detecting their slave addresses, so there is no option +to NACK them. For those reasons, this API does not support NACK in the address +phase. + +Currently, there is no slave event to report if the master did ACK or NACK a +byte when it reads from us. We could make this an optional event if the need +arises. However, cases should be extremely rare because the master is expected +to send STOP after that and we have an event for that. Also, keep in mind not +all I2C controllers have the possibility to report that event. + + +About buffers +------------- + +During development of this API, the question of using buffers instead of just +bytes came up. Such an extension might be possible, usefulness is unclear at +this time of writing. Some points to keep in mind when using buffers: + +* Buffers should be opt-in and slave drivers will always have to support + byte-based transactions as the ultimate fallback because this is how the + majority of HW works. + +* For backends simulating hardware registers, buffers are not helpful because + on writes an action should be immediately triggered. For reads, the data in + the buffer might get stale. + +* A master can send STOP at any time. For partially transferred buffers, this + means additional code to handle this exception. Such code tends to be + error-prone. + diff --git a/Documentation/i2c/summary b/Documentation/i2c/summary index 13ab076dcd92..809541ab352f 100644 --- a/Documentation/i2c/summary +++ b/Documentation/i2c/summary @@ -41,7 +41,3 @@ integrated than Algorithm and Adapter. For a given configuration, you will need a driver for your I2C bus, and drivers for your I2C devices (usually one driver for each device). - -At this time, Linux only operates I2C (or SMBus) in master mode; you can't -use these APIs to make a Linux system behave as a slave/device, either to -speak a custom protocol or to emulate some other device. -- cgit v1.2.3-59-g8ed1b From d0c892f59c918535f902caea63637af87d931d91 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 23 Mar 2015 09:26:38 +0100 Subject: i2c: slave: add documentation for i2c-slave-eeprom Signed-off-by: Wolfram Sang Acked-by: Geert Uytterhoeven Signed-off-by: Wolfram Sang --- Documentation/i2c/slave-eeprom-backend | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 Documentation/i2c/slave-eeprom-backend (limited to 'Documentation') diff --git a/Documentation/i2c/slave-eeprom-backend b/Documentation/i2c/slave-eeprom-backend new file mode 100644 index 000000000000..c8444ef82acf --- /dev/null +++ b/Documentation/i2c/slave-eeprom-backend @@ -0,0 +1,14 @@ +Linux I2C slave eeprom backend +============================== + +by Wolfram Sang in 2014-15 + +This is a proof-of-concept backend which acts like an EEPROM on the connected +I2C bus. The memory contents can be modified from userspace via this file +located in sysfs: + + /sys/bus/i2c/devices//slave-eeprom + +As of 2015, Linux doesn't support poll on binary sysfs files, so there is no +notfication when another master changed the content. + -- cgit v1.2.3-59-g8ed1b From 1006e3c93161431c81135b8a23fbfa69dcd43ab0 Mon Sep 17 00:00:00 2001 From: Andrew Bresticker Date: Tue, 24 Feb 2015 19:56:01 -0800 Subject: CLK: Add binding document for Pistachio clock controllers Add a device-tree binding document describing the four clock controllers present on the IMG Pistachio SoC. Signed-off-by: Damien Horsley Signed-off-by: Andrew Bresticker Cc: Rob Herring Cc: Pawel Moll Cc: Mark Rutland Cc: Ian Campbell Cc: Kumar Gala Cc: Mike Turquette Cc: Stephen Boyd Cc: devicetree@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Cc: Andrew Bresticker Cc: Ezequiel Garcia Cc: James Hartley Cc: James Hogan Cc: Damien Horsley Acked-by: Stephen Boyd Patchwork: https://patchwork.linux-mips.org/patch/9319/ Signed-off-by: Ralf Baechle --- .../devicetree/bindings/clock/pistachio-clock.txt | 123 ++++++++++++++ include/dt-bindings/clock/pistachio-clk.h | 183 +++++++++++++++++++++ 2 files changed, 306 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/pistachio-clock.txt create mode 100644 include/dt-bindings/clock/pistachio-clk.h (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/pistachio-clock.txt b/Documentation/devicetree/bindings/clock/pistachio-clock.txt new file mode 100644 index 000000000000..868db499eed2 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/pistachio-clock.txt @@ -0,0 +1,123 @@ +Imagination Technologies Pistachio SoC clock controllers +======================================================== + +Pistachio has four clock controllers (core clock, peripheral clock, peripheral +general control, and top general control) which are instantiated individually +from the device-tree. + +External clocks: +---------------- + +There are three external inputs to the clock controllers which should be +defined with the following clock-output-names: +- "xtal": External 52Mhz oscillator (required) +- "audio_clk_in": Alternate audio reference clock (optional) +- "enet_clk_in": Alternate ethernet PHY clock (optional) + +Core clock controller: +---------------------- + +The core clock controller generates clocks for the CPU, RPU (WiFi + BT +co-processor), audio, and several peripherals. + +Required properties: +- compatible: Must be "img,pistachio-clk". +- reg: Must contain the base address and length of the core clock controller. +- #clock-cells: Must be 1. The single cell is the clock identifier. + See dt-bindings/clock/pistachio-clk.h for the list of valid identifiers. +- clocks: Must contain an entry for each clock in clock-names. +- clock-names: Must include "xtal" (see "External clocks") and + "audio_clk_in_gate", "enet_clk_in_gate" which are generated by the + top-level general control. + +Example: + clk_core: clock-controller@18144000 { + compatible = "img,pistachio-clk"; + reg = <0x18144000 0x800>; + clocks = <&xtal>, <&cr_top EXT_CLK_AUDIO_IN>, + <&cr_top EXT_CLK_ENET_IN>; + clock-names = "xtal", "audio_clk_in_gate", "enet_clk_in_gate"; + + #clock-cells = <1>; + }; + +Peripheral clock controller: +---------------------------- + +The peripheral clock controller generates clocks for the DDR, ROM, and other +peripherals. The peripheral system clock ("periph_sys") generated by the core +clock controller is the input clock to the peripheral clock controller. + +Required properties: +- compatible: Must be "img,pistachio-periph-clk". +- reg: Must contain the base address and length of the peripheral clock + controller. +- #clock-cells: Must be 1. The single cell is the clock identifier. + See dt-bindings/clock/pistachio-clk.h for the list of valid identifiers. +- clocks: Must contain an entry for each clock in clock-names. +- clock-names: Must include "periph_sys", the peripheral system clock generated + by the core clock controller. + +Example: + clk_periph: clock-controller@18144800 { + compatible = "img,pistachio-clk-periph"; + reg = <0x18144800 0x800>; + clocks = <&clk_core CLK_PERIPH_SYS>; + clock-names = "periph_sys"; + + #clock-cells = <1>; + }; + +Peripheral general control: +--------------------------- + +The peripheral general control block generates system interface clocks and +resets for various peripherals. It also contains miscellaneous peripheral +control registers. The system clock ("sys") generated by the peripheral clock +controller is the input clock to the system clock controller. + +Required properties: +- compatible: Must include "img,pistachio-periph-cr" and "syscon". +- reg: Must contain the base address and length of the peripheral general + control registers. +- #clock-cells: Must be 1. The single cell is the clock identifier. + See dt-bindings/clock/pistachio-clk.h for the list of valid identifiers. +- clocks: Must contain an entry for each clock in clock-names. +- clock-names: Must include "sys", the system clock generated by the peripheral + clock controller. + +Example: + cr_periph: syscon@18144800 { + compatible = "img,pistachio-cr-periph", "syscon"; + reg = <0x18148000 0x1000>; + clocks = <&clock_periph PERIPH_CLK_PERIPH_SYS>; + clock-names = "sys"; + + #clock-cells = <1>; + }; + +Top-level general control: +-------------------------- + +The top-level general control block contains miscellaneous control registers and +gates for the external clocks "audio_clk_in" and "enet_clk_in". + +Required properties: +- compatible: Must include "img,pistachio-cr-top" and "syscon". +- reg: Must contain the base address and length of the top-level + control registers. +- clocks: Must contain an entry for each clock in clock-names. +- clock-names: Two optional clocks, "audio_clk_in" and "enet_clk_in" (see + "External clocks"). +- #clock-cells: Must be 1. The single cell is the clock identifier. + See dt-bindings/clock/pistachio-clk.h for the list of valid identifiers. + +Example: + cr_top: syscon@18144800 { + compatible = "img,pistachio-cr-top", "syscon"; + reg = <0x18149000 0x200>; + clocks = <&audio_refclk>, <&ext_enet_in>; + clock-names = "audio_clk_in", "enet_clk_in"; + + #clock-cells = <1>; + }; diff --git a/include/dt-bindings/clock/pistachio-clk.h b/include/dt-bindings/clock/pistachio-clk.h new file mode 100644 index 000000000000..039f83facb68 --- /dev/null +++ b/include/dt-bindings/clock/pistachio-clk.h @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2014 Google, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + */ + +#ifndef _DT_BINDINGS_CLOCK_PISTACHIO_H +#define _DT_BINDINGS_CLOCK_PISTACHIO_H + +/* PLLs */ +#define CLK_MIPS_PLL 0 +#define CLK_AUDIO_PLL 1 +#define CLK_RPU_V_PLL 2 +#define CLK_RPU_L_PLL 3 +#define CLK_SYS_PLL 4 +#define CLK_WIFI_PLL 5 +#define CLK_BT_PLL 6 + +/* Fixed-factor clocks */ +#define CLK_WIFI_DIV4 16 +#define CLK_WIFI_DIV8 17 + +/* Gate clocks */ +#define CLK_MIPS 32 +#define CLK_AUDIO_IN 33 +#define CLK_AUDIO 34 +#define CLK_I2S 35 +#define CLK_SPDIF 36 +#define CLK_AUDIO_DAC 37 +#define CLK_RPU_V 38 +#define CLK_RPU_L 39 +#define CLK_RPU_SLEEP 40 +#define CLK_WIFI_PLL_GATE 41 +#define CLK_RPU_CORE 42 +#define CLK_WIFI_ADC 43 +#define CLK_WIFI_DAC 44 +#define CLK_USB_PHY 45 +#define CLK_ENET_IN 46 +#define CLK_ENET 47 +#define CLK_UART0 48 +#define CLK_UART1 49 +#define CLK_PERIPH_SYS 50 +#define CLK_SPI0 51 +#define CLK_SPI1 52 +#define CLK_EVENT_TIMER 53 +#define CLK_AUX_ADC_INTERNAL 54 +#define CLK_AUX_ADC 55 +#define CLK_SD_HOST 56 +#define CLK_BT 57 +#define CLK_BT_DIV4 58 +#define CLK_BT_DIV8 59 +#define CLK_BT_1MHZ 60 + +/* Divider clocks */ +#define CLK_MIPS_INTERNAL_DIV 64 +#define CLK_MIPS_DIV 65 +#define CLK_AUDIO_DIV 66 +#define CLK_I2S_DIV 67 +#define CLK_SPDIF_DIV 68 +#define CLK_AUDIO_DAC_DIV 69 +#define CLK_RPU_V_DIV 70 +#define CLK_RPU_L_DIV 71 +#define CLK_RPU_SLEEP_DIV 72 +#define CLK_RPU_CORE_DIV 73 +#define CLK_USB_PHY_DIV 74 +#define CLK_ENET_DIV 75 +#define CLK_UART0_INTERNAL_DIV 76 +#define CLK_UART0_DIV 77 +#define CLK_UART1_INTERNAL_DIV 78 +#define CLK_UART1_DIV 79 +#define CLK_SYS_INTERNAL_DIV 80 +#define CLK_SPI0_INTERNAL_DIV 81 +#define CLK_SPI0_DIV 82 +#define CLK_SPI1_INTERNAL_DIV 83 +#define CLK_SPI1_DIV 84 +#define CLK_EVENT_TIMER_INTERNAL_DIV 85 +#define CLK_EVENT_TIMER_DIV 86 +#define CLK_AUX_ADC_INTERNAL_DIV 87 +#define CLK_AUX_ADC_DIV 88 +#define CLK_SD_HOST_DIV 89 +#define CLK_BT_DIV 90 +#define CLK_BT_DIV4_DIV 91 +#define CLK_BT_DIV8_DIV 92 +#define CLK_BT_1MHZ_INTERNAL_DIV 93 +#define CLK_BT_1MHZ_DIV 94 + +/* Mux clocks */ +#define CLK_AUDIO_REF_MUX 96 +#define CLK_MIPS_PLL_MUX 97 +#define CLK_AUDIO_PLL_MUX 98 +#define CLK_AUDIO_MUX 99 +#define CLK_RPU_V_PLL_MUX 100 +#define CLK_RPU_L_PLL_MUX 101 +#define CLK_RPU_L_MUX 102 +#define CLK_WIFI_PLL_MUX 103 +#define CLK_WIFI_DIV4_MUX 104 +#define CLK_WIFI_DIV8_MUX 105 +#define CLK_RPU_CORE_MUX 106 +#define CLK_SYS_PLL_MUX 107 +#define CLK_ENET_MUX 108 +#define CLK_EVENT_TIMER_MUX 109 +#define CLK_SD_HOST_MUX 110 +#define CLK_BT_PLL_MUX 111 +#define CLK_DEBUG_MUX 112 + +#define CLK_NR_CLKS 113 + +/* Peripheral gate clocks */ +#define PERIPH_CLK_SYS 0 +#define PERIPH_CLK_SYS_BUS 1 +#define PERIPH_CLK_DDR 2 +#define PERIPH_CLK_ROM 3 +#define PERIPH_CLK_COUNTER_FAST 4 +#define PERIPH_CLK_COUNTER_SLOW 5 +#define PERIPH_CLK_IR 6 +#define PERIPH_CLK_WD 7 +#define PERIPH_CLK_PDM 8 +#define PERIPH_CLK_PWM 9 +#define PERIPH_CLK_I2C0 10 +#define PERIPH_CLK_I2C1 11 +#define PERIPH_CLK_I2C2 12 +#define PERIPH_CLK_I2C3 13 + +/* Peripheral divider clocks */ +#define PERIPH_CLK_ROM_DIV 32 +#define PERIPH_CLK_COUNTER_FAST_DIV 33 +#define PERIPH_CLK_COUNTER_SLOW_PRE_DIV 34 +#define PERIPH_CLK_COUNTER_SLOW_DIV 35 +#define PERIPH_CLK_IR_PRE_DIV 36 +#define PERIPH_CLK_IR_DIV 37 +#define PERIPH_CLK_WD_PRE_DIV 38 +#define PERIPH_CLK_WD_DIV 39 +#define PERIPH_CLK_PDM_PRE_DIV 40 +#define PERIPH_CLK_PDM_DIV 41 +#define PERIPH_CLK_PWM_PRE_DIV 42 +#define PERIPH_CLK_PWM_DIV 43 +#define PERIPH_CLK_I2C0_PRE_DIV 44 +#define PERIPH_CLK_I2C0_DIV 45 +#define PERIPH_CLK_I2C1_PRE_DIV 46 +#define PERIPH_CLK_I2C1_DIV 47 +#define PERIPH_CLK_I2C2_PRE_DIV 48 +#define PERIPH_CLK_I2C2_DIV 49 +#define PERIPH_CLK_I2C3_PRE_DIV 50 +#define PERIPH_CLK_I2C3_DIV 51 + +#define PERIPH_CLK_NR_CLKS 52 + +/* System gate clocks */ +#define SYS_CLK_I2C0 0 +#define SYS_CLK_I2C1 1 +#define SYS_CLK_I2C2 2 +#define SYS_CLK_I2C3 3 +#define SYS_CLK_I2S_IN 4 +#define SYS_CLK_PAUD_OUT 5 +#define SYS_CLK_SPDIF_OUT 6 +#define SYS_CLK_SPI0_MASTER 7 +#define SYS_CLK_SPI0_SLAVE 8 +#define SYS_CLK_PWM 9 +#define SYS_CLK_UART0 10 +#define SYS_CLK_UART1 11 +#define SYS_CLK_SPI1 12 +#define SYS_CLK_MDC 13 +#define SYS_CLK_SD_HOST 14 +#define SYS_CLK_ENET 15 +#define SYS_CLK_IR 16 +#define SYS_CLK_WD 17 +#define SYS_CLK_TIMER 18 +#define SYS_CLK_I2S_OUT 24 +#define SYS_CLK_SPDIF_IN 25 +#define SYS_CLK_EVENT_TIMER 26 +#define SYS_CLK_HASH 27 + +#define SYS_CLK_NR_CLKS 28 + +/* Gates for external input clocks */ +#define EXT_CLK_AUDIO_IN 0 +#define EXT_CLK_ENET_IN 1 + +#define EXT_CLK_NR_CLKS 2 + +#endif /* _DT_BINDINGS_CLOCK_PISTACHIO_H */ -- cgit v1.2.3-59-g8ed1b From 7e7d638ab1542d22ff9b14e56f323e1f6cd25cf1 Mon Sep 17 00:00:00 2001 From: Iyappan Subramanian Date: Wed, 25 Mar 2015 12:19:10 -0700 Subject: Documentation: dts: xgene: Update interrupt field description Signed-off-by: Iyappan Subramanian Signed-off-by: Keyur Chudgar Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/apm-xgene-enet.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/apm-xgene-enet.txt b/Documentation/devicetree/bindings/net/apm-xgene-enet.txt index dc7961b33076..f55aa280d34f 100644 --- a/Documentation/devicetree/bindings/net/apm-xgene-enet.txt +++ b/Documentation/devicetree/bindings/net/apm-xgene-enet.txt @@ -14,7 +14,10 @@ Required properties for all the ethernet interfaces: - "enet_csr": Ethernet control and status register address space - "ring_csr": Descriptor ring control and status register address space - "ring_cmd": Descriptor ring command register address space -- interrupts: Ethernet main interrupt +- interrupts: Two interrupt specifiers can be specified. + - First is the Rx interrupt. This irq is mandatory. + - Second is the Tx completion interrupt. + This is supported only on SGMII based 1GbE and 10GbE interfaces. - port-id: Port number (0 or 1) - clocks: Reference to the clock entry. - local-mac-address: MAC address assigned to this device -- cgit v1.2.3-59-g8ed1b From 1068eaaf2f64ffb44d97fbaa9ff7a4662b76cf9e Mon Sep 17 00:00:00 2001 From: James Hogan Date: Thu, 26 Jun 2014 13:56:52 +0100 Subject: MIPS: KVM: Implement PRid CP0 register access Implement access to the guest Processor Identification CP0 register using the KVM_GET_ONE_REG and KVM_SET_ONE_REG ioctls. This allows the owning process to modify and read back the value that is exposed to the guest in this register. Signed-off-by: James Hogan Cc: Paolo Bonzini Cc: Ralf Baechle Cc: Gleb Natapov Cc: linux-mips@linux-mips.org Cc: kvm@vger.kernel.org --- Documentation/virtual/kvm/api.txt | 1 + arch/mips/include/asm/kvm_host.h | 1 + arch/mips/kvm/mips.c | 7 +++++++ 3 files changed, 9 insertions(+) (limited to 'Documentation') diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 0d7fc66289a0..9a5f8a482db1 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -1967,6 +1967,7 @@ registers, find a list below: MIPS | KVM_REG_MIPS_CP0_STATUS | 32 MIPS | KVM_REG_MIPS_CP0_CAUSE | 32 MIPS | KVM_REG_MIPS_CP0_EPC | 64 + MIPS | KVM_REG_MIPS_CP0_PRID | 32 MIPS | KVM_REG_MIPS_CP0_CONFIG | 32 MIPS | KVM_REG_MIPS_CP0_CONFIG1 | 32 MIPS | KVM_REG_MIPS_CP0_CONFIG2 | 32 diff --git a/arch/mips/include/asm/kvm_host.h b/arch/mips/include/asm/kvm_host.h index 8fc3ba2872f0..26d91b0f3c3c 100644 --- a/arch/mips/include/asm/kvm_host.h +++ b/arch/mips/include/asm/kvm_host.h @@ -42,6 +42,7 @@ #define KVM_REG_MIPS_CP0_STATUS MIPS_CP0_32(12, 0) #define KVM_REG_MIPS_CP0_CAUSE MIPS_CP0_32(13, 0) #define KVM_REG_MIPS_CP0_EPC MIPS_CP0_64(14, 0) +#define KVM_REG_MIPS_CP0_PRID MIPS_CP0_32(15, 0) #define KVM_REG_MIPS_CP0_EBASE MIPS_CP0_64(15, 1) #define KVM_REG_MIPS_CP0_CONFIG MIPS_CP0_32(16, 0) #define KVM_REG_MIPS_CP0_CONFIG1 MIPS_CP0_32(16, 1) diff --git a/arch/mips/kvm/mips.c b/arch/mips/kvm/mips.c index 399b5517ecb8..fd620cc8a44c 100644 --- a/arch/mips/kvm/mips.c +++ b/arch/mips/kvm/mips.c @@ -505,6 +505,7 @@ static u64 kvm_mips_get_one_regs[] = { KVM_REG_MIPS_CP0_STATUS, KVM_REG_MIPS_CP0_CAUSE, KVM_REG_MIPS_CP0_EPC, + KVM_REG_MIPS_CP0_PRID, KVM_REG_MIPS_CP0_CONFIG, KVM_REG_MIPS_CP0_CONFIG1, KVM_REG_MIPS_CP0_CONFIG2, @@ -574,6 +575,9 @@ static int kvm_mips_get_reg(struct kvm_vcpu *vcpu, case KVM_REG_MIPS_CP0_EPC: v = (long)kvm_read_c0_guest_epc(cop0); break; + case KVM_REG_MIPS_CP0_PRID: + v = (long)kvm_read_c0_guest_prid(cop0); + break; case KVM_REG_MIPS_CP0_ERROREPC: v = (long)kvm_read_c0_guest_errorepc(cop0); break; @@ -687,6 +691,9 @@ static int kvm_mips_set_reg(struct kvm_vcpu *vcpu, case KVM_REG_MIPS_CP0_EPC: kvm_write_c0_guest_epc(cop0, v); break; + case KVM_REG_MIPS_CP0_PRID: + kvm_write_c0_guest_prid(cop0, v); + break; case KVM_REG_MIPS_CP0_ERROREPC: kvm_write_c0_guest_errorepc(cop0, v); break; -- cgit v1.2.3-59-g8ed1b From c771607af959f282704268a209743560d3264eb3 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Thu, 26 Jun 2014 15:11:29 +0100 Subject: MIPS: KVM: Add Config4/5 and writing of Config registers Add Config4 and Config5 co-processor 0 registers, and add capability to write the Config1, Config3, Config4, and Config5 registers using the KVM API. Only supported bits can be written, to minimise the chances of the guest being given a configuration from e.g. QEMU that is inconsistent with that being emulated, and as such the handling is in trap_emul.c as it may need to be different for VZ. Currently the only modification permitted is to make Config4 and Config5 exist via the M bits, but other bits will be added for FPU and MSA support in future patches. Care should be taken by userland not to change bits without fully handling the possible extra state that may then exist and which the guest may begin to use and depend on. Signed-off-by: James Hogan Cc: Paolo Bonzini Cc: Ralf Baechle Cc: Gleb Natapov Cc: linux-mips@linux-mips.org Cc: kvm@vger.kernel.org --- Documentation/virtual/kvm/api.txt | 2 ++ arch/mips/include/asm/kvm_host.h | 13 ++++++++++ arch/mips/kvm/emulate.c | 52 +++++++++++++++++++++++++++++++++++++++ arch/mips/kvm/mips.c | 14 +++++++++++ arch/mips/kvm/trap_emul.c | 49 ++++++++++++++++++++++++++++++++++-- 5 files changed, 128 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 9a5f8a482db1..3f295a04b09f 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -1972,6 +1972,8 @@ registers, find a list below: MIPS | KVM_REG_MIPS_CP0_CONFIG1 | 32 MIPS | KVM_REG_MIPS_CP0_CONFIG2 | 32 MIPS | KVM_REG_MIPS_CP0_CONFIG3 | 32 + MIPS | KVM_REG_MIPS_CP0_CONFIG4 | 32 + MIPS | KVM_REG_MIPS_CP0_CONFIG5 | 32 MIPS | KVM_REG_MIPS_CP0_CONFIG7 | 32 MIPS | KVM_REG_MIPS_CP0_ERROREPC | 64 MIPS | KVM_REG_MIPS_COUNT_CTL | 64 diff --git a/arch/mips/include/asm/kvm_host.h b/arch/mips/include/asm/kvm_host.h index 6996447fd2a7..3f58ee1ebfab 100644 --- a/arch/mips/include/asm/kvm_host.h +++ b/arch/mips/include/asm/kvm_host.h @@ -48,6 +48,8 @@ #define KVM_REG_MIPS_CP0_CONFIG1 MIPS_CP0_32(16, 1) #define KVM_REG_MIPS_CP0_CONFIG2 MIPS_CP0_32(16, 2) #define KVM_REG_MIPS_CP0_CONFIG3 MIPS_CP0_32(16, 3) +#define KVM_REG_MIPS_CP0_CONFIG4 MIPS_CP0_32(16, 4) +#define KVM_REG_MIPS_CP0_CONFIG5 MIPS_CP0_32(16, 5) #define KVM_REG_MIPS_CP0_CONFIG7 MIPS_CP0_32(16, 7) #define KVM_REG_MIPS_CP0_XCONTEXT MIPS_CP0_64(20, 0) #define KVM_REG_MIPS_CP0_ERROREPC MIPS_CP0_64(30, 0) @@ -209,6 +211,8 @@ struct mips_coproc { #define MIPS_CP0_CONFIG1_SEL 1 #define MIPS_CP0_CONFIG2_SEL 2 #define MIPS_CP0_CONFIG3_SEL 3 +#define MIPS_CP0_CONFIG4_SEL 4 +#define MIPS_CP0_CONFIG5_SEL 5 /* Config0 register bits */ #define CP0C0_M 31 @@ -461,11 +465,15 @@ struct kvm_vcpu_arch { #define kvm_read_c0_guest_config1(cop0) (cop0->reg[MIPS_CP0_CONFIG][1]) #define kvm_read_c0_guest_config2(cop0) (cop0->reg[MIPS_CP0_CONFIG][2]) #define kvm_read_c0_guest_config3(cop0) (cop0->reg[MIPS_CP0_CONFIG][3]) +#define kvm_read_c0_guest_config4(cop0) (cop0->reg[MIPS_CP0_CONFIG][4]) +#define kvm_read_c0_guest_config5(cop0) (cop0->reg[MIPS_CP0_CONFIG][5]) #define kvm_read_c0_guest_config7(cop0) (cop0->reg[MIPS_CP0_CONFIG][7]) #define kvm_write_c0_guest_config(cop0, val) (cop0->reg[MIPS_CP0_CONFIG][0] = (val)) #define kvm_write_c0_guest_config1(cop0, val) (cop0->reg[MIPS_CP0_CONFIG][1] = (val)) #define kvm_write_c0_guest_config2(cop0, val) (cop0->reg[MIPS_CP0_CONFIG][2] = (val)) #define kvm_write_c0_guest_config3(cop0, val) (cop0->reg[MIPS_CP0_CONFIG][3] = (val)) +#define kvm_write_c0_guest_config4(cop0, val) (cop0->reg[MIPS_CP0_CONFIG][4] = (val)) +#define kvm_write_c0_guest_config5(cop0, val) (cop0->reg[MIPS_CP0_CONFIG][5] = (val)) #define kvm_write_c0_guest_config7(cop0, val) (cop0->reg[MIPS_CP0_CONFIG][7] = (val)) #define kvm_read_c0_guest_errorepc(cop0) (cop0->reg[MIPS_CP0_ERROR_PC][0]) #define kvm_write_c0_guest_errorepc(cop0, val) (cop0->reg[MIPS_CP0_ERROR_PC][0] = (val)) @@ -735,6 +743,11 @@ enum emulation_result kvm_mips_emulate_load(uint32_t inst, struct kvm_run *run, struct kvm_vcpu *vcpu); +unsigned int kvm_mips_config1_wrmask(struct kvm_vcpu *vcpu); +unsigned int kvm_mips_config3_wrmask(struct kvm_vcpu *vcpu); +unsigned int kvm_mips_config4_wrmask(struct kvm_vcpu *vcpu); +unsigned int kvm_mips_config5_wrmask(struct kvm_vcpu *vcpu); + /* Dynamic binary translation */ extern int kvm_mips_trans_cache_index(uint32_t inst, uint32_t *opc, struct kvm_vcpu *vcpu); diff --git a/arch/mips/kvm/emulate.c b/arch/mips/kvm/emulate.c index 33e132dc7de8..91d5b0e370b4 100644 --- a/arch/mips/kvm/emulate.c +++ b/arch/mips/kvm/emulate.c @@ -884,6 +884,58 @@ enum emulation_result kvm_mips_emul_tlbp(struct kvm_vcpu *vcpu) return EMULATE_DONE; } +/** + * kvm_mips_config1_wrmask() - Find mask of writable bits in guest Config1 + * @vcpu: Virtual CPU. + * + * Finds the mask of bits which are writable in the guest's Config1 CP0 + * register, by userland (currently read-only to the guest). + */ +unsigned int kvm_mips_config1_wrmask(struct kvm_vcpu *vcpu) +{ + /* Read-only */ + return 0; +} + +/** + * kvm_mips_config3_wrmask() - Find mask of writable bits in guest Config3 + * @vcpu: Virtual CPU. + * + * Finds the mask of bits which are writable in the guest's Config3 CP0 + * register, by userland (currently read-only to the guest). + */ +unsigned int kvm_mips_config3_wrmask(struct kvm_vcpu *vcpu) +{ + /* Config4 is optional */ + return MIPS_CONF_M; +} + +/** + * kvm_mips_config4_wrmask() - Find mask of writable bits in guest Config4 + * @vcpu: Virtual CPU. + * + * Finds the mask of bits which are writable in the guest's Config4 CP0 + * register, by userland (currently read-only to the guest). + */ +unsigned int kvm_mips_config4_wrmask(struct kvm_vcpu *vcpu) +{ + /* Config5 is optional */ + return MIPS_CONF_M; +} + +/** + * kvm_mips_config5_wrmask() - Find mask of writable bits in guest Config5 + * @vcpu: Virtual CPU. + * + * Finds the mask of bits which are writable in the guest's Config5 CP0 + * register, by the guest itself. + */ +unsigned int kvm_mips_config5_wrmask(struct kvm_vcpu *vcpu) +{ + /* Read-only */ + return 0; +} + enum emulation_result kvm_mips_emulate_CP0(uint32_t inst, uint32_t *opc, uint32_t cause, struct kvm_run *run, struct kvm_vcpu *vcpu) diff --git a/arch/mips/kvm/mips.c b/arch/mips/kvm/mips.c index 0aab83d894ba..73eecc779454 100644 --- a/arch/mips/kvm/mips.c +++ b/arch/mips/kvm/mips.c @@ -510,6 +510,8 @@ static u64 kvm_mips_get_one_regs[] = { KVM_REG_MIPS_CP0_CONFIG1, KVM_REG_MIPS_CP0_CONFIG2, KVM_REG_MIPS_CP0_CONFIG3, + KVM_REG_MIPS_CP0_CONFIG4, + KVM_REG_MIPS_CP0_CONFIG5, KVM_REG_MIPS_CP0_CONFIG7, KVM_REG_MIPS_CP0_ERROREPC, @@ -590,6 +592,12 @@ static int kvm_mips_get_reg(struct kvm_vcpu *vcpu, case KVM_REG_MIPS_CP0_CONFIG3: v = (long)kvm_read_c0_guest_config3(cop0); break; + case KVM_REG_MIPS_CP0_CONFIG4: + v = (long)kvm_read_c0_guest_config4(cop0); + break; + case KVM_REG_MIPS_CP0_CONFIG5: + v = (long)kvm_read_c0_guest_config5(cop0); + break; case KVM_REG_MIPS_CP0_CONFIG7: v = (long)kvm_read_c0_guest_config7(cop0); break; @@ -701,6 +709,12 @@ static int kvm_mips_set_reg(struct kvm_vcpu *vcpu, case KVM_REG_MIPS_CP0_COUNT: case KVM_REG_MIPS_CP0_COMPARE: case KVM_REG_MIPS_CP0_CAUSE: + case KVM_REG_MIPS_CP0_CONFIG: + case KVM_REG_MIPS_CP0_CONFIG1: + case KVM_REG_MIPS_CP0_CONFIG2: + case KVM_REG_MIPS_CP0_CONFIG3: + case KVM_REG_MIPS_CP0_CONFIG4: + case KVM_REG_MIPS_CP0_CONFIG5: case KVM_REG_MIPS_COUNT_CTL: case KVM_REG_MIPS_COUNT_RESUME: case KVM_REG_MIPS_COUNT_HZ: diff --git a/arch/mips/kvm/trap_emul.c b/arch/mips/kvm/trap_emul.c index bffba002d1a4..8e0968428a78 100644 --- a/arch/mips/kvm/trap_emul.c +++ b/arch/mips/kvm/trap_emul.c @@ -418,8 +418,14 @@ static int kvm_trap_emul_vcpu_setup(struct kvm_vcpu *vcpu) kvm_write_c0_guest_config2(cop0, MIPS_CONF_M); /* MIPS_CONF_M | (read_c0_config2() & 0xfff) */ - /* No config4, UserLocal */ - kvm_write_c0_guest_config3(cop0, MIPS_CONF3_ULRI); + /* Have config4, UserLocal */ + kvm_write_c0_guest_config3(cop0, MIPS_CONF_M | MIPS_CONF3_ULRI); + + /* Have config5 */ + kvm_write_c0_guest_config4(cop0, MIPS_CONF_M); + + /* No config6 */ + kvm_write_c0_guest_config5(cop0, 0); /* Set Wait IE/IXMT Ignore in Config7, IAR, AR */ kvm_write_c0_guest_config7(cop0, (MIPS_CONF7_WII) | (1 << 10)); @@ -464,6 +470,7 @@ static int kvm_trap_emul_set_one_reg(struct kvm_vcpu *vcpu, { struct mips_coproc *cop0 = vcpu->arch.cop0; int ret = 0; + unsigned int cur, change; switch (reg->id) { case KVM_REG_MIPS_CP0_COUNT: @@ -492,6 +499,44 @@ static int kvm_trap_emul_set_one_reg(struct kvm_vcpu *vcpu, kvm_write_c0_guest_cause(cop0, v); } break; + case KVM_REG_MIPS_CP0_CONFIG: + /* read-only for now */ + break; + case KVM_REG_MIPS_CP0_CONFIG1: + cur = kvm_read_c0_guest_config1(cop0); + change = (cur ^ v) & kvm_mips_config1_wrmask(vcpu); + if (change) { + v = cur ^ change; + kvm_write_c0_guest_config1(cop0, v); + } + break; + case KVM_REG_MIPS_CP0_CONFIG2: + /* read-only for now */ + break; + case KVM_REG_MIPS_CP0_CONFIG3: + cur = kvm_read_c0_guest_config3(cop0); + change = (cur ^ v) & kvm_mips_config3_wrmask(vcpu); + if (change) { + v = cur ^ change; + kvm_write_c0_guest_config3(cop0, v); + } + break; + case KVM_REG_MIPS_CP0_CONFIG4: + cur = kvm_read_c0_guest_config4(cop0); + change = (cur ^ v) & kvm_mips_config4_wrmask(vcpu); + if (change) { + v = cur ^ change; + kvm_write_c0_guest_config4(cop0, v); + } + break; + case KVM_REG_MIPS_CP0_CONFIG5: + cur = kvm_read_c0_guest_config5(cop0); + change = (cur ^ v) & kvm_mips_config5_wrmask(vcpu); + if (change) { + v = cur ^ change; + kvm_write_c0_guest_config5(cop0, v); + } + break; case KVM_REG_MIPS_COUNT_CTL: ret = kvm_mips_set_count_ctl(vcpu, v); break; -- cgit v1.2.3-59-g8ed1b From 379245cdf1d1efc1eccc38bf0cc985dae232123d Mon Sep 17 00:00:00 2001 From: James Hogan Date: Tue, 2 Dec 2014 15:48:24 +0000 Subject: MIPS: KVM: Expose FPU registers Add KVM register numbers for the MIPS FPU registers, and implement access to them with the KVM_GET_ONE_REG / KVM_SET_ONE_REG ioctls when the FPU capability is enabled (exposed in a later patch) and present in the guest according to its Config1.FP bit. The registers are accessible in the current mode of the guest, with each sized access showing what the guest would see with an equivalent access, and like the architecture they may become UNPREDICTABLE if the FR mode is changed. When FR=0, odd doubles are inaccessible as they do not exist in that mode. Signed-off-by: James Hogan Acked-by: Paolo Bonzini Cc: Paul Burton Cc: Ralf Baechle Cc: Gleb Natapov Cc: Jonathan Corbet Cc: linux-mips@linux-mips.org Cc: kvm@vger.kernel.org Cc: linux-api@vger.kernel.org Cc: linux-doc@vger.kernel.org --- Documentation/virtual/kvm/api.txt | 16 +++++++++ arch/mips/include/uapi/asm/kvm.h | 37 ++++++++++++++------ arch/mips/kvm/mips.c | 72 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 114 insertions(+), 11 deletions(-) (limited to 'Documentation') diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 3f295a04b09f..f3c198360785 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -1979,6 +1979,10 @@ registers, find a list below: MIPS | KVM_REG_MIPS_COUNT_CTL | 64 MIPS | KVM_REG_MIPS_COUNT_RESUME | 64 MIPS | KVM_REG_MIPS_COUNT_HZ | 64 + MIPS | KVM_REG_MIPS_FPR_32(0..31) | 32 + MIPS | KVM_REG_MIPS_FPR_64(0..31) | 64 + MIPS | KVM_REG_MIPS_FCR_IR | 32 + MIPS | KVM_REG_MIPS_FCR_CSR | 32 ARM registers are mapped using the lower 32 bits. The upper 16 of that is the register group type, or coprocessor number: @@ -2032,6 +2036,18 @@ patterns depending on whether they're 32-bit or 64-bit registers: MIPS KVM control registers (see above) have the following id bit patterns: 0x7030 0000 0002 +MIPS FPU registers (see KVM_REG_MIPS_FPR_{32,64}() above) have the following +id bit patterns depending on the size of the register being accessed. They are +always accessed according to the current guest FPU mode (Status.FR and +Config5.FRE), i.e. as the guest would see them, and they become unpredictable +if the guest FPU mode is changed: + 0x7020 0000 0003 00 <0:3> (32-bit FPU registers) + 0x7030 0000 0003 00 <0:3> (64-bit FPU registers) + +MIPS FPU control registers (see KVM_REG_MIPS_FCR_{IR,CSR} above) have the +following id bit patterns: + 0x7020 0000 0003 01 <0:3> + 4.69 KVM_GET_ONE_REG diff --git a/arch/mips/include/uapi/asm/kvm.h b/arch/mips/include/uapi/asm/kvm.h index 75d6d8557e57..401e6a6f8bb8 100644 --- a/arch/mips/include/uapi/asm/kvm.h +++ b/arch/mips/include/uapi/asm/kvm.h @@ -36,18 +36,8 @@ struct kvm_regs { /* * for KVM_GET_FPU and KVM_SET_FPU - * - * If Status[FR] is zero (32-bit FPU), the upper 32-bits of the FPRs - * are zero filled. */ struct kvm_fpu { - __u64 fpr[32]; - __u32 fir; - __u32 fccr; - __u32 fexr; - __u32 fenr; - __u32 fcsr; - __u32 pad; }; @@ -68,6 +58,8 @@ struct kvm_fpu { * * Register set = 2: KVM specific registers (see definitions below). * + * Register set = 3: FPU registers (see definitions below). + * * Other sets registers may be added in the future. Each set would * have its own identifier in bits[31..16]. */ @@ -75,6 +67,7 @@ struct kvm_fpu { #define KVM_REG_MIPS_GP (KVM_REG_MIPS | 0x0000000000000000ULL) #define KVM_REG_MIPS_CP0 (KVM_REG_MIPS | 0x0000000000010000ULL) #define KVM_REG_MIPS_KVM (KVM_REG_MIPS | 0x0000000000020000ULL) +#define KVM_REG_MIPS_FPU (KVM_REG_MIPS | 0x0000000000030000ULL) /* @@ -154,6 +147,30 @@ struct kvm_fpu { #define KVM_REG_MIPS_COUNT_HZ (KVM_REG_MIPS_KVM | KVM_REG_SIZE_U64 | 2) +/* + * KVM_REG_MIPS_FPU - Floating Point registers. + * + * bits[15..8] - Register subset (see definitions below). + * bits[7..5] - Must be zero. + * bits[4..0] - Register number within register subset. + */ + +#define KVM_REG_MIPS_FPR (KVM_REG_MIPS_FPU | 0x0000000000000000ULL) +#define KVM_REG_MIPS_FCR (KVM_REG_MIPS_FPU | 0x0000000000000100ULL) + +/* + * KVM_REG_MIPS_FPR - Floating point / Vector registers. + */ +#define KVM_REG_MIPS_FPR_32(n) (KVM_REG_MIPS_FPR | KVM_REG_SIZE_U32 | (n)) +#define KVM_REG_MIPS_FPR_64(n) (KVM_REG_MIPS_FPR | KVM_REG_SIZE_U64 | (n)) + +/* + * KVM_REG_MIPS_FCR - Floating point control registers. + */ +#define KVM_REG_MIPS_FCR_IR (KVM_REG_MIPS_FCR | KVM_REG_SIZE_U32 | 0) +#define KVM_REG_MIPS_FCR_CSR (KVM_REG_MIPS_FCR | KVM_REG_SIZE_U32 | 31) + + /* * KVM MIPS specific structures and definitions * diff --git a/arch/mips/kvm/mips.c b/arch/mips/kvm/mips.c index dd0833833bea..5e41afe15ae8 100644 --- a/arch/mips/kvm/mips.c +++ b/arch/mips/kvm/mips.c @@ -526,10 +526,13 @@ static int kvm_mips_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) { struct mips_coproc *cop0 = vcpu->arch.cop0; + struct mips_fpu_struct *fpu = &vcpu->arch.fpu; int ret; s64 v; + unsigned int idx; switch (reg->id) { + /* General purpose registers */ case KVM_REG_MIPS_R0 ... KVM_REG_MIPS_R31: v = (long)vcpu->arch.gprs[reg->id - KVM_REG_MIPS_R0]; break; @@ -543,6 +546,38 @@ static int kvm_mips_get_reg(struct kvm_vcpu *vcpu, v = (long)vcpu->arch.pc; break; + /* Floating point registers */ + case KVM_REG_MIPS_FPR_32(0) ... KVM_REG_MIPS_FPR_32(31): + if (!kvm_mips_guest_has_fpu(&vcpu->arch)) + return -EINVAL; + idx = reg->id - KVM_REG_MIPS_FPR_32(0); + /* Odd singles in top of even double when FR=0 */ + if (kvm_read_c0_guest_status(cop0) & ST0_FR) + v = get_fpr32(&fpu->fpr[idx], 0); + else + v = get_fpr32(&fpu->fpr[idx & ~1], idx & 1); + break; + case KVM_REG_MIPS_FPR_64(0) ... KVM_REG_MIPS_FPR_64(31): + if (!kvm_mips_guest_has_fpu(&vcpu->arch)) + return -EINVAL; + idx = reg->id - KVM_REG_MIPS_FPR_64(0); + /* Can't access odd doubles in FR=0 mode */ + if (idx & 1 && !(kvm_read_c0_guest_status(cop0) & ST0_FR)) + return -EINVAL; + v = get_fpr64(&fpu->fpr[idx], 0); + break; + case KVM_REG_MIPS_FCR_IR: + if (!kvm_mips_guest_has_fpu(&vcpu->arch)) + return -EINVAL; + v = boot_cpu_data.fpu_id; + break; + case KVM_REG_MIPS_FCR_CSR: + if (!kvm_mips_guest_has_fpu(&vcpu->arch)) + return -EINVAL; + v = fpu->fcr31; + break; + + /* Co-processor 0 registers */ case KVM_REG_MIPS_CP0_INDEX: v = (long)kvm_read_c0_guest_index(cop0); break; @@ -636,7 +671,9 @@ static int kvm_mips_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) { struct mips_coproc *cop0 = vcpu->arch.cop0; - u64 v; + struct mips_fpu_struct *fpu = &vcpu->arch.fpu; + s64 v; + unsigned int idx; if ((reg->id & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U64) { u64 __user *uaddr64 = (u64 __user *)(long)reg->addr; @@ -655,6 +692,7 @@ static int kvm_mips_set_reg(struct kvm_vcpu *vcpu, } switch (reg->id) { + /* General purpose registers */ case KVM_REG_MIPS_R0: /* Silently ignore requests to set $0 */ break; @@ -671,6 +709,38 @@ static int kvm_mips_set_reg(struct kvm_vcpu *vcpu, vcpu->arch.pc = v; break; + /* Floating point registers */ + case KVM_REG_MIPS_FPR_32(0) ... KVM_REG_MIPS_FPR_32(31): + if (!kvm_mips_guest_has_fpu(&vcpu->arch)) + return -EINVAL; + idx = reg->id - KVM_REG_MIPS_FPR_32(0); + /* Odd singles in top of even double when FR=0 */ + if (kvm_read_c0_guest_status(cop0) & ST0_FR) + set_fpr32(&fpu->fpr[idx], 0, v); + else + set_fpr32(&fpu->fpr[idx & ~1], idx & 1, v); + break; + case KVM_REG_MIPS_FPR_64(0) ... KVM_REG_MIPS_FPR_64(31): + if (!kvm_mips_guest_has_fpu(&vcpu->arch)) + return -EINVAL; + idx = reg->id - KVM_REG_MIPS_FPR_64(0); + /* Can't access odd doubles in FR=0 mode */ + if (idx & 1 && !(kvm_read_c0_guest_status(cop0) & ST0_FR)) + return -EINVAL; + set_fpr64(&fpu->fpr[idx], 0, v); + break; + case KVM_REG_MIPS_FCR_IR: + if (!kvm_mips_guest_has_fpu(&vcpu->arch)) + return -EINVAL; + /* Read-only */ + break; + case KVM_REG_MIPS_FCR_CSR: + if (!kvm_mips_guest_has_fpu(&vcpu->arch)) + return -EINVAL; + fpu->fcr31 = v; + break; + + /* Co-processor 0 registers */ case KVM_REG_MIPS_CP0_INDEX: kvm_write_c0_guest_index(cop0, v); break; -- cgit v1.2.3-59-g8ed1b From 5fafd8748b366105e08c198892e9fe02ef15c021 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Mon, 8 Dec 2014 23:07:56 +0000 Subject: MIPS: KVM: Wire up FPU capability Now that the code is in place for KVM to support FPU in MIPS KVM guests, wire up the new KVM_CAP_MIPS_FPU capability. For backwards compatibility, the capability must be explicitly enabled in order to detect or make use of the FPU from the guest. Signed-off-by: James Hogan Cc: Paolo Bonzini Cc: Ralf Baechle Cc: Gleb Natapov Cc: Jonathan Corbet Cc: linux-mips@linux-mips.org Cc: kvm@vger.kernel.org Cc: linux-api@vger.kernel.org Cc: linux-doc@vger.kernel.org --- Documentation/virtual/kvm/api.txt | 13 +++++++++++++ arch/mips/kvm/mips.c | 37 +++++++++++++++++++++++++++++++++++++ include/uapi/linux/kvm.h | 1 + 3 files changed, 51 insertions(+) (limited to 'Documentation') diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index f3c198360785..a1e9bfa5fe9e 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -3312,6 +3312,19 @@ Parameters: none This capability enables the in-kernel irqchip for s390. Please refer to "4.24 KVM_CREATE_IRQCHIP" for details. +6.9 KVM_CAP_MIPS_FPU + +Architectures: mips +Target: vcpu +Parameters: args[0] is reserved for future use (should be 0). + +This capability allows the use of the host Floating Point Unit by the guest. It +allows the Config1.FP bit to be set to enable the FPU in the guest. Once this is +done the KVM_REG_MIPS_FPR_* and KVM_REG_MIPS_FCR_* registers can be accessed +(depending on the current guest FPU register mode), and the Status.FR, +Config5.FRE bits are accessible via the KVM API and also from the guest, +depending on them being supported by the FPU. + 7. Capabilities that can be enabled on VMs ------------------------------------------ diff --git a/arch/mips/kvm/mips.c b/arch/mips/kvm/mips.c index 5e41afe15ae8..7f86cb73d05d 100644 --- a/arch/mips/kvm/mips.c +++ b/arch/mips/kvm/mips.c @@ -797,6 +797,30 @@ static int kvm_mips_set_reg(struct kvm_vcpu *vcpu, return 0; } +static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, + struct kvm_enable_cap *cap) +{ + int r = 0; + + if (!kvm_vm_ioctl_check_extension(vcpu->kvm, cap->cap)) + return -EINVAL; + if (cap->flags) + return -EINVAL; + if (cap->args[0]) + return -EINVAL; + + switch (cap->cap) { + case KVM_CAP_MIPS_FPU: + vcpu->arch.fpu_enabled = true; + break; + default: + r = -EINVAL; + break; + } + + return r; +} + long kvm_arch_vcpu_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { @@ -854,6 +878,15 @@ long kvm_arch_vcpu_ioctl(struct file *filp, unsigned int ioctl, r = kvm_vcpu_ioctl_interrupt(vcpu, &irq); break; } + case KVM_ENABLE_CAP: { + struct kvm_enable_cap cap; + + r = -EFAULT; + if (copy_from_user(&cap, argp, sizeof(cap))) + goto out; + r = kvm_vcpu_ioctl_enable_cap(vcpu, &cap); + break; + } default: r = -ENOIOCTLCMD; } @@ -962,11 +995,15 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) switch (ext) { case KVM_CAP_ONE_REG: + case KVM_CAP_ENABLE_CAP: r = 1; break; case KVM_CAP_COALESCED_MMIO: r = KVM_COALESCED_MMIO_PAGE_OFFSET; break; + case KVM_CAP_MIPS_FPU: + r = !!cpu_has_fpu; + break; default: r = 0; break; diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 1162ef7a3fa1..ce49688976d2 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -802,6 +802,7 @@ struct kvm_ppc_smmu_info { #define KVM_CAP_S390_MEM_OP 108 #define KVM_CAP_S390_USER_STSI 109 #define KVM_CAP_S390_SKEYS 110 +#define KVM_CAP_MIPS_FPU 111 #ifdef KVM_CAP_IRQ_ROUTING -- cgit v1.2.3-59-g8ed1b From ab86bd600400357ffa0dfdb1797f587476d01352 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Tue, 2 Dec 2014 15:48:24 +0000 Subject: MIPS: KVM: Expose MSA registers Add KVM register numbers for the MIPS SIMD Architecture (MSA) registers, and implement access to them with the KVM_GET_ONE_REG / KVM_SET_ONE_REG ioctls when the MSA capability is enabled (exposed in a later patch) and present in the guest according to its Config3.MSAP bit. The MSA vector registers use the same register numbers as the FPU registers except with a different size (128bits). Since MSA depends on Status.FR=1, these registers are inaccessible when Status.FR=0. These registers are returned as a single native endian 128bit value, rather than least significant half first with each 64-bit half native endian as the kernel uses internally. Signed-off-by: James Hogan Cc: Paolo Bonzini Cc: Paul Burton Cc: Ralf Baechle Cc: Gleb Natapov Cc: Jonathan Corbet Cc: linux-mips@linux-mips.org Cc: kvm@vger.kernel.org Cc: linux-api@vger.kernel.org Cc: linux-doc@vger.kernel.org --- Documentation/virtual/kvm/api.txt | 12 +++++++- arch/mips/include/uapi/asm/kvm.h | 12 ++++++-- arch/mips/kvm/mips.c | 65 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index a1e9bfa5fe9e..62809871814b 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -1981,8 +1981,11 @@ registers, find a list below: MIPS | KVM_REG_MIPS_COUNT_HZ | 64 MIPS | KVM_REG_MIPS_FPR_32(0..31) | 32 MIPS | KVM_REG_MIPS_FPR_64(0..31) | 64 + MIPS | KVM_REG_MIPS_VEC_128(0..31) | 128 MIPS | KVM_REG_MIPS_FCR_IR | 32 MIPS | KVM_REG_MIPS_FCR_CSR | 32 + MIPS | KVM_REG_MIPS_MSA_IR | 32 + MIPS | KVM_REG_MIPS_MSA_CSR | 32 ARM registers are mapped using the lower 32 bits. The upper 16 of that is the register group type, or coprocessor number: @@ -2040,14 +2043,21 @@ MIPS FPU registers (see KVM_REG_MIPS_FPR_{32,64}() above) have the following id bit patterns depending on the size of the register being accessed. They are always accessed according to the current guest FPU mode (Status.FR and Config5.FRE), i.e. as the guest would see them, and they become unpredictable -if the guest FPU mode is changed: +if the guest FPU mode is changed. MIPS SIMD Architecture (MSA) vector +registers (see KVM_REG_MIPS_VEC_128() above) have similar patterns as they +overlap the FPU registers: 0x7020 0000 0003 00 <0:3> (32-bit FPU registers) 0x7030 0000 0003 00 <0:3> (64-bit FPU registers) + 0x7040 0000 0003 00 <0:3> (128-bit MSA vector registers) MIPS FPU control registers (see KVM_REG_MIPS_FCR_{IR,CSR} above) have the following id bit patterns: 0x7020 0000 0003 01 <0:3> +MIPS MSA control registers (see KVM_REG_MIPS_MSA_{IR,CSR} above) have the +following id bit patterns: + 0x7020 0000 0003 02 <0:3> + 4.69 KVM_GET_ONE_REG diff --git a/arch/mips/include/uapi/asm/kvm.h b/arch/mips/include/uapi/asm/kvm.h index 401e6a6f8bb8..6985eb59b085 100644 --- a/arch/mips/include/uapi/asm/kvm.h +++ b/arch/mips/include/uapi/asm/kvm.h @@ -58,7 +58,7 @@ struct kvm_fpu { * * Register set = 2: KVM specific registers (see definitions below). * - * Register set = 3: FPU registers (see definitions below). + * Register set = 3: FPU / MSA registers (see definitions below). * * Other sets registers may be added in the future. Each set would * have its own identifier in bits[31..16]. @@ -148,7 +148,7 @@ struct kvm_fpu { /* - * KVM_REG_MIPS_FPU - Floating Point registers. + * KVM_REG_MIPS_FPU - Floating Point and MIPS SIMD Architecture (MSA) registers. * * bits[15..8] - Register subset (see definitions below). * bits[7..5] - Must be zero. @@ -157,12 +157,14 @@ struct kvm_fpu { #define KVM_REG_MIPS_FPR (KVM_REG_MIPS_FPU | 0x0000000000000000ULL) #define KVM_REG_MIPS_FCR (KVM_REG_MIPS_FPU | 0x0000000000000100ULL) +#define KVM_REG_MIPS_MSACR (KVM_REG_MIPS_FPU | 0x0000000000000200ULL) /* * KVM_REG_MIPS_FPR - Floating point / Vector registers. */ #define KVM_REG_MIPS_FPR_32(n) (KVM_REG_MIPS_FPR | KVM_REG_SIZE_U32 | (n)) #define KVM_REG_MIPS_FPR_64(n) (KVM_REG_MIPS_FPR | KVM_REG_SIZE_U64 | (n)) +#define KVM_REG_MIPS_VEC_128(n) (KVM_REG_MIPS_FPR | KVM_REG_SIZE_U128 | (n)) /* * KVM_REG_MIPS_FCR - Floating point control registers. @@ -170,6 +172,12 @@ struct kvm_fpu { #define KVM_REG_MIPS_FCR_IR (KVM_REG_MIPS_FCR | KVM_REG_SIZE_U32 | 0) #define KVM_REG_MIPS_FCR_CSR (KVM_REG_MIPS_FCR | KVM_REG_SIZE_U32 | 31) +/* + * KVM_REG_MIPS_MSACR - MIPS SIMD Architecture (MSA) control registers. + */ +#define KVM_REG_MIPS_MSA_IR (KVM_REG_MIPS_MSACR | KVM_REG_SIZE_U32 | 0) +#define KVM_REG_MIPS_MSA_CSR (KVM_REG_MIPS_MSACR | KVM_REG_SIZE_U32 | 1) + /* * KVM MIPS specific structures and definitions diff --git a/arch/mips/kvm/mips.c b/arch/mips/kvm/mips.c index e02c7e5a12ff..35d3146895f1 100644 --- a/arch/mips/kvm/mips.c +++ b/arch/mips/kvm/mips.c @@ -531,6 +531,7 @@ static int kvm_mips_get_reg(struct kvm_vcpu *vcpu, struct mips_fpu_struct *fpu = &vcpu->arch.fpu; int ret; s64 v; + s64 vs[2]; unsigned int idx; switch (reg->id) { @@ -579,6 +580,35 @@ static int kvm_mips_get_reg(struct kvm_vcpu *vcpu, v = fpu->fcr31; break; + /* MIPS SIMD Architecture (MSA) registers */ + case KVM_REG_MIPS_VEC_128(0) ... KVM_REG_MIPS_VEC_128(31): + if (!kvm_mips_guest_has_msa(&vcpu->arch)) + return -EINVAL; + /* Can't access MSA registers in FR=0 mode */ + if (!(kvm_read_c0_guest_status(cop0) & ST0_FR)) + return -EINVAL; + idx = reg->id - KVM_REG_MIPS_VEC_128(0); +#ifdef CONFIG_CPU_LITTLE_ENDIAN + /* least significant byte first */ + vs[0] = get_fpr64(&fpu->fpr[idx], 0); + vs[1] = get_fpr64(&fpu->fpr[idx], 1); +#else + /* most significant byte first */ + vs[0] = get_fpr64(&fpu->fpr[idx], 1); + vs[1] = get_fpr64(&fpu->fpr[idx], 0); +#endif + break; + case KVM_REG_MIPS_MSA_IR: + if (!kvm_mips_guest_has_msa(&vcpu->arch)) + return -EINVAL; + v = boot_cpu_data.msa_id; + break; + case KVM_REG_MIPS_MSA_CSR: + if (!kvm_mips_guest_has_msa(&vcpu->arch)) + return -EINVAL; + v = fpu->msacsr; + break; + /* Co-processor 0 registers */ case KVM_REG_MIPS_CP0_INDEX: v = (long)kvm_read_c0_guest_index(cop0); @@ -664,6 +694,10 @@ static int kvm_mips_get_reg(struct kvm_vcpu *vcpu, u32 v32 = (u32)v; return put_user(v32, uaddr32); + } else if ((reg->id & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U128) { + void __user *uaddr = (void __user *)(long)reg->addr; + + return copy_to_user(uaddr, vs, 16); } else { return -EINVAL; } @@ -675,6 +709,7 @@ static int kvm_mips_set_reg(struct kvm_vcpu *vcpu, struct mips_coproc *cop0 = vcpu->arch.cop0; struct mips_fpu_struct *fpu = &vcpu->arch.fpu; s64 v; + s64 vs[2]; unsigned int idx; if ((reg->id & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U64) { @@ -689,6 +724,10 @@ static int kvm_mips_set_reg(struct kvm_vcpu *vcpu, if (get_user(v32, uaddr32) != 0) return -EFAULT; v = (s64)v32; + } else if ((reg->id & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U128) { + void __user *uaddr = (void __user *)(long)reg->addr; + + return copy_from_user(vs, uaddr, 16); } else { return -EINVAL; } @@ -742,6 +781,32 @@ static int kvm_mips_set_reg(struct kvm_vcpu *vcpu, fpu->fcr31 = v; break; + /* MIPS SIMD Architecture (MSA) registers */ + case KVM_REG_MIPS_VEC_128(0) ... KVM_REG_MIPS_VEC_128(31): + if (!kvm_mips_guest_has_msa(&vcpu->arch)) + return -EINVAL; + idx = reg->id - KVM_REG_MIPS_VEC_128(0); +#ifdef CONFIG_CPU_LITTLE_ENDIAN + /* least significant byte first */ + set_fpr64(&fpu->fpr[idx], 0, vs[0]); + set_fpr64(&fpu->fpr[idx], 1, vs[1]); +#else + /* most significant byte first */ + set_fpr64(&fpu->fpr[idx], 1, vs[0]); + set_fpr64(&fpu->fpr[idx], 0, vs[1]); +#endif + break; + case KVM_REG_MIPS_MSA_IR: + if (!kvm_mips_guest_has_msa(&vcpu->arch)) + return -EINVAL; + /* Read-only */ + break; + case KVM_REG_MIPS_MSA_CSR: + if (!kvm_mips_guest_has_msa(&vcpu->arch)) + return -EINVAL; + fpu->msacsr = v; + break; + /* Co-processor 0 registers */ case KVM_REG_MIPS_CP0_INDEX: kvm_write_c0_guest_index(cop0, v); -- cgit v1.2.3-59-g8ed1b From d952bd070f79b6dcbad52c03dbc41cbc8ba086c8 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Mon, 8 Dec 2014 23:07:56 +0000 Subject: MIPS: KVM: Wire up MSA capability Now that the code is in place for KVM to support MIPS SIMD Architecutre (MSA) in MIPS guests, wire up the new KVM_CAP_MIPS_MSA capability. For backwards compatibility, the capability must be explicitly enabled in order to detect or make use of MSA from the guest. The capability is not supported if the hardware supports MSA vector partitioning, since the extra support cannot be tested yet and it extends the state that the userland program would have to save. Signed-off-by: James Hogan Acked-by: Paolo Bonzini Cc: Ralf Baechle Cc: Gleb Natapov Cc: Jonathan Corbet Cc: linux-mips@linux-mips.org Cc: kvm@vger.kernel.org Cc: linux-api@vger.kernel.org Cc: linux-doc@vger.kernel.org --- Documentation/virtual/kvm/api.txt | 12 ++++++++++++ arch/mips/kvm/mips.c | 18 ++++++++++++++++++ include/uapi/linux/kvm.h | 1 + 3 files changed, 31 insertions(+) (limited to 'Documentation') diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 62809871814b..1490eb0ef798 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -3335,6 +3335,18 @@ done the KVM_REG_MIPS_FPR_* and KVM_REG_MIPS_FCR_* registers can be accessed Config5.FRE bits are accessible via the KVM API and also from the guest, depending on them being supported by the FPU. +6.10 KVM_CAP_MIPS_MSA + +Architectures: mips +Target: vcpu +Parameters: args[0] is reserved for future use (should be 0). + +This capability allows the use of the MIPS SIMD Architecture (MSA) by the guest. +It allows the Config3.MSAP bit to be set to enable the use of MSA by the guest. +Once this is done the KVM_REG_MIPS_VEC_* and KVM_REG_MIPS_MSA_* registers can be +accessed, and the Config5.MSAEn bit is accessible via the KVM API and also from +the guest. + 7. Capabilities that can be enabled on VMs ------------------------------------------ diff --git a/arch/mips/kvm/mips.c b/arch/mips/kvm/mips.c index 35d3146895f1..bb68e8d520e8 100644 --- a/arch/mips/kvm/mips.c +++ b/arch/mips/kvm/mips.c @@ -880,6 +880,9 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, case KVM_CAP_MIPS_FPU: vcpu->arch.fpu_enabled = true; break; + case KVM_CAP_MIPS_MSA: + vcpu->arch.msa_enabled = true; + break; default: r = -EINVAL; break; @@ -1071,6 +1074,21 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_MIPS_FPU: r = !!cpu_has_fpu; break; + case KVM_CAP_MIPS_MSA: + /* + * We don't support MSA vector partitioning yet: + * 1) It would require explicit support which can't be tested + * yet due to lack of support in current hardware. + * 2) It extends the state that would need to be saved/restored + * by e.g. QEMU for migration. + * + * When vector partitioning hardware becomes available, support + * could be added by requiring a flag when enabling + * KVM_CAP_MIPS_MSA capability to indicate that userland knows + * to save/restore the appropriate extra state. + */ + r = cpu_has_msa && !(boot_cpu_data.msa_id & MSA_IR_WRPF); + break; default: r = 0; break; diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index ce49688976d2..05a2083f7a28 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -803,6 +803,7 @@ struct kvm_ppc_smmu_info { #define KVM_CAP_S390_USER_STSI 109 #define KVM_CAP_S390_SKEYS 110 #define KVM_CAP_MIPS_FPU 111 +#define KVM_CAP_MIPS_MSA 112 #ifdef KVM_CAP_IRQ_ROUTING -- cgit v1.2.3-59-g8ed1b From 415f1cb29d3be865b034b528058c7115bc262f43 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 26 Mar 2015 04:01:27 +0000 Subject: ASoC: rsrc-card: add Renesas sampling rate convert sound card support Renesas sound card has "sampling rate convert" feature which should be implemented via DPCM. But, sound card driver point of view, it is difficult to add this DPCM feature on simple-card driver. Especially, DT binding support is very difficult. This patch implements DPCM feature on DT as Renesas specific sound card. This new driver is copied from current simple-card driver. Main difference between simple-card and this driver are... 1. removed unused feature from simple-card 2. removed driver named prefix from DT property 3. CPU will be FE, CODEC will be BE with snd-soc-dummy 4. it supports sampling rate convert via .be_hw_params_fixup 5. board specific routing is implemented in driver Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- .../bindings/sound/renesas,rsrc-card.txt | 66 +++ sound/soc/sh/Kconfig | 5 + sound/soc/sh/rcar/Makefile | 5 +- sound/soc/sh/rcar/rsrc-card.c | 489 +++++++++++++++++++++ 4 files changed, 564 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt create mode 100644 sound/soc/sh/rcar/rsrc-card.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt b/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt new file mode 100644 index 000000000000..12e287ed4dce --- /dev/null +++ b/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt @@ -0,0 +1,66 @@ +Renesas Sampling Rate Convert Sound Card: + +Renesas Sampling Rate Convert Sound Card specifies audio DAI connections of SoC <-> codec. + +Required properties: + +- compatible : "renesas,rsrc-card," + Examples with soctypes are: + - "renesas,rsrc-card,lager" + - "renesas,rsrc-card,koelsch" +Optional properties: + +- card_name : User specified audio sound card name, one string + property. +- cpu : CPU sub-node +- codec : CODEC sub-node + +Optional subnode properties: + +- format : CPU/CODEC common audio format. + "i2s", "right_j", "left_j" , "dsp_a" + "dsp_b", "ac97", "pdm", "msb", "lsb" +- frame-master : Indicates dai-link frame master. + phandle to a cpu or codec subnode. +- bitclock-master : Indicates dai-link bit clock master. + phandle to a cpu or codec subnode. +- bitclock-inversion : bool property. Add this if the + dai-link uses bit clock inversion. +- frame-inversion : bool property. Add this if the + dai-link uses frame clock inversion. + +Required CPU/CODEC subnodes properties: + +- sound-dai : phandle and port of CPU/CODEC + +Optional CPU/CODEC subnodes properties: + +- clocks / system-clock-frequency : specify subnode's clock if needed. + it can be specified via "clocks" if system has + clock node (= common clock), or "system-clock-frequency" + (if system doens't support common clock) + If a clock is specified, it is + enabled with clk_prepare_enable() + in dai startup() and disabled with + clk_disable_unprepare() in dai + shutdown(). + +Example + +sound { + compatible = "renesas,rsrc-card,lager"; + + card-name = "rsnd-ak4643"; + format = "left_j"; + bitclock-master = <&sndcodec>; + frame-master = <&sndcodec>; + + sndcpu: cpu { + sound-dai = <&rcar_sound>; + }; + + sndcodec: codec { + sound-dai = <&ak4643>; + system-clock-frequency = <11289600>; + }; +}; diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig index 80245b6eebd6..2b3030415573 100644 --- a/sound/soc/sh/Kconfig +++ b/sound/soc/sh/Kconfig @@ -41,6 +41,11 @@ config SND_SOC_RCAR help This option enables R-Car SUR/SCU/SSIU/SSI sound support +config SND_SOC_RSRC_CARD + tristate "Renesas Sampling Rate Convert Sound Card" + help + This option enables simple sound if you need sampling rate convert + ## ## Boards ## diff --git a/sound/soc/sh/rcar/Makefile b/sound/soc/sh/rcar/Makefile index 7b204925b8c5..f1b445173fba 100644 --- a/sound/soc/sh/rcar/Makefile +++ b/sound/soc/sh/rcar/Makefile @@ -1,2 +1,5 @@ snd-soc-rcar-objs := core.o gen.o dma.o src.o adg.o ssi.o dvc.o -obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o \ No newline at end of file +obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o + +snd-soc-rsrc-card-objs := rsrc-card.o +obj-$(CONFIG_SND_SOC_RSRC_CARD) += snd-soc-rsrc-card.o diff --git a/sound/soc/sh/rcar/rsrc-card.c b/sound/soc/sh/rcar/rsrc-card.c new file mode 100644 index 000000000000..3baeab726bc3 --- /dev/null +++ b/sound/soc/sh/rcar/rsrc-card.c @@ -0,0 +1,489 @@ +/* + * Renesas Sampling Rate Convert Sound Card for DPCM + * + * Copyright (C) 2015 Renesas Solutions Corp. + * Kuninori Morimoto + * + * based on ${LINUX}/sound/soc/generic/simple-card.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct rsrc_card_of_data { + const char *prefix; + const struct snd_soc_dapm_route *routes; + int num_routes; +}; + +static const struct snd_soc_dapm_route routes_ssi0_ak4642[] = { + {"ak4642 Playback", NULL, "DAI0 Playback"}, + {"DAI0 Capture", NULL, "ak4642 Capture"}, +}; + +static const struct rsrc_card_of_data routes_of_ssi0_ak4642 = { + .prefix = "ak4642", + .routes = routes_ssi0_ak4642, + .num_routes = ARRAY_SIZE(routes_ssi0_ak4642), +}; + +static const struct of_device_id rsrc_card_of_match[] = { + { .compatible = "renesas,rsrc-card,lager", .data = &routes_of_ssi0_ak4642 }, + { .compatible = "renesas,rsrc-card,koelsch", .data = &routes_of_ssi0_ak4642 }, + {}, +}; +MODULE_DEVICE_TABLE(of, rsrc_card_of_match); + +struct rsrc_card_dai { + const char *name; + unsigned int fmt; + unsigned int sysclk; + struct clk *clk; +}; + +#define RSRC_FB_NUM 2 /* FE/BE */ +#define IDX_CPU 0 +#define IDX_CODEC 1 +struct rsrc_card_priv { + struct snd_soc_card snd_card; + struct rsrc_card_dai_props { + struct rsrc_card_dai cpu_dai; + struct rsrc_card_dai codec_dai; + } dai_props[RSRC_FB_NUM]; + struct snd_soc_codec_conf codec_conf; + struct snd_soc_dai_link dai_link[RSRC_FB_NUM]; +}; + +#define rsrc_priv_to_dev(priv) ((priv)->snd_card.dev) +#define rsrc_priv_to_link(priv, i) ((priv)->snd_card.dai_link + i) +#define rsrc_priv_to_props(priv, i) ((priv)->dai_props + i) +#define rsrc_dev_to_of_data(dev) (of_match_device(rsrc_card_of_match, (dev))->data) + +static int rsrc_card_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct rsrc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); + struct rsrc_card_dai_props *dai_props = + &priv->dai_props[rtd - rtd->card->rtd]; + int ret; + + ret = clk_prepare_enable(dai_props->cpu_dai.clk); + if (ret) + return ret; + + ret = clk_prepare_enable(dai_props->codec_dai.clk); + if (ret) + clk_disable_unprepare(dai_props->cpu_dai.clk); + + return ret; +} + +static void rsrc_card_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct rsrc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); + struct rsrc_card_dai_props *dai_props = + &priv->dai_props[rtd - rtd->card->rtd]; + + clk_disable_unprepare(dai_props->cpu_dai.clk); + + clk_disable_unprepare(dai_props->codec_dai.clk); +} + +static struct snd_soc_ops rsrc_card_ops = { + .startup = rsrc_card_startup, + .shutdown = rsrc_card_shutdown, +}; + +static int __rsrc_card_dai_init(struct snd_soc_dai *dai, + struct rsrc_card_dai *set) +{ + int ret; + + if (set->fmt) { + ret = snd_soc_dai_set_fmt(dai, set->fmt); + if (ret && ret != -ENOTSUPP) { + dev_err(dai->dev, "set_fmt error\n"); + goto err; + } + } + + if (set->sysclk) { + ret = snd_soc_dai_set_sysclk(dai, 0, set->sysclk, 0); + if (ret && ret != -ENOTSUPP) { + dev_err(dai->dev, "set_sysclk error\n"); + goto err; + } + } + + ret = 0; + +err: + return ret; +} + +static int rsrc_card_dai_init(struct snd_soc_pcm_runtime *rtd) +{ + struct rsrc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *codec = rtd->codec_dai; + struct snd_soc_dai *cpu = rtd->cpu_dai; + struct rsrc_card_dai_props *dai_props; + int num, ret; + + num = rtd - rtd->card->rtd; + dai_props = &priv->dai_props[num]; + ret = __rsrc_card_dai_init(codec, &dai_props->codec_dai); + if (ret < 0) + return ret; + + ret = __rsrc_card_dai_init(cpu, &dai_props->cpu_dai); + if (ret < 0) + return ret; + + return 0; +} + +static int +rsrc_card_sub_parse_of(struct rsrc_card_priv *priv, + struct device_node *np, + struct rsrc_card_dai *dai, + struct snd_soc_dai_link *dai_link, + int *args_count) +{ + struct device *dev = rsrc_priv_to_dev(priv); + const struct rsrc_card_of_data *of_data = rsrc_dev_to_of_data(dev); + struct of_phandle_args args; + struct device_node **p_node; + struct clk *clk; + const char **dai_name; + const char **name; + u32 val; + int ret; + + if (args_count) { + p_node = &dai_link->cpu_of_node; + dai_name = &dai_link->cpu_dai_name; + name = &dai_link->cpu_name; + } else { + p_node = &dai_link->codec_of_node; + dai_name = &dai_link->codec_dai_name; + name = &dai_link->codec_name; + } + + if (!np) { + /* use snd-soc-dummy */ + *p_node = NULL; + *dai_name = "snd-soc-dummy-dai"; + *name = "snd-soc-dummy"; + return 0; + } + + /* + * Get node via "sound-dai = <&phandle port>" + * it will be used as xxx_of_node on soc_bind_dai_link() + */ + ret = of_parse_phandle_with_args(np, "sound-dai", + "#sound-dai-cells", 0, &args); + if (ret) + return ret; + + *p_node = args.np; + + /* Get dai->name */ + ret = snd_soc_of_get_dai_name(np, dai_name); + if (ret < 0) + return ret; + + /* + * FIXME + * + * rsrc assumes DPCM playback/capture + */ + dai_link->dpcm_playback = 1; + dai_link->dpcm_capture = 1; + + if (args_count) { + *args_count = args.args_count; + dai_link->dynamic = 1; + } else { + dai_link->no_pcm = 1; + priv->codec_conf.of_node = (*p_node); + priv->codec_conf.name_prefix = of_data->prefix; + } + + /* + * Parse dai->sysclk come from "clocks = <&xxx>" + * (if system has common clock) + * or "system-clock-frequency = " + * or device's module clock. + */ + if (of_property_read_bool(np, "clocks")) { + clk = of_clk_get(np, 0); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + return ret; + } + + dai->sysclk = clk_get_rate(clk); + dai->clk = clk; + } else if (!of_property_read_u32(np, "system-clock-frequency", &val)) { + dai->sysclk = val; + } else { + clk = of_clk_get(args.np, 0); + if (!IS_ERR(clk)) + dai->sysclk = clk_get_rate(clk); + } + + return 0; +} + +static int rsrc_card_parse_daifmt(struct device_node *node, + struct rsrc_card_priv *priv, + struct device_node *codec, + int idx) +{ + struct device_node *bitclkmaster = NULL; + struct device_node *framemaster = NULL; + struct rsrc_card_dai_props *dai_props = rsrc_priv_to_props(priv, idx); + struct rsrc_card_dai *cpu_dai = &dai_props->cpu_dai; + struct rsrc_card_dai *codec_dai = &dai_props->codec_dai; + unsigned int daifmt; + + daifmt = snd_soc_of_parse_daifmt(node, NULL, + &bitclkmaster, &framemaster); + daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK; + + if (!bitclkmaster && !framemaster) + return -EINVAL; + + if (codec == bitclkmaster) + daifmt |= (codec == framemaster) ? + SND_SOC_DAIFMT_CBM_CFM : SND_SOC_DAIFMT_CBM_CFS; + else + daifmt |= (codec == framemaster) ? + SND_SOC_DAIFMT_CBS_CFM : SND_SOC_DAIFMT_CBS_CFS; + + cpu_dai->fmt = daifmt; + codec_dai->fmt = daifmt; + + of_node_put(bitclkmaster); + of_node_put(framemaster); + + return 0; +} + +static int rsrc_card_dai_link_of(struct device_node *node, + struct rsrc_card_priv *priv, + int idx) +{ + struct device *dev = rsrc_priv_to_dev(priv); + struct snd_soc_dai_link *dai_link = rsrc_priv_to_link(priv, idx); + struct rsrc_card_dai_props *dai_props = rsrc_priv_to_props(priv, idx); + struct device_node *cpu = NULL; + struct device_node *codec = NULL; + char *name; + char prop[128]; + int ret, cpu_args; + + cpu = of_get_child_by_name(node, "cpu"); + codec = of_get_child_by_name(node, "codec"); + + if (!cpu || !codec) { + ret = -EINVAL; + dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop); + goto dai_link_of_err; + } + + ret = rsrc_card_parse_daifmt(node, priv, codec, idx); + if (ret < 0) + goto dai_link_of_err; + + ret = rsrc_card_sub_parse_of(priv, (idx == IDX_CPU) ? cpu : NULL, + &dai_props->cpu_dai, + dai_link, + &cpu_args); + if (ret < 0) + goto dai_link_of_err; + + ret = rsrc_card_sub_parse_of(priv, (idx == IDX_CODEC) ? codec : NULL, + &dai_props->codec_dai, + dai_link, + NULL); + if (ret < 0) + goto dai_link_of_err; + + if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name) { + ret = -EINVAL; + goto dai_link_of_err; + } + + /* Simple Card assumes platform == cpu */ + dai_link->platform_of_node = dai_link->cpu_of_node; + + /* DAI link name is created from CPU/CODEC dai name */ + name = devm_kzalloc(dev, + strlen(dai_link->cpu_dai_name) + + strlen(dai_link->codec_dai_name) + 2, + GFP_KERNEL); + if (!name) { + ret = -ENOMEM; + goto dai_link_of_err; + } + + sprintf(name, "%s-%s", dai_link->cpu_dai_name, + dai_link->codec_dai_name); + dai_link->name = dai_link->stream_name = name; + dai_link->ops = &rsrc_card_ops; + dai_link->init = rsrc_card_dai_init; + + dev_dbg(dev, "\tname : %s\n", dai_link->stream_name); + dev_dbg(dev, "\tcpu : %s / %04x / %d\n", + dai_link->cpu_dai_name, + dai_props->cpu_dai.fmt, + dai_props->cpu_dai.sysclk); + dev_dbg(dev, "\tcodec : %s / %04x / %d\n", + dai_link->codec_dai_name, + dai_props->codec_dai.fmt, + dai_props->codec_dai.sysclk); + + /* + * In soc_bind_dai_link() will check cpu name after + * of_node matching if dai_link has cpu_dai_name. + * but, it will never match if name was created by + * fmt_single_name() remove cpu_dai_name if cpu_args + * was 0. See: + * fmt_single_name() + * fmt_multiple_name() + */ + if (!cpu_args) + dai_link->cpu_dai_name = NULL; + +dai_link_of_err: + of_node_put(cpu); + of_node_put(codec); + + return ret; +} + +static int rsrc_card_parse_of(struct device_node *node, + struct rsrc_card_priv *priv) +{ + struct device *dev = rsrc_priv_to_dev(priv); + const struct rsrc_card_of_data *of_data = rsrc_dev_to_of_data(dev); + int ret; + int i; + + if (!node) + return -EINVAL; + + /* Parse the card name from DT */ + snd_soc_of_parse_card_name(&priv->snd_card, "card-name"); + + /* DAPM routes */ + priv->snd_card.of_dapm_routes = of_data->routes; + priv->snd_card.num_of_dapm_routes = of_data->num_routes; + + dev_dbg(dev, "New rsrc-audio-card: %s\n", priv->snd_card.name ? + priv->snd_card.name : ""); + + /* FE/BE */ + for (i = 0; i < RSRC_FB_NUM; i++) { + ret = rsrc_card_dai_link_of(node, priv, i); + if (ret < 0) + return ret; + } + + if (!priv->snd_card.name) + priv->snd_card.name = priv->snd_card.dai_link->name; + + return 0; +} + +/* Decrease the reference count of the device nodes */ +static int rsrc_card_unref(struct snd_soc_card *card) +{ + struct snd_soc_dai_link *dai_link; + int num_links; + + for (num_links = 0, dai_link = card->dai_link; + num_links < card->num_links; + num_links++, dai_link++) { + of_node_put(dai_link->cpu_of_node); + of_node_put(dai_link->codec_of_node); + } + return 0; +} + +static int rsrc_card_probe(struct platform_device *pdev) +{ + struct rsrc_card_priv *priv; + struct snd_soc_dai_link *dai_link; + struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; + int ret; + + /* Allocate the private data */ + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + /* Init snd_soc_card */ + priv->snd_card.owner = THIS_MODULE; + priv->snd_card.dev = dev; + dai_link = priv->dai_link; + priv->snd_card.dai_link = dai_link; + priv->snd_card.num_links = RSRC_FB_NUM; + priv->snd_card.codec_conf = &priv->codec_conf; + priv->snd_card.num_configs = 1; + + ret = rsrc_card_parse_of(np, priv); + if (ret < 0) { + if (ret != -EPROBE_DEFER) + dev_err(dev, "parse error %d\n", ret); + goto err; + } + + snd_soc_card_set_drvdata(&priv->snd_card, priv); + + ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card); + if (ret >= 0) + return ret; +err: + rsrc_card_unref(&priv->snd_card); + + return ret; +} + +static int rsrc_card_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + + return rsrc_card_unref(card); +} + +static struct platform_driver rsrc_card = { + .driver = { + .name = "renesas-src-audio-card", + .of_match_table = rsrc_card_of_match, + }, + .probe = rsrc_card_probe, + .remove = rsrc_card_remove, +}; + +module_platform_driver(rsrc_card); + +MODULE_ALIAS("platform:renesas-src-audio-card"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Renesas Sampling Rate Convert Sound Card"); +MODULE_AUTHOR("Kuninori Morimoto "); -- cgit v1.2.3-59-g8ed1b From af7e2be96623785816c1a6e521307b7af11ad016 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 26 Mar 2015 04:01:46 +0000 Subject: ASoC: rsrc-card: add .be_hw_params_fixup support for convert rate Current rsnd-dpcm-card is supporting DPCM FE/BE sound card. This patch adds .be_hw_params_fixup and enabled sampling convert rate. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- .../bindings/sound/renesas,rsrc-card.txt | 1 + sound/soc/sh/rcar/rsrc-card.c | 27 ++++++++++++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt b/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt index 12e287ed4dce..c64155027288 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt +++ b/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt @@ -28,6 +28,7 @@ Optional subnode properties: dai-link uses bit clock inversion. - frame-inversion : bool property. Add this if the dai-link uses frame clock inversion. +- convert-rate : platform specified sampling rate convert Required CPU/CODEC subnodes properties: diff --git a/sound/soc/sh/rcar/rsrc-card.c b/sound/soc/sh/rcar/rsrc-card.c index 3baeab726bc3..a68517afe615 100644 --- a/sound/soc/sh/rcar/rsrc-card.c +++ b/sound/soc/sh/rcar/rsrc-card.c @@ -63,6 +63,7 @@ struct rsrc_card_priv { } dai_props[RSRC_FB_NUM]; struct snd_soc_codec_conf codec_conf; struct snd_soc_dai_link dai_link[RSRC_FB_NUM]; + u32 convert_rate; }; #define rsrc_priv_to_dev(priv) ((priv)->snd_card.dev) @@ -154,6 +155,21 @@ static int rsrc_card_dai_init(struct snd_soc_pcm_runtime *rtd) return 0; } +static int rsrc_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct rsrc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + + if (!priv->convert_rate) + return 0; + + rate->min = rate->max = priv->convert_rate; + + return 0; +} + static int rsrc_card_sub_parse_of(struct rsrc_card_priv *priv, struct device_node *np, @@ -347,6 +363,9 @@ static int rsrc_card_dai_link_of(struct device_node *node, dai_link->ops = &rsrc_card_ops; dai_link->init = rsrc_card_dai_init; + if (idx == IDX_CODEC) + dai_link->be_hw_params_fixup = rsrc_card_be_hw_params_fixup; + dev_dbg(dev, "\tname : %s\n", dai_link->stream_name); dev_dbg(dev, "\tcpu : %s / %04x / %d\n", dai_link->cpu_dai_name, @@ -394,8 +413,12 @@ static int rsrc_card_parse_of(struct device_node *node, priv->snd_card.of_dapm_routes = of_data->routes; priv->snd_card.num_of_dapm_routes = of_data->num_routes; - dev_dbg(dev, "New rsrc-audio-card: %s\n", priv->snd_card.name ? - priv->snd_card.name : ""); + /* sampling rate convert */ + of_property_read_u32(node, "convert-rate", &priv->convert_rate); + + dev_dbg(dev, "New rsrc-audio-card: %s (%d)\n", + priv->snd_card.name ? priv->snd_card.name : "", + priv->convert_rate); /* FE/BE */ for (i = 0; i < RSRC_FB_NUM; i++) { -- cgit v1.2.3-59-g8ed1b From 3acddf74f807778f0593ab4aaf26189c93e55ff1 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 18 Mar 2015 10:52:06 +0100 Subject: iio: st-sensors: add support for lis3lv02d accelerometer This adds support for the LIS3LV02 accelerometer found in the ST Microelectronics Nomadik board series. Cc: devicetree@vger.kernel.org Cc: Denis CIOCCA Acked-by: Lee Jones Signed-off-by: Linus Walleij Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/st-sensors.txt | 1 + drivers/iio/accel/st_accel.h | 1 + drivers/iio/accel/st_accel_core.c | 81 ++++++++++++++++++++++ drivers/iio/accel/st_accel_i2c.c | 4 ++ 4 files changed, 87 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/iio/st-sensors.txt b/Documentation/devicetree/bindings/iio/st-sensors.txt index a7a0a15913ad..d2aaca974531 100644 --- a/Documentation/devicetree/bindings/iio/st-sensors.txt +++ b/Documentation/devicetree/bindings/iio/st-sensors.txt @@ -23,6 +23,7 @@ standard bindings from pinctrl/pinctrl-bindings.txt. Valid compatible strings: Accelerometers: +- st,lis3lv02dl-accel - st,lsm303dlh-accel - st,lsm303dlhc-accel - st,lis3dh-accel diff --git a/drivers/iio/accel/st_accel.h b/drivers/iio/accel/st_accel.h index fa9646034305..7ee9724b1428 100644 --- a/drivers/iio/accel/st_accel.h +++ b/drivers/iio/accel/st_accel.h @@ -14,6 +14,7 @@ #include #include +#define LIS3LV02DL_ACCEL_DEV_NAME "lis3lv02dl_accel" #define LSM303DLHC_ACCEL_DEV_NAME "lsm303dlhc_accel" #define LIS3DH_ACCEL_DEV_NAME "lis3dh" #define LSM330D_ACCEL_DEV_NAME "lsm330d_accel" diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index 53f32629283a..58d1d13d552a 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -129,6 +129,30 @@ #define ST_ACCEL_3_IG1_EN_MASK 0x08 #define ST_ACCEL_3_MULTIREAD_BIT false +/* CUSTOM VALUES FOR SENSOR 4 */ +#define ST_ACCEL_4_WAI_EXP 0x3a +#define ST_ACCEL_4_ODR_ADDR 0x20 +#define ST_ACCEL_4_ODR_MASK 0x30 /* DF1 and DF0 */ +#define ST_ACCEL_4_ODR_AVL_40HZ_VAL 0x00 +#define ST_ACCEL_4_ODR_AVL_160HZ_VAL 0x01 +#define ST_ACCEL_4_ODR_AVL_640HZ_VAL 0x02 +#define ST_ACCEL_4_ODR_AVL_2560HZ_VAL 0x03 +#define ST_ACCEL_4_PW_ADDR 0x20 +#define ST_ACCEL_4_PW_MASK 0xc0 +#define ST_ACCEL_4_FS_ADDR 0x21 +#define ST_ACCEL_4_FS_MASK 0x80 +#define ST_ACCEL_4_FS_AVL_2_VAL 0X00 +#define ST_ACCEL_4_FS_AVL_6_VAL 0X01 +#define ST_ACCEL_4_FS_AVL_2_GAIN IIO_G_TO_M_S_2(1024) +#define ST_ACCEL_4_FS_AVL_6_GAIN IIO_G_TO_M_S_2(340) +#define ST_ACCEL_4_BDU_ADDR 0x21 +#define ST_ACCEL_4_BDU_MASK 0x40 +#define ST_ACCEL_4_DRDY_IRQ_ADDR 0x21 +#define ST_ACCEL_4_DRDY_IRQ_INT1_MASK 0x04 +#define ST_ACCEL_4_IG1_EN_ADDR 0x21 +#define ST_ACCEL_4_IG1_EN_MASK 0x08 +#define ST_ACCEL_4_MULTIREAD_BIT true + static const struct iio_chan_spec st_accel_12bit_channels[] = { ST_SENSORS_LSM_CHANNELS(IIO_ACCEL, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), @@ -373,6 +397,63 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { .multi_read_bit = ST_ACCEL_3_MULTIREAD_BIT, .bootime = 2, }, + { + .wai = ST_ACCEL_4_WAI_EXP, + .sensors_supported = { + [0] = LIS3LV02DL_ACCEL_DEV_NAME, + }, + .ch = (struct iio_chan_spec *)st_accel_12bit_channels, + .odr = { + .addr = ST_ACCEL_4_ODR_ADDR, + .mask = ST_ACCEL_4_ODR_MASK, + .odr_avl = { + { 40, ST_ACCEL_4_ODR_AVL_40HZ_VAL }, + { 160, ST_ACCEL_4_ODR_AVL_160HZ_VAL, }, + { 640, ST_ACCEL_4_ODR_AVL_640HZ_VAL, }, + { 2560, ST_ACCEL_4_ODR_AVL_2560HZ_VAL, }, + }, + }, + .pw = { + .addr = ST_ACCEL_4_PW_ADDR, + .mask = ST_ACCEL_4_PW_MASK, + .value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE, + .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE, + }, + .enable_axis = { + .addr = ST_SENSORS_DEFAULT_AXIS_ADDR, + .mask = ST_SENSORS_DEFAULT_AXIS_MASK, + }, + .fs = { + .addr = ST_ACCEL_4_FS_ADDR, + .mask = ST_ACCEL_4_FS_MASK, + .fs_avl = { + [0] = { + .num = ST_ACCEL_FS_AVL_2G, + .value = ST_ACCEL_4_FS_AVL_2_VAL, + .gain = ST_ACCEL_4_FS_AVL_2_GAIN, + }, + [1] = { + .num = ST_ACCEL_FS_AVL_6G, + .value = ST_ACCEL_4_FS_AVL_6_VAL, + .gain = ST_ACCEL_4_FS_AVL_6_GAIN, + }, + }, + }, + .bdu = { + .addr = ST_ACCEL_4_BDU_ADDR, + .mask = ST_ACCEL_4_BDU_MASK, + }, + .drdy_irq = { + .addr = ST_ACCEL_4_DRDY_IRQ_ADDR, + .mask_int1 = ST_ACCEL_4_DRDY_IRQ_INT1_MASK, + .ig1 = { + .en_addr = ST_ACCEL_4_IG1_EN_ADDR, + .en_mask = ST_ACCEL_4_IG1_EN_MASK, + }, + }, + .multi_read_bit = ST_ACCEL_4_MULTIREAD_BIT, + .bootime = 2, /* guess */ + }, }; static int st_accel_read_raw(struct iio_dev *indio_dev, diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c index c7246bdd30b9..6b720c190b2d 100644 --- a/drivers/iio/accel/st_accel_i2c.c +++ b/drivers/iio/accel/st_accel_i2c.c @@ -20,6 +20,10 @@ #ifdef CONFIG_OF static const struct of_device_id st_accel_of_match[] = { + { + .compatible = "st,lis3lv02dl-accel", + .data = LIS3LV02DL_ACCEL_DEV_NAME, + }, { .compatible = "st,lsm303dlh-accel", .data = LSM303DLH_ACCEL_DEV_NAME, -- cgit v1.2.3-59-g8ed1b From 7cf78db585b13d5f43e5108cca6cdc5d9682793a Mon Sep 17 00:00:00 2001 From: Darshana Padmadas Date: Mon, 16 Mar 2015 17:18:20 +0530 Subject: iio: Add ABI documentation for illuminance raw and scale values in light This patchset adds ABI documentation for the following attributes: in_illuminance_scale, used atleast once in al3320a staging/iio/light/ in_illuminance_calibscale, used atleast once in cm32181 in_illuminance_input, used in cm3232 at least once in_illuminance_raw used atleast once in al3320a in_illuminance_clear_raw and in_illuminance_ir_raw exposed by gp2ap020a00f with modifiers IIO_MOD_LIGHT_CLEAR and IIO_MOD_LIGHT_IR respectively. Signed-off-by: Darshana Padmadas Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 6be17c2c5c65..7438e4efdf4c 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -297,6 +297,7 @@ What: /sys/bus/iio/devices/iio:deviceX/in_pressureY_scale What: /sys/bus/iio/devices/iio:deviceX/in_pressure_scale What: /sys/bus/iio/devices/iio:deviceX/in_humidityrelative_scale What: /sys/bus/iio/devices/iio:deviceX/in_velocity_sqrt(x^2+y^2+z^2)_scale +What: /sys/bus/iio/devices/iio:deviceX/in_illuminance_scale KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org Description: @@ -337,6 +338,7 @@ what /sys/bus/iio/devices/iio:deviceX/in_illuminance0_calibscale what /sys/bus/iio/devices/iio:deviceX/in_proximity0_calibscale What: /sys/bus/iio/devices/iio:deviceX/in_pressureY_calibscale What: /sys/bus/iio/devices/iio:deviceX/in_pressure_calibscale +What: /sys/bus/iio/devices/iio:deviceX/in_illuminance_calibscale KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org Description: @@ -1167,9 +1169,13 @@ Description: values should behave in the same way as a distance, i.e. lower values indicate something is closer to the sensor. +What: /sys/.../iio:deviceX/in_illuminance_input +What: /sys/.../iio:deviceX/in_illuminance_raw What: /sys/.../iio:deviceX/in_illuminanceY_input What: /sys/.../iio:deviceX/in_illuminanceY_raw What: /sys/.../iio:deviceX/in_illuminanceY_mean_raw +What: /sys/.../iio:deviceX/in_illuminance_ir_raw +What: /sys/.../iio:deviceX/in_illuminance_clear_raw KernelVersion: 3.4 Contact: linux-iio@vger.kernel.org Description: -- cgit v1.2.3-59-g8ed1b From 8ea06893e66d03dc567845d65b42812efd71b9f3 Mon Sep 17 00:00:00 2001 From: Haneen Mohammed Date: Sat, 28 Mar 2015 03:02:39 +0300 Subject: iio: Add ABI documentation for in_rot offset value This patch adds ABI documentation entries for in_rot_offset. At least one user for these is present that is the HID Sensors Driver. Signed-off-by: Haneen Mohammed Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 7438e4efdf4c..580b3f85437b 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -254,6 +254,7 @@ What: /sys/bus/iio/devices/iio:deviceX/in_pressureY_offset What: /sys/bus/iio/devices/iio:deviceX/in_pressure_offset What: /sys/bus/iio/devices/iio:deviceX/in_humidityrelative_offset What: /sys/bus/iio/devices/iio:deviceX/in_magn_offset +What: /sys/bus/iio/devices/iio:deviceX/in_rot_offset KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org Description: -- cgit v1.2.3-59-g8ed1b From 37d3455672732b29a477732a94abfe95e199f0ce Mon Sep 17 00:00:00 2001 From: Josselin Costanzi Date: Sun, 22 Mar 2015 20:33:38 +0200 Subject: iio: add watermark logic to iio read and poll Currently the IIO buffer blocking read only wait until at least one data element is available. This patch makes the reader sleep until enough data is collected before returning to userspace. This should limit the read() calls count when trying to get data in batches. Co-author: Yannick Bedhomme Signed-off-by: Josselin Costanzi [rebased and remove buffer timeout] Signed-off-by: Octavian Purdila Reviewed-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 15 ++++ drivers/iio/industrialio-buffer.c | 120 +++++++++++++++++++++++++++---- drivers/iio/kfifo_buf.c | 11 ++- drivers/staging/iio/accel/sca3000_ring.c | 4 +- include/linux/iio/buffer.h | 8 ++- 5 files changed, 131 insertions(+), 27 deletions(-) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 580b3f85437b..0b6f0abf3370 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -1280,3 +1280,18 @@ Contact: linux-iio@vger.kernel.org Description: Specifies number of seconds in which we compute the steps that occur in order to decide if the consumer is making steps. + +What: /sys/bus/iio/devices/iio:deviceX/buffer/watermark +KernelVersion: 4.2 +Contact: linux-iio@vger.kernel.org +Description: + A single positive integer specifying the maximum number of scan + elements to wait for. + Poll will block until the watermark is reached. + Blocking read will wait until the minimum between the requested + read amount or the low water mark is available. + Non-blocking read will retrieve the available samples from the + buffer even if there are less samples then watermark level. This + allows the application to block on poll with a timeout and read + the available samples after the timeout expires and thus have a + maximum delay guarantee. diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index c2d5440aa226..a24b2e005eb3 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -37,11 +37,28 @@ static bool iio_buffer_is_active(struct iio_buffer *buf) return !list_empty(&buf->buffer_list); } -static bool iio_buffer_data_available(struct iio_buffer *buf) +static size_t iio_buffer_data_available(struct iio_buffer *buf) { return buf->access->data_available(buf); } +static bool iio_buffer_ready(struct iio_dev *indio_dev, struct iio_buffer *buf, + size_t to_wait) +{ + /* wakeup if the device was unregistered */ + if (!indio_dev->info) + return true; + + /* drain the buffer if it was disabled */ + if (!iio_buffer_is_active(buf)) + to_wait = min_t(size_t, to_wait, 1); + + if (iio_buffer_data_available(buf) >= to_wait) + return true; + + return false; +} + /** * iio_buffer_read_first_n_outer() - chrdev read for buffer access * @@ -53,6 +70,8 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf, { struct iio_dev *indio_dev = filp->private_data; struct iio_buffer *rb = indio_dev->buffer; + size_t datum_size; + size_t to_wait = 0; int ret; if (!indio_dev->info) @@ -61,19 +80,26 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf, if (!rb || !rb->access->read_first_n) return -EINVAL; + datum_size = rb->bytes_per_datum; + + /* + * If datum_size is 0 there will never be anything to read from the + * buffer, so signal end of file now. + */ + if (!datum_size) + return 0; + + if (!(filp->f_flags & O_NONBLOCK)) + to_wait = min_t(size_t, n / datum_size, rb->watermark); + do { - if (!iio_buffer_data_available(rb)) { - if (filp->f_flags & O_NONBLOCK) - return -EAGAIN; + ret = wait_event_interruptible(rb->pollq, + iio_buffer_ready(indio_dev, rb, to_wait)); + if (ret) + return ret; - ret = wait_event_interruptible(rb->pollq, - iio_buffer_data_available(rb) || - indio_dev->info == NULL); - if (ret) - return ret; - if (indio_dev->info == NULL) - return -ENODEV; - } + if (!indio_dev->info) + return -ENODEV; ret = rb->access->read_first_n(rb, n, buf); if (ret == 0 && (filp->f_flags & O_NONBLOCK)) @@ -96,9 +122,8 @@ unsigned int iio_buffer_poll(struct file *filp, return -ENODEV; poll_wait(filp, &rb->pollq, wait); - if (iio_buffer_data_available(rb)) + if (iio_buffer_ready(indio_dev, rb, rb->watermark)) return POLLIN | POLLRDNORM; - /* need a way of knowing if there may be enough data... */ return 0; } @@ -123,6 +148,7 @@ void iio_buffer_init(struct iio_buffer *buffer) INIT_LIST_HEAD(&buffer->buffer_list); init_waitqueue_head(&buffer->pollq); kref_init(&buffer->ref); + buffer->watermark = 1; } EXPORT_SYMBOL(iio_buffer_init); @@ -416,6 +442,11 @@ static ssize_t iio_buffer_write_length(struct device *dev, buffer->access->set_length(buffer, val); ret = 0; } + if (ret) + goto out; + if (buffer->length && buffer->length < buffer->watermark) + buffer->watermark = buffer->length; +out: mutex_unlock(&indio_dev->mlock); return ret ? ret : len; @@ -472,6 +503,7 @@ static void iio_buffer_activate(struct iio_dev *indio_dev, static void iio_buffer_deactivate(struct iio_buffer *buffer) { list_del_init(&buffer->buffer_list); + wake_up_interruptible(&buffer->pollq); iio_buffer_put(buffer); } @@ -754,16 +786,64 @@ done: static const char * const iio_scan_elements_group_name = "scan_elements"; +static ssize_t iio_buffer_show_watermark(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct iio_buffer *buffer = indio_dev->buffer; + + return sprintf(buf, "%u\n", buffer->watermark); +} + +static ssize_t iio_buffer_store_watermark(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct iio_buffer *buffer = indio_dev->buffer; + unsigned int val; + int ret; + + ret = kstrtouint(buf, 10, &val); + if (ret) + return ret; + if (!val) + return -EINVAL; + + mutex_lock(&indio_dev->mlock); + + if (val > buffer->length) { + ret = -EINVAL; + goto out; + } + + if (iio_buffer_is_active(indio_dev->buffer)) { + ret = -EBUSY; + goto out; + } + + buffer->watermark = val; +out: + mutex_unlock(&indio_dev->mlock); + + return ret ? ret : len; +} + static DEVICE_ATTR(length, S_IRUGO | S_IWUSR, iio_buffer_read_length, iio_buffer_write_length); static struct device_attribute dev_attr_length_ro = __ATTR(length, S_IRUGO, iio_buffer_read_length, NULL); static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, iio_buffer_show_enable, iio_buffer_store_enable); +static DEVICE_ATTR(watermark, S_IRUGO | S_IWUSR, + iio_buffer_show_watermark, iio_buffer_store_watermark); static struct attribute *iio_buffer_attrs[] = { &dev_attr_length.attr, &dev_attr_enable.attr, + &dev_attr_watermark.attr, }; int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev) @@ -944,8 +1024,18 @@ static const void *iio_demux(struct iio_buffer *buffer, static int iio_push_to_buffer(struct iio_buffer *buffer, const void *data) { const void *dataout = iio_demux(buffer, data); + int ret; + + ret = buffer->access->store_to(buffer, dataout); + if (ret) + return ret; - return buffer->access->store_to(buffer, dataout); + /* + * We can't just test for watermark to decide if we wake the poll queue + * because read may request less samples than the watermark. + */ + wake_up_interruptible_poll(&buffer->pollq, POLLIN | POLLRDNORM); + return 0; } static void iio_buffer_demux_free(struct iio_buffer *buffer) diff --git a/drivers/iio/kfifo_buf.c b/drivers/iio/kfifo_buf.c index b2beea01c49b..847ca561afe0 100644 --- a/drivers/iio/kfifo_buf.c +++ b/drivers/iio/kfifo_buf.c @@ -83,9 +83,6 @@ static int iio_store_to_kfifo(struct iio_buffer *r, ret = kfifo_in(&kf->kf, data, 1); if (ret != 1) return -EBUSY; - - wake_up_interruptible_poll(&r->pollq, POLLIN | POLLRDNORM); - return 0; } @@ -109,16 +106,16 @@ static int iio_read_first_n_kfifo(struct iio_buffer *r, return copied; } -static bool iio_kfifo_buf_data_available(struct iio_buffer *r) +static size_t iio_kfifo_buf_data_available(struct iio_buffer *r) { struct iio_kfifo *kf = iio_to_kfifo(r); - bool empty; + size_t samples; mutex_lock(&kf->user_lock); - empty = kfifo_is_empty(&kf->kf); + samples = kfifo_len(&kf->kf); mutex_unlock(&kf->user_lock); - return !empty; + return samples; } static void iio_kfifo_buffer_release(struct iio_buffer *buffer) diff --git a/drivers/staging/iio/accel/sca3000_ring.c b/drivers/staging/iio/accel/sca3000_ring.c index f76a26885808..8589eade1057 100644 --- a/drivers/staging/iio/accel/sca3000_ring.c +++ b/drivers/staging/iio/accel/sca3000_ring.c @@ -129,9 +129,9 @@ error_ret: return ret ? ret : num_read; } -static bool sca3000_ring_buf_data_available(struct iio_buffer *r) +static size_t sca3000_ring_buf_data_available(struct iio_buffer *r) { - return r->stufftoread; + return r->stufftoread ? r->watermark : 0; } /** diff --git a/include/linux/iio/buffer.h b/include/linux/iio/buffer.h index b65850a41127..eb8622b78ec9 100644 --- a/include/linux/iio/buffer.h +++ b/include/linux/iio/buffer.h @@ -21,8 +21,8 @@ struct iio_buffer; * struct iio_buffer_access_funcs - access functions for buffers. * @store_to: actually store stuff to the buffer * @read_first_n: try to get a specified number of bytes (must exist) - * @data_available: indicates whether data for reading from the buffer is - * available. + * @data_available: indicates how much data is available for reading from + * the buffer. * @request_update: if a parameter change has been marked, update underlying * storage. * @set_bytes_per_datum:set number of bytes per datum @@ -43,7 +43,7 @@ struct iio_buffer_access_funcs { int (*read_first_n)(struct iio_buffer *buffer, size_t n, char __user *buf); - bool (*data_available)(struct iio_buffer *buffer); + size_t (*data_available)(struct iio_buffer *buffer); int (*request_update)(struct iio_buffer *buffer); @@ -72,6 +72,7 @@ struct iio_buffer_access_funcs { * @demux_bounce: [INTERN] buffer for doing gather from incoming scan. * @buffer_list: [INTERN] entry in the devices list of current buffers. * @ref: [INTERN] reference count of the buffer. + * @watermark: [INTERN] number of datums to wait for poll/read. */ struct iio_buffer { int length; @@ -90,6 +91,7 @@ struct iio_buffer { void *demux_bounce; struct list_head buffer_list; struct kref ref; + unsigned int watermark; }; /** -- cgit v1.2.3-59-g8ed1b From f4f4673b7535eff4ee1a8cfb1685fa1e1a0cb79d Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Sun, 22 Mar 2015 20:33:39 +0200 Subject: iio: add support for hardware fifo Some devices have hardware buffers that can store a number of samples for later consumption. Hardware usually provides interrupts to notify the processor when the FIFO is full or when it has reached a certain watermark level. This helps with reducing the number of interrupts to the host processor and thus it helps decreasing the power consumption. This patch enables usage of hardware FIFOs for IIO devices in conjunction with software device buffers. When the hardware FIFO is enabled the samples are stored in the hardware FIFO. The samples are later flushed to the device software buffer when the number of entries in the hardware FIFO reaches the hardware watermark or when a flush operation is triggered by the user when doing a non-blocking read on an empty software device buffer. In order to implement hardware FIFO support the device drivers must implement the following new operations: setting and getting the hardware FIFO watermark level, flushing the hardware FIFO to the software device buffer. The device must also expose information about the hardware FIFO such it's minimum and maximum watermark and if necessary a list of supported watermark values. Finally, the device driver must activate the hardware FIFO when the device buffer is enabled, if the current device settings allows it. The software device buffer watermark is passed by the IIO core to the device driver as a hint for the hardware FIFO watermark. The device driver can adjust this value to allow for hardware limitations (such as capping it to the maximum hardware watermark or adjust it to a value that is supported by the hardware). It can also disable the hardware watermark (and implicitly the hardware FIFO) it this value is below the minimum hardware watermark. Since a driver may support hardware FIFO only when not in triggered buffer mode (due to different semantics of hardware FIFO sampling and triggered sampling) this patch changes the IIO core code to allow falling back to non-triggered buffered mode if no trigger is enabled. Signed-off-by: Octavian Purdila Reviewed-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 69 +++++++++++++++++++++++++++++++++ drivers/iio/industrialio-buffer.c | 58 ++++++++++++++++++++------- include/linux/iio/iio.h | 13 +++++++ 3 files changed, 127 insertions(+), 13 deletions(-) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 0b6f0abf3370..6bf79072179f 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -1295,3 +1295,72 @@ Description: allows the application to block on poll with a timeout and read the available samples after the timeout expires and thus have a maximum delay guarantee. + +What: /sys/bus/iio/devices/iio:deviceX/buffer/hwfifo_enabled +KernelVersion: 4.2 +Contact: linux-iio@vger.kernel.org +Description: + A read-only boolean value that indicates if the hardware fifo is + currently enabled or disabled. If the device does not have a + hardware fifo this entry is not present. + The hardware fifo is enabled when the buffer is enabled if the + current hardware fifo watermark level is set and other current + device settings allows it (e.g. if a trigger is set that samples + data differently that the hardware fifo does then hardware fifo + will not enabled). + If the hardware fifo is enabled and the level of the hardware + fifo reaches the hardware fifo watermark level the device will + flush its hardware fifo to the device buffer. Doing a non + blocking read on the device when no samples are present in the + device buffer will also force a flush. + When the hardware fifo is enabled there is no need to use a + trigger to use buffer mode since the watermark settings + guarantees that the hardware fifo is flushed to the device + buffer. + +What: /sys/bus/iio/devices/iio:deviceX/buffer/hwfifo_watermark +KernelVersion: 4.2 +Contact: linux-iio@vger.kernel.org +Description: + Read-only entry that contains a single integer specifying the + current watermark level for the hardware fifo. If the device + does not have a hardware fifo this entry is not present. + The watermark level for the hardware fifo is set by the driver + based on the value set by the user in buffer/watermark but + taking into account hardware limitations (e.g. most hardware + buffers are limited to 32-64 samples, some hardware buffers + watermarks are fixed or have minimum levels). A value of 0 + means that the hardware watermark is unset. + +What: /sys/bus/iio/devices/iio:deviceX/buffer/hwfifo_watermark_min +KernelVersion: 4.2 +Contact: linux-iio@vger.kernel.org +Description: + A single positive integer specifying the minimum watermark level + for the hardware fifo of this device. If the device does not + have a hardware fifo this entry is not present. + If the user sets buffer/watermark to a value less than this one, + then the hardware watermark will remain unset. + +What: /sys/bus/iio/devices/iio:deviceX/buffer/hwfifo_watermark_max +KernelVersion: 4.2 +Contact: linux-iio@vger.kernel.org +Description: + A single positive integer specifying the maximum watermark level + for the hardware fifo of this device. If the device does not + have a hardware fifo this entry is not present. + If the user sets buffer/watermark to a value greater than this + one, then the hardware watermark will be capped at this value. + +What: /sys/bus/iio/devices/iio:deviceX/buffer/hwfifo_watermark_available +KernelVersion: 4.2 +Contact: linux-iio@vger.kernel.org +Description: + A list of positive integers specifying the available watermark + levels for the hardware fifo. This entry is optional and if it + is not present it means that all the values between + hwfifo_watermark_min and hwfifo_watermark_max are supported. + If the user sets buffer/watermark to a value greater than + hwfifo_watermak_min but not equal to any of the values in this + list, the driver will chose an appropriate value for the + hardware fifo watermark level. diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index a24b2e005eb3..df919f44d513 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -42,18 +42,47 @@ static size_t iio_buffer_data_available(struct iio_buffer *buf) return buf->access->data_available(buf); } +static int iio_buffer_flush_hwfifo(struct iio_dev *indio_dev, + struct iio_buffer *buf, size_t required) +{ + if (!indio_dev->info->hwfifo_flush_to_buffer) + return -ENODEV; + + return indio_dev->info->hwfifo_flush_to_buffer(indio_dev, required); +} + static bool iio_buffer_ready(struct iio_dev *indio_dev, struct iio_buffer *buf, - size_t to_wait) + size_t to_wait, int to_flush) { + size_t avail; + int flushed = 0; + /* wakeup if the device was unregistered */ if (!indio_dev->info) return true; /* drain the buffer if it was disabled */ - if (!iio_buffer_is_active(buf)) + if (!iio_buffer_is_active(buf)) { to_wait = min_t(size_t, to_wait, 1); + to_flush = 0; + } + + avail = iio_buffer_data_available(buf); - if (iio_buffer_data_available(buf) >= to_wait) + if (avail >= to_wait) { + /* force a flush for non-blocking reads */ + if (!to_wait && !avail && to_flush) + iio_buffer_flush_hwfifo(indio_dev, buf, to_flush); + return true; + } + + if (to_flush) + flushed = iio_buffer_flush_hwfifo(indio_dev, buf, + to_wait - avail); + if (flushed <= 0) + return false; + + if (avail + flushed >= to_wait) return true; return false; @@ -72,6 +101,7 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf, struct iio_buffer *rb = indio_dev->buffer; size_t datum_size; size_t to_wait = 0; + size_t to_read; int ret; if (!indio_dev->info) @@ -89,12 +119,14 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf, if (!datum_size) return 0; + to_read = min_t(size_t, n / datum_size, rb->watermark); + if (!(filp->f_flags & O_NONBLOCK)) - to_wait = min_t(size_t, n / datum_size, rb->watermark); + to_wait = to_read; do { ret = wait_event_interruptible(rb->pollq, - iio_buffer_ready(indio_dev, rb, to_wait)); + iio_buffer_ready(indio_dev, rb, to_wait, to_read)); if (ret) return ret; @@ -122,7 +154,7 @@ unsigned int iio_buffer_poll(struct file *filp, return -ENODEV; poll_wait(filp, &rb->pollq, wait); - if (iio_buffer_ready(indio_dev, rb, rb->watermark)) + if (iio_buffer_ready(indio_dev, rb, rb->watermark, 0)) return POLLIN | POLLRDNORM; return 0; } @@ -661,19 +693,16 @@ static int __iio_update_buffers(struct iio_dev *indio_dev, } } /* Definitely possible for devices to support both of these. */ - if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) { - if (!indio_dev->trig) { - printk(KERN_INFO "Buffer not started: no trigger\n"); - ret = -EINVAL; - /* Can only occur on first buffer */ - goto error_run_postdisable; - } + if ((indio_dev->modes & INDIO_BUFFER_TRIGGERED) && indio_dev->trig) { indio_dev->currentmode = INDIO_BUFFER_TRIGGERED; } else if (indio_dev->modes & INDIO_BUFFER_HARDWARE) { indio_dev->currentmode = INDIO_BUFFER_HARDWARE; } else if (indio_dev->modes & INDIO_BUFFER_SOFTWARE) { indio_dev->currentmode = INDIO_BUFFER_SOFTWARE; } else { /* Should never be reached */ + /* Can only occur on first buffer */ + if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) + pr_info("Buffer not started: no trigger\n"); ret = -EINVAL; goto error_run_postdisable; } @@ -825,6 +854,9 @@ static ssize_t iio_buffer_store_watermark(struct device *dev, } buffer->watermark = val; + + if (indio_dev->info->hwfifo_set_watermark) + indio_dev->info->hwfifo_set_watermark(indio_dev, val); out: mutex_unlock(&indio_dev->mlock); diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index 80d855061064..d86b753e9b30 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -338,6 +338,16 @@ struct iio_dev; * provide a custom of_xlate function that reads the * *args* and returns the appropriate index in registered * IIO channels array. + * @hwfifo_set_watermark: function pointer to set the current hardware + * fifo watermark level; see hwfifo_* entries in + * Documentation/ABI/testing/sysfs-bus-iio for details on + * how the hardware fifo operates + * @hwfifo_flush_to_buffer: function pointer to flush the samples stored + * in the hardware fifo to the device buffer. The driver + * should not flush more than count samples. The function + * must return the number of samples flushed, 0 if no + * samples were flushed or a negative integer if no samples + * were flushed and there was an error. **/ struct iio_info { struct module *driver_module; @@ -399,6 +409,9 @@ struct iio_info { unsigned *readval); int (*of_xlate)(struct iio_dev *indio_dev, const struct of_phandle_args *iiospec); + int (*hwfifo_set_watermark)(struct iio_dev *indio_dev, unsigned val); + int (*hwfifo_flush_to_buffer)(struct iio_dev *indio_dev, + unsigned count); }; /** -- cgit v1.2.3-59-g8ed1b From 5798cd23f87a93a7f187c0314804b9a736a5319a Mon Sep 17 00:00:00 2001 From: Martin Kepplinger Date: Sun, 29 Mar 2015 01:59:49 +0100 Subject: Documentation/ABI:iio:fix typo Signed-off-by: Martin Kepplinger Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 6bf79072179f..103dd9b94192 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -800,7 +800,7 @@ Description: What: /sys/.../events/in_accel_x_thresh_rising_period What: /sys/.../events/in_accel_x_thresh_falling_period -hat: /sys/.../events/in_accel_x_roc_rising_period +What: /sys/.../events/in_accel_x_roc_rising_period What: /sys/.../events/in_accel_x_roc_falling_period What: /sys/.../events/in_accel_y_thresh_rising_period What: /sys/.../events/in_accel_y_thresh_falling_period -- cgit v1.2.3-59-g8ed1b From cf1d54394dd5ee04ca4a88283deaaade37d12882 Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Fri, 20 Feb 2015 19:19:27 +0800 Subject: mfd: AXP20x: Add bindings documentation Bindings documentation for the AXP20x driver. In this file also sub-nodes are documented. Signed-off-by: Carlo Caione [wens@csie.org: clarify interrupt source for the axp PMIC] [wens@csie.org: explain dcdc-workmode in detail and trim lines to 80 chars] [wens@csie.org: make regulator supplies optional if using unregulated input] [wens@csie.org: use cubieboard2 regulator nodes as example] [wens@csie.org: x-powers,dcdc-workmode default changed to 'current hardware setting'] [wens@csie.org: reorganized regulator related properties into separate section.] Signed-off-by: Chen-Yu Tsai Acked-by: Maxime Ripard Signed-off-by: Lee Jones --- Documentation/devicetree/bindings/mfd/axp20x.txt | 96 ++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 Documentation/devicetree/bindings/mfd/axp20x.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mfd/axp20x.txt b/Documentation/devicetree/bindings/mfd/axp20x.txt new file mode 100644 index 000000000000..98685f291a72 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/axp20x.txt @@ -0,0 +1,96 @@ +AXP202/AXP209 device tree bindings + +The axp20x family current members : +axp202 (X-Powers) +axp209 (X-Powers) + +Required properties: +- compatible: "x-powers,axp202" or "x-powers,axp209" +- reg: The I2C slave address for the AXP chip +- interrupt-parent: The parent interrupt controller +- interrupts: SoC NMI / GPIO interrupt connected to the PMIC's IRQ pin +- interrupt-controller: axp20x has its own internal IRQs +- #interrupt-cells: Should be set to 1 + +Optional properties: +- x-powers,dcdc-freq: defines the work frequency of DC-DC in KHz + (range: 750-1875). Default: 1.5MHz +- -supply: a phandle to the regulator supply node. May be omitted if + inputs are unregulated, such as using the IPSOUT output + from the PMIC. + +- regulators: A node that houses a sub-node for each regulator. Regulators + not used but preferred to be managed by the OS should be + listed as well. + See Documentation/devicetree/bindings/regulator/regulator.txt + for more information on standard regulator bindings. + +Optional properties for DCDC regulators: +- x-powers,dcdc-workmode: 1 for PWM mode, 0 for AUTO (PWM/PFM) mode + Default: Current hardware setting + The DCDC regulators work in a mixed PWM/PFM mode, + using PFM under light loads and switching to PWM + for heavier loads. Forcing PWM mode trades efficiency + under light loads for lower output noise. This + probably makes sense for HiFi audio related + applications that aren't battery constrained. + + +AXP202/AXP209 regulators, type, and corresponding input supply names: + +Regulator Type Supply Name Notes +--------- ---- ----------- ----- +DCDC2 : DC-DC buck : vin2-supply +DCDC3 : DC-DC buck : vin3-supply +LDO1 : LDO : acin-supply : always on +LDO2 : LDO : ldo24in-supply : shared supply +LDO3 : LDO : ldo3in-supply +LDO4 : LDO : ldo24in-supply : shared supply +LDO5 : LDO : ldo5in-supply + +Example: + +axp209: pmic@34 { + compatible = "x-powers,axp209"; + reg = <0x34>; + interrupt-parent = <&nmi_intc>; + interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupt-controller; + #interrupt-cells = <1>; + + regulators { + x-powers,dcdc-freq = <1500>; + + vdd_cpu: dcdc2 { + regulator-always-on; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1450000>; + regulator-name = "vdd-cpu"; + }; + + vdd_int_dll: dcdc3 { + regulator-always-on; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1400000>; + regulator-name = "vdd-int-dll"; + }; + + vdd_rtc: ldo1 { + regulator-always-on; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1400000>; + regulator-name = "vdd-rtc"; + }; + + avcc: ldo2 { + regulator-always-on; + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <3300000>; + regulator-name = "avcc"; + }; + + ldo3 { + /* unused but preferred to be managed by OS */ + }; + }; +}; -- cgit v1.2.3-59-g8ed1b From 0787ded88e620c81ee2e42cee56cbb5cc26077de Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Fri, 20 Feb 2015 19:19:28 +0800 Subject: dt-bindings: Add vendor-prefix for X-Powers Signed-off-by: Carlo Caione Signed-off-by: Chen-Yu Tsai Signed-off-by: Lee Jones --- Documentation/devicetree/bindings/vendor-prefixes.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index c4fe9cc64162..657a7e544109 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -193,6 +193,7 @@ voipac Voipac Technologies s.r.o. winbond Winbond Electronics corp. wlf Wolfson Microelectronics wm Wondermedia Technologies, Inc. +x-powers X-Powers xes Extreme Engineering Solutions (X-ES) xillybus Xillybus Ltd. xlnx Xilinx -- cgit v1.2.3-59-g8ed1b From 30bc3aa5c4ed3072bdff7d915772df1b91307ed4 Mon Sep 17 00:00:00 2001 From: Josh Cartwright Date: Thu, 26 Mar 2015 11:29:25 -0700 Subject: mfd: devicetree: qcom_rpm: Document IPQ8064 resources The IPQ8064 SoC has several RPM-controlled resources, an NSS fabrick clock and four regulator resources. Provide definitions for them. Signed-off-by: Josh Cartwright [sboyd@codeaurora.org: Drop regulator part of binding] Signed-off-by: Stephen Boyd Signed-off-by: Lee Jones --- Documentation/devicetree/bindings/mfd/qcom-rpm.txt | 1 + include/dt-bindings/mfd/qcom-rpm.h | 6 ++++++ 2 files changed, 7 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mfd/qcom-rpm.txt b/Documentation/devicetree/bindings/mfd/qcom-rpm.txt index 85e31980017a..94d9ae8d5168 100644 --- a/Documentation/devicetree/bindings/mfd/qcom-rpm.txt +++ b/Documentation/devicetree/bindings/mfd/qcom-rpm.txt @@ -12,6 +12,7 @@ frequencies. "qcom,rpm-apq8064" "qcom,rpm-msm8660" "qcom,rpm-msm8960" + "qcom,rpm-ipq8064" - reg: Usage: required diff --git a/include/dt-bindings/mfd/qcom-rpm.h b/include/dt-bindings/mfd/qcom-rpm.h index 388a6f3d6165..13a9d4bf2662 100644 --- a/include/dt-bindings/mfd/qcom-rpm.h +++ b/include/dt-bindings/mfd/qcom-rpm.h @@ -141,6 +141,12 @@ #define QCOM_RPM_SYS_FABRIC_MODE 131 #define QCOM_RPM_USB_OTG_SWITCH 132 #define QCOM_RPM_VDDMIN_GPIO 133 +#define QCOM_RPM_NSS_FABRIC_0_CLK 134 +#define QCOM_RPM_NSS_FABRIC_1_CLK 135 +#define QCOM_RPM_SMB208_S1a 136 +#define QCOM_RPM_SMB208_S1b 137 +#define QCOM_RPM_SMB208_S2a 138 +#define QCOM_RPM_SMB208_S2b 139 /* * Constants used to select force mode for regulators. -- cgit v1.2.3-59-g8ed1b From dc716bbf1d487503110139b019c3e6e526bf7cc8 Mon Sep 17 00:00:00 2001 From: "Ivan T. Ivanov" Date: Tue, 17 Mar 2015 12:47:24 +0200 Subject: mfd: qcom-spmi-pmic: Add specific compatible strings for Qualcomm's SPMI PMIC's Some of the PMIC's could have specific regmap configuration tables in future, so add specific compatible strings for known PMIC's. Also print runtime detected chip revision information. Signed-off-by: Ivan T. Ivanov Acked-by: Stephen Boyd Signed-off-by: Lee Jones --- .../devicetree/bindings/mfd/qcom,spmi-pmic.txt | 19 +++- drivers/mfd/qcom-spmi-pmic.c | 103 +++++++++++++++++++-- 2 files changed, 111 insertions(+), 11 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.txt b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.txt index 7182b8857f57..6ac06c1b9aec 100644 --- a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.txt +++ b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.txt @@ -15,10 +15,21 @@ each. A function can consume one or more of these fixed-size register regions. Required properties: - compatible: Should contain one of: - "qcom,pm8941" - "qcom,pm8841" - "qcom,pma8084" - or generalized "qcom,spmi-pmic". + "qcom,pm8941", + "qcom,pm8841", + "qcom,pma8084", + "qcom,pm8019", + "qcom,pm8226", + "qcom,pm8110", + "qcom,pma8084", + "qcom,pmi8962", + "qcom,pmd9635", + "qcom,pm8994", + "qcom,pmi8994", + "qcom,pm8916", + "qcom,pm8004", + "qcom,pm8909", + or generalized "qcom,spmi-pmic". - reg: Specifies the SPMI USID slave address for this device. For more information see: Documentation/devicetree/bindings/spmi/spmi.txt diff --git a/drivers/mfd/qcom-spmi-pmic.c b/drivers/mfd/qcom-spmi-pmic.c index 4b8beb2a1579..af6ac1c4b45c 100644 --- a/drivers/mfd/qcom-spmi-pmic.c +++ b/drivers/mfd/qcom-spmi-pmic.c @@ -17,6 +17,100 @@ #include #include +#define PMIC_REV2 0x101 +#define PMIC_REV3 0x102 +#define PMIC_REV4 0x103 +#define PMIC_TYPE 0x104 +#define PMIC_SUBTYPE 0x105 + +#define PMIC_TYPE_VALUE 0x51 + +#define COMMON_SUBTYPE 0x00 +#define PM8941_SUBTYPE 0x01 +#define PM8841_SUBTYPE 0x02 +#define PM8019_SUBTYPE 0x03 +#define PM8226_SUBTYPE 0x04 +#define PM8110_SUBTYPE 0x05 +#define PMA8084_SUBTYPE 0x06 +#define PMI8962_SUBTYPE 0x07 +#define PMD9635_SUBTYPE 0x08 +#define PM8994_SUBTYPE 0x09 +#define PMI8994_SUBTYPE 0x0a +#define PM8916_SUBTYPE 0x0b +#define PM8004_SUBTYPE 0x0c +#define PM8909_SUBTYPE 0x0d + +static const struct of_device_id pmic_spmi_id_table[] = { + { .compatible = "qcom,spmi-pmic", .data = (void *)COMMON_SUBTYPE }, + { .compatible = "qcom,pm8941", .data = (void *)PM8941_SUBTYPE }, + { .compatible = "qcom,pm8841", .data = (void *)PM8841_SUBTYPE }, + { .compatible = "qcom,pm8019", .data = (void *)PM8019_SUBTYPE }, + { .compatible = "qcom,pm8226", .data = (void *)PM8226_SUBTYPE }, + { .compatible = "qcom,pm8110", .data = (void *)PM8110_SUBTYPE }, + { .compatible = "qcom,pma8084", .data = (void *)PMA8084_SUBTYPE }, + { .compatible = "qcom,pmi8962", .data = (void *)PMI8962_SUBTYPE }, + { .compatible = "qcom,pmd9635", .data = (void *)PMD9635_SUBTYPE }, + { .compatible = "qcom,pm8994", .data = (void *)PM8994_SUBTYPE }, + { .compatible = "qcom,pmi8994", .data = (void *)PMI8994_SUBTYPE }, + { .compatible = "qcom,pm8916", .data = (void *)PM8916_SUBTYPE }, + { .compatible = "qcom,pm8004", .data = (void *)PM8004_SUBTYPE }, + { .compatible = "qcom,pm8909", .data = (void *)PM8909_SUBTYPE }, + { } +}; + +static void pmic_spmi_show_revid(struct regmap *map, struct device *dev) +{ + unsigned int rev2, minor, major, type, subtype; + const char *name = "unknown"; + int ret, i; + + ret = regmap_read(map, PMIC_TYPE, &type); + if (ret < 0) + return; + + if (type != PMIC_TYPE_VALUE) + return; + + ret = regmap_read(map, PMIC_SUBTYPE, &subtype); + if (ret < 0) + return; + + for (i = 0; i < ARRAY_SIZE(pmic_spmi_id_table); i++) { + if (subtype == (unsigned long)pmic_spmi_id_table[i].data) + break; + } + + if (i != ARRAY_SIZE(pmic_spmi_id_table)) + name = pmic_spmi_id_table[i].compatible; + + ret = regmap_read(map, PMIC_REV2, &rev2); + if (ret < 0) + return; + + ret = regmap_read(map, PMIC_REV3, &minor); + if (ret < 0) + return; + + ret = regmap_read(map, PMIC_REV4, &major); + if (ret < 0) + return; + + /* + * In early versions of PM8941 and PM8226, the major revision number + * started incrementing from 0 (eg 0 = v1.0, 1 = v2.0). + * Increment the major revision number here if the chip is an early + * version of PM8941 or PM8226. + */ + if ((subtype == PM8941_SUBTYPE || subtype == PM8226_SUBTYPE) && + major < 0x02) + major++; + + if (subtype == PM8110_SUBTYPE) + minor = rev2; + + dev_dbg(dev, "%x: %s v%d.%d\n", subtype, name, major, minor); +} + static const struct regmap_config spmi_regmap_config = { .reg_bits = 16, .val_bits = 8, @@ -33,6 +127,8 @@ static int pmic_spmi_probe(struct spmi_device *sdev) if (IS_ERR(regmap)) return PTR_ERR(regmap); + pmic_spmi_show_revid(regmap, &sdev->dev); + return of_platform_populate(root, NULL, NULL, &sdev->dev); } @@ -41,13 +137,6 @@ static void pmic_spmi_remove(struct spmi_device *sdev) of_platform_depopulate(&sdev->dev); } -static const struct of_device_id pmic_spmi_id_table[] = { - { .compatible = "qcom,spmi-pmic" }, - { .compatible = "qcom,pm8941" }, - { .compatible = "qcom,pm8841" }, - { .compatible = "qcom,pma8084" }, - { } -}; MODULE_DEVICE_TABLE(of, pmic_spmi_id_table); static struct spmi_driver pmic_spmi_driver = { -- cgit v1.2.3-59-g8ed1b From cbbd896f25316e823af228432c690c35992d60f4 Mon Sep 17 00:00:00 2001 From: Courtney Cavin Date: Thu, 12 Mar 2015 08:47:07 -0700 Subject: leds: add DT binding for Qualcomm PM8941 WLED block This adds device tree binding documentation for the WLED ('White' LED) block on Qualcomm's PM8941 PMICs. Signed-off-by: Courtney Cavin Signed-off-by: Bjorn Andersson Signed-off-by: Bryan Wu --- .../devicetree/bindings/leds/leds-pm8941-wled.txt | 43 ++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 Documentation/devicetree/bindings/leds/leds-pm8941-wled.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/leds/leds-pm8941-wled.txt b/Documentation/devicetree/bindings/leds/leds-pm8941-wled.txt new file mode 100644 index 000000000000..a85a964d61f5 --- /dev/null +++ b/Documentation/devicetree/bindings/leds/leds-pm8941-wled.txt @@ -0,0 +1,43 @@ +Binding for Qualcomm PM8941 WLED driver + +Required properties: +- compatible: should be "qcom,pm8941-wled" +- reg: slave address + +Optional properties: +- label: The label for this led + See Documentation/devicetree/bindings/leds/common.txt +- linux,default-trigger: Default trigger assigned to the LED + See Documentation/devicetree/bindings/leds/common.txt +- qcom,cs-out: bool; enable current sink output +- qcom,cabc: bool; enable content adaptive backlight control +- qcom,ext-gen: bool; use externally generated modulator signal to dim +- qcom,current-limit: mA; per-string current limit; value from 0 to 25 + default: 20mA +- qcom,current-boost-limit: mA; boost current limit; one of: + 105, 385, 525, 805, 980, 1260, 1400, 1680 + default: 805mA +- qcom,switching-freq: kHz; switching frequency; one of: + 600, 640, 685, 738, 800, 872, 960, 1066, 1200, 1371, + 1600, 1920, 2400, 3200, 4800, 9600, + default: 1600kHz +- qcom,ovp: V; Over-voltage protection limit; one of: + 27, 29, 32, 35 + default: 29V +- qcom,num-strings: #; number of led strings attached; value from 1 to 3 + default: 2 + +Example: + +pm8941-wled@d800 { + compatible = "qcom,pm8941-wled"; + reg = <0xd800>; + label = "backlight"; + + qcom,cs-out; + qcom,current-limit = <20>; + qcom,current-boost-limit = <805>; + qcom,switching-freq = <1600>; + qcom,ovp = <29>; + qcom,num-strings = <2>; +}; -- cgit v1.2.3-59-g8ed1b From 116b8e164116be537f50cdcce84d80be0facd0cf Mon Sep 17 00:00:00 2001 From: Jacek Anaszewski Date: Thu, 26 Mar 2015 07:03:09 -0700 Subject: DT: leds: Add uniqueness requirement for 'label' property. Label is used for naming LED class devices. Since ePAPR doesn't require uniqueness for label properties, it has to be explicitly required in the LEDs common bindings documentation. Signed-off-by: Jacek Anaszewski Acked-by: Kyungmin Park Cc: Richard Purdie Cc: devicetree@vger.kernel.org Acked-by: Sakari Ailus Signed-off-by: Bryan Wu --- Documentation/devicetree/bindings/leds/common.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/leds/common.txt b/Documentation/devicetree/bindings/leds/common.txt index 34811c57db69..747c53805eec 100644 --- a/Documentation/devicetree/bindings/leds/common.txt +++ b/Documentation/devicetree/bindings/leds/common.txt @@ -14,8 +14,10 @@ Optional properties for child nodes: - led-sources : List of device current outputs the LED is connected to. The outputs are identified by the numbers that must be defined in the LED device binding documentation. -- label : The label for this LED. If omitted, the label is - taken from the node name (excluding the unit address). +- label : The label for this LED. If omitted, the label is taken from the node + name (excluding the unit address). It has to uniquely identify + a device, i.e. no other LED class device can be assigned the same + label. - linux,default-trigger : This parameter, if present, is a string defining the trigger assigned to the LED. Current triggers are: -- cgit v1.2.3-59-g8ed1b From e0631a31b9ed501415e552a783b1f1e3988c7c46 Mon Sep 17 00:00:00 2001 From: Irina Tirdea Date: Mon, 30 Mar 2015 14:22:13 +0300 Subject: iio: Documentation: fix kernel version for 4.0 new ABI Kernel version for new ABI in 4.0 has been documented as 3.20, since the changes have been merged before the kernel version number change. Change kernel version from 3.20 to 4.0. Signed-off-by: Irina Tirdea Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 103dd9b94192..3befcb19f414 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -351,7 +351,7 @@ What: /sys/bus/iio/devices/iio:deviceX/in_activity_calibgender What: /sys/bus/iio/devices/iio:deviceX/in_energy_calibgender What: /sys/bus/iio/devices/iio:deviceX/in_distance_calibgender What: /sys/bus/iio/devices/iio:deviceX/in_velocity_calibgender -KernelVersion: 3.20 +KernelVersion: 4.0 Contact: linux-iio@vger.kernel.org Description: Gender of the user (e.g.: male, female) used by some pedometers @@ -362,7 +362,7 @@ What: /sys/bus/iio/devices/iio:deviceX/in_activity_calibgender_available What: /sys/bus/iio/devices/iio:deviceX/in_energy_calibgender_available What: /sys/bus/iio/devices/iio:deviceX/in_distance_calibgender_available What: /sys/bus/iio/devices/iio:deviceX/in_velocity_calibgender_available -KernelVersion: 3.20 +KernelVersion: 4.0 Contact: linux-iio@vger.kernel.org Description: Lists all available gender values (e.g.: male, female). @@ -379,7 +379,7 @@ Description: type. What: /sys/bus/iio/devices/iio:deviceX/in_energy_calibweight -KernelVersion: 3.20 +KernelVersion: 4.0 Contact: linux-iio@vger.kernel.org Description: Weight of the user (in kg). It is needed by some pedometers @@ -947,7 +947,7 @@ Description: this type. What: /sys/.../events/in_steps_change_en -KernelVersion: 3.20 +KernelVersion: 4.0 Contact: linux-iio@vger.kernel.org Description: Event generated when channel passes a threshold on the absolute @@ -956,7 +956,7 @@ Description: in_steps_change_value. What: /sys/.../events/in_steps_change_value -KernelVersion: 3.20 +KernelVersion: 4.0 Contact: linux-iio@vger.kernel.org Description: Specifies the value of change threshold that the @@ -1131,7 +1131,7 @@ Description: What: /sys/.../iio:deviceX/in_energy_input What: /sys/.../iio:deviceX/in_energy_raw -KernelVersion: 3.20 +KernelVersion: 4.0 Contact: linux-iio@vger.kernel.org Description: This attribute is used to read the energy value reported by the @@ -1140,7 +1140,7 @@ Description: What: /sys/.../iio:deviceX/in_distance_input What: /sys/.../iio:deviceX/in_distance_raw -KernelVersion: 3.20 +KernelVersion: 4.0 Contact: linux-iio@vger.kernel.org Description: This attribute is used to read the distance covered by the user @@ -1205,7 +1205,7 @@ Description: seconds. What: /sys/.../iio:deviceX/in_velocity_sqrt(x^2+y^2+z^2)_integration_time -KernelVersion: 3.20 +KernelVersion: 4.0 Contact: linux-iio@vger.kernel.org Description: Number of seconds in which to compute speed. @@ -1267,7 +1267,7 @@ Description: Units after application of scale are m/s. What: /sys/.../iio:deviceX/in_steps_debounce_count -KernelVersion: 3.20 +KernelVersion: 4.0 Contact: linux-iio@vger.kernel.org Description: Specifies the number of steps that must occur within @@ -1275,7 +1275,7 @@ Description: consumer is making steps. What: /sys/.../iio:deviceX/in_steps_debounce_time -KernelVersion: 3.20 +KernelVersion: 4.0 Contact: linux-iio@vger.kernel.org Description: Specifies number of seconds in which we compute the steps -- cgit v1.2.3-59-g8ed1b From 330524404298b2142d2e3a2f64251ca855d55d72 Mon Sep 17 00:00:00 2001 From: Wei Yang Date: Wed, 25 Mar 2015 16:24:01 +0800 Subject: powerpc/pci: Add PCI resource alignment documentation In order to enable SRIOV on PowerNV platform, the PF's IOV BAR needs to be adjusted: 1. size expanded 2. aligned to M64BT size This patch documents this change on the reason and how. [bhelgaas: reformat, clarify, expand] Signed-off-by: Wei Yang Signed-off-by: Benjamin Herrenschmidt --- .../powerpc/pci_iov_resource_on_powernv.txt | 301 +++++++++++++++++++++ 1 file changed, 301 insertions(+) create mode 100644 Documentation/powerpc/pci_iov_resource_on_powernv.txt (limited to 'Documentation') diff --git a/Documentation/powerpc/pci_iov_resource_on_powernv.txt b/Documentation/powerpc/pci_iov_resource_on_powernv.txt new file mode 100644 index 000000000000..b55c5cd83f8d --- /dev/null +++ b/Documentation/powerpc/pci_iov_resource_on_powernv.txt @@ -0,0 +1,301 @@ +Wei Yang +Benjamin Herrenschmidt +Bjorn Helgaas +26 Aug 2014 + +This document describes the requirement from hardware for PCI MMIO resource +sizing and assignment on PowerKVM and how generic PCI code handles this +requirement. The first two sections describe the concepts of Partitionable +Endpoints and the implementation on P8 (IODA2). The next two sections talks +about considerations on enabling SRIOV on IODA2. + +1. Introduction to Partitionable Endpoints + +A Partitionable Endpoint (PE) is a way to group the various resources +associated with a device or a set of devices to provide isolation between +partitions (i.e., filtering of DMA, MSIs etc.) and to provide a mechanism +to freeze a device that is causing errors in order to limit the possibility +of propagation of bad data. + +There is thus, in HW, a table of PE states that contains a pair of "frozen" +state bits (one for MMIO and one for DMA, they get set together but can be +cleared independently) for each PE. + +When a PE is frozen, all stores in any direction are dropped and all loads +return all 1's value. MSIs are also blocked. There's a bit more state that +captures things like the details of the error that caused the freeze etc., but +that's not critical. + +The interesting part is how the various PCIe transactions (MMIO, DMA, ...) +are matched to their corresponding PEs. + +The following section provides a rough description of what we have on P8 +(IODA2). Keep in mind that this is all per PHB (PCI host bridge). Each PHB +is a completely separate HW entity that replicates the entire logic, so has +its own set of PEs, etc. + +2. Implementation of Partitionable Endpoints on P8 (IODA2) + +P8 supports up to 256 Partitionable Endpoints per PHB. + + * Inbound + + For DMA, MSIs and inbound PCIe error messages, we have a table (in + memory but accessed in HW by the chip) that provides a direct + correspondence between a PCIe RID (bus/dev/fn) with a PE number. + We call this the RTT. + + - For DMA we then provide an entire address space for each PE that can + contain two "windows", depending on the value of PCI address bit 59. + Each window can be configured to be remapped via a "TCE table" (IOMMU + translation table), which has various configurable characteristics + not described here. + + - For MSIs, we have two windows in the address space (one at the top of + the 32-bit space and one much higher) which, via a combination of the + address and MSI value, will result in one of the 2048 interrupts per + bridge being triggered. There's a PE# in the interrupt controller + descriptor table as well which is compared with the PE# obtained from + the RTT to "authorize" the device to emit that specific interrupt. + + - Error messages just use the RTT. + + * Outbound. That's where the tricky part is. + + Like other PCI host bridges, the Power8 IODA2 PHB supports "windows" + from the CPU address space to the PCI address space. There is one M32 + window and sixteen M64 windows. They have different characteristics. + First what they have in common: they forward a configurable portion of + the CPU address space to the PCIe bus and must be naturally aligned + power of two in size. The rest is different: + + - The M32 window: + + * Is limited to 4GB in size. + + * Drops the top bits of the address (above the size) and replaces + them with a configurable value. This is typically used to generate + 32-bit PCIe accesses. We configure that window at boot from FW and + don't touch it from Linux; it's usually set to forward a 2GB + portion of address space from the CPU to PCIe + 0x8000_0000..0xffff_ffff. (Note: The top 64KB are actually + reserved for MSIs but this is not a problem at this point; we just + need to ensure Linux doesn't assign anything there, the M32 logic + ignores that however and will forward in that space if we try). + + * It is divided into 256 segments of equal size. A table in the chip + maps each segment to a PE#. That allows portions of the MMIO space + to be assigned to PEs on a segment granularity. For a 2GB window, + the segment granularity is 2GB/256 = 8MB. + + Now, this is the "main" window we use in Linux today (excluding + SR-IOV). We basically use the trick of forcing the bridge MMIO windows + onto a segment alignment/granularity so that the space behind a bridge + can be assigned to a PE. + + Ideally we would like to be able to have individual functions in PEs + but that would mean using a completely different address allocation + scheme where individual function BARs can be "grouped" to fit in one or + more segments. + + - The M64 windows: + + * Must be at least 256MB in size. + + * Do not translate addresses (the address on PCIe is the same as the + address on the PowerBus). There is a way to also set the top 14 + bits which are not conveyed by PowerBus but we don't use this. + + * Can be configured to be segmented. When not segmented, we can + specify the PE# for the entire window. When segmented, a window + has 256 segments; however, there is no table for mapping a segment + to a PE#. The segment number *is* the PE#. + + * Support overlaps. If an address is covered by multiple windows, + there's a defined ordering for which window applies. + + We have code (fairly new compared to the M32 stuff) that exploits that + for large BARs in 64-bit space: + + We configure an M64 window to cover the entire region of address space + that has been assigned by FW for the PHB (about 64GB, ignore the space + for the M32, it comes out of a different "reserve"). We configure it + as segmented. + + Then we do the same thing as with M32, using the bridge alignment + trick, to match to those giant segments. + + Since we cannot remap, we have two additional constraints: + + - We do the PE# allocation *after* the 64-bit space has been assigned + because the addresses we use directly determine the PE#. We then + update the M32 PE# for the devices that use both 32-bit and 64-bit + spaces or assign the remaining PE# to 32-bit only devices. + + - We cannot "group" segments in HW, so if a device ends up using more + than one segment, we end up with more than one PE#. There is a HW + mechanism to make the freeze state cascade to "companion" PEs but + that only works for PCIe error messages (typically used so that if + you freeze a switch, it freezes all its children). So we do it in + SW. We lose a bit of effectiveness of EEH in that case, but that's + the best we found. So when any of the PEs freezes, we freeze the + other ones for that "domain". We thus introduce the concept of + "master PE" which is the one used for DMA, MSIs, etc., and "secondary + PEs" that are used for the remaining M64 segments. + + We would like to investigate using additional M64 windows in "single + PE" mode to overlay over specific BARs to work around some of that, for + example for devices with very large BARs, e.g., GPUs. It would make + sense, but we haven't done it yet. + +3. Considerations for SR-IOV on PowerKVM + + * SR-IOV Background + + The PCIe SR-IOV feature allows a single Physical Function (PF) to + support several Virtual Functions (VFs). Registers in the PF's SR-IOV + Capability control the number of VFs and whether they are enabled. + + When VFs are enabled, they appear in Configuration Space like normal + PCI devices, but the BARs in VF config space headers are unusual. For + a non-VF device, software uses BARs in the config space header to + discover the BAR sizes and assign addresses for them. For VF devices, + software uses VF BAR registers in the *PF* SR-IOV Capability to + discover sizes and assign addresses. The BARs in the VF's config space + header are read-only zeros. + + When a VF BAR in the PF SR-IOV Capability is programmed, it sets the + base address for all the corresponding VF(n) BARs. For example, if the + PF SR-IOV Capability is programmed to enable eight VFs, and it has a + 1MB VF BAR0, the address in that VF BAR sets the base of an 8MB region. + This region is divided into eight contiguous 1MB regions, each of which + is a BAR0 for one of the VFs. Note that even though the VF BAR + describes an 8MB region, the alignment requirement is for a single VF, + i.e., 1MB in this example. + + There are several strategies for isolating VFs in PEs: + + - M32 window: There's one M32 window, and it is split into 256 + equally-sized segments. The finest granularity possible is a 256MB + window with 1MB segments. VF BARs that are 1MB or larger could be + mapped to separate PEs in this window. Each segment can be + individually mapped to a PE via the lookup table, so this is quite + flexible, but it works best when all the VF BARs are the same size. If + they are different sizes, the entire window has to be small enough that + the segment size matches the smallest VF BAR, which means larger VF + BARs span several segments. + + - Non-segmented M64 window: A non-segmented M64 window is mapped entirely + to a single PE, so it could only isolate one VF. + + - Single segmented M64 windows: A segmented M64 window could be used just + like the M32 window, but the segments can't be individually mapped to + PEs (the segment number is the PE#), so there isn't as much + flexibility. A VF with multiple BARs would have to be in a "domain" of + multiple PEs, which is not as well isolated as a single PE. + + - Multiple segmented M64 windows: As usual, each window is split into 256 + equally-sized segments, and the segment number is the PE#. But if we + use several M64 windows, they can be set to different base addresses + and different segment sizes. If we have VFs that each have a 1MB BAR + and a 32MB BAR, we could use one M64 window to assign 1MB segments and + another M64 window to assign 32MB segments. + + Finally, the plan to use M64 windows for SR-IOV, which will be described + more in the next two sections. For a given VF BAR, we need to + effectively reserve the entire 256 segments (256 * VF BAR size) and + position the VF BAR to start at the beginning of a free range of + segments/PEs inside that M64 window. + + The goal is of course to be able to give a separate PE for each VF. + + The IODA2 platform has 16 M64 windows, which are used to map MMIO + range to PE#. Each M64 window defines one MMIO range and this range is + divided into 256 segments, with each segment corresponding to one PE. + + We decide to leverage this M64 window to map VFs to individual PEs, since + SR-IOV VF BARs are all the same size. + + But doing so introduces another problem: total_VFs is usually smaller + than the number of M64 window segments, so if we map one VF BAR directly + to one M64 window, some part of the M64 window will map to another + device's MMIO range. + + IODA supports 256 PEs, so segmented windows contain 256 segments, so if + total_VFs is less than 256, we have the situation in Figure 1.0, where + segments [total_VFs, 255] of the M64 window may map to some MMIO range on + other devices: + + 0 1 total_VFs - 1 + +------+------+- -+------+------+ + | | | ... | | | + +------+------+- -+------+------+ + + VF(n) BAR space + + 0 1 total_VFs - 1 255 + +------+------+- -+------+------+- -+------+------+ + | | | ... | | | ... | | | + +------+------+- -+------+------+- -+------+------+ + + M64 window + + Figure 1.0 Direct map VF(n) BAR space + + Our current solution is to allocate 256 segments even if the VF(n) BAR + space doesn't need that much, as shown in Figure 1.1: + + 0 1 total_VFs - 1 255 + +------+------+- -+------+------+- -+------+------+ + | | | ... | | | ... | | | + +------+------+- -+------+------+- -+------+------+ + + VF(n) BAR space + extra + + 0 1 total_VFs - 1 255 + +------+------+- -+------+------+- -+------+------+ + | | | ... | | | ... | | | + +------+------+- -+------+------+- -+------+------+ + + M64 window + + Figure 1.1 Map VF(n) BAR space + extra + + Allocating the extra space ensures that the entire M64 window will be + assigned to this one SR-IOV device and none of the space will be + available for other devices. Note that this only expands the space + reserved in software; there are still only total_VFs VFs, and they only + respond to segments [0, total_VFs - 1]. There's nothing in hardware that + responds to segments [total_VFs, 255]. + +4. Implications for the Generic PCI Code + +The PCIe SR-IOV spec requires that the base of the VF(n) BAR space be +aligned to the size of an individual VF BAR. + +In IODA2, the MMIO address determines the PE#. If the address is in an M32 +window, we can set the PE# by updating the table that translates segments +to PE#s. Similarly, if the address is in an unsegmented M64 window, we can +set the PE# for the window. But if it's in a segmented M64 window, the +segment number is the PE#. + +Therefore, the only way to control the PE# for a VF is to change the base +of the VF(n) BAR space in the VF BAR. If the PCI core allocates the exact +amount of space required for the VF(n) BAR space, the VF BAR value is fixed +and cannot be changed. + +On the other hand, if the PCI core allocates additional space, the VF BAR +value can be changed as long as the entire VF(n) BAR space remains inside +the space allocated by the core. + +Ideally the segment size will be the same as an individual VF BAR size. +Then each VF will be in its own PE. The VF BARs (and therefore the PE#s) +are contiguous. If VF0 is in PE(x), then VF(n) is in PE(x+n). If we +allocate 256 segments, there are (256 - numVFs) choices for the PE# of VF0. + +If the segment size is smaller than the VF BAR size, it will take several +segments to cover a VF BAR, and a VF will be in several PEs. This is +possible, but the isolation isn't as good, and it reduces the number of PE# +choices because instead of consuming only numVFs segments, the VF(n) BAR +space will consume (numVFs * n) segments. That means there aren't as many +available segments for adjusting base of the VF(n) BAR space. -- cgit v1.2.3-59-g8ed1b From e14ba3cdd6dddb004def9811ee057576e53ca9a0 Mon Sep 17 00:00:00 2001 From: Andrew Bresticker Date: Mon, 16 Mar 2015 14:43:09 -0700 Subject: MIPS: Document Pistachio boot protocol and device-tree bindings The Pistachio SoC boots only with device-tree. Document the required properties and nodes as well as the boot protocol between the bootlaoder and the kernel. Signed-off-by: Andrew Bresticker Cc: Rob Herring Cc: Pawel Moll Cc: Mark Rutland Cc: Ian Campbell Cc: Kumar Gala Cc: devicetree@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: Andrew Bresticker Cc: Ezequiel Garcia Cc: James Hartley Cc: James Hogan Patchwork: https://patchwork.linux-mips.org/patch/9568/ Signed-off-by: Ralf Baechle --- .../devicetree/bindings/mips/img/pistachio.txt | 42 ++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 Documentation/devicetree/bindings/mips/img/pistachio.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mips/img/pistachio.txt b/Documentation/devicetree/bindings/mips/img/pistachio.txt new file mode 100644 index 000000000000..a736d889c2b8 --- /dev/null +++ b/Documentation/devicetree/bindings/mips/img/pistachio.txt @@ -0,0 +1,42 @@ +Imagination Pistachio SoC +========================= + +Required properties: +-------------------- + - compatible: Must include "img,pistachio". + +CPU nodes: +---------- +A "cpus" node is required. Required properties: + - #address-cells: Must be 1. + - #size-cells: Must be 0. +A CPU sub-node is also required for at least CPU 0. Since the topology may +be probed via CPS, it is not necessary to specify secondary CPUs. Required +propertis: + - device_type: Must be "cpu". + - compatible: Must be "mti,interaptiv". + - reg: CPU number. + - clocks: Must include the CPU clock. See ../../clock/clock-bindings.txt for + details on clock bindings. +Example: + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "mti,interaptiv"; + reg = <0>; + clocks = <&clk_core CLK_MIPS>; + }; + }; + + +Boot protocol: +-------------- +In accordance with the MIPS UHI specification[1], the bootloader must pass the +following arguments to the kernel: + - $a0: -2. + - $a1: KSEG0 address of the flattened device-tree blob. + +[1] http://prplfoundation.org/wiki/MIPS_documentation -- cgit v1.2.3-59-g8ed1b From e73f6e8a0de8ce28edef986d86720ef83dd2864f Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Fri, 27 Feb 2015 15:25:31 -0500 Subject: dm switch: fix Documentation to use plain text Signed-off-by: Mike Snitzer --- Documentation/device-mapper/switch.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/device-mapper/switch.txt b/Documentation/device-mapper/switch.txt index 8897d0494838..424835e57f27 100644 --- a/Documentation/device-mapper/switch.txt +++ b/Documentation/device-mapper/switch.txt @@ -47,8 +47,8 @@ consume far too much memory. Using this device-mapper switch target we can now build a two-layer device hierarchy: - Upper Tier – Determine which array member the I/O should be sent to. - Lower Tier – Load balance amongst paths to a particular member. + Upper Tier - Determine which array member the I/O should be sent to. + Lower Tier - Load balance amongst paths to a particular member. The lower tier consists of a single dm multipath device for each member. Each of these multipath devices contains the set of paths directly to -- cgit v1.2.3-59-g8ed1b From 18779b75e90e75bf7f1aee8e71307b69fa5f7631 Mon Sep 17 00:00:00 2001 From: Casey Schaufler Date: Tue, 31 Mar 2015 09:49:40 -0700 Subject: Smack: Updates for Smack documentation Document the Smack bringup features. Update the proper location for mounting smackfs from /smack to /sys/fs/smackfs. Fix some spelling errors. Suggest the use of the load2 interface instead of the load interface. Signed-off-by: Casey Schaufler --- Documentation/security/Smack.txt | 129 ++++++++++++++++++++++++--------------- 1 file changed, 79 insertions(+), 50 deletions(-) (limited to 'Documentation') diff --git a/Documentation/security/Smack.txt b/Documentation/security/Smack.txt index b6ef7e9dba30..abc82f85215b 100644 --- a/Documentation/security/Smack.txt +++ b/Documentation/security/Smack.txt @@ -33,11 +33,18 @@ The current git repository for Smack user space is: git://github.com/smack-team/smack.git This should make and install on most modern distributions. -There are three commands included in smackutil: +There are five commands included in smackutil: -smackload - properly formats data for writing to /smack/load -smackcipso - properly formats data for writing to /smack/cipso chsmack - display or set Smack extended attribute values +smackctl - load the Smack access rules +smackaccess - report if a process with one label has access + to an object with another + +These two commands are obsolete with the introduction of +the smackfs/load2 and smackfs/cipso2 interfaces. + +smackload - properly formats data for writing to smackfs/load +smackcipso - properly formats data for writing to smackfs/cipso In keeping with the intent of Smack, configuration data is minimal and not strictly required. The most important @@ -47,9 +54,9 @@ of this, but it can be manually as well. Add this line to /etc/fstab: - smackfs /smack smackfs smackfsdef=* 0 0 + smackfs /sys/fs/smackfs smackfs defaults 0 0 -and create the /smack directory for mounting. +The /sys/fs/smackfs directory is created by the kernel. Smack uses extended attributes (xattrs) to store labels on filesystem objects. The attributes are stored in the extended attribute security @@ -92,13 +99,13 @@ There are multiple ways to set a Smack label on a file: # attr -S -s SMACK64 -V "value" path # chsmack -a value path -A process can see the smack label it is running with by +A process can see the Smack label it is running with by reading /proc/self/attr/current. A process with CAP_MAC_ADMIN -can set the process smack by writing there. +can set the process Smack by writing there. Most Smack configuration is accomplished by writing to files -in the smackfs filesystem. This pseudo-filesystem is usually -mounted on /smack. +in the smackfs filesystem. This pseudo-filesystem is mounted +on /sys/fs/smackfs. access This interface reports whether a subject with the specified @@ -206,23 +213,30 @@ onlycap file or cleared by writing "-" to the file. ptrace This is used to define the current ptrace policy - 0 - default: this is the policy that relies on smack access rules. + 0 - default: this is the policy that relies on Smack access rules. For the PTRACE_READ a subject needs to have a read access on object. For the PTRACE_ATTACH a read-write access is required. 1 - exact: this is the policy that limits PTRACE_ATTACH. Attach is only allowed when subject's and object's labels are equal. - PTRACE_READ is not affected. Can be overriden with CAP_SYS_PTRACE. + PTRACE_READ is not affected. Can be overridden with CAP_SYS_PTRACE. 2 - draconian: this policy behaves like the 'exact' above with an - exception that it can't be overriden with CAP_SYS_PTRACE. + exception that it can't be overridden with CAP_SYS_PTRACE. revoke-subject Writing a Smack label here sets the access to '-' for all access rules with that subject label. +unconfined + If the kernel is configured with CONFIG_SECURITY_SMACK_BRINGUP + a process with CAP_MAC_ADMIN can write a label into this interface. + Thereafter, accesses that involve that label will be logged and + the access permitted if it wouldn't be otherwise. Note that this + is dangerous and can ruin the proper labeling of your system. + It should never be used in production. You can add access rules in /etc/smack/accesses. They take the form: subjectlabel objectlabel access -access is a combination of the letters rwxa which specify the +access is a combination of the letters rwxatb which specify the kind of access permitted a subject with subjectlabel on an object with objectlabel. If there is no rule no access is allowed. @@ -318,8 +332,9 @@ each of the subject and the object. Labels -Smack labels are ASCII character strings, one to twenty-three characters in -length. Single character labels using special characters, that being anything +Smack labels are ASCII character strings. They can be up to 255 characters +long, but keeping them to twenty-three characters is recommended. +Single character labels using special characters, that being anything other than a letter or digit, are reserved for use by the Smack development team. Smack labels are unstructured, case sensitive, and the only operation ever performed on them is comparison for equality. Smack labels cannot @@ -335,10 +350,9 @@ There are some predefined labels: ? Pronounced "huh", a single question mark character. @ Pronounced "web", a single at sign character. -Every task on a Smack system is assigned a label. System tasks, such as -init(8) and systems daemons, are run with the floor ("_") label. User tasks -are assigned labels according to the specification found in the -/etc/smack/user configuration file. +Every task on a Smack system is assigned a label. The Smack label +of a process will usually be assigned by the system initialization +mechanism. Access Rules @@ -393,6 +407,7 @@ describe access modes: w: indicates that write access should be granted. x: indicates that execute access should be granted. t: indicates that the rule requests transmutation. + b: indicates that the rule should be reported for bring-up. Uppercase values for the specification letters are allowed as well. Access mode specifications can be in any order. Examples of acceptable rules @@ -402,6 +417,7 @@ are: Secret Unclass R Manager Game x User HR w + Snap Crackle rwxatb New Old rRrRr Closed Off - @@ -413,7 +429,7 @@ Examples of unacceptable rules are: Spaces are not allowed in labels. Since a subject always has access to files with the same label specifying a rule for that case is pointless. Only -valid letters (rwxatRWXAT) and the dash ('-') character are allowed in +valid letters (rwxatbRWXATB) and the dash ('-') character are allowed in access specifications. The dash is a placeholder, so "a-r" is the same as "ar". A lone dash is used to specify that no access should be allowed. @@ -462,16 +478,11 @@ receiver. The receiver is not required to have read access to the sender. Setting Access Rules The configuration file /etc/smack/accesses contains the rules to be set at -system startup. The contents are written to the special file /smack/load. -Rules can be written to /smack/load at any time and take effect immediately. -For any pair of subject and object labels there can be only one rule, with the -most recently specified overriding any earlier specification. - -The program smackload is provided to ensure data is formatted -properly when written to /smack/load. This program reads lines -of the form - - subjectlabel objectlabel mode. +system startup. The contents are written to the special file +/sys/fs/smackfs/load2. Rules can be added at any time and take effect +immediately. For any pair of subject and object labels there can be only +one rule, with the most recently specified overriding any earlier +specification. Task Attribute @@ -488,7 +499,10 @@ only be changed by a process with privilege. Privilege -A process with CAP_MAC_OVERRIDE is privileged. +A process with CAP_MAC_OVERRIDE or CAP_MAC_ADMIN is privileged. +CAP_MAC_OVERRIDE allows the process access to objects it would +be denied otherwise. CAP_MAC_ADMIN allows a process to change +Smack data, including rules and attributes. Smack Networking @@ -510,14 +524,14 @@ intervention. Unlabeled packets that come into the system will be given the ambient label. Smack requires configuration in the case where packets from a system that is -not smack that speaks CIPSO may be encountered. Usually this will be a Trusted +not Smack that speaks CIPSO may be encountered. Usually this will be a Trusted Solaris system, but there are other, less widely deployed systems out there. CIPSO provides 3 important values, a Domain Of Interpretation (DOI), a level, and a category set with each packet. The DOI is intended to identify a group of systems that use compatible labeling schemes, and the DOI specified on the -smack system must match that of the remote system or packets will be -discarded. The DOI is 3 by default. The value can be read from /smack/doi and -can be changed by writing to /smack/doi. +Smack system must match that of the remote system or packets will be +discarded. The DOI is 3 by default. The value can be read from +/sys/fs/smackfs/doi and can be changed by writing to /sys/fs/smackfs/doi. The label and category set are mapped to a Smack label as defined in /etc/smack/cipso. @@ -539,15 +553,13 @@ The ":" and "," characters are permitted in a Smack label but have no special meaning. The mapping of Smack labels to CIPSO values is defined by writing to -/smack/cipso. Again, the format of data written to this special file -is highly restrictive, so the program smackcipso is provided to -ensure the writes are done properly. This program takes mappings -on the standard input and sends them to /smack/cipso properly. +/sys/fs/smackfs/cipso2. In addition to explicit mappings Smack supports direct CIPSO mappings. One CIPSO level is used to indicate that the category set passed in the packet is in fact an encoding of the Smack label. The level used is 250 by default. The -value can be read from /smack/direct and changed by writing to /smack/direct. +value can be read from /sys/fs/smackfs/direct and changed by writing to +/sys/fs/smackfs/direct. Socket Attributes @@ -565,8 +577,8 @@ sockets. Smack Netlabel Exceptions You will often find that your labeled application has to talk to the outside, -unlabeled world. To do this there's a special file /smack/netlabel where you can -add some exceptions in the form of : +unlabeled world. To do this there's a special file /sys/fs/smackfs/netlabel +where you can add some exceptions in the form of : @IP1 LABEL1 or @IP2/MASK LABEL2 @@ -574,22 +586,22 @@ It means that your application will have unlabeled access to @IP1 if it has write access on LABEL1, and access to the subnet @IP2/MASK if it has write access on LABEL2. -Entries in the /smack/netlabel file are matched by longest mask first, like in -classless IPv4 routing. +Entries in the /sys/fs/smackfs/netlabel file are matched by longest mask +first, like in classless IPv4 routing. A special label '@' and an option '-CIPSO' can be used there : @ means Internet, any application with any label has access to it -CIPSO means standard CIPSO networking If you don't know what CIPSO is and don't plan to use it, you can just do : -echo 127.0.0.1 -CIPSO > /smack/netlabel -echo 0.0.0.0/0 @ > /smack/netlabel +echo 127.0.0.1 -CIPSO > /sys/fs/smackfs/netlabel +echo 0.0.0.0/0 @ > /sys/fs/smackfs/netlabel If you use CIPSO on your 192.168.0.0/16 local network and need also unlabeled Internet access, you can have : -echo 127.0.0.1 -CIPSO > /smack/netlabel -echo 192.168.0.0/16 -CIPSO > /smack/netlabel -echo 0.0.0.0/0 @ > /smack/netlabel +echo 127.0.0.1 -CIPSO > /sys/fs/smackfs/netlabel +echo 192.168.0.0/16 -CIPSO > /sys/fs/smackfs/netlabel +echo 0.0.0.0/0 @ > /sys/fs/smackfs/netlabel Writing Applications for Smack @@ -676,7 +688,7 @@ Smack auditing If you want Smack auditing of security events, you need to set CONFIG_AUDIT in your kernel configuration. By default, all denied events will be audited. You can change this behavior by -writing a single character to the /smack/logging file : +writing a single character to the /sys/fs/smackfs/logging file : 0 : no logging 1 : log denied (default) 2 : log accepted @@ -686,3 +698,20 @@ Events are logged as 'key=value' pairs, for each event you at least will get the subject, the object, the rights requested, the action, the kernel function that triggered the event, plus other pairs depending on the type of event audited. + +Bringup Mode + +Bringup mode provides logging features that can make application +configuration and system bringup easier. Configure the kernel with +CONFIG_SECURITY_SMACK_BRINGUP to enable these features. When bringup +mode is enabled accesses that succeed due to rules marked with the "b" +access mode will logged. When a new label is introduced for processes +rules can be added aggressively, marked with the "b". The logging allows +tracking of which rules actual get used for that label. + +Another feature of bringup mode is the "unconfined" option. Writing +a label to /sys/fs/smackfs/unconfined makes subjects with that label +able to access any object, and objects with that label accessible to +all subjects. Any access that is granted because a label is unconfined +is logged. This feature is dangerous, as files and directories may +be created in places they couldn't if the policy were being enforced. -- cgit v1.2.3-59-g8ed1b From 94aa033efcac47b09db22cb561e135baf37b7887 Mon Sep 17 00:00:00 2001 From: Jens Freimann Date: Mon, 16 Mar 2015 12:17:13 +0100 Subject: KVM: s390: fix get_all_floating_irqs This fixes a bug introduced with commit c05c4186bbe4 ("KVM: s390: add floating irq controller"). get_all_floating_irqs() does copy_to_user() while holding a spin lock. Let's fix this by filling a temporary buffer first and copy it to userspace after giving up the lock. Cc: # 3.18+: 69a8d4562638 KVM: s390: no need to hold... Reviewed-by: David Hildenbrand Signed-off-by: Jens Freimann Signed-off-by: Christian Borntraeger Acked-by: Cornelia Huck --- Documentation/virtual/kvm/devices/s390_flic.txt | 3 ++ arch/s390/kvm/interrupt.c | 58 ++++++++++++++----------- 2 files changed, 35 insertions(+), 26 deletions(-) (limited to 'Documentation') diff --git a/Documentation/virtual/kvm/devices/s390_flic.txt b/Documentation/virtual/kvm/devices/s390_flic.txt index 4ceef53164b0..d1ad9d5cae46 100644 --- a/Documentation/virtual/kvm/devices/s390_flic.txt +++ b/Documentation/virtual/kvm/devices/s390_flic.txt @@ -27,6 +27,9 @@ Groups: Copies all floating interrupts into a buffer provided by userspace. When the buffer is too small it returns -ENOMEM, which is the indication for userspace to try again with a bigger buffer. + -ENOBUFS is returned when the allocation of a kernelspace buffer has + failed. + -EFAULT is returned when copying data to userspace failed. All interrupts remain pending, i.e. are not deleted from the list of currently pending interrupts. attr->addr contains the userspace address of the buffer into which all diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index 2361b8ed0a50..5ebd500e6400 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -1477,61 +1478,66 @@ void kvm_s390_clear_float_irqs(struct kvm *kvm) spin_unlock(&fi->lock); } -static inline int copy_irq_to_user(struct kvm_s390_interrupt_info *inti, - u8 *addr) +static void inti_to_irq(struct kvm_s390_interrupt_info *inti, + struct kvm_s390_irq *irq) { - struct kvm_s390_irq __user *uptr = (struct kvm_s390_irq __user *) addr; - struct kvm_s390_irq irq = {0}; - - irq.type = inti->type; + irq->type = inti->type; switch (inti->type) { case KVM_S390_INT_PFAULT_INIT: case KVM_S390_INT_PFAULT_DONE: case KVM_S390_INT_VIRTIO: case KVM_S390_INT_SERVICE: - irq.u.ext = inti->ext; + irq->u.ext = inti->ext; break; case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX: - irq.u.io = inti->io; + irq->u.io = inti->io; break; case KVM_S390_MCHK: - irq.u.mchk = inti->mchk; + irq->u.mchk = inti->mchk; break; - default: - return -EINVAL; } - - if (copy_to_user(uptr, &irq, sizeof(irq))) - return -EFAULT; - - return 0; } -static int get_all_floating_irqs(struct kvm *kvm, __u8 *buf, __u64 len) +static int get_all_floating_irqs(struct kvm *kvm, u8 __user *usrbuf, u64 len) { struct kvm_s390_interrupt_info *inti; struct kvm_s390_float_interrupt *fi; + struct kvm_s390_irq *buf; + int max_irqs; int ret = 0; int n = 0; + if (len > KVM_S390_FLIC_MAX_BUFFER || len == 0) + return -EINVAL; + + /* + * We are already using -ENOMEM to signal + * userspace it may retry with a bigger buffer, + * so we need to use something else for this case + */ + buf = vzalloc(len); + if (!buf) + return -ENOBUFS; + + max_irqs = len / sizeof(struct kvm_s390_irq); + fi = &kvm->arch.float_int; spin_lock(&fi->lock); - list_for_each_entry(inti, &fi->list, list) { - if (len < sizeof(struct kvm_s390_irq)) { + if (n == max_irqs) { /* signal userspace to try again */ ret = -ENOMEM; break; } - ret = copy_irq_to_user(inti, buf); - if (ret) - break; - buf += sizeof(struct kvm_s390_irq); - len -= sizeof(struct kvm_s390_irq); + inti_to_irq(inti, &buf[n]); n++; } - spin_unlock(&fi->lock); + if (!ret && n > 0) { + if (copy_to_user(usrbuf, buf, sizeof(struct kvm_s390_irq) * n)) + ret = -EFAULT; + } + vfree(buf); return ret < 0 ? ret : n; } @@ -1542,7 +1548,7 @@ static int flic_get_attr(struct kvm_device *dev, struct kvm_device_attr *attr) switch (attr->group) { case KVM_DEV_FLIC_GET_ALL_IRQS: - r = get_all_floating_irqs(dev->kvm, (u8 *) attr->addr, + r = get_all_floating_irqs(dev->kvm, (u8 __user *) attr->addr, attr->attr); break; default: -- cgit v1.2.3-59-g8ed1b From 47b43c52ee4b0425449d1b2b1eedca7f6b7a578a Mon Sep 17 00:00:00 2001 From: Jens Freimann Date: Tue, 11 Nov 2014 20:57:06 +0100 Subject: KVM: s390: add ioctl to inject local interrupts We have introduced struct kvm_s390_irq a while ago which allows to inject all kinds of interrupts as defined in the Principles of Operation. Add ioctl to inject interrupts with the extended struct kvm_s390_irq Signed-off-by: Jens Freimann Signed-off-by: Christian Borntraeger Acked-by: Cornelia Huck --- Documentation/virtual/kvm/api.txt | 56 +++++++++++++++++++++++++++++++++++++++ arch/s390/kvm/kvm-s390.c | 10 +++++++ include/uapi/linux/kvm.h | 3 +++ virt/kvm/kvm_main.c | 2 +- 4 files changed, 70 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 0d7fc66289a0..a7c651d0dc63 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -2820,6 +2820,62 @@ single frame starting at start_gfn for count frames. Note: If any architecturally invalid key value is found in the given data then the ioctl will return -EINVAL. +4.92 KVM_S390_IRQ + +Capability: KVM_CAP_S390_INJECT_IRQ +Architectures: s390 +Type: vcpu ioctl +Parameters: struct kvm_s390_irq (in) +Returns: 0 on success, -1 on error +Errors: + EINVAL: interrupt type is invalid + type is KVM_S390_SIGP_STOP and flag parameter is invalid value + type is KVM_S390_INT_EXTERNAL_CALL and code is bigger + than the maximum of VCPUs + EBUSY: type is KVM_S390_SIGP_SET_PREFIX and vcpu is not stopped + type is KVM_S390_SIGP_STOP and a stop irq is already pending + type is KVM_S390_INT_EXTERNAL_CALL and an external call interrupt + is already pending + +Allows to inject an interrupt to the guest. + +Using struct kvm_s390_irq as a parameter allows +to inject additional payload which is not +possible via KVM_S390_INTERRUPT. + +Interrupt parameters are passed via kvm_s390_irq: + +struct kvm_s390_irq { + __u64 type; + union { + struct kvm_s390_io_info io; + struct kvm_s390_ext_info ext; + struct kvm_s390_pgm_info pgm; + struct kvm_s390_emerg_info emerg; + struct kvm_s390_extcall_info extcall; + struct kvm_s390_prefix_info prefix; + struct kvm_s390_stop_info stop; + struct kvm_s390_mchk_info mchk; + char reserved[64]; + } u; +}; + +type can be one of the following: + +KVM_S390_SIGP_STOP - sigp stop; parameter in .stop +KVM_S390_PROGRAM_INT - program check; parameters in .pgm +KVM_S390_SIGP_SET_PREFIX - sigp set prefix; parameters in .prefix +KVM_S390_RESTART - restart; no parameters +KVM_S390_INT_CLOCK_COMP - clock comparator interrupt; no parameters +KVM_S390_INT_CPU_TIMER - CPU timer interrupt; no parameters +KVM_S390_INT_EMERGENCY - sigp emergency; parameters in .emerg +KVM_S390_INT_EXTERNAL_CALL - sigp external call; parameters in .extcall +KVM_S390_MCHK - machine check interrupt; parameters in .mchk + + +Note that the vcpu ioctl is asynchronous to vcpu execution. + + 5. The kvm_run structure ------------------------ diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index dbc9ca34d9da..8bc25d405edf 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -177,6 +177,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_S390_IRQCHIP: case KVM_CAP_VM_ATTRIBUTES: case KVM_CAP_MP_STATE: + case KVM_CAP_S390_INJECT_IRQ: case KVM_CAP_S390_USER_SIGP: case KVM_CAP_S390_USER_STSI: case KVM_CAP_S390_SKEYS: @@ -2391,6 +2392,15 @@ long kvm_arch_vcpu_ioctl(struct file *filp, long r; switch (ioctl) { + case KVM_S390_IRQ: { + struct kvm_s390_irq s390irq; + + r = -EFAULT; + if (copy_from_user(&s390irq, argp, sizeof(s390irq))) + break; + r = kvm_s390_inject_vcpu(vcpu, &s390irq); + break; + } case KVM_S390_INTERRUPT: { struct kvm_s390_interrupt s390int; struct kvm_s390_irq s390irq; diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 1162ef7a3fa1..c0632e87a00f 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -802,6 +802,7 @@ struct kvm_ppc_smmu_info { #define KVM_CAP_S390_MEM_OP 108 #define KVM_CAP_S390_USER_STSI 109 #define KVM_CAP_S390_SKEYS 110 +#define KVM_CAP_S390_INJECT_IRQ 113 #ifdef KVM_CAP_IRQ_ROUTING @@ -1182,6 +1183,8 @@ struct kvm_s390_ucas_mapping { /* Available with KVM_CAP_S390_SKEYS */ #define KVM_S390_GET_SKEYS _IOW(KVMIO, 0xb2, struct kvm_s390_skeys) #define KVM_S390_SET_SKEYS _IOW(KVMIO, 0xb3, struct kvm_s390_skeys) +/* Available with KVM_CAP_S390_INJECT_IRQ */ +#define KVM_S390_IRQ _IOW(KVMIO, 0xb4, struct kvm_s390_irq) #define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0) #define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1) diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index a1093700f3a4..34310a8d24b9 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -2118,7 +2118,7 @@ static long kvm_vcpu_ioctl(struct file *filp, * Special cases: vcpu ioctls that are asynchronous to vcpu execution, * so vcpu_load() would break it. */ - if (ioctl == KVM_S390_INTERRUPT || ioctl == KVM_INTERRUPT) + if (ioctl == KVM_S390_INTERRUPT || ioctl == KVM_S390_IRQ || ioctl == KVM_INTERRUPT) return kvm_arch_vcpu_ioctl(filp, ioctl, arg); #endif -- cgit v1.2.3-59-g8ed1b From 816c7667ea97c61884e014cfeedaede5b67b0e58 Mon Sep 17 00:00:00 2001 From: Jens Freimann Date: Mon, 24 Nov 2014 17:13:46 +0100 Subject: KVM: s390: migrate vcpu interrupt state This patch adds support to migrate vcpu interrupts. Two new vcpu ioctls are added which get/set the complete status of pending interrupts in one go. The ioctls are marked as available with the new capability KVM_CAP_S390_IRQ_STATE. We can not use a ONEREG, as the number of pending local interrupts is not constant and depends on the number of CPUs. To retrieve the interrupt state we add an ioctl KVM_S390_GET_IRQ_STATE. Its input parameter is a pointer to a struct kvm_s390_irq_state which has a buffer and length. For all currently pending interrupts, we copy a struct kvm_s390_irq into the buffer and pass it to userspace. To store interrupt state into a buffer provided by userspace, we add an ioctl KVM_S390_SET_IRQ_STATE. It passes a struct kvm_s390_irq_state into the kernel and injects all interrupts contained in the buffer. Signed-off-by: Jens Freimann Signed-off-by: Christian Borntraeger Acked-by: Cornelia Huck --- Documentation/virtual/kvm/api.txt | 61 +++++++++++++++++ arch/s390/kvm/interrupt.c | 140 ++++++++++++++++++++++++++++++++++++++ arch/s390/kvm/kvm-s390.c | 36 ++++++++++ arch/s390/kvm/kvm-s390.h | 4 ++ include/uapi/linux/kvm.h | 11 +++ 5 files changed, 252 insertions(+) (limited to 'Documentation') diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index a7c651d0dc63..18fb7630e2ad 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -2875,6 +2875,67 @@ KVM_S390_MCHK - machine check interrupt; parameters in .mchk Note that the vcpu ioctl is asynchronous to vcpu execution. +4.94 KVM_S390_GET_IRQ_STATE + +Capability: KVM_CAP_S390_IRQ_STATE +Architectures: s390 +Type: vcpu ioctl +Parameters: struct kvm_s390_irq_state (out) +Returns: >= number of bytes copied into buffer, + -EINVAL if buffer size is 0, + -ENOBUFS if buffer size is too small to fit all pending interrupts, + -EFAULT if the buffer address was invalid + +This ioctl allows userspace to retrieve the complete state of all currently +pending interrupts in a single buffer. Use cases include migration +and introspection. The parameter structure contains the address of a +userspace buffer and its length: + +struct kvm_s390_irq_state { + __u64 buf; + __u32 flags; + __u32 len; + __u32 reserved[4]; +}; + +Userspace passes in the above struct and for each pending interrupt a +struct kvm_s390_irq is copied to the provided buffer. + +If -ENOBUFS is returned the buffer provided was too small and userspace +may retry with a bigger buffer. + +4.95 KVM_S390_SET_IRQ_STATE + +Capability: KVM_CAP_S390_IRQ_STATE +Architectures: s390 +Type: vcpu ioctl +Parameters: struct kvm_s390_irq_state (in) +Returns: 0 on success, + -EFAULT if the buffer address was invalid, + -EINVAL for an invalid buffer length (see below), + -EBUSY if there were already interrupts pending, + errors occurring when actually injecting the + interrupt. See KVM_S390_IRQ. + +This ioctl allows userspace to set the complete state of all cpu-local +interrupts currently pending for the vcpu. It is intended for restoring +interrupt state after a migration. The input parameter is a userspace buffer +containing a struct kvm_s390_irq_state: + +struct kvm_s390_irq_state { + __u64 buf; + __u32 len; + __u32 pad; +}; + +The userspace memory referenced by buf contains a struct kvm_s390_irq +for each interrupt to be injected into the guest. +If one of the interrupts could not be injected for some reason the +ioctl aborts. + +len must be a multiple of sizeof(struct kvm_s390_irq). It must be > 0 +and it must not exceed (max_vcpus + 32) * sizeof(struct kvm_s390_irq), +which is the maximum number of possibly pending cpu-local interrupts. 5. The kvm_run structure ------------------------ diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index bc0988093c5b..9de47265ef73 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c @@ -2123,3 +2123,143 @@ int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, struct kvm *kvm, { return -EINVAL; } + +int kvm_s390_set_irq_state(struct kvm_vcpu *vcpu, void __user *irqstate, int len) +{ + struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; + struct kvm_s390_irq *buf; + int r = 0; + int n; + + buf = vmalloc(len); + if (!buf) + return -ENOMEM; + + if (copy_from_user((void *) buf, irqstate, len)) { + r = -EFAULT; + goto out_free; + } + + /* + * Don't allow setting the interrupt state + * when there are already interrupts pending + */ + spin_lock(&li->lock); + if (li->pending_irqs) { + r = -EBUSY; + goto out_unlock; + } + + for (n = 0; n < len / sizeof(*buf); n++) { + r = do_inject_vcpu(vcpu, &buf[n]); + if (r) + break; + } + +out_unlock: + spin_unlock(&li->lock); +out_free: + vfree(buf); + + return r; +} + +static void store_local_irq(struct kvm_s390_local_interrupt *li, + struct kvm_s390_irq *irq, + unsigned long irq_type) +{ + switch (irq_type) { + case IRQ_PEND_MCHK_EX: + case IRQ_PEND_MCHK_REP: + irq->type = KVM_S390_MCHK; + irq->u.mchk = li->irq.mchk; + break; + case IRQ_PEND_PROG: + irq->type = KVM_S390_PROGRAM_INT; + irq->u.pgm = li->irq.pgm; + break; + case IRQ_PEND_PFAULT_INIT: + irq->type = KVM_S390_INT_PFAULT_INIT; + irq->u.ext = li->irq.ext; + break; + case IRQ_PEND_EXT_EXTERNAL: + irq->type = KVM_S390_INT_EXTERNAL_CALL; + irq->u.extcall = li->irq.extcall; + break; + case IRQ_PEND_EXT_CLOCK_COMP: + irq->type = KVM_S390_INT_CLOCK_COMP; + break; + case IRQ_PEND_EXT_CPU_TIMER: + irq->type = KVM_S390_INT_CPU_TIMER; + break; + case IRQ_PEND_SIGP_STOP: + irq->type = KVM_S390_SIGP_STOP; + irq->u.stop = li->irq.stop; + break; + case IRQ_PEND_RESTART: + irq->type = KVM_S390_RESTART; + break; + case IRQ_PEND_SET_PREFIX: + irq->type = KVM_S390_SIGP_SET_PREFIX; + irq->u.prefix = li->irq.prefix; + break; + } +} + +int kvm_s390_get_irq_state(struct kvm_vcpu *vcpu, __u8 __user *buf, int len) +{ + uint8_t sigp_ctrl = vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sigp_ctrl; + unsigned long sigp_emerg_pending[BITS_TO_LONGS(KVM_MAX_VCPUS)]; + struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; + unsigned long pending_irqs; + struct kvm_s390_irq irq; + unsigned long irq_type; + int cpuaddr; + int n = 0; + + spin_lock(&li->lock); + pending_irqs = li->pending_irqs; + memcpy(&sigp_emerg_pending, &li->sigp_emerg_pending, + sizeof(sigp_emerg_pending)); + spin_unlock(&li->lock); + + for_each_set_bit(irq_type, &pending_irqs, IRQ_PEND_COUNT) { + memset(&irq, 0, sizeof(irq)); + if (irq_type == IRQ_PEND_EXT_EMERGENCY) + continue; + if (n + sizeof(irq) > len) + return -ENOBUFS; + store_local_irq(&vcpu->arch.local_int, &irq, irq_type); + if (copy_to_user(&buf[n], &irq, sizeof(irq))) + return -EFAULT; + n += sizeof(irq); + } + + if (test_bit(IRQ_PEND_EXT_EMERGENCY, &pending_irqs)) { + for_each_set_bit(cpuaddr, sigp_emerg_pending, KVM_MAX_VCPUS) { + memset(&irq, 0, sizeof(irq)); + if (n + sizeof(irq) > len) + return -ENOBUFS; + irq.type = KVM_S390_INT_EMERGENCY; + irq.u.emerg.code = cpuaddr; + if (copy_to_user(&buf[n], &irq, sizeof(irq))) + return -EFAULT; + n += sizeof(irq); + } + } + + if ((sigp_ctrl & SIGP_CTRL_C) && + (atomic_read(&vcpu->arch.sie_block->cpuflags) & + CPUSTAT_ECALL_PEND)) { + if (n + sizeof(irq) > len) + return -ENOBUFS; + memset(&irq, 0, sizeof(irq)); + irq.type = KVM_S390_INT_EXTERNAL_CALL; + irq.u.extcall.code = sigp_ctrl & SIGP_CTRL_SCN_MASK; + if (copy_to_user(&buf[n], &irq, sizeof(irq))) + return -EFAULT; + n += sizeof(irq); + } + + return n; +} diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 8bc25d405edf..3040b14751b8 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -41,6 +41,9 @@ #include "trace-s390.h" #define MEM_OP_MAX_SIZE 65536 /* Maximum transfer size for KVM_S390_MEM_OP */ +#define LOCAL_IRQS 32 +#define VCPU_IRQS_MAX_BUF (sizeof(struct kvm_s390_irq) * \ + (KVM_MAX_VCPUS + LOCAL_IRQS)) #define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU @@ -181,6 +184,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_S390_USER_SIGP: case KVM_CAP_S390_USER_STSI: case KVM_CAP_S390_SKEYS: + case KVM_CAP_S390_IRQ_STATE: r = 1; break; case KVM_CAP_S390_MEM_OP: @@ -2500,6 +2504,38 @@ long kvm_arch_vcpu_ioctl(struct file *filp, r = -EFAULT; break; } + case KVM_S390_SET_IRQ_STATE: { + struct kvm_s390_irq_state irq_state; + + r = -EFAULT; + if (copy_from_user(&irq_state, argp, sizeof(irq_state))) + break; + if (irq_state.len > VCPU_IRQS_MAX_BUF || + irq_state.len == 0 || + irq_state.len % sizeof(struct kvm_s390_irq) > 0) { + r = -EINVAL; + break; + } + r = kvm_s390_set_irq_state(vcpu, + (void __user *) irq_state.buf, + irq_state.len); + break; + } + case KVM_S390_GET_IRQ_STATE: { + struct kvm_s390_irq_state irq_state; + + r = -EFAULT; + if (copy_from_user(&irq_state, argp, sizeof(irq_state))) + break; + if (irq_state.len == 0) { + r = -EINVAL; + break; + } + r = kvm_s390_get_irq_state(vcpu, + (__u8 __user *) irq_state.buf, + irq_state.len); + break; + } default: r = -ENOTTY; } diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h index 343644a59392..ca108b90ae56 100644 --- a/arch/s390/kvm/kvm-s390.h +++ b/arch/s390/kvm/kvm-s390.h @@ -272,6 +272,10 @@ int kvm_s390_ext_call_pending(struct kvm_vcpu *vcpu); extern struct kvm_device_ops kvm_flic_ops; int kvm_s390_is_stop_irq_pending(struct kvm_vcpu *vcpu); void kvm_s390_clear_stop_irq(struct kvm_vcpu *vcpu); +int kvm_s390_set_irq_state(struct kvm_vcpu *vcpu, + void __user *buf, int len); +int kvm_s390_get_irq_state(struct kvm_vcpu *vcpu, + __u8 __user *buf, int len); /* implemented in guestdbg.c */ void kvm_s390_backup_guest_per_regs(struct kvm_vcpu *vcpu); diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index c0632e87a00f..c045c725e521 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -558,6 +558,13 @@ struct kvm_s390_irq { } u; }; +struct kvm_s390_irq_state { + __u64 buf; + __u32 flags; + __u32 len; + __u32 reserved[4]; +}; + /* for KVM_SET_GUEST_DEBUG */ #define KVM_GUESTDBG_ENABLE 0x00000001 @@ -803,6 +810,7 @@ struct kvm_ppc_smmu_info { #define KVM_CAP_S390_USER_STSI 109 #define KVM_CAP_S390_SKEYS 110 #define KVM_CAP_S390_INJECT_IRQ 113 +#define KVM_CAP_S390_IRQ_STATE 114 #ifdef KVM_CAP_IRQ_ROUTING @@ -1185,6 +1193,9 @@ struct kvm_s390_ucas_mapping { #define KVM_S390_SET_SKEYS _IOW(KVMIO, 0xb3, struct kvm_s390_skeys) /* Available with KVM_CAP_S390_INJECT_IRQ */ #define KVM_S390_IRQ _IOW(KVMIO, 0xb4, struct kvm_s390_irq) +/* Available with KVM_CAP_S390_IRQ_STATE */ +#define KVM_S390_SET_IRQ_STATE _IOW(KVMIO, 0xb5, struct kvm_s390_irq_state) +#define KVM_S390_GET_IRQ_STATE _IOW(KVMIO, 0xb6, struct kvm_s390_irq_state) #define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0) #define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1) -- cgit v1.2.3-59-g8ed1b From a5581ef4c2eac6449188862e903eb46c7233582a Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Wed, 1 Apr 2015 07:50:29 +0200 Subject: can: introduce new raw socket option to join the given CAN filters The CAN_RAW socket can set multiple CAN identifier specific filters that lead to multiple filters in the af_can.c filter processing. These filters are indenpendent from each other which leads to logical OR'ed filters when applied. This socket option joines the given CAN filters in the way that only CAN frames are passed to user space that matched *all* given CAN filters. The semantic for the applied filters is therefore changed to a logical AND. This is useful especially when the filterset is a combination of filters where the CAN_INV_FILTER flag is set in order to notch single CAN IDs or CAN ID ranges from the incoming traffic. As the raw_rcv() function is executed from NET_RX softirq the introduced variables are implemented as per-CPU variables to avoid extensive locking at CAN frame reception time. Signed-off-by: Oliver Hartkopp Signed-off-by: Marc Kleine-Budde --- Documentation/networking/can.txt | 20 ++++++++++++++++++-- include/uapi/linux/can/raw.h | 1 + net/can/raw.c | 31 ++++++++++++++++++++++++++++++- 3 files changed, 49 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/can.txt b/Documentation/networking/can.txt index 0a2859a8ee7e..5abad1e921ca 100644 --- a/Documentation/networking/can.txt +++ b/Documentation/networking/can.txt @@ -22,7 +22,8 @@ This file contains 4.1.3 RAW socket option CAN_RAW_LOOPBACK 4.1.4 RAW socket option CAN_RAW_RECV_OWN_MSGS 4.1.5 RAW socket option CAN_RAW_FD_FRAMES - 4.1.6 RAW socket returned message flags + 4.1.6 RAW socket option CAN_RAW_JOIN_FILTERS + 4.1.7 RAW socket returned message flags 4.2 Broadcast Manager protocol sockets (SOCK_DGRAM) 4.2.1 Broadcast Manager operations 4.2.2 Broadcast Manager message flags @@ -601,7 +602,22 @@ solution for a couple of reasons: CAN FD frames by checking if the device maximum transfer unit is CANFD_MTU. The CAN device MTU can be retrieved e.g. with a SIOCGIFMTU ioctl() syscall. - 4.1.6 RAW socket returned message flags + 4.1.6 RAW socket option CAN_RAW_JOIN_FILTERS + + The CAN_RAW socket can set multiple CAN identifier specific filters that + lead to multiple filters in the af_can.c filter processing. These filters + are indenpendent from each other which leads to logical OR'ed filters when + applied (see 4.1.1). + + This socket option joines the given CAN filters in the way that only CAN + frames are passed to user space that matched *all* given CAN filters. The + semantic for the applied filters is therefore changed to a logical AND. + + This is useful especially when the filterset is a combination of filters + where the CAN_INV_FILTER flag is set in order to notch single CAN IDs or + CAN ID ranges from the incoming traffic. + + 4.1.7 RAW socket returned message flags When using recvmsg() call, the msg->msg_flags may contain following flags: diff --git a/include/uapi/linux/can/raw.h b/include/uapi/linux/can/raw.h index 78ec76fd89a6..8735f1080385 100644 --- a/include/uapi/linux/can/raw.h +++ b/include/uapi/linux/can/raw.h @@ -57,6 +57,7 @@ enum { CAN_RAW_LOOPBACK, /* local loopback (default:on) */ CAN_RAW_RECV_OWN_MSGS, /* receive my own msgs (default:off) */ CAN_RAW_FD_FRAMES, /* allow CAN FD frames (default:off) */ + CAN_RAW_JOIN_FILTERS, /* all filters must match to trigger */ }; #endif /* !_UAPI_CAN_RAW_H */ diff --git a/net/can/raw.c b/net/can/raw.c index 0c8d537b59b8..31b9748cbb4e 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -77,6 +77,7 @@ MODULE_ALIAS("can-proto-1"); struct uniqframe { ktime_t tstamp; const struct sk_buff *skb; + unsigned int join_rx_count; }; struct raw_sock { @@ -87,6 +88,7 @@ struct raw_sock { int loopback; int recv_own_msgs; int fd_frames; + int join_filters; int count; /* number of active filters */ struct can_filter dfilter; /* default/single filter */ struct can_filter *filter; /* pointer to filter(s) */ @@ -132,10 +134,21 @@ static void raw_rcv(struct sk_buff *oskb, void *data) /* eliminate multiple filter matches for the same skb */ if (this_cpu_ptr(ro->uniq)->skb == oskb && ktime_equal(this_cpu_ptr(ro->uniq)->tstamp, oskb->tstamp)) { - return; + if (ro->join_filters) { + this_cpu_inc(ro->uniq->join_rx_count); + /* drop frame until all enabled filters matched */ + if (this_cpu_ptr(ro->uniq)->join_rx_count < ro->count) + return; + } else { + return; + } } else { this_cpu_ptr(ro->uniq)->skb = oskb; this_cpu_ptr(ro->uniq)->tstamp = oskb->tstamp; + this_cpu_ptr(ro->uniq)->join_rx_count = 1; + /* drop first frame to check all enabled filters? */ + if (ro->join_filters && ro->count > 1) + return; } /* clone the given skb to be able to enqueue it into the rcv queue */ @@ -311,6 +324,7 @@ static int raw_init(struct sock *sk) ro->loopback = 1; ro->recv_own_msgs = 0; ro->fd_frames = 0; + ro->join_filters = 0; /* alloc_percpu provides zero'ed memory */ ro->uniq = alloc_percpu(struct uniqframe); @@ -604,6 +618,15 @@ static int raw_setsockopt(struct socket *sock, int level, int optname, break; + case CAN_RAW_JOIN_FILTERS: + if (optlen != sizeof(ro->join_filters)) + return -EINVAL; + + if (copy_from_user(&ro->join_filters, optval, optlen)) + return -EFAULT; + + break; + default: return -ENOPROTOOPT; } @@ -668,6 +691,12 @@ static int raw_getsockopt(struct socket *sock, int level, int optname, val = &ro->fd_frames; break; + case CAN_RAW_JOIN_FILTERS: + if (len > sizeof(int)) + len = sizeof(int); + val = &ro->join_filters; + break; + default: return -ENOPROTOOPT; } -- cgit v1.2.3-59-g8ed1b From fed6cefe3b6e862dcc74d07324478caa07e84eaf Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Thu, 5 Feb 2015 11:44:41 +0100 Subject: x86/efi: Add a "debug" option to the efi= cmdline ... and hide the memory regions dump behind it. Make it default-off. Signed-off-by: Borislav Petkov Link: http://lkml.kernel.org/r/20141209095843.GA3990@pd.tnic Acked-by: Laszlo Ersek Acked-by: Dave Young Signed-off-by: Matt Fleming --- Documentation/kernel-parameters.txt | 3 ++- arch/x86/platform/efi/efi.c | 5 ++++- include/linux/efi.h | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index bfcb1a62a7b4..01aa47d3b6ab 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1036,7 +1036,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted. Format: {"off" | "on" | "skip[mbr]"} efi= [EFI] - Format: { "old_map", "nochunk", "noruntime" } + Format: { "old_map", "nochunk", "noruntime", "debug" } old_map [X86-64]: switch to the old ioremap-based EFI runtime services mapping. 32-bit still uses this one by default. @@ -1044,6 +1044,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted. boot stub, as chunking can cause problems with some firmware implementations. noruntime : disable EFI runtime services support + debug: enable misc debug output efi_no_storage_paranoia [EFI; X86] Using this parameter you can use more than 50% of diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index dbc8627a5cdf..e859d56ce9f8 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -491,7 +491,8 @@ void __init efi_init(void) if (efi_memmap_init()) return; - print_efi_memmap(); + if (efi_enabled(EFI_DBG)) + print_efi_memmap(); } void __init efi_late_init(void) @@ -939,6 +940,8 @@ static int __init arch_parse_efi_cmdline(char *str) { if (parse_option_str(str, "old_map")) set_bit(EFI_OLD_MEMMAP, &efi.flags); + if (parse_option_str(str, "debug")) + set_bit(EFI_DBG, &efi.flags); return 0; } diff --git a/include/linux/efi.h b/include/linux/efi.h index cf7e431cbc73..af5be0368dec 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -942,6 +942,7 @@ extern int __init efi_setup_pcdp_console(char *); #define EFI_64BIT 5 /* Is the firmware 64-bit? */ #define EFI_PARAVIRT 6 /* Access is via a paravirt interface */ #define EFI_ARCH_1 7 /* First arch-specific bit */ +#define EFI_DBG 8 /* Print additional debug info at runtime */ #ifdef CONFIG_EFI /* -- cgit v1.2.3-59-g8ed1b From ec776ef6bbe1734c29cd6bd05219cd93b2731bd4 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 1 Apr 2015 09:12:18 +0200 Subject: x86/mm: Add support for the non-standard protected e820 type Various recent BIOSes support NVDIMMs or ADR using a non-standard e820 memory type, and Intel supplied reference Linux code using this type to various vendors. Wire this e820 table type up to export platform devices for the pmem driver so that we can use it in Linux. Based on earlier work from: Dave Jiang Dan Williams Includes fixes for NUMA regions from Boaz Harrosh. Tested-by: Ross Zwisler Signed-off-by: Christoph Hellwig Acked-by: Dan Williams Cc: Andrew Morton Cc: Andy Lutomirski Cc: Boaz Harrosh Cc: Borislav Petkov Cc: H. Peter Anvin Cc: Jens Axboe Cc: Jens Axboe Cc: Keith Busch Cc: Linus Torvalds Cc: Matthew Wilcox Cc: Thomas Gleixner Cc: linux-nvdimm@ml01.01.org Link: http://lkml.kernel.org/r/1427872339-6688-2-git-send-email-hch@lst.de [ Minor cleanups. ] Signed-off-by: Ingo Molnar --- Documentation/kernel-parameters.txt | 6 +++++ arch/x86/Kconfig | 10 +++++++ arch/x86/include/uapi/asm/e820.h | 10 +++++++ arch/x86/kernel/Makefile | 1 + arch/x86/kernel/e820.c | 26 +++++++++++++----- arch/x86/kernel/pmem.c | 53 +++++++++++++++++++++++++++++++++++++ 6 files changed, 100 insertions(+), 6 deletions(-) create mode 100644 arch/x86/kernel/pmem.c (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index bfcb1a62a7b4..c87122dd790f 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1965,6 +1965,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted. or memmap=0x10000$0x18690000 + memmap=nn[KMG]!ss[KMG] + [KNL,X86] Mark specific memory as protected. + Region of memory to be used, from ss to ss+nn. + The memory region may be marked as e820 type 12 (0xc) + and is NVDIMM or ADR memory. + memory_corruption_check=0/1 [X86] Some BIOSes seem to corrupt the first 64k of memory when doing things like suspend/resume. diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index b7d31ca55187..9e3bcd6f4a48 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1430,6 +1430,16 @@ config ILLEGAL_POINTER_VALUE source "mm/Kconfig" +config X86_PMEM_LEGACY + bool "Support non-standard NVDIMMs and ADR protected memory" + help + Treat memory marked using the non-standard e820 type of 12 as used + by the Intel Sandy Bridge-EP reference BIOS as protected memory. + The kernel will offer these regions to the 'pmem' driver so + they can be used for persistent storage. + + Say Y if unsure. + config HIGHPTE bool "Allocate 3rd-level pagetables from highmem" depends on HIGHMEM diff --git a/arch/x86/include/uapi/asm/e820.h b/arch/x86/include/uapi/asm/e820.h index d993e33f5236..960a8a9dc4ab 100644 --- a/arch/x86/include/uapi/asm/e820.h +++ b/arch/x86/include/uapi/asm/e820.h @@ -33,6 +33,16 @@ #define E820_NVS 4 #define E820_UNUSABLE 5 +/* + * This is a non-standardized way to represent ADR or NVDIMM regions that + * persist over a reboot. The kernel will ignore their special capabilities + * unless the CONFIG_X86_PMEM_LEGACY=y option is set. + * + * ( Note that older platforms also used 6 for the same type of memory, + * but newer versions switched to 12 as 6 was assigned differently. Some + * time they will learn... ) + */ +#define E820_PRAM 12 /* * reserved RAM used by kernel itself diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index cdb1b70ddad0..971f18cd9ca0 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -94,6 +94,7 @@ obj-$(CONFIG_KVM_GUEST) += kvm.o kvmclock.o obj-$(CONFIG_PARAVIRT) += paravirt.o paravirt_patch_$(BITS).o obj-$(CONFIG_PARAVIRT_SPINLOCKS)+= paravirt-spinlocks.o obj-$(CONFIG_PARAVIRT_CLOCK) += pvclock.o +obj-$(CONFIG_X86_PMEM_LEGACY) += pmem.o obj-$(CONFIG_PCSPKR_PLATFORM) += pcspeaker.o diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c index 46201deee923..11cc7d54ec3f 100644 --- a/arch/x86/kernel/e820.c +++ b/arch/x86/kernel/e820.c @@ -149,6 +149,9 @@ static void __init e820_print_type(u32 type) case E820_UNUSABLE: printk(KERN_CONT "unusable"); break; + case E820_PRAM: + printk(KERN_CONT "persistent (type %u)", type); + break; default: printk(KERN_CONT "type %u", type); break; @@ -343,7 +346,7 @@ int __init sanitize_e820_map(struct e820entry *biosmap, int max_nr_map, * continue building up new bios map based on this * information */ - if (current_type != last_type) { + if (current_type != last_type || current_type == E820_PRAM) { if (last_type != 0) { new_bios[new_bios_entry].size = change_point[chgidx]->addr - last_addr; @@ -688,6 +691,7 @@ void __init e820_mark_nosave_regions(unsigned long limit_pfn) register_nosave_region(pfn, PFN_UP(ei->addr)); pfn = PFN_DOWN(ei->addr + ei->size); + if (ei->type != E820_RAM && ei->type != E820_RESERVED_KERN) register_nosave_region(PFN_UP(ei->addr), pfn); @@ -748,7 +752,7 @@ u64 __init early_reserve_e820(u64 size, u64 align) /* * Find the highest page frame number we have available */ -static unsigned long __init e820_end_pfn(unsigned long limit_pfn, unsigned type) +static unsigned long __init e820_end_pfn(unsigned long limit_pfn) { int i; unsigned long last_pfn = 0; @@ -759,7 +763,11 @@ static unsigned long __init e820_end_pfn(unsigned long limit_pfn, unsigned type) unsigned long start_pfn; unsigned long end_pfn; - if (ei->type != type) + /* + * Persistent memory is accounted as ram for purposes of + * establishing max_pfn and mem_map. + */ + if (ei->type != E820_RAM && ei->type != E820_PRAM) continue; start_pfn = ei->addr >> PAGE_SHIFT; @@ -784,12 +792,12 @@ static unsigned long __init e820_end_pfn(unsigned long limit_pfn, unsigned type) } unsigned long __init e820_end_of_ram_pfn(void) { - return e820_end_pfn(MAX_ARCH_PFN, E820_RAM); + return e820_end_pfn(MAX_ARCH_PFN); } unsigned long __init e820_end_of_low_ram_pfn(void) { - return e820_end_pfn(1UL<<(32 - PAGE_SHIFT), E820_RAM); + return e820_end_pfn(1UL << (32-PAGE_SHIFT)); } static void early_panic(char *msg) @@ -866,6 +874,9 @@ static int __init parse_memmap_one(char *p) } else if (*p == '$') { start_at = memparse(p+1, &p); e820_add_region(start_at, mem_size, E820_RESERVED); + } else if (*p == '!') { + start_at = memparse(p+1, &p); + e820_add_region(start_at, mem_size, E820_PRAM); } else e820_remove_range(mem_size, ULLONG_MAX - mem_size, E820_RAM, 1); @@ -907,6 +918,7 @@ static inline const char *e820_type_to_string(int e820_type) case E820_ACPI: return "ACPI Tables"; case E820_NVS: return "ACPI Non-volatile Storage"; case E820_UNUSABLE: return "Unusable memory"; + case E820_PRAM: return "Persistent RAM"; default: return "reserved"; } } @@ -940,7 +952,9 @@ void __init e820_reserve_resources(void) * pci device BAR resource and insert them later in * pcibios_resource_survey() */ - if (e820.map[i].type != E820_RESERVED || res->start < (1ULL<<20)) { + if (((e820.map[i].type != E820_RESERVED) && + (e820.map[i].type != E820_PRAM)) || + res->start < (1ULL<<20)) { res->flags |= IORESOURCE_BUSY; insert_resource(&iomem_resource, res); } diff --git a/arch/x86/kernel/pmem.c b/arch/x86/kernel/pmem.c new file mode 100644 index 000000000000..3420c874ddc5 --- /dev/null +++ b/arch/x86/kernel/pmem.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2015, Christoph Hellwig. + */ +#include +#include +#include +#include +#include +#include + +static __init void register_pmem_device(struct resource *res) +{ + struct platform_device *pdev; + int error; + + pdev = platform_device_alloc("pmem", PLATFORM_DEVID_AUTO); + if (!pdev) + return; + + error = platform_device_add_resources(pdev, res, 1); + if (error) + goto out_put_pdev; + + error = platform_device_add(pdev); + if (error) + goto out_put_pdev; + return; + +out_put_pdev: + dev_warn(&pdev->dev, "failed to add 'pmem' (persistent memory) device!\n"); + platform_device_put(pdev); +} + +static __init int register_pmem_devices(void) +{ + int i; + + for (i = 0; i < e820.nr_map; i++) { + struct e820entry *ei = &e820.map[i]; + + if (ei->type == E820_PRAM) { + struct resource res = { + .flags = IORESOURCE_MEM, + .start = ei->addr, + .end = ei->addr + ei->size - 1, + }; + register_pmem_device(&res); + } + } + + return 0; +} +device_initcall(register_pmem_devices); -- cgit v1.2.3-59-g8ed1b From 7e229fa07da10ee3dc3f88989b515293758c42eb Mon Sep 17 00:00:00 2001 From: Kevin Cernekee Date: Thu, 25 Dec 2014 09:49:01 -0800 Subject: IRQCHIP: Update docs regarding irq_domain_add_tree() Several drivers now use this API, including the ARM GIC driver, so remove the outdated comment. Signed-off-by: Kevin Cernekee Cc: f.fainelli@gmail.com Cc: jaedon.shin@gmail.com Cc: abrestic@chromium.org Cc: tglx@linutronix.de Cc: jason@lakedaemon.net Cc: jogo@openwrt.org Cc: computersforpeace@gmail.com Cc: linux-mips@linux-mips.org Cc: devicetree@vger.kernel.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/8839/ Signed-off-by: Ralf Baechle --- Documentation/IRQ-domain.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/IRQ-domain.txt b/Documentation/IRQ-domain.txt index 39cfa72732ff..3a8e15cba816 100644 --- a/Documentation/IRQ-domain.txt +++ b/Documentation/IRQ-domain.txt @@ -95,8 +95,7 @@ since it doesn't need to allocate a table as large as the largest hwirq number. The disadvantage is that hwirq to IRQ number lookup is dependent on how many entries are in the table. -Very few drivers should need this mapping. At the moment, powerpc -iseries is the only user. +Very few drivers should need this mapping. ==== No Map ===- irq_domain_add_nomap() -- cgit v1.2.3-59-g8ed1b From ca40f1b23df70c6f31b14a5743a6f3b60e862ce1 Mon Sep 17 00:00:00 2001 From: Kevin Cernekee Date: Thu, 25 Dec 2014 09:49:04 -0800 Subject: IRQCHIP: bcm7120-l2: Split STB-specific logic into its own function The BCM7xxx instances of this block (listed in the register manual as simply "IRQ0") all have the following items in common: - brcm,int-map-mask: for routing different bits in the L2 to different parent IRQs - brcm,int-fwd-mask: for hardwiring certain IRQs to bypass the L2 and use dedicated L1 lines - one enable/status pair (32 bits only) Much of the driver code can be shared with BCM3380-style controllers, but in order to do this cleanly, let's split out the BCM7xxx-specific logic first. Signed-off-by: Kevin Cernekee Cc: f.fainelli@gmail.com Cc: jaedon.shin@gmail.com Cc: abrestic@chromium.org Cc: tglx@linutronix.de Cc: jason@lakedaemon.net Cc: jogo@openwrt.org Cc: arnd@arndb.de Cc: computersforpeace@gmail.com Cc: linux-mips@linux-mips.org Cc: devicetree@vger.kernel.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/8842/ Signed-off-by: Ralf Baechle --- .../interrupt-controller/brcm,bcm7120-l2-intc.txt | 12 +- drivers/irqchip/irq-bcm7120-l2.c | 123 ++++++++++++--------- 2 files changed, 71 insertions(+), 64 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm7120-l2-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm7120-l2-intc.txt index bae1f2187226..44a9bb15dd56 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm7120-l2-intc.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm7120-l2-intc.txt @@ -13,8 +13,7 @@ Such an interrupt controller has the following hardware design: or if they will output an interrupt signal at this 2nd level interrupt controller, in particular for UARTs -- typically has one 32-bit enable word and one 32-bit status word, but on - some hardware may have more than one enable/status pair +- has one 32-bit enable word and one 32-bit status word - no atomic set/clear operations @@ -53,9 +52,7 @@ The typical hardware layout for this controller is represented below: Required properties: - compatible: should be "brcm,bcm7120-l2-intc" -- reg: specifies the base physical address and size of the registers; - multiple pairs may be specified, with the first pair handling IRQ offsets - 0..31 and the second pair handling 32..63 +- reg: specifies the base physical address and size of the registers - interrupt-controller: identifies the node as an interrupt controller - #interrupt-cells: specifies the number of cells needed to encode an interrupt source, should be 1. @@ -66,10 +63,7 @@ Required properties: - brcm,int-map-mask: 32-bits bit mask describing how many and which interrupts are wired to this 2nd level interrupt controller, and how they match their respective interrupt parents. Should match exactly the number of interrupts - specified in the 'interrupts' property, multiplied by the number of - enable/status register pairs implemented by this controller. For - multiple parent IRQs with multiple enable/status words, this looks like: - + specified in the 'interrupts' property. Optional properties: diff --git a/drivers/irqchip/irq-bcm7120-l2.c b/drivers/irqchip/irq-bcm7120-l2.c index e8441ee7454c..6a6285897df1 100644 --- a/drivers/irqchip/irq-bcm7120-l2.c +++ b/drivers/irqchip/irq-bcm7120-l2.c @@ -34,7 +34,7 @@ #define IRQSTAT 0x04 #define MAX_WORDS 4 -#define MAX_MAPPINGS MAX_WORDS +#define MAX_MAPPINGS (MAX_WORDS * 2) #define IRQS_PER_WORD 32 struct bcm7120_l2_intc_data { @@ -47,6 +47,8 @@ struct bcm7120_l2_intc_data { bool can_wake; u32 irq_fwd_mask[MAX_WORDS]; u32 irq_map_mask[MAX_WORDS]; + int num_parent_irqs; + const __be32 *map_mask_prop; }; static void bcm7120_l2_intc_irq_handle(unsigned int irq, struct irq_desc *desc) @@ -104,7 +106,7 @@ static void bcm7120_l2_intc_resume(struct irq_data *d) static int bcm7120_l2_intc_init_one(struct device_node *dn, struct bcm7120_l2_intc_data *data, - int irq, const __be32 *map_mask) + int irq) { int parent_irq; unsigned int idx; @@ -120,7 +122,8 @@ static int bcm7120_l2_intc_init_one(struct device_node *dn, */ for (idx = 0; idx < data->n_words; idx++) data->irq_map_mask[idx] |= - be32_to_cpup(map_mask + irq * data->n_words + idx); + be32_to_cpup(data->map_mask_prop + + irq * data->n_words + idx); irq_set_handler_data(parent_irq, data); irq_set_chained_handler(parent_irq, bcm7120_l2_intc_irq_handle); @@ -128,74 +131,76 @@ static int bcm7120_l2_intc_init_one(struct device_node *dn, return 0; } -int __init bcm7120_l2_intc_of_init(struct device_node *dn, - struct device_node *parent) +static int __init bcm7120_l2_intc_iomap_7120(struct device_node *dn, + struct bcm7120_l2_intc_data *data) +{ + int ret; + + data->map_base[0] = of_iomap(dn, 0); + if (!data->map_base[0]) { + pr_err("unable to map registers\n"); + return -ENOMEM; + } + + data->pair_base[0] = data->map_base[0]; + data->en_offset[0] = IRQEN; + data->stat_offset[0] = IRQSTAT; + data->n_words = 1; + + ret = of_property_read_u32_array(dn, "brcm,int-fwd-mask", + data->irq_fwd_mask, data->n_words); + if (ret != 0 && ret != -EINVAL) { + /* property exists but has the wrong number of words */ + pr_err("invalid brcm,int-fwd-mask property\n"); + return -EINVAL; + } + + data->map_mask_prop = of_get_property(dn, "brcm,int-map-mask", &ret); + if (!data->map_mask_prop || + (ret != (sizeof(__be32) * data->num_parent_irqs * data->n_words))) { + pr_err("invalid brcm,int-map-mask property\n"); + return -EINVAL; + } + + return 0; +} + +int __init bcm7120_l2_intc_probe(struct device_node *dn, + struct device_node *parent, + int (*iomap_regs_fn)(struct device_node *, + struct bcm7120_l2_intc_data *), + const char *intc_name) { unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN; struct bcm7120_l2_intc_data *data; struct irq_chip_generic *gc; struct irq_chip_type *ct; - const __be32 *map_mask; - int num_parent_irqs; - int ret = 0, len; + int ret = 0; unsigned int idx, irq, flags; data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; - for (idx = 0; idx < MAX_WORDS; idx++) { - data->map_base[idx] = of_iomap(dn, idx); - if (!data->map_base[idx]) - break; - - data->pair_base[idx] = data->map_base[idx]; - data->en_offset[idx] = IRQEN; - data->stat_offset[idx] = IRQSTAT; - - data->n_words = idx + 1; - } - if (!data->n_words) { - pr_err("failed to remap intc L2 registers\n"); - ret = -ENOMEM; - goto out_unmap; - } - - /* Enable all interrupts specified in the interrupt forward mask; - * disable all others. If the property doesn't exist (-EINVAL), - * assume all zeroes. - */ - ret = of_property_read_u32_array(dn, "brcm,int-fwd-mask", - data->irq_fwd_mask, data->n_words); - if (ret == 0 || ret == -EINVAL) { - for (idx = 0; idx < data->n_words; idx++) - __raw_writel(data->irq_fwd_mask[idx], - data->pair_base[idx] + - data->en_offset[idx]); - } else { - /* property exists but has the wrong number of words */ - pr_err("invalid int-fwd-mask property\n"); - ret = -EINVAL; - goto out_unmap; - } - - num_parent_irqs = of_irq_count(dn); - if (num_parent_irqs <= 0) { + data->num_parent_irqs = of_irq_count(dn); + if (data->num_parent_irqs <= 0) { pr_err("invalid number of parent interrupts\n"); ret = -ENOMEM; goto out_unmap; } - map_mask = of_get_property(dn, "brcm,int-map-mask", &len); - if (!map_mask || - (len != (sizeof(*map_mask) * num_parent_irqs * data->n_words))) { - pr_err("invalid brcm,int-map-mask property\n"); - ret = -EINVAL; + ret = iomap_regs_fn(dn, data); + if (ret < 0) goto out_unmap; + + for (idx = 0; idx < data->n_words; idx++) { + __raw_writel(data->irq_fwd_mask[idx], + data->pair_base[idx] + + data->en_offset[idx]); } - for (irq = 0; irq < num_parent_irqs; irq++) { - ret = bcm7120_l2_intc_init_one(dn, data, irq, map_mask); + for (irq = 0; irq < data->num_parent_irqs; irq++) { + ret = bcm7120_l2_intc_init_one(dn, data, irq); if (ret) goto out_unmap; } @@ -251,8 +256,8 @@ int __init bcm7120_l2_intc_of_init(struct device_node *dn, } } - pr_info("registered BCM7120 L2 intc (mem: 0x%p, parent IRQ(s): %d)\n", - data->map_base[0], num_parent_irqs); + pr_info("registered %s intc (mem: 0x%p, parent IRQ(s): %d)\n", + intc_name, data->map_base[0], data->num_parent_irqs); return 0; @@ -266,5 +271,13 @@ out_unmap: kfree(data); return ret; } + +int __init bcm7120_l2_intc_probe_7120(struct device_node *dn, + struct device_node *parent) +{ + return bcm7120_l2_intc_probe(dn, parent, bcm7120_l2_intc_iomap_7120, + "BCM7120 L2"); +} + IRQCHIP_DECLARE(bcm7120_l2_intc, "brcm,bcm7120-l2-intc", - bcm7120_l2_intc_of_init); + bcm7120_l2_intc_probe_7120); -- cgit v1.2.3-59-g8ed1b From 7b7230e70e9eda75356cf15c450b65b77924486f Mon Sep 17 00:00:00 2001 From: Kevin Cernekee Date: Thu, 25 Dec 2014 09:49:05 -0800 Subject: IRQCHIP: bcm7120-l2: Add support for BCM3380-style controllers These controllers support multiple enable/status pairs (64+ IRQs), can put the enable/status words at different offsets, and do not support multiple parent IRQs. Signed-off-by: Kevin Cernekee Cc: f.fainelli@gmail.com Cc: jaedon.shin@gmail.com Cc: abrestic@chromium.org Cc: tglx@linutronix.de Cc: jason@lakedaemon.net Cc: jogo@openwrt.org Cc: arnd@arndb.de Cc: computersforpeace@gmail.com Cc: linux-mips@linux-mips.org Cc: devicetree@vger.kernel.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/8843/ Signed-off-by: Ralf Baechle --- .../interrupt-controller/brcm,bcm3380-l2-intc.txt | 41 ++++++++++++++++ drivers/irqchip/irq-bcm7120-l2.c | 55 ++++++++++++++++++++-- 2 files changed, 92 insertions(+), 4 deletions(-) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/brcm,bcm3380-l2-intc.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm3380-l2-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm3380-l2-intc.txt new file mode 100644 index 000000000000..8f48aad50868 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm3380-l2-intc.txt @@ -0,0 +1,41 @@ +Broadcom BCM3380-style Level 1 / Level 2 interrupt controller + +This interrupt controller shows up in various forms on many BCM338x/BCM63xx +chipsets. It has the following properties: + +- outputs a single interrupt signal to its interrupt controller parent + +- contains one or more enable/status word pairs, which often appear at + different offsets in different blocks + +- no atomic set/clear operations + +Required properties: + +- compatible: should be "brcm,bcm3380-l2-intc" +- reg: specifies one or more enable/status pairs, in the following format: + ... +- interrupt-controller: identifies the node as an interrupt controller +- #interrupt-cells: specifies the number of cells needed to encode an interrupt + source, should be 1. +- interrupt-parent: specifies the phandle to the parent interrupt controller + this one is cascaded from +- interrupts: specifies the interrupt line in the interrupt-parent controller + node, valid values depend on the type of parent interrupt controller + +Optional properties: + +- brcm,irq-can-wake: if present, this means the L2 controller can be used as a + wakeup source for system suspend/resume. + +Example: + +irq0_intc: interrupt-controller@10000020 { + compatible = "brcm,bcm3380-l2-intc"; + reg = <0x10000024 0x4 0x1000002c 0x4>, + <0x10000020 0x4 0x10000028 0x4>; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&cpu_intc>; + interrupts = <2>; +}; diff --git a/drivers/irqchip/irq-bcm7120-l2.c b/drivers/irqchip/irq-bcm7120-l2.c index 6a6285897df1..3ba5cc780fcb 100644 --- a/drivers/irqchip/irq-bcm7120-l2.c +++ b/drivers/irqchip/irq-bcm7120-l2.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -120,10 +121,15 @@ static int bcm7120_l2_intc_init_one(struct device_node *dn, /* For multiple parent IRQs with multiple words, this looks like: * */ - for (idx = 0; idx < data->n_words; idx++) - data->irq_map_mask[idx] |= - be32_to_cpup(data->map_mask_prop + - irq * data->n_words + idx); + for (idx = 0; idx < data->n_words; idx++) { + if (data->map_mask_prop) { + data->irq_map_mask[idx] |= + be32_to_cpup(data->map_mask_prop + + irq * data->n_words + idx); + } else { + data->irq_map_mask[idx] = 0xffffffff; + } + } irq_set_handler_data(parent_irq, data); irq_set_chained_handler(parent_irq, bcm7120_l2_intc_irq_handle); @@ -165,6 +171,37 @@ static int __init bcm7120_l2_intc_iomap_7120(struct device_node *dn, return 0; } +static int __init bcm7120_l2_intc_iomap_3380(struct device_node *dn, + struct bcm7120_l2_intc_data *data) +{ + unsigned int gc_idx; + + for (gc_idx = 0; gc_idx < MAX_WORDS; gc_idx++) { + unsigned int map_idx = gc_idx * 2; + void __iomem *en = of_iomap(dn, map_idx + 0); + void __iomem *stat = of_iomap(dn, map_idx + 1); + void __iomem *base = min(en, stat); + + data->map_base[map_idx + 0] = en; + data->map_base[map_idx + 1] = stat; + + if (!base) + break; + + data->pair_base[gc_idx] = base; + data->en_offset[gc_idx] = en - base; + data->stat_offset[gc_idx] = stat - base; + } + + if (!gc_idx) { + pr_err("unable to map registers\n"); + return -EINVAL; + } + + data->n_words = gc_idx; + return 0; +} + int __init bcm7120_l2_intc_probe(struct device_node *dn, struct device_node *parent, int (*iomap_regs_fn)(struct device_node *, @@ -279,5 +316,15 @@ int __init bcm7120_l2_intc_probe_7120(struct device_node *dn, "BCM7120 L2"); } +int __init bcm7120_l2_intc_probe_3380(struct device_node *dn, + struct device_node *parent) +{ + return bcm7120_l2_intc_probe(dn, parent, bcm7120_l2_intc_iomap_3380, + "BCM3380 L2"); +} + IRQCHIP_DECLARE(bcm7120_l2_intc, "brcm,bcm7120-l2-intc", bcm7120_l2_intc_probe_7120); + +IRQCHIP_DECLARE(bcm3380_l2_intc, "brcm,bcm3380-l2-intc", + bcm7120_l2_intc_probe_3380); -- cgit v1.2.3-59-g8ed1b From 5f7f0317ed28b86bdae9baf65bb72d405b6f79ee Mon Sep 17 00:00:00 2001 From: Kevin Cernekee Date: Thu, 25 Dec 2014 09:49:06 -0800 Subject: IRQCHIP: Add new driver for BCM7038-style level 1 interrupt controllers This is the main peripheral IRQ controller on the BCM7xxx MIPS chips; it has the following characteristics: - 64 to 160+ level IRQs - Atomic set/clear registers - Reasonably predictable register layout (N status words, then N mask status words, then N mask set words, then N mask clear words) - SMP affinity supported on most systems - Typically connected to MIPS IRQ 2,3,2,3 on CPUs 0,1,2,3 This driver registers one IRQ domain and one IRQ chip to cover all instances of the block. Up to 4 instances of the block may appear, as it supports 4-way IRQ affinity on BCM7435. The same block exists on the ARM BCM7xxx chips, but typically the ARM GIC is used instead. So this driver is primarily intended for MIPS STB chips. Signed-off-by: Kevin Cernekee Cc: f.fainelli@gmail.com Cc: jaedon.shin@gmail.com Cc: abrestic@chromium.org Cc: tglx@linutronix.de Cc: jason@lakedaemon.net Cc: jogo@openwrt.org Cc: arnd@arndb.de Cc: computersforpeace@gmail.com Cc: linux-mips@linux-mips.org Cc: devicetree@vger.kernel.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/8844/ Signed-off-by: Ralf Baechle --- .../interrupt-controller/brcm,bcm7038-l1-intc.txt | 52 ++++ drivers/irqchip/Kconfig | 5 + drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-bcm7038-l1.c | 335 +++++++++++++++++++++ 4 files changed, 393 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/brcm,bcm7038-l1-intc.txt create mode 100644 drivers/irqchip/irq-bcm7038-l1.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm7038-l1-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm7038-l1-intc.txt new file mode 100644 index 000000000000..cc217b22dccd --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm7038-l1-intc.txt @@ -0,0 +1,52 @@ +Broadcom BCM7038-style Level 1 interrupt controller + +This block is a first level interrupt controller that is typically connected +directly to one of the HW INT lines on each CPU. Every BCM7xxx set-top chip +since BCM7038 has contained this hardware. + +Key elements of the hardware design include: + +- 64, 96, 128, or 160 incoming level IRQ lines + +- Most onchip peripherals are wired directly to an L1 input + +- A separate instance of the register set for each CPU, allowing individual + peripheral IRQs to be routed to any CPU + +- Atomic mask/unmask operations + +- No polarity/level/edge settings + +- No FIFO or priority encoder logic; software is expected to read all + 2-5 status words to determine which IRQs are pending + +Required properties: + +- compatible: should be "brcm,bcm7038-l1-intc" +- reg: specifies the base physical address and size of the registers; + the number of supported IRQs is inferred from the size argument +- interrupt-controller: identifies the node as an interrupt controller +- #interrupt-cells: specifies the number of cells needed to encode an interrupt + source, should be 1. +- interrupt-parent: specifies the phandle to the parent interrupt controller(s) + this one is cascaded from +- interrupts: specifies the interrupt line(s) in the interrupt-parent controller + node; valid values depend on the type of parent interrupt controller + +If multiple reg ranges and interrupt-parent entries are present on an SMP +system, the driver will allow IRQ SMP affinity to be set up through the +/proc/irq/ interface. In the simplest possible configuration, only one +reg range and one interrupt-parent is needed. + +Example: + +periph_intc: periph_intc@1041a400 { + compatible = "brcm,bcm7038-l1-intc"; + reg = <0x1041a400 0x30 0x1041a600 0x30>; + + interrupt-controller; + #interrupt-cells = <1>; + + interrupt-parent = <&cpu_intc>; + interrupts = <2>, <3>; +}; diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index cc79d2a5a8c2..241a5b2dd6a1 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -60,6 +60,11 @@ config ATMEL_AIC5_IRQ select MULTI_IRQ_HANDLER select SPARSE_IRQ +config BCM7038_L1_IRQ + bool + select GENERIC_IRQ_CHIP + select IRQ_DOMAIN + config BCM7120_L2_IRQ bool select GENERIC_IRQ_CHIP diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 42965d2476bb..89e45613de76 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_TB10X_IRQC) += irq-tb10x.o obj-$(CONFIG_XTENSA) += irq-xtensa-pic.o obj-$(CONFIG_XTENSA_MX) += irq-xtensa-mx.o obj-$(CONFIG_IRQ_CROSSBAR) += irq-crossbar.o +obj-$(CONFIG_BCM7038_L1_IRQ) += irq-bcm7038-l1.o obj-$(CONFIG_BCM7120_L2_IRQ) += irq-bcm7120-l2.o obj-$(CONFIG_BRCMSTB_L2_IRQ) += irq-brcmstb-l2.o obj-$(CONFIG_KEYSTONE_IRQ) += irq-keystone.o diff --git a/drivers/irqchip/irq-bcm7038-l1.c b/drivers/irqchip/irq-bcm7038-l1.c new file mode 100644 index 000000000000..d3b8c8be15f6 --- /dev/null +++ b/drivers/irqchip/irq-bcm7038-l1.c @@ -0,0 +1,335 @@ +/* + * Broadcom BCM7038 style Level 1 interrupt controller driver + * + * Copyright (C) 2014 Broadcom Corporation + * Author: Kevin Cernekee + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "irqchip.h" + +#define IRQS_PER_WORD 32 +#define REG_BYTES_PER_IRQ_WORD (sizeof(u32) * 4) +#define MAX_WORDS 8 + +struct bcm7038_l1_cpu; + +struct bcm7038_l1_chip { + raw_spinlock_t lock; + unsigned int n_words; + struct irq_domain *domain; + struct bcm7038_l1_cpu *cpus[NR_CPUS]; + u8 affinity[MAX_WORDS * IRQS_PER_WORD]; +}; + +struct bcm7038_l1_cpu { + void __iomem *map_base; + u32 mask_cache[0]; +}; + +/* + * STATUS/MASK_STATUS/MASK_SET/MASK_CLEAR are packed one right after another: + * + * 7038: + * 0x1000_1400: W0_STATUS + * 0x1000_1404: W1_STATUS + * 0x1000_1408: W0_MASK_STATUS + * 0x1000_140c: W1_MASK_STATUS + * 0x1000_1410: W0_MASK_SET + * 0x1000_1414: W1_MASK_SET + * 0x1000_1418: W0_MASK_CLEAR + * 0x1000_141c: W1_MASK_CLEAR + * + * 7445: + * 0xf03e_1500: W0_STATUS + * 0xf03e_1504: W1_STATUS + * 0xf03e_1508: W2_STATUS + * 0xf03e_150c: W3_STATUS + * 0xf03e_1510: W4_STATUS + * 0xf03e_1514: W0_MASK_STATUS + * 0xf03e_1518: W1_MASK_STATUS + * [...] + */ + +static inline unsigned int reg_status(struct bcm7038_l1_chip *intc, + unsigned int word) +{ + return (0 * intc->n_words + word) * sizeof(u32); +} + +static inline unsigned int reg_mask_status(struct bcm7038_l1_chip *intc, + unsigned int word) +{ + return (1 * intc->n_words + word) * sizeof(u32); +} + +static inline unsigned int reg_mask_set(struct bcm7038_l1_chip *intc, + unsigned int word) +{ + return (2 * intc->n_words + word) * sizeof(u32); +} + +static inline unsigned int reg_mask_clr(struct bcm7038_l1_chip *intc, + unsigned int word) +{ + return (3 * intc->n_words + word) * sizeof(u32); +} + +static inline u32 l1_readl(void __iomem *reg) +{ + if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) + return ioread32be(reg); + else + return readl(reg); +} + +static inline void l1_writel(u32 val, void __iomem *reg) +{ + if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) + iowrite32be(val, reg); + else + writel(val, reg); +} + +static void bcm7038_l1_irq_handle(unsigned int irq, struct irq_desc *desc) +{ + struct bcm7038_l1_chip *intc = irq_desc_get_handler_data(desc); + struct bcm7038_l1_cpu *cpu; + struct irq_chip *chip = irq_desc_get_chip(desc); + unsigned int idx; + +#ifdef CONFIG_SMP + cpu = intc->cpus[cpu_logical_map(smp_processor_id())]; +#else + cpu = intc->cpus[0]; +#endif + + chained_irq_enter(chip, desc); + + for (idx = 0; idx < intc->n_words; idx++) { + int base = idx * IRQS_PER_WORD; + unsigned long pending, flags; + int hwirq; + + raw_spin_lock_irqsave(&intc->lock, flags); + pending = l1_readl(cpu->map_base + reg_status(intc, idx)) & + ~cpu->mask_cache[idx]; + raw_spin_unlock_irqrestore(&intc->lock, flags); + + for_each_set_bit(hwirq, &pending, IRQS_PER_WORD) { + generic_handle_irq(irq_find_mapping(intc->domain, + base + hwirq)); + } + } + + chained_irq_exit(chip, desc); +} + +static void __bcm7038_l1_unmask(struct irq_data *d, unsigned int cpu_idx) +{ + struct bcm7038_l1_chip *intc = irq_data_get_irq_chip_data(d); + u32 word = d->hwirq / IRQS_PER_WORD; + u32 mask = BIT(d->hwirq % IRQS_PER_WORD); + + intc->cpus[cpu_idx]->mask_cache[word] &= ~mask; + l1_writel(mask, intc->cpus[cpu_idx]->map_base + + reg_mask_clr(intc, word)); +} + +static void __bcm7038_l1_mask(struct irq_data *d, unsigned int cpu_idx) +{ + struct bcm7038_l1_chip *intc = irq_data_get_irq_chip_data(d); + u32 word = d->hwirq / IRQS_PER_WORD; + u32 mask = BIT(d->hwirq % IRQS_PER_WORD); + + intc->cpus[cpu_idx]->mask_cache[word] |= mask; + l1_writel(mask, intc->cpus[cpu_idx]->map_base + + reg_mask_set(intc, word)); +} + +static void bcm7038_l1_unmask(struct irq_data *d) +{ + struct bcm7038_l1_chip *intc = irq_data_get_irq_chip_data(d); + unsigned long flags; + + raw_spin_lock_irqsave(&intc->lock, flags); + __bcm7038_l1_unmask(d, intc->affinity[d->hwirq]); + raw_spin_unlock_irqrestore(&intc->lock, flags); +} + +static void bcm7038_l1_mask(struct irq_data *d) +{ + struct bcm7038_l1_chip *intc = irq_data_get_irq_chip_data(d); + unsigned long flags; + + raw_spin_lock_irqsave(&intc->lock, flags); + __bcm7038_l1_mask(d, intc->affinity[d->hwirq]); + raw_spin_unlock_irqrestore(&intc->lock, flags); +} + +static int bcm7038_l1_set_affinity(struct irq_data *d, + const struct cpumask *dest, + bool force) +{ + struct bcm7038_l1_chip *intc = irq_data_get_irq_chip_data(d); + unsigned long flags; + irq_hw_number_t hw = d->hwirq; + u32 word = hw / IRQS_PER_WORD; + u32 mask = BIT(hw % IRQS_PER_WORD); + unsigned int first_cpu = cpumask_any_and(dest, cpu_online_mask); + bool was_disabled; + + raw_spin_lock_irqsave(&intc->lock, flags); + + was_disabled = !!(intc->cpus[intc->affinity[hw]]->mask_cache[word] & + mask); + __bcm7038_l1_mask(d, intc->affinity[hw]); + intc->affinity[hw] = first_cpu; + if (!was_disabled) + __bcm7038_l1_unmask(d, first_cpu); + + raw_spin_unlock_irqrestore(&intc->lock, flags); + return 0; +} + +static int __init bcm7038_l1_init_one(struct device_node *dn, + unsigned int idx, + struct bcm7038_l1_chip *intc) +{ + struct resource res; + resource_size_t sz; + struct bcm7038_l1_cpu *cpu; + unsigned int i, n_words, parent_irq; + + if (of_address_to_resource(dn, idx, &res)) + return -EINVAL; + sz = resource_size(&res); + n_words = sz / REG_BYTES_PER_IRQ_WORD; + + if (n_words > MAX_WORDS) + return -EINVAL; + else if (!intc->n_words) + intc->n_words = n_words; + else if (intc->n_words != n_words) + return -EINVAL; + + cpu = intc->cpus[idx] = kzalloc(sizeof(*cpu) + n_words * sizeof(u32), + GFP_KERNEL); + if (!cpu) + return -ENOMEM; + + cpu->map_base = ioremap(res.start, sz); + if (!cpu->map_base) + return -ENOMEM; + + for (i = 0; i < n_words; i++) { + l1_writel(0xffffffff, cpu->map_base + reg_mask_set(intc, i)); + cpu->mask_cache[i] = 0xffffffff; + } + + parent_irq = irq_of_parse_and_map(dn, idx); + if (!parent_irq) { + pr_err("failed to map parent interrupt %d\n", parent_irq); + return -EINVAL; + } + irq_set_handler_data(parent_irq, intc); + irq_set_chained_handler(parent_irq, bcm7038_l1_irq_handle); + + return 0; +} + +static struct irq_chip bcm7038_l1_irq_chip = { + .name = "bcm7038-l1", + .irq_mask = bcm7038_l1_mask, + .irq_unmask = bcm7038_l1_unmask, + .irq_set_affinity = bcm7038_l1_set_affinity, +}; + +static int bcm7038_l1_map(struct irq_domain *d, unsigned int virq, + irq_hw_number_t hw_irq) +{ + irq_set_chip_and_handler(virq, &bcm7038_l1_irq_chip, handle_level_irq); + irq_set_chip_data(virq, d->host_data); + return 0; +} + +static const struct irq_domain_ops bcm7038_l1_domain_ops = { + .xlate = irq_domain_xlate_onecell, + .map = bcm7038_l1_map, +}; + +int __init bcm7038_l1_of_init(struct device_node *dn, + struct device_node *parent) +{ + struct bcm7038_l1_chip *intc; + int idx, ret; + + intc = kzalloc(sizeof(*intc), GFP_KERNEL); + if (!intc) + return -ENOMEM; + + raw_spin_lock_init(&intc->lock); + for_each_possible_cpu(idx) { + ret = bcm7038_l1_init_one(dn, idx, intc); + if (ret < 0) { + if (idx) + break; + pr_err("failed to remap intc L1 registers\n"); + goto out_free; + } + } + + intc->domain = irq_domain_add_linear(dn, IRQS_PER_WORD * intc->n_words, + &bcm7038_l1_domain_ops, + intc); + if (!intc->domain) { + ret = -ENOMEM; + goto out_unmap; + } + + pr_info("registered BCM7038 L1 intc (mem: 0x%p, IRQs: %d)\n", + intc->cpus[0]->map_base, IRQS_PER_WORD * intc->n_words); + + return 0; + +out_unmap: + for_each_possible_cpu(idx) { + struct bcm7038_l1_cpu *cpu = intc->cpus[idx]; + + if (cpu) { + if (cpu->map_base) + iounmap(cpu->map_base); + kfree(cpu); + } + } +out_free: + kfree(intc); + return ret; +} + +IRQCHIP_DECLARE(bcm7038_l1, "brcm,bcm7038-l1-intc", bcm7038_l1_of_init); -- cgit v1.2.3-59-g8ed1b From 9c24ce29b2b8c60d4bcca90c0a4da54b28f0b4e7 Mon Sep 17 00:00:00 2001 From: Kevin Cernekee Date: Thu, 25 Dec 2014 09:49:11 -0800 Subject: MIPS: BMIPS: Document the firmware->kernel DTB interface Add a new section covering the Generic BMIPS machine type. Signed-off-by: Kevin Cernekee Cc: f.fainelli@gmail.com Cc: jaedon.shin@gmail.com Cc: abrestic@chromium.org Cc: tglx@linutronix.de Cc: jason@lakedaemon.net Cc: jogo@openwrt.org Cc: arnd@arndb.de Cc: computersforpeace@gmail.com Cc: linux-mips@linux-mips.org Cc: devicetree@vger.kernel.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/8849/ Signed-off-by: Ralf Baechle --- Documentation/devicetree/booting-without-of.txt | 28 +++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/booting-without-of.txt b/Documentation/devicetree/booting-without-of.txt index 77685185cf3b..e49e423268c0 100644 --- a/Documentation/devicetree/booting-without-of.txt +++ b/Documentation/devicetree/booting-without-of.txt @@ -15,6 +15,7 @@ Table of Contents 1) Entry point for arch/arm 2) Entry point for arch/powerpc 3) Entry point for arch/x86 + 4) Entry point for arch/mips/bmips II - The DT block format 1) Header @@ -288,6 +289,33 @@ it with special cases. or initrd address. It simply holds information which can not be retrieved otherwise like interrupt routing or a list of devices behind an I2C bus. +4) Entry point for arch/mips/bmips +---------------------------------- + + Some bootloaders only support a single entry point, at the start of the + kernel image. Other bootloaders will jump to the ELF start address. + Both schemes are supported; CONFIG_BOOT_RAW=y and CONFIG_NO_EXCEPT_FILL=y, + so the first instruction immediately jumps to kernel_entry(). + + Similar to the arch/arm case (b), a DT-aware bootloader is expected to + set up the following registers: + + a0 : 0 + + a1 : 0xffffffff + + a2 : Physical pointer to the device tree block (defined in chapter + II) in RAM. The device tree can be located anywhere in the first + 512MB of the physical address space (0x00000000 - 0x1fffffff), + aligned on a 64 bit boundary. + + Legacy bootloaders do not use this convention, and they do not pass in a + DT block. In this case, Linux will look for a builtin DTB, selected via + CONFIG_DT_*. + + This convention is defined for 32-bit systems only, as there are not + currently any 64-bit BMIPS implementations. + II - The DT block format ======================== -- cgit v1.2.3-59-g8ed1b From e5a6fcc05831b269be35ec266639d901b43cba78 Mon Sep 17 00:00:00 2001 From: Kevin Cernekee Date: Thu, 25 Dec 2014 09:49:15 -0800 Subject: MIPS: BMIPS: Delete the irqchip driver from irq.c BCM3384/BCM63xx can use the common drivers/irqchip/irq-bcm7120-l2.c for this purpose; BCM7xxx will use drivers/irqchip/irq-bcm7038-l1.c. We no longer need this code under arch/mips. [ralf@linux-mips.org: Fix conflicts.] Signed-off-by: Kevin Cernekee Cc: f.fainelli@gmail.com Cc: jaedon.shin@gmail.com Cc: abrestic@chromium.org Cc: tglx@linutronix.de Cc: jason@lakedaemon.net Cc: jogo@openwrt.org Cc: arnd@arndb.de Cc: computersforpeace@gmail.com Cc: linux-mips@linux-mips.org Cc: devicetree@vger.kernel.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/8853/ Signed-off-by: Ralf Baechle --- .../devicetree/bindings/mips/brcm/bcm3384-intc.txt | 37 ---- arch/mips/bmips/irq.c | 189 ++------------------- 2 files changed, 17 insertions(+), 209 deletions(-) delete mode 100644 Documentation/devicetree/bindings/mips/brcm/bcm3384-intc.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mips/brcm/bcm3384-intc.txt b/Documentation/devicetree/bindings/mips/brcm/bcm3384-intc.txt deleted file mode 100644 index d4e0141d3620..000000000000 --- a/Documentation/devicetree/bindings/mips/brcm/bcm3384-intc.txt +++ /dev/null @@ -1,37 +0,0 @@ -* Interrupt Controller - -Properties: -- compatible: "brcm,bcm3384-intc" - - Compatibility with BCM3384 and possibly other BCM33xx/BCM63xx SoCs. - -- reg: Address/length pairs for each mask/status register set. Length must - be 8. If multiple register sets are specified, the first set will - handle IRQ offsets 0..31, the second set 32..63, and so on. - -- interrupt-controller: This is an interrupt controller. - -- #interrupt-cells: Must be <1>. Just a simple IRQ offset; no level/edge - or polarity configuration is possible with this controller. - -- interrupt-parent: This controller is cascaded from a MIPS CPU HW IRQ, or - from another INTC. - -- interrupts: The IRQ on the parent controller. - -Example: - periph_intc: periph_intc@14e00038 { - compatible = "brcm,bcm3384-intc"; - - /* - * IRQs 0..31: mask reg 0x14e00038, status reg 0x14e0003c - * IRQs 32..63: mask reg 0x14e00340, status reg 0x14e00344 - */ - reg = <0x14e00038 0x8 0x14e00340 0x8>; - - interrupt-controller; - #interrupt-cells = <1>; - - interrupt-parent = <&cpu_intc>; - interrupts = <4>; - }; diff --git a/arch/mips/bmips/irq.c b/arch/mips/bmips/irq.c index fd94fe849af6..14552e58ff7e 100644 --- a/arch/mips/bmips/irq.c +++ b/arch/mips/bmips/irq.c @@ -3,191 +3,36 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Partially based on arch/mips/ralink/irq.c - * - * Copyright (C) 2009 Gabor Juhos - * Copyright (C) 2013 John Crispin - * Copyright (C) 2014 Kevin Cernekee + * Copyright (C) 2014 Broadcom Corporation + * Author: Kevin Cernekee */ -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include #include +#include #include -#include - -/* INTC register offsets */ -#define INTC_REG_ENABLE 0x00 -#define INTC_REG_STATUS 0x04 - -#define MAX_WORDS 2 -#define IRQS_PER_WORD 32 - -struct bcm3384_intc { - int n_words; - void __iomem *reg[MAX_WORDS]; - u32 enable[MAX_WORDS]; - spinlock_t lock; -}; - -static void bcm3384_intc_irq_unmask(struct irq_data *d) -{ - struct bcm3384_intc *priv = d->domain->host_data; - unsigned long flags; - int idx = d->hwirq / IRQS_PER_WORD; - int bit = d->hwirq % IRQS_PER_WORD; - - spin_lock_irqsave(&priv->lock, flags); - priv->enable[idx] |= BIT(bit); - __raw_writel(priv->enable[idx], priv->reg[idx] + INTC_REG_ENABLE); - spin_unlock_irqrestore(&priv->lock, flags); -} - -static void bcm3384_intc_irq_mask(struct irq_data *d) -{ - struct bcm3384_intc *priv = d->domain->host_data; - unsigned long flags; - int idx = d->hwirq / IRQS_PER_WORD; - int bit = d->hwirq % IRQS_PER_WORD; - - spin_lock_irqsave(&priv->lock, flags); - priv->enable[idx] &= ~BIT(bit); - __raw_writel(priv->enable[idx], priv->reg[idx] + INTC_REG_ENABLE); - spin_unlock_irqrestore(&priv->lock, flags); -} - -static struct irq_chip bcm3384_intc_irq_chip = { - .name = "INTC", - .irq_unmask = bcm3384_intc_irq_unmask, - .irq_mask = bcm3384_intc_irq_mask, - .irq_mask_ack = bcm3384_intc_irq_mask, -}; +#include unsigned int get_c0_compare_int(void) { return CP0_LEGACY_COMPARE_IRQ; } -static void bcm3384_intc_irq_handler(unsigned int irq, struct irq_desc *desc) -{ - struct irq_domain *domain = irq_get_handler_data(irq); - struct bcm3384_intc *priv = domain->host_data; - unsigned long flags; - unsigned int idx; - - for (idx = 0; idx < priv->n_words; idx++) { - unsigned long pending; - int hwirq; - - spin_lock_irqsave(&priv->lock, flags); - pending = __raw_readl(priv->reg[idx] + INTC_REG_STATUS) & - priv->enable[idx]; - spin_unlock_irqrestore(&priv->lock, flags); - - for_each_set_bit(hwirq, &pending, IRQS_PER_WORD) { - generic_handle_irq(irq_find_mapping(domain, - hwirq + idx * IRQS_PER_WORD)); - } - } -} - -asmlinkage void plat_irq_dispatch(void) -{ - unsigned long pending = - (read_c0_status() & read_c0_cause() & ST0_IM) >> STATUSB_IP0; - int bit; - - for_each_set_bit(bit, &pending, 8) - do_IRQ(MIPS_CPU_IRQ_BASE + bit); -} - -static int intc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) -{ - irq_set_chip_and_handler(irq, &bcm3384_intc_irq_chip, handle_level_irq); - return 0; -} - -static const struct irq_domain_ops irq_domain_ops = { - .xlate = irq_domain_xlate_onecell, - .map = intc_map, -}; - -static int __init ioremap_one_pair(struct bcm3384_intc *priv, - struct device_node *node, - int idx) -{ - struct resource res; - - if (of_address_to_resource(node, idx, &res)) - return 0; - - if (request_mem_region(res.start, resource_size(&res), - res.name) < 0) - pr_err("Failed to request INTC register region\n"); - - priv->reg[idx] = ioremap_nocache(res.start, resource_size(&res)); - if (!priv->reg[idx]) - panic("Failed to ioremap INTC register range"); - - /* start up with everything masked before we hook the parent IRQ */ - __raw_writel(0, priv->reg[idx] + INTC_REG_ENABLE); - priv->enable[idx] = 0; - - return IRQS_PER_WORD; -} - -static int __init intc_of_init(struct device_node *node, - struct device_node *parent) +void __init arch_init_irq(void) { - struct irq_domain *domain; - unsigned int parent_irq, n_irqs = 0; - struct bcm3384_intc *priv; - - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - panic("Failed to allocate bcm3384_intc struct"); - - spin_lock_init(&priv->lock); - - parent_irq = irq_of_parse_and_map(node, 0); - if (!parent_irq) - panic("Failed to get INTC IRQ"); - - n_irqs += ioremap_one_pair(priv, node, 0); - n_irqs += ioremap_one_pair(priv, node, 1); - - if (!n_irqs) - panic("Failed to map INTC registers"); + struct device_node *dn; - priv->n_words = n_irqs / IRQS_PER_WORD; - domain = irq_domain_add_linear(node, n_irqs, &irq_domain_ops, priv); - if (!domain) - panic("Failed to add irqdomain"); + /* Only the STB (bcm7038) controller supports SMP IRQ affinity */ + dn = of_find_compatible_node(NULL, NULL, "brcm,bcm7038-l1-intc"); + if (dn) + of_node_put(dn); + else + bmips_tp1_irqs = 0; - irq_set_chained_handler(parent_irq, bcm3384_intc_irq_handler); - irq_set_handler_data(parent_irq, domain); - - return 0; + irqchip_init(); } -static struct of_device_id of_irq_ids[] __initdata = { - { .compatible = "mti,cpu-interrupt-controller", - .data = mips_cpu_irq_of_init }, - { .compatible = "brcm,bcm3384-intc", - .data = intc_of_init }, - {}, -}; - -void __init arch_init_irq(void) -{ - bmips_tp1_irqs = 0; - of_irq_init(of_irq_ids); -} +OF_DECLARE_2(irqchip, mips_cpu_intc, "mti,cpu-interrupt-controller", + mips_cpu_irq_of_init); -- cgit v1.2.3-59-g8ed1b From 81a07b4abe1b574605b67e01e3167be44b541980 Mon Sep 17 00:00:00 2001 From: Kevin Cernekee Date: Thu, 25 Dec 2014 09:49:19 -0800 Subject: MIPS: BMIPS: Update DT bindings to reflect new SoC support Add an entry for each supported Broadcom SoC. Signed-off-by: Kevin Cernekee Signed-off-by: Jaedon Shin Cc: f.fainelli@gmail.com Cc: abrestic@chromium.org Cc: tglx@linutronix.de Cc: jason@lakedaemon.net Cc: jogo@openwrt.org Cc: arnd@arndb.de Cc: computersforpeace@gmail.com Cc: linux-mips@linux-mips.org Cc: devicetree@vger.kernel.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/8857/ Signed-off-by: Ralf Baechle --- Documentation/devicetree/bindings/mips/brcm/cm-dsl.txt | 11 ----------- Documentation/devicetree/bindings/mips/brcm/soc.txt | 12 ++++++++++++ 2 files changed, 12 insertions(+), 11 deletions(-) delete mode 100644 Documentation/devicetree/bindings/mips/brcm/cm-dsl.txt create mode 100644 Documentation/devicetree/bindings/mips/brcm/soc.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mips/brcm/cm-dsl.txt b/Documentation/devicetree/bindings/mips/brcm/cm-dsl.txt deleted file mode 100644 index 8a139cb3c0b5..000000000000 --- a/Documentation/devicetree/bindings/mips/brcm/cm-dsl.txt +++ /dev/null @@ -1,11 +0,0 @@ -* Broadcom cable/DSL platforms - -SoCs: - -Required properties: -- compatible: "brcm,bcm3384", "brcm,bcm33843" - -Boards: - -Required properties: -- compatible: "brcm,bcm93384wvg" diff --git a/Documentation/devicetree/bindings/mips/brcm/soc.txt b/Documentation/devicetree/bindings/mips/brcm/soc.txt new file mode 100644 index 000000000000..7bab90cc4a7b --- /dev/null +++ b/Documentation/devicetree/bindings/mips/brcm/soc.txt @@ -0,0 +1,12 @@ +* Broadcom cable/DSL/settop platforms + +Required properties: + +- compatible: "brcm,bcm3384", "brcm,bcm33843" + "brcm,bcm3384-viper", "brcm,bcm33843-viper" + "brcm,bcm6328", "brcm,bcm6368", + "brcm,bcm7125", "brcm,bcm7346", "brcm,bcm7358", "brcm,bcm7360", + "brcm,bcm7362", "brcm,bcm7420", "brcm,bcm7425" + +The experimental -viper variants are for running Linux on the 3384's +BMIPS4355 cable modem CPU instead of the BMIPS5000 application processor. -- cgit v1.2.3-59-g8ed1b From 5b4e845393d313af1d319b8bd01c9daaca3aa487 Mon Sep 17 00:00:00 2001 From: Andrew Bresticker Date: Mon, 23 Feb 2015 18:28:34 -0800 Subject: CLOCKSOURCE: mips-gic: Allow GIC clock to be specified in device-tree As an alternative to the "clock-frequency" property, allow the GIC timer operating clock to be specified in the device-tree instead. This is useful on systems which use common clock or where the GIC is not fixed to a particular frequency and is instead, for example, derived from the CPU clock. Signed-off-by: Andrew Bresticker Cc: James Hogan Cc: Rob Herring Cc: Pawel Moll Cc: Mark Rutland Cc: Ian Campbell Cc: Kumar Gala Cc: Daniel Lezcano Cc: Thomas Gleixner Cc: devicetree@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/9309/ --- .../devicetree/bindings/interrupt-controller/mips-gic.txt | 5 +++++ drivers/clocksource/mips-gic-timer.c | 10 +++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/interrupt-controller/mips-gic.txt b/Documentation/devicetree/bindings/interrupt-controller/mips-gic.txt index 5a65478e5d40..aae4c384ee1f 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/mips-gic.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/mips-gic.txt @@ -27,8 +27,13 @@ Optional properties: Required properties for timer sub-node: - compatible : Should be "mti,gic-timer". - interrupts : Interrupt for the GIC local timer. + +Optional properties for timer sub-node: +- clocks : GIC timer operating clock. - clock-frequency : Clock frequency at which the GIC timers operate. +Note that one of clocks or clock-frequency must be specified. + Example: gic: interrupt-controller@1bdc0000 { diff --git a/drivers/clocksource/mips-gic-timer.c b/drivers/clocksource/mips-gic-timer.c index 16adbc1fa4c1..b81ed1a5342d 100644 --- a/drivers/clocksource/mips-gic-timer.c +++ b/drivers/clocksource/mips-gic-timer.c @@ -5,6 +5,7 @@ * * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. */ +#include #include #include #include @@ -149,11 +150,18 @@ void __init gic_clocksource_init(unsigned int frequency) static void __init gic_clocksource_of_init(struct device_node *node) { + struct clk *clk; + if (WARN_ON(!gic_present || !node->parent || !of_device_is_compatible(node->parent, "mti,gic"))) return; - if (of_property_read_u32(node, "clock-frequency", &gic_frequency)) { + clk = of_clk_get(node, 0); + if (!IS_ERR(clk)) { + gic_frequency = clk_get_rate(clk); + clk_put(clk); + } else if (of_property_read_u32(node, "clock-frequency", + &gic_frequency)) { pr_err("GIC frequency not specified.\n"); return; } -- cgit v1.2.3-59-g8ed1b From b6305d62234642a37fa1a68d15e741cfc3428c45 Mon Sep 17 00:00:00 2001 From: Peter Griffin Date: Tue, 31 Mar 2015 18:37:12 +0100 Subject: ahci: st: Update the DT example for how to obtain the PHY. The example is wrong in that the phys property should take a phandle to the phy port. Also with the changing over to generic PHY type constants we also update that as well. Signed-off-by: Peter Griffin Acked-by: Rob Herring Acked-by: Lee Jones Signed-off-by: Tejun Heo --- Documentation/devicetree/bindings/ata/ahci-st.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/ata/ahci-st.txt b/Documentation/devicetree/bindings/ata/ahci-st.txt index 0574a77a0b9f..133120270066 100644 --- a/Documentation/devicetree/bindings/ata/ahci-st.txt +++ b/Documentation/devicetree/bindings/ata/ahci-st.txt @@ -11,7 +11,7 @@ Required properties: - reset-names : Associated names must be; "pwr-dwn" and "sw-rst" - clocks : The phandle for the clock - clock-names : Associated name must be; "ahci_clk" - - phys : The phandle for the PHY device + - phys : The phandle for the PHY port - phy-names : Associated name must be; "ahci_phy" Example: @@ -21,7 +21,7 @@ Example: reg = <0xfe380000 0x1000>; interrupts = ; interrupt-names = "hostc"; - phys = <&miphy365x_phy MIPHY_PORT_0 MIPHY_TYPE_SATA>; + phys = <&phy_port0 PHY_TYPE_SATA>; phy-names = "ahci_phy"; resets = <&powerdown STIH416_SATA0_POWERDOWN>, <&softreset STIH416_SATA0_SOFTRESET>; -- cgit v1.2.3-59-g8ed1b From 9a8340bfeb03c5fc20b39aa533b164844ef582f9 Mon Sep 17 00:00:00 2001 From: Peter Griffin Date: Tue, 31 Mar 2015 08:35:07 +0100 Subject: ahci: st: Update the ahci_st DT documentation As part of testing ahci_st driver working on stih407 I noticed several things wrong in the DT documentation: - 1) Compatible string doesn't match the driver code 2) pwr-rst reset isn't documented (but exists in the driver) 3) some whitespace issues (spaces not tabs) Also add in a stih407 family example into the doc. Signed-off-by: Peter Griffin Acked-by: Lee Jones Acked-by: Maxime Coquelin Signed-off-by: Tejun Heo --- Documentation/devicetree/bindings/ata/ahci-st.txt | 45 ++++++++++++++++------- 1 file changed, 32 insertions(+), 13 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/ata/ahci-st.txt b/Documentation/devicetree/bindings/ata/ahci-st.txt index 133120270066..e1d01df8e3c1 100644 --- a/Documentation/devicetree/bindings/ata/ahci-st.txt +++ b/Documentation/devicetree/bindings/ata/ahci-st.txt @@ -3,29 +3,48 @@ STMicroelectronics STi SATA controller This binding describes a SATA device. Required properties: - - compatible : Must be "st,sti-ahci" + - compatible : Must be "st,ahci" - reg : Physical base addresses and length of register sets - interrupts : Interrupt associated with the SATA device - interrupt-names : Associated name must be; "hostc" - - resets : The power-down and soft-reset lines of SATA IP - - reset-names : Associated names must be; "pwr-dwn" and "sw-rst" - clocks : The phandle for the clock - clock-names : Associated name must be; "ahci_clk" - phys : The phandle for the PHY port - phy-names : Associated name must be; "ahci_phy" +Optional properties: + - resets : The power-down, soft-reset and power-reset lines of SATA IP + - reset-names : Associated names must be; "pwr-dwn", "sw-rst" and "pwr-rst" + Example: + /* Example for stih416 */ sata0: sata@fe380000 { - compatible = "st,sti-ahci"; - reg = <0xfe380000 0x1000>; - interrupts = ; - interrupt-names = "hostc"; - phys = <&phy_port0 PHY_TYPE_SATA>; - phy-names = "ahci_phy"; - resets = <&powerdown STIH416_SATA0_POWERDOWN>, + compatible = "st,ahci"; + reg = <0xfe380000 0x1000>; + interrupts = ; + interrupt-names = "hostc"; + phys = <&phy_port0 PHY_TYPE_SATA>; + phy-names = "ahci_phy"; + resets = <&powerdown STIH416_SATA0_POWERDOWN>, <&softreset STIH416_SATA0_SOFTRESET>; - reset-names = "pwr-dwn", "sw-rst"; - clocks = <&clk_s_a0_ls CLK_ICN_REG>; - clock-names = "ahci_clk"; + reset-names = "pwr-dwn", "sw-rst"; + clocks = <&clk_s_a0_ls CLK_ICN_REG>; + clock-names = "ahci_clk"; + }; + + /* Example for stih407 family silicon */ + sata0: sata@9b20000 { + compatible = "st,ahci"; + reg = <0x9b20000 0x1000>; + interrupts = ; + interrupt-names = "hostc"; + phys = <&phy_port0 PHY_TYPE_SATA>; + phy-names = "ahci_phy"; + resets = <&powerdown STIH407_SATA0_POWERDOWN>, + <&softreset STIH407_SATA0_SOFTRESET>, + <&softreset STIH407_SATA0_PWR_SOFTRESET>; + reset-names = "pwr-dwn", "sw-rst", "pwr-rst"; + clocks = <&clk_s_c0_flexgen CLK_ICN_REG>; + clock-names = "ahci_clk"; }; -- cgit v1.2.3-59-g8ed1b From 81f8a7be6642b4c26ab681b2e0f4c4120a6de1b0 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 1 Apr 2015 17:26:23 +0200 Subject: mmc: Add support for marking hpi as broken through devicetree The eMMC on a tablet I've will stop working / communicating as soon as the kernel executes: mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HPI_MGMT, 1, card->ext_csd.generic_cmd6_time); There seems to be no way to reliable identify eMMC-s which have a broken hpi implementation, but at least for eMMC's which are soldered onto a board we can work around this by specifying that hpi is broken in devicetree. Signed-off-by: Hans de Goede Signed-off-by: Ulf Hansson --- Documentation/devicetree/bindings/mmc/mmc-card.txt | 31 ++++++++++++++++++++++ drivers/mmc/core/mmc.c | 10 ++++++- 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/mmc/mmc-card.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mmc/mmc-card.txt b/Documentation/devicetree/bindings/mmc/mmc-card.txt new file mode 100644 index 000000000000..a70fcd65b9ea --- /dev/null +++ b/Documentation/devicetree/bindings/mmc/mmc-card.txt @@ -0,0 +1,31 @@ +mmc-card / eMMC bindings +------------------------ + +This documents describes the devicetree bindings for a mmc-host controller +child node describing a mmc-card / an eMMC, see "Use of Function subnodes" +in mmc.txt + +Required properties: +-compatible : Must be "mmc-card" +-reg : Must be <0> + +Optional properties: +-broken-hpi : Use this to indicate that the mmc-card has a broken hpi + implementation, and that hpi should not be used + +Example: + +&mmc2 { + pinctrl-names = "default"; + pinctrl-0 = <&mmc2_pins_a>; + vmmc-supply = <®_vcc3v3>; + bus-width = <8>; + non-removable; + status = "okay"; + + mmccard: mmccard@0 { + reg = <0>; + compatible = "mmc-card"; + broken-hpi; + }; +}; diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 1d41e8541f38..c84131e28625 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -11,6 +11,7 @@ */ #include +#include #include #include #include @@ -336,6 +337,8 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd) { int err = 0, idx; unsigned int part_size; + struct device_node *np; + bool broken_hpi = false; /* Version is coded in the CSD_STRUCTURE byte in the EXT_CSD register */ card->ext_csd.raw_ext_csd_structure = ext_csd[EXT_CSD_STRUCTURE]; @@ -349,6 +352,11 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd) } } + np = mmc_of_find_child_device(card->host, 0); + if (np && of_device_is_compatible(np, "mmc-card")) + broken_hpi = of_property_read_bool(np, "broken-hpi"); + of_node_put(np); + /* * The EXT_CSD format is meant to be forward compatible. As long * as CSD_STRUCTURE does not change, all values for EXT_CSD_REV @@ -494,7 +502,7 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd) } /* check whether the eMMC card supports HPI */ - if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1) { + if (!broken_hpi && (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1)) { card->ext_csd.hpi = 1; if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x2) card->ext_csd.hpi_cmd = MMC_STOP_TRANSMISSION; -- cgit v1.2.3-59-g8ed1b From 38e42f121601fc0640c032871a38efa5a59cff68 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Thu, 26 Mar 2015 08:58:31 +0100 Subject: ARM: 8335/1: Documentation: DT bindings: Tegra AHB: document the legacy base address Documentation: DT bindings: Tegra AHB: require the legacy base address for existing chips Per Stephen Warren, note in the Tegra AHB DT binding documentation that we specifically deprecate any attempt to use the IP block's actual hardware base address, and advocate the use of the legacy "off-by-four" address in the 'regs' property, for Tegra chips with existing upstream Linux DT files that include a Tegra AHB node. This patch updates the documentation accordingly. Changing the existing kernel DT data isn't under consideration because Linux kernel DT data policy is to preserve compatibility between newer DT data files and older kernels. However, this additional step of changing the documentation should discourage others from sending kernel patches to try to change the legacy kernel DT data. Furthermore, for out-of-tree software (such as bootloaders or other operating systems) that may rely on Linux kernel DT binding documentation as an ABI (but not the Linux kernel DT data itself), such a change may allow future convergence with the Linux kernel DT data without additional code changes. Signed-off-by: Paul Walmsley Cc: Paul Walmsley Cc: Stephen Warren Cc: Alexandre Courbot Cc: Eduardo Valentin Cc: Ian Campbell Cc: Kumar Gala Cc: Mark Rutland Cc: Pawel Moll Cc: Rob Herring Cc: Thierry Reding Cc: devicetree@vger.kernel.org Cc: linux-kernel@vger.kernel.org Acked-by: Stephen Warren Signed-off-by: Russell King --- Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-ahb.txt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-ahb.txt b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-ahb.txt index 067c9790062f..9a4295b54539 100644 --- a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-ahb.txt +++ b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-ahb.txt @@ -5,9 +5,12 @@ Required properties: Tegra30, must contain "nvidia,tegra30-ahb". Otherwise, must contain '"nvidia,-ahb", "nvidia,tegra30-ahb"' where is tegra124, tegra132, or tegra210. -- reg : Should contain 1 register ranges(address and length) +- reg : Should contain 1 register ranges(address and length). For + Tegra20, Tegra30, and Tegra114 chips, the value must be <0x6000c004 + 0x10c>. For Tegra124, Tegra132 and Tegra210 chips, the value should + be be <0x6000c000 0x150>. -Example: +Example (for a Tegra20 chip): ahb: ahb@6000c004 { compatible = "nvidia,tegra20-ahb"; reg = <0x6000c004 0x10c>; /* AHB Arbitration + Gizmo Controller */ -- cgit v1.2.3-59-g8ed1b From ef8d9e7db285ea3d26b13dfeb6762346c95dc0d1 Mon Sep 17 00:00:00 2001 From: Markus Pargmann Date: Thu, 2 Apr 2015 10:11:33 +0200 Subject: Documentation: nbd: Reformat to allow more documentation Reformat the existing documentation to have more structure. This allows for more documentation seperated from the existing paragraphs. Signed-off-by: Markus Pargmann Signed-off-by: Jens Axboe --- Documentation/blockdev/nbd.txt | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) (limited to 'Documentation') diff --git a/Documentation/blockdev/nbd.txt b/Documentation/blockdev/nbd.txt index 271e607304da..337946bd460e 100644 --- a/Documentation/blockdev/nbd.txt +++ b/Documentation/blockdev/nbd.txt @@ -1,17 +1,21 @@ - Network Block Device (TCP version) - - What is it: With this compiled in the kernel (or as a module), Linux - can use a remote server as one of its block devices. So every time - the client computer wants to read, e.g., /dev/nb0, it sends a - request over TCP to the server, which will reply with the data read. - This can be used for stations with low disk space (or even diskless) - to borrow disk space from another computer. - Unlike NFS, it is possible to put any filesystem on it, etc. +Network Block Device (TCP version) +================================== - For more information, or to download the nbd-client and nbd-server - tools, go to http://nbd.sf.net/. +1) Overview +----------- - The nbd kernel module need only be installed on the client - system, as the nbd-server is completely in userspace. In fact, - the nbd-server has been successfully ported to other operating - systems, including Windows. +What is it: With this compiled in the kernel (or as a module), Linux +can use a remote server as one of its block devices. So every time +the client computer wants to read, e.g., /dev/nb0, it sends a +request over TCP to the server, which will reply with the data read. +This can be used for stations with low disk space (or even diskless) +to borrow disk space from another computer. +Unlike NFS, it is possible to put any filesystem on it, etc. + +For more information, or to download the nbd-client and nbd-server +tools, go to http://nbd.sf.net/. + +The nbd kernel module need only be installed on the client +system, as the nbd-server is completely in userspace. In fact, +the nbd-server has been successfully ported to other operating +systems, including Windows. -- cgit v1.2.3-59-g8ed1b From 4e5b44ca7b5c44872b6ec172331a5545116e2d46 Mon Sep 17 00:00:00 2001 From: Markus Pargmann Date: Thu, 2 Apr 2015 10:11:34 +0200 Subject: Documentation: nbd: Add list of module parameters Add a list of available module parameters as attachment to the documentation. Signed-off-by: Markus Pargmann Signed-off-by: Jens Axboe --- Documentation/blockdev/nbd.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'Documentation') diff --git a/Documentation/blockdev/nbd.txt b/Documentation/blockdev/nbd.txt index 337946bd460e..db242ea2bce8 100644 --- a/Documentation/blockdev/nbd.txt +++ b/Documentation/blockdev/nbd.txt @@ -19,3 +19,13 @@ The nbd kernel module need only be installed on the client system, as the nbd-server is completely in userspace. In fact, the nbd-server has been successfully ported to other operating systems, including Windows. + +A) NBD parameters +----------------- + +max_part + Number of partitions per device (default: 0). + +nbds_max + Number of block devices that should be initialized (default: 16). + -- cgit v1.2.3-59-g8ed1b From 609adde838f4557f9d209b0432f4bac5c5eb5e86 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 19 Mar 2015 17:08:07 -0700 Subject: phy: Add a driver for dm816x USB PHY Add a minimal driver for dm816x USB. This makes USB work on dm816x without any other changes needed as it can use the existing musb_dsps glue layer for the USB controller. Note that this phy is different from dm814x and am335x. Cc: Bin Liu Cc: Brian Hutchinson Cc: Felipe Balbi Cc: Matthijs van Duin Cc: Paul Bolle Cc: Rusty Russell Signed-off-by: Tony Lindgren Signed-off-by: Kishon Vijay Abraham I --- .../devicetree/bindings/phy/dm816x-phy.txt | 24 ++ drivers/phy/Kconfig | 7 + drivers/phy/Makefile | 1 + drivers/phy/phy-dm816x-usb.c | 290 +++++++++++++++++++++ 4 files changed, 322 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/dm816x-phy.txt create mode 100644 drivers/phy/phy-dm816x-usb.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/phy/dm816x-phy.txt b/Documentation/devicetree/bindings/phy/dm816x-phy.txt new file mode 100644 index 000000000000..2fe3d11d063d --- /dev/null +++ b/Documentation/devicetree/bindings/phy/dm816x-phy.txt @@ -0,0 +1,24 @@ +Device tree binding documentation for am816x USB PHY +========================= + +Required properties: +- compatible : should be "ti,dm816x-usb-phy" +- reg : offset and length of the PHY register set. +- reg-names : name for the phy registers +- clocks : phandle to the clock +- clock-names : name of the clock +- syscon: phandle for the syscon node to access misc registers +- #phy-cells : from the generic PHY bindings, must be 1 +- syscon: phandle for the syscon node to access misc registers + +Example: + +usb_phy0: usb-phy@20 { + compatible = "ti,dm8168-usb-phy"; + reg = <0x20 0x8>; + reg-names = "phy"; + clocks = <&main_fapll 6>; + clock-names = "refclk"; + #phy-cells = <0>; + syscon = <&scm_conf>; +}; diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 2962de205ba7..885c39c28a8b 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -35,6 +35,13 @@ config ARMADA375_USBCLUSTER_PHY depends on OF select GENERIC_PHY +config PHY_DM816X_USB + tristate "TI dm816x USB PHY driver" + depends on ARCH_OMAP2PLUS + select GENERIC_PHY + help + Enable this for dm816x USB to work. + config PHY_EXYNOS_MIPI_VIDEO tristate "S5P/EXYNOS SoC series MIPI CSI-2/DSI PHY driver" depends on HAS_IOMEM diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index f080e1bb2a74..dab6665ad9c1 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_GENERIC_PHY) += phy-core.o obj-$(CONFIG_PHY_BERLIN_USB) += phy-berlin-usb.o obj-$(CONFIG_PHY_BERLIN_SATA) += phy-berlin-sata.o +obj-$(CONFIG_PHY_DM816X_USB) += phy-dm816x-usb.o obj-$(CONFIG_ARMADA375_USBCLUSTER_PHY) += phy-armada375-usb2.o obj-$(CONFIG_BCM_KONA_USB2_PHY) += phy-bcm-kona-usb2.o obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO) += phy-exynos-dp-video.o diff --git a/drivers/phy/phy-dm816x-usb.c b/drivers/phy/phy-dm816x-usb.c new file mode 100644 index 000000000000..7b42555ddd51 --- /dev/null +++ b/drivers/phy/phy-dm816x-usb.c @@ -0,0 +1,290 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * TRM has two sets of USB_CTRL registers.. The correct register bits + * are in TRM section 24.9.8.2 USB_CTRL Register. The TRM documents the + * phy as being SR70LX Synopsys USB 2.0 OTG nanoPHY. It also seems at + * least dm816x rev c ignores writes to USB_CTRL register, but the TI + * kernel is writing to those so it's possible that later revisions + * have worknig USB_CTRL register. + * + * Also note that At least USB_CTRL register seems to be dm816x specific + * according to the TRM. It's possible that USBPHY_CTRL is more generic, + * but that would have to be checked against the SR70LX documentation + * which does not seem to be publicly available. + * + * Finally, the phy on dm814x and am335x is different from dm816x. + */ +#define DM816X_USB_CTRL_PHYCLKSRC BIT(8) /* 1 = PLL ref clock */ +#define DM816X_USB_CTRL_PHYSLEEP1 BIT(1) /* Enable the first phy */ +#define DM816X_USB_CTRL_PHYSLEEP0 BIT(0) /* Enable the second phy */ + +#define DM816X_USBPHY_CTRL_TXRISETUNE 1 +#define DM816X_USBPHY_CTRL_TXVREFTUNE 0xc +#define DM816X_USBPHY_CTRL_TXPREEMTUNE 0x2 + +struct dm816x_usb_phy { + struct regmap *syscon; + struct device *dev; + unsigned int instance; + struct clk *refclk; + struct usb_phy phy; + unsigned int usb_ctrl; /* Shared between phy0 and phy1 */ + unsigned int usbphy_ctrl; +}; + +static int dm816x_usb_phy_set_host(struct usb_otg *otg, struct usb_bus *host) +{ + otg->host = host; + if (!host) + otg->state = OTG_STATE_UNDEFINED; + + return 0; +} + +static int dm816x_usb_phy_set_peripheral(struct usb_otg *otg, + struct usb_gadget *gadget) +{ + otg->gadget = gadget; + if (!gadget) + otg->state = OTG_STATE_UNDEFINED; + + return 0; +} + +static int dm816x_usb_phy_init(struct phy *x) +{ + struct dm816x_usb_phy *phy = phy_get_drvdata(x); + unsigned int val; + int error; + + if (clk_get_rate(phy->refclk) != 24000000) + dev_warn(phy->dev, "nonstandard phy refclk\n"); + + /* Set PLL ref clock and put phys to sleep */ + error = regmap_update_bits(phy->syscon, phy->usb_ctrl, + DM816X_USB_CTRL_PHYCLKSRC | + DM816X_USB_CTRL_PHYSLEEP1 | + DM816X_USB_CTRL_PHYSLEEP0, + 0); + regmap_read(phy->syscon, phy->usb_ctrl, &val); + if ((val & 3) != 0) + dev_info(phy->dev, + "Working dm816x USB_CTRL! (0x%08x)\n", + val); + + /* + * TI kernel sets these values for "symmetrical eye diagram and + * better signal quality" so let's assume somebody checked the + * values with a scope and set them here too. + */ + regmap_read(phy->syscon, phy->usbphy_ctrl, &val); + val |= DM816X_USBPHY_CTRL_TXRISETUNE | + DM816X_USBPHY_CTRL_TXVREFTUNE | + DM816X_USBPHY_CTRL_TXPREEMTUNE; + regmap_write(phy->syscon, phy->usbphy_ctrl, val); + + return 0; +} + +static struct phy_ops ops = { + .init = dm816x_usb_phy_init, + .owner = THIS_MODULE, +}; + +static int dm816x_usb_phy_runtime_suspend(struct device *dev) +{ + struct dm816x_usb_phy *phy = dev_get_drvdata(dev); + unsigned int mask, val; + int error = 0; + + mask = BIT(phy->instance); + val = ~BIT(phy->instance); + error = regmap_update_bits(phy->syscon, phy->usb_ctrl, + mask, val); + if (error) + dev_err(phy->dev, "phy%i failed to power off\n", + phy->instance); + clk_disable(phy->refclk); + + return 0; +} + +static int dm816x_usb_phy_runtime_resume(struct device *dev) +{ + struct dm816x_usb_phy *phy = dev_get_drvdata(dev); + unsigned int mask, val; + int error; + + error = clk_enable(phy->refclk); + if (error) + return error; + + /* + * Note that at least dm816x rev c does not seem to do + * anything with the USB_CTRL register. But let's follow + * what the TI tree is doing in case later revisions use + * USB_CTRL. + */ + mask = BIT(phy->instance); + val = BIT(phy->instance); + error = regmap_update_bits(phy->syscon, phy->usb_ctrl, + mask, val); + if (error) { + dev_err(phy->dev, "phy%i failed to power on\n", + phy->instance); + clk_disable(phy->refclk); + return error; + } + + return 0; +} + +static UNIVERSAL_DEV_PM_OPS(dm816x_usb_phy_pm_ops, + dm816x_usb_phy_runtime_suspend, + dm816x_usb_phy_runtime_resume, + NULL); + +#ifdef CONFIG_OF +static const struct of_device_id dm816x_usb_phy_id_table[] = { + { + .compatible = "ti,dm8168-usb-phy", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, dm816x_usb_phy_id_table); +#endif + +static int dm816x_usb_phy_probe(struct platform_device *pdev) +{ + struct dm816x_usb_phy *phy; + struct resource *res; + struct phy *generic_phy; + struct phy_provider *phy_provider; + struct usb_otg *otg; + const struct of_device_id *of_id; + const struct usb_phy_data *phy_data; + int error; + + of_id = of_match_device(of_match_ptr(dm816x_usb_phy_id_table), + &pdev->dev); + if (!of_id) + return -EINVAL; + + phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL); + if (!phy) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENOENT; + + phy->syscon = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "syscon"); + if (IS_ERR(phy->syscon)) + return PTR_ERR(phy->syscon); + + /* + * According to sprs614e.pdf, the first usb_ctrl is shared and + * the second instance for usb_ctrl is reserved.. Also the + * register bits are different from earlier TRMs. + */ + phy->usb_ctrl = 0x20; + phy->usbphy_ctrl = (res->start & 0xff) + 4; + if (phy->usbphy_ctrl == 0x2c) + phy->instance = 1; + + phy_data = of_id->data; + + otg = devm_kzalloc(&pdev->dev, sizeof(*otg), GFP_KERNEL); + if (!otg) + return -ENOMEM; + + phy->dev = &pdev->dev; + phy->phy.dev = phy->dev; + phy->phy.label = "dm8168_usb_phy"; + phy->phy.otg = otg; + phy->phy.type = USB_PHY_TYPE_USB2; + otg->set_host = dm816x_usb_phy_set_host; + otg->set_peripheral = dm816x_usb_phy_set_peripheral; + otg->usb_phy = &phy->phy; + + platform_set_drvdata(pdev, phy); + + phy->refclk = devm_clk_get(phy->dev, "refclk"); + if (IS_ERR(phy->refclk)) + return PTR_ERR(phy->refclk); + error = clk_prepare(phy->refclk); + if (error) + return error; + + pm_runtime_enable(phy->dev); + generic_phy = devm_phy_create(phy->dev, NULL, &ops); + if (IS_ERR(generic_phy)) + return PTR_ERR(generic_phy); + + phy_set_drvdata(generic_phy, phy); + + phy_provider = devm_of_phy_provider_register(phy->dev, + of_phy_simple_xlate); + if (IS_ERR(phy_provider)) + return PTR_ERR(phy_provider); + + usb_add_phy_dev(&phy->phy); + + return 0; +} + +static int dm816x_usb_phy_remove(struct platform_device *pdev) +{ + struct dm816x_usb_phy *phy = platform_get_drvdata(pdev); + + usb_remove_phy(&phy->phy); + pm_runtime_disable(phy->dev); + clk_unprepare(phy->refclk); + + return 0; +} + +static struct platform_driver dm816x_usb_phy_driver = { + .probe = dm816x_usb_phy_probe, + .remove = dm816x_usb_phy_remove, + .driver = { + .name = "dm816x-usb-phy", + .pm = &dm816x_usb_phy_pm_ops, + .of_match_table = of_match_ptr(dm816x_usb_phy_id_table), + }, +}; + +module_platform_driver(dm816x_usb_phy_driver); + +MODULE_ALIAS("platform:dm816x_usb"); +MODULE_AUTHOR("Tony Lindgren "); +MODULE_DESCRIPTION("dm816x usb phy driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-59-g8ed1b From 9c3b443026368583d2df3373a11b1c18c361d9a6 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Sat, 14 Mar 2015 11:57:16 +0800 Subject: phy: Add driver to support individual USB PHYs on sun9i Unlike previous Allwinner SoCs, there is no central PHY control block on the A80. Also, OTG support is completely split off into a different controller. This adds a new driver to support the regular USB PHYs. Signed-off-by: Chen-Yu Tsai Acked-by: Maxime Ripard Signed-off-by: Kishon Vijay Abraham I --- .../devicetree/bindings/phy/sun9i-usb-phy.txt | 38 ++++ drivers/phy/Kconfig | 11 ++ drivers/phy/Makefile | 1 + drivers/phy/phy-sun9i-usb.c | 202 +++++++++++++++++++++ 4 files changed, 252 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/sun9i-usb-phy.txt create mode 100644 drivers/phy/phy-sun9i-usb.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/phy/sun9i-usb-phy.txt b/Documentation/devicetree/bindings/phy/sun9i-usb-phy.txt new file mode 100644 index 000000000000..1cca85c709d1 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/sun9i-usb-phy.txt @@ -0,0 +1,38 @@ +Allwinner sun9i USB PHY +----------------------- + +Required properties: +- compatible : should be one of + * allwinner,sun9i-a80-usb-phy +- reg : a list of offset + length pairs +- #phy-cells : from the generic phy bindings, must be 0 +- phy_type : "hsic" for HSIC usage; + other values or absence of this property indicates normal USB +- clocks : phandle + clock specifier for the phy clocks +- clock-names : depending on the "phy_type" property, + * "phy" for normal USB + * "hsic_480M", "hsic_12M" for HSIC +- resets : a list of phandle + reset specifier pairs +- reset-names : depending on the "phy_type" property, + * "phy" for normal USB + * "hsic" for HSIC + +Optional Properties: +- phy-supply : from the generic phy bindings, a phandle to a regulator that + provides power to VBUS. + +It is recommended to list all clocks and resets available. +The driver will only use those matching the phy_type. + +Example: + usbphy1: phy@00a01800 { + compatible = "allwinner,sun9i-a80-usb-phy"; + reg = <0x00a01800 0x4>; + clocks = <&usb_phy_clk 2>, <&usb_phy_clk 10>, + <&usb_phy_clk 3>; + clock-names = "hsic_480M", "hsic_12M", "phy"; + resets = <&usb_phy_clk 18>, <&usb_phy_clk 19>; + reset-names = "hsic", "phy"; + status = "disabled"; + #phy-cells = <0>; + }; diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 885c39c28a8b..a53bd5b52df9 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -181,6 +181,17 @@ config PHY_SUN4I_USB This driver controls the entire USB PHY block, both the USB OTG parts, as well as the 2 regular USB 2 host PHYs. +config PHY_SUN9I_USB + tristate "Allwinner sun9i SoC USB PHY driver" + depends on ARCH_SUNXI && HAS_IOMEM && OF + depends on RESET_CONTROLLER + select GENERIC_PHY + help + Enable this to support the transceiver that is part of Allwinner + sun9i SoCs. + + This driver controls each individual USB 2 host PHY. + config PHY_SAMSUNG_USB2 tristate "Samsung USB 2.0 PHY driver" depends on HAS_IOMEM diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index dab6665ad9c1..f12625178780 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_TWL4030_USB) += phy-twl4030-usb.o obj-$(CONFIG_PHY_EXYNOS5250_SATA) += phy-exynos5250-sata.o obj-$(CONFIG_PHY_HIX5HD2_SATA) += phy-hix5hd2-sata.o obj-$(CONFIG_PHY_SUN4I_USB) += phy-sun4i-usb.o +obj-$(CONFIG_PHY_SUN9I_USB) += phy-sun9i-usb.o obj-$(CONFIG_PHY_SAMSUNG_USB2) += phy-exynos-usb2.o phy-exynos-usb2-y += phy-samsung-usb2.o phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4210_USB2) += phy-exynos4210-usb2.o diff --git a/drivers/phy/phy-sun9i-usb.c b/drivers/phy/phy-sun9i-usb.c new file mode 100644 index 000000000000..0095914a662c --- /dev/null +++ b/drivers/phy/phy-sun9i-usb.c @@ -0,0 +1,202 @@ +/* + * Allwinner sun9i USB phy driver + * + * Copyright (C) 2014-2015 Chen-Yu Tsai + * + * Based on phy-sun4i-usb.c from + * Hans de Goede + * + * and code from + * Allwinner Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define SUNXI_AHB_INCR16_BURST_EN BIT(11) +#define SUNXI_AHB_INCR8_BURST_EN BIT(10) +#define SUNXI_AHB_INCR4_BURST_EN BIT(9) +#define SUNXI_AHB_INCRX_ALIGN_EN BIT(8) +#define SUNXI_ULPI_BYPASS_EN BIT(0) + +/* usb1 HSIC specific bits */ +#define SUNXI_EHCI_HS_FORCE BIT(20) +#define SUNXI_HSIC_CONNECT_DET BIT(17) +#define SUNXI_HSIC_CONNECT_INT BIT(16) +#define SUNXI_HSIC BIT(1) + +struct sun9i_usb_phy { + struct phy *phy; + void __iomem *pmu; + struct reset_control *reset; + struct clk *clk; + struct clk *hsic_clk; + enum usb_phy_interface type; +}; + +static void sun9i_usb_phy_passby(struct sun9i_usb_phy *phy, int enable) +{ + u32 bits, reg_value; + + bits = SUNXI_AHB_INCR16_BURST_EN | SUNXI_AHB_INCR8_BURST_EN | + SUNXI_AHB_INCR4_BURST_EN | SUNXI_AHB_INCRX_ALIGN_EN | + SUNXI_ULPI_BYPASS_EN; + + if (phy->type == USBPHY_INTERFACE_MODE_HSIC) + bits |= SUNXI_HSIC | SUNXI_EHCI_HS_FORCE | + SUNXI_HSIC_CONNECT_DET | SUNXI_HSIC_CONNECT_INT; + + reg_value = readl(phy->pmu); + + if (enable) + reg_value |= bits; + else + reg_value &= ~bits; + + writel(reg_value, phy->pmu); +} + +static int sun9i_usb_phy_init(struct phy *_phy) +{ + struct sun9i_usb_phy *phy = phy_get_drvdata(_phy); + int ret; + + ret = clk_prepare_enable(phy->clk); + if (ret) + goto err_clk; + + ret = clk_prepare_enable(phy->hsic_clk); + if (ret) + goto err_hsic_clk; + + ret = reset_control_deassert(phy->reset); + if (ret) + goto err_reset; + + sun9i_usb_phy_passby(phy, 1); + return 0; + +err_reset: + clk_disable_unprepare(phy->hsic_clk); + +err_hsic_clk: + clk_disable_unprepare(phy->clk); + +err_clk: + return ret; +} + +static int sun9i_usb_phy_exit(struct phy *_phy) +{ + struct sun9i_usb_phy *phy = phy_get_drvdata(_phy); + + sun9i_usb_phy_passby(phy, 0); + reset_control_assert(phy->reset); + clk_disable_unprepare(phy->hsic_clk); + clk_disable_unprepare(phy->clk); + + return 0; +} + +static struct phy_ops sun9i_usb_phy_ops = { + .init = sun9i_usb_phy_init, + .exit = sun9i_usb_phy_exit, + .owner = THIS_MODULE, +}; + +static int sun9i_usb_phy_probe(struct platform_device *pdev) +{ + struct sun9i_usb_phy *phy; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct phy_provider *phy_provider; + struct resource *res; + + phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); + if (!phy) + return -ENOMEM; + + phy->type = of_usb_get_phy_mode(np); + if (phy->type == USBPHY_INTERFACE_MODE_HSIC) { + phy->clk = devm_clk_get(dev, "hsic_480M"); + if (IS_ERR(phy->clk)) { + dev_err(dev, "failed to get hsic_480M clock\n"); + return PTR_ERR(phy->clk); + } + + phy->hsic_clk = devm_clk_get(dev, "hsic_12M"); + if (IS_ERR(phy->clk)) { + dev_err(dev, "failed to get hsic_12M clock\n"); + return PTR_ERR(phy->clk); + } + + phy->reset = devm_reset_control_get(dev, "hsic"); + if (IS_ERR(phy->reset)) { + dev_err(dev, "failed to get reset control\n"); + return PTR_ERR(phy->reset); + } + } else { + phy->clk = devm_clk_get(dev, "phy"); + if (IS_ERR(phy->clk)) { + dev_err(dev, "failed to get phy clock\n"); + return PTR_ERR(phy->clk); + } + + phy->reset = devm_reset_control_get(dev, "phy"); + if (IS_ERR(phy->reset)) { + dev_err(dev, "failed to get reset control\n"); + return PTR_ERR(phy->reset); + } + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + phy->pmu = devm_ioremap_resource(dev, res); + if (IS_ERR(phy->pmu)) + return PTR_ERR(phy->pmu); + + phy->phy = devm_phy_create(dev, NULL, &sun9i_usb_phy_ops); + if (IS_ERR(phy->phy)) { + dev_err(dev, "failed to create PHY\n"); + return PTR_ERR(phy->phy); + } + + phy_set_drvdata(phy->phy, phy); + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + + return PTR_ERR_OR_ZERO(phy_provider); +} + +static const struct of_device_id sun9i_usb_phy_of_match[] = { + { .compatible = "allwinner,sun9i-a80-usb-phy" }, + { }, +}; +MODULE_DEVICE_TABLE(of, sun9i_usb_phy_of_match); + +static struct platform_driver sun9i_usb_phy_driver = { + .probe = sun9i_usb_phy_probe, + .driver = { + .of_match_table = sun9i_usb_phy_of_match, + .name = "sun9i-usb-phy", + } +}; +module_platform_driver(sun9i_usb_phy_driver); + +MODULE_DESCRIPTION("Allwinner sun9i USB phy driver"); +MODULE_AUTHOR("Chen-Yu Tsai "); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-59-g8ed1b From fbea230e7884044ee2e84bb28f6879dc30e1db24 Mon Sep 17 00:00:00 2001 From: Peter Griffin Date: Mon, 30 Mar 2015 16:17:07 +0100 Subject: phy: miphy365x: Use the generic phy type constants in dt-bindings/phy/phy.h Now there are generic phy type constants declared in phy.h, migrate over to using them rather than defining our own. This change has been done as one atomic commit to be bisectable. Note: The values of the defines are the same, so there is no ABI breakage with this patch. Signed-off-by: Peter Griffin Acked-by: Rob Herring Acked-by: Lee Jones Acked-by: Maxime Coquelin Signed-off-by: Kishon Vijay Abraham I --- Documentation/devicetree/bindings/phy/phy-miphy365x.txt | 8 ++++---- arch/arm/boot/dts/stih416.dtsi | 4 ++-- drivers/phy/phy-miphy365x.c | 14 +++++++------- include/dt-bindings/phy/phy-miphy365x.h | 14 -------------- 4 files changed, 13 insertions(+), 27 deletions(-) delete mode 100644 include/dt-bindings/phy/phy-miphy365x.h (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/phy/phy-miphy365x.txt b/Documentation/devicetree/bindings/phy/phy-miphy365x.txt index 9802d5d911aa..8772900e056a 100644 --- a/Documentation/devicetree/bindings/phy/phy-miphy365x.txt +++ b/Documentation/devicetree/bindings/phy/phy-miphy365x.txt @@ -20,8 +20,8 @@ Required nodes : A sub-node is required for each channel the controller Required properties (port (child) node): - #phy-cells : Should be 1 (See second example) Cell after port phandle is device type from: - - MIPHY_TYPE_SATA - - MIPHY_TYPE_PCI + - PHY_TYPE_SATA + - PHY_TYPE_PCI - reg : Address and length of register sets for each device in "reg-names" - reg-names : The names of the register addresses corresponding to the @@ -68,10 +68,10 @@ property, containing a phandle to the phy port node and a device type. Example: -#include +#include sata0: sata@fe380000 { ... - phys = <&phy_port0 MIPHY_TYPE_SATA>; + phys = <&phy_port0 PHY_TYPE_SATA>; ... }; diff --git a/arch/arm/boot/dts/stih416.dtsi b/arch/arm/boot/dts/stih416.dtsi index ea28ebadab1a..eeb7afecbbe6 100644 --- a/arch/arm/boot/dts/stih416.dtsi +++ b/arch/arm/boot/dts/stih416.dtsi @@ -10,7 +10,7 @@ #include "stih416-clock.dtsi" #include "stih416-pinctrl.dtsi" -#include +#include #include #include / { @@ -306,7 +306,7 @@ reg = <0xfe380000 0x1000>; interrupts = ; interrupt-names = "hostc"; - phys = <&phy_port0 MIPHY_TYPE_SATA>; + phys = <&phy_port0 PHY_TYPE_SATA>; phy-names = "sata-phy"; resets = <&powerdown STIH416_SATA0_POWERDOWN>, <&softreset STIH416_SATA0_SOFTRESET>; diff --git a/drivers/phy/phy-miphy365x.c b/drivers/phy/phy-miphy365x.c index 6c80154e8bff..98bffbc0f74d 100644 --- a/drivers/phy/phy-miphy365x.c +++ b/drivers/phy/phy-miphy365x.c @@ -25,7 +25,7 @@ #include #include -#include +#include #define HFC_TIMEOUT 100 @@ -176,7 +176,7 @@ static u8 rx_tx_spd[] = { static int miphy365x_set_path(struct miphy365x_phy *miphy_phy, struct miphy365x_dev *miphy_dev) { - bool sata = (miphy_phy->type == MIPHY_TYPE_SATA); + bool sata = (miphy_phy->type == PHY_TYPE_SATA); return regmap_update_bits(miphy_dev->regmap, miphy_phy->ctrlreg, @@ -430,7 +430,7 @@ static int miphy365x_init(struct phy *phy) } /* Initialise Miphy for PCIe or SATA */ - if (miphy_phy->type == MIPHY_TYPE_PCIE) + if (miphy_phy->type == PHY_TYPE_PCIE) ret = miphy365x_init_pcie_port(miphy_phy, miphy_dev); else ret = miphy365x_init_sata_port(miphy_phy, miphy_dev); @@ -454,8 +454,8 @@ int miphy365x_get_addr(struct device *dev, struct miphy365x_phy *miphy_phy, return ret; } - if (!((!strncmp(name, "sata", 4) && type == MIPHY_TYPE_SATA) || - (!strncmp(name, "pcie", 4) && type == MIPHY_TYPE_PCIE))) + if (!((!strncmp(name, "sata", 4) && type == PHY_TYPE_SATA) || + (!strncmp(name, "pcie", 4) && type == PHY_TYPE_PCIE))) return 0; miphy_phy->base = of_iomap(phynode, index); @@ -498,8 +498,8 @@ static struct phy *miphy365x_xlate(struct device *dev, miphy_phy->type = args->args[0]; - if (!(miphy_phy->type == MIPHY_TYPE_SATA || - miphy_phy->type == MIPHY_TYPE_PCIE)) { + if (!(miphy_phy->type == PHY_TYPE_SATA || + miphy_phy->type == PHY_TYPE_PCIE)) { dev_err(dev, "Unsupported device type: %d\n", miphy_phy->type); return ERR_PTR(-EINVAL); } diff --git a/include/dt-bindings/phy/phy-miphy365x.h b/include/dt-bindings/phy/phy-miphy365x.h deleted file mode 100644 index 8ef8aba6edd6..000000000000 --- a/include/dt-bindings/phy/phy-miphy365x.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * This header provides constants for the phy framework - * based on the STMicroelectronics MiPHY365x. - * - * Author: Lee Jones - */ -#ifndef _DT_BINDINGS_PHY_MIPHY -#define _DT_BINDINGS_PHY_MIPHY - -#define MIPHY_TYPE_SATA 1 -#define MIPHY_TYPE_PCIE 2 -#define MIPHY_TYPE_USB 3 - -#endif /* _DT_BINDINGS_PHY_MIPHY */ -- cgit v1.2.3-59-g8ed1b From 78cac48c0434c82e860fade3cd0420a7a4adbb08 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Wed, 1 Apr 2015 12:49:52 +0200 Subject: x86/mm/KASLR: Propagate KASLR status to kernel proper Commit: e2b32e678513 ("x86, kaslr: randomize module base load address") made module base address randomization unconditional and didn't regard disabled KKASLR due to CONFIG_HIBERNATION and command line option "nokaslr". For more info see (now reverted) commit: f47233c2d34f ("x86/mm/ASLR: Propagate base load address calculation") In order to propagate KASLR status to kernel proper, we need a single bit in boot_params.hdr.loadflags and we've chosen bit 1 thus leaving the top-down allocated bits for bits supposed to be used by the bootloader. Originally-From: Jiri Kosina Suggested-by: H. Peter Anvin Signed-off-by: Borislav Petkov Cc: Kees Cook Signed-off-by: Ingo Molnar --- Documentation/x86/boot.txt | 6 ++++++ arch/x86/boot/compressed/aslr.c | 5 ++++- arch/x86/boot/compressed/misc.c | 5 ++++- arch/x86/boot/compressed/misc.h | 6 ++++-- arch/x86/include/asm/setup.h | 5 +++++ arch/x86/include/uapi/asm/bootparam.h | 1 + arch/x86/kernel/module.c | 11 ++--------- arch/x86/kernel/setup.c | 13 +++++++++---- 8 files changed, 35 insertions(+), 17 deletions(-) (limited to 'Documentation') diff --git a/Documentation/x86/boot.txt b/Documentation/x86/boot.txt index a75e3adaa39d..88b85899d309 100644 --- a/Documentation/x86/boot.txt +++ b/Documentation/x86/boot.txt @@ -406,6 +406,12 @@ Protocol: 2.00+ - If 0, the protected-mode code is loaded at 0x10000. - If 1, the protected-mode code is loaded at 0x100000. + Bit 1 (kernel internal): ALSR_FLAG + - Used internally by the compressed kernel to communicate + KASLR status to kernel proper. + If 1, KASLR enabled. + If 0, KASLR disabled. + Bit 5 (write): QUIET_FLAG - If 0, print early messages. - If 1, suppress early messages. diff --git a/arch/x86/boot/compressed/aslr.c b/arch/x86/boot/compressed/aslr.c index bb1376381985..d7b1f655b3ef 100644 --- a/arch/x86/boot/compressed/aslr.c +++ b/arch/x86/boot/compressed/aslr.c @@ -295,7 +295,8 @@ static unsigned long find_random_addr(unsigned long minimum, return slots_fetch_random(); } -unsigned char *choose_kernel_location(unsigned char *input, +unsigned char *choose_kernel_location(struct boot_params *boot_params, + unsigned char *input, unsigned long input_size, unsigned char *output, unsigned long output_size) @@ -315,6 +316,8 @@ unsigned char *choose_kernel_location(unsigned char *input, } #endif + boot_params->hdr.loadflags |= KASLR_FLAG; + /* Record the various known unsafe memory ranges. */ mem_avoid_init((unsigned long)input, input_size, (unsigned long)output, output_size); diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c index a950864a64da..a107b935e22f 100644 --- a/arch/x86/boot/compressed/misc.c +++ b/arch/x86/boot/compressed/misc.c @@ -377,6 +377,9 @@ asmlinkage __visible void *decompress_kernel(void *rmode, memptr heap, real_mode = rmode; + /* Clear it for solely in-kernel use */ + real_mode->hdr.loadflags &= ~KASLR_FLAG; + sanitize_boot_params(real_mode); if (real_mode->screen_info.orig_video_mode == 7) { @@ -401,7 +404,7 @@ asmlinkage __visible void *decompress_kernel(void *rmode, memptr heap, * the entire decompressed kernel plus relocation table, or the * entire decompressed kernel plus .bss and .brk sections. */ - output = choose_kernel_location(input_data, input_len, output, + output = choose_kernel_location(real_mode, input_data, input_len, output, output_len > run_size ? output_len : run_size); diff --git a/arch/x86/boot/compressed/misc.h b/arch/x86/boot/compressed/misc.h index 04477d68403f..89dd0d78013a 100644 --- a/arch/x86/boot/compressed/misc.h +++ b/arch/x86/boot/compressed/misc.h @@ -57,7 +57,8 @@ int cmdline_find_option_bool(const char *option); #if CONFIG_RANDOMIZE_BASE /* aslr.c */ -unsigned char *choose_kernel_location(unsigned char *input, +unsigned char *choose_kernel_location(struct boot_params *boot_params, + unsigned char *input, unsigned long input_size, unsigned char *output, unsigned long output_size); @@ -65,7 +66,8 @@ unsigned char *choose_kernel_location(unsigned char *input, bool has_cpuflag(int flag); #else static inline -unsigned char *choose_kernel_location(unsigned char *input, +unsigned char *choose_kernel_location(struct boot_params *boot_params, + unsigned char *input, unsigned long input_size, unsigned char *output, unsigned long output_size) diff --git a/arch/x86/include/asm/setup.h b/arch/x86/include/asm/setup.h index ff4e7b236e21..f69e06b283fb 100644 --- a/arch/x86/include/asm/setup.h +++ b/arch/x86/include/asm/setup.h @@ -66,6 +66,11 @@ static inline void x86_ce4100_early_setup(void) { } */ extern struct boot_params boot_params; +static inline bool kaslr_enabled(void) +{ + return !!(boot_params.hdr.loadflags & KASLR_FLAG); +} + /* * Do NOT EVER look at the BIOS memory size location. * It does not work on many machines. diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h index 225b0988043a..ab456dc233b5 100644 --- a/arch/x86/include/uapi/asm/bootparam.h +++ b/arch/x86/include/uapi/asm/bootparam.h @@ -15,6 +15,7 @@ /* loadflags */ #define LOADED_HIGH (1<<0) +#define KASLR_FLAG (1<<1) #define QUIET_FLAG (1<<5) #define KEEP_SEGMENTS (1<<6) #define CAN_USE_HEAP (1<<7) diff --git a/arch/x86/kernel/module.c b/arch/x86/kernel/module.c index d1ac80b72c72..005c03e93fc5 100644 --- a/arch/x86/kernel/module.c +++ b/arch/x86/kernel/module.c @@ -33,6 +33,7 @@ #include #include +#include #if 0 #define DEBUGP(fmt, ...) \ @@ -47,21 +48,13 @@ do { \ #ifdef CONFIG_RANDOMIZE_BASE static unsigned long module_load_offset; -static int randomize_modules = 1; /* Mutex protects the module_load_offset. */ static DEFINE_MUTEX(module_kaslr_mutex); -static int __init parse_nokaslr(char *p) -{ - randomize_modules = 0; - return 0; -} -early_param("nokaslr", parse_nokaslr); - static unsigned long int get_module_load_offset(void) { - if (randomize_modules) { + if (kaslr_enabled()) { mutex_lock(&module_kaslr_mutex); /* * Calculate the module_load_offset the first time this diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 0a2421cca01f..014466b152b5 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -832,10 +832,15 @@ static void __init trim_low_memory_range(void) static int dump_kernel_offset(struct notifier_block *self, unsigned long v, void *p) { - pr_emerg("Kernel Offset: 0x%lx from 0x%lx " - "(relocation range: 0x%lx-0x%lx)\n", - (unsigned long)&_text - __START_KERNEL, __START_KERNEL, - __START_KERNEL_map, MODULES_VADDR-1); + if (kaslr_enabled()) { + pr_emerg("Kernel Offset: 0x%lx from 0x%lx (relocation range: 0x%lx-0x%lx)\n", + (unsigned long)&_text - __START_KERNEL, + __START_KERNEL, + __START_KERNEL_map, + MODULES_VADDR-1); + } else { + pr_emerg("Kernel Offset: disabled\n"); + } return 0; } -- cgit v1.2.3-59-g8ed1b From ba92222ed63a12d09120df9b92f56cc990abac19 Mon Sep 17 00:00:00 2001 From: Zubair Lutfullah Kakakhel Date: Tue, 31 Mar 2015 14:03:55 +0100 Subject: i2c: jz4780: Add i2c bus controller driver for Ingenic JZ4780 Adds the i2c bus controller driver for the Ingenic JZ4780 SoC. Signed-off-by: Zubair Lutfullah Kakakhel Signed-off-by: Wolfram Sang --- .../devicetree/bindings/i2c/i2c-jz4780.txt | 35 + drivers/i2c/busses/Kconfig | 9 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-jz4780.c | 832 +++++++++++++++++++++ 4 files changed, 877 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/i2c-jz4780.txt create mode 100644 drivers/i2c/busses/i2c-jz4780.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/i2c/i2c-jz4780.txt b/Documentation/devicetree/bindings/i2c/i2c-jz4780.txt new file mode 100644 index 000000000000..231e4cc4008c --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-jz4780.txt @@ -0,0 +1,35 @@ +* Ingenic JZ4780 I2C Bus controller + +Required properties: +- compatible: should be "ingenic,jz4780-i2c" +- reg: Should contain the address & size of the I2C controller registers. +- interrupts: Should specify the interrupt provided by parent. +- clocks: Should contain a single clock specifier for the JZ4780 I2C clock. +- clock-frequency: desired I2C bus clock frequency in Hz. + +Recommended properties: +- pinctrl-names: should be "default"; +- pinctrl-0: phandle to pinctrl function + +Optional properties: +- interrupt-parent: Should be the phandle of the interrupt controller that + delivers interrupts to the I2C block. + +Example + +/ { + i2c4: i2c4@0x10054000 { + compatible = "ingenic,jz4780-i2c"; + reg = <0x10054000 0x1000>; + + interrupt-parent = <&intc>; + interrupts = <56>; + + clocks = <&cgu JZ4780_CLK_SMB4>; + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pins_i2c4_data>; + + }; +}; + diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index db09881614b7..0b0ca7dd5d1f 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -583,6 +583,15 @@ config I2C_IOP3XX This driver can also be built as a module. If so, the module will be called i2c-iop3xx. +config I2C_JZ4780 + tristate "JZ4780 I2C controller interface support" + depends on MACH_JZ4780 || COMPILE_TEST + help + If you say yes to this option, support will be included for the + Ingenic JZ4780 I2C controller. + + If you don't know what to do here, say N. + config I2C_KEMPLD tristate "Kontron COM I2C Controller" depends on MFD_KEMPLD diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 4413f09996cb..ab6a0a67aca1 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -56,6 +56,7 @@ obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o obj-$(CONFIG_I2C_IMG) += i2c-img-scb.o obj-$(CONFIG_I2C_IMX) += i2c-imx.o obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o +obj-$(CONFIG_I2C_JZ4780) += i2c-jz4780.o obj-$(CONFIG_I2C_KEMPLD) += i2c-kempld.o obj-$(CONFIG_I2C_MESON) += i2c-meson.o obj-$(CONFIG_I2C_MPC) += i2c-mpc.o diff --git a/drivers/i2c/busses/i2c-jz4780.c b/drivers/i2c/busses/i2c-jz4780.c new file mode 100644 index 000000000000..ce1d69324169 --- /dev/null +++ b/drivers/i2c/busses/i2c-jz4780.c @@ -0,0 +1,832 @@ +/* + * Ingenic JZ4780 I2C bus driver + * + * Copyright (C) 2006 - 2009 Ingenic Semiconductor Inc. + * Copyright (C) 2015 Imagination Technologies + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define JZ4780_I2C_CTRL 0x00 +#define JZ4780_I2C_TAR 0x04 +#define JZ4780_I2C_SAR 0x08 +#define JZ4780_I2C_DC 0x10 +#define JZ4780_I2C_SHCNT 0x14 +#define JZ4780_I2C_SLCNT 0x18 +#define JZ4780_I2C_FHCNT 0x1C +#define JZ4780_I2C_FLCNT 0x20 +#define JZ4780_I2C_INTST 0x2C +#define JZ4780_I2C_INTM 0x30 +#define JZ4780_I2C_RXTL 0x38 +#define JZ4780_I2C_TXTL 0x3C +#define JZ4780_I2C_CINTR 0x40 +#define JZ4780_I2C_CRXUF 0x44 +#define JZ4780_I2C_CRXOF 0x48 +#define JZ4780_I2C_CTXOF 0x4C +#define JZ4780_I2C_CRXREQ 0x50 +#define JZ4780_I2C_CTXABRT 0x54 +#define JZ4780_I2C_CRXDONE 0x58 +#define JZ4780_I2C_CACT 0x5C +#define JZ4780_I2C_CSTP 0x60 +#define JZ4780_I2C_CSTT 0x64 +#define JZ4780_I2C_CGC 0x68 +#define JZ4780_I2C_ENB 0x6C +#define JZ4780_I2C_STA 0x70 +#define JZ4780_I2C_TXABRT 0x80 +#define JZ4780_I2C_DMACR 0x88 +#define JZ4780_I2C_DMATDLR 0x8C +#define JZ4780_I2C_DMARDLR 0x90 +#define JZ4780_I2C_SDASU 0x94 +#define JZ4780_I2C_ACKGC 0x98 +#define JZ4780_I2C_ENSTA 0x9C +#define JZ4780_I2C_SDAHD 0xD0 + +#define JZ4780_I2C_CTRL_STPHLD BIT(7) +#define JZ4780_I2C_CTRL_SLVDIS BIT(6) +#define JZ4780_I2C_CTRL_REST BIT(5) +#define JZ4780_I2C_CTRL_MATP BIT(4) +#define JZ4780_I2C_CTRL_SATP BIT(3) +#define JZ4780_I2C_CTRL_SPDF BIT(2) +#define JZ4780_I2C_CTRL_SPDS BIT(1) +#define JZ4780_I2C_CTRL_MD BIT(0) + +#define JZ4780_I2C_STA_SLVACT BIT(6) +#define JZ4780_I2C_STA_MSTACT BIT(5) +#define JZ4780_I2C_STA_RFF BIT(4) +#define JZ4780_I2C_STA_RFNE BIT(3) +#define JZ4780_I2C_STA_TFE BIT(2) +#define JZ4780_I2C_STA_TFNF BIT(1) +#define JZ4780_I2C_STA_ACT BIT(0) + +static const char * const jz4780_i2c_abrt_src[] = { + "ABRT_7B_ADDR_NOACK", + "ABRT_10ADDR1_NOACK", + "ABRT_10ADDR2_NOACK", + "ABRT_XDATA_NOACK", + "ABRT_GCALL_NOACK", + "ABRT_GCALL_READ", + "ABRT_HS_ACKD", + "SBYTE_ACKDET", + "ABRT_HS_NORSTRT", + "SBYTE_NORSTRT", + "ABRT_10B_RD_NORSTRT", + "ABRT_MASTER_DIS", + "ARB_LOST", + "SLVFLUSH_TXFIFO", + "SLV_ARBLOST", + "SLVRD_INTX", +}; + +#define JZ4780_I2C_INTST_IGC BIT(11) +#define JZ4780_I2C_INTST_ISTT BIT(10) +#define JZ4780_I2C_INTST_ISTP BIT(9) +#define JZ4780_I2C_INTST_IACT BIT(8) +#define JZ4780_I2C_INTST_RXDN BIT(7) +#define JZ4780_I2C_INTST_TXABT BIT(6) +#define JZ4780_I2C_INTST_RDREQ BIT(5) +#define JZ4780_I2C_INTST_TXEMP BIT(4) +#define JZ4780_I2C_INTST_TXOF BIT(3) +#define JZ4780_I2C_INTST_RXFL BIT(2) +#define JZ4780_I2C_INTST_RXOF BIT(1) +#define JZ4780_I2C_INTST_RXUF BIT(0) + +#define JZ4780_I2C_INTM_MIGC BIT(11) +#define JZ4780_I2C_INTM_MISTT BIT(10) +#define JZ4780_I2C_INTM_MISTP BIT(9) +#define JZ4780_I2C_INTM_MIACT BIT(8) +#define JZ4780_I2C_INTM_MRXDN BIT(7) +#define JZ4780_I2C_INTM_MTXABT BIT(6) +#define JZ4780_I2C_INTM_MRDREQ BIT(5) +#define JZ4780_I2C_INTM_MTXEMP BIT(4) +#define JZ4780_I2C_INTM_MTXOF BIT(3) +#define JZ4780_I2C_INTM_MRXFL BIT(2) +#define JZ4780_I2C_INTM_MRXOF BIT(1) +#define JZ4780_I2C_INTM_MRXUF BIT(0) + +#define JZ4780_I2C_DC_READ BIT(8) + +#define JZ4780_I2C_SDAHD_HDENB BIT(8) + +#define JZ4780_I2C_ENB_I2C BIT(0) + +#define JZ4780_I2CSHCNT_ADJUST(n) (((n) - 8) < 6 ? 6 : ((n) - 8)) +#define JZ4780_I2CSLCNT_ADJUST(n) (((n) - 1) < 8 ? 8 : ((n) - 1)) +#define JZ4780_I2CFHCNT_ADJUST(n) (((n) - 8) < 6 ? 6 : ((n) - 8)) +#define JZ4780_I2CFLCNT_ADJUST(n) (((n) - 1) < 8 ? 8 : ((n) - 1)) + +#define JZ4780_I2C_FIFO_LEN 16 +#define TX_LEVEL 3 +#define RX_LEVEL (JZ4780_I2C_FIFO_LEN - TX_LEVEL - 1) + +#define JZ4780_I2C_TIMEOUT 300 + +#define BUFSIZE 200 + +struct jz4780_i2c { + void __iomem *iomem; + int irq; + struct clk *clk; + struct i2c_adapter adap; + + /* lock to protect rbuf and wbuf between xfer_rd/wr and irq handler */ + spinlock_t lock; + + /* beginning of lock scope */ + unsigned char *rbuf; + int rd_total_len; + int rd_data_xfered; + int rd_cmd_xfered; + + unsigned char *wbuf; + int wt_len; + + int is_write; + int stop_hold; + int speed; + + int data_buf[BUFSIZE]; + int cmd_buf[BUFSIZE]; + int cmd; + + /* end of lock scope */ + struct completion trans_waitq; +}; + +static inline unsigned short jz4780_i2c_readw(struct jz4780_i2c *i2c, + unsigned long offset) +{ + return readw(i2c->iomem + offset); +} + +static inline void jz4780_i2c_writew(struct jz4780_i2c *i2c, + unsigned long offset, unsigned short val) +{ + writew(val, i2c->iomem + offset); +} + +static int jz4780_i2c_disable(struct jz4780_i2c *i2c) +{ + unsigned short regval; + unsigned long loops = 5; + + jz4780_i2c_writew(i2c, JZ4780_I2C_ENB, 0); + + do { + regval = jz4780_i2c_readw(i2c, JZ4780_I2C_ENSTA); + if (!(regval & JZ4780_I2C_ENB_I2C)) + return 0; + + usleep_range(5000, 15000); + } while (--loops); + + dev_err(&i2c->adap.dev, "disable failed: ENSTA=0x%04x\n", regval); + return -ETIMEDOUT; +} + +static int jz4780_i2c_enable(struct jz4780_i2c *i2c) +{ + unsigned short regval; + unsigned long loops = 5; + + jz4780_i2c_writew(i2c, JZ4780_I2C_ENB, 1); + + do { + regval = jz4780_i2c_readw(i2c, JZ4780_I2C_ENSTA); + if (regval & JZ4780_I2C_ENB_I2C) + return 0; + + usleep_range(5000, 15000); + } while (--loops); + + dev_err(&i2c->adap.dev, "enable failed: ENSTA=0x%04x\n", regval); + return -ETIMEDOUT; +} + +static int jz4780_i2c_set_target(struct jz4780_i2c *i2c, unsigned char address) +{ + unsigned short regval; + unsigned long loops = 5; + + do { + regval = jz4780_i2c_readw(i2c, JZ4780_I2C_STA); + if ((regval & JZ4780_I2C_STA_TFE) && + !(regval & JZ4780_I2C_STA_MSTACT)) + break; + + usleep_range(5000, 15000); + } while (--loops); + + if (loops) { + jz4780_i2c_writew(i2c, JZ4780_I2C_TAR, address); + return 0; + } + + dev_err(&i2c->adap.dev, + "set device to address 0x%02x failed, STA=0x%04x\n", + address, regval); + + return -ENXIO; +} + +static int jz4780_i2c_set_speed(struct jz4780_i2c *i2c) +{ + int dev_clk_khz = clk_get_rate(i2c->clk) / 1000; + int cnt_high = 0; /* HIGH period count of the SCL clock */ + int cnt_low = 0; /* LOW period count of the SCL clock */ + int cnt_period = 0; /* period count of the SCL clock */ + int setup_time = 0; + int hold_time = 0; + unsigned short tmp = 0; + int i2c_clk = i2c->speed; + + if (jz4780_i2c_disable(i2c)) + dev_dbg(&i2c->adap.dev, "i2c not disabled\n"); + + /* + * 1 JZ4780_I2C cycle equals to cnt_period PCLK(i2c_clk) + * standard mode, min LOW and HIGH period are 4700 ns and 4000 ns + * fast mode, min LOW and HIGH period are 1300 ns and 600 ns + */ + cnt_period = dev_clk_khz / i2c_clk; + + if (i2c_clk <= 100) + cnt_high = (cnt_period * 4000) / (4700 + 4000); + else + cnt_high = (cnt_period * 600) / (1300 + 600); + + cnt_low = cnt_period - cnt_high; + + /* + * NOTE: JZ4780_I2C_CTRL_REST can't set when i2c enabled, because + * normal read are 2 messages, we cannot disable i2c controller + * between these two messages, this means that we must always set + * JZ4780_I2C_CTRL_REST when init JZ4780_I2C_CTRL + * + */ + if (i2c_clk <= 100) { + tmp = JZ4780_I2C_CTRL_SPDS | JZ4780_I2C_CTRL_REST + | JZ4780_I2C_CTRL_SLVDIS | JZ4780_I2C_CTRL_MD; + jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp); + + jz4780_i2c_writew(i2c, JZ4780_I2C_SHCNT, + JZ4780_I2CSHCNT_ADJUST(cnt_high)); + jz4780_i2c_writew(i2c, JZ4780_I2C_SLCNT, + JZ4780_I2CSLCNT_ADJUST(cnt_low)); + } else { + tmp = JZ4780_I2C_CTRL_SPDF | JZ4780_I2C_CTRL_REST + | JZ4780_I2C_CTRL_SLVDIS | JZ4780_I2C_CTRL_MD; + jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp); + + jz4780_i2c_writew(i2c, JZ4780_I2C_FHCNT, + JZ4780_I2CFHCNT_ADJUST(cnt_high)); + jz4780_i2c_writew(i2c, JZ4780_I2C_FLCNT, + JZ4780_I2CFLCNT_ADJUST(cnt_low)); + } + + /* + * a i2c device must internally provide a hold time at least 300ns + * tHD:DAT + * Standard Mode: min=300ns, max=3450ns + * Fast Mode: min=0ns, max=900ns + * tSU:DAT + * Standard Mode: min=250ns, max=infinite + * Fast Mode: min=100(250ns is recommended), max=infinite + * + * 1i2c_clk = 10^6 / dev_clk_khz + * on FPGA, dev_clk_khz = 12000, so 1i2c_clk = 1000/12 = 83ns + * on Pisces(1008M), dev_clk_khz=126000, so 1i2c_clk = 1000 / 126 = 8ns + * + * The actual hold time is (SDAHD + 1) * (i2c_clk period). + * + * Length of setup time calculated using (SDASU - 1) * (ic_clk_period) + * + */ + if (i2c_clk <= 100) { /* standard mode */ + setup_time = 300; + hold_time = 400; + } else { + setup_time = 450; + hold_time = 450; + } + + hold_time = ((hold_time * dev_clk_khz) / 1000000) - 1; + setup_time = ((setup_time * dev_clk_khz) / 1000000) + 1; + + if (setup_time > 255) + setup_time = 255; + + if (setup_time <= 0) + setup_time = 1; + + jz4780_i2c_writew(i2c, JZ4780_I2C_SDASU, setup_time); + + if (hold_time > 255) + hold_time = 255; + + if (hold_time >= 0) { + /*i2c hold time enable */ + hold_time |= JZ4780_I2C_SDAHD_HDENB; + jz4780_i2c_writew(i2c, JZ4780_I2C_SDAHD, hold_time); + } else { + /* disable hold time */ + jz4780_i2c_writew(i2c, JZ4780_I2C_SDAHD, 0); + } + + return 0; +} + +static int jz4780_i2c_cleanup(struct jz4780_i2c *i2c) +{ + int ret; + unsigned long flags; + unsigned short tmp; + + spin_lock_irqsave(&i2c->lock, flags); + + /* can send stop now if need */ + tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL); + tmp &= ~JZ4780_I2C_CTRL_STPHLD; + jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp); + + /* disable all interrupts first */ + jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, 0); + + /* then clear all interrupts */ + jz4780_i2c_readw(i2c, JZ4780_I2C_CTXABRT); + jz4780_i2c_readw(i2c, JZ4780_I2C_CINTR); + + /* then disable the controller */ + tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL); + tmp &= ~JZ4780_I2C_ENB_I2C; + jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp); + udelay(10); + tmp |= JZ4780_I2C_ENB_I2C; + jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp); + + spin_unlock_irqrestore(&i2c->lock, flags); + + ret = jz4780_i2c_disable(i2c); + if (ret) + dev_err(&i2c->adap.dev, + "unable to disable device during cleanup!\n"); + + if (unlikely(jz4780_i2c_readw(i2c, JZ4780_I2C_INTM) + & jz4780_i2c_readw(i2c, JZ4780_I2C_INTST))) + dev_err(&i2c->adap.dev, + "device has interrupts after a complete cleanup!\n"); + + return ret; +} + +static int jz4780_i2c_prepare(struct jz4780_i2c *i2c) +{ + jz4780_i2c_set_speed(i2c); + return jz4780_i2c_enable(i2c); +} + +static void jz4780_i2c_send_rcmd(struct jz4780_i2c *i2c, int cmd_count) +{ + int i; + + for (i = 0; i < cmd_count; i++) + jz4780_i2c_writew(i2c, JZ4780_I2C_DC, JZ4780_I2C_DC_READ); +} + +static void jz4780_i2c_trans_done(struct jz4780_i2c *i2c) +{ + jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, 0); + complete(&i2c->trans_waitq); +} + +static irqreturn_t jz4780_i2c_irq(int irqno, void *dev_id) +{ + unsigned short tmp; + unsigned short intst; + unsigned short intmsk; + struct jz4780_i2c *i2c = dev_id; + unsigned long flags; + + spin_lock_irqsave(&i2c->lock, flags); + intmsk = jz4780_i2c_readw(i2c, JZ4780_I2C_INTM); + intst = jz4780_i2c_readw(i2c, JZ4780_I2C_INTST); + + intst &= intmsk; + + if (intst & JZ4780_I2C_INTST_TXABT) { + jz4780_i2c_trans_done(i2c); + goto done; + } + + if (intst & JZ4780_I2C_INTST_RXOF) { + dev_dbg(&i2c->adap.dev, "received fifo overflow!\n"); + jz4780_i2c_trans_done(i2c); + goto done; + } + + /* + * When reading, always drain RX FIFO before we send more Read + * Commands to avoid fifo overrun + */ + if (i2c->is_write == 0) { + int rd_left; + + while ((jz4780_i2c_readw(i2c, JZ4780_I2C_STA) + & JZ4780_I2C_STA_RFNE)) { + *(i2c->rbuf++) = jz4780_i2c_readw(i2c, JZ4780_I2C_DC) + & 0xff; + i2c->rd_data_xfered++; + if (i2c->rd_data_xfered == i2c->rd_total_len) { + jz4780_i2c_trans_done(i2c); + goto done; + } + } + + rd_left = i2c->rd_total_len - i2c->rd_data_xfered; + + if (rd_left <= JZ4780_I2C_FIFO_LEN) + jz4780_i2c_writew(i2c, JZ4780_I2C_RXTL, rd_left - 1); + } + + if (intst & JZ4780_I2C_INTST_TXEMP) { + if (i2c->is_write == 0) { + int cmd_left = i2c->rd_total_len - i2c->rd_cmd_xfered; + int max_send = (JZ4780_I2C_FIFO_LEN - 1) + - (i2c->rd_cmd_xfered + - i2c->rd_data_xfered); + int cmd_to_send = min(cmd_left, max_send); + + if (i2c->rd_cmd_xfered != 0) + cmd_to_send = min(cmd_to_send, + JZ4780_I2C_FIFO_LEN + - TX_LEVEL - 1); + + if (cmd_to_send) { + jz4780_i2c_send_rcmd(i2c, cmd_to_send); + i2c->rd_cmd_xfered += cmd_to_send; + } + + cmd_left = i2c->rd_total_len - i2c->rd_cmd_xfered; + if (cmd_left == 0) { + intmsk = jz4780_i2c_readw(i2c, JZ4780_I2C_INTM); + intmsk &= ~JZ4780_I2C_INTM_MTXEMP; + jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, intmsk); + + tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL); + tmp &= ~JZ4780_I2C_CTRL_STPHLD; + jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp); + } + } else { + unsigned short data; + unsigned short i2c_sta; + + i2c_sta = jz4780_i2c_readw(i2c, JZ4780_I2C_STA); + + while ((i2c_sta & JZ4780_I2C_STA_TFNF) && + (i2c->wt_len > 0)) { + i2c_sta = jz4780_i2c_readw(i2c, JZ4780_I2C_STA); + data = *i2c->wbuf; + data &= ~JZ4780_I2C_DC_READ; + jz4780_i2c_writew(i2c, JZ4780_I2C_DC, + data); + i2c->wbuf++; + i2c->wt_len--; + } + + if (i2c->wt_len == 0) { + if (!i2c->stop_hold) { + tmp = jz4780_i2c_readw(i2c, + JZ4780_I2C_CTRL); + tmp &= ~JZ4780_I2C_CTRL_STPHLD; + jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, + tmp); + } + + jz4780_i2c_trans_done(i2c); + goto done; + } + } + } + +done: + spin_unlock_irqrestore(&i2c->lock, flags); + return IRQ_HANDLED; +} + +static void jz4780_i2c_txabrt(struct jz4780_i2c *i2c, int src) +{ + int i; + + dev_err(&i2c->adap.dev, "txabrt: 0x%08x\n", src); + dev_err(&i2c->adap.dev, "device addr=%x\n", + jz4780_i2c_readw(i2c, JZ4780_I2C_TAR)); + dev_err(&i2c->adap.dev, "send cmd count:%d %d\n", + i2c->cmd, i2c->cmd_buf[i2c->cmd]); + dev_err(&i2c->adap.dev, "receive data count:%d %d\n", + i2c->cmd, i2c->data_buf[i2c->cmd]); + + for (i = 0; i < 16; i++) { + if (src & BIT(i)) + dev_dbg(&i2c->adap.dev, "I2C TXABRT[%d]=%s\n", + i, jz4780_i2c_abrt_src[i]); + } +} + +static inline int jz4780_i2c_xfer_read(struct jz4780_i2c *i2c, + unsigned char *buf, int len, int cnt, + int idx) +{ + int ret = 0; + long timeout; + int wait_time = JZ4780_I2C_TIMEOUT * (len + 5); + unsigned short tmp; + unsigned long flags; + + memset(buf, 0, len); + + spin_lock_irqsave(&i2c->lock, flags); + + i2c->stop_hold = 0; + i2c->is_write = 0; + i2c->rbuf = buf; + i2c->rd_total_len = len; + i2c->rd_data_xfered = 0; + i2c->rd_cmd_xfered = 0; + + if (len <= JZ4780_I2C_FIFO_LEN) + jz4780_i2c_writew(i2c, JZ4780_I2C_RXTL, len - 1); + else + jz4780_i2c_writew(i2c, JZ4780_I2C_RXTL, RX_LEVEL); + + jz4780_i2c_writew(i2c, JZ4780_I2C_TXTL, TX_LEVEL); + + jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, + JZ4780_I2C_INTM_MRXFL | JZ4780_I2C_INTM_MTXEMP + | JZ4780_I2C_INTM_MTXABT | JZ4780_I2C_INTM_MRXOF); + + tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL); + tmp |= JZ4780_I2C_CTRL_STPHLD; + jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp); + + spin_unlock_irqrestore(&i2c->lock, flags); + + timeout = wait_for_completion_timeout(&i2c->trans_waitq, + msecs_to_jiffies(wait_time)); + + if (!timeout) { + dev_err(&i2c->adap.dev, "irq read timeout\n"); + dev_dbg(&i2c->adap.dev, "send cmd count:%d %d\n", + i2c->cmd, i2c->cmd_buf[i2c->cmd]); + dev_dbg(&i2c->adap.dev, "receive data count:%d %d\n", + i2c->cmd, i2c->data_buf[i2c->cmd]); + ret = -EIO; + } + + tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_TXABRT); + if (tmp) { + jz4780_i2c_txabrt(i2c, tmp); + ret = -EIO; + } + + return ret; +} + +static inline int jz4780_i2c_xfer_write(struct jz4780_i2c *i2c, + unsigned char *buf, int len, + int cnt, int idx) +{ + int ret = 0; + int wait_time = JZ4780_I2C_TIMEOUT * (len + 5); + long timeout; + unsigned short tmp; + unsigned long flags; + + spin_lock_irqsave(&i2c->lock, flags); + + if (idx < (cnt - 1)) + i2c->stop_hold = 1; + else + i2c->stop_hold = 0; + + i2c->is_write = 1; + i2c->wbuf = buf; + i2c->wt_len = len; + + jz4780_i2c_writew(i2c, JZ4780_I2C_TXTL, TX_LEVEL); + + jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, JZ4780_I2C_INTM_MTXEMP + | JZ4780_I2C_INTM_MTXABT); + + tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL); + tmp |= JZ4780_I2C_CTRL_STPHLD; + jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp); + + spin_unlock_irqrestore(&i2c->lock, flags); + + timeout = wait_for_completion_timeout(&i2c->trans_waitq, + msecs_to_jiffies(wait_time)); + if (timeout && !i2c->stop_hold) { + unsigned short i2c_sta; + int write_in_process; + + timeout = JZ4780_I2C_TIMEOUT * 100; + for (; timeout > 0; timeout--) { + i2c_sta = jz4780_i2c_readw(i2c, JZ4780_I2C_STA); + + write_in_process = (i2c_sta & JZ4780_I2C_STA_MSTACT) || + !(i2c_sta & JZ4780_I2C_STA_TFE); + if (!write_in_process) + break; + udelay(10); + } + } + + if (!timeout) { + dev_err(&i2c->adap.dev, "write wait timeout\n"); + ret = -EIO; + } + + tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_TXABRT); + if (tmp) { + jz4780_i2c_txabrt(i2c, tmp); + ret = -EIO; + } + + return ret; +} + +static int jz4780_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, + int count) +{ + int i = -EIO; + int ret = 0; + struct jz4780_i2c *i2c = adap->algo_data; + + ret = jz4780_i2c_prepare(i2c); + if (ret) { + dev_err(&i2c->adap.dev, "I2C prepare failed\n"); + goto out; + } + + if (msg->addr != jz4780_i2c_readw(i2c, JZ4780_I2C_TAR)) { + ret = jz4780_i2c_set_target(i2c, msg->addr); + if (ret) + goto out; + } + for (i = 0; i < count; i++, msg++) { + if (msg->flags & I2C_M_RD) + ret = jz4780_i2c_xfer_read(i2c, msg->buf, msg->len, + count, i); + else + ret = jz4780_i2c_xfer_write(i2c, msg->buf, msg->len, + count, i); + + if (ret) + goto out; + } + + ret = i; + +out: + jz4780_i2c_cleanup(i2c); + return ret; +} + +static u32 jz4780_i2c_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm jz4780_i2c_algorithm = { + .master_xfer = jz4780_i2c_xfer, + .functionality = jz4780_i2c_functionality, +}; + +static const struct of_device_id jz4780_i2c_of_matches[] = { + { .compatible = "ingenic,jz4780-i2c", }, + { /* sentinel */ } +}; + +static int jz4780_i2c_probe(struct platform_device *pdev) +{ + int ret = 0; + unsigned int clk_freq = 0; + unsigned short tmp; + struct resource *r; + struct jz4780_i2c *i2c; + + i2c = devm_kzalloc(&pdev->dev, sizeof(struct jz4780_i2c), GFP_KERNEL); + if (!i2c) + return -ENOMEM; + + i2c->adap.owner = THIS_MODULE; + i2c->adap.algo = &jz4780_i2c_algorithm; + i2c->adap.algo_data = i2c; + i2c->adap.retries = 5; + i2c->adap.dev.parent = &pdev->dev; + i2c->adap.dev.of_node = pdev->dev.of_node; + sprintf(i2c->adap.name, "%s", pdev->name); + + init_completion(&i2c->trans_waitq); + spin_lock_init(&i2c->lock); + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + i2c->iomem = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(i2c->iomem)) + return PTR_ERR(i2c->iomem); + + platform_set_drvdata(pdev, i2c); + + i2c->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(i2c->clk)) + return PTR_ERR(i2c->clk); + + clk_prepare_enable(i2c->clk); + + if (of_property_read_u32(pdev->dev.of_node, "clock-frequency", + &clk_freq)) { + dev_err(&pdev->dev, "clock-frequency not specified in DT"); + return clk_freq; + } + + i2c->speed = clk_freq / 1000; + jz4780_i2c_set_speed(i2c); + + dev_info(&pdev->dev, "Bus frequency is %d KHz\n", i2c->speed); + + tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL); + tmp &= ~JZ4780_I2C_CTRL_STPHLD; + jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp); + + jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, 0x0); + + i2c->cmd = 0; + memset(i2c->cmd_buf, 0, BUFSIZE); + memset(i2c->data_buf, 0, BUFSIZE); + + i2c->irq = platform_get_irq(pdev, 0); + ret = devm_request_irq(&pdev->dev, i2c->irq, jz4780_i2c_irq, 0, + dev_name(&pdev->dev), i2c); + if (ret) { + ret = -ENODEV; + goto err; + } + + ret = i2c_add_adapter(&i2c->adap); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to add bus\n"); + goto err; + } + + return 0; + +err: + clk_disable_unprepare(i2c->clk); + return ret; +} + +static int jz4780_i2c_remove(struct platform_device *pdev) +{ + struct jz4780_i2c *i2c = platform_get_drvdata(pdev); + + clk_disable_unprepare(i2c->clk); + i2c_del_adapter(&i2c->adap); + return 0; +} + +static struct platform_driver jz4780_i2c_driver = { + .probe = jz4780_i2c_probe, + .remove = jz4780_i2c_remove, + .driver = { + .name = "jz4780-i2c", + .of_match_table = of_match_ptr(jz4780_i2c_of_matches), + }, +}; + +module_platform_driver(jz4780_i2c_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("ztyan"); +MODULE_DESCRIPTION("i2c driver for JZ4780 SoCs"); -- cgit v1.2.3-59-g8ed1b From 007c33bb9c8ee4ca7a7f0003a4529ad7df0c9e5c Mon Sep 17 00:00:00 2001 From: Fu Wei Date: Thu, 26 Mar 2015 17:49:25 +0800 Subject: Documentation: Chinese translation of arm64/legacy_instructions.txt This is a Chinese translated version of Documentation/arm64/legacy_instructions.txt It is based on the modifications of Documentation/arm64/legacy_instructions.txt in submission: "587064b6", "bd35a4ad", "2d888f48", "c852f320". Signed-off-by: Fu Wei Signed-off-by: Jonathan Corbet --- Documentation/zh_CN/arm64/legacy_instructions.txt | 72 +++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 Documentation/zh_CN/arm64/legacy_instructions.txt (limited to 'Documentation') diff --git a/Documentation/zh_CN/arm64/legacy_instructions.txt b/Documentation/zh_CN/arm64/legacy_instructions.txt new file mode 100644 index 000000000000..68362a1ab717 --- /dev/null +++ b/Documentation/zh_CN/arm64/legacy_instructions.txt @@ -0,0 +1,72 @@ +Chinese translated version of Documentation/arm64/legacy_instructions.txt + +If you have any comment or update to the content, please contact the +original document maintainer directly. However, if you have a problem +communicating in English you can also ask the Chinese maintainer for +help. Contact the Chinese maintainer if this translation is outdated +or if there is a problem with the translation. + +Maintainer: Punit Agrawal + Suzuki K. Poulose +Chinese maintainer: Fu Wei +--------------------------------------------------------------------- +Documentation/arm64/legacy_instructions.txt 的中文翻译 + +如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文 +交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻 +译存在问题,请联系中文版维护者。 + +本文翻译提交时的 Git 检出点为: bc465aa9d045feb0e13b4a8f32cc33c1943f62d6 + +英文版维护者: Punit Agrawal + Suzuki K. Poulose +中文版维护者: 傅炜 Fu Wei +中文版翻译者: 傅炜 Fu Wei +中文版校译者: 傅炜 Fu Wei + +以下为正文 +--------------------------------------------------------------------- +Linux 内核在 arm64 上的移植提供了一个基础框架,以支持构架中正在被淘汰或已废弃指令的模拟执行。 +这个基础框架的代码使用未定义指令钩子(hooks)来支持模拟。如果指令存在,它也允许在硬件中启用该指令。 + +模拟模式可通过写 sysctl 节点(/proc/sys/abi)来控制。 +不同的执行方式及 sysctl 节点的相应值,解释如下: + +* Undef(未定义) + 值: 0 + 产生未定义指令终止异常。它是那些构架中已废弃的指令,如 SWP,的默认处理方式。 + +* Emulate(模拟) + 值: 1 + 使用软件模拟方式。为解决软件迁移问题,这种模拟指令模式的使用是被跟踪的,并会发出速率限制警告。 + 它是那些构架中正在被淘汰的指令,如 CP15 barriers(隔离指令),的默认处理方式。 + +* Hardware Execution(硬件执行) + 值: 2 + 虽然标记为正在被淘汰,但一些实现可能提供硬件执行这些指令的使能/禁用操作。 + 使用硬件执行一般会有更好的性能,但将无法收集运行时对正被淘汰指令的使用统计数据。 + +默认执行模式依赖于指令在构架中状态。正在被淘汰的指令应该以模拟(Emulate)作为默认模式, +而已废弃的指令必须默认使用未定义(Undef)模式 + +注意:指令模拟可能无法应对所有情况。更多详情请参考单独的指令注释。 + +受支持的遗留指令 +------------- +* SWP{B} +节点: /proc/sys/abi/swp +状态: 已废弃 +默认执行方式: Undef (0) + +* CP15 Barriers +节点: /proc/sys/abi/cp15_barrier +状态: 正被淘汰,不推荐使用 +默认执行方式: Emulate (1) + +* SETEND +节点: /proc/sys/abi/setend +状态: 正被淘汰,不推荐使用 +默认执行方式: Emulate (1)* +注:为了使能这个特性,系统中的所有 CPU 必须在 EL0 支持混合字节序。 +如果一个新的 CPU (不支持混合字节序) 在使能这个特性后被热插入系统, +在应用中可能会出现不可预期的结果。 -- cgit v1.2.3-59-g8ed1b From 89098bfcf5944e4aab98c83de3cf4c0d802e8d3f Mon Sep 17 00:00:00 2001 From: Fu Wei Date: Tue, 24 Mar 2015 17:37:19 +0800 Subject: Documentation:Update Documentation/zh_CN/arm64/booting.txt This is a update of Chinese documentation: Documentation/zh_CN/arm64/booting.txt It is based on the modifications of Documentation/arm64/booting.txt in submission: "a2c1d73b", "cdd78578", "c218bca7", "63f8344c". Signed-off-by: Fu Wei Signed-off-by: Jonathan Corbet --- Documentation/zh_CN/arm64/booting.txt | 54 +++++++++++++++++++++++++++++------ 1 file changed, 45 insertions(+), 9 deletions(-) (limited to 'Documentation') diff --git a/Documentation/zh_CN/arm64/booting.txt b/Documentation/zh_CN/arm64/booting.txt index 6f6d956ac1c9..7cd36af11e71 100644 --- a/Documentation/zh_CN/arm64/booting.txt +++ b/Documentation/zh_CN/arm64/booting.txt @@ -15,6 +15,8 @@ Documentation/arm64/booting.txt 的中文翻译 交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻 译存在问题,请联系中文版维护者。 +本文翻译提交时的 Git 检出点为: bc465aa9d045feb0e13b4a8f32cc33c1943f62d6 + 英文版维护者: Will Deacon 中文版维护者: 傅炜 Fu Wei 中文版翻译者: 傅炜 Fu Wei @@ -88,22 +90,44 @@ AArch64 内核当前没有提供自解压代码,因此如果使用了压缩内 u32 code0; /* 可执行代码 */ u32 code1; /* 可执行代码 */ - u64 text_offset; /* 映像装载偏移 */ - u64 res0 = 0; /* 保留 */ - u64 res1 = 0; /* 保留 */ + u64 text_offset; /* 映像装载偏移,小端模式 */ + u64 image_size; /* 映像实际大小, 小端模式 */ + u64 flags; /* 内核旗标, 小端模式 * u64 res2 = 0; /* 保留 */ u64 res3 = 0; /* 保留 */ u64 res4 = 0; /* 保留 */ u32 magic = 0x644d5241; /* 魔数, 小端, "ARM\x64" */ - u32 res5 = 0; /* 保留 */ + u32 res5; /* 保留 (用于 PE COFF 偏移) */ 映像头注释: +- 自 v3.17 起,除非另有说明,所有域都是小端模式。 + - code0/code1 负责跳转到 stext. -映像必须位于系统 RAM 起始处的特定偏移(当前是 0x80000)。系统 RAM -的起始地址必须是以 2MB 对齐的。 +- 当通过 EFI 启动时, 最初 code0/code1 被跳过。 + res5 是到 PE 文件头的偏移,而 PE 文件头含有 EFI 的启动入口点 (efi_stub_entry)。 + 当 stub 代码完成了它的使命,它会跳转到 code0 继续正常的启动流程。 + +- v3.17 之前,未明确指定 text_offset 的字节序。此时,image_size 为零, + 且 text_offset 依照内核字节序为 0x80000。 + 当 image_size 非零,text_offset 为小端模式且是有效值,应被引导加载程序使用。 + 当 image_size 为零,text_offset 可假定为 0x80000。 + +- flags 域 (v3.17 引入) 为 64 位小端模式,其编码如下: + 位 0: 内核字节序。 1 表示大端模式,0 表示小端模式。 + 位 1-63: 保留。 + +- 当 image_size 为零时,引导装载程序应该试图在内核映像末尾之后尽可能多地保留空闲内存 + 供内核直接使用。对内存空间的需求量因所选定的内核特性而异, 且无实际限制。 + +内核映像必须被放置在靠近可用系统内存起始的 2MB 对齐为基址的 text_offset 字节处,并从那里被调用。 +当前,对 Linux 来说在此基址以下的内存是无法使用的,因此强烈建议将系统内存的起始作为这个基址。 +从映像起始地址算起,最少必须为内核释放出 image_size 字节的空间。 + +任何提供给内核的内存(甚至在 2MB 对齐的基地址之前),若未从内核中标记为保留 +(如在设备树(dtb)的 memreserve 区域),都将被认为对内核是可用。 在跳转入内核前,必须符合以下状态: @@ -124,8 +148,12 @@ AArch64 内核当前没有提供自解压代码,因此如果使用了压缩内 - 高速缓存、MMU MMU 必须关闭。 指令缓存开启或关闭都可以。 - 数据缓存必须关闭且无效。 - 外部高速缓存(如果存在)必须配置并禁用。 + 已载入的内核映像的相应内存区必须被清理,以达到缓存一致性点(PoC)。 + 当存在系统缓存或其他使能缓存的一致性主控器时,通常需使用虚拟地址维护其缓存,而非 set/way 操作。 + 遵从通过虚拟地址操作维护构架缓存的系统缓存必须被配置,并可以被使能。 + 而不通过虚拟地址操作维护构架缓存的系统缓存(不推荐),必须被配置且禁用。 + + *译者注:对于 PoC 以及缓存相关内容,请参考 ARMv8 构架参考手册 ARM DDI 0487A - 架构计时器 CNTFRQ 必须设定为计时器的频率,且 CNTVOFF 必须设定为对所有 CPU @@ -141,6 +169,14 @@ AArch64 内核当前没有提供自解压代码,因此如果使用了压缩内 在进入内核映像的异常级中,所有构架中可写的系统寄存器必须通过软件 在一个更高的异常级别下初始化,以防止在 未知 状态下运行。 + 对于拥有 GICv3 中断控制器的系统: + - 若当前在 EL3 : + ICC_SRE_EL3.Enable (位 3) 必须初始化为 0b1。 + ICC_SRE_EL3.SRE (位 0) 必须初始化为 0b1。 + - 若内核运行在 EL1: + ICC_SRE_EL2.Enable (位 3) 必须初始化为 0b1。 + ICC_SRE_EL2.SRE (位 0) 必须初始化为 0b1。 + 以上对于 CPU 模式、高速缓存、MMU、架构计时器、一致性、系统寄存器的 必要条件描述适用于所有 CPU。所有 CPU 必须在同一异常级别跳入内核。 @@ -170,7 +206,7 @@ AArch64 内核当前没有提供自解压代码,因此如果使用了压缩内 ARM DEN 0022A:用于 ARM 上的电源状态协调接口系统软件)中描述的 CPU_ON 调用来将 CPU 带入内核。 - *译者注:到文档翻译时,此文档已更新为 ARM DEN 0022B。 + *译者注: ARM DEN 0022A 已更新到 ARM DEN 0022C。 设备树必须包含一个 ‘psci’ 节点,请参考以下文档: Documentation/devicetree/bindings/arm/psci.txt -- cgit v1.2.3-59-g8ed1b From 4997166a393851d0595f85cbe1195208d582e172 Mon Sep 17 00:00:00 2001 From: Fu Wei Date: Tue, 24 Mar 2015 00:43:17 +0800 Subject: Documentation:Update Documentation/zh_CN/arm64/memory.txt This is a update of Chinese documentation:Documentation/zh_CN/arm64/memory.txt It is based on the modifications of Documentation/arm64/memory.txt in submission: "08375198", "4edae01e", "a24637d5", "383c2799". Signed-off-by: Fu Wei Signed-off-by: Jonathan Corbet --- Documentation/zh_CN/arm64/memory.txt | 65 +++++++++++++++--------------------- 1 file changed, 26 insertions(+), 39 deletions(-) (limited to 'Documentation') diff --git a/Documentation/zh_CN/arm64/memory.txt b/Documentation/zh_CN/arm64/memory.txt index a782704c1cb5..19b3a52d5d94 100644 --- a/Documentation/zh_CN/arm64/memory.txt +++ b/Documentation/zh_CN/arm64/memory.txt @@ -15,6 +15,8 @@ Documentation/arm64/memory.txt 的中文翻译 交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻 译存在问题,请联系中文版维护者。 +本文翻译提交时的 Git 检出点为: bc465aa9d045feb0e13b4a8f32cc33c1943f62d6 + 英文版维护者: Catalin Marinas 中文版维护者: 傅炜 Fu Wei 中文版翻译者: 傅炜 Fu Wei @@ -26,69 +28,53 @@ Documentation/arm64/memory.txt 的中文翻译 =========================== 作者: Catalin Marinas -日期: 2012 年 02 月 20 日 本文档描述 AArch64 Linux 内核所使用的虚拟内存布局。此构架可以实现 页大小为 4KB 的 4 级转换表和页大小为 64KB 的 3 级转换表。 -AArch64 Linux 使用页大小为 4KB 的 3 级转换表配置,对于用户和内核 -都有 39-bit (512GB) 的虚拟地址空间。对于页大小为 64KB的配置,仅 -使用 2 级转换表,但内存布局相同。 +AArch64 Linux 使用 3 级或 4 级转换表,其页大小配置为 4KB,对于用户和内核 +分别都有 39-bit (512GB) 或 48-bit (256TB) 的虚拟地址空间。 +对于页大小为 64KB的配置,仅使用 2 级转换表,有 42-bit (4TB) 的虚拟地址空间,但内存布局相同。 -用户地址空间的 63:39 位为 0,而内核地址空间的相应位为 1。TTBRx 的 +用户地址空间的 63:48 位为 0,而内核地址空间的相应位为 1。TTBRx 的 选择由虚拟地址的 63 位给出。swapper_pg_dir 仅包含内核(全局)映射, -而用户 pgd 仅包含用户(非全局)映射。swapper_pgd_dir 地址被写入 +而用户 pgd 仅包含用户(非全局)映射。swapper_pg_dir 地址被写入 TTBR1 中,且从不写入 TTBR0。 -AArch64 Linux 在页大小为 4KB 时的内存布局: +AArch64 Linux 在页大小为 4KB,并使用 3 级转换表时的内存布局: 起始地址 结束地址 大小 用途 ----------------------------------------------------------------------- 0000000000000000 0000007fffffffff 512GB 用户空间 +ffffff8000000000 ffffffffffffffff 512GB 内核空间 -ffffff8000000000 ffffffbbfffeffff ~240GB vmalloc - -ffffffbbffff0000 ffffffbbffffffff 64KB [防护页] - -ffffffbc00000000 ffffffbdffffffff 8GB vmemmap - -ffffffbe00000000 ffffffbffbbfffff ~8GB [防护页,未来用于 vmmemap] -ffffffbffbc00000 ffffffbffbdfffff 2MB earlyprintk 设备 +AArch64 Linux 在页大小为 4KB,并使用 4 级转换表时的内存布局: -ffffffbffbe00000 ffffffbffbe0ffff 64KB PCI I/O 空间 - -ffffffbffbe10000 ffffffbcffffffff ~2MB [防护页] - -ffffffbffc000000 ffffffbfffffffff 64MB 模块 - -ffffffc000000000 ffffffffffffffff 256GB 内核逻辑内存映射 +起始地址 结束地址 大小 用途 +----------------------------------------------------------------------- +0000000000000000 0000ffffffffffff 256TB 用户空间 +ffff000000000000 ffffffffffffffff 256TB 内核空间 -AArch64 Linux 在页大小为 64KB 时的内存布局: +AArch64 Linux 在页大小为 64KB,并使用 2 级转换表时的内存布局: 起始地址 结束地址 大小 用途 ----------------------------------------------------------------------- 0000000000000000 000003ffffffffff 4TB 用户空间 +fffffc0000000000 ffffffffffffffff 4TB 内核空间 -fffffc0000000000 fffffdfbfffeffff ~2TB vmalloc - -fffffdfbffff0000 fffffdfbffffffff 64KB [防护页] - -fffffdfc00000000 fffffdfdffffffff 8GB vmemmap - -fffffdfe00000000 fffffdfffbbfffff ~8GB [防护页,未来用于 vmmemap] -fffffdfffbc00000 fffffdfffbdfffff 2MB earlyprintk 设备 +AArch64 Linux 在页大小为 64KB,并使用 3 级转换表时的内存布局: -fffffdfffbe00000 fffffdfffbe0ffff 64KB PCI I/O 空间 - -fffffdfffbe10000 fffffdfffbffffff ~2MB [防护页] +起始地址 结束地址 大小 用途 +----------------------------------------------------------------------- +0000000000000000 0000ffffffffffff 256TB 用户空间 +ffff000000000000 ffffffffffffffff 256TB 内核空间 -fffffdfffc000000 fffffdffffffffff 64MB 模块 -fffffe0000000000 ffffffffffffffff 2TB 内核逻辑内存映射 +更详细的内核虚拟内存布局,请参阅内核启动信息。 4KB 页大小的转换表查找: @@ -102,7 +88,7 @@ fffffe0000000000 ffffffffffffffff 2TB 内核逻辑内存映射 | | | | +-> [20:12] L3 索引 | | | +-----------> [29:21] L2 索引 | | +---------------------> [38:30] L1 索引 - | +-------------------------------> [47:39] L0 索引 (未使用) + | +-------------------------------> [47:39] L0 索引 +-------------------------------------------------> [63] TTBR0/1 @@ -115,10 +101,11 @@ fffffe0000000000 ffffffffffffffff 2TB 内核逻辑内存映射 | | | | v | | | | [15:0] 页内偏移 | | | +----------> [28:16] L3 索引 - | | +--------------------------> [41:29] L2 索引 (仅使用 38:29 ) - | +-------------------------------> [47:42] L1 索引 (未使用) + | | +--------------------------> [41:29] L2 索引 + | +-------------------------------> [47:42] L1 索引 +-------------------------------------------------> [63] TTBR0/1 + 当使用 KVM 时, 管理程序(hypervisor)在 EL2 中通过相对内核虚拟地址的 一个固定偏移来映射内核页(内核虚拟地址的高 24 位设为零): -- cgit v1.2.3-59-g8ed1b From 4988aaa6e508614e5d4c4f08723635fc8191188b Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Fri, 20 Feb 2015 12:28:48 -0500 Subject: doc: completion: context, scope and language fixes Fix for imprecise/wrong statements on context in which wait_for_completion*() can be called, updated notes on "going out of scope" problems and some language fixups. Signed-off-by: Nicholas Mc Guire Acked-by: Ingo Molnar Signed-off-by: Jonathan Corbet --- Documentation/scheduler/completion.txt | 99 +++++++++++++++++++--------------- 1 file changed, 55 insertions(+), 44 deletions(-) (limited to 'Documentation') diff --git a/Documentation/scheduler/completion.txt b/Documentation/scheduler/completion.txt index f77651eca31e..083d9c931b8d 100644 --- a/Documentation/scheduler/completion.txt +++ b/Documentation/scheduler/completion.txt @@ -11,11 +11,11 @@ to have reached a point or a specific state, completions can provide a race free solution to this problem. Semantically they are somewhat like a pthread_barriers and have similar use-cases. -Completions are a code synchronization mechanism that is preferable to any +Completions are a code synchronization mechanism which are preferable to any misuse of locks. Any time you think of using yield() or some quirky msleep(1); loop to allow something else to proceed, you probably want to look into using one of the wait_for_completion*() calls instead. The -advantage of using completions is clear intent of the code but also more +advantage of using completions is clear intent of the code, but also more efficient code as both threads can continue until the result is actually needed. @@ -24,7 +24,7 @@ with the event reduced to a simple flag appropriately called "done" in struct completion, that tells the waiting threads of execution if they can continue safely. -As completions are scheduling related the code is found in +As completions are scheduling related, the code is found in kernel/sched/completion.c - for details on completion design and implementation see completions-design.txt @@ -32,9 +32,9 @@ implementation see completions-design.txt Usage: ------ -There are three parts to the using completions, the initialization of the +There are three parts to using completions, the initialization of the struct completion, the waiting part through a call to one of the variants of -wait_for_completion() and the signaling side through a call to complete(), +wait_for_completion() and the signaling side through a call to complete() or complete_all(). Further there are some helper functions for checking the state of completions. @@ -50,7 +50,7 @@ handling of completions is: providing the wait queue to place tasks on for waiting and the flag for indicating the state of affairs. -Completions should be named to convey the intent of the waiter. A good +Completions should be named to convey the intent of the waiter. A good example is: wait_for_completion(&early_console_added); @@ -73,7 +73,7 @@ the default state to "not available", that is, "done" is set to 0. The re-initialization function, reinit_completion(), simply resets the done element to "not available", thus again to 0, without touching the -wait queue. Calling init_completion() on the same completions object is +wait queue. Calling init_completion() on the same completion object is most likely a bug as it re-initializes the queue to an empty queue and enqueued tasks could get "lost" - use reinit_completion() in that case. @@ -87,10 +87,17 @@ initialization should always use: DECLARE_COMPLETION_ONSTACK(setup_done) suitable for automatic/local variables on the stack and will make lockdep -happy. Note also that one needs to making *sure* the completion passt to +happy. Note also that one needs to make *sure* the completion passed to work threads remains in-scope, and no references remain to on-stack data when the initiating function returns. +Using on-stack completions for code that calls any of the _timeout or +_interruptible/_killable variants is not advisable as they will require +additional synchronization to prevent the on-stack completion object in +the timeout/signal cases from going out of scope. Consider using dynamically +allocated completions when intending to use the _interruptible/_killable +or _timeout variants of wait_for_completion(). + Waiting for completions: ------------------------ @@ -101,21 +108,22 @@ A typical usage scenario is: structure completion setup_done; init_completion(&setup_done); - initialze_work(...,&setup_done,...) + initialize_work(...,&setup_done,...) /* run non-dependent code */ /* do setup */ - wait_for_completion(&seupt_done); complete(setup_done) + wait_for_completion(&setup_done); complete(setup_done) -This is not implying any temporal order of wait_for_completion() and the +This is not implying any temporal order on wait_for_completion() and the call to complete() - if the call to complete() happened before the call to wait_for_completion() then the waiting side simply will continue -immediately as all dependencies are satisfied. +immediately as all dependencies are satisfied if not it will block until +completion is signaled by complete(). Note that wait_for_completion() is calling spin_lock_irq/spin_unlock_irq so it can only be called safely when you know that interrupts are enabled. -Calling it from hard-irq context will result in hard to detect spurious -enabling of interrupts. +Calling it from hard-irq or irqs-off atomic contexts will result in hard +to detect spurious enabling of interrupts. wait_for_completion(): @@ -123,10 +131,13 @@ wait_for_completion(): The default behavior is to wait without a timeout and mark the task as uninterruptible. wait_for_completion() and its variants are only safe -in soft-interrupt or process context but not in hard-irq context. +in process context (as they can sleep) but not in atomic context, +interrupt context, with disabled irqs. or preemption is disabled - see also +try_wait_for_completion() below for handling completion in atomic/interrupt +context. + As all variants of wait_for_completion() can (obviously) block for a long -time, you probably don't want to call this with held locks - see also -try_wait_for_completion() below. +time, you probably don't want to call this with held mutexes. Variants available: @@ -141,20 +152,20 @@ A common problem that occurs is to have unclean assignment of return types, so care should be taken with assigning return-values to variables of proper type. Checking for the specific meaning of return values also has been found to be quite inaccurate e.g. constructs like -if(!wait_for_completion_interruptible_timeout(...)) would execute the same +if (!wait_for_completion_interruptible_timeout(...)) would execute the same code path for successful completion and for the interrupted case - which is probably not what you want. int wait_for_completion_interruptible(struct completion *done) -marking the task TASK_INTERRUPTIBLE. If a signal was received while waiting. -It will return -ERESTARTSYS and 0 otherwise. +This function marks the task TASK_INTERRUPTIBLE. If a signal was received +while waiting it will return -ERESTARTSYS and 0 otherwise. unsigned long wait_for_completion_timeout(struct completion *done, unsigned long timeout) -The task is marked as TASK_UNINTERRUPTIBLE and will wait at most timeout -(in jiffies). If timeout occurs it return 0 else the remaining time in +The task is marked as TASK_UNINTERRUPTIBLE and will wait at most 'timeout' +(in jiffies). If timeout occurs it returns 0 else the remaining time in jiffies (but at least 1). Timeouts are preferably passed by msecs_to_jiffies() or usecs_to_jiffies(). If the returned timeout value is deliberately ignored a comment should probably explain why (e.g. see drivers/mfd/wm8350-core.c @@ -163,21 +174,21 @@ wm8350_read_auxadc()) long wait_for_completion_interruptible_timeout( struct completion *done, unsigned long timeout) -passing a timeout in jiffies and marking the task as TASK_INTERRUPTIBLE. If a -signal was received it will return -ERESTARTSYS, 0 if completion timed-out and -the remaining time in jiffies if completion occurred. +This function passes a timeout in jiffies and marking the task as +TASK_INTERRUPTIBLE. If a signal was received it will return -ERESTARTSYS, 0 if +completion timed out and the remaining time in jiffies if completion occurred. Further variants include _killable which passes TASK_KILLABLE as the -designated tasks state and will return a -ERESTARTSYS if interrupted or -else 0 if completions was achieved as well as a _timeout variant. +designated tasks state and will return -ERESTARTSYS if interrupted or +else 0 if completion was achieved as well as a _timeout variant. long wait_for_completion_killable(struct completion *done) long wait_for_completion_killable_timeout(struct completion *done, unsigned long timeout) -The _io variants wait_for_completion_io behave the same as the non-_io +The _io variants wait_for_completion_io() behave the same as the non-_io variants, except for accounting waiting time as waiting on IO, which has -an impact on how scheduling is calculated. +an impact on how the task is accounted in scheduling stats. void wait_for_completion_io(struct completion *done) unsigned long wait_for_completion_io_timeout(struct completion *done @@ -187,13 +198,13 @@ an impact on how scheduling is calculated. Signaling completions: ---------------------- -A thread of execution that wants to signal that the conditions for -continuation have been achieved calls complete() to signal exactly one -of the waiters that it can continue. +A thread that wants to signal that the conditions for continuation have been +achieved calls complete() to signal exactly one of the waiters that it can +continue. void complete(struct completion *done) -or calls complete_all to signal all current and future waiters. +or calls complete_all() to signal all current and future waiters. void complete_all(struct completion *done) @@ -205,32 +216,32 @@ wakeup order is the same in which they were enqueued (FIFO order). If complete() is called multiple times then this will allow for that number of waiters to continue - each call to complete() will simply increment the done element. Calling complete_all() multiple times is a bug though. Both -complete() and complete_all() can be called in hard-irq context safely. +complete() and complete_all() can be called in hard-irq/atomic context safely. There only can be one thread calling complete() or complete_all() on a -particular struct completions at any time - serialized through the wait +particular struct completion at any time - serialized through the wait queue spinlock. Any such concurrent calls to complete() or complete_all() probably are a design bug. Signaling completion from hard-irq context is fine as it will appropriately -lock with spin_lock_irqsave/spin_unlock_irqrestore. +lock with spin_lock_irqsave/spin_unlock_irqrestore and it will never sleep. try_wait_for_completion()/completion_done(): -------------------------------------------- -The try_wait_for_completion will not put the thread on the wait queue but -rather returns false if it would need to enqueue (block) the thread, else it -consumes any posted completions and returns true. +The try_wait_for_completion() function will not put the thread on the wait +queue but rather returns false if it would need to enqueue (block) the thread, +else it consumes any posted completions and returns true. - bool try_wait_for_completion(struct completion *done) + bool try_wait_for_completion(struct completion *done) -Finally to check state of a completions without changing it in any way is -provided by completion_done() returning false if there are any posted +Finally to check state of a completion without changing it in any way is +provided by completion_done() returning false if there is any posted completion that was not yet consumed by waiters implying that there are waiters and true otherwise; - bool completion_done(struct completion *done) + bool completion_done(struct completion *done) Both try_wait_for_completion() and completion_done() are safe to be called in -hard-irq context. +hard-irq or atomic context. -- cgit v1.2.3-59-g8ed1b From 7085f6c354e1d0b1cc6efafc1389dc63f8b0699a Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Fri, 27 Mar 2015 10:16:35 -0600 Subject: docs/completion.txt: Various tweaks and corrections Mostly language improvements to the new completions.txt document, but there is also a semantic correction in the description of completion_done() at the very end. Acked-by: Ingo Molnar Signed-off-by: Jonathan Corbet --- Documentation/scheduler/completion.txt | 59 +++++++++++++++++----------------- 1 file changed, 30 insertions(+), 29 deletions(-) (limited to 'Documentation') diff --git a/Documentation/scheduler/completion.txt b/Documentation/scheduler/completion.txt index 083d9c931b8d..2622bc7a188b 100644 --- a/Documentation/scheduler/completion.txt +++ b/Documentation/scheduler/completion.txt @@ -7,21 +7,21 @@ Introduction: ------------- If you have one or more threads of execution that must wait for some process -to have reached a point or a specific state, completions can provide a race -free solution to this problem. Semantically they are somewhat like a -pthread_barriers and have similar use-cases. +to have reached a point or a specific state, completions can provide a +race-free solution to this problem. Semantically they are somewhat like a +pthread_barrier and have similar use-cases. -Completions are a code synchronization mechanism which are preferable to any +Completions are a code synchronization mechanism which is preferable to any misuse of locks. Any time you think of using yield() or some quirky -msleep(1); loop to allow something else to proceed, you probably want to +msleep(1) loop to allow something else to proceed, you probably want to look into using one of the wait_for_completion*() calls instead. The advantage of using completions is clear intent of the code, but also more efficient code as both threads can continue until the result is actually needed. Completions are built on top of the generic event infrastructure in Linux, -with the event reduced to a simple flag appropriately called "done" in -struct completion, that tells the waiting threads of execution if they +with the event reduced to a simple flag (appropriately called "done") in +struct completion that tells the waiting threads of execution if they can continue safely. As completions are scheduling related, the code is found in @@ -73,7 +73,7 @@ the default state to "not available", that is, "done" is set to 0. The re-initialization function, reinit_completion(), simply resets the done element to "not available", thus again to 0, without touching the -wait queue. Calling init_completion() on the same completion object is +wait queue. Calling init_completion() twice on the same completion object is most likely a bug as it re-initializes the queue to an empty queue and enqueued tasks could get "lost" - use reinit_completion() in that case. @@ -106,7 +106,7 @@ For a thread of execution to wait for some concurrent work to finish, it calls wait_for_completion() on the initialized completion structure. A typical usage scenario is: - structure completion setup_done; + struct completion setup_done; init_completion(&setup_done); initialize_work(...,&setup_done,...) @@ -120,16 +120,16 @@ to wait_for_completion() then the waiting side simply will continue immediately as all dependencies are satisfied if not it will block until completion is signaled by complete(). -Note that wait_for_completion() is calling spin_lock_irq/spin_unlock_irq +Note that wait_for_completion() is calling spin_lock_irq()/spin_unlock_irq(), so it can only be called safely when you know that interrupts are enabled. -Calling it from hard-irq or irqs-off atomic contexts will result in hard -to detect spurious enabling of interrupts. +Calling it from hard-irq or irqs-off atomic contexts will result in +hard-to-detect spurious enabling of interrupts. wait_for_completion(): void wait_for_completion(struct completion *done): -The default behavior is to wait without a timeout and mark the task as +The default behavior is to wait without a timeout and to mark the task as uninterruptible. wait_for_completion() and its variants are only safe in process context (as they can sleep) but not in atomic context, interrupt context, with disabled irqs. or preemption is disabled - see also @@ -159,28 +159,29 @@ probably not what you want. int wait_for_completion_interruptible(struct completion *done) This function marks the task TASK_INTERRUPTIBLE. If a signal was received -while waiting it will return -ERESTARTSYS and 0 otherwise. +while waiting it will return -ERESTARTSYS; 0 otherwise. unsigned long wait_for_completion_timeout(struct completion *done, unsigned long timeout) The task is marked as TASK_UNINTERRUPTIBLE and will wait at most 'timeout' (in jiffies). If timeout occurs it returns 0 else the remaining time in -jiffies (but at least 1). Timeouts are preferably passed by msecs_to_jiffies() -or usecs_to_jiffies(). If the returned timeout value is deliberately ignored -a comment should probably explain why (e.g. see drivers/mfd/wm8350-core.c -wm8350_read_auxadc()) +jiffies (but at least 1). Timeouts are preferably calculated with +msecs_to_jiffies() or usecs_to_jiffies(). If the returned timeout value is +deliberately ignored a comment should probably explain why (e.g. see +drivers/mfd/wm8350-core.c wm8350_read_auxadc()) long wait_for_completion_interruptible_timeout( struct completion *done, unsigned long timeout) -This function passes a timeout in jiffies and marking the task as -TASK_INTERRUPTIBLE. If a signal was received it will return -ERESTARTSYS, 0 if -completion timed out and the remaining time in jiffies if completion occurred. +This function passes a timeout in jiffies and marks the task as +TASK_INTERRUPTIBLE. If a signal was received it will return -ERESTARTSYS; +otherwise it returns 0 if the completion timed out or the remaining time in +jiffies if completion occurred. -Further variants include _killable which passes TASK_KILLABLE as the -designated tasks state and will return -ERESTARTSYS if interrupted or -else 0 if completion was achieved as well as a _timeout variant. +Further variants include _killable which uses TASK_KILLABLE as the +designated tasks state and will return -ERESTARTSYS if it is interrupted or +else 0 if completion was achieved. There is a _timeout variant as well: long wait_for_completion_killable(struct completion *done) long wait_for_completion_killable_timeout(struct completion *done, @@ -232,14 +233,14 @@ try_wait_for_completion()/completion_done(): The try_wait_for_completion() function will not put the thread on the wait queue but rather returns false if it would need to enqueue (block) the thread, -else it consumes any posted completions and returns true. +else it consumes one posted completion and returns true. bool try_wait_for_completion(struct completion *done) -Finally to check state of a completion without changing it in any way is -provided by completion_done() returning false if there is any posted -completion that was not yet consumed by waiters implying that there are -waiters and true otherwise; +Finally, to check the state of a completion without changing it in any way, +call completion_done(), which returns false if there are no posted +completions that were not yet consumed by waiters (implying that there are +waiters) and true otherwise; bool completion_done(struct completion *done) -- cgit v1.2.3-59-g8ed1b From cfc507648c2c9060aeba0d1a41bb5e5985f16636 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Wed, 1 Apr 2015 11:13:16 +0300 Subject: Documentation: gpio: Update ACPI part of the document to mention _DSD With ACPI 5.1 _DSD (Device Specific Data) it is now possible to name functions just like Device Tree is doing. Make sure that the documentation mentions _DSD as the recommended way to describe GPIOs in ACPI systems. Reported-by: Darren Hart Reviewed-by: Darren Hart Signed-off-by: Mika Westerberg Acked-by: Rafael J. Wysocki Signed-off-by: Jonathan Corbet --- Documentation/gpio/board.txt | 41 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/gpio/board.txt b/Documentation/gpio/board.txt index 8b35f51fe7b6..b80606de545a 100644 --- a/Documentation/gpio/board.txt +++ b/Documentation/gpio/board.txt @@ -50,10 +50,43 @@ gpiod_is_active_low(power) will be true). ACPI ---- -ACPI does not support function names for GPIOs. Therefore, only the "idx" -argument of gpiod_get_index() is useful to discriminate between GPIOs assigned -to a device. The "con_id" argument can still be set for debugging purposes (it -will appear under error messages as well as debug and sysfs nodes). +ACPI also supports function names for GPIOs in a similar fashion to DT. +The above DT example can be converted to an equivalent ACPI description +with the help of _DSD (Device Specific Data), introduced in ACPI 5.1: + + Device (FOO) { + Name (_CRS, ResourceTemplate () { + GpioIo (Exclusive, ..., IoRestrictionOutputOnly, + "\\_SB.GPI0") {15} // red + GpioIo (Exclusive, ..., IoRestrictionOutputOnly, + "\\_SB.GPI0") {16} // green + GpioIo (Exclusive, ..., IoRestrictionOutputOnly, + "\\_SB.GPI0") {17} // blue + GpioIo (Exclusive, ..., IoRestrictionOutputOnly, + "\\_SB.GPI0") {1} // power + }) + + Name (_DSD, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package () { + "led-gpios", + Package () { + ^FOO, 0, 0, 1, + ^FOO, 1, 0, 1, + ^FOO, 2, 0, 1, + } + }, + Package () { + "power-gpios", + Package () {^FOO, 3, 0, 0}, + }, + } + }) + } + +For more information about the ACPI GPIO bindings see +Documentation/acpi/gpio-properties.txt. Platform Data ------------- -- cgit v1.2.3-59-g8ed1b From f29ba61d0abad6ad0beed5237cd337b5e25adad7 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Fri, 27 Mar 2015 16:15:18 +0100 Subject: Documentation/kernel-parameters: Move "eagerfpu" to its right place We're at least trying to be alphabetically sorted. So move "eagerfpu=" in the vicinity of where it belongs at least. Signed-off-by: Borislav Petkov Signed-off-by: Jonathan Corbet --- Documentation/kernel-parameters.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index bfcb1a62a7b4..155d736c1210 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -928,6 +928,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted. Enable debug messages at boot time. See Documentation/dynamic-debug-howto.txt for details. + eagerfpu= [X86] + on enable eager fpu restore + off disable eager fpu restore + auto selects the default scheme, which automatically + enables eagerfpu restore for xsaveopt. + early_ioremap_debug [KNL] Enable debug messages in early_ioremap support. This is useful for tracking down temporary early mappings @@ -2340,12 +2346,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted. parameter, xsave area per process might occupy more memory on xsaves enabled systems. - eagerfpu= [X86] - on enable eager fpu restore - off disable eager fpu restore - auto selects the default scheme, which automatically - enables eagerfpu restore for xsaveopt. - nohlt [BUGS=ARM,SH] Tells the kernel that the sleep(SH) or wfi(ARM) instruction doesn't work correctly and not to use it. This is also useful when using JTAG debugger. -- cgit v1.2.3-59-g8ed1b From c8a329c777f5a38e39b25425d29b2e37cbb06614 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Mon, 30 Mar 2015 15:49:26 +0200 Subject: doc: Add guest_nice column to example output of `cat /proc/stat' Commit ce0e7b28fb75cb00 ("sched, cpuacct: Fix niced guest time accounting") added the guest_nice column to /proc/stat, but the example output of `cat /proc/stat' in Documentation/filesystems/proc.txt wasn't updated accordingly. Do so now. Cc: Ryota Ozaki Signed-off-by: Tobias Klauser Signed-off-by: Jonathan Corbet --- Documentation/filesystems/proc.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt index a07ba61662ed..f0546401b9e0 100644 --- a/Documentation/filesystems/proc.txt +++ b/Documentation/filesystems/proc.txt @@ -1255,9 +1255,9 @@ Various pieces of information about kernel activity are available in the since the system first booted. For a quick look, simply cat the file: > cat /proc/stat - cpu 2255 34 2290 22625563 6290 127 456 0 0 - cpu0 1132 34 1441 11311718 3675 127 438 0 0 - cpu1 1123 0 849 11313845 2614 0 18 0 0 + cpu 2255 34 2290 22625563 6290 127 456 0 0 0 + cpu0 1132 34 1441 11311718 3675 127 438 0 0 0 + cpu1 1123 0 849 11313845 2614 0 18 0 0 0 intr 114930548 113199788 3 0 5 263 0 4 [... lots more numbers ...] ctxt 1990473 btime 1062191376 -- cgit v1.2.3-59-g8ed1b From 4ee07157d690b1b824328a473816a371130de6f2 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Wed, 25 Mar 2015 23:26:28 -0700 Subject: hwmon: (it87) Add support for IT8790E IT8790E is a super-IO chip with three fan tachometers. It is mostly compatible to IT8728F, but only supports three fan tachometers instead of five. Reviewed-by: Jean Delvare Signed-off-by: Guenter Roeck --- Documentation/hwmon/it87 | 13 ++++++++++--- drivers/hwmon/Kconfig | 4 ++-- drivers/hwmon/it87.c | 14 +++++++++++++- 3 files changed, 25 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/hwmon/it87 b/Documentation/hwmon/it87 index 19fbe775ae10..91e8f011dacf 100644 --- a/Documentation/hwmon/it87 +++ b/Documentation/hwmon/it87 @@ -58,6 +58,10 @@ Supported chips: Prefix: 'it8786' Addresses scanned: from Super I/O config space (8 I/O ports) Datasheet: Not publicly available + * IT8790E + Prefix: 'it8790' + Addresses scanned: from Super I/O config space (8 I/O ports) + Datasheet: Not publicly available * SiS950 [clone of IT8705F] Prefix: 'it87' Addresses scanned: from Super I/O config space (8 I/O ports) @@ -102,9 +106,10 @@ motherboard models. Description ----------- -This driver implements support for the IT8603E, IT8623E, IT8705F, IT8712F, -IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E, IT8771E, -IT8772E, IT8781F, IT8782F, IT8783E/F, IT8786E, and SiS950 chips. +This driver implements support for the IT8603E, IT8623E, IT8705F, +IT8712F, IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E, +IT8771E, IT8772E, IT8781F, IT8782F, IT8783E/F, IT8786E, IT8790E, and SiS950 +chips. These chips are 'Super I/O chips', supporting floppy disks, infrared ports, joysticks and other miscellaneous stuff. For hardware monitoring, they @@ -145,6 +150,8 @@ The IT8603E/IT8623E is a custom design, hardware monitoring part is similar to IT8728F. It only supports 16-bit fan mode, the full speed mode of the fan is not supported (value 0 of pwmX_enable). +The IT8790E supports up to 3 fans. 16-bit fan mode is always enabled. + Temperatures are measured in degrees Celsius. An alarm is triggered once when the Overtemperature Shutdown limit is crossed. diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 8f73dccb75ac..848ddfe30ef8 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -600,8 +600,8 @@ config SENSORS_IT87 help If you say yes here you get support for ITE IT8705F, IT8712F, IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E, - IT8771E, IT8772E, IT8781F, IT8782F, IT8783E/F, IT8786E, - and IT8603E sensor chips, and the SiS950 clone. + IT8771E, IT8772E, IT8781F, IT8782F, IT8783E/F, IT8786E, IT8790E, + IT8603E, and IT8623E sensor chips, and the SiS950 clone. This driver can also be built as a module. If so, the module will be called it87. diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index 9f4c662c5905..80580cdf9a15 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -27,6 +27,7 @@ * IT8782F Super I/O chip w/LPC interface * IT8783E/F Super I/O chip w/LPC interface * IT8786E Super I/O chip w/LPC interface + * IT8790E Super I/O chip w/LPC interface * Sis950 A clone of the IT8705F * * Copyright (C) 2001 Chris Gauthron @@ -68,7 +69,7 @@ #define DRVNAME "it87" enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8771, - it8772, it8781, it8782, it8783, it8786, it8603 }; + it8772, it8781, it8782, it8783, it8786, it8790, it8603 }; static unsigned short force_id; module_param(force_id, ushort, 0); @@ -152,6 +153,7 @@ static inline void superio_exit(void) #define IT8782F_DEVID 0x8782 #define IT8783E_DEVID 0x8783 #define IT8786E_DEVID 0x8786 +#define IT8790E_DEVID 0x8790 #define IT8603E_DEVID 0x8603 #define IT8623E_DEVID 0x8623 #define IT87_ACT_REG 0x30 @@ -359,6 +361,13 @@ static const struct it87_devices it87_devices[] = { | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL, .peci_mask = 0x07, }, + [it8790] = { + .name = "it8790", + .suffix = "E", + .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS + | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL, + .peci_mask = 0x07, + }, [it8603] = { .name = "it8603", .suffix = "E", @@ -1834,6 +1843,9 @@ static int __init it87_find(unsigned short *address, case IT8786E_DEVID: sio_data->type = it8786; break; + case IT8790E_DEVID: + sio_data->type = it8790; + break; case IT8603E_DEVID: case IT8623E_DEVID: sio_data->type = it8603; -- cgit v1.2.3-59-g8ed1b From 3ba9d977a9b8a90c586f46444448d977bdbdcc3b Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Fri, 13 Feb 2015 20:13:20 -0800 Subject: hwmon: (it87) Add support for IT8620E IT8620E is mostly compatible to IT7828F. Add generic support for it. IT8620E supports up to 6 fan tachometers and 6 pwm controls. Support for the 6th tachometer and for the additional pwm controls are addded in separate patches. Reviewed-by: Jean Delvare Signed-off-by: Guenter Roeck --- Documentation/hwmon/it87 | 13 ++++++++++--- drivers/hwmon/Kconfig | 2 +- drivers/hwmon/it87.c | 43 ++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 53 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/hwmon/it87 b/Documentation/hwmon/it87 index 91e8f011dacf..e87294878334 100644 --- a/Documentation/hwmon/it87 +++ b/Documentation/hwmon/it87 @@ -6,6 +6,10 @@ Supported chips: Prefix: 'it8603' Addresses scanned: from Super I/O config space (8 I/O ports) Datasheet: Not publicly available + * IT8620E + Prefix: 'it8620' + Addresses scanned: from Super I/O config space (8 I/O ports) + Datasheet: Not publicly available * IT8705F Prefix: 'it87' Addresses scanned: from Super I/O config space (8 I/O ports) @@ -106,7 +110,7 @@ motherboard models. Description ----------- -This driver implements support for the IT8603E, IT8623E, IT8705F, +This driver implements support for the IT8603E, IT8620E, IT8623E, IT8705F, IT8712F, IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E, IT8771E, IT8772E, IT8781F, IT8782F, IT8783E/F, IT8786E, IT8790E, and SiS950 chips. @@ -147,8 +151,11 @@ The IT8728F, IT8771E, and IT8772E are considered compatible with the IT8721F, until a datasheet becomes available (hopefully.) The IT8603E/IT8623E is a custom design, hardware monitoring part is similar to -IT8728F. It only supports 16-bit fan mode, the full speed mode of the -fan is not supported (value 0 of pwmX_enable). +IT8728F. It only supports 3 fans, 16-bit fan mode, and the full speed mode +of the fan is not supported (value 0 of pwmX_enable). + +The IT8620E is another custom design, hardware monitoring part is similar to +IT8728F. It only supports 16-bit fan mode. The IT8790E supports up to 3 fans. 16-bit fan mode is always enabled. diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 848ddfe30ef8..25d9e72627e9 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -601,7 +601,7 @@ config SENSORS_IT87 If you say yes here you get support for ITE IT8705F, IT8712F, IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E, IT8771E, IT8772E, IT8781F, IT8782F, IT8783E/F, IT8786E, IT8790E, - IT8603E, and IT8623E sensor chips, and the SiS950 clone. + IT8603E, IT8620E, and IT8623E sensor chips, and the SiS950 clone. This driver can also be built as a module. If so, the module will be called it87. diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index 80580cdf9a15..4e4db72d38e8 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -11,6 +11,7 @@ * similar parts. The other devices are supported by different drivers. * * Supports: IT8603E Super I/O chip w/LPC interface + * IT8620E Super I/O chip w/LPC interface * IT8623E Super I/O chip w/LPC interface * IT8705F Super I/O chip w/LPC interface * IT8712F Super I/O chip w/LPC interface @@ -69,7 +70,7 @@ #define DRVNAME "it87" enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8771, - it8772, it8781, it8782, it8783, it8786, it8790, it8603 }; + it8772, it8781, it8782, it8783, it8786, it8790, it8603, it8620 }; static unsigned short force_id; module_param(force_id, ushort, 0); @@ -155,12 +156,14 @@ static inline void superio_exit(void) #define IT8786E_DEVID 0x8786 #define IT8790E_DEVID 0x8790 #define IT8603E_DEVID 0x8603 +#define IT8620E_DEVID 0x8620 #define IT8623E_DEVID 0x8623 #define IT87_ACT_REG 0x30 #define IT87_BASE_REG 0x60 /* Logical device 7 registers (IT8712F and later) */ #define IT87_SIO_GPIO1_REG 0x25 +#define IT87_SIO_GPIO2_REG 0x26 #define IT87_SIO_GPIO3_REG 0x27 #define IT87_SIO_GPIO5_REG 0x29 #define IT87_SIO_PINX1_REG 0x2a /* Pin selection */ @@ -375,6 +378,14 @@ static const struct it87_devices it87_devices[] = { | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL, .peci_mask = 0x07, }, + [it8620] = { + .name = "it8620", + .suffix = "E", + .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS + | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_FIVE_FANS + | FEAT_IN7_INTERNAL, + .peci_mask = 0x07, + }, }; #define has_16bit_fans(data) ((data)->features & FEAT_16BIT_FANS) @@ -1850,6 +1861,9 @@ static int __init it87_find(unsigned short *address, case IT8623E_DEVID: sio_data->type = it8603; break; + case IT8620E_DEVID: + sio_data->type = it8620; + break; case 0xffff: /* No device at all */ goto exit; default: @@ -1984,6 +1998,33 @@ static int __init it87_find(unsigned short *address, sio_data->internal |= (1 << 3); /* in9 is AVCC */ + sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f; + } else if (sio_data->type == it8620) { + int reg; + + superio_select(GPIO); + + /* Check for fan4, fan5 */ + reg = superio_inb(IT87_SIO_GPIO2_REG); + if (!(reg & (1 << 5))) + sio_data->skip_fan |= (1 << 3); + if (!(reg & (1 << 4))) + sio_data->skip_fan |= (1 << 4); + + /* Check for pwm3, fan3 */ + reg = superio_inb(IT87_SIO_GPIO3_REG); + if (reg & (1 << 6)) + sio_data->skip_pwm |= (1 << 2); + if (reg & (1 << 7)) + sio_data->skip_fan |= (1 << 2); + + /* Check for pwm2, fan2 */ + reg = superio_inb(IT87_SIO_GPIO5_REG); + if (reg & (1 << 1)) + sio_data->skip_pwm |= (1 << 1); + if (reg & (1 << 2)) + sio_data->skip_fan |= (1 << 1); + sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f; } else { int reg; -- cgit v1.2.3-59-g8ed1b From 0db739fa06f95a040313c4479e1940caeb48e92f Mon Sep 17 00:00:00 2001 From: Moritz Fischer Date: Wed, 11 Mar 2015 17:37:19 -0700 Subject: dt: power: Add docs for generic SYSCON poweroff driver. Add documentation for generic SYSCON poweroff driver. Signed-off-by: Moritz Fischer Signed-off-by: Sebastian Reichel --- .../bindings/power/reset/syscon-poweroff.txt | 23 ++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 Documentation/devicetree/bindings/power/reset/syscon-poweroff.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/power/reset/syscon-poweroff.txt b/Documentation/devicetree/bindings/power/reset/syscon-poweroff.txt new file mode 100644 index 000000000000..1e2546f8b08a --- /dev/null +++ b/Documentation/devicetree/bindings/power/reset/syscon-poweroff.txt @@ -0,0 +1,23 @@ +Generic SYSCON mapped register poweroff driver + +This is a generic poweroff driver using syscon to map the poweroff register. +The poweroff is generally performed with a write to the poweroff register +defined by the register map pointed by syscon reference plus the offset +with the mask defined in the poweroff node. + +Required properties: +- compatible: should contain "syscon-poweroff" +- regmap: this is phandle to the register map node +- offset: offset in the register map for the poweroff register (in bytes) +- mask: the poweroff value written to the poweroff register (32 bit access) + +Default will be little endian mode, 32 bit access only. + +Examples: + + poweroff { + compatible = "syscon-poweroff"; + regmap = <®mapnode>; + offset = <0x0>; + mask = <0x7a>; + }; -- cgit v1.2.3-59-g8ed1b From c1c14957afd3026dcbc2e7ca599e6d035c7d8e01 Mon Sep 17 00:00:00 2001 From: Aaron Brice Date: Fri, 3 Apr 2015 13:39:30 -0700 Subject: spi: fsl-dspi: Add cs-sck delays Adding fsl,spi-cs-sck-delay and fsl,spi-sck-cs-delay properties to support delays before and after starting the clock in a transfer. Signed-off-by: Aaron Brice Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt b/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt index cbbe16ed3874..70af78a9185e 100644 --- a/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt +++ b/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt @@ -16,6 +16,12 @@ Optional property: in big endian mode, otherwise in native mode(same with CPU), for more detail please see: Documentation/devicetree/bindings/regmap/regmap.txt. +Optional SPI slave node properties: +- fsl,spi-cs-sck-delay: a delay in nanoseconds between activating chip + select and the start of clock signal, at the start of a transfer. +- fsl,spi-sck-cs-delay: a delay in nanoseconds between stopping the clock + signal and deactivating chip select, at the end of a transfer. + Example: dspi0@4002c000 { @@ -43,6 +49,8 @@ dspi0@4002c000 { reg = <0>; linux,modalias = "m25p80"; modal = "at26df081a"; + fsl,spi-cs-sck-delay = <100>; + fsl,spi-sck-cs-delay = <50>; }; }; -- cgit v1.2.3-59-g8ed1b From faa246debff1cfc0950f73c778f2db83451aa38b Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Thu, 19 Mar 2015 22:34:11 +0100 Subject: documentation: Extend pinctrl docs for Meson8b Add the compatible string for Meson8b in Meson pinctrl documentation and add new information for Meson8b in source code comments. Signed-off-by: Carlo Caione Acked-by: Beniamino Galvani Signed-off-by: Linus Walleij --- Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt | 2 +- drivers/pinctrl/meson/pinctrl-meson.c | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt index 17e7240c6998..3f6a524cc5ff 100644 --- a/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt +++ b/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt @@ -1,7 +1,7 @@ == Amlogic Meson pinmux controller == Required properties for the root node: - - compatible: "amlogic,meson8-pinctrl" + - compatible: "amlogic,meson8-pinctrl" or "amlogic,meson8b-pinctrl" - reg: address and size of registers controlling irq functionality === GPIO sub-nodes === diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c index a2bf49ce16e7..e0195c1081c4 100644 --- a/drivers/pinctrl/meson/pinctrl-meson.c +++ b/drivers/pinctrl/meson/pinctrl-meson.c @@ -13,8 +13,9 @@ /* * The available pins are organized in banks (A,B,C,D,E,X,Y,Z,AO, - * BOOT,CARD for meson6 and X,Y,DV,H,Z,AO,BOOT,CARD for meson8) and - * each bank has a variable number of pins. + * BOOT,CARD for meson6, X,Y,DV,H,Z,AO,BOOT,CARD for meson8 and + * X,Y,DV,H,AO,BOOT,CARD,DIF for meson8b) and each bank has a + * variable number of pins. * * The AO bank is special because it belongs to the Always-On power * domain which can't be powered off; the bank also uses a set of -- cgit v1.2.3-59-g8ed1b From 9b5c352e5425622b4371387d4718060da5d3ae32 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 7 Apr 2015 11:34:51 +0100 Subject: ASoC: wm8804: Update binding documentation to include reset GPIO Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/wm8804.txt | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/wm8804.txt b/Documentation/devicetree/bindings/sound/wm8804.txt index 10ef07606b84..6fd124b16496 100644 --- a/Documentation/devicetree/bindings/sound/wm8804.txt +++ b/Documentation/devicetree/bindings/sound/wm8804.txt @@ -13,6 +13,10 @@ Required properties: - PVDD-supply, DVDD-supply : Power supplies for the device, as covered in Documentation/devicetree/bindings/regulator/regulator.txt +Optional properties: + + - wlf,reset-gpio: A GPIO specifier for the GPIO controlling the reset pin + Example: codec: wm8804@1a { -- cgit v1.2.3-59-g8ed1b From cec656501fc20a5d1b20a43cfa4679705fa7e1ef Mon Sep 17 00:00:00 2001 From: Andrew Bresticker Date: Mon, 30 Mar 2015 16:16:54 -0700 Subject: pinctrl: Document "function" + "pins" pinmux binding Currently the "function" + "groups" combination is the only documented format for pinmux nodes, although many drivers use "function" + "pins". Update the generic pinctrl binding to include the "function" + "pins" combination as well. Signed-off-by: Andrew Bresticker Cc: Rob Herring Cc: Pawel Moll Cc: Mark Rutland Cc: Ian Campbell Cc: Kumar Gala Signed-off-by: Linus Walleij --- Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt index e9ebe5d35835..b73c96d24f59 100644 --- a/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt +++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt @@ -133,6 +133,9 @@ pin multiplexing nodes: function - the mux function to select groups - the list of groups to select with this function + (either this or "pins" must be specified) +pins - the list of pins to select with this function (either + this or "groups" must be specified) Example: @@ -148,6 +151,10 @@ state_1_node_a { groups = "spi0pins"; }; }; +state_2_node_a { + function = "i2c0"; + pins = "mfio29", "mfio30"; +}; == Generic pin configuration node content == -- cgit v1.2.3-59-g8ed1b From 2771d00081a4e70f52a9b290dae1b68b1bdf41f6 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 18 Mar 2015 19:42:41 +0100 Subject: thermal: rcar: Fix typo in r8a73a4 SoC name r8a73a4 is R-Mobile APE6, not AP6. Signed-off-by: Geert Uytterhoeven Signed-off-by: Eduardo Valentin --- Documentation/devicetree/bindings/thermal/rcar-thermal.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/thermal/rcar-thermal.txt b/Documentation/devicetree/bindings/thermal/rcar-thermal.txt index 43404b197933..332e625f6ed0 100644 --- a/Documentation/devicetree/bindings/thermal/rcar-thermal.txt +++ b/Documentation/devicetree/bindings/thermal/rcar-thermal.txt @@ -4,7 +4,7 @@ Required properties: - compatible : "renesas,thermal-", "renesas,rcar-thermal" as fallback. Examples with soctypes are: - - "renesas,thermal-r8a73a4" (R-Mobile AP6) + - "renesas,thermal-r8a73a4" (R-Mobile APE6) - "renesas,thermal-r8a7779" (R-Car H1) - "renesas,thermal-r8a7790" (R-Car H2) - "renesas,thermal-r8a7791" (R-Car M2-W) -- cgit v1.2.3-59-g8ed1b From fab43ef4c8b825d8cbe05e8f70c9138de1951980 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 3 Apr 2015 23:23:34 +0100 Subject: DOC: kernel-parameters.txt: Mark `nofpu' for MIPS too The MIPS port has supported this option since forever, long before SH was even in plans. Signed-off-by: Maciej W. Rozycki Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/9665/ Signed-off-by: Ralf Baechle --- Documentation/kernel-parameters.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index bfcb1a62a7b4..f23384402ee4 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -2315,7 +2315,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted. noexec32=off: disable non-executable mappings read implies executable mappings - nofpu [SH] Disable hardware FPU at boot time. + nofpu [MIPS,SH] Disable hardware FPU at boot time. nofxsr [BUGS=X86-32] Disables x86 floating point extended register save and restore. The kernel will only save -- cgit v1.2.3-59-g8ed1b From 7414b0993cd020aea14574065c28b55f3f849688 Mon Sep 17 00:00:00 2001 From: "Ivan T. Ivanov" Date: Tue, 31 Mar 2015 12:37:18 +0300 Subject: pinctrl: Add support for PM8916 GPIO's and MPP's Add compatible string definitions and supported pin functions. Signed-off-by: Ivan T. Ivanov Acked-by: Bjorn Andersson Signed-off-by: Linus Walleij --- .../devicetree/bindings/pinctrl/qcom,pmic-gpio.txt | 2 ++ .../devicetree/bindings/pinctrl/qcom,pmic-mpp.txt | 2 ++ drivers/pinctrl/qcom/pinctrl-spmi-gpio.c | 1 + drivers/pinctrl/qcom/pinctrl-spmi-mpp.c | 1 + include/dt-bindings/pinctrl/qcom,pmic-gpio.h | 15 +++++++++++++++ include/dt-bindings/pinctrl/qcom,pmic-mpp.h | 4 ++++ 6 files changed, 25 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.txt b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.txt index 7ed08048516a..1ae63c0acd40 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.txt +++ b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.txt @@ -10,6 +10,7 @@ PMIC's from Qualcomm. "qcom,pm8018-gpio" "qcom,pm8038-gpio" "qcom,pm8058-gpio" + "qcom,pm8916-gpio" "qcom,pm8917-gpio" "qcom,pm8921-gpio" "qcom,pm8941-gpio" @@ -74,6 +75,7 @@ to specify in a pin configuration subnode: gpio1-gpio6 for pm8018 gpio1-gpio12 for pm8038 gpio1-gpio40 for pm8058 + gpio1-gpio4 for pm8916 gpio1-gpio38 for pm8917 gpio1-gpio44 for pm8921 gpio1-gpio36 for pm8941 diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt index 854774b194ed..ed19991aad35 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt +++ b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt @@ -8,6 +8,7 @@ of PMIC's from Qualcomm. Value type: Definition: Should contain one of: "qcom,pm8841-mpp", + "qcom,pm8916-mpp", "qcom,pm8941-mpp", "qcom,pma8084-mpp", @@ -67,6 +68,7 @@ to specify in a pin configuration subnode: Definition: List of MPP pins affected by the properties specified in this subnode. Valid pins are: mpp1-mpp4 for pm8841 + mpp1-mpp4 for pm8916 mpp1-mpp8 for pm8941 mpp1-mpp4 for pma8084 diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c index 0f11a26d932b..b2d22218a258 100644 --- a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c +++ b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c @@ -810,6 +810,7 @@ static int pmic_gpio_remove(struct platform_device *pdev) } static const struct of_device_id pmic_gpio_of_match[] = { + { .compatible = "qcom,pm8916-gpio" }, /* 4 GPIO's */ { .compatible = "qcom,pm8941-gpio" }, /* 36 GPIO's */ { .compatible = "qcom,pma8084-gpio" }, /* 22 GPIO's */ { }, diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c index a8924dba335e..8f36c5f91949 100644 --- a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c +++ b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c @@ -925,6 +925,7 @@ static int pmic_mpp_remove(struct platform_device *pdev) static const struct of_device_id pmic_mpp_of_match[] = { { .compatible = "qcom,pm8841-mpp" }, /* 4 MPP's */ + { .compatible = "qcom,pm8916-mpp" }, /* 4 MPP's */ { .compatible = "qcom,pm8941-mpp" }, /* 8 MPP's */ { .compatible = "qcom,pma8084-mpp" }, /* 8 MPP's */ { }, diff --git a/include/dt-bindings/pinctrl/qcom,pmic-gpio.h b/include/dt-bindings/pinctrl/qcom,pmic-gpio.h index fa74d7cc960c..aafa76cb569d 100644 --- a/include/dt-bindings/pinctrl/qcom,pmic-gpio.h +++ b/include/dt-bindings/pinctrl/qcom,pmic-gpio.h @@ -48,6 +48,14 @@ #define PM8058_GPIO_L5 6 #define PM8058_GPIO_L2 7 +/* + * Note: PM8916 GPIO1 and GPIO2 are supporting + * only L2(1.15V) and L5(1.8V) options + */ +#define PM8916_GPIO_VPH 0 +#define PM8916_GPIO_L2 2 +#define PM8916_GPIO_L5 3 + #define PM8917_GPIO_VPH 0 #define PM8917_GPIO_S4 2 #define PM8917_GPIO_L15 3 @@ -115,6 +123,13 @@ #define PM8058_GPIO39_MP3_CLK PMIC_GPIO_FUNC_FUNC1 #define PM8058_GPIO40_EXT_BB_EN PMIC_GPIO_FUNC_FUNC1 +#define PM8916_GPIO1_BAT_ALRM_OUT PMIC_GPIO_FUNC_FUNC1 +#define PM8916_GPIO1_KEYP_DRV PMIC_GPIO_FUNC_FUNC2 +#define PM8916_GPIO2_DIV_CLK PMIC_GPIO_FUNC_FUNC1 +#define PM8916_GPIO2_SLEEP_CLK PMIC_GPIO_FUNC_FUNC2 +#define PM8916_GPIO3_KEYP_DRV PMIC_GPIO_FUNC_FUNC1 +#define PM8916_GPIO4_KEYP_DRV PMIC_GPIO_FUNC_FUNC2 + #define PM8917_GPIO9_18_KEYP_DRV PMIC_GPIO_FUNC_FUNC1 #define PM8917_GPIO20_BAT_ALRM_OUT PMIC_GPIO_FUNC_FUNC1 #define PM8917_GPIO21_23_UART_TX PMIC_GPIO_FUNC_FUNC2 diff --git a/include/dt-bindings/pinctrl/qcom,pmic-mpp.h b/include/dt-bindings/pinctrl/qcom,pmic-mpp.h index d2c7dabe3223..c10205491f8d 100644 --- a/include/dt-bindings/pinctrl/qcom,pmic-mpp.h +++ b/include/dt-bindings/pinctrl/qcom,pmic-mpp.h @@ -10,6 +10,10 @@ #define PM8841_MPP_VPH 0 #define PM8841_MPP_S3 2 +#define PM8916_MPP_VPH 0 +#define PM8916_MPP_L2 2 +#define PM8916_MPP_L5 3 + #define PM8941_MPP_VPH 0 #define PM8941_MPP_L1 1 #define PM8941_MPP_S3 2 -- cgit v1.2.3-59-g8ed1b From 5f9755d26fbfcb6787a6746653f1760fef0d5ba5 Mon Sep 17 00:00:00 2001 From: Andrew Bresticker Date: Tue, 7 Apr 2015 13:38:45 -0700 Subject: stmmac: Add an optional register interface clock The DWMAC block on certain SoCs (such as IMG Pistachio) have a second clock which must be enabled in order to access the peripheral's register interface, so add support for requesting and enabling an optional "pclk". Signed-off-by: Andrew Bresticker Cc: James Hartley Cc: Arnd Bergmann Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/stmmac.txt | 7 ++++--- drivers/net/ethernet/stmicro/stmmac/stmmac.h | 1 + drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 15 +++++++++++++++ 3 files changed, 20 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/stmmac.txt b/Documentation/devicetree/bindings/net/stmmac.txt index 8ca65cec52ae..29aca8591b16 100644 --- a/Documentation/devicetree/bindings/net/stmmac.txt +++ b/Documentation/devicetree/bindings/net/stmmac.txt @@ -35,10 +35,11 @@ Optional properties: - reset-names: Should contain the reset signal name "stmmaceth", if a reset phandle is given - max-frame-size: See ethernet.txt file in the same directory -- clocks: If present, the first clock should be the GMAC main clock, - further clocks may be specified in derived bindings. +- clocks: If present, the first clock should be the GMAC main clock and + the second clock should be peripheral's register interface clock. Further + clocks may be specified in derived bindings. - clock-names: One name for each entry in the clocks property, the - first one should be "stmmaceth". + first one should be "stmmaceth" and the second one should be "pclk". - clk_ptp_ref: this is the PTP reference clock; in case of the PTP is available this clock is used for programming the Timestamp Addend Register. If not passed then the system clock will be used and this is fine on some diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index c0a391983372..2ac9552d1fa3 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -97,6 +97,7 @@ struct stmmac_priv { int wolopts; int wol_irq; struct clk *stmmac_clk; + struct clk *pclk; struct reset_control *stmmac_rst; int clk_csr; struct timer_list eee_ctrl_timer; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 5336594abed1..06103cad7c77 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -2849,6 +2849,16 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device, } clk_prepare_enable(priv->stmmac_clk); + priv->pclk = devm_clk_get(priv->device, "pclk"); + if (IS_ERR(priv->pclk)) { + if (PTR_ERR(priv->pclk) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto error_pclk_get; + } + priv->pclk = NULL; + } + clk_prepare_enable(priv->pclk); + priv->stmmac_rst = devm_reset_control_get(priv->device, STMMAC_RESOURCE_NAME); if (IS_ERR(priv->stmmac_rst)) { @@ -2934,6 +2944,8 @@ error_mdio_register: error_netdev_register: netif_napi_del(&priv->napi); error_hw_init: + clk_disable_unprepare(priv->pclk); +error_pclk_get: clk_disable_unprepare(priv->stmmac_clk); error_clk_get: free_netdev(ndev); @@ -2965,6 +2977,7 @@ int stmmac_dvr_remove(struct net_device *ndev) unregister_netdev(ndev); if (priv->stmmac_rst) reset_control_assert(priv->stmmac_rst); + clk_disable_unprepare(priv->pclk); clk_disable_unprepare(priv->stmmac_clk); free_netdev(ndev); @@ -3011,6 +3024,7 @@ int stmmac_suspend(struct net_device *ndev) stmmac_set_mac(priv->ioaddr, false); pinctrl_pm_select_sleep_state(priv->device); /* Disable clock in case of PWM is off */ + clk_disable(priv->pclk); clk_disable(priv->stmmac_clk); } spin_unlock_irqrestore(&priv->lock, flags); @@ -3051,6 +3065,7 @@ int stmmac_resume(struct net_device *ndev) pinctrl_pm_select_default_state(priv->device); /* enable the clk prevously disabled */ clk_enable(priv->stmmac_clk); + clk_enable(priv->pclk); /* reset the phy so that it's ready */ if (priv->mii) stmmac_mdio_reset(priv->mii); -- cgit v1.2.3-59-g8ed1b From ebe96e641dee2cbd135ee802ae7e40c361640088 Mon Sep 17 00:00:00 2001 From: Sowmini Varadhan Date: Wed, 8 Apr 2015 12:33:45 -0400 Subject: RDS: Documentation: Document AF_RDS, PF_RDS and SOL_RDS correctly. AF_RDS, PF_RDS and SOL_RDS are available in header files, and there is no need to get their values from /proc. Document this correctly. Fixes: 0c5f9b8830aa ("RDS: Documentation") Signed-off-by: Sowmini Varadhan Signed-off-by: David S. Miller --- Documentation/networking/rds.txt | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/rds.txt b/Documentation/networking/rds.txt index c67077cbeb80..e1a3d59bbe0f 100644 --- a/Documentation/networking/rds.txt +++ b/Documentation/networking/rds.txt @@ -62,11 +62,10 @@ Socket Interface ================ AF_RDS, PF_RDS, SOL_RDS - These constants haven't been assigned yet, because RDS isn't in - mainline yet. Currently, the kernel module assigns some constant - and publishes it to user space through two sysctl files - /proc/sys/net/rds/pf_rds - /proc/sys/net/rds/sol_rds + AF_RDS and PF_RDS are the domain type to be used with socket(2) + to create RDS sockets. SOL_RDS is the socket-level to be used + with setsockopt(2) and getsockopt(2) for RDS specific socket + options. fd = socket(PF_RDS, SOCK_SEQPACKET, 0); This creates a new, unbound RDS socket. -- cgit v1.2.3-59-g8ed1b From 1b55d62259187fe77ade87dccc33522d51f113ee Mon Sep 17 00:00:00 2001 From: Ray Jui Date: Wed, 8 Apr 2015 11:21:34 -0700 Subject: PCI: iproc: Add DT docs for Broadcom iProc PCIe driver Document the Broadcom iProc PCIe platform interface device tree binding. Signed-off-by: Ray Jui Signed-off-by: Bjorn Helgaas Reviewed-by: Scott Branden Acked-by: Arnd Bergmann --- .../devicetree/bindings/pci/brcm,iproc-pcie.txt | 63 ++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt b/Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt new file mode 100644 index 000000000000..f7ce50e38ed4 --- /dev/null +++ b/Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt @@ -0,0 +1,63 @@ +* Broadcom iProc PCIe controller with the platform bus interface + +Required properties: +- compatible: Must be "brcm,iproc-pcie" +- reg: base address and length of the PCIe controller I/O register space +- #interrupt-cells: set to <1> +- interrupt-map-mask and interrupt-map, standard PCI properties to define the + mapping of the PCIe interface to interrupt numbers +- linux,pci-domain: PCI domain ID. Should be unique for each host controller +- bus-range: PCI bus numbers covered +- #address-cells: set to <3> +- #size-cells: set to <2> +- device_type: set to "pci" +- ranges: ranges for the PCI memory and I/O regions + +Optional properties: +- phys: phandle of the PCIe PHY device +- phy-names: must be "pcie-phy" + +Example: + pcie0: pcie@18012000 { + compatible = "brcm,iproc-pcie"; + reg = <0x18012000 0x1000>; + + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &gic GIC_SPI 100 IRQ_TYPE_NONE>; + + linux,pci-domain = <0>; + + bus-range = <0x00 0xff>; + + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + ranges = <0x81000000 0 0 0x28000000 0 0x00010000 + 0x82000000 0 0x20000000 0x20000000 0 0x04000000>; + + phys = <&phy 0 5>; + phy-names = "pcie-phy"; + }; + + pcie1: pcie@18013000 { + compatible = "brcm,iproc-pcie"; + reg = <0x18013000 0x1000>; + + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &gic GIC_SPI 106 IRQ_TYPE_NONE>; + + linux,pci-domain = <1>; + + bus-range = <0x00 0xff>; + + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + ranges = <0x81000000 0 0 0x48000000 0 0x00010000 + 0x82000000 0 0x40000000 0x40000000 0 0x04000000>; + + phys = <&phy 1 6>; + phy-names = "pcie-phy"; + }; -- cgit v1.2.3-59-g8ed1b From 8c2c8c03cdcb9b0a75b5585e611715fdd8096c38 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Wed, 8 Apr 2015 10:03:16 -0700 Subject: spi: img-spfi: Control CS lines with GPIO When the CONTINUE bit is set, the interrupt status we are polling to identify if a transaction has finished can be sporadic. Even though the transfer has finished, the interrupt status may erroneously indicate that there is still data in the FIFO. This behaviour causes random timeouts in large PIO transfers. Instead of using the CONTINUE bit to control the CS lines, use the SPI core's CS GPIO handling. Also, now that the CONTINUE bit is not being used, we can poll for the ALLDONE interrupt to indicate transfer completion. Signed-off-by: Sifan Naeem Signed-off-by: Ezequiel Garcia Signed-off-by: Andrew Bresticker Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/spi-img-spfi.txt | 1 + drivers/spi/spi-img-spfi.c | 92 +++++++++++----------- 2 files changed, 45 insertions(+), 48 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/spi/spi-img-spfi.txt b/Documentation/devicetree/bindings/spi/spi-img-spfi.txt index c7dd50fb8eb2..e02fbf18c82c 100644 --- a/Documentation/devicetree/bindings/spi/spi-img-spfi.txt +++ b/Documentation/devicetree/bindings/spi/spi-img-spfi.txt @@ -14,6 +14,7 @@ Required properties: - dma-names: Must include the following entries: - rx - tx +- cs-gpios: Must specify the GPIOs used for chipselect lines. - #address-cells: Must be 1. - #size-cells: Must be 0. diff --git a/drivers/spi/spi-img-spfi.c b/drivers/spi/spi-img-spfi.c index dedb7d880ccc..788e2b176a4f 100644 --- a/drivers/spi/spi-img-spfi.c +++ b/drivers/spi/spi-img-spfi.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -122,35 +123,31 @@ static inline void spfi_start(struct img_spfi *spfi) spfi_writel(spfi, val, SPFI_CONTROL); } -static inline void spfi_stop(struct img_spfi *spfi) -{ - u32 val; - - val = spfi_readl(spfi, SPFI_CONTROL); - val &= ~SPFI_CONTROL_SPFI_EN; - spfi_writel(spfi, val, SPFI_CONTROL); -} - static inline void spfi_reset(struct img_spfi *spfi) { spfi_writel(spfi, SPFI_CONTROL_SOFT_RESET, SPFI_CONTROL); spfi_writel(spfi, 0, SPFI_CONTROL); } -static void spfi_flush_tx_fifo(struct img_spfi *spfi) +static int spfi_wait_all_done(struct img_spfi *spfi) { - unsigned long timeout = jiffies + msecs_to_jiffies(10); + unsigned long timeout = jiffies + msecs_to_jiffies(50); - spfi_writel(spfi, SPFI_INTERRUPT_SDE, SPFI_INTERRUPT_CLEAR); while (time_before(jiffies, timeout)) { - if (spfi_readl(spfi, SPFI_INTERRUPT_STATUS) & - SPFI_INTERRUPT_SDE) - return; + u32 status = spfi_readl(spfi, SPFI_INTERRUPT_STATUS); + + if (status & SPFI_INTERRUPT_ALLDONETRIG) { + spfi_writel(spfi, SPFI_INTERRUPT_ALLDONETRIG, + SPFI_INTERRUPT_CLEAR); + return 0; + } cpu_relax(); } - dev_err(spfi->dev, "Timed out waiting for FIFO to drain\n"); + dev_err(spfi->dev, "Timed out waiting for transaction to complete\n"); spfi_reset(spfi); + + return -ETIMEDOUT; } static unsigned int spfi_pio_write32(struct img_spfi *spfi, const u32 *buf, @@ -236,6 +233,7 @@ static int img_spfi_start_pio(struct spi_master *master, const void *tx_buf = xfer->tx_buf; void *rx_buf = xfer->rx_buf; unsigned long timeout; + int ret; if (tx_buf) tx_bytes = xfer->len; @@ -268,15 +266,15 @@ static int img_spfi_start_pio(struct spi_master *master, cpu_relax(); } + ret = spfi_wait_all_done(spfi); + if (ret < 0) + return ret; + if (rx_bytes > 0 || tx_bytes > 0) { dev_err(spfi->dev, "PIO transfer timed out\n"); return -ETIMEDOUT; } - if (tx_buf) - spfi_flush_tx_fifo(spfi); - spfi_stop(spfi); - return 0; } @@ -285,14 +283,12 @@ static void img_spfi_dma_rx_cb(void *data) struct img_spfi *spfi = data; unsigned long flags; - spin_lock_irqsave(&spfi->lock, flags); + spfi_wait_all_done(spfi); + spin_lock_irqsave(&spfi->lock, flags); spfi->rx_dma_busy = false; - if (!spfi->tx_dma_busy) { - spfi_stop(spfi); + if (!spfi->tx_dma_busy) spi_finalize_current_transfer(spfi->master); - } - spin_unlock_irqrestore(&spfi->lock, flags); } @@ -301,16 +297,12 @@ static void img_spfi_dma_tx_cb(void *data) struct img_spfi *spfi = data; unsigned long flags; - spfi_flush_tx_fifo(spfi); + spfi_wait_all_done(spfi); spin_lock_irqsave(&spfi->lock, flags); - spfi->tx_dma_busy = false; - if (!spfi->rx_dma_busy) { - spfi_stop(spfi); + if (!spfi->rx_dma_busy) spi_finalize_current_transfer(spfi->master); - } - spin_unlock_irqrestore(&spfi->lock, flags); } @@ -445,6 +437,25 @@ static int img_spfi_unprepare(struct spi_master *master, return 0; } +static int img_spfi_setup(struct spi_device *spi) +{ + int ret; + + ret = gpio_request_one(spi->cs_gpio, (spi->mode & SPI_CS_HIGH) ? + GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH, + dev_name(&spi->dev)); + if (ret) + dev_err(&spi->dev, "can't request chipselect gpio %d\n", + spi->cs_gpio); + + return ret; +} + +static void img_spfi_cleanup(struct spi_device *spi) +{ + gpio_free(spi->cs_gpio); +} + static void img_spfi_config(struct spi_master *master, struct spi_device *spi, struct spi_transfer *xfer) { @@ -480,10 +491,6 @@ static void img_spfi_config(struct spi_master *master, struct spi_device *spi, else if (xfer->tx_nbits == SPI_NBITS_QUAD && xfer->rx_nbits == SPI_NBITS_QUAD) val |= SPFI_CONTROL_TMODE_QUAD << SPFI_CONTROL_TMODE_SHIFT; - val &= ~SPFI_CONTROL_CONTINUE; - if (!xfer->cs_change && !list_is_last(&xfer->transfer_list, - &master->cur_msg->transfers)) - val |= SPFI_CONTROL_CONTINUE; spfi_writel(spfi, val, SPFI_CONTROL); } @@ -510,17 +517,6 @@ static int img_spfi_transfer_one(struct spi_master *master, return ret; } -static void img_spfi_set_cs(struct spi_device *spi, bool enable) -{ - struct img_spfi *spfi = spi_master_get_devdata(spi->master); - u32 val; - - val = spfi_readl(spfi, SPFI_PORT_STATE); - val &= ~(SPFI_PORT_STATE_DEV_SEL_MASK << SPFI_PORT_STATE_DEV_SEL_SHIFT); - val |= spi->chip_select << SPFI_PORT_STATE_DEV_SEL_SHIFT; - spfi_writel(spfi, val, SPFI_PORT_STATE); -} - static bool img_spfi_can_dma(struct spi_master *master, struct spi_device *spi, struct spi_transfer *xfer) { @@ -609,13 +605,13 @@ static int img_spfi_probe(struct platform_device *pdev) master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_TX_DUAL | SPI_RX_DUAL; if (of_property_read_bool(spfi->dev->of_node, "img,supports-quad-mode")) master->mode_bits |= SPI_TX_QUAD | SPI_RX_QUAD; - master->num_chipselect = 5; master->dev.of_node = pdev->dev.of_node; master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(8); master->max_speed_hz = clk_get_rate(spfi->spfi_clk) / 4; master->min_speed_hz = clk_get_rate(spfi->spfi_clk) / 512; - master->set_cs = img_spfi_set_cs; + master->setup = img_spfi_setup; + master->cleanup = img_spfi_cleanup; master->transfer_one = img_spfi_transfer_one; master->prepare_message = img_spfi_prepare; master->unprepare_message = img_spfi_unprepare; -- cgit v1.2.3-59-g8ed1b From 7a4580075d37d334b40f510cab54008d2dc66827 Mon Sep 17 00:00:00 2001 From: Sylvain Trias Date: Wed, 8 Apr 2015 10:27:57 +0200 Subject: Documentation/memory-barriers.txt: typo fix Fix an obvious typo in the documentation. Signed-off-by: Michael S. Tsirkin Signed-off-by: Jonathan Corbet --- Documentation/memory-barriers.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt index ca2387ef27ab..a3a94ff71a77 100644 --- a/Documentation/memory-barriers.txt +++ b/Documentation/memory-barriers.txt @@ -1711,7 +1711,7 @@ There are some more advanced barrier functions: } The dma_rmb() allows us guarantee the device has released ownership - before we read the data from the descriptor, and he dma_wmb() allows + before we read the data from the descriptor, and the dma_wmb() allows us to guarantee the data is written to the descriptor before the device can see it now has ownership. The wmb() is needed to guarantee that the cache coherent memory writes have completed before attempting a write to -- cgit v1.2.3-59-g8ed1b From 8d2f1a9d36f270b28cca960510f293f2b9eb905d Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Mon, 6 Apr 2015 16:33:56 -0700 Subject: mfd: devicetree: bindings: Add Qualcomm RPM regulator subnodes Add the regulator subnodes to the Qualcomm RPM MFD device tree bindings. Signed-off-by: Bjorn Andersson Reviewed-by: Stephen Boyd Signed-off-by: Lee Jones --- Documentation/devicetree/bindings/mfd/qcom-rpm.txt | 217 +++++++++++++++++++-- 1 file changed, 205 insertions(+), 12 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mfd/qcom-rpm.txt b/Documentation/devicetree/bindings/mfd/qcom-rpm.txt index 94d9ae8d5168..5e97a9593ad7 100644 --- a/Documentation/devicetree/bindings/mfd/qcom-rpm.txt +++ b/Documentation/devicetree/bindings/mfd/qcom-rpm.txt @@ -32,16 +32,6 @@ frequencies. Value type: Definition: must be the three strings "ack", "err" and "wakeup", in order -- #address-cells: - Usage: required - Value type: - Definition: must be 1 - -- #size-cells: - Usage: required - Value type: - Definition: must be 0 - - qcom,ipc: Usage: required Value type: @@ -53,6 +43,188 @@ frequencies. - u32 representing the ipc bit within the register += SUBNODES + +The RPM exposes resources to its subnodes. The below bindings specify the set +of valid subnodes that can operate on these resources. + +== Regulators + +Regulator nodes are identified by their compatible: + +- compatible: + Usage: required + Value type: + Definition: must be one of: + "qcom,rpm-pm8058-regulators" + "qcom,rpm-pm8901-regulators" + "qcom,rpm-pm8921-regulators" + +- vdd_l0_l1_lvs-supply: +- vdd_l2_l11_l12-supply: +- vdd_l3_l4_l5-supply: +- vdd_l6_l7-supply: +- vdd_l8-supply: +- vdd_l9-supply: +- vdd_l10-supply: +- vdd_l13_l16-supply: +- vdd_l14_l15-supply: +- vdd_l17_l18-supply: +- vdd_l19_l20-supply: +- vdd_l21-supply: +- vdd_l22-supply: +- vdd_l23_l24_l25-supply: +- vdd_ncp-supply: +- vdd_s0-supply: +- vdd_s1-supply: +- vdd_s2-supply: +- vdd_s3-supply: +- vdd_s4-supply: + Usage: optional (pm8058 only) + Value type: + Definition: reference to regulator supplying the input pin, as + described in the data sheet + +- lvs0_in-supply: +- lvs1_in-supply: +- lvs2_in-supply: +- lvs3_in-supply: +- mvs_in-supply: +- vdd_l0-supply: +- vdd_l1-supply: +- vdd_l2-supply: +- vdd_l3-supply: +- vdd_l4-supply: +- vdd_l5-supply: +- vdd_l6-supply: +- vdd_s0-supply: +- vdd_s1-supply: +- vdd_s2-supply: +- vdd_s3-supply: +- vdd_s4-supply: + Usage: optional (pm8901 only) + Value type: + Definition: reference to regulator supplying the input pin, as + described in the data sheet + +- vdd_l1_l2_l12_l18-supply: +- vdd_l3_l15_l17-supply: +- vdd_l4_l14-supply: +- vdd_l5_l8_l16-supply: +- vdd_l6_l7-supply: +- vdd_l9_l11-supply: +- vdd_l10_l22-supply: +- vdd_l21_l23_l29-supply: +- vdd_l24-supply: +- vdd_l25-supply: +- vdd_l26-supply: +- vdd_l27-supply: +- vdd_l28-supply: +- vdd_ncp-supply: +- vdd_s1-supply: +- vdd_s2-supply: +- vdd_s4-supply: +- vdd_s5-supply: +- vdd_s6-supply: +- vdd_s7-supply: +- vdd_s8-supply: +- vin_5vs-supply: +- vin_lvs1_3_6-supply: +- vin_lvs2-supply: +- vin_lvs4_5_7-supply: + Usage: optional (pm8921 only) + Value type: + Definition: reference to regulator supplying the input pin, as + described in the data sheet + +The regulator node houses sub-nodes for each regulator within the device. Each +sub-node is identified using the node's name, with valid values listed for each +of the pmics below. + +pm8058: + l0, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, + l16, l17, l18, l19, l20, l21, l22, l23, l24, l25, s0, s1, s2, s3, s4, + lvs0, lvs1, ncp + +pm8901: + l0, l1, l2, l3, l4, l5, l6, s0, s1, s2, s3, s4, lvs0, lvs1, lvs2, lvs3, + mvs + +pm8921: + s1, s2, s3, s4, s7, s8, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, + l12, l14, l15, l16, l17, l18, l21, l22, l23, l24, l25, l26, l27, l28, + l29, lvs1, lvs2, lvs3, lvs4, lvs5, lvs6, lvs7, usb-switch, hdmi-switch, + ncp + +The content of each sub-node is defined by the standard binding for regulators - +see regulator.txt - with additional custom properties described below: + +=== Switch-mode Power Supply regulator custom properties + +- bias-pull-down: + Usage: optional + Value type: + Definition: enable pull down of the regulator when inactive + +- qcom,switch-mode-frequency: + Usage: required + Value type: + Definition: Frequency (Hz) of the switch-mode power supply; + must be one of: + 19200000, 9600000, 6400000, 4800000, 3840000, 3200000, + 2740000, 2400000, 2130000, 1920000, 1750000, 1600000, + 1480000, 1370000, 1280000, 1200000 + +- qcom,force-mode: + Usage: optional (default if no other qcom,force-mode is specified) + Value type: + Defintion: indicates that the regulator should be forced to a + particular mode, valid values are: + QCOM_RPM_FORCE_MODE_NONE - do not force any mode + QCOM_RPM_FORCE_MODE_LPM - force into low power mode + QCOM_RPM_FORCE_MODE_HPM - force into high power mode + QCOM_RPM_FORCE_MODE_AUTO - allow regulator to automatically + select its own mode based on + realtime current draw, only for: + pm8921 smps and ftsmps + +- qcom,power-mode-hysteretic: + Usage: optional + Value type: + Definition: select that the power supply should operate in hysteretic + mode, instead of the default pwm mode + +=== Low-dropout regulator custom properties + +- bias-pull-down: + Usage: optional + Value type: + Definition: enable pull down of the regulator when inactive + +- qcom,force-mode: + Usage: optional + Value type: + Defintion: indicates that the regulator should not be forced to any + particular mode, valid values are: + QCOM_RPM_FORCE_MODE_NONE - do not force any mode + QCOM_RPM_FORCE_MODE_LPM - force into low power mode + QCOM_RPM_FORCE_MODE_HPM - force into high power mode + QCOM_RPM_FORCE_MODE_BYPASS - set regulator to use bypass + mode, i.e. to act as a switch + and not regulate, only for: + pm8921 pldo, nldo and nldo1200 + +=== Negative Charge Pump custom properties + +- qcom,switch-mode-frequency: + Usage: required + Value type: + Definition: Frequency (Hz) of the swith mode power supply; + must be one of: + 19200000, 9600000, 6400000, 4800000, 3840000, 3200000, + 2740000, 2400000, 2130000, 1920000, 1750000, 1600000, + 1480000, 1370000, 1280000, 1200000 + = EXAMPLE #include @@ -65,7 +237,28 @@ frequencies. interrupts = <0 19 0>, <0 21 0>, <0 22 0>; interrupt-names = "ack", "err", "wakeup"; - #address-cells = <1>; - #size-cells = <0>; + regulators { + compatible = "qcom,rpm-pm8921-regulators"; + vdd_l1_l2_l12_l18-supply = <&pm8921_s4>; + + s1 { + regulator-min-microvolt = <1225000>; + regulator-max-microvolt = <1225000>; + + bias-pull-down; + + qcom,switch-mode-frequency = <3200000>; + }; + + pm8921_s4: s4 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + qcom,switch-mode-frequency = <1600000>; + bias-pull-down; + + qcom,force-mode = ; + }; + }; }; -- cgit v1.2.3-59-g8ed1b From 37a9c502c0af013aaae094556830100c2bb133ac Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Mon, 30 Mar 2015 10:32:34 +0200 Subject: PCI: Clarify policy for vendor IDs in pci.txt Clarify pci.txt so it matches the "do not add new entries unless they are shared between multiple drivers" comment in include/linux/pci_ids.h. [bhelgaas: changelog, strengthen language] Signed-off-by: Michael S. Tsirkin Signed-off-by: Bjorn Helgaas --- Documentation/PCI/pci.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/PCI/pci.txt b/Documentation/PCI/pci.txt index 9518006f6675..123881f62219 100644 --- a/Documentation/PCI/pci.txt +++ b/Documentation/PCI/pci.txt @@ -564,14 +564,14 @@ to be handled by platform and generic code, not individual drivers. 8. Vendor and device identifications ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -One is not required to add new device ids to include/linux/pci_ids.h. -Please add PCI_VENDOR_ID_xxx for vendors and a hex constant for device ids. +Do not add new device or vendor IDs to include/linux/pci_ids.h unless they +are shared across multiple drivers. You can add private definitions in +your driver if they're helpful, or just use plain hex constants. -PCI_VENDOR_ID_xxx constants are re-used. The device ids are arbitrary -hex numbers (vendor controlled) and normally used only in a single -location, the pci_device_id table. +The device IDs are arbitrary hex numbers (vendor controlled) and normally used +only in a single location, the pci_device_id table. -Please DO submit new vendor/device ids to pciids.sourceforge.net project. +Please DO submit new vendor/device IDs to http://pciids.sourceforge.net/. -- cgit v1.2.3-59-g8ed1b From c0a34ebd43959ca83df86ba2ffc63ab0ddb2ea75 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 9 Apr 2015 21:02:02 -0700 Subject: igb: doc don't refer to ifconfig ifconfig command is obsolete, best to remove all references so that new users learn ip. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Kirsher --- Documentation/networking/igb.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/igb.txt b/Documentation/networking/igb.txt index 43d3549366a0..15534fdd09a8 100644 --- a/Documentation/networking/igb.txt +++ b/Documentation/networking/igb.txt @@ -42,10 +42,10 @@ Additional Configurations Jumbo Frames ------------ Jumbo Frames support is enabled by changing the MTU to a value larger than - the default of 1500. Use the ifconfig command to increase the MTU size. + the default of 1500. Use the ip command to increase the MTU size. For example: - ifconfig eth mtu 9000 up + ip link set dev eth mtu 9000 This setting is not saved across reboots. -- cgit v1.2.3-59-g8ed1b From d7018be0ae2aee988331d2908234d1a1ee3196ac Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 9 Apr 2015 22:03:21 -0700 Subject: ixgbe: fix documentation The MTU values in the documentation do not match the source. The source has frame limit of IXGBE_MAX_JUMBO_FRAME_SIZE (9728) which is MTU of 9710 because of the accounting for Ethernet header and CRC. Also, don't refer to the obsolete ifconfig command. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Kirsher --- Documentation/networking/ixgbe.txt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/ixgbe.txt b/Documentation/networking/ixgbe.txt index 0ace6e776ac8..6f0cb57b59c6 100644 --- a/Documentation/networking/ixgbe.txt +++ b/Documentation/networking/ixgbe.txt @@ -70,10 +70,10 @@ Avago 1000BASE-T SFP ABCU-5710RZ 82599-based adapters support all passive and active limiting direct attach cables that comply with SFF-8431 v4.1 and SFF-8472 v10.4 specifications. -Laser turns off for SFP+ when ifconfig down +Laser turns off for SFP+ when device is down ------------------------------------------- -"ifconfig down" turns off the laser for 82599-based SFP+ fiber adapters. -"ifconfig up" turns on the laser. +"ip link set down" turns off the laser for 82599-based SFP+ fiber adapters. +"ip link set up" turns on the laser. 82598-BASED ADAPTERS @@ -213,13 +213,13 @@ Additional Configurations ------------ The driver supports Jumbo Frames for all adapters. Jumbo Frames support is enabled by changing the MTU to a value larger than the default of 1500. - The maximum value for the MTU is 16110. Use the ifconfig command to + The maximum value for the MTU is 16110. Use the ip command to increase the MTU size. For example: - ifconfig ethx mtu 9000 up + ip link set dev ethx mtu 9000 - The maximum MTU setting for Jumbo Frames is 16110. This value coincides - with the maximum Jumbo Frames size of 16128. + The maximum MTU setting for Jumbo Frames is 9710. This value coincides + with the maximum Jumbo Frames size of 9728. Generic Receive Offload, aka GRO -------------------------------- -- cgit v1.2.3-59-g8ed1b From 322d3ed1679047e4ed0c9997d84acf3cdd4f1d29 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 9 Apr 2015 22:03:21 -0700 Subject: ixgb: remove references to ifconfig Move documentation into this century, even if this device hasn't been available for some time. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Kirsher --- Documentation/networking/ixgb.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/ixgb.txt b/Documentation/networking/ixgb.txt index 1e0c045e89f7..9b4a10a1cf50 100644 --- a/Documentation/networking/ixgb.txt +++ b/Documentation/networking/ixgb.txt @@ -39,7 +39,7 @@ Channel Bonding documentation can be found in the Linux kernel source: The driver information previously displayed in the /proc filesystem is not supported in this release. Alternatively, you can use ethtool (version 1.6 -or later), lspci, and ifconfig to obtain the same information. +or later), lspci, and iproute2 to obtain the same information. Instructions on updating ethtool can be found in the section "Additional Configurations" later in this document. @@ -90,7 +90,7 @@ select m for "Intel(R) PRO/10GbE support" located at: 3. Assign an IP address to the interface by entering the following, where x is the interface number: - ifconfig ethx + ip addr add ethx 4. Verify that the interface works. Enter the following, where is the IP address for another machine on the same subnet as the interface @@ -177,7 +177,7 @@ NOTE: These changes are only suggestions, and serve as a starting point for tuning your network performance. The changes are made in three major ways, listed in order of greatest effect: -- Use ifconfig to modify the mtu (maximum transmission unit) and the txqueuelen +- Use ip link to modify the mtu (maximum transmission unit) and the txqueuelen parameter. - Use sysctl to modify /proc parameters (essentially kernel tuning) - Use setpci to modify the MMRBC field in PCI-X configuration space to increase @@ -202,7 +202,7 @@ setpci -d 8086:1a48 e6.b=2e # to change as well. # set the txqueuelen # your ixgb adapter should be loaded as eth1 for this to work, change if needed -ifconfig eth1 mtu 9000 txqueuelen 1000 up +ip li set dev eth1 mtu 9000 txqueuelen 1000 up # call the sysctl utility to modify /proc/sys entries sysctl -p ./sysctl_ixgb.conf - END ixgb_perf.sh @@ -297,10 +297,10 @@ Additional Configurations ------------ The driver supports Jumbo Frames for all adapters. Jumbo Frames support is enabled by changing the MTU to a value larger than the default of 1500. - The maximum value for the MTU is 16114. Use the ifconfig command to + The maximum value for the MTU is 16114. Use the ip command to increase the MTU size. For example: - ifconfig ethx mtu 9000 up + ip li set dev ethx mtu 9000 The maximum MTU setting for Jumbo Frames is 16114. This value coincides with the maximum Jumbo Frames size of 16128. -- cgit v1.2.3-59-g8ed1b From 69f0fb2a592fc9ebc5e3e55178055d1cff31d479 Mon Sep 17 00:00:00 2001 From: Peter Griffin Date: Fri, 10 Apr 2015 10:40:29 +0100 Subject: mmc: sdhci-st: Update ST SDHCI binding documentation. This patch updates the binding information to reflect the extra dt options which are now supported by the sdhci-st.c driver which enable support for stih407 family silicon. STiH410 SoC and later support UHS modes for eMMC, so the driver now makes use of these common bindings. Examples are provided for both eMMC (which has additional bindings) and also sd slot for STiH407. Signed-off-by: Peter Griffin Acked-by: Maxime Coquelin Signed-off-by: Ulf Hansson --- Documentation/devicetree/bindings/mmc/sdhci-st.txt | 100 ++++++++++++++++++--- 1 file changed, 90 insertions(+), 10 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mmc/sdhci-st.txt b/Documentation/devicetree/bindings/mmc/sdhci-st.txt index 7527db447a35..18d950df2749 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-st.txt +++ b/Documentation/devicetree/bindings/mmc/sdhci-st.txt @@ -5,20 +5,62 @@ Documentation/devicetree/bindings/mmc/mmc.txt and the properties used by the sdhci-st driver. Required properties: -- compatible : Must be "st,sdhci" -- clock-names : Should be "mmc" - See: Documentation/devicetree/bindings/resource-names.txt -- clocks : Phandle of the clock used by the sdhci controler - See: Documentation/devicetree/bindings/clock/clock-bindings.txt +- compatible: Must be "st,sdhci" and it can be compatible to "st,sdhci-stih407" + to set the internal glue logic used for configuring the MMC + subsystem (mmcss) inside the FlashSS (available in STiH407 SoC + family). + +- clock-names: Should be "mmc". + See: Documentation/devicetree/bindings/resource-names.txt +- clocks: Phandle to the clock. + See: Documentation/devicetree/bindings/clock/clock-bindings.txt + +- interrupts: One mmc interrupt should be described here. +- interrupt-names: Should be "mmcirq". + +- pinctrl-names: A pinctrl state names "default" must be defined. +- pinctrl-0: Phandle referencing pin configuration of the sd/emmc controller. + See: Documentation/devicetree/bindings/pinctrl/pinctrl-binding.txt + +- reg: This must provide the host controller base address and it can also + contain the FlashSS Top register for TX/RX delay used by the driver + to configure DLL inside the flashSS, if so reg-names must also be + specified. Optional properties: -- non-removable: non-removable slot - See: Documentation/devicetree/bindings/mmc/mmc.txt -- bus-width: Number of data lines - See: Documentation/devicetree/bindings/mmc/mmc.txt +- reg-names: Should be "mmc" and "top-mmc-delay". "top-mmc-delay" is optional + for eMMC on stih407 family silicon to configure DLL inside FlashSS. + +- non-removable: Non-removable slot. Also used for configuring mmcss in STiH407 SoC + family. + See: Documentation/devicetree/bindings/mmc/mmc.txt. + +- bus-width: Number of data lines. + See: Documentation/devicetree/bindings/mmc/mmc.txt. + +- max-frequency: Can be 200MHz, 100Mz or 50MHz (default) and used for + configuring the CCONFIG3 in the mmcss. + See: Documentation/devicetree/bindings/mmc/mmc.txt. + +- resets: Phandle and reset specifier pair to softreset line of HC IP. + See: Documentation/devicetree/bindings/reset/reset.txt + +- vqmmc-supply: Phandle to the regulator dt node, mentioned as the vcc/vdd + supply in eMMC/SD specs. + +- sd-uhs--sdr50: To enable the SDR50 in the mmcss. + See: Documentation/devicetree/bindings/mmc/mmc.txt. + +- sd-uhs-sdr104: To enable the SDR104 in the mmcss. + See: Documentation/devicetree/bindings/mmc/mmc.txt. + +- sd-uhs-ddr50: To enable the DDR50 in the mmcss. + See: Documentation/devicetree/bindings/mmc/mmc.txt. Example: +/* Example stih416e eMMC configuration */ + mmc0: sdhci@fe81e000 { compatible = "st,sdhci"; status = "disabled"; @@ -29,5 +71,43 @@ mmc0: sdhci@fe81e000 { pinctrl-0 = <&pinctrl_mmc0>; clock-names = "mmc"; clocks = <&clk_s_a1_ls 1>; - bus-width = <8> + bus-width = <8> + +/* Example SD stih407 family configuration */ + +mmc1: sdhci@09080000 { + compatible = "st,sdhci-stih407", "st,sdhci"; + status = "disabled"; + reg = <0x09080000 0x7ff>; + reg-names = "mmc"; + interrupts = ; + interrupt-names = "mmcirq"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sd1>; + clock-names = "mmc"; + clocks = <&clk_s_c0_flexgen CLK_MMC_1>; + resets = <&softreset STIH407_MMC1_SOFTRESET>; + bus-width = <4>; +}; + +/* Example eMMC stih407 family configuration */ + +mmc0: sdhci@09060000 { + compatible = "st,sdhci-stih407", "st,sdhci"; + status = "disabled"; + reg = <0x09060000 0x7ff>, <0x9061008 0x20>; + reg-names = "mmc", "top-mmc-delay"; + interrupts = ; + interrupt-names = "mmcirq"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_mmc0>; + clock-names = "mmc"; + clocks = <&clk_s_c0_flexgen CLK_MMC_0>; + vqmmc-supply = <&vmmc_reg>; + max-frequency = <200000000>; + bus-width = <8>; + non-removable; + sd-uhs-sdr50; + sd-uhs-sdr104; + sd-uhs-ddr50; }; -- cgit v1.2.3-59-g8ed1b From 7ef97e9a312c359a2b32a7b5d918c60f238b69b2 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Mon, 6 Apr 2015 15:38:41 +0300 Subject: i2c: davinci: use ICPFUNC to toggle I2C as gpio for bus recovery MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Having a board where the I2C bus locks up occasionally made it clear that the bus recovery in the i2c-davinci driver will only work on some boards, because on regular boards, this will only toggle GPIO lines that aren't muxed to the actual pins. The I2C controller on SoCs like da850 (and da830), Keystone 2 has the built-in capability to bit-bang its lines by using the ICPFUNC registers of the i2c controller. Implement the suggested procedure by toggling SCL and checking SDA using the ICPFUNC registers of the I2C controller when present. Allow platforms to indicate the presence of the ICPFUNC registers with a has_pfunc platform data flag and add optional DT property "ti,has-pfunc" to indicate the same in DT. Reviewed-by: Uwe Kleine-König Acked-by: Alexander Sverdlin Tested-by: Michael Lawnick Signed-off-by: Ben Gardiner Signed-off-by: Mike Looijmans [grygorii.strashko@ti.com: combined patches from Ben Gardiner and Mike Looijmans and reimplemented ICPFUNC bus recovery using I2C bus recovery infrastructure] Signed-off-by: Grygorii Strashko Signed-off-by: Wolfram Sang --- .../devicetree/bindings/i2c/i2c-davinci.txt | 3 + drivers/i2c/busses/i2c-davinci.c | 102 ++++++++++++++++++++- include/linux/platform_data/i2c-davinci.h | 1 + 3 files changed, 105 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/i2c/i2c-davinci.txt b/Documentation/devicetree/bindings/i2c/i2c-davinci.txt index 2dc935b4113d..a4e1cbc810c1 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-davinci.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-davinci.txt @@ -10,6 +10,9 @@ Required properties: Recommended properties : - interrupts : standard interrupt property. - clock-frequency : desired I2C bus clock frequency in Hz. +- ti,has-pfunc: boolean; if defined, it indicates that SoC supports PFUNC + registers. PFUNC registers allow to switch I2C pins to function as + GPIOs, so they can by toggled manually. Example (enbw_cmc board): i2c@1c22000 { diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index 54819fb4f82e..4788a32afb86 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -60,6 +60,12 @@ #define DAVINCI_I2C_IVR_REG 0x28 #define DAVINCI_I2C_EMDR_REG 0x2c #define DAVINCI_I2C_PSC_REG 0x30 +#define DAVINCI_I2C_FUNC_REG 0x48 +#define DAVINCI_I2C_DIR_REG 0x4c +#define DAVINCI_I2C_DIN_REG 0x50 +#define DAVINCI_I2C_DOUT_REG 0x54 +#define DAVINCI_I2C_DSET_REG 0x58 +#define DAVINCI_I2C_DCLR_REG 0x5c #define DAVINCI_I2C_IVR_AAS 0x07 #define DAVINCI_I2C_IVR_SCD 0x06 @@ -93,6 +99,29 @@ #define DAVINCI_I2C_IMR_NACK BIT(1) #define DAVINCI_I2C_IMR_AL BIT(0) +/* set SDA and SCL as GPIO */ +#define DAVINCI_I2C_FUNC_PFUNC0 BIT(0) + +/* set SCL as output when used as GPIO*/ +#define DAVINCI_I2C_DIR_PDIR0 BIT(0) +/* set SDA as output when used as GPIO*/ +#define DAVINCI_I2C_DIR_PDIR1 BIT(1) + +/* read SCL GPIO level */ +#define DAVINCI_I2C_DIN_PDIN0 BIT(0) +/* read SDA GPIO level */ +#define DAVINCI_I2C_DIN_PDIN1 BIT(1) + +/*set the SCL GPIO high */ +#define DAVINCI_I2C_DSET_PDSET0 BIT(0) +/*set the SDA GPIO high */ +#define DAVINCI_I2C_DSET_PDSET1 BIT(1) + +/* set the SCL GPIO low */ +#define DAVINCI_I2C_DCLR_PDCLR0 BIT(0) +/* set the SDA GPIO low */ +#define DAVINCI_I2C_DCLR_PDCLR1 BIT(1) + struct davinci_i2c_dev { struct device *dev; void __iomem *base; @@ -253,6 +282,71 @@ static struct i2c_bus_recovery_info davinci_i2c_gpio_recovery_info = { .unprepare_recovery = davinci_i2c_unprepare_recovery, }; +static void davinci_i2c_set_scl(struct i2c_adapter *adap, int val) +{ + struct davinci_i2c_dev *dev = i2c_get_adapdata(adap); + + if (val) + davinci_i2c_write_reg(dev, DAVINCI_I2C_DSET_REG, + DAVINCI_I2C_DSET_PDSET0); + else + davinci_i2c_write_reg(dev, DAVINCI_I2C_DCLR_REG, + DAVINCI_I2C_DCLR_PDCLR0); +} + +static int davinci_i2c_get_scl(struct i2c_adapter *adap) +{ + struct davinci_i2c_dev *dev = i2c_get_adapdata(adap); + int val; + + /* read the state of SCL */ + val = davinci_i2c_read_reg(dev, DAVINCI_I2C_DIN_REG); + return val & DAVINCI_I2C_DIN_PDIN0; +} + +static int davinci_i2c_get_sda(struct i2c_adapter *adap) +{ + struct davinci_i2c_dev *dev = i2c_get_adapdata(adap); + int val; + + /* read the state of SDA */ + val = davinci_i2c_read_reg(dev, DAVINCI_I2C_DIN_REG); + return val & DAVINCI_I2C_DIN_PDIN1; +} + +static void davinci_i2c_scl_prepare_recovery(struct i2c_adapter *adap) +{ + struct davinci_i2c_dev *dev = i2c_get_adapdata(adap); + + davinci_i2c_prepare_recovery(adap); + + /* SCL output, SDA input */ + davinci_i2c_write_reg(dev, DAVINCI_I2C_DIR_REG, DAVINCI_I2C_DIR_PDIR0); + + /* change to GPIO mode */ + davinci_i2c_write_reg(dev, DAVINCI_I2C_FUNC_REG, + DAVINCI_I2C_FUNC_PFUNC0); +} + +static void davinci_i2c_scl_unprepare_recovery(struct i2c_adapter *adap) +{ + struct davinci_i2c_dev *dev = i2c_get_adapdata(adap); + + /* change back to I2C mode */ + davinci_i2c_write_reg(dev, DAVINCI_I2C_FUNC_REG, 0); + + davinci_i2c_unprepare_recovery(adap); +} + +static struct i2c_bus_recovery_info davinci_i2c_scl_recovery_info = { + .recover_bus = i2c_generic_scl_recovery, + .set_scl = davinci_i2c_set_scl, + .get_scl = davinci_i2c_get_scl, + .get_sda = davinci_i2c_get_sda, + .prepare_recovery = davinci_i2c_scl_prepare_recovery, + .unprepare_recovery = davinci_i2c_scl_unprepare_recovery, +}; + /* * Waiting for bus not busy */ @@ -660,6 +754,10 @@ static int davinci_i2c_probe(struct platform_device *pdev) if (!of_property_read_u32(pdev->dev.of_node, "clock-frequency", &prop)) dev->pdata->bus_freq = prop / 1000; + + dev->pdata->has_pfunc = + of_property_read_bool(pdev->dev.of_node, + "ti,has-pfunc"); } else if (!dev->pdata) { dev->pdata = &davinci_i2c_platform_data_default; } @@ -701,7 +799,9 @@ static int davinci_i2c_probe(struct platform_device *pdev) adap->timeout = DAVINCI_I2C_TIMEOUT; adap->dev.of_node = pdev->dev.of_node; - if (dev->pdata->scl_pin) { + if (dev->pdata->has_pfunc) + adap->bus_recovery_info = &davinci_i2c_scl_recovery_info; + else if (dev->pdata->scl_pin) { adap->bus_recovery_info = &davinci_i2c_gpio_recovery_info; adap->bus_recovery_info->scl_gpio = dev->pdata->scl_pin; adap->bus_recovery_info->sda_gpio = dev->pdata->sda_pin; diff --git a/include/linux/platform_data/i2c-davinci.h b/include/linux/platform_data/i2c-davinci.h index 2312d197dfb7..89fd34727a24 100644 --- a/include/linux/platform_data/i2c-davinci.h +++ b/include/linux/platform_data/i2c-davinci.h @@ -18,6 +18,7 @@ struct davinci_i2c_platform_data { unsigned int bus_delay; /* post-transaction delay (usec) */ unsigned int sda_pin; /* GPIO pin ID to use for SDA */ unsigned int scl_pin; /* GPIO pin ID to use for SCL */ + bool has_pfunc; /*chip has a ICPFUNC register */ }; /* for board setup code */ -- cgit v1.2.3-59-g8ed1b From 85e4564ab234221f81b13e08ec5eb235734e51b0 Mon Sep 17 00:00:00 2001 From: Subhendu Sekhar Behera Date: Wed, 18 Mar 2015 17:20:28 +0530 Subject: of: Add vendor prefix 'netlogic' Add vendor name "netlogic" in vendor-prefixes.txt, which will be used for the Netlogic XLP and XLPII MIPS SoCs. These processors were from NetLogic Microsystems that is now a part of Broadcom Corporation. Signed-off-by: Subhendu Sekhar Behera Signed-off-by: Jayachandran C Signed-off-by: Wolfram Sang --- Documentation/devicetree/bindings/vendor-prefixes.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 389ca1347a77..a718eb1961fd 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -123,6 +123,7 @@ mxicy Macronix International Co., Ltd. national National Semiconductor neonode Neonode Inc. netgear NETGEAR +netlogic Broadcom Corporation (formerly NetLogic Microsystems) newhaven Newhaven Display International nintendo Nintendo nokia Nokia -- cgit v1.2.3-59-g8ed1b From 2bbd681ba2bfa0f3805fb541b0840b96893c5727 Mon Sep 17 00:00:00 2001 From: Subhendu Sekhar Behera Date: Wed, 18 Mar 2015 17:20:29 +0530 Subject: i2c: xlp9xx: Driver for Netlogic XLP9XX/5XX I2C controller Add an I2C bus driver i2c-xlp9xx.c to support the I2C block in the XLP9xx/XLP5xx MIPS SoC. Update Kconfig and Makefile to add the CONFIG_I2C_XLP9XX option. Signed-off-by: Subhendu Sekhar Behera Signed-off-by: Jayachandran C Reviewed-by: Ray Jui Signed-off-by: Wolfram Sang --- .../devicetree/bindings/i2c/i2c-xlp9xx.txt | 22 + drivers/i2c/busses/Kconfig | 10 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-xlp9xx.c | 445 +++++++++++++++++++++ 4 files changed, 478 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/i2c-xlp9xx.txt create mode 100644 drivers/i2c/busses/i2c-xlp9xx.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/i2c/i2c-xlp9xx.txt b/Documentation/devicetree/bindings/i2c/i2c-xlp9xx.txt new file mode 100644 index 000000000000..f818ef507ab7 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-xlp9xx.txt @@ -0,0 +1,22 @@ +Device tree configuration for the I2C controller on the XLP9xx/5xx SoC + +Required properties: +- compatible : should be "netlogic,xlp980-i2c" +- reg : bus address start and address range size of device +- interrupts : interrupt number + +Optional properties: +- clock-frequency : frequency of bus clock in Hz + Defaults to 100 KHz when the property is not specified + +Example: + +i2c0: i2c@113100 { + compatible = "netlogic,xlp980-i2c"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0 0x113100 0x100>; + clock-frequency = <400000>; + interrupts = <30>; + interrupt-parent = <&pic>; +}; diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 0b0ca7dd5d1f..2255af23b9c7 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -916,6 +916,16 @@ config I2C_XLR This driver can also be built as a module. If so, the module will be called i2c-xlr. +config I2C_XLP9XX + tristate "XLP9XX I2C support" + depends on CPU_XLP || COMPILE_TEST + help + This driver enables support for the on-chip I2C interface of + the Broadcom XLP9xx/XLP5xx MIPS processors. + + This driver can also be built as a module. If so, the module will + be called i2c-xlp9xx. + config I2C_RCAR tristate "Renesas R-Car I2C Controller" depends on ARCH_SHMOBILE || COMPILE_TEST diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index ab6a0a67aca1..cdf941da91c6 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -89,6 +89,7 @@ obj-$(CONFIG_I2C_WMT) += i2c-wmt.o obj-$(CONFIG_I2C_OCTEON) += i2c-octeon.o obj-$(CONFIG_I2C_XILINX) += i2c-xiic.o obj-$(CONFIG_I2C_XLR) += i2c-xlr.o +obj-$(CONFIG_I2C_XLP9XX) += i2c-xlp9xx.o obj-$(CONFIG_I2C_RCAR) += i2c-rcar.o # External I2C/SMBus adapter drivers diff --git a/drivers/i2c/busses/i2c-xlp9xx.c b/drivers/i2c/busses/i2c-xlp9xx.c new file mode 100644 index 000000000000..c941418f06f5 --- /dev/null +++ b/drivers/i2c/busses/i2c-xlp9xx.c @@ -0,0 +1,445 @@ +/* + * Copyright (c) 2003-2015 Broadcom Corporation + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define XLP9XX_I2C_DIV 0x0 +#define XLP9XX_I2C_CTRL 0x1 +#define XLP9XX_I2C_CMD 0x2 +#define XLP9XX_I2C_STATUS 0x3 +#define XLP9XX_I2C_MTXFIFO 0x4 +#define XLP9XX_I2C_MRXFIFO 0x5 +#define XLP9XX_I2C_MFIFOCTRL 0x6 +#define XLP9XX_I2C_STXFIFO 0x7 +#define XLP9XX_I2C_SRXFIFO 0x8 +#define XLP9XX_I2C_SFIFOCTRL 0x9 +#define XLP9XX_I2C_SLAVEADDR 0xA +#define XLP9XX_I2C_OWNADDR 0xB +#define XLP9XX_I2C_FIFOWCNT 0xC +#define XLP9XX_I2C_INTEN 0xD +#define XLP9XX_I2C_INTST 0xE +#define XLP9XX_I2C_WAITCNT 0xF +#define XLP9XX_I2C_TIMEOUT 0X10 +#define XLP9XX_I2C_GENCALLADDR 0x11 + +#define XLP9XX_I2C_CMD_START BIT(7) +#define XLP9XX_I2C_CMD_STOP BIT(6) +#define XLP9XX_I2C_CMD_READ BIT(5) +#define XLP9XX_I2C_CMD_WRITE BIT(4) +#define XLP9XX_I2C_CMD_ACK BIT(3) + +#define XLP9XX_I2C_CTRL_MCTLEN_SHIFT 16 +#define XLP9XX_I2C_CTRL_MCTLEN_MASK 0xffff0000 +#define XLP9XX_I2C_CTRL_RST BIT(8) +#define XLP9XX_I2C_CTRL_EN BIT(6) +#define XLP9XX_I2C_CTRL_MASTER BIT(4) +#define XLP9XX_I2C_CTRL_FIFORD BIT(1) +#define XLP9XX_I2C_CTRL_ADDMODE BIT(0) + +#define XLP9XX_I2C_INTEN_NACKADDR BIT(25) +#define XLP9XX_I2C_INTEN_SADDR BIT(13) +#define XLP9XX_I2C_INTEN_DATADONE BIT(12) +#define XLP9XX_I2C_INTEN_ARLOST BIT(11) +#define XLP9XX_I2C_INTEN_MFIFOFULL BIT(4) +#define XLP9XX_I2C_INTEN_MFIFOEMTY BIT(3) +#define XLP9XX_I2C_INTEN_MFIFOHI BIT(2) +#define XLP9XX_I2C_INTEN_BUSERR BIT(0) + +#define XLP9XX_I2C_MFIFOCTRL_HITH_SHIFT 8 +#define XLP9XX_I2C_MFIFOCTRL_LOTH_SHIFT 0 +#define XLP9XX_I2C_MFIFOCTRL_RST BIT(16) + +#define XLP9XX_I2C_SLAVEADDR_RW BIT(0) +#define XLP9XX_I2C_SLAVEADDR_ADDR_SHIFT 1 + +#define XLP9XX_I2C_IP_CLK_FREQ 133000000UL +#define XLP9XX_I2C_DEFAULT_FREQ 100000 +#define XLP9XX_I2C_HIGH_FREQ 400000 +#define XLP9XX_I2C_FIFO_SIZE 0x80U +#define XLP9XX_I2C_TIMEOUT_MS 1000 + +#define XLP9XX_I2C_FIFO_WCNT_MASK 0xff +#define XLP9XX_I2C_STATUS_ERRMASK (XLP9XX_I2C_INTEN_ARLOST | \ + XLP9XX_I2C_INTEN_NACKADDR | XLP9XX_I2C_INTEN_BUSERR) + +struct xlp9xx_i2c_dev { + struct device *dev; + struct i2c_adapter adapter; + struct completion msg_complete; + int irq; + bool msg_read; + u32 __iomem *base; + u32 msg_buf_remaining; + u32 msg_len; + u32 clk_hz; + u32 msg_err; + u8 *msg_buf; +}; + +static inline void xlp9xx_write_i2c_reg(struct xlp9xx_i2c_dev *priv, + unsigned long reg, u32 val) +{ + writel(val, priv->base + reg); +} + +static inline u32 xlp9xx_read_i2c_reg(struct xlp9xx_i2c_dev *priv, + unsigned long reg) +{ + return readl(priv->base + reg); +} + +static void xlp9xx_i2c_mask_irq(struct xlp9xx_i2c_dev *priv, u32 mask) +{ + u32 inten; + + inten = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_INTEN) & ~mask; + xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, inten); +} + +static void xlp9xx_i2c_unmask_irq(struct xlp9xx_i2c_dev *priv, u32 mask) +{ + u32 inten; + + inten = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_INTEN) | mask; + xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, inten); +} + +static void xlp9xx_i2c_update_rx_fifo_thres(struct xlp9xx_i2c_dev *priv) +{ + u32 thres; + + thres = min(priv->msg_buf_remaining, XLP9XX_I2C_FIFO_SIZE); + xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_MFIFOCTRL, + thres << XLP9XX_I2C_MFIFOCTRL_HITH_SHIFT); +} + +static void xlp9xx_i2c_fill_tx_fifo(struct xlp9xx_i2c_dev *priv) +{ + u32 len, i; + u8 *buf = priv->msg_buf; + + len = min(priv->msg_buf_remaining, XLP9XX_I2C_FIFO_SIZE); + for (i = 0; i < len; i++) + xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_MTXFIFO, buf[i]); + priv->msg_buf_remaining -= len; + priv->msg_buf += len; +} + +static void xlp9xx_i2c_drain_rx_fifo(struct xlp9xx_i2c_dev *priv) +{ + u32 len, i; + u8 *buf = priv->msg_buf; + + len = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_FIFOWCNT) & + XLP9XX_I2C_FIFO_WCNT_MASK; + len = min(priv->msg_buf_remaining, len); + for (i = 0; i < len; i++, buf++) + *buf = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_MRXFIFO); + + priv->msg_buf_remaining -= len; + priv->msg_buf = buf; + + if (priv->msg_buf_remaining) + xlp9xx_i2c_update_rx_fifo_thres(priv); +} + +static irqreturn_t xlp9xx_i2c_isr(int irq, void *dev_id) +{ + struct xlp9xx_i2c_dev *priv = dev_id; + u32 status; + + status = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_INTST); + if (status == 0) + return IRQ_NONE; + + xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTST, status); + if (status & XLP9XX_I2C_STATUS_ERRMASK) { + priv->msg_err = status; + goto xfer_done; + } + + /* SADDR ACK for SMBUS_QUICK */ + if ((status & XLP9XX_I2C_INTEN_SADDR) && (priv->msg_len == 0)) + goto xfer_done; + + if (!priv->msg_read) { + if (status & XLP9XX_I2C_INTEN_MFIFOEMTY) { + /* TX FIFO got empty, fill it up again */ + if (priv->msg_buf_remaining) + xlp9xx_i2c_fill_tx_fifo(priv); + else + xlp9xx_i2c_mask_irq(priv, + XLP9XX_I2C_INTEN_MFIFOEMTY); + } + } else { + if (status & (XLP9XX_I2C_INTEN_DATADONE | + XLP9XX_I2C_INTEN_MFIFOHI)) { + /* data is in FIFO, read it */ + if (priv->msg_buf_remaining) + xlp9xx_i2c_drain_rx_fifo(priv); + } + } + + /* Transfer complete */ + if (status & XLP9XX_I2C_INTEN_DATADONE) + goto xfer_done; + + return IRQ_HANDLED; + +xfer_done: + xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, 0); + complete(&priv->msg_complete); + return IRQ_HANDLED; +} + +static int xlp9xx_i2c_init(struct xlp9xx_i2c_dev *priv) +{ + u32 prescale; + + /* + * The controller uses 5 * SCL clock internally. + * So prescale value should be divided by 5. + */ + prescale = DIV_ROUND_UP(XLP9XX_I2C_IP_CLK_FREQ, priv->clk_hz); + prescale = ((prescale - 8) / 5) - 1; + xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, XLP9XX_I2C_CTRL_RST); + xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, XLP9XX_I2C_CTRL_EN | + XLP9XX_I2C_CTRL_MASTER); + xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_DIV, prescale); + xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, 0); + + return 0; +} + +static int xlp9xx_i2c_xfer_msg(struct xlp9xx_i2c_dev *priv, struct i2c_msg *msg, + int last_msg) +{ + unsigned long timeleft; + u32 intr_mask, cmd, val; + + priv->msg_buf = msg->buf; + priv->msg_buf_remaining = priv->msg_len = msg->len; + priv->msg_err = 0; + priv->msg_read = (msg->flags & I2C_M_RD); + reinit_completion(&priv->msg_complete); + + /* Reset FIFO */ + xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_MFIFOCTRL, + XLP9XX_I2C_MFIFOCTRL_RST); + + /* set FIFO threshold if reading */ + if (priv->msg_read) + xlp9xx_i2c_update_rx_fifo_thres(priv); + + /* set slave addr */ + xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_SLAVEADDR, + (msg->addr << XLP9XX_I2C_SLAVEADDR_ADDR_SHIFT) | + (priv->msg_read ? XLP9XX_I2C_SLAVEADDR_RW : 0)); + + /* Build control word for transfer */ + val = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_CTRL); + if (!priv->msg_read) + val &= ~XLP9XX_I2C_CTRL_FIFORD; + else + val |= XLP9XX_I2C_CTRL_FIFORD; /* read */ + + if (msg->flags & I2C_M_TEN) + val |= XLP9XX_I2C_CTRL_ADDMODE; /* 10-bit address mode*/ + else + val &= ~XLP9XX_I2C_CTRL_ADDMODE; + + /* set data length to be transferred */ + val = (val & ~XLP9XX_I2C_CTRL_MCTLEN_MASK) | + (msg->len << XLP9XX_I2C_CTRL_MCTLEN_SHIFT); + xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, val); + + /* fill fifo during tx */ + if (!priv->msg_read) + xlp9xx_i2c_fill_tx_fifo(priv); + + /* set interrupt mask */ + intr_mask = (XLP9XX_I2C_INTEN_ARLOST | XLP9XX_I2C_INTEN_BUSERR | + XLP9XX_I2C_INTEN_NACKADDR | XLP9XX_I2C_INTEN_DATADONE); + + if (priv->msg_read) { + intr_mask |= XLP9XX_I2C_INTEN_MFIFOHI; + if (msg->len == 0) + intr_mask |= XLP9XX_I2C_INTEN_SADDR; + } else { + if (msg->len == 0) + intr_mask |= XLP9XX_I2C_INTEN_SADDR; + else + intr_mask |= XLP9XX_I2C_INTEN_MFIFOEMTY; + } + xlp9xx_i2c_unmask_irq(priv, intr_mask); + + /* set cmd reg */ + cmd = XLP9XX_I2C_CMD_START; + cmd |= (priv->msg_read ? XLP9XX_I2C_CMD_READ : XLP9XX_I2C_CMD_WRITE); + if (last_msg) + cmd |= XLP9XX_I2C_CMD_STOP; + + xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CMD, cmd); + + timeleft = msecs_to_jiffies(XLP9XX_I2C_TIMEOUT_MS); + timeleft = wait_for_completion_timeout(&priv->msg_complete, timeleft); + + if (priv->msg_err) { + dev_dbg(priv->dev, "transfer error %x!\n", priv->msg_err); + if (priv->msg_err & XLP9XX_I2C_INTEN_BUSERR) + xlp9xx_i2c_init(priv); + return -EIO; + } + + if (timeleft == 0) { + dev_dbg(priv->dev, "i2c transfer timed out!\n"); + xlp9xx_i2c_init(priv); + return -ETIMEDOUT; + } + + return 0; +} + +static int xlp9xx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + int num) +{ + int i, ret; + struct xlp9xx_i2c_dev *priv = i2c_get_adapdata(adap); + + for (i = 0; i < num; i++) { + ret = xlp9xx_i2c_xfer_msg(priv, &msgs[i], i == num - 1); + if (ret != 0) + return ret; + } + + return num; +} + +static u32 xlp9xx_i2c_functionality(struct i2c_adapter *adapter) +{ + return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C | + I2C_FUNC_10BIT_ADDR; +} + +static struct i2c_algorithm xlp9xx_i2c_algo = { + .master_xfer = xlp9xx_i2c_xfer, + .functionality = xlp9xx_i2c_functionality, +}; + +static int xlp9xx_i2c_get_frequency(struct platform_device *pdev, + struct xlp9xx_i2c_dev *priv) +{ + struct device_node *np = pdev->dev.of_node; + u32 freq; + int err; + + err = of_property_read_u32(np, "clock-frequency", &freq); + if (err) { + freq = XLP9XX_I2C_DEFAULT_FREQ; + dev_dbg(&pdev->dev, "using default frequency %u\n", freq); + } else if (freq == 0 || freq > XLP9XX_I2C_HIGH_FREQ) { + dev_warn(&pdev->dev, "invalid frequency %u, using default\n", + freq); + freq = XLP9XX_I2C_DEFAULT_FREQ; + } + priv->clk_hz = freq; + + return 0; +} + +static int xlp9xx_i2c_probe(struct platform_device *pdev) +{ + struct xlp9xx_i2c_dev *priv; + struct resource *res; + int err = 0; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + priv->irq = platform_get_irq(pdev, 0); + if (priv->irq <= 0) { + dev_err(&pdev->dev, "invalid irq!\n"); + return priv->irq; + } + + xlp9xx_i2c_get_frequency(pdev, priv); + xlp9xx_i2c_init(priv); + + err = devm_request_irq(&pdev->dev, priv->irq, xlp9xx_i2c_isr, 0, + pdev->name, priv); + if (err) { + dev_err(&pdev->dev, "IRQ request failed!\n"); + return err; + } + + init_completion(&priv->msg_complete); + priv->adapter.dev.parent = &pdev->dev; + priv->adapter.algo = &xlp9xx_i2c_algo; + priv->adapter.dev.of_node = pdev->dev.of_node; + priv->dev = &pdev->dev; + + snprintf(priv->adapter.name, sizeof(priv->adapter.name), "xlp9xx-i2c"); + i2c_set_adapdata(&priv->adapter, priv); + + err = i2c_add_adapter(&priv->adapter); + if (err) { + dev_err(&pdev->dev, "failed to add I2C adapter!\n"); + return err; + } + + platform_set_drvdata(pdev, priv); + dev_dbg(&pdev->dev, "I2C bus:%d added\n", priv->adapter.nr); + + return 0; +} + +static int xlp9xx_i2c_remove(struct platform_device *pdev) +{ + struct xlp9xx_i2c_dev *priv; + + priv = platform_get_drvdata(pdev); + xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, 0); + synchronize_irq(priv->irq); + i2c_del_adapter(&priv->adapter); + xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, 0); + + return 0; +} + +static const struct of_device_id xlp9xx_i2c_of_match[] = { + { .compatible = "netlogic,xlp980-i2c", }, + { /* sentinel */ }, +}; + +static struct platform_driver xlp9xx_i2c_driver = { + .probe = xlp9xx_i2c_probe, + .remove = xlp9xx_i2c_remove, + .driver = { + .name = "xlp9xx-i2c", + .of_match_table = xlp9xx_i2c_of_match, + }, +}; + +module_platform_driver(xlp9xx_i2c_driver); + +MODULE_AUTHOR("Subhendu Sekhar Behera "); +MODULE_DESCRIPTION("XLP9XX/5XX I2C Bus Controller Driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-59-g8ed1b From b2eafd7282fdfd148fc09032540b0ff42bfedfbf Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Fri, 10 Apr 2015 11:22:23 -0700 Subject: HID: sensor: Update document for custom sensor Added custom sensor documentation Signed-off-by: Srinivas Pandruvada Acked-by: Jonathan Cameron Signed-off-by: Jiri Kosina --- Documentation/hid/hid-sensor.txt | 84 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) (limited to 'Documentation') diff --git a/Documentation/hid/hid-sensor.txt b/Documentation/hid/hid-sensor.txt index 948b0989c433..b287752a31cd 100644 --- a/Documentation/hid/hid-sensor.txt +++ b/Documentation/hid/hid-sensor.txt @@ -138,3 +138,87 @@ accelerometer wants to poll X axis value, then it can call this function with the usage id of X axis. HID sensors can provide events, so this is not necessary to poll for any field. If there is some new sample, the core driver will call registered callback function to process the sample. + + +---------- + +HID Custom and generic Sensors + +HID Sensor specification defines two special sensor usage types. Since they +don't represent a standard sensor, it is not possible to define using Linux IIO +type interfaces. +The purpose of these sensors is to extend the functionality or provide a +way to obfuscate the data being communicated by a sensor. Without knowing the +mapping between the data and its encapsulated form, it is difficult for +an application/driver to determine what data is being communicated by the sensor. +This allows some differentiating use cases, where vendor can provide applications. +Some common use cases are debug other sensors or to provide some events like +keyboard attached/detached or lid open/close. + +To allow application to utilize these sensors, here they are exported uses sysfs +attribute groups, attributes and misc device interface. + +An example of this representation on sysfs: +/sys/devices/pci0000:00/INT33C2:00/i2c-0/i2c-INT33D1:00/0018:8086:09FA.0001/HID-SENSOR-2000e1.6.auto$ tree -R +. +????????? enable_sensor +????????? feature-0-200316 +??????? ????????? feature-0-200316-maximum +??????? ????????? feature-0-200316-minimum +??????? ????????? feature-0-200316-name +??????? ????????? feature-0-200316-size +??????? ????????? feature-0-200316-unit-expo +??????? ????????? feature-0-200316-units +??????? ????????? feature-0-200316-value +????????? feature-1-200201 +??????? ????????? feature-1-200201-maximum +??????? ????????? feature-1-200201-minimum +??????? ????????? feature-1-200201-name +??????? ????????? feature-1-200201-size +??????? ????????? feature-1-200201-unit-expo +??????? ????????? feature-1-200201-units +??????? ????????? feature-1-200201-value +????????? input-0-200201 +??????? ????????? input-0-200201-maximum +??????? ????????? input-0-200201-minimum +??????? ????????? input-0-200201-name +??????? ????????? input-0-200201-size +??????? ????????? input-0-200201-unit-expo +??????? ????????? input-0-200201-units +??????? ????????? input-0-200201-value +????????? input-1-200202 +??????? ????????? input-1-200202-maximum +??????? ????????? input-1-200202-minimum +??????? ????????? input-1-200202-name +??????? ????????? input-1-200202-size +??????? ????????? input-1-200202-unit-expo +??????? ????????? input-1-200202-units +??????? ????????? input-1-200202-value + +Here there is a custom sensors with four fields, two feature and two inputs. +Each field is represented by a set of attributes. All fields except the "value" +are read only. The value field is a RW field. +Example +/sys/bus/platform/devices/HID-SENSOR-2000e1.6.auto/feature-0-200316$ grep -r . * +feature-0-200316-maximum:6 +feature-0-200316-minimum:0 +feature-0-200316-name:property-reporting-state +feature-0-200316-size:1 +feature-0-200316-unit-expo:0 +feature-0-200316-units:25 +feature-0-200316-value:1 + +How to enable such sensor? +By default sensor can be power gated. To enable sysfs attribute "enable" can be +used. +$ echo 1 > enable_sensor + +Once enabled and powered on, sensor can report value using HID reports. +These reports are pushed using misc device interface in a FIFO order. +/dev$ tree | grep HID-SENSOR-2000e1.6.auto +??????? ????????? 10:53 -> ../HID-SENSOR-2000e1.6.auto +????????? HID-SENSOR-2000e1.6.auto + +Each reports can be of variable length preceded by a header. This header +consist of a 32 bit usage id, 64 bit time stamp and 32 bit length field of raw +data. -- cgit v1.2.3-59-g8ed1b From 75342797988a0f9ebec400a2dde8d4de581c4079 Mon Sep 17 00:00:00 2001 From: Wanpeng Li Date: Tue, 24 Mar 2015 10:20:27 +0800 Subject: f2fs: enable inline data by default Enable inline_data feature by default since it brings us better performance and space utilization and now has already stable. Add another option noinline_data to disable it during mount. Suggested-by: Jaegeuk Kim Suggested-by: Chao Yu Signed-off-by: Wanpeng Li Signed-off-by: Jaegeuk Kim --- Documentation/filesystems/f2fs.txt | 2 ++ fs/f2fs/super.c | 8 ++++++++ 2 files changed, 10 insertions(+) (limited to 'Documentation') diff --git a/Documentation/filesystems/f2fs.txt b/Documentation/filesystems/f2fs.txt index 48e2123c2582..e9e750e59efc 100644 --- a/Documentation/filesystems/f2fs.txt +++ b/Documentation/filesystems/f2fs.txt @@ -144,6 +144,8 @@ extent_cache Enable an extent cache based on rb-tree, it can cache as many as extent which map between contiguous logical address and physical address per inode, resulting in increasing the cache hit ratio. +noinline_data Disable the inline data feature, inline data feature is + enabled by default. ================================================================================ DEBUGFS ENTRIES diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index fc6857f378cc..45aa843fa597 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -58,6 +58,7 @@ enum { Opt_nobarrier, Opt_fastboot, Opt_extent_cache, + Opt_noinline_data, Opt_err, }; @@ -80,6 +81,7 @@ static match_table_t f2fs_tokens = { {Opt_nobarrier, "nobarrier"}, {Opt_fastboot, "fastboot"}, {Opt_extent_cache, "extent_cache"}, + {Opt_noinline_data, "noinline_data"}, {Opt_err, NULL}, }; @@ -372,6 +374,9 @@ static int parse_options(struct super_block *sb, char *options) case Opt_extent_cache: set_opt(sbi, EXTENT_CACHE); break; + case Opt_noinline_data: + clear_opt(sbi, INLINE_DATA); + break; default: f2fs_msg(sb, KERN_ERR, "Unrecognized mount option \"%s\" or missing value", @@ -596,6 +601,8 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) seq_puts(seq, ",disable_ext_identify"); if (test_opt(sbi, INLINE_DATA)) seq_puts(seq, ",inline_data"); + else + seq_puts(seq, ",noinline_data"); if (test_opt(sbi, INLINE_DENTRY)) seq_puts(seq, ",inline_dentry"); if (!f2fs_readonly(sbi->sb) && test_opt(sbi, FLUSH_MERGE)) @@ -991,6 +998,7 @@ try_onemore: sbi->active_logs = NR_CURSEG_TYPE; set_opt(sbi, BG_GC); + set_opt(sbi, INLINE_DATA); #ifdef CONFIG_F2FS_FS_XATTR set_opt(sbi, XATTR_USER); -- cgit v1.2.3-59-g8ed1b From feba40362b11341bee6d8ed58d54b896abbd9f84 Mon Sep 17 00:00:00 2001 From: Sam bobroff Date: Fri, 10 Apr 2015 14:16:47 +1000 Subject: powerpc/tm: Abort syscalls in active transactions This patch changes the syscall handler to doom (tabort) active transactions when a syscall is made and return immediately without performing the syscall. Currently, the system call instruction automatically suspends an active transaction which causes side effects to persist when an active transaction fails. This does change the kernel's behaviour, but in a way that was documented as unsupported. It doesn't reduce functionality because syscalls will still be performed after tsuspend. It also provides a consistent interface and makes the behaviour of user code substantially the same across powerpc and platforms that do not support suspended transactions (e.g. x86 and s390). Performance measurements using http://ozlabs.org/~anton/junkcode/null_syscall.c indicate the cost of a system call increases by about 0.5%. Signed-off-by: Sam Bobroff Acked-By: Michael Neuling Signed-off-by: Michael Ellerman --- Documentation/powerpc/transactional_memory.txt | 32 +++++++++++++------------- arch/powerpc/include/uapi/asm/tm.h | 2 +- arch/powerpc/kernel/entry_64.S | 19 +++++++++++++++ 3 files changed, 36 insertions(+), 17 deletions(-) (limited to 'Documentation') diff --git a/Documentation/powerpc/transactional_memory.txt b/Documentation/powerpc/transactional_memory.txt index 9791e98ab49c..98b39af5254f 100644 --- a/Documentation/powerpc/transactional_memory.txt +++ b/Documentation/powerpc/transactional_memory.txt @@ -74,22 +74,23 @@ Causes of transaction aborts Syscalls ======== -Performing syscalls from within transaction is not recommended, and can lead -to unpredictable results. +Syscalls made from within an active transaction will not be performed and the +transaction will be doomed by the kernel with the failure code TM_CAUSE_SYSCALL +| TM_CAUSE_PERSISTENT. -Syscalls do not by design abort transactions, but beware: The kernel code will -not be running in transactional state. The effect of syscalls will always -remain visible, but depending on the call they may abort your transaction as a -side-effect, read soon-to-be-aborted transactional data that should not remain -invisible, etc. If you constantly retry a transaction that constantly aborts -itself by calling a syscall, you'll have a livelock & make no progress. +Syscalls made from within a suspended transaction are performed as normal and +the transaction is not explicitly doomed by the kernel. However, what the +kernel does to perform the syscall may result in the transaction being doomed +by the hardware. The syscall is performed in suspended mode so any side +effects will be persistent, independent of transaction success or failure. No +guarantees are provided by the kernel about which syscalls will affect +transaction success. -Simple syscalls (e.g. sigprocmask()) "could" be OK. Even things like write() -from, say, printf() should be OK as long as the kernel does not access any -memory that was accessed transactionally. - -Consider any syscalls that happen to work as debug-only -- not recommended for -production use. Best to queue them up till after the transaction is over. +Care must be taken when relying on syscalls to abort during active transactions +if the calls are made via a library. Libraries may cache values (which may +give the appearance of success) or perform operations that cause transaction +failure before entering the kernel (which may produce different failure codes). +Examples are glibc's getpid() and lazy symbol resolution. Signals @@ -176,8 +177,7 @@ kernel aborted a transaction: TM_CAUSE_RESCHED Thread was rescheduled. TM_CAUSE_TLBI Software TLB invalide. TM_CAUSE_FAC_UNAV FP/VEC/VSX unavailable trap. - TM_CAUSE_SYSCALL Currently unused; future syscalls that must abort - transactions for consistency will use this. + TM_CAUSE_SYSCALL Syscall from active transaction. TM_CAUSE_SIGNAL Signal delivered. TM_CAUSE_MISC Currently unused. TM_CAUSE_ALIGNMENT Alignment fault. diff --git a/arch/powerpc/include/uapi/asm/tm.h b/arch/powerpc/include/uapi/asm/tm.h index 5d836b7c1176..5047659815a5 100644 --- a/arch/powerpc/include/uapi/asm/tm.h +++ b/arch/powerpc/include/uapi/asm/tm.h @@ -11,7 +11,7 @@ #define TM_CAUSE_RESCHED 0xde #define TM_CAUSE_TLBI 0xdc #define TM_CAUSE_FAC_UNAV 0xda -#define TM_CAUSE_SYSCALL 0xd8 /* future use */ +#define TM_CAUSE_SYSCALL 0xd8 #define TM_CAUSE_MISC 0xd6 /* future use */ #define TM_CAUSE_SIGNAL 0xd4 #define TM_CAUSE_ALIGNMENT 0xd2 diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index afbc20019c2e..8ca9434c40e6 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -34,6 +34,7 @@ #include #include #include +#include /* * System calls. @@ -145,6 +146,24 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR) andi. r11,r10,_TIF_SYSCALL_DOTRACE bne syscall_dotrace .Lsyscall_dotrace_cont: +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM +BEGIN_FTR_SECTION + b 1f +END_FTR_SECTION_IFCLR(CPU_FTR_TM) + extrdi. r11, r12, 1, (63-MSR_TS_T_LG) /* transaction active? */ + beq+ 1f + + /* Doom the transaction and don't perform the syscall: */ + mfmsr r11 + li r12, 1 + rldimi r11, r12, MSR_TM_LG, 63-MSR_TM_LG + mtmsrd r11, 0 + li r11, (TM_CAUSE_SYSCALL|TM_CAUSE_PERSISTENT) + TABORT(R11) + + b .Lsyscall_exit +1: +#endif cmpldi 0,r0,NR_syscalls bge- syscall_enosys -- cgit v1.2.3-59-g8ed1b From d1d915783d90b15236e73d261cd8909db7275001 Mon Sep 17 00:00:00 2001 From: Sam bobroff Date: Fri, 10 Apr 2015 14:16:50 +1000 Subject: powerpc/tm: Correct minor documentation typos Signed-off-by: Sam Bobroff Signed-off-by: Michael Ellerman --- Documentation/powerpc/transactional_memory.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/powerpc/transactional_memory.txt b/Documentation/powerpc/transactional_memory.txt index 98b39af5254f..ba0a2a4a54ba 100644 --- a/Documentation/powerpc/transactional_memory.txt +++ b/Documentation/powerpc/transactional_memory.txt @@ -175,7 +175,7 @@ These are defined in , and distinguish different reasons why the kernel aborted a transaction: TM_CAUSE_RESCHED Thread was rescheduled. - TM_CAUSE_TLBI Software TLB invalide. + TM_CAUSE_TLBI Software TLB invalid. TM_CAUSE_FAC_UNAV FP/VEC/VSX unavailable trap. TM_CAUSE_SYSCALL Syscall from active transaction. TM_CAUSE_SIGNAL Signal delivered. @@ -185,7 +185,7 @@ kernel aborted a transaction: These can be checked by the user program's abort handler as TEXASR[0:7]. If bit 7 is set, it indicates that the error is consider persistent. For example -a TM_CAUSE_ALIGNMENT will be persistent while a TM_CAUSE_RESCHED will not.q +a TM_CAUSE_ALIGNMENT will be persistent while a TM_CAUSE_RESCHED will not. GDB === -- cgit v1.2.3-59-g8ed1b From 3250af197b0ad7b6935a955c7e5492cf49d39ccd Mon Sep 17 00:00:00 2001 From: Randy Wright Date: Fri, 10 Apr 2015 15:00:02 -0600 Subject: Documentation/vm/pagemap.txt: correct location of page-types tool The page-types tool was relocated to tools/vm in the 3.4 kernel timeframe. Signed-off-by: Randy Wright Signed-off-by: Jonathan Corbet --- Documentation/vm/pagemap.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/vm/pagemap.txt b/Documentation/vm/pagemap.txt index 6fbd55ef6b45..6bfbc172cdb9 100644 --- a/Documentation/vm/pagemap.txt +++ b/Documentation/vm/pagemap.txt @@ -131,7 +131,8 @@ Short descriptions to the page flags: 13. SWAPCACHE page is mapped to swap space, ie. has an associated swap entry 14. SWAPBACKED page is backed by swap/RAM -The page-types tool in this directory can be used to query the above flags. +The page-types tool in the tools/vm directory can be used to query the +above flags. Using pagemap to do something useful: -- cgit v1.2.3-59-g8ed1b From 82c91e87642dd6f88b9d9b1e5cc09232b6701eb0 Mon Sep 17 00:00:00 2001 From: Chen Gang Date: Sun, 5 Apr 2015 11:50:02 +0800 Subject: Documentation: blackfin: Makefile: Typo building issue Miss a ')' for ifneq in Makefile, the related building error: Documentation/blackfin/Makefile:2: *** invalid syntax in conditional. Stop. make[1]: *** [Documentation/blackfin] Error 2 Signed-off-by: Chen Gang Signed-off-by: Jonathan Corbet --- Documentation/blackfin/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/blackfin/Makefile b/Documentation/blackfin/Makefile index 03f78059d6f5..6782c58fbc29 100644 --- a/Documentation/blackfin/Makefile +++ b/Documentation/blackfin/Makefile @@ -1,5 +1,5 @@ ifneq ($(CONFIG_BLACKFIN),) -ifneq ($(CONFIG_BFIN_GPTIMERS,) +ifneq ($(CONFIG_BFIN_GPTIMERS),) obj-m := gptimers-example.o endif endif -- cgit v1.2.3-59-g8ed1b From 197175427a221fe3200f7727ea35e261727e7228 Mon Sep 17 00:00:00 2001 From: Vladimir Davydov Date: Wed, 1 Apr 2015 17:30:36 +0300 Subject: Documentation/memcg: update memcg/kmem status Memcg/kmem reclaim support has been finally merged. Reflect this in the documentation. Acked-by: Michal Hocko Signed-off-by: Vladimir Davydov Signed-off-by: Jonathan Corbet --- Documentation/cgroups/memory.txt | 8 +++----- init/Kconfig | 6 ------ 2 files changed, 3 insertions(+), 11 deletions(-) (limited to 'Documentation') diff --git a/Documentation/cgroups/memory.txt b/Documentation/cgroups/memory.txt index a22df3ad35ff..f456b4315e86 100644 --- a/Documentation/cgroups/memory.txt +++ b/Documentation/cgroups/memory.txt @@ -275,11 +275,6 @@ When oom event notifier is registered, event will be delivered. 2.7 Kernel Memory Extension (CONFIG_MEMCG_KMEM) -WARNING: Current implementation lacks reclaim support. That means allocation - attempts will fail when close to the limit even if there are plenty of - kmem available for reclaim. That makes this option unusable in real - life so DO NOT SELECT IT unless for development purposes. - With the Kernel memory extension, the Memory Controller is able to limit the amount of kernel memory used by the system. Kernel memory is fundamentally different than user memory, since it can't be swapped out, which makes it @@ -345,6 +340,9 @@ set: In this case, the admin could set up K so that the sum of all groups is never greater than the total memory, and freely set U at the cost of his QoS. + WARNING: In the current implementation, memory reclaim will NOT be + triggered for a cgroup when it hits K while staying below U, which makes + this setup impractical. U != 0, K >= U: Since kmem charges will also be fed to the user counter and reclaim will be diff --git a/init/Kconfig b/init/Kconfig index f5dbc6d4261b..115051093d2f 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1032,12 +1032,6 @@ config MEMCG_KMEM the kmem extension can use it to guarantee that no group of processes will ever exhaust kernel resources alone. - WARNING: Current implementation lacks reclaim support. That means - allocation attempts will fail when close to the limit even if there - are plenty of kmem available for reclaim. That makes this option - unusable in real life so DO NOT SELECT IT unless for development - purposes. - config CGROUP_HUGETLB bool "HugeTLB Resource Controller for Control Groups" depends on HUGETLB_PAGE -- cgit v1.2.3-59-g8ed1b From 5d5d568975307877e9195f5305f4240e506a2807 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 3 Apr 2015 15:41:18 -0400 Subject: make new_sync_{read,write}() static All places outside of core VFS that checked ->read and ->write for being NULL or called the methods directly are gone now, so NULL {read,write} with non-NULL {read,write}_iter will do the right thing in all cases. Signed-off-by: Al Viro --- Documentation/filesystems/porting | 9 +++++++++ arch/s390/hypfs/inode.c | 2 -- drivers/char/mem.c | 2 -- drivers/char/raw.c | 2 -- drivers/net/macvtap.c | 2 -- drivers/net/tun.c | 2 -- drivers/staging/lustre/lustre/llite/file.c | 6 ------ drivers/usb/gadget/function/f_fs.c | 2 -- drivers/usb/gadget/legacy/inode.c | 2 -- fs/9p/vfs_file.c | 12 ------------ fs/adfs/file.c | 2 -- fs/affs/file.c | 2 -- fs/afs/file.c | 2 -- fs/bfs/file.c | 2 -- fs/block_dev.c | 2 -- fs/btrfs/file.c | 2 -- fs/ceph/file.c | 2 -- fs/cifs/cifsfs.c | 12 ------------ fs/coda/file.c | 2 -- fs/ecryptfs/file.c | 2 -- fs/exofs/file.c | 2 -- fs/ext2/file.c | 4 ---- fs/ext3/file.c | 2 -- fs/ext4/file.c | 4 ---- fs/f2fs/file.c | 2 -- fs/fat/file.c | 2 -- fs/fuse/cuse.c | 2 -- fs/fuse/file.c | 4 ---- fs/gfs2/file.c | 4 ---- fs/hfs/inode.c | 2 -- fs/hfsplus/inode.c | 2 -- fs/hostfs/hostfs_kern.c | 2 -- fs/hpfs/file.c | 2 -- fs/hugetlbfs/inode.c | 1 - fs/jffs2/file.c | 2 -- fs/jfs/file.c | 2 -- fs/logfs/file.c | 2 -- fs/minix/file.c | 2 -- fs/ncpfs/file.c | 2 -- fs/nfs/file.c | 2 -- fs/nfs/nfs4file.c | 2 -- fs/nilfs2/file.c | 2 -- fs/ntfs/file.c | 2 -- fs/ocfs2/file.c | 4 ---- fs/omfs/file.c | 2 -- fs/pipe.c | 2 -- fs/ramfs/file-mmu.c | 2 -- fs/ramfs/file-nommu.c | 2 -- fs/read_write.c | 9 ++------- fs/reiserfs/file.c | 2 -- fs/romfs/mmap-nommu.c | 1 - fs/sysv/file.c | 2 -- fs/ubifs/file.c | 2 -- fs/udf/file.c | 2 -- fs/ufs/file.c | 2 -- fs/xfs/xfs_file.c | 2 -- include/linux/fs.h | 2 -- mm/shmem.c | 2 -- net/socket.c | 2 -- 59 files changed, 11 insertions(+), 153 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting index fa2db081505e..4006483c275f 100644 --- a/Documentation/filesystems/porting +++ b/Documentation/filesystems/porting @@ -471,3 +471,12 @@ in your dentry operations instead. [mandatory] f_dentry is gone; use f_path.dentry, or, better yet, see if you can avoid it entirely. +-- +[mandatory] + never call ->read() and ->write() directly; use __vfs_{read,write} or + wrappers; instead of checking for ->write or ->read being NULL, look for + FMODE_CAN_{WRITE,READ} in file->f_mode. +-- +[mandatory] + do _not_ use new_sync_{read,write} for ->read/->write; leave it NULL + instead. diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c index df7d8cbee377..3f5c799b7fb5 100644 --- a/arch/s390/hypfs/inode.c +++ b/arch/s390/hypfs/inode.c @@ -437,8 +437,6 @@ struct dentry *hypfs_create_str(struct dentry *dir, static const struct file_operations hypfs_file_ops = { .open = hypfs_open, .release = hypfs_release, - .read = new_sync_read, - .write = new_sync_write, .read_iter = hypfs_read_iter, .write_iter = hypfs_write_iter, .llseek = no_llseek, diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 9c4fd7a8e2e5..ad08400491ae 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -764,7 +764,6 @@ static const struct file_operations __maybe_unused port_fops = { static const struct file_operations zero_fops = { .llseek = zero_lseek, - .read = new_sync_read, .write = write_zero, .read_iter = read_iter_zero, .aio_write = aio_write_zero, @@ -776,7 +775,6 @@ static const struct file_operations zero_fops = { static const struct file_operations full_fops = { .llseek = full_lseek, - .read = new_sync_read, .read_iter = read_iter_zero, .write = write_full, }; diff --git a/drivers/char/raw.c b/drivers/char/raw.c index 6e29bf2db536..5fc291c6157e 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -282,9 +282,7 @@ static long raw_ctl_compat_ioctl(struct file *file, unsigned int cmd, #endif static const struct file_operations raw_fops = { - .read = new_sync_read, .read_iter = blkdev_read_iter, - .write = new_sync_write, .write_iter = blkdev_write_iter, .fsync = blkdev_fsync, .open = raw_open, diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 8362aef0c15e..9c91ff872485 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -1118,8 +1118,6 @@ static const struct file_operations macvtap_fops = { .owner = THIS_MODULE, .open = macvtap_open, .release = macvtap_release, - .read = new_sync_read, - .write = new_sync_write, .read_iter = macvtap_read_iter, .write_iter = macvtap_write_iter, .poll = macvtap_poll, diff --git a/drivers/net/tun.c b/drivers/net/tun.c index b96b94cee760..e470ae59d405 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -2223,8 +2223,6 @@ static void tun_chr_show_fdinfo(struct seq_file *m, struct file *f) static const struct file_operations tun_fops = { .owner = THIS_MODULE, .llseek = no_llseek, - .read = new_sync_read, - .write = new_sync_write, .read_iter = tun_chr_read_iter, .write_iter = tun_chr_write_iter, .poll = tun_chr_poll, diff --git a/drivers/staging/lustre/lustre/llite/file.c b/drivers/staging/lustre/lustre/llite/file.c index 5ebee6ca0a10..d73111ef949e 100644 --- a/drivers/staging/lustre/lustre/llite/file.c +++ b/drivers/staging/lustre/lustre/llite/file.c @@ -3128,9 +3128,7 @@ int ll_inode_permission(struct inode *inode, int mask) /* -o localflock - only provides locally consistent flock locks */ struct file_operations ll_file_operations = { - .read = new_sync_read, .read_iter = ll_file_read_iter, - .write = new_sync_write, .write_iter = ll_file_write_iter, .unlocked_ioctl = ll_file_ioctl, .open = ll_file_open, @@ -3143,9 +3141,7 @@ struct file_operations ll_file_operations = { }; struct file_operations ll_file_operations_flock = { - .read = new_sync_read, .read_iter = ll_file_read_iter, - .write = new_sync_write, .write_iter = ll_file_write_iter, .unlocked_ioctl = ll_file_ioctl, .open = ll_file_open, @@ -3161,9 +3157,7 @@ struct file_operations ll_file_operations_flock = { /* These are for -o noflock - to return ENOSYS on flock calls */ struct file_operations ll_file_operations_noflock = { - .read = new_sync_read, .read_iter = ll_file_read_iter, - .write = new_sync_write, .write_iter = ll_file_write_iter, .unlocked_ioctl = ll_file_ioctl, .open = ll_file_open, diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index a12315a78248..6bdb57069044 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -1061,8 +1061,6 @@ static const struct file_operations ffs_epfile_operations = { .llseek = no_llseek, .open = ffs_epfile_open, - .write = new_sync_write, - .read = new_sync_read, .write_iter = ffs_epfile_write_iter, .read_iter = ffs_epfile_read_iter, .release = ffs_epfile_release, diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c index 662ef2c1c62b..6af58c6dba5e 100644 --- a/drivers/usb/gadget/legacy/inode.c +++ b/drivers/usb/gadget/legacy/inode.c @@ -699,8 +699,6 @@ static const struct file_operations ep_io_operations = { .open = ep_open, .release = ep_release, .llseek = no_llseek, - .read = new_sync_read, - .write = new_sync_write, .unlocked_ioctl = ep_ioctl, .read_iter = ep_read_iter, .write_iter = ep_write_iter, diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index 55cc9c80e187..d7fcb775311e 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c @@ -641,8 +641,6 @@ static const struct vm_operations_struct v9fs_mmap_file_vm_ops = { const struct file_operations v9fs_cached_file_operations = { .llseek = generic_file_llseek, - .read = new_sync_read, - .write = new_sync_write, .read_iter = generic_file_read_iter, .write_iter = generic_file_write_iter, .open = v9fs_file_open, @@ -654,8 +652,6 @@ const struct file_operations v9fs_cached_file_operations = { const struct file_operations v9fs_cached_file_operations_dotl = { .llseek = generic_file_llseek, - .read = new_sync_read, - .write = new_sync_write, .read_iter = generic_file_read_iter, .write_iter = generic_file_write_iter, .open = v9fs_file_open, @@ -668,8 +664,6 @@ const struct file_operations v9fs_cached_file_operations_dotl = { const struct file_operations v9fs_file_operations = { .llseek = generic_file_llseek, - .read = new_sync_read, - .write = new_sync_write, .read_iter = v9fs_file_read_iter, .write_iter = v9fs_file_write_iter, .open = v9fs_file_open, @@ -681,8 +675,6 @@ const struct file_operations v9fs_file_operations = { const struct file_operations v9fs_file_operations_dotl = { .llseek = generic_file_llseek, - .read = new_sync_read, - .write = new_sync_write, .read_iter = v9fs_file_read_iter, .write_iter = v9fs_file_write_iter, .open = v9fs_file_open, @@ -695,8 +687,6 @@ const struct file_operations v9fs_file_operations_dotl = { const struct file_operations v9fs_mmap_file_operations = { .llseek = generic_file_llseek, - .read = new_sync_read, - .write = new_sync_write, .read_iter = v9fs_mmap_file_read_iter, .write_iter = v9fs_mmap_file_write_iter, .open = v9fs_file_open, @@ -708,8 +698,6 @@ const struct file_operations v9fs_mmap_file_operations = { const struct file_operations v9fs_mmap_file_operations_dotl = { .llseek = generic_file_llseek, - .read = new_sync_read, - .write = new_sync_write, .read_iter = v9fs_mmap_file_read_iter, .write_iter = v9fs_mmap_file_write_iter, .open = v9fs_file_open, diff --git a/fs/adfs/file.c b/fs/adfs/file.c index 07c9edce5aa7..46c0d5671cd5 100644 --- a/fs/adfs/file.c +++ b/fs/adfs/file.c @@ -23,11 +23,9 @@ const struct file_operations adfs_file_operations = { .llseek = generic_file_llseek, - .read = new_sync_read, .read_iter = generic_file_read_iter, .mmap = generic_file_mmap, .fsync = generic_file_fsync, - .write = new_sync_write, .write_iter = generic_file_write_iter, .splice_read = generic_file_splice_read, }; diff --git a/fs/affs/file.c b/fs/affs/file.c index 3aa7eb66547e..7c1a3d4c19c2 100644 --- a/fs/affs/file.c +++ b/fs/affs/file.c @@ -969,9 +969,7 @@ int affs_file_fsync(struct file *filp, loff_t start, loff_t end, int datasync) } const struct file_operations affs_file_operations = { .llseek = generic_file_llseek, - .read = new_sync_read, .read_iter = generic_file_read_iter, - .write = new_sync_write, .write_iter = generic_file_write_iter, .mmap = generic_file_mmap, .open = affs_file_open, diff --git a/fs/afs/file.c b/fs/afs/file.c index 932ce07948b3..999bc3caec92 100644 --- a/fs/afs/file.c +++ b/fs/afs/file.c @@ -31,8 +31,6 @@ const struct file_operations afs_file_operations = { .open = afs_open, .release = afs_release, .llseek = generic_file_llseek, - .read = new_sync_read, - .write = new_sync_write, .read_iter = generic_file_read_iter, .write_iter = afs_file_write, .mmap = generic_file_readonly_mmap, diff --git a/fs/bfs/file.c b/fs/bfs/file.c index e7f88ace1a25..97f1b5160155 100644 --- a/fs/bfs/file.c +++ b/fs/bfs/file.c @@ -23,9 +23,7 @@ const struct file_operations bfs_file_operations = { .llseek = generic_file_llseek, - .read = new_sync_read, .read_iter = generic_file_read_iter, - .write = new_sync_write, .write_iter = generic_file_write_iter, .mmap = generic_file_mmap, .splice_read = generic_file_splice_read, diff --git a/fs/block_dev.c b/fs/block_dev.c index 2e522aed6584..b5e87896f517 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -1659,8 +1659,6 @@ const struct file_operations def_blk_fops = { .open = blkdev_open, .release = blkdev_close, .llseek = block_llseek, - .read = new_sync_read, - .write = new_sync_write, .read_iter = blkdev_read_iter, .write_iter = blkdev_write_iter, .mmap = generic_file_mmap, diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index aee18f84e315..cdc801c85105 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -2806,8 +2806,6 @@ out: const struct file_operations btrfs_file_operations = { .llseek = btrfs_file_llseek, - .read = new_sync_read, - .write = new_sync_write, .read_iter = generic_file_read_iter, .splice_read = generic_file_splice_read, .write_iter = btrfs_file_write_iter, diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 139f2fea91a0..56237ea5fc22 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -1331,8 +1331,6 @@ const struct file_operations ceph_file_fops = { .open = ceph_open, .release = ceph_release, .llseek = ceph_llseek, - .read = new_sync_read, - .write = new_sync_write, .read_iter = ceph_read_iter, .write_iter = ceph_write_iter, .mmap = ceph_mmap, diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index d72fe37f5420..eaab4b2a0595 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -906,8 +906,6 @@ const struct inode_operations cifs_symlink_inode_ops = { }; const struct file_operations cifs_file_ops = { - .read = new_sync_read, - .write = new_sync_write, .read_iter = cifs_loose_read_iter, .write_iter = cifs_file_write_iter, .open = cifs_open, @@ -926,8 +924,6 @@ const struct file_operations cifs_file_ops = { }; const struct file_operations cifs_file_strict_ops = { - .read = new_sync_read, - .write = new_sync_write, .read_iter = cifs_strict_readv, .write_iter = cifs_strict_writev, .open = cifs_open, @@ -947,8 +943,6 @@ const struct file_operations cifs_file_strict_ops = { const struct file_operations cifs_file_direct_ops = { /* BB reevaluate whether they can be done with directio, no cache */ - .read = new_sync_read, - .write = new_sync_write, .read_iter = cifs_user_readv, .write_iter = cifs_user_writev, .open = cifs_open, @@ -967,8 +961,6 @@ const struct file_operations cifs_file_direct_ops = { }; const struct file_operations cifs_file_nobrl_ops = { - .read = new_sync_read, - .write = new_sync_write, .read_iter = cifs_loose_read_iter, .write_iter = cifs_file_write_iter, .open = cifs_open, @@ -986,8 +978,6 @@ const struct file_operations cifs_file_nobrl_ops = { }; const struct file_operations cifs_file_strict_nobrl_ops = { - .read = new_sync_read, - .write = new_sync_write, .read_iter = cifs_strict_readv, .write_iter = cifs_strict_writev, .open = cifs_open, @@ -1006,8 +996,6 @@ const struct file_operations cifs_file_strict_nobrl_ops = { const struct file_operations cifs_file_direct_nobrl_ops = { /* BB reevaluate whether they can be done with directio, no cache */ - .read = new_sync_read, - .write = new_sync_write, .read_iter = cifs_user_readv, .write_iter = cifs_user_writev, .open = cifs_open, diff --git a/fs/coda/file.c b/fs/coda/file.c index d9f1d9a85e04..1da3805f3ddc 100644 --- a/fs/coda/file.c +++ b/fs/coda/file.c @@ -219,8 +219,6 @@ int coda_fsync(struct file *coda_file, loff_t start, loff_t end, int datasync) const struct file_operations coda_file_operations = { .llseek = generic_file_llseek, - .read = new_sync_read, - .write = new_sync_write, .read_iter = coda_file_read_iter, .write_iter = coda_file_write_iter, .mmap = coda_file_mmap, diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c index 79675089443d..a65786e26b05 100644 --- a/fs/ecryptfs/file.c +++ b/fs/ecryptfs/file.c @@ -358,9 +358,7 @@ const struct file_operations ecryptfs_dir_fops = { const struct file_operations ecryptfs_main_fops = { .llseek = generic_file_llseek, - .read = new_sync_read, .read_iter = ecryptfs_read_update_atime, - .write = new_sync_write, .write_iter = generic_file_write_iter, .iterate = ecryptfs_readdir, .unlocked_ioctl = ecryptfs_unlocked_ioctl, diff --git a/fs/exofs/file.c b/fs/exofs/file.c index 1a376b42d305..906de66e8e7e 100644 --- a/fs/exofs/file.c +++ b/fs/exofs/file.c @@ -67,8 +67,6 @@ static int exofs_flush(struct file *file, fl_owner_t id) const struct file_operations exofs_file_operations = { .llseek = generic_file_llseek, - .read = new_sync_read, - .write = new_sync_write, .read_iter = generic_file_read_iter, .write_iter = generic_file_write_iter, .mmap = generic_file_mmap, diff --git a/fs/ext2/file.c b/fs/ext2/file.c index e31701713516..ef04fdb57dbf 100644 --- a/fs/ext2/file.c +++ b/fs/ext2/file.c @@ -92,8 +92,6 @@ int ext2_fsync(struct file *file, loff_t start, loff_t end, int datasync) */ const struct file_operations ext2_file_operations = { .llseek = generic_file_llseek, - .read = new_sync_read, - .write = new_sync_write, .read_iter = generic_file_read_iter, .write_iter = generic_file_write_iter, .unlocked_ioctl = ext2_ioctl, @@ -111,8 +109,6 @@ const struct file_operations ext2_file_operations = { #ifdef CONFIG_FS_DAX const struct file_operations ext2_dax_file_operations = { .llseek = generic_file_llseek, - .read = new_sync_read, - .write = new_sync_write, .read_iter = generic_file_read_iter, .write_iter = generic_file_write_iter, .unlocked_ioctl = ext2_ioctl, diff --git a/fs/ext3/file.c b/fs/ext3/file.c index a062fa1e1b11..3b8f650de22c 100644 --- a/fs/ext3/file.c +++ b/fs/ext3/file.c @@ -50,8 +50,6 @@ static int ext3_release_file (struct inode * inode, struct file * filp) const struct file_operations ext3_file_operations = { .llseek = generic_file_llseek, - .read = new_sync_read, - .write = new_sync_write, .read_iter = generic_file_read_iter, .write_iter = generic_file_write_iter, .unlocked_ioctl = ext3_ioctl, diff --git a/fs/ext4/file.c b/fs/ext4/file.c index 598abbbe6786..9ad03036d9f5 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c @@ -607,8 +607,6 @@ loff_t ext4_llseek(struct file *file, loff_t offset, int whence) const struct file_operations ext4_file_operations = { .llseek = ext4_llseek, - .read = new_sync_read, - .write = new_sync_write, .read_iter = generic_file_read_iter, .write_iter = ext4_file_write_iter, .unlocked_ioctl = ext4_ioctl, @@ -627,8 +625,6 @@ const struct file_operations ext4_file_operations = { #ifdef CONFIG_FS_DAX const struct file_operations ext4_dax_file_operations = { .llseek = ext4_llseek, - .read = new_sync_read, - .write = new_sync_write, .read_iter = generic_file_read_iter, .write_iter = ext4_file_write_iter, .unlocked_ioctl = ext4_ioctl, diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 98dac27bc3f7..df6a0596eccf 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -1104,8 +1104,6 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) const struct file_operations f2fs_file_operations = { .llseek = f2fs_llseek, - .read = new_sync_read, - .write = new_sync_write, .read_iter = generic_file_read_iter, .write_iter = generic_file_write_iter, .open = generic_file_open, diff --git a/fs/fat/file.c b/fs/fat/file.c index 8429c68e3057..1e98d333879f 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c @@ -170,8 +170,6 @@ int fat_file_fsync(struct file *filp, loff_t start, loff_t end, int datasync) const struct file_operations fat_file_operations = { .llseek = generic_file_llseek, - .read = new_sync_read, - .write = new_sync_write, .read_iter = generic_file_read_iter, .write_iter = generic_file_write_iter, .mmap = generic_file_mmap, diff --git a/fs/fuse/cuse.c b/fs/fuse/cuse.c index 644f05744993..e5bbf748b698 100644 --- a/fs/fuse/cuse.c +++ b/fs/fuse/cuse.c @@ -177,8 +177,6 @@ static long cuse_file_compat_ioctl(struct file *file, unsigned int cmd, static const struct file_operations cuse_frontend_fops = { .owner = THIS_MODULE, - .read = new_sync_read, - .write = new_sync_write, .read_iter = cuse_read_iter, .write_iter = cuse_write_iter, .open = cuse_open, diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 727e139e1fea..e1afdd7abf90 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -2953,9 +2953,7 @@ out: static const struct file_operations fuse_file_operations = { .llseek = fuse_file_llseek, - .read = new_sync_read, .read_iter = fuse_file_read_iter, - .write = new_sync_write, .write_iter = fuse_file_write_iter, .mmap = fuse_file_mmap, .open = fuse_open, @@ -2973,9 +2971,7 @@ static const struct file_operations fuse_file_operations = { static const struct file_operations fuse_direct_io_file_operations = { .llseek = fuse_file_llseek, - .read = new_sync_read, .read_iter = fuse_direct_read_iter, - .write = new_sync_write, .write_iter = fuse_direct_write_iter, .mmap = fuse_direct_mmap, .open = fuse_open, diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index f6fc412b1100..614bb42cb7e1 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c @@ -1064,9 +1064,7 @@ static int gfs2_flock(struct file *file, int cmd, struct file_lock *fl) const struct file_operations gfs2_file_fops = { .llseek = gfs2_llseek, - .read = new_sync_read, .read_iter = generic_file_read_iter, - .write = new_sync_write, .write_iter = gfs2_file_write_iter, .unlocked_ioctl = gfs2_ioctl, .mmap = gfs2_mmap, @@ -1096,9 +1094,7 @@ const struct file_operations gfs2_dir_fops = { const struct file_operations gfs2_file_fops_nolock = { .llseek = gfs2_llseek, - .read = new_sync_read, .read_iter = generic_file_read_iter, - .write = new_sync_write, .write_iter = gfs2_file_write_iter, .unlocked_ioctl = gfs2_ioctl, .mmap = gfs2_mmap, diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c index 98d4ea45bb70..9337065bcc67 100644 --- a/fs/hfs/inode.c +++ b/fs/hfs/inode.c @@ -674,9 +674,7 @@ static int hfs_file_fsync(struct file *filp, loff_t start, loff_t end, static const struct file_operations hfs_file_operations = { .llseek = generic_file_llseek, - .read = new_sync_read, .read_iter = generic_file_read_iter, - .write = new_sync_write, .write_iter = generic_file_write_iter, .mmap = generic_file_mmap, .splice_read = generic_file_splice_read, diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index f541196d4ee9..5f86cadb0542 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c @@ -341,9 +341,7 @@ static const struct inode_operations hfsplus_file_inode_operations = { static const struct file_operations hfsplus_file_operations = { .llseek = generic_file_llseek, - .read = new_sync_read, .read_iter = generic_file_read_iter, - .write = new_sync_write, .write_iter = generic_file_write_iter, .mmap = generic_file_mmap, .splice_read = generic_file_splice_read, diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index fd62cae0fdcb..e021188ca110 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c @@ -378,11 +378,9 @@ static int hostfs_fsync(struct file *file, loff_t start, loff_t end, static const struct file_operations hostfs_file_fops = { .llseek = generic_file_llseek, - .read = new_sync_read, .splice_read = generic_file_splice_read, .read_iter = generic_file_read_iter, .write_iter = generic_file_write_iter, - .write = new_sync_write, .mmap = generic_file_mmap, .open = hostfs_file_open, .release = hostfs_file_release, diff --git a/fs/hpfs/file.c b/fs/hpfs/file.c index 7f54e5f76cec..6d8cfe9b52d6 100644 --- a/fs/hpfs/file.c +++ b/fs/hpfs/file.c @@ -197,9 +197,7 @@ const struct address_space_operations hpfs_aops = { const struct file_operations hpfs_file_ops = { .llseek = generic_file_llseek, - .read = new_sync_read, .read_iter = generic_file_read_iter, - .write = new_sync_write, .write_iter = generic_file_write_iter, .mmap = generic_file_mmap, .release = hpfs_file_release, diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 5291c14ee6b8..8c2dad629e7c 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -696,7 +696,6 @@ static void init_once(void *foo) } const struct file_operations hugetlbfs_file_operations = { - .read = new_sync_read, .read_iter = hugetlbfs_read_iter, .mmap = hugetlbfs_file_mmap, .fsync = noop_fsync, diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c index 64989ca9ba90..f509f62e12f6 100644 --- a/fs/jffs2/file.c +++ b/fs/jffs2/file.c @@ -51,9 +51,7 @@ const struct file_operations jffs2_file_operations = { .llseek = generic_file_llseek, .open = generic_file_open, - .read = new_sync_read, .read_iter = generic_file_read_iter, - .write = new_sync_write, .write_iter = generic_file_write_iter, .unlocked_ioctl=jffs2_ioctl, .mmap = generic_file_readonly_mmap, diff --git a/fs/jfs/file.c b/fs/jfs/file.c index 10815f8dfd8b..ae46788b9723 100644 --- a/fs/jfs/file.c +++ b/fs/jfs/file.c @@ -151,8 +151,6 @@ const struct inode_operations jfs_file_inode_operations = { const struct file_operations jfs_file_operations = { .open = jfs_open, .llseek = generic_file_llseek, - .write = new_sync_write, - .read = new_sync_read, .read_iter = generic_file_read_iter, .write_iter = generic_file_write_iter, .mmap = generic_file_mmap, diff --git a/fs/logfs/file.c b/fs/logfs/file.c index 8538752df2f6..b2c13f739ffa 100644 --- a/fs/logfs/file.c +++ b/fs/logfs/file.c @@ -271,8 +271,6 @@ const struct file_operations logfs_reg_fops = { .llseek = generic_file_llseek, .mmap = generic_file_readonly_mmap, .open = generic_file_open, - .read = new_sync_read, - .write = new_sync_write, }; const struct address_space_operations logfs_reg_aops = { diff --git a/fs/minix/file.c b/fs/minix/file.c index a967de085ac0..6d63e27ec961 100644 --- a/fs/minix/file.c +++ b/fs/minix/file.c @@ -14,9 +14,7 @@ */ const struct file_operations minix_file_operations = { .llseek = generic_file_llseek, - .read = new_sync_read, .read_iter = generic_file_read_iter, - .write = new_sync_write, .write_iter = generic_file_write_iter, .mmap = generic_file_mmap, .fsync = generic_file_fsync, diff --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c index 5f9d5624e377..479bf8db264e 100644 --- a/fs/ncpfs/file.c +++ b/fs/ncpfs/file.c @@ -249,8 +249,6 @@ static int ncp_release(struct inode *inode, struct file *file) { const struct file_operations ncp_file_operations = { .llseek = generic_file_llseek, - .read = new_sync_read, - .write = new_sync_write, .read_iter = ncp_file_read_iter, .write_iter = ncp_file_write_iter, .unlocked_ioctl = ncp_ioctl, diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 37b15582e0de..f6a3adedf027 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -926,8 +926,6 @@ EXPORT_SYMBOL_GPL(nfs_flock); const struct file_operations nfs_file_operations = { .llseek = nfs_file_llseek, - .read = new_sync_read, - .write = new_sync_write, .read_iter = nfs_file_read, .write_iter = nfs_file_write, .mmap = nfs_file_mmap, diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c index 8b46389c4c5b..0181cde1d102 100644 --- a/fs/nfs/nfs4file.c +++ b/fs/nfs/nfs4file.c @@ -170,8 +170,6 @@ const struct file_operations nfs4_file_operations = { #else .llseek = nfs_file_llseek, #endif - .read = new_sync_read, - .write = new_sync_write, .read_iter = nfs_file_read, .write_iter = nfs_file_write, .mmap = nfs_file_mmap, diff --git a/fs/nilfs2/file.c b/fs/nilfs2/file.c index a8c728acb7a8..54575e3cc1a2 100644 --- a/fs/nilfs2/file.c +++ b/fs/nilfs2/file.c @@ -143,8 +143,6 @@ static int nilfs_file_mmap(struct file *file, struct vm_area_struct *vma) */ const struct file_operations nilfs_file_operations = { .llseek = generic_file_llseek, - .read = new_sync_read, - .write = new_sync_write, .read_iter = generic_file_read_iter, .write_iter = generic_file_write_iter, .unlocked_ioctl = nilfs_ioctl, diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c index c1da78dad1af..840e95e3f1d2 100644 --- a/fs/ntfs/file.c +++ b/fs/ntfs/file.c @@ -2048,10 +2048,8 @@ static int ntfs_file_fsync(struct file *filp, loff_t start, loff_t end, const struct file_operations ntfs_file_ops = { .llseek = generic_file_llseek, - .read = new_sync_read, .read_iter = generic_file_read_iter, #ifdef NTFS_RW - .write = new_sync_write, .write_iter = ntfs_file_write_iter, .fsync = ntfs_file_fsync, #endif /* NTFS_RW */ diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 266845de2100..0a6ec7e6efd8 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -2676,8 +2676,6 @@ const struct inode_operations ocfs2_special_file_iops = { */ const struct file_operations ocfs2_fops = { .llseek = ocfs2_file_llseek, - .read = new_sync_read, - .write = new_sync_write, .mmap = ocfs2_mmap, .fsync = ocfs2_sync_file, .release = ocfs2_file_release, @@ -2724,8 +2722,6 @@ const struct file_operations ocfs2_dops = { */ const struct file_operations ocfs2_fops_no_plocks = { .llseek = ocfs2_file_llseek, - .read = new_sync_read, - .write = new_sync_write, .mmap = ocfs2_mmap, .fsync = ocfs2_sync_file, .release = ocfs2_file_release, diff --git a/fs/omfs/file.c b/fs/omfs/file.c index 902e88527fce..f993be7f2156 100644 --- a/fs/omfs/file.c +++ b/fs/omfs/file.c @@ -337,8 +337,6 @@ static sector_t omfs_bmap(struct address_space *mapping, sector_t block) const struct file_operations omfs_file_operations = { .llseek = generic_file_llseek, - .read = new_sync_read, - .write = new_sync_write, .read_iter = generic_file_read_iter, .write_iter = generic_file_write_iter, .mmap = generic_file_mmap, diff --git a/fs/pipe.c b/fs/pipe.c index 2d084f2d0b83..822da5b7cff0 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -946,9 +946,7 @@ err: const struct file_operations pipefifo_fops = { .open = fifo_open, .llseek = no_llseek, - .read = new_sync_read, .read_iter = pipe_read, - .write = new_sync_write, .write_iter = pipe_write, .poll = pipe_poll, .unlocked_ioctl = pipe_ioctl, diff --git a/fs/ramfs/file-mmu.c b/fs/ramfs/file-mmu.c index 4f56de822d2f..183a212694bf 100644 --- a/fs/ramfs/file-mmu.c +++ b/fs/ramfs/file-mmu.c @@ -31,9 +31,7 @@ #include "internal.h" const struct file_operations ramfs_file_operations = { - .read = new_sync_read, .read_iter = generic_file_read_iter, - .write = new_sync_write, .write_iter = generic_file_write_iter, .mmap = generic_file_mmap, .fsync = noop_fsync, diff --git a/fs/ramfs/file-nommu.c b/fs/ramfs/file-nommu.c index f6ab41b39612..0b38befa69f3 100644 --- a/fs/ramfs/file-nommu.c +++ b/fs/ramfs/file-nommu.c @@ -44,9 +44,7 @@ const struct file_operations ramfs_file_operations = { .mmap_capabilities = ramfs_mmap_capabilities, .mmap = ramfs_nommu_mmap, .get_unmapped_area = ramfs_nommu_get_unmapped_area, - .read = new_sync_read, .read_iter = generic_file_read_iter, - .write = new_sync_write, .write_iter = generic_file_write_iter, .fsync = noop_fsync, .splice_read = generic_file_splice_read, diff --git a/fs/read_write.c b/fs/read_write.c index c75e6ef0952c..3ae8eee3b82a 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -28,7 +28,6 @@ typedef ssize_t (*iter_fn_t)(struct kiocb *, struct iov_iter *); const struct file_operations generic_ro_fops = { .llseek = generic_file_llseek, - .read = new_sync_read, .read_iter = generic_file_read_iter, .mmap = generic_file_readonly_mmap, .splice_read = generic_file_splice_read, @@ -428,7 +427,7 @@ ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *pp EXPORT_SYMBOL(do_sync_read); -ssize_t new_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos) +static ssize_t new_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos) { struct iovec iov = { .iov_base = buf, .iov_len = len }; struct kiocb kiocb; @@ -445,8 +444,6 @@ ssize_t new_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *p return ret; } -EXPORT_SYMBOL(new_sync_read); - ssize_t __vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { @@ -505,7 +502,7 @@ ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, lof EXPORT_SYMBOL(do_sync_write); -ssize_t new_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos) +static ssize_t new_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos) { struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = len }; struct kiocb kiocb; @@ -522,8 +519,6 @@ ssize_t new_sync_write(struct file *filp, const char __user *buf, size_t len, lo return ret; } -EXPORT_SYMBOL(new_sync_write); - ssize_t __vfs_write(struct file *file, const char __user *p, size_t count, loff_t *pos) { diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c index 751dd3f4346b..96a1bcf33db4 100644 --- a/fs/reiserfs/file.c +++ b/fs/reiserfs/file.c @@ -243,8 +243,6 @@ drop_write_lock: } const struct file_operations reiserfs_file_operations = { - .read = new_sync_read, - .write = new_sync_write, .unlocked_ioctl = reiserfs_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = reiserfs_compat_ioctl, diff --git a/fs/romfs/mmap-nommu.c b/fs/romfs/mmap-nommu.c index 7da9e2153953..1118a0dc6b45 100644 --- a/fs/romfs/mmap-nommu.c +++ b/fs/romfs/mmap-nommu.c @@ -81,7 +81,6 @@ static unsigned romfs_mmap_capabilities(struct file *file) const struct file_operations romfs_ro_fops = { .llseek = generic_file_llseek, - .read = new_sync_read, .read_iter = generic_file_read_iter, .splice_read = generic_file_splice_read, .mmap = romfs_mmap, diff --git a/fs/sysv/file.c b/fs/sysv/file.c index b00811c75b24..a48e30410ad1 100644 --- a/fs/sysv/file.c +++ b/fs/sysv/file.c @@ -21,9 +21,7 @@ */ const struct file_operations sysv_file_operations = { .llseek = generic_file_llseek, - .read = new_sync_read, .read_iter = generic_file_read_iter, - .write = new_sync_write, .write_iter = generic_file_write_iter, .mmap = generic_file_mmap, .fsync = generic_file_fsync, diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c index c3d15fe83403..475b15635f11 100644 --- a/fs/ubifs/file.c +++ b/fs/ubifs/file.c @@ -1580,8 +1580,6 @@ const struct inode_operations ubifs_symlink_inode_operations = { const struct file_operations ubifs_file_operations = { .llseek = generic_file_llseek, - .read = new_sync_read, - .write = new_sync_write, .read_iter = generic_file_read_iter, .write_iter = ubifs_write_iter, .mmap = ubifs_file_mmap, diff --git a/fs/udf/file.c b/fs/udf/file.c index 7f885cc8b0b7..74050bff64f4 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c @@ -240,12 +240,10 @@ static int udf_release_file(struct inode *inode, struct file *filp) } const struct file_operations udf_file_operations = { - .read = new_sync_read, .read_iter = generic_file_read_iter, .unlocked_ioctl = udf_ioctl, .open = generic_file_open, .mmap = generic_file_mmap, - .write = new_sync_write, .write_iter = udf_file_write_iter, .release = udf_release_file, .fsync = generic_file_fsync, diff --git a/fs/ufs/file.c b/fs/ufs/file.c index c84ec010a676..042ddbf110cc 100644 --- a/fs/ufs/file.c +++ b/fs/ufs/file.c @@ -35,9 +35,7 @@ const struct file_operations ufs_file_operations = { .llseek = generic_file_llseek, - .read = new_sync_read, .read_iter = generic_file_read_iter, - .write = new_sync_write, .write_iter = generic_file_write_iter, .mmap = generic_file_mmap, .open = generic_file_open, diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index f44212fae653..44856c3b9617 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c @@ -1386,8 +1386,6 @@ xfs_file_llseek( const struct file_operations xfs_file_operations = { .llseek = xfs_file_llseek, - .read = new_sync_read, - .write = new_sync_write, .read_iter = xfs_file_read_iter, .write_iter = xfs_file_write_iter, .splice_read = xfs_file_splice_read, diff --git a/include/linux/fs.h b/include/linux/fs.h index 4a1cb00bd805..cade1304d27b 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2576,8 +2576,6 @@ extern ssize_t generic_file_direct_write(struct kiocb *, struct iov_iter *, loff extern ssize_t generic_perform_write(struct file *, struct iov_iter *, loff_t); extern ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos); extern ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos); -extern ssize_t new_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos); -extern ssize_t new_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos); ssize_t vfs_iter_read(struct file *file, struct iov_iter *iter, loff_t *ppos); ssize_t vfs_iter_write(struct file *file, struct iov_iter *iter, loff_t *ppos); diff --git a/mm/shmem.c b/mm/shmem.c index 80b360c7bcd1..1ea2400b5245 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -3118,8 +3118,6 @@ static const struct file_operations shmem_file_operations = { .mmap = shmem_mmap, #ifdef CONFIG_TMPFS .llseek = shmem_file_llseek, - .read = new_sync_read, - .write = new_sync_write, .read_iter = shmem_file_read_iter, .write_iter = generic_file_write_iter, .fsync = noop_fsync, diff --git a/net/socket.c b/net/socket.c index 5b0126234606..3e33959f3ce5 100644 --- a/net/socket.c +++ b/net/socket.c @@ -140,8 +140,6 @@ static ssize_t sock_splice_read(struct file *file, loff_t *ppos, static const struct file_operations socket_file_ops = { .owner = THIS_MODULE, .llseek = no_llseek, - .read = new_sync_read, - .write = new_sync_write, .read_iter = sock_read_iter, .write_iter = sock_write_iter, .poll = sock_poll, -- cgit v1.2.3-59-g8ed1b From 8436318205b9f29e45db88850ec60e326327e241 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 4 Apr 2015 01:14:53 -0400 Subject: ->aio_read and ->aio_write removed no remaining users Signed-off-by: Al Viro --- Documentation/filesystems/Locking | 2 -- Documentation/filesystems/porting | 3 +++ Documentation/filesystems/vfs.txt | 6 ------ fs/aio.c | 13 ++----------- fs/file_table.c | 4 ++-- fs/open.c | 4 ++-- fs/read_write.c | 29 ----------------------------- include/linux/fs.h | 2 -- 8 files changed, 9 insertions(+), 54 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking index f91926f2f482..c3cd6279e92e 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/Locking @@ -429,8 +429,6 @@ prototypes: loff_t (*llseek) (struct file *, loff_t, int); ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); - ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t); - ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t); ssize_t (*read_iter) (struct kiocb *, struct iov_iter *); ssize_t (*write_iter) (struct kiocb *, struct iov_iter *); int (*iterate) (struct file *, struct dir_context *); diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting index 4006483c275f..e69274de8d0c 100644 --- a/Documentation/filesystems/porting +++ b/Documentation/filesystems/porting @@ -480,3 +480,6 @@ in your dentry operations instead. [mandatory] do _not_ use new_sync_{read,write} for ->read/->write; leave it NULL instead. +-- +[mandatory] + ->aio_read/->aio_write are gone. Use ->read_iter/->write_iter. diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt index 966b22829f3b..207cdca68bed 100644 --- a/Documentation/filesystems/vfs.txt +++ b/Documentation/filesystems/vfs.txt @@ -804,8 +804,6 @@ struct file_operations { loff_t (*llseek) (struct file *, loff_t, int); ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); - ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t); - ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t); ssize_t (*read_iter) (struct kiocb *, struct iov_iter *); ssize_t (*write_iter) (struct kiocb *, struct iov_iter *); int (*iterate) (struct file *, struct dir_context *); @@ -838,14 +836,10 @@ otherwise noted. read: called by read(2) and related system calls - aio_read: vectored, possibly asynchronous read - read_iter: possibly asynchronous read with iov_iter as destination write: called by write(2) and related system calls - aio_write: vectored, possibly asynchronous write - write_iter: possibly asynchronous write with iov_iter as source iterate: called when the VFS needs to read the directory contents diff --git a/fs/aio.c b/fs/aio.c index f0b0a2f8a63f..8eece807abed 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -1347,8 +1347,6 @@ SYSCALL_DEFINE1(io_destroy, aio_context_t, ctx) return -EINVAL; } -typedef ssize_t (aio_rw_op)(struct kiocb *, const struct iovec *, - unsigned long, loff_t); typedef ssize_t (rw_iter_op)(struct kiocb *, struct iov_iter *); static int aio_setup_vectored_rw(int rw, char __user *buf, size_t len, @@ -1377,7 +1375,6 @@ static ssize_t aio_run_iocb(struct kiocb *req, unsigned opcode, ssize_t ret; int rw; fmode_t mode; - aio_rw_op *rw_op; rw_iter_op *iter_op; struct iovec inline_vecs[UIO_FASTIOV], *iovec = inline_vecs; struct iov_iter iter; @@ -1387,7 +1384,6 @@ static ssize_t aio_run_iocb(struct kiocb *req, unsigned opcode, case IOCB_CMD_PREADV: mode = FMODE_READ; rw = READ; - rw_op = file->f_op->aio_read; iter_op = file->f_op->read_iter; goto rw_common; @@ -1395,14 +1391,13 @@ static ssize_t aio_run_iocb(struct kiocb *req, unsigned opcode, case IOCB_CMD_PWRITEV: mode = FMODE_WRITE; rw = WRITE; - rw_op = file->f_op->aio_write; iter_op = file->f_op->write_iter; goto rw_common; rw_common: if (unlikely(!(file->f_mode & mode))) return -EBADF; - if (!rw_op && !iter_op) + if (!iter_op) return -EINVAL; if (opcode == IOCB_CMD_PREADV || opcode == IOCB_CMD_PWRITEV) @@ -1425,11 +1420,7 @@ rw_common: if (rw == WRITE) file_start_write(file); - if (iter_op) { - ret = iter_op(req, &iter); - } else { - ret = rw_op(req, iter.iov, iter.nr_segs, req->ki_pos); - } + ret = iter_op(req, &iter); if (rw == WRITE) file_end_write(file); diff --git a/fs/file_table.c b/fs/file_table.c index 3f85411b03ce..294174dcc226 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -168,10 +168,10 @@ struct file *alloc_file(struct path *path, fmode_t mode, file->f_inode = path->dentry->d_inode; file->f_mapping = path->dentry->d_inode->i_mapping; if ((mode & FMODE_READ) && - likely(fop->read || fop->aio_read || fop->read_iter)) + likely(fop->read || fop->read_iter)) mode |= FMODE_CAN_READ; if ((mode & FMODE_WRITE) && - likely(fop->write || fop->aio_write || fop->write_iter)) + likely(fop->write || fop->write_iter)) mode |= FMODE_CAN_WRITE; file->f_mode = mode; file->f_op = fop; diff --git a/fs/open.c b/fs/open.c index 6a83c47d5904..6796f04d6032 100644 --- a/fs/open.c +++ b/fs/open.c @@ -734,10 +734,10 @@ static int do_dentry_open(struct file *f, if ((f->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) i_readcount_inc(inode); if ((f->f_mode & FMODE_READ) && - likely(f->f_op->read || f->f_op->aio_read || f->f_op->read_iter)) + likely(f->f_op->read || f->f_op->read_iter)) f->f_mode |= FMODE_CAN_READ; if ((f->f_mode & FMODE_WRITE) && - likely(f->f_op->write || f->f_op->aio_write || f->f_op->write_iter)) + likely(f->f_op->write || f->f_op->write_iter)) f->f_mode |= FMODE_CAN_WRITE; f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); diff --git a/fs/read_write.c b/fs/read_write.c index 3d42d8ee5940..45d583c33879 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -22,8 +22,6 @@ #include typedef ssize_t (*io_fn_t)(struct file *, char __user *, size_t, loff_t *); -typedef ssize_t (*iov_fn_t)(struct kiocb *, const struct iovec *, - unsigned long, loff_t); typedef ssize_t (*iter_fn_t)(struct kiocb *, struct iov_iter *); const struct file_operations generic_ro_fops = { @@ -668,21 +666,6 @@ static ssize_t do_iter_readv_writev(struct file *filp, struct iov_iter *iter, return ret; } -static ssize_t do_sync_readv_writev(struct file *filp, struct iov_iter *iter, - loff_t *ppos, iov_fn_t fn) -{ - struct kiocb kiocb; - ssize_t ret; - - init_sync_kiocb(&kiocb, filp); - kiocb.ki_pos = *ppos; - - ret = fn(&kiocb, iter->iov, iter->nr_segs, kiocb.ki_pos); - BUG_ON(ret == -EIOCBQUEUED); - *ppos = kiocb.ki_pos; - return ret; -} - /* Do it by hand, with file-ops */ static ssize_t do_loop_readv_writev(struct file *filp, struct iov_iter *iter, loff_t *ppos, io_fn_t fn) @@ -797,7 +780,6 @@ static ssize_t do_readv_writev(int type, struct file *file, struct iov_iter iter; ssize_t ret; io_fn_t fn; - iov_fn_t fnv; iter_fn_t iter_fn; ret = import_iovec(type, uvector, nr_segs, @@ -812,22 +794,17 @@ static ssize_t do_readv_writev(int type, struct file *file, if (ret < 0) goto out; - fnv = NULL; if (type == READ) { fn = file->f_op->read; - fnv = file->f_op->aio_read; iter_fn = file->f_op->read_iter; } else { fn = (io_fn_t)file->f_op->write; - fnv = file->f_op->aio_write; iter_fn = file->f_op->write_iter; file_start_write(file); } if (iter_fn) ret = do_iter_readv_writev(file, &iter, pos, iter_fn); - else if (fnv) - ret = do_sync_readv_writev(file, &iter, pos, fnv); else ret = do_loop_readv_writev(file, &iter, pos, fn); @@ -977,7 +954,6 @@ static ssize_t compat_do_readv_writev(int type, struct file *file, struct iov_iter iter; ssize_t ret; io_fn_t fn; - iov_fn_t fnv; iter_fn_t iter_fn; ret = compat_import_iovec(type, uvector, nr_segs, @@ -992,22 +968,17 @@ static ssize_t compat_do_readv_writev(int type, struct file *file, if (ret < 0) goto out; - fnv = NULL; if (type == READ) { fn = file->f_op->read; - fnv = file->f_op->aio_read; iter_fn = file->f_op->read_iter; } else { fn = (io_fn_t)file->f_op->write; - fnv = file->f_op->aio_write; iter_fn = file->f_op->write_iter; file_start_write(file); } if (iter_fn) ret = do_iter_readv_writev(file, &iter, pos, iter_fn); - else if (fnv) - ret = do_sync_readv_writev(file, &iter, pos, fnv); else ret = do_loop_readv_writev(file, &iter, pos, fn); diff --git a/include/linux/fs.h b/include/linux/fs.h index 83e122c1a902..f1e3f65255a8 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1562,8 +1562,6 @@ struct file_operations { loff_t (*llseek) (struct file *, loff_t, int); ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); - ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t); - ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t); ssize_t (*read_iter) (struct kiocb *, struct iov_iter *); ssize_t (*write_iter) (struct kiocb *, struct iov_iter *); int (*iterate) (struct file *, struct dir_context *); -- cgit v1.2.3-59-g8ed1b From 22c6186ecea0be9eff1c399298ad36e94a59995f Mon Sep 17 00:00:00 2001 From: Omar Sandoval Date: Mon, 16 Mar 2015 04:33:53 -0700 Subject: direct_IO: remove rw from a_ops->direct_IO() Now that no one is using rw, remove it completely. Signed-off-by: Omar Sandoval Signed-off-by: Al Viro --- Documentation/filesystems/Locking | 2 +- Documentation/filesystems/vfs.txt | 2 +- drivers/staging/lustre/lustre/llite/rw26.c | 4 ++-- fs/9p/vfs_addr.c | 3 +-- fs/affs/file.c | 3 +-- fs/block_dev.c | 3 +-- fs/btrfs/inode.c | 4 ++-- fs/ceph/addr.c | 3 +-- fs/cifs/file.c | 3 +-- fs/exofs/inode.c | 4 ++-- fs/ext2/inode.c | 3 +-- fs/ext3/inode.c | 4 ++-- fs/ext4/inode.c | 4 ++-- fs/f2fs/data.c | 4 ++-- fs/fat/inode.c | 3 +-- fs/fuse/file.c | 3 +-- fs/gfs2/aops.c | 4 ++-- fs/hfs/inode.c | 4 ++-- fs/hfsplus/inode.c | 4 ++-- fs/jfs/inode.c | 4 ++-- fs/nfs/direct.c | 3 +-- fs/nilfs2/inode.c | 3 +-- fs/ocfs2/aops.c | 4 +--- fs/reiserfs/inode.c | 4 ++-- fs/udf/file.c | 3 +-- fs/udf/inode.c | 3 +-- fs/xfs/xfs_aops.c | 1 - include/linux/fs.h | 2 +- include/linux/nfs_fs.h | 2 +- mm/filemap.c | 4 ++-- mm/page_io.c | 4 +--- 31 files changed, 42 insertions(+), 59 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking index c3cd6279e92e..7cdbca44e343 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/Locking @@ -196,7 +196,7 @@ prototypes: void (*invalidatepage) (struct page *, unsigned int, unsigned int); int (*releasepage) (struct page *, int); void (*freepage)(struct page *); - int (*direct_IO)(int, struct kiocb *, struct iov_iter *iter, loff_t offset); + int (*direct_IO)(struct kiocb *, struct iov_iter *iter, loff_t offset); int (*migratepage)(struct address_space *, struct page *, struct page *); int (*launder_page)(struct page *); int (*is_partially_uptodate)(struct page *, unsigned long, unsigned long); diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt index 207cdca68bed..5d833b32bbcd 100644 --- a/Documentation/filesystems/vfs.txt +++ b/Documentation/filesystems/vfs.txt @@ -590,7 +590,7 @@ struct address_space_operations { void (*invalidatepage) (struct page *, unsigned int, unsigned int); int (*releasepage) (struct page *, int); void (*freepage)(struct page *); - ssize_t (*direct_IO)(int, struct kiocb *, struct iov_iter *iter, loff_t offset); + ssize_t (*direct_IO)(struct kiocb *, struct iov_iter *iter, loff_t offset); /* migrate the contents of a page to the specified target */ int (*migratepage) (struct page *, struct page *); int (*launder_page) (struct page *); diff --git a/drivers/staging/lustre/lustre/llite/rw26.c b/drivers/staging/lustre/lustre/llite/rw26.c index 3aa9de6bcc40..0d7ce6b0e23c 100644 --- a/drivers/staging/lustre/lustre/llite/rw26.c +++ b/drivers/staging/lustre/lustre/llite/rw26.c @@ -359,8 +359,8 @@ static ssize_t ll_direct_IO_26_seg(const struct lu_env *env, struct cl_io *io, * up to 22MB for 128kB kmalloc and up to 682MB for 4MB kmalloc. */ #define MAX_DIO_SIZE ((MAX_MALLOC / sizeof(struct brw_page) * PAGE_CACHE_SIZE) & \ ~(DT_MAX_BRW_SIZE - 1)) -static ssize_t ll_direct_IO_26(int rw, struct kiocb *iocb, - struct iov_iter *iter, loff_t file_offset) +static ssize_t ll_direct_IO_26(struct kiocb *iocb, struct iov_iter *iter, + loff_t file_offset) { struct lu_env *env; struct cl_io *io; diff --git a/fs/9p/vfs_addr.c b/fs/9p/vfs_addr.c index dd5543b1d183..be35d05a4d0e 100644 --- a/fs/9p/vfs_addr.c +++ b/fs/9p/vfs_addr.c @@ -230,7 +230,6 @@ static int v9fs_launder_page(struct page *page) /** * v9fs_direct_IO - 9P address space operation for direct I/O - * @rw: direction (read or write) * @iocb: target I/O control block * @iov: array of vectors that define I/O buffer * @pos: offset in file to begin the operation @@ -248,7 +247,7 @@ static int v9fs_launder_page(struct page *page) * */ static ssize_t -v9fs_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, loff_t pos) +v9fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter, loff_t pos) { struct file *file = iocb->ki_filp; ssize_t n; diff --git a/fs/affs/file.c b/fs/affs/file.c index 7f05a468d594..dcf27951781c 100644 --- a/fs/affs/file.c +++ b/fs/affs/file.c @@ -389,8 +389,7 @@ static void affs_write_failed(struct address_space *mapping, loff_t to) } static ssize_t -affs_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, - loff_t offset) +affs_direct_IO(struct kiocb *iocb, struct iov_iter *iter, loff_t offset) { struct file *file = iocb->ki_filp; struct address_space *mapping = file->f_mapping; diff --git a/fs/block_dev.c b/fs/block_dev.c index bc23afd35fdb..6e3de63c3055 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -146,8 +146,7 @@ blkdev_get_block(struct inode *inode, sector_t iblock, } static ssize_t -blkdev_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, - loff_t offset) +blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter, loff_t offset) { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index ca69e83d4f3c..43192e10cc43 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -8114,8 +8114,8 @@ out: return retval; } -static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb, - struct iov_iter *iter, loff_t offset) +static ssize_t btrfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter, + loff_t offset) { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index fd5599d32362..155ab9c0246b 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -1198,8 +1198,7 @@ static int ceph_write_end(struct file *file, struct address_space *mapping, * intercept O_DIRECT reads and writes early, this function should * never get called. */ -static ssize_t ceph_direct_io(int rw, struct kiocb *iocb, - struct iov_iter *iter, +static ssize_t ceph_direct_io(struct kiocb *iocb, struct iov_iter *iter, loff_t pos) { WARN_ON(1); diff --git a/fs/cifs/file.c b/fs/cifs/file.c index ca30c391a894..72394c5abd0f 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -3877,8 +3877,7 @@ void cifs_oplock_break(struct work_struct *work) * Direct IO is not yet supported in the cached mode. */ static ssize_t -cifs_direct_io(int rw, struct kiocb *iocb, struct iov_iter *iter, - loff_t pos) +cifs_direct_io(struct kiocb *iocb, struct iov_iter *iter, loff_t pos) { /* * FIXME diff --git a/fs/exofs/inode.c b/fs/exofs/inode.c index a198e94813fe..35073aaec6e0 100644 --- a/fs/exofs/inode.c +++ b/fs/exofs/inode.c @@ -963,8 +963,8 @@ static void exofs_invalidatepage(struct page *page, unsigned int offset, /* TODO: Should be easy enough to do proprly */ -static ssize_t exofs_direct_IO(int rw, struct kiocb *iocb, - struct iov_iter *iter, loff_t offset) +static ssize_t exofs_direct_IO(struct kiocb *iocb, struct iov_iter *iter, + loff_t offset) { return 0; } diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 685e514c57dd..e1abf75e994c 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -851,8 +851,7 @@ static sector_t ext2_bmap(struct address_space *mapping, sector_t block) } static ssize_t -ext2_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, - loff_t offset) +ext2_direct_IO(struct kiocb *iocb, struct iov_iter *iter, loff_t offset) { struct file *file = iocb->ki_filp; struct address_space *mapping = file->f_mapping; diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index c70839d26ccd..13c0868c7160 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -1820,8 +1820,8 @@ static int ext3_releasepage(struct page *page, gfp_t wait) * crashes then stale disk data _may_ be exposed inside the file. But current * VFS code falls back into buffered path in that case so we are safe. */ -static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb, - struct iov_iter *iter, loff_t offset) +static ssize_t ext3_direct_IO(struct kiocb *iocb, struct iov_iter *iter, + loff_t offset) { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index cf6ba6536035..42c942a950e1 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -3089,8 +3089,8 @@ retake_lock: return ret; } -static ssize_t ext4_direct_IO(int rw, struct kiocb *iocb, - struct iov_iter *iter, loff_t offset) +static ssize_t ext4_direct_IO(struct kiocb *iocb, struct iov_iter *iter, + loff_t offset) { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index ce25f62edfa7..319eda511c4f 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -1135,8 +1135,8 @@ static int check_direct_IO(struct inode *inode, struct iov_iter *iter, return 0; } -static ssize_t f2fs_direct_IO(int rw, struct kiocb *iocb, - struct iov_iter *iter, loff_t offset) +static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter, + loff_t offset) { struct file *file = iocb->ki_filp; struct address_space *mapping = file->f_mapping; diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 342d791b28db..41b729933638 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -245,8 +245,7 @@ static int fat_write_end(struct file *file, struct address_space *mapping, return err; } -static ssize_t fat_direct_IO(int rw, struct kiocb *iocb, - struct iov_iter *iter, +static ssize_t fat_direct_IO(struct kiocb *iocb, struct iov_iter *iter, loff_t offset) { struct file *file = iocb->ki_filp; diff --git a/fs/fuse/file.c b/fs/fuse/file.c index c1a67da6a8a0..3d355e946991 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -2782,8 +2782,7 @@ static inline loff_t fuse_round_up(loff_t off) } static ssize_t -fuse_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, - loff_t offset) +fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter, loff_t offset) { DECLARE_COMPLETION_ONSTACK(wait); ssize_t ret = 0; diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c index e22e6e686a11..20dd33da92de 100644 --- a/fs/gfs2/aops.c +++ b/fs/gfs2/aops.c @@ -1038,8 +1038,8 @@ static int gfs2_ok_for_dio(struct gfs2_inode *ip, loff_t offset) -static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb, - struct iov_iter *iter, loff_t offset) +static ssize_t gfs2_direct_IO(struct kiocb *iocb, struct iov_iter *iter, + loff_t offset) { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c index 0085d527a55c..75fd5d873c19 100644 --- a/fs/hfs/inode.c +++ b/fs/hfs/inode.c @@ -124,8 +124,8 @@ static int hfs_releasepage(struct page *page, gfp_t mask) return res ? try_to_free_buffers(page) : 0; } -static ssize_t hfs_direct_IO(int rw, struct kiocb *iocb, - struct iov_iter *iter, loff_t offset) +static ssize_t hfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter, + loff_t offset) { struct file *file = iocb->ki_filp; struct address_space *mapping = file->f_mapping; diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index afcde36b506b..a43811f90935 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c @@ -122,8 +122,8 @@ static int hfsplus_releasepage(struct page *page, gfp_t mask) return res ? try_to_free_buffers(page) : 0; } -static ssize_t hfsplus_direct_IO(int rw, struct kiocb *iocb, - struct iov_iter *iter, loff_t offset) +static ssize_t hfsplus_direct_IO(struct kiocb *iocb, struct iov_iter *iter, + loff_t offset) { struct file *file = iocb->ki_filp; struct address_space *mapping = file->f_mapping; diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c index e7047b63ffc5..070dc4b33544 100644 --- a/fs/jfs/inode.c +++ b/fs/jfs/inode.c @@ -330,8 +330,8 @@ static sector_t jfs_bmap(struct address_space *mapping, sector_t block) return generic_block_bmap(mapping, block, jfs_get_block); } -static ssize_t jfs_direct_IO(int rw, struct kiocb *iocb, - struct iov_iter *iter, loff_t offset) +static ssize_t jfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter, + loff_t offset) { struct file *file = iocb->ki_filp; struct address_space *mapping = file->f_mapping; diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index e8482b8f4830..06503bc604e1 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -240,7 +240,6 @@ static int nfs_direct_cmp_commit_data_verf(struct nfs_direct_req *dreq, /** * nfs_direct_IO - NFS address space operation for direct I/O - * @rw: direction (read or write) * @iocb: target I/O control block * @iov: array of vectors that define I/O buffer * @pos: offset in file to begin the operation @@ -251,7 +250,7 @@ static int nfs_direct_cmp_commit_data_verf(struct nfs_direct_req *dreq, * shunt off direct read and write requests before the VFS gets them, * so this method is only ever called for swap. */ -ssize_t nfs_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, loff_t pos) +ssize_t nfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter, loff_t pos) { struct inode *inode = iocb->ki_filp->f_mapping->host; diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index 4726f1493d5d..36f057fa8aa3 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c @@ -305,8 +305,7 @@ static int nilfs_write_end(struct file *file, struct address_space *mapping, } static ssize_t -nilfs_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, - loff_t offset) +nilfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter, loff_t offset) { struct file *file = iocb->ki_filp; struct address_space *mapping = file->f_mapping; diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index 0ee9474cca46..28b5ad81bbec 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c @@ -818,9 +818,7 @@ out: return ret; } -static ssize_t ocfs2_direct_IO(int rw, - struct kiocb *iocb, - struct iov_iter *iter, +static ssize_t ocfs2_direct_IO(struct kiocb *iocb, struct iov_iter *iter, loff_t offset) { struct file *file = iocb->ki_filp; diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index d61ab13244a8..742242b60972 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -3278,8 +3278,8 @@ static int reiserfs_releasepage(struct page *page, gfp_t unused_gfp_flags) * We thank Mingming Cao for helping us understand in great detail what * to do in this section of the code. */ -static ssize_t reiserfs_direct_IO(int rw, struct kiocb *iocb, - struct iov_iter *iter, loff_t offset) +static ssize_t reiserfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter, + loff_t offset) { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; diff --git a/fs/udf/file.c b/fs/udf/file.c index 74050bff64f4..78d42548b260 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c @@ -100,8 +100,7 @@ static int udf_adinicb_write_begin(struct file *file, return 0; } -static ssize_t udf_adinicb_direct_IO(int rw, struct kiocb *iocb, - struct iov_iter *iter, +static ssize_t udf_adinicb_direct_IO(struct kiocb *iocb, struct iov_iter *iter, loff_t offset) { /* Fallback to buffered I/O. */ diff --git a/fs/udf/inode.c b/fs/udf/inode.c index a685aea93068..4f178c83b04f 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -215,8 +215,7 @@ static int udf_write_begin(struct file *file, struct address_space *mapping, return ret; } -static ssize_t udf_direct_IO(int rw, struct kiocb *iocb, - struct iov_iter *iter, +static ssize_t udf_direct_IO(struct kiocb *iocb, struct iov_iter *iter, loff_t offset) { struct file *file = iocb->ki_filp; diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c index 532d5279df2f..1d8eef9cf0f5 100644 --- a/fs/xfs/xfs_aops.c +++ b/fs/xfs/xfs_aops.c @@ -1495,7 +1495,6 @@ xfs_end_io_direct_write( STATIC ssize_t xfs_vm_direct_IO( - int rw, struct kiocb *iocb, struct iov_iter *iter, loff_t offset) diff --git a/include/linux/fs.h b/include/linux/fs.h index 295bc589fe1b..72e3759de8c3 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -383,7 +383,7 @@ struct address_space_operations { void (*invalidatepage) (struct page *, unsigned int, unsigned int); int (*releasepage) (struct page *, gfp_t); void (*freepage)(struct page *); - ssize_t (*direct_IO)(int, struct kiocb *, struct iov_iter *iter, loff_t offset); + ssize_t (*direct_IO)(struct kiocb *, struct iov_iter *iter, loff_t offset); /* * migrate the contents of a page to the specified target. If * migrate_mode is MIGRATE_ASYNC, it must not block. diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index b01ccf371fdc..3d1b0d2fe55e 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -447,7 +447,7 @@ static inline struct rpc_cred *nfs_file_cred(struct file *file) /* * linux/fs/nfs/direct.c */ -extern ssize_t nfs_direct_IO(int, struct kiocb *, struct iov_iter *, loff_t); +extern ssize_t nfs_direct_IO(struct kiocb *, struct iov_iter *, loff_t); extern ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter, loff_t pos); diff --git a/mm/filemap.c b/mm/filemap.c index 876f4e6f3ed6..9920db455f05 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -1707,7 +1707,7 @@ generic_file_read_iter(struct kiocb *iocb, struct iov_iter *iter) pos + count - 1); if (!retval) { struct iov_iter data = *iter; - retval = mapping->a_ops->direct_IO(READ, iocb, &data, pos); + retval = mapping->a_ops->direct_IO(iocb, &data, pos); } if (retval > 0) { @@ -2395,7 +2395,7 @@ generic_file_direct_write(struct kiocb *iocb, struct iov_iter *from, loff_t pos) } data = *from; - written = mapping->a_ops->direct_IO(WRITE, iocb, &data, pos); + written = mapping->a_ops->direct_IO(iocb, &data, pos); /* * Finally, try again to invalidate clean pages which might have been diff --git a/mm/page_io.c b/mm/page_io.c index a96c8562d835..6424869e275e 100644 --- a/mm/page_io.c +++ b/mm/page_io.c @@ -277,9 +277,7 @@ int __swap_writepage(struct page *page, struct writeback_control *wbc, set_page_writeback(page); unlock_page(page); - ret = mapping->a_ops->direct_IO(ITER_BVEC | WRITE, - &kiocb, &from, - kiocb.ki_pos); + ret = mapping->a_ops->direct_IO(&kiocb, &from, kiocb.ki_pos); if (ret == PAGE_SIZE) { count_vm_event(PSWPOUT); ret = 0; -- cgit v1.2.3-59-g8ed1b From b67c961cb86c2e296742c4e86096effb1f2c6ab8 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Tue, 7 Oct 2014 00:45:13 +0400 Subject: irqchip: xtensa-pic: xtensa-mx: document DT bindings Signed-off-by: Max Filippov --- .../interrupt-controller/cdns,xtensa-mx.txt | 18 ++++++++++++++++ .../interrupt-controller/cdns,xtensa-pic.txt | 25 ++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/cdns,xtensa-mx.txt create mode 100644 Documentation/devicetree/bindings/interrupt-controller/cdns,xtensa-pic.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/interrupt-controller/cdns,xtensa-mx.txt b/Documentation/devicetree/bindings/interrupt-controller/cdns,xtensa-mx.txt new file mode 100644 index 000000000000..d4de980e55fa --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/cdns,xtensa-mx.txt @@ -0,0 +1,18 @@ +* Xtensa Interrupt Distributor and Programmable Interrupt Controller (MX) + +Required properties: +- compatible: Should be "cdns,xtensa-mx". + +Remaining properties have exact same meaning as in Xtensa PIC +(see cdns,xtensa-pic.txt). + +Examples: + pic: pic { + compatible = "cdns,xtensa-mx"; + /* one cell: internal irq number, + * two cells: second cell == 0: internal irq number + * second cell == 1: external irq number + */ + #interrupt-cells = <2>; + interrupt-controller; + }; diff --git a/Documentation/devicetree/bindings/interrupt-controller/cdns,xtensa-pic.txt b/Documentation/devicetree/bindings/interrupt-controller/cdns,xtensa-pic.txt new file mode 100644 index 000000000000..026ef4cfc1d5 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/cdns,xtensa-pic.txt @@ -0,0 +1,25 @@ +* Xtensa built-in Programmable Interrupt Controller (PIC) + +Required properties: +- compatible: Should be "cdns,xtensa-pic". +- interrupt-controller: Identifies the node as an interrupt controller. +- #interrupt-cells: The number of cells to define the interrupts. + It may be either 1 or 2. + When it's 1, the first cell is the internal IRQ number. + When it's 2, the first cell is the IRQ number, and the second cell + specifies whether it's internal (0) or external (1). + Periferals are usually connected to a fixed external IRQ, but for different + core variants it may be mapped to different internal IRQ. + IRQ sensitivity and priority are fixed for each core variant and may not be + changed at runtime. + +Examples: + pic: pic { + compatible = "cdns,xtensa-pic"; + /* one cell: internal irq number, + * two cells: second cell == 0: internal irq number + * second cell == 1: external irq number + */ + #interrupt-cells = <2>; + interrupt-controller; + }; -- cgit v1.2.3-59-g8ed1b From 195daf665a6299de98a4da3843fed2dd9de19d3a Mon Sep 17 00:00:00 2001 From: Ulrich Obergfell Date: Tue, 14 Apr 2015 15:44:13 -0700 Subject: watchdog: enable the new user interface of the watchdog mechanism With the current user interface of the watchdog mechanism it is only possible to disable or enable both lockup detectors at the same time. This series introduces new kernel parameters and changes the semantics of some existing kernel parameters, so that the hard lockup detector and the soft lockup detector can be disabled or enabled individually. With this series applied, the user interface is as follows. - parameters in /proc/sys/kernel . soft_watchdog This is a new parameter to control and examine the run state of the soft lockup detector. . nmi_watchdog The semantics of this parameter have changed. It can now be used to control and examine the run state of the hard lockup detector. . watchdog This parameter is still available to control the run state of both lockup detectors at the same time. If this parameter is examined, it shows the logical OR of soft_watchdog and nmi_watchdog. . watchdog_thresh The semantics of this parameter are not affected by the patch. - kernel command line parameters . nosoftlockup The semantics of this parameter have changed. It can now be used to disable the soft lockup detector at boot time. . nmi_watchdog=0 or nmi_watchdog=1 Disable or enable the hard lockup detector at boot time. The patch introduces '=1' as a new option. . nowatchdog The semantics of this parameter are not affected by the patch. It is still available to disable both lockup detectors at boot time. Also, remove the proc_dowatchdog() function which is no longer needed. [dzickus@redhat.com: wrote changelog] [dzickus@redhat.com: update documentation for kernel params and sysctl] Signed-off-by: Ulrich Obergfell Signed-off-by: Don Zickus Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/kernel-parameters.txt | 6 ++- Documentation/sysctl/kernel.txt | 62 +++++++++++++++++++++++----- include/linux/nmi.h | 2 - kernel/sysctl.c | 35 +++++++++++----- kernel/watchdog.c | 81 ++++++++----------------------------- 5 files changed, 97 insertions(+), 89 deletions(-) (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 01aa47d3b6ab..71eecb263250 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -2236,8 +2236,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted. nmi_watchdog= [KNL,BUGS=X86] Debugging features for SMP kernels Format: [panic,][nopanic,][num] - Valid num: 0 + Valid num: 0 or 1 0 - turn nmi_watchdog off + 1 - turn nmi_watchdog on When panic is specified, panic when an NMI watchdog timeout occurs (or 'nopanic' to override the opposite default). @@ -2464,7 +2465,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted. nousb [USB] Disable the USB subsystem - nowatchdog [KNL] Disable the lockup detector (NMI watchdog). + nowatchdog [KNL] Disable both lockup detectors, i.e. + soft-lockup and NMI watchdog (hard-lockup). nowb [ARM] diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt index 83ab25660fc9..99d7eb3a1416 100644 --- a/Documentation/sysctl/kernel.txt +++ b/Documentation/sysctl/kernel.txt @@ -77,12 +77,14 @@ show up in /proc/sys/kernel: - shmmax [ sysv ipc ] - shmmni - softlockup_all_cpu_backtrace +- soft_watchdog - stop-a [ SPARC only ] - sysrq ==> Documentation/sysrq.txt - sysctl_writes_strict - tainted - threads-max - unknown_nmi_panic +- watchdog - watchdog_thresh - version @@ -417,16 +419,23 @@ successful IPC object allocation. nmi_watchdog: -Enables/Disables the NMI watchdog on x86 systems. When the value is -non-zero the NMI watchdog is enabled and will continuously test all -online cpus to determine whether or not they are still functioning -properly. Currently, passing "nmi_watchdog=" parameter at boot time is -required for this function to work. +This parameter can be used to control the NMI watchdog +(i.e. the hard lockup detector) on x86 systems. -If LAPIC NMI watchdog method is in use (nmi_watchdog=2 kernel -parameter), the NMI watchdog shares registers with oprofile. By -disabling the NMI watchdog, oprofile may have more registers to -utilize. + 0 - disable the hard lockup detector + 1 - enable the hard lockup detector + +The hard lockup detector monitors each CPU for its ability to respond to +timer interrupts. The mechanism utilizes CPU performance counter registers +that are programmed to generate Non-Maskable Interrupts (NMIs) periodically +while a CPU is busy. Hence, the alternative name 'NMI watchdog'. + +The NMI watchdog is disabled by default if the kernel is running as a guest +in a KVM virtual machine. This default can be overridden by adding + + nmi_watchdog=1 + +to the guest kernel command line (see Documentation/kernel-parameters.txt). ============================================================== @@ -816,6 +825,22 @@ NMI. ============================================================== +soft_watchdog + +This parameter can be used to control the soft lockup detector. + + 0 - disable the soft lockup detector + 1 - enable the soft lockup detector + +The soft lockup detector monitors CPUs for threads that are hogging the CPUs +without rescheduling voluntarily, and thus prevent the 'watchdog/N' threads +from running. The mechanism depends on the CPUs ability to respond to timer +interrupts which are needed for the 'watchdog/N' threads to be woken up by +the watchdog timer function, otherwise the NMI watchdog - if enabled - can +detect a hard lockup condition. + +============================================================== + tainted: Non-zero if the kernel has been tainted. Numeric values, which @@ -858,6 +883,25 @@ example. If a system hangs up, try pressing the NMI switch. ============================================================== +watchdog: + +This parameter can be used to disable or enable the soft lockup detector +_and_ the NMI watchdog (i.e. the hard lockup detector) at the same time. + + 0 - disable both lockup detectors + 1 - enable both lockup detectors + +The soft lockup detector and the NMI watchdog can also be disabled or +enabled individually, using the soft_watchdog and nmi_watchdog parameters. +If the watchdog parameter is read, for example by executing + + cat /proc/sys/kernel/watchdog + +the output of this command (0 or 1) shows the logical OR of soft_watchdog +and nmi_watchdog. + +============================================================== + watchdog_thresh: This value can be used to control the frequency of hrtimer and NMI diff --git a/include/linux/nmi.h b/include/linux/nmi.h index 5b5450585b8a..0426357297d5 100644 --- a/include/linux/nmi.h +++ b/include/linux/nmi.h @@ -82,8 +82,6 @@ extern int proc_soft_watchdog(struct ctl_table *, int , void __user *, size_t *, loff_t *); extern int proc_watchdog_thresh(struct ctl_table *, int , void __user *, size_t *, loff_t *); -extern int proc_dowatchdog(struct ctl_table *, int , - void __user *, size_t *, loff_t *); #endif #ifdef CONFIG_HAVE_ACPI_APEI_NMI diff --git a/kernel/sysctl.c b/kernel/sysctl.c index ce410bb9f2e1..245e7dcc3741 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -846,7 +846,7 @@ static struct ctl_table kern_table[] = { .data = &watchdog_user_enabled, .maxlen = sizeof (int), .mode = 0644, - .proc_handler = proc_dowatchdog, + .proc_handler = proc_watchdog, .extra1 = &zero, .extra2 = &one, }, @@ -855,10 +855,32 @@ static struct ctl_table kern_table[] = { .data = &watchdog_thresh, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = proc_dowatchdog, + .proc_handler = proc_watchdog_thresh, .extra1 = &zero, .extra2 = &sixty, }, + { + .procname = "nmi_watchdog", + .data = &nmi_watchdog_enabled, + .maxlen = sizeof (int), + .mode = 0644, + .proc_handler = proc_nmi_watchdog, + .extra1 = &zero, +#if defined(CONFIG_HAVE_NMI_WATCHDOG) || defined(CONFIG_HARDLOCKUP_DETECTOR) + .extra2 = &one, +#else + .extra2 = &zero, +#endif + }, + { + .procname = "soft_watchdog", + .data = &soft_watchdog_enabled, + .maxlen = sizeof (int), + .mode = 0644, + .proc_handler = proc_soft_watchdog, + .extra1 = &zero, + .extra2 = &one, + }, { .procname = "softlockup_panic", .data = &softlockup_panic, @@ -879,15 +901,6 @@ static struct ctl_table kern_table[] = { .extra2 = &one, }, #endif /* CONFIG_SMP */ - { - .procname = "nmi_watchdog", - .data = &watchdog_user_enabled, - .maxlen = sizeof (int), - .mode = 0644, - .proc_handler = proc_dowatchdog, - .extra1 = &zero, - .extra2 = &one, - }, #endif #if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86) { diff --git a/kernel/watchdog.c b/kernel/watchdog.c index fd2b6dc14486..63d702885686 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c @@ -110,15 +110,9 @@ static int __init hardlockup_panic_setup(char *str) else if (!strncmp(str, "nopanic", 7)) hardlockup_panic = 0; else if (!strncmp(str, "0", 1)) - watchdog_user_enabled = 0; - else if (!strncmp(str, "1", 1) || !strncmp(str, "2", 1)) { - /* - * Setting 'nmi_watchdog=1' or 'nmi_watchdog=2' (legacy option) - * has the same effect. - */ - watchdog_user_enabled = 1; - watchdog_enable_hardlockup_detector(true); - } + watchdog_enabled &= ~NMI_WATCHDOG_ENABLED; + else if (!strncmp(str, "1", 1)) + watchdog_enabled |= NMI_WATCHDOG_ENABLED; return 1; } __setup("nmi_watchdog=", hardlockup_panic_setup); @@ -137,19 +131,18 @@ __setup("softlockup_panic=", softlockup_panic_setup); static int __init nowatchdog_setup(char *str) { - watchdog_user_enabled = 0; + watchdog_enabled = 0; return 1; } __setup("nowatchdog", nowatchdog_setup); -/* deprecated */ static int __init nosoftlockup_setup(char *str) { - watchdog_user_enabled = 0; + watchdog_enabled &= ~SOFT_WATCHDOG_ENABLED; return 1; } __setup("nosoftlockup", nosoftlockup_setup); -/* */ + #ifdef CONFIG_SMP static int __init softlockup_all_cpu_backtrace_setup(char *str) { @@ -264,10 +257,11 @@ static int is_softlockup(unsigned long touch_ts) { unsigned long now = get_timestamp(); - /* Warn about unreasonable delays: */ - if (time_after(now, touch_ts + get_softlockup_thresh())) - return now - touch_ts; - + if (watchdog_enabled & SOFT_WATCHDOG_ENABLED) { + /* Warn about unreasonable delays. */ + if (time_after(now, touch_ts + get_softlockup_thresh())) + return now - touch_ts; + } return 0; } @@ -532,6 +526,10 @@ static int watchdog_nmi_enable(unsigned int cpu) struct perf_event_attr *wd_attr; struct perf_event *event = per_cpu(watchdog_ev, cpu); + /* nothing to do if the hard lockup detector is disabled */ + if (!(watchdog_enabled & NMI_WATCHDOG_ENABLED)) + goto out; + /* * Some kernels need to default hard lockup detection to * 'disabled', for example a guest on a hypervisor. @@ -856,59 +854,12 @@ out: mutex_unlock(&watchdog_proc_mutex); return err; } - -/* - * proc handler for /proc/sys/kernel/nmi_watchdog,watchdog_thresh - */ - -int proc_dowatchdog(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - int err, old_thresh, old_enabled; - bool old_hardlockup; - - mutex_lock(&watchdog_proc_mutex); - old_thresh = ACCESS_ONCE(watchdog_thresh); - old_enabled = ACCESS_ONCE(watchdog_user_enabled); - old_hardlockup = watchdog_hardlockup_detector_is_enabled(); - - err = proc_dointvec_minmax(table, write, buffer, lenp, ppos); - if (err || !write) - goto out; - - set_sample_period(); - /* - * Watchdog threads shouldn't be enabled if they are - * disabled. The 'watchdog_running' variable check in - * watchdog_*_all_cpus() function takes care of this. - */ - if (watchdog_user_enabled && watchdog_thresh) { - /* - * Prevent a change in watchdog_thresh accidentally overriding - * the enablement of the hardlockup detector. - */ - if (watchdog_user_enabled != old_enabled) - watchdog_enable_hardlockup_detector(true); - err = watchdog_enable_all_cpus(old_thresh != watchdog_thresh); - } else - watchdog_disable_all_cpus(); - - /* Restore old values on failure */ - if (err) { - watchdog_thresh = old_thresh; - watchdog_user_enabled = old_enabled; - watchdog_enable_hardlockup_detector(old_hardlockup); - } -out: - mutex_unlock(&watchdog_proc_mutex); - return err; -} #endif /* CONFIG_SYSCTL */ void __init lockup_detector_init(void) { set_sample_period(); - if (watchdog_user_enabled) + if (watchdog_enabled) watchdog_enable_all_cpus(false); } -- cgit v1.2.3-59-g8ed1b From fc05f566210fa57f8e68ead8762b8dbb3f1c61e3 Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Tue, 14 Apr 2015 15:44:39 -0700 Subject: mm: rename __mlock_vma_pages_range() to populate_vma_page_range() __mlock_vma_pages_range() doesn't necessarily mlock pages. It depends on vma flags. The same codepath is used for MAP_POPULATE. Let's rename __mlock_vma_pages_range() to populate_vma_page_range(). This patch also drops mlock_vma_pages_range() references from documentation. It has gone in cea10a19b797 ("mm: directly use __mlock_vma_pages_range() in find_extend_vma()"). Signed-off-by: Kirill A. Shutemov Acked-by: Linus Torvalds Acked-by: David Rientjes Cc: Michel Lespinasse Cc: Rik van Riel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/vm/unevictable-lru.txt | 26 ++++++++------------------ mm/internal.h | 2 +- mm/mlock.c | 12 ++++++------ mm/mmap.c | 4 ++-- 4 files changed, 17 insertions(+), 27 deletions(-) (limited to 'Documentation') diff --git a/Documentation/vm/unevictable-lru.txt b/Documentation/vm/unevictable-lru.txt index 744f82f86c58..86cb4624fc5a 100644 --- a/Documentation/vm/unevictable-lru.txt +++ b/Documentation/vm/unevictable-lru.txt @@ -317,7 +317,7 @@ If the VMA passes some filtering as described in "Filtering Special Vmas" below, mlock_fixup() will attempt to merge the VMA with its neighbors or split off a subset of the VMA if the range does not cover the entire VMA. Once the VMA has been merged or split or neither, mlock_fixup() will call -__mlock_vma_pages_range() to fault in the pages via get_user_pages() and to +populate_vma_page_range() to fault in the pages via get_user_pages() and to mark the pages as mlocked via mlock_vma_page(). Note that the VMA being mlocked might be mapped with PROT_NONE. In this case, @@ -327,7 +327,7 @@ fault path or in vmscan. Also note that a page returned by get_user_pages() could be truncated or migrated out from under us, while we're trying to mlock it. To detect this, -__mlock_vma_pages_range() checks page_mapping() after acquiring the page lock. +populate_vma_page_range() checks page_mapping() after acquiring the page lock. If the page is still associated with its mapping, we'll go ahead and call mlock_vma_page(). If the mapping is gone, we just unlock the page and move on. In the worst case, this will result in a page mapped in a VM_LOCKED VMA @@ -392,7 +392,7 @@ ignored for munlock. If the VMA is VM_LOCKED, mlock_fixup() again attempts to merge or split off the specified range. The range is then munlocked via the function -__mlock_vma_pages_range() - the same function used to mlock a VMA range - +populate_vma_page_range() - the same function used to mlock a VMA range - passing a flag to indicate that munlock() is being performed. Because the VMA access protections could have been changed to PROT_NONE after @@ -402,7 +402,7 @@ get_user_pages() was enhanced to accept a flag to ignore the permissions when fetching the pages - all of which should be resident as a result of previous mlocking. -For munlock(), __mlock_vma_pages_range() unlocks individual pages by calling +For munlock(), populate_vma_page_range() unlocks individual pages by calling munlock_vma_page(). munlock_vma_page() unconditionally clears the PG_mlocked flag using TestClearPageMlocked(). As with mlock_vma_page(), munlock_vma_page() use the Test*PageMlocked() function to handle the case where @@ -463,21 +463,11 @@ populate the page table. To mlock a range of memory under the unevictable/mlock infrastructure, the mmap() handler and task address space expansion functions call -mlock_vma_pages_range() specifying the vma and the address range to mlock. -mlock_vma_pages_range() filters VMAs like mlock_fixup(), as described above in -"Filtering Special VMAs". It will clear the VM_LOCKED flag, which will have -already been set by the caller, in filtered VMAs. Thus these VMA's need not be -visited for munlock when the region is unmapped. - -For "normal" VMAs, mlock_vma_pages_range() calls __mlock_vma_pages_range() to -fault/allocate the pages and mlock them. Again, like mlock_fixup(), -mlock_vma_pages_range() downgrades the mmap semaphore to read mode before -attempting to fault/allocate and mlock the pages and "upgrades" the semaphore -back to write mode before returning. - -The callers of mlock_vma_pages_range() will have already added the memory range +populate_vma_page_range() specifying the vma and the address range to mlock. + +The callers of populate_vma_page_range() will have already added the memory range to be mlocked to the task's "locked_vm". To account for filtered VMAs, -mlock_vma_pages_range() returns the number of pages NOT mlocked. All of the +populate_vma_page_range() returns the number of pages NOT mlocked. All of the callers then subtract a non-negative return value from the task's locked_vm. A negative return value represent an error - for example, from get_user_pages() attempting to fault in a VMA with PROT_NONE access. In this case, we leave the diff --git a/mm/internal.h b/mm/internal.h index a96da5b0029d..7df78a5269f3 100644 --- a/mm/internal.h +++ b/mm/internal.h @@ -240,7 +240,7 @@ void __vma_link_list(struct mm_struct *mm, struct vm_area_struct *vma, struct vm_area_struct *prev, struct rb_node *rb_parent); #ifdef CONFIG_MMU -extern long __mlock_vma_pages_range(struct vm_area_struct *vma, +extern long populate_vma_page_range(struct vm_area_struct *vma, unsigned long start, unsigned long end, int *nonblocking); extern void munlock_vma_pages_range(struct vm_area_struct *vma, unsigned long start, unsigned long end); diff --git a/mm/mlock.c b/mm/mlock.c index f756e28b33fc..9d0f3cd716c5 100644 --- a/mm/mlock.c +++ b/mm/mlock.c @@ -206,13 +206,13 @@ out: } /** - * __mlock_vma_pages_range() - mlock a range of pages in the vma. + * populate_vma_page_range() - populate a range of pages in the vma. * @vma: target vma * @start: start address * @end: end address * @nonblocking: * - * This takes care of making the pages present too. + * This takes care of mlocking the pages too if VM_LOCKED is set. * * return 0 on success, negative error code on error. * @@ -224,7 +224,7 @@ out: * If @nonblocking is non-NULL, it must held for read only and may be * released. If it's released, *@nonblocking will be set to 0. */ -long __mlock_vma_pages_range(struct vm_area_struct *vma, +long populate_vma_page_range(struct vm_area_struct *vma, unsigned long start, unsigned long end, int *nonblocking) { struct mm_struct *mm = vma->vm_mm; @@ -596,7 +596,7 @@ success: /* * vm_flags is protected by the mmap_sem held in write mode. * It's okay if try_to_unmap_one unmaps a page just after we - * set VM_LOCKED, __mlock_vma_pages_range will bring it back. + * set VM_LOCKED, populate_vma_page_range will bring it back. */ if (lock) @@ -702,11 +702,11 @@ int __mm_populate(unsigned long start, unsigned long len, int ignore_errors) if (nstart < vma->vm_start) nstart = vma->vm_start; /* - * Now fault in a range of pages. __mlock_vma_pages_range() + * Now fault in a range of pages. populate_vma_page_range() * double checks the vma flags, so that it won't mlock pages * if the vma was already munlocked. */ - ret = __mlock_vma_pages_range(vma, nstart, nend, &locked); + ret = populate_vma_page_range(vma, nstart, nend, &locked); if (ret < 0) { if (ignore_errors) { ret = 0; diff --git a/mm/mmap.c b/mm/mmap.c index 9ec50a368634..06a6076c92e5 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -2316,7 +2316,7 @@ find_extend_vma(struct mm_struct *mm, unsigned long addr) if (!prev || expand_stack(prev, addr)) return NULL; if (prev->vm_flags & VM_LOCKED) - __mlock_vma_pages_range(prev, addr, prev->vm_end, NULL); + populate_vma_page_range(prev, addr, prev->vm_end, NULL); return prev; } #else @@ -2351,7 +2351,7 @@ find_extend_vma(struct mm_struct *mm, unsigned long addr) if (expand_stack(vma, addr)) return NULL; if (vma->vm_flags & VM_LOCKED) - __mlock_vma_pages_range(vma, addr, start, NULL); + populate_vma_page_range(vma, addr, start, NULL); return vma; } #endif -- cgit v1.2.3-59-g8ed1b From 17e0db822b00cff96c1b662ac0dc0449cb70e0ec Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Tue, 14 Apr 2015 15:45:08 -0700 Subject: cma: debug: document new debugfs interface Document the structure and files under the new debugfs interface. Signed-off-by: Sasha Levin Cc: Joonsoo Kim Cc: Konrad Rzeszutek Wilk Cc: Laura Abbott Cc: Marek Szyprowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/cma/debugfs.txt | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 Documentation/cma/debugfs.txt (limited to 'Documentation') diff --git a/Documentation/cma/debugfs.txt b/Documentation/cma/debugfs.txt new file mode 100644 index 000000000000..6cef20a8cedc --- /dev/null +++ b/Documentation/cma/debugfs.txt @@ -0,0 +1,21 @@ +The CMA debugfs interface is useful to retrieve basic information out of the +different CMA areas and to test allocation/release in each of the areas. + +Each CMA zone represents a directory under /cma/, indexed by the +kernel's CMA index. So the first CMA zone would be: + + /cma/cma-0 + +The structure of the files created under that directory is as follows: + + - [RO] base_pfn: The base PFN (Page Frame Number) of the zone. + - [RO] count: Amount of memory in the CMA area. + - [RO] order_per_bit: Order of pages represented by one bit. + - [RO] bitmap: The bitmap of page states in the zone. + - [WO] alloc: Allocate N pages from that CMA area. For example: + + echo 5 > /cma/cma-2/alloc + +would try to allocate 5 pages from the cma-2 area. + + - [WO] free: Free N pages from that CMA area, similar to the above. -- cgit v1.2.3-59-g8ed1b From 53d85c98566535d7bc69470f008d7dcb09a0fec9 Mon Sep 17 00:00:00 2001 From: Vladimir Davydov Date: Tue, 14 Apr 2015 15:46:45 -0700 Subject: cleancache: forbid overriding cleancache_ops Currently, cleancache_register_ops returns the previous value of cleancache_ops to allow chaining. However, chaining, as it is implemented now, is extremely dangerous due to possible pool id collisions. Suppose, a new cleancache driver is registered after the previous one assigned an id to a super block. If the new driver assigns the same id to another super block, which is perfectly possible, we will have two different filesystems using the same id. No matter if the new driver implements chaining or not, we are likely to get data corruption with such a configuration eventually. This patch therefore disables the ability to override cleancache_ops altogether as potentially dangerous. If there is already cleancache driver registered, all further calls to cleancache_register_ops will return EBUSY. Since no user of cleancache implements chaining, we only need to make minor changes to the code outside the cleancache core. Signed-off-by: Vladimir Davydov Cc: Konrad Rzeszutek Wilk Cc: Boris Ostrovsky Cc: David Vrabel Cc: Mark Fasheh Cc: Joel Becker Cc: Stefan Hengelein Cc: Florian Schmaus Cc: Andor Daam Cc: Dan Magenheimer Cc: Bob Liu Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/vm/cleancache.txt | 4 +--- drivers/xen/tmem.c | 16 +++++++++------- include/linux/cleancache.h | 3 +-- mm/cleancache.c | 12 +++++++----- 4 files changed, 18 insertions(+), 17 deletions(-) (limited to 'Documentation') diff --git a/Documentation/vm/cleancache.txt b/Documentation/vm/cleancache.txt index 01d76282444e..e4b49df7a048 100644 --- a/Documentation/vm/cleancache.txt +++ b/Documentation/vm/cleancache.txt @@ -28,9 +28,7 @@ IMPLEMENTATION OVERVIEW A cleancache "backend" that provides transcendent memory registers itself to the kernel's cleancache "frontend" by calling cleancache_register_ops, passing a pointer to a cleancache_ops structure with funcs set appropriately. -Note that cleancache_register_ops returns the previous settings so that -chaining can be performed if desired. The functions provided must conform to -certain semantics as follows: +The functions provided must conform to certain semantics as follows: Most important, cleancache is "ephemeral". Pages which are copied into cleancache have an indefinite lifetime which is completely unknowable diff --git a/drivers/xen/tmem.c b/drivers/xen/tmem.c index 8a65423bc696..c4211a31612d 100644 --- a/drivers/xen/tmem.c +++ b/drivers/xen/tmem.c @@ -397,13 +397,15 @@ static int __init xen_tmem_init(void) #ifdef CONFIG_CLEANCACHE BUG_ON(sizeof(struct cleancache_filekey) != sizeof(struct tmem_oid)); if (tmem_enabled && cleancache) { - char *s = ""; - struct cleancache_ops *old_ops = - cleancache_register_ops(&tmem_cleancache_ops); - if (old_ops) - s = " (WARNING: cleancache_ops overridden)"; - pr_info("cleancache enabled, RAM provided by Xen Transcendent Memory%s\n", - s); + int err; + + err = cleancache_register_ops(&tmem_cleancache_ops); + if (err) + pr_warn("xen-tmem: failed to enable cleancache: %d\n", + err); + else + pr_info("cleancache enabled, RAM provided by " + "Xen Transcendent Memory\n"); } #endif #ifdef CONFIG_XEN_SELFBALLOONING diff --git a/include/linux/cleancache.h b/include/linux/cleancache.h index 29657d1c83fb..b23611f43cfb 100644 --- a/include/linux/cleancache.h +++ b/include/linux/cleancache.h @@ -33,8 +33,7 @@ struct cleancache_ops { void (*invalidate_fs)(int); }; -extern struct cleancache_ops * - cleancache_register_ops(struct cleancache_ops *ops); +extern int cleancache_register_ops(struct cleancache_ops *ops); extern void __cleancache_init_fs(struct super_block *); extern void __cleancache_init_shared_fs(struct super_block *); extern int __cleancache_get_page(struct page *); diff --git a/mm/cleancache.c b/mm/cleancache.c index 532495f2e4f4..aa10f9a3bc88 100644 --- a/mm/cleancache.c +++ b/mm/cleancache.c @@ -106,15 +106,17 @@ static DEFINE_MUTEX(poolid_mutex); */ /* - * Register operations for cleancache, returning previous thus allowing - * detection of multiple backends and possible nesting. + * Register operations for cleancache. Returns 0 on success. */ -struct cleancache_ops *cleancache_register_ops(struct cleancache_ops *ops) +int cleancache_register_ops(struct cleancache_ops *ops) { - struct cleancache_ops *old = cleancache_ops; int i; mutex_lock(&poolid_mutex); + if (cleancache_ops) { + mutex_unlock(&poolid_mutex); + return -EBUSY; + } for (i = 0; i < MAX_INITIALIZABLE_FS; i++) { if (fs_poolid_map[i] == FS_NO_BACKEND) fs_poolid_map[i] = ops->init_fs(PAGE_SIZE); @@ -130,7 +132,7 @@ struct cleancache_ops *cleancache_register_ops(struct cleancache_ops *ops) barrier(); cleancache_ops = ops; mutex_unlock(&poolid_mutex); - return old; + return 0; } EXPORT_SYMBOL(cleancache_register_ops); -- cgit v1.2.3-59-g8ed1b From 0ddab1d2ed664c85c95488eef569786a84aedf37 Mon Sep 17 00:00:00 2001 From: Toshi Kani Date: Tue, 14 Apr 2015 15:47:20 -0700 Subject: lib/ioremap.c: add huge I/O map capability interfaces Add ioremap_pud_enabled() and ioremap_pmd_enabled(), which return 1 when I/O mappings with pud/pmd are enabled on the kernel. ioremap_huge_init() calls arch_ioremap_pud_supported() and arch_ioremap_pmd_supported() to initialize the capabilities at boot-time. A new kernel option "nohugeiomap" is also added, so that user can disable the huge I/O map capabilities when necessary. Signed-off-by: Toshi Kani Cc: "H. Peter Anvin" Cc: Thomas Gleixner Cc: Ingo Molnar Cc: Arnd Bergmann Cc: Dave Hansen Cc: Robert Elliott Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/kernel-parameters.txt | 2 ++ arch/Kconfig | 3 +++ include/linux/io.h | 8 ++++++++ init/main.c | 2 ++ lib/ioremap.c | 37 +++++++++++++++++++++++++++++++++++++ 5 files changed, 52 insertions(+) (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 71eecb263250..b1fa70907ccf 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -2323,6 +2323,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted. register save and restore. The kernel will only save legacy floating-point registers on task switch. + nohugeiomap [KNL,x86] Disable kernel huge I/O mappings. + noxsave [BUGS=X86] Disables x86 extended register state save and restore using xsave. The kernel will fallback to enabling legacy floating-point and sse state. diff --git a/arch/Kconfig b/arch/Kconfig index a9c95d36ba70..c88c23f0a1da 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -446,6 +446,9 @@ config HAVE_IRQ_TIME_ACCOUNTING config HAVE_ARCH_TRANSPARENT_HUGEPAGE bool +config HAVE_ARCH_HUGE_VMAP + bool + config HAVE_ARCH_SOFT_DIRTY bool diff --git a/include/linux/io.h b/include/linux/io.h index fa02e55e5a2e..4cc299c598e0 100644 --- a/include/linux/io.h +++ b/include/linux/io.h @@ -38,6 +38,14 @@ static inline int ioremap_page_range(unsigned long addr, unsigned long end, } #endif +#ifdef CONFIG_HAVE_ARCH_HUGE_VMAP +void __init ioremap_huge_init(void); +int arch_ioremap_pud_supported(void); +int arch_ioremap_pmd_supported(void); +#else +static inline void ioremap_huge_init(void) { } +#endif + /* * Managed iomap interface */ diff --git a/init/main.c b/init/main.c index 4a6974e67839..f6dd8fe1f22c 100644 --- a/init/main.c +++ b/init/main.c @@ -80,6 +80,7 @@ #include #include #include +#include #include #include @@ -484,6 +485,7 @@ static void __init mm_init(void) percpu_init_late(); pgtable_init(); vmalloc_init(); + ioremap_huge_init(); } asmlinkage __visible void __init start_kernel(void) diff --git a/lib/ioremap.c b/lib/ioremap.c index 0c9216c48762..2008652c9a1f 100644 --- a/lib/ioremap.c +++ b/lib/ioremap.c @@ -13,6 +13,43 @@ #include #include +#ifdef CONFIG_HAVE_ARCH_HUGE_VMAP +int __read_mostly ioremap_pud_capable; +int __read_mostly ioremap_pmd_capable; +int __read_mostly ioremap_huge_disabled; + +static int __init set_nohugeiomap(char *str) +{ + ioremap_huge_disabled = 1; + return 0; +} +early_param("nohugeiomap", set_nohugeiomap); + +void __init ioremap_huge_init(void) +{ + if (!ioremap_huge_disabled) { + if (arch_ioremap_pud_supported()) + ioremap_pud_capable = 1; + if (arch_ioremap_pmd_supported()) + ioremap_pmd_capable = 1; + } +} + +static inline int ioremap_pud_enabled(void) +{ + return ioremap_pud_capable; +} + +static inline int ioremap_pmd_enabled(void) +{ + return ioremap_pmd_capable; +} + +#else /* !CONFIG_HAVE_ARCH_HUGE_VMAP */ +static inline int ioremap_pud_enabled(void) { return 0; } +static inline int ioremap_pmd_enabled(void) { return 0; } +#endif /* CONFIG_HAVE_ARCH_HUGE_VMAP */ + static int ioremap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, phys_addr_t phys_addr, pgprot_t prot) { -- cgit v1.2.3-59-g8ed1b From e4b0db72be2487bae0e3251c22f82c104f7c1cfd Mon Sep 17 00:00:00 2001 From: Vladimir Murzin Date: Tue, 14 Apr 2015 15:48:43 -0700 Subject: Documentation: update arch list in the 'memtest' entry Since arm64/arm support memtest command line option update the "memtest" entry. Signed-off-by: Vladimir Murzin Cc: "H. Peter Anvin" Cc: Catalin Marinas Cc: Ingo Molnar Cc: Mark Rutland Cc: Russell King Cc: Thomas Gleixner Cc: Will Deacon Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/kernel-parameters.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index b1fa70907ccf..8cc635f4c4f0 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1989,7 +1989,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted. seconds. Use this parameter to check at some other rate. 0 disables periodic checking. - memtest= [KNL,X86] Enable memtest + memtest= [KNL,X86,ARM] Enable memtest Format: default : 0 Specifies the number of memtest passes to be -- cgit v1.2.3-59-g8ed1b From 0ce65797a77ee780f62909d3128bf08b9735718b Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Thu, 26 Feb 2015 00:50:28 -0500 Subject: dm: impose configurable deadline for dm_request_fn's merge heuristic Otherwise, for sequential workloads, the dm_request_fn can allow excessive request merging at the expense of increased service time. Add a per-device sysfs attribute to allow the user to control how long a request, that is a reasonable merge candidate, can be queued on the request queue. The resolution of this request dispatch deadline is in microseconds (ranging from 1 to 100000 usecs), to set a 20us deadline: echo 20 > /sys/block/dm-7/dm/rq_based_seq_io_merge_deadline The dm_request_fn's merge heuristic and associated extra accounting is disabled by default (rq_based_seq_io_merge_deadline is 0). This sysfs attribute is not applicable to bio-based DM devices so it will only ever report 0 for them. By allowing a request to remain on the queue it will block others requests on the queue. But introducing a short dequeue delay has proven very effective at enabling certain sequential IO workloads on really fast, yet IOPS constrained, devices to build up slightly larger IOs -- yielding 90+% throughput improvements. Having precise control over the time taken to wait for larger requests to build affords control beyond that of waiting for certain IO sizes to accumulate (which would require a deadline anyway). This knob will only ever make sense with sequential IO workloads and the particular value used is storage configuration specific. Given the expected niche use-case for when this knob is useful it has been deemed acceptable to expose this relatively crude method for crafting optimal IO on specific storage -- especially given the solution is simple yet effective. In the context of DM multipath, it is advisable to tune this sysfs attribute to a value that offers the best performance for the common case (e.g. if 4 paths are expected active, tune for that; if paths fail then performance may be slightly reduced). Alternatives were explored to have request-based DM autotune this value (e.g. if/when paths fail) but they were quickly deemed too fragile and complex to warrant further design and development time. If this problem proves more common as faster storage emerges we'll have to look at elevating a generic solution into the block core. Tested-by: Shiva Krishna Merla Signed-off-by: Mike Snitzer --- Documentation/ABI/testing/sysfs-block-dm | 14 ++++++++ drivers/md/dm-sysfs.c | 2 ++ drivers/md/dm.c | 57 +++++++++++++++++++++++++++++--- drivers/md/dm.h | 4 +++ 4 files changed, 73 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-block-dm b/Documentation/ABI/testing/sysfs-block-dm index 87ca5691e29b..ac4b6fe245d9 100644 --- a/Documentation/ABI/testing/sysfs-block-dm +++ b/Documentation/ABI/testing/sysfs-block-dm @@ -23,3 +23,17 @@ Description: Device-mapper device suspend state. Contains the value 1 while the device is suspended. Otherwise it contains 0. Read-only attribute. Users: util-linux, device-mapper udev rules + +What: /sys/block/dm-/dm/rq_based_seq_io_merge_deadline +Date: March 2015 +KernelVersion: 4.1 +Contact: dm-devel@redhat.com +Description: Allow control over how long a request that is a + reasonable merge candidate can be queued on the request + queue. The resolution of this deadline is in + microseconds (ranging from 1 to 100000 usecs). + Setting this attribute to 0 (the default) will disable + request-based DM's merge heuristic and associated extra + accounting. This attribute is not applicable to + bio-based DM devices so it will only ever report 0 for + them. diff --git a/drivers/md/dm-sysfs.c b/drivers/md/dm-sysfs.c index 1271c31709fd..f5bb3944f75e 100644 --- a/drivers/md/dm-sysfs.c +++ b/drivers/md/dm-sysfs.c @@ -92,11 +92,13 @@ static ssize_t dm_attr_suspended_show(struct mapped_device *md, char *buf) static DM_ATTR_RO(name); static DM_ATTR_RO(uuid); static DM_ATTR_RO(suspended); +static DM_ATTR_RW(rq_based_seq_io_merge_deadline); static struct attribute *dm_attrs[] = { &dm_attr_name.attr, &dm_attr_uuid.attr, &dm_attr_suspended.attr, + &dm_attr_rq_based_seq_io_merge_deadline.attr, NULL, }; diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 2ae78b31e4c0..5294e016e92b 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -21,6 +21,7 @@ #include #include #include +#include #include /* for rq_end_sector() */ #include @@ -219,8 +220,10 @@ struct mapped_device { struct task_struct *kworker_task; /* for request-based merge heuristic in dm_request_fn() */ - sector_t last_rq_pos; + unsigned seq_rq_merge_deadline_usecs; int last_rq_rw; + sector_t last_rq_pos; + ktime_t last_rq_start_time; }; /* @@ -1935,8 +1938,11 @@ static void dm_start_request(struct mapped_device *md, struct request *orig) blk_start_request(orig); atomic_inc(&md->pending[rq_data_dir(orig)]); - md->last_rq_pos = rq_end_sector(orig); - md->last_rq_rw = rq_data_dir(orig); + if (md->seq_rq_merge_deadline_usecs) { + md->last_rq_pos = rq_end_sector(orig); + md->last_rq_rw = rq_data_dir(orig); + md->last_rq_start_time = ktime_get(); + } /* * Hold the md reference here for the in-flight I/O. @@ -1948,6 +1954,45 @@ static void dm_start_request(struct mapped_device *md, struct request *orig) dm_get(md); } +#define MAX_SEQ_RQ_MERGE_DEADLINE_USECS 100000 + +ssize_t dm_attr_rq_based_seq_io_merge_deadline_show(struct mapped_device *md, char *buf) +{ + return sprintf(buf, "%u\n", md->seq_rq_merge_deadline_usecs); +} + +ssize_t dm_attr_rq_based_seq_io_merge_deadline_store(struct mapped_device *md, + const char *buf, size_t count) +{ + unsigned deadline; + + if (!dm_request_based(md)) + return count; + + if (kstrtouint(buf, 10, &deadline)) + return -EINVAL; + + if (deadline > MAX_SEQ_RQ_MERGE_DEADLINE_USECS) + deadline = MAX_SEQ_RQ_MERGE_DEADLINE_USECS; + + md->seq_rq_merge_deadline_usecs = deadline; + + return count; +} + +static bool dm_request_peeked_before_merge_deadline(struct mapped_device *md) +{ + ktime_t kt_deadline; + + if (!md->seq_rq_merge_deadline_usecs) + return false; + + kt_deadline = ns_to_ktime((u64)md->seq_rq_merge_deadline_usecs * NSEC_PER_USEC); + kt_deadline = ktime_add_safe(md->last_rq_start_time, kt_deadline); + + return !ktime_after(ktime_get(), kt_deadline); +} + /* * q->request_fn for request-based dm. * Called with the queue lock held. @@ -1990,7 +2035,8 @@ static void dm_request_fn(struct request_queue *q) continue; } - if (md_in_flight(md) && rq->bio && rq->bio->bi_vcnt == 1 && + if (dm_request_peeked_before_merge_deadline(md) && + md_in_flight(md) && rq->bio && rq->bio->bi_vcnt == 1 && md->last_rq_pos == pos && md->last_rq_rw == rq_data_dir(rq)) goto delay_and_out; @@ -2532,6 +2578,9 @@ static int dm_init_request_based_queue(struct mapped_device *md) if (!q) return 0; + /* disable dm_request_fn's merge heuristic by default */ + md->seq_rq_merge_deadline_usecs = 0; + md->queue = q; dm_init_md_queue(md); blk_queue_softirq_done(md->queue, dm_softirq_done); diff --git a/drivers/md/dm.h b/drivers/md/dm.h index db495863fa5f..5522422cc6c4 100644 --- a/drivers/md/dm.h +++ b/drivers/md/dm.h @@ -234,4 +234,8 @@ static inline bool dm_message_test_buffer_overflow(char *result, unsigned maxlen return !maxlen || strlen(result) + 1 >= maxlen; } +ssize_t dm_attr_rq_based_seq_io_merge_deadline_show(struct mapped_device *md, char *buf); +ssize_t dm_attr_rq_based_seq_io_merge_deadline_store(struct mapped_device *md, + const char *buf, size_t count); + #endif -- cgit v1.2.3-59-g8ed1b From 17e149b8f73ba116e71e25930dd6f2eb3828792d Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Wed, 11 Mar 2015 15:01:09 -0400 Subject: dm: add 'use_blk_mq' module param and expose in per-device ro sysfs attr Request-based DM's blk-mq support defaults to off; but a user can easily change the default using the dm_mod.use_blk_mq module/boot option. Also, you can check what mode a given request-based DM device is using with: cat /sys/block/dm-X/dm/use_blk_mq This change enabled further cleanup and reduced work (e.g. the md->io_pool and md->rq_pool isn't created if using blk-mq). Signed-off-by: Mike Snitzer --- Documentation/ABI/testing/sysfs-block-dm | 8 +++++ drivers/md/Kconfig | 11 +++++++ drivers/md/dm-sysfs.c | 9 ++++++ drivers/md/dm-table.c | 6 ++-- drivers/md/dm.c | 53 ++++++++++++++++++++++++-------- drivers/md/dm.h | 5 ++- 6 files changed, 76 insertions(+), 16 deletions(-) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-block-dm b/Documentation/ABI/testing/sysfs-block-dm index ac4b6fe245d9..f9f2339b9a0a 100644 --- a/Documentation/ABI/testing/sysfs-block-dm +++ b/Documentation/ABI/testing/sysfs-block-dm @@ -37,3 +37,11 @@ Description: Allow control over how long a request that is a accounting. This attribute is not applicable to bio-based DM devices so it will only ever report 0 for them. + +What: /sys/block/dm-/dm/use_blk_mq +Date: March 2015 +KernelVersion: 4.1 +Contact: dm-devel@redhat.com +Description: Request-based Device-mapper blk-mq I/O path mode. + Contains the value 1 if the device is using blk-mq. + Otherwise it contains 0. Read-only attribute. diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig index 63e05e32b462..109f9dcc9cab 100644 --- a/drivers/md/Kconfig +++ b/drivers/md/Kconfig @@ -196,6 +196,17 @@ config BLK_DEV_DM If unsure, say N. +config DM_MQ_DEFAULT + bool "request-based DM: use blk-mq I/O path by default" + depends on BLK_DEV_DM + ---help--- + This option enables the blk-mq based I/O path for request-based + DM devices by default. With the option the dm_mod.use_blk_mq + module/boot option defaults to Y, without it to N, but it can + still be overriden either way. + + If unsure say N. + config DM_DEBUG bool "Device mapper debugging support" depends on BLK_DEV_DM diff --git a/drivers/md/dm-sysfs.c b/drivers/md/dm-sysfs.c index f5bb3944f75e..7e818f5f1dc4 100644 --- a/drivers/md/dm-sysfs.c +++ b/drivers/md/dm-sysfs.c @@ -89,15 +89,24 @@ static ssize_t dm_attr_suspended_show(struct mapped_device *md, char *buf) return strlen(buf); } +static ssize_t dm_attr_use_blk_mq_show(struct mapped_device *md, char *buf) +{ + sprintf(buf, "%d\n", dm_use_blk_mq(md)); + + return strlen(buf); +} + static DM_ATTR_RO(name); static DM_ATTR_RO(uuid); static DM_ATTR_RO(suspended); +static DM_ATTR_RO(use_blk_mq); static DM_ATTR_RW(rq_based_seq_io_merge_deadline); static struct attribute *dm_attrs[] = { &dm_attr_name.attr, &dm_attr_uuid.attr, &dm_attr_suspended.attr, + &dm_attr_use_blk_mq.attr, &dm_attr_rq_based_seq_io_merge_deadline.attr, NULL, }; diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 66600cab9fa5..8d025f33de92 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -940,7 +940,7 @@ bool dm_table_mq_request_based(struct dm_table *t) return dm_table_get_type(t) == DM_TYPE_MQ_REQUEST_BASED; } -static int dm_table_alloc_md_mempools(struct dm_table *t) +static int dm_table_alloc_md_mempools(struct dm_table *t, struct mapped_device *md) { unsigned type = dm_table_get_type(t); unsigned per_bio_data_size = 0; @@ -958,7 +958,7 @@ static int dm_table_alloc_md_mempools(struct dm_table *t) per_bio_data_size = max(per_bio_data_size, tgt->per_bio_data_size); } - t->mempools = dm_alloc_md_mempools(type, t->integrity_supported, per_bio_data_size); + t->mempools = dm_alloc_md_mempools(md, type, t->integrity_supported, per_bio_data_size); if (!t->mempools) return -ENOMEM; @@ -1128,7 +1128,7 @@ int dm_table_complete(struct dm_table *t) return r; } - r = dm_table_alloc_md_mempools(t); + r = dm_table_alloc_md_mempools(t, t->md); if (r) DMERR("unable to allocate mempools"); diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 55cadb1a2735..944cdb322708 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -228,8 +228,20 @@ struct mapped_device { /* for blk-mq request-based DM support */ struct blk_mq_tag_set tag_set; + bool use_blk_mq; }; +#ifdef CONFIG_DM_MQ_DEFAULT +static bool use_blk_mq = true; +#else +static bool use_blk_mq = false; +#endif + +bool dm_use_blk_mq(struct mapped_device *md) +{ + return md->use_blk_mq; +} + /* * For mempools pre-allocation at the table loading time. */ @@ -2034,7 +2046,7 @@ ssize_t dm_attr_rq_based_seq_io_merge_deadline_store(struct mapped_device *md, { unsigned deadline; - if (!dm_request_based(md)) + if (!dm_request_based(md) || md->use_blk_mq) return count; if (kstrtouint(buf, 10, &deadline)) @@ -2222,6 +2234,7 @@ static void dm_init_md_queue(struct mapped_device *md) static void dm_init_old_md_queue(struct mapped_device *md) { + md->use_blk_mq = false; dm_init_md_queue(md); /* @@ -2263,6 +2276,7 @@ static struct mapped_device *alloc_dev(int minor) if (r < 0) goto bad_io_barrier; + md->use_blk_mq = use_blk_mq; md->type = DM_TYPE_NONE; mutex_init(&md->suspend_lock); mutex_init(&md->type_lock); @@ -2349,7 +2363,6 @@ static void unlock_fs(struct mapped_device *md); static void free_dev(struct mapped_device *md) { int minor = MINOR(disk_devt(md->disk)); - bool using_blk_mq = !!md->queue->mq_ops; unlock_fs(md); destroy_workqueue(md->wq); @@ -2375,7 +2388,7 @@ static void free_dev(struct mapped_device *md) del_gendisk(md->disk); put_disk(md->disk); blk_cleanup_queue(md->queue); - if (using_blk_mq) + if (md->use_blk_mq) blk_mq_free_tag_set(&md->tag_set); bdput(md->bdev); free_minor(minor); @@ -2388,7 +2401,7 @@ static void __bind_mempools(struct mapped_device *md, struct dm_table *t) { struct dm_md_mempools *p = dm_table_get_md_mempools(t); - if (md->io_pool && md->bs) { + if (md->bs) { /* The md already has necessary mempools. */ if (dm_table_get_type(t) == DM_TYPE_BIO_BASED) { /* @@ -2798,13 +2811,21 @@ out_tag_set: return err; } +static unsigned filter_md_type(unsigned type, struct mapped_device *md) +{ + if (type == DM_TYPE_BIO_BASED) + return type; + + return !md->use_blk_mq ? DM_TYPE_REQUEST_BASED : DM_TYPE_MQ_REQUEST_BASED; +} + /* * Setup the DM device's queue based on md's type */ int dm_setup_md_queue(struct mapped_device *md) { int r; - unsigned md_type = dm_get_md_type(md); + unsigned md_type = filter_md_type(dm_get_md_type(md), md); switch (md_type) { case DM_TYPE_REQUEST_BASED: @@ -3509,16 +3530,19 @@ int dm_noflush_suspending(struct dm_target *ti) } EXPORT_SYMBOL_GPL(dm_noflush_suspending); -struct dm_md_mempools *dm_alloc_md_mempools(unsigned type, unsigned integrity, unsigned per_bio_data_size) +struct dm_md_mempools *dm_alloc_md_mempools(struct mapped_device *md, unsigned type, + unsigned integrity, unsigned per_bio_data_size) { struct dm_md_mempools *pools = kzalloc(sizeof(*pools), GFP_KERNEL); - struct kmem_cache *cachep; + struct kmem_cache *cachep = NULL; unsigned int pool_size = 0; unsigned int front_pad; if (!pools) return NULL; + type = filter_md_type(type, md); + switch (type) { case DM_TYPE_BIO_BASED: cachep = _io_cache; @@ -3526,13 +3550,13 @@ struct dm_md_mempools *dm_alloc_md_mempools(unsigned type, unsigned integrity, u front_pad = roundup(per_bio_data_size, __alignof__(struct dm_target_io)) + offsetof(struct dm_target_io, clone); break; case DM_TYPE_REQUEST_BASED: + cachep = _rq_tio_cache; pool_size = dm_get_reserved_rq_based_ios(); pools->rq_pool = mempool_create_slab_pool(pool_size, _rq_cache); if (!pools->rq_pool) goto out; /* fall through to setup remaining rq-based pools */ case DM_TYPE_MQ_REQUEST_BASED: - cachep = _rq_tio_cache; if (!pool_size) pool_size = dm_get_reserved_rq_based_ios(); front_pad = offsetof(struct dm_rq_clone_bio_info, clone); @@ -3540,12 +3564,14 @@ struct dm_md_mempools *dm_alloc_md_mempools(unsigned type, unsigned integrity, u WARN_ON(per_bio_data_size != 0); break; default: - goto out; + BUG(); } - pools->io_pool = mempool_create_slab_pool(pool_size, cachep); - if (!pools->io_pool) - goto out; + if (cachep) { + pools->io_pool = mempool_create_slab_pool(pool_size, cachep); + if (!pools->io_pool) + goto out; + } pools->bs = bioset_create_nobvec(pool_size, front_pad); if (!pools->bs) @@ -3602,6 +3628,9 @@ MODULE_PARM_DESC(reserved_bio_based_ios, "Reserved IOs in bio-based mempools"); module_param(reserved_rq_based_ios, uint, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(reserved_rq_based_ios, "Reserved IOs in request-based mempools"); +module_param(use_blk_mq, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(use_blk_mq, "Use block multiqueue for request-based DM devices"); + MODULE_DESCRIPTION(DM_NAME " driver"); MODULE_AUTHOR("Joe Thornber "); MODULE_LICENSE("GPL"); diff --git a/drivers/md/dm.h b/drivers/md/dm.h index 5522422cc6c4..6123c2bf9150 100644 --- a/drivers/md/dm.h +++ b/drivers/md/dm.h @@ -211,6 +211,8 @@ int dm_kobject_uevent(struct mapped_device *md, enum kobject_action action, void dm_internal_suspend(struct mapped_device *md); void dm_internal_resume(struct mapped_device *md); +bool dm_use_blk_mq(struct mapped_device *md); + int dm_io_init(void); void dm_io_exit(void); @@ -220,7 +222,8 @@ void dm_kcopyd_exit(void); /* * Mempool operations */ -struct dm_md_mempools *dm_alloc_md_mempools(unsigned type, unsigned integrity, unsigned per_bio_data_size); +struct dm_md_mempools *dm_alloc_md_mempools(struct mapped_device *md, unsigned type, + unsigned integrity, unsigned per_bio_data_size); void dm_free_md_mempools(struct dm_md_mempools *pools); /* -- cgit v1.2.3-59-g8ed1b From 0e0e32c16cfd2eeaf4fd4f16aa6cccd1333ce1e0 Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Wed, 18 Mar 2015 20:57:29 -0400 Subject: dm thin: remove stale 'trim' message documentation The 'trim' message wasn't ever implemented. Signed-off-by: Mike Snitzer --- Documentation/device-mapper/thin-provisioning.txt | 3 --- 1 file changed, 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/device-mapper/thin-provisioning.txt b/Documentation/device-mapper/thin-provisioning.txt index 2f5173500bd9..4f67578b2954 100644 --- a/Documentation/device-mapper/thin-provisioning.txt +++ b/Documentation/device-mapper/thin-provisioning.txt @@ -380,9 +380,6 @@ then you'll have no access to blocks mapped beyond the end. If you load a target that is bigger than before, then extra blocks will be provisioned as and when needed. -If you wish to reduce the size of your thin device and potentially -regain some space then send the 'trim' message to the pool. - ii) Status -- cgit v1.2.3-59-g8ed1b From 65ff5b7ddf0541f2b6e5cc59c47bfbf6cbcd91b8 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Wed, 18 Mar 2015 15:52:14 +0000 Subject: dm verity: add error handling modes for corrupted blocks Add device specific modes to dm-verity to specify how corrupted blocks should be handled. The following modes are defined: - DM_VERITY_MODE_EIO is the default behavior, where reading a corrupted block results in -EIO. - DM_VERITY_MODE_LOGGING only logs corrupted blocks, but does not block the read. - DM_VERITY_MODE_RESTART calls kernel_restart when a corrupted block is discovered. In addition, each mode sends a uevent to notify userspace of corruption and to allow further recovery actions. The driver defaults to previous behavior (DM_VERITY_MODE_EIO) and other modes can be enabled with an additional parameter to the verity table. Signed-off-by: Sami Tolvanen Signed-off-by: Mike Snitzer --- Documentation/device-mapper/verity.txt | 17 ++++ drivers/md/dm-verity.c | 147 ++++++++++++++++++++++++++++++--- drivers/md/dm.c | 1 + 3 files changed, 153 insertions(+), 12 deletions(-) (limited to 'Documentation') diff --git a/Documentation/device-mapper/verity.txt b/Documentation/device-mapper/verity.txt index 9884681535ee..64ccc5a079a5 100644 --- a/Documentation/device-mapper/verity.txt +++ b/Documentation/device-mapper/verity.txt @@ -11,6 +11,7 @@ Construction Parameters + [<#opt_params> ] This is the type of the on-disk hash format. @@ -62,6 +63,22 @@ Construction Parameters The hexadecimal encoding of the salt value. +<#opt_params> + Number of optional parameters. If there are no optional parameters, + the optional paramaters section can be skipped or #opt_params can be zero. + Otherwise #opt_params is the number of following arguments. + + Example of optional parameters section: + 1 ignore_corruption + +ignore_corruption + Log corrupted blocks, but allow read operations to proceed normally. + +restart_on_corruption + Restart the system when a corrupted block is discovered. This option is + not compatible with ignore_corruption and requires user space support to + avoid restart loops. + Theory of operation =================== diff --git a/drivers/md/dm-verity.c b/drivers/md/dm-verity.c index 7a7bab8947ae..66616db33e6f 100644 --- a/drivers/md/dm-verity.c +++ b/drivers/md/dm-verity.c @@ -18,20 +18,39 @@ #include #include +#include #include #define DM_MSG_PREFIX "verity" +#define DM_VERITY_ENV_LENGTH 42 +#define DM_VERITY_ENV_VAR_NAME "DM_VERITY_ERR_BLOCK_NR" + #define DM_VERITY_IO_VEC_INLINE 16 #define DM_VERITY_MEMPOOL_SIZE 4 #define DM_VERITY_DEFAULT_PREFETCH_SIZE 262144 #define DM_VERITY_MAX_LEVELS 63 +#define DM_VERITY_MAX_CORRUPTED_ERRS 100 + +#define DM_VERITY_OPT_LOGGING "ignore_corruption" +#define DM_VERITY_OPT_RESTART "restart_on_corruption" static unsigned dm_verity_prefetch_cluster = DM_VERITY_DEFAULT_PREFETCH_SIZE; module_param_named(prefetch_cluster, dm_verity_prefetch_cluster, uint, S_IRUGO | S_IWUSR); +enum verity_mode { + DM_VERITY_MODE_EIO, + DM_VERITY_MODE_LOGGING, + DM_VERITY_MODE_RESTART +}; + +enum verity_block_type { + DM_VERITY_BLOCK_TYPE_DATA, + DM_VERITY_BLOCK_TYPE_METADATA +}; + struct dm_verity { struct dm_dev *data_dev; struct dm_dev *hash_dev; @@ -54,6 +73,8 @@ struct dm_verity { unsigned digest_size; /* digest size for the current hash algorithm */ unsigned shash_descsize;/* the size of temporary space for crypto */ int hash_failed; /* set to 1 if hash of any block failed */ + enum verity_mode mode; /* mode for handling verification errors */ + unsigned corrupted_errs;/* Number of errors for corrupted blocks */ mempool_t *vec_mempool; /* mempool of bio vector */ @@ -174,6 +195,57 @@ static void verity_hash_at_level(struct dm_verity *v, sector_t block, int level, *offset = idx << (v->hash_dev_block_bits - v->hash_per_block_bits); } +/* + * Handle verification errors. + */ +static int verity_handle_err(struct dm_verity *v, enum verity_block_type type, + unsigned long long block) +{ + char verity_env[DM_VERITY_ENV_LENGTH]; + char *envp[] = { verity_env, NULL }; + const char *type_str = ""; + struct mapped_device *md = dm_table_get_md(v->ti->table); + + /* Corruption should be visible in device status in all modes */ + v->hash_failed = 1; + + if (v->corrupted_errs >= DM_VERITY_MAX_CORRUPTED_ERRS) + goto out; + + v->corrupted_errs++; + + switch (type) { + case DM_VERITY_BLOCK_TYPE_DATA: + type_str = "data"; + break; + case DM_VERITY_BLOCK_TYPE_METADATA: + type_str = "metadata"; + break; + default: + BUG(); + } + + DMERR("%s: %s block %llu is corrupted", v->data_dev->name, type_str, + block); + + if (v->corrupted_errs == DM_VERITY_MAX_CORRUPTED_ERRS) + DMERR("%s: reached maximum errors", v->data_dev->name); + + snprintf(verity_env, DM_VERITY_ENV_LENGTH, "%s=%d,%llu", + DM_VERITY_ENV_VAR_NAME, type, block); + + kobject_uevent_env(&disk_to_dev(dm_disk(md))->kobj, KOBJ_CHANGE, envp); + +out: + if (v->mode == DM_VERITY_MODE_LOGGING) + return 0; + + if (v->mode == DM_VERITY_MODE_RESTART) + kernel_restart("dm-verity device corrupted"); + + return 1; +} + /* * Verify hash of a metadata block pertaining to the specified data block * ("block" argument) at a specified level ("level" argument). @@ -251,11 +323,11 @@ static int verity_verify_level(struct dm_verity_io *io, sector_t block, goto release_ret_r; } if (unlikely(memcmp(result, io_want_digest(v, io), v->digest_size))) { - DMERR_LIMIT("metadata block %llu is corrupted", - (unsigned long long)hash_block); - v->hash_failed = 1; - r = -EIO; - goto release_ret_r; + if (verity_handle_err(v, DM_VERITY_BLOCK_TYPE_METADATA, + hash_block)) { + r = -EIO; + goto release_ret_r; + } } else aux->hash_verified = 1; } @@ -367,10 +439,9 @@ test_block_hash: return r; } if (unlikely(memcmp(result, io_want_digest(v, io), v->digest_size))) { - DMERR_LIMIT("data block %llu is corrupted", - (unsigned long long)(io->block + b)); - v->hash_failed = 1; - return -EIO; + if (verity_handle_err(v, DM_VERITY_BLOCK_TYPE_DATA, + io->block + b)) + return -EIO; } } @@ -546,6 +617,19 @@ static void verity_status(struct dm_target *ti, status_type_t type, else for (x = 0; x < v->salt_size; x++) DMEMIT("%02x", v->salt[x]); + if (v->mode != DM_VERITY_MODE_EIO) { + DMEMIT(" 1 "); + switch (v->mode) { + case DM_VERITY_MODE_LOGGING: + DMEMIT(DM_VERITY_OPT_LOGGING); + break; + case DM_VERITY_MODE_RESTART: + DMEMIT(DM_VERITY_OPT_RESTART); + break; + default: + BUG(); + } + } break; } } @@ -647,13 +731,19 @@ static void verity_dtr(struct dm_target *ti) static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv) { struct dm_verity *v; - unsigned num; + struct dm_arg_set as; + const char *opt_string; + unsigned int num, opt_params; unsigned long long num_ll; int r; int i; sector_t hash_position; char dummy; + static struct dm_arg _args[] = { + {0, 1, "Invalid number of feature args"}, + }; + v = kzalloc(sizeof(struct dm_verity), GFP_KERNEL); if (!v) { ti->error = "Cannot allocate verity structure"; @@ -668,8 +758,8 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv) goto bad; } - if (argc != 10) { - ti->error = "Invalid argument count: exactly 10 arguments required"; + if (argc < 10) { + ti->error = "Not enough arguments"; r = -EINVAL; goto bad; } @@ -790,6 +880,39 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv) } } + argv += 10; + argc -= 10; + + /* Optional parameters */ + if (argc) { + as.argc = argc; + as.argv = argv; + + r = dm_read_arg_group(_args, &as, &opt_params, &ti->error); + if (r) + goto bad; + + while (opt_params) { + opt_params--; + opt_string = dm_shift_arg(&as); + if (!opt_string) { + ti->error = "Not enough feature arguments"; + r = -EINVAL; + goto bad; + } + + if (!strcasecmp(opt_string, DM_VERITY_OPT_LOGGING)) + v->mode = DM_VERITY_MODE_LOGGING; + else if (!strcasecmp(opt_string, DM_VERITY_OPT_RESTART)) + v->mode = DM_VERITY_MODE_RESTART; + else { + ti->error = "Invalid feature arguments"; + r = -EINVAL; + goto bad; + } + } + } + v->hash_per_block_bits = __fls((1 << v->hash_dev_block_bits) / v->digest_size); diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 944cdb322708..f8c7ca3e8947 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -3483,6 +3483,7 @@ struct gendisk *dm_disk(struct mapped_device *md) { return md->disk; } +EXPORT_SYMBOL_GPL(dm_disk); struct kobject *dm_kobject(struct mapped_device *md) { -- cgit v1.2.3-59-g8ed1b From 0e9cebe724597a76ab1b0ebc0a21e16f7db11b47 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Fri, 20 Mar 2015 10:50:37 -0400 Subject: dm: add log writes target Introduce a new target that is meant for file system developers to test file system integrity at particular points in the life of a file system. We capture all write requests and associated data and log them to a separate device for later replay. There is a userspace utility to do this replay. The idea behind this is to give file system developers a tool to verify that the file system is always consistent. Signed-off-by: Josef Bacik Reviewed-by: Zach Brown Signed-off-by: Mike Snitzer --- Documentation/device-mapper/log-writes.txt | 140 +++++ drivers/md/Kconfig | 16 + drivers/md/Makefile | 1 + drivers/md/dm-log-writes.c | 825 +++++++++++++++++++++++++++++ 4 files changed, 982 insertions(+) create mode 100644 Documentation/device-mapper/log-writes.txt create mode 100644 drivers/md/dm-log-writes.c (limited to 'Documentation') diff --git a/Documentation/device-mapper/log-writes.txt b/Documentation/device-mapper/log-writes.txt new file mode 100644 index 000000000000..c10f30c9b534 --- /dev/null +++ b/Documentation/device-mapper/log-writes.txt @@ -0,0 +1,140 @@ +dm-log-writes +============= + +This target takes 2 devices, one to pass all IO to normally, and one to log all +of the write operations to. This is intended for file system developers wishing +to verify the integrity of metadata or data as the file system is written to. +There is a log_write_entry written for every WRITE request and the target is +able to take arbitrary data from userspace to insert into the log. The data +that is in the WRITE requests is copied into the log to make the replay happen +exactly as it happened originally. + +Log Ordering +============ + +We log things in order of completion once we are sure the write is no longer in +cache. This means that normal WRITE requests are not actually logged until the +next REQ_FLUSH request. This is to make it easier for userspace to replay the +log in a way that correlates to what is on disk and not what is in cache, to +make it easier to detect improper waiting/flushing. + +This works by attaching all WRITE requests to a list once the write completes. +Once we see a REQ_FLUSH request we splice this list onto the request and once +the FLUSH request completes we log all of the WRITEs and then the FLUSH. Only +completed WRITEs, at the time the REQ_FLUSH is issued, are added in order to +simulate the worst case scenario with regard to power failures. Consider the +following example (W means write, C means complete): + +W1,W2,W3,C3,C2,Wflush,C1,Cflush + +The log would show the following + +W3,W2,flush,W1.... + +Again this is to simulate what is actually on disk, this allows us to detect +cases where a power failure at a particular point in time would create an +inconsistent file system. + +Any REQ_FUA requests bypass this flushing mechanism and are logged as soon as +they complete as those requests will obviously bypass the device cache. + +Any REQ_DISCARD requests are treated like WRITE requests. Otherwise we would +have all the DISCARD requests, and then the WRITE requests and then the FLUSH +request. Consider the following example: + +WRITE block 1, DISCARD block 1, FLUSH + +If we logged DISCARD when it completed, the replay would look like this + +DISCARD 1, WRITE 1, FLUSH + +which isn't quite what happened and wouldn't be caught during the log replay. + +Target interface +================ + +i) Constructor + + log-writes + + dev_path : Device that all of the IO will go to normally. + log_dev_path : Device where the log entries are written to. + +ii) Status + + <#logged entries> + + #logged entries : Number of logged entries + highest allocated sector : Highest allocated sector + +iii) Messages + + mark + + You can use a dmsetup message to set an arbitrary mark in a log. + For example say you want to fsck a file system after every + write, but first you need to replay up to the mkfs to make sure + we're fsck'ing something reasonable, you would do something like + this: + + mkfs.btrfs -f /dev/mapper/log + dmsetup message log 0 mark mkfs + + + This would allow you to replay the log up to the mkfs mark and + then replay from that point on doing the fsck check in the + interval that you want. + + Every log has a mark at the end labeled "dm-log-writes-end". + +Userspace component +=================== + +There is a userspace tool that will replay the log for you in various ways. +It can be found here: https://github.com/josefbacik/log-writes + +Example usage +============= + +Say you want to test fsync on your file system. You would do something like +this: + +TABLE="0 $(blockdev --getsz /dev/sdb) log-writes /dev/sdb /dev/sdc" +dmsetup create log --table "$TABLE" +mkfs.btrfs -f /dev/mapper/log +dmsetup message log 0 mark mkfs + +mount /dev/mapper/log /mnt/btrfs-test + +dmsetup message log 0 mark fsync +md5sum /mnt/btrfs-test/foo +umount /mnt/btrfs-test + +dmsetup remove log +replay-log --log /dev/sdc --replay /dev/sdb --end-mark fsync +mount /dev/sdb /mnt/btrfs-test +md5sum /mnt/btrfs-test/foo + + +Another option is to do a complicated file system operation and verify the file +system is consistent during the entire operation. You could do this with: + +TABLE="0 $(blockdev --getsz /dev/sdb) log-writes /dev/sdb /dev/sdc" +dmsetup create log --table "$TABLE" +mkfs.btrfs -f /dev/mapper/log +dmsetup message log 0 mark mkfs + +mount /dev/mapper/log /mnt/btrfs-test + +btrfs filesystem balance /mnt/btrfs-test +umount /mnt/btrfs-test +dmsetup remove log + +replay-log --log /dev/sdc --replay /dev/sdb --end-mark mkfs +btrfsck /dev/sdb +replay-log --log /dev/sdc --replay /dev/sdb --start-mark mkfs \ + --fsck "btrfsck /dev/sdb" --check fua + +And that will replay the log until it sees a FUA request, run the fsck command +and if the fsck passes it will replay to the next FUA, until it is completed or +the fsck command exists abnormally. diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig index 109f9dcc9cab..6ddc983417d5 100644 --- a/drivers/md/Kconfig +++ b/drivers/md/Kconfig @@ -443,4 +443,20 @@ config DM_SWITCH If unsure, say N. +config DM_LOG_WRITES + tristate "Log writes target support" + depends on BLK_DEV_DM + ---help--- + This device-mapper target takes two devices, one device to use + normally, one to log all write operations done to the first device. + This is for use by file system developers wishing to verify that + their fs is writing a consitent file system at all times by allowing + them to replay the log in a variety of ways and to check the + contents. + + To compile this code as a module, choose M here: the module will + be called dm-log-writes. + + If unsure, say N. + endif # MD diff --git a/drivers/md/Makefile b/drivers/md/Makefile index a2da532b1c2b..1863feaa5846 100644 --- a/drivers/md/Makefile +++ b/drivers/md/Makefile @@ -55,6 +55,7 @@ obj-$(CONFIG_DM_CACHE) += dm-cache.o obj-$(CONFIG_DM_CACHE_MQ) += dm-cache-mq.o obj-$(CONFIG_DM_CACHE_CLEANER) += dm-cache-cleaner.o obj-$(CONFIG_DM_ERA) += dm-era.o +obj-$(CONFIG_DM_LOG_WRITES) += dm-log-writes.o ifeq ($(CONFIG_DM_UEVENT),y) dm-mod-objs += dm-uevent.o diff --git a/drivers/md/dm-log-writes.c b/drivers/md/dm-log-writes.c new file mode 100644 index 000000000000..93e08446a87d --- /dev/null +++ b/drivers/md/dm-log-writes.c @@ -0,0 +1,825 @@ +/* + * Copyright (C) 2014 Facebook. All rights reserved. + * + * This file is released under the GPL. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#define DM_MSG_PREFIX "log-writes" + +/* + * This target will sequentially log all writes to the target device onto the + * log device. This is helpful for replaying writes to check for fs consistency + * at all times. This target provides a mechanism to mark specific events to + * check data at a later time. So for example you would: + * + * write data + * fsync + * dmsetup message /dev/whatever mark mymark + * unmount /mnt/test + * + * Then replay the log up to mymark and check the contents of the replay to + * verify it matches what was written. + * + * We log writes only after they have been flushed, this makes the log describe + * close to the order in which the data hits the actual disk, not its cache. So + * for example the following sequence (W means write, C means complete) + * + * Wa,Wb,Wc,Cc,Ca,FLUSH,FUAd,Cb,CFLUSH,CFUAd + * + * Would result in the log looking like this: + * + * c,a,flush,fuad,b,, + * + * This is meant to help expose problems where file systems do not properly wait + * on data being written before invoking a FLUSH. FUA bypasses cache so once it + * completes it is added to the log as it should be on disk. + * + * We treat DISCARDs as if they don't bypass cache so that they are logged in + * order of completion along with the normal writes. If we didn't do it this + * way we would process all the discards first and then write all the data, when + * in fact we want to do the data and the discard in the order that they + * completed. + */ +#define LOG_FLUSH_FLAG (1 << 0) +#define LOG_FUA_FLAG (1 << 1) +#define LOG_DISCARD_FLAG (1 << 2) +#define LOG_MARK_FLAG (1 << 3) + +#define WRITE_LOG_VERSION 1 +#define WRITE_LOG_MAGIC 0x6a736677736872 + +/* + * The disk format for this is braindead simple. + * + * At byte 0 we have our super, followed by the following sequence for + * nr_entries: + * + * [ 1 sector ][ entry->nr_sectors ] + * [log_write_entry][ data written ] + * + * The log_write_entry takes up a full sector so we can have arbitrary length + * marks and it leaves us room for extra content in the future. + */ + +/* + * Basic info about the log for userspace. + */ +struct log_write_super { + __le64 magic; + __le64 version; + __le64 nr_entries; + __le32 sectorsize; +}; + +/* + * sector - the sector we wrote. + * nr_sectors - the number of sectors we wrote. + * flags - flags for this log entry. + * data_len - the size of the data in this log entry, this is for private log + * entry stuff, the MARK data provided by userspace for example. + */ +struct log_write_entry { + __le64 sector; + __le64 nr_sectors; + __le64 flags; + __le64 data_len; +}; + +struct log_writes_c { + struct dm_dev *dev; + struct dm_dev *logdev; + u64 logged_entries; + u32 sectorsize; + atomic_t io_blocks; + atomic_t pending_blocks; + sector_t next_sector; + sector_t end_sector; + bool logging_enabled; + bool device_supports_discard; + spinlock_t blocks_lock; + struct list_head unflushed_blocks; + struct list_head logging_blocks; + wait_queue_head_t wait; + struct task_struct *log_kthread; +}; + +struct pending_block { + int vec_cnt; + u64 flags; + sector_t sector; + sector_t nr_sectors; + char *data; + u32 datalen; + struct list_head list; + struct bio_vec vecs[0]; +}; + +struct per_bio_data { + struct pending_block *block; +}; + +static void put_pending_block(struct log_writes_c *lc) +{ + if (atomic_dec_and_test(&lc->pending_blocks)) { + smp_mb__after_atomic(); + if (waitqueue_active(&lc->wait)) + wake_up(&lc->wait); + } +} + +static void put_io_block(struct log_writes_c *lc) +{ + if (atomic_dec_and_test(&lc->io_blocks)) { + smp_mb__after_atomic(); + if (waitqueue_active(&lc->wait)) + wake_up(&lc->wait); + } +} + +static void log_end_io(struct bio *bio, int err) +{ + struct log_writes_c *lc = bio->bi_private; + struct bio_vec *bvec; + int i; + + if (err) { + unsigned long flags; + + DMERR("Error writing log block, error=%d", err); + spin_lock_irqsave(&lc->blocks_lock, flags); + lc->logging_enabled = false; + spin_unlock_irqrestore(&lc->blocks_lock, flags); + } + + bio_for_each_segment_all(bvec, bio, i) + __free_page(bvec->bv_page); + + put_io_block(lc); + bio_put(bio); +} + +/* + * Meant to be called if there is an error, it will free all the pages + * associated with the block. + */ +static void free_pending_block(struct log_writes_c *lc, + struct pending_block *block) +{ + int i; + + for (i = 0; i < block->vec_cnt; i++) { + if (block->vecs[i].bv_page) + __free_page(block->vecs[i].bv_page); + } + kfree(block->data); + kfree(block); + put_pending_block(lc); +} + +static int write_metadata(struct log_writes_c *lc, void *entry, + size_t entrylen, void *data, size_t datalen, + sector_t sector) +{ + struct bio *bio; + struct page *page; + void *ptr; + size_t ret; + + bio = bio_alloc(GFP_KERNEL, 1); + if (!bio) { + DMERR("Couldn't alloc log bio"); + goto error; + } + bio->bi_iter.bi_size = 0; + bio->bi_iter.bi_sector = sector; + bio->bi_bdev = lc->logdev->bdev; + bio->bi_end_io = log_end_io; + bio->bi_private = lc; + set_bit(BIO_UPTODATE, &bio->bi_flags); + + page = alloc_page(GFP_KERNEL); + if (!page) { + DMERR("Couldn't alloc log page"); + bio_put(bio); + goto error; + } + + ptr = kmap_atomic(page); + memcpy(ptr, entry, entrylen); + if (datalen) + memcpy(ptr + entrylen, data, datalen); + memset(ptr + entrylen + datalen, 0, + lc->sectorsize - entrylen - datalen); + kunmap_atomic(ptr); + + ret = bio_add_page(bio, page, lc->sectorsize, 0); + if (ret != lc->sectorsize) { + DMERR("Couldn't add page to the log block"); + goto error_bio; + } + submit_bio(WRITE, bio); + return 0; +error_bio: + bio_put(bio); + __free_page(page); +error: + put_io_block(lc); + return -1; +} + +static int log_one_block(struct log_writes_c *lc, + struct pending_block *block, sector_t sector) +{ + struct bio *bio; + struct log_write_entry entry; + size_t ret; + int i; + + entry.sector = cpu_to_le64(block->sector); + entry.nr_sectors = cpu_to_le64(block->nr_sectors); + entry.flags = cpu_to_le64(block->flags); + entry.data_len = cpu_to_le64(block->datalen); + if (write_metadata(lc, &entry, sizeof(entry), block->data, + block->datalen, sector)) { + free_pending_block(lc, block); + return -1; + } + + if (!block->vec_cnt) + goto out; + sector++; + + bio = bio_alloc(GFP_KERNEL, block->vec_cnt); + if (!bio) { + DMERR("Couldn't alloc log bio"); + goto error; + } + atomic_inc(&lc->io_blocks); + bio->bi_iter.bi_size = 0; + bio->bi_iter.bi_sector = sector; + bio->bi_bdev = lc->logdev->bdev; + bio->bi_end_io = log_end_io; + bio->bi_private = lc; + set_bit(BIO_UPTODATE, &bio->bi_flags); + + for (i = 0; i < block->vec_cnt; i++) { + /* + * The page offset is always 0 because we allocate a new page + * for every bvec in the original bio for simplicity sake. + */ + ret = bio_add_page(bio, block->vecs[i].bv_page, + block->vecs[i].bv_len, 0); + if (ret != block->vecs[i].bv_len) { + atomic_inc(&lc->io_blocks); + submit_bio(WRITE, bio); + bio = bio_alloc(GFP_KERNEL, block->vec_cnt - i); + if (!bio) { + DMERR("Couldn't alloc log bio"); + goto error; + } + bio->bi_iter.bi_size = 0; + bio->bi_iter.bi_sector = sector; + bio->bi_bdev = lc->logdev->bdev; + bio->bi_end_io = log_end_io; + bio->bi_private = lc; + set_bit(BIO_UPTODATE, &bio->bi_flags); + + ret = bio_add_page(bio, block->vecs[i].bv_page, + block->vecs[i].bv_len, 0); + if (ret != block->vecs[i].bv_len) { + DMERR("Couldn't add page on new bio?"); + bio_put(bio); + goto error; + } + } + sector += block->vecs[i].bv_len >> SECTOR_SHIFT; + } + submit_bio(WRITE, bio); +out: + kfree(block->data); + kfree(block); + put_pending_block(lc); + return 0; +error: + free_pending_block(lc, block); + put_io_block(lc); + return -1; +} + +static int log_super(struct log_writes_c *lc) +{ + struct log_write_super super; + + super.magic = cpu_to_le64(WRITE_LOG_MAGIC); + super.version = cpu_to_le64(WRITE_LOG_VERSION); + super.nr_entries = cpu_to_le64(lc->logged_entries); + super.sectorsize = cpu_to_le32(lc->sectorsize); + + if (write_metadata(lc, &super, sizeof(super), NULL, 0, 0)) { + DMERR("Couldn't write super"); + return -1; + } + + return 0; +} + +static inline sector_t logdev_last_sector(struct log_writes_c *lc) +{ + return i_size_read(lc->logdev->bdev->bd_inode) >> SECTOR_SHIFT; +} + +static int log_writes_kthread(void *arg) +{ + struct log_writes_c *lc = (struct log_writes_c *)arg; + sector_t sector = 0; + + while (!kthread_should_stop()) { + bool super = false; + bool logging_enabled; + struct pending_block *block = NULL; + int ret; + + spin_lock_irq(&lc->blocks_lock); + if (!list_empty(&lc->logging_blocks)) { + block = list_first_entry(&lc->logging_blocks, + struct pending_block, list); + list_del_init(&block->list); + if (!lc->logging_enabled) + goto next; + + sector = lc->next_sector; + if (block->flags & LOG_DISCARD_FLAG) + lc->next_sector++; + else + lc->next_sector += block->nr_sectors + 1; + + /* + * Apparently the size of the device may not be known + * right away, so handle this properly. + */ + if (!lc->end_sector) + lc->end_sector = logdev_last_sector(lc); + if (lc->end_sector && + lc->next_sector >= lc->end_sector) { + DMERR("Ran out of space on the logdev"); + lc->logging_enabled = false; + goto next; + } + lc->logged_entries++; + atomic_inc(&lc->io_blocks); + + super = (block->flags & (LOG_FUA_FLAG | LOG_MARK_FLAG)); + if (super) + atomic_inc(&lc->io_blocks); + } +next: + logging_enabled = lc->logging_enabled; + spin_unlock_irq(&lc->blocks_lock); + if (block) { + if (logging_enabled) { + ret = log_one_block(lc, block, sector); + if (!ret && super) + ret = log_super(lc); + if (ret) { + spin_lock_irq(&lc->blocks_lock); + lc->logging_enabled = false; + spin_unlock_irq(&lc->blocks_lock); + } + } else + free_pending_block(lc, block); + continue; + } + + if (!try_to_freeze()) { + set_current_state(TASK_INTERRUPTIBLE); + if (!kthread_should_stop() && + !atomic_read(&lc->pending_blocks)) + schedule(); + __set_current_state(TASK_RUNNING); + } + } + return 0; +} + +/* + * Construct a log-writes mapping: + * log-writes + */ +static int log_writes_ctr(struct dm_target *ti, unsigned int argc, char **argv) +{ + struct log_writes_c *lc; + struct dm_arg_set as; + const char *devname, *logdevname; + + as.argc = argc; + as.argv = argv; + + if (argc < 2) { + ti->error = "Invalid argument count"; + return -EINVAL; + } + + lc = kzalloc(sizeof(struct log_writes_c), GFP_KERNEL); + if (!lc) { + ti->error = "Cannot allocate context"; + return -ENOMEM; + } + spin_lock_init(&lc->blocks_lock); + INIT_LIST_HEAD(&lc->unflushed_blocks); + INIT_LIST_HEAD(&lc->logging_blocks); + init_waitqueue_head(&lc->wait); + lc->sectorsize = 1 << SECTOR_SHIFT; + atomic_set(&lc->io_blocks, 0); + atomic_set(&lc->pending_blocks, 0); + + devname = dm_shift_arg(&as); + if (dm_get_device(ti, devname, dm_table_get_mode(ti->table), &lc->dev)) { + ti->error = "Device lookup failed"; + goto bad; + } + + logdevname = dm_shift_arg(&as); + if (dm_get_device(ti, logdevname, dm_table_get_mode(ti->table), &lc->logdev)) { + ti->error = "Log device lookup failed"; + dm_put_device(ti, lc->dev); + goto bad; + } + + lc->log_kthread = kthread_run(log_writes_kthread, lc, "log-write"); + if (!lc->log_kthread) { + ti->error = "Couldn't alloc kthread"; + dm_put_device(ti, lc->dev); + dm_put_device(ti, lc->logdev); + goto bad; + } + + /* We put the super at sector 0, start logging at sector 1 */ + lc->next_sector = 1; + lc->logging_enabled = true; + lc->end_sector = logdev_last_sector(lc); + lc->device_supports_discard = true; + + ti->num_flush_bios = 1; + ti->flush_supported = true; + ti->num_discard_bios = 1; + ti->discards_supported = true; + ti->per_bio_data_size = sizeof(struct per_bio_data); + ti->private = lc; + return 0; + +bad: + kfree(lc); + return -EINVAL; +} + +static int log_mark(struct log_writes_c *lc, char *data) +{ + struct pending_block *block; + size_t maxsize = lc->sectorsize - sizeof(struct log_write_entry); + + block = kzalloc(sizeof(struct pending_block), GFP_KERNEL); + if (!block) { + DMERR("Error allocating pending block"); + return -ENOMEM; + } + + block->data = kstrndup(data, maxsize, GFP_KERNEL); + if (!block->data) { + DMERR("Error copying mark data"); + kfree(block); + return -ENOMEM; + } + atomic_inc(&lc->pending_blocks); + block->datalen = strlen(block->data); + block->flags |= LOG_MARK_FLAG; + spin_lock_irq(&lc->blocks_lock); + list_add_tail(&block->list, &lc->logging_blocks); + spin_unlock_irq(&lc->blocks_lock); + wake_up_process(lc->log_kthread); + return 0; +} + +static void log_writes_dtr(struct dm_target *ti) +{ + struct log_writes_c *lc = ti->private; + + spin_lock_irq(&lc->blocks_lock); + list_splice_init(&lc->unflushed_blocks, &lc->logging_blocks); + spin_unlock_irq(&lc->blocks_lock); + + /* + * This is just nice to have since it'll update the super to include the + * unflushed blocks, if it fails we don't really care. + */ + log_mark(lc, "dm-log-writes-end"); + wake_up_process(lc->log_kthread); + wait_event(lc->wait, !atomic_read(&lc->io_blocks) && + !atomic_read(&lc->pending_blocks)); + kthread_stop(lc->log_kthread); + + WARN_ON(!list_empty(&lc->logging_blocks)); + WARN_ON(!list_empty(&lc->unflushed_blocks)); + dm_put_device(ti, lc->dev); + dm_put_device(ti, lc->logdev); + kfree(lc); +} + +static void normal_map_bio(struct dm_target *ti, struct bio *bio) +{ + struct log_writes_c *lc = ti->private; + + bio->bi_bdev = lc->dev->bdev; +} + +static int log_writes_map(struct dm_target *ti, struct bio *bio) +{ + struct log_writes_c *lc = ti->private; + struct per_bio_data *pb = dm_per_bio_data(bio, sizeof(struct per_bio_data)); + struct pending_block *block; + struct bvec_iter iter; + struct bio_vec bv; + size_t alloc_size; + int i = 0; + bool flush_bio = (bio->bi_rw & REQ_FLUSH); + bool fua_bio = (bio->bi_rw & REQ_FUA); + bool discard_bio = (bio->bi_rw & REQ_DISCARD); + + pb->block = NULL; + + /* Don't bother doing anything if logging has been disabled */ + if (!lc->logging_enabled) + goto map_bio; + + /* + * Map reads as normal. + */ + if (bio_data_dir(bio) == READ) + goto map_bio; + + /* No sectors and not a flush? Don't care */ + if (!bio_sectors(bio) && !flush_bio) + goto map_bio; + + /* + * Discards will have bi_size set but there's no actual data, so just + * allocate the size of the pending block. + */ + if (discard_bio) + alloc_size = sizeof(struct pending_block); + else + alloc_size = sizeof(struct pending_block) + sizeof(struct bio_vec) * bio_segments(bio); + + block = kzalloc(alloc_size, GFP_NOIO); + if (!block) { + DMERR("Error allocating pending block"); + spin_lock_irq(&lc->blocks_lock); + lc->logging_enabled = false; + spin_unlock_irq(&lc->blocks_lock); + return -ENOMEM; + } + INIT_LIST_HEAD(&block->list); + pb->block = block; + atomic_inc(&lc->pending_blocks); + + if (flush_bio) + block->flags |= LOG_FLUSH_FLAG; + if (fua_bio) + block->flags |= LOG_FUA_FLAG; + if (discard_bio) + block->flags |= LOG_DISCARD_FLAG; + + block->sector = bio->bi_iter.bi_sector; + block->nr_sectors = bio_sectors(bio); + + /* We don't need the data, just submit */ + if (discard_bio) { + WARN_ON(flush_bio || fua_bio); + if (lc->device_supports_discard) + goto map_bio; + bio_endio(bio, 0); + return DM_MAPIO_SUBMITTED; + } + + /* Flush bio, splice the unflushed blocks onto this list and submit */ + if (flush_bio && !bio_sectors(bio)) { + spin_lock_irq(&lc->blocks_lock); + list_splice_init(&lc->unflushed_blocks, &block->list); + spin_unlock_irq(&lc->blocks_lock); + goto map_bio; + } + + /* + * We will write this bio somewhere else way later so we need to copy + * the actual contents into new pages so we know the data will always be + * there. + * + * We do this because this could be a bio from O_DIRECT in which case we + * can't just hold onto the page until some later point, we have to + * manually copy the contents. + */ + bio_for_each_segment(bv, bio, iter) { + struct page *page; + void *src, *dst; + + page = alloc_page(GFP_NOIO); + if (!page) { + DMERR("Error allocing page"); + free_pending_block(lc, block); + spin_lock_irq(&lc->blocks_lock); + lc->logging_enabled = false; + spin_unlock_irq(&lc->blocks_lock); + return -ENOMEM; + } + + src = kmap_atomic(bv.bv_page); + dst = kmap_atomic(page); + memcpy(dst, src + bv.bv_offset, bv.bv_len); + kunmap_atomic(dst); + kunmap_atomic(src); + block->vecs[i].bv_page = page; + block->vecs[i].bv_len = bv.bv_len; + block->vec_cnt++; + i++; + } + + /* Had a flush with data in it, weird */ + if (flush_bio) { + spin_lock_irq(&lc->blocks_lock); + list_splice_init(&lc->unflushed_blocks, &block->list); + spin_unlock_irq(&lc->blocks_lock); + } +map_bio: + normal_map_bio(ti, bio); + return DM_MAPIO_REMAPPED; +} + +static int normal_end_io(struct dm_target *ti, struct bio *bio, int error) +{ + struct log_writes_c *lc = ti->private; + struct per_bio_data *pb = dm_per_bio_data(bio, sizeof(struct per_bio_data)); + + if (bio_data_dir(bio) == WRITE && pb->block) { + struct pending_block *block = pb->block; + unsigned long flags; + + spin_lock_irqsave(&lc->blocks_lock, flags); + if (block->flags & LOG_FLUSH_FLAG) { + list_splice_tail_init(&block->list, &lc->logging_blocks); + list_add_tail(&block->list, &lc->logging_blocks); + wake_up_process(lc->log_kthread); + } else if (block->flags & LOG_FUA_FLAG) { + list_add_tail(&block->list, &lc->logging_blocks); + wake_up_process(lc->log_kthread); + } else + list_add_tail(&block->list, &lc->unflushed_blocks); + spin_unlock_irqrestore(&lc->blocks_lock, flags); + } + + return error; +} + +/* + * INFO format: + */ +static void log_writes_status(struct dm_target *ti, status_type_t type, + unsigned status_flags, char *result, + unsigned maxlen) +{ + unsigned sz = 0; + struct log_writes_c *lc = ti->private; + + switch (type) { + case STATUSTYPE_INFO: + DMEMIT("%llu %llu", lc->logged_entries, + (unsigned long long)lc->next_sector - 1); + if (!lc->logging_enabled) + DMEMIT(" logging_disabled"); + break; + + case STATUSTYPE_TABLE: + DMEMIT("%s %s", lc->dev->name, lc->logdev->name); + break; + } +} + +static int log_writes_ioctl(struct dm_target *ti, unsigned int cmd, + unsigned long arg) +{ + struct log_writes_c *lc = ti->private; + struct dm_dev *dev = lc->dev; + int r = 0; + + /* + * Only pass ioctls through if the device sizes match exactly. + */ + if (ti->len != i_size_read(dev->bdev->bd_inode) >> SECTOR_SHIFT) + r = scsi_verify_blk_ioctl(NULL, cmd); + + return r ? : __blkdev_driver_ioctl(dev->bdev, dev->mode, cmd, arg); +} + +static int log_writes_merge(struct dm_target *ti, struct bvec_merge_data *bvm, + struct bio_vec *biovec, int max_size) +{ + struct log_writes_c *lc = ti->private; + struct request_queue *q = bdev_get_queue(lc->dev->bdev); + + if (!q->merge_bvec_fn) + return max_size; + + bvm->bi_bdev = lc->dev->bdev; + bvm->bi_sector = dm_target_offset(ti, bvm->bi_sector); + + return min(max_size, q->merge_bvec_fn(q, bvm, biovec)); +} + +static int log_writes_iterate_devices(struct dm_target *ti, + iterate_devices_callout_fn fn, + void *data) +{ + struct log_writes_c *lc = ti->private; + + return fn(ti, lc->dev, 0, ti->len, data); +} + +/* + * Messages supported: + * mark - specify the marked data. + */ +static int log_writes_message(struct dm_target *ti, unsigned argc, char **argv) +{ + int r = -EINVAL; + struct log_writes_c *lc = ti->private; + + if (argc != 2) { + DMWARN("Invalid log-writes message arguments, expect 2 arguments, got %d", argc); + return r; + } + + if (!strcasecmp(argv[0], "mark")) + r = log_mark(lc, argv[1]); + else + DMWARN("Unrecognised log writes target message received: %s", argv[0]); + + return r; +} + +static void log_writes_io_hints(struct dm_target *ti, struct queue_limits *limits) +{ + struct log_writes_c *lc = ti->private; + struct request_queue *q = bdev_get_queue(lc->dev->bdev); + + if (!q || !blk_queue_discard(q)) { + lc->device_supports_discard = false; + limits->discard_granularity = 1 << SECTOR_SHIFT; + limits->max_discard_sectors = (UINT_MAX >> SECTOR_SHIFT); + } +} + +static struct target_type log_writes_target = { + .name = "log-writes", + .version = {1, 0, 0}, + .module = THIS_MODULE, + .ctr = log_writes_ctr, + .dtr = log_writes_dtr, + .map = log_writes_map, + .end_io = normal_end_io, + .status = log_writes_status, + .ioctl = log_writes_ioctl, + .merge = log_writes_merge, + .message = log_writes_message, + .iterate_devices = log_writes_iterate_devices, + .io_hints = log_writes_io_hints, +}; + +static int __init dm_log_writes_init(void) +{ + int r = dm_register_target(&log_writes_target); + + if (r < 0) + DMERR("register failed %d", r); + + return r; +} + +static void __exit dm_log_writes_exit(void) +{ + dm_unregister_target(&log_writes_target); +} + +module_init(dm_log_writes_init); +module_exit(dm_log_writes_exit); + +MODULE_DESCRIPTION(DM_NAME " log writes target"); +MODULE_AUTHOR("Josef Bacik "); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-59-g8ed1b From e44f23b32dc7916b2bc12817e2f723fefa21ba41 Mon Sep 17 00:00:00 2001 From: Milan Broz Date: Sun, 5 Apr 2015 18:03:10 +0200 Subject: dm crypt: update URLs to new cryptsetup project page Cryptsetup home page moved to GitLab. Also remove link to abandonded Truecrypt page. Signed-off-by: Milan Broz Signed-off-by: Mike Snitzer --- Documentation/device-mapper/dm-crypt.txt | 4 ++-- Documentation/device-mapper/verity.txt | 4 ++-- drivers/md/dm-crypt.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/device-mapper/dm-crypt.txt b/Documentation/device-mapper/dm-crypt.txt index ad697781f9ac..692171fe9da0 100644 --- a/Documentation/device-mapper/dm-crypt.txt +++ b/Documentation/device-mapper/dm-crypt.txt @@ -5,7 +5,7 @@ Device-Mapper's "crypt" target provides transparent encryption of block devices using the kernel crypto API. For a more detailed description of supported parameters see: -http://code.google.com/p/cryptsetup/wiki/DMCrypt +https://gitlab.com/cryptsetup/cryptsetup/wikis/DMCrypt Parameters: \ [<#opt_params> ] @@ -80,7 +80,7 @@ Example scripts =============== LUKS (Linux Unified Key Setup) is now the preferred way to set up disk encryption with dm-crypt using the 'cryptsetup' utility, see -http://code.google.com/p/cryptsetup/ +https://gitlab.com/cryptsetup/cryptsetup [[ #!/bin/sh diff --git a/Documentation/device-mapper/verity.txt b/Documentation/device-mapper/verity.txt index 64ccc5a079a5..e15bc1a0fb98 100644 --- a/Documentation/device-mapper/verity.txt +++ b/Documentation/device-mapper/verity.txt @@ -142,7 +142,7 @@ block boundary) are the hash blocks which are stored a depth at a time The full specification of kernel parameters and on-disk metadata format is available at the cryptsetup project's wiki page - http://code.google.com/p/cryptsetup/wiki/DMVerity + https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity Status ====== @@ -159,7 +159,7 @@ Set up a device: A command line tool veritysetup is available to compute or verify the hash tree or activate the kernel device. This is available from -the cryptsetup upstream repository http://code.google.com/p/cryptsetup/ +the cryptsetup upstream repository https://gitlab.com/cryptsetup/cryptsetup/ (as a libcryptsetup extension). Create hash on the device: diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 713a96237a80..ea09d5464a9f 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -228,7 +228,7 @@ static struct crypto_ablkcipher *any_tfm(struct crypt_config *cc) * * tcw: Compatible implementation of the block chaining mode used * by the TrueCrypt device encryption system (prior to version 4.1). - * For more info see: http://www.truecrypt.org + * For more info see: https://gitlab.com/cryptsetup/cryptsetup/wikis/TrueCryptOnDiskFormat * It operates on full 512 byte sectors and uses CBC * with an IV derived from initial key and the sector number. * In addition, whitening value is applied on every sector, whitening -- cgit v1.2.3-59-g8ed1b From 5bbe3547aa3ba5242366a322a28996872301b703 Mon Sep 17 00:00:00 2001 From: Eric B Munson Date: Wed, 15 Apr 2015 16:13:20 -0700 Subject: mm: allow compaction of unevictable pages Currently, pages which are marked as unevictable are protected from compaction, but not from other types of migration. The POSIX real time extension explicitly states that mlock() will prevent a major page fault, but the spirit of this is that mlock() should give a process the ability to control sources of latency, including minor page faults. However, the mlock manpage only explicitly says that a locked page will not be written to swap and this can cause some confusion. The compaction code today does not give a developer who wants to avoid swap but wants to have large contiguous areas available any method to achieve this state. This patch introduces a sysctl for controlling compaction behavior with respect to the unevictable lru. Users who demand no page faults after a page is present can set compact_unevictable_allowed to 0 and users who need the large contiguous areas can enable compaction on locked memory by leaving the default value of 1. To illustrate this problem I wrote a quick test program that mmaps a large number of 1MB files filled with random data. These maps are created locked and read only. Then every other mmap is unmapped and I attempt to allocate huge pages to the static huge page pool. When the compact_unevictable_allowed sysctl is 0, I cannot allocate hugepages after fragmenting memory. When the value is set to 1, allocations succeed. Signed-off-by: Eric B Munson Acked-by: Michal Hocko Acked-by: Vlastimil Babka Acked-by: Christoph Lameter Acked-by: David Rientjes Acked-by: Rik van Riel Cc: Vlastimil Babka Cc: Thomas Gleixner Cc: Christoph Lameter Cc: Peter Zijlstra Cc: Mel Gorman Cc: David Rientjes Cc: Michal Hocko Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/sysctl/vm.txt | 11 +++++++++++ include/linux/compaction.h | 1 + kernel/sysctl.c | 9 +++++++++ mm/compaction.c | 7 +++++++ 4 files changed, 28 insertions(+) (limited to 'Documentation') diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt index 902b4574acfb..9832ec52f859 100644 --- a/Documentation/sysctl/vm.txt +++ b/Documentation/sysctl/vm.txt @@ -21,6 +21,7 @@ Currently, these files are in /proc/sys/vm: - admin_reserve_kbytes - block_dump - compact_memory +- compact_unevictable_allowed - dirty_background_bytes - dirty_background_ratio - dirty_bytes @@ -106,6 +107,16 @@ huge pages although processes will also directly compact memory as required. ============================================================== +compact_unevictable_allowed + +Available only when CONFIG_COMPACTION is set. When set to 1, compaction is +allowed to examine the unevictable lru (mlocked pages) for pages to compact. +This should be used on systems where stalls for minor page faults are an +acceptable trade for large contiguous free memory. Set to 0 to prevent +compaction from moving pages that are unevictable. Default value is 1. + +============================================================== + dirty_background_bytes Contains the amount of dirty memory at which the background kernel diff --git a/include/linux/compaction.h b/include/linux/compaction.h index a014559e4a49..aa8f61cf3a19 100644 --- a/include/linux/compaction.h +++ b/include/linux/compaction.h @@ -34,6 +34,7 @@ extern int sysctl_compaction_handler(struct ctl_table *table, int write, extern int sysctl_extfrag_threshold; extern int sysctl_extfrag_handler(struct ctl_table *table, int write, void __user *buffer, size_t *length, loff_t *ppos); +extern int sysctl_compact_unevictable_allowed; extern int fragmentation_index(struct zone *zone, unsigned int order); extern unsigned long try_to_compact_pages(gfp_t gfp_mask, unsigned int order, diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 8c0eabd41886..42b7fc2860c1 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -1335,6 +1335,15 @@ static struct ctl_table vm_table[] = { .extra1 = &min_extfrag_threshold, .extra2 = &max_extfrag_threshold, }, + { + .procname = "compact_unevictable_allowed", + .data = &sysctl_compact_unevictable_allowed, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + .extra1 = &zero, + .extra2 = &one, + }, #endif /* CONFIG_COMPACTION */ { diff --git a/mm/compaction.c b/mm/compaction.c index a18201a8124e..570426edcadf 100644 --- a/mm/compaction.c +++ b/mm/compaction.c @@ -1046,6 +1046,12 @@ typedef enum { ISOLATE_SUCCESS, /* Pages isolated, migrate */ } isolate_migrate_t; +/* + * Allow userspace to control policy on scanning the unevictable LRU for + * compactable pages. + */ +int sysctl_compact_unevictable_allowed __read_mostly = 1; + /* * Isolate all pages that can be migrated from the first suitable block, * starting at the block pointed to by the migrate scanner pfn within @@ -1057,6 +1063,7 @@ static isolate_migrate_t isolate_migratepages(struct zone *zone, unsigned long low_pfn, end_pfn; struct page *page; const isolate_mode_t isolate_mode = + (sysctl_compact_unevictable_allowed ? ISOLATE_UNEVICTABLE : 0) | (cc->mode == MIGRATE_ASYNC ? ISOLATE_ASYNC_MIGRATE : 0); /* -- cgit v1.2.3-59-g8ed1b From 922c0551a795dccadeb1dadc756d93fe3e303180 Mon Sep 17 00:00:00 2001 From: Eric B Munson Date: Wed, 15 Apr 2015 16:13:23 -0700 Subject: Documentation/vm/unevictable-lru.txt: document interaction between compaction and the unevictable LRU The memory compaction code uses the migration code to do most of the work in compaction. However, the compaction code interacts with the unevictable LRU differently than migration code and this difference should be noted in the documentation. [akpm@linux-foundation.org: identify /proc/sys/vm/compact_unevictable directly] Signed-off-by: Eric B Munson Cc: Michal Hocko Cc: Vlastimil Babka Cc: Christoph Lameter Cc: David Rientjes Cc: Rik van Riel Cc: Thomas Gleixner Cc: Peter Zijlstra Cc: Mel Gorman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/vm/unevictable-lru.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'Documentation') diff --git a/Documentation/vm/unevictable-lru.txt b/Documentation/vm/unevictable-lru.txt index 86cb4624fc5a..3be0bfc4738d 100644 --- a/Documentation/vm/unevictable-lru.txt +++ b/Documentation/vm/unevictable-lru.txt @@ -22,6 +22,7 @@ CONTENTS - Filtering special vmas. - munlock()/munlockall() system call handling. - Migrating mlocked pages. + - Compacting mlocked pages. - mmap(MAP_LOCKED) system call handling. - munmap()/exit()/exec() system call handling. - try_to_unmap(). @@ -450,6 +451,17 @@ list because of a race between munlock and migration, page migration uses the putback_lru_page() function to add migrated pages back to the LRU. +COMPACTING MLOCKED PAGES +------------------------ + +The unevictable LRU can be scanned for compactable regions and the default +behavior is to do so. /proc/sys/vm/compact_unevictable_allowed controls +this behavior (see Documentation/sysctl/vm.txt). Once scanning of the +unevictable LRU is enabled, the work of compaction is mostly handled by +the page migration code and the same work flow as described in MIGRATING +MLOCKED PAGES will apply. + + mmap(MAP_LOCKED) SYSTEM CALL HANDLING ------------------------------------- -- cgit v1.2.3-59-g8ed1b From 8c9b97033547834404a58ea88da7226ed5167726 Mon Sep 17 00:00:00 2001 From: Mike Kravetz Date: Wed, 15 Apr 2015 16:13:45 -0700 Subject: hugetlbfs: document min_size mount option and cleanup Add min_size mount option to the hugetlbfs documentation. Also, add the missing pagesize option and mention that size can be specified as bytes or a percentage of huge page pool. Signed-off-by: Mike Kravetz Cc: Davidlohr Bueso Cc: Aneesh Kumar Cc: Joonsoo Kim Cc: Andi Kleen Cc: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/vm/hugetlbpage.txt | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) (limited to 'Documentation') diff --git a/Documentation/vm/hugetlbpage.txt b/Documentation/vm/hugetlbpage.txt index f2d3a100fe38..b32b9cd50c0e 100644 --- a/Documentation/vm/hugetlbpage.txt +++ b/Documentation/vm/hugetlbpage.txt @@ -267,21 +267,34 @@ call, then it is required that system administrator mount a file system of type hugetlbfs: mount -t hugetlbfs \ - -o uid=,gid=,mode=,size=,nr_inodes= \ - none /mnt/huge + -o uid=,gid=,mode=,pagesize=,size=,\ + min_size=,nr_inodes= none /mnt/huge This command mounts a (pseudo) filesystem of type hugetlbfs on the directory /mnt/huge. Any files created on /mnt/huge uses huge pages. The uid and gid options sets the owner and group of the root of the file system. By default the uid and gid of the current process are taken. The mode option sets the mode of root of file system to value & 01777. This value is given in octal. -By default the value 0755 is picked. The size option sets the maximum value of -memory (huge pages) allowed for that filesystem (/mnt/huge). The size is -rounded down to HPAGE_SIZE. The option nr_inodes sets the maximum number of -inodes that /mnt/huge can use. If the size or nr_inodes option is not -provided on command line then no limits are set. For size and nr_inodes -options, you can use [G|g]/[M|m]/[K|k] to represent giga/mega/kilo. For -example, size=2K has the same meaning as size=2048. +By default the value 0755 is picked. If the paltform supports multiple huge +page sizes, the pagesize option can be used to specify the huge page size and +associated pool. pagesize is specified in bytes. If pagesize is not specified +the paltform's default huge page size and associated pool will be used. The +size option sets the maximum value of memory (huge pages) allowed for that +filesystem (/mnt/huge). The size option can be specified in bytes, or as a +percentage of the specified huge page pool (nr_hugepages). The size is +rounded down to HPAGE_SIZE boundary. The min_size option sets the minimum +value of memory (huge pages) allowed for the filesystem. min_size can be +specified in the same way as size, either bytes or a percentage of the +huge page pool. At mount time, the number of huge pages specified by +min_size are reserved for use by the filesystem. If there are not enough +free huge pages available, the mount will fail. As huge pages are allocated +to the filesystem and freed, the reserve count is adjusted so that the sum +of allocated and reserved huge pages is always at least min_size. The option +nr_inodes sets the maximum number of inodes that /mnt/huge can use. If the +size, min_size or nr_inodes option is not provided on command line then +no limits are set. For pagesize, size, min_size and nr_inodes options, you +can use [G|g]/[M|m]/[K|k] to represent giga/mega/kilo. For example, size=2K +has the same meaning as size=2048. While read system calls are supported on files that reside on hugetlb file systems, write system calls are not. -- cgit v1.2.3-59-g8ed1b From 80d6b94bd69a7a49b52bf503ef6a841f43cf5bbb Mon Sep 17 00:00:00 2001 From: David Rientjes Date: Wed, 15 Apr 2015 16:14:26 -0700 Subject: mm, doc: cleanup and clarify munmap behavior for hugetlb memory munmap(2) of hugetlb memory requires a length that is hugepage aligned, otherwise it may fail. Add this to the documentation. This also cleans up the documentation and separates it into logical units: one part refers to MAP_HUGETLB and another part refers to requirements for shared memory segments. Signed-off-by: David Rientjes Cc: Jonathan Corbet Cc: Davide Libenzi Cc: Luiz Capitulino Cc: Shuah Khan Acked-by: Hugh Dickins Cc: Andrea Arcangeli Cc: Joern Engel Cc: Jianguo Wu Cc: Eric B Munson Cc: Michael Ellerman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/vm/hugetlbpage.txt | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) (limited to 'Documentation') diff --git a/Documentation/vm/hugetlbpage.txt b/Documentation/vm/hugetlbpage.txt index b32b9cd50c0e..030977fb8d2d 100644 --- a/Documentation/vm/hugetlbpage.txt +++ b/Documentation/vm/hugetlbpage.txt @@ -302,15 +302,23 @@ file systems, write system calls are not. Regular chown, chgrp, and chmod commands (with right permissions) could be used to change the file attributes on hugetlbfs. -Also, it is important to note that no such mount command is required if the +Also, it is important to note that no such mount command is required if applications are going to use only shmat/shmget system calls or mmap with -MAP_HUGETLB. Users who wish to use hugetlb page via shared memory segment -should be a member of a supplementary group and system admin needs to -configure that gid into /proc/sys/vm/hugetlb_shm_group. It is possible for -same or different applications to use any combination of mmaps and shm* -calls, though the mount of filesystem will be required for using mmap calls -without MAP_HUGETLB. For an example of how to use mmap with MAP_HUGETLB see -map_hugetlb.c. +MAP_HUGETLB. For an example of how to use mmap with MAP_HUGETLB see map_hugetlb +below. + +Users who wish to use hugetlb memory via shared memory segment should be a +member of a supplementary group and system admin needs to configure that gid +into /proc/sys/vm/hugetlb_shm_group. It is possible for same or different +applications to use any combination of mmaps and shm* calls, though the mount of +filesystem will be required for using mmap calls without MAP_HUGETLB. + +Syscalls that operate on memory backed by hugetlb pages only have their lengths +aligned to the native page size of the processor; they will normally fail with +errno set to EINVAL or exclude hugetlb pages that extend beyond the length if +not hugepage aligned. For example, munmap(2) will fail if memory is backed by +a hugetlb page and the length is smaller than the hugepage size. + Examples ======== -- cgit v1.2.3-59-g8ed1b From dd9061846a3ba01b0fa45423aaa087e4a69187fa Mon Sep 17 00:00:00 2001 From: Boaz Harrosh Date: Wed, 15 Apr 2015 16:15:11 -0700 Subject: mm: new pfn_mkwrite same as page_mkwrite for VM_PFNMAP This will allow FS that uses VM_PFNMAP | VM_MIXEDMAP (no page structs) to get notified when access is a write to a read-only PFN. This can happen if we mmap() a file then first mmap-read from it to page-in a read-only PFN, than we mmap-write to the same page. We need this functionality to fix a DAX bug, where in the scenario above we fail to set ctime/mtime though we modified the file. An xfstest is attached to this patchset that shows the failure and the fix. (A DAX patch will follow) This functionality is extra important for us, because upon dirtying of a pmem page we also want to RDMA the page to a remote cluster node. We define a new pfn_mkwrite and do not reuse page_mkwrite because 1 - The name ;-) 2 - But mainly because it would take a very long and tedious audit of all page_mkwrite functions of VM_MIXEDMAP/VM_PFNMAP users. To make sure they do not now CRASH. For example current DAX code (which this is for) would crash. If we would want to reuse page_mkwrite, We will need to first patch all users, so to not-crash-on-no-page. Then enable this patch. But even if I did that I would not sleep so well at night. Adding a new vector is the safest thing to do, and is not that expensive. an extra pointer at a static function vector per driver. Also the new vector is better for performance, because else we Will call all current Kernel vectors, so to: check-ha-no-page-do-nothing and return. No need to call it from do_shared_fault because do_wp_page is called to change pte permissions anyway. Signed-off-by: Yigal Korman Signed-off-by: Boaz Harrosh Acked-by: Kirill A. Shutemov Cc: Matthew Wilcox Cc: Jan Kara Cc: Hugh Dickins Cc: Mel Gorman Cc: Dave Chinner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/filesystems/Locking | 8 ++++++++ include/linux/mm.h | 3 +++ mm/memory.c | 43 +++++++++++++++++++++++++++++++++++---- 3 files changed, 50 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking index f91926f2f482..8bb8a7ee0f99 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/Locking @@ -525,6 +525,7 @@ prototypes: void (*close)(struct vm_area_struct*); int (*fault)(struct vm_area_struct*, struct vm_fault *); int (*page_mkwrite)(struct vm_area_struct *, struct vm_fault *); + int (*pfn_mkwrite)(struct vm_area_struct *, struct vm_fault *); int (*access)(struct vm_area_struct *, unsigned long, void*, int, int); locking rules: @@ -534,6 +535,7 @@ close: yes fault: yes can return with page locked map_pages: yes page_mkwrite: yes can return with page locked +pfn_mkwrite: yes access: yes ->fault() is called when a previously not present pte is about @@ -560,6 +562,12 @@ the page has been truncated, the filesystem should not look up a new page like the ->fault() handler, but simply return with VM_FAULT_NOPAGE, which will cause the VM to retry the fault. + ->pfn_mkwrite() is the same as page_mkwrite but when the pte is +VM_PFNMAP or VM_MIXEDMAP with a page-less entry. Expected return is +VM_FAULT_NOPAGE. Or one of the VM_FAULT_ERROR types. The default behavior +after this call is to make the pte read-write, unless pfn_mkwrite returns +an error. + ->access() is called when get_user_pages() fails in access_process_vm(), typically used to debug a process through /proc/pid/mem or ptrace. This function is needed only for diff --git a/include/linux/mm.h b/include/linux/mm.h index 0e7bb2194da5..8b086070c3a5 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -251,6 +251,9 @@ struct vm_operations_struct { * writable, if an error is returned it will cause a SIGBUS */ int (*page_mkwrite)(struct vm_area_struct *vma, struct vm_fault *vmf); + /* same as page_mkwrite when using VM_PFNMAP|VM_MIXEDMAP */ + int (*pfn_mkwrite)(struct vm_area_struct *vma, struct vm_fault *vmf); + /* called by access_process_vm when get_user_pages() fails, typically * for use by special VMAs that can switch between memory and hardware */ diff --git a/mm/memory.c b/mm/memory.c index f9628e568c58..22e037e3364e 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -2180,6 +2180,42 @@ oom: return VM_FAULT_OOM; } +/* + * Handle write page faults for VM_MIXEDMAP or VM_PFNMAP for a VM_SHARED + * mapping + */ +static int wp_pfn_shared(struct mm_struct *mm, + struct vm_area_struct *vma, unsigned long address, + pte_t *page_table, spinlock_t *ptl, pte_t orig_pte, + pmd_t *pmd) +{ + if (vma->vm_ops && vma->vm_ops->pfn_mkwrite) { + struct vm_fault vmf = { + .page = NULL, + .pgoff = linear_page_index(vma, address), + .virtual_address = (void __user *)(address & PAGE_MASK), + .flags = FAULT_FLAG_WRITE | FAULT_FLAG_MKWRITE, + }; + int ret; + + pte_unmap_unlock(page_table, ptl); + ret = vma->vm_ops->pfn_mkwrite(vma, &vmf); + if (ret & VM_FAULT_ERROR) + return ret; + page_table = pte_offset_map_lock(mm, pmd, address, &ptl); + /* + * We might have raced with another page fault while we + * released the pte_offset_map_lock. + */ + if (!pte_same(*page_table, orig_pte)) { + pte_unmap_unlock(page_table, ptl); + return 0; + } + } + return wp_page_reuse(mm, vma, address, page_table, ptl, orig_pte, + NULL, 0, 0); +} + static int wp_page_shared(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long address, pte_t *page_table, pmd_t *pmd, spinlock_t *ptl, pte_t orig_pte, @@ -2258,13 +2294,12 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma, * VM_PFNMAP VMA. * * We should not cow pages in a shared writeable mapping. - * Just mark the pages writable as we can't do any dirty - * accounting on raw pfn maps. + * Just mark the pages writable and/or call ops->pfn_mkwrite. */ if ((vma->vm_flags & (VM_WRITE|VM_SHARED)) == (VM_WRITE|VM_SHARED)) - return wp_page_reuse(mm, vma, address, page_table, ptl, - orig_pte, old_page, 0, 0); + return wp_pfn_shared(mm, vma, address, page_table, ptl, + orig_pte, pmd); pte_unmap_unlock(page_table, ptl); return wp_page_copy(mm, vma, address, page_table, pmd, -- cgit v1.2.3-59-g8ed1b From 4e3ba87845420e0bfa21e6c4f7f81897aed38f8c Mon Sep 17 00:00:00 2001 From: Minchan Kim Date: Wed, 15 Apr 2015 16:15:36 -0700 Subject: zram: support compaction Now that zsmalloc supports compaction, zram can use it. For the first step, this patch exports compact knob via sysfs so user can do compaction via "echo 1 > /sys/block/zram0/compact". Signed-off-by: Minchan Kim Cc: Juneho Choi Cc: Gunho Lee Cc: Luigi Semenzato Cc: Dan Streetman Cc: Seth Jennings Cc: Nitin Gupta Cc: Jerome Marchand Cc: Sergey Senozhatsky Cc: Joonsoo Kim Cc: Mel Gorman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/ABI/testing/sysfs-block-zram | 15 +++++++++++++++ drivers/block/zram/zram_drv.c | 25 +++++++++++++++++++++++++ drivers/block/zram/zram_drv.h | 1 + 3 files changed, 41 insertions(+) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-block-zram b/Documentation/ABI/testing/sysfs-block-zram index a6148eaf91e5..bede9028a5a0 100644 --- a/Documentation/ABI/testing/sysfs-block-zram +++ b/Documentation/ABI/testing/sysfs-block-zram @@ -141,3 +141,18 @@ Description: amount of memory ZRAM can use to store the compressed data. The limit could be changed in run time and "0" means disable the limit. No limit is the initial state. Unit: bytes + +What: /sys/block/zram/compact +Date: August 2015 +Contact: Minchan Kim +Description: + The compact file is write-only and trigger compaction for + allocator zrm uses. The allocator moves some objects so that + it could free fragment space. + +What: /sys/block/zram/num_migrated +Date: August 2015 +Contact: Minchan Kim +Description: + The compact file is read-only and shows how many object + migrated by compaction. diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index 871bd3550cb0..1626961fdb2f 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -63,6 +63,27 @@ static inline struct zram *dev_to_zram(struct device *dev) return (struct zram *)dev_to_disk(dev)->private_data; } +static ssize_t compact_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + unsigned long nr_migrated; + struct zram *zram = dev_to_zram(dev); + struct zram_meta *meta; + + down_read(&zram->init_lock); + if (!init_done(zram)) { + up_read(&zram->init_lock); + return -EINVAL; + } + + meta = zram->meta; + nr_migrated = zs_compact(meta->mem_pool); + atomic64_add(nr_migrated, &zram->stats.num_migrated); + up_read(&zram->init_lock); + + return len; +} + static ssize_t disksize_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1017,6 +1038,7 @@ static const struct block_device_operations zram_devops = { .owner = THIS_MODULE }; +static DEVICE_ATTR_WO(compact); static DEVICE_ATTR_RW(disksize); static DEVICE_ATTR_RO(initstate); static DEVICE_ATTR_WO(reset); @@ -1035,6 +1057,7 @@ ZRAM_ATTR_RO(invalid_io); ZRAM_ATTR_RO(notify_free); ZRAM_ATTR_RO(zero_pages); ZRAM_ATTR_RO(compr_data_size); +ZRAM_ATTR_RO(num_migrated); static struct attribute *zram_disk_attrs[] = { &dev_attr_disksize.attr, @@ -1044,6 +1067,8 @@ static struct attribute *zram_disk_attrs[] = { &dev_attr_num_writes.attr, &dev_attr_failed_reads.attr, &dev_attr_failed_writes.attr, + &dev_attr_num_migrated.attr, + &dev_attr_compact.attr, &dev_attr_invalid_io.attr, &dev_attr_notify_free.attr, &dev_attr_zero_pages.attr, diff --git a/drivers/block/zram/zram_drv.h b/drivers/block/zram/zram_drv.h index 17056e589146..570c598f4ce9 100644 --- a/drivers/block/zram/zram_drv.h +++ b/drivers/block/zram/zram_drv.h @@ -84,6 +84,7 @@ struct zram_stats { atomic64_t compr_data_size; /* compressed size of pages stored */ atomic64_t num_reads; /* failed + successful */ atomic64_t num_writes; /* --do-- */ + atomic64_t num_migrated; /* no. of migrated object */ atomic64_t failed_reads; /* can happen when memory is too low */ atomic64_t failed_writes; /* can happen when memory is too low */ atomic64_t invalid_io; /* non-page-aligned I/O requests */ -- cgit v1.2.3-59-g8ed1b From d02be50dba649b4246e0c1c4b7cb5d8a8d49de9a Mon Sep 17 00:00:00 2001 From: Minchan Kim Date: Wed, 15 Apr 2015 16:15:46 -0700 Subject: zsmalloc: zsmalloc documentation Create zsmalloc doc which explains design concept and stat information. Signed-off-by: Minchan Kim Cc: Juneho Choi Cc: Gunho Lee Cc: Luigi Semenzato Cc: Dan Streetman Cc: Seth Jennings Cc: Nitin Gupta Cc: Jerome Marchand Cc: Sergey Senozhatsky Cc: Joonsoo Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/vm/zsmalloc.txt | 70 +++++++++++++++++++++++++++++++++++++++++++ MAINTAINERS | 1 + mm/zsmalloc.c | 29 ------------------ 3 files changed, 71 insertions(+), 29 deletions(-) create mode 100644 Documentation/vm/zsmalloc.txt (limited to 'Documentation') diff --git a/Documentation/vm/zsmalloc.txt b/Documentation/vm/zsmalloc.txt new file mode 100644 index 000000000000..64ed63c4f69d --- /dev/null +++ b/Documentation/vm/zsmalloc.txt @@ -0,0 +1,70 @@ +zsmalloc +-------- + +This allocator is designed for use with zram. Thus, the allocator is +supposed to work well under low memory conditions. In particular, it +never attempts higher order page allocation which is very likely to +fail under memory pressure. On the other hand, if we just use single +(0-order) pages, it would suffer from very high fragmentation -- +any object of size PAGE_SIZE/2 or larger would occupy an entire page. +This was one of the major issues with its predecessor (xvmalloc). + +To overcome these issues, zsmalloc allocates a bunch of 0-order pages +and links them together using various 'struct page' fields. These linked +pages act as a single higher-order page i.e. an object can span 0-order +page boundaries. The code refers to these linked pages as a single entity +called zspage. + +For simplicity, zsmalloc can only allocate objects of size up to PAGE_SIZE +since this satisfies the requirements of all its current users (in the +worst case, page is incompressible and is thus stored "as-is" i.e. in +uncompressed form). For allocation requests larger than this size, failure +is returned (see zs_malloc). + +Additionally, zs_malloc() does not return a dereferenceable pointer. +Instead, it returns an opaque handle (unsigned long) which encodes actual +location of the allocated object. The reason for this indirection is that +zsmalloc does not keep zspages permanently mapped since that would cause +issues on 32-bit systems where the VA region for kernel space mappings +is very small. So, before using the allocating memory, the object has to +be mapped using zs_map_object() to get a usable pointer and subsequently +unmapped using zs_unmap_object(). + +stat +---- + +With CONFIG_ZSMALLOC_STAT, we could see zsmalloc internal information via +/sys/kernel/debug/zsmalloc/. Here is a sample of stat output: + +# cat /sys/kernel/debug/zsmalloc/zram0/classes + + class size almost_full almost_empty obj_allocated obj_used pages_used pages_per_zspage + .. + .. + 9 176 0 1 186 129 8 4 + 10 192 1 0 2880 2872 135 3 + 11 208 0 1 819 795 42 2 + 12 224 0 1 219 159 12 4 + .. + .. + + +class: index +size: object size zspage stores +almost_empty: the number of ZS_ALMOST_EMPTY zspages(see below) +almost_full: the number of ZS_ALMOST_FULL zspages(see below) +obj_allocated: the number of objects allocated +obj_used: the number of objects allocated to the user +pages_used: the number of pages allocated for the class +pages_per_zspage: the number of 0-order pages to make a zspage + +We assign a zspage to ZS_ALMOST_EMPTY fullness group when: + n <= N / f, where +n = number of allocated objects +N = total number of objects zspage can store +f = fullness_threshold_frac(ie, 4 at the moment) + +Similarly, we assign zspage to: + ZS_ALMOST_FULL when n > N / f + ZS_EMPTY when n == 0 + ZS_FULL when n == N diff --git a/MAINTAINERS b/MAINTAINERS index 6ee1e79ea16b..190981382853 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10972,6 +10972,7 @@ L: linux-mm@kvack.org S: Maintained F: mm/zsmalloc.c F: include/linux/zsmalloc.h +F: Documentation/vm/zsmalloc.txt ZSWAP COMPRESSED SWAP CACHING M: Seth Jennings diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c index 461243e14d3e..1833fc9e09cb 100644 --- a/mm/zsmalloc.c +++ b/mm/zsmalloc.c @@ -12,35 +12,6 @@ */ /* - * This allocator is designed for use with zram. Thus, the allocator is - * supposed to work well under low memory conditions. In particular, it - * never attempts higher order page allocation which is very likely to - * fail under memory pressure. On the other hand, if we just use single - * (0-order) pages, it would suffer from very high fragmentation -- - * any object of size PAGE_SIZE/2 or larger would occupy an entire page. - * This was one of the major issues with its predecessor (xvmalloc). - * - * To overcome these issues, zsmalloc allocates a bunch of 0-order pages - * and links them together using various 'struct page' fields. These linked - * pages act as a single higher-order page i.e. an object can span 0-order - * page boundaries. The code refers to these linked pages as a single entity - * called zspage. - * - * For simplicity, zsmalloc can only allocate objects of size up to PAGE_SIZE - * since this satisfies the requirements of all its current users (in the - * worst case, page is incompressible and is thus stored "as-is" i.e. in - * uncompressed form). For allocation requests larger than this size, failure - * is returned (see zs_malloc). - * - * Additionally, zs_malloc() does not return a dereferenceable pointer. - * Instead, it returns an opaque handle (unsigned long) which encodes actual - * location of the allocated object. The reason for this indirection is that - * zsmalloc does not keep zspages permanently mapped since that would cause - * issues on 32-bit systems where the VA region for kernel space mappings - * is very small. So, before using the allocating memory, the object has to - * be mapped using zs_map_object() to get a usable pointer and subsequently - * unmapped using zs_unmap_object(). - * * Following is how we use various fields and flags of underlying * struct page(s) to form a zspage. * -- cgit v1.2.3-59-g8ed1b From 10447b60bee52f026bdbc5fe2aca52d0492fc91d Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Wed, 15 Apr 2015 16:15:52 -0700 Subject: zram: remove `num_migrated' device attr This patch introduces rework to zram stats. We have per-stat sysfs nodes, and it makes things a bit hard to use in user space: it doesn't give an immediate stats 'snapshot', it requires user space to use more syscalls - open, read, close for every stat file, with appropriate error checks on every step, etc. First, zram now accounts block layer statistics, available in /sys/block/zram/stat and /proc/diskstats files. So some new stats are available (see Documentation/block/stat.txt), besides, zram's activities now can be monitored by sysstat's iostat or similar tools. Example: cat /sys/block/zram0/stat 248 0 1984 0 251029 0 2008232 5120 0 5116 5116 Second, group currently exported on per-stat basis nodes into two categories (files): -- zram/io_stat accumulates device's IO stats, that are not accounted by block layer, and contains: failed_reads failed_writes invalid_io notify_free Example: cat /sys/block/zram0/io_stat 0 0 0 652572 -- zram/mm_stat accumulates zram mm stats and contains: orig_data_size compr_data_size mem_used_total mem_limit mem_used_max zero_pages num_migrated Example: cat /sys/block/zram0/mm_stat 434634752 270288572 279158784 0 579895296 15060 0 per-stat sysfs nodes are now considered to be deprecated and we plan to remove them (and clean up some of the existing stat code) in two years (as of now, there is no warning printed to syslog about deprecated stats being used). User space is advised to use the above mentioned 3 files. This patch (of 7): Remove sysfs `num_migrated' attribute. We are moving away from per-stat device attrs towards 3 stat files that will accumulate io and mm stats in a format similar to block layer statistics in /sys/block//stat. That will be easier to use in user space, and reduce the number of syscalls needed to read zram device statistics. `num_migrated' will return back in zram/mm_stat file. Signed-off-by: Sergey Senozhatsky Acked-by: Minchan Kim Cc: Nitin Gupta Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/ABI/testing/sysfs-block-zram | 7 ------- drivers/block/zram/zram_drv.c | 2 -- 2 files changed, 9 deletions(-) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-block-zram b/Documentation/ABI/testing/sysfs-block-zram index bede9028a5a0..91ad7071b9e8 100644 --- a/Documentation/ABI/testing/sysfs-block-zram +++ b/Documentation/ABI/testing/sysfs-block-zram @@ -149,10 +149,3 @@ Description: The compact file is write-only and trigger compaction for allocator zrm uses. The allocator moves some objects so that it could free fragment space. - -What: /sys/block/zram/num_migrated -Date: August 2015 -Contact: Minchan Kim -Description: - The compact file is read-only and shows how many object - migrated by compaction. diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index 1626961fdb2f..f416e3ce6392 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -1057,7 +1057,6 @@ ZRAM_ATTR_RO(invalid_io); ZRAM_ATTR_RO(notify_free); ZRAM_ATTR_RO(zero_pages); ZRAM_ATTR_RO(compr_data_size); -ZRAM_ATTR_RO(num_migrated); static struct attribute *zram_disk_attrs[] = { &dev_attr_disksize.attr, @@ -1067,7 +1066,6 @@ static struct attribute *zram_disk_attrs[] = { &dev_attr_num_writes.attr, &dev_attr_failed_reads.attr, &dev_attr_failed_writes.attr, - &dev_attr_num_migrated.attr, &dev_attr_compact.attr, &dev_attr_invalid_io.attr, &dev_attr_notify_free.attr, -- cgit v1.2.3-59-g8ed1b From 77ba015f9d5c584226a634753e9b318cb272cd41 Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Wed, 15 Apr 2015 16:16:00 -0700 Subject: zram: describe device attrs in documentation Briefly describe exported device stat attrs in zram documentation. We will eventually get rid of per-stat sysfs nodes and, thus, clean up Documentation/ABI/testing/sysfs-block-zram file, which is the only source of information about device sysfs nodes. Add `num_migrated' description, since there is no independent `num_migrated' sysfs node (and no corresponding sysfs-block-zram entry), it will be exported via zram/mm_stat file. At this point we can provide minimal description, because sysfs-block-zram still contains detailed information. Signed-off-by: Sergey Senozhatsky Acked-by: Minchan Kim Cc: Nitin Gupta Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/blockdev/zram.txt | 48 +++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 14 deletions(-) (limited to 'Documentation') diff --git a/Documentation/blockdev/zram.txt b/Documentation/blockdev/zram.txt index 7fcf9c6592ec..971765ed5ac1 100644 --- a/Documentation/blockdev/zram.txt +++ b/Documentation/blockdev/zram.txt @@ -98,20 +98,40 @@ size of the disk when not in use so a huge zram is wasteful. mount /dev/zram1 /tmp 7) Stats: - Per-device statistics are exported as various nodes under - /sys/block/zram/ - disksize - num_reads - num_writes - failed_reads - failed_writes - invalid_io - notify_free - zero_pages - orig_data_size - compr_data_size - mem_used_total - mem_used_max +Per-device statistics are exported as various nodes under /sys/block/zram/ + +A brief description of exported device attritbutes. For more details please +read Documentation/ABI/testing/sysfs-block-zram. + +Name access description +---- ------ ----------- +disksize RW show and set the device's disk size +initstate RO shows the initialization state of the device +reset WO trigger device reset +num_reads RO the number of reads +failed_reads RO the number of failed reads +num_write RO the number of writes +failed_writes RO the number of failed writes +invalid_io RO the number of non-page-size-aligned I/O requests +max_comp_streams RW the number of possible concurrent compress operations +comp_algorithm RW show and change the compression algorithm +notify_free RO the number of notifications to free pages (either + slot free notifications or REQ_DISCARD requests) +zero_pages RO the number of zero filled pages written to this disk +orig_data_size RO uncompressed size of data stored in this disk +compr_data_size RO compressed size of data stored in this disk +mem_used_total RO the amount of memory allocated for this disk +mem_used_max RW the maximum amount memory zram have consumed to + store compressed data +mem_limit RW the maximum amount of memory ZRAM can use to store + the compressed data +num_migrated RO the number of objects migrated migrated by compaction + + +File /sys/block/zram/stat + +Represents block layer statistics. Read Documentation/block/stat.txt for +details. 8) Deactivate: swapoff /dev/zram0 -- cgit v1.2.3-59-g8ed1b From 2f6a3bed7347ee94fe57b3501fddaa646a26d890 Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Wed, 15 Apr 2015 16:16:03 -0700 Subject: zram: export new 'io_stat' sysfs attrs Per-device `zram/io_stat' file provides accumulated I/O statistics of particular zram device in a format similar to block layer statistics. The file consists of a single line and represents the following stats (separated by whitespace): failed_reads failed_writes invalid_io notify_free Signed-off-by: Sergey Senozhatsky Acked-by: Minchan Kim Cc: Nitin Gupta Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/ABI/testing/sysfs-block-zram | 9 +++++++++ Documentation/blockdev/zram.txt | 11 +++++++++++ drivers/block/zram/zram_drv.c | 20 ++++++++++++++++++++ 3 files changed, 40 insertions(+) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-block-zram b/Documentation/ABI/testing/sysfs-block-zram index 91ad7071b9e8..a7f622f9bcf6 100644 --- a/Documentation/ABI/testing/sysfs-block-zram +++ b/Documentation/ABI/testing/sysfs-block-zram @@ -149,3 +149,12 @@ Description: The compact file is write-only and trigger compaction for allocator zrm uses. The allocator moves some objects so that it could free fragment space. + +What: /sys/block/zram/io_stat +Date: August 2015 +Contact: Sergey Senozhatsky +Description: + The io_stat file is read-only and accumulates device's I/O + statistics not accounted by block layer. For example, + failed_reads, failed_writes, etc. File format is similar to + block layer statistics file format. diff --git a/Documentation/blockdev/zram.txt b/Documentation/blockdev/zram.txt index 971765ed5ac1..9610be3e9d36 100644 --- a/Documentation/blockdev/zram.txt +++ b/Documentation/blockdev/zram.txt @@ -133,6 +133,17 @@ File /sys/block/zram/stat Represents block layer statistics. Read Documentation/block/stat.txt for details. +File /sys/block/zram/io_stat + +The stat file represents device's I/O statistics not accounted by block +layer and, thus, not available in zram/stat file. It consists of a +single line of text and contains the following stats separated by +whitespace: + failed_reads + failed_writes + invalid_io + notify_free + 8) Deactivate: swapoff /dev/zram0 umount /dev/zram1 diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index 35dafd9a0350..1b63a717bdbb 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -1033,6 +1033,25 @@ static DEVICE_ATTR_RW(mem_used_max); static DEVICE_ATTR_RW(max_comp_streams); static DEVICE_ATTR_RW(comp_algorithm); +static ssize_t io_stat_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct zram *zram = dev_to_zram(dev); + ssize_t ret; + + down_read(&zram->init_lock); + ret = scnprintf(buf, PAGE_SIZE, + "%8llu %8llu %8llu %8llu\n", + (u64)atomic64_read(&zram->stats.failed_reads), + (u64)atomic64_read(&zram->stats.failed_writes), + (u64)atomic64_read(&zram->stats.invalid_io), + (u64)atomic64_read(&zram->stats.notify_free)); + up_read(&zram->init_lock); + + return ret; +} + +static DEVICE_ATTR_RO(io_stat); ZRAM_ATTR_RO(num_reads); ZRAM_ATTR_RO(num_writes); ZRAM_ATTR_RO(failed_reads); @@ -1060,6 +1079,7 @@ static struct attribute *zram_disk_attrs[] = { &dev_attr_mem_used_max.attr, &dev_attr_max_comp_streams.attr, &dev_attr_comp_algorithm.attr, + &dev_attr_io_stat.attr, NULL, }; -- cgit v1.2.3-59-g8ed1b From 4f2109f60881585dc04fa0b5657a60556576625c Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Wed, 15 Apr 2015 16:16:06 -0700 Subject: zram: export new 'mm_stat' sysfs attrs Per-device `zram/mm_stat' file provides mm statistics of a particular zram device in a format similar to block layer statistics. The file consists of a single line and represents the following stats (separated by whitespace): orig_data_size compr_data_size mem_used_total mem_limit mem_used_max zero_pages num_migrated Signed-off-by: Sergey Senozhatsky Acked-by: Minchan Kim Cc: Nitin Gupta Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/ABI/testing/sysfs-block-zram | 8 ++++++++ Documentation/blockdev/zram.txt | 12 ++++++++++++ drivers/block/zram/zram_drv.c | 31 ++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-block-zram b/Documentation/ABI/testing/sysfs-block-zram index a7f622f9bcf6..2e69e83bf510 100644 --- a/Documentation/ABI/testing/sysfs-block-zram +++ b/Documentation/ABI/testing/sysfs-block-zram @@ -158,3 +158,11 @@ Description: statistics not accounted by block layer. For example, failed_reads, failed_writes, etc. File format is similar to block layer statistics file format. + +What: /sys/block/zram/mm_stat +Date: August 2015 +Contact: Sergey Senozhatsky +Description: + The mm_stat file is read-only and represents device's mm + statistics (orig_data_size, compr_data_size, etc.) in a format + similar to block layer statistics file format. diff --git a/Documentation/blockdev/zram.txt b/Documentation/blockdev/zram.txt index 9610be3e9d36..7920f4026d36 100644 --- a/Documentation/blockdev/zram.txt +++ b/Documentation/blockdev/zram.txt @@ -144,6 +144,18 @@ whitespace: invalid_io notify_free +File /sys/block/zram/mm_stat + +The stat file represents device's mm statistics. It consists of a single +line of text and contains the following stats separated by whitespace: + orig_data_size + compr_data_size + mem_used_total + mem_limit + mem_used_max + zero_pages + num_migrated + 8) Deactivate: swapoff /dev/zram0 umount /dev/zram1 diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index 1b63a717bdbb..c94a1a98e301 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -1051,7 +1051,37 @@ static ssize_t io_stat_show(struct device *dev, return ret; } +static ssize_t mm_stat_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct zram *zram = dev_to_zram(dev); + u64 orig_size, mem_used = 0; + long max_used; + ssize_t ret; + + down_read(&zram->init_lock); + if (init_done(zram)) + mem_used = zs_get_total_pages(zram->meta->mem_pool); + + orig_size = atomic64_read(&zram->stats.pages_stored); + max_used = atomic_long_read(&zram->stats.max_used_pages); + + ret = scnprintf(buf, PAGE_SIZE, + "%8llu %8llu %8llu %8lu %8ld %8llu %8llu\n", + orig_size << PAGE_SHIFT, + (u64)atomic64_read(&zram->stats.compr_data_size), + mem_used << PAGE_SHIFT, + zram->limit_pages << PAGE_SHIFT, + max_used << PAGE_SHIFT, + (u64)atomic64_read(&zram->stats.zero_pages), + (u64)atomic64_read(&zram->stats.num_migrated)); + up_read(&zram->init_lock); + + return ret; +} + static DEVICE_ATTR_RO(io_stat); +static DEVICE_ATTR_RO(mm_stat); ZRAM_ATTR_RO(num_reads); ZRAM_ATTR_RO(num_writes); ZRAM_ATTR_RO(failed_reads); @@ -1080,6 +1110,7 @@ static struct attribute *zram_disk_attrs[] = { &dev_attr_max_comp_streams.attr, &dev_attr_comp_algorithm.attr, &dev_attr_io_stat.attr, + &dev_attr_mm_stat.attr, NULL, }; -- cgit v1.2.3-59-g8ed1b From 8f7d282c717acaae25245c61b6b60e8995ec4ef4 Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Wed, 15 Apr 2015 16:16:09 -0700 Subject: zram: deprecate zram attrs sysfs nodes Add Documentation/ABI/obsolete/sysfs-block-zram file and list obsolete and deprecated attributes there. The patch also adds additional information to zram documentation and describes the basic strategy: - the existing RW nodes will be downgraded to WO nodes (in 4.11) - deprecated RO sysfs nodes will eventually be removed (in 4.11) Users will be additionally notified about deprecated attr usage by pr_warn_once() (added to every deprecated attr _show()), as suggested by Minchan Kim. User space is advised to use zram/stat, zram/io_stat and zram/mm_stat files. Signed-off-by: Sergey Senozhatsky Reported-by: Minchan Kim Cc: Nitin Gupta Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/ABI/obsolete/sysfs-block-zram | 119 ++++++++++++++++++++++++++++ Documentation/blockdev/zram.txt | 16 ++++ drivers/block/zram/zram_drv.c | 15 ++++ 3 files changed, 150 insertions(+) create mode 100644 Documentation/ABI/obsolete/sysfs-block-zram (limited to 'Documentation') diff --git a/Documentation/ABI/obsolete/sysfs-block-zram b/Documentation/ABI/obsolete/sysfs-block-zram new file mode 100644 index 000000000000..720ea92cfb2e --- /dev/null +++ b/Documentation/ABI/obsolete/sysfs-block-zram @@ -0,0 +1,119 @@ +What: /sys/block/zram/num_reads +Date: August 2015 +Contact: Sergey Senozhatsky +Description: + The num_reads file is read-only and specifies the number of + reads (failed or successful) done on this device. + Now accessible via zram/stat node. + +What: /sys/block/zram/num_writes +Date: August 2015 +Contact: Sergey Senozhatsky +Description: + The num_writes file is read-only and specifies the number of + writes (failed or successful) done on this device. + Now accessible via zram/stat node. + +What: /sys/block/zram/invalid_io +Date: August 2015 +Contact: Sergey Senozhatsky +Description: + The invalid_io file is read-only and specifies the number of + non-page-size-aligned I/O requests issued to this device. + Now accessible via zram/io_stat node. + +What: /sys/block/zram/failed_reads +Date: August 2015 +Contact: Sergey Senozhatsky +Description: + The failed_reads file is read-only and specifies the number of + failed reads happened on this device. + Now accessible via zram/io_stat node. + +What: /sys/block/zram/failed_writes +Date: August 2015 +Contact: Sergey Senozhatsky +Description: + The failed_writes file is read-only and specifies the number of + failed writes happened on this device. + Now accessible via zram/io_stat node. + +What: /sys/block/zram/notify_free +Date: August 2015 +Contact: Sergey Senozhatsky +Description: + The notify_free file is read-only. Depending on device usage + scenario it may account a) the number of pages freed because + of swap slot free notifications or b) the number of pages freed + because of REQ_DISCARD requests sent by bio. The former ones + are sent to a swap block device when a swap slot is freed, which + implies that this disk is being used as a swap disk. The latter + ones are sent by filesystem mounted with discard option, + whenever some data blocks are getting discarded. + Now accessible via zram/io_stat node. + +What: /sys/block/zram/zero_pages +Date: August 2015 +Contact: Sergey Senozhatsky +Description: + The zero_pages file is read-only and specifies number of zero + filled pages written to this disk. No memory is allocated for + such pages. + Now accessible via zram/mm_stat node. + +What: /sys/block/zram/orig_data_size +Date: August 2015 +Contact: Sergey Senozhatsky +Description: + The orig_data_size file is read-only and specifies uncompressed + size of data stored in this disk. This excludes zero-filled + pages (zero_pages) since no memory is allocated for them. + Unit: bytes + Now accessible via zram/mm_stat node. + +What: /sys/block/zram/compr_data_size +Date: August 2015 +Contact: Sergey Senozhatsky +Description: + The compr_data_size file is read-only and specifies compressed + size of data stored in this disk. So, compression ratio can be + calculated using orig_data_size and this statistic. + Unit: bytes + Now accessible via zram/mm_stat node. + +What: /sys/block/zram/mem_used_total +Date: August 2015 +Contact: Sergey Senozhatsky +Description: + The mem_used_total file is read-only and specifies the amount + of memory, including allocator fragmentation and metadata + overhead, allocated for this disk. So, allocator space + efficiency can be calculated using compr_data_size and this + statistic. + Unit: bytes + Now accessible via zram/mm_stat node. + +What: /sys/block/zram/mem_used_max +Date: August 2015 +Contact: Sergey Senozhatsky +Description: + The mem_used_max file is read/write and specifies the amount + of maximum memory zram have consumed to store compressed data. + For resetting the value, you should write "0". Otherwise, + you could see -EINVAL. + Unit: bytes + Downgraded to write-only node: so it's possible to set new + value only; its current value is stored in zram/mm_stat + node. + +What: /sys/block/zram/mem_limit +Date: August 2015 +Contact: Sergey Senozhatsky +Description: + The mem_limit file is read/write and specifies the maximum + amount of memory ZRAM can use to store the compressed data. + The limit could be changed in run time and "0" means disable + the limit. No limit is the initial state. Unit: bytes + Downgraded to write-only node: so it's possible to set new + value only; its current value is stored in zram/mm_stat + node. diff --git a/Documentation/blockdev/zram.txt b/Documentation/blockdev/zram.txt index 7920f4026d36..48a183e29988 100644 --- a/Documentation/blockdev/zram.txt +++ b/Documentation/blockdev/zram.txt @@ -128,6 +128,22 @@ mem_limit RW the maximum amount of memory ZRAM can use to store num_migrated RO the number of objects migrated migrated by compaction +WARNING +======= +per-stat sysfs attributes are considered to be deprecated. +The basic strategy is: +-- the existing RW nodes will be downgraded to WO nodes (in linux 4.11) +-- deprecated RO sysfs nodes will eventually be removed (in linux 4.11) + +The list of deprecated attributes can be found here: +Documentation/ABI/obsolete/sysfs-block-zram + +Basically, every attribute that has its own read accessible sysfs node +(e.g. num_reads) *AND* is accessible via one of the stat files (zram/stat +or zram/io_stat or zram/mm_stat) is considered to be deprecated. + +User space is advised to use the following files to read the device statistics. + File /sys/block/zram/stat Represents block layer statistics. Read Documentation/block/stat.txt for diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index c94a1a98e301..4491787095a0 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -43,11 +43,22 @@ static const char *default_compressor = "lzo"; /* Module params (documentation at end) */ static unsigned int num_devices = 1; +static inline void deprecated_attr_warn(const char *name) +{ + pr_warn_once("%d (%s) Attribute %s (and others) will be removed. %s\n", + task_pid_nr(current), + current->comm, + name, + "See zram documentation."); +} + #define ZRAM_ATTR_RO(name) \ static ssize_t name##_show(struct device *d, \ struct device_attribute *attr, char *b) \ { \ struct zram *zram = dev_to_zram(d); \ + \ + deprecated_attr_warn(__stringify(name)); \ return scnprintf(b, PAGE_SIZE, "%llu\n", \ (u64)atomic64_read(&zram->stats.name)); \ } \ @@ -89,6 +100,7 @@ static ssize_t orig_data_size_show(struct device *dev, { struct zram *zram = dev_to_zram(dev); + deprecated_attr_warn("orig_data_size"); return scnprintf(buf, PAGE_SIZE, "%llu\n", (u64)(atomic64_read(&zram->stats.pages_stored)) << PAGE_SHIFT); } @@ -99,6 +111,7 @@ static ssize_t mem_used_total_show(struct device *dev, u64 val = 0; struct zram *zram = dev_to_zram(dev); + deprecated_attr_warn("mem_used_total"); down_read(&zram->init_lock); if (init_done(zram)) { struct zram_meta *meta = zram->meta; @@ -128,6 +141,7 @@ static ssize_t mem_limit_show(struct device *dev, u64 val; struct zram *zram = dev_to_zram(dev); + deprecated_attr_warn("mem_limit"); down_read(&zram->init_lock); val = zram->limit_pages; up_read(&zram->init_lock); @@ -159,6 +173,7 @@ static ssize_t mem_used_max_show(struct device *dev, u64 val = 0; struct zram *zram = dev_to_zram(dev); + deprecated_attr_warn("mem_used_max"); down_read(&zram->init_lock); if (init_done(zram)) val = atomic_long_read(&zram->stats.max_used_pages); -- cgit v1.2.3-59-g8ed1b From 7330660ed2e8d8d4c65b90cea62d8f1ed49c0104 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 15 Apr 2015 16:17:14 -0700 Subject: lib/vsprintf: document %p parameters passed by reference This patch series improves the documentation for printk() formats, and adds support for printing clocks. The latter has always been a hassle if you wanted to support both the common and legacy clock frameworks. - '%pC' and '%pCn' print the name (Common Clock Framework) or address (legacy clock framework) of a clock, - '%pCr' prints the current clock rate. This patch (of 3): Make sure all %p extensions that take parameters by references are documented to do so. Signed-off-by: Geert Uytterhoeven Cc: Jonathan Corbet Cc: Mike Turquette Cc: Stephen Boyd Cc: Tetsuo Handa Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/printk-formats.txt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'Documentation') diff --git a/Documentation/printk-formats.txt b/Documentation/printk-formats.txt index 5a615c14f75d..71438f3eb0c0 100644 --- a/Documentation/printk-formats.txt +++ b/Documentation/printk-formats.txt @@ -54,6 +54,7 @@ Struct Resources: For printing struct resources. The 'R' and 'r' specifiers result in a printed resource with ('R') or without ('r') a decoded flags member. + Passed by reference. Physical addresses types phys_addr_t: @@ -132,6 +133,8 @@ MAC/FDDI addresses: specifier to use reversed byte order suitable for visual interpretation of Bluetooth addresses which are in the little endian order. + Passed by reference. + IPv4 addresses: %pI4 1.2.3.4 @@ -146,6 +149,8 @@ IPv4 addresses: host, network, big or little endian order addresses respectively. Where no specifier is provided the default network/big endian order is used. + Passed by reference. + IPv6 addresses: %pI6 0001:0002:0003:0004:0005:0006:0007:0008 @@ -160,6 +165,8 @@ IPv6 addresses: print a compressed IPv6 address as described by http://tools.ietf.org/html/rfc5952 + Passed by reference. + IPv4/IPv6 addresses (generic, with port, flowinfo, scope): %pIS 1.2.3.4 or 0001:0002:0003:0004:0005:0006:0007:0008 @@ -186,6 +193,8 @@ IPv4/IPv6 addresses (generic, with port, flowinfo, scope): specifiers can be used as well and are ignored in case of an IPv6 address. + Passed by reference. + Further examples: %pISfc 1.2.3.4 or [1:2:3:4:5:6:7:8]/123456789 @@ -207,6 +216,8 @@ UUID/GUID addresses: Where no additional specifiers are used the default little endian order with lower case hex characters will be printed. + Passed by reference. + dentry names: %pd{,2,3,4} %pD{,2,3,4} @@ -216,6 +227,8 @@ dentry names: equivalent of %s dentry->d_name.name we used to use, %pd prints n last components. %pD does the same thing for struct file. + Passed by reference. + struct va_format: %pV @@ -231,6 +244,8 @@ struct va_format: Do not use this feature without some mechanism to verify the correctness of the format string and va_list arguments. + Passed by reference. + u64 SHOULD be printed with %llu/%llx: printk("%llu", u64_var); -- cgit v1.2.3-59-g8ed1b From e8a7ba5f5c8c0c94c0c7f1bcd53c0289560c7446 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 15 Apr 2015 16:17:17 -0700 Subject: lib/vsprintf: Move integer format types to the top Move the format types for 64-bit integers and configurable size integers to the top, so they're next to the other integer format types. While at it, add the missing format types for s32 and u32. Signed-off-by: Geert Uytterhoeven Cc: Jonathan Corbet Cc: Mike Turquette Cc: Stephen Boyd Cc: Tetsuo Handa Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/printk-formats.txt | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) (limited to 'Documentation') diff --git a/Documentation/printk-formats.txt b/Documentation/printk-formats.txt index 71438f3eb0c0..56804e40cb18 100644 --- a/Documentation/printk-formats.txt +++ b/Documentation/printk-formats.txt @@ -8,6 +8,21 @@ If variable is of Type, use printk format specifier: unsigned long long %llu or %llx size_t %zu or %zx ssize_t %zd or %zx + s32 %d or %x + u32 %u or %x + s64 %lld or %llx + u64 %llu or %llx + +If is dependent on a config option for its size (e.g., sector_t, +blkcnt_t) or is architecture-dependent for its size (e.g., tcflag_t), use a +format specifier of its largest possible type and explicitly cast to it. +Example: + + printk("test: sector number/total blocks: %llu/%llu\n", + (unsigned long long)sector, (unsigned long long)blockcount); + +Reminder: sizeof() result is of type size_t. + Raw pointer value SHOULD be printed with %p. The kernel supports the following extended format specifiers for pointer types: @@ -246,23 +261,6 @@ struct va_format: Passed by reference. -u64 SHOULD be printed with %llu/%llx: - - printk("%llu", u64_var); - -s64 SHOULD be printed with %lld/%llx: - - printk("%lld", s64_var); - -If is dependent on a config option for its size (e.g., sector_t, -blkcnt_t) or is architecture-dependent for its size (e.g., tcflag_t), use a -format specifier of its largest possible type and explicitly cast to it. -Example: - - printk("test: sector number/total blocks: %llu/%llu\n", - (unsigned long long)sector, (unsigned long long)blockcount); - -Reminder: sizeof() result is of type size_t. Thank you for your cooperation and attention. -- cgit v1.2.3-59-g8ed1b From 900cca2944254edd2d54dc181629314d3177a4af Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 15 Apr 2015 16:17:20 -0700 Subject: lib/vsprintf: add %pC{,n,r} format specifiers for clocks Add format specifiers for printing struct clk: - '%pC' or '%pCn': name (Common Clock Framework) or address (legacy clock framework) of the clock, - '%pCr': rate of the clock. [akpm@linux-foundation.org: omit code if !CONFIG_HAVE_CLK] Signed-off-by: Geert Uytterhoeven Cc: Jonathan Corbet Cc: Mike Turquette Cc: Stephen Boyd Cc: Tetsuo Handa Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/printk-formats.txt | 12 ++++++++++++ lib/vsprintf.c | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) (limited to 'Documentation') diff --git a/Documentation/printk-formats.txt b/Documentation/printk-formats.txt index 56804e40cb18..cb6a596072bb 100644 --- a/Documentation/printk-formats.txt +++ b/Documentation/printk-formats.txt @@ -261,6 +261,18 @@ struct va_format: Passed by reference. +struct clk: + + %pC pll1 + %pCn pll1 + %pCr 1560000000 + + For printing struct clk structures. '%pC' and '%pCn' print the name + (Common Clock Framework) or address (legacy clock framework) of the + structure; '%pCr' prints the current clock rate. + + Passed by reference. + Thank you for your cooperation and attention. diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 2753f9261115..3ab8c9cf3980 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -17,6 +17,7 @@ */ #include +#include #include /* for KSYM_SYMBOL_LEN */ #include #include @@ -1315,6 +1316,30 @@ char *address_val(char *buf, char *end, const void *addr, return number(buf, end, num, spec); } +static noinline_for_stack +char *clock(char *buf, char *end, struct clk *clk, struct printf_spec spec, + const char *fmt) +{ + if (!IS_ENABLED(CONFIG_HAVE_CLK) || !clk) + return string(buf, end, NULL, spec); + + switch (fmt[1]) { + case 'r': + return number(buf, end, clk_get_rate(clk), spec); + + case 'n': + default: +#ifdef CONFIG_COMMON_CLK + return string(buf, end, __clk_get_name(clk), spec); +#else + spec.base = 16; + spec.field_width = sizeof(unsigned long) * 2 + 2; + spec.flags |= SPECIAL | SMALL | ZEROPAD; + return number(buf, end, (unsigned long)clk, spec); +#endif + } +} + int kptr_restrict __read_mostly; /* @@ -1397,6 +1422,11 @@ int kptr_restrict __read_mostly; * (default assumed to be phys_addr_t, passed by reference) * - 'd[234]' For a dentry name (optionally 2-4 last components) * - 'D[234]' Same as 'd' but for a struct file + * - 'C' For a clock, it prints the name (Common Clock Framework) or address + * (legacy clock framework) of the clock + * - 'Cn' For a clock, it prints the name (Common Clock Framework) or address + * (legacy clock framework) of the clock + * - 'Cr' For a clock, it prints the current rate of the clock * * Note: The difference between 'S' and 'F' is that on ia64 and ppc64 * function pointers are really function descriptors, which contain a @@ -1541,6 +1571,8 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr, return address_val(buf, end, ptr, spec, fmt); case 'd': return dentry_name(buf, end, ptr, spec, fmt); + case 'C': + return clock(buf, end, ptr, spec, fmt); case 'D': return dentry_name(buf, end, ((const struct file *)ptr)->f_path.dentry, @@ -1785,6 +1817,11 @@ qualifier: * %*pE[achnops] print an escaped buffer * %*ph[CDN] a variable-length hex string with a separator (supports up to 64 * bytes of the input) + * %pC output the name (Common Clock Framework) or address (legacy clock + * framework) of a clock + * %pCn output the name (Common Clock Framework) or address (legacy clock + * framework) of a clock + * %pCr output the current rate of a clock * %n is ignored * * ** Please update Documentation/printk-formats.txt when making changes ** -- cgit v1.2.3-59-g8ed1b From 13967f0c2abc088c27718319b9a571ccbf43fa89 Mon Sep 17 00:00:00 2001 From: Vince Bridgers Date: Wed, 15 Apr 2015 11:17:38 -0500 Subject: stmmac: Add properties for transmit and receive fifo sizes The Synopsys stmmac fifo sizes are configurable, and need to be known in order to configure certain controller features. This patch adds tx-fifo-depth and rx-fifo-depth properties to the stmmac document file. Signed-off-by: Vince Bridgers Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/ethernet.txt | 6 ++++++ Documentation/devicetree/bindings/net/stmmac.txt | 4 ++++ 2 files changed, 10 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/ethernet.txt b/Documentation/devicetree/bindings/net/ethernet.txt index 3fc360523bc9..41b3f3f864e8 100644 --- a/Documentation/devicetree/bindings/net/ethernet.txt +++ b/Documentation/devicetree/bindings/net/ethernet.txt @@ -19,6 +19,12 @@ The following properties are common to the Ethernet controllers: - phy: the same as "phy-handle" property, not recommended for new bindings. - phy-device: the same as "phy-handle" property, not recommended for new bindings. +- rx-fifo-depth: the size of the controller's receive fifo in bytes. This + is used for components that can have configurable receive fifo sizes, + and is useful for determining certain configuration settings such as + flow control thresholds. +- tx-fifo-depth: the size of the controller's transmit fifo in bytes. This + is used for components that can have configurable fifo sizes. Child nodes of the Ethernet controller are typically the individual PHY devices connected via the MDIO bus (sometimes the MDIO bus controller is separate). diff --git a/Documentation/devicetree/bindings/net/stmmac.txt b/Documentation/devicetree/bindings/net/stmmac.txt index 29aca8591b16..f34fc3c81a75 100644 --- a/Documentation/devicetree/bindings/net/stmmac.txt +++ b/Documentation/devicetree/bindings/net/stmmac.txt @@ -45,6 +45,8 @@ Optional properties: If not passed then the system clock will be used and this is fine on some platforms. - snps,burst_len: The AXI burst lenth value of the AXI BUS MODE register. +- tx-fifo-depth: See ethernet.txt file in the same directory +- rx-fifo-depth: See ethernet.txt file in the same directory Examples: @@ -59,6 +61,8 @@ Examples: phy-mode = "gmii"; snps,multicast-filter-bins = <256>; snps,perfect-filter-entries = <128>; + rx-fifo-depth = <16384>; + tx-fifo-depth = <16384>; clocks = <&clock>; clock-names = "stmmaceth"; }; -- cgit v1.2.3-59-g8ed1b From f2027543b9cb47e1853d8c34fe931e2fcee5cb65 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Thu, 16 Apr 2015 12:43:31 -0700 Subject: documentation: update CodingStyle on local variables naming in macros Describe proper naming convention for local variables in macros resembling functions. Signed-off-by: Bartosz Golaszewski Cc: Guenter Roeck Cc: Steven Rostedt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/CodingStyle | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'Documentation') diff --git a/Documentation/CodingStyle b/Documentation/CodingStyle index 449a8a19fc21..4d4f06d47e06 100644 --- a/Documentation/CodingStyle +++ b/Documentation/CodingStyle @@ -659,6 +659,19 @@ macros using parameters. #define CONSTANT 0x4000 #define CONSTEXP (CONSTANT | 3) +5) namespace collisions when defining local variables in macros resembling +functions: + +#define FOO(x) \ +({ \ + typeof(x) ret; \ + ret = calc_ret(x); \ + (ret); \ +)} + +ret is a common name for a local variable - __foo_ret is less likely +to collide with an existing variable. + The cpp manual deals with macros exhaustively. The gcc internals manual also covers RTL which is used frequently with assembly language in the kernel. -- cgit v1.2.3-59-g8ed1b From 2a076f40d8c9be95bee7bcf18436655e1140447f Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 16 Apr 2015 12:44:28 -0700 Subject: checkpatch, SubmittingPatches: suggest line wrapping commit messages at 75 columns Commit messages lines are sometimes overly long. Suggest line wrapping at 75 columns so the default git commit log indentation of 4 plus the commit message text still fits on an 80 column screen. Add a checkpatch test for long commit messages lines too. Signed-off-by: Joe Perches Cc: David Miller Cc: Jonathan Corbet Cc: Ian Morris Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/SubmittingPatches | 4 ++-- scripts/checkpatch.pl | 9 +++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches index 447671bd2927..b03a832a08e2 100644 --- a/Documentation/SubmittingPatches +++ b/Documentation/SubmittingPatches @@ -614,8 +614,8 @@ The canonical patch message body contains the following: - An empty line. - - The body of the explanation, which will be copied to the - permanent changelog to describe this patch. + - The body of the explanation, line wrapped at 75 columns, which will + be copied to the permanent changelog to describe this patch. - The "Signed-off-by:" lines, described above, which will also go in the changelog. diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index c72e7ee1000b..9a8b2bd14dc2 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -1898,6 +1898,7 @@ sub process { my $in_header_lines = $file ? 0 : 1; my $in_commit_log = 0; #Scanning lines before patch + my $commit_log_long_line = 0; my $reported_maintainer_file = 0; my $non_utf8_charset = 0; @@ -2233,6 +2234,14 @@ sub process { "Remove Gerrit Change-Id's before submitting upstream.\n" . $herecurr); } +# Check for line lengths > 75 in commit log, warn once + if ($in_commit_log && !$commit_log_long_line && + length($line) > 75) { + WARN("COMMIT_LOG_LONG_LINE", + "Possible unwrapped commit description (prefer a maximum 75 chars per line)\n" . $herecurr); + $commit_log_long_line = 1; + } + # Check for git id commit length and improperly formed commit descriptions if ($in_commit_log && $line =~ /\b(c)ommit\s+([0-9a-f]{5,})/i) { my $init_char = $1; -- cgit v1.2.3-59-g8ed1b From 7f48b21bdfede2c06e966258317a3bb4be3e4f25 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Thu, 16 Apr 2015 12:45:04 -0700 Subject: rtc: stmp3xxx: use optional crystal in low power states MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The rtc's status register allows to determine if a 32k crystal is connected to keep the rtc running in low power states provided the corresponding fuse bits were blown correctly during production. (In case they were not, the right frequency can be stated in the device tree.) If there is no such crystal available force the 24 MHz XTAL clock to keep running to retain the right date and time. Otherwise use the crystal to save some power. It would be nice to only switch to the crystal when the XTAL clock is about to be disabled and keep the crystal off when unneeded because XTAL is always on while the chip is powered on. But as sudden power loss isn't detectable this is not save. Signed-off-by: Uwe Kleine-König Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- .../devicetree/bindings/rtc/stmp3xxx-rtc.txt | 5 ++ drivers/rtc/rtc-stmp3xxx.c | 66 ++++++++++++++++++++-- 2 files changed, 65 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/rtc/stmp3xxx-rtc.txt b/Documentation/devicetree/bindings/rtc/stmp3xxx-rtc.txt index b800070fe6e9..fa6a94226669 100644 --- a/Documentation/devicetree/bindings/rtc/stmp3xxx-rtc.txt +++ b/Documentation/devicetree/bindings/rtc/stmp3xxx-rtc.txt @@ -7,6 +7,11 @@ Required properties: region. - interrupts: rtc alarm interrupt +Optional properties: +- stmp,crystal-freq: override crystal frequency as determined from fuse bits. + Only <32000> and <32768> are possible for the hardware. Use <0> for + "no crystal". + Example: rtc@80056000 { diff --git a/drivers/rtc/rtc-stmp3xxx.c b/drivers/rtc/rtc-stmp3xxx.c index 2939cdcb2688..eb09eddf39b8 100644 --- a/drivers/rtc/rtc-stmp3xxx.c +++ b/drivers/rtc/rtc-stmp3xxx.c @@ -42,6 +42,8 @@ #define STMP3XXX_RTC_STAT 0x10 #define STMP3XXX_RTC_STAT_STALE_SHIFT 16 #define STMP3XXX_RTC_STAT_RTC_PRESENT 0x80000000 +#define STMP3XXX_RTC_STAT_XTAL32000_PRESENT 0x10000000 +#define STMP3XXX_RTC_STAT_XTAL32768_PRESENT 0x08000000 #define STMP3XXX_RTC_SECONDS 0x30 @@ -52,9 +54,13 @@ #define STMP3XXX_RTC_PERSISTENT0 0x60 #define STMP3XXX_RTC_PERSISTENT0_SET 0x64 #define STMP3XXX_RTC_PERSISTENT0_CLR 0x68 -#define STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN 0x00000002 -#define STMP3XXX_RTC_PERSISTENT0_ALARM_EN 0x00000004 -#define STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE 0x00000080 +#define STMP3XXX_RTC_PERSISTENT0_CLOCKSOURCE (1 << 0) +#define STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN (1 << 1) +#define STMP3XXX_RTC_PERSISTENT0_ALARM_EN (1 << 2) +#define STMP3XXX_RTC_PERSISTENT0_XTAL24MHZ_PWRUP (1 << 4) +#define STMP3XXX_RTC_PERSISTENT0_XTAL32KHZ_PWRUP (1 << 5) +#define STMP3XXX_RTC_PERSISTENT0_XTAL32_FREQ (1 << 6) +#define STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE (1 << 7) #define STMP3XXX_RTC_PERSISTENT1 0x70 /* missing bitmask in headers */ @@ -248,6 +254,9 @@ static int stmp3xxx_rtc_probe(struct platform_device *pdev) { struct stmp3xxx_rtc_data *rtc_data; struct resource *r; + u32 rtc_stat; + u32 pers0_set, pers0_clr; + u32 crystalfreq = 0; int err; rtc_data = devm_kzalloc(&pdev->dev, sizeof(*rtc_data), GFP_KERNEL); @@ -268,8 +277,8 @@ static int stmp3xxx_rtc_probe(struct platform_device *pdev) rtc_data->irq_alarm = platform_get_irq(pdev, 0); - if (!(readl(STMP3XXX_RTC_STAT + rtc_data->io) & - STMP3XXX_RTC_STAT_RTC_PRESENT)) { + rtc_stat = readl(rtc_data->io + STMP3XXX_RTC_STAT); + if (!(rtc_stat & STMP3XXX_RTC_STAT_RTC_PRESENT)) { dev_err(&pdev->dev, "no device onboard\n"); return -ENODEV; } @@ -282,9 +291,54 @@ static int stmp3xxx_rtc_probe(struct platform_device *pdev) return err; } + /* + * Obviously the rtc needs a clock input to be able to run. + * This clock can be provided by an external 32k crystal. If that one is + * missing XTAL must not be disabled in suspend which consumes a + * lot of power. Normally the presence and exact frequency (supported + * are 32000 Hz and 32768 Hz) is detectable from fuses, but as reality + * proves these fuses are not blown correctly on all machines, so the + * frequency can be overridden in the device tree. + */ + if (rtc_stat & STMP3XXX_RTC_STAT_XTAL32000_PRESENT) + crystalfreq = 32000; + else if (rtc_stat & STMP3XXX_RTC_STAT_XTAL32768_PRESENT) + crystalfreq = 32768; + + of_property_read_u32(pdev->dev.of_node, "stmp,crystal-freq", + &crystalfreq); + + switch (crystalfreq) { + case 32000: + /* keep 32kHz crystal running in low-power mode */ + pers0_set = STMP3XXX_RTC_PERSISTENT0_XTAL32_FREQ | + STMP3XXX_RTC_PERSISTENT0_XTAL32KHZ_PWRUP | + STMP3XXX_RTC_PERSISTENT0_CLOCKSOURCE; + pers0_clr = STMP3XXX_RTC_PERSISTENT0_XTAL24MHZ_PWRUP; + break; + case 32768: + /* keep 32.768kHz crystal running in low-power mode */ + pers0_set = STMP3XXX_RTC_PERSISTENT0_XTAL32KHZ_PWRUP | + STMP3XXX_RTC_PERSISTENT0_CLOCKSOURCE; + pers0_clr = STMP3XXX_RTC_PERSISTENT0_XTAL24MHZ_PWRUP | + STMP3XXX_RTC_PERSISTENT0_XTAL32_FREQ; + break; + default: + dev_warn(&pdev->dev, + "invalid crystal-freq specified in device-tree. Assuming no crystal\n"); + /* fall-through */ + case 0: + /* keep XTAL on in low-power mode */ + pers0_set = STMP3XXX_RTC_PERSISTENT0_XTAL24MHZ_PWRUP; + pers0_clr = STMP3XXX_RTC_PERSISTENT0_XTAL32KHZ_PWRUP | + STMP3XXX_RTC_PERSISTENT0_CLOCKSOURCE; + } + + writel(pers0_set, rtc_data->io + STMP3XXX_RTC_PERSISTENT0_SET); + writel(STMP3XXX_RTC_PERSISTENT0_ALARM_EN | STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN | - STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE, + STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE | pers0_clr, rtc_data->io + STMP3XXX_RTC_PERSISTENT0_CLR); writel(STMP3XXX_RTC_CTRL_ONEMSEC_IRQ_EN | -- cgit v1.2.3-59-g8ed1b From 71b800b628570ce315a3f820b79969e460cd297f Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Thu, 16 Apr 2015 12:45:37 -0700 Subject: rtc: digicolor: document device tree binding Add a device tree binding documentation to the Real Time Clock hardware block on the Conexant CX92755 SoC. The CX92755 is from the Digicolor SoCs series. Other SoCs in that series may share the same hardware block. Signed-off-by: Baruch Siach Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/devicetree/bindings/rtc/digicolor-rtc.txt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 Documentation/devicetree/bindings/rtc/digicolor-rtc.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/rtc/digicolor-rtc.txt b/Documentation/devicetree/bindings/rtc/digicolor-rtc.txt new file mode 100644 index 000000000000..d464986012cd --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/digicolor-rtc.txt @@ -0,0 +1,17 @@ +Conexant Digicolor Real Time Clock controller + +This binding currently supports the CX92755 SoC. + +Required properties: +- compatible: should be "cnxt,cx92755-rtc" +- reg: physical base address of the controller and length of memory mapped + region. +- interrupts: rtc alarm interrupt + +Example: + + rtc@f0000c30 { + compatible = "cnxt,cx92755-rtc"; + reg = <0xf0000c30 0x18>; + interrupts = <25>; + }; -- cgit v1.2.3-59-g8ed1b From 0ec62afeb143a34ce78143cf442f879ef68382f7 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 16 Apr 2015 12:47:53 -0700 Subject: Doc/sysctl/kernel.txt: document threads-max File /proc/sys/kernel/threads-max controls the maximum number of threads that can be created using fork(). [akpm@linux-foundation.org: fix typo, per Guenter] Signed-off-by: Heinrich Schuchardt Cc: Oleg Nesterov Cc: Ingo Molnar Cc: Guenter Roeck Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/sysctl/kernel.txt | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'Documentation') diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt index 99d7eb3a1416..c831001c45f1 100644 --- a/Documentation/sysctl/kernel.txt +++ b/Documentation/sysctl/kernel.txt @@ -872,6 +872,27 @@ can be ORed together: ============================================================== +threads-max + +This value controls the maximum number of threads that can be created +using fork(). + +During initialization the kernel sets this value such that even if the +maximum number of threads is created, the thread structures occupy only +a part (1/8th) of the available RAM pages. + +The minimum value that can be written to threads-max is 20. +The maximum value that can be written to threads-max is given by the +constant FUTEX_TID_MASK (0x3fffffff). +If a value outside of this range is written to threads-max an error +EINVAL occurs. + +The value written is checked against the available RAM pages. If the +thread structures would occupy too much (more than 1/8th) of the +available RAM pages threads-max is reduced accordingly. + +============================================================== + unknown_nmi_panic: The value in this file affects behavior of handling NMI. When the -- cgit v1.2.3-59-g8ed1b From 07eec628ffcea711e14644e14d2c83b4150ba1b7 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 16 Apr 2015 12:49:29 -0700 Subject: Documentation/spi/spidev_test.c: fix warning Documentation/spi/spidev_test.c:83:5: warning: no previous prototype for 'unespcape' [-Wmissing-prototypes] fix spelling too. Acked-by: Mark Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/spi/spidev_test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/spi/spidev_test.c b/Documentation/spi/spidev_test.c index 94f574b0fdb2..135b3f592b83 100644 --- a/Documentation/spi/spidev_test.c +++ b/Documentation/spi/spidev_test.c @@ -80,7 +80,7 @@ static void hex_dump(const void *src, size_t length, size_t line_size, char *pre * Unescape - process hexadecimal escape character * converts shell input "\x23" -> 0x23 */ -int unespcape(char *_dst, char *_src, size_t len) +static int unescape(char *_dst, char *_src, size_t len) { int ret = 0; char *src = _src; @@ -304,7 +304,7 @@ int main(int argc, char *argv[]) size = strlen(input_tx+1); tx = malloc(size); rx = malloc(size); - size = unespcape((char *)tx, input_tx, size); + size = unescape((char *)tx, input_tx, size); transfer(fd, tx, rx, size); free(rx); free(tx); -- cgit v1.2.3-59-g8ed1b From 15eb42d674de8da66950f78b5c7202accabe026e Mon Sep 17 00:00:00 2001 From: Nathan Scott Date: Thu, 16 Apr 2015 12:49:35 -0700 Subject: docs: add missing and new /proc/PID/status file entries, fix typos docs: add missing and new /proc/PID/status file entries, fix typos Signed-off-by: Nathan Scott Signed-off-by: Chen Hanxiao Cc: Serge Hallyn Cc: "Eric W. Biederman" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/filesystems/proc.txt | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt index a07ba61662ed..6d370622fdfe 100644 --- a/Documentation/filesystems/proc.txt +++ b/Documentation/filesystems/proc.txt @@ -200,12 +200,12 @@ contains details information about the process itself. Its fields are explained in Table 1-4. (for SMP CONFIG users) -For making accounting scalable, RSS related information are handled in -asynchronous manner and the vaule may not be very precise. To see a precise +For making accounting scalable, RSS related information are handled in an +asynchronous manner and the value may not be very precise. To see a precise snapshot of a moment, you can see /proc//smaps file and scan page table. It's slow but very precise. -Table 1-2: Contents of the status files (as of 2.6.30-rc7) +Table 1-2: Contents of the status files (as of 3.20.0) .............................................................................. Field Content Name filename of the executable @@ -213,6 +213,7 @@ Table 1-2: Contents of the status files (as of 2.6.30-rc7) in an uninterruptible wait, Z is zombie, T is traced or stopped) Tgid thread group ID + Ngid NUMA group ID (0 if none) Pid process id PPid process id of the parent process TracerPid PID of process tracing this process (0 if not) @@ -220,6 +221,10 @@ Table 1-2: Contents of the status files (as of 2.6.30-rc7) Gid Real, effective, saved set, and file system GIDs FDSize number of file descriptor slots currently allocated Groups supplementary group list + NStgid descendant namespace thread group ID hierarchy + NSpid descendant namespace process ID hierarchy + NSpgid descendant namespace process group ID hierarchy + NSsid descendant namespace session ID hierarchy VmPeak peak virtual memory size VmSize total program size VmLck locked memory size -- cgit v1.2.3-59-g8ed1b From 6c8c90319c0bb1c9e0b68e721359b89ae4f28465 Mon Sep 17 00:00:00 2001 From: Andrey Vagin Date: Thu, 16 Apr 2015 12:49:38 -0700 Subject: proc: show locks in /proc/pid/fdinfo/X Let's show locks which are associated with a file descriptor in its fdinfo file. Currently we don't have a reliable way to determine who holds a lock. We can find some information in /proc/locks, but PID which is reported there can be wrong. For example, a process takes a lock, then forks a child and dies. In this case /proc/locks contains the parent pid, which can be reused by another process. $ cat /proc/locks ... 6: FLOCK ADVISORY WRITE 324 00:13:13431 0 EOF ... $ ps -C rpcbind PID TTY TIME CMD 332 ? 00:00:00 rpcbind $ cat /proc/332/fdinfo/4 pos: 0 flags: 0100000 mnt_id: 22 lock: 1: FLOCK ADVISORY WRITE 324 00:13:13431 0 EOF $ ls -l /proc/332/fd/4 lr-x------ 1 root root 64 Mar 5 14:43 /proc/332/fd/4 -> /run/rpcbind.lock $ ls -l /proc/324/fd/ total 0 lrwx------ 1 root root 64 Feb 27 14:50 0 -> /dev/pts/0 lrwx------ 1 root root 64 Feb 27 14:50 1 -> /dev/pts/0 lrwx------ 1 root root 64 Feb 27 14:49 2 -> /dev/pts/0 You can see that the process with the 324 pid doesn't hold the lock. This information is required for proper dumping and restoring file locks. Signed-off-by: Andrey Vagin Cc: Jonathan Corbet Cc: Alexander Viro Acked-by: Jeff Layton Acked-by: "J. Bruce Fields" Acked-by: Cyrill Gorcunov Cc: Pavel Emelyanov Cc: Joe Perches Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/filesystems/proc.txt | 4 ++++ fs/locks.c | 38 ++++++++++++++++++++++++++++++++++++++ fs/proc/fd.c | 27 +++++++++++++++++---------- include/linux/fs.h | 7 +++++++ 4 files changed, 66 insertions(+), 10 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt index 6d370622fdfe..8e36c7e3c345 100644 --- a/Documentation/filesystems/proc.txt +++ b/Documentation/filesystems/proc.txt @@ -1709,6 +1709,10 @@ A typical output is flags: 0100002 mnt_id: 19 +All locks associated with a file descriptor are shown in its fdinfo too. + +lock: 1: FLOCK ADVISORY WRITE 359 00:13:11691 0 EOF + The files such as eventfd, fsnotify, signalfd, epoll among the regular pos/flags pair provide additional information particular to the objects they represent. diff --git a/fs/locks.c b/fs/locks.c index 52b780fb5258..653faabb07f4 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -2590,6 +2590,44 @@ static int locks_show(struct seq_file *f, void *v) return 0; } +static void __show_fd_locks(struct seq_file *f, + struct list_head *head, int *id, + struct file *filp, struct files_struct *files) +{ + struct file_lock *fl; + + list_for_each_entry(fl, head, fl_list) { + + if (filp != fl->fl_file) + continue; + if (fl->fl_owner != files && + fl->fl_owner != filp) + continue; + + (*id)++; + seq_puts(f, "lock:\t"); + lock_get_status(f, fl, *id, ""); + } +} + +void show_fd_locks(struct seq_file *f, + struct file *filp, struct files_struct *files) +{ + struct inode *inode = file_inode(filp); + struct file_lock_context *ctx; + int id = 0; + + ctx = inode->i_flctx; + if (!ctx) + return; + + spin_lock(&ctx->flc_lock); + __show_fd_locks(f, &ctx->flc_flock, &id, filp, files); + __show_fd_locks(f, &ctx->flc_posix, &id, filp, files); + __show_fd_locks(f, &ctx->flc_lease, &id, filp, files); + spin_unlock(&ctx->flc_lock); +} + static void *locks_start(struct seq_file *f, loff_t *pos) __acquires(&blocked_lock_lock) { diff --git a/fs/proc/fd.c b/fs/proc/fd.c index 8e5ad83b629a..af84ad04df77 100644 --- a/fs/proc/fd.c +++ b/fs/proc/fd.c @@ -8,6 +8,7 @@ #include #include #include +#include #include @@ -48,17 +49,23 @@ static int seq_show(struct seq_file *m, void *v) put_files_struct(files); } - if (!ret) { - seq_printf(m, "pos:\t%lli\nflags:\t0%o\nmnt_id:\t%i\n", - (long long)file->f_pos, f_flags, - real_mount(file->f_path.mnt)->mnt_id); - if (file->f_op->show_fdinfo) - file->f_op->show_fdinfo(m, file); - ret = seq_has_overflowed(m); - fput(file); - } + if (ret) + return ret; - return ret; + seq_printf(m, "pos:\t%lli\nflags:\t0%o\nmnt_id:\t%i\n", + (long long)file->f_pos, f_flags, + real_mount(file->f_path.mnt)->mnt_id); + + show_fd_locks(m, file, files); + if (seq_has_overflowed(m)) + goto out; + + if (file->f_op->show_fdinfo) + file->f_op->show_fdinfo(m, file); + +out: + fput(file); + return 0; } static int seq_fdinfo_open(struct inode *inode, struct file *file) diff --git a/include/linux/fs.h b/include/linux/fs.h index 6bf7ab7c1573..c4e927358503 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1042,6 +1042,9 @@ extern void lease_get_mtime(struct inode *, struct timespec *time); extern int generic_setlease(struct file *, long, struct file_lock **, void **priv); extern int vfs_setlease(struct file *, long, struct file_lock **, void **); extern int lease_modify(struct file_lock *, int, struct list_head *); +struct files_struct; +extern void show_fd_locks(struct seq_file *f, + struct file *filp, struct files_struct *files); #else /* !CONFIG_FILE_LOCKING */ static inline int fcntl_getlk(struct file *file, unsigned int cmd, struct flock __user *user) @@ -1178,6 +1181,10 @@ static inline int lease_modify(struct file_lock *fl, int arg, { return -EINVAL; } + +struct files_struct; +static inline void show_fd_locks(struct seq_file *f, + struct file *filp, struct files_struct *files) {} #endif /* !CONFIG_FILE_LOCKING */ -- cgit v1.2.3-59-g8ed1b