From 4c21bbb475c16be9ec878e8753d5e8373f9b9d59 Mon Sep 17 00:00:00 2001 From: Heiko Stübner Date: Mon, 15 Sep 2014 22:47:00 +0100 Subject: iio: adc: rockchip_saradc: add support for rk3066-tsadc variant Older Rockchip SoCs, at least the rk3066, used a slightly modified saradc for temperature measurements. This so called tsadc does not contain any active parts like temperature interrupts and only supports polling the current temperature. The returned voltage can then be converted by a suitable thermal driver to and actual temperature and used for thermal handling. Signed-off-by: Heiko Stuebner Acked-by: Hartmut Knaack Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/adc/rockchip-saradc.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/iio/adc/rockchip-saradc.txt b/Documentation/devicetree/bindings/iio/adc/rockchip-saradc.txt index 5d3ec1df226d..a9a5fe19ff2a 100644 --- a/Documentation/devicetree/bindings/iio/adc/rockchip-saradc.txt +++ b/Documentation/devicetree/bindings/iio/adc/rockchip-saradc.txt @@ -1,7 +1,7 @@ Rockchip Successive Approximation Register (SAR) A/D Converter bindings Required properties: -- compatible: Should be "rockchip,saradc" +- compatible: Should be "rockchip,saradc" or "rockchip,rk3066-tsadc" - reg: physical base address of the controller and length of memory mapped region. - interrupts: The interrupt number to the cpu. The interrupt specifier format -- cgit v1.2.3-59-g8ed1b From c20d4dffd537bee8d3db5ec28ca871ef73d44078 Mon Sep 17 00:00:00 2001 From: Jacob Pan Date: Wed, 17 Sep 2014 01:11:00 +0100 Subject: iio: add documentation for current attribute Add documentation for input current raw sysfs attribute. Signed-off-by: Jacob Pan Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index d760b0224ef7..1ac9ac20f530 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -1028,3 +1028,12 @@ Contact: linux-iio@vger.kernel.org Description: Raw value of rotation from true/magnetic north measured with or without compensation from tilt sensors. + +What: /sys/bus/iio/devices/iio:deviceX/in_currentX_raw +KernelVersion: 3.18 +Contact: linux-iio@vger.kernel.org +Description: + Raw current measurement from channel X. Units are in milliamps + after application of scale and offset. If no offset or scale is + present, output should be considered as processed with the + unit in milliamps. -- cgit v1.2.3-59-g8ed1b From c2426d2ad5027397342107b7ff094aa9b234acb8 Mon Sep 17 00:00:00 2001 From: Roberto Sassu Date: Mon, 13 Oct 2014 14:08:42 +0200 Subject: ima: added support for new kernel cmdline parameter ima_template_fmt This patch allows users to provide a custom template format through the new kernel command line parameter 'ima_template_fmt'. If the supplied format is not valid, IMA uses the default template descriptor. Changelog: - v3: - added check for 'fields' and 'num_fields' in template_desc_init_fields() (suggested by Mimi Zohar) - v2: - using template_desc_init_fields() to validate a format string (Roberto Sassu) - updated documentation by stating that only the chosen template descriptor is initialized (Roberto Sassu) - v1: - simplified code of ima_template_fmt_setup() (Roberto Sassu, suggested by Mimi Zohar) Signed-off-by: Roberto Sassu Signed-off-by: Mimi Zohar --- Documentation/kernel-parameters.txt | 4 ++++ Documentation/security/IMA-templates.txt | 29 ++++++++++++------------ security/integrity/ima/ima_template.c | 39 ++++++++++++++++++++++++++++---- 3 files changed, 52 insertions(+), 20 deletions(-) (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 802a3fd9e485..06b2cd5739dd 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1318,6 +1318,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted. Formats: { "ima" | "ima-ng" } Default: "ima-ng" + ima_template_fmt= + [IMA] Define a custom template format. + Format: { "field1|...|fieldN" } + ima.ahash_minsize= [IMA] Minimum file size for asynchronous hash usage Format: Set the minimal file size for using asynchronous hash. diff --git a/Documentation/security/IMA-templates.txt b/Documentation/security/IMA-templates.txt index a4e102dddfea..839b5dad9226 100644 --- a/Documentation/security/IMA-templates.txt +++ b/Documentation/security/IMA-templates.txt @@ -27,25 +27,22 @@ Managing templates with these structures is very simple. To support a new data type, developers define the field identifier and implement two functions, init() and show(), respectively to generate and display measurement entries. Defining a new template descriptor requires -specifying the template format, a string of field identifiers separated -by the '|' character. While in the current implementation it is possible -to define new template descriptors only by adding their definition in the -template specific code (ima_template.c), in a future version it will be -possible to register a new template on a running kernel by supplying to IMA -the desired format string. In this version, IMA initializes at boot time -all defined template descriptors by translating the format into an array -of template fields structures taken from the set of the supported ones. +specifying the template format (a string of field identifiers separated +by the '|' character) through the 'ima_template_fmt' kernel command line +parameter. At boot time, IMA initializes the chosen template descriptor +by translating the format into an array of template fields structures taken +from the set of the supported ones. After the initialization step, IMA will call ima_alloc_init_template() (new function defined within the patches for the new template management mechanism) to generate a new measurement entry by using the template descriptor chosen through the kernel configuration or through the newly -introduced 'ima_template=' kernel command line parameter. It is during this -phase that the advantages of the new architecture are clearly shown: -the latter function will not contain specific code to handle a given template -but, instead, it simply calls the init() method of the template fields -associated to the chosen template descriptor and store the result (pointer -to allocated data and data length) in the measurement entry structure. +introduced 'ima_template' and 'ima_template_fmt' kernel command line parameters. +It is during this phase that the advantages of the new architecture are +clearly shown: the latter function will not contain specific code to handle +a given template but, instead, it simply calls the init() method of the template +fields associated to the chosen template descriptor and store the result +(pointer to allocated data and data length) in the measurement entry structure. The same mechanism is employed to display measurements entries. The functions ima[_ascii]_measurements_show() retrieve, for each entry, @@ -86,4 +83,6 @@ currently the following methods are supported: - select a template descriptor among those supported in the kernel configuration ('ima-ng' is the default choice); - specify a template descriptor name from the kernel command line through - the 'ima_template=' parameter. + the 'ima_template=' parameter; + - register a new template descriptor with custom format through the kernel + command line parameter 'ima_template_fmt='. diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c index 65117ba06809..0b7404ebfa80 100644 --- a/security/integrity/ima/ima_template.c +++ b/security/integrity/ima/ima_template.c @@ -24,6 +24,7 @@ static struct ima_template_desc defined_templates[] = { {.name = IMA_TEMPLATE_IMA_NAME, .fmt = IMA_TEMPLATE_IMA_FMT}, {.name = "ima-ng", .fmt = "d-ng|n-ng"}, {.name = "ima-sig", .fmt = "d-ng|n-ng|sig"}, + {.name = "", .fmt = ""}, /* placeholder for a custom format */ }; static struct ima_template_field supported_fields[] = { @@ -41,12 +42,18 @@ static struct ima_template_field supported_fields[] = { static struct ima_template_desc *ima_template; static struct ima_template_desc *lookup_template_desc(const char *name); +static int template_desc_init_fields(const char *template_fmt, + struct ima_template_field ***fields, + int *num_fields); static int __init ima_template_setup(char *str) { struct ima_template_desc *template_desc; int template_len = strlen(str); + if (ima_template) + return 1; + /* * Verify that a template with the supplied name exists. * If not, use CONFIG_IMA_DEFAULT_TEMPLATE. @@ -73,6 +80,25 @@ static int __init ima_template_setup(char *str) } __setup("ima_template=", ima_template_setup); +static int __init ima_template_fmt_setup(char *str) +{ + int num_templates = ARRAY_SIZE(defined_templates); + + if (ima_template) + return 1; + + if (template_desc_init_fields(str, NULL, NULL) < 0) { + pr_err("format string '%s' not valid, using template %s\n", + str, CONFIG_IMA_DEFAULT_TEMPLATE); + return 1; + } + + defined_templates[num_templates - 1].fmt = str; + ima_template = defined_templates + num_templates - 1; + return 1; +} +__setup("ima_template_fmt=", ima_template_fmt_setup); + static struct ima_template_desc *lookup_template_desc(const char *name) { int i; @@ -146,12 +172,15 @@ static int template_desc_init_fields(const char *template_fmt, } } - *fields = kmalloc_array(i, sizeof(*fields), GFP_KERNEL); - if (*fields == NULL) - return -ENOMEM; + if (fields && num_fields) { + *fields = kmalloc_array(i, sizeof(*fields), GFP_KERNEL); + if (*fields == NULL) + return -ENOMEM; + + memcpy(*fields, found_fields, i * sizeof(*fields)); + *num_fields = i; + } - memcpy(*fields, found_fields, i * sizeof(*fields)); - *num_fields = i; return 0; } -- cgit v1.2.3-59-g8ed1b From 836a24183273e9db1c092246bd8e306b297d9917 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 2 Jul 2014 02:01:15 -0500 Subject: ARM: expand fixmap region to 3MB With commit a05e54c103b0 ("ARM: 8031/2: change fixmap mapping region to support 32 CPUs"), the fixmap region was expanded to 2MB, but it precluded any other uses of the fixmap region. In order to support other uses the fixmap region needs to be expanded beyond 2MB. Fortunately, the adjacent 1MB range 0xffe00000-0xfff00000 is availabe. Remove fixmap_page_table ptr and lookup the page table via the virtual address so that the fixmap region can span more that one pmd. The 2nd pmd is already created since it is shared with the vector page. Signed-off-by: Rob Herring [kees: fixed CONFIG_DEBUG_HIGHMEM get_fixmap() calls] [kees: moved pte allocation outside of CONFIG_HIGHMEM] Signed-off-by: Kees Cook Acked-by: Nicolas Pitre --- Documentation/arm/memory.txt | 2 +- arch/arm/include/asm/fixmap.h | 2 +- arch/arm/mm/highmem.c | 15 ++++++++------- arch/arm/mm/mmu.c | 6 +++--- 4 files changed, 13 insertions(+), 12 deletions(-) (limited to 'Documentation') diff --git a/Documentation/arm/memory.txt b/Documentation/arm/memory.txt index 38dc06d0a791..4178ebda6e66 100644 --- a/Documentation/arm/memory.txt +++ b/Documentation/arm/memory.txt @@ -41,7 +41,7 @@ fffe8000 fffeffff DTCM mapping area for platforms with fffe0000 fffe7fff ITCM mapping area for platforms with ITCM mounted inside the CPU. -ffc00000 ffdfffff Fixmap mapping region. Addresses provided +ffc00000 ffefffff Fixmap mapping region. Addresses provided by fix_to_virt() will be located here. fee00000 feffffff Mapping of PCI I/O space. This is a static diff --git a/arch/arm/include/asm/fixmap.h b/arch/arm/include/asm/fixmap.h index a7add6f9315d..d984ca69ce19 100644 --- a/arch/arm/include/asm/fixmap.h +++ b/arch/arm/include/asm/fixmap.h @@ -2,7 +2,7 @@ #define _ASM_FIXMAP_H #define FIXADDR_START 0xffc00000UL -#define FIXADDR_END 0xffe00000UL +#define FIXADDR_END 0xfff00000UL #define FIXADDR_TOP (FIXADDR_END - PAGE_SIZE) #include diff --git a/arch/arm/mm/highmem.c b/arch/arm/mm/highmem.c index 45aeaaca9052..81061987ac45 100644 --- a/arch/arm/mm/highmem.c +++ b/arch/arm/mm/highmem.c @@ -18,19 +18,20 @@ #include #include "mm.h" -pte_t *fixmap_page_table; - static inline void set_fixmap_pte(int idx, pte_t pte) { unsigned long vaddr = __fix_to_virt(idx); - set_pte_ext(fixmap_page_table + idx, pte, 0); + pte_t *ptep = pte_offset_kernel(pmd_off_k(vaddr), vaddr); + + set_pte_ext(ptep, pte, 0); local_flush_tlb_kernel_page(vaddr); } static inline pte_t get_fixmap_pte(unsigned long vaddr) { - unsigned long idx = __virt_to_fix(vaddr); - return *(fixmap_page_table + idx); + pte_t *ptep = pte_offset_kernel(pmd_off_k(vaddr), vaddr); + + return *ptep; } void *kmap(struct page *page) @@ -84,7 +85,7 @@ void *kmap_atomic(struct page *page) * With debugging enabled, kunmap_atomic forces that entry to 0. * Make sure it was indeed properly unmapped. */ - BUG_ON(!pte_none(*(fixmap_page_table + idx))); + BUG_ON(!pte_none(get_fixmap_pte(vaddr))); #endif /* * When debugging is off, kunmap_atomic leaves the previous mapping @@ -134,7 +135,7 @@ void *kmap_atomic_pfn(unsigned long pfn) idx = type + KM_TYPE_NR * smp_processor_id(); vaddr = __fix_to_virt(idx); #ifdef CONFIG_DEBUG_HIGHMEM - BUG_ON(!pte_none(*(fixmap_page_table + idx))); + BUG_ON(!pte_none(get_fixmap_pte(vaddr))); #endif set_fixmap_pte(idx, pfn_pte(pfn, kmap_prot)); diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index 8348ed6b2efe..7fa0966cd15f 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -1326,10 +1326,10 @@ static void __init kmap_init(void) #ifdef CONFIG_HIGHMEM pkmap_page_table = early_pte_alloc(pmd_off_k(PKMAP_BASE), PKMAP_BASE, _PAGE_KERNEL_TABLE); - - fixmap_page_table = early_pte_alloc(pmd_off_k(FIXADDR_START), - FIXADDR_START, _PAGE_KERNEL_TABLE); #endif + + early_pte_alloc(pmd_off_k(FIXADDR_START), FIXADDR_START, + _PAGE_KERNEL_TABLE); } static void __init map_lowmem(void) -- cgit v1.2.3-59-g8ed1b From 4944d2cac6de0aec02032bdda45668c932bb6732 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 30 Sep 2014 12:29:19 +0200 Subject: pinctrl: abx500: update device tree bindings After force converting the ABx500 bindings in the driver and device tree sources, also update the binding documentation to state that we are now using standard bindings. Signed-off-by: Linus Walleij --- .../devicetree/bindings/pinctrl/ste,abx500.txt | 184 +++++++++------------ 1 file changed, 75 insertions(+), 109 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/pinctrl/ste,abx500.txt b/Documentation/devicetree/bindings/pinctrl/ste,abx500.txt index e3865e136067..87697420439e 100644 --- a/Documentation/devicetree/bindings/pinctrl/ste,abx500.txt +++ b/Documentation/devicetree/bindings/pinctrl/ste,abx500.txt @@ -8,42 +8,8 @@ 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". -ST Ericsson'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 input, output, pull up, pull down... - -The name of each subnode is not important; all subnodes should be enumerated -and processed purely based on their content. - -Required subnode-properties: -- ste,pins : An array of strings. Each string contains the name of a pin or - group. - -Optional subnode-properties: -- ste,function: A string containing the name of the function to mux to the - pin or group. - -- generic pin configuration option to use. Example : - - default_cfg { - ste,pins = "GPIO1"; - bias-disable; - }; - -- ste,config: Handle of pin configuration node containing the generic - pinconfig options to use, as described in pinctrl-bindings.txt in - this directory. Example : - - pcfg_bias_disable: pcfg_bias_disable { - bias-disable; - }; - - default_cfg { - ste,pins = "GPIO1"; - ste.config = <&pcfg_bias_disable>; - }; +ST Ericsson's pin configuration nodes use the generic pin multiplexing +and pin configuration bindings, see pinctrl-bindings.txt Example board file extract: @@ -54,11 +20,11 @@ Example board file extract: sysclkreq2 { sysclkreq2_default_mode: sysclkreq2_default { default_mux { - ste,function = "sysclkreq"; - ste,pins = "sysclkreq2_d_1"; + function = "sysclkreq"; + groups = "sysclkreq2_d_1"; }; default_cfg { - ste,pins = "GPIO1"; + pins = "GPIO1"; bias-disable; }; }; @@ -66,11 +32,11 @@ Example board file extract: sysclkreq3 { sysclkreq3_default_mode: sysclkreq3_default { default_mux { - ste,function = "sysclkreq"; - ste,pins = "sysclkreq3_d_1"; + function = "sysclkreq"; + groups = "sysclkreq3_d_1"; }; default_cfg { - ste,pins = "GPIO2"; + pins = "GPIO2"; output-low; }; }; @@ -78,11 +44,11 @@ Example board file extract: gpio3 { gpio3_default_mode: gpio3_default { default_mux { - ste,function = "gpio"; - ste,pins = "gpio3_a_1"; + function = "gpio"; + groups = "gpio3_a_1"; }; default_cfg { - ste,pins = "GPIO3"; + pins = "GPIO3"; output-low; }; }; @@ -90,11 +56,11 @@ Example board file extract: sysclkreq6 { sysclkreq6_default_mode: sysclkreq6_default { default_mux { - ste,function = "sysclkreq"; - ste,pins = "sysclkreq6_d_1"; + function = "sysclkreq"; + groups = "sysclkreq6_d_1"; }; default_cfg { - ste,pins = "GPIO4"; + pins = "GPIO4"; bias-disable; }; }; @@ -102,11 +68,11 @@ Example board file extract: pwmout1 { pwmout1_default_mode: pwmout1_default { default_mux { - ste,function = "pwmout"; - ste,pins = "pwmout1_d_1"; + function = "pwmout"; + groups = "pwmout1_d_1"; }; default_cfg { - ste,pins = "GPIO14"; + pins = "GPIO14"; output-low; }; }; @@ -114,11 +80,11 @@ Example board file extract: pwmout2 { pwmout2_default_mode: pwmout2_default { pwmout2_default_mux { - ste,function = "pwmout"; - ste,pins = "pwmout2_d_1"; + function = "pwmout"; + groups = "pwmout2_d_1"; }; pwmout2_default_cfg { - ste,pins = "GPIO15"; + pins = "GPIO15"; output-low; }; }; @@ -126,11 +92,11 @@ Example board file extract: pwmout3 { pwmout3_default_mode: pwmout3_default { pwmout3_default_mux { - ste,function = "pwmout"; - ste,pins = "pwmout3_d_1"; + function = "pwmout"; + groups = "pwmout3_d_1"; }; pwmout3_default_cfg { - ste,pins = "GPIO16"; + pins = "GPIO16"; output-low; }; }; @@ -139,15 +105,15 @@ Example board file extract: adi1_default_mode: adi1_default { adi1_default_mux { - ste,function = "adi1"; - ste,pins = "adi1_d_1"; + function = "adi1"; + groups = "adi1_d_1"; }; adi1_default_cfg1 { - ste,pins = "GPIO17","GPIO19","GPIO20"; + pins = "GPIO17","GPIO19","GPIO20"; bias-disable; }; adi1_default_cfg2 { - ste,pins = "GPIO18"; + pins = "GPIO18"; output-low; }; }; @@ -155,15 +121,15 @@ Example board file extract: dmic12 { dmic12_default_mode: dmic12_default { dmic12_default_mux { - ste,function = "dmic"; - ste,pins = "dmic12_d_1"; + function = "dmic"; + groups = "dmic12_d_1"; }; dmic12_default_cfg1 { - ste,pins = "GPIO27"; + pins = "GPIO27"; output-low; }; dmic12_default_cfg2 { - ste,pins = "GPIO28"; + pins = "GPIO28"; bias-disable; }; }; @@ -171,15 +137,15 @@ Example board file extract: dmic34 { dmic34_default_mode: dmic34_default { dmic34_default_mux { - ste,function = "dmic"; - ste,pins = "dmic34_d_1"; + function = "dmic"; + groups = "dmic34_d_1"; }; dmic34_default_cfg1 { - ste,pins = "GPIO29"; + pins = "GPIO29"; output-low; }; dmic34_default_cfg2 { - ste,pins = "GPIO30"; + pins = "GPIO30"; bias-disable;{ }; @@ -188,15 +154,15 @@ Example board file extract: dmic56 { dmic56_default_mode: dmic56_default { dmic56_default_mux { - ste,function = "dmic"; - ste,pins = "dmic56_d_1"; + function = "dmic"; + groups = "dmic56_d_1"; }; dmic56_default_cfg1 { - ste,pins = "GPIO31"; + pins = "GPIO31"; output-low; }; dmic56_default_cfg2 { - ste,pins = "GPIO32"; + pins = "GPIO32"; bias-disable; }; }; @@ -204,11 +170,11 @@ Example board file extract: sysclkreq5 { sysclkreq5_default_mode: sysclkreq5_default { sysclkreq5_default_mux { - ste,function = "sysclkreq"; - ste,pins = "sysclkreq5_d_1"; + function = "sysclkreq"; + groups = "sysclkreq5_d_1"; }; sysclkreq5_default_cfg { - ste,pins = "GPIO42"; + pins = "GPIO42"; output-low; }; }; @@ -216,11 +182,11 @@ Example board file extract: batremn { batremn_default_mode: batremn_default { batremn_default_mux { - ste,function = "batremn"; - ste,pins = "batremn_d_1"; + function = "batremn"; + groups = "batremn_d_1"; }; batremn_default_cfg { - ste,pins = "GPIO43"; + pins = "GPIO43"; bias-disable; }; }; @@ -228,11 +194,11 @@ Example board file extract: service { service_default_mode: service_default { service_default_mux { - ste,function = "service"; - ste,pins = "service_d_1"; + function = "service"; + groups = "service_d_1"; }; service_default_cfg { - ste,pins = "GPIO44"; + pins = "GPIO44"; bias-disable; }; }; @@ -240,13 +206,13 @@ Example board file extract: pwrctrl0 { pwrctrl0_default_mux: pwrctrl0_mux { pwrctrl0_default_mux { - ste,function = "pwrctrl"; - ste,pins = "pwrctrl0_d_1"; + function = "pwrctrl"; + groups = "pwrctrl0_d_1"; }; }; pwrctrl0_default_mode: pwrctrl0_default { pwrctrl0_default_cfg { - ste,pins = "GPIO45"; + pins = "GPIO45"; bias-disable; }; }; @@ -254,13 +220,13 @@ Example board file extract: pwrctrl1 { pwrctrl1_default_mux: pwrctrl1_mux { pwrctrl1_default_mux { - ste,function = "pwrctrl"; - ste,pins = "pwrctrl1_d_1"; + function = "pwrctrl"; + groups = "pwrctrl1_d_1"; }; }; pwrctrl1_default_mode: pwrctrl1_default { pwrctrl1_default_cfg { - ste,pins = "GPIO46"; + pins = "GPIO46"; bias-disable; }; }; @@ -268,11 +234,11 @@ Example board file extract: pwmextvibra1 { pwmextvibra1_default_mode: pwmextvibra1_default { pwmextvibra1_default_mux { - ste,function = "pwmextvibra"; - ste,pins = "pwmextvibra1_d_1"; + function = "pwmextvibra"; + groups = "pwmextvibra1_d_1"; }; pwmextvibra1_default_cfg { - ste,pins = "GPIO47"; + pins = "GPIO47"; bias-disable; }; }; @@ -280,11 +246,11 @@ Example board file extract: pwmextvibra2 { pwmextvibra2_default_mode: pwmextvibra2_default { pwmextvibra2_default_mux { - ste,function = "pwmextvibra"; - ste,pins = "pwmextvibra2_d_1"; + function = "pwmextvibra"; + groups = "pwmextvibra2_d_1"; }; pwmextvibra1_default_cfg { - ste,pins = "GPIO48"; + pins = "GPIO48"; bias-disable; }; }; @@ -292,11 +258,11 @@ Example board file extract: gpio51 { gpio51_default_mode: gpio51_default { gpio51_default_mux { - ste,function = "gpio"; - ste,pins = "gpio51_a_1"; + function = "gpio"; + groups = "gpio51_a_1"; }; gpio51_default_cfg { - ste,pins = "GPIO51"; + pins = "GPIO51"; output-low; }; }; @@ -304,11 +270,11 @@ Example board file extract: gpio52 { gpio52_default_mode: gpio52_default { gpio52_default_mux { - ste,function = "gpio"; - ste,pins = "gpio52_a_1"; + function = "gpio"; + groups = "gpio52_a_1"; }; gpio52_default_cfg { - ste,pins = "GPIO52"; + pins = "GPIO52"; bias-pull-down; }; }; @@ -316,11 +282,11 @@ Example board file extract: gpio53 { gpio53_default_mode: gpio53_default { gpio53_default_mux { - ste,function = "gpio"; - ste,pins = "gpio53_a_1"; + function = "gpio"; + groups = "gpio53_a_1"; }; gpio53_default_cfg { - ste,pins = "GPIO53"; + pins = "GPIO53"; bias-pull-down; }; }; @@ -328,11 +294,11 @@ Example board file extract: gpio54 { gpio54_default_mode: gpio54_default { gpio54_default_mux { - ste,function = "gpio"; - ste,pins = "gpio54_a_1"; + function = "gpio"; + groups = "gpio54_a_1"; }; gpio54_default_cfg { - ste,pins = "GPIO54"; + pins = "GPIO54"; output-low; }; }; @@ -340,11 +306,11 @@ Example board file extract: pdmclkdat { pdmclkdat_default_mode: pdmclkdat_default { pdmclkdat_default_mux { - ste,function = "pdm"; - ste,pins = "pdmclkdat_d_1"; + function = "pdm"; + groups = "pdmclkdat_d_1"; }; pdmclkdat_default_cfg { - ste,pins = "GPIO55", "GPIO56"; + pins = "GPIO55", "GPIO56"; bias-disable; }; }; -- cgit v1.2.3-59-g8ed1b From 73a2cd9193ae50d4cc7c447f8929e13010b589be Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Tue, 7 Oct 2014 12:29:04 -0700 Subject: ASoC: fsl_esai: Add indentation for binding doc to increase readability This patch simply adds indentations for DT binding doc to increase readability without changing any contents. Signed-off-by: Nicolin Chen Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/fsl,esai.txt | 44 +++++++++++----------- 1 file changed, 23 insertions(+), 21 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/fsl,esai.txt b/Documentation/devicetree/bindings/sound/fsl,esai.txt index 52f5b6bf3e8e..d3b6b5f48010 100644 --- a/Documentation/devicetree/bindings/sound/fsl,esai.txt +++ b/Documentation/devicetree/bindings/sound/fsl,esai.txt @@ -7,37 +7,39 @@ other DSPs. It has up to six transmitters and four receivers. Required properties: - - compatible : Compatible list, must contain "fsl,imx35-esai" or - "fsl,vf610-esai" + - compatible : Compatible list, must contain "fsl,imx35-esai" or + "fsl,vf610-esai" - - reg : Offset and length of the register set for the device. + - reg : Offset and length of the register set for the device. - - interrupts : Contains the spdif interrupt. + - interrupts : Contains the spdif interrupt. - - dmas : Generic dma devicetree binding as described in - Documentation/devicetree/bindings/dma/dma.txt. + - dmas : Generic dma devicetree binding as described in + Documentation/devicetree/bindings/dma/dma.txt. - - dma-names : Two dmas have to be defined, "tx" and "rx". + - dma-names : Two dmas have to be defined, "tx" and "rx". - - clocks: Contains an entry for each entry in clock-names. + - clocks : Contains an entry for each entry in clock-names. - - clock-names : Includes the following entries: - "core" The core clock used to access registers - "extal" The esai baud clock for esai controller used to derive - HCK, SCK and FS. - "fsys" The system clock derived from ahb clock used to derive - HCK, SCK and FS. + - clock-names : Includes the following entries: + "core" The core clock used to access registers + "extal" The esai baud clock for esai controller used to + derive HCK, SCK and FS. + "fsys" The system clock derived from ahb clock used to + derive HCK, SCK and FS. - - fsl,fifo-depth: The number of elements in the transmit and receive FIFOs. - This number is the maximum allowed value for TFCR[TFWM] or RFCR[RFWM]. + - fsl,fifo-depth : The number of elements in the transmit and receive + FIFOs. This number is the maximum allowed value for + TFCR[TFWM] or RFCR[RFWM]. - fsl,esai-synchronous: This is a boolean property. If present, indicating - that ESAI would work in the synchronous mode, which means all the settings - for Receiving would be duplicated from Transmition related registers. + that ESAI would work in the synchronous mode, which + means all the settings for Receiving would be + duplicated from Transmition related registers. - - big-endian : If this property is absent, the native endian mode will - be in use as default, or the big endian mode will be in use for all the - device registers. + - big-endian : If this property is absent, the native endian mode + will be in use as default, or the big endian mode + will be in use for all the device registers. Example: -- cgit v1.2.3-59-g8ed1b From 9c4c1045343836b848c3dd546277c955d145d20a Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Tue, 7 Oct 2014 12:29:05 -0700 Subject: ASoC: fsl_spdif: Add indentation for binding doc to increase readability This patch simply adds indentations for DT binding doc to increase readability without changing any contents. Signed-off-by: Nicolin Chen Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/fsl,spdif.txt | 37 +++++++++++----------- 1 file changed, 18 insertions(+), 19 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/fsl,spdif.txt b/Documentation/devicetree/bindings/sound/fsl,spdif.txt index 3e9e82c8eab3..b5ee32ee3706 100644 --- a/Documentation/devicetree/bindings/sound/fsl,spdif.txt +++ b/Documentation/devicetree/bindings/sound/fsl,spdif.txt @@ -6,32 +6,31 @@ a fibre cable. Required properties: - - compatible : Compatible list, must contain "fsl,imx35-spdif". + - compatible : Compatible list, must contain "fsl,imx35-spdif". - - reg : Offset and length of the register set for the device. + - reg : Offset and length of the register set for the device. - - interrupts : Contains the spdif interrupt. + - interrupts : Contains the spdif interrupt. - - dmas : Generic dma devicetree binding as described in - Documentation/devicetree/bindings/dma/dma.txt. + - dmas : Generic dma devicetree binding as described in + Documentation/devicetree/bindings/dma/dma.txt. - - dma-names : Two dmas have to be defined, "tx" and "rx". + - dma-names : Two dmas have to be defined, "tx" and "rx". - - clocks : Contains an entry for each entry in clock-names. + - clocks : Contains an entry for each entry in clock-names. - - clock-names : Includes the following entries: - "core" The core clock of spdif controller - "rxtx<0-7>" Clock source list for tx and rx clock. - This clock list should be identical to - the source list connecting to the spdif - clock mux in "SPDIF Transceiver Clock - Diagram" of SoC reference manual. It - can also be referred to TxClk_Source - bit of register SPDIF_STC. + - clock-names : Includes the following entries: + "core" The core clock of spdif controller. + "rxtx<0-7>" Clock source list for tx and rx clock. + This clock list should be identical to the source + list connecting to the spdif clock mux in "SPDIF + Transceiver Clock Diagram" of SoC reference manual. + It can also be referred to TxClk_Source bit of + register SPDIF_STC. - - big-endian : If this property is absent, the native endian mode will - be in use as default, or the big endian mode will be in use for all the - device registers. + - big-endian : If this property is absent, the native endian mode + will be in use as default, or the big endian mode + will be in use for all the device registers. Example: -- cgit v1.2.3-59-g8ed1b From 0b9938b264d1a76458cf06aab6de7b9cec68efca Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Tue, 7 Oct 2014 12:29:06 -0700 Subject: ASoC: fsl_sai: Add indentation for binding doc to increase readability This patch refines the DT binding doc for more readability by adding extra blank lines and indentations. Signed-off-by: Nicolin Chen Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/fsl-sai.txt | 66 ++++++++++++++-------- 1 file changed, 41 insertions(+), 25 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/fsl-sai.txt b/Documentation/devicetree/bindings/sound/fsl-sai.txt index 4956b14d4b06..044e5d76e2dd 100644 --- a/Documentation/devicetree/bindings/sound/fsl-sai.txt +++ b/Documentation/devicetree/bindings/sound/fsl-sai.txt @@ -5,32 +5,48 @@ which provides a synchronous audio interface that supports fullduplex serial interfaces with frame synchronization such as I2S, AC97, TDM, and codec/DSP interfaces. - Required properties: -- compatible: Compatible list, contains "fsl,vf610-sai" or "fsl,imx6sx-sai". -- reg: Offset and length of the register set for the device. -- clocks: Must contain an entry for each entry in clock-names. -- clock-names : Must include the "bus" for register access and "mclk1" "mclk2" - "mclk3" for bit clock and frame clock providing. -- dmas : Generic dma devicetree binding as described in - Documentation/devicetree/bindings/dma/dma.txt. -- dma-names : Two dmas have to be defined, "tx" and "rx". -- pinctrl-names: Must contain a "default" entry. -- pinctrl-NNN: One property must exist for each entry in pinctrl-names. - See ../pinctrl/pinctrl-bindings.txt for details of the property values. -- big-endian: Boolean property, required if all the FTM_PWM registers - are big-endian rather than little-endian. -- lsb-first: Configures whether the LSB or the MSB is transmitted first for - the fifo data. If this property is absent, the MSB is transmitted first as - default, or the LSB is transmitted first. -- fsl,sai-synchronous-rx: This is a boolean property. If present, indicating - that SAI will work in the synchronous mode (sync Tx with Rx) which means - both the transimitter and receiver will send and receive data by following - receiver's bit clocks and frame sync clocks. -- fsl,sai-asynchronous: This is a boolean property. If present, indicating - that SAI will work in the asynchronous mode, which means both transimitter - and receiver will send and receive data by following their own bit clocks - and frame sync clocks separately. + + - compatible : Compatible list, contains "fsl,vf610-sai" or + "fsl,imx6sx-sai". + + - reg : Offset and length of the register set for the device. + + - clocks : Must contain an entry for each entry in clock-names. + + - clock-names : Must include the "bus" for register access and + "mclk1", "mclk2", "mclk3" for bit clock and frame + clock providing. + - dmas : Generic dma devicetree binding as described in + Documentation/devicetree/bindings/dma/dma.txt. + + - dma-names : Two dmas have to be defined, "tx" and "rx". + + - pinctrl-names : Must contain a "default" entry. + + - pinctrl-NNN : One property must exist for each entry in + pinctrl-names. See ../pinctrl/pinctrl-bindings.txt + for details of the property values. + + - big-endian : Boolean property, required if all the FTM_PWM + registers are big-endian rather than little-endian. + + - lsb-first : Configures whether the LSB or the MSB is transmitted + first for the fifo data. If this property is absent, + the MSB is transmitted first as default, or the LSB + is transmitted first. + + - fsl,sai-synchronous-rx: This is a boolean property. If present, indicating + that SAI will work in the synchronous mode (sync Tx + with Rx) which means both the transimitter and the + receiver will send and receive data by following + receiver's bit clocks and frame sync clocks. + + - fsl,sai-asynchronous: This is a boolean property. If present, indicating + that SAI will work in the asynchronous mode, which + means both transimitter and receiver will send and + receive data by following their own bit clocks and + frame sync clocks separately. Note: - If both fsl,sai-asynchronous and fsl,sai-synchronous-rx are absent, the -- cgit v1.2.3-59-g8ed1b From d29ae41edde680c00f9f74d448b7d59c91ca0474 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Tue, 7 Oct 2014 12:29:07 -0700 Subject: ASoC: eukrea-tlv320: Add indentation for binding doc to increase readability This patch refines the DT binding doc for more readability by adding extra blank lines and indentations. Signed-off-by: Nicolin Chen Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/eukrea-tlv320.txt | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/eukrea-tlv320.txt b/Documentation/devicetree/bindings/sound/eukrea-tlv320.txt index 0d7985c864af..6dfa88c4dc1e 100644 --- a/Documentation/devicetree/bindings/sound/eukrea-tlv320.txt +++ b/Documentation/devicetree/bindings/sound/eukrea-tlv320.txt @@ -1,11 +1,16 @@ Audio complex for Eukrea boards with tlv320aic23 codec. Required properties: -- compatible : "eukrea,asoc-tlv320" -- eukrea,model : The user-visible name of this sound complex. -- ssi-controller : The phandle of the SSI controller. -- fsl,mux-int-port : The internal port of the i.MX audio muxer (AUDMUX). -- fsl,mux-ext-port : The external port of the i.MX audio muxer. + + - compatible : "eukrea,asoc-tlv320" + + - eukrea,model : The user-visible name of this sound complex. + + - ssi-controller : The phandle of the SSI controller. + + - fsl,mux-int-port : The internal port of the i.MX audio muxer (AUDMUX). + + - fsl,mux-ext-port : The external port of the i.MX audio muxer. Note: The AUDMUX port numbering should start at 1, which is consistent with hardware manual. -- cgit v1.2.3-59-g8ed1b From 5463c709ddeeacc73ae6844fd8aebc0a217b98d4 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Tue, 7 Oct 2014 12:29:08 -0700 Subject: ASoC: imx-audmux: Add indentation for binding doc to increase readability This patch refines the DT binding doc for more readability by adding extra blank lines and indentations. Signed-off-by: Nicolin Chen Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/imx-audmux.txt | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/imx-audmux.txt b/Documentation/devicetree/bindings/sound/imx-audmux.txt index f88a00e54c63..b30a737e209e 100644 --- a/Documentation/devicetree/bindings/sound/imx-audmux.txt +++ b/Documentation/devicetree/bindings/sound/imx-audmux.txt @@ -1,18 +1,24 @@ Freescale Digital Audio Mux (AUDMUX) device Required properties: -- compatible : "fsl,imx21-audmux" for AUDMUX version firstly used on i.MX21, - or "fsl,imx31-audmux" for the version firstly used on i.MX31. -- reg : Should contain AUDMUX registers location and length + + - compatible : "fsl,imx21-audmux" for AUDMUX version firstly used + on i.MX21, or "fsl,imx31-audmux" for the version + firstly used on i.MX31. + + - reg : Should contain AUDMUX registers location and length. An initial configuration can be setup using child nodes. Required properties of optional child nodes: -- fsl,audmux-port : Integer of the audmux port that is configured by this - child node. -- fsl,port-config : List of configuration options for the specific port. For - imx31-audmux and above, it is a list of tuples . For - imx21-audmux it is a list of pcr values. + + - fsl,audmux-port : Integer of the audmux port that is configured by this + child node. + + - fsl,port-config : List of configuration options for the specific port. + For imx31-audmux and above, it is a list of tuples + . For imx21-audmux it is a list of pcr + values. Example: -- cgit v1.2.3-59-g8ed1b From afa1fde676592b9c40e893f4f652f2c842e31683 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Tue, 7 Oct 2014 12:29:09 -0700 Subject: ASoC: imx-sgtl5000: Add indentation for binding doc to increase readability This patch refines the DT binding doc for more readability by adding extra blank lines and indentations. Signed-off-by: Nicolin Chen Signed-off-by: Mark Brown --- .../bindings/sound/imx-audio-sgtl5000.txt | 61 ++++++++++++---------- 1 file changed, 34 insertions(+), 27 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt b/Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt index e4acdd891e49..2f89db88fd57 100644 --- a/Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt +++ b/Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt @@ -1,33 +1,40 @@ Freescale i.MX audio complex with SGTL5000 codec Required properties: -- compatible : "fsl,imx-audio-sgtl5000" -- model : The user-visible name of this sound complex -- ssi-controller : The phandle of the i.MX SSI controller -- audio-codec : The phandle of the SGTL5000 audio codec -- audio-routing : A list of the connections between audio components. - Each entry is a pair of strings, the first being the connection's sink, - the second being the connection's source. Valid names could be power - supplies, SGTL5000 pins, and the jacks on the board: - - Power supplies: - * Mic Bias - - SGTL5000 pins: - * MIC_IN - * LINE_IN - * HP_OUT - * LINE_OUT - - Board connectors: - * Mic Jack - * Line In Jack - * Headphone Jack - * Line Out Jack - * Ext Spk - -- mux-int-port : The internal port of the i.MX audio muxer (AUDMUX) -- mux-ext-port : The external port of the i.MX audio muxer + + - compatible : "fsl,imx-audio-sgtl5000" + + - model : The user-visible name of this sound complex + + - ssi-controller : The phandle of the i.MX SSI controller + + - audio-codec : The phandle of the SGTL5000 audio codec + + - audio-routing : A list of the connections between audio components. + Each entry is a pair of strings, the first being the + connection's sink, the second being the connection's + source. Valid names could be power supplies, SGTL5000 + pins, and the jacks on the board: + + Power supplies: + * Mic Bias + + SGTL5000 pins: + * MIC_IN + * LINE_IN + * HP_OUT + * LINE_OUT + + Board connectors: + * Mic Jack + * Line In Jack + * Headphone Jack + * Line Out Jack + * Ext Spk + + - mux-int-port : The internal port of the i.MX audio muxer (AUDMUX) + + - mux-ext-port : The external port of the i.MX audio muxer Note: The AUDMUX port numbering should start at 1, which is consistent with hardware manual. -- cgit v1.2.3-59-g8ed1b From 6219b082b3099668c32be99bd31216379fc3d97a Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Tue, 7 Oct 2014 12:29:10 -0700 Subject: ASoC: imx-spdif: Add indentation for binding doc to increase readability This patch simply adds indentations for DT binding doc to increase readability without changing any contents. Signed-off-by: Nicolin Chen Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/imx-audio-spdif.txt | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/imx-audio-spdif.txt b/Documentation/devicetree/bindings/sound/imx-audio-spdif.txt index 7d13479f9c3c..da84a442ccea 100644 --- a/Documentation/devicetree/bindings/sound/imx-audio-spdif.txt +++ b/Documentation/devicetree/bindings/sound/imx-audio-spdif.txt @@ -2,23 +2,25 @@ Freescale i.MX audio complex with S/PDIF transceiver Required properties: - - compatible : "fsl,imx-audio-spdif" + - compatible : "fsl,imx-audio-spdif" - - model : The user-visible name of this sound complex + - model : The user-visible name of this sound complex - - spdif-controller : The phandle of the i.MX S/PDIF controller + - spdif-controller : The phandle of the i.MX S/PDIF controller Optional properties: - - spdif-out : This is a boolean property. If present, the transmitting - function of S/PDIF will be enabled, indicating there's a physical - S/PDIF out connector/jack on the board or it's connecting to some - other IP block, such as an HDMI encoder/display-controller. + - spdif-out : This is a boolean property. If present, the + transmitting function of S/PDIF will be enabled, + indicating there's a physical S/PDIF out connector + or jack on the board or it's connecting to some + other IP block, such as an HDMI encoder or + display-controller. - - spdif-in : This is a boolean property. If present, the receiving - function of S/PDIF will be enabled, indicating there's a physical - S/PDIF in connector/jack on the board. + - spdif-in : This is a boolean property. If present, the receiving + function of S/PDIF will be enabled, indicating there + is a physical S/PDIF in connector/jack on the board. * Note: At least one of these two properties should be set in the DT binding. -- cgit v1.2.3-59-g8ed1b From 6a6dec83e5abbc5003dac234970b51afa142defd Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Tue, 7 Oct 2014 12:29:11 -0700 Subject: ASoC: imx-wm8962: Add indentation for binding doc to increase readability This patch simply adds indentations for DT binding doc to increase readability without changing any contents. Signed-off-by: Nicolin Chen Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/imx-audio-wm8962.txt | 45 +++++++++++++--------- 1 file changed, 26 insertions(+), 19 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt b/Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt index f49450a87890..acea71bee34f 100644 --- a/Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt +++ b/Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt @@ -1,25 +1,32 @@ Freescale i.MX audio complex with WM8962 codec Required properties: -- compatible : "fsl,imx-audio-wm8962" -- model : The user-visible name of this sound complex -- ssi-controller : The phandle of the i.MX SSI controller -- audio-codec : The phandle of the WM8962 audio codec -- audio-routing : A list of the connections between audio components. - Each entry is a pair of strings, the first being the connection's sink, - the second being the connection's source. Valid names could be power - supplies, WM8962 pins, and the jacks on the board: - - Power supplies: - * Mic Bias - - Board connectors: - * Mic Jack - * Headphone Jack - * Ext Spk - -- mux-int-port : The internal port of the i.MX audio muxer (AUDMUX) -- mux-ext-port : The external port of the i.MX audio muxer + + - compatible : "fsl,imx-audio-wm8962" + + - model : The user-visible name of this sound complex + + - ssi-controller : The phandle of the i.MX SSI controller + + - audio-codec : The phandle of the WM8962 audio codec + + - audio-routing : A list of the connections between audio components. + Each entry is a pair of strings, the first being the + connection's sink, the second being the connection's + source. Valid names could be power supplies, WM8962 + pins, and the jacks on the board: + + Power supplies: + * Mic Bias + + Board connectors: + * Mic Jack + * Headphone Jack + * Ext Spk + + - mux-int-port : The internal port of the i.MX audio muxer (AUDMUX) + + - mux-ext-port : The external port of the i.MX audio muxer Note: The AUDMUX port numbering should start at 1, which is consistent with hardware manual. -- cgit v1.2.3-59-g8ed1b From 40eb90a18e93fbd4fd0e6892b31241356c3c8e43 Mon Sep 17 00:00:00 2001 From: Anatol Pomozov Date: Fri, 10 Oct 2014 20:46:36 -0700 Subject: ASoC: rt5677: Add option to configure gpio as floating/pullup/pulldown gpio_config is array of 6 elements that allows to set GPIO as floating, pullup, pulldown. Sponsored: Google ChromeOS Signed-off-by: Anatol Pomozov Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/rt5677.txt | 7 ++++ include/sound/rt5677.h | 3 ++ sound/soc/codecs/rt5677.c | 39 ++++++++++++++++++++++ 3 files changed, 49 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/rt5677.txt b/Documentation/devicetree/bindings/sound/rt5677.txt index 0701b834fc73..f82f0e906cd9 100644 --- a/Documentation/devicetree/bindings/sound/rt5677.txt +++ b/Documentation/devicetree/bindings/sound/rt5677.txt @@ -27,6 +27,12 @@ Optional properties: Boolean. Indicate MIC1/2 input and LOUT1/2/3 outputs are differential, rather than single-ended. +- realtek,gpio-config + Array of six 8bit elements that configures GPIO. + 0 - floating (reset value) + 1 - pull down + 2 - pull up + Pins on the device (for linking into audio routes): * IN1P @@ -56,4 +62,5 @@ rt5677 { realtek,pow-ldo2-gpio = <&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>; realtek,in1-differential = "true"; + realtek,gpio-config = /bits/ 8 <0 0 0 0 0 2>; /* pull up GPIO6 */ }; diff --git a/include/sound/rt5677.h b/include/sound/rt5677.h index 082670e3a353..a56b429a1dbc 100644 --- a/include/sound/rt5677.h +++ b/include/sound/rt5677.h @@ -27,6 +27,9 @@ struct rt5677_platform_data { bool lout3_diff; /* DMIC2 clock source selection */ enum rt5677_dmic2_clk dmic2_clk_pin; + + /* configures GPIO, 0 - floating, 1 - pulldown, 2 - pullup */ + u8 gpio_config[6]; }; #endif diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 16aa4d99a713..a454df39b7a5 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -3309,6 +3309,38 @@ static int rt5677_gpio_direction_in(struct gpio_chip *chip, unsigned offset) return 0; } +/** Configures the gpio as + * 0 - floating + * 1 - pull down + * 2 - pull up + */ +static void rt5677_gpio_config(struct rt5677_priv *rt5677, unsigned offset, + int value) +{ + int shift; + + switch (offset) { + case RT5677_GPIO1 ... RT5677_GPIO2: + shift = 2 * (1 - offset); + regmap_update_bits(rt5677->regmap, + RT5677_PR_BASE + RT5677_DIG_IN_PIN_ST_CTRL2, + 0x3 << shift, + (value & 0x3) << shift); + break; + + case RT5677_GPIO3 ... RT5677_GPIO6: + shift = 2 * (9 - offset); + regmap_update_bits(rt5677->regmap, + RT5677_PR_BASE + RT5677_DIG_IN_PIN_ST_CTRL3, + 0x3 << shift, + (value & 0x3) << shift); + break; + + default: + break; + } +} + static struct gpio_chip rt5677_template_chip = { .label = "rt5677", .owner = THIS_MODULE, @@ -3353,6 +3385,7 @@ static void rt5677_free_gpio(struct i2c_client *i2c) static int rt5677_probe(struct snd_soc_codec *codec) { struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); + int i; rt5677->codec = codec; @@ -3371,6 +3404,9 @@ static int rt5677_probe(struct snd_soc_codec *codec) regmap_write(rt5677->regmap, RT5677_DIG_MISC, 0x0020); regmap_write(rt5677->regmap, RT5677_PWR_DSP2, 0x0c00); + for (i = 0; i < RT5677_GPIO_NUM; i++) + rt5677_gpio_config(rt5677, i, rt5677->pdata.gpio_config[i]); + return 0; } @@ -3590,6 +3626,9 @@ static int rt5677_parse_dt(struct rt5677_priv *rt5677, struct device_node *np) (rt5677->pow_ldo2 != -ENOENT)) return rt5677->pow_ldo2; + of_property_read_u8_array(np, "realtek,gpio-config", + rt5677->pdata.gpio_config, RT5677_GPIO_NUM); + return 0; } -- cgit v1.2.3-59-g8ed1b From bd0593f5f6add279257334b4a76aecd3ee8d31dc Mon Sep 17 00:00:00 2001 From: Jean-Michel Hautbois Date: Tue, 14 Oct 2014 08:43:11 +0200 Subject: ASoC: sgtl5000: Add MicBias resistor support in DT Some systems may require a different resistor than the default one (4K). This adds a property in sgtl5000 codec. It keeps the default of 4K when nothing is specified so it does not break existing code. Signed-off-by: Jean-Michel Hautbois Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/sgtl5000.txt | 8 ++++ sound/soc/codecs/sgtl5000.c | 55 ++++++++++++++++++++-- 2 files changed, 59 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/sgtl5000.txt b/Documentation/devicetree/bindings/sound/sgtl5000.txt index 955df60a118c..d6ec92707d81 100644 --- a/Documentation/devicetree/bindings/sound/sgtl5000.txt +++ b/Documentation/devicetree/bindings/sound/sgtl5000.txt @@ -7,10 +7,18 @@ Required properties: - clocks : the clock provider of SYS_MCLK +- micbias-resistor-k-ohms : the bias resistor to be used in kOmhs + The resistor can take values of 2k, 4k or 8k. + If set to 0 it will be off. + If this node is not mentioned or if the value is unknown, then + micbias resistor is set to 4K. + + Example: codec: sgtl5000@0a { compatible = "fsl,sgtl5000"; reg = <0x0a>; clocks = <&clks 150>; + sgtl5000-micbias-resistor = <1>; }; diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index 10160e7a9277..c417b4ad0492 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -121,6 +122,13 @@ struct ldo_regulator { bool enabled; }; +enum sgtl5000_micbias_resistor { + SGTL5000_MICBIAS_OFF = 0, + SGTL5000_MICBIAS_2K = 2, + SGTL5000_MICBIAS_4K = 4, + SGTL5000_MICBIAS_8K = 8, +}; + /* sgtl5000 private structure in codec */ struct sgtl5000_priv { int sysclk; /* sysclk rate */ @@ -131,6 +139,7 @@ struct sgtl5000_priv { struct regmap *regmap; struct clk *mclk; int revision; + u8 micbias_resistor; }; /* @@ -145,12 +154,14 @@ struct sgtl5000_priv { static int mic_bias_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { + struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(w->codec); + switch (event) { case SND_SOC_DAPM_POST_PMU: - /* change mic bias resistor to 4Kohm */ + /* change mic bias resistor */ snd_soc_update_bits(w->codec, SGTL5000_CHIP_MIC_CTRL, - SGTL5000_BIAS_R_MASK, - SGTL5000_BIAS_R_4k << SGTL5000_BIAS_R_SHIFT); + SGTL5000_BIAS_R_MASK, + sgtl5000->micbias_resistor << SGTL5000_BIAS_R_SHIFT); break; case SND_SOC_DAPM_PRE_PMD: @@ -1327,7 +1338,9 @@ static int sgtl5000_probe(struct snd_soc_codec *codec) SGTL5000_HP_ZCD_EN | SGTL5000_ADC_ZCD_EN); - snd_soc_write(codec, SGTL5000_CHIP_MIC_CTRL, 2); + snd_soc_update_bits(codec, SGTL5000_CHIP_MIC_CTRL, + SGTL5000_BIAS_R_MASK, + sgtl5000->micbias_resistor << SGTL5000_BIAS_R_SHIFT); /* * disable DAP @@ -1419,6 +1432,8 @@ static int sgtl5000_i2c_probe(struct i2c_client *client, struct sgtl5000_priv *sgtl5000; int ret, reg, rev; unsigned int mclk; + struct device_node *np = client->dev.of_node; + u32 value; sgtl5000 = devm_kzalloc(&client->dev, sizeof(struct sgtl5000_priv), GFP_KERNEL); @@ -1471,6 +1486,38 @@ static int sgtl5000_i2c_probe(struct i2c_client *client, dev_info(&client->dev, "sgtl5000 revision 0x%x\n", rev); sgtl5000->revision = rev; + if (np) { + if (!of_property_read_u32(np, + "micbias-resistor-k-ohms", &value)) { + switch (value) { + case SGTL5000_MICBIAS_OFF: + sgtl5000->micbias_resistor = 0; + break; + case SGTL5000_MICBIAS_2K: + sgtl5000->micbias_resistor = 1; + break; + case SGTL5000_MICBIAS_4K: + sgtl5000->micbias_resistor = 2; + break; + case SGTL5000_MICBIAS_8K: + sgtl5000->micbias_resistor = 3; + break; + default: + sgtl5000->micbias_resistor = 2; + dev_err(&client->dev, + "Unsuitable MicBias resistor\n"); + } + } else { + /* default is 4Kohms */ + sgtl5000->micbias_resistor = 2; + } + dev_err(&client->dev, + "Unsuitable MicBias resistor\n"); + } + } else { + } + } + i2c_set_clientdata(client, sgtl5000); /* Ensure sgtl5000 will start with sane register values */ -- cgit v1.2.3-59-g8ed1b From 8735779774b8bbe14456c9e6ba4525eefc67a228 Mon Sep 17 00:00:00 2001 From: Jean-Michel Hautbois Date: Tue, 14 Oct 2014 08:43:12 +0200 Subject: ASoC: sgtl5000: Add MicBias voltage support Some systems may require to specify a bias different than default (1.25V). This adds a property in sgtl5000 codec. The property is specified in milli-volts so that it is coherent with datasheet. Signed-off-by: Jean-Michel Hautbois Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/sgtl5000.txt | 7 ++++++- sound/soc/codecs/sgtl5000.c | 13 +++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/sgtl5000.txt b/Documentation/devicetree/bindings/sound/sgtl5000.txt index d6ec92707d81..1aab40339617 100644 --- a/Documentation/devicetree/bindings/sound/sgtl5000.txt +++ b/Documentation/devicetree/bindings/sound/sgtl5000.txt @@ -13,6 +13,10 @@ Required properties: If this node is not mentioned or if the value is unknown, then micbias resistor is set to 4K. +- micbias-voltage-m-volts : the bias voltage to be used in mVolts + The voltage can take values from 1.25V to 3V by 250mV steps + If this node is not mentionned or the value is unknown, then + the value is set to 1.25V. Example: @@ -20,5 +24,6 @@ codec: sgtl5000@0a { compatible = "fsl,sgtl5000"; reg = <0x0a>; clocks = <&clks 150>; - sgtl5000-micbias-resistor = <1>; + micbias-resistor-k-ohms = <2>; + micbias-voltage-m-volts = <2250>; }; diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index c417b4ad0492..59336f6aba80 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -140,6 +140,7 @@ struct sgtl5000_priv { struct clk *mclk; int revision; u8 micbias_resistor; + u8 micbias_voltage; }; /* @@ -1342,6 +1343,9 @@ static int sgtl5000_probe(struct snd_soc_codec *codec) SGTL5000_BIAS_R_MASK, sgtl5000->micbias_resistor << SGTL5000_BIAS_R_SHIFT); + snd_soc_update_bits(codec, SGTL5000_CHIP_MIC_CTRL, + SGTL5000_BIAS_R_MASK, + sgtl5000->micbias_voltage << SGTL5000_BIAS_R_SHIFT); /* * disable DAP * TODO: @@ -1511,10 +1515,19 @@ static int sgtl5000_i2c_probe(struct i2c_client *client, /* default is 4Kohms */ sgtl5000->micbias_resistor = 2; } + if (!of_property_read_u32(np, + "micbias-voltage-m-volts", &value)) { + /* 1250mV => 0 */ + /* steps of 250mV */ + if ((value >= 1250) && (value <= 3000)) + sgtl5000->micbias_voltage = (value / 250) - 5; + else { + sgtl5000->micbias_voltage = 0; dev_err(&client->dev, "Unsuitable MicBias resistor\n"); } } else { + sgtl5000->micbias_voltage = 0; } } -- cgit v1.2.3-59-g8ed1b From 291d761c16c9dc05050a92679c6aa92f263c4f51 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Fri, 10 Oct 2014 20:35:34 +0900 Subject: regulator: Document binding for regulator suspend state for PM state This patch add regulator suspend state to constraint in dt file. The regulation_ constraints structure already has regulator suspend state field as following. The regulator suspend state control the state of regulator according to PM (Power Management) state. - struct regulator_state state_disk - struct regulator_state state_mem Signed-off-by: Chanwoo Choi Acked-by: Kyungmin Park Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/regulator/regulator.txt | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/regulator/regulator.txt b/Documentation/devicetree/bindings/regulator/regulator.txt index 86074334e342..aaad615899d2 100644 --- a/Documentation/devicetree/bindings/regulator/regulator.txt +++ b/Documentation/devicetree/bindings/regulator/regulator.txt @@ -19,6 +19,15 @@ Optional properties: design requires. This property describes the total system ramp time required due to the combination of internal ramping of the regulator itself, and board design issues such as trace capacitance and load on the supply. +- regulator-state-mem sub-root node for Suspend-to-RAM mode + : suspend to memory, the device goes to sleep, but all data stored in memory, + only some external interrupt can wake the device. +- regulator-state-disk sub-root node for Suspend-to-DISK mode + : suspend to disk, this state operates similarly to Suspend-to-RAM, + but includes a final step of writing memory contents to disk. +- regulator-state-[mem/disk] node has following common properties: + - regulator-on-in-suspend: regulator should be on in suspend state. + - regulator-off-in-suspend: regulator should be off in suspend state. Deprecated properties: - regulator-compatible: If a regulator chip contains multiple @@ -34,6 +43,10 @@ Example: regulator-max-microvolt = <2500000>; regulator-always-on; vin-supply = <&vin>; + + regulator-state-mem { + regulator-on-in-suspend; + }; }; Regulator Consumers: -- cgit v1.2.3-59-g8ed1b From 0da6e72504f327c051979745843b5c614565e2ed Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Wed, 24 Sep 2014 23:09:09 +0800 Subject: Documentation: sunxi: Update Allwinner SoC documentation (A31/A31s/A23) Lately we have received documentation for A31 and A31s, in addition to A23 documentation which was received earlier but not added. Add these to the README, and update to reflect that A31 and A23 are supported. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- Documentation/arm/sunxi/README | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/arm/sunxi/README b/Documentation/arm/sunxi/README index 7945238453ed..57c4da6a9ed2 100644 --- a/Documentation/arm/sunxi/README +++ b/Documentation/arm/sunxi/README @@ -37,15 +37,24 @@ SunXi family http://dl.linux-sunxi.org/A20/A20%20User%20Manual%202013-03-22.pdf - Allwinner A23 - + Not Supported + + Datasheet + http://dl.linux-sunxi.org/A23/A23%20Datasheet%20V1.0%2020130830.pdf + + User Manual + http://dl.linux-sunxi.org/A23/A23%20User%20Manual%20V1.0%2020130830.pdf * Quad ARM Cortex-A7 based SoCs - Allwinner A31 (sun6i) + Datasheet - http://dl.linux-sunxi.org/A31/A31%20Datasheet%20-%20v1.00%20(2012-12-24).pdf + http://dl.linux-sunxi.org/A31/A3x_release_document/A31/IC/A31%20datasheet%20V1.3%2020131106.pdf + + User Manual + http://dl.linux-sunxi.org/A31/A3x_release_document/A31/IC/A31%20user%20manual%20V1.1%2020130630.pdf - Allwinner A31s (sun6i) + Not Supported + + Datasheet + http://dl.linux-sunxi.org/A31/A3x_release_document/A31s/IC/A31s%20datasheet%20V1.3%2020131106.pdf + + User Manual + http://dl.linux-sunxi.org/A31/A3x_release_document/A31s/IC/A31s%20User%20Manual%20%20V1.0%2020130322.pdf * Quad ARM Cortex-A15, Quad ARM Cortex-A7 based SoCs - Allwinner A80 -- cgit v1.2.3-59-g8ed1b From bb647665bae4dfdf7e1d07540325eab81f9800a8 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Wed, 24 Sep 2014 22:48:59 +0800 Subject: devicetree: bindings: Add vendor prefix for Merrii Technology Co., Ltd. Merrii Technology Co., Ltd. is a Chinese ARM integration developer that specializes in Allwinner SoC based designs. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- 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 723999d73744..3da78a14e6c7 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -90,6 +90,7 @@ lltc Linear Technology Corporation marvell Marvell Technology Group Ltd. maxim Maxim Integrated Products mediatek MediaTek Inc. +merrii Merrii Technology Co., Ltd. micrel Micrel Inc. microchip Microchip Technology Inc. mitsubishi Mitsubishi Electric Corporation -- cgit v1.2.3-59-g8ed1b From a1a0193bdd855d0bcfbfc62fa59882242236882b Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Wed, 8 Oct 2014 21:02:55 +0800 Subject: devicetree: bindings: Document supported Allwinner sunxi SoCs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds a list of supported Allwinner SoC bindings. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard Tested-by: Andreas Färber --- Documentation/devicetree/bindings/arm/sunxi.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/sunxi.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/sunxi.txt b/Documentation/devicetree/bindings/arm/sunxi.txt new file mode 100644 index 000000000000..42941fdefb11 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/sunxi.txt @@ -0,0 +1,12 @@ +Allwinner sunXi Platforms Device Tree Bindings + +Each device tree must specify which Allwinner SoC it uses, +using one of the following compatible strings: + + allwinner,sun4i-a10 + allwinner,sun5i-a10s + allwinner,sun5i-a13 + allwinner,sun6i-a31 + allwinner,sun7i-a20 + allwinner,sun8i-a23 + allwinner,sun9i-a80 -- cgit v1.2.3-59-g8ed1b From 19e704e35e33e2e468a4d038f83003ff9e9bd4cd Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Wed, 8 Oct 2014 21:02:56 +0800 Subject: Documentation: sunxi: Add A80 datasheet link MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We now have initial support for the A80, as well a the datasheet. Update the documents to reflect this. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard Tested-by: Andreas Färber --- Documentation/arm/sunxi/README | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/arm/sunxi/README b/Documentation/arm/sunxi/README index 57c4da6a9ed2..e68d163df33d 100644 --- a/Documentation/arm/sunxi/README +++ b/Documentation/arm/sunxi/README @@ -58,4 +58,5 @@ SunXi family * Quad ARM Cortex-A15, Quad ARM Cortex-A7 based SoCs - Allwinner A80 - + Not Supported \ No newline at end of file + + Datasheet + http://dl.linux-sunxi.org/A80/A80_Datasheet_Revision_1.0_0404.pdf -- cgit v1.2.3-59-g8ed1b From 8e648204194cb51df8562d1e2a64b7dc6b0aead3 Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Mon, 20 Oct 2014 14:38:09 +0200 Subject: ALSA: Update control names documentation This document was not really up-to-date. Add recent additions to this standard - based on what the HDA driver currently does, which is some kind of a de facto standard. Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/ControlNames.txt | 32 ++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/ControlNames.txt b/Documentation/sound/alsa/ControlNames.txt index fea65bb6269e..79a6127863ca 100644 --- a/Documentation/sound/alsa/ControlNames.txt +++ b/Documentation/sound/alsa/ControlNames.txt @@ -1,6 +1,6 @@ This document describes standard names of mixer controls. -Syntax: SOURCE [DIRECTION] FUNCTION +Syntax: [LOCATION] SOURCE [CHANNEL] [DIRECTION] FUNCTION DIRECTION: (both directions) @@ -14,12 +14,29 @@ FUNCTION: Volume Route (route control, hardware specific) +CHANNEL: + (channel independent, or applies to all channels) + Front + Surround (rear left/right in 4.0/5.1 surround) + CLFE + Center + LFE + Side (side left/right for 7.1 surround) + +LOCATION: (physical location of source) + Front + Rear + Dock (docking station) + Internal + SOURCE: Master Master Mono Hardware Master Speaker (internal speaker) + Bass Speaker (internal LFE speaker) Headphone + Line Out Beep (beep generator) Phone Phone Input @@ -27,14 +44,14 @@ SOURCE: Synth FM Mic - Line + Headset Mic (mic part of combined headset jack - 4-pin headphone + mic) + Headphone Mic (mic part of either/or - 3-pin headphone or mic) + Line (input only, use "Line Out" for output) CD Video Zoom Video Aux PCM - PCM Front - PCM Rear PCM Pan Loopback Analog Loopback (D/A -> A/D loopback) @@ -47,8 +64,13 @@ SOURCE: Music I2S IEC958 + HDMI + SPDIF (output only) + SPDIF In + Digital In + HDMI/DP (either HDMI or DisplayPort) -Exceptions: +Exceptions (deprecated): [Digital] Capture Source [Digital] Capture Switch (aka input gain switch) [Digital] Capture Volume (aka input gain volume) -- cgit v1.2.3-59-g8ed1b From 9c261f89a30010a33c15e6b7cfc7c79ae6bea653 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Wed, 24 Sep 2014 01:24:35 +0900 Subject: ARM: firmware: Introduce suspend and resume operations This patch extends the firmware_ops structure with two new callbacks: .suspend() and .resume(). The former is intended to ask the firmware to save all its volatile state and suspend the system, without returning back to the kernel in between. The latter is to be called early by very low level platform suspend code after waking up to restore low level hardware state, which can't be restored in non-secure mode. While at it, outdated version of the structure is removed from the documentation and replaced with a reference to the header file. Signed-off-by: Tomasz Figa Acked-by: Alexandre Courbot Signed-off-by: Kukjin Kim --- Documentation/arm/firmware.txt | 28 +++++----------------------- arch/arm/include/asm/firmware.h | 8 ++++++++ 2 files changed, 13 insertions(+), 23 deletions(-) (limited to 'Documentation') diff --git a/Documentation/arm/firmware.txt b/Documentation/arm/firmware.txt index c2e468fe7b0b..da6713adac8a 100644 --- a/Documentation/arm/firmware.txt +++ b/Documentation/arm/firmware.txt @@ -7,32 +7,14 @@ world, which changes the way some things have to be initialized. This makes a need to provide an interface for such platforms to specify available firmware operations and call them when needed. -Firmware operations can be specified using struct firmware_ops - - struct firmware_ops { - /* - * Enters CPU idle mode - */ - int (*do_idle)(void); - /* - * Sets boot address of specified physical CPU - */ - int (*set_cpu_boot_addr)(int cpu, unsigned long boot_addr); - /* - * Boots specified physical CPU - */ - int (*cpu_boot)(int cpu); - /* - * Initializes L2 cache - */ - int (*l2x0_init)(void); - }; - -and then registered with register_firmware_ops function +Firmware operations can be specified by filling in a struct firmware_ops +with appropriate callbacks and then registering it with register_firmware_ops() +function. void register_firmware_ops(const struct firmware_ops *ops) -the ops pointer must be non-NULL. +The ops pointer must be non-NULL. More information about struct firmware_ops +and its members can be found in arch/arm/include/asm/firmware.h header. There is a default, empty set of operations provided, so there is no need to set anything if platform does not require firmware operations. diff --git a/arch/arm/include/asm/firmware.h b/arch/arm/include/asm/firmware.h index 2c9f10df7568..5904f59b0409 100644 --- a/arch/arm/include/asm/firmware.h +++ b/arch/arm/include/asm/firmware.h @@ -41,6 +41,14 @@ struct firmware_ops { * Initializes L2 cache */ int (*l2x0_init)(void); + /* + * Enter system-wide suspend. + */ + int (*suspend)(void); + /* + * Restore state of privileged hardware after system-wide suspend. + */ + int (*resume)(void); }; /* Global pointer for current firmware_ops structure, can't be NULL. */ -- cgit v1.2.3-59-g8ed1b From be93709cb13a1947fec3493267d04cd87baf497e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Oct 2014 18:06:04 +0200 Subject: ALSA: doc: Recommend the use of snd_ctl_elem_info() Instead of the open code for the info call back of enum elements, recommend the use of snd_ctl_elem_info(), which will reduce lots of codes. Signed-off-by: Takashi Iwai --- Documentation/DocBook/writing-an-alsa-driver.tmpl | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'Documentation') diff --git a/Documentation/DocBook/writing-an-alsa-driver.tmpl b/Documentation/DocBook/writing-an-alsa-driver.tmpl index 784793df81ed..84ef6a90131c 100644 --- a/Documentation/DocBook/writing-an-alsa-driver.tmpl +++ b/Documentation/DocBook/writing-an-alsa-driver.tmpl @@ -3657,6 +3657,29 @@ struct _snd_pcm_runtime { + + The above callback can be simplified with a helper function, + snd_ctl_enum_info. The final code + looks like below. + (You can pass ARRAY_SIZE(texts) instead of 4 in the third + argument; it's a matter of taste.) + + + + + + + + Some common info callbacks are available for your convenience: snd_ctl_boolean_mono_info() and -- cgit v1.2.3-59-g8ed1b From a8e0aead70b4af957e6b27b82fba849c6179b707 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Wed, 4 Sep 2013 12:30:08 +0100 Subject: documentation: memory-barriers: clarify relaxed io accessor semantics This patch extends the paragraph describing the relaxed read io accessors so that the relaxed accessors are defined to be: - Ordered with respect to each other if accessing the same peripheral - Unordered with respect to normal memory accesses - Unordered with respect to LOCK/UNLOCK operations Whilst many architectures will provide stricter semantics, ARM, Alpha and PPC can achieve significant performance gains by taking advantage of some or all of the above relaxations. Cc: Randy Dunlap Cc: Benjamin Herrenschmidt Cc: Paul E. McKenney Cc: David Howells Signed-off-by: Will Deacon --- Documentation/memory-barriers.txt | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt index 22a969cdd476..4af4cea8cff0 100644 --- a/Documentation/memory-barriers.txt +++ b/Documentation/memory-barriers.txt @@ -2465,10 +2465,15 @@ functions: Please refer to the PCI specification for more information on interactions between PCI transactions. - (*) readX_relaxed() - - These are similar to readX(), but are not guaranteed to be ordered in any - way. Be aware that there is no I/O read barrier available. + (*) readX_relaxed(), writeX_relaxed() + + These are similar to readX() and writeX(), but provide weaker memory + ordering guarantees. Specifically, they do not guarantee ordering with + respect to normal memory accesses (e.g. DMA buffers) nor do they guarantee + ordering with respect to LOCK or UNLOCK operations. If the latter is + required, an mmiowb() barrier can be used. Note that relaxed accesses to + the same peripheral are guaranteed to be ordered with respect to each + other. (*) ioreadX(), iowriteX() -- cgit v1.2.3-59-g8ed1b From 4515b76d9b158ae89db094fe0fb277eaac88be25 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Fri, 3 Oct 2014 11:32:15 +0400 Subject: GPIO: 74xx-mmio: Add DT bindings documentation This patch adds DT binding documentation for the 74xx-mmio GPIO driver. Signed-off-by: Alexander Shiyan Signed-off-by: Linus Walleij --- .../devicetree/bindings/gpio/gpio-74xx-mmio.txt | 30 ++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpio/gpio-74xx-mmio.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/gpio/gpio-74xx-mmio.txt b/Documentation/devicetree/bindings/gpio/gpio-74xx-mmio.txt new file mode 100644 index 000000000000..7bb1a9d60133 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio-74xx-mmio.txt @@ -0,0 +1,30 @@ +* 74XX MMIO GPIO driver + +Required properties: +- compatible: Should contain one of the following: + "ti,741g125": for 741G125 (1-bit Input), + "ti,741g174": for 741G74 (1-bit Output), + "ti,742g125": for 742G125 (2-bit Input), + "ti,7474" : for 7474 (2-bit Output), + "ti,74125" : for 74125 (4-bit Input), + "ti,74175" : for 74175 (4-bit Output), + "ti,74365" : for 74365 (6-bit Input), + "ti,74174" : for 74174 (6-bit Output), + "ti,74244" : for 74244 (8-bit Input), + "ti,74273" : for 74273 (8-bit Output), + "ti,741624" : for 741624 (16-bit Input), + "ti,7416374": for 7416374 (16-bit Output). +- reg: Physical base address and length where IC resides. +- gpio-controller: Marks the device node as a gpio controller. +- #gpio-cells: Should be two. The first cell is the pin number and + the second cell is used to specify the GPIO polarity: + 0 = Active High, + 1 = Active Low. + +Example: + ctrl: gpio@30008004 { + compatible = "ti,74174"; + reg = <0x30008004 0x1>; + gpio-controller; + #gpio-cells = <2>; + }; -- cgit v1.2.3-59-g8ed1b From 3b2bd70f03c75d37de791b65d574a31d1e2507b0 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Mon, 20 Oct 2014 22:10:27 +0800 Subject: clk: sunxi: Add support for A80 basic bus clocks The A80 SoC has 12 PLL clocks, 3 AHB clocks, 2 APB clocks, and a new "GT" bus, which I assume is some kind of data bus connecting the processor cores, memory and various busses. Also there is a bus clock for a ARM CCI400 module. As far as I can tell, the GT bus and CCI400 bus clock must be protected. This patch adds driver support for peripheral related PLLs and bus clocks on the A80. The GT and CCI400 clocks are added as well as these 2 along with the PLLs they are clocked from must not be disabled. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- Documentation/devicetree/bindings/clock/sunxi.txt | 5 + drivers/clk/sunxi/Makefile | 1 + drivers/clk/sunxi/clk-sun9i-core.c | 271 ++++++++++++++++++++++ 3 files changed, 277 insertions(+) create mode 100644 drivers/clk/sunxi/clk-sun9i-core.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt index ed116df9c3e7..7f1c486691e0 100644 --- a/Documentation/devicetree/bindings/clock/sunxi.txt +++ b/Documentation/devicetree/bindings/clock/sunxi.txt @@ -10,14 +10,17 @@ Required properties: "allwinner,sun4i-a10-pll1-clk" - for the main PLL clock and PLL4 "allwinner,sun6i-a31-pll1-clk" - for the main PLL clock on A31 "allwinner,sun8i-a23-pll1-clk" - for the main PLL clock on A23 + "allwinner,sun9i-a80-pll4-clk" - for the peripheral PLLs on A80 "allwinner,sun4i-a10-pll5-clk" - for the PLL5 clock "allwinner,sun4i-a10-pll6-clk" - for the PLL6 clock "allwinner,sun6i-a31-pll6-clk" - for the PLL6 clock on A31 + "allwinner,sun9i-a80-gt-clk" - for the GT bus clock on A80 "allwinner,sun4i-a10-cpu-clk" - for the CPU multiplexer clock "allwinner,sun4i-a10-axi-clk" - for the AXI clock "allwinner,sun8i-a23-axi-clk" - for the AXI clock on A23 "allwinner,sun4i-a10-axi-gates-clk" - for the AXI gates "allwinner,sun4i-a10-ahb-clk" - for the AHB clock + "allwinner,sun9i-a80-ahb-clk" - for the AHB bus clocks on A80 "allwinner,sun4i-a10-ahb-gates-clk" - for the AHB gates on A10 "allwinner,sun5i-a13-ahb-gates-clk" - for the AHB gates on A13 "allwinner,sun5i-a10s-ahb-gates-clk" - for the AHB gates on A10s @@ -29,6 +32,7 @@ Required properties: "allwinner,sun4i-a10-apb0-clk" - for the APB0 clock "allwinner,sun6i-a31-apb0-clk" - for the APB0 clock on A31 "allwinner,sun8i-a23-apb0-clk" - for the APB0 clock on A23 + "allwinner,sun9i-a80-apb0-clk" - for the APB0 bus clock on A80 "allwinner,sun4i-a10-apb0-gates-clk" - for the APB0 gates on A10 "allwinner,sun5i-a13-apb0-gates-clk" - for the APB0 gates on A13 "allwinner,sun5i-a10s-apb0-gates-clk" - for the APB0 gates on A10s @@ -36,6 +40,7 @@ Required properties: "allwinner,sun7i-a20-apb0-gates-clk" - for the APB0 gates on A20 "allwinner,sun8i-a23-apb0-gates-clk" - for the APB0 gates on A23 "allwinner,sun4i-a10-apb1-clk" - for the APB1 clock + "allwinner,sun9i-a80-apb1-clk" - for the APB1 bus clock on A80 "allwinner,sun4i-a10-apb1-mux-clk" - for the APB1 clock muxing "allwinner,sun4i-a10-apb1-gates-clk" - for the APB1 gates on A10 "allwinner,sun5i-a13-apb1-gates-clk" - for the APB1 gates on A13 diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile index 7ddc2b553846..a66953c0f430 100644 --- a/drivers/clk/sunxi/Makefile +++ b/drivers/clk/sunxi/Makefile @@ -7,6 +7,7 @@ obj-y += clk-a10-hosc.o obj-y += clk-a20-gmac.o obj-y += clk-mod0.o obj-y += clk-sun8i-mbus.o +obj-y += clk-sun9i-core.o obj-$(CONFIG_MFD_SUN6I_PRCM) += \ clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o \ diff --git a/drivers/clk/sunxi/clk-sun9i-core.c b/drivers/clk/sunxi/clk-sun9i-core.c new file mode 100644 index 000000000000..3cb9036d91bb --- /dev/null +++ b/drivers/clk/sunxi/clk-sun9i-core.c @@ -0,0 +1,271 @@ +/* + * Copyright 2014 Chen-Yu Tsai + * + * Chen-Yu Tsai + * + * 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 "clk-factors.h" + + +/** + * sun9i_a80_get_pll4_factors() - calculates n, p, m factors for PLL1 + * PLL4 rate is calculated as follows + * rate = (parent_rate * n >> p) / (m + 1); + * parent_rate is always 24Mhz + * + * p and m are named div1 and div2 in Allwinner's SDK + */ + +static void sun9i_a80_get_pll4_factors(u32 *freq, u32 parent_rate, + u8 *n, u8 *k, u8 *m, u8 *p) +{ + int div; + + /* Normalize value to a 6M multiple */ + div = DIV_ROUND_UP(*freq, 6000000); + + /* divs above 256 cannot be odd */ + if (div > 256) + div = round_up(div, 2); + + /* divs above 512 must be a multiple of 4 */ + if (div > 512) + div = round_up(div, 4); + + *freq = 6000000 * div; + + /* we were called to round the frequency, we can now return */ + if (n == NULL) + return; + + /* p will be 1 for divs under 512 */ + if (div < 512) + *p = 1; + else + *p = 0; + + /* m will be 1 if div is odd */ + if (div & 1) + *m = 1; + else + *m = 0; + + /* calculate a suitable n based on m and p */ + *n = div / (*p + 1) / (*m + 1); +} + +static struct clk_factors_config sun9i_a80_pll4_config = { + .mshift = 18, + .mwidth = 1, + .nshift = 8, + .nwidth = 8, + .pshift = 16, + .pwidth = 1, +}; + +static const struct factors_data sun9i_a80_pll4_data __initconst = { + .enable = 31, + .table = &sun9i_a80_pll4_config, + .getter = sun9i_a80_get_pll4_factors, +}; + +static DEFINE_SPINLOCK(sun9i_a80_pll4_lock); + +static void __init sun9i_a80_pll4_setup(struct device_node *node) +{ + sunxi_factors_register(node, &sun9i_a80_pll4_data, &sun9i_a80_pll4_lock); +} +CLK_OF_DECLARE(sun9i_a80_pll4, "allwinner,sun9i-a80-pll4-clk", sun9i_a80_pll4_setup); + + +/** + * sun9i_a80_get_gt_factors() - calculates m factor for GT + * GT rate is calculated as follows + * rate = parent_rate / (m + 1); + */ + +static void sun9i_a80_get_gt_factors(u32 *freq, u32 parent_rate, + u8 *n, u8 *k, u8 *m, u8 *p) +{ + u32 div; + + if (parent_rate < *freq) + *freq = parent_rate; + + div = DIV_ROUND_UP(parent_rate, *freq); + + /* maximum divider is 4 */ + if (div > 4) + div = 4; + + *freq = parent_rate / div; + + /* we were called to round the frequency, we can now return */ + if (!m) + return; + + *m = div; +} + +static struct clk_factors_config sun9i_a80_gt_config = { + .mshift = 0, + .mwidth = 2, +}; + +static const struct factors_data sun9i_a80_gt_data __initconst = { + .mux = 24, + .muxmask = BIT(1) | BIT(0), + .table = &sun9i_a80_gt_config, + .getter = sun9i_a80_get_gt_factors, +}; + +static DEFINE_SPINLOCK(sun9i_a80_gt_lock); + +static void __init sun9i_a80_gt_setup(struct device_node *node) +{ + struct clk *gt = sunxi_factors_register(node, &sun9i_a80_gt_data, + &sun9i_a80_gt_lock); + + /* The GT bus clock needs to be always enabled */ + __clk_get(gt); + clk_prepare_enable(gt); +} +CLK_OF_DECLARE(sun9i_a80_gt, "allwinner,sun9i-a80-gt-clk", sun9i_a80_gt_setup); + + +/** + * sun9i_a80_get_ahb_factors() - calculates p factor for AHB0/1/2 + * AHB rate is calculated as follows + * rate = parent_rate >> p; + */ + +static void sun9i_a80_get_ahb_factors(u32 *freq, u32 parent_rate, + u8 *n, u8 *k, u8 *m, u8 *p) +{ + u32 _p; + + if (parent_rate < *freq) + *freq = parent_rate; + + _p = order_base_2(DIV_ROUND_UP(parent_rate, *freq)); + + /* maximum p is 3 */ + if (_p > 3) + _p = 3; + + *freq = parent_rate >> _p; + + /* we were called to round the frequency, we can now return */ + if (!p) + return; + + *p = _p; +} + +static struct clk_factors_config sun9i_a80_ahb_config = { + .pshift = 0, + .pwidth = 2, +}; + +static const struct factors_data sun9i_a80_ahb_data __initconst = { + .mux = 24, + .muxmask = BIT(1) | BIT(0), + .table = &sun9i_a80_ahb_config, + .getter = sun9i_a80_get_ahb_factors, +}; + +static DEFINE_SPINLOCK(sun9i_a80_ahb_lock); + +static void __init sun9i_a80_ahb_setup(struct device_node *node) +{ + sunxi_factors_register(node, &sun9i_a80_ahb_data, &sun9i_a80_ahb_lock); +} +CLK_OF_DECLARE(sun9i_a80_ahb, "allwinner,sun9i-a80-ahb-clk", sun9i_a80_ahb_setup); + + +static const struct factors_data sun9i_a80_apb0_data __initconst = { + .mux = 24, + .muxmask = BIT(0), + .table = &sun9i_a80_ahb_config, + .getter = sun9i_a80_get_ahb_factors, +}; + +static DEFINE_SPINLOCK(sun9i_a80_apb0_lock); + +static void __init sun9i_a80_apb0_setup(struct device_node *node) +{ + sunxi_factors_register(node, &sun9i_a80_apb0_data, &sun9i_a80_apb0_lock); +} +CLK_OF_DECLARE(sun9i_a80_apb0, "allwinner,sun9i-a80-apb0-clk", sun9i_a80_apb0_setup); + + +/** + * sun9i_a80_get_apb1_factors() - calculates m, p factors for APB1 + * APB1 rate is calculated as follows + * rate = (parent_rate >> p) / (m + 1); + */ + +static void sun9i_a80_get_apb1_factors(u32 *freq, u32 parent_rate, + u8 *n, u8 *k, u8 *m, u8 *p) +{ + u32 div; + u8 calcm, calcp; + + if (parent_rate < *freq) + *freq = parent_rate; + + div = DIV_ROUND_UP(parent_rate, *freq); + + /* Highest possible divider is 256 (p = 3, m = 31) */ + if (div > 256) + div = 256; + + calcp = order_base_2(div); + calcm = (parent_rate >> calcp) - 1; + *freq = (parent_rate >> calcp) / (calcm + 1); + + /* we were called to round the frequency, we can now return */ + if (n == NULL) + return; + + *m = calcm; + *p = calcp; +} + +static struct clk_factors_config sun9i_a80_apb1_config = { + .mshift = 0, + .mwidth = 5, + .pshift = 16, + .pwidth = 2, +}; + +static const struct factors_data sun9i_a80_apb1_data __initconst = { + .mux = 24, + .muxmask = BIT(0), + .table = &sun9i_a80_apb1_config, + .getter = sun9i_a80_get_apb1_factors, +}; + +static DEFINE_SPINLOCK(sun9i_a80_apb1_lock); + +static void __init sun9i_a80_apb1_setup(struct device_node *node) +{ + sunxi_factors_register(node, &sun9i_a80_apb1_data, &sun9i_a80_apb1_lock); +} +CLK_OF_DECLARE(sun9i_a80_apb1, "allwinner,sun9i-a80-apb1-clk", sun9i_a80_apb1_setup); -- cgit v1.2.3-59-g8ed1b From 0b0f08028e4e2d69edbe4bb073af26cd17505a04 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Mon, 20 Oct 2014 22:10:28 +0800 Subject: clk: sunxi: Add support for bus clock gates on Allwinner A80 SoC This adds the gate clocks for AHB/APB busses on the A80 SoC. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- Documentation/devicetree/bindings/clock/sunxi.txt | 5 ++++ drivers/clk/sunxi/clk-sunxi.c | 31 +++++++++++++++++++++++ 2 files changed, 36 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt index 7f1c486691e0..0455cb9caa97 100644 --- a/Documentation/devicetree/bindings/clock/sunxi.txt +++ b/Documentation/devicetree/bindings/clock/sunxi.txt @@ -29,6 +29,9 @@ Required properties: "allwinner,sun6i-a31-ahb1-mux-clk" - for the AHB1 multiplexer on A31 "allwinner,sun6i-a31-ahb1-gates-clk" - for the AHB1 gates on A31 "allwinner,sun8i-a23-ahb1-gates-clk" - for the AHB1 gates on A23 + "allwinner,sun9i-a80-ahb0-gates-clk" - for the AHB0 gates on A80 + "allwinner,sun9i-a80-ahb1-gates-clk" - for the AHB1 gates on A80 + "allwinner,sun9i-a80-ahb2-gates-clk" - for the AHB2 gates on A80 "allwinner,sun4i-a10-apb0-clk" - for the APB0 clock "allwinner,sun6i-a31-apb0-clk" - for the APB0 clock on A31 "allwinner,sun8i-a23-apb0-clk" - for the APB0 clock on A23 @@ -39,6 +42,7 @@ Required properties: "allwinner,sun6i-a31-apb0-gates-clk" - for the APB0 gates on A31 "allwinner,sun7i-a20-apb0-gates-clk" - for the APB0 gates on A20 "allwinner,sun8i-a23-apb0-gates-clk" - for the APB0 gates on A23 + "allwinner,sun9i-a80-apb0-gates-clk" - for the APB0 gates on A80 "allwinner,sun4i-a10-apb1-clk" - for the APB1 clock "allwinner,sun9i-a80-apb1-clk" - for the APB1 bus clock on A80 "allwinner,sun4i-a10-apb1-mux-clk" - for the APB1 clock muxing @@ -48,6 +52,7 @@ Required properties: "allwinner,sun6i-a31-apb1-gates-clk" - for the APB1 gates on A31 "allwinner,sun7i-a20-apb1-gates-clk" - for the APB1 gates on A20 "allwinner,sun8i-a23-apb1-gates-clk" - for the APB1 gates on A23 + "allwinner,sun9i-a80-apb1-gates-clk" - for the APB1 gates on A80 "allwinner,sun6i-a31-apb2-div-clk" - for the APB2 gates on A31 "allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31 "allwinner,sun8i-a23-apb2-gates-clk" - for the APB2 gates on A23 diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c index 636b8d772d4a..20f47c68a946 100644 --- a/drivers/clk/sunxi/clk-sunxi.c +++ b/drivers/clk/sunxi/clk-sunxi.c @@ -758,6 +758,18 @@ static const struct gates_data sun8i_a23_ahb1_gates_data __initconst = { .mask = {0x25386742, 0x2505111}, }; +static const struct gates_data sun9i_a80_ahb0_gates_data __initconst = { + .mask = {0xF5F12B}, +}; + +static const struct gates_data sun9i_a80_ahb1_gates_data __initconst = { + .mask = {0x1E20003}, +}; + +static const struct gates_data sun9i_a80_ahb2_gates_data __initconst = { + .mask = {0x9B7}, +}; + static const struct gates_data sun4i_apb0_gates_data __initconst = { .mask = {0x4EF}, }; @@ -774,6 +786,10 @@ static const struct gates_data sun7i_a20_apb0_gates_data __initconst = { .mask = { 0x4ff }, }; +static const struct gates_data sun9i_a80_apb0_gates_data __initconst = { + .mask = {0xEB822}, +}; + static const struct gates_data sun4i_apb1_gates_data __initconst = { .mask = {0xFF00F7}, }; @@ -802,6 +818,10 @@ static const struct gates_data sun7i_a20_apb1_gates_data __initconst = { .mask = { 0xff80ff }, }; +static const struct gates_data sun9i_a80_apb1_gates_data __initconst = { + .mask = {0x3F001F}, +}; + static const struct gates_data sun8i_a23_apb2_gates_data __initconst = { .mask = {0x1F0007}, }; @@ -1103,16 +1123,21 @@ static const struct of_device_id clk_gates_match[] __initconst = { {.compatible = "allwinner,sun6i-a31-ahb1-gates-clk", .data = &sun6i_a31_ahb1_gates_data,}, {.compatible = "allwinner,sun7i-a20-ahb-gates-clk", .data = &sun7i_a20_ahb_gates_data,}, {.compatible = "allwinner,sun8i-a23-ahb1-gates-clk", .data = &sun8i_a23_ahb1_gates_data,}, + {.compatible = "allwinner,sun9i-a80-ahb0-gates-clk", .data = &sun9i_a80_ahb0_gates_data,}, + {.compatible = "allwinner,sun9i-a80-ahb1-gates-clk", .data = &sun9i_a80_ahb1_gates_data,}, + {.compatible = "allwinner,sun9i-a80-ahb2-gates-clk", .data = &sun9i_a80_ahb2_gates_data,}, {.compatible = "allwinner,sun4i-a10-apb0-gates-clk", .data = &sun4i_apb0_gates_data,}, {.compatible = "allwinner,sun5i-a10s-apb0-gates-clk", .data = &sun5i_a10s_apb0_gates_data,}, {.compatible = "allwinner,sun5i-a13-apb0-gates-clk", .data = &sun5i_a13_apb0_gates_data,}, {.compatible = "allwinner,sun7i-a20-apb0-gates-clk", .data = &sun7i_a20_apb0_gates_data,}, + {.compatible = "allwinner,sun9i-a80-apb0-gates-clk", .data = &sun9i_a80_apb0_gates_data,}, {.compatible = "allwinner,sun4i-a10-apb1-gates-clk", .data = &sun4i_apb1_gates_data,}, {.compatible = "allwinner,sun5i-a10s-apb1-gates-clk", .data = &sun5i_a10s_apb1_gates_data,}, {.compatible = "allwinner,sun5i-a13-apb1-gates-clk", .data = &sun5i_a13_apb1_gates_data,}, {.compatible = "allwinner,sun6i-a31-apb1-gates-clk", .data = &sun6i_a31_apb1_gates_data,}, {.compatible = "allwinner,sun7i-a20-apb1-gates-clk", .data = &sun7i_a20_apb1_gates_data,}, {.compatible = "allwinner,sun8i-a23-apb1-gates-clk", .data = &sun8i_a23_apb1_gates_data,}, + {.compatible = "allwinner,sun9i-a80-apb1-gates-clk", .data = &sun9i_a80_apb1_gates_data,}, {.compatible = "allwinner,sun6i-a31-apb2-gates-clk", .data = &sun6i_a31_apb2_gates_data,}, {.compatible = "allwinner,sun8i-a23-apb2-gates-clk", .data = &sun8i_a23_apb2_gates_data,}, {.compatible = "allwinner,sun4i-a10-usb-clk", .data = &sun4i_a10_usb_gates_data,}, @@ -1201,3 +1226,9 @@ static void __init sun6i_init_clocks(struct device_node *node) } CLK_OF_DECLARE(sun6i_a31_clk_init, "allwinner,sun6i-a31", sun6i_init_clocks); CLK_OF_DECLARE(sun8i_a23_clk_init, "allwinner,sun8i-a23", sun6i_init_clocks); + +static void __init sun9i_init_clocks(struct device_node *node) +{ + sunxi_init_clocks(NULL, 0); +} +CLK_OF_DECLARE(sun9i_a80_clk_init, "allwinner,sun9i-a80", sun9i_init_clocks); -- cgit v1.2.3-59-g8ed1b From 9c350066a709f7ee3d1219e9888252daf547af99 Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Sat, 27 Sep 2014 21:34:30 +0200 Subject: mtd: docg3: add device-tree documentation Add documentation for the sandisk docg3 chip. Signed-off-by: Robert Jarzmik Cc: devicetree@vger.kernel.org Cc: Mark Rutland Signed-off-by: Brian Norris --- Documentation/devicetree/bindings/mtd/diskonchip.txt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 Documentation/devicetree/bindings/mtd/diskonchip.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mtd/diskonchip.txt b/Documentation/devicetree/bindings/mtd/diskonchip.txt new file mode 100644 index 000000000000..3e13bfdbea5b --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/diskonchip.txt @@ -0,0 +1,15 @@ +M-Systems and Sandisk DiskOnChip devices + +M-System DiskOnChip G3 +====================== +The Sandisk (formerly M-Systems) docg3 is a nand device of 64M to 256MB. + +Required properties: + - compatible: should be "m-systems,diskonchip-g3" + - reg: register base and size + +Example: + docg3: flash@0 { + compatible = "m-systems,diskonchip-g3"; + reg = <0x0 0x2000>; + }; -- cgit v1.2.3-59-g8ed1b From 5f9f975b7984ffec0a25f55e58246aebf68794f4 Mon Sep 17 00:00:00 2001 From: Mark Knibbs Date: Sat, 4 Oct 2014 12:19:59 +0100 Subject: USB: serial: keyspan_pda: fix Entrega company name spelling Entrega is misspelled as Entregra or Entrgra, so fix that. Signed-off-by: Mark Knibbs Signed-off-by: Johan Hovold --- Documentation/usb/usb-serial.txt | 2 +- drivers/usb/serial/Kconfig | 4 ++-- drivers/usb/serial/keyspan_pda.c | 16 ++++++++-------- 3 files changed, 11 insertions(+), 11 deletions(-) (limited to 'Documentation') diff --git a/Documentation/usb/usb-serial.txt b/Documentation/usb/usb-serial.txt index 5bd7926185e8..947fa62bccf2 100644 --- a/Documentation/usb/usb-serial.txt +++ b/Documentation/usb/usb-serial.txt @@ -145,7 +145,7 @@ Keyspan PDA Serial Adapter Single port DB-9 serial adapter, pushed as a PDA adapter for iMacs (mostly sold in Macintosh catalogs, comes in a translucent white/green dongle). Fairly simple device. Firmware is homebrew. - This driver also works for the Xircom/Entrgra single port serial adapter. + This driver also works for the Xircom/Entrega single port serial adapter. Current status: Things that work: diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index a69f7cd9d0bf..d185613bbd7d 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -606,10 +606,10 @@ config USB_SERIAL_CYBERJACK If unsure, say N. config USB_SERIAL_XIRCOM - tristate "USB Xircom / Entregra Single Port Serial Driver" + tristate "USB Xircom / Entrega Single Port Serial Driver" select USB_EZUSB_FX2 help - Say Y here if you want to use a Xircom or Entregra single port USB to + Say Y here if you want to use a Xircom or Entrega single port USB to serial converter device. This driver makes use of firmware developed from scratch by Brian Warner. diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index 742d827f876c..dd97d8b572c3 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -1,5 +1,5 @@ /* - * USB Keyspan PDA / Xircom / Entregra Converter driver + * USB Keyspan PDA / Xircom / Entrega Converter driver * * Copyright (C) 1999 - 2001 Greg Kroah-Hartman * Copyright (C) 1999, 2000 Brian Warner @@ -58,11 +58,11 @@ struct keyspan_pda_private { #define KEYSPAN_PDA_FAKE_ID 0x0103 #define KEYSPAN_PDA_ID 0x0104 /* no clue */ -/* For Xircom PGSDB9 and older Entregra version of the same device */ +/* For Xircom PGSDB9 and older Entrega version of the same device */ #define XIRCOM_VENDOR_ID 0x085a #define XIRCOM_FAKE_ID 0x8027 -#define ENTREGRA_VENDOR_ID 0x1645 -#define ENTREGRA_FAKE_ID 0x8093 +#define ENTREGA_VENDOR_ID 0x1645 +#define ENTREGA_FAKE_ID 0x8093 static const struct usb_device_id id_table_combined[] = { #ifdef KEYSPAN @@ -70,7 +70,7 @@ static const struct usb_device_id id_table_combined[] = { #endif #ifdef XIRCOM { USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID) }, - { USB_DEVICE(ENTREGRA_VENDOR_ID, ENTREGRA_FAKE_ID) }, + { USB_DEVICE(ENTREGA_VENDOR_ID, ENTREGA_FAKE_ID) }, #endif { USB_DEVICE(KEYSPAN_VENDOR_ID, KEYSPAN_PDA_ID) }, { } /* Terminating entry */ @@ -93,7 +93,7 @@ static const struct usb_device_id id_table_fake[] = { #ifdef XIRCOM static const struct usb_device_id id_table_fake_xircom[] = { { USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID) }, - { USB_DEVICE(ENTREGRA_VENDOR_ID, ENTREGRA_FAKE_ID) }, + { USB_DEVICE(ENTREGA_VENDOR_ID, ENTREGA_FAKE_ID) }, { } }; #endif @@ -667,7 +667,7 @@ static int keyspan_pda_fake_startup(struct usb_serial *serial) #endif #ifdef XIRCOM else if ((le16_to_cpu(serial->dev->descriptor.idVendor) == XIRCOM_VENDOR_ID) || - (le16_to_cpu(serial->dev->descriptor.idVendor) == ENTREGRA_VENDOR_ID)) + (le16_to_cpu(serial->dev->descriptor.idVendor) == ENTREGA_VENDOR_ID)) fw_name = "keyspan_pda/xircom_pgs.fw"; #endif else { @@ -744,7 +744,7 @@ static struct usb_serial_driver xircom_pgs_fake_device = { .owner = THIS_MODULE, .name = "xircom_no_firm", }, - .description = "Xircom / Entregra PGS - (prerenumeration)", + .description = "Xircom / Entrega PGS - (prerenumeration)", .id_table = id_table_fake_xircom, .num_ports = 1, .attach = keyspan_pda_fake_startup, -- cgit v1.2.3-59-g8ed1b From 5e3363ad1b7b2e1f197a3f56b01e21cb155ad454 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Thu, 16 Oct 2014 11:24:26 -0700 Subject: ASoC: rt5677: add GPIO IRQ support This allows to enable Mic Jack detection feature Signed-off-by: Oder Chiou Modified-by: Anatol Pomozov Signed-off-by: Anatol Pomozov Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/rt5677.txt | 10 ++ include/sound/rt5677.h | 7 ++ sound/soc/codecs/rt5677.c | 134 +++++++++++++++++++++ sound/soc/codecs/rt5677.h | 49 ++++++++ 4 files changed, 200 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/rt5677.txt b/Documentation/devicetree/bindings/sound/rt5677.txt index f82f0e906cd9..740ff771aa8b 100644 --- a/Documentation/devicetree/bindings/sound/rt5677.txt +++ b/Documentation/devicetree/bindings/sound/rt5677.txt @@ -33,6 +33,15 @@ Optional properties: 1 - pull down 2 - pull up +- realtek,jd1-gpio + Configures GPIO Mic Jack detection 1. + Select 0 ~ 3 as OFF, GPIO1, GPIO2 and GPIO3 respectively. + +- realtek,jd2-gpio +- realtek,jd3-gpio + Configures GPIO Mic Jack detection 2 and 3. + Select 0 ~ 3 as OFF, GPIO4, GPIO5 and GPIO6 respectively. + Pins on the device (for linking into audio routes): * IN1P @@ -63,4 +72,5 @@ rt5677 { <&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>; realtek,in1-differential = "true"; realtek,gpio-config = /bits/ 8 <0 0 0 0 0 2>; /* pull up GPIO6 */ + realtek,jd2-gpio = <3>; /* Enables Jack detection for GPIO6 */ }; diff --git a/include/sound/rt5677.h b/include/sound/rt5677.h index a56b429a1dbc..d9eb7d861cd0 100644 --- a/include/sound/rt5677.h +++ b/include/sound/rt5677.h @@ -30,6 +30,13 @@ struct rt5677_platform_data { /* configures GPIO, 0 - floating, 1 - pulldown, 2 - pullup */ u8 gpio_config[6]; + + /* jd1 can select 0 ~ 3 as OFF, GPIO1, GPIO2 and GPIO3 respectively */ + unsigned int jd1_gpio; + /* jd2 and jd3 can select 0 ~ 3 as + OFF, GPIO4, GPIO5 and GPIO6 respectively */ + unsigned int jd2_gpio; + unsigned int jd3_gpio; }; #endif diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index d17d079fdcf3..6c73dfd22a0c 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -3614,6 +3614,46 @@ static void rt5677_gpio_config(struct rt5677_priv *rt5677, unsigned offset, } } +static int rt5677_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct rt5677_priv *rt5677 = gpio_to_rt5677(chip); + struct regmap_irq_chip_data *data = rt5677->irq_data; + int irq; + + if (offset >= RT5677_GPIO1 && offset <= RT5677_GPIO3) { + if ((rt5677->pdata.jd1_gpio == 1 && offset == RT5677_GPIO1) || + (rt5677->pdata.jd1_gpio == 2 && + offset == RT5677_GPIO2) || + (rt5677->pdata.jd1_gpio == 3 && + offset == RT5677_GPIO3)) { + irq = RT5677_IRQ_JD1; + } else { + return -ENXIO; + } + } + + if (offset >= RT5677_GPIO4 && offset <= RT5677_GPIO6) { + if ((rt5677->pdata.jd2_gpio == 1 && offset == RT5677_GPIO4) || + (rt5677->pdata.jd2_gpio == 2 && + offset == RT5677_GPIO5) || + (rt5677->pdata.jd2_gpio == 3 && + offset == RT5677_GPIO6)) { + irq = RT5677_IRQ_JD2; + } else if ((rt5677->pdata.jd3_gpio == 1 && + offset == RT5677_GPIO4) || + (rt5677->pdata.jd3_gpio == 2 && + offset == RT5677_GPIO5) || + (rt5677->pdata.jd3_gpio == 3 && + offset == RT5677_GPIO6)) { + irq = RT5677_IRQ_JD3; + } else { + return -ENXIO; + } + } + + return regmap_irq_get_virq(data, irq); +} + static struct gpio_chip rt5677_template_chip = { .label = "rt5677", .owner = THIS_MODULE, @@ -3621,6 +3661,7 @@ static struct gpio_chip rt5677_template_chip = { .set = rt5677_gpio_set, .direction_input = rt5677_gpio_direction_in, .get = rt5677_gpio_get, + .to_irq = rt5677_to_irq, .can_sleep = 1, }; @@ -3685,6 +3726,31 @@ static int rt5677_probe(struct snd_soc_codec *codec) for (i = 0; i < RT5677_GPIO_NUM; i++) rt5677_gpio_config(rt5677, i, rt5677->pdata.gpio_config[i]); + if (rt5677->irq_data) { + regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL1, 0x8000, + 0x8000); + regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, 0x0018, + 0x0008); + + if (rt5677->pdata.jd1_gpio) + regmap_update_bits(rt5677->regmap, RT5677_JD_CTRL1, + RT5677_SEL_GPIO_JD1_MASK, + rt5677->pdata.jd1_gpio << + RT5677_SEL_GPIO_JD1_SFT); + + if (rt5677->pdata.jd2_gpio) + regmap_update_bits(rt5677->regmap, RT5677_JD_CTRL1, + RT5677_SEL_GPIO_JD2_MASK, + rt5677->pdata.jd2_gpio << + RT5677_SEL_GPIO_JD2_SFT); + + if (rt5677->pdata.jd3_gpio) + regmap_update_bits(rt5677->regmap, RT5677_JD_CTRL1, + RT5677_SEL_GPIO_JD3_MASK, + rt5677->pdata.jd3_gpio << + RT5677_SEL_GPIO_JD3_SFT); + } + mutex_init(&rt5677->dsp_cmd_lock); return 0; @@ -3915,9 +3981,74 @@ static int rt5677_parse_dt(struct rt5677_priv *rt5677, struct device_node *np) of_property_read_u8_array(np, "realtek,gpio-config", rt5677->pdata.gpio_config, RT5677_GPIO_NUM); + of_property_read_u32(np, "realtek,jd1-gpio", &rt5677->pdata.jd1_gpio); + of_property_read_u32(np, "realtek,jd2-gpio", &rt5677->pdata.jd2_gpio); + of_property_read_u32(np, "realtek,jd3-gpio", &rt5677->pdata.jd3_gpio); + return 0; } +static struct regmap_irq rt5677_irqs[] = { + [RT5677_IRQ_JD1] = { + .reg_offset = 0, + .mask = RT5677_EN_IRQ_GPIO_JD1, + }, + [RT5677_IRQ_JD2] = { + .reg_offset = 0, + .mask = RT5677_EN_IRQ_GPIO_JD2, + }, + [RT5677_IRQ_JD3] = { + .reg_offset = 0, + .mask = RT5677_EN_IRQ_GPIO_JD3, + }, +}; + +static struct regmap_irq_chip rt5677_irq_chip = { + .name = "rt5677", + .irqs = rt5677_irqs, + .num_irqs = ARRAY_SIZE(rt5677_irqs), + + .num_regs = 1, + .status_base = RT5677_IRQ_CTRL1, + .mask_base = RT5677_IRQ_CTRL1, + .mask_invert = 1, +}; + +int rt5677_irq_init(struct i2c_client *i2c) +{ + int ret; + struct rt5677_priv *rt5677 = i2c_get_clientdata(i2c); + + if (!rt5677->pdata.jd1_gpio && + !rt5677->pdata.jd2_gpio && + !rt5677->pdata.jd3_gpio) + return 0; + + if (!i2c->irq) { + dev_err(&i2c->dev, "No interrupt specified\n"); + return -EINVAL; + } + + ret = regmap_add_irq_chip(rt5677->regmap, i2c->irq, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 0, + &rt5677_irq_chip, &rt5677->irq_data); + + if (ret != 0) { + dev_err(&i2c->dev, "Failed to register IRQ chip: %d\n", ret); + return ret; + } + + return 0; +} + +void rt5677_irq_exit(struct i2c_client *i2c) +{ + struct rt5677_priv *rt5677 = i2c_get_clientdata(i2c); + + if (rt5677->irq_data) + regmap_del_irq_chip(i2c->irq, rt5677->irq_data); +} + static int rt5677_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -4015,6 +4146,7 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, } rt5677_init_gpio(i2c); + rt5677_irq_init(i2c); return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5677, rt5677_dai, ARRAY_SIZE(rt5677_dai)); @@ -4022,6 +4154,8 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, static int rt5677_i2c_remove(struct i2c_client *i2c) { + rt5677_irq_exit(i2c); + snd_soc_unregister_codec(&i2c->dev); rt5677_free_gpio(i2c); diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h index 20efa4a4c82c..d2c743c255a1 100644 --- a/sound/soc/codecs/rt5677.h +++ b/sound/soc/codecs/rt5677.h @@ -1368,6 +1368,48 @@ #define RT5677_SEL_SRC_IB01 (0x1 << 0) #define RT5677_SEL_SRC_IB01_SFT 0 +/* Jack Detect Control 1 (0xb5) */ +#define RT5677_SEL_GPIO_JD1_MASK (0x3 << 14) +#define RT5677_SEL_GPIO_JD1_SFT 14 +#define RT5677_SEL_GPIO_JD2_MASK (0x3 << 12) +#define RT5677_SEL_GPIO_JD2_SFT 12 +#define RT5677_SEL_GPIO_JD3_MASK (0x3 << 10) +#define RT5677_SEL_GPIO_JD3_SFT 10 + +/* IRQ Control 1 (0xbd) */ +#define RT5677_STA_GPIO_JD1 (0x1 << 15) +#define RT5677_STA_GPIO_JD1_SFT 15 +#define RT5677_EN_IRQ_GPIO_JD1 (0x1 << 14) +#define RT5677_EN_IRQ_GPIO_JD1_SFT 14 +#define RT5677_EN_GPIO_JD1_STICKY (0x1 << 13) +#define RT5677_EN_GPIO_JD1_STICKY_SFT 13 +#define RT5677_INV_GPIO_JD1 (0x1 << 12) +#define RT5677_INV_GPIO_JD1_SFT 12 +#define RT5677_STA_GPIO_JD2 (0x1 << 11) +#define RT5677_STA_GPIO_JD2_SFT 11 +#define RT5677_EN_IRQ_GPIO_JD2 (0x1 << 10) +#define RT5677_EN_IRQ_GPIO_JD2_SFT 10 +#define RT5677_EN_GPIO_JD2_STICKY (0x1 << 9) +#define RT5677_EN_GPIO_JD2_STICKY_SFT 9 +#define RT5677_INV_GPIO_JD2 (0x1 << 8) +#define RT5677_INV_GPIO_JD2_SFT 8 +#define RT5677_STA_MICBIAS1_OVCD (0x1 << 7) +#define RT5677_STA_MICBIAS1_OVCD_SFT 7 +#define RT5677_EN_IRQ_MICBIAS1_OVCD (0x1 << 6) +#define RT5677_EN_IRQ_MICBIAS1_OVCD_SFT 6 +#define RT5677_EN_MICBIAS1_OVCD_STICKY (0x1 << 5) +#define RT5677_EN_MICBIAS1_OVCD_STICKY_SFT 5 +#define RT5677_INV_MICBIAS1_OVCD (0x1 << 4) +#define RT5677_INV_MICBIAS1_OVCD_SFT 4 +#define RT5677_STA_GPIO_JD3 (0x1 << 3) +#define RT5677_STA_GPIO_JD3_SFT 3 +#define RT5677_EN_IRQ_GPIO_JD3 (0x1 << 2) +#define RT5677_EN_IRQ_GPIO_JD3_SFT 2 +#define RT5677_EN_GPIO_JD3_STICKY (0x1 << 1) +#define RT5677_EN_GPIO_JD3_STICKY_SFT 1 +#define RT5677_INV_GPIO_JD3 (0x1 << 0) +#define RT5677_INV_GPIO_JD3_SFT 0 + /* GPIO status (0xbf) */ #define RT5677_GPIO6_STATUS_MASK (0x1 << 5) #define RT5677_GPIO6_STATUS_SFT 5 @@ -1545,6 +1587,12 @@ enum { RT5677_GPIO_NUM, }; +enum { + RT5677_IRQ_JD1, + RT5677_IRQ_JD2, + RT5677_IRQ_JD3, +}; + struct rt5677_priv { struct snd_soc_codec *codec; struct rt5677_platform_data pdata; @@ -1565,6 +1613,7 @@ struct rt5677_priv { struct gpio_chip gpio_chip; #endif bool dsp_vad_en; + struct regmap_irq_chip_data *irq_data; }; #endif /* __RT5677_H__ */ -- cgit v1.2.3-59-g8ed1b From f123a66cbdc47e31bcb11b59f935bed89343a8ed Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 1 Oct 2014 09:30:45 +0200 Subject: ARM: realview: add device tree and bindings for PB1176 As a first example, add device tree and bindings for the RealView PB1176. Signed-off-by: Linus Walleij --- Documentation/devicetree/bindings/arm/arm-boards | 65 ++++++ Documentation/devicetree/bindings/arm/gic.txt | 1 + arch/arm/boot/dts/Makefile | 1 + arch/arm/boot/dts/arm-realview-pb1176.dts | 247 +++++++++++++++++++++++ 4 files changed, 314 insertions(+) create mode 100644 arch/arm/boot/dts/arm-realview-pb1176.dts (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/arm-boards b/Documentation/devicetree/bindings/arm/arm-boards index c554ed3d44fb..556c8665fdbf 100644 --- a/Documentation/devicetree/bindings/arm/arm-boards +++ b/Documentation/devicetree/bindings/arm/arm-boards @@ -92,3 +92,68 @@ Required nodes: - core-module: the root node to the Versatile platforms must have a core-module with regs and the compatible strings "arm,core-module-versatile", "syscon" + +ARM RealView Boards +------------------- +The RealView boards cover tailored evaluation boards that are used to explore +the ARM11 and Cortex A-8 and Cortex A-9 processors. + +Required properties (in root node): + /* RealView Emulation Baseboard */ + compatible = "arm,realview-eb"; + /* RealView Platform Baseboard for ARM1176JZF-S */ + compatible = "arm,realview-pb1176"; + /* RealView Platform Baseboard for ARM11 MPCore */ + compatible = "arm,realview-pb11mp"; + /* RealView Platform Baseboard for Cortex A-8 */ + compatible = "arm,realview-pba8"; + /* RealView Platform Baseboard Explore for Cortex A-9 */ + compatible = "arm,realview-pbx"; + +Required nodes: + +- soc: some node of the RealView platforms must be the SoC + node that contain the SoC-specific devices, withe the compatible + string set to one of these tuples: + "arm,realview-eb-soc", "simple-bus" + "arm,realview-pb1176-soc", "simple-bus" + "arm,realview-pb11mp-soc", "simple-bus" + "arm,realview-pba8-soc", "simple-bus" + "arm,realview-pbx-soc", "simple-bus" + +- syscon: some subnode of the RealView SoC node must be a + system controller node pointing to the control registers, + with the compatible string set to one of these tuples: + "arm,realview-eb-syscon", "syscon" + "arm,realview-pb1176-syscon", "syscon" + "arm,realview-pb11mp-syscon", "syscon" + "arm,realview-pba8-syscon", "syscon" + "arm,realview-pbx-syscon", "syscon" + + Required properties for the system controller: + - regs: the location and size of the system controller registers, + one range of 0x1000 bytes. + +Example: + +/dts-v1/; +#include +#include "skeleton.dtsi" + +/ { + model = "ARM RealView PB1176 with device tree"; + compatible = "arm,realview-pb1176"; + + soc { + #address-cells = <1>; + #size-cells = <1>; + compatible = "arm,realview-pb1176-soc", "simple-bus"; + ranges; + + syscon: syscon@10000000 { + compatible = "arm,realview-syscon", "syscon"; + reg = <0x10000000 0x1000>; + }; + + }; +}; diff --git a/Documentation/devicetree/bindings/arm/gic.txt b/Documentation/devicetree/bindings/arm/gic.txt index c7d2fa156678..b38608af66db 100644 --- a/Documentation/devicetree/bindings/arm/gic.txt +++ b/Documentation/devicetree/bindings/arm/gic.txt @@ -17,6 +17,7 @@ Main node required properties: "arm,cortex-a7-gic" "arm,arm11mp-gic" "brcm,brahma-b15-gic" + "arm,arm1176jzf-devchip-gic" - interrupt-controller : Identifies the node as an interrupt controller - #interrupt-cells : Specifies the number of cells needed to encode an interrupt source. The type shall be a and the value shall be 3. diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 38c89cafa1ab..ab4435a59cd1 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -363,6 +363,7 @@ dtb-$(CONFIG_ARCH_QCOM) += \ qcom-msm8660-surf.dtb \ qcom-msm8960-cdp.dtb \ qcom-msm8974-sony-xperia-honami.dtb +dtb-$(CONFIG_ARCH_REALVIEW) += arm-realview-pb1176.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += \ rk3066a-bqcurie2.dtb \ rk3188-radxarock.dtb \ diff --git a/arch/arm/boot/dts/arm-realview-pb1176.dts b/arch/arm/boot/dts/arm-realview-pb1176.dts new file mode 100644 index 000000000000..3135939cd13f --- /dev/null +++ b/arch/arm/boot/dts/arm-realview-pb1176.dts @@ -0,0 +1,247 @@ +/* + * Copyright 2014 Linaro Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/dts-v1/; +#include +#include "skeleton.dtsi" + +/ { + model = "ARM RealView PB1176"; + compatible = "arm,realview-pb1176"; + + chosen { }; + + aliases { + serial0 = &pb1176_serial0; + serial1 = &pb1176_serial1; + serial2 = &pb1176_serial2; + serial3 = &pb1176_serial3; + }; + + memory { + /* 128 MiB memory @ 0x0 */ + reg = <0x00000000 0x08000000>; + }; + + xtal24mhz: xtal24mhz@24M { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <24000000>; + }; + + timclk: timclk@1M { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clock-div = <24>; + clock-mult = <1>; + clocks = <&xtal24mhz>; + }; + + uartclk: uartclk@24M { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clock-div = <1>; + clock-mult = <1>; + clocks = <&xtal24mhz>; + }; + + /* FIXME: this actually hangs off the PLL clocks */ + pclk: pclk@0 { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + soc { + #address-cells = <1>; + #size-cells = <1>; + compatible = "arm,realview-pb1176-soc", "simple-bus"; + regmap = <&syscon>; + ranges; + + syscon: syscon@10000000 { + compatible = "arm,realview-pb1176-syscon", "syscon"; + reg = <0x10000000 0x1000>; + + led@08.0 { + compatible = "register-bit-led"; + offset = <0x08>; + mask = <0x01>; + label = "versatile:0"; + linux,default-trigger = "heartbeat"; + default-state = "on"; + }; + led@08.1 { + compatible = "register-bit-led"; + offset = <0x08>; + mask = <0x02>; + label = "versatile:1"; + linux,default-trigger = "mmc0"; + default-state = "off"; + }; + led@08.2 { + compatible = "register-bit-led"; + offset = <0x08>; + mask = <0x04>; + label = "versatile:2"; + linux,default-trigger = "cpu0"; + default-state = "off"; + }; + led@08.3 { + compatible = "register-bit-led"; + offset = <0x08>; + mask = <0x08>; + label = "versatile:3"; + default-state = "off"; + }; + led@08.4 { + compatible = "register-bit-led"; + offset = <0x08>; + mask = <0x10>; + label = "versatile:4"; + default-state = "off"; + }; + led@08.5 { + compatible = "register-bit-led"; + offset = <0x08>; + mask = <0x20>; + label = "versatile:5"; + default-state = "off"; + }; + led@08.6 { + compatible = "register-bit-led"; + offset = <0x08>; + mask = <0x40>; + label = "versatile:6"; + default-state = "off"; + }; + led@08.7 { + compatible = "register-bit-led"; + offset = <0x08>; + mask = <0x80>; + label = "versatile:7"; + default-state = "off"; + }; + }; + + /* Primary DevChip GIC synthesized with the CPU */ + intc_dc1176: interrupt-controller@10120000 { + compatible = "arm,arm1176jzf-devchip-gic", "arm,arm11mp-gic"; + #interrupt-cells = <3>; + #address-cells = <1>; + interrupt-controller; + reg = <0x10121000 0x1000>, + <0x10120000 0x100>; + }; + + /* This GIC on the board is cascaded off the DevChip GIC */ + intc_pb1176: interrupt-controller@10040000 { + compatible = "arm,arm1176jzf-devchip-gic", "arm,arm11mp-gic"; + #interrupt-cells = <3>; + #address-cells = <1>; + interrupt-controller; + reg = <0x10041000 0x1000>, + <0x10040000 0x100>; + interrupt-parent = <&intc_dc1176>; + interrupts = <0 31 IRQ_TYPE_LEVEL_HIGH>; + }; + + L2: l2-cache { + compatible = "arm,l220-cache"; + reg = <0x10110000 0x1000>; + interrupt-parent = <&intc_dc1176>; + interrupts = <0 13 IRQ_TYPE_LEVEL_HIGH>; + cache-unified; + cache-level = <2>; + /* + * Override default cache size, sets and + * associativity as these may be erroneously set + * up by boot loader(s). + */ + arm,override-auxreg; + cache-size = <131072>; // 128kB + cache-sets = <512>; + cache-line-size = <32>; + }; + + pmu { + compatible = "arm,arm1176-pmu"; + interrupt-parent = <&intc_dc1176>; + interrupts = <0 7 IRQ_TYPE_LEVEL_HIGH>; + }; + + timer01: timer@10104000 { + compatible = "arm,sp804", "arm,primecell"; + reg = <0x10104000 0x1000>; + interrupt-parent = <&intc_dc1176>; + interrupts = <0 8 IRQ_TYPE_LEVEL_HIGH>, <0 9 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&timclk>, <&timclk>, <&pclk>; + clock-names = "timer1", "timer2", "apb_pclk"; + }; + + timer23: timer@10105000 { + compatible = "arm,sp804", "arm,primecell"; + reg = <0x10105000 0x1000>; + interrupt-parent = <&intc_dc1176>; + interrupts = <0 10 IRQ_TYPE_LEVEL_HIGH>; + arm,sp804-has-irq = <1>; + clocks = <&timclk>, <&timclk>, <&pclk>; + clock-names = "timer1", "timer2", "apb_pclk"; + }; + + pb1176_serial0: serial@1010c000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x1010c000 0x1000>; + interrupt-parent = <&intc_dc1176>; + interrupts = <0 18 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&uartclk>, <&pclk>; + clock-names = "uartclk", "apb_pclk"; + }; + + pb1176_serial1: serial@1010d000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x1010d000 0x1000>; + interrupt-parent = <&intc_dc1176>; + interrupts = <0 19 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&uartclk>, <&pclk>; + clock-names = "uartclk", "apb_pclk"; + }; + + pb1176_serial2: serial@1010e000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x1010e000 0x1000>; + interrupt-parent = <&intc_dc1176>; + interrupts = <0 20 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&uartclk>, <&pclk>; + clock-names = "uartclk", "apb_pclk"; + }; + + pb1176_serial3: serial@1010f000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x1010f000 0x1000>; + interrupt-parent = <&intc_dc1176>; + interrupts = <0 21 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&uartclk>, <&pclk>; + clock-names = "uartclk", "apb_pclk"; + }; + }; +}; -- cgit v1.2.3-59-g8ed1b From a88f5c6deb2a44f694b01aac48231ec97059b26a Mon Sep 17 00:00:00 2001 From: Romain Perier Date: Tue, 14 Oct 2014 06:31:12 +0000 Subject: dt-bindings: Document the standard property "poweroff-source" Signed-off-by: Romain Perier Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/power/poweroff.txt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 Documentation/devicetree/bindings/power/poweroff.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/power/poweroff.txt b/Documentation/devicetree/bindings/power/poweroff.txt new file mode 100644 index 000000000000..845868bf3273 --- /dev/null +++ b/Documentation/devicetree/bindings/power/poweroff.txt @@ -0,0 +1,18 @@ +* Generic Poweroff capability + +Power-management integrated circuits or miscellaneous harware components are +sometimes able to control the system power. The device driver associated to these +components might needs to define poweroff capability, which tells to the kernel +how to switch off the system. The corresponding driver must have the standard +property "poweroff-source" in its device node. This property marks the device as +able to shutdown the system. In order to test if this property is found +programmatically, use the helper function "of_system_has_poweroff_source" from +of.h . + +Example: + +act8846: act8846@5 { + compatible = "active-semi,act8846"; + status = "okay"; + poweroff-source; +} -- cgit v1.2.3-59-g8ed1b From 7a5f5d7b7ec6ccd2e907534e31c13ca63d2b497f Mon Sep 17 00:00:00 2001 From: Romain Perier Date: Tue, 14 Oct 2014 06:31:13 +0000 Subject: dt-bindings: Document the property poweroff-source for act8865 regulator Signed-off-by: Romain Perier Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/regulator/act8865-regulator.txt | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/regulator/act8865-regulator.txt b/Documentation/devicetree/bindings/regulator/act8865-regulator.txt index 865614b34d6f..01a5b0766e53 100644 --- a/Documentation/devicetree/bindings/regulator/act8865-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/act8865-regulator.txt @@ -5,6 +5,10 @@ Required properties: - compatible: "active-semi,act8846" or "active-semi,act8865" - reg: I2C slave address +Optional properties: +- poweroff-source: Telling whether or not this pmic is controlling + the system power. See Documentation/devicetree/bindings/power/poweroff.txt . + Any standard regulator properties can be used to configure the single regulator. The valid names for regulators are: -- cgit v1.2.3-59-g8ed1b From c22e15f352066e8ee4d662f4a721c2fd10590f81 Mon Sep 17 00:00:00 2001 From: Vlad Dogaru Date: Mon, 13 Oct 2014 14:53:00 +0100 Subject: iio: add ABI documentation for scaled pressure Signed-off-by: Vlad Dogaru Reviewed-by: Daniel Baluta Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 1ac9ac20f530..5a7fc666b07e 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -200,6 +200,13 @@ Description: Raw pressure measurement from channel Y. Units after application of scale and offset are kilopascal. +What: /sys/bus/iio/devices/iio:deviceX/in_pressureY_input +What: /sys/bus/iio/devices/iio:deviceX/in_pressure_input +KernelVersion: 3.8 +Contact: linux-iio@vger.kernel.org +Description: + Scaled pressure measurement from channel Y, in kilopascal. + What: /sys/bus/iio/devices/iio:deviceX/in_humidityrelative_raw KernelVersion: 3.14 Contact: linux-iio@vger.kernel.org -- cgit v1.2.3-59-g8ed1b From 580b9676e53af8f037002c16bafc7037319bbbce Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Thu, 16 Oct 2014 21:48:00 +0200 Subject: Documentation: dts: add bindings for Vybrid GPIO/PORT module The Vybrid SoC device tree (vf610.dtsi) used this bindings since its initial commit in May 2013. However, a proper gpiolib driver was missing so far. With the addition of the gpiolib driver, the bindings proved to be useful and complete, hence a good time to add the documentation. Signed-off-by: Stefan Agner Acked-by: Shawn Guo Signed-off-by: Linus Walleij --- .../devicetree/bindings/gpio/gpio-vf610.txt | 55 ++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpio/gpio-vf610.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/gpio/gpio-vf610.txt b/Documentation/devicetree/bindings/gpio/gpio-vf610.txt new file mode 100644 index 000000000000..436cc99c6598 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio-vf610.txt @@ -0,0 +1,55 @@ +* Freescale VF610 PORT/GPIO module + +The Freescale PORT/GPIO modules are two adjacent modules providing GPIO +functionality. Each pair serves 32 GPIOs. The VF610 has 5 instances of +each, and each PORT module has its own interrupt. + +Required properties for GPIO node: +- compatible : Should be "fsl,-gpio", currently "fsl,vf610-gpio" +- reg : The first reg tuple represents the PORT module, the second tuple + the GPIO module. +- interrupts : Should be the port interrupt shared by all 32 pins. +- gpio-controller : Marks the device node as a gpio controller. +- #gpio-cells : Should be two. The first cell is the pin number and + the second cell is used to specify the gpio polarity: + 0 = active high + 1 = active low +- interrupt-controller: Marks the device node as an interrupt controller. +- #interrupt-cells : Should be 2. The first cell is the GPIO number. + The second cell bits[3:0] is used to specify trigger type and level flags: + 1 = low-to-high edge triggered. + 2 = high-to-low edge triggered. + 4 = active high level-sensitive. + 8 = active low level-sensitive. + +Note: Each GPIO port should have an alias correctly numbered in "aliases" +node. + +Examples: + +aliases { + gpio0 = &gpio1; + gpio1 = &gpio2; +}; + +gpio1: gpio@40049000 { + compatible = "fsl,vf610-gpio"; + reg = <0x40049000 0x1000 0x400ff000 0x40>; + interrupts = <0 107 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-ranges = <&iomuxc 0 0 32>; +}; + +gpio2: gpio@4004a000 { + compatible = "fsl,vf610-gpio"; + reg = <0x4004a000 0x1000 0x400ff040 0x40>; + interrupts = <0 108 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-ranges = <&iomuxc 0 32 32>; +}; -- cgit v1.2.3-59-g8ed1b From 6696777c6506fa52b2a0282121195843ed855be6 Mon Sep 17 00:00:00 2001 From: Duson Lin Date: Fri, 3 Oct 2014 13:24:27 -0700 Subject: Input: add driver for Elan I2C/SMbus touchpad This driver supports Elan I2C/SMbus touchpads found in some laptops and also in many Chromebooks. Signed-off-by: Duson Lin Reviewed-by: Benson Leung Signed-off-by: Dmitry Torokhov --- .../devicetree/bindings/input/elan_i2c.txt | 34 + .../devicetree/bindings/vendor-prefixes.txt | 1 + drivers/input/mouse/Kconfig | 30 + drivers/input/mouse/Makefile | 5 + drivers/input/mouse/elan_i2c.h | 86 ++ drivers/input/mouse/elan_i2c_core.c | 1137 ++++++++++++++++++++ drivers/input/mouse/elan_i2c_i2c.c | 611 +++++++++++ drivers/input/mouse/elan_i2c_smbus.c | 514 +++++++++ 8 files changed, 2418 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/elan_i2c.txt create mode 100644 drivers/input/mouse/elan_i2c.h create mode 100644 drivers/input/mouse/elan_i2c_core.c create mode 100644 drivers/input/mouse/elan_i2c_i2c.c create mode 100644 drivers/input/mouse/elan_i2c_smbus.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/input/elan_i2c.txt b/Documentation/devicetree/bindings/input/elan_i2c.txt new file mode 100644 index 000000000000..ee3242c4ba67 --- /dev/null +++ b/Documentation/devicetree/bindings/input/elan_i2c.txt @@ -0,0 +1,34 @@ +Elantech I2C Touchpad + +Required properties: +- compatible: must be "elan,ekth3000". +- reg: I2C address of the chip. +- interrupt-parent: a phandle for the interrupt controller (see interrupt + binding[0]). +- interrupts: interrupt to which the chip is connected (see interrupt + binding[0]). + +Optional properties: +- wakeup-source: touchpad can be used as a wakeup source. +- pinctrl-names: should be "default" (see pinctrl binding [1]). +- pinctrl-0: a phandle pointing to the pin settings for the device (see + pinctrl binding [1]). +- vcc-supply: a phandle for the regulator supplying 3.3V power. + +[0]: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt +[1]: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt + +Example: + &i2c1 { + /* ... */ + + touchpad@15 { + compatible = "elan,ekth3000"; + reg = <0x15>; + interrupt-parent = <&gpio4>; + interrupts = <0x0 IRQ_TYPE_EDGE_FALLING>; + wakeup-source; + }; + + /* ... */ + }; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index ac7269f90764..e6469ec7a90e 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -42,6 +42,7 @@ dlink D-Link Corporation dmo Data Modul AG ebv EBV Elektronik edt Emerging Display Technologies +elan Elan Microelectronic Corp. emmicro EM Microelectronic epcos EPCOS AG epfl Ecole Polytechnique Fédérale de Lausanne diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index 366fc7ad5eb6..d8b46b0f2dbe 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig @@ -215,6 +215,36 @@ config MOUSE_CYAPA To compile this driver as a module, choose M here: the module will be called cyapa. +config MOUSE_ELAN_I2C + tristate "ELAN I2C Touchpad support" + depends on I2C + help + This driver adds support for Elan I2C/SMbus Trackpads. + + Say Y here if you have a ELAN I2C/SMbus Touchpad. + + To compile this driver as a module, choose M here: the module will be + called elan_i2c. + +config MOUSE_ELAN_I2C_I2C + bool "Enable I2C support" + depends on MOUSE_ELAN_I2C + default y + help + Say Y here if Elan Touchpad in your system is connected to + a standard I2C controller. + + If unsure, say Y. + +config MOUSE_ELAN_I2C_SMBUS + bool "Enable SMbus support" + depends on MOUSE_ELAN_I2C + help + Say Y here if Elan Touchpad in your system is connected to + a SMbus adapter. + + If unsure, say Y. + config MOUSE_INPORT tristate "InPort/MS/ATIXL busmouse" depends on ISA diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile index dda507f8b3a2..560003dcac37 100644 --- a/drivers/input/mouse/Makefile +++ b/drivers/input/mouse/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_MOUSE_APPLETOUCH) += appletouch.o obj-$(CONFIG_MOUSE_ATARI) += atarimouse.o obj-$(CONFIG_MOUSE_BCM5974) += bcm5974.o obj-$(CONFIG_MOUSE_CYAPA) += cyapa.o +obj-$(CONFIG_MOUSE_ELAN_I2C) += elan_i2c.o obj-$(CONFIG_MOUSE_GPIO) += gpio_mouse.o obj-$(CONFIG_MOUSE_INPORT) += inport.o obj-$(CONFIG_MOUSE_LOGIBM) += logibm.o @@ -34,3 +35,7 @@ psmouse-$(CONFIG_MOUSE_PS2_SENTELIC) += sentelic.o psmouse-$(CONFIG_MOUSE_PS2_TRACKPOINT) += trackpoint.o psmouse-$(CONFIG_MOUSE_PS2_TOUCHKIT) += touchkit_ps2.o psmouse-$(CONFIG_MOUSE_PS2_CYPRESS) += cypress_ps2.o + +elan_i2c-objs := elan_i2c_core.o +elan_i2c-$(CONFIG_MOUSE_ELAN_I2C_I2C) += elan_i2c_i2c.o +elan_i2c-$(CONFIG_MOUSE_ELAN_I2C_SMBUS) += elan_i2c_smbus.o diff --git a/drivers/input/mouse/elan_i2c.h b/drivers/input/mouse/elan_i2c.h new file mode 100644 index 000000000000..2e838626205f --- /dev/null +++ b/drivers/input/mouse/elan_i2c.h @@ -0,0 +1,86 @@ +/* + * Elan I2C/SMBus Touchpad driver + * + * Copyright (c) 2013 ELAN Microelectronics Corp. + * + * Author: 林政維 (Duson Lin) + * Version: 1.5.5 + * + * Based on cyapa driver: + * copyright (c) 2011-2012 Cypress Semiconductor, Inc. + * copyright (c) 2011-2012 Google, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * Trademarks are the property of their respective owners. + */ + +#ifndef _ELAN_I2C_H +#define _ELAN_i2C_H + +#include + +#define ETP_ENABLE_ABS 0x0001 +#define ETP_ENABLE_CALIBRATE 0x0002 +#define ETP_DISABLE_CALIBRATE 0x0000 +#define ETP_DISABLE_POWER 0x0001 + +/* IAP Firmware handling */ +#define ETP_FW_NAME "elan_i2c.bin" +#define ETP_IAP_START_ADDR 0x0083 +#define ETP_FW_IAP_PAGE_ERR (1 << 5) +#define ETP_FW_IAP_INTF_ERR (1 << 4) +#define ETP_FW_PAGE_SIZE 64 +#define ETP_FW_PAGE_COUNT 768 +#define ETP_FW_SIZE (ETP_FW_PAGE_SIZE * ETP_FW_PAGE_COUNT) + +struct i2c_client; +struct completion; + +enum tp_mode { + IAP_MODE = 1, + MAIN_MODE +}; + +struct elan_transport_ops { + int (*initialize)(struct i2c_client *client); + int (*sleep_control)(struct i2c_client *, bool sleep); + int (*power_control)(struct i2c_client *, bool enable); + int (*set_mode)(struct i2c_client *client, u8 mode); + + int (*calibrate)(struct i2c_client *client); + int (*calibrate_result)(struct i2c_client *client, u8 *val); + + int (*get_baseline_data)(struct i2c_client *client, + bool max_baseliune, u8 *value); + + int (*get_version)(struct i2c_client *client, bool iap, u8 *version); + int (*get_sm_version)(struct i2c_client *client, u8 *version); + int (*get_checksum)(struct i2c_client *client, bool iap, u16 *csum); + int (*get_product_id)(struct i2c_client *client, u8 *id); + + int (*get_max)(struct i2c_client *client, + unsigned int *max_x, unsigned int *max_y); + int (*get_resolution)(struct i2c_client *client, + u8 *hw_res_x, u8 *hw_res_y); + int (*get_num_traces)(struct i2c_client *client, + unsigned int *x_tracenum, + unsigned int *y_tracenum); + + int (*iap_get_mode)(struct i2c_client *client, enum tp_mode *mode); + int (*iap_reset)(struct i2c_client *client); + + int (*prepare_fw_update)(struct i2c_client *client); + int (*write_fw_block)(struct i2c_client *client, + const u8 *page, u16 checksum, int idx); + int (*finish_fw_update)(struct i2c_client *client, + struct completion *reset_done); + + int (*get_report)(struct i2c_client *client, u8 *report); +}; + +extern const struct elan_transport_ops elan_smbus_ops, elan_i2c_ops; + +#endif /* _ELAN_I2C_H */ diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c new file mode 100644 index 000000000000..0cb2be48d537 --- /dev/null +++ b/drivers/input/mouse/elan_i2c_core.c @@ -0,0 +1,1137 @@ +/* + * Elan I2C/SMBus Touchpad driver + * + * Copyright (c) 2013 ELAN Microelectronics Corp. + * + * Author: 林政維 (Duson Lin) + * Version: 1.5.5 + * + * Based on cyapa driver: + * copyright (c) 2011-2012 Cypress Semiconductor, Inc. + * copyright (c) 2011-2012 Google, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * Trademarks are the property of their respective owners. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "elan_i2c.h" + +#define DRIVER_NAME "elan_i2c" +#define ELAN_DRIVER_VERSION "1.5.5" +#define ETP_PRESSURE_OFFSET 25 +#define ETP_MAX_PRESSURE 255 +#define ETP_FWIDTH_REDUCE 90 +#define ETP_FINGER_WIDTH 15 +#define ETP_RETRY_COUNT 3 + +#define ETP_MAX_FINGERS 5 +#define ETP_FINGER_DATA_LEN 5 +#define ETP_REPORT_ID 0x5D +#define ETP_REPORT_ID_OFFSET 2 +#define ETP_TOUCH_INFO_OFFSET 3 +#define ETP_FINGER_DATA_OFFSET 4 +#define ETP_MAX_REPORT_LEN 34 + +/* The main device structure */ +struct elan_tp_data { + struct i2c_client *client; + struct input_dev *input; + struct regulator *vcc; + + const struct elan_transport_ops *ops; + + /* for fw update */ + struct completion fw_completion; + bool in_fw_update; + + struct mutex sysfs_mutex; + + unsigned int max_x; + unsigned int max_y; + unsigned int width_x; + unsigned int width_y; + unsigned int x_res; + unsigned int y_res; + + u8 product_id; + u8 fw_version; + u8 sm_version; + u8 iap_version; + u16 fw_checksum; + + u8 mode; + + bool irq_wake; + + u8 min_baseline; + u8 max_baseline; + bool baseline_ready; +}; + +static int elan_enable_power(struct elan_tp_data *data) +{ + int repeat = ETP_RETRY_COUNT; + int error; + + error = regulator_enable(data->vcc); + if (error) { + dev_err(&data->client->dev, + "Failed to enable regulator: %d\n", error); + return error; + } + + do { + error = data->ops->power_control(data->client, true); + if (error >= 0) + return 0; + + msleep(30); + } while (--repeat > 0); + + return error; +} + +static int elan_disable_power(struct elan_tp_data *data) +{ + int repeat = ETP_RETRY_COUNT; + int error; + + do { + error = data->ops->power_control(data->client, false); + if (!error) { + error = regulator_disable(data->vcc); + if (error) { + dev_err(&data->client->dev, + "Failed to disable regulator: %d\n", + error); + /* Attempt to power the chip back up */ + data->ops->power_control(data->client, true); + break; + } + + return 0; + } + + msleep(30); + } while (--repeat > 0); + + return error; +} + +static int elan_sleep(struct elan_tp_data *data) +{ + int repeat = ETP_RETRY_COUNT; + int error; + + do { + error = data->ops->sleep_control(data->client, true); + if (!error) + return 0; + + msleep(30); + } while (--repeat > 0); + + return error; +} + +static int __elan_initialize(struct elan_tp_data *data) +{ + struct i2c_client *client = data->client; + int error; + + error = data->ops->initialize(client); + if (error) { + dev_err(&client->dev, "device initialize failed: %d\n", error); + return error; + } + + data->mode |= ETP_ENABLE_ABS; + error = data->ops->set_mode(client, data->mode); + if (error) { + dev_err(&client->dev, + "failed to switch to absolute mode: %d\n", error); + return error; + } + + error = data->ops->sleep_control(client, false); + if (error) { + dev_err(&client->dev, + "failed to wake device up: %d\n", error); + return error; + } + + return 0; +} + +static int elan_initialize(struct elan_tp_data *data) +{ + int repeat = ETP_RETRY_COUNT; + int error; + + do { + error = __elan_initialize(data); + if (!error) + return 0; + + repeat--; + msleep(30); + } while (--repeat > 0); + + return error; +} + +static int elan_query_device_info(struct elan_tp_data *data) +{ + int error; + + error = data->ops->get_product_id(data->client, &data->product_id); + if (error) + return error; + + error = data->ops->get_version(data->client, false, &data->fw_version); + if (error) + return error; + + error = data->ops->get_checksum(data->client, false, + &data->fw_checksum); + if (error) + return error; + + error = data->ops->get_sm_version(data->client, &data->sm_version); + if (error) + return error; + + error = data->ops->get_version(data->client, true, &data->iap_version); + if (error) + return error; + + return 0; +} + +static unsigned int elan_convert_resolution(u8 val) +{ + /* + * (value from firmware) * 10 + 790 = dpi + * + * We also have to convert dpi to dots/mm (*10/254 to avoid floating + * point). + */ + + return ((int)(char)val * 10 + 790) * 10 / 254; +} + +static int elan_query_device_parameters(struct elan_tp_data *data) +{ + unsigned int x_traces, y_traces; + u8 hw_x_res, hw_y_res; + int error; + + error = data->ops->get_max(data->client, &data->max_x, &data->max_y); + if (error) + return error; + + error = data->ops->get_num_traces(data->client, &x_traces, &y_traces); + if (error) + return error; + + data->width_x = data->max_x / x_traces; + data->width_y = data->max_y / y_traces; + + error = data->ops->get_resolution(data->client, &hw_x_res, &hw_y_res); + if (error) + return error; + + data->x_res = elan_convert_resolution(hw_x_res); + data->y_res = elan_convert_resolution(hw_y_res); + + return 0; +} + +/* + ********************************************************** + * IAP firmware updater related routines + ********************************************************** + */ +static int elan_write_fw_block(struct elan_tp_data *data, + const u8 *page, u16 checksum, int idx) +{ + int retry = ETP_RETRY_COUNT; + int error; + + do { + error = data->ops->write_fw_block(data->client, + page, checksum, idx); + if (!error) + return 0; + + dev_dbg(&data->client->dev, + "IAP retrying page %d (error: %d)\n", idx, error); + } while (--retry > 0); + + return error; +} + +static int __elan_update_firmware(struct elan_tp_data *data, + const struct firmware *fw) +{ + struct i2c_client *client = data->client; + struct device *dev = &client->dev; + int i, j; + int error; + u16 iap_start_addr; + u16 boot_page_count; + u16 sw_checksum = 0, fw_checksum = 0; + + error = data->ops->prepare_fw_update(client); + if (error) + return error; + + iap_start_addr = get_unaligned_le16(&fw->data[ETP_IAP_START_ADDR * 2]); + + boot_page_count = (iap_start_addr * 2) / ETP_FW_PAGE_SIZE; + for (i = boot_page_count; i < ETP_FW_PAGE_COUNT; i++) { + u16 checksum = 0; + const u8 *page = &fw->data[i * ETP_FW_PAGE_SIZE]; + + for (j = 0; j < ETP_FW_PAGE_SIZE; j += 2) + checksum += ((page[j + 1] << 8) | page[j]); + + error = elan_write_fw_block(data, page, checksum, i); + if (error) { + dev_err(dev, "write page %d fail: %d\n", i, error); + return error; + } + + sw_checksum += checksum; + } + + /* Wait WDT reset and power on reset */ + msleep(600); + + error = data->ops->finish_fw_update(client, &data->fw_completion); + if (error) + return error; + + error = data->ops->get_checksum(client, true, &fw_checksum); + if (error) + return error; + + if (sw_checksum != fw_checksum) { + dev_err(dev, "checksum diff sw=[%04X], fw=[%04X]\n", + sw_checksum, fw_checksum); + return -EIO; + } + + return 0; +} + +static int elan_update_firmware(struct elan_tp_data *data, + const struct firmware *fw) +{ + struct i2c_client *client = data->client; + int retval; + + dev_dbg(&client->dev, "Starting firmware update....\n"); + + disable_irq(client->irq); + data->in_fw_update = true; + + retval = __elan_update_firmware(data, fw); + if (retval) { + dev_err(&client->dev, "firmware update failed: %d\n", retval); + data->ops->iap_reset(client); + } else { + /* Reinitialize TP after fw is updated */ + elan_initialize(data); + elan_query_device_info(data); + } + + data->in_fw_update = false; + enable_irq(client->irq); + + return retval; +} + +/* + ******************************************************************* + * SYSFS attributes + ******************************************************************* + */ +static ssize_t elan_sysfs_read_fw_checksum(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct elan_tp_data *data = i2c_get_clientdata(client); + + return sprintf(buf, "0x%04x\n", data->fw_checksum); +} + +static ssize_t elan_sysfs_read_product_id(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct elan_tp_data *data = i2c_get_clientdata(client); + + return sprintf(buf, "%d.0\n", data->product_id); +} + +static ssize_t elan_sysfs_read_fw_ver(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct elan_tp_data *data = i2c_get_clientdata(client); + + return sprintf(buf, "%d.0\n", data->fw_version); +} + +static ssize_t elan_sysfs_read_sm_ver(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct elan_tp_data *data = i2c_get_clientdata(client); + + return sprintf(buf, "%d.0\n", data->sm_version); +} + +static ssize_t elan_sysfs_read_iap_ver(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct elan_tp_data *data = i2c_get_clientdata(client); + + return sprintf(buf, "%d.0\n", data->iap_version); +} + +static ssize_t elan_sysfs_update_fw(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct elan_tp_data *data = i2c_get_clientdata(client); + const struct firmware *fw; + int error; + + error = request_firmware(&fw, ETP_FW_NAME, dev); + if (error) { + dev_err(dev, "cannot load firmware %s: %d\n", + ETP_FW_NAME, error); + return error; + } + + /* Firmware must be exactly PAGE_NUM * PAGE_SIZE bytes */ + if (fw->size != ETP_FW_SIZE) { + dev_err(dev, "invalid firmware size = %zu, expected %d.\n", + fw->size, ETP_FW_SIZE); + error = -EBADF; + goto out_release_fw; + } + + error = mutex_lock_interruptible(&data->sysfs_mutex); + if (error) + goto out_release_fw; + + error = elan_update_firmware(data, fw); + + mutex_unlock(&data->sysfs_mutex); + +out_release_fw: + release_firmware(fw); + return error ?: count; +} + +static ssize_t calibrate_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct elan_tp_data *data = i2c_get_clientdata(client); + int tries = 20; + int retval; + int error; + u8 val[3]; + + retval = mutex_lock_interruptible(&data->sysfs_mutex); + if (retval) + return retval; + + disable_irq(client->irq); + + data->mode |= ETP_ENABLE_CALIBRATE; + retval = data->ops->set_mode(client, data->mode); + if (retval) { + dev_err(dev, "failed to enable calibration mode: %d\n", + retval); + goto out; + } + + retval = data->ops->calibrate(client); + if (retval) { + dev_err(dev, "failed to start calibration: %d\n", + retval); + goto out_disable_calibrate; + } + + val[0] = 0xff; + do { + /* Wait 250ms before checking if calibration has completed. */ + msleep(250); + + retval = data->ops->calibrate_result(client, val); + if (retval) + dev_err(dev, "failed to check calibration result: %d\n", + retval); + else if (val[0] == 0) + break; /* calibration done */ + + } while (--tries); + + if (tries == 0) { + dev_err(dev, "failed to calibrate. Timeout.\n"); + retval = -ETIMEDOUT; + } + +out_disable_calibrate: + data->mode &= ~ETP_ENABLE_CALIBRATE; + error = data->ops->set_mode(data->client, data->mode); + if (error) { + dev_err(dev, "failed to disable calibration mode: %d\n", + error); + if (!retval) + retval = error; + } +out: + enable_irq(client->irq); + mutex_unlock(&data->sysfs_mutex); + return retval ?: count; +} + +static ssize_t elan_sysfs_read_mode(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct elan_tp_data *data = i2c_get_clientdata(client); + int error; + enum tp_mode mode; + + error = mutex_lock_interruptible(&data->sysfs_mutex); + if (error) + return error; + + error = data->ops->iap_get_mode(data->client, &mode); + + mutex_unlock(&data->sysfs_mutex); + + if (error) + return error; + + return sprintf(buf, "%d\n", (int)mode); +} + +static DEVICE_ATTR(product_id, S_IRUGO, elan_sysfs_read_product_id, NULL); +static DEVICE_ATTR(firmware_version, S_IRUGO, elan_sysfs_read_fw_ver, NULL); +static DEVICE_ATTR(sample_version, S_IRUGO, elan_sysfs_read_sm_ver, NULL); +static DEVICE_ATTR(iap_version, S_IRUGO, elan_sysfs_read_iap_ver, NULL); +static DEVICE_ATTR(fw_checksum, S_IRUGO, elan_sysfs_read_fw_checksum, NULL); +static DEVICE_ATTR(mode, S_IRUGO, elan_sysfs_read_mode, NULL); +static DEVICE_ATTR(update_fw, S_IWUSR, NULL, elan_sysfs_update_fw); + +static DEVICE_ATTR_WO(calibrate); + +static struct attribute *elan_sysfs_entries[] = { + &dev_attr_product_id.attr, + &dev_attr_firmware_version.attr, + &dev_attr_sample_version.attr, + &dev_attr_iap_version.attr, + &dev_attr_fw_checksum.attr, + &dev_attr_calibrate.attr, + &dev_attr_mode.attr, + &dev_attr_update_fw.attr, + NULL, +}; + +static const struct attribute_group elan_sysfs_group = { + .attrs = elan_sysfs_entries, +}; + +static ssize_t acquire_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct elan_tp_data *data = i2c_get_clientdata(client); + int error; + int retval; + + retval = mutex_lock_interruptible(&data->sysfs_mutex); + if (retval) + return retval; + + disable_irq(client->irq); + + data->baseline_ready = false; + + data->mode |= ETP_ENABLE_CALIBRATE; + retval = data->ops->set_mode(data->client, data->mode); + if (retval) { + dev_err(dev, "Failed to enable calibration mode to get baseline: %d\n", + retval); + goto out; + } + + msleep(250); + + retval = data->ops->get_baseline_data(data->client, true, + &data->max_baseline); + if (retval) { + dev_err(dev, "Failed to read max baseline form device: %d\n", + retval); + goto out_disable_calibrate; + } + + retval = data->ops->get_baseline_data(data->client, false, + &data->min_baseline); + if (retval) { + dev_err(dev, "Failed to read min baseline form device: %d\n", + retval); + goto out_disable_calibrate; + } + + data->baseline_ready = true; + +out_disable_calibrate: + data->mode &= ~ETP_ENABLE_CALIBRATE; + error = data->ops->set_mode(data->client, data->mode); + if (error) { + dev_err(dev, "Failed to disable calibration mode after acquiring baseline: %d\n", + error); + if (!retval) + retval = error; + } +out: + enable_irq(client->irq); + mutex_unlock(&data->sysfs_mutex); + return retval ?: count; +} + +static ssize_t min_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct elan_tp_data *data = i2c_get_clientdata(client); + int retval; + + retval = mutex_lock_interruptible(&data->sysfs_mutex); + if (retval) + return retval; + + if (!data->baseline_ready) { + retval = -ENODATA; + goto out; + } + + retval = snprintf(buf, PAGE_SIZE, "%d", data->min_baseline); + +out: + mutex_unlock(&data->sysfs_mutex); + return retval; +} + +static ssize_t max_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct elan_tp_data *data = i2c_get_clientdata(client); + int retval; + + retval = mutex_lock_interruptible(&data->sysfs_mutex); + if (retval) + return retval; + + if (!data->baseline_ready) { + retval = -ENODATA; + goto out; + } + + retval = snprintf(buf, PAGE_SIZE, "%d", data->max_baseline); + +out: + mutex_unlock(&data->sysfs_mutex); + return retval; +} + + +static DEVICE_ATTR_WO(acquire); +static DEVICE_ATTR_RO(min); +static DEVICE_ATTR_RO(max); + +static struct attribute *elan_baseline_sysfs_entries[] = { + &dev_attr_acquire.attr, + &dev_attr_min.attr, + &dev_attr_max.attr, + NULL, +}; + +static const struct attribute_group elan_baseline_sysfs_group = { + .name = "baseline", + .attrs = elan_baseline_sysfs_entries, +}; + +static const struct attribute_group *elan_sysfs_groups[] = { + &elan_sysfs_group, + &elan_baseline_sysfs_group, + NULL +}; + +/* + ****************************************************************** + * Elan isr functions + ****************************************************************** + */ +static void elan_report_contact(struct elan_tp_data *data, + int contact_num, bool contact_valid, + u8 *finger_data) +{ + struct input_dev *input = data->input; + unsigned int pos_x, pos_y; + unsigned int pressure, mk_x, mk_y; + unsigned int area_x, area_y, major, minor, new_pressure; + + + if (contact_valid) { + pos_x = ((finger_data[0] & 0xf0) << 4) | + finger_data[1]; + pos_y = ((finger_data[0] & 0x0f) << 8) | + finger_data[2]; + mk_x = (finger_data[3] & 0x0f); + mk_y = (finger_data[3] >> 4); + pressure = finger_data[4]; + + if (pos_x > data->max_x || pos_y > data->max_y) { + dev_dbg(input->dev.parent, + "[%d] x=%d y=%d over max (%d, %d)", + contact_num, pos_x, pos_y, + data->max_x, data->max_y); + return; + } + + /* + * To avoid treating large finger as palm, let's reduce the + * width x and y per trace. + */ + area_x = mk_x * (data->width_x - ETP_FWIDTH_REDUCE); + area_y = mk_y * (data->width_y - ETP_FWIDTH_REDUCE); + + major = max(area_x, area_y); + minor = min(area_x, area_y); + + new_pressure = pressure + ETP_PRESSURE_OFFSET; + if (new_pressure > ETP_MAX_PRESSURE) + new_pressure = ETP_MAX_PRESSURE; + + input_mt_slot(input, contact_num); + input_mt_report_slot_state(input, MT_TOOL_FINGER, true); + input_report_abs(input, ABS_MT_POSITION_X, pos_x); + input_report_abs(input, ABS_MT_POSITION_Y, data->max_y - pos_y); + input_report_abs(input, ABS_MT_PRESSURE, new_pressure); + input_report_abs(input, ABS_TOOL_WIDTH, mk_x); + input_report_abs(input, ABS_MT_TOUCH_MAJOR, major); + input_report_abs(input, ABS_MT_TOUCH_MINOR, minor); + } else { + input_mt_slot(input, contact_num); + input_mt_report_slot_state(input, MT_TOOL_FINGER, false); + } +} + +static void elan_report_absolute(struct elan_tp_data *data, u8 *packet) +{ + struct input_dev *input = data->input; + u8 *finger_data = &packet[ETP_FINGER_DATA_OFFSET]; + int i; + u8 tp_info = packet[ETP_TOUCH_INFO_OFFSET]; + bool contact_valid; + + for (i = 0; i < ETP_MAX_FINGERS; i++) { + contact_valid = tp_info & (1U << (3 + i)); + elan_report_contact(data, i, contact_valid, finger_data); + + if (contact_valid) + finger_data += ETP_FINGER_DATA_LEN; + } + + input_report_key(input, BTN_LEFT, tp_info & 0x01); + input_mt_report_pointer_emulation(input, true); + input_sync(input); +} + +static irqreturn_t elan_isr(int irq, void *dev_id) +{ + struct elan_tp_data *data = dev_id; + struct device *dev = &data->client->dev; + int error; + u8 report[ETP_MAX_REPORT_LEN]; + + /* + * When device is connected to i2c bus, when all IAP page writes + * complete, the driver will receive interrupt and must read + * 0000 to confirm that IAP is finished. + */ + if (data->in_fw_update) { + complete(&data->fw_completion); + goto out; + } + + error = data->ops->get_report(data->client, report); + if (error) + goto out; + + if (report[ETP_REPORT_ID_OFFSET] != ETP_REPORT_ID) + dev_err(dev, "invalid report id data (%x)\n", + report[ETP_REPORT_ID_OFFSET]); + else + elan_report_absolute(data, report); + +out: + return IRQ_HANDLED; +} + +/* + ****************************************************************** + * Elan initialization functions + ****************************************************************** + */ +static int elan_setup_input_device(struct elan_tp_data *data) +{ + struct device *dev = &data->client->dev; + struct input_dev *input; + unsigned int max_width = max(data->width_x, data->width_y); + unsigned int min_width = min(data->width_x, data->width_y); + int error; + + input = devm_input_allocate_device(dev); + if (!input) + return -ENOMEM; + + input->name = "Elan Touchpad"; + input->id.bustype = BUS_I2C; + input_set_drvdata(input, data); + + error = input_mt_init_slots(input, ETP_MAX_FINGERS, + INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED); + if (error) { + dev_err(dev, "failed to initialize MT slots: %d\n", error); + return error; + } + + __set_bit(EV_ABS, input->evbit); + __set_bit(INPUT_PROP_POINTER, input->propbit); + __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); + __set_bit(BTN_LEFT, input->keybit); + + /* Set up ST parameters */ + input_set_abs_params(input, ABS_X, 0, data->max_x, 0, 0); + input_set_abs_params(input, ABS_Y, 0, data->max_y, 0, 0); + input_abs_set_res(input, ABS_X, data->x_res); + input_abs_set_res(input, ABS_Y, data->y_res); + input_set_abs_params(input, ABS_PRESSURE, 0, ETP_MAX_PRESSURE, 0, 0); + input_set_abs_params(input, ABS_TOOL_WIDTH, 0, ETP_FINGER_WIDTH, 0, 0); + + /* And MT parameters */ + input_set_abs_params(input, ABS_MT_POSITION_X, 0, data->max_x, 0, 0); + input_set_abs_params(input, ABS_MT_POSITION_Y, 0, data->max_y, 0, 0); + input_abs_set_res(input, ABS_MT_POSITION_X, data->x_res); + input_abs_set_res(input, ABS_MT_POSITION_Y, data->y_res); + input_set_abs_params(input, ABS_MT_PRESSURE, 0, + ETP_MAX_PRESSURE, 0, 0); + input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, + ETP_FINGER_WIDTH * max_width, 0, 0); + input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, + ETP_FINGER_WIDTH * min_width, 0, 0); + + data->input = input; + + return 0; +} + +static void elan_disable_regulator(void *_data) +{ + struct elan_tp_data *data = _data; + + regulator_disable(data->vcc); +} + +static void elan_remove_sysfs_groups(void *_data) +{ + struct elan_tp_data *data = _data; + + sysfs_remove_groups(&data->client->dev.kobj, elan_sysfs_groups); +} + +static int elan_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + const struct elan_transport_ops *transport_ops; + struct device *dev = &client->dev; + struct elan_tp_data *data; + unsigned long irqflags; + int error; + + if (IS_ENABLED(CONFIG_MOUSE_ELAN_I2C_I2C) && + i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + transport_ops = &elan_i2c_ops; + } else if (IS_ENABLED(CONFIG_MOUSE_ELAN_I2C_SMBUS) && + i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_BLOCK_DATA | + I2C_FUNC_SMBUS_I2C_BLOCK)) { + transport_ops = &elan_smbus_ops; + } else { + dev_err(dev, "not a supported I2C/SMBus adapter\n"); + return -EIO; + } + + data = devm_kzalloc(&client->dev, sizeof(struct elan_tp_data), + GFP_KERNEL); + if (!data) + return -ENOMEM; + + i2c_set_clientdata(client, data); + + data->ops = transport_ops; + data->client = client; + init_completion(&data->fw_completion); + mutex_init(&data->sysfs_mutex); + + data->vcc = devm_regulator_get(&client->dev, "vcc"); + if (IS_ERR(data->vcc)) { + error = PTR_ERR(data->vcc); + if (error != -EPROBE_DEFER) + dev_err(&client->dev, + "Failed to get 'vcc' regulator: %d\n", + error); + return error; + } + + error = regulator_enable(data->vcc); + if (error) { + dev_err(&client->dev, + "Failed to enable regulator: %d\n", error); + return error; + } + + error = devm_add_action(&client->dev, + elan_disable_regulator, data); + if (error) { + regulator_disable(data->vcc); + dev_err(&client->dev, + "Failed to add disable regulator action: %d\n", + error); + return error; + } + + /* Initialize the touchpad. */ + error = elan_initialize(data); + if (error) + return error; + + error = elan_query_device_info(data); + if (error) + return error; + + error = elan_query_device_parameters(data); + if (error) + return error; + + dev_dbg(&client->dev, + "Elan Touchpad Information:\n" + " Module product ID: 0x%04x\n" + " Firmware Version: 0x%04x\n" + " Sample Version: 0x%04x\n" + " IAP Version: 0x%04x\n" + " Max ABS X,Y: %d,%d\n" + " Width X,Y: %d,%d\n" + " Resolution X,Y: %d,%d (dots/mm)\n", + data->product_id, + data->fw_version, + data->sm_version, + data->iap_version, + data->max_x, data->max_y, + data->width_x, data->width_y, + data->x_res, data->y_res); + + /* Set up input device properties based on queried parameters. */ + error = elan_setup_input_device(data); + if (error) + return error; + + /* + * Systems using device tree should set up interrupt via DTS, + * the rest will use the default falling edge interrupts. + */ + irqflags = client->dev.of_node ? 0 : IRQF_TRIGGER_FALLING; + + error = devm_request_threaded_irq(&client->dev, client->irq, + NULL, elan_isr, + irqflags | IRQF_ONESHOT, + client->name, data); + if (error) { + dev_err(&client->dev, "cannot register irq=%d\n", client->irq); + return error; + } + + error = sysfs_create_groups(&client->dev.kobj, elan_sysfs_groups); + if (error) { + dev_err(&client->dev, "failed to create sysfs attributes: %d\n", + error); + return error; + } + + error = devm_add_action(&client->dev, + elan_remove_sysfs_groups, data); + if (error) { + elan_remove_sysfs_groups(data); + dev_err(&client->dev, + "Failed to add sysfs cleanup action: %d\n", + error); + return error; + } + + error = input_register_device(data->input); + if (error) { + dev_err(&client->dev, "failed to register input device: %d\n", + error); + return error; + } + + /* + * Systems using device tree should set up wakeup via DTS, + * the rest will configure device as wakeup source by default. + */ + if (!client->dev.of_node) + device_init_wakeup(&client->dev, true); + + return 0; +} + +static int __maybe_unused elan_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct elan_tp_data *data = i2c_get_clientdata(client); + int ret; + + /* + * We are taking the mutex to make sure sysfs operations are + * complete before we attempt to bring the device into low[er] + * power mode. + */ + ret = mutex_lock_interruptible(&data->sysfs_mutex); + if (ret) + return ret; + + disable_irq(client->irq); + + if (device_may_wakeup(dev)) { + ret = elan_sleep(data); + /* Enable wake from IRQ */ + data->irq_wake = (enable_irq_wake(client->irq) == 0); + } else { + ret = elan_disable_power(data); + } + + mutex_unlock(&data->sysfs_mutex); + return ret; +} + +static int __maybe_unused elan_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct elan_tp_data *data = i2c_get_clientdata(client); + int error; + + if (device_may_wakeup(dev) && data->irq_wake) { + disable_irq_wake(client->irq); + data->irq_wake = false; + } + + error = elan_enable_power(data); + if (error) + dev_err(dev, "power up when resuming failed: %d\n", error); + + error = elan_initialize(data); + if (error) + dev_err(dev, "initialize when resuming failed: %d\n", error); + + enable_irq(data->client->irq); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(elan_pm_ops, elan_suspend, elan_resume); + +static const struct i2c_device_id elan_id[] = { + { DRIVER_NAME, 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, elan_id); + +#ifdef CONFIG_ACPI +static const struct acpi_device_id elan_acpi_id[] = { + { "ELAN0000", 0 }, + { } +}; +MODULE_DEVICE_TABLE(acpi, elan_acpi_id); +#endif + +#ifdef CONFIG_OF +static const struct of_device_id elan_of_match[] = { + { .compatible = "elan,ekth3000" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, elan_of_match); +#endif + +static struct i2c_driver elan_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .pm = &elan_pm_ops, + .acpi_match_table = ACPI_PTR(elan_acpi_id), + .of_match_table = of_match_ptr(elan_of_match), + }, + .probe = elan_probe, + .id_table = elan_id, +}; + +module_i2c_driver(elan_driver); + +MODULE_AUTHOR("Duson Lin "); +MODULE_DESCRIPTION("Elan I2C/SMBus Touchpad driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(ELAN_DRIVER_VERSION); diff --git a/drivers/input/mouse/elan_i2c_i2c.c b/drivers/input/mouse/elan_i2c_i2c.c new file mode 100644 index 000000000000..97d4937fc244 --- /dev/null +++ b/drivers/input/mouse/elan_i2c_i2c.c @@ -0,0 +1,611 @@ +/* + * Elan I2C/SMBus Touchpad driver - I2C interface + * + * Copyright (c) 2013 ELAN Microelectronics Corp. + * + * Author: 林政維 (Duson Lin) + * Version: 1.5.5 + * + * Based on cyapa driver: + * copyright (c) 2011-2012 Cypress Semiconductor, Inc. + * copyright (c) 2011-2012 Google, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * Trademarks are the property of their respective owners. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "elan_i2c.h" + +/* Elan i2c commands */ +#define ETP_I2C_RESET 0x0100 +#define ETP_I2C_WAKE_UP 0x0800 +#define ETP_I2C_SLEEP 0x0801 +#define ETP_I2C_DESC_CMD 0x0001 +#define ETP_I2C_REPORT_DESC_CMD 0x0002 +#define ETP_I2C_STAND_CMD 0x0005 +#define ETP_I2C_UNIQUEID_CMD 0x0101 +#define ETP_I2C_FW_VERSION_CMD 0x0102 +#define ETP_I2C_SM_VERSION_CMD 0x0103 +#define ETP_I2C_XY_TRACENUM_CMD 0x0105 +#define ETP_I2C_MAX_X_AXIS_CMD 0x0106 +#define ETP_I2C_MAX_Y_AXIS_CMD 0x0107 +#define ETP_I2C_RESOLUTION_CMD 0x0108 +#define ETP_I2C_IAP_VERSION_CMD 0x0110 +#define ETP_I2C_SET_CMD 0x0300 +#define ETP_I2C_POWER_CMD 0x0307 +#define ETP_I2C_FW_CHECKSUM_CMD 0x030F +#define ETP_I2C_IAP_CTRL_CMD 0x0310 +#define ETP_I2C_IAP_CMD 0x0311 +#define ETP_I2C_IAP_RESET_CMD 0x0314 +#define ETP_I2C_IAP_CHECKSUM_CMD 0x0315 +#define ETP_I2C_CALIBRATE_CMD 0x0316 +#define ETP_I2C_MAX_BASELINE_CMD 0x0317 +#define ETP_I2C_MIN_BASELINE_CMD 0x0318 + +#define ETP_I2C_REPORT_LEN 34 +#define ETP_I2C_DESC_LENGTH 30 +#define ETP_I2C_REPORT_DESC_LENGTH 158 +#define ETP_I2C_INF_LENGTH 2 +#define ETP_I2C_IAP_PASSWORD 0x1EA5 +#define ETP_I2C_IAP_RESET 0xF0F0 +#define ETP_I2C_MAIN_MODE_ON (1 << 9) +#define ETP_I2C_IAP_REG_L 0x01 +#define ETP_I2C_IAP_REG_H 0x06 + +static int elan_i2c_read_block(struct i2c_client *client, + u16 reg, u8 *val, u16 len) +{ + __le16 buf[] = { + cpu_to_le16(reg), + }; + struct i2c_msg msgs[] = { + { + .addr = client->addr, + .flags = client->flags & I2C_M_TEN, + .len = sizeof(buf), + .buf = (u8 *)buf, + }, + { + .addr = client->addr, + .flags = (client->flags & I2C_M_TEN) | I2C_M_RD, + .len = len, + .buf = val, + } + }; + int ret; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + return ret == ARRAY_SIZE(msgs) ? 0 : (ret < 0 ? ret : -EIO); +} + +static int elan_i2c_read_cmd(struct i2c_client *client, u16 reg, u8 *val) +{ + int retval; + + retval = elan_i2c_read_block(client, reg, val, ETP_I2C_INF_LENGTH); + if (retval < 0) { + dev_err(&client->dev, "reading cmd (0x%04x) fail.\n", reg); + return retval; + } + + return 0; +} + +static int elan_i2c_write_cmd(struct i2c_client *client, u16 reg, u16 cmd) +{ + __le16 buf[] = { + cpu_to_le16(reg), + cpu_to_le16(cmd), + }; + struct i2c_msg msg = { + .addr = client->addr, + .flags = client->flags & I2C_M_TEN, + .len = sizeof(buf), + .buf = (u8 *)buf, + }; + int ret; + + ret = i2c_transfer(client->adapter, &msg, 1); + return ret == 1 ? 0 : (ret < 0 ? ret : -EIO); +} + +static int elan_i2c_initialize(struct i2c_client *client) +{ + struct device *dev = &client->dev; + int error; + u8 val[256]; + + error = elan_i2c_write_cmd(client, ETP_I2C_STAND_CMD, ETP_I2C_RESET); + if (error) { + dev_err(dev, "device reset failed: %d\n", error); + return error; + } + + /* Wait for the device to reset */ + msleep(100); + + /* get reset acknowledgement 0000 */ + error = i2c_master_recv(client, val, ETP_I2C_INF_LENGTH); + if (error < 0) { + dev_err(dev, "failed to read reset response: %d\n", error); + return error; + } + + error = elan_i2c_read_block(client, ETP_I2C_DESC_CMD, + val, ETP_I2C_DESC_LENGTH); + if (error) { + dev_err(dev, "cannot get device descriptor: %d\n", error); + return error; + } + + error = elan_i2c_read_block(client, ETP_I2C_REPORT_DESC_CMD, + val, ETP_I2C_REPORT_DESC_LENGTH); + if (error) { + dev_err(dev, "fetching report descriptor failed.: %d\n", error); + return error; + } + + return 0; +} + +static int elan_i2c_sleep_control(struct i2c_client *client, bool sleep) +{ + return elan_i2c_write_cmd(client, ETP_I2C_STAND_CMD, + sleep ? ETP_I2C_SLEEP : ETP_I2C_WAKE_UP); +} + +static int elan_i2c_power_control(struct i2c_client *client, bool enable) +{ + u8 val[2]; + u16 reg; + int error; + + error = elan_i2c_read_cmd(client, ETP_I2C_POWER_CMD, val); + if (error) { + dev_err(&client->dev, + "failed to read current power state: %d\n", + error); + return error; + } + + reg = le16_to_cpup((__le16 *)val); + if (enable) + reg &= ~ETP_DISABLE_POWER; + else + reg |= ETP_DISABLE_POWER; + + error = elan_i2c_write_cmd(client, ETP_I2C_POWER_CMD, reg); + if (error) { + dev_err(&client->dev, + "failed to write current power state: %d\n", + error); + return error; + } + + return 0; +} + +static int elan_i2c_set_mode(struct i2c_client *client, u8 mode) +{ + return elan_i2c_write_cmd(client, ETP_I2C_SET_CMD, mode); +} + + +static int elan_i2c_calibrate(struct i2c_client *client) +{ + return elan_i2c_write_cmd(client, ETP_I2C_CALIBRATE_CMD, 1); +} + +static int elan_i2c_calibrate_result(struct i2c_client *client, u8 *val) +{ + return elan_i2c_read_block(client, ETP_I2C_CALIBRATE_CMD, val, 1); +} + +static int elan_i2c_get_baseline_data(struct i2c_client *client, + bool max_baseline, u8 *value) +{ + int error; + u8 val[3]; + + error = elan_i2c_read_cmd(client, + max_baseline ? ETP_I2C_MAX_BASELINE_CMD : + ETP_I2C_MIN_BASELINE_CMD, + val); + if (error) + return error; + + *value = le16_to_cpup((__le16 *)val); + + return 0; +} + +static int elan_i2c_get_version(struct i2c_client *client, + bool iap, u8 *version) +{ + int error; + u8 val[3]; + + error = elan_i2c_read_cmd(client, + iap ? ETP_I2C_IAP_VERSION_CMD : + ETP_I2C_FW_VERSION_CMD, + val); + if (error) { + dev_err(&client->dev, "failed to get %s version: %d\n", + iap ? "IAP" : "FW", error); + return error; + } + + *version = val[0]; + return 0; +} + +static int elan_i2c_get_sm_version(struct i2c_client *client, u8 *version) +{ + int error; + u8 val[3]; + + error = elan_i2c_read_cmd(client, ETP_I2C_SM_VERSION_CMD, val); + if (error) { + dev_err(&client->dev, "failed to get SM version: %d\n", error); + return error; + } + + *version = val[0]; + return 0; +} + +static int elan_i2c_get_product_id(struct i2c_client *client, u8 *id) +{ + int error; + u8 val[3]; + + error = elan_i2c_read_cmd(client, ETP_I2C_UNIQUEID_CMD, val); + if (error) { + dev_err(&client->dev, "failed to get product ID: %d\n", error); + return error; + } + + *id = val[0]; + return 0; +} + +static int elan_i2c_get_checksum(struct i2c_client *client, + bool iap, u16 *csum) +{ + int error; + u8 val[3]; + + error = elan_i2c_read_cmd(client, + iap ? ETP_I2C_IAP_CHECKSUM_CMD : + ETP_I2C_FW_CHECKSUM_CMD, + val); + if (error) { + dev_err(&client->dev, "failed to get %s checksum: %d\n", + iap ? "IAP" : "FW", error); + return error; + } + + *csum = le16_to_cpup((__le16 *)val); + return 0; +} + +static int elan_i2c_get_max(struct i2c_client *client, + unsigned int *max_x, unsigned int *max_y) +{ + int error; + u8 val[3]; + + error = elan_i2c_read_cmd(client, ETP_I2C_MAX_X_AXIS_CMD, val); + if (error) { + dev_err(&client->dev, "failed to get X dimension: %d\n", error); + return error; + } + + *max_x = le16_to_cpup((__le16 *)val) & 0x0fff; + + error = elan_i2c_read_cmd(client, ETP_I2C_MAX_Y_AXIS_CMD, val); + if (error) { + dev_err(&client->dev, "failed to get Y dimension: %d\n", error); + return error; + } + + *max_y = le16_to_cpup((__le16 *)val) & 0x0fff; + + return 0; +} + +static int elan_i2c_get_resolution(struct i2c_client *client, + u8 *hw_res_x, u8 *hw_res_y) +{ + int error; + u8 val[3]; + + error = elan_i2c_read_cmd(client, ETP_I2C_RESOLUTION_CMD, val); + if (error) { + dev_err(&client->dev, "failed to get resolution: %d\n", error); + return error; + } + + *hw_res_x = val[0]; + *hw_res_y = val[1]; + + return 0; +} + +static int elan_i2c_get_num_traces(struct i2c_client *client, + unsigned int *x_traces, + unsigned int *y_traces) +{ + int error; + u8 val[3]; + + error = elan_i2c_read_cmd(client, ETP_I2C_XY_TRACENUM_CMD, val); + if (error) { + dev_err(&client->dev, "failed to get trace info: %d\n", error); + return error; + } + + *x_traces = val[0] - 1; + *y_traces = val[1] - 1; + + return 0; +} + +static int elan_i2c_iap_get_mode(struct i2c_client *client, enum tp_mode *mode) +{ + int error; + u16 constant; + u8 val[3]; + + error = elan_i2c_read_cmd(client, ETP_I2C_IAP_CTRL_CMD, val); + if (error) { + dev_err(&client->dev, + "failed to read iap control register: %d\n", + error); + return error; + } + + constant = le16_to_cpup((__le16 *)val); + dev_dbg(&client->dev, "iap control reg: 0x%04x.\n", constant); + + *mode = (constant & ETP_I2C_MAIN_MODE_ON) ? MAIN_MODE : IAP_MODE; + + return 0; +} + +static int elan_i2c_iap_reset(struct i2c_client *client) +{ + int error; + + error = elan_i2c_write_cmd(client, ETP_I2C_IAP_RESET_CMD, + ETP_I2C_IAP_RESET); + if (error) { + dev_err(&client->dev, "cannot reset IC: %d\n", error); + return error; + } + + return 0; +} + +static int elan_i2c_set_flash_key(struct i2c_client *client) +{ + int error; + + error = elan_i2c_write_cmd(client, ETP_I2C_IAP_CMD, + ETP_I2C_IAP_PASSWORD); + if (error) { + dev_err(&client->dev, "cannot set flash key: %d\n", error); + return error; + } + + return 0; +} + +static int elan_i2c_prepare_fw_update(struct i2c_client *client) +{ + struct device *dev = &client->dev; + int error; + enum tp_mode mode; + u8 val[3]; + u16 password; + + /* Get FW in which mode (IAP_MODE/MAIN_MODE) */ + error = elan_i2c_iap_get_mode(client, &mode); + if (error) + return error; + + if (mode == IAP_MODE) { + /* Reset IC */ + error = elan_i2c_iap_reset(client); + if (error) + return error; + + msleep(30); + } + + /* Set flash key*/ + error = elan_i2c_set_flash_key(client); + if (error) + return error; + + /* Wait for F/W IAP initialization */ + msleep(mode == MAIN_MODE ? 100 : 30); + + /* Check if we are in IAP mode or not */ + error = elan_i2c_iap_get_mode(client, &mode); + if (error) + return error; + + if (mode == MAIN_MODE) { + dev_err(dev, "wrong mode: %d\n", mode); + return -EIO; + } + + /* Set flash key again */ + error = elan_i2c_set_flash_key(client); + if (error) + return error; + + /* Wait for F/W IAP initialization */ + msleep(30); + + /* read back to check we actually enabled successfully. */ + error = elan_i2c_read_cmd(client, ETP_I2C_IAP_CMD, val); + if (error) { + dev_err(dev, "cannot read iap password: %d\n", + error); + return error; + } + + password = le16_to_cpup((__le16 *)val); + if (password != ETP_I2C_IAP_PASSWORD) { + dev_err(dev, "wrong iap password: 0x%X\n", password); + return -EIO; + } + + return 0; +} + +static int elan_i2c_write_fw_block(struct i2c_client *client, + const u8 *page, u16 checksum, int idx) +{ + struct device *dev = &client->dev; + u8 page_store[ETP_FW_PAGE_SIZE + 4]; + u8 val[3]; + u16 result; + int ret, error; + + page_store[0] = ETP_I2C_IAP_REG_L; + page_store[1] = ETP_I2C_IAP_REG_H; + memcpy(&page_store[2], page, ETP_FW_PAGE_SIZE); + /* recode checksum at last two bytes */ + put_unaligned_le16(checksum, &page_store[ETP_FW_PAGE_SIZE + 2]); + + ret = i2c_master_send(client, page_store, sizeof(page_store)); + if (ret != sizeof(page_store)) { + error = ret < 0 ? ret : -EIO; + dev_err(dev, "Failed to write page %d: %d\n", idx, error); + return error; + } + + /* Wait for F/W to update one page ROM data. */ + msleep(20); + + error = elan_i2c_read_cmd(client, ETP_I2C_IAP_CTRL_CMD, val); + if (error) { + dev_err(dev, "Failed to read IAP write result: %d\n", error); + return error; + } + + result = le16_to_cpup((__le16 *)val); + if (result & (ETP_FW_IAP_PAGE_ERR | ETP_FW_IAP_INTF_ERR)) { + dev_err(dev, "IAP reports failed write: %04hx\n", + result); + return -EIO; + } + + return 0; +} + +static int elan_i2c_finish_fw_update(struct i2c_client *client, + struct completion *completion) +{ + struct device *dev = &client->dev; + long ret; + int error; + int len; + u8 buffer[ETP_I2C_INF_LENGTH]; + + reinit_completion(completion); + enable_irq(client->irq); + + error = elan_i2c_write_cmd(client, ETP_I2C_STAND_CMD, ETP_I2C_RESET); + if (!error) + ret = wait_for_completion_interruptible_timeout(completion, + msecs_to_jiffies(300)); + disable_irq(client->irq); + + if (error) { + dev_err(dev, "device reset failed: %d\n", error); + return error; + } else if (ret == 0) { + dev_err(dev, "timeout waiting for device reset\n"); + return -ETIMEDOUT; + } else if (ret < 0) { + error = ret; + dev_err(dev, "error waiting for device reset: %d\n", error); + return error; + } + + len = i2c_master_recv(client, buffer, ETP_I2C_INF_LENGTH); + if (len != ETP_I2C_INF_LENGTH) { + error = len < 0 ? len : -EIO; + dev_err(dev, "failed to read INT signal: %d (%d)\n", + error, len); + return error; + } + + return 0; +} + +static int elan_i2c_get_report(struct i2c_client *client, u8 *report) +{ + int len; + + len = i2c_master_recv(client, report, ETP_I2C_REPORT_LEN); + if (len < 0) { + dev_err(&client->dev, "failed to read report data: %d\n", len); + return len; + } + + if (len != ETP_I2C_REPORT_LEN) { + dev_err(&client->dev, + "wrong report length (%d vs %d expected)\n", + len, ETP_I2C_REPORT_LEN); + return -EIO; + } + + return 0; +} + +const struct elan_transport_ops elan_i2c_ops = { + .initialize = elan_i2c_initialize, + .sleep_control = elan_i2c_sleep_control, + .power_control = elan_i2c_power_control, + .set_mode = elan_i2c_set_mode, + + .calibrate = elan_i2c_calibrate, + .calibrate_result = elan_i2c_calibrate_result, + + .get_baseline_data = elan_i2c_get_baseline_data, + + .get_version = elan_i2c_get_version, + .get_sm_version = elan_i2c_get_sm_version, + .get_product_id = elan_i2c_get_product_id, + .get_checksum = elan_i2c_get_checksum, + + .get_max = elan_i2c_get_max, + .get_resolution = elan_i2c_get_resolution, + .get_num_traces = elan_i2c_get_num_traces, + + .iap_get_mode = elan_i2c_iap_get_mode, + .iap_reset = elan_i2c_iap_reset, + + .prepare_fw_update = elan_i2c_prepare_fw_update, + .write_fw_block = elan_i2c_write_fw_block, + .finish_fw_update = elan_i2c_finish_fw_update, + + .get_report = elan_i2c_get_report, +}; diff --git a/drivers/input/mouse/elan_i2c_smbus.c b/drivers/input/mouse/elan_i2c_smbus.c new file mode 100644 index 000000000000..359bf8583d54 --- /dev/null +++ b/drivers/input/mouse/elan_i2c_smbus.c @@ -0,0 +1,514 @@ +/* + * Elan I2C/SMBus Touchpad driver - SMBus interface + * + * Copyright (c) 2013 ELAN Microelectronics Corp. + * + * Author: 林政維 (Duson Lin) + * Version: 1.5.5 + * + * Based on cyapa driver: + * copyright (c) 2011-2012 Cypress Semiconductor, Inc. + * copyright (c) 2011-2012 Google, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * Trademarks are the property of their respective owners. + */ + +#include +#include +#include +#include + +#include "elan_i2c.h" + +/* Elan SMbus commands */ +#define ETP_SMBUS_IAP_CMD 0x00 +#define ETP_SMBUS_ENABLE_TP 0x20 +#define ETP_SMBUS_SLEEP_CMD 0x21 +#define ETP_SMBUS_IAP_PASSWORD_WRITE 0x29 +#define ETP_SMBUS_IAP_PASSWORD_READ 0x80 +#define ETP_SMBUS_WRITE_FW_BLOCK 0x2A +#define ETP_SMBUS_IAP_RESET_CMD 0x2B +#define ETP_SMBUS_RANGE_CMD 0xA0 +#define ETP_SMBUS_FW_VERSION_CMD 0xA1 +#define ETP_SMBUS_XY_TRACENUM_CMD 0xA2 +#define ETP_SMBUS_SM_VERSION_CMD 0xA3 +#define ETP_SMBUS_UNIQUEID_CMD 0xA3 +#define ETP_SMBUS_RESOLUTION_CMD 0xA4 +#define ETP_SMBUS_HELLOPACKET_CMD 0xA7 +#define ETP_SMBUS_PACKET_QUERY 0xA8 +#define ETP_SMBUS_IAP_VERSION_CMD 0xAC +#define ETP_SMBUS_IAP_CTRL_CMD 0xAD +#define ETP_SMBUS_IAP_CHECKSUM_CMD 0xAE +#define ETP_SMBUS_FW_CHECKSUM_CMD 0xAF +#define ETP_SMBUS_MAX_BASELINE_CMD 0xC3 +#define ETP_SMBUS_MIN_BASELINE_CMD 0xC4 +#define ETP_SMBUS_CALIBRATE_QUERY 0xC5 + +#define ETP_SMBUS_REPORT_LEN 32 +#define ETP_SMBUS_REPORT_OFFSET 2 +#define ETP_SMBUS_HELLOPACKET_LEN 5 +#define ETP_SMBUS_IAP_PASSWORD 0x1234 +#define ETP_SMBUS_IAP_MODE_ON (1 << 6) + +static int elan_smbus_initialize(struct i2c_client *client) +{ + u8 check[ETP_SMBUS_HELLOPACKET_LEN] = { 0x55, 0x55, 0x55, 0x55, 0x55 }; + u8 values[ETP_SMBUS_HELLOPACKET_LEN] = { 0, 0, 0, 0, 0 }; + int len, error; + + /* Get hello packet */ + len = i2c_smbus_read_block_data(client, + ETP_SMBUS_HELLOPACKET_CMD, values); + if (len != ETP_SMBUS_HELLOPACKET_LEN) { + dev_err(&client->dev, "hello packet length fail: %d\n", len); + error = len < 0 ? len : -EIO; + return error; + } + + /* compare hello packet */ + if (memcmp(values, check, ETP_SMBUS_HELLOPACKET_LEN)) { + dev_err(&client->dev, "hello packet fail [%*px]\n", + ETP_SMBUS_HELLOPACKET_LEN, values); + return -ENXIO; + } + + /* enable tp */ + error = i2c_smbus_write_byte(client, ETP_SMBUS_ENABLE_TP); + if (error) { + dev_err(&client->dev, "failed to enable touchpad: %d\n", error); + return error; + } + + return 0; +} + +static int elan_smbus_set_mode(struct i2c_client *client, u8 mode) +{ + u8 cmd[4] = { 0x00, 0x07, 0x00, mode }; + + return i2c_smbus_write_block_data(client, ETP_SMBUS_IAP_CMD, + sizeof(cmd), cmd); +} + +static int elan_smbus_sleep_control(struct i2c_client *client, bool sleep) +{ + if (sleep) + return i2c_smbus_write_byte(client, ETP_SMBUS_SLEEP_CMD); + else + return 0; /* XXX should we send ETP_SMBUS_ENABLE_TP here? */ +} + +static int elan_smbus_power_control(struct i2c_client *client, bool enable) +{ + return 0; /* A no-op */ +} + +static int elan_smbus_calibrate(struct i2c_client *client) +{ + u8 cmd[4] = { 0x00, 0x08, 0x00, 0x01 }; + + return i2c_smbus_write_block_data(client, ETP_SMBUS_IAP_CMD, + sizeof(cmd), cmd); +} + +static int elan_smbus_calibrate_result(struct i2c_client *client, u8 *val) +{ + int error; + + error = i2c_smbus_read_block_data(client, + ETP_SMBUS_CALIBRATE_QUERY, val); + if (error < 0) + return error; + + return 0; +} + +static int elan_smbus_get_baseline_data(struct i2c_client *client, + bool max_baseline, u8 *value) +{ + int error; + u8 val[3]; + + error = i2c_smbus_read_block_data(client, + max_baseline ? + ETP_SMBUS_MAX_BASELINE_CMD : + ETP_SMBUS_MIN_BASELINE_CMD, + val); + if (error < 0) + return error; + + *value = be16_to_cpup((__be16 *)val); + + return 0; +} + +static int elan_smbus_get_version(struct i2c_client *client, + bool iap, u8 *version) +{ + int error; + u8 val[3]; + + error = i2c_smbus_read_block_data(client, + iap ? ETP_SMBUS_IAP_VERSION_CMD : + ETP_SMBUS_FW_VERSION_CMD, + val); + if (error < 0) { + dev_err(&client->dev, "failed to get %s version: %d\n", + iap ? "IAP" : "FW", error); + return error; + } + + *version = val[2]; + return 0; +} + +static int elan_smbus_get_sm_version(struct i2c_client *client, u8 *version) +{ + int error; + u8 val[3]; + + error = i2c_smbus_read_block_data(client, + ETP_SMBUS_SM_VERSION_CMD, val); + if (error < 0) { + dev_err(&client->dev, "failed to get SM version: %d\n", error); + return error; + } + + *version = val[0]; /* XXX Why 0 and not 2 as in IAP/FW versions? */ + return 0; +} + +static int elan_smbus_get_product_id(struct i2c_client *client, u8 *id) +{ + int error; + u8 val[3]; + + error = i2c_smbus_read_block_data(client, + ETP_SMBUS_UNIQUEID_CMD, val); + if (error < 0) { + dev_err(&client->dev, "failed to get product ID: %d\n", error); + return error; + } + + *id = val[1]; + return 0; +} + +static int elan_smbus_get_checksum(struct i2c_client *client, + bool iap, u16 *csum) +{ + int error; + u8 val[3]; + + error = i2c_smbus_read_block_data(client, + iap ? ETP_SMBUS_FW_CHECKSUM_CMD : + ETP_SMBUS_IAP_CHECKSUM_CMD, + val); + if (error < 0) { + dev_err(&client->dev, "failed to get %s checksum: %d\n", + iap ? "IAP" : "FW", error); + return error; + } + + *csum = be16_to_cpup((__be16 *)val); + return 0; +} + +static int elan_smbus_get_max(struct i2c_client *client, + unsigned int *max_x, unsigned int *max_y) +{ + int error; + u8 val[3]; + + error = i2c_smbus_read_block_data(client, ETP_SMBUS_RANGE_CMD, val); + if (error) { + dev_err(&client->dev, "failed to get dimensions: %d\n", error); + return error; + } + + *max_x = (0x0f & val[0]) << 8 | val[1]; + *max_y = (0xf0 & val[0]) << 4 | val[2]; + + return 0; +} + +static int elan_smbus_get_resolution(struct i2c_client *client, + u8 *hw_res_x, u8 *hw_res_y) +{ + int error; + u8 val[3]; + + error = i2c_smbus_read_block_data(client, + ETP_SMBUS_RESOLUTION_CMD, val); + if (error) { + dev_err(&client->dev, "failed to get resolution: %d\n", error); + return error; + } + + *hw_res_x = val[1] & 0x0F; + *hw_res_y = (val[1] & 0xF0) >> 4; + + return 0; +} + +static int elan_smbus_get_num_traces(struct i2c_client *client, + unsigned int *x_traces, + unsigned int *y_traces) +{ + int error; + u8 val[3]; + + error = i2c_smbus_read_block_data(client, + ETP_SMBUS_XY_TRACENUM_CMD, val); + if (error) { + dev_err(&client->dev, "failed to get trace info: %d\n", error); + return error; + } + + *x_traces = val[1] - 1; + *y_traces = val[2] - 1; + + return 0; +} + +static int elan_smbus_iap_get_mode(struct i2c_client *client, + enum tp_mode *mode) +{ + int error; + u16 constant; + u8 val[3]; + + error = i2c_smbus_read_block_data(client, ETP_SMBUS_IAP_CTRL_CMD, val); + if (error < 0) { + dev_err(&client->dev, "failed to read iap ctrol register: %d\n", + error); + return error; + } + + constant = be16_to_cpup((__be16 *)val); + dev_dbg(&client->dev, "iap control reg: 0x%04x.\n", constant); + + *mode = (constant & ETP_SMBUS_IAP_MODE_ON) ? IAP_MODE : MAIN_MODE; + + return 0; +} + +static int elan_smbus_iap_reset(struct i2c_client *client) +{ + int error; + + error = i2c_smbus_write_byte(client, ETP_SMBUS_IAP_RESET_CMD); + if (error) { + dev_err(&client->dev, "cannot reset IC: %d\n", error); + return error; + } + + return 0; +} + +static int elan_smbus_set_flash_key(struct i2c_client *client) +{ + int error; + u8 cmd[4] = { 0x00, 0x0B, 0x00, 0x5A }; + + error = i2c_smbus_write_block_data(client, ETP_SMBUS_IAP_CMD, + sizeof(cmd), cmd); + if (error) { + dev_err(&client->dev, "cannot set flash key: %d\n", error); + return error; + } + + return 0; +} + +static int elan_smbus_prepare_fw_update(struct i2c_client *client) +{ + struct device *dev = &client->dev; + int len; + int error; + enum tp_mode mode; + u8 val[3]; + u8 cmd[4] = {0x0F, 0x78, 0x00, 0x06}; + u16 password; + + /* Get FW in which mode (IAP_MODE/MAIN_MODE) */ + error = elan_smbus_iap_get_mode(client, &mode); + if (error) + return error; + + if (mode == MAIN_MODE) { + + /* set flash key */ + error = elan_smbus_set_flash_key(client); + if (error) + return error; + + /* write iap password */ + if (i2c_smbus_write_byte(client, + ETP_SMBUS_IAP_PASSWORD_WRITE) < 0) { + dev_err(dev, "cannot write iap password\n"); + return -EIO; + } + + error = i2c_smbus_write_block_data(client, ETP_SMBUS_IAP_CMD, + sizeof(cmd), cmd); + if (error) { + dev_err(dev, "failed to write iap password: %d\n", + error); + return error; + } + + /* + * Read back password to make sure we enabled flash + * successfully. + */ + len = i2c_smbus_read_block_data(client, + ETP_SMBUS_IAP_PASSWORD_READ, + val); + if (len < sizeof(u16)) { + error = len < 0 ? len : -EIO; + dev_err(dev, "failed to read iap password: %d\n", + error); + return error; + } + + password = be16_to_cpup((__be16 *)val); + if (password != ETP_SMBUS_IAP_PASSWORD) { + dev_err(dev, "wrong iap password = 0x%X\n", password); + return -EIO; + } + + /* Wait 30ms for MAIN_MODE change to IAP_MODE */ + msleep(30); + } + + error = elan_smbus_set_flash_key(client); + if (error) + return error; + + /* Reset IC */ + error = elan_smbus_iap_reset(client); + if (error) + return error; + + return 0; +} + + +static int elan_smbus_write_fw_block(struct i2c_client *client, + const u8 *page, u16 checksum, int idx) +{ + struct device *dev = &client->dev; + int error; + u16 result; + u8 val[3]; + + /* + * Due to the limitation of smbus protocol limiting + * transfer to 32 bytes at a time, we must split block + * in 2 transfers. + */ + error = i2c_smbus_write_block_data(client, + ETP_SMBUS_WRITE_FW_BLOCK, + ETP_FW_PAGE_SIZE / 2, + page); + if (error) { + dev_err(dev, "Failed to write page %d (part %d): %d\n", + idx, 1, error); + return error; + } + + error = i2c_smbus_write_block_data(client, + ETP_SMBUS_WRITE_FW_BLOCK, + ETP_FW_PAGE_SIZE / 2, + page + ETP_FW_PAGE_SIZE / 2); + if (error) { + dev_err(dev, "Failed to write page %d (part %d): %d\n", + idx, 2, error); + return error; + } + + + /* Wait for F/W to update one page ROM data. */ + usleep_range(8000, 10000); + + error = i2c_smbus_read_block_data(client, + ETP_SMBUS_IAP_CTRL_CMD, val); + if (error < 0) { + dev_err(dev, "Failed to read IAP write result: %d\n", + error); + return error; + } + + result = be16_to_cpup((__be16 *)val); + if (result & (ETP_FW_IAP_PAGE_ERR | ETP_FW_IAP_INTF_ERR)) { + dev_err(dev, "IAP reports failed write: %04hx\n", + result); + return -EIO; + } + + return 0; +} + +static int elan_smbus_get_report(struct i2c_client *client, u8 *report) +{ + int len; + + len = i2c_smbus_read_block_data(client, + ETP_SMBUS_PACKET_QUERY, + &report[ETP_SMBUS_REPORT_OFFSET]); + if (len < 0) { + dev_err(&client->dev, "failed to read report data: %d\n", len); + return len; + } + + if (len != ETP_SMBUS_REPORT_LEN) { + dev_err(&client->dev, + "wrong report length (%d vs %d expected)\n", + len, ETP_SMBUS_REPORT_LEN); + return -EIO; + } + + return 0; +} + +static int elan_smbus_finish_fw_update(struct i2c_client *client, + struct completion *fw_completion) +{ + /* No special handling unlike I2C transport */ + return 0; +} + +const struct elan_transport_ops elan_smbus_ops = { + .initialize = elan_smbus_initialize, + .sleep_control = elan_smbus_sleep_control, + .power_control = elan_smbus_power_control, + .set_mode = elan_smbus_set_mode, + + .calibrate = elan_smbus_calibrate, + .calibrate_result = elan_smbus_calibrate_result, + + .get_baseline_data = elan_smbus_get_baseline_data, + + .get_version = elan_smbus_get_version, + .get_sm_version = elan_smbus_get_sm_version, + .get_product_id = elan_smbus_get_product_id, + .get_checksum = elan_smbus_get_checksum, + + .get_max = elan_smbus_get_max, + .get_resolution = elan_smbus_get_resolution, + .get_num_traces = elan_smbus_get_num_traces, + + .iap_get_mode = elan_smbus_iap_get_mode, + .iap_reset = elan_smbus_iap_reset, + + .prepare_fw_update = elan_smbus_prepare_fw_update, + .write_fw_block = elan_smbus_write_fw_block, + .finish_fw_update = elan_smbus_finish_fw_update, + + .get_report = elan_smbus_get_report, +}; -- cgit v1.2.3-59-g8ed1b From 4d5ce6bb11abee638052d8682263008fea57e068 Mon Sep 17 00:00:00 2001 From: Roberta Dobrescu Date: Thu, 23 Oct 2014 12:44:00 +0100 Subject: iio: Add ABI documentation for offset and scaled humidity This patch adds ABI documentation entries for in_humidityrelative_offset and in_humidityrelative_scale, since there is at least one user for these, Si7005 humidity and temperature sensor driver. Signed-off-by: Roberta Dobrescu Reviewed-by: Daniel Baluta 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 5a7fc666b07e..d9dd70f591ab 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -238,6 +238,7 @@ What: /sys/bus/iio/devices/iio:deviceX/in_tempY_offset 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 KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org Description: @@ -273,6 +274,7 @@ What: /sys/bus/iio/devices/iio:deviceX/in_rot_from_north_magnetic_tilt_comp_sca What: /sys/bus/iio/devices/iio:deviceX/in_rot_from_north_true_tilt_comp_scale 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 KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org Description: -- cgit v1.2.3-59-g8ed1b From ed56330df215b014c45940cceb97590d283b865f Mon Sep 17 00:00:00 2001 From: Roberta Dobrescu Date: Fri, 24 Oct 2014 22:41:00 +0100 Subject: iio: Add ABI documentation for RGBC intensity hardware gain factor This patch adds documentation for RGBC in_intensity_*_hardwaregain. There is at least one user for these, ADJD-S311-CR999 digital color sensor driver. Signed-off-by: Roberta Dobrescu Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index d9dd70f591ab..ea7e7abbbdf4 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -337,6 +337,10 @@ Description: are listed in this attribute. What /sys/bus/iio/devices/iio:deviceX/out_voltageY_hardwaregain +What: /sys/bus/iio/devices/iio:deviceX/in_intensity_red_hardwaregain +What: /sys/bus/iio/devices/iio:deviceX/in_intensity_green_hardwaregain +What: /sys/bus/iio/devices/iio:deviceX/in_intensity_blue_hardwaregain +What: /sys/bus/iio/devices/iio:deviceX/in_intensity_clear_hardwaregain KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org Description: -- cgit v1.2.3-59-g8ed1b From ce0694841ea61607afcbdb5a67bb0b00328357ef Mon Sep 17 00:00:00 2001 From: "Ivan T. Ivanov" Date: Wed, 22 Oct 2014 17:13:33 +0300 Subject: iio: iadc: Qualcomm SPMI PMIC current ADC driver The current ADC is peripheral of Qualcomm SPMI PMIC chips. It has 16 bits resolution and register space inside PMIC accessible across SPMI bus. The driver registers itself through IIO interface. Signed-off-by: Ivan T. Ivanov Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/adc/qcom,spmi-iadc.txt | 46 ++ drivers/iio/adc/Kconfig | 14 + drivers/iio/adc/Makefile | 1 + drivers/iio/adc/qcom-spmi-iadc.c | 595 +++++++++++++++++++++ 4 files changed, 656 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/qcom,spmi-iadc.txt create mode 100644 drivers/iio/adc/qcom-spmi-iadc.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/iio/adc/qcom,spmi-iadc.txt b/Documentation/devicetree/bindings/iio/adc/qcom,spmi-iadc.txt new file mode 100644 index 000000000000..4e36d6e2f7b6 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/qcom,spmi-iadc.txt @@ -0,0 +1,46 @@ +Qualcomm's SPMI PMIC current ADC + +QPNP PMIC current ADC (IADC) provides interface to clients to read current. +A 16 bit ADC is used for current measurements. IADC can measure the current +through an external resistor (channel 1) or internal (built-in) resistor +(channel 0). When using an external resistor it is to be described by +qcom,external-resistor-micro-ohms property. + +IADC node: + +- compatible: + Usage: required + Value type: + Definition: Should contain "qcom,spmi-iadc". + +- reg: + Usage: required + Value type: + Definition: IADC base address and length in the SPMI PMIC register map + +- interrupts: + Usage: optional + Value type: + Definition: End of ADC conversion. + +- qcom,external-resistor-micro-ohms: + Usage: optional + Value type: + Definition: Sense resister value in micro Ohm. + If not defined value of 10000 micro Ohms will be used. + +Example: + /* IADC node */ + pmic_iadc: iadc@3600 { + compatible = "qcom,spmi-iadc"; + reg = <0x3600 0x100>; + interrupts = <0x0 0x36 0x0 IRQ_TYPE_EDGE_RISING>; + qcom,external-resistor-micro-ohms = <10000>; + #io-channel-cells = <1>; + }; + + /* IIO client node */ + bat { + io-channels = <&pmic_iadc 0>; + io-channel-names = "iadc"; + }; diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 88bdc8f612e2..d0924f3cfa25 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -206,6 +206,20 @@ config NAU7802 To compile this driver as a module, choose M here: the module will be called nau7802. +config QCOM_SPMI_IADC + tristate "Qualcomm SPMI PMIC current ADC" + depends on SPMI + select REGMAP_SPMI + help + This is the IIO Current ADC driver for Qualcomm QPNP IADC Chip. + + The driver supports single mode operation to read from one of two + channels (external or internal). Hardware have additional + channels internally used for gain and offset calibration. + + To compile this driver as a module, choose M here: the module will + be called qcom-spmi-iadc. + config ROCKCHIP_SARADC tristate "Rockchip SARADC driver" depends on ARCH_ROCKCHIP || (ARM && COMPILE_TEST) diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index cb88a6a23b8f..c06718b9d8ce 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_MCP320X) += mcp320x.o obj-$(CONFIG_MCP3422) += mcp3422.o obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o obj-$(CONFIG_NAU7802) += nau7802.o +obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o diff --git a/drivers/iio/adc/qcom-spmi-iadc.c b/drivers/iio/adc/qcom-spmi-iadc.c new file mode 100644 index 000000000000..b9666f2f5e51 --- /dev/null +++ b/drivers/iio/adc/qcom-spmi-iadc.c @@ -0,0 +1,595 @@ +/* + * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* IADC register and bit definition */ +#define IADC_REVISION2 0x1 +#define IADC_REVISION2_SUPPORTED_IADC 1 + +#define IADC_PERPH_TYPE 0x4 +#define IADC_PERPH_TYPE_ADC 8 + +#define IADC_PERPH_SUBTYPE 0x5 +#define IADC_PERPH_SUBTYPE_IADC 3 + +#define IADC_STATUS1 0x8 +#define IADC_STATUS1_OP_MODE 4 +#define IADC_STATUS1_REQ_STS BIT(1) +#define IADC_STATUS1_EOC BIT(0) +#define IADC_STATUS1_REQ_STS_EOC_MASK 0x3 + +#define IADC_MODE_CTL 0x40 +#define IADC_OP_MODE_SHIFT 3 +#define IADC_OP_MODE_NORMAL 0 +#define IADC_TRIM_EN BIT(0) + +#define IADC_EN_CTL1 0x46 +#define IADC_EN_CTL1_SET BIT(7) + +#define IADC_CH_SEL_CTL 0x48 + +#define IADC_DIG_PARAM 0x50 +#define IADC_DIG_DEC_RATIO_SEL_SHIFT 2 + +#define IADC_HW_SETTLE_DELAY 0x51 + +#define IADC_CONV_REQ 0x52 +#define IADC_CONV_REQ_SET BIT(7) + +#define IADC_FAST_AVG_CTL 0x5a +#define IADC_FAST_AVG_EN 0x5b +#define IADC_FAST_AVG_EN_SET BIT(7) + +#define IADC_PERH_RESET_CTL3 0xda +#define IADC_FOLLOW_WARM_RB BIT(2) + +#define IADC_DATA 0x60 /* 16 bits */ + +#define IADC_SEC_ACCESS 0xd0 +#define IADC_SEC_ACCESS_DATA 0xa5 + +#define IADC_NOMINAL_RSENSE 0xf4 +#define IADC_NOMINAL_RSENSE_SIGN_MASK BIT(7) + +#define IADC_REF_GAIN_MICRO_VOLTS 17857 + +#define IADC_INT_RSENSE_DEVIATION 15625 /* nano Ohms per bit */ + +#define IADC_INT_RSENSE_IDEAL_VALUE 10000 /* micro Ohms */ +#define IADC_INT_RSENSE_DEFAULT_VALUE 7800 /* micro Ohms */ +#define IADC_INT_RSENSE_DEFAULT_GF 9000 /* micro Ohms */ +#define IADC_INT_RSENSE_DEFAULT_SMIC 9700 /* micro Ohms */ + +#define IADC_CONV_TIME_MIN_US 2000 +#define IADC_CONV_TIME_MAX_US 2100 + +#define IADC_DEF_PRESCALING 0 /* 1:1 */ +#define IADC_DEF_DECIMATION 0 /* 512 */ +#define IADC_DEF_HW_SETTLE_TIME 0 /* 0 us */ +#define IADC_DEF_AVG_SAMPLES 0 /* 1 sample */ + +/* IADC channel list */ +#define IADC_INT_RSENSE 0 +#define IADC_EXT_RSENSE 1 +#define IADC_GAIN_17P857MV 3 +#define IADC_EXT_OFFSET_CSP_CSN 5 +#define IADC_INT_OFFSET_CSP2_CSN2 6 + +/** + * struct iadc_chip - IADC Current ADC device structure. + * @regmap: regmap for register read/write. + * @dev: This device pointer. + * @base: base offset for the ADC peripheral. + * @rsense: Values of the internal and external sense resister in micro Ohms. + * @poll_eoc: Poll for end of conversion instead of waiting for IRQ. + * @offset: Raw offset values for the internal and external channels. + * @gain: Raw gain of the channels. + * @lock: ADC lock for access to the peripheral. + * @complete: ADC notification after end of conversion interrupt is received. + */ +struct iadc_chip { + struct regmap *regmap; + struct device *dev; + u16 base; + bool poll_eoc; + u32 rsense[2]; + u16 offset[2]; + u16 gain; + struct mutex lock; + struct completion complete; +}; + +static int iadc_read(struct iadc_chip *iadc, u16 offset, u8 *data) +{ + unsigned int val; + int ret; + + ret = regmap_read(iadc->regmap, iadc->base + offset, &val); + if (ret < 0) + return ret; + + *data = val; + return 0; +} + +static int iadc_write(struct iadc_chip *iadc, u16 offset, u8 data) +{ + return regmap_write(iadc->regmap, iadc->base + offset, data); +} + +static int iadc_reset(struct iadc_chip *iadc) +{ + u8 data; + int ret; + + ret = iadc_write(iadc, IADC_SEC_ACCESS, IADC_SEC_ACCESS_DATA); + if (ret < 0) + return ret; + + ret = iadc_read(iadc, IADC_PERH_RESET_CTL3, &data); + if (ret < 0) + return ret; + + ret = iadc_write(iadc, IADC_SEC_ACCESS, IADC_SEC_ACCESS_DATA); + if (ret < 0) + return ret; + + data |= IADC_FOLLOW_WARM_RB; + + return iadc_write(iadc, IADC_PERH_RESET_CTL3, data); +} + +static int iadc_set_state(struct iadc_chip *iadc, bool state) +{ + return iadc_write(iadc, IADC_EN_CTL1, state ? IADC_EN_CTL1_SET : 0); +} + +static void iadc_status_show(struct iadc_chip *iadc) +{ + u8 mode, sta1, chan, dig, en, req; + int ret; + + ret = iadc_read(iadc, IADC_MODE_CTL, &mode); + if (ret < 0) + return; + + ret = iadc_read(iadc, IADC_DIG_PARAM, &dig); + if (ret < 0) + return; + + ret = iadc_read(iadc, IADC_CH_SEL_CTL, &chan); + if (ret < 0) + return; + + ret = iadc_read(iadc, IADC_CONV_REQ, &req); + if (ret < 0) + return; + + ret = iadc_read(iadc, IADC_STATUS1, &sta1); + if (ret < 0) + return; + + ret = iadc_read(iadc, IADC_EN_CTL1, &en); + if (ret < 0) + return; + + dev_err(iadc->dev, + "mode:%02x en:%02x chan:%02x dig:%02x req:%02x sta1:%02x\n", + mode, en, chan, dig, req, sta1); +} + +static int iadc_configure(struct iadc_chip *iadc, int channel) +{ + u8 decim, mode; + int ret; + + /* Mode selection */ + mode = (IADC_OP_MODE_NORMAL << IADC_OP_MODE_SHIFT) | IADC_TRIM_EN; + ret = iadc_write(iadc, IADC_MODE_CTL, mode); + if (ret < 0) + return ret; + + /* Channel selection */ + ret = iadc_write(iadc, IADC_CH_SEL_CTL, channel); + if (ret < 0) + return ret; + + /* Digital parameter setup */ + decim = IADC_DEF_DECIMATION << IADC_DIG_DEC_RATIO_SEL_SHIFT; + ret = iadc_write(iadc, IADC_DIG_PARAM, decim); + if (ret < 0) + return ret; + + /* HW settle time delay */ + ret = iadc_write(iadc, IADC_HW_SETTLE_DELAY, IADC_DEF_HW_SETTLE_TIME); + if (ret < 0) + return ret; + + ret = iadc_write(iadc, IADC_FAST_AVG_CTL, IADC_DEF_AVG_SAMPLES); + if (ret < 0) + return ret; + + if (IADC_DEF_AVG_SAMPLES) + ret = iadc_write(iadc, IADC_FAST_AVG_EN, IADC_FAST_AVG_EN_SET); + else + ret = iadc_write(iadc, IADC_FAST_AVG_EN, 0); + + if (ret < 0) + return ret; + + if (!iadc->poll_eoc) + reinit_completion(&iadc->complete); + + ret = iadc_set_state(iadc, true); + if (ret < 0) + return ret; + + /* Request conversion */ + return iadc_write(iadc, IADC_CONV_REQ, IADC_CONV_REQ_SET); +} + +static int iadc_poll_wait_eoc(struct iadc_chip *iadc, unsigned int interval_us) +{ + unsigned int count, retry; + int ret; + u8 sta1; + + retry = interval_us / IADC_CONV_TIME_MIN_US; + + for (count = 0; count < retry; count++) { + ret = iadc_read(iadc, IADC_STATUS1, &sta1); + if (ret < 0) + return ret; + + sta1 &= IADC_STATUS1_REQ_STS_EOC_MASK; + if (sta1 == IADC_STATUS1_EOC) + return 0; + + usleep_range(IADC_CONV_TIME_MIN_US, IADC_CONV_TIME_MAX_US); + } + + iadc_status_show(iadc); + + return -ETIMEDOUT; +} + +static int iadc_read_result(struct iadc_chip *iadc, u16 *data) +{ + return regmap_bulk_read(iadc->regmap, iadc->base + IADC_DATA, data, 2); +} + +static int iadc_do_conversion(struct iadc_chip *iadc, int chan, u16 *data) +{ + unsigned int wait; + int ret; + + ret = iadc_configure(iadc, chan); + if (ret < 0) + goto exit; + + wait = BIT(IADC_DEF_AVG_SAMPLES) * IADC_CONV_TIME_MIN_US * 2; + + if (iadc->poll_eoc) { + ret = iadc_poll_wait_eoc(iadc, wait); + } else { + ret = wait_for_completion_timeout(&iadc->complete, wait); + if (!ret) + ret = -ETIMEDOUT; + else + /* double check conversion status */ + ret = iadc_poll_wait_eoc(iadc, IADC_CONV_TIME_MIN_US); + } + + if (!ret) + ret = iadc_read_result(iadc, data); +exit: + iadc_set_state(iadc, false); + if (ret < 0) + dev_err(iadc->dev, "conversion failed\n"); + + return ret; +} + +static int iadc_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct iadc_chip *iadc = iio_priv(indio_dev); + s32 isense_ua, vsense_uv; + u16 adc_raw, vsense_raw; + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + mutex_lock(&iadc->lock); + ret = iadc_do_conversion(iadc, chan->channel, &adc_raw); + mutex_unlock(&iadc->lock); + if (ret < 0) + return ret; + + vsense_raw = adc_raw - iadc->offset[chan->channel]; + + vsense_uv = vsense_raw * IADC_REF_GAIN_MICRO_VOLTS; + vsense_uv /= (s32)iadc->gain - iadc->offset[chan->channel]; + + isense_ua = vsense_uv / iadc->rsense[chan->channel]; + + dev_dbg(iadc->dev, "off %d gain %d adc %d %duV I %duA\n", + iadc->offset[chan->channel], iadc->gain, + adc_raw, vsense_uv, isense_ua); + + *val = isense_ua; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = 0; + *val2 = 1000; + return IIO_VAL_INT_PLUS_MICRO; + } + + return -EINVAL; +} + +static const struct iio_info iadc_info = { + .read_raw = iadc_read_raw, + .driver_module = THIS_MODULE, +}; + +static irqreturn_t iadc_isr(int irq, void *dev_id) +{ + struct iadc_chip *iadc = dev_id; + + complete(&iadc->complete); + + return IRQ_HANDLED; +} + +static int iadc_update_offset(struct iadc_chip *iadc) +{ + int ret; + + ret = iadc_do_conversion(iadc, IADC_GAIN_17P857MV, &iadc->gain); + if (ret < 0) + return ret; + + ret = iadc_do_conversion(iadc, IADC_INT_OFFSET_CSP2_CSN2, + &iadc->offset[IADC_INT_RSENSE]); + if (ret < 0) + return ret; + + if (iadc->gain == iadc->offset[IADC_INT_RSENSE]) { + dev_err(iadc->dev, "error: internal offset == gain %d\n", + iadc->gain); + return -EINVAL; + } + + ret = iadc_do_conversion(iadc, IADC_EXT_OFFSET_CSP_CSN, + &iadc->offset[IADC_EXT_RSENSE]); + if (ret < 0) + return ret; + + if (iadc->gain == iadc->offset[IADC_EXT_RSENSE]) { + dev_err(iadc->dev, "error: external offset == gain %d\n", + iadc->gain); + return -EINVAL; + } + + return 0; +} + +static int iadc_version_check(struct iadc_chip *iadc) +{ + u8 val; + int ret; + + ret = iadc_read(iadc, IADC_PERPH_TYPE, &val); + if (ret < 0) + return ret; + + if (val < IADC_PERPH_TYPE_ADC) { + dev_err(iadc->dev, "%d is not ADC\n", val); + return -EINVAL; + } + + ret = iadc_read(iadc, IADC_PERPH_SUBTYPE, &val); + if (ret < 0) + return ret; + + if (val < IADC_PERPH_SUBTYPE_IADC) { + dev_err(iadc->dev, "%d is not IADC\n", val); + return -EINVAL; + } + + ret = iadc_read(iadc, IADC_REVISION2, &val); + if (ret < 0) + return ret; + + if (val < IADC_REVISION2_SUPPORTED_IADC) { + dev_err(iadc->dev, "revision %d not supported\n", val); + return -EINVAL; + } + + return 0; +} + +static int iadc_rsense_read(struct iadc_chip *iadc, struct device_node *node) +{ + int ret, sign, int_sense; + u8 deviation; + + ret = of_property_read_u32(node, "qcom,external-resistor-micro-ohms", + &iadc->rsense[IADC_EXT_RSENSE]); + if (ret < 0) + iadc->rsense[IADC_EXT_RSENSE] = IADC_INT_RSENSE_IDEAL_VALUE; + + if (!iadc->rsense[IADC_EXT_RSENSE]) { + dev_err(iadc->dev, "external resistor can't be zero Ohms"); + return -EINVAL; + } + + ret = iadc_read(iadc, IADC_NOMINAL_RSENSE, &deviation); + if (ret < 0) + return ret; + + /* + * Deviation value stored is an offset from 10 mili Ohms, bit 7 is + * the sign, the remaining bits have an LSB of 15625 nano Ohms. + */ + sign = (deviation & IADC_NOMINAL_RSENSE_SIGN_MASK) ? -1 : 1; + + deviation &= ~IADC_NOMINAL_RSENSE_SIGN_MASK; + + /* Scale it to nono Ohms */ + int_sense = IADC_INT_RSENSE_IDEAL_VALUE * 1000; + int_sense += sign * deviation * IADC_INT_RSENSE_DEVIATION; + int_sense /= 1000; /* micro Ohms */ + + iadc->rsense[IADC_INT_RSENSE] = int_sense; + return 0; +} + +static const struct iio_chan_spec iadc_channels[] = { + { + .type = IIO_CURRENT, + .datasheet_name = "INTERNAL_RSENSE", + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + .indexed = 1, + }, + { + .type = IIO_CURRENT, + .datasheet_name = "EXTERNAL_RSENSE", + .channel = 1, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + .indexed = 1, + }, +}; + +static int iadc_probe(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct device *dev = &pdev->dev; + struct iio_dev *indio_dev; + struct iadc_chip *iadc; + int ret, irq_eoc; + u32 res; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*iadc)); + if (!indio_dev) + return -ENOMEM; + + iadc = iio_priv(indio_dev); + iadc->dev = dev; + + iadc->regmap = dev_get_regmap(dev->parent, NULL); + if (!iadc->regmap) + return -ENODEV; + + init_completion(&iadc->complete); + mutex_init(&iadc->lock); + + ret = of_property_read_u32(node, "reg", &res); + if (ret < 0) + return -ENODEV; + + iadc->base = res; + + ret = iadc_version_check(iadc); + if (ret < 0) + return -ENODEV; + + ret = iadc_rsense_read(iadc, node); + if (ret < 0) + return -ENODEV; + + dev_dbg(iadc->dev, "sense resistors %d and %d micro Ohm\n", + iadc->rsense[IADC_INT_RSENSE], + iadc->rsense[IADC_EXT_RSENSE]); + + irq_eoc = platform_get_irq(pdev, 0); + if (irq_eoc == -EPROBE_DEFER) + return irq_eoc; + + if (irq_eoc < 0) + iadc->poll_eoc = true; + + ret = iadc_reset(iadc); + if (ret < 0) { + dev_err(dev, "reset failed\n"); + return ret; + } + + if (!iadc->poll_eoc) { + ret = devm_request_irq(dev, irq_eoc, iadc_isr, 0, + "spmi-iadc", iadc); + if (!ret) + enable_irq_wake(irq_eoc); + else + return ret; + } else { + device_init_wakeup(iadc->dev, 1); + } + + ret = iadc_update_offset(iadc); + if (ret < 0) { + dev_err(dev, "failed offset calibration\n"); + return ret; + } + + indio_dev->dev.parent = dev; + indio_dev->dev.of_node = node; + indio_dev->name = pdev->name; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &iadc_info; + indio_dev->channels = iadc_channels; + indio_dev->num_channels = ARRAY_SIZE(iadc_channels); + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct of_device_id iadc_match_table[] = { + { .compatible = "qcom,spmi-iadc" }, + { } +}; + +MODULE_DEVICE_TABLE(of, iadc_match_table); + +static struct platform_driver iadc_driver = { + .driver = { + .name = "qcom-spmi-iadc", + .of_match_table = iadc_match_table, + }, + .probe = iadc_probe, +}; + +module_platform_driver(iadc_driver); + +MODULE_ALIAS("platform:qcom-spmi-iadc"); +MODULE_DESCRIPTION("Qualcomm SPMI PMIC current ADC driver"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Ivan T. Ivanov "); -- cgit v1.2.3-59-g8ed1b From ec95a345198fc97022c98b44446c96b31d693882 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 22 Oct 2014 11:38:27 +0200 Subject: clocksource: sh_tmu: Document R-Mobile r8a7740 binding Compared to the r8a7779, the r8a7740 lacks the input capture register, which is not used by the driver (the current driver already handles the r8a7740 in the non-DT case). Signed-off-by: Geert Uytterhoeven Acked-by: Laurent Pinchart Signed-off-by: Simon Horman --- Documentation/devicetree/bindings/timer/renesas,tmu.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/timer/renesas,tmu.txt b/Documentation/devicetree/bindings/timer/renesas,tmu.txt index 7db89fb25444..4ae7910af09f 100644 --- a/Documentation/devicetree/bindings/timer/renesas,tmu.txt +++ b/Documentation/devicetree/bindings/timer/renesas,tmu.txt @@ -1,4 +1,4 @@ -* Renesas R-Car Timer Unit (TMU) +* Renesas R-Mobile/R-Car Timer Unit (TMU) The TMU is a 32-bit timer/counter with configurable clock inputs and programmable compare match. @@ -9,6 +9,7 @@ are independent. The TMU hardware supports up to three channels. Required Properties: - compatible: must contain one or more of the following: + - "renesas,tmu-r8a7740" for the r8a7740 TMU - "renesas,tmu-r8a7779" for the r8a7779 TMU - "renesas,tmu" for any TMU. This is a fallback for the above renesas,tmu-* entries -- cgit v1.2.3-59-g8ed1b From f9d6ec6f546a061f5b9eeb53927f1bfac5fb8278 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 24 Oct 2014 13:31:52 +0200 Subject: clocksource: sh_tmu: Document r8a7778 binding The r8a7778 is very similar to the r8a7779, and already handled by the current driver in the non-DT case. Signed-off-by: Geert Uytterhoeven Acked-by: Laurent Pinchart Signed-off-by: Simon Horman --- Documentation/devicetree/bindings/timer/renesas,tmu.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/timer/renesas,tmu.txt b/Documentation/devicetree/bindings/timer/renesas,tmu.txt index 4ae7910af09f..cd5f20bf2582 100644 --- a/Documentation/devicetree/bindings/timer/renesas,tmu.txt +++ b/Documentation/devicetree/bindings/timer/renesas,tmu.txt @@ -10,6 +10,7 @@ Required Properties: - compatible: must contain one or more of the following: - "renesas,tmu-r8a7740" for the r8a7740 TMU + - "renesas,tmu-r8a7778" for the r8a7778 TMU - "renesas,tmu-r8a7779" for the r8a7779 TMU - "renesas,tmu" for any TMU. This is a fallback for the above renesas,tmu-* entries -- cgit v1.2.3-59-g8ed1b From d5153cd734dd6c1243bb3dc98065be99b10d049f Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 24 Oct 2014 13:29:38 +0200 Subject: clocksource: sh_mtu2: Drop incorrect SoC family name The MTU2 hardware block is found in many Renesas SH and ARM SoCs, but not in R-Car. Signed-off-by: Geert Uytterhoeven Acked-by: Laurent Pinchart Signed-off-by: Simon Horman --- Documentation/devicetree/bindings/timer/renesas,mtu2.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/timer/renesas,mtu2.txt b/Documentation/devicetree/bindings/timer/renesas,mtu2.txt index d9a8d5af1a21..ba0a34d97eb8 100644 --- a/Documentation/devicetree/bindings/timer/renesas,mtu2.txt +++ b/Documentation/devicetree/bindings/timer/renesas,mtu2.txt @@ -1,4 +1,4 @@ -* Renesas R-Car Multi-Function Timer Pulse Unit 2 (MTU2) +* Renesas Multi-Function Timer Pulse Unit 2 (MTU2) The MTU2 is a multi-purpose, multi-channel timer/counter with configurable clock inputs and programmable compare match. -- cgit v1.2.3-59-g8ed1b From 24a543254b4aba9bbf4d0793ad8d7d91a07b7182 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 14 Oct 2014 11:12:54 +0200 Subject: dt: bindings: ux500: Add documentation for PM domains Signed-off-by: Ulf Hansson Signed-off-by: Linus Walleij --- .../devicetree/bindings/arm/ux500/power_domain.txt | 35 ++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/ux500/power_domain.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/ux500/power_domain.txt b/Documentation/devicetree/bindings/arm/ux500/power_domain.txt new file mode 100644 index 000000000000..5679d1742d3e --- /dev/null +++ b/Documentation/devicetree/bindings/arm/ux500/power_domain.txt @@ -0,0 +1,35 @@ +* ST-Ericsson UX500 PM Domains + +UX500 supports multiple PM domains which are used to gate power to one or +more peripherals on the SOC. + +The implementation of PM domains for UX500 are based upon the generic PM domain +and use the corresponding DT bindings. + +==PM domain providers== + +Required properties: + - compatible: Must be "stericsson,ux500-pm-domains". + - #power-domain-cells : Number of cells in a power domain specifier, must be 1. + +Example: + pm_domains: pm_domains0 { + compatible = "stericsson,ux500-pm-domains"; + #power-domain-cells = <1>; + }; + +==PM domain consumers== + +Required properties: + - power-domains: A phandle and PM domain specifier. Below are the list of + valid specifiers: + + Index Specifier + ----- --------- + 0 DOMAIN_VAPE + +Example: + sdi0_per1@80126000 { + compatible = "arm,pl18x", "arm,primecell"; + power-domains = <&pm_domains DOMAIN_VAPE> + }; -- cgit v1.2.3-59-g8ed1b From 90446d0746c399e47246232f66ff2fa8616ba470 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 28 Oct 2014 15:28:07 +0100 Subject: ALSA: doc: Add missing headers and compress stuff to alsa-driver-api.tmpl Some header files have kereldoc comments but are not referred properly. Let's add them. Signed-off-by: Takashi Iwai --- Documentation/DocBook/alsa-driver-api.tmpl | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'Documentation') diff --git a/Documentation/DocBook/alsa-driver-api.tmpl b/Documentation/DocBook/alsa-driver-api.tmpl index 0230a96f0564..13f8b241f042 100644 --- a/Documentation/DocBook/alsa-driver-api.tmpl +++ b/Documentation/DocBook/alsa-driver-api.tmpl @@ -57,6 +57,7 @@ !Esound/core/pcm.c !Esound/core/pcm_lib.c !Esound/core/pcm_native.c +!include/sound/pcm.h PCM Format Helpers !Esound/core/pcm_misc.c @@ -64,6 +65,10 @@ PCM Memory Management !Esound/core/pcm_memory.c + PCM DMA Engine API +!Esound/core/pcm_dmaengine.c +!Iinclude/sound/dmaengine_pcm.h + Control/Mixer API General Control Interface @@ -91,12 +96,19 @@ !Esound/core/info.c + Compress Offload + Compress Offload API +!Esound/core/compress_offload.c +!Iinclude/sound/compress_driver.h + + Miscellaneous Functions Hardware-Dependent Devices API !Esound/core/hwdep.c Jack Abstraction Layer API !Esound/core/jack.c +!Iinclude/sound/jack.h ISA DMA Helpers !Esound/core/isadma.c -- cgit v1.2.3-59-g8ed1b From e3a2e87893125bcd99bd7e1ddf9bfc421e492572 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Thu, 23 Oct 2014 17:27:07 +0900 Subject: gpio: rename gpio_lock_as_irq to gpiochip_lock_as_irq This function actually operates on a gpio_chip, so its prefix should reflect that fact for consistency with other functions defined in gpio/driver.h. Signed-off-by: Alexandre Courbot Signed-off-by: Linus Walleij --- Documentation/gpio/driver.txt | 4 ++-- drivers/gpio/gpio-bcm-kona.c | 4 ++-- drivers/gpio/gpio-dwapb.c | 4 ++-- drivers/gpio/gpio-em.c | 4 ++-- drivers/gpio/gpio-mcp23s08.c | 4 ++-- drivers/gpio/gpio-omap.c | 2 +- drivers/gpio/gpio-tegra.c | 4 ++-- drivers/gpio/gpio-vr41xx.c | 4 ++-- drivers/gpio/gpiolib-acpi.c | 6 +++--- drivers/gpio/gpiolib-sysfs.c | 4 ++-- drivers/gpio/gpiolib.c | 16 ++++++++-------- drivers/pinctrl/pinctrl-at91.c | 4 ++-- drivers/pinctrl/samsung/pinctrl-exynos.c | 4 ++-- drivers/pinctrl/sunxi/pinctrl-sunxi.c | 6 +++--- include/linux/gpio.h | 7 ++++--- include/linux/gpio/driver.h | 4 ++-- 16 files changed, 41 insertions(+), 40 deletions(-) (limited to 'Documentation') diff --git a/Documentation/gpio/driver.txt b/Documentation/gpio/driver.txt index 31e0b5db55d8..90d0f6aba7a6 100644 --- a/Documentation/gpio/driver.txt +++ b/Documentation/gpio/driver.txt @@ -158,12 +158,12 @@ Locking IRQ usage Input GPIOs can be used as IRQ signals. When this happens, a driver is requested to mark the GPIO as being used as an IRQ: - int gpio_lock_as_irq(struct gpio_chip *chip, unsigned int offset) + int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset) This will prevent the use of non-irq related GPIO APIs until the GPIO IRQ lock is released: - void gpio_unlock_as_irq(struct gpio_chip *chip, unsigned int offset) + void gpiochip_unlock_as_irq(struct gpio_chip *chip, unsigned int offset) When implementing an irqchip inside a GPIO driver, these two functions should typically be called in the .startup() and .shutdown() callbacks from the diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c index de0801e9767a..56fb5ce47aa1 100644 --- a/drivers/gpio/gpio-bcm-kona.c +++ b/drivers/gpio/gpio-bcm-kona.c @@ -470,7 +470,7 @@ static int bcm_kona_gpio_irq_reqres(struct irq_data *d) { struct bcm_kona_gpio *kona_gpio = irq_data_get_irq_chip_data(d); - if (gpio_lock_as_irq(&kona_gpio->gpio_chip, d->hwirq)) { + if (gpiochip_lock_as_irq(&kona_gpio->gpio_chip, d->hwirq)) { dev_err(kona_gpio->gpio_chip.dev, "unable to lock HW IRQ %lu for IRQ\n", d->hwirq); @@ -483,7 +483,7 @@ static void bcm_kona_gpio_irq_relres(struct irq_data *d) { struct bcm_kona_gpio *kona_gpio = irq_data_get_irq_chip_data(d); - gpio_unlock_as_irq(&kona_gpio->gpio_chip, d->hwirq); + gpiochip_unlock_as_irq(&kona_gpio->gpio_chip, d->hwirq); } static struct irq_chip bcm_gpio_irq_chip = { diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index b43cd84b61f1..4beb37839392 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -194,7 +194,7 @@ static int dwapb_irq_reqres(struct irq_data *d) struct dwapb_gpio *gpio = igc->private; struct bgpio_chip *bgc = &gpio->ports[0].bgc; - if (gpio_lock_as_irq(&bgc->gc, irqd_to_hwirq(d))) { + if (gpiochip_lock_as_irq(&bgc->gc, irqd_to_hwirq(d))) { dev_err(gpio->dev, "unable to lock HW IRQ %lu for IRQ\n", irqd_to_hwirq(d)); return -EINVAL; @@ -208,7 +208,7 @@ static void dwapb_irq_relres(struct irq_data *d) struct dwapb_gpio *gpio = igc->private; struct bgpio_chip *bgc = &gpio->ports[0].bgc; - gpio_unlock_as_irq(&bgc->gc, irqd_to_hwirq(d)); + gpiochip_unlock_as_irq(&bgc->gc, irqd_to_hwirq(d)); } static int dwapb_irq_set_type(struct irq_data *d, u32 type) diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c index fe49ec3cdb7d..21d34d4d473d 100644 --- a/drivers/gpio/gpio-em.c +++ b/drivers/gpio/gpio-em.c @@ -103,7 +103,7 @@ static int em_gio_irq_reqres(struct irq_data *d) { struct em_gio_priv *p = irq_data_get_irq_chip_data(d); - if (gpio_lock_as_irq(&p->gpio_chip, irqd_to_hwirq(d))) { + if (gpiochip_lock_as_irq(&p->gpio_chip, irqd_to_hwirq(d))) { dev_err(p->gpio_chip.dev, "unable to lock HW IRQ %lu for IRQ\n", irqd_to_hwirq(d)); @@ -116,7 +116,7 @@ static void em_gio_irq_relres(struct irq_data *d) { struct em_gio_priv *p = irq_data_get_irq_chip_data(d); - gpio_unlock_as_irq(&p->gpio_chip, irqd_to_hwirq(d)); + gpiochip_unlock_as_irq(&p->gpio_chip, irqd_to_hwirq(d)); } diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c index 8488e2fd307c..468d10d2ac1e 100644 --- a/drivers/gpio/gpio-mcp23s08.c +++ b/drivers/gpio/gpio-mcp23s08.c @@ -444,7 +444,7 @@ static int mcp23s08_irq_reqres(struct irq_data *data) { struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data); - if (gpio_lock_as_irq(&mcp->chip, data->hwirq)) { + if (gpiochip_lock_as_irq(&mcp->chip, data->hwirq)) { dev_err(mcp->chip.dev, "unable to lock HW IRQ %lu for IRQ usage\n", data->hwirq); @@ -458,7 +458,7 @@ static void mcp23s08_irq_relres(struct irq_data *data) { struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data); - gpio_unlock_as_irq(&mcp->chip, data->hwirq); + gpiochip_unlock_as_irq(&mcp->chip, data->hwirq); } static struct irq_chip mcp23s08_irq_chip = { diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 415682f69214..a38686786e46 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -800,7 +800,7 @@ static void omap_gpio_irq_shutdown(struct irq_data *d) unsigned offset = GPIO_INDEX(bank, gpio); spin_lock_irqsave(&bank->lock, flags); - gpio_unlock_as_irq(&bank->chip, offset); + gpiochip_unlock_as_irq(&bank->chip, offset); bank->irq_usage &= ~(BIT(offset)); omap_disable_gpio_module(bank, offset); omap_reset_gpio(bank, gpio); diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 4e8fb8261a87..61bcfa93606d 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -233,7 +233,7 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type) return -EINVAL; } - ret = gpio_lock_as_irq(&tegra_gpio_chip, gpio); + ret = gpiochip_lock_as_irq(&tegra_gpio_chip, gpio); if (ret) { dev_err(dev, "unable to lock Tegra GPIO %d as IRQ\n", gpio); return ret; @@ -263,7 +263,7 @@ static void tegra_gpio_irq_shutdown(struct irq_data *d) { int gpio = d->hwirq; - gpio_unlock_as_irq(&tegra_gpio_chip, gpio); + gpiochip_unlock_as_irq(&tegra_gpio_chip, gpio); } static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) diff --git a/drivers/gpio/gpio-vr41xx.c b/drivers/gpio/gpio-vr41xx.c index dbf28fa03f67..cec55226143d 100644 --- a/drivers/gpio/gpio-vr41xx.c +++ b/drivers/gpio/gpio-vr41xx.c @@ -138,7 +138,7 @@ static void unmask_giuint_low(struct irq_data *d) static unsigned int startup_giuint(struct irq_data *data) { - if (gpio_lock_as_irq(&vr41xx_gpio_chip, data->hwirq)) + if (gpiochip_lock_as_irq(&vr41xx_gpio_chip, data->hwirq)) dev_err(vr41xx_gpio_chip.dev, "unable to lock HW IRQ %lu for IRQ\n", data->hwirq); @@ -150,7 +150,7 @@ static unsigned int startup_giuint(struct irq_data *data) static void shutdown_giuint(struct irq_data *data) { mask_giuint_low(data); - gpio_unlock_as_irq(&vr41xx_gpio_chip, data->hwirq); + gpiochip_unlock_as_irq(&vr41xx_gpio_chip, data->hwirq); } static struct irq_chip giuint_low_irq_chip = { diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 05c6275da224..349a7552dd23 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -153,7 +153,7 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares, gpiod_direction_input(desc); - ret = gpio_lock_as_irq(chip, pin); + ret = gpiochip_lock_as_irq(chip, pin); if (ret) { dev_err(chip->dev, "Failed to lock GPIO as interrupt\n"); goto fail_free_desc; @@ -209,7 +209,7 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares, fail_free_event: kfree(event); fail_unlock_irq: - gpio_unlock_as_irq(chip, pin); + gpiochip_unlock_as_irq(chip, pin); fail_free_desc: gpiochip_free_own_desc(desc); @@ -280,7 +280,7 @@ void acpi_gpiochip_free_interrupts(struct gpio_chip *chip) desc = event->desc; if (WARN_ON(IS_ERR(desc))) continue; - gpio_unlock_as_irq(chip, event->pin); + gpiochip_unlock_as_irq(chip, event->pin); gpiochip_free_own_desc(desc); list_del(&event->node); kfree(event); diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c index 5f2150b619a7..781fbed00fc3 100644 --- a/drivers/gpio/gpiolib-sysfs.c +++ b/drivers/gpio/gpiolib-sysfs.c @@ -161,7 +161,7 @@ static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev, desc->flags &= ~GPIO_TRIGGER_MASK; if (!gpio_flags) { - gpio_unlock_as_irq(desc->chip, gpio_chip_hwgpio(desc)); + gpiochip_unlock_as_irq(desc->chip, gpio_chip_hwgpio(desc)); ret = 0; goto free_id; } @@ -200,7 +200,7 @@ static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev, if (ret < 0) goto free_id; - ret = gpio_lock_as_irq(desc->chip, gpio_chip_hwgpio(desc)); + ret = gpiochip_lock_as_irq(desc->chip, gpio_chip_hwgpio(desc)); if (ret < 0) { gpiod_warn(desc, "failed to flag the GPIO for IRQ\n"); goto free_id; diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index e8e98ca25ec7..50e18a4b3a9f 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -495,7 +495,7 @@ static int gpiochip_irq_reqres(struct irq_data *d) { struct gpio_chip *chip = irq_data_get_irq_chip_data(d); - if (gpio_lock_as_irq(chip, d->hwirq)) { + if (gpiochip_lock_as_irq(chip, d->hwirq)) { chip_err(chip, "unable to lock HW IRQ %lu for IRQ\n", d->hwirq); @@ -508,7 +508,7 @@ static void gpiochip_irq_relres(struct irq_data *d) { struct gpio_chip *chip = irq_data_get_irq_chip_data(d); - gpio_unlock_as_irq(chip, d->hwirq); + gpiochip_unlock_as_irq(chip, d->hwirq); } static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset) @@ -1332,14 +1332,14 @@ int gpiod_to_irq(const struct gpio_desc *desc) EXPORT_SYMBOL_GPL(gpiod_to_irq); /** - * gpio_lock_as_irq() - lock a GPIO to be used as IRQ + * gpiochip_lock_as_irq() - lock a GPIO to be used as IRQ * @chip: the chip the GPIO to lock belongs to * @offset: the offset of the GPIO to lock as IRQ * * This is used directly by GPIO drivers that want to lock down * a certain GPIO line to be used for IRQs. */ -int gpio_lock_as_irq(struct gpio_chip *chip, unsigned int offset) +int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset) { if (offset >= chip->ngpio) return -EINVAL; @@ -1354,24 +1354,24 @@ int gpio_lock_as_irq(struct gpio_chip *chip, unsigned int offset) set_bit(FLAG_USED_AS_IRQ, &chip->desc[offset].flags); return 0; } -EXPORT_SYMBOL_GPL(gpio_lock_as_irq); +EXPORT_SYMBOL_GPL(gpiochip_lock_as_irq); /** - * gpio_unlock_as_irq() - unlock a GPIO used as IRQ + * gpiochip_unlock_as_irq() - unlock a GPIO used as IRQ * @chip: the chip the GPIO to lock belongs to * @offset: the offset of the GPIO to lock as IRQ * * This is used directly by GPIO drivers that want to indicate * that a certain GPIO is no longer used exclusively for IRQ. */ -void gpio_unlock_as_irq(struct gpio_chip *chip, unsigned int offset) +void gpiochip_unlock_as_irq(struct gpio_chip *chip, unsigned int offset) { if (offset >= chip->ngpio) return; clear_bit(FLAG_USED_AS_IRQ, &chip->desc[offset].flags); } -EXPORT_SYMBOL_GPL(gpio_unlock_as_irq); +EXPORT_SYMBOL_GPL(gpiochip_unlock_as_irq); /** * gpiod_get_raw_value_cansleep() - return a gpio's raw value diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c index 354a81d40925..608671704522 100644 --- a/drivers/pinctrl/pinctrl-at91.c +++ b/drivers/pinctrl/pinctrl-at91.c @@ -1472,7 +1472,7 @@ static unsigned int gpio_irq_startup(struct irq_data *d) unsigned pin = d->hwirq; int ret; - ret = gpio_lock_as_irq(&at91_gpio->chip, pin); + ret = gpiochip_lock_as_irq(&at91_gpio->chip, pin); if (ret) { dev_err(at91_gpio->chip.dev, "unable to lock pind %lu IRQ\n", d->hwirq); @@ -1488,7 +1488,7 @@ static void gpio_irq_shutdown(struct irq_data *d) unsigned pin = d->hwirq; gpio_irq_mask(d); - gpio_unlock_as_irq(&at91_gpio->chip, pin); + gpiochip_unlock_as_irq(&at91_gpio->chip, pin); } #ifdef CONFIG_PM diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.c b/drivers/pinctrl/samsung/pinctrl-exynos.c index d7154ed0b0eb..fa54a2d1c966 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos.c @@ -180,7 +180,7 @@ static int exynos_irq_request_resources(struct irq_data *irqd) unsigned int con; int ret; - ret = gpio_lock_as_irq(&bank->gpio_chip, irqd->hwirq); + ret = gpiochip_lock_as_irq(&bank->gpio_chip, irqd->hwirq); if (ret) { dev_err(bank->gpio_chip.dev, "unable to lock pin %s-%lu IRQ\n", bank->name, irqd->hwirq); @@ -233,7 +233,7 @@ static void exynos_irq_release_resources(struct irq_data *irqd) spin_unlock_irqrestore(&bank->slock, flags); - gpio_unlock_as_irq(&bank->gpio_chip, irqd->hwirq); + gpiochip_unlock_as_irq(&bank->gpio_chip, irqd->hwirq); } /* diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index ef9d804e55de..3d0744337736 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -553,7 +553,7 @@ static int sunxi_pinctrl_irq_request_resources(struct irq_data *d) if (!func) return -EINVAL; - ret = gpio_lock_as_irq(pctl->chip, + ret = gpiochip_lock_as_irq(pctl->chip, pctl->irq_array[d->hwirq] - pctl->desc->pin_base); if (ret) { dev_err(pctl->dev, "unable to lock HW IRQ %lu for IRQ\n", @@ -571,8 +571,8 @@ static void sunxi_pinctrl_irq_release_resources(struct irq_data *d) { struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); - gpio_unlock_as_irq(pctl->chip, - pctl->irq_array[d->hwirq] - pctl->desc->pin_base); + gpiochip_unlock_as_irq(pctl->chip, + pctl->irq_array[d->hwirq] - pctl->desc->pin_base); } static int sunxi_pinctrl_irq_set_type(struct irq_data *d, unsigned int type) diff --git a/include/linux/gpio.h b/include/linux/gpio.h index 85aa5d0b9357..ab81339a8590 100644 --- a/include/linux/gpio.h +++ b/include/linux/gpio.h @@ -216,14 +216,15 @@ static inline int gpio_to_irq(unsigned gpio) return -EINVAL; } -static inline int gpio_lock_as_irq(struct gpio_chip *chip, unsigned int offset) +static inline int gpiochip_lock_as_irq(struct gpio_chip *chip, + unsigned int offset) { WARN_ON(1); return -EINVAL; } -static inline void gpio_unlock_as_irq(struct gpio_chip *chip, - unsigned int offset) +static inline void gpiochip_unlock_as_irq(struct gpio_chip *chip, + unsigned int offset) { WARN_ON(1); } diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 249db3057e4d..ff200a75501e 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -149,8 +149,8 @@ extern struct gpio_chip *gpiochip_find(void *data, int (*match)(struct gpio_chip *chip, void *data)); /* lock/unlock as IRQ */ -int gpio_lock_as_irq(struct gpio_chip *chip, unsigned int offset); -void gpio_unlock_as_irq(struct gpio_chip *chip, unsigned int offset); +int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset); +void gpiochip_unlock_as_irq(struct gpio_chip *chip, unsigned int offset); struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc); -- cgit v1.2.3-59-g8ed1b From 0eafa46823971b4c368f4cdf19f1d081c4ee52b7 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 28 Aug 2014 15:00:30 -0700 Subject: rcu: Remove CONFIG_RCU_CPU_STALL_VERBOSE The CONFIG_RCU_CPU_STALL_VERBOSE Kconfig parameter causes preemptible RCU's CPU stall warnings to dump out any preempted tasks that are blocking the current RCU grace period. This information is useful, and the default has been CONFIG_RCU_CPU_STALL_VERBOSE=y for some years. It is therefore time for this commit to remove this Kconfig parameter, so that future kernel builds will always act as if CONFIG_RCU_CPU_STALL_VERBOSE=y. Signed-off-by: Paul E. McKenney --- Documentation/RCU/stallwarn.txt | 6 ------ kernel/rcu/tree_plugin.h | 13 ------------- lib/Kconfig.debug | 12 ------------ tools/testing/selftests/rcutorture/configs/rcu/TREE01 | 1 - tools/testing/selftests/rcutorture/configs/rcu/TREE02 | 1 - tools/testing/selftests/rcutorture/configs/rcu/TREE02-T | 1 - tools/testing/selftests/rcutorture/configs/rcu/TREE03 | 1 - tools/testing/selftests/rcutorture/configs/rcu/TREE04 | 1 - tools/testing/selftests/rcutorture/configs/rcu/TREE05 | 1 - tools/testing/selftests/rcutorture/configs/rcu/TREE06 | 1 - tools/testing/selftests/rcutorture/configs/rcu/TREE07 | 1 - tools/testing/selftests/rcutorture/configs/rcu/TREE08 | 1 - tools/testing/selftests/rcutorture/configs/rcu/TREE08-T | 1 - tools/testing/selftests/rcutorture/configs/rcu/TREE09 | 1 - tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt | 3 +-- 15 files changed, 1 insertion(+), 44 deletions(-) (limited to 'Documentation') diff --git a/Documentation/RCU/stallwarn.txt b/Documentation/RCU/stallwarn.txt index ef5a2fd4ff70..1560efbcc759 100644 --- a/Documentation/RCU/stallwarn.txt +++ b/Documentation/RCU/stallwarn.txt @@ -26,12 +26,6 @@ CONFIG_RCU_CPU_STALL_TIMEOUT Stall-warning messages may be enabled and disabled completely via /sys/module/rcupdate/parameters/rcu_cpu_stall_suppress. -CONFIG_RCU_CPU_STALL_VERBOSE - - This kernel configuration parameter causes the stall warning to - also dump the stacks of any tasks that are blocking the current - RCU-preempt grace period. - CONFIG_RCU_CPU_STALL_INFO This kernel configuration parameter causes the stall warning to diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h index c1d7f27bd38f..d062f4d6f037 100644 --- a/kernel/rcu/tree_plugin.h +++ b/kernel/rcu/tree_plugin.h @@ -72,9 +72,6 @@ static void __init rcu_bootup_announce_oddness(void) #ifdef CONFIG_RCU_TORTURE_TEST_RUNNABLE pr_info("\tRCU torture testing starts during boot.\n"); #endif -#if defined(CONFIG_TREE_PREEMPT_RCU) && !defined(CONFIG_RCU_CPU_STALL_VERBOSE) - pr_info("\tDump stacks of tasks blocking RCU-preempt GP.\n"); -#endif #if defined(CONFIG_RCU_CPU_STALL_INFO) pr_info("\tAdditional per-CPU info printed with stalls.\n"); #endif @@ -415,8 +412,6 @@ void rcu_read_unlock_special(struct task_struct *t) } } -#ifdef CONFIG_RCU_CPU_STALL_VERBOSE - /* * Dump detailed information for all tasks blocking the current RCU * grace period on the specified rcu_node structure. @@ -451,14 +446,6 @@ static void rcu_print_detail_task_stall(struct rcu_state *rsp) rcu_print_detail_task_stall_rnp(rnp); } -#else /* #ifdef CONFIG_RCU_CPU_STALL_VERBOSE */ - -static void rcu_print_detail_task_stall(struct rcu_state *rsp) -{ -} - -#endif /* #else #ifdef CONFIG_RCU_CPU_STALL_VERBOSE */ - #ifdef CONFIG_RCU_CPU_STALL_INFO static void rcu_print_task_stall_begin(struct rcu_node *rnp) diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 4e35a5d767ed..04e54cd3e948 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -1238,18 +1238,6 @@ config RCU_CPU_STALL_TIMEOUT RCU grace period persists, additional CPU stall warnings are printed at more widely spaced intervals. -config RCU_CPU_STALL_VERBOSE - bool "Print additional per-task information for RCU_CPU_STALL_DETECTOR" - depends on TREE_PREEMPT_RCU - default y - help - This option causes RCU to printk detailed per-task information - for any tasks that are stalling the current RCU grace period. - - Say N if you are unsure. - - Say Y if you want to enable such checks. - config RCU_CPU_STALL_INFO bool "Print additional diagnostics on RCU CPU stall" depends on (TREE_RCU || TREE_PREEMPT_RCU) && DEBUG_KERNEL diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE01 b/tools/testing/selftests/rcutorture/configs/rcu/TREE01 index 38e3895759dd..a04420e7ac9b 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE01 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE01 @@ -14,6 +14,5 @@ CONFIG_RCU_NOCB_CPU=y CONFIG_RCU_NOCB_CPU_ZERO=y CONFIG_DEBUG_LOCK_ALLOC=n CONFIG_RCU_CPU_STALL_INFO=n -CONFIG_RCU_CPU_STALL_VERBOSE=n CONFIG_RCU_BOOST=n CONFIG_DEBUG_OBJECTS_RCU_HEAD=n diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE02 b/tools/testing/selftests/rcutorture/configs/rcu/TREE02 index ea119ba2f7d4..a4f8bfbdd71d 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE02 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE02 @@ -19,6 +19,5 @@ CONFIG_RCU_NOCB_CPU=n CONFIG_DEBUG_LOCK_ALLOC=y CONFIG_PROVE_LOCKING=n CONFIG_RCU_CPU_STALL_INFO=n -CONFIG_RCU_CPU_STALL_VERBOSE=y CONFIG_RCU_BOOST=n CONFIG_DEBUG_OBJECTS_RCU_HEAD=n diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE02-T b/tools/testing/selftests/rcutorture/configs/rcu/TREE02-T index 19cf9485f48a..fe19aaf8f20c 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE02-T +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE02-T @@ -19,6 +19,5 @@ CONFIG_RCU_NOCB_CPU=n CONFIG_DEBUG_LOCK_ALLOC=y CONFIG_PROVE_LOCKING=n CONFIG_RCU_CPU_STALL_INFO=n -CONFIG_RCU_CPU_STALL_VERBOSE=y CONFIG_RCU_BOOST=n CONFIG_DEBUG_OBJECTS_RCU_HEAD=n diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE03 b/tools/testing/selftests/rcutorture/configs/rcu/TREE03 index f4567fb3e332..a2a9a9bcd1cd 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE03 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE03 @@ -15,7 +15,6 @@ CONFIG_RCU_FANOUT_EXACT=n CONFIG_RCU_NOCB_CPU=n CONFIG_DEBUG_LOCK_ALLOC=n CONFIG_RCU_CPU_STALL_INFO=n -CONFIG_RCU_CPU_STALL_VERBOSE=n CONFIG_RCU_BOOST=y CONFIG_RCU_BOOST_PRIO=2 CONFIG_DEBUG_OBJECTS_RCU_HEAD=n diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE04 b/tools/testing/selftests/rcutorture/configs/rcu/TREE04 index 0a262fbb0c12..0f84db35b36d 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE04 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE04 @@ -19,5 +19,4 @@ CONFIG_RCU_FANOUT_EXACT=n CONFIG_RCU_NOCB_CPU=n CONFIG_DEBUG_LOCK_ALLOC=n CONFIG_RCU_CPU_STALL_INFO=y -CONFIG_RCU_CPU_STALL_VERBOSE=y CONFIG_DEBUG_OBJECTS_RCU_HEAD=n diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE05 b/tools/testing/selftests/rcutorture/configs/rcu/TREE05 index 3a06b97e9a73..212e3bfd2b2a 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE05 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE05 @@ -19,5 +19,4 @@ CONFIG_DEBUG_LOCK_ALLOC=y CONFIG_PROVE_LOCKING=y CONFIG_PROVE_RCU=y CONFIG_RCU_CPU_STALL_INFO=n -CONFIG_RCU_CPU_STALL_VERBOSE=n CONFIG_DEBUG_OBJECTS_RCU_HEAD=n diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE06 b/tools/testing/selftests/rcutorture/configs/rcu/TREE06 index 8f084cca91bf..7eee63b44218 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE06 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE06 @@ -20,5 +20,4 @@ CONFIG_DEBUG_LOCK_ALLOC=y CONFIG_PROVE_LOCKING=y CONFIG_PROVE_RCU=y CONFIG_RCU_CPU_STALL_INFO=n -CONFIG_RCU_CPU_STALL_VERBOSE=n CONFIG_DEBUG_OBJECTS_RCU_HEAD=y diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE07 b/tools/testing/selftests/rcutorture/configs/rcu/TREE07 index 8f1017666aa7..92a97fa97dec 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE07 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE07 @@ -19,5 +19,4 @@ CONFIG_RCU_FANOUT_EXACT=n CONFIG_RCU_NOCB_CPU=n CONFIG_DEBUG_LOCK_ALLOC=n CONFIG_RCU_CPU_STALL_INFO=y -CONFIG_RCU_CPU_STALL_VERBOSE=n CONFIG_DEBUG_OBJECTS_RCU_HEAD=n diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE08 b/tools/testing/selftests/rcutorture/configs/rcu/TREE08 index 69a2e255bf98..316aa6cedce5 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE08 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE08 @@ -19,6 +19,5 @@ CONFIG_RCU_NOCB_CPU=y CONFIG_RCU_NOCB_CPU_ALL=y CONFIG_DEBUG_LOCK_ALLOC=n CONFIG_RCU_CPU_STALL_INFO=n -CONFIG_RCU_CPU_STALL_VERBOSE=n CONFIG_RCU_BOOST=n CONFIG_DEBUG_OBJECTS_RCU_HEAD=n diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE08-T b/tools/testing/selftests/rcutorture/configs/rcu/TREE08-T index a0f32fb8f17e..55daf08038e8 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE08-T +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE08-T @@ -19,6 +19,5 @@ CONFIG_RCU_NOCB_CPU=y CONFIG_RCU_NOCB_CPU_ALL=y CONFIG_DEBUG_LOCK_ALLOC=n CONFIG_RCU_CPU_STALL_INFO=n -CONFIG_RCU_CPU_STALL_VERBOSE=n CONFIG_RCU_BOOST=n CONFIG_DEBUG_OBJECTS_RCU_HEAD=n diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE09 b/tools/testing/selftests/rcutorture/configs/rcu/TREE09 index b7a62a540ad1..13081a87586c 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE09 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE09 @@ -14,6 +14,5 @@ CONFIG_HIBERNATION=n CONFIG_RCU_NOCB_CPU=n CONFIG_DEBUG_LOCK_ALLOC=n CONFIG_RCU_CPU_STALL_INFO=n -CONFIG_RCU_CPU_STALL_VERBOSE=n CONFIG_RCU_BOOST=n CONFIG_DEBUG_OBJECTS_RCU_HEAD=n diff --git a/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt b/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt index 3e588db86a17..0dcde4c70945 100644 --- a/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt +++ b/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt @@ -16,8 +16,7 @@ CONFIG_PROVE_LOCKING -- Do all but two, covering CONFIG_PROVE_RCU and not. CONFIG_PROVE_RCU -- Do all but one under CONFIG_PROVE_LOCKING. CONFIG_RCU_BOOST -- one of TREE_PREEMPT_RCU. CONFIG_RCU_BOOST_PRIO -- set to 2 for _BOOST testing. -CONFIG_RCU_CPU_STALL_INFO -- do one with and without _VERBOSE. -CONFIG_RCU_CPU_STALL_VERBOSE -- do one with and without _INFO. +CONFIG_RCU_CPU_STALL_INFO -- Do one. CONFIG_RCU_FANOUT -- Cover hierarchy as currently, but overlap with others. CONFIG_RCU_FANOUT_EXACT -- Do one. CONFIG_RCU_FANOUT_LEAF -- Do one non-default. -- cgit v1.2.3-59-g8ed1b From 00dad6cfd25b75cc9cc24b8abfc263177e581ae2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 29 Oct 2014 08:23:31 +0100 Subject: ALSA: doc: Include uapi/sound/compress_*.h, too Signed-off-by: Takashi Iwai --- Documentation/DocBook/alsa-driver-api.tmpl | 2 ++ 1 file changed, 2 insertions(+) (limited to 'Documentation') diff --git a/Documentation/DocBook/alsa-driver-api.tmpl b/Documentation/DocBook/alsa-driver-api.tmpl index 13f8b241f042..7bec270e2494 100644 --- a/Documentation/DocBook/alsa-driver-api.tmpl +++ b/Documentation/DocBook/alsa-driver-api.tmpl @@ -99,6 +99,8 @@ Compress Offload Compress Offload API !Esound/core/compress_offload.c +!Iinclude/uapi/sound/compress_offload.h +!Iinclude/uapi/sound/compress_params.h !Iinclude/sound/compress_driver.h -- cgit v1.2.3-59-g8ed1b From 43059f6ba21177f25ab1b10f95149cff1895806a Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 22 Oct 2014 12:58:44 +0300 Subject: pinctrl: Device tree bindings for Qualcomm PMIC GPIO block This introduced the device tree bindings for the GPIO block found in PMIC's from Qualcomm. Signed-off-by: Bjorn Andersson Signed-off-by: Ivan T. Ivanov Signed-off-by: Linus Walleij --- .../devicetree/bindings/pinctrl/qcom,pmic-gpio.txt | 215 +++++++++++++++++++++ include/dt-bindings/pinctrl/qcom,pmic-gpio.h | 142 ++++++++++++++ 2 files changed, 357 insertions(+) create mode 100644 Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.txt create mode 100644 include/dt-bindings/pinctrl/qcom,pmic-gpio.h (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.txt b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.txt new file mode 100644 index 000000000000..7ed08048516a --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.txt @@ -0,0 +1,215 @@ +Qualcomm PMIC GPIO block + +This binding describes the GPIO block(s) found in the 8xxx series of +PMIC's from Qualcomm. + +- compatible: + Usage: required + Value type: + Definition: must be one of: + "qcom,pm8018-gpio" + "qcom,pm8038-gpio" + "qcom,pm8058-gpio" + "qcom,pm8917-gpio" + "qcom,pm8921-gpio" + "qcom,pm8941-gpio" + "qcom,pma8084-gpio" + +- reg: + Usage: required + Value type: + Definition: Register base of the GPIO block and length. + +- interrupts: + Usage: required + Value type: + Definition: Must contain an array of encoded interrupt specifiers for + each available GPIO + +- gpio-controller: + Usage: required + Value type: + Definition: Mark the device node as a GPIO controller + +- #gpio-cells: + Usage: required + Value type: + Definition: Must be 2; + the first cell will be used to define gpio number and the + second denotes the flags for this gpio + +Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for +a general description of GPIO and interrupt bindings. + +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". + +The pin configuration nodes act as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin or a list of pins. This configuration can include the +mux function to select on those pin(s), and various pin configuration +parameters, as listed below. + + +SUBNODES: + +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. + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pin configuration subnode: + +- pins: + Usage: required + Value type: + Definition: List of gpio pins affected by the properties specified in + this subnode. Valid pins are: + gpio1-gpio6 for pm8018 + gpio1-gpio12 for pm8038 + gpio1-gpio40 for pm8058 + gpio1-gpio38 for pm8917 + gpio1-gpio44 for pm8921 + gpio1-gpio36 for pm8941 + gpio1-gpio22 for pma8084 + +- function: + Usage: required + Value type: + Definition: Specify the alternative function to be configured for the + specified pins. Valid values are: + "normal", + "paired", + "func1", + "func2", + "dtest1", + "dtest2", + "dtest3", + "dtest4" + +- bias-disable: + Usage: optional + Value type: + Definition: The specified pins should be configured as no pull. + +- bias-pull-down: + Usage: optional + Value type: + Definition: The specified pins should be configured as pull down. + +- bias-pull-up: + Usage: optional + Value type: + Definition: The specified pins should be configured as pull up. + +- qcom,pull-up-strength: + Usage: optional + Value type: + Definition: Specifies the strength to use for pull up, if selected. + Valid values are; as defined in + : + 1: 30uA (PMIC_GPIO_PULL_UP_30) + 2: 1.5uA (PMIC_GPIO_PULL_UP_1P5) + 3: 31.5uA (PMIC_GPIO_PULL_UP_31P5) + 4: 1.5uA + 30uA boost (PMIC_GPIO_PULL_UP_1P5_30) + If this property is ommited 30uA strength will be used if + pull up is selected + +- bias-high-impedance: + Usage: optional + Value type: + Definition: The specified pins will put in high-Z mode and disabled. + +- input-enable: + Usage: optional + Value type: + Definition: The specified pins are put in input mode. + +- output-high: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + high. + +- output-low: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + low. + +- power-source: + Usage: optional + Value type: + Definition: Selects the power source for the specified pins. Valid + power sources are defined per chip in + + +- qcom,drive-strength: + Usage: optional + Value type: + Definition: Selects the drive strength for the specified pins. Value + drive strengths are: + 0: no (PMIC_GPIO_STRENGTH_NO) + 1: high (PMIC_GPIO_STRENGTH_HIGH) 0.9mA @ 1.8V - 1.9mA @ 2.6V + 2: medium (PMIC_GPIO_STRENGTH_MED) 0.6mA @ 1.8V - 1.25mA @ 2.6V + 3: low (PMIC_GPIO_STRENGTH_LOW) 0.15mA @ 1.8V - 0.3mA @ 2.6V + as defined in + +- drive-push-pull: + Usage: optional + Value type: + Definition: The specified pins are configured in push-pull mode. + +- drive-open-drain: + Usage: optional + Value type: + Definition: The specified pins are configured in open-drain mode. + +- drive-open-source: + Usage: optional + Value type: + Definition: The specified pins are configured in open-source mode. + +Example: + + pm8921_gpio: gpio@150 { + compatible = "qcom,pm8921-gpio"; + reg = <0x150 0x160>; + interrupts = <192 1>, <193 1>, <194 1>, + <195 1>, <196 1>, <197 1>, + <198 1>, <199 1>, <200 1>, + <201 1>, <202 1>, <203 1>, + <204 1>, <205 1>, <206 1>, + <207 1>, <208 1>, <209 1>, + <210 1>, <211 1>, <212 1>, + <213 1>, <214 1>, <215 1>, + <216 1>, <217 1>, <218 1>, + <219 1>, <220 1>, <221 1>, + <222 1>, <223 1>, <224 1>, + <225 1>, <226 1>, <227 1>, + <228 1>, <229 1>, <230 1>, + <231 1>, <232 1>, <233 1>, + <234 1>, <235 1>; + + gpio-controller; + #gpio-cells = <2>; + + pm8921_gpio_keys: gpio-keys { + volume-keys { + pins = "gpio20", "gpio21"; + function = "normal"; + + input-enable; + bias-pull-up; + drive-push-pull; + qcom,drive-strength = ; + power-source = ; + }; + }; + }; diff --git a/include/dt-bindings/pinctrl/qcom,pmic-gpio.h b/include/dt-bindings/pinctrl/qcom,pmic-gpio.h new file mode 100644 index 000000000000..fa74d7cc960c --- /dev/null +++ b/include/dt-bindings/pinctrl/qcom,pmic-gpio.h @@ -0,0 +1,142 @@ +/* + * This header provides constants for the Qualcomm PMIC GPIO binding. + */ + +#ifndef _DT_BINDINGS_PINCTRL_QCOM_PMIC_GPIO_H +#define _DT_BINDINGS_PINCTRL_QCOM_PMIC_GPIO_H + +#define PMIC_GPIO_PULL_UP_30 0 +#define PMIC_GPIO_PULL_UP_1P5 1 +#define PMIC_GPIO_PULL_UP_31P5 2 +#define PMIC_GPIO_PULL_UP_1P5_30 3 + +#define PMIC_GPIO_STRENGTH_NO 0 +#define PMIC_GPIO_STRENGTH_HIGH 1 +#define PMIC_GPIO_STRENGTH_MED 2 +#define PMIC_GPIO_STRENGTH_LOW 3 + +/* + * Note: PM8018 GPIO3 and GPIO4 are supporting + * only S3 and L2 options (1.8V) + */ +#define PM8018_GPIO_L6 0 +#define PM8018_GPIO_L5 1 +#define PM8018_GPIO_S3 2 +#define PM8018_GPIO_L14 3 +#define PM8018_GPIO_L2 4 +#define PM8018_GPIO_L4 5 +#define PM8018_GPIO_VDD 6 + +/* + * Note: PM8038 GPIO7 and GPIO8 are supporting + * only L11 and L4 options (1.8V) + */ +#define PM8038_GPIO_VPH 0 +#define PM8038_GPIO_BB 1 +#define PM8038_GPIO_L11 2 +#define PM8038_GPIO_L15 3 +#define PM8038_GPIO_L4 4 +#define PM8038_GPIO_L3 5 +#define PM8038_GPIO_L17 6 + +#define PM8058_GPIO_VPH 0 +#define PM8058_GPIO_BB 1 +#define PM8058_GPIO_S3 2 +#define PM8058_GPIO_L3 3 +#define PM8058_GPIO_L7 4 +#define PM8058_GPIO_L6 5 +#define PM8058_GPIO_L5 6 +#define PM8058_GPIO_L2 7 + +#define PM8917_GPIO_VPH 0 +#define PM8917_GPIO_S4 2 +#define PM8917_GPIO_L15 3 +#define PM8917_GPIO_L4 4 +#define PM8917_GPIO_L3 5 +#define PM8917_GPIO_L17 6 + +#define PM8921_GPIO_VPH 0 +#define PM8921_GPIO_BB 1 +#define PM8921_GPIO_S4 2 +#define PM8921_GPIO_L15 3 +#define PM8921_GPIO_L4 4 +#define PM8921_GPIO_L3 5 +#define PM8921_GPIO_L17 6 + +/* + * Note: PM8941 gpios from 15 to 18 are supporting + * only S3 and L6 options (1.8V) + */ +#define PM8941_GPIO_VPH 0 +#define PM8941_GPIO_L1 1 +#define PM8941_GPIO_S3 2 +#define PM8941_GPIO_L6 3 + +/* + * Note: PMA8084 gpios from 15 to 18 are supporting + * only S4 and L6 options (1.8V) + */ +#define PMA8084_GPIO_VPH 0 +#define PMA8084_GPIO_L1 1 +#define PMA8084_GPIO_S4 2 +#define PMA8084_GPIO_L6 3 + +/* To be used with "function" */ +#define PMIC_GPIO_FUNC_NORMAL "normal" +#define PMIC_GPIO_FUNC_PAIRED "paired" +#define PMIC_GPIO_FUNC_FUNC1 "func1" +#define PMIC_GPIO_FUNC_FUNC2 "func2" +#define PMIC_GPIO_FUNC_DTEST1 "dtest1" +#define PMIC_GPIO_FUNC_DTEST2 "dtest2" +#define PMIC_GPIO_FUNC_DTEST3 "dtest3" +#define PMIC_GPIO_FUNC_DTEST4 "dtest4" + +#define PM8038_GPIO1_2_LPG_DRV PMIC_GPIO_FUNC_FUNC1 +#define PM8038_GPIO3_5V_BOOST_EN PMIC_GPIO_FUNC_FUNC1 +#define PM8038_GPIO4_SSBI_ALT_CLK PMIC_GPIO_FUNC_FUNC1 +#define PM8038_GPIO5_6_EXT_REG_EN PMIC_GPIO_FUNC_FUNC1 +#define PM8038_GPIO10_11_EXT_REG_EN PMIC_GPIO_FUNC_FUNC1 +#define PM8038_GPIO6_7_CLK PMIC_GPIO_FUNC_FUNC1 +#define PM8038_GPIO9_BAT_ALRM_OUT PMIC_GPIO_FUNC_FUNC1 +#define PM8038_GPIO6_12_KYPD_DRV PMIC_GPIO_FUNC_FUNC2 + +#define PM8058_GPIO7_8_MP3_CLK PMIC_GPIO_FUNC_FUNC1 +#define PM8058_GPIO7_8_BCLK_19P2MHZ PMIC_GPIO_FUNC_FUNC2 +#define PM8058_GPIO9_26_KYPD_DRV PMIC_GPIO_FUNC_FUNC1 +#define PM8058_GPIO21_23_UART_TX PMIC_GPIO_FUNC_FUNC2 +#define PM8058_GPIO24_26_LPG_DRV PMIC_GPIO_FUNC_FUNC2 +#define PM8058_GPIO33_BCLK_19P2MHZ PMIC_GPIO_FUNC_FUNC1 +#define PM8058_GPIO34_35_MP3_CLK PMIC_GPIO_FUNC_FUNC1 +#define PM8058_GPIO36_BCLK_19P2MHZ PMIC_GPIO_FUNC_FUNC1 +#define PM8058_GPIO37_UPL_OUT PMIC_GPIO_FUNC_FUNC1 +#define PM8058_GPIO37_UART_M_RX PMIC_GPIO_FUNC_FUNC2 +#define PM8058_GPIO38_XO_SLEEP_CLK PMIC_GPIO_FUNC_FUNC1 +#define PM8058_GPIO38_39_CLK_32KHZ PMIC_GPIO_FUNC_FUNC2 +#define PM8058_GPIO39_MP3_CLK PMIC_GPIO_FUNC_FUNC1 +#define PM8058_GPIO40_EXT_BB_EN PMIC_GPIO_FUNC_FUNC1 + +#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 +#define PM8917_GPIO25_26_EXT_REG_EN PMIC_GPIO_FUNC_FUNC1 +#define PM8917_GPIO37_38_XO_SLEEP_CLK PMIC_GPIO_FUNC_FUNC1 +#define PM8917_GPIO37_38_MP3_CLK PMIC_GPIO_FUNC_FUNC2 + +#define PM8941_GPIO9_14_KYPD_DRV PMIC_GPIO_FUNC_FUNC1 +#define PM8941_GPIO15_18_DIV_CLK PMIC_GPIO_FUNC_FUNC1 +#define PM8941_GPIO15_18_SLEEP_CLK PMIC_GPIO_FUNC_FUNC2 +#define PM8941_GPIO23_26_KYPD_DRV PMIC_GPIO_FUNC_FUNC1 +#define PM8941_GPIO23_26_LPG_DRV_HI PMIC_GPIO_FUNC_FUNC2 +#define PM8941_GPIO31_BAT_ALRM_OUT PMIC_GPIO_FUNC_FUNC1 +#define PM8941_GPIO33_36_LPG_DRV_3D PMIC_GPIO_FUNC_FUNC1 +#define PM8941_GPIO33_36_LPG_DRV_HI PMIC_GPIO_FUNC_FUNC2 + +#define PMA8084_GPIO4_5_LPG_DRV PMIC_GPIO_FUNC_FUNC1 +#define PMA8084_GPIO7_10_LPG_DRV PMIC_GPIO_FUNC_FUNC1 +#define PMA8084_GPIO5_14_KEYP_DRV PMIC_GPIO_FUNC_FUNC2 +#define PMA8084_GPIO19_21_KEYP_DRV PMIC_GPIO_FUNC_FUNC2 +#define PMA8084_GPIO15_18_DIV_CLK PMIC_GPIO_FUNC_FUNC1 +#define PMA8084_GPIO15_18_SLEEP_CLK PMIC_GPIO_FUNC_FUNC2 +#define PMA8084_GPIO22_BAT_ALRM_OUT PMIC_GPIO_FUNC_FUNC1 + +#endif -- cgit v1.2.3-59-g8ed1b From 89a7117d56d405b49b7d1f8ed30e01188e9d5a05 Mon Sep 17 00:00:00 2001 From: "Ivan T. Ivanov" Date: Wed, 22 Oct 2014 12:58:45 +0300 Subject: pinctrl: Device tree bindings for Qualcomm PMIC MPP block DeviceTree binding documentation for Qualcomm SPMI PMIC MPP pinctrl drivers. Signed-off-by: Ivan T. Ivanov Acked-by: Bjorn Andersson Signed-off-by: Linus Walleij --- .../devicetree/bindings/pinctrl/qcom,pmic-mpp.txt | 162 +++++++++++++++++++++ include/dt-bindings/pinctrl/qcom,pmic-mpp.h | 44 ++++++ 2 files changed, 206 insertions(+) create mode 100644 Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt create mode 100644 include/dt-bindings/pinctrl/qcom,pmic-mpp.h (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt new file mode 100644 index 000000000000..854774b194ed --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt @@ -0,0 +1,162 @@ +Qualcomm PMIC Multi-Purpose Pin (MPP) block + +This binding describes the MPP block(s) found in the 8xxx series +of PMIC's from Qualcomm. + +- compatible: + Usage: required + Value type: + Definition: Should contain one of: + "qcom,pm8841-mpp", + "qcom,pm8941-mpp", + "qcom,pma8084-mpp", + +- reg: + Usage: required + Value type: + Definition: Register base of the MPP block and length. + +- interrupts: + Usage: required + Value type: + Definition: Must contain an array of encoded interrupt specifiers for + each available MPP + +- gpio-controller: + Usage: required + Value type: + Definition: Mark the device node as a GPIO controller + +- #gpio-cells: + Usage: required + Value type: + Definition: Must be 2; + the first cell will be used to define MPP number and the + second denotes the flags for this MPP + +Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for +a general description of GPIO and interrupt bindings. + +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". + +The pin configuration nodes act as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin or a list of pins. This configuration can include the +mux function to select on those pin(s), and various pin configuration +parameters, as listed below. + +SUBNODES: + +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. + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pin configuration subnode: + +- pins: + Usage: required + Value type: + Definition: List of MPP pins affected by the properties specified in + this subnode. Valid pins are: + mpp1-mpp4 for pm8841 + mpp1-mpp8 for pm8941 + mpp1-mpp4 for pma8084 + +- function: + Usage: required + Value type: + Definition: Specify the alternative function to be configured for the + specified pins. Valid values are: + "normal", + "paired", + "dtest1", + "dtest2", + "dtest3", + "dtest4" + +- bias-disable: + Usage: optional + Value type: + Definition: The specified pins should be configured as no pull. + +- bias-pull-up: + Usage: optional + Value type: + Definition: The specified pins should be configured as pull up. + Valid values are 600, 10000 and 30000 in bidirectional mode + only, i.e. when operating in qcom,analog-mode and input and + outputs are enabled. The hardware ignores the configuration + when operating in other modes. + +- bias-high-impedance: + Usage: optional + Value type: + Definition: The specified pins will put in high-Z mode and disabled. + +- input-enable: + Usage: optional + Value type: + Definition: The specified pins are put in input mode, i.e. their input + buffer is enabled + +- output-high: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + high. + +- output-low: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + low. + +- power-source: + Usage: optional + Value type: + Definition: Selects the power source for the specified pins. Valid power + sources are defined in + +- qcom,analog-mode: + Usage: optional + Value type: + Definition: Selects Analog mode of operation: combined with input-enable + and/or output-high, output-low MPP could operate as + Bidirectional Logic, Analog Input, Analog Output. + +- qcom,amux-route: + Usage: optional + Value type: + Definition: Selects the source for analog input. Valid values are + defined in + PMIC_MPP_AMUX_ROUTE_CH5, PMIC_MPP_AMUX_ROUTE_CH6... + +Example: + + mpps@a000 { + compatible = "qcom,pm8841-mpp"; + reg = <0xa000>; + gpio-controller; + #gpio-cells = <2>; + interrupts = <4 0xa0 0 0>, <4 0xa1 0 0>, <4 0xa2 0 0>, <4 0xa3 0 0>; + + pinctrl-names = "default"; + pinctrl-0 = <&pm8841_default>; + + pm8841_default: default { + gpio { + pins = "mpp1", "mpp2", "mpp3", "mpp4"; + function = "normal"; + input-enable; + power-source = ; + }; + }; + }; diff --git a/include/dt-bindings/pinctrl/qcom,pmic-mpp.h b/include/dt-bindings/pinctrl/qcom,pmic-mpp.h new file mode 100644 index 000000000000..d2c7dabe3223 --- /dev/null +++ b/include/dt-bindings/pinctrl/qcom,pmic-mpp.h @@ -0,0 +1,44 @@ +/* + * This header provides constants for the Qualcomm PMIC's + * Multi-Purpose Pin binding. + */ + +#ifndef _DT_BINDINGS_PINCTRL_QCOM_PMIC_MPP_H +#define _DT_BINDINGS_PINCTRL_QCOM_PMIC_MPP_H + +/* power-source */ +#define PM8841_MPP_VPH 0 +#define PM8841_MPP_S3 2 + +#define PM8941_MPP_VPH 0 +#define PM8941_MPP_L1 1 +#define PM8941_MPP_S3 2 +#define PM8941_MPP_L6 3 + +#define PMA8084_MPP_VPH 0 +#define PMA8084_MPP_L1 1 +#define PMA8084_MPP_S4 2 +#define PMA8084_MPP_L6 3 + +/* + * Analog Input - Set the source for analog input. + * To be used with "qcom,amux-route" property + */ +#define PMIC_MPP_AMUX_ROUTE_CH5 0 +#define PMIC_MPP_AMUX_ROUTE_CH6 1 +#define PMIC_MPP_AMUX_ROUTE_CH7 2 +#define PMIC_MPP_AMUX_ROUTE_CH8 3 +#define PMIC_MPP_AMUX_ROUTE_ABUS1 4 +#define PMIC_MPP_AMUX_ROUTE_ABUS2 5 +#define PMIC_MPP_AMUX_ROUTE_ABUS3 6 +#define PMIC_MPP_AMUX_ROUTE_ABUS4 7 + +/* To be used with "function" */ +#define PMIC_MPP_FUNC_NORMAL "normal" +#define PMIC_MPP_FUNC_PAIRED "paired" +#define PMIC_MPP_FUNC_DTEST1 "dtest1" +#define PMIC_MPP_FUNC_DTEST2 "dtest2" +#define PMIC_MPP_FUNC_DTEST3 "dtest3" +#define PMIC_MPP_FUNC_DTEST4 "dtest4" + +#endif -- cgit v1.2.3-59-g8ed1b From 720a8d369b7f841741baf723cecd32cdef19d040 Mon Sep 17 00:00:00 2001 From: Frans Klaver Date: Wed, 1 Oct 2014 15:30:31 +0200 Subject: gadget_configfs.txt: fix spelling of 'function' Signed-off-by: Frans Klaver Signed-off-by: Jiri Kosina --- Documentation/usb/gadget_configfs.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/usb/gadget_configfs.txt b/Documentation/usb/gadget_configfs.txt index 4cf53e406613..635e57493709 100644 --- a/Documentation/usb/gadget_configfs.txt +++ b/Documentation/usb/gadget_configfs.txt @@ -376,7 +376,7 @@ functions and binds them. This way the whole gadget is bound. configured, so config_groups for particular functions are defined in the functions implementation files drivers/usb/gadget/f_*.c. -5. Funciton's code is written in such a way that it uses +5. Function's code is written in such a way that it uses usb_get_function_instance(), which, in turn, calls request_module. So, provided that modprobe works, modules for particular functions -- cgit v1.2.3-59-g8ed1b From 542cb4593104ae306970eb181ea42a01f1a79ed2 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Fri, 3 Oct 2014 11:42:17 +1000 Subject: scsi: Fix "choir" and "beeing" malaprops Signed-off-by: Finn Thain Reviewed-by: Christoph Hellwig Signed-off-by: Jiri Kosina --- Documentation/scsi/scsi_eh.txt | 4 ++-- drivers/scsi/aha152x.c | 2 +- drivers/scsi/mac_scsi.c | 2 +- include/scsi/scsi_host.h | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/scsi/scsi_eh.txt b/Documentation/scsi/scsi_eh.txt index a0c85110a07e..8638f61c8c9d 100644 --- a/Documentation/scsi/scsi_eh.txt +++ b/Documentation/scsi/scsi_eh.txt @@ -172,7 +172,7 @@ ways. - eh_strategy_handler() callback This is one big callback which should perform whole error - handling. As such, it should do all choirs SCSI midlayer + handling. As such, it should do all chores the SCSI midlayer performs during recovery. This will be discussed in [2-2]. Once recovery is complete, SCSI EH resumes normal operation by @@ -428,7 +428,7 @@ scmd->allowed. scsi_unjam_host() and it is responsible for whole recovery process. On completion, the handler should have made lower layers forget about all failed scmds and either ready for new commands or offline. Also, -it should perform SCSI EH maintenance choirs to maintain integrity of +it should perform SCSI EH maintenance chores to maintain integrity of SCSI midlayer. IOW, of the steps described in [2-1-2], all steps except for #1 must be implemented by eh_strategy_handler(). diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c index e77b72f78006..ee2407b83afb 100644 --- a/drivers/scsi/aha152x.c +++ b/drivers/scsi/aha152x.c @@ -345,7 +345,7 @@ CMD_INC_RESID(struct scsi_cmnd *cmd, int inc) enum { not_issued = 0x0001, /* command not yet issued */ - selecting = 0x0002, /* target is beeing selected */ + selecting = 0x0002, /* target is being selected */ identified = 0x0004, /* IDENTIFY was sent */ disconnected = 0x0008, /* target disconnected */ completed = 0x0010, /* target sent COMMAND COMPLETE */ diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c index 6a039eb1cbce..dccce08d0ad4 100644 --- a/drivers/scsi/mac_scsi.c +++ b/drivers/scsi/mac_scsi.c @@ -360,7 +360,7 @@ const char * macscsi_info (struct Scsi_Host *spnt) { XXX: Since bus errors in the PDMA routines never happen on my computer, the bus error code is untested. If the code works as intended, a bus error results in Pseudo-DMA - beeing disabled, meaning that the driver switches to slow handshake. + being disabled, meaning that the driver switches to slow handshake. If bus errors are NOT extremely rare, this has to be changed. */ diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index ba2034779961..b286b5787c85 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -555,7 +555,7 @@ struct Scsi_Host { * __devices is protected by the host_lock, but you should * usually use scsi_device_lookup / shost_for_each_device * to access it and don't care about locking yourself. - * In the rare case of beeing in irq context you can use + * In the rare case of being in irq context you can use * their __ prefixed variants with the lock held. NEVER * access this list directly from a driver. */ -- cgit v1.2.3-59-g8ed1b From 994bef1094500f78f36d0df56b5c0c58c73a7492 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 22 Oct 2014 11:50:40 +0200 Subject: clk: st: Spelling s/stucture/structure/ Signed-off-by: Geert Uytterhoeven Cc: Mike Turquette Signed-off-by: Jiri Kosina --- Documentation/devicetree/bindings/clock/st/st,flexgen.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/st/st,flexgen.txt b/Documentation/devicetree/bindings/clock/st/st,flexgen.txt index 1d3ace088172..b7ee5c7e0f75 100644 --- a/Documentation/devicetree/bindings/clock/st/st,flexgen.txt +++ b/Documentation/devicetree/bindings/clock/st/st,flexgen.txt @@ -11,7 +11,7 @@ Please find an example below: Clockgen block diagram ------------------------------------------------------------------- - | Flexgen stucture | + | Flexgen structure | | --------------------------------------------- | | | ------- -------- -------- | | clk_sysin | | | | | | | | | -- cgit v1.2.3-59-g8ed1b From 5935946c6a1180dcb495fffb2c45eddedfa09064 Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Tue, 21 Oct 2014 15:08:42 +0200 Subject: mtd: nand: add sunxi NFC dt bindings doc Add the sunxi NAND Flash Controller dt bindings documentation. Signed-off-by: Boris Brezillon Signed-off-by: Brian Norris --- .../devicetree/bindings/mtd/sunxi-nand.txt | 45 ++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 Documentation/devicetree/bindings/mtd/sunxi-nand.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mtd/sunxi-nand.txt b/Documentation/devicetree/bindings/mtd/sunxi-nand.txt new file mode 100644 index 000000000000..0273adb8638c --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/sunxi-nand.txt @@ -0,0 +1,45 @@ +Allwinner NAND Flash Controller (NFC) + +Required properties: +- compatible : "allwinner,sun4i-a10-nand". +- reg : shall contain registers location and length for data and reg. +- interrupts : shall define the nand controller interrupt. +- #address-cells: shall be set to 1. Encode the nand CS. +- #size-cells : shall be set to 0. +- clocks : shall reference nand controller clocks. +- clock-names : nand controller internal clock names. Shall contain : + * "ahb" : AHB gating clock + * "mod" : nand controller clock + +Optional children nodes: +Children nodes represent the available nand chips. + +Optional properties: +- allwinner,rb : shall contain the native Ready/Busy ids. + or +- rb-gpios : shall contain the gpios used as R/B pins. +- nand-ecc-mode : one of the supported ECC modes ("hw", "hw_syndrome", "soft", + "soft_bch" or "none") + +see Documentation/devicetree/mtd/nand.txt for generic bindings. + + +Examples: +nfc: nand@01c03000 { + compatible = "allwinner,sun4i-a10-nand"; + reg = <0x01c03000 0x1000>; + interrupts = <0 37 1>; + clocks = <&ahb_gates 13>, <&nand_clk>; + clock-names = "ahb", "mod"; + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&nand_pins_a &nand_cs0_pins_a &nand_rb0_pins_a>; + status = "okay"; + + nand@0 { + reg = <0>; + allwinner,rb = <0>; + nand-ecc-mode = "soft_bch"; + }; +}; -- cgit v1.2.3-59-g8ed1b From 21871d7eff2c96ae67e18e00adf59d56940e2fcc Mon Sep 17 00:00:00 2001 From: Clark Williams Date: Fri, 12 Sep 2014 21:21:09 -0500 Subject: rcu: Unify boost and kthread priorities Rename CONFIG_RCU_BOOST_PRIO to CONFIG_RCU_KTHREAD_PRIO and use this value for both the per-CPU kthreads (rcuc/N) and the rcu boosting threads (rcub/n). Also, create the module_parameter rcutree.kthread_prio to be used on the kernel command line at boot to set a new value (rcutree.kthread_prio=N). Signed-off-by: Clark Williams [ paulmck: Ported to rcu/dev, applied Paul Bolle and Peter Zijlstra feedback. ] Signed-off-by: Paul E. McKenney --- Documentation/kernel-parameters.txt | 7 +++++++ init/Kconfig | 23 +++++++++++----------- kernel/rcu/tree_plugin.h | 20 +++++++++---------- .../selftests/rcutorture/configs/rcu/TREE03 | 2 +- .../selftests/rcutorture/doc/TREE_RCU-kconfig.txt | 4 ++-- 5 files changed, 32 insertions(+), 24 deletions(-) (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 7dbe5ec9d9cd..6608520e9fa2 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -2922,6 +2922,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted. quiescent states. Units are jiffies, minimum 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). + rcutree.rcu_nocb_leader_stride= [KNL] Set the number of NOCB kthread groups, which defaults to the square root of the number of diff --git a/init/Kconfig b/init/Kconfig index 0c9546ba56e8..15c299cc7c1e 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -672,30 +672,31 @@ config RCU_BOOST Say Y here if you are working with real-time apps or heavy loads Say N here if you are unsure. -config RCU_BOOST_PRIO - int "Real-time priority to boost RCU readers to" +config RCU_KTHREAD_PRIO + int "Real-time priority to use for RCU worker threads" range 1 99 depends on RCU_BOOST default 1 help - This option specifies the real-time priority to which long-term - preempted RCU readers are to be boosted. If you are working - with a real-time application that has one or more CPU-bound - threads running at a real-time priority level, you should set - RCU_BOOST_PRIO to a priority higher then the highest-priority - real-time CPU-bound thread. The default RCU_BOOST_PRIO value - of 1 is appropriate in the common case, which is real-time + This option specifies the SCHED_FIFO priority value that will be + assigned to the rcuc/n and rcub/n threads and is also the value + used for RCU_BOOST (if enabled). If you are working with a + real-time application that has one or more CPU-bound threads + running at a real-time priority level, you should set + RCU_KTHREAD_PRIO to a priority higher than the highest-priority + real-time CPU-bound application thread. The default RCU_KTHREAD_PRIO + value of 1 is appropriate in the common case, which is real-time applications that do not have any CPU-bound threads. Some real-time applications might not have a single real-time thread that saturates a given CPU, but instead might have multiple real-time threads that, taken together, fully utilize - that CPU. In this case, you should set RCU_BOOST_PRIO to + that CPU. In this case, you should set RCU_KTHREAD_PRIO to a priority higher than the lowest-priority thread that is conspiring to prevent the CPU from running any non-real-time tasks. For example, if one thread at priority 10 and another thread at priority 5 are between themselves fully consuming - the CPU time on a given CPU, then RCU_BOOST_PRIO should be + the CPU time on a given CPU, then RCU_KTHREAD_PRIO should be set to priority 6 or higher. Specify the real-time priority, or take the default if unsure. diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h index 357891104ea0..344f0e661515 100644 --- a/kernel/rcu/tree_plugin.h +++ b/kernel/rcu/tree_plugin.h @@ -30,12 +30,13 @@ #include #include "../time/tick-internal.h" -#define RCU_KTHREAD_PRIO 1 - #ifdef CONFIG_RCU_BOOST #include "../locking/rtmutex_common.h" -#define RCU_BOOST_PRIO CONFIG_RCU_BOOST_PRIO + +/* rcuc/rcub kthread realtime priority */ +static int kthread_prio = CONFIG_RCU_KTHREAD_PRIO; +module_param(kthread_prio, int, 0644); /* * Control variables for per-CPU and per-rcu_node kthreads. These @@ -46,11 +47,7 @@ DEFINE_PER_CPU(unsigned int, rcu_cpu_kthread_status); DEFINE_PER_CPU(unsigned int, rcu_cpu_kthread_loops); DEFINE_PER_CPU(char, rcu_cpu_has_work); -#else /* #ifdef CONFIG_RCU_BOOST */ - -#define RCU_BOOST_PRIO RCU_KTHREAD_PRIO - -#endif /* #else #ifdef CONFIG_RCU_BOOST */ +#endif /* #ifdef CONFIG_RCU_BOOST */ #ifdef CONFIG_RCU_NOCB_CPU static cpumask_var_t rcu_nocb_mask; /* CPUs to have callbacks offloaded. */ @@ -98,6 +95,9 @@ static void __init rcu_bootup_announce_oddness(void) pr_info("\tBoot-time adjustment of leaf fanout to %d.\n", rcu_fanout_leaf); if (nr_cpu_ids != NR_CPUS) pr_info("\tRCU restricting CPUs from NR_CPUS=%d to nr_cpu_ids=%d.\n", NR_CPUS, nr_cpu_ids); +#ifdef CONFIG_RCU_BOOST + pr_info("\tRCU kthread priority: %d.\n", kthread_prio); +#endif } #ifdef CONFIG_TREE_PREEMPT_RCU @@ -1339,7 +1339,7 @@ static int rcu_spawn_one_boost_kthread(struct rcu_state *rsp, smp_mb__after_unlock_lock(); rnp->boost_kthread_task = t; raw_spin_unlock_irqrestore(&rnp->lock, flags); - sp.sched_priority = RCU_BOOST_PRIO; + sp.sched_priority = kthread_prio; sched_setscheduler_nocheck(t, SCHED_FIFO, &sp); wake_up_process(t); /* get to TASK_INTERRUPTIBLE quickly. */ return 0; @@ -1356,7 +1356,7 @@ static void rcu_cpu_kthread_setup(unsigned int cpu) { struct sched_param sp; - sp.sched_priority = RCU_KTHREAD_PRIO; + sp.sched_priority = kthread_prio; sched_setscheduler_nocheck(current, SCHED_FIFO, &sp); } diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE03 b/tools/testing/selftests/rcutorture/configs/rcu/TREE03 index f4567fb3e332..b95f62efd6f2 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE03 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE03 @@ -17,5 +17,5 @@ CONFIG_DEBUG_LOCK_ALLOC=n CONFIG_RCU_CPU_STALL_INFO=n CONFIG_RCU_CPU_STALL_VERBOSE=n CONFIG_RCU_BOOST=y -CONFIG_RCU_BOOST_PRIO=2 +CONFIG_RCU_KTHREAD_PRIO=2 CONFIG_DEBUG_OBJECTS_RCU_HEAD=n diff --git a/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt b/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt index 3e588db86a17..ab6e7b4103ac 100644 --- a/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt +++ b/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt @@ -15,8 +15,8 @@ CONFIG_PREEMPT -- Do half. (First three and #8.) CONFIG_PROVE_LOCKING -- Do all but two, covering CONFIG_PROVE_RCU and not. CONFIG_PROVE_RCU -- Do all but one under CONFIG_PROVE_LOCKING. CONFIG_RCU_BOOST -- one of TREE_PREEMPT_RCU. -CONFIG_RCU_BOOST_PRIO -- set to 2 for _BOOST testing. -CONFIG_RCU_CPU_STALL_INFO -- do one with and without _VERBOSE. +CONFIG_RCU_KTHREAD_PRIO -- set to 2 for _BOOST testing. +CONFIG_RCU_CPU_STALL_INFO -- Do one. CONFIG_RCU_CPU_STALL_VERBOSE -- do one with and without _INFO. CONFIG_RCU_FANOUT -- Cover hierarchy as currently, but overlap with others. CONFIG_RCU_FANOUT_EXACT -- Do one. -- cgit v1.2.3-59-g8ed1b From 28f6569ab7d036cd4ee94c26bb76dc1b3f3fc056 Mon Sep 17 00:00:00 2001 From: Pranith Kumar Date: Mon, 22 Sep 2014 14:00:48 -0400 Subject: rcu: Remove redundant TREE_PREEMPT_RCU config option PREEMPT_RCU and TREE_PREEMPT_RCU serve the same function after TINY_PREEMPT_RCU has been removed. This patch removes TREE_PREEMPT_RCU and uses PREEMPT_RCU config option in its place. Signed-off-by: Pranith Kumar Signed-off-by: Paul E. McKenney --- Documentation/RCU/rcu.txt | 4 ++-- Documentation/RCU/stallwarn.txt | 8 ++++---- Documentation/RCU/trace.txt | 4 ++-- Documentation/RCU/whatisRCU.txt | 2 +- include/linux/init_task.h | 2 +- include/linux/rcupdate.h | 6 +++--- include/linux/sched.h | 4 ++-- include/trace/events/rcu.h | 4 ++-- init/Kconfig | 22 ++++++++-------------- kernel/rcu/Makefile | 2 +- kernel/rcu/tree.h | 10 +++++----- kernel/rcu/tree_plugin.h | 6 +++--- kernel/rcu/update.c | 2 +- lib/Kconfig.debug | 2 +- .../selftests/rcutorture/configs/rcu/TREE01 | 2 +- .../selftests/rcutorture/configs/rcu/TREE02 | 2 +- .../selftests/rcutorture/configs/rcu/TREE02-T | 2 +- .../selftests/rcutorture/configs/rcu/TREE03 | 2 +- .../selftests/rcutorture/configs/rcu/TREE08 | 2 +- .../selftests/rcutorture/configs/rcu/TREE08-T | 2 +- .../selftests/rcutorture/configs/rcu/TREE09 | 2 +- .../configs/rcu/v0.0/P1-S-T-NH-SD-SMP-HP | 2 +- .../configs/rcu/v0.0/P2-2-t-nh-sd-SMP-hp | 2 +- .../configs/rcu/v0.0/P3-3-T-nh-SD-SMP-hp | 2 +- .../configs/rcu/v0.0/P4-A-t-NH-sd-SMP-HP | 2 +- .../configs/rcu/v0.0/P5-U-T-NH-sd-SMP-hp | 2 +- .../configs/rcu/v3.12/P1-S-T-NH-SD-SMP-HP | 2 +- .../configs/rcu/v3.12/P2-2-t-nh-sd-SMP-hp | 2 +- .../configs/rcu/v3.12/P3-3-T-nh-SD-SMP-hp | 2 +- .../configs/rcu/v3.12/P4-A-t-NH-sd-SMP-HP | 2 +- .../configs/rcu/v3.12/P5-U-T-NH-sd-SMP-hp | 2 +- .../configs/rcu/v3.12/P6---t-nh-SD-smp-hp | 2 +- .../configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP | 2 +- .../configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-all | 2 +- .../configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-none | 2 +- .../configs/rcu/v3.12/P7-4-T-NH-SD-SMP-hp | 2 +- .../configs/rcu/v3.3/P1-S-T-NH-SD-SMP-HP | 2 +- .../configs/rcu/v3.3/P2-2-t-nh-sd-SMP-hp | 2 +- .../configs/rcu/v3.3/P3-3-T-nh-SD-SMP-hp | 2 +- .../configs/rcu/v3.3/P4-A-t-NH-sd-SMP-HP | 2 +- .../configs/rcu/v3.3/P5-U-T-NH-sd-SMP-hp | 2 +- .../configs/rcu/v3.5/P1-S-T-NH-SD-SMP-HP | 2 +- .../configs/rcu/v3.5/P2-2-t-nh-sd-SMP-hp | 2 +- .../configs/rcu/v3.5/P3-3-T-nh-SD-SMP-hp | 2 +- .../configs/rcu/v3.5/P4-A-t-NH-sd-SMP-HP | 2 +- .../configs/rcu/v3.5/P5-U-T-NH-sd-SMP-hp | 2 +- .../testing/selftests/rcutorture/doc/TINY_RCU.txt | 2 +- .../selftests/rcutorture/doc/TREE_RCU-kconfig.txt | 10 +++++----- 48 files changed, 74 insertions(+), 80 deletions(-) (limited to 'Documentation') diff --git a/Documentation/RCU/rcu.txt b/Documentation/RCU/rcu.txt index bf778332a28f..745f429fda79 100644 --- a/Documentation/RCU/rcu.txt +++ b/Documentation/RCU/rcu.txt @@ -36,7 +36,7 @@ o How can the updater tell when a grace period has completed executed in user mode, or executed in the idle loop, we can safely free up that item. - Preemptible variants of RCU (CONFIG_TREE_PREEMPT_RCU) get the + Preemptible variants of RCU (CONFIG_PREEMPT_RCU) get the same effect, but require that the readers manipulate CPU-local counters. These counters allow limited types of blocking within RCU read-side critical sections. SRCU also uses CPU-local @@ -81,7 +81,7 @@ o I hear that RCU is patented? What is with that? o I hear that RCU needs work in order to support realtime kernels? This work is largely completed. Realtime-friendly RCU can be - enabled via the CONFIG_TREE_PREEMPT_RCU kernel configuration + enabled via the CONFIG_PREEMPT_RCU kernel configuration parameter. However, work is in progress for enabling priority boosting of preempted RCU read-side critical sections. This is needed if you have CPU-bound realtime threads. diff --git a/Documentation/RCU/stallwarn.txt b/Documentation/RCU/stallwarn.txt index ef5a2fd4ff70..783e0720994d 100644 --- a/Documentation/RCU/stallwarn.txt +++ b/Documentation/RCU/stallwarn.txt @@ -77,7 +77,7 @@ This message indicates that CPU 5 detected that it was causing a stall, and that the stall was affecting RCU-sched. This message will normally be followed by a stack dump of the offending CPU. On TREE_RCU kernel builds, RCU and RCU-sched are implemented by the same underlying mechanism, -while on TREE_PREEMPT_RCU kernel builds, RCU is instead implemented +while on PREEMPT_RCU kernel builds, RCU is instead implemented by rcu_preempt_state. On the other hand, if the offending CPU fails to print out a stall-warning @@ -89,7 +89,7 @@ INFO: rcu_bh_state detected stalls on CPUs/tasks: { 3 5 } (detected by 2, 2502 j This message indicates that CPU 2 detected that CPUs 3 and 5 were both causing stalls, and that the stall was affecting RCU-bh. This message will normally be followed by stack dumps for each CPU. Please note that -TREE_PREEMPT_RCU builds can be stalled by tasks as well as by CPUs, +PREEMPT_RCU builds can be stalled by tasks as well as by CPUs, and that the tasks will be indicated by PID, for example, "P3421". It is even possible for a rcu_preempt_state stall to be caused by both CPUs -and- tasks, in which case the offending CPUs and tasks will all @@ -205,10 +205,10 @@ o A CPU-bound real-time task in a CONFIG_PREEMPT kernel, which might o A CPU-bound real-time task in a CONFIG_PREEMPT_RT kernel that is running at a higher priority than the RCU softirq threads. This will prevent RCU callbacks from ever being invoked, - and in a CONFIG_TREE_PREEMPT_RCU kernel will further prevent + and in a CONFIG_PREEMPT_RCU kernel will further prevent RCU grace periods from ever completing. Either way, the system will eventually run out of memory and hang. In the - CONFIG_TREE_PREEMPT_RCU case, you might see stall-warning + CONFIG_PREEMPT_RCU case, you might see stall-warning messages. o A hardware or software issue shuts off the scheduler-clock diff --git a/Documentation/RCU/trace.txt b/Documentation/RCU/trace.txt index 910870b15acd..b63b9bb3bc0c 100644 --- a/Documentation/RCU/trace.txt +++ b/Documentation/RCU/trace.txt @@ -8,7 +8,7 @@ The following sections describe the debugfs files and formats, first for rcutree and next for rcutiny. -CONFIG_TREE_RCU and CONFIG_TREE_PREEMPT_RCU debugfs Files and Formats +CONFIG_TREE_RCU and CONFIG_PREEMPT_RCU debugfs Files and Formats These implementations of RCU provide several debugfs directories under the top-level directory "rcu": @@ -18,7 +18,7 @@ rcu/rcu_preempt rcu/rcu_sched Each directory contains files for the corresponding flavor of RCU. -Note that rcu/rcu_preempt is only present for CONFIG_TREE_PREEMPT_RCU. +Note that rcu/rcu_preempt is only present for CONFIG_PREEMPT_RCU. For CONFIG_TREE_RCU, the RCU flavor maps onto the RCU-sched flavor, so that activity for both appears in rcu/rcu_sched. diff --git a/Documentation/RCU/whatisRCU.txt b/Documentation/RCU/whatisRCU.txt index e48c57f1943b..88dfce182f66 100644 --- a/Documentation/RCU/whatisRCU.txt +++ b/Documentation/RCU/whatisRCU.txt @@ -137,7 +137,7 @@ rcu_read_lock() Used by a reader to inform the reclaimer that the reader is entering an RCU read-side critical section. It is illegal to block while in an RCU read-side critical section, though - kernels built with CONFIG_TREE_PREEMPT_RCU can preempt RCU + kernels built with CONFIG_PREEMPT_RCU can preempt RCU read-side critical sections. Any RCU-protected data structure accessed during an RCU read-side critical section is guaranteed to remain unreclaimed for the full duration of that critical section. diff --git a/include/linux/init_task.h b/include/linux/init_task.h index 77fc43f8fb72..d996aef8044f 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h @@ -102,7 +102,7 @@ extern struct group_info init_groups; #define INIT_IDS #endif -#ifdef CONFIG_TREE_PREEMPT_RCU +#ifdef CONFIG_PREEMPT_RCU #define INIT_TASK_RCU_TREE_PREEMPT() \ .rcu_blocked_node = NULL, #else diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index a4a819ffb2d1..295bb4595de6 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -57,7 +57,7 @@ enum rcutorture_type { INVALID_RCU_FLAVOR }; -#if defined(CONFIG_TREE_RCU) || defined(CONFIG_TREE_PREEMPT_RCU) +#if defined(CONFIG_TREE_RCU) || defined(CONFIG_PREEMPT_RCU) void rcutorture_get_gp_data(enum rcutorture_type test_type, int *flags, unsigned long *gpnum, unsigned long *completed); void rcutorture_record_test_transition(void); @@ -365,7 +365,7 @@ typedef void call_rcu_func_t(struct rcu_head *head, void (*func)(struct rcu_head *head)); void wait_rcu_gp(call_rcu_func_t crf); -#if defined(CONFIG_TREE_RCU) || defined(CONFIG_TREE_PREEMPT_RCU) +#if defined(CONFIG_TREE_RCU) || defined(CONFIG_PREEMPT_RCU) #include #elif defined(CONFIG_TINY_RCU) #include @@ -852,7 +852,7 @@ static inline void rcu_preempt_sleep_check(void) * * In non-preemptible RCU implementations (TREE_RCU and TINY_RCU), * it is illegal to block while in an RCU read-side critical section. - * In preemptible RCU implementations (TREE_PREEMPT_RCU) in CONFIG_PREEMPT + * In preemptible RCU implementations (PREEMPT_RCU) in CONFIG_PREEMPT * kernel builds, RCU read-side critical sections may be preempted, * but explicit blocking is illegal. Finally, in preemptible RCU * implementations in real-time (with -rt patchset) kernel builds, RCU diff --git a/include/linux/sched.h b/include/linux/sched.h index 5e344bbe63ec..706a9f744909 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1278,9 +1278,9 @@ struct task_struct { union rcu_special rcu_read_unlock_special; struct list_head rcu_node_entry; #endif /* #ifdef CONFIG_PREEMPT_RCU */ -#ifdef CONFIG_TREE_PREEMPT_RCU +#ifdef CONFIG_PREEMPT_RCU struct rcu_node *rcu_blocked_node; -#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */ +#endif /* #ifdef CONFIG_PREEMPT_RCU */ #ifdef CONFIG_TASKS_RCU unsigned long rcu_tasks_nvcsw; bool rcu_tasks_holdout; diff --git a/include/trace/events/rcu.h b/include/trace/events/rcu.h index e335e7d8c6c2..c78e88ce5ea3 100644 --- a/include/trace/events/rcu.h +++ b/include/trace/events/rcu.h @@ -36,7 +36,7 @@ TRACE_EVENT(rcu_utilization, #ifdef CONFIG_RCU_TRACE -#if defined(CONFIG_TREE_RCU) || defined(CONFIG_TREE_PREEMPT_RCU) +#if defined(CONFIG_TREE_RCU) || defined(CONFIG_PREEMPT_RCU) /* * Tracepoint for grace-period events. Takes a string identifying the @@ -345,7 +345,7 @@ TRACE_EVENT(rcu_fqs, __entry->cpu, __entry->qsevent) ); -#endif /* #if defined(CONFIG_TREE_RCU) || defined(CONFIG_TREE_PREEMPT_RCU) */ +#endif /* #if defined(CONFIG_TREE_RCU) || defined(CONFIG_PREEMPT_RCU) */ /* * Tracepoint for dyntick-idle entry/exit events. These take a string diff --git a/init/Kconfig b/init/Kconfig index 15c299cc7c1e..5ac596e2cb4b 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -477,7 +477,7 @@ config TREE_RCU thousands of CPUs. It also scales down nicely to smaller systems. -config TREE_PREEMPT_RCU +config PREEMPT_RCU bool "Preemptible tree-based hierarchical RCU" depends on PREEMPT select IRQ_WORK @@ -501,12 +501,6 @@ config TINY_RCU endchoice -config PREEMPT_RCU - def_bool TREE_PREEMPT_RCU - help - This option enables preemptible-RCU code that is common between - TREE_PREEMPT_RCU and, in the old days, TINY_PREEMPT_RCU. - config TASKS_RCU bool "Task_based RCU implementation using voluntary context switch" default n @@ -518,7 +512,7 @@ config TASKS_RCU If unsure, say N. config RCU_STALL_COMMON - def_bool ( TREE_RCU || TREE_PREEMPT_RCU || RCU_TRACE ) + def_bool ( TREE_RCU || PREEMPT_RCU || RCU_TRACE ) help This option enables RCU CPU stall code that is common between the TINY and TREE variants of RCU. The purpose is to allow @@ -576,7 +570,7 @@ config RCU_FANOUT int "Tree-based hierarchical RCU fanout value" range 2 64 if 64BIT range 2 32 if !64BIT - depends on TREE_RCU || TREE_PREEMPT_RCU + depends on TREE_RCU || PREEMPT_RCU default 64 if 64BIT default 32 if !64BIT help @@ -596,7 +590,7 @@ config RCU_FANOUT_LEAF int "Tree-based hierarchical RCU leaf-level fanout value" range 2 RCU_FANOUT if 64BIT range 2 RCU_FANOUT if !64BIT - depends on TREE_RCU || TREE_PREEMPT_RCU + depends on TREE_RCU || PREEMPT_RCU default 16 help This option controls the leaf-level fanout of hierarchical @@ -621,7 +615,7 @@ config RCU_FANOUT_LEAF config RCU_FANOUT_EXACT bool "Disable tree-based hierarchical RCU auto-balancing" - depends on TREE_RCU || TREE_PREEMPT_RCU + depends on TREE_RCU || PREEMPT_RCU default n help This option forces use of the exact RCU_FANOUT value specified, @@ -652,11 +646,11 @@ config RCU_FAST_NO_HZ Say N if you are unsure. config TREE_RCU_TRACE - def_bool RCU_TRACE && ( TREE_RCU || TREE_PREEMPT_RCU ) + def_bool RCU_TRACE && ( TREE_RCU || PREEMPT_RCU ) select DEBUG_FS help This option provides tracing for the TREE_RCU and - TREE_PREEMPT_RCU implementations, permitting Makefile to + PREEMPT_RCU implementations, permitting Makefile to trivially select kernel/rcutree_trace.c. config RCU_BOOST @@ -716,7 +710,7 @@ config RCU_BOOST_DELAY config RCU_NOCB_CPU bool "Offload RCU callback processing from boot-selected CPUs" - depends on TREE_RCU || TREE_PREEMPT_RCU + depends on TREE_RCU || PREEMPT_RCU default n help Use this option to reduce OS jitter for aggressive HPC or diff --git a/kernel/rcu/Makefile b/kernel/rcu/Makefile index 807ccfbf69b3..e6fae503d1bc 100644 --- a/kernel/rcu/Makefile +++ b/kernel/rcu/Makefile @@ -1,6 +1,6 @@ obj-y += update.o srcu.o obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o obj-$(CONFIG_TREE_RCU) += tree.o -obj-$(CONFIG_TREE_PREEMPT_RCU) += tree.o +obj-$(CONFIG_PREEMPT_RCU) += tree.o obj-$(CONFIG_TREE_RCU_TRACE) += tree_trace.o obj-$(CONFIG_TINY_RCU) += tiny.o diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h index bbdc45d8d74f..66cde5109c7d 100644 --- a/kernel/rcu/tree.h +++ b/kernel/rcu/tree.h @@ -139,7 +139,7 @@ struct rcu_node { unsigned long expmask; /* Groups that have ->blkd_tasks */ /* elements that need to drain to allow the */ /* current expedited grace period to */ - /* complete (only for TREE_PREEMPT_RCU). */ + /* complete (only for PREEMPT_RCU). */ unsigned long qsmaskinit; /* Per-GP initial value for qsmask & expmask. */ unsigned long grpmask; /* Mask to apply to parent qsmask. */ @@ -530,10 +530,10 @@ DECLARE_PER_CPU(struct rcu_data, rcu_sched_data); extern struct rcu_state rcu_bh_state; DECLARE_PER_CPU(struct rcu_data, rcu_bh_data); -#ifdef CONFIG_TREE_PREEMPT_RCU +#ifdef CONFIG_PREEMPT_RCU extern struct rcu_state rcu_preempt_state; DECLARE_PER_CPU(struct rcu_data, rcu_preempt_data); -#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */ +#endif /* #ifdef CONFIG_PREEMPT_RCU */ #ifdef CONFIG_RCU_BOOST DECLARE_PER_CPU(unsigned int, rcu_cpu_kthread_status); @@ -563,10 +563,10 @@ static int rcu_preempt_offline_tasks(struct rcu_state *rsp, #endif /* #ifdef CONFIG_HOTPLUG_CPU */ static void rcu_preempt_check_callbacks(int cpu); void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu)); -#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_TREE_PREEMPT_RCU) +#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_PREEMPT_RCU) static void rcu_report_exp_rnp(struct rcu_state *rsp, struct rcu_node *rnp, bool wake); -#endif /* #if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_TREE_PREEMPT_RCU) */ +#endif /* #if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_PREEMPT_RCU) */ static void __init __rcu_init_preempt(void); static void rcu_initiate_boost(struct rcu_node *rnp, unsigned long flags); static void rcu_preempt_boost_start_gp(struct rcu_node *rnp); diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h index 344f0e661515..6d07fb402e84 100644 --- a/kernel/rcu/tree_plugin.h +++ b/kernel/rcu/tree_plugin.h @@ -100,7 +100,7 @@ static void __init rcu_bootup_announce_oddness(void) #endif } -#ifdef CONFIG_TREE_PREEMPT_RCU +#ifdef CONFIG_PREEMPT_RCU RCU_STATE_INITIALIZER(rcu_preempt, 'p', call_rcu); static struct rcu_state *rcu_state_p = &rcu_preempt_state; @@ -932,7 +932,7 @@ void exit_rcu(void) __rcu_read_unlock(); } -#else /* #ifdef CONFIG_TREE_PREEMPT_RCU */ +#else /* #ifdef CONFIG_PREEMPT_RCU */ static struct rcu_state *rcu_state_p = &rcu_sched_state; @@ -1083,7 +1083,7 @@ void exit_rcu(void) { } -#endif /* #else #ifdef CONFIG_TREE_PREEMPT_RCU */ +#endif /* #else #ifdef CONFIG_PREEMPT_RCU */ #ifdef CONFIG_RCU_BOOST diff --git a/kernel/rcu/update.c b/kernel/rcu/update.c index 3ef8ba58694e..27a5b174b2a4 100644 --- a/kernel/rcu/update.c +++ b/kernel/rcu/update.c @@ -306,7 +306,7 @@ struct debug_obj_descr rcuhead_debug_descr = { EXPORT_SYMBOL_GPL(rcuhead_debug_descr); #endif /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */ -#if defined(CONFIG_TREE_RCU) || defined(CONFIG_TREE_PREEMPT_RCU) || defined(CONFIG_RCU_TRACE) +#if defined(CONFIG_TREE_RCU) || defined(CONFIG_PREEMPT_RCU) || defined(CONFIG_RCU_TRACE) void do_trace_rcu_torture_read(const char *rcutorturename, struct rcu_head *rhp, unsigned long secs, unsigned long c_old, unsigned long c) diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 4e35a5d767ed..12e7b020539f 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -1252,7 +1252,7 @@ config RCU_CPU_STALL_VERBOSE config RCU_CPU_STALL_INFO bool "Print additional diagnostics on RCU CPU stall" - depends on (TREE_RCU || TREE_PREEMPT_RCU) && DEBUG_KERNEL + depends on (TREE_RCU || PREEMPT_RCU) && DEBUG_KERNEL default n help For each stalled CPU that is aware of the current RCU grace diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE01 b/tools/testing/selftests/rcutorture/configs/rcu/TREE01 index 38e3895759dd..69f8e5878a58 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE01 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE01 @@ -2,7 +2,7 @@ CONFIG_SMP=y CONFIG_PREEMPT_NONE=n CONFIG_PREEMPT_VOLUNTARY=n CONFIG_PREEMPT=y -#CHECK#CONFIG_TREE_PREEMPT_RCU=y +#CHECK#CONFIG_PREEMPT_RCU=y CONFIG_HZ_PERIODIC=n CONFIG_NO_HZ_IDLE=y CONFIG_NO_HZ_FULL=n diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE02 b/tools/testing/selftests/rcutorture/configs/rcu/TREE02 index ea119ba2f7d4..fc29c6297197 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE02 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE02 @@ -3,7 +3,7 @@ CONFIG_NR_CPUS=8 CONFIG_PREEMPT_NONE=n CONFIG_PREEMPT_VOLUNTARY=n CONFIG_PREEMPT=y -#CHECK#CONFIG_TREE_PREEMPT_RCU=y +#CHECK#CONFIG_PREEMPT_RCU=y CONFIG_HZ_PERIODIC=n CONFIG_NO_HZ_IDLE=y CONFIG_NO_HZ_FULL=n diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE02-T b/tools/testing/selftests/rcutorture/configs/rcu/TREE02-T index 19cf9485f48a..778ec567a472 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE02-T +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE02-T @@ -3,7 +3,7 @@ CONFIG_NR_CPUS=8 CONFIG_PREEMPT_NONE=n CONFIG_PREEMPT_VOLUNTARY=n CONFIG_PREEMPT=y -#CHECK#CONFIG_TREE_PREEMPT_RCU=y +#CHECK#CONFIG_PREEMPT_RCU=y CONFIG_HZ_PERIODIC=n CONFIG_NO_HZ_IDLE=y CONFIG_NO_HZ_FULL=n diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE03 b/tools/testing/selftests/rcutorture/configs/rcu/TREE03 index b95f62efd6f2..a022f0332303 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE03 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE03 @@ -3,7 +3,7 @@ CONFIG_NR_CPUS=8 CONFIG_PREEMPT_NONE=n CONFIG_PREEMPT_VOLUNTARY=n CONFIG_PREEMPT=y -#CHECK#CONFIG_TREE_PREEMPT_RCU=y +#CHECK#CONFIG_PREEMPT_RCU=y CONFIG_HZ_PERIODIC=y CONFIG_NO_HZ_IDLE=n CONFIG_NO_HZ_FULL=n diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE08 b/tools/testing/selftests/rcutorture/configs/rcu/TREE08 index 69a2e255bf98..6f8609d2d072 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE08 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE08 @@ -3,7 +3,7 @@ CONFIG_NR_CPUS=16 CONFIG_PREEMPT_NONE=n CONFIG_PREEMPT_VOLUNTARY=n CONFIG_PREEMPT=y -#CHECK#CONFIG_TREE_PREEMPT_RCU=y +#CHECK#CONFIG_PREEMPT_RCU=y CONFIG_HZ_PERIODIC=n CONFIG_NO_HZ_IDLE=y CONFIG_NO_HZ_FULL=n diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE08-T b/tools/testing/selftests/rcutorture/configs/rcu/TREE08-T index a0f32fb8f17e..4e55bee2d3f8 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE08-T +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE08-T @@ -3,7 +3,7 @@ CONFIG_NR_CPUS=16 CONFIG_PREEMPT_NONE=n CONFIG_PREEMPT_VOLUNTARY=n CONFIG_PREEMPT=y -#CHECK#CONFIG_TREE_PREEMPT_RCU=y +#CHECK#CONFIG_PREEMPT_RCU=y CONFIG_HZ_PERIODIC=n CONFIG_NO_HZ_IDLE=y CONFIG_NO_HZ_FULL=n diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE09 b/tools/testing/selftests/rcutorture/configs/rcu/TREE09 index b7a62a540ad1..47e2ecd1844f 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE09 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE09 @@ -3,7 +3,7 @@ CONFIG_NR_CPUS=1 CONFIG_PREEMPT_NONE=n CONFIG_PREEMPT_VOLUNTARY=n CONFIG_PREEMPT=y -#CHECK#CONFIG_TREE_PREEMPT_RCU=y +#CHECK#CONFIG_PREEMPT_RCU=y CONFIG_HZ_PERIODIC=n CONFIG_NO_HZ_IDLE=y CONFIG_NO_HZ_FULL=n diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P1-S-T-NH-SD-SMP-HP index f72402d7c13d..dd7bd4d2d85a 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P1-S-T-NH-SD-SMP-HP +++ b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P1-S-T-NH-SD-SMP-HP @@ -9,7 +9,7 @@ CONFIG_HOTPLUG_CPU=y CONFIG_PREEMPT_NONE=n CONFIG_PREEMPT_VOLUNTARY=n CONFIG_PREEMPT=y -#CHECK#CONFIG_TREE_PREEMPT_RCU=y +#CHECK#CONFIG_PREEMPT_RCU=y CONFIG_RCU_TORTURE_TEST=m CONFIG_MODULE_UNLOAD=y CONFIG_SYSFS_DEPRECATED_V2=y diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P2-2-t-nh-sd-SMP-hp index 0f3b667d2a9f..81d484362820 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P2-2-t-nh-sd-SMP-hp +++ b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P2-2-t-nh-sd-SMP-hp @@ -10,7 +10,7 @@ CONFIG_HIBERNATION=n CONFIG_PREEMPT_NONE=n CONFIG_PREEMPT_VOLUNTARY=n CONFIG_PREEMPT=y -#CHECK#CONFIG_TREE_PREEMPT_RCU=y +#CHECK#CONFIG_PREEMPT_RCU=y CONFIG_RCU_TORTURE_TEST=m CONFIG_MODULE_UNLOAD=y CONFIG_SYSFS_DEPRECATED_V2=y diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P3-3-T-nh-SD-SMP-hp index b035e141bf2a..16e22b7815c2 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P3-3-T-nh-SD-SMP-hp +++ b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P3-3-T-nh-SD-SMP-hp @@ -10,7 +10,7 @@ CONFIG_HIBERNATION=n CONFIG_PREEMPT_NONE=n CONFIG_PREEMPT_VOLUNTARY=n CONFIG_PREEMPT=y -#CHECK#CONFIG_TREE_PREEMPT_RCU=y +#CHECK#CONFIG_PREEMPT_RCU=y CONFIG_RCU_TORTURE_TEST=m CONFIG_MODULE_UNLOAD=y CONFIG_SYSFS_DEPRECATED_V2=y diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P4-A-t-NH-sd-SMP-HP index 3ccf6a9447f5..ea7ed3b9a2da 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P4-A-t-NH-sd-SMP-HP +++ b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P4-A-t-NH-sd-SMP-HP @@ -8,7 +8,7 @@ CONFIG_HOTPLUG_CPU=y CONFIG_PREEMPT_NONE=n CONFIG_PREEMPT_VOLUNTARY=n CONFIG_PREEMPT=y -#CHECK#CONFIG_TREE_PREEMPT_RCU=y +#CHECK#CONFIG_PREEMPT_RCU=y CONFIG_RCU_TORTURE_TEST=m CONFIG_MODULE_UNLOAD=y CONFIG_RT_MUTEXES=y diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P5-U-T-NH-sd-SMP-hp index a55c00877fe4..24f4d5e40c80 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P5-U-T-NH-sd-SMP-hp +++ b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P5-U-T-NH-sd-SMP-hp @@ -11,7 +11,7 @@ CONFIG_HIBERNATION=n CONFIG_PREEMPT_NONE=n CONFIG_PREEMPT_VOLUNTARY=n CONFIG_PREEMPT=y -#CHECK#CONFIG_TREE_PREEMPT_RCU=y +#CHECK#CONFIG_PREEMPT_RCU=y CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_OBJECTS=y CONFIG_DEBUG_OBJECTS_RCU_HEAD=y diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P1-S-T-NH-SD-SMP-HP index 9647c44cf4b7..688066322c89 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P1-S-T-NH-SD-SMP-HP +++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P1-S-T-NH-SD-SMP-HP @@ -10,7 +10,7 @@ CONFIG_HOTPLUG_CPU=y CONFIG_PREEMPT_NONE=n CONFIG_PREEMPT_VOLUNTARY=n CONFIG_PREEMPT=y -#CHECK#CONFIG_TREE_PREEMPT_RCU=y +#CHECK#CONFIG_PREEMPT_RCU=y CONFIG_RCU_TORTURE_TEST=m CONFIG_MODULE_UNLOAD=y CONFIG_SYSFS_DEPRECATED_V2=y diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P2-2-t-nh-sd-SMP-hp index 0f3b667d2a9f..81d484362820 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P2-2-t-nh-sd-SMP-hp +++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P2-2-t-nh-sd-SMP-hp @@ -10,7 +10,7 @@ CONFIG_HIBERNATION=n CONFIG_PREEMPT_NONE=n CONFIG_PREEMPT_VOLUNTARY=n CONFIG_PREEMPT=y -#CHECK#CONFIG_TREE_PREEMPT_RCU=y +#CHECK#CONFIG_PREEMPT_RCU=y CONFIG_RCU_TORTURE_TEST=m CONFIG_MODULE_UNLOAD=y CONFIG_SYSFS_DEPRECATED_V2=y diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P3-3-T-nh-SD-SMP-hp index b035e141bf2a..16e22b7815c2 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P3-3-T-nh-SD-SMP-hp +++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P3-3-T-nh-SD-SMP-hp @@ -10,7 +10,7 @@ CONFIG_HIBERNATION=n CONFIG_PREEMPT_NONE=n CONFIG_PREEMPT_VOLUNTARY=n CONFIG_PREEMPT=y -#CHECK#CONFIG_TREE_PREEMPT_RCU=y +#CHECK#CONFIG_PREEMPT_RCU=y CONFIG_RCU_TORTURE_TEST=m CONFIG_MODULE_UNLOAD=y CONFIG_SYSFS_DEPRECATED_V2=y diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P4-A-t-NH-sd-SMP-HP index 3ccf6a9447f5..ea7ed3b9a2da 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P4-A-t-NH-sd-SMP-HP +++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P4-A-t-NH-sd-SMP-HP @@ -8,7 +8,7 @@ CONFIG_HOTPLUG_CPU=y CONFIG_PREEMPT_NONE=n CONFIG_PREEMPT_VOLUNTARY=n CONFIG_PREEMPT=y -#CHECK#CONFIG_TREE_PREEMPT_RCU=y +#CHECK#CONFIG_PREEMPT_RCU=y CONFIG_RCU_TORTURE_TEST=m CONFIG_MODULE_UNLOAD=y CONFIG_RT_MUTEXES=y diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P5-U-T-NH-sd-SMP-hp index a55c00877fe4..24f4d5e40c80 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P5-U-T-NH-sd-SMP-hp +++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P5-U-T-NH-sd-SMP-hp @@ -11,7 +11,7 @@ CONFIG_HIBERNATION=n CONFIG_PREEMPT_NONE=n CONFIG_PREEMPT_VOLUNTARY=n CONFIG_PREEMPT=y -#CHECK#CONFIG_TREE_PREEMPT_RCU=y +#CHECK#CONFIG_PREEMPT_RCU=y CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_OBJECTS=y CONFIG_DEBUG_OBJECTS_RCU_HEAD=y diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P6---t-nh-SD-smp-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P6---t-nh-SD-smp-hp index f4c9175828bf..1be59e4c8ba7 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P6---t-nh-SD-smp-hp +++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P6---t-nh-SD-smp-hp @@ -8,7 +8,7 @@ CONFIG_HIBERNATION=n CONFIG_PREEMPT_NONE=n CONFIG_PREEMPT_VOLUNTARY=n CONFIG_PREEMPT=y -CONFIG_TREE_PREEMPT_RCU=y +CONFIG_PREEMPT_RCU=y CONFIG_RCU_TORTURE_TEST=m CONFIG_MODULE_UNLOAD=y CONFIG_SYSFS_DEPRECATED_V2=y diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP index 77a8c5b75763..b49ef7463099 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP +++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP @@ -14,7 +14,7 @@ CONFIG_HIBERNATION=n CONFIG_PREEMPT_NONE=n CONFIG_PREEMPT_VOLUNTARY=n CONFIG_PREEMPT=y -#CHECK#CONFIG_TREE_PREEMPT_RCU=y +#CHECK#CONFIG_PREEMPT_RCU=y CONFIG_RCU_TORTURE_TEST=m CONFIG_MODULE_UNLOAD=y CONFIG_PROVE_LOCKING=y diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-all b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-all index 0eecebc6e95f..a55a6ac447d8 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-all +++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-all @@ -14,7 +14,7 @@ CONFIG_HIBERNATION=n CONFIG_PREEMPT_NONE=n CONFIG_PREEMPT_VOLUNTARY=n CONFIG_PREEMPT=y -#CHECK#CONFIG_TREE_PREEMPT_RCU=y +#CHECK#CONFIG_PREEMPT_RCU=y CONFIG_RCU_TORTURE_TEST=m CONFIG_MODULE_UNLOAD=y CONFIG_PROVE_LOCKING=y diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-none b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-none index 0eecebc6e95f..a55a6ac447d8 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-none +++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-none @@ -14,7 +14,7 @@ CONFIG_HIBERNATION=n CONFIG_PREEMPT_NONE=n CONFIG_PREEMPT_VOLUNTARY=n CONFIG_PREEMPT=y -#CHECK#CONFIG_TREE_PREEMPT_RCU=y +#CHECK#CONFIG_PREEMPT_RCU=y CONFIG_RCU_TORTURE_TEST=m CONFIG_MODULE_UNLOAD=y CONFIG_PROVE_LOCKING=y diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-hp index 588bc70420cd..3134f46b2f87 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-hp +++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-hp @@ -14,7 +14,7 @@ CONFIG_HIBERNATION=n CONFIG_PREEMPT_NONE=n CONFIG_PREEMPT_VOLUNTARY=n CONFIG_PREEMPT=y -#CHECK#CONFIG_TREE_PREEMPT_RCU=y +#CHECK#CONFIG_PREEMPT_RCU=y CONFIG_RCU_TORTURE_TEST=m CONFIG_MODULE_UNLOAD=y CONFIG_PROVE_LOCKING=y diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P1-S-T-NH-SD-SMP-HP index 9647c44cf4b7..688066322c89 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P1-S-T-NH-SD-SMP-HP +++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P1-S-T-NH-SD-SMP-HP @@ -10,7 +10,7 @@ CONFIG_HOTPLUG_CPU=y CONFIG_PREEMPT_NONE=n CONFIG_PREEMPT_VOLUNTARY=n CONFIG_PREEMPT=y -#CHECK#CONFIG_TREE_PREEMPT_RCU=y +#CHECK#CONFIG_PREEMPT_RCU=y CONFIG_RCU_TORTURE_TEST=m CONFIG_MODULE_UNLOAD=y CONFIG_SYSFS_DEPRECATED_V2=y diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P2-2-t-nh-sd-SMP-hp index 0f3b667d2a9f..81d484362820 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P2-2-t-nh-sd-SMP-hp +++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P2-2-t-nh-sd-SMP-hp @@ -10,7 +10,7 @@ CONFIG_HIBERNATION=n CONFIG_PREEMPT_NONE=n CONFIG_PREEMPT_VOLUNTARY=n CONFIG_PREEMPT=y -#CHECK#CONFIG_TREE_PREEMPT_RCU=y +#CHECK#CONFIG_PREEMPT_RCU=y CONFIG_RCU_TORTURE_TEST=m CONFIG_MODULE_UNLOAD=y CONFIG_SYSFS_DEPRECATED_V2=y diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P3-3-T-nh-SD-SMP-hp index b035e141bf2a..16e22b7815c2 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P3-3-T-nh-SD-SMP-hp +++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P3-3-T-nh-SD-SMP-hp @@ -10,7 +10,7 @@ CONFIG_HIBERNATION=n CONFIG_PREEMPT_NONE=n CONFIG_PREEMPT_VOLUNTARY=n CONFIG_PREEMPT=y -#CHECK#CONFIG_TREE_PREEMPT_RCU=y +#CHECK#CONFIG_PREEMPT_RCU=y CONFIG_RCU_TORTURE_TEST=m CONFIG_MODULE_UNLOAD=y CONFIG_SYSFS_DEPRECATED_V2=y diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P4-A-t-NH-sd-SMP-HP index 3ccf6a9447f5..ea7ed3b9a2da 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P4-A-t-NH-sd-SMP-HP +++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P4-A-t-NH-sd-SMP-HP @@ -8,7 +8,7 @@ CONFIG_HOTPLUG_CPU=y CONFIG_PREEMPT_NONE=n CONFIG_PREEMPT_VOLUNTARY=n CONFIG_PREEMPT=y -#CHECK#CONFIG_TREE_PREEMPT_RCU=y +#CHECK#CONFIG_PREEMPT_RCU=y CONFIG_RCU_TORTURE_TEST=m CONFIG_MODULE_UNLOAD=y CONFIG_RT_MUTEXES=y diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P5-U-T-NH-sd-SMP-hp index a55c00877fe4..24f4d5e40c80 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P5-U-T-NH-sd-SMP-hp +++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P5-U-T-NH-sd-SMP-hp @@ -11,7 +11,7 @@ CONFIG_HIBERNATION=n CONFIG_PREEMPT_NONE=n CONFIG_PREEMPT_VOLUNTARY=n CONFIG_PREEMPT=y -#CHECK#CONFIG_TREE_PREEMPT_RCU=y +#CHECK#CONFIG_PREEMPT_RCU=y CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_OBJECTS=y CONFIG_DEBUG_OBJECTS_RCU_HEAD=y diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P1-S-T-NH-SD-SMP-HP index 9647c44cf4b7..688066322c89 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P1-S-T-NH-SD-SMP-HP +++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P1-S-T-NH-SD-SMP-HP @@ -10,7 +10,7 @@ CONFIG_HOTPLUG_CPU=y CONFIG_PREEMPT_NONE=n CONFIG_PREEMPT_VOLUNTARY=n CONFIG_PREEMPT=y -#CHECK#CONFIG_TREE_PREEMPT_RCU=y +#CHECK#CONFIG_PREEMPT_RCU=y CONFIG_RCU_TORTURE_TEST=m CONFIG_MODULE_UNLOAD=y CONFIG_SYSFS_DEPRECATED_V2=y diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P2-2-t-nh-sd-SMP-hp index 0f3b667d2a9f..81d484362820 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P2-2-t-nh-sd-SMP-hp +++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P2-2-t-nh-sd-SMP-hp @@ -10,7 +10,7 @@ CONFIG_HIBERNATION=n CONFIG_PREEMPT_NONE=n CONFIG_PREEMPT_VOLUNTARY=n CONFIG_PREEMPT=y -#CHECK#CONFIG_TREE_PREEMPT_RCU=y +#CHECK#CONFIG_PREEMPT_RCU=y CONFIG_RCU_TORTURE_TEST=m CONFIG_MODULE_UNLOAD=y CONFIG_SYSFS_DEPRECATED_V2=y diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P3-3-T-nh-SD-SMP-hp index b035e141bf2a..16e22b7815c2 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P3-3-T-nh-SD-SMP-hp +++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P3-3-T-nh-SD-SMP-hp @@ -10,7 +10,7 @@ CONFIG_HIBERNATION=n CONFIG_PREEMPT_NONE=n CONFIG_PREEMPT_VOLUNTARY=n CONFIG_PREEMPT=y -#CHECK#CONFIG_TREE_PREEMPT_RCU=y +#CHECK#CONFIG_PREEMPT_RCU=y CONFIG_RCU_TORTURE_TEST=m CONFIG_MODULE_UNLOAD=y CONFIG_SYSFS_DEPRECATED_V2=y diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P4-A-t-NH-sd-SMP-HP index 3ccf6a9447f5..ea7ed3b9a2da 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P4-A-t-NH-sd-SMP-HP +++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P4-A-t-NH-sd-SMP-HP @@ -8,7 +8,7 @@ CONFIG_HOTPLUG_CPU=y CONFIG_PREEMPT_NONE=n CONFIG_PREEMPT_VOLUNTARY=n CONFIG_PREEMPT=y -#CHECK#CONFIG_TREE_PREEMPT_RCU=y +#CHECK#CONFIG_PREEMPT_RCU=y CONFIG_RCU_TORTURE_TEST=m CONFIG_MODULE_UNLOAD=y CONFIG_RT_MUTEXES=y diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P5-U-T-NH-sd-SMP-hp index a55c00877fe4..24f4d5e40c80 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P5-U-T-NH-sd-SMP-hp +++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P5-U-T-NH-sd-SMP-hp @@ -11,7 +11,7 @@ CONFIG_HIBERNATION=n CONFIG_PREEMPT_NONE=n CONFIG_PREEMPT_VOLUNTARY=n CONFIG_PREEMPT=y -#CHECK#CONFIG_TREE_PREEMPT_RCU=y +#CHECK#CONFIG_PREEMPT_RCU=y CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_OBJECTS=y CONFIG_DEBUG_OBJECTS_RCU_HEAD=y diff --git a/tools/testing/selftests/rcutorture/doc/TINY_RCU.txt b/tools/testing/selftests/rcutorture/doc/TINY_RCU.txt index 28db67b54e55..9ef33a743b73 100644 --- a/tools/testing/selftests/rcutorture/doc/TINY_RCU.txt +++ b/tools/testing/selftests/rcutorture/doc/TINY_RCU.txt @@ -34,7 +34,7 @@ CONFIG_PREEMPT CONFIG_PREEMPT_RCU CONFIG_SMP CONFIG_TINY_RCU -CONFIG_TREE_PREEMPT_RCU +CONFIG_PREEMPT_RCU CONFIG_TREE_RCU All forced by CONFIG_TINY_RCU. diff --git a/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt b/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt index ab6e7b4103ac..f613755a90bd 100644 --- a/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt +++ b/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt @@ -1,5 +1,5 @@ This document gives a brief rationale for the TREE_RCU-related test -cases, a group that includes TREE_PREEMPT_RCU. +cases, a group that includes PREEMPT_RCU. Kconfig Parameters: @@ -14,7 +14,7 @@ CONFIG_NO_HZ_FULL_SYSIDLE -- Do one. CONFIG_PREEMPT -- Do half. (First three and #8.) CONFIG_PROVE_LOCKING -- Do all but two, covering CONFIG_PROVE_RCU and not. CONFIG_PROVE_RCU -- Do all but one under CONFIG_PROVE_LOCKING. -CONFIG_RCU_BOOST -- one of TREE_PREEMPT_RCU. +CONFIG_RCU_BOOST -- one of PREEMPT_RCU. CONFIG_RCU_KTHREAD_PRIO -- set to 2 for _BOOST testing. CONFIG_RCU_CPU_STALL_INFO -- Do one. CONFIG_RCU_CPU_STALL_VERBOSE -- do one with and without _INFO. @@ -27,7 +27,7 @@ CONFIG_RCU_NOCB_CPU_ALL -- Do one. CONFIG_RCU_NOCB_CPU_NONE -- Do one. CONFIG_RCU_NOCB_CPU_ZERO -- Do one. CONFIG_RCU_TRACE -- Do half. -CONFIG_SMP -- Need one !SMP for TREE_PREEMPT_RCU. +CONFIG_SMP -- Need one !SMP for PREEMPT_RCU. RCU-bh: Do one with PREEMPT and one with !PREEMPT. RCU-sched: Do one with PREEMPT but not BOOST. @@ -77,7 +77,7 @@ CONFIG_RCU_CPU_STALL_TIMEOUT CONFIG_RCU_STALL_COMMON - Implied by TREE_RCU and TREE_PREEMPT_RCU. + Implied by TREE_RCU and PREEMPT_RCU. CONFIG_RCU_TORTURE_TEST CONFIG_RCU_TORTURE_TEST_RUNNABLE @@ -88,7 +88,7 @@ CONFIG_RCU_USER_QS Redundant with CONFIG_NO_HZ_FULL. -CONFIG_TREE_PREEMPT_RCU +CONFIG_PREEMPT_RCU CONFIG_TREE_RCU These are controlled by CONFIG_PREEMPT. -- cgit v1.2.3-59-g8ed1b From cdaea91019056fad4f21a697038a84606a6187cc Mon Sep 17 00:00:00 2001 From: Antoine Ténart Date: Wed, 3 Sep 2014 09:48:21 +0200 Subject: Documentation: bindings: add reset bindings docs for Marvell Berlin SoCs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the reset binding documentation to the SoC binding documentation as the reset driver in Marvell Berlin SoC is part of the chip/system control registers. This patch adds the required properties to configure the reset controller. Signed-off-by: Antoine Ténart Acked-by: Philipp Zabel Signed-off-by: Sebastian Hesselbarth --- Documentation/devicetree/bindings/arm/marvell,berlin.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/marvell,berlin.txt b/Documentation/devicetree/bindings/arm/marvell,berlin.txt index 904de5781f44..a99eb9eb14c0 100644 --- a/Documentation/devicetree/bindings/arm/marvell,berlin.txt +++ b/Documentation/devicetree/bindings/arm/marvell,berlin.txt @@ -106,11 +106,21 @@ Required subnode-properties: - groups: a list of strings describing the group names. - function: a string describing the function used to mux the groups. +* Reset controller binding + +A reset controller is part of the chip control registers set. The chip control +node also provides the reset. The register set is not at the same offset between +Berlin SoCs. + +Required property: +- #reset-cells: must be set to 2 + Example: chip: chip-control@ea0000 { compatible = "marvell,berlin2-chip-ctrl"; #clock-cells = <1>; + #reset-cells = <2>; reg = <0xea0000 0x400>; clocks = <&refclk>, <&externaldev 0>; clock-names = "refclk", "video_ext0"; -- cgit v1.2.3-59-g8ed1b From dca145ffaa8d39ea1904491ac81b92b7049372c0 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 27 Oct 2014 21:45:24 -0700 Subject: tcp: allow for bigger reordering level While testing upcoming Yaogong patch (converting out of order queue into an RB tree), I hit the max reordering level of linux TCP stack. Reordering level was limited to 127 for no good reason, and some network setups [1] can easily reach this limit and get limited throughput. Allow a new max limit of 300, and add a sysctl to allow admins to even allow bigger (or lower) values if needed. [1] Aggregation of links, per packet load balancing, fabrics not doing deep packet inspections, alternative TCP congestion modules... Signed-off-by: Eric Dumazet Cc: Yaogong Wang Signed-off-by: David S. Miller --- Documentation/networking/bonding.txt | 7 ++----- Documentation/networking/ip-sysctl.txt | 10 +++++++++- include/linux/tcp.h | 4 ++-- include/net/tcp.h | 4 +--- net/ipv4/sysctl_net_ipv4.c | 7 +++++++ net/ipv4/tcp_input.c | 3 ++- 6 files changed, 23 insertions(+), 12 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt index eeb5b2e97bed..83bf4986baea 100644 --- a/Documentation/networking/bonding.txt +++ b/Documentation/networking/bonding.txt @@ -2230,11 +2230,8 @@ balance-rr: This mode is the only mode that will permit a single It is possible to adjust TCP/IP's congestion limits by altering the net.ipv4.tcp_reordering sysctl parameter. The - usual default value is 3, and the maximum useful value is 127. - For a four interface balance-rr bond, expect that a single - TCP/IP stream will utilize no more than approximately 2.3 - interface's worth of throughput, even after adjusting - tcp_reordering. + usual default value is 3. But keep in mind TCP stack is able + to automatically increase this when it detects reorders. Note that the fraction of packets that will be delivered out of order is highly variable, and is unlikely to be zero. The level diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index 0307e2875f21..9028b879a97b 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -376,9 +376,17 @@ tcp_orphan_retries - INTEGER may consume significant resources. Cf. tcp_max_orphans. tcp_reordering - INTEGER - Maximal reordering of packets in a TCP stream. + Initial reordering level of packets in a TCP stream. + TCP stack can then dynamically adjust flow reordering level + between this initial value and tcp_max_reordering Default: 3 +tcp_max_reordering - INTEGER + Maximal reordering level of packets in a TCP stream. + 300 is a fairly conservative value, but you might increase it + if paths are using per packet load balancing (like bonding rr mode) + Default: 300 + tcp_retrans_collapse - BOOLEAN Bug-to-bug compatibility with some broken printers. On retransmit try to send bigger packets to work around bugs in diff --git a/include/linux/tcp.h b/include/linux/tcp.h index c2dee7deefa8..f566b8567892 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -204,10 +204,10 @@ struct tcp_sock { u16 urg_data; /* Saved octet of OOB data and control flags */ u8 ecn_flags; /* ECN status bits. */ - u8 reordering; /* Packet reordering metric. */ + u8 keepalive_probes; /* num of allowed keep alive probes */ + u32 reordering; /* Packet reordering metric. */ u32 snd_up; /* Urgent pointer */ - u8 keepalive_probes; /* num of allowed keep alive probes */ /* * Options received (usually on last packet, some only on SYN packets). */ diff --git a/include/net/tcp.h b/include/net/tcp.h index c73fc145ee45..3a35b1500359 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -70,9 +70,6 @@ void tcp_time_wait(struct sock *sk, int state, int timeo); /* After receiving this amount of duplicate ACKs fast retransmit starts. */ #define TCP_FASTRETRANS_THRESH 3 -/* Maximal reordering. */ -#define TCP_MAX_REORDERING 127 - /* Maximal number of ACKs sent quickly to accelerate slow-start. */ #define TCP_MAX_QUICKACKS 16U @@ -252,6 +249,7 @@ extern int sysctl_tcp_abort_on_overflow; extern int sysctl_tcp_max_orphans; extern int sysctl_tcp_fack; extern int sysctl_tcp_reordering; +extern int sysctl_tcp_max_reordering; extern int sysctl_tcp_dsack; extern long sysctl_tcp_mem[3]; extern int sysctl_tcp_wmem[3]; diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index b3c53c8b331e..e0ee384a448f 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -495,6 +495,13 @@ static struct ctl_table ipv4_table[] = { .mode = 0644, .proc_handler = proc_dointvec }, + { + .procname = "tcp_max_reordering", + .data = &sysctl_tcp_max_reordering, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec + }, { .procname = "tcp_dsack", .data = &sysctl_tcp_dsack, diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index a12b455928e5..9a18cdd633f3 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -81,6 +81,7 @@ int sysctl_tcp_window_scaling __read_mostly = 1; int sysctl_tcp_sack __read_mostly = 1; int sysctl_tcp_fack __read_mostly = 1; int sysctl_tcp_reordering __read_mostly = TCP_FASTRETRANS_THRESH; +int sysctl_tcp_max_reordering __read_mostly = 300; EXPORT_SYMBOL(sysctl_tcp_reordering); int sysctl_tcp_dsack __read_mostly = 1; int sysctl_tcp_app_win __read_mostly = 31; @@ -833,7 +834,7 @@ static void tcp_update_reordering(struct sock *sk, const int metric, if (metric > tp->reordering) { int mib_idx; - tp->reordering = min(TCP_MAX_REORDERING, metric); + tp->reordering = min(sysctl_tcp_max_reordering, metric); /* This exciting event is worth to be remembered. 8) */ if (ts) -- cgit v1.2.3-59-g8ed1b From 7fd2561e4ebdd070ebba6d3326c4c5b13942323f Mon Sep 17 00:00:00 2001 From: Erik Kline Date: Tue, 28 Oct 2014 18:11:14 +0900 Subject: net: ipv6: Add a sysctl to make optimistic addresses useful candidates Add a sysctl that causes an interface's optimistic addresses to be considered equivalent to other non-deprecated addresses for source address selection purposes. Preferred addresses will still take precedence over optimistic addresses, subject to other ranking in the source address selection algorithm. This is useful where different interfaces are connected to different networks from different ISPs (e.g., a cell network and a home wifi network). The current behaviour complies with RFC 3484/6724, and it makes sense if the host has only one interface, or has multiple interfaces on the same network (same or cooperating administrative domain(s), but not in the multiple distinct networks case. For example, if a mobile device has an IPv6 address on an LTE network and then connects to IPv6-enabled wifi, while the wifi IPv6 address is undergoing DAD, IPv6 connections will try use the wifi default route with the LTE IPv6 address, and will get stuck until they time out. Also, because optimistic nodes can receive frames, issue an RTM_NEWADDR as soon as DAD starts (with the IFA_F_OPTIMSTIC flag appropriately set). A second RTM_NEWADDR is sent if DAD completes (the address flags have changed), otherwise an RTM_DELADDR is sent. Also: add an entry in ip-sysctl.txt for optimistic_dad. Signed-off-by: Erik Kline Acked-by: Lorenzo Colitti Acked-by: Hannes Frederic Sowa Signed-off-by: David S. Miller --- Documentation/networking/ip-sysctl.txt | 13 ++++++++++ include/linux/ipv6.h | 1 + include/uapi/linux/ipv6.h | 1 + net/ipv6/addrconf.c | 46 ++++++++++++++++++++++++++++++++-- 4 files changed, 59 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index 9028b879a97b..368e3251c553 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -1460,6 +1460,19 @@ suppress_frag_ndisc - INTEGER 1 - (default) discard fragmented neighbor discovery packets 0 - allow fragmented neighbor discovery packets +optimistic_dad - BOOLEAN + Whether to perform Optimistic Duplicate Address Detection (RFC 4429). + 0: disabled (default) + 1: enabled + +use_optimistic - BOOLEAN + If enabled, do not classify optimistic addresses as deprecated during + source address selection. Preferred addresses will still be chosen + before optimistic addresses, subject to other ranking in the source + address selection algorithm. + 0: disabled (default) + 1: enabled + icmp/*: ratelimit - INTEGER Limit the maximal rates for sending ICMPv6 packets. diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index ff560537dd61..7121a2e97ce2 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -42,6 +42,7 @@ struct ipv6_devconf { __s32 accept_ra_from_local; #ifdef CONFIG_IPV6_OPTIMISTIC_DAD __s32 optimistic_dad; + __s32 use_optimistic; #endif #ifdef CONFIG_IPV6_MROUTE __s32 mc_forwarding; diff --git a/include/uapi/linux/ipv6.h b/include/uapi/linux/ipv6.h index efa2666f4b8a..e863d088b9a5 100644 --- a/include/uapi/linux/ipv6.h +++ b/include/uapi/linux/ipv6.h @@ -164,6 +164,7 @@ enum { DEVCONF_MLDV2_UNSOLICITED_REPORT_INTERVAL, DEVCONF_SUPPRESS_FRAG_NDISC, DEVCONF_ACCEPT_RA_FROM_LOCAL, + DEVCONF_USE_OPTIMISTIC, DEVCONF_MAX }; diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 50b95b2db87c..8d12b7c7018f 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -1170,6 +1170,9 @@ enum { IPV6_SADDR_RULE_PRIVACY, IPV6_SADDR_RULE_ORCHID, IPV6_SADDR_RULE_PREFIX, +#ifdef CONFIG_IPV6_OPTIMISTIC_DAD + IPV6_SADDR_RULE_NOT_OPTIMISTIC, +#endif IPV6_SADDR_RULE_MAX }; @@ -1197,6 +1200,15 @@ static inline int ipv6_saddr_preferred(int type) return 0; } +static inline bool ipv6_use_optimistic_addr(struct inet6_dev *idev) +{ +#ifdef CONFIG_IPV6_OPTIMISTIC_DAD + return idev && idev->cnf.optimistic_dad && idev->cnf.use_optimistic; +#else + return false; +#endif +} + static int ipv6_get_saddr_eval(struct net *net, struct ipv6_saddr_score *score, struct ipv6_saddr_dst *dst, @@ -1257,10 +1269,16 @@ static int ipv6_get_saddr_eval(struct net *net, score->scopedist = ret; break; case IPV6_SADDR_RULE_PREFERRED: + { /* Rule 3: Avoid deprecated and optimistic addresses */ + u8 avoid = IFA_F_DEPRECATED; + + if (!ipv6_use_optimistic_addr(score->ifa->idev)) + avoid |= IFA_F_OPTIMISTIC; ret = ipv6_saddr_preferred(score->addr_type) || - !(score->ifa->flags & (IFA_F_DEPRECATED|IFA_F_OPTIMISTIC)); + !(score->ifa->flags & avoid); break; + } #ifdef CONFIG_IPV6_MIP6 case IPV6_SADDR_RULE_HOA: { @@ -1306,6 +1324,14 @@ static int ipv6_get_saddr_eval(struct net *net, ret = score->ifa->prefix_len; score->matchlen = ret; break; +#ifdef CONFIG_IPV6_OPTIMISTIC_DAD + case IPV6_SADDR_RULE_NOT_OPTIMISTIC: + /* Optimistic addresses still have lower precedence than other + * preferred addresses. + */ + ret = !(score->ifa->flags & IFA_F_OPTIMISTIC); + break; +#endif default: ret = 0; } @@ -3222,8 +3248,15 @@ static void addrconf_dad_begin(struct inet6_ifaddr *ifp) * Optimistic nodes can start receiving * Frames right away */ - if (ifp->flags & IFA_F_OPTIMISTIC) + if (ifp->flags & IFA_F_OPTIMISTIC) { ip6_ins_rt(ifp->rt); + if (ipv6_use_optimistic_addr(idev)) { + /* Because optimistic nodes can use this address, + * notify listeners. If DAD fails, RTM_DELADDR is sent. + */ + ipv6_ifa_notify(RTM_NEWADDR, ifp); + } + } addrconf_dad_kick(ifp); out: @@ -4330,6 +4363,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf, array[DEVCONF_ACCEPT_SOURCE_ROUTE] = cnf->accept_source_route; #ifdef CONFIG_IPV6_OPTIMISTIC_DAD array[DEVCONF_OPTIMISTIC_DAD] = cnf->optimistic_dad; + array[DEVCONF_USE_OPTIMISTIC] = cnf->use_optimistic; #endif #ifdef CONFIG_IPV6_MROUTE array[DEVCONF_MC_FORWARDING] = cnf->mc_forwarding; @@ -5155,6 +5189,14 @@ static struct addrconf_sysctl_table .proc_handler = proc_dointvec, }, + { + .procname = "use_optimistic", + .data = &ipv6_devconf.use_optimistic, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + + }, #endif #ifdef CONFIG_IPV6_MROUTE { -- cgit v1.2.3-59-g8ed1b From 1f33c41c03daece85a84b8dcea5733f3efe3e2b0 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 29 Sep 2014 16:08:21 -0700 Subject: seq_file: Rename seq_overflow() to seq_has_overflowed() and make public The return values of seq_printf/puts/putc are frequently misused. Start down a path to remove all the return value uses of these functions. Move the seq_overflow() to a global inlined function called seq_has_overflowed() that can be used by the users of seq_file() calls. Update the documentation to not show return types for seq_printf et al. Add a description of seq_has_overflowed(). Link: http://lkml.kernel.org/p/848ac7e3d1c31cddf638a8526fa3c59fa6fdeb8a.1412031505.git.joe@perches.com Cc: Al Viro Signed-off-by: Joe Perches [ Reworked the original patch from Joe ] Signed-off-by: Steven Rostedt --- Documentation/filesystems/seq_file.txt | 22 +++++++++++++--------- fs/seq_file.c | 15 ++------------- include/linux/seq_file.h | 15 +++++++++++++++ 3 files changed, 30 insertions(+), 22 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/seq_file.txt b/Documentation/filesystems/seq_file.txt index 8ea3e90ace07..b797ed38de46 100644 --- a/Documentation/filesystems/seq_file.txt +++ b/Documentation/filesystems/seq_file.txt @@ -180,23 +180,19 @@ output must be passed to the seq_file code. Some utility functions have been defined which make this task easy. Most code will simply use seq_printf(), which works pretty much like -printk(), but which requires the seq_file pointer as an argument. It is -common to ignore the return value from seq_printf(), but a function -producing complicated output may want to check that value and quit if -something non-zero is returned; an error return means that the seq_file -buffer has been filled and further output will be discarded. +printk(), but which requires the seq_file pointer as an argument. For straight character output, the following functions may be used: - int seq_putc(struct seq_file *m, char c); - int seq_puts(struct seq_file *m, const char *s); - int seq_escape(struct seq_file *m, const char *s, const char *esc); + seq_putc(struct seq_file *m, char c); + seq_puts(struct seq_file *m, const char *s); + seq_escape(struct seq_file *m, const char *s, const char *esc); The first two output a single character and a string, just like one would expect. seq_escape() is like seq_puts(), except that any character in s which is in the string esc will be represented in octal form in the output. -There is also a pair of functions for printing filenames: +There are also a pair of functions for printing filenames: int seq_path(struct seq_file *m, struct path *path, char *esc); int seq_path_root(struct seq_file *m, struct path *path, @@ -209,6 +205,14 @@ root is desired, it can be used with seq_path_root(). Note that, if it turns out that path cannot be reached from root, the value of root will be changed in seq_file_root() to a root which *does* work. +A function producing complicated output may want to check + bool seq_has_overflowed(struct seq_file *m); +and avoid further seq_ calls if true is returned. + +A true return from seq_has_overflowed means that the seq_file buffer will +be discarded and the seq_show function will attempt to allocate a larger +buffer and retry printing. + Making it all work diff --git a/fs/seq_file.c b/fs/seq_file.c index 3857b720cb1b..353948ba1c5b 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c @@ -16,17 +16,6 @@ #include #include - -/* - * seq_files have a buffer which can may overflow. When this happens a larger - * buffer is reallocated and all the data will be printed again. - * The overflow state is true when m->count == m->size. - */ -static bool seq_overflow(struct seq_file *m) -{ - return m->count == m->size; -} - static void seq_set_overflow(struct seq_file *m) { m->count = m->size; @@ -124,7 +113,7 @@ static int traverse(struct seq_file *m, loff_t offset) error = 0; m->count = 0; } - if (seq_overflow(m)) + if (seq_has_overflowed(m)) goto Eoverflow; if (pos + m->count > offset) { m->from = offset - pos; @@ -267,7 +256,7 @@ Fill: break; } err = m->op->show(m, p); - if (seq_overflow(m) || err) { + if (seq_has_overflowed(m) || err) { m->count = offs; if (likely(err <= 0)) break; diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h index 52e0097f61f0..cf6a9daaaf6d 100644 --- a/include/linux/seq_file.h +++ b/include/linux/seq_file.h @@ -42,6 +42,21 @@ struct seq_operations { #define SEQ_SKIP 1 +/** + * seq_has_overflowed - check if the buffer has overflowed + * @m: the seq_file handle + * + * seq_files have a buffer which may overflow. When this happens a larger + * buffer is reallocated and all the data will be printed again. + * The overflow state is true when m->count == m->size. + * + * Returns true if the buffer received more than it can hold. + */ +static inline bool seq_has_overflowed(struct seq_file *m) +{ + return m->count == m->size; +} + /** * seq_get_buf - get buffer to write arbitrary data to * @m: the seq_file handle -- cgit v1.2.3-59-g8ed1b From a47959fbd5808890963fe8475a7c436bfd60d8c3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 26 Sep 2014 15:37:38 -0300 Subject: [media] Documentation: FE_SET_PROPERTY requires R/W FE_SET_PROPERTY requires to open the devnode on R/W mode, or otherwise it will fail. Document it. Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/dvb/dvbproperty.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/DocBook/media/dvb/dvbproperty.xml b/Documentation/DocBook/media/dvb/dvbproperty.xml index 948ddaab592e..3018564ddfd9 100644 --- a/Documentation/DocBook/media/dvb/dvbproperty.xml +++ b/Documentation/DocBook/media/dvb/dvbproperty.xml @@ -120,8 +120,8 @@ struct dtv_properties { -This ioctl call sets one or more frontend properties. This call only - requires read-only access to the device. +This ioctl call sets one or more frontend properties. This call + requires read/write access to the device. SYNOPSIS -- cgit v1.2.3-59-g8ed1b From 438f4e2801d730442d6fc36ab2b265c4b54cff8b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 30 Oct 2014 12:44:00 +0100 Subject: ALSA: doc: Add ASoC codes into API documentation Signed-off-by: Takashi Iwai --- Documentation/DocBook/alsa-driver-api.tmpl | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/DocBook/alsa-driver-api.tmpl b/Documentation/DocBook/alsa-driver-api.tmpl index 7bec270e2494..b2d2c3b74fb0 100644 --- a/Documentation/DocBook/alsa-driver-api.tmpl +++ b/Documentation/DocBook/alsa-driver-api.tmpl @@ -104,13 +104,30 @@ !Iinclude/sound/compress_driver.h + ASoC + ASoC Core API +!Iinclude/sound/soc.h +!Esound/soc/soc-core.c +!Esound/soc/soc-cache.c +!Esound/soc/soc-devres.c +!Esound/soc/soc-io.c +!Esound/soc/soc-pcm.c + + ASoC DAPM API +!Esound/soc/soc-dapm.c + + ASoC DMA Engine API +!Esound/soc/soc-generic-dmaengine-pcm.c + + Miscellaneous Functions Hardware-Dependent Devices API !Esound/core/hwdep.c Jack Abstraction Layer API -!Esound/core/jack.c !Iinclude/sound/jack.h +!Esound/core/jack.c +!Esound/soc/soc-jack.c ISA DMA Helpers !Esound/core/isadma.c -- cgit v1.2.3-59-g8ed1b From 67faa6ebd7fc0a811f6c1f3e3c113571953489ee Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 30 Oct 2014 15:37:37 +0100 Subject: ALSA: doc: Fix missing "I" for kerneldoc inclusion Fixes: 90446d0746c3 ('ALSA: doc: Add missing headers and compress stuff to alsa-driver-api.tmpl') Signed-off-by: Takashi Iwai --- Documentation/DocBook/alsa-driver-api.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/DocBook/alsa-driver-api.tmpl b/Documentation/DocBook/alsa-driver-api.tmpl index b2d2c3b74fb0..71f9246127ec 100644 --- a/Documentation/DocBook/alsa-driver-api.tmpl +++ b/Documentation/DocBook/alsa-driver-api.tmpl @@ -57,7 +57,7 @@ !Esound/core/pcm.c !Esound/core/pcm_lib.c !Esound/core/pcm_native.c -!include/sound/pcm.h +!Iinclude/sound/pcm.h PCM Format Helpers !Esound/core/pcm_misc.c -- cgit v1.2.3-59-g8ed1b From 2071d0968e564b4b4a11d36dc58de6e57188edd4 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Wed, 29 Oct 2014 17:13:14 +0900 Subject: Documentation: gpio: guidelines for bindings Now that ACPI supports named GPIO properties, either through ACPI 5.1 or the per-driver ACPI GPIO mappings, we can be more narrow about the way GPIOs should be specified in Device Tree bindings. This patch updates the GPIO DT bindings documentation to highlight the following rules for new GPIO bindings: - All new bindings must have a meaningful name (e.g. the "gpios" property must not be used) - The only suffix allowed is "-gpios", no matter the number of descriptors in the property - GPIOs can only be grouped under the same property when they serve the same purpose, a case that should remain exceptional (e.g. bit-banged data lines). Signed-off-by: Alexandre Courbot Cc: Rafael J. Wysocki Acked-by: Arnd Bergmann Reviewed-by: Mika Westerberg Signed-off-by: Linus Walleij --- Documentation/devicetree/bindings/gpio/gpio.txt | 40 ++++++++++++++++--------- 1 file changed, 26 insertions(+), 14 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/gpio/gpio.txt b/Documentation/devicetree/bindings/gpio/gpio.txt index 3fb8f53071b8..b9bd1d64cfa6 100644 --- a/Documentation/devicetree/bindings/gpio/gpio.txt +++ b/Documentation/devicetree/bindings/gpio/gpio.txt @@ -13,13 +13,22 @@ properties, each containing a 'gpio-list': gpio-specifier : Array of #gpio-cells specifying specific gpio (controller specific) -GPIO properties should be named "[-]gpios". The exact -meaning of each gpios property must be documented in the device tree -binding for each device. +GPIO properties should be named "[-]gpios", with being the purpose +of this GPIO for the device. While a non-existent is considered valid +for compatibility reasons (resolving to the "gpios" property), it is not allowed +for new bindings. -For example, the following could be used to describe GPIO pins used -as chip select lines; with chip selects 0, 1 and 3 populated, and chip -select 2 left empty: +GPIO properties can contain one or more GPIO phandles, but only in exceptional +cases should they contain more than one. If your device uses several GPIOs with +distinct functions, reference each of them under its own property, giving it a +meaningful name. The only case where an array of GPIOs is accepted is when +several GPIOs serve the same function (e.g. a parallel data line). + +The exact purpose of each gpios property must be documented in the device tree +binding of the device. + +The following example could be used to describe GPIO pins used as device enable +and bit-banged data signals: gpio1: gpio1 { gpio-controller @@ -30,10 +39,12 @@ select 2 left empty: #gpio-cells = <1>; }; [...] - chipsel-gpios = <&gpio1 12 0>, - <&gpio1 13 0>, - <0>, /* holes are permitted, means no GPIO 2 */ - <&gpio2 2>; + + enable-gpios = <&gpio2 2>; + data-gpios = <&gpio1 12 0>, + <&gpio1 13 0>, + <&gpio1 14 0>, + <&gpio1 15 0>; Note that gpio-specifier length is controller dependent. In the above example, &gpio1 uses 2 cells to specify a gpio, while &gpio2 @@ -42,16 +53,17 @@ only uses one. gpio-specifier may encode: bank, pin position inside the bank, whether pin is open-drain and whether pin is logically inverted. Exact meaning of each specifier cell is controller specific, and must -be documented in the device tree binding for the device. +be documented in the device tree binding for the device. Use the macros +defined in include/dt-bindings/gpio/gpio.h whenever possible: Example of a node using GPIOs: node { - gpios = <&qe_pio_e 18 0>; + enable-gpios = <&qe_pio_e 18 GPIO_ACTIVE_HIGH>; }; -In this example gpio-specifier is "18 0" and encodes GPIO pin number, -and GPIO flags as accepted by the "qe_pio_e" gpio-controller. +GPIO_ACTIVE_HIGH is 0, so in this example gpio-specifier is "18 0" and encodes +GPIO pin number, and GPIO flags as accepted by the "qe_pio_e" gpio-controller. 1.1) GPIO specifier best practices ---------------------------------- -- cgit v1.2.3-59-g8ed1b From 7cfdaddc4d1f5e673ded29e659726a8df7f2dd39 Mon Sep 17 00:00:00 2001 From: Jonathan Richardson Date: Fri, 15 Aug 2014 13:51:50 -0700 Subject: dt-bindings: Document Broadcom Cygnus SoC and clocks Reviewed-by: Arun Parameswaran Tested-by: Jonathan Richardson Reviewed-by: JD (Jiandong) Zheng Reviewed-by: Ray Jui Signed-off-by: Scott Branden --- .../devicetree/bindings/arm/bcm/cygnus.txt | 31 ++++++++++++++++++++ .../devicetree/bindings/clock/bcm-cygnus-clock.txt | 34 ++++++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/bcm/cygnus.txt create mode 100644 Documentation/devicetree/bindings/clock/bcm-cygnus-clock.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/bcm/cygnus.txt b/Documentation/devicetree/bindings/arm/bcm/cygnus.txt new file mode 100644 index 000000000000..4c77169bb534 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/bcm/cygnus.txt @@ -0,0 +1,31 @@ +Broadcom Cygnus device tree bindings +------------------------------------ + + +Boards with Cygnus SoCs shall have the following properties: + +Required root node property: + +BCM11300 +compatible = "brcm,bcm11300", "brcm,cygnus"; + +BCM11320 +compatible = "brcm,bcm11320", "brcm,cygnus"; + +BCM11350 +compatible = "brcm,bcm11350", "brcm,cygnus"; + +BCM11360 +compatible = "brcm,bcm11360", "brcm,cygnus"; + +BCM58300 +compatible = "brcm,bcm58300", "brcm,cygnus"; + +BCM58302 +compatible = "brcm,bcm58302", "brcm,cygnus"; + +BCM58303 +compatible = "brcm,bcm58303", "brcm,cygnus"; + +BCM58305 +compatible = "brcm,bcm58305", "brcm,cygnus"; diff --git a/Documentation/devicetree/bindings/clock/bcm-cygnus-clock.txt b/Documentation/devicetree/bindings/clock/bcm-cygnus-clock.txt new file mode 100644 index 000000000000..00d26edec8bc --- /dev/null +++ b/Documentation/devicetree/bindings/clock/bcm-cygnus-clock.txt @@ -0,0 +1,34 @@ +Broadcom Cygnus Clocks + +This binding uses the common clock binding: +Documentation/devicetree/bindings/clock/clock-bindings.txt + +Currently various "fixed" clocks are declared for peripheral drivers that use +the common clock framework to reference their core clocks. Proper support of +these clocks will be added later + +Device tree example: + + clocks { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + osc: oscillator { + compatible = "fixed-clock"; + #clock-cells = <1>; + clock-frequency = <25000000>; + }; + + apb_clk: apb_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <1000000000>; + }; + + periph_clk: periph_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <500000000>; + }; + }; -- cgit v1.2.3-59-g8ed1b From 6233fe38048a80a9fa111ddb166ce9e8e0f5f1b3 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 27 Oct 2014 10:11:58 +0900 Subject: clk: samsung: Document binding for Exynos4415 clock controller This patch adds DT binding documentation for Exynos4415 SoC system clock controllers. Signed-off-by: Chanwoo Choi Acked-by: Kyungmin Park Signed-off-by: Sylwester Nawrocki --- .../devicetree/bindings/clock/exynos4415-clock.txt | 38 ++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/exynos4415-clock.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/exynos4415-clock.txt b/Documentation/devicetree/bindings/clock/exynos4415-clock.txt new file mode 100644 index 000000000000..847d98bae8cf --- /dev/null +++ b/Documentation/devicetree/bindings/clock/exynos4415-clock.txt @@ -0,0 +1,38 @@ +* Samsung Exynos4415 Clock Controller + +The Exynos4415 clock controller generates and supplies clock to various +consumer devices within the Exynos4415 SoC. + +Required properties: + +- compatible: should be one of the following: + - "samsung,exynos4415-cmu" - for the main system clocks controller + (CMU_LEFTBUS, CMU_RIGHTBUS, CMU_TOP, CMU_CPU clock domains). + - "samsung,exynos4415-cmu-dmc" - for the Exynos4415 SoC DRAM Memory + Controller (DMC) domain clock controller. + +- reg: physical base address of the controller and length of memory mapped + region. + +- #clock-cells: should be 1. + +Each clock is assigned an identifier and client nodes can use this identifier +to specify the clock which they consume. + +All available clocks are defined as preprocessor macros in +dt-bindings/clock/exynos4415.h header and can be used in device +tree sources. + +Example 1: An example of a clock controller node is listed below. + + cmu: clock-controller@10030000 { + compatible = "samsung,exynos4415-cmu"; + reg = <0x10030000 0x18000>; + #clock-cells = <1>; + }; + + cmu-dmc: clock-controller@105C0000 { + compatible = "samsung,exynos4415-cmu-dmc"; + reg = <0x105C0000 0x3000>; + #clock-cells = <1>; + }; -- cgit v1.2.3-59-g8ed1b From 06745729c48e3677a64db63481184cc7aef1ea69 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Wed, 29 Oct 2014 10:45:02 -0700 Subject: dsa: Add new optional devicetree property to describe EEPROM size The dsa core now supports reading from and writing to a switch EEPROM if connected. Describe optional devicetree property indicating that an EEPROM is present and its size. Signed-off-by: Guenter Roeck Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/dsa/dsa.txt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/dsa/dsa.txt b/Documentation/devicetree/bindings/net/dsa/dsa.txt index a62c889aafca..e124847443f8 100644 --- a/Documentation/devicetree/bindings/net/dsa/dsa.txt +++ b/Documentation/devicetree/bindings/net/dsa/dsa.txt @@ -10,7 +10,7 @@ Required properties: - dsa,ethernet : Should be a phandle to a valid Ethernet device node - dsa,mii-bus : Should be a phandle to a valid MDIO bus device node -Optionnal properties: +Optional properties: - interrupts : property with a value describing the switch interrupt number (not supported by the driver) @@ -23,6 +23,13 @@ Each of these switch child nodes should have the following required properties: - #address-cells : Must be 1 - #size-cells : Must be 0 +A switch child node has the following optional property: + +- eeprom-length : Set to the length of an EEPROM connected to the + switch. Must be set if the switch can not detect + the presence and/or size of a connected EEPROM, + otherwise optional. + A switch may have multiple "port" children nodes Each port children node must have the following mandatory properties: -- cgit v1.2.3-59-g8ed1b From 532abc3a4a4502e13315d246c545d7567c80b03e Mon Sep 17 00:00:00 2001 From: Naveen Krishna Ch Date: Mon, 22 Sep 2014 10:17:04 +0530 Subject: clk: samsung: add initial clock support for Exynos7 SoC Add initial clock support for Exynos7 SoC which is required to bring up platforms based on Exynos7. Signed-off-by: Naveen Krishna Ch Signed-off-by: Abhilash Kesavan Reviewed-by: Thomas Abraham Tested-by: Thomas Abraham Signed-off-by: Sylwester Nawrocki --- .../devicetree/bindings/clock/exynos7-clock.txt | 67 ++++ drivers/clk/samsung/Makefile | 1 + drivers/clk/samsung/clk-exynos7.c | 425 +++++++++++++++++++++ include/dt-bindings/clock/exynos7-clk.h | 49 +++ 4 files changed, 542 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/exynos7-clock.txt create mode 100644 drivers/clk/samsung/clk-exynos7.c create mode 100644 include/dt-bindings/clock/exynos7-clk.h (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/exynos7-clock.txt b/Documentation/devicetree/bindings/clock/exynos7-clock.txt new file mode 100644 index 000000000000..789f76132a85 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/exynos7-clock.txt @@ -0,0 +1,67 @@ +* Samsung Exynos7 Clock Controller + +Exynos7 clock controller has various blocks which are instantiated +independently from the device-tree. These clock controllers +generate and supply clocks to various hardware blocks within +the SoC. + +Each clock is assigned an identifier and client nodes can use +this identifier to specify the clock which they consume. All +available clocks are defined as preprocessor macros in +dt-bindings/clock/exynos7-clk.h header and can be used in +device tree sources. + +External clocks: + +There are several clocks that are generated outside the SoC. It +is expected that they are defined using standard clock bindings +with following clock-output-names: + + - "fin_pll" - PLL input clock from XXTI + +Required Properties for Clock Controller: + + - compatible: clock controllers will use one of the following + compatible strings to indicate the clock controller + functionality. + + - "samsung,exynos7-clock-topc" + - "samsung,exynos7-clock-top0" + - "samsung,exynos7-clock-peric0" + - "samsung,exynos7-clock-peric1" + - "samsung,exynos7-clock-peris" + + - reg: physical base address of the controller and the length of + memory mapped region. + + - #clock-cells: should be 1. + + - clocks: list of clock identifiers which are fed as the input to + the given clock controller. Please refer the next section to + find the input clocks for a given controller. + +- clock-names: list of names of clocks which are fed as the input + to the given clock controller. + +Input clocks for top0 clock controller: + - fin_pll + - dout_sclk_bus0_pll + - dout_sclk_bus1_pll + - dout_sclk_cc_pll + - dout_sclk_mfc_pll + +Input clocks for peric0 clock controller: + - fin_pll + - dout_aclk_peric0_66 + - sclk_uart0 + +Input clocks for peric1 clock controller: + - fin_pll + - dout_aclk_peric1_66 + - sclk_uart1 + - sclk_uart2 + - sclk_uart3 + +Input clocks for peris clock controller: + - fin_pll + - dout_aclk_peris_66 diff --git a/drivers/clk/samsung/Makefile b/drivers/clk/samsung/Makefile index d8535e6df1db..006c6f294310 100644 --- a/drivers/clk/samsung/Makefile +++ b/drivers/clk/samsung/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_SOC_EXYNOS5420) += clk-exynos5420.o obj-$(CONFIG_SOC_EXYNOS5440) += clk-exynos5440.o obj-$(CONFIG_ARCH_EXYNOS) += clk-exynos-audss.o obj-$(CONFIG_ARCH_EXYNOS) += clk-exynos-clkout.o +obj-$(CONFIG_ARCH_EXYNOS7) += clk-exynos7.o obj-$(CONFIG_S3C2410_COMMON_CLK)+= clk-s3c2410.o obj-$(CONFIG_S3C2410_COMMON_DCLK)+= clk-s3c2410-dclk.o obj-$(CONFIG_S3C2412_COMMON_CLK)+= clk-s3c2412.o diff --git a/drivers/clk/samsung/clk-exynos7.c b/drivers/clk/samsung/clk-exynos7.c new file mode 100644 index 000000000000..54206d4d408a --- /dev/null +++ b/drivers/clk/samsung/clk-exynos7.c @@ -0,0 +1,425 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * Author: Naveen Krishna Ch + * + * 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 "clk.h" +#include + +/* Register Offset definitions for CMU_TOPC (0x10570000) */ +#define CC_PLL_LOCK 0x0000 +#define BUS0_PLL_LOCK 0x0004 +#define BUS1_DPLL_LOCK 0x0008 +#define MFC_PLL_LOCK 0x000C +#define AUD_PLL_LOCK 0x0010 +#define CC_PLL_CON0 0x0100 +#define BUS0_PLL_CON0 0x0110 +#define BUS1_DPLL_CON0 0x0120 +#define MFC_PLL_CON0 0x0130 +#define AUD_PLL_CON0 0x0140 +#define MUX_SEL_TOPC0 0x0200 +#define MUX_SEL_TOPC1 0x0204 +#define MUX_SEL_TOPC3 0x020C +#define DIV_TOPC1 0x0604 +#define DIV_TOPC3 0x060C + +static struct samsung_fixed_factor_clock topc_fixed_factor_clks[] __initdata = { + FFACTOR(0, "ffac_topc_bus0_pll_div2", "mout_bus0_pll_ctrl", 1, 2, 0), + FFACTOR(0, "ffac_topc_bus0_pll_div4", + "ffac_topc_bus0_pll_div2", 1, 2, 0), + FFACTOR(0, "ffac_topc_bus1_pll_div2", "mout_bus1_pll_ctrl", 1, 2, 0), + FFACTOR(0, "ffac_topc_cc_pll_div2", "mout_cc_pll_ctrl", 1, 2, 0), + FFACTOR(0, "ffac_topc_mfc_pll_div2", "mout_mfc_pll_ctrl", 1, 2, 0), +}; + +/* List of parent clocks for Muxes in CMU_TOPC */ +PNAME(mout_bus0_pll_ctrl_p) = { "fin_pll", "fout_bus0_pll" }; +PNAME(mout_bus1_pll_ctrl_p) = { "fin_pll", "fout_bus1_pll" }; +PNAME(mout_cc_pll_ctrl_p) = { "fin_pll", "fout_cc_pll" }; +PNAME(mout_mfc_pll_ctrl_p) = { "fin_pll", "fout_mfc_pll" }; + +PNAME(mout_topc_group2) = { "mout_sclk_bus0_pll_cmuc", + "mout_sclk_bus1_pll_cmuc", "mout_sclk_cc_pll_cmuc", + "mout_sclk_mfc_pll_cmuc" }; + +PNAME(mout_sclk_bus0_pll_cmuc_p) = { "mout_bus0_pll_ctrl", + "ffac_topc_bus0_pll_div2", "ffac_topc_bus0_pll_div4"}; +PNAME(mout_sclk_bus1_pll_cmuc_p) = { "mout_bus1_pll_ctrl", + "ffac_topc_bus1_pll_div2"}; +PNAME(mout_sclk_cc_pll_cmuc_p) = { "mout_cc_pll_ctrl", + "ffac_topc_cc_pll_div2"}; +PNAME(mout_sclk_mfc_pll_cmuc_p) = { "mout_mfc_pll_ctrl", + "ffac_topc_mfc_pll_div2"}; + + +PNAME(mout_sclk_bus0_pll_out_p) = {"mout_bus0_pll_ctrl", + "ffac_topc_bus0_pll_div2"}; + +static unsigned long topc_clk_regs[] __initdata = { + CC_PLL_LOCK, + BUS0_PLL_LOCK, + BUS1_DPLL_LOCK, + MFC_PLL_LOCK, + AUD_PLL_LOCK, + CC_PLL_CON0, + BUS0_PLL_CON0, + BUS1_DPLL_CON0, + MFC_PLL_CON0, + AUD_PLL_CON0, + MUX_SEL_TOPC0, + MUX_SEL_TOPC1, + MUX_SEL_TOPC3, + DIV_TOPC1, + DIV_TOPC3, +}; + +static struct samsung_mux_clock topc_mux_clks[] __initdata = { + MUX(0, "mout_bus0_pll_ctrl", mout_bus0_pll_ctrl_p, MUX_SEL_TOPC0, 0, 1), + MUX(0, "mout_bus1_pll_ctrl", mout_bus1_pll_ctrl_p, MUX_SEL_TOPC0, 4, 1), + MUX(0, "mout_cc_pll_ctrl", mout_cc_pll_ctrl_p, MUX_SEL_TOPC0, 8, 1), + MUX(0, "mout_mfc_pll_ctrl", mout_mfc_pll_ctrl_p, MUX_SEL_TOPC0, 12, 1), + + MUX(0, "mout_sclk_bus0_pll_cmuc", mout_sclk_bus0_pll_cmuc_p, + MUX_SEL_TOPC0, 16, 2), + MUX(0, "mout_sclk_bus1_pll_cmuc", mout_sclk_bus1_pll_cmuc_p, + MUX_SEL_TOPC0, 20, 1), + MUX(0, "mout_sclk_cc_pll_cmuc", mout_sclk_cc_pll_cmuc_p, + MUX_SEL_TOPC0, 24, 1), + MUX(0, "mout_sclk_mfc_pll_cmuc", mout_sclk_mfc_pll_cmuc_p, + MUX_SEL_TOPC0, 28, 1), + + MUX(0, "mout_sclk_bus0_pll_out", mout_sclk_bus0_pll_out_p, + MUX_SEL_TOPC1, 16, 1), + + MUX(0, "mout_aclk_peris_66", mout_topc_group2, MUX_SEL_TOPC3, 24, 2), +}; + +static struct samsung_div_clock topc_div_clks[] __initdata = { + DIV(DOUT_ACLK_PERIS, "dout_aclk_peris_66", "mout_aclk_peris_66", + DIV_TOPC1, 24, 4), + + DIV(DOUT_SCLK_BUS0_PLL, "dout_sclk_bus0_pll", "mout_sclk_bus0_pll_out", + DIV_TOPC3, 0, 3), + DIV(DOUT_SCLK_BUS1_PLL, "dout_sclk_bus1_pll", "mout_bus1_pll_ctrl", + DIV_TOPC3, 8, 3), + DIV(DOUT_SCLK_CC_PLL, "dout_sclk_cc_pll", "mout_cc_pll_ctrl", + DIV_TOPC3, 12, 3), + DIV(DOUT_SCLK_MFC_PLL, "dout_sclk_mfc_pll", "mout_mfc_pll_ctrl", + DIV_TOPC3, 16, 3), +}; + +static struct samsung_pll_clock topc_pll_clks[] __initdata = { + PLL(pll_1451x, 0, "fout_bus0_pll", "fin_pll", BUS0_PLL_LOCK, + BUS0_PLL_CON0, NULL), + PLL(pll_1452x, 0, "fout_cc_pll", "fin_pll", CC_PLL_LOCK, + CC_PLL_CON0, NULL), + PLL(pll_1452x, 0, "fout_bus1_pll", "fin_pll", BUS1_DPLL_LOCK, + BUS1_DPLL_CON0, NULL), + PLL(pll_1452x, 0, "fout_mfc_pll", "fin_pll", MFC_PLL_LOCK, + MFC_PLL_CON0, NULL), + PLL(pll_1460x, 0, "fout_aud_pll", "fin_pll", AUD_PLL_LOCK, + AUD_PLL_CON0, NULL), +}; + +static struct samsung_cmu_info topc_cmu_info __initdata = { + .pll_clks = topc_pll_clks, + .nr_pll_clks = ARRAY_SIZE(topc_pll_clks), + .mux_clks = topc_mux_clks, + .nr_mux_clks = ARRAY_SIZE(topc_mux_clks), + .div_clks = topc_div_clks, + .nr_div_clks = ARRAY_SIZE(topc_div_clks), + .fixed_factor_clks = topc_fixed_factor_clks, + .nr_fixed_factor_clks = ARRAY_SIZE(topc_fixed_factor_clks), + .nr_clk_ids = TOPC_NR_CLK, + .clk_regs = topc_clk_regs, + .nr_clk_regs = ARRAY_SIZE(topc_clk_regs), +}; + +static void __init exynos7_clk_topc_init(struct device_node *np) +{ + samsung_cmu_register_one(np, &topc_cmu_info); +} + +CLK_OF_DECLARE(exynos7_clk_topc, "samsung,exynos7-clock-topc", + exynos7_clk_topc_init); + +/* Register Offset definitions for CMU_TOP0 (0x105D0000) */ +#define MUX_SEL_TOP00 0x0200 +#define MUX_SEL_TOP01 0x0204 +#define MUX_SEL_TOP03 0x020C +#define MUX_SEL_TOP0_PERIC3 0x023C +#define DIV_TOP03 0x060C +#define DIV_TOP0_PERIC3 0x063C +#define ENABLE_SCLK_TOP0_PERIC3 0x0A3C + +/* List of parent clocks for Muxes in CMU_TOP0 */ +PNAME(mout_bus0_pll_p) = { "fin_pll", "dout_sclk_bus0_pll" }; +PNAME(mout_bus1_pll_p) = { "fin_pll", "dout_sclk_bus1_pll" }; +PNAME(mout_cc_pll_p) = { "fin_pll", "dout_sclk_cc_pll" }; +PNAME(mout_mfc_pll_p) = { "fin_pll", "dout_sclk_mfc_pll" }; + +PNAME(mout_top0_half_bus0_pll_p) = {"mout_top0_bus0_pll", + "ffac_top0_bus0_pll_div2"}; +PNAME(mout_top0_half_bus1_pll_p) = {"mout_top0_bus1_pll", + "ffac_top0_bus1_pll_div2"}; +PNAME(mout_top0_half_cc_pll_p) = {"mout_top0_cc_pll", + "ffac_top0_cc_pll_div2"}; +PNAME(mout_top0_half_mfc_pll_p) = {"mout_top0_mfc_pll", + "ffac_top0_mfc_pll_div2"}; + +PNAME(mout_top0_group1) = {"mout_top0_half_bus0_pll", + "mout_top0_half_bus1_pll", "mout_top0_half_cc_pll", + "mout_top0_half_mfc_pll"}; + +static unsigned long top0_clk_regs[] __initdata = { + MUX_SEL_TOP00, + MUX_SEL_TOP01, + MUX_SEL_TOP03, + MUX_SEL_TOP0_PERIC3, + DIV_TOP03, + DIV_TOP0_PERIC3, + ENABLE_SCLK_TOP0_PERIC3, +}; + +static struct samsung_mux_clock top0_mux_clks[] __initdata = { + MUX(0, "mout_top0_mfc_pll", mout_mfc_pll_p, MUX_SEL_TOP00, 4, 1), + MUX(0, "mout_top0_cc_pll", mout_cc_pll_p, MUX_SEL_TOP00, 8, 1), + MUX(0, "mout_top0_bus1_pll", mout_bus1_pll_p, MUX_SEL_TOP00, 12, 1), + MUX(0, "mout_top0_bus0_pll", mout_bus0_pll_p, MUX_SEL_TOP00, 16, 1), + + MUX(0, "mout_top0_half_mfc_pll", mout_top0_half_mfc_pll_p, + MUX_SEL_TOP01, 4, 1), + MUX(0, "mout_top0_half_cc_pll", mout_top0_half_cc_pll_p, + MUX_SEL_TOP01, 8, 1), + MUX(0, "mout_top0_half_bus1_pll", mout_top0_half_bus1_pll_p, + MUX_SEL_TOP01, 12, 1), + MUX(0, "mout_top0_half_bus0_pll", mout_top0_half_bus0_pll_p, + MUX_SEL_TOP01, 16, 1), + + MUX(0, "mout_aclk_peric1_66", mout_top0_group1, MUX_SEL_TOP03, 12, 2), + MUX(0, "mout_aclk_peric0_66", mout_top0_group1, MUX_SEL_TOP03, 20, 2), + + MUX(0, "mout_sclk_uart3", mout_top0_group1, MUX_SEL_TOP0_PERIC3, 4, 2), + MUX(0, "mout_sclk_uart2", mout_top0_group1, MUX_SEL_TOP0_PERIC3, 8, 2), + MUX(0, "mout_sclk_uart1", mout_top0_group1, MUX_SEL_TOP0_PERIC3, 12, 2), + MUX(0, "mout_sclk_uart0", mout_top0_group1, MUX_SEL_TOP0_PERIC3, 16, 2), +}; + +static struct samsung_div_clock top0_div_clks[] __initdata = { + DIV(DOUT_ACLK_PERIC1, "dout_aclk_peric1_66", "mout_aclk_peric1_66", + DIV_TOP03, 12, 6), + DIV(DOUT_ACLK_PERIC0, "dout_aclk_peric0_66", "mout_aclk_peric0_66", + DIV_TOP03, 20, 6), + + DIV(0, "dout_sclk_uart3", "mout_sclk_uart3", DIV_TOP0_PERIC3, 4, 4), + DIV(0, "dout_sclk_uart2", "mout_sclk_uart2", DIV_TOP0_PERIC3, 8, 4), + DIV(0, "dout_sclk_uart1", "mout_sclk_uart1", DIV_TOP0_PERIC3, 12, 4), + DIV(0, "dout_sclk_uart0", "mout_sclk_uart0", DIV_TOP0_PERIC3, 16, 4), +}; + +static struct samsung_gate_clock top0_gate_clks[] __initdata = { + GATE(CLK_SCLK_UART3, "sclk_uart3", "dout_sclk_uart3", + ENABLE_SCLK_TOP0_PERIC3, 4, 0, 0), + GATE(CLK_SCLK_UART2, "sclk_uart2", "dout_sclk_uart2", + ENABLE_SCLK_TOP0_PERIC3, 8, 0, 0), + GATE(CLK_SCLK_UART1, "sclk_uart1", "dout_sclk_uart1", + ENABLE_SCLK_TOP0_PERIC3, 12, 0, 0), + GATE(CLK_SCLK_UART0, "sclk_uart0", "dout_sclk_uart0", + ENABLE_SCLK_TOP0_PERIC3, 16, 0, 0), +}; + +static struct samsung_fixed_factor_clock top0_fixed_factor_clks[] __initdata = { + FFACTOR(0, "ffac_top0_bus0_pll_div2", "mout_top0_bus0_pll", 1, 2, 0), + FFACTOR(0, "ffac_top0_bus1_pll_div2", "mout_top0_bus1_pll", 1, 2, 0), + FFACTOR(0, "ffac_top0_cc_pll_div2", "mout_top0_cc_pll", 1, 2, 0), + FFACTOR(0, "ffac_top0_mfc_pll_div2", "mout_top0_mfc_pll", 1, 2, 0), +}; + +static struct samsung_cmu_info top0_cmu_info __initdata = { + .mux_clks = top0_mux_clks, + .nr_mux_clks = ARRAY_SIZE(top0_mux_clks), + .div_clks = top0_div_clks, + .nr_div_clks = ARRAY_SIZE(top0_div_clks), + .gate_clks = top0_gate_clks, + .nr_gate_clks = ARRAY_SIZE(top0_gate_clks), + .fixed_factor_clks = top0_fixed_factor_clks, + .nr_fixed_factor_clks = ARRAY_SIZE(top0_fixed_factor_clks), + .nr_clk_ids = TOP0_NR_CLK, + .clk_regs = top0_clk_regs, + .nr_clk_regs = ARRAY_SIZE(top0_clk_regs), +}; + +static void __init exynos7_clk_top0_init(struct device_node *np) +{ + samsung_cmu_register_one(np, &top0_cmu_info); +} + +CLK_OF_DECLARE(exynos7_clk_top0, "samsung,exynos7-clock-top0", + exynos7_clk_top0_init); + +/* Register Offset definitions for CMU_PERIC0 (0x13610000) */ +#define MUX_SEL_PERIC0 0x0200 +#define ENABLE_PCLK_PERIC0 0x0900 +#define ENABLE_SCLK_PERIC0 0x0A00 + +/* List of parent clocks for Muxes in CMU_PERIC0 */ +PNAME(mout_aclk_peric0_66_p) = { "fin_pll", "dout_aclk_peric0_66" }; +PNAME(mout_sclk_uart0_p) = { "fin_pll", "sclk_uart0" }; + +static unsigned long peric0_clk_regs[] __initdata = { + MUX_SEL_PERIC0, + ENABLE_PCLK_PERIC0, + ENABLE_SCLK_PERIC0, +}; + +static struct samsung_mux_clock peric0_mux_clks[] __initdata = { + MUX(0, "mout_aclk_peric0_66_user", mout_aclk_peric0_66_p, + MUX_SEL_PERIC0, 0, 1), + MUX(0, "mout_sclk_uart0_user", mout_sclk_uart0_p, + MUX_SEL_PERIC0, 16, 1), +}; + +static struct samsung_gate_clock peric0_gate_clks[] __initdata = { + GATE(PCLK_UART0, "pclk_uart0", "mout_aclk_peric0_66_user", + ENABLE_PCLK_PERIC0, 16, 0, 0), + + GATE(SCLK_UART0, "sclk_uart0_user", "mout_sclk_uart0_user", + ENABLE_SCLK_PERIC0, 16, 0, 0), +}; + +static struct samsung_cmu_info peric0_cmu_info __initdata = { + .mux_clks = peric0_mux_clks, + .nr_mux_clks = ARRAY_SIZE(peric0_mux_clks), + .gate_clks = peric0_gate_clks, + .nr_gate_clks = ARRAY_SIZE(peric0_gate_clks), + .nr_clk_ids = PERIC0_NR_CLK, + .clk_regs = peric0_clk_regs, + .nr_clk_regs = ARRAY_SIZE(peric0_clk_regs), +}; + +static void __init exynos7_clk_peric0_init(struct device_node *np) +{ + samsung_cmu_register_one(np, &peric0_cmu_info); +} + +/* Register Offset definitions for CMU_PERIC1 (0x14C80000) */ +#define MUX_SEL_PERIC10 0x0200 +#define MUX_SEL_PERIC11 0x0204 +#define ENABLE_PCLK_PERIC1 0x0900 +#define ENABLE_SCLK_PERIC10 0x0A00 + +CLK_OF_DECLARE(exynos7_clk_peric0, "samsung,exynos7-clock-peric0", + exynos7_clk_peric0_init); + +/* List of parent clocks for Muxes in CMU_PERIC1 */ +PNAME(mout_aclk_peric1_66_p) = { "fin_pll", "dout_aclk_peric1_66" }; +PNAME(mout_sclk_uart1_p) = { "fin_pll", "sclk_uart1" }; +PNAME(mout_sclk_uart2_p) = { "fin_pll", "sclk_uart2" }; +PNAME(mout_sclk_uart3_p) = { "fin_pll", "sclk_uart3" }; + +static unsigned long peric1_clk_regs[] __initdata = { + MUX_SEL_PERIC10, + MUX_SEL_PERIC11, + ENABLE_PCLK_PERIC1, + ENABLE_SCLK_PERIC10, +}; + +static struct samsung_mux_clock peric1_mux_clks[] __initdata = { + MUX(0, "mout_aclk_peric1_66_user", mout_aclk_peric1_66_p, + MUX_SEL_PERIC10, 0, 1), + + MUX(0, "mout_sclk_uart1_user", mout_sclk_uart1_p, + MUX_SEL_PERIC11, 20, 1), + MUX(0, "mout_sclk_uart2_user", mout_sclk_uart2_p, + MUX_SEL_PERIC11, 24, 1), + MUX(0, "mout_sclk_uart3_user", mout_sclk_uart3_p, + MUX_SEL_PERIC11, 28, 1), +}; + +static struct samsung_gate_clock peric1_gate_clks[] __initdata = { + GATE(PCLK_UART1, "pclk_uart1", "mout_aclk_peric1_66_user", + ENABLE_PCLK_PERIC1, 9, 0, 0), + GATE(PCLK_UART2, "pclk_uart2", "mout_aclk_peric1_66_user", + ENABLE_PCLK_PERIC1, 10, 0, 0), + GATE(PCLK_UART3, "pclk_uart3", "mout_aclk_peric1_66_user", + ENABLE_PCLK_PERIC1, 11, 0, 0), + + GATE(SCLK_UART1, "sclk_uart1_user", "mout_sclk_uart1_user", + ENABLE_SCLK_PERIC10, 9, 0, 0), + GATE(SCLK_UART2, "sclk_uart2_user", "mout_sclk_uart2_user", + ENABLE_SCLK_PERIC10, 10, 0, 0), + GATE(SCLK_UART3, "sclk_uart3_user", "mout_sclk_uart3_user", + ENABLE_SCLK_PERIC10, 11, 0, 0), +}; + +static struct samsung_cmu_info peric1_cmu_info __initdata = { + .mux_clks = peric1_mux_clks, + .nr_mux_clks = ARRAY_SIZE(peric1_mux_clks), + .gate_clks = peric1_gate_clks, + .nr_gate_clks = ARRAY_SIZE(peric1_gate_clks), + .nr_clk_ids = PERIC1_NR_CLK, + .clk_regs = peric1_clk_regs, + .nr_clk_regs = ARRAY_SIZE(peric1_clk_regs), +}; + +static void __init exynos7_clk_peric1_init(struct device_node *np) +{ + samsung_cmu_register_one(np, &peric1_cmu_info); +} + +CLK_OF_DECLARE(exynos7_clk_peric1, "samsung,exynos7-clock-peric1", + exynos7_clk_peric1_init); + +/* Register Offset definitions for CMU_PERIS (0x10040000) */ +#define MUX_SEL_PERIS 0x0200 +#define ENABLE_PCLK_PERIS_SECURE_CHIPID 0x0910 +#define ENABLE_SCLK_PERIS_SECURE_CHIPID 0x0A10 + +/* List of parent clocks for Muxes in CMU_PERIS */ +PNAME(mout_aclk_peris_66_p) = { "fin_pll", "dout_aclk_peris_66" }; + +static unsigned long peris_clk_regs[] __initdata = { + MUX_SEL_PERIS, + ENABLE_PCLK_PERIS_SECURE_CHIPID, + ENABLE_SCLK_PERIS_SECURE_CHIPID, +}; + +static struct samsung_mux_clock peris_mux_clks[] __initdata = { + MUX(0, "mout_aclk_peris_66_user", + mout_aclk_peris_66_p, MUX_SEL_PERIS, 0, 1), +}; + +static struct samsung_gate_clock peris_gate_clks[] __initdata = { + GATE(PCLK_CHIPID, "pclk_chipid", "mout_aclk_peris_66_user", + ENABLE_PCLK_PERIS_SECURE_CHIPID, 0, 0, 0), + GATE(SCLK_CHIPID, "sclk_chipid", "fin_pll", + ENABLE_SCLK_PERIS_SECURE_CHIPID, 0, 0, 0), +}; + +static struct samsung_cmu_info peris_cmu_info __initdata = { + .mux_clks = peris_mux_clks, + .nr_mux_clks = ARRAY_SIZE(peris_mux_clks), + .gate_clks = peris_gate_clks, + .nr_gate_clks = ARRAY_SIZE(peris_gate_clks), + .nr_clk_ids = PERIS_NR_CLK, + .clk_regs = peris_clk_regs, + .nr_clk_regs = ARRAY_SIZE(peris_clk_regs), +}; + +static void __init exynos7_clk_peris_init(struct device_node *np) +{ + samsung_cmu_register_one(np, &peris_cmu_info); +} + +CLK_OF_DECLARE(exynos7_clk_peris, "samsung,exynos7-clock-peris", + exynos7_clk_peris_init); diff --git a/include/dt-bindings/clock/exynos7-clk.h b/include/dt-bindings/clock/exynos7-clk.h new file mode 100644 index 000000000000..00fd6de1cb25 --- /dev/null +++ b/include/dt-bindings/clock/exynos7-clk.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * Author: Naveen Krishna Ch + * + * 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_CLOCK_EXYNOS7_H +#define _DT_BINDINGS_CLOCK_EXYNOS7_H + +/* TOPC */ +#define DOUT_ACLK_PERIS 1 +#define DOUT_SCLK_BUS0_PLL 2 +#define DOUT_SCLK_BUS1_PLL 3 +#define DOUT_SCLK_CC_PLL 4 +#define DOUT_SCLK_MFC_PLL 5 +#define TOPC_NR_CLK 6 + +/* TOP0 */ +#define DOUT_ACLK_PERIC1 1 +#define DOUT_ACLK_PERIC0 2 +#define CLK_SCLK_UART0 3 +#define CLK_SCLK_UART1 4 +#define CLK_SCLK_UART2 5 +#define CLK_SCLK_UART3 6 +#define TOP0_NR_CLK 7 + +/* PERIC0 */ +#define PCLK_UART0 1 +#define SCLK_UART0 2 +#define PERIC0_NR_CLK 3 + +/* PERIC1 */ +#define PCLK_UART1 1 +#define PCLK_UART2 2 +#define PCLK_UART3 3 +#define SCLK_UART1 4 +#define SCLK_UART2 5 +#define SCLK_UART3 6 +#define PERIC1_NR_CLK 7 + +/* PERIS */ +#define PCLK_CHIPID 1 +#define SCLK_CHIPID 2 +#define PERIS_NR_CLK 3 + +#endif /* _DT_BINDINGS_CLOCK_EXYNOS7_H */ -- cgit v1.2.3-59-g8ed1b From 6d0c8c723f0b886f58263c089831fd2bee0b3b57 Mon Sep 17 00:00:00 2001 From: Naveen Krishna Ch Date: Tue, 21 Oct 2014 11:13:52 +0530 Subject: clk: samsung: exynos7: add clocks for MMC block Exynos7 supports 3 MMC channels, add the MMC gate clocks to support them. Signed-off-by: Naveen Krishna Ch Signed-off-by: Abhilash Kesavan Signed-off-by: Sylwester Nawrocki --- .../devicetree/bindings/clock/exynos7-clock.txt | 21 ++ drivers/clk/samsung/clk-exynos7.c | 224 +++++++++++++++++++++ include/dt-bindings/clock/exynos7-clk.h | 20 ++ 3 files changed, 265 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/exynos7-clock.txt b/Documentation/devicetree/bindings/clock/exynos7-clock.txt index 789f76132a85..b29cb50048c6 100644 --- a/Documentation/devicetree/bindings/clock/exynos7-clock.txt +++ b/Documentation/devicetree/bindings/clock/exynos7-clock.txt @@ -27,9 +27,12 @@ Required Properties for Clock Controller: - "samsung,exynos7-clock-topc" - "samsung,exynos7-clock-top0" + - "samsung,exynos7-clock-top1" - "samsung,exynos7-clock-peric0" - "samsung,exynos7-clock-peric1" - "samsung,exynos7-clock-peris" + - "samsung,exynos7-clock-fsys0" + - "samsung,exynos7-clock-fsys1" - reg: physical base address of the controller and the length of memory mapped region. @@ -50,6 +53,13 @@ Input clocks for top0 clock controller: - dout_sclk_cc_pll - dout_sclk_mfc_pll +Input clocks for top1 clock controller: + - fin_pll + - dout_sclk_bus0_pll + - dout_sclk_bus1_pll + - dout_sclk_cc_pll + - dout_sclk_mfc_pll + Input clocks for peric0 clock controller: - fin_pll - dout_aclk_peric0_66 @@ -65,3 +75,14 @@ Input clocks for peric1 clock controller: Input clocks for peris clock controller: - fin_pll - dout_aclk_peris_66 + +Input clocks for fsys0 clock controller: + - fin_pll + - dout_aclk_fsys0_200 + - dout_sclk_mmc2 + +Input clocks for fsys1 clock controller: + - fin_pll + - dout_aclk_fsys1_200 + - dout_sclk_mmc0 + - dout_sclk_mmc1 diff --git a/drivers/clk/samsung/clk-exynos7.c b/drivers/clk/samsung/clk-exynos7.c index c700f654289e..f5e43fab1951 100644 --- a/drivers/clk/samsung/clk-exynos7.c +++ b/drivers/clk/samsung/clk-exynos7.c @@ -267,6 +267,132 @@ static void __init exynos7_clk_top0_init(struct device_node *np) CLK_OF_DECLARE(exynos7_clk_top0, "samsung,exynos7-clock-top0", exynos7_clk_top0_init); +/* Register Offset definitions for CMU_TOP1 (0x105E0000) */ +#define MUX_SEL_TOP10 0x0200 +#define MUX_SEL_TOP11 0x0204 +#define MUX_SEL_TOP13 0x020C +#define MUX_SEL_TOP1_FSYS0 0x0224 +#define MUX_SEL_TOP1_FSYS1 0x0228 +#define DIV_TOP13 0x060C +#define DIV_TOP1_FSYS0 0x0624 +#define DIV_TOP1_FSYS1 0x0628 +#define ENABLE_ACLK_TOP13 0x080C +#define ENABLE_SCLK_TOP1_FSYS0 0x0A24 +#define ENABLE_SCLK_TOP1_FSYS1 0x0A28 + +/* List of parent clocks for Muxes in CMU_TOP1 */ +PNAME(mout_top1_bus0_pll_p) = { "fin_pll", "dout_sclk_bus0_pll" }; +PNAME(mout_top1_bus1_pll_p) = { "fin_pll", "dout_sclk_bus1_pll_b" }; +PNAME(mout_top1_cc_pll_p) = { "fin_pll", "dout_sclk_cc_pll_b" }; +PNAME(mout_top1_mfc_pll_p) = { "fin_pll", "dout_sclk_mfc_pll_b" }; + +PNAME(mout_top1_half_bus0_pll_p) = {"mout_top1_bus0_pll", + "ffac_top1_bus0_pll_div2"}; +PNAME(mout_top1_half_bus1_pll_p) = {"mout_top1_bus1_pll", + "ffac_top1_bus1_pll_div2"}; +PNAME(mout_top1_half_cc_pll_p) = {"mout_top1_cc_pll", + "ffac_top1_cc_pll_div2"}; +PNAME(mout_top1_half_mfc_pll_p) = {"mout_top1_mfc_pll", + "ffac_top1_mfc_pll_div2"}; + +PNAME(mout_top1_group1) = {"mout_top1_half_bus0_pll", + "mout_top1_half_bus1_pll", "mout_top1_half_cc_pll", + "mout_top1_half_mfc_pll"}; + +static unsigned long top1_clk_regs[] __initdata = { + MUX_SEL_TOP10, + MUX_SEL_TOP11, + MUX_SEL_TOP13, + MUX_SEL_TOP1_FSYS0, + MUX_SEL_TOP1_FSYS1, + DIV_TOP13, + DIV_TOP1_FSYS0, + DIV_TOP1_FSYS1, + ENABLE_ACLK_TOP13, + ENABLE_SCLK_TOP1_FSYS0, + ENABLE_SCLK_TOP1_FSYS1, +}; + +static struct samsung_mux_clock top1_mux_clks[] __initdata = { + MUX(0, "mout_top1_mfc_pll", mout_top1_mfc_pll_p, MUX_SEL_TOP10, 4, 1), + MUX(0, "mout_top1_cc_pll", mout_top1_cc_pll_p, MUX_SEL_TOP10, 8, 1), + MUX(0, "mout_top1_bus1_pll", mout_top1_bus1_pll_p, + MUX_SEL_TOP10, 12, 1), + MUX(0, "mout_top1_bus0_pll", mout_top1_bus0_pll_p, + MUX_SEL_TOP10, 16, 1), + + MUX(0, "mout_top1_half_mfc_pll", mout_top1_half_mfc_pll_p, + MUX_SEL_TOP11, 4, 1), + MUX(0, "mout_top1_half_cc_pll", mout_top1_half_cc_pll_p, + MUX_SEL_TOP11, 8, 1), + MUX(0, "mout_top1_half_bus1_pll", mout_top1_half_bus1_pll_p, + MUX_SEL_TOP11, 12, 1), + MUX(0, "mout_top1_half_bus0_pll", mout_top1_half_bus0_pll_p, + MUX_SEL_TOP11, 16, 1), + + MUX(0, "mout_aclk_fsys1_200", mout_top1_group1, MUX_SEL_TOP13, 24, 2), + MUX(0, "mout_aclk_fsys0_200", mout_top1_group1, MUX_SEL_TOP13, 28, 2), + + MUX(0, "mout_sclk_mmc2", mout_top1_group1, MUX_SEL_TOP1_FSYS0, 24, 2), + + MUX(0, "mout_sclk_mmc1", mout_top1_group1, MUX_SEL_TOP1_FSYS1, 24, 2), + MUX(0, "mout_sclk_mmc0", mout_top1_group1, MUX_SEL_TOP1_FSYS1, 28, 2), +}; + +static struct samsung_div_clock top1_div_clks[] __initdata = { + DIV(DOUT_ACLK_FSYS1_200, "dout_aclk_fsys1_200", "mout_aclk_fsys1_200", + DIV_TOP13, 24, 4), + DIV(DOUT_ACLK_FSYS0_200, "dout_aclk_fsys0_200", "mout_aclk_fsys0_200", + DIV_TOP13, 28, 4), + + DIV(DOUT_SCLK_MMC2, "dout_sclk_mmc2", "mout_sclk_mmc2", + DIV_TOP1_FSYS0, 24, 4), + + DIV(DOUT_SCLK_MMC1, "dout_sclk_mmc1", "mout_sclk_mmc1", + DIV_TOP1_FSYS1, 24, 4), + DIV(DOUT_SCLK_MMC0, "dout_sclk_mmc0", "mout_sclk_mmc0", + DIV_TOP1_FSYS1, 28, 4), +}; + +static struct samsung_gate_clock top1_gate_clks[] __initdata = { + GATE(CLK_SCLK_MMC2, "sclk_mmc2", "dout_sclk_mmc2", + ENABLE_SCLK_TOP1_FSYS0, 24, CLK_SET_RATE_PARENT, 0), + + GATE(CLK_SCLK_MMC1, "sclk_mmc1", "dout_sclk_mmc1", + ENABLE_SCLK_TOP1_FSYS1, 24, CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_MMC0, "sclk_mmc0", "dout_sclk_mmc0", + ENABLE_SCLK_TOP1_FSYS1, 28, CLK_SET_RATE_PARENT, 0), +}; + +static struct samsung_fixed_factor_clock top1_fixed_factor_clks[] __initdata = { + FFACTOR(0, "ffac_top1_bus0_pll_div2", "mout_top1_bus0_pll", 1, 2, 0), + FFACTOR(0, "ffac_top1_bus1_pll_div2", "mout_top1_bus1_pll", 1, 2, 0), + FFACTOR(0, "ffac_top1_cc_pll_div2", "mout_top1_cc_pll", 1, 2, 0), + FFACTOR(0, "ffac_top1_mfc_pll_div2", "mout_top1_mfc_pll", 1, 2, 0), +}; + +static struct samsung_cmu_info top1_cmu_info __initdata = { + .mux_clks = top1_mux_clks, + .nr_mux_clks = ARRAY_SIZE(top1_mux_clks), + .div_clks = top1_div_clks, + .nr_div_clks = ARRAY_SIZE(top1_div_clks), + .gate_clks = top1_gate_clks, + .nr_gate_clks = ARRAY_SIZE(top1_gate_clks), + .fixed_factor_clks = top1_fixed_factor_clks, + .nr_fixed_factor_clks = ARRAY_SIZE(top1_fixed_factor_clks), + .nr_clk_ids = TOP1_NR_CLK, + .clk_regs = top1_clk_regs, + .nr_clk_regs = ARRAY_SIZE(top1_clk_regs), +}; + +static void __init exynos7_clk_top1_init(struct device_node *np) +{ + samsung_cmu_register_one(np, &top1_cmu_info); +} + +CLK_OF_DECLARE(exynos7_clk_top1, "samsung,exynos7-clock-top1", + exynos7_clk_top1_init); + /* Register Offset definitions for CMU_PERIC0 (0x13610000) */ #define MUX_SEL_PERIC0 0x0200 #define ENABLE_PCLK_PERIC0 0x0900 @@ -447,3 +573,101 @@ static void __init exynos7_clk_peris_init(struct device_node *np) CLK_OF_DECLARE(exynos7_clk_peris, "samsung,exynos7-clock-peris", exynos7_clk_peris_init); + +/* Register Offset definitions for CMU_FSYS0 (0x10E90000) */ +#define MUX_SEL_FSYS00 0x0200 +#define MUX_SEL_FSYS01 0x0204 +#define ENABLE_ACLK_FSYS01 0x0804 + +/* + * List of parent clocks for Muxes in CMU_FSYS0 + */ +PNAME(mout_aclk_fsys0_200_p) = { "fin_pll", "dout_aclk_fsys0_200" }; +PNAME(mout_sclk_mmc2_p) = { "fin_pll", "sclk_mmc2" }; + +static unsigned long fsys0_clk_regs[] __initdata = { + MUX_SEL_FSYS00, + MUX_SEL_FSYS01, + ENABLE_ACLK_FSYS01, +}; + +static struct samsung_mux_clock fsys0_mux_clks[] __initdata = { + MUX(0, "mout_aclk_fsys0_200_user", mout_aclk_fsys0_200_p, + MUX_SEL_FSYS00, 24, 1), + + MUX(0, "mout_sclk_mmc2_user", mout_sclk_mmc2_p, MUX_SEL_FSYS01, 24, 1), +}; + +static struct samsung_gate_clock fsys0_gate_clks[] __initdata = { + GATE(ACLK_MMC2, "aclk_mmc2", "mout_aclk_fsys0_200_user", + ENABLE_ACLK_FSYS01, 31, 0, 0), +}; + +static struct samsung_cmu_info fsys0_cmu_info __initdata = { + .mux_clks = fsys0_mux_clks, + .nr_mux_clks = ARRAY_SIZE(fsys0_mux_clks), + .gate_clks = fsys0_gate_clks, + .nr_gate_clks = ARRAY_SIZE(fsys0_gate_clks), + .nr_clk_ids = TOP1_NR_CLK, + .clk_regs = fsys0_clk_regs, + .nr_clk_regs = ARRAY_SIZE(fsys0_clk_regs), +}; + +static void __init exynos7_clk_fsys0_init(struct device_node *np) +{ + samsung_cmu_register_one(np, &fsys0_cmu_info); +} + +CLK_OF_DECLARE(exynos7_clk_fsys0, "samsung,exynos7-clock-fsys0", + exynos7_clk_fsys0_init); + +/* Register Offset definitions for CMU_FSYS1 (0x156E0000) */ +#define MUX_SEL_FSYS10 0x0200 +#define MUX_SEL_FSYS11 0x0204 +#define ENABLE_ACLK_FSYS1 0x0800 + +/* + * List of parent clocks for Muxes in CMU_FSYS1 + */ +PNAME(mout_aclk_fsys1_200_p) = { "fin_pll", "dout_aclk_fsys1_200" }; +PNAME(mout_sclk_mmc0_p) = { "fin_pll", "sclk_mmc0" }; +PNAME(mout_sclk_mmc1_p) = { "fin_pll", "sclk_mmc1" }; + +static unsigned long fsys1_clk_regs[] __initdata = { + MUX_SEL_FSYS10, + MUX_SEL_FSYS11, + ENABLE_ACLK_FSYS1, +}; + +static struct samsung_mux_clock fsys1_mux_clks[] __initdata = { + MUX(0, "mout_aclk_fsys1_200_user", mout_aclk_fsys1_200_p, + MUX_SEL_FSYS10, 28, 1), + + MUX(0, "mout_sclk_mmc1_user", mout_sclk_mmc1_p, MUX_SEL_FSYS11, 24, 1), + MUX(0, "mout_sclk_mmc0_user", mout_sclk_mmc0_p, MUX_SEL_FSYS11, 28, 1), +}; + +static struct samsung_gate_clock fsys1_gate_clks[] __initdata = { + GATE(ACLK_MMC1, "aclk_mmc1", "mout_aclk_fsys1_200_user", + ENABLE_ACLK_FSYS1, 29, 0, 0), + GATE(ACLK_MMC0, "aclk_mmc0", "mout_aclk_fsys1_200_user", + ENABLE_ACLK_FSYS1, 30, 0, 0), +}; + +static struct samsung_cmu_info fsys1_cmu_info __initdata = { + .mux_clks = fsys1_mux_clks, + .nr_mux_clks = ARRAY_SIZE(fsys1_mux_clks), + .gate_clks = fsys1_gate_clks, + .nr_gate_clks = ARRAY_SIZE(fsys1_gate_clks), + .nr_clk_ids = TOP1_NR_CLK, + .clk_regs = fsys1_clk_regs, + .nr_clk_regs = ARRAY_SIZE(fsys1_clk_regs), +}; + +static void __init exynos7_clk_fsys1_init(struct device_node *np) +{ + samsung_cmu_register_one(np, &fsys1_cmu_info); +} + +CLK_OF_DECLARE(exynos7_clk_fsys1, "samsung,exynos7-clock-fsys1", + exynos7_clk_fsys1_init); diff --git a/include/dt-bindings/clock/exynos7-clk.h b/include/dt-bindings/clock/exynos7-clk.h index 6d07b6f1d615..ff63c4e15cc5 100644 --- a/include/dt-bindings/clock/exynos7-clk.h +++ b/include/dt-bindings/clock/exynos7-clk.h @@ -27,6 +27,17 @@ #define CLK_SCLK_UART3 6 #define TOP0_NR_CLK 7 +/* TOP1 */ +#define DOUT_ACLK_FSYS1_200 1 +#define DOUT_ACLK_FSYS0_200 2 +#define DOUT_SCLK_MMC2 3 +#define DOUT_SCLK_MMC1 4 +#define DOUT_SCLK_MMC0 5 +#define CLK_SCLK_MMC2 6 +#define CLK_SCLK_MMC1 7 +#define CLK_SCLK_MMC0 8 +#define TOP1_NR_CLK 9 + /* PERIC0 */ #define PCLK_UART0 1 #define SCLK_UART0 2 @@ -58,4 +69,13 @@ #define SCLK_CHIPID 2 #define PERIS_NR_CLK 3 +/* FSYS0 */ +#define ACLK_MMC2 1 +#define FSYS0_NR_CLK 2 + +/* FSYS1 */ +#define ACLK_MMC1 1 +#define ACLK_MMC0 2 +#define FSYS1_NR_CLK 3 + #endif /* _DT_BINDINGS_CLOCK_EXYNOS7_H */ -- cgit v1.2.3-59-g8ed1b From f5e127cd5ee52b3f0edaeeb7a40c0b9599f4e691 Mon Sep 17 00:00:00 2001 From: Naveen Krishna Ch Date: Tue, 28 Oct 2014 16:48:53 +0530 Subject: clk: samsung: exynos7: add clocks for RTC block Add clock support for the RTC block in Exynos7. Signed-off-by: Naveen Krishna Ch Signed-off-by: Abhilash Kesavan Signed-off-by: Sylwester Nawrocki --- .../devicetree/bindings/clock/exynos7-clock.txt | 5 ++ drivers/clk/samsung/clk-exynos7.c | 54 ++++++++++++++++++++++ include/dt-bindings/clock/exynos7-clk.h | 7 ++- 3 files changed, 65 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/exynos7-clock.txt b/Documentation/devicetree/bindings/clock/exynos7-clock.txt index b29cb50048c6..6d3d5f80c1c3 100644 --- a/Documentation/devicetree/bindings/clock/exynos7-clock.txt +++ b/Documentation/devicetree/bindings/clock/exynos7-clock.txt @@ -28,6 +28,7 @@ Required Properties for Clock Controller: - "samsung,exynos7-clock-topc" - "samsung,exynos7-clock-top0" - "samsung,exynos7-clock-top1" + - "samsung,exynos7-clock-ccore" - "samsung,exynos7-clock-peric0" - "samsung,exynos7-clock-peric1" - "samsung,exynos7-clock-peris" @@ -60,6 +61,10 @@ Input clocks for top1 clock controller: - dout_sclk_cc_pll - dout_sclk_mfc_pll +Input clocks for ccore clock controller: + - fin_pll + - dout_aclk_ccore_133 + Input clocks for peric0 clock controller: - fin_pll - dout_aclk_peric0_66 diff --git a/drivers/clk/samsung/clk-exynos7.c b/drivers/clk/samsung/clk-exynos7.c index f5e43fab1951..3a30f43fa925 100644 --- a/drivers/clk/samsung/clk-exynos7.c +++ b/drivers/clk/samsung/clk-exynos7.c @@ -29,7 +29,9 @@ #define AUD_PLL_CON0 0x0140 #define MUX_SEL_TOPC0 0x0200 #define MUX_SEL_TOPC1 0x0204 +#define MUX_SEL_TOPC2 0x0208 #define MUX_SEL_TOPC3 0x020C +#define DIV_TOPC0 0x0600 #define DIV_TOPC1 0x0604 #define DIV_TOPC3 0x060C @@ -78,7 +80,9 @@ static unsigned long topc_clk_regs[] __initdata = { AUD_PLL_CON0, MUX_SEL_TOPC0, MUX_SEL_TOPC1, + MUX_SEL_TOPC2, MUX_SEL_TOPC3, + DIV_TOPC0, DIV_TOPC1, DIV_TOPC3, }; @@ -101,10 +105,15 @@ static struct samsung_mux_clock topc_mux_clks[] __initdata = { MUX(0, "mout_sclk_bus0_pll_out", mout_sclk_bus0_pll_out_p, MUX_SEL_TOPC1, 16, 1), + MUX(0, "mout_aclk_ccore_133", mout_topc_group2, MUX_SEL_TOPC2, 4, 2), + MUX(0, "mout_aclk_peris_66", mout_topc_group2, MUX_SEL_TOPC3, 24, 2), }; static struct samsung_div_clock topc_div_clks[] __initdata = { + DIV(DOUT_ACLK_CCORE_133, "dout_aclk_ccore_133", "mout_aclk_ccore_133", + DIV_TOPC0, 4, 4), + DIV(DOUT_ACLK_PERIS, "dout_aclk_peris_66", "mout_aclk_peris_66", DIV_TOPC1, 24, 4), @@ -393,6 +402,51 @@ static void __init exynos7_clk_top1_init(struct device_node *np) CLK_OF_DECLARE(exynos7_clk_top1, "samsung,exynos7-clock-top1", exynos7_clk_top1_init); +/* Register Offset definitions for CMU_CCORE (0x105B0000) */ +#define MUX_SEL_CCORE 0x0200 +#define DIV_CCORE 0x0600 +#define ENABLE_ACLK_CCORE0 0x0800 +#define ENABLE_ACLK_CCORE1 0x0804 +#define ENABLE_PCLK_CCORE 0x0900 + +/* + * List of parent clocks for Muxes in CMU_CCORE + */ +PNAME(mout_aclk_ccore_133_p) = { "fin_pll", "dout_aclk_ccore_133" }; + +static unsigned long ccore_clk_regs[] __initdata = { + MUX_SEL_CCORE, + ENABLE_PCLK_CCORE, +}; + +static struct samsung_mux_clock ccore_mux_clks[] __initdata = { + MUX(0, "mout_aclk_ccore_133_user", mout_aclk_ccore_133_p, + MUX_SEL_CCORE, 1, 1), +}; + +static struct samsung_gate_clock ccore_gate_clks[] __initdata = { + GATE(PCLK_RTC, "pclk_rtc", "mout_aclk_ccore_133_user", + ENABLE_PCLK_CCORE, 8, 0, 0), +}; + +static struct samsung_cmu_info ccore_cmu_info __initdata = { + .mux_clks = ccore_mux_clks, + .nr_mux_clks = ARRAY_SIZE(ccore_mux_clks), + .gate_clks = ccore_gate_clks, + .nr_gate_clks = ARRAY_SIZE(ccore_gate_clks), + .nr_clk_ids = CCORE_NR_CLK, + .clk_regs = ccore_clk_regs, + .nr_clk_regs = ARRAY_SIZE(ccore_clk_regs), +}; + +static void __init exynos7_clk_ccore_init(struct device_node *np) +{ + samsung_cmu_register_one(np, &ccore_cmu_info); +} + +CLK_OF_DECLARE(exynos7_clk_ccore, "samsung,exynos7-clock-ccore", + exynos7_clk_ccore_init); + /* Register Offset definitions for CMU_PERIC0 (0x13610000) */ #define MUX_SEL_PERIC0 0x0200 #define ENABLE_PCLK_PERIC0 0x0900 diff --git a/include/dt-bindings/clock/exynos7-clk.h b/include/dt-bindings/clock/exynos7-clk.h index ff63c4e15cc5..dd89aa0f84e1 100644 --- a/include/dt-bindings/clock/exynos7-clk.h +++ b/include/dt-bindings/clock/exynos7-clk.h @@ -16,7 +16,8 @@ #define DOUT_SCLK_BUS1_PLL 3 #define DOUT_SCLK_CC_PLL 4 #define DOUT_SCLK_MFC_PLL 5 -#define TOPC_NR_CLK 6 +#define DOUT_ACLK_CCORE_133 6 +#define TOPC_NR_CLK 7 /* TOP0 */ #define DOUT_ACLK_PERIC1 1 @@ -38,6 +39,10 @@ #define CLK_SCLK_MMC0 8 #define TOP1_NR_CLK 9 +/* CCORE */ +#define PCLK_RTC 1 +#define CCORE_NR_CLK 2 + /* PERIC0 */ #define PCLK_UART0 1 #define SCLK_UART0 2 -- cgit v1.2.3-59-g8ed1b From 4b171b3d3bdf256b0d75a6b3430d8b73134b1bf7 Mon Sep 17 00:00:00 2001 From: Peter Griffin Date: Wed, 2 Jul 2014 15:08:47 +0100 Subject: reset: sti: Document sti-picophyreset controllers bindings. Add DT bindings documentation for sti-picophyreset controller. Signed-off-by: Peter Griffin Acked-by: Lee Jones Signed-off-by: Maxime Coquelin --- .../bindings/reset/st,sti-picophyreset.txt | 42 ++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 Documentation/devicetree/bindings/reset/st,sti-picophyreset.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/reset/st,sti-picophyreset.txt b/Documentation/devicetree/bindings/reset/st,sti-picophyreset.txt new file mode 100644 index 000000000000..54ae9f747e45 --- /dev/null +++ b/Documentation/devicetree/bindings/reset/st,sti-picophyreset.txt @@ -0,0 +1,42 @@ +STMicroelectronics STi family Sysconfig Picophy SoftReset Controller +============================================================================= + +This binding describes a reset controller device that is used to enable and +disable on-chip PicoPHY USB2 phy(s) using "softreset" control bits found in +the STi family SoC system configuration registers. + +The actual action taken when softreset is asserted is hardware dependent. +However, when asserted it may not be possible to access the hardware's +registers and after an assert/deassert sequence the hardware's previous state +may no longer be valid. + +Please refer to Documentation/devicetree/bindings/reset/reset.txt +for common reset controller binding usage. + +Required properties: +- compatible: Should be "st,stih407-picophyreset" +- #reset-cells: 1, see below + +Example: + + picophyreset: picophyreset-controller { + compatible = "st,stih407-picophyreset"; + #reset-cells = <1>; + }; + +Specifying picophyreset control of devices +======================================= + +Device nodes should specify the reset channel required in their "resets" +property, containing a phandle to the picophyreset device node and an +index specifying which channel to use, as described in +Documentation/devicetree/bindings/reset/reset.txt. + +Example: + + usb2_picophy0: usbpicophy@0 { + resets = <&picophyreset STIH407_PICOPHY0_RESET>; + }; + +Macro definitions for the supported reset channels can be found in: +include/dt-bindings/reset-controller/stih407-resets.h -- cgit v1.2.3-59-g8ed1b From 451f2334f09c4387dcd51a628eda534ed7f66d2a Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 9 Oct 2014 22:10:35 +0200 Subject: ARM: nomadik: device tree for NHK15 board This adds a device tree for the Nomadik NHK15 development kit board. Signed-off-by: Linus Walleij --- .../devicetree/bindings/arm/ste-nomadik.txt | 6 + arch/arm/boot/dts/Makefile | 3 +- arch/arm/boot/dts/ste-nomadik-nhk15.dts | 151 +++++++++++++++++++++ arch/arm/mach-nomadik/cpu-8815.c | 1 + 4 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 arch/arm/boot/dts/ste-nomadik-nhk15.dts (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/ste-nomadik.txt b/Documentation/devicetree/bindings/arm/ste-nomadik.txt index 6256ec31666d..2fdff5a806cf 100644 --- a/Documentation/devicetree/bindings/arm/ste-nomadik.txt +++ b/Documentation/devicetree/bindings/arm/ste-nomadik.txt @@ -10,6 +10,12 @@ Required root node property: src Boards with the Nomadik SoC include: +Nomadik NHK-15 board manufactured by ST Microelectronics: + +Required root node property: + +compatible="st,nomadik-nhk-15"; + S8815 "MiniKit" manufactured by Calao Systems: Required root node property: diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 38c89cafa1ab..50bb73ec2b7d 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -274,7 +274,8 @@ dtb-$(CONFIG_ARCH_MXS) += imx23-evk.dtb \ imx28-m28evk.dtb \ imx28-sps1.dtb \ imx28-tx28.dtb -dtb-$(CONFIG_ARCH_NOMADIK) += ste-nomadik-s8815.dtb +dtb-$(CONFIG_ARCH_NOMADIK) += ste-nomadik-s8815.dtb \ + ste-nomadik-nhk15.dtb dtb-$(CONFIG_ARCH_NSPIRE) += nspire-cx.dtb \ nspire-tp.dtb \ nspire-clp.dtb diff --git a/arch/arm/boot/dts/ste-nomadik-nhk15.dts b/arch/arm/boot/dts/ste-nomadik-nhk15.dts new file mode 100644 index 000000000000..a8c00ee7522a --- /dev/null +++ b/arch/arm/boot/dts/ste-nomadik-nhk15.dts @@ -0,0 +1,151 @@ +/* + * Device Tree for the ST-Ericsson Nomadik S8815 board + * Produced by Calao Systems + */ + +/dts-v1/; +#include +#include +#include "ste-nomadik-stn8815.dtsi" + +/ { + model = "Nomadik STN8815NHK"; + compatible = "st,nomadik-nhk-15"; + + chosen { + bootargs = "root=/dev/ram0 console=ttyAMA1,115200n8 earlyprintk"; + }; + + aliases { + stmpe-i2c0 = &stmpe0; + stmpe-i2c1 = &stmpe1; + }; + + pinctrl { + stmpe2401_1 { + stmpe2401_1_nhk_mode: stmpe2401_1_nhk { + nhk_cfg1 { + ste,pins = "GPIO76_B20"; // IRQ line + ste,input = <0>; + }; + nhk_cfg2 { + ste,pins = "GPIO77_B8"; // reset line + ste,output = <1>; + }; + }; + }; + stmpe2401_2 { + stmpe2401_2_nhk_mode: stmpe2401_2_nhk { + nhk_cfg1 { + ste,pins = "GPIO78_A8"; // IRQ line + ste,input = <0>; + }; + nhk_cfg2 { + ste,pins = "GPIO79_C9"; // reset line + ste,output = <1>; + }; + }; + }; + }; + + src@101e0000 { + /* These chrystal outputs are not used on this board */ + disable-sxtalo; + disable-mxtalo; + }; + + /* This is where the interrupt is routed on the NHK-15 debug board */ + external-bus@34000000 { + compatible = "simple-bus"; + reg = <0x34000000 0x1000000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x34000000 0x1000000>; + ethernet@300 { + compatible = "smsc,lan91c111"; + reg = <0x300 0x0fd00>; + reg-io-width = <2>; + reset-gpios = <&stmpe_gpio44 10 GPIO_ACTIVE_HIGH>; + interrupt-parent = <&stmpe_gpio44>; + interrupts = <11 IRQ_TYPE_EDGE_RISING>; + }; + }; + + i2c0 { + stmpe0: stmpe2401@43 { + compatible = "st,stmpe2401"; + reg = <0x43>; + reset-gpios = <&gpio2 13 GPIO_ACTIVE_LOW>; // GPIO77 + interrupts = <12 IRQ_TYPE_EDGE_FALLING>; // GPIO76 + interrupt-parent = <&gpio2>; + interrupt-controller; + wakeup-source; + pinctrl-names = "default"; + pinctrl-0 = <&stmpe2401_1_nhk_mode>; + stmpe_gpio43: stmpe_gpio { + compatible = "st,stmpe-gpio"; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + /* Some pins in alternate functions */ + st,norequest-mask = <0xf0f002>; + }; + stmpe_keypad { + compatible = "st,stmpe-keypad"; + debounce-interval = <64>; + st,scan-count = <8>; + st,no-autorepeat; + keypad,num-rows = <8>; + keypad,num-columns = <8>; + linux,keymap = <0x00020072 // Vol down + 0x00030073 // Vol up + 0x0100009e // Back + 0x010100e3 // TV out + 0x01020098 // Lock + 0x0103013b // Start + 0x020000a3 // Next + 0x020100a4 // Play + 0x020200a5 // Prev + 0x02030160 // OK + 0x03000069 // Left + 0x0301006a // Right + 0x03020067 // Up + 0x0303006c>; // Down + }; + }; + stmpe1: stmpe2401@44 { + compatible = "st,stmpe2401"; + reg = <0x44>; + reset-gpios = <&gpio2 15 GPIO_ACTIVE_LOW>; // GPIO79 + interrupts = <14 IRQ_TYPE_EDGE_FALLING>; // GPIO78 + interrupt-parent = <&gpio2>; + interrupt-controller; + wakeup-source; + pinctrl-names = "default"; + pinctrl-0 = <&stmpe2401_2_nhk_mode>; + stmpe_gpio44: stmpe_gpio { + compatible = "st,stmpe-gpio"; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + }; + + amba { + mmcsd: sdi@101f6000 { + cd-gpios = <&stmpe_gpio44 7 GPIO_ACTIVE_LOW>; + wp-gpios = <&stmpe_gpio44 18 GPIO_ACTIVE_HIGH>; + }; + }; + + /* Custom board node with GPIO pins to active etc */ + usb-s8815 { + /* This will turn off SATA so that MMC/SD can thrive */ + mmcsd-gpio { + gpios = <&stmpe_gpio44 2 0x1>; + }; + }; +}; diff --git a/arch/arm/mach-nomadik/cpu-8815.c b/arch/arm/mach-nomadik/cpu-8815.c index 9116ca476d7c..9bda46f1fab7 100644 --- a/arch/arm/mach-nomadik/cpu-8815.c +++ b/arch/arm/mach-nomadik/cpu-8815.c @@ -144,6 +144,7 @@ static int __init cpu8815_mmcsd_init(void) device_initcall(cpu8815_mmcsd_init); static const char * cpu8815_board_compat[] = { + "st,nomadik-nhk-15", "calaosystems,usb-s8815", NULL, }; -- cgit v1.2.3-59-g8ed1b From c77fd0a42b24acc2d6cc466e73dcb67d50177df6 Mon Sep 17 00:00:00 2001 From: Matt Ranostay Date: Fri, 31 Oct 2014 20:00:13 -0700 Subject: Input: rename cap1106 driver to cap11xx There are several devices in cap11xx family besides cap1106. The driver can be made to support all of them, so let's give it more generic name. Signed-off-by: Matt Ranostay Reviewed-by: Daniel Mack Signed-off-by: Dmitry Torokhov --- .../devicetree/bindings/input/cap1106.txt | 53 ---- .../devicetree/bindings/input/cap11xx.txt | 54 ++++ drivers/input/keyboard/Kconfig | 8 +- drivers/input/keyboard/Makefile | 2 +- drivers/input/keyboard/cap1106.c | 341 --------------------- drivers/input/keyboard/cap11xx.c | 340 ++++++++++++++++++++ 6 files changed, 399 insertions(+), 399 deletions(-) delete mode 100644 Documentation/devicetree/bindings/input/cap1106.txt create mode 100644 Documentation/devicetree/bindings/input/cap11xx.txt delete mode 100644 drivers/input/keyboard/cap1106.c create mode 100644 drivers/input/keyboard/cap11xx.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/input/cap1106.txt b/Documentation/devicetree/bindings/input/cap1106.txt deleted file mode 100644 index 4b463904cba0..000000000000 --- a/Documentation/devicetree/bindings/input/cap1106.txt +++ /dev/null @@ -1,53 +0,0 @@ -Device tree bindings for Microchip CAP1106, 6 channel capacitive touch sensor - -The node for this driver must be a child of a I2C controller node, as the -device communication via I2C only. - -Required properties: - - compatible: Must be "microchip,cap1106" - - reg: The I2C slave address of the device. - Only 0x28 is valid. - - interrupts: Property describing the interrupt line the - device's ALERT#/CM_IRQ# pin is connected to. - The device only has one interrupt source. - -Optional properties: - - autorepeat: Enables the Linux input system's autorepeat - feature on the input device. - - microchip,sensor-gain: Defines the gain of the sensor circuitry. This - effectively controls the sensitivity, as a - smaller delta capacitance is required to - generate the same delta count values. - Valid values are 1, 2, 4, and 8. - By default, a gain of 1 is set. - - linux,keycodes: Specifies an array of numeric keycode values to - be used for the channels. If this property is - omitted, KEY_A, KEY_B, etc are used as - defaults. The array must have exactly six - entries. - -Example: - -i2c_controller { - cap1106@28 { - compatible = "microchip,cap1106"; - interrupt-parent = <&gpio1>; - interrupts = <0 0>; - reg = <0x28>; - autorepeat; - microchip,sensor-gain = <2>; - - linux,keycodes = <103 /* KEY_UP */ - 106 /* KEY_RIGHT */ - 108 /* KEY_DOWN */ - 105 /* KEY_LEFT */ - 109 /* KEY_PAGEDOWN */ - 104>; /* KEY_PAGEUP */ - }; -} diff --git a/Documentation/devicetree/bindings/input/cap11xx.txt b/Documentation/devicetree/bindings/input/cap11xx.txt new file mode 100644 index 000000000000..51649203658a --- /dev/null +++ b/Documentation/devicetree/bindings/input/cap11xx.txt @@ -0,0 +1,54 @@ +Device tree bindings for Microchip CAP11xx based capacitive touch sensors + +The node for this device must be a child of a I2C controller node, as the +device communication via I2C only. + +Required properties: + + compatible: Must contain one of: + "microchip,cap1106" + + reg: The I2C slave address of the device. + Only 0x28 is valid. + + interrupts: Property describing the interrupt line the + device's ALERT#/CM_IRQ# pin is connected to. + The device only has one interrupt source. + +Optional properties: + + autorepeat: Enables the Linux input system's autorepeat + feature on the input device. + + microchip,sensor-gain: Defines the gain of the sensor circuitry. This + effectively controls the sensitivity, as a + smaller delta capacitance is required to + generate the same delta count values. + Valid values are 1, 2, 4, and 8. + By default, a gain of 1 is set. + + linux,keycodes: Specifies an array of numeric keycode values to + be used for the channels. If this property is + omitted, KEY_A, KEY_B, etc are used as + defaults. The array must have exactly six + entries. + +Example: + +i2c_controller { + cap1106@28 { + compatible = "microchip,cap1106"; + interrupt-parent = <&gpio1>; + interrupts = <0 0>; + reg = <0x28>; + autorepeat; + microchip,sensor-gain = <2>; + + linux,keycodes = <103>, /* KEY_UP */ + <106>, /* KEY_RIGHT */ + <108>, /* KEY_DOWN */ + <105>, /* KEY_LEFT */ + <109>, /* KEY_PAGEDOWN */ + <104>; /* KEY_PAGEUP */ + }; +} diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index a3958c63d7d5..96ee26c555e0 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -665,14 +665,14 @@ config KEYBOARD_CROS_EC To compile this driver as a module, choose M here: the module will be called cros_ec_keyb. -config KEYBOARD_CAP1106 - tristate "Microchip CAP1106 touch sensor" +config KEYBOARD_CAP11XX + tristate "Microchip CAP11XX based touch sensors" depends on OF && I2C select REGMAP_I2C help - Say Y here to enable the CAP1106 touch sensor driver. + Say Y here to enable the CAP11XX touch sensor driver. To compile this driver as a module, choose M here: the - module will be called cap1106. + module will be called cap11xx. endif diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 0a3345634d79..febafa527eb6 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -11,7 +11,7 @@ obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o -obj-$(CONFIG_KEYBOARD_CAP1106) += cap1106.o +obj-$(CONFIG_KEYBOARD_CAP11XX) += cap11xx.o obj-$(CONFIG_KEYBOARD_CLPS711X) += clps711x-keypad.o obj-$(CONFIG_KEYBOARD_CROS_EC) += cros_ec_keyb.o obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o diff --git a/drivers/input/keyboard/cap1106.c b/drivers/input/keyboard/cap1106.c deleted file mode 100644 index d70b65a14ced..000000000000 --- a/drivers/input/keyboard/cap1106.c +++ /dev/null @@ -1,341 +0,0 @@ -/* - * Input driver for Microchip CAP1106, 6 channel capacitive touch sensor - * - * http://www.microchip.com/wwwproducts/Devices.aspx?product=CAP1106 - * - * (c) 2014 Daniel Mack - * - * 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 - -#define CAP1106_REG_MAIN_CONTROL 0x00 -#define CAP1106_REG_MAIN_CONTROL_GAIN_SHIFT (6) -#define CAP1106_REG_MAIN_CONTROL_GAIN_MASK (0xc0) -#define CAP1106_REG_MAIN_CONTROL_DLSEEP BIT(4) -#define CAP1106_REG_GENERAL_STATUS 0x02 -#define CAP1106_REG_SENSOR_INPUT 0x03 -#define CAP1106_REG_NOISE_FLAG_STATUS 0x0a -#define CAP1106_REG_SENOR_DELTA(X) (0x10 + (X)) -#define CAP1106_REG_SENSITIVITY_CONTROL 0x1f -#define CAP1106_REG_CONFIG 0x20 -#define CAP1106_REG_SENSOR_ENABLE 0x21 -#define CAP1106_REG_SENSOR_CONFIG 0x22 -#define CAP1106_REG_SENSOR_CONFIG2 0x23 -#define CAP1106_REG_SAMPLING_CONFIG 0x24 -#define CAP1106_REG_CALIBRATION 0x26 -#define CAP1106_REG_INT_ENABLE 0x27 -#define CAP1106_REG_REPEAT_RATE 0x28 -#define CAP1106_REG_MT_CONFIG 0x2a -#define CAP1106_REG_MT_PATTERN_CONFIG 0x2b -#define CAP1106_REG_MT_PATTERN 0x2d -#define CAP1106_REG_RECALIB_CONFIG 0x2f -#define CAP1106_REG_SENSOR_THRESH(X) (0x30 + (X)) -#define CAP1106_REG_SENSOR_NOISE_THRESH 0x38 -#define CAP1106_REG_STANDBY_CHANNEL 0x40 -#define CAP1106_REG_STANDBY_CONFIG 0x41 -#define CAP1106_REG_STANDBY_SENSITIVITY 0x42 -#define CAP1106_REG_STANDBY_THRESH 0x43 -#define CAP1106_REG_CONFIG2 0x44 -#define CAP1106_REG_SENSOR_BASE_CNT(X) (0x50 + (X)) -#define CAP1106_REG_SENSOR_CALIB (0xb1 + (X)) -#define CAP1106_REG_SENSOR_CALIB_LSB1 0xb9 -#define CAP1106_REG_SENSOR_CALIB_LSB2 0xba -#define CAP1106_REG_PRODUCT_ID 0xfd -#define CAP1106_REG_MANUFACTURER_ID 0xfe -#define CAP1106_REG_REVISION 0xff - -#define CAP1106_NUM_CHN 6 -#define CAP1106_PRODUCT_ID 0x55 -#define CAP1106_MANUFACTURER_ID 0x5d - -struct cap1106_priv { - struct regmap *regmap; - struct input_dev *idev; - - /* config */ - unsigned short keycodes[CAP1106_NUM_CHN]; -}; - -static const struct reg_default cap1106_reg_defaults[] = { - { CAP1106_REG_MAIN_CONTROL, 0x00 }, - { CAP1106_REG_GENERAL_STATUS, 0x00 }, - { CAP1106_REG_SENSOR_INPUT, 0x00 }, - { CAP1106_REG_NOISE_FLAG_STATUS, 0x00 }, - { CAP1106_REG_SENSITIVITY_CONTROL, 0x2f }, - { CAP1106_REG_CONFIG, 0x20 }, - { CAP1106_REG_SENSOR_ENABLE, 0x3f }, - { CAP1106_REG_SENSOR_CONFIG, 0xa4 }, - { CAP1106_REG_SENSOR_CONFIG2, 0x07 }, - { CAP1106_REG_SAMPLING_CONFIG, 0x39 }, - { CAP1106_REG_CALIBRATION, 0x00 }, - { CAP1106_REG_INT_ENABLE, 0x3f }, - { CAP1106_REG_REPEAT_RATE, 0x3f }, - { CAP1106_REG_MT_CONFIG, 0x80 }, - { CAP1106_REG_MT_PATTERN_CONFIG, 0x00 }, - { CAP1106_REG_MT_PATTERN, 0x3f }, - { CAP1106_REG_RECALIB_CONFIG, 0x8a }, - { CAP1106_REG_SENSOR_THRESH(0), 0x40 }, - { CAP1106_REG_SENSOR_THRESH(1), 0x40 }, - { CAP1106_REG_SENSOR_THRESH(2), 0x40 }, - { CAP1106_REG_SENSOR_THRESH(3), 0x40 }, - { CAP1106_REG_SENSOR_THRESH(4), 0x40 }, - { CAP1106_REG_SENSOR_THRESH(5), 0x40 }, - { CAP1106_REG_SENSOR_NOISE_THRESH, 0x01 }, - { CAP1106_REG_STANDBY_CHANNEL, 0x00 }, - { CAP1106_REG_STANDBY_CONFIG, 0x39 }, - { CAP1106_REG_STANDBY_SENSITIVITY, 0x02 }, - { CAP1106_REG_STANDBY_THRESH, 0x40 }, - { CAP1106_REG_CONFIG2, 0x40 }, - { CAP1106_REG_SENSOR_CALIB_LSB1, 0x00 }, - { CAP1106_REG_SENSOR_CALIB_LSB2, 0x00 }, -}; - -static bool cap1106_volatile_reg(struct device *dev, unsigned int reg) -{ - switch (reg) { - case CAP1106_REG_MAIN_CONTROL: - case CAP1106_REG_SENSOR_INPUT: - case CAP1106_REG_SENOR_DELTA(0): - case CAP1106_REG_SENOR_DELTA(1): - case CAP1106_REG_SENOR_DELTA(2): - case CAP1106_REG_SENOR_DELTA(3): - case CAP1106_REG_SENOR_DELTA(4): - case CAP1106_REG_SENOR_DELTA(5): - case CAP1106_REG_PRODUCT_ID: - case CAP1106_REG_MANUFACTURER_ID: - case CAP1106_REG_REVISION: - return true; - } - - return false; -} - -static const struct regmap_config cap1106_regmap_config = { - .reg_bits = 8, - .val_bits = 8, - - .max_register = CAP1106_REG_REVISION, - .reg_defaults = cap1106_reg_defaults, - - .num_reg_defaults = ARRAY_SIZE(cap1106_reg_defaults), - .cache_type = REGCACHE_RBTREE, - .volatile_reg = cap1106_volatile_reg, -}; - -static irqreturn_t cap1106_thread_func(int irq_num, void *data) -{ - struct cap1106_priv *priv = data; - unsigned int status; - int ret, i; - - /* - * Deassert interrupt. This needs to be done before reading the status - * registers, which will not carry valid values otherwise. - */ - ret = regmap_update_bits(priv->regmap, CAP1106_REG_MAIN_CONTROL, 1, 0); - if (ret < 0) - goto out; - - ret = regmap_read(priv->regmap, CAP1106_REG_SENSOR_INPUT, &status); - if (ret < 0) - goto out; - - for (i = 0; i < CAP1106_NUM_CHN; i++) - input_report_key(priv->idev, priv->keycodes[i], - status & (1 << i)); - - input_sync(priv->idev); - -out: - return IRQ_HANDLED; -} - -static int cap1106_set_sleep(struct cap1106_priv *priv, bool sleep) -{ - return regmap_update_bits(priv->regmap, CAP1106_REG_MAIN_CONTROL, - CAP1106_REG_MAIN_CONTROL_DLSEEP, - sleep ? CAP1106_REG_MAIN_CONTROL_DLSEEP : 0); -} - -static int cap1106_input_open(struct input_dev *idev) -{ - struct cap1106_priv *priv = input_get_drvdata(idev); - - return cap1106_set_sleep(priv, false); -} - -static void cap1106_input_close(struct input_dev *idev) -{ - struct cap1106_priv *priv = input_get_drvdata(idev); - - cap1106_set_sleep(priv, true); -} - -static int cap1106_i2c_probe(struct i2c_client *i2c_client, - const struct i2c_device_id *id) -{ - struct device *dev = &i2c_client->dev; - struct cap1106_priv *priv; - struct device_node *node; - int i, error, irq, gain = 0; - unsigned int val, rev; - u32 gain32, keycodes[CAP1106_NUM_CHN]; - - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->regmap = devm_regmap_init_i2c(i2c_client, &cap1106_regmap_config); - if (IS_ERR(priv->regmap)) - return PTR_ERR(priv->regmap); - - error = regmap_read(priv->regmap, CAP1106_REG_PRODUCT_ID, &val); - if (error) - return error; - - if (val != CAP1106_PRODUCT_ID) { - dev_err(dev, "Product ID: Got 0x%02x, expected 0x%02x\n", - val, CAP1106_PRODUCT_ID); - return -ENODEV; - } - - error = regmap_read(priv->regmap, CAP1106_REG_MANUFACTURER_ID, &val); - if (error) - return error; - - if (val != CAP1106_MANUFACTURER_ID) { - dev_err(dev, "Manufacturer ID: Got 0x%02x, expected 0x%02x\n", - val, CAP1106_MANUFACTURER_ID); - return -ENODEV; - } - - error = regmap_read(priv->regmap, CAP1106_REG_REVISION, &rev); - if (error < 0) - return error; - - dev_info(dev, "CAP1106 detected, revision 0x%02x\n", rev); - i2c_set_clientdata(i2c_client, priv); - node = dev->of_node; - - if (!of_property_read_u32(node, "microchip,sensor-gain", &gain32)) { - if (is_power_of_2(gain32) && gain32 <= 8) - gain = ilog2(gain32); - else - dev_err(dev, "Invalid sensor-gain value %d\n", gain32); - } - - BUILD_BUG_ON(ARRAY_SIZE(keycodes) != ARRAY_SIZE(priv->keycodes)); - - /* Provide some useful defaults */ - for (i = 0; i < ARRAY_SIZE(keycodes); i++) - keycodes[i] = KEY_A + i; - - of_property_read_u32_array(node, "linux,keycodes", - keycodes, ARRAY_SIZE(keycodes)); - - for (i = 0; i < ARRAY_SIZE(keycodes); i++) - priv->keycodes[i] = keycodes[i]; - - error = regmap_update_bits(priv->regmap, CAP1106_REG_MAIN_CONTROL, - CAP1106_REG_MAIN_CONTROL_GAIN_MASK, - gain << CAP1106_REG_MAIN_CONTROL_GAIN_SHIFT); - if (error) - return error; - - /* Disable autorepeat. The Linux input system has its own handling. */ - error = regmap_write(priv->regmap, CAP1106_REG_REPEAT_RATE, 0); - if (error) - return error; - - priv->idev = devm_input_allocate_device(dev); - if (!priv->idev) - return -ENOMEM; - - priv->idev->name = "CAP1106 capacitive touch sensor"; - priv->idev->id.bustype = BUS_I2C; - priv->idev->evbit[0] = BIT_MASK(EV_KEY); - - if (of_property_read_bool(node, "autorepeat")) - __set_bit(EV_REP, priv->idev->evbit); - - for (i = 0; i < CAP1106_NUM_CHN; i++) - __set_bit(priv->keycodes[i], priv->idev->keybit); - - __clear_bit(KEY_RESERVED, priv->idev->keybit); - - priv->idev->keycode = priv->keycodes; - priv->idev->keycodesize = sizeof(priv->keycodes[0]); - priv->idev->keycodemax = ARRAY_SIZE(priv->keycodes); - - priv->idev->id.vendor = CAP1106_MANUFACTURER_ID; - priv->idev->id.product = CAP1106_PRODUCT_ID; - priv->idev->id.version = rev; - - priv->idev->open = cap1106_input_open; - priv->idev->close = cap1106_input_close; - - input_set_drvdata(priv->idev, priv); - - /* - * Put the device in deep sleep mode for now. - * ->open() will bring it back once the it is actually needed. - */ - cap1106_set_sleep(priv, true); - - error = input_register_device(priv->idev); - if (error) - return error; - - irq = irq_of_parse_and_map(node, 0); - if (!irq) { - dev_err(dev, "Unable to parse or map IRQ\n"); - return -ENXIO; - } - - error = devm_request_threaded_irq(dev, irq, NULL, cap1106_thread_func, - IRQF_ONESHOT, dev_name(dev), priv); - if (error) - return error; - - return 0; -} - -static const struct of_device_id cap1106_dt_ids[] = { - { .compatible = "microchip,cap1106", }, - {} -}; -MODULE_DEVICE_TABLE(of, cap1106_dt_ids); - -static const struct i2c_device_id cap1106_i2c_ids[] = { - { "cap1106", 0 }, - {} -}; -MODULE_DEVICE_TABLE(i2c, cap1106_i2c_ids); - -static struct i2c_driver cap1106_i2c_driver = { - .driver = { - .name = "cap1106", - .owner = THIS_MODULE, - .of_match_table = cap1106_dt_ids, - }, - .id_table = cap1106_i2c_ids, - .probe = cap1106_i2c_probe, -}; - -module_i2c_driver(cap1106_i2c_driver); - -MODULE_ALIAS("platform:cap1106"); -MODULE_DESCRIPTION("Microchip CAP1106 driver"); -MODULE_AUTHOR("Daniel Mack "); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/input/keyboard/cap11xx.c b/drivers/input/keyboard/cap11xx.c new file mode 100644 index 000000000000..0da2e838e788 --- /dev/null +++ b/drivers/input/keyboard/cap11xx.c @@ -0,0 +1,340 @@ +/* + * Input driver for Microchip CAP11xx based capacitive touch sensors + * + * + * (c) 2014 Daniel Mack + * + * 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 + +#define CAP11XX_REG_MAIN_CONTROL 0x00 +#define CAP11XX_REG_MAIN_CONTROL_GAIN_SHIFT (6) +#define CAP11XX_REG_MAIN_CONTROL_GAIN_MASK (0xc0) +#define CAP11XX_REG_MAIN_CONTROL_DLSEEP BIT(4) +#define CAP11XX_REG_GENERAL_STATUS 0x02 +#define CAP11XX_REG_SENSOR_INPUT 0x03 +#define CAP11XX_REG_NOISE_FLAG_STATUS 0x0a +#define CAP11XX_REG_SENOR_DELTA(X) (0x10 + (X)) +#define CAP11XX_REG_SENSITIVITY_CONTROL 0x1f +#define CAP11XX_REG_CONFIG 0x20 +#define CAP11XX_REG_SENSOR_ENABLE 0x21 +#define CAP11XX_REG_SENSOR_CONFIG 0x22 +#define CAP11XX_REG_SENSOR_CONFIG2 0x23 +#define CAP11XX_REG_SAMPLING_CONFIG 0x24 +#define CAP11XX_REG_CALIBRATION 0x26 +#define CAP11XX_REG_INT_ENABLE 0x27 +#define CAP11XX_REG_REPEAT_RATE 0x28 +#define CAP11XX_REG_MT_CONFIG 0x2a +#define CAP11XX_REG_MT_PATTERN_CONFIG 0x2b +#define CAP11XX_REG_MT_PATTERN 0x2d +#define CAP11XX_REG_RECALIB_CONFIG 0x2f +#define CAP11XX_REG_SENSOR_THRESH(X) (0x30 + (X)) +#define CAP11XX_REG_SENSOR_NOISE_THRESH 0x38 +#define CAP11XX_REG_STANDBY_CHANNEL 0x40 +#define CAP11XX_REG_STANDBY_CONFIG 0x41 +#define CAP11XX_REG_STANDBY_SENSITIVITY 0x42 +#define CAP11XX_REG_STANDBY_THRESH 0x43 +#define CAP11XX_REG_CONFIG2 0x44 +#define CAP11XX_REG_SENSOR_BASE_CNT(X) (0x50 + (X)) +#define CAP11XX_REG_SENSOR_CALIB (0xb1 + (X)) +#define CAP11XX_REG_SENSOR_CALIB_LSB1 0xb9 +#define CAP11XX_REG_SENSOR_CALIB_LSB2 0xba +#define CAP11XX_REG_PRODUCT_ID 0xfd +#define CAP11XX_REG_MANUFACTURER_ID 0xfe +#define CAP11XX_REG_REVISION 0xff + +#define CAP11XX_NUM_CHN 6 +#define CAP11XX_PRODUCT_ID 0x55 +#define CAP11XX_MANUFACTURER_ID 0x5d + +struct cap11xx_priv { + struct regmap *regmap; + struct input_dev *idev; + + /* config */ + unsigned short keycodes[CAP11XX_NUM_CHN]; +}; + +static const struct reg_default cap11xx_reg_defaults[] = { + { CAP11XX_REG_MAIN_CONTROL, 0x00 }, + { CAP11XX_REG_GENERAL_STATUS, 0x00 }, + { CAP11XX_REG_SENSOR_INPUT, 0x00 }, + { CAP11XX_REG_NOISE_FLAG_STATUS, 0x00 }, + { CAP11XX_REG_SENSITIVITY_CONTROL, 0x2f }, + { CAP11XX_REG_CONFIG, 0x20 }, + { CAP11XX_REG_SENSOR_ENABLE, 0x3f }, + { CAP11XX_REG_SENSOR_CONFIG, 0xa4 }, + { CAP11XX_REG_SENSOR_CONFIG2, 0x07 }, + { CAP11XX_REG_SAMPLING_CONFIG, 0x39 }, + { CAP11XX_REG_CALIBRATION, 0x00 }, + { CAP11XX_REG_INT_ENABLE, 0x3f }, + { CAP11XX_REG_REPEAT_RATE, 0x3f }, + { CAP11XX_REG_MT_CONFIG, 0x80 }, + { CAP11XX_REG_MT_PATTERN_CONFIG, 0x00 }, + { CAP11XX_REG_MT_PATTERN, 0x3f }, + { CAP11XX_REG_RECALIB_CONFIG, 0x8a }, + { CAP11XX_REG_SENSOR_THRESH(0), 0x40 }, + { CAP11XX_REG_SENSOR_THRESH(1), 0x40 }, + { CAP11XX_REG_SENSOR_THRESH(2), 0x40 }, + { CAP11XX_REG_SENSOR_THRESH(3), 0x40 }, + { CAP11XX_REG_SENSOR_THRESH(4), 0x40 }, + { CAP11XX_REG_SENSOR_THRESH(5), 0x40 }, + { CAP11XX_REG_SENSOR_NOISE_THRESH, 0x01 }, + { CAP11XX_REG_STANDBY_CHANNEL, 0x00 }, + { CAP11XX_REG_STANDBY_CONFIG, 0x39 }, + { CAP11XX_REG_STANDBY_SENSITIVITY, 0x02 }, + { CAP11XX_REG_STANDBY_THRESH, 0x40 }, + { CAP11XX_REG_CONFIG2, 0x40 }, + { CAP11XX_REG_SENSOR_CALIB_LSB1, 0x00 }, + { CAP11XX_REG_SENSOR_CALIB_LSB2, 0x00 }, +}; + +static bool cap11xx_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CAP11XX_REG_MAIN_CONTROL: + case CAP11XX_REG_SENSOR_INPUT: + case CAP11XX_REG_SENOR_DELTA(0): + case CAP11XX_REG_SENOR_DELTA(1): + case CAP11XX_REG_SENOR_DELTA(2): + case CAP11XX_REG_SENOR_DELTA(3): + case CAP11XX_REG_SENOR_DELTA(4): + case CAP11XX_REG_SENOR_DELTA(5): + case CAP11XX_REG_PRODUCT_ID: + case CAP11XX_REG_MANUFACTURER_ID: + case CAP11XX_REG_REVISION: + return true; + } + + return false; +} + +static const struct regmap_config cap11xx_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = CAP11XX_REG_REVISION, + .reg_defaults = cap11xx_reg_defaults, + + .num_reg_defaults = ARRAY_SIZE(cap11xx_reg_defaults), + .cache_type = REGCACHE_RBTREE, + .volatile_reg = cap11xx_volatile_reg, +}; + +static irqreturn_t cap11xx_thread_func(int irq_num, void *data) +{ + struct cap11xx_priv *priv = data; + unsigned int status; + int ret, i; + + /* + * Deassert interrupt. This needs to be done before reading the status + * registers, which will not carry valid values otherwise. + */ + ret = regmap_update_bits(priv->regmap, CAP11XX_REG_MAIN_CONTROL, 1, 0); + if (ret < 0) + goto out; + + ret = regmap_read(priv->regmap, CAP11XX_REG_SENSOR_INPUT, &status); + if (ret < 0) + goto out; + + for (i = 0; i < CAP11XX_NUM_CHN; i++) + input_report_key(priv->idev, priv->keycodes[i], + status & (1 << i)); + + input_sync(priv->idev); + +out: + return IRQ_HANDLED; +} + +static int cap11xx_set_sleep(struct cap11xx_priv *priv, bool sleep) +{ + return regmap_update_bits(priv->regmap, CAP11XX_REG_MAIN_CONTROL, + CAP11XX_REG_MAIN_CONTROL_DLSEEP, + sleep ? CAP11XX_REG_MAIN_CONTROL_DLSEEP : 0); +} + +static int cap11xx_input_open(struct input_dev *idev) +{ + struct cap11xx_priv *priv = input_get_drvdata(idev); + + return cap11xx_set_sleep(priv, false); +} + +static void cap11xx_input_close(struct input_dev *idev) +{ + struct cap11xx_priv *priv = input_get_drvdata(idev); + + cap11xx_set_sleep(priv, true); +} + +static int cap11xx_i2c_probe(struct i2c_client *i2c_client, + const struct i2c_device_id *id) +{ + struct device *dev = &i2c_client->dev; + struct cap11xx_priv *priv; + struct device_node *node; + int i, error, irq, gain = 0; + unsigned int val, rev; + u32 gain32, keycodes[CAP11XX_NUM_CHN]; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->regmap = devm_regmap_init_i2c(i2c_client, &cap11xx_regmap_config); + if (IS_ERR(priv->regmap)) + return PTR_ERR(priv->regmap); + + error = regmap_read(priv->regmap, CAP11XX_REG_PRODUCT_ID, &val); + if (error) + return error; + + if (val != CAP11XX_PRODUCT_ID) { + dev_err(dev, "Product ID: Got 0x%02x, expected 0x%02x\n", + val, CAP11XX_PRODUCT_ID); + return -ENODEV; + } + + error = regmap_read(priv->regmap, CAP11XX_REG_MANUFACTURER_ID, &val); + if (error) + return error; + + if (val != CAP11XX_MANUFACTURER_ID) { + dev_err(dev, "Manufacturer ID: Got 0x%02x, expected 0x%02x\n", + val, CAP11XX_MANUFACTURER_ID); + return -ENODEV; + } + + error = regmap_read(priv->regmap, CAP11XX_REG_REVISION, &rev); + if (error < 0) + return error; + + dev_info(dev, "CAP11XX detected, revision 0x%02x\n", rev); + i2c_set_clientdata(i2c_client, priv); + node = dev->of_node; + + if (!of_property_read_u32(node, "microchip,sensor-gain", &gain32)) { + if (is_power_of_2(gain32) && gain32 <= 8) + gain = ilog2(gain32); + else + dev_err(dev, "Invalid sensor-gain value %d\n", gain32); + } + + BUILD_BUG_ON(ARRAY_SIZE(keycodes) != ARRAY_SIZE(priv->keycodes)); + + /* Provide some useful defaults */ + for (i = 0; i < ARRAY_SIZE(keycodes); i++) + keycodes[i] = KEY_A + i; + + of_property_read_u32_array(node, "linux,keycodes", + keycodes, ARRAY_SIZE(keycodes)); + + for (i = 0; i < ARRAY_SIZE(keycodes); i++) + priv->keycodes[i] = keycodes[i]; + + error = regmap_update_bits(priv->regmap, CAP11XX_REG_MAIN_CONTROL, + CAP11XX_REG_MAIN_CONTROL_GAIN_MASK, + gain << CAP11XX_REG_MAIN_CONTROL_GAIN_SHIFT); + if (error) + return error; + + /* Disable autorepeat. The Linux input system has its own handling. */ + error = regmap_write(priv->regmap, CAP11XX_REG_REPEAT_RATE, 0); + if (error) + return error; + + priv->idev = devm_input_allocate_device(dev); + if (!priv->idev) + return -ENOMEM; + + priv->idev->name = "CAP11XX capacitive touch sensor"; + priv->idev->id.bustype = BUS_I2C; + priv->idev->evbit[0] = BIT_MASK(EV_KEY); + + if (of_property_read_bool(node, "autorepeat")) + __set_bit(EV_REP, priv->idev->evbit); + + for (i = 0; i < CAP11XX_NUM_CHN; i++) + __set_bit(priv->keycodes[i], priv->idev->keybit); + + __clear_bit(KEY_RESERVED, priv->idev->keybit); + + priv->idev->keycode = priv->keycodes; + priv->idev->keycodesize = sizeof(priv->keycodes[0]); + priv->idev->keycodemax = ARRAY_SIZE(priv->keycodes); + + priv->idev->id.vendor = CAP11XX_MANUFACTURER_ID; + priv->idev->id.product = CAP11XX_PRODUCT_ID; + priv->idev->id.version = rev; + + priv->idev->open = cap11xx_input_open; + priv->idev->close = cap11xx_input_close; + + input_set_drvdata(priv->idev, priv); + + /* + * Put the device in deep sleep mode for now. + * ->open() will bring it back once the it is actually needed. + */ + cap11xx_set_sleep(priv, true); + + error = input_register_device(priv->idev); + if (error) + return error; + + irq = irq_of_parse_and_map(node, 0); + if (!irq) { + dev_err(dev, "Unable to parse or map IRQ\n"); + return -ENXIO; + } + + error = devm_request_threaded_irq(dev, irq, NULL, cap11xx_thread_func, + IRQF_ONESHOT, dev_name(dev), priv); + if (error) + return error; + + return 0; +} + +static const struct of_device_id cap11xx_dt_ids[] = { + { .compatible = "microchip,cap1106", }, + {} +}; +MODULE_DEVICE_TABLE(of, cap11xx_dt_ids); + +static const struct i2c_device_id cap11xx_i2c_ids[] = { + { "cap1106", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, cap11xx_i2c_ids); + +static struct i2c_driver cap11xx_i2c_driver = { + .driver = { + .name = "cap11xx", + .owner = THIS_MODULE, + .of_match_table = cap11xx_dt_ids, + }, + .id_table = cap11xx_i2c_ids, + .probe = cap11xx_i2c_probe, +}; + +module_i2c_driver(cap11xx_i2c_driver); + +MODULE_ALIAS("platform:cap11xx"); +MODULE_DESCRIPTION("Microchip CAP11XX driver"); +MODULE_AUTHOR("Daniel Mack "); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-59-g8ed1b From 7609a5e973c43a647c4e40184fc8404311fdb97c Mon Sep 17 00:00:00 2001 From: Matt Ranostay Date: Fri, 31 Oct 2014 20:01:37 -0700 Subject: Input: cap11xx - add support for various cap11xx devices There are variants of the cap11xx device with a varying number of capacitance detection channels. Signed-off-by: Matt Ranostay Reviewed-by: Daniel Mack Signed-off-by: Dmitry Torokhov --- .../devicetree/bindings/input/cap11xx.txt | 3 +- drivers/input/keyboard/cap11xx.c | 74 +++++++++++++++------- 2 files changed, 53 insertions(+), 24 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/input/cap11xx.txt b/Documentation/devicetree/bindings/input/cap11xx.txt index 51649203658a..61d20d8d97e2 100644 --- a/Documentation/devicetree/bindings/input/cap11xx.txt +++ b/Documentation/devicetree/bindings/input/cap11xx.txt @@ -7,9 +7,10 @@ Required properties: compatible: Must contain one of: "microchip,cap1106" + "microchip,cap1126" + "microchip,cap1188" reg: The I2C slave address of the device. - Only 0x28 is valid. interrupts: Property describing the interrupt line the device's ALERT#/CM_IRQ# pin is connected to. diff --git a/drivers/input/keyboard/cap11xx.c b/drivers/input/keyboard/cap11xx.c index 0da2e838e788..eeda1f9359cd 100644 --- a/drivers/input/keyboard/cap11xx.c +++ b/drivers/input/keyboard/cap11xx.c @@ -1,7 +1,6 @@ /* * Input driver for Microchip CAP11xx based capacitive touch sensors * - * * (c) 2014 Daniel Mack * * This program is free software; you can redistribute it and/or modify @@ -54,8 +53,6 @@ #define CAP11XX_REG_MANUFACTURER_ID 0xfe #define CAP11XX_REG_REVISION 0xff -#define CAP11XX_NUM_CHN 6 -#define CAP11XX_PRODUCT_ID 0x55 #define CAP11XX_MANUFACTURER_ID 0x5d struct cap11xx_priv { @@ -63,7 +60,24 @@ struct cap11xx_priv { struct input_dev *idev; /* config */ - unsigned short keycodes[CAP11XX_NUM_CHN]; + u32 keycodes[]; +}; + +struct cap11xx_hw_model { + u8 product_id; + unsigned int num_channels; +}; + +enum { + CAP1106, + CAP1126, + CAP1188, +}; + +static const struct cap11xx_hw_model cap11xx_devices[] = { + [CAP1106] = { .product_id = 0x55, .num_channels = 6 }, + [CAP1126] = { .product_id = 0x53, .num_channels = 6 }, + [CAP1188] = { .product_id = 0x50, .num_channels = 8 }, }; static const struct reg_default cap11xx_reg_defaults[] = { @@ -150,7 +164,7 @@ static irqreturn_t cap11xx_thread_func(int irq_num, void *data) if (ret < 0) goto out; - for (i = 0; i < CAP11XX_NUM_CHN; i++) + for (i = 0; i < priv->idev->keycodemax; i++) input_report_key(priv->idev, priv->keycodes[i], status & (1 << i)); @@ -187,11 +201,26 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client, struct device *dev = &i2c_client->dev; struct cap11xx_priv *priv; struct device_node *node; + const struct cap11xx_hw_model *cap; int i, error, irq, gain = 0; unsigned int val, rev; - u32 gain32, keycodes[CAP11XX_NUM_CHN]; + u32 gain32; - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (id->driver_data >= ARRAY_SIZE(cap11xx_devices)) { + dev_err(dev, "Invalid device ID %lu\n", id->driver_data); + return -EINVAL; + } + + cap = &cap11xx_devices[id->driver_data]; + if (!cap || !cap->num_channels) { + dev_err(dev, "Invalid device configuration\n"); + return -EINVAL; + } + + priv = devm_kzalloc(dev, + sizeof(*priv) + + cap->num_channels * sizeof(priv->keycodes[0]), + GFP_KERNEL); if (!priv) return -ENOMEM; @@ -203,10 +232,10 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client, if (error) return error; - if (val != CAP11XX_PRODUCT_ID) { + if (val != cap->product_id) { dev_err(dev, "Product ID: Got 0x%02x, expected 0x%02x\n", - val, CAP11XX_PRODUCT_ID); - return -ENODEV; + val, cap->product_id); + return -ENXIO; } error = regmap_read(priv->regmap, CAP11XX_REG_MANUFACTURER_ID, &val); @@ -216,7 +245,7 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client, if (val != CAP11XX_MANUFACTURER_ID) { dev_err(dev, "Manufacturer ID: Got 0x%02x, expected 0x%02x\n", val, CAP11XX_MANUFACTURER_ID); - return -ENODEV; + return -ENXIO; } error = regmap_read(priv->regmap, CAP11XX_REG_REVISION, &rev); @@ -234,17 +263,12 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client, dev_err(dev, "Invalid sensor-gain value %d\n", gain32); } - BUILD_BUG_ON(ARRAY_SIZE(keycodes) != ARRAY_SIZE(priv->keycodes)); - /* Provide some useful defaults */ - for (i = 0; i < ARRAY_SIZE(keycodes); i++) - keycodes[i] = KEY_A + i; + for (i = 0; i < cap->num_channels; i++) + priv->keycodes[i] = KEY_A + i; of_property_read_u32_array(node, "linux,keycodes", - keycodes, ARRAY_SIZE(keycodes)); - - for (i = 0; i < ARRAY_SIZE(keycodes); i++) - priv->keycodes[i] = keycodes[i]; + priv->keycodes, cap->num_channels); error = regmap_update_bits(priv->regmap, CAP11XX_REG_MAIN_CONTROL, CAP11XX_REG_MAIN_CONTROL_GAIN_MASK, @@ -268,17 +292,17 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client, if (of_property_read_bool(node, "autorepeat")) __set_bit(EV_REP, priv->idev->evbit); - for (i = 0; i < CAP11XX_NUM_CHN; i++) + for (i = 0; i < cap->num_channels; i++) __set_bit(priv->keycodes[i], priv->idev->keybit); __clear_bit(KEY_RESERVED, priv->idev->keybit); priv->idev->keycode = priv->keycodes; priv->idev->keycodesize = sizeof(priv->keycodes[0]); - priv->idev->keycodemax = ARRAY_SIZE(priv->keycodes); + priv->idev->keycodemax = cap->num_channels; priv->idev->id.vendor = CAP11XX_MANUFACTURER_ID; - priv->idev->id.product = CAP11XX_PRODUCT_ID; + priv->idev->id.product = cap->product_id; priv->idev->id.version = rev; priv->idev->open = cap11xx_input_open; @@ -312,12 +336,16 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client, static const struct of_device_id cap11xx_dt_ids[] = { { .compatible = "microchip,cap1106", }, + { .compatible = "microchip,cap1126", }, + { .compatible = "microchip,cap1188", }, {} }; MODULE_DEVICE_TABLE(of, cap11xx_dt_ids); static const struct i2c_device_id cap11xx_i2c_ids[] = { - { "cap1106", 0 }, + { "cap1106", CAP1106 }, + { "cap1126", CAP1126 }, + { "cap1188", CAP1188 }, {} }; MODULE_DEVICE_TABLE(i2c, cap11xx_i2c_ids); -- cgit v1.2.3-59-g8ed1b From 6bdd2fd1ed6f66597f3cff75c1bb1569beec2fc9 Mon Sep 17 00:00:00 2001 From: Matt Ranostay Date: Fri, 31 Oct 2014 20:02:08 -0700 Subject: Input: cap11xx - support for irq-active-high option Some applications need to use the irq-active-high push-pull option. This allows it be enabled in the device tree child node. Signed-off-by: Matt Ranostay Reviewed-by: Daniel Mack Signed-off-by: Dmitry Torokhov --- Documentation/devicetree/bindings/input/cap11xx.txt | 4 ++++ drivers/input/keyboard/cap11xx.c | 8 ++++++++ 2 files changed, 12 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/input/cap11xx.txt b/Documentation/devicetree/bindings/input/cap11xx.txt index 61d20d8d97e2..7d0a3009771b 100644 --- a/Documentation/devicetree/bindings/input/cap11xx.txt +++ b/Documentation/devicetree/bindings/input/cap11xx.txt @@ -28,6 +28,10 @@ Optional properties: Valid values are 1, 2, 4, and 8. By default, a gain of 1 is set. + microchip,irq-active-high: By default the interrupt pin is active low + open drain. This property allows using the active + high push-pull output. + linux,keycodes: Specifies an array of numeric keycode values to be used for the channels. If this property is omitted, KEY_A, KEY_B, etc are used as diff --git a/drivers/input/keyboard/cap11xx.c b/drivers/input/keyboard/cap11xx.c index eeda1f9359cd..4f59f0bab28f 100644 --- a/drivers/input/keyboard/cap11xx.c +++ b/drivers/input/keyboard/cap11xx.c @@ -45,6 +45,7 @@ #define CAP11XX_REG_STANDBY_SENSITIVITY 0x42 #define CAP11XX_REG_STANDBY_THRESH 0x43 #define CAP11XX_REG_CONFIG2 0x44 +#define CAP11XX_REG_CONFIG2_ALT_POL BIT(6) #define CAP11XX_REG_SENSOR_BASE_CNT(X) (0x50 + (X)) #define CAP11XX_REG_SENSOR_CALIB (0xb1 + (X)) #define CAP11XX_REG_SENSOR_CALIB_LSB1 0xb9 @@ -263,6 +264,13 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client, dev_err(dev, "Invalid sensor-gain value %d\n", gain32); } + if (of_property_read_bool(node, "microchip,irq-active-high")) { + error = regmap_update_bits(priv->regmap, CAP11XX_REG_CONFIG2, + CAP11XX_REG_CONFIG2_ALT_POL, 0); + if (error) + return error; + } + /* Provide some useful defaults */ for (i = 0; i < cap->num_channels; i++) priv->keycodes[i] = KEY_A + i; -- cgit v1.2.3-59-g8ed1b From ccfe128d3b4735ac1750d27010ad4b0c8693eefb Mon Sep 17 00:00:00 2001 From: Romain Perier Date: Sun, 2 Nov 2014 10:20:01 +0000 Subject: ARM: dts: rockchip: Add devicetree source for MarsBoard RK3066 This patch adds initial support for the Marsboard RK3066. It enables EMAC Rockchip which is the ethernet support on the board and registers it as a supported rockchip platform. Signed-off-by: Romain Perier Signed-off-by: Heiko Stuebner --- Documentation/devicetree/bindings/arm/rockchip.txt | 4 + arch/arm/boot/dts/Makefile | 1 + arch/arm/boot/dts/rk3066a-marsboard.dts | 192 +++++++++++++++++++++ 3 files changed, 197 insertions(+) create mode 100644 arch/arm/boot/dts/rk3066a-marsboard.dts (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/rockchip.txt b/Documentation/devicetree/bindings/arm/rockchip.txt index 857f12636eb2..eaa3d1a0eb05 100644 --- a/Documentation/devicetree/bindings/arm/rockchip.txt +++ b/Documentation/devicetree/bindings/arm/rockchip.txt @@ -1,6 +1,10 @@ Rockchip platforms device tree bindings --------------------------------------- +- MarsBoard RK3066 board: + Required root node properties: + - compatible = "haoyu,marsboard-rk3066", "rockchip,rk3066a"; + - bq Curie 2 tablet: Required root node properties: - compatible = "mundoreader,bq-curie2", "rockchip,rk3066a"; diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 38c89cafa1ab..45dc351a81fc 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -365,6 +365,7 @@ dtb-$(CONFIG_ARCH_QCOM) += \ qcom-msm8974-sony-xperia-honami.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += \ rk3066a-bqcurie2.dtb \ + rk3066a-marsboard.dtb \ rk3188-radxarock.dtb \ rk3288-evb-act8846.dtb \ rk3288-evb-rk808.dtb diff --git a/arch/arm/boot/dts/rk3066a-marsboard.dts b/arch/arm/boot/dts/rk3066a-marsboard.dts new file mode 100644 index 000000000000..57489ee54022 --- /dev/null +++ b/arch/arm/boot/dts/rk3066a-marsboard.dts @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2014 Romain Perier + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file 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 file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/dts-v1/; +#include "rk3066a.dtsi" + +/ { + model = "MarsBoard RK3066"; + compatible = "haoyu,marsboard-rk3066", "rockchip,rk3066a"; + + memory { + reg = <0x60000000 0x40000000>; + }; + + vcc_sd0: sdmmc-regulator { + compatible = "regulator-fixed"; + regulator-name = "sdmmc-supply"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + gpio = <&gpio3 7 GPIO_ACTIVE_LOW>; + startup-delay-us = <100000>; + vin-supply = <&vcc_io>; + }; +}; + +&i2c1 { + status = "okay"; + clock-frequency = <400000>; + + tps: tps@2d { + reg = <0x2d>; + + interrupt-parent = <&gpio6>; + interrupts = <4 IRQ_TYPE_LEVEL_LOW>; + + vcc5-supply = <&vcc_io>; + vcc6-supply = <&vcc_io>; + + regulators { + vcc_rtc: regulator@0 { + regulator-name = "vcc_rtc"; + regulator-always-on; + }; + + vcc_io: regulator@1 { + regulator-name = "vcc_io"; + regulator-always-on; + }; + + vdd_arm: regulator@2 { + regulator-name = "vdd_arm"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <1500000>; + regulator-boot-on; + regulator-always-on; + }; + + vcc_ddr: regulator@3 { + regulator-name = "vcc_ddr"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <1500000>; + regulator-boot-on; + regulator-always-on; + }; + + vcc18_cif: regulator@5 { + regulator-name = "vcc18_cif"; + regulator-always-on; + }; + + vdd_11: regulator@6 { + regulator-name = "vdd_11"; + regulator-always-on; + }; + + vcc_25: regulator@7 { + regulator-name = "vcc_25"; + regulator-always-on; + }; + + vcc_18: regulator@8 { + regulator-name = "vcc_18"; + regulator-always-on; + }; + + vcc25_hdmi: regulator@9 { + regulator-name = "vcc25_hdmi"; + regulator-always-on; + }; + + vcca_33: regulator@10 { + regulator-name = "vcca_33"; + regulator-always-on; + }; + + vcc_rmii: regulator@11 { + regulator-name = "vcc_rmii"; + }; + + vcc28_cif: regulator@12 { + regulator-name = "vcc28_cif"; + regulator-always-on; + }; + }; + }; +}; + +/* must be included after &tps gets defined */ +#include "tps65910.dtsi" + +&emac { + status = "okay"; + + phy = <&phy0>; + phy-supply = <&vcc_rmii>; + + pinctrl-names = "default"; + pinctrl-0 = <&emac_xfer>, <&emac_mdio>, <&phy_int>; + + phy0: ethernet-phy@0 { + reg = <0>; + interrupt-parent = <&gpio1>; + interrupts = <26 IRQ_TYPE_LEVEL_LOW>; + }; +}; + +&pinctrl { + lan8720a { + phy_int: phy-int { + rockchip,pins = ; + }; + }; +}; + +&uart0 { + status = "okay"; +}; + +&uart1 { + status = "okay"; +}; + +&uart2 { + status = "okay"; +}; + +&uart3 { + status = "okay"; +}; + +&wdt { + status = "okay"; +}; -- cgit v1.2.3-59-g8ed1b From 91690bf32ee12a85caf497ec01cfb47c0b298bac Mon Sep 17 00:00:00 2001 From: Tiejun Chen Date: Sat, 11 Oct 2014 09:19:54 +0800 Subject: Documentation: virtual: kvm: correct one bit description in APF case When commit 6adba5274206 (KVM: Let host know whether the guest can handle async PF in non-userspace context.) is introduced, actually bit 2 still is reserved and should be zero. Instead, bit 1 is 1 to indicate if asynchronous page faults can be injected when vcpu is in cpl == 0, and also please see this, in the file kvm_para.h, #define KVM_ASYNC_PF_SEND_ALWAYS (1 << 1). Signed-off-by: Tiejun Chen Signed-off-by: Paolo Bonzini --- Documentation/virtual/kvm/msr.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/virtual/kvm/msr.txt b/Documentation/virtual/kvm/msr.txt index 6d470ae7b073..2a71c8f29f68 100644 --- a/Documentation/virtual/kvm/msr.txt +++ b/Documentation/virtual/kvm/msr.txt @@ -168,7 +168,7 @@ MSR_KVM_ASYNC_PF_EN: 0x4b564d02 64 byte memory area which must be in guest RAM and must be zeroed. Bits 5-2 are reserved and should be zero. Bit 0 is 1 when asynchronous page faults are enabled on the vcpu 0 when - disabled. Bit 2 is 1 if asynchronous page faults can be injected + disabled. Bit 1 is 1 if asynchronous page faults can be injected when vcpu is in cpl == 0. First 4 byte of 64 byte memory location will be written to by -- cgit v1.2.3-59-g8ed1b From 7f05db6a20fe4d85bada20d365c78029831b9de1 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Sun, 12 Oct 2014 11:34:00 +0300 Subject: kvm: drop unsupported capabilities, fix documentation No kernel ever reported KVM_CAP_DEVICE_MSIX, KVM_CAP_DEVICE_MSI, KVM_CAP_DEVICE_ASSIGNMENT, KVM_CAP_DEVICE_DEASSIGNMENT. This makes the documentation wrong, and no application ever written to use these capabilities has a chance to work correctly. The only way to detect support is to try, and test errno for ENOTTY. That's unfortunate, but we can't fix the past. Document the actual semantics, and drop the definitions from the exported header to make it easier for application developers to note and fix the bug. Signed-off-by: Michael S. Tsirkin Signed-off-by: Paolo Bonzini --- Documentation/virtual/kvm/api.txt | 40 ++++++++++++++++++++++++++++++++------- include/uapi/linux/kvm.h | 8 -------- 2 files changed, 33 insertions(+), 15 deletions(-) (limited to 'Documentation') diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 7610eaa4d491..7a943c23db1c 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -68,9 +68,12 @@ description: Capability: which KVM extension provides this ioctl. Can be 'basic', which means that is will be provided by any kernel that supports - API version 12 (see section 4.1), or a KVM_CAP_xyz constant, which + API version 12 (see section 4.1), a KVM_CAP_xyz constant, which means availability needs to be checked with KVM_CHECK_EXTENSION - (see section 4.4). + (see section 4.4), or 'none' which means that while not all kernels + support this ioctl, there's no capability bit to check its + availability: for kernels that don't support the ioctl, + the ioctl returns -ENOTTY. Architectures: which instruction set architectures provide this ioctl. x86 includes both i386 and x86_64. @@ -1257,7 +1260,7 @@ The flags bitmap is defined as: 4.48 KVM_ASSIGN_PCI_DEVICE -Capability: KVM_CAP_DEVICE_ASSIGNMENT +Capability: none Architectures: x86 ia64 Type: vm ioctl Parameters: struct kvm_assigned_pci_dev (in) @@ -1298,10 +1301,16 @@ Only PCI header type 0 devices with PCI BAR resources are supported by device assignment. The user requesting this ioctl must have read/write access to the PCI sysfs resource files associated with the device. +Errors: + ENOTTY: kernel does not support this ioctl + + Other error conditions may be defined by individual device types or + have their standard meanings. + 4.49 KVM_DEASSIGN_PCI_DEVICE -Capability: KVM_CAP_DEVICE_DEASSIGNMENT +Capability: none Architectures: x86 ia64 Type: vm ioctl Parameters: struct kvm_assigned_pci_dev (in) @@ -1309,9 +1318,14 @@ Returns: 0 on success, -1 on error Ends PCI device assignment, releasing all associated resources. -See KVM_CAP_DEVICE_ASSIGNMENT for the data structure. Only assigned_dev_id is +See KVM_ASSIGN_PCI_DEVICE for the data structure. Only assigned_dev_id is used in kvm_assigned_pci_dev to identify the device. +Errors: + ENOTTY: kernel does not support this ioctl + + Other error conditions may be defined by individual device types or + have their standard meanings. 4.50 KVM_ASSIGN_DEV_IRQ @@ -1346,6 +1360,12 @@ The following flags are defined: It is not valid to specify multiple types per host or guest IRQ. However, the IRQ type of host and guest can differ or can even be null. +Errors: + ENOTTY: kernel does not support this ioctl + + Other error conditions may be defined by individual device types or + have their standard meanings. + 4.51 KVM_DEASSIGN_DEV_IRQ @@ -1423,7 +1443,7 @@ struct kvm_irq_routing_s390_adapter { 4.53 KVM_ASSIGN_SET_MSIX_NR -Capability: KVM_CAP_DEVICE_MSIX +Capability: none Architectures: x86 ia64 Type: vm ioctl Parameters: struct kvm_assigned_msix_nr (in) @@ -1445,7 +1465,7 @@ struct kvm_assigned_msix_nr { 4.54 KVM_ASSIGN_SET_MSIX_ENTRY -Capability: KVM_CAP_DEVICE_MSIX +Capability: none Architectures: x86 ia64 Type: vm ioctl Parameters: struct kvm_assigned_msix_entry (in) @@ -1461,6 +1481,12 @@ struct kvm_assigned_msix_entry { __u16 padding[3]; }; +Errors: + ENOTTY: kernel does not support this ioctl + + Other error conditions may be defined by individual device types or + have their standard meanings. + 4.55 KVM_SET_TSC_KHZ diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 60768822b140..6d59e5b39c9c 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -647,11 +647,7 @@ struct kvm_ppc_smmu_info { #define KVM_CAP_MP_STATE 14 #define KVM_CAP_COALESCED_MMIO 15 #define KVM_CAP_SYNC_MMU 16 /* Changes to host mmap are reflected in guest */ -#define KVM_CAP_DEVICE_ASSIGNMENT 17 #define KVM_CAP_IOMMU 18 -#ifdef __KVM_HAVE_MSI -#define KVM_CAP_DEVICE_MSI 20 -#endif /* Bug in KVM_SET_USER_MEMORY_REGION fixed: */ #define KVM_CAP_DESTROY_MEMORY_REGION_WORKS 21 #define KVM_CAP_USER_NMI 22 @@ -663,10 +659,6 @@ struct kvm_ppc_smmu_info { #endif #define KVM_CAP_IRQ_ROUTING 25 #define KVM_CAP_IRQ_INJECT_STATUS 26 -#define KVM_CAP_DEVICE_DEASSIGNMENT 27 -#ifdef __KVM_HAVE_MSIX -#define KVM_CAP_DEVICE_MSIX 28 -#endif #define KVM_CAP_ASSIGN_DEV_IRQ 29 /* Another bug in KVM_SET_USER_MEMORY_REGION fixed: */ #define KVM_CAP_JOIN_MEMORY_REGIONS_WORKS 30 -- cgit v1.2.3-59-g8ed1b From c99ade664177db9a73400465470b5bd25309c14e Mon Sep 17 00:00:00 2001 From: Doug Anderson Date: Fri, 31 Oct 2014 20:52:57 -0700 Subject: regulator: Document binding for regulator suspend voltage This patch builds upon (291d761 regulator: Document binding for regulator suspend state for PM state) to allow setting the uV in addition to the state at suspend time. Signed-off-by: Doug Anderson Reviewed-by: Javier Martinez Canillas Reviewed-by: Chris Zhong Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/regulator/regulator.txt | 2 ++ 1 file changed, 2 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/regulator/regulator.txt b/Documentation/devicetree/bindings/regulator/regulator.txt index aaad615899d2..4e7ed762b3bb 100644 --- a/Documentation/devicetree/bindings/regulator/regulator.txt +++ b/Documentation/devicetree/bindings/regulator/regulator.txt @@ -28,6 +28,8 @@ Optional properties: - regulator-state-[mem/disk] node has following common properties: - regulator-on-in-suspend: regulator should be on in suspend state. - regulator-off-in-suspend: regulator should be off in suspend state. + - regulator-suspend-microvolt: regulator should be set to this voltage + in suspend. Deprecated properties: - regulator-compatible: If a regulator chip contains multiple -- cgit v1.2.3-59-g8ed1b From 8d6d514941d37bd3625bc8ab99a042fbccdaa0da Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 3 Nov 2014 11:35:01 -0200 Subject: [media] Update Documentation cardlist Some new devices got added. Update cardlists. Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.cx23885 | 2 ++ Documentation/video4linux/CARDLIST.em28xx | 1 + Documentation/video4linux/CARDLIST.saa7134 | 1 + 3 files changed, 4 insertions(+) (limited to 'Documentation') diff --git a/Documentation/video4linux/CARDLIST.cx23885 b/Documentation/video4linux/CARDLIST.cx23885 index a74eeccfe700..4c84ec853265 100644 --- a/Documentation/video4linux/CARDLIST.cx23885 +++ b/Documentation/video4linux/CARDLIST.cx23885 @@ -43,3 +43,5 @@ 42 -> Leadtek Winfast PxPVR2200 [107d:6f21] 43 -> Hauppauge ImpactVCB-e [0070:7133] 44 -> DViCO FusionHDTV DVB-T Dual Express2 [18ac:db98] + 45 -> DVBSky T9580 [4254:9580] + 46 -> DVBSky T980C [4254:980c] diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx index bc3351bb48b4..3700edb81db2 100644 --- a/Documentation/video4linux/CARDLIST.em28xx +++ b/Documentation/video4linux/CARDLIST.em28xx @@ -93,3 +93,4 @@ 92 -> PCTV DVB-S2 Stick (461e) (em28178) 93 -> KWorld USB ATSC TV Stick UB435-Q V3 (em2874) [1b80:e34c] 94 -> PCTV tripleStick (292e) (em28178) + 95 -> Leadtek VC100 (em2861) [0413:6f07] diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134 index 8df17d063499..a93d86455233 100644 --- a/Documentation/video4linux/CARDLIST.saa7134 +++ b/Documentation/video4linux/CARDLIST.saa7134 @@ -191,3 +191,4 @@ 190 -> Asus My Cinema PS3-100 [1043:48cd] 191 -> Hawell HW-9004V1 192 -> AverMedia AverTV Satellite Hybrid+FM A706 [1461:2055] +193 -> WIS Voyager or compatible [1905:7007] -- cgit v1.2.3-59-g8ed1b From f2918ad89df5a5deb4773e13b5f6e21eabfce282 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 10 Oct 2014 15:21:56 -0500 Subject: usb: gadget: udc: document our sysfs ABI I noticed that this has been missing for quite some time so I decided it was about time to document it. Signed-off-by: Felipe Balbi --- Documentation/ABI/stable/sysfs-class-udc | 93 ++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 Documentation/ABI/stable/sysfs-class-udc (limited to 'Documentation') diff --git a/Documentation/ABI/stable/sysfs-class-udc b/Documentation/ABI/stable/sysfs-class-udc new file mode 100644 index 000000000000..85d3dac2e204 --- /dev/null +++ b/Documentation/ABI/stable/sysfs-class-udc @@ -0,0 +1,93 @@ +What: /sys/class/udc//a_alt_hnp_support +Date: June 2011 +KernelVersion: 3.1 +Contact: Felipe Balbi +Description: + Indicates if an OTG A-Host supports HNP at an alternate port. +Users: + +What: /sys/class/udc//a_hnp_support +Date: June 2011 +KernelVersion: 3.1 +Contact: Felipe Balbi +Description: + Indicates if an OTG A-Host supports HNP at this port. +Users: + +What: /sys/class/udc//b_hnp_enable +Date: June 2011 +KernelVersion: 3.1 +Contact: Felipe Balbi +Description: + Indicates if an OTG A-Host enabled HNP support. +Users: + +What: /sys/class/udc//current_speed +Date: June 2011 +KernelVersion: 3.1 +Contact: Felipe Balbi +Description: + Indicates the current negotiated speed at this port. +Users: + +What: /sys/class/udc//is_a_peripheral +Date: June 2011 +KernelVersion: 3.1 +Contact: Felipe Balbi +Description: + Indicates that this port is the default Host on an OTG session + but HNP was used to switch roles. +Users: + +What: /sys/class/udc//is_otg +Date: June 2011 +KernelVersion: 3.1 +Contact: Felipe Balbi +Description: + Indicates that this port support OTG. +Users: + +What: /sys/class/udc//maximum_speed +Date: June 2011 +KernelVersion: 3.1 +Contact: Felipe Balbi +Description: + Indicates the maximum USB speed supported by this port. +Users: + +What: /sys/class/udc//maximum_speed +Date: June 2011 +KernelVersion: 3.1 +Contact: Felipe Balbi +Description: + Indicates the maximum USB speed supported by this port. +Users: + +What: /sys/class/udc//soft_connect +Date: June 2011 +KernelVersion: 3.1 +Contact: Felipe Balbi +Description: + Allows users to disconnect data pullup resistors thus causing a + logical disconnection from the USB Host. +Users: + +What: /sys/class/udc//srp +Date: June 2011 +KernelVersion: 3.1 +Contact: Felipe Balbi +Description: + Allows users to manually start Session Request Protocol. +Users: + +What: /sys/class/udc//state +Date: June 2011 +KernelVersion: 3.1 +Contact: Felipe Balbi +Description: + Indicates current state of the USB Device Controller. Valid + states are: 'not-attached', 'attached', 'powered', + 'reconnecting', 'unauthenticated', 'default', 'addressed', + 'configured', and 'suspended'; however not all USB Device + Controllers support reporting all states. +Users: -- cgit v1.2.3-59-g8ed1b From 545d64a46c1ed04eb96802a3bf5b6627c4d28dbd Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Fri, 17 Oct 2014 22:43:04 +0200 Subject: usb: gadget: pxa27x_udc device-tree documentation Add documentation for device-tree binding of arm PXA 27x udc (usb device) driver. Signed-off-by: Robert Jarzmik Cc: devicetree@vger.kernel.org Acked-by: Arnd Bergmann Signed-off-by: Felipe Balbi --- Documentation/devicetree/bindings/usb/pxa-usb.txt | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/usb/pxa-usb.txt b/Documentation/devicetree/bindings/usb/pxa-usb.txt index 79729a948d5a..9c331799b87c 100644 --- a/Documentation/devicetree/bindings/usb/pxa-usb.txt +++ b/Documentation/devicetree/bindings/usb/pxa-usb.txt @@ -29,3 +29,25 @@ Example: marvell,port-mode = <2>; /* PMM_GLOBAL_MODE */ }; +UDC + +Required properties: + - compatible: Should be "marvell,pxa270-udc" for USB controllers + used in device mode. + - reg: usb device MMIO address space + - interrupts: single interrupt generated by the UDC IP + - clocks: input clock of the UDC IP (see clock-bindings.txt) + +Optional properties: + - gpios: + - gpio activated to control the USB D+ pullup (see gpio.txt) + +Example: + + pxa27x_udc: udc@40600000 { + compatible = "marvell,pxa270-udc"; + reg = <0x40600000 0x10000>; + interrupts = <11>; + clocks = <&pxa2xx_clks 11>; + gpios = <&gpio 22 GPIO_ACTIVE_LOW>; + }; -- cgit v1.2.3-59-g8ed1b From 3b81221a529c087171557d7c4aec02b0ba029bb1 Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Tue, 28 Oct 2014 19:54:25 +0800 Subject: usb: dwc3: add disscramble quirk This patch adds disscramble quirk, and it only needs to be enabled at fpga board on some vendor platforms. Signed-off-by: Huang Rui Signed-off-by: Felipe Balbi --- Documentation/devicetree/bindings/usb/dwc3.txt | 2 ++ drivers/usb/dwc3/core.c | 14 +++++++++++++- drivers/usb/dwc3/core.h | 3 +++ drivers/usb/dwc3/platform_data.h | 2 ++ 4 files changed, 20 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt index 471366d6a129..8ec2256a4a09 100644 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ b/Documentation/devicetree/bindings/usb/dwc3.txt @@ -14,6 +14,8 @@ 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,disable_scramble_quirk: true when SW should disable data scrambling. + Only really useful for FPGA builds. This is usually a subnode to DWC3 glue to which it is connected. diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 9830f87b6940..a0ae1326b7e3 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -422,7 +422,6 @@ static int dwc3_core_init(struct dwc3 *dwc) reg = dwc3_readl(dwc->regs, DWC3_GCTL); reg &= ~DWC3_GCTL_SCALEDOWN_MASK; - reg &= ~DWC3_GCTL_DISSCRAMBLE; switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) { case DWC3_GHWPARAMS1_EN_PWROPT_CLK: @@ -466,6 +465,14 @@ static int dwc3_core_init(struct dwc3 *dwc) dwc->is_fpga = true; } + WARN_ONCE(dwc->disable_scramble_quirk && !dwc->is_fpga, + "disable_scramble cannot be used on non-FPGA builds\n"); + + if (dwc->disable_scramble_quirk && dwc->is_fpga) + reg |= DWC3_GCTL_DISSCRAMBLE; + else + reg &= ~DWC3_GCTL_DISSCRAMBLE; + /* * WORKAROUND: DWC3 revisions <1.90a have a bug * where the device can fail to connect at SuperSpeed @@ -710,11 +717,16 @@ static int dwc3_probe(struct platform_device *pdev) dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize"); dwc->dr_mode = of_usb_get_dr_mode(node); + + dwc->disable_scramble_quirk = of_property_read_bool(node, + "snps,disable_scramble_quirk"); } else if (pdata) { dwc->maximum_speed = pdata->maximum_speed; dwc->needs_fifo_resize = pdata->tx_fifo_resize; dwc->dr_mode = pdata->dr_mode; + + dwc->disable_scramble_quirk = pdata->disable_scramble_quirk; } /* default to superspeed if no maximum_speed passed */ diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index f6ee623e2d1b..56bada6c8604 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -672,6 +672,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 + * @disable_scramble_quirk: set if we enable the disable scramble quirk */ struct dwc3 { struct usb_ctrlrequest *ctrl_req; @@ -776,6 +777,8 @@ struct dwc3 { unsigned setup_packet_pending:1; unsigned start_config_issued:1; unsigned three_stage_setup:1; + + unsigned disable_scramble_quirk:1; }; /* -------------------------------------------------------------------------- */ diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h index 7db34f00b89a..9209d025597b 100644 --- a/drivers/usb/dwc3/platform_data.h +++ b/drivers/usb/dwc3/platform_data.h @@ -24,4 +24,6 @@ struct dwc3_platform_data { enum usb_device_speed maximum_speed; enum usb_dr_mode dr_mode; bool tx_fifo_resize; + + unsigned disable_scramble_quirk:1; }; -- cgit v1.2.3-59-g8ed1b From 80caf7d21adca10c4621d511f6eb01f7ed2b342c Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Tue, 28 Oct 2014 19:54:26 +0800 Subject: usb: dwc3: add lpm erratum support When parameter DWC_USB3_LPM_ERRATA_ENABLE is enabled in Andvanced Configuration of coreConsultant, it supports of xHCI BESL Errata Dated 10/19/2011 is enabled in host mode. In device mode it adds the capability to send NYET response threshold based on the BESL value received in the LPM token, and the threhold is configurable for each soc platform. This patch adds an entry that soc platform is able to define the lpm capacity with their own device tree or bus glue layer. [ balbi@ti.com : added devicetree documentation, spelled threshold completely, made sure threshold is only applied to proper core revisions. ] Signed-off-by: Huang Rui Signed-off-by: Felipe Balbi --- Documentation/devicetree/bindings/usb/dwc3.txt | 2 ++ drivers/usb/dwc3/core.c | 16 +++++++++++++++- drivers/usb/dwc3/core.h | 26 +++++++++++++++++--------- drivers/usb/dwc3/gadget.c | 13 +++++++++++++ drivers/usb/dwc3/platform_data.h | 3 +++ 5 files changed, 50 insertions(+), 10 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt index 8ec2256a4a09..2b0c1f2e6e27 100644 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ b/Documentation/devicetree/bindings/usb/dwc3.txt @@ -16,6 +16,8 @@ Optional properties: - tx-fifo-resize: determines if the FIFO *has* to be reallocated. - 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 + - snps,lpm-nyet-threshold: LPM NYET threshold This is usually a subnode to DWC3 glue to which it is connected. diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index a0ae1326b7e3..6f9e5b85977a 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -657,6 +657,7 @@ static int dwc3_probe(struct platform_device *pdev) struct device_node *node = dev->of_node; struct resource *res; struct dwc3 *dwc; + u8 lpm_nyet_threshold; int ret; @@ -712,16 +713,27 @@ static int dwc3_probe(struct platform_device *pdev) */ res->start -= DWC3_GLOBALS_REGS_START; + /* default to highest possible threshold */ + lpm_nyet_threshold = 0xff; + if (node) { dwc->maximum_speed = of_usb_get_maximum_speed(node); + dwc->has_lpm_erratum = of_property_read_bool(node, + "snps,has-lpm-erratum"); + of_property_read_u8(node, "snps,lpm-nyet-threshold", + &lpm_nyet_threshold); - dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize"); + dwc->needs_fifo_resize = of_property_read_bool(node, + "tx-fifo-resize"); dwc->dr_mode = of_usb_get_dr_mode(node); dwc->disable_scramble_quirk = of_property_read_bool(node, "snps,disable_scramble_quirk"); } else if (pdata) { dwc->maximum_speed = pdata->maximum_speed; + dwc->has_lpm_erratum = pdata->has_lpm_erratum; + if (pdata->lpm_nyet_threshold) + lpm_nyet_threshold = pdata->lpm_nyet_threshold; dwc->needs_fifo_resize = pdata->tx_fifo_resize; dwc->dr_mode = pdata->dr_mode; @@ -733,6 +745,8 @@ static int dwc3_probe(struct platform_device *pdev) if (dwc->maximum_speed == USB_SPEED_UNKNOWN) dwc->maximum_speed = USB_SPEED_SUPER; + dwc->lpm_nyet_threshold = lpm_nyet_threshold; + ret = dwc3_core_get_phy(dwc); if (ret) return ret; diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 56bada6c8604..34f1e08988fe 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -246,16 +246,19 @@ #define DWC3_DCTL_TRGTULST_SS_INACT (DWC3_DCTL_TRGTULST(6)) /* These apply for core versions 1.94a and later */ -#define DWC3_DCTL_KEEP_CONNECT (1 << 19) -#define DWC3_DCTL_L1_HIBER_EN (1 << 18) -#define DWC3_DCTL_CRS (1 << 17) -#define DWC3_DCTL_CSS (1 << 16) +#define DWC3_DCTL_LPM_ERRATA_MASK DWC3_DCTL_LPM_ERRATA(0xf) +#define DWC3_DCTL_LPM_ERRATA(n) ((n) << 20) -#define DWC3_DCTL_INITU2ENA (1 << 12) -#define DWC3_DCTL_ACCEPTU2ENA (1 << 11) -#define DWC3_DCTL_INITU1ENA (1 << 10) -#define DWC3_DCTL_ACCEPTU1ENA (1 << 9) -#define DWC3_DCTL_TSTCTRL_MASK (0xf << 1) +#define DWC3_DCTL_KEEP_CONNECT (1 << 19) +#define DWC3_DCTL_L1_HIBER_EN (1 << 18) +#define DWC3_DCTL_CRS (1 << 17) +#define DWC3_DCTL_CSS (1 << 16) + +#define DWC3_DCTL_INITU2ENA (1 << 12) +#define DWC3_DCTL_ACCEPTU2ENA (1 << 11) +#define DWC3_DCTL_INITU1ENA (1 << 10) +#define DWC3_DCTL_ACCEPTU1ENA (1 << 9) +#define DWC3_DCTL_TSTCTRL_MASK (0xf << 1) #define DWC3_DCTL_ULSTCHNGREQ_MASK (0x0f << 5) #define DWC3_DCTL_ULSTCHNGREQ(n) (((n) << 5) & DWC3_DCTL_ULSTCHNGREQ_MASK) @@ -660,10 +663,13 @@ struct dwc3_scratchpad_array { * @regset: debugfs pointer to regdump file * @test_mode: true when we're entering a USB test mode * @test_mode_nr: test feature selector + * @lpm_nyet_threshold: LPM NYET response threshold * @delayed_status: true when gadget driver asks for delayed status * @ep0_bounced: true when we used bounce buffer * @ep0_expect_in: true when we expect a DATA IN transfer * @has_hibernation: true when dwc3 was configured with Hibernation + * @has_lpm_erratum: true when core was configured with LPM Erratum. Note that + * there's now way for software to detect this in runtime. * @is_selfpowered: true when we are selfpowered * @is_fpga: true when we are using the FPGA board * @needs_fifo_resize: not all users might want fifo resizing, flag it @@ -764,11 +770,13 @@ struct dwc3 { u8 test_mode; u8 test_mode_nr; + u8 lpm_nyet_threshold; unsigned delayed_status:1; unsigned ep0_bounced:1; unsigned ep0_expect_in:1; unsigned has_hibernation:1; + unsigned has_lpm_erratum:1; unsigned is_selfpowered:1; unsigned is_fpga:1; unsigned needs_fifo_resize:1; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 20dda60b27c3..88a065f61150 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2301,6 +2301,19 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) */ reg |= DWC3_DCTL_HIRD_THRES(12); + /* + * When dwc3 revisions >= 2.40a, LPM Erratum is enabled and + * DCFG.LPMCap is set, core responses with an ACK and the + * BESL value in the LPM token is less than or equal to LPM + * NYET threshold. + */ + WARN_ONCE(dwc->revision < DWC3_REVISION_240A + && dwc->has_lpm_erratum, + "LPM Erratum not available on dwc3 revisisions < 2.40a\n"); + + if (dwc->has_lpm_erratum && dwc->revision >= DWC3_REVISION_240A) + reg |= DWC3_DCTL_LPM_ERRATA(dwc->lpm_nyet_threshold); + dwc3_writel(dwc->regs, DWC3_DCTL, reg); } else { reg = dwc3_readl(dwc->regs, DWC3_DCTL); diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h index 9209d025597b..e1283080a49f 100644 --- a/drivers/usb/dwc3/platform_data.h +++ b/drivers/usb/dwc3/platform_data.h @@ -25,5 +25,8 @@ struct dwc3_platform_data { enum usb_dr_mode dr_mode; bool tx_fifo_resize; + u8 lpm_nyet_threshold; + unsigned disable_scramble_quirk:1; + unsigned has_lpm_erratum:1; }; -- cgit v1.2.3-59-g8ed1b From 9a5b2f3167c1f98b879d6a800ab138f04e34f9d5 Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Tue, 28 Oct 2014 19:54:27 +0800 Subject: usb: dwc3: add u2exit lfps quirk This patch adds u2exit lfps quirk, and some special platforms can configure that if it is needed. [ balbi@ti.com : added DeviceTree binding documentation ] Signed-off-by: Huang Rui Signed-off-by: Felipe Balbi --- Documentation/devicetree/bindings/usb/dwc3.txt | 1 + drivers/usb/dwc3/core.c | 6 ++++++ drivers/usb/dwc3/core.h | 3 +++ drivers/usb/dwc3/platform_data.h | 1 + 4 files changed, 11 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt index 2b0c1f2e6e27..5fcd68008945 100644 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ b/Documentation/devicetree/bindings/usb/dwc3.txt @@ -18,6 +18,7 @@ Optional properties: Only really useful for FPGA builds. - snps,has-lpm-erratum: true when DWC3 was configured with LPM Erratum enabled - snps,lpm-nyet-threshold: LPM NYET threshold + - snps,u2exit_lfps_quirk: set if we want to enable u2exit lfps quirk This is usually a subnode to DWC3 glue to which it is connected. diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 6f9e5b85977a..33cbea5c6dda 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -473,6 +473,9 @@ static int dwc3_core_init(struct dwc3 *dwc) else reg &= ~DWC3_GCTL_DISSCRAMBLE; + if (dwc->u2exit_lfps_quirk) + reg |= DWC3_GCTL_U2EXIT_LFPS; + /* * WORKAROUND: DWC3 revisions <1.90a have a bug * where the device can fail to connect at SuperSpeed @@ -729,6 +732,8 @@ static int dwc3_probe(struct platform_device *pdev) dwc->disable_scramble_quirk = of_property_read_bool(node, "snps,disable_scramble_quirk"); + dwc->u2exit_lfps_quirk = of_property_read_bool(node, + "snps,u2exit_lfps_quirk"); } else if (pdata) { dwc->maximum_speed = pdata->maximum_speed; dwc->has_lpm_erratum = pdata->has_lpm_erratum; @@ -739,6 +744,7 @@ static int dwc3_probe(struct platform_device *pdev) dwc->dr_mode = pdata->dr_mode; dwc->disable_scramble_quirk = pdata->disable_scramble_quirk; + dwc->u2exit_lfps_quirk = pdata->u2exit_lfps_quirk; } /* default to superspeed if no maximum_speed passed */ diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 34f1e08988fe..f93145cb52f5 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -166,6 +166,7 @@ #define DWC3_GCTL_SCALEDOWN(n) ((n) << 4) #define DWC3_GCTL_SCALEDOWN_MASK DWC3_GCTL_SCALEDOWN(3) #define DWC3_GCTL_DISSCRAMBLE (1 << 3) +#define DWC3_GCTL_U2EXIT_LFPS (1 << 2) #define DWC3_GCTL_GBLHIBERNATIONEN (1 << 1) #define DWC3_GCTL_DSBLCLKGTNG (1 << 0) @@ -679,6 +680,7 @@ struct dwc3_scratchpad_array { * @start_config_issued: true when StartConfig command has been issued * @three_stage_setup: set if we perform a three phase setup * @disable_scramble_quirk: set if we enable the disable scramble quirk + * @u2exit_lfps_quirk: set if we enable u2exit lfps quirk */ struct dwc3 { struct usb_ctrlrequest *ctrl_req; @@ -787,6 +789,7 @@ struct dwc3 { unsigned three_stage_setup:1; unsigned disable_scramble_quirk:1; + unsigned u2exit_lfps_quirk:1; }; /* -------------------------------------------------------------------------- */ diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h index e1283080a49f..3f2159108f7d 100644 --- a/drivers/usb/dwc3/platform_data.h +++ b/drivers/usb/dwc3/platform_data.h @@ -29,4 +29,5 @@ struct dwc3_platform_data { unsigned disable_scramble_quirk:1; unsigned has_lpm_erratum:1; + unsigned u2exit_lfps_quirk:1; }; -- cgit v1.2.3-59-g8ed1b From b5a65c406367e3e79ece6f687c83d4ffce4c174c Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Tue, 28 Oct 2014 19:54:28 +0800 Subject: usb: dwc3: add P3 in U2 SS inactive quirk This patch adds P3 in U2 SS inactive quirk, and some special platforms can configure that if it is needed. [ balbi@ti.com : added DeviceTree binding documentation ] Signed-off-by: Huang Rui Signed-off-by: Felipe Balbi --- Documentation/devicetree/bindings/usb/dwc3.txt | 1 + drivers/usb/dwc3/core.c | 23 +++++++++++++++++++++++ drivers/usb/dwc3/core.h | 3 +++ drivers/usb/dwc3/platform_data.h | 1 + 4 files changed, 28 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt index 5fcd68008945..36e4287c40f5 100644 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ b/Documentation/devicetree/bindings/usb/dwc3.txt @@ -19,6 +19,7 @@ Optional properties: - snps,has-lpm-erratum: true when DWC3 was configured with LPM Erratum enabled - snps,lpm-nyet-threshold: LPM NYET threshold - snps,u2exit_lfps_quirk: set if we want to enable u2exit lfps quirk + - snps,u2ss_inp3_quirk: set if we enable P3 OK for U2/SS Inactive quirk This is usually a subnode to DWC3 glue to which it is connected. diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 33cbea5c6dda..7c54da187062 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -364,6 +364,24 @@ static void dwc3_cache_hwparams(struct dwc3 *dwc) parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8); } +/** + * dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core + * @dwc: Pointer to our controller context structure + */ +static void dwc3_phy_setup(struct dwc3 *dwc) +{ + u32 reg; + + reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); + + if (dwc->u2ss_inp3_quirk) + reg |= DWC3_GUSB3PIPECTL_U2SSINP3OK; + + dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); + + mdelay(100); +} + /** * dwc3_core_init - Low-level initialization of DWC3 Core * @dwc: Pointer to our controller context structure @@ -489,6 +507,8 @@ static int dwc3_core_init(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_GCTL, reg); + dwc3_phy_setup(dwc); + ret = dwc3_alloc_scratch_buffers(dwc); if (ret) goto err1; @@ -734,6 +754,8 @@ static int dwc3_probe(struct platform_device *pdev) "snps,disable_scramble_quirk"); dwc->u2exit_lfps_quirk = of_property_read_bool(node, "snps,u2exit_lfps_quirk"); + dwc->u2ss_inp3_quirk = of_property_read_bool(node, + "snps,u2ss_inp3_quirk"); } else if (pdata) { dwc->maximum_speed = pdata->maximum_speed; dwc->has_lpm_erratum = pdata->has_lpm_erratum; @@ -745,6 +767,7 @@ static int dwc3_probe(struct platform_device *pdev) dwc->disable_scramble_quirk = pdata->disable_scramble_quirk; dwc->u2exit_lfps_quirk = pdata->u2exit_lfps_quirk; + dwc->u2ss_inp3_quirk = pdata->u2ss_inp3_quirk; } /* default to superspeed if no maximum_speed passed */ diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index f93145cb52f5..66fd26bfdbfa 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -176,6 +176,7 @@ /* Global USB3 PIPE Control Register */ #define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31) +#define DWC3_GUSB3PIPECTL_U2SSINP3OK (1 << 29) #define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17) /* Global TX Fifo Size Register */ @@ -681,6 +682,7 @@ struct dwc3_scratchpad_array { * @three_stage_setup: set if we perform a three phase setup * @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 */ struct dwc3 { struct usb_ctrlrequest *ctrl_req; @@ -790,6 +792,7 @@ struct dwc3 { unsigned disable_scramble_quirk:1; unsigned u2exit_lfps_quirk:1; + unsigned u2ss_inp3_quirk:1; }; /* -------------------------------------------------------------------------- */ diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h index 3f2159108f7d..cf92c81e2e22 100644 --- a/drivers/usb/dwc3/platform_data.h +++ b/drivers/usb/dwc3/platform_data.h @@ -30,4 +30,5 @@ struct dwc3_platform_data { unsigned disable_scramble_quirk:1; unsigned has_lpm_erratum:1; unsigned u2exit_lfps_quirk:1; + unsigned u2ss_inp3_quirk:1; }; -- cgit v1.2.3-59-g8ed1b From df31f5b3a6d3ef0bb692edff13167e9a1c5aa25e Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Tue, 28 Oct 2014 19:54:29 +0800 Subject: usb: dwc3: add request p1p2p3 quirk This patch adds request P1/P2/P3 quirk for U2/U2/U3, and some special platforms can configure that if it is needed. [ balbi@ti.com : added DeviceTree binding documentation ] Signed-off-by: Huang Rui Signed-off-by: Felipe Balbi --- Documentation/devicetree/bindings/usb/dwc3.txt | 2 ++ drivers/usb/dwc3/core.c | 6 ++++++ drivers/usb/dwc3/core.h | 3 +++ drivers/usb/dwc3/platform_data.h | 1 + 4 files changed, 12 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt index 36e4287c40f5..40edc78ca602 100644 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ b/Documentation/devicetree/bindings/usb/dwc3.txt @@ -20,6 +20,8 @@ Optional properties: - snps,lpm-nyet-threshold: LPM NYET threshold - snps,u2exit_lfps_quirk: set if we want to enable u2exit lfps quirk - snps,u2ss_inp3_quirk: set if we enable P3 OK for U2/SS Inactive quirk + - snps,req_p1p2p3_quirk: when set, the core will always request for + P1/P2/P3 transition sequence. This is usually a subnode to DWC3 glue to which it is connected. diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 7c54da187062..600d3bc8d04d 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -377,6 +377,9 @@ static void dwc3_phy_setup(struct dwc3 *dwc) if (dwc->u2ss_inp3_quirk) reg |= DWC3_GUSB3PIPECTL_U2SSINP3OK; + if (dwc->req_p1p2p3_quirk) + reg |= DWC3_GUSB3PIPECTL_REQP1P2P3; + dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); mdelay(100); @@ -756,6 +759,8 @@ static int dwc3_probe(struct platform_device *pdev) "snps,u2exit_lfps_quirk"); dwc->u2ss_inp3_quirk = of_property_read_bool(node, "snps,u2ss_inp3_quirk"); + dwc->req_p1p2p3_quirk = of_property_read_bool(node, + "snps,req_p1p2p3_quirk"); } else if (pdata) { dwc->maximum_speed = pdata->maximum_speed; dwc->has_lpm_erratum = pdata->has_lpm_erratum; @@ -768,6 +773,7 @@ static int dwc3_probe(struct platform_device *pdev) dwc->disable_scramble_quirk = pdata->disable_scramble_quirk; dwc->u2exit_lfps_quirk = pdata->u2exit_lfps_quirk; dwc->u2ss_inp3_quirk = pdata->u2ss_inp3_quirk; + dwc->req_p1p2p3_quirk = pdata->req_p1p2p3_quirk; } /* default to superspeed if no maximum_speed passed */ diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 66fd26bfdbfa..ce331630fad9 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -177,6 +177,7 @@ /* Global USB3 PIPE Control Register */ #define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31) #define DWC3_GUSB3PIPECTL_U2SSINP3OK (1 << 29) +#define DWC3_GUSB3PIPECTL_REQP1P2P3 (1 << 24) #define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17) /* Global TX Fifo Size Register */ @@ -683,6 +684,7 @@ struct dwc3_scratchpad_array { * @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 + * @req_p1p2p3_quirk: set if we enable request p1p2p3 quirk */ struct dwc3 { struct usb_ctrlrequest *ctrl_req; @@ -793,6 +795,7 @@ struct dwc3 { unsigned disable_scramble_quirk:1; unsigned u2exit_lfps_quirk:1; unsigned u2ss_inp3_quirk:1; + unsigned req_p1p2p3_quirk:1; }; /* -------------------------------------------------------------------------- */ diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h index cf92c81e2e22..d3e6ec210ef3 100644 --- a/drivers/usb/dwc3/platform_data.h +++ b/drivers/usb/dwc3/platform_data.h @@ -31,4 +31,5 @@ struct dwc3_platform_data { unsigned has_lpm_erratum:1; unsigned u2exit_lfps_quirk:1; unsigned u2ss_inp3_quirk:1; + unsigned req_p1p2p3_quirk:1; }; -- cgit v1.2.3-59-g8ed1b From a2a1d0f5838d6aa0d1306ef9bb1011f501faa695 Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Tue, 28 Oct 2014 19:54:30 +0800 Subject: usb: dwc3: add delay p1p2p3 quirk This patch adds delay P0 to P1/P2/P3 quirk for U2/U2/U3, and some special platforms can configure that if it is needed. [ balbi@ti.com : added DeviceTree binding documentation ] Signed-off-by: Huang Rui Signed-off-by: Felipe Balbi --- Documentation/devicetree/bindings/usb/dwc3.txt | 2 ++ drivers/usb/dwc3/core.c | 6 ++++++ drivers/usb/dwc3/core.h | 5 +++++ drivers/usb/dwc3/platform_data.h | 1 + 4 files changed, 14 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt index 40edc78ca602..4c77ed6e7c07 100644 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ b/Documentation/devicetree/bindings/usb/dwc3.txt @@ -22,6 +22,8 @@ Optional properties: - snps,u2ss_inp3_quirk: set if we enable P3 OK for U2/SS Inactive quirk - snps,req_p1p2p3_quirk: when set, the core will always request for P1/P2/P3 transition sequence. + - snps,del_p1p2p3_quirk: when set core will delay P1/P2/P3 until a certain + amount of 8B10B errors occur. This is usually a subnode to DWC3 glue to which it is connected. diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 600d3bc8d04d..c07651484c60 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -380,6 +380,9 @@ static void dwc3_phy_setup(struct dwc3 *dwc) if (dwc->req_p1p2p3_quirk) reg |= DWC3_GUSB3PIPECTL_REQP1P2P3; + if (dwc->del_p1p2p3_quirk) + reg |= DWC3_GUSB3PIPECTL_DEP1P2P3_EN; + dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); mdelay(100); @@ -761,6 +764,8 @@ static int dwc3_probe(struct platform_device *pdev) "snps,u2ss_inp3_quirk"); dwc->req_p1p2p3_quirk = of_property_read_bool(node, "snps,req_p1p2p3_quirk"); + dwc->del_p1p2p3_quirk = of_property_read_bool(node, + "snps,del_p1p2p3_quirk"); } else if (pdata) { dwc->maximum_speed = pdata->maximum_speed; dwc->has_lpm_erratum = pdata->has_lpm_erratum; @@ -774,6 +779,7 @@ static int dwc3_probe(struct platform_device *pdev) dwc->u2exit_lfps_quirk = pdata->u2exit_lfps_quirk; dwc->u2ss_inp3_quirk = pdata->u2ss_inp3_quirk; dwc->req_p1p2p3_quirk = pdata->req_p1p2p3_quirk; + dwc->del_p1p2p3_quirk = pdata->del_p1p2p3_quirk; } /* default to superspeed if no maximum_speed passed */ diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index ce331630fad9..b8fbc4a1ee4a 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -178,6 +178,9 @@ #define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31) #define DWC3_GUSB3PIPECTL_U2SSINP3OK (1 << 29) #define DWC3_GUSB3PIPECTL_REQP1P2P3 (1 << 24) +#define DWC3_GUSB3PIPECTL_DEP1P2P3(n) ((n) << 19) +#define DWC3_GUSB3PIPECTL_DEP1P2P3_MASK DWC3_GUSB3PIPECTL_DEP1P2P3(7) +#define DWC3_GUSB3PIPECTL_DEP1P2P3_EN DWC3_GUSB3PIPECTL_DEP1P2P3(1) #define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17) /* Global TX Fifo Size Register */ @@ -685,6 +688,7 @@ struct dwc3_scratchpad_array { * @u2exit_lfps_quirk: set if we enable u2exit lfps quirk * @u2ss_inp3_quirk: set if we enable P3 OK for U2/SS Inactive quirk * @req_p1p2p3_quirk: set if we enable request p1p2p3 quirk + * @del_p1p2p3_quirk: set if we enable delay p1p2p3 quirk */ struct dwc3 { struct usb_ctrlrequest *ctrl_req; @@ -796,6 +800,7 @@ struct dwc3 { unsigned u2exit_lfps_quirk:1; unsigned u2ss_inp3_quirk:1; unsigned req_p1p2p3_quirk:1; + unsigned del_p1p2p3_quirk:1; }; /* -------------------------------------------------------------------------- */ diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h index d3e6ec210ef3..a421cecd6c16 100644 --- a/drivers/usb/dwc3/platform_data.h +++ b/drivers/usb/dwc3/platform_data.h @@ -32,4 +32,5 @@ struct dwc3_platform_data { unsigned u2exit_lfps_quirk:1; unsigned u2ss_inp3_quirk:1; unsigned req_p1p2p3_quirk:1; + unsigned del_p1p2p3_quirk:1; }; -- cgit v1.2.3-59-g8ed1b From 41c06ffdf9cc63edd875cc8ff8ae002cd9b14f96 Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Tue, 28 Oct 2014 19:54:31 +0800 Subject: usb: dwc3: add delay phy power change quirk This patch adds delay PHY power change from P0 to P1/P2/P3 when link state changing from U0 to U1/U2/U3 respectively, and some special platforms can configure that if it is needed. [ balbi@ti.com : added DeviceTree binding documentation ] Signed-off-by: Huang Rui Signed-off-by: Felipe Balbi --- Documentation/devicetree/bindings/usb/dwc3.txt | 2 ++ drivers/usb/dwc3/core.c | 6 ++++++ drivers/usb/dwc3/core.h | 3 +++ drivers/usb/dwc3/platform_data.h | 1 + 4 files changed, 12 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt index 4c77ed6e7c07..a2598d3c7c12 100644 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ b/Documentation/devicetree/bindings/usb/dwc3.txt @@ -24,6 +24,8 @@ Optional properties: P1/P2/P3 transition sequence. - snps,del_p1p2p3_quirk: when set core will delay P1/P2/P3 until a certain amount of 8B10B errors occur. + - snps,del_phy_power_chg_quirk: when set core will delay PHY power change + from P0 to P1/P2/P3. This is usually a subnode to DWC3 glue to which it is connected. diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index c07651484c60..de6a00969bc7 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -383,6 +383,9 @@ static void dwc3_phy_setup(struct dwc3 *dwc) if (dwc->del_p1p2p3_quirk) reg |= DWC3_GUSB3PIPECTL_DEP1P2P3_EN; + if (dwc->del_phy_power_chg_quirk) + reg |= DWC3_GUSB3PIPECTL_DEPOCHANGE; + dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); mdelay(100); @@ -766,6 +769,8 @@ static int dwc3_probe(struct platform_device *pdev) "snps,req_p1p2p3_quirk"); dwc->del_p1p2p3_quirk = of_property_read_bool(node, "snps,del_p1p2p3_quirk"); + dwc->del_phy_power_chg_quirk = of_property_read_bool(node, + "snps,del_phy_power_chg_quirk"); } else if (pdata) { dwc->maximum_speed = pdata->maximum_speed; dwc->has_lpm_erratum = pdata->has_lpm_erratum; @@ -780,6 +785,7 @@ static int dwc3_probe(struct platform_device *pdev) dwc->u2ss_inp3_quirk = pdata->u2ss_inp3_quirk; dwc->req_p1p2p3_quirk = pdata->req_p1p2p3_quirk; dwc->del_p1p2p3_quirk = pdata->del_p1p2p3_quirk; + dwc->del_phy_power_chg_quirk = pdata->del_phy_power_chg_quirk; } /* default to superspeed if no maximum_speed passed */ diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index b8fbc4a1ee4a..5e8a75c3f3c8 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -181,6 +181,7 @@ #define DWC3_GUSB3PIPECTL_DEP1P2P3(n) ((n) << 19) #define DWC3_GUSB3PIPECTL_DEP1P2P3_MASK DWC3_GUSB3PIPECTL_DEP1P2P3(7) #define DWC3_GUSB3PIPECTL_DEP1P2P3_EN DWC3_GUSB3PIPECTL_DEP1P2P3(1) +#define DWC3_GUSB3PIPECTL_DEPOCHANGE (1 << 18) #define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17) /* Global TX Fifo Size Register */ @@ -689,6 +690,7 @@ struct dwc3_scratchpad_array { * @u2ss_inp3_quirk: set if we enable P3 OK for U2/SS Inactive quirk * @req_p1p2p3_quirk: set if we enable request p1p2p3 quirk * @del_p1p2p3_quirk: set if we enable delay p1p2p3 quirk + * @del_phy_power_chg_quirk: set if we enable delay phy power change quirk */ struct dwc3 { struct usb_ctrlrequest *ctrl_req; @@ -801,6 +803,7 @@ struct dwc3 { unsigned u2ss_inp3_quirk:1; unsigned req_p1p2p3_quirk:1; unsigned del_p1p2p3_quirk:1; + unsigned del_phy_power_chg_quirk:1; }; /* -------------------------------------------------------------------------- */ diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h index a421cecd6c16..ae67151dc870 100644 --- a/drivers/usb/dwc3/platform_data.h +++ b/drivers/usb/dwc3/platform_data.h @@ -33,4 +33,5 @@ struct dwc3_platform_data { unsigned u2ss_inp3_quirk:1; unsigned req_p1p2p3_quirk:1; unsigned del_p1p2p3_quirk:1; + unsigned del_phy_power_chg_quirk:1; }; -- cgit v1.2.3-59-g8ed1b From fb67afca177a215684d6124137f61e639c5483d4 Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Tue, 28 Oct 2014 19:54:32 +0800 Subject: usb: dwc3: add lfps filter quirk This patch adds LFPS filter quirk, and some special platforms can configure that if it is needed. [ balbi@ti.com : added DeviceTree binding documentation ] Signed-off-by: Huang Rui Signed-off-by: Felipe Balbi --- Documentation/devicetree/bindings/usb/dwc3.txt | 1 + drivers/usb/dwc3/core.c | 6 ++++++ drivers/usb/dwc3/core.h | 3 +++ drivers/usb/dwc3/platform_data.h | 1 + 4 files changed, 11 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt index a2598d3c7c12..4edd29a24e74 100644 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ b/Documentation/devicetree/bindings/usb/dwc3.txt @@ -26,6 +26,7 @@ Optional properties: amount of 8B10B errors occur. - snps,del_phy_power_chg_quirk: when set core will delay PHY power change from P0 to P1/P2/P3. + - snps,lfps_filter_quirk: when set core will filter LFPS reception. This is usually a subnode to DWC3 glue to which it is connected. diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index de6a00969bc7..29a7da0c3178 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -386,6 +386,9 @@ static void dwc3_phy_setup(struct dwc3 *dwc) if (dwc->del_phy_power_chg_quirk) reg |= DWC3_GUSB3PIPECTL_DEPOCHANGE; + if (dwc->lfps_filter_quirk) + reg |= DWC3_GUSB3PIPECTL_LFPSFILT; + dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); mdelay(100); @@ -771,6 +774,8 @@ static int dwc3_probe(struct platform_device *pdev) "snps,del_p1p2p3_quirk"); dwc->del_phy_power_chg_quirk = of_property_read_bool(node, "snps,del_phy_power_chg_quirk"); + dwc->lfps_filter_quirk = of_property_read_bool(node, + "snps,lfps_filter_quirk"); } else if (pdata) { dwc->maximum_speed = pdata->maximum_speed; dwc->has_lpm_erratum = pdata->has_lpm_erratum; @@ -786,6 +791,7 @@ static int dwc3_probe(struct platform_device *pdev) dwc->req_p1p2p3_quirk = pdata->req_p1p2p3_quirk; dwc->del_p1p2p3_quirk = pdata->del_p1p2p3_quirk; dwc->del_phy_power_chg_quirk = pdata->del_phy_power_chg_quirk; + dwc->lfps_filter_quirk = pdata->lfps_filter_quirk; } /* default to superspeed if no maximum_speed passed */ diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 5e8a75c3f3c8..368d32948e27 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -183,6 +183,7 @@ #define DWC3_GUSB3PIPECTL_DEP1P2P3_EN DWC3_GUSB3PIPECTL_DEP1P2P3(1) #define DWC3_GUSB3PIPECTL_DEPOCHANGE (1 << 18) #define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17) +#define DWC3_GUSB3PIPECTL_LFPSFILT (1 << 9) /* Global TX Fifo Size Register */ #define DWC3_GTXFIFOSIZ_TXFDEF(n) ((n) & 0xffff) @@ -691,6 +692,7 @@ struct dwc3_scratchpad_array { * @req_p1p2p3_quirk: set if we enable request p1p2p3 quirk * @del_p1p2p3_quirk: set if we enable delay p1p2p3 quirk * @del_phy_power_chg_quirk: set if we enable delay phy power change quirk + * @lfps_filter_quirk: set if we enable LFPS filter quirk */ struct dwc3 { struct usb_ctrlrequest *ctrl_req; @@ -804,6 +806,7 @@ struct dwc3 { unsigned req_p1p2p3_quirk:1; unsigned del_p1p2p3_quirk:1; unsigned del_phy_power_chg_quirk:1; + unsigned lfps_filter_quirk:1; }; /* -------------------------------------------------------------------------- */ diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h index ae67151dc870..dad0211e8743 100644 --- a/drivers/usb/dwc3/platform_data.h +++ b/drivers/usb/dwc3/platform_data.h @@ -34,4 +34,5 @@ struct dwc3_platform_data { unsigned req_p1p2p3_quirk:1; unsigned del_p1p2p3_quirk:1; unsigned del_phy_power_chg_quirk:1; + unsigned lfps_filter_quirk:1; }; -- cgit v1.2.3-59-g8ed1b From 14f4ac53dfb2321b07a0e690df797fba61102fa6 Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Tue, 28 Oct 2014 19:54:33 +0800 Subject: usb: dwc3: add rx_detect to polling lfps quirk This patch adds RX_DETECT to Polling.LFPS control quirk, and some special platforms can configure that if it is needed. [ balbi@ti.com : added DeviceTree binding documentation ] Signed-off-by: Huang Rui Signed-off-by: Felipe Balbi --- Documentation/devicetree/bindings/usb/dwc3.txt | 2 ++ drivers/usb/dwc3/core.c | 6 ++++++ drivers/usb/dwc3/core.h | 3 +++ drivers/usb/dwc3/platform_data.h | 1 + 4 files changed, 12 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt index 4edd29a24e74..1ecc33315e1f 100644 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ b/Documentation/devicetree/bindings/usb/dwc3.txt @@ -27,6 +27,8 @@ Optional properties: - snps,del_phy_power_chg_quirk: when set core will delay PHY power change from P0 to P1/P2/P3. - snps,lfps_filter_quirk: when set core will filter LFPS reception. + - snps,rx_detect_poll_quirk: when set core will disable a 400us delay to start + Polling LFPS after RX.Detect. This is usually a subnode to DWC3 glue to which it is connected. diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 29a7da0c3178..b440b2b29872 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -389,6 +389,9 @@ static void dwc3_phy_setup(struct dwc3 *dwc) if (dwc->lfps_filter_quirk) reg |= DWC3_GUSB3PIPECTL_LFPSFILT; + if (dwc->rx_detect_poll_quirk) + reg |= DWC3_GUSB3PIPECTL_RX_DETOPOLL; + dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); mdelay(100); @@ -776,6 +779,8 @@ static int dwc3_probe(struct platform_device *pdev) "snps,del_phy_power_chg_quirk"); dwc->lfps_filter_quirk = of_property_read_bool(node, "snps,lfps_filter_quirk"); + dwc->rx_detect_poll_quirk = of_property_read_bool(node, + "snps,rx_detect_poll_quirk"); } else if (pdata) { dwc->maximum_speed = pdata->maximum_speed; dwc->has_lpm_erratum = pdata->has_lpm_erratum; @@ -792,6 +797,7 @@ static int dwc3_probe(struct platform_device *pdev) dwc->del_p1p2p3_quirk = pdata->del_p1p2p3_quirk; dwc->del_phy_power_chg_quirk = pdata->del_phy_power_chg_quirk; dwc->lfps_filter_quirk = pdata->lfps_filter_quirk; + dwc->rx_detect_poll_quirk = pdata->rx_detect_poll_quirk; } /* default to superspeed if no maximum_speed passed */ diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 368d32948e27..8953d739b73d 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -184,6 +184,7 @@ #define DWC3_GUSB3PIPECTL_DEPOCHANGE (1 << 18) #define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17) #define DWC3_GUSB3PIPECTL_LFPSFILT (1 << 9) +#define DWC3_GUSB3PIPECTL_RX_DETOPOLL (1 << 8) /* Global TX Fifo Size Register */ #define DWC3_GTXFIFOSIZ_TXFDEF(n) ((n) & 0xffff) @@ -693,6 +694,7 @@ struct dwc3_scratchpad_array { * @del_p1p2p3_quirk: set if we enable delay p1p2p3 quirk * @del_phy_power_chg_quirk: set if we enable delay phy power change quirk * @lfps_filter_quirk: set if we enable LFPS filter quirk + * @rx_detect_poll_quirk: set if we enable rx_detect to polling lfps quirk */ struct dwc3 { struct usb_ctrlrequest *ctrl_req; @@ -807,6 +809,7 @@ struct dwc3 { unsigned del_p1p2p3_quirk:1; unsigned del_phy_power_chg_quirk:1; unsigned lfps_filter_quirk:1; + unsigned rx_detect_poll_quirk:1; }; /* -------------------------------------------------------------------------- */ diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h index dad0211e8743..4a0f06b2a6c7 100644 --- a/drivers/usb/dwc3/platform_data.h +++ b/drivers/usb/dwc3/platform_data.h @@ -35,4 +35,5 @@ struct dwc3_platform_data { unsigned del_p1p2p3_quirk:1; unsigned del_phy_power_chg_quirk:1; unsigned lfps_filter_quirk:1; + unsigned rx_detect_poll_quirk:1; }; -- cgit v1.2.3-59-g8ed1b From 6b6a0c9a3ffa3107994d92d5758cbe274c5a97b6 Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Fri, 31 Oct 2014 11:11:12 +0800 Subject: usb: dwc3: add Tx de-emphasis quirk This patch adds Tx de-emphasis quirk, and the Tx de-emphasis value is configurable according to PIPE3 specification. Value Description 0 -6dB de-emphasis 1 -3.5dB de-emphasis 2 No de-emphasis 3 Reserved It can be configured on DT or platform data. Signed-off-by: Huang Rui Signed-off-by: Felipe Balbi --- Documentation/devicetree/bindings/usb/dwc3.txt | 3 +++ drivers/usb/dwc3/core.c | 17 +++++++++++++++++ drivers/usb/dwc3/core.h | 11 +++++++++++ drivers/usb/dwc3/platform_data.h | 3 +++ 4 files changed, 34 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt index 1ecc33315e1f..b724b2e78549 100644 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ b/Documentation/devicetree/bindings/usb/dwc3.txt @@ -29,6 +29,9 @@ Optional properties: - snps,lfps_filter_quirk: when set core will filter LFPS reception. - snps,rx_detect_poll_quirk: when set core will disable a 400us delay to start Polling LFPS after RX.Detect. + - snps,tx_de_emphasis_quirk: when set core will set Tx de-emphasis value. + - snps,tx_de_emphasis: the value driven to the PHY is controlled by the + LTSSM during USB3 Compliance mode. This is usually a subnode to DWC3 glue to which it is connected. diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index aefb59d6db8f..c3dfb195f79c 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -401,6 +401,9 @@ static void dwc3_phy_setup(struct dwc3 *dwc) if (dwc->rx_detect_poll_quirk) reg |= DWC3_GUSB3PIPECTL_RX_DETOPOLL; + if (dwc->tx_de_emphasis_quirk) + reg |= DWC3_GUSB3PIPECTL_TX_DEEPH(dwc->tx_de_emphasis); + dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); mdelay(100); @@ -720,6 +723,7 @@ static int dwc3_probe(struct platform_device *pdev) struct resource *res; struct dwc3 *dwc; u8 lpm_nyet_threshold; + u8 tx_de_emphasis; int ret; @@ -778,6 +782,9 @@ static int dwc3_probe(struct platform_device *pdev) /* default to highest possible threshold */ lpm_nyet_threshold = 0xff; + /* default to -3.5dB de-emphasis */ + tx_de_emphasis = 1; + if (node) { dwc->maximum_speed = of_usb_get_maximum_speed(node); dwc->has_lpm_erratum = of_property_read_bool(node, @@ -805,6 +812,11 @@ static int dwc3_probe(struct platform_device *pdev) "snps,lfps_filter_quirk"); dwc->rx_detect_poll_quirk = of_property_read_bool(node, "snps,rx_detect_poll_quirk"); + + dwc->tx_de_emphasis_quirk = of_property_read_bool(node, + "snps,tx_de_emphasis_quirk"); + of_property_read_u8(node, "snps,tx_de_emphasis", + &tx_de_emphasis); } else if (pdata) { dwc->maximum_speed = pdata->maximum_speed; dwc->has_lpm_erratum = pdata->has_lpm_erratum; @@ -822,6 +834,10 @@ static int dwc3_probe(struct platform_device *pdev) dwc->del_phy_power_chg_quirk = pdata->del_phy_power_chg_quirk; dwc->lfps_filter_quirk = pdata->lfps_filter_quirk; dwc->rx_detect_poll_quirk = pdata->rx_detect_poll_quirk; + + dwc->tx_de_emphasis_quirk = pdata->tx_de_emphasis_quirk; + if (pdata->tx_de_emphasis) + tx_de_emphasis = pdata->tx_de_emphasis; } /* default to superspeed if no maximum_speed passed */ @@ -829,6 +845,7 @@ static int dwc3_probe(struct platform_device *pdev) dwc->maximum_speed = USB_SPEED_SUPER; dwc->lpm_nyet_threshold = lpm_nyet_threshold; + dwc->tx_de_emphasis = tx_de_emphasis; ret = dwc3_core_get_phy(dwc); if (ret) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 8953d739b73d..cf9aaca6add0 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -185,6 +185,8 @@ #define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17) #define DWC3_GUSB3PIPECTL_LFPSFILT (1 << 9) #define DWC3_GUSB3PIPECTL_RX_DETOPOLL (1 << 8) +#define DWC3_GUSB3PIPECTL_TX_DEEPH_MASK DWC3_GUSB3PIPECTL_TX_DEEPH(3) +#define DWC3_GUSB3PIPECTL_TX_DEEPH(n) ((n) << 1) /* Global TX Fifo Size Register */ #define DWC3_GTXFIFOSIZ_TXFDEF(n) ((n) & 0xffff) @@ -695,6 +697,12 @@ struct dwc3_scratchpad_array { * @del_phy_power_chg_quirk: set if we enable delay phy power change quirk * @lfps_filter_quirk: set if we enable LFPS filter quirk * @rx_detect_poll_quirk: set if we enable rx_detect to polling lfps quirk + * @tx_de_emphasis_quirk: set if we enable Tx de-emphasis quirk + * @tx_de_emphasis: Tx de-emphasis value + * 0 - -6dB de-emphasis + * 1 - -3.5dB de-emphasis + * 2 - No de-emphasis + * 3 - Reserved */ struct dwc3 { struct usb_ctrlrequest *ctrl_req; @@ -810,6 +818,9 @@ struct dwc3 { unsigned del_phy_power_chg_quirk:1; unsigned lfps_filter_quirk:1; unsigned rx_detect_poll_quirk:1; + + unsigned tx_de_emphasis_quirk:1; + unsigned tx_de_emphasis:2; }; /* -------------------------------------------------------------------------- */ diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h index 4a0f06b2a6c7..e1ab900a8623 100644 --- a/drivers/usb/dwc3/platform_data.h +++ b/drivers/usb/dwc3/platform_data.h @@ -36,4 +36,7 @@ struct dwc3_platform_data { unsigned del_phy_power_chg_quirk:1; unsigned lfps_filter_quirk:1; unsigned rx_detect_poll_quirk:1; + + unsigned tx_de_emphasis_quirk:1; + unsigned tx_de_emphasis:2; }; -- cgit v1.2.3-59-g8ed1b From 59acfa208164205f94a11f454d08cd88f06b9908 Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Fri, 31 Oct 2014 11:11:13 +0800 Subject: usb: dwc3: add disable usb3 suspend phy quirk This patch adds disable usb3 suspend phy quirk, and some special platforms can configure that if it is needed. Signed-off-by: Huang Rui Signed-off-by: Felipe Balbi --- Documentation/devicetree/bindings/usb/dwc3.txt | 1 + drivers/usb/dwc3/core.c | 6 ++++++ drivers/usb/dwc3/core.h | 2 ++ drivers/usb/dwc3/platform_data.h | 1 + 4 files changed, 10 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt index b724b2e78549..08b394ebeb3e 100644 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ b/Documentation/devicetree/bindings/usb/dwc3.txt @@ -32,6 +32,7 @@ Optional properties: - snps,tx_de_emphasis_quirk: when set core will set Tx de-emphasis value. - snps,tx_de_emphasis: the value driven to the PHY is controlled by the LTSSM during USB3 Compliance mode. + - snps,dis_u3_susphy_quirk: when set core will disable USB3 suspend phy. This is usually a subnode to DWC3 glue to which it is connected. diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index c3dfb195f79c..87ffb86bc2f2 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -404,6 +404,9 @@ static void dwc3_phy_setup(struct dwc3 *dwc) if (dwc->tx_de_emphasis_quirk) reg |= DWC3_GUSB3PIPECTL_TX_DEEPH(dwc->tx_de_emphasis); + if (dwc->dis_u3_susphy_quirk && dwc->is_fpga) + reg &= ~DWC3_GUSB3PIPECTL_SUSPHY; + dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); mdelay(100); @@ -812,6 +815,8 @@ static int dwc3_probe(struct platform_device *pdev) "snps,lfps_filter_quirk"); dwc->rx_detect_poll_quirk = of_property_read_bool(node, "snps,rx_detect_poll_quirk"); + dwc->dis_u3_susphy_quirk = of_property_read_bool(node, + "snps,dis_u3_susphy_quirk"); dwc->tx_de_emphasis_quirk = of_property_read_bool(node, "snps,tx_de_emphasis_quirk"); @@ -834,6 +839,7 @@ static int dwc3_probe(struct platform_device *pdev) dwc->del_phy_power_chg_quirk = pdata->del_phy_power_chg_quirk; dwc->lfps_filter_quirk = pdata->lfps_filter_quirk; dwc->rx_detect_poll_quirk = pdata->rx_detect_poll_quirk; + dwc->dis_u3_susphy_quirk = pdata->dis_u3_susphy_quirk; dwc->tx_de_emphasis_quirk = pdata->tx_de_emphasis_quirk; if (pdata->tx_de_emphasis) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index cf9aaca6add0..fa778b0a5ab7 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -697,6 +697,7 @@ struct dwc3_scratchpad_array { * @del_phy_power_chg_quirk: set if we enable delay phy power change quirk * @lfps_filter_quirk: set if we enable LFPS filter quirk * @rx_detect_poll_quirk: set if we enable rx_detect to polling lfps quirk + * @dis_u3_susphy_quirk: set if we disable usb3 suspend phy * @tx_de_emphasis_quirk: set if we enable Tx de-emphasis quirk * @tx_de_emphasis: Tx de-emphasis value * 0 - -6dB de-emphasis @@ -818,6 +819,7 @@ struct dwc3 { unsigned del_phy_power_chg_quirk:1; unsigned lfps_filter_quirk:1; unsigned rx_detect_poll_quirk:1; + unsigned dis_u3_susphy_quirk:1; unsigned tx_de_emphasis_quirk:1; unsigned tx_de_emphasis:2; diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h index e1ab900a8623..0f1d5adc657d 100644 --- a/drivers/usb/dwc3/platform_data.h +++ b/drivers/usb/dwc3/platform_data.h @@ -36,6 +36,7 @@ struct dwc3_platform_data { unsigned del_phy_power_chg_quirk:1; unsigned lfps_filter_quirk:1; unsigned rx_detect_poll_quirk:1; + unsigned dis_u3_susphy_quirk:1; unsigned tx_de_emphasis_quirk:1; unsigned tx_de_emphasis:2; -- cgit v1.2.3-59-g8ed1b From 0effe0a3e741c0e2318f541ce207c9bd6cfe985c Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Fri, 31 Oct 2014 11:11:14 +0800 Subject: usb: dwc3: add disable usb2 suspend phy quirk This patch adds disable usb2 suspend phy quirk, and some special platforms can configure that if it is needed. Signed-off-by: Huang Rui Signed-off-by: Felipe Balbi --- Documentation/devicetree/bindings/usb/dwc3.txt | 1 + drivers/usb/dwc3/core.c | 6 ++++++ drivers/usb/dwc3/core.h | 2 ++ drivers/usb/dwc3/platform_data.h | 1 + 4 files changed, 10 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt index 08b394ebeb3e..f200ecc1f0dc 100644 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ b/Documentation/devicetree/bindings/usb/dwc3.txt @@ -33,6 +33,7 @@ Optional properties: - snps,tx_de_emphasis: the value driven to the PHY is controlled by the LTSSM during USB3 Compliance mode. - snps,dis_u3_susphy_quirk: when set core will disable USB3 suspend phy. + - snps,dis_u2_susphy_quirk: when set core will disable USB2 suspend phy. This is usually a subnode to DWC3 glue to which it is connected. diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 87ffb86bc2f2..3ea55f214439 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -422,6 +422,9 @@ static void dwc3_phy_setup(struct dwc3 *dwc) if (dwc->revision > DWC3_REVISION_194A) reg |= DWC3_GUSB2PHYCFG_SUSPHY; + if (dwc->dis_u2_susphy_quirk && dwc->is_fpga) + reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); mdelay(100); @@ -817,6 +820,8 @@ static int dwc3_probe(struct platform_device *pdev) "snps,rx_detect_poll_quirk"); dwc->dis_u3_susphy_quirk = of_property_read_bool(node, "snps,dis_u3_susphy_quirk"); + dwc->dis_u2_susphy_quirk = of_property_read_bool(node, + "snps,dis_u2_susphy_quirk"); dwc->tx_de_emphasis_quirk = of_property_read_bool(node, "snps,tx_de_emphasis_quirk"); @@ -840,6 +845,7 @@ static int dwc3_probe(struct platform_device *pdev) dwc->lfps_filter_quirk = pdata->lfps_filter_quirk; dwc->rx_detect_poll_quirk = pdata->rx_detect_poll_quirk; dwc->dis_u3_susphy_quirk = pdata->dis_u3_susphy_quirk; + dwc->dis_u2_susphy_quirk = pdata->dis_u2_susphy_quirk; dwc->tx_de_emphasis_quirk = pdata->tx_de_emphasis_quirk; if (pdata->tx_de_emphasis) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index fa778b0a5ab7..cf86d3022b52 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -698,6 +698,7 @@ struct dwc3_scratchpad_array { * @lfps_filter_quirk: set if we enable LFPS filter quirk * @rx_detect_poll_quirk: set if we enable rx_detect to polling lfps quirk * @dis_u3_susphy_quirk: set if we disable usb3 suspend phy + * @dis_u2_susphy_quirk: set if we disable usb2 suspend phy * @tx_de_emphasis_quirk: set if we enable Tx de-emphasis quirk * @tx_de_emphasis: Tx de-emphasis value * 0 - -6dB de-emphasis @@ -820,6 +821,7 @@ struct dwc3 { unsigned lfps_filter_quirk:1; unsigned rx_detect_poll_quirk:1; unsigned dis_u3_susphy_quirk:1; + unsigned dis_u2_susphy_quirk:1; unsigned tx_de_emphasis_quirk:1; unsigned tx_de_emphasis:2; diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h index 0f1d5adc657d..245300be057a 100644 --- a/drivers/usb/dwc3/platform_data.h +++ b/drivers/usb/dwc3/platform_data.h @@ -37,6 +37,7 @@ struct dwc3_platform_data { unsigned lfps_filter_quirk:1; unsigned rx_detect_poll_quirk:1; unsigned dis_u3_susphy_quirk:1; + unsigned dis_u2_susphy_quirk:1; unsigned tx_de_emphasis_quirk:1; unsigned tx_de_emphasis:2; -- cgit v1.2.3-59-g8ed1b From 460d098cb6728134e0e4ba3d58e10bb43032daa5 Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Fri, 31 Oct 2014 11:11:18 +0800 Subject: usb: dwc3: make HIRD threshold configurable HIRD threshold should be configurable by different platforms. From DesignWare databook: When HIRD_Threshold[4] is set to 1b1 and HIRD value is greater than or equal to the value in HIRD_Threshold[3:0], dwc3 asserts output signals utmi_l1_suspend_n to put PHY into Deep Low-Power mode in L1. When HIRD_Threshold[4] is set to 1b0 or the HIRD value is less than HIRD_Threshold[3:0], dwc3 asserts output signals utmi_sleep_n on L1. Signed-off-by: Huang Rui Signed-off-by: Felipe Balbi --- Documentation/devicetree/bindings/usb/dwc3.txt | 3 +++ drivers/usb/dwc3/core.c | 17 +++++++++++++++++ drivers/usb/dwc3/core.h | 6 ++++++ drivers/usb/dwc3/gadget.c | 6 +----- drivers/usb/dwc3/platform_data.h | 3 +++ 5 files changed, 30 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt index f200ecc1f0dc..cd7f0454e13a 100644 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ b/Documentation/devicetree/bindings/usb/dwc3.txt @@ -34,6 +34,9 @@ Optional properties: LTSSM during USB3 Compliance mode. - snps,dis_u3_susphy_quirk: when set core will disable USB3 suspend phy. - snps,dis_u2_susphy_quirk: when set core will disable USB2 suspend phy. + - snps,is-utmi-l1-suspend: true when DWC3 asserts output signal + utmi_l1_suspend_n, false when asserts utmi_sleep_n + - snps,hird-threshold: HIRD threshold This is usually a subnode to DWC3 glue to which it is connected. diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 3ea55f214439..8ae42b8db02b 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -730,6 +730,7 @@ static int dwc3_probe(struct platform_device *pdev) struct dwc3 *dwc; u8 lpm_nyet_threshold; u8 tx_de_emphasis; + u8 hird_threshold; int ret; @@ -791,12 +792,22 @@ static int dwc3_probe(struct platform_device *pdev) /* default to -3.5dB de-emphasis */ tx_de_emphasis = 1; + /* + * default to assert utmi_sleep_n and use maximum allowed HIRD + * threshold value of 0b1100 + */ + hird_threshold = 12; + if (node) { dwc->maximum_speed = of_usb_get_maximum_speed(node); dwc->has_lpm_erratum = of_property_read_bool(node, "snps,has-lpm-erratum"); of_property_read_u8(node, "snps,lpm-nyet-threshold", &lpm_nyet_threshold); + dwc->is_utmi_l1_suspend = of_property_read_bool(node, + "snps,is-utmi-l1-suspend"); + of_property_read_u8(node, "snps,hird-threshold", + &hird_threshold); dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize"); @@ -832,6 +843,9 @@ static int dwc3_probe(struct platform_device *pdev) dwc->has_lpm_erratum = pdata->has_lpm_erratum; if (pdata->lpm_nyet_threshold) lpm_nyet_threshold = pdata->lpm_nyet_threshold; + dwc->is_utmi_l1_suspend = pdata->is_utmi_l1_suspend; + if (pdata->hird_threshold) + hird_threshold = pdata->hird_threshold; dwc->needs_fifo_resize = pdata->tx_fifo_resize; dwc->dr_mode = pdata->dr_mode; @@ -859,6 +873,9 @@ static int dwc3_probe(struct platform_device *pdev) dwc->lpm_nyet_threshold = lpm_nyet_threshold; dwc->tx_de_emphasis = tx_de_emphasis; + dwc->hird_threshold = hird_threshold + | (dwc->is_utmi_l1_suspend << 4); + ret = dwc3_core_get_phy(dwc); if (ret) return ret; diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index cf86d3022b52..4bb9aa696ede 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -675,12 +675,16 @@ struct dwc3_scratchpad_array { * @test_mode: true when we're entering a USB test mode * @test_mode_nr: test feature selector * @lpm_nyet_threshold: LPM NYET response threshold + * @hird_threshold: HIRD threshold * @delayed_status: true when gadget driver asks for delayed status * @ep0_bounced: true when we used bounce buffer * @ep0_expect_in: true when we expect a DATA IN transfer * @has_hibernation: true when dwc3 was configured with Hibernation * @has_lpm_erratum: true when core was configured with LPM Erratum. Note that * there's now way for software to detect this in runtime. + * @is_utmi_l1_suspend: the core asserts output signal + * 0 - utmi_sleep_n + * 1 - utmi_l1_suspend_n * @is_selfpowered: true when we are selfpowered * @is_fpga: true when we are using the FPGA board * @needs_fifo_resize: not all users might want fifo resizing, flag it @@ -797,12 +801,14 @@ struct dwc3 { u8 test_mode; u8 test_mode_nr; u8 lpm_nyet_threshold; + u8 hird_threshold; unsigned delayed_status:1; unsigned ep0_bounced:1; unsigned ep0_expect_in:1; unsigned has_hibernation:1; unsigned has_lpm_erratum:1; + unsigned is_utmi_l1_suspend:1; unsigned is_selfpowered:1; unsigned is_fpga:1; unsigned needs_fifo_resize:1; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 88a065f61150..398c12f5efe3 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2295,11 +2295,7 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg &= ~(DWC3_DCTL_HIRD_THRES_MASK | DWC3_DCTL_L1_HIBER_EN); - /* - * TODO: This should be configurable. For now using - * maximum allowed HIRD threshold value of 0b1100 - */ - reg |= DWC3_DCTL_HIRD_THRES(12); + reg |= DWC3_DCTL_HIRD_THRES(dwc->hird_threshold); /* * When dwc3 revisions >= 2.40a, LPM Erratum is enabled and diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h index 245300be057a..a3a3b6d5668c 100644 --- a/drivers/usb/dwc3/platform_data.h +++ b/drivers/usb/dwc3/platform_data.h @@ -25,6 +25,9 @@ struct dwc3_platform_data { enum usb_dr_mode dr_mode; bool tx_fifo_resize; + unsigned is_utmi_l1_suspend:1; + u8 hird_threshold; + u8 lpm_nyet_threshold; unsigned disable_scramble_quirk:1; -- cgit v1.2.3-59-g8ed1b From 656d7077d8ffd1c2492d4a0a354367ab2e545059 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Mon, 3 Nov 2014 10:53:28 +0800 Subject: dt-bindings: iommu: Add documentation for rockchip iommu Add binding documentation for Rockchip IOMMU. Signed-off-by: Daniel Kurtz Signed-off-by: Simon Xue Reviewed-by: Heiko Stuebner Signed-off-by: Joerg Roedel --- .../devicetree/bindings/iommu/rockchip,iommu.txt | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 Documentation/devicetree/bindings/iommu/rockchip,iommu.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/iommu/rockchip,iommu.txt b/Documentation/devicetree/bindings/iommu/rockchip,iommu.txt new file mode 100644 index 000000000000..9a55ac3735e5 --- /dev/null +++ b/Documentation/devicetree/bindings/iommu/rockchip,iommu.txt @@ -0,0 +1,26 @@ +Rockchip IOMMU +============== + +A Rockchip DRM iommu translates io virtual addresses to physical addresses for +its master device. Each slave device is bound to a single master device, and +shares its clocks, power domain and irq. + +Required properties: +- compatible : Should be "rockchip,iommu" +- reg : Address space for the configuration registers +- interrupts : Interrupt specifier for the IOMMU instance +- interrupt-names : Interrupt name for the IOMMU instance +- #iommu-cells : Should be <0>. This indicates the iommu is a + "single-master" device, and needs no additional information + to associate with its master device. See: + Documentation/devicetree/bindings/iommu/iommu.txt + +Example: + + vopl_mmu: iommu@ff940300 { + compatible = "rockchip,iommu"; + reg = <0xff940300 0x100>; + interrupts = ; + interrupt-names = "vopl_mmu"; + #iommu-cells = <0>; + }; -- cgit v1.2.3-59-g8ed1b From 21228a1868692c34ade648dbb0bc3db0069ab551 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 29 Oct 2014 11:15:17 -0700 Subject: CodingStyle: Add a chapter on conditional compilation Document several common practices and conventions regarding conditional compilation, most notably the preference for ifdefs in headers rather than .c files. Signed-off-by: Josh Triplett Acked-by: Geert Uytterhoeven Signed-off-by: Jonathan Corbet --- Documentation/CodingStyle | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) (limited to 'Documentation') diff --git a/Documentation/CodingStyle b/Documentation/CodingStyle index 3171822c22a5..9f28b140dc89 100644 --- a/Documentation/CodingStyle +++ b/Documentation/CodingStyle @@ -845,6 +845,49 @@ next instruction in the assembly output: : /* outputs */ : /* inputs */ : /* clobbers */); + Chapter 20: Conditional Compilation + +Wherever possible, don't use preprocessor conditionals (#if, #ifdef) in .c +files; doing so makes code harder to read and logic harder to follow. Instead, +use such conditionals in a header file defining functions for use in those .c +files, providing no-op stub versions in the #else case, and then call those +functions unconditionally from .c files. The compiler will avoid generating +any code for the stub calls, producing identical results, but the logic will +remain easy to follow. + +Prefer to compile out entire functions, rather than portions of functions or +portions of expressions. Rather than putting an ifdef in an expression, factor +out part or all of the expression into a separate helper function and apply the +conditional to that function. + +If you have a function or variable which may potentially go unused in a +particular configuration, and the compiler would warn about its definition +going unused, mark the definition as __maybe_unused rather than wrapping it in +a preprocessor conditional. (However, if a function or variable *always* goes +unused, delete it.) + +Within code, where possible, use the IS_ENABLED macro to convert a Kconfig +symbol into a C boolean expression, and use it in a normal C conditional: + + if (IS_ENABLED(CONFIG_SOMETHING)) { + ... + } + +The compiler will constant-fold the conditional away, and include or exclude +the block of code just as with an #ifdef, so this will not add any runtime +overhead. However, this approach still allows the C compiler to see the code +inside the block, and check it for correctness (syntax, types, symbol +references, etc). Thus, you still have to use an #ifdef if the code inside the +block references symbols that will not exist if the condition is not met. + +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 */ + Appendix I: References -- cgit v1.2.3-59-g8ed1b From 9fd1f310a13ab16034cbda4f874eafadc8f80caf Mon Sep 17 00:00:00 2001 From: Simon Farnsworth Date: Fri, 31 Oct 2014 12:48:42 -0300 Subject: [media] DocBook media: Clarify V4L2_FIELD_ANY for drivers Documentation for enum v4l2_field did not make it clear that V4L2_FIELD_ANY is only acceptable as input to the kernel, not as a response from the driver. Make it clear, to stop userspace developers like me assuming it can be returned by the driver. Signed-off-by: Simon Farnsworth Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/io.xml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/DocBook/media/v4l/io.xml b/Documentation/DocBook/media/v4l/io.xml index e5e8325aa3d7..1c17f802b471 100644 --- a/Documentation/DocBook/media/v4l/io.xml +++ b/Documentation/DocBook/media/v4l/io.xml @@ -1422,7 +1422,10 @@ one of the V4L2_FIELD_NONE, V4L2_FIELD_BOTTOM, or V4L2_FIELD_INTERLACED formats is acceptable. Drivers choose depending on hardware capabilities or e. g. the -requested image size, and return the actual field order. &v4l2-buffer; +requested image size, and return the actual field order. Drivers must +never return V4L2_FIELD_ANY. If multiple +field orders are possible the driver must choose one of the possible +field orders during &VIDIOC-S-FMT; or &VIDIOC-TRY-FMT;. &v4l2-buffer; field can never be V4L2_FIELD_ANY. -- cgit v1.2.3-59-g8ed1b From 70c036347fe6675dcd87fd9c2f3159f90233a0ed Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Wed, 22 Oct 2014 08:36:07 +0900 Subject: Documentation: Fix a typo in mailbox.txt This patch fix a typo in Documentation/mailbox.txt "bool async" is defined in struct demo_client. Signed-off-by: Masanari Iida Signed-off-by: Jonathan Corbet --- Documentation/mailbox.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/mailbox.txt b/Documentation/mailbox.txt index 60f43ff629aa..1092ad9578da 100644 --- a/Documentation/mailbox.txt +++ b/Documentation/mailbox.txt @@ -53,7 +53,7 @@ static void message_from_remote(struct mbox_client *cl, void *mssg) { struct demo_client *dc = container_of(mbox_client, struct demo_client, cl); - if (dc->aysnc) { + if (dc->async) { if (is_an_ack(mssg)) { /* An ACK to our last sample sent */ return; /* Or do something else here */ -- cgit v1.2.3-59-g8ed1b From c4b8692a0520331a0ede604e20a0a52b96a98607 Mon Sep 17 00:00:00 2001 From: Kevin Cernekee Date: Sat, 11 Oct 2014 11:10:48 -0700 Subject: USB: ohci-platform: Expose no_big_frame_no and num_ports in DT These quirks are currently set through platform_data; allow DT-based SoCs to use them too. Signed-off-by: Kevin Cernekee Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/usb-ohci.txt | 2 ++ drivers/usb/host/ohci-platform.c | 6 ++++++ 2 files changed, 8 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/usb/usb-ohci.txt b/Documentation/devicetree/bindings/usb/usb-ohci.txt index b968a1aea995..19233b7365e1 100644 --- a/Documentation/devicetree/bindings/usb/usb-ohci.txt +++ b/Documentation/devicetree/bindings/usb/usb-ohci.txt @@ -9,6 +9,8 @@ Optional properties: - big-endian-regs : boolean, set this for hcds with big-endian registers - big-endian-desc : boolean, set this for hcds with big-endian descriptors - big-endian : boolean, for hcds with big-endian-regs + big-endian-desc +- no-big-frame-no : boolean, set if frame_no lives in bits [15:0] of HCCA +- num-ports : u32, to override the detected port count - clocks : a list of phandle + clock specifier pairs - phys : phandle + phy specifier pair - phy-names : "usb" diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c index 4369299064c7..6fb03f88b51d 100644 --- a/drivers/usb/host/ohci-platform.c +++ b/drivers/usb/host/ohci-platform.c @@ -175,6 +175,12 @@ static int ohci_platform_probe(struct platform_device *dev) if (of_property_read_bool(dev->dev.of_node, "big-endian")) ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC; + if (of_property_read_bool(dev->dev.of_node, "no-big-frame-no")) + ohci->flags |= OHCI_QUIRK_FRAME_NO; + + of_property_read_u32(dev->dev.of_node, "num-ports", + &ohci->num_ports); + priv->phy = devm_phy_get(&dev->dev, "usb"); if (IS_ERR(priv->phy)) { err = PTR_ERR(priv->phy); -- cgit v1.2.3-59-g8ed1b From d37a868ffca325509af87f59c142d9dc717772bd Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Wed, 24 Sep 2014 18:20:23 +0800 Subject: f2fs: update f2fs documentation for inline dir support This patch adds descriptions for the inline dir support in f2fs document. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- Documentation/filesystems/f2fs.txt | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'Documentation') diff --git a/Documentation/filesystems/f2fs.txt b/Documentation/filesystems/f2fs.txt index 2cca5a25ef89..4bb9f278c031 100644 --- a/Documentation/filesystems/f2fs.txt +++ b/Documentation/filesystems/f2fs.txt @@ -122,6 +122,10 @@ disable_ext_identify Disable the extension list configured by mkfs, so f2fs inline_xattr Enable the inline xattrs feature. inline_data Enable the inline data feature: New created small(<~3.4k) files can be written into inode block. +inline_dentry Enable the inline dir feature: data in new created + directory entries can be written into inode block. The + space of inode block which is used to store inline + dentries is limited to ~3.4k. flush_merge Merge concurrent cache_flush commands as much as possible to eliminate redundant command issues. If the underlying device handles the cache_flush command relatively slowly, -- cgit v1.2.3-59-g8ed1b From ee76a9abde4f428a3d342822301ddb8d080d6557 Mon Sep 17 00:00:00 2001 From: Yingjoe Chen Date: Mon, 3 Nov 2014 10:28:11 +0800 Subject: pinctrl: Fix path error in documentation Fix pinconfig include file path. Signed-off-by: Yingjoe Chen 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 98eb94d91a1c..47d84b6ee91b 100644 --- a/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt +++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt @@ -216,4 +216,4 @@ arguments are described below. or 0 to disable debouncing More in-depth documentation on these parameters can be found in - + -- cgit v1.2.3-59-g8ed1b From f5914908a5b7b2338f210e56827a1ef35585dc6d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 4 Nov 2014 12:45:59 +0100 Subject: ALSA: pcm: Replace PCM hwptr tracking with tracepoints ALSA PCM core has a mechanism tracking the PCM hwptr updates for analyzing XRUNs. But its log is limited (up to 10) and its log output is a kernel message, which is hard to handle. In this patch, the hwptr logging is moved to the tracing infrastructure instead of its own. Not only the hwptr updates but also XRUN and hwptr errors are recorded on the trace log, so that user can see such events at the exact timing. The new "snd_pcm" entry will appear in the tracing events: # ls -F /sys/kernel/debug/tracing/events/snd_pcm enable filter hw_ptr_error/ hwptr/ xrun/ The hwptr is for the regular hwptr update events. An event trace looks like: aplay-26187 [004] d..3 4012.834761: hwptr: pcmC0D0p/sub0: POS: pos=488, old=0, base=0, period=1024, buf=16384 "POS" shows the hwptr update by the explicit position update call and "IRQ" means the hwptr update by the interrupt, i.e. snd_pcm_period_elapsed() call. The "pos" is the passed ring-buffer offset by the caller, "old" is the previous hwptr, "base" is the hwptr base position, "period" and "buf" are period- and buffer-size of the target PCM substream. (Note that the hwptr position displayed here isn't the ring-buffer offset. It increments up to the PCM position boundary.) The XRUN event appears similarly, but without "pos" field. The hwptr error events appear with the PCM identifier and its reason string, such as "Lost interrupt?". The XRUN and hwptr error reports on kernel message are still left, can be turned on/off via xrun_debug proc like before. But the bit 3, 4, 5 and 6 bits of xrun_debug proc are dropped by this patch. Also, along with the change, the message strings have been reformatted to be a bit more consistent. Last but not least, the hwptr reporting is enabled only when CONFIG_SND_PCM_XRUN_DEBUG is set. Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/Procfile.txt | 13 --- sound/core/Makefile | 3 + sound/core/pcm_lib.c | 146 ++++++---------------------------- sound/core/pcm_trace.h | 110 +++++++++++++++++++++++++ 4 files changed, 137 insertions(+), 135 deletions(-) create mode 100644 sound/core/pcm_trace.h (limited to 'Documentation') diff --git a/Documentation/sound/alsa/Procfile.txt b/Documentation/sound/alsa/Procfile.txt index 7fcd1ad96fcc..cfc49567b9dc 100644 --- a/Documentation/sound/alsa/Procfile.txt +++ b/Documentation/sound/alsa/Procfile.txt @@ -101,10 +101,6 @@ card*/pcm*/xrun_debug bit 0 = Enable XRUN/jiffies debug messages bit 1 = Show stack trace at XRUN / jiffies check bit 2 = Enable additional jiffies check - bit 3 = Log hwptr update at each period interrupt - bit 4 = Log hwptr update at each snd_pcm_update_hw_ptr() - bit 5 = Show last 10 positions on error - bit 6 = Do above only once When the bit 0 is set, the driver will show the messages to kernel log when an xrun is detected. The debug message is @@ -121,15 +117,6 @@ card*/pcm*/xrun_debug buggy) hardware that doesn't give smooth pointer updates. This feature is enabled via the bit 2. - Bits 3 and 4 are for logging the hwptr records. Note that - these will give flood of kernel messages. - - When bit 5 is set, the driver logs the last 10 xrun errors and - the proc file shows each jiffies, position, period_size, - buffer_size, old_hw_ptr, and hw_ptr_base values. - - When bit 6 is set, the full xrun log is shown only once. - card*/pcm*/sub*/info The general information of this PCM sub-stream. diff --git a/sound/core/Makefile b/sound/core/Makefile index 394a38909f6b..4daf2f58261c 100644 --- a/sound/core/Makefile +++ b/sound/core/Makefile @@ -14,6 +14,9 @@ snd-pcm-y := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \ pcm_memory.o memalloc.o snd-pcm-$(CONFIG_SND_DMA_SGBUF) += sgbuf.o +# for trace-points +CFLAGS_pcm_lib.o := -I$(src) + snd-pcm-dmaengine-objs := pcm_dmaengine.o snd-rawmidi-objs := rawmidi.o diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 7b9e2fb35a86..ec9e7866177f 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -32,6 +32,15 @@ #include #include +#ifdef CONFIG_SND_PCM_XRUN_DEBUG +#define CREATE_TRACE_POINTS +#include "pcm_trace.h" +#else +#define trace_hwptr(substream, pos, in_interrupt) +#define trace_xrun(substream) +#define trace_hw_ptr_error(substream, reason) +#endif + /* * fill ring buffer with silence * runtime->silence_start: starting pointer to silence area @@ -146,10 +155,6 @@ EXPORT_SYMBOL(snd_pcm_debug_name); #define XRUN_DEBUG_BASIC (1<<0) #define XRUN_DEBUG_STACK (1<<1) /* dump also stack */ #define XRUN_DEBUG_JIFFIESCHECK (1<<2) /* do jiffies check */ -#define XRUN_DEBUG_PERIODUPDATE (1<<3) /* full period update info */ -#define XRUN_DEBUG_HWPTRUPDATE (1<<4) /* full hwptr update info */ -#define XRUN_DEBUG_LOG (1<<5) /* show last 10 positions on err */ -#define XRUN_DEBUG_LOGONCE (1<<6) /* do above only once */ #ifdef CONFIG_SND_PCM_XRUN_DEBUG @@ -168,6 +173,7 @@ static void xrun(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; + trace_xrun(substream); if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); @@ -180,97 +186,19 @@ static void xrun(struct snd_pcm_substream *substream) } #ifdef CONFIG_SND_PCM_XRUN_DEBUG -#define hw_ptr_error(substream, fmt, args...) \ +#define hw_ptr_error(substream, in_interrupt, reason, fmt, args...) \ do { \ + trace_hw_ptr_error(substream, reason); \ if (xrun_debug(substream, XRUN_DEBUG_BASIC)) { \ - xrun_log_show(substream); \ - pr_err_ratelimited("ALSA: PCM: " fmt, ##args); \ + pr_err_ratelimited("ALSA: PCM: [%c] " reason ": " fmt, \ + (in_interrupt) ? 'Q' : 'P', ##args); \ dump_stack_on_xrun(substream); \ } \ } while (0) -#define XRUN_LOG_CNT 10 - -struct hwptr_log_entry { - unsigned int in_interrupt; - unsigned long jiffies; - snd_pcm_uframes_t pos; - snd_pcm_uframes_t period_size; - snd_pcm_uframes_t buffer_size; - snd_pcm_uframes_t old_hw_ptr; - snd_pcm_uframes_t hw_ptr_base; -}; - -struct snd_pcm_hwptr_log { - unsigned int idx; - unsigned int hit: 1; - struct hwptr_log_entry entries[XRUN_LOG_CNT]; -}; - -static void xrun_log(struct snd_pcm_substream *substream, - snd_pcm_uframes_t pos, int in_interrupt) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_pcm_hwptr_log *log = runtime->hwptr_log; - struct hwptr_log_entry *entry; - - if (log == NULL) { - log = kzalloc(sizeof(*log), GFP_ATOMIC); - if (log == NULL) - return; - runtime->hwptr_log = log; - } else { - if (xrun_debug(substream, XRUN_DEBUG_LOGONCE) && log->hit) - return; - } - entry = &log->entries[log->idx]; - entry->in_interrupt = in_interrupt; - entry->jiffies = jiffies; - entry->pos = pos; - entry->period_size = runtime->period_size; - entry->buffer_size = runtime->buffer_size; - entry->old_hw_ptr = runtime->status->hw_ptr; - entry->hw_ptr_base = runtime->hw_ptr_base; - log->idx = (log->idx + 1) % XRUN_LOG_CNT; -} - -static void xrun_log_show(struct snd_pcm_substream *substream) -{ - struct snd_pcm_hwptr_log *log = substream->runtime->hwptr_log; - struct hwptr_log_entry *entry; - char name[16]; - unsigned int idx; - int cnt; - - if (log == NULL) - return; - if (xrun_debug(substream, XRUN_DEBUG_LOGONCE) && log->hit) - return; - snd_pcm_debug_name(substream, name, sizeof(name)); - for (cnt = 0, idx = log->idx; cnt < XRUN_LOG_CNT; cnt++) { - entry = &log->entries[idx]; - if (entry->period_size == 0) - break; - pr_info("hwptr log: %s: %sj=%lu, pos=%ld/%ld/%ld, " - "hwptr=%ld/%ld\n", - name, entry->in_interrupt ? "[Q] " : "", - entry->jiffies, - (unsigned long)entry->pos, - (unsigned long)entry->period_size, - (unsigned long)entry->buffer_size, - (unsigned long)entry->old_hw_ptr, - (unsigned long)entry->hw_ptr_base); - idx++; - idx %= XRUN_LOG_CNT; - } - log->hit = 1; -} - #else /* ! CONFIG_SND_PCM_XRUN_DEBUG */ #define hw_ptr_error(substream, fmt, args...) do { } while (0) -#define xrun_log(substream, pos, in_interrupt) do { } while (0) -#define xrun_log_show(substream) do { } while (0) #endif @@ -343,7 +271,6 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, if (printk_ratelimit()) { char name[16]; snd_pcm_debug_name(substream, name, sizeof(name)); - xrun_log_show(substream); pcm_err(substream->pcm, "BUG: %s, pos = %ld, buffer size = %ld, period size = %ld\n", name, pos, runtime->buffer_size, @@ -352,8 +279,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, pos = 0; } pos -= pos % runtime->min_align; - if (xrun_debug(substream, XRUN_DEBUG_LOG)) - xrun_log(substream, pos, in_interrupt); + trace_hwptr(substream, pos, in_interrupt); hw_base = runtime->hw_ptr_base; new_hw_ptr = hw_base + pos; if (in_interrupt) { @@ -388,22 +314,6 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, delta = new_hw_ptr - old_hw_ptr; if (delta < 0) delta += runtime->boundary; - if (xrun_debug(substream, in_interrupt ? - XRUN_DEBUG_PERIODUPDATE : XRUN_DEBUG_HWPTRUPDATE)) { - char name[16]; - snd_pcm_debug_name(substream, name, sizeof(name)); - pcm_dbg(substream->pcm, - "%s_update: %s: pos=%u/%u/%u, hwptr=%ld/%ld/%ld/%ld\n", - in_interrupt ? "period" : "hwptr", - name, - (unsigned int)pos, - (unsigned int)runtime->period_size, - (unsigned int)runtime->buffer_size, - (unsigned long)delta, - (unsigned long)old_hw_ptr, - (unsigned long)new_hw_ptr, - (unsigned long)runtime->hw_ptr_base); - } if (runtime->no_period_wakeup) { snd_pcm_sframes_t xrun_threshold; @@ -431,13 +341,10 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, /* something must be really wrong */ if (delta >= runtime->buffer_size + runtime->period_size) { - hw_ptr_error(substream, - "Unexpected hw_pointer value %s" - "(stream=%i, pos=%ld, new_hw_ptr=%ld, " - "old_hw_ptr=%ld)\n", - in_interrupt ? "[Q] " : "[P]", - substream->stream, (long)pos, - (long)new_hw_ptr, (long)old_hw_ptr); + hw_ptr_error(substream, in_interrupt, "Unexpected hw_ptr", + "(stream=%i, pos=%ld, new_hw_ptr=%ld, old_hw_ptr=%ld)\n", + substream->stream, (long)pos, + (long)new_hw_ptr, (long)old_hw_ptr); return 0; } @@ -474,11 +381,8 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, delta--; } /* align hw_base to buffer_size */ - hw_ptr_error(substream, - "hw_ptr skipping! %s" - "(pos=%ld, delta=%ld, period=%ld, " - "jdelta=%lu/%lu/%lu, hw_ptr=%ld/%ld)\n", - in_interrupt ? "[Q] " : "", + hw_ptr_error(substream, in_interrupt, "hw_ptr skipping", + "(pos=%ld, delta=%ld, period=%ld, jdelta=%lu/%lu/%lu, hw_ptr=%ld/%ld)\n", (long)pos, (long)hdelta, (long)runtime->period_size, jdelta, ((hdelta * HZ) / runtime->rate), hw_base, @@ -490,11 +394,9 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, } no_jiffies_check: if (delta > runtime->period_size + runtime->period_size / 2) { - hw_ptr_error(substream, - "Lost interrupts? %s" - "(stream=%i, delta=%ld, new_hw_ptr=%ld, " - "old_hw_ptr=%ld)\n", - in_interrupt ? "[Q] " : "", + hw_ptr_error(substream, in_interrupt, + "Lost interrupts?", + "(stream=%i, delta=%ld, new_hw_ptr=%ld, old_hw_ptr=%ld)\n", substream->stream, (long)delta, (long)new_hw_ptr, (long)old_hw_ptr); diff --git a/sound/core/pcm_trace.h b/sound/core/pcm_trace.h new file mode 100644 index 000000000000..b63b654da5ff --- /dev/null +++ b/sound/core/pcm_trace.h @@ -0,0 +1,110 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM snd_pcm +#define TRACE_INCLUDE_FILE pcm_trace + +#if !defined(_PCM_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) +#define _PCM_TRACE_H + +#include + +TRACE_EVENT(hwptr, + TP_PROTO(struct snd_pcm_substream *substream, snd_pcm_uframes_t pos, bool irq), + TP_ARGS(substream, pos, irq), + TP_STRUCT__entry( + __field( bool, in_interrupt ) + __field( unsigned int, card ) + __field( unsigned int, device ) + __field( unsigned int, number ) + __field( unsigned int, stream ) + __field( snd_pcm_uframes_t, pos ) + __field( snd_pcm_uframes_t, period_size ) + __field( snd_pcm_uframes_t, buffer_size ) + __field( snd_pcm_uframes_t, old_hw_ptr ) + __field( snd_pcm_uframes_t, hw_ptr_base ) + ), + TP_fast_assign( + __entry->in_interrupt = (irq); + __entry->card = (substream)->pcm->card->number; + __entry->device = (substream)->pcm->device; + __entry->number = (substream)->number; + __entry->stream = (substream)->stream; + __entry->pos = (pos); + __entry->period_size = (substream)->runtime->period_size; + __entry->buffer_size = (substream)->runtime->buffer_size; + __entry->old_hw_ptr = (substream)->runtime->status->hw_ptr; + __entry->hw_ptr_base = (substream)->runtime->hw_ptr_base; + ), + TP_printk("pcmC%dD%d%c/sub%d: %s: pos=%lu, old=%lu, base=%lu, period=%lu, buf=%lu", + __entry->card, __entry->device, + __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c', + __entry->number, + __entry->in_interrupt ? "IRQ" : "POS", + (unsigned long)__entry->pos, + (unsigned long)__entry->old_hw_ptr, + (unsigned long)__entry->hw_ptr_base, + (unsigned long)__entry->period_size, + (unsigned long)__entry->buffer_size) +); + +TRACE_EVENT(xrun, + TP_PROTO(struct snd_pcm_substream *substream), + TP_ARGS(substream), + TP_STRUCT__entry( + __field( unsigned int, card ) + __field( unsigned int, device ) + __field( unsigned int, number ) + __field( unsigned int, stream ) + __field( snd_pcm_uframes_t, period_size ) + __field( snd_pcm_uframes_t, buffer_size ) + __field( snd_pcm_uframes_t, old_hw_ptr ) + __field( snd_pcm_uframes_t, hw_ptr_base ) + ), + TP_fast_assign( + __entry->card = (substream)->pcm->card->number; + __entry->device = (substream)->pcm->device; + __entry->number = (substream)->number; + __entry->stream = (substream)->stream; + __entry->period_size = (substream)->runtime->period_size; + __entry->buffer_size = (substream)->runtime->buffer_size; + __entry->old_hw_ptr = (substream)->runtime->status->hw_ptr; + __entry->hw_ptr_base = (substream)->runtime->hw_ptr_base; + ), + TP_printk("pcmC%dD%d%c/sub%d: XRUN: old=%lu, base=%lu, period=%lu, buf=%lu", + __entry->card, __entry->device, + __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c', + __entry->number, + (unsigned long)__entry->old_hw_ptr, + (unsigned long)__entry->hw_ptr_base, + (unsigned long)__entry->period_size, + (unsigned long)__entry->buffer_size) +); + +TRACE_EVENT(hw_ptr_error, + TP_PROTO(struct snd_pcm_substream *substream, const char *why), + TP_ARGS(substream, why), + TP_STRUCT__entry( + __field( unsigned int, card ) + __field( unsigned int, device ) + __field( unsigned int, number ) + __field( unsigned int, stream ) + __field( const char *, reason ) + ), + TP_fast_assign( + __entry->card = (substream)->pcm->card->number; + __entry->device = (substream)->pcm->device; + __entry->number = (substream)->number; + __entry->stream = (substream)->stream; + __entry->reason = (why); + ), + TP_printk("pcmC%dD%d%c/sub%d: ERROR: %s", + __entry->card, __entry->device, + __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c', + __entry->number, __entry->reason) +); + +#endif /* _PCM_TRACE_H */ + +/* This part must be outside protection */ +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#include -- cgit v1.2.3-59-g8ed1b From 2b30d411dbc6eddfb5b4f9afd5a2c57b6f4dd96c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 4 Nov 2014 14:02:40 +0100 Subject: ALSA: pcm: Add xrun_injection proc entry This patch adds a new proc entry for PCM substreams to inject an XRUN. When a PCM substream is running and any value is written to its xrun_injection proc file, the driver triggers XRUN. This is a useful feature for debugging XRUN and error handling code paths. Note that this entry is enabled only when CONFIG_SND_PCM_XRUN_DEBUG is set. Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/Procfile.txt | 4 ++++ include/sound/pcm.h | 3 +++ sound/core/pcm.c | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/Procfile.txt b/Documentation/sound/alsa/Procfile.txt index cfc49567b9dc..7f8a0d325905 100644 --- a/Documentation/sound/alsa/Procfile.txt +++ b/Documentation/sound/alsa/Procfile.txt @@ -133,6 +133,10 @@ card*/pcm*/sub*/sw_params card*/pcm*/sub*/prealloc The buffer pre-allocation information. +card*/pcm*/sub*/xrun_injection + Triggers an XRUN to the running stream when any value is + written to this proc file. Used for fault injection. + This entry is write-only. AC97 Codec Information ---------------------- diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 29eb09ef2969..0b8daeed0a33 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -416,7 +416,10 @@ struct snd_pcm_substream { struct snd_info_entry *proc_status_entry; struct snd_info_entry *proc_prealloc_entry; struct snd_info_entry *proc_prealloc_max_entry; +#ifdef CONFIG_SND_PCM_XRUN_DEBUG + struct snd_info_entry *proc_xrun_injection_entry; #endif +#endif /* CONFIG_SND_VERBOSE_PROCFS */ /* misc flags */ unsigned int hw_opened: 1; }; diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 31acc3df62cd..8f624b7af0ca 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -483,6 +483,19 @@ static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry, } #ifdef CONFIG_SND_PCM_XRUN_DEBUG +static void snd_pcm_xrun_injection_write(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + struct snd_pcm_substream *substream = entry->private_data; + struct snd_pcm_runtime *runtime; + + snd_pcm_stream_lock_irq(substream); + runtime = substream->runtime; + if (runtime && runtime->status->state == SNDRV_PCM_STATE_RUNNING) + snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); + snd_pcm_stream_unlock_irq(substream); +} + static void snd_pcm_xrun_debug_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { @@ -614,6 +627,22 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream) } substream->proc_status_entry = entry; +#ifdef CONFIG_SND_PCM_XRUN_DEBUG + entry = snd_info_create_card_entry(card, "xrun_injection", + substream->proc_root); + if (entry) { + entry->private_data = substream; + entry->c.text.read = NULL; + entry->c.text.write = snd_pcm_xrun_injection_write; + entry->mode = S_IFREG | S_IWUSR; + if (snd_info_register(entry) < 0) { + snd_info_free_entry(entry); + entry = NULL; + } + } + substream->proc_xrun_injection_entry = entry; +#endif /* CONFIG_SND_PCM_XRUN_DEBUG */ + return 0; } @@ -627,6 +656,10 @@ static int snd_pcm_substream_proc_done(struct snd_pcm_substream *substream) substream->proc_sw_params_entry = NULL; snd_info_free_entry(substream->proc_status_entry); substream->proc_status_entry = NULL; +#ifdef CONFIG_SND_PCM_XRUN_DEBUG + snd_info_free_entry(substream->proc_xrun_injection_entry); + substream->proc_xrun_injection_entry = NULL; +#endif snd_info_free_entry(substream->proc_root); substream->proc_root = NULL; return 0; -- cgit v1.2.3-59-g8ed1b From 5063e25a302e6a83f6590d9a06bd5f6400b17430 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Fri, 3 Oct 2014 16:28:27 +0100 Subject: of: Eliminate of_allnodes list The device tree structure is composed of two lists; the 'allnodes' list which is a singly linked list containing every node in the tree, and the child->parent structure where each parent node has a singly linked list of children. All of the data in the allnodes list can be easily reproduced with the parent-child lists, so of_allnodes is actually unnecessary. Remove it entirely which saves a bit of memory and simplifies the data structure quite a lot. Signed-off-by: Grant Likely Cc: Rob Herring Cc: Gaurav Minocha Cc: Pantelis Antoniou --- Documentation/devicetree/of_selftest.txt | 20 ++------- Documentation/devicetree/todo.txt | 1 - drivers/mfd/vexpress-sysreg.c | 2 +- drivers/of/base.c | 53 ++++++++++++++---------- drivers/of/dynamic.c | 13 ------ drivers/of/fdt.c | 30 +++++++------- drivers/of/pdt.c | 27 ++++-------- drivers/of/selftest.c | 71 +++++++++++++++----------------- include/linux/of.h | 11 ++--- include/linux/of_pdt.h | 3 +- 10 files changed, 98 insertions(+), 133 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/of_selftest.txt b/Documentation/devicetree/of_selftest.txt index 1e3d5c92b5e3..57a808b588bf 100644 --- a/Documentation/devicetree/of_selftest.txt +++ b/Documentation/devicetree/of_selftest.txt @@ -63,7 +63,6 @@ struct device_node { struct device_node *parent; struct device_node *child; struct device_node *sibling; - struct device_node *allnext; /* next in list of all nodes */ ... }; @@ -99,12 +98,6 @@ child11 -> sibling12 -> sibling13 -> sibling14 -> null Figure 1: Generic structure of un-flattened device tree -*allnext: it is used to link all the nodes of DT into a list. So, for the - above tree the list would be as follows: - -root->child1->child11->sibling12->sibling13->child131->sibling14->sibling2-> -child21->sibling22->sibling23->sibling3->child31->sibling32->sibling4->null - Before executing OF selftest, it is required to attach the test data to machine's device tree (if present). So, when selftest_data_add() is called, at first it reads the flattened device tree data linked into the kernel image @@ -131,11 +124,6 @@ root ('/') test-child01 null null null -allnext list: - -root->testcase-data->test-child0->test-child01->test-sibling1->test-sibling2 -->test-sibling3->null - Figure 2: Example test data tree to be attached to live tree. According to the scenario above, the live tree is already present so it isn't @@ -204,8 +192,6 @@ detached and then moving up the parent nodes are removed, and eventually the whole tree). selftest_data_remove() calls detach_node_and_children() that uses of_detach_node() to detach the nodes from the live device tree. -To detach a node, of_detach_node() first updates all_next linked list, by -attaching the previous node's allnext to current node's allnext pointer. And -then, it either updates the child pointer of given node's parent to its -sibling or attaches the previous sibling to the given node's sibling, as -appropriate. That is it :) +To detach a node, of_detach_node() either updates the child pointer of given +node's parent to its sibling or attaches the previous sibling to the given +node's sibling, as appropriate. That is it :) diff --git a/Documentation/devicetree/todo.txt b/Documentation/devicetree/todo.txt index c3cf0659bd19..b5139d1de811 100644 --- a/Documentation/devicetree/todo.txt +++ b/Documentation/devicetree/todo.txt @@ -2,7 +2,6 @@ Todo list for devicetree: === General structure === - Switch from custom lists to (h)list_head for nodes and properties structure -- Remove of_allnodes list and iterate using list of child nodes alone === CONFIG_OF_DYNAMIC === - Switch to RCU for tree updates and get rid of global spinlock diff --git a/drivers/mfd/vexpress-sysreg.c b/drivers/mfd/vexpress-sysreg.c index 9e21e4fc9599..8f43ab8fd2d6 100644 --- a/drivers/mfd/vexpress-sysreg.c +++ b/drivers/mfd/vexpress-sysreg.c @@ -223,7 +223,7 @@ static int vexpress_sysreg_probe(struct platform_device *pdev) vexpress_config_set_master(vexpress_sysreg_get_master()); /* Confirm board type against DT property, if available */ - if (of_property_read_u32(of_allnodes, "arm,hbi", &dt_hbi) == 0) { + if (of_property_read_u32(of_root, "arm,hbi", &dt_hbi) == 0) { u32 id = vexpress_get_procid(VEXPRESS_SITE_MASTER); u32 hbi = (id >> SYS_PROCIDx_HBI_SHIFT) & SYS_HBI_MASK; diff --git a/drivers/of/base.c b/drivers/of/base.c index 3823edf2d012..1f61a908a767 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -32,8 +32,8 @@ LIST_HEAD(aliases_lookup); -struct device_node *of_allnodes; -EXPORT_SYMBOL(of_allnodes); +struct device_node *of_root; +EXPORT_SYMBOL(of_root); struct device_node *of_chosen; struct device_node *of_aliases; struct device_node *of_stdout; @@ -48,7 +48,7 @@ struct kset *of_kset; */ DEFINE_MUTEX(of_mutex); -/* use when traversing tree through the allnext, child, sibling, +/* use when traversing tree through the child, sibling, * or parent members of struct device_node. */ DEFINE_RAW_SPINLOCK(devtree_lock); @@ -204,7 +204,7 @@ static int __init of_init(void) mutex_unlock(&of_mutex); /* Symlink in /proc as required by userspace ABI */ - if (of_allnodes) + if (of_root) proc_symlink("device-tree", NULL, "/sys/firmware/devicetree/base"); return 0; @@ -245,6 +245,23 @@ struct property *of_find_property(const struct device_node *np, } EXPORT_SYMBOL(of_find_property); +struct device_node *__of_find_all_nodes(struct device_node *prev) +{ + struct device_node *np; + if (!prev) { + np = of_root; + } else if (prev->child) { + np = prev->child; + } else { + /* Walk back up looking for a sibling, or the end of the structure */ + np = prev; + while (np->parent && !np->sibling) + np = np->parent; + np = np->sibling; /* Might be null at the end of the tree */ + } + return np; +} + /** * of_find_all_nodes - Get next node in global list * @prev: Previous node or NULL to start iteration @@ -259,10 +276,8 @@ struct device_node *of_find_all_nodes(struct device_node *prev) unsigned long flags; raw_spin_lock_irqsave(&devtree_lock, flags); - np = prev ? prev->allnext : of_allnodes; - for (; np != NULL; np = np->allnext) - if (of_node_get(np)) - break; + np = __of_find_all_nodes(prev); + of_node_get(np); of_node_put(prev); raw_spin_unlock_irqrestore(&devtree_lock, flags); return np; @@ -736,7 +751,7 @@ struct device_node *of_find_node_by_path(const char *path) unsigned long flags; if (strcmp(path, "/") == 0) - return of_node_get(of_allnodes); + return of_node_get(of_root); /* The path could begin with an alias */ if (*path != '/') { @@ -761,7 +776,7 @@ struct device_node *of_find_node_by_path(const char *path) /* Step down the tree matching path components */ raw_spin_lock_irqsave(&devtree_lock, flags); if (!np) - np = of_node_get(of_allnodes); + np = of_node_get(of_root); while (np && *path == '/') { path++; /* Increment past '/' delimiter */ np = __of_find_node_by_path(np, path); @@ -790,8 +805,7 @@ struct device_node *of_find_node_by_name(struct device_node *from, unsigned long flags; raw_spin_lock_irqsave(&devtree_lock, flags); - np = from ? from->allnext : of_allnodes; - for (; np; np = np->allnext) + for_each_of_allnodes_from(from, np) if (np->name && (of_node_cmp(np->name, name) == 0) && of_node_get(np)) break; @@ -820,8 +834,7 @@ struct device_node *of_find_node_by_type(struct device_node *from, unsigned long flags; raw_spin_lock_irqsave(&devtree_lock, flags); - np = from ? from->allnext : of_allnodes; - for (; np; np = np->allnext) + for_each_of_allnodes_from(from, np) if (np->type && (of_node_cmp(np->type, type) == 0) && of_node_get(np)) break; @@ -852,12 +865,10 @@ struct device_node *of_find_compatible_node(struct device_node *from, unsigned long flags; raw_spin_lock_irqsave(&devtree_lock, flags); - np = from ? from->allnext : of_allnodes; - for (; np; np = np->allnext) { + for_each_of_allnodes_from(from, np) if (__of_device_is_compatible(np, compatible, type, NULL) && of_node_get(np)) break; - } of_node_put(from); raw_spin_unlock_irqrestore(&devtree_lock, flags); return np; @@ -884,8 +895,7 @@ struct device_node *of_find_node_with_property(struct device_node *from, unsigned long flags; raw_spin_lock_irqsave(&devtree_lock, flags); - np = from ? from->allnext : of_allnodes; - for (; np; np = np->allnext) { + for_each_of_allnodes_from(from, np) { for (pp = np->properties; pp; pp = pp->next) { if (of_prop_cmp(pp->name, prop_name) == 0) { of_node_get(np); @@ -967,8 +977,7 @@ struct device_node *of_find_matching_node_and_match(struct device_node *from, *match = NULL; raw_spin_lock_irqsave(&devtree_lock, flags); - np = from ? from->allnext : of_allnodes; - for (; np; np = np->allnext) { + for_each_of_allnodes_from(from, np) { m = __of_match_node(matches, np); if (m && of_node_get(np)) { if (match) @@ -1025,7 +1034,7 @@ struct device_node *of_find_node_by_phandle(phandle handle) return NULL; raw_spin_lock_irqsave(&devtree_lock, flags); - for (np = of_allnodes; np; np = np->allnext) + for_each_of_allnodes(np) if (np->phandle == handle) break; of_node_get(np); diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c index f297891d8529..da2509d639c8 100644 --- a/drivers/of/dynamic.c +++ b/drivers/of/dynamic.c @@ -117,8 +117,6 @@ void __of_attach_node(struct device_node *np) np->child = NULL; np->sibling = np->parent->child; - np->allnext = np->parent->allnext; - np->parent->allnext = np; np->parent->child = np; of_node_clear_flag(np, OF_DETACHED); } @@ -154,17 +152,6 @@ void __of_detach_node(struct device_node *np) if (WARN_ON(!parent)) return; - if (of_allnodes == np) - of_allnodes = np->allnext; - else { - struct device_node *prev; - for (prev = of_allnodes; - prev->allnext != np; - prev = prev->allnext) - ; - prev->allnext = np->allnext; - } - if (parent->child == np) parent->child = np->sibling; else { diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index d1ffca8b34ea..1d30b9f96466 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -145,15 +145,15 @@ static void *unflatten_dt_alloc(void **mem, unsigned long size, * @mem: Memory chunk to use for allocating device nodes and properties * @p: pointer to node in flat tree * @dad: Parent struct device_node - * @allnextpp: pointer to ->allnext from last allocated device_node * @fpsize: Size of the node path up at the current depth. */ static void * unflatten_dt_node(void *blob, void *mem, int *poffset, struct device_node *dad, - struct device_node ***allnextpp, - unsigned long fpsize) + struct device_node **nodepp, + unsigned long fpsize, + bool dryrun) { const __be32 *p; struct device_node *np; @@ -200,7 +200,7 @@ static void * unflatten_dt_node(void *blob, np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl, __alignof__(struct device_node)); - if (allnextpp) { + if (!dryrun) { char *fn; of_node_init(np); np->full_name = fn = ((char *)np) + sizeof(*np); @@ -222,8 +222,6 @@ static void * unflatten_dt_node(void *blob, memcpy(fn, pathp, l); prev_pp = &np->properties; - **allnextpp = np; - *allnextpp = &np->allnext; if (dad != NULL) { np->parent = dad; /* we temporarily use the next field as `last_child'*/ @@ -254,7 +252,7 @@ static void * unflatten_dt_node(void *blob, has_name = 1; pp = unflatten_dt_alloc(&mem, sizeof(struct property), __alignof__(struct property)); - if (allnextpp) { + if (!dryrun) { /* We accept flattened tree phandles either in * ePAPR-style "phandle" properties, or the * legacy "linux,phandle" properties. If both @@ -296,7 +294,7 @@ static void * unflatten_dt_node(void *blob, sz = (pa - ps) + 1; pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz, __alignof__(struct property)); - if (allnextpp) { + if (!dryrun) { pp->name = "name"; pp->length = sz; pp->value = pp + 1; @@ -308,7 +306,7 @@ static void * unflatten_dt_node(void *blob, (char *)pp->value); } } - if (allnextpp) { + if (!dryrun) { *prev_pp = NULL; np->name = of_get_property(np, "name", NULL); np->type = of_get_property(np, "device_type", NULL); @@ -324,11 +322,13 @@ static void * unflatten_dt_node(void *blob, if (depth < 0) depth = 0; while (*poffset > 0 && depth > old_depth) - mem = unflatten_dt_node(blob, mem, poffset, np, allnextpp, - fpsize); + mem = unflatten_dt_node(blob, mem, poffset, np, NULL, + fpsize, dryrun); if (*poffset < 0 && *poffset != -FDT_ERR_NOTFOUND) pr_err("unflatten: error %d processing FDT\n", *poffset); + if (nodepp) + *nodepp = np; return mem; } @@ -352,7 +352,6 @@ static void __unflatten_device_tree(void *blob, unsigned long size; int start; void *mem; - struct device_node **allnextp = mynodes; pr_debug(" -> unflatten_device_tree()\n"); @@ -373,7 +372,7 @@ static void __unflatten_device_tree(void *blob, /* First pass, scan for size */ start = 0; - size = (unsigned long)unflatten_dt_node(blob, NULL, &start, NULL, NULL, 0); + size = (unsigned long)unflatten_dt_node(blob, NULL, &start, NULL, NULL, 0, true); size = ALIGN(size, 4); pr_debug(" size is %lx, allocating...\n", size); @@ -388,11 +387,10 @@ static void __unflatten_device_tree(void *blob, /* Second pass, do actual unflattening */ start = 0; - unflatten_dt_node(blob, mem, &start, NULL, &allnextp, 0); + unflatten_dt_node(blob, mem, &start, NULL, mynodes, 0, false); if (be32_to_cpup(mem + size) != 0xdeadbeef) pr_warning("End of tree marker overwritten: %08x\n", be32_to_cpup(mem + size)); - *allnextp = NULL; pr_debug(" <- unflatten_device_tree()\n"); } @@ -1041,7 +1039,7 @@ bool __init early_init_dt_scan(void *params) */ void __init unflatten_device_tree(void) { - __unflatten_device_tree(initial_boot_params, &of_allnodes, + __unflatten_device_tree(initial_boot_params, &of_root, early_init_dt_alloc_memory_arch); /* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */ diff --git a/drivers/of/pdt.c b/drivers/of/pdt.c index 36b4035881b0..d2acae825af9 100644 --- a/drivers/of/pdt.c +++ b/drivers/of/pdt.c @@ -25,8 +25,7 @@ static struct of_pdt_ops *of_pdt_prom_ops __initdata; -void __initdata (*of_pdt_build_more)(struct device_node *dp, - struct device_node ***nextp); +void __initdata (*of_pdt_build_more)(struct device_node *dp); #if defined(CONFIG_SPARC) unsigned int of_pdt_unique_id __initdata; @@ -192,8 +191,7 @@ static struct device_node * __init of_pdt_create_node(phandle node, } static struct device_node * __init of_pdt_build_tree(struct device_node *parent, - phandle node, - struct device_node ***nextp) + phandle node) { struct device_node *ret = NULL, *prev_sibling = NULL; struct device_node *dp; @@ -210,16 +208,12 @@ static struct device_node * __init of_pdt_build_tree(struct device_node *parent, ret = dp; prev_sibling = dp; - *(*nextp) = dp; - *nextp = &dp->allnext; - dp->full_name = of_pdt_build_full_name(dp); - dp->child = of_pdt_build_tree(dp, - of_pdt_prom_ops->getchild(node), nextp); + dp->child = of_pdt_build_tree(dp, of_pdt_prom_ops->getchild(node)); if (of_pdt_build_more) - of_pdt_build_more(dp, nextp); + of_pdt_build_more(dp); node = of_pdt_prom_ops->getsibling(node); } @@ -234,20 +228,17 @@ static void * __init kernel_tree_alloc(u64 size, u64 align) void __init of_pdt_build_devicetree(phandle root_node, struct of_pdt_ops *ops) { - struct device_node **nextp; - BUG_ON(!ops); of_pdt_prom_ops = ops; - of_allnodes = of_pdt_create_node(root_node, NULL); + of_root = of_pdt_create_node(root_node, NULL); #if defined(CONFIG_SPARC) - of_allnodes->path_component_name = ""; + of_root->path_component_name = ""; #endif - of_allnodes->full_name = "/"; + of_root->full_name = "/"; - nextp = &of_allnodes->allnext; - of_allnodes->child = of_pdt_build_tree(of_allnodes, - of_pdt_prom_ops->getchild(of_allnodes->phandle), &nextp); + of_root->child = of_pdt_build_tree(of_root, + of_pdt_prom_ops->getchild(of_root->phandle)); /* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */ of_alias_scan(kernel_tree_alloc); diff --git a/drivers/of/selftest.c b/drivers/of/selftest.c index 11b873c54a77..bf7d99317a94 100644 --- a/drivers/of/selftest.c +++ b/drivers/of/selftest.c @@ -148,7 +148,7 @@ static void __init of_selftest_dynamic(void) static int __init of_selftest_check_node_linkage(struct device_node *np) { - struct device_node *child, *allnext_index = np; + struct device_node *child; int count = 0, rc; for_each_child_of_node(np, child) { @@ -158,14 +158,6 @@ static int __init of_selftest_check_node_linkage(struct device_node *np) return -EINVAL; } - while (allnext_index && allnext_index != child) - allnext_index = allnext_index->allnext; - if (allnext_index != child) { - pr_err("Node %s is ordered differently in sibling and allnode lists\n", - child->name); - return -EINVAL; - } - rc = of_selftest_check_node_linkage(child); if (rc < 0) return rc; @@ -180,12 +172,12 @@ static void __init of_selftest_check_tree_linkage(void) struct device_node *np; int allnode_count = 0, child_count; - if (!of_allnodes) + if (!of_root) return; for_each_of_allnodes(np) allnode_count++; - child_count = of_selftest_check_node_linkage(of_allnodes); + child_count = of_selftest_check_node_linkage(of_root); selftest(child_count > 0, "Device node data structure is corrupted\n"); selftest(child_count == allnode_count, "allnodes list size (%i) doesn't match" @@ -775,33 +767,29 @@ static void update_node_properties(struct device_node *np, */ static int attach_node_and_children(struct device_node *np) { - struct device_node *next, *root = np, *dup; + struct device_node *next, *dup, *child; - /* skip root node */ - np = np->child; - /* storing a copy in temporary node */ - dup = np; + dup = of_find_node_by_path(np->full_name); + if (dup) { + update_node_properties(np, dup); + return 0; + } - while (dup) { + /* Children of the root need to be remembered for removal */ + if (np->parent == of_root) { if (WARN_ON(last_node_index >= NO_OF_NODES)) return -EINVAL; - nodes[last_node_index++] = dup; - dup = dup->sibling; + nodes[last_node_index++] = np; } - dup = NULL; - while (np) { - next = np->allnext; - dup = of_find_node_by_path(np->full_name); - if (dup) - update_node_properties(np, dup); - else { - np->child = NULL; - if (np->parent == root) - np->parent = of_allnodes; - of_attach_node(np); - } - np = next; + child = np->child; + np->child = NULL; + np->sibling = NULL; + of_attach_node(np); + while (child) { + next = child->sibling; + attach_node_and_children(child); + child = next; } return 0; @@ -846,10 +834,10 @@ static int __init selftest_data_add(void) return -EINVAL; } - if (!of_allnodes) { + if (!of_root) { /* enabling flag for removing nodes */ selftest_live_tree = true; - of_allnodes = selftest_data_node; + of_root = selftest_data_node; for_each_of_allnodes(np) __of_attach_node_sysfs(np); @@ -859,7 +847,14 @@ static int __init selftest_data_add(void) } /* attach the sub-tree to live tree */ - return attach_node_and_children(selftest_data_node); + np = selftest_data_node->child; + while (np) { + struct device_node *next = np->sibling; + np->parent = of_root; + attach_node_and_children(np); + np = next; + } + return 0; } /** @@ -889,10 +884,10 @@ static void selftest_data_remove(void) of_node_put(of_chosen); of_aliases = NULL; of_chosen = NULL; - for_each_child_of_node(of_allnodes, np) + for_each_child_of_node(of_root, np) detach_node_and_children(np); - __of_detach_node_sysfs(of_allnodes); - of_allnodes = NULL; + __of_detach_node_sysfs(of_root); + of_root = NULL; return; } diff --git a/include/linux/of.h b/include/linux/of.h index 30912939a610..f54da3b699a8 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -56,7 +56,6 @@ struct device_node { struct device_node *child; struct device_node *sibling; struct device_node *next; /* next device of same type */ - struct device_node *allnext; /* next in list of all nodes */ struct kobject kobj; unsigned long _flags; void *data; @@ -108,7 +107,7 @@ static inline void of_node_put(struct device_node *node) { } #ifdef CONFIG_OF /* Pointer for first entry in chain of all nodes. */ -extern struct device_node *of_allnodes; +extern struct device_node *of_root; extern struct device_node *of_chosen; extern struct device_node *of_aliases; extern struct device_node *of_stdout; @@ -116,7 +115,7 @@ extern raw_spinlock_t devtree_lock; static inline bool of_have_populated_dt(void) { - return of_allnodes != NULL; + return of_root != NULL; } static inline bool of_node_is_root(const struct device_node *node) @@ -160,6 +159,7 @@ static inline void of_property_clear_flag(struct property *p, unsigned long flag clear_bit(flag, &p->_flags); } +extern struct device_node *__of_find_all_nodes(struct device_node *prev); extern struct device_node *of_find_all_nodes(struct device_node *prev); /* @@ -215,8 +215,9 @@ static inline const char *of_node_full_name(const struct device_node *np) return np ? np->full_name : ""; } -#define for_each_of_allnodes(dn) \ - for (dn = of_allnodes; dn; dn = dn->allnext) +#define for_each_of_allnodes_from(from, dn) \ + for (dn = __of_find_all_nodes(from); dn; dn = __of_find_all_nodes(dn)) +#define for_each_of_allnodes(dn) for_each_of_allnodes_from(NULL, dn) extern struct device_node *of_find_node_by_name(struct device_node *from, const char *name); extern struct device_node *of_find_node_by_type(struct device_node *from, diff --git a/include/linux/of_pdt.h b/include/linux/of_pdt.h index c65a18a0cfdf..7e09244bb679 100644 --- a/include/linux/of_pdt.h +++ b/include/linux/of_pdt.h @@ -39,7 +39,6 @@ extern void *prom_early_alloc(unsigned long size); /* for building the device tree */ extern void of_pdt_build_devicetree(phandle root_node, struct of_pdt_ops *ops); -extern void (*of_pdt_build_more)(struct device_node *dp, - struct device_node ***nextp); +extern void (*of_pdt_build_more)(struct device_node *dp); #endif /* _LINUX_OF_PDT_H */ -- cgit v1.2.3-59-g8ed1b From b8ab956c544e51a8d19ea3f38b54355d6aa92c33 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 4 Nov 2014 12:52:41 +0100 Subject: block: Expand a bit documentation about elevator_allow_merge_fn Explain that two requests can be merged without elevator_allow_merge_fn() being called. Signed-off-by: Jan Kara Signed-off-by: Jens Axboe --- Documentation/block/biodoc.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/block/biodoc.txt b/Documentation/block/biodoc.txt index 2101e718670d..f1323c6b7ed2 100644 --- a/Documentation/block/biodoc.txt +++ b/Documentation/block/biodoc.txt @@ -946,7 +946,11 @@ elevator_allow_merge_fn called whenever the block layer determines request safely. The io scheduler may still want to stop a merge at this point if it results in some sort of conflict internally, - this hook allows it to do that. + this hook allows it to do that. Note however + that two *requests* can still be merged at later + time. Currently the io scheduler has no way to + prevent that. It can only learn about the fact + from elevator_merge_req_fn callback. elevator_dispatch_fn* fills the dispatch queue with ready requests. I/O schedulers are free to postpone requests by -- cgit v1.2.3-59-g8ed1b From d1d81802522ade84128a2c66c0d500e372474dca Mon Sep 17 00:00:00 2001 From: Torsten Fleischer Date: Mon, 3 Nov 2014 17:17:55 +0100 Subject: spi: spi-gpio: Add dt support for a single device with no chip select In order to describe a single slave device that has no chip select line the 'num-chipselects' property has to be <0> and the 'cs-gpios' property doesn't need to be set. Signed-off-by: Torsten Fleischer Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/spi-gpio.txt | 6 ++++-- drivers/spi/spi-gpio.c | 21 +++++++++++++++------ 2 files changed, 19 insertions(+), 8 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/spi/spi-gpio.txt b/Documentation/devicetree/bindings/spi/spi-gpio.txt index 8a824be15754..a95603bcf6ff 100644 --- a/Documentation/devicetree/bindings/spi/spi-gpio.txt +++ b/Documentation/devicetree/bindings/spi/spi-gpio.txt @@ -8,8 +8,10 @@ Required properties: - gpio-sck: GPIO spec for the SCK line to use - gpio-miso: GPIO spec for the MISO line to use - gpio-mosi: GPIO spec for the MOSI line to use - - cs-gpios: GPIOs to use for chipselect lines - - num-chipselects: number of chipselect lines + - cs-gpios: GPIOs to use for chipselect lines. + Not needed if num-chipselects = <0>. + - num-chipselects: Number of chipselect lines. Should be <0> if a single device + with no chip select is connected. Example: diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c index 9f595535cf27..f0492c99d145 100644 --- a/drivers/spi/spi-gpio.c +++ b/drivers/spi/spi-gpio.c @@ -413,6 +413,7 @@ static int spi_gpio_probe(struct platform_device *pdev) struct spi_gpio_platform_data *pdata; u16 master_flags = 0; bool use_of = 0; + int num_devices; status = spi_gpio_probe_dt(pdev); if (status < 0) @@ -422,16 +423,21 @@ static int spi_gpio_probe(struct platform_device *pdev) pdata = dev_get_platdata(&pdev->dev); #ifdef GENERIC_BITBANG - if (!pdata || !pdata->num_chipselect) + if (!pdata || (!use_of && !pdata->num_chipselect)) return -ENODEV; #endif + if (use_of && !SPI_N_CHIPSEL) + num_devices = 1; + else + num_devices = SPI_N_CHIPSEL; + status = spi_gpio_request(pdata, dev_name(&pdev->dev), &master_flags); if (status < 0) return status; master = spi_alloc_master(&pdev->dev, sizeof(*spi_gpio) + - (sizeof(int) * SPI_N_CHIPSEL)); + (sizeof(int) * num_devices)); if (!master) { status = -ENOMEM; goto gpio_free; @@ -446,7 +452,7 @@ static int spi_gpio_probe(struct platform_device *pdev) master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32); master->flags = master_flags; master->bus_num = pdev->id; - master->num_chipselect = SPI_N_CHIPSEL; + master->num_chipselect = num_devices; master->setup = spi_gpio_setup; master->cleanup = spi_gpio_cleanup; #ifdef CONFIG_OF @@ -461,9 +467,12 @@ static int spi_gpio_probe(struct platform_device *pdev) * property of the node. */ - for (i = 0; i < SPI_N_CHIPSEL; i++) - spi_gpio->cs_gpios[i] = - of_get_named_gpio(np, "cs-gpios", i); + if (!SPI_N_CHIPSEL) + spi_gpio->cs_gpios[0] = SPI_GPIO_NO_CHIPSELECT; + else + for (i = 0; i < SPI_N_CHIPSEL; i++) + spi_gpio->cs_gpios[i] = + of_get_named_gpio(np, "cs-gpios", i); } #endif -- cgit v1.2.3-59-g8ed1b From defcd98b16461e123cb4a6cb6ef24a1d0085c1b2 Mon Sep 17 00:00:00 2001 From: Dylan Reid Date: Mon, 3 Nov 2014 10:28:57 -0800 Subject: ASoC: max98090: Different comp tables for different pclks In addtion expand the table to handle other values of sysclk. Instead of making the table 3D, expand it to a more descriptive struct. The divisors are specified in Table 19 of the 98090 data sheet version 0p94. The dmic frequency was previously assumed. Instead make it explicit and configurable through device tree. This now handles independently set pclk and dmic frequency. Based on downstream work by Ralph Birt. Signed-off-by: Dylan Reid Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/max98090.txt | 2 + sound/soc/codecs/max98090.c | 189 +++++++++++++++++---- sound/soc/codecs/max98090.h | 8 + 3 files changed, 163 insertions(+), 36 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/max98090.txt b/Documentation/devicetree/bindings/sound/max98090.txt index c454e67f54bb..aa802a274520 100644 --- a/Documentation/devicetree/bindings/sound/max98090.txt +++ b/Documentation/devicetree/bindings/sound/max98090.txt @@ -16,6 +16,8 @@ Optional properties: - clock-names: Should be "mclk" +- maxim,dmic-freq: Frequency at which to clock DMIC + Pins on the device (for linking into audio routes): * MIC1 diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index 1229554f1464..a65861cf0a44 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -1826,27 +1826,155 @@ static int max98090_set_bias_level(struct snd_soc_codec *codec, return 0; } -static const int comp_pclk_rates[] = { - 11289600, 12288000, 12000000, 13000000, 19200000 -}; - -static const int dmic_micclk[] = { - 2, 2, 2, 2, 4, 2 -}; +static const int dmic_divisors[] = { 2, 3, 4, 5, 6, 8 }; static const int comp_lrclk_rates[] = { 8000, 16000, 32000, 44100, 48000, 96000 }; -static const int dmic_comp[6][6] = { - {7, 8, 3, 3, 3, 3}, - {7, 8, 3, 3, 3, 3}, - {7, 8, 3, 3, 3, 3}, - {7, 8, 3, 1, 1, 1}, - {7, 8, 3, 1, 2, 2}, - {7, 8, 3, 3, 3, 3} +struct dmic_table { + int pclk; + struct { + int freq; + int comp[6]; /* One each for 8, 16, 32, 44.1, 48, and 96 kHz */ + } settings[6]; /* One for each dmic divisor. */ }; +static const struct dmic_table dmic_table[] = { /* One for each pclk freq. */ + { + .pclk = 11289600, + .settings = { + { .freq = 2, .comp = { 7, 8, 3, 3, 3, 3 } }, + { .freq = 1, .comp = { 7, 8, 2, 2, 2, 2 } }, + { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } }, + { .freq = 0, .comp = { 7, 8, 6, 6, 6, 6 } }, + { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } }, + { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } }, + }, + }, + { + .pclk = 12000000, + .settings = { + { .freq = 2, .comp = { 7, 8, 3, 3, 3, 3 } }, + { .freq = 1, .comp = { 7, 8, 2, 2, 2, 2 } }, + { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } }, + { .freq = 0, .comp = { 7, 8, 5, 5, 6, 6 } }, + { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } }, + { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } }, + } + }, + { + .pclk = 12288000, + .settings = { + { .freq = 2, .comp = { 7, 8, 3, 3, 3, 3 } }, + { .freq = 1, .comp = { 7, 8, 2, 2, 2, 2 } }, + { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } }, + { .freq = 0, .comp = { 7, 8, 6, 6, 6, 6 } }, + { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } }, + { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } }, + } + }, + { + .pclk = 13000000, + .settings = { + { .freq = 2, .comp = { 7, 8, 1, 1, 1, 1 } }, + { .freq = 1, .comp = { 7, 8, 0, 0, 0, 0 } }, + { .freq = 0, .comp = { 7, 8, 1, 1, 1, 1 } }, + { .freq = 0, .comp = { 7, 8, 4, 4, 5, 5 } }, + { .freq = 0, .comp = { 7, 8, 1, 1, 1, 1 } }, + { .freq = 0, .comp = { 7, 8, 1, 1, 1, 1 } }, + } + }, + { + .pclk = 19200000, + .settings = { + { .freq = 2, .comp = { 0, 0, 0, 0, 0, 0 } }, + { .freq = 1, .comp = { 7, 8, 1, 1, 1, 1 } }, + { .freq = 0, .comp = { 7, 8, 5, 5, 6, 6 } }, + { .freq = 0, .comp = { 7, 8, 2, 2, 3, 3 } }, + { .freq = 0, .comp = { 7, 8, 1, 1, 2, 2 } }, + { .freq = 0, .comp = { 7, 8, 5, 5, 6, 6 } }, + } + }, +}; + +static int max98090_find_divisor(int target_freq, int pclk) +{ + int current_diff = INT_MAX; + int test_diff = INT_MAX; + int divisor_index = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(dmic_divisors); i++) { + test_diff = abs(target_freq - (pclk / dmic_divisors[i])); + if (test_diff < current_diff) { + current_diff = test_diff; + divisor_index = i; + } + } + + return divisor_index; +} + +static int max98090_find_closest_pclk(int pclk) +{ + int m1; + int m2; + int i; + + for (i = 0; i < ARRAY_SIZE(dmic_table); i++) { + if (pclk == dmic_table[i].pclk) + return i; + if (pclk < dmic_table[i].pclk) { + if (i == 0) + return i; + m1 = pclk - dmic_table[i-1].pclk; + m2 = dmic_table[i].pclk - pclk; + if (m1 < m2) + return i - 1; + else + return i; + } + } + + return -EINVAL; +} + +static int max98090_configure_dmic(struct max98090_priv *max98090, + int target_dmic_clk, int pclk, int fs) +{ + int micclk_index; + int pclk_index; + int dmic_freq; + int dmic_comp; + int i; + + pclk_index = max98090_find_closest_pclk(pclk); + if (pclk_index < 0) + return pclk_index; + + micclk_index = max98090_find_divisor(target_dmic_clk, pclk); + + for (i = 0; i < ARRAY_SIZE(comp_lrclk_rates) - 1; i++) { + if (fs <= (comp_lrclk_rates[i] + comp_lrclk_rates[i+1]) / 2) + break; + } + + dmic_freq = dmic_table[pclk_index].settings[micclk_index].freq; + dmic_comp = dmic_table[pclk_index].settings[micclk_index].comp[i]; + + regmap_update_bits(max98090->regmap, M98090_REG_DIGITAL_MIC_ENABLE, + M98090_MICCLK_MASK, + micclk_index << M98090_MICCLK_SHIFT); + + regmap_update_bits(max98090->regmap, M98090_REG_DIGITAL_MIC_CONFIG, + M98090_DMIC_COMP_MASK | M98090_DMIC_FREQ_MASK, + dmic_comp << M98090_DMIC_COMP_SHIFT | + dmic_freq << M98090_DMIC_FREQ_SHIFT); + + return 0; +} + static int max98090_dai_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -1854,7 +1982,6 @@ static int max98090_dai_hw_params(struct snd_pcm_substream *substream, struct snd_soc_codec *codec = dai->codec; struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); struct max98090_cdata *cdata; - int i, j; cdata = &max98090->dai[0]; max98090->bclk = snd_soc_params_to_bclk(params); @@ -1893,27 +2020,8 @@ static int max98090_dai_hw_params(struct snd_pcm_substream *substream, snd_soc_update_bits(codec, M98090_REG_FILTER_CONFIG, M98090_DHF_MASK, M98090_DHF_MASK); - /* Check for supported PCLK to LRCLK ratios */ - for (j = 0; j < ARRAY_SIZE(comp_pclk_rates); j++) { - if (comp_pclk_rates[j] == max98090->sysclk) { - break; - } - } - - for (i = 0; i < ARRAY_SIZE(comp_lrclk_rates) - 1; i++) { - if (max98090->lrclk <= (comp_lrclk_rates[i] + - comp_lrclk_rates[i + 1]) / 2) { - break; - } - } - - snd_soc_update_bits(codec, M98090_REG_DIGITAL_MIC_ENABLE, - M98090_MICCLK_MASK, - dmic_micclk[j] << M98090_MICCLK_SHIFT); - - snd_soc_update_bits(codec, M98090_REG_DIGITAL_MIC_CONFIG, - M98090_DMIC_COMP_MASK, - dmic_comp[j][i] << M98090_DMIC_COMP_SHIFT); + max98090_configure_dmic(max98090, max98090->dmic_freq, max98090->pclk, + max98090->lrclk); return 0; } @@ -1944,12 +2052,15 @@ static int max98090_dai_set_sysclk(struct snd_soc_dai *dai, if ((freq >= 10000000) && (freq <= 20000000)) { snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK, M98090_PSCLK_DIV1); + max98090->pclk = freq; } else if ((freq > 20000000) && (freq <= 40000000)) { snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK, M98090_PSCLK_DIV2); + max98090->pclk = freq >> 1; } else if ((freq > 40000000) && (freq <= 60000000)) { snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK, M98090_PSCLK_DIV4); + max98090->pclk = freq >> 2; } else { dev_err(codec->dev, "Invalid master clock frequency\n"); return -EINVAL; @@ -2324,6 +2435,7 @@ static int max98090_probe(struct snd_soc_codec *codec) /* Initialize private data */ max98090->sysclk = (unsigned)-1; + max98090->pclk = (unsigned)-1; max98090->master = false; cdata = &max98090->dai[0]; @@ -2463,6 +2575,11 @@ static int max98090_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, max98090); max98090->pdata = i2c->dev.platform_data; + ret = of_property_read_u32(i2c->dev.of_node, "maxim,dmic-freq", + &max98090->dmic_freq); + if (ret < 0) + max98090->dmic_freq = MAX98090_DEFAULT_DMIC_FREQ; + max98090->regmap = devm_regmap_init_i2c(i2c, &max98090_regmap); if (IS_ERR(max98090->regmap)) { ret = PTR_ERR(max98090->regmap); diff --git a/sound/soc/codecs/max98090.h b/sound/soc/codecs/max98090.h index a5f6bada06da..21ff743f5af2 100644 --- a/sound/soc/codecs/max98090.h +++ b/sound/soc/codecs/max98090.h @@ -11,6 +11,12 @@ #ifndef _MAX98090_H #define _MAX98090_H +/* + * The default operating frequency for a DMIC attached to the codec. + * This can be overridden by a device tree property. + */ +#define MAX98090_DEFAULT_DMIC_FREQ 2500000 + /* * MAX98090 Register Definitions */ @@ -1518,8 +1524,10 @@ struct max98090_priv { struct max98090_pdata *pdata; struct clk *mclk; unsigned int sysclk; + unsigned int pclk; unsigned int bclk; unsigned int lrclk; + u32 dmic_freq; struct max98090_cdata dai[1]; int jack_state; struct delayed_work jack_work; -- cgit v1.2.3-59-g8ed1b From 0d9a693cc8619b28f0eeb689a554647d42848fde Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Wed, 29 Oct 2014 15:41:01 +0100 Subject: gpio / ACPI: Add support for _DSD device properties With release of ACPI 5.1 and _DSD method we can finally name GPIOs (and other things as well) returned by _CRS. Previously we were only able to use integer index to find the corresponding GPIO, which is pretty error prone if the order changes. With _DSD we can now query GPIOs using name instead of an integer index, like the below example shows: // Bluetooth device with reset and shutdown GPIOs Device (BTH) { Name (_HID, ...) Name (_CRS, ResourceTemplate () { GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionInputOnly, "\\_SB.GPO0", 0, ResourceConsumer) {15} GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionInputOnly, "\\_SB.GPO0", 0, ResourceConsumer) {27, 31} }) Name (_DSD, Package () { ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), Package () { Package () {"reset-gpio", Package() {^BTH, 1, 1, 0 }}, Package () {"shutdown-gpio", Package() {^BTH, 0, 0, 0 }}, } }) } The format of the supported GPIO property is: Package () { "name", Package () { ref, index, pin, active_low }} ref - The device that has _CRS containing GpioIo()/GpioInt() resources, typically this is the device itself (BTH in our case). index - Index of the GpioIo()/GpioInt() resource in _CRS starting from zero. pin - Pin in the GpioIo()/GpioInt() resource. Typically this is zero. active_low - If 1 the GPIO is marked as active_low. Since ACPI GpioIo() resource does not have field saying whether it is active low or high, the "active_low" argument can be used here. Setting it to 1 marks the GPIO as active low. In our Bluetooth example the "reset-gpio" refers to the second GpioIo() resource, second pin in that resource with the GPIO number of 31. This patch implements necessary support to gpiolib for extracting GPIOs using _DSD device properties. Signed-off-by: Mika Westerberg Acked-by: Linus Walleij Acked-by: Grant Likely Signed-off-by: Rafael J. Wysocki --- Documentation/acpi/gpio-properties.txt | 52 +++++++++++++++++++++++ drivers/gpio/gpiolib-acpi.c | 78 ++++++++++++++++++++++++++++------ drivers/gpio/gpiolib.c | 30 +++++++++++-- drivers/gpio/gpiolib.h | 7 +-- 4 files changed, 146 insertions(+), 21 deletions(-) create mode 100644 Documentation/acpi/gpio-properties.txt (limited to 'Documentation') diff --git a/Documentation/acpi/gpio-properties.txt b/Documentation/acpi/gpio-properties.txt new file mode 100644 index 000000000000..3e45b8b7e4f2 --- /dev/null +++ b/Documentation/acpi/gpio-properties.txt @@ -0,0 +1,52 @@ +_DSD Device Properties Related to GPIO +-------------------------------------- + +With the release of ACPI 5.1 and the _DSD configuration objecte names +can finally be given to GPIOs (and other things as well) returned by +_CRS. Previously, we were only able to use an integer index to find +the corresponding GPIO, which is pretty error prone (it depends on +the _CRS output ordering, for example). + +With _DSD we can now query GPIOs using a name instead of an integer +index, like the ASL example below shows: + + // Bluetooth device with reset and shutdown GPIOs + Device (BTH) + { + Name (_HID, ...) + + Name (_CRS, ResourceTemplate () + { + GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionInputOnly, + "\\_SB.GPO0", 0, ResourceConsumer) {15} + GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionInputOnly, + "\\_SB.GPO0", 0, ResourceConsumer) {27, 31} + }) + + Name (_DSD, Package () + { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () + { + Package () {"reset-gpio", Package() {^BTH, 1, 1, 0 }}, + Package () {"shutdown-gpio", Package() {^BTH, 0, 0, 0 }}, + } + }) + } + +The format of the supported GPIO property is: + + Package () { "name", Package () { ref, index, pin, active_low }} + + ref - The device that has _CRS containing GpioIo()/GpioInt() resources, + typically this is the device itself (BTH in our case). + index - Index of the GpioIo()/GpioInt() resource in _CRS starting from zero. + pin - Pin in the GpioIo()/GpioInt() resource. Typically this is zero. + active_low - If 1 the GPIO is marked as active_low. + +Since ACPI GpioIo() resource does not have a field saying whether it is +active low or high, the "active_low" argument can be used here. Setting +it to 1 marks the GPIO as active low. + +In our Bluetooth example the "reset-gpio" refers to the second GpioIo() +resource, second pin in that resource with the GPIO number of 31. diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 05c6275da224..8aa6ca473748 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -290,6 +290,7 @@ void acpi_gpiochip_free_interrupts(struct gpio_chip *chip) struct acpi_gpio_lookup { struct acpi_gpio_info info; int index; + int pin_index; struct gpio_desc *desc; int n; }; @@ -303,13 +304,24 @@ static int acpi_find_gpio(struct acpi_resource *ares, void *data) if (lookup->n++ == lookup->index && !lookup->desc) { const struct acpi_resource_gpio *agpio = &ares->data.gpio; + int pin_index = lookup->pin_index; + + if (pin_index >= agpio->pin_table_length) + return 1; lookup->desc = acpi_get_gpiod(agpio->resource_source.string_ptr, - agpio->pin_table[0]); + agpio->pin_table[pin_index]); lookup->info.gpioint = agpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT; - lookup->info.active_low = - agpio->polarity == ACPI_ACTIVE_LOW; + + /* + * ActiveLow is only specified for GpioInt resource. If + * GpioIo is used then the only way to set the flag is + * to use _DSD "gpios" property. + */ + if (lookup->info.gpioint) + lookup->info.active_low = + agpio->polarity == ACPI_ACTIVE_LOW; } return 1; @@ -317,40 +329,75 @@ static int acpi_find_gpio(struct acpi_resource *ares, void *data) /** * acpi_get_gpiod_by_index() - get a GPIO descriptor from device resources - * @dev: pointer to a device to get GPIO from + * @adev: pointer to a ACPI device to get GPIO from + * @propname: Property name of the GPIO (optional) * @index: index of GpioIo/GpioInt resource (starting from %0) * @info: info pointer to fill in (optional) * - * Function goes through ACPI resources for @dev and based on @index looks + * Function goes through ACPI resources for @adev and based on @index looks * up a GpioIo/GpioInt resource, translates it to the Linux GPIO descriptor, * and returns it. @index matches GpioIo/GpioInt resources only so if there * are total %3 GPIO resources, the index goes from %0 to %2. * + * If @propname is specified the GPIO is looked using device property. In + * that case @index is used to select the GPIO entry in the property value + * (in case of multiple). + * * If the GPIO cannot be translated or there is an error an ERR_PTR is * returned. * * Note: if the GPIO resource has multiple entries in the pin list, this * function only returns the first. */ -struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index, +struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev, + const char *propname, int index, struct acpi_gpio_info *info) { struct acpi_gpio_lookup lookup; struct list_head resource_list; - struct acpi_device *adev; - acpi_handle handle; + bool active_low = false; int ret; - if (!dev) - return ERR_PTR(-EINVAL); - - handle = ACPI_HANDLE(dev); - if (!handle || acpi_bus_get_device(handle, &adev)) + if (!adev) return ERR_PTR(-ENODEV); memset(&lookup, 0, sizeof(lookup)); lookup.index = index; + if (propname) { + struct acpi_reference_args args; + + dev_dbg(&adev->dev, "GPIO: looking up %s\n", propname); + + memset(&args, 0, sizeof(args)); + ret = acpi_dev_get_property_reference(adev, propname, NULL, + index, &args); + if (ret) + return ERR_PTR(ret); + + /* + * The property was found and resolved so need to + * lookup the GPIO based on returned args instead. + */ + adev = args.adev; + if (args.nargs >= 2) { + lookup.index = args.args[0]; + lookup.pin_index = args.args[1]; + /* + * 3rd argument, if present is used to + * specify active_low. + */ + if (args.nargs >= 3) + active_low = !!args.args[2]; + } + + dev_dbg(&adev->dev, "GPIO: _DSD returned %s %zd %llu %llu %llu\n", + dev_name(&adev->dev), args.nargs, + args.args[0], args.args[1], args.args[2]); + } else { + dev_dbg(&adev->dev, "GPIO: looking up %d in _CRS\n", index); + } + INIT_LIST_HEAD(&resource_list); ret = acpi_dev_get_resources(adev, &resource_list, acpi_find_gpio, &lookup); @@ -359,8 +406,11 @@ struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index, acpi_dev_free_resource_list(&resource_list); - if (lookup.desc && info) + if (lookup.desc && info) { *info = lookup.info; + if (active_low) + info->active_low = active_low; + } return lookup.desc ? lookup.desc : ERR_PTR(-ENOENT); } diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index e8e98ca25ec7..2bca0495cb46 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1505,14 +1505,36 @@ static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id, unsigned int idx, enum gpio_lookup_flags *flags) { + static const char * const suffixes[] = { "gpios", "gpio" }; + struct acpi_device *adev = ACPI_COMPANION(dev); struct acpi_gpio_info info; struct gpio_desc *desc; + char propname[32]; + int i; - desc = acpi_get_gpiod_by_index(dev, idx, &info); - if (IS_ERR(desc)) - return desc; + /* Try first from _DSD */ + for (i = 0; i < ARRAY_SIZE(suffixes); i++) { + if (con_id && strcmp(con_id, "gpios")) { + snprintf(propname, sizeof(propname), "%s-%s", + con_id, suffixes[i]); + } else { + snprintf(propname, sizeof(propname), "%s", + suffixes[i]); + } + + desc = acpi_get_gpiod_by_index(adev, propname, idx, &info); + if (!IS_ERR(desc) || (PTR_ERR(desc) == -EPROBE_DEFER)) + break; + } + + /* Then from plain _CRS GPIOs */ + if (IS_ERR(desc)) { + desc = acpi_get_gpiod_by_index(adev, NULL, idx, &info); + if (IS_ERR(desc)) + return desc; + } - if (info.gpioint && info.active_low) + if (info.active_low) *flags |= GPIO_ACTIVE_LOW; return desc; diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index 9db2b6a71c5d..e3a52113a541 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -34,7 +34,8 @@ void acpi_gpiochip_remove(struct gpio_chip *chip); void acpi_gpiochip_request_interrupts(struct gpio_chip *chip); void acpi_gpiochip_free_interrupts(struct gpio_chip *chip); -struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index, +struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev, + const char *propname, int index, struct acpi_gpio_info *info); #else static inline void acpi_gpiochip_add(struct gpio_chip *chip) { } @@ -47,8 +48,8 @@ static inline void acpi_gpiochip_free_interrupts(struct gpio_chip *chip) { } static inline struct gpio_desc * -acpi_get_gpiod_by_index(struct device *dev, int index, - struct acpi_gpio_info *info) +acpi_get_gpiod_by_index(struct acpi_device *adev, const char *propname, + int index, struct acpi_gpio_info *info) { return ERR_PTR(-ENOSYS); } -- cgit v1.2.3-59-g8ed1b From e36d453e98c57dda0f8ba68585676ac4ba36631e Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 3 Nov 2014 23:39:57 +0100 Subject: ACPI / GPIO: Document ACPI GPIO mappings API Document the previously introduced method that can be used by device drivers to provide the GPIO subsystem with mappings between GPIO names (connection IDs) and GpioIo()/GpioInt() resources in _CRS. Signed-off-by: Rafael J. Wysocki Reviewed-by: Mika Westerberg --- Documentation/acpi/gpio-properties.txt | 44 ++++++++++++++++++++++++++++++++++ Documentation/gpio/consumer.txt | 18 ++++++++++++++ 2 files changed, 62 insertions(+) (limited to 'Documentation') diff --git a/Documentation/acpi/gpio-properties.txt b/Documentation/acpi/gpio-properties.txt index 3e45b8b7e4f2..ae36fcf86dc7 100644 --- a/Documentation/acpi/gpio-properties.txt +++ b/Documentation/acpi/gpio-properties.txt @@ -50,3 +50,47 @@ it to 1 marks the GPIO as active low. In our Bluetooth example the "reset-gpio" refers to the second GpioIo() resource, second pin in that resource with the GPIO number of 31. + +ACPI GPIO Mappings Provided by Drivers +-------------------------------------- + +There are systems in which the ACPI tables do not contain _DSD but provide _CRS +with GpioIo()/GpioInt() resources and device drivers still need to work with +them. + +In those cases ACPI device identification objects, _HID, _CID, _CLS, _SUB, _HRV, +available to the driver can be used to identify the device and that is supposed +to be sufficient to determine the meaning and purpose of all of the GPIO lines +listed by the GpioIo()/GpioInt() resources returned by _CRS. In other words, +the driver is supposed to know what to use the GpioIo()/GpioInt() resources for +once it has identified the device. Having done that, it can simply assign names +to the GPIO lines it is going to use and provide the GPIO subsystem with a +mapping between those names and the ACPI GPIO resources corresponding to them. + +To do that, the driver needs to define a mapping table as a NULL-terminated +array of struct acpi_gpio_mapping objects that each contain a name, a pointer +to an array of line data (struct acpi_gpio_params) objects and the size of that +array. Each struct acpi_gpio_params object consists of three fields, +crs_entry_index, line_index, active_low, representing the index of the target +GpioIo()/GpioInt() resource in _CRS starting from zero, the index of the target +line in that resource starting from zero, and the active-low flag for that line, +respectively, in analogy with the _DSD GPIO property format specified above. + +For the example Bluetooth device discussed previously the data structures in +question would look like this: + +static const struct acpi_gpio_params reset_gpio = { 1, 1, false }; +static const struct acpi_gpio_params shutdown_gpio = { 0, 0, false }; + +static const struct acpi_gpio_mapping bluetooth_acpi_gpios[] = { + { "reset-gpio", &reset_gpio, 1 }, + { "shutdown-gpio", &shutdown_gpio, 1 }, + { }, +}; + +Next, the mapping table needs to be passed as the second argument to +acpi_dev_add_driver_gpios() that will register it with the ACPI device object +pointed to by its first argument. That should be done in the driver's .probe() +routine. On removal, the driver should unregister its GPIO mapping table by +calling acpi_dev_remove_driver_gpios() on the ACPI device object where that +table was previously registered. diff --git a/Documentation/gpio/consumer.txt b/Documentation/gpio/consumer.txt index 6ce544191ca6..859918db36b8 100644 --- a/Documentation/gpio/consumer.txt +++ b/Documentation/gpio/consumer.txt @@ -219,6 +219,24 @@ part of the IRQ interface, e.g. IRQF_TRIGGER_FALLING, as are system wakeup capabilities. +GPIOs and ACPI +============== + +On ACPI systems, GPIOs are described by GpioIo()/GpioInt() resources listed by +the _CRS configuration objects of devices. Those resources do not provide +connection IDs (names) for GPIOs, so it is necessary to use an additional +mechanism for this purpose. + +Systems compliant with ACPI 5.1 or newer may provide a _DSD configuration object +which, among other things, may be used to provide connection IDs for specific +GPIOs described by the GpioIo()/GpioInt() resources in _CRS. If that is the +case, it will be handled by the GPIO subsystem automatically. However, if the +_DSD is not present, the mappings between GpioIo()/GpioInt() resources and GPIO +connection IDs need to be provided by device drivers. + +For details refer to Documentation/acpi/gpio-properties.txt + + Interacting With the Legacy GPIO Subsystem ========================================== Many kernel subsystems still handle GPIOs using the legacy integer-based -- cgit v1.2.3-59-g8ed1b From d5053a34a9cc797b9d5d77574354b5555848c43c Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Thu, 30 Oct 2014 22:47:03 -0700 Subject: f2fs: introduce -o fastboot for reducing booting time only If a system wants to reduce the booting time as a top priority, now we can use a mount option, -o fastboot. With this option, f2fs conducts a little bit slow write_checkpoint, but it can avoid the node page reads during the next mount time. Signed-off-by: Jaegeuk Kim --- Documentation/filesystems/f2fs.txt | 3 +++ fs/f2fs/f2fs.h | 1 + fs/f2fs/file.c | 2 ++ fs/f2fs/gc.c | 6 +++--- fs/f2fs/super.c | 13 ++++++++++--- 5 files changed, 19 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/f2fs.txt b/Documentation/filesystems/f2fs.txt index 4bb9f278c031..e0950c483c22 100644 --- a/Documentation/filesystems/f2fs.txt +++ b/Documentation/filesystems/f2fs.txt @@ -135,6 +135,9 @@ nobarrier This option can be used if underlying storage guarantees If this option is set, no cache_flush commands are issued but f2fs still guarantees the write ordering of all the data writes. +fastboot This option is used when a system wants to reduce mount + time as much as possible, even though normal performance + can be sacrificed. ================================================================================ DEBUGFS ENTRIES diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 5a9705842f10..d45f3f4d7f93 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -49,6 +49,7 @@ #define F2FS_MOUNT_INLINE_DENTRY 0x00000200 #define F2FS_MOUNT_FLUSH_MERGE 0x00000400 #define F2FS_MOUNT_NOBARRIER 0x00000800 +#define F2FS_MOUNT_FASTBOOT 0x00001000 #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/file.c b/fs/f2fs/file.c index 832bd91922b8..46311e7b388a 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -130,6 +130,8 @@ static inline bool need_do_checkpoint(struct inode *inode) need_cp = true; else if (F2FS_I(inode)->xattr_ver == cur_cp_version(F2FS_CKPT(sbi))) need_cp = true; + else if (test_opt(sbi, FASTBOOT)) + need_cp = true; return need_cp; } diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 7151d7de7d95..b197a2f2993a 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -695,9 +695,9 @@ int f2fs_gc(struct f2fs_sb_info *sbi) int gc_type = BG_GC; int nfree = 0; int ret = -1; - struct cp_control cpc = { - .reason = CP_SYNC, - }; + struct cp_control cpc; + + cpc.reason = test_opt(sbi, FASTBOOT) ? CP_UMOUNT : CP_SYNC; INIT_LIST_HEAD(&ilist); gc_more: diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 6c5fc7605109..512ffd8e1624 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -54,6 +54,7 @@ enum { Opt_inline_dentry, Opt_flush_merge, Opt_nobarrier, + Opt_fastboot, Opt_err, }; @@ -73,6 +74,7 @@ static match_table_t f2fs_tokens = { {Opt_inline_dentry, "inline_dentry"}, {Opt_flush_merge, "flush_merge"}, {Opt_nobarrier, "nobarrier"}, + {Opt_fastboot, "fastboot"}, {Opt_err, NULL}, }; @@ -351,6 +353,9 @@ static int parse_options(struct super_block *sb, char *options) case Opt_nobarrier: set_opt(sbi, NOBARRIER); break; + case Opt_fastboot: + set_opt(sbi, FASTBOOT); + break; default: f2fs_msg(sb, KERN_ERR, "Unrecognized mount option \"%s\" or missing value", @@ -479,9 +484,9 @@ int f2fs_sync_fs(struct super_block *sb, int sync) trace_f2fs_sync_fs(sb, sync); if (sync) { - struct cp_control cpc = { - .reason = CP_SYNC, - }; + struct cp_control cpc; + + cpc.reason = test_opt(sbi, FASTBOOT) ? CP_UMOUNT : CP_SYNC; mutex_lock(&sbi->gc_mutex); write_checkpoint(sbi, &cpc); mutex_unlock(&sbi->gc_mutex); @@ -574,6 +579,8 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) seq_puts(seq, ",flush_merge"); if (test_opt(sbi, NOBARRIER)) seq_puts(seq, ",nobarrier"); + if (test_opt(sbi, FASTBOOT)) + seq_puts(seq, ",fastboot"); seq_printf(seq, ",active_logs=%u", sbi->active_logs); return 0; -- cgit v1.2.3-59-g8ed1b From f861a9253e7f456d870f8dd46bdde2ac02149bc6 Mon Sep 17 00:00:00 2001 From: Gerhard Sittig Date: Tue, 5 Aug 2014 10:37:25 +0200 Subject: devicetree: bindings: improve description for GPIO assisted NAND flash Expand the description of the 'gpios' property in the GPIO assisted NAND flash binding, to explicitly list the required GPIO pin references and their order. Update the example section to individually bracket the GPIO references, and capitalize the signal names for improved readability. Signed-off-by: Gerhard Sittig Signed-off-by: Brian Norris --- .../devicetree/bindings/mtd/gpio-control-nand.txt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mtd/gpio-control-nand.txt b/Documentation/devicetree/bindings/mtd/gpio-control-nand.txt index 36ef07d3c90f..af8915b41ccf 100644 --- a/Documentation/devicetree/bindings/mtd/gpio-control-nand.txt +++ b/Documentation/devicetree/bindings/mtd/gpio-control-nand.txt @@ -11,8 +11,8 @@ Required properties: are made in native endianness. - #address-cells, #size-cells : Must be present if the device has sub-nodes representing partitions. -- gpios : specifies the gpio pins to control the NAND device. nwp is an - optional gpio and may be set to 0 if not present. +- gpios : Specifies the GPIO pins to control the NAND device. The order of + GPIO references is: RDY, nCE, ALE, CLE, and an optional nWP. Optional properties: - bank-width : Width (in bytes) of the device. If not present, the width @@ -35,11 +35,11 @@ gpio-nand@1,0 { reg = <1 0x0000 0x2>; #address-cells = <1>; #size-cells = <1>; - gpios = <&banka 1 0 /* rdy */ - &banka 2 0 /* nce */ - &banka 3 0 /* ale */ - &banka 4 0 /* cle */ - 0 /* nwp */>; + gpios = <&banka 1 0>, /* RDY */ + <&banka 2 0>, /* nCE */ + <&banka 3 0>, /* ALE */ + <&banka 4 0>, /* CLE */ + <0>; /* nWP */ partition@0 { ... -- cgit v1.2.3-59-g8ed1b From b626c8f0d909be88534ab3d25dd9fbffcc884b47 Mon Sep 17 00:00:00 2001 From: Naveen Krishna Chatradhi Date: Tue, 16 Sep 2014 09:58:00 +0100 Subject: Documentation: dt-bindings: update exynos-adc.txt with syscon handle This patch updates the DT bindings for ADC in exynos-adc.txt with the syscon phandle to the ADC nodes. Signed-off-by: Naveen Krishna Chatradhi To: devicetree@vger.kernel.org Acked-by: Kukjin Kim Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/arm/samsung/exynos-adc.txt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/samsung/exynos-adc.txt b/Documentation/devicetree/bindings/arm/samsung/exynos-adc.txt index 709efaa30841..c36821095393 100644 --- a/Documentation/devicetree/bindings/arm/samsung/exynos-adc.txt +++ b/Documentation/devicetree/bindings/arm/samsung/exynos-adc.txt @@ -43,13 +43,16 @@ Required properties: compatible ADC block) - vdd-supply VDD input supply. +- samsung,syscon-phandle Contains the PMU system controller node + (To access the ADC_PHY register on Exynos5250/5420/5800/3250) + Note: child nodes can be added for auto probing from device tree. Example: adding device info in dtsi file adc: adc@12D10000 { compatible = "samsung,exynos-adc-v1"; - reg = <0x12D10000 0x100>, <0x10040718 0x4>; + reg = <0x12D10000 0x100>; interrupts = <0 106 0>; #io-channel-cells = <1>; io-channel-ranges; @@ -58,13 +61,14 @@ adc: adc@12D10000 { clock-names = "adc"; vdd-supply = <&buck5_reg>; + samsung,syscon-phandle = <&pmu_system_controller>; }; Example: adding device info in dtsi file for Exynos3250 with additional sclk adc: adc@126C0000 { compatible = "samsung,exynos3250-adc", "samsung,exynos-adc-v2; - reg = <0x126C0000 0x100>, <0x10020718 0x4>; + reg = <0x126C0000 0x100>; interrupts = <0 137 0>; #io-channel-cells = <1>; io-channel-ranges; @@ -73,6 +77,7 @@ adc: adc@126C0000 { clock-names = "adc", "sclk"; vdd-supply = <&buck5_reg>; + samsung,syscon-phandle = <&pmu_system_controller>; }; Example: Adding child nodes in dts file -- cgit v1.2.3-59-g8ed1b From c1b501564c98a94b48f4ed936737403108dc7300 Mon Sep 17 00:00:00 2001 From: Abhilash Kesavan Date: Sat, 1 Nov 2014 09:30:43 +0530 Subject: iio: adc: exynos_adc: Add support for exynos7 The ADC on exynos7 is quite similar to ADCv2. The differences are as follows: - exynos7-adc has 8 input channels (as against 10 in ADCv2). - exynos7 does not include an ADC PHY control register. - Some ADC_CON2 register bits being used in ADCv2 are listed as reserved in exynos7-adc. This results in a different init_hw function for exynos7. Signed-off-by: Abhilash Kesavan Reviewed-by: Chanwoo Choi Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/arm/samsung/exynos-adc.txt | 2 ++ drivers/iio/adc/exynos_adc.c | 32 ++++++++++++++++++++++ 2 files changed, 34 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/samsung/exynos-adc.txt b/Documentation/devicetree/bindings/arm/samsung/exynos-adc.txt index c36821095393..f46ca9a316a2 100644 --- a/Documentation/devicetree/bindings/arm/samsung/exynos-adc.txt +++ b/Documentation/devicetree/bindings/arm/samsung/exynos-adc.txt @@ -16,6 +16,8 @@ Required properties: future controllers. Must be "samsung,exynos3250-adc" for controllers compatible with ADC of Exynos3250. + Must be "samsung,exynos7-adc" for + the ADC in Exynos7 and compatibles Must be "samsung,s3c2410-adc" for the ADC in s3c2410 and compatibles Must be "samsung,s3c2416-adc" for diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c index fe0317745436..3a2dbb3b4926 100644 --- a/drivers/iio/adc/exynos_adc.c +++ b/drivers/iio/adc/exynos_adc.c @@ -390,6 +390,35 @@ static const struct exynos_adc_data exynos3250_adc_data = { .start_conv = exynos_adc_v2_start_conv, }; +static void exynos_adc_exynos7_init_hw(struct exynos_adc *info) +{ + u32 con1, con2; + + if (info->data->needs_adc_phy) + regmap_write(info->pmu_map, info->data->phy_offset, 1); + + con1 = ADC_V2_CON1_SOFT_RESET; + writel(con1, ADC_V2_CON1(info->regs)); + + con2 = readl(ADC_V2_CON2(info->regs)); + con2 &= ~ADC_V2_CON2_C_TIME(7); + con2 |= ADC_V2_CON2_C_TIME(0); + writel(con2, ADC_V2_CON2(info->regs)); + + /* Enable interrupts */ + writel(1, ADC_V2_INT_EN(info->regs)); +} + +static const struct exynos_adc_data exynos7_adc_data = { + .num_channels = MAX_ADC_V1_CHANNELS, + .mask = ADC_DATX_MASK, /* 12 bit ADC resolution */ + + .init_hw = exynos_adc_exynos7_init_hw, + .exit_hw = exynos_adc_v2_exit_hw, + .clear_irq = exynos_adc_v2_clear_irq, + .start_conv = exynos_adc_v2_start_conv, +}; + static const struct of_device_id exynos_adc_match[] = { { .compatible = "samsung,s3c2410-adc", @@ -415,6 +444,9 @@ static const struct of_device_id exynos_adc_match[] = { }, { .compatible = "samsung,exynos3250-adc", .data = &exynos3250_adc_data, + }, { + .compatible = "samsung,exynos7-adc", + .data = &exynos7_adc_data, }, {}, }; -- cgit v1.2.3-59-g8ed1b From 4e4cd14e7cbead5ca20465f4a7ce973d42434a2f Mon Sep 17 00:00:00 2001 From: Darshana Padmadas Date: Wed, 5 Nov 2014 21:48:11 +0530 Subject: iio: Add ABI documentation for scaled voltage This patch adds an entry in ABI documentation for in_voltage-voltage_scale. It has at least one user driver, adis16220, in accel driver. Signed-off-by: Darshana Padmadas 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 ea7e7abbbdf4..117521dbf2b3 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -259,6 +259,7 @@ Description: What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_scale What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_supply_scale What: /sys/bus/iio/devices/iio:deviceX/in_voltage_scale +What: /sys/bus/iio/devices/iio:deviceX/in_voltage-voltage_scale What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_scale What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_scale What: /sys/bus/iio/devices/iio:deviceX/in_accel_scale -- cgit v1.2.3-59-g8ed1b From a3816ab0e8fe542a89a53b82506a8ddac063fbe3 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 29 Sep 2014 16:08:25 -0700 Subject: fs: Convert show_fdinfo functions to void seq_printf functions shouldn't really check the return value. Checking seq_has_overflowed() occasionally is used instead. Update vfs documentation. Link: http://lkml.kernel.org/p/e37e6e7b76acbdcc3bb4ab2a57c8f8ca1ae11b9a.1412031505.git.joe@perches.com Cc: David S. Miller Cc: Al Viro Signed-off-by: Joe Perches [ did a few clean ups ] Signed-off-by: Steven Rostedt --- Documentation/filesystems/vfs.txt | 2 +- drivers/net/tun.c | 4 +- fs/eventfd.c | 9 ++--- fs/eventpoll.c | 13 +++---- fs/notify/fdinfo.c | 78 ++++++++++++++++----------------------- fs/notify/fdinfo.h | 4 +- fs/proc/fd.c | 3 +- fs/signalfd.c | 4 +- fs/timerfd.c | 27 +++++++------- include/linux/fs.h | 2 +- 10 files changed, 63 insertions(+), 83 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt index fceff7c00a3c..af1dbc1823bb 100644 --- a/Documentation/filesystems/vfs.txt +++ b/Documentation/filesystems/vfs.txt @@ -828,7 +828,7 @@ struct file_operations { ssize_t (*splice_read)(struct file *, struct pipe_inode_info *, size_t, unsigned int); int (*setlease)(struct file *, long arg, struct file_lock **, void **); long (*fallocate)(struct file *, int mode, loff_t offset, loff_t len); - int (*show_fdinfo)(struct seq_file *m, struct file *f); + void (*show_fdinfo)(struct seq_file *m, struct file *f); }; Again, all methods are called without any locks being held, unless diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 186ce541c657..a3420e091689 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -2209,7 +2209,7 @@ static int tun_chr_close(struct inode *inode, struct file *file) } #ifdef CONFIG_PROC_FS -static int tun_chr_show_fdinfo(struct seq_file *m, struct file *f) +static void tun_chr_show_fdinfo(struct seq_file *m, struct file *f) { struct tun_struct *tun; struct ifreq ifr; @@ -2225,7 +2225,7 @@ static int tun_chr_show_fdinfo(struct seq_file *m, struct file *f) if (tun) tun_put(tun); - return seq_printf(m, "iff:\t%s\n", ifr.ifr_name); + seq_printf(m, "iff:\t%s\n", ifr.ifr_name); } #endif diff --git a/fs/eventfd.c b/fs/eventfd.c index d6a88e7812f3..4b0a226024fa 100644 --- a/fs/eventfd.c +++ b/fs/eventfd.c @@ -287,17 +287,14 @@ static ssize_t eventfd_write(struct file *file, const char __user *buf, size_t c } #ifdef CONFIG_PROC_FS -static int eventfd_show_fdinfo(struct seq_file *m, struct file *f) +static void eventfd_show_fdinfo(struct seq_file *m, struct file *f) { struct eventfd_ctx *ctx = f->private_data; - int ret; spin_lock_irq(&ctx->wqh.lock); - ret = seq_printf(m, "eventfd-count: %16llx\n", - (unsigned long long)ctx->count); + seq_printf(m, "eventfd-count: %16llx\n", + (unsigned long long)ctx->count); spin_unlock_irq(&ctx->wqh.lock); - - return ret; } #endif diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 7bcfff900f05..d77f94491352 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -870,25 +870,22 @@ static unsigned int ep_eventpoll_poll(struct file *file, poll_table *wait) } #ifdef CONFIG_PROC_FS -static int ep_show_fdinfo(struct seq_file *m, struct file *f) +static void ep_show_fdinfo(struct seq_file *m, struct file *f) { struct eventpoll *ep = f->private_data; struct rb_node *rbp; - int ret = 0; mutex_lock(&ep->mtx); for (rbp = rb_first(&ep->rbr); rbp; rbp = rb_next(rbp)) { struct epitem *epi = rb_entry(rbp, struct epitem, rbn); - ret = seq_printf(m, "tfd: %8d events: %8x data: %16llx\n", - epi->ffd.fd, epi->event.events, - (long long)epi->event.data); - if (ret) + seq_printf(m, "tfd: %8d events: %8x data: %16llx\n", + epi->ffd.fd, epi->event.events, + (long long)epi->event.data); + if (seq_has_overflowed(m)) break; } mutex_unlock(&ep->mtx); - - return ret; } #endif diff --git a/fs/notify/fdinfo.c b/fs/notify/fdinfo.c index 9d7e2b9659cb..6ffd220eb14d 100644 --- a/fs/notify/fdinfo.c +++ b/fs/notify/fdinfo.c @@ -20,25 +20,24 @@ #if defined(CONFIG_INOTIFY_USER) || defined(CONFIG_FANOTIFY) -static int show_fdinfo(struct seq_file *m, struct file *f, - int (*show)(struct seq_file *m, struct fsnotify_mark *mark)) +static void show_fdinfo(struct seq_file *m, struct file *f, + void (*show)(struct seq_file *m, + struct fsnotify_mark *mark)) { struct fsnotify_group *group = f->private_data; struct fsnotify_mark *mark; - int ret = 0; mutex_lock(&group->mark_mutex); list_for_each_entry(mark, &group->marks_list, g_list) { - ret = show(m, mark); - if (ret) + show(m, mark); + if (seq_has_overflowed(m)) break; } mutex_unlock(&group->mark_mutex); - return ret; } #if defined(CONFIG_EXPORTFS) -static int show_mark_fhandle(struct seq_file *m, struct inode *inode) +static void show_mark_fhandle(struct seq_file *m, struct inode *inode) { struct { struct file_handle handle; @@ -52,71 +51,62 @@ static int show_mark_fhandle(struct seq_file *m, struct inode *inode) ret = exportfs_encode_inode_fh(inode, (struct fid *)f.handle.f_handle, &size, 0); if ((ret == FILEID_INVALID) || (ret < 0)) { WARN_ONCE(1, "Can't encode file handler for inotify: %d\n", ret); - return 0; + return; } f.handle.handle_type = ret; f.handle.handle_bytes = size * sizeof(u32); - ret = seq_printf(m, "fhandle-bytes:%x fhandle-type:%x f_handle:", - f.handle.handle_bytes, f.handle.handle_type); + seq_printf(m, "fhandle-bytes:%x fhandle-type:%x f_handle:", + f.handle.handle_bytes, f.handle.handle_type); for (i = 0; i < f.handle.handle_bytes; i++) - ret |= seq_printf(m, "%02x", (int)f.handle.f_handle[i]); - - return ret; + seq_printf(m, "%02x", (int)f.handle.f_handle[i]); } #else -static int show_mark_fhandle(struct seq_file *m, struct inode *inode) +static void show_mark_fhandle(struct seq_file *m, struct inode *inode) { - return 0; } #endif #ifdef CONFIG_INOTIFY_USER -static int inotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark) +static void inotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark) { struct inotify_inode_mark *inode_mark; struct inode *inode; - int ret = 0; if (!(mark->flags & (FSNOTIFY_MARK_FLAG_ALIVE | FSNOTIFY_MARK_FLAG_INODE))) - return 0; + return; inode_mark = container_of(mark, struct inotify_inode_mark, fsn_mark); inode = igrab(mark->i.inode); if (inode) { - ret = seq_printf(m, "inotify wd:%x ino:%lx sdev:%x " - "mask:%x ignored_mask:%x ", - inode_mark->wd, inode->i_ino, - inode->i_sb->s_dev, - mark->mask, mark->ignored_mask); - ret |= show_mark_fhandle(m, inode); - ret |= seq_putc(m, '\n'); + seq_printf(m, "inotify wd:%x ino:%lx sdev:%x mask:%x ignored_mask:%x ", + inode_mark->wd, inode->i_ino, inode->i_sb->s_dev, + mark->mask, mark->ignored_mask); + show_mark_fhandle(m, inode); + seq_putc(m, '\n'); iput(inode); } - - return ret; } -int inotify_show_fdinfo(struct seq_file *m, struct file *f) +void inotify_show_fdinfo(struct seq_file *m, struct file *f) { - return show_fdinfo(m, f, inotify_fdinfo); + show_fdinfo(m, f, inotify_fdinfo); } #endif /* CONFIG_INOTIFY_USER */ #ifdef CONFIG_FANOTIFY -static int fanotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark) +static void fanotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark) { unsigned int mflags = 0; struct inode *inode; - int ret = 0; if (!(mark->flags & FSNOTIFY_MARK_FLAG_ALIVE)) - return 0; + return; if (mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY) mflags |= FAN_MARK_IGNORED_SURV_MODIFY; @@ -124,26 +114,22 @@ static int fanotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark) if (mark->flags & FSNOTIFY_MARK_FLAG_INODE) { inode = igrab(mark->i.inode); if (!inode) - goto out; - ret = seq_printf(m, "fanotify ino:%lx sdev:%x " - "mflags:%x mask:%x ignored_mask:%x ", - inode->i_ino, inode->i_sb->s_dev, - mflags, mark->mask, mark->ignored_mask); - ret |= show_mark_fhandle(m, inode); - ret |= seq_putc(m, '\n'); + return; + seq_printf(m, "fanotify ino:%lx sdev:%x mflags:%x mask:%x ignored_mask:%x ", + inode->i_ino, inode->i_sb->s_dev, + mflags, mark->mask, mark->ignored_mask); + show_mark_fhandle(m, inode); + seq_putc(m, '\n'); iput(inode); } else if (mark->flags & FSNOTIFY_MARK_FLAG_VFSMOUNT) { struct mount *mnt = real_mount(mark->m.mnt); - ret = seq_printf(m, "fanotify mnt_id:%x mflags:%x mask:%x " - "ignored_mask:%x\n", mnt->mnt_id, mflags, - mark->mask, mark->ignored_mask); + seq_printf(m, "fanotify mnt_id:%x mflags:%x mask:%x ignored_mask:%x\n", + mnt->mnt_id, mflags, mark->mask, mark->ignored_mask); } -out: - return ret; } -int fanotify_show_fdinfo(struct seq_file *m, struct file *f) +void fanotify_show_fdinfo(struct seq_file *m, struct file *f) { struct fsnotify_group *group = f->private_data; unsigned int flags = 0; @@ -169,7 +155,7 @@ int fanotify_show_fdinfo(struct seq_file *m, struct file *f) seq_printf(m, "fanotify flags:%x event-flags:%x\n", flags, group->fanotify_data.f_flags); - return show_fdinfo(m, f, fanotify_fdinfo); + show_fdinfo(m, f, fanotify_fdinfo); } #endif /* CONFIG_FANOTIFY */ diff --git a/fs/notify/fdinfo.h b/fs/notify/fdinfo.h index 556afda990e9..9664c4904d6b 100644 --- a/fs/notify/fdinfo.h +++ b/fs/notify/fdinfo.h @@ -10,11 +10,11 @@ struct file; #ifdef CONFIG_PROC_FS #ifdef CONFIG_INOTIFY_USER -extern int inotify_show_fdinfo(struct seq_file *m, struct file *f); +void inotify_show_fdinfo(struct seq_file *m, struct file *f); #endif #ifdef CONFIG_FANOTIFY -extern int fanotify_show_fdinfo(struct seq_file *m, struct file *f); +void fanotify_show_fdinfo(struct seq_file *m, struct file *f); #endif #else /* CONFIG_PROC_FS */ diff --git a/fs/proc/fd.c b/fs/proc/fd.c index e11d7c590bb0..8e5ad83b629a 100644 --- a/fs/proc/fd.c +++ b/fs/proc/fd.c @@ -53,7 +53,8 @@ static int seq_show(struct seq_file *m, void *v) (long long)file->f_pos, f_flags, real_mount(file->f_path.mnt)->mnt_id); if (file->f_op->show_fdinfo) - ret = file->f_op->show_fdinfo(m, file); + file->f_op->show_fdinfo(m, file); + ret = seq_has_overflowed(m); fput(file); } diff --git a/fs/signalfd.c b/fs/signalfd.c index 424b7b65321f..7e412ad74836 100644 --- a/fs/signalfd.c +++ b/fs/signalfd.c @@ -230,7 +230,7 @@ static ssize_t signalfd_read(struct file *file, char __user *buf, size_t count, } #ifdef CONFIG_PROC_FS -static int signalfd_show_fdinfo(struct seq_file *m, struct file *f) +static void signalfd_show_fdinfo(struct seq_file *m, struct file *f) { struct signalfd_ctx *ctx = f->private_data; sigset_t sigmask; @@ -238,8 +238,6 @@ static int signalfd_show_fdinfo(struct seq_file *m, struct file *f) sigmask = ctx->sigmask; signotset(&sigmask); render_sigset_t(m, "sigmask:\t", &sigmask); - - return 0; } #endif diff --git a/fs/timerfd.c b/fs/timerfd.c index b46ffa94372a..b94fa6c3c6eb 100644 --- a/fs/timerfd.c +++ b/fs/timerfd.c @@ -288,7 +288,7 @@ static ssize_t timerfd_read(struct file *file, char __user *buf, size_t count, } #ifdef CONFIG_PROC_FS -static int timerfd_show(struct seq_file *m, struct file *file) +static void timerfd_show(struct seq_file *m, struct file *file) { struct timerfd_ctx *ctx = file->private_data; struct itimerspec t; @@ -298,18 +298,19 @@ static int timerfd_show(struct seq_file *m, struct file *file) t.it_interval = ktime_to_timespec(ctx->tintv); spin_unlock_irq(&ctx->wqh.lock); - return seq_printf(m, - "clockid: %d\n" - "ticks: %llu\n" - "settime flags: 0%o\n" - "it_value: (%llu, %llu)\n" - "it_interval: (%llu, %llu)\n", - ctx->clockid, (unsigned long long)ctx->ticks, - ctx->settime_flags, - (unsigned long long)t.it_value.tv_sec, - (unsigned long long)t.it_value.tv_nsec, - (unsigned long long)t.it_interval.tv_sec, - (unsigned long long)t.it_interval.tv_nsec); + seq_printf(m, + "clockid: %d\n" + "ticks: %llu\n" + "settime flags: 0%o\n" + "it_value: (%llu, %llu)\n" + "it_interval: (%llu, %llu)\n", + ctx->clockid, + (unsigned long long)ctx->ticks, + ctx->settime_flags, + (unsigned long long)t.it_value.tv_sec, + (unsigned long long)t.it_value.tv_nsec, + (unsigned long long)t.it_interval.tv_sec, + (unsigned long long)t.it_interval.tv_nsec); } #else #define timerfd_show NULL diff --git a/include/linux/fs.h b/include/linux/fs.h index a957d4366c24..01dd9052a142 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1491,7 +1491,7 @@ struct file_operations { int (*setlease)(struct file *, long, struct file_lock **, void **); long (*fallocate)(struct file *file, int mode, loff_t offset, loff_t len); - int (*show_fdinfo)(struct seq_file *m, struct file *f); + void (*show_fdinfo)(struct seq_file *m, struct file *f); }; struct inode_operations { -- cgit v1.2.3-59-g8ed1b From 9761536e1d9e9e1f325fb04d4ad46b15a39eb94a Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 29 Sep 2014 16:08:26 -0700 Subject: debugfs: Have debugfs_print_regs32() return void The seq_printf() will soon just return void, and seq_has_overflowed() should be used instead to see if the seq can no longer accept input. As the return value of debugfs_print_regs32() has no users and the seq_file descriptor should be checked with seq_has_overflowed() instead of return values of functions, it is better to just have debugfs_print_regs32() also return void. Link: http://lkml.kernel.org/p/2634b19eb1c04a9d31148c1fe6f1f3819be95349.1412031505.git.joe@perches.com Acked-by: Greg Kroah-Hartman Signed-off-by: Joe Perches [ original change only updated seq_printf() return, added return of void to debugfs_print_regs32() as well ] Signed-off-by: Steven Rostedt --- Documentation/filesystems/debugfs.txt | 2 +- fs/debugfs/file.c | 15 ++++++++------- include/linux/debugfs.h | 7 +++---- 3 files changed, 12 insertions(+), 12 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/debugfs.txt b/Documentation/filesystems/debugfs.txt index 3a863f692728..88ab81c79109 100644 --- a/Documentation/filesystems/debugfs.txt +++ b/Documentation/filesystems/debugfs.txt @@ -140,7 +140,7 @@ file. struct dentry *parent, struct debugfs_regset32 *regset); - int debugfs_print_regs32(struct seq_file *s, struct debugfs_reg32 *regs, + void debugfs_print_regs32(struct seq_file *s, struct debugfs_reg32 *regs, int nregs, void __iomem *base, char *prefix); The "base" argument may be 0, but you may want to build the reg32 array diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index 76c08c2beb2f..8e0f2f410189 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -692,18 +692,19 @@ EXPORT_SYMBOL_GPL(debugfs_create_u32_array); * because some peripherals have several blocks of identical registers, * for example configuration of dma channels */ -int debugfs_print_regs32(struct seq_file *s, const struct debugfs_reg32 *regs, - int nregs, void __iomem *base, char *prefix) +void debugfs_print_regs32(struct seq_file *s, const struct debugfs_reg32 *regs, + int nregs, void __iomem *base, char *prefix) { - int i, ret = 0; + int i; for (i = 0; i < nregs; i++, regs++) { if (prefix) - ret += seq_printf(s, "%s", prefix); - ret += seq_printf(s, "%s = 0x%08x\n", regs->name, - readl(base + regs->offset)); + seq_printf(s, "%s", prefix); + seq_printf(s, "%s = 0x%08x\n", regs->name, + readl(base + regs->offset)); + if (seq_has_overflowed(s)) + break; } - return ret; } EXPORT_SYMBOL_GPL(debugfs_print_regs32); diff --git a/include/linux/debugfs.h b/include/linux/debugfs.h index 4d0b4d1aa132..d84f8c254a87 100644 --- a/include/linux/debugfs.h +++ b/include/linux/debugfs.h @@ -92,8 +92,8 @@ struct dentry *debugfs_create_regset32(const char *name, umode_t mode, struct dentry *parent, struct debugfs_regset32 *regset); -int debugfs_print_regs32(struct seq_file *s, const struct debugfs_reg32 *regs, - int nregs, void __iomem *base, char *prefix); +void debugfs_print_regs32(struct seq_file *s, const struct debugfs_reg32 *regs, + int nregs, void __iomem *base, char *prefix); struct dentry *debugfs_create_u32_array(const char *name, umode_t mode, struct dentry *parent, @@ -233,10 +233,9 @@ static inline struct dentry *debugfs_create_regset32(const char *name, return ERR_PTR(-ENODEV); } -static inline int debugfs_print_regs32(struct seq_file *s, const struct debugfs_reg32 *regs, +static inline void debugfs_print_regs32(struct seq_file *s, const struct debugfs_reg32 *regs, int nregs, void __iomem *base, char *prefix) { - return 0; } static inline bool debugfs_initialized(void) -- cgit v1.2.3-59-g8ed1b From 6f1de344557315a8e5de0d15a28276198ca7fdac Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 16 Oct 2014 13:33:31 +0200 Subject: usb: gadget: f_midi: add configfs support Make the midi function available for gadgets composed with configfs. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Felipe Balbi --- Documentation/ABI/testing/configfs-usb-gadget-midi | 12 ++ drivers/usb/gadget/Kconfig | 14 ++ drivers/usb/gadget/function/f_midi.c | 161 ++++++++++++++++++++- drivers/usb/gadget/function/u_midi.h | 8 + 4 files changed, 193 insertions(+), 2 deletions(-) create mode 100644 Documentation/ABI/testing/configfs-usb-gadget-midi (limited to 'Documentation') diff --git a/Documentation/ABI/testing/configfs-usb-gadget-midi b/Documentation/ABI/testing/configfs-usb-gadget-midi new file mode 100644 index 000000000000..6b341df7249c --- /dev/null +++ b/Documentation/ABI/testing/configfs-usb-gadget-midi @@ -0,0 +1,12 @@ +What: /config/usb-gadget/gadget/functions/midi.name +Date: Nov 2014 +KernelVersion: 3.19 +Description: + The attributes: + + index - index value for the USB MIDI adapter + id - ID string for the USB MIDI adapter + buflen - MIDI buffer length + qlen - USB read request queue length + in_ports - number of MIDI input ports + out_ports - number of MIDI output ports diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index b51307805151..501c2a38d071 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -396,6 +396,20 @@ config USB_CONFIGFS_F_UAC2 received from the USB Host and choose to provide whatever it wants as audio data to the USB Host. +config USB_CONFIGFS_F_MIDI + boolean "MIDI function" + depends on USB_CONFIGFS + depends on SND + select USB_LIBCOMPOSITE + select SND_RAWMIDI + select USB_F_MIDI + help + The MIDI Function acts as a USB Audio device, with one MIDI + input and one MIDI output. These MIDI jacks appear as + a sound "card" in the ALSA sound system. Other MIDI + connections can then be made on the gadget system, using + ALSA's aconnect utility etc. + source "drivers/usb/gadget/legacy/Kconfig" endchoice diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index ec2a9cee4589..1f94dad57307 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -896,12 +896,145 @@ fail_register: return status; } +static inline struct f_midi_opts *to_f_midi_opts(struct config_item *item) +{ + return container_of(to_config_group(item), struct f_midi_opts, + func_inst.group); +} + +CONFIGFS_ATTR_STRUCT(f_midi_opts); +CONFIGFS_ATTR_OPS(f_midi_opts); + +static void midi_attr_release(struct config_item *item) +{ + struct f_midi_opts *opts = to_f_midi_opts(item); + + usb_put_function_instance(&opts->func_inst); +} + +static struct configfs_item_operations midi_item_ops = { + .release = midi_attr_release, + .show_attribute = f_midi_opts_attr_show, + .store_attribute = f_midi_opts_attr_store, +}; + +#define F_MIDI_OPT(name, test_limit, limit) \ +static ssize_t f_midi_opts_##name##_show(struct f_midi_opts *opts, char *page) \ +{ \ + int result; \ + \ + mutex_lock(&opts->lock); \ + result = sprintf(page, "%d\n", opts->name); \ + mutex_unlock(&opts->lock); \ + \ + return result; \ +} \ + \ +static ssize_t f_midi_opts_##name##_store(struct f_midi_opts *opts, \ + const char *page, size_t len) \ +{ \ + int ret; \ + u32 num; \ + \ + mutex_lock(&opts->lock); \ + if (opts->refcnt) { \ + ret = -EBUSY; \ + goto end; \ + } \ + \ + ret = kstrtou32(page, 0, &num); \ + if (ret) \ + goto end; \ + \ + if (test_limit && num > limit) { \ + ret = -EINVAL; \ + goto end; \ + } \ + opts->name = num; \ + ret = len; \ + \ +end: \ + mutex_unlock(&opts->lock); \ + return ret; \ +} \ + \ +static struct f_midi_opts_attribute f_midi_opts_##name = \ + __CONFIGFS_ATTR(name, S_IRUGO | S_IWUSR, f_midi_opts_##name##_show, \ + f_midi_opts_##name##_store) + +F_MIDI_OPT(index, true, SNDRV_CARDS); +F_MIDI_OPT(buflen, false, 0); +F_MIDI_OPT(qlen, false, 0); +F_MIDI_OPT(in_ports, true, MAX_PORTS); +F_MIDI_OPT(out_ports, true, MAX_PORTS); + +static ssize_t f_midi_opts_id_show(struct f_midi_opts *opts, char *page) +{ + int result; + + mutex_lock(&opts->lock); + result = strlcpy(page, opts->id, PAGE_SIZE); + mutex_unlock(&opts->lock); + + return result; +} + +static ssize_t f_midi_opts_id_store(struct f_midi_opts *opts, + const char *page, size_t len) +{ + int ret; + char *c; + + mutex_lock(&opts->lock); + if (opts->refcnt) { + ret = -EBUSY; + goto end; + } + + c = kstrndup(page, len, GFP_KERNEL); + if (!c) { + ret = -ENOMEM; + goto end; + } + if (opts->id_allocated) + kfree(opts->id); + opts->id = c; + opts->id_allocated = true; + ret = len; +end: + mutex_unlock(&opts->lock); + return ret; +} + +static struct f_midi_opts_attribute f_midi_opts_id = + __CONFIGFS_ATTR(id, S_IRUGO | S_IWUSR, f_midi_opts_id_show, + f_midi_opts_id_store); + +static struct configfs_attribute *midi_attrs[] = { + &f_midi_opts_index.attr, + &f_midi_opts_buflen.attr, + &f_midi_opts_qlen.attr, + &f_midi_opts_in_ports.attr, + &f_midi_opts_out_ports.attr, + &f_midi_opts_id.attr, + NULL, +}; + +static struct config_item_type midi_func_type = { + .ct_item_ops = &midi_item_ops, + .ct_attrs = midi_attrs, + .ct_owner = THIS_MODULE, +}; + static void f_midi_free_inst(struct usb_function_instance *f) { struct f_midi_opts *opts; opts = container_of(f, struct f_midi_opts, func_inst); + if (opts->id_allocated) + kfree(opts->id); + kfree(opts); } @@ -912,7 +1045,18 @@ static struct usb_function_instance *f_midi_alloc_inst(void) opts = kzalloc(sizeof(*opts), GFP_KERNEL); if (!opts) return ERR_PTR(-ENOMEM); + + mutex_init(&opts->lock); opts->func_inst.free_func_inst = f_midi_free_inst; + opts->index = SNDRV_DEFAULT_IDX1; + opts->id = SNDRV_DEFAULT_STR1; + opts->buflen = 256; + opts->qlen = 32; + opts->in_ports = 1; + opts->out_ports = 1; + + config_group_init_type_name(&opts->func_inst.group, "", + &midi_func_type); return &opts->func_inst; } @@ -926,9 +1070,12 @@ static void f_midi_free(struct usb_function *f) midi = func_to_midi(f); opts = container_of(f->fi, struct f_midi_opts, func_inst); kfree(midi->id); + mutex_lock(&opts->lock); for (i = opts->in_ports - 1; i >= 0; --i) kfree(midi->in_port[i]); kfree(midi); + --opts->refcnt; + mutex_unlock(&opts->lock); } static void f_midi_unbind(struct usb_configuration *c, struct usb_function *f) @@ -957,20 +1104,27 @@ struct usb_function *f_midi_alloc(struct usb_function_instance *fi) int status, i; opts = container_of(fi, struct f_midi_opts, func_inst); + + mutex_lock(&opts->lock); /* sanity check */ - if (opts->in_ports > MAX_PORTS || opts->out_ports > MAX_PORTS) + if (opts->in_ports > MAX_PORTS || opts->out_ports > MAX_PORTS) { + mutex_unlock(&opts->lock); return ERR_PTR(-EINVAL); + } /* allocate and initialize one new instance */ midi = kzalloc(sizeof(*midi), GFP_KERNEL); - if (!midi) + if (!midi) { + mutex_unlock(&opts->lock); return ERR_PTR(-ENOMEM); + } for (i = 0; i < opts->in_ports; i++) { struct gmidi_in_port *port = kzalloc(sizeof(*port), GFP_KERNEL); if (!port) { status = -ENOMEM; + mutex_unlock(&opts->lock); goto setup_fail; } @@ -984,6 +1138,7 @@ struct usb_function *f_midi_alloc(struct usb_function_instance *fi) midi->id = kstrdup(opts->id, GFP_KERNEL); if (opts->id && !midi->id) { status = -ENOMEM; + mutex_unlock(&opts->lock); goto kstrdup_fail; } midi->in_ports = opts->in_ports; @@ -991,6 +1146,8 @@ struct usb_function *f_midi_alloc(struct usb_function_instance *fi) midi->index = opts->index; midi->buflen = opts->buflen; midi->qlen = opts->qlen; + ++opts->refcnt; + mutex_unlock(&opts->lock); midi->func.name = "gmidi function"; midi->func.bind = f_midi_bind; diff --git a/drivers/usb/gadget/function/u_midi.h b/drivers/usb/gadget/function/u_midi.h index 76bccc1fdbb4..22510189758e 100644 --- a/drivers/usb/gadget/function/u_midi.h +++ b/drivers/usb/gadget/function/u_midi.h @@ -22,10 +22,18 @@ struct f_midi_opts { struct usb_function_instance func_inst; int index; char *id; + bool id_allocated; unsigned int in_ports; unsigned int out_ports; unsigned int buflen; unsigned int qlen; + + /* + * Protect the data form concurrent access by read/write + * and create symlink/remove symlink. + */ + struct mutex lock; + int refcnt; }; #endif /* U_MIDI_H */ -- cgit v1.2.3-59-g8ed1b From 6de2d21adaf05b7a456077625b6e311feabd3718 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Wed, 15 Oct 2014 10:23:01 -0700 Subject: ARM: rockchip: add option to access the pmu via a phandle in smp_operations Makes it possible to define a rockchip,pmu phandle in the cpus node directly referencing the pmu syscon instead of searching for specific compatible. The old way of finding the pmu stays of course available. Signed-off-by: Kever Yang Tested-by: Kevin Hilman Signed-off-by: Heiko Stuebner --- Documentation/devicetree/bindings/arm/cpus.txt | 9 +++++++++ arch/arm/mach-rockchip/platsmp.c | 13 +++++++++++++ 2 files changed, 22 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/cpus.txt b/Documentation/devicetree/bindings/arm/cpus.txt index fc446347ab6d..b2aacbe16ed9 100644 --- a/Documentation/devicetree/bindings/arm/cpus.txt +++ b/Documentation/devicetree/bindings/arm/cpus.txt @@ -227,6 +227,15 @@ nodes to be present and contain the properties described below. # List of phandles to idle state nodes supported by this cpu [3]. + - rockchip,pmu + Usage: optional for systems that have an "enable-method" + property value of "rockchip,rk3066-smp" + While optional, it is the preferred way to get access to + the cpu-core power-domains. + Value type: + Definition: Specifies the syscon node controlling the cpu core + power domains. + Example 1 (dual-cluster big.LITTLE system 32-bit): cpus { diff --git a/arch/arm/mach-rockchip/platsmp.c b/arch/arm/mach-rockchip/platsmp.c index 4c36fbf99afb..57b53b32e103 100644 --- a/arch/arm/mach-rockchip/platsmp.c +++ b/arch/arm/mach-rockchip/platsmp.c @@ -155,6 +155,19 @@ static int __init rockchip_smp_prepare_pmu(void) struct device_node *node; void __iomem *pmu_base; + /* + * This function is only called via smp_ops->smp_prepare_cpu(). + * That only happens if a "/cpus" device tree node exists + * and has an "enable-method" property that selects the SMP + * operations defined herein. + */ + node = of_find_node_by_path("/cpus"); + + pmu = syscon_regmap_lookup_by_phandle(node, "rockchip,pmu"); + of_node_put(node); + if (!IS_ERR(pmu)) + return 0; + pmu = syscon_regmap_lookup_by_compatible("rockchip,rk3066-pmu"); if (!IS_ERR(pmu)) return 0; -- cgit v1.2.3-59-g8ed1b From abb1cd00e6b7434e866f1f817b4994e1c7f1f16d Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Sat, 11 Oct 2014 18:01:50 +0800 Subject: mtd: atmel_nand: make PMECC lookup table and offset property optional If there is no PMECC lookup table stored in ROM, or lookup table offset is not specified, PMECC driver should build it in DDR by itself. That make the PMECC driver work for some board which doesn't have PMECC lookup table in ROM. The PMECC use the BCH algorithm, so based on the build_gf_tables() function in lib/bch.c, we can build the Galois Field lookup table. For more information can refer to section 5.4 of PMECC controller application note: http://www.atmel.com/images/doc11127.pdf Signed-off-by: Josh Wu Cc: devicetree@vger.kernel.org Signed-off-by: Brian Norris --- .../devicetree/bindings/mtd/atmel-nand.txt | 6 +- drivers/mtd/nand/atmel_nand.c | 81 ++++++++++++++++++++-- drivers/mtd/nand/atmel_nand_ecc.h | 4 ++ 3 files changed, 85 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mtd/atmel-nand.txt b/Documentation/devicetree/bindings/mtd/atmel-nand.txt index 6edc3b616e98..1fe6dde98499 100644 --- a/Documentation/devicetree/bindings/mtd/atmel-nand.txt +++ b/Documentation/devicetree/bindings/mtd/atmel-nand.txt @@ -5,7 +5,9 @@ Required properties: - reg : should specify localbus address and size used for the chip, and hardware ECC controller if available. If the hardware ECC is PMECC, it should contain address and size for - PMECC, PMECC Error Location controller and ROM which has lookup tables. + PMECC and PMECC Error Location controller. + The PMECC lookup table address and size in ROM is optional. If not + specified, driver will build it in runtime. - atmel,nand-addr-offset : offset for the address latch. - atmel,nand-cmd-offset : offset for the command latch. - #address-cells, #size-cells : Must be present if the device has sub-nodes @@ -27,7 +29,7 @@ Optional properties: are: 512, 1024. - atmel,pmecc-lookup-table-offset : includes two offsets of lookup table in ROM for different sector size. First one is for sector size 512, the next is for - sector size 1024. + sector size 1024. If not specified, driver will build the table in runtime. - nand-bus-width : 8 or 16 bus width if not present 8 - nand-on-flash-bbt: boolean to enable on flash bbt option if not present false - Nand Flash Controller(NFC) is a slave driver under Atmel nand flash diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 19d1e9d17bf9..5c1423a2ffb5 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -127,6 +127,7 @@ struct atmel_nand_host { bool has_pmecc; u8 pmecc_corr_cap; u16 pmecc_sector_size; + bool has_no_lookup_table; u32 pmecc_lookup_table_offset; u32 pmecc_lookup_table_offset_512; u32 pmecc_lookup_table_offset_1024; @@ -1112,12 +1113,66 @@ static int pmecc_choose_ecc(struct atmel_nand_host *host, return 0; } +static inline int deg(unsigned int poly) +{ + /* polynomial degree is the most-significant bit index */ + return fls(poly) - 1; +} + +static int build_gf_tables(int mm, unsigned int poly, + int16_t *index_of, int16_t *alpha_to) +{ + unsigned int i, x = 1; + const unsigned int k = 1 << deg(poly); + unsigned int nn = (1 << mm) - 1; + + /* primitive polynomial must be of degree m */ + if (k != (1u << mm)) + return -EINVAL; + + for (i = 0; i < nn; i++) { + alpha_to[i] = x; + index_of[x] = i; + if (i && (x == 1)) + /* polynomial is not primitive (a^i=1 with 0mtd; struct nand_chip *nand_chip = &host->nand_chip; struct resource *regs, *regs_pmerr, *regs_rom; + uint16_t *galois_table; int cap, sector_size, err_no; err_no = pmecc_choose_ecc(host, &cap, §or_size); @@ -1163,8 +1218,24 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev, regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3); host->pmecc_rom_base = devm_ioremap_resource(&pdev->dev, regs_rom); if (IS_ERR(host->pmecc_rom_base)) { - err_no = PTR_ERR(host->pmecc_rom_base); - goto err; + if (!host->has_no_lookup_table) + /* Don't display the information again */ + dev_err(host->dev, "Can not get I/O resource for ROM, will build a lookup table in runtime!\n"); + + host->has_no_lookup_table = true; + } + + if (host->has_no_lookup_table) { + /* Build the look-up table in runtime */ + galois_table = create_lookup_table(host->dev, sector_size); + if (!galois_table) { + dev_err(host->dev, "Failed to build a lookup table in runtime!\n"); + err_no = -EINVAL; + goto err; + } + + host->pmecc_rom_base = (void __iomem *)galois_table; + host->pmecc_lookup_table_offset = 0; } nand_chip->ecc.size = sector_size; @@ -1501,8 +1572,10 @@ static int atmel_of_init_port(struct atmel_nand_host *host, if (of_property_read_u32_array(np, "atmel,pmecc-lookup-table-offset", offset, 2) != 0) { - dev_err(host->dev, "Cannot get PMECC lookup table offset\n"); - return -EINVAL; + dev_err(host->dev, "Cannot get PMECC lookup table offset, will build a lookup table in runtime.\n"); + host->has_no_lookup_table = true; + /* Will build a lookup table and initialize the offset later */ + return 0; } if (!offset[0] && !offset[1]) { dev_err(host->dev, "Invalid PMECC lookup table offset\n"); diff --git a/drivers/mtd/nand/atmel_nand_ecc.h b/drivers/mtd/nand/atmel_nand_ecc.h index 8a1e9a686759..d4035e335ad8 100644 --- a/drivers/mtd/nand/atmel_nand_ecc.h +++ b/drivers/mtd/nand/atmel_nand_ecc.h @@ -142,6 +142,10 @@ #define PMECC_GF_DIMENSION_13 13 #define PMECC_GF_DIMENSION_14 14 +/* Primitive Polynomial used by PMECC */ +#define PMECC_GF_13_PRIMITIVE_POLY 0x201b +#define PMECC_GF_14_PRIMITIVE_POLY 0x4443 + #define PMECC_LOOKUP_TABLE_SIZE_512 0x2000 #define PMECC_LOOKUP_TABLE_SIZE_1024 0x4000 -- cgit v1.2.3-59-g8ed1b From 9227dc5e579b6b2ef58ad0d3d0d23ddac77846ef Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Tue, 4 Nov 2014 16:06:56 -0600 Subject: amd-xgbe: Add support for per DMA channel interrupts This patch provides support for interrupts that are generated by the Tx/Rx DMA channel pairs of the device. This allows for Tx and Rx processing to run across multiple processsors. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/amd-xgbe.txt | 12 +- drivers/net/ethernet/amd/xgbe/xgbe-dev.c | 12 +- drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 226 +++++++++++++++++---- drivers/net/ethernet/amd/xgbe/xgbe-main.c | 10 +- drivers/net/ethernet/amd/xgbe/xgbe.h | 10 +- 5 files changed, 219 insertions(+), 51 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/amd-xgbe.txt b/Documentation/devicetree/bindings/net/amd-xgbe.txt index 41354f730beb..26efd526d16c 100644 --- a/Documentation/devicetree/bindings/net/amd-xgbe.txt +++ b/Documentation/devicetree/bindings/net/amd-xgbe.txt @@ -7,7 +7,10 @@ Required properties: - PCS registers - interrupt-parent: Should be the phandle for the interrupt controller that services interrupts for this device -- interrupts: Should contain the amd-xgbe interrupt +- interrupts: Should contain the amd-xgbe interrupt(s). The first interrupt + listed is required and is the general device interrupt. If the optional + amd,per-channel-interrupt property is specified, then one additional + interrupt for each DMA channel supported by the device should be specified - clocks: - DMA clock for the amd-xgbe device (used for calculating the correct Rx interrupt watchdog timer value on a DMA channel @@ -23,6 +26,9 @@ Optional properties: - mac-address: mac address to be assigned to the device. Can be overridden by UEFI. - dma-coherent: Present if dma operations are coherent +- amd,per-channel-interrupt: Indicates that Rx and Tx complete will generate + a unique interrupt for each DMA channel - this requires an additional + interrupt be configured for each DMA channel Example: xgbe@e0700000 { @@ -30,7 +36,9 @@ Example: reg = <0 0xe0700000 0 0x80000>, <0 0xe0780000 0 0x80000>; interrupt-parent = <&gic>; - interrupts = <0 325 4>; + interrupts = <0 325 4>, + <0 326 1>, <0 327 1>, <0 328 1>, <0 329 1>; + amd,per-channel-interrupt; clocks = <&xgbe_dma_clk>, <&xgbe_ptp_clk>; clock-names = "dma_clk", "ptp_clk"; phy-handle = <&phy>; diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c index b3719f154637..ac3d319ffab3 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c @@ -481,17 +481,21 @@ static void xgbe_enable_dma_interrupts(struct xgbe_prv_data *pdata) if (channel->tx_ring) { /* Enable the following Tx interrupts - * TIE - Transmit Interrupt Enable (unless polling) + * TIE - Transmit Interrupt Enable (unless using + * per channel interrupts) */ - XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, TIE, 1); + if (!pdata->per_channel_irq) + XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, TIE, 1); } if (channel->rx_ring) { /* Enable following Rx interrupts * RBUE - Receive Buffer Unavailable Enable - * RIE - Receive Interrupt Enable + * RIE - Receive Interrupt Enable (unless using + * per channel interrupts) */ XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, RBUE, 1); - XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, RIE, 1); + if (!pdata->per_channel_irq) + XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, RIE, 1); } XGMAC_DMA_IOWRITE(channel, DMA_CH_IER, dma_ch_ier); diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index 07e2d216323a..c3533e104c61 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -114,6 +114,7 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ +#include #include #include #include @@ -126,7 +127,8 @@ #include "xgbe.h" #include "xgbe-common.h" -static int xgbe_poll(struct napi_struct *, int); +static int xgbe_one_poll(struct napi_struct *, int); +static int xgbe_all_poll(struct napi_struct *, int); static void xgbe_set_rx_mode(struct net_device *); static int xgbe_alloc_channels(struct xgbe_prv_data *pdata) @@ -134,6 +136,7 @@ static int xgbe_alloc_channels(struct xgbe_prv_data *pdata) struct xgbe_channel *channel_mem, *channel; struct xgbe_ring *tx_ring, *rx_ring; unsigned int count, i; + int ret = -ENOMEM; count = max_t(unsigned int, pdata->tx_ring_count, pdata->rx_ring_count); @@ -158,6 +161,19 @@ static int xgbe_alloc_channels(struct xgbe_prv_data *pdata) channel->dma_regs = pdata->xgmac_regs + DMA_CH_BASE + (DMA_CH_INC * i); + if (pdata->per_channel_irq) { + /* Get the DMA interrupt (offset 1) */ + ret = platform_get_irq(pdata->pdev, i + 1); + if (ret < 0) { + netdev_err(pdata->netdev, + "platform_get_irq %u failed\n", + i + 1); + goto err_irq; + } + + channel->dma_irq = ret; + } + if (i < pdata->tx_ring_count) { spin_lock_init(&tx_ring->lock); channel->tx_ring = tx_ring++; @@ -168,9 +184,9 @@ static int xgbe_alloc_channels(struct xgbe_prv_data *pdata) channel->rx_ring = rx_ring++; } - DBGPR(" %s - queue_index=%u, dma_regs=%p, tx=%p, rx=%p\n", + DBGPR(" %s: queue=%u, dma_regs=%p, dma_irq=%d, tx=%p, rx=%p\n", channel->name, channel->queue_index, channel->dma_regs, - channel->tx_ring, channel->rx_ring); + channel->dma_irq, channel->tx_ring, channel->rx_ring); } pdata->channel = channel_mem; @@ -178,6 +194,9 @@ static int xgbe_alloc_channels(struct xgbe_prv_data *pdata) return 0; +err_irq: + kfree(rx_ring); + err_rx_ring: kfree(tx_ring); @@ -185,9 +204,7 @@ err_tx_ring: kfree(channel_mem); err_channel: - netdev_err(pdata->netdev, "channel allocation failed\n"); - - return -ENOMEM; + return ret; } static void xgbe_free_channels(struct xgbe_prv_data *pdata) @@ -287,11 +304,7 @@ static irqreturn_t xgbe_isr(int irq, void *data) if (!dma_isr) goto isr_done; - DBGPR("-->xgbe_isr\n"); - DBGPR(" DMA_ISR = %08x\n", dma_isr); - DBGPR(" DMA_DS0 = %08x\n", XGMAC_IOREAD(pdata, DMA_DSR0)); - DBGPR(" DMA_DS1 = %08x\n", XGMAC_IOREAD(pdata, DMA_DSR1)); for (i = 0; i < pdata->channel_count; i++) { if (!(dma_isr & (1 << i))) @@ -302,6 +315,10 @@ static irqreturn_t xgbe_isr(int irq, void *data) dma_ch_isr = XGMAC_DMA_IOREAD(channel, DMA_CH_SR); DBGPR(" DMA_CH%u_ISR = %08x\n", i, dma_ch_isr); + /* If we get a TI or RI interrupt that means per channel DMA + * interrupts are not enabled, so we use the private data napi + * structure, not the per channel napi structure + */ if (XGMAC_GET_BITS(dma_ch_isr, DMA_CH_SR, TI) || XGMAC_GET_BITS(dma_ch_isr, DMA_CH_SR, RI)) { if (napi_schedule_prep(&pdata->napi)) { @@ -344,12 +361,28 @@ static irqreturn_t xgbe_isr(int irq, void *data) DBGPR(" DMA_ISR = %08x\n", XGMAC_IOREAD(pdata, DMA_ISR)); - DBGPR("<--xgbe_isr\n"); - isr_done: return IRQ_HANDLED; } +static irqreturn_t xgbe_dma_isr(int irq, void *data) +{ + struct xgbe_channel *channel = data; + + /* Per channel DMA interrupts are enabled, so we use the per + * channel napi structure and not the private data napi structure + */ + if (napi_schedule_prep(&channel->napi)) { + /* Disable Tx and Rx interrupts */ + disable_irq(channel->dma_irq); + + /* Turn on polling */ + __napi_schedule(&channel->napi); + } + + return IRQ_HANDLED; +} + static enum hrtimer_restart xgbe_tx_timer(struct hrtimer *timer) { struct xgbe_channel *channel = container_of(timer, @@ -357,18 +390,24 @@ static enum hrtimer_restart xgbe_tx_timer(struct hrtimer *timer) tx_timer); struct xgbe_ring *ring = channel->tx_ring; struct xgbe_prv_data *pdata = channel->pdata; + struct napi_struct *napi; unsigned long flags; DBGPR("-->xgbe_tx_timer\n"); + napi = (pdata->per_channel_irq) ? &channel->napi : &pdata->napi; + spin_lock_irqsave(&ring->lock, flags); - if (napi_schedule_prep(&pdata->napi)) { + if (napi_schedule_prep(napi)) { /* Disable Tx and Rx interrupts */ - xgbe_disable_rx_tx_ints(pdata); + if (pdata->per_channel_irq) + disable_irq(channel->dma_irq); + else + xgbe_disable_rx_tx_ints(pdata); /* Turn on polling */ - __napi_schedule(&pdata->napi); + __napi_schedule(napi); } channel->tx_timer_active = 0; @@ -504,18 +543,46 @@ void xgbe_get_all_hw_features(struct xgbe_prv_data *pdata) static void xgbe_napi_enable(struct xgbe_prv_data *pdata, unsigned int add) { - if (add) - netif_napi_add(pdata->netdev, &pdata->napi, xgbe_poll, - NAPI_POLL_WEIGHT); - napi_enable(&pdata->napi); + struct xgbe_channel *channel; + unsigned int i; + + if (pdata->per_channel_irq) { + channel = pdata->channel; + for (i = 0; i < pdata->channel_count; i++, channel++) { + if (add) + netif_napi_add(pdata->netdev, &channel->napi, + xgbe_one_poll, NAPI_POLL_WEIGHT); + + napi_enable(&channel->napi); + } + } else { + if (add) + netif_napi_add(pdata->netdev, &pdata->napi, + xgbe_all_poll, NAPI_POLL_WEIGHT); + + napi_enable(&pdata->napi); + } } static void xgbe_napi_disable(struct xgbe_prv_data *pdata, unsigned int del) { - napi_disable(&pdata->napi); + struct xgbe_channel *channel; + unsigned int i; + + if (pdata->per_channel_irq) { + channel = pdata->channel; + for (i = 0; i < pdata->channel_count; i++, channel++) { + napi_disable(&channel->napi); - if (del) - netif_napi_del(&pdata->napi); + if (del) + netif_napi_del(&channel->napi); + } + } else { + napi_disable(&pdata->napi); + + if (del) + netif_napi_del(&pdata->napi); + } } void xgbe_init_tx_coalesce(struct xgbe_prv_data *pdata) @@ -828,7 +895,9 @@ static void xgbe_stop(struct xgbe_prv_data *pdata) static void xgbe_restart_dev(struct xgbe_prv_data *pdata, unsigned int reset) { + struct xgbe_channel *channel; struct xgbe_hw_if *hw_if = &pdata->hw_if; + unsigned int i; DBGPR("-->xgbe_restart_dev\n"); @@ -837,7 +906,12 @@ static void xgbe_restart_dev(struct xgbe_prv_data *pdata, unsigned int reset) return; xgbe_stop(pdata); - synchronize_irq(pdata->irq_number); + synchronize_irq(pdata->dev_irq); + if (pdata->per_channel_irq) { + channel = pdata->channel; + for (i = 0; i < pdata->channel_count; i++, channel++) + synchronize_irq(channel->dma_irq); + } xgbe_free_tx_data(pdata); xgbe_free_rx_data(pdata); @@ -1165,6 +1239,9 @@ static int xgbe_open(struct net_device *netdev) struct xgbe_prv_data *pdata = netdev_priv(netdev); struct xgbe_hw_if *hw_if = &pdata->hw_if; struct xgbe_desc_if *desc_if = &pdata->desc_if; + struct xgbe_channel *channel = NULL; + char dma_irq_name[IFNAMSIZ + 32]; + unsigned int i = 0; int ret; DBGPR("-->xgbe_open\n"); @@ -1208,14 +1285,32 @@ static int xgbe_open(struct net_device *netdev) INIT_WORK(&pdata->tx_tstamp_work, xgbe_tx_tstamp); /* Request interrupts */ - ret = devm_request_irq(pdata->dev, netdev->irq, xgbe_isr, 0, + ret = devm_request_irq(pdata->dev, pdata->dev_irq, xgbe_isr, 0, netdev->name, pdata); if (ret) { netdev_alert(netdev, "error requesting irq %d\n", - pdata->irq_number); + pdata->dev_irq); goto err_rings; } - pdata->irq_number = netdev->irq; + + if (pdata->per_channel_irq) { + channel = pdata->channel; + for (i = 0; i < pdata->channel_count; i++, channel++) { + snprintf(dma_irq_name, sizeof(dma_irq_name) - 1, + "%s-TxRx-%u", netdev_name(netdev), + channel->queue_index); + + ret = devm_request_irq(pdata->dev, channel->dma_irq, + xgbe_dma_isr, 0, dma_irq_name, + channel); + if (ret) { + netdev_alert(netdev, + "error requesting irq %d\n", + channel->dma_irq); + goto err_irq; + } + } + } ret = xgbe_start(pdata); if (ret) @@ -1228,8 +1323,14 @@ static int xgbe_open(struct net_device *netdev) err_start: hw_if->exit(pdata); - devm_free_irq(pdata->dev, pdata->irq_number, pdata); - pdata->irq_number = 0; +err_irq: + if (pdata->per_channel_irq) { + /* Using an unsigned int, 'i' will go to UINT_MAX and exit */ + for (i--, channel--; i < pdata->channel_count; i--, channel--) + devm_free_irq(pdata->dev, channel->dma_irq, channel); + } + + devm_free_irq(pdata->dev, pdata->dev_irq, pdata); err_rings: desc_if->free_ring_resources(pdata); @@ -1254,6 +1355,8 @@ static int xgbe_close(struct net_device *netdev) struct xgbe_prv_data *pdata = netdev_priv(netdev); struct xgbe_hw_if *hw_if = &pdata->hw_if; struct xgbe_desc_if *desc_if = &pdata->desc_if; + struct xgbe_channel *channel; + unsigned int i; DBGPR("-->xgbe_close\n"); @@ -1269,10 +1372,12 @@ static int xgbe_close(struct net_device *netdev) /* Free the channel and ring structures */ xgbe_free_channels(pdata); - /* Release the interrupt */ - if (pdata->irq_number != 0) { - devm_free_irq(pdata->dev, pdata->irq_number, pdata); - pdata->irq_number = 0; + /* Release the interrupts */ + devm_free_irq(pdata->dev, pdata->dev_irq, pdata); + if (pdata->per_channel_irq) { + channel = pdata->channel; + for (i = 0; i < pdata->channel_count; i++, channel++) + devm_free_irq(pdata->dev, channel->dma_irq, channel); } /* Disable the clocks */ @@ -1505,14 +1610,20 @@ static int xgbe_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, static void xgbe_poll_controller(struct net_device *netdev) { struct xgbe_prv_data *pdata = netdev_priv(netdev); + struct xgbe_channel *channel; + unsigned int i; DBGPR("-->xgbe_poll_controller\n"); - disable_irq(pdata->irq_number); - - xgbe_isr(pdata->irq_number, pdata); - - enable_irq(pdata->irq_number); + if (pdata->per_channel_irq) { + channel = pdata->channel; + for (i = 0; i < pdata->channel_count; i++, channel++) + xgbe_dma_isr(channel->dma_irq, channel); + } else { + disable_irq(pdata->dev_irq); + xgbe_isr(pdata->dev_irq, pdata); + enable_irq(pdata->dev_irq); + } DBGPR("<--xgbe_poll_controller\n"); } @@ -1704,6 +1815,7 @@ static int xgbe_rx_poll(struct xgbe_channel *channel, int budget) struct xgbe_ring_data *rdata; struct xgbe_packet_data *packet; struct net_device *netdev = pdata->netdev; + struct napi_struct *napi; struct sk_buff *skb; struct skb_shared_hwtstamps *hwtstamps; unsigned int incomplete, error, context_next, context; @@ -1717,6 +1829,8 @@ static int xgbe_rx_poll(struct xgbe_channel *channel, int budget) if (!ring) return 0; + napi = (pdata->per_channel_irq) ? &channel->napi : &pdata->napi; + rdata = XGBE_GET_DESC_DATA(ring, ring->cur); packet = &ring->packet_data; while (packet_count < budget) { @@ -1849,10 +1963,10 @@ read_again: skb->dev = netdev; skb->protocol = eth_type_trans(skb, netdev); skb_record_rx_queue(skb, channel->queue_index); - skb_mark_napi_id(skb, &pdata->napi); + skb_mark_napi_id(skb, napi); netdev->last_rx = jiffies; - napi_gro_receive(&pdata->napi, skb); + napi_gro_receive(napi, skb); next_packet: packet_count++; @@ -1874,7 +1988,35 @@ next_packet: return packet_count; } -static int xgbe_poll(struct napi_struct *napi, int budget) +static int xgbe_one_poll(struct napi_struct *napi, int budget) +{ + struct xgbe_channel *channel = container_of(napi, struct xgbe_channel, + napi); + int processed = 0; + + DBGPR("-->xgbe_one_poll: budget=%d\n", budget); + + /* Cleanup Tx ring first */ + xgbe_tx_poll(channel); + + /* Process Rx ring next */ + processed = xgbe_rx_poll(channel, budget); + + /* If we processed everything, we are done */ + if (processed < budget) { + /* Turn off polling */ + napi_complete(napi); + + /* Enable Tx and Rx interrupts */ + enable_irq(channel->dma_irq); + } + + DBGPR("<--xgbe_one_poll: received = %d\n", processed); + + return processed; +} + +static int xgbe_all_poll(struct napi_struct *napi, int budget) { struct xgbe_prv_data *pdata = container_of(napi, struct xgbe_prv_data, napi); @@ -1883,7 +2025,7 @@ static int xgbe_poll(struct napi_struct *napi, int budget) int processed, last_processed; unsigned int i; - DBGPR("-->xgbe_poll: budget=%d\n", budget); + DBGPR("-->xgbe_all_poll: budget=%d\n", budget); processed = 0; ring_budget = budget / pdata->rx_ring_count; @@ -1911,7 +2053,7 @@ static int xgbe_poll(struct napi_struct *napi, int budget) xgbe_enable_rx_tx_ints(pdata); } - DBGPR("<--xgbe_poll: received = %d\n", processed); + DBGPR("<--xgbe_all_poll: received = %d\n", processed); return processed; } diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-main.c b/drivers/net/ethernet/amd/xgbe/xgbe-main.c index e5077fd5b012..cff9902d1456 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-main.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-main.c @@ -264,12 +264,18 @@ static int xgbe_probe(struct platform_device *pdev) pdata->awcache = XGBE_DMA_SYS_AWCACHE; } + /* Check for per channel interrupt support */ + if (of_property_read_bool(dev->of_node, XGBE_DMA_IRQS)) + pdata->per_channel_irq = 1; + ret = platform_get_irq(pdev, 0); if (ret < 0) { - dev_err(dev, "platform_get_irq failed\n"); + dev_err(dev, "platform_get_irq 0 failed\n"); goto err_io; } - netdev->irq = ret; + pdata->dev_irq = ret; + + netdev->irq = pdata->dev_irq; netdev->base_addr = (unsigned long)pdata->xgmac_regs; /* Set all the function pointers */ diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h index 1480c9d41821..55c935f4884a 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h @@ -173,6 +173,7 @@ /* Device-tree clock names */ #define XGBE_DMA_CLOCK "dma_clk" #define XGBE_PTP_CLOCK "ptp_clk" +#define XGBE_DMA_IRQS "amd,per-channel-interrupt" /* Timestamp support - values based on 50MHz PTP clock * 50MHz => 20 nsec @@ -359,6 +360,12 @@ struct xgbe_channel { unsigned int queue_index; void __iomem *dma_regs; + /* Per channel interrupt irq number */ + int dma_irq; + + /* Netdev related settings */ + struct napi_struct napi; + unsigned int saved_ier; unsigned int tx_timer_active; @@ -609,7 +616,8 @@ struct xgbe_prv_data { /* XPCS indirect addressing mutex */ struct mutex xpcs_mutex; - int irq_number; + int dev_irq; + unsigned int per_channel_irq; struct xgbe_hw_if hw_if; struct xgbe_desc_if desc_if; -- cgit v1.2.3-59-g8ed1b From 7c8ab967e3cd1513cd79fd5edc404fb43c7f3a96 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Thu, 16 Oct 2014 16:54:20 -0400 Subject: serial: Fix locking for uart driver set_termios() method The low-level uart driver may modify termios settings to override settings that are not compatible with the uart, such as CRTSCTS. Thus, callers of the low-level uart driver's set_termios() method must hold termios_rwsem write lock to prevent concurrent access to termios, in case such override occurs. The termios_rwsem lock requirement does not extend to console setup (ie., uart_set_options), as console setup cannot race with tty operations. Nor does this lock requirement extend to functions which cannot be concurrent with tty ioctls (ie., uart_port_startup() and uart_resume_port()). Further, always claim the port mutex to protect hardware re-reprogramming in the set_termios() uart driver method. Note this is unnecessary for console initialization in uart_set_options() which cannot be concurrent with other uart operations. Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- Documentation/serial/driver | 6 ++++-- drivers/tty/serial/serial_core.c | 8 +++++++- 2 files changed, 11 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/serial/driver b/Documentation/serial/driver index ba64e4b892e9..c415b0ef4493 100644 --- a/Documentation/serial/driver +++ b/Documentation/serial/driver @@ -59,7 +59,9 @@ The core driver uses the info->tmpbuf_sem lock to prevent multi-threaded access to the info->tmpbuf bouncebuffer used for port writes. The port_sem semaphore is used to protect against ports being added/ -removed or reconfigured at inappropriate times. +removed or reconfigured at inappropriate times. Since v2.6.27, this +semaphore has been the 'mutex' member of the tty_port struct, and +commonly referred to as the port mutex (or port->mutex). uart_ops @@ -248,7 +250,7 @@ hardware. Other flags may be used (eg, xon/xoff characters) if your hardware supports hardware "soft" flow control. - Locking: none. + Locking: caller holds port->mutex Interrupts: caller dependent. This call must not sleep diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 9d142972ee2d..e31d56159aee 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -436,7 +436,7 @@ uart_get_divisor(struct uart_port *port, unsigned int baud) EXPORT_SYMBOL(uart_get_divisor); -/* FIXME: Consistent locking policy */ +/* Caller holds port mutex */ static void uart_change_speed(struct tty_struct *tty, struct uart_state *state, struct ktermios *old_termios) { @@ -1173,11 +1173,15 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, break; case TIOCSSERIAL: + down_write(&tty->termios_rwsem); ret = uart_set_info_user(tty, state, uarg); + up_write(&tty->termios_rwsem); break; case TIOCSERCONFIG: + down_write(&tty->termios_rwsem); ret = uart_do_autoconfig(tty, state); + up_write(&tty->termios_rwsem); break; case TIOCSERGWILD: /* obsolete */ @@ -1278,7 +1282,9 @@ static void uart_set_termios(struct tty_struct *tty, return; } + mutex_lock(&state->port.mutex); uart_change_speed(tty, state, old_termios); + mutex_unlock(&state->port.mutex); /* reload cflag from termios; port driver may have overriden flags */ cflag = tty->termios.c_cflag; -- cgit v1.2.3-59-g8ed1b From a3d3044e7d0af3c47ebe6300653edc4203665c5f Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Wed, 22 Oct 2014 17:22:19 +0200 Subject: ARM: dts: at_xdmac: add bindings documentation Add bindings documentation for the new Atmel DMA controller (XDMAC) introduced with SAMA5D4. Signed-off-by: Ludovic Desroches Acked-by: Nicolas Ferre Signed-off-by: Vinod Koul --- .../devicetree/bindings/dma/atmel-xdma.txt | 54 ++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 Documentation/devicetree/bindings/dma/atmel-xdma.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/dma/atmel-xdma.txt b/Documentation/devicetree/bindings/dma/atmel-xdma.txt new file mode 100644 index 000000000000..e75c128c53fa --- /dev/null +++ b/Documentation/devicetree/bindings/dma/atmel-xdma.txt @@ -0,0 +1,54 @@ +* Atmel Extensible Direct Memory Access Controller (XDMAC) + +* XDMA Controller +Required properties: +- compatible: Should be "atmel,-dma". + compatible description: + - sama5d4: first SoC adding the XDMAC +- reg: Should contain DMA registers location and length. +- interrupts: Should contain DMA interrupt. +- #dma-cells: Must be <1>, used to represent the number of integer cells in +the dmas property of client devices. + - The 1st cell specifies the channel configuration register: + - bit 13: SIF, source interface identifier, used to get the memory + interface identifier, + - bit 14: DIF, destination interface identifier, used to get the peripheral + interface identifier, + - bit 30-24: PERID, peripheral identifier. + +Example: + +dma1: dma-controller@f0004000 { + compatible = "atmel,sama5d4-dma"; + reg = <0xf0004000 0x200>; + interrupts = <50 4 0>; + #dma-cells = <2>; +}; + + +* DMA clients +DMA clients connected to the Atmel XDMA controller must use the format +described in the dma.txt file, using a one-cell specifier for each channel. +The two cells in order are: +1. A phandle pointing to the DMA controller. +2. Channel configuration register. Configurable fields are: + - bit 13: SIF, source interface identifier, used to get the memory + interface identifier, + - bit 14: DIF, destination interface identifier, used to get the peripheral + interface identifier, + - bit 30-24: PERID, peripheral identifier. + +Example: + +i2c2: i2c@f8024000 { + compatible = "atmel,at91sam9x5-i2c"; + reg = <0xf8024000 0x4000>; + interrupts = <34 4 6>; + dmas = <&dma1 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) + | AT91_XDMAC_DT_PERID(6))>, + <&dma1 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) + | AT91_XDMAC_DT_PERID(7))>; + dma-names = "tx", "rx"; +}; -- cgit v1.2.3-59-g8ed1b From f36d2e6752bad5323fd0dc2c717cc200d83a09d1 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 28 Oct 2014 21:55:49 +0100 Subject: Documentation: dmaengine: Move the current doc to a folder of its own Move the current client-side documentation to a subfolder to prepare the introduction of a provider-side API documentation. Signed-off-by: Maxime Ripard Signed-off-by: Vinod Koul --- Documentation/dmaengine.txt | 199 ------------------------------------- Documentation/dmaengine/client.txt | 199 +++++++++++++++++++++++++++++++++++++ 2 files changed, 199 insertions(+), 199 deletions(-) delete mode 100644 Documentation/dmaengine.txt create mode 100644 Documentation/dmaengine/client.txt (limited to 'Documentation') diff --git a/Documentation/dmaengine.txt b/Documentation/dmaengine.txt deleted file mode 100644 index 11fb87ff6cd0..000000000000 --- a/Documentation/dmaengine.txt +++ /dev/null @@ -1,199 +0,0 @@ - DMA Engine API Guide - ==================== - - Vinod Koul - -NOTE: For DMA Engine usage in async_tx please see: - Documentation/crypto/async-tx-api.txt - - -Below is a guide to device driver writers on how to use the Slave-DMA API of the -DMA Engine. This is applicable only for slave DMA usage only. - -The slave DMA usage consists of following steps: -1. Allocate a DMA slave channel -2. Set slave and controller specific parameters -3. Get a descriptor for transaction -4. Submit the transaction -5. Issue pending requests and wait for callback notification - -1. Allocate a DMA slave channel - - Channel allocation is slightly different in the slave DMA context, - client drivers typically need a channel from a particular DMA - controller only and even in some cases a specific channel is desired. - To request a channel dma_request_channel() API is used. - - Interface: - struct dma_chan *dma_request_channel(dma_cap_mask_t mask, - dma_filter_fn filter_fn, - void *filter_param); - where dma_filter_fn is defined as: - typedef bool (*dma_filter_fn)(struct dma_chan *chan, void *filter_param); - - The 'filter_fn' parameter is optional, but highly recommended for - slave and cyclic channels as they typically need to obtain a specific - DMA channel. - - When the optional 'filter_fn' parameter is NULL, dma_request_channel() - simply returns the first channel that satisfies the capability mask. - - Otherwise, the 'filter_fn' routine will be called once for each free - channel which has a capability in 'mask'. 'filter_fn' is expected to - return 'true' when the desired DMA channel is found. - - A channel allocated via this interface is exclusive to the caller, - until dma_release_channel() is called. - -2. Set slave and controller specific parameters - - Next step is always to pass some specific information to the DMA - driver. Most of the generic information which a slave DMA can use - is in struct dma_slave_config. This allows the clients to specify - DMA direction, DMA addresses, bus widths, DMA burst lengths etc - for the peripheral. - - If some DMA controllers have more parameters to be sent then they - should try to embed struct dma_slave_config in their controller - specific structure. That gives flexibility to client to pass more - parameters, if required. - - Interface: - int dmaengine_slave_config(struct dma_chan *chan, - struct dma_slave_config *config) - - Please see the dma_slave_config structure definition in dmaengine.h - for a detailed explanation of the struct members. Please note - that the 'direction' member will be going away as it duplicates the - direction given in the prepare call. - -3. Get a descriptor for transaction - - For slave usage the various modes of slave transfers supported by the - DMA-engine are: - - slave_sg - DMA a list of scatter gather buffers from/to a peripheral - dma_cyclic - Perform a cyclic DMA operation from/to a peripheral till the - operation is explicitly stopped. - interleaved_dma - This is common to Slave as well as M2M clients. For slave - address of devices' fifo could be already known to the driver. - Various types of operations could be expressed by setting - appropriate values to the 'dma_interleaved_template' members. - - A non-NULL return of this transfer API represents a "descriptor" for - the given transaction. - - Interface: - struct dma_async_tx_descriptor *dmaengine_prep_slave_sg( - struct dma_chan *chan, struct scatterlist *sgl, - unsigned int sg_len, enum dma_data_direction direction, - unsigned long flags); - - struct dma_async_tx_descriptor *dmaengine_prep_dma_cyclic( - struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, - size_t period_len, enum dma_data_direction direction); - - struct dma_async_tx_descriptor *dmaengine_prep_interleaved_dma( - struct dma_chan *chan, struct dma_interleaved_template *xt, - unsigned long flags); - - The peripheral driver is expected to have mapped the scatterlist for - the DMA operation prior to calling dmaengine_prep_slave_sg(), and must - keep the scatterlist mapped until the DMA operation has completed. - The scatterlist must be mapped using the DMA struct device. - If a mapping needs to be synchronized later, dma_sync_*_for_*() must be - called using the DMA struct device, too. - So, normal setup should look like this: - - nr_sg = dma_map_sg(chan->device->dev, sgl, sg_len); - if (nr_sg == 0) - /* error */ - - desc = dmaengine_prep_slave_sg(chan, sgl, nr_sg, direction, flags); - - Once a descriptor has been obtained, the callback information can be - added and the descriptor must then be submitted. Some DMA engine - drivers may hold a spinlock between a successful preparation and - submission so it is important that these two operations are closely - paired. - - Note: - Although the async_tx API specifies that completion callback - routines cannot submit any new operations, this is not the - case for slave/cyclic DMA. - - For slave DMA, the subsequent transaction may not be available - for submission prior to callback function being invoked, so - slave DMA callbacks are permitted to prepare and submit a new - transaction. - - For cyclic DMA, a callback function may wish to terminate the - DMA via dmaengine_terminate_all(). - - Therefore, it is important that DMA engine drivers drop any - locks before calling the callback function which may cause a - deadlock. - - Note that callbacks will always be invoked from the DMA - engines tasklet, never from interrupt context. - -4. Submit the transaction - - Once the descriptor has been prepared and the callback information - added, it must be placed on the DMA engine drivers pending queue. - - Interface: - dma_cookie_t dmaengine_submit(struct dma_async_tx_descriptor *desc) - - This returns a cookie can be used to check the progress of DMA engine - activity via other DMA engine calls not covered in this document. - - dmaengine_submit() will not start the DMA operation, it merely adds - it to the pending queue. For this, see step 5, dma_async_issue_pending. - -5. Issue pending DMA requests and wait for callback notification - - The transactions in the pending queue can be activated by calling the - issue_pending API. If channel is idle then the first transaction in - queue is started and subsequent ones queued up. - - On completion of each DMA operation, the next in queue is started and - a tasklet triggered. The tasklet will then call the client driver - completion callback routine for notification, if set. - - Interface: - void dma_async_issue_pending(struct dma_chan *chan); - -Further APIs: - -1. int dmaengine_terminate_all(struct dma_chan *chan) - - This causes all activity for the DMA channel to be stopped, and may - discard data in the DMA FIFO which hasn't been fully transferred. - No callback functions will be called for any incomplete transfers. - -2. int dmaengine_pause(struct dma_chan *chan) - - This pauses activity on the DMA channel without data loss. - -3. int dmaengine_resume(struct dma_chan *chan) - - Resume a previously paused DMA channel. It is invalid to resume a - channel which is not currently paused. - -4. enum dma_status dma_async_is_tx_complete(struct dma_chan *chan, - dma_cookie_t cookie, dma_cookie_t *last, dma_cookie_t *used) - - This can be used to check the status of the channel. Please see - the documentation in include/linux/dmaengine.h for a more complete - description of this API. - - This can be used in conjunction with dma_async_is_complete() and - the cookie returned from dmaengine_submit() to check for - completion of a specific DMA transaction. - - Note: - Not all DMA engine drivers can return reliable information for - a running DMA channel. It is recommended that DMA engine users - pause or stop (via dmaengine_terminate_all()) the channel before - using this API. diff --git a/Documentation/dmaengine/client.txt b/Documentation/dmaengine/client.txt new file mode 100644 index 000000000000..11fb87ff6cd0 --- /dev/null +++ b/Documentation/dmaengine/client.txt @@ -0,0 +1,199 @@ + DMA Engine API Guide + ==================== + + Vinod Koul + +NOTE: For DMA Engine usage in async_tx please see: + Documentation/crypto/async-tx-api.txt + + +Below is a guide to device driver writers on how to use the Slave-DMA API of the +DMA Engine. This is applicable only for slave DMA usage only. + +The slave DMA usage consists of following steps: +1. Allocate a DMA slave channel +2. Set slave and controller specific parameters +3. Get a descriptor for transaction +4. Submit the transaction +5. Issue pending requests and wait for callback notification + +1. Allocate a DMA slave channel + + Channel allocation is slightly different in the slave DMA context, + client drivers typically need a channel from a particular DMA + controller only and even in some cases a specific channel is desired. + To request a channel dma_request_channel() API is used. + + Interface: + struct dma_chan *dma_request_channel(dma_cap_mask_t mask, + dma_filter_fn filter_fn, + void *filter_param); + where dma_filter_fn is defined as: + typedef bool (*dma_filter_fn)(struct dma_chan *chan, void *filter_param); + + The 'filter_fn' parameter is optional, but highly recommended for + slave and cyclic channels as they typically need to obtain a specific + DMA channel. + + When the optional 'filter_fn' parameter is NULL, dma_request_channel() + simply returns the first channel that satisfies the capability mask. + + Otherwise, the 'filter_fn' routine will be called once for each free + channel which has a capability in 'mask'. 'filter_fn' is expected to + return 'true' when the desired DMA channel is found. + + A channel allocated via this interface is exclusive to the caller, + until dma_release_channel() is called. + +2. Set slave and controller specific parameters + + Next step is always to pass some specific information to the DMA + driver. Most of the generic information which a slave DMA can use + is in struct dma_slave_config. This allows the clients to specify + DMA direction, DMA addresses, bus widths, DMA burst lengths etc + for the peripheral. + + If some DMA controllers have more parameters to be sent then they + should try to embed struct dma_slave_config in their controller + specific structure. That gives flexibility to client to pass more + parameters, if required. + + Interface: + int dmaengine_slave_config(struct dma_chan *chan, + struct dma_slave_config *config) + + Please see the dma_slave_config structure definition in dmaengine.h + for a detailed explanation of the struct members. Please note + that the 'direction' member will be going away as it duplicates the + direction given in the prepare call. + +3. Get a descriptor for transaction + + For slave usage the various modes of slave transfers supported by the + DMA-engine are: + + slave_sg - DMA a list of scatter gather buffers from/to a peripheral + dma_cyclic - Perform a cyclic DMA operation from/to a peripheral till the + operation is explicitly stopped. + interleaved_dma - This is common to Slave as well as M2M clients. For slave + address of devices' fifo could be already known to the driver. + Various types of operations could be expressed by setting + appropriate values to the 'dma_interleaved_template' members. + + A non-NULL return of this transfer API represents a "descriptor" for + the given transaction. + + Interface: + struct dma_async_tx_descriptor *dmaengine_prep_slave_sg( + struct dma_chan *chan, struct scatterlist *sgl, + unsigned int sg_len, enum dma_data_direction direction, + unsigned long flags); + + struct dma_async_tx_descriptor *dmaengine_prep_dma_cyclic( + struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, + size_t period_len, enum dma_data_direction direction); + + struct dma_async_tx_descriptor *dmaengine_prep_interleaved_dma( + struct dma_chan *chan, struct dma_interleaved_template *xt, + unsigned long flags); + + The peripheral driver is expected to have mapped the scatterlist for + the DMA operation prior to calling dmaengine_prep_slave_sg(), and must + keep the scatterlist mapped until the DMA operation has completed. + The scatterlist must be mapped using the DMA struct device. + If a mapping needs to be synchronized later, dma_sync_*_for_*() must be + called using the DMA struct device, too. + So, normal setup should look like this: + + nr_sg = dma_map_sg(chan->device->dev, sgl, sg_len); + if (nr_sg == 0) + /* error */ + + desc = dmaengine_prep_slave_sg(chan, sgl, nr_sg, direction, flags); + + Once a descriptor has been obtained, the callback information can be + added and the descriptor must then be submitted. Some DMA engine + drivers may hold a spinlock between a successful preparation and + submission so it is important that these two operations are closely + paired. + + Note: + Although the async_tx API specifies that completion callback + routines cannot submit any new operations, this is not the + case for slave/cyclic DMA. + + For slave DMA, the subsequent transaction may not be available + for submission prior to callback function being invoked, so + slave DMA callbacks are permitted to prepare and submit a new + transaction. + + For cyclic DMA, a callback function may wish to terminate the + DMA via dmaengine_terminate_all(). + + Therefore, it is important that DMA engine drivers drop any + locks before calling the callback function which may cause a + deadlock. + + Note that callbacks will always be invoked from the DMA + engines tasklet, never from interrupt context. + +4. Submit the transaction + + Once the descriptor has been prepared and the callback information + added, it must be placed on the DMA engine drivers pending queue. + + Interface: + dma_cookie_t dmaengine_submit(struct dma_async_tx_descriptor *desc) + + This returns a cookie can be used to check the progress of DMA engine + activity via other DMA engine calls not covered in this document. + + dmaengine_submit() will not start the DMA operation, it merely adds + it to the pending queue. For this, see step 5, dma_async_issue_pending. + +5. Issue pending DMA requests and wait for callback notification + + The transactions in the pending queue can be activated by calling the + issue_pending API. If channel is idle then the first transaction in + queue is started and subsequent ones queued up. + + On completion of each DMA operation, the next in queue is started and + a tasklet triggered. The tasklet will then call the client driver + completion callback routine for notification, if set. + + Interface: + void dma_async_issue_pending(struct dma_chan *chan); + +Further APIs: + +1. int dmaengine_terminate_all(struct dma_chan *chan) + + This causes all activity for the DMA channel to be stopped, and may + discard data in the DMA FIFO which hasn't been fully transferred. + No callback functions will be called for any incomplete transfers. + +2. int dmaengine_pause(struct dma_chan *chan) + + This pauses activity on the DMA channel without data loss. + +3. int dmaengine_resume(struct dma_chan *chan) + + Resume a previously paused DMA channel. It is invalid to resume a + channel which is not currently paused. + +4. enum dma_status dma_async_is_tx_complete(struct dma_chan *chan, + dma_cookie_t cookie, dma_cookie_t *last, dma_cookie_t *used) + + This can be used to check the status of the channel. Please see + the documentation in include/linux/dmaengine.h for a more complete + description of this API. + + This can be used in conjunction with dma_async_is_complete() and + the cookie returned from dmaengine_submit() to check for + completion of a specific DMA transaction. + + Note: + Not all DMA engine drivers can return reliable information for + a running DMA channel. It is recommended that DMA engine users + pause or stop (via dmaengine_terminate_all()) the channel before + using this API. -- cgit v1.2.3-59-g8ed1b From c4d2ae967c1821b424a7d818c8297db8e61fc267 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 28 Oct 2014 21:55:50 +0100 Subject: Documentation: dmaengine: Add a documentation for the dma controller API The dmaengine is neither trivial nor properly documented at the moment, which means a lot of trial and error development, which is not that good for such a central piece of the system. Attempt at making such a documentation. Signed-off-by: Maxime Ripard [fixed some minor typos] Signed-off-by: Vinod Koul --- Documentation/dmaengine/provider.txt | 366 +++++++++++++++++++++++++++++++++++ 1 file changed, 366 insertions(+) create mode 100644 Documentation/dmaengine/provider.txt (limited to 'Documentation') diff --git a/Documentation/dmaengine/provider.txt b/Documentation/dmaengine/provider.txt new file mode 100644 index 000000000000..766658ccf235 --- /dev/null +++ b/Documentation/dmaengine/provider.txt @@ -0,0 +1,366 @@ +DMAengine controller documentation +================================== + +Hardware Introduction ++++++++++++++++++++++ + +Most of the Slave DMA controllers have the same general principles of +operations. + +They have a given number of channels to use for the DMA transfers, and +a given number of requests lines. + +Requests and channels are pretty much orthogonal. Channels can be used +to serve several to any requests. To simplify, channels are the +entities that will be doing the copy, and requests what endpoints are +involved. + +The request lines actually correspond to physical lines going from the +DMA-eligible devices to the controller itself. Whenever the device +will want to start a transfer, it will assert a DMA request (DRQ) by +asserting that request line. + +A very simple DMA controller would only take into account a single +parameter: the transfer size. At each clock cycle, it would transfer a +byte of data from one buffer to another, until the transfer size has +been reached. + +That wouldn't work well in the real world, since slave devices might +require a specific number of bits to be transferred in a single +cycle. For example, we may want to transfer as much data as the +physical bus allows to maximize performances when doing a simple +memory copy operation, but our audio device could have a narrower FIFO +that requires data to be written exactly 16 or 24 bits at a time. This +is why most if not all of the DMA controllers can adjust this, using a +parameter called the transfer width. + +Moreover, some DMA controllers, whenever the RAM is used as a source +or destination, can group the reads or writes in memory into a buffer, +so instead of having a lot of small memory accesses, which is not +really efficient, you'll get several bigger transfers. This is done +using a parameter called the burst size, that defines how many single +reads/writes it's allowed to do without the controller splitting the +transfer into smaller sub-transfers. + +Our theoretical DMA controller would then only be able to do transfers +that involve a single contiguous block of data. However, some of the +transfers we usually have are not, and want to copy data from +non-contiguous buffers to a contiguous buffer, which is called +scatter-gather. + +DMAEngine, at least for mem2dev transfers, require support for +scatter-gather. So we're left with two cases here: either we have a +quite simple DMA controller that doesn't support it, and we'll have to +implement it in software, or we have a more advanced DMA controller, +that implements in hardware scatter-gather. + +The latter are usually programmed using a collection of chunks to +transfer, and whenever the transfer is started, the controller will go +over that collection, doing whatever we programmed there. + +This collection is usually either a table or a linked list. You will +then push either the address of the table and its number of elements, +or the first item of the list to one channel of the DMA controller, +and whenever a DRQ will be asserted, it will go through the collection +to know where to fetch the data from. + +Either way, the format of this collection is completely dependent on +your hardware. Each DMA controller will require a different structure, +but all of them will require, for every chunk, at least the source and +destination addresses, whether it should increment these addresses or +not and the three parameters we saw earlier: the burst size, the +transfer width and the transfer size. + +The one last thing is that usually, slave devices won't issue DRQ by +default, and you have to enable this in your slave device driver first +whenever you're willing to use DMA. + +These were just the general memory-to-memory (also called mem2mem) or +memory-to-device (mem2dev) kind of transfers. Most devices often +support other kind of transfers or memory operations that dmaengine +support and will be detailed later in this document. + +DMA Support in Linux +++++++++++++++++++++ + +Historically, DMA controller drivers have been implemented using the +async TX API, to offload operations such as memory copy, XOR, +cryptography, etc., basically any memory to memory operation. + +Over time, the need for memory to device transfers arose, and +dmaengine was extended. Nowadays, the async TX API is written as a +layer on top of dmaengine, and acts as a client. Still, dmaengine +accommodates that API in some cases, and made some design choices to +ensure that it stayed compatible. + +For more information on the Async TX API, please look the relevant +documentation file in Documentation/crypto/async-tx-api.txt. + +DMAEngine Registration +++++++++++++++++++++++ + +struct dma_device Initialization +-------------------------------- + +Just like any other kernel framework, the whole DMAEngine registration +relies on the driver filling a structure and registering against the +framework. In our case, that structure is dma_device. + +The first thing you need to do in your driver is to allocate this +structure. Any of the usual memory allocators will do, but you'll also +need to initialize a few fields in there: + + * channels: should be initialized as a list using the + INIT_LIST_HEAD macro for example + + * dev: should hold the pointer to the struct device associated + to your current driver instance. + +Supported transaction types +--------------------------- + +The next thing you need is to set which transaction types your device +(and driver) supports. + +Our dma_device structure has a field called cap_mask that holds the +various types of transaction supported, and you need to modify this +mask using the dma_cap_set function, with various flags depending on +transaction types you support as an argument. + +All those capabilities are defined in the dma_transaction_type enum, +in include/linux/dmaengine.h + +Currently, the types available are: + * DMA_MEMCPY + - The device is able to do memory to memory copies + + * DMA_XOR + - The device is able to perform XOR operations on memory areas + - Used to accelerate XOR intensive tasks, such as RAID5 + + * DMA_XOR_VAL + - The device is able to perform parity check using the XOR + algorithm against a memory buffer. + + * DMA_PQ + - The device is able to perform RAID6 P+Q computations, P being a + simple XOR, and Q being a Reed-Solomon algorithm. + + * DMA_PQ_VAL + - The device is able to perform parity check using RAID6 P+Q + algorithm against a memory buffer. + + * DMA_INTERRUPT + - The device is able to trigger a dummy transfer that will + generate periodic interrupts + - Used by the client drivers to register a callback that will be + called on a regular basis through the DMA controller interrupt + + * DMA_SG + - The device supports memory to memory scatter-gather + transfers. + - Even though a plain memcpy can look like a particular case of a + scatter-gather transfer, with a single chunk to transfer, it's a + distinct transaction type in the mem2mem transfers case + + * DMA_PRIVATE + - The devices only supports slave transfers, and as such isn't + available for async transfers. + + * DMA_ASYNC_TX + - Must not be set by the device, and will be set by the framework + if needed + - /* TODO: What is it about? */ + + * DMA_SLAVE + - The device can handle device to memory transfers, including + scatter-gather transfers. + - While in the mem2mem case we were having two distinct types to + deal with a single chunk to copy or a collection of them, here, + we just have a single transaction type that is supposed to + handle both. + - If you want to transfer a single contiguous memory buffer, + simply build a scatter list with only one item. + + * DMA_CYCLIC + - The device can handle cyclic transfers. + - A cyclic transfer is a transfer where the chunk collection will + loop over itself, with the last item pointing to the first. + - It's usually used for audio transfers, where you want to operate + on a single ring buffer that you will fill with your audio data. + + * DMA_INTERLEAVE + - The device supports interleaved transfer. + - These transfers can transfer data from a non-contiguous buffer + to a non-contiguous buffer, opposed to DMA_SLAVE that can + transfer data from a non-contiguous data set to a continuous + destination buffer. + - It's usually used for 2d content transfers, in which case you + want to transfer a portion of uncompressed data directly to the + display to print it + +These various types will also affect how the source and destination +addresses change over time. + +Addresses pointing to RAM are typically incremented (or decremented) +after each transfer. In case of a ring buffer, they may loop +(DMA_CYCLIC). Addresses pointing to a device's register (e.g. a FIFO) +are typically fixed. + +Device operations +----------------- + +Our dma_device structure also requires a few function pointers in +order to implement the actual logic, now that we described what +operations we were able to perform. + +The functions that we have to fill in there, and hence have to +implement, obviously depend on the transaction types you reported as +supported. + + * device_alloc_chan_resources + * device_free_chan_resources + - These functions will be called whenever a driver will call + dma_request_channel or dma_release_channel for the first/last + time on the channel associated to that driver. + - They are in charge of allocating/freeing all the needed + resources in order for that channel to be useful for your + driver. + - These functions can sleep. + + * device_prep_dma_* + - These functions are matching the capabilities you registered + previously. + - These functions all take the buffer or the scatterlist relevant + for the transfer being prepared, and should create a hardware + descriptor or a list of hardware descriptors from it + - These functions can be called from an interrupt context + - Any allocation you might do should be using the GFP_NOWAIT + flag, in order not to potentially sleep, but without depleting + the emergency pool either. + - Drivers should try to pre-allocate any memory they might need + during the transfer setup at probe time to avoid putting to + much pressure on the nowait allocator. + + - It should return a unique instance of the + dma_async_tx_descriptor structure, that further represents this + particular transfer. + + - This structure can be initialized using the function + dma_async_tx_descriptor_init. + - You'll also need to set two fields in this structure: + + flags: + TODO: Can it be modified by the driver itself, or + should it be always the flags passed in the arguments + + + tx_submit: A pointer to a function you have to implement, + that is supposed to push the current + transaction descriptor to a pending queue, waiting + for issue_pending to be called. + + * device_issue_pending + - Takes the first transaction descriptor in the pending queue, + and starts the transfer. Whenever that transfer is done, it + should move to the next transaction in the list. + - This function can be called in an interrupt context + + * device_tx_status + - Should report the bytes left to go over on the given channel + - Should only care about the transaction descriptor passed as + argument, not the currently active one on a given channel + - The tx_state argument might be NULL + - Should use dma_set_residue to report it + - In the case of a cyclic transfer, it should only take into + account the current period. + - This function can be called in an interrupt context. + + * device_control + - Used by client drivers to control and configure the channel it + has a handle on. + - Called with a command and an argument + + The command is one of the values listed by the enum + dma_ctrl_cmd. The valid commands are: + + DMA_PAUSE + + Pauses a transfer on the channel + + This command should operate synchronously on the channel, + pausing right away the work of the given channel + + DMA_RESUME + + Restarts a transfer on the channel + + This command should operate synchronously on the channel, + resuming right away the work of the given channel + + DMA_TERMINATE_ALL + + Aborts all the pending and ongoing transfers on the + channel + + This command should operate synchronously on the channel, + terminating right away all the channels + + DMA_SLAVE_CONFIG + + Reconfigures the channel with passed configuration + + This command should NOT perform synchronously, or on any + currently queued transfers, but only on subsequent ones + + In this case, the function will receive a + dma_slave_config structure pointer as an argument, that + will detail which configuration to use. + + Even though that structure contains a direction field, + this field is deprecated in favor of the direction + argument given to the prep_* functions + + FSLDMA_EXTERNAL_START + + TODO: Why does that even exist? + + The argument is an opaque unsigned long. This actually is a + pointer to a struct dma_slave_config that should be used only + in the DMA_SLAVE_CONFIG. + + * device_slave_caps + - Called through the framework by client drivers in order to have + an idea of what are the properties of the channel allocated to + them. + - Such properties are the buswidth, available directions, etc. + - Required for every generic layer doing DMA transfers, such as + ASoC. + +Misc notes (stuff that should be documented, but don't really know +where to put them) +------------------------------------------------------------------ + * dma_run_dependencies + - Should be called at the end of an async TX transfer, and can be + ignored in the slave transfers case. + - Makes sure that dependent operations are run before marking it + as complete. + + * dma_cookie_t + - it's a DMA transaction ID that will increment over time. + - Not really relevant any more since the introduction of virt-dma + that abstracts it away. + + * DMA_CTRL_ACK + - Undocumented feature + - No one really has an idea of what it's about, besides being + related to reusing the DMA transaction descriptors or having + additional transactions added to it in the async-tx API + - Useless in the case of the slave API + +General Design Notes +-------------------- + +Most of the DMAEngine drivers you'll see are based on a similar design +that handles the end of transfer interrupts in the handler, but defer +most work to a tasklet, including the start of a new transfer whenever +the previous transfer ended. + +This is a rather inefficient design though, because the inter-transfer +latency will be not only the interrupt latency, but also the +scheduling latency of the tasklet, which will leave the channel idle +in between, which will slow down the global transfer rate. + +You should avoid this kind of practice, and instead of electing a new +transfer in your tasklet, move that part to the interrupt handler in +order to have a shorter idle window (that we can't really avoid +anyway). + +Glossary +-------- + +Burst: A number of consecutive read or write operations + that can be queued to buffers before being flushed to + memory. +Chunk: A contiguous collection of bursts +Transfer: A collection of chunks (be it contiguous or not) -- cgit v1.2.3-59-g8ed1b From 935cdb56344d3d2dcc63db3175e0ddae79eba410 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 6 Nov 2014 11:17:37 +0530 Subject: Documentation: dmanegine: move dmatest.txt to dmaengine folder Signed-off-by: Vinod Koul --- Documentation/dmaengine/dmatest.txt | 92 +++++++++++++++++++++++++++++++++++++ Documentation/dmatest.txt | 92 ------------------------------------- 2 files changed, 92 insertions(+), 92 deletions(-) create mode 100644 Documentation/dmaengine/dmatest.txt delete mode 100644 Documentation/dmatest.txt (limited to 'Documentation') diff --git a/Documentation/dmaengine/dmatest.txt b/Documentation/dmaengine/dmatest.txt new file mode 100644 index 000000000000..dd77a81bdb80 --- /dev/null +++ b/Documentation/dmaengine/dmatest.txt @@ -0,0 +1,92 @@ + DMA Test Guide + ============== + + Andy Shevchenko + +This small document introduces how to test DMA drivers using dmatest module. + + Part 1 - How to build the test module + +The menuconfig contains an option that could be found by following path: + Device Drivers -> DMA Engine support -> DMA Test client + +In the configuration file the option called CONFIG_DMATEST. The dmatest could +be built as module or inside kernel. Let's consider those cases. + + Part 2 - When dmatest is built as a module... + +Example of usage: + % modprobe dmatest channel=dma0chan0 timeout=2000 iterations=1 run=1 + +...or: + % modprobe dmatest + % echo dma0chan0 > /sys/module/dmatest/parameters/channel + % echo 2000 > /sys/module/dmatest/parameters/timeout + % echo 1 > /sys/module/dmatest/parameters/iterations + % echo 1 > /sys/module/dmatest/parameters/run + +...or on the kernel command line: + + dmatest.channel=dma0chan0 dmatest.timeout=2000 dmatest.iterations=1 dmatest.run=1 + +Hint: available channel list could be extracted by running the following +command: + % ls -1 /sys/class/dma/ + +Once started a message like "dmatest: Started 1 threads using dma0chan0" is +emitted. After that only test failure messages are reported until the test +stops. + +Note that running a new test will not stop any in progress test. + +The following command returns the state of the test. + % cat /sys/module/dmatest/parameters/run + +To wait for test completion userpace can poll 'run' until it is false, or use +the wait parameter. Specifying 'wait=1' when loading the module causes module +initialization to pause until a test run has completed, while reading +/sys/module/dmatest/parameters/wait waits for any running test to complete +before returning. For example, the following scripts wait for 42 tests +to complete before exiting. Note that if 'iterations' is set to 'infinite' then +waiting is disabled. + +Example: + % modprobe dmatest run=1 iterations=42 wait=1 + % modprobe -r dmatest +...or: + % modprobe dmatest run=1 iterations=42 + % cat /sys/module/dmatest/parameters/wait + % modprobe -r dmatest + + Part 3 - When built-in in the kernel... + +The module parameters that is supplied to the kernel command line will be used +for the first performed test. After user gets a control, the test could be +re-run with the same or different parameters. For the details see the above +section "Part 2 - When dmatest is built as a module..." + +In both cases the module parameters are used as the actual values for the test +case. You always could check them at run-time by running + % grep -H . /sys/module/dmatest/parameters/* + + Part 4 - Gathering the test results + +Test results are printed to the kernel log buffer with the format: + +"dmatest: result : : '' with src_off= dst_off= len= ()" + +Example of output: + % dmesg | tail -n 1 + dmatest: result dma0chan0-copy0: #1: No errors with src_off=0x7bf dst_off=0x8ad len=0x3fea (0) + +The message format is unified across the different types of errors. A number in +the parens represents additional information, e.g. error code, error counter, +or status. A test thread also emits a summary line at completion listing the +number of tests executed, number that failed, and a result code. + +Example: + % dmesg | tail -n 1 + dmatest: dma0chan0-copy0: summary 1 test, 0 failures 1000 iops 100000 KB/s (0) + +The details of a data miscompare error are also emitted, but do not follow the +above format. diff --git a/Documentation/dmatest.txt b/Documentation/dmatest.txt deleted file mode 100644 index dd77a81bdb80..000000000000 --- a/Documentation/dmatest.txt +++ /dev/null @@ -1,92 +0,0 @@ - DMA Test Guide - ============== - - Andy Shevchenko - -This small document introduces how to test DMA drivers using dmatest module. - - Part 1 - How to build the test module - -The menuconfig contains an option that could be found by following path: - Device Drivers -> DMA Engine support -> DMA Test client - -In the configuration file the option called CONFIG_DMATEST. The dmatest could -be built as module or inside kernel. Let's consider those cases. - - Part 2 - When dmatest is built as a module... - -Example of usage: - % modprobe dmatest channel=dma0chan0 timeout=2000 iterations=1 run=1 - -...or: - % modprobe dmatest - % echo dma0chan0 > /sys/module/dmatest/parameters/channel - % echo 2000 > /sys/module/dmatest/parameters/timeout - % echo 1 > /sys/module/dmatest/parameters/iterations - % echo 1 > /sys/module/dmatest/parameters/run - -...or on the kernel command line: - - dmatest.channel=dma0chan0 dmatest.timeout=2000 dmatest.iterations=1 dmatest.run=1 - -Hint: available channel list could be extracted by running the following -command: - % ls -1 /sys/class/dma/ - -Once started a message like "dmatest: Started 1 threads using dma0chan0" is -emitted. After that only test failure messages are reported until the test -stops. - -Note that running a new test will not stop any in progress test. - -The following command returns the state of the test. - % cat /sys/module/dmatest/parameters/run - -To wait for test completion userpace can poll 'run' until it is false, or use -the wait parameter. Specifying 'wait=1' when loading the module causes module -initialization to pause until a test run has completed, while reading -/sys/module/dmatest/parameters/wait waits for any running test to complete -before returning. For example, the following scripts wait for 42 tests -to complete before exiting. Note that if 'iterations' is set to 'infinite' then -waiting is disabled. - -Example: - % modprobe dmatest run=1 iterations=42 wait=1 - % modprobe -r dmatest -...or: - % modprobe dmatest run=1 iterations=42 - % cat /sys/module/dmatest/parameters/wait - % modprobe -r dmatest - - Part 3 - When built-in in the kernel... - -The module parameters that is supplied to the kernel command line will be used -for the first performed test. After user gets a control, the test could be -re-run with the same or different parameters. For the details see the above -section "Part 2 - When dmatest is built as a module..." - -In both cases the module parameters are used as the actual values for the test -case. You always could check them at run-time by running - % grep -H . /sys/module/dmatest/parameters/* - - Part 4 - Gathering the test results - -Test results are printed to the kernel log buffer with the format: - -"dmatest: result : : '' with src_off= dst_off= len= ()" - -Example of output: - % dmesg | tail -n 1 - dmatest: result dma0chan0-copy0: #1: No errors with src_off=0x7bf dst_off=0x8ad len=0x3fea (0) - -The message format is unified across the different types of errors. A number in -the parens represents additional information, e.g. error code, error counter, -or status. A test thread also emits a summary line at completion listing the -number of tests executed, number that failed, and a result code. - -Example: - % dmesg | tail -n 1 - dmatest: dma0chan0-copy0: summary 1 test, 0 failures 1000 iops 100000 KB/s (0) - -The details of a data miscompare error are also emitted, but do not follow the -above format. -- cgit v1.2.3-59-g8ed1b From 747029a566e5d637ef4972afd2cb7202f7b7ca7c Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Thu, 6 Nov 2014 19:46:50 +0100 Subject: ipv4: add kernel parameter tcpmhash_entries This patch also adds a reference to ip-sysctl.txt where TCP metrics setup is described Signed-off-by: Fabian Frederick Signed-off-by: Jonathan Corbet --- Documentation/kernel-parameters.txt | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 4c81a860cc2b..e8066db54d3d 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -3412,6 +3412,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted. neutralize any effect of /proc/sys/kernel/sysrq. Useful for debugging. + tcpmhash_entries= [KNL,NET] + Set the number of tcp_metrics_hash slots. + Default value is 8192 or 16384 depending on total + ram pages. This is used to specify the TCP metrics + cache size. See Documentation/networking/ip-sysctl.txt + "tcp_no_metrics_save" section for more details. + tdfx= [HW,DRM] test_suspend= [SUSPEND][,N] -- cgit v1.2.3-59-g8ed1b From c0d7305cb3e5e77dba822706e21898314e893fb7 Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Fri, 7 Nov 2014 00:31:15 +0900 Subject: Documentation: vm: Add 1GB large page support information This patch adds 1GB large page support information in Documentation/vm/hugetlbpage.txt Reference: https://lkml.org/lkml/2014/10/31/366 Signed-off-by: Masanari Iida Reviewed-by: Luiz Capitulino Signed-off-by: Jonathan Corbet --- Documentation/vm/hugetlbpage.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/vm/hugetlbpage.txt b/Documentation/vm/hugetlbpage.txt index b64e0af9cc56..f2d3a100fe38 100644 --- a/Documentation/vm/hugetlbpage.txt +++ b/Documentation/vm/hugetlbpage.txt @@ -1,8 +1,8 @@ The intent of this file is to give a brief summary of hugetlbpage support in the Linux kernel. This support is built on top of multiple page size support -that is provided by most modern architectures. For example, i386 -architecture supports 4K and 4M (2M in PAE mode) page sizes, ia64 +that is provided by most modern architectures. For example, x86 CPUs normally +support 4K and 2M (1G if architecturally supported) page sizes, ia64 architecture supports multiple page sizes 4K, 8K, 64K, 256K, 1M, 4M, 16M, 256M and ppc64 supports 4K and 16M. A TLB is a cache of virtual-to-physical translations. Typically this is a very scarce resource on processor. -- cgit v1.2.3-59-g8ed1b From 63692df103e9c76b26c382ce8079283b7df9a99a Mon Sep 17 00:00:00 2001 From: Prarit Bhargava Date: Thu, 23 Oct 2014 14:22:12 -0400 Subject: PCI: Allow numa_node override via sysfs NUMA systems with ACPI normally describe the physical topology via _PXM methods. But many BIOSes don't implement _PXM, which leaves the kernel with no way to discover the device topology, which reduces performance because we can't put memory and processes close to the device. The NUMA node of a PCI device is already exported in the sysfs "numa_node" file. Make that file writable so users can workaround the lack of _PXM methods in the BIOS. For example: echo 3 > /sys/devices/pci0000:ff/0000:03:1f.3/numa_node sets the node for PCI device 0000:03:1f.3. Writing the file emits a FW_BUG warning to encourage users to request firmware updates. It also taints the kernel with TAINT_FIRMWARE_WORKAROUND because overriding the node incorrectly can cause performance issues. [bhelgaas: changelog, documentation text] Signed-off-by: Prarit Bhargava Signed-off-by: Bjorn Helgaas CC: Myron Stowe CC: Alexander Ducyk CC: Jiang Liu --- Documentation/ABI/testing/sysfs-bus-pci | 13 +++++++++++++ drivers/pci/pci-sysfs.c | 27 ++++++++++++++++++++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci index ee6c04036492..b3bc50f650ee 100644 --- a/Documentation/ABI/testing/sysfs-bus-pci +++ b/Documentation/ABI/testing/sysfs-bus-pci @@ -281,3 +281,16 @@ Description: opt-out of driver binding using a driver_override name such as "none". Only a single driver may be specified in the override, there is no support for parsing delimiters. + +What: /sys/bus/pci/devices/.../numa_node +Date: Oct 2014 +Contact: Prarit Bhargava +Description: + This file contains the NUMA node to which the PCI device is + attached, or -1 if the node is unknown. The initial value + comes from an ACPI _PXM method or a similar firmware + source. If that is missing or incorrect, this file can be + written to override the node. In that case, please report + a firmware bug to the system vendor. Writing to this file + taints the kernel with TAINT_FIRMWARE_WORKAROUND, which + reduces the supportability of your system. diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 92b6d9ab00e4..91e760f9655b 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -221,12 +221,37 @@ static ssize_t enabled_show(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR_RW(enabled); #ifdef CONFIG_NUMA +static ssize_t numa_node_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct pci_dev *pdev = to_pci_dev(dev); + int node, ret; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + ret = kstrtoint(buf, 0, &node); + if (ret) + return ret; + + if (!node_online(node)) + return -EINVAL; + + add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK); + dev_alert(&pdev->dev, FW_BUG "Overriding NUMA node to %d. Contact your vendor for updates.", + node); + + dev->numa_node = node; + return count; +} + static ssize_t numa_node_show(struct device *dev, struct device_attribute *attr, char *buf) { return sprintf(buf, "%d\n", dev->numa_node); } -static DEVICE_ATTR_RO(numa_node); +static DEVICE_ATTR_RW(numa_node); #endif static ssize_t dma_mask_bits_show(struct device *dev, -- cgit v1.2.3-59-g8ed1b From 21a9476a7ba847e413bf1c144d7c614532aed6dd Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 6 Nov 2014 11:12:03 +0100 Subject: usb: gadget: hid: add configfs support Make the hid function available for gadgets composed with configfs. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Felipe Balbi --- Documentation/ABI/testing/configfs-usb-gadget-hid | 11 ++ Documentation/usb/gadget_hid.txt | 7 ++ drivers/usb/gadget/Kconfig | 10 ++ drivers/usb/gadget/function/f_hid.c | 144 +++++++++++++++++++++- drivers/usb/gadget/function/u_hid.h | 7 ++ 5 files changed, 178 insertions(+), 1 deletion(-) create mode 100644 Documentation/ABI/testing/configfs-usb-gadget-hid (limited to 'Documentation') diff --git a/Documentation/ABI/testing/configfs-usb-gadget-hid b/Documentation/ABI/testing/configfs-usb-gadget-hid new file mode 100644 index 000000000000..f12e00e6baa3 --- /dev/null +++ b/Documentation/ABI/testing/configfs-usb-gadget-hid @@ -0,0 +1,11 @@ +What: /config/usb-gadget/gadget/functions/hid.name +Date: Nov 2014 +KernelVersion: 3.19 +Description: + The attributes: + + protocol - HID protocol to use + report_desc - blob corresponding to HID report descriptors + except the data passed through /dev/hidg + report_length - HID report length + subclass - HID device subclass to use diff --git a/Documentation/usb/gadget_hid.txt b/Documentation/usb/gadget_hid.txt index 12696c2e43fb..7a0fb8e16e27 100644 --- a/Documentation/usb/gadget_hid.txt +++ b/Documentation/usb/gadget_hid.txt @@ -74,6 +74,13 @@ static struct platform_device my_hid = { You can add as many HID functions as you want, only limited by the amount of interrupt endpoints your gadget driver supports. +Configuration with configfs + + Instead of adding fake platform devices and drivers in order to pass + some data to the kernel, if HID is a part of a gadget composed with + configfs the hidg_func_descriptor.report_desc is passed to the kernel + by writing the appropriate stream of bytes to a configfs attribute. + Send and receive HID reports HID reports can be sent/received using read/write on the diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index ea2d7706db6c..747ef53bda14 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -413,6 +413,16 @@ config USB_CONFIGFS_F_MIDI connections can then be made on the gadget system, using ALSA's aconnect utility etc. +config USB_CONFIGFS_F_HID + boolean "HID function" + depends on USB_CONFIGFS + select USB_F_HID + help + The HID function driver provides generic emulation of USB + Human Interface Devices (HID). + + For more information, see Documentation/usb/gadget_hid.txt. + source "drivers/usb/gadget/legacy/Kconfig" endchoice diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index dfdb4327ef3e..56ca3fc81555 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -690,6 +690,136 @@ static inline int hidg_get_minor(void) return ret; } +static inline struct f_hid_opts *to_f_hid_opts(struct config_item *item) +{ + return container_of(to_config_group(item), struct f_hid_opts, + func_inst.group); +} + +CONFIGFS_ATTR_STRUCT(f_hid_opts); +CONFIGFS_ATTR_OPS(f_hid_opts); + +static void hid_attr_release(struct config_item *item) +{ + struct f_hid_opts *opts = to_f_hid_opts(item); + + usb_put_function_instance(&opts->func_inst); +} + +static struct configfs_item_operations hidg_item_ops = { + .release = hid_attr_release, + .show_attribute = f_hid_opts_attr_show, + .store_attribute = f_hid_opts_attr_store, +}; + +#define F_HID_OPT(name, prec, limit) \ +static ssize_t f_hid_opts_##name##_show(struct f_hid_opts *opts, char *page)\ +{ \ + int result; \ + \ + mutex_lock(&opts->lock); \ + result = sprintf(page, "%d\n", opts->name); \ + mutex_unlock(&opts->lock); \ + \ + return result; \ +} \ + \ +static ssize_t f_hid_opts_##name##_store(struct f_hid_opts *opts, \ + const char *page, size_t len) \ +{ \ + int ret; \ + u##prec num; \ + \ + mutex_lock(&opts->lock); \ + if (opts->refcnt) { \ + ret = -EBUSY; \ + goto end; \ + } \ + \ + ret = kstrtou##prec(page, 0, &num); \ + if (ret) \ + goto end; \ + \ + if (num > limit) { \ + ret = -EINVAL; \ + goto end; \ + } \ + opts->name = num; \ + ret = len; \ + \ +end: \ + mutex_unlock(&opts->lock); \ + return ret; \ +} \ + \ +static struct f_hid_opts_attribute f_hid_opts_##name = \ + __CONFIGFS_ATTR(name, S_IRUGO | S_IWUSR, f_hid_opts_##name##_show,\ + f_hid_opts_##name##_store) + +F_HID_OPT(subclass, 8, 255); +F_HID_OPT(protocol, 8, 255); +F_HID_OPT(report_length, 16, 65536); + +static ssize_t f_hid_opts_report_desc_show(struct f_hid_opts *opts, char *page) +{ + int result; + + mutex_lock(&opts->lock); + result = opts->report_desc_length; + memcpy(page, opts->report_desc, opts->report_desc_length); + mutex_unlock(&opts->lock); + + return result; +} + +static ssize_t f_hid_opts_report_desc_store(struct f_hid_opts *opts, + const char *page, size_t len) +{ + int ret = -EBUSY; + char *d; + + mutex_lock(&opts->lock); + + if (opts->refcnt) + goto end; + if (len > PAGE_SIZE) { + ret = -ENOSPC; + goto end; + } + d = kmemdup(page, len, GFP_KERNEL); + if (!d) { + ret = -ENOMEM; + goto end; + } + kfree(opts->report_desc); + opts->report_desc = d; + opts->report_desc_length = len; + opts->report_desc_alloc = true; + ret = len; +end: + mutex_unlock(&opts->lock); + return ret; +} + +static struct f_hid_opts_attribute f_hid_opts_report_desc = + __CONFIGFS_ATTR(report_desc, S_IRUGO | S_IWUSR, + f_hid_opts_report_desc_show, + f_hid_opts_report_desc_store); + +static struct configfs_attribute *hid_attrs[] = { + &f_hid_opts_subclass.attr, + &f_hid_opts_protocol.attr, + &f_hid_opts_report_length.attr, + &f_hid_opts_report_desc.attr, + NULL, +}; + +static struct config_item_type hid_func_type = { + .ct_item_ops = &hidg_item_ops, + .ct_attrs = hid_attrs, + .ct_owner = THIS_MODULE, +}; + static inline void hidg_put_minor(int minor) { ida_simple_remove(&hidg_ida, minor); @@ -724,7 +854,7 @@ static struct usb_function_instance *hidg_alloc_inst(void) opts = kzalloc(sizeof(*opts), GFP_KERNEL); if (!opts) return ERR_PTR(-ENOMEM); - + mutex_init(&opts->lock); opts->func_inst.free_func_inst = hidg_free_inst; ret = &opts->func_inst; @@ -746,6 +876,7 @@ static struct usb_function_instance *hidg_alloc_inst(void) if (idr_is_empty(&hidg_ida.idr)) ghid_cleanup(); } + config_group_init_type_name(&opts->func_inst.group, "", &hid_func_type); unlock: mutex_unlock(&hidg_ida_lock); @@ -755,10 +886,15 @@ unlock: static void hidg_free(struct usb_function *f) { struct f_hidg *hidg; + struct f_hid_opts *opts; hidg = func_to_hidg(f); + opts = container_of(f->fi, struct f_hid_opts, func_inst); kfree(hidg->report_desc); kfree(hidg); + mutex_lock(&opts->lock); + --opts->refcnt; + mutex_unlock(&opts->lock); } static void hidg_unbind(struct usb_configuration *c, struct usb_function *f) @@ -789,6 +925,9 @@ struct usb_function *hidg_alloc(struct usb_function_instance *fi) opts = container_of(fi, struct f_hid_opts, func_inst); + mutex_lock(&opts->lock); + ++opts->refcnt; + hidg->minor = opts->minor; hidg->bInterfaceSubClass = opts->subclass; hidg->bInterfaceProtocol = opts->protocol; @@ -800,10 +939,13 @@ struct usb_function *hidg_alloc(struct usb_function_instance *fi) GFP_KERNEL); if (!hidg->report_desc) { kfree(hidg); + mutex_unlock(&opts->lock); return ERR_PTR(-ENOMEM); } } + mutex_unlock(&opts->lock); + hidg->func.name = "hid"; hidg->func.bind = hidg_bind; hidg->func.unbind = hidg_unbind; diff --git a/drivers/usb/gadget/function/u_hid.h b/drivers/usb/gadget/function/u_hid.h index 3edfc9567ab7..aaa0e368a159 100644 --- a/drivers/usb/gadget/function/u_hid.h +++ b/drivers/usb/gadget/function/u_hid.h @@ -27,6 +27,13 @@ struct f_hid_opts { unsigned short report_desc_length; unsigned char *report_desc; bool report_desc_alloc; + + /* + * Protect the data form concurrent access by read/write + * and create symlink/remove symlink. + */ + struct mutex lock; + int refcnt; }; int ghid_setup(struct usb_gadget *g, int count); -- cgit v1.2.3-59-g8ed1b From a7ae7f8243b15cd65b5811de031eb4f8413b3e6f Mon Sep 17 00:00:00 2001 From: John Crispin Date: Thu, 16 Oct 2014 22:43:27 +0200 Subject: serial: of_serial: add "ralink,rt2880-uart" to the binding documentation Signed-off-by: John Crispin Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/of-serial.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/serial/of-serial.txt b/Documentation/devicetree/bindings/serial/of-serial.txt index 8c4fd0332028..b52b98234b9b 100644 --- a/Documentation/devicetree/bindings/serial/of-serial.txt +++ b/Documentation/devicetree/bindings/serial/of-serial.txt @@ -10,6 +10,7 @@ Required properties: - "ns16850" - "nvidia,tegra20-uart" - "nxp,lpc3220-uart" + - "ralink,rt2880-uart" - "ibm,qpace-nwp-serial" - "altr,16550-FIFO32" - "altr,16550-FIFO64" -- cgit v1.2.3-59-g8ed1b From 7c573d7ea6c5a866cf89b7bf45fc5ab82d289cf1 Mon Sep 17 00:00:00 2001 From: Janusz Uzycki Date: Fri, 10 Oct 2014 18:53:25 +0200 Subject: serial: mxs-auart: use mctrl_gpio helpers for handling modem signals Dedicated CTS and RTS pins are unusable together with a lot of other peripherals because they share the same line. Pinctrl is limited. Moreover, the AUART controller doesn't handle DTR/DSR/DCD/RI signals, so we have to control them via GPIO. This patch permits to use GPIOs to control the CTS/RTS/DTR/DSR/DCD/RI signals. Signed-off-by: Janusz Uzycki Reviewed-by: Richard Genoud Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/serial/fsl-mxs-auart.txt | 10 ++++- drivers/tty/serial/Kconfig | 1 + drivers/tty/serial/mxs-auart.c | 50 +++++++++++++++++++--- 3 files changed, 55 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/serial/fsl-mxs-auart.txt b/Documentation/devicetree/bindings/serial/fsl-mxs-auart.txt index 59a40f18d551..7c408c87e613 100644 --- a/Documentation/devicetree/bindings/serial/fsl-mxs-auart.txt +++ b/Documentation/devicetree/bindings/serial/fsl-mxs-auart.txt @@ -11,8 +11,13 @@ Required properties: - dma-names: "rx" for RX channel, "tx" for TX channel. Optional properties: -- fsl,uart-has-rtscts : Indicate the UART has RTS and CTS lines, +- fsl,uart-has-rtscts : Indicate the UART has RTS and CTS lines + for hardware flow control, it also means you enable the DMA support for this UART. +- {rts,cts,dtr,dsr,rng,dcd}-gpios: specify a GPIO for RTS/CTS/DTR/DSR/RI/DCD + line respectively. It will use specified PIO instead of the peripheral + function pin for the USART feature. + If unsure, don't specify this property. Example: auart0: serial@8006a000 { @@ -21,6 +26,9 @@ auart0: serial@8006a000 { interrupts = <112>; dmas = <&dma_apbx 8>, <&dma_apbx 9>; dma-names = "rx", "tx"; + cts-gpios = <&gpio1 15 GPIO_ACTIVE_LOW>; + dsr-gpios = <&gpio1 16 GPIO_ACTIVE_LOW>; + dcd-gpios = <&gpio1 17 GPIO_ACTIVE_LOW>; }; Note: Each auart port should have an alias correctly numbered in "aliases" diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 649b784081c7..4e6a0babf6b9 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1408,6 +1408,7 @@ config SERIAL_MXS_AUART depends on ARCH_MXS tristate "MXS AUART support" select SERIAL_CORE + select SERIAL_MCTRL_GPIO if GPIOLIB help This driver supports the MXS Application UART (AUART) port. diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index 907c3e521906..5922cb435a87 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -42,6 +42,9 @@ #include +#include +#include "serial_mctrl_gpio.h" + #define MXS_AUART_PORTS 5 #define MXS_AUART_FIFO_SIZE 16 @@ -158,6 +161,8 @@ struct mxs_auart_port { struct scatterlist rx_sgl; struct dma_chan *rx_dma_chan; void *rx_dma_buf; + + struct mctrl_gpios *gpios; }; static struct platform_device_id mxs_auart_devtype[] = { @@ -405,6 +410,8 @@ static void mxs_auart_release_port(struct uart_port *u) static void mxs_auart_set_mctrl(struct uart_port *u, unsigned mctrl) { + struct mxs_auart_port *s = to_auart_port(u); + u32 ctrl = readl(u->membase + AUART_CTRL2); ctrl &= ~(AUART_CTRL2_RTSEN | AUART_CTRL2_RTS); @@ -416,17 +423,20 @@ static void mxs_auart_set_mctrl(struct uart_port *u, unsigned mctrl) } writel(ctrl, u->membase + AUART_CTRL2); + + mctrl_gpio_set(s->gpios, mctrl); } static u32 mxs_auart_get_mctrl(struct uart_port *u) { + struct mxs_auart_port *s = to_auart_port(u); u32 stat = readl(u->membase + AUART_STAT); u32 mctrl = 0; if (stat & AUART_STAT_CTS) mctrl |= TIOCM_CTS; - return mctrl; + return mctrl_gpio_get(s->gpios, &mctrl); } static int mxs_auart_dma_prep_rx(struct mxs_auart_port *s); @@ -554,6 +564,10 @@ err_out: } +#define RTS_AT_AUART() IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(s->gpios, \ + UART_GPIO_RTS)) +#define CTS_AT_AUART() IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(s->gpios, \ + UART_GPIO_CTS)) static void mxs_auart_settermios(struct uart_port *u, struct ktermios *termios, struct ktermios *old) @@ -630,6 +644,7 @@ static void mxs_auart_settermios(struct uart_port *u, ctrl |= AUART_LINECTRL_STP2; /* figure out the hardware flow control settings */ + ctrl2 &= ~(AUART_CTRL2_CTSEN | AUART_CTRL2_RTSEN); if (cflag & CRTSCTS) { /* * The DMA has a bug(see errata:2836) in mx23. @@ -644,9 +659,11 @@ static void mxs_auart_settermios(struct uart_port *u, ctrl2 |= AUART_CTRL2_TXDMAE | AUART_CTRL2_RXDMAE | AUART_CTRL2_DMAONERR; } - ctrl2 |= AUART_CTRL2_CTSEN | AUART_CTRL2_RTSEN; - } else { - ctrl2 &= ~(AUART_CTRL2_CTSEN | AUART_CTRL2_RTSEN); + /* Even if RTS is GPIO line RTSEN can be enabled because + * the pinctrl configuration decides about RTS pin function */ + ctrl2 |= AUART_CTRL2_RTSEN; + if (CTS_AT_AUART()) + ctrl2 |= AUART_CTRL2_CTSEN; } /* set baud rate */ @@ -690,7 +707,9 @@ static irqreturn_t mxs_auart_irq_handle(int irq, void *context) s->port.membase + AUART_INTR_CLR); if (istat & AUART_INTR_CTSMIS) { - uart_handle_cts_change(&s->port, stat & AUART_STAT_CTS); + if (CTS_AT_AUART()) + uart_handle_cts_change(&s->port, + stat & AUART_STAT_CTS); writel(AUART_INTR_CTSMIS, s->port.membase + AUART_INTR_CLR); istat &= ~AUART_INTR_CTSMIS; @@ -1014,6 +1033,23 @@ static int serial_mxs_probe_dt(struct mxs_auart_port *s, return 0; } +static bool mxs_auart_init_gpios(struct mxs_auart_port *s, struct device *dev) +{ + s->gpios = mctrl_gpio_init(dev, 0); + if (IS_ERR_OR_NULL(s->gpios)) + return false; + + /* Block (enabled before) DMA option if RTS or CTS is GPIO line */ + if (!RTS_AT_AUART() || !CTS_AT_AUART()) { + if (test_bit(MXS_AUART_RTSCTS, &s->flags)) + dev_warn(dev, + "DMA and flow control via gpio may cause some problems. DMA disabled!\n"); + clear_bit(MXS_AUART_RTSCTS, &s->flags); + } + + return true; +} + static int mxs_auart_probe(struct platform_device *pdev) { const struct of_device_id *of_id = @@ -1069,6 +1105,10 @@ static int mxs_auart_probe(struct platform_device *pdev) platform_set_drvdata(pdev, s); + if (!mxs_auart_init_gpios(s, &pdev->dev)) + dev_err(&pdev->dev, + "Failed to initialize GPIOs. The serial port may not work as expected\n"); + auart_port[s->port.line] = s; mxs_auart_reset(&s->port); -- cgit v1.2.3-59-g8ed1b From e1a184eea9bcab00faa5943292d049bc30f8cd09 Mon Sep 17 00:00:00 2001 From: Kevin Cernekee Date: Tue, 21 Oct 2014 15:23:01 -0700 Subject: Documentation: DT: Add entries for bcm63xx UART This squashes a checkpatch warning on my new bcm3384 dts submission. Signed-off-by: Kevin Cernekee Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/serial/bcm63xx-uart.txt | 30 ++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 Documentation/devicetree/bindings/serial/bcm63xx-uart.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/serial/bcm63xx-uart.txt b/Documentation/devicetree/bindings/serial/bcm63xx-uart.txt new file mode 100644 index 000000000000..5c52e5eef16d --- /dev/null +++ b/Documentation/devicetree/bindings/serial/bcm63xx-uart.txt @@ -0,0 +1,30 @@ +* BCM63xx UART + +Required properties: + +- compatible: "brcm,bcm6345-uart" + +- reg: The base address of the UART register bank. + +- interrupts: A single interrupt specifier. + +- clocks: Clock driving the hardware; used to figure out the baud rate + divisor. + +Example: + + uart0: serial@14e00520 { + compatible = "brcm,bcm6345-uart"; + reg = <0x14e00520 0x18>; + interrupt-parent = <&periph_intc>; + interrupts = <2>; + clocks = <&periph_clk>; + }; + + clocks { + periph_clk: periph_clk@0 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <54000000>; + }; + }; -- cgit v1.2.3-59-g8ed1b From 365dc1633521a32d55d839f56b41bb9a531d957a Mon Sep 17 00:00:00 2001 From: Dominik Dingel Date: Fri, 31 Oct 2014 16:44:10 +0100 Subject: KVM: fix vm device attribute documentation Documentation uses incorrect attribute names for some vm device attributes: fix this. Signed-off-by: Dominik Dingel Signed-off-by: Christian Borntraeger --- Documentation/virtual/kvm/devices/vm.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/virtual/kvm/devices/vm.txt b/Documentation/virtual/kvm/devices/vm.txt index 0d16f96c0eac..d426fc87fe93 100644 --- a/Documentation/virtual/kvm/devices/vm.txt +++ b/Documentation/virtual/kvm/devices/vm.txt @@ -12,14 +12,14 @@ specific. 1. GROUP: KVM_S390_VM_MEM_CTRL Architectures: s390 -1.1. ATTRIBUTE: KVM_S390_VM_MEM_CTRL +1.1. ATTRIBUTE: KVM_S390_VM_MEM_ENABLE_CMMA Parameters: none -Returns: -EBUSY if already a vcpus is defined, otherwise 0 +Returns: -EBUSY if a vcpu is already defined, otherwise 0 -Enables CMMA for the virtual machine +Enables Collaborative Memory Management Assist (CMMA) for the virtual machine. -1.2. ATTRIBUTE: KVM_S390_VM_CLR_CMMA -Parameteres: none +1.2. ATTRIBUTE: KVM_S390_VM_MEM_CLR_CMMA +Parameters: none Returns: 0 Clear the CMMA status for all guest pages, so any pages the guest marked -- cgit v1.2.3-59-g8ed1b From a5a56871f804edac93a53b5e871c0e9818fb9033 Mon Sep 17 00:00:00 2001 From: Padmavathi Venna Date: Fri, 7 Nov 2014 12:24:40 +0530 Subject: ASoC: samsung: add support for exynos7 I2S controller Exynos7 I2S controller has no internal dma, supports more no. of root clock sampling frequencies and has more no.of Rx fifos to support 7.1CH recording in TDM mode. Due to more no. of root clock frequency values some of the bit offsets got shifted up by one. Also I2S1 on previous Samsung platforms uses v3 dai type but on Exynos7 it is upgraded to v5 with slightly modified register offsets for supporting more no.of RFS values. Due to the above changes, the driver has to be modified to handle all versions of I2S controller. For this I introduced a new structure to hold modified bit offsets and masks which is passed as dai data. Signed-off-by: Padmavathi Venna Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/samsung-i2s.txt | 15 +- sound/soc/samsung/Kconfig | 2 +- sound/soc/samsung/i2s-regs.h | 10 +- sound/soc/samsung/i2s.c | 218 +++++++++++++++------ 4 files changed, 174 insertions(+), 71 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/samsung-i2s.txt b/Documentation/devicetree/bindings/sound/samsung-i2s.txt index 7386d444ada1..d188296bb6ec 100644 --- a/Documentation/devicetree/bindings/sound/samsung-i2s.txt +++ b/Documentation/devicetree/bindings/sound/samsung-i2s.txt @@ -6,10 +6,17 @@ Required SoC Specific Properties: - samsung,s3c6410-i2s: for 8/16/24bit stereo I2S. - samsung,s5pv210-i2s: for 8/16/24bit multichannel(5.1) I2S with secondary fifo, s/w reset control and internal mux for root clk src. - - samsung,exynos5420-i2s: for 8/16/24bit multichannel(7.1) I2S with - secondary fifo, s/w reset control, internal mux for root clk src and - TDM support. TDM (Time division multiplexing) is to allow transfer of - multiple channel audio data on single data line. + - samsung,exynos5420-i2s: for 8/16/24bit multichannel(5.1) I2S for + playback, sterio channel capture, secondary fifo using internal + or external dma, s/w reset control, internal mux for root clk src + and 7.1 channel TDM support for playback. TDM (Time division multiplexing) + is to allow transfer of multiple channel audio data on single data line. + - samsung,exynos7-i2s: with all the available features of exynos5 i2s, + exynos7 I2S has 7.1 channel TDM support for capture, secondary fifo + with only external dma and more no.of root clk sampling frequencies. + - samsung,exynos7-i2s1: I2S1 on previous samsung platforms supports + stereo channels. exynos7 i2s1 upgraded to 5.1 multichannel with + slightly modified bit offsets. - reg: physical base address of the controller and length of memory mapped region. diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index 55a38697443d..e0e737faadd9 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig @@ -1,6 +1,6 @@ config SND_SOC_SAMSUNG tristate "ASoC support for Samsung" - depends on PLAT_SAMSUNG + depends on (PLAT_SAMSUNG || ARCH_EXYNOS) depends on S3C64XX_PL080 || !ARCH_S3C64XX depends on S3C24XX_DMAC || !ARCH_S3C24XX select SND_SOC_GENERIC_DMAENGINE_PCM diff --git a/sound/soc/samsung/i2s-regs.h b/sound/soc/samsung/i2s-regs.h index 821a50231002..9170c311d66e 100644 --- a/sound/soc/samsung/i2s-regs.h +++ b/sound/soc/samsung/i2s-regs.h @@ -33,8 +33,9 @@ #define I2SLVL3ADDR 0x3c #define I2SSTR1 0x40 #define I2SVER 0x44 -#define I2SFIC2 0x48 +#define I2SFIC1 0x48 #define I2STDM 0x4c +#define I2SFSTA 0x50 #define CON_RSTCLR (1 << 31) #define CON_FRXOFSTATUS (1 << 26) @@ -93,8 +94,6 @@ #define MOD_BLC_24BIT (2 << 13) #define MOD_BLC_MASK (3 << 13) -#define MOD_IMS_SYSMUX (1 << 10) -#define MOD_SLAVE (1 << 11) #define MOD_TXONLY (0 << 8) #define MOD_RXONLY (1 << 8) #define MOD_TXRX (2 << 8) @@ -132,7 +131,10 @@ #define EXYNOS5420_MOD_BCLK_256FS 8 #define EXYNOS5420_MOD_BCLK_MASK 0xf -#define MOD_CDCLKCON (1 << 12) +#define EXYNOS7_MOD_RCLK_64FS 4 +#define EXYNOS7_MOD_RCLK_128FS 5 +#define EXYNOS7_MOD_RCLK_96FS 6 +#define EXYNOS7_MOD_RCLK_192FS 7 #define PSR_PSREN (1 << 15) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 38b9a524cc9f..947352d00ddf 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -36,9 +36,24 @@ enum samsung_dai_type { TYPE_SEC, }; +struct samsung_i2s_variant_regs { + unsigned int bfs_off; + unsigned int rfs_off; + unsigned int sdf_off; + unsigned int txr_off; + unsigned int rclksrc_off; + unsigned int mss_off; + unsigned int cdclkcon_off; + unsigned int lrp_off; + unsigned int bfs_mask; + unsigned int rfs_mask; + unsigned int ftx0cnt_off; +}; + struct samsung_i2s_dai_data { int dai_type; u32 quirks; + const struct samsung_i2s_variant_regs *i2s_variant_regs; }; struct i2s_dai { @@ -81,6 +96,7 @@ struct i2s_dai { u32 suspend_i2scon; u32 suspend_i2spsr; unsigned long gpios[7]; /* i2s gpio line numbers */ + const struct samsung_i2s_variant_regs *variant_regs; }; /* Lock for cross i/f checks */ @@ -95,7 +111,8 @@ static inline bool is_secondary(struct i2s_dai *i2s) /* If operating in SoC-Slave mode */ static inline bool is_slave(struct i2s_dai *i2s) { - return (readl(i2s->addr + I2SMOD) & MOD_SLAVE) ? true : false; + u32 mod = readl(i2s->addr + I2SMOD); + return (mod & (1 << i2s->variant_regs->mss_off)) ? true : false; } /* If this interface of the controller is transmitting data */ @@ -200,14 +217,14 @@ static inline bool is_manager(struct i2s_dai *i2s) static inline unsigned get_rfs(struct i2s_dai *i2s) { u32 rfs; - - if (i2s->quirks & QUIRK_SUPPORTS_TDM) - rfs = readl(i2s->addr + I2SMOD) >> EXYNOS5420_MOD_RCLK_SHIFT; - else - rfs = (readl(i2s->addr + I2SMOD) >> MOD_RCLK_SHIFT); - rfs &= MOD_RCLK_MASK; + rfs = readl(i2s->addr + I2SMOD) >> i2s->variant_regs->rfs_off; + rfs &= i2s->variant_regs->rfs_mask; switch (rfs) { + case 7: return 192; + case 6: return 96; + case 5: return 128; + case 4: return 64; case 3: return 768; case 2: return 384; case 1: return 512; @@ -219,15 +236,23 @@ static inline unsigned get_rfs(struct i2s_dai *i2s) static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs) { u32 mod = readl(i2s->addr + I2SMOD); - int rfs_shift; + int rfs_shift = i2s->variant_regs->rfs_off; - if (i2s->quirks & QUIRK_SUPPORTS_TDM) - rfs_shift = EXYNOS5420_MOD_RCLK_SHIFT; - else - rfs_shift = MOD_RCLK_SHIFT; - mod &= ~(MOD_RCLK_MASK << rfs_shift); + mod &= ~(i2s->variant_regs->rfs_mask << rfs_shift); switch (rfs) { + case 192: + mod |= (EXYNOS7_MOD_RCLK_192FS << rfs_shift); + break; + case 96: + mod |= (EXYNOS7_MOD_RCLK_96FS << rfs_shift); + break; + case 128: + mod |= (EXYNOS7_MOD_RCLK_128FS << rfs_shift); + break; + case 64: + mod |= (EXYNOS7_MOD_RCLK_64FS << rfs_shift); + break; case 768: mod |= (MOD_RCLK_768FS << rfs_shift); break; @@ -249,14 +274,8 @@ static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs) static inline unsigned get_bfs(struct i2s_dai *i2s) { u32 bfs; - - if (i2s->quirks & QUIRK_SUPPORTS_TDM) { - bfs = readl(i2s->addr + I2SMOD) >> EXYNOS5420_MOD_BCLK_SHIFT; - bfs &= EXYNOS5420_MOD_BCLK_MASK; - } else { - bfs = readl(i2s->addr + I2SMOD) >> MOD_BCLK_SHIFT; - bfs &= MOD_BCLK_MASK; - } + bfs = readl(i2s->addr + I2SMOD) >> i2s->variant_regs->bfs_off; + bfs &= i2s->variant_regs->bfs_mask; switch (bfs) { case 8: return 256; @@ -275,16 +294,8 @@ static inline unsigned get_bfs(struct i2s_dai *i2s) static inline void set_bfs(struct i2s_dai *i2s, unsigned bfs) { u32 mod = readl(i2s->addr + I2SMOD); - int bfs_shift; int tdm = i2s->quirks & QUIRK_SUPPORTS_TDM; - - if (i2s->quirks & QUIRK_SUPPORTS_TDM) { - bfs_shift = EXYNOS5420_MOD_BCLK_SHIFT; - mod &= ~(EXYNOS5420_MOD_BCLK_MASK << bfs_shift); - } else { - bfs_shift = MOD_BCLK_SHIFT; - mod &= ~(MOD_BCLK_MASK << bfs_shift); - } + int bfs_shift = i2s->variant_regs->bfs_off; /* Non-TDM I2S controllers do not support BCLK > 48 * FS */ if (!tdm && bfs > 48) { @@ -292,6 +303,8 @@ static inline void set_bfs(struct i2s_dai *i2s, unsigned bfs) return; } + mod &= ~(i2s->variant_regs->bfs_mask << bfs_shift); + switch (bfs) { case 48: mod |= (MOD_BCLK_48FS << bfs_shift); @@ -346,8 +359,9 @@ static inline int get_blc(struct i2s_dai *i2s) static void i2s_txctrl(struct i2s_dai *i2s, int on) { void __iomem *addr = i2s->addr; + int txr_off = i2s->variant_regs->txr_off; u32 con = readl(addr + I2SCON); - u32 mod = readl(addr + I2SMOD) & ~MOD_MASK; + u32 mod = readl(addr + I2SMOD) & ~(3 << txr_off); if (on) { con |= CON_ACTIVE; @@ -362,9 +376,9 @@ static void i2s_txctrl(struct i2s_dai *i2s, int on) } if (any_rx_active(i2s)) - mod |= MOD_TXRX; + mod |= 2 << txr_off; else - mod |= MOD_TXONLY; + mod |= 0 << txr_off; } else { if (is_secondary(i2s)) { con |= CON_TXSDMA_PAUSE; @@ -382,7 +396,7 @@ static void i2s_txctrl(struct i2s_dai *i2s, int on) con |= CON_TXCH_PAUSE; if (any_rx_active(i2s)) - mod |= MOD_RXONLY; + mod |= 1 << txr_off; else con &= ~CON_ACTIVE; } @@ -395,23 +409,24 @@ static void i2s_txctrl(struct i2s_dai *i2s, int on) static void i2s_rxctrl(struct i2s_dai *i2s, int on) { void __iomem *addr = i2s->addr; + int txr_off = i2s->variant_regs->txr_off; u32 con = readl(addr + I2SCON); - u32 mod = readl(addr + I2SMOD) & ~MOD_MASK; + u32 mod = readl(addr + I2SMOD) & ~(3 << txr_off); if (on) { con |= CON_RXDMA_ACTIVE | CON_ACTIVE; con &= ~(CON_RXDMA_PAUSE | CON_RXCH_PAUSE); if (any_tx_active(i2s)) - mod |= MOD_TXRX; + mod |= 2 << txr_off; else - mod |= MOD_RXONLY; + mod |= 1 << txr_off; } else { con |= CON_RXDMA_PAUSE | CON_RXCH_PAUSE; con &= ~CON_RXDMA_ACTIVE; if (any_tx_active(i2s)) - mod |= MOD_TXONLY; + mod |= 0 << txr_off; else con &= ~CON_ACTIVE; } @@ -451,6 +466,9 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, struct i2s_dai *i2s = to_info(dai); struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai; u32 mod = readl(i2s->addr + I2SMOD); + const struct samsung_i2s_variant_regs *i2s_regs = i2s->variant_regs; + unsigned int cdcon_mask = 1 << i2s_regs->cdclkcon_off; + unsigned int rsrc_mask = 1 << i2s_regs->rclksrc_off; switch (clk_id) { case SAMSUNG_I2S_OPCLK: @@ -465,18 +483,18 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, if ((rfs && other && other->rfs && (other->rfs != rfs)) || (any_active(i2s) && (((dir == SND_SOC_CLOCK_IN) - && !(mod & MOD_CDCLKCON)) || + && !(mod & cdcon_mask)) || ((dir == SND_SOC_CLOCK_OUT) - && (mod & MOD_CDCLKCON))))) { + && (mod & cdcon_mask))))) { dev_err(&i2s->pdev->dev, "%s:%d Other DAI busy\n", __func__, __LINE__); return -EAGAIN; } if (dir == SND_SOC_CLOCK_IN) - mod |= MOD_CDCLKCON; + mod |= 1 << i2s_regs->cdclkcon_off; else - mod &= ~MOD_CDCLKCON; + mod &= 0 << i2s_regs->cdclkcon_off; i2s->rfs = rfs; break; @@ -491,8 +509,8 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, if (!any_active(i2s)) { if (i2s->op_clk && !IS_ERR(i2s->op_clk)) { - if ((clk_id && !(mod & MOD_IMS_SYSMUX)) || - (!clk_id && (mod & MOD_IMS_SYSMUX))) { + if ((clk_id && !(mod & rsrc_mask)) || + (!clk_id && (mod & rsrc_mask))) { clk_disable_unprepare(i2s->op_clk); clk_put(i2s->op_clk); } else { @@ -520,8 +538,8 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, other->op_clk = i2s->op_clk; other->rclk_srcrate = i2s->rclk_srcrate; } - } else if ((!clk_id && (mod & MOD_IMS_SYSMUX)) - || (clk_id && !(mod & MOD_IMS_SYSMUX))) { + } else if ((!clk_id && (mod & rsrc_mask)) + || (clk_id && !(mod & rsrc_mask))) { dev_err(&i2s->pdev->dev, "%s:%d Other DAI busy\n", __func__, __LINE__); return -EAGAIN; @@ -533,10 +551,9 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, } if (clk_id == 0) - mod &= ~MOD_IMS_SYSMUX; + mod &= 0 << i2s_regs->rclksrc_off; else - mod |= MOD_IMS_SYSMUX; - break; + mod |= 1 << i2s_regs->rclksrc_off; default: dev_err(&i2s->pdev->dev, "We don't serve that!\n"); @@ -553,16 +570,12 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, { struct i2s_dai *i2s = to_info(dai); u32 mod = readl(i2s->addr + I2SMOD); - int lrp_shift, sdf_shift, sdf_mask, lrp_rlow; + int lrp_shift, sdf_shift, sdf_mask, lrp_rlow, mod_slave; u32 tmp = 0; - if (i2s->quirks & QUIRK_SUPPORTS_TDM) { - lrp_shift = EXYNOS5420_MOD_LRP_SHIFT; - sdf_shift = EXYNOS5420_MOD_SDF_SHIFT; - } else { - lrp_shift = MOD_LRP_SHIFT; - sdf_shift = MOD_SDF_SHIFT; - } + lrp_shift = i2s->variant_regs->lrp_off; + sdf_shift = i2s->variant_regs->sdf_off; + mod_slave = 1 << i2s->variant_regs->mss_off; sdf_mask = MOD_SDF_MASK << sdf_shift; lrp_rlow = MOD_LR_RLOW << lrp_shift; @@ -605,7 +618,7 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBM_CFM: - tmp |= MOD_SLAVE; + tmp |= mod_slave; break; case SND_SOC_DAIFMT_CBS_CFS: /* Set default source clock in Master mode */ @@ -623,13 +636,13 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, * channel. */ if (any_active(i2s) && - ((mod & (sdf_mask | lrp_rlow | MOD_SLAVE)) != tmp)) { + ((mod & (sdf_mask | lrp_rlow | mod_slave)) != tmp)) { dev_err(&i2s->pdev->dev, "%s:%d Other DAI busy\n", __func__, __LINE__); return -EAGAIN; } - mod &= ~(sdf_mask | lrp_rlow | MOD_SLAVE); + mod &= ~(sdf_mask | lrp_rlow | mod_slave); mod |= tmp; writel(mod, i2s->addr + I2SMOD); @@ -751,6 +764,7 @@ static void i2s_shutdown(struct snd_pcm_substream *substream, struct i2s_dai *i2s = to_info(dai); struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai; unsigned long flags; + const struct samsung_i2s_variant_regs *i2s_regs = i2s->variant_regs; spin_lock_irqsave(&lock, flags); @@ -761,7 +775,7 @@ static void i2s_shutdown(struct snd_pcm_substream *substream, other->mode |= DAI_MANAGER; } else { u32 mod = readl(i2s->addr + I2SMOD); - i2s->cdclk_out = !(mod & MOD_CDCLKCON); + i2s->cdclk_out = !(mod & (1 << i2s_regs->cdclkcon_off)); if (other) other->cdclk_out = i2s->cdclk_out; } @@ -914,13 +928,14 @@ i2s_delay(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) struct i2s_dai *i2s = to_info(dai); u32 reg = readl(i2s->addr + I2SFIC); snd_pcm_sframes_t delay; + const struct samsung_i2s_variant_regs *i2s_regs = i2s->variant_regs; if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) delay = FIC_RXCOUNT(reg); else if (is_secondary(i2s)) delay = FICS_TXCOUNT(readl(i2s->addr + I2SFICS)); else - delay = FIC_TXCOUNT(reg); + delay = (reg >> i2s_regs->ftx0cnt_off) & 0x7f; return delay; } @@ -1227,6 +1242,7 @@ static int samsung_i2s_probe(struct platform_device *pdev) pri_dai->dma_capture.dma_size = 4; pri_dai->base = regs_base; pri_dai->quirks = quirks; + pri_dai->variant_regs = i2s_dai_data->i2s_variant_regs; if (quirks & QUIRK_PRI_6CHAN) pri_dai->i2s_dai_drv.playback.channels_max = 6; @@ -1301,21 +1317,93 @@ static int samsung_i2s_remove(struct platform_device *pdev) return 0; } +static const struct samsung_i2s_variant_regs i2sv3_regs = { + .bfs_off = 1, + .rfs_off = 3, + .sdf_off = 5, + .txr_off = 8, + .rclksrc_off = 10, + .mss_off = 11, + .cdclkcon_off = 12, + .lrp_off = 7, + .bfs_mask = 0x3, + .rfs_mask = 0x3, + .ftx0cnt_off = 8, +}; + +static const struct samsung_i2s_variant_regs i2sv6_regs = { + .bfs_off = 0, + .rfs_off = 4, + .sdf_off = 6, + .txr_off = 8, + .rclksrc_off = 10, + .mss_off = 11, + .cdclkcon_off = 12, + .lrp_off = 15, + .bfs_mask = 0xf, + .rfs_mask = 0x3, + .ftx0cnt_off = 8, +}; + +static const struct samsung_i2s_variant_regs i2sv7_regs = { + .bfs_off = 0, + .rfs_off = 4, + .sdf_off = 7, + .txr_off = 9, + .rclksrc_off = 11, + .mss_off = 12, + .cdclkcon_off = 22, + .lrp_off = 15, + .bfs_mask = 0xf, + .rfs_mask = 0x7, + .ftx0cnt_off = 0, +}; + +static const struct samsung_i2s_variant_regs i2sv5_i2s1_regs = { + .bfs_off = 0, + .rfs_off = 3, + .sdf_off = 6, + .txr_off = 8, + .rclksrc_off = 10, + .mss_off = 11, + .cdclkcon_off = 12, + .lrp_off = 15, + .bfs_mask = 0x7, + .rfs_mask = 0x7, + .ftx0cnt_off = 8, +}; + static const struct samsung_i2s_dai_data i2sv3_dai_type = { .dai_type = TYPE_PRI, .quirks = QUIRK_NO_MUXPSR, + .i2s_variant_regs = &i2sv3_regs, }; static const struct samsung_i2s_dai_data i2sv5_dai_type = { .dai_type = TYPE_PRI, .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR | QUIRK_SUPPORTS_IDMA, + .i2s_variant_regs = &i2sv3_regs, }; static const struct samsung_i2s_dai_data i2sv6_dai_type = { .dai_type = TYPE_PRI, .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR | QUIRK_SUPPORTS_TDM | QUIRK_SUPPORTS_IDMA, + .i2s_variant_regs = &i2sv6_regs, +}; + +static const struct samsung_i2s_dai_data i2sv7_dai_type = { + .dai_type = TYPE_PRI, + .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR | + QUIRK_SUPPORTS_TDM, + .i2s_variant_regs = &i2sv7_regs, +}; + +static const struct samsung_i2s_dai_data i2sv5_dai_type_i2s1 = { + .dai_type = TYPE_PRI, + .quirks = QUIRK_PRI_6CHAN | QUIRK_NEED_RSTCLR, + .i2s_variant_regs = &i2sv5_i2s1_regs, }; static const struct samsung_i2s_dai_data samsung_dai_type_pri = { @@ -1349,6 +1437,12 @@ static const struct of_device_id exynos_i2s_match[] = { }, { .compatible = "samsung,exynos5420-i2s", .data = &i2sv6_dai_type, + }, { + .compatible = "samsung,exynos7-i2s", + .data = &i2sv7_dai_type, + }, { + .compatible = "samsung,exynos7-i2s1", + .data = &i2sv5_dai_type_i2s1, }, {}, }; -- cgit v1.2.3-59-g8ed1b From 98267d33e2da8cd386212856a22f4a64b32834ab Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Fri, 7 Nov 2014 14:14:23 +0000 Subject: serial: pl011: Add device tree support for RX DMA polling Add equivalent attributes to those provided in the platform data for use when RX DMA is enabled. Signed-off-by: Andrew Jackson Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/pl011.txt | 19 ++++++++++++------- drivers/tty/serial/amba-pl011.c | 22 +++++++++++++++++++--- 2 files changed, 31 insertions(+), 10 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/serial/pl011.txt b/Documentation/devicetree/bindings/serial/pl011.txt index 5d2e840ae65c..0e05340055e1 100644 --- a/Documentation/devicetree/bindings/serial/pl011.txt +++ b/Documentation/devicetree/bindings/serial/pl011.txt @@ -6,12 +6,17 @@ Required properties: - interrupts: exactly one interrupt specifier Optional properties: -- pinctrl: When present, must have one state named "sleep" - and one state named "default" -- clocks: When present, must refer to exactly one clock named - "apb_pclk" -- dmas: When present, may have one or two dma channels. - The first one must be named "rx", the second one - must be named "tx". +- pinctrl: When present, must have one state named "sleep" + and one state named "default" +- clocks: When present, must refer to exactly one clock named + "apb_pclk" +- dmas: When present, may have one or two dma channels. + The first one must be named "rx", the second one + must be named "tx". +- auto-poll: Enables polling when using RX DMA. +- poll-rate-ms: Rate at which poll occurs when auto-poll is set, + default 100ms. +- poll-timeout-ms: Poll timeout when auto-poll is set, default + 3000ms. See also bindings/arm/primecell.txt diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index d984a97043b3..8d94c194f090 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -341,6 +341,7 @@ static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port * dmaengine_slave_config(chan, &rx_conf); uap->dmarx.chan = chan; + uap->dmarx.auto_poll_rate = false; if (plat && plat->dma_rx_poll_enable) { /* Set poll rate if specified. */ if (plat->dma_rx_poll_rate) { @@ -361,9 +362,24 @@ static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port * plat->dma_rx_poll_timeout; else uap->dmarx.poll_timeout = 3000; - } else - uap->dmarx.auto_poll_rate = false; - + } else if (!plat && dev->of_node) { + uap->dmarx.auto_poll_rate = of_property_read_bool( + dev->of_node, "auto-poll"); + if (uap->dmarx.auto_poll_rate) { + u32 x; + + if (0 == of_property_read_u32(dev->of_node, + "poll-rate-ms", &x)) + uap->dmarx.poll_rate = x; + else + uap->dmarx.poll_rate = 100; + if (0 == of_property_read_u32(dev->of_node, + "poll-timeout-ms", &x)) + uap->dmarx.poll_timeout = x; + else + uap->dmarx.poll_timeout = 3000; + } + } dev_info(uap->port.dev, "DMA channel RX %s\n", dma_chan_name(uap->dmarx.chan)); } -- cgit v1.2.3-59-g8ed1b From e0f1147cc9512d3610d2f2a0f069690661444703 Mon Sep 17 00:00:00 2001 From: Cristian Stoica Date: Thu, 9 Oct 2014 15:00:27 +0300 Subject: uio: support memory sizes larger than 32 bits This is a completion to 27a90700a4275c5178b883b65927affdafa5185c The size field is also increased to allow values larger than 32 bits on platforms that have more than 32 bit physical addresses. Signed-off-by: Cristian Stoica Signed-off-by: Greg Kroah-Hartman --- Documentation/DocBook/uio-howto.tmpl | 2 +- drivers/uio/uio.c | 4 ++-- include/linux/uio_driver.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/DocBook/uio-howto.tmpl b/Documentation/DocBook/uio-howto.tmpl index bbe9c1fd5cef..1fdc246e4256 100644 --- a/Documentation/DocBook/uio-howto.tmpl +++ b/Documentation/DocBook/uio-howto.tmpl @@ -540,7 +540,7 @@ appears in sysfs. -unsigned long size: Fill in the size of the +resource_size_t size: Fill in the size of the memory block that addr points to. If size is zero, the mapping is considered unused. Note that you must initialize size with zero for diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index 60fa6278fbce..6276f13e9e12 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c @@ -56,12 +56,12 @@ static ssize_t map_name_show(struct uio_mem *mem, char *buf) static ssize_t map_addr_show(struct uio_mem *mem, char *buf) { - return sprintf(buf, "0x%llx\n", (unsigned long long)mem->addr); + return sprintf(buf, "%pa\n", &mem->addr); } static ssize_t map_size_show(struct uio_mem *mem, char *buf) { - return sprintf(buf, "0x%lx\n", mem->size); + return sprintf(buf, "%pa\n", &mem->size); } static ssize_t map_offset_show(struct uio_mem *mem, char *buf) diff --git a/include/linux/uio_driver.h b/include/linux/uio_driver.h index baa81718d985..32c0e83d6239 100644 --- a/include/linux/uio_driver.h +++ b/include/linux/uio_driver.h @@ -35,7 +35,7 @@ struct uio_map; struct uio_mem { const char *name; phys_addr_t addr; - unsigned long size; + resource_size_t size; int memtype; void __iomem *internal_addr; struct uio_map *map; -- cgit v1.2.3-59-g8ed1b From 246246cbde5e840012f853e27630ebb59f409486 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Tue, 30 Sep 2014 14:48:25 +0100 Subject: drivers: base: support cpu cache information interface to userspace via sysfs This patch adds initial support for providing processor cache information to userspace through sysfs interface. This is based on already existing implementations(x86, ia64, s390 and powerpc) and hence the interface is intended to be fully compatible. The main purpose of this generic support is to avoid further code duplication to support new architectures and also to unify all the existing different implementations. This implementation maintains the hierarchy of cache objects which reflects the system's cache topology. Cache devices are instantiated as needed as CPUs come online. The cache information is replicated per-cpu even if they are shared. A per-cpu array of cache information maintained is used mainly for sysfs-related book keeping. It also implements the shared_cpu_map attribute, which is essential for enabling both kernel and user-space to discover the system's overall cache topology. This patch also add the missing ABI documentation for the cacheinfo sysfs interface already, which is well defined and widely used. Signed-off-by: Sudeep Holla Reviewed-by: Stephen Boyd Tested-by: Stephen Boyd Cc: Greg Kroah-Hartman Cc: linux-api@vger.kernel.org Cc: linux390@de.ibm.com Cc: linux-arm-kernel@lists.infradead.org Cc: linux-ia64@vger.kernel.org Cc: linuxppc-dev@lists.ozlabs.org Cc: linux-s390@vger.kernel.org Cc: x86@kernel.org Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/sysfs-devices-system-cpu | 47 ++ drivers/base/Makefile | 2 +- drivers/base/cacheinfo.c | 541 +++++++++++++++++++++ include/linux/cacheinfo.h | 100 ++++ 4 files changed, 689 insertions(+), 1 deletion(-) create mode 100644 drivers/base/cacheinfo.c create mode 100644 include/linux/cacheinfo.h (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-devices-system-cpu b/Documentation/ABI/testing/sysfs-devices-system-cpu index acb9bfc89b48..99983e67c13c 100644 --- a/Documentation/ABI/testing/sysfs-devices-system-cpu +++ b/Documentation/ABI/testing/sysfs-devices-system-cpu @@ -224,3 +224,50 @@ Description: Parameters for the Intel P-state driver frequency range. More details can be found in Documentation/cpu-freq/intel-pstate.txt + +What: /sys/devices/system/cpu/cpu*/cache/index*/ +Date: July 2014(documented, existed before August 2008) +Contact: Sudeep Holla + Linux kernel mailing list +Description: Parameters for the CPU cache attributes + + allocation_policy: + - WriteAllocate: allocate a memory location to a cache line + on a cache miss because of a write + - ReadAllocate: allocate a memory location to a cache line + on a cache miss because of a read + - ReadWriteAllocate: both writeallocate and readallocate + + attributes: LEGACY used only on IA64 and is same as write_policy + + coherency_line_size: the minimum amount of data in bytes that gets + transferred from memory to cache + + level: the cache hierarcy in the multi-level cache configuration + + number_of_sets: total number of sets in the cache, a set is a + collection of cache lines with the same cache index + + physical_line_partition: number of physical cache line per cache tag + + shared_cpu_list: the list of logical cpus sharing the cache + + shared_cpu_map: logical cpu mask containing the list of cpus sharing + the cache + + size: the total cache size in kB + + type: + - Instruction: cache that only holds instructions + - Data: cache that only caches data + - Unified: cache that holds both data and instructions + + ways_of_associativity: degree of freedom in placing a particular block + of memory in the cache + + write_policy: + - WriteThrough: data is written to both the cache line + and to the block in the lower-level memory + - WriteBack: data is written only to the cache line and + the modified cache line is written to main + memory only when it is replaced diff --git a/drivers/base/Makefile b/drivers/base/Makefile index 6922cd6850a2..e81a55ca513c 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile @@ -4,7 +4,7 @@ obj-y := component.o core.o bus.o dd.o syscore.o \ driver.o class.o platform.o \ cpu.o firmware.o init.o map.o devres.o \ attribute_container.o transport_class.o \ - topology.o container.o + topology.o container.o cacheinfo.o obj-$(CONFIG_DEVTMPFS) += devtmpfs.o obj-$(CONFIG_DMA_CMA) += dma-contiguous.o obj-y += power/ diff --git a/drivers/base/cacheinfo.c b/drivers/base/cacheinfo.c new file mode 100644 index 000000000000..8ed4ea1f3716 --- /dev/null +++ b/drivers/base/cacheinfo.c @@ -0,0 +1,541 @@ +/* + * cacheinfo support - processor cache information via sysfs + * + * Based on arch/x86/kernel/cpu/intel_cacheinfo.c + * Author: Sudeep Holla + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed "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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* pointer to per cpu cacheinfo */ +static DEFINE_PER_CPU(struct cpu_cacheinfo, ci_cpu_cacheinfo); +#define ci_cacheinfo(cpu) (&per_cpu(ci_cpu_cacheinfo, cpu)) +#define cache_leaves(cpu) (ci_cacheinfo(cpu)->num_leaves) +#define per_cpu_cacheinfo(cpu) (ci_cacheinfo(cpu)->info_list) + +struct cpu_cacheinfo *get_cpu_cacheinfo(unsigned int cpu) +{ + return ci_cacheinfo(cpu); +} + +#ifdef CONFIG_OF +static int cache_setup_of_node(unsigned int cpu) +{ + struct device_node *np; + struct cacheinfo *this_leaf; + struct device *cpu_dev = get_cpu_device(cpu); + struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); + unsigned int index = 0; + + /* skip if of_node is already populated */ + if (this_cpu_ci->info_list->of_node) + return 0; + + if (!cpu_dev) { + pr_err("No cpu device for CPU %d\n", cpu); + return -ENODEV; + } + np = cpu_dev->of_node; + if (!np) { + pr_err("Failed to find cpu%d device node\n", cpu); + return -ENOENT; + } + + while (np && index < cache_leaves(cpu)) { + this_leaf = this_cpu_ci->info_list + index; + if (this_leaf->level != 1) + np = of_find_next_cache_node(np); + else + np = of_node_get(np);/* cpu node itself */ + this_leaf->of_node = np; + index++; + } + return 0; +} + +static inline bool cache_leaves_are_shared(struct cacheinfo *this_leaf, + struct cacheinfo *sib_leaf) +{ + return sib_leaf->of_node == this_leaf->of_node; +} +#else +static inline int cache_setup_of_node(unsigned int cpu) { return 0; } +static inline bool cache_leaves_are_shared(struct cacheinfo *this_leaf, + struct cacheinfo *sib_leaf) +{ + /* + * For non-DT systems, assume unique level 1 cache, system-wide + * shared caches for all other levels. This will be used only if + * arch specific code has not populated shared_cpu_map + */ + return !(this_leaf->level == 1); +} +#endif + +static int cache_shared_cpu_map_setup(unsigned int cpu) +{ + struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); + struct cacheinfo *this_leaf, *sib_leaf; + unsigned int index; + int ret; + + ret = cache_setup_of_node(cpu); + if (ret) + return ret; + + for (index = 0; index < cache_leaves(cpu); index++) { + unsigned int i; + + this_leaf = this_cpu_ci->info_list + index; + /* skip if shared_cpu_map is already populated */ + if (!cpumask_empty(&this_leaf->shared_cpu_map)) + continue; + + cpumask_set_cpu(cpu, &this_leaf->shared_cpu_map); + for_each_online_cpu(i) { + struct cpu_cacheinfo *sib_cpu_ci = get_cpu_cacheinfo(i); + + if (i == cpu || !sib_cpu_ci->info_list) + continue;/* skip if itself or no cacheinfo */ + sib_leaf = sib_cpu_ci->info_list + index; + if (cache_leaves_are_shared(this_leaf, sib_leaf)) { + cpumask_set_cpu(cpu, &sib_leaf->shared_cpu_map); + cpumask_set_cpu(i, &this_leaf->shared_cpu_map); + } + } + } + + return 0; +} + +static void cache_shared_cpu_map_remove(unsigned int cpu) +{ + struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); + struct cacheinfo *this_leaf, *sib_leaf; + unsigned int sibling, index; + + for (index = 0; index < cache_leaves(cpu); index++) { + this_leaf = this_cpu_ci->info_list + index; + for_each_cpu(sibling, &this_leaf->shared_cpu_map) { + struct cpu_cacheinfo *sib_cpu_ci; + + if (sibling == cpu) /* skip itself */ + continue; + sib_cpu_ci = get_cpu_cacheinfo(sibling); + sib_leaf = sib_cpu_ci->info_list + index; + cpumask_clear_cpu(cpu, &sib_leaf->shared_cpu_map); + cpumask_clear_cpu(sibling, &this_leaf->shared_cpu_map); + } + of_node_put(this_leaf->of_node); + } +} + +static void free_cache_attributes(unsigned int cpu) +{ + cache_shared_cpu_map_remove(cpu); + + kfree(per_cpu_cacheinfo(cpu)); + per_cpu_cacheinfo(cpu) = NULL; +} + +int __weak init_cache_level(unsigned int cpu) +{ + return -ENOENT; +} + +int __weak populate_cache_leaves(unsigned int cpu) +{ + return -ENOENT; +} + +static int detect_cache_attributes(unsigned int cpu) +{ + int ret; + + if (init_cache_level(cpu)) + return -ENOENT; + + per_cpu_cacheinfo(cpu) = kcalloc(cache_leaves(cpu), + sizeof(struct cacheinfo), GFP_KERNEL); + if (per_cpu_cacheinfo(cpu) == NULL) + return -ENOMEM; + + ret = populate_cache_leaves(cpu); + if (ret) + goto free_ci; + /* + * For systems using DT for cache hierarcy, of_node and shared_cpu_map + * will be set up here only if they are not populated already + */ + ret = cache_shared_cpu_map_setup(cpu); + if (ret) + goto free_ci; + return 0; + +free_ci: + free_cache_attributes(cpu); + return ret; +} + +/* pointer to cpuX/cache device */ +static DEFINE_PER_CPU(struct device *, ci_cache_dev); +#define per_cpu_cache_dev(cpu) (per_cpu(ci_cache_dev, cpu)) + +static cpumask_t cache_dev_map; + +/* pointer to array of devices for cpuX/cache/indexY */ +static DEFINE_PER_CPU(struct device **, ci_index_dev); +#define per_cpu_index_dev(cpu) (per_cpu(ci_index_dev, cpu)) +#define per_cache_index_dev(cpu, idx) ((per_cpu_index_dev(cpu))[idx]) + +#define show_one(file_name, object) \ +static ssize_t file_name##_show(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct cacheinfo *this_leaf = dev_get_drvdata(dev); \ + return sprintf(buf, "%u\n", this_leaf->object); \ +} + +show_one(level, level); +show_one(coherency_line_size, coherency_line_size); +show_one(number_of_sets, number_of_sets); +show_one(physical_line_partition, physical_line_partition); +show_one(ways_of_associativity, ways_of_associativity); + +static ssize_t size_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cacheinfo *this_leaf = dev_get_drvdata(dev); + + return sprintf(buf, "%uK\n", this_leaf->size >> 10); +} + +static ssize_t shared_cpumap_show_func(struct device *dev, bool list, char *buf) +{ + struct cacheinfo *this_leaf = dev_get_drvdata(dev); + const struct cpumask *mask = &this_leaf->shared_cpu_map; + + return cpumap_print_to_pagebuf(list, buf, mask); +} + +static ssize_t shared_cpu_map_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return shared_cpumap_show_func(dev, false, buf); +} + +static ssize_t shared_cpu_list_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return shared_cpumap_show_func(dev, true, buf); +} + +static ssize_t type_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cacheinfo *this_leaf = dev_get_drvdata(dev); + + switch (this_leaf->type) { + case CACHE_TYPE_DATA: + return sprintf(buf, "Data\n"); + case CACHE_TYPE_INST: + return sprintf(buf, "Instruction\n"); + case CACHE_TYPE_UNIFIED: + return sprintf(buf, "Unified\n"); + default: + return -EINVAL; + } +} + +static ssize_t allocation_policy_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cacheinfo *this_leaf = dev_get_drvdata(dev); + unsigned int ci_attr = this_leaf->attributes; + int n = 0; + + if ((ci_attr & CACHE_READ_ALLOCATE) && (ci_attr & CACHE_WRITE_ALLOCATE)) + n = sprintf(buf, "ReadWriteAllocate\n"); + else if (ci_attr & CACHE_READ_ALLOCATE) + n = sprintf(buf, "ReadAllocate\n"); + else if (ci_attr & CACHE_WRITE_ALLOCATE) + n = sprintf(buf, "WriteAllocate\n"); + return n; +} + +static ssize_t write_policy_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cacheinfo *this_leaf = dev_get_drvdata(dev); + unsigned int ci_attr = this_leaf->attributes; + int n = 0; + + if (ci_attr & CACHE_WRITE_THROUGH) + n = sprintf(buf, "WriteThrough\n"); + else if (ci_attr & CACHE_WRITE_BACK) + n = sprintf(buf, "WriteBack\n"); + return n; +} + +static DEVICE_ATTR_RO(level); +static DEVICE_ATTR_RO(type); +static DEVICE_ATTR_RO(coherency_line_size); +static DEVICE_ATTR_RO(ways_of_associativity); +static DEVICE_ATTR_RO(number_of_sets); +static DEVICE_ATTR_RO(size); +static DEVICE_ATTR_RO(allocation_policy); +static DEVICE_ATTR_RO(write_policy); +static DEVICE_ATTR_RO(shared_cpu_map); +static DEVICE_ATTR_RO(shared_cpu_list); +static DEVICE_ATTR_RO(physical_line_partition); + +static struct attribute *cache_default_attrs[] = { + &dev_attr_type.attr, + &dev_attr_level.attr, + &dev_attr_shared_cpu_map.attr, + &dev_attr_shared_cpu_list.attr, + &dev_attr_coherency_line_size.attr, + &dev_attr_ways_of_associativity.attr, + &dev_attr_number_of_sets.attr, + &dev_attr_size.attr, + &dev_attr_allocation_policy.attr, + &dev_attr_write_policy.attr, + &dev_attr_physical_line_partition.attr, + NULL +}; + +static umode_t +cache_default_attrs_is_visible(struct kobject *kobj, + struct attribute *attr, int unused) +{ + struct device *dev = kobj_to_dev(kobj); + struct cacheinfo *this_leaf = dev_get_drvdata(dev); + const struct cpumask *mask = &this_leaf->shared_cpu_map; + umode_t mode = attr->mode; + + if ((attr == &dev_attr_type.attr) && this_leaf->type) + return mode; + if ((attr == &dev_attr_level.attr) && this_leaf->level) + return mode; + if ((attr == &dev_attr_shared_cpu_map.attr) && !cpumask_empty(mask)) + return mode; + if ((attr == &dev_attr_shared_cpu_list.attr) && !cpumask_empty(mask)) + return mode; + if ((attr == &dev_attr_coherency_line_size.attr) && + this_leaf->coherency_line_size) + return mode; + if ((attr == &dev_attr_ways_of_associativity.attr) && + this_leaf->size) /* allow 0 = full associativity */ + return mode; + if ((attr == &dev_attr_number_of_sets.attr) && + this_leaf->number_of_sets) + return mode; + if ((attr == &dev_attr_size.attr) && this_leaf->size) + return mode; + if ((attr == &dev_attr_write_policy.attr) && + (this_leaf->attributes & CACHE_WRITE_POLICY_MASK)) + return mode; + if ((attr == &dev_attr_allocation_policy.attr) && + (this_leaf->attributes & CACHE_ALLOCATE_POLICY_MASK)) + return mode; + if ((attr == &dev_attr_physical_line_partition.attr) && + this_leaf->physical_line_partition) + return mode; + + return 0; +} + +static const struct attribute_group cache_default_group = { + .attrs = cache_default_attrs, + .is_visible = cache_default_attrs_is_visible, +}; + +static const struct attribute_group *cache_default_groups[] = { + &cache_default_group, + NULL, +}; + +static const struct attribute_group *cache_private_groups[] = { + &cache_default_group, + NULL, /* Place holder for private group */ + NULL, +}; + +const struct attribute_group * +__weak cache_get_priv_group(struct cacheinfo *this_leaf) +{ + return NULL; +} + +static const struct attribute_group ** +cache_get_attribute_groups(struct cacheinfo *this_leaf) +{ + const struct attribute_group *priv_group = + cache_get_priv_group(this_leaf); + + if (!priv_group) + return cache_default_groups; + + if (!cache_private_groups[1]) + cache_private_groups[1] = priv_group; + + return cache_private_groups; +} + +/* Add/Remove cache interface for CPU device */ +static void cpu_cache_sysfs_exit(unsigned int cpu) +{ + int i; + struct device *ci_dev; + + if (per_cpu_index_dev(cpu)) { + for (i = 0; i < cache_leaves(cpu); i++) { + ci_dev = per_cache_index_dev(cpu, i); + if (!ci_dev) + continue; + device_unregister(ci_dev); + } + kfree(per_cpu_index_dev(cpu)); + per_cpu_index_dev(cpu) = NULL; + } + device_unregister(per_cpu_cache_dev(cpu)); + per_cpu_cache_dev(cpu) = NULL; +} + +static int cpu_cache_sysfs_init(unsigned int cpu) +{ + struct device *dev = get_cpu_device(cpu); + + if (per_cpu_cacheinfo(cpu) == NULL) + return -ENOENT; + + per_cpu_cache_dev(cpu) = cpu_device_create(dev, NULL, NULL, "cache"); + if (IS_ERR(per_cpu_cache_dev(cpu))) + return PTR_ERR(per_cpu_cache_dev(cpu)); + + /* Allocate all required memory */ + per_cpu_index_dev(cpu) = kcalloc(cache_leaves(cpu), + sizeof(struct device *), GFP_KERNEL); + if (unlikely(per_cpu_index_dev(cpu) == NULL)) + goto err_out; + + return 0; + +err_out: + cpu_cache_sysfs_exit(cpu); + return -ENOMEM; +} + +static int cache_add_dev(unsigned int cpu) +{ + unsigned int i; + int rc; + struct device *ci_dev, *parent; + struct cacheinfo *this_leaf; + struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); + const struct attribute_group **cache_groups; + + rc = cpu_cache_sysfs_init(cpu); + if (unlikely(rc < 0)) + return rc; + + parent = per_cpu_cache_dev(cpu); + for (i = 0; i < cache_leaves(cpu); i++) { + this_leaf = this_cpu_ci->info_list + i; + if (this_leaf->disable_sysfs) + continue; + cache_groups = cache_get_attribute_groups(this_leaf); + ci_dev = cpu_device_create(parent, this_leaf, cache_groups, + "index%1u", i); + if (IS_ERR(ci_dev)) { + rc = PTR_ERR(ci_dev); + goto err; + } + per_cache_index_dev(cpu, i) = ci_dev; + } + cpumask_set_cpu(cpu, &cache_dev_map); + + return 0; +err: + cpu_cache_sysfs_exit(cpu); + return rc; +} + +static void cache_remove_dev(unsigned int cpu) +{ + if (!cpumask_test_cpu(cpu, &cache_dev_map)) + return; + cpumask_clear_cpu(cpu, &cache_dev_map); + + cpu_cache_sysfs_exit(cpu); +} + +static int cacheinfo_cpu_callback(struct notifier_block *nfb, + unsigned long action, void *hcpu) +{ + unsigned int cpu = (unsigned long)hcpu; + int rc = 0; + + switch (action & ~CPU_TASKS_FROZEN) { + case CPU_ONLINE: + rc = detect_cache_attributes(cpu); + if (!rc) + rc = cache_add_dev(cpu); + break; + case CPU_DEAD: + cache_remove_dev(cpu); + if (per_cpu_cacheinfo(cpu)) + free_cache_attributes(cpu); + break; + } + return notifier_from_errno(rc); +} + +static int __init cacheinfo_sysfs_init(void) +{ + int cpu, rc = 0; + + cpu_notifier_register_begin(); + + for_each_online_cpu(cpu) { + rc = detect_cache_attributes(cpu); + if (rc) { + pr_err("error detecting cacheinfo..cpu%d\n", cpu); + goto out; + } + rc = cache_add_dev(cpu); + if (rc) { + free_cache_attributes(cpu); + pr_err("error populating cacheinfo..cpu%d\n", cpu); + goto out; + } + } + __hotcpu_notifier(cacheinfo_cpu_callback, 0); + +out: + cpu_notifier_register_done(); + return rc; +} + +device_initcall(cacheinfo_sysfs_init); diff --git a/include/linux/cacheinfo.h b/include/linux/cacheinfo.h new file mode 100644 index 000000000000..3daf5ed392c9 --- /dev/null +++ b/include/linux/cacheinfo.h @@ -0,0 +1,100 @@ +#ifndef _LINUX_CACHEINFO_H +#define _LINUX_CACHEINFO_H + +#include +#include +#include + +struct device_node; +struct attribute; + +enum cache_type { + CACHE_TYPE_NOCACHE = 0, + CACHE_TYPE_INST = BIT(0), + CACHE_TYPE_DATA = BIT(1), + CACHE_TYPE_SEPARATE = CACHE_TYPE_INST | CACHE_TYPE_DATA, + CACHE_TYPE_UNIFIED = BIT(2), +}; + +/** + * struct cacheinfo - represent a cache leaf node + * @type: type of the cache - data, inst or unified + * @level: represents the hierarcy in the multi-level cache + * @coherency_line_size: size of each cache line usually representing + * the minimum amount of data that gets transferred from memory + * @number_of_sets: total number of sets, a set is a collection of cache + * lines sharing the same index + * @ways_of_associativity: number of ways in which a particular memory + * block can be placed in the cache + * @physical_line_partition: number of physical cache lines sharing the + * same cachetag + * @size: Total size of the cache + * @shared_cpu_map: logical cpumask representing all the cpus sharing + * this cache node + * @attributes: bitfield representing various cache attributes + * @of_node: if devicetree is used, this represents either the cpu node in + * case there's no explicit cache node or the cache node itself in the + * device tree + * @disable_sysfs: indicates whether this node is visible to the user via + * sysfs or not + * @priv: pointer to any private data structure specific to particular + * cache design + * + * While @of_node, @disable_sysfs and @priv are used for internal book + * keeping, the remaining members form the core properties of the cache + */ +struct cacheinfo { + enum cache_type type; + unsigned int level; + unsigned int coherency_line_size; + unsigned int number_of_sets; + unsigned int ways_of_associativity; + unsigned int physical_line_partition; + unsigned int size; + cpumask_t shared_cpu_map; + unsigned int attributes; +#define CACHE_WRITE_THROUGH BIT(0) +#define CACHE_WRITE_BACK BIT(1) +#define CACHE_WRITE_POLICY_MASK \ + (CACHE_WRITE_THROUGH | CACHE_WRITE_BACK) +#define CACHE_READ_ALLOCATE BIT(2) +#define CACHE_WRITE_ALLOCATE BIT(3) +#define CACHE_ALLOCATE_POLICY_MASK \ + (CACHE_READ_ALLOCATE | CACHE_WRITE_ALLOCATE) + + struct device_node *of_node; + bool disable_sysfs; + void *priv; +}; + +struct cpu_cacheinfo { + struct cacheinfo *info_list; + unsigned int num_levels; + unsigned int num_leaves; +}; + +/* + * Helpers to make sure "func" is executed on the cpu whose cache + * attributes are being detected + */ +#define DEFINE_SMP_CALL_CACHE_FUNCTION(func) \ +static inline void _##func(void *ret) \ +{ \ + int cpu = smp_processor_id(); \ + *(int *)ret = __##func(cpu); \ +} \ + \ +int func(unsigned int cpu) \ +{ \ + int ret; \ + smp_call_function_single(cpu, _##func, &ret, true); \ + return ret; \ +} + +struct cpu_cacheinfo *get_cpu_cacheinfo(unsigned int cpu); +int init_cache_level(unsigned int cpu); +int populate_cache_leaves(unsigned int cpu); + +const struct attribute_group *cache_get_priv_group(struct cacheinfo *this_leaf); + +#endif /* _LINUX_CACHEINFO_H */ -- cgit v1.2.3-59-g8ed1b From 872234d3fb32e26d3377590c396858d2324b8c16 Mon Sep 17 00:00:00 2001 From: Mathieu Poirier Date: Mon, 3 Nov 2014 11:07:42 -0700 Subject: coresight: documentation for coresight framework and drivers Documentation containing an explanation on what the framework provides and the drivers working with it. A minimal example on how to use the functionality is also provided. Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- Documentation/trace/coresight.txt | 299 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 299 insertions(+) create mode 100644 Documentation/trace/coresight.txt (limited to 'Documentation') diff --git a/Documentation/trace/coresight.txt b/Documentation/trace/coresight.txt new file mode 100644 index 000000000000..bba7dbfc49ed --- /dev/null +++ b/Documentation/trace/coresight.txt @@ -0,0 +1,299 @@ + Coresight - HW Assisted Tracing on ARM + ====================================== + + Author: Mathieu Poirier + Date: September 11th, 2014 + +Introduction +------------ + +Coresight is an umbrella of technologies allowing for the debugging of ARM +based SoC. It includes solutions for JTAG and HW assisted tracing. This +document is concerned with the latter. + +HW assisted tracing is becoming increasingly useful when dealing with systems +that have many SoCs and other components like GPU and DMA engines. ARM has +developed a HW assisted tracing solution by means of different components, each +being added to a design at systhesis time to cater to specific tracing needs. +Compoments are generally categorised as source, link and sinks and are +(usually) discovered using the AMBA bus. + +"Sources" generate a compressed stream representing the processor instruction +path based on tracing scenarios as configured by users. From there the stream +flows through the coresight system (via ATB bus) using links that are connecting +the emanating source to a sink(s). Sinks serve as endpoints to the coresight +implementation, either storing the compressed stream in a memory buffer or +creating an interface to the outside world where data can be transferred to a +host without fear of filling up the onboard coresight memory buffer. + +At typical coresight system would look like this: + + ***************************************************************** + **************************** AMBA AXI ****************************===|| + ***************************************************************** || + ^ ^ | || + | | * ** + 0000000 ::::: 0000000 ::::: ::::: @@@@@@@ |||||||||||| + 0 CPU 0<-->: C : 0 CPU 0<-->: C : : C : @ STM @ || System || + |->0000000 : T : |->0000000 : T : : T :<--->@@@@@ || Memory || + | #######<-->: I : | #######<-->: I : : I : @@@<-| |||||||||||| + | # ETM # ::::: | # PTM # ::::: ::::: @ | + | ##### ^ ^ | ##### ^ ! ^ ! . | ||||||||| + | |->### | ! | |->### | ! | ! . | || DAP || + | | # | ! | | # | ! | ! . | ||||||||| + | | . | ! | | . | ! | ! . | | | + | | . | ! | | . | ! | ! . | | * + | | . | ! | | . | ! | ! . | | SWD/ + | | . | ! | | . | ! | ! . | | JTAG + *****************************************************************<-| + *************************** AMBA Debug ABP ************************ + ***************************************************************** + | . ! . ! ! . | + | . * . * * . | + ***************************************************************** + ******************** Cross Trigger Matrix (CTM) ******************* + ***************************************************************** + | . ^ . . | + | * ! * * | + ***************************************************************** + ****************** AMBA Advanced Trace Bus (ATB) ****************** + ***************************************************************** + | ! =============== | + | * ===== F =====<---------| + | ::::::::: ==== U ==== + |-->:: CTI ::&& ETB &&<......II I ======= + | ! &&&&&&&&& II I . + | ! I I . + | ! I REP I<.......... + | ! I I + | !!>&&&&&&&&& II I *Source: ARM ltd. + |------>& TPIU &<......II I DAP = Debug Access Port + &&&&&&&&& IIIIIII ETM = Embedded Trace Macrocell + ; PTM = Program Trace Macrocell + ; CTI = Cross Trigger Interface + * ETB = Embedded Trace Buffer + To trace port TPIU= Trace Port Interface Unit + SWD = Serial Wire Debug + +While on target configuration of the components is done via the ABP bus, +all trace data are carried out-of-band on the ATB bus. The CTM provides +a way to aggregate and distribute signals between CoreSight components. + +The coresight framework provides a central point to represent, configure and +manage coresight devices on a platform. This first implementation centers on +the basic tracing functionality, enabling components such ETM/PTM, funnel, +replicator, TMC, TPIU and ETB. Future work will enable more +intricate IP blocks such as STM and CTI. + + +Acronyms and Classification +--------------------------- + +Acronyms: + +PTM: Program Trace Macrocell +ETM: Embedded Trace Macrocell +STM: System trace Macrocell +ETB: Embedded Trace Buffer +ITM: Instrumentation Trace Macrocell +TPIU: Trace Port Interface Unit +TMC-ETR: Trace Memory Controller, configured as Embedded Trace Router +TMC-ETF: Trace Memory Controller, configured as Embedded Trace FIFO +CTI: Cross Trigger Interface + +Classification: + +Source: + ETMv3.x ETMv4, PTMv1.0, PTMv1.1, STM, STM500, ITM +Link: + Funnel, replicator (intelligent or not), TMC-ETR +Sinks: + ETBv1.0, ETB1.1, TPIU, TMC-ETF +Misc: + CTI + + +Device Tree Bindings +---------------------- + +See Documentation/devicetree/bindings/arm/coresight.txt for details. + +As of this writing drivers for ITM, STMs and CTIs are not provided but are +expected to be added as the solution matures. + + +Framework and implementation +---------------------------- + +The coresight framework provides a central point to represent, configure and +manage coresight devices on a platform. Any coresight compliant device can +register with the framework for as long as they use the right APIs: + +struct coresight_device *coresight_register(struct coresight_desc *desc); +void coresight_unregister(struct coresight_device *csdev); + +The registering function is taking a "struct coresight_device *csdev" and +register the device with the core framework. The unregister function takes +a reference to a "strut coresight_device", obtained at registration time. + +If everything goes well during the registration process the new devices will +show up under /sys/bus/coresight/devices, as showns here for a TC2 platform: + +root:~# ls /sys/bus/coresight/devices/ +replicator 20030000.tpiu 2201c000.ptm 2203c000.etm 2203e000.etm +20010000.etb 20040000.funnel 2201d000.ptm 2203d000.etm +root:~# + +The functions take a "struct coresight_device", which looks like this: + +struct coresight_desc { + enum coresight_dev_type type; + struct coresight_dev_subtype subtype; + const struct coresight_ops *ops; + struct coresight_platform_data *pdata; + struct device *dev; + const struct attribute_group **groups; +}; + + +The "coresight_dev_type" identifies what the device is, i.e, source link or +sink while the "coresight_dev_subtype" will characterise that type further. + +The "struct coresight_ops" is mandatory and will tell the framework how to +perform base operations related to the components, each component having +a different set of requirement. For that "struct coresight_ops_sink", +"struct coresight_ops_link" and "struct coresight_ops_source" have been +provided. + +The next field, "struct coresight_platform_data *pdata" is acquired by calling +"of_get_coresight_platform_data()", as part of the driver's _probe routine and +"struct device *dev" gets the device reference embedded in the "amba_device": + +static int etm_probe(struct amba_device *adev, const struct amba_id *id) +{ + ... + ... + drvdata->dev = &adev->dev; + ... +} + +Specific class of device (source, link, or sink) have generic operations +that can be performed on them (see "struct coresight_ops"). The +"**groups" is a list of sysfs entries pertaining to operations +specific to that component only. "Implementation defined" customisations are +expected to be accessed and controlled using those entries. + +Last but not least, "struct module *owner" is expected to be set to reflect +the information carried in "THIS_MODULE". + +How to use +---------- + +Before trace collection can start, a coresight sink needs to be identify. +There is no limit on the amount of sinks (nor sources) that can be enabled at +any given moment. As a generic operation, all device pertaining to the sink +class will have an "active" entry in sysfs: + +root:/sys/bus/coresight/devices# ls +replicator 20030000.tpiu 2201c000.ptm 2203c000.etm 2203e000.etm +20010000.etb 20040000.funnel 2201d000.ptm 2203d000.etm +root:/sys/bus/coresight/devices# ls 20010000.etb +enable_sink status trigger_cntr +root:/sys/bus/coresight/devices# echo 1 > 20010000.etb/enable_sink +root:/sys/bus/coresight/devices# cat 20010000.etb/enable_sink +1 +root:/sys/bus/coresight/devices# + +At boot time the current etm3x driver will configure the first address +comparator with "_stext" and "_etext", essentially tracing any instruction +that falls within that range. As such "enabling" a source will immediately +trigger a trace capture: + +root:/sys/bus/coresight/devices# echo 1 > 2201c000.ptm/enable_source +root:/sys/bus/coresight/devices# cat 2201c000.ptm/enable_source +1 +root:/sys/bus/coresight/devices# cat 20010000.etb/status +Depth: 0x2000 +Status: 0x1 +RAM read ptr: 0x0 +RAM wrt ptr: 0x19d3 <----- The write pointer is moving +Trigger cnt: 0x0 +Control: 0x1 +Flush status: 0x0 +Flush ctrl: 0x2001 +root:/sys/bus/coresight/devices# + +Trace collection is stopped the same way: + +root:/sys/bus/coresight/devices# echo 0 > 2201c000.ptm/enable_source +root:/sys/bus/coresight/devices# + +The content of the ETB buffer can be harvested directly from /dev: + +root:/sys/bus/coresight/devices# dd if=/dev/20010000.etb \ +of=~/cstrace.bin + +64+0 records in +64+0 records out +32768 bytes (33 kB) copied, 0.00125258 s, 26.2 MB/s +root:/sys/bus/coresight/devices# + +The file cstrace.bin can be decompressed using "ptm2human", DS-5 or Trace32. + +Following is a DS-5 output of an experimental loop that increments a variable up +to a certain value. The example is simple and yet provides a glimpse of the +wealth of possibilities that coresight provides. + +Info Tracing enabled +Instruction 106378866 0x8026B53C E52DE004 false PUSH {lr} +Instruction 0 0x8026B540 E24DD00C false SUB sp,sp,#0xc +Instruction 0 0x8026B544 E3A03000 false MOV r3,#0 +Instruction 0 0x8026B548 E58D3004 false STR r3,[sp,#4] +Instruction 0 0x8026B54C E59D3004 false LDR r3,[sp,#4] +Instruction 0 0x8026B550 E3530004 false CMP r3,#4 +Instruction 0 0x8026B554 E2833001 false ADD r3,r3,#1 +Instruction 0 0x8026B558 E58D3004 false STR r3,[sp,#4] +Instruction 0 0x8026B55C DAFFFFFA true BLE {pc}-0x10 ; 0x8026b54c +Timestamp Timestamp: 17106715833 +Instruction 319 0x8026B54C E59D3004 false LDR r3,[sp,#4] +Instruction 0 0x8026B550 E3530004 false CMP r3,#4 +Instruction 0 0x8026B554 E2833001 false ADD r3,r3,#1 +Instruction 0 0x8026B558 E58D3004 false STR r3,[sp,#4] +Instruction 0 0x8026B55C DAFFFFFA true BLE {pc}-0x10 ; 0x8026b54c +Instruction 9 0x8026B54C E59D3004 false LDR r3,[sp,#4] +Instruction 0 0x8026B550 E3530004 false CMP r3,#4 +Instruction 0 0x8026B554 E2833001 false ADD r3,r3,#1 +Instruction 0 0x8026B558 E58D3004 false STR r3,[sp,#4] +Instruction 0 0x8026B55C DAFFFFFA true BLE {pc}-0x10 ; 0x8026b54c +Instruction 7 0x8026B54C E59D3004 false LDR r3,[sp,#4] +Instruction 0 0x8026B550 E3530004 false CMP r3,#4 +Instruction 0 0x8026B554 E2833001 false ADD r3,r3,#1 +Instruction 0 0x8026B558 E58D3004 false STR r3,[sp,#4] +Instruction 0 0x8026B55C DAFFFFFA true BLE {pc}-0x10 ; 0x8026b54c +Instruction 7 0x8026B54C E59D3004 false LDR r3,[sp,#4] +Instruction 0 0x8026B550 E3530004 false CMP r3,#4 +Instruction 0 0x8026B554 E2833001 false ADD r3,r3,#1 +Instruction 0 0x8026B558 E58D3004 false STR r3,[sp,#4] +Instruction 0 0x8026B55C DAFFFFFA true BLE {pc}-0x10 ; 0x8026b54c +Instruction 10 0x8026B54C E59D3004 false LDR r3,[sp,#4] +Instruction 0 0x8026B550 E3530004 false CMP r3,#4 +Instruction 0 0x8026B554 E2833001 false ADD r3,r3,#1 +Instruction 0 0x8026B558 E58D3004 false STR r3,[sp,#4] +Instruction 0 0x8026B55C DAFFFFFA true BLE {pc}-0x10 ; 0x8026b54c +Instruction 6 0x8026B560 EE1D3F30 false MRC p15,#0x0,r3,c13,c0,#1 +Instruction 0 0x8026B564 E1A0100D false MOV r1,sp +Instruction 0 0x8026B568 E3C12D7F false BIC r2,r1,#0x1fc0 +Instruction 0 0x8026B56C E3C2203F false BIC r2,r2,#0x3f +Instruction 0 0x8026B570 E59D1004 false LDR r1,[sp,#4] +Instruction 0 0x8026B574 E59F0010 false LDR r0,[pc,#16] ; [0x8026B58C] = 0x80550368 +Instruction 0 0x8026B578 E592200C false LDR r2,[r2,#0xc] +Instruction 0 0x8026B57C E59221D0 false LDR r2,[r2,#0x1d0] +Instruction 0 0x8026B580 EB07A4CF true BL {pc}+0x1e9344 ; 0x804548c4 +Info Tracing enabled +Instruction 13570831 0x8026B584 E28DD00C false ADD sp,sp,#0xc +Instruction 0 0x8026B588 E8BD8000 true LDM sp!,{pc} +Timestamp Timestamp: 17107041535 -- cgit v1.2.3-59-g8ed1b From f1aa77c9703148fad7d819d9d764dae0cb82d141 Mon Sep 17 00:00:00 2001 From: Emil Medve Date: Thu, 6 Nov 2014 09:48:12 -0600 Subject: dt/bindings: qoriq-clock: Add binding for the platform PLL Signed-off-by: Emil Medve Change-Id: I7950afa9650d15ec7ce2cca89bb2a1e38586d4a5 Signed-off-by: Scott Wood --- Documentation/devicetree/bindings/clock/qoriq-clock.txt | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/qoriq-clock.txt b/Documentation/devicetree/bindings/clock/qoriq-clock.txt index 5666812fc42b..266ff9d23229 100644 --- a/Documentation/devicetree/bindings/clock/qoriq-clock.txt +++ b/Documentation/devicetree/bindings/clock/qoriq-clock.txt @@ -62,6 +62,8 @@ Required properties: It takes parent's clock-frequency as its clock. * "fsl,qoriq-sysclk-2.0": for input system clock (v2.0). It takes parent's clock-frequency as its clock. + * "fsl,qoriq-platform-pll-1.0" for the platform PLL clock (v1.0) + * "fsl,qoriq-platform-pll-2.0" for the platform PLL clock (v2.0) - #clock-cells: From common clock binding. The number of cells in a clock-specifier. Should be <0> for "fsl,qoriq-sysclk-[1,2].0" clocks, or <1> for "fsl,qoriq-core-pll-[1,2].0" clocks. @@ -128,8 +130,16 @@ Example for clock block and clock provider: clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2"; clock-output-names = "cmux1"; }; + + platform-pll: platform-pll@c00 { + #clock-cells = <1>; + reg = <0xc00 0x4>; + compatible = "fsl,qoriq-platform-pll-1.0"; + clocks = <&sysclk>; + clock-output-names = "platform-pll", "platform-pll-div2"; + }; }; - } +}; Example for clock consumer: @@ -139,4 +149,4 @@ Example for clock consumer: clocks = <&mux0>; ... }; - } +}; -- cgit v1.2.3-59-g8ed1b From 1f999d14fc7f772fbdd19151ebe5ee081f53dd49 Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Sat, 8 Nov 2014 17:54:51 +0900 Subject: Documentation: power: Fix typo in Documentation/power This patch fix spelling typos found in Documentation/power. Signed-off-by: Masanari Iida Signed-off-by: Jonathan Corbet --- Documentation/power/runtime_pm.txt | 6 +++--- Documentation/power/suspend-and-interrupts.txt | 2 +- Documentation/power/userland-swsusp.txt | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/power/runtime_pm.txt b/Documentation/power/runtime_pm.txt index f32ce5419573..0e5ea26b255a 100644 --- a/Documentation/power/runtime_pm.txt +++ b/Documentation/power/runtime_pm.txt @@ -229,13 +229,13 @@ defined in include/linux/pm.h: - if set, the value of child_count is ignored (but still updated) unsigned int disable_depth; - - used for disabling the helper funcions (they work normally if this is + - used for disabling the helper functions (they work normally if this is equal to zero); the initial value of it is 1 (i.e. runtime PM is initially disabled for all devices) int runtime_error; - if set, there was a fatal error (one of the callbacks returned error code - as described in Section 2), so the helper funtions will not work until + as described in Section 2), so the helper functions will not work until this flag is cleared; this is the error code returned by the failing callback @@ -524,7 +524,7 @@ pm_runtime_put_sync_autosuspend() 5. Runtime PM Initialization, Device Probing and Removal Initially, the runtime PM is disabled for all devices, which means that the -majority of the runtime PM helper funtions described in Section 4 will return +majority of the runtime PM helper functions described in Section 4 will return -EAGAIN until pm_runtime_enable() is called for the device. In addition to that, the initial runtime PM status of all devices is diff --git a/Documentation/power/suspend-and-interrupts.txt b/Documentation/power/suspend-and-interrupts.txt index 69663640dea5..2f9c5a5fcb25 100644 --- a/Documentation/power/suspend-and-interrupts.txt +++ b/Documentation/power/suspend-and-interrupts.txt @@ -77,7 +77,7 @@ Calling enable_irq_wake() causes suspend_device_irqs() to treat the given IRQ in a special way. Namely, the IRQ remains enabled, by on the first interrupt it will be disabled, marked as pending and "suspended" so that it will be re-enabled by resume_device_irqs() during the subsequent system resume. Also -the PM core is notified about the event which casues the system suspend in +the PM core is notified about the event which causes the system suspend in progress to be aborted (that doesn't have to happen immediately, but at one of the points where the suspend thread looks for pending wakeup events). diff --git a/Documentation/power/userland-swsusp.txt b/Documentation/power/userland-swsusp.txt index 0e870825c1b9..bbfcd1bbedc5 100644 --- a/Documentation/power/userland-swsusp.txt +++ b/Documentation/power/userland-swsusp.txt @@ -99,7 +99,7 @@ SNAPSHOT_S2RAM - suspend to RAM; using this call causes the kernel to The device's read() operation can be used to transfer the snapshot image from the kernel. It has the following limitations: - you cannot read() more than one virtual memory page at a time -- read()s across page boundaries are impossible (ie. if ypu read() 1/2 of +- read()s across page boundaries are impossible (ie. if you read() 1/2 of a page in the previous call, you will only be able to read() _at_ _most_ 1/2 of the page in the next call) -- cgit v1.2.3-59-g8ed1b From c76acf4dffa3232711b5364d7a29746df590f3db Mon Sep 17 00:00:00 2001 From: Kevin Cernekee Date: Thu, 6 Nov 2014 22:44:26 -0800 Subject: irqchip: bcm7120-l2: Extend driver to support 64+ bit controllers Most implementations of the bcm7120-l2 controller only have a single 32-bit enable word + 32-bit status word. But some instances have added more enable/status pairs in order to support 64+ IRQs (which are all ORed into one parent IRQ input). Make the following changes to allow the driver to support this: - Extend DT bindings so that multiple words can be specified for the reg property, various masks, etc. - Add loops to the probe/handle functions to deal with each word separately - Allocate 1 generic-chip for every 32 IRQs, so we can still use the clr/set helper functions - Update the documentation This uses one domain per bcm7120-l2 DT node. If the DT node defines multiple enable/status pairs (i.e. >=64 IRQs) then the driver will create a single IRQ domain with 2+ generic chips. Multiple generic chips are required because the generic-chip code can only handle one enable/status register pair per instance. Signed-off-by: Kevin Cernekee Acked-by: Arnd Bergmann Link: https://lkml.kernel.org/r/1415342669-30640-12-git-send-email-cernekee@gmail.com Signed-off-by: Jason Cooper --- .../interrupt-controller/brcm,bcm7120-l2-intc.txt | 26 ++-- drivers/irqchip/irq-bcm7120-l2.c | 144 ++++++++++++++------- 2 files changed, 113 insertions(+), 57 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 ff812a8a82bc..bae1f2187226 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm7120-l2-intc.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm7120-l2-intc.txt @@ -13,7 +13,12 @@ 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 -- not all 32-bits within the interrupt controller actually map to an interrupt +- 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 + +- no atomic set/clear operations + +- not all bits within the interrupt controller actually map to an interrupt The typical hardware layout for this controller is represented below: @@ -48,7 +53,9 @@ 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 +- 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 - 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. @@ -59,18 +66,21 @@ 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. + 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: + Optional properties: - brcm,irq-can-wake: if present, this means the L2 controller can be used as a wakeup source for system suspend/resume. -- brcm,int-fwd-mask: if present, a 32-bits bit mask to configure for the - interrupts which have a mux gate, typically UARTs. Setting these bits will - make their respective interrupts outputs bypass this 2nd level interrupt - controller completely, it completely transparent for the interrupt controller - parent +- brcm,int-fwd-mask: if present, a bit mask to configure the interrupts which + have a mux gate, typically UARTs. Setting these bits will make their + respective interrupt outputs bypass this 2nd level interrupt controller + completely; it is completely transparent for the interrupt controller + parent. This should have one 32-bit word per enable/status pair. Example: diff --git a/drivers/irqchip/irq-bcm7120-l2.c b/drivers/irqchip/irq-bcm7120-l2.c index 984112112042..ef4d32cf267f 100644 --- a/drivers/irqchip/irq-bcm7120-l2.c +++ b/drivers/irqchip/irq-bcm7120-l2.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "irqchip.h" @@ -31,27 +32,42 @@ #define IRQEN 0x00 #define IRQSTAT 0x04 +#define MAX_WORDS 4 +#define IRQS_PER_WORD 32 + struct bcm7120_l2_intc_data { - void __iomem *base; + unsigned int n_words; + void __iomem *base[MAX_WORDS]; struct irq_domain *domain; bool can_wake; - u32 irq_fwd_mask; - u32 irq_map_mask; + u32 irq_fwd_mask[MAX_WORDS]; + u32 irq_map_mask[MAX_WORDS]; }; static void bcm7120_l2_intc_irq_handle(unsigned int irq, struct irq_desc *desc) { struct bcm7120_l2_intc_data *b = irq_desc_get_handler_data(desc); struct irq_chip *chip = irq_desc_get_chip(desc); - u32 status; + unsigned int idx; chained_irq_enter(chip, desc); - status = __raw_readl(b->base + IRQSTAT); - while (status) { - irq = ffs(status) - 1; - status &= ~(1 << irq); - generic_handle_irq(irq_find_mapping(b->domain, irq)); + for (idx = 0; idx < b->n_words; idx++) { + int base = idx * IRQS_PER_WORD; + struct irq_chip_generic *gc = + irq_get_domain_generic_chip(b->domain, base); + unsigned long pending; + int hwirq; + + irq_gc_lock(gc); + pending = __raw_readl(b->base[idx] + IRQSTAT) & + gc->mask_cache; + irq_gc_unlock(gc); + + for_each_set_bit(hwirq, &pending, IRQS_PER_WORD) { + generic_handle_irq(irq_find_mapping(b->domain, + base + hwirq)); + } } chained_irq_exit(chip, desc); @@ -65,7 +81,7 @@ static void bcm7120_l2_intc_suspend(struct irq_data *d) irq_gc_lock(gc); if (b->can_wake) { __raw_writel(gc->mask_cache | gc->wake_active, - b->base + IRQEN); + gc->reg_base + IRQEN); } irq_gc_unlock(gc); } @@ -76,7 +92,7 @@ static void bcm7120_l2_intc_resume(struct irq_data *d) /* Restore the saved mask */ irq_gc_lock(gc); - __raw_writel(gc->mask_cache, b->base + IRQEN); + __raw_writel(gc->mask_cache, gc->reg_base + IRQEN); irq_gc_unlock(gc); } @@ -85,6 +101,7 @@ static int bcm7120_l2_intc_init_one(struct device_node *dn, int irq, const __be32 *map_mask) { int parent_irq; + unsigned int idx; parent_irq = irq_of_parse_and_map(dn, irq); if (parent_irq < 0) { @@ -92,7 +109,12 @@ static int bcm7120_l2_intc_init_one(struct device_node *dn, return parent_irq; } - data->irq_map_mask |= be32_to_cpup(map_mask + irq); + /* 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(map_mask + irq * data->n_words + idx); irq_set_handler_data(parent_irq, data); irq_set_chained_handler(parent_irq, bcm7120_l2_intc_irq_handle); @@ -109,26 +131,41 @@ int __init bcm7120_l2_intc_of_init(struct device_node *dn, struct irq_chip_type *ct; const __be32 *map_mask; int num_parent_irqs; - int ret = 0, len, irq; + int ret = 0, len; + unsigned int idx, irq; data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; - data->base = of_iomap(dn, 0); - if (!data->base) { + for (idx = 0; idx < MAX_WORDS; idx++) { + data->base[idx] = of_iomap(dn, idx); + if (!data->base[idx]) + break; + data->n_words = idx + 1; + } + if (!data->n_words) { pr_err("failed to remap intc L2 registers\n"); ret = -ENOMEM; - goto out_free; + goto out_unmap; } - if (of_property_read_u32(dn, "brcm,int-fwd-mask", &data->irq_fwd_mask)) - data->irq_fwd_mask = 0; - - /* Enable all interrupt specified in the interrupt forward mask and have - * the other disabled + /* Enable all interrupts specified in the interrupt forward mask; + * disable all others. If the property doesn't exist (-EINVAL), + * assume all zeroes. */ - __raw_writel(data->irq_fwd_mask, data->base + IRQEN); + 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->base[idx] + IRQEN); + } 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) { @@ -138,7 +175,8 @@ int __init bcm7120_l2_intc_of_init(struct device_node *dn, } map_mask = of_get_property(dn, "brcm,int-map-mask", &len); - if (!map_mask || (len != (sizeof(*map_mask) * num_parent_irqs))) { + if (!map_mask || + (len != (sizeof(*map_mask) * num_parent_irqs * data->n_words))) { pr_err("invalid brcm,int-map-mask property\n"); ret = -EINVAL; goto out_unmap; @@ -150,14 +188,14 @@ int __init bcm7120_l2_intc_of_init(struct device_node *dn, goto out_unmap; } - data->domain = irq_domain_add_linear(dn, 32, - &irq_generic_chip_ops, NULL); + data->domain = irq_domain_add_linear(dn, IRQS_PER_WORD * data->n_words, + &irq_generic_chip_ops, NULL); if (!data->domain) { ret = -ENOMEM; goto out_unmap; } - ret = irq_alloc_domain_generic_chips(data->domain, 32, 1, + ret = irq_alloc_domain_generic_chips(data->domain, IRQS_PER_WORD, 1, dn->full_name, handle_level_irq, clr, 0, IRQ_GC_INIT_MASK_CACHE); if (ret) { @@ -165,39 +203,47 @@ int __init bcm7120_l2_intc_of_init(struct device_node *dn, goto out_free_domain; } - gc = irq_get_domain_generic_chip(data->domain, 0); - gc->unused = 0xffffffff & ~data->irq_map_mask; - gc->reg_base = data->base; - gc->private = data; - ct = gc->chip_types; - - ct->regs.mask = IRQEN; - ct->chip.irq_mask = irq_gc_mask_clr_bit; - ct->chip.irq_unmask = irq_gc_mask_set_bit; - ct->chip.irq_ack = irq_gc_noop; - ct->chip.irq_suspend = bcm7120_l2_intc_suspend; - ct->chip.irq_resume = bcm7120_l2_intc_resume; - - if (of_property_read_bool(dn, "brcm,irq-can-wake")) { + if (of_property_read_bool(dn, "brcm,irq-can-wake")) data->can_wake = true; - /* This IRQ chip can wake the system, set all relevant child - * interupts in wake_enabled mask - */ - gc->wake_enabled = 0xffffffff; - gc->wake_enabled &= ~gc->unused; - ct->chip.irq_set_wake = irq_gc_set_wake; + + for (idx = 0; idx < data->n_words; idx++) { + irq = idx * IRQS_PER_WORD; + gc = irq_get_domain_generic_chip(data->domain, irq); + + gc->unused = 0xffffffff & ~data->irq_map_mask[idx]; + gc->reg_base = data->base[idx]; + gc->private = data; + ct = gc->chip_types; + + ct->regs.mask = IRQEN; + ct->chip.irq_mask = irq_gc_mask_clr_bit; + ct->chip.irq_unmask = irq_gc_mask_set_bit; + ct->chip.irq_ack = irq_gc_noop; + ct->chip.irq_suspend = bcm7120_l2_intc_suspend; + ct->chip.irq_resume = bcm7120_l2_intc_resume; + + if (data->can_wake) { + /* This IRQ chip can wake the system, set all + * relevant child interupts in wake_enabled mask + */ + gc->wake_enabled = 0xffffffff; + gc->wake_enabled &= ~gc->unused; + ct->chip.irq_set_wake = irq_gc_set_wake; + } } pr_info("registered BCM7120 L2 intc (mem: 0x%p, parent IRQ(s): %d)\n", - data->base, num_parent_irqs); + data->base[0], num_parent_irqs); return 0; out_free_domain: irq_domain_remove(data->domain); out_unmap: - iounmap(data->base); -out_free: + for (idx = 0; idx < MAX_WORDS; idx++) { + if (data->base[idx]) + iounmap(data->base[idx]); + } kfree(data); return ret; } -- cgit v1.2.3-59-g8ed1b From 14c255d35b25126149fb2fd199b030404229af65 Mon Sep 17 00:00:00 2001 From: Abhilash Kesavan Date: Thu, 9 Oct 2014 19:24:31 +0530 Subject: pinctrl: exynos: Add irq_chip instance for Exynos7 wakeup interrupts Exynos7 uses different offsets for wakeup interrupt configuration registers. So a new irq_chip instance for Exynos7 wakeup interrupts is added. The irq_chip selection is now based on the wakeup interrupt controller compatible string. Signed-off-by: Abhilash Kesavan Reviewed-by: Thomas Abraham Tested-by: Thomas Abraham Acked-by: Tomasz Figa Cc: Linus Walleij Signed-off-by: Tomasz Figa --- .../bindings/pinctrl/samsung-pinctrl.txt | 2 + drivers/pinctrl/samsung/pinctrl-exynos.c | 45 +++++++++++++++++----- drivers/pinctrl/samsung/pinctrl-exynos.h | 3 ++ 3 files changed, 40 insertions(+), 10 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt index e82aaf492517..f80519a98df8 100644 --- a/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt +++ b/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt @@ -136,6 +136,8 @@ B. External Wakeup Interrupts: For supporting external wakeup interrupts, a found on Samsung S3C64xx SoCs, - samsung,exynos4210-wakeup-eint: represents wakeup interrupt controller found on Samsung Exynos4210 and S5PC110/S5PV210 SoCs. + - samsung,exynos7-wakeup-eint: represents wakeup interrupt controller + found on Samsung Exynos7 SoC. - interrupt-parent: phandle of the interrupt parent to which the external wakeup interrupts are forwarded to. - interrupts: interrupt used by multiplexed wakeup interrupts. diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.c b/drivers/pinctrl/samsung/pinctrl-exynos.c index 7a7eb6a271eb..d97765c20466 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos.c @@ -56,12 +56,6 @@ static const struct samsung_pin_bank_type bank_type_alive = { .reg_offset = { 0x00, 0x04, 0x08, 0x0c, }, }; -/* list of external wakeup controllers supported */ -static const struct of_device_id exynos_wkup_irq_ids[] = { - { .compatible = "samsung,exynos4210-wakeup-eint", }, - { } -}; - static void exynos_irq_mask(struct irq_data *irqd) { struct irq_chip *chip = irq_data_get_irq_chip(irqd); @@ -384,9 +378,9 @@ static int exynos_wkup_irq_set_wake(struct irq_data *irqd, unsigned int on) /* * irq_chip for wakeup interrupts */ -static struct exynos_irq_chip exynos_wkup_irq_chip = { +static struct exynos_irq_chip exynos4210_wkup_irq_chip __initdata = { .chip = { - .name = "exynos_wkup_irq_chip", + .name = "exynos4210_wkup_irq_chip", .irq_unmask = exynos_irq_unmask, .irq_mask = exynos_irq_mask, .irq_ack = exynos_irq_ack, @@ -400,6 +394,31 @@ static struct exynos_irq_chip exynos_wkup_irq_chip = { .eint_pend = EXYNOS_WKUP_EPEND_OFFSET, }; +static struct exynos_irq_chip exynos7_wkup_irq_chip __initdata = { + .chip = { + .name = "exynos7_wkup_irq_chip", + .irq_unmask = exynos_irq_unmask, + .irq_mask = exynos_irq_mask, + .irq_ack = exynos_irq_ack, + .irq_set_type = exynos_irq_set_type, + .irq_set_wake = exynos_wkup_irq_set_wake, + .irq_request_resources = exynos_irq_request_resources, + .irq_release_resources = exynos_irq_release_resources, + }, + .eint_con = EXYNOS7_WKUP_ECON_OFFSET, + .eint_mask = EXYNOS7_WKUP_EMASK_OFFSET, + .eint_pend = EXYNOS7_WKUP_EPEND_OFFSET, +}; + +/* list of external wakeup controllers supported */ +static const struct of_device_id exynos_wkup_irq_ids[] = { + { .compatible = "samsung,exynos4210-wakeup-eint", + .data = &exynos4210_wkup_irq_chip }, + { .compatible = "samsung,exynos7-wakeup-eint", + .data = &exynos7_wkup_irq_chip }, + { } +}; + /* interrupt handler for wakeup interrupts 0..15 */ static void exynos_irq_eint0_15(unsigned int irq, struct irq_desc *desc) { @@ -468,12 +487,18 @@ static int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d) struct samsung_pin_bank *bank; struct exynos_weint_data *weint_data; struct exynos_muxed_weint_data *muxed_data; + struct exynos_irq_chip *irq_chip; unsigned int muxed_banks = 0; unsigned int i; int idx, irq; for_each_child_of_node(dev->of_node, np) { - if (of_match_node(exynos_wkup_irq_ids, np)) { + const struct of_device_id *match; + + match = of_match_node(exynos_wkup_irq_ids, np); + if (match) { + irq_chip = kmemdup(match->data, + sizeof(*irq_chip), GFP_KERNEL); wkup_np = np; break; } @@ -493,7 +518,7 @@ static int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d) return -ENXIO; } - bank->irq_chip = &exynos_wkup_irq_chip; + bank->irq_chip = irq_chip; if (!of_find_property(bank->of_node, "interrupts", NULL)) { bank->eint_type = EINT_TYPE_WKUP_MUX; diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.h b/drivers/pinctrl/samsung/pinctrl-exynos.h index 3c91c357792f..0f0f7cedb2dc 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos.h +++ b/drivers/pinctrl/samsung/pinctrl-exynos.h @@ -25,6 +25,9 @@ #define EXYNOS_WKUP_ECON_OFFSET 0xE00 #define EXYNOS_WKUP_EMASK_OFFSET 0xF00 #define EXYNOS_WKUP_EPEND_OFFSET 0xF40 +#define EXYNOS7_WKUP_ECON_OFFSET 0x700 +#define EXYNOS7_WKUP_EMASK_OFFSET 0x900 +#define EXYNOS7_WKUP_EPEND_OFFSET 0xA00 #define EXYNOS_SVC_OFFSET 0xB08 #define EXYNOS_EINT_FUNC 0xF -- cgit v1.2.3-59-g8ed1b From 50cea0cff7131b364c0ff80dedf8e91212b18a26 Mon Sep 17 00:00:00 2001 From: Naveen Krishna Ch Date: Thu, 9 Oct 2014 19:24:32 +0530 Subject: pinctrl: exynos: Add initial driver data for Exynos7 This patch adds initial driver data for Exynos7 pinctrl support. Signed-off-by: Naveen Krishna Ch Signed-off-by: Abhilash Kesavan Reviewed-by: Thomas Abraham Tested-by: Thomas Abraham Acked-by: Tomasz Figa Cc: Linus Walleij Signed-off-by: Tomasz Figa --- .../bindings/pinctrl/samsung-pinctrl.txt | 1 + drivers/pinctrl/samsung/pinctrl-exynos.c | 105 +++++++++++++++++++++ drivers/pinctrl/samsung/pinctrl-samsung.c | 2 + drivers/pinctrl/samsung/pinctrl-samsung.h | 1 + 4 files changed, 109 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt index f80519a98df8..8425838a6dff 100644 --- a/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt +++ b/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt @@ -18,6 +18,7 @@ Required Properties: - "samsung,exynos5250-pinctrl": for Exynos5250 compatible pin-controller. - "samsung,exynos5260-pinctrl": for Exynos5260 compatible pin-controller. - "samsung,exynos5420-pinctrl": for Exynos5420 compatible pin-controller. + - "samsung,exynos7-pinctrl": for Exynos7 compatible pin-controller. - reg: Base address of the pin controller hardware module and length of the address space it occupies. diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.c b/drivers/pinctrl/samsung/pinctrl-exynos.c index d97765c20466..5622d8a3e478 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos.c @@ -1164,3 +1164,108 @@ const struct samsung_pin_ctrl exynos5420_pin_ctrl[] __initconst = { .eint_gpio_init = exynos_eint_gpio_init, }, }; + +/* pin banks of exynos7 pin-controller - ALIVE */ +static const struct samsung_pin_bank_data exynos7_pin_banks0[] __initconst = { + EXYNOS_PIN_BANK_EINTW(8, 0x000, "gpa0", 0x00), + EXYNOS_PIN_BANK_EINTW(8, 0x020, "gpa1", 0x04), + EXYNOS_PIN_BANK_EINTW(8, 0x040, "gpa2", 0x08), + EXYNOS_PIN_BANK_EINTW(8, 0x060, "gpa3", 0x0c), +}; + +/* pin banks of exynos7 pin-controller - BUS0 */ +static const struct samsung_pin_bank_data exynos7_pin_banks1[] __initconst = { + EXYNOS_PIN_BANK_EINTG(5, 0x000, "gpb0", 0x00), + EXYNOS_PIN_BANK_EINTG(8, 0x020, "gpc0", 0x04), + EXYNOS_PIN_BANK_EINTG(2, 0x040, "gpc1", 0x08), + EXYNOS_PIN_BANK_EINTG(6, 0x060, "gpc2", 0x0c), + EXYNOS_PIN_BANK_EINTG(8, 0x080, "gpc3", 0x10), + EXYNOS_PIN_BANK_EINTG(4, 0x0a0, "gpd0", 0x14), + EXYNOS_PIN_BANK_EINTG(6, 0x0c0, "gpd1", 0x18), + EXYNOS_PIN_BANK_EINTG(8, 0x0e0, "gpd2", 0x1c), + EXYNOS_PIN_BANK_EINTG(5, 0x100, "gpd4", 0x20), + EXYNOS_PIN_BANK_EINTG(4, 0x120, "gpd5", 0x24), + EXYNOS_PIN_BANK_EINTG(6, 0x140, "gpd6", 0x28), + EXYNOS_PIN_BANK_EINTG(3, 0x160, "gpd7", 0x2c), + EXYNOS_PIN_BANK_EINTG(2, 0x180, "gpd8", 0x30), + EXYNOS_PIN_BANK_EINTG(2, 0x1a0, "gpg0", 0x34), + EXYNOS_PIN_BANK_EINTG(4, 0x1c0, "gpg3", 0x38), +}; + +/* pin banks of exynos7 pin-controller - NFC */ +static const struct samsung_pin_bank_data exynos7_pin_banks2[] __initconst = { + EXYNOS_PIN_BANK_EINTG(3, 0x000, "gpj0", 0x00), +}; + +/* pin banks of exynos7 pin-controller - TOUCH */ +static const struct samsung_pin_bank_data exynos7_pin_banks3[] __initconst = { + EXYNOS_PIN_BANK_EINTG(3, 0x000, "gpj1", 0x00), +}; + +/* pin banks of exynos7 pin-controller - FF */ +static const struct samsung_pin_bank_data exynos7_pin_banks4[] __initconst = { + EXYNOS_PIN_BANK_EINTG(4, 0x000, "gpg4", 0x00), +}; + +/* pin banks of exynos7 pin-controller - ESE */ +static const struct samsung_pin_bank_data exynos7_pin_banks5[] __initconst = { + EXYNOS_PIN_BANK_EINTG(5, 0x000, "gpv7", 0x00), +}; + +/* pin banks of exynos7 pin-controller - FSYS0 */ +static const struct samsung_pin_bank_data exynos7_pin_banks6[] __initconst = { + EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpr4", 0x00), +}; + +/* pin banks of exynos7 pin-controller - FSYS1 */ +static const struct samsung_pin_bank_data exynos7_pin_banks7[] __initconst = { + EXYNOS_PIN_BANK_EINTG(4, 0x000, "gpr0", 0x00), + EXYNOS_PIN_BANK_EINTG(8, 0x020, "gpr1", 0x04), + EXYNOS_PIN_BANK_EINTG(5, 0x040, "gpr2", 0x08), + EXYNOS_PIN_BANK_EINTG(8, 0x060, "gpr3", 0x0c), +}; + +const struct samsung_pin_ctrl exynos7_pin_ctrl[] __initconst = { + { + /* pin-controller instance 0 Alive data */ + .pin_banks = exynos7_pin_banks0, + .nr_banks = ARRAY_SIZE(exynos7_pin_banks0), + .eint_gpio_init = exynos_eint_gpio_init, + .eint_wkup_init = exynos_eint_wkup_init, + }, { + /* pin-controller instance 1 BUS0 data */ + .pin_banks = exynos7_pin_banks1, + .nr_banks = ARRAY_SIZE(exynos7_pin_banks1), + .eint_gpio_init = exynos_eint_gpio_init, + }, { + /* pin-controller instance 2 NFC data */ + .pin_banks = exynos7_pin_banks2, + .nr_banks = ARRAY_SIZE(exynos7_pin_banks2), + .eint_gpio_init = exynos_eint_gpio_init, + }, { + /* pin-controller instance 3 TOUCH data */ + .pin_banks = exynos7_pin_banks3, + .nr_banks = ARRAY_SIZE(exynos7_pin_banks3), + .eint_gpio_init = exynos_eint_gpio_init, + }, { + /* pin-controller instance 4 FF data */ + .pin_banks = exynos7_pin_banks4, + .nr_banks = ARRAY_SIZE(exynos7_pin_banks4), + .eint_gpio_init = exynos_eint_gpio_init, + }, { + /* pin-controller instance 5 ESE data */ + .pin_banks = exynos7_pin_banks5, + .nr_banks = ARRAY_SIZE(exynos7_pin_banks5), + .eint_gpio_init = exynos_eint_gpio_init, + }, { + /* pin-controller instance 6 FSYS0 data */ + .pin_banks = exynos7_pin_banks6, + .nr_banks = ARRAY_SIZE(exynos7_pin_banks6), + .eint_gpio_init = exynos_eint_gpio_init, + }, { + /* pin-controller instance 7 FSYS1 data */ + .pin_banks = exynos7_pin_banks7, + .nr_banks = ARRAY_SIZE(exynos7_pin_banks7), + .eint_gpio_init = exynos_eint_gpio_init, + }, +}; diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.c b/drivers/pinctrl/samsung/pinctrl-samsung.c index 96ef6e50f1f6..e5a81503f533 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.c +++ b/drivers/pinctrl/samsung/pinctrl-samsung.c @@ -1239,6 +1239,8 @@ static const struct of_device_id samsung_pinctrl_dt_match[] = { .data = (void *)exynos5420_pin_ctrl }, { .compatible = "samsung,s5pv210-pinctrl", .data = (void *)s5pv210_pin_ctrl }, + { .compatible = "samsung,exynos7-pinctrl", + .data = (void *)exynos7_pin_ctrl }, #endif #ifdef CONFIG_PINCTRL_S3C64XX { .compatible = "samsung,s3c64xx-pinctrl", diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.h b/drivers/pinctrl/samsung/pinctrl-samsung.h index 3076b8b591c7..29004be52eaa 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.h +++ b/drivers/pinctrl/samsung/pinctrl-samsung.h @@ -270,6 +270,7 @@ extern const struct samsung_pin_ctrl exynos4x12_pin_ctrl[]; extern const struct samsung_pin_ctrl exynos5250_pin_ctrl[]; extern const struct samsung_pin_ctrl exynos5260_pin_ctrl[]; extern const struct samsung_pin_ctrl exynos5420_pin_ctrl[]; +extern const struct samsung_pin_ctrl exynos7_pin_ctrl[]; extern const struct samsung_pin_ctrl s3c64xx_pin_ctrl[]; extern const struct samsung_pin_ctrl s3c2412_pin_ctrl[]; extern const struct samsung_pin_ctrl s3c2416_pin_ctrl[]; -- cgit v1.2.3-59-g8ed1b From fc3756faa71e51664e3d43b401c273723047a049 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 6 Nov 2014 12:52:08 +0100 Subject: i2c: sh_mobile: Document SoC-specific bindings Explicitly list the various SoC-specific compatible properties. This allows checkpatch to validate DTSes. Signed-off-by: Geert Uytterhoeven Acked-by: Simon Horman Signed-off-by: Wolfram Sang --- Documentation/devicetree/bindings/i2c/i2c-sh_mobile.txt | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/i2c/i2c-sh_mobile.txt b/Documentation/devicetree/bindings/i2c/i2c-sh_mobile.txt index d2153ce36fa8..c33e9a32d496 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-sh_mobile.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-sh_mobile.txt @@ -2,6 +2,15 @@ Device tree configuration for Renesas IIC (sh_mobile) driver Required properties: - compatible : "renesas,iic-". "renesas,rmobile-iic" as fallback + Examples with soctypes are: + - "renesas,iic-r8a73a4" (R-Mobile APE6) + - "renesas,iic-r8a7740" (R-Mobile A1) + - "renesas,iic-r8a7790" (R-Car H2) + - "renesas,iic-r8a7791" (R-Car M2-W) + - "renesas,iic-r8a7792" (R-Car V2H) + - "renesas,iic-r8a7793" (R-Car M2-N) + - "renesas,iic-r8a7794" (R-Car E2) + - "renesas,iic-sh73a0" (SH-Mobile AG5) - reg : address start and address range size of device - interrupts : interrupt of device - clocks : clock for device -- cgit v1.2.3-59-g8ed1b From 0654bb3cdd5142ca8bf27a4f72bf22098394fbd5 Mon Sep 17 00:00:00 2001 From: Sebastian Hesselbarth Date: Tue, 21 Oct 2014 11:22:41 +0200 Subject: mmc: sdhci-pxav3: Document clocks and additional clock-names property Now that sdhci-pxav3 driver allows to have more than one IP clock defined, document both clocks and clock-names properties. Signed-off-by: Sebastian Hesselbarth Signed-off-by: Ulf Hansson --- Documentation/devicetree/bindings/mmc/sdhci-pxa.txt | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mmc/sdhci-pxa.txt b/Documentation/devicetree/bindings/mmc/sdhci-pxa.txt index 86223c3eda90..4dd6deb90719 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-pxa.txt +++ b/Documentation/devicetree/bindings/mmc/sdhci-pxa.txt @@ -12,6 +12,10 @@ Required properties: * for "marvell,armada-380-sdhci", two register areas. The first one for the SDHCI registers themselves, and the second one for the AXI/Mbus bridge registers of the SDHCI unit. +- clocks: Array of clocks required for SDHCI; requires at least one for + I/O clock. +- clock-names: Array of names corresponding to clocks property; shall be + "io" for I/O clock and "core" for optional core clock. Optional properties: - mrvl,clk-delay-cycles: Specify a number of cycles to delay for tuning. @@ -23,6 +27,8 @@ sdhci@d4280800 { reg = <0xd4280800 0x800>; bus-width = <8>; interrupts = <27>; + clocks = <&chip CLKID_SDIO1XIN>, <&chip CLKID_SDIO1>; + clock-names = "io", "core"; non-removable; mrvl,clk-delay-cycles = <31>; }; @@ -32,5 +38,6 @@ sdhci@d8000 { reg = <0xd8000 0x1000>, <0xdc000 0x100>; interrupts = <0 25 0x4>; clocks = <&gateclk 17>; + clock-names = "io"; mrvl,clk-delay-cycles = <0x1F>; }; -- cgit v1.2.3-59-g8ed1b From b155aa0e5a81ea1f05ff7aced0ec8e34c980c19e Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Wed, 22 Oct 2014 14:30:58 +0100 Subject: dm cache policy mq: tweak algorithm that decides when to promote a block Rather than maintaining a separate promote_threshold variable that we periodically update we now use the hit count of the oldest clean block. Also add a fudge factor to discourage demoting dirty blocks. With some tests this has a sizeable difference, because the old code was too eager to demote blocks. For example, device-mapper-test-suite's git_extract_cache_quick test goes from taking 190 seconds, to 142 (linear on spindle takes 250). Signed-off-by: Joe Thornber Signed-off-by: Mike Snitzer --- Documentation/device-mapper/cache-policies.txt | 6 +-- drivers/md/dm-cache-policy-mq.c | 75 +++++++++++++++++--------- 2 files changed, 53 insertions(+), 28 deletions(-) (limited to 'Documentation') diff --git a/Documentation/device-mapper/cache-policies.txt b/Documentation/device-mapper/cache-policies.txt index 66c2774c0c64..7746e5dbfd40 100644 --- a/Documentation/device-mapper/cache-policies.txt +++ b/Documentation/device-mapper/cache-policies.txt @@ -58,9 +58,9 @@ since spindles tend to have good bandwidth. The io_tracker counts contiguous I/Os to try to spot when the io is in one of these sequential modes. -Internally the mq policy maintains a promotion threshold variable. If -the hit count of a block not in the cache goes above this threshold it -gets promoted to the cache. The read, write and discard promote adjustment +Internally the mq policy determines a promotion threshold. If the hit +count of a block not in the cache goes above this threshold it gets +promoted to the cache. The read, write and discard promote adjustment tunables allow you to tweak the promotion threshold by adding a small value based on the io type. They default to 4, 8 and 1 respectively. If you're trying to quickly warm a new cache device you may wish to diff --git a/drivers/md/dm-cache-policy-mq.c b/drivers/md/dm-cache-policy-mq.c index 0e385e40909e..334d098d720d 100644 --- a/drivers/md/dm-cache-policy-mq.c +++ b/drivers/md/dm-cache-policy-mq.c @@ -181,24 +181,30 @@ static void queue_shift_down(struct queue *q) * Gives us the oldest entry of the lowest popoulated level. If the first * level is emptied then we shift down one level. */ -static struct list_head *queue_pop(struct queue *q) +static struct list_head *queue_peek(struct queue *q) { unsigned level; - struct list_head *r; for (level = 0; level < NR_QUEUE_LEVELS; level++) - if (!list_empty(q->qs + level)) { - r = q->qs[level].next; - list_del(r); + if (!list_empty(q->qs + level)) + return q->qs[level].next; - /* have we just emptied the bottom level? */ - if (level == 0 && list_empty(q->qs)) - queue_shift_down(q); + return NULL; +} - return r; - } +static struct list_head *queue_pop(struct queue *q) +{ + struct list_head *r = queue_peek(q); - return NULL; + if (r) { + list_del(r); + + /* have we just emptied the bottom level? */ + if (list_empty(q->qs)) + queue_shift_down(q); + } + + return r; } static struct list_head *list_pop(struct list_head *lh) @@ -383,13 +389,6 @@ struct mq_policy { unsigned generation; unsigned generation_period; /* in lookups (will probably change) */ - /* - * Entries in the pre_cache whose hit count passes the promotion - * threshold move to the cache proper. Working out the correct - * value for the promotion_threshold is crucial to this policy. - */ - unsigned promote_threshold; - unsigned discard_promote_adjustment; unsigned read_promote_adjustment; unsigned write_promote_adjustment; @@ -406,6 +405,7 @@ struct mq_policy { #define DEFAULT_DISCARD_PROMOTE_ADJUSTMENT 1 #define DEFAULT_READ_PROMOTE_ADJUSTMENT 4 #define DEFAULT_WRITE_PROMOTE_ADJUSTMENT 8 +#define DISCOURAGE_DEMOTING_DIRTY_THRESHOLD 128 /*----------------------------------------------------------------*/ @@ -518,6 +518,12 @@ static struct entry *pop(struct mq_policy *mq, struct queue *q) return e; } +static struct entry *peek(struct queue *q) +{ + struct list_head *h = queue_peek(q); + return h ? container_of(h, struct entry, list) : NULL; +} + /* * Has this entry already been updated? */ @@ -570,10 +576,6 @@ static void check_generation(struct mq_policy *mq) break; } } - - mq->promote_threshold = nr ? total / nr : 1; - if (mq->promote_threshold * nr < total) - mq->promote_threshold++; } } @@ -640,6 +642,30 @@ static int demote_cblock(struct mq_policy *mq, dm_oblock_t *oblock) return 0; } +/* + * Entries in the pre_cache whose hit count passes the promotion + * threshold move to the cache proper. Working out the correct + * value for the promotion_threshold is crucial to this policy. + */ +static unsigned promote_threshold(struct mq_policy *mq) +{ + struct entry *e; + + if (any_free_cblocks(mq)) + return 0; + + e = peek(&mq->cache_clean); + if (e) + return e->hit_count; + + e = peek(&mq->cache_dirty); + if (e) + return e->hit_count + DISCOURAGE_DEMOTING_DIRTY_THRESHOLD; + + /* This should never happen */ + return 0; +} + /* * We modify the basic promotion_threshold depending on the specific io. * @@ -653,7 +679,7 @@ static unsigned adjusted_promote_threshold(struct mq_policy *mq, bool discarded_oblock, int data_dir) { if (data_dir == READ) - return mq->promote_threshold + mq->read_promote_adjustment; + return promote_threshold(mq) + mq->read_promote_adjustment; if (discarded_oblock && (any_free_cblocks(mq) || any_clean_cblocks(mq))) { /* @@ -663,7 +689,7 @@ static unsigned adjusted_promote_threshold(struct mq_policy *mq, return mq->discard_promote_adjustment; } - return mq->promote_threshold + mq->write_promote_adjustment; + return promote_threshold(mq) + mq->write_promote_adjustment; } static bool should_promote(struct mq_policy *mq, struct entry *e, @@ -1230,7 +1256,6 @@ static struct dm_cache_policy *mq_create(dm_cblock_t cache_size, mq->tick = 0; mq->hit_count = 0; mq->generation = 0; - mq->promote_threshold = 0; mq->discard_promote_adjustment = DEFAULT_DISCARD_PROMOTE_ADJUSTMENT; mq->read_promote_adjustment = DEFAULT_READ_PROMOTE_ADJUSTMENT; mq->write_promote_adjustment = DEFAULT_WRITE_PROMOTE_ADJUSTMENT; -- cgit v1.2.3-59-g8ed1b From f1afb36a6102b52949c2c6d8eb250eddcce3fc5f Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Thu, 30 Oct 2014 10:02:01 -0400 Subject: dm cache policy mq: simplify ability to promote sequential IO to the cache Before, if the user wanted sequential IO to be promoted to the cache they'd have to set sequential_threshold to some nebulous large value. Now, the user may easily disable sequential IO detection (and sequential IO's implicit bypass of the cache) by setting sequential_threshold to 0. Signed-off-by: Mike Snitzer --- Documentation/device-mapper/cache-policies.txt | 16 +++++++++++----- drivers/md/dm-cache-policy-mq.c | 7 ++++--- 2 files changed, 15 insertions(+), 8 deletions(-) (limited to 'Documentation') diff --git a/Documentation/device-mapper/cache-policies.txt b/Documentation/device-mapper/cache-policies.txt index 7746e5dbfd40..0d124a971801 100644 --- a/Documentation/device-mapper/cache-policies.txt +++ b/Documentation/device-mapper/cache-policies.txt @@ -47,16 +47,22 @@ Message and constructor argument pairs are: 'discard_promote_adjustment ' The sequential threshold indicates the number of contiguous I/Os -required before a stream is treated as sequential. The random threshold +required before a stream is treated as sequential. Once a stream is +considered sequential it will bypass the cache. The random threshold is the number of intervening non-contiguous I/Os that must be seen before the stream is treated as random again. The sequential and random thresholds default to 512 and 4 respectively. -Large, sequential ios are probably better left on the origin device -since spindles tend to have good bandwidth. The io_tracker counts -contiguous I/Os to try to spot when the io is in one of these sequential -modes. +Large, sequential I/Os are probably better left on the origin device +since spindles tend to have good sequential I/O bandwidth. The +io_tracker counts contiguous I/Os to try to spot when the I/O is in one +of these sequential modes. But there are use-cases for wanting to +promote sequential blocks to the cache (e.g. fast application startup). +If sequential threshold is set to 0 the sequential I/O detection is +disabled and sequential I/O will no longer implicitly bypass the cache. +Setting the random threshold to 0 does _not_ disable the random I/O +stream detection. Internally the mq policy determines a promotion threshold. If the hit count of a block not in the cache goes above this threshold it gets diff --git a/drivers/md/dm-cache-policy-mq.c b/drivers/md/dm-cache-policy-mq.c index 334d098d720d..13f547a4eeb6 100644 --- a/drivers/md/dm-cache-policy-mq.c +++ b/drivers/md/dm-cache-policy-mq.c @@ -865,7 +865,8 @@ static int map(struct mq_policy *mq, dm_oblock_t oblock, if (e && in_cache(mq, e)) r = cache_entry_found(mq, e, result); - else if (iot_pattern(&mq->tracker) == PATTERN_SEQUENTIAL) + else if (mq->tracker.thresholds[PATTERN_SEQUENTIAL] && + iot_pattern(&mq->tracker) == PATTERN_SEQUENTIAL) result->op = POLICY_MISS; else if (e) @@ -1290,7 +1291,7 @@ bad_pre_cache_init: static struct dm_cache_policy_type mq_policy_type = { .name = "mq", - .version = {1, 2, 0}, + .version = {1, 3, 0}, .hint_size = 4, .owner = THIS_MODULE, .create = mq_create @@ -1298,7 +1299,7 @@ static struct dm_cache_policy_type mq_policy_type = { static struct dm_cache_policy_type default_policy_type = { .name = "default", - .version = {1, 2, 0}, + .version = {1, 3, 0}, .hint_size = 4, .owner = THIS_MODULE, .create = mq_create, -- cgit v1.2.3-59-g8ed1b From 126e31faa12c0d40c3b603adb9ac6d72dd424860 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Sat, 8 Nov 2014 10:30:32 +1100 Subject: w1: omap-hdq: support device probing with device-tree This driver has no 'compatible' string and so is not found when using device-tree. Add one with value to match hdqw1w: 1w@480b2000 { device in omap3.dtsi. Signed-off-by: NeilBrown Acked-by: Evgeniy Polyakov Signed-off-by: Tony Lindgren --- Documentation/devicetree/bindings/w1/omap-hdq.txt | 17 +++++++++++++++++ drivers/w1/masters/omap_hdq.c | 7 +++++++ 2 files changed, 24 insertions(+) create mode 100644 Documentation/devicetree/bindings/w1/omap-hdq.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/w1/omap-hdq.txt b/Documentation/devicetree/bindings/w1/omap-hdq.txt new file mode 100644 index 000000000000..fef794741bd1 --- /dev/null +++ b/Documentation/devicetree/bindings/w1/omap-hdq.txt @@ -0,0 +1,17 @@ +* OMAP HDQ One wire bus master controller + +Required properties: +- compatible : should be "ti,omap3-1w" +- reg : Address and length of the register set for the device +- interrupts : interrupt line. +- ti,hwmods : "hdq1w" + +Example: + +- From omap3.dtsi + hdqw1w: 1w@480b2000 { + compatible = "ti,omap3-1w"; + reg = <0x480b2000 0x1000>; + interrupts = <58>; + ti,hwmods = "hdq1w"; + }; diff --git a/drivers/w1/masters/omap_hdq.c b/drivers/w1/masters/omap_hdq.c index 9900e8ec7393..03321d6a2684 100644 --- a/drivers/w1/masters/omap_hdq.c +++ b/drivers/w1/masters/omap_hdq.c @@ -72,11 +72,18 @@ struct hdq_data { static int omap_hdq_probe(struct platform_device *pdev); static int omap_hdq_remove(struct platform_device *pdev); +static struct of_device_id omap_hdq_dt_ids[] = { + { .compatible = "ti,omap3-1w" }, + {} +}; +MODULE_DEVICE_TABLE(of, omap_hdq_dt_ids); + static struct platform_driver omap_hdq_driver = { .probe = omap_hdq_probe, .remove = omap_hdq_remove, .driver = { .name = "omap_hdq", + .of_match_table = omap_hdq_dt_ids, }, }; -- cgit v1.2.3-59-g8ed1b From 93746e70be83a3f113134a16065957b324af50f7 Mon Sep 17 00:00:00 2001 From: Emilio López Date: Thu, 6 Nov 2014 11:40:29 +0800 Subject: clk: sunxi: unify APB1 clock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit unifies the APB1 mux with the APB1 clock, using the new factors infrastructure. Signed-off-by: Emilio López [wens@csie.org: Add mux mask bits] Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- Documentation/devicetree/bindings/clock/sunxi.txt | 1 - drivers/clk/sunxi/clk-sunxi.c | 7 ++----- 2 files changed, 2 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt index 0455cb9caa97..6ddcf6e10eb8 100644 --- a/Documentation/devicetree/bindings/clock/sunxi.txt +++ b/Documentation/devicetree/bindings/clock/sunxi.txt @@ -45,7 +45,6 @@ Required properties: "allwinner,sun9i-a80-apb0-gates-clk" - for the APB0 gates on A80 "allwinner,sun4i-a10-apb1-clk" - for the APB1 clock "allwinner,sun9i-a80-apb1-clk" - for the APB1 bus clock on A80 - "allwinner,sun4i-a10-apb1-mux-clk" - for the APB1 clock muxing "allwinner,sun4i-a10-apb1-gates-clk" - for the APB1 gates on A10 "allwinner,sun5i-a13-apb1-gates-clk" - for the APB1 gates on A13 "allwinner,sun5i-a10s-apb1-gates-clk" - for the APB1 gates on A10s diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c index 20f47c68a946..4133e278212b 100644 --- a/drivers/clk/sunxi/clk-sunxi.c +++ b/drivers/clk/sunxi/clk-sunxi.c @@ -507,6 +507,8 @@ static const struct factors_data sun6i_a31_pll6_data __initconst = { }; static const struct factors_data sun4i_apb1_data __initconst = { + .mux = 24, + .muxmask = BIT(1) | BIT(0), .table = &sun4i_apb1_config, .getter = sun4i_get_apb1_factors, }; @@ -545,10 +547,6 @@ static const struct mux_data sun6i_a31_ahb1_mux_data __initconst = { .shift = 12, }; -static const struct mux_data sun4i_apb1_mux_data __initconst = { - .shift = 24, -}; - static void __init sunxi_mux_clk_setup(struct device_node *node, struct mux_data *data) { @@ -1109,7 +1107,6 @@ static const struct of_device_id clk_divs_match[] __initconst = { /* Matches for mux clocks */ static const struct of_device_id clk_mux_match[] __initconst = { {.compatible = "allwinner,sun4i-a10-cpu-clk", .data = &sun4i_cpu_mux_data,}, - {.compatible = "allwinner,sun4i-a10-apb1-mux-clk", .data = &sun4i_apb1_mux_data,}, {.compatible = "allwinner,sun6i-a31-ahb1-mux-clk", .data = &sun6i_a31_ahb1_mux_data,}, {} }; -- cgit v1.2.3-59-g8ed1b From ba7a46f16dd29f93303daeb1fee8af316c5a07f4 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 11 Nov 2014 10:59:17 -0800 Subject: net: Convert LIMIT_NETDEBUG to net_dbg_ratelimited Use the more common dynamic_debug capable net_dbg_ratelimited and remove the LIMIT_NETDEBUG macro. All messages are still ratelimited. Some KERN_ uses are changed to KERN_DEBUG. This may have some negative impact on messages that were emitted at KERN_INFO that are not not enabled at all unless DEBUG is defined or dynamic_debug is enabled. Even so, these messages are now _not_ emitted by default. This also eliminates the use of the net_msg_warn sysctl "/proc/sys/net/core/warnings". For backward compatibility, the sysctl is not removed, but it has no function. The extern declaration of net_msg_warn is removed from sock.h and made static in net/core/sysctl_net_core.c Miscellanea: o Update the sysctl documentation o Remove the embedded uses of pr_fmt o Coalesce format fragments o Realign arguments Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- Documentation/sysctl/net.txt | 12 ++++++++---- include/net/sock.h | 7 ------- include/net/udplite.h | 6 +++--- net/core/sysctl_net_core.c | 2 ++ net/core/utils.c | 3 --- net/ipv4/icmp.c | 8 ++++---- net/ipv4/inet_fragment.c | 2 +- net/ipv4/ip_fragment.c | 3 +-- net/ipv4/tcp_input.c | 8 ++++---- net/ipv4/tcp_timer.c | 18 ++++++++++-------- net/ipv4/udp.c | 30 +++++++++++++++--------------- net/ipv6/addrconf.c | 6 ++---- net/ipv6/ah6.c | 7 +++---- net/ipv6/datagram.c | 4 ++-- net/ipv6/esp6.c | 4 ++-- net/ipv6/exthdrs.c | 18 +++++++++--------- net/ipv6/icmp.c | 15 +++++++-------- net/ipv6/mip6.c | 11 ++++++----- net/ipv6/netfilter.c | 2 +- net/ipv6/udp.c | 31 +++++++++++++------------------ net/phonet/af_phonet.c | 9 +++++---- net/phonet/pep-gprs.c | 3 +-- net/phonet/pep.c | 12 ++++++------ 23 files changed, 105 insertions(+), 116 deletions(-) (limited to 'Documentation') diff --git a/Documentation/sysctl/net.txt b/Documentation/sysctl/net.txt index 04892b821157..e26c607468a6 100644 --- a/Documentation/sysctl/net.txt +++ b/Documentation/sysctl/net.txt @@ -120,10 +120,14 @@ seconds. warnings -------- -This controls console messages from the networking stack that can occur because -of problems on the network like duplicate address or bad checksums. Normally, -this should be enabled, but if the problem persists the messages can be -disabled. +This sysctl is now unused. + +This was used to control console messages from the networking stack that +occur because of problems on the network like duplicate address or bad +checksums. + +These messages are now emitted at KERN_DEBUG and can generally be enabled +and controlled by the dynamic_debug facility. netdev_budget ------------- diff --git a/include/net/sock.h b/include/net/sock.h index 7789b59c0c40..83a669f83bae 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -2288,13 +2288,6 @@ bool sk_ns_capable(const struct sock *sk, bool sk_capable(const struct sock *sk, int cap); bool sk_net_capable(const struct sock *sk, int cap); -/* - * Enable debug/info messages - */ -extern int net_msg_warn; -#define LIMIT_NETDEBUG(fmt, args...) \ - do { if (net_msg_warn && net_ratelimit()) printk(fmt,##args); } while(0) - extern __u32 sysctl_wmem_max; extern __u32 sysctl_rmem_max; diff --git a/include/net/udplite.h b/include/net/udplite.h index 2caadabcd07b..9a28a5179400 100644 --- a/include/net/udplite.h +++ b/include/net/udplite.h @@ -40,7 +40,7 @@ static inline int udplite_checksum_init(struct sk_buff *skb, struct udphdr *uh) * checksum. UDP-Lite (like IPv6) mandates checksums, hence packets * with a zero checksum field are illegal. */ if (uh->check == 0) { - LIMIT_NETDEBUG(KERN_DEBUG "UDPLite: zeroed checksum field\n"); + net_dbg_ratelimited("UDPLite: zeroed checksum field\n"); return 1; } @@ -52,8 +52,8 @@ static inline int udplite_checksum_init(struct sk_buff *skb, struct udphdr *uh) /* * Coverage length violates RFC 3828: log and discard silently. */ - LIMIT_NETDEBUG(KERN_DEBUG "UDPLite: bad csum coverage %d/%d\n", - cscov, skb->len); + net_dbg_ratelimited("UDPLite: bad csum coverage %d/%d\n", + cscov, skb->len); return 1; } else if (cscov < skb->len) { diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c index cf9cd13509a7..f93f092fe226 100644 --- a/net/core/sysctl_net_core.c +++ b/net/core/sysctl_net_core.c @@ -26,6 +26,8 @@ static int zero = 0; static int one = 1; static int ushort_max = USHRT_MAX; +static int net_msg_warn; /* Unused, but still a sysctl */ + #ifdef CONFIG_RPS static int rps_sock_flow_sysctl(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) diff --git a/net/core/utils.c b/net/core/utils.c index efc76dd9dcd1..7b803884c162 100644 --- a/net/core/utils.c +++ b/net/core/utils.c @@ -33,9 +33,6 @@ #include #include -int net_msg_warn __read_mostly = 1; -EXPORT_SYMBOL(net_msg_warn); - DEFINE_RATELIMIT_STATE(net_ratelimit_state, 5 * HZ, 10); /* * All net warning printk()s should be guarded by this function. diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 5882f584910e..36b7bfa609d6 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -784,8 +784,8 @@ static void icmp_unreach(struct sk_buff *skb) */ switch (net->ipv4.sysctl_ip_no_pmtu_disc) { default: - LIMIT_NETDEBUG(KERN_INFO pr_fmt("%pI4: fragmentation needed and DF set\n"), - &iph->daddr); + net_dbg_ratelimited("%pI4: fragmentation needed and DF set\n", + &iph->daddr); break; case 2: goto out; @@ -798,8 +798,8 @@ static void icmp_unreach(struct sk_buff *skb) } break; case ICMP_SR_FAILED: - LIMIT_NETDEBUG(KERN_INFO pr_fmt("%pI4: Source Route Failed\n"), - &iph->daddr); + net_dbg_ratelimited("%pI4: Source Route Failed\n", + &iph->daddr); break; default: break; diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c index 19419b60cb37..e7920352646a 100644 --- a/net/ipv4/inet_fragment.c +++ b/net/ipv4/inet_fragment.c @@ -458,6 +458,6 @@ void inet_frag_maybe_warn_overflow(struct inet_frag_queue *q, ". Dropping fragment.\n"; if (PTR_ERR(q) == -ENOBUFS) - LIMIT_NETDEBUG(KERN_WARNING "%s%s", prefix, msg); + net_dbg_ratelimited("%s%s", prefix, msg); } EXPORT_SYMBOL(inet_frag_maybe_warn_overflow); diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 4d964dadd655..e5b6d0ddcb58 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -618,8 +618,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev, return 0; out_nomem: - LIMIT_NETDEBUG(KERN_ERR pr_fmt("queue_glue: no memory for gluing queue %p\n"), - qp); + net_dbg_ratelimited("queue_glue: no memory for gluing queue %p\n", qp); err = -ENOMEM; goto out_fail; out_oversize: diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 5f979c7f5135..d91436ba17ea 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -5854,12 +5854,12 @@ static inline void pr_drop_req(struct request_sock *req, __u16 port, int family) struct inet_request_sock *ireq = inet_rsk(req); if (family == AF_INET) - LIMIT_NETDEBUG(KERN_DEBUG pr_fmt("drop open request from %pI4/%u\n"), - &ireq->ir_rmt_addr, port); + net_dbg_ratelimited("drop open request from %pI4/%u\n", + &ireq->ir_rmt_addr, port); #if IS_ENABLED(CONFIG_IPV6) else if (family == AF_INET6) - LIMIT_NETDEBUG(KERN_DEBUG pr_fmt("drop open request from %pI6/%u\n"), - &ireq->ir_v6_rmt_addr, port); + net_dbg_ratelimited("drop open request from %pI6/%u\n", + &ireq->ir_v6_rmt_addr, port); #endif } diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index 9b21ae8b2e31..1829c7fbc77e 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -374,17 +374,19 @@ void tcp_retransmit_timer(struct sock *sk) */ struct inet_sock *inet = inet_sk(sk); if (sk->sk_family == AF_INET) { - LIMIT_NETDEBUG(KERN_DEBUG pr_fmt("Peer %pI4:%u/%u unexpectedly shrunk window %u:%u (repaired)\n"), - &inet->inet_daddr, - ntohs(inet->inet_dport), inet->inet_num, - tp->snd_una, tp->snd_nxt); + net_dbg_ratelimited("Peer %pI4:%u/%u unexpectedly shrunk window %u:%u (repaired)\n", + &inet->inet_daddr, + ntohs(inet->inet_dport), + inet->inet_num, + tp->snd_una, tp->snd_nxt); } #if IS_ENABLED(CONFIG_IPV6) else if (sk->sk_family == AF_INET6) { - LIMIT_NETDEBUG(KERN_DEBUG pr_fmt("Peer %pI6:%u/%u unexpectedly shrunk window %u:%u (repaired)\n"), - &sk->sk_v6_daddr, - ntohs(inet->inet_dport), inet->inet_num, - tp->snd_una, tp->snd_nxt); + net_dbg_ratelimited("Peer %pI6:%u/%u unexpectedly shrunk window %u:%u (repaired)\n", + &sk->sk_v6_daddr, + ntohs(inet->inet_dport), + inet->inet_num, + tp->snd_una, tp->snd_nxt); } #endif if (tcp_time_stamp - tp->rcv_tstamp > TCP_RTO_MAX) { diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index d13751685f44..1b6e9d5fadef 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1051,7 +1051,7 @@ back_from_confirm: /* ... which is an evident application bug. --ANK */ release_sock(sk); - LIMIT_NETDEBUG(KERN_DEBUG pr_fmt("cork app bug 2\n")); + net_dbg_ratelimited("cork app bug 2\n"); err = -EINVAL; goto out; } @@ -1133,7 +1133,7 @@ int udp_sendpage(struct sock *sk, struct page *page, int offset, if (unlikely(!up->pending)) { release_sock(sk); - LIMIT_NETDEBUG(KERN_DEBUG pr_fmt("udp cork app bug 3\n")); + net_dbg_ratelimited("udp cork app bug 3\n"); return -EINVAL; } @@ -1547,8 +1547,8 @@ int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) * provided by the application." */ if (up->pcrlen == 0) { /* full coverage was set */ - LIMIT_NETDEBUG(KERN_WARNING "UDPLite: partial coverage %d while full coverage %d requested\n", - UDP_SKB_CB(skb)->cscov, skb->len); + net_dbg_ratelimited("UDPLite: partial coverage %d while full coverage %d requested\n", + UDP_SKB_CB(skb)->cscov, skb->len); goto drop; } /* The next case involves violating the min. coverage requested @@ -1558,8 +1558,8 @@ int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) * Therefore the above ...()->partial_cov statement is essential. */ if (UDP_SKB_CB(skb)->cscov < up->pcrlen) { - LIMIT_NETDEBUG(KERN_WARNING "UDPLite: coverage %d too small, need min %d\n", - UDP_SKB_CB(skb)->cscov, up->pcrlen); + net_dbg_ratelimited("UDPLite: coverage %d too small, need min %d\n", + UDP_SKB_CB(skb)->cscov, up->pcrlen); goto drop; } } @@ -1828,11 +1828,11 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, return 0; short_packet: - LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: short packet: From %pI4:%u %d/%d to %pI4:%u\n", - proto == IPPROTO_UDPLITE ? "Lite" : "", - &saddr, ntohs(uh->source), - ulen, skb->len, - &daddr, ntohs(uh->dest)); + net_dbg_ratelimited("UDP%s: short packet: From %pI4:%u %d/%d to %pI4:%u\n", + proto == IPPROTO_UDPLITE ? "Lite" : "", + &saddr, ntohs(uh->source), + ulen, skb->len, + &daddr, ntohs(uh->dest)); goto drop; csum_error: @@ -1840,10 +1840,10 @@ csum_error: * RFC1122: OK. Discards the bad packet silently (as far as * the network is concerned, anyway) as per 4.1.3.4 (MUST). */ - LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: bad checksum. From %pI4:%u to %pI4:%u ulen %d\n", - proto == IPPROTO_UDPLITE ? "Lite" : "", - &saddr, ntohs(uh->source), &daddr, ntohs(uh->dest), - ulen); + net_dbg_ratelimited("UDP%s: bad checksum. From %pI4:%u to %pI4:%u ulen %d\n", + proto == IPPROTO_UDPLITE ? "Lite" : "", + &saddr, ntohs(uh->source), &daddr, ntohs(uh->dest), + ulen); UDP_INC_STATS_BH(net, UDP_MIB_CSUMERRORS, proto == IPPROTO_UDPLITE); drop: UDP_INC_STATS_BH(net, UDP_MIB_INERRORS, proto == IPPROTO_UDPLITE); diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 06e897832a7a..251fcb48b216 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -1411,10 +1411,8 @@ int ipv6_dev_get_saddr(struct net *net, const struct net_device *dst_dev, if (unlikely(score->addr_type == IPV6_ADDR_ANY || score->addr_type & IPV6_ADDR_MULTICAST)) { - LIMIT_NETDEBUG(KERN_DEBUG - "ADDRCONF: unspecified / multicast address " - "assigned as unicast address on %s", - dev->name); + net_dbg_ratelimited("ADDRCONF: unspecified / multicast address assigned as unicast address on %s", + dev->name); continue; } diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index 6d16eb0e0c7f..8ab1989198f6 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c @@ -272,10 +272,9 @@ static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len, int dir) ipv6_rearrange_destopt(iph, exthdr.opth); case NEXTHDR_HOP: if (!zero_out_mutable_opts(exthdr.opth)) { - LIMIT_NETDEBUG( - KERN_WARNING "overrun %sopts\n", - nexthdr == NEXTHDR_HOP ? - "hop" : "dest"); + net_dbg_ratelimited("overrun %sopts\n", + nexthdr == NEXTHDR_HOP ? + "hop" : "dest"); return -EINVAL; } break; diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 5c6996e44b14..cc1139687fd7 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -893,8 +893,8 @@ int ip6_datagram_send_ctl(struct net *net, struct sock *sk, break; } default: - LIMIT_NETDEBUG(KERN_DEBUG "invalid cmsg type: %d\n", - cmsg->cmsg_type); + net_dbg_ratelimited("invalid cmsg type: %d\n", + cmsg->cmsg_type); err = -EINVAL; goto exit_f; } diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index d21d7b22eebc..d2c2d749b6db 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -286,8 +286,8 @@ static int esp_input_done2(struct sk_buff *skb, int err) err = -EINVAL; padlen = nexthdr[0]; if (padlen + 2 + alen >= elen) { - LIMIT_NETDEBUG(KERN_WARNING "ipsec esp packet is garbage " - "padlen=%d, elen=%d\n", padlen + 2, elen - alen); + net_dbg_ratelimited("ipsec esp packet is garbage padlen=%d, elen=%d\n", + padlen + 2, elen - alen); goto out; } diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index 601d896f22d0..a7bbbe45570b 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c @@ -184,7 +184,7 @@ static bool ipv6_dest_hao(struct sk_buff *skb, int optoff) int ret; if (opt->dsthao) { - LIMIT_NETDEBUG(KERN_DEBUG "hao duplicated\n"); + net_dbg_ratelimited("hao duplicated\n"); goto discard; } opt->dsthao = opt->dst1; @@ -193,14 +193,14 @@ static bool ipv6_dest_hao(struct sk_buff *skb, int optoff) hao = (struct ipv6_destopt_hao *)(skb_network_header(skb) + optoff); if (hao->length != 16) { - LIMIT_NETDEBUG( - KERN_DEBUG "hao invalid option length = %d\n", hao->length); + net_dbg_ratelimited("hao invalid option length = %d\n", + hao->length); goto discard; } if (!(ipv6_addr_type(&hao->addr) & IPV6_ADDR_UNICAST)) { - LIMIT_NETDEBUG( - KERN_DEBUG "hao is not an unicast addr: %pI6\n", &hao->addr); + net_dbg_ratelimited("hao is not an unicast addr: %pI6\n", + &hao->addr); goto discard; } @@ -551,8 +551,8 @@ static bool ipv6_hop_ra(struct sk_buff *skb, int optoff) memcpy(&IP6CB(skb)->ra, nh + optoff + 2, sizeof(IP6CB(skb)->ra)); return true; } - LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_ra: wrong RA length %d\n", - nh[optoff + 1]); + net_dbg_ratelimited("ipv6_hop_ra: wrong RA length %d\n", + nh[optoff + 1]); kfree_skb(skb); return false; } @@ -566,8 +566,8 @@ static bool ipv6_hop_jumbo(struct sk_buff *skb, int optoff) u32 pkt_len; if (nh[optoff + 1] != 4 || (optoff & 3) != 2) { - LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n", - nh[optoff+1]); + net_dbg_ratelimited("ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n", + nh[optoff+1]); IP6_INC_STATS_BH(net, ipv6_skb_idev(skb), IPSTATS_MIB_INHDRERRORS); goto drop; diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 62c1037d9e83..092934032077 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -338,7 +338,7 @@ static struct dst_entry *icmpv6_route_lookup(struct net *net, * anycast. */ if (((struct rt6_info *)dst)->rt6i_flags & RTF_ANYCAST) { - LIMIT_NETDEBUG(KERN_DEBUG "icmp6_send: acast source\n"); + net_dbg_ratelimited("icmp6_send: acast source\n"); dst_release(dst); return ERR_PTR(-EINVAL); } @@ -452,7 +452,7 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info) * and anycast addresses will be checked later. */ if ((addr_type == IPV6_ADDR_ANY) || (addr_type & IPV6_ADDR_MULTICAST)) { - LIMIT_NETDEBUG(KERN_DEBUG "icmp6_send: addr_any/mcast source\n"); + net_dbg_ratelimited("icmp6_send: addr_any/mcast source\n"); return; } @@ -460,7 +460,7 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info) * Never answer to a ICMP packet. */ if (is_ineligible(skb)) { - LIMIT_NETDEBUG(KERN_DEBUG "icmp6_send: no reply to icmp error\n"); + net_dbg_ratelimited("icmp6_send: no reply to icmp error\n"); return; } @@ -509,7 +509,7 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info) len = skb->len - msg.offset; len = min_t(unsigned int, len, IPV6_MIN_MTU - sizeof(struct ipv6hdr) - sizeof(struct icmp6hdr)); if (len < 0) { - LIMIT_NETDEBUG(KERN_DEBUG "icmp: len problem\n"); + net_dbg_ratelimited("icmp: len problem\n"); goto out_dst_release; } @@ -706,9 +706,8 @@ static int icmpv6_rcv(struct sk_buff *skb) daddr = &ipv6_hdr(skb)->daddr; if (skb_checksum_validate(skb, IPPROTO_ICMPV6, ip6_compute_pseudo)) { - LIMIT_NETDEBUG(KERN_DEBUG - "ICMPv6 checksum failed [%pI6c > %pI6c]\n", - saddr, daddr); + net_dbg_ratelimited("ICMPv6 checksum failed [%pI6c > %pI6c]\n", + saddr, daddr); goto csum_error; } @@ -781,7 +780,7 @@ static int icmpv6_rcv(struct sk_buff *skb) if (type & ICMPV6_INFOMSG_MASK) break; - LIMIT_NETDEBUG(KERN_DEBUG "icmpv6: msg of unknown type\n"); + net_dbg_ratelimited("icmpv6: msg of unknown type\n"); /* * error of unknown type. diff --git a/net/ipv6/mip6.c b/net/ipv6/mip6.c index f61429d391d3..b9779d441b12 100644 --- a/net/ipv6/mip6.c +++ b/net/ipv6/mip6.c @@ -97,16 +97,17 @@ static int mip6_mh_filter(struct sock *sk, struct sk_buff *skb) return -1; if (mh->ip6mh_hdrlen < mip6_mh_len(mh->ip6mh_type)) { - LIMIT_NETDEBUG(KERN_DEBUG "mip6: MH message too short: %d vs >=%d\n", - mh->ip6mh_hdrlen, mip6_mh_len(mh->ip6mh_type)); + net_dbg_ratelimited("mip6: MH message too short: %d vs >=%d\n", + mh->ip6mh_hdrlen, + mip6_mh_len(mh->ip6mh_type)); mip6_param_prob(skb, 0, offsetof(struct ip6_mh, ip6mh_hdrlen) + skb_network_header_len(skb)); return -1; } if (mh->ip6mh_proto != IPPROTO_NONE) { - LIMIT_NETDEBUG(KERN_DEBUG "mip6: MH invalid payload proto = %d\n", - mh->ip6mh_proto); + net_dbg_ratelimited("mip6: MH invalid payload proto = %d\n", + mh->ip6mh_proto); mip6_param_prob(skb, 0, offsetof(struct ip6_mh, ip6mh_proto) + skb_network_header_len(skb)); return -1; @@ -288,7 +289,7 @@ static int mip6_destopt_offset(struct xfrm_state *x, struct sk_buff *skb, * XXX: packet if HAO exists. */ if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0) { - LIMIT_NETDEBUG(KERN_WARNING "mip6: hao exists already, override\n"); + net_dbg_ratelimited("mip6: hao exists already, override\n"); return offset; } diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c index d38e6a8d8b9f..398377a9d018 100644 --- a/net/ipv6/netfilter.c +++ b/net/ipv6/netfilter.c @@ -36,7 +36,7 @@ int ip6_route_me_harder(struct sk_buff *skb) err = dst->error; if (err) { IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); - LIMIT_NETDEBUG(KERN_DEBUG "ip6_route_me_harder: No more route.\n"); + net_dbg_ratelimited("ip6_route_me_harder: No more route\n"); dst_release(dst); return err; } diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index d1fe36274906..0ba3de4f2368 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -660,15 +660,13 @@ int udpv6_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) if ((is_udplite & UDPLITE_RECV_CC) && UDP_SKB_CB(skb)->partial_cov) { if (up->pcrlen == 0) { /* full coverage was set */ - LIMIT_NETDEBUG(KERN_WARNING "UDPLITE6: partial coverage" - " %d while full coverage %d requested\n", - UDP_SKB_CB(skb)->cscov, skb->len); + net_dbg_ratelimited("UDPLITE6: partial coverage %d while full coverage %d requested\n", + UDP_SKB_CB(skb)->cscov, skb->len); goto drop; } if (UDP_SKB_CB(skb)->cscov < up->pcrlen) { - LIMIT_NETDEBUG(KERN_WARNING "UDPLITE6: coverage %d " - "too small, need min %d\n", - UDP_SKB_CB(skb)->cscov, up->pcrlen); + net_dbg_ratelimited("UDPLITE6: coverage %d too small, need min %d\n", + UDP_SKB_CB(skb)->cscov, up->pcrlen); goto drop; } } @@ -761,9 +759,9 @@ static void udp6_csum_zero_error(struct sk_buff *skb) /* RFC 2460 section 8.1 says that we SHOULD log * this error. Well, it is reasonable. */ - LIMIT_NETDEBUG(KERN_INFO "IPv6: udp checksum is 0 for [%pI6c]:%u->[%pI6c]:%u\n", - &ipv6_hdr(skb)->saddr, ntohs(udp_hdr(skb)->source), - &ipv6_hdr(skb)->daddr, ntohs(udp_hdr(skb)->dest)); + net_dbg_ratelimited("IPv6: udp checksum is 0 for [%pI6c]:%u->[%pI6c]:%u\n", + &ipv6_hdr(skb)->saddr, ntohs(udp_hdr(skb)->source), + &ipv6_hdr(skb)->daddr, ntohs(udp_hdr(skb)->dest)); } /* @@ -931,14 +929,11 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, return 0; short_packet: - LIMIT_NETDEBUG(KERN_DEBUG "UDP%sv6: short packet: From [%pI6c]:%u %d/%d to [%pI6c]:%u\n", - proto == IPPROTO_UDPLITE ? "-Lite" : "", - saddr, - ntohs(uh->source), - ulen, - skb->len, - daddr, - ntohs(uh->dest)); + net_dbg_ratelimited("UDP%sv6: short packet: From [%pI6c]:%u %d/%d to [%pI6c]:%u\n", + proto == IPPROTO_UDPLITE ? "-Lite" : "", + saddr, ntohs(uh->source), + ulen, skb->len, + daddr, ntohs(uh->dest)); goto discard; csum_error: UDP6_INC_STATS_BH(net, UDP_MIB_CSUMERRORS, proto == IPPROTO_UDPLITE); @@ -1290,7 +1285,7 @@ back_from_confirm: /* ... which is an evident application bug. --ANK */ release_sock(sk); - LIMIT_NETDEBUG(KERN_DEBUG "udp cork app bug 2\n"); + net_dbg_ratelimited("udp cork app bug 2\n"); err = -EINVAL; goto out; } diff --git a/net/phonet/af_phonet.c b/net/phonet/af_phonet.c index 5a940dbd74a3..32ab87d34828 100644 --- a/net/phonet/af_phonet.c +++ b/net/phonet/af_phonet.c @@ -426,16 +426,17 @@ static int phonet_rcv(struct sk_buff *skb, struct net_device *dev, out_dev = phonet_route_output(net, pn_sockaddr_get_addr(&sa)); if (!out_dev) { - LIMIT_NETDEBUG(KERN_WARNING"No Phonet route to %02X\n", - pn_sockaddr_get_addr(&sa)); + net_dbg_ratelimited("No Phonet route to %02X\n", + pn_sockaddr_get_addr(&sa)); goto out; } __skb_push(skb, sizeof(struct phonethdr)); skb->dev = out_dev; if (out_dev == dev) { - LIMIT_NETDEBUG(KERN_ERR"Phonet loop to %02X on %s\n", - pn_sockaddr_get_addr(&sa), dev->name); + net_dbg_ratelimited("Phonet loop to %02X on %s\n", + pn_sockaddr_get_addr(&sa), + dev->name); goto out_dev; } /* Some drivers (e.g. TUN) do not allocate HW header space */ diff --git a/net/phonet/pep-gprs.c b/net/phonet/pep-gprs.c index e9a83a637185..fa8237fdc57b 100644 --- a/net/phonet/pep-gprs.c +++ b/net/phonet/pep-gprs.c @@ -203,8 +203,7 @@ static netdev_tx_t gprs_xmit(struct sk_buff *skb, struct net_device *dev) len = skb->len; err = pep_write(sk, skb); if (err) { - LIMIT_NETDEBUG(KERN_WARNING"%s: TX error (%d)\n", - dev->name, err); + net_dbg_ratelimited("%s: TX error (%d)\n", dev->name, err); dev->stats.tx_aborted_errors++; dev->stats.tx_errors++; } else { diff --git a/net/phonet/pep.c b/net/phonet/pep.c index 44b2123e22b8..9cd069dfaf65 100644 --- a/net/phonet/pep.c +++ b/net/phonet/pep.c @@ -272,8 +272,8 @@ static int pipe_rcv_status(struct sock *sk, struct sk_buff *skb) hdr = pnp_hdr(skb); if (hdr->data[0] != PN_PEP_TYPE_COMMON) { - LIMIT_NETDEBUG(KERN_DEBUG"Phonet unknown PEP type: %u\n", - (unsigned int)hdr->data[0]); + net_dbg_ratelimited("Phonet unknown PEP type: %u\n", + (unsigned int)hdr->data[0]); return -EOPNOTSUPP; } @@ -304,8 +304,8 @@ static int pipe_rcv_status(struct sock *sk, struct sk_buff *skb) break; default: - LIMIT_NETDEBUG(KERN_DEBUG"Phonet unknown PEP indication: %u\n", - (unsigned int)hdr->data[1]); + net_dbg_ratelimited("Phonet unknown PEP indication: %u\n", + (unsigned int)hdr->data[1]); return -EOPNOTSUPP; } if (wake) @@ -451,8 +451,8 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb) break; default: - LIMIT_NETDEBUG(KERN_DEBUG"Phonet unknown PEP message: %u\n", - hdr->message_id); + net_dbg_ratelimited("Phonet unknown PEP message: %u\n", + hdr->message_id); err = -EINVAL; } out: -- cgit v1.2.3-59-g8ed1b From 71783576b5345d63df048c0f18974037eea6e4f9 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sat, 1 Nov 2014 16:54:56 +0100 Subject: bcma: get IRQ numbers from dt It is not possible to auto detect the irq numbers used by the cores on an arm SoC. If bcma was registered with device tree it will search for some device tree nodes with the irq number and add it to the core configuration. Signed-off-by: Hauke Mehrtens Signed-off-by: John W. Linville --- Documentation/devicetree/bindings/bus/bcma.txt | 21 +++++++++++ drivers/bcma/main.c | 52 +++++++++++++++++++++++++- 2 files changed, 72 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/bus/bcma.txt b/Documentation/devicetree/bindings/bus/bcma.txt index 62a48348ac15..edd44d802139 100644 --- a/Documentation/devicetree/bindings/bus/bcma.txt +++ b/Documentation/devicetree/bindings/bus/bcma.txt @@ -8,6 +8,11 @@ Required properties: The cores on the AXI bus are automatically detected by bcma with the memory ranges they are using and they get registered afterwards. +Automatic detection of the IRQ number is not working on +BCM47xx/BCM53xx ARM SoCs. To assign IRQ numbers to the cores, provide +them manually through device tree. Use an interrupt-map to specify the +IRQ used by the devices on the bus. The first address is just an index, +because we do not have any special register. The top-level axi bus may contain children representing attached cores (devices). This is needed since some hardware details can't be auto @@ -22,6 +27,22 @@ Example: ranges = <0x00000000 0x18000000 0x00100000>; #address-cells = <1>; #size-cells = <1>; + #interrupt-cells = <1>; + interrupt-map-mask = <0x000fffff 0xffff>; + interrupt-map = + /* Ethernet Controller 0 */ + <0x00024000 0 &gic GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>, + + /* Ethernet Controller 1 */ + <0x00025000 0 &gic GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>; + + /* PCIe Controller 0 */ + <0x00012000 0 &gic GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>, + <0x00012000 1 &gic GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>, + <0x00012000 2 &gic GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>, + <0x00012000 3 &gic GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>, + <0x00012000 4 &gic GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>, + <0x00012000 5 &gic GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>; chipcommon { reg = <0x00000000 0x1000>; diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c index 6d1cf5701452..122086ef9fe1 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c @@ -11,6 +11,7 @@ #include #include #include +#include MODULE_DESCRIPTION("Broadcom's specific AMBA driver"); MODULE_LICENSE("GPL"); @@ -153,6 +154,46 @@ static struct device_node *bcma_of_find_child_device(struct platform_device *par return NULL; } +static int bcma_of_irq_parse(struct platform_device *parent, + struct bcma_device *core, + struct of_phandle_args *out_irq, int num) +{ + __be32 laddr[1]; + int rc; + + if (core->dev.of_node) { + rc = of_irq_parse_one(core->dev.of_node, num, out_irq); + if (!rc) + return rc; + } + + out_irq->np = parent->dev.of_node; + out_irq->args_count = 1; + out_irq->args[0] = num; + + laddr[0] = cpu_to_be32(core->addr); + return of_irq_parse_raw(laddr, out_irq); +} + +static unsigned int bcma_of_get_irq(struct platform_device *parent, + struct bcma_device *core, int num) +{ + struct of_phandle_args out_irq; + int ret; + + if (!parent || !parent->dev.of_node) + return 0; + + ret = bcma_of_irq_parse(parent, core, &out_irq, num); + if (ret) { + bcma_debug(core->bus, "bcma_of_get_irq() failed with rc=%d\n", + ret); + return 0; + } + + return irq_create_of_mapping(&out_irq); +} + static void bcma_of_fill_device(struct platform_device *parent, struct bcma_device *core) { @@ -161,12 +202,19 @@ static void bcma_of_fill_device(struct platform_device *parent, node = bcma_of_find_child_device(parent, core); if (node) core->dev.of_node = node; + + core->irq = bcma_of_get_irq(parent, core, 0); } #else static void bcma_of_fill_device(struct platform_device *parent, struct bcma_device *core) { } +static inline unsigned int bcma_of_get_irq(struct platform_device *parent, + struct bcma_device *core, int num) +{ + return 0; +} #endif /* CONFIG_OF */ unsigned int bcma_core_irq(struct bcma_device *core, int num) @@ -182,7 +230,9 @@ unsigned int bcma_core_irq(struct bcma_device *core, int num) mips_irq = bcma_core_mips_irq(core); return mips_irq <= 4 ? mips_irq + 2 : 0; } - break; + if (bus->host_pdev) + return bcma_of_get_irq(bus->host_pdev, core, num); + return 0; case BCMA_HOSTTYPE_SDIO: return 0; } -- cgit v1.2.3-59-g8ed1b From 2f86dc4cddcb21290ca099e1dce2a53533c86e0b Mon Sep 17 00:00:00 2001 From: Dirk Brandewie Date: Thu, 6 Nov 2014 09:40:47 -0800 Subject: intel_pstate: Add support for HWP Add support of Hardware Managed Performance States (HWP) described in Volume 3 section 14.4 of the SDM. With HWP enbaled intel_pstate will no longer be responsible for selecting P states for the processor. intel_pstate will continue to register to the cpufreq core as the scaling driver for CPUs implementing HWP. In HWP mode intel_pstate provides three functions reporting frequency to the cpufreq core, support for the set_policy() interface from the core and maintaining the intel_pstate sysfs interface in /sys/devices/system/cpu/intel_pstate. User preferences expressed via the set_policy() interface or the sysfs interface are forwared to the CPU via the HWP MSR interface. Signed-off-by: Dirk Brandewie Signed-off-by: Rafael J. Wysocki --- Documentation/cpu-freq/intel-pstate.txt | 37 ++++++++---- Documentation/kernel-parameters.txt | 3 + arch/x86/include/uapi/asm/msr-index.h | 41 +++++++++++++ drivers/cpufreq/intel_pstate.c | 100 +++++++++++++++++++++++++++++++- 4 files changed, 167 insertions(+), 14 deletions(-) (limited to 'Documentation') diff --git a/Documentation/cpu-freq/intel-pstate.txt b/Documentation/cpu-freq/intel-pstate.txt index a69ffe1d54d5..765d7fc0e692 100644 --- a/Documentation/cpu-freq/intel-pstate.txt +++ b/Documentation/cpu-freq/intel-pstate.txt @@ -1,17 +1,28 @@ Intel P-state driver -------------------- -This driver implements a scaling driver with an internal governor for -Intel Core processors. The driver follows the same model as the -Transmeta scaling driver (longrun.c) and implements the setpolicy() -instead of target(). Scaling drivers that implement setpolicy() are -assumed to implement internal governors by the cpufreq core. All the -logic for selecting the current P state is contained within the -driver; no external governor is used by the cpufreq core. - -Intel SandyBridge+ processors are supported. - -New sysfs files for controlling P state selection have been added to +This driver provides an interface to control the P state selection for +SandyBridge+ Intel processors. The driver can operate two different +modes based on the processor model legacy and Hardware P state (HWP) +mode. + +In legacy mode the driver implements a scaling driver with an internal +governor for Intel Core processors. The driver follows the same model +as the Transmeta scaling driver (longrun.c) and implements the +setpolicy() instead of target(). Scaling drivers that implement +setpolicy() are assumed to implement internal governors by the cpufreq +core. All the logic for selecting the current P state is contained +within the driver; no external governor is used by the cpufreq core. + +In HWP mode P state selection is implemented in the processor +itself. The driver provides the interfaces between the cpufreq core and +the processor to control P state selection based on user preferences +and reporting frequency to the cpufreq core. In this mode the +internal governor code is disabled. + +In addtion to the interfaces provided by the cpufreq core for +controlling frequency the driver provides sysfs files for +controlling P state selection. These files have been added to /sys/devices/system/cpu/intel_pstate/ max_perf_pct: limits the maximum P state that will be requested by @@ -33,7 +44,9 @@ frequency is fiction for Intel Core processors. Even if the scaling driver selects a single P state the actual frequency the processor will run at is selected by the processor itself. -New debugfs files have also been added to /sys/kernel/debug/pstate_snb/ +For legacy mode debugfs files have also been added to allow tuning of +the internal governor algorythm. These files are located at +/sys/kernel/debug/pstate_snb/ These files are NOT present in HWP mode. deadband d_gain_pct diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 4c81a860cc2b..907a0f119bee 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1446,6 +1446,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted. disable Do not enable intel_pstate as the default scaling driver for the supported processors + no_hwp + Do not enable hardware P state control (HWP) + if available. intremap= [X86-64, Intel-IOMMU] on enable Interrupt Remapping (default) diff --git a/arch/x86/include/uapi/asm/msr-index.h b/arch/x86/include/uapi/asm/msr-index.h index e21331ce368f..62838e54947d 100644 --- a/arch/x86/include/uapi/asm/msr-index.h +++ b/arch/x86/include/uapi/asm/msr-index.h @@ -152,6 +152,45 @@ #define MSR_CC6_DEMOTION_POLICY_CONFIG 0x00000668 #define MSR_MC6_DEMOTION_POLICY_CONFIG 0x00000669 +/* Hardware P state interface */ +#define MSR_PPERF 0x0000064e +#define MSR_PERF_LIMIT_REASONS 0x0000064f +#define MSR_PM_ENABLE 0x00000770 +#define MSR_HWP_CAPABILITIES 0x00000771 +#define MSR_HWP_REQUEST_PKG 0x00000772 +#define MSR_HWP_INTERRUPT 0x00000773 +#define MSR_HWP_REQUEST 0x00000774 +#define MSR_HWP_STATUS 0x00000777 + +/* CPUID.6.EAX */ +#define HWP_BASE_BIT (1<<7) +#define HWP_NOTIFICATIONS_BIT (1<<8) +#define HWP_ACTIVITY_WINDOW_BIT (1<<9) +#define HWP_ENERGY_PERF_PREFERENCE_BIT (1<<10) +#define HWP_PACKAGE_LEVEL_REQUEST_BIT (1<<11) + +/* IA32_HWP_CAPABILITIES */ +#define HWP_HIGHEST_PERF(x) (x & 0xff) +#define HWP_GUARANTEED_PERF(x) ((x & (0xff << 8)) >>8) +#define HWP_MOSTEFFICIENT_PERF(x) ((x & (0xff << 16)) >>16) +#define HWP_LOWEST_PERF(x) ((x & (0xff << 24)) >>24) + +/* IA32_HWP_REQUEST */ +#define HWP_MIN_PERF(x) (x & 0xff) +#define HWP_MAX_PERF(x) ((x & 0xff) << 8) +#define HWP_DESIRED_PERF(x) ((x & 0xff) << 16) +#define HWP_ENERGY_PERF_PREFERENCE(x) ((x & 0xff) << 24) +#define HWP_ACTIVITY_WINDOW(x) ((x & 0xff3) << 32) +#define HWP_PACKAGE_CONTROL(x) ((x & 0x1) << 42) + +/* IA32_HWP_STATUS */ +#define HWP_GUARANTEED_CHANGE(x) (x & 0x1) +#define HWP_EXCURSION_TO_MINIMUM(x) (x & 0x4) + +/* IA32_HWP_INTERRUPT */ +#define HWP_CHANGE_TO_GUARANTEED_INT(x) (x & 0x1) +#define HWP_EXCURSION_TO_MINIMUM_INT(x) (x & 0x2) + #define MSR_AMD64_MC0_MASK 0xc0010044 #define MSR_IA32_MCx_CTL(x) (MSR_IA32_MC0_CTL + 4*(x)) @@ -345,6 +384,8 @@ #define MSR_IA32_TEMPERATURE_TARGET 0x000001a2 +#define MSR_MISC_PWR_MGMT 0x000001aa + #define MSR_IA32_ENERGY_PERF_BIAS 0x000001b0 #define ENERGY_PERF_BIAS_PERFORMANCE 0 #define ENERGY_PERF_BIAS_NORMAL 6 diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 27bb6d3877ed..ba35db092239 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -137,6 +137,7 @@ struct cpu_defaults { static struct pstate_adjust_policy pid_params; static struct pstate_funcs pstate_funcs; +static int hwp_active; struct perf_limits { int no_turbo; @@ -244,6 +245,34 @@ static inline void update_turbo_state(void) cpu->pstate.max_pstate == cpu->pstate.turbo_pstate); } +#define PCT_TO_HWP(x) (x * 255 / 100) +static void intel_pstate_hwp_set(void) +{ + int min, max, cpu; + u64 value, freq; + + get_online_cpus(); + + for_each_online_cpu(cpu) { + rdmsrl_on_cpu(cpu, MSR_HWP_REQUEST, &value); + min = PCT_TO_HWP(limits.min_perf_pct); + value &= ~HWP_MIN_PERF(~0L); + value |= HWP_MIN_PERF(min); + + max = PCT_TO_HWP(limits.max_perf_pct); + if (limits.no_turbo) { + rdmsrl( MSR_HWP_CAPABILITIES, freq); + max = HWP_GUARANTEED_PERF(freq); + } + + value &= ~HWP_MAX_PERF(~0L); + value |= HWP_MAX_PERF(max); + wrmsrl_on_cpu(cpu, MSR_HWP_REQUEST, value); + } + + put_online_cpus(); +} + /************************** debugfs begin ************************/ static int pid_param_set(void *data, u64 val) { @@ -279,6 +308,8 @@ static void __init intel_pstate_debug_expose_params(void) struct dentry *debugfs_parent; int i = 0; + if (hwp_active) + return; debugfs_parent = debugfs_create_dir("pstate_snb", NULL); if (IS_ERR_OR_NULL(debugfs_parent)) return; @@ -329,8 +360,12 @@ static ssize_t store_no_turbo(struct kobject *a, struct attribute *b, pr_warn("Turbo disabled by BIOS or unavailable on processor\n"); return -EPERM; } + limits.no_turbo = clamp_t(int, input, 0, 1); + if (hwp_active) + intel_pstate_hwp_set(); + return count; } @@ -348,6 +383,8 @@ static ssize_t store_max_perf_pct(struct kobject *a, struct attribute *b, limits.max_perf_pct = min(limits.max_policy_pct, limits.max_sysfs_pct); limits.max_perf = div_fp(int_tofp(limits.max_perf_pct), int_tofp(100)); + if (hwp_active) + intel_pstate_hwp_set(); return count; } @@ -363,6 +400,8 @@ static ssize_t store_min_perf_pct(struct kobject *a, struct attribute *b, limits.min_perf_pct = clamp_t(int, input, 0 , 100); limits.min_perf = div_fp(int_tofp(limits.min_perf_pct), int_tofp(100)); + if (hwp_active) + intel_pstate_hwp_set(); return count; } @@ -395,8 +434,16 @@ static void __init intel_pstate_sysfs_expose_params(void) rc = sysfs_create_group(intel_pstate_kobject, &intel_pstate_attr_group); BUG_ON(rc); } - /************************** sysfs end ************************/ + +static void intel_pstate_hwp_enable(void) +{ + hwp_active++; + pr_info("intel_pstate HWP enabled\n"); + + wrmsrl( MSR_PM_ENABLE, 0x1); +} + static int byt_get_min_pstate(void) { u64 value; @@ -648,6 +695,14 @@ static inline void intel_pstate_sample(struct cpudata *cpu) cpu->prev_mperf = mperf; } +static inline void intel_hwp_set_sample_time(struct cpudata *cpu) +{ + int delay; + + delay = msecs_to_jiffies(50); + mod_timer_pinned(&cpu->timer, jiffies + delay); +} + static inline void intel_pstate_set_sample_time(struct cpudata *cpu) { int delay; @@ -694,6 +749,14 @@ static inline void intel_pstate_adjust_busy_pstate(struct cpudata *cpu) intel_pstate_set_pstate(cpu, cpu->pstate.current_pstate - ctl); } +static void intel_hwp_timer_func(unsigned long __data) +{ + struct cpudata *cpu = (struct cpudata *) __data; + + intel_pstate_sample(cpu); + intel_hwp_set_sample_time(cpu); +} + static void intel_pstate_timer_func(unsigned long __data) { struct cpudata *cpu = (struct cpudata *) __data; @@ -737,6 +800,11 @@ static const struct x86_cpu_id intel_pstate_cpu_ids[] = { }; MODULE_DEVICE_TABLE(x86cpu, intel_pstate_cpu_ids); +static const struct x86_cpu_id intel_pstate_cpu_oob_ids[] = { + ICPU(0x56, core_params), + {} +}; + static int intel_pstate_init_cpu(unsigned int cpunum) { struct cpudata *cpu; @@ -753,9 +821,14 @@ static int intel_pstate_init_cpu(unsigned int cpunum) intel_pstate_get_cpu_pstates(cpu); init_timer_deferrable(&cpu->timer); - cpu->timer.function = intel_pstate_timer_func; cpu->timer.data = (unsigned long)cpu; cpu->timer.expires = jiffies + HZ/100; + + if (!hwp_active) + cpu->timer.function = intel_pstate_timer_func; + else + cpu->timer.function = intel_hwp_timer_func; + intel_pstate_busy_pid_reset(cpu); intel_pstate_sample(cpu); @@ -792,6 +865,7 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy) limits.no_turbo = 0; return 0; } + limits.min_perf_pct = (policy->min * 100) / policy->cpuinfo.max_freq; limits.min_perf_pct = clamp_t(int, limits.min_perf_pct, 0 , 100); limits.min_perf = div_fp(int_tofp(limits.min_perf_pct), int_tofp(100)); @@ -801,6 +875,9 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy) limits.max_perf_pct = min(limits.max_policy_pct, limits.max_sysfs_pct); limits.max_perf = div_fp(int_tofp(limits.max_perf_pct), int_tofp(100)); + if (hwp_active) + intel_pstate_hwp_set(); + return 0; } @@ -823,6 +900,9 @@ static void intel_pstate_stop_cpu(struct cpufreq_policy *policy) pr_info("intel_pstate CPU %d exiting\n", cpu_num); del_timer_sync(&all_cpu_data[cpu_num]->timer); + if (hwp_active) + return; + intel_pstate_set_pstate(cpu, cpu->pstate.min_pstate); } @@ -866,6 +946,7 @@ static struct cpufreq_driver intel_pstate_driver = { }; static int __initdata no_load; +static int __initdata no_hwp; static int intel_pstate_msrs_not_valid(void) { @@ -959,6 +1040,15 @@ static bool intel_pstate_platform_pwr_mgmt_exists(void) { struct acpi_table_header hdr; struct hw_vendor_info *v_info; + const struct x86_cpu_id *id; + u64 misc_pwr; + + id = x86_match_cpu(intel_pstate_cpu_oob_ids); + if (id) { + rdmsrl(MSR_MISC_PWR_MGMT, misc_pwr); + if ( misc_pwr & (1 << 8)) + return true; + } if (acpi_disabled || ACPI_FAILURE(acpi_get_table_header(ACPI_SIG_FADT, 0, &hdr))) @@ -982,6 +1072,7 @@ static int __init intel_pstate_init(void) int cpu, rc = 0; const struct x86_cpu_id *id; struct cpu_defaults *cpu_info; + struct cpuinfo_x86 *c = &boot_cpu_data; if (no_load) return -ENODEV; @@ -1011,6 +1102,9 @@ static int __init intel_pstate_init(void) if (!all_cpu_data) return -ENOMEM; + if (cpu_has(c,X86_FEATURE_HWP) && !no_hwp) + intel_pstate_hwp_enable(); + rc = cpufreq_register_driver(&intel_pstate_driver); if (rc) goto out; @@ -1041,6 +1135,8 @@ static int __init intel_pstate_setup(char *str) if (!strcmp(str, "disable")) no_load = 1; + if (!strcmp(str, "no_hwp")) + no_hwp = 1; return 0; } early_param("intel_pstate", intel_pstate_setup); -- cgit v1.2.3-59-g8ed1b From 2bec708a88ce053ffcb0dd8e373d1e46c6dc38a4 Mon Sep 17 00:00:00 2001 From: Laurence Oberman Date: Sun, 19 Oct 2014 09:44:25 -0400 Subject: st: add a debug_flag module parameter request This patch adds a debug_flag parameter that can be set on module load, and allows the DEBUG facility without a module recompile. Note that now DEBUG 1 is the default with this patch. Usage: modprobe st debug_flag=1 Signed-off-by: Laurence Oberman Acked-by: Kai M??kisara Signed-off-by: Christoph Hellwig --- Documentation/scsi/st.txt | 8 +++++--- drivers/scsi/st.c | 16 +++++++++++++++- 2 files changed, 20 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/scsi/st.txt b/Documentation/scsi/st.txt index f346abbdd6ff..0d5bdb153d3b 100644 --- a/Documentation/scsi/st.txt +++ b/Documentation/scsi/st.txt @@ -506,9 +506,11 @@ user does not request data that far.) DEBUGGING HINTS -To enable debugging messages, edit st.c and #define DEBUG 1. As seen -above, debugging can be switched off with an ioctl if debugging is -compiled into the driver. The debugging output is not voluminous. +Debugging code is now compiled in by default but debugging is turned off +with the kernel module parameter debug_flag defaulting to 0. Debugging +can still be switched on and off with an ioctl. To enable debug at +module load time add debug_flag=1 to the module load options, the +debugging output is not voluminous. If the tape seems to hang, I would be very interested to hear where the driver is waiting. With the command 'ps -l' you can see the state diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 4daa372ed381..8d5f8b4f9a22 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -56,7 +56,8 @@ static const char *verstr = "20101219"; /* The driver prints some debugging information on the console if DEBUG is defined and non-zero. */ -#define DEBUG 0 +#define DEBUG 1 +#define NO_DEBUG 0 #define ST_DEB_MSG KERN_NOTICE #if DEBUG @@ -80,6 +81,7 @@ static int max_sg_segs; static int try_direct_io = TRY_DIRECT_IO; static int try_rdio = 1; static int try_wdio = 1; +static int debug_flag; static struct class st_sysfs_class; static const struct attribute_group *st_dev_groups[]; @@ -100,6 +102,9 @@ module_param_named(max_sg_segs, max_sg_segs, int, 0); MODULE_PARM_DESC(max_sg_segs, "Maximum number of scatter/gather segments to use (256)"); module_param_named(try_direct_io, try_direct_io, int, 0); MODULE_PARM_DESC(try_direct_io, "Try direct I/O between user buffer and tape drive (1)"); +module_param_named(debug_flag, debug_flag, int, 0); +MODULE_PARM_DESC(debug_flag, "Enable DEBUG, same as setting debugging=1"); + /* Extra parameters for testing */ module_param_named(try_rdio, try_rdio, int, 0); @@ -124,6 +129,9 @@ static struct st_dev_parm { }, { "try_direct_io", &try_direct_io + }, + { + "debug_flag", &debug_flag } }; #endif @@ -4309,6 +4317,12 @@ static int __init init_st(void) printk(KERN_INFO "st: Version %s, fixed bufsize %d, s/g segs %d\n", verstr, st_fixed_buffer_size, st_max_sg_segs); + debugging = (debug_flag > 0) ? debug_flag : NO_DEBUG; + if (debugging) { + printk(KERN_INFO "st: Debugging enabled debug_flag = %d\n", + debugging); + } + err = class_register(&st_sysfs_class); if (err) { pr_err("Unable register sysfs class for SCSI tapes\n"); -- cgit v1.2.3-59-g8ed1b From 125c99bc8b6b108d251169a86324a7ed3c6f3cce Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 3 Nov 2014 12:47:47 +0100 Subject: scsi: add new scsi-command flag for tagged commands Currently scsi piggy backs on the block layer to define the concept of a tagged command. But we want to be able to have block-level host-wide tags assigned even for untagged commands like the initial INQUIRY, so add a new SCSI-level flag for commands that are tagged at the scsi level, so that even commands without that set can have tags assigned to them. Note that this alredy is the case for the blk-mq code path, and this just lets the old path catch up with it. We also set this flag based upon sdev->simple_tags instead of the block queue flag, so that it is entirely independent of the block layer tagging, and thus always correct even if a driver doesn't use block level tagging yet. Also remove the old blk_rq_tagged; it was only used by SCSI drivers, and removing it forces them to look for the proper replacement. Signed-off-by: Christoph Hellwig Reviewed-by: Mike Christie Reviewed-by: Martin K. Petersen Reviewed-by: Hannes Reinecke --- Documentation/block/biodoc.txt | 4 ---- block/blk-core.c | 4 ++-- drivers/scsi/53c700.c | 6 +++--- drivers/scsi/aic7xxx/aic7xxx_osm.c | 2 +- drivers/scsi/scsi_lib.c | 13 +++++++++---- drivers/usb/storage/uas.c | 2 +- include/linux/blkdev.h | 1 - include/scsi/scsi_cmnd.h | 4 ++++ include/scsi/scsi_tcq.h | 6 ++---- 9 files changed, 22 insertions(+), 20 deletions(-) (limited to 'Documentation') diff --git a/Documentation/block/biodoc.txt b/Documentation/block/biodoc.txt index 2101e718670d..6b972b287795 100644 --- a/Documentation/block/biodoc.txt +++ b/Documentation/block/biodoc.txt @@ -827,10 +827,6 @@ but in the event of any barrier requests in the tag queue we need to ensure that requests are restarted in the order they were queue. This may happen if the driver needs to use blk_queue_invalidate_tags(). -Tagging also defines a new request flag, REQ_QUEUED. This is set whenever -a request is currently tagged. You should not use this flag directly, -blk_rq_tagged(rq) is the portable way to do so. - 3.3 I/O Submission The routine submit_bio() is used to submit a single io. Higher level i/o diff --git a/block/blk-core.c b/block/blk-core.c index 0421b53e6431..2e7424b42947 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -1266,7 +1266,7 @@ void blk_requeue_request(struct request_queue *q, struct request *rq) blk_clear_rq_complete(rq); trace_block_rq_requeue(q, rq); - if (blk_rq_tagged(rq)) + if (rq->cmd_flags & REQ_QUEUED) blk_queue_end_tag(q, rq); BUG_ON(blk_queued_rq(rq)); @@ -2554,7 +2554,7 @@ EXPORT_SYMBOL_GPL(blk_unprep_request); */ void blk_finish_request(struct request *req, int error) { - if (blk_rq_tagged(req)) + if (req->cmd_flags & REQ_QUEUED) blk_queue_end_tag(req->q, req); BUG_ON(blk_queued_rq(req)); diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c index 474cc6dc98e2..5143d3213e86 100644 --- a/drivers/scsi/53c700.c +++ b/drivers/scsi/53c700.c @@ -1767,7 +1767,7 @@ NCR_700_queuecommand_lck(struct scsi_cmnd *SCp, void (*done)(struct scsi_cmnd *) */ if(NCR_700_get_depth(SCp->device) != 0 && (!(hostdata->tag_negotiated & (1<request))) { + || !(SCp->flags & SCMD_TAGGED))) { CDEBUG(KERN_ERR, SCp, "has non zero depth %d\n", NCR_700_get_depth(SCp->device)); return SCSI_MLQUEUE_DEVICE_BUSY; @@ -1795,7 +1795,7 @@ NCR_700_queuecommand_lck(struct scsi_cmnd *SCp, void (*done)(struct scsi_cmnd *) printk("53c700: scsi%d, command ", SCp->device->host->host_no); scsi_print_command(SCp); #endif - if(blk_rq_tagged(SCp->request) + if ((SCp->flags & SCMD_TAGGED) && (hostdata->tag_negotiated &(1<device) == NCR_700_START_TAG_NEGOTIATION) { scmd_printk(KERN_ERR, SCp, "Enabling Tag Command Queuing\n"); @@ -1809,7 +1809,7 @@ NCR_700_queuecommand_lck(struct scsi_cmnd *SCp, void (*done)(struct scsi_cmnd *) * * FIXME: This will royally screw up on multiple LUN devices * */ - if(!blk_rq_tagged(SCp->request) + if (!(SCp->flags & SCMD_TAGGED) && (hostdata->tag_negotiated &(1<tag_negotiated &= ~(1<request) + if (!(cmd->flags & SCMD_TAGGED) && (ahc->features & AHC_SCB_BTT) == 0) { int target_offset; diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 38f8c85957b6..994eb083fff9 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1740,7 +1740,7 @@ static void scsi_request_fn(struct request_queue *q) * we add the dev to the starved list so it eventually gets * a run when a tag is freed. */ - if (blk_queue_tagged(q) && !blk_rq_tagged(req)) { + if (blk_queue_tagged(q) && !(req->cmd_flags & REQ_QUEUED)) { spin_lock_irq(shost->host_lock); if (list_empty(&sdev->starved_entry)) list_add_tail(&sdev->starved_entry, @@ -1754,6 +1754,11 @@ static void scsi_request_fn(struct request_queue *q) if (!scsi_host_queue_ready(q, shost, sdev)) goto host_not_ready; + + if (sdev->simple_tags) + cmd->flags |= SCMD_TAGGED; + else + cmd->flags &= ~SCMD_TAGGED; /* * Finally, initialize any error handling parameters, and set up @@ -1908,10 +1913,10 @@ static int scsi_queue_rq(struct blk_mq_hw_ctx *hctx, struct request *req, blk_mq_start_request(req); } - if (blk_queue_tagged(q)) - req->cmd_flags |= REQ_QUEUED; + if (sdev->simple_tags) + cmd->flags |= SCMD_TAGGED; else - req->cmd_flags &= ~REQ_QUEUED; + cmd->flags &= ~SCMD_TAGGED; scsi_init_cmd_errh(cmd); cmd->scsi_done = scsi_mq_done; diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index 89b24349269e..b38bc1318a60 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c @@ -181,7 +181,7 @@ static int uas_get_tag(struct scsi_cmnd *cmnd) { int tag; - if (blk_rq_tagged(cmnd->request)) + if (cmnd->flags & SCMD_TAGGED) tag = cmnd->request->tag + 2; else tag = 1; diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index aac0f9ea952a..6d76b8b4aa2b 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -1136,7 +1136,6 @@ static inline bool blk_needs_flush_plug(struct task_struct *tsk) /* * tag stuff */ -#define blk_rq_tagged(rq) ((rq)->cmd_flags & REQ_QUEUED) extern int blk_queue_start_tag(struct request_queue *, struct request *); extern struct request *blk_queue_find_tag(struct request_queue *, int); extern void blk_queue_end_tag(struct request_queue *, struct request *); diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h index 522a5f27f553..e119142e565e 100644 --- a/include/scsi/scsi_cmnd.h +++ b/include/scsi/scsi_cmnd.h @@ -53,6 +53,9 @@ struct scsi_pointer { volatile int phase; }; +/* for scmd->flags */ +#define SCMD_TAGGED (1 << 0) + struct scsi_cmnd { struct scsi_device *device; struct list_head list; /* scsi_cmnd participates in queue lists */ @@ -132,6 +135,7 @@ struct scsi_cmnd { * to be at an address < 16Mb). */ int result; /* Status code from lower level driver */ + int flags; /* Command flags */ unsigned char tag; /* SCSI-II queued command tag */ }; diff --git a/include/scsi/scsi_tcq.h b/include/scsi/scsi_tcq.h index 1712dab6e00e..032df74b66d7 100644 --- a/include/scsi/scsi_tcq.h +++ b/include/scsi/scsi_tcq.h @@ -101,11 +101,9 @@ static inline void scsi_deactivate_tcq(struct scsi_device *sdev, int depth) **/ static inline int scsi_populate_tag_msg(struct scsi_cmnd *cmd, char *msg) { - struct request *req = cmd->request; - - if (blk_rq_tagged(req)) { + if (cmd->flags & SCMD_TAGGED) { *msg++ = MSG_SIMPLE_TAG; - *msg++ = req->tag; + *msg++ = cmd->request->tag; return 2; } -- cgit v1.2.3-59-g8ed1b From 2ecb204d07ac8debe3893c362415919bc78bebd6 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 3 Nov 2014 14:09:02 +0100 Subject: scsi: always assign block layer tags if enabled Allow a driver to ask for block layer tags by setting .use_blk_tags in the host template, in which case it will always see a valid value in request->tag, similar to the behavior when using blk-mq. This means even SCSI "untagged" commands will now have a tag, which is especially useful when using a host-wide tag map. Signed-off-by: Christoph Hellwig Reviewed-by: Mike Christie Reviewed-by: Martin K. Petersen Reviewed-by: Hannes Reinecke --- Documentation/scsi/scsi_mid_low_api.txt | 38 +-------------------------------- drivers/message/fusion/mptsas.c | 1 + drivers/scsi/53c700.c | 12 +++++------ drivers/scsi/aic7xxx/aic79xx_osm.c | 11 +++++----- drivers/scsi/aic7xxx/aic7xxx_osm.c | 11 +++++----- drivers/scsi/aic94xx/aic94xx_init.c | 1 + drivers/scsi/bfa/bfad_im.c | 8 +++---- drivers/scsi/bnx2fc/bnx2fc_fcoe.c | 1 + drivers/scsi/csiostor/csio_scsi.c | 8 +++---- drivers/scsi/esas2r/esas2r_main.c | 12 +++++------ drivers/scsi/esp_scsi.c | 6 +++--- drivers/scsi/fcoe/fcoe.c | 1 + drivers/scsi/fnic/fnic_main.c | 3 ++- drivers/scsi/ibmvscsi/ibmvfc.c | 11 +++++----- drivers/scsi/ipr.c | 1 + drivers/scsi/isci/init.c | 1 + drivers/scsi/libfc/fc_fcp.c | 7 +----- drivers/scsi/libsas/sas_scsi_host.c | 11 +++------- drivers/scsi/lpfc/lpfc_scsi.c | 7 +++--- drivers/scsi/mvsas/mv_init.c | 1 + drivers/scsi/pm8001/pm8001_init.c | 1 + drivers/scsi/pmcraid.c | 4 ++-- drivers/scsi/qla2xxx/qla_os.c | 6 ++---- drivers/scsi/qla4xxx/ql4_os.c | 10 ++------- drivers/scsi/scsi.c | 12 ++++------- drivers/scsi/scsi_scan.c | 6 ++++++ drivers/scsi/stex.c | 10 ++------- drivers/scsi/tmscsim.c | 3 ++- drivers/scsi/ufs/ufshcd.c | 5 +++-- drivers/target/loopback/tcm_loop.c | 2 +- drivers/usb/storage/uas.c | 4 ++-- include/scsi/scsi_host.h | 5 +++++ include/scsi/scsi_tcq.h | 34 ----------------------------- 33 files changed, 86 insertions(+), 168 deletions(-) (limited to 'Documentation') diff --git a/Documentation/scsi/scsi_mid_low_api.txt b/Documentation/scsi/scsi_mid_low_api.txt index d6a9bdeee7f2..a67194209581 100644 --- a/Documentation/scsi/scsi_mid_low_api.txt +++ b/Documentation/scsi/scsi_mid_low_api.txt @@ -366,13 +366,11 @@ is initialized. The functions below are listed alphabetically and their names all start with "scsi_". Summary: - scsi_activate_tcq - turn on tag command queueing scsi_add_device - creates new scsi device (lu) instance scsi_add_host - perform sysfs registration and set up transport class scsi_adjust_queue_depth - change the queue depth on a SCSI device scsi_bios_ptable - return copy of block device's partition table scsi_block_requests - prevent further commands being queued to given host - scsi_deactivate_tcq - turn off tag command queueing scsi_host_alloc - return a new scsi_host instance whose refcount==1 scsi_host_get - increments Scsi_Host instance's refcount scsi_host_put - decrements Scsi_Host instance's refcount (free if 0) @@ -389,24 +387,6 @@ Summary: Details: -/** - * scsi_activate_tcq - turn on tag command queueing ("ordered" task attribute) - * @sdev: device to turn on TCQ for - * @depth: queue depth - * - * Returns nothing - * - * Might block: no - * - * Notes: Eventually, it is hoped depth would be the maximum depth - * the device could cope with and the real queue depth - * would be adjustable from 0 to depth. - * - * Defined (inline) in: include/scsi/scsi_tcq.h - **/ -void scsi_activate_tcq(struct scsi_device *sdev, int depth) - - /** * scsi_add_device - creates new scsi device (lu) instance * @shost: pointer to scsi host instance @@ -471,9 +451,7 @@ int scsi_add_host(struct Scsi_Host *shost, struct device * dev) * * Notes: Can be invoked any time on a SCSI device controlled by this * LLD. [Specifically during and after slave_configure() and prior to - * slave_destroy().] Can safely be invoked from interrupt code. Actual - * queue depth change may be delayed until the next command is being - * processed. See also scsi_activate_tcq() and scsi_deactivate_tcq(). + * slave_destroy().] Can safely be invoked from interrupt code. * * Defined in: drivers/scsi/scsi.c [see source code for more notes] * @@ -514,20 +492,6 @@ unsigned char *scsi_bios_ptable(struct block_device *dev) void scsi_block_requests(struct Scsi_Host * shost) -/** - * scsi_deactivate_tcq - turn off tag command queueing - * @sdev: device to turn off TCQ for - * @depth: queue depth (stored in sdev) - * - * Returns nothing - * - * Might block: no - * - * Defined (inline) in: include/scsi/scsi_tcq.h - **/ -void scsi_deactivate_tcq(struct scsi_device *sdev, int depth) - - /** * scsi_host_alloc - create a scsi host adapter instance and perform basic * initialization. diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 0707fa2c701b..5bdaae15a742 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -1994,6 +1994,7 @@ static struct scsi_host_template mptsas_driver_template = { .cmd_per_lun = 7, .use_clustering = ENABLE_CLUSTERING, .shost_attrs = mptscsih_host_attrs, + .use_blk_tags = 1, }; static int mptsas_get_linkerrors(struct sas_phy *phy) diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c index 1b36fd3a6e62..497cbb1efd4b 100644 --- a/drivers/scsi/53c700.c +++ b/drivers/scsi/53c700.c @@ -327,6 +327,7 @@ NCR_700_detect(struct scsi_host_template *tpnt, tpnt->slave_alloc = NCR_700_slave_alloc; tpnt->change_queue_depth = NCR_700_change_queue_depth; tpnt->change_queue_type = NCR_700_change_queue_type; + tpnt->use_blk_tags = 1; if(tpnt->name == NULL) tpnt->name = "53c700"; @@ -902,7 +903,7 @@ process_message(struct Scsi_Host *host, struct NCR_700_Host_Parameters *hostdata NCR_700_set_tag_neg_state(SCp->device, NCR_700_FINISHED_TAG_NEGOTIATION); hostdata->tag_negotiated &= ~(1<device->tagged_supported = 0; - scsi_deactivate_tcq(SCp->device, host->cmd_per_lun); + scsi_adjust_queue_depth(SCp->device, 0, host->cmd_per_lun); } else { shost_printk(KERN_WARNING, host, "(%d:%d) Unexpected REJECT Message %s\n", @@ -2049,8 +2050,7 @@ NCR_700_slave_configure(struct scsi_device *SDp) /* to do here: allocate memory; build a queue_full list */ if(SDp->tagged_supported) { - scsi_set_tag_type(SDp, MSG_ORDERED_TAG); - scsi_activate_tcq(SDp, NCR_700_DEFAULT_TAGS); + scsi_adjust_queue_depth(SDp, MSG_ORDERED_TAG, NCR_700_DEFAULT_TAGS); NCR_700_set_tag_neg_state(SDp, NCR_700_START_TAG_NEGOTIATION); } else { /* initialise to default depth */ @@ -2094,8 +2094,6 @@ static int NCR_700_change_queue_type(struct scsi_device *SDp, int tag_type) struct NCR_700_Host_Parameters *hostdata = (struct NCR_700_Host_Parameters *)SDp->host->hostdata[0]; - scsi_set_tag_type(SDp, tag_type); - /* We have a global (per target) flag to track whether TCQ is * enabled, so we'll be turning it off for the entire target here. * our tag algorithm will fail if we mix tagged and untagged commands, @@ -2106,12 +2104,12 @@ static int NCR_700_change_queue_type(struct scsi_device *SDp, int tag_type) if (!tag_type) { /* shift back to the default unqueued number of commands * (the user can still raise this) */ - scsi_deactivate_tcq(SDp, SDp->host->cmd_per_lun); + scsi_adjust_queue_depth(SDp, 0, SDp->host->cmd_per_lun); hostdata->tag_negotiated &= ~(1 << sdev_id(SDp)); } else { /* Here, we cleared the negotiation flag above, so this * will force the driver to renegotiate */ - scsi_activate_tcq(SDp, SDp->queue_depth); + scsi_adjust_queue_depth(SDp, tag_type, SDp->queue_depth); if (change_tag) NCR_700_set_tag_neg_state(SDp, NCR_700_START_TAG_NEGOTIATION); } diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index d3b6d68107ea..9fd6b5618b25 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -925,6 +925,7 @@ struct scsi_host_template aic79xx_driver_template = { .slave_configure = ahd_linux_slave_configure, .target_alloc = ahd_linux_target_alloc, .target_destroy = ahd_linux_target_destroy, + .use_blk_tags = 1, }; /******************************** Bus DMA *************************************/ @@ -1468,12 +1469,12 @@ ahd_platform_set_tags(struct ahd_softc *ahd, struct scsi_device *sdev, switch ((dev->flags & (AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED))) { case AHD_DEV_Q_BASIC: - scsi_set_tag_type(sdev, MSG_SIMPLE_TASK); - scsi_activate_tcq(sdev, dev->openings + dev->active); + scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TASK, + dev->openings + dev->active); break; case AHD_DEV_Q_TAGGED: - scsi_set_tag_type(sdev, MSG_ORDERED_TASK); - scsi_activate_tcq(sdev, dev->openings + dev->active); + scsi_adjust_queue_depth(sdev, MSG_ORDERED_TASK, + dev->openings + dev->active); break; default: /* @@ -1482,7 +1483,7 @@ ahd_platform_set_tags(struct ahd_softc *ahd, struct scsi_device *sdev, * serially on the controller/device. This should * remove some latency. */ - scsi_deactivate_tcq(sdev, 1); + scsi_adjust_queue_depth(sdev, 0, 1); break; } } diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index 33a5f959e86a..f18b6d69d3fb 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -812,6 +812,7 @@ struct scsi_host_template aic7xxx_driver_template = { .slave_configure = ahc_linux_slave_configure, .target_alloc = ahc_linux_target_alloc, .target_destroy = ahc_linux_target_destroy, + .use_blk_tags = 1, }; /**************************** Tasklet Handler *********************************/ @@ -1334,12 +1335,12 @@ ahc_platform_set_tags(struct ahc_softc *ahc, struct scsi_device *sdev, } switch ((dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED))) { case AHC_DEV_Q_BASIC: - scsi_set_tag_type(sdev, MSG_SIMPLE_TAG); - scsi_activate_tcq(sdev, dev->openings + dev->active); + scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TASK, + dev->openings + dev->active); break; case AHC_DEV_Q_TAGGED: - scsi_set_tag_type(sdev, MSG_ORDERED_TAG); - scsi_activate_tcq(sdev, dev->openings + dev->active); + scsi_adjust_queue_depth(sdev, MSG_ORDERED_TASK, + dev->openings + dev->active); break; default: /* @@ -1348,7 +1349,7 @@ ahc_platform_set_tags(struct ahc_softc *ahc, struct scsi_device *sdev, * serially on the controller/device. This should * remove some latency. */ - scsi_deactivate_tcq(sdev, 2); + scsi_adjust_queue_depth(sdev, 0, 2); break; } } diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c index c56741fc4b99..579dc2f460c4 100644 --- a/drivers/scsi/aic94xx/aic94xx_init.c +++ b/drivers/scsi/aic94xx/aic94xx_init.c @@ -83,6 +83,7 @@ static struct scsi_host_template aic94xx_sht = { .eh_bus_reset_handler = sas_eh_bus_reset_handler, .target_destroy = sas_target_destroy, .ioctl = sas_ioctl, + .use_blk_tags = 1, }; static int asd_map_memio(struct asd_ha_struct *asd_ha) diff --git a/drivers/scsi/bfa/bfad_im.c b/drivers/scsi/bfa/bfad_im.c index 99280e89c289..d8e43c81d19b 100644 --- a/drivers/scsi/bfa/bfad_im.c +++ b/drivers/scsi/bfa/bfad_im.c @@ -776,11 +776,7 @@ bfad_thread_workq(struct bfad_s *bfad) static int bfad_im_slave_configure(struct scsi_device *sdev) { - if (sdev->tagged_supported) - scsi_activate_tcq(sdev, bfa_lun_queue_depth); - else - scsi_deactivate_tcq(sdev, bfa_lun_queue_depth); - + scsi_adjust_queue_depth(sdev, 0, bfa_lun_queue_depth); return 0; } @@ -804,6 +800,7 @@ struct scsi_host_template bfad_im_scsi_host_template = { .shost_attrs = bfad_im_host_attrs, .max_sectors = BFAD_MAX_SECTORS, .vendor_id = BFA_PCI_VENDOR_ID_BROCADE, + .use_blk_tags = 1, }; struct scsi_host_template bfad_im_vport_template = { @@ -825,6 +822,7 @@ struct scsi_host_template bfad_im_vport_template = { .use_clustering = ENABLE_CLUSTERING, .shost_attrs = bfad_im_vport_attrs, .max_sectors = BFAD_MAX_SECTORS, + .use_blk_tags = 1, }; bfa_status_t diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index 3c6dc8abc776..cd2e61025926 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -2790,6 +2790,7 @@ static struct scsi_host_template bnx2fc_shost_template = { .use_clustering = ENABLE_CLUSTERING, .sg_tablesize = BNX2FC_MAX_BDS_PER_CMD, .max_sectors = 1024, + .use_blk_tags = 1, }; static struct libfc_function_template bnx2fc_libfc_fcn_templ = { diff --git a/drivers/scsi/csiostor/csio_scsi.c b/drivers/scsi/csiostor/csio_scsi.c index 8231505cce0a..f73155db80a3 100644 --- a/drivers/scsi/csiostor/csio_scsi.c +++ b/drivers/scsi/csiostor/csio_scsi.c @@ -2241,11 +2241,7 @@ csio_slave_alloc(struct scsi_device *sdev) static int csio_slave_configure(struct scsi_device *sdev) { - if (sdev->tagged_supported) - scsi_activate_tcq(sdev, csio_lun_qdepth); - else - scsi_deactivate_tcq(sdev, csio_lun_qdepth); - + scsi_adjust_queue_depth(sdev, 0, csio_lun_qdepth); return 0; } @@ -2290,6 +2286,7 @@ struct scsi_host_template csio_fcoe_shost_template = { .use_clustering = ENABLE_CLUSTERING, .shost_attrs = csio_fcoe_lport_attrs, .max_sectors = CSIO_MAX_SECTOR_SIZE, + .use_blk_tags = 1, }; struct scsi_host_template csio_fcoe_shost_vport_template = { @@ -2309,6 +2306,7 @@ struct scsi_host_template csio_fcoe_shost_vport_template = { .use_clustering = ENABLE_CLUSTERING, .shost_attrs = csio_fcoe_vport_attrs, .max_sectors = CSIO_MAX_SECTOR_SIZE, + .use_blk_tags = 1, }; /* diff --git a/drivers/scsi/esas2r/esas2r_main.c b/drivers/scsi/esas2r/esas2r_main.c index be09c628d034..a020b09ba347 100644 --- a/drivers/scsi/esas2r/esas2r_main.c +++ b/drivers/scsi/esas2r/esas2r_main.c @@ -260,6 +260,7 @@ static struct scsi_host_template driver_template = { .change_queue_depth = esas2r_change_queue_depth, .change_queue_type = scsi_change_queue_type, .max_sectors = 0xFFFF, + .use_blk_tags = 1, }; int sgl_page_size = 512; @@ -1278,13 +1279,10 @@ int esas2r_slave_configure(struct scsi_device *dev) esas2r_log_dev(ESAS2R_LOG_INFO, &(dev->sdev_gendev), "esas2r_slave_configure()"); - if (dev->tagged_supported) { - scsi_set_tag_type(dev, MSG_SIMPLE_TAG); - scsi_activate_tcq(dev, cmd_per_lun); - } else { - scsi_set_tag_type(dev, 0); - scsi_deactivate_tcq(dev, cmd_per_lun); - } + if (dev->tagged_supported) + scsi_adjust_queue_depth(dev, MSG_SIMPLE_TAG, cmd_per_lun); + else + scsi_adjust_queue_depth(dev, 0, cmd_per_lun); return 0; } diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c index b23101b28bfa..66b6ce10b259 100644 --- a/drivers/scsi/esp_scsi.c +++ b/drivers/scsi/esp_scsi.c @@ -2419,10 +2419,9 @@ static int esp_slave_configure(struct scsi_device *dev) queue_depth = dev->host->cmd_per_lun; if (goal_tags) { - scsi_set_tag_type(dev, MSG_ORDERED_TAG); - scsi_activate_tcq(dev, queue_depth); + scsi_adjust_queue_depth(dev, MSG_ORDERED_TAG, queue_depth); } else { - scsi_deactivate_tcq(dev, queue_depth); + scsi_adjust_queue_depth(dev, 0, queue_depth); } tp->flags |= ESP_TGT_DISCONNECT; @@ -2631,6 +2630,7 @@ struct scsi_host_template scsi_esp_template = { .use_clustering = ENABLE_CLUSTERING, .max_sectors = 0xffff, .skip_settle_delay = 1, + .use_blk_tags = 1, }; EXPORT_SYMBOL(scsi_esp_template); diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 86956cc3448e..a3eeb6842499 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -288,6 +288,7 @@ static struct scsi_host_template fcoe_shost_template = { .use_clustering = ENABLE_CLUSTERING, .sg_tablesize = SG_ALL, .max_sectors = 0xffff, + .use_blk_tags = 1, }; /** diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c index 8581ce662cf0..2a6c98b7d4db 100644 --- a/drivers/scsi/fnic/fnic_main.c +++ b/drivers/scsi/fnic/fnic_main.c @@ -100,7 +100,7 @@ static int fnic_slave_alloc(struct scsi_device *sdev) if (!rport || fc_remote_port_chkready(rport)) return -ENXIO; - scsi_activate_tcq(sdev, fnic_max_qdepth); + scsi_adjust_queue_depth(sdev, 0, fnic_max_qdepth); return 0; } @@ -121,6 +121,7 @@ static struct scsi_host_template fnic_host_template = { .sg_tablesize = FNIC_MAX_SG_DESC_CNT, .max_sectors = 0xffff, .shost_attrs = fnic_attrs, + .use_blk_tags = 1, }; static void diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index a964f8c85833..4723d89df5ac 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -2888,11 +2888,11 @@ static int ibmvfc_slave_configure(struct scsi_device *sdev) if (sdev->type == TYPE_DISK) sdev->allow_restart = 1; - if (sdev->tagged_supported) { - scsi_set_tag_type(sdev, MSG_SIMPLE_TAG); - scsi_activate_tcq(sdev, sdev->queue_depth); - } else - scsi_deactivate_tcq(sdev, sdev->queue_depth); + if (sdev->tagged_supported) + scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, + sdev->queue_depth); + else + scsi_adjust_queue_depth(sdev, 0, sdev->queue_depth); spin_unlock_irqrestore(shost->host_lock, flags); return 0; } @@ -3108,6 +3108,7 @@ static struct scsi_host_template driver_template = { .max_sectors = IBMVFC_MAX_SECTORS, .use_clustering = ENABLE_CLUSTERING, .shost_attrs = ibmvfc_attrs, + .use_blk_tags = 1, }; /** diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 6b52feafa929..f84fcb9a6ed7 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -6317,6 +6317,7 @@ static struct scsi_host_template driver_template = { .sdev_attrs = ipr_dev_attrs, .proc_name = IPR_NAME, .no_write_same = 1, + .use_blk_tags = 1, }; /** diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c index 2e890b1e2526..897562056018 100644 --- a/drivers/scsi/isci/init.c +++ b/drivers/scsi/isci/init.c @@ -172,6 +172,7 @@ static struct scsi_host_template isci_sht = { .target_destroy = sas_target_destroy, .ioctl = sas_ioctl, .shost_attrs = isci_host_attrs, + .use_blk_tags = 1, }; static struct sas_domain_function_template isci_transport_ops = { diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index f3043ad1f35d..d4bb642f2681 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -2160,12 +2160,7 @@ int fc_slave_alloc(struct scsi_device *sdev) if (!rport || fc_remote_port_chkready(rport)) return -ENXIO; - if (sdev->tagged_supported) - scsi_activate_tcq(sdev, FC_FCP_DFLT_QUEUE_DEPTH); - else - scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), - FC_FCP_DFLT_QUEUE_DEPTH); - + scsi_adjust_queue_depth(sdev, 0, FC_FCP_DFLT_QUEUE_DEPTH); return 0; } EXPORT_SYMBOL(fc_slave_alloc); diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index 24e477d2ea70..eee21a060d93 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -940,15 +940,13 @@ int sas_slave_configure(struct scsi_device *scsi_dev) sas_read_port_mode_page(scsi_dev); if (scsi_dev->tagged_supported) { - scsi_set_tag_type(scsi_dev, MSG_SIMPLE_TAG); - scsi_activate_tcq(scsi_dev, SAS_DEF_QD); + scsi_adjust_queue_depth(scsi_dev, MSG_SIMPLE_TAG, SAS_DEF_QD); } else { SAS_DPRINTK("device %llx, LUN %llx doesn't support " "TCQ\n", SAS_ADDR(dev->sas_addr), scsi_dev->lun); scsi_dev->tagged_supported = 0; - scsi_set_tag_type(scsi_dev, 0); - scsi_deactivate_tcq(scsi_dev, 1); + scsi_adjust_queue_depth(scsi_dev, 0, 1); } scsi_dev->allow_restart = 1; @@ -991,10 +989,7 @@ int sas_change_queue_type(struct scsi_device *scsi_dev, int qt) if (!scsi_dev->tagged_supported) return 0; - scsi_deactivate_tcq(scsi_dev, 1); - - scsi_set_tag_type(scsi_dev, qt); - scsi_activate_tcq(scsi_dev, scsi_dev->queue_depth); + scsi_adjust_queue_depth(scsi_dev, qt, scsi_dev->queue_depth); return qt; } diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 4a150063fb4d..a24106a70968 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -5598,10 +5598,7 @@ lpfc_slave_configure(struct scsi_device *sdev) struct lpfc_vport *vport = (struct lpfc_vport *) sdev->host->hostdata; struct lpfc_hba *phba = vport->phba; - if (sdev->tagged_supported) - scsi_activate_tcq(sdev, vport->cfg_lun_queue_depth); - else - scsi_deactivate_tcq(sdev, vport->cfg_lun_queue_depth); + scsi_adjust_queue_depth(sdev, 0, vport->cfg_lun_queue_depth); if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) { lpfc_sli_handle_fast_ring_event(phba, @@ -5986,6 +5983,7 @@ struct scsi_host_template lpfc_template = { .vendor_id = LPFC_NL_VENDOR_ID, .change_queue_depth = lpfc_change_queue_depth, .change_queue_type = scsi_change_queue_type, + .use_blk_tags = 1, }; struct scsi_host_template lpfc_vport_template = { @@ -6009,4 +6007,5 @@ struct scsi_host_template lpfc_vport_template = { .max_sectors = 0xFFFF, .change_queue_depth = lpfc_change_queue_depth, .change_queue_type = scsi_change_queue_type, + .use_blk_tags = 1, }; diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c index eacee48a955c..d3c1fa5e76fb 100644 --- a/drivers/scsi/mvsas/mv_init.c +++ b/drivers/scsi/mvsas/mv_init.c @@ -76,6 +76,7 @@ static struct scsi_host_template mvs_sht = { .target_destroy = sas_target_destroy, .ioctl = sas_ioctl, .shost_attrs = mvst_host_attrs, + .use_blk_tags = 1, }; static struct sas_domain_function_template mvs_transport_ops = { diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c index 666bf5af06e2..3ff759a3b74d 100644 --- a/drivers/scsi/pm8001/pm8001_init.c +++ b/drivers/scsi/pm8001/pm8001_init.c @@ -89,6 +89,7 @@ static struct scsi_host_template pm8001_sht = { .target_destroy = sas_target_destroy, .ioctl = sas_ioctl, .shost_attrs = pm8001_host_attrs, + .use_blk_tags = 1, }; /** diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c index d5fb31fa388b..71f9f59b13c6 100644 --- a/drivers/scsi/pmcraid.c +++ b/drivers/scsi/pmcraid.c @@ -251,7 +251,6 @@ static int pmcraid_slave_configure(struct scsi_device *scsi_dev) if (scsi_dev->tagged_supported && (RES_IS_GSCSI(res->cfg_entry) || RES_IS_VSET(res->cfg_entry))) { - scsi_activate_tcq(scsi_dev, scsi_dev->queue_depth); scsi_adjust_queue_depth(scsi_dev, MSG_SIMPLE_TAG, scsi_dev->host->cmd_per_lun); } else { @@ -4295,7 +4294,8 @@ static struct scsi_host_template pmcraid_host_template = { .cmd_per_lun = PMCRAID_MAX_CMD_PER_LUN, .use_clustering = ENABLE_CLUSTERING, .shost_attrs = pmcraid_host_attrs, - .proc_name = PMCRAID_DRIVER_NAME + .proc_name = PMCRAID_DRIVER_NAME, + .use_blk_tags = 1, }; /* diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 1e34fcf68e77..eb0465305f8d 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -269,6 +269,7 @@ struct scsi_host_template qla2xxx_driver_template = { .shost_attrs = qla2x00_host_attrs, .supported_mode = MODE_INITIATOR, + .use_blk_tags = 1, }; static struct scsi_transport_template *qla2xxx_transport_template = NULL; @@ -1404,10 +1405,7 @@ qla2xxx_slave_configure(struct scsi_device *sdev) if (IS_T10_PI_CAPABLE(vha->hw)) blk_queue_update_dma_alignment(sdev->request_queue, 0x7); - if (sdev->tagged_supported) - scsi_activate_tcq(sdev, req->max_q_depth); - else - scsi_deactivate_tcq(sdev, req->max_q_depth); + scsi_adjust_queue_depth(sdev, 0, req->max_q_depth); return 0; } diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 199fcf79a051..f3119c144e29 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -163,7 +163,6 @@ static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd); static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd); static int qla4xxx_slave_alloc(struct scsi_device *device); static int qla4xxx_slave_configure(struct scsi_device *device); -static void qla4xxx_slave_destroy(struct scsi_device *sdev); static umode_t qla4_attr_is_visible(int param_type, int param); static int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type); static int qla4xxx_change_queue_depth(struct scsi_device *sdev, int qdepth, @@ -206,7 +205,6 @@ static struct scsi_host_template qla4xxx_driver_template = { .slave_configure = qla4xxx_slave_configure, .slave_alloc = qla4xxx_slave_alloc, - .slave_destroy = qla4xxx_slave_destroy, .change_queue_depth = qla4xxx_change_queue_depth, .this_id = -1, @@ -218,6 +216,7 @@ static struct scsi_host_template qla4xxx_driver_template = { .shost_attrs = qla4xxx_host_attrs, .host_reset = qla4xxx_host_reset, .vendor_id = SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_QLOGIC, + .use_blk_tags = 1, }; static struct iscsi_transport qla4xxx_iscsi_transport = { @@ -9065,7 +9064,7 @@ static int qla4xxx_slave_alloc(struct scsi_device *sdev) if (ql4xmaxqdepth != 0 && ql4xmaxqdepth <= 0xffffU) queue_depth = ql4xmaxqdepth; - scsi_activate_tcq(sdev, queue_depth); + scsi_adjust_queue_depth(sdev, 0, queue_depth); return 0; } @@ -9075,11 +9074,6 @@ static int qla4xxx_slave_configure(struct scsi_device *sdev) return 0; } -static void qla4xxx_slave_destroy(struct scsi_device *sdev) -{ - scsi_deactivate_tcq(sdev, 1); -} - static int qla4xxx_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason) { diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 22c449e926fa..a3426f1bf0dd 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -864,16 +864,12 @@ EXPORT_SYMBOL(scsi_track_queue_full); */ int scsi_change_queue_type(struct scsi_device *sdev, int tag_type) { - if (sdev->tagged_supported) { - scsi_set_tag_type(sdev, tag_type); - if (tag_type) - scsi_activate_tcq(sdev, sdev->queue_depth); - else - scsi_deactivate_tcq(sdev, sdev->queue_depth); - } else - tag_type = 0; + if (!sdev->tagged_supported) + return 0; + scsi_adjust_queue_depth(sdev, tag_type, sdev->queue_depth); return tag_type; + } EXPORT_SYMBOL(scsi_change_queue_type); diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index b1aa1646012a..408891cb14ff 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -286,6 +286,12 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget, } WARN_ON_ONCE(!blk_get_queue(sdev->request_queue)); sdev->request_queue->queuedata = sdev; + + if (!shost_use_blk_mq(sdev->host) && + (shost->bqt || shost->hostt->use_blk_tags)) { + blk_queue_init_tags(sdev->request_queue, + sdev->host->cmd_per_lun, shost->bqt); + } scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun); scsi_sysfs_device_initialize(sdev); diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c index 713af13b858e..b5eae4f6ba46 100644 --- a/drivers/scsi/stex.c +++ b/drivers/scsi/stex.c @@ -549,7 +549,7 @@ stex_slave_alloc(struct scsi_device *sdev) /* Cheat: usually extracted from Inquiry data */ sdev->tagged_supported = 1; - scsi_activate_tcq(sdev, sdev->host->can_queue); + scsi_adjust_queue_depth(sdev, 0, sdev->host->can_queue); return 0; } @@ -565,12 +565,6 @@ stex_slave_config(struct scsi_device *sdev) return 0; } -static void -stex_slave_destroy(struct scsi_device *sdev) -{ - scsi_deactivate_tcq(sdev, 1); -} - static int stex_queuecommand_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) { @@ -1390,10 +1384,10 @@ static struct scsi_host_template driver_template = { .queuecommand = stex_queuecommand, .slave_alloc = stex_slave_alloc, .slave_configure = stex_slave_config, - .slave_destroy = stex_slave_destroy, .eh_abort_handler = stex_abort, .eh_host_reset_handler = stex_reset, .this_id = -1, + .use_blk_tags = 1, }; static struct pci_device_id stex_pci_tbl[] = { diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c index 547812437a7c..6369f9a282f1 100644 --- a/drivers/scsi/tmscsim.c +++ b/drivers/scsi/tmscsim.c @@ -2187,7 +2187,7 @@ static int dc390_slave_configure(struct scsi_device *sdev) acb->scan_devices = 0; if (sdev->tagged_supported && (dcb->DevMode & TAG_QUEUEING_)) { dcb->SyncMode |= EN_TAG_QUEUEING; - scsi_activate_tcq(sdev, acb->TagMaxNum); + scsi_adjust_queue_depth(sdev, 0, acb->TagMaxNum); } return 0; @@ -2209,6 +2209,7 @@ static struct scsi_host_template driver_template = { .cmd_per_lun = 1, .use_clustering = ENABLE_CLUSTERING, .max_sectors = 0x4000, /* 8MiB = 16 * 1024 * 512 */ + .use_blk_tags = 1, }; /*********************************************************************** diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 9da319130da5..48c7f9e8f256 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -2695,7 +2695,8 @@ static void ufshcd_set_queue_depth(struct scsi_device *sdev) dev_dbg(hba->dev, "%s: activate tcq with queue depth %d\n", __func__, lun_qdepth); - scsi_activate_tcq(sdev, lun_qdepth); + if (sdev->tagged_supported) + scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), lun_qdepth); } /* @@ -2842,7 +2843,6 @@ static void ufshcd_slave_destroy(struct scsi_device *sdev) struct ufs_hba *hba; hba = shost_priv(sdev->host); - scsi_deactivate_tcq(sdev, hba->nutrs); /* Drop the reference as it won't be needed anymore */ if (ufshcd_scsi_to_upiu_lun(sdev->lun) == UFS_UPIU_UFS_DEVICE_WLUN) hba->sdev_ufs_device = NULL; @@ -4235,6 +4235,7 @@ static struct scsi_host_template ufshcd_driver_template = { .cmd_per_lun = UFSHCD_CMD_PER_LUN, .can_queue = UFSHCD_CAN_QUEUE, .max_host_blocked = 1, + .use_blk_tags = 1, }; static int ufshcd_config_vreg_load(struct device *dev, struct ufs_vreg *vreg, diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index e30932f989a1..120a851df0d7 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -407,7 +407,6 @@ static int tcm_loop_slave_alloc(struct scsi_device *sd) static int tcm_loop_slave_configure(struct scsi_device *sd) { if (sd->tagged_supported) { - scsi_activate_tcq(sd, sd->queue_depth); scsi_adjust_queue_depth(sd, MSG_SIMPLE_TAG, sd->host->cmd_per_lun); } else { @@ -437,6 +436,7 @@ static struct scsi_host_template tcm_loop_driver_template = { .slave_alloc = tcm_loop_slave_alloc, .slave_configure = tcm_loop_slave_configure, .module = THIS_MODULE, + .use_blk_tags = 1, }; static int tcm_loop_driver_probe(struct device *dev) diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index 1bc5df4200a7..ee69b82fc7d1 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c @@ -799,8 +799,7 @@ static int uas_slave_configure(struct scsi_device *sdev) if (devinfo->flags & US_FL_NO_REPORT_OPCODES) sdev->no_report_opcodes = 1; - scsi_set_tag_type(sdev, MSG_ORDERED_TAG); - scsi_activate_tcq(sdev, devinfo->qdepth - 2); + scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, devinfo->qdepth - 2); return 0; } @@ -824,6 +823,7 @@ static struct scsi_host_template uas_host_template = { * allocator. */ .disable_blk_mq = true, + .use_blk_tags = 1, }; #define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index d6bd65294009..61a81bf77e28 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -421,6 +421,11 @@ struct scsi_host_template { */ unsigned char present; + /* + * Let the block layer assigns tags to all commands. + */ + unsigned use_blk_tags:1; + /* * This specifies the mode that a LLD supports. */ diff --git a/include/scsi/scsi_tcq.h b/include/scsi/scsi_tcq.h index 005f68da5adb..fe4a70299419 100644 --- a/include/scsi/scsi_tcq.h +++ b/include/scsi/scsi_tcq.h @@ -45,40 +45,6 @@ static inline void scsi_set_tag_type(struct scsi_device *sdev, int tag) break; } } -/** - * scsi_activate_tcq - turn on tag command queueing - * @SDpnt: device to turn on TCQ for - * @depth: queue depth - * - * Notes: - * Eventually, I hope depth would be the maximum depth - * the device could cope with and the real queue depth - * would be adjustable from 0 to depth. - **/ -static inline void scsi_activate_tcq(struct scsi_device *sdev, int depth) -{ - if (!sdev->tagged_supported) - return; - - if (shost_use_blk_mq(sdev->host)) - queue_flag_set_unlocked(QUEUE_FLAG_QUEUED, sdev->request_queue); - else if (!blk_queue_tagged(sdev->request_queue)) - blk_queue_init_tags(sdev->request_queue, depth, - sdev->host->bqt); - - scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth); -} - -/** - * scsi_deactivate_tcq - turn off tag command queueing - * @SDpnt: device to turn off TCQ for - **/ -static inline void scsi_deactivate_tcq(struct scsi_device *sdev, int depth) -{ - if (blk_queue_tagged(sdev->request_queue)) - blk_queue_free_tags(sdev->request_queue); - scsi_adjust_queue_depth(sdev, 0, depth); -} static inline struct scsi_cmnd *scsi_mq_find_tag(struct Scsi_Host *shost, int unique_tag) -- cgit v1.2.3-59-g8ed1b From c8b09f6fb67df7fc1b51ced1037fa9b677428149 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 3 Nov 2014 20:15:14 +0100 Subject: scsi: don't set tagging state from scsi_adjust_queue_depth Remove the tagged argument from scsi_adjust_queue_depth, and just let it handle the queue depth. For most drivers those two are fairly separate, given that most modern drivers don't care about the SCSI "tagged" status of a command at all, and many old drivers allow queuing of multiple untagged commands in the driver. Instead we start out with the ->simple_tags flag set before calling ->slave_configure, which is how all drivers actually looking at ->simple_tags except for one worke anyway. The one other case looks broken, but I've kept the behavior as-is for now. Except for that we only change ->simple_tags from the ->change_queue_type, and when rejecting a tag message in a single driver, so keeping this churn out of scsi_adjust_queue_depth is a clear win. Now that the usage of scsi_adjust_queue_depth is more obvious we can also remove all the trivial instances in ->slave_alloc or ->slave_configure that just set it to the cmd_per_lun default. Signed-off-by: Christoph Hellwig Reviewed-by: Mike Christie Reviewed-by: Hannes Reinecke Reviewed-by: Martin K. Petersen --- Documentation/scsi/scsi_mid_low_api.txt | 12 ++++------ drivers/ata/libata-scsi.c | 4 ++-- drivers/infiniband/ulp/srp/ib_srp.c | 2 +- drivers/message/fusion/mptscsih.c | 2 +- drivers/s390/scsi/zfcp_scsi.c | 8 +++---- drivers/scsi/3w-9xxx.c | 2 +- drivers/scsi/3w-sas.c | 2 +- drivers/scsi/3w-xxxx.c | 2 +- drivers/scsi/53c700.c | 17 ++++++------- drivers/scsi/BusLogic.c | 4 ++-- drivers/scsi/aacraid/linit.c | 8 +++---- drivers/scsi/advansys.c | 7 ++---- drivers/scsi/aic7xxx/aic79xx_osm.c | 7 ++---- drivers/scsi/aic7xxx/aic7xxx_osm.c | 8 ++----- drivers/scsi/arcmsr/arcmsr_hba.c | 2 +- drivers/scsi/bfa/bfad_im.c | 3 +-- drivers/scsi/csiostor/csio_scsi.c | 2 +- drivers/scsi/dpt_i2o.c | 4 +--- drivers/scsi/eata.c | 8 +++---- drivers/scsi/esas2r/esas2r.h | 3 --- drivers/scsi/esas2r/esas2r_main.c | 29 +--------------------- drivers/scsi/esp_scsi.c | 17 ++----------- drivers/scsi/fnic/fnic_main.c | 2 +- drivers/scsi/gdth.c | 1 - drivers/scsi/hpsa.c | 2 +- drivers/scsi/hptiop.c | 2 +- drivers/scsi/ibmvscsi/ibmvfc.c | 8 +------ drivers/scsi/ibmvscsi/ibmvscsi.c | 3 +-- drivers/scsi/ipr.c | 8 +++---- drivers/scsi/ips.c | 2 +- drivers/scsi/libfc/fc_fcp.c | 6 ++--- drivers/scsi/libiscsi.c | 4 ++-- drivers/scsi/libsas/sas_scsi_host.c | 20 +++++----------- drivers/scsi/lpfc/lpfc_scsi.c | 4 ++-- drivers/scsi/megaraid/megaraid_mbox.c | 2 +- drivers/scsi/megaraid/megaraid_sas_base.c | 3 +-- drivers/scsi/mpt2sas/mpt2sas_scsih.c | 2 +- drivers/scsi/mpt3sas/mpt3sas_scsih.c | 2 +- drivers/scsi/ncr53c8xx.c | 5 +--- drivers/scsi/pmcraid.c | 40 ++++++------------------------- drivers/scsi/qla1280.c | 5 ++-- drivers/scsi/qla2xxx/qla_os.c | 6 ++--- drivers/scsi/qla4xxx/ql4_os.c | 2 +- drivers/scsi/scsi.c | 25 ++++--------------- drivers/scsi/scsi_debug.c | 7 ++---- drivers/scsi/scsi_scan.c | 6 +++-- drivers/scsi/stex.c | 2 -- drivers/scsi/storvsc_drv.c | 3 +-- drivers/scsi/sym53c8xx_2/sym_glue.c | 4 +--- drivers/scsi/tmscsim.c | 9 ++++++- drivers/scsi/u14-34f.c | 10 ++++---- drivers/scsi/ufs/ufshcd.c | 4 ++-- drivers/scsi/virtio_scsi.c | 4 +--- drivers/scsi/vmw_pvscsi.c | 2 +- drivers/target/loopback/tcm_loop.c | 18 ++------------ drivers/usb/storage/uas.c | 2 +- include/scsi/scsi_device.h | 2 +- 57 files changed, 120 insertions(+), 260 deletions(-) (limited to 'Documentation') diff --git a/Documentation/scsi/scsi_mid_low_api.txt b/Documentation/scsi/scsi_mid_low_api.txt index a67194209581..bee7d86b9dcc 100644 --- a/Documentation/scsi/scsi_mid_low_api.txt +++ b/Documentation/scsi/scsi_mid_low_api.txt @@ -271,9 +271,9 @@ init_this_scsi_driver() ----+ slave_destroy() *** ------------------------------------------------------------ -The mid level invokes scsi_adjust_queue_depth() with tagged queuing off and -"cmd_per_lun" for that host as the queue length. These settings can be -overridden by a slave_configure() supplied by the LLD. +The mid level invokes scsi_adjust_queue_depth() with "cmd_per_lun" for that +host as the queue length. These settings can be overridden by a +slave_configure() supplied by the LLD. *** For scsi devices that the mid level tries to scan but do not respond, a slave_alloc(), slave_destroy() pair is called. @@ -438,9 +438,6 @@ int scsi_add_host(struct Scsi_Host *shost, struct device * dev) /** * scsi_adjust_queue_depth - allow LLD to change queue depth on a SCSI device * @sdev: pointer to SCSI device to change queue depth on - * @tagged: 0 - no tagged queuing - * MSG_SIMPLE_TAG - simple tagged queuing - * MSG_ORDERED_TAG - ordered tagged queuing * @tags Number of tags allowed if tagged queuing enabled, * or number of commands the LLD can queue up * in non-tagged mode (as per cmd_per_lun). @@ -456,8 +453,7 @@ int scsi_add_host(struct Scsi_Host *shost, struct device * dev) * Defined in: drivers/scsi/scsi.c [see source code for more notes] * **/ -void scsi_adjust_queue_depth(struct scsi_device * sdev, int tagged, - int tags) +void scsi_adjust_queue_depth(struct scsi_device *sdev, int tags) /** diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 0586f66d70fa..c8bb6abbf12c 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1164,7 +1164,7 @@ static int ata_scsi_dev_config(struct scsi_device *sdev, depth = min(sdev->host->can_queue, ata_id_queue_depth(dev->id)); depth = min(ATA_MAX_QUEUE - 1, depth); - scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, depth); + scsi_adjust_queue_depth(sdev, depth); } blk_queue_flush_queueable(q, false); @@ -1282,7 +1282,7 @@ int __ata_change_queue_depth(struct ata_port *ap, struct scsi_device *sdev, if (sdev->queue_depth == queue_depth) return -EINVAL; - scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, queue_depth); + scsi_adjust_queue_depth(sdev, queue_depth); return queue_depth; } diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 51670d75ab78..023a66f5ca14 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -2278,7 +2278,7 @@ srp_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason) max_depth = 1; if (qdepth > max_depth) qdepth = max_depth; - scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth); + scsi_adjust_queue_depth(sdev, qdepth); } else if (reason == SCSI_QDEPTH_QFULL) scsi_track_queue_full(sdev, qdepth); else diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index c0d84a09db9a..dee06d6f0b68 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -2347,7 +2347,7 @@ mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason) if (qdepth > max_depth) qdepth = max_depth; - scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth); + scsi_adjust_queue_depth(sdev, qdepth); return sdev->queue_depth; } diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 7b353647cb90..b5dfa51f396f 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -37,13 +37,13 @@ static int zfcp_scsi_change_queue_depth(struct scsi_device *sdev, int depth, { switch (reason) { case SCSI_QDEPTH_DEFAULT: - scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth); + scsi_adjust_queue_depth(sdev, depth); break; case SCSI_QDEPTH_QFULL: scsi_track_queue_full(sdev, depth); break; case SCSI_QDEPTH_RAMP_UP: - scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth); + scsi_adjust_queue_depth(sdev, depth); break; default: return -EOPNOTSUPP; @@ -66,9 +66,7 @@ static void zfcp_scsi_slave_destroy(struct scsi_device *sdev) static int zfcp_scsi_slave_configure(struct scsi_device *sdp) { if (sdp->tagged_supported) - scsi_adjust_queue_depth(sdp, MSG_SIMPLE_TAG, default_depth); - else - scsi_adjust_queue_depth(sdp, 0, 1); + scsi_adjust_queue_depth(sdp, default_depth); return 0; } diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c index 0a7325361d29..02021f5ca866 100644 --- a/drivers/scsi/3w-9xxx.c +++ b/drivers/scsi/3w-9xxx.c @@ -198,7 +198,7 @@ static int twa_change_queue_depth(struct scsi_device *sdev, int queue_depth, if (queue_depth > TW_Q_LENGTH-2) queue_depth = TW_Q_LENGTH-2; - scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth); + scsi_adjust_queue_depth(sdev, queue_depth); return queue_depth; } /* End twa_change_queue_depth() */ diff --git a/drivers/scsi/3w-sas.c b/drivers/scsi/3w-sas.c index 6da6cec9a651..ac0c2544a470 100644 --- a/drivers/scsi/3w-sas.c +++ b/drivers/scsi/3w-sas.c @@ -200,7 +200,7 @@ static int twl_change_queue_depth(struct scsi_device *sdev, int queue_depth, if (queue_depth > TW_Q_LENGTH-2) queue_depth = TW_Q_LENGTH-2; - scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth); + scsi_adjust_queue_depth(sdev, queue_depth); return queue_depth; } /* End twl_change_queue_depth() */ diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c index 752624e6bc00..1ec9ad92b6c3 100644 --- a/drivers/scsi/3w-xxxx.c +++ b/drivers/scsi/3w-xxxx.c @@ -532,7 +532,7 @@ static int tw_change_queue_depth(struct scsi_device *sdev, int queue_depth, if (queue_depth > TW_Q_LENGTH-2) queue_depth = TW_Q_LENGTH-2; - scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth); + scsi_adjust_queue_depth(sdev, queue_depth); return queue_depth; } /* End tw_change_queue_depth() */ diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c index 497cbb1efd4b..d7557b932113 100644 --- a/drivers/scsi/53c700.c +++ b/drivers/scsi/53c700.c @@ -902,8 +902,10 @@ process_message(struct Scsi_Host *host, struct NCR_700_Host_Parameters *hostdata /* we're done negotiating */ NCR_700_set_tag_neg_state(SCp->device, NCR_700_FINISHED_TAG_NEGOTIATION); hostdata->tag_negotiated &= ~(1<device->tagged_supported = 0; - scsi_adjust_queue_depth(SCp->device, 0, host->cmd_per_lun); + scsi_adjust_queue_depth(SCp->device, host->cmd_per_lun); + scsi_set_tag_type(SCp->device, 0); } else { shost_printk(KERN_WARNING, host, "(%d:%d) Unexpected REJECT Message %s\n", @@ -2050,12 +2052,10 @@ NCR_700_slave_configure(struct scsi_device *SDp) /* to do here: allocate memory; build a queue_full list */ if(SDp->tagged_supported) { - scsi_adjust_queue_depth(SDp, MSG_ORDERED_TAG, NCR_700_DEFAULT_TAGS); + scsi_adjust_queue_depth(SDp, NCR_700_DEFAULT_TAGS); NCR_700_set_tag_neg_state(SDp, NCR_700_START_TAG_NEGOTIATION); - } else { - /* initialise to default depth */ - scsi_adjust_queue_depth(SDp, 0, SDp->host->cmd_per_lun); } + if(hostdata->fast) { /* Find the correct offset and period via domain validation */ if (!spi_initial_dv(SDp->sdev_target)) @@ -2083,7 +2083,7 @@ NCR_700_change_queue_depth(struct scsi_device *SDp, int depth, int reason) if (depth > NCR_700_MAX_TAGS) depth = NCR_700_MAX_TAGS; - scsi_adjust_queue_depth(SDp, scsi_get_tag_type(SDp), depth); + scsi_adjust_queue_depth(SDp, depth); return depth; } @@ -2101,15 +2101,16 @@ static int NCR_700_change_queue_type(struct scsi_device *SDp, int tag_type) if (change_tag) scsi_target_quiesce(SDp->sdev_target); + scsi_set_tag_type(SDp, tag_type); if (!tag_type) { /* shift back to the default unqueued number of commands * (the user can still raise this) */ - scsi_adjust_queue_depth(SDp, 0, SDp->host->cmd_per_lun); + scsi_adjust_queue_depth(SDp, SDp->host->cmd_per_lun); hostdata->tag_negotiated &= ~(1 << sdev_id(SDp)); } else { /* Here, we cleared the negotiation flag above, so this * will force the driver to renegotiate */ - scsi_adjust_queue_depth(SDp, tag_type, SDp->queue_depth); + scsi_adjust_queue_depth(SDp, SDp->queue_depth); if (change_tag) NCR_700_set_tag_neg_state(SDp, NCR_700_START_TAG_NEGOTIATION); } diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c index 64c75143c89a..5aa476b6b8a8 100644 --- a/drivers/scsi/BusLogic.c +++ b/drivers/scsi/BusLogic.c @@ -2327,12 +2327,12 @@ static int blogic_slaveconfig(struct scsi_device *dev) if (qdepth == 0) qdepth = BLOGIC_MAX_AUTO_TAG_DEPTH; adapter->qdepth[tgt_id] = qdepth; - scsi_adjust_queue_depth(dev, MSG_SIMPLE_TAG, qdepth); + scsi_adjust_queue_depth(dev, qdepth); } else { adapter->tagq_ok &= ~(1 << tgt_id); qdepth = adapter->untag_qdepth; adapter->qdepth[tgt_id] = qdepth; - scsi_adjust_queue_depth(dev, 0, qdepth); + scsi_adjust_queue_depth(dev, qdepth); } qdepth = 0; for (tgt_id = 0; tgt_id < adapter->maxdev; tgt_id++) diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index a759cb2d4b15..41b9c68bca67 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -462,9 +462,9 @@ static int aac_slave_configure(struct scsi_device *sdev) depth = 256; else if (depth < 2) depth = 2; - scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, depth); + scsi_adjust_queue_depth(sdev, depth); } else - scsi_adjust_queue_depth(sdev, 0, 1); + scsi_adjust_queue_depth(sdev, 1); return 0; } @@ -504,9 +504,9 @@ static int aac_change_queue_depth(struct scsi_device *sdev, int depth, depth = 256; else if (depth < 2) depth = 2; - scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, depth); + scsi_adjust_queue_depth(sdev, depth); } else - scsi_adjust_queue_depth(sdev, 0, 1); + scsi_adjust_queue_depth(sdev, 1); return sdev->queue_depth; } diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index 43761c1c46f0..ae4840e4c1c5 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -7706,7 +7706,7 @@ advansys_narrow_slave_configure(struct scsi_device *sdev, ASC_DVC_VAR *asc_dvc) asc_dvc->cfg->can_tagged_qng |= tid_bit; asc_dvc->use_tagged_qng |= tid_bit; } - scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, + scsi_adjust_queue_depth(sdev, asc_dvc->max_dvc_qng[sdev->id]); } } else { @@ -7714,7 +7714,6 @@ advansys_narrow_slave_configure(struct scsi_device *sdev, ASC_DVC_VAR *asc_dvc) asc_dvc->cfg->can_tagged_qng &= ~tid_bit; asc_dvc->use_tagged_qng &= ~tid_bit; } - scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun); } if ((sdev->lun == 0) && @@ -7849,10 +7848,8 @@ advansys_wide_slave_configure(struct scsi_device *sdev, ADV_DVC_VAR *adv_dvc) } if ((adv_dvc->tagqng_able & tidmask) && sdev->tagged_supported) { - scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, + scsi_adjust_queue_depth(sdev, adv_dvc->max_dvc_qng); - } else { - scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun); } } diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index 9fd6b5618b25..80cb4fd7caaa 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -1469,11 +1469,8 @@ ahd_platform_set_tags(struct ahd_softc *ahd, struct scsi_device *sdev, switch ((dev->flags & (AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED))) { case AHD_DEV_Q_BASIC: - scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TASK, - dev->openings + dev->active); - break; case AHD_DEV_Q_TAGGED: - scsi_adjust_queue_depth(sdev, MSG_ORDERED_TASK, + scsi_adjust_queue_depth(sdev, dev->openings + dev->active); break; default: @@ -1483,7 +1480,7 @@ ahd_platform_set_tags(struct ahd_softc *ahd, struct scsi_device *sdev, * serially on the controller/device. This should * remove some latency. */ - scsi_adjust_queue_depth(sdev, 0, 1); + scsi_adjust_queue_depth(sdev, 1); break; } } diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index f18b6d69d3fb..a6a27d5398dd 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -1335,13 +1335,9 @@ ahc_platform_set_tags(struct ahc_softc *ahc, struct scsi_device *sdev, } switch ((dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED))) { case AHC_DEV_Q_BASIC: - scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TASK, - dev->openings + dev->active); - break; case AHC_DEV_Q_TAGGED: - scsi_adjust_queue_depth(sdev, MSG_ORDERED_TASK, + scsi_adjust_queue_depth(sdev, dev->openings + dev->active); - break; default: /* * We allow the OS to queue 2 untagged transactions to @@ -1349,7 +1345,7 @@ ahc_platform_set_tags(struct ahc_softc *ahc, struct scsi_device *sdev, * serially on the controller/device. This should * remove some latency. */ - scsi_adjust_queue_depth(sdev, 0, 2); + scsi_adjust_queue_depth(sdev, 2); break; } } diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index 0b44fb5ee485..209f77162d06 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -122,7 +122,7 @@ static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev, if (queue_depth > ARCMSR_MAX_CMD_PERLUN) queue_depth = ARCMSR_MAX_CMD_PERLUN; - scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth); + scsi_adjust_queue_depth(sdev, queue_depth); return queue_depth; } diff --git a/drivers/scsi/bfa/bfad_im.c b/drivers/scsi/bfa/bfad_im.c index d8e43c81d19b..87b09cd232cc 100644 --- a/drivers/scsi/bfa/bfad_im.c +++ b/drivers/scsi/bfa/bfad_im.c @@ -776,7 +776,7 @@ bfad_thread_workq(struct bfad_s *bfad) static int bfad_im_slave_configure(struct scsi_device *sdev) { - scsi_adjust_queue_depth(sdev, 0, bfa_lun_queue_depth); + scsi_adjust_queue_depth(sdev, bfa_lun_queue_depth); return 0; } @@ -867,7 +867,6 @@ bfad_ramp_up_qdepth(struct bfad_itnim_s *itnim, struct scsi_device *sdev) if (tmp_sdev->id != sdev->id) continue; scsi_adjust_queue_depth(tmp_sdev, - MSG_SIMPLE_TAG, tmp_sdev->queue_depth + 1); itnim->last_ramp_up_time = jiffies; diff --git a/drivers/scsi/csiostor/csio_scsi.c b/drivers/scsi/csiostor/csio_scsi.c index f73155db80a3..44a8cc51428f 100644 --- a/drivers/scsi/csiostor/csio_scsi.c +++ b/drivers/scsi/csiostor/csio_scsi.c @@ -2241,7 +2241,7 @@ csio_slave_alloc(struct scsi_device *sdev) static int csio_slave_configure(struct scsi_device *sdev) { - scsi_adjust_queue_depth(sdev, 0, csio_lun_qdepth); + scsi_adjust_queue_depth(sdev, csio_lun_qdepth); return 0; } diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c index 072f0ec2851e..1af8d54bcded 100644 --- a/drivers/scsi/dpt_i2o.c +++ b/drivers/scsi/dpt_i2o.c @@ -415,10 +415,8 @@ static int adpt_slave_configure(struct scsi_device * device) pHba = (adpt_hba *) host->hostdata[0]; if (host->can_queue && device->tagged_supported) { - scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG, + scsi_adjust_queue_depth(device, host->can_queue - 1); - } else { - scsi_adjust_queue_depth(device, 0, 1); } return 0; } diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c index 943ad3a19661..bc0f918f1729 100644 --- a/drivers/scsi/eata.c +++ b/drivers/scsi/eata.c @@ -946,20 +946,18 @@ static int eata2x_slave_configure(struct scsi_device *dev) if (TLDEV(dev->type) && dev->tagged_supported) { if (tag_mode == TAG_SIMPLE) { - scsi_adjust_queue_depth(dev, MSG_SIMPLE_TAG, tqd); tag_suffix = ", simple tags"; } else if (tag_mode == TAG_ORDERED) { - scsi_adjust_queue_depth(dev, MSG_ORDERED_TAG, tqd); tag_suffix = ", ordered tags"; } else { - scsi_adjust_queue_depth(dev, 0, tqd); tag_suffix = ", no tags"; } + scsi_adjust_queue_depth(dev, tqd); } else if (TLDEV(dev->type) && linked_comm) { - scsi_adjust_queue_depth(dev, 0, tqd); + scsi_adjust_queue_depth(dev, tqd); tag_suffix = ", untagged"; } else { - scsi_adjust_queue_depth(dev, 0, utqd); + scsi_adjust_queue_depth(dev, utqd); tag_suffix = ""; } diff --git a/drivers/scsi/esas2r/esas2r.h b/drivers/scsi/esas2r/esas2r.h index 20ab211983f2..1941d837f6f2 100644 --- a/drivers/scsi/esas2r/esas2r.h +++ b/drivers/scsi/esas2r/esas2r.h @@ -972,9 +972,6 @@ u8 handle_hba_ioctl(struct esas2r_adapter *a, struct atto_ioctl *ioctl_hba); int esas2r_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd); int esas2r_show_info(struct seq_file *m, struct Scsi_Host *sh); -int esas2r_slave_alloc(struct scsi_device *dev); -int esas2r_slave_configure(struct scsi_device *dev); -void esas2r_slave_destroy(struct scsi_device *dev); int esas2r_change_queue_depth(struct scsi_device *dev, int depth, int reason); long esas2r_proc_ioctl(struct file *fp, unsigned int cmd, unsigned long arg); diff --git a/drivers/scsi/esas2r/esas2r_main.c b/drivers/scsi/esas2r/esas2r_main.c index a020b09ba347..30fce64faf75 100644 --- a/drivers/scsi/esas2r/esas2r_main.c +++ b/drivers/scsi/esas2r/esas2r_main.c @@ -254,9 +254,6 @@ static struct scsi_host_template driver_template = { .use_clustering = ENABLE_CLUSTERING, .emulated = 0, .proc_name = ESAS2R_DRVR_NAME, - .slave_configure = esas2r_slave_configure, - .slave_alloc = esas2r_slave_alloc, - .slave_destroy = esas2r_slave_destroy, .change_queue_depth = esas2r_change_queue_depth, .change_queue_type = scsi_change_queue_type, .max_sectors = 0xFFFF, @@ -1264,35 +1261,11 @@ int esas2r_change_queue_depth(struct scsi_device *dev, int depth, int reason) { esas2r_log(ESAS2R_LOG_INFO, "change_queue_depth %p, %d", dev, depth); - scsi_adjust_queue_depth(dev, scsi_get_tag_type(dev), depth); + scsi_adjust_queue_depth(dev, depth); return dev->queue_depth; } -int esas2r_slave_alloc(struct scsi_device *dev) -{ - return 0; -} - -int esas2r_slave_configure(struct scsi_device *dev) -{ - esas2r_log_dev(ESAS2R_LOG_INFO, &(dev->sdev_gendev), - "esas2r_slave_configure()"); - - if (dev->tagged_supported) - scsi_adjust_queue_depth(dev, MSG_SIMPLE_TAG, cmd_per_lun); - else - scsi_adjust_queue_depth(dev, 0, cmd_per_lun); - - return 0; -} - -void esas2r_slave_destroy(struct scsi_device *dev) -{ - esas2r_log_dev(ESAS2R_LOG_INFO, &(dev->sdev_gendev), - "esas2r_slave_destroy()"); -} - void esas2r_log_request_failure(struct esas2r_adapter *a, struct esas2r_request *rq) { diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c index 66b6ce10b259..38c23e0b73af 100644 --- a/drivers/scsi/esp_scsi.c +++ b/drivers/scsi/esp_scsi.c @@ -2402,27 +2402,14 @@ static int esp_slave_configure(struct scsi_device *dev) { struct esp *esp = shost_priv(dev->host); struct esp_target_data *tp = &esp->target[dev->id]; - int goal_tags, queue_depth; - - goal_tags = 0; if (dev->tagged_supported) { /* XXX make this configurable somehow XXX */ - goal_tags = ESP_DEFAULT_TAGS; + int goal_tags = min(ESP_DEFAULT_TAGS, ESP_MAX_TAG); - if (goal_tags > ESP_MAX_TAG) - goal_tags = ESP_MAX_TAG; + scsi_adjust_queue_depth(dev, goal_tags); } - queue_depth = goal_tags; - if (queue_depth < dev->host->cmd_per_lun) - queue_depth = dev->host->cmd_per_lun; - - if (goal_tags) { - scsi_adjust_queue_depth(dev, MSG_ORDERED_TAG, queue_depth); - } else { - scsi_adjust_queue_depth(dev, 0, queue_depth); - } tp->flags |= ESP_TGT_DISCONNECT; if (!spi_initial_dv(dev->sdev_target)) diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c index 2a6c98b7d4db..0f29e3f89b26 100644 --- a/drivers/scsi/fnic/fnic_main.c +++ b/drivers/scsi/fnic/fnic_main.c @@ -100,7 +100,7 @@ static int fnic_slave_alloc(struct scsi_device *sdev) if (!rport || fc_remote_port_chkready(rport)) return -ENXIO; - scsi_adjust_queue_depth(sdev, 0, fnic_max_qdepth); + scsi_adjust_queue_depth(sdev, fnic_max_qdepth); return 0; } diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c index 0f1ae13ce7c7..4ebbeae161e2 100644 --- a/drivers/scsi/gdth.c +++ b/drivers/scsi/gdth.c @@ -4661,7 +4661,6 @@ static void gdth_flush(gdth_ha_str *ha) /* configure lun */ static int gdth_slave_configure(struct scsi_device *sdev) { - scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun); sdev->skip_ms_page_3f = 1; sdev->skip_ms_page_8 = 1; return 0; diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index cef5d49b59cd..18ea2e16e34f 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4165,7 +4165,7 @@ static int hpsa_change_queue_depth(struct scsi_device *sdev, else if (qdepth > h->nr_cmds) qdepth = h->nr_cmds; - scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth); + scsi_adjust_queue_depth(sdev, qdepth); return sdev->queue_depth; } diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c index dedb62c21b29..151893148abd 100644 --- a/drivers/scsi/hptiop.c +++ b/drivers/scsi/hptiop.c @@ -1127,7 +1127,7 @@ static int hptiop_adjust_disk_queue_depth(struct scsi_device *sdev, if (queue_depth > hba->max_requests) queue_depth = hba->max_requests; - scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth); + scsi_adjust_queue_depth(sdev, queue_depth); return queue_depth; } diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index 4723d89df5ac..147b80e07b00 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -2887,12 +2887,6 @@ static int ibmvfc_slave_configure(struct scsi_device *sdev) spin_lock_irqsave(shost->host_lock, flags); if (sdev->type == TYPE_DISK) sdev->allow_restart = 1; - - if (sdev->tagged_supported) - scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, - sdev->queue_depth); - else - scsi_adjust_queue_depth(sdev, 0, sdev->queue_depth); spin_unlock_irqrestore(shost->host_lock, flags); return 0; } @@ -2915,7 +2909,7 @@ static int ibmvfc_change_queue_depth(struct scsi_device *sdev, int qdepth, if (qdepth > IBMVFC_MAX_CMDS_PER_LUN) qdepth = IBMVFC_MAX_CMDS_PER_LUN; - scsi_adjust_queue_depth(sdev, 0, qdepth); + scsi_adjust_queue_depth(sdev, qdepth); return sdev->queue_depth; } diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 7b23f21f22f1..e8c3cdf0d03b 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -1929,7 +1929,6 @@ static int ibmvscsi_slave_configure(struct scsi_device *sdev) blk_queue_rq_timeout(sdev->request_queue, 120 * HZ); } spin_unlock_irqrestore(shost->host_lock, lock_flags); - scsi_adjust_queue_depth(sdev, 0, shost->cmd_per_lun); return 0; } @@ -1951,7 +1950,7 @@ static int ibmvscsi_change_queue_depth(struct scsi_device *sdev, int qdepth, if (qdepth > IBMVSCSI_MAX_CMDS_PER_LUN) qdepth = IBMVSCSI_MAX_CMDS_PER_LUN; - scsi_adjust_queue_depth(sdev, 0, qdepth); + scsi_adjust_queue_depth(sdev, qdepth); return sdev->queue_depth; } diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index f84fcb9a6ed7..256ef98f5c29 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -4344,7 +4344,7 @@ static int ipr_change_queue_depth(struct scsi_device *sdev, int qdepth, qdepth = IPR_MAX_CMD_PER_ATA_LUN; spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth); + scsi_adjust_queue_depth(sdev, qdepth); return sdev->queue_depth; } @@ -4751,10 +4751,10 @@ static int ipr_slave_configure(struct scsi_device *sdev) spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); if (ap) { - scsi_adjust_queue_depth(sdev, 0, IPR_MAX_CMD_PER_ATA_LUN); + scsi_adjust_queue_depth(sdev, IPR_MAX_CMD_PER_ATA_LUN); ata_sas_slave_configure(sdev, ap); - } else - scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun); + } + if (ioa_cfg->sis64) sdev_printk(KERN_INFO, sdev, "Resource path: %s\n", ipr_format_res_path(ioa_cfg, diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c index e5afc3884d74..454741a8da45 100644 --- a/drivers/scsi/ips.c +++ b/drivers/scsi/ips.c @@ -1210,7 +1210,7 @@ ips_slave_configure(struct scsi_device * SDptr) min = ha->max_cmds / 2; if (ha->enq->ucLogDriveCount <= 2) min = ha->max_cmds - 1; - scsi_adjust_queue_depth(SDptr, MSG_ORDERED_TAG, min); + scsi_adjust_queue_depth(SDptr, min); } SDptr->skip_ms_page_8 = 1; diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index d4bb642f2681..bf954ee050f8 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -2160,7 +2160,7 @@ int fc_slave_alloc(struct scsi_device *sdev) if (!rport || fc_remote_port_chkready(rport)) return -ENXIO; - scsi_adjust_queue_depth(sdev, 0, FC_FCP_DFLT_QUEUE_DEPTH); + scsi_adjust_queue_depth(sdev, FC_FCP_DFLT_QUEUE_DEPTH); return 0; } EXPORT_SYMBOL(fc_slave_alloc); @@ -2175,13 +2175,13 @@ int fc_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason) { switch (reason) { case SCSI_QDEPTH_DEFAULT: - scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth); + scsi_adjust_queue_depth(sdev, qdepth); break; case SCSI_QDEPTH_QFULL: scsi_track_queue_full(sdev, qdepth); break; case SCSI_QDEPTH_RAMP_UP: - scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth); + scsi_adjust_queue_depth(sdev, qdepth); break; default: return -EOPNOTSUPP; diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 0d8bc6c66650..d521624dedfb 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1775,13 +1775,13 @@ int iscsi_change_queue_depth(struct scsi_device *sdev, int depth, int reason) { switch (reason) { case SCSI_QDEPTH_DEFAULT: - scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth); + scsi_adjust_queue_depth(sdev, depth); break; case SCSI_QDEPTH_QFULL: scsi_track_queue_full(sdev, depth); break; case SCSI_QDEPTH_RAMP_UP: - scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth); + scsi_adjust_queue_depth(sdev, depth); break; default: return -EOPNOTSUPP; diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index eee21a060d93..56d698af073d 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -940,13 +940,13 @@ int sas_slave_configure(struct scsi_device *scsi_dev) sas_read_port_mode_page(scsi_dev); if (scsi_dev->tagged_supported) { - scsi_adjust_queue_depth(scsi_dev, MSG_SIMPLE_TAG, SAS_DEF_QD); + scsi_adjust_queue_depth(scsi_dev, SAS_DEF_QD); } else { SAS_DPRINTK("device %llx, LUN %llx doesn't support " "TCQ\n", SAS_ADDR(dev->sas_addr), scsi_dev->lun); scsi_dev->tagged_supported = 0; - scsi_adjust_queue_depth(scsi_dev, 0, 1); + scsi_adjust_queue_depth(scsi_dev, 1); } scsi_dev->allow_restart = 1; @@ -967,7 +967,7 @@ int sas_change_queue_depth(struct scsi_device *sdev, int depth, int reason) case SCSI_QDEPTH_RAMP_UP: if (!sdev->tagged_supported) depth = 1; - scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth); + scsi_adjust_queue_depth(sdev, depth); break; case SCSI_QDEPTH_QFULL: scsi_track_queue_full(sdev, depth); @@ -979,19 +979,11 @@ int sas_change_queue_depth(struct scsi_device *sdev, int depth, int reason) return depth; } -int sas_change_queue_type(struct scsi_device *scsi_dev, int qt) +int sas_change_queue_type(struct scsi_device *scsi_dev, int type) { - struct domain_device *dev = sdev_to_domain_dev(scsi_dev); - - if (dev_is_sata(dev)) + if (dev_is_sata(sdev_to_domain_dev(scsi_dev))) return -EINVAL; - - if (!scsi_dev->tagged_supported) - return 0; - - scsi_adjust_queue_depth(scsi_dev, qt, scsi_dev->queue_depth); - - return qt; + return scsi_change_queue_type(scsi_dev, type); } int sas_bios_param(struct scsi_device *scsi_dev, diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index a24106a70968..8533ee9b818d 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -320,7 +320,7 @@ lpfc_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason) case SCSI_QDEPTH_DEFAULT: /* change request from sysfs, fall through */ case SCSI_QDEPTH_RAMP_UP: - scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth); + scsi_adjust_queue_depth(sdev, qdepth); break; case SCSI_QDEPTH_QFULL: if (scsi_track_queue_full(sdev, qdepth) == 0) @@ -5598,7 +5598,7 @@ lpfc_slave_configure(struct scsi_device *sdev) struct lpfc_vport *vport = (struct lpfc_vport *) sdev->host->hostdata; struct lpfc_hba *phba = vport->phba; - scsi_adjust_queue_depth(sdev, 0, vport->cfg_lun_queue_depth); + scsi_adjust_queue_depth(sdev, vport->cfg_lun_queue_depth); if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) { lpfc_sli_handle_fast_ring_event(phba, diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c index 531dce419c18..6b077d839f2b 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.c +++ b/drivers/scsi/megaraid/megaraid_mbox.c @@ -349,7 +349,7 @@ static int megaraid_change_queue_depth(struct scsi_device *sdev, int qdepth, if (qdepth > MBOX_MAX_SCSI_CMDS) qdepth = MBOX_MAX_SCSI_CMDS; - scsi_adjust_queue_depth(sdev, 0, qdepth); + scsi_adjust_queue_depth(sdev, qdepth); return sdev->queue_depth; } diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 5640ad1c8214..107244cebd22 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -2594,8 +2594,7 @@ static int megasas_change_queue_depth(struct scsi_device *sdev, if (queue_depth > sdev->host->can_queue) queue_depth = sdev->host->can_queue; - scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), - queue_depth); + scsi_adjust_queue_depth(sdev, queue_depth); return queue_depth; } diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index 69dc166b52bc..42fef914d441 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -1222,7 +1222,7 @@ _scsih_adjust_queue_depth(struct scsi_device *sdev, int qdepth) max_depth = 1; if (qdepth > max_depth) qdepth = max_depth; - scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth); + scsi_adjust_queue_depth(sdev, qdepth); } /** diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index d3abf254341d..b23c2e7588e5 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -1090,7 +1090,7 @@ _scsih_adjust_queue_depth(struct scsi_device *sdev, int qdepth) max_depth = 1; if (qdepth > max_depth) qdepth = max_depth; - scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth); + scsi_adjust_queue_depth(sdev, qdepth); } /** diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c index a7305ffc359d..9c331b7bfdcd 100644 --- a/drivers/scsi/ncr53c8xx.c +++ b/drivers/scsi/ncr53c8xx.c @@ -7997,10 +7997,7 @@ static int ncr53c8xx_slave_configure(struct scsi_device *device) if (depth_to_use > MAX_TAGS) depth_to_use = MAX_TAGS; - scsi_adjust_queue_depth(device, - (device->tagged_supported ? - MSG_SIMPLE_TAG : 0), - depth_to_use); + scsi_adjust_queue_depth(device, depth_to_use); /* ** Since the queue depth is not tunable under Linux, diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c index 71f9f59b13c6..d8b9ba251fbd 100644 --- a/drivers/scsi/pmcraid.c +++ b/drivers/scsi/pmcraid.c @@ -249,14 +249,11 @@ static int pmcraid_slave_configure(struct scsi_device *scsi_dev) PMCRAID_VSET_MAX_SECTORS); } - if (scsi_dev->tagged_supported && - (RES_IS_GSCSI(res->cfg_entry) || RES_IS_VSET(res->cfg_entry))) { - scsi_adjust_queue_depth(scsi_dev, MSG_SIMPLE_TAG, - scsi_dev->host->cmd_per_lun); - } else { - scsi_adjust_queue_depth(scsi_dev, 0, - scsi_dev->host->cmd_per_lun); - } + /* + * We never want to report TCQ support for these types of devices. + */ + if (!RES_IS_GSCSI(res->cfg_entry) && !RES_IS_VSET(res->cfg_entry)) + scsi_dev->tagged_supported = 0; return 0; } @@ -302,34 +299,11 @@ static int pmcraid_change_queue_depth(struct scsi_device *scsi_dev, int depth, if (depth > PMCRAID_MAX_CMD_PER_LUN) depth = PMCRAID_MAX_CMD_PER_LUN; - scsi_adjust_queue_depth(scsi_dev, scsi_get_tag_type(scsi_dev), depth); + scsi_adjust_queue_depth(scsi_dev, depth); return scsi_dev->queue_depth; } -/** - * pmcraid_change_queue_type - Change the device's queue type - * @scsi_dev: scsi device struct - * @tag: type of tags to use - * - * Return value: - * actual queue type set - */ -static int pmcraid_change_queue_type(struct scsi_device *scsi_dev, int tag) -{ - struct pmcraid_resource_entry *res; - - res = (struct pmcraid_resource_entry *)scsi_dev->hostdata; - if (res && scsi_dev->tagged_supported && - (RES_IS_GSCSI(res->cfg_entry) || RES_IS_VSET(res->cfg_entry))) - tag = scsi_change_queue_type(scsi_dev, tag); - else - tag = 0; - - return tag; -} - - /** * pmcraid_init_cmdblk - initializes a command block * @@ -4285,7 +4259,7 @@ static struct scsi_host_template pmcraid_host_template = { .slave_configure = pmcraid_slave_configure, .slave_destroy = pmcraid_slave_destroy, .change_queue_depth = pmcraid_change_queue_depth, - .change_queue_type = pmcraid_change_queue_type, + .change_queue_type = scsi_change_queue_type, .can_queue = PMCRAID_MAX_IO_CMD, .this_id = -1, .sg_tablesize = PMCRAID_MAX_IOADLS, diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 158020522dfb..adedb6ef8eec 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -1224,10 +1224,9 @@ qla1280_slave_configure(struct scsi_device *device) if (device->tagged_supported && (ha->bus_settings[bus].qtag_enables & (BIT_0 << target))) { - scsi_adjust_queue_depth(device, MSG_ORDERED_TAG, - ha->bus_settings[bus].hiwat); + scsi_adjust_queue_depth(device, ha->bus_settings[bus].hiwat); } else { - scsi_adjust_queue_depth(device, 0, default_depth); + scsi_adjust_queue_depth(device, default_depth); } nv->bus[bus].target[target].parameter.enable_sync = device->sdtr; diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index eb0465305f8d..33166ebec7d8 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1405,7 +1405,7 @@ qla2xxx_slave_configure(struct scsi_device *sdev) if (IS_T10_PI_CAPABLE(vha->hw)) blk_queue_update_dma_alignment(sdev->request_queue, 0x7); - scsi_adjust_queue_depth(sdev, 0, req->max_q_depth); + scsi_adjust_queue_depth(sdev, req->max_q_depth); return 0; } @@ -1440,7 +1440,7 @@ static void qla2x00_adjust_sdev_qdepth_up(struct scsi_device *sdev, int qdepth) if (req->max_q_depth <= sdev->queue_depth || req->max_q_depth < qdepth) return; - scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, qdepth); + scsi_adjust_queue_depth(sdev, qdepth); ql_dbg(ql_dbg_io, vha, 0x302a, "Queue depth adjusted-up to %d for nexus=%ld:%d:%llu.\n", @@ -1452,7 +1452,7 @@ qla2x00_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason) { switch (reason) { case SCSI_QDEPTH_DEFAULT: - scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth); + scsi_adjust_queue_depth(sdev, qdepth); break; case SCSI_QDEPTH_QFULL: qla2x00_handle_queue_full(sdev, qdepth); diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index f3119c144e29..784f59e55510 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -9064,7 +9064,7 @@ static int qla4xxx_slave_alloc(struct scsi_device *sdev) if (ql4xmaxqdepth != 0 && ql4xmaxqdepth <= 0xffffU) queue_depth = ql4xmaxqdepth; - scsi_adjust_queue_depth(sdev, 0, queue_depth); + scsi_adjust_queue_depth(sdev, queue_depth); return 0; } diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index a3426f1bf0dd..106fa2f886d2 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -744,8 +744,6 @@ void scsi_finish_command(struct scsi_cmnd *cmd) /** * scsi_adjust_queue_depth - Let low level drivers change a device's queue depth * @sdev: SCSI Device in question - * @tagged: Do we use tagged queueing (non-0) or do we treat - * this device as an untagged device (0) * @tags: Number of tags allowed if tagged queueing enabled, * or number of commands the low level driver can * queue up in non-tagged mode (as per cmd_per_lun). @@ -759,7 +757,7 @@ void scsi_finish_command(struct scsi_cmnd *cmd) * currently active and whether or not it even has the * command blocks built yet. */ -void scsi_adjust_queue_depth(struct scsi_device *sdev, int tagged, int tags) +void scsi_adjust_queue_depth(struct scsi_device *sdev, int tags) { unsigned long flags; @@ -787,20 +785,6 @@ void scsi_adjust_queue_depth(struct scsi_device *sdev, int tagged, int tags) } sdev->queue_depth = tags; - switch (tagged) { - case 0: - sdev->simple_tags = 0; - break; - case MSG_ORDERED_TAG: - case MSG_SIMPLE_TAG: - sdev->simple_tags = 1; - break; - default: - sdev->simple_tags = 0; - sdev_printk(KERN_WARNING, sdev, - "scsi_adjust_queue_depth, bad queue type, " - "disabled\n"); - } out: spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); } @@ -848,11 +832,12 @@ int scsi_track_queue_full(struct scsi_device *sdev, int depth) return 0; if (sdev->last_queue_full_depth < 8) { /* Drop back to untagged */ - scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun); + scsi_set_tag_type(sdev, 0); + scsi_adjust_queue_depth(sdev, sdev->host->cmd_per_lun); return -1; } - scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, depth); + scsi_adjust_queue_depth(sdev, depth); return depth; } EXPORT_SYMBOL(scsi_track_queue_full); @@ -867,7 +852,7 @@ int scsi_change_queue_type(struct scsi_device *sdev, int tag_type) if (!sdev->tagged_supported) return 0; - scsi_adjust_queue_depth(sdev, tag_type, sdev->queue_depth); + scsi_set_tag_type(sdev, tag_type); return tag_type; } diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 7bcace2cdd53..fce4e47becc7 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -2700,11 +2700,8 @@ static int scsi_debug_slave_configure(struct scsi_device *sdp) devip = devInfoReg(sdp); if (NULL == devip) return 1; /* no resources, will be marked offline */ - sdp->hostdata = devip; sdp->tagged_supported = 1; - if (sdp->host->cmd_per_lun) - scsi_adjust_queue_depth(sdp, DEF_TAGGED_QUEUING, - DEF_CMD_PER_LUN); + sdp->hostdata = devip; blk_queue_max_segment_size(sdp->request_queue, -1U); if (scsi_debug_no_uld) sdp->no_uld_attach = 1; @@ -4494,7 +4491,7 @@ sdebug_change_qdepth(struct scsi_device *sdev, int qdepth, int reason) /* allow to exceed max host queued_arr elements for testing */ if (qdepth > SCSI_DEBUG_CANQUEUE + 10) qdepth = SCSI_DEBUG_CANQUEUE + 10; - scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth); + scsi_adjust_queue_depth(sdev, qdepth); } else if (reason == SCSI_QDEPTH_QFULL) scsi_track_queue_full(sdev, qdepth); else diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 408891cb14ff..d97597e6337e 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -292,7 +292,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget, blk_queue_init_tags(sdev->request_queue, sdev->host->cmd_per_lun, shost->bqt); } - scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun); + scsi_adjust_queue_depth(sdev, sdev->host->cmd_per_lun); scsi_sysfs_device_initialize(sdev); @@ -880,8 +880,10 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, (inq_result[3] & 0x0f) == 1 ? " CCS" : ""); if ((sdev->scsi_level >= SCSI_2) && (inq_result[7] & 2) && - !(*bflags & BLIST_NOTQ)) + !(*bflags & BLIST_NOTQ)) { sdev->tagged_supported = 1; + sdev->simple_tags = 1; + } /* * Some devices (Texel CD ROM drives) have handshaking problems diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c index b5eae4f6ba46..2bb8a9e74dac 100644 --- a/drivers/scsi/stex.c +++ b/drivers/scsi/stex.c @@ -549,8 +549,6 @@ stex_slave_alloc(struct scsi_device *sdev) /* Cheat: usually extracted from Inquiry data */ sdev->tagged_supported = 1; - scsi_adjust_queue_depth(sdev, 0, sdev->host->can_queue); - return 0; } diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index 37f5fd8ed765..ff8befbdf17c 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -1429,8 +1429,7 @@ static void storvsc_device_destroy(struct scsi_device *sdevice) static int storvsc_device_configure(struct scsi_device *sdevice) { - scsi_adjust_queue_depth(sdevice, MSG_SIMPLE_TAG, - STORVSC_MAX_IO_REQUESTS); + scsi_adjust_queue_depth(sdevice, STORVSC_MAX_IO_REQUESTS); blk_queue_max_segment_size(sdevice->request_queue, PAGE_SIZE); diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c index e59e6f96b725..3557b385251a 100644 --- a/drivers/scsi/sym53c8xx_2/sym_glue.c +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c @@ -820,9 +820,7 @@ static int sym53c8xx_slave_configure(struct scsi_device *sdev) if (reqtags > SYM_CONF_MAX_TAG) reqtags = SYM_CONF_MAX_TAG; depth_to_use = reqtags ? reqtags : 1; - scsi_adjust_queue_depth(sdev, - sdev->tagged_supported ? MSG_SIMPLE_TAG : 0, - depth_to_use); + scsi_adjust_queue_depth(sdev, depth_to_use); lp->s.scdev_depth = depth_to_use; sym_tune_dev_queuing(tp, sdev->lun, reqtags); diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c index 6369f9a282f1..844c9a048c00 100644 --- a/drivers/scsi/tmscsim.c +++ b/drivers/scsi/tmscsim.c @@ -2185,9 +2185,16 @@ static int dc390_slave_configure(struct scsi_device *sdev) struct dc390_dcb *dcb = (struct dc390_dcb *)sdev->hostdata; acb->scan_devices = 0; + + /* + * XXX: Note that while this driver used to called scsi_activate_tcq, + * it never actually set a tag type, so emulate the old behavior. + */ + scsi_set_tag_type(sdev, 0); + if (sdev->tagged_supported && (dcb->DevMode & TAG_QUEUEING_)) { dcb->SyncMode |= EN_TAG_QUEUEING; - scsi_adjust_queue_depth(sdev, 0, acb->TagMaxNum); + scsi_adjust_queue_depth(sdev, acb->TagMaxNum); } return 0; diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c index d8dcf36aed11..aa0f4035afaf 100644 --- a/drivers/scsi/u14-34f.c +++ b/drivers/scsi/u14-34f.c @@ -696,25 +696,25 @@ static int u14_34f_slave_configure(struct scsi_device *dev) { if (TLDEV(dev->type) && dev->tagged_supported) if (tag_mode == TAG_SIMPLE) { - scsi_adjust_queue_depth(dev, MSG_SIMPLE_TAG, tqd); + scsi_adjust_queue_depth(dev, tqd); tag_suffix = ", simple tags"; } else if (tag_mode == TAG_ORDERED) { - scsi_adjust_queue_depth(dev, MSG_ORDERED_TAG, tqd); + scsi_adjust_queue_depth(dev, tqd); tag_suffix = ", ordered tags"; } else { - scsi_adjust_queue_depth(dev, 0, tqd); + scsi_adjust_queue_depth(dev, tqd); tag_suffix = ", no tags"; } else if (TLDEV(dev->type) && linked_comm) { - scsi_adjust_queue_depth(dev, 0, tqd); + scsi_adjust_queue_depth(dev, tqd); tag_suffix = ", untagged"; } else { - scsi_adjust_queue_depth(dev, 0, utqd); + scsi_adjust_queue_depth(dev, utqd); tag_suffix = ""; } diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 48c7f9e8f256..5eb4931e2adc 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -2696,7 +2696,7 @@ static void ufshcd_set_queue_depth(struct scsi_device *sdev) dev_dbg(hba->dev, "%s: activate tcq with queue depth %d\n", __func__, lun_qdepth); if (sdev->tagged_supported) - scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), lun_qdepth); + scsi_adjust_queue_depth(sdev, lun_qdepth); } /* @@ -2808,7 +2808,7 @@ static int ufshcd_change_queue_depth(struct scsi_device *sdev, case SCSI_QDEPTH_RAMP_UP: if (!sdev->tagged_supported) depth = 1; - scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth); + scsi_adjust_queue_depth(sdev, depth); break; case SCSI_QDEPTH_QFULL: scsi_track_queue_full(sdev, depth); diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c index b83846fc7859..355afbc7fde1 100644 --- a/drivers/scsi/virtio_scsi.c +++ b/drivers/scsi/virtio_scsi.c @@ -683,9 +683,7 @@ static int virtscsi_change_queue_depth(struct scsi_device *sdev, break; case SCSI_QDEPTH_RAMP_UP: /* Raise qdepth after BUSY state resolved */ case SCSI_QDEPTH_DEFAULT: /* Manual change via sysfs */ - scsi_adjust_queue_depth(sdev, - scsi_get_tag_type(sdev), - min(max_depth, qdepth)); + scsi_adjust_queue_depth(sdev, min(max_depth, qdepth)); break; default: return -EOPNOTSUPP; diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c index 53a3eb6c0634..c3b4f8b3a3a5 100644 --- a/drivers/scsi/vmw_pvscsi.c +++ b/drivers/scsi/vmw_pvscsi.c @@ -522,7 +522,7 @@ static int pvscsi_change_queue_depth(struct scsi_device *sdev, max_depth = 1; if (qdepth > max_depth) qdepth = max_depth; - scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth); + scsi_adjust_queue_depth(sdev, qdepth); if (sdev->inquiry_len > 7) sdev_printk(KERN_INFO, sdev, diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index 120a851df0d7..0ed96644ec94 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -121,13 +121,13 @@ static int tcm_loop_change_queue_depth( { switch (reason) { case SCSI_QDEPTH_DEFAULT: - scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth); + scsi_adjust_queue_depth(sdev, depth); break; case SCSI_QDEPTH_QFULL: scsi_track_queue_full(sdev, depth); break; case SCSI_QDEPTH_RAMP_UP: - scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth); + scsi_adjust_queue_depth(sdev, depth); break; default: return -EOPNOTSUPP; @@ -404,19 +404,6 @@ static int tcm_loop_slave_alloc(struct scsi_device *sd) return 0; } -static int tcm_loop_slave_configure(struct scsi_device *sd) -{ - if (sd->tagged_supported) { - scsi_adjust_queue_depth(sd, MSG_SIMPLE_TAG, - sd->host->cmd_per_lun); - } else { - scsi_adjust_queue_depth(sd, 0, - sd->host->cmd_per_lun); - } - - return 0; -} - static struct scsi_host_template tcm_loop_driver_template = { .show_info = tcm_loop_show_info, .proc_name = "tcm_loopback", @@ -434,7 +421,6 @@ static struct scsi_host_template tcm_loop_driver_template = { .max_sectors = 0xFFFF, .use_clustering = DISABLE_CLUSTERING, .slave_alloc = tcm_loop_slave_alloc, - .slave_configure = tcm_loop_slave_configure, .module = THIS_MODULE, .use_blk_tags = 1, }; diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index ee69b82fc7d1..33f211b56a42 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c @@ -799,7 +799,7 @@ static int uas_slave_configure(struct scsi_device *sdev) if (devinfo->flags & US_FL_NO_REPORT_OPCODES) sdev->no_report_opcodes = 1; - scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, devinfo->qdepth - 2); + scsi_adjust_queue_depth(sdev, devinfo->qdepth - 2); return 0; } diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index e8fecb5ea79a..0aeaa003c3c1 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -380,7 +380,7 @@ extern struct scsi_device *__scsi_iterate_devices(struct Scsi_Host *, #define __shost_for_each_device(sdev, shost) \ list_for_each_entry((sdev), &((shost)->__devices), siblings) -extern void scsi_adjust_queue_depth(struct scsi_device *, int, int); +extern void scsi_adjust_queue_depth(struct scsi_device *, int); extern int scsi_track_queue_full(struct scsi_device *, int); extern int scsi_set_medium_removal(struct scsi_device *, char); -- cgit v1.2.3-59-g8ed1b From d92c0da71a35dfddccca7bfa932829504311359e Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 6 Oct 2014 17:14:36 +0200 Subject: IB/srp: Add multichannel support Improve performance by using multiple RDMA/RC channels per SCSI host for communication with an SRP target. About the implementation: - Introduce a loop over all channels in the code that uses target->ch. - Set the SRP_MULTICHAN_MULTI flag during login for the creation of the second and subsequent channels. - RDMA completion vectors are chosen such that RDMA completion interrupts are handled by the CPU socket that submitted the I/O request. As one can see in this patch it has been assumed if a system contains n CPU sockets and m RDMA completion vectors have been assigned to an RDMA HCA that IRQ affinity has been configured such that completion vectors [i*m/n..(i+1)*m/n) are bound to CPU socket i with 0 <= i < n. - Modify srp_free_ch_ib() and srp_free_req_data() such that it becomes safe to invoke these functions after the corresponding allocation function failed. - Add a ch_count sysfs attribute per target port. Signed-off-by: Bart Van Assche Reviewed-by: Sagi Grimberg Signed-off-by: Christoph Hellwig --- Documentation/ABI/stable/sysfs-driver-ib_srp | 25 ++- drivers/infiniband/ulp/srp/ib_srp.c | 288 ++++++++++++++++++++------- drivers/infiniband/ulp/srp/ib_srp.h | 3 +- 3 files changed, 235 insertions(+), 81 deletions(-) (limited to 'Documentation') diff --git a/Documentation/ABI/stable/sysfs-driver-ib_srp b/Documentation/ABI/stable/sysfs-driver-ib_srp index b9688de8455b..7049a2b50359 100644 --- a/Documentation/ABI/stable/sysfs-driver-ib_srp +++ b/Documentation/ABI/stable/sysfs-driver-ib_srp @@ -55,12 +55,12 @@ Description: Interface for making ib_srp connect to a new target. only safe with partial memory descriptor list support enabled (allow_ext_sg=1). * comp_vector, a number in the range 0..n-1 specifying the - MSI-X completion vector. Some HCA's allocate multiple (n) - MSI-X vectors per HCA port. If the IRQ affinity masks of - these interrupts have been configured such that each MSI-X - interrupt is handled by a different CPU then the comp_vector - parameter can be used to spread the SRP completion workload - over multiple CPU's. + MSI-X completion vector of the first RDMA channel. Some + HCA's allocate multiple (n) MSI-X vectors per HCA port. If + the IRQ affinity masks of these interrupts have been + configured such that each MSI-X interrupt is handled by a + different CPU then the comp_vector parameter can be used to + spread the SRP completion workload over multiple CPU's. * tl_retry_count, a number in the range 2..7 specifying the IB RC retry count. * queue_size, the maximum number of commands that the @@ -88,6 +88,13 @@ Description: Whether ib_srp is allowed to include a partial memory descriptor list in an SRP_CMD when communicating with an SRP target. +What: /sys/class/scsi_host/host/ch_count +Date: April 1, 2015 +KernelVersion: 3.19 +Contact: linux-rdma@vger.kernel.org +Description: Number of RDMA channels used for communication with the SRP + target. + What: /sys/class/scsi_host/host/cmd_sg_entries Date: May 19, 2011 KernelVersion: 2.6.39 @@ -95,6 +102,12 @@ Contact: linux-rdma@vger.kernel.org Description: Maximum number of data buffer descriptors that may be sent to the target in a single SRP_CMD request. +What: /sys/class/scsi_host/host/comp_vector +Date: September 2, 2013 +KernelVersion: 3.11 +Contact: linux-rdma@vger.kernel.org +Description: Completion vector used for the first RDMA channel. + What: /sys/class/scsi_host/host/dgid Date: June 17, 2006 KernelVersion: 2.6.17 diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 42af59f3c8c6..aac844a6eef6 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -123,6 +123,11 @@ MODULE_PARM_DESC(dev_loss_tmo, " if fast_io_fail_tmo has not been set. \"off\" means that" " this functionality is disabled."); +static unsigned ch_count; +module_param(ch_count, uint, 0444); +MODULE_PARM_DESC(ch_count, + "Number of RDMA channels to use for communication with an SRP target. Using more than one channel improves performance if the HCA supports multiple completion vectors. The default value is the minimum of four times the number of online CPU sockets and the number of completion vectors supported by the HCA."); + static void srp_add_one(struct ib_device *device); static void srp_remove_one(struct ib_device *device); static void srp_recv_completion(struct ib_cq *cq, void *ch_ptr); @@ -562,11 +567,18 @@ static void srp_free_ch_ib(struct srp_target_port *target, struct srp_device *dev = target->srp_host->srp_dev; int i; + if (!ch->target) + return; + if (ch->cm_id) { ib_destroy_cm_id(ch->cm_id); ch->cm_id = NULL; } + /* If srp_new_cm_id() succeeded but srp_create_ch_ib() not, return. */ + if (!ch->qp) + return; + if (dev->use_fast_reg) { if (ch->fr_pool) srp_destroy_fr_pool(ch->fr_pool); @@ -578,6 +590,14 @@ static void srp_free_ch_ib(struct srp_target_port *target, ib_destroy_cq(ch->send_cq); ib_destroy_cq(ch->recv_cq); + /* + * Avoid that the SCSI error handler tries to use this channel after + * it has been freed. The SCSI error handler can namely continue + * trying to perform recovery actions after scsi_remove_host() + * returned. + */ + ch->target = NULL; + ch->qp = NULL; ch->send_cq = ch->recv_cq = NULL; @@ -647,7 +667,7 @@ static int srp_lookup_path(struct srp_rdma_ch *ch) return ch->status; } -static int srp_send_req(struct srp_rdma_ch *ch) +static int srp_send_req(struct srp_rdma_ch *ch, bool multich) { struct srp_target_port *target = ch->target; struct { @@ -688,6 +708,8 @@ static int srp_send_req(struct srp_rdma_ch *ch) req->priv.req_it_iu_len = cpu_to_be32(target->max_iu_len); req->priv.req_buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT | SRP_BUF_FORMAT_INDIRECT); + req->priv.req_flags = (multich ? SRP_MULTICHAN_MULTI : + SRP_MULTICHAN_SINGLE); /* * In the published SRP specification (draft rev. 16a), the * port identifier format is 8 bytes of ID extension followed @@ -769,14 +791,18 @@ static bool srp_change_conn_state(struct srp_target_port *target, static void srp_disconnect_target(struct srp_target_port *target) { - struct srp_rdma_ch *ch = &target->ch; + struct srp_rdma_ch *ch; + int i; if (srp_change_conn_state(target, false)) { /* XXX should send SRP_I_LOGOUT request */ - if (ib_send_cm_dreq(ch->cm_id, NULL, 0)) { - shost_printk(KERN_DEBUG, target->scsi_host, - PFX "Sending CM DREQ failed\n"); + for (i = 0; i < target->ch_count; i++) { + ch = &target->ch[i]; + if (ch->cm_id && ib_send_cm_dreq(ch->cm_id, NULL, 0)) { + shost_printk(KERN_DEBUG, target->scsi_host, + PFX "Sending CM DREQ failed\n"); + } } } } @@ -789,7 +815,7 @@ static void srp_free_req_data(struct srp_target_port *target, struct srp_request *req; int i; - if (!ch->req_ring) + if (!ch->target || !ch->req_ring) return; for (i = 0; i < target->req_ring_size; ++i) { @@ -875,7 +901,8 @@ static void srp_del_scsi_host_attr(struct Scsi_Host *shost) static void srp_remove_target(struct srp_target_port *target) { - struct srp_rdma_ch *ch = &target->ch; + struct srp_rdma_ch *ch; + int i; WARN_ON_ONCE(target->state != SRP_TARGET_REMOVED); @@ -885,10 +912,18 @@ static void srp_remove_target(struct srp_target_port *target) scsi_remove_host(target->scsi_host); srp_stop_rport_timers(target->rport); srp_disconnect_target(target); - srp_free_ch_ib(target, ch); + for (i = 0; i < target->ch_count; i++) { + ch = &target->ch[i]; + srp_free_ch_ib(target, ch); + } cancel_work_sync(&target->tl_err_work); srp_rport_put(target->rport); - srp_free_req_data(target, ch); + for (i = 0; i < target->ch_count; i++) { + ch = &target->ch[i]; + srp_free_req_data(target, ch); + } + kfree(target->ch); + target->ch = NULL; spin_lock(&target->srp_host->target_lock); list_del(&target->list); @@ -914,12 +949,12 @@ static void srp_rport_delete(struct srp_rport *rport) srp_queue_remove_work(target); } -static int srp_connect_ch(struct srp_rdma_ch *ch) +static int srp_connect_ch(struct srp_rdma_ch *ch, bool multich) { struct srp_target_port *target = ch->target; int ret; - WARN_ON_ONCE(target->connected); + WARN_ON_ONCE(!multich && target->connected); target->qp_in_error = false; @@ -929,7 +964,7 @@ static int srp_connect_ch(struct srp_rdma_ch *ch) while (1) { init_completion(&ch->done); - ret = srp_send_req(ch); + ret = srp_send_req(ch, multich); if (ret) return ret; ret = wait_for_completion_interruptible(&ch->done); @@ -1090,10 +1125,10 @@ static void srp_finish_req(struct srp_rdma_ch *ch, struct srp_request *req, static void srp_terminate_io(struct srp_rport *rport) { struct srp_target_port *target = rport->lld_data; - struct srp_rdma_ch *ch = &target->ch; + struct srp_rdma_ch *ch; struct Scsi_Host *shost = target->scsi_host; struct scsi_device *sdev; - int i; + int i, j; /* * Invoking srp_terminate_io() while srp_queuecommand() is running @@ -1102,10 +1137,15 @@ static void srp_terminate_io(struct srp_rport *rport) shost_for_each_device(sdev, shost) WARN_ON_ONCE(sdev->request_queue->request_fn_active); - for (i = 0; i < target->req_ring_size; ++i) { - struct srp_request *req = &ch->req_ring[i]; + for (i = 0; i < target->ch_count; i++) { + ch = &target->ch[i]; - srp_finish_req(ch, req, NULL, DID_TRANSPORT_FAILFAST << 16); + for (j = 0; j < target->req_ring_size; ++j) { + struct srp_request *req = &ch->req_ring[j]; + + srp_finish_req(ch, req, NULL, + DID_TRANSPORT_FAILFAST << 16); + } } } @@ -1121,8 +1161,9 @@ static void srp_terminate_io(struct srp_rport *rport) static int srp_rport_reconnect(struct srp_rport *rport) { struct srp_target_port *target = rport->lld_data; - struct srp_rdma_ch *ch = &target->ch; - int i, ret; + struct srp_rdma_ch *ch; + int i, j, ret = 0; + bool multich = false; srp_disconnect_target(target); @@ -1134,27 +1175,47 @@ static int srp_rport_reconnect(struct srp_rport *rport) * case things are really fouled up. Doing so also ensures that all CM * callbacks will have finished before a new QP is allocated. */ - ret = srp_new_cm_id(ch); - - for (i = 0; i < target->req_ring_size; ++i) { - struct srp_request *req = &ch->req_ring[i]; - - srp_finish_req(ch, req, NULL, DID_RESET << 16); + for (i = 0; i < target->ch_count; i++) { + ch = &target->ch[i]; + if (!ch->target) + break; + ret += srp_new_cm_id(ch); } + for (i = 0; i < target->ch_count; i++) { + ch = &target->ch[i]; + if (!ch->target) + break; + for (j = 0; j < target->req_ring_size; ++j) { + struct srp_request *req = &ch->req_ring[j]; - /* - * Whether or not creating a new CM ID succeeded, create a new - * QP. This guarantees that all callback functions for the old QP have - * finished before any send requests are posted on the new QP. - */ - ret += srp_create_ch_ib(ch); - - INIT_LIST_HEAD(&ch->free_tx); - for (i = 0; i < target->queue_size; ++i) - list_add(&ch->tx_ring[i]->list, &ch->free_tx); + srp_finish_req(ch, req, NULL, DID_RESET << 16); + } + } + for (i = 0; i < target->ch_count; i++) { + ch = &target->ch[i]; + if (!ch->target) + break; + /* + * Whether or not creating a new CM ID succeeded, create a new + * QP. This guarantees that all completion callback function + * invocations have finished before request resetting starts. + */ + ret += srp_create_ch_ib(ch); - if (ret == 0) - ret = srp_connect_ch(ch); + INIT_LIST_HEAD(&ch->free_tx); + for (j = 0; j < target->queue_size; ++j) + list_add(&ch->tx_ring[j]->list, &ch->free_tx); + } + for (i = 0; i < target->ch_count; i++) { + ch = &target->ch[i]; + if (ret || !ch->target) { + if (i > 1) + ret = 0; + break; + } + ret = srp_connect_ch(ch, multich); + multich = true; + } if (ret == 0) shost_printk(KERN_INFO, target->scsi_host, @@ -1650,8 +1711,8 @@ static void srp_process_rsp(struct srp_rdma_ch *ch, struct srp_rsp *rsp) } if (!scmnd) { shost_printk(KERN_ERR, target->scsi_host, - "Null scmnd for RSP w/tag %016llx\n", - (unsigned long long) rsp->tag); + "Null scmnd for RSP w/tag %#016llx received on ch %td / QP %#x\n", + rsp->tag, ch - target->ch, ch->qp->qp_num); spin_lock_irqsave(&ch->lock, flags); ch->req_lim += be32_to_cpu(rsp->req_lim_delta); @@ -1907,7 +1968,7 @@ static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd) WARN_ON_ONCE(scmnd->request->tag < 0); tag = blk_mq_unique_tag(scmnd->request); - ch = &target->ch; + ch = &target->ch[blk_mq_unique_tag_to_hwq(tag)]; idx = blk_mq_unique_tag_to_tag(tag); WARN_ONCE(idx >= target->req_ring_size, "%s: tag %#x: idx %d >= %d\n", dev_name(&shost->shost_gendev), tag, idx, @@ -2387,15 +2448,23 @@ static int srp_abort(struct scsi_cmnd *scmnd) struct srp_target_port *target = host_to_target(scmnd->device->host); struct srp_request *req = (struct srp_request *) scmnd->host_scribble; u32 tag; + u16 ch_idx; struct srp_rdma_ch *ch; int ret; shost_printk(KERN_ERR, target->scsi_host, "SRP abort called\n"); - ch = &target->ch; - if (!req || !srp_claim_req(ch, req, NULL, scmnd)) + if (!req) return SUCCESS; tag = blk_mq_unique_tag(scmnd->request); + ch_idx = blk_mq_unique_tag_to_hwq(tag); + if (WARN_ON_ONCE(ch_idx >= target->ch_count)) + return SUCCESS; + ch = &target->ch[ch_idx]; + if (!srp_claim_req(ch, req, NULL, scmnd)) + return SUCCESS; + shost_printk(KERN_ERR, target->scsi_host, + "Sending SRP abort for tag %#x\n", tag); if (srp_send_tsk_mgmt(ch, tag, scmnd->device->lun, SRP_TSK_ABORT_TASK) == 0) ret = SUCCESS; @@ -2413,21 +2482,25 @@ static int srp_abort(struct scsi_cmnd *scmnd) static int srp_reset_device(struct scsi_cmnd *scmnd) { struct srp_target_port *target = host_to_target(scmnd->device->host); - struct srp_rdma_ch *ch = &target->ch; + struct srp_rdma_ch *ch; int i; shost_printk(KERN_ERR, target->scsi_host, "SRP reset_device called\n"); + ch = &target->ch[0]; if (srp_send_tsk_mgmt(ch, SRP_TAG_NO_REQ, scmnd->device->lun, SRP_TSK_LUN_RESET)) return FAILED; if (ch->tsk_mgmt_status) return FAILED; - for (i = 0; i < target->req_ring_size; ++i) { - struct srp_request *req = &ch->req_ring[i]; + for (i = 0; i < target->ch_count; i++) { + ch = &target->ch[i]; + for (i = 0; i < target->req_ring_size; ++i) { + struct srp_request *req = &ch->req_ring[i]; - srp_finish_req(ch, req, scmnd->device, DID_RESET << 16); + srp_finish_req(ch, req, scmnd->device, DID_RESET << 16); + } } return SUCCESS; @@ -2504,7 +2577,7 @@ static ssize_t show_dgid(struct device *dev, struct device_attribute *attr, char *buf) { struct srp_target_port *target = host_to_target(class_to_shost(dev)); - struct srp_rdma_ch *ch = &target->ch; + struct srp_rdma_ch *ch = &target->ch[0]; return sprintf(buf, "%pI6\n", ch->path.dgid.raw); } @@ -2521,8 +2594,14 @@ static ssize_t show_req_lim(struct device *dev, struct device_attribute *attr, char *buf) { struct srp_target_port *target = host_to_target(class_to_shost(dev)); + struct srp_rdma_ch *ch; + int i, req_lim = INT_MAX; - return sprintf(buf, "%d\n", target->ch.req_lim); + for (i = 0; i < target->ch_count; i++) { + ch = &target->ch[i]; + req_lim = min(req_lim, ch->req_lim); + } + return sprintf(buf, "%d\n", req_lim); } static ssize_t show_zero_req_lim(struct device *dev, @@ -2549,6 +2628,14 @@ static ssize_t show_local_ib_device(struct device *dev, return sprintf(buf, "%s\n", target->srp_host->srp_dev->dev->name); } +static ssize_t show_ch_count(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct srp_target_port *target = host_to_target(class_to_shost(dev)); + + return sprintf(buf, "%d\n", target->ch_count); +} + static ssize_t show_comp_vector(struct device *dev, struct device_attribute *attr, char *buf) { @@ -2592,6 +2679,7 @@ static DEVICE_ATTR(req_lim, S_IRUGO, show_req_lim, NULL); static DEVICE_ATTR(zero_req_lim, S_IRUGO, show_zero_req_lim, NULL); static DEVICE_ATTR(local_ib_port, S_IRUGO, show_local_ib_port, NULL); static DEVICE_ATTR(local_ib_device, S_IRUGO, show_local_ib_device, NULL); +static DEVICE_ATTR(ch_count, S_IRUGO, show_ch_count, NULL); static DEVICE_ATTR(comp_vector, S_IRUGO, show_comp_vector, NULL); static DEVICE_ATTR(tl_retry_count, S_IRUGO, show_tl_retry_count, NULL); static DEVICE_ATTR(cmd_sg_entries, S_IRUGO, show_cmd_sg_entries, NULL); @@ -2609,6 +2697,7 @@ static struct device_attribute *srp_host_attrs[] = { &dev_attr_zero_req_lim, &dev_attr_local_ib_port, &dev_attr_local_ib_device, + &dev_attr_ch_count, &dev_attr_comp_vector, &dev_attr_tl_retry_count, &dev_attr_cmd_sg_entries, @@ -3018,7 +3107,8 @@ static ssize_t srp_create_target(struct device *dev, struct srp_rdma_ch *ch; struct srp_device *srp_dev = host->srp_dev; struct ib_device *ibdev = srp_dev->dev; - int ret; + int ret, node_idx, node, cpu, i; + bool multich = false; target_host = scsi_host_alloc(&srp_template, sizeof (struct srp_target_port)); @@ -3088,34 +3178,82 @@ static ssize_t srp_create_target(struct device *dev, INIT_WORK(&target->tl_err_work, srp_tl_err_work); INIT_WORK(&target->remove_work, srp_remove_work); spin_lock_init(&target->lock); - ch = &target->ch; - ch->target = target; - ch->comp_vector = target->comp_vector; - spin_lock_init(&ch->lock); - INIT_LIST_HEAD(&ch->free_tx); - ret = srp_alloc_req_data(ch); - if (ret) - goto err_free_mem; - ret = ib_query_gid(ibdev, host->port, 0, &target->sgid); if (ret) - goto err_free_mem; + goto err; - ret = srp_create_ch_ib(ch); - if (ret) - goto err_free_mem; + ret = -ENOMEM; + target->ch_count = max_t(unsigned, num_online_nodes(), + min(ch_count ? : + min(4 * num_online_nodes(), + ibdev->num_comp_vectors), + num_online_cpus())); + target->ch = kcalloc(target->ch_count, sizeof(*target->ch), + GFP_KERNEL); + if (!target->ch) + goto err; - ret = srp_new_cm_id(ch); - if (ret) - goto err_free_ib; + node_idx = 0; + for_each_online_node(node) { + const int ch_start = (node_idx * target->ch_count / + num_online_nodes()); + const int ch_end = ((node_idx + 1) * target->ch_count / + num_online_nodes()); + const int cv_start = (node_idx * ibdev->num_comp_vectors / + num_online_nodes() + target->comp_vector) + % ibdev->num_comp_vectors; + const int cv_end = ((node_idx + 1) * ibdev->num_comp_vectors / + num_online_nodes() + target->comp_vector) + % ibdev->num_comp_vectors; + int cpu_idx = 0; + + for_each_online_cpu(cpu) { + if (cpu_to_node(cpu) != node) + continue; + if (ch_start + cpu_idx >= ch_end) + continue; + ch = &target->ch[ch_start + cpu_idx]; + ch->target = target; + ch->comp_vector = cv_start == cv_end ? cv_start : + cv_start + cpu_idx % (cv_end - cv_start); + spin_lock_init(&ch->lock); + INIT_LIST_HEAD(&ch->free_tx); + ret = srp_new_cm_id(ch); + if (ret) + goto err_disconnect; - ret = srp_connect_ch(ch); - if (ret) { - shost_printk(KERN_ERR, target->scsi_host, - PFX "Connection failed\n"); - goto err_free_ib; + ret = srp_create_ch_ib(ch); + if (ret) + goto err_disconnect; + + ret = srp_alloc_req_data(ch); + if (ret) + goto err_disconnect; + + ret = srp_connect_ch(ch, multich); + if (ret) { + shost_printk(KERN_ERR, target->scsi_host, + PFX "Connection %d/%d failed\n", + ch_start + cpu_idx, + target->ch_count); + if (node_idx == 0 && cpu_idx == 0) { + goto err_disconnect; + } else { + srp_free_ch_ib(target, ch); + srp_free_req_data(target, ch); + target->ch_count = ch - target->ch; + break; + } + } + + multich = true; + cpu_idx++; + } + node_idx++; } + target->scsi_host->nr_hw_queues = target->ch_count; + ret = srp_add_target(host, target); if (ret) goto err_disconnect; @@ -3142,11 +3280,13 @@ out: err_disconnect: srp_disconnect_target(target); -err_free_ib: - srp_free_ch_ib(target, ch); + for (i = 0; i < target->ch_count; i++) { + ch = &target->ch[i]; + srp_free_ch_ib(target, ch); + srp_free_req_data(target, ch); + } -err_free_mem: - srp_free_req_data(target, ch); + kfree(target->ch); err: scsi_host_put(target_host); diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h index 37aa9f49947a..ca7c6f065434 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.h +++ b/drivers/infiniband/ulp/srp/ib_srp.h @@ -179,8 +179,9 @@ struct srp_target_port { /* read and written in the hot path */ spinlock_t lock; - struct srp_rdma_ch ch; /* read only in the hot path */ + struct srp_rdma_ch *ch; + u32 ch_count; u32 lkey; u32 rkey; enum srp_target_state state; -- cgit v1.2.3-59-g8ed1b From 5de985de12d18ceca5d60cfd9d72a03cdfa94f4f Mon Sep 17 00:00:00 2001 From: Gabriel FERNANDEZ Date: Tue, 4 Nov 2014 11:51:17 +0100 Subject: phy: miphy28lp: Add Device Tree bindings for the MiPHY28lp The MiPHY28lp is a Generic PHY which can serve various SATA or PCIe or USB3 devices. Signed-off-by: alexandre torgue Signed-off-by: Giuseppe Cavallaro Signed-off-by: Gabriel Fernandez Signed-off-by: Kishon Vijay Abraham I --- .../devicetree/bindings/phy/phy-miphy28lp.txt | 126 +++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/phy-miphy28lp.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/phy/phy-miphy28lp.txt b/Documentation/devicetree/bindings/phy/phy-miphy28lp.txt new file mode 100644 index 000000000000..b7c13ad81a22 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/phy-miphy28lp.txt @@ -0,0 +1,126 @@ +STMicroelectronics STi MIPHY28LP PHY binding +============================================ + +This binding describes a miphy device that is used to control PHY hardware +for SATA, PCIe or USB3. + +Required properties (controller (parent) node): +- compatible : Should be "st,miphy28lp-phy". +- st,syscfg : Should be a phandle of the system configuration register group + which contain the SATA, PCIe or USB3 mode setting bits. + +Required nodes : A sub-node is required for each channel the controller + provides. Address range information including the usual + 'reg' and 'reg-names' properties are used inside these + nodes to describe the controller's topology. These nodes + are translated by the driver's .xlate() function. + +Required properties (port (child) node): +- #phy-cells : Should be 1 (See second example) + Cell after port phandle is device type from: + - PHY_TYPE_SATA + - PHY_TYPE_PCI + - PHY_TYPE_USB3 +- reg : Address and length of the register set for the device. +- reg-names : The names of the register addresses corresponding to the registers + filled in "reg". It can also contain the offset of the system configuration + registers used as glue-logic to setup the device for SATA/PCIe or USB3 + devices. +- resets : phandle to the parent reset controller. +- reset-names : Associated name must be "miphy-sw-rst". + +Optional properties (port (child) node): +- st,osc-rdy : to check the MIPHY0_OSC_RDY status in the glue-logic. This + is not available in all the MiPHY. For example, for STiH407, only the + MiPHY0 has this bit. +- st,osc-force-ext : to select the external oscillator. This can change from + different MiPHY inside the same SoC. +- st,sata_gen : to select which SATA_SPDMODE has to be set in the SATA system config + register. +- st,px_rx_pol_inv : to invert polarity of RXn/RXp (respectively negative line and positive + line). + +example: + + miphy28lp_phy: miphy28lp@9b22000 { + compatible = "st,miphy28lp-phy"; + st,syscfg = <&syscfg_core>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + phy_port0: port@9b22000 { + reg = <0x9b22000 0xff>, + <0x9b09000 0xff>, + <0x9b04000 0xff>, + <0x114 0x4>, /* sysctrl MiPHY cntrl */ + <0x818 0x4>, /* sysctrl MiPHY status*/ + <0xe0 0x4>, /* sysctrl PCIe */ + <0xec 0x4>; /* sysctrl SATA */ + reg-names = "sata-up", + "pcie-up", + "pipew", + "miphy-ctrl-glue", + "miphy-status-glue", + "pcie-glue", + "sata-glue"; + #phy-cells = <1>; + st,osc-rdy; + reset-names = "miphy-sw-rst"; + resets = <&softreset STIH407_MIPHY0_SOFTRESET>; + }; + + phy_port1: port@9b2a000 { + reg = <0x9b2a000 0xff>, + <0x9b19000 0xff>, + <0x9b14000 0xff>, + <0x118 0x4>, + <0x81c 0x4>, + <0xe4 0x4>, + <0xf0 0x4>; + reg-names = "sata-up", + "pcie-up", + "pipew", + "miphy-ctrl-glue", + "miphy-status-glue", + "pcie-glue", + "sata-glue"; + #phy-cells = <1>; + st,osc-force-ext; + reset-names = "miphy-sw-rst"; + resets = <&softreset STIH407_MIPHY1_SOFTRESET>; + }; + + phy_port2: port@8f95000 { + reg = <0x8f95000 0xff>, + <0x8f90000 0xff>, + <0x11c 0x4>, + <0x820 0x4>; + reg-names = "pipew", + "usb3-up", + "miphy-ctrl-glue", + "miphy-status-glue"; + #phy-cells = <1>; + reset-names = "miphy-sw-rst"; + resets = <&softreset STIH407_MIPHY2_SOFTRESET>; + }; + }; + + +Specifying phy control of devices +================================= + +Device nodes should specify the configuration required in their "phys" +property, containing a phandle to the miphy device node and an index +specifying which configuration to use, as described in phy-bindings.txt. + +example: + sata0: sata@9b20000 { + ... + phys = <&phy_port0 PHY_TYPE_SATA>; + ... + }; + +Macro definitions for the supported miphy configuration can be found in: + +include/dt-bindings/phy/phy-miphy28lp.h -- cgit v1.2.3-59-g8ed1b From 2b041b27a83fbe951d4b1cb1523001d4a8a5cccb Mon Sep 17 00:00:00 2001 From: Gabriel FERNANDEZ Date: Tue, 4 Nov 2014 11:51:21 +0100 Subject: phy: miphy28lp: Add SSC support for SATA This patch to tune on/off the ssc on miphy sata setup. User can now enable ssc via dt blob, it is useful to reduce effects of EMI. Signed-off-by: Giuseppe Condorelli Signed-off-by: Gabriel Fernandez Signed-off-by: Kishon Vijay Abraham I --- .../devicetree/bindings/phy/phy-miphy28lp.txt | 1 + drivers/phy/phy-miphy28lp.c | 46 ++++++++++++++++++++++ 2 files changed, 47 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/phy/phy-miphy28lp.txt b/Documentation/devicetree/bindings/phy/phy-miphy28lp.txt index b7c13ad81a22..4a3b4af3c1e6 100644 --- a/Documentation/devicetree/bindings/phy/phy-miphy28lp.txt +++ b/Documentation/devicetree/bindings/phy/phy-miphy28lp.txt @@ -39,6 +39,7 @@ Optional properties (port (child) node): register. - st,px_rx_pol_inv : to invert polarity of RXn/RXp (respectively negative line and positive line). +- st,scc-on : enable ssc to reduce effects of EMI (only for sata or PCIe). example: diff --git a/drivers/phy/phy-miphy28lp.c b/drivers/phy/phy-miphy28lp.c index 7d592e6392ac..d2f797c79fbc 100644 --- a/drivers/phy/phy-miphy28lp.c +++ b/drivers/phy/phy-miphy28lp.c @@ -191,6 +191,8 @@ #define SYSCFG_PCIE_PCIE_VAL 0x80 #define SATA_SPDMODE 1 +#define MIPHY_SATA_BANK_NB 3 + struct miphy28lp_phy { struct phy *phy; struct miphy28lp_dev *phydev; @@ -200,6 +202,7 @@ struct miphy28lp_phy { bool osc_force_ext; bool osc_rdy; bool px_rx_pol_inv; + bool ssc; struct reset_control *miphy_rst; @@ -550,6 +553,44 @@ static inline void miphy28_usb3_miphy_reset(struct miphy28lp_phy *miphy_phy) writeb_relaxed(0x00, base + MIPHY_CONF); } +static void miphy_sata_tune_ssc(struct miphy28lp_phy *miphy_phy) +{ + void __iomem *base = miphy_phy->base; + u8 val; + + /* Compensate Tx impedance to avoid out of range values */ + /* + * Enable the SSC on PLL for all banks + * SSC Modulation @ 31 KHz and 4000 ppm modulation amp + */ + val = readb_relaxed(base + MIPHY_BOUNDARY_2); + val |= SSC_EN_SW; + writeb_relaxed(val, base + MIPHY_BOUNDARY_2); + + val = readb_relaxed(base + MIPHY_BOUNDARY_SEL); + val |= SSC_SEL; + writeb_relaxed(val, base + MIPHY_BOUNDARY_SEL); + + for (val = 0; val < MIPHY_SATA_BANK_NB; val++) { + writeb_relaxed(val, base + MIPHY_CONF); + + /* Add value to each reference clock cycle */ + /* and define the period length of the SSC */ + writeb_relaxed(0x3c, base + MIPHY_PLL_SBR_2); + writeb_relaxed(0x6c, base + MIPHY_PLL_SBR_3); + writeb_relaxed(0x81, base + MIPHY_PLL_SBR_4); + + /* Clear any previous request */ + writeb_relaxed(0x00, base + MIPHY_PLL_SBR_1); + + /* requests the PLL to take in account new parameters */ + writeb_relaxed(SET_NEW_CHANGE, base + MIPHY_PLL_SBR_1); + + /* To be sure there is no other pending requests */ + writeb_relaxed(0x00, base + MIPHY_PLL_SBR_1); + } +} + static inline int miphy28lp_configure_sata(struct miphy28lp_phy *miphy_phy) { void __iomem *base = miphy_phy->base; @@ -585,6 +626,9 @@ static inline int miphy28lp_configure_sata(struct miphy28lp_phy *miphy_phy) writeb_relaxed(val, miphy_phy->base + MIPHY_CONTROL); } + if (miphy_phy->ssc) + miphy_sata_tune_ssc(miphy_phy); + return 0; } @@ -1064,6 +1108,8 @@ static int miphy28lp_of_probe(struct device_node *np, miphy_phy->px_rx_pol_inv = of_property_read_bool(np, "st,px_rx_pol_inv"); + miphy_phy->ssc = of_property_read_bool(np, "st,ssc-on"); + of_property_read_u32(np, "st,sata-gen", &miphy_phy->sata_gen); if (!miphy_phy->sata_gen) miphy_phy->sata_gen = SATA_GEN1; -- cgit v1.2.3-59-g8ed1b From 28ba384dc5e42a23328dca7e5e72d19e2dd4c9ce Mon Sep 17 00:00:00 2001 From: Gabriel FERNANDEZ Date: Tue, 4 Nov 2014 11:51:23 +0100 Subject: phy: miphy28lp: Tune tx impedance across Soc cuts This patch to compensate tx impedance (Sata, PCIe) depending on Soc cuts the kernel is built for. Signed-off-by: Giuseppe Condorelli Signed-off-by: Gabriel Fernandez Signed-off-by: Kishon Vijay Abraham I --- Documentation/devicetree/bindings/phy/phy-miphy28lp.txt | 1 + drivers/phy/phy-miphy28lp.c | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/phy/phy-miphy28lp.txt b/Documentation/devicetree/bindings/phy/phy-miphy28lp.txt index 4a3b4af3c1e6..46a135dae6b3 100644 --- a/Documentation/devicetree/bindings/phy/phy-miphy28lp.txt +++ b/Documentation/devicetree/bindings/phy/phy-miphy28lp.txt @@ -40,6 +40,7 @@ Optional properties (port (child) node): - st,px_rx_pol_inv : to invert polarity of RXn/RXp (respectively negative line and positive line). - st,scc-on : enable ssc to reduce effects of EMI (only for sata or PCIe). +- st,tx-impedance-comp : to compensate tx impedance avoiding out of range values. example: diff --git a/drivers/phy/phy-miphy28lp.c b/drivers/phy/phy-miphy28lp.c index d8ff8956ed05..87dcc9ab7f23 100644 --- a/drivers/phy/phy-miphy28lp.c +++ b/drivers/phy/phy-miphy28lp.c @@ -204,6 +204,7 @@ struct miphy28lp_phy { bool osc_rdy; bool px_rx_pol_inv; bool ssc; + bool tx_impedance; struct reset_control *miphy_rst; @@ -632,6 +633,12 @@ static void miphy_pcie_tune_ssc(struct miphy28lp_phy *miphy_phy) } } +static inline void miphy_tune_tx_impedance(struct miphy28lp_phy *miphy_phy) +{ + /* Compensate Tx impedance to avoid out of range values */ + writeb_relaxed(0x02, miphy_phy->base + MIPHY_COMP_POSTP); +} + static inline int miphy28lp_configure_sata(struct miphy28lp_phy *miphy_phy) { void __iomem *base = miphy_phy->base; @@ -670,6 +677,9 @@ static inline int miphy28lp_configure_sata(struct miphy28lp_phy *miphy_phy) if (miphy_phy->ssc) miphy_sata_tune_ssc(miphy_phy); + if (miphy_phy->tx_impedance) + miphy_tune_tx_impedance(miphy_phy); + return 0; } @@ -703,6 +713,9 @@ static inline int miphy28lp_configure_pcie(struct miphy28lp_phy *miphy_phy) if (miphy_phy->ssc) miphy_pcie_tune_ssc(miphy_phy); + if (miphy_phy->tx_impedance) + miphy_tune_tx_impedance(miphy_phy); + return 0; } @@ -1154,6 +1167,9 @@ static int miphy28lp_of_probe(struct device_node *np, miphy_phy->ssc = of_property_read_bool(np, "st,ssc-on"); + miphy_phy->tx_impedance = + of_property_read_bool(np, "st,tx-impedance-comp"); + of_property_read_u32(np, "st,sata-gen", &miphy_phy->sata_gen); if (!miphy_phy->sata_gen) miphy_phy->sata_gen = SATA_GEN1; -- cgit v1.2.3-59-g8ed1b From bfadcadf03a63bc841f69ed1c47e930b2ba2273d Mon Sep 17 00:00:00 2001 From: Ulrich Hecht Date: Fri, 7 Nov 2014 16:51:08 +0100 Subject: clk: shmobile: document DIV6 clock parent bindings Describes how to specify the parents for clocks with EXSRC bits. Signed-off-by: Ulrich Hecht Signed-off-by: Geert Uytterhoeven --- .../bindings/clock/renesas,cpg-div6-clocks.txt | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/renesas,cpg-div6-clocks.txt b/Documentation/devicetree/bindings/clock/renesas,cpg-div6-clocks.txt index 952e373178d2..054f65f9319c 100644 --- a/Documentation/devicetree/bindings/clock/renesas,cpg-div6-clocks.txt +++ b/Documentation/devicetree/bindings/clock/renesas,cpg-div6-clocks.txt @@ -7,11 +7,16 @@ to 64. Required Properties: - compatible: Must be one of the following + - "renesas,r8a73a4-div6-clock" for R8A73A4 (R-Mobile APE6) DIV6 clocks + - "renesas,r8a7740-div6-clock" for R8A7740 (R-Mobile A1) DIV6 clocks - "renesas,r8a7790-div6-clock" for R8A7790 (R-Car H2) DIV6 clocks - "renesas,r8a7791-div6-clock" for R8A7791 (R-Car M2) DIV6 clocks + - "renesas,sh73a0-div6-clock" for SH73A0 (SH-Mobile AG5) DIV6 clocks - "renesas,cpg-div6-clock" for generic DIV6 clocks - reg: Base address and length of the memory resource used by the DIV6 clock - - clocks: Reference to the parent clock + - clocks: Reference to the parent clock(s); either one, four, or eight + clocks must be specified. For clocks with multiple parents, invalid + settings must be specified as "<0>". - #clock-cells: Must be 0 - clock-output-names: The name of the clock as a free-form string @@ -19,10 +24,11 @@ Required Properties: Example ------- - sd2_clk: sd2_clk@e6150078 { - compatible = "renesas,r8a7790-div6-clock", "renesas,cpg-div6-clock"; - reg = <0 0xe6150078 0 4>; - clocks = <&pll1_div2_clk>; + sdhi2_clk: sdhi2_clk@e615007c { + compatible = "renesas,r8a73a4-div6-clock", "renesas,cpg-div6-clock"; + reg = <0 0xe615007c 0 4>; + clocks = <&pll1_div2_clk>, <&cpg_clocks R8A73A4_CLK_PLL2S>, + <0>, <&extal2_clk>; #clock-cells = <0>; - clock-output-names = "sd2"; + clock-output-names = "sdhi2ck"; }; -- cgit v1.2.3-59-g8ed1b From a7a3324a602cd7ebabfb7f5990006ec4f3d6449f Mon Sep 17 00:00:00 2001 From: Misael Lopez Cruz Date: Wed, 12 Nov 2014 16:38:05 +0200 Subject: ASoC: davinci-mcasp: Add overrun/underrun event handling An underrun (playback) event occurs when the serializer transfer data from the XRBUF buffer to the XRSR shift register, but the XRBUF hasn't been filled. Similarly, the overrun (capture) event occurs when data from the XRSR shift register is transferred to the XRBUF but it hasn't been read yet. These events are handled as XRUN events that cause the pcm to stop. The stream has to be explicitly restarted by the userspace which ensures that after stopping/starting McASP the data transfer is aligned with DMA. The other possibility was to internally stop and start McASP without DMA even knowing about it. Signed-off-by: Misael Lopez Cruz Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- .../bindings/sound/davinci-mcasp-audio.txt | 2 +- sound/soc/davinci/davinci-mcasp.c | 124 +++++++++++++++++++++ sound/soc/davinci/davinci-mcasp.h | 11 ++ 3 files changed, 136 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt index 60ca07996458..46bc9829c71a 100644 --- a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt +++ b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt @@ -32,7 +32,7 @@ Optional properties: - rx-num-evt : FIFO levels. - sram-size-playback : size of sram to be allocated during playback - sram-size-capture : size of sram to be allocated during capture -- interrupts : Interrupt numbers for McASP, currently not used by the driver +- interrupts : Interrupt numbers for McASP - interrupt-names : Known interrupt names are "tx" and "rx" - pinctrl-0: Should specify pin control group used for this controller. - pinctrl-names: Should contain only one value - "default", for more details diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index a9822c7bbb0b..e460f97c514e 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -70,6 +70,7 @@ struct davinci_mcasp { void __iomem *base; u32 fifo_base; struct device *dev; + struct snd_pcm_substream *substreams[2]; /* McASP specific data */ int tdm_slots; @@ -80,6 +81,7 @@ struct davinci_mcasp { u8 bclk_div; u16 bclk_lrclk_ratio; int streams; + u32 irq_request[2]; int sysclk_freq; bool bclk_master; @@ -185,6 +187,10 @@ static void mcasp_start_rx(struct davinci_mcasp *mcasp) mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXFSRST); if (mcasp_is_synchronous(mcasp)) mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST); + + /* enable receive IRQs */ + mcasp_set_bits(mcasp, DAVINCI_MCASP_EVTCTLR_REG, + mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE]); } static void mcasp_start_tx(struct davinci_mcasp *mcasp) @@ -214,6 +220,10 @@ static void mcasp_start_tx(struct davinci_mcasp *mcasp) mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSMRST); /* Release Frame Sync generator */ mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST); + + /* enable transmit IRQs */ + mcasp_set_bits(mcasp, DAVINCI_MCASP_EVTCTLX_REG, + mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK]); } static void davinci_mcasp_start(struct davinci_mcasp *mcasp, int stream) @@ -228,6 +238,10 @@ static void davinci_mcasp_start(struct davinci_mcasp *mcasp, int stream) static void mcasp_stop_rx(struct davinci_mcasp *mcasp) { + /* disable IRQ sources */ + mcasp_clr_bits(mcasp, DAVINCI_MCASP_EVTCTLR_REG, + mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE]); + /* * In synchronous mode stop the TX clocks if no other stream is * running @@ -249,6 +263,10 @@ static void mcasp_stop_tx(struct davinci_mcasp *mcasp) { u32 val = 0; + /* disable IRQ sources */ + mcasp_clr_bits(mcasp, DAVINCI_MCASP_EVTCTLX_REG, + mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK]); + /* * In synchronous mode keep TX clocks running if the capture stream is * still running. @@ -276,6 +294,76 @@ static void davinci_mcasp_stop(struct davinci_mcasp *mcasp, int stream) mcasp_stop_rx(mcasp); } +static irqreturn_t davinci_mcasp_tx_irq_handler(int irq, void *data) +{ + struct davinci_mcasp *mcasp = (struct davinci_mcasp *)data; + struct snd_pcm_substream *substream; + u32 irq_mask = mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK]; + u32 handled_mask = 0; + u32 stat; + + stat = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG); + if (stat & XUNDRN & irq_mask) { + dev_warn(mcasp->dev, "Transmit buffer underflow\n"); + handled_mask |= XUNDRN; + + substream = mcasp->substreams[SNDRV_PCM_STREAM_PLAYBACK]; + if (substream) { + snd_pcm_stream_lock_irq(substream); + if (snd_pcm_running(substream)) + snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); + snd_pcm_stream_unlock_irq(substream); + } + } + + if (!handled_mask) + dev_warn(mcasp->dev, "unhandled tx event. txstat: 0x%08x\n", + stat); + + if (stat & XRERR) + handled_mask |= XRERR; + + /* Ack the handled event only */ + mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, handled_mask); + + return IRQ_RETVAL(handled_mask); +} + +static irqreturn_t davinci_mcasp_rx_irq_handler(int irq, void *data) +{ + struct davinci_mcasp *mcasp = (struct davinci_mcasp *)data; + struct snd_pcm_substream *substream; + u32 irq_mask = mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE]; + u32 handled_mask = 0; + u32 stat; + + stat = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG); + if (stat & ROVRN & irq_mask) { + dev_warn(mcasp->dev, "Receive buffer overflow\n"); + handled_mask |= ROVRN; + + substream = mcasp->substreams[SNDRV_PCM_STREAM_CAPTURE]; + if (substream) { + snd_pcm_stream_lock_irq(substream); + if (snd_pcm_running(substream)) + snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); + snd_pcm_stream_unlock_irq(substream); + } + } + + if (!handled_mask) + dev_warn(mcasp->dev, "unhandled rx event. rxstat: 0x%08x\n", + stat); + + if (stat & XRERR) + handled_mask |= XRERR; + + /* Ack the handled event only */ + mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, handled_mask); + + return IRQ_RETVAL(handled_mask); +} + static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) { @@ -869,6 +957,8 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream, u32 max_channels = 0; int i, dir; + mcasp->substreams[substream->stream] = substream; + if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) return 0; @@ -907,6 +997,8 @@ static void davinci_mcasp_shutdown(struct snd_pcm_substream *substream, { struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); + mcasp->substreams[substream->stream] = NULL; + if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) return; @@ -1256,6 +1348,8 @@ static int davinci_mcasp_probe(struct platform_device *pdev) struct resource *mem, *ioarea, *res, *dat; struct davinci_mcasp_pdata *pdata; struct davinci_mcasp *mcasp; + char *irq_name; + int irq; int ret; if (!pdev->dev.platform_data && !pdev->dev.of_node) { @@ -1336,6 +1430,36 @@ static int davinci_mcasp_probe(struct platform_device *pdev) mcasp->dev = &pdev->dev; + irq = platform_get_irq_byname(pdev, "rx"); + if (irq >= 0) { + irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_rx\n", + dev_name(&pdev->dev)); + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, + davinci_mcasp_rx_irq_handler, + IRQF_ONESHOT, irq_name, mcasp); + if (ret) { + dev_err(&pdev->dev, "RX IRQ request failed\n"); + goto err; + } + + mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE] = ROVRN; + } + + irq = platform_get_irq_byname(pdev, "tx"); + if (irq >= 0) { + irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_tx\n", + dev_name(&pdev->dev)); + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, + davinci_mcasp_tx_irq_handler, + IRQF_ONESHOT, irq_name, mcasp); + if (ret) { + dev_err(&pdev->dev, "TX IRQ request failed\n"); + goto err; + } + + mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK] = XUNDRN; + } + dat = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat"); if (dat) mcasp->dat_port = true; diff --git a/sound/soc/davinci/davinci-mcasp.h b/sound/soc/davinci/davinci-mcasp.h index 9737108f0305..79dc511180bf 100644 --- a/sound/soc/davinci/davinci-mcasp.h +++ b/sound/soc/davinci/davinci-mcasp.h @@ -256,6 +256,7 @@ * DAVINCI_MCASP_TXSTAT_REG - Transmitter Status Register Bits * DAVINCI_MCASP_RXSTAT_REG - Receiver Status Register Bits */ +#define XRERR BIT(8) /* Transmit/Receive error */ #define XRDATA BIT(5) /* Transmit/Receive data ready */ /* @@ -284,6 +285,16 @@ */ #define TXDATADMADIS BIT(0) +/* + * DAVINCI_MCASP_EVTCTLR_REG - Receiver Interrupt Control Register Bits + */ +#define ROVRN BIT(0) + +/* + * DAVINCI_MCASP_EVTCTLX_REG - Transmitter Interrupt Control Register Bits + */ +#define XUNDRN BIT(0) + /* * DAVINCI_MCASP_W[R]FIFOCTL - Write/Read FIFO Control Register bits */ -- cgit v1.2.3-59-g8ed1b From 2d09581b4cc95c82b5fcc654e78b2d6de7350527 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 7 Nov 2014 11:11:41 +0100 Subject: i2c: sh_mobile: add DMA support Make it possible to transfer i2c message buffers via DMA. Start/Stop/Sending_Slave_Address is still handled using the old state machine, it is sending the actual data that is done via DMA. This is least intrusive and allows us to work with the message buffers directly instead of preparing a custom buffer which involves copying the data around. Signed-off-by: Wolfram Sang [wsa: fixed an uninitialized var problem] Signed-off-by: Wolfram Sang --- .../devicetree/bindings/i2c/i2c-sh_mobile.txt | 5 + drivers/i2c/busses/i2c-sh_mobile.c | 195 +++++++++++++++++++-- 2 files changed, 190 insertions(+), 10 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/i2c/i2c-sh_mobile.txt b/Documentation/devicetree/bindings/i2c/i2c-sh_mobile.txt index c33e9a32d496..2bfc6e7ed094 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-sh_mobile.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-sh_mobile.txt @@ -19,6 +19,11 @@ Required properties: Optional properties: - clock-frequency : frequency of bus clock in Hz. Default 100kHz if unset. +- dmas : Must contain a list of two references to DMA + specifiers, one for transmission, and one for + reception. +- dma-names : Must contain a list of two DMA names, "tx" and "rx". + Pinctrl properties might be needed, too. See there. diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index de609be67793..d9a5622b89c8 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -1,6 +1,8 @@ /* * SuperH Mobile I2C Controller * + * Copyright (C) 2014 Wolfram Sang + * * Copyright (C) 2008 Magnus Damm * * Portions of the code based on out-of-tree driver i2c-sh7343.c @@ -18,6 +20,8 @@ #include #include +#include +#include #include #include #include @@ -110,6 +114,7 @@ enum sh_mobile_i2c_op { OP_TX_FIRST, OP_TX, OP_TX_STOP, + OP_TX_STOP_DATA, OP_TX_TO_RX, OP_RX, OP_RX_STOP, @@ -134,6 +139,11 @@ struct sh_mobile_i2c_data { int pos; int sr; bool send_stop; + + struct dma_chan *dma_tx; + struct dma_chan *dma_rx; + struct scatterlist sg; + enum dma_data_direction dma_direction; }; struct sh_mobile_dt_config { @@ -171,6 +181,8 @@ struct sh_mobile_dt_config { #define ICIC_ICCLB8 0x80 #define ICIC_ICCHB8 0x40 +#define ICIC_TDMAE 0x20 +#define ICIC_RDMAE 0x10 #define ICIC_ALE 0x08 #define ICIC_TACKE 0x04 #define ICIC_WAITE 0x02 @@ -332,8 +344,10 @@ static unsigned char i2c_op(struct sh_mobile_i2c_data *pd, case OP_TX: /* write data */ iic_wr(pd, ICDR, data); break; - case OP_TX_STOP: /* write data and issue a stop afterwards */ + case OP_TX_STOP_DATA: /* write data and issue a stop afterwards */ iic_wr(pd, ICDR, data); + /* fallthrough */ + case OP_TX_STOP: /* issue a stop */ iic_wr(pd, ICCR, pd->send_stop ? ICCR_ICE | ICCR_TRS : ICCR_ICE | ICCR_TRS | ICCR_BBSY); break; @@ -389,13 +403,17 @@ static int sh_mobile_i2c_isr_tx(struct sh_mobile_i2c_data *pd) { unsigned char data; - if (pd->pos == pd->msg->len) + if (pd->pos == pd->msg->len) { + /* Send stop if we haven't yet (DMA case) */ + if (pd->send_stop && (iic_rd(pd, ICCR) & ICCR_BBSY)) + i2c_op(pd, OP_TX_STOP, 0); return 1; + } sh_mobile_i2c_get_data(pd, &data); if (sh_mobile_i2c_is_last_byte(pd)) - i2c_op(pd, OP_TX_STOP, data); + i2c_op(pd, OP_TX_STOP_DATA, data); else if (sh_mobile_i2c_is_first_byte(pd)) i2c_op(pd, OP_TX_FIRST, data); else @@ -450,7 +468,7 @@ static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id) struct platform_device *dev = dev_id; struct sh_mobile_i2c_data *pd = platform_get_drvdata(dev); unsigned char sr; - int wakeup; + int wakeup = 0; sr = iic_rd(pd, ICSR); pd->sr |= sr; /* remember state */ @@ -459,15 +477,21 @@ static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id) (pd->msg->flags & I2C_M_RD) ? "read" : "write", pd->pos, pd->msg->len); - if (sr & (ICSR_AL | ICSR_TACK)) { + /* Kick off TxDMA after preface was done */ + if (pd->dma_direction == DMA_TO_DEVICE && pd->pos == 0) + iic_set_clr(pd, ICIC, ICIC_TDMAE, 0); + else if (sr & (ICSR_AL | ICSR_TACK)) /* don't interrupt transaction - continue to issue stop */ iic_wr(pd, ICSR, sr & ~(ICSR_AL | ICSR_TACK)); - wakeup = 0; - } else if (pd->msg->flags & I2C_M_RD) + else if (pd->msg->flags & I2C_M_RD) wakeup = sh_mobile_i2c_isr_rx(pd); else wakeup = sh_mobile_i2c_isr_tx(pd); + /* Kick off RxDMA after preface was done */ + if (pd->dma_direction == DMA_FROM_DEVICE && pd->pos == 1) + iic_set_clr(pd, ICIC, ICIC_RDMAE, 0); + if (sr & ICSR_WAIT) /* TODO: add delay here to support slow acks */ iic_wr(pd, ICSR, sr & ~ICSR_WAIT); @@ -482,6 +506,79 @@ static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id) return IRQ_HANDLED; } +static void sh_mobile_i2c_cleanup_dma(struct sh_mobile_i2c_data *pd) +{ + if (pd->dma_direction == DMA_NONE) + return; + else if (pd->dma_direction == DMA_FROM_DEVICE) + dmaengine_terminate_all(pd->dma_rx); + else if (pd->dma_direction == DMA_TO_DEVICE) + dmaengine_terminate_all(pd->dma_tx); + + dma_unmap_single(pd->dev, sg_dma_address(&pd->sg), + pd->msg->len, pd->dma_direction); + + pd->dma_direction = DMA_NONE; +} + +static void sh_mobile_i2c_dma_callback(void *data) +{ + struct sh_mobile_i2c_data *pd = data; + + dma_unmap_single(pd->dev, sg_dma_address(&pd->sg), + pd->msg->len, pd->dma_direction); + + pd->dma_direction = DMA_NONE; + pd->pos = pd->msg->len; + + iic_set_clr(pd, ICIC, 0, ICIC_TDMAE | ICIC_RDMAE); +} + +static void sh_mobile_i2c_xfer_dma(struct sh_mobile_i2c_data *pd) +{ + bool read = pd->msg->flags & I2C_M_RD; + enum dma_data_direction dir = read ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + struct dma_chan *chan = read ? pd->dma_rx : pd->dma_tx; + struct dma_async_tx_descriptor *txdesc; + dma_addr_t dma_addr; + dma_cookie_t cookie; + + if (!chan) + return; + + dma_addr = dma_map_single(pd->dev, pd->msg->buf, pd->msg->len, dir); + if (dma_mapping_error(pd->dev, dma_addr)) { + dev_dbg(pd->dev, "dma map failed, using PIO\n"); + return; + } + + sg_dma_len(&pd->sg) = pd->msg->len; + sg_dma_address(&pd->sg) = dma_addr; + + pd->dma_direction = dir; + + txdesc = dmaengine_prep_slave_sg(chan, &pd->sg, 1, + read ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!txdesc) { + dev_dbg(pd->dev, "dma prep slave sg failed, using PIO\n"); + sh_mobile_i2c_cleanup_dma(pd); + return; + } + + txdesc->callback = sh_mobile_i2c_dma_callback; + txdesc->callback_param = pd; + + cookie = dmaengine_submit(txdesc); + if (dma_submit_error(cookie)) { + dev_dbg(pd->dev, "submitting dma failed, using PIO\n"); + sh_mobile_i2c_cleanup_dma(pd); + return; + } + + dma_async_issue_pending(chan); +} + static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg, bool do_init) { @@ -506,6 +603,9 @@ static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg, pd->pos = -1; pd->sr = 0; + if (pd->msg->len > 8) + sh_mobile_i2c_xfer_dma(pd); + /* Enable all interrupts to begin with */ iic_wr(pd, ICIC, ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE); return 0; @@ -589,6 +689,9 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter, 5 * HZ); if (!k) { dev_err(pd->dev, "Transfer request timed out\n"); + if (pd->dma_direction != DMA_NONE) + sh_mobile_i2c_cleanup_dma(pd); + err = -ETIMEDOUT; break; } @@ -639,6 +742,62 @@ static const struct of_device_id sh_mobile_i2c_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, sh_mobile_i2c_dt_ids); +static int sh_mobile_i2c_request_dma_chan(struct device *dev, enum dma_transfer_direction dir, + dma_addr_t port_addr, struct dma_chan **chan_ptr) +{ + dma_cap_mask_t mask; + struct dma_chan *chan; + struct dma_slave_config cfg; + char *chan_name = dir == DMA_MEM_TO_DEV ? "tx" : "rx"; + int ret; + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + *chan_ptr = NULL; + + chan = dma_request_slave_channel_reason(dev, chan_name); + if (IS_ERR(chan)) { + ret = PTR_ERR(chan); + dev_dbg(dev, "request_channel failed for %s (%d)\n", chan_name, ret); + return ret; + } + + memset(&cfg, 0, sizeof(cfg)); + cfg.direction = dir; + if (dir == DMA_MEM_TO_DEV) { + cfg.dst_addr = port_addr; + cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + } else { + cfg.src_addr = port_addr; + cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + } + + ret = dmaengine_slave_config(chan, &cfg); + if (ret) { + dev_dbg(dev, "slave_config failed for %s (%d)\n", chan_name, ret); + dma_release_channel(chan); + return ret; + } + + *chan_ptr = chan; + + dev_dbg(dev, "got DMA channel for %s\n", chan_name); + return 0; +} + +static void sh_mobile_i2c_release_dma(struct sh_mobile_i2c_data *pd) +{ + if (pd->dma_tx) { + dma_release_channel(pd->dma_tx); + pd->dma_tx = NULL; + } + + if (pd->dma_rx) { + dma_release_channel(pd->dma_rx); + pd->dma_rx = NULL; + } +} + static int sh_mobile_i2c_hook_irqs(struct platform_device *dev) { struct resource *res; @@ -725,6 +884,21 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) if (ret) return ret; + /* Init DMA */ + sg_init_table(&pd->sg, 1); + pd->dma_direction = DMA_NONE; + ret = sh_mobile_i2c_request_dma_chan(pd->dev, DMA_DEV_TO_MEM, + res->start + ICDR, &pd->dma_rx); + if (ret == -EPROBE_DEFER) + return ret; + + ret = sh_mobile_i2c_request_dma_chan(pd->dev, DMA_MEM_TO_DEV, + res->start + ICDR, &pd->dma_tx); + if (ret == -EPROBE_DEFER) { + sh_mobile_i2c_release_dma(pd); + return ret; + } + /* Enable Runtime PM for this device. * * Also tell the Runtime PM core to ignore children @@ -756,6 +930,7 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) ret = i2c_add_numbered_adapter(adap); if (ret < 0) { + sh_mobile_i2c_release_dma(pd); dev_err(&dev->dev, "cannot add numbered adapter\n"); return ret; } @@ -772,6 +947,7 @@ static int sh_mobile_i2c_remove(struct platform_device *dev) struct sh_mobile_i2c_data *pd = platform_get_drvdata(dev); i2c_del_adapter(&pd->adap); + sh_mobile_i2c_release_dma(pd); pm_runtime_disable(&dev->dev); return 0; } @@ -808,16 +984,15 @@ static int __init sh_mobile_i2c_adap_init(void) { return platform_driver_register(&sh_mobile_i2c_driver); } +subsys_initcall(sh_mobile_i2c_adap_init); static void __exit sh_mobile_i2c_adap_exit(void) { platform_driver_unregister(&sh_mobile_i2c_driver); } - -subsys_initcall(sh_mobile_i2c_adap_init); module_exit(sh_mobile_i2c_adap_exit); MODULE_DESCRIPTION("SuperH Mobile I2C Bus Controller driver"); -MODULE_AUTHOR("Magnus Damm"); +MODULE_AUTHOR("Magnus Damm and Wolfram Sang"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:i2c-sh_mobile"); -- cgit v1.2.3-59-g8ed1b From 3eee1799aed90e990e02a73a89bfcff1982c74dd Mon Sep 17 00:00:00 2001 From: Devin Ryles Date: Wed, 5 Nov 2014 16:30:03 -0500 Subject: i2c: i801: Add DeviceIDs for SunrisePoint LP Signed-off-by: Devin Ryles Reviewed-by: Jean Delvare Signed-off-by: Wolfram Sang --- Documentation/i2c/busses/i2c-i801 | 1 + drivers/i2c/busses/Kconfig | 1 + drivers/i2c/busses/i2c-i801.c | 3 +++ 3 files changed, 5 insertions(+) (limited to 'Documentation') diff --git a/Documentation/i2c/busses/i2c-i801 b/Documentation/i2c/busses/i2c-i801 index 793c83dac738..82f48f774afb 100644 --- a/Documentation/i2c/busses/i2c-i801 +++ b/Documentation/i2c/busses/i2c-i801 @@ -29,6 +29,7 @@ Supported adapters: * Intel Wildcat Point-LP (PCH) * Intel BayTrail (SOC) * Intel Sunrise Point-H (PCH) + * Intel Sunrise Point-LP (PCH) Datasheets: Publicly available at the Intel website On Intel Patsburg and later chipsets, both the normal host SMBus controller diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 917c3585f45b..06e99eb64295 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -123,6 +123,7 @@ config I2C_I801 Wildcat Point-LP (PCH) BayTrail (SOC) Sunrise Point-H (PCH) + Sunrise Point-LP (PCH) This driver can also be built as a module. If so, the module will be called i2c-i801. diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 48b925a0ae7c..8fafb254e42a 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -59,6 +59,7 @@ * Wildcat Point-LP (PCH) 0x9ca2 32 hard yes yes yes * BayTrail (SOC) 0x0f12 32 hard yes yes yes * Sunrise Point-H (PCH) 0xa123 32 hard yes yes yes + * Sunrise Point-LP (PCH) 0x9d23 32 hard yes yes yes * * Features supported by this driver: * Software PEC no @@ -186,6 +187,7 @@ #define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS 0x9c22 #define PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_SMBUS 0x9ca2 #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS 0xa123 +#define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS 0x9d23 struct i801_mux_config { char *gpio_chip; @@ -846,6 +848,7 @@ static const struct pci_device_id i801_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BRASWELL_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS) }, { 0, } }; -- cgit v1.2.3-59-g8ed1b From c88c7d3204e66faf1f24402d551ac1d0b400e3ff Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 11 Nov 2014 20:00:07 +0100 Subject: dt/bindings: fix documentation of ethernet-phy compatible property A recent commit extended the documentation of the ethernet-phy compatible property, but placed the new paragraph under the max-speed property. Fixes: f00e756ed12d ("dt: Document a compatible entry for MDIO ethernet Phys") Cc: devicetree@vger.kernel.org Signed-off-by: Johan Hovold Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/phy.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/phy.txt b/Documentation/devicetree/bindings/net/phy.txt index 5b8c58903077..40831fbaff72 100644 --- a/Documentation/devicetree/bindings/net/phy.txt +++ b/Documentation/devicetree/bindings/net/phy.txt @@ -19,7 +19,6 @@ Optional Properties: specifications. If neither of these are specified, the default is to assume clause 22. The compatible list may also contain other elements. -- max-speed: Maximum PHY supported speed (10, 100, 1000...) If the phy's identifier is known then the list may contain an entry of the form: "ethernet-phy-idAAAA.BBBB" where @@ -29,6 +28,8 @@ Optional Properties: 4 hex digits. This is the chip vendor OUI bits 19:24, followed by 10 bits of a vendor specific ID. +- max-speed: Maximum PHY supported speed (10, 100, 1000...) + Example: ethernet-phy@0 { -- cgit v1.2.3-59-g8ed1b From 7b52314cc44569f56aa07abdbe43e6ccfcef9478 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 11 Nov 2014 20:00:15 +0100 Subject: net: phy: micrel: enable led-mode for KSZ8081/KSZ8091 Enable led-mode configuration for KSZ8081 and KSZ8091. Signed-off-by: Johan Hovold Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/micrel.txt | 2 ++ drivers/net/phy/micrel.c | 1 + 2 files changed, 3 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/micrel.txt b/Documentation/devicetree/bindings/net/micrel.txt index e1d99b95c4ec..30062fae5623 100644 --- a/Documentation/devicetree/bindings/net/micrel.txt +++ b/Documentation/devicetree/bindings/net/micrel.txt @@ -14,6 +14,8 @@ Optional properties: KSZ8021: register 0x1f, bits 5..4 KSZ8031: register 0x1f, bits 5..4 KSZ8051: register 0x1f, bits 5..4 + KSZ8081: register 0x1f, bits 5..4 + KSZ8091: register 0x1f, bits 5..4 See the respective PHY datasheet for the mode values. diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 12e18f7273ce..30e894d6ffbd 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -265,6 +265,7 @@ static int ks8051_config_init(struct phy_device *phydev) static int ksz8081_config_init(struct phy_device *phydev) { kszphy_broadcast_disable(phydev); + kszphy_setup_led(phydev, MII_KSZPHY_CTRL_2); return 0; } -- cgit v1.2.3-59-g8ed1b From caaeb6a96f35af14f615838b924f54c9d0f33ab3 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 10 Nov 2014 20:00:40 +0100 Subject: ASoC: sh: fsi: Document SoC-specific bindings The documentation only mentioned the generic fallback compatible property. Add the missing SoC-specific compatible properties, some of which are already in use. Also fix a small typo, while we're at it. Signed-off-by: Geert Uytterhoeven Acked-by: Simon Horman Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/renesas,fsi.txt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/renesas,fsi.txt b/Documentation/devicetree/bindings/sound/renesas,fsi.txt index c5be003f413e..0d0ab51105b0 100644 --- a/Documentation/devicetree/bindings/sound/renesas,fsi.txt +++ b/Documentation/devicetree/bindings/sound/renesas,fsi.txt @@ -1,11 +1,16 @@ Renesas FSI Required properties: -- compatible : "renesas,sh_fsi2" or "renesas,sh_fsi" +- compatible : "renesas,fsi2-", + "renesas,sh_fsi2" or "renesas,sh_fsi" as + fallback. + Examples with soctypes are: + - "renesas,fsi2-r8a7740" (R-Mobile A1) + - "renesas,fsi2-sh73a0" (SH-Mobile AG5) - reg : Should contain the register physical address and length - interrupts : Should contain FSI interrupt -- fsia,spdif-connection : FSI is connected by S/PDFI +- fsia,spdif-connection : FSI is connected by S/PDIF - fsia,stream-mode-support : FSI supports 16bit stream mode. - fsia,use-internal-clock : FSI uses internal clock when master mode. -- cgit v1.2.3-59-g8ed1b From 56ba98acc398883324c0e70dc8aee1dc53eb2331 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 10 Nov 2014 20:00:42 +0100 Subject: ASoC: rsnd: Document SoC-specific bindings The documentation only mentioned the generic fallback compatible property. Add the missing SoC-specific compatible properties, which are already in use. Also drop a bogus 0x unit-address prefix while we're at it. Signed-off-by: Geert Uytterhoeven Acked-by: Simon Horman Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/renesas,rsnd.txt | 10 +++++++--- 1 file changed, 7 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 aa697abf337e..2dd690bc19cc 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt @@ -1,8 +1,12 @@ Renesas R-Car sound Required properties: -- compatible : "renesas,rcar_sound-gen1" if generation1 +- compatible : "renesas,rcar_sound-", fallbacks + "renesas,rcar_sound-gen1" if generation1, and "renesas,rcar_sound-gen2" if generation2 + Examples with soctypes are: + - "renesas,rcar_sound-r8a7790" (R-Car H2) + - "renesas,rcar_sound-r8a7791" (R-Car M2-W) - reg : Should contain the register physical address. required register is SRU/ADG/SSI if generation1 @@ -35,9 +39,9 @@ DAI subnode properties: Example: -rcar_sound: rcar_sound@0xffd90000 { +rcar_sound: rcar_sound@ec500000 { #sound-dai-cells = <1>; - compatible = "renesas,rcar_sound-gen2"; + compatible = "renesas,rcar_sound-r8a7791", "renesas,rcar_sound-gen2"; reg = <0 0xec500000 0 0x1000>, /* SCU */ <0 0xec5a0000 0 0x100>, /* ADG */ <0 0xec540000 0 0x1000>, /* SSIU */ -- cgit v1.2.3-59-g8ed1b From ab08aefcd12d4e21abb28264ca77a430dcce7ebd Mon Sep 17 00:00:00 2001 From: Chao Xie Date: Fri, 31 Oct 2014 10:13:49 +0800 Subject: clk: mmp: add pxa168 DT support for clock driver It adds the DT support for pxa168 clock subsystem. Signed-off-by: Chao Xie Acked-by: Haojian Zhuang Signed-off-by: Michael Turquette --- .../devicetree/bindings/clock/marvell,pxa168.txt | 21 ++ drivers/clk/mmp/Makefile | 2 + drivers/clk/mmp/clk-of-pxa168.c | 279 +++++++++++++++++++++ include/dt-bindings/clock/marvell,pxa168.h | 57 +++++ 4 files changed, 359 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/marvell,pxa168.txt create mode 100644 drivers/clk/mmp/clk-of-pxa168.c create mode 100644 include/dt-bindings/clock/marvell,pxa168.h (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/marvell,pxa168.txt b/Documentation/devicetree/bindings/clock/marvell,pxa168.txt new file mode 100644 index 000000000000..c62eb1d173a6 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/marvell,pxa168.txt @@ -0,0 +1,21 @@ +* Marvell PXA168 Clock Controller + +The PXA168 clock subsystem generates and supplies clock to various +controllers within the PXA168 SoC. + +Required Properties: + +- compatible: should be one of the following. + - "marvell,pxa168-clock" - controller compatible with PXA168 SoC. + +- reg: physical base address of the clock subsystem and length of memory mapped + region. There are 3 places in SOC has clock control logic: + "mpmu", "apmu", "apbc". So three reg spaces need to be defined. + +- #clock-cells: should be 1. +- #reset-cells: should be 1. + +Each clock is assigned an identifier and client nodes use this identifier +to specify the clock which they consume. + +All these identifier could be found in . diff --git a/drivers/clk/mmp/Makefile b/drivers/clk/mmp/Makefile index 2573d7c6198e..733acc7aa484 100644 --- a/drivers/clk/mmp/Makefile +++ b/drivers/clk/mmp/Makefile @@ -6,6 +6,8 @@ obj-y += clk-apbc.o clk-apmu.o clk-frac.o clk-mix.o clk-gate.o clk.o obj-$(CONFIG_RESET_CONTROLLER) += reset.o +obj-$(CONFIG_MACH_MMP_DT) += clk-of-pxa168.o + obj-$(CONFIG_CPU_PXA168) += clk-pxa168.o obj-$(CONFIG_CPU_PXA910) += clk-pxa910.o obj-$(CONFIG_CPU_MMP2) += clk-mmp2.o diff --git a/drivers/clk/mmp/clk-of-pxa168.c b/drivers/clk/mmp/clk-of-pxa168.c new file mode 100644 index 000000000000..5b1810dc4bd2 --- /dev/null +++ b/drivers/clk/mmp/clk-of-pxa168.c @@ -0,0 +1,279 @@ +/* + * pxa168 clock framework source file + * + * Copyright (C) 2012 Marvell + * Chao Xie + * + * 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 + +#include "clk.h" +#include "reset.h" + +#define APBC_RTC 0x28 +#define APBC_TWSI0 0x2c +#define APBC_KPC 0x30 +#define APBC_UART0 0x0 +#define APBC_UART1 0x4 +#define APBC_GPIO 0x8 +#define APBC_PWM0 0xc +#define APBC_PWM1 0x10 +#define APBC_PWM2 0x14 +#define APBC_PWM3 0x18 +#define APBC_SSP0 0x81c +#define APBC_SSP1 0x820 +#define APBC_SSP2 0x84c +#define APBC_SSP3 0x858 +#define APBC_SSP4 0x85c +#define APBC_TWSI1 0x6c +#define APBC_UART2 0x70 +#define APMU_SDH0 0x54 +#define APMU_SDH1 0x58 +#define APMU_USB 0x5c +#define APMU_DISP0 0x4c +#define APMU_CCIC0 0x50 +#define APMU_DFC 0x60 +#define MPMU_UART_PLL 0x14 + +struct pxa168_clk_unit { + struct mmp_clk_unit unit; + void __iomem *mpmu_base; + void __iomem *apmu_base; + void __iomem *apbc_base; +}; + +static struct mmp_param_fixed_rate_clk fixed_rate_clks[] = { + {PXA168_CLK_CLK32, "clk32", NULL, CLK_IS_ROOT, 32768}, + {PXA168_CLK_VCTCXO, "vctcxo", NULL, CLK_IS_ROOT, 26000000}, + {PXA168_CLK_PLL1, "pll1", NULL, CLK_IS_ROOT, 624000000}, +}; + +static struct mmp_param_fixed_factor_clk fixed_factor_clks[] = { + {PXA168_CLK_PLL1_2, "pll1_2", "pll1", 1, 2, 0}, + {PXA168_CLK_PLL1_4, "pll1_4", "pll1_2", 1, 2, 0}, + {PXA168_CLK_PLL1_8, "pll1_8", "pll1_4", 1, 2, 0}, + {PXA168_CLK_PLL1_16, "pll1_16", "pll1_8", 1, 2, 0}, + {PXA168_CLK_PLL1_6, "pll1_6", "pll1_2", 1, 3, 0}, + {PXA168_CLK_PLL1_12, "pll1_12", "pll1_6", 1, 2, 0}, + {PXA168_CLK_PLL1_24, "pll1_24", "pll1_12", 1, 2, 0}, + {PXA168_CLK_PLL1_48, "pll1_48", "pll1_24", 1, 2, 0}, + {PXA168_CLK_PLL1_96, "pll1_96", "pll1_48", 1, 2, 0}, + {PXA168_CLK_PLL1_13, "pll1_13", "pll1", 1, 13, 0}, + {PXA168_CLK_PLL1_13_1_5, "pll1_13_1_5", "pll1_13", 2, 3, 0}, + {PXA168_CLK_PLL1_2_1_5, "pll1_2_1_5", "pll1_2", 2, 3, 0}, + {PXA168_CLK_PLL1_3_16, "pll1_3_16", "pll1", 3, 16, 0}, +}; + +static struct mmp_clk_factor_masks uart_factor_masks = { + .factor = 2, + .num_mask = 0x1fff, + .den_mask = 0x1fff, + .num_shift = 16, + .den_shift = 0, +}; + +static struct mmp_clk_factor_tbl uart_factor_tbl[] = { + {.num = 8125, .den = 1536}, /*14.745MHZ */ +}; + +static void pxa168_pll_init(struct pxa168_clk_unit *pxa_unit) +{ + struct clk *clk; + struct mmp_clk_unit *unit = &pxa_unit->unit; + + mmp_register_fixed_rate_clks(unit, fixed_rate_clks, + ARRAY_SIZE(fixed_rate_clks)); + + mmp_register_fixed_factor_clks(unit, fixed_factor_clks, + ARRAY_SIZE(fixed_factor_clks)); + + clk = mmp_clk_register_factor("uart_pll", "pll1_4", + CLK_SET_RATE_PARENT, + pxa_unit->mpmu_base + MPMU_UART_PLL, + &uart_factor_masks, uart_factor_tbl, + ARRAY_SIZE(uart_factor_tbl), NULL); + mmp_clk_add(unit, PXA168_CLK_UART_PLL, clk); +} + +static DEFINE_SPINLOCK(uart0_lock); +static DEFINE_SPINLOCK(uart1_lock); +static DEFINE_SPINLOCK(uart2_lock); +static const char *uart_parent_names[] = {"pll1_3_16", "uart_pll"}; + +static DEFINE_SPINLOCK(ssp0_lock); +static DEFINE_SPINLOCK(ssp1_lock); +static DEFINE_SPINLOCK(ssp2_lock); +static DEFINE_SPINLOCK(ssp3_lock); +static DEFINE_SPINLOCK(ssp4_lock); +static const char *ssp_parent_names[] = {"pll1_96", "pll1_48", "pll1_24", "pll1_12"}; + +static DEFINE_SPINLOCK(reset_lock); + +static struct mmp_param_mux_clk apbc_mux_clks[] = { + {0, "uart0_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBC_UART0, 4, 3, 0, &uart0_lock}, + {0, "uart1_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBC_UART1, 4, 3, 0, &uart1_lock}, + {0, "uart2_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBC_UART2, 4, 3, 0, &uart2_lock}, + {0, "ssp0_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP0, 4, 3, 0, &ssp0_lock}, + {0, "ssp1_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP1, 4, 3, 0, &ssp1_lock}, + {0, "ssp2_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP2, 4, 3, 0, &ssp2_lock}, + {0, "ssp3_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP3, 4, 3, 0, &ssp3_lock}, + {0, "ssp4_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP4, 4, 3, 0, &ssp4_lock}, +}; + +static struct mmp_param_gate_clk apbc_gate_clks[] = { + {PXA168_CLK_TWSI0, "twsi0_clk", "pll1_13_1_5", CLK_SET_RATE_PARENT, APBC_TWSI0, 0x3, 0x3, 0x0, 0, &reset_lock}, + {PXA168_CLK_TWSI1, "twsi1_clk", "pll1_13_1_5", CLK_SET_RATE_PARENT, APBC_TWSI1, 0x3, 0x3, 0x0, 0, &reset_lock}, + {PXA168_CLK_GPIO, "gpio_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_GPIO, 0x3, 0x3, 0x0, 0, &reset_lock}, + {PXA168_CLK_KPC, "kpc_clk", "clk32", CLK_SET_RATE_PARENT, APBC_KPC, 0x3, 0x3, 0x0, MMP_CLK_GATE_NEED_DELAY, NULL}, + {PXA168_CLK_RTC, "rtc_clk", "clk32", CLK_SET_RATE_PARENT, APBC_RTC, 0x83, 0x83, 0x0, MMP_CLK_GATE_NEED_DELAY, NULL}, + {PXA168_CLK_PWM0, "pwm0_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM0, 0x3, 0x3, 0x0, 0, &reset_lock}, + {PXA168_CLK_PWM1, "pwm1_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM1, 0x3, 0x3, 0x0, 0, &reset_lock}, + {PXA168_CLK_PWM2, "pwm2_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM2, 0x3, 0x3, 0x0, 0, &reset_lock}, + {PXA168_CLK_PWM3, "pwm3_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM3, 0x3, 0x3, 0x0, 0, &reset_lock}, + /* The gate clocks has mux parent. */ + {PXA168_CLK_UART0, "uart0_clk", "uart0_mux", CLK_SET_RATE_PARENT, APBC_UART0, 0x3, 0x3, 0x0, 0, &uart0_lock}, + {PXA168_CLK_UART1, "uart1_clk", "uart1_mux", CLK_SET_RATE_PARENT, APBC_UART1, 0x3, 0x3, 0x0, 0, &uart1_lock}, + {PXA168_CLK_UART2, "uart2_clk", "uart2_mux", CLK_SET_RATE_PARENT, APBC_UART2, 0x3, 0x3, 0x0, 0, &uart2_lock}, + {PXA168_CLK_SSP0, "ssp0_clk", "ssp0_mux", CLK_SET_RATE_PARENT, APBC_SSP0, 0x3, 0x3, 0x0, 0, &ssp0_lock}, + {PXA168_CLK_SSP1, "ssp1_clk", "ssp1_mux", CLK_SET_RATE_PARENT, APBC_SSP1, 0x3, 0x3, 0x0, 0, &ssp1_lock}, + {PXA168_CLK_SSP2, "ssp2_clk", "ssp2_mux", CLK_SET_RATE_PARENT, APBC_SSP2, 0x3, 0x3, 0x0, 0, &ssp2_lock}, + {PXA168_CLK_SSP3, "ssp3_clk", "ssp3_mux", CLK_SET_RATE_PARENT, APBC_SSP3, 0x3, 0x3, 0x0, 0, &ssp3_lock}, + {PXA168_CLK_SSP4, "ssp4_clk", "ssp4_mux", CLK_SET_RATE_PARENT, APBC_SSP4, 0x3, 0x3, 0x0, 0, &ssp4_lock}, +}; + +static void pxa168_apb_periph_clk_init(struct pxa168_clk_unit *pxa_unit) +{ + struct mmp_clk_unit *unit = &pxa_unit->unit; + + mmp_register_mux_clks(unit, apbc_mux_clks, pxa_unit->apbc_base, + ARRAY_SIZE(apbc_mux_clks)); + + mmp_register_gate_clks(unit, apbc_gate_clks, pxa_unit->apbc_base, + ARRAY_SIZE(apbc_gate_clks)); + +} + +static DEFINE_SPINLOCK(sdh0_lock); +static DEFINE_SPINLOCK(sdh1_lock); +static const char *sdh_parent_names[] = {"pll1_12", "pll1_13"}; + +static DEFINE_SPINLOCK(usb_lock); + +static DEFINE_SPINLOCK(disp0_lock); +static const char *disp_parent_names[] = {"pll1_2", "pll1_12"}; + +static DEFINE_SPINLOCK(ccic0_lock); +static const char *ccic_parent_names[] = {"pll1_2", "pll1_12"}; +static const char *ccic_phy_parent_names[] = {"pll1_6", "pll1_12"}; + +static struct mmp_param_mux_clk apmu_mux_clks[] = { + {0, "sdh0_mux", sdh_parent_names, ARRAY_SIZE(sdh_parent_names), CLK_SET_RATE_PARENT, APMU_SDH0, 6, 1, 0, &sdh0_lock}, + {0, "sdh1_mux", sdh_parent_names, ARRAY_SIZE(sdh_parent_names), CLK_SET_RATE_PARENT, APMU_SDH1, 6, 1, 0, &sdh1_lock}, + {0, "disp0_mux", disp_parent_names, ARRAY_SIZE(disp_parent_names), CLK_SET_RATE_PARENT, APMU_DISP0, 6, 1, 0, &disp0_lock}, + {0, "ccic0_mux", ccic_parent_names, ARRAY_SIZE(ccic_parent_names), CLK_SET_RATE_PARENT, APMU_CCIC0, 6, 1, 0, &ccic0_lock}, + {0, "ccic0_phy_mux", ccic_phy_parent_names, ARRAY_SIZE(ccic_phy_parent_names), CLK_SET_RATE_PARENT, APMU_CCIC0, 7, 1, 0, &ccic0_lock}, +}; + +static struct mmp_param_div_clk apmu_div_clks[] = { + {0, "ccic0_sphy_div", "ccic0_mux", CLK_SET_RATE_PARENT, APMU_CCIC0, 10, 5, 0, &ccic0_lock}, +}; + +static struct mmp_param_gate_clk apmu_gate_clks[] = { + {PXA168_CLK_DFC, "dfc_clk", "pll1_4", CLK_SET_RATE_PARENT, APMU_DFC, 0x19b, 0x19b, 0x0, 0, NULL}, + {PXA168_CLK_USB, "usb_clk", "usb_pll", 0, APMU_USB, 0x9, 0x9, 0x0, 0, &usb_lock}, + {PXA168_CLK_SPH, "sph_clk", "usb_pll", 0, APMU_USB, 0x12, 0x12, 0x0, 0, &usb_lock}, + /* The gate clocks has mux parent. */ + {PXA168_CLK_SDH0, "sdh0_clk", "sdh0_mux", CLK_SET_RATE_PARENT, APMU_SDH0, 0x1b, 0x1b, 0x0, 0, &sdh0_lock}, + {PXA168_CLK_SDH1, "sdh1_clk", "sdh1_mux", CLK_SET_RATE_PARENT, APMU_SDH1, 0x1b, 0x1b, 0x0, 0, &sdh1_lock}, + {PXA168_CLK_DISP0, "disp0_clk", "disp0_mux", CLK_SET_RATE_PARENT, APMU_DISP0, 0x1b, 0x1b, 0x0, 0, &disp0_lock}, + {PXA168_CLK_CCIC0, "ccic0_clk", "ccic0_mux", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x1b, 0x1b, 0x0, 0, &ccic0_lock}, + {PXA168_CLK_CCIC0_PHY, "ccic0_phy_clk", "ccic0_phy_mux", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x24, 0x24, 0x0, 0, &ccic0_lock}, + {PXA168_CLK_CCIC0_SPHY, "ccic0_sphy_clk", "ccic0_sphy_div", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x300, 0x300, 0x0, 0, &ccic0_lock}, +}; + +static void pxa168_axi_periph_clk_init(struct pxa168_clk_unit *pxa_unit) +{ + struct mmp_clk_unit *unit = &pxa_unit->unit; + + mmp_register_mux_clks(unit, apmu_mux_clks, pxa_unit->apmu_base, + ARRAY_SIZE(apmu_mux_clks)); + + mmp_register_div_clks(unit, apmu_div_clks, pxa_unit->apmu_base, + ARRAY_SIZE(apmu_div_clks)); + + mmp_register_gate_clks(unit, apmu_gate_clks, pxa_unit->apmu_base, + ARRAY_SIZE(apmu_gate_clks)); +} + +static void pxa168_clk_reset_init(struct device_node *np, + struct pxa168_clk_unit *pxa_unit) +{ + struct mmp_clk_reset_cell *cells; + int i, nr_resets; + + nr_resets = ARRAY_SIZE(apbc_gate_clks); + cells = kcalloc(nr_resets, sizeof(*cells), GFP_KERNEL); + if (!cells) + return; + + for (i = 0; i < nr_resets; i++) { + cells[i].clk_id = apbc_gate_clks[i].id; + cells[i].reg = pxa_unit->apbc_base + apbc_gate_clks[i].offset; + cells[i].flags = 0; + cells[i].lock = apbc_gate_clks[i].lock; + cells[i].bits = 0x4; + } + + mmp_clk_reset_register(np, cells, nr_resets); +} + +static void __init pxa168_clk_init(struct device_node *np) +{ + struct pxa168_clk_unit *pxa_unit; + + pxa_unit = kzalloc(sizeof(*pxa_unit), GFP_KERNEL); + if (!pxa_unit) + return; + + pxa_unit->mpmu_base = of_iomap(np, 0); + if (!pxa_unit->mpmu_base) { + pr_err("failed to map mpmu registers\n"); + return; + } + + pxa_unit->apmu_base = of_iomap(np, 1); + if (!pxa_unit->mpmu_base) { + pr_err("failed to map apmu registers\n"); + return; + } + + pxa_unit->apbc_base = of_iomap(np, 2); + if (!pxa_unit->apbc_base) { + pr_err("failed to map apbc registers\n"); + return; + } + + mmp_clk_init(np, &pxa_unit->unit, PXA168_NR_CLKS); + + pxa168_pll_init(pxa_unit); + + pxa168_apb_periph_clk_init(pxa_unit); + + pxa168_axi_periph_clk_init(pxa_unit); + + pxa168_clk_reset_init(np, pxa_unit); +} + +CLK_OF_DECLARE(pxa168_clk, "marvell,pxa168-clock", pxa168_clk_init); diff --git a/include/dt-bindings/clock/marvell,pxa168.h b/include/dt-bindings/clock/marvell,pxa168.h new file mode 100644 index 000000000000..79630b9d74b8 --- /dev/null +++ b/include/dt-bindings/clock/marvell,pxa168.h @@ -0,0 +1,57 @@ +#ifndef __DTS_MARVELL_PXA168_CLOCK_H +#define __DTS_MARVELL_PXA168_CLOCK_H + +/* fixed clocks and plls */ +#define PXA168_CLK_CLK32 1 +#define PXA168_CLK_VCTCXO 2 +#define PXA168_CLK_PLL1 3 +#define PXA168_CLK_PLL1_2 8 +#define PXA168_CLK_PLL1_4 9 +#define PXA168_CLK_PLL1_8 10 +#define PXA168_CLK_PLL1_16 11 +#define PXA168_CLK_PLL1_6 12 +#define PXA168_CLK_PLL1_12 13 +#define PXA168_CLK_PLL1_24 14 +#define PXA168_CLK_PLL1_48 15 +#define PXA168_CLK_PLL1_96 16 +#define PXA168_CLK_PLL1_13 17 +#define PXA168_CLK_PLL1_13_1_5 18 +#define PXA168_CLK_PLL1_2_1_5 19 +#define PXA168_CLK_PLL1_3_16 20 +#define PXA168_CLK_UART_PLL 27 + +/* apb periphrals */ +#define PXA168_CLK_TWSI0 60 +#define PXA168_CLK_TWSI1 61 +#define PXA168_CLK_TWSI2 62 +#define PXA168_CLK_TWSI3 63 +#define PXA168_CLK_GPIO 64 +#define PXA168_CLK_KPC 65 +#define PXA168_CLK_RTC 66 +#define PXA168_CLK_PWM0 67 +#define PXA168_CLK_PWM1 68 +#define PXA168_CLK_PWM2 69 +#define PXA168_CLK_PWM3 70 +#define PXA168_CLK_UART0 71 +#define PXA168_CLK_UART1 72 +#define PXA168_CLK_UART2 73 +#define PXA168_CLK_SSP0 74 +#define PXA168_CLK_SSP1 75 +#define PXA168_CLK_SSP2 76 +#define PXA168_CLK_SSP3 77 +#define PXA168_CLK_SSP4 78 + +/* axi periphrals */ +#define PXA168_CLK_DFC 100 +#define PXA168_CLK_SDH0 101 +#define PXA168_CLK_SDH1 102 +#define PXA168_CLK_SDH2 103 +#define PXA168_CLK_USB 104 +#define PXA168_CLK_SPH 105 +#define PXA168_CLK_DISP0 106 +#define PXA168_CLK_CCIC0 107 +#define PXA168_CLK_CCIC0_PHY 108 +#define PXA168_CLK_CCIC0_SPHY 109 + +#define PXA168_NR_CLKS 200 +#endif -- cgit v1.2.3-59-g8ed1b From 2bc61da9f7ff422117a68bef0d309a29affd023a Mon Sep 17 00:00:00 2001 From: Chao Xie Date: Fri, 31 Oct 2014 10:13:50 +0800 Subject: clk: mmp: add pxa910 DT support for clock driver It adds the DT support for pxa910 clock subsystem. Signed-off-by: Chao Xie Acked-by: Haojian Zhuang Signed-off-by: Michael Turquette --- .../devicetree/bindings/clock/marvell,pxa910.txt | 21 ++ drivers/clk/mmp/Makefile | 2 +- drivers/clk/mmp/clk-of-pxa910.c | 301 +++++++++++++++++++++ include/dt-bindings/clock/marvell,pxa910.h | 54 ++++ 4 files changed, 377 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/clock/marvell,pxa910.txt create mode 100644 drivers/clk/mmp/clk-of-pxa910.c create mode 100644 include/dt-bindings/clock/marvell,pxa910.h (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/marvell,pxa910.txt b/Documentation/devicetree/bindings/clock/marvell,pxa910.txt new file mode 100644 index 000000000000..d9f41f3c03a0 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/marvell,pxa910.txt @@ -0,0 +1,21 @@ +* Marvell PXA910 Clock Controller + +The PXA910 clock subsystem generates and supplies clock to various +controllers within the PXA910 SoC. + +Required Properties: + +- compatible: should be one of the following. + - "marvell,pxa910-clock" - controller compatible with PXA910 SoC. + +- reg: physical base address of the clock subsystem and length of memory mapped + region. There are 4 places in SOC has clock control logic: + "mpmu", "apmu", "apbc", "apbcp". So four reg spaces need to be defined. + +- #clock-cells: should be 1. +- #reset-cells: should be 1. + +Each clock is assigned an identifier and client nodes use this identifier +to specify the clock which they consume. + +All these identifier could be found in . diff --git a/drivers/clk/mmp/Makefile b/drivers/clk/mmp/Makefile index 733acc7aa484..947cd74a82a7 100644 --- a/drivers/clk/mmp/Makefile +++ b/drivers/clk/mmp/Makefile @@ -6,7 +6,7 @@ obj-y += clk-apbc.o clk-apmu.o clk-frac.o clk-mix.o clk-gate.o clk.o obj-$(CONFIG_RESET_CONTROLLER) += reset.o -obj-$(CONFIG_MACH_MMP_DT) += clk-of-pxa168.o +obj-$(CONFIG_MACH_MMP_DT) += clk-of-pxa168.o clk-of-pxa910.o obj-$(CONFIG_CPU_PXA168) += clk-pxa168.o obj-$(CONFIG_CPU_PXA910) += clk-pxa910.o diff --git a/drivers/clk/mmp/clk-of-pxa910.c b/drivers/clk/mmp/clk-of-pxa910.c new file mode 100644 index 000000000000..5e3c80dad336 --- /dev/null +++ b/drivers/clk/mmp/clk-of-pxa910.c @@ -0,0 +1,301 @@ +/* + * pxa910 clock framework source file + * + * Copyright (C) 2012 Marvell + * Chao Xie + * + * 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 + +#include "clk.h" +#include "reset.h" + +#define APBC_RTC 0x28 +#define APBC_TWSI0 0x2c +#define APBC_KPC 0x18 +#define APBC_UART0 0x0 +#define APBC_UART1 0x4 +#define APBC_GPIO 0x8 +#define APBC_PWM0 0xc +#define APBC_PWM1 0x10 +#define APBC_PWM2 0x14 +#define APBC_PWM3 0x18 +#define APBC_SSP0 0x1c +#define APBC_SSP1 0x20 +#define APBC_SSP2 0x4c +#define APBCP_TWSI1 0x28 +#define APBCP_UART2 0x1c +#define APMU_SDH0 0x54 +#define APMU_SDH1 0x58 +#define APMU_USB 0x5c +#define APMU_DISP0 0x4c +#define APMU_CCIC0 0x50 +#define APMU_DFC 0x60 +#define MPMU_UART_PLL 0x14 + +struct pxa910_clk_unit { + struct mmp_clk_unit unit; + void __iomem *mpmu_base; + void __iomem *apmu_base; + void __iomem *apbc_base; + void __iomem *apbcp_base; +}; + +static struct mmp_param_fixed_rate_clk fixed_rate_clks[] = { + {PXA910_CLK_CLK32, "clk32", NULL, CLK_IS_ROOT, 32768}, + {PXA910_CLK_VCTCXO, "vctcxo", NULL, CLK_IS_ROOT, 26000000}, + {PXA910_CLK_PLL1, "pll1", NULL, CLK_IS_ROOT, 624000000}, +}; + +static struct mmp_param_fixed_factor_clk fixed_factor_clks[] = { + {PXA910_CLK_PLL1_2, "pll1_2", "pll1", 1, 2, 0}, + {PXA910_CLK_PLL1_4, "pll1_4", "pll1_2", 1, 2, 0}, + {PXA910_CLK_PLL1_8, "pll1_8", "pll1_4", 1, 2, 0}, + {PXA910_CLK_PLL1_16, "pll1_16", "pll1_8", 1, 2, 0}, + {PXA910_CLK_PLL1_6, "pll1_6", "pll1_2", 1, 3, 0}, + {PXA910_CLK_PLL1_12, "pll1_12", "pll1_6", 1, 2, 0}, + {PXA910_CLK_PLL1_24, "pll1_24", "pll1_12", 1, 2, 0}, + {PXA910_CLK_PLL1_48, "pll1_48", "pll1_24", 1, 2, 0}, + {PXA910_CLK_PLL1_96, "pll1_96", "pll1_48", 1, 2, 0}, + {PXA910_CLK_PLL1_13, "pll1_13", "pll1", 1, 13, 0}, + {PXA910_CLK_PLL1_13_1_5, "pll1_13_1_5", "pll1_13", 2, 3, 0}, + {PXA910_CLK_PLL1_2_1_5, "pll1_2_1_5", "pll1_2", 2, 3, 0}, + {PXA910_CLK_PLL1_3_16, "pll1_3_16", "pll1", 3, 16, 0}, +}; + +static struct mmp_clk_factor_masks uart_factor_masks = { + .factor = 2, + .num_mask = 0x1fff, + .den_mask = 0x1fff, + .num_shift = 16, + .den_shift = 0, +}; + +static struct mmp_clk_factor_tbl uart_factor_tbl[] = { + {.num = 8125, .den = 1536}, /*14.745MHZ */ +}; + +static void pxa910_pll_init(struct pxa910_clk_unit *pxa_unit) +{ + struct clk *clk; + struct mmp_clk_unit *unit = &pxa_unit->unit; + + mmp_register_fixed_rate_clks(unit, fixed_rate_clks, + ARRAY_SIZE(fixed_rate_clks)); + + mmp_register_fixed_factor_clks(unit, fixed_factor_clks, + ARRAY_SIZE(fixed_factor_clks)); + + clk = mmp_clk_register_factor("uart_pll", "pll1_4", + CLK_SET_RATE_PARENT, + pxa_unit->mpmu_base + MPMU_UART_PLL, + &uart_factor_masks, uart_factor_tbl, + ARRAY_SIZE(uart_factor_tbl), NULL); + mmp_clk_add(unit, PXA910_CLK_UART_PLL, clk); +} + +static DEFINE_SPINLOCK(uart0_lock); +static DEFINE_SPINLOCK(uart1_lock); +static DEFINE_SPINLOCK(uart2_lock); +static const char *uart_parent_names[] = {"pll1_3_16", "uart_pll"}; + +static DEFINE_SPINLOCK(ssp0_lock); +static DEFINE_SPINLOCK(ssp1_lock); +static const char *ssp_parent_names[] = {"pll1_96", "pll1_48", "pll1_24", "pll1_12"}; + +static DEFINE_SPINLOCK(reset_lock); + +static struct mmp_param_mux_clk apbc_mux_clks[] = { + {0, "uart0_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBC_UART0, 4, 3, 0, &uart0_lock}, + {0, "uart1_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBC_UART1, 4, 3, 0, &uart1_lock}, + {0, "ssp0_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP0, 4, 3, 0, &ssp0_lock}, + {0, "ssp1_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP1, 4, 3, 0, &ssp1_lock}, +}; + +static struct mmp_param_mux_clk apbcp_mux_clks[] = { + {0, "uart2_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBCP_UART2, 4, 3, 0, &uart2_lock}, +}; + +static struct mmp_param_gate_clk apbc_gate_clks[] = { + {PXA910_CLK_TWSI0, "twsi0_clk", "pll1_13_1_5", CLK_SET_RATE_PARENT, APBC_TWSI0, 0x3, 0x3, 0x0, 0, &reset_lock}, + {PXA910_CLK_GPIO, "gpio_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_GPIO, 0x3, 0x3, 0x0, 0, &reset_lock}, + {PXA910_CLK_KPC, "kpc_clk", "clk32", CLK_SET_RATE_PARENT, APBC_KPC, 0x3, 0x3, 0x0, MMP_CLK_GATE_NEED_DELAY, NULL}, + {PXA910_CLK_RTC, "rtc_clk", "clk32", CLK_SET_RATE_PARENT, APBC_RTC, 0x83, 0x83, 0x0, MMP_CLK_GATE_NEED_DELAY, NULL}, + {PXA910_CLK_PWM0, "pwm0_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM0, 0x3, 0x3, 0x0, 0, &reset_lock}, + {PXA910_CLK_PWM1, "pwm1_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM1, 0x3, 0x3, 0x0, 0, &reset_lock}, + {PXA910_CLK_PWM2, "pwm2_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM2, 0x3, 0x3, 0x0, 0, &reset_lock}, + {PXA910_CLK_PWM3, "pwm3_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM3, 0x3, 0x3, 0x0, 0, &reset_lock}, + /* The gate clocks has mux parent. */ + {PXA910_CLK_UART0, "uart0_clk", "uart0_mux", CLK_SET_RATE_PARENT, APBC_UART0, 0x3, 0x3, 0x0, 0, &uart0_lock}, + {PXA910_CLK_UART1, "uart1_clk", "uart1_mux", CLK_SET_RATE_PARENT, APBC_UART1, 0x3, 0x3, 0x0, 0, &uart1_lock}, + {PXA910_CLK_SSP0, "ssp0_clk", "ssp0_mux", CLK_SET_RATE_PARENT, APBC_SSP0, 0x3, 0x3, 0x0, 0, &ssp0_lock}, + {PXA910_CLK_SSP1, "ssp1_clk", "ssp1_mux", CLK_SET_RATE_PARENT, APBC_SSP1, 0x3, 0x3, 0x0, 0, &ssp1_lock}, +}; + +static struct mmp_param_gate_clk apbcp_gate_clks[] = { + {PXA910_CLK_TWSI1, "twsi1_clk", "pll1_13_1_5", CLK_SET_RATE_PARENT, APBCP_TWSI1, 0x3, 0x3, 0x0, 0, &reset_lock}, + /* The gate clocks has mux parent. */ + {PXA910_CLK_UART2, "uart2_clk", "uart2_mux", CLK_SET_RATE_PARENT, APBCP_UART2, 0x3, 0x3, 0x0, 0, &uart2_lock}, +}; + +static void pxa910_apb_periph_clk_init(struct pxa910_clk_unit *pxa_unit) +{ + struct mmp_clk_unit *unit = &pxa_unit->unit; + + mmp_register_mux_clks(unit, apbc_mux_clks, pxa_unit->apbc_base, + ARRAY_SIZE(apbc_mux_clks)); + + mmp_register_mux_clks(unit, apbcp_mux_clks, pxa_unit->apbcp_base, + ARRAY_SIZE(apbcp_mux_clks)); + + mmp_register_gate_clks(unit, apbc_gate_clks, pxa_unit->apbc_base, + ARRAY_SIZE(apbc_gate_clks)); + + mmp_register_gate_clks(unit, apbcp_gate_clks, pxa_unit->apbcp_base, + ARRAY_SIZE(apbcp_gate_clks)); +} + +static DEFINE_SPINLOCK(sdh0_lock); +static DEFINE_SPINLOCK(sdh1_lock); +static const char *sdh_parent_names[] = {"pll1_12", "pll1_13"}; + +static DEFINE_SPINLOCK(usb_lock); + +static DEFINE_SPINLOCK(disp0_lock); +static const char *disp_parent_names[] = {"pll1_2", "pll1_12"}; + +static DEFINE_SPINLOCK(ccic0_lock); +static const char *ccic_parent_names[] = {"pll1_2", "pll1_12"}; +static const char *ccic_phy_parent_names[] = {"pll1_6", "pll1_12"}; + +static struct mmp_param_mux_clk apmu_mux_clks[] = { + {0, "sdh0_mux", sdh_parent_names, ARRAY_SIZE(sdh_parent_names), CLK_SET_RATE_PARENT, APMU_SDH0, 6, 1, 0, &sdh0_lock}, + {0, "sdh1_mux", sdh_parent_names, ARRAY_SIZE(sdh_parent_names), CLK_SET_RATE_PARENT, APMU_SDH1, 6, 1, 0, &sdh1_lock}, + {0, "disp0_mux", disp_parent_names, ARRAY_SIZE(disp_parent_names), CLK_SET_RATE_PARENT, APMU_DISP0, 6, 1, 0, &disp0_lock}, + {0, "ccic0_mux", ccic_parent_names, ARRAY_SIZE(ccic_parent_names), CLK_SET_RATE_PARENT, APMU_CCIC0, 6, 1, 0, &ccic0_lock}, + {0, "ccic0_phy_mux", ccic_phy_parent_names, ARRAY_SIZE(ccic_phy_parent_names), CLK_SET_RATE_PARENT, APMU_CCIC0, 7, 1, 0, &ccic0_lock}, +}; + +static struct mmp_param_div_clk apmu_div_clks[] = { + {0, "ccic0_sphy_div", "ccic0_mux", CLK_SET_RATE_PARENT, APMU_CCIC0, 10, 5, 0, &ccic0_lock}, +}; + +static struct mmp_param_gate_clk apmu_gate_clks[] = { + {PXA910_CLK_DFC, "dfc_clk", "pll1_4", CLK_SET_RATE_PARENT, APMU_DFC, 0x19b, 0x19b, 0x0, 0, NULL}, + {PXA910_CLK_USB, "usb_clk", "usb_pll", 0, APMU_USB, 0x9, 0x9, 0x0, 0, &usb_lock}, + {PXA910_CLK_SPH, "sph_clk", "usb_pll", 0, APMU_USB, 0x12, 0x12, 0x0, 0, &usb_lock}, + /* The gate clocks has mux parent. */ + {PXA910_CLK_SDH0, "sdh0_clk", "sdh0_mux", CLK_SET_RATE_PARENT, APMU_SDH0, 0x1b, 0x1b, 0x0, 0, &sdh0_lock}, + {PXA910_CLK_SDH1, "sdh1_clk", "sdh1_mux", CLK_SET_RATE_PARENT, APMU_SDH1, 0x1b, 0x1b, 0x0, 0, &sdh1_lock}, + {PXA910_CLK_DISP0, "disp0_clk", "disp0_mux", CLK_SET_RATE_PARENT, APMU_DISP0, 0x1b, 0x1b, 0x0, 0, &disp0_lock}, + {PXA910_CLK_CCIC0, "ccic0_clk", "ccic0_mux", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x1b, 0x1b, 0x0, 0, &ccic0_lock}, + {PXA910_CLK_CCIC0_PHY, "ccic0_phy_clk", "ccic0_phy_mux", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x24, 0x24, 0x0, 0, &ccic0_lock}, + {PXA910_CLK_CCIC0_SPHY, "ccic0_sphy_clk", "ccic0_sphy_div", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x300, 0x300, 0x0, 0, &ccic0_lock}, +}; + +static void pxa910_axi_periph_clk_init(struct pxa910_clk_unit *pxa_unit) +{ + struct mmp_clk_unit *unit = &pxa_unit->unit; + + mmp_register_mux_clks(unit, apmu_mux_clks, pxa_unit->apmu_base, + ARRAY_SIZE(apmu_mux_clks)); + + mmp_register_div_clks(unit, apmu_div_clks, pxa_unit->apmu_base, + ARRAY_SIZE(apmu_div_clks)); + + mmp_register_gate_clks(unit, apmu_gate_clks, pxa_unit->apmu_base, + ARRAY_SIZE(apmu_gate_clks)); +} + +static void pxa910_clk_reset_init(struct device_node *np, + struct pxa910_clk_unit *pxa_unit) +{ + struct mmp_clk_reset_cell *cells; + int i, base, nr_resets_apbc, nr_resets_apbcp, nr_resets; + + nr_resets_apbc = ARRAY_SIZE(apbc_gate_clks); + nr_resets_apbcp = ARRAY_SIZE(apbcp_gate_clks); + nr_resets = nr_resets_apbc + nr_resets_apbcp; + cells = kcalloc(nr_resets, sizeof(*cells), GFP_KERNEL); + if (!cells) + return; + + base = 0; + for (i = 0; i < nr_resets_apbc; i++) { + cells[base + i].clk_id = apbc_gate_clks[i].id; + cells[base + i].reg = + pxa_unit->apbc_base + apbc_gate_clks[i].offset; + cells[base + i].flags = 0; + cells[base + i].lock = apbc_gate_clks[i].lock; + cells[base + i].bits = 0x4; + } + + base = nr_resets_apbc; + for (i = 0; i < nr_resets_apbcp; i++) { + cells[base + i].clk_id = apbcp_gate_clks[i].id; + cells[base + i].reg = + pxa_unit->apbc_base + apbc_gate_clks[i].offset; + cells[base + i].flags = 0; + cells[base + i].lock = apbc_gate_clks[i].lock; + cells[base + i].bits = 0x4; + } + + mmp_clk_reset_register(np, cells, nr_resets); +} + +static void __init pxa910_clk_init(struct device_node *np) +{ + struct pxa910_clk_unit *pxa_unit; + + pxa_unit = kzalloc(sizeof(*pxa_unit), GFP_KERNEL); + if (!pxa_unit) + return; + + pxa_unit->mpmu_base = of_iomap(np, 0); + if (!pxa_unit->mpmu_base) { + pr_err("failed to map mpmu registers\n"); + return; + } + + pxa_unit->apmu_base = of_iomap(np, 1); + if (!pxa_unit->mpmu_base) { + pr_err("failed to map apmu registers\n"); + return; + } + + pxa_unit->apbc_base = of_iomap(np, 2); + if (!pxa_unit->apbc_base) { + pr_err("failed to map apbc registers\n"); + return; + } + + pxa_unit->apbcp_base = of_iomap(np, 3); + if (!pxa_unit->mpmu_base) { + pr_err("failed to map apbcp registers\n"); + return; + } + + mmp_clk_init(np, &pxa_unit->unit, PXA910_NR_CLKS); + + pxa910_pll_init(pxa_unit); + + pxa910_apb_periph_clk_init(pxa_unit); + + pxa910_axi_periph_clk_init(pxa_unit); + + pxa910_clk_reset_init(np, pxa_unit); +} + +CLK_OF_DECLARE(pxa910_clk, "marvell,pxa910-clock", pxa910_clk_init); diff --git a/include/dt-bindings/clock/marvell,pxa910.h b/include/dt-bindings/clock/marvell,pxa910.h new file mode 100644 index 000000000000..719cffb2bea2 --- /dev/null +++ b/include/dt-bindings/clock/marvell,pxa910.h @@ -0,0 +1,54 @@ +#ifndef __DTS_MARVELL_PXA910_CLOCK_H +#define __DTS_MARVELL_PXA910_CLOCK_H + +/* fixed clocks and plls */ +#define PXA910_CLK_CLK32 1 +#define PXA910_CLK_VCTCXO 2 +#define PXA910_CLK_PLL1 3 +#define PXA910_CLK_PLL1_2 8 +#define PXA910_CLK_PLL1_4 9 +#define PXA910_CLK_PLL1_8 10 +#define PXA910_CLK_PLL1_16 11 +#define PXA910_CLK_PLL1_6 12 +#define PXA910_CLK_PLL1_12 13 +#define PXA910_CLK_PLL1_24 14 +#define PXA910_CLK_PLL1_48 15 +#define PXA910_CLK_PLL1_96 16 +#define PXA910_CLK_PLL1_13 17 +#define PXA910_CLK_PLL1_13_1_5 18 +#define PXA910_CLK_PLL1_2_1_5 19 +#define PXA910_CLK_PLL1_3_16 20 +#define PXA910_CLK_UART_PLL 27 + +/* apb periphrals */ +#define PXA910_CLK_TWSI0 60 +#define PXA910_CLK_TWSI1 61 +#define PXA910_CLK_TWSI2 62 +#define PXA910_CLK_TWSI3 63 +#define PXA910_CLK_GPIO 64 +#define PXA910_CLK_KPC 65 +#define PXA910_CLK_RTC 66 +#define PXA910_CLK_PWM0 67 +#define PXA910_CLK_PWM1 68 +#define PXA910_CLK_PWM2 69 +#define PXA910_CLK_PWM3 70 +#define PXA910_CLK_UART0 71 +#define PXA910_CLK_UART1 72 +#define PXA910_CLK_UART2 73 +#define PXA910_CLK_SSP0 74 +#define PXA910_CLK_SSP1 75 + +/* axi periphrals */ +#define PXA910_CLK_DFC 100 +#define PXA910_CLK_SDH0 101 +#define PXA910_CLK_SDH1 102 +#define PXA910_CLK_SDH2 103 +#define PXA910_CLK_USB 104 +#define PXA910_CLK_SPH 105 +#define PXA910_CLK_DISP0 106 +#define PXA910_CLK_CCIC0 107 +#define PXA910_CLK_CCIC0_PHY 108 +#define PXA910_CLK_CCIC0_SPHY 109 + +#define PXA910_NR_CLKS 200 +#endif -- cgit v1.2.3-59-g8ed1b From 1ec770d92a62582ac1f7e0969d6a0ddc54d5f49e Mon Sep 17 00:00:00 2001 From: Chao Xie Date: Fri, 31 Oct 2014 10:13:51 +0800 Subject: clk: mmp: add mmp2 DT support for clock driver It adds the DT support for mmp2 clock subsystem. Signed-off-by: Chao Xie Acked-by: Haojian Zhuang Signed-off-by: Michael Turquette --- .../devicetree/bindings/clock/marvell,mmp2.txt | 21 ++ drivers/clk/mmp/Makefile | 1 + drivers/clk/mmp/clk-of-mmp2.c | 334 +++++++++++++++++++++ include/dt-bindings/clock/marvell,mmp2.h | 74 +++++ 4 files changed, 430 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/marvell,mmp2.txt create mode 100644 drivers/clk/mmp/clk-of-mmp2.c create mode 100644 include/dt-bindings/clock/marvell,mmp2.h (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/marvell,mmp2.txt b/Documentation/devicetree/bindings/clock/marvell,mmp2.txt new file mode 100644 index 000000000000..af376a01f2b7 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/marvell,mmp2.txt @@ -0,0 +1,21 @@ +* Marvell MMP2 Clock Controller + +The MMP2 clock subsystem generates and supplies clock to various +controllers within the MMP2 SoC. + +Required Properties: + +- compatible: should be one of the following. + - "marvell,mmp2-clock" - controller compatible with MMP2 SoC. + +- reg: physical base address of the clock subsystem and length of memory mapped + region. There are 3 places in SOC has clock control logic: + "mpmu", "apmu", "apbc". So three reg spaces need to be defined. + +- #clock-cells: should be 1. +- #reset-cells: should be 1. + +Each clock is assigned an identifier and client nodes use this identifier +to specify the clock which they consume. + +All these identifier could be found in . diff --git a/drivers/clk/mmp/Makefile b/drivers/clk/mmp/Makefile index 947cd74a82a7..3caaf7cc169c 100644 --- a/drivers/clk/mmp/Makefile +++ b/drivers/clk/mmp/Makefile @@ -7,6 +7,7 @@ obj-y += clk-apbc.o clk-apmu.o clk-frac.o clk-mix.o clk-gate.o clk.o obj-$(CONFIG_RESET_CONTROLLER) += reset.o obj-$(CONFIG_MACH_MMP_DT) += clk-of-pxa168.o clk-of-pxa910.o +obj-$(CONFIG_MACH_MMP2_DT) += clk-of-mmp2.o obj-$(CONFIG_CPU_PXA168) += clk-pxa168.o obj-$(CONFIG_CPU_PXA910) += clk-pxa910.o diff --git a/drivers/clk/mmp/clk-of-mmp2.c b/drivers/clk/mmp/clk-of-mmp2.c new file mode 100644 index 000000000000..2cbc2b43ae52 --- /dev/null +++ b/drivers/clk/mmp/clk-of-mmp2.c @@ -0,0 +1,334 @@ +/* + * mmp2 clock framework source file + * + * Copyright (C) 2012 Marvell + * Chao Xie + * + * 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 + +#include "clk.h" +#include "reset.h" + +#define APBC_RTC 0x0 +#define APBC_TWSI0 0x4 +#define APBC_TWSI1 0x8 +#define APBC_TWSI2 0xc +#define APBC_TWSI3 0x10 +#define APBC_TWSI4 0x7c +#define APBC_TWSI5 0x80 +#define APBC_KPC 0x18 +#define APBC_UART0 0x2c +#define APBC_UART1 0x30 +#define APBC_UART2 0x34 +#define APBC_UART3 0x88 +#define APBC_GPIO 0x38 +#define APBC_PWM0 0x3c +#define APBC_PWM1 0x40 +#define APBC_PWM2 0x44 +#define APBC_PWM3 0x48 +#define APBC_SSP0 0x50 +#define APBC_SSP1 0x54 +#define APBC_SSP2 0x58 +#define APBC_SSP3 0x5c +#define APMU_SDH0 0x54 +#define APMU_SDH1 0x58 +#define APMU_SDH2 0xe8 +#define APMU_SDH3 0xec +#define APMU_USB 0x5c +#define APMU_DISP0 0x4c +#define APMU_DISP1 0x110 +#define APMU_CCIC0 0x50 +#define APMU_CCIC1 0xf4 +#define MPMU_UART_PLL 0x14 + +struct mmp2_clk_unit { + struct mmp_clk_unit unit; + void __iomem *mpmu_base; + void __iomem *apmu_base; + void __iomem *apbc_base; +}; + +static struct mmp_param_fixed_rate_clk fixed_rate_clks[] = { + {MMP2_CLK_CLK32, "clk32", NULL, CLK_IS_ROOT, 32768}, + {MMP2_CLK_VCTCXO, "vctcxo", NULL, CLK_IS_ROOT, 26000000}, + {MMP2_CLK_PLL1, "pll1", NULL, CLK_IS_ROOT, 800000000}, + {MMP2_CLK_PLL2, "pll2", NULL, CLK_IS_ROOT, 960000000}, + {MMP2_CLK_USB_PLL, "usb_pll", NULL, CLK_IS_ROOT, 480000000}, +}; + +static struct mmp_param_fixed_factor_clk fixed_factor_clks[] = { + {MMP2_CLK_PLL1_2, "pll1_2", "pll1", 1, 2, 0}, + {MMP2_CLK_PLL1_4, "pll1_4", "pll1_2", 1, 2, 0}, + {MMP2_CLK_PLL1_8, "pll1_8", "pll1_4", 1, 2, 0}, + {MMP2_CLK_PLL1_16, "pll1_16", "pll1_8", 1, 2, 0}, + {MMP2_CLK_PLL1_20, "pll1_20", "pll1_4", 1, 5, 0}, + {MMP2_CLK_PLL1_3, "pll1_3", "pll1", 1, 3, 0}, + {MMP2_CLK_PLL1_6, "pll1_6", "pll1_3", 1, 2, 0}, + {MMP2_CLK_PLL1_12, "pll1_12", "pll1_6", 1, 2, 0}, + {MMP2_CLK_PLL2_2, "pll2_2", "pll2", 1, 2, 0}, + {MMP2_CLK_PLL2_4, "pll2_4", "pll2_2", 1, 2, 0}, + {MMP2_CLK_PLL2_8, "pll2_8", "pll2_4", 1, 2, 0}, + {MMP2_CLK_PLL2_16, "pll2_16", "pll2_8", 1, 2, 0}, + {MMP2_CLK_PLL2_3, "pll2_3", "pll2", 1, 3, 0}, + {MMP2_CLK_PLL2_6, "pll2_6", "pll2_3", 1, 2, 0}, + {MMP2_CLK_PLL2_12, "pll2_12", "pll2_6", 1, 2, 0}, + {MMP2_CLK_VCTCXO_2, "vctcxo_2", "vctcxo", 1, 2, 0}, + {MMP2_CLK_VCTCXO_4, "vctcxo_4", "vctcxo_2", 1, 2, 0}, +}; + +static struct mmp_clk_factor_masks uart_factor_masks = { + .factor = 2, + .num_mask = 0x1fff, + .den_mask = 0x1fff, + .num_shift = 16, + .den_shift = 0, +}; + +static struct mmp_clk_factor_tbl uart_factor_tbl[] = { + {.num = 14634, .den = 2165}, /*14.745MHZ */ + {.num = 3521, .den = 689}, /*19.23MHZ */ + {.num = 9679, .den = 5728}, /*58.9824MHZ */ + {.num = 15850, .den = 9451}, /*59.429MHZ */ +}; + +static void mmp2_pll_init(struct mmp2_clk_unit *pxa_unit) +{ + struct clk *clk; + struct mmp_clk_unit *unit = &pxa_unit->unit; + + mmp_register_fixed_rate_clks(unit, fixed_rate_clks, + ARRAY_SIZE(fixed_rate_clks)); + + mmp_register_fixed_factor_clks(unit, fixed_factor_clks, + ARRAY_SIZE(fixed_factor_clks)); + + clk = mmp_clk_register_factor("uart_pll", "pll1_4", + CLK_SET_RATE_PARENT, + pxa_unit->mpmu_base + MPMU_UART_PLL, + &uart_factor_masks, uart_factor_tbl, + ARRAY_SIZE(uart_factor_tbl), NULL); + mmp_clk_add(unit, MMP2_CLK_UART_PLL, clk); +} + +static DEFINE_SPINLOCK(uart0_lock); +static DEFINE_SPINLOCK(uart1_lock); +static DEFINE_SPINLOCK(uart2_lock); +static const char *uart_parent_names[] = {"uart_pll", "vctcxo"}; + +static DEFINE_SPINLOCK(ssp0_lock); +static DEFINE_SPINLOCK(ssp1_lock); +static DEFINE_SPINLOCK(ssp2_lock); +static DEFINE_SPINLOCK(ssp3_lock); +static const char *ssp_parent_names[] = {"vctcxo_4", "vctcxo_2", "vctcxo", "pll1_16"}; + +static DEFINE_SPINLOCK(reset_lock); + +static struct mmp_param_mux_clk apbc_mux_clks[] = { + {0, "uart0_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBC_UART0, 4, 3, 0, &uart0_lock}, + {0, "uart1_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBC_UART1, 4, 3, 0, &uart1_lock}, + {0, "uart2_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBC_UART2, 4, 3, 0, &uart2_lock}, + {0, "uart3_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBC_UART3, 4, 3, 0, &uart2_lock}, + {0, "ssp0_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP0, 4, 3, 0, &ssp0_lock}, + {0, "ssp1_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP1, 4, 3, 0, &ssp1_lock}, + {0, "ssp2_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP2, 4, 3, 0, &ssp2_lock}, + {0, "ssp3_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP3, 4, 3, 0, &ssp3_lock}, +}; + +static struct mmp_param_gate_clk apbc_gate_clks[] = { + {MMP2_CLK_TWSI0, "twsi0_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_TWSI0, 0x7, 0x3, 0x0, 0, &reset_lock}, + {MMP2_CLK_TWSI1, "twsi1_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_TWSI1, 0x7, 0x3, 0x0, 0, &reset_lock}, + {MMP2_CLK_TWSI2, "twsi2_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_TWSI2, 0x7, 0x3, 0x0, 0, &reset_lock}, + {MMP2_CLK_TWSI3, "twsi3_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_TWSI3, 0x7, 0x3, 0x0, 0, &reset_lock}, + {MMP2_CLK_TWSI4, "twsi4_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_TWSI4, 0x7, 0x3, 0x0, 0, &reset_lock}, + {MMP2_CLK_TWSI5, "twsi5_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_TWSI5, 0x7, 0x3, 0x0, 0, &reset_lock}, + {MMP2_CLK_GPIO, "gpio_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_GPIO, 0x7, 0x3, 0x0, 0, &reset_lock}, + {MMP2_CLK_KPC, "kpc_clk", "clk32", CLK_SET_RATE_PARENT, APBC_KPC, 0x7, 0x3, 0x0, MMP_CLK_GATE_NEED_DELAY, &reset_lock}, + {MMP2_CLK_RTC, "rtc_clk", "clk32", CLK_SET_RATE_PARENT, APBC_RTC, 0x87, 0x83, 0x0, MMP_CLK_GATE_NEED_DELAY, &reset_lock}, + {MMP2_CLK_PWM0, "pwm0_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM0, 0x7, 0x3, 0x0, 0, &reset_lock}, + {MMP2_CLK_PWM1, "pwm1_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM1, 0x7, 0x3, 0x0, 0, &reset_lock}, + {MMP2_CLK_PWM2, "pwm2_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM2, 0x7, 0x3, 0x0, 0, &reset_lock}, + {MMP2_CLK_PWM3, "pwm3_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM3, 0x7, 0x3, 0x0, 0, &reset_lock}, + /* The gate clocks has mux parent. */ + {MMP2_CLK_UART0, "uart0_clk", "uart0_mux", CLK_SET_RATE_PARENT, APBC_UART0, 0x7, 0x3, 0x0, 0, &uart0_lock}, + {MMP2_CLK_UART1, "uart1_clk", "uart1_mux", CLK_SET_RATE_PARENT, APBC_UART1, 0x7, 0x3, 0x0, 0, &uart1_lock}, + {MMP2_CLK_UART2, "uart2_clk", "uart2_mux", CLK_SET_RATE_PARENT, APBC_UART2, 0x7, 0x3, 0x0, 0, &uart2_lock}, + {MMP2_CLK_UART3, "uart3_clk", "uart3_mux", CLK_SET_RATE_PARENT, APBC_UART3, 0x7, 0x3, 0x0, 0, &uart2_lock}, + {MMP2_CLK_SSP0, "ssp0_clk", "ssp0_mux", CLK_SET_RATE_PARENT, APBC_SSP0, 0x7, 0x3, 0x0, 0, &ssp0_lock}, + {MMP2_CLK_SSP1, "ssp1_clk", "ssp1_mux", CLK_SET_RATE_PARENT, APBC_SSP1, 0x7, 0x3, 0x0, 0, &ssp1_lock}, + {MMP2_CLK_SSP2, "ssp2_clk", "ssp2_mux", CLK_SET_RATE_PARENT, APBC_SSP2, 0x7, 0x3, 0x0, 0, &ssp2_lock}, + {MMP2_CLK_SSP3, "ssp3_clk", "ssp3_mux", CLK_SET_RATE_PARENT, APBC_SSP3, 0x7, 0x3, 0x0, 0, &ssp3_lock}, +}; + +static void mmp2_apb_periph_clk_init(struct mmp2_clk_unit *pxa_unit) +{ + struct mmp_clk_unit *unit = &pxa_unit->unit; + + mmp_register_mux_clks(unit, apbc_mux_clks, pxa_unit->apbc_base, + ARRAY_SIZE(apbc_mux_clks)); + + mmp_register_gate_clks(unit, apbc_gate_clks, pxa_unit->apbc_base, + ARRAY_SIZE(apbc_gate_clks)); +} + +static DEFINE_SPINLOCK(sdh_lock); +static const char *sdh_parent_names[] = {"pll1_4", "pll2", "usb_pll", "pll1"}; +static struct mmp_clk_mix_config sdh_mix_config = { + .reg_info = DEFINE_MIX_REG_INFO(4, 10, 2, 8, 32), +}; + +static DEFINE_SPINLOCK(usb_lock); + +static DEFINE_SPINLOCK(disp0_lock); +static DEFINE_SPINLOCK(disp1_lock); +static const char *disp_parent_names[] = {"pll1", "pll1_16", "pll2", "vctcxo"}; + +static DEFINE_SPINLOCK(ccic0_lock); +static DEFINE_SPINLOCK(ccic1_lock); +static const char *ccic_parent_names[] = {"pll1_2", "pll1_16", "vctcxo"}; +static struct mmp_clk_mix_config ccic0_mix_config = { + .reg_info = DEFINE_MIX_REG_INFO(4, 17, 2, 6, 32), +}; +static struct mmp_clk_mix_config ccic1_mix_config = { + .reg_info = DEFINE_MIX_REG_INFO(4, 16, 2, 6, 32), +}; + +static struct mmp_param_mux_clk apmu_mux_clks[] = { + {MMP2_CLK_DISP0_MUX, "disp0_mux", disp_parent_names, ARRAY_SIZE(disp_parent_names), CLK_SET_RATE_PARENT, APMU_DISP0, 6, 2, 0, &disp0_lock}, + {MMP2_CLK_DISP1_MUX, "disp1_mux", disp_parent_names, ARRAY_SIZE(disp_parent_names), CLK_SET_RATE_PARENT, APMU_DISP1, 6, 2, 0, &disp1_lock}, +}; + +static struct mmp_param_div_clk apmu_div_clks[] = { + {0, "disp0_div", "disp0_mux", CLK_SET_RATE_PARENT, APMU_DISP0, 8, 4, 0, &disp0_lock}, + {0, "disp0_sphy_div", "disp0_mux", CLK_SET_RATE_PARENT, APMU_DISP0, 15, 5, 0, &disp0_lock}, + {0, "disp1_div", "disp1_mux", CLK_SET_RATE_PARENT, APMU_DISP1, 8, 4, 0, &disp1_lock}, + {0, "ccic0_sphy_div", "ccic0_mix_clk", CLK_SET_RATE_PARENT, APMU_CCIC0, 10, 5, 0, &ccic0_lock}, + {0, "ccic1_sphy_div", "ccic1_mix_clk", CLK_SET_RATE_PARENT, APMU_CCIC1, 10, 5, 0, &ccic1_lock}, +}; + +static struct mmp_param_gate_clk apmu_gate_clks[] = { + {MMP2_CLK_USB, "usb_clk", "usb_pll", 0, APMU_USB, 0x9, 0x9, 0x0, 0, &usb_lock}, + /* The gate clocks has mux parent. */ + {MMP2_CLK_SDH0, "sdh0_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH0, 0x1b, 0x1b, 0x0, 0, &sdh_lock}, + {MMP2_CLK_SDH1, "sdh1_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH1, 0x1b, 0x1b, 0x0, 0, &sdh_lock}, + {MMP2_CLK_SDH1, "sdh2_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH2, 0x1b, 0x1b, 0x0, 0, &sdh_lock}, + {MMP2_CLK_SDH1, "sdh3_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH3, 0x1b, 0x1b, 0x0, 0, &sdh_lock}, + {MMP2_CLK_DISP0, "disp0_clk", "disp0_div", CLK_SET_RATE_PARENT, APMU_DISP0, 0x1b, 0x1b, 0x0, 0, &disp0_lock}, + {MMP2_CLK_DISP0_SPHY, "disp0_sphy_clk", "disp0_sphy_div", CLK_SET_RATE_PARENT, APMU_DISP0, 0x1024, 0x1024, 0x0, 0, &disp0_lock}, + {MMP2_CLK_DISP1, "disp1_clk", "disp1_div", CLK_SET_RATE_PARENT, APMU_DISP1, 0x1b, 0x1b, 0x0, 0, &disp1_lock}, + {MMP2_CLK_CCIC_ARBITER, "ccic_arbiter", "vctcxo", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x1800, 0x1800, 0x0, 0, &ccic0_lock}, + {MMP2_CLK_CCIC0, "ccic0_clk", "ccic0_mix_clk", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x1b, 0x1b, 0x0, 0, &ccic0_lock}, + {MMP2_CLK_CCIC0_PHY, "ccic0_phy_clk", "ccic0_mix_clk", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x24, 0x24, 0x0, 0, &ccic0_lock}, + {MMP2_CLK_CCIC0_SPHY, "ccic0_sphy_clk", "ccic0_sphy_div", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x300, 0x300, 0x0, 0, &ccic0_lock}, + {MMP2_CLK_CCIC1, "ccic1_clk", "ccic1_mix_clk", CLK_SET_RATE_PARENT, APMU_CCIC1, 0x1b, 0x1b, 0x0, 0, &ccic1_lock}, + {MMP2_CLK_CCIC1_PHY, "ccic1_phy_clk", "ccic1_mix_clk", CLK_SET_RATE_PARENT, APMU_CCIC1, 0x24, 0x24, 0x0, 0, &ccic1_lock}, + {MMP2_CLK_CCIC1_SPHY, "ccic1_sphy_clk", "ccic1_sphy_div", CLK_SET_RATE_PARENT, APMU_CCIC1, 0x300, 0x300, 0x0, 0, &ccic1_lock}, +}; + +static void mmp2_axi_periph_clk_init(struct mmp2_clk_unit *pxa_unit) +{ + struct clk *clk; + struct mmp_clk_unit *unit = &pxa_unit->unit; + + sdh_mix_config.reg_info.reg_clk_ctrl = pxa_unit->apmu_base + APMU_SDH0; + clk = mmp_clk_register_mix(NULL, "sdh_mix_clk", sdh_parent_names, + ARRAY_SIZE(sdh_parent_names), + CLK_SET_RATE_PARENT, + &sdh_mix_config, &sdh_lock); + + ccic0_mix_config.reg_info.reg_clk_ctrl = pxa_unit->apmu_base + APMU_CCIC0; + clk = mmp_clk_register_mix(NULL, "ccic0_mix_clk", ccic_parent_names, + ARRAY_SIZE(ccic_parent_names), + CLK_SET_RATE_PARENT, + &ccic0_mix_config, &ccic0_lock); + mmp_clk_add(unit, MMP2_CLK_CCIC0_MIX, clk); + + ccic1_mix_config.reg_info.reg_clk_ctrl = pxa_unit->apmu_base + APMU_CCIC1; + clk = mmp_clk_register_mix(NULL, "ccic1_mix_clk", ccic_parent_names, + ARRAY_SIZE(ccic_parent_names), + CLK_SET_RATE_PARENT, + &ccic1_mix_config, &ccic1_lock); + mmp_clk_add(unit, MMP2_CLK_CCIC1_MIX, clk); + + mmp_register_mux_clks(unit, apmu_mux_clks, pxa_unit->apmu_base, + ARRAY_SIZE(apmu_mux_clks)); + + mmp_register_div_clks(unit, apmu_div_clks, pxa_unit->apmu_base, + ARRAY_SIZE(apmu_div_clks)); + + mmp_register_gate_clks(unit, apmu_gate_clks, pxa_unit->apmu_base, + ARRAY_SIZE(apmu_gate_clks)); +} + +static void mmp2_clk_reset_init(struct device_node *np, + struct mmp2_clk_unit *pxa_unit) +{ + struct mmp_clk_reset_cell *cells; + int i, nr_resets; + + nr_resets = ARRAY_SIZE(apbc_gate_clks); + cells = kcalloc(nr_resets, sizeof(*cells), GFP_KERNEL); + if (!cells) + return; + + for (i = 0; i < nr_resets; i++) { + cells[i].clk_id = apbc_gate_clks[i].id; + cells[i].reg = pxa_unit->apbc_base + apbc_gate_clks[i].offset; + cells[i].flags = 0; + cells[i].lock = apbc_gate_clks[i].lock; + cells[i].bits = 0x4; + } + + mmp_clk_reset_register(np, cells, nr_resets); +} + +static void __init mmp2_clk_init(struct device_node *np) +{ + struct mmp2_clk_unit *pxa_unit; + + pxa_unit = kzalloc(sizeof(*pxa_unit), GFP_KERNEL); + if (!pxa_unit) + return; + + pxa_unit->mpmu_base = of_iomap(np, 0); + if (!pxa_unit->mpmu_base) { + pr_err("failed to map mpmu registers\n"); + return; + } + + pxa_unit->apmu_base = of_iomap(np, 1); + if (!pxa_unit->mpmu_base) { + pr_err("failed to map apmu registers\n"); + return; + } + + pxa_unit->apbc_base = of_iomap(np, 2); + if (!pxa_unit->apbc_base) { + pr_err("failed to map apbc registers\n"); + return; + } + + mmp_clk_init(np, &pxa_unit->unit, MMP2_NR_CLKS); + + mmp2_pll_init(pxa_unit); + + mmp2_apb_periph_clk_init(pxa_unit); + + mmp2_axi_periph_clk_init(pxa_unit); + + mmp2_clk_reset_init(np, pxa_unit); +} + +CLK_OF_DECLARE(mmp2_clk, "marvell,mmp2-clock", mmp2_clk_init); diff --git a/include/dt-bindings/clock/marvell,mmp2.h b/include/dt-bindings/clock/marvell,mmp2.h new file mode 100644 index 000000000000..591f7fba89e2 --- /dev/null +++ b/include/dt-bindings/clock/marvell,mmp2.h @@ -0,0 +1,74 @@ +#ifndef __DTS_MARVELL_MMP2_CLOCK_H +#define __DTS_MARVELL_MMP2_CLOCK_H + +/* fixed clocks and plls */ +#define MMP2_CLK_CLK32 1 +#define MMP2_CLK_VCTCXO 2 +#define MMP2_CLK_PLL1 3 +#define MMP2_CLK_PLL1_2 8 +#define MMP2_CLK_PLL1_4 9 +#define MMP2_CLK_PLL1_8 10 +#define MMP2_CLK_PLL1_16 11 +#define MMP2_CLK_PLL1_3 12 +#define MMP2_CLK_PLL1_6 13 +#define MMP2_CLK_PLL1_12 14 +#define MMP2_CLK_PLL1_20 15 +#define MMP2_CLK_PLL2 16 +#define MMP2_CLK_PLL2_2 17 +#define MMP2_CLK_PLL2_4 18 +#define MMP2_CLK_PLL2_8 19 +#define MMP2_CLK_PLL2_16 20 +#define MMP2_CLK_PLL2_3 21 +#define MMP2_CLK_PLL2_6 22 +#define MMP2_CLK_PLL2_12 23 +#define MMP2_CLK_VCTCXO_2 24 +#define MMP2_CLK_VCTCXO_4 25 +#define MMP2_CLK_UART_PLL 26 +#define MMP2_CLK_USB_PLL 27 + +/* apb periphrals */ +#define MMP2_CLK_TWSI0 60 +#define MMP2_CLK_TWSI1 61 +#define MMP2_CLK_TWSI2 62 +#define MMP2_CLK_TWSI3 63 +#define MMP2_CLK_TWSI4 64 +#define MMP2_CLK_TWSI5 65 +#define MMP2_CLK_GPIO 66 +#define MMP2_CLK_KPC 67 +#define MMP2_CLK_RTC 68 +#define MMP2_CLK_PWM0 69 +#define MMP2_CLK_PWM1 70 +#define MMP2_CLK_PWM2 71 +#define MMP2_CLK_PWM3 72 +#define MMP2_CLK_UART0 73 +#define MMP2_CLK_UART1 74 +#define MMP2_CLK_UART2 75 +#define MMP2_CLK_UART3 76 +#define MMP2_CLK_SSP0 77 +#define MMP2_CLK_SSP1 78 +#define MMP2_CLK_SSP2 79 +#define MMP2_CLK_SSP3 80 + +/* axi periphrals */ +#define MMP2_CLK_SDH0 101 +#define MMP2_CLK_SDH1 102 +#define MMP2_CLK_SDH2 103 +#define MMP2_CLK_SDH3 104 +#define MMP2_CLK_USB 105 +#define MMP2_CLK_DISP0 106 +#define MMP2_CLK_DISP0_MUX 107 +#define MMP2_CLK_DISP0_SPHY 108 +#define MMP2_CLK_DISP1 109 +#define MMP2_CLK_DISP1_MUX 110 +#define MMP2_CLK_CCIC_ARBITER 111 +#define MMP2_CLK_CCIC0 112 +#define MMP2_CLK_CCIC0_MIX 113 +#define MMP2_CLK_CCIC0_PHY 114 +#define MMP2_CLK_CCIC0_SPHY 115 +#define MMP2_CLK_CCIC1 116 +#define MMP2_CLK_CCIC1_MIX 117 +#define MMP2_CLK_CCIC1_PHY 118 +#define MMP2_CLK_CCIC1_SPHY 119 + +#define MMP2_NR_CLKS 200 +#endif -- cgit v1.2.3-59-g8ed1b From 31ceb157f294843563330658c3ad6e3b5a1c4fe2 Mon Sep 17 00:00:00 2001 From: Emil Medve Date: Wed, 5 Nov 2014 09:18:51 -0600 Subject: dt/bindings: Introduce the FSL QorIQ DPAA BMan The Buffer Manager is part of the Data-Path Acceleration Architecture (DPAA). BMan supports hardware allocation and deallocation of buffers belonging to pools originally created by software with configurable depletion thresholds. This binding covers the CCSR space programming model Signed-off-by: Emil Medve Change-Id: I3ec479bfb3c91951e96902f091f5d7d2adbef3b2 Signed-off-by: Scott Wood --- Documentation/devicetree/bindings/soc/fsl/bman.txt | 125 +++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 Documentation/devicetree/bindings/soc/fsl/bman.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/soc/fsl/bman.txt b/Documentation/devicetree/bindings/soc/fsl/bman.txt new file mode 100644 index 000000000000..9f80bf8709ac --- /dev/null +++ b/Documentation/devicetree/bindings/soc/fsl/bman.txt @@ -0,0 +1,125 @@ +QorIQ DPAA Buffer Manager Device Tree Bindings + +Copyright (C) 2008 - 2014 Freescale Semiconductor Inc. + +CONTENTS + + - BMan Node + - BMan Private Memory Node + - Example + +BMan Node + +The Buffer Manager is part of the Data-Path Acceleration Architecture (DPAA). +BMan supports hardware allocation and deallocation of buffers belonging to pools +originally created by software with configurable depletion thresholds. This +binding covers the CCSR space programming model + +PROPERTIES + +- compatible + Usage: Required + Value type: + Definition: Must include "fsl,bman" + May include "fsl,-bman" + +- reg + Usage: Required + Value type: + Definition: Registers region within the CCSR address space + +The BMan revision information is located in the BMAN_IP_REV_1/2 registers which +are located at offsets 0xbf8 and 0xbfc + +- interrupts + Usage: Required + Value type: + Definition: Standard property. The error interrupt + +- fsl,liodn + Usage: See pamu.txt + Value type: + Definition: PAMU property used for static LIODN assignment + +- fsl,iommu-parent + Usage: See pamu.txt + Value type: + Definition: PAMU property used for dynamic LIODN assignment + + For additional details about the PAMU/LIODN binding(s) see pamu.txt + +Devices connected to a BMan instance via Direct Connect Portals (DCP) must link +to the respective BMan instance + +- fsl,bman + Usage: Required + Value type: + Description: List of phandle and DCP index pairs, to the BMan instance + to which this device is connected via the DCP + +BMan Private Memory Node + +BMan requires a contiguous range of physical memory used for the backing store +for BMan Free Buffer Proxy Records (FBPR). This memory is reserved/allocated as a +node under the /reserved-memory node + +The BMan FBPR memory node must be named "bman-fbpr" + +PROPERTIES + +- compatible + Usage: required + Value type: + Definition: Must inclide "fsl,bman-fbpr" + +The following constraints are relevant to the FBPR private memory: + - The size must be 2^(size + 1), with size = 11..33. That is 4 KiB to + 16 GiB + - The alignment must be a muliptle of the memory size + +The size of the FBPR must be chosen by observing the hardware features configured +via the Reset Configuration Word (RCW) and that are relevant to a specific board +(e.g. number of MAC(s) pinned-out, number of offline/host command FMan ports, +etc.). The size configured in the DT must reflect the hardware capabilities and +not the specific needs of an application + +For additional details about reserved memory regions see reserved-memory.txt + +EXAMPLE + +The example below shows a BMan FBPR dynamic allocation memory node + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + bman_fbpr: bman-fbpr { + compatible = "fsl,bman-fbpr"; + alloc-ranges = <0 0 0xf 0xffffffff>; + size = <0 0x1000000>; + alignment = <0 0x1000000>; + }; + }; + +The example below shows a (P4080) BMan CCSR-space node + + crypto@300000 { + ... + fsl,bman = <&bman, 2>; + ... + }; + + bman: bman@31a000 { + compatible = "fsl,bman"; + reg = <0x31a000 0x1000>; + interrupts = <16 2 1 2>; + fsl,liodn = <0x17>; + memory-region = <&bman_fbpr>; + }; + + fman@400000 { + ... + fsl,bman = <&bman, 0>; + ... + }; -- cgit v1.2.3-59-g8ed1b From 5f3af4008bfcb388a3193fd871e1b2e94ba4b09c Mon Sep 17 00:00:00 2001 From: Emil Medve Date: Wed, 5 Nov 2014 09:18:52 -0600 Subject: dt/bindings: Introduce the FSL QorIQ DPAA BMan portal(s) Portals are memory mapped interfaces to BMan that allow low-latency, lock-less interaction by software running on processor cores, accelerators and network interfaces with the BMan Signed-off-by: Emil Medve Change-Id: I6d245ffc14ba3d0e91d403ac7c3b91b75a9e6a95 Signed-off-by: Scott Wood --- .../devicetree/bindings/soc/fsl/bman-portals.txt | 56 ++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 Documentation/devicetree/bindings/soc/fsl/bman-portals.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/soc/fsl/bman-portals.txt b/Documentation/devicetree/bindings/soc/fsl/bman-portals.txt new file mode 100644 index 000000000000..2a00e14e11e0 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/fsl/bman-portals.txt @@ -0,0 +1,56 @@ +QorIQ DPAA Buffer Manager Portals Device Tree Binding + +Copyright (C) 2008 - 2014 Freescale Semiconductor Inc. + +CONTENTS + + - BMan Portal + - Example + +BMan Portal Node + +Portals are memory mapped interfaces to BMan that allow low-latency, lock-less +interaction by software running on processor cores, accelerators and network +interfaces with the BMan + +PROPERTIES + +- compatible + Usage: Required + Value type: + Definition: Must include "fsl,bman-portal-" + May include "fsl,-bman-portal" or "fsl,bman-portal" + +- reg + Usage: Required + Value type: + Definition: Two regions. The first is the cache-enabled region of + the portal. The second is the cache-inhibited region of + the portal + +- interrupts + Usage: Required + Value type: + Definition: Standard property + +EXAMPLE + +The example below shows a (P4080) BMan portals container/bus node with two portals + + bman-portals@ff4000000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + ranges = <0 0xf 0xf4000000 0x200000>; + + bman-portal@0 { + compatible = "fsl,bman-portal-1.0.0", "fsl,bman-portal"; + reg = <0x0 0x4000>, <0x100000 0x1000>; + interrupts = <105 2 0 0>; + }; + bman-portal@4000 { + compatible = "fsl,bman-portal-1.0.0", "fsl,bman-portal"; + reg = <0x4000 0x4000>, <0x101000 0x1000>; + interrupts = <107 2 0 0>; + }; + }; -- cgit v1.2.3-59-g8ed1b From 76a4f03f3ec7221112c20d053a1233540a601473 Mon Sep 17 00:00:00 2001 From: Emil Medve Date: Wed, 5 Nov 2014 09:18:53 -0600 Subject: dt/bindings: Introduce the FSL QorIQ DPAA QMan The Queue Manager is part of the Data-Path Acceleration Architecture (DPAA). QMan supports queuing and QoS scheduling of frames to CPUs, network interfaces and DPAA logic modules, maintains packet ordering within flows. Besides providing flow-level queuing, is also responsible for congestion management functions such as RED/WRED, congestion notifications and tail discards. This binding covers the CCSR space programming model Signed-off-by: Emil Medve Change-Id: I3acb223893e42003d6c9dc061db568ec0b10d29b Signed-off-by: Scott Wood --- Documentation/devicetree/bindings/soc/fsl/qman.txt | 165 +++++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 Documentation/devicetree/bindings/soc/fsl/qman.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/soc/fsl/qman.txt b/Documentation/devicetree/bindings/soc/fsl/qman.txt new file mode 100644 index 000000000000..063e3a0b9d04 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/fsl/qman.txt @@ -0,0 +1,165 @@ +QorIQ DPAA Queue Manager Device Tree Binding + +Copyright (C) 2008 - 2014 Freescale Semiconductor Inc. + +CONTENTS + + - QMan Node + - QMan Private Memory Nodes + - Example + +QMan Node + +The Queue Manager is part of the Data-Path Acceleration Architecture (DPAA). QMan +supports queuing and QoS scheduling of frames to CPUs, network interfaces and +DPAA logic modules, maintains packet ordering within flows. Besides providing +flow-level queuing, is also responsible for congestion management functions such +as RED/WRED, congestion notifications and tail discards. This binding covers the +CCSR space programming model + +PROPERTIES + +- compatible + Usage: Required + Value type: + Definition: Must include "fsl,qman" + May include "fsl,-qman" + +- reg + Usage: Required + Value type: + Definition: Registers region within the CCSR address space + +The QMan revision information is located in the QMAN_IP_REV_1/2 registers which +are located at offsets 0xbf8 and 0xbfc + +- interrupts + Usage: Required + Value type: + Definition: Standard property. The error interrupt + +- fsl,liodn + Usage: See pamu.txt + Value type: + Definition: PAMU property used for static LIODN assignment + +- fsl,iommu-parent + Usage: See pamu.txt + Value type: + Definition: PAMU property used for dynamic LIODN assignment + + For additional details about the PAMU/LIODN binding(s) see pamu.txt + +- clocks + Usage: See clock-bindings.txt and qoriq-clock.txt + Value type: + Definition: Reference input clock. Its frequency is half of the + platform clock + +Devices connected to a QMan instance via Direct Connect Portals (DCP) must link +to the respective QMan instance + +- fsl,qman + Usage: Required + Value type: + Description: List of phandle and DCP index pairs, to the QMan instance + to which this device is connected via the DCP + +QMan Private Memory Nodes + +QMan requires two contiguous range of physical memory used for the backing store +for QMan Frame Queue Descriptor (FQD) and Packed Frame Descriptor Record (PFDR). +This memory is reserved/allocated as a nodes under the /reserved-memory node + +The QMan FQD memory node must be named "qman-fqd" + +PROPERTIES + +- compatible + Usage: required + Value type: + Definition: Must inclide "fsl,qman-fqd" + +The QMan PFDR memory node must be named "qman-pfdr" + +PROPERTIES + +- compatible + Usage: required + Value type: + Definition: Must inclide "fsl,qman-pfdr" + +The following constraints are relevant to the FQD and PFDR private memory: + - The size must be 2^(size + 1), with size = 11..29. That is 4 KiB to + 1 GiB + - The alignment must be a muliptle of the memory size + +The size of the FQD and PFDP must be chosen by observing the hardware features +configured via the Reset Configuration Word (RCW) and that are relevant to a +specific board (e.g. number of MAC(s) pinned-out, number of offline/host command +FMan ports, etc.). The size configured in the DT must reflect the hardware +capabilities and not the specific needs of an application + +For additional details about reserved memory regions see reserved-memory.txt + +EXAMPLE + +The example below shows a QMan FQD and a PFDR dynamic allocation memory nodes + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + qman_fqd: qman-fqd { + compatible = "fsl,qman-fqd"; + alloc-ranges = <0 0 0xf 0xffffffff>; + size = <0 0x400000>; + alignment = <0 0x400000>; + }; + qman_pfdr: qman-pfdr { + compatible = "fsl,qman-pfdr"; + alloc-ranges = <0 0 0xf 0xffffffff>; + size = <0 0x2000000>; + alignment = <0 0x2000000>; + }; + }; + +The example below shows a (P4080) QMan CCSR-space node + + clockgen: global-utilities@e1000 { + ... + sysclk: sysclk { + ... + }; + ... + platform_pll: platform-pll@c00 { + #clock-cells = <1>; + reg = <0xc00 0x4>; + compatible = "fsl,qoriq-platform-pll-1.0"; + clocks = <&sysclk>; + clock-output-names = "platform-pll", "platform-pll-div2"; + }; + ... + }; + + crypto@300000 { + ... + fsl,qman = <&qman, 2>; + ... + }; + + qman: qman@318000 { + compatible = "fsl,qman"; + reg = <0x318000 0x1000>; + interrupts = <16 2 1 3> + fsl,liodn = <0x16>; + memory-region = <&qman_fqd &qman_pfdr>; + clocks = <&platform_pll 1>; + }; + + fman@400000 { + ... + fsl,qman = <&qman, 0>; + ... + }; -- cgit v1.2.3-59-g8ed1b From f3f6743d1b719ba53aa69493bf76b76a8871bbfa Mon Sep 17 00:00:00 2001 From: Emil Medve Date: Wed, 5 Nov 2014 09:18:54 -0600 Subject: dt/bindings: Introduce the FSL QorIQ DPAA QMan portal(s) Portals are memory mapped interfaces to QMan that allow low-latency, lock-less interaction by software running on processor cores, accelerators and network interfaces with the QMan Signed-off-by: Emil Medve Change-Id: I29764fa8093b5ce65460abc879446795c50d7185 Signed-off-by: Scott Wood --- .../devicetree/bindings/soc/fsl/qman-portals.txt | 154 +++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 Documentation/devicetree/bindings/soc/fsl/qman-portals.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/soc/fsl/qman-portals.txt b/Documentation/devicetree/bindings/soc/fsl/qman-portals.txt new file mode 100644 index 000000000000..48c4dae5d6f9 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/fsl/qman-portals.txt @@ -0,0 +1,154 @@ +QorIQ DPAA Queue Manager Portals Device Tree Binding + +Copyright (C) 2008 - 2014 Freescale Semiconductor Inc. + +CONTENTS + + - QMan Portal + - QMan Pool Channel + - Example + +QMan Portal Node + +Portals are memory mapped interfaces to QMan that allow low-latency, lock-less +interaction by software running on processor cores, accelerators and network +interfaces with the QMan + +PROPERTIES + +- compatible + Usage: Required + Value type: + Definition: Must include "fsl,qman-portal-" + May include "fsl,-qman-portal" or "fsl,qman-portal" + +- reg + Usage: Required + Value type: + Definition: Two regions. The first is the cache-enabled region of + the portal. The second is the cache-inhibited region of + the portal + +- interrupts + Usage: Required + Value type: + Definition: Standard property + +- fsl,liodn + Usage: See pamu.txt + Value type: + Definition: Two LIODN(s). DQRR LIODN (DLIODN) and Frame LIODN + (FLIODN) + +- fsl,iommu-parent + Usage: See pamu.txt + Value type: + Definition: PAMU property used for dynamic LIODN assignment + + For additional details about the PAMU/LIODN binding(s) see pamu.txt + +- fsl,qman-channel-id + Usage: Required + Value type: + Definition: The hardware index of the channel. This can also be + determined by dividing any of the channel's 8 work queue + IDs by 8 + +In addition to these properties the qman-portals should have sub-nodes to +represent the HW devices/portals that are connected to the software portal +described here + +The currently supported sub-nodes are: + * fman0 + * fman1 + * pme + * crypto + +These subnodes should have the following properties: + +- fsl,liodn + Usage: See pamu.txt + Value type: + Definition: PAMU property used for static LIODN assignment + +- fsl,iommu-parent + Usage: See pamu.txt + Value type: + Definition: PAMU property used for dynamic LIODN assignment + +- dev-handle + Usage: Required + Value type: + Definition: The phandle to the particular hardware device that this + portal is connected to. + +DPAA QMan Pool Channel Nodes + +Pool Channels are defined with the following properties. + +PROPERTIES + +- compatible + Usage: Required + Value type: + Definition: Must include "fsl,qman-pool-channel" + May include "fsl,-qman-pool-channel" + +- fsl,qman-channel-id + Usage: Required + Value type: + Definition: The hardware index of the channel. This can also be + determined by dividing any of the channel's 8 work queue + IDs by 8 + +EXAMPLE + +The example below shows a (P4080) QMan portals container/bus node with two portals + + qman-portals@ff4200000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + ranges = <0 0xf 0xf4200000 0x200000>; + + qman-portal@0 { + compatible = "fsl,qman-portal-1.2.0", "fsl,qman-portal"; + reg = <0 0x4000>, <0x100000 0x1000>; + interrupts = <104 2 0 0>; + fsl,liodn = <1 2>; + fsl,qman-channel-id = <0>; + + fman0 { + fsl,liodn = <0x21>; + dev-handle = <&fman0>; + }; + fman1 { + fsl,liodn = <0xa1>; + dev-handle = <&fman1>; + }; + crypto { + fsl,liodn = <0x41 0x66>; + dev-handle = <&crypto>; + }; + }; + qman-portal@4000 { + compatible = "fsl,qman-portal-1.2.0", "fsl,qman-portal"; + reg = <0x4000 0x4000>, <0x101000 0x1000>; + interrupts = <106 2 0 0>; + fsl,liodn = <3 4>; + fsl,qman-channel-id = <1>; + + fman0 { + fsl,liodn = <0x22>; + dev-handle = <&fman0>; + }; + fman1 { + fsl,liodn = <0xa2>; + dev-handle = <&fman1>; + }; + crypto { + fsl,liodn = <0x42 0x67>; + dev-handle = <&crypto>; + }; + }; + }; -- cgit v1.2.3-59-g8ed1b From 297d35fd2a7d3fbd4e5c0f0c1c18213117ba11ba Mon Sep 17 00:00:00 2001 From: Igal Liberman Date: Wed, 17 Sep 2014 14:08:30 +0300 Subject: powerpc/fsl: Frame Manager Device Tree binding document The Frame Manager (FMan) combines the Ethernet network interfaces with packet distribution logic to provide intelligent distribution and queuing decisions for incoming traffic at line rate. This binding document describes Freescale's Frame Manager hardware attributes that are used by the Frame Manager driver for its basic initialization and configuration. Signed-off-by: Igal Liberman Signed-off-by: Scott Wood --- .../devicetree/bindings/powerpc/fsl/fman.txt | 529 +++++++++++++++++++++ 1 file changed, 529 insertions(+) create mode 100644 Documentation/devicetree/bindings/powerpc/fsl/fman.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/powerpc/fsl/fman.txt b/Documentation/devicetree/bindings/powerpc/fsl/fman.txt new file mode 100644 index 000000000000..da8e5f25768f --- /dev/null +++ b/Documentation/devicetree/bindings/powerpc/fsl/fman.txt @@ -0,0 +1,529 @@ +============================================================================= +Freescale Frame Manager Device Bindings + +CONTENTS + - FMan Node + - FMan Port Node + - FMan MURAM Node + - FMan dTSEC/XGEC/mEMAC Node + - FMan IEEE 1588 Node + - Example + +============================================================================= +FMan Node + +DESCRIPTION + +Due to the fact that the FMan is an aggregation of sub-engines (ports, MACs, +etc.) the FMan node will have child nodes for each of them. + +PROPERTIES + +- compatible + Usage: required + Value type: + Definition: Must include "fsl,fman" + FMan version can be determined via FM_IP_REV_1 register in the + FMan block. The offset is 0xc4 from the beginning of the + Frame Processing Manager memory map (0xc3000 from the + beginning of the FMan node). + +- cell-index + Usage: required + Value type: + Definition: Specifies the index of the FMan unit. + + The cell-index value may be used by the SoC, to identify the + FMan unit in the SoC memory map. In the table bellow, + there's a description of the cell-index use in each SoC: + + - P1023: + register[bit] FMan unit cell-index + ============================================================ + DEVDISR[1] 1 0 + + - P2041, P3041, P4080 P5020, P5040: + register[bit] FMan unit cell-index + ============================================================ + DCFG_DEVDISR2[6] 1 0 + DCFG_DEVDISR2[14] 2 1 + (Second FM available only in P4080 and P5040) + + - B4860, T1040, T2080, T4240: + register[bit] FMan unit cell-index + ============================================================ + DCFG_CCSR_DEVDISR2[24] 1 0 + DCFG_CCSR_DEVDISR2[25] 2 1 + (Second FM available only in T4240) + + DEVDISR, DCFG_DEVDISR2 and DCFG_CCSR_DEVDISR2 are located in + the specific SoC "Device Configuration/Pin Control" Memory + Map. + +- reg + Usage: required + Value type: + Definition: A standard property. Specifies the offset of the + following configuration registers: + - BMI configuration registers. + - QMI configuration registers. + - DMA configuration registers. + - FPM configuration registers. + - FMan controller configuration registers. + +- ranges + Usage: required + Value type: + Definition: A standard property. + +- clocks + Usage: required + Value type: + Definition: phandle for fman clock. + +- clock-names + usage: optional + Value type: + Definition: A standard property + +- interrupts + Usage: required + Value type: + Definition: A pair of IRQs are specified in this property. + The first element is associated with the event interrupts and + the second element is associated with the error interrupts. + +- fsl,qman-channel-range + Usage: required + Value type: + Definition: Specifies the range of the available dedicated + channels in the FMan. The first cell specifies the beginning + of the range and the second cell specifies the number of + channels. + Further information available at: + "Work Queue (WQ) Channel Assignments in the QMan" section + in DPAA Reference Manual. + +============================================================================= +FMan MURAM Node + +DESCRIPTION + +FMan Internal memory - shared between all the FMan modules. +It contains data structures that are common and written to or read by +the modules. +FMan internal memory is split into the following parts: + Packet buffering (Tx/Rx FIFOs) + Frames internal context + +PROPERTIES + +- compatible + Usage: required + Value type: + Definition: Must include "fsl,fman-muram" + +- ranges + Usage: required + Value type: + Definition: A standard property. + Specifies the multi-user memory offset and the size within + the FMan. + +EXAMPLE + +muram@0 { + compatible = "fsl,fman-muram"; + ranges = <0 0x000000 0x28000>; +}; + +============================================================================= +FMan Port Node + +DESCRIPTION + +The Frame Manager (FMan) supports several types of hardware ports: + Ethernet receiver (RX) + Ethernet transmitter (TX) + Offline/Host command (O/H) + +PROPERTIES + +- compatible + Usage: required + Value type: + Definition: A standard property. + Must include one of the following: + - "fsl,fman-v2-port-oh" for FManV2 OH ports + - "fsl,fman-v2-port-rx" for FManV2 RX ports + - "fsl,fman-v2-port-tx" for FManV2 TX ports + - "fsl,fman-v3-port-oh" for FManV3 OH ports + - "fsl,fman-v3-port-rx" for FManV3 RX ports + - "fsl,fman-v3-port-tx" for FManV3 TX ports + +- cell-index + Usage: required + Value type: + Definition: Specifies the hardware port id. + Each hardware port on the FMan has its own hardware PortID. + Super set of all hardware Port IDs available at FMan Reference + Manual under "FMan Hardware Ports in Freescale Devices" table. + + Each hardware port is assigned a 4KB, port-specific page in + the FMan hardware port memory region (which is part of the + FMan memory map). The first 4 KB in the FMan hardware ports + memory region is used for what are called common registers. + The subsequent 63 4KB pages are allocated to the hardware + ports. + The page of a specific port is determined by the cell-index. + +- reg + Usage: required + Value type: + Definition: There is one reg region describing the port + configuration registers. + +EXAMPLE + +port@a8000 { + cell-index = <0x28>; + compatible = "fsl,fman-v2-port-tx"; + reg = <0xa8000 0x1000>; +}; + +port@88000 { + cell-index = <0x8>; + compatible = "fsl,fman-v2-port-rx"; + reg = <0x88000 0x1000>; +}; + +port@81000 { + cell-index = <0x1>; + compatible = "fsl,fman-v2-port-oh"; + reg = <0x81000 0x1000>; +}; + +============================================================================= +FMan dTSEC/XGEC/mEMAC Node + +DESCRIPTION + +mEMAC/dTSEC/XGEC are the Ethernet network interfaces + +PROPERTIES + +- compatible + Usage: required + Value type: + Definition: A standard property. + Must include one of the following: + - "fsl,fman-dtsec" for dTSEC MAC + - "fsl,fman-xgec" for XGEC MAC + - "fsl,fman-memac for mEMAC MAC + +- cell-index + Usage: required + Value type: + Definition: Specifies the MAC id. + + The cell-index value may be used by the FMan or the SoC, to + identify the MAC unit in the FMan (or SoC) memory map. + In the tables bellow there's a description of the cell-index + use, there are two tables, one describes the use of cell-index + by the FMan, the second describes the use by the SoC: + + 1. FMan Registers + + FManV2: + register[bit] MAC cell-index + ============================================================ + FM_EPI[16] XGEC 8 + FM_EPI[16+n] dTSECn n-1 + FM_NPI[11+n] dTSECn n-1 + n = 1,..,5 + + FManV3: + register[bit] MAC cell-index + ============================================================ + FM_EPI[16+n] mEMACn n-1 + FM_EPI[25] mEMAC10 9 + + FM_NPI[11+n] mEMACn n-1 + FM_NPI[10] mEMAC10 9 + FM_NPI[11] mEMAC9 8 + n = 1,..8 + + FM_EPI and FM_NPI are located in the FMan memory map. + + 2. SoC registers: + + - P2041, P3041, P4080 P5020, P5040: + register[bit] FMan MAC cell + Unit index + ============================================================ + DCFG_DEVDISR2[7] 1 XGEC 8 + DCFG_DEVDISR2[7+n] 1 dTSECn n-1 + DCFG_DEVDISR2[15] 2 XGEC 8 + DCFG_DEVDISR2[15+n] 2 dTSECn n-1 + n = 1,..5 + + - T1040, T2080, T4240, B4860: + register[bit] FMan MAC cell + Unit index + ============================================================ + DCFG_CCSR_DEVDISR2[n-1] 1 mEMACn n-1 + DCFG_CCSR_DEVDISR2[11+n] 2 mEMACn n-1 + n = 1,..6,9,10 + + EVDISR, DCFG_DEVDISR2 and DCFG_CCSR_DEVDISR2 are located in + the specific SoC "Device Configuration/Pin Control" Memory + Map. + +- reg + Usage: required + Value type: + Definition: A standard property. + +- fsl,fman-ports + Usage: required + Value type: + Definition: An array of two phandles - the first references is + the FMan RX port and the second is the TX port used by this + MAC. + +- ptp-timer + Usage required + Value type: + Definition: A phandle for 1EEE1588 timer. + +EXAMPLE + +fman1_tx28: port@a8000 { + cell-index = <0x28>; + compatible = "fsl,fman-v2-port-tx"; + reg = <0xa8000 0x1000>; +}; + +fman1_rx8: port@88000 { + cell-index = <0x8>; + compatible = "fsl,fman-v2-port-rx"; + reg = <0x88000 0x1000>; +}; + +ptp-timer: ptp_timer@fe000 { + compatible = "fsl,fman-ptp-timer"; + reg = <0xfe000 0x1000>; +}; + +ethernet@e0000 { + compatible = "fsl,fman-dtsec"; + cell-index = <0>; + reg = <0xe0000 0x1000>; + fsl,fman-ports = <&fman1_rx8 &fman1_tx28>; + ptp-timer = <&ptp-timer>; +}; + +============================================================================ +FMan IEEE 1588 Node + +DESCRIPTION + +The FMan interface to support IEEE 1588 + + +PROPERTIES + +- compatible + Usage: required + Value type: + Definition: A standard property. + Must include "fsl,fman-ptp-timer". + +- reg + Usage: required + Value type: + Definition: A standard property. + +EXAMPLE + +ptp-timer@fe000 { + compatible = "fsl,fman-ptp-timer"; + reg = <0xfe000 0x1000>; +}; + +============================================================================= +Example + +fman@400000 { + #address-cells = <1>; + #size-cells = <1>; + cell-index = <1>; + compatible = "fsl,fman" + ranges = <0 0x400000 0x100000>; + reg = <0x400000 0x100000>; + clocks = <&fman_clk>; + clock-names = "fmanclk"; + interrupts = < + 96 2 0 0 + 16 2 1 1>; + fsl,qman-channel-range = <0x40 0xc>; + + muram@0 { + compatible = "fsl,fman-muram"; + reg = <0x0 0x28000>; + }; + + port@81000 { + cell-index = <1>; + compatible = "fsl,fman-v2-port-oh"; + reg = <0x81000 0x1000>; + }; + + port@82000 { + cell-index = <2>; + compatible = "fsl,fman-v2-port-oh"; + reg = <0x82000 0x1000>; + }; + + port@83000 { + cell-index = <3>; + compatible = "fsl,fman-v2-port-oh"; + reg = <0x83000 0x1000>; + }; + + port@84000 { + cell-index = <4>; + compatible = "fsl,fman-v2-port-oh"; + reg = <0x84000 0x1000>; + }; + + port@85000 { + cell-index = <5>; + compatible = "fsl,fman-v2-port-oh"; + reg = <0x85000 0x1000>; + }; + + port@86000 { + cell-index = <6>; + compatible = "fsl,fman-v2-port-oh"; + reg = <0x86000 0x1000>; + }; + + fman1_rx_0x8: port@88000 { + cell-index = <0x8>; + compatible = "fsl,fman-v2-port-rx"; + reg = <0x88000 0x1000>; + }; + + fman1_rx_0x9: port@89000 { + cell-index = <0x9>; + compatible = "fsl,fman-v2-port-rx"; + reg = <0x89000 0x1000>; + }; + + fman1_rx_0xa: port@8a000 { + cell-index = <0xa>; + compatible = "fsl,fman-v2-port-rx"; + reg = <0x8a000 0x1000>; + }; + + fman1_rx_0xb: port@8b000 { + cell-index = <0xb>; + compatible = "fsl,fman-v2-port-rx"; + reg = <0x8b000 0x1000>; + }; + + fman1_rx_0xc: port@8c000 { + cell-index = <0xc>; + compatible = "fsl,fman-v2-port-rx"; + reg = <0x8c000 0x1000>; + }; + + fman1_rx_0x10: port@90000 { + cell-index = <0x10>; + compatible = "fsl,fman-v2-port-rx"; + reg = <0x90000 0x1000>; + }; + + fman1_tx_0x28: port@a8000 { + cell-index = <0x28>; + compatible = "fsl,fman-v2-port-tx"; + reg = <0xa8000 0x1000>; + }; + + fman1_tx_0x29: port@a9000 { + cell-index = <0x29>; + compatible = "fsl,fman-v2-port-tx"; + reg = <0xa9000 0x1000>; + }; + + fman1_tx_0x2a: port@aa000 { + cell-index = <0x2a>; + compatible = "fsl,fman-v2-port-tx"; + reg = <0xaa000 0x1000>; + }; + + fman1_tx_0x2b: port@ab000 { + cell-index = <0x2b>; + compatible = "fsl,fman-v2-port-tx"; + reg = <0xab000 0x1000>; + }; + + fman1_tx_0x2c: port@ac0000 { + cell-index = <0x2c>; + compatible = "fsl,fman-v2-port-tx"; + reg = <0xac000 0x1000>; + }; + + fman1_tx_0x30: port@b0000 { + cell-index = <0x30>; + compatible = "fsl,fman-v2-port-tx"; + reg = <0xb0000 0x1000>; + }; + + ethernet@e0000 { + compatible = "fsl,fman-dtsec"; + cell-index = <0>; + reg = <0xe0000 0x1000>; + fsl,fman-ports = <&fman1_rx_0x8 &fman1_tx_0x28>; + }; + + ethernet@e2000 { + compatible = "fsl,fman-dtsec"; + cell-index = <1>; + reg = <0xe2000 0x1000>; + fsl,fman-ports = <&fman1_rx_0x9 &fman1_tx_0x29>; + }; + + ethernet@e4000 { + compatible = "fsl,fman-dtsec"; + cell-index = <2>; + reg = <0xe4000 0x1000>; + fsl,fman-ports = <&fman1_rx_0xa &fman1_tx_0x2a>; + }; + + ethernet@e6000 { + compatible = "fsl,fman-dtsec"; + cell-index = <3>; + reg = <0xe6000 0x1000>; + fsl,fman-ports = <&fman1_rx_0xb &fman1_tx_0x2b>; + }; + + ethernet@e8000 { + compatible = "fsl,fman-dtsec"; + cell-index = <4>; + reg = <0xf0000 0x1000>; + fsl,fman-ports = <&fman1_rx_0xc &fman1_tx_0x2c>; + + ethernet@f0000 { + cell-index = <8>; + compatible = "fsl,fman-xgec"; + reg = <0xf0000 0x1000>; + fsl,fman-ports = <&fman1_rx_0x10 &fman1_tx_0x30>; + }; + + ptp-timer@fe000 { + compatible = "fsl,fman-ptp-timer"; + reg = <0xfe000 0x1000>; + }; +}; -- cgit v1.2.3-59-g8ed1b From e327fff47b6778e56f8e1dbd6493c1b0bbad1ae8 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Thu, 6 Nov 2014 20:56:07 -0600 Subject: powerpc/fsl: Update fman dt binding with clock name and qbman link The clock name "fmanclk" was given in the example, but not specified in the binding itself. Made clock-names mandatory as otherwise there's not much point having it. Added a reference to the fsl,qman and fsl,bman properties proposed in http://patchwork.ozlabs.org/patch/407034/ and http://patchwork.ozlabs.org/patch/407035/ Signed-off-by: Scott Wood --- Documentation/devicetree/bindings/powerpc/fsl/fman.txt | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/powerpc/fsl/fman.txt b/Documentation/devicetree/bindings/powerpc/fsl/fman.txt index da8e5f25768f..edeea160ca39 100644 --- a/Documentation/devicetree/bindings/powerpc/fsl/fman.txt +++ b/Documentation/devicetree/bindings/powerpc/fsl/fman.txt @@ -79,12 +79,12 @@ PROPERTIES - clocks Usage: required Value type: - Definition: phandle for fman clock. + Definition: phandle for the fman input clock. - clock-names - usage: optional + usage: required Value type: - Definition: A standard property + Definition: "fmanclk" for the fman input clock. - interrupts Usage: required @@ -104,6 +104,11 @@ PROPERTIES "Work Queue (WQ) Channel Assignments in the QMan" section in DPAA Reference Manual. +- fsl,qman +- fsl,bman + Usage: required + Definition: See soc/fsl/qman.txt and soc/fsl/bman.txt + ============================================================================= FMan MURAM Node -- cgit v1.2.3-59-g8ed1b From ec4637bfff1c7d5f2bc7e51d180dd4aa51883af0 Mon Sep 17 00:00:00 2001 From: Sebastian Hesselbarth Date: Thu, 30 Oct 2014 11:21:26 +0100 Subject: phy: berlin-sata: Document BG2 compatible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Berlin BG2 SATA PHY is slightly different from currently supported BG2Q SATA PHY. Document the new compatible for BG2's PHY. Acked-by: Antoine Ténart Signed-off-by: Sebastian Hesselbarth Signed-off-by: Kishon Vijay Abraham I --- Documentation/devicetree/bindings/phy/berlin-sata-phy.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/phy/berlin-sata-phy.txt b/Documentation/devicetree/bindings/phy/berlin-sata-phy.txt index 88f8c23384c0..c0155f842f62 100644 --- a/Documentation/devicetree/bindings/phy/berlin-sata-phy.txt +++ b/Documentation/devicetree/bindings/phy/berlin-sata-phy.txt @@ -2,7 +2,9 @@ Berlin SATA PHY --------------- Required properties: -- compatible: should be "marvell,berlin2q-sata-phy" +- compatible: should be one of + "marvell,berlin2-sata-phy" + "marvell,berlin2q-sata-phy" - address-cells: should be 1 - size-cells: should be 0 - phy-cells: from the generic PHY bindings, must be 1 -- cgit v1.2.3-59-g8ed1b From 7d12993ed8901038bb46b27194e2ef5726d39f9a Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Wed, 12 Nov 2014 05:24:04 +0100 Subject: crypto: doc - crypto API high level spec The design of the kernel crypto API as well as hints to program with the kernel crypto API are given. The documentation contains: * design aspects of crypto API * develper specific hints * references to the API function description * source code examples CC: Marek Vasut Signed-off-by: Stephan Mueller Signed-off-by: Herbert Xu --- Documentation/DocBook/crypto-API.tmpl | 1253 +++++++++++++++++++++++++++++++++ 1 file changed, 1253 insertions(+) create mode 100644 Documentation/DocBook/crypto-API.tmpl (limited to 'Documentation') diff --git a/Documentation/DocBook/crypto-API.tmpl b/Documentation/DocBook/crypto-API.tmpl new file mode 100644 index 000000000000..c763d30f4893 --- /dev/null +++ b/Documentation/DocBook/crypto-API.tmpl @@ -0,0 +1,1253 @@ + + + + + + Linux Kernel Crypto API + + + + Stephan + Mueller + +
+ smueller@chronox.de +
+
+
+ + Marek + Vasut + +
+ marek@denx.de +
+
+
+
+ + + 2014 + Stephan Mueller + + + + + + This documentation is free software; you can redistribute + it and/or modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later + version. + + + + This program is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, + MA 02111-1307 USA + + + + For more details see the file COPYING in the source + distribution of Linux. + + +
+ + + + + Kernel Crypto API Interface Specification + + Introduction + + + The kernel crypto API offers a rich set of cryptographic ciphers as + well as other data transformation mechanisms and methods to invoke + these. This document contains a description of the API and provides + example code. + + + + To understand and properly use the kernel crypto API a brief + explanation of its structure is given. Based on the architecture, + the API can be separated into different components. Following the + architecture specification, hints to developers of ciphers are + provided. Pointers to the API function call documentation are + given at the end. + + + + The kernel crypto API refers to all algorithms as "transformations". + Therefore, a cipher handle variable usually has the name "tfm". + Besides cryptographic operations, the kernel crypto API also knows + compression transformations and handles them the same way as ciphers. + + + + The kernel crypto API serves the following entity types: + + + + consumers requesting cryptographic services + + + data transformation implementations (typically ciphers) + that can be called by consumers using the kernel crypto + API + + + + + + This specification is intended for consumers of the kernel crypto + API as well as for developers implementing ciphers. This API + specification, however, does not discusses all API calls available + to data transformation implementations (i.e. implementations of + ciphers and other transformations (such as CRC or even compression + algorithms) that can register with the kernel crypto API). + + + + Note: The terms "transformation" and cipher algorithm are used + interchangably. + + + + Terminology + + The transformation implementation is an actual code or interface + to hardware which implements a certain transformation with precisely + defined behavior. + + + + The transformation object (TFM) is an instance of a transformation + implementation. There can be multiple transformation objects + associated with a single transformation implementation. Each of + those transformation objects is held by a crypto API consumer or + another transformation. Transformation object is allocated when a + crypto API consumer requests a transformation implementation. + The consumer is then provided with a structure, which contains + a transformation object (TFM). + + + + The structure that contains transformation objects may also be + referred to as a "cipher handle". Such a cipher handle is always + subject to the following phases that are reflected in the API calls + applicable to such a cipher handle: + + + + + Initialization of a cipher handle. + + + Execution of all intended cipher operations applicable + for the handle where the cipher handle must be furnished to + every API call. + + + Destruction of a cipher handle. + + + + + When using the initialization API calls, a cipher handle is + created and returned to the consumer. Therefore, please refer + to all initialization API calls that refer to the data + structure type a consumer is expected to receive and subsequently + to use. The initialization API calls have all the same naming + conventions of crypto_alloc_*. + + + + The transformation context is private data associated with + the transformation object. + + + + + Kernel Crypto API Architecture + Cipher algorithm types + + The kernel crypto API provides different API calls for the + following cipher types: + + + Symmetric ciphers + AEAD ciphers + Message digest, including keyed message digest + Random number generation + User space interface + + + + + Ciphers And Templates + + The kernel crypto API provides implementations of single block + ciphers and message digests. In addition, the kernel crypto API + provides numerous "templates" that can be used in conjunction + with the single block ciphers and message digests. Templates + include all types of block chaining mode, the HMAC mechanism, etc. + + + + Single block ciphers and message digests can either be directly + used by a caller or invoked together with a template to form + multi-block ciphers or keyed message digests. + + + + A single block cipher may even be called with multiple templates. + However, templates cannot be used without a single cipher. + + + + See /proc/crypto and search for "name". For example: + + + aes + ecb(aes) + cmac(aes) + ccm(aes) + rfc4106(gcm(aes)) + sha1 + hmac(sha1) + authenc(hmac(sha1),cbc(aes)) + + + + + In these examples, "aes" and "sha1" are the ciphers and all + others are the templates. + + + + Synchronous And Asynchronous Operation + + The kernel crypto API provides synchronous and asynchronous + API operations. + + + + When using the synchronous API operation, the caller invokes + a cipher operation which is performed synchronously by the + kernel crypto API. That means, the caller waits until the + cipher operation completes. Therefore, the kernel crypto API + calls work like regular function calls. For synchronous + operation, the set of API calls is small and conceptually + similar to any other crypto library. + + + + Asynchronous operation is provided by the kernel crypto API + which implies that the invocation of a cipher operation will + complete almost instantly. That invocation triggers the + cipher operation but it does not signal its completion. Before + invoking a cipher operation, the caller must provide a callback + function the kernel crypto API can invoke to signal the + completion of the cipher operation. Furthermore, the caller + must ensure it can handle such asynchronous events by applying + appropriate locking around its data. The kernel crypto API + does not perform any special serialization operation to protect + the caller's data integrity. + + + + Crypto API Cipher References And Priority + + A cipher is referenced by the caller with a string. That string + has the following semantics: + + + template(single block cipher) + + + where "template" and "single block cipher" is the aforementioned + template and single block cipher, respectively. If applicable, + additional templates may enclose other templates, such as + + + template1(template2(single block cipher))) + + + + + The kernel crypto API may provide multiple implementations of a + template or a single block cipher. For example, AES on newer + Intel hardware has the following implementations: AES-NI, + assembler implementation, or straight C. Now, when using the + string "aes" with the kernel crypto API, which cipher + implementation is used? The answer to that question is the + priority number assigned to each cipher implementation by the + kernel crypto API. When a caller uses the string to refer to a + cipher during initialization of a cipher handle, the kernel + crypto API looks up all implementations providing an + implementation with that name and selects the implementation + with the highest priority. + + + + Now, a caller may have the need to refer to a specific cipher + implementation and thus does not want to rely on the + priority-based selection. To accommodate this scenario, the + kernel crypto API allows the cipher implementation to register + a unique name in addition to common names. When using that + unique name, a caller is therefore always sure to refer to + the intended cipher implementation. + + + + The list of available ciphers is given in /proc/crypto. However, + that list does not specify all possible permutations of + templates and ciphers. Each block listed in /proc/crypto may + contain the following information -- if one of the components + listed as follows are not applicable to a cipher, it is not + displayed: + + + + + name: the generic name of the cipher that is subject + to the priority-based selection -- this name can be used by + the cipher allocation API calls (all names listed above are + examples for such generic names) + + + driver: the unique name of the cipher -- this name can + be used by the cipher allocation API calls + + + module: the kernel module providing the cipher + implementation (or "kernel" for statically linked ciphers) + + + priority: the priority value of the cipher implementation + + + refcnt: the reference count of the respective cipher + (i.e. the number of current consumers of this cipher) + + + selftest: specification whether the self test for the + cipher passed + + + type: + + + blkcipher for synchronous block ciphers + + + ablkcipher for asynchronous block ciphers + + + cipher for single block ciphers that may be used with + an additional template + + + shash for synchronous message digest + + + ahash for asynchronous message digest + + + aead for AEAD cipher type + + + compression for compression type transformations + + + rng for random number generator + + + givcipher for cipher with associated IV generator + (see the geniv entry below for the specification of the + IV generator type used by the cipher implementation) + + + + + + blocksize: blocksize of cipher in bytes + + + keysize: key size in bytes + + + ivsize: IV size in bytes + + + seedsize: required size of seed data for random number + generator + + + digestsize: output size of the message digest + + + geniv: IV generation type: + + + eseqiv for encrypted sequence number based IV + generation + + + seqiv for sequence number based IV generation + + + chainiv for chain iv generation + + + <builtin> is a marker that the cipher implements + IV generation and handling as it is specific to the given + cipher + + + + + + + + Key Sizes + + When allocating a cipher handle, the caller only specifies the + cipher type. Symmetric ciphers, however, typically support + multiple key sizes (e.g. AES-128 vs. AES-192 vs. AES-256). + These key sizes are determined with the length of the provided + key. Thus, the kernel crypto API does not provide a separate + way to select the particular symmetric cipher key size. + + + + Cipher Allocation Type And Masks + + The different cipher handle allocation functions allow the + specification of a type and mask flag. Both parameters have + the following meaning (and are therefore not covered in the + subsequent sections). + + + + The type flag specifies the type of the cipher algorithm. + The caller usually provides a 0 when the caller wants the + default handling. Otherwise, the caller may provide the + following selections which match the the aforementioned + cipher types: + + + + + CRYPTO_ALG_TYPE_CIPHER Single block cipher + + + CRYPTO_ALG_TYPE_COMPRESS Compression + + + CRYPTO_ALG_TYPE_AEAD Authenticated Encryption with + Associated Data (MAC) + + + CRYPTO_ALG_TYPE_BLKCIPHER Synchronous multi-block cipher + + + CRYPTO_ALG_TYPE_ABLKCIPHER Asynchronous multi-block cipher + + + CRYPTO_ALG_TYPE_GIVCIPHER Asynchronous multi-block + cipher packed together with an IV generator (see geniv field + in the /proc/crypto listing for the known IV generators) + + + CRYPTO_ALG_TYPE_DIGEST Raw message digest + + + CRYPTO_ALG_TYPE_HASH Alias for CRYPTO_ALG_TYPE_DIGEST + + + CRYPTO_ALG_TYPE_SHASH Synchronous multi-block hash + + + CRYPTO_ALG_TYPE_AHASH Asynchronous multi-block hash + + + CRYPTO_ALG_TYPE_RNG Random Number Generation + + + CRYPTO_ALG_TYPE_PCOMPRESS Enhanced version of + CRYPTO_ALG_TYPE_COMPRESS allowing for segmented compression / + decompression instead of performing the operation on one + segment only. CRYPTO_ALG_TYPE_PCOMPRESS is intended to replace + CRYPTO_ALG_TYPE_COMPRESS once existing consumers are converted. + + + + + The mask flag restricts the type of cipher. The only allowed + flag is CRYPTO_ALG_ASYNC to restrict the cipher lookup function + to asynchronous ciphers. Usually, a caller provides a 0 for the + mask flag. + + + + When the caller provides a mask and type specification, the + caller limits the search the kernel crypto API can perform for + a suitable cipher implementation for the given cipher name. + That means, even when a caller uses a cipher name that exists + during its initialization call, the kernel crypto API may not + select it due to the used type and mask field. + + + + + Developing Cipher Algorithms + Registering And Unregistering Transformation + + There are three distinct types of registration functions in + the Crypto API. One is used to register a generic cryptographic + transformation, while the other two are specific to HASH + transformations and COMPRESSion. We will discuss the latter + two in a separate chapter, here we will only look at the + generic ones. + + + + Before discussing the register functions, the data structure + to be filled with each, struct crypto_alg, must be considered + -- see below for a description of this data structure. + + + + The generic registration functions can be found in + include/linux/crypto.h and their definition can be seen below. + The former function registers a single transformation, while + the latter works on an array of transformation descriptions. + The latter is useful when registering transformations in bulk. + + + + int crypto_register_alg(struct crypto_alg *alg); + int crypto_register_algs(struct crypto_alg *algs, int count); + + + + The counterparts to those functions are listed below. + + + + int crypto_unregister_alg(struct crypto_alg *alg); + int crypto_unregister_algs(struct crypto_alg *algs, int count); + + + + Notice that both registration and unregistration functions + do return a value, so make sure to handle errors. A return + code of zero implies success. Any return code < 0 implies + an error. + + + + The bulk registration / unregistration functions require + that struct crypto_alg is an array of count size. These + functions simply loop over that array and register / + unregister each individual algorithm. If an error occurs, + the loop is terminated at the offending algorithm definition. + That means, the algorithms prior to the offending algorithm + are successfully registered. Note, the caller has no way of + knowing which cipher implementations have successfully + registered. If this is important to know, the caller should + loop through the different implementations using the single + instance *_alg functions for each individual implementation. + + + + Single-Block Symmetric Ciphers [CIPHER] + + Example of transformations: aes, arc4, ... + + + + This section describes the simplest of all transformation + implementations, that being the CIPHER type used for symmetric + ciphers. The CIPHER type is used for transformations which + operate on exactly one block at a time and there are no + dependencies between blocks at all. + + + Registration specifics + + The registration of [CIPHER] algorithm is specific in that + struct crypto_alg field .cra_type is empty. The .cra_u.cipher + has to be filled in with proper callbacks to implement this + transformation. + + + + See struct cipher_alg below. + + + + Cipher Definition With struct cipher_alg + + Struct cipher_alg defines a single block cipher. + + + + Here are schematics of how these functions are called when + operated from other part of the kernel. Note that the + .cia_setkey() call might happen before or after any of these + schematics happen, but must not happen during any of these + are in-flight. + + + + + KEY ---. PLAINTEXT ---. + v v + .cia_setkey() -> .cia_encrypt() + | + '-----> CIPHERTEXT + + + + + Please note that a pattern where .cia_setkey() is called + multiple times is also valid: + + + + + + KEY1 --. PLAINTEXT1 --. KEY2 --. PLAINTEXT2 --. + v v v v + .cia_setkey() -> .cia_encrypt() -> .cia_setkey() -> .cia_encrypt() + | | + '---> CIPHERTEXT1 '---> CIPHERTEXT2 + + + + + + + Multi-Block Ciphers [BLKCIPHER] [ABLKCIPHER] + + Example of transformations: cbc(aes), ecb(arc4), ... + + + + This section describes the multi-block cipher transformation + implementations for both synchronous [BLKCIPHER] and + asynchronous [ABLKCIPHER] case. The multi-block ciphers are + used for transformations which operate on scatterlists of + data supplied to the transformation functions. They output + the result into a scatterlist of data as well. + + + Registration Specifics + + + The registration of [BLKCIPHER] or [ABLKCIPHER] algorithms + is one of the most standard procedures throughout the crypto API. + + + + Note, if a cipher implementation requires a proper alignment + of data, the caller should use the functions of + crypto_blkcipher_alignmask() or crypto_ablkcipher_alignmask() + respectively to identify a memory alignment mask. The kernel + crypto API is able to process requests that are unaligned. + This implies, however, additional overhead as the kernel + crypto API needs to perform the realignment of the data which + may imply moving of data. + + + + Cipher Definition With struct blkcipher_alg and ablkcipher_alg + + Struct blkcipher_alg defines a synchronous block cipher whereas + struct ablkcipher_alg defines an asynchronous block cipher. + + + + Please refer to the single block cipher description for schematics + of the block cipher usage. The usage patterns are exactly the same + for [ABLKCIPHER] and [BLKCIPHER] as they are for plain [CIPHER]. + + + + Specifics Of Asynchronous Multi-Block Cipher + + There are a couple of specifics to the [ABLKCIPHER] interface. + + + + First of all, some of the drivers will want to use the + Generic ScatterWalk in case the hardware needs to be fed + separate chunks of the scatterlist which contains the + plaintext and will contain the ciphertext. Please refer + to the ScatterWalk interface offered by the Linux kernel + scatter / gather list implementation. + + + + + Hashing [HASH] + + + Example of transformations: crc32, md5, sha1, sha256,... + + + Registering And Unregistering The Transformation + + + There are multiple ways to register a HASH transformation, + depending on whether the transformation is synchronous [SHASH] + or asynchronous [AHASH] and the amount of HASH transformations + we are registering. You can find the prototypes defined in + include/crypto/internal/hash.h: + + + + int crypto_register_ahash(struct ahash_alg *alg); + + int crypto_register_shash(struct shash_alg *alg); + int crypto_register_shashes(struct shash_alg *algs, int count); + + + + The respective counterparts for unregistering the HASH + transformation are as follows: + + + + int crypto_unregister_ahash(struct ahash_alg *alg); + + int crypto_unregister_shash(struct shash_alg *alg); + int crypto_unregister_shashes(struct shash_alg *algs, int count); + + + + Cipher Definition With struct shash_alg and ahash_alg + + Here are schematics of how these functions are called when + operated from other part of the kernel. Note that the .setkey() + call might happen before or after any of these schematics happen, + but must not happen during any of these are in-flight. Please note + that calling .init() followed immediately by .finish() is also a + perfectly valid transformation. + + + + I) DATA -----------. + v + .init() -> .update() -> .final() ! .update() might not be called + ^ | | at all in this scenario. + '----' '---> HASH + + II) DATA -----------.-----------. + v v + .init() -> .update() -> .finup() ! .update() may not be called + ^ | | at all in this scenario. + '----' '---> HASH + + III) DATA -----------. + v + .digest() ! The entire process is handled + | by the .digest() call. + '---------------> HASH + + + + Here is a schematic of how the .export()/.import() functions are + called when used from another part of the kernel. + + + + KEY--. DATA--. + v v ! .update() may not be called + .setkey() -> .init() -> .update() -> .export() at all in this scenario. + ^ | | + '-----' '--> PARTIAL_HASH + + ----------- other transformations happen here ----------- + + PARTIAL_HASH--. DATA1--. + v v + .import -> .update() -> .final() ! .update() may not be called + ^ | | at all in this scenario. + '----' '--> HASH1 + + PARTIAL_HASH--. DATA2-. + v v + .import -> .finup() + | + '---------------> HASH2 + + + + Specifics Of Asynchronous HASH Transformation + + Some of the drivers will want to use the Generic ScatterWalk + in case the implementation needs to be fed separate chunks of the + scatterlist which contains the input data. The buffer containing + the resulting hash will always be properly aligned to + .cra_alignmask so there is no need to worry about this. + + + + + + Programming Interface + Block Cipher Context Data Structures +!Pinclude/linux/crypto.h Block Cipher Context Data Structures +!Finclude/linux/crypto.h aead_request + + Block Cipher Algorithm Definitions +!Pinclude/linux/crypto.h Block Cipher Algorithm Definitions +!Finclude/linux/crypto.h crypto_alg +!Finclude/linux/crypto.h ablkcipher_alg +!Finclude/linux/crypto.h aead_alg +!Finclude/linux/crypto.h blkcipher_alg +!Finclude/linux/crypto.h cipher_alg +!Finclude/linux/crypto.h rng_alg + + Asynchronous Block Cipher API +!Pinclude/linux/crypto.h Asynchronous Block Cipher API +!Finclude/linux/crypto.h crypto_alloc_ablkcipher +!Finclude/linux/crypto.h crypto_free_ablkcipher +!Finclude/linux/crypto.h crypto_has_ablkcipher +!Finclude/linux/crypto.h crypto_ablkcipher_ivsize +!Finclude/linux/crypto.h crypto_ablkcipher_blocksize +!Finclude/linux/crypto.h crypto_ablkcipher_setkey +!Finclude/linux/crypto.h crypto_ablkcipher_reqtfm +!Finclude/linux/crypto.h crypto_ablkcipher_encrypt +!Finclude/linux/crypto.h crypto_ablkcipher_decrypt + + Asynchronous Cipher Request Handle +!Pinclude/linux/crypto.h Asynchronous Cipher Request Handle +!Finclude/linux/crypto.h crypto_ablkcipher_reqsize +!Finclude/linux/crypto.h ablkcipher_request_set_tfm +!Finclude/linux/crypto.h ablkcipher_request_alloc +!Finclude/linux/crypto.h ablkcipher_request_free +!Finclude/linux/crypto.h ablkcipher_request_set_callback +!Finclude/linux/crypto.h ablkcipher_request_set_crypt + + Authenticated Encryption With Associated Data (AEAD) Cipher API +!Pinclude/linux/crypto.h Authenticated Encryption With Associated Data (AEAD) Cipher API +!Finclude/linux/crypto.h crypto_alloc_aead +!Finclude/linux/crypto.h crypto_free_aead +!Finclude/linux/crypto.h crypto_aead_ivsize +!Finclude/linux/crypto.h crypto_aead_authsize +!Finclude/linux/crypto.h crypto_aead_blocksize +!Finclude/linux/crypto.h crypto_aead_setkey +!Finclude/linux/crypto.h crypto_aead_setauthsize +!Finclude/linux/crypto.h crypto_aead_encrypt +!Finclude/linux/crypto.h crypto_aead_decrypt + + Asynchronous AEAD Request Handle +!Pinclude/linux/crypto.h Asynchronous AEAD Request Handle +!Finclude/linux/crypto.h crypto_aead_reqsize +!Finclude/linux/crypto.h aead_request_set_tfm +!Finclude/linux/crypto.h aead_request_alloc +!Finclude/linux/crypto.h aead_request_free +!Finclude/linux/crypto.h aead_request_set_callback +!Finclude/linux/crypto.h aead_request_set_crypt +!Finclude/linux/crypto.h aead_request_set_assoc + + Synchronous Block Cipher API +!Pinclude/linux/crypto.h Synchronous Block Cipher API +!Finclude/linux/crypto.h crypto_alloc_blkcipher +!Finclude/linux/crypto.h crypto_free_blkcipher +!Finclude/linux/crypto.h crypto_has_blkcipher +!Finclude/linux/crypto.h crypto_blkcipher_name +!Finclude/linux/crypto.h crypto_blkcipher_ivsize +!Finclude/linux/crypto.h crypto_blkcipher_blocksize +!Finclude/linux/crypto.h crypto_blkcipher_setkey +!Finclude/linux/crypto.h crypto_blkcipher_encrypt +!Finclude/linux/crypto.h crypto_blkcipher_encrypt_iv +!Finclude/linux/crypto.h crypto_blkcipher_decrypt +!Finclude/linux/crypto.h crypto_blkcipher_decrypt_iv +!Finclude/linux/crypto.h crypto_blkcipher_set_iv +!Finclude/linux/crypto.h crypto_blkcipher_get_iv + + Single Block Cipher API +!Pinclude/linux/crypto.h Single Block Cipher API +!Finclude/linux/crypto.h crypto_alloc_cipher +!Finclude/linux/crypto.h crypto_free_cipher +!Finclude/linux/crypto.h crypto_has_cipher +!Finclude/linux/crypto.h crypto_cipher_blocksize +!Finclude/linux/crypto.h crypto_cipher_setkey +!Finclude/linux/crypto.h crypto_cipher_encrypt_one +!Finclude/linux/crypto.h crypto_cipher_decrypt_one + + Synchronous Message Digest API +!Pinclude/linux/crypto.h Synchronous Message Digest API +!Finclude/linux/crypto.h crypto_alloc_hash +!Finclude/linux/crypto.h crypto_free_hash +!Finclude/linux/crypto.h crypto_has_hash +!Finclude/linux/crypto.h crypto_hash_blocksize +!Finclude/linux/crypto.h crypto_hash_digestsize +!Finclude/linux/crypto.h crypto_hash_init +!Finclude/linux/crypto.h crypto_hash_update +!Finclude/linux/crypto.h crypto_hash_final +!Finclude/linux/crypto.h crypto_hash_digest +!Finclude/linux/crypto.h crypto_hash_setkey + + Message Digest Algorithm Definitions +!Pinclude/crypto/hash.h Message Digest Algorithm Definitions +!Finclude/crypto/hash.h hash_alg_common +!Finclude/crypto/hash.h ahash_alg +!Finclude/crypto/hash.h shash_alg + + Asynchronous Message Digest API +!Pinclude/crypto/hash.h Asynchronous Message Digest API +!Finclude/crypto/hash.h crypto_alloc_ahash +!Finclude/crypto/hash.h crypto_free_ahash +!Finclude/crypto/hash.h crypto_ahash_init +!Finclude/crypto/hash.h crypto_ahash_digestsize +!Finclude/crypto/hash.h crypto_ahash_reqtfm +!Finclude/crypto/hash.h crypto_ahash_reqsize +!Finclude/crypto/hash.h crypto_ahash_setkey +!Finclude/crypto/hash.h crypto_ahash_finup +!Finclude/crypto/hash.h crypto_ahash_final +!Finclude/crypto/hash.h crypto_ahash_digest +!Finclude/crypto/hash.h crypto_ahash_export +!Finclude/crypto/hash.h crypto_ahash_import + + Asynchronous Hash Request Handle +!Pinclude/crypto/hash.h Asynchronous Hash Request Handle +!Finclude/crypto/hash.h ahash_request_set_tfm +!Finclude/crypto/hash.h ahash_request_alloc +!Finclude/crypto/hash.h ahash_request_free +!Finclude/crypto/hash.h ahash_request_set_callback +!Finclude/crypto/hash.h ahash_request_set_crypt + + Synchronous Message Digest API +!Pinclude/crypto/hash.h Synchronous Message Digest API +!Finclude/crypto/hash.h crypto_alloc_shash +!Finclude/crypto/hash.h crypto_free_shash +!Finclude/crypto/hash.h crypto_shash_blocksize +!Finclude/crypto/hash.h crypto_shash_digestsize +!Finclude/crypto/hash.h crypto_shash_descsize +!Finclude/crypto/hash.h crypto_shash_setkey +!Finclude/crypto/hash.h crypto_shash_digest +!Finclude/crypto/hash.h crypto_shash_export +!Finclude/crypto/hash.h crypto_shash_import +!Finclude/crypto/hash.h crypto_shash_init +!Finclude/crypto/hash.h crypto_shash_update +!Finclude/crypto/hash.h crypto_shash_final +!Finclude/crypto/hash.h crypto_shash_finup + + Crypto API Random Number API +!Pinclude/crypto/rng.h Random number generator API +!Finclude/crypto/rng.h crypto_alloc_rng +!Finclude/crypto/rng.h crypto_rng_alg +!Finclude/crypto/rng.h crypto_free_rng +!Finclude/crypto/rng.h crypto_rng_get_bytes +!Finclude/crypto/rng.h crypto_rng_reset +!Finclude/crypto/rng.h crypto_rng_seedsize +!Cinclude/crypto/rng.h + + + + Code Examples + Code Example For Asynchronous Block Cipher Operation + + +struct tcrypt_result { + struct completion completion; + int err; +}; + +/* tie all data structures together */ +struct ablkcipher_def { + struct scatterlist sg; + struct crypto_ablkcipher *tfm; + struct ablkcipher_request *req; + struct tcrypt_result result; +}; + +/* Callback function */ +static void test_ablkcipher_cb(struct crypto_async_request *req, int error) +{ + struct tcrypt_result *result = req->data; + + if (error == -EINPROGRESS) + return; + result->err = error; + complete(&result->completion); + pr_info("Encryption finished successfully\n"); +} + +/* Perform cipher operation */ +static unsigned int test_ablkcipher_encdec(struct ablkcipher_def *ablk, + int enc) +{ + int rc = 0; + + if (enc) + rc = crypto_ablkcipher_encrypt(ablk->req); + else + rc = crypto_ablkcipher_decrypt(ablk->req); + + switch (rc) { + case 0: + break; + case -EINPROGRESS: + case -EBUSY: + rc = wait_for_completion_interruptible( + &ablk->result.completion); + if (!rc && !ablk->result.err) { + reinit_completion(&ablk->result.completion); + break; + } + default: + pr_info("ablkcipher encrypt returned with %d result %d\n", + rc, ablk->result.err); + break; + } + init_completion(&ablk->result.completion); + + return rc; +} + +/* Initialize and trigger cipher operation */ +static int test_ablkcipher(void) +{ + struct ablkcipher_def ablk; + struct crypto_ablkcipher *ablkcipher = NULL; + struct ablkcipher_request *req = NULL; + char *scratchpad = NULL; + char *ivdata = NULL; + unsigned char key[32]; + int ret = -EFAULT; + + ablkcipher = crypto_alloc_ablkcipher("cbc-aes-aesni", 0, 0); + if (IS_ERR(ablkcipher)) { + pr_info("could not allocate ablkcipher handle\n"); + return PTR_ERR(ablkcipher); + } + + req = ablkcipher_request_alloc(ablkcipher, GFP_KERNEL); + if (IS_ERR(req)) { + pr_info("could not allocate request queue\n"); + ret = PTR_ERR(req); + goto out; + } + + ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, + test_ablkcipher_cb, + &ablk.result); + + /* AES 256 with random key */ + get_random_bytes(&key, 32); + if (crypto_ablkcipher_setkey(ablkcipher, key, 32)) { + pr_info("key could not be set\n"); + ret = -EAGAIN; + goto out; + } + + /* IV will be random */ + ivdata = kmalloc(16, GFP_KERNEL); + if (!ivdata) { + pr_info("could not allocate ivdata\n"); + goto out; + } + get_random_bytes(ivdata, 16); + + /* Input data will be random */ + scratchpad = kmalloc(16, GFP_KERNEL); + if (!scratchpad) { + pr_info("could not allocate scratchpad\n"); + goto out; + } + get_random_bytes(scratchpad, 16); + + ablk.tfm = ablkcipher; + ablk.req = req; + + /* We encrypt one block */ + sg_init_one(&ablk.sg, scratchpad, 16); + ablkcipher_request_set_crypt(req, &ablk.sg, &ablk.sg, 16, ivdata); + init_completion(&ablk.result.completion); + + /* encrypt data */ + ret = test_ablkcipher_encdec(&ablk, 1); + if (ret) + goto out; + + pr_info("Encryption triggered successfully\n"); + +out: + if (ablkcipher) + crypto_free_ablkcipher(ablkcipher); + if (req) + ablkcipher_request_free(req); + if (ivdata) + kfree(ivdata); + if (scratchpad) + kfree(scratchpad); + return ret; +} + + + + Code Example For Synchronous Block Cipher Operation + + +static int test_blkcipher(void) +{ + struct crypto_blkcipher *blkcipher = NULL; + char *cipher = "cbc(aes)"; + // AES 128 + charkey = +"\x12\x34\x56\x78\x90\xab\xcd\xef\x12\x34\x56\x78\x90\xab\xcd\xef"; + chariv = +"\x12\x34\x56\x78\x90\xab\xcd\xef\x12\x34\x56\x78\x90\xab\xcd\xef"; + unsigned int ivsize = 0; + char *scratchpad = NULL; // holds plaintext and ciphertext + struct scatterlist sg; + struct blkcipher_desc desc; + int ret = -EFAULT; + + blkcipher = crypto_alloc_blkcipher(cipher, 0, 0); + if (IS_ERR(blkcipher)) { + printk("could not allocate blkcipher handle for %s\n", cipher); + return -PTR_ERR(blkcipher); + } + + if (crypto_blkcipher_setkey(blkcipher, key, strlen(key))) { + printk("key could not be set\n"); + ret = -EAGAIN; + goto out; + } + + ivsize = crypto_blkcipher_ivsize(blkcipher); + if (ivsize) { + if (ivsize != strlen(iv)) + printk("IV length differs from expected length\n"); + crypto_blkcipher_set_iv(blkcipher, iv, ivsize); + } + + scratchpad = kmalloc(crypto_blkcipher_blocksize(blkcipher), GFP_KERNEL); + if (!scratchpad) { + printk("could not allocate scratchpad for %s\n", cipher); + goto out; + } + /* get some random data that we want to encrypt */ + get_random_bytes(scratchpad, crypto_blkcipher_blocksize(blkcipher)); + + desc.flags = 0; + desc.tfm = blkcipher; + sg_init_one(&sg, scratchpad, crypto_blkcipher_blocksize(blkcipher)); + + /* encrypt data in place */ + crypto_blkcipher_encrypt(&desc, &sg, &sg, + crypto_blkcipher_blocksize(blkcipher)); + + /* decrypt data in place + * crypto_blkcipher_decrypt(&desc, &sg, &sg, + */ crypto_blkcipher_blocksize(blkcipher)); + + + printk("Cipher operation completed\n"); + return 0; + +out: + if (blkcipher) + crypto_free_blkcipher(blkcipher); + if (scratchpad) + kzfree(scratchpad); + return ret; +} + + + + Code Example For Use of Operational State Memory With SHASH + + +struct sdesc { + struct shash_desc shash; + char ctx[]; +}; + +static struct sdescinit_sdesc(struct crypto_shash *alg) +{ + struct sdescsdesc; + int size; + + size = sizeof(struct shash_desc) + crypto_shash_descsize(alg); + sdesc = kmalloc(size, GFP_KERNEL); + if (!sdesc) + return ERR_PTR(-ENOMEM); + sdesc->shash.tfm = alg; + sdesc->shash.flags = 0x0; + return sdesc; +} + +static int calc_hash(struct crypto_shashalg, + const unsigned chardata, unsigned int datalen, + unsigned chardigest) { + struct sdescsdesc; + int ret; + + sdesc = init_sdesc(alg); + if (IS_ERR(sdesc)) { + pr_info("trusted_key: can't alloc %s\n", hash_alg); + return PTR_ERR(sdesc); + } + + ret = crypto_shash_digest(&sdesc->shash, data, datalen, digest); + kfree(sdesc); + return ret; +} + + + + Code Example For Random Number Generator Usage + + +static int get_random_numbers(u8 *buf, unsigned int len) +{ + struct crypto_rngrng = NULL; + chardrbg = "drbg_nopr_sha256"; /* Hash DRBG with SHA-256, no PR */ + int ret; + + if (!buf || !len) { + pr_debug("No output buffer provided\n"); + return -EINVAL; + } + + rng = crypto_alloc_rng(drbg, 0, 0); + if (IS_ERR(rng)) { + pr_debug("could not allocate RNG handle for %s\n", drbg); + return -PTR_ERR(rng); + } + + ret = crypto_rng_get_bytes(rng, buf, len); + if (ret < 0) + pr_debug("generation of random numbers failed\n"); + else if (ret == 0) + pr_debug("RNG returned no data"); + else + pr_debug("RNG returned %d bytes of data\n", ret); + +out: + crypto_free_rng(rng); + return ret; +} + + + +
-- cgit v1.2.3-59-g8ed1b From e9a44230dbca10cb02daffd81f1f1073004a5b8b Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Wed, 12 Nov 2014 05:24:12 +0100 Subject: crypto: doc - compile crypto API spec Add the crypto API documentation into the DocBook Makefile to allow it being compiled Signed-off-by: Stephan Mueller Signed-off-by: Herbert Xu --- Documentation/DocBook/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile index bec06659e0eb..9c7d92d03f62 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile @@ -15,7 +15,7 @@ DOCBOOKS := z8530book.xml device-drivers.xml \ 80211.xml debugobjects.xml sh.xml regulator.xml \ alsa-driver-api.xml writing-an-alsa-driver.xml \ tracepoint.xml drm.xml media_api.xml w1.xml \ - writing_musb_glue_layer.xml + writing_musb_glue_layer.xml crypto-API.xml include Documentation/DocBook/media/Makefile -- cgit v1.2.3-59-g8ed1b From e63b673f601dda77c668e6fd5240425b5331ec7f Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Wed, 12 Nov 2014 05:24:53 +0100 Subject: crypto: doc - userspace interface spec The userspace interface of the kernel crypto API is documented with * a general explanation * a discussion of the memory in-place operation * the description of the message digest API * the description of the symmetric cipher API The documentation refers to libkcapi as a working example on how to use the kernel crypto API from user space. Signed-off-by: Stephan Mueller Signed-off-by: Herbert Xu --- Documentation/crypto/crypto-API-userspace.txt | 205 ++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) create mode 100644 Documentation/crypto/crypto-API-userspace.txt (limited to 'Documentation') diff --git a/Documentation/crypto/crypto-API-userspace.txt b/Documentation/crypto/crypto-API-userspace.txt new file mode 100644 index 000000000000..ac619cd90300 --- /dev/null +++ b/Documentation/crypto/crypto-API-userspace.txt @@ -0,0 +1,205 @@ +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 2c91e61dc97cce57ffd9dd654a6ee284e1f45a1f Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Tue, 23 Sep 2014 16:45:12 +0200 Subject: rtc: at91sam9: add DT bindings documentation Add RTT bindings documentation. Signed-off-by: Boris BREZILLON Acked-by: Johan Hovold Acked-by: Arnd Bergmann Signed-off-by: Nicolas Ferre --- .../devicetree/bindings/rtc/atmel,at91sam9-rtc.txt | 23 ++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 Documentation/devicetree/bindings/rtc/atmel,at91sam9-rtc.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/rtc/atmel,at91sam9-rtc.txt b/Documentation/devicetree/bindings/rtc/atmel,at91sam9-rtc.txt new file mode 100644 index 000000000000..6ae79d1843f3 --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/atmel,at91sam9-rtc.txt @@ -0,0 +1,23 @@ +Atmel AT91SAM9260 Real Time Timer + +Required properties: +- compatible: should be: "atmel,at91sam9260-rtt" +- reg: should encode the memory region of the RTT controller +- interrupts: rtt alarm/event interrupt +- clocks: should contain the 32 KHz slow clk that will drive the RTT block. +- atmel,rtt-rtc-time-reg: should encode the GPBR register used to store + the time base when the RTT is used as an RTC. + The first cell should point to the GPBR node and the second one + encode the offset within the GPBR block (or in other words, the + GPBR register used to store the time base). + + +Example: + +rtt@fffffd20 { + compatible = "atmel,at91sam9260-rtt"; + reg = <0xfffffd20 0x10>; + interrupts = <1 4 7>; + clocks = <&clk32k>; + atmel,rtt-rtc-time-reg = <&gpbr 0x0>; +}; -- cgit v1.2.3-59-g8ed1b From 62d0ff83c6e2221662fa0dccf2de096bdc7a2fc4 Mon Sep 17 00:00:00 2001 From: Minghuan Lian Date: Wed, 5 Nov 2014 16:45:11 +0800 Subject: PCI: layerscape: Add Freescale Layerscape PCIe driver Add support for Freescale Layerscape PCIe controller. This driver re-uses the Synopsis DesignWare core code. [bhelgaas: add Kconfig dependency on CONFIG_ARM] Signed-off-by: Minghuan Lian Signed-off-by: Bjorn Helgaas Acked-by: Arnd Bergmann --- .../devicetree/bindings/pci/layerscape-pci.txt | 42 +++++ MAINTAINERS | 10 ++ drivers/pci/host/Kconfig | 8 + drivers/pci/host/Makefile | 1 + drivers/pci/host/pci-layerscape.c | 179 +++++++++++++++++++++ 5 files changed, 240 insertions(+) create mode 100644 Documentation/devicetree/bindings/pci/layerscape-pci.txt create mode 100644 drivers/pci/host/pci-layerscape.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/pci/layerscape-pci.txt b/Documentation/devicetree/bindings/pci/layerscape-pci.txt new file mode 100644 index 000000000000..6286f049bf18 --- /dev/null +++ b/Documentation/devicetree/bindings/pci/layerscape-pci.txt @@ -0,0 +1,42 @@ +Freescale Layerscape PCIe controller + +This PCIe host controller is based on the Synopsis Designware PCIe IP +and thus inherits all the common properties defined in designware-pcie.txt. + +Required properties: +- compatible: should contain the platform identifier such as "fsl,ls1021a-pcie" +- reg: base addresses and lengths of the PCIe controller +- interrupts: A list of interrupt outputs of the controller. Must contain an + entry for each entry in the interrupt-names property. +- interrupt-names: Must include the following entries: + "intr": The interrupt that is asserted for controller interrupts +- fsl,pcie-scfg: Must include two entries. + The first entry must be a link to the SCFG device node + The second entry must be '0' or '1' based on physical PCIe controller index. + This is used to get SCFG PEXN registers + +Example: + + pcie@3400000 { + compatible = "fsl,ls1021a-pcie", "snps,dw-pcie"; + reg = <0x00 0x03400000 0x0 0x00010000 /* controller registers */ + 0x40 0x00000000 0x0 0x00002000>; /* configuration space */ + reg-names = "regs", "config"; + interrupts = ; /* controller interrupt */ + interrupt-names = "intr"; + fsl,pcie-scfg = <&scfg 0>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + num-lanes = <4>; + bus-range = <0x0 0xff>; + ranges = <0x81000000 0x0 0x00000000 0x40 0x00010000 0x0 0x00010000 /* downstream I/O */ + 0xc2000000 0x0 0x20000000 0x40 0x20000000 0x0 0x20000000 /* prefetchable memory */ + 0x82000000 0x0 0x40000000 0x40 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0000 0 0 1 &gic GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>, + <0000 0 0 2 &gic GIC_SPI 188 IRQ_TYPE_LEVEL_HIGH>, + <0000 0 0 3 &gic GIC_SPI 190 IRQ_TYPE_LEVEL_HIGH>, + <0000 0 0 4 &gic GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>; + }; diff --git a/MAINTAINERS b/MAINTAINERS index a20df9bf8ab0..016e1ef1c16c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6983,6 +6983,16 @@ S: Maintained F: Documentation/devicetree/bindings/pci/xgene-pci.txt F: drivers/pci/host/pci-xgene.c +PCI DRIVER FOR FREESCALE LAYERSCAPE +M: Minghuan Lian +M: Mingkai Hu +M: Roy Zang +L: linuxppc-dev@lists.ozlabs.org +L: linux-pci@vger.kernel.org +L: linux-arm-kernel@lists.infradead.org +S: Maintained +F: drivers/pci/host/*layerscape* + PCI DRIVER FOR IMX6 M: Richard Zhu M: Lucas Stach diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig index 3dc25fad490c..67e2cc5a0bd4 100644 --- a/drivers/pci/host/Kconfig +++ b/drivers/pci/host/Kconfig @@ -91,4 +91,12 @@ config PCI_XGENE There are 5 internal PCIe ports available. Each port is GEN3 capable and have varied lanes from x1 to x8. +config PCI_LAYERSCAPE + bool "Freescale Layerscape PCIe controller" + depends on OF && ARM + select PCIE_DW + select MFD_SYSCON + help + Say Y here if you want PCIe controller support on Layerscape SoCs. + endmenu diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile index 26b3461d68d7..44c26998027f 100644 --- a/drivers/pci/host/Makefile +++ b/drivers/pci/host/Makefile @@ -11,3 +11,4 @@ obj-$(CONFIG_PCIE_SPEAR13XX) += pcie-spear13xx.o obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone-dw.o pci-keystone.o obj-$(CONFIG_PCIE_XILINX) += pcie-xilinx.o obj-$(CONFIG_PCI_XGENE) += pci-xgene.o +obj-$(CONFIG_PCI_LAYERSCAPE) += pci-layerscape.o diff --git a/drivers/pci/host/pci-layerscape.c b/drivers/pci/host/pci-layerscape.c new file mode 100644 index 000000000000..6697b1a4d4fa --- /dev/null +++ b/drivers/pci/host/pci-layerscape.c @@ -0,0 +1,179 @@ +/* + * PCIe host controller driver for Freescale Layerscape SoCs + * + * Copyright (C) 2014 Freescale Semiconductor. + * + * Author: Minghuan Lian + * + * 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 +#include +#include + +#include "pcie-designware.h" + +/* PEX1/2 Misc Ports Status Register */ +#define SCFG_PEXMSCPORTSR(pex_idx) (0x94 + (pex_idx) * 4) +#define LTSSM_STATE_SHIFT 20 +#define LTSSM_STATE_MASK 0x3f +#define LTSSM_PCIE_L0 0x11 /* L0 state */ + +/* Symbol Timer Register and Filter Mask Register 1 */ +#define PCIE_STRFMR1 0x71c + +struct ls_pcie { + struct list_head node; + struct device *dev; + struct pci_bus *bus; + void __iomem *dbi; + struct regmap *scfg; + struct pcie_port pp; + int index; + int msi_irq; +}; + +#define to_ls_pcie(x) container_of(x, struct ls_pcie, pp) + +static int ls_pcie_link_up(struct pcie_port *pp) +{ + u32 state; + struct ls_pcie *pcie = to_ls_pcie(pp); + + regmap_read(pcie->scfg, SCFG_PEXMSCPORTSR(pcie->index), &state); + state = (state >> LTSSM_STATE_SHIFT) & LTSSM_STATE_MASK; + + if (state < LTSSM_PCIE_L0) + return 0; + + return 1; +} + +static void ls_pcie_host_init(struct pcie_port *pp) +{ + struct ls_pcie *pcie = to_ls_pcie(pp); + int count = 0; + u32 val; + + dw_pcie_setup_rc(pp); + + while (!ls_pcie_link_up(pp)) { + usleep_range(100, 1000); + count++; + if (count >= 200) { + dev_err(pp->dev, "phy link never came up\n"); + return; + } + } + + /* + * LS1021A Workaround for internal TKT228622 + * to fix the INTx hang issue + */ + val = ioread32(pcie->dbi + PCIE_STRFMR1); + val &= 0xffff; + iowrite32(val, pcie->dbi + PCIE_STRFMR1); +} + +static struct pcie_host_ops ls_pcie_host_ops = { + .link_up = ls_pcie_link_up, + .host_init = ls_pcie_host_init, +}; + +static int ls_add_pcie_port(struct ls_pcie *pcie) +{ + struct pcie_port *pp; + int ret; + + pp = &pcie->pp; + pp->dev = pcie->dev; + pp->dbi_base = pcie->dbi; + pp->root_bus_nr = -1; + pp->ops = &ls_pcie_host_ops; + + ret = dw_pcie_host_init(pp); + if (ret) { + dev_err(pp->dev, "failed to initialize host\n"); + return ret; + } + + return 0; +} + +static int __init ls_pcie_probe(struct platform_device *pdev) +{ + struct ls_pcie *pcie; + struct resource *dbi_base; + u32 index[2]; + int ret; + + pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL); + if (!pcie) + return -ENOMEM; + + pcie->dev = &pdev->dev; + + dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); + if (!dbi_base) { + dev_err(&pdev->dev, "missing *regs* space\n"); + return -ENODEV; + } + + pcie->dbi = devm_ioremap_resource(&pdev->dev, dbi_base); + if (IS_ERR(pcie->dbi)) + return PTR_ERR(pcie->dbi); + + pcie->scfg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "fsl,pcie-scfg"); + if (IS_ERR(pcie->scfg)) { + dev_err(&pdev->dev, "No syscfg phandle specified\n"); + return PTR_ERR(pcie->scfg); + } + + ret = of_property_read_u32_array(pdev->dev.of_node, + "fsl,pcie-scfg", index, 2); + if (ret) + return ret; + pcie->index = index[1]; + + ret = ls_add_pcie_port(pcie); + if (ret < 0) + return ret; + + platform_set_drvdata(pdev, pcie); + + return 0; +} + +static const struct of_device_id ls_pcie_of_match[] = { + { .compatible = "fsl,ls1021a-pcie" }, + { }, +}; +MODULE_DEVICE_TABLE(of, ls_pcie_of_match); + +static struct platform_driver ls_pcie_driver = { + .driver = { + .name = "layerscape-pcie", + .owner = THIS_MODULE, + .of_match_table = ls_pcie_of_match, + }, +}; + +module_platform_driver_probe(ls_pcie_driver, ls_pcie_probe); + +MODULE_AUTHOR("Minghuan Lian "); +MODULE_DESCRIPTION("Freescale Layerscape PCIe host controller driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-59-g8ed1b From 9e6280cd44c1cceaaac921567ee8c5731b7cc72b Mon Sep 17 00:00:00 2001 From: Krishna Mohan Dani Date: Thu, 13 Nov 2014 17:44:21 +0530 Subject: ASoC: rt5631: Add device tree binding documentation Document the device tree binding for the ALC5631 codec and update vendor specific prefix for the Realtek. Signed-off-by: Krishna Mohan Dani Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/rt5631.txt | 48 ++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/rt5631.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/rt5631.txt b/Documentation/devicetree/bindings/sound/rt5631.txt new file mode 100644 index 000000000000..92b986ca337b --- /dev/null +++ b/Documentation/devicetree/bindings/sound/rt5631.txt @@ -0,0 +1,48 @@ +ALC5631/RT5631 audio CODEC + +This device supports I2C only. + +Required properties: + + - compatible : "realtek,alc5631" or "realtek,rt5631" + + - reg : the I2C address of the device. + +Pins on the device (for linking into audio routes): + + * SPK_OUT_R_P + * SPK_OUT_R_N + * SPK_OUT_L_P + * SPK_OUT_L_N + * HP_OUT_L + * HP_OUT_R + * AUX_OUT2_LP + * AUX_OUT2_RN + * AUX_OUT1_LP + * AUX_OUT1_RN + * AUX_IN_L_JD + * AUX_IN_R_JD + * MONO_IN_P + * MONO_IN_N + * MIC1_P + * MIC1_N + * MIC2_P + * MIC2_N + * MONO_OUT_P + * MONO_OUT_N + * MICBIAS1 + * MICBIAS2 + +Example: + +alc5631: alc5631@1a { + compatible = "realtek,alc5631"; + reg = <0x1a>; +}; + +or + +rt5631: rt5631@1a { + compatible = "realtek,rt5631"; + reg = <0x1a>; +}; -- cgit v1.2.3-59-g8ed1b From 74860feed5ed570659e0f3852dd945be5b046038 Mon Sep 17 00:00:00 2001 From: Pranith Kumar Date: Fri, 19 Sep 2014 11:34:09 -0400 Subject: documentation: Document RCU self test boot params Document the RCU self test boot parameters in kernel-parameters.txt. Signed-off-by: Pranith Kumar Signed-off-by: Paul E. McKenney --- Documentation/kernel-parameters.txt | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 7dbe5ec9d9cd..4e2ae0e55474 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -3071,6 +3071,15 @@ bytes respectively. Such letter suffixes can also be entirely omitted. messages. Disable with a value less than or equal to zero. + rcupdate.rcu_self_test= [KNL] + Run the RCU early boot self tests + + rcupdate.rcu_self_test_bh= [KNL] + Run the RCU bh early boot self tests + + rcupdate.rcu_self_test_sched= [KNL] + Run the RCU sched early boot self tests + rdinit= [KNL] Format: Run specified binary instead of /init from the ramdisk, -- cgit v1.2.3-59-g8ed1b From 8b19d1dead8413442ba0ff0b4e19b08f69d2f1b7 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sun, 12 Oct 2014 07:55:47 -0700 Subject: documentation: Additional restriction for control dependencies Short-circuit booleans are not defences against compilers breaking your intended control dependencies. Signed-off-by: Paul E. McKenney Reviewed-by: Pranith Kumar --- Documentation/memory-barriers.txt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'Documentation') diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt index 22a969cdd476..1073e019ef06 100644 --- a/Documentation/memory-barriers.txt +++ b/Documentation/memory-barriers.txt @@ -694,6 +694,24 @@ Please note once again that the stores to 'b' differ. If they were identical, as noted earlier, the compiler could pull this store outside of the 'if' statement. +You must also be careful not to rely too much on boolean short-circuit +evaluation. Consider this example: + + q = ACCESS_ONCE(a); + if (a || 1 > 0) + ACCESS_ONCE(b) = 1; + +Because the second condition is always true, the compiler can transform +this example as following, defeating control dependency: + + q = ACCESS_ONCE(a); + ACCESS_ONCE(b) = 1; + +This example underscores the need to ensure that the compiler cannot +out-guess your code. More generally, although ACCESS_ONCE() does force +the compiler to actually emit code for a given load, it does not force +the compiler to use the results. + Finally, control dependencies do -not- provide transitivity. This is demonstrated by two related examples, with the initial values of x and y both being zero: -- cgit v1.2.3-59-g8ed1b From 1f7870dd8729c64b8472b42440811e7ff94d16a4 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sun, 19 Oct 2014 12:05:22 -0700 Subject: documentation: Add atomic_long_t to atomic_ops.txt Signed-off-by: Paul E. McKenney Reviewed-by: Pranith Kumar --- Documentation/atomic_ops.txt | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/atomic_ops.txt b/Documentation/atomic_ops.txt index 68542fe13b85..183e41bdcb69 100644 --- a/Documentation/atomic_ops.txt +++ b/Documentation/atomic_ops.txt @@ -7,12 +7,13 @@ maintainers on how to implement atomic counter, bitops, and spinlock interfaces properly. - The atomic_t type should be defined as a signed integer. -Also, it should be made opaque such that any kind of cast to a normal -C integer type will fail. Something like the following should -suffice: + The atomic_t type should be defined as a signed integer and +the atomic_long_t type as a signed long integer. Also, they should +be made opaque such that any kind of cast to a normal C integer type +will fail. Something like the following should suffice: typedef struct { int counter; } atomic_t; + typedef struct { long counter; } atomic_long_t; Historically, counter has been declared volatile. This is now discouraged. See Documentation/volatile-considered-harmful.txt for the complete rationale. @@ -37,6 +38,9 @@ initializer is used before runtime. If the initializer is used at runtime, a proper implicit or explicit read memory barrier is needed before reading the value with atomic_read from another thread. +As with all of the atomic_ interfaces, replace the leading "atomic_" +with "atomic_long_" to operate on atomic_long_t. + The second interface can be used at runtime, as in: struct foo { atomic_t counter; }; -- cgit v1.2.3-59-g8ed1b From 8ab8b3e1837fc580b30263ed3c44dc34798714d9 Mon Sep 17 00:00:00 2001 From: Pranith Kumar Date: Tue, 2 Sep 2014 23:34:29 -0400 Subject: documentation: memory-barriers.txt: Correct example for reorderings Correct the example of memory orderings in memory-barriers.txt Commit 615cc2c9cf95 "Documentation/memory-barriers.txt: fix important typo re memory barriers" changed the assignment to x and y. Change the rest of the example to match this change. Reported-by: Ganesh Rapolu Signed-off-by: Pranith Kumar Signed-off-by: Paul E. McKenney --- Documentation/memory-barriers.txt | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'Documentation') diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt index 1073e019ef06..f7fa63508aba 100644 --- a/Documentation/memory-barriers.txt +++ b/Documentation/memory-barriers.txt @@ -121,22 +121,22 @@ For example, consider the following sequence of events: The set of accesses as seen by the memory system in the middle can be arranged in 24 different combinations: - STORE A=3, STORE B=4, x=LOAD A->3, y=LOAD B->4 - STORE A=3, STORE B=4, y=LOAD B->4, x=LOAD A->3 - STORE A=3, x=LOAD A->3, STORE B=4, y=LOAD B->4 - STORE A=3, x=LOAD A->3, y=LOAD B->2, STORE B=4 - STORE A=3, y=LOAD B->2, STORE B=4, x=LOAD A->3 - STORE A=3, y=LOAD B->2, x=LOAD A->3, STORE B=4 - STORE B=4, STORE A=3, x=LOAD A->3, y=LOAD B->4 + STORE A=3, STORE B=4, y=LOAD A->3, x=LOAD B->4 + STORE A=3, STORE B=4, x=LOAD B->4, y=LOAD A->3 + STORE A=3, y=LOAD A->3, STORE B=4, x=LOAD B->4 + STORE A=3, y=LOAD A->3, x=LOAD B->2, STORE B=4 + STORE A=3, x=LOAD B->2, STORE B=4, y=LOAD A->3 + STORE A=3, x=LOAD B->2, y=LOAD A->3, STORE B=4 + STORE B=4, STORE A=3, y=LOAD A->3, x=LOAD B->4 STORE B=4, ... ... and can thus result in four different combinations of values: - x == 1, y == 2 - x == 1, y == 4 - x == 3, y == 2 - x == 3, y == 4 + x == 2, y == 1 + x == 2, y == 3 + x == 4, y == 1 + x == 4, y == 3 Furthermore, the stores committed by a CPU to the memory system may not be -- cgit v1.2.3-59-g8ed1b From 9488e1e5b319751c71eebfd49027bf9e2377f38c Mon Sep 17 00:00:00 2001 From: Hisashi Nakamura Date: Thu, 13 Nov 2014 15:59:07 +0900 Subject: net: sh_eth: Add r8a7793 support The device tree probing for R-Car M2N (r8a7793) is added. Signed-off-by: Hisashi Nakamura Signed-off-by: Yoshihiro Kaneko Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/sh_eth.txt | 1 + drivers/net/ethernet/renesas/sh_eth.c | 2 ++ 2 files changed, 3 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/sh_eth.txt b/Documentation/devicetree/bindings/net/sh_eth.txt index 34d4db1a4e25..2f6ec85fda8e 100644 --- a/Documentation/devicetree/bindings/net/sh_eth.txt +++ b/Documentation/devicetree/bindings/net/sh_eth.txt @@ -9,6 +9,7 @@ Required properties: "renesas,ether-r8a7779" if the device is a part of R8A7779 SoC. "renesas,ether-r8a7790" if the device is a part of R8A7790 SoC. "renesas,ether-r8a7791" if the device is a part of R8A7791 SoC. + "renesas,ether-r8a7793" if the device is a part of R8A7793 SoC. "renesas,ether-r8a7794" if the device is a part of R8A7794 SoC. "renesas,ether-r7s72100" if the device is a part of R7S72100 SoC. - reg: offset and length of (1) the E-DMAC/feLic register block (required), diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index 1f79ed61f9cd..71f59ee51304 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -2747,6 +2747,7 @@ static const struct of_device_id sh_eth_match_table[] = { { .compatible = "renesas,ether-r8a7779", .data = &r8a777x_data }, { .compatible = "renesas,ether-r8a7790", .data = &r8a779x_data }, { .compatible = "renesas,ether-r8a7791", .data = &r8a779x_data }, + { .compatible = "renesas,ether-r8a7793", .data = &r8a779x_data }, { .compatible = "renesas,ether-r8a7794", .data = &r8a779x_data }, { .compatible = "renesas,ether-r7s72100", .data = &r7s72100_data }, { } @@ -2973,6 +2974,7 @@ static struct platform_device_id sh_eth_id_table[] = { { "r8a777x-ether", (kernel_ulong_t)&r8a777x_data }, { "r8a7790-ether", (kernel_ulong_t)&r8a779x_data }, { "r8a7791-ether", (kernel_ulong_t)&r8a779x_data }, + { "r8a7793-ether", (kernel_ulong_t)&r8a779x_data }, { "r8a7794-ether", (kernel_ulong_t)&r8a779x_data }, { } }; -- cgit v1.2.3-59-g8ed1b From 2880fc877971d6c14b0c76ac09744e3ff5b126d5 Mon Sep 17 00:00:00 2001 From: Dylan Reid Date: Thu, 13 Nov 2014 11:18:29 -0800 Subject: ASoC: add TI ts3a227e headset chip driver The TS3A227E is an autonomous audio accessory detection and configuration switch that detects 3-pole or 4-pole audio accessories and configures internal switches to route the signals accordingly. This chip also has built-in support for the new button standard described in the Android "Wired audio headset specification" v1.0. These buttons will be reported on the jack as buttons 0-3 mapped to KEY_MEDIA, KEY_VOLUMEUP, KEY_VOLUMEDOWN, and KEY_VOICE_COMMAND. This will be added as an aux_dev and have the jack passed in from the machine driver. Signed-off-by: Dylan Reid Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/ts3a227e.txt | 26 ++ sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/ts3a227e.c | 314 +++++++++++++++++++++ sound/soc/codecs/ts3a227e.h | 17 ++ 5 files changed, 364 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/ts3a227e.txt create mode 100644 sound/soc/codecs/ts3a227e.c create mode 100644 sound/soc/codecs/ts3a227e.h (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/ts3a227e.txt b/Documentation/devicetree/bindings/sound/ts3a227e.txt new file mode 100644 index 000000000000..e8bf23eb1803 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/ts3a227e.txt @@ -0,0 +1,26 @@ +Texas Instruments TS3A227E +Autonomous Audio Accessory Detection and Configuration Switch + +The TS3A227E detect headsets of 3-ring and 4-ring standards and +switches automatically to route the microphone correctly. It also +handles key press detection in accordance with the Android audio +headset specification v1.0. + +Required properties: + + - compatible: Should contain "ti,ts3a227e". + - reg: The i2c address. Should contain <0x3b>. + - interrupt-parent: The parent interrupt controller + - interrupts: Interrupt number for /INT pin from the 227e + + +Examples: + + i2c { + ts3a227e@3b { + compatible = "ti,ts3a227e"; + reg = <0x3b>; + interrupt-parent = <&gpio>; + interrupts = <3 IRQ_TYPE_LEVEL_LOW>; + }; + }; diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index a68d1731a8fd..243ec862c426 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -109,6 +109,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_TLV320AIC3X if I2C select SND_SOC_TPA6130A2 if I2C select SND_SOC_TLV320DAC33 if I2C + select SND_SOC_TS3A227E if I2C select SND_SOC_TWL4030 if TWL4030_CORE select SND_SOC_TWL6040 if TWL6040_CORE select SND_SOC_UDA134X @@ -607,6 +608,10 @@ config SND_SOC_TLV320AIC3X config SND_SOC_TLV320DAC33 tristate +config SND_SOC_TS3A227E + tristate "TI Headset/Mic detect and keypress chip" + depends on I2C + config SND_SOC_TWL4030 select MFD_TWL4030_AUDIO tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 5dce451661e4..a1eb7ef3b90e 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -109,6 +109,7 @@ snd-soc-tlv320aic31xx-objs := tlv320aic31xx.o snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o snd-soc-tlv320aic3x-objs := tlv320aic3x.o snd-soc-tlv320dac33-objs := tlv320dac33.o +snd-soc-ts3a227e-objs := ts3a227e.o snd-soc-twl4030-objs := twl4030.o snd-soc-twl6040-objs := twl6040.o snd-soc-uda134x-objs := uda134x.o @@ -282,6 +283,7 @@ obj-$(CONFIG_SND_SOC_TLV320AIC31XX) += snd-soc-tlv320aic31xx.o obj-$(CONFIG_SND_SOC_TLV320AIC32X4) += snd-soc-tlv320aic32x4.o obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o obj-$(CONFIG_SND_SOC_TLV320DAC33) += snd-soc-tlv320dac33.o +obj-$(CONFIG_SND_SOC_TS3A227E) += snd-soc-ts3a227e.o obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o diff --git a/sound/soc/codecs/ts3a227e.c b/sound/soc/codecs/ts3a227e.c new file mode 100644 index 000000000000..1d1205702d23 --- /dev/null +++ b/sound/soc/codecs/ts3a227e.c @@ -0,0 +1,314 @@ +/* + * TS3A227E Autonomous Audio Accessory Detection and Configuration Switch + * + * Copyright (C) 2014 Google, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +struct ts3a227e { + struct regmap *regmap; + struct snd_soc_jack *jack; + bool plugged; + bool mic_present; + unsigned int buttons_held; +}; + +/* Button values to be reported on the jack */ +static const int ts3a227e_buttons[] = { + SND_JACK_BTN_0, + SND_JACK_BTN_1, + SND_JACK_BTN_2, + SND_JACK_BTN_3, +}; + +#define TS3A227E_NUM_BUTTONS 4 +#define TS3A227E_JACK_MASK (SND_JACK_HEADPHONE | \ + SND_JACK_MICROPHONE | \ + SND_JACK_BTN_0 | \ + SND_JACK_BTN_1 | \ + SND_JACK_BTN_2 | \ + SND_JACK_BTN_3) + +/* TS3A227E registers */ +#define TS3A227E_REG_DEVICE_ID 0x00 +#define TS3A227E_REG_INTERRUPT 0x01 +#define TS3A227E_REG_KP_INTERRUPT 0x02 +#define TS3A227E_REG_INTERRUPT_DISABLE 0x03 +#define TS3A227E_REG_SETTING_1 0x04 +#define TS3A227E_REG_SETTING_2 0x05 +#define TS3A227E_REG_SETTING_3 0x06 +#define TS3A227E_REG_SWITCH_CONTROL_1 0x07 +#define TS3A227E_REG_SWITCH_CONTROL_2 0x08 +#define TS3A227E_REG_SWITCH_STATUS_1 0x09 +#define TS3A227E_REG_SWITCH_STATUS_2 0x0a +#define TS3A227E_REG_ACCESSORY_STATUS 0x0b +#define TS3A227E_REG_ADC_OUTPUT 0x0c +#define TS3A227E_REG_KP_THRESHOLD_1 0x0d +#define TS3A227E_REG_KP_THRESHOLD_2 0x0e +#define TS3A227E_REG_KP_THRESHOLD_3 0x0f + +/* TS3A227E_REG_INTERRUPT 0x01 */ +#define INS_REM_EVENT 0x01 +#define DETECTION_COMPLETE_EVENT 0x02 + +/* TS3A227E_REG_KP_INTERRUPT 0x02 */ +#define PRESS_MASK(idx) (0x01 << (2 * (idx))) +#define RELEASE_MASK(idx) (0x02 << (2 * (idx))) + +/* TS3A227E_REG_INTERRUPT_DISABLE 0x03 */ +#define INS_REM_INT_DISABLE 0x01 +#define DETECTION_COMPLETE_INT_DISABLE 0x02 +#define ADC_COMPLETE_INT_DISABLE 0x04 +#define INTB_DISABLE 0x08 + +/* TS3A227E_REG_SETTING_2 0x05 */ +#define KP_ENABLE 0x04 + +/* TS3A227E_REG_ACCESSORY_STATUS 0x0b */ +#define TYPE_3_POLE 0x01 +#define TYPE_4_POLE_OMTP 0x02 +#define TYPE_4_POLE_STANDARD 0x04 +#define JACK_INSERTED 0x08 +#define EITHER_MIC_MASK (TYPE_4_POLE_OMTP | TYPE_4_POLE_STANDARD) + +static const struct reg_default ts3a227e_reg_defaults[] = { + { TS3A227E_REG_DEVICE_ID, 0x10 }, + { TS3A227E_REG_INTERRUPT, 0x00 }, + { TS3A227E_REG_KP_INTERRUPT, 0x00 }, + { TS3A227E_REG_INTERRUPT_DISABLE, 0x08 }, + { TS3A227E_REG_SETTING_1, 0x23 }, + { TS3A227E_REG_SETTING_2, 0x00 }, + { TS3A227E_REG_SETTING_3, 0x0e }, + { TS3A227E_REG_SWITCH_CONTROL_1, 0x00 }, + { TS3A227E_REG_SWITCH_CONTROL_2, 0x00 }, + { TS3A227E_REG_SWITCH_STATUS_1, 0x0c }, + { TS3A227E_REG_SWITCH_STATUS_2, 0x00 }, + { TS3A227E_REG_ACCESSORY_STATUS, 0x00 }, + { TS3A227E_REG_ADC_OUTPUT, 0x00 }, + { TS3A227E_REG_KP_THRESHOLD_1, 0x20 }, + { TS3A227E_REG_KP_THRESHOLD_2, 0x40 }, + { TS3A227E_REG_KP_THRESHOLD_3, 0x68 }, +}; + +static bool ts3a227e_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TS3A227E_REG_DEVICE_ID ... TS3A227E_REG_KP_THRESHOLD_3: + return true; + default: + return false; + } +} + +static bool ts3a227e_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TS3A227E_REG_INTERRUPT_DISABLE ... TS3A227E_REG_SWITCH_CONTROL_2: + case TS3A227E_REG_KP_THRESHOLD_1 ... TS3A227E_REG_KP_THRESHOLD_3: + return true; + default: + return false; + } +} + +static bool ts3a227e_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TS3A227E_REG_INTERRUPT ... TS3A227E_REG_INTERRUPT_DISABLE: + case TS3A227E_REG_SETTING_2: + case TS3A227E_REG_SWITCH_STATUS_1 ... TS3A227E_REG_ADC_OUTPUT: + return true; + default: + return false; + } +} + +static void ts3a227e_jack_report(struct ts3a227e *ts3a227e) +{ + unsigned int i; + int report = 0; + + if (!ts3a227e->jack) + return; + + if (ts3a227e->plugged) + report = SND_JACK_HEADPHONE; + if (ts3a227e->mic_present) + report |= SND_JACK_MICROPHONE; + for (i = 0; i < TS3A227E_NUM_BUTTONS; i++) { + if (ts3a227e->buttons_held & (1 << i)) + report |= ts3a227e_buttons[i]; + } + snd_soc_jack_report(ts3a227e->jack, report, TS3A227E_JACK_MASK); +} + +static void ts3a227e_new_jack_state(struct ts3a227e *ts3a227e, unsigned acc_reg) +{ + bool plugged, mic_present; + + plugged = !!(acc_reg & JACK_INSERTED); + mic_present = plugged && !!(acc_reg & EITHER_MIC_MASK); + + ts3a227e->plugged = plugged; + + if (mic_present != ts3a227e->mic_present) { + ts3a227e->mic_present = mic_present; + ts3a227e->buttons_held = 0; + if (mic_present) { + /* Enable key press detection. */ + regmap_update_bits(ts3a227e->regmap, + TS3A227E_REG_SETTING_2, + KP_ENABLE, KP_ENABLE); + } + } +} + +static irqreturn_t ts3a227e_interrupt(int irq, void *data) +{ + struct ts3a227e *ts3a227e = (struct ts3a227e *)data; + struct regmap *regmap = ts3a227e->regmap; + unsigned int int_reg, kp_int_reg, acc_reg, i; + + /* Check for plug/unplug. */ + regmap_read(regmap, TS3A227E_REG_INTERRUPT, &int_reg); + if (int_reg & (DETECTION_COMPLETE_EVENT | INS_REM_EVENT)) { + regmap_read(regmap, TS3A227E_REG_ACCESSORY_STATUS, &acc_reg); + ts3a227e_new_jack_state(ts3a227e, acc_reg); + } + + /* Report any key events. */ + regmap_read(regmap, TS3A227E_REG_KP_INTERRUPT, &kp_int_reg); + for (i = 0; i < TS3A227E_NUM_BUTTONS; i++) { + if (kp_int_reg & PRESS_MASK(i)) + ts3a227e->buttons_held |= (1 << i); + if (kp_int_reg & RELEASE_MASK(i)) + ts3a227e->buttons_held &= ~(1 << i); + } + + ts3a227e_jack_report(ts3a227e); + + return IRQ_HANDLED; +} + +/** + * ts3a227e_enable_jack_detect - Specify a jack for event reporting + * + * @component: component to register the jack with + * @jack: jack to use to report headset and button events on + * + * After this function has been called the headset insert/remove and button + * events 0-3 will be routed to the given jack. Jack can be null to stop + * reporting. + */ +int ts3a227e_enable_jack_detect(struct snd_soc_component *component, + struct snd_soc_jack *jack) +{ + struct ts3a227e *ts3a227e = snd_soc_component_get_drvdata(component); + + snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_MEDIA); + snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP); + snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); + snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); + + ts3a227e->jack = jack; + ts3a227e_jack_report(ts3a227e); + + return 0; +} +EXPORT_SYMBOL_GPL(ts3a227e_enable_jack_detect); + +static struct snd_soc_component_driver ts3a227e_soc_driver; + +static const struct regmap_config ts3a227e_regmap_config = { + .val_bits = 8, + .reg_bits = 8, + + .max_register = TS3A227E_REG_KP_THRESHOLD_3, + .readable_reg = ts3a227e_readable_reg, + .writeable_reg = ts3a227e_writeable_reg, + .volatile_reg = ts3a227e_volatile_reg, + + .cache_type = REGCACHE_RBTREE, + .reg_defaults = ts3a227e_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(ts3a227e_reg_defaults), +}; + +static int ts3a227e_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct ts3a227e *ts3a227e; + struct device *dev = &i2c->dev; + int ret; + + ts3a227e = devm_kzalloc(&i2c->dev, sizeof(*ts3a227e), GFP_KERNEL); + if (ts3a227e == NULL) + return -ENOMEM; + + i2c_set_clientdata(i2c, ts3a227e); + + ts3a227e->regmap = devm_regmap_init_i2c(i2c, &ts3a227e_regmap_config); + if (IS_ERR(ts3a227e->regmap)) + return PTR_ERR(ts3a227e->regmap); + + ret = devm_request_threaded_irq(dev, i2c->irq, NULL, ts3a227e_interrupt, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + "TS3A227E", ts3a227e); + if (ret) { + dev_err(dev, "Cannot request irq %d (%d)\n", i2c->irq, ret); + return ret; + } + + ret = devm_snd_soc_register_component(&i2c->dev, &ts3a227e_soc_driver, + NULL, 0); + if (ret) + return ret; + + /* Enable interrupts except for ADC complete. */ + regmap_update_bits(ts3a227e->regmap, TS3A227E_REG_INTERRUPT_DISABLE, + INTB_DISABLE | ADC_COMPLETE_INT_DISABLE, + ADC_COMPLETE_INT_DISABLE); + + return 0; +} + +static const struct i2c_device_id ts3a227e_i2c_ids[] = { + { "ts3a227e", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ts3a227e_i2c_ids); + +static const struct of_device_id ts3a227e_of_match[] = { + { .compatible = "ti,ts3a227e", }, + { } +}; +MODULE_DEVICE_TABLE(of, ts3a227e_of_match); + +static struct i2c_driver ts3a227e_driver = { + .driver = { + .name = "ts3a227e", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(ts3a227e_of_match), + }, + .probe = ts3a227e_i2c_probe, + .id_table = ts3a227e_i2c_ids, +}; +module_i2c_driver(ts3a227e_driver); + +MODULE_DESCRIPTION("ASoC ts3a227e driver"); +MODULE_AUTHOR("Dylan Reid "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/ts3a227e.h b/sound/soc/codecs/ts3a227e.h new file mode 100644 index 000000000000..e2acf9c5bebe --- /dev/null +++ b/sound/soc/codecs/ts3a227e.h @@ -0,0 +1,17 @@ +/* + * TS3A227E Autonous Audio Accessory Detection and Configureation Switch + * + * Copyright (C) 2014 Google, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _TS3A227E_H +#define _TS3A227E_H + +int ts3a227e_enable_jack_detect(struct snd_soc_component *component, + struct snd_soc_jack *jack); + +#endif -- cgit v1.2.3-59-g8ed1b From 491374c67817796785a2403a0d7825c50a39f6ce Mon Sep 17 00:00:00 2001 From: "Joe.C" Date: Tue, 4 Nov 2014 15:30:52 +0800 Subject: dt-bindings: add more chips in documentation for Mediatek SoC Add MT8127 & MT8135 from Mediatek. Signed-off-by: Joe.C Signed-off-by: Matthias Brugger --- Documentation/devicetree/bindings/arm/mediatek.txt | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/mediatek.txt b/Documentation/devicetree/bindings/arm/mediatek.txt index fa252261dfaf..c549c1e5e7c9 100644 --- a/Documentation/devicetree/bindings/arm/mediatek.txt +++ b/Documentation/devicetree/bindings/arm/mediatek.txt @@ -1,10 +1,13 @@ -Mediatek MT6589 Platforms Device Tree Bindings +MediaTek mt65xx & mt81xx Platforms Device Tree Bindings -Boards with a SoC of the Mediatek MT6589 shall have the following property: +Boards with a MediaTek mt65xx/mt81xx SoC shall have the following property: Required root node property: -compatible: must contain "mediatek,mt6589" +compatible: Must contain one of + "mediatek,mt6589" + "mediatek,mt8127" + "mediatek,mt8135" Supported boards: @@ -12,3 +15,9 @@ Supported boards: - bq Aquaris5 smart phone: Required root node properties: - compatible = "mundoreader,bq-aquaris5", "mediatek,mt6589"; +- MTK mt8127 tablet moose EVB: + Required root node properties: + - compatible = "mediatek,mt8127-moose", "mediatek,mt8127"; +- MTK mt8135 tablet EVB: + Required root node properties: + - compatible = "mediatek,mt8135-evbp1", "mediatek,mt8135"; -- cgit v1.2.3-59-g8ed1b From 256e7653c8bac60f1ccf9e0a58cc45b01a7954b9 Mon Sep 17 00:00:00 2001 From: Howard Chen Date: Fri, 14 Nov 2014 13:14:54 +0800 Subject: dt-bindings: add documentation for Mediatek SoC This adds a DT binding documentation for the MT6592 SoC from Mediatek. Signed-off-by: Howard Chen Signed-off-by: Matthias Brugger --- Documentation/devicetree/bindings/arm/mediatek.txt | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/mediatek.txt b/Documentation/devicetree/bindings/arm/mediatek.txt index c549c1e5e7c9..3be40139cfbb 100644 --- a/Documentation/devicetree/bindings/arm/mediatek.txt +++ b/Documentation/devicetree/bindings/arm/mediatek.txt @@ -6,6 +6,7 @@ Required root node property: compatible: Must contain one of "mediatek,mt6589" + "mediatek,mt6592" "mediatek,mt8127" "mediatek,mt8135" @@ -15,6 +16,9 @@ Supported boards: - bq Aquaris5 smart phone: Required root node properties: - compatible = "mundoreader,bq-aquaris5", "mediatek,mt6589"; +- Evaluation board for MT6592: + Required root node properties: + - compatible = "mediatek,mt6592-evb", "mediatek,mt6592"; - MTK mt8127 tablet moose EVB: Required root node properties: - compatible = "mediatek,mt8127-moose", "mediatek,mt8127"; -- cgit v1.2.3-59-g8ed1b From 9ee4cd1aa3eec2f405652dc51779612104feebef Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 14 Nov 2014 13:26:47 +0100 Subject: dt-bindings: Add a clocks property to the simple-framebuffer binding A simple-framebuffer node represents a framebuffer setup by the firmware / bootloader. Such a framebuffer may have a number of clocks in use, add a property to communicate this to the OS. Signed-off-by: Hans de Goede Reviewed-by: Mike Turquette Acked-by: Geert Uytterhoeven Reviewed-by: Maxime Ripard Acked-by: Grant Likely Signed-off-by: Tomi Valkeinen --- .../devicetree/bindings/video/simple-framebuffer.txt | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/video/simple-framebuffer.txt b/Documentation/devicetree/bindings/video/simple-framebuffer.txt index 70c26f3a5b9a..8f35718f4f5b 100644 --- a/Documentation/devicetree/bindings/video/simple-framebuffer.txt +++ b/Documentation/devicetree/bindings/video/simple-framebuffer.txt @@ -1,8 +1,8 @@ Simple Framebuffer -A simple frame-buffer describes a raw memory region that may be rendered to, -with the assumption that the display hardware has already been set up to scan -out from that buffer. +A simple frame-buffer describes a frame-buffer setup by firmware or +the bootloader, with the assumption that the display hardware has already +been set up to scan out from the memory pointed to by the reg property. Required properties: - compatible: "simple-framebuffer" @@ -14,6 +14,12 @@ Required properties: - r5g6b5 (16-bit pixels, d[15:11]=r, d[10:5]=g, d[4:0]=b). - a8b8g8r8 (32-bit pixels, d[31:24]=a, d[23:16]=b, d[15:8]=g, d[7:0]=r). +Optional properties: +- clocks : List of clocks used by the framebuffer. Clocks listed here + are expected to already be configured correctly. The OS must + ensure these clocks are not modified or disabled while the + simple framebuffer remains active. + Example: framebuffer { -- cgit v1.2.3-59-g8ed1b From 9bb5b20f5d983e98d9a1cc7b7af5877b0f1c791b Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 14 Nov 2014 13:26:51 +0100 Subject: dt-bindings: simplefb: Specify node location and handoff related properties Since simplefb nodes do not relate directly to hw typically they have been placed in the root of the devicetree. As the represent runtime information having them as sub-nodes of /chosen is more logical, specify this. Also specify when to set the chosen stdout-path property to a simplefb node. For reliable handover to a hardware specific driver, that driver needs to know which simplefb to unregister when taking over, specify how the hw driver can find the matching simplefb node. Last add some advice on how to fill and use simplefb nodes from a firmware pov. Signed-off-by: Hans de Goede Acked-by: Geert Uytterhoeven Acked-by: Maxime Ripard Signed-off-by: Tomi Valkeinen --- .../bindings/video/simple-framebuffer.txt | 58 +++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/video/simple-framebuffer.txt b/Documentation/devicetree/bindings/video/simple-framebuffer.txt index 8f35718f4f5b..f8fb7e6e5609 100644 --- a/Documentation/devicetree/bindings/video/simple-framebuffer.txt +++ b/Documentation/devicetree/bindings/video/simple-framebuffer.txt @@ -4,6 +4,40 @@ A simple frame-buffer describes a frame-buffer setup by firmware or the bootloader, with the assumption that the display hardware has already been set up to scan out from the memory pointed to by the reg property. +Since simplefb nodes represent runtime information they must be sub-nodes of +the chosen node (*). Simplefb nodes must be named "framebuffer@
". + +If the devicetree contains nodes for the display hardware used by a simplefb, +then the simplefb node must contain a property called "display", which +contains a phandle pointing to the primary display hw node, so that the OS +knows which simplefb to disable when handing over control to a driver for the +real hardware. The bindings for the hw nodes must specify which node is +considered the primary node. + +It is advised to add display# aliases to help the OS determine how to number +things. If display# aliases are used, then if the simplefb node contains a +"display" property then the /aliases/display# path must point to the display +hw node the "display" property points to, otherwise it must point directly +to the simplefb node. + +If a simplefb node represents the preferred console for user interaction, +then the chosen node's stdout-path property should point to it, or to the +primary display hw node, as with display# aliases. If display aliases are +used then it should be set to the alias instead. + +It is advised that devicetree files contain pre-filled, disabled framebuffer +nodes, so that the firmware only needs to update the mode information and +enable them. This way if e.g. later on support for more display clocks get +added, the simplefb nodes will already contain this info and the firmware +does not need to be updated. + +If pre-filled framebuffer nodes are used, they should be named +"framebuffer#-", e.g. "framebuffer0-hdmi". The output should be +included in the name since different outputs typically require different +clocks and the clocks are part of the pre-populated nodes. The firmware must +rename the nodes to the standard "framebuffer@
" name using the +runtime chosen address when enabling the nodes. + Required properties: - compatible: "simple-framebuffer" - reg: Should contain the location and size of the framebuffer memory. @@ -19,14 +53,36 @@ Optional properties: are expected to already be configured correctly. The OS must ensure these clocks are not modified or disabled while the simple framebuffer remains active. +- display : phandle pointing to the primary display hardware node Example: - framebuffer { +aliases { + display0 = &lcdc0; +} + +chosen { + framebuffer0: framebuffer@1d385000 { compatible = "simple-framebuffer"; reg = <0x1d385000 (1600 * 1200 * 2)>; width = <1600>; height = <1200>; stride = <(1600 * 2)>; format = "r5g6b5"; + clocks = <&ahb_gates 36>, <&ahb_gates 43>, <&ahb_gates 44>; + display = <&lcdc0>; + }; + stdout-path = "display0"; +}; + +soc@01c00000 { + lcdc0: lcdc@1c0c000 { + compatible = "allwinner,sun4i-a10-lcdc"; + ... }; +}; + + +*) Older devicetree files may have a compatible = "simple-framebuffer" node +in a different place, operating systems must first enumerate any compatible +nodes found under chosen and then check for other compatible nodes. -- cgit v1.2.3-59-g8ed1b From b78384d5334b10139c64db1ec13ea249b92b0ef6 Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Mon, 10 Nov 2014 19:42:29 +0100 Subject: sata_rcar: Add clocks to sata_rcar bindings Now that the clocks are available in the R-Car Gen2 DT, add clocks property description to the sata_rcar bindings. The clocks have been tested on r8a7791 so we use that as an example of the R-Car SATA node. Signed-off-by: Valentine Barshak [geert: Reworded clocks property] Signed-off-by: Geert Uytterhoeven Acked-by: Simon Horman Signed-off-by: Tejun Heo --- Documentation/devicetree/bindings/ata/sata_rcar.txt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/ata/sata_rcar.txt b/Documentation/devicetree/bindings/ata/sata_rcar.txt index 80ae87a0784b..f09c1ee260ba 100644 --- a/Documentation/devicetree/bindings/ata/sata_rcar.txt +++ b/Documentation/devicetree/bindings/ata/sata_rcar.txt @@ -9,12 +9,14 @@ Required properties: - "renesas,sata-r8a7793" for R-Car M2-N - reg : address and length of the SATA registers; - interrupts : must consist of one interrupt specifier. +- clocks : must contain a reference to the functional clock. Example: -sata: sata@fc600000 { - compatible = "renesas,sata-r8a7779"; - reg = <0xfc600000 0x2000>; +sata0: sata@ee300000 { + compatible = "renesas,sata-r8a7791"; + reg = <0 0xee300000 0 0x2000>; interrupt-parent = <&gic>; - interrupts = <0 100 IRQ_TYPE_LEVEL_HIGH>; + interrupts = <0 105 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp8_clks R8A7791_CLK_SATA0>; }; -- cgit v1.2.3-59-g8ed1b From 598e9a9005ef3ad7540227c9161f7cfbdccd0dbe Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 10 Nov 2014 19:42:30 +0100 Subject: sata_rcar: Document deprecated "renesas,rcar-sata" Commit e67adb4e669db834 ("sata_rcar: Add R-Car Gen2 SATA PHY support") deprecated "renesas,rcar-sata" in favor of "renesas,sata-r8a7779", but the deprecated value was never documented in the binding documentation, while it is still in active use. Signed-off-by: Geert Uytterhoeven Acked-by: Simon Horman Signed-off-by: Tejun Heo --- Documentation/devicetree/bindings/ata/sata_rcar.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/ata/sata_rcar.txt b/Documentation/devicetree/bindings/ata/sata_rcar.txt index f09c1ee260ba..2493a5a31655 100644 --- a/Documentation/devicetree/bindings/ata/sata_rcar.txt +++ b/Documentation/devicetree/bindings/ata/sata_rcar.txt @@ -3,6 +3,7 @@ Required properties: - compatible : should contain one of the following: - "renesas,sata-r8a7779" for R-Car H1 + ("renesas,rcar-sata" is deprecated) - "renesas,sata-r8a7790-es1" for R-Car H2 ES1 - "renesas,sata-r8a7790" for R-Car H2 other than ES1 - "renesas,sata-r8a7791" for R-Car M2-W -- cgit v1.2.3-59-g8ed1b From 55b8cbf75fe714f283073048b560d30a0af13473 Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Mon, 10 Nov 2014 14:28:27 -0300 Subject: [media] v4l: Update subdev-formats doc with new MEDIA_BUS_FMT values In order to have subsytem agnostic media bus format definitions we've moved media bus definition to include/uapi/linux/media-bus-format.h and prefixed them with MEDIA_BUS_FMT instead of V4L2_MBUS_FMT. Update the v4l documentation accordingly. Signed-off-by: Boris Brezillon Acked-by: Hans Verkuil Acked-by: Sakari Ailus Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/subdev-formats.xml | 308 ++++++++++----------- 1 file changed, 154 insertions(+), 154 deletions(-) (limited to 'Documentation') diff --git a/Documentation/DocBook/media/v4l/subdev-formats.xml b/Documentation/DocBook/media/v4l/subdev-formats.xml index b2d5a0363cba..18730b96e1e6 100644 --- a/Documentation/DocBook/media/v4l/subdev-formats.xml +++ b/Documentation/DocBook/media/v4l/subdev-formats.xml @@ -86,7 +86,7 @@ green and 5-bit blue values padded on the high bit, transferred as 2 8-bit samples per pixel with the most significant bits (padding, red and half of the green value) transferred first will be named - V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE. + MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE. The following tables list existing packed RGB formats. @@ -176,8 +176,8 @@ - - V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE + + MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE 0x1001 &dash-ent-24; @@ -204,8 +204,8 @@ b1 b0 - - V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE + + MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE 0x1002 &dash-ent-24; @@ -232,8 +232,8 @@ r1 r0 - - V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE + + MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE 0x1003 &dash-ent-24; @@ -260,8 +260,8 @@ b1 b0 - - V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE + + MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE 0x1004 &dash-ent-24; @@ -288,8 +288,8 @@ g4 g3 - - V4L2_MBUS_FMT_BGR565_2X8_BE + + MEDIA_BUS_FMT_BGR565_2X8_BE 0x1005 &dash-ent-24; @@ -316,8 +316,8 @@ r1 r0 - - V4L2_MBUS_FMT_BGR565_2X8_LE + + MEDIA_BUS_FMT_BGR565_2X8_LE 0x1006 &dash-ent-24; @@ -344,8 +344,8 @@ g4 g3 - - V4L2_MBUS_FMT_RGB565_2X8_BE + + MEDIA_BUS_FMT_RGB565_2X8_BE 0x1007 &dash-ent-24; @@ -372,8 +372,8 @@ b1 b0 - - V4L2_MBUS_FMT_RGB565_2X8_LE + + MEDIA_BUS_FMT_RGB565_2X8_LE 0x1008 &dash-ent-24; @@ -400,8 +400,8 @@ g4 g3 - - V4L2_MBUS_FMT_RGB666_1X18 + + MEDIA_BUS_FMT_RGB666_1X18 0x1009 &dash-ent-14; @@ -424,8 +424,8 @@ b1 b0 - - V4L2_MBUS_FMT_RGB888_1X24 + + MEDIA_BUS_FMT_RGB888_1X24 0x100a &dash-ent-8; @@ -454,8 +454,8 @@ b1 b0 - - V4L2_MBUS_FMT_RGB888_2X12_BE + + MEDIA_BUS_FMT_RGB888_2X12_BE 0x100b &dash-ent-20; @@ -490,8 +490,8 @@ b1 b0 - - V4L2_MBUS_FMT_RGB888_2X12_LE + + MEDIA_BUS_FMT_RGB888_2X12_LE 0x100c &dash-ent-20; @@ -526,8 +526,8 @@ g5 g4 - - V4L2_MBUS_FMT_ARGB888_1X32 + + MEDIA_BUS_FMT_ARGB888_1X32 0x100d a7 @@ -600,7 +600,7 @@ For instance, a format with uncompressed 10-bit Bayer components arranged in a red, green, green, blue pattern transferred as 2 8-bit samples per pixel with the least significant bits transferred first will - be named V4L2_MBUS_FMT_SRGGB10_2X8_PADHI_LE. + be named MEDIA_BUS_FMT_SRGGB10_2X8_PADHI_LE.
@@ -663,8 +663,8 @@ - - V4L2_MBUS_FMT_SBGGR8_1X8 + + MEDIA_BUS_FMT_SBGGR8_1X8 0x3001 - @@ -680,8 +680,8 @@ b1 b0 - - V4L2_MBUS_FMT_SGBRG8_1X8 + + MEDIA_BUS_FMT_SGBRG8_1X8 0x3013 - @@ -697,8 +697,8 @@ g1 g0 - - V4L2_MBUS_FMT_SGRBG8_1X8 + + MEDIA_BUS_FMT_SGRBG8_1X8 0x3002 - @@ -714,8 +714,8 @@ g1 g0 - - V4L2_MBUS_FMT_SRGGB8_1X8 + + MEDIA_BUS_FMT_SRGGB8_1X8 0x3014 - @@ -731,8 +731,8 @@ r1 r0 - - V4L2_MBUS_FMT_SBGGR10_ALAW8_1X8 + + MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8 0x3015 - @@ -748,8 +748,8 @@ b1 b0 - - V4L2_MBUS_FMT_SGBRG10_ALAW8_1X8 + + MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8 0x3016 - @@ -765,8 +765,8 @@ g1 g0 - - V4L2_MBUS_FMT_SGRBG10_ALAW8_1X8 + + MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8 0x3017 - @@ -782,8 +782,8 @@ g1 g0 - - V4L2_MBUS_FMT_SRGGB10_ALAW8_1X8 + + MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8 0x3018 - @@ -799,8 +799,8 @@ r1 r0 - - V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8 + + MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8 0x300b - @@ -816,8 +816,8 @@ b1 b0 - - V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8 + + MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8 0x300c - @@ -833,8 +833,8 @@ g1 g0 - - V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8 + + MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8 0x3009 - @@ -850,8 +850,8 @@ g1 g0 - - V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8 + + MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8 0x300d - @@ -867,8 +867,8 @@ r1 r0 - - V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE + + MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE 0x3003 - @@ -901,8 +901,8 @@ b1 b0 - - V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE + + MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE 0x3004 - @@ -935,8 +935,8 @@ b9 b8 - - V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE + + MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE 0x3005 - @@ -969,8 +969,8 @@ 0 0 - - V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE + + MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE 0x3006 - @@ -1003,8 +1003,8 @@ b3 b2 - - V4L2_MBUS_FMT_SBGGR10_1X10 + + MEDIA_BUS_FMT_SBGGR10_1X10 0x3007 - @@ -1020,8 +1020,8 @@ b1 b0 - - V4L2_MBUS_FMT_SGBRG10_1X10 + + MEDIA_BUS_FMT_SGBRG10_1X10 0x300e - @@ -1037,8 +1037,8 @@ g1 g0 - - V4L2_MBUS_FMT_SGRBG10_1X10 + + MEDIA_BUS_FMT_SGRBG10_1X10 0x300a - @@ -1054,8 +1054,8 @@ g1 g0 - - V4L2_MBUS_FMT_SRGGB10_1X10 + + MEDIA_BUS_FMT_SRGGB10_1X10 0x300f - @@ -1071,8 +1071,8 @@ r1 r0 - - V4L2_MBUS_FMT_SBGGR12_1X12 + + MEDIA_BUS_FMT_SBGGR12_1X12 0x3008 b11 @@ -1088,8 +1088,8 @@ b1 b0 - - V4L2_MBUS_FMT_SGBRG12_1X12 + + MEDIA_BUS_FMT_SGBRG12_1X12 0x3010 g11 @@ -1105,8 +1105,8 @@ g1 g0 - - V4L2_MBUS_FMT_SGRBG12_1X12 + + MEDIA_BUS_FMT_SGRBG12_1X12 0x3011 g11 @@ -1122,8 +1122,8 @@ g1 g0 - - V4L2_MBUS_FMT_SRGGB12_1X12 + + MEDIA_BUS_FMT_SRGGB12_1X12 0x3012 r11 @@ -1175,7 +1175,7 @@ For instance, a format where pixels are encoded as 8-bit YUV values downsampled to 4:2:2 and transferred as 2 8-bit bus samples per pixel in the - U, Y, V, Y order will be named V4L2_MBUS_FMT_UYVY8_2X8. + U, Y, V, Y order will be named MEDIA_BUS_FMT_UYVY8_2X8. lists existing packed YUV @@ -1280,8 +1280,8 @@ - - V4L2_MBUS_FMT_Y8_1X8 + + MEDIA_BUS_FMT_Y8_1X8 0x2001 &dash-ent-24; @@ -1294,8 +1294,8 @@ y1 y0 - - V4L2_MBUS_FMT_UV8_1X8 + + MEDIA_BUS_FMT_UV8_1X8 0x2015 &dash-ent-24; @@ -1322,8 +1322,8 @@ v1 v0 - - V4L2_MBUS_FMT_UYVY8_1_5X8 + + MEDIA_BUS_FMT_UYVY8_1_5X8 0x2002 &dash-ent-24; @@ -1406,8 +1406,8 @@ y1 y0 - - V4L2_MBUS_FMT_VYUY8_1_5X8 + + MEDIA_BUS_FMT_VYUY8_1_5X8 0x2003 &dash-ent-24; @@ -1490,8 +1490,8 @@ y1 y0 - - V4L2_MBUS_FMT_YUYV8_1_5X8 + + MEDIA_BUS_FMT_YUYV8_1_5X8 0x2004 &dash-ent-24; @@ -1574,8 +1574,8 @@ v1 v0 - - V4L2_MBUS_FMT_YVYU8_1_5X8 + + MEDIA_BUS_FMT_YVYU8_1_5X8 0x2005 &dash-ent-24; @@ -1658,8 +1658,8 @@ u1 u0 - - V4L2_MBUS_FMT_UYVY8_2X8 + + MEDIA_BUS_FMT_UYVY8_2X8 0x2006 &dash-ent-24; @@ -1714,8 +1714,8 @@ y1 y0 - - V4L2_MBUS_FMT_VYUY8_2X8 + + MEDIA_BUS_FMT_VYUY8_2X8 0x2007 &dash-ent-24; @@ -1770,8 +1770,8 @@ y1 y0 - - V4L2_MBUS_FMT_YUYV8_2X8 + + MEDIA_BUS_FMT_YUYV8_2X8 0x2008 &dash-ent-24; @@ -1826,8 +1826,8 @@ v1 v0 - - V4L2_MBUS_FMT_YVYU8_2X8 + + MEDIA_BUS_FMT_YVYU8_2X8 0x2009 &dash-ent-24; @@ -1882,8 +1882,8 @@ u1 u0 - - V4L2_MBUS_FMT_Y10_1X10 + + MEDIA_BUS_FMT_Y10_1X10 0x200a &dash-ent-22; @@ -1898,8 +1898,8 @@ y1 y0 - - V4L2_MBUS_FMT_UYVY10_2X10 + + MEDIA_BUS_FMT_UYVY10_2X10 0x2018 &dash-ent-22; @@ -1962,8 +1962,8 @@ y1 y0 - - V4L2_MBUS_FMT_VYUY10_2X10 + + MEDIA_BUS_FMT_VYUY10_2X10 0x2019 &dash-ent-22; @@ -2026,8 +2026,8 @@ y1 y0 - - V4L2_MBUS_FMT_YUYV10_2X10 + + MEDIA_BUS_FMT_YUYV10_2X10 0x200b &dash-ent-22; @@ -2090,8 +2090,8 @@ v1 v0 - - V4L2_MBUS_FMT_YVYU10_2X10 + + MEDIA_BUS_FMT_YVYU10_2X10 0x200c &dash-ent-22; @@ -2154,8 +2154,8 @@ u1 u0 - - V4L2_MBUS_FMT_Y12_1X12 + + MEDIA_BUS_FMT_Y12_1X12 0x2013 &dash-ent-20; @@ -2172,8 +2172,8 @@ y1 y0 - - V4L2_MBUS_FMT_UYVY8_1X16 + + MEDIA_BUS_FMT_UYVY8_1X16 0x200f &dash-ent-16; @@ -2216,8 +2216,8 @@ y1 y0 - - V4L2_MBUS_FMT_VYUY8_1X16 + + MEDIA_BUS_FMT_VYUY8_1X16 0x2010 &dash-ent-16; @@ -2260,8 +2260,8 @@ y1 y0 - - V4L2_MBUS_FMT_YUYV8_1X16 + + MEDIA_BUS_FMT_YUYV8_1X16 0x2011 &dash-ent-16; @@ -2304,8 +2304,8 @@ v1 v0 - - V4L2_MBUS_FMT_YVYU8_1X16 + + MEDIA_BUS_FMT_YVYU8_1X16 0x2012 &dash-ent-16; @@ -2348,8 +2348,8 @@ u1 u0 - - V4L2_MBUS_FMT_YDYUYDYV8_1X16 + + MEDIA_BUS_FMT_YDYUYDYV8_1X16 0x2014 &dash-ent-16; @@ -2436,8 +2436,8 @@ v1 v0 - - V4L2_MBUS_FMT_UYVY10_1X20 + + MEDIA_BUS_FMT_UYVY10_1X20 0x201a &dash-ent-12; @@ -2488,8 +2488,8 @@ y1 y0 - - V4L2_MBUS_FMT_VYUY10_1X20 + + MEDIA_BUS_FMT_VYUY10_1X20 0x201b &dash-ent-12; @@ -2540,8 +2540,8 @@ y1 y0 - - V4L2_MBUS_FMT_YUYV10_1X20 + + MEDIA_BUS_FMT_YUYV10_1X20 0x200d &dash-ent-12; @@ -2592,8 +2592,8 @@ v1 v0 - - V4L2_MBUS_FMT_YVYU10_1X20 + + MEDIA_BUS_FMT_YVYU10_1X20 0x200e &dash-ent-12; @@ -2644,8 +2644,8 @@ u1 u0 - - V4L2_MBUS_FMT_YUV10_1X30 + + MEDIA_BUS_FMT_YUV10_1X30 0x2016 - @@ -2681,8 +2681,8 @@ v1 v0 - - V4L2_MBUS_FMT_AYUV8_1X32 + + MEDIA_BUS_FMT_AYUV8_1X32 0x2017 a7 @@ -2718,8 +2718,8 @@ v1 v0 - - V4L2_MBUS_FMT_UYVY12_2X12 + + MEDIA_BUS_FMT_UYVY12_2X12 0x201c &dash-ent-20; @@ -2790,8 +2790,8 @@ y1 y0 - - V4L2_MBUS_FMT_VYUY12_2X12 + + MEDIA_BUS_FMT_VYUY12_2X12 0x201d &dash-ent-20; @@ -2862,8 +2862,8 @@ y1 y0 - - V4L2_MBUS_FMT_YUYV12_2X12 + + MEDIA_BUS_FMT_YUYV12_2X12 0x201e &dash-ent-20; @@ -2934,8 +2934,8 @@ v1 v0 - - V4L2_MBUS_FMT_YVYU12_2X12 + + MEDIA_BUS_FMT_YVYU12_2X12 0x201f &dash-ent-20; @@ -3006,8 +3006,8 @@ u1 u0 - - V4L2_MBUS_FMT_UYVY12_1X24 + + MEDIA_BUS_FMT_UYVY12_1X24 0x2020 &dash-ent-8; @@ -3066,8 +3066,8 @@ y1 y0 - - V4L2_MBUS_FMT_VYUY12_1X24 + + MEDIA_BUS_FMT_VYUY12_1X24 0x2021 &dash-ent-8; @@ -3126,8 +3126,8 @@ y1 y0 - - V4L2_MBUS_FMT_YUYV12_1X24 + + MEDIA_BUS_FMT_YUYV12_1X24 0x2022 &dash-ent-8; @@ -3186,8 +3186,8 @@ v1 v0 - - V4L2_MBUS_FMT_YVYU12_1X24 + + MEDIA_BUS_FMT_YVYU12_1X24 0x2023 &dash-ent-8; @@ -3366,8 +3366,8 @@ - - V4L2_MBUS_FMT_AHSV8888_1X32 + + MEDIA_BUS_FMT_AHSV8888_1X32 0x6001 a7 @@ -3422,7 +3422,7 @@ For instance, for a JPEG baseline process and an 8-bit bus width - the format will be named V4L2_MBUS_FMT_JPEG_1X8. + the format will be named MEDIA_BUS_FMT_JPEG_1X8. The following table lists existing JPEG compressed formats. @@ -3441,8 +3441,8 @@ - - V4L2_MBUS_FMT_JPEG_1X8 + + MEDIA_BUS_FMT_JPEG_1X8 0x4001 Besides of its usage for the parallel bus this format is recommended for transmission of JPEG data over MIPI CSI bus @@ -3484,8 +3484,8 @@ interface and may change in the future. - - V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8 + + MEDIA_BUS_FMT_S5C_UYVY_JPEG_1X8 0x5001 Interleaved raw UYVY and JPEG image format with embedded -- cgit v1.2.3-59-g8ed1b From 27ffaeb0ab160852c87e2dfa505594020e9a3a06 Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Mon, 10 Nov 2014 14:28:31 -0300 Subject: [media] platform: Make use of media_bus_format enum In order to have subsytem agnostic media bus format definitions we've moved media bus definition to include/uapi/linux/media-bus-format.h and prefixed values with MEDIA_BUS_FMT instead of V4L2_MBUS_FMT. Reference new definitions in all platform drivers. Signed-off-by: Boris Brezillon Acked-by: Hans Verkuil Acked-by: Sakari Ailus Acked-by: Sekhar Nori Acked-by: Lad, Prabhakar Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/soc-camera.txt | 2 +- arch/arm/mach-davinci/board-dm355-evm.c | 2 +- arch/arm/mach-davinci/board-dm365-evm.c | 4 +- arch/arm/mach-davinci/dm355.c | 7 +- arch/arm/mach-davinci/dm365.c | 7 +- arch/arm/mach-shmobile/board-mackerel.c | 2 +- arch/sh/boards/mach-ap325rxa/setup.c | 2 +- drivers/media/platform/blackfin/bfin_capture.c | 14 +-- drivers/media/platform/davinci/vpbe.c | 2 +- drivers/media/platform/davinci/vpfe_capture.c | 4 +- drivers/media/platform/exynos-gsc/gsc-core.c | 8 +- drivers/media/platform/exynos-gsc/gsc-core.h | 2 +- drivers/media/platform/exynos4-is/fimc-capture.c | 2 +- drivers/media/platform/exynos4-is/fimc-core.c | 14 +-- drivers/media/platform/exynos4-is/fimc-core.h | 4 +- drivers/media/platform/exynos4-is/fimc-isp.c | 16 +-- drivers/media/platform/exynos4-is/fimc-lite-reg.c | 26 ++--- drivers/media/platform/exynos4-is/fimc-lite.c | 14 +-- drivers/media/platform/exynos4-is/fimc-reg.c | 14 +-- drivers/media/platform/exynos4-is/mipi-csis.c | 14 +-- drivers/media/platform/marvell-ccic/mcam-core.c | 21 ++-- drivers/media/platform/marvell-ccic/mcam-core.h | 2 +- drivers/media/platform/omap3isp/ispccdc.c | 112 ++++++++++----------- drivers/media/platform/omap3isp/ispccp2.c | 18 ++-- drivers/media/platform/omap3isp/ispcsi2.c | 42 ++++---- drivers/media/platform/omap3isp/isppreview.c | 60 ++++++----- drivers/media/platform/omap3isp/ispresizer.c | 19 ++-- drivers/media/platform/omap3isp/ispvideo.c | 95 +++++++++-------- drivers/media/platform/omap3isp/ispvideo.h | 10 +- drivers/media/platform/s3c-camif/camif-capture.c | 10 +- drivers/media/platform/s3c-camif/camif-regs.c | 8 +- drivers/media/platform/s5p-tv/hdmi_drv.c | 2 +- drivers/media/platform/s5p-tv/sdo_drv.c | 2 +- drivers/media/platform/sh_vou.c | 8 +- drivers/media/platform/soc_camera/atmel-isi.c | 22 ++-- drivers/media/platform/soc_camera/mx2_camera.c | 26 +++-- drivers/media/platform/soc_camera/mx3_camera.c | 6 +- drivers/media/platform/soc_camera/omap1_camera.c | 36 +++---- drivers/media/platform/soc_camera/pxa_camera.c | 16 +-- drivers/media/platform/soc_camera/rcar_vin.c | 14 +-- .../platform/soc_camera/sh_mobile_ceu_camera.c | 20 ++-- drivers/media/platform/soc_camera/sh_mobile_csi2.c | 38 +++---- drivers/media/platform/soc_camera/soc_camera.c | 2 +- .../platform/soc_camera/soc_camera_platform.c | 2 +- drivers/media/platform/soc_camera/soc_mediabus.c | 78 +++++++------- drivers/media/platform/via-camera.c | 8 +- drivers/media/platform/vsp1/vsp1_bru.c | 14 +-- drivers/media/platform/vsp1/vsp1_hsit.c | 12 +-- drivers/media/platform/vsp1/vsp1_lif.c | 10 +- drivers/media/platform/vsp1/vsp1_lut.c | 14 +-- drivers/media/platform/vsp1/vsp1_rwpf.c | 10 +- drivers/media/platform/vsp1/vsp1_sru.c | 12 +-- drivers/media/platform/vsp1/vsp1_uds.c | 10 +- drivers/media/platform/vsp1/vsp1_video.c | 42 ++++---- include/media/davinci/vpbe.h | 2 +- include/media/davinci/vpbe_venc.h | 5 +- include/media/exynos-fimc.h | 2 +- include/media/soc_camera.h | 2 +- include/media/soc_mediabus.h | 6 +- 59 files changed, 483 insertions(+), 495 deletions(-) (limited to 'Documentation') diff --git a/Documentation/video4linux/soc-camera.txt b/Documentation/video4linux/soc-camera.txt index daa9e2ac162c..84f41cf1f3e8 100644 --- a/Documentation/video4linux/soc-camera.txt +++ b/Documentation/video4linux/soc-camera.txt @@ -151,7 +151,7 @@ they are transferred over a media bus. Soc-camera provides support to conveniently manage these formats. A table of standard transformations is maintained by soc-camera core, which describes, what FOURCC pixel format will be obtained, if a media-bus pixel format is stored in memory according to -certain rules. E.g. if V4L2_MBUS_FMT_YUYV8_2X8 data is sampled with 8 bits per +certain rules. E.g. if MEDIA_BUS_FMT_YUYV8_2X8 data is sampled with 8 bits per sample and stored in memory in the little-endian order with no gaps between bytes, data in memory will represent the V4L2_PIX_FMT_YUYV FOURCC format. These standard transformations will be used by soc-camera or by camera host drivers to diff --git a/arch/arm/mach-davinci/board-dm355-evm.c b/arch/arm/mach-davinci/board-dm355-evm.c index 06d63d5651f3..b46b4d25f93e 100644 --- a/arch/arm/mach-davinci/board-dm355-evm.c +++ b/arch/arm/mach-davinci/board-dm355-evm.c @@ -294,7 +294,7 @@ static struct vpbe_output dm355evm_vpbe_outputs[] = { .default_mode = "ntsc", .num_modes = ARRAY_SIZE(dm355evm_enc_preset_timing), .modes = dm355evm_enc_preset_timing, - .if_params = V4L2_MBUS_FMT_FIXED, + .if_params = MEDIA_BUS_FMT_FIXED, }, }; diff --git a/arch/arm/mach-davinci/board-dm365-evm.c b/arch/arm/mach-davinci/board-dm365-evm.c index e08a8684ead2..a756003595e9 100644 --- a/arch/arm/mach-davinci/board-dm365-evm.c +++ b/arch/arm/mach-davinci/board-dm365-evm.c @@ -485,7 +485,7 @@ static struct vpbe_output dm365evm_vpbe_outputs[] = { .default_mode = "ntsc", .num_modes = ARRAY_SIZE(dm365evm_enc_std_timing), .modes = dm365evm_enc_std_timing, - .if_params = V4L2_MBUS_FMT_FIXED, + .if_params = MEDIA_BUS_FMT_FIXED, }, { .output = { @@ -498,7 +498,7 @@ static struct vpbe_output dm365evm_vpbe_outputs[] = { .default_mode = "480p59_94", .num_modes = ARRAY_SIZE(dm365evm_enc_preset_timing), .modes = dm365evm_enc_preset_timing, - .if_params = V4L2_MBUS_FMT_FIXED, + .if_params = MEDIA_BUS_FMT_FIXED, }, }; diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c index 2f3ed3a58d57..9cbeda798584 100644 --- a/arch/arm/mach-davinci/dm355.c +++ b/arch/arm/mach-davinci/dm355.c @@ -785,14 +785,13 @@ static struct resource dm355_v4l2_disp_resources[] = { }, }; -static int dm355_vpbe_setup_pinmux(enum v4l2_mbus_pixelcode if_type, - int field) +static int dm355_vpbe_setup_pinmux(u32 if_type, int field) { switch (if_type) { - case V4L2_MBUS_FMT_SGRBG8_1X8: + case MEDIA_BUS_FMT_SGRBG8_1X8: davinci_cfg_reg(DM355_VOUT_FIELD_G70); break; - case V4L2_MBUS_FMT_YUYV10_1X20: + case MEDIA_BUS_FMT_YUYV10_1X20: if (field) davinci_cfg_reg(DM355_VOUT_FIELD); else diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c index 0ae8114f5cc9..e3a3c54b6832 100644 --- a/arch/arm/mach-davinci/dm365.c +++ b/arch/arm/mach-davinci/dm365.c @@ -1306,16 +1306,15 @@ static struct resource dm365_v4l2_disp_resources[] = { }, }; -static int dm365_vpbe_setup_pinmux(enum v4l2_mbus_pixelcode if_type, - int field) +static int dm365_vpbe_setup_pinmux(u32 if_type, int field) { switch (if_type) { - case V4L2_MBUS_FMT_SGRBG8_1X8: + case MEDIA_BUS_FMT_SGRBG8_1X8: davinci_cfg_reg(DM365_VOUT_FIELD_G81); davinci_cfg_reg(DM365_VOUT_COUTL_EN); davinci_cfg_reg(DM365_VOUT_COUTH_EN); break; - case V4L2_MBUS_FMT_YUYV10_1X20: + case MEDIA_BUS_FMT_YUYV10_1X20: if (field) davinci_cfg_reg(DM365_VOUT_FIELD); else diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c index ca5d34b92aa7..a673624878d1 100644 --- a/arch/arm/mach-shmobile/board-mackerel.c +++ b/arch/arm/mach-shmobile/board-mackerel.c @@ -1153,7 +1153,7 @@ static struct soc_camera_platform_info camera_info = { .format_name = "UYVY", .format_depth = 16, .format = { - .code = V4L2_MBUS_FMT_UYVY8_2X8, + .code = MEDIA_BUS_FMT_UYVY8_2X8, .colorspace = V4L2_COLORSPACE_SMPTE170M, .field = V4L2_FIELD_NONE, .width = 640, diff --git a/arch/sh/boards/mach-ap325rxa/setup.c b/arch/sh/boards/mach-ap325rxa/setup.c index 5620e33c18a0..d4b01d4cc102 100644 --- a/arch/sh/boards/mach-ap325rxa/setup.c +++ b/arch/sh/boards/mach-ap325rxa/setup.c @@ -338,7 +338,7 @@ static struct soc_camera_platform_info camera_info = { .format_name = "UYVY", .format_depth = 16, .format = { - .code = V4L2_MBUS_FMT_UYVY8_2X8, + .code = MEDIA_BUS_FMT_UYVY8_2X8, .colorspace = V4L2_COLORSPACE_SMPTE170M, .field = V4L2_FIELD_NONE, .width = 640, diff --git a/drivers/media/platform/blackfin/bfin_capture.c b/drivers/media/platform/blackfin/bfin_capture.c index 9b5daa65841c..b3345b37bb10 100644 --- a/drivers/media/platform/blackfin/bfin_capture.c +++ b/drivers/media/platform/blackfin/bfin_capture.c @@ -49,7 +49,7 @@ struct bcap_format { char *desc; u32 pixelformat; - enum v4l2_mbus_pixelcode mbus_code; + u32 mbus_code; int bpp; /* bits per pixel */ int dlen; /* data length for ppi in bits */ }; @@ -116,35 +116,35 @@ static const struct bcap_format bcap_formats[] = { { .desc = "YCbCr 4:2:2 Interleaved UYVY", .pixelformat = V4L2_PIX_FMT_UYVY, - .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8, + .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8, .bpp = 16, .dlen = 8, }, { .desc = "YCbCr 4:2:2 Interleaved YUYV", .pixelformat = V4L2_PIX_FMT_YUYV, - .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8, + .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, .bpp = 16, .dlen = 8, }, { .desc = "YCbCr 4:2:2 Interleaved UYVY", .pixelformat = V4L2_PIX_FMT_UYVY, - .mbus_code = V4L2_MBUS_FMT_UYVY8_1X16, + .mbus_code = MEDIA_BUS_FMT_UYVY8_1X16, .bpp = 16, .dlen = 16, }, { .desc = "RGB 565", .pixelformat = V4L2_PIX_FMT_RGB565, - .mbus_code = V4L2_MBUS_FMT_RGB565_2X8_LE, + .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE, .bpp = 16, .dlen = 8, }, { .desc = "RGB 444", .pixelformat = V4L2_PIX_FMT_RGB444, - .mbus_code = V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE, + .mbus_code = MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE, .bpp = 16, .dlen = 8, }, @@ -161,7 +161,7 @@ static struct bcap_buffer *to_bcap_vb(struct vb2_buffer *vb) static int bcap_init_sensor_formats(struct bcap_device *bcap_dev) { - enum v4l2_mbus_pixelcode code; + u32 code; struct bcap_format *sf; unsigned int num_formats = 0; int i, j; diff --git a/drivers/media/platform/davinci/vpbe.c b/drivers/media/platform/davinci/vpbe.c index e5df9916b2a1..244d3d6c244c 100644 --- a/drivers/media/platform/davinci/vpbe.c +++ b/drivers/media/platform/davinci/vpbe.c @@ -227,7 +227,7 @@ static int vpbe_set_output(struct vpbe_device *vpbe_dev, int index) vpbe_current_encoder_info(vpbe_dev); struct vpbe_config *cfg = vpbe_dev->cfg; struct venc_platform_data *venc_device = vpbe_dev->venc_device; - enum v4l2_mbus_pixelcode if_params; + u32 if_params; int enc_out_index; int sd_index; int ret = 0; diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index de55f47a77db..3d0e3ae1795c 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -414,13 +414,13 @@ static int vpfe_config_image_format(struct vpfe_device *vpfe_dev, /* assume V4L2_PIX_FMT_UYVY as default */ pix->pixelformat = V4L2_PIX_FMT_UYVY; v4l2_fill_mbus_format(&mbus_fmt, pix, - V4L2_MBUS_FMT_YUYV10_2X10); + MEDIA_BUS_FMT_YUYV10_2X10); } else { pix->field = V4L2_FIELD_NONE; /* assume V4L2_PIX_FMT_SBGGR8 */ pix->pixelformat = V4L2_PIX_FMT_SBGGR8; v4l2_fill_mbus_format(&mbus_fmt, pix, - V4L2_MBUS_FMT_SBGGR8_1X8); + MEDIA_BUS_FMT_SBGGR8_1X8); } /* if sub device supports g_mbus_fmt, override the defaults */ diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c index b4c9f1d08968..91d226b8fe5c 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.c +++ b/drivers/media/platform/exynos-gsc/gsc-core.c @@ -54,7 +54,7 @@ static const struct gsc_fmt gsc_formats[] = { .corder = GSC_CBCR, .num_planes = 1, .num_comp = 1, - .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8, + .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, }, { .name = "YUV 4:2:2 packed, CbYCrY", .pixelformat = V4L2_PIX_FMT_UYVY, @@ -64,7 +64,7 @@ static const struct gsc_fmt gsc_formats[] = { .corder = GSC_CBCR, .num_planes = 1, .num_comp = 1, - .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8, + .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8, }, { .name = "YUV 4:2:2 packed, CrYCbY", .pixelformat = V4L2_PIX_FMT_VYUY, @@ -74,7 +74,7 @@ static const struct gsc_fmt gsc_formats[] = { .corder = GSC_CRCB, .num_planes = 1, .num_comp = 1, - .mbus_code = V4L2_MBUS_FMT_VYUY8_2X8, + .mbus_code = MEDIA_BUS_FMT_VYUY8_2X8, }, { .name = "YUV 4:2:2 packed, YCrYCb", .pixelformat = V4L2_PIX_FMT_YVYU, @@ -84,7 +84,7 @@ static const struct gsc_fmt gsc_formats[] = { .corder = GSC_CRCB, .num_planes = 1, .num_comp = 1, - .mbus_code = V4L2_MBUS_FMT_YVYU8_2X8, + .mbus_code = MEDIA_BUS_FMT_YVYU8_2X8, }, { .name = "YUV 4:4:4 planar, YCbYCr", .pixelformat = V4L2_PIX_FMT_YUV32, diff --git a/drivers/media/platform/exynos-gsc/gsc-core.h b/drivers/media/platform/exynos-gsc/gsc-core.h index ef0a6564cef9..0abdb17fb19c 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.h +++ b/drivers/media/platform/exynos-gsc/gsc-core.h @@ -117,7 +117,7 @@ enum gsc_yuv_fmt { * @flags: flags indicating which operation mode format applies to */ struct gsc_fmt { - enum v4l2_mbus_pixelcode mbus_code; + u32 mbus_code; char *name; u32 pixelformat; u32 color; diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c index 3d2babd5067a..8a2fd8c33d42 100644 --- a/drivers/media/platform/exynos4-is/fimc-capture.c +++ b/drivers/media/platform/exynos4-is/fimc-capture.c @@ -749,7 +749,7 @@ static int fimc_cap_enum_fmt_mplane(struct file *file, void *priv, return -EINVAL; strncpy(f->description, fmt->name, sizeof(f->description) - 1); f->pixelformat = fmt->fourcc; - if (fmt->fourcc == V4L2_MBUS_FMT_JPEG_1X8) + if (fmt->fourcc == MEDIA_BUS_FMT_JPEG_1X8) f->flags |= V4L2_FMT_FLAG_COMPRESSED; return 0; } diff --git a/drivers/media/platform/exynos4-is/fimc-core.c b/drivers/media/platform/exynos4-is/fimc-core.c index aee92d908e49..dbd74d8dc2a8 100644 --- a/drivers/media/platform/exynos4-is/fimc-core.c +++ b/drivers/media/platform/exynos4-is/fimc-core.c @@ -81,7 +81,7 @@ static struct fimc_fmt fimc_formats[] = { .flags = FMT_FLAGS_M2M_OUT | FMT_HAS_ALPHA, }, { .name = "YUV 4:4:4", - .mbus_code = V4L2_MBUS_FMT_YUV10_1X30, + .mbus_code = MEDIA_BUS_FMT_YUV10_1X30, .flags = FMT_FLAGS_WRITEBACK, }, { .name = "YUV 4:2:2 packed, YCbYCr", @@ -90,7 +90,7 @@ static struct fimc_fmt fimc_formats[] = { .color = FIMC_FMT_YCBYCR422, .memplanes = 1, .colplanes = 1, - .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8, + .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM, }, { .name = "YUV 4:2:2 packed, CbYCrY", @@ -99,7 +99,7 @@ static struct fimc_fmt fimc_formats[] = { .color = FIMC_FMT_CBYCRY422, .memplanes = 1, .colplanes = 1, - .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8, + .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8, .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM, }, { .name = "YUV 4:2:2 packed, CrYCbY", @@ -108,7 +108,7 @@ static struct fimc_fmt fimc_formats[] = { .color = FIMC_FMT_CRYCBY422, .memplanes = 1, .colplanes = 1, - .mbus_code = V4L2_MBUS_FMT_VYUY8_2X8, + .mbus_code = MEDIA_BUS_FMT_VYUY8_2X8, .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM, }, { .name = "YUV 4:2:2 packed, YCrYCb", @@ -117,7 +117,7 @@ static struct fimc_fmt fimc_formats[] = { .color = FIMC_FMT_YCRYCB422, .memplanes = 1, .colplanes = 1, - .mbus_code = V4L2_MBUS_FMT_YVYU8_2X8, + .mbus_code = MEDIA_BUS_FMT_YVYU8_2X8, .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM, }, { .name = "YUV 4:2:2 planar, Y/Cb/Cr", @@ -190,7 +190,7 @@ static struct fimc_fmt fimc_formats[] = { .depth = { 8 }, .memplanes = 1, .colplanes = 1, - .mbus_code = V4L2_MBUS_FMT_JPEG_1X8, + .mbus_code = MEDIA_BUS_FMT_JPEG_1X8, .flags = FMT_FLAGS_CAM | FMT_FLAGS_COMPRESSED, }, { .name = "S5C73MX interleaved UYVY/JPEG", @@ -200,7 +200,7 @@ static struct fimc_fmt fimc_formats[] = { .memplanes = 2, .colplanes = 1, .mdataplanes = 0x2, /* plane 1 holds frame meta data */ - .mbus_code = V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8, + .mbus_code = MEDIA_BUS_FMT_S5C_UYVY_JPEG_1X8, .flags = FMT_FLAGS_CAM | FMT_FLAGS_COMPRESSED, }, }; diff --git a/drivers/media/platform/exynos4-is/fimc-core.h b/drivers/media/platform/exynos4-is/fimc-core.h index 6c75c6ced1f7..7328f0845065 100644 --- a/drivers/media/platform/exynos4-is/fimc-core.h +++ b/drivers/media/platform/exynos4-is/fimc-core.h @@ -579,8 +579,8 @@ static inline bool fimc_jpeg_fourcc(u32 pixelformat) static inline bool fimc_user_defined_mbus_fmt(u32 code) { - return (code == V4L2_MBUS_FMT_JPEG_1X8 || - code == V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8); + return (code == MEDIA_BUS_FMT_JPEG_1X8 || + code == MEDIA_BUS_FMT_S5C_UYVY_JPEG_1X8); } /* Return the alpha component bit mask */ diff --git a/drivers/media/platform/exynos4-is/fimc-isp.c b/drivers/media/platform/exynos4-is/fimc-isp.c index be62d6b9ac48..60c744915549 100644 --- a/drivers/media/platform/exynos4-is/fimc-isp.c +++ b/drivers/media/platform/exynos4-is/fimc-isp.c @@ -41,21 +41,21 @@ static const struct fimc_fmt fimc_isp_formats[FIMC_ISP_NUM_FORMATS] = { .depth = { 8 }, .color = FIMC_FMT_RAW8, .memplanes = 1, - .mbus_code = V4L2_MBUS_FMT_SGRBG8_1X8, + .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, }, { .name = "RAW10 (GRBG)", .fourcc = V4L2_PIX_FMT_SGRBG10, .depth = { 10 }, .color = FIMC_FMT_RAW10, .memplanes = 1, - .mbus_code = V4L2_MBUS_FMT_SGRBG10_1X10, + .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, }, { .name = "RAW12 (GRBG)", .fourcc = V4L2_PIX_FMT_SGRBG12, .depth = { 12 }, .color = FIMC_FMT_RAW12, .memplanes = 1, - .mbus_code = V4L2_MBUS_FMT_SGRBG12_1X12, + .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12, }, }; @@ -149,7 +149,7 @@ static int fimc_isp_subdev_get_fmt(struct v4l2_subdev *sd, if (fmt->pad == FIMC_ISP_SD_PAD_SRC_FIFO) { mf->colorspace = V4L2_COLORSPACE_JPEG; - mf->code = V4L2_MBUS_FMT_YUV10_1X30; + mf->code = MEDIA_BUS_FMT_YUV10_1X30; } } @@ -175,7 +175,7 @@ static void __isp_subdev_try_format(struct fimc_isp *isp, FIMC_ISP_SINK_WIDTH_MAX, 0, &mf->height, FIMC_ISP_SINK_HEIGHT_MIN, FIMC_ISP_SINK_HEIGHT_MAX, 0, 0); - mf->code = V4L2_MBUS_FMT_SGRBG10_1X10; + mf->code = MEDIA_BUS_FMT_SGRBG10_1X10; } else { if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) format = v4l2_subdev_get_try_format(fh, @@ -188,7 +188,7 @@ static void __isp_subdev_try_format(struct fimc_isp *isp, mf->height = format->height - FIMC_ISP_CAC_MARGIN_HEIGHT; if (fmt->pad == FIMC_ISP_SD_PAD_SRC_FIFO) { - mf->code = V4L2_MBUS_FMT_YUV10_1X30; + mf->code = MEDIA_BUS_FMT_YUV10_1X30; mf->colorspace = V4L2_COLORSPACE_JPEG; } else { mf->code = format->code; @@ -680,11 +680,11 @@ static void __isp_subdev_set_default_format(struct fimc_isp *isp) FIMC_ISP_CAC_MARGIN_WIDTH; isp->sink_fmt.height = DEFAULT_PREVIEW_STILL_HEIGHT + FIMC_ISP_CAC_MARGIN_HEIGHT; - isp->sink_fmt.code = V4L2_MBUS_FMT_SGRBG10_1X10; + isp->sink_fmt.code = MEDIA_BUS_FMT_SGRBG10_1X10; isp->src_fmt.width = DEFAULT_PREVIEW_STILL_WIDTH; isp->src_fmt.height = DEFAULT_PREVIEW_STILL_HEIGHT; - isp->src_fmt.code = V4L2_MBUS_FMT_SGRBG10_1X10; + isp->src_fmt.code = MEDIA_BUS_FMT_SGRBG10_1X10; __is_set_frame_size(is, &isp->src_fmt); } diff --git a/drivers/media/platform/exynos4-is/fimc-lite-reg.c b/drivers/media/platform/exynos4-is/fimc-lite-reg.c index bc3ec7d25a32..0477716a20db 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite-reg.c +++ b/drivers/media/platform/exynos4-is/fimc-lite-reg.c @@ -112,24 +112,24 @@ void flite_hw_set_test_pattern(struct fimc_lite *dev, bool on) } static const u32 src_pixfmt_map[8][3] = { - { V4L2_MBUS_FMT_YUYV8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_YCBYCR, + { MEDIA_BUS_FMT_YUYV8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_YCBYCR, FLITE_REG_CIGCTRL_YUV422_1P }, - { V4L2_MBUS_FMT_YVYU8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_YCRYCB, + { MEDIA_BUS_FMT_YVYU8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_YCRYCB, FLITE_REG_CIGCTRL_YUV422_1P }, - { V4L2_MBUS_FMT_UYVY8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_CBYCRY, + { MEDIA_BUS_FMT_UYVY8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_CBYCRY, FLITE_REG_CIGCTRL_YUV422_1P }, - { V4L2_MBUS_FMT_VYUY8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_CRYCBY, + { MEDIA_BUS_FMT_VYUY8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_CRYCBY, FLITE_REG_CIGCTRL_YUV422_1P }, - { V4L2_MBUS_FMT_SGRBG8_1X8, 0, FLITE_REG_CIGCTRL_RAW8 }, - { V4L2_MBUS_FMT_SGRBG10_1X10, 0, FLITE_REG_CIGCTRL_RAW10 }, - { V4L2_MBUS_FMT_SGRBG12_1X12, 0, FLITE_REG_CIGCTRL_RAW12 }, - { V4L2_MBUS_FMT_JPEG_1X8, 0, FLITE_REG_CIGCTRL_USER(1) }, + { MEDIA_BUS_FMT_SGRBG8_1X8, 0, FLITE_REG_CIGCTRL_RAW8 }, + { MEDIA_BUS_FMT_SGRBG10_1X10, 0, FLITE_REG_CIGCTRL_RAW10 }, + { MEDIA_BUS_FMT_SGRBG12_1X12, 0, FLITE_REG_CIGCTRL_RAW12 }, + { MEDIA_BUS_FMT_JPEG_1X8, 0, FLITE_REG_CIGCTRL_USER(1) }, }; /* Set camera input pixel format and resolution */ void flite_hw_set_source_format(struct fimc_lite *dev, struct flite_frame *f) { - enum v4l2_mbus_pixelcode pixelcode = f->fmt->mbus_code; + u32 pixelcode = f->fmt->mbus_code; int i = ARRAY_SIZE(src_pixfmt_map); u32 cfg; @@ -232,10 +232,10 @@ static void flite_hw_set_pack12(struct fimc_lite *dev, int on) static void flite_hw_set_out_order(struct fimc_lite *dev, struct flite_frame *f) { static const u32 pixcode[4][2] = { - { V4L2_MBUS_FMT_YUYV8_2X8, FLITE_REG_CIODMAFMT_YCBYCR }, - { V4L2_MBUS_FMT_YVYU8_2X8, FLITE_REG_CIODMAFMT_YCRYCB }, - { V4L2_MBUS_FMT_UYVY8_2X8, FLITE_REG_CIODMAFMT_CBYCRY }, - { V4L2_MBUS_FMT_VYUY8_2X8, FLITE_REG_CIODMAFMT_CRYCBY }, + { MEDIA_BUS_FMT_YUYV8_2X8, FLITE_REG_CIODMAFMT_YCBYCR }, + { MEDIA_BUS_FMT_YVYU8_2X8, FLITE_REG_CIODMAFMT_YCRYCB }, + { MEDIA_BUS_FMT_UYVY8_2X8, FLITE_REG_CIODMAFMT_CBYCRY }, + { MEDIA_BUS_FMT_VYUY8_2X8, FLITE_REG_CIODMAFMT_CRYCBY }, }; u32 cfg = readl(dev->regs + FLITE_REG_CIODMAFMT); int i = ARRAY_SIZE(pixcode); diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c index a97d2352f1d7..b7dca8b2d455 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/exynos4-is/fimc-lite.c @@ -48,7 +48,7 @@ static const struct fimc_fmt fimc_lite_formats[] = { .depth = { 16 }, .color = FIMC_FMT_YCBYCR422, .memplanes = 1, - .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8, + .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, .flags = FMT_FLAGS_YUV, }, { .name = "YUV 4:2:2 packed, CbYCrY", @@ -57,7 +57,7 @@ static const struct fimc_fmt fimc_lite_formats[] = { .depth = { 16 }, .color = FIMC_FMT_CBYCRY422, .memplanes = 1, - .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8, + .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8, .flags = FMT_FLAGS_YUV, }, { .name = "YUV 4:2:2 packed, CrYCbY", @@ -66,7 +66,7 @@ static const struct fimc_fmt fimc_lite_formats[] = { .depth = { 16 }, .color = FIMC_FMT_CRYCBY422, .memplanes = 1, - .mbus_code = V4L2_MBUS_FMT_VYUY8_2X8, + .mbus_code = MEDIA_BUS_FMT_VYUY8_2X8, .flags = FMT_FLAGS_YUV, }, { .name = "YUV 4:2:2 packed, YCrYCb", @@ -75,7 +75,7 @@ static const struct fimc_fmt fimc_lite_formats[] = { .depth = { 16 }, .color = FIMC_FMT_YCRYCB422, .memplanes = 1, - .mbus_code = V4L2_MBUS_FMT_YVYU8_2X8, + .mbus_code = MEDIA_BUS_FMT_YVYU8_2X8, .flags = FMT_FLAGS_YUV, }, { .name = "RAW8 (GRBG)", @@ -84,7 +84,7 @@ static const struct fimc_fmt fimc_lite_formats[] = { .depth = { 8 }, .color = FIMC_FMT_RAW8, .memplanes = 1, - .mbus_code = V4L2_MBUS_FMT_SGRBG8_1X8, + .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, .flags = FMT_FLAGS_RAW_BAYER, }, { .name = "RAW10 (GRBG)", @@ -93,7 +93,7 @@ static const struct fimc_fmt fimc_lite_formats[] = { .depth = { 16 }, .color = FIMC_FMT_RAW10, .memplanes = 1, - .mbus_code = V4L2_MBUS_FMT_SGRBG10_1X10, + .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, .flags = FMT_FLAGS_RAW_BAYER, }, { .name = "RAW12 (GRBG)", @@ -102,7 +102,7 @@ static const struct fimc_fmt fimc_lite_formats[] = { .depth = { 16 }, .color = FIMC_FMT_RAW12, .memplanes = 1, - .mbus_code = V4L2_MBUS_FMT_SGRBG12_1X12, + .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12, .flags = FMT_FLAGS_RAW_BAYER, }, }; diff --git a/drivers/media/platform/exynos4-is/fimc-reg.c b/drivers/media/platform/exynos4-is/fimc-reg.c index 2d77fd8f440a..df0cbcb69b6b 100644 --- a/drivers/media/platform/exynos4-is/fimc-reg.c +++ b/drivers/media/platform/exynos4-is/fimc-reg.c @@ -592,10 +592,10 @@ struct mbus_pixfmt_desc { }; static const struct mbus_pixfmt_desc pix_desc[] = { - { V4L2_MBUS_FMT_YUYV8_2X8, FIMC_REG_CISRCFMT_ORDER422_YCBYCR, 8 }, - { V4L2_MBUS_FMT_YVYU8_2X8, FIMC_REG_CISRCFMT_ORDER422_YCRYCB, 8 }, - { V4L2_MBUS_FMT_VYUY8_2X8, FIMC_REG_CISRCFMT_ORDER422_CRYCBY, 8 }, - { V4L2_MBUS_FMT_UYVY8_2X8, FIMC_REG_CISRCFMT_ORDER422_CBYCRY, 8 }, + { MEDIA_BUS_FMT_YUYV8_2X8, FIMC_REG_CISRCFMT_ORDER422_YCBYCR, 8 }, + { MEDIA_BUS_FMT_YVYU8_2X8, FIMC_REG_CISRCFMT_ORDER422_YCRYCB, 8 }, + { MEDIA_BUS_FMT_VYUY8_2X8, FIMC_REG_CISRCFMT_ORDER422_CRYCBY, 8 }, + { MEDIA_BUS_FMT_UYVY8_2X8, FIMC_REG_CISRCFMT_ORDER422_CBYCRY, 8 }, }; int fimc_hw_set_camera_source(struct fimc_dev *fimc, @@ -689,11 +689,11 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc, /* TODO: add remaining supported formats. */ switch (vid_cap->ci_fmt.code) { - case V4L2_MBUS_FMT_VYUY8_2X8: + case MEDIA_BUS_FMT_VYUY8_2X8: tmp = FIMC_REG_CSIIMGFMT_YCBCR422_8BIT; break; - case V4L2_MBUS_FMT_JPEG_1X8: - case V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8: + case MEDIA_BUS_FMT_JPEG_1X8: + case MEDIA_BUS_FMT_S5C_UYVY_JPEG_1X8: tmp = FIMC_REG_CSIIMGFMT_USER(1); cfg |= FIMC_REG_CIGCTRL_CAM_JPEG; break; diff --git a/drivers/media/platform/exynos4-is/mipi-csis.c b/drivers/media/platform/exynos4-is/mipi-csis.c index db6fd14d1936..2f3fdfba1a45 100644 --- a/drivers/media/platform/exynos4-is/mipi-csis.c +++ b/drivers/media/platform/exynos4-is/mipi-csis.c @@ -238,34 +238,34 @@ struct csis_state { */ struct csis_pix_format { unsigned int pix_width_alignment; - enum v4l2_mbus_pixelcode code; + u32 code; u32 fmt_reg; u8 data_alignment; }; static const struct csis_pix_format s5pcsis_formats[] = { { - .code = V4L2_MBUS_FMT_VYUY8_2X8, + .code = MEDIA_BUS_FMT_VYUY8_2X8, .fmt_reg = S5PCSIS_CFG_FMT_YCBCR422_8BIT, .data_alignment = 32, }, { - .code = V4L2_MBUS_FMT_JPEG_1X8, + .code = MEDIA_BUS_FMT_JPEG_1X8, .fmt_reg = S5PCSIS_CFG_FMT_USER(1), .data_alignment = 32, }, { - .code = V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8, + .code = MEDIA_BUS_FMT_S5C_UYVY_JPEG_1X8, .fmt_reg = S5PCSIS_CFG_FMT_USER(1), .data_alignment = 32, }, { - .code = V4L2_MBUS_FMT_SGRBG8_1X8, + .code = MEDIA_BUS_FMT_SGRBG8_1X8, .fmt_reg = S5PCSIS_CFG_FMT_RAW8, .data_alignment = 24, }, { - .code = V4L2_MBUS_FMT_SGRBG10_1X10, + .code = MEDIA_BUS_FMT_SGRBG10_1X10, .fmt_reg = S5PCSIS_CFG_FMT_RAW10, .data_alignment = 24, }, { - .code = V4L2_MBUS_FMT_SGRBG12_1X12, + .code = MEDIA_BUS_FMT_SGRBG12_1X12, .fmt_reg = S5PCSIS_CFG_FMT_RAW12, .data_alignment = 24, } diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c index 7a86c77bffa0..f0eeb6cd262c 100644 --- a/drivers/media/platform/marvell-ccic/mcam-core.c +++ b/drivers/media/platform/marvell-ccic/mcam-core.c @@ -106,61 +106,61 @@ static struct mcam_format_struct { __u32 pixelformat; int bpp; /* Bytes per pixel */ bool planar; - enum v4l2_mbus_pixelcode mbus_code; + u32 mbus_code; } mcam_formats[] = { { .desc = "YUYV 4:2:2", .pixelformat = V4L2_PIX_FMT_YUYV, - .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8, + .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, .bpp = 2, .planar = false, }, { .desc = "UYVY 4:2:2", .pixelformat = V4L2_PIX_FMT_UYVY, - .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8, + .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, .bpp = 2, .planar = false, }, { .desc = "YUV 4:2:2 PLANAR", .pixelformat = V4L2_PIX_FMT_YUV422P, - .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8, + .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, .bpp = 2, .planar = true, }, { .desc = "YUV 4:2:0 PLANAR", .pixelformat = V4L2_PIX_FMT_YUV420, - .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8, + .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, .bpp = 2, .planar = true, }, { .desc = "YVU 4:2:0 PLANAR", .pixelformat = V4L2_PIX_FMT_YVU420, - .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8, + .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, .bpp = 2, .planar = true, }, { .desc = "RGB 444", .pixelformat = V4L2_PIX_FMT_RGB444, - .mbus_code = V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE, + .mbus_code = MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE, .bpp = 2, .planar = false, }, { .desc = "RGB 565", .pixelformat = V4L2_PIX_FMT_RGB565, - .mbus_code = V4L2_MBUS_FMT_RGB565_2X8_LE, + .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE, .bpp = 2, .planar = false, }, { .desc = "Raw RGB Bayer", .pixelformat = V4L2_PIX_FMT_SBGGR8, - .mbus_code = V4L2_MBUS_FMT_SBGGR8_1X8, + .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, .bpp = 1, .planar = false, }, @@ -190,8 +190,7 @@ static const struct v4l2_pix_format mcam_def_pix_format = { .sizeimage = VGA_WIDTH*VGA_HEIGHT*2, }; -static const enum v4l2_mbus_pixelcode mcam_def_mbus_code = - V4L2_MBUS_FMT_YUYV8_2X8; +static const u32 mcam_def_mbus_code = MEDIA_BUS_FMT_YUYV8_2X8; /* diff --git a/drivers/media/platform/marvell-ccic/mcam-core.h b/drivers/media/platform/marvell-ccic/mcam-core.h index e0e628cb98f9..60a8e1cfeff7 100644 --- a/drivers/media/platform/marvell-ccic/mcam-core.h +++ b/drivers/media/platform/marvell-ccic/mcam-core.h @@ -183,7 +183,7 @@ struct mcam_camera { /* Current operating parameters */ struct v4l2_pix_format pix_format; - enum v4l2_mbus_pixelcode mbus_code; + u32 mbus_code; /* Locks */ struct mutex s_mutex; /* Access to this structure */ diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index 81a9dc053d58..587489a072d5 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -36,23 +36,23 @@ __ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, unsigned int pad, enum v4l2_subdev_format_whence which); static const unsigned int ccdc_fmts[] = { - V4L2_MBUS_FMT_Y8_1X8, - V4L2_MBUS_FMT_Y10_1X10, - V4L2_MBUS_FMT_Y12_1X12, - V4L2_MBUS_FMT_SGRBG8_1X8, - V4L2_MBUS_FMT_SRGGB8_1X8, - V4L2_MBUS_FMT_SBGGR8_1X8, - V4L2_MBUS_FMT_SGBRG8_1X8, - V4L2_MBUS_FMT_SGRBG10_1X10, - V4L2_MBUS_FMT_SRGGB10_1X10, - V4L2_MBUS_FMT_SBGGR10_1X10, - V4L2_MBUS_FMT_SGBRG10_1X10, - V4L2_MBUS_FMT_SGRBG12_1X12, - V4L2_MBUS_FMT_SRGGB12_1X12, - V4L2_MBUS_FMT_SBGGR12_1X12, - V4L2_MBUS_FMT_SGBRG12_1X12, - V4L2_MBUS_FMT_YUYV8_2X8, - V4L2_MBUS_FMT_UYVY8_2X8, + MEDIA_BUS_FMT_Y8_1X8, + MEDIA_BUS_FMT_Y10_1X10, + MEDIA_BUS_FMT_Y12_1X12, + MEDIA_BUS_FMT_SGRBG8_1X8, + MEDIA_BUS_FMT_SRGGB8_1X8, + MEDIA_BUS_FMT_SBGGR8_1X8, + MEDIA_BUS_FMT_SGBRG8_1X8, + MEDIA_BUS_FMT_SGRBG10_1X10, + MEDIA_BUS_FMT_SRGGB10_1X10, + MEDIA_BUS_FMT_SBGGR10_1X10, + MEDIA_BUS_FMT_SGBRG10_1X10, + MEDIA_BUS_FMT_SGRBG12_1X12, + MEDIA_BUS_FMT_SRGGB12_1X12, + MEDIA_BUS_FMT_SBGGR12_1X12, + MEDIA_BUS_FMT_SGBRG12_1X12, + MEDIA_BUS_FMT_YUYV8_2X8, + MEDIA_BUS_FMT_UYVY8_2X8, }; /* @@ -266,10 +266,10 @@ static int __ccdc_lsc_enable(struct isp_ccdc_device *ccdc, int enable) __ccdc_get_format(ccdc, NULL, CCDC_PAD_SINK, V4L2_SUBDEV_FORMAT_ACTIVE); - if ((format->code != V4L2_MBUS_FMT_SGRBG10_1X10) && - (format->code != V4L2_MBUS_FMT_SRGGB10_1X10) && - (format->code != V4L2_MBUS_FMT_SBGGR10_1X10) && - (format->code != V4L2_MBUS_FMT_SGBRG10_1X10)) + if ((format->code != MEDIA_BUS_FMT_SGRBG10_1X10) && + (format->code != MEDIA_BUS_FMT_SRGGB10_1X10) && + (format->code != MEDIA_BUS_FMT_SBGGR10_1X10) && + (format->code != MEDIA_BUS_FMT_SGBRG10_1X10)) return -EINVAL; if (enable) @@ -971,8 +971,8 @@ static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc, format = &ccdc->formats[CCDC_PAD_SINK]; - if (format->code == V4L2_MBUS_FMT_YUYV8_2X8 || - format->code == V4L2_MBUS_FMT_UYVY8_2X8) { + if (format->code == MEDIA_BUS_FMT_YUYV8_2X8 || + format->code == MEDIA_BUS_FMT_UYVY8_2X8) { /* According to the OMAP3 TRM the input mode only affects SYNC * mode, enabling BT.656 mode should take precedence. However, * in practice setting the input mode to YCbCr data on 8 bits @@ -1020,7 +1020,7 @@ static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc, /* The CCDC_CFG.Y8POS bit is used in YCbCr8 input mode only. The * hardware seems to ignore it in all other input modes. */ - if (format->code == V4L2_MBUS_FMT_UYVY8_2X8) + if (format->code == MEDIA_BUS_FMT_UYVY8_2X8) isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG, ISPCCDC_CFG_Y8POS); else @@ -1168,9 +1168,9 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) if (ccdc->bt656) bridge = ISPCTRL_PAR_BRIDGE_DISABLE; - else if (fmt_info->code == V4L2_MBUS_FMT_YUYV8_2X8) + else if (fmt_info->code == MEDIA_BUS_FMT_YUYV8_2X8) bridge = ISPCTRL_PAR_BRIDGE_LENDIAN; - else if (fmt_info->code == V4L2_MBUS_FMT_UYVY8_2X8) + else if (fmt_info->code == MEDIA_BUS_FMT_UYVY8_2X8) bridge = ISPCTRL_PAR_BRIDGE_BENDIAN; else bridge = ISPCTRL_PAR_BRIDGE_DISABLE; @@ -1199,16 +1199,16 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) /* Mosaic filter */ switch (format->code) { - case V4L2_MBUS_FMT_SRGGB10_1X10: - case V4L2_MBUS_FMT_SRGGB12_1X12: + case MEDIA_BUS_FMT_SRGGB10_1X10: + case MEDIA_BUS_FMT_SRGGB12_1X12: ccdc_pattern = ccdc_srggb_pattern; break; - case V4L2_MBUS_FMT_SBGGR10_1X10: - case V4L2_MBUS_FMT_SBGGR12_1X12: + case MEDIA_BUS_FMT_SBGGR10_1X10: + case MEDIA_BUS_FMT_SBGGR12_1X12: ccdc_pattern = ccdc_sbggr_pattern; break; - case V4L2_MBUS_FMT_SGBRG10_1X10: - case V4L2_MBUS_FMT_SGBRG12_1X12: + case MEDIA_BUS_FMT_SGBRG10_1X10: + case MEDIA_BUS_FMT_SGBRG12_1X12: ccdc_pattern = ccdc_sgbrg_pattern; break; default: @@ -1267,7 +1267,7 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) /* The CCDC outputs data in UYVY order by default. Swap bytes to get * YUYV. */ - if (format->code == V4L2_MBUS_FMT_YUYV8_1X16) + if (format->code == MEDIA_BUS_FMT_YUYV8_1X16) isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG, ISPCCDC_CFG_BSWD); else @@ -1967,7 +1967,7 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, enum v4l2_subdev_format_whence which) { const struct isp_format_info *info; - enum v4l2_mbus_pixelcode pixelcode; + u32 pixelcode; unsigned int width = fmt->width; unsigned int height = fmt->height; struct v4l2_rect *crop; @@ -1983,7 +1983,7 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, /* If not found, use SGRBG10 as default */ if (i >= ARRAY_SIZE(ccdc_fmts)) - fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10; + fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; /* Clamp the input size. */ fmt->width = clamp_t(u32, width, 32, 4096); @@ -2007,19 +2007,19 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, * configured to pack bytes in BT.656, hiding the inaccuracy. * In all cases bytes can be swapped. */ - if (fmt->code == V4L2_MBUS_FMT_YUYV8_2X8 || - fmt->code == V4L2_MBUS_FMT_UYVY8_2X8) { + if (fmt->code == MEDIA_BUS_FMT_YUYV8_2X8 || + fmt->code == MEDIA_BUS_FMT_UYVY8_2X8) { /* Use the user requested format if YUV. */ - if (pixelcode == V4L2_MBUS_FMT_YUYV8_2X8 || - pixelcode == V4L2_MBUS_FMT_UYVY8_2X8 || - pixelcode == V4L2_MBUS_FMT_YUYV8_1X16 || - pixelcode == V4L2_MBUS_FMT_UYVY8_1X16) + if (pixelcode == MEDIA_BUS_FMT_YUYV8_2X8 || + pixelcode == MEDIA_BUS_FMT_UYVY8_2X8 || + pixelcode == MEDIA_BUS_FMT_YUYV8_1X16 || + pixelcode == MEDIA_BUS_FMT_UYVY8_1X16) fmt->code = pixelcode; - if (fmt->code == V4L2_MBUS_FMT_YUYV8_2X8) - fmt->code = V4L2_MBUS_FMT_YUYV8_1X16; - else if (fmt->code == V4L2_MBUS_FMT_UYVY8_2X8) - fmt->code = V4L2_MBUS_FMT_UYVY8_1X16; + if (fmt->code == MEDIA_BUS_FMT_YUYV8_2X8) + fmt->code = MEDIA_BUS_FMT_YUYV8_1X16; + else if (fmt->code == MEDIA_BUS_FMT_UYVY8_2X8) + fmt->code = MEDIA_BUS_FMT_UYVY8_1X16; } /* Hardcode the output size to the crop rectangle size. */ @@ -2047,8 +2047,8 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, fmt->code = info->truncated; /* YUV formats are not supported by the video port. */ - if (fmt->code == V4L2_MBUS_FMT_YUYV8_2X8 || - fmt->code == V4L2_MBUS_FMT_UYVY8_2X8) + if (fmt->code == MEDIA_BUS_FMT_YUYV8_2X8 || + fmt->code == MEDIA_BUS_FMT_UYVY8_2X8) fmt->code = 0; /* The number of lines that can be clocked out from the video @@ -2083,7 +2083,7 @@ static void ccdc_try_crop(struct isp_ccdc_device *ccdc, * to keep the Bayer pattern. */ info = omap3isp_video_format_info(sink->code); - if (info->flavor != V4L2_MBUS_FMT_Y8_1X8) { + if (info->flavor != MEDIA_BUS_FMT_Y8_1X8) { crop->left &= ~1; crop->top &= ~1; } @@ -2103,7 +2103,7 @@ static void ccdc_try_crop(struct isp_ccdc_device *ccdc, sink->height - crop->top); /* Odd width/height values don't make sense for Bayer formats. */ - if (info->flavor != V4L2_MBUS_FMT_Y8_1X8) { + if (info->flavor != MEDIA_BUS_FMT_Y8_1X8) { crop->width &= ~1; crop->height &= ~1; } @@ -2135,13 +2135,13 @@ static int ccdc_enum_mbus_code(struct v4l2_subdev *sd, format = __ccdc_get_format(ccdc, fh, code->pad, V4L2_SUBDEV_FORMAT_TRY); - if (format->code == V4L2_MBUS_FMT_YUYV8_2X8 || - format->code == V4L2_MBUS_FMT_UYVY8_2X8) { + if (format->code == MEDIA_BUS_FMT_YUYV8_2X8 || + format->code == MEDIA_BUS_FMT_UYVY8_2X8) { /* In YUV mode the CCDC can swap bytes. */ if (code->index == 0) - code->code = V4L2_MBUS_FMT_YUYV8_1X16; + code->code = MEDIA_BUS_FMT_YUYV8_1X16; else if (code->index == 1) - code->code = V4L2_MBUS_FMT_UYVY8_1X16; + code->code = MEDIA_BUS_FMT_UYVY8_1X16; else return -EINVAL; } else { @@ -2383,9 +2383,7 @@ static int ccdc_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, * return true if the combination is possible * return false otherwise */ -static bool ccdc_is_shiftable(enum v4l2_mbus_pixelcode in, - enum v4l2_mbus_pixelcode out, - unsigned int additional_shift) +static bool ccdc_is_shiftable(u32 in, u32 out, unsigned int additional_shift) { const struct isp_format_info *in_info, *out_info; @@ -2452,7 +2450,7 @@ static int ccdc_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) memset(&format, 0, sizeof(format)); format.pad = CCDC_PAD_SINK; format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; - format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10; + format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10; format.format.width = 4096; format.format.height = 4096; ccdc_set_format(sd, fh, &format); diff --git a/drivers/media/platform/omap3isp/ispccp2.c b/drivers/media/platform/omap3isp/ispccp2.c index 9cb49b3c04bd..f4aedb37e41e 100644 --- a/drivers/media/platform/omap3isp/ispccp2.c +++ b/drivers/media/platform/omap3isp/ispccp2.c @@ -289,10 +289,10 @@ static void ccp2_lcx_config(struct isp_ccp2_device *ccp2, u32 val, format; switch (config->format) { - case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8: + case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8: format = ISPCCP2_LCx_CTRL_FORMAT_RAW8_DPCM10_VP; break; - case V4L2_MBUS_FMT_SGRBG10_1X10: + case MEDIA_BUS_FMT_SGRBG10_1X10: default: format = ISPCCP2_LCx_CTRL_FORMAT_RAW10_VP; /* RAW10+VP */ break; @@ -438,7 +438,7 @@ static void ccp2_mem_configure(struct isp_ccp2_device *ccp2, u32 val, hwords; if (sink_pixcode != source_pixcode && - sink_pixcode == V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8) + sink_pixcode == MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8) dpcm_decompress = 1; ccp2_pwr_cfg(ccp2); @@ -604,8 +604,8 @@ void omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2) */ static const unsigned int ccp2_fmts[] = { - V4L2_MBUS_FMT_SGRBG10_1X10, - V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, + MEDIA_BUS_FMT_SGRBG10_1X10, + MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, }; /* @@ -643,8 +643,8 @@ static void ccp2_try_format(struct isp_ccp2_device *ccp2, switch (pad) { case CCP2_PAD_SINK: - if (fmt->code != V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8) - fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10; + if (fmt->code != MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8) + fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; if (ccp2->input == CCP2_INPUT_SENSOR) { fmt->width = clamp_t(u32, fmt->width, @@ -671,7 +671,7 @@ static void ccp2_try_format(struct isp_ccp2_device *ccp2, */ format = __ccp2_get_format(ccp2, fh, CCP2_PAD_SINK, which); memcpy(fmt, format, sizeof(*fmt)); - fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10; + fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; break; } @@ -808,7 +808,7 @@ static int ccp2_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) memset(&format, 0, sizeof(format)); format.pad = CCP2_PAD_SINK; format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; - format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10; + format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10; format.format.width = 4096; format.format.height = 4096; ccp2_set_format(sd, fh, &format); diff --git a/drivers/media/platform/omap3isp/ispcsi2.c b/drivers/media/platform/omap3isp/ispcsi2.c index 6530b255f103..09c686d96ae8 100644 --- a/drivers/media/platform/omap3isp/ispcsi2.c +++ b/drivers/media/platform/omap3isp/ispcsi2.c @@ -78,15 +78,15 @@ static void csi2_recv_config(struct isp_device *isp, } static const unsigned int csi2_input_fmts[] = { - V4L2_MBUS_FMT_SGRBG10_1X10, - V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, - V4L2_MBUS_FMT_SRGGB10_1X10, - V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8, - V4L2_MBUS_FMT_SBGGR10_1X10, - V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8, - V4L2_MBUS_FMT_SGBRG10_1X10, - V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8, - V4L2_MBUS_FMT_YUYV8_2X8, + MEDIA_BUS_FMT_SGRBG10_1X10, + MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, + MEDIA_BUS_FMT_SRGGB10_1X10, + MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8, + MEDIA_BUS_FMT_SBGGR10_1X10, + MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8, + MEDIA_BUS_FMT_SGBRG10_1X10, + MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8, + MEDIA_BUS_FMT_YUYV8_2X8, }; /* To set the format on the CSI2 requires a mapping function that takes @@ -171,19 +171,19 @@ static u16 csi2_ctx_map_format(struct isp_csi2_device *csi2) int fmtidx, destidx, is_3630; switch (fmt->code) { - case V4L2_MBUS_FMT_SGRBG10_1X10: - case V4L2_MBUS_FMT_SRGGB10_1X10: - case V4L2_MBUS_FMT_SBGGR10_1X10: - case V4L2_MBUS_FMT_SGBRG10_1X10: + case MEDIA_BUS_FMT_SGRBG10_1X10: + case MEDIA_BUS_FMT_SRGGB10_1X10: + case MEDIA_BUS_FMT_SBGGR10_1X10: + case MEDIA_BUS_FMT_SGBRG10_1X10: fmtidx = 0; break; - case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8: - case V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8: - case V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8: - case V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8: + case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8: + case MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8: + case MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8: + case MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8: fmtidx = 1; break; - case V4L2_MBUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_YUYV8_2X8: fmtidx = 2; break; default: @@ -843,7 +843,7 @@ csi2_try_format(struct isp_csi2_device *csi2, struct v4l2_subdev_fh *fh, unsigned int pad, struct v4l2_mbus_framefmt *fmt, enum v4l2_subdev_format_whence which) { - enum v4l2_mbus_pixelcode pixelcode; + u32 pixelcode; struct v4l2_mbus_framefmt *format; const struct isp_format_info *info; unsigned int i; @@ -858,7 +858,7 @@ csi2_try_format(struct isp_csi2_device *csi2, struct v4l2_subdev_fh *fh, /* If not found, use SGRBG10 as default */ if (i >= ARRAY_SIZE(csi2_input_fmts)) - fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10; + fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; fmt->width = clamp_t(u32, fmt->width, 1, 8191); fmt->height = clamp_t(u32, fmt->height, 1, 8191); @@ -1029,7 +1029,7 @@ static int csi2_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) memset(&format, 0, sizeof(format)); format.pad = CSI2_PAD_SINK; format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; - format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10; + format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10; format.format.width = 4096; format.format.height = 4096; csi2_set_format(sd, fh, &format); diff --git a/drivers/media/platform/omap3isp/isppreview.c b/drivers/media/platform/omap3isp/isppreview.c index 605f57ef0a49..dd9eed45d853 100644 --- a/drivers/media/platform/omap3isp/isppreview.c +++ b/drivers/media/platform/omap3isp/isppreview.c @@ -964,18 +964,16 @@ static void preview_setup_hw(struct isp_prev_device *prev, u32 update, * @prev: pointer to previewer private structure * @pixelcode: pixel code */ -static void -preview_config_ycpos(struct isp_prev_device *prev, - enum v4l2_mbus_pixelcode pixelcode) +static void preview_config_ycpos(struct isp_prev_device *prev, u32 pixelcode) { struct isp_device *isp = to_isp_device(prev); enum preview_ycpos_mode mode; switch (pixelcode) { - case V4L2_MBUS_FMT_YUYV8_1X16: + case MEDIA_BUS_FMT_YUYV8_1X16: mode = YCPOS_CrYCbY; break; - case V4L2_MBUS_FMT_UYVY8_1X16: + case MEDIA_BUS_FMT_UYVY8_1X16: mode = YCPOS_YCrYCb; break; default: @@ -1028,16 +1026,16 @@ static void preview_config_input_format(struct isp_prev_device *prev, ISPPRV_PCR_WIDTH); switch (info->flavor) { - case V4L2_MBUS_FMT_SGRBG8_1X8: + case MEDIA_BUS_FMT_SGRBG8_1X8: prev->params.cfa_order = 0; break; - case V4L2_MBUS_FMT_SRGGB8_1X8: + case MEDIA_BUS_FMT_SRGGB8_1X8: prev->params.cfa_order = 1; break; - case V4L2_MBUS_FMT_SBGGR8_1X8: + case MEDIA_BUS_FMT_SBGGR8_1X8: prev->params.cfa_order = 2; break; - case V4L2_MBUS_FMT_SGBRG8_1X8: + case MEDIA_BUS_FMT_SGBRG8_1X8: prev->params.cfa_order = 3; break; default: @@ -1078,8 +1076,8 @@ static void preview_config_input_size(struct isp_prev_device *prev, u32 active) unsigned int elv = prev->crop.top + prev->crop.height - 1; u32 features; - if (format->code != V4L2_MBUS_FMT_Y8_1X8 && - format->code != V4L2_MBUS_FMT_Y10_1X10) { + if (format->code != MEDIA_BUS_FMT_Y8_1X8 && + format->code != MEDIA_BUS_FMT_Y10_1X10) { sph -= 2; eph += 2; slv -= 2; @@ -1709,21 +1707,21 @@ __preview_get_crop(struct isp_prev_device *prev, struct v4l2_subdev_fh *fh, /* previewer format descriptions */ static const unsigned int preview_input_fmts[] = { - V4L2_MBUS_FMT_Y8_1X8, - V4L2_MBUS_FMT_SGRBG8_1X8, - V4L2_MBUS_FMT_SRGGB8_1X8, - V4L2_MBUS_FMT_SBGGR8_1X8, - V4L2_MBUS_FMT_SGBRG8_1X8, - V4L2_MBUS_FMT_Y10_1X10, - V4L2_MBUS_FMT_SGRBG10_1X10, - V4L2_MBUS_FMT_SRGGB10_1X10, - V4L2_MBUS_FMT_SBGGR10_1X10, - V4L2_MBUS_FMT_SGBRG10_1X10, + MEDIA_BUS_FMT_Y8_1X8, + MEDIA_BUS_FMT_SGRBG8_1X8, + MEDIA_BUS_FMT_SRGGB8_1X8, + MEDIA_BUS_FMT_SBGGR8_1X8, + MEDIA_BUS_FMT_SGBRG8_1X8, + MEDIA_BUS_FMT_Y10_1X10, + MEDIA_BUS_FMT_SGRBG10_1X10, + MEDIA_BUS_FMT_SRGGB10_1X10, + MEDIA_BUS_FMT_SBGGR10_1X10, + MEDIA_BUS_FMT_SGBRG10_1X10, }; static const unsigned int preview_output_fmts[] = { - V4L2_MBUS_FMT_UYVY8_1X16, - V4L2_MBUS_FMT_YUYV8_1X16, + MEDIA_BUS_FMT_UYVY8_1X16, + MEDIA_BUS_FMT_YUYV8_1X16, }; /* @@ -1742,7 +1740,7 @@ static void preview_try_format(struct isp_prev_device *prev, struct v4l2_mbus_framefmt *fmt, enum v4l2_subdev_format_whence which) { - enum v4l2_mbus_pixelcode pixelcode; + u32 pixelcode; struct v4l2_rect *crop; unsigned int i; @@ -1774,7 +1772,7 @@ static void preview_try_format(struct isp_prev_device *prev, /* If not found, use SGRBG10 as default */ if (i >= ARRAY_SIZE(preview_input_fmts)) - fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10; + fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; break; case PREV_PAD_SOURCE: @@ -1782,13 +1780,13 @@ static void preview_try_format(struct isp_prev_device *prev, *fmt = *__preview_get_format(prev, fh, PREV_PAD_SINK, which); switch (pixelcode) { - case V4L2_MBUS_FMT_YUYV8_1X16: - case V4L2_MBUS_FMT_UYVY8_1X16: + case MEDIA_BUS_FMT_YUYV8_1X16: + case MEDIA_BUS_FMT_UYVY8_1X16: fmt->code = pixelcode; break; default: - fmt->code = V4L2_MBUS_FMT_YUYV8_1X16; + fmt->code = MEDIA_BUS_FMT_YUYV8_1X16; break; } @@ -1843,8 +1841,8 @@ static void preview_try_crop(struct isp_prev_device *prev, * and no columns in other modes. Increase the margins based on the sink * format. */ - if (sink->code != V4L2_MBUS_FMT_Y8_1X8 && - sink->code != V4L2_MBUS_FMT_Y10_1X10) { + if (sink->code != MEDIA_BUS_FMT_Y8_1X8 && + sink->code != MEDIA_BUS_FMT_Y10_1X10) { left += 2; right -= 2; top += 2; @@ -2092,7 +2090,7 @@ static int preview_init_formats(struct v4l2_subdev *sd, memset(&format, 0, sizeof(format)); format.pad = PREV_PAD_SINK; format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; - format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10; + format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10; format.format.width = 4096; format.format.height = 4096; preview_set_format(sd, fh, &format); diff --git a/drivers/media/platform/omap3isp/ispresizer.c b/drivers/media/platform/omap3isp/ispresizer.c index 05d1ace57451..2b9bc4839876 100644 --- a/drivers/media/platform/omap3isp/ispresizer.c +++ b/drivers/media/platform/omap3isp/ispresizer.c @@ -198,17 +198,16 @@ static void resizer_set_bilinear(struct isp_res_device *res, * @res: Device context. * @pixelcode: pixel code. */ -static void resizer_set_ycpos(struct isp_res_device *res, - enum v4l2_mbus_pixelcode pixelcode) +static void resizer_set_ycpos(struct isp_res_device *res, u32 pixelcode) { struct isp_device *isp = to_isp_device(res); switch (pixelcode) { - case V4L2_MBUS_FMT_YUYV8_1X16: + case MEDIA_BUS_FMT_YUYV8_1X16: isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, ISPRSZ_CNT_YCPOS); break; - case V4L2_MBUS_FMT_UYVY8_1X16: + case MEDIA_BUS_FMT_UYVY8_1X16: isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, ISPRSZ_CNT_YCPOS); break; @@ -1348,8 +1347,8 @@ static int resizer_set_selection(struct v4l2_subdev *sd, /* resizer pixel formats */ static const unsigned int resizer_formats[] = { - V4L2_MBUS_FMT_UYVY8_1X16, - V4L2_MBUS_FMT_YUYV8_1X16, + MEDIA_BUS_FMT_UYVY8_1X16, + MEDIA_BUS_FMT_YUYV8_1X16, }; static unsigned int resizer_max_in_width(struct isp_res_device *res) @@ -1385,9 +1384,9 @@ static void resizer_try_format(struct isp_res_device *res, switch (pad) { case RESZ_PAD_SINK: - if (fmt->code != V4L2_MBUS_FMT_YUYV8_1X16 && - fmt->code != V4L2_MBUS_FMT_UYVY8_1X16) - fmt->code = V4L2_MBUS_FMT_YUYV8_1X16; + if (fmt->code != MEDIA_BUS_FMT_YUYV8_1X16 && + fmt->code != MEDIA_BUS_FMT_UYVY8_1X16) + fmt->code = MEDIA_BUS_FMT_YUYV8_1X16; fmt->width = clamp_t(u32, fmt->width, MIN_IN_WIDTH, resizer_max_in_width(res)); @@ -1571,7 +1570,7 @@ static int resizer_init_formats(struct v4l2_subdev *sd, memset(&format, 0, sizeof(format)); format.pad = RESZ_PAD_SINK; format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; - format.format.code = V4L2_MBUS_FMT_YUYV8_1X16; + format.format.code = MEDIA_BUS_FMT_YUYV8_1X16; format.format.width = 4096; format.format.height = 4096; resizer_set_format(sd, fh, &format); diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c index bc38c88c7bd9..b463fe172d16 100644 --- a/drivers/media/platform/omap3isp/ispvideo.c +++ b/drivers/media/platform/omap3isp/ispvideo.c @@ -39,74 +39,74 @@ * corresponding in-memory formats to the table below!!! */ static struct isp_format_info formats[] = { - { V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8, - V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8, + { MEDIA_BUS_FMT_Y8_1X8, MEDIA_BUS_FMT_Y8_1X8, + MEDIA_BUS_FMT_Y8_1X8, MEDIA_BUS_FMT_Y8_1X8, V4L2_PIX_FMT_GREY, 8, 1, }, - { V4L2_MBUS_FMT_Y10_1X10, V4L2_MBUS_FMT_Y10_1X10, - V4L2_MBUS_FMT_Y10_1X10, V4L2_MBUS_FMT_Y8_1X8, + { MEDIA_BUS_FMT_Y10_1X10, MEDIA_BUS_FMT_Y10_1X10, + MEDIA_BUS_FMT_Y10_1X10, MEDIA_BUS_FMT_Y8_1X8, V4L2_PIX_FMT_Y10, 10, 2, }, - { V4L2_MBUS_FMT_Y12_1X12, V4L2_MBUS_FMT_Y10_1X10, - V4L2_MBUS_FMT_Y12_1X12, V4L2_MBUS_FMT_Y8_1X8, + { MEDIA_BUS_FMT_Y12_1X12, MEDIA_BUS_FMT_Y10_1X10, + MEDIA_BUS_FMT_Y12_1X12, MEDIA_BUS_FMT_Y8_1X8, V4L2_PIX_FMT_Y12, 12, 2, }, - { V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_MBUS_FMT_SBGGR8_1X8, - V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_MBUS_FMT_SBGGR8_1X8, + { MEDIA_BUS_FMT_SBGGR8_1X8, MEDIA_BUS_FMT_SBGGR8_1X8, + MEDIA_BUS_FMT_SBGGR8_1X8, MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_PIX_FMT_SBGGR8, 8, 1, }, - { V4L2_MBUS_FMT_SGBRG8_1X8, V4L2_MBUS_FMT_SGBRG8_1X8, - V4L2_MBUS_FMT_SGBRG8_1X8, V4L2_MBUS_FMT_SGBRG8_1X8, + { MEDIA_BUS_FMT_SGBRG8_1X8, MEDIA_BUS_FMT_SGBRG8_1X8, + MEDIA_BUS_FMT_SGBRG8_1X8, MEDIA_BUS_FMT_SGBRG8_1X8, V4L2_PIX_FMT_SGBRG8, 8, 1, }, - { V4L2_MBUS_FMT_SGRBG8_1X8, V4L2_MBUS_FMT_SGRBG8_1X8, - V4L2_MBUS_FMT_SGRBG8_1X8, V4L2_MBUS_FMT_SGRBG8_1X8, + { MEDIA_BUS_FMT_SGRBG8_1X8, MEDIA_BUS_FMT_SGRBG8_1X8, + MEDIA_BUS_FMT_SGRBG8_1X8, MEDIA_BUS_FMT_SGRBG8_1X8, V4L2_PIX_FMT_SGRBG8, 8, 1, }, - { V4L2_MBUS_FMT_SRGGB8_1X8, V4L2_MBUS_FMT_SRGGB8_1X8, - V4L2_MBUS_FMT_SRGGB8_1X8, V4L2_MBUS_FMT_SRGGB8_1X8, + { MEDIA_BUS_FMT_SRGGB8_1X8, MEDIA_BUS_FMT_SRGGB8_1X8, + MEDIA_BUS_FMT_SRGGB8_1X8, MEDIA_BUS_FMT_SRGGB8_1X8, V4L2_PIX_FMT_SRGGB8, 8, 1, }, - { V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8, V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8, - V4L2_MBUS_FMT_SBGGR10_1X10, 0, + { MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8, MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8, + MEDIA_BUS_FMT_SBGGR10_1X10, 0, V4L2_PIX_FMT_SBGGR10DPCM8, 8, 1, }, - { V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8, V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8, - V4L2_MBUS_FMT_SGBRG10_1X10, 0, + { MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8, MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8, + MEDIA_BUS_FMT_SGBRG10_1X10, 0, V4L2_PIX_FMT_SGBRG10DPCM8, 8, 1, }, - { V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, - V4L2_MBUS_FMT_SGRBG10_1X10, 0, + { MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, + MEDIA_BUS_FMT_SGRBG10_1X10, 0, V4L2_PIX_FMT_SGRBG10DPCM8, 8, 1, }, - { V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8, V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8, - V4L2_MBUS_FMT_SRGGB10_1X10, 0, + { MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8, MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8, + MEDIA_BUS_FMT_SRGGB10_1X10, 0, V4L2_PIX_FMT_SRGGB10DPCM8, 8, 1, }, - { V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_MBUS_FMT_SBGGR10_1X10, - V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_MBUS_FMT_SBGGR8_1X8, + { MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SBGGR10_1X10, + MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_PIX_FMT_SBGGR10, 10, 2, }, - { V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_MBUS_FMT_SGBRG10_1X10, - V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_MBUS_FMT_SGBRG8_1X8, + { MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SGBRG10_1X10, + MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SGBRG8_1X8, V4L2_PIX_FMT_SGBRG10, 10, 2, }, - { V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_MBUS_FMT_SGRBG10_1X10, - V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_MBUS_FMT_SGRBG8_1X8, + { MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SGRBG10_1X10, + MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SGRBG8_1X8, V4L2_PIX_FMT_SGRBG10, 10, 2, }, - { V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_MBUS_FMT_SRGGB10_1X10, - V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_MBUS_FMT_SRGGB8_1X8, + { MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SRGGB10_1X10, + MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SRGGB8_1X8, V4L2_PIX_FMT_SRGGB10, 10, 2, }, - { V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_MBUS_FMT_SBGGR10_1X10, - V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_MBUS_FMT_SBGGR8_1X8, + { MEDIA_BUS_FMT_SBGGR12_1X12, MEDIA_BUS_FMT_SBGGR10_1X10, + MEDIA_BUS_FMT_SBGGR12_1X12, MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_PIX_FMT_SBGGR12, 12, 2, }, - { V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_MBUS_FMT_SGBRG10_1X10, - V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_MBUS_FMT_SGBRG8_1X8, + { MEDIA_BUS_FMT_SGBRG12_1X12, MEDIA_BUS_FMT_SGBRG10_1X10, + MEDIA_BUS_FMT_SGBRG12_1X12, MEDIA_BUS_FMT_SGBRG8_1X8, V4L2_PIX_FMT_SGBRG12, 12, 2, }, - { V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_MBUS_FMT_SGRBG10_1X10, - V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_MBUS_FMT_SGRBG8_1X8, + { MEDIA_BUS_FMT_SGRBG12_1X12, MEDIA_BUS_FMT_SGRBG10_1X10, + MEDIA_BUS_FMT_SGRBG12_1X12, MEDIA_BUS_FMT_SGRBG8_1X8, V4L2_PIX_FMT_SGRBG12, 12, 2, }, - { V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_MBUS_FMT_SRGGB10_1X10, - V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_MBUS_FMT_SRGGB8_1X8, + { MEDIA_BUS_FMT_SRGGB12_1X12, MEDIA_BUS_FMT_SRGGB10_1X10, + MEDIA_BUS_FMT_SRGGB12_1X12, MEDIA_BUS_FMT_SRGGB8_1X8, V4L2_PIX_FMT_SRGGB12, 12, 2, }, - { V4L2_MBUS_FMT_UYVY8_1X16, V4L2_MBUS_FMT_UYVY8_1X16, - V4L2_MBUS_FMT_UYVY8_1X16, 0, + { MEDIA_BUS_FMT_UYVY8_1X16, MEDIA_BUS_FMT_UYVY8_1X16, + MEDIA_BUS_FMT_UYVY8_1X16, 0, V4L2_PIX_FMT_UYVY, 16, 2, }, - { V4L2_MBUS_FMT_YUYV8_1X16, V4L2_MBUS_FMT_YUYV8_1X16, - V4L2_MBUS_FMT_YUYV8_1X16, 0, + { MEDIA_BUS_FMT_YUYV8_1X16, MEDIA_BUS_FMT_YUYV8_1X16, + MEDIA_BUS_FMT_YUYV8_1X16, 0, V4L2_PIX_FMT_YUYV, 16, 2, }, - { V4L2_MBUS_FMT_UYVY8_2X8, V4L2_MBUS_FMT_UYVY8_2X8, - V4L2_MBUS_FMT_UYVY8_2X8, 0, + { MEDIA_BUS_FMT_UYVY8_2X8, MEDIA_BUS_FMT_UYVY8_2X8, + MEDIA_BUS_FMT_UYVY8_2X8, 0, V4L2_PIX_FMT_UYVY, 8, 2, }, - { V4L2_MBUS_FMT_YUYV8_2X8, V4L2_MBUS_FMT_YUYV8_2X8, - V4L2_MBUS_FMT_YUYV8_2X8, 0, + { MEDIA_BUS_FMT_YUYV8_2X8, MEDIA_BUS_FMT_YUYV8_2X8, + MEDIA_BUS_FMT_YUYV8_2X8, 0, V4L2_PIX_FMT_YUYV, 8, 2, }, /* Empty entry to catch the unsupported pixel code (0) used by the CCDC * module and avoid NULL pointer dereferences. @@ -114,8 +114,7 @@ static struct isp_format_info formats[] = { { 0, } }; -const struct isp_format_info * -omap3isp_video_format_info(enum v4l2_mbus_pixelcode code) +const struct isp_format_info *omap3isp_video_format_info(u32 code) { unsigned int i; diff --git a/drivers/media/platform/omap3isp/ispvideo.h b/drivers/media/platform/omap3isp/ispvideo.h index 0b7efedc3da9..4071dd7060ea 100644 --- a/drivers/media/platform/omap3isp/ispvideo.h +++ b/drivers/media/platform/omap3isp/ispvideo.h @@ -44,10 +44,10 @@ struct v4l2_pix_format; * @bpp: Bytes per pixel (when stored in memory) */ struct isp_format_info { - enum v4l2_mbus_pixelcode code; - enum v4l2_mbus_pixelcode truncated; - enum v4l2_mbus_pixelcode uncompressed; - enum v4l2_mbus_pixelcode flavor; + u32 code; + u32 truncated; + u32 uncompressed; + u32 flavor; u32 pixelformat; unsigned int width; unsigned int bpp; @@ -206,6 +206,6 @@ void omap3isp_video_resume(struct isp_video *video, int continuous); struct media_pad *omap3isp_video_remote_pad(struct isp_video *video); const struct isp_format_info * -omap3isp_video_format_info(enum v4l2_mbus_pixelcode code); +omap3isp_video_format_info(u32 code); #endif /* OMAP3_ISP_VIDEO_H */ diff --git a/drivers/media/platform/s3c-camif/camif-capture.c b/drivers/media/platform/s3c-camif/camif-capture.c index 4f81b4c9d113..aa40c8269ab8 100644 --- a/drivers/media/platform/s3c-camif/camif-capture.c +++ b/drivers/media/platform/s3c-camif/camif-capture.c @@ -1218,11 +1218,11 @@ void s3c_camif_unregister_video_node(struct camif_dev *camif, int idx) } /* Media bus pixel formats supported at the camif input */ -static const enum v4l2_mbus_pixelcode camif_mbus_formats[] = { - V4L2_MBUS_FMT_YUYV8_2X8, - V4L2_MBUS_FMT_YVYU8_2X8, - V4L2_MBUS_FMT_UYVY8_2X8, - V4L2_MBUS_FMT_VYUY8_2X8, +static const u32 camif_mbus_formats[] = { + MEDIA_BUS_FMT_YUYV8_2X8, + MEDIA_BUS_FMT_YVYU8_2X8, + MEDIA_BUS_FMT_UYVY8_2X8, + MEDIA_BUS_FMT_VYUY8_2X8, }; /* diff --git a/drivers/media/platform/s3c-camif/camif-regs.c b/drivers/media/platform/s3c-camif/camif-regs.c index 6e0c9988a191..812fb3a7c4e3 100644 --- a/drivers/media/platform/s3c-camif/camif-regs.c +++ b/drivers/media/platform/s3c-camif/camif-regs.c @@ -96,10 +96,10 @@ void camif_hw_set_effect(struct camif_dev *camif, unsigned int effect, } static const u32 src_pixfmt_map[8][2] = { - { V4L2_MBUS_FMT_YUYV8_2X8, CISRCFMT_ORDER422_YCBYCR }, - { V4L2_MBUS_FMT_YVYU8_2X8, CISRCFMT_ORDER422_YCRYCB }, - { V4L2_MBUS_FMT_UYVY8_2X8, CISRCFMT_ORDER422_CBYCRY }, - { V4L2_MBUS_FMT_VYUY8_2X8, CISRCFMT_ORDER422_CRYCBY }, + { MEDIA_BUS_FMT_YUYV8_2X8, CISRCFMT_ORDER422_YCBYCR }, + { MEDIA_BUS_FMT_YVYU8_2X8, CISRCFMT_ORDER422_YCRYCB }, + { MEDIA_BUS_FMT_UYVY8_2X8, CISRCFMT_ORDER422_CBYCRY }, + { MEDIA_BUS_FMT_VYUY8_2X8, CISRCFMT_ORDER422_CRYCBY }, }; /* Set camera input pixel format and resolution */ diff --git a/drivers/media/platform/s5p-tv/hdmi_drv.c b/drivers/media/platform/s5p-tv/hdmi_drv.c index 37c8bd694c5f..1d1ef211e113 100644 --- a/drivers/media/platform/s5p-tv/hdmi_drv.c +++ b/drivers/media/platform/s5p-tv/hdmi_drv.c @@ -660,7 +660,7 @@ static int hdmi_g_mbus_fmt(struct v4l2_subdev *sd, memset(fmt, 0, sizeof(*fmt)); fmt->width = t->hact.end - t->hact.beg; fmt->height = t->vact[0].end - t->vact[0].beg; - fmt->code = V4L2_MBUS_FMT_FIXED; /* means RGB888 */ + fmt->code = MEDIA_BUS_FMT_FIXED; /* means RGB888 */ fmt->colorspace = V4L2_COLORSPACE_SRGB; if (t->interlaced) { fmt->field = V4L2_FIELD_INTERLACED; diff --git a/drivers/media/platform/s5p-tv/sdo_drv.c b/drivers/media/platform/s5p-tv/sdo_drv.c index 72cf892dd008..46f4d56aaa1b 100644 --- a/drivers/media/platform/s5p-tv/sdo_drv.c +++ b/drivers/media/platform/s5p-tv/sdo_drv.c @@ -170,7 +170,7 @@ static int sdo_g_mbus_fmt(struct v4l2_subdev *sd, /* all modes are 720 pixels wide */ fmt->width = 720; fmt->height = sdev->fmt->height; - fmt->code = V4L2_MBUS_FMT_FIXED; + fmt->code = MEDIA_BUS_FMT_FIXED; fmt->field = V4L2_FIELD_INTERLACED; fmt->colorspace = V4L2_COLORSPACE_JPEG; return 0; diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c index e5f1d4c14f2c..047669609458 100644 --- a/drivers/media/platform/sh_vou.c +++ b/drivers/media/platform/sh_vou.c @@ -680,7 +680,7 @@ static int sh_vou_s_fmt_vid_out(struct file *file, void *priv, struct sh_vou_geometry geo; struct v4l2_mbus_framefmt mbfmt = { /* Revisit: is this the correct code? */ - .code = V4L2_MBUS_FMT_YUYV8_2X8, + .code = MEDIA_BUS_FMT_YUYV8_2X8, .field = V4L2_FIELD_INTERLACED, .colorspace = V4L2_COLORSPACE_SMPTE170M, }; @@ -733,7 +733,7 @@ static int sh_vou_s_fmt_vid_out(struct file *file, void *priv, /* Sanity checks */ if ((unsigned)mbfmt.width > VOU_MAX_IMAGE_WIDTH || (unsigned)mbfmt.height > img_height_max || - mbfmt.code != V4L2_MBUS_FMT_YUYV8_2X8) + mbfmt.code != MEDIA_BUS_FMT_YUYV8_2X8) return -EIO; if (mbfmt.width != geo.output.width || @@ -943,7 +943,7 @@ static int sh_vou_s_crop(struct file *file, void *fh, const struct v4l2_crop *a) struct sh_vou_geometry geo; struct v4l2_mbus_framefmt mbfmt = { /* Revisit: is this the correct code? */ - .code = V4L2_MBUS_FMT_YUYV8_2X8, + .code = MEDIA_BUS_FMT_YUYV8_2X8, .field = V4L2_FIELD_INTERLACED, .colorspace = V4L2_COLORSPACE_SMPTE170M, }; @@ -994,7 +994,7 @@ static int sh_vou_s_crop(struct file *file, void *fh, const struct v4l2_crop *a) /* Sanity checks */ if ((unsigned)mbfmt.width > VOU_MAX_IMAGE_WIDTH || (unsigned)mbfmt.height > img_height_max || - mbfmt.code != V4L2_MBUS_FMT_YUYV8_2X8) + mbfmt.code != MEDIA_BUS_FMT_YUYV8_2X8) return -EIO; geo.output.width = mbfmt.width; diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index c5291b001057..ee5650f4ea2d 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -105,25 +105,25 @@ static u32 isi_readl(struct atmel_isi *isi, u32 reg) } static int configure_geometry(struct atmel_isi *isi, u32 width, - u32 height, enum v4l2_mbus_pixelcode code) + u32 height, u32 code) { u32 cfg2, cr; switch (code) { /* YUV, including grey */ - case V4L2_MBUS_FMT_Y8_1X8: + case MEDIA_BUS_FMT_Y8_1X8: cr = ISI_CFG2_GRAYSCALE; break; - case V4L2_MBUS_FMT_VYUY8_2X8: + case MEDIA_BUS_FMT_VYUY8_2X8: cr = ISI_CFG2_YCC_SWAP_MODE_3; break; - case V4L2_MBUS_FMT_UYVY8_2X8: + case MEDIA_BUS_FMT_UYVY8_2X8: cr = ISI_CFG2_YCC_SWAP_MODE_2; break; - case V4L2_MBUS_FMT_YVYU8_2X8: + case MEDIA_BUS_FMT_YVYU8_2X8: cr = ISI_CFG2_YCC_SWAP_MODE_1; break; - case V4L2_MBUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_YUYV8_2X8: cr = ISI_CFG2_YCC_SWAP_DEFAULT; break; /* RGB, TODO */ @@ -645,7 +645,7 @@ static int isi_camera_get_formats(struct soc_camera_device *icd, struct v4l2_subdev *sd = soc_camera_to_subdev(icd); int formats = 0, ret; /* sensor format */ - enum v4l2_mbus_pixelcode code; + u32 code; /* soc camera host format */ const struct soc_mbus_pixelfmt *fmt; @@ -670,10 +670,10 @@ static int isi_camera_get_formats(struct soc_camera_device *icd, } switch (code) { - case V4L2_MBUS_FMT_UYVY8_2X8: - case V4L2_MBUS_FMT_VYUY8_2X8: - case V4L2_MBUS_FMT_YUYV8_2X8: - case V4L2_MBUS_FMT_YVYU8_2X8: + case MEDIA_BUS_FMT_UYVY8_2X8: + case MEDIA_BUS_FMT_VYUY8_2X8: + case MEDIA_BUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_YVYU8_2X8: formats++; if (xlate) { xlate->host_fmt = &isi_camera_formats[0]; diff --git a/drivers/media/platform/soc_camera/mx2_camera.c b/drivers/media/platform/soc_camera/mx2_camera.c index 2347612a4cc1..ce72bd26a6ac 100644 --- a/drivers/media/platform/soc_camera/mx2_camera.c +++ b/drivers/media/platform/soc_camera/mx2_camera.c @@ -211,7 +211,7 @@ struct emma_prp_resize { /* prp configuration for a client-host fmt pair */ struct mx2_fmt_cfg { - enum v4l2_mbus_pixelcode in_fmt; + u32 in_fmt; u32 out_fmt; struct mx2_prp_cfg cfg; }; @@ -309,7 +309,7 @@ static struct mx2_fmt_cfg mx27_emma_prp_table[] = { } }, { - .in_fmt = V4L2_MBUS_FMT_UYVY8_2X8, + .in_fmt = MEDIA_BUS_FMT_UYVY8_2X8, .out_fmt = V4L2_PIX_FMT_YUYV, .cfg = { .channel = 1, @@ -323,7 +323,7 @@ static struct mx2_fmt_cfg mx27_emma_prp_table[] = { } }, { - .in_fmt = V4L2_MBUS_FMT_YUYV8_2X8, + .in_fmt = MEDIA_BUS_FMT_YUYV8_2X8, .out_fmt = V4L2_PIX_FMT_YUYV, .cfg = { .channel = 1, @@ -337,7 +337,7 @@ static struct mx2_fmt_cfg mx27_emma_prp_table[] = { } }, { - .in_fmt = V4L2_MBUS_FMT_YUYV8_2X8, + .in_fmt = MEDIA_BUS_FMT_YUYV8_2X8, .out_fmt = V4L2_PIX_FMT_YUV420, .cfg = { .channel = 2, @@ -351,7 +351,7 @@ static struct mx2_fmt_cfg mx27_emma_prp_table[] = { } }, { - .in_fmt = V4L2_MBUS_FMT_UYVY8_2X8, + .in_fmt = MEDIA_BUS_FMT_UYVY8_2X8, .out_fmt = V4L2_PIX_FMT_YUV420, .cfg = { .channel = 2, @@ -366,9 +366,7 @@ static struct mx2_fmt_cfg mx27_emma_prp_table[] = { }, }; -static struct mx2_fmt_cfg *mx27_emma_prp_get_format( - enum v4l2_mbus_pixelcode in_fmt, - u32 out_fmt) +static struct mx2_fmt_cfg *mx27_emma_prp_get_format(u32 in_fmt, u32 out_fmt) { int i; @@ -945,7 +943,7 @@ static int mx2_camera_get_formats(struct soc_camera_device *icd, struct v4l2_subdev *sd = soc_camera_to_subdev(icd); const struct soc_mbus_pixelfmt *fmt; struct device *dev = icd->parent; - enum v4l2_mbus_pixelcode code; + u32 code; int ret, formats = 0; ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); @@ -959,8 +957,8 @@ static int mx2_camera_get_formats(struct soc_camera_device *icd, return 0; } - if (code == V4L2_MBUS_FMT_YUYV8_2X8 || - code == V4L2_MBUS_FMT_UYVY8_2X8) { + if (code == MEDIA_BUS_FMT_YUYV8_2X8 || + code == MEDIA_BUS_FMT_UYVY8_2X8) { formats++; if (xlate) { /* @@ -968,7 +966,7 @@ static int mx2_camera_get_formats(struct soc_camera_device *icd, * soc_mediabus.c */ xlate->host_fmt = - soc_mbus_get_fmtdesc(V4L2_MBUS_FMT_YUYV8_1_5X8); + soc_mbus_get_fmtdesc(MEDIA_BUS_FMT_YUYV8_1_5X8); xlate->code = code; dev_dbg(dev, "Providing host format %s for sensor code %d\n", xlate->host_fmt->name, code); @@ -976,11 +974,11 @@ static int mx2_camera_get_formats(struct soc_camera_device *icd, } } - if (code == V4L2_MBUS_FMT_UYVY8_2X8) { + if (code == MEDIA_BUS_FMT_UYVY8_2X8) { formats++; if (xlate) { xlate->host_fmt = - soc_mbus_get_fmtdesc(V4L2_MBUS_FMT_YUYV8_2X8); + soc_mbus_get_fmtdesc(MEDIA_BUS_FMT_YUYV8_2X8); xlate->code = code; dev_dbg(dev, "Providing host format %s for sensor code %d\n", xlate->host_fmt->name, code); diff --git a/drivers/media/platform/soc_camera/mx3_camera.c b/drivers/media/platform/soc_camera/mx3_camera.c index 7696a873510d..8e52ccce66de 100644 --- a/drivers/media/platform/soc_camera/mx3_camera.c +++ b/drivers/media/platform/soc_camera/mx3_camera.c @@ -656,7 +656,7 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int id struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct device *dev = icd->parent; int formats = 0, ret; - enum v4l2_mbus_pixelcode code; + u32 code; const struct soc_mbus_pixelfmt *fmt; ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); @@ -677,7 +677,7 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int id return 0; switch (code) { - case V4L2_MBUS_FMT_SBGGR10_1X10: + case MEDIA_BUS_FMT_SBGGR10_1X10: formats++; if (xlate) { xlate->host_fmt = &mx3_camera_formats[0]; @@ -687,7 +687,7 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int id mx3_camera_formats[0].name, code); } break; - case V4L2_MBUS_FMT_Y10_1X10: + case MEDIA_BUS_FMT_Y10_1X10: formats++; if (xlate) { xlate->host_fmt = &mx3_camera_formats[1]; diff --git a/drivers/media/platform/soc_camera/omap1_camera.c b/drivers/media/platform/soc_camera/omap1_camera.c index 74ce8b6b79fa..e6b93281f246 100644 --- a/drivers/media/platform/soc_camera/omap1_camera.c +++ b/drivers/media/platform/soc_camera/omap1_camera.c @@ -140,7 +140,7 @@ /* buffer for one video frame */ struct omap1_cam_buf { struct videobuf_buffer vb; - enum v4l2_mbus_pixelcode code; + u32 code; int inwork; struct scatterlist *sgbuf; int sgcount; @@ -980,7 +980,7 @@ static void omap1_cam_clock_stop(struct soc_camera_host *ici) /* Duplicate standard formats based on host capability of byte swapping */ static const struct soc_mbus_lookup omap1_cam_formats[] = { { - .code = V4L2_MBUS_FMT_UYVY8_2X8, + .code = MEDIA_BUS_FMT_UYVY8_2X8, .fmt = { .fourcc = V4L2_PIX_FMT_YUYV, .name = "YUYV", @@ -990,7 +990,7 @@ static const struct soc_mbus_lookup omap1_cam_formats[] = { .layout = SOC_MBUS_LAYOUT_PACKED, }, }, { - .code = V4L2_MBUS_FMT_VYUY8_2X8, + .code = MEDIA_BUS_FMT_VYUY8_2X8, .fmt = { .fourcc = V4L2_PIX_FMT_YVYU, .name = "YVYU", @@ -1000,7 +1000,7 @@ static const struct soc_mbus_lookup omap1_cam_formats[] = { .layout = SOC_MBUS_LAYOUT_PACKED, }, }, { - .code = V4L2_MBUS_FMT_YUYV8_2X8, + .code = MEDIA_BUS_FMT_YUYV8_2X8, .fmt = { .fourcc = V4L2_PIX_FMT_UYVY, .name = "UYVY", @@ -1010,7 +1010,7 @@ static const struct soc_mbus_lookup omap1_cam_formats[] = { .layout = SOC_MBUS_LAYOUT_PACKED, }, }, { - .code = V4L2_MBUS_FMT_YVYU8_2X8, + .code = MEDIA_BUS_FMT_YVYU8_2X8, .fmt = { .fourcc = V4L2_PIX_FMT_VYUY, .name = "VYUY", @@ -1020,7 +1020,7 @@ static const struct soc_mbus_lookup omap1_cam_formats[] = { .layout = SOC_MBUS_LAYOUT_PACKED, }, }, { - .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE, + .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE, .fmt = { .fourcc = V4L2_PIX_FMT_RGB555, .name = "RGB555", @@ -1030,7 +1030,7 @@ static const struct soc_mbus_lookup omap1_cam_formats[] = { .layout = SOC_MBUS_LAYOUT_PACKED, }, }, { - .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE, + .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, .fmt = { .fourcc = V4L2_PIX_FMT_RGB555X, .name = "RGB555X", @@ -1040,7 +1040,7 @@ static const struct soc_mbus_lookup omap1_cam_formats[] = { .layout = SOC_MBUS_LAYOUT_PACKED, }, }, { - .code = V4L2_MBUS_FMT_RGB565_2X8_BE, + .code = MEDIA_BUS_FMT_RGB565_2X8_BE, .fmt = { .fourcc = V4L2_PIX_FMT_RGB565, .name = "RGB565", @@ -1050,7 +1050,7 @@ static const struct soc_mbus_lookup omap1_cam_formats[] = { .layout = SOC_MBUS_LAYOUT_PACKED, }, }, { - .code = V4L2_MBUS_FMT_RGB565_2X8_LE, + .code = MEDIA_BUS_FMT_RGB565_2X8_LE, .fmt = { .fourcc = V4L2_PIX_FMT_RGB565X, .name = "RGB565X", @@ -1068,7 +1068,7 @@ static int omap1_cam_get_formats(struct soc_camera_device *icd, struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct device *dev = icd->parent; int formats = 0, ret; - enum v4l2_mbus_pixelcode code; + u32 code; const struct soc_mbus_pixelfmt *fmt; ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); @@ -1088,14 +1088,14 @@ static int omap1_cam_get_formats(struct soc_camera_device *icd, return 0; switch (code) { - case V4L2_MBUS_FMT_YUYV8_2X8: - case V4L2_MBUS_FMT_YVYU8_2X8: - case V4L2_MBUS_FMT_UYVY8_2X8: - case V4L2_MBUS_FMT_VYUY8_2X8: - case V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE: - case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE: - case V4L2_MBUS_FMT_RGB565_2X8_BE: - case V4L2_MBUS_FMT_RGB565_2X8_LE: + case MEDIA_BUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_YVYU8_2X8: + case MEDIA_BUS_FMT_UYVY8_2X8: + case MEDIA_BUS_FMT_VYUY8_2X8: + case MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE: + case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE: + case MEDIA_BUS_FMT_RGB565_2X8_BE: + case MEDIA_BUS_FMT_RGB565_2X8_LE: formats++; if (xlate) { xlate->host_fmt = soc_mbus_find_fmtdesc(code, diff --git a/drivers/media/platform/soc_camera/pxa_camera.c b/drivers/media/platform/soc_camera/pxa_camera.c index 66178fc9f9eb..951226af0eba 100644 --- a/drivers/media/platform/soc_camera/pxa_camera.c +++ b/drivers/media/platform/soc_camera/pxa_camera.c @@ -187,7 +187,7 @@ struct pxa_cam_dma { struct pxa_buffer { /* common v4l buffer stuff -- must be first */ struct videobuf_buffer vb; - enum v4l2_mbus_pixelcode code; + u32 code; /* our descriptor lists for Y, U and V channels */ struct pxa_cam_dma dmas[3]; int inwork; @@ -1253,7 +1253,7 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, unsigned int id struct device *dev = icd->parent; int formats = 0, ret; struct pxa_cam *cam; - enum v4l2_mbus_pixelcode code; + u32 code; const struct soc_mbus_pixelfmt *fmt; ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); @@ -1283,7 +1283,7 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, unsigned int id } switch (code) { - case V4L2_MBUS_FMT_UYVY8_2X8: + case MEDIA_BUS_FMT_UYVY8_2X8: formats++; if (xlate) { xlate->host_fmt = &pxa_camera_formats[0]; @@ -1292,11 +1292,11 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, unsigned int id dev_dbg(dev, "Providing format %s using code %d\n", pxa_camera_formats[0].name, code); } - case V4L2_MBUS_FMT_VYUY8_2X8: - case V4L2_MBUS_FMT_YUYV8_2X8: - case V4L2_MBUS_FMT_YVYU8_2X8: - case V4L2_MBUS_FMT_RGB565_2X8_LE: - case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE: + case MEDIA_BUS_FMT_VYUY8_2X8: + case MEDIA_BUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_YVYU8_2X8: + case MEDIA_BUS_FMT_RGB565_2X8_LE: + case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE: if (xlate) dev_dbg(dev, "Providing format %s packed\n", fmt->name); diff --git a/drivers/media/platform/soc_camera/rcar_vin.c b/drivers/media/platform/soc_camera/rcar_vin.c index 20defcb8b31b..8d8438b10b87 100644 --- a/drivers/media/platform/soc_camera/rcar_vin.c +++ b/drivers/media/platform/soc_camera/rcar_vin.c @@ -272,16 +272,16 @@ static int rcar_vin_setup(struct rcar_vin_priv *priv) /* input interface */ switch (icd->current_fmt->code) { - case V4L2_MBUS_FMT_YUYV8_1X16: + case MEDIA_BUS_FMT_YUYV8_1X16: /* BT.601/BT.1358 16bit YCbCr422 */ vnmc |= VNMC_INF_YUV16; break; - case V4L2_MBUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_YUYV8_2X8: /* BT.656 8bit YCbCr422 or BT.601 8bit YCbCr422 */ vnmc |= priv->pdata_flags & RCAR_VIN_BT656 ? VNMC_INF_YUV8_BT656 : VNMC_INF_YUV8_BT601; break; - case V4L2_MBUS_FMT_YUYV10_2X10: + case MEDIA_BUS_FMT_YUYV10_2X10: /* BT.656 10bit YCbCr422 or BT.601 10bit YCbCr422 */ vnmc |= priv->pdata_flags & RCAR_VIN_BT656 ? VNMC_INF_YUV10_BT656 : VNMC_INF_YUV10_BT601; @@ -921,7 +921,7 @@ static int rcar_vin_get_formats(struct soc_camera_device *icd, unsigned int idx, int ret, k, n; int formats = 0; struct rcar_vin_cam *cam; - enum v4l2_mbus_pixelcode code; + u32 code; const struct soc_mbus_pixelfmt *fmt; ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); @@ -1010,9 +1010,9 @@ static int rcar_vin_get_formats(struct soc_camera_device *icd, unsigned int idx, cam->extra_fmt = NULL; switch (code) { - case V4L2_MBUS_FMT_YUYV8_1X16: - case V4L2_MBUS_FMT_YUYV8_2X8: - case V4L2_MBUS_FMT_YUYV10_2X10: + case MEDIA_BUS_FMT_YUYV8_1X16: + case MEDIA_BUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_YUYV10_2X10: if (cam->extra_fmt) break; diff --git a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c index 20ad4a571d37..5f58ed995320 100644 --- a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c +++ b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c @@ -149,7 +149,7 @@ struct sh_mobile_ceu_cam { /* Camera cropping rectangle */ struct v4l2_rect rect; const struct soc_mbus_pixelfmt *extra_fmt; - enum v4l2_mbus_pixelcode code; + u32 code; }; static struct sh_mobile_ceu_buffer *to_ceu_vb(struct vb2_buffer *vb) @@ -861,16 +861,16 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd) case V4L2_PIX_FMT_NV16: case V4L2_PIX_FMT_NV61: switch (cam->code) { - case V4L2_MBUS_FMT_UYVY8_2X8: + case MEDIA_BUS_FMT_UYVY8_2X8: value = 0x00000000; /* Cb0, Y0, Cr0, Y1 */ break; - case V4L2_MBUS_FMT_VYUY8_2X8: + case MEDIA_BUS_FMT_VYUY8_2X8: value = 0x00000100; /* Cr0, Y0, Cb0, Y1 */ break; - case V4L2_MBUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_YUYV8_2X8: value = 0x00000200; /* Y0, Cb0, Y1, Cr0 */ break; - case V4L2_MBUS_FMT_YVYU8_2X8: + case MEDIA_BUS_FMT_YVYU8_2X8: value = 0x00000300; /* Y0, Cr0, Y1, Cb0 */ break; default: @@ -1048,7 +1048,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int int ret, k, n; int formats = 0; struct sh_mobile_ceu_cam *cam; - enum v4l2_mbus_pixelcode code; + u32 code; const struct soc_mbus_pixelfmt *fmt; ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); @@ -1141,10 +1141,10 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int cam->extra_fmt = NULL; switch (code) { - case V4L2_MBUS_FMT_UYVY8_2X8: - case V4L2_MBUS_FMT_VYUY8_2X8: - case V4L2_MBUS_FMT_YUYV8_2X8: - case V4L2_MBUS_FMT_YVYU8_2X8: + case MEDIA_BUS_FMT_UYVY8_2X8: + case MEDIA_BUS_FMT_VYUY8_2X8: + case MEDIA_BUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_YVYU8_2X8: if (cam->extra_fmt) break; diff --git a/drivers/media/platform/soc_camera/sh_mobile_csi2.c b/drivers/media/platform/soc_camera/sh_mobile_csi2.c index 05dd21a35d63..c738e27a75d7 100644 --- a/drivers/media/platform/soc_camera/sh_mobile_csi2.c +++ b/drivers/media/platform/soc_camera/sh_mobile_csi2.c @@ -59,28 +59,28 @@ static int sh_csi2_try_fmt(struct v4l2_subdev *sd, switch (pdata->type) { case SH_CSI2C: switch (mf->code) { - case V4L2_MBUS_FMT_UYVY8_2X8: /* YUV422 */ - case V4L2_MBUS_FMT_YUYV8_1_5X8: /* YUV420 */ - case V4L2_MBUS_FMT_Y8_1X8: /* RAW8 */ - case V4L2_MBUS_FMT_SBGGR8_1X8: - case V4L2_MBUS_FMT_SGRBG8_1X8: + case MEDIA_BUS_FMT_UYVY8_2X8: /* YUV422 */ + case MEDIA_BUS_FMT_YUYV8_1_5X8: /* YUV420 */ + case MEDIA_BUS_FMT_Y8_1X8: /* RAW8 */ + case MEDIA_BUS_FMT_SBGGR8_1X8: + case MEDIA_BUS_FMT_SGRBG8_1X8: break; default: /* All MIPI CSI-2 devices must support one of primary formats */ - mf->code = V4L2_MBUS_FMT_YUYV8_2X8; + mf->code = MEDIA_BUS_FMT_YUYV8_2X8; } break; case SH_CSI2I: switch (mf->code) { - case V4L2_MBUS_FMT_Y8_1X8: /* RAW8 */ - case V4L2_MBUS_FMT_SBGGR8_1X8: - case V4L2_MBUS_FMT_SGRBG8_1X8: - case V4L2_MBUS_FMT_SBGGR10_1X10: /* RAW10 */ - case V4L2_MBUS_FMT_SBGGR12_1X12: /* RAW12 */ + case MEDIA_BUS_FMT_Y8_1X8: /* RAW8 */ + case MEDIA_BUS_FMT_SBGGR8_1X8: + case MEDIA_BUS_FMT_SGRBG8_1X8: + case MEDIA_BUS_FMT_SBGGR10_1X10: /* RAW10 */ + case MEDIA_BUS_FMT_SBGGR12_1X12: /* RAW12 */ break; default: /* All MIPI CSI-2 devices must support one of primary formats */ - mf->code = V4L2_MBUS_FMT_SBGGR8_1X8; + mf->code = MEDIA_BUS_FMT_SBGGR8_1X8; } break; } @@ -104,21 +104,21 @@ static int sh_csi2_s_fmt(struct v4l2_subdev *sd, return -EINVAL; switch (mf->code) { - case V4L2_MBUS_FMT_UYVY8_2X8: + case MEDIA_BUS_FMT_UYVY8_2X8: tmp |= 0x1e; /* YUV422 8 bit */ break; - case V4L2_MBUS_FMT_YUYV8_1_5X8: + case MEDIA_BUS_FMT_YUYV8_1_5X8: tmp |= 0x18; /* YUV420 8 bit */ break; - case V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE: + case MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE: tmp |= 0x21; /* RGB555 */ break; - case V4L2_MBUS_FMT_RGB565_2X8_BE: + case MEDIA_BUS_FMT_RGB565_2X8_BE: tmp |= 0x22; /* RGB565 */ break; - case V4L2_MBUS_FMT_Y8_1X8: - case V4L2_MBUS_FMT_SBGGR8_1X8: - case V4L2_MBUS_FMT_SGRBG8_1X8: + case MEDIA_BUS_FMT_Y8_1X8: + case MEDIA_BUS_FMT_SBGGR8_1X8: + case MEDIA_BUS_FMT_SGRBG8_1X8: tmp |= 0x2a; /* RAW8 */ break; default: diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index 8e61b976da19..f4be2a1c659a 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -460,7 +460,7 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd) struct soc_camera_host *ici = to_soc_camera_host(icd->parent); unsigned int i, fmts = 0, raw_fmts = 0; int ret; - enum v4l2_mbus_pixelcode code; + u32 code; while (!v4l2_subdev_call(sd, video, enum_mbus_fmt, raw_fmts, &code)) raw_fmts++; diff --git a/drivers/media/platform/soc_camera/soc_camera_platform.c b/drivers/media/platform/soc_camera/soc_camera_platform.c index ceaddfb85e49..f2ce1ab06d53 100644 --- a/drivers/media/platform/soc_camera/soc_camera_platform.c +++ b/drivers/media/platform/soc_camera/soc_camera_platform.c @@ -62,7 +62,7 @@ static struct v4l2_subdev_core_ops platform_subdev_core_ops = { }; static int soc_camera_platform_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - enum v4l2_mbus_pixelcode *code) + u32 *code) { struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); diff --git a/drivers/media/platform/soc_camera/soc_mediabus.c b/drivers/media/platform/soc_camera/soc_mediabus.c index dc02deca7563..1dbcd426683c 100644 --- a/drivers/media/platform/soc_camera/soc_mediabus.c +++ b/drivers/media/platform/soc_camera/soc_mediabus.c @@ -17,7 +17,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = { { - .code = V4L2_MBUS_FMT_YUYV8_2X8, + .code = MEDIA_BUS_FMT_YUYV8_2X8, .fmt = { .fourcc = V4L2_PIX_FMT_YUYV, .name = "YUYV", @@ -27,7 +27,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = { .layout = SOC_MBUS_LAYOUT_PACKED, }, }, { - .code = V4L2_MBUS_FMT_YVYU8_2X8, + .code = MEDIA_BUS_FMT_YVYU8_2X8, .fmt = { .fourcc = V4L2_PIX_FMT_YVYU, .name = "YVYU", @@ -37,7 +37,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = { .layout = SOC_MBUS_LAYOUT_PACKED, }, }, { - .code = V4L2_MBUS_FMT_UYVY8_2X8, + .code = MEDIA_BUS_FMT_UYVY8_2X8, .fmt = { .fourcc = V4L2_PIX_FMT_UYVY, .name = "UYVY", @@ -47,7 +47,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = { .layout = SOC_MBUS_LAYOUT_PACKED, }, }, { - .code = V4L2_MBUS_FMT_VYUY8_2X8, + .code = MEDIA_BUS_FMT_VYUY8_2X8, .fmt = { .fourcc = V4L2_PIX_FMT_VYUY, .name = "VYUY", @@ -57,7 +57,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = { .layout = SOC_MBUS_LAYOUT_PACKED, }, }, { - .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE, + .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, .fmt = { .fourcc = V4L2_PIX_FMT_RGB555, .name = "RGB555", @@ -67,7 +67,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = { .layout = SOC_MBUS_LAYOUT_PACKED, }, }, { - .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE, + .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE, .fmt = { .fourcc = V4L2_PIX_FMT_RGB555X, .name = "RGB555X", @@ -77,7 +77,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = { .layout = SOC_MBUS_LAYOUT_PACKED, }, }, { - .code = V4L2_MBUS_FMT_RGB565_2X8_LE, + .code = MEDIA_BUS_FMT_RGB565_2X8_LE, .fmt = { .fourcc = V4L2_PIX_FMT_RGB565, .name = "RGB565", @@ -87,7 +87,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = { .layout = SOC_MBUS_LAYOUT_PACKED, }, }, { - .code = V4L2_MBUS_FMT_RGB565_2X8_BE, + .code = MEDIA_BUS_FMT_RGB565_2X8_BE, .fmt = { .fourcc = V4L2_PIX_FMT_RGB565X, .name = "RGB565X", @@ -97,7 +97,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = { .layout = SOC_MBUS_LAYOUT_PACKED, }, }, { - .code = V4L2_MBUS_FMT_RGB666_1X18, + .code = MEDIA_BUS_FMT_RGB666_1X18, .fmt = { .fourcc = V4L2_PIX_FMT_RGB32, .name = "RGB666/32bpp", @@ -106,7 +106,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = { .order = SOC_MBUS_ORDER_LE, }, }, { - .code = V4L2_MBUS_FMT_RGB888_1X24, + .code = MEDIA_BUS_FMT_RGB888_1X24, .fmt = { .fourcc = V4L2_PIX_FMT_RGB32, .name = "RGB888/32bpp", @@ -115,7 +115,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = { .order = SOC_MBUS_ORDER_LE, }, }, { - .code = V4L2_MBUS_FMT_RGB888_2X12_BE, + .code = MEDIA_BUS_FMT_RGB888_2X12_BE, .fmt = { .fourcc = V4L2_PIX_FMT_RGB32, .name = "RGB888/32bpp", @@ -124,7 +124,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = { .order = SOC_MBUS_ORDER_BE, }, }, { - .code = V4L2_MBUS_FMT_RGB888_2X12_LE, + .code = MEDIA_BUS_FMT_RGB888_2X12_LE, .fmt = { .fourcc = V4L2_PIX_FMT_RGB32, .name = "RGB888/32bpp", @@ -133,7 +133,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = { .order = SOC_MBUS_ORDER_LE, }, }, { - .code = V4L2_MBUS_FMT_SBGGR8_1X8, + .code = MEDIA_BUS_FMT_SBGGR8_1X8, .fmt = { .fourcc = V4L2_PIX_FMT_SBGGR8, .name = "Bayer 8 BGGR", @@ -143,7 +143,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = { .layout = SOC_MBUS_LAYOUT_PACKED, }, }, { - .code = V4L2_MBUS_FMT_SBGGR10_1X10, + .code = MEDIA_BUS_FMT_SBGGR10_1X10, .fmt = { .fourcc = V4L2_PIX_FMT_SBGGR10, .name = "Bayer 10 BGGR", @@ -153,7 +153,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = { .layout = SOC_MBUS_LAYOUT_PACKED, }, }, { - .code = V4L2_MBUS_FMT_Y8_1X8, + .code = MEDIA_BUS_FMT_Y8_1X8, .fmt = { .fourcc = V4L2_PIX_FMT_GREY, .name = "Grey", @@ -163,7 +163,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = { .layout = SOC_MBUS_LAYOUT_PACKED, }, }, { - .code = V4L2_MBUS_FMT_Y10_1X10, + .code = MEDIA_BUS_FMT_Y10_1X10, .fmt = { .fourcc = V4L2_PIX_FMT_Y10, .name = "Grey 10bit", @@ -173,7 +173,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = { .layout = SOC_MBUS_LAYOUT_PACKED, }, }, { - .code = V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE, + .code = MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, .fmt = { .fourcc = V4L2_PIX_FMT_SBGGR10, .name = "Bayer 10 BGGR", @@ -183,7 +183,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = { .layout = SOC_MBUS_LAYOUT_PACKED, }, }, { - .code = V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE, + .code = MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE, .fmt = { .fourcc = V4L2_PIX_FMT_SBGGR10, .name = "Bayer 10 BGGR", @@ -193,7 +193,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = { .layout = SOC_MBUS_LAYOUT_PACKED, }, }, { - .code = V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE, + .code = MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE, .fmt = { .fourcc = V4L2_PIX_FMT_SBGGR10, .name = "Bayer 10 BGGR", @@ -203,7 +203,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = { .layout = SOC_MBUS_LAYOUT_PACKED, }, }, { - .code = V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE, + .code = MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE, .fmt = { .fourcc = V4L2_PIX_FMT_SBGGR10, .name = "Bayer 10 BGGR", @@ -213,7 +213,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = { .layout = SOC_MBUS_LAYOUT_PACKED, }, }, { - .code = V4L2_MBUS_FMT_JPEG_1X8, + .code = MEDIA_BUS_FMT_JPEG_1X8, .fmt = { .fourcc = V4L2_PIX_FMT_JPEG, .name = "JPEG", @@ -223,7 +223,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = { .layout = SOC_MBUS_LAYOUT_PACKED, }, }, { - .code = V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE, + .code = MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE, .fmt = { .fourcc = V4L2_PIX_FMT_RGB444, .name = "RGB444", @@ -233,7 +233,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = { .layout = SOC_MBUS_LAYOUT_PACKED, }, }, { - .code = V4L2_MBUS_FMT_YUYV8_1_5X8, + .code = MEDIA_BUS_FMT_YUYV8_1_5X8, .fmt = { .fourcc = V4L2_PIX_FMT_YUV420, .name = "YUYV 4:2:0", @@ -243,7 +243,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = { .layout = SOC_MBUS_LAYOUT_PACKED, }, }, { - .code = V4L2_MBUS_FMT_YVYU8_1_5X8, + .code = MEDIA_BUS_FMT_YVYU8_1_5X8, .fmt = { .fourcc = V4L2_PIX_FMT_YVU420, .name = "YVYU 4:2:0", @@ -253,7 +253,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = { .layout = SOC_MBUS_LAYOUT_PACKED, }, }, { - .code = V4L2_MBUS_FMT_UYVY8_1X16, + .code = MEDIA_BUS_FMT_UYVY8_1X16, .fmt = { .fourcc = V4L2_PIX_FMT_UYVY, .name = "UYVY 16bit", @@ -263,7 +263,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = { .layout = SOC_MBUS_LAYOUT_PACKED, }, }, { - .code = V4L2_MBUS_FMT_VYUY8_1X16, + .code = MEDIA_BUS_FMT_VYUY8_1X16, .fmt = { .fourcc = V4L2_PIX_FMT_VYUY, .name = "VYUY 16bit", @@ -273,7 +273,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = { .layout = SOC_MBUS_LAYOUT_PACKED, }, }, { - .code = V4L2_MBUS_FMT_YUYV8_1X16, + .code = MEDIA_BUS_FMT_YUYV8_1X16, .fmt = { .fourcc = V4L2_PIX_FMT_YUYV, .name = "YUYV 16bit", @@ -283,7 +283,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = { .layout = SOC_MBUS_LAYOUT_PACKED, }, }, { - .code = V4L2_MBUS_FMT_YVYU8_1X16, + .code = MEDIA_BUS_FMT_YVYU8_1X16, .fmt = { .fourcc = V4L2_PIX_FMT_YVYU, .name = "YVYU 16bit", @@ -293,7 +293,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = { .layout = SOC_MBUS_LAYOUT_PACKED, }, }, { - .code = V4L2_MBUS_FMT_SGRBG8_1X8, + .code = MEDIA_BUS_FMT_SGRBG8_1X8, .fmt = { .fourcc = V4L2_PIX_FMT_SGRBG8, .name = "Bayer 8 GRBG", @@ -303,7 +303,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = { .layout = SOC_MBUS_LAYOUT_PACKED, }, }, { - .code = V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, + .code = MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, .fmt = { .fourcc = V4L2_PIX_FMT_SGRBG10DPCM8, .name = "Bayer 10 BGGR DPCM 8", @@ -313,7 +313,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = { .layout = SOC_MBUS_LAYOUT_PACKED, }, }, { - .code = V4L2_MBUS_FMT_SGBRG10_1X10, + .code = MEDIA_BUS_FMT_SGBRG10_1X10, .fmt = { .fourcc = V4L2_PIX_FMT_SGBRG10, .name = "Bayer 10 GBRG", @@ -323,7 +323,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = { .layout = SOC_MBUS_LAYOUT_PACKED, }, }, { - .code = V4L2_MBUS_FMT_SGRBG10_1X10, + .code = MEDIA_BUS_FMT_SGRBG10_1X10, .fmt = { .fourcc = V4L2_PIX_FMT_SGRBG10, .name = "Bayer 10 GRBG", @@ -333,7 +333,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = { .layout = SOC_MBUS_LAYOUT_PACKED, }, }, { - .code = V4L2_MBUS_FMT_SRGGB10_1X10, + .code = MEDIA_BUS_FMT_SRGGB10_1X10, .fmt = { .fourcc = V4L2_PIX_FMT_SRGGB10, .name = "Bayer 10 RGGB", @@ -343,7 +343,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = { .layout = SOC_MBUS_LAYOUT_PACKED, }, }, { - .code = V4L2_MBUS_FMT_SBGGR12_1X12, + .code = MEDIA_BUS_FMT_SBGGR12_1X12, .fmt = { .fourcc = V4L2_PIX_FMT_SBGGR12, .name = "Bayer 12 BGGR", @@ -353,7 +353,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = { .layout = SOC_MBUS_LAYOUT_PACKED, }, }, { - .code = V4L2_MBUS_FMT_SGBRG12_1X12, + .code = MEDIA_BUS_FMT_SGBRG12_1X12, .fmt = { .fourcc = V4L2_PIX_FMT_SGBRG12, .name = "Bayer 12 GBRG", @@ -363,7 +363,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = { .layout = SOC_MBUS_LAYOUT_PACKED, }, }, { - .code = V4L2_MBUS_FMT_SGRBG12_1X12, + .code = MEDIA_BUS_FMT_SGRBG12_1X12, .fmt = { .fourcc = V4L2_PIX_FMT_SGRBG12, .name = "Bayer 12 GRBG", @@ -373,7 +373,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = { .layout = SOC_MBUS_LAYOUT_PACKED, }, }, { - .code = V4L2_MBUS_FMT_SRGGB12_1X12, + .code = MEDIA_BUS_FMT_SRGGB12_1X12, .fmt = { .fourcc = V4L2_PIX_FMT_SRGGB12, .name = "Bayer 12 RGGB", @@ -458,7 +458,7 @@ s32 soc_mbus_image_size(const struct soc_mbus_pixelfmt *mf, EXPORT_SYMBOL(soc_mbus_image_size); const struct soc_mbus_pixelfmt *soc_mbus_find_fmtdesc( - enum v4l2_mbus_pixelcode code, + u32 code, const struct soc_mbus_lookup *lookup, int n) { @@ -473,7 +473,7 @@ const struct soc_mbus_pixelfmt *soc_mbus_find_fmtdesc( EXPORT_SYMBOL(soc_mbus_find_fmtdesc); const struct soc_mbus_pixelfmt *soc_mbus_get_fmtdesc( - enum v4l2_mbus_pixelcode code) + u32 code) { return soc_mbus_find_fmtdesc(code, mbus_fmt, ARRAY_SIZE(mbus_fmt)); } diff --git a/drivers/media/platform/via-camera.c b/drivers/media/platform/via-camera.c index ae6870cb8339..2616483fce0b 100644 --- a/drivers/media/platform/via-camera.c +++ b/drivers/media/platform/via-camera.c @@ -101,7 +101,7 @@ struct via_camera { */ struct v4l2_pix_format sensor_format; struct v4l2_pix_format user_format; - enum v4l2_mbus_pixelcode mbus_code; + u32 mbus_code; }; /* @@ -143,12 +143,12 @@ static struct via_format { __u8 *desc; __u32 pixelformat; int bpp; /* Bytes per pixel */ - enum v4l2_mbus_pixelcode mbus_code; + u32 mbus_code; } via_formats[] = { { .desc = "YUYV 4:2:2", .pixelformat = V4L2_PIX_FMT_YUYV, - .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8, + .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, .bpp = 2, }, /* RGB444 and Bayer should be doable, but have never been @@ -849,7 +849,7 @@ static const struct v4l2_pix_format viacam_def_pix_format = { .sizeimage = VGA_WIDTH * VGA_HEIGHT * 2, }; -static const enum v4l2_mbus_pixelcode via_def_mbus_code = V4L2_MBUS_FMT_YUYV8_2X8; +static const u32 via_def_mbus_code = MEDIA_BUS_FMT_YUYV8_2X8; static int viacam_enum_fmt_vid_cap(struct file *filp, void *priv, struct v4l2_fmtdesc *fmt) diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c index a0c1984c733e..b21f381a9862 100644 --- a/drivers/media/platform/vsp1/vsp1_bru.c +++ b/drivers/media/platform/vsp1/vsp1_bru.c @@ -187,8 +187,8 @@ static int bru_enum_mbus_code(struct v4l2_subdev *subdev, struct v4l2_subdev_mbus_code_enum *code) { static const unsigned int codes[] = { - V4L2_MBUS_FMT_ARGB8888_1X32, - V4L2_MBUS_FMT_AYUV8_1X32, + MEDIA_BUS_FMT_ARGB8888_1X32, + MEDIA_BUS_FMT_AYUV8_1X32, }; struct v4l2_mbus_framefmt *format; @@ -215,8 +215,8 @@ static int bru_enum_frame_size(struct v4l2_subdev *subdev, if (fse->index) return -EINVAL; - if (fse->code != V4L2_MBUS_FMT_ARGB8888_1X32 && - fse->code != V4L2_MBUS_FMT_AYUV8_1X32) + if (fse->code != MEDIA_BUS_FMT_ARGB8888_1X32 && + fse->code != MEDIA_BUS_FMT_AYUV8_1X32) return -EINVAL; fse->min_width = BRU_MIN_SIZE; @@ -261,9 +261,9 @@ static void bru_try_format(struct vsp1_bru *bru, struct v4l2_subdev_fh *fh, switch (pad) { case BRU_PAD_SINK(0): /* Default to YUV if the requested format is not supported. */ - if (fmt->code != V4L2_MBUS_FMT_ARGB8888_1X32 && - fmt->code != V4L2_MBUS_FMT_AYUV8_1X32) - fmt->code = V4L2_MBUS_FMT_AYUV8_1X32; + if (fmt->code != MEDIA_BUS_FMT_ARGB8888_1X32 && + fmt->code != MEDIA_BUS_FMT_AYUV8_1X32) + fmt->code = MEDIA_BUS_FMT_AYUV8_1X32; break; default: diff --git a/drivers/media/platform/vsp1/vsp1_hsit.c b/drivers/media/platform/vsp1/vsp1_hsit.c index db2950a73c60..80bedc554ee3 100644 --- a/drivers/media/platform/vsp1/vsp1_hsit.c +++ b/drivers/media/platform/vsp1/vsp1_hsit.c @@ -70,9 +70,9 @@ static int hsit_enum_mbus_code(struct v4l2_subdev *subdev, if ((code->pad == HSIT_PAD_SINK && !hsit->inverse) | (code->pad == HSIT_PAD_SOURCE && hsit->inverse)) - code->code = V4L2_MBUS_FMT_ARGB8888_1X32; + code->code = MEDIA_BUS_FMT_ARGB8888_1X32; else - code->code = V4L2_MBUS_FMT_AHSV8888_1X32; + code->code = MEDIA_BUS_FMT_AHSV8888_1X32; return 0; } @@ -136,8 +136,8 @@ static int hsit_set_format(struct v4l2_subdev *subdev, return 0; } - format->code = hsit->inverse ? V4L2_MBUS_FMT_AHSV8888_1X32 - : V4L2_MBUS_FMT_ARGB8888_1X32; + format->code = hsit->inverse ? MEDIA_BUS_FMT_AHSV8888_1X32 + : MEDIA_BUS_FMT_ARGB8888_1X32; format->width = clamp_t(unsigned int, fmt->format.width, HSIT_MIN_SIZE, HSIT_MAX_SIZE); format->height = clamp_t(unsigned int, fmt->format.height, @@ -151,8 +151,8 @@ static int hsit_set_format(struct v4l2_subdev *subdev, format = vsp1_entity_get_pad_format(&hsit->entity, fh, HSIT_PAD_SOURCE, fmt->which); *format = fmt->format; - format->code = hsit->inverse ? V4L2_MBUS_FMT_ARGB8888_1X32 - : V4L2_MBUS_FMT_AHSV8888_1X32; + format->code = hsit->inverse ? MEDIA_BUS_FMT_ARGB8888_1X32 + : MEDIA_BUS_FMT_AHSV8888_1X32; return 0; } diff --git a/drivers/media/platform/vsp1/vsp1_lif.c b/drivers/media/platform/vsp1/vsp1_lif.c index d4fb23e9c4a8..17a6ca7dafe6 100644 --- a/drivers/media/platform/vsp1/vsp1_lif.c +++ b/drivers/media/platform/vsp1/vsp1_lif.c @@ -78,8 +78,8 @@ static int lif_enum_mbus_code(struct v4l2_subdev *subdev, struct v4l2_subdev_mbus_code_enum *code) { static const unsigned int codes[] = { - V4L2_MBUS_FMT_ARGB8888_1X32, - V4L2_MBUS_FMT_AYUV8_1X32, + MEDIA_BUS_FMT_ARGB8888_1X32, + MEDIA_BUS_FMT_AYUV8_1X32, }; if (code->pad == LIF_PAD_SINK) { @@ -147,9 +147,9 @@ static int lif_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, struct v4l2_mbus_framefmt *format; /* Default to YUV if the requested format is not supported. */ - if (fmt->format.code != V4L2_MBUS_FMT_ARGB8888_1X32 && - fmt->format.code != V4L2_MBUS_FMT_AYUV8_1X32) - fmt->format.code = V4L2_MBUS_FMT_AYUV8_1X32; + if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 && + fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32) + fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32; format = vsp1_entity_get_pad_format(&lif->entity, fh, fmt->pad, fmt->which); diff --git a/drivers/media/platform/vsp1/vsp1_lut.c b/drivers/media/platform/vsp1/vsp1_lut.c index fea36ebe2565..6f185c3621fe 100644 --- a/drivers/media/platform/vsp1/vsp1_lut.c +++ b/drivers/media/platform/vsp1/vsp1_lut.c @@ -86,9 +86,9 @@ static int lut_enum_mbus_code(struct v4l2_subdev *subdev, struct v4l2_subdev_mbus_code_enum *code) { static const unsigned int codes[] = { - V4L2_MBUS_FMT_ARGB8888_1X32, - V4L2_MBUS_FMT_AHSV8888_1X32, - V4L2_MBUS_FMT_AYUV8_1X32, + MEDIA_BUS_FMT_ARGB8888_1X32, + MEDIA_BUS_FMT_AHSV8888_1X32, + MEDIA_BUS_FMT_AYUV8_1X32, }; struct v4l2_mbus_framefmt *format; @@ -158,10 +158,10 @@ static int lut_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, struct v4l2_mbus_framefmt *format; /* Default to YUV if the requested format is not supported. */ - if (fmt->format.code != V4L2_MBUS_FMT_ARGB8888_1X32 && - fmt->format.code != V4L2_MBUS_FMT_AHSV8888_1X32 && - fmt->format.code != V4L2_MBUS_FMT_AYUV8_1X32) - fmt->format.code = V4L2_MBUS_FMT_AYUV8_1X32; + if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 && + fmt->format.code != MEDIA_BUS_FMT_AHSV8888_1X32 && + fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32) + fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32; format = vsp1_entity_get_pad_format(&lut->entity, fh, fmt->pad, fmt->which); diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.c b/drivers/media/platform/vsp1/vsp1_rwpf.c index ec3dab6a9b9b..1f1ba26a834a 100644 --- a/drivers/media/platform/vsp1/vsp1_rwpf.c +++ b/drivers/media/platform/vsp1/vsp1_rwpf.c @@ -29,8 +29,8 @@ int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev, struct v4l2_subdev_mbus_code_enum *code) { static const unsigned int codes[] = { - V4L2_MBUS_FMT_ARGB8888_1X32, - V4L2_MBUS_FMT_AYUV8_1X32, + MEDIA_BUS_FMT_ARGB8888_1X32, + MEDIA_BUS_FMT_AYUV8_1X32, }; if (code->index >= ARRAY_SIZE(codes)) @@ -103,9 +103,9 @@ int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, struct v4l2_rect *crop; /* Default to YUV if the requested format is not supported. */ - if (fmt->format.code != V4L2_MBUS_FMT_ARGB8888_1X32 && - fmt->format.code != V4L2_MBUS_FMT_AYUV8_1X32) - fmt->format.code = V4L2_MBUS_FMT_AYUV8_1X32; + if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 && + fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32) + fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32; format = vsp1_entity_get_pad_format(&rwpf->entity, fh, fmt->pad, fmt->which); diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c index b7d3c8b9f189..1129494c7cfc 100644 --- a/drivers/media/platform/vsp1/vsp1_sru.c +++ b/drivers/media/platform/vsp1/vsp1_sru.c @@ -139,7 +139,7 @@ static int sru_s_stream(struct v4l2_subdev *subdev, int enable) input = &sru->entity.formats[SRU_PAD_SINK]; output = &sru->entity.formats[SRU_PAD_SOURCE]; - if (input->code == V4L2_MBUS_FMT_ARGB8888_1X32) + if (input->code == MEDIA_BUS_FMT_ARGB8888_1X32) ctrl0 = VI6_SRU_CTRL0_PARAM2 | VI6_SRU_CTRL0_PARAM3 | VI6_SRU_CTRL0_PARAM4; else @@ -170,8 +170,8 @@ static int sru_enum_mbus_code(struct v4l2_subdev *subdev, struct v4l2_subdev_mbus_code_enum *code) { static const unsigned int codes[] = { - V4L2_MBUS_FMT_ARGB8888_1X32, - V4L2_MBUS_FMT_AYUV8_1X32, + MEDIA_BUS_FMT_ARGB8888_1X32, + MEDIA_BUS_FMT_AYUV8_1X32, }; struct v4l2_mbus_framefmt *format; @@ -248,9 +248,9 @@ static void sru_try_format(struct vsp1_sru *sru, struct v4l2_subdev_fh *fh, switch (pad) { case SRU_PAD_SINK: /* Default to YUV if the requested format is not supported. */ - if (fmt->code != V4L2_MBUS_FMT_ARGB8888_1X32 && - fmt->code != V4L2_MBUS_FMT_AYUV8_1X32) - fmt->code = V4L2_MBUS_FMT_AYUV8_1X32; + if (fmt->code != MEDIA_BUS_FMT_ARGB8888_1X32 && + fmt->code != MEDIA_BUS_FMT_AYUV8_1X32) + fmt->code = MEDIA_BUS_FMT_AYUV8_1X32; fmt->width = clamp(fmt->width, SRU_MIN_SIZE, SRU_MAX_SIZE); fmt->height = clamp(fmt->height, SRU_MIN_SIZE, SRU_MAX_SIZE); diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c index de92ef4944b3..a4afec133800 100644 --- a/drivers/media/platform/vsp1/vsp1_uds.c +++ b/drivers/media/platform/vsp1/vsp1_uds.c @@ -173,8 +173,8 @@ static int uds_enum_mbus_code(struct v4l2_subdev *subdev, struct v4l2_subdev_mbus_code_enum *code) { static const unsigned int codes[] = { - V4L2_MBUS_FMT_ARGB8888_1X32, - V4L2_MBUS_FMT_AYUV8_1X32, + MEDIA_BUS_FMT_ARGB8888_1X32, + MEDIA_BUS_FMT_AYUV8_1X32, }; if (code->pad == UDS_PAD_SINK) { @@ -246,9 +246,9 @@ static void uds_try_format(struct vsp1_uds *uds, struct v4l2_subdev_fh *fh, switch (pad) { case UDS_PAD_SINK: /* Default to YUV if the requested format is not supported. */ - if (fmt->code != V4L2_MBUS_FMT_ARGB8888_1X32 && - fmt->code != V4L2_MBUS_FMT_AYUV8_1X32) - fmt->code = V4L2_MBUS_FMT_AYUV8_1X32; + if (fmt->code != MEDIA_BUS_FMT_ARGB8888_1X32 && + fmt->code != MEDIA_BUS_FMT_AYUV8_1X32) + fmt->code = MEDIA_BUS_FMT_AYUV8_1X32; fmt->width = clamp(fmt->width, UDS_MIN_SIZE, UDS_MAX_SIZE); fmt->height = clamp(fmt->height, UDS_MIN_SIZE, UDS_MAX_SIZE); diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c index 915a20eb003e..d91f19a9e1c1 100644 --- a/drivers/media/platform/vsp1/vsp1_video.c +++ b/drivers/media/platform/vsp1/vsp1_video.c @@ -48,85 +48,85 @@ */ static const struct vsp1_format_info vsp1_video_formats[] = { - { V4L2_PIX_FMT_RGB332, V4L2_MBUS_FMT_ARGB8888_1X32, + { V4L2_PIX_FMT_RGB332, MEDIA_BUS_FMT_ARGB8888_1X32, VI6_FMT_RGB_332, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, 1, { 8, 0, 0 }, false, false, 1, 1, false }, - { V4L2_PIX_FMT_ARGB444, V4L2_MBUS_FMT_ARGB8888_1X32, + { V4L2_PIX_FMT_ARGB444, MEDIA_BUS_FMT_ARGB8888_1X32, VI6_FMT_ARGB_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | VI6_RPF_DSWAP_P_WDS, 1, { 16, 0, 0 }, false, false, 1, 1, true }, - { V4L2_PIX_FMT_XRGB444, V4L2_MBUS_FMT_ARGB8888_1X32, + { V4L2_PIX_FMT_XRGB444, MEDIA_BUS_FMT_ARGB8888_1X32, VI6_FMT_XRGB_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | VI6_RPF_DSWAP_P_WDS, 1, { 16, 0, 0 }, false, false, 1, 1, true }, - { V4L2_PIX_FMT_ARGB555, V4L2_MBUS_FMT_ARGB8888_1X32, + { V4L2_PIX_FMT_ARGB555, MEDIA_BUS_FMT_ARGB8888_1X32, VI6_FMT_ARGB_1555, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | VI6_RPF_DSWAP_P_WDS, 1, { 16, 0, 0 }, false, false, 1, 1, true }, - { V4L2_PIX_FMT_XRGB555, V4L2_MBUS_FMT_ARGB8888_1X32, + { V4L2_PIX_FMT_XRGB555, MEDIA_BUS_FMT_ARGB8888_1X32, VI6_FMT_XRGB_1555, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | VI6_RPF_DSWAP_P_WDS, 1, { 16, 0, 0 }, false, false, 1, 1, false }, - { V4L2_PIX_FMT_RGB565, V4L2_MBUS_FMT_ARGB8888_1X32, + { V4L2_PIX_FMT_RGB565, MEDIA_BUS_FMT_ARGB8888_1X32, VI6_FMT_RGB_565, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | VI6_RPF_DSWAP_P_WDS, 1, { 16, 0, 0 }, false, false, 1, 1, false }, - { V4L2_PIX_FMT_BGR24, V4L2_MBUS_FMT_ARGB8888_1X32, + { V4L2_PIX_FMT_BGR24, MEDIA_BUS_FMT_ARGB8888_1X32, VI6_FMT_BGR_888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, 1, { 24, 0, 0 }, false, false, 1, 1, false }, - { V4L2_PIX_FMT_RGB24, V4L2_MBUS_FMT_ARGB8888_1X32, + { V4L2_PIX_FMT_RGB24, MEDIA_BUS_FMT_ARGB8888_1X32, VI6_FMT_RGB_888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, 1, { 24, 0, 0 }, false, false, 1, 1, false }, - { V4L2_PIX_FMT_ABGR32, V4L2_MBUS_FMT_ARGB8888_1X32, + { V4L2_PIX_FMT_ABGR32, MEDIA_BUS_FMT_ARGB8888_1X32, VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS, 1, { 32, 0, 0 }, false, false, 1, 1, true }, - { V4L2_PIX_FMT_XBGR32, V4L2_MBUS_FMT_ARGB8888_1X32, + { V4L2_PIX_FMT_XBGR32, MEDIA_BUS_FMT_ARGB8888_1X32, VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS, 1, { 32, 0, 0 }, false, false, 1, 1, false }, - { V4L2_PIX_FMT_ARGB32, V4L2_MBUS_FMT_ARGB8888_1X32, + { V4L2_PIX_FMT_ARGB32, MEDIA_BUS_FMT_ARGB8888_1X32, VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, 1, { 32, 0, 0 }, false, false, 1, 1, true }, - { V4L2_PIX_FMT_XRGB32, V4L2_MBUS_FMT_ARGB8888_1X32, + { V4L2_PIX_FMT_XRGB32, MEDIA_BUS_FMT_ARGB8888_1X32, VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, 1, { 32, 0, 0 }, false, false, 1, 1, false }, - { V4L2_PIX_FMT_UYVY, V4L2_MBUS_FMT_AYUV8_1X32, + { V4L2_PIX_FMT_UYVY, MEDIA_BUS_FMT_AYUV8_1X32, VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, 1, { 16, 0, 0 }, false, false, 2, 1, false }, - { V4L2_PIX_FMT_VYUY, V4L2_MBUS_FMT_AYUV8_1X32, + { V4L2_PIX_FMT_VYUY, MEDIA_BUS_FMT_AYUV8_1X32, VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, 1, { 16, 0, 0 }, false, true, 2, 1, false }, - { V4L2_PIX_FMT_YUYV, V4L2_MBUS_FMT_AYUV8_1X32, + { V4L2_PIX_FMT_YUYV, MEDIA_BUS_FMT_AYUV8_1X32, VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, 1, { 16, 0, 0 }, true, false, 2, 1, false }, - { V4L2_PIX_FMT_YVYU, V4L2_MBUS_FMT_AYUV8_1X32, + { V4L2_PIX_FMT_YVYU, MEDIA_BUS_FMT_AYUV8_1X32, VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, 1, { 16, 0, 0 }, true, true, 2, 1, false }, - { V4L2_PIX_FMT_NV12M, V4L2_MBUS_FMT_AYUV8_1X32, + { V4L2_PIX_FMT_NV12M, MEDIA_BUS_FMT_AYUV8_1X32, VI6_FMT_Y_UV_420, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, 2, { 8, 16, 0 }, false, false, 2, 2, false }, - { V4L2_PIX_FMT_NV21M, V4L2_MBUS_FMT_AYUV8_1X32, + { V4L2_PIX_FMT_NV21M, MEDIA_BUS_FMT_AYUV8_1X32, VI6_FMT_Y_UV_420, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, 2, { 8, 16, 0 }, false, true, 2, 2, false }, - { V4L2_PIX_FMT_NV16M, V4L2_MBUS_FMT_AYUV8_1X32, + { V4L2_PIX_FMT_NV16M, MEDIA_BUS_FMT_AYUV8_1X32, VI6_FMT_Y_UV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, 2, { 8, 16, 0 }, false, false, 2, 1, false }, - { V4L2_PIX_FMT_NV61M, V4L2_MBUS_FMT_AYUV8_1X32, + { V4L2_PIX_FMT_NV61M, MEDIA_BUS_FMT_AYUV8_1X32, VI6_FMT_Y_UV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, 2, { 8, 16, 0 }, false, true, 2, 1, false }, - { V4L2_PIX_FMT_YUV420M, V4L2_MBUS_FMT_AYUV8_1X32, + { V4L2_PIX_FMT_YUV420M, MEDIA_BUS_FMT_AYUV8_1X32, VI6_FMT_Y_U_V_420, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, 3, { 8, 8, 8 }, false, false, 2, 2, false }, diff --git a/include/media/davinci/vpbe.h b/include/media/davinci/vpbe.h index 57585c7004a4..4376beeb28c2 100644 --- a/include/media/davinci/vpbe.h +++ b/include/media/davinci/vpbe.h @@ -63,7 +63,7 @@ struct vpbe_output { * output basis. If per mode is needed, we may have to move this to * mode_info structure */ - enum v4l2_mbus_pixelcode if_params; + u32 if_params; }; /* encoder configuration info */ diff --git a/include/media/davinci/vpbe_venc.h b/include/media/davinci/vpbe_venc.h index 476fafc2f522..3dbd20026107 100644 --- a/include/media/davinci/vpbe_venc.h +++ b/include/media/davinci/vpbe_venc.h @@ -30,11 +30,10 @@ #define VENC_SECOND_FIELD BIT(2) struct venc_platform_data { - int (*setup_pinmux)(enum v4l2_mbus_pixelcode if_type, - int field); + int (*setup_pinmux)(u32 if_type, int field); int (*setup_clock)(enum vpbe_enc_timings_type type, unsigned int pixclock); - int (*setup_if_config)(enum v4l2_mbus_pixelcode pixcode); + int (*setup_if_config)(u32 pixcode); /* Number of LCD outputs supported */ int num_lcd_outputs; struct vpbe_if_params *lcd_if_params; diff --git a/include/media/exynos-fimc.h b/include/media/exynos-fimc.h index aa44660e2041..69bcd2a07d5c 100644 --- a/include/media/exynos-fimc.h +++ b/include/media/exynos-fimc.h @@ -101,7 +101,7 @@ struct fimc_source_info { * @flags: flags indicating which operation mode format applies to */ struct fimc_fmt { - enum v4l2_mbus_pixelcode mbus_code; + u32 mbus_code; char *name; u32 fourcc; u32 color; diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h index 865246b00127..2f6261f3e570 100644 --- a/include/media/soc_camera.h +++ b/include/media/soc_camera.h @@ -296,7 +296,7 @@ const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc( * format setup. */ struct soc_camera_format_xlate { - enum v4l2_mbus_pixelcode code; + u32 code; const struct soc_mbus_pixelfmt *host_fmt; }; diff --git a/include/media/soc_mediabus.h b/include/media/soc_mediabus.h index d33f6d059692..2ff773785fb6 100644 --- a/include/media/soc_mediabus.h +++ b/include/media/soc_mediabus.h @@ -91,16 +91,16 @@ struct soc_mbus_pixelfmt { * @fmt: pixel format description */ struct soc_mbus_lookup { - enum v4l2_mbus_pixelcode code; + u32 code; struct soc_mbus_pixelfmt fmt; }; const struct soc_mbus_pixelfmt *soc_mbus_find_fmtdesc( - enum v4l2_mbus_pixelcode code, + u32 code, const struct soc_mbus_lookup *lookup, int n); const struct soc_mbus_pixelfmt *soc_mbus_get_fmtdesc( - enum v4l2_mbus_pixelcode code); + u32 code); s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf); s32 soc_mbus_image_size(const struct soc_mbus_pixelfmt *mf, u32 bytes_per_line, u32 height); -- cgit v1.2.3-59-g8ed1b From 5325d844fdae416993c41271a6460fd1c81c6172 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Mon, 10 Nov 2014 17:34:42 -0300 Subject: [media] si4713: add DT binding documentation This patch adds the DT bindings documentation for Silicon Labs Si4713 FM radio transmitter. Signed-off-by: Sebastian Reichel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/devicetree/bindings/media/si4713.txt | 30 ++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/si4713.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/media/si4713.txt b/Documentation/devicetree/bindings/media/si4713.txt new file mode 100644 index 000000000000..5ee5552d3465 --- /dev/null +++ b/Documentation/devicetree/bindings/media/si4713.txt @@ -0,0 +1,30 @@ +* Silicon Labs FM Radio transmitter + +The Silicon Labs Si4713 is an FM radio transmitter with receive power scan +supporting 76-108 MHz. It includes an RDS encoder and has both, a stereo-analog +and a digital interface, which supports I2S, left-justified and a custom +DSP-mode format. It is programmable through an I2C interface. + +Required Properties: +- compatible: Should contain "silabs,si4713" +- reg: the I2C address of the device + +Optional Properties: +- interrupts-extended: Interrupt specifier for the chips interrupt +- reset-gpios: GPIO specifier for the chips reset line +- vdd-supply: phandle for Vdd regulator +- vio-supply: phandle for Vio regulator + +Example: + +&i2c2 { + fmtx: si4713@63 { + compatible = "silabs,si4713"; + reg = <0x63>; + + interrupts-extended = <&gpio2 21 IRQ_TYPE_EDGE_FALLING>; /* 53 */ + reset-gpios = <&gpio6 3 GPIO_ACTIVE_HIGH>; /* 163 */ + vio-supply = <&vio>; + vdd-supply = <&vaux1>; + }; +}; -- cgit v1.2.3-59-g8ed1b From 960fb622f85180f36d3aff82af53e2be3db2f888 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 16 Nov 2014 06:23:05 -0800 Subject: net: provide a per host RSS key generic infrastructure RSS (Receive Side Scaling) typically uses Toeplitz hash and a 40 or 52 bytes RSS key. Some drivers use a constant (and well known key), some drivers use a random key per port, making bonding setups hard to tune. Well known keys increase attack surface, considering that number of queues is usually a power of two. This patch provides infrastructure to help drivers doing the right thing. netdev_rss_key_fill() should be used by drivers to initialize their RSS key, even if they provide ethtool -X support to let user redefine the key later. A new /proc/sys/net/core/netdev_rss_key file can be used to get the host RSS key even for drivers not providing ethtool -x support, in case some applications want to precisely setup flows to match some RX queues. Tested: myhost:~# cat /proc/sys/net/core/netdev_rss_key 11:63:99:bb:79:fb:a5:a7:07:45:b2:20:bf:02:42:2d:08:1a:dd:19:2b:6b:23:ac:56:28:9d:70:c3:ac:e8:16:4b:b7:c1:10:53:a4:78:41:36:40:74:b6:15:ca:27:44:aa:b3:4d:72 myhost:~# ethtool -x eth0 RX flow hash indirection table for eth0 with 8 RX ring(s): 0: 0 1 2 3 4 5 6 7 RSS hash key: 11:63:99:bb:79:fb:a5:a7:07:45:b2:20:bf:02:42:2d:08:1a:dd:19:2b:6b:23:ac:56:28:9d:70:c3:ac:e8:16:4b:b7:c1:10:53:a4:78:41 Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- Documentation/sysctl/net.txt | 22 ++++++++++++++++++++++ include/linux/netdevice.h | 6 ++++++ net/core/ethtool.c | 11 +++++++++++ net/core/sysctl_net_core.c | 19 +++++++++++++++++++ 4 files changed, 58 insertions(+) (limited to 'Documentation') diff --git a/Documentation/sysctl/net.txt b/Documentation/sysctl/net.txt index e26c607468a6..666594b43cff 100644 --- a/Documentation/sysctl/net.txt +++ b/Documentation/sysctl/net.txt @@ -142,6 +142,28 @@ netdev_max_backlog Maximum number of packets, queued on the INPUT side, when the interface receives packets faster than kernel can process them. +netdev_rss_key +-------------- + +RSS (Receive Side Scaling) enabled drivers use a 40 bytes host key that is +randomly generated. +Some user space might need to gather its content even if drivers do not +provide ethtool -x support yet. + +myhost:~# cat /proc/sys/net/core/netdev_rss_key +84:50:f4:00:a8:15:d1:a7:e9:7f:1d:60:35:c7:47:25:42:97:74:ca:56:bb:b6:a1:d8: ... (52 bytes total) + +File contains nul bytes if no driver ever called netdev_rss_key_fill() function. +Note: +/proc/sys/net/core/netdev_rss_key contains 52 bytes of key, +but most drivers only use 40 bytes of it. + +myhost:~# ethtool -x eth0 +RX flow hash indirection table for eth0 with 8 RX ring(s): + 0: 0 1 2 3 4 5 6 7 +RSS hash key: +84:50:f4:00:a8:15:d1:a7:e9:7f:1d:60:35:c7:47:25:42:97:74:ca:56:bb:b6:a1:d8:43:e3:c9:0c:fd:17:55:c2:3a:4d:69:ed:f1:42:89 + netdev_tstamp_prequeue ---------------------- diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 4a6f770377d3..db63cf459ba1 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -3422,6 +3422,12 @@ void netdev_upper_dev_unlink(struct net_device *dev, void netdev_adjacent_rename_links(struct net_device *dev, char *oldname); void *netdev_lower_dev_get_private(struct net_device *dev, struct net_device *lower_dev); + +/* RSS keys are 40 or 52 bytes long */ +#define NETDEV_RSS_KEY_LEN 52 +extern u8 netdev_rss_key[NETDEV_RSS_KEY_LEN]; +void netdev_rss_key_fill(void *buffer, size_t len); + int dev_get_nest_level(struct net_device *dev, bool (*type_check)(struct net_device *dev)); int skb_checksum_help(struct sk_buff *skb); diff --git a/net/core/ethtool.c b/net/core/ethtool.c index b0f84f5ddda8..715f51f321e9 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -25,6 +25,7 @@ #include #include #include +#include /* * Some useful ethtool_ops methods that're device independent. @@ -573,6 +574,16 @@ static int ethtool_copy_validate_indir(u32 *indir, void __user *useraddr, return 0; } +u8 netdev_rss_key[NETDEV_RSS_KEY_LEN]; + +void netdev_rss_key_fill(void *buffer, size_t len) +{ + BUG_ON(len > sizeof(netdev_rss_key)); + net_get_random_once(netdev_rss_key, sizeof(netdev_rss_key)); + memcpy(buffer, netdev_rss_key, len); +} +EXPORT_SYMBOL(netdev_rss_key_fill); + static noinline_for_stack int ethtool_get_rxfh_indir(struct net_device *dev, void __user *useraddr) { diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c index f93f092fe226..31baba2a71ce 100644 --- a/net/core/sysctl_net_core.c +++ b/net/core/sysctl_net_core.c @@ -217,6 +217,18 @@ static int set_default_qdisc(struct ctl_table *table, int write, } #endif +static int proc_do_rss_key(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + struct ctl_table fake_table; + char buf[NETDEV_RSS_KEY_LEN * 3]; + + snprintf(buf, sizeof(buf), "%*phC", NETDEV_RSS_KEY_LEN, netdev_rss_key); + fake_table.data = buf; + fake_table.maxlen = sizeof(buf); + return proc_dostring(&fake_table, write, buffer, lenp, ppos); +} + static struct ctl_table net_core_table[] = { #ifdef CONFIG_NET { @@ -265,6 +277,13 @@ static struct ctl_table net_core_table[] = { .mode = 0644, .proc_handler = proc_dointvec }, + { + .procname = "netdev_rss_key", + .data = &netdev_rss_key, + .maxlen = sizeof(int), + .mode = 0444, + .proc_handler = proc_do_rss_key, + }, #ifdef CONFIG_BPF_JIT { .procname = "bpf_jit_enable", -- cgit v1.2.3-59-g8ed1b From 15962df86e0e89055f9a519f149201ee33d96091 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Tue, 23 Sep 2014 22:42:14 +0200 Subject: dt-bindings: document gpio-charger bindings This documents the binding for the gpio-charger power-supply. Signed-off-by: Heiko Stuebner Reviewed-by: Doug Anderson --- .../bindings/power_supply/gpio-charger.txt | 27 ++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 Documentation/devicetree/bindings/power_supply/gpio-charger.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/power_supply/gpio-charger.txt b/Documentation/devicetree/bindings/power_supply/gpio-charger.txt new file mode 100644 index 000000000000..adbb5dc5b6e9 --- /dev/null +++ b/Documentation/devicetree/bindings/power_supply/gpio-charger.txt @@ -0,0 +1,27 @@ +gpio-charger + +Required properties : + - compatible : "gpio-charger" + - gpios : GPIO indicating the charger presence. + See GPIO binding in bindings/gpio/gpio.txt . + - charger-type : power supply type, one of + unknown + battery + ups + mains + usb-sdp (USB standard downstream port) + usb-dcp (USB dedicated charging port) + usb-cdp (USB charging downstream port) + usb-aca (USB accessory charger adapter) + +Example: + + usb_charger: charger { + compatible = "gpio-charger"; + charger-type = "usb-sdp"; + gpios = <&gpf0 2 0 0 0>; + } + + battery { + power-supplies = <&usb_charger>; + }; -- cgit v1.2.3-59-g8ed1b From b8e64eea41ea71b58e61e35ee347464efd60ca21 Mon Sep 17 00:00:00 2001 From: Robin Gong Date: Fri, 26 Sep 2014 11:59:06 +0800 Subject: power: reset: imx-snvs-poweroff: add power off driver for i.mx6 This driver register pm_power_off with snvs power off function. If your boards NOT use PMIC_ON_REQ to turn on/off external pmic, or use other pin to do, please disable the driver in dts, otherwise, your pm_power_off maybe overwrote by this driver. Signed-off-by: Robin Gong Signed-off-by: Sebastian Reichel --- .../bindings/power_supply/imx-snvs-poweroff.txt | 23 ++++++++ drivers/power/reset/Kconfig | 9 +++ drivers/power/reset/Makefile | 1 + drivers/power/reset/imx-snvs-poweroff.c | 66 ++++++++++++++++++++++ 4 files changed, 99 insertions(+) create mode 100644 Documentation/devicetree/bindings/power_supply/imx-snvs-poweroff.txt create mode 100644 drivers/power/reset/imx-snvs-poweroff.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/power_supply/imx-snvs-poweroff.txt b/Documentation/devicetree/bindings/power_supply/imx-snvs-poweroff.txt new file mode 100644 index 000000000000..dc7c9bad63ea --- /dev/null +++ b/Documentation/devicetree/bindings/power_supply/imx-snvs-poweroff.txt @@ -0,0 +1,23 @@ +i.mx6 Poweroff Driver + +SNVS_LPCR in SNVS module can power off the whole system by pull +PMIC_ON_REQ low if PMIC_ON_REQ is connected with external PMIC. +If you don't want to use PMIC_ON_REQ as power on/off control, +please set status='disabled' to disable this driver. + +Required Properties: +-compatible: "fsl,sec-v4.0-poweroff" +-reg: Specifies the physical address of the SNVS_LPCR register + +Example: + snvs@020cc000 { + compatible = "fsl,sec-v4.0-mon", "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x020cc000 0x4000>; + ..... + snvs_poweroff: snvs-poweroff@38 { + compatible = "fsl,sec-v4.0-poweroff"; + reg = <0x38 0x4>; + }; + } diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index f65ff49bb275..028e76504519 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -71,6 +71,15 @@ config POWER_RESET_HISI help Reboot support for Hisilicon boards. +config POWER_RESET_IMX + bool "IMX6 power-off driver" + depends on POWER_RESET && SOC_IMX6 + help + This driver support power off external PMIC by PMIC_ON_REQ on i.mx6 + boards.If you want to use other pin to control external power,please + say N here or disable in dts to make sure pm_power_off never be + overwrote wrongly by this driver. + config POWER_RESET_MSM bool "Qualcomm MSM power-off driver" depends on ARCH_QCOM diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile index 76ce1c59469b..1d4804d6b323 100644 --- a/drivers/power/reset/Makefile +++ b/drivers/power/reset/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_POWER_RESET_BRCMSTB) += brcmstb-reboot.o obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o obj-$(CONFIG_POWER_RESET_HISI) += hisi-reboot.o +obj-$(CONFIG_POWER_RESET_IMX) += imx-snvs-poweroff.o obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o obj-$(CONFIG_POWER_RESET_LTC2952) += ltc2952-poweroff.o obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o diff --git a/drivers/power/reset/imx-snvs-poweroff.c b/drivers/power/reset/imx-snvs-poweroff.c new file mode 100644 index 000000000000..ad6ce5020ea7 --- /dev/null +++ b/drivers/power/reset/imx-snvs-poweroff.c @@ -0,0 +1,66 @@ +/* Power off driver for i.mx6 + * Copyright (c) 2014, FREESCALE CORPORATION. All rights reserved. + * + * based on msm-poweroff.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 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 + +static void __iomem *snvs_base; + +static void do_imx_poweroff(void) +{ + u32 value = readl(snvs_base); + + /* set TOP and DP_EN bit */ + writel(value | 0x60, snvs_base); +} + +static int imx_poweroff_probe(struct platform_device *pdev) +{ + snvs_base = of_iomap(pdev->dev.of_node, 0); + if (!snvs_base) { + dev_err(&pdev->dev, "failed to get memory\n"); + return -ENODEV; + } + + pm_power_off = do_imx_poweroff; + return 0; +} + +static const struct of_device_id of_imx_poweroff_match[] = { + { .compatible = "fsl,sec-v4.0-poweroff", }, + {}, +}; +MODULE_DEVICE_TABLE(of, of_imx_poweroff_match); + +static struct platform_driver imx_poweroff_driver = { + .probe = imx_poweroff_probe, + .driver = { + .name = "imx-snvs-poweroff", + .of_match_table = of_match_ptr(of_imx_poweroff_match), + }, +}; + +static int __init imx_poweroff_init(void) +{ + return platform_driver_register(&imx_poweroff_driver); +} +device_initcall(imx_poweroff_init); -- cgit v1.2.3-59-g8ed1b From 16b1d26e77b142546e2b9b6dc3b5aa5c44ae3b77 Mon Sep 17 00:00:00 2001 From: Neelesh Gupta Date: Tue, 14 Oct 2014 14:08:36 +0530 Subject: rtc/tpo: Driver to support rtc and wakeup on PowerNV platform The patch implements the OPAL rtc driver that binds with the rtc driver subsystem. The driver uses the platform device infrastructure to probe the rtc device and register it to rtc class framework. The 'wakeup' is supported depending upon the property 'has-tpo' present in the OF node. It provides a way to load the generic rtc driver in in the absence of an OPAL driver. The patch also moves the existing OPAL rtc get/set time interfaces to the new driver and exposes the necessary OPAL calls using EXPORT_SYMBOL_GPL. Test results: ------------- Host: [root@tul169p1 ~]# ls -l /sys/class/rtc/ total 0 lrwxrwxrwx 1 root root 0 Oct 14 03:07 rtc0 -> ../../devices/opal-rtc/rtc/rtc0 [root@tul169p1 ~]# cat /sys/devices/opal-rtc/rtc/rtc0/time 08:10:07 [root@tul169p1 ~]# echo `date '+%s' -d '+ 2 minutes'` > /sys/class/rtc/rtc0/wakealarm [root@tul169p1 ~]# cat /sys/class/rtc/rtc0/wakealarm 1413274345 [root@tul169p1 ~]# FSP: $ smgr mfgState standby $ rtim timeofday System time is valid: 2014/10/14 08:12:04.225115 $ smgr mfgState ipling $ CC: devicetree@vger.kernel.org CC: tglx@linutronix.de CC: rtc-linux@googlegroups.com CC: a.zummo@towertech.it Signed-off-by: Neelesh Gupta Signed-off-by: Michael Ellerman --- Documentation/devicetree/bindings/rtc/rtc-opal.txt | 16 ++ arch/powerpc/include/asm/opal.h | 7 +- arch/powerpc/kernel/time.c | 1 + arch/powerpc/platforms/powernv/opal-async.c | 3 + arch/powerpc/platforms/powernv/opal-rtc.c | 65 ++--- arch/powerpc/platforms/powernv/opal-wrappers.S | 2 + arch/powerpc/platforms/powernv/opal.c | 6 + arch/powerpc/platforms/powernv/setup.c | 2 - drivers/rtc/Kconfig | 11 + drivers/rtc/Makefile | 1 + drivers/rtc/rtc-opal.c | 261 +++++++++++++++++++++ 11 files changed, 325 insertions(+), 50 deletions(-) create mode 100644 Documentation/devicetree/bindings/rtc/rtc-opal.txt create mode 100644 drivers/rtc/rtc-opal.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/rtc/rtc-opal.txt b/Documentation/devicetree/bindings/rtc/rtc-opal.txt new file mode 100644 index 000000000000..af87e5ecac54 --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/rtc-opal.txt @@ -0,0 +1,16 @@ +IBM OPAL real-time clock +------------------------ + +Required properties: +- comapatible: Should be "ibm,opal-rtc" + +Optional properties: +- has-tpo: Decides if the wakeup is supported or not. + +Example: + rtc { + compatible = "ibm,opal-rtc"; + has-tpo; + phandle = <0x10000029>; + linux,phandle = <0x10000029>; + }; diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h index 5d073e50cac8..60250e2d1f0d 100644 --- a/arch/powerpc/include/asm/opal.h +++ b/arch/powerpc/include/asm/opal.h @@ -154,6 +154,8 @@ struct opal_sg_list { #define OPAL_HANDLE_HMI 98 #define OPAL_REGISTER_DUMP_REGION 101 #define OPAL_UNREGISTER_DUMP_REGION 102 +#define OPAL_WRITE_TPO 103 +#define OPAL_READ_TPO 104 #define OPAL_IPMI_SEND 107 #define OPAL_IPMI_RECV 108 @@ -832,6 +834,9 @@ int64_t opal_rtc_read(__be32 *year_month_day, __be64 *hour_minute_second_millisecond); int64_t opal_rtc_write(uint32_t year_month_day, uint64_t hour_minute_second_millisecond); +int64_t opal_tpo_read(uint64_t token, __be32 *year_mon_day, __be32 *hour_min); +int64_t opal_tpo_write(uint64_t token, uint32_t year_mon_day, + uint32_t hour_min); int64_t opal_cec_power_down(uint64_t request); int64_t opal_cec_reboot(void); int64_t opal_read_nvram(uint64_t buffer, uint64_t size, uint64_t offset); @@ -1009,8 +1014,6 @@ extern int opal_async_wait_response(uint64_t token, struct opal_msg *msg); extern int opal_get_sensor_data(u32 sensor_hndl, u32 *sensor_data); struct rtc_time; -extern int opal_set_rtc_time(struct rtc_time *tm); -extern void opal_get_rtc_time(struct rtc_time *tm); extern unsigned long opal_get_boot_time(void); extern void opal_nvram_init(void); extern void opal_flash_init(void); diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 9f8ea617ff2c..fa7c4f12104f 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -989,6 +989,7 @@ void GregorianDay(struct rtc_time * tm) tm->tm_wday = day % 7; } +EXPORT_SYMBOL_GPL(GregorianDay); void to_tm(int tim, struct rtc_time * tm) { diff --git a/arch/powerpc/platforms/powernv/opal-async.c b/arch/powerpc/platforms/powernv/opal-async.c index e462ab947d16..693b6cdac691 100644 --- a/arch/powerpc/platforms/powernv/opal-async.c +++ b/arch/powerpc/platforms/powernv/opal-async.c @@ -71,6 +71,7 @@ int opal_async_get_token_interruptible(void) return token; } +EXPORT_SYMBOL_GPL(opal_async_get_token_interruptible); int __opal_async_release_token(int token) { @@ -102,6 +103,7 @@ int opal_async_release_token(int token) return 0; } +EXPORT_SYMBOL_GPL(opal_async_release_token); int opal_async_wait_response(uint64_t token, struct opal_msg *msg) { @@ -120,6 +122,7 @@ int opal_async_wait_response(uint64_t token, struct opal_msg *msg) return 0; } +EXPORT_SYMBOL_GPL(opal_async_wait_response); static int opal_async_comp_event(struct notifier_block *nb, unsigned long msg_type, void *msg) diff --git a/arch/powerpc/platforms/powernv/opal-rtc.c b/arch/powerpc/platforms/powernv/opal-rtc.c index 499707ddaa9c..37dbee15769f 100644 --- a/arch/powerpc/platforms/powernv/opal-rtc.c +++ b/arch/powerpc/platforms/powernv/opal-rtc.c @@ -15,6 +15,8 @@ #include #include #include +#include +#include #include #include @@ -43,7 +45,7 @@ unsigned long __init opal_get_boot_time(void) long rc = OPAL_BUSY; if (!opal_check_token(OPAL_RTC_READ)) - goto out; + return 0; while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { rc = opal_rtc_read(&__y_m_d, &__h_m_s_ms); @@ -53,62 +55,33 @@ unsigned long __init opal_get_boot_time(void) mdelay(10); } if (rc != OPAL_SUCCESS) - goto out; + return 0; y_m_d = be32_to_cpu(__y_m_d); h_m_s_ms = be64_to_cpu(__h_m_s_ms); opal_to_tm(y_m_d, h_m_s_ms, &tm); return mktime(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); -out: - ppc_md.get_rtc_time = NULL; - ppc_md.set_rtc_time = NULL; - return 0; } -void opal_get_rtc_time(struct rtc_time *tm) +static __init int opal_time_init(void) { - long rc = OPAL_BUSY; - u32 y_m_d; - u64 h_m_s_ms; - __be32 __y_m_d; - __be64 __h_m_s_ms; + struct platform_device *pdev; + struct device_node *rtc; - while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { - rc = opal_rtc_read(&__y_m_d, &__h_m_s_ms); - if (rc == OPAL_BUSY_EVENT) - opal_poll_events(NULL); + rtc = of_find_node_by_path("/ibm,opal/rtc"); + if (rtc) { + pdev = of_platform_device_create(rtc, "opal-rtc", NULL); + of_node_put(rtc); + } else { + if (opal_check_token(OPAL_RTC_READ) || + opal_check_token(OPAL_READ_TPO)) + pdev = platform_device_register_simple("opal-rtc", -1, + NULL, 0); else - mdelay(10); + return -ENODEV; } - if (rc != OPAL_SUCCESS) - return; - y_m_d = be32_to_cpu(__y_m_d); - h_m_s_ms = be64_to_cpu(__h_m_s_ms); - opal_to_tm(y_m_d, h_m_s_ms, tm); -} - -int opal_set_rtc_time(struct rtc_time *tm) -{ - long rc = OPAL_BUSY; - u32 y_m_d = 0; - u64 h_m_s_ms = 0; - - y_m_d |= ((u32)bin2bcd((tm->tm_year + 1900) / 100)) << 24; - y_m_d |= ((u32)bin2bcd((tm->tm_year + 1900) % 100)) << 16; - y_m_d |= ((u32)bin2bcd((tm->tm_mon + 1))) << 8; - y_m_d |= ((u32)bin2bcd(tm->tm_mday)); - - h_m_s_ms |= ((u64)bin2bcd(tm->tm_hour)) << 56; - h_m_s_ms |= ((u64)bin2bcd(tm->tm_min)) << 48; - h_m_s_ms |= ((u64)bin2bcd(tm->tm_sec)) << 40; - while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { - rc = opal_rtc_write(y_m_d, h_m_s_ms); - if (rc == OPAL_BUSY_EVENT) - opal_poll_events(NULL); - else - mdelay(10); - } - return rc == OPAL_SUCCESS ? 0 : -EIO; + return PTR_ERR_OR_ZERO(pdev); } +machine_subsys_initcall(powernv, opal_time_init); diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S index 59978af9babe..0a299be588af 100644 --- a/arch/powerpc/platforms/powernv/opal-wrappers.S +++ b/arch/powerpc/platforms/powernv/opal-wrappers.S @@ -250,5 +250,7 @@ OPAL_CALL(opal_handle_hmi, OPAL_HANDLE_HMI); OPAL_CALL(opal_register_dump_region, OPAL_REGISTER_DUMP_REGION); OPAL_CALL(opal_unregister_dump_region, OPAL_UNREGISTER_DUMP_REGION); OPAL_CALL(opal_pci_set_phb_cxl_mode, OPAL_PCI_SET_PHB_CXL_MODE); +OPAL_CALL(opal_tpo_write, OPAL_WRITE_TPO); +OPAL_CALL(opal_tpo_read, OPAL_READ_TPO); OPAL_CALL(opal_ipmi_send, OPAL_IPMI_SEND); OPAL_CALL(opal_ipmi_recv, OPAL_IPMI_RECV); diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c index 0297702e8ae9..a1c37f9d60d2 100644 --- a/arch/powerpc/platforms/powernv/opal.c +++ b/arch/powerpc/platforms/powernv/opal.c @@ -819,3 +819,9 @@ void opal_free_sg_list(struct opal_sg_list *sg) sg = NULL; } } + +EXPORT_SYMBOL_GPL(opal_poll_events); +EXPORT_SYMBOL_GPL(opal_rtc_read); +EXPORT_SYMBOL_GPL(opal_rtc_write); +EXPORT_SYMBOL_GPL(opal_tpo_read); +EXPORT_SYMBOL_GPL(opal_tpo_write); diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c index 941831d67cb2..30b1c3e298a6 100644 --- a/arch/powerpc/platforms/powernv/setup.c +++ b/arch/powerpc/platforms/powernv/setup.c @@ -265,8 +265,6 @@ static unsigned long pnv_memory_block_size(void) static void __init pnv_setup_machdep_opal(void) { ppc_md.get_boot_time = opal_get_boot_time; - ppc_md.get_rtc_time = opal_get_rtc_time; - ppc_md.set_rtc_time = opal_set_rtc_time; ppc_md.restart = pnv_restart; pm_power_off = pnv_power_off; ppc_md.halt = pnv_halt; diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 6dd12ddbabc6..c8f0ec7464ce 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -979,6 +979,17 @@ config RTC_DRV_NUC900 If you say yes here you get support for the RTC subsystem of the NUC910/NUC920 used in embedded systems. +config RTC_DRV_OPAL + tristate "IBM OPAL RTC driver" + depends on PPC_POWERNV + default y + help + If you say yes here you get support for the PowerNV platform RTC + driver based on OPAL interfaces. + + This driver can also be built as a module. If so, the module + will be called rtc-opal. + comment "on-CPU RTC drivers" config RTC_DRV_DAVINCI diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index b188323c096a..c8ef3e1e6ccd 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -92,6 +92,7 @@ obj-$(CONFIG_RTC_DRV_MSM6242) += rtc-msm6242.o obj-$(CONFIG_RTC_DRV_MPC5121) += rtc-mpc5121.o obj-$(CONFIG_RTC_DRV_MV) += rtc-mv.o obj-$(CONFIG_RTC_DRV_NUC900) += rtc-nuc900.o +obj-$(CONFIG_RTC_DRV_OPAL) += rtc-opal.o obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o obj-$(CONFIG_RTC_DRV_PALMAS) += rtc-palmas.o obj-$(CONFIG_RTC_DRV_PCAP) += rtc-pcap.o diff --git a/drivers/rtc/rtc-opal.c b/drivers/rtc/rtc-opal.c new file mode 100644 index 000000000000..95f652165fe9 --- /dev/null +++ b/drivers/rtc/rtc-opal.c @@ -0,0 +1,261 @@ +/* + * IBM OPAL RTC driver + * Copyright (C) 2014 IBM + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. + */ + +#define DRVNAME "rtc-opal" +#define pr_fmt(fmt) DRVNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void opal_to_tm(u32 y_m_d, u64 h_m_s_ms, struct rtc_time *tm) +{ + tm->tm_year = ((bcd2bin(y_m_d >> 24) * 100) + + bcd2bin((y_m_d >> 16) & 0xff)) - 1900; + tm->tm_mon = bcd2bin((y_m_d >> 8) & 0xff) - 1; + tm->tm_mday = bcd2bin(y_m_d & 0xff); + tm->tm_hour = bcd2bin((h_m_s_ms >> 56) & 0xff); + tm->tm_min = bcd2bin((h_m_s_ms >> 48) & 0xff); + tm->tm_sec = bcd2bin((h_m_s_ms >> 40) & 0xff); + + GregorianDay(tm); +} + +static void tm_to_opal(struct rtc_time *tm, u32 *y_m_d, u64 *h_m_s_ms) +{ + *y_m_d |= ((u32)bin2bcd((tm->tm_year + 1900) / 100)) << 24; + *y_m_d |= ((u32)bin2bcd((tm->tm_year + 1900) % 100)) << 16; + *y_m_d |= ((u32)bin2bcd((tm->tm_mon + 1))) << 8; + *y_m_d |= ((u32)bin2bcd(tm->tm_mday)); + + *h_m_s_ms |= ((u64)bin2bcd(tm->tm_hour)) << 56; + *h_m_s_ms |= ((u64)bin2bcd(tm->tm_min)) << 48; + *h_m_s_ms |= ((u64)bin2bcd(tm->tm_sec)) << 40; +} + +static int opal_get_rtc_time(struct device *dev, struct rtc_time *tm) +{ + long rc = OPAL_BUSY; + u32 y_m_d; + u64 h_m_s_ms; + __be32 __y_m_d; + __be64 __h_m_s_ms; + + while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { + rc = opal_rtc_read(&__y_m_d, &__h_m_s_ms); + if (rc == OPAL_BUSY_EVENT) + opal_poll_events(NULL); + else + msleep(10); + } + + if (rc != OPAL_SUCCESS) + return -EIO; + + y_m_d = be32_to_cpu(__y_m_d); + h_m_s_ms = be64_to_cpu(__h_m_s_ms); + opal_to_tm(y_m_d, h_m_s_ms, tm); + + return 0; +} + +static int opal_set_rtc_time(struct device *dev, struct rtc_time *tm) +{ + long rc = OPAL_BUSY; + u32 y_m_d = 0; + u64 h_m_s_ms = 0; + + tm_to_opal(tm, &y_m_d, &h_m_s_ms); + while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { + rc = opal_rtc_write(y_m_d, h_m_s_ms); + if (rc == OPAL_BUSY_EVENT) + opal_poll_events(NULL); + else + msleep(10); + } + + return rc == OPAL_SUCCESS ? 0 : -EIO; +} + +/* + * TPO Timed Power-On + * + * TPO get/set OPAL calls care about the hour and min and to make it consistent + * with the rtc utility time conversion functions, we use the 'u64' to store + * its value and perform bit shift by 32 before use.. + */ +static int opal_get_tpo_time(struct device *dev, struct rtc_wkalrm *alarm) +{ + __be32 __y_m_d, __h_m; + struct opal_msg msg; + int rc, token; + u64 h_m_s_ms; + u32 y_m_d; + + token = opal_async_get_token_interruptible(); + if (token < 0) { + if (token != -ERESTARTSYS) + pr_err("Failed to get the async token\n"); + + return token; + } + + rc = opal_tpo_read(token, &__y_m_d, &__h_m); + if (rc != OPAL_ASYNC_COMPLETION) { + rc = -EIO; + goto exit; + } + + rc = opal_async_wait_response(token, &msg); + if (rc) { + rc = -EIO; + goto exit; + } + + rc = be64_to_cpu(msg.params[1]); + if (rc != OPAL_SUCCESS) { + rc = -EIO; + goto exit; + } + + y_m_d = be32_to_cpu(__y_m_d); + h_m_s_ms = ((u64)be32_to_cpu(__h_m) << 32); + opal_to_tm(y_m_d, h_m_s_ms, &alarm->time); + +exit: + opal_async_release_token(token); + return rc; +} + +/* Set Timed Power-On */ +static int opal_set_tpo_time(struct device *dev, struct rtc_wkalrm *alarm) +{ + u64 h_m_s_ms = 0, token; + struct opal_msg msg; + u32 y_m_d = 0; + int rc; + + tm_to_opal(&alarm->time, &y_m_d, &h_m_s_ms); + + token = opal_async_get_token_interruptible(); + if (token < 0) { + if (token != -ERESTARTSYS) + pr_err("Failed to get the async token\n"); + + return token; + } + + /* TPO, we care about hour and minute */ + rc = opal_tpo_write(token, y_m_d, + (u32)((h_m_s_ms >> 32) & 0xffff0000)); + if (rc != OPAL_ASYNC_COMPLETION) { + rc = -EIO; + goto exit; + } + + rc = opal_async_wait_response(token, &msg); + if (rc) { + rc = -EIO; + goto exit; + } + + rc = be64_to_cpu(msg.params[1]); + if (rc != OPAL_SUCCESS) + rc = -EIO; + +exit: + opal_async_release_token(token); + return rc; +} + +static const struct rtc_class_ops opal_rtc_ops = { + .read_time = opal_get_rtc_time, + .set_time = opal_set_rtc_time, + .read_alarm = opal_get_tpo_time, + .set_alarm = opal_set_tpo_time, +}; + +static int opal_rtc_probe(struct platform_device *pdev) +{ + struct rtc_device *rtc; + + if (pdev->dev.of_node && of_get_property(pdev->dev.of_node, "has-tpo", + NULL)) + device_set_wakeup_capable(&pdev->dev, true); + + rtc = devm_rtc_device_register(&pdev->dev, DRVNAME, &opal_rtc_ops, + THIS_MODULE); + if (IS_ERR(rtc)) + return PTR_ERR(rtc); + + rtc->uie_unsupported = 1; + + return 0; +} + +static const struct of_device_id opal_rtc_match[] = { + { + .compatible = "ibm,opal-rtc", + }, + { } +}; +MODULE_DEVICE_TABLE(of, opal_rtc_match); + +static const struct platform_device_id opal_rtc_driver_ids[] = { + { + .name = "opal-rtc", + }, + { } +}; +MODULE_DEVICE_TABLE(platform, opal_rtc_driver_ids); + +static struct platform_driver opal_rtc_driver = { + .probe = opal_rtc_probe, + .id_table = opal_rtc_driver_ids, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + .of_match_table = opal_rtc_match, + }, +}; + +static int __init opal_rtc_init(void) +{ + if (!firmware_has_feature(FW_FEATURE_OPAL)) + return -ENODEV; + + return platform_driver_register(&opal_rtc_driver); +} + +static void __exit opal_rtc_exit(void) +{ + platform_driver_unregister(&opal_rtc_driver); +} + +MODULE_AUTHOR("Neelesh Gupta "); +MODULE_DESCRIPTION("IBM OPAL RTC driver"); +MODULE_LICENSE("GPL"); + +module_init(opal_rtc_init); +module_exit(opal_rtc_exit); -- cgit v1.2.3-59-g8ed1b From 0b04ddf8638ca5652b1f7ab7794beb363942407d Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Fri, 7 Nov 2014 12:15:47 +0800 Subject: dmaengine: sun6i: Add support for Allwinner A23 (sun8i) variant The A23 SoC has the same dma engine as the A31 (sun6i), with a reduced amount of endpoints and physical channels. Add the proper config data and compatible string to support it. A slight difference in sun8i is an undocumented register needs to be toggled for dma to function. Signed-off-by: Chen-Yu Tsai Acked-by: Maxime Ripard Signed-off-by: Vinod Koul --- .../devicetree/bindings/dma/sun6i-dma.txt | 2 +- drivers/dma/Kconfig | 4 ++-- drivers/dma/sun6i-dma.c | 27 ++++++++++++++++++++++ 3 files changed, 30 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/dma/sun6i-dma.txt b/Documentation/devicetree/bindings/dma/sun6i-dma.txt index 3e145c1675b1..9cdcba24d7c3 100644 --- a/Documentation/devicetree/bindings/dma/sun6i-dma.txt +++ b/Documentation/devicetree/bindings/dma/sun6i-dma.txt @@ -4,7 +4,7 @@ This driver follows the generic DMA bindings defined in dma.txt. Required properties: -- compatible: Must be "allwinner,sun6i-a31-dma" +- compatible: Must be "allwinner,sun6i-a31-dma" or "allwinner,sun8i-a23-dma" - reg: Should contain the registers base address and length - interrupts: Should contain a reference to the interrupt used by this device - clocks: Should contain a reference to the parent AHB clock diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 607271a999a9..aef8b9dd4db6 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -402,12 +402,12 @@ config XILINX_VDMA config DMA_SUN6I tristate "Allwinner A31 SoCs DMA support" - depends on MACH_SUN6I || COMPILE_TEST + depends on MACH_SUN6I || MACH_SUN8I || COMPILE_TEST depends on RESET_CONTROLLER select DMA_ENGINE select DMA_VIRTUAL_CHANNELS help - Support for the DMA engine for Allwinner A31 SoCs. + Support for the DMA engine first found in Allwinner A31 SoCs. config NBPFAXI_DMA tristate "Renesas Type-AXI NBPF DMA support" diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c index 531abbf68a9d..f9f8f4d9915f 100644 --- a/drivers/dma/sun6i-dma.c +++ b/drivers/dma/sun6i-dma.c @@ -42,6 +42,12 @@ #define DMA_STAT 0x30 +/* + * sun8i specific registers + */ +#define SUN8I_DMA_GATE 0x20 +#define SUN8I_DMA_GATE_ENABLE 0x4 + /* * Channels specific registers */ @@ -878,8 +884,20 @@ static struct sun6i_dma_config sun6i_a31_dma_cfg = { .nr_max_vchans = 53, }; +/* + * The A23 only has 8 physical channels, a maximum DRQ port id of 24, + * and a total of 37 usable source and destination endpoints. + */ + +static struct sun6i_dma_config sun8i_a23_dma_cfg = { + .nr_max_channels = 8, + .nr_max_requests = 24, + .nr_max_vchans = 37, +}; + static struct of_device_id sun6i_dma_match[] = { { .compatible = "allwinner,sun6i-a31-dma", .data = &sun6i_a31_dma_cfg }, + { .compatible = "allwinner,sun8i-a23-dma", .data = &sun8i_a23_dma_cfg }, { /* sentinel */ } }; @@ -1007,6 +1025,15 @@ static int sun6i_dma_probe(struct platform_device *pdev) goto err_dma_unregister; } + /* + * sun8i variant requires us to toggle a dma gating register, + * as seen in Allwinner's SDK. This register is not documented + * in the A23 user manual. + */ + if (of_device_is_compatible(pdev->dev.of_node, + "allwinner,sun8i-a23-dma")) + writel(SUN8I_DMA_GATE_ENABLE, sdc->base + SUN8I_DMA_GATE); + return 0; err_dma_unregister: -- cgit v1.2.3-59-g8ed1b From ce9406380dea1e462ab609700c9daeb6c8b23766 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Mon, 29 Sep 2014 10:03:09 +0530 Subject: dt/bindings: dmaengine: qcom_bam_dma: Add compatible string for BAM v1.3.0 Add compatible string for BAM v1.3.0 in the DT bindings documentation. Mentioned a few more SoCs which have BAM v1.4.0 in them. Reviewed-by: Kumar Gala Reviewed-by: Andy Gross Signed-off-by: Archit Taneja Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/dma/qcom_bam_dma.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/dma/qcom_bam_dma.txt b/Documentation/devicetree/bindings/dma/qcom_bam_dma.txt index d75a9d767022..f8c3311b7153 100644 --- a/Documentation/devicetree/bindings/dma/qcom_bam_dma.txt +++ b/Documentation/devicetree/bindings/dma/qcom_bam_dma.txt @@ -1,7 +1,9 @@ QCOM BAM DMA controller Required properties: -- compatible: must contain "qcom,bam-v1.4.0" for MSM8974 +- compatible: must be one of the following: + * "qcom,bam-v1.4.0" for MSM8974, APQ8074 and APQ8084 + * "qcom,bam-v1.3.0" for APQ8064, IPQ8064 and MSM8960 - reg: Address range for DMA registers - interrupts: Should contain the one interrupt shared by all channels - #dma-cells: must be <1>, the cell in the dmas property of the client device -- cgit v1.2.3-59-g8ed1b From 29aebfde8802b64a5b505a1d8a6842c188abfdbc Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Fri, 24 Oct 2014 12:37:41 -0700 Subject: dmaengine: imx-sdma: Add a new DMATYPE for SAI This patch simply adds a new DMATYPE for SAI which's included in i.MX6 Solo X. Signed-off-by: Nicolin Chen Acked-by: Shawn Guo Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt | 1 + drivers/dma/imx-sdma.c | 1 + include/linux/platform_data/dma-imx.h | 1 + 3 files changed, 3 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt b/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt index 4659fd952301..dc8d3aac1aa9 100644 --- a/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt +++ b/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt @@ -48,6 +48,7 @@ The full ID of peripheral types can be found below. 21 ESAI 22 SSI Dual FIFO (needs firmware ver >= 2) 23 Shared ASRC + 24 SAI The third cell specifies the transfer priority as below. diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index 99d8833edbd6..5b38f2bbd42a 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -729,6 +729,7 @@ static void sdma_get_pc(struct sdma_channel *sdmac, case IMX_DMATYPE_CSPI: case IMX_DMATYPE_EXT: case IMX_DMATYPE_SSI: + case IMX_DMATYPE_SAI: per_2_emi = sdma->script_addrs->app_2_mcu_addr; emi_2_per = sdma->script_addrs->mcu_2_app_addr; break; diff --git a/include/linux/platform_data/dma-imx.h b/include/linux/platform_data/dma-imx.h index 6a1357d31871..7d964e787299 100644 --- a/include/linux/platform_data/dma-imx.h +++ b/include/linux/platform_data/dma-imx.h @@ -41,6 +41,7 @@ enum sdma_peripheral_type { IMX_DMATYPE_ESAI, /* ESAI */ IMX_DMATYPE_SSI_DUAL, /* SSI Dual FIFO */ IMX_DMATYPE_ASRC_SP, /* Shared ASRC */ + IMX_DMATYPE_SAI, /* SAI */ }; enum imx_dma_prio { -- cgit v1.2.3-59-g8ed1b From 466b3cf17ea6bee26cf7a404f51a44f2e884b31e Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Thu, 13 Nov 2014 11:52:44 +0100 Subject: ARM: dts: at_xdmac: fix bad value of dma-cells in documentation The dma-cells value in the example was 2 instead of 1. Signed-off-by: Ludovic Desroches Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/dma/atmel-xdma.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/dma/atmel-xdma.txt b/Documentation/devicetree/bindings/dma/atmel-xdma.txt index e75c128c53fa..0eb2b3207e08 100644 --- a/Documentation/devicetree/bindings/dma/atmel-xdma.txt +++ b/Documentation/devicetree/bindings/dma/atmel-xdma.txt @@ -22,7 +22,7 @@ dma1: dma-controller@f0004000 { compatible = "atmel,sama5d4-dma"; reg = <0xf0004000 0x200>; interrupts = <50 4 0>; - #dma-cells = <2>; + #dma-cells = <1>; }; -- cgit v1.2.3-59-g8ed1b From 3ff9027ca6b00e194d2eae353febf7233cfcc1ea Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Fri, 14 Nov 2014 17:37:39 +0200 Subject: can: c_can: Add syscon/regmap RAMINIT mechanism Some TI SoCs like DRA7 have a RAMINIT register specification different from the other AMxx SoCs and as expected by the existing driver. To add more insanity, this register is shared with other IPs like DSS, PCIe and PWM. Provides a more generic mechanism to specify the RAMINIT register location and START/DONE bit position and use the syscon/regmap framework to access the register. Signed-off-by: Roger Quadros Signed-off-by: Marc Kleine-Budde --- .../devicetree/bindings/net/can/c_can.txt | 3 + drivers/net/can/c_can/c_can.h | 10 +- drivers/net/can/c_can/c_can_platform.c | 109 +++++++++++++-------- 3 files changed, 81 insertions(+), 41 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/can/c_can.txt b/Documentation/devicetree/bindings/net/can/c_can.txt index 8f1ae81228e3..a3ca3ee53546 100644 --- a/Documentation/devicetree/bindings/net/can/c_can.txt +++ b/Documentation/devicetree/bindings/net/can/c_can.txt @@ -12,6 +12,9 @@ Required properties: Optional properties: - ti,hwmods : Must be "d_can" or "c_can", n being the instance number +- syscon-raminit : Handle to system control region that contains the + RAMINIT register, register offset to the RAMINIT + register and the CAN instance number (0 offset). Note: "ti,hwmods" field is used to fetch the base address and irq resources from TI, omap hwmod data base during device registration. diff --git a/drivers/net/can/c_can/c_can.h b/drivers/net/can/c_can/c_can.h index 3f111f4f0f6e..28a73d14ea8d 100644 --- a/drivers/net/can/c_can/c_can.h +++ b/drivers/net/can/c_can/c_can.h @@ -183,6 +183,13 @@ struct c_can_driver_data { bool raminit_pulse; /* If set, sets and clears START bit (pulse) */ }; +/* Out of band RAMINIT register access via syscon regmap */ +struct c_can_raminit { + struct regmap *syscon; /* for raminit ctrl. reg. access */ + unsigned int reg; /* register index within syscon */ + struct raminit_bits bits; +}; + /* c_can private data structure */ struct c_can_priv { struct can_priv can; /* must be the first member */ @@ -200,8 +207,7 @@ struct c_can_priv { const u16 *regs; void *priv; /* for board-specific data */ enum c_can_dev_id type; - u32 __iomem *raminit_ctrlreg; - int instance; + struct c_can_raminit raminit_sys; /* RAMINIT via syscon regmap */ void (*raminit) (const struct c_can_priv *priv, bool enable); u32 comm_rcv_high; u32 rxmasked; diff --git a/drivers/net/can/c_can/c_can_platform.c b/drivers/net/can/c_can/c_can_platform.c index 44c293926f78..1fbfa1d59c29 100644 --- a/drivers/net/can/c_can/c_can_platform.c +++ b/drivers/net/can/c_can/c_can_platform.c @@ -32,14 +32,13 @@ #include #include #include +#include +#include #include #include "c_can.h" -#define CAN_RAMINIT_START_MASK(i) (0x001 << (i)) -#define CAN_RAMINIT_DONE_MASK(i) (0x100 << (i)) -#define CAN_RAMINIT_ALL_MASK(i) (0x101 << (i)) #define DCAN_RAM_INIT_BIT (1 << 3) static DEFINE_SPINLOCK(raminit_lock); /* @@ -72,48 +71,57 @@ static void c_can_plat_write_reg_aligned_to_32bit(const struct c_can_priv *priv, writew(val, priv->base + 2 * priv->regs[index]); } -static void c_can_hw_raminit_wait_ti(const struct c_can_priv *priv, u32 mask, - u32 val) +static void c_can_hw_raminit_wait_syscon(const struct c_can_priv *priv, + u32 mask, u32 val) { + const struct c_can_raminit *raminit = &priv->raminit_sys; int timeout = 0; + u32 ctrl = 0; /* We look only at the bits of our instance. */ val &= mask; - while ((readl(priv->raminit_ctrlreg) & mask) != val) { + do { udelay(1); timeout++; + regmap_read(raminit->syscon, raminit->reg, &ctrl); if (timeout == 1000) { dev_err(&priv->dev->dev, "%s: time out\n", __func__); break; } - } + } while ((ctrl & mask) != val); } -static void c_can_hw_raminit_ti(const struct c_can_priv *priv, bool enable) +static void c_can_hw_raminit_syscon(const struct c_can_priv *priv, bool enable) { - u32 mask = CAN_RAMINIT_ALL_MASK(priv->instance); - u32 ctrl; + const struct c_can_raminit *raminit = &priv->raminit_sys; + u32 ctrl = 0; + u32 mask; spin_lock(&raminit_lock); - ctrl = readl(priv->raminit_ctrlreg); + mask = 1 << raminit->bits.start | 1 << raminit->bits.done; + regmap_read(raminit->syscon, raminit->reg, &ctrl); + /* We clear the done and start bit first. The start bit is * looking at the 0 -> transition, but is not self clearing; * And we clear the init done bit as well. + * NOTE: DONE must be written with 1 to clear it. */ - ctrl &= ~CAN_RAMINIT_START_MASK(priv->instance); - ctrl |= CAN_RAMINIT_DONE_MASK(priv->instance); - writel(ctrl, priv->raminit_ctrlreg); - ctrl &= ~CAN_RAMINIT_DONE_MASK(priv->instance); - c_can_hw_raminit_wait_ti(priv, mask, ctrl); + ctrl &= ~(1 << raminit->bits.start); + ctrl |= 1 << raminit->bits.done; + regmap_write(raminit->syscon, raminit->reg, ctrl); + + ctrl &= ~(1 << raminit->bits.done); + c_can_hw_raminit_wait_syscon(priv, mask, ctrl); if (enable) { /* Set start bit and wait for the done bit. */ - ctrl |= CAN_RAMINIT_START_MASK(priv->instance); - writel(ctrl, priv->raminit_ctrlreg); - ctrl |= CAN_RAMINIT_DONE_MASK(priv->instance); - c_can_hw_raminit_wait_ti(priv, mask, ctrl); + ctrl |= 1 << raminit->bits.start; + regmap_write(raminit->syscon, raminit->reg, ctrl); + + ctrl |= 1 << raminit->bits.done; + c_can_hw_raminit_wait_syscon(priv, mask, ctrl); } spin_unlock(&raminit_lock); } @@ -207,10 +215,11 @@ static int c_can_plat_probe(struct platform_device *pdev) struct net_device *dev; struct c_can_priv *priv; const struct of_device_id *match; - struct resource *mem, *res; + struct resource *mem; int irq; struct clk *clk; const struct c_can_driver_data *drvdata; + struct device_node *np = pdev->dev.of_node; match = of_match_device(c_can_of_table, &pdev->dev); if (match) { @@ -278,27 +287,49 @@ static int c_can_plat_probe(struct platform_device *pdev) priv->read_reg32 = d_can_plat_read_reg32; priv->write_reg32 = d_can_plat_write_reg32; - if (pdev->dev.of_node) - priv->instance = of_alias_get_id(pdev->dev.of_node, "d_can"); - else - priv->instance = pdev->id; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - /* Not all D_CAN modules have a separate register for the D_CAN - * RAM initialization. Use default RAM init bit in D_CAN module - * if not specified in DT. + /* Check if we need custom RAMINIT via syscon. Mostly for TI + * platforms. Only supported with DT boot. */ - if (!res) { + if (np && of_property_read_bool(np, "syscon-raminit")) { + u32 id; + struct c_can_raminit *raminit = &priv->raminit_sys; + + ret = -EINVAL; + raminit->syscon = syscon_regmap_lookup_by_phandle(np, + "syscon-raminit"); + if (IS_ERR(raminit->syscon)) { + /* can fail with -EPROBE_DEFER */ + ret = PTR_ERR(raminit->syscon); + free_c_can_dev(dev); + return ret; + } + + if (of_property_read_u32_index(np, "syscon-raminit", 1, + &raminit->reg)) { + dev_err(&pdev->dev, + "couldn't get the RAMINIT reg. offset!\n"); + goto exit_free_device; + } + + if (of_property_read_u32_index(np, "syscon-raminit", 2, + &id)) { + dev_err(&pdev->dev, + "couldn't get the CAN instance ID\n"); + goto exit_free_device; + } + + if (id >= drvdata->raminit_num) { + dev_err(&pdev->dev, + "Invalid CAN instance ID\n"); + goto exit_free_device; + } + + raminit->bits = drvdata->raminit_bits[id]; + + priv->raminit = c_can_hw_raminit_syscon; + } else { priv->raminit = c_can_hw_raminit; - break; } - - priv->raminit_ctrlreg = devm_ioremap(&pdev->dev, res->start, - resource_size(res)); - if (!priv->raminit_ctrlreg || priv->instance < 0) - dev_info(&pdev->dev, "control memory is not used for raminit\n"); - else - priv->raminit = c_can_hw_raminit_ti; break; default: ret = -EINVAL; -- cgit v1.2.3-59-g8ed1b From 0f4da3a8da5fe3a079b1adf613d121a0fafd63f1 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Fri, 7 Nov 2014 16:49:21 +0200 Subject: can: c_can: Add support for TI DRA7 DCAN DRA7 SoC has 2 CAN IPs. Provide compatible IDs and RAMINIT register data for both. Signed-off-by: Roger Quadros Signed-off-by: Marc Kleine-Budde --- Documentation/devicetree/bindings/net/can/c_can.txt | 1 + drivers/net/can/c_can/c_can_platform.c | 13 +++++++++++++ 2 files changed, 14 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/can/c_can.txt b/Documentation/devicetree/bindings/net/can/c_can.txt index a3ca3ee53546..f682fdb6d921 100644 --- a/Documentation/devicetree/bindings/net/can/c_can.txt +++ b/Documentation/devicetree/bindings/net/can/c_can.txt @@ -4,6 +4,7 @@ Bosch C_CAN/D_CAN controller Device Tree Bindings Required properties: - compatible : Should be "bosch,c_can" for C_CAN controllers and "bosch,d_can" for D_CAN controllers. + Can be "ti,dra7-d_can". - reg : physical base address and size of the C_CAN/D_CAN registers map - interrupts : property with a value describing the interrupt diff --git a/drivers/net/can/c_can/c_can_platform.c b/drivers/net/can/c_can/c_can_platform.c index 41fa460c3592..570da5f56aae 100644 --- a/drivers/net/can/c_can/c_can_platform.c +++ b/drivers/net/can/c_can/c_can_platform.c @@ -190,6 +190,18 @@ static const struct c_can_driver_data d_can_drvdata = { .id = BOSCH_D_CAN, }; +static const struct raminit_bits dra7_raminit_bits[] = { + [0] = { .start = 3, .done = 1, }, + [1] = { .start = 5, .done = 2, }, +}; + +static const struct c_can_driver_data dra7_dcan_drvdata = { + .id = BOSCH_D_CAN, + .raminit_num = ARRAY_SIZE(dra7_raminit_bits), + .raminit_bits = dra7_raminit_bits, + .raminit_pulse = true, +}; + static struct platform_device_id c_can_id_table[] = { { .name = KBUILD_MODNAME, @@ -210,6 +222,7 @@ MODULE_DEVICE_TABLE(platform, c_can_id_table); static const struct of_device_id c_can_of_table[] = { { .compatible = "bosch,c_can", .data = &c_can_drvdata }, { .compatible = "bosch,d_can", .data = &d_can_drvdata }, + { .compatible = "ti,dra7-d_can", .data = &dra7_dcan_drvdata }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, c_can_of_table); -- cgit v1.2.3-59-g8ed1b From c71d0b31bf71b84ad566292ea2412755da7934b2 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Fri, 7 Nov 2014 16:49:22 +0200 Subject: can: c_can: Add support for TI am3352 DCAN AM3352 SoC has 2 DCAN modules. Add compatible id and raminit driver data for am3352 DCAN. Signed-off-by: Roger Quadros Acked-by: Wolfram Sang Signed-off-by: Marc Kleine-Budde --- Documentation/devicetree/bindings/net/can/c_can.txt | 2 +- drivers/net/can/c_can/c_can_platform.c | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/can/c_can.txt b/Documentation/devicetree/bindings/net/can/c_can.txt index f682fdb6d921..6731730eec0d 100644 --- a/Documentation/devicetree/bindings/net/can/c_can.txt +++ b/Documentation/devicetree/bindings/net/can/c_can.txt @@ -4,7 +4,7 @@ Bosch C_CAN/D_CAN controller Device Tree Bindings Required properties: - compatible : Should be "bosch,c_can" for C_CAN controllers and "bosch,d_can" for D_CAN controllers. - Can be "ti,dra7-d_can". + Can be "ti,dra7-d_can" or "ti,am3352-d_can". - reg : physical base address and size of the C_CAN/D_CAN registers map - interrupts : property with a value describing the interrupt diff --git a/drivers/net/can/c_can/c_can_platform.c b/drivers/net/can/c_can/c_can_platform.c index 570da5f56aae..f4488e5d5d68 100644 --- a/drivers/net/can/c_can/c_can_platform.c +++ b/drivers/net/can/c_can/c_can_platform.c @@ -202,6 +202,17 @@ static const struct c_can_driver_data dra7_dcan_drvdata = { .raminit_pulse = true, }; +static const struct raminit_bits am3352_raminit_bits[] = { + [0] = { .start = 0, .done = 8, }, + [1] = { .start = 1, .done = 9, }, +}; + +static const struct c_can_driver_data am3352_dcan_drvdata = { + .id = BOSCH_D_CAN, + .raminit_num = ARRAY_SIZE(am3352_raminit_bits), + .raminit_bits = am3352_raminit_bits, +}; + static struct platform_device_id c_can_id_table[] = { { .name = KBUILD_MODNAME, @@ -223,6 +234,7 @@ static const struct of_device_id c_can_of_table[] = { { .compatible = "bosch,c_can", .data = &c_can_drvdata }, { .compatible = "bosch,d_can", .data = &d_can_drvdata }, { .compatible = "ti,dra7-d_can", .data = &dra7_dcan_drvdata }, + { .compatible = "ti,am3352-d_can", .data = &am3352_dcan_drvdata }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, c_can_of_table); -- cgit v1.2.3-59-g8ed1b From e5a06dc5ac1f686d11b11488a88a63ab12e079cb Mon Sep 17 00:00:00 2001 From: Bart Tanghe Date: Wed, 8 Oct 2014 12:14:32 +0200 Subject: pwm: Add BCM2835 PWM driver Add PWM driver for Broadcom BCM2835 processor (Raspberry Pi) Signed-off-by: Bart Tanghe Acked-by: Stephen Warren Signed-off-by: Thierry Reding --- .../devicetree/bindings/pwm/pwm-bcm2835.txt | 30 +++ drivers/pwm/Kconfig | 9 + drivers/pwm/Makefile | 1 + drivers/pwm/pwm-bcm2835.c | 205 +++++++++++++++++++++ 4 files changed, 245 insertions(+) create mode 100644 Documentation/devicetree/bindings/pwm/pwm-bcm2835.txt create mode 100644 drivers/pwm/pwm-bcm2835.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/pwm/pwm-bcm2835.txt b/Documentation/devicetree/bindings/pwm/pwm-bcm2835.txt new file mode 100644 index 000000000000..fb6fb31bc4c4 --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/pwm-bcm2835.txt @@ -0,0 +1,30 @@ +BCM2835 PWM controller (Raspberry Pi controller) + +Required properties: +- compatible: should be "brcm,bcm2835-pwm" +- reg: physical base address and length of the controller's registers +- clock: This clock defines the base clock frequency of the PWM hardware + system, the period and the duty_cycle of the PWM signal is a multiple of + the base period. +- #pwm-cells: Should be 2. See pwm.txt in this directory for a description of + the cells format. + +Examples: + +pwm@2020c000 { + compatible = "brcm,bcm2835-pwm"; + reg = <0x2020c000 0x28>; + clocks = <&clk_pwm>; + #pwm-cells = <2>; +}; + +clocks { + .... + clk_pwm: pwm { + compatible = "fixed-clock"; + reg = <3>; + #clock-cells = <0>; + clock-frequency = <9200000>; + }; + .... +}; diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index ef2dd2e4754b..ddabe3983549 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -71,6 +71,15 @@ config PWM_BCM_KONA To compile this driver as a module, choose M here: the module will be called pwm-bcm-kona. +config PWM_BCM2835 + tristate "BCM2835 PWM support" + depends on ARCH_BCM2835 + help + PWM framework driver for BCM2835 controller (Raspberry Pi) + + To compile this driver as a module, choose M here: the module + will be called pwm-bcm2835. + config PWM_BFIN tristate "Blackfin PWM support" depends on BFIN_GPTIMERS diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index c458606c3755..88be33bbfdf6 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_PWM_AB8500) += pwm-ab8500.o obj-$(CONFIG_PWM_ATMEL) += pwm-atmel.o obj-$(CONFIG_PWM_ATMEL_TCB) += pwm-atmel-tcb.o obj-$(CONFIG_PWM_BCM_KONA) += pwm-bcm-kona.o +obj-$(CONFIG_PWM_BCM2835) += pwm-bcm2835.o obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o obj-$(CONFIG_PWM_CLPS711X) += pwm-clps711x.o obj-$(CONFIG_PWM_EP93XX) += pwm-ep93xx.o diff --git a/drivers/pwm/pwm-bcm2835.c b/drivers/pwm/pwm-bcm2835.c new file mode 100644 index 000000000000..b4c7f956b6fa --- /dev/null +++ b/drivers/pwm/pwm-bcm2835.c @@ -0,0 +1,205 @@ +/* + * Copyright 2014 Bart Tanghe + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define PWM_CONTROL 0x000 +#define PWM_CONTROL_SHIFT(x) ((x) * 8) +#define PWM_CONTROL_MASK 0xff +#define PWM_MODE 0x80 /* set timer in PWM mode */ +#define PWM_ENABLE (1 << 0) +#define PWM_POLARITY (1 << 4) + +#define PERIOD(x) (((x) * 0x10) + 0x10) +#define DUTY(x) (((x) * 0x10) + 0x14) + +#define MIN_PERIOD 108 /* 9.2 MHz max. PWM clock */ + +struct bcm2835_pwm { + struct pwm_chip chip; + struct device *dev; + unsigned long scaler; + void __iomem *base; + struct clk *clk; +}; + +static inline struct bcm2835_pwm *to_bcm2835_pwm(struct pwm_chip *chip) +{ + return container_of(chip, struct bcm2835_pwm, chip); +} + +static int bcm2835_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct bcm2835_pwm *pc = to_bcm2835_pwm(chip); + u32 value; + + value = readl(pc->base + PWM_CONTROL); + value &= ~(PWM_CONTROL_MASK << PWM_CONTROL_SHIFT(pwm->hwpwm)); + value |= (PWM_MODE << PWM_CONTROL_SHIFT(pwm->hwpwm)); + writel(value, pc->base + PWM_CONTROL); + + return 0; +} + +static void bcm2835_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct bcm2835_pwm *pc = to_bcm2835_pwm(chip); + u32 value; + + value = readl(pc->base + PWM_CONTROL); + value &= ~(PWM_CONTROL_MASK << PWM_CONTROL_SHIFT(pwm->hwpwm)); + writel(value, pc->base + PWM_CONTROL); +} + +static int bcm2835_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, + int duty_ns, int period_ns) +{ + struct bcm2835_pwm *pc = to_bcm2835_pwm(chip); + + if (period_ns <= MIN_PERIOD) { + dev_err(pc->dev, "period %d not supported, minimum %d\n", + period_ns, MIN_PERIOD); + return -EINVAL; + } + + writel(duty_ns / pc->scaler, pc->base + DUTY(pwm->hwpwm)); + writel(period_ns / pc->scaler, pc->base + PERIOD(pwm->hwpwm)); + + return 0; +} + +static int bcm2835_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct bcm2835_pwm *pc = to_bcm2835_pwm(chip); + u32 value; + + value = readl(pc->base + PWM_CONTROL); + value |= PWM_ENABLE << PWM_CONTROL_SHIFT(pwm->hwpwm); + writel(value, pc->base + PWM_CONTROL); + + return 0; +} + +static void bcm2835_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct bcm2835_pwm *pc = to_bcm2835_pwm(chip); + u32 value; + + value = readl(pc->base + PWM_CONTROL); + value &= ~(PWM_ENABLE << PWM_CONTROL_SHIFT(pwm->hwpwm)); + writel(value, pc->base + PWM_CONTROL); +} + +static int bcm2835_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm, + enum pwm_polarity polarity) +{ + struct bcm2835_pwm *pc = to_bcm2835_pwm(chip); + u32 value; + + value = readl(pc->base + PWM_CONTROL); + + if (polarity == PWM_POLARITY_NORMAL) + value &= ~(PWM_POLARITY << PWM_CONTROL_SHIFT(pwm->hwpwm)); + else + value |= PWM_POLARITY << PWM_CONTROL_SHIFT(pwm->hwpwm); + + writel(value, pc->base + PWM_CONTROL); + + return 0; +} + +static const struct pwm_ops bcm2835_pwm_ops = { + .request = bcm2835_pwm_request, + .free = bcm2835_pwm_free, + .config = bcm2835_pwm_config, + .enable = bcm2835_pwm_enable, + .disable = bcm2835_pwm_disable, + .set_polarity = bcm2835_set_polarity, + .owner = THIS_MODULE, +}; + +static int bcm2835_pwm_probe(struct platform_device *pdev) +{ + struct bcm2835_pwm *pc; + struct resource *res; + int ret; + + pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL); + if (!pc) + return -ENOMEM; + + pc->dev = &pdev->dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + pc->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(pc->base)) + return PTR_ERR(pc->base); + + pc->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(pc->clk)) { + dev_err(&pdev->dev, "clock not found: %ld\n", PTR_ERR(pc->clk)); + return PTR_ERR(pc->clk); + } + + ret = clk_prepare_enable(pc->clk); + if (ret) + return ret; + + pc->scaler = NSEC_PER_SEC / clk_get_rate(pc->clk); + + pc->chip.dev = &pdev->dev; + pc->chip.ops = &bcm2835_pwm_ops; + pc->chip.npwm = 2; + + platform_set_drvdata(pdev, pc); + + ret = pwmchip_add(&pc->chip); + if (ret < 0) + goto add_fail; + + return 0; + +add_fail: + clk_disable_unprepare(pc->clk); + return ret; +} + +static int bcm2835_pwm_remove(struct platform_device *pdev) +{ + struct bcm2835_pwm *pc = platform_get_drvdata(pdev); + + clk_disable_unprepare(pc->clk); + + return pwmchip_remove(&pc->chip); +} + +static const struct of_device_id bcm2835_pwm_of_match[] = { + { .compatible = "brcm,bcm2835-pwm", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, bcm2835_pwm_of_match); + +static struct platform_driver bcm2835_pwm_driver = { + .driver = { + .name = "bcm2835-pwm", + .of_match_table = bcm2835_pwm_of_match, + }, + .probe = bcm2835_pwm_probe, + .remove = bcm2835_pwm_remove, +}; +module_platform_driver(bcm2835_pwm_driver); + +MODULE_AUTHOR("Bart Tanghe Date: Tue, 7 Oct 2014 15:38:15 +0200 Subject: pwm: add DT bindings documentation for atmel-hlcdc-pwm driver The HLCDC IP available in some Atmel SoCs (i.e. at91sam9x5, at91sam9n12 or sama5d3 families for instance) provides a PWM device. The DT bindings used for this PWM device is following the default 3 cells bindings described in Documentation/devicetree/bindings/pwm/pwm.txt. Signed-off-by: Boris Brezillon Acked-by: Thierry Reding Acked-by: Nicolas Ferre Signed-off-by: Thierry Reding --- .../devicetree/bindings/pwm/atmel-hlcdc-pwm.txt | 29 ++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 Documentation/devicetree/bindings/pwm/atmel-hlcdc-pwm.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/pwm/atmel-hlcdc-pwm.txt b/Documentation/devicetree/bindings/pwm/atmel-hlcdc-pwm.txt new file mode 100644 index 000000000000..cfda0d57d302 --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/atmel-hlcdc-pwm.txt @@ -0,0 +1,29 @@ +Device-Tree bindings for Atmel's HLCDC (High-end LCD Controller) PWM driver + +The Atmel HLCDC PWM is subdevice of the HLCDC MFD device. +See ../mfd/atmel-hlcdc.txt for more details. + +Required properties: + - compatible: value should be one of the following: + "atmel,hlcdc-pwm" + - pinctr-names: the pin control state names. Should contain "default". + - pinctrl-0: should contain the pinctrl states described by pinctrl + default. + - #pwm-cells: should be set to 3. This PWM chip use the default 3 cells + bindings defined in pwm.txt in this directory. + +Example: + + hlcdc: hlcdc@f0030000 { + compatible = "atmel,sama5d3-hlcdc"; + reg = <0xf0030000 0x2000>; + clocks = <&lcdc_clk>, <&lcdck>, <&clk32k>; + clock-names = "periph_clk","sys_clk", "slow_clk"; + + hlcdc_pwm: hlcdc-pwm { + compatible = "atmel,hlcdc-pwm"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lcd_pwm>; + #pwm-cells = <3>; + }; + }; -- cgit v1.2.3-59-g8ed1b From 07a186893af5a274877d11ce9e5d81c142890cf6 Mon Sep 17 00:00:00 2001 From: Andrew Bresticker Date: Fri, 14 Nov 2014 10:48:31 -0800 Subject: spi: Add binding document for IMG SPFI controller The Synchronous Peripheral Flash Interface (SPFI) controller found on IMG SoCs supports single, dual, and (optionally) quad mode SPI transfers. Signed-off-by: Andrew Bresticker Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/spi-img-spfi.txt | 37 ++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 Documentation/devicetree/bindings/spi/spi-img-spfi.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/spi/spi-img-spfi.txt b/Documentation/devicetree/bindings/spi/spi-img-spfi.txt new file mode 100644 index 000000000000..c7dd50fb8eb2 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi-img-spfi.txt @@ -0,0 +1,37 @@ +IMG Synchronous Peripheral Flash Interface (SPFI) controller + +Required properties: +- compatible: Must be "img,spfi". +- reg: Must contain the base address and length of the SPFI registers. +- interrupts: Must contain the SPFI interrupt. +- clocks: Must contain an entry for each entry in clock-names. + See ../clock/clock-bindings.txt for details. +- clock-names: Must include the following entries: + - spfi: SPI operating clock + - sys: SPI system interface clock +- dmas: Must contain an entry for each entry in dma-names. + See ../dma/dma.txt for details. +- dma-names: Must include the following entries: + - rx + - tx +- #address-cells: Must be 1. +- #size-cells: Must be 0. + +Optional properties: +- img,supports-quad-mode: Should be set if the interface supports quad mode + SPI transfers. + +Example: + +spi@18100f00 { + compatible = "img,spfi"; + reg = <0x18100f00 0x100>; + interrupts = ; + clocks = <&spi_clk>, <&system_clk>; + clock-names = "spfi", "sys"; + dmas = <&mdc 9 0xffffffff 0>, <&mdc 10 0xffffffff 0>; + dma-names = "rx", "tx"; + + #address-cells = <1>; + #size-cells = <0>; +}; -- cgit v1.2.3-59-g8ed1b From f2bf2589834faec7af8c02c3949c90788d21b790 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Mon, 17 Nov 2014 14:09:03 +0200 Subject: net: can: c_can: Add support for TI am4372 DCAN AM4372 SoC has 2 DCAN modules. Add compatible id and raminit driver data for it. The driver data is same as AM3352 but this gives us flexibility to add AM4372 specific quirks if required later. Signed-off-by: Roger Quadros Signed-off-by: Marc Kleine-Budde --- Documentation/devicetree/bindings/net/can/c_can.txt | 3 ++- drivers/net/can/c_can/c_can_platform.c | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/can/c_can.txt b/Documentation/devicetree/bindings/net/can/c_can.txt index 6731730eec0d..5a1d8b0c39e9 100644 --- a/Documentation/devicetree/bindings/net/can/c_can.txt +++ b/Documentation/devicetree/bindings/net/can/c_can.txt @@ -4,7 +4,8 @@ Bosch C_CAN/D_CAN controller Device Tree Bindings Required properties: - compatible : Should be "bosch,c_can" for C_CAN controllers and "bosch,d_can" for D_CAN controllers. - Can be "ti,dra7-d_can" or "ti,am3352-d_can". + Can be "ti,dra7-d_can", "ti,am3352-d_can" or + "ti,am4372-d_can". - reg : physical base address and size of the C_CAN/D_CAN registers map - interrupts : property with a value describing the interrupt diff --git a/drivers/net/can/c_can/c_can_platform.c b/drivers/net/can/c_can/c_can_platform.c index f4488e5d5d68..a4535d2142a7 100644 --- a/drivers/net/can/c_can/c_can_platform.c +++ b/drivers/net/can/c_can/c_can_platform.c @@ -235,6 +235,7 @@ static const struct of_device_id c_can_of_table[] = { { .compatible = "bosch,d_can", .data = &d_can_drvdata }, { .compatible = "ti,dra7-d_can", .data = &dra7_dcan_drvdata }, { .compatible = "ti,am3352-d_can", .data = &am3352_dcan_drvdata }, + { .compatible = "ti,am4372-d_can", .data = &am3352_dcan_drvdata }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, c_can_of_table); -- cgit v1.2.3-59-g8ed1b From 039e60ed6cb6715d168943de99a4aececcb65e15 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Thu, 13 Nov 2014 10:25:11 -0300 Subject: DT: i2c: Add binding document for IMG I2C SCB Introduce a devicetree binding for Imagination Technologies I2C SCB controller. Reviewed-by: Andrew Bresticker Signed-off-by: James Hogan Signed-off-by: Ezequiel Garcia Signed-off-by: Wolfram Sang --- .../devicetree/bindings/i2c/i2c-img-scb.txt | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/i2c-img-scb.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/i2c/i2c-img-scb.txt b/Documentation/devicetree/bindings/i2c/i2c-img-scb.txt new file mode 100644 index 000000000000..b6461602dca5 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-img-scb.txt @@ -0,0 +1,26 @@ +IMG Serial Control Bus (SCB) I2C Controller + +Required Properties: +- compatible: "img,scb-i2c" +- reg: Physical base address and length of controller registers +- interrupts: Interrupt number used by the controller +- clocks : Should contain a clock specifier for each entry in clock-names +- clock-names : Should contain the following entries: + "scb", for the SCB core clock. + "sys", for the system clock. +- clock-frequency: The I2C bus frequency in Hz +- #address-cells: Should be <1> +- #size-cells: Should be <0> + +Example: + +i2c@18100000 { + compatible = "img,scb-i2c"; + reg = <0x18100000 0x200>; + interrupts = ; + clocks = <&i2c0_clk>, <&system_clk>; + clock-names = "scb", "sys"; + clock-frequency = <400000>; + #address-cells = <1>; + #size-cells = <0>; +}; -- cgit v1.2.3-59-g8ed1b From 3fb1581ea1ab0aec6ac5430dc0e257a8c9b71680 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 14 Nov 2014 09:47:25 +0100 Subject: ARM: 8199/1: PM / Runtime: Add getter for querying the IRQ safe option v12 Add a simple getter pm_runtime_is_irq_safe() for querying whether runtime PM IRQ safe was set or not. Various bus drivers implementing runtime PM may use choose to suspend differently based on IRQ safeness status of child driver (e.g. do not unprepare the clock if IRQ safe is not set). Signed-off-by: Krzysztof Kozlowski Reviewed-by: Ulf Hansson Acked-by: Rafael J. Wysocki Signed-off-by: Russell King --- Documentation/power/runtime_pm.txt | 4 ++++ include/linux/pm_runtime.h | 6 ++++++ 2 files changed, 10 insertions(+) (limited to 'Documentation') diff --git a/Documentation/power/runtime_pm.txt b/Documentation/power/runtime_pm.txt index f32ce5419573..397b81593142 100644 --- a/Documentation/power/runtime_pm.txt +++ b/Documentation/power/runtime_pm.txt @@ -468,6 +468,10 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h: - set the power.irq_safe flag for the device, causing the runtime-PM callbacks to be invoked with interrupts off + bool pm_runtime_is_irq_safe(struct device *dev); + - return true if power.irq_safe flag was set for the device, causing + the runtime-PM callbacks to be invoked with interrupts off + void pm_runtime_mark_last_busy(struct device *dev); - set the power.last_busy field to the current time diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h index 367f49b9a1c9..44d74f0f182e 100644 --- a/include/linux/pm_runtime.h +++ b/include/linux/pm_runtime.h @@ -128,6 +128,11 @@ static inline void pm_runtime_mark_last_busy(struct device *dev) ACCESS_ONCE(dev->power.last_busy) = jiffies; } +static inline bool pm_runtime_is_irq_safe(struct device *dev) +{ + return dev->power.irq_safe; +} + #else /* !CONFIG_PM_RUNTIME */ static inline int __pm_runtime_idle(struct device *dev, int rpmflags) @@ -167,6 +172,7 @@ static inline bool pm_runtime_enabled(struct device *dev) { return false; } static inline void pm_runtime_no_callbacks(struct device *dev) {} static inline void pm_runtime_irq_safe(struct device *dev) {} +static inline bool pm_runtime_is_irq_safe(struct device *dev) { return false; } static inline bool pm_runtime_callbacks_present(struct device *dev) { return false; } static inline void pm_runtime_mark_last_busy(struct device *dev) {} -- cgit v1.2.3-59-g8ed1b From 5776563648f6437ede91c91cbad85862ca682b0b Mon Sep 17 00:00:00 2001 From: Qiaowei Ren Date: Fri, 14 Nov 2014 07:18:32 -0800 Subject: x86, mpx: Add documentation on Intel MPX This patch adds the Documentation/x86/intel_mpx.txt file with some information about Intel MPX. Signed-off-by: Qiaowei Ren Signed-off-by: Dave Hansen Cc: linux-mm@kvack.org Cc: linux-mips@linux-mips.org Cc: Dave Hansen Link: http://lkml.kernel.org/r/20141114151832.7FDB1720@viggo.jf.intel.com Signed-off-by: Thomas Gleixner --- Documentation/x86/intel_mpx.txt | 234 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 234 insertions(+) create mode 100644 Documentation/x86/intel_mpx.txt (limited to 'Documentation') diff --git a/Documentation/x86/intel_mpx.txt b/Documentation/x86/intel_mpx.txt new file mode 100644 index 000000000000..4472ed2ad921 --- /dev/null +++ b/Documentation/x86/intel_mpx.txt @@ -0,0 +1,234 @@ +1. Intel(R) MPX Overview +======================== + +Intel(R) Memory Protection Extensions (Intel(R) MPX) is a new capability +introduced into Intel Architecture. Intel MPX provides hardware features +that can be used in conjunction with compiler changes to check memory +references, for those references whose compile-time normal intentions are +usurped at runtime due to buffer overflow or underflow. + +For more information, please refer to Intel(R) Architecture Instruction +Set Extensions Programming Reference, Chapter 9: Intel(R) Memory Protection +Extensions. + +Note: Currently no hardware with MPX ISA is available but it is always +possible to use SDE (Intel(R) Software Development Emulator) instead, which +can be downloaded from +http://software.intel.com/en-us/articles/intel-software-development-emulator + + +2. How to get the advantage of MPX +================================== + +For MPX to work, changes are required in the kernel, binutils and compiler. +No source changes are required for applications, just a recompile. + +There are a lot of moving parts of this to all work right. The following +is how we expect the compiler, application and kernel to work together. + +1) Application developer compiles with -fmpx. The compiler will add the + instrumentation as well as some setup code called early after the app + starts. New instruction prefixes are noops for old CPUs. +2) That setup code allocates (virtual) space for the "bounds directory", + points the "bndcfgu" register to the directory and notifies the kernel + (via the new prctl(PR_MPX_ENABLE_MANAGEMENT)) that the app will be using + MPX. +3) The kernel detects that the CPU has MPX, allows the new prctl() to + succeed, and notes the location of the bounds directory. Userspace is + expected to keep the bounds directory at that locationWe note it + instead of reading it each time because the 'xsave' operation needed + to access the bounds directory register is an expensive operation. +4) If the application needs to spill bounds out of the 4 registers, it + issues a bndstx instruction. Since the bounds directory is empty at + this point, a bounds fault (#BR) is raised, the kernel allocates a + bounds table (in the user address space) and makes the relevant entry + in the bounds directory point to the new table. +5) If the application violates the bounds specified in the bounds registers, + a separate kind of #BR is raised which will deliver a signal with + information about the violation in the 'struct siginfo'. +6) Whenever memory is freed, we know that it can no longer contain valid + pointers, and we attempt to free the associated space in the bounds + tables. If an entire table becomes unused, we will attempt to free + the table and remove the entry in the directory. + +To summarize, there are essentially three things interacting here: + +GCC with -fmpx: + * enables annotation of code with MPX instructions and prefixes + * inserts code early in the application to call in to the "gcc runtime" +GCC MPX Runtime: + * Checks for hardware MPX support in cpuid leaf + * allocates virtual space for the bounds directory (malloc() essentially) + * points the hardware BNDCFGU register at the directory + * calls a new prctl(PR_MPX_ENABLE_MANAGEMENT) to notify the kernel to + start managing the bounds directories +Kernel MPX Code: + * Checks for hardware MPX support in cpuid leaf + * Handles #BR exceptions and sends SIGSEGV to the app when it violates + bounds, like during a buffer overflow. + * When bounds are spilled in to an unallocated bounds table, the kernel + notices in the #BR exception, allocates the virtual space, then + updates the bounds directory to point to the new table. It keeps + special track of the memory with a VM_MPX flag. + * Frees unused bounds tables at the time that the memory they described + is unmapped. + + +3. How does MPX kernel code work +================================ + +Handling #BR faults caused by MPX +--------------------------------- + +When MPX is enabled, there are 2 new situations that can generate +#BR faults. + * new bounds tables (BT) need to be allocated to save bounds. + * bounds violation caused by MPX instructions. + +We hook #BR handler to handle these two new situations. + +On-demand kernel allocation of bounds tables +-------------------------------------------- + +MPX only has 4 hardware registers for storing bounds information. If +MPX-enabled code needs more than these 4 registers, it needs to spill +them somewhere. It has two special instructions for this which allow +the bounds to be moved between the bounds registers and some new "bounds +tables". + +#BR exceptions are a new class of exceptions just for MPX. They are +similar conceptually to a page fault and will be raised by the MPX +hardware during both bounds violations or when the tables are not +present. The kernel handles those #BR exceptions for not-present tables +by carving the space out of the normal processes address space and then +pointing the bounds-directory over to it. + +The tables need to be accessed and controlled by userspace because +the instructions for moving bounds in and out of them are extremely +frequent. They potentially happen every time a register points to +memory. Any direct kernel involvement (like a syscall) to access the +tables would obviously destroy performance. + +Why not do this in userspace? MPX does not strictly require anything in +the kernel. It can theoretically be done completely from userspace. Here +are a few ways this could be done. We don't think any of them are practical +in the real-world, but here they are. + +Q: Can virtual space simply be reserved for the bounds tables so that we + never have to allocate them? +A: MPX-enabled application will possibly create a lot of bounds tables in + process address space to save bounds information. These tables can take + up huge swaths of memory (as much as 80% of the memory on the system) + even if we clean them up aggressively. In the worst-case scenario, the + tables can be 4x the size of the data structure being tracked. IOW, a + 1-page structure can require 4 bounds-table pages. An X-GB virtual + area needs 4*X GB of virtual space, plus 2GB for the bounds directory. + If we were to preallocate them for the 128TB of user virtual address + space, we would need to reserve 512TB+2GB, which is larger than the + entire virtual address space today. This means they can not be reserved + ahead of time. Also, a single process's pre-popualated bounds directory + consumes 2GB of virtual *AND* physical memory. IOW, it's completely + infeasible to prepopulate bounds directories. + +Q: Can we preallocate bounds table space at the same time memory is + allocated which might contain pointers that might eventually need + bounds tables? +A: This would work if we could hook the site of each and every memory + allocation syscall. This can be done for small, constrained applications. + But, it isn't practical at a larger scale since a given app has no + way of controlling how all the parts of the app might allocate memory + (think libraries). The kernel is really the only place to intercept + these calls. + +Q: Could a bounds fault be handed to userspace and the tables allocated + there in a signal handler intead of in the kernel? +A: mmap() is not on the list of safe async handler functions and even + if mmap() would work it still requires locking or nasty tricks to + keep track of the allocation state there. + +Having ruled out all of the userspace-only approaches for managing +bounds tables that we could think of, we create them on demand in +the kernel. + +Decoding MPX instructions +------------------------- + +If a #BR is generated due to a bounds violation caused by MPX. +We need to decode MPX instructions to get violation address and +set this address into extended struct siginfo. + +The _sigfault feild of struct siginfo is extended as follow: + +87 /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ +88 struct { +89 void __user *_addr; /* faulting insn/memory ref. */ +90 #ifdef __ARCH_SI_TRAPNO +91 int _trapno; /* TRAP # which caused the signal */ +92 #endif +93 short _addr_lsb; /* LSB of the reported address */ +94 struct { +95 void __user *_lower; +96 void __user *_upper; +97 } _addr_bnd; +98 } _sigfault; + +The '_addr' field refers to violation address, and new '_addr_and' +field refers to the upper/lower bounds when a #BR is caused. + +Glibc will be also updated to support this new siginfo. So user +can get violation address and bounds when bounds violations occur. + +Cleanup unused bounds tables +---------------------------- + +When a BNDSTX instruction attempts to save bounds to a bounds directory +entry marked as invalid, a #BR is generated. This is an indication that +no bounds table exists for this entry. In this case the fault handler +will allocate a new bounds table on demand. + +Since the kernel allocated those tables on-demand without userspace +knowledge, it is also responsible for freeing them when the associated +mappings go away. + +Here, the solution for this issue is to hook do_munmap() to check +whether one process is MPX enabled. If yes, those bounds tables covered +in the virtual address region which is being unmapped will be freed also. + +Adding new prctl commands +------------------------- + +Two new prctl commands are added to enable and disable MPX bounds tables +management in kernel. + +155 #define PR_MPX_ENABLE_MANAGEMENT 43 +156 #define PR_MPX_DISABLE_MANAGEMENT 44 + +Runtime library in userspace is responsible for allocation of bounds +directory. So kernel have to use XSAVE instruction to get the base +of bounds directory from BNDCFG register. + +But XSAVE is expected to be very expensive. In order to do performance +optimization, we have to get the base of bounds directory and save it +into struct mm_struct to be used in future during PR_MPX_ENABLE_MANAGEMENT +command execution. + + +4. Special rules +================ + +1) If userspace is requesting help from the kernel to do the management +of bounds tables, it may not create or modify entries in the bounds directory. + +Certainly users can allocate bounds tables and forcibly point the bounds +directory at them through XSAVE instruction, and then set valid bit +of bounds entry to have this entry valid. But, the kernel will decline +to assist in managing these tables. + +2) Userspace may not take multiple bounds directory entries and point +them at the same bounds table. + +This is allowed architecturally. See more information "Intel(R) Architecture +Instruction Set Extensions Programming Reference" (9.3.4). + +However, if users did this, the kernel might be fooled in to unmaping an +in-use bounds table since it does not recognize sharing. -- cgit v1.2.3-59-g8ed1b From ce1a78840ff7ab846065d5b65eaac959bafe1949 Mon Sep 17 00:00:00 2001 From: Yao Yuan Date: Tue, 18 Nov 2014 18:31:06 +0800 Subject: i2c: imx: add DMA support for freescale i2c driver Add dma support for i2c. This function depend on DMA driver. You can turn on it by write both the dmas and dma-name properties in dts node. DMA is optional, even DMA request unsuccessfully, i2c can also work well. Signed-off-by: Yuan Yao Signed-off-by: Wolfram Sang --- Documentation/devicetree/bindings/i2c/i2c-imx.txt | 11 + drivers/i2c/busses/i2c-imx.c | 335 +++++++++++++++++++++- 2 files changed, 344 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/i2c/i2c-imx.txt b/Documentation/devicetree/bindings/i2c/i2c-imx.txt index 4a8513e44740..52d37fd8d3e5 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-imx.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-imx.txt @@ -11,6 +11,8 @@ Required properties: Optional properties: - clock-frequency : Constains desired I2C/HS-I2C bus clock frequency in Hz. The absence of the propoerty indicates the default frequency 100 kHz. +- dmas: A list of two dma specifiers, one for each entry in dma-names. +- dma-names: should contain "tx" and "rx". Examples: @@ -26,3 +28,12 @@ i2c@70038000 { /* HS-I2C on i.MX51 */ interrupts = <64>; clock-frequency = <400000>; }; + +i2c0: i2c@40066000 { /* i2c0 on vf610 */ + compatible = "fsl,vf610-i2c"; + reg = <0x40066000 0x1000>; + interrupts =<0 71 0x04>; + dmas = <&edma0 0 50>, + <&edma0 0 51>; + dma-names = "rx","tx"; +}; diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index d137289edfca..d0668d0d626d 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -33,7 +33,11 @@ *******************************************************************************/ #include +#include #include +#include +#include +#include #include #include #include @@ -44,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -58,6 +63,15 @@ /* Default value */ #define IMX_I2C_BIT_RATE 100000 /* 100kHz */ +/* + * Enable DMA if transfer byte size is bigger than this threshold. + * As the hardware request, it must bigger than 4 bytes.\ + * I have set '16' here, maybe it's not the best but I think it's + * the appropriate. + */ +#define DMA_THRESHOLD 16 +#define DMA_TIMEOUT 1000 + /* IMX I2C registers: * the I2C register offset is different between SoCs, * to provid support for all these chips, split the @@ -83,6 +97,7 @@ #define I2SR_IBB 0x20 #define I2SR_IAAS 0x40 #define I2SR_ICF 0x80 +#define I2CR_DMAEN 0x02 #define I2CR_RSTA 0x04 #define I2CR_TXAK 0x08 #define I2CR_MTX 0x10 @@ -169,6 +184,17 @@ struct imx_i2c_hwdata { unsigned i2cr_ien_opcode; }; +struct imx_i2c_dma { + struct dma_chan *chan_tx; + struct dma_chan *chan_rx; + struct dma_chan *chan_using; + struct completion cmd_complete; + dma_addr_t dma_buf; + unsigned int dma_len; + enum dma_transfer_direction dma_transfer_dir; + enum dma_data_direction dma_data_dir; +}; + struct imx_i2c_struct { struct i2c_adapter adapter; struct clk *clk; @@ -181,6 +207,8 @@ struct imx_i2c_struct { unsigned int cur_clk; unsigned int bitrate; const struct imx_i2c_hwdata *hwdata; + + struct imx_i2c_dma *dma; }; static const struct imx_i2c_hwdata imx1_i2c_hwdata = { @@ -251,6 +279,138 @@ static inline unsigned char imx_i2c_read_reg(struct imx_i2c_struct *i2c_imx, return readb(i2c_imx->base + (reg << i2c_imx->hwdata->regshift)); } +/* Functions for DMA support */ +static void i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx, + dma_addr_t phy_addr) +{ + struct imx_i2c_dma *dma; + struct dma_slave_config dma_sconfig; + struct device *dev = &i2c_imx->adapter.dev; + int ret; + + dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL); + if (!dma) + return; + + dma->chan_tx = dma_request_slave_channel(dev, "tx"); + if (!dma->chan_tx) { + dev_dbg(dev, "can't request DMA tx channel\n"); + ret = -ENODEV; + goto fail_al; + } + + dma_sconfig.dst_addr = phy_addr + + (IMX_I2C_I2DR << i2c_imx->hwdata->regshift); + dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + dma_sconfig.dst_maxburst = 1; + dma_sconfig.direction = DMA_MEM_TO_DEV; + ret = dmaengine_slave_config(dma->chan_tx, &dma_sconfig); + if (ret < 0) { + dev_dbg(dev, "can't configure tx channel\n"); + goto fail_tx; + } + + dma->chan_rx = dma_request_slave_channel(dev, "rx"); + if (!dma->chan_rx) { + dev_dbg(dev, "can't request DMA rx channel\n"); + ret = -ENODEV; + goto fail_tx; + } + + dma_sconfig.src_addr = phy_addr + + (IMX_I2C_I2DR << i2c_imx->hwdata->regshift); + dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + dma_sconfig.src_maxburst = 1; + dma_sconfig.direction = DMA_DEV_TO_MEM; + ret = dmaengine_slave_config(dma->chan_rx, &dma_sconfig); + if (ret < 0) { + dev_dbg(dev, "can't configure rx channel\n"); + goto fail_rx; + } + + i2c_imx->dma = dma; + init_completion(&dma->cmd_complete); + dev_info(dev, "using %s (tx) and %s (rx) for DMA transfers\n", + dma_chan_name(dma->chan_tx), dma_chan_name(dma->chan_rx)); + + return; + +fail_rx: + dma_release_channel(dma->chan_rx); +fail_tx: + dma_release_channel(dma->chan_tx); +fail_al: + devm_kfree(dev, dma); + dev_info(dev, "can't use DMA\n"); +} + +static void i2c_imx_dma_callback(void *arg) +{ + struct imx_i2c_struct *i2c_imx = (struct imx_i2c_struct *)arg; + struct imx_i2c_dma *dma = i2c_imx->dma; + + dma_unmap_single(dma->chan_using->device->dev, dma->dma_buf, + dma->dma_len, dma->dma_data_dir); + complete(&dma->cmd_complete); +} + +static int i2c_imx_dma_xfer(struct imx_i2c_struct *i2c_imx, + struct i2c_msg *msgs) +{ + struct imx_i2c_dma *dma = i2c_imx->dma; + struct dma_async_tx_descriptor *txdesc; + struct device *dev = &i2c_imx->adapter.dev; + struct device *chan_dev = dma->chan_using->device->dev; + + dma->dma_buf = dma_map_single(chan_dev, msgs->buf, + dma->dma_len, dma->dma_data_dir); + if (dma_mapping_error(chan_dev, dma->dma_buf)) { + dev_err(dev, "DMA mapping failed\n"); + goto err_map; + } + + txdesc = dmaengine_prep_slave_single(dma->chan_using, dma->dma_buf, + dma->dma_len, dma->dma_transfer_dir, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!txdesc) { + dev_err(dev, "Not able to get desc for DMA xfer\n"); + goto err_desc; + } + + txdesc->callback = i2c_imx_dma_callback; + txdesc->callback_param = i2c_imx; + if (dma_submit_error(dmaengine_submit(txdesc))) { + dev_err(dev, "DMA submit failed\n"); + goto err_submit; + } + + dma_async_issue_pending(dma->chan_using); + return 0; + +err_submit: +err_desc: + dma_unmap_single(chan_dev, dma->dma_buf, + dma->dma_len, dma->dma_data_dir); +err_map: + return -EINVAL; +} + +static void i2c_imx_dma_free(struct imx_i2c_struct *i2c_imx) +{ + struct imx_i2c_dma *dma = i2c_imx->dma; + + dma->dma_buf = 0; + dma->dma_len = 0; + + dma_release_channel(dma->chan_tx); + dma->chan_tx = NULL; + + dma_release_channel(dma->chan_rx); + dma->chan_rx = NULL; + + dma->chan_using = NULL; +} + /** Functions for IMX I2C adapter driver *************************************** *******************************************************************************/ @@ -382,6 +542,7 @@ static int i2c_imx_start(struct imx_i2c_struct *i2c_imx) i2c_imx->stopped = 0; temp |= I2CR_IIEN | I2CR_MTX | I2CR_TXAK; + temp &= ~I2CR_DMAEN; imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); return result; } @@ -395,6 +556,8 @@ static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx) dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__); temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); temp &= ~(I2CR_MSTA | I2CR_MTX); + if (i2c_imx->dma) + temp &= ~I2CR_DMAEN; imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); } if (is_imx1_i2c(i2c_imx)) { @@ -435,6 +598,159 @@ static irqreturn_t i2c_imx_isr(int irq, void *dev_id) return IRQ_NONE; } +static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx, + struct i2c_msg *msgs) +{ + int result; + unsigned int temp = 0; + unsigned long orig_jiffies = jiffies; + struct imx_i2c_dma *dma = i2c_imx->dma; + struct device *dev = &i2c_imx->adapter.dev; + + dma->chan_using = dma->chan_tx; + dma->dma_transfer_dir = DMA_MEM_TO_DEV; + dma->dma_data_dir = DMA_TO_DEVICE; + dma->dma_len = msgs->len - 1; + result = i2c_imx_dma_xfer(i2c_imx, msgs); + if (result) + return result; + + temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); + temp |= I2CR_DMAEN; + imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); + + /* + * Write slave address. + * The first byte must be transmitted by the CPU. + */ + imx_i2c_write_reg(msgs->addr << 1, i2c_imx, IMX_I2C_I2DR); + reinit_completion(&i2c_imx->dma->cmd_complete); + result = wait_for_completion_timeout( + &i2c_imx->dma->cmd_complete, + msecs_to_jiffies(DMA_TIMEOUT)); + if (result <= 0) { + dmaengine_terminate_all(dma->chan_using); + return result ?: -ETIMEDOUT; + } + + /* Waiting for transfer complete. */ + while (1) { + temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR); + if (temp & I2SR_ICF) + break; + if (time_after(jiffies, orig_jiffies + + msecs_to_jiffies(DMA_TIMEOUT))) { + dev_dbg(dev, "<%s> Timeout\n", __func__); + return -ETIMEDOUT; + } + schedule(); + } + + temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); + temp &= ~I2CR_DMAEN; + imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); + + /* The last data byte must be transferred by the CPU. */ + imx_i2c_write_reg(msgs->buf[msgs->len-1], + i2c_imx, IMX_I2C_I2DR); + result = i2c_imx_trx_complete(i2c_imx); + if (result) + return result; + + result = i2c_imx_acked(i2c_imx); + if (result) + return result; + + return 0; +} + +static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx, + struct i2c_msg *msgs, bool is_lastmsg) +{ + int result; + unsigned int temp; + unsigned long orig_jiffies = jiffies; + struct imx_i2c_dma *dma = i2c_imx->dma; + struct device *dev = &i2c_imx->adapter.dev; + + temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); + temp |= I2CR_DMAEN; + imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); + + dma->chan_using = dma->chan_rx; + dma->dma_transfer_dir = DMA_DEV_TO_MEM; + dma->dma_data_dir = DMA_FROM_DEVICE; + /* The last two data bytes must be transferred by the CPU. */ + dma->dma_len = msgs->len - 2; + result = i2c_imx_dma_xfer(i2c_imx, msgs); + if (result) + return result; + + reinit_completion(&i2c_imx->dma->cmd_complete); + result = wait_for_completion_timeout( + &i2c_imx->dma->cmd_complete, + msecs_to_jiffies(DMA_TIMEOUT)); + if (result <= 0) { + dmaengine_terminate_all(dma->chan_using); + return result ?: -ETIMEDOUT; + } + + /* waiting for transfer complete. */ + while (1) { + temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR); + if (temp & I2SR_ICF) + break; + if (time_after(jiffies, orig_jiffies + + msecs_to_jiffies(DMA_TIMEOUT))) { + dev_dbg(dev, "<%s> Timeout\n", __func__); + return -ETIMEDOUT; + } + schedule(); + } + + temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); + temp &= ~I2CR_DMAEN; + imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); + + /* read n-1 byte data */ + temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); + temp |= I2CR_TXAK; + imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); + + msgs->buf[msgs->len-2] = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); + /* read n byte data */ + result = i2c_imx_trx_complete(i2c_imx); + if (result) + return result; + + if (is_lastmsg) { + /* + * It must generate STOP before read I2DR to prevent + * controller from generating another clock cycle + */ + dev_dbg(dev, "<%s> clear MSTA\n", __func__); + temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); + temp &= ~(I2CR_MSTA | I2CR_MTX); + imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); + i2c_imx_bus_busy(i2c_imx, 0); + i2c_imx->stopped = 1; + } else { + /* + * For i2c master receiver repeat restart operation like: + * read -> repeat MSTA -> read/write + * The controller must set MTX before read the last byte in + * the first read operation, otherwise the first read cost + * one extra clock cycle. + */ + temp = readb(i2c_imx->base + IMX_I2C_I2CR); + temp |= I2CR_MTX; + writeb(temp, i2c_imx->base + IMX_I2C_I2CR); + } + msgs->buf[msgs->len-1] = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); + + return 0; +} + static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs) { int i, result; @@ -504,6 +820,9 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bo dev_dbg(&i2c_imx->adapter.dev, "<%s> read data\n", __func__); + if (i2c_imx->dma && msgs->len >= DMA_THRESHOLD && !block_data) + return i2c_imx_dma_read(i2c_imx, msgs, is_lastmsg); + /* read data */ for (i = 0; i < msgs->len; i++) { u8 len = 0; @@ -618,8 +937,12 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter, #endif if (msgs[i].flags & I2C_M_RD) result = i2c_imx_read(i2c_imx, &msgs[i], is_lastmsg); - else - result = i2c_imx_write(i2c_imx, &msgs[i]); + else { + if (i2c_imx->dma && msgs[i].len >= DMA_THRESHOLD) + result = i2c_imx_dma_write(i2c_imx, &msgs[i]); + else + result = i2c_imx_write(i2c_imx, &msgs[i]); + } if (result) goto fail0; } @@ -654,6 +977,7 @@ static int i2c_imx_probe(struct platform_device *pdev) struct imxi2c_platform_data *pdata = dev_get_platdata(&pdev->dev); void __iomem *base; int irq, ret; + dma_addr_t phy_addr; dev_dbg(&pdev->dev, "<%s>\n", __func__); @@ -668,6 +992,7 @@ static int i2c_imx_probe(struct platform_device *pdev) if (IS_ERR(base)) return PTR_ERR(base); + phy_addr = (dma_addr_t)res->start; i2c_imx = devm_kzalloc(&pdev->dev, sizeof(*i2c_imx), GFP_KERNEL); if (!i2c_imx) return -ENOMEM; @@ -742,6 +1067,9 @@ static int i2c_imx_probe(struct platform_device *pdev) i2c_imx->adapter.name); dev_info(&i2c_imx->adapter.dev, "IMX I2C adapter registered\n"); + /* Init DMA config if support*/ + i2c_imx_dma_request(i2c_imx, phy_addr); + return 0; /* Return OK */ clk_disable: @@ -757,6 +1085,9 @@ static int i2c_imx_remove(struct platform_device *pdev) dev_dbg(&i2c_imx->adapter.dev, "adapter removed\n"); i2c_del_adapter(&i2c_imx->adapter); + if (i2c_imx->dma) + i2c_imx_dma_free(i2c_imx); + /* setup chip registers to defaults */ imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IADR); imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IFDR); -- cgit v1.2.3-59-g8ed1b From 30021e3707a75cc29dc1252c062d374151c5985f Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Thu, 13 Nov 2014 20:32:01 +0100 Subject: i2c: add support for Amlogic Meson I2C controller This is a driver for the I2C controller found in Amlogic Meson SoCs. Signed-off-by: Beniamino Galvani Signed-off-by: Wolfram Sang --- .../devicetree/bindings/i2c/i2c-meson.txt | 24 + drivers/i2c/busses/Kconfig | 7 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-meson.c | 492 +++++++++++++++++++++ 4 files changed, 524 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/i2c-meson.txt create mode 100644 drivers/i2c/busses/i2c-meson.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/i2c/i2c-meson.txt b/Documentation/devicetree/bindings/i2c/i2c-meson.txt new file mode 100644 index 000000000000..682f9a6f766e --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-meson.txt @@ -0,0 +1,24 @@ +Amlogic Meson I2C controller + +Required properties: + - compatible: must be "amlogic,meson6-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). + +Examples: + + i2c@c8100500 { + compatible = "amlogic,meson6-i2c"; + reg = <0xc8100500 0x20>; + interrupts = <0 92 1>; + clocks = <&clk81>; + #address-cells = <1>; + #size-cells = <0>; + }; diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 03c6119325ef..a940e336351d 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -564,6 +564,13 @@ config I2C_KEMPLD This driver can also be built as a module. If so, the module will be called i2c-kempld. +config I2C_MESON + tristate "Amlogic Meson I2C controller" + depends on ARCH_MESON + help + If you say yes to this option, support will be included for the + I2C interface on the Amlogic Meson family of SoCs. + config I2C_MPC tristate "MPC107/824x/85xx/512x/52xx/83xx/86xx" depends on PPC diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 84861ead6be9..e9b4a1f8431f 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -54,6 +54,7 @@ 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_KEMPLD) += i2c-kempld.o +obj-$(CONFIG_I2C_MESON) += i2c-meson.o obj-$(CONFIG_I2C_MPC) += i2c-mpc.o obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o obj-$(CONFIG_I2C_MXS) += i2c-mxs.o diff --git a/drivers/i2c/busses/i2c-meson.c b/drivers/i2c/busses/i2c-meson.c new file mode 100644 index 000000000000..5e176adca8e8 --- /dev/null +++ b/drivers/i2c/busses/i2c-meson.c @@ -0,0 +1,492 @@ +/* + * I2C bus driver for Amlogic Meson SoCs + * + * Copyright (C) 2014 Beniamino Galvani + * + * 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 + +/* Meson I2C register map */ +#define REG_CTRL 0x00 +#define REG_SLAVE_ADDR 0x04 +#define REG_TOK_LIST0 0x08 +#define REG_TOK_LIST1 0x0c +#define REG_TOK_WDATA0 0x10 +#define REG_TOK_WDATA1 0x14 +#define REG_TOK_RDATA0 0x18 +#define REG_TOK_RDATA1 0x1c + +/* Control register fields */ +#define REG_CTRL_START BIT(0) +#define REG_CTRL_ACK_IGNORE BIT(1) +#define REG_CTRL_STATUS BIT(2) +#define REG_CTRL_ERROR BIT(3) +#define REG_CTRL_CLKDIV_SHIFT 12 +#define REG_CTRL_CLKDIV_MASK ((BIT(10) - 1) << REG_CTRL_CLKDIV_SHIFT) + +#define I2C_TIMEOUT_MS 500 +#define DEFAULT_FREQ 100000 + +enum { + TOKEN_END = 0, + TOKEN_START, + TOKEN_SLAVE_ADDR_WRITE, + TOKEN_SLAVE_ADDR_READ, + TOKEN_DATA, + TOKEN_DATA_LAST, + TOKEN_STOP, +}; + +enum { + STATE_IDLE, + STATE_READ, + STATE_WRITE, + STATE_STOP, +}; + +/** + * struct meson_i2c - Meson I2C device private data + * + * @adap: I2C adapter instance + * @dev: Pointer to device structure + * @regs: Base address of the device memory mapped registers + * @clk: Pointer to clock structure + * @irq: IRQ number + * @msg: Pointer to the current I2C message + * @state: Current state in the driver state machine + * @last: Flag set for the last message in the transfer + * @count: Number of bytes to be sent/received in current transfer + * @pos: Current position in the send/receive buffer + * @error: Flag set when an error is received + * @lock: To avoid race conditions between irq handler and xfer code + * @done: Completion used to wait for transfer termination + * @frequency: Operating frequency of I2C bus clock + * @tokens: Sequence of tokens to be written to the device + * @num_tokens: Number of tokens + */ +struct meson_i2c { + struct i2c_adapter adap; + struct device *dev; + void __iomem *regs; + struct clk *clk; + int irq; + + struct i2c_msg *msg; + int state; + bool last; + int count; + int pos; + int error; + + spinlock_t lock; + struct completion done; + unsigned int frequency; + u32 tokens[2]; + int num_tokens; +}; + +static void meson_i2c_set_mask(struct meson_i2c *i2c, int reg, u32 mask, + u32 val) +{ + u32 data; + + data = readl(i2c->regs + reg); + data &= ~mask; + data |= val & mask; + writel(data, i2c->regs + reg); +} + +static void meson_i2c_reset_tokens(struct meson_i2c *i2c) +{ + i2c->tokens[0] = 0; + i2c->tokens[1] = 0; + i2c->num_tokens = 0; +} + +static void meson_i2c_add_token(struct meson_i2c *i2c, int token) +{ + if (i2c->num_tokens < 8) + i2c->tokens[0] |= (token & 0xf) << (i2c->num_tokens * 4); + else + i2c->tokens[1] |= (token & 0xf) << ((i2c->num_tokens % 8) * 4); + + i2c->num_tokens++; +} + +static void meson_i2c_write_tokens(struct meson_i2c *i2c) +{ + writel(i2c->tokens[0], i2c->regs + REG_TOK_LIST0); + writel(i2c->tokens[1], i2c->regs + REG_TOK_LIST1); +} + +static void meson_i2c_set_clk_div(struct meson_i2c *i2c) +{ + unsigned long clk_rate = clk_get_rate(i2c->clk); + unsigned int div; + + div = DIV_ROUND_UP(clk_rate, i2c->frequency * 4); + meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIV_MASK, + div << REG_CTRL_CLKDIV_SHIFT); + + dev_dbg(i2c->dev, "%s: clk %lu, freq %u, div %u\n", __func__, + clk_rate, i2c->frequency, div); +} + +static void meson_i2c_get_data(struct meson_i2c *i2c, char *buf, int len) +{ + u32 rdata0, rdata1; + int i; + + rdata0 = readl(i2c->regs + REG_TOK_RDATA0); + rdata1 = readl(i2c->regs + REG_TOK_RDATA1); + + dev_dbg(i2c->dev, "%s: data %08x %08x len %d\n", __func__, + rdata0, rdata1, len); + + for (i = 0; i < min_t(int, 4, len); i++) + *buf++ = (rdata0 >> i * 8) & 0xff; + + for (i = 4; i < min_t(int, 8, len); i++) + *buf++ = (rdata1 >> (i - 4) * 8) & 0xff; +} + +static void meson_i2c_put_data(struct meson_i2c *i2c, char *buf, int len) +{ + u32 wdata0 = 0, wdata1 = 0; + int i; + + for (i = 0; i < min_t(int, 4, len); i++) + wdata0 |= *buf++ << (i * 8); + + for (i = 4; i < min_t(int, 8, len); i++) + wdata1 |= *buf++ << ((i - 4) * 8); + + writel(wdata0, i2c->regs + REG_TOK_WDATA0); + writel(wdata0, i2c->regs + REG_TOK_WDATA1); + + dev_dbg(i2c->dev, "%s: data %08x %08x len %d\n", __func__, + wdata0, wdata1, len); +} + +static void meson_i2c_prepare_xfer(struct meson_i2c *i2c) +{ + bool write = !(i2c->msg->flags & I2C_M_RD); + int i; + + i2c->count = min_t(int, i2c->msg->len - i2c->pos, 8); + + for (i = 0; i < i2c->count - 1; i++) + meson_i2c_add_token(i2c, TOKEN_DATA); + + if (i2c->count) { + if (write || i2c->pos + i2c->count < i2c->msg->len) + meson_i2c_add_token(i2c, TOKEN_DATA); + else + meson_i2c_add_token(i2c, TOKEN_DATA_LAST); + } + + if (write) + meson_i2c_put_data(i2c, i2c->msg->buf + i2c->pos, i2c->count); +} + +static void meson_i2c_stop(struct meson_i2c *i2c) +{ + dev_dbg(i2c->dev, "%s: last %d\n", __func__, i2c->last); + + if (i2c->last) { + i2c->state = STATE_STOP; + meson_i2c_add_token(i2c, TOKEN_STOP); + } else { + i2c->state = STATE_IDLE; + complete_all(&i2c->done); + } +} + +static irqreturn_t meson_i2c_irq(int irqno, void *dev_id) +{ + struct meson_i2c *i2c = dev_id; + unsigned int ctrl; + + spin_lock(&i2c->lock); + + meson_i2c_reset_tokens(i2c); + ctrl = readl(i2c->regs + REG_CTRL); + + dev_dbg(i2c->dev, "irq: state %d, pos %d, count %d, ctrl %08x\n", + i2c->state, i2c->pos, i2c->count, ctrl); + + if (ctrl & REG_CTRL_ERROR && i2c->state != STATE_IDLE) { + /* + * The bit is set when the IGNORE_NAK bit is cleared + * and the device didn't respond. In this case, the + * I2C controller automatically generates a STOP + * condition. + */ + dev_dbg(i2c->dev, "error bit set\n"); + i2c->error = -ENXIO; + i2c->state = STATE_IDLE; + complete_all(&i2c->done); + goto out; + } + + switch (i2c->state) { + case STATE_READ: + if (i2c->count > 0) { + meson_i2c_get_data(i2c, i2c->msg->buf + i2c->pos, + i2c->count); + i2c->pos += i2c->count; + } + + if (i2c->pos >= i2c->msg->len) { + meson_i2c_stop(i2c); + break; + } + + meson_i2c_prepare_xfer(i2c); + break; + case STATE_WRITE: + i2c->pos += i2c->count; + + if (i2c->pos >= i2c->msg->len) { + meson_i2c_stop(i2c); + break; + } + + meson_i2c_prepare_xfer(i2c); + break; + case STATE_STOP: + i2c->state = STATE_IDLE; + complete_all(&i2c->done); + break; + case STATE_IDLE: + break; + } + +out: + if (i2c->state != STATE_IDLE) { + /* Restart the processing */ + meson_i2c_write_tokens(i2c); + meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, 0); + meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, + REG_CTRL_START); + } + + spin_unlock(&i2c->lock); + + return IRQ_HANDLED; +} + +static void meson_i2c_do_start(struct meson_i2c *i2c, struct i2c_msg *msg) +{ + int token; + + token = (msg->flags & I2C_M_RD) ? TOKEN_SLAVE_ADDR_READ : + TOKEN_SLAVE_ADDR_WRITE; + + writel(msg->addr << 1, i2c->regs + REG_SLAVE_ADDR); + meson_i2c_add_token(i2c, TOKEN_START); + meson_i2c_add_token(i2c, token); +} + +static int meson_i2c_xfer_msg(struct meson_i2c *i2c, struct i2c_msg *msg, + int last) +{ + unsigned long time_left, flags; + int ret = 0; + + i2c->msg = msg; + i2c->last = last; + i2c->pos = 0; + i2c->count = 0; + i2c->error = 0; + + meson_i2c_reset_tokens(i2c); + + flags = (msg->flags & I2C_M_IGNORE_NAK) ? REG_CTRL_ACK_IGNORE : 0; + meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_ACK_IGNORE, flags); + + if (!(msg->flags & I2C_M_NOSTART)) + meson_i2c_do_start(i2c, msg); + + i2c->state = (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE; + meson_i2c_prepare_xfer(i2c); + meson_i2c_write_tokens(i2c); + reinit_completion(&i2c->done); + + /* Start the transfer */ + meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, REG_CTRL_START); + + time_left = msecs_to_jiffies(I2C_TIMEOUT_MS); + time_left = wait_for_completion_timeout(&i2c->done, time_left); + + /* + * Protect access to i2c struct and registers from interrupt + * handlers triggered by a transfer terminated after the + * timeout period + */ + spin_lock_irqsave(&i2c->lock, flags); + + /* Abort any active operation */ + meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, 0); + + if (!time_left) { + i2c->state = STATE_IDLE; + ret = -ETIMEDOUT; + } + + if (i2c->error) + ret = i2c->error; + + spin_unlock_irqrestore(&i2c->lock, flags); + + return ret; +} + +static int meson_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + int num) +{ + struct meson_i2c *i2c = adap->algo_data; + int i, ret = 0, count = 0; + + clk_enable(i2c->clk); + meson_i2c_set_clk_div(i2c); + + for (i = 0; i < num; i++) { + ret = meson_i2c_xfer_msg(i2c, msgs + i, i == num - 1); + if (ret) + break; + count++; + } + + clk_disable(i2c->clk); + + return ret ? ret : count; +} + +static u32 meson_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm meson_i2c_algorithm = { + .master_xfer = meson_i2c_xfer, + .functionality = meson_i2c_func, +}; + +static int meson_i2c_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct meson_i2c *i2c; + struct resource *mem; + int ret = 0; + + i2c = devm_kzalloc(&pdev->dev, sizeof(struct meson_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)) { + dev_err(&pdev->dev, "can't get device clock\n"); + return PTR_ERR(i2c->clk); + } + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + i2c->regs = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(i2c->regs)) + return PTR_ERR(i2c->regs); + + i2c->irq = platform_get_irq(pdev, 0); + if (i2c->irq < 0) { + dev_err(&pdev->dev, "can't find IRQ\n"); + return i2c->irq; + } + + ret = devm_request_irq(&pdev->dev, i2c->irq, meson_i2c_irq, + 0, dev_name(&pdev->dev), i2c); + if (ret < 0) { + dev_err(&pdev->dev, "can't request IRQ\n"); + return ret; + } + + ret = clk_prepare(i2c->clk); + if (ret < 0) { + dev_err(&pdev->dev, "can't prepare clock\n"); + return ret; + } + + strlcpy(i2c->adap.name, "Meson I2C adapter", + sizeof(i2c->adap.name)); + i2c->adap.owner = THIS_MODULE; + i2c->adap.algo = &meson_i2c_algorithm; + i2c->adap.dev.parent = &pdev->dev; + i2c->adap.dev.of_node = np; + i2c->adap.algo_data = i2c; + + /* + * A transfer is triggered when START bit changes from 0 to 1. + * Ensure that the bit is set to 0 after probe + */ + meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, 0); + + ret = i2c_add_adapter(&i2c->adap); + if (ret < 0) { + dev_err(&pdev->dev, "can't register adapter\n"); + clk_unprepare(i2c->clk); + return ret; + } + + return 0; +} + +static int meson_i2c_remove(struct platform_device *pdev) +{ + struct meson_i2c *i2c = platform_get_drvdata(pdev); + + i2c_del_adapter(&i2c->adap); + clk_unprepare(i2c->clk); + + return 0; +} + +static const struct of_device_id meson_i2c_match[] = { + { .compatible = "amlogic,meson6-i2c" }, + { }, +}; + +static struct platform_driver meson_i2c_driver = { + .probe = meson_i2c_probe, + .remove = meson_i2c_remove, + .driver = { + .name = "meson-i2c", + .of_match_table = meson_i2c_match, + }, +}; + +module_platform_driver(meson_i2c_driver); + +MODULE_DESCRIPTION("Amlogic Meson I2C Bus driver"); +MODULE_AUTHOR("Beniamino Galvani "); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-59-g8ed1b From a25a6772db05b252d9861b80b6387b67f69a8b8e Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Sun, 5 Oct 2014 23:59:18 +0200 Subject: ARM: meson: document meson8 compatible properties Add device tree bindings documentation for Amlogic Meson8 SoCs. Signed-off-by: Beniamino Galvani Acked-by: Arnd Bergmann Signed-off-by: Carlo Caione --- Documentation/devicetree/bindings/arm/amlogic.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/amlogic.txt b/Documentation/devicetree/bindings/arm/amlogic.txt index 7eece72b1a35..8fe815046140 100644 --- a/Documentation/devicetree/bindings/arm/amlogic.txt +++ b/Documentation/devicetree/bindings/arm/amlogic.txt @@ -2,7 +2,9 @@ Amlogic MesonX device tree bindings ------------------------------------------- Boards with the Amlogic Meson6 SoC shall have the following properties: + Required root node property: + compatible: "amlogic,meson6" -Required root node property: - -compatible = "amlogic,meson6"; +Boards with the Amlogic Meson8 SoC shall have the following properties: + Required root node property: + compatible: "amlogic,meson8"; -- cgit v1.2.3-59-g8ed1b From b19556231156ce3e58ffd677747bf3ef7890a937 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 31 Oct 2014 14:10:14 +0100 Subject: s390/docs: Fix the documentation of the address spaces The information about the address spaces was completely outdated, since the usage of the address spaces changed quite a bit since the early days. This patch now updates the information about the usage of the address spaces, mostly by using the description from Heiko's patch "rework uaccess code - fix locking issues" (457f2180951cdcbfb4657ddcc83b486e93497f56). Signed-off-by: Thomas Huth Signed-off-by: Martin Schwidefsky --- Documentation/s390/Debugging390.txt | 88 +++++++++++++++++++++++++------------ 1 file changed, 61 insertions(+), 27 deletions(-) (limited to 'Documentation') diff --git a/Documentation/s390/Debugging390.txt b/Documentation/s390/Debugging390.txt index 462321c1aeea..2120eec48a5c 100644 --- a/Documentation/s390/Debugging390.txt +++ b/Documentation/s390/Debugging390.txt @@ -114,28 +114,25 @@ s/390 z/Architecture 16-17 16-17 Address Space Control - 00 Primary Space Mode when DAT on - The linux kernel currently runs in this mode, CR1 is affiliated with - this mode & points to the primary segment table origin etc. - - 01 Access register mode this mode is used in functions to - copy data between kernel & user space. - - 10 Secondary space mode not used in linux however CR7 the - register affiliated with this mode is & this & normally - CR13=CR7 to allow us to copy data between kernel & user space. - We do this as follows: - We set ar2 to 0 to designate its - affiliated gpr ( gpr2 )to point to primary=kernel space. - We set ar4 to 1 to designate its - affiliated gpr ( gpr4 ) to point to secondary=home=user space - & then essentially do a memcopy(gpr2,gpr4,size) to - copy data between the address spaces, the reason we use home space for the - kernel & don't keep secondary space free is that code will not run in - secondary space. - - 11 Home Space Mode all user programs run in this mode. - it is affiliated with CR13. + 00 Primary Space Mode: + The register CR1 contains the primary address-space control ele- + ment (PASCE), which points to the primary space region/segment + table origin. + + 01 Access register mode + + 10 Secondary Space Mode: + The register CR7 contains the secondary address-space control + element (SASCE), which points to the secondary space region or + segment table origin. + + 11 Home Space Mode: + The register CR13 contains the home space address-space control + element (HASCE), which points to the home space region/segment + table origin. + + See "Address Spaces on Linux for s/390 & z/Architecture" below + for more information about address space usage in Linux. 18-19 18-19 Condition codes (CC) @@ -249,9 +246,9 @@ currently 4TB of physical memory currently on z/Architecture. Address Spaces on Linux for s/390 & z/Architecture ================================================== -Our addressing scheme is as follows - +Our addressing scheme is basically as follows: + Primary Space Home Space Himem 0x7fffffff 2GB on s/390 ***************** **************** currently 0x3ffffffffff (2^42)-1 * User Stack * * * on z/Architecture. ***************** * * @@ -264,9 +261,46 @@ on z/Architecture. ***************** * * * Sections * * * 0x00000000 ***************** **************** -This also means that we need to look at the PSW problem state bit -or the addressing mode to decide whether we are looking at -user or kernel space. +This also means that we need to look at the PSW problem state bit and the +addressing mode to decide whether we are looking at user or kernel space. + +User space runs in primary address mode (or access register mode within +the vdso code). + +The kernel usually also runs in home space mode, however when accessing +user space the kernel switches to primary or secondary address mode if +the mvcos instruction is not available or if a compare-and-swap (futex) +instruction on a user space address is performed. + +When also looking at the ASCE control registers, this means: + +User space: +- runs in primary or access register mode +- cr1 contains the user asce +- cr7 contains the user asce +- cr13 contains the kernel asce + +Kernel space: +- runs in home space mode +- cr1 contains the user or kernel asce + -> the kernel asce is loaded when a uaccess requires primary or + secondary address mode +- cr7 contains the user or kernel asce, (changed with set_fs()) +- cr13 contains the kernel asce + +In case of uaccess the kernel changes to: +- primary space mode in case of a uaccess (copy_to_user) and uses + e.g. the mvcp instruction to access user space. However the kernel + will stay in home space mode if the mvcos instruction is available +- secondary space mode in case of futex atomic operations, so that the + instructions come from primary address space and data from secondary + space + +In case of KVM, the kernel runs in home space mode, but cr1 gets switched +to contain the gmap asce before the SIE instruction gets executed. When +the SIE instruction is finished, cr1 will be switched back to contain the +user asce. + Virtual Addresses on s/390 & z/Architecture =========================================== -- cgit v1.2.3-59-g8ed1b From a6b42afa3fc452339e157ad5245320804cf1206f Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 28 Oct 2014 15:12:23 +0100 Subject: s390/docs: Remove sections that are not related to s390 Information how to use the GCC pre-processor, objdump, strace, top, etc. are generic and not specific to the S390 architecture, so we do not need this information in Debugging390.txt Signed-off-by: Thomas Huth Signed-off-by: Martin Schwidefsky --- Documentation/s390/Debugging390.txt | 374 ------------------------------------ 1 file changed, 374 deletions(-) (limited to 'Documentation') diff --git a/Documentation/s390/Debugging390.txt b/Documentation/s390/Debugging390.txt index 2120eec48a5c..08911b5c6b0e 100644 --- a/Documentation/s390/Debugging390.txt +++ b/Documentation/s390/Debugging390.txt @@ -26,11 +26,6 @@ The Linux for s/390 & z/Architecture Kernel Task Structure Register Usage & Stackframes on Linux for s/390 & z/Architecture A sample program with comments Compiling programs for debugging on Linux for s/390 & z/Architecture -Figuring out gcc compile errors -Debugging Tools -objdump -strace -Performance Debugging Debugging under VM s/390 & z/Architecture IO Overview Debugging IO on s/390 & z/Architecture under VM @@ -740,376 +735,7 @@ Debugging with optimisation has since much improved after fixing some bugs, please make sure you are using gdb-5.0 or later developed after Nov'2000. -Figuring out gcc compile errors -=============================== -If you are getting a lot of syntax errors compiling a program & the problem -isn't blatantly obvious from the source. -It often helps to just preprocess the file, this is done with the -E -option in gcc. -What this does is that it runs through the very first phase of compilation -( compilation in gcc is done in several stages & gcc calls many programs to -achieve its end result ) with the -E option gcc just calls the gcc preprocessor (cpp). -The c preprocessor does the following, it joins all the files #included together -recursively ( #include files can #include other files ) & also the c file you wish to compile. -It puts a fully qualified path of the #included files in a comment & it -does macro expansion. -This is useful for debugging because -1) You can double check whether the files you expect to be included are the ones -that are being included ( e.g. double check that you aren't going to the i386 asm directory ). -2) Check that macro definitions aren't clashing with typedefs, -3) Check that definitions aren't being used before they are being included. -4) Helps put the line emitting the error under the microscope if it contains macros. - -For convenience the Linux kernel's makefile will do preprocessing automatically for you -by suffixing the file you want built with .i ( instead of .o ) - -e.g. -from the linux directory type -make arch/s390/kernel/signal.i -this will build - -s390-gcc -D__KERNEL__ -I/home1/barrow/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer --fno-strict-aliasing -D__SMP__ -pipe -fno-strength-reduce -E arch/s390/kernel/signal.c -> arch/s390/kernel/signal.i - -Now look at signal.i you should see something like. - - -# 1 "/home1/barrow/linux/include/asm/types.h" 1 -typedef unsigned short umode_t; -typedef __signed__ char __s8; -typedef unsigned char __u8; -typedef __signed__ short __s16; -typedef unsigned short __u16; - -If instead you are getting errors further down e.g. -unknown instruction:2515 "move.l" or better still unknown instruction:2515 -"Fixme not implemented yet, call Martin" you are probably are attempting to compile some code -meant for another architecture or code that is simply not implemented, with a fixme statement -stuck into the inline assembly code so that the author of the file now knows he has work to do. -To look at the assembly emitted by gcc just before it is about to call gas ( the gnu assembler ) -use the -S option. -Again for your convenience the Linux kernel's Makefile will hold your hand & -do all this donkey work for you also by building the file with the .s suffix. -e.g. -from the Linux directory type -make arch/s390/kernel/signal.s - -s390-gcc -D__KERNEL__ -I/home1/barrow/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer --fno-strict-aliasing -D__SMP__ -pipe -fno-strength-reduce -S arch/s390/kernel/signal.c --o arch/s390/kernel/signal.s - - -This will output something like, ( please note the constant pool & the useful comments -in the prologue to give you a hand at interpreting it ). - -.LC54: - .string "misaligned (__u16 *) in __xchg\n" -.LC57: - .string "misaligned (__u32 *) in __xchg\n" -.L$PG1: # Pool sys_sigsuspend -.LC192: - .long -262401 -.LC193: - .long -1 -.LC194: - .long schedule-.L$PG1 -.LC195: - .long do_signal-.L$PG1 - .align 4 -.globl sys_sigsuspend - .type sys_sigsuspend,@function -sys_sigsuspend: -# leaf function 0 -# automatics 16 -# outgoing args 0 -# need frame pointer 0 -# call alloca 0 -# has varargs 0 -# incoming args (stack) 0 -# function length 168 - STM 8,15,32(15) - LR 0,15 - AHI 15,-112 - BASR 13,0 -.L$CO1: AHI 13,.L$PG1-.L$CO1 - ST 0,0(15) - LR 8,2 - N 5,.LC192-.L$PG1(13) - -Adding -g to the above output makes the output even more useful -e.g. typing -make CC:="s390-gcc -g" kernel/sched.s - -which compiles. -s390-gcc -g -D__KERNEL__ -I/home/barrow/linux-2.3/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -pipe -fno-strength-reduce -S kernel/sched.c -o kernel/sched.s - -also outputs stabs ( debugger ) info, from this info you can find out the -offsets & sizes of various elements in structures. -e.g. the stab for the structure -struct rlimit { - unsigned long rlim_cur; - unsigned long rlim_max; -}; -is -.stabs "rlimit:T(151,2)=s8rlim_cur:(0,5),0,32;rlim_max:(0,5),32,32;;",128,0,0,0 -from this stab you can see that -rlimit_cur starts at bit offset 0 & is 32 bits in size -rlimit_max starts at bit offset 32 & is 32 bits in size. - - -Debugging Tools: -================ - -objdump -======= -This is a tool with many options the most useful being ( if compiled with -g). -objdump --source > - - -The whole kernel can be compiled like this ( Doing this will make a 17MB kernel -& a 200 MB listing ) however you have to strip it before building the image -using the strip command to make it a more reasonable size to boot it. - -A source/assembly mixed dump of the kernel can be done with the line -objdump --source vmlinux > vmlinux.lst -Also, if the file isn't compiled -g, this will output as much debugging information -as it can (e.g. function names). This is very slow as it spends lots -of time searching for debugging info. The following self explanatory line should be used -instead if the code isn't compiled -g, as it is much faster: -objdump --disassemble-all --syms vmlinux > vmlinux.lst - -As hard drive space is valuable most of us use the following approach. -1) Look at the emitted psw on the console to find the crash address in the kernel. -2) Look at the file System.map ( in the linux directory ) produced when building -the kernel to find the closest address less than the current PSW to find the -offending function. -3) use grep or similar to search the source tree looking for the source file - with this function if you don't know where it is. -4) rebuild this object file with -g on, as an example suppose the file was -( /arch/s390/kernel/signal.o ) -5) Assuming the file with the erroneous function is signal.c Move to the base of the -Linux source tree. -6) rm /arch/s390/kernel/signal.o -7) make /arch/s390/kernel/signal.o -8) watch the gcc command line emitted -9) type it in again or alternatively cut & paste it on the console adding the -g option. -10) objdump --source arch/s390/kernel/signal.o > signal.lst -This will output the source & the assembly intermixed, as the snippet below shows -This will unfortunately output addresses which aren't the same -as the kernel ones you should be able to get around the mental arithmetic -by playing with the --adjust-vma parameter to objdump. - - - - -static inline void spin_lock(spinlock_t *lp) -{ - a0: 18 34 lr %r3,%r4 - a2: a7 3a 03 bc ahi %r3,956 - __asm__ __volatile(" lhi 1,-1\n" - a6: a7 18 ff ff lhi %r1,-1 - aa: 1f 00 slr %r0,%r0 - ac: ba 01 30 00 cs %r0,%r1,0(%r3) - b0: a7 44 ff fd jm aa - saveset = current->blocked; - b4: d2 07 f0 68 mvc 104(8,%r15),972(%r4) - b8: 43 cc - return (set->sig[0] & mask) != 0; -} - -6) If debugging under VM go down to that section in the document for more info. - - -I now have a tool which takes the pain out of --adjust-vma -& you are able to do something like -make /arch/s390/kernel/traps.lst -& it automatically generates the correctly relocated entries for -the text segment in traps.lst. -This tool is now standard in linux distro's in scripts/makelst - -strace: -------- -Q. What is it ? -A. It is a tool for intercepting calls to the kernel & logging them -to a file & on the screen. - -Q. What use is it ? -A. You can use it to find out what files a particular program opens. - - - -Example 1 ---------- -If you wanted to know does ping work but didn't have the source -strace ping -c 1 127.0.0.1 -& then look at the man pages for each of the syscalls below, -( In fact this is sometimes easier than looking at some spaghetti -source which conditionally compiles for several architectures ). -Not everything that it throws out needs to make sense immediately. - -Just looking quickly you can see that it is making up a RAW socket -for the ICMP protocol. -Doing an alarm(10) for a 10 second timeout -& doing a gettimeofday call before & after each read to see -how long the replies took, & writing some text to stdout so the user -has an idea what is going on. - -socket(PF_INET, SOCK_RAW, IPPROTO_ICMP) = 3 -getuid() = 0 -setuid(0) = 0 -stat("/usr/share/locale/C/libc.cat", 0xbffff134) = -1 ENOENT (No such file or directory) -stat("/usr/share/locale/libc/C", 0xbffff134) = -1 ENOENT (No such file or directory) -stat("/usr/local/share/locale/C/libc.cat", 0xbffff134) = -1 ENOENT (No such file or directory) -getpid() = 353 -setsockopt(3, SOL_SOCKET, SO_BROADCAST, [1], 4) = 0 -setsockopt(3, SOL_SOCKET, SO_RCVBUF, [49152], 4) = 0 -fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(3, 1), ...}) = 0 -mmap(0, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40008000 -ioctl(1, TCGETS, {B9600 opost isig icanon echo ...}) = 0 -write(1, "PING 127.0.0.1 (127.0.0.1): 56 d"..., 42PING 127.0.0.1 (127.0.0.1): 56 data bytes -) = 42 -sigaction(SIGINT, {0x8049ba0, [], SA_RESTART}, {SIG_DFL}) = 0 -sigaction(SIGALRM, {0x8049600, [], SA_RESTART}, {SIG_DFL}) = 0 -gettimeofday({948904719, 138951}, NULL) = 0 -sendto(3, "\10\0D\201a\1\0\0\17#\2178\307\36"..., 64, 0, {sin_family=AF_INET, -sin_port=htons(0), sin_addr=inet_addr("127.0.0.1")}, 16) = 64 -sigaction(SIGALRM, {0x8049600, [], SA_RESTART}, {0x8049600, [], SA_RESTART}) = 0 -sigaction(SIGALRM, {0x8049ba0, [], SA_RESTART}, {0x8049600, [], SA_RESTART}) = 0 -alarm(10) = 0 -recvfrom(3, "E\0\0T\0005\0\0@\1|r\177\0\0\1\177"..., 192, 0, -{sin_family=AF_INET, sin_port=htons(50882), sin_addr=inet_addr("127.0.0.1")}, [16]) = 84 -gettimeofday({948904719, 160224}, NULL) = 0 -recvfrom(3, "E\0\0T\0006\0\0\377\1\275p\177\0"..., 192, 0, -{sin_family=AF_INET, sin_port=htons(50882), sin_addr=inet_addr("127.0.0.1")}, [16]) = 84 -gettimeofday({948904719, 166952}, NULL) = 0 -write(1, "64 bytes from 127.0.0.1: icmp_se"..., -5764 bytes from 127.0.0.1: icmp_seq=0 ttl=255 time=28.0 ms - -Example 2 ---------- -strace passwd 2>&1 | grep open -produces the following output -open("/etc/ld.so.cache", O_RDONLY) = 3 -open("/opt/kde/lib/libc.so.5", O_RDONLY) = -1 ENOENT (No such file or directory) -open("/lib/libc.so.5", O_RDONLY) = 3 -open("/dev", O_RDONLY) = 3 -open("/var/run/utmp", O_RDONLY) = 3 -open("/etc/passwd", O_RDONLY) = 3 -open("/etc/shadow", O_RDONLY) = 3 -open("/etc/login.defs", O_RDONLY) = 4 -open("/dev/tty", O_RDONLY) = 4 - -The 2>&1 is done to redirect stderr to stdout & grep is then filtering this input -through the pipe for each line containing the string open. - - -Example 3 ---------- -Getting sophisticated -telnetd crashes & I don't know why - -Steps ------ -1) Replace the following line in /etc/inetd.conf -telnet stream tcp nowait root /usr/sbin/in.telnetd -h -with -telnet stream tcp nowait root /blah - -2) Create the file /blah with the following contents to start tracing telnetd -#!/bin/bash -/usr/bin/strace -o/t1 -f /usr/sbin/in.telnetd -h -3) chmod 700 /blah to make it executable only to root -4) -killall -HUP inetd -or ps aux | grep inetd -get inetd's process id -& kill -HUP inetd to restart it. - -Important options ------------------ --o is used to tell strace to output to a file in our case t1 in the root directory --f is to follow children i.e. -e.g in our case above telnetd will start the login process & subsequently a shell like bash. -You will be able to tell which is which from the process ID's listed on the left hand side -of the strace output. --p will tell strace to attach to a running process, yup this can be done provided - it isn't being traced or debugged already & you have enough privileges, -the reason 2 processes cannot trace or debug the same program is that strace -becomes the parent process of the one being debugged & processes ( unlike people ) -can have only one parent. - - -However the file /t1 will get big quite quickly -to test it telnet 127.0.0.1 - -now look at what files in.telnetd execve'd -413 execve("/usr/sbin/in.telnetd", ["/usr/sbin/in.telnetd", "-h"], [/* 17 vars */]) = 0 -414 execve("/bin/login", ["/bin/login", "-h", "localhost", "-p"], [/* 2 vars */]) = 0 -Whey it worked!. - - -Other hints: ------------- -If the program is not very interactive ( i.e. not much keyboard input ) -& is crashing in one architecture but not in another you can do -an strace of both programs under as identical a scenario as you can -on both architectures outputting to a file then. -do a diff of the two traces using the diff program -i.e. -diff output1 output2 -& maybe you'll be able to see where the call paths differed, this -is possibly near the cause of the crash. - -More info ---------- -Look at man pages for strace & the various syscalls -e.g. man strace, man alarm, man socket. - - -Performance Debugging -===================== -gcc is capable of compiling in profiling code just add the -p option -to the CFLAGS, this obviously affects program size & performance. -This can be used by the gprof gnu profiling tool or the -gcov the gnu code coverage tool ( code coverage is a means of testing -code quality by checking if all the code in an executable in exercised by -a tester ). - - -Using top to find out where processes are sleeping in the kernel ----------------------------------------------------------------- -To do this copy the System.map from the root directory where -the linux kernel was built to the /boot directory on your -linux machine. -Start top -Now type fU -You should see a new field called WCHAN which -tells you where each process is sleeping here is a typical output. - - 6:59pm up 41 min, 1 user, load average: 0.00, 0.00, 0.00 -28 processes: 27 sleeping, 1 running, 0 zombie, 0 stopped -CPU states: 0.0% user, 0.1% system, 0.0% nice, 99.8% idle -Mem: 254900K av, 45976K used, 208924K free, 0K shrd, 28636K buff -Swap: 0K av, 0K used, 0K free 8620K cached - - PID USER PRI NI SIZE RSS SHARE WCHAN STAT LIB %CPU %MEM TIME COMMAND - 750 root 12 0 848 848 700 do_select S 0 0.1 0.3 0:00 in.telnetd - 767 root 16 0 1140 1140 964 R 0 0.1 0.4 0:00 top - 1 root 8 0 212 212 180 do_select S 0 0.0 0.0 0:00 init - 2 root 9 0 0 0 0 down_inte SW 0 0.0 0.0 0:00 kmcheck - -The time command ----------------- -Another related command is the time command which gives you an indication -of where a process is spending the majority of its time. -e.g. -time ping -c 5 nc -outputs -real 0m4.054s -user 0m0.010s -sys 0m0.010s Debugging under VM ================== -- cgit v1.2.3-59-g8ed1b From 97735da074fdd3fe39d975cad8760807df0d4388 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Wed, 15 Oct 2014 16:50:52 +0100 Subject: drivers: cpuidle: Add status property to ARM idle states On some platforms the device tree bindings must provide the kernel with a status flag for idle states, that defines whether the idle state is operational or not in the current configuration. This patch adds a status property to the ARM idle states compliant with ePAPR v1.1 and updates the DT parsing code accordingly. Acked-by: Kevin Hilman Signed-off-by: Lorenzo Pieralisi Signed-off-by: Daniel Lezcano --- Documentation/devicetree/bindings/arm/idle-states.txt | 14 ++++++++++++++ drivers/cpuidle/dt_idle_states.c | 3 +++ 2 files changed, 17 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/idle-states.txt b/Documentation/devicetree/bindings/arm/idle-states.txt index 37375c7f3ccc..5e5151130c20 100644 --- a/Documentation/devicetree/bindings/arm/idle-states.txt +++ b/Documentation/devicetree/bindings/arm/idle-states.txt @@ -317,6 +317,20 @@ follows: In such systems entry-latency-us + exit-latency-us will exceed wakeup-latency-us by this duration. + - status: + Usage: Optional + Value type: + Definition: A standard device tree property [5] that indicates + the operational status of an idle-state. + If present, it shall be: + "okay": to indicate that the idle state is + operational. + "disabled": to indicate that the idle state has + been disabled in firmware so it is not + operational. + If the property is not present the idle-state must + be considered operational. + In addition to the properties listed above, a state node may require additional properties specifics to the entry-method defined in the idle-states node, please refer to the entry-method bindings diff --git a/drivers/cpuidle/dt_idle_states.c b/drivers/cpuidle/dt_idle_states.c index 52f4d11bbf3f..22840f40283c 100644 --- a/drivers/cpuidle/dt_idle_states.c +++ b/drivers/cpuidle/dt_idle_states.c @@ -169,6 +169,9 @@ int dt_init_idle_driver(struct cpuidle_driver *drv, if (!state_node) break; + if (!of_device_is_available(state_node)) + continue; + if (!idle_state_valid(state_node, i, cpumask)) { pr_warn("%s idle state not valid, bailing out\n", state_node->full_name); -- cgit v1.2.3-59-g8ed1b From c00bc5df7c01a189843cb048cf29e2a445e0037a Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Wed, 15 Oct 2014 16:57:34 +0100 Subject: drivers: cpuidle: Add idle-state-name description to ARM idle states On ARM machines, where generally speaking the idle state numbering has no fixed and standard meaning it is useful to provide a description of the idle state inner workings for benchmarking and monitoring purposes. This patch adds a property to the idle states bindings that if present gives platform firmware a means of describing the idle state and export the string description to user space. The patch updates the DT parsing code accordingly to take the description, if present, into consideration. Acked-by: Kevin Hilman Signed-off-by: Lorenzo Pieralisi Signed-off-by: Daniel Lezcano --- Documentation/devicetree/bindings/arm/idle-states.txt | 6 ++++++ drivers/cpuidle/dt_idle_states.c | 7 ++++++- 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/idle-states.txt b/Documentation/devicetree/bindings/arm/idle-states.txt index 5e5151130c20..a8274eabae2e 100644 --- a/Documentation/devicetree/bindings/arm/idle-states.txt +++ b/Documentation/devicetree/bindings/arm/idle-states.txt @@ -331,6 +331,12 @@ follows: If the property is not present the idle-state must be considered operational. + - idle-state-name: + Usage: Optional + Value type: + Definition: A string used as a descriptive name for the idle + state. + In addition to the properties listed above, a state node may require additional properties specifics to the entry-method defined in the idle-states node, please refer to the entry-method bindings diff --git a/drivers/cpuidle/dt_idle_states.c b/drivers/cpuidle/dt_idle_states.c index 22840f40283c..5301912cb84e 100644 --- a/drivers/cpuidle/dt_idle_states.c +++ b/drivers/cpuidle/dt_idle_states.c @@ -27,6 +27,7 @@ static int init_state_node(struct cpuidle_state *idle_state, { int err; const struct of_device_id *match_id; + const char *desc; match_id = of_match_node(matches, state_node); if (!match_id) @@ -73,6 +74,10 @@ static int init_state_node(struct cpuidle_state *idle_state, return -EINVAL; } + err = of_property_read_string(state_node, "idle-state-name", &desc); + if (err) + desc = state_node->name; + idle_state->flags = CPUIDLE_FLAG_TIME_VALID; if (of_property_read_bool(state_node, "local-timer-stop")) idle_state->flags |= CPUIDLE_FLAG_TIMER_STOP; @@ -82,7 +87,7 @@ static int init_state_node(struct cpuidle_state *idle_state, * and desc become string pointers */ strncpy(idle_state->name, state_node->name, CPUIDLE_NAME_LEN - 1); - strncpy(idle_state->desc, state_node->name, CPUIDLE_DESC_LEN - 1); + strncpy(idle_state->desc, desc, CPUIDLE_DESC_LEN - 1); return 0; } -- cgit v1.2.3-59-g8ed1b From fa040c24b19d8067c57fa488660361b122d2138e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 14 Nov 2014 17:03:30 +0100 Subject: DT: i2c: Add more devices handled by the rtc-rs5c372 driver This allows checkpatch to validate more DTSes. Signed-off-by: Geert Uytterhoeven Signed-off-by: Wolfram Sang --- Documentation/devicetree/bindings/i2c/trivial-devices.txt | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/i2c/trivial-devices.txt b/Documentation/devicetree/bindings/i2c/trivial-devices.txt index fbde415078e6..7a2bbea61b70 100644 --- a/Documentation/devicetree/bindings/i2c/trivial-devices.txt +++ b/Documentation/devicetree/bindings/i2c/trivial-devices.txt @@ -74,7 +74,12 @@ ovti,ov5642 OV5642: Color CMOS QSXGA (5-megapixel) Image Sensor with OmniBSI an pericom,pt7c4338 Real-time Clock Module plx,pex8648 48-Lane, 12-Port PCI Express Gen 2 (5.0 GT/s) Switch ramtron,24c64 i2c serial eeprom (24cxx) +ricoh,r2025sd I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC +ricoh,r2221tl I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC ricoh,rs5c372a I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC +ricoh,rs5c372b I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC +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 st-micro,24c256 i2c serial eeprom (24cxx) -- cgit v1.2.3-59-g8ed1b From 11321585f91bcb6de64376c3d767fb3200e20b53 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 14 Nov 2014 17:03:31 +0100 Subject: DT: i2c: Add more devices handled by the adxl34x-i2c driver This allows checkpatch to validate more DTSes. Signed-off-by: Geert Uytterhoeven Signed-off-by: Wolfram Sang --- Documentation/devicetree/bindings/i2c/trivial-devices.txt | 3 +++ 1 file changed, 3 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/i2c/trivial-devices.txt b/Documentation/devicetree/bindings/i2c/trivial-devices.txt index 7a2bbea61b70..e0beef4f8cff 100644 --- a/Documentation/devicetree/bindings/i2c/trivial-devices.txt +++ b/Documentation/devicetree/bindings/i2c/trivial-devices.txt @@ -17,6 +17,9 @@ adi,adt7473 +/-1C TDM Extended Temp Range I.C adi,adt7475 +/-1C TDM Extended Temp Range I.C adi,adt7476 +/-1C TDM Extended Temp Range I.C adi,adt7490 +/-1C TDM Extended Temp Range I.C +adi,adxl345 Three-Axis Digital Accelerometer +adi,adxl346 Three-Axis Digital Accelerometer +adi,adxl34x Three-Axis Digital Accelerometer at,24c08 i2c serial eeprom (24cxx) atmel,24c00 i2c serial eeprom (24cxx) atmel,24c01 i2c serial eeprom (24cxx) -- cgit v1.2.3-59-g8ed1b From 098ea6bc4cb5890d09b1b79154fa11182e0f71e0 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Wed, 19 Nov 2014 01:28:32 -0800 Subject: Bluetooth: btmrvl: add DT bindings documentation Calibration data can be downloaded through device tree method. This patch adds the documentation. Also, instead of searching device tree node by name using of_find_node_by_name() API, let's use for_each_compatible_node(). Signed-off-by: Amitkumar Karwar Signed-off-by: Cathy Luo Signed-off-by: Avinash Patil Signed-off-by: Marcel Holtmann --- Documentation/devicetree/bindings/btmrvl.txt | 22 ++++++++++++++++++++ drivers/bluetooth/btmrvl_main.c | 31 +++++++++++++--------------- 2 files changed, 36 insertions(+), 17 deletions(-) create mode 100644 Documentation/devicetree/bindings/btmrvl.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/btmrvl.txt b/Documentation/devicetree/bindings/btmrvl.txt new file mode 100644 index 000000000000..cdd57680a749 --- /dev/null +++ b/Documentation/devicetree/bindings/btmrvl.txt @@ -0,0 +1,22 @@ +btmrvl +------ + +Required properties: + + - compatible : must be "btmrvl,cfgdata" + +Optional properties: + + - btmrvl,cal-data : Calibration data downloaded to the device during + initialization. This is an array of 28 values(u8). + +Example: + +btmrvl { + compatible = "btmrvl,cfgdata"; + + btmrvl,cal-data = /bits/ 8 < + 0x37 0x01 0x1c 0x00 0xff 0xff 0xff 0xff 0x01 0x7f 0x04 0x02 + 0x00 0x00 0xba 0xce 0xc0 0xc6 0x2d 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0xf0 0x00>; +}; diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index 1d7db2064889..2909bca6b8b6 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c @@ -496,25 +496,22 @@ static int btmrvl_cal_data_dt(struct btmrvl_private *priv) { struct device_node *dt_node; u8 cal_data[BT_CAL_HDR_LEN + BT_CAL_DATA_SIZE]; - const char name[] = "btmrvl_caldata"; - const char property[] = "btmrvl,caldata"; int ret; - dt_node = of_find_node_by_name(NULL, name); - if (!dt_node) - return -ENODEV; - - ret = of_property_read_u8_array(dt_node, property, - cal_data + BT_CAL_HDR_LEN, - BT_CAL_DATA_SIZE); - if (ret) - return ret; - - BT_DBG("Use cal data from device tree"); - ret = btmrvl_download_cal_data(priv, cal_data, BT_CAL_DATA_SIZE); - if (ret) { - BT_ERR("Fail to download calibrate data"); - return ret; + for_each_compatible_node(dt_node, NULL, "btmrvl,cfgdata") { + ret = of_property_read_u8_array(dt_node, "btmrvl,cal-data", + cal_data + BT_CAL_HDR_LEN, + BT_CAL_DATA_SIZE); + if (ret) + return ret; + + BT_DBG("Use cal data from device tree"); + ret = btmrvl_download_cal_data(priv, cal_data, + BT_CAL_DATA_SIZE); + if (ret) { + BT_ERR("Fail to download calibrate data"); + return ret; + } } return 0; -- cgit v1.2.3-59-g8ed1b From 025a60a752261fd479a4bb74cf7cb04fdc313ec7 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Wed, 19 Nov 2014 01:28:33 -0800 Subject: Bluetooth: btmrvl: add DT-bindings for gpio-gap This can be used to have GPIO host wakeup method suitable for the platform and configurable GAP for host sleep handshake. Signed-off-by: Amitkumar Karwar Signed-off-by: Cathy Luo Signed-off-by: Avinash Patil Signed-off-by: Marcel Holtmann --- Documentation/devicetree/bindings/btmrvl.txt | 7 +++++++ drivers/bluetooth/btmrvl_main.c | 12 +++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/btmrvl.txt b/Documentation/devicetree/bindings/btmrvl.txt index cdd57680a749..58f964bb0a52 100644 --- a/Documentation/devicetree/bindings/btmrvl.txt +++ b/Documentation/devicetree/bindings/btmrvl.txt @@ -10,8 +10,14 @@ Optional properties: - btmrvl,cal-data : Calibration data downloaded to the device during initialization. This is an array of 28 values(u8). + - btmrvl,gpio-gap : gpio and gap (in msecs) combination to be + configured. + Example: +GPIO pin 13 is configured as a wakeup source and GAP is set to 100 msecs +in below example. + btmrvl { compatible = "btmrvl,cfgdata"; @@ -19,4 +25,5 @@ btmrvl { 0x37 0x01 0x1c 0x00 0xff 0xff 0xff 0xff 0x01 0x7f 0x04 0x02 0x00 0x00 0xba 0xce 0xc0 0xc6 0x2d 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xf0 0x00>; + btmrvl,gpio-gap = <0x0d64>; }; diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index 2909bca6b8b6..e43c495e8181 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c @@ -492,13 +492,18 @@ static int btmrvl_download_cal_data(struct btmrvl_private *priv, return 0; } -static int btmrvl_cal_data_dt(struct btmrvl_private *priv) +static int btmrvl_check_device_tree(struct btmrvl_private *priv) { struct device_node *dt_node; u8 cal_data[BT_CAL_HDR_LEN + BT_CAL_DATA_SIZE]; int ret; + u32 val; for_each_compatible_node(dt_node, NULL, "btmrvl,cfgdata") { + ret = of_property_read_u32(dt_node, "btmrvl,gpio-gap", &val); + if (!ret) + priv->btmrvl_dev.gpio_gap = val; + ret = of_property_read_u8_array(dt_node, "btmrvl,cal-data", cal_data + BT_CAL_HDR_LEN, BT_CAL_DATA_SIZE); @@ -523,14 +528,15 @@ static int btmrvl_setup(struct hci_dev *hdev) btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ); - btmrvl_cal_data_dt(priv); + priv->btmrvl_dev.gpio_gap = 0xffff; + + btmrvl_check_device_tree(priv); btmrvl_pscan_window_reporting(priv, 0x01); priv->btmrvl_dev.psmode = 1; btmrvl_enable_ps(priv); - priv->btmrvl_dev.gpio_gap = 0xffff; btmrvl_send_hscfg_cmd(priv); return 0; -- cgit v1.2.3-59-g8ed1b From 41d28bca2da4bd75a8915c1ccf2cacf7f4a2e531 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 12 Oct 2014 22:24:21 -0400 Subject: switch d_materialise_unique() users to d_splice_alias() Signed-off-by: Al Viro --- Documentation/filesystems/nfs/Exporting | 23 +++++------------------ Documentation/filesystems/porting | 4 ++++ fs/9p/vfs_inode.c | 2 +- fs/btrfs/inode.c | 2 +- fs/ceph/inode.c | 2 +- fs/cifs/readdir.c | 2 +- fs/fuse/dir.c | 4 ++-- fs/kernfs/dir.c | 2 +- fs/nfs/dir.c | 4 ++-- fs/nfs/getroot.c | 2 +- include/linux/dcache.h | 1 - 11 files changed, 19 insertions(+), 29 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/nfs/Exporting b/Documentation/filesystems/nfs/Exporting index c8f036a9b13f..520a4becb75c 100644 --- a/Documentation/filesystems/nfs/Exporting +++ b/Documentation/filesystems/nfs/Exporting @@ -72,24 +72,11 @@ c/ Helper routines to allocate anonymous dentries, and to help attach DCACHE_DISCONNECTED) dentry is allocated and attached. In the case of a directory, care is taken that only one dentry can ever be attached. - d_splice_alias(inode, dentry) or d_materialise_unique(dentry, inode) - will introduce a new dentry into the tree; either the passed-in - dentry or a preexisting alias for the given inode (such as an - anonymous one created by d_obtain_alias), if appropriate. The two - functions differ in their handling of directories with preexisting - aliases: - d_splice_alias will use any existing IS_ROOT dentry, but it will - return -EIO rather than try to move a dentry with a different - parent. This is appropriate for local filesystems, which - should never see such an alias unless the filesystem is - corrupted somehow (for example, if two on-disk directory - entries refer to the same directory.) - d_materialise_unique will attempt to move any dentry. This is - appropriate for distributed filesystems, where finding a - directory other than where we last cached it may be a normal - consequence of concurrent operations on other hosts. - Both functions return NULL when the passed-in dentry is used, - following the calling convention of ->lookup. + d_splice_alias(inode, dentry) will introduce a new dentry into the tree; + either the passed-in dentry or a preexisting alias for the given inode + (such as an anonymous one created by d_obtain_alias), if appropriate. + It returns NULL when the passed-in dentry is used, following the calling + convention of ->lookup. Filesystem Issues diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting index 0f3a1390bf00..b6b55a9cffee 100644 --- a/Documentation/filesystems/porting +++ b/Documentation/filesystems/porting @@ -463,3 +463,7 @@ in your dentry operations instead. of the in-tree instances did). inode_hash_lock is still held, of course, so they are still serialized wrt removal from inode hash, as well as wrt set() callback of iget5_locked(). +-- +[mandatory] + d_materialise_unique() is gone; d_splice_alias() does everything you + need now. Remember that they have opposite orders of arguments ;-/ diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 296482fc77a9..9ee5343d4884 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -832,7 +832,7 @@ struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, * moved b under k and client parallely did a lookup for * k/b. */ - res = d_materialise_unique(dentry, inode); + res = d_splice_alias(inode, dentry); if (!res) v9fs_fid_add(dentry, fid); else if (!IS_ERR(res)) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index d23362f4464e..ff0dcc016b71 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -5303,7 +5303,7 @@ static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry, return ERR_CAST(inode); } - return d_materialise_unique(dentry, inode); + return d_splice_alias(inode, dentry); } unsigned char btrfs_filetype_table[] = { diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 7a1df90c7771..90ec8e32c138 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -967,7 +967,7 @@ static struct dentry *splice_dentry(struct dentry *dn, struct inode *in, /* dn must be unhashed */ if (!d_unhashed(dn)) d_drop(dn); - realdn = d_materialise_unique(dn, in); + realdn = d_splice_alias(in, dn); if (IS_ERR(realdn)) { pr_err("splice_dentry error %ld %p inode %p ino %llx.%llx\n", PTR_ERR(realdn), dn, in, ceph_vinop(in)); diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 8fd2a95860ba..586e3d3b204e 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -123,7 +123,7 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name, if (!inode) goto out; - alias = d_materialise_unique(dentry, inode); + alias = d_splice_alias(inode, dentry); if (alias && !IS_ERR(alias)) dput(alias); out: diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index dbab798f5caf..df562cc87763 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -372,7 +372,7 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, if (inode && get_node_id(inode) == FUSE_ROOT_ID) goto out_iput; - newent = d_materialise_unique(entry, inode); + newent = d_splice_alias(inode, entry); err = PTR_ERR(newent); if (IS_ERR(newent)) goto out_err; @@ -1320,7 +1320,7 @@ static int fuse_direntplus_link(struct file *file, if (!inode) goto out; - alias = d_materialise_unique(dentry, inode); + alias = d_splice_alias(inode, dentry); err = PTR_ERR(alias); if (IS_ERR(alias)) goto out; diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index 1c771931bb60..37989f02a226 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c @@ -807,7 +807,7 @@ static struct dentry *kernfs_iop_lookup(struct inode *dir, } /* instantiate and hash dentry */ - ret = d_materialise_unique(dentry, inode); + ret = d_splice_alias(inode, dentry); out_unlock: mutex_unlock(&kernfs_mutex); return ret; diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 06e8cfcbb670..44d7d0c7e376 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -499,7 +499,7 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry) if (IS_ERR(inode)) goto out; - alias = d_materialise_unique(dentry, inode); + alias = d_splice_alias(inode, dentry); if (IS_ERR(alias)) goto out; else if (alias) { @@ -1393,7 +1393,7 @@ struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned in nfs_advise_use_readdirplus(dir); no_entry: - res = d_materialise_unique(dentry, inode); + res = d_splice_alias(inode, dentry); if (res != NULL) { if (IS_ERR(res)) goto out_unblock_sillyrename; diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c index ebc6a0add5ae..9ac3846cb59e 100644 --- a/fs/nfs/getroot.c +++ b/fs/nfs/getroot.c @@ -51,7 +51,7 @@ static int nfs_superblock_set_dummy_root(struct super_block *sb, struct inode *i /* * Ensure that this dentry is invisible to d_find_alias(). * Otherwise, it may be spliced into the tree by - * d_materialise_unique if a parent directory from the same + * d_splice_alias if a parent directory from the same * filesystem gets mounted at a later time. * This again causes shrink_dcache_for_umount_subtree() to * Oops, since the test for IS_ROOT() will fail. diff --git a/include/linux/dcache.h b/include/linux/dcache.h index ee569da27b72..5a813988e6d4 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -230,7 +230,6 @@ extern seqlock_t rename_lock; */ extern void d_instantiate(struct dentry *, struct inode *); extern struct dentry * d_instantiate_unique(struct dentry *, struct inode *); -#define d_materialise_unique(d, i) d_splice_alias(i, d) extern int d_instantiate_no_diralias(struct dentry *, struct inode *); extern void __d_drop(struct dentry *dentry); extern void d_drop(struct dentry *dentry); -- cgit v1.2.3-59-g8ed1b From 78d28e651f97866d608d9b41f8ad291e65d47dd5 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 31 Oct 2014 01:22:04 -0400 Subject: kill f_dentry macro Signed-off-by: Al Viro --- Documentation/filesystems/porting | 4 ++++ include/linux/fs.h | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting index b6b55a9cffee..fa2db081505e 100644 --- a/Documentation/filesystems/porting +++ b/Documentation/filesystems/porting @@ -467,3 +467,7 @@ in your dentry operations instead. [mandatory] d_materialise_unique() is gone; d_splice_alias() does everything you need now. Remember that they have opposite orders of arguments ;-/ +-- +[mandatory] + f_dentry is gone; use f_path.dentry, or, better yet, see if you can avoid + it entirely. diff --git a/include/linux/fs.h b/include/linux/fs.h index 1c12c681803f..1a8bb3c023a1 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -789,7 +789,6 @@ struct file { struct rcu_head fu_rcuhead; } f_u; struct path f_path; -#define f_dentry f_path.dentry struct inode *f_inode; /* cached value */ const struct file_operations *f_op; -- cgit v1.2.3-59-g8ed1b From 7a8685accb95801bb29ab85d5b370999d3fb8e32 Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Wed, 19 Nov 2014 04:48:35 -0800 Subject: leds: lp8860: Introduce TI lp8860 4 channel LED driver Introduce the Texas Instruments lp8860 4 channel LED driver. This driver configures the device in display cluster mode as this seems to be the most used configuration at the time of the driver configuration. For more product information please see the link below: http://www.ti.com/product/lp8860-q1 Signed-off-by: Dan Murphy Signed-off-by: Bryan Wu --- .../devicetree/bindings/leds/leds-lp8860.txt | 29 ++ drivers/leds/Kconfig | 10 + drivers/leds/Makefile | 1 + drivers/leds/leds-lp8860.c | 491 +++++++++++++++++++++ 4 files changed, 531 insertions(+) create mode 100644 Documentation/devicetree/bindings/leds/leds-lp8860.txt create mode 100644 drivers/leds/leds-lp8860.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/leds/leds-lp8860.txt b/Documentation/devicetree/bindings/leds/leds-lp8860.txt new file mode 100644 index 000000000000..aad38dd94d4b --- /dev/null +++ b/Documentation/devicetree/bindings/leds/leds-lp8860.txt @@ -0,0 +1,29 @@ +* Texas Instruments - lp8860 4-Channel LED Driver + +The LP8860-Q1 is an high-efficiency LED +driver with boost controller. It has 4 high-precision +current sinks that can be controlled by a PWM input +signal, a SPI/I2C master, or both. + +Required properties: + - compatible: + "ti,lp8860" + - reg - I2C slave address + - label - Used for naming LEDs + +Optional properties: + - enable-gpio - gpio pin to enable/disable the device. + - supply - "vled" - LED supply + +Example: + +leds: leds@6 { + compatible = "ti,lp8860"; + reg = <0x2d>; + label = "display_cluster"; + enable-gpio = <&gpio1 28 GPIO_ACTIVE_HIGH>; + vled-supply = <&vbatt>; +} + +For more product information please see the link below: +http://www.ti.com/product/lp8860-q1 diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index a210338cfeb1..b0dce59f23e8 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -250,6 +250,16 @@ config LEDS_LP8788 help This option enables support for the Keyboard LEDs on the LP8788 PMIC. +config LEDS_LP8860 + tristate "LED support for the TI LP8860 4 channel LED driver" + depends on LEDS_CLASS && REGMAP_I2C + help + If you say yes here you get support for the TI LP8860 4 channel + LED driver. + This option enables support for the display cluster LEDs + on the LP8860 4 channel LED driver using the I2C communication + bus. + config LEDS_CLEVO_MAIL tristate "Mail LED on Clevo notebook" depends on LEDS_CLASS diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index a2b164741465..1c65a191d907 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_LEDS_LP5523) += leds-lp5523.o obj-$(CONFIG_LEDS_LP5562) += leds-lp5562.o obj-$(CONFIG_LEDS_LP8501) += leds-lp8501.o obj-$(CONFIG_LEDS_LP8788) += leds-lp8788.o +obj-$(CONFIG_LEDS_LP8860) += leds-lp8860.o obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o obj-$(CONFIG_LEDS_CLEVO_MAIL) += leds-clevo-mail.o obj-$(CONFIG_LEDS_IPAQ_MICRO) += leds-ipaq-micro.o diff --git a/drivers/leds/leds-lp8860.c b/drivers/leds/leds-lp8860.c new file mode 100644 index 000000000000..840e93f3ab3e --- /dev/null +++ b/drivers/leds/leds-lp8860.c @@ -0,0 +1,491 @@ +/* + * TI LP8860 4-Channel LED Driver + * + * Copyright (C) 2014 Texas Instruments + * + * Author: Dan Murphy + * + * 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 LP8860_DISP_CL1_BRT_MSB 0x00 +#define LP8860_DISP_CL1_BRT_LSB 0x01 +#define LP8860_DISP_CL1_CURR_MSB 0x02 +#define LP8860_DISP_CL1_CURR_LSB 0x03 +#define LP8860_CL2_BRT_MSB 0x04 +#define LP8860_CL2_BRT_LSB 0x05 +#define LP8860_CL2_CURRENT 0x06 +#define LP8860_CL3_BRT_MSB 0x07 +#define LP8860_CL3_BRT_LSB 0x08 +#define LP8860_CL3_CURRENT 0x09 +#define LP8860_CL4_BRT_MSB 0x0a +#define LP8860_CL4_BRT_LSB 0x0b +#define LP8860_CL4_CURRENT 0x0c +#define LP8860_CONFIG 0x0d +#define LP8860_STATUS 0x0e +#define LP8860_FAULT 0x0f +#define LP8860_LED_FAULT 0x10 +#define LP8860_FAULT_CLEAR 0x11 +#define LP8860_ID 0x12 +#define LP8860_TEMP_MSB 0x13 +#define LP8860_TEMP_LSB 0x14 +#define LP8860_DISP_LED_CURR_MSB 0x15 +#define LP8860_DISP_LED_CURR_LSB 0x16 +#define LP8860_DISP_LED_PWM_MSB 0x17 +#define LP8860_DISP_LED_PWM_LSB 0x18 +#define LP8860_EEPROM_CNTRL 0x19 +#define LP8860_EEPROM_UNLOCK 0x1a + +#define LP8860_EEPROM_REG_0 0x60 +#define LP8860_EEPROM_REG_1 0x61 +#define LP8860_EEPROM_REG_2 0x62 +#define LP8860_EEPROM_REG_3 0x63 +#define LP8860_EEPROM_REG_4 0x64 +#define LP8860_EEPROM_REG_5 0x65 +#define LP8860_EEPROM_REG_6 0x66 +#define LP8860_EEPROM_REG_7 0x67 +#define LP8860_EEPROM_REG_8 0x68 +#define LP8860_EEPROM_REG_9 0x69 +#define LP8860_EEPROM_REG_10 0x6a +#define LP8860_EEPROM_REG_11 0x6b +#define LP8860_EEPROM_REG_12 0x6c +#define LP8860_EEPROM_REG_13 0x6d +#define LP8860_EEPROM_REG_14 0x6e +#define LP8860_EEPROM_REG_15 0x6f +#define LP8860_EEPROM_REG_16 0x70 +#define LP8860_EEPROM_REG_17 0x71 +#define LP8860_EEPROM_REG_18 0x72 +#define LP8860_EEPROM_REG_19 0x73 +#define LP8860_EEPROM_REG_20 0x74 +#define LP8860_EEPROM_REG_21 0x75 +#define LP8860_EEPROM_REG_22 0x76 +#define LP8860_EEPROM_REG_23 0x77 +#define LP8860_EEPROM_REG_24 0x78 + +#define LP8860_LOCK_EEPROM 0x00 +#define LP8860_UNLOCK_EEPROM 0x01 +#define LP8860_PROGRAM_EEPROM 0x02 +#define LP8860_EEPROM_CODE_1 0x08 +#define LP8860_EEPROM_CODE_2 0xba +#define LP8860_EEPROM_CODE_3 0xef + +#define LP8860_CLEAR_FAULTS 0x01 + +#define LP8860_DISP_LED_NAME "display_cluster" + +/** + * struct lp8860_led - + * @lock - Lock for reading/writing the device + * @work - Work item used to off load the brightness register writes + * @client - Pointer to the I2C client + * @led_dev - led class device pointer + * @regmap - Devices register map + * @eeprom_regmap - EEPROM register map + * @enable_gpio - VDDIO/EN gpio to enable communication interface + * @regulator - LED supply regulator pointer + * @brightness - Current brightness value requested + * @label - LED label +**/ +struct lp8860_led { + struct mutex lock; + struct work_struct work; + struct i2c_client *client; + struct led_classdev led_dev; + struct regmap *regmap; + struct regmap *eeprom_regmap; + struct gpio_desc *enable_gpio; + struct regulator *regulator; + enum led_brightness brightness; + const char *label; +}; + +struct lp8860_eeprom_reg { + uint8_t reg; + uint8_t value; +}; + +static struct lp8860_eeprom_reg lp8860_eeprom_disp_regs[] = { + { LP8860_EEPROM_REG_0, 0xed }, + { LP8860_EEPROM_REG_1, 0xdf }, + { LP8860_EEPROM_REG_2, 0xdc }, + { LP8860_EEPROM_REG_3, 0xf0 }, + { LP8860_EEPROM_REG_4, 0xdf }, + { LP8860_EEPROM_REG_5, 0xe5 }, + { LP8860_EEPROM_REG_6, 0xf2 }, + { LP8860_EEPROM_REG_7, 0x77 }, + { LP8860_EEPROM_REG_8, 0x77 }, + { LP8860_EEPROM_REG_9, 0x71 }, + { LP8860_EEPROM_REG_10, 0x3f }, + { LP8860_EEPROM_REG_11, 0xb7 }, + { LP8860_EEPROM_REG_12, 0x17 }, + { LP8860_EEPROM_REG_13, 0xef }, + { LP8860_EEPROM_REG_14, 0xb0 }, + { LP8860_EEPROM_REG_15, 0x87 }, + { LP8860_EEPROM_REG_16, 0xce }, + { LP8860_EEPROM_REG_17, 0x72 }, + { LP8860_EEPROM_REG_18, 0xe5 }, + { LP8860_EEPROM_REG_19, 0xdf }, + { LP8860_EEPROM_REG_20, 0x35 }, + { LP8860_EEPROM_REG_21, 0x06 }, + { LP8860_EEPROM_REG_22, 0xdc }, + { LP8860_EEPROM_REG_23, 0x88 }, + { LP8860_EEPROM_REG_24, 0x3E }, +}; + +static int lp8860_unlock_eeprom(struct lp8860_led *led, int lock) +{ + int ret; + + mutex_lock(&led->lock); + + if (lock == LP8860_UNLOCK_EEPROM) { + ret = regmap_write(led->regmap, + LP8860_EEPROM_UNLOCK, + LP8860_EEPROM_CODE_1); + if (ret) { + dev_err(&led->client->dev, "EEPROM Unlock failed\n"); + goto out; + } + + ret = regmap_write(led->regmap, + LP8860_EEPROM_UNLOCK, + LP8860_EEPROM_CODE_2); + if (ret) { + dev_err(&led->client->dev, "EEPROM Unlock failed\n"); + goto out; + } + ret = regmap_write(led->regmap, + LP8860_EEPROM_UNLOCK, + LP8860_EEPROM_CODE_3); + if (ret) { + dev_err(&led->client->dev, "EEPROM Unlock failed\n"); + goto out; + } + } else { + ret = regmap_write(led->regmap, + LP8860_EEPROM_UNLOCK, + LP8860_LOCK_EEPROM); + } + +out: + mutex_unlock(&led->lock); + return ret; +} + +static int lp8860_fault_check(struct lp8860_led *led) +{ + int ret, fault; + unsigned int read_buf; + + ret = regmap_read(led->regmap, LP8860_LED_FAULT, &read_buf); + if (ret) + goto out; + + fault = read_buf; + + ret = regmap_read(led->regmap, LP8860_FAULT, &read_buf); + if (ret) + goto out; + + fault |= read_buf; + + /* Attempt to clear any faults */ + if (fault) + ret = regmap_write(led->regmap, LP8860_FAULT_CLEAR, + LP8860_CLEAR_FAULTS); +out: + return ret; +} + +static void lp8860_led_brightness_work(struct work_struct *work) +{ + struct lp8860_led *led = container_of(work, struct lp8860_led, work); + int ret; + int disp_brightness = led->brightness * 255; + + mutex_lock(&led->lock); + + ret = lp8860_fault_check(led); + if (ret) { + dev_err(&led->client->dev, "Cannot read/clear faults\n"); + goto out; + } + + ret = regmap_write(led->regmap, LP8860_DISP_CL1_BRT_MSB, + (disp_brightness & 0xff00) >> 8); + if (ret) { + dev_err(&led->client->dev, "Cannot write CL1 MSB\n"); + goto out; + } + + ret = regmap_write(led->regmap, LP8860_DISP_CL1_BRT_LSB, + disp_brightness & 0xff); + if (ret) { + dev_err(&led->client->dev, "Cannot write CL1 LSB\n"); + goto out; + } +out: + mutex_unlock(&led->lock); +} + +static void lp8860_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brt_val) +{ + struct lp8860_led *led = + container_of(led_cdev, struct lp8860_led, led_dev); + + led->brightness = brt_val; + schedule_work(&led->work); +} + +static int lp8860_init(struct lp8860_led *led) +{ + unsigned int read_buf; + int ret, i, reg_count; + + if (led->enable_gpio) + gpiod_direction_output(led->enable_gpio, 1); + + ret = lp8860_fault_check(led); + if (ret) + goto out; + + ret = regmap_read(led->regmap, LP8860_STATUS, &read_buf); + if (ret) + goto out; + + ret = lp8860_unlock_eeprom(led, LP8860_UNLOCK_EEPROM); + if (ret) { + dev_err(&led->client->dev, "Failed unlocking EEPROM\n"); + goto out; + } + + reg_count = ARRAY_SIZE(lp8860_eeprom_disp_regs) / sizeof(lp8860_eeprom_disp_regs[0]); + for (i = 0; i < reg_count; i++) { + ret = regmap_write(led->eeprom_regmap, + lp8860_eeprom_disp_regs[i].reg, + lp8860_eeprom_disp_regs[i].value); + if (ret) { + dev_err(&led->client->dev, "Failed writing EEPROM\n"); + goto out; + } + } + + ret = lp8860_unlock_eeprom(led, LP8860_LOCK_EEPROM); + if (ret) + goto out; + + ret = regmap_write(led->regmap, + LP8860_EEPROM_CNTRL, + LP8860_PROGRAM_EEPROM); + if (ret) + dev_err(&led->client->dev, "Failed programming EEPROM\n"); +out: + if (ret) + if (led->enable_gpio) + gpiod_direction_output(led->enable_gpio, 0); + return ret; +} + +static struct reg_default lp8860_reg_defs[] = { + { LP8860_DISP_CL1_BRT_MSB, 0x00}, + { LP8860_DISP_CL1_BRT_LSB, 0x00}, + { LP8860_DISP_CL1_CURR_MSB, 0x00}, + { LP8860_DISP_CL1_CURR_LSB, 0x00}, + { LP8860_CL2_BRT_MSB, 0x00}, + { LP8860_CL2_BRT_LSB, 0x00}, + { LP8860_CL2_CURRENT, 0x00}, + { LP8860_CL3_BRT_MSB, 0x00}, + { LP8860_CL3_BRT_LSB, 0x00}, + { LP8860_CL3_CURRENT, 0x00}, + { LP8860_CL4_BRT_MSB, 0x00}, + { LP8860_CL4_BRT_LSB, 0x00}, + { LP8860_CL4_CURRENT, 0x00}, + { LP8860_CONFIG, 0x00}, + { LP8860_FAULT_CLEAR, 0x00}, + { LP8860_EEPROM_CNTRL, 0x80}, + { LP8860_EEPROM_UNLOCK, 0x00}, +}; + +static const struct regmap_config lp8860_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = LP8860_EEPROM_UNLOCK, + .reg_defaults = lp8860_reg_defs, + .num_reg_defaults = ARRAY_SIZE(lp8860_reg_defs), + .cache_type = REGCACHE_NONE, +}; + +static struct reg_default lp8860_eeprom_defs[] = { + { LP8860_EEPROM_REG_0, 0x00 }, + { LP8860_EEPROM_REG_1, 0x00 }, + { LP8860_EEPROM_REG_2, 0x00 }, + { LP8860_EEPROM_REG_3, 0x00 }, + { LP8860_EEPROM_REG_4, 0x00 }, + { LP8860_EEPROM_REG_5, 0x00 }, + { LP8860_EEPROM_REG_6, 0x00 }, + { LP8860_EEPROM_REG_7, 0x00 }, + { LP8860_EEPROM_REG_8, 0x00 }, + { LP8860_EEPROM_REG_9, 0x00 }, + { LP8860_EEPROM_REG_10, 0x00 }, + { LP8860_EEPROM_REG_11, 0x00 }, + { LP8860_EEPROM_REG_12, 0x00 }, + { LP8860_EEPROM_REG_13, 0x00 }, + { LP8860_EEPROM_REG_14, 0x00 }, + { LP8860_EEPROM_REG_15, 0x00 }, + { LP8860_EEPROM_REG_16, 0x00 }, + { LP8860_EEPROM_REG_17, 0x00 }, + { LP8860_EEPROM_REG_18, 0x00 }, + { LP8860_EEPROM_REG_19, 0x00 }, + { LP8860_EEPROM_REG_20, 0x00 }, + { LP8860_EEPROM_REG_21, 0x00 }, + { LP8860_EEPROM_REG_22, 0x00 }, + { LP8860_EEPROM_REG_23, 0x00 }, + { LP8860_EEPROM_REG_24, 0x00 }, +}; + +static const struct regmap_config lp8860_eeprom_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = LP8860_EEPROM_REG_24, + .reg_defaults = lp8860_eeprom_defs, + .num_reg_defaults = ARRAY_SIZE(lp8860_eeprom_defs), + .cache_type = REGCACHE_NONE, +}; + +static int lp8860_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret; + struct lp8860_led *led; + struct device_node *np = client->dev.of_node; + + led = devm_kzalloc(&client->dev, sizeof(*led), GFP_KERNEL); + if (!led) + return -ENOMEM; + + led->label = LP8860_DISP_LED_NAME; + + if (client->dev.of_node) { + ret = of_property_read_string(np, "label", &led->label); + if (ret) { + dev_err(&client->dev, "Missing label in dt\n"); + return -EINVAL; + } + } + + led->enable_gpio = devm_gpiod_get(&client->dev, "enable"); + if (IS_ERR(led->enable_gpio)) + led->enable_gpio = NULL; + else + gpiod_direction_output(led->enable_gpio, 0); + + led->regulator = devm_regulator_get(&client->dev, "vled"); + if (IS_ERR(led->regulator)) + led->regulator = NULL; + + led->client = client; + led->led_dev.name = led->label; + led->led_dev.max_brightness = LED_FULL; + led->led_dev.brightness_set = lp8860_brightness_set; + + mutex_init(&led->lock); + INIT_WORK(&led->work, lp8860_led_brightness_work); + + i2c_set_clientdata(client, led); + + led->regmap = devm_regmap_init_i2c(client, &lp8860_regmap_config); + if (IS_ERR(led->regmap)) { + ret = PTR_ERR(led->regmap); + dev_err(&client->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + led->eeprom_regmap = devm_regmap_init_i2c(client, &lp8860_eeprom_regmap_config); + if (IS_ERR(led->eeprom_regmap)) { + ret = PTR_ERR(led->eeprom_regmap); + dev_err(&client->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + ret = lp8860_init(led); + if (ret) + return ret; + + ret = led_classdev_register(&client->dev, &led->led_dev); + if (ret) { + dev_err(&client->dev, "led register err: %d\n", ret); + return ret; + } + + return 0; +} + +static int lp8860_remove(struct i2c_client *client) +{ + struct lp8860_led *led = i2c_get_clientdata(client); + int ret; + + led_classdev_unregister(&led->led_dev); + cancel_work_sync(&led->work); + + if (led->enable_gpio) + gpiod_direction_output(led->enable_gpio, 0); + + if (led->regulator) { + ret = regulator_disable(led->regulator); + if (ret) + dev_err(&led->client->dev, + "Failed to disable regulator\n"); + } + + return 0; +} + +static const struct i2c_device_id lp8860_id[] = { + { "lp8860", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, lp8860_id); + +#ifdef CONFIG_OF +static const struct of_device_id of_lp8860_leds_match[] = { + { .compatible = "ti,lp8860", }, + {}, +}; +MODULE_DEVICE_TABLE(of, of_lp8860_leds_match); +#endif + +static struct i2c_driver lp8860_driver = { + .driver = { + .name = "lp8860", + .of_match_table = of_match_ptr(of_lp8860_leds_match), + }, + .probe = lp8860_probe, + .remove = lp8860_remove, + .id_table = lp8860_id, +}; +module_i2c_driver(lp8860_driver); + +MODULE_DESCRIPTION("Texas Instruments LP8860 LED drvier"); +MODULE_AUTHOR("Dan Murphy "); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-59-g8ed1b From 29a77b8a04e794c6c34d45ea10a300b117a68e08 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 10 Nov 2014 19:49:34 +0100 Subject: clk: shmobile: Deprecate renesas,clock-indices Commit 8e33f91a0b84ae19 ("clk: shmobile: clk-mstp: change to using clock-indices") forgot to replace all occurrences of "renesas,clock-indices" in the driver-specific binding documentation. Signed-off-by: Geert Uytterhoeven Acked-by: Simon Horman Acked-by: Kuninori Morimoto Acked-by: Laurent Pinchart Signed-off-by: Michael Turquette --- .../devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt b/Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt index a5f52238c80d..2e18676bd4b5 100644 --- a/Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt +++ b/Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt @@ -26,11 +26,11 @@ Required Properties: must appear in the same order as the output clocks. - #clock-cells: Must be 1 - clock-output-names: The name of the clocks as free-form strings - - renesas,clock-indices: Indices of the gate clocks into the group (0 to 31) + - clock-indices: Indices of the gate clocks into the group (0 to 31) -The clocks, clock-output-names and renesas,clock-indices properties contain one -entry per gate clock. The MSTP groups are sparsely populated. Unimplemented -gate clocks must not be declared. +The clocks, clock-output-names and clock-indices properties contain one entry +per gate clock. The MSTP groups are sparsely populated. Unimplemented gate +clocks must not be declared. Example -- cgit v1.2.3-59-g8ed1b From 233b36cf1f83ef4a7b3670ffa5eeac1ed9d41889 Mon Sep 17 00:00:00 2001 From: Giuseppe CAVALLARO Date: Tue, 18 Nov 2014 09:46:59 +0100 Subject: stmmac: update driver documentation Recently many changes have been done inside the driver so this patch updates the driver's doc for example reviewing information for the rx and tx processes that are managed by napi method, adding new information for missing glue-logic files etc. Signed-off-by: Giuseppe Cavallaro Signed-off-by: David S. Miller --- Documentation/networking/stmmac.txt | 132 ++++++++++++++++++------------------ 1 file changed, 65 insertions(+), 67 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/stmmac.txt b/Documentation/networking/stmmac.txt index 2090895b08d4..e655e2453c98 100644 --- a/Documentation/networking/stmmac.txt +++ b/Documentation/networking/stmmac.txt @@ -1,12 +1,12 @@ STMicroelectronics 10/100/1000 Synopsys Ethernet driver -Copyright (C) 2007-2013 STMicroelectronics Ltd +Copyright (C) 2007-2014 STMicroelectronics Ltd Author: Giuseppe Cavallaro This is the driver for the MAC 10/100/1000 on-chip Ethernet controllers (Synopsys IP blocks). -Currently this network device driver is for all STM embedded MAC/GMAC +Currently this network device driver is for all STi embedded MAC/GMAC (i.e. 7xxx/5xxx SoCs), SPEAr (arm), Loongson1B (mips) and XLINX XC2V3000 FF1152AMT0221 D1215994A VIRTEX FPGA board. @@ -22,6 +22,9 @@ The kernel configuration option is STMMAC_ETH: Device Drivers ---> Network device support ---> Ethernet (1000 Mbit) ---> STMicroelectronics 10/100/1000 Ethernet driver (STMMAC_ETH) +CONFIG_STMMAC_PLATFORM: is to enable the platform driver. +CONFIG_STMMAC_PCI: is to enable the pci driver. + 2) Driver parameters list: debug: message level (0: no output, 16: all); phyaddr: to manually provide the physical address to the PHY device; @@ -45,10 +48,11 @@ Driver parameters can be also passed in command line by using: The xmit method is invoked when the kernel needs to transmit a packet; it sets the descriptors in the ring and informs the DMA engine that there is a packet ready to be transmitted. -Once the controller has finished transmitting the packet, an interrupt is -triggered; So the driver will be able to release the socket buffers. By default, the driver sets the NETIF_F_SG bit in the features field of the -net_device structure enabling the scatter/gather feature. +net_device structure enabling the scatter-gather feature. This is true on +chips and configurations where the checksum can be done in hardware. +Once the controller has finished transmitting the packet, napi will be +scheduled to release the transmit resources. 4.2) Receive process When one or more packets are received, an interrupt happens. The interrupts @@ -58,20 +62,12 @@ This is based on NAPI so the interrupt handler signals only if there is work to be done, and it exits. Then the poll method will be scheduled at some future point. The incoming packets are stored, by the DMA, in a list of pre-allocated socket -buffers in order to avoid the memcpy (Zero-copy). +buffers in order to avoid the memcpy (zero-copy). 4.3) Interrupt Mitigation The driver is able to mitigate the number of its DMA interrupts using NAPI for the reception on chips older than the 3.50. New chips have an HW RX-Watchdog used for this mitigation. - -On Tx-side, the mitigation schema is based on a SW timer that calls the -tx function (stmmac_tx) to reclaim the resource after transmitting the -frames. -Also there is another parameter (like a threshold) used to program -the descriptors avoiding to set the interrupt on completion bit in -when the frame is sent (xmit). - Mitigation parameters can be tuned by ethtool. 4.4) WOL @@ -79,7 +75,7 @@ Wake up on Lan feature through Magic and Unicast frames are supported for the GMAC core. 4.5) DMA descriptors -Driver handles both normal and enhanced descriptors. The latter has been only +Driver handles both normal and alternate descriptors. The latter has been only tested on DWC Ether MAC 10/100/1000 Universal version 3.41a and later. STMMAC supports DMA descriptor to operate both in dual buffer (RING) @@ -91,9 +87,20 @@ In CHAINED mode each descriptor will have pointer to next descriptor in the list, hence creating the explicit chaining in the descriptor itself, whereas such explicit chaining is not possible in RING mode. +4.5.1) Extended descriptors + The extended descriptors give us information about the Ethernet payload + when it is carrying PTP packets or TCP/UDP/ICMP over IP. + These are not available on GMAC Synopsys chips older than the 3.50. + At probe time the driver will decide if these can be actually used. + This support also is mandatory for PTPv2 because the extra descriptors + are used for saving the hardware timestamps and Extended Status. + 4.6) Ethtool support -Ethtool is supported. Driver statistics and internal errors can be taken using: -ethtool -S ethX command. It is possible to dump registers etc. +Ethtool is supported. + +For example, driver statistics (including RMON), internal errors can be taken +using: + # ethtool -S ethX command 4.7) Jumbo and Segmentation Offloading Jumbo frames are supported and tested for the GMAC. @@ -101,12 +108,11 @@ The GSO has been also added but it's performed in software. LRO is not supported. 4.8) Physical -The driver is compatible with PAL to work with PHY and GPHY devices. +The driver is compatible with Physical Abstraction Layer to be connected with +PHY and GPHY devices. 4.9) Platform information -Several driver's information can be passed through the platform -These are included in the include/linux/stmmac.h header file -and detailed below as well: +Several information can be passed through the platform and device-tree. struct plat_stmmacenet_data { char *phy_bus_name; @@ -125,15 +131,18 @@ struct plat_stmmacenet_data { int force_sf_dma_mode; int force_thresh_dma_mode; int riwt_off; + int max_speed; + int maxmtu; void (*fix_mac_speed)(void *priv, unsigned int speed); void (*bus_setup)(void __iomem *ioaddr); void *(*setup)(struct platform_device *pdev); + void (*free)(struct platform_device *pdev, void *priv); int (*init)(struct platform_device *pdev, void *priv); void (*exit)(struct platform_device *pdev, void *priv); void *custom_cfg; void *custom_data; void *bsp_priv; - }; +}; Where: o phy_bus_name: phy bus name to attach to the stmmac. @@ -258,32 +267,43 @@ and the second one, with a real PHY device attached to the bus, by using the stmmac_mdio_bus_data structure (to provide the id, the reset procedure etc). -4.10) List of source files: - o Kconfig - o Makefile - o stmmac_main.c: main network device driver; - o stmmac_mdio.c: mdio functions; - o stmmac_pci: PCI driver; - o stmmac_platform.c: platform driver - o stmmac_ethtool.c: ethtool support; - o stmmac_timer.[ch]: timer code used for mitigating the driver dma interrupts - (only tested on ST40 platforms based); +Note that, starting from new chips, where it is available the HW capability +register, many configurations are discovered at run-time for example to +understand if EEE, HW csum, PTP, enhanced descriptor etc are actually +available. As strategy adopted in this driver, the information from the HW +capability register can replace what has been passed from the platform. + +4.10) Device-tree support. + +Please see the following document: + Documentation/devicetree/bindings/net/stmmac.txt + +and the stmmac_of_data structure inside the include/linux/stmmac.h header file. + +4.11) This is a summary of the content of some relevant files: + o stmmac_main.c: to implement the main network device driver; + o stmmac_mdio.c: to provide mdio functions; + o stmmac_pci: this the PCI driver; + o stmmac_platform.c: this the platform driver (OF supported) + o stmmac_ethtool.c: to implement the ethtool support; o stmmac.h: private driver structure; o common.h: common definitions and VFTs; o descs.h: descriptor structure definitions; - o dwmac1000_core.c: GMAC core functions; - o dwmac1000_dma.c: dma functions for the GMAC chip; - o dwmac1000.h: specific header file for the GMAC; - o dwmac100_core: MAC 100 core and dma code; - o dwmac100_dma.c: dma functions for the MAC chip; + o dwmac1000_core.c: dwmac GiGa core functions; + o dwmac1000_dma.c: dma functions for the GMAC chip; + o dwmac1000.h: specific header file for the dwmac GiGa; + o dwmac100_core: dwmac 100 core code; + o dwmac100_dma.c: dma functions for the dwmac 100 chip; o dwmac1000.h: specific header file for the MAC; - o dwmac_lib.c: generic DMA functions shared among chips; + o dwmac_lib.c: generic DMA functions; o enh_desc.c: functions for handling enhanced descriptors; o norm_desc.c: functions for handling normal descriptors; o chain_mode.c/ring_mode.c:: functions to manage RING/CHAINED modes; o mmc_core.c/mmc.h: Management MAC Counters; - o stmmac_hwtstamp.c: HW timestamp support for PTP - o stmmac_ptp.c: PTP 1588 clock + o stmmac_hwtstamp.c: HW timestamp support for PTP; + o stmmac_ptp.c: PTP 1588 clock; + o dwmac-.c: these are for the platform glue-logic file; e.g. dwmac-sti.c + for STMicroelectronics SoCs. 5) Debug Information @@ -298,23 +318,14 @@ to get statistics: e.g. using: ethtool -S ethX (that shows the Management counters (MMC) if supported) or sees the MAC/DMA registers: e.g. using: ethtool -d ethX -Compiling the Kernel with CONFIG_DEBUG_FS and enabling the -STMMAC_DEBUG_FS option the driver will export the following +Compiling the Kernel with CONFIG_DEBUG_FS the driver will export the following debugfs entries: /sys/kernel/debug/stmmaceth/descriptors_status To show the DMA TX/RX descriptor rings -Developer can also use the "debug" module parameter to get -further debug information. - -In the end, there are other macros (that cannot be enabled -via menuconfig) to turn-on the RX/TX DMA debugging, -specific MAC core debug printk etc. Others to enable the -debug in the TX and RX processes. -All these are only useful during the developing stage -and should never enabled inside the code for general usage. -In fact, these can generate an huge amount of debug messages. +Developer can also use the "debug" module parameter to get further debug +information (please see: NETIF Msg Level). 6) Energy Efficient Ethernet @@ -337,15 +348,7 @@ To enter in Tx LPI mode the driver needs to have a software timer that enable and disable the LPI mode when there is nothing to be transmitted. -7) Extended descriptors -The extended descriptors give us information about the receive Ethernet payload -when it is carrying PTP packets or TCP/UDP/ICMP over IP. -These are not available on GMAC Synopsys chips older than the 3.50. -At probe time the driver will decide if these can be actually used. -This support also is mandatory for PTPv2 because the extra descriptors 6 and 7 -are used for saving the hardware timestamps. - -8) Precision Time Protocol (PTP) +7) Precision Time Protocol (PTP) The driver supports the IEEE 1588-2002, Precision Time Protocol (PTP), which enables precise synchronization of clocks in measurement and control systems implemented with technologies such as network @@ -355,7 +358,7 @@ In addition to the basic timestamp features mentioned in IEEE 1588-2002 Timestamps, new GMAC cores support the advanced timestamp features. IEEE 1588-2008 that can be enabled when configure the Kernel. -9) SGMII/RGMII supports +8) SGMII/RGMII supports New GMAC devices provide own way to manage RGMII/SGMII. This information is available at run-time by looking at the HW capability register. This means that the stmmac can manage @@ -364,8 +367,3 @@ In fact, the HW provides a subset of extended registers to restart the ANE, verify Full/Half duplex mode and Speed. Also thanks to these registers it is possible to look at the Auto-negotiated Link Parter Ability. - -10) TODO: - o XGMAC is not supported. - o Complete the TBI & RTBI support. - o extend VLAN support for 3.70a SYNP GMAC. -- cgit v1.2.3-59-g8ed1b From c32a42721ce67594e4481a961aa149055de9c1d9 Mon Sep 17 00:00:00 2001 From: Tiejun Chen Date: Thu, 20 Nov 2014 11:07:18 +0100 Subject: kvm: Documentation: remove ia64 kvm/ia64 is gone, clean up Documentation too. Signed-off-by: Paolo Bonzini --- Documentation/ia64/kvm.txt | 83 --------------------------------------- Documentation/virtual/kvm/api.txt | 45 +++++++++++---------- 2 files changed, 22 insertions(+), 106 deletions(-) delete mode 100644 Documentation/ia64/kvm.txt (limited to 'Documentation') diff --git a/Documentation/ia64/kvm.txt b/Documentation/ia64/kvm.txt deleted file mode 100644 index ffb5c80bec3e..000000000000 --- a/Documentation/ia64/kvm.txt +++ /dev/null @@ -1,83 +0,0 @@ -Currently, kvm module is in EXPERIMENTAL stage on IA64. This means that -interfaces are not stable enough to use. So, please don't run critical -applications in virtual machine. -We will try our best to improve it in future versions! - - Guide: How to boot up guests on kvm/ia64 - -This guide is to describe how to enable kvm support for IA-64 systems. - -1. Get the kvm source from git.kernel.org. - Userspace source: - git clone git://git.kernel.org/pub/scm/virt/kvm/kvm-userspace.git - Kernel Source: - git clone git://git.kernel.org/pub/scm/linux/kernel/git/xiantao/kvm-ia64.git - -2. Compile the source code. - 2.1 Compile userspace code: - (1)cd ./kvm-userspace - (2)./configure - (3)cd kernel - (4)make sync LINUX= $kernel_dir (kernel_dir is the directory of kernel source.) - (5)cd .. - (6)make qemu - (7)cd qemu; make install - - 2.2 Compile kernel source code: - (1) cd ./$kernel_dir - (2) Make menuconfig - (3) Enter into virtualization option, and choose kvm. - (4) make - (5) Once (4) done, make modules_install - (6) Make initrd, and use new kernel to reboot up host machine. - (7) Once (6) done, cd $kernel_dir/arch/ia64/kvm - (8) insmod kvm.ko; insmod kvm-intel.ko - -Note: For step 2, please make sure that host page size == TARGET_PAGE_SIZE of qemu, otherwise, may fail. - -3. Get Guest Firmware named as Flash.fd, and put it under right place: - (1) If you have the guest firmware (binary) released by Intel Corp for Xen, use it directly. - - (2) If you have no firmware at hand, Please download its source from - hg clone http://xenbits.xensource.com/ext/efi-vfirmware.hg - you can get the firmware's binary in the directory of efi-vfirmware.hg/binaries. - - (3) Rename the firmware you owned to Flash.fd, and copy it to /usr/local/share/qemu - -4. Boot up Linux or Windows guests: - 4.1 Create or install a image for guest boot. If you have xen experience, it should be easy. - - 4.2 Boot up guests use the following command. - /usr/local/bin/qemu-system-ia64 -smp xx -m 512 -hda $your_image - (xx is the number of virtual processors for the guest, now the maximum value is 4) - -5. Known possible issue on some platforms with old Firmware. - -In the event of strange host crash issues, try to solve it through either of the following ways: - -(1): Upgrade your Firmware to the latest one. - -(2): Applying the below patch to kernel source. -diff --git a/arch/ia64/kernel/pal.S b/arch/ia64/kernel/pal.S -index 0b53344..f02b0f7 100644 ---- a/arch/ia64/kernel/pal.S -+++ b/arch/ia64/kernel/pal.S -@@ -84,7 +84,8 @@ GLOBAL_ENTRY(ia64_pal_call_static) - mov ar.pfs = loc1 - mov rp = loc0 - ;; -- srlz.d // serialize restoration of psr.l -+ srlz.i // serialize restoration of psr.l -+ ;; - br.ret.sptk.many b0 - END(ia64_pal_call_static) - -6. Bug report: - If you found any issues when use kvm/ia64, Please post the bug info to kvm-ia64-devel mailing list. - https://lists.sourceforge.net/lists/listinfo/kvm-ia64-devel/ - -Thanks for your interest! Let's work together, and make kvm/ia64 stronger and stronger! - - - Xiantao Zhang - 2008.3.10 diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 7a943c23db1c..80bfe59fc992 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -607,7 +607,7 @@ struct kvm_fpu { 4.24 KVM_CREATE_IRQCHIP Capability: KVM_CAP_IRQCHIP, KVM_CAP_S390_IRQCHIP (s390) -Architectures: x86, ia64, ARM, arm64, s390 +Architectures: x86, ARM, arm64, s390 Type: vm ioctl Parameters: none Returns: 0 on success, -1 on error @@ -615,7 +615,7 @@ Returns: 0 on success, -1 on error Creates an interrupt controller model in the kernel. On x86, creates a virtual ioapic, a virtual PIC (two PICs, nested), and sets up future vcpus to have a local APIC. IRQ routing for GSIs 0-15 is set to both PIC and IOAPIC; GSI 16-23 -only go to the IOAPIC. On ia64, a IOSAPIC is created. On ARM/arm64, a GIC is +only go to the IOAPIC. On ARM/arm64, a GIC is created. On s390, a dummy irq routing table is created. Note that on s390 the KVM_CAP_S390_IRQCHIP vm capability needs to be enabled @@ -625,7 +625,7 @@ before KVM_CREATE_IRQCHIP can be used. 4.25 KVM_IRQ_LINE Capability: KVM_CAP_IRQCHIP -Architectures: x86, ia64, arm, arm64 +Architectures: x86, arm, arm64 Type: vm ioctl Parameters: struct kvm_irq_level Returns: 0 on success, -1 on error @@ -679,7 +679,7 @@ struct kvm_irq_level { 4.26 KVM_GET_IRQCHIP Capability: KVM_CAP_IRQCHIP -Architectures: x86, ia64 +Architectures: x86 Type: vm ioctl Parameters: struct kvm_irqchip (in/out) Returns: 0 on success, -1 on error @@ -701,7 +701,7 @@ struct kvm_irqchip { 4.27 KVM_SET_IRQCHIP Capability: KVM_CAP_IRQCHIP -Architectures: x86, ia64 +Architectures: x86 Type: vm ioctl Parameters: struct kvm_irqchip (in) Returns: 0 on success, -1 on error @@ -994,7 +994,7 @@ for vm-wide capabilities. 4.38 KVM_GET_MP_STATE Capability: KVM_CAP_MP_STATE -Architectures: x86, ia64, s390 +Architectures: x86, s390 Type: vcpu ioctl Parameters: struct kvm_mp_state (out) Returns: 0 on success; -1 on error @@ -1008,16 +1008,15 @@ uniprocessor guests). Possible values are: - - KVM_MP_STATE_RUNNABLE: the vcpu is currently running [x86, ia64] + - KVM_MP_STATE_RUNNABLE: the vcpu is currently running [x86] - KVM_MP_STATE_UNINITIALIZED: the vcpu is an application processor (AP) - which has not yet received an INIT signal [x86, - ia64] + which has not yet received an INIT signal [x86] - KVM_MP_STATE_INIT_RECEIVED: the vcpu has received an INIT signal, and is - now ready for a SIPI [x86, ia64] + now ready for a SIPI [x86] - KVM_MP_STATE_HALTED: the vcpu has executed a HLT instruction and - is waiting for an interrupt [x86, ia64] + 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, ia64] + accessible via KVM_GET_VCPU_EVENTS) [x86] - KVM_MP_STATE_STOPPED: the vcpu is stopped [s390] - 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) @@ -1025,7 +1024,7 @@ Possible values are: - KVM_MP_STATE_LOAD: the vcpu is in a special load/startup state [s390] -On x86 and ia64, this ioctl is only useful after KVM_CREATE_IRQCHIP. Without an +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. @@ -1033,7 +1032,7 @@ these architectures. 4.39 KVM_SET_MP_STATE Capability: KVM_CAP_MP_STATE -Architectures: x86, ia64, s390 +Architectures: x86, s390 Type: vcpu ioctl Parameters: struct kvm_mp_state (in) Returns: 0 on success; -1 on error @@ -1041,7 +1040,7 @@ Returns: 0 on success; -1 on error Sets the vcpu's current "multiprocessing state"; see KVM_GET_MP_STATE for arguments. -On x86 and ia64, this ioctl is only useful after KVM_CREATE_IRQCHIP. Without an +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. @@ -1068,7 +1067,7 @@ documentation when it pops into existence). 4.41 KVM_SET_BOOT_CPU_ID Capability: KVM_CAP_SET_BOOT_CPU_ID -Architectures: x86, ia64 +Architectures: x86 Type: vm ioctl Parameters: unsigned long vcpu_id Returns: 0 on success, -1 on error @@ -1261,7 +1260,7 @@ The flags bitmap is defined as: 4.48 KVM_ASSIGN_PCI_DEVICE Capability: none -Architectures: x86 ia64 +Architectures: x86 Type: vm ioctl Parameters: struct kvm_assigned_pci_dev (in) Returns: 0 on success, -1 on error @@ -1311,7 +1310,7 @@ Errors: 4.49 KVM_DEASSIGN_PCI_DEVICE Capability: none -Architectures: x86 ia64 +Architectures: x86 Type: vm ioctl Parameters: struct kvm_assigned_pci_dev (in) Returns: 0 on success, -1 on error @@ -1330,7 +1329,7 @@ Errors: 4.50 KVM_ASSIGN_DEV_IRQ Capability: KVM_CAP_ASSIGN_DEV_IRQ -Architectures: x86 ia64 +Architectures: x86 Type: vm ioctl Parameters: struct kvm_assigned_irq (in) Returns: 0 on success, -1 on error @@ -1370,7 +1369,7 @@ Errors: 4.51 KVM_DEASSIGN_DEV_IRQ Capability: KVM_CAP_ASSIGN_DEV_IRQ -Architectures: x86 ia64 +Architectures: x86 Type: vm ioctl Parameters: struct kvm_assigned_irq (in) Returns: 0 on success, -1 on error @@ -1385,7 +1384,7 @@ KVM_ASSIGN_DEV_IRQ. Partial deassignment of host or guest IRQ is allowed. 4.52 KVM_SET_GSI_ROUTING Capability: KVM_CAP_IRQ_ROUTING -Architectures: x86 ia64 s390 +Architectures: x86 s390 Type: vm ioctl Parameters: struct kvm_irq_routing (in) Returns: 0 on success, -1 on error @@ -1444,7 +1443,7 @@ struct kvm_irq_routing_s390_adapter { 4.53 KVM_ASSIGN_SET_MSIX_NR Capability: none -Architectures: x86 ia64 +Architectures: x86 Type: vm ioctl Parameters: struct kvm_assigned_msix_nr (in) Returns: 0 on success, -1 on error @@ -1466,7 +1465,7 @@ struct kvm_assigned_msix_nr { 4.54 KVM_ASSIGN_SET_MSIX_ENTRY Capability: none -Architectures: x86 ia64 +Architectures: x86 Type: vm ioctl Parameters: struct kvm_assigned_msix_entry (in) Returns: 0 on success, -1 on error -- cgit v1.2.3-59-g8ed1b From b2ea3f82e7984d855c5e61fef18746771d90c73c Mon Sep 17 00:00:00 2001 From: Darshana Padmadas Date: Sat, 8 Nov 2014 22:52:05 +0530 Subject: dt-bindings: Document correct and deprecated vendor-prefix with device isl29028 This patch documents the device isl29028 with its vendor-prefix. Undocumented deprecated vendor-prefix found by checkpatch also documented for compatibility reasons. Signed-off-by: Darshana Padmadas Acked-by: Arnd Bergmann Acked-by: Mark Rutland Signed-off-by: Arnd Bergmann --- Documentation/devicetree/bindings/i2c/trivial-devices.txt | 2 ++ 1 file changed, 2 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/i2c/trivial-devices.txt b/Documentation/devicetree/bindings/i2c/trivial-devices.txt index fbde415078e6..605dcca5dbec 100644 --- a/Documentation/devicetree/bindings/i2c/trivial-devices.txt +++ b/Documentation/devicetree/bindings/i2c/trivial-devices.txt @@ -56,6 +56,8 @@ gmt,g751 G751: Digital Temperature Sensor and Thermal Watchdog with Two-Wire In infineon,slb9635tt Infineon SLB9635 (Soft-) I2C TPM (old protocol, max 100khz) infineon,slb9645tt Infineon SLB9645 I2C TPM (new protocol, max 400khz) isl,isl12057 Intersil ISL12057 I2C RTC Chip +isil,isl29028 (deprecated, use isl) +isl,isl29028 Intersil ISL29028 Ambient Light and Proximity Sensor maxim,ds1050 5 Bit Programmable, Pulse-Width Modulator maxim,max1237 Low-Power, 4-/12-Channel, 2-Wire Serial, 12-Bit ADCs maxim,max6625 9-Bit/12-Bit Temperature Sensors with I²C-Compatible Serial Interface -- cgit v1.2.3-59-g8ed1b From 7c75c1d5e72be6736aa558efd33ca2b31d77e425 Mon Sep 17 00:00:00 2001 From: Darshana Padmadas Date: Sat, 8 Nov 2014 22:52:06 +0530 Subject: dt-bindings: Document deprecated device vendor name to fix related warning This patch documents deprecated vendor name "isil" to fix warning of undocumented string for device isl29028 as reported while running checkpatch.pl on drivers/staging/iio/light/isl29028.c. This is done to maintain compatibility with older kernels. Signed-off-by: Darshana Padmadas Acked-by: Arnd Bergmann Acked-by: Mark Rutland Signed-off-by: Arnd Bergmann --- 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 723999d73744..bfbd93e06bae 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -77,6 +77,7 @@ innolux Innolux Corporation intel Intel Corporation intercontrol Inter Control Group isee ISEE 2007 S.L. +isil Intersil (deprecated, use isl) isl Intersil karo Ka-Ro electronics GmbH keymile Keymile GmbH -- cgit v1.2.3-59-g8ed1b From 1281c87ff067933cdeed79c4bda18ef3052b1165 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Thu, 20 Nov 2014 10:43:24 +0100 Subject: hwrng: atmel - Add TRNG DT binding doc Document DT bindings of Atmel's TRNG (True Random Number Generator) IP. Signed-off-by: Boris Brezillon Acked-by: Peter Korsgaard Acked-by: Nicolas Ferre Signed-off-by: Herbert Xu --- Documentation/devicetree/bindings/hwrng/atmel-trng.txt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 Documentation/devicetree/bindings/hwrng/atmel-trng.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/hwrng/atmel-trng.txt b/Documentation/devicetree/bindings/hwrng/atmel-trng.txt new file mode 100644 index 000000000000..4ac5aaa2d024 --- /dev/null +++ b/Documentation/devicetree/bindings/hwrng/atmel-trng.txt @@ -0,0 +1,16 @@ +Atmel TRNG (True Random Number Generator) block + +Required properties: +- compatible : Should be "atmel,at91sam9g45-trng" +- reg : Offset and length of the register set of this block +- interrupts : the interrupt number for the TRNG block +- clocks: should contain the TRNG clk source + +Example: + +trng@fffcc000 { + compatible = "atmel,at91sam9g45-trng"; + reg = <0xfffcc000 0x4000>; + interrupts = <6 IRQ_TYPE_LEVEL_HIGH 0>; + clocks = <&trng_clk>; +}; -- cgit v1.2.3-59-g8ed1b From 0199e9938f2c0e7f5476f5983f1763d28f049837 Mon Sep 17 00:00:00 2001 From: Mikko Perttunen Date: Fri, 26 Sep 2014 12:43:10 +0300 Subject: of: Add bindings for nvidia,tegra124-soctherm This adds binding documentation and headers for the Tegra124 SOCTHERM device tree node. Signed-off-by: Mikko Perttunen Acked-by: Stephen Warren Acked-by: Eduardo Valentin Signed-off-by: Eduardo Valentin --- .../devicetree/bindings/thermal/tegra-soctherm.txt | 53 ++++++++++++++++++++++ include/dt-bindings/thermal/tegra124-soctherm.h | 13 ++++++ 2 files changed, 66 insertions(+) create mode 100644 Documentation/devicetree/bindings/thermal/tegra-soctherm.txt create mode 100644 include/dt-bindings/thermal/tegra124-soctherm.h (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/thermal/tegra-soctherm.txt b/Documentation/devicetree/bindings/thermal/tegra-soctherm.txt new file mode 100644 index 000000000000..ecf3ed76cd46 --- /dev/null +++ b/Documentation/devicetree/bindings/thermal/tegra-soctherm.txt @@ -0,0 +1,53 @@ +Tegra124 SOCTHERM thermal management system + +The SOCTHERM IP block contains thermal sensors, support for polled +or interrupt-based thermal monitoring, CPU and GPU throttling based +on temperature trip points, and handling external overcurrent +notifications. It is also used to manage emergency shutdown in an +overheating situation. + +Required properties : +- compatible : "nvidia,tegra124-soctherm". +- reg : Should contain 1 entry: + - SOCTHERM register set +- interrupts : Defines the interrupt used by SOCTHERM +- clocks : Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. +- clock-names : Must include the following entries: + - tsensor + - soctherm +- resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names : Must include the following entries: + - soctherm +- #thermal-sensor-cells : Should be 1. See ./thermal.txt for a description + of this property. See for a + list of valid values when referring to thermal sensors. + + +Example : + + soctherm@0,700e2000 { + compatible = "nvidia,tegra124-soctherm"; + reg = <0x0 0x700e2000 0x0 0x1000>; + interrupts = ; + clocks = <&tegra_car TEGRA124_CLK_TSENSOR>, + <&tegra_car TEGRA124_CLK_SOC_THERM>; + clock-names = "tsensor", "soctherm"; + resets = <&tegra_car 78>; + reset-names = "soctherm"; + + #thermal-sensor-cells = <1>; + }; + +Example: referring to thermal sensors : + + thermal-zones { + cpu { + polling-delay-passive = <1000>; + polling-delay = <1000>; + + thermal-sensors = + <&soctherm TEGRA124_SOCTHERM_SENSOR_CPU>; + }; + }; diff --git a/include/dt-bindings/thermal/tegra124-soctherm.h b/include/dt-bindings/thermal/tegra124-soctherm.h new file mode 100644 index 000000000000..85aaf66690f9 --- /dev/null +++ b/include/dt-bindings/thermal/tegra124-soctherm.h @@ -0,0 +1,13 @@ +/* + * This header provides constants for binding nvidia,tegra124-soctherm. + */ + +#ifndef _DT_BINDINGS_THERMAL_TEGRA124_SOCTHERM_H +#define _DT_BINDINGS_THERMAL_TEGRA124_SOCTHERM_H + +#define TEGRA124_SOCTHERM_SENSOR_CPU 0 +#define TEGRA124_SOCTHERM_SENSOR_MEM 1 +#define TEGRA124_SOCTHERM_SENSOR_GPU 2 +#define TEGRA124_SOCTHERM_SENSOR_PLLX 3 + +#endif -- cgit v1.2.3-59-g8ed1b From 587064b610c703f259317d00dc37bf6d40f4fc74 Mon Sep 17 00:00:00 2001 From: Punit Agrawal Date: Tue, 18 Nov 2014 11:41:24 +0000 Subject: arm64: Add framework for legacy instruction emulation Typically, providing support for legacy instructions requires emulating the behaviour of instructions whose encodings have become undefined. If the instructions haven't been removed from the architecture, there maybe an option in the implementation to turn on/off the support for these instructions. Create common infrastructure to support legacy instruction emulation. In addition to emulation, also provide an option to support hardware execution when supported. The default execution mode (one of undef, emulate, hw exeuction) is dependent on the state of the instruction (deprecated or obsolete) in the architecture and can specified at the time of registering the instruction handlers. The runtime state of the emulation can be controlled by writing to individual nodes in sysctl. The expected default behaviour is documented as part of this patch. Reviewed-by: Catalin Marinas Signed-off-by: Punit Agrawal Signed-off-by: Will Deacon --- Documentation/arm64/legacy_instructions.txt | 33 +++++ arch/arm64/Kconfig | 18 +++ arch/arm64/kernel/Makefile | 1 + arch/arm64/kernel/armv8_deprecated.c | 216 ++++++++++++++++++++++++++++ 4 files changed, 268 insertions(+) create mode 100644 Documentation/arm64/legacy_instructions.txt create mode 100644 arch/arm64/kernel/armv8_deprecated.c (limited to 'Documentation') diff --git a/Documentation/arm64/legacy_instructions.txt b/Documentation/arm64/legacy_instructions.txt new file mode 100644 index 000000000000..49d4867c0c09 --- /dev/null +++ b/Documentation/arm64/legacy_instructions.txt @@ -0,0 +1,33 @@ +The arm64 port of the Linux kernel provides infrastructure to support +emulation of instructions which have been deprecated, or obsoleted in +the architecture. The infrastructure code uses undefined instruction +hooks to support emulation. Where available it also allows turning on +the instruction execution in hardware. + +The emulation mode can be controlled by writing to sysctl nodes +(/proc/sys/abi). The following explains the different execution +behaviours and the corresponding values of the sysctl nodes - + +* Undef + Value: 0 + Generates undefined instruction abort. Default for instructions that + have been obsoleted in the architecture, e.g., SWP + +* Emulate + Value: 1 + Uses software emulation. To aid migration of software, in this mode + usage of emulated instruction is traced as well as rate limited + warnings are issued. This is the default for deprecated + instructions, .e.g., CP15 barriers + +* Hardware Execution + Value: 2 + Although marked as deprecated, some implementations may support the + enabling/disabling of hardware support for the execution of these + instructions. Using hardware execution generally provides better + performance, but at the loss of ability to gather runtime statistics + about the use of the deprecated instructions. + +The default mode depends on the status of the instruction in the +architecture. Deprecated instructions should default to emulation +while obsolete instructions must be undefined by default. diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 1e0e4671dd25..aa8f4bea3738 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -164,6 +164,24 @@ config ARCH_XGENE help This enables support for AppliedMicro X-Gene SOC Family +comment "Processor Features" + +menuconfig ARMV8_DEPRECATED + bool "Emulate deprecated/obsolete ARMv8 instructions" + depends on COMPAT + help + Legacy software support may require certain instructions + that have been deprecated or obsoleted in the architecture. + + Enable this config to enable selective emulation of these + features. + + If unsure, say Y + +if ARMV8_DEPRECATED + +endif + endmenu menu "Bus support" diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index a4d8671d6d11..84e9e5153efe 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -32,6 +32,7 @@ arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o arm64-obj-$(CONFIG_KGDB) += kgdb.o arm64-obj-$(CONFIG_EFI) += efi.o efi-stub.o efi-entry.o arm64-obj-$(CONFIG_PCI) += pci.o +arm64-obj-$(CONFIG_ARMV8_DEPRECATED) += armv8_deprecated.o obj-y += $(arm64-obj-y) vdso/ obj-m += $(arm64-obj-m) diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c new file mode 100644 index 000000000000..db3b79da6a48 --- /dev/null +++ b/arch/arm64/kernel/armv8_deprecated.c @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2014 ARM Limited + * + * 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 + +/* + * The runtime support for deprecated instruction support can be in one of + * following three states - + * + * 0 = undef + * 1 = emulate (software emulation) + * 2 = hw (supported in hardware) + */ +enum insn_emulation_mode { + INSN_UNDEF, + INSN_EMULATE, + INSN_HW, +}; + +enum legacy_insn_status { + INSN_DEPRECATED, + INSN_OBSOLETE, +}; + +struct insn_emulation_ops { + const char *name; + enum legacy_insn_status status; + struct undef_hook *hooks; + int (*set_hw_mode)(bool enable); +}; + +struct insn_emulation { + struct list_head node; + struct insn_emulation_ops *ops; + int current_mode; + int min; + int max; +}; + +static LIST_HEAD(insn_emulation); +static int nr_insn_emulated; +static DEFINE_RAW_SPINLOCK(insn_emulation_lock); + +static void register_emulation_hooks(struct insn_emulation_ops *ops) +{ + struct undef_hook *hook; + + BUG_ON(!ops->hooks); + + for (hook = ops->hooks; hook->instr_mask; hook++) + register_undef_hook(hook); + + pr_notice("Registered %s emulation handler\n", ops->name); +} + +static void remove_emulation_hooks(struct insn_emulation_ops *ops) +{ + struct undef_hook *hook; + + BUG_ON(!ops->hooks); + + for (hook = ops->hooks; hook->instr_mask; hook++) + unregister_undef_hook(hook); + + pr_notice("Removed %s emulation handler\n", ops->name); +} + +static int update_insn_emulation_mode(struct insn_emulation *insn, + enum insn_emulation_mode prev) +{ + int ret = 0; + + switch (prev) { + case INSN_UNDEF: /* Nothing to be done */ + break; + case INSN_EMULATE: + remove_emulation_hooks(insn->ops); + break; + case INSN_HW: + if (insn->ops->set_hw_mode) { + insn->ops->set_hw_mode(false); + pr_notice("Disabled %s support\n", insn->ops->name); + } + break; + } + + switch (insn->current_mode) { + case INSN_UNDEF: + break; + case INSN_EMULATE: + register_emulation_hooks(insn->ops); + break; + case INSN_HW: + if (insn->ops->set_hw_mode && insn->ops->set_hw_mode(true)) + pr_notice("Enabled %s support\n", insn->ops->name); + else + ret = -EINVAL; + break; + } + + return ret; +} + +static void register_insn_emulation(struct insn_emulation_ops *ops) +{ + unsigned long flags; + struct insn_emulation *insn; + + insn = kzalloc(sizeof(*insn), GFP_KERNEL); + insn->ops = ops; + insn->min = INSN_UNDEF; + + switch (ops->status) { + case INSN_DEPRECATED: + insn->current_mode = INSN_EMULATE; + insn->max = INSN_HW; + break; + case INSN_OBSOLETE: + insn->current_mode = INSN_UNDEF; + insn->max = INSN_EMULATE; + break; + } + + raw_spin_lock_irqsave(&insn_emulation_lock, flags); + list_add(&insn->node, &insn_emulation); + nr_insn_emulated++; + raw_spin_unlock_irqrestore(&insn_emulation_lock, flags); + + /* Register any handlers if required */ + update_insn_emulation_mode(insn, INSN_UNDEF); +} + +static int emulation_proc_handler(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, + loff_t *ppos) +{ + int ret = 0; + struct insn_emulation *insn = (struct insn_emulation *) table->data; + enum insn_emulation_mode prev_mode = insn->current_mode; + + table->data = &insn->current_mode; + ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos); + + if (ret || !write || prev_mode == insn->current_mode) + goto ret; + + ret = update_insn_emulation_mode(insn, prev_mode); + if (!ret) { + /* Mode change failed, revert to previous mode. */ + insn->current_mode = prev_mode; + update_insn_emulation_mode(insn, INSN_UNDEF); + } +ret: + table->data = insn; + return ret; +} + +static struct ctl_table ctl_abi[] = { + { + .procname = "abi", + .mode = 0555, + }, + { } +}; + +static void register_insn_emulation_sysctl(struct ctl_table *table) +{ + unsigned long flags; + int i = 0; + struct insn_emulation *insn; + struct ctl_table *insns_sysctl, *sysctl; + + insns_sysctl = kzalloc(sizeof(*sysctl) * (nr_insn_emulated + 1), + GFP_KERNEL); + + raw_spin_lock_irqsave(&insn_emulation_lock, flags); + list_for_each_entry(insn, &insn_emulation, node) { + sysctl = &insns_sysctl[i]; + + sysctl->mode = 0644; + sysctl->maxlen = sizeof(int); + + sysctl->procname = insn->ops->name; + sysctl->data = insn; + sysctl->extra1 = &insn->min; + sysctl->extra2 = &insn->max; + sysctl->proc_handler = emulation_proc_handler; + i++; + } + raw_spin_unlock_irqrestore(&insn_emulation_lock, flags); + + table->child = insns_sysctl; + register_sysctl_table(table); +} + +/* + * Invoked as late_initcall, since not needed before init spawned. + */ +static int __init armv8_deprecated_init(void) +{ + register_insn_emulation_sysctl(ctl_abi); + + return 0; +} + +late_initcall(armv8_deprecated_init); -- cgit v1.2.3-59-g8ed1b From bd35a4adc4131c530ec7d90242555eac7b3dbe3f Mon Sep 17 00:00:00 2001 From: Punit Agrawal Date: Tue, 18 Nov 2014 11:41:25 +0000 Subject: arm64: Port SWP/SWPB emulation support from arm The SWP instruction was deprecated in the ARMv6 architecture. The ARMv7 multiprocessing extensions mandate that SWP/SWPB instructions are treated as undefined from reset, with the ability to enable them through the System Control Register SW bit. With ARMv8, the option to enable these instructions through System Control Register was dropped as well. To support legacy applications using these instructions, port the emulation of the SWP and SWPB instructions from the arm port to arm64. Reviewed-by: Catalin Marinas Signed-off-by: Punit Agrawal Signed-off-by: Will Deacon --- Documentation/arm64/legacy_instructions.txt | 7 + arch/arm64/Kconfig | 21 +++ arch/arm64/include/asm/insn.h | 6 + arch/arm64/kernel/armv8_deprecated.c | 191 ++++++++++++++++++++++++++++ arch/arm64/kernel/insn.c | 8 ++ 5 files changed, 233 insertions(+) (limited to 'Documentation') diff --git a/Documentation/arm64/legacy_instructions.txt b/Documentation/arm64/legacy_instructions.txt index 49d4867c0c09..5ab58614b7ed 100644 --- a/Documentation/arm64/legacy_instructions.txt +++ b/Documentation/arm64/legacy_instructions.txt @@ -31,3 +31,10 @@ behaviours and the corresponding values of the sysctl nodes - The default mode depends on the status of the instruction in the architecture. Deprecated instructions should default to emulation while obsolete instructions must be undefined by default. + +Supported legacy instructions +----------------------------- +* SWP{B} +Node: /proc/sys/abi/swp +Status: Obsolete +Default: Undef (0) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index aa8f4bea3738..2b6213840ec8 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -180,6 +180,27 @@ menuconfig ARMV8_DEPRECATED if ARMV8_DEPRECATED +config SWP_EMULATION + bool "Emulate SWP/SWPB instructions" + help + ARMv8 obsoletes the use of A32 SWP/SWPB instructions such that + they are always undefined. Say Y here to enable software + emulation of these instructions for userspace using LDXR/STXR. + + In some older versions of glibc [<=2.8] SWP is used during futex + trylock() operations with the assumption that the code will not + be preempted. This invalid assumption may be more likely to fail + with SWP emulation enabled, leading to deadlock of the user + application. + + NOTE: when accessing uncached shared regions, LDXR/STXR rely + on an external transaction monitoring block called a global + monitor to maintain update atomicity. If your system does not + implement a global monitor, this option can cause programs that + perform SWP operations to uncached memory to deadlock. + + If unsure, say Y + endif endmenu diff --git a/arch/arm64/include/asm/insn.h b/arch/arm64/include/asm/insn.h index 1bb043018315..3ecc57c47c04 100644 --- a/arch/arm64/include/asm/insn.h +++ b/arch/arm64/include/asm/insn.h @@ -356,6 +356,12 @@ int aarch64_insn_patch_text_sync(void *addrs[], u32 insns[], int cnt); int aarch64_insn_patch_text(void *addrs[], u32 insns[], int cnt); bool aarch32_insn_is_wide(u32 insn); + +#define A32_RN_OFFSET 16 +#define A32_RT_OFFSET 12 +#define A32_RT2_OFFSET 0 + +u32 aarch32_insn_extract_reg_num(u32 insn, int offset); #endif /* __ASSEMBLY__ */ #endif /* __ASM_INSN_H */ diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c index db3b79da6a48..98865a7868f1 100644 --- a/arch/arm64/kernel/armv8_deprecated.c +++ b/arch/arm64/kernel/armv8_deprecated.c @@ -8,10 +8,16 @@ #include #include +#include +#include #include #include +#include +#include +#include #include +#include /* * The runtime support for deprecated instruction support can be in one of @@ -203,11 +209,196 @@ static void register_insn_emulation_sysctl(struct ctl_table *table) register_sysctl_table(table); } +/* + * Implement emulation of the SWP/SWPB instructions using load-exclusive and + * store-exclusive. + * + * Syntax of SWP{B} instruction: SWP{B} , , [] + * Where: Rt = destination + * Rt2 = source + * Rn = address + */ + +/* + * Error-checking SWP macros implemented using ldxr{b}/stxr{b} + */ +#define __user_swpX_asm(data, addr, res, temp, B) \ + __asm__ __volatile__( \ + " mov %w2, %w1\n" \ + "0: ldxr"B" %w1, [%3]\n" \ + "1: stxr"B" %w0, %w2, [%3]\n" \ + " cbz %w0, 2f\n" \ + " mov %w0, %w4\n" \ + "2:\n" \ + " .pushsection .fixup,\"ax\"\n" \ + " .align 2\n" \ + "3: mov %w0, %w5\n" \ + " b 2b\n" \ + " .popsection" \ + " .pushsection __ex_table,\"a\"\n" \ + " .align 3\n" \ + " .quad 0b, 3b\n" \ + " .quad 1b, 3b\n" \ + " .popsection" \ + : "=&r" (res), "+r" (data), "=&r" (temp) \ + : "r" (addr), "i" (-EAGAIN), "i" (-EFAULT) \ + : "memory") + +#define __user_swp_asm(data, addr, res, temp) \ + __user_swpX_asm(data, addr, res, temp, "") +#define __user_swpb_asm(data, addr, res, temp) \ + __user_swpX_asm(data, addr, res, temp, "b") + +/* + * Bit 22 of the instruction encoding distinguishes between + * the SWP and SWPB variants (bit set means SWPB). + */ +#define TYPE_SWPB (1 << 22) + +/* + * Set up process info to signal segmentation fault - called on access error. + */ +static void set_segfault(struct pt_regs *regs, unsigned long addr) +{ + siginfo_t info; + + down_read(¤t->mm->mmap_sem); + if (find_vma(current->mm, addr) == NULL) + info.si_code = SEGV_MAPERR; + else + info.si_code = SEGV_ACCERR; + up_read(¤t->mm->mmap_sem); + + info.si_signo = SIGSEGV; + info.si_errno = 0; + info.si_addr = (void *) instruction_pointer(regs); + + pr_debug("SWP{B} emulation: access caused memory abort!\n"); + arm64_notify_die("Illegal memory access", regs, &info, 0); +} + +static int emulate_swpX(unsigned int address, unsigned int *data, + unsigned int type) +{ + unsigned int res = 0; + + if ((type != TYPE_SWPB) && (address & 0x3)) { + /* SWP to unaligned address not permitted */ + pr_debug("SWP instruction on unaligned pointer!\n"); + return -EFAULT; + } + + while (1) { + unsigned long temp; + + if (type == TYPE_SWPB) + __user_swpb_asm(*data, address, res, temp); + else + __user_swp_asm(*data, address, res, temp); + + if (likely(res != -EAGAIN) || signal_pending(current)) + break; + + cond_resched(); + } + + return res; +} + +/* + * swp_handler logs the id of calling process, dissects the instruction, sanity + * checks the memory location, calls emulate_swpX for the actual operation and + * deals with fixup/error handling before returning + */ +static int swp_handler(struct pt_regs *regs, u32 instr) +{ + u32 destreg, data, type, address = 0; + int rn, rt2, res = 0; + + perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->pc); + + type = instr & TYPE_SWPB; + + switch (arm_check_condition(instr, regs->pstate)) { + case ARM_OPCODE_CONDTEST_PASS: + break; + case ARM_OPCODE_CONDTEST_FAIL: + /* Condition failed - return to next instruction */ + goto ret; + case ARM_OPCODE_CONDTEST_UNCOND: + /* If unconditional encoding - not a SWP, undef */ + return -EFAULT; + default: + return -EINVAL; + } + + rn = aarch32_insn_extract_reg_num(instr, A32_RN_OFFSET); + rt2 = aarch32_insn_extract_reg_num(instr, A32_RT2_OFFSET); + + address = (u32)regs->user_regs.regs[rn]; + data = (u32)regs->user_regs.regs[rt2]; + destreg = aarch32_insn_extract_reg_num(instr, A32_RT_OFFSET); + + pr_debug("addr in r%d->0x%08x, dest is r%d, source in r%d->0x%08x)\n", + rn, address, destreg, + aarch32_insn_extract_reg_num(instr, A32_RT2_OFFSET), data); + + /* Check access in reasonable access range for both SWP and SWPB */ + if (!access_ok(VERIFY_WRITE, (address & ~3), 4)) { + pr_debug("SWP{B} emulation: access to 0x%08x not allowed!\n", + address); + goto fault; + } + + res = emulate_swpX(address, &data, type); + if (res == -EFAULT) + goto fault; + else if (res == 0) + regs->user_regs.regs[destreg] = data; + +ret: + pr_warn_ratelimited("\"%s\" (%ld) uses obsolete SWP{B} instruction at 0x%llx\n", + current->comm, (unsigned long)current->pid, regs->pc); + + regs->pc += 4; + return 0; + +fault: + set_segfault(regs, address); + + return 0; +} + +/* + * Only emulate SWP/SWPB executed in ARM state/User mode. + * The kernel must be SWP free and SWP{B} does not exist in Thumb. + */ +static struct undef_hook swp_hooks[] = { + { + .instr_mask = 0x0fb00ff0, + .instr_val = 0x01000090, + .pstate_mask = COMPAT_PSR_MODE_MASK, + .pstate_val = COMPAT_PSR_MODE_USR, + .fn = swp_handler + }, + { } +}; + +static struct insn_emulation_ops swp_ops = { + .name = "swp", + .status = INSN_OBSOLETE, + .hooks = swp_hooks, + .set_hw_mode = NULL, +}; + /* * Invoked as late_initcall, since not needed before init spawned. */ static int __init armv8_deprecated_init(void) { + if (IS_ENABLED(CONFIG_SWP_EMULATION)) + register_insn_emulation(&swp_ops); + register_insn_emulation_sysctl(ctl_abi); return 0; diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c index ab00eb58d385..63122dcd8524 100644 --- a/arch/arm64/kernel/insn.c +++ b/arch/arm64/kernel/insn.c @@ -964,3 +964,11 @@ bool aarch32_insn_is_wide(u32 insn) { return insn >= 0xe800; } + +/* + * Macros/defines for extracting register numbers from instruction. + */ +u32 aarch32_insn_extract_reg_num(u32 insn, int offset) +{ + return (insn & (0xf << offset)) >> offset; +} -- cgit v1.2.3-59-g8ed1b From c852f320584600a372646055d8229e063949eee7 Mon Sep 17 00:00:00 2001 From: Punit Agrawal Date: Tue, 18 Nov 2014 11:41:26 +0000 Subject: arm64: Emulate CP15 Barrier instructions The CP15 barrier instructions (CP15ISB, CP15DSB and CP15DMB) are deprecated in the ARMv7 architecture, superseded by ISB, DSB and DMB instructions respectively. Some implementations may provide the ability to disable the CP15 barriers by disabling the CP15BEN bit in SCTLR_EL1. If not enabled, the encodings for these instructions become undefined. To support legacy software using these instructions, this patch register hooks to - * emulate CP15 barriers and warn the user about their use * toggle CP15BEN in SCTLR_EL1 Signed-off-by: Punit Agrawal Reviewed-by: Catalin Marinas Signed-off-by: Will Deacon --- Documentation/arm64/legacy_instructions.txt | 5 ++ arch/arm64/Kconfig | 15 ++++ arch/arm64/include/asm/insn.h | 2 + arch/arm64/kernel/armv8_deprecated.c | 131 ++++++++++++++++++++++++++++ arch/arm64/kernel/insn.c | 13 +++ 5 files changed, 166 insertions(+) (limited to 'Documentation') diff --git a/Documentation/arm64/legacy_instructions.txt b/Documentation/arm64/legacy_instructions.txt index 5ab58614b7ed..a3b3da2ec6ed 100644 --- a/Documentation/arm64/legacy_instructions.txt +++ b/Documentation/arm64/legacy_instructions.txt @@ -38,3 +38,8 @@ Supported legacy instructions Node: /proc/sys/abi/swp Status: Obsolete Default: Undef (0) + +* CP15 Barriers +Node: /proc/sys/abi/cp15_barrier +Status: Deprecated +Default: Emulate (1) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 2b6213840ec8..8e74dfe1e74d 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -201,6 +201,21 @@ config SWP_EMULATION If unsure, say Y +config CP15_BARRIER_EMULATION + bool "Emulate CP15 Barrier instructions" + help + The CP15 barrier instructions - CP15ISB, CP15DSB, and + CP15DMB - are deprecated in ARMv8 (and ARMv7). It is + strongly recommended to use the ISB, DSB, and DMB + instructions instead. + + Say Y here to enable software emulation of these + instructions for AArch32 userspace code. When this option is + enabled, CP15 barrier usage is traced which can help + identify software that needs updating. + + If unsure, say Y + endif endmenu diff --git a/arch/arm64/include/asm/insn.h b/arch/arm64/include/asm/insn.h index 3ecc57c47c04..e2ff32a93b5c 100644 --- a/arch/arm64/include/asm/insn.h +++ b/arch/arm64/include/asm/insn.h @@ -362,6 +362,8 @@ bool aarch32_insn_is_wide(u32 insn); #define A32_RT2_OFFSET 0 u32 aarch32_insn_extract_reg_num(u32 insn, int offset); +u32 aarch32_insn_mcr_extract_opc2(u32 insn); +u32 aarch32_insn_mcr_extract_crm(u32 insn); #endif /* __ASSEMBLY__ */ #endif /* __ASM_INSN_H */ diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c index 98865a7868f1..401c2e544ede 100644 --- a/arch/arm64/kernel/armv8_deprecated.c +++ b/arch/arm64/kernel/armv8_deprecated.c @@ -6,6 +6,7 @@ * published by the Free Software Foundation. */ +#include #include #include #include @@ -391,6 +392,133 @@ static struct insn_emulation_ops swp_ops = { .set_hw_mode = NULL, }; +static int cp15barrier_handler(struct pt_regs *regs, u32 instr) +{ + perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->pc); + + switch (arm_check_condition(instr, regs->pstate)) { + case ARM_OPCODE_CONDTEST_PASS: + break; + case ARM_OPCODE_CONDTEST_FAIL: + /* Condition failed - return to next instruction */ + goto ret; + case ARM_OPCODE_CONDTEST_UNCOND: + /* If unconditional encoding - not a barrier instruction */ + return -EFAULT; + default: + return -EINVAL; + } + + switch (aarch32_insn_mcr_extract_crm(instr)) { + case 10: + /* + * dmb - mcr p15, 0, Rt, c7, c10, 5 + * dsb - mcr p15, 0, Rt, c7, c10, 4 + */ + if (aarch32_insn_mcr_extract_opc2(instr) == 5) + dmb(sy); + else + dsb(sy); + break; + case 5: + /* + * isb - mcr p15, 0, Rt, c7, c5, 4 + * + * Taking an exception or returning from one acts as an + * instruction barrier. So no explicit barrier needed here. + */ + break; + } + +ret: + pr_warn_ratelimited("\"%s\" (%ld) uses deprecated CP15 Barrier instruction at 0x%llx\n", + current->comm, (unsigned long)current->pid, regs->pc); + + regs->pc += 4; + return 0; +} + +#define SCTLR_EL1_CP15BEN (1 << 5) + +static inline void config_sctlr_el1(u32 clear, u32 set) +{ + u32 val; + + asm volatile("mrs %0, sctlr_el1" : "=r" (val)); + val &= ~clear; + val |= set; + asm volatile("msr sctlr_el1, %0" : : "r" (val)); +} + +static void enable_cp15_ben(void *info) +{ + config_sctlr_el1(0, SCTLR_EL1_CP15BEN); +} + +static void disable_cp15_ben(void *info) +{ + config_sctlr_el1(SCTLR_EL1_CP15BEN, 0); +} + +static int cpu_hotplug_notify(struct notifier_block *b, + unsigned long action, void *hcpu) +{ + switch (action) { + case CPU_STARTING: + case CPU_STARTING_FROZEN: + enable_cp15_ben(NULL); + return NOTIFY_DONE; + case CPU_DYING: + case CPU_DYING_FROZEN: + disable_cp15_ben(NULL); + return NOTIFY_DONE; + } + + return NOTIFY_OK; +} + +static struct notifier_block cpu_hotplug_notifier = { + .notifier_call = cpu_hotplug_notify, +}; + +static int cp15_barrier_set_hw_mode(bool enable) +{ + if (enable) { + register_cpu_notifier(&cpu_hotplug_notifier); + on_each_cpu(enable_cp15_ben, NULL, true); + } else { + unregister_cpu_notifier(&cpu_hotplug_notifier); + on_each_cpu(disable_cp15_ben, NULL, true); + } + + return true; +} + +static struct undef_hook cp15_barrier_hooks[] = { + { + .instr_mask = 0x0fff0fdf, + .instr_val = 0x0e070f9a, + .pstate_mask = COMPAT_PSR_MODE_MASK, + .pstate_val = COMPAT_PSR_MODE_USR, + .fn = cp15barrier_handler, + }, + { + .instr_mask = 0x0fff0fff, + .instr_val = 0x0e070f95, + .pstate_mask = COMPAT_PSR_MODE_MASK, + .pstate_val = COMPAT_PSR_MODE_USR, + .fn = cp15barrier_handler, + }, + { } +}; + +static struct insn_emulation_ops cp15_barrier_ops = { + .name = "cp15_barrier", + .status = INSN_DEPRECATED, + .hooks = cp15_barrier_hooks, + .set_hw_mode = cp15_barrier_set_hw_mode, +}; + /* * Invoked as late_initcall, since not needed before init spawned. */ @@ -399,6 +527,9 @@ static int __init armv8_deprecated_init(void) if (IS_ENABLED(CONFIG_SWP_EMULATION)) register_insn_emulation(&swp_ops); + if (IS_ENABLED(CONFIG_CP15_BARRIER_EMULATION)) + register_insn_emulation(&cp15_barrier_ops); + register_insn_emulation_sysctl(ctl_abi); return 0; diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c index 63122dcd8524..819e409029ce 100644 --- a/arch/arm64/kernel/insn.c +++ b/arch/arm64/kernel/insn.c @@ -972,3 +972,16 @@ u32 aarch32_insn_extract_reg_num(u32 insn, int offset) { return (insn & (0xf << offset)) >> offset; } + +#define OPC2_MASK 0x7 +#define OPC2_OFFSET 5 +u32 aarch32_insn_mcr_extract_opc2(u32 insn) +{ + return (insn & (OPC2_MASK << OPC2_OFFSET)) >> OPC2_OFFSET; +} + +#define CRM_MASK 0xf +u32 aarch32_insn_mcr_extract_crm(u32 insn) +{ + return insn & CRM_MASK; +} -- cgit v1.2.3-59-g8ed1b From 2f3fa3a0e5672f87f5b972910737a2ef60941b62 Mon Sep 17 00:00:00 2001 From: Antoine Tenart Date: Thu, 20 Nov 2014 22:53:26 +0100 Subject: Documentation: bindings: add doc for the Berlin USB PHY Document the bindings of the Marvell Berlin USB PHY driver. Signed-off-by: Antoine Tenart Signed-off-by: Kishon Vijay Abraham I --- Documentation/devicetree/bindings/phy/berlin-usb-phy.txt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/berlin-usb-phy.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/phy/berlin-usb-phy.txt b/Documentation/devicetree/bindings/phy/berlin-usb-phy.txt new file mode 100644 index 000000000000..be33780f668e --- /dev/null +++ b/Documentation/devicetree/bindings/phy/berlin-usb-phy.txt @@ -0,0 +1,16 @@ +* Marvell Berlin USB PHY + +Required properties: +- compatible: "marvell,berlin2-usb-phy" or "marvell,berlin2cd-usb-phy" +- reg: base address and length of the registers +- #phys-cells: should be 0 +- resets: reference to the reset controller + +Example: + + usb-phy@f774000 { + compatible = "marvell,berlin2-usb-phy"; + reg = <0xf774000 0x128>; + #phy-cells = <0>; + resets = <&chip 0x104 14>; + }; -- cgit v1.2.3-59-g8ed1b From b7bc15b98e843926d01eb03b9c0e196d8ddbadeb Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Wed, 19 Nov 2014 17:28:18 +0200 Subject: phy: improved lookup method Separates registration of the phy and the lookup. The method is copied from clkdev.c, Signed-off-by: Heikki Krogerus Signed-off-by: Kishon Vijay Abraham I --- Documentation/phy.txt | 60 ++++++++++------------------------- drivers/phy/phy-core.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++- include/linux/phy/phy.h | 16 ++++++++++ 3 files changed, 115 insertions(+), 45 deletions(-) (limited to 'Documentation') diff --git a/Documentation/phy.txt b/Documentation/phy.txt index c6594af94d25..371361c69a4b 100644 --- a/Documentation/phy.txt +++ b/Documentation/phy.txt @@ -54,18 +54,14 @@ The PHY driver should create the PHY in order for other peripheral controllers to make use of it. The PHY framework provides 2 APIs to create the PHY. struct phy *phy_create(struct device *dev, struct device_node *node, - const struct phy_ops *ops, - struct phy_init_data *init_data); + const struct phy_ops *ops); struct phy *devm_phy_create(struct device *dev, struct device_node *node, - const struct phy_ops *ops, - struct phy_init_data *init_data); + const struct phy_ops *ops); The PHY drivers can use one of the above 2 APIs to create the PHY by passing -the device pointer, phy ops and init_data. +the device pointer and phy ops. phy_ops is a set of function pointers for performing PHY operations such as -init, exit, power_on and power_off. *init_data* is mandatory to get a reference -to the PHY in the case of non-dt boot. See section *Board File Initialization* -on how init_data should be used. +init, exit, power_on and power_off. Inorder to dereference the private data (in phy_ops), the phy provider driver can use phy_set_drvdata() after creating the PHY and use phy_get_drvdata() in @@ -137,42 +133,18 @@ There are exported APIs like phy_pm_runtime_get, phy_pm_runtime_get_sync, phy_pm_runtime_put, phy_pm_runtime_put_sync, phy_pm_runtime_allow and phy_pm_runtime_forbid for performing PM operations. -8. Board File Initialization - -Certain board file initialization is necessary in order to get a reference -to the PHY in the case of non-dt boot. -Say we have a single device that implements 3 PHYs that of USB, SATA and PCIe, -then in the board file the following initialization should be done. - -struct phy_consumer consumers[] = { - PHY_CONSUMER("dwc3.0", "usb"), - PHY_CONSUMER("pcie.0", "pcie"), - PHY_CONSUMER("sata.0", "sata"), -}; -PHY_CONSUMER takes 2 parameters, first is the device name of the controller -(PHY consumer) and second is the port name. - -struct phy_init_data init_data = { - .consumers = consumers, - .num_consumers = ARRAY_SIZE(consumers), -}; - -static const struct platform_device pipe3_phy_dev = { - .name = "pipe3-phy", - .id = -1, - .dev = { - .platform_data = { - .init_data = &init_data, - }, - }, -}; - -then, while doing phy_create, the PHY driver should pass this init_data - phy_create(dev, ops, pdata->init_data); - -and the controller driver (phy consumer) should pass the port name along with -the device to get a reference to the PHY - phy_get(dev, "pcie"); +8. PHY Mappings + +In order to get reference to a PHY without help from DeviceTree, the framework +offers lookups which can be compared to clkdev that allow clk structures to be +bound to devices. A lookup can be made be made during runtime when a handle to +the struct phy already exists. + +The framework offers the following API for registering and unregistering the +lookups. + +int phy_create_lookup(struct phy *phy, const char *con_id, const char *dev_id); +void phy_remove_lookup(struct phy *phy, const char *con_id, const char *dev_id); 9. DeviceTree Binding diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c index 1606ce9805d0..bc830773fe05 100644 --- a/drivers/phy/phy-core.c +++ b/drivers/phy/phy-core.c @@ -26,6 +26,7 @@ static struct class *phy_class; static DEFINE_MUTEX(phy_provider_mutex); static LIST_HEAD(phy_provider_list); +static LIST_HEAD(phys); static DEFINE_IDA(phy_ida); static void devm_phy_release(struct device *dev, void *res) @@ -84,6 +85,87 @@ static struct phy *phy_lookup(struct device *device, const char *port) return ERR_PTR(-ENODEV); } +/** + * phy_create_lookup() - allocate and register PHY/device association + * @phy: the phy of the association + * @con_id: connection ID string on device + * @dev_id: the device of the association + * + * Creates and registers phy_lookup entry. + */ +int phy_create_lookup(struct phy *phy, const char *con_id, const char *dev_id) +{ + struct phy_lookup *pl; + + if (!phy || !dev_id || !con_id) + return -EINVAL; + + pl = kzalloc(sizeof(*pl), GFP_KERNEL); + if (!pl) + return -ENOMEM; + + pl->dev_id = dev_id; + pl->con_id = con_id; + pl->phy = phy; + + mutex_lock(&phy_provider_mutex); + list_add_tail(&pl->node, &phys); + mutex_unlock(&phy_provider_mutex); + + return 0; +} +EXPORT_SYMBOL_GPL(phy_create_lookup); + +/** + * phy_remove_lookup() - find and remove PHY/device association + * @phy: the phy of the association + * @con_id: connection ID string on device + * @dev_id: the device of the association + * + * Finds and unregisters phy_lookup entry that was created with + * phy_create_lookup(). + */ +void phy_remove_lookup(struct phy *phy, const char *con_id, const char *dev_id) +{ + struct phy_lookup *pl; + + if (!phy || !dev_id || !con_id) + return; + + mutex_lock(&phy_provider_mutex); + list_for_each_entry(pl, &phys, node) + if (pl->phy == phy && !strcmp(pl->dev_id, dev_id) && + !strcmp(pl->con_id, con_id)) { + list_del(&pl->node); + kfree(pl); + break; + } + mutex_unlock(&phy_provider_mutex); +} +EXPORT_SYMBOL_GPL(phy_remove_lookup); + +static struct phy *phy_find(struct device *dev, const char *con_id) +{ + const char *dev_id = dev_name(dev); + struct phy_lookup *p, *pl = NULL; + struct phy *phy; + + mutex_lock(&phy_provider_mutex); + list_for_each_entry(p, &phys, node) + if (!strcmp(p->dev_id, dev_id) && !strcmp(p->con_id, con_id)) { + pl = p; + break; + } + mutex_unlock(&phy_provider_mutex); + + phy = pl ? pl->phy : ERR_PTR(-ENODEV); + + /* fall-back to the old lookup method for now */ + if (IS_ERR(phy)) + phy = phy_lookup(dev, con_id); + return phy; +} + static struct phy_provider *of_phy_provider_lookup(struct device_node *node) { struct phy_provider *phy_provider; @@ -455,7 +537,7 @@ struct phy *phy_get(struct device *dev, const char *string) string); phy = _of_phy_get(dev->of_node, index); } else { - phy = phy_lookup(dev, string); + phy = phy_find(dev, string); } if (IS_ERR(phy)) return phy; diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h index 9fda68324298..849284e5873f 100644 --- a/include/linux/phy/phy.h +++ b/include/linux/phy/phy.h @@ -110,6 +110,13 @@ struct phy_init_data { .port = _port, \ } +struct phy_lookup { + struct list_head node; + const char *dev_id; + const char *con_id; + struct phy *phy; +}; + #define to_phy(a) (container_of((a), struct phy, dev)) #define of_phy_provider_register(dev, xlate) \ @@ -174,6 +181,8 @@ struct phy_provider *__devm_of_phy_provider_register(struct device *dev, void of_phy_provider_unregister(struct phy_provider *phy_provider); void devm_of_phy_provider_unregister(struct device *dev, struct phy_provider *phy_provider); +int phy_create_lookup(struct phy *phy, const char *con_id, const char *dev_id); +void phy_remove_lookup(struct phy *phy, const char *con_id, const char *dev_id); #else static inline int phy_pm_runtime_get(struct phy *phy) { @@ -345,6 +354,13 @@ static inline void devm_of_phy_provider_unregister(struct device *dev, struct phy_provider *phy_provider) { } +static inline int +phy_create_lookup(struct phy *phy, const char *con_id, const char *dev_id) +{ + return 0; +} +static inline void phy_remove_lookup(struct phy *phy, const char *con_id, + const char *dev_id) { } #endif #endif /* __DRIVERS_PHY_H */ -- cgit v1.2.3-59-g8ed1b From ed692a99f31c92ec649ee2f7a0ecb4aa0f69d853 Mon Sep 17 00:00:00 2001 From: Vivek Gautam Date: Fri, 21 Nov 2014 19:05:47 +0530 Subject: usb: dwc3: exynos: Add provision for AXI UpScaler clock on exynos7 DWC3 controller on Exynos7 SoC has separate control for AXI UpScaler which connects DWC3 DRD controller to AXI bus. Get the gate clock for the same to control it across power cycles. Suggested-by: Anton Tikhomirov Signed-off-by: Vivek Gautam Signed-off-by: Felipe Balbi --- Documentation/devicetree/bindings/usb/exynos-usb.txt | 6 ++++-- drivers/usb/dwc3/dwc3-exynos.c | 17 +++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/usb/exynos-usb.txt b/Documentation/devicetree/bindings/usb/exynos-usb.txt index a3b5990d0f2c..9b4dbe3b2acc 100644 --- a/Documentation/devicetree/bindings/usb/exynos-usb.txt +++ b/Documentation/devicetree/bindings/usb/exynos-usb.txt @@ -82,8 +82,10 @@ Example: DWC3 Required properties: - - compatible: should be "samsung,exynos5250-dwusb3" for USB 3.0 DWC3 - controller. + - compatible: should be one of the following - + "samsung,exynos5250-dwusb3": for USB 3.0 DWC3 controller on + Exynos5250/5420. + "samsung,exynos7-dwusb3": for USB 3.0 DWC3 controller on Exynos7. - #address-cells, #size-cells : should be '1' if the device has sub-nodes with 'reg' property. - ranges: allows valid 1:1 translation between child's address space and diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c index a1782d86a226..7bd0a95b2815 100644 --- a/drivers/usb/dwc3/dwc3-exynos.c +++ b/drivers/usb/dwc3/dwc3-exynos.c @@ -35,6 +35,7 @@ struct dwc3_exynos { struct clk *clk; struct clk *susp_clk; + struct clk *axius_clk; struct regulator *vdd33; struct regulator *vdd10; @@ -149,6 +150,17 @@ static int dwc3_exynos_probe(struct platform_device *pdev) } clk_prepare_enable(exynos->susp_clk); + if (of_device_is_compatible(node, "samsung,exynos7-dwusb3")) { + exynos->axius_clk = devm_clk_get(dev, "usbdrd30_axius_clk"); + if (IS_ERR(exynos->axius_clk)) { + dev_err(dev, "no AXI UpScaler clk specified\n"); + return -ENODEV; + } + clk_prepare_enable(exynos->axius_clk); + } else { + exynos->axius_clk = NULL; + } + exynos->vdd33 = devm_regulator_get(dev, "vdd33"); if (IS_ERR(exynos->vdd33)) { ret = PTR_ERR(exynos->vdd33); @@ -190,6 +202,7 @@ err4: err3: regulator_disable(exynos->vdd33); err2: + clk_disable_unprepare(exynos->axius_clk); clk_disable_unprepare(exynos->susp_clk); clk_disable_unprepare(exynos->clk); return ret; @@ -203,6 +216,7 @@ static int dwc3_exynos_remove(struct platform_device *pdev) platform_device_unregister(exynos->usb2_phy); platform_device_unregister(exynos->usb3_phy); + clk_disable_unprepare(exynos->axius_clk); clk_disable_unprepare(exynos->susp_clk); clk_disable_unprepare(exynos->clk); @@ -214,6 +228,7 @@ static int dwc3_exynos_remove(struct platform_device *pdev) static const struct of_device_id exynos_dwc3_match[] = { { .compatible = "samsung,exynos5250-dwusb3" }, + { .compatible = "samsung,exynos7-dwusb3" }, {}, }; MODULE_DEVICE_TABLE(of, exynos_dwc3_match); @@ -223,6 +238,7 @@ static int dwc3_exynos_suspend(struct device *dev) { struct dwc3_exynos *exynos = dev_get_drvdata(dev); + clk_disable(exynos->axius_clk); clk_disable(exynos->clk); regulator_disable(exynos->vdd33); @@ -248,6 +264,7 @@ static int dwc3_exynos_resume(struct device *dev) } clk_enable(exynos->clk); + clk_enable(exynos->axius_clk); /* runtime set active to reflect active state. */ pm_runtime_disable(dev); -- cgit v1.2.3-59-g8ed1b From e2280c9040d8bc5039617af35ccf7b8ac4abb428 Mon Sep 17 00:00:00 2001 From: Zidan Wang Date: Thu, 20 Nov 2014 19:07:48 +0800 Subject: ASoC: wm8960: Add device tree support Document the device tree binding for the WM8960 codec, and modify the driver to extract the platform data from device tree, if present. Signed-off-by: Zidan Wang Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/wm8960.txt | 31 ++++++++++++++++ sound/soc/codecs/wm8960.c | 41 ++++++++++++++++------ 2 files changed, 62 insertions(+), 10 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/wm8960.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/wm8960.txt b/Documentation/devicetree/bindings/sound/wm8960.txt new file mode 100644 index 000000000000..2deb8a3da9c5 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/wm8960.txt @@ -0,0 +1,31 @@ +WM8960 audio CODEC + +This device supports I2C only. + +Required properties: + + - compatible : "wlf,wm8960" + + - reg : the I2C address of the device. + +Optional properties: + - wlf,shared-lrclk: This is a boolean property. If present, the LRCM bit of + R24 (Additional control 2) gets set, indicating that ADCLRC and DACLRC pins + will be disabled only when ADC (Left and Right) and DAC (Left and Right) + are disabled. + When wm8960 works on synchronize mode and DACLRC pin is used to supply + frame clock, it will no frame clock for captrue unless enable DAC to enable + DACLRC pin. If shared-lrclk is present, no need to enable DAC for captrue. + + - wlf,capless: This is a boolean property. If present, OUT3 pin will be + enabled and disabled together with HP_L and HP_R pins in response to jack + detect events. + +Example: + +codec: wm8960@1a { + compatible = "wlf,wm8960"; + reg = <0x1a>; + + wlf,shared-lrclk; +}; diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index 4dc4e85116cd..99d6457c87ba 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -125,6 +125,7 @@ struct wm8960_priv { struct snd_soc_dapm_widget *out3; bool deemph; int playback_fs; + struct wm8960_data pdata; }; #define wm8960_reset(c) snd_soc_write(c, WM8960_RESET, 0) @@ -440,8 +441,8 @@ static const struct snd_soc_dapm_route audio_paths_capless[] = { static int wm8960_add_widgets(struct snd_soc_codec *codec) { - struct wm8960_data *pdata = codec->dev->platform_data; struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); + struct wm8960_data *pdata = &wm8960->pdata; struct snd_soc_dapm_context *dapm = &codec->dapm; struct snd_soc_dapm_widget *w; @@ -961,17 +962,13 @@ static int wm8960_resume(struct snd_soc_codec *codec) static int wm8960_probe(struct snd_soc_codec *codec) { struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); - struct wm8960_data *pdata = dev_get_platdata(codec->dev); + struct wm8960_data *pdata = &wm8960->pdata; int ret; - wm8960->set_bias_level = wm8960_set_bias_level_out3; - - if (!pdata) { - dev_warn(codec->dev, "No platform data supplied\n"); - } else { - if (pdata->capless) - wm8960->set_bias_level = wm8960_set_bias_level_capless; - } + if (pdata->capless) + wm8960->set_bias_level = wm8960_set_bias_level_capless; + else + wm8960->set_bias_level = wm8960_set_bias_level_out3; ret = wm8960_reset(codec); if (ret < 0) { @@ -1029,6 +1026,18 @@ static const struct regmap_config wm8960_regmap = { .volatile_reg = wm8960_volatile, }; +static void wm8960_set_pdata_from_of(struct i2c_client *i2c, + struct wm8960_data *pdata) +{ + const struct device_node *np = i2c->dev.of_node; + + if (of_property_read_bool(np, "wlf,capless")) + pdata->capless = true; + + if (of_property_read_bool(np, "wlf,shared-lrclk")) + pdata->shared_lrclk = true; +} + static int wm8960_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -1045,6 +1054,11 @@ static int wm8960_i2c_probe(struct i2c_client *i2c, if (IS_ERR(wm8960->regmap)) return PTR_ERR(wm8960->regmap); + if (pdata) + memcpy(&wm8960->pdata, pdata, sizeof(struct wm8960_data)); + else if (i2c->dev.of_node) + wm8960_set_pdata_from_of(i2c, &wm8960->pdata); + if (pdata && pdata->shared_lrclk) { ret = regmap_update_bits(wm8960->regmap, WM8960_ADDCTL2, 0x4, 0x4); @@ -1075,10 +1089,17 @@ static const struct i2c_device_id wm8960_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, wm8960_i2c_id); +static const struct of_device_id wm8960_of_match[] = { + { .compatible = "wlf,wm8960", }, + { } +}; +MODULE_DEVICE_TABLE(of, wm8960_of_match); + static struct i2c_driver wm8960_i2c_driver = { .driver = { .name = "wm8960", .owner = THIS_MODULE, + .of_match_table = wm8960_of_match, }, .probe = wm8960_i2c_probe, .remove = wm8960_i2c_remove, -- cgit v1.2.3-59-g8ed1b From 86dc1342bcbb1905b2ac9653a559b303f62bd728 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 19 Nov 2014 12:59:19 +0100 Subject: net: phy: micrel: add support for clock-mode select to KSZ8081/KSZ8091 Micrel KSZ8081 and KSZ8091 PHYs have the RMII Reference Clock Select bit, which is used to select 25 or 50 MHz clock mode. Note that on some revisions of the PHY (e.g. KSZ8081RND) the function of this bit is inverted so that setting it enables 25 rather than 50 MHz mode. Add a new device-tree property "micrel,rmii-reference-clock-select-25-mhz" to describe this. Signed-off-by: Johan Hovold Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/micrel.txt | 4 ++-- drivers/net/phy/micrel.c | 11 ++++++----- 2 files changed, 8 insertions(+), 7 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/micrel.txt b/Documentation/devicetree/bindings/net/micrel.txt index 30062fae5623..a1bab5eaae02 100644 --- a/Documentation/devicetree/bindings/net/micrel.txt +++ b/Documentation/devicetree/bindings/net/micrel.txt @@ -22,5 +22,5 @@ Optional properties: - clocks, clock-names: contains clocks according to the common clock bindings. supported clocks: - - KSZ8021, KSZ8031: "rmii-ref": The RMII refence input clock. Used - to determine the XI input clock. + - KSZ8021, KSZ8031, KSZ8081, KSZ8091: "rmii-ref": The RMII + refence input clock. Used to determine the XI input clock. diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index d2e790cd3651..04fbee846b66 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -102,6 +102,7 @@ static const struct kszphy_type ksz8051_type = { static const struct kszphy_type ksz8081_type = { .led_mode_reg = MII_KSZPHY_CTRL_2, .has_broadcast_disable = true, + .has_rmii_ref_clk_sel = true, }; static int kszphy_extended_write(struct phy_device *phydev, @@ -548,16 +549,16 @@ static int kszphy_probe(struct phy_device *phydev) clk = devm_clk_get(&phydev->dev, "rmii-ref"); if (!IS_ERR(clk)) { unsigned long rate = clk_get_rate(clk); + bool rmii_ref_clk_sel_25_mhz; priv->rmii_ref_clk_sel = type->has_rmii_ref_clk_sel; + rmii_ref_clk_sel_25_mhz = of_property_read_bool(np, + "micrel,rmii-reference-clock-select-25-mhz"); - /* FIXME: add support for PHY revisions that have this bit - * inverted (e.g. through new property or based on PHY ID). - */ if (rate > 24500000 && rate < 25500000) { - priv->rmii_ref_clk_sel_val = false; + priv->rmii_ref_clk_sel_val = rmii_ref_clk_sel_25_mhz; } else if (rate > 49500000 && rate < 50500000) { - priv->rmii_ref_clk_sel_val = true; + priv->rmii_ref_clk_sel_val = !rmii_ref_clk_sel_25_mhz; } else { dev_err(&phydev->dev, "Clock rate out of range: %ld\n", rate); return -EINVAL; -- cgit v1.2.3-59-g8ed1b From 6d01329444725a5c17cf75ba6c5c0c5e42843613 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 19 Nov 2014 12:59:20 +0100 Subject: dt/bindings: reformat micrel eth-phy documentation Reduce indentation of Micrel PHY binding documentations somewhat. Also fix "reference input clock" typo while at it. Cc: devicetree@vger.kernel.org Signed-off-by: Johan Hovold Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/micrel.txt | 26 ++++++++++++------------ 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/micrel.txt b/Documentation/devicetree/bindings/net/micrel.txt index a1bab5eaae02..20a6cac7abc6 100644 --- a/Documentation/devicetree/bindings/net/micrel.txt +++ b/Documentation/devicetree/bindings/net/micrel.txt @@ -6,21 +6,21 @@ Optional properties: - micrel,led-mode : LED mode value to set for PHYs with configurable LEDs. - Configure the LED mode with single value. The list of PHYs and - the bits that are currently supported: + Configure the LED mode with single value. The list of PHYs and the + bits that are currently supported: - KSZ8001: register 0x1e, bits 15..14 - KSZ8041: register 0x1e, bits 15..14 - KSZ8021: register 0x1f, bits 5..4 - KSZ8031: register 0x1f, bits 5..4 - KSZ8051: register 0x1f, bits 5..4 - KSZ8081: register 0x1f, bits 5..4 - KSZ8091: register 0x1f, bits 5..4 + KSZ8001: register 0x1e, bits 15..14 + KSZ8041: register 0x1e, bits 15..14 + KSZ8021: register 0x1f, bits 5..4 + KSZ8031: register 0x1f, bits 5..4 + KSZ8051: register 0x1f, bits 5..4 + KSZ8081: register 0x1f, bits 5..4 + KSZ8091: register 0x1f, bits 5..4 - See the respective PHY datasheet for the mode values. + See the respective PHY datasheet for the mode values. - clocks, clock-names: contains clocks according to the common clock bindings. - supported clocks: - - KSZ8021, KSZ8031, KSZ8081, KSZ8091: "rmii-ref": The RMII - refence input clock. Used to determine the XI input clock. + supported clocks: + - KSZ8021, KSZ8031, KSZ8081, KSZ8091: "rmii-ref": The RMII reference + input clock. Used to determine the XI input clock. -- cgit v1.2.3-59-g8ed1b From c3a8e1eddd6c140fbaaf957f7da8f2175f79623d Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 19 Nov 2014 12:59:21 +0100 Subject: dt/bindings: add clock-select function property to micrel phy binding Add "micrel,rmii-reference-clock-select-25-mhz" to Micrel ethernet PHY binding documentation. This property is needed to properly describe some revisions of Micrel PHYs which has the function of this configuration bit inverted so that setting it enables 25 MHz rather than 50 MHz clock mode. Note that a clock reference ("rmii-ref") is still needed to actually select either mode. Cc: devicetree@vger.kernel.org Signed-off-by: Johan Hovold Acked-by: Sascha Hauer Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/micrel.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/micrel.txt b/Documentation/devicetree/bindings/net/micrel.txt index 20a6cac7abc6..87496a8c64ab 100644 --- a/Documentation/devicetree/bindings/net/micrel.txt +++ b/Documentation/devicetree/bindings/net/micrel.txt @@ -19,6 +19,17 @@ Optional properties: See the respective PHY datasheet for the mode values. + - micrel,rmii-reference-clock-select-25-mhz: RMII Reference Clock Select + bit selects 25 MHz mode + + Setting the RMII Reference Clock Select bit enables 25 MHz rather + than 50 MHz clock mode. + + Note that this option in only needed for certain PHY revisions with a + non-standard, inverted function of this configuration bit. + Specifically, a clock reference ("rmii-ref" below) is always needed to + actually select a mode. + - clocks, clock-names: contains clocks according to the common clock bindings. supported clocks: -- cgit v1.2.3-59-g8ed1b From f8b8be8a310a55856fd2c369dade08088d85df3b Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Fri, 21 Nov 2014 05:25:16 -0500 Subject: ftrace, kprobes: Support IPMODIFY flag to find IP modify conflict Introduce FTRACE_OPS_FL_IPMODIFY to avoid conflict among ftrace users who may modify regs->ip to change the execution path. If two or more users modify the regs->ip on the same function entry, one of them will be broken. So they must add IPMODIFY flag and make sure that ftrace_set_filter_ip() succeeds. Note that ftrace doesn't allow ftrace_ops which has IPMODIFY flag to have notrace hash, and the ftrace_ops must have a filter hash (so that the ftrace_ops can hook only specific entries), because it strongly depends on the address and must be allowed for only few selected functions. Link: http://lkml.kernel.org/r/20141121102516.11844.27829.stgit@localhost.localdomain Cc: Jiri Kosina Cc: Seth Jennings Cc: Petr Mladek Cc: Vojtech Pavlik Cc: Miroslav Benes Cc: Ingo Molnar Cc: Ananth N Mavinakayanahalli Cc: Josh Poimboeuf Cc: Namhyung Kim Signed-off-by: Masami Hiramatsu [ fixed up some of the comments ] Signed-off-by: Steven Rostedt --- Documentation/trace/ftrace.txt | 5 ++ include/linux/ftrace.h | 16 ++++- kernel/trace/ftrace.c | 142 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 159 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/trace/ftrace.txt b/Documentation/trace/ftrace.txt index 4da42616939f..f10f5f5d260d 100644 --- a/Documentation/trace/ftrace.txt +++ b/Documentation/trace/ftrace.txt @@ -234,6 +234,11 @@ of ftrace. Here is a list of some of the key files: will be displayed on the same line as the function that is returning registers. + If the callback registered to be traced by a function with + the "ip modify" attribute (thus the regs->ip can be changed), + an 'I' will be displayed on the same line as the function that + can be overridden. + function_profile_enabled: When set it will enable all functions with either the function diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index 7b2616fa2472..ed501953f0b2 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h @@ -61,6 +61,11 @@ ftrace_func_t ftrace_ops_get_func(struct ftrace_ops *ops); /* * FTRACE_OPS_FL_* bits denote the state of ftrace_ops struct and are * set in the flags member. + * CONTROL, SAVE_REGS, SAVE_REGS_IF_SUPPORTED, RECURSION_SAFE, STUB and + * IPMODIFY are a kind of attribute flags which can be set only before + * registering the ftrace_ops, and can not be modified while registered. + * Changing those attribute flags after regsitering ftrace_ops will + * cause unexpected results. * * ENABLED - set/unset when ftrace_ops is registered/unregistered * DYNAMIC - set when ftrace_ops is registered to denote dynamically @@ -101,6 +106,10 @@ ftrace_func_t ftrace_ops_get_func(struct ftrace_ops *ops); * The ftrace_ops trampoline can be set by the ftrace users, and * in such cases the arch must not modify it. Only the arch ftrace * core code should set this flag. + * IPMODIFY - The ops can modify the IP register. This can only be set with + * SAVE_REGS. If another ops with this flag set is already registered + * for any of the functions that this ops will be registered for, then + * this ops will fail to register or set_filter_ip. */ enum { FTRACE_OPS_FL_ENABLED = 1 << 0, @@ -116,6 +125,7 @@ enum { FTRACE_OPS_FL_REMOVING = 1 << 10, FTRACE_OPS_FL_MODIFYING = 1 << 11, FTRACE_OPS_FL_ALLOC_TRAMP = 1 << 12, + FTRACE_OPS_FL_IPMODIFY = 1 << 13, }; #ifdef CONFIG_DYNAMIC_FTRACE @@ -310,6 +320,7 @@ bool is_ftrace_trampoline(unsigned long addr); * ENABLED - the function is being traced * REGS - the record wants the function to save regs * REGS_EN - the function is set up to save regs. + * IPMODIFY - the record allows for the IP address to be changed. * * When a new ftrace_ops is registered and wants a function to save * pt_regs, the rec->flag REGS is set. When the function has been @@ -323,10 +334,11 @@ enum { FTRACE_FL_REGS_EN = (1UL << 29), FTRACE_FL_TRAMP = (1UL << 28), FTRACE_FL_TRAMP_EN = (1UL << 27), + FTRACE_FL_IPMODIFY = (1UL << 26), }; -#define FTRACE_REF_MAX_SHIFT 27 -#define FTRACE_FL_BITS 5 +#define FTRACE_REF_MAX_SHIFT 26 +#define FTRACE_FL_BITS 6 #define FTRACE_FL_MASKED_BITS ((1UL << FTRACE_FL_BITS) - 1) #define FTRACE_FL_MASK (FTRACE_FL_MASKED_BITS << FTRACE_REF_MAX_SHIFT) #define FTRACE_REF_MAX ((1UL << FTRACE_REF_MAX_SHIFT) - 1) diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 588af40d33db..929a733d302e 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -1358,6 +1358,9 @@ ftrace_hash_rec_disable_modify(struct ftrace_ops *ops, int filter_hash); static void ftrace_hash_rec_enable_modify(struct ftrace_ops *ops, int filter_hash); +static int ftrace_hash_ipmodify_update(struct ftrace_ops *ops, + struct ftrace_hash *new_hash); + static int ftrace_hash_move(struct ftrace_ops *ops, int enable, struct ftrace_hash **dst, struct ftrace_hash *src) @@ -1368,8 +1371,13 @@ ftrace_hash_move(struct ftrace_ops *ops, int enable, struct ftrace_hash *new_hash; int size = src->count; int bits = 0; + int ret; int i; + /* Reject setting notrace hash on IPMODIFY ftrace_ops */ + if (ops->flags & FTRACE_OPS_FL_IPMODIFY && !enable) + return -EINVAL; + /* * If the new source is empty, just free dst and assign it * the empty_hash. @@ -1403,6 +1411,16 @@ ftrace_hash_move(struct ftrace_ops *ops, int enable, } update: + /* Make sure this can be applied if it is IPMODIFY ftrace_ops */ + if (enable) { + /* IPMODIFY should be updated only when filter_hash updating */ + ret = ftrace_hash_ipmodify_update(ops, new_hash); + if (ret < 0) { + free_ftrace_hash(new_hash); + return ret; + } + } + /* * Remove the current set, update the hash and add * them back. @@ -1767,6 +1785,114 @@ static void ftrace_hash_rec_enable_modify(struct ftrace_ops *ops, ftrace_hash_rec_update_modify(ops, filter_hash, 1); } +/* + * Try to update IPMODIFY flag on each ftrace_rec. Return 0 if it is OK + * or no-needed to update, -EBUSY if it detects a conflict of the flag + * on a ftrace_rec, and -EINVAL if the new_hash tries to trace all recs. + * Note that old_hash and new_hash has below meanings + * - If the hash is NULL, it hits all recs (if IPMODIFY is set, this is rejected) + * - If the hash is EMPTY_HASH, it hits nothing + * - Anything else hits the recs which match the hash entries. + */ +static int __ftrace_hash_update_ipmodify(struct ftrace_ops *ops, + struct ftrace_hash *old_hash, + struct ftrace_hash *new_hash) +{ + struct ftrace_page *pg; + struct dyn_ftrace *rec, *end = NULL; + int in_old, in_new; + + /* Only update if the ops has been registered */ + if (!(ops->flags & FTRACE_OPS_FL_ENABLED)) + return 0; + + if (!(ops->flags & FTRACE_OPS_FL_IPMODIFY)) + return 0; + + /* + * Since the IPMODIFY is a very address sensitive action, we do not + * allow ftrace_ops to set all functions to new hash. + */ + if (!new_hash || !old_hash) + return -EINVAL; + + /* Update rec->flags */ + do_for_each_ftrace_rec(pg, rec) { + /* We need to update only differences of filter_hash */ + in_old = !!ftrace_lookup_ip(old_hash, rec->ip); + in_new = !!ftrace_lookup_ip(new_hash, rec->ip); + if (in_old == in_new) + continue; + + if (in_new) { + /* New entries must ensure no others are using it */ + if (rec->flags & FTRACE_FL_IPMODIFY) + goto rollback; + rec->flags |= FTRACE_FL_IPMODIFY; + } else /* Removed entry */ + rec->flags &= ~FTRACE_FL_IPMODIFY; + } while_for_each_ftrace_rec(); + + return 0; + +rollback: + end = rec; + + /* Roll back what we did above */ + do_for_each_ftrace_rec(pg, rec) { + if (rec == end) + goto err_out; + + in_old = !!ftrace_lookup_ip(old_hash, rec->ip); + in_new = !!ftrace_lookup_ip(new_hash, rec->ip); + if (in_old == in_new) + continue; + + if (in_new) + rec->flags &= ~FTRACE_FL_IPMODIFY; + else + rec->flags |= FTRACE_FL_IPMODIFY; + } while_for_each_ftrace_rec(); + +err_out: + return -EBUSY; +} + +static int ftrace_hash_ipmodify_enable(struct ftrace_ops *ops) +{ + struct ftrace_hash *hash = ops->func_hash->filter_hash; + + if (ftrace_hash_empty(hash)) + hash = NULL; + + return __ftrace_hash_update_ipmodify(ops, EMPTY_HASH, hash); +} + +/* Disabling always succeeds */ +static void ftrace_hash_ipmodify_disable(struct ftrace_ops *ops) +{ + struct ftrace_hash *hash = ops->func_hash->filter_hash; + + if (ftrace_hash_empty(hash)) + hash = NULL; + + __ftrace_hash_update_ipmodify(ops, hash, EMPTY_HASH); +} + +static int ftrace_hash_ipmodify_update(struct ftrace_ops *ops, + struct ftrace_hash *new_hash) +{ + struct ftrace_hash *old_hash = ops->func_hash->filter_hash; + + if (ftrace_hash_empty(old_hash)) + old_hash = NULL; + + if (ftrace_hash_empty(new_hash)) + new_hash = NULL; + + return __ftrace_hash_update_ipmodify(ops, old_hash, new_hash); +} + static void print_ip_ins(const char *fmt, unsigned char *p) { int i; @@ -2436,6 +2562,15 @@ static int ftrace_startup(struct ftrace_ops *ops, int command) */ ops->flags |= FTRACE_OPS_FL_ENABLED | FTRACE_OPS_FL_ADDING; + ret = ftrace_hash_ipmodify_enable(ops); + if (ret < 0) { + /* Rollback registration process */ + __unregister_ftrace_function(ops); + ftrace_start_up--; + ops->flags &= ~FTRACE_OPS_FL_ENABLED; + return ret; + } + ftrace_hash_rec_enable(ops, 1); ftrace_startup_enable(command); @@ -2464,6 +2599,8 @@ static int ftrace_shutdown(struct ftrace_ops *ops, int command) */ WARN_ON_ONCE(ftrace_start_up < 0); + /* Disabling ipmodify never fails */ + ftrace_hash_ipmodify_disable(ops); ftrace_hash_rec_disable(ops, 1); ops->flags &= ~FTRACE_OPS_FL_ENABLED; @@ -3058,9 +3195,10 @@ static int t_show(struct seq_file *m, void *v) if (iter->flags & FTRACE_ITER_ENABLED) { struct ftrace_ops *ops = NULL; - seq_printf(m, " (%ld)%s", + seq_printf(m, " (%ld)%s%s", ftrace_rec_count(rec), - rec->flags & FTRACE_FL_REGS ? " R" : " "); + rec->flags & FTRACE_FL_REGS ? " R" : " ", + rec->flags & FTRACE_FL_IPMODIFY ? " I" : " "); if (rec->flags & FTRACE_FL_TRAMP_EN) { ops = ftrace_find_tramp_ops_any(rec); if (ops) -- cgit v1.2.3-59-g8ed1b From d574454160cf13c34bf25782b62524eb33679966 Mon Sep 17 00:00:00 2001 From: George McCollister Date: Mon, 17 Nov 2014 13:02:35 -0600 Subject: ARM: dts: Add devicetree for NovaTech OrionLXm This adds the NovaTech OrionLXm which is based on the AM335x SoC http://www.novatechweb.com/substation-automation/orionlxm/ RAM: 512MiB Flash: 4GB eMMC Ethernet PHYs: 2x Micrel KSZ8041FTLI USB ports are used internally by the expansion cards. Internal micro SD slot is available. Signed-off-by: George McCollister Reviewed-by: Felipe Balbi Signed-off-by: Tony Lindgren --- .../devicetree/bindings/arm/omap/omap.txt | 3 + arch/arm/boot/dts/Makefile | 3 +- arch/arm/boot/dts/am335x-lxm.dts | 362 +++++++++++++++++++++ 3 files changed, 367 insertions(+), 1 deletion(-) create mode 100644 arch/arm/boot/dts/am335x-lxm.dts (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/omap/omap.txt b/Documentation/devicetree/bindings/arm/omap/omap.txt index ddd9bcdf889c..4f6a82cef1d1 100644 --- a/Documentation/devicetree/bindings/arm/omap/omap.txt +++ b/Documentation/devicetree/bindings/arm/omap/omap.txt @@ -132,6 +132,9 @@ Boards: - AM335X Bone : Low cost community board compatible = "ti,am335x-bone", "ti,am33xx", "ti,omap3" +- AM335X OrionLXm : Substation Automation Platform + compatible = "novatech,am335x-lxm", "ti,am33xx" + - OMAP5 EVM : Evaluation Module compatible = "ti,omap5-evm", "ti,omap5" diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index a77cec87acbd..99b4df1c1f76 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -333,7 +333,8 @@ dtb-$(CONFIG_SOC_AM33XX) += am335x-base0033.dtb \ am335x-evm.dtb \ am335x-evmsk.dtb \ am335x-nano.dtb \ - am335x-pepper.dtb + am335x-pepper.dtb \ + am335x-lxm.dtb dtb-$(CONFIG_ARCH_OMAP4) += omap4-duovero-parlor.dtb \ omap4-panda.dtb \ omap4-panda-a4.dtb \ diff --git a/arch/arm/boot/dts/am335x-lxm.dts b/arch/arm/boot/dts/am335x-lxm.dts new file mode 100644 index 000000000000..7266a00aab2e --- /dev/null +++ b/arch/arm/boot/dts/am335x-lxm.dts @@ -0,0 +1,362 @@ +/* + * Copyright (C) 2014 NovaTech LLC - http://www.novatechweb.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +/dts-v1/; + +#include "am33xx.dtsi" + +/ { + model = "NovaTech OrionLXm"; + compatible = "novatech,am335x-lxm", "ti,am33xx"; + + cpus { + cpu@0 { + cpu0-supply = <&vdd1_reg>; + }; + }; + + memory { + device_type = "memory"; + reg = <0x80000000 0x20000000>; /* 512 MB */ + }; + + /* Power supply provides a fixed 5V @2A */ + vbat: fixedregulator@0 { + compatible = "regulator-fixed"; + regulator-name = "vbat"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-boot-on; + }; + + /* Power supply provides a fixed 3.3V @3A */ + vmmcsd_fixed: fixedregulator@1 { + compatible = "regulator-fixed"; + regulator-name = "vmmcsd_fixed"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + }; +}; + +&am33xx_pinmux { + mmc1_pins: pinmux_mmc1_pins { + pinctrl-single,pins = < + 0xf0 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat3 */ + 0xf4 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat2 */ + 0xf8 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat1 */ + 0xfc (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat0 */ + 0x100 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_clk */ + 0x104 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_cmd */ + >; + }; + + i2c0_pins: pinmux_i2c0_pins { + pinctrl-single,pins = < + 0x188 (PIN_INPUT | MUX_MODE0) /* i2c0_sda.i2c0_sda */ + 0x18c (PIN_INPUT | MUX_MODE0) /* i2c0_scl.i2c0_scl */ + >; + }; + + cpsw_default: cpsw_default { + pinctrl-single,pins = < + /* Slave 1 */ + 0x64 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii1_int */ + 0x10c (PIN_INPUT_PULLDOWN | MUX_MODE1) /* rmii1_crs_dv */ + 0x110 (PIN_INPUT_PULLDOWN | MUX_MODE1) /* rmii1_rxer */ + 0x114 (PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* rmii1_txen */ + 0x124 (PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* rmii1_td1 */ + 0x128 (PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* rmii1_td0 */ + 0x13c (PIN_INPUT_PULLDOWN | MUX_MODE1) /* rmii1_rd1 */ + 0x140 (PIN_INPUT_PULLDOWN | MUX_MODE1) /* rmii1_rd0 */ + 0x144 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* rmii1_refclk */ + + /* Slave 2 */ + 0x40 (PIN_OUTPUT_PULLDOWN | MUX_MODE3) /* rmii2_txen */ + 0x50 (PIN_OUTPUT_PULLDOWN | MUX_MODE3) /* rmii2_td1 */ + 0x54 (PIN_OUTPUT_PULLDOWN | MUX_MODE3) /* rmii2_td0 */ + 0x68 (PIN_INPUT_PULLDOWN | MUX_MODE3) /* rmii2_rd1 */ + 0x6c (PIN_INPUT_PULLDOWN | MUX_MODE3) /* rmii2_rd0 */ + 0x70 (PIN_INPUT_PULLDOWN | MUX_MODE3) /* rmii2_crs_dv */ + 0x74 (PIN_INPUT_PULLDOWN | MUX_MODE3) /* rmii2_rxer */ + 0x78 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii2_int */ + 0x108 (PIN_INPUT_PULLDOWN | MUX_MODE1) /* rmii2_refclk */ + >; + }; + + cpsw_sleep: cpsw_sleep { + pinctrl-single,pins = < + /* Slave 1 reset value */ + 0x64 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii1_int */ + 0x10c (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii1_crs_dv */ + 0x110 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii1_rxer */ + 0x114 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii1_txen */ + 0x124 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii1_td1 */ + 0x128 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii1_td0 */ + 0x13c (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii1_rd1 */ + 0x140 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii1_rd0 */ + 0x144 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii1_refclk */ + + /* Slave 2 reset value*/ + 0x40 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii2_txen */ + 0x50 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii2_td1 */ + 0x54 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii2_td0 */ + 0x68 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii2_rd1 */ + 0x6c (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii2_rd0 */ + 0x70 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii2_crs_dv */ + 0x74 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii2_rxer */ + 0x78 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii2_int */ + 0x108 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii2_refclk */ + >; + }; + + davinci_mdio_default: davinci_mdio_default { + pinctrl-single,pins = < + /* MDIO */ + 0x148 (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0) /* mdio_data.mdio_data */ + 0x14c (PIN_OUTPUT_PULLUP | MUX_MODE0) /* mdio_clk.mdio_clk */ + >; + }; + + davinci_mdio_sleep: davinci_mdio_sleep { + pinctrl-single,pins = < + /* MDIO reset value */ + 0x148 (PIN_INPUT_PULLDOWN | MUX_MODE7) + 0x14c (PIN_INPUT_PULLDOWN | MUX_MODE7) + >; + }; + + emmc_pins: pinmux_emmc_pins { + pinctrl-single,pins = < + 0x80 (PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn1.mmc1_clk */ + 0x84 (PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn2.mmc1_cmd */ + 0x00 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad0.mmc1_dat0 */ + 0x04 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad1.mmc1_dat1 */ + 0x08 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad2.mmc1_dat2 */ + 0x0c (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad3.mmc1_dat3 */ + 0x10 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad4.mmc1_dat4 */ + 0x14 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad5.mmc1_dat5 */ + 0x18 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad6.mmc1_dat6 */ + 0x1c (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad7.mmc1_dat7 */ + >; + }; + + uart0_pins: pinmux_uart0_pins { + pinctrl-single,pins = < + 0x170 (PIN_INPUT_PULLUP | MUX_MODE0) /* uart0_rxd.uart0_rxd */ + 0x174 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart0_txd.uart0_txd */ + >; + }; +}; + +&i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_pins>; + + status = "okay"; + clock-frequency = <400000>; + + serial_config1: serial_config1@20 { + compatible = "nxp,pca9539"; + reg = <0x20>; + }; + + serial_config2: serial_config2@21 { + compatible = "nxp,pca9539"; + reg = <0x21>; + }; + + tps: tps@2d { + compatible = "ti,tps65910"; + reg = <0x2d>; + }; +}; + +/include/ "tps65910.dtsi" + +&tps { + vcc1-supply = <&vbat>; + vcc2-supply = <&vbat>; + vcc3-supply = <&vbat>; + vcc4-supply = <&vbat>; + vcc5-supply = <&vbat>; + vcc6-supply = <&vbat>; + vcc7-supply = <&vbat>; + vccio-supply = <&vbat>; + + regulators { + /* vrtc - unused */ + + vio_reg: regulator@1 { + regulator-name = "vio_1v5,ddr"; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <1500000>; + regulator-boot-on; + regulator-always-on; + }; + + vdd1_reg: regulator@2 { + regulator-name = "vdd1,mpu"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <1500000>; + regulator-boot-on; + regulator-always-on; + }; + + vdd2_reg: regulator@3 { + regulator-name = "vdd2_1v1,core"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-boot-on; + regulator-always-on; + }; + + /* vdd3 - unused */ + + /* vdig1 - unused */ + + vdig2_reg: regulator@6 { + regulator-name = "vdig2_1v8,vdds_pll"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + /* vpll - unused */ + + vdac_reg: regulator@8 { + regulator-name = "vdac_1v8,vdds"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + vaux1_reg: regulator@9 { + regulator-name = "vaux1_1v8,usb"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + vaux2_reg: regulator@10 { + regulator-name = "vaux2_3v3,io"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + vaux33_reg: regulator@11 { + regulator-name = "vaux33_3v3,usb"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + vmmc_reg: regulator@12 { + regulator-name = "vmmc_3v3,io"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + }; +}; + +&sham { + status = "okay"; +}; + +&aes { + status = "okay"; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pins>; + + status = "okay"; +}; + +&usb { + status = "okay"; +}; + +&usb_ctrl_mod { + status = "okay"; +}; + +&usb0_phy { + status = "okay"; +}; + +&usb1_phy { + status = "okay"; +}; + +&usb0 { + status = "okay"; + dr_mode = "host"; +}; + +&usb1 { + status = "okay"; + dr_mode = "host"; +}; + +&cppi41dma { + status = "okay"; +}; + +&cpsw_emac0 { + phy_id = <&davinci_mdio>, <5>; + phy-mode = "rmii"; + dual_emac_res_vlan = <2>; +}; + +&cpsw_emac1 { + phy_id = <&davinci_mdio>, <4>; + phy-mode = "rmii"; + dual_emac_res_vlan = <3>; +}; + +&mac { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&cpsw_default>; + pinctrl-1 = <&cpsw_sleep>; + dual_emac = <1>; + status = "okay"; +}; + +&davinci_mdio { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&davinci_mdio_default>; + pinctrl-1 = <&davinci_mdio_sleep>; + status = "okay"; +}; + +&mmc1 { + pinctrl-names = "default"; + pinctrl-0 = <&mmc1_pins>; + vmmc-supply = <&vmmcsd_fixed>; + bus-width = <4>; + status = "okay"; +}; + +&mmc2 { + pinctrl-names = "default"; + pinctrl-0 = <&emmc_pins>; + vmmc-supply = <&vmmcsd_fixed>; + bus-width = <8>; + ti,non-removable; + status = "okay"; +}; + -- cgit v1.2.3-59-g8ed1b From e92293a2a7edc68a37ee124b6665ca240fb2ce07 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Fri, 21 Nov 2014 16:59:58 +0100 Subject: Documentation: dt-bindings: minimal documentation for MVEBU SDRAM controller The suspend/resume code for Armada XP has to modify certain registers of the SDRAM controller. Therefore, we need to define a Device Tree binding for this hardware block. Signed-off-by: Thomas Petazzoni Cc: devicetree@vger.kernel.org Cc: Kumar Gala Cc: Ian Campbell Cc: Mark Rutland Cc: Rob Herring Reviewed-by: Gregory CLEMENT Link: https://lkml.kernel.org/r/1416585613-2113-2-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- .../memory-controllers/mvebu-sdram-controller.txt | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 Documentation/devicetree/bindings/memory-controllers/mvebu-sdram-controller.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/memory-controllers/mvebu-sdram-controller.txt b/Documentation/devicetree/bindings/memory-controllers/mvebu-sdram-controller.txt new file mode 100644 index 000000000000..89657d1d4cd4 --- /dev/null +++ b/Documentation/devicetree/bindings/memory-controllers/mvebu-sdram-controller.txt @@ -0,0 +1,21 @@ +Device Tree bindings for MVEBU SDRAM controllers + +The Marvell EBU SoCs all have a SDRAM controller. The SDRAM controller +differs from one SoC variant to another, but they also share a number +of commonalities. + +For now, this Device Tree binding documentation only documents the +Armada XP SDRAM controller. + +Required properties: + + - compatible: for Armada XP, "marvell,armada-xp-sdram-controller" + - reg: a resource specifier for the register space, which should + include all SDRAM controller registers as per the datasheet. + +Example: + +sdramc@1400 { + compatible = "marvell,armada-xp-sdram-controller"; + reg = <0x1400 0x500>; +}; -- cgit v1.2.3-59-g8ed1b From 9bde18c1b5d2c9a1b90fc0f3bbe1a314194f6fdf Mon Sep 17 00:00:00 2001 From: Vivek Gautam Date: Fri, 21 Nov 2014 19:05:48 +0530 Subject: phy: exynos5-usbdrd: Add pipe-clk, utmi-clk and itp-clk support Exynos7 SoC has now separate gate control for 125MHz pipe3 phy clock, as well as 60MHz utmi phy clock. Additionally, separate gate control is available for the clock used for ITP (Isochronous Transfer Packet) generation. So get the same and control in the phy-exynos5-usbdrd driver. Suggested-by: Anton Tikhomirov Signed-off-by: Vivek Gautam Signed-off-by: Kishon Vijay Abraham I --- .../devicetree/bindings/phy/samsung-phy.txt | 6 ++ drivers/phy/phy-exynos5-usbdrd.c | 104 +++++++++++++++++---- 2 files changed, 92 insertions(+), 18 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/phy/samsung-phy.txt b/Documentation/devicetree/bindings/phy/samsung-phy.txt index 15e0f2c7130f..d5bad920827f 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,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 - clock-names: names of clocks correseponding to IDs in the clock property; @@ -138,6 +139,11 @@ 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 + gate clocks available: + - phy_pipe: for PIPE3 phy + - phy_utmi: for UTMI+ phy + - itp: for ITP generation - samsung,pmu-syscon: phandle for PMU system controller interface, used to control pmu registers for power isolation. - #phy-cells : from the generic PHY bindings, must be 1; diff --git a/drivers/phy/phy-exynos5-usbdrd.c b/drivers/phy/phy-exynos5-usbdrd.c index b3ca3bc2314f..99ba56dc63dd 100644 --- a/drivers/phy/phy-exynos5-usbdrd.c +++ b/drivers/phy/phy-exynos5-usbdrd.c @@ -141,6 +141,7 @@ struct exynos5_usbdrd_phy_drvdata { const struct exynos5_usbdrd_phy_config *phy_cfg; u32 pmu_offset_usbdrd0_phy; u32 pmu_offset_usbdrd1_phy; + bool has_common_clk_gate; }; /** @@ -148,6 +149,9 @@ struct exynos5_usbdrd_phy_drvdata { * @dev: pointer to device instance of this platform device * @reg_phy: usb phy controller register memory base * @clk: phy clock for register access + * @pipeclk: clock for pipe3 phy + * @utmiclk: clock for utmi+ phy + * @itpclk: clock for ITP generation * @drv_data: pointer to SoC level driver data structure * @phys[]: array for 'EXYNOS5_DRDPHYS_NUM' number of PHY * instances each with its 'phy' and 'phy_cfg'. @@ -155,12 +159,14 @@ struct exynos5_usbdrd_phy_drvdata { * reference clocks' for SS and HS operations * @ref_clk: reference clock to PHY block from which PHY's * operational clocks are derived - * @ref_rate: rate of above reference clock */ struct exynos5_usbdrd_phy { struct device *dev; void __iomem *reg_phy; struct clk *clk; + struct clk *pipeclk; + struct clk *utmiclk; + struct clk *itpclk; const struct exynos5_usbdrd_phy_drvdata *drv_data; struct phy_usb_instance { struct phy *phy; @@ -447,6 +453,11 @@ static int exynos5_usbdrd_phy_power_on(struct phy *phy) dev_dbg(phy_drd->dev, "Request to power_on usbdrd_phy phy\n"); clk_prepare_enable(phy_drd->ref_clk); + if (!phy_drd->drv_data->has_common_clk_gate) { + clk_prepare_enable(phy_drd->pipeclk); + clk_prepare_enable(phy_drd->utmiclk); + clk_prepare_enable(phy_drd->itpclk); + } /* Enable VBUS supply */ if (phy_drd->vbus) { @@ -464,6 +475,11 @@ static int exynos5_usbdrd_phy_power_on(struct phy *phy) fail_vbus: clk_disable_unprepare(phy_drd->ref_clk); + if (!phy_drd->drv_data->has_common_clk_gate) { + clk_disable_unprepare(phy_drd->itpclk); + clk_disable_unprepare(phy_drd->utmiclk); + clk_disable_unprepare(phy_drd->pipeclk); + } return ret; } @@ -483,6 +499,11 @@ static int exynos5_usbdrd_phy_power_off(struct phy *phy) regulator_disable(phy_drd->vbus); clk_disable_unprepare(phy_drd->ref_clk); + if (!phy_drd->drv_data->has_common_clk_gate) { + clk_disable_unprepare(phy_drd->itpclk); + clk_disable_unprepare(phy_drd->pipeclk); + clk_disable_unprepare(phy_drd->utmiclk); + } return 0; } @@ -506,6 +527,57 @@ static struct phy_ops exynos5_usbdrd_phy_ops = { .owner = THIS_MODULE, }; +static int exynos5_usbdrd_phy_clk_handle(struct exynos5_usbdrd_phy *phy_drd) +{ + unsigned long ref_rate; + int ret; + + phy_drd->clk = devm_clk_get(phy_drd->dev, "phy"); + if (IS_ERR(phy_drd->clk)) { + dev_err(phy_drd->dev, "Failed to get phy clock\n"); + return PTR_ERR(phy_drd->clk); + } + + phy_drd->ref_clk = devm_clk_get(phy_drd->dev, "ref"); + if (IS_ERR(phy_drd->ref_clk)) { + dev_err(phy_drd->dev, "Failed to get phy reference clock\n"); + return PTR_ERR(phy_drd->ref_clk); + } + ref_rate = clk_get_rate(phy_drd->ref_clk); + + ret = exynos5_rate_to_clk(ref_rate, &phy_drd->extrefclk); + if (ret) { + dev_err(phy_drd->dev, "Clock rate (%ld) not supported\n", + ref_rate); + return ret; + } + + if (!phy_drd->drv_data->has_common_clk_gate) { + phy_drd->pipeclk = devm_clk_get(phy_drd->dev, "phy_pipe"); + if (IS_ERR(phy_drd->pipeclk)) { + dev_info(phy_drd->dev, + "PIPE3 phy operational clock not specified\n"); + phy_drd->pipeclk = NULL; + } + + phy_drd->utmiclk = devm_clk_get(phy_drd->dev, "phy_utmi"); + if (IS_ERR(phy_drd->utmiclk)) { + dev_info(phy_drd->dev, + "UTMI phy operational clock not specified\n"); + phy_drd->utmiclk = NULL; + } + + phy_drd->itpclk = devm_clk_get(phy_drd->dev, "itp"); + if (IS_ERR(phy_drd->itpclk)) { + dev_info(phy_drd->dev, + "ITP clock from main OSC not specified\n"); + phy_drd->itpclk = NULL; + } + } + + return 0; +} + static const struct exynos5_usbdrd_phy_config phy_cfg_exynos5[] = { { .id = EXYNOS5_DRDPHY_UTMI, @@ -525,11 +597,19 @@ static const struct exynos5_usbdrd_phy_drvdata exynos5420_usbdrd_phy = { .phy_cfg = phy_cfg_exynos5, .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL, .pmu_offset_usbdrd1_phy = EXYNOS5420_USBDRD1_PHY_CONTROL, + .has_common_clk_gate = true, }; static const struct exynos5_usbdrd_phy_drvdata exynos5250_usbdrd_phy = { .phy_cfg = phy_cfg_exynos5, .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL, + .has_common_clk_gate = true, +}; + +static const struct exynos5_usbdrd_phy_drvdata exynos7_usbdrd_phy = { + .phy_cfg = phy_cfg_exynos5, + .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL, + .has_common_clk_gate = false, }; static const struct of_device_id exynos5_usbdrd_phy_of_match[] = { @@ -539,6 +619,9 @@ static const struct of_device_id exynos5_usbdrd_phy_of_match[] = { }, { .compatible = "samsung,exynos5420-usbdrd-phy", .data = &exynos5420_usbdrd_phy + }, { + .compatible = "samsung,exynos7-usbdrd-phy", + .data = &exynos7_usbdrd_phy }, { }, }; @@ -555,7 +638,6 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev) const struct exynos5_usbdrd_phy_drvdata *drv_data; struct regmap *reg_pmu; u32 pmu_offset; - unsigned long ref_rate; int i, ret; int channel; @@ -576,23 +658,9 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev) drv_data = match->data; phy_drd->drv_data = drv_data; - phy_drd->clk = devm_clk_get(dev, "phy"); - if (IS_ERR(phy_drd->clk)) { - dev_err(dev, "Failed to get clock of phy controller\n"); - return PTR_ERR(phy_drd->clk); - } - - phy_drd->ref_clk = devm_clk_get(dev, "ref"); - if (IS_ERR(phy_drd->ref_clk)) { - dev_err(dev, "Failed to get reference clock of usbdrd phy\n"); - return PTR_ERR(phy_drd->ref_clk); - } - ref_rate = clk_get_rate(phy_drd->ref_clk); - - ret = exynos5_rate_to_clk(ref_rate, &phy_drd->extrefclk); + ret = exynos5_usbdrd_phy_clk_handle(phy_drd); if (ret) { - dev_err(phy_drd->dev, "Clock rate (%ld) not supported\n", - ref_rate); + dev_err(dev, "Failed to initialize clocks\n"); return ret; } -- cgit v1.2.3-59-g8ed1b From 3db47dc0ae4d370ec3c86fc357608132ca695c27 Mon Sep 17 00:00:00 2001 From: Robin Gong Date: Wed, 12 Nov 2014 16:20:38 +0800 Subject: power: reset: imx-snvs-poweroff: add power off driver for i.mx6 This driver register pm_power_off with snvs power off function. If your boards NOT use PMIC_ON_REQ to turn on/off external pmic, or use other pin to do, please disable the driver in dts, otherwise, your pm_power_off maybe overwrote by this driver. Signed-off-by: Robin Gong Acked-By: Sebastian Reichel Signed-off-by: Shawn Guo --- .../bindings/power_supply/imx-snvs-poweroff.txt | 23 ++++++++ drivers/power/reset/Kconfig | 9 +++ drivers/power/reset/Makefile | 1 + drivers/power/reset/imx-snvs-poweroff.c | 66 ++++++++++++++++++++++ 4 files changed, 99 insertions(+) create mode 100644 Documentation/devicetree/bindings/power_supply/imx-snvs-poweroff.txt create mode 100644 drivers/power/reset/imx-snvs-poweroff.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/power_supply/imx-snvs-poweroff.txt b/Documentation/devicetree/bindings/power_supply/imx-snvs-poweroff.txt new file mode 100644 index 000000000000..dc7c9bad63ea --- /dev/null +++ b/Documentation/devicetree/bindings/power_supply/imx-snvs-poweroff.txt @@ -0,0 +1,23 @@ +i.mx6 Poweroff Driver + +SNVS_LPCR in SNVS module can power off the whole system by pull +PMIC_ON_REQ low if PMIC_ON_REQ is connected with external PMIC. +If you don't want to use PMIC_ON_REQ as power on/off control, +please set status='disabled' to disable this driver. + +Required Properties: +-compatible: "fsl,sec-v4.0-poweroff" +-reg: Specifies the physical address of the SNVS_LPCR register + +Example: + snvs@020cc000 { + compatible = "fsl,sec-v4.0-mon", "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x020cc000 0x4000>; + ..... + snvs_poweroff: snvs-poweroff@38 { + compatible = "fsl,sec-v4.0-poweroff"; + reg = <0x38 0x4>; + }; + } diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index f65ff49bb275..028e76504519 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -71,6 +71,15 @@ config POWER_RESET_HISI help Reboot support for Hisilicon boards. +config POWER_RESET_IMX + bool "IMX6 power-off driver" + depends on POWER_RESET && SOC_IMX6 + help + This driver support power off external PMIC by PMIC_ON_REQ on i.mx6 + boards.If you want to use other pin to control external power,please + say N here or disable in dts to make sure pm_power_off never be + overwrote wrongly by this driver. + config POWER_RESET_MSM bool "Qualcomm MSM power-off driver" depends on ARCH_QCOM diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile index 76ce1c59469b..1d4804d6b323 100644 --- a/drivers/power/reset/Makefile +++ b/drivers/power/reset/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_POWER_RESET_BRCMSTB) += brcmstb-reboot.o obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o obj-$(CONFIG_POWER_RESET_HISI) += hisi-reboot.o +obj-$(CONFIG_POWER_RESET_IMX) += imx-snvs-poweroff.o obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o obj-$(CONFIG_POWER_RESET_LTC2952) += ltc2952-poweroff.o obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o diff --git a/drivers/power/reset/imx-snvs-poweroff.c b/drivers/power/reset/imx-snvs-poweroff.c new file mode 100644 index 000000000000..ad6ce5020ea7 --- /dev/null +++ b/drivers/power/reset/imx-snvs-poweroff.c @@ -0,0 +1,66 @@ +/* Power off driver for i.mx6 + * Copyright (c) 2014, FREESCALE CORPORATION. All rights reserved. + * + * based on msm-poweroff.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 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 + +static void __iomem *snvs_base; + +static void do_imx_poweroff(void) +{ + u32 value = readl(snvs_base); + + /* set TOP and DP_EN bit */ + writel(value | 0x60, snvs_base); +} + +static int imx_poweroff_probe(struct platform_device *pdev) +{ + snvs_base = of_iomap(pdev->dev.of_node, 0); + if (!snvs_base) { + dev_err(&pdev->dev, "failed to get memory\n"); + return -ENODEV; + } + + pm_power_off = do_imx_poweroff; + return 0; +} + +static const struct of_device_id of_imx_poweroff_match[] = { + { .compatible = "fsl,sec-v4.0-poweroff", }, + {}, +}; +MODULE_DEVICE_TABLE(of, of_imx_poweroff_match); + +static struct platform_driver imx_poweroff_driver = { + .probe = imx_poweroff_probe, + .driver = { + .name = "imx-snvs-poweroff", + .of_match_table = of_match_ptr(of_imx_poweroff_match), + }, +}; + +static int __init imx_poweroff_init(void) +{ + return platform_driver_register(&imx_poweroff_driver); +} +device_initcall(imx_poweroff_init); -- cgit v1.2.3-59-g8ed1b From c3096cd4189bab5900e4723705cd0c3ee4d0f2e2 Mon Sep 17 00:00:00 2001 From: Soeren Moch Date: Mon, 27 Oct 2014 20:10:50 +0100 Subject: devicetree: bindings: Add vendor prefix for TBS Technologies TBS Technologies is a company which specializes in developing, producing and marketing of digital TV tuner cards for PCs. for additional details refer to http://www.tbsdtv.com/about-us.html Signed-off-by: Soeren Moch Acked-by: Rob Herring Signed-off-by: Shawn Guo --- 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 723999d73744..776f4af2155d 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -146,6 +146,7 @@ st STMicroelectronics ste ST-Ericsson stericsson ST-Ericsson synology Synology, Inc. +tbs TBS Technologies thine THine Electronics, Inc. ti Texas Instruments tlm Trusted Logic Mobility -- cgit v1.2.3-59-g8ed1b From 7e41a98dcc1b220c2c705f839ba76787c08858d3 Mon Sep 17 00:00:00 2001 From: Jingchang Lu Date: Fri, 31 Oct 2014 17:01:11 +0800 Subject: dt-bindings: arm: add Freescale LS1021A SoC device tree binding Signed-off-by: Jingchang Lu Signed-off-by: Shawn Guo --- Documentation/devicetree/bindings/arm/fsl.txt | 38 +++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/fsl.txt b/Documentation/devicetree/bindings/arm/fsl.txt index e935d7d4ac43..4e8b7df7fc62 100644 --- a/Documentation/devicetree/bindings/arm/fsl.txt +++ b/Documentation/devicetree/bindings/arm/fsl.txt @@ -74,3 +74,41 @@ Required root node properties: i.MX6q generic board Required root node properties: - compatible = "fsl,imx6q"; + + +Freescale LS1021A Platform Device Tree Bindings +------------------------------------------------ + +Required root node compatible properties: + - compatible = "fsl,ls1021a"; + +Freescale LS1021A SoC-specific Device Tree Bindings +------------------------------------------- + +Freescale SCFG + SCFG is the supplemental configuration unit, that provides SoC specific +configuration and status registers for the chip. Such as getting PEX port +status. + Required properties: + - compatible: should be "fsl,ls1021a-scfg" + - reg: should contain base address and length of SCFG memory-mapped registers + +Example: + scfg: scfg@1570000 { + compatible = "fsl,ls1021a-scfg"; + reg = <0x0 0x1570000 0x0 0x10000>; + }; + +Freescale DCFG + DCFG is the device configuration unit, that provides general purpose +configuration and status for the device. Such as setting the secondary +core start address and release the secondary core from holdoff and startup. + Required properties: + - compatible: should be "fsl,ls1021a-dcfg" + - reg : should contain base address and length of DCFG memory-mapped registers + +Example: + dcfg: dcfg@1ee0000 { + compatible = "fsl,ls1021a-dcfg"; + reg = <0x0 0x1ee0000 0x0 0x10000>; + }; -- cgit v1.2.3-59-g8ed1b From 3f3ebfb84aad46e3b49a41fe2ed9037835b2860e Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Sun, 2 Nov 2014 21:36:44 +0100 Subject: ARM: dts: vf610: assign oscillator to clock module The clock controller module (CCM) has several clock inputs, which are connected to external crystal oscillators. To reflect this, assign these fixed clocks to the CCM node directly. This especially resolves initialization order dependencies we had with the earlier initialization code: When resolving of the fixed clocks failed in clk-vf610, the code created fixed clocks with a rate of 0. Signed-off-by: Stefan Agner Signed-off-by: Shawn Guo --- .../devicetree/bindings/clock/vf610-clock.txt | 15 +++++++++++++ arch/arm/boot/dts/vf610-cosmic.dts | 14 ++++++------ arch/arm/boot/dts/vf610-twr.dts | 25 ++++++++++++---------- arch/arm/boot/dts/vf610.dtsi | 25 ++++++++++------------ 4 files changed, 48 insertions(+), 31 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/vf610-clock.txt b/Documentation/devicetree/bindings/clock/vf610-clock.txt index c80863d344ac..63f9f1ac3439 100644 --- a/Documentation/devicetree/bindings/clock/vf610-clock.txt +++ b/Documentation/devicetree/bindings/clock/vf610-clock.txt @@ -5,6 +5,19 @@ Required properties: - reg: Address and length of the register set - #clock-cells: Should be <1> +Optional properties: +- clocks: list of clock identifiers which are external input clocks to the + given clock controller. Please refer the next section to find + the input clocks for a given controller. +- clock-names: list of names of clocks which are exteral input clocks to the + given clock controller. + +Input clocks for top clock controller: + - sxosc (external crystal oscillator 32KHz, recommended) + - fxosc (external crystal oscillator 24MHz, recommended) + - audio_ext + - enet_ext + The clock consumer should specify the desired clock by having the clock ID in its "clocks" phandle cell. See include/dt-bindings/clock/vf610-clock.h for the full list of VF610 clock IDs. @@ -15,6 +28,8 @@ clks: ccm@4006b000 { compatible = "fsl,vf610-ccm"; reg = <0x4006b000 0x1000>; #clock-cells = <1>; + clocks = <&sxosc>, <&fxosc>; + clock-names = "sxosc", "fxosc"; }; uart1: serial@40028000 { diff --git a/arch/arm/boot/dts/vf610-cosmic.dts b/arch/arm/boot/dts/vf610-cosmic.dts index 3fd1b74e1216..b0ce8b8b2e0e 100644 --- a/arch/arm/boot/dts/vf610-cosmic.dts +++ b/arch/arm/boot/dts/vf610-cosmic.dts @@ -23,14 +23,16 @@ reg = <0x80000000 0x10000000>; }; - clocks { - enet_ext { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <50000000>; - }; + enet_ext: enet_ext { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <50000000>; }; +}; +&clks { + clocks = <&sxosc>, <&fxosc>, <&enet_ext>; + clock-names = "sxosc", "fxosc", "enet_ext"; }; &fec1 { diff --git a/arch/arm/boot/dts/vf610-twr.dts b/arch/arm/boot/dts/vf610-twr.dts index 189b6975fe7d..7d06d1a367a5 100644 --- a/arch/arm/boot/dts/vf610-twr.dts +++ b/arch/arm/boot/dts/vf610-twr.dts @@ -22,18 +22,16 @@ reg = <0x80000000 0x8000000>; }; - clocks { - audio_ext { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <24576000>; - }; + audio_ext: mclk_osc { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24576000>; + }; - enet_ext { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <50000000>; - }; + enet_ext: eth_osc { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <50000000>; }; regulators { @@ -95,6 +93,11 @@ status = "okay"; }; +&clks { + clocks = <&sxosc>, <&fxosc>, <&enet_ext>, <&audio_ext>; + clock-names = "sxosc", "fxosc", "enet_ext", "audio_ext"; +}; + &dspi0 { bus-num = <0>; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/vf610.dtsi b/arch/arm/boot/dts/vf610.dtsi index 699da487222d..ed12d9a7be3e 100644 --- a/arch/arm/boot/dts/vf610.dtsi +++ b/arch/arm/boot/dts/vf610.dtsi @@ -44,21 +44,16 @@ }; }; - clocks { - #address-cells = <1>; - #size-cells = <0>; - - sxosc { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <32768>; - }; + fxosc: fxosc { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + }; - fxosc { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <24000000>; - }; + sxosc: sxosc { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <32768>; }; soc { @@ -358,6 +353,8 @@ clks: ccm@4006b000 { compatible = "fsl,vf610-ccm"; reg = <0x4006b000 0x1000>; + clocks = <&sxosc>, <&fxosc>; + clock-names = "sxosc", "fxosc"; #clock-cells = <1>; }; -- cgit v1.2.3-59-g8ed1b From f8264e34965aaf43203912ed8f7b543c00c8d70f Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 6 Nov 2014 22:20:14 +0800 Subject: irqdomain: Introduce new interfaces to support hierarchy irqdomains We plan to use hierarchy irqdomain to suppport CPU vector assignment, interrupt remapping controller, IO-APIC controller, MSI interrupt and hypertransport interrupt etc on x86 platforms. So extend irqdomain interfaces to support hierarchy irqdomain. There are already many clients of current irqdomain interfaces. To minimize the changes, we choose to introduce new version 2 interfaces to support hierarchy instead of extending existing irqdomain interfaces. According to Thomas's suggestion, the most important design decision is to build hierarchy struct irq_data to support hierarchy irqdomain, so hierarchy irqdomain related data could be saved in struct irq_data. With support of hierarchy irq_data, we could also support stacked irq_chips. This is most useful in case of set_affinity(). The new hierarchy irqdomain introduces following interfaces: 1) irq_domain_alloc_irqs()/irq_domain_free_irqs(): allocate/release IRQ and related resources. 2) __irq_domain_alloc_irqs(): a special version to support legacy IRQs. 3) irq_domain_activate_irq()/irq_domain_deactivate_irq(): program interrupt controllers to activate/deactivate interrupt. There are also several help functions to ease irqdomain implemenations: 1) irq_domain_get_irq_data(): get irq_data associated with a specific irqdomain. 2) irq_domain_set_hwirq_and_chip(): save irqdomain specific data into irq_data. 3) irq_domain_alloc_irqs_parent()/irq_domain_free_irqs_parent(): invoke parent irqdomain's alloc/free callbacks. We also changed irq_startup()/irq_shutdown() to invoke irq_domain_activate_irq()/irq_domain_deactivate_irq() to program interrupt controller when start/stop interrupts. [ tglx: Folded parts of the later patch series in ] Signed-off-by: Jiang Liu Cc: Bjorn Helgaas Cc: Grant Likely Cc: Marc Zyngier Cc: Yingjoe Chen Cc: Yijing Wang Signed-off-by: Thomas Gleixner --- Documentation/IRQ-domain.txt | 71 ++++++++ include/linux/irq.h | 5 + include/linux/irqdomain.h | 98 ++++++++++ kernel/irq/Kconfig | 5 + kernel/irq/chip.c | 3 + kernel/irq/irqdomain.c | 415 +++++++++++++++++++++++++++++++++++++++++-- 6 files changed, 581 insertions(+), 16 deletions(-) (limited to 'Documentation') diff --git a/Documentation/IRQ-domain.txt b/Documentation/IRQ-domain.txt index 8a8b82c9ca53..39cfa72732ff 100644 --- a/Documentation/IRQ-domain.txt +++ b/Documentation/IRQ-domain.txt @@ -151,3 +151,74 @@ used and no descriptor gets allocated it is very important to make sure that the driver using the simple domain call irq_create_mapping() before any irq_find_mapping() since the latter will actually work for the static IRQ assignment case. + +==== Hierarchy IRQ domain ==== +On some architectures, there may be multiple interrupt controllers +involved in delivering an interrupt from the device to the target CPU. +Let's look at a typical interrupt delivering path on x86 platforms: + +Device --> IOAPIC -> Interrupt remapping Controller -> Local APIC -> CPU + +There are three interrupt controllers involved: +1) IOAPIC controller +2) Interrupt remapping controller +3) Local APIC controller + +To support such a hardware topology and make software architecture match +hardware architecture, an irq_domain data structure is built for each +interrupt controller and those irq_domains are organized into hierarchy. +When building irq_domain hierarchy, the irq_domain near to the device is +child and the irq_domain near to CPU is parent. So a hierarchy structure +as below will be built for the example above. + CPU Vector irq_domain (root irq_domain to manage CPU vectors) + ^ + | + Interrupt Remapping irq_domain (manage irq_remapping entries) + ^ + | + IOAPIC irq_domain (manage IOAPIC delivery entries/pins) + +There are four major interfaces to use hierarchy irq_domain: +1) irq_domain_alloc_irqs(): allocate IRQ descriptors and interrupt + controller related resources to deliver these interrupts. +2) irq_domain_free_irqs(): free IRQ descriptors and interrupt controller + related resources associated with these interrupts. +3) irq_domain_activate_irq(): activate interrupt controller hardware to + deliver the interrupt. +3) irq_domain_deactivate_irq(): deactivate interrupt controller hardware + to stop delivering the interrupt. + +Following changes are needed to support hierarchy irq_domain. +1) a new field 'parent' is added to struct irq_domain; it's used to + maintain irq_domain hierarchy information. +2) a new field 'parent_data' is added to struct irq_data; it's used to + build hierarchy irq_data to match hierarchy irq_domains. The irq_data + is used to store irq_domain pointer and hardware irq number. +3) new callbacks are added to struct irq_domain_ops to support hierarchy + irq_domain operations. + +With support of hierarchy irq_domain and hierarchy irq_data ready, an +irq_domain structure is built for each interrupt controller, and an +irq_data structure is allocated for each irq_domain associated with an +IRQ. Now we could go one step further to support stacked(hierarchy) +irq_chip. That is, an irq_chip is associated with each irq_data along +the hierarchy. A child irq_chip may implement a required action by +itself or by cooperating with its parent irq_chip. + +With stacked irq_chip, interrupt controller driver only needs to deal +with the hardware managed by itself and may ask for services from its +parent irq_chip when needed. So we could achieve a much cleaner +software architecture. + +For an interrupt controller driver to support hierarchy irq_domain, it +needs to: +1) Implement irq_domain_ops.alloc and irq_domain_ops.free +2) Optionally implement irq_domain_ops.activate and + irq_domain_ops.deactivate. +3) Optionally implement an irq_chip to manage the interrupt controller + hardware. +4) No need to implement irq_domain_ops.map and irq_domain_ops.unmap, + they are unused with hierarchy irq_domain. + +Hierarchy irq_domain may also be used to support other architectures, +such as ARM, ARM64 etc. diff --git a/include/linux/irq.h b/include/linux/irq.h index 03f48d936f66..13ba412ce3a0 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -133,6 +133,8 @@ struct irq_domain; * @chip: low level interrupt hardware access * @domain: Interrupt translation domain; responsible for mapping * between hwirq number and linux irq number. + * @parent_data: pointer to parent struct irq_data to support hierarchy + * irq_domain * @handler_data: per-IRQ data for the irq_chip methods * @chip_data: platform-specific per-chip private data for the chip * methods, to allow shared chip implementations @@ -151,6 +153,9 @@ struct irq_data { unsigned int state_use_accessors; struct irq_chip *chip; struct irq_domain *domain; +#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY + struct irq_data *parent_data; +#endif void *handler_data; void *chip_data; struct msi_desc *msi_desc; diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index b0f9d16e48f6..f8563dcfd254 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -38,6 +38,8 @@ struct device_node; struct irq_domain; struct of_device_id; +struct irq_chip; +struct irq_data; /* Number of irqs reserved for a legacy isa controller */ #define NUM_ISA_INTERRUPTS 16 @@ -64,6 +66,16 @@ struct irq_domain_ops { int (*xlate)(struct irq_domain *d, struct device_node *node, const u32 *intspec, unsigned int intsize, unsigned long *out_hwirq, unsigned int *out_type); + +#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY + /* extended V2 interfaces to support hierarchy irq_domains */ + int (*alloc)(struct irq_domain *d, unsigned int virq, + unsigned int nr_irqs, void *arg); + void (*free)(struct irq_domain *d, unsigned int virq, + unsigned int nr_irqs); + void (*activate)(struct irq_domain *d, struct irq_data *irq_data); + void (*deactivate)(struct irq_domain *d, struct irq_data *irq_data); +#endif }; extern struct irq_domain_ops irq_generic_chip_ops; @@ -77,6 +89,7 @@ struct irq_domain_chip_generic; * @ops: pointer to irq_domain methods * @host_data: private data pointer for use by owner. Not touched by irq_domain * core code. + * @flags: host per irq_domain flags * * Optional elements * @of_node: Pointer to device tree nodes associated with the irq_domain. Used @@ -84,6 +97,7 @@ struct irq_domain_chip_generic; * @gc: Pointer to a list of generic chips. There is a helper function for * setting up one or more generic chips for interrupt controllers * drivers using the generic chip library which uses this pointer. + * @parent: Pointer to parent irq_domain to support hierarchy irq_domains * * Revmap data, used internally by irq_domain * @revmap_direct_max_irq: The largest hwirq that can be set for controllers that @@ -97,10 +111,14 @@ struct irq_domain { const char *name; const struct irq_domain_ops *ops; void *host_data; + unsigned int flags; /* Optional data */ struct device_node *of_node; struct irq_domain_chip_generic *gc; +#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY + struct irq_domain *parent; +#endif /* reverse map data. The linear map gets appended to the irq_domain */ irq_hw_number_t hwirq_max; @@ -110,6 +128,19 @@ struct irq_domain { unsigned int linear_revmap[]; }; +/* Irq domain flags */ +enum { + /* Irq domain is hierarchical */ + IRQ_DOMAIN_FLAG_HIERARCHY = (1 << 0), + + /* + * Flags starting from IRQ_DOMAIN_FLAG_NONCORE are reserved + * for implementation specific purposes and ignored by the + * core code. + */ + IRQ_DOMAIN_FLAG_NONCORE = (1 << 16), +}; + #ifdef CONFIG_IRQ_DOMAIN struct irq_domain *__irq_domain_add(struct device_node *of_node, int size, irq_hw_number_t hwirq_max, int direct_max, @@ -220,8 +251,75 @@ int irq_domain_xlate_onetwocell(struct irq_domain *d, struct device_node *ctrlr, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_type); +/* V2 interfaces to support hierarchy IRQ domains. */ +extern struct irq_data *irq_domain_get_irq_data(struct irq_domain *domain, + unsigned int virq); +#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY +extern int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base, + unsigned int nr_irqs, int node, void *arg, + bool realloc); +extern void irq_domain_free_irqs(unsigned int virq, unsigned int nr_irqs); +extern void irq_domain_activate_irq(struct irq_data *irq_data); +extern void irq_domain_deactivate_irq(struct irq_data *irq_data); + +static inline int irq_domain_alloc_irqs(struct irq_domain *domain, + unsigned int nr_irqs, int node, void *arg) +{ + return __irq_domain_alloc_irqs(domain, -1, nr_irqs, node, arg, false); +} + +extern int irq_domain_set_hwirq_and_chip(struct irq_domain *domain, + unsigned int virq, + irq_hw_number_t hwirq, + struct irq_chip *chip, + void *chip_data); +extern void irq_domain_reset_irq_data(struct irq_data *irq_data); +extern void irq_domain_free_irqs_common(struct irq_domain *domain, + unsigned int virq, + unsigned int nr_irqs); +extern void irq_domain_free_irqs_top(struct irq_domain *domain, + unsigned int virq, unsigned int nr_irqs); + +static inline int irq_domain_alloc_irqs_parent(struct irq_domain *domain, + unsigned int irq_base, + unsigned int nr_irqs, void *arg) +{ + if (domain->parent && domain->parent->ops->alloc) + return domain->parent->ops->alloc(domain->parent, irq_base, + nr_irqs, arg); + return -ENOSYS; +} + +static inline void irq_domain_free_irqs_parent(struct irq_domain *domain, + unsigned int irq_base, unsigned int nr_irqs) +{ + if (domain->parent && domain->parent->ops->free) + domain->parent->ops->free(domain->parent, irq_base, nr_irqs); +} + +static inline bool irq_domain_is_hierarchy(struct irq_domain *domain) +{ + return domain->flags & IRQ_DOMAIN_FLAG_HIERARCHY; +} +#else /* CONFIG_IRQ_DOMAIN_HIERARCHY */ +static inline void irq_domain_activate_irq(struct irq_data *data) { } +static inline void irq_domain_deactivate_irq(struct irq_data *data) { } +static inline int irq_domain_alloc_irqs(struct irq_domain *domain, + unsigned int nr_irqs, int node, void *arg) +{ + return -1; +} + +static inline bool irq_domain_is_hierarchy(struct irq_domain *domain) +{ + return false; +} +#endif /* CONFIG_IRQ_DOMAIN_HIERARCHY */ + #else /* CONFIG_IRQ_DOMAIN */ static inline void irq_dispose_mapping(unsigned int virq) { } +static inline void irq_domain_activate_irq(struct irq_data *data) { } +static inline void irq_domain_deactivate_irq(struct irq_data *data) { } #endif /* !CONFIG_IRQ_DOMAIN */ #endif /* _LINUX_IRQDOMAIN_H */ diff --git a/kernel/irq/Kconfig b/kernel/irq/Kconfig index 225086b2652e..4f2eb2b1f23b 100644 --- a/kernel/irq/Kconfig +++ b/kernel/irq/Kconfig @@ -55,6 +55,11 @@ config GENERIC_IRQ_CHIP config IRQ_DOMAIN bool +# Support for hierarchical irq domains +config IRQ_DOMAIN_HIERARCHY + bool + select IRQ_DOMAIN + config HANDLE_DOMAIN_IRQ bool diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index e5202f00cabc..72a93086216b 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -15,6 +15,7 @@ #include #include #include +#include #include @@ -178,6 +179,7 @@ int irq_startup(struct irq_desc *desc, bool resend) irq_state_clr_disabled(desc); desc->depth = 0; + irq_domain_activate_irq(&desc->irq_data); if (desc->irq_data.chip->irq_startup) { ret = desc->irq_data.chip->irq_startup(&desc->irq_data); irq_state_clr_masked(desc); @@ -199,6 +201,7 @@ void irq_shutdown(struct irq_desc *desc) desc->irq_data.chip->irq_disable(&desc->irq_data); else desc->irq_data.chip->irq_mask(&desc->irq_data); + irq_domain_deactivate_irq(&desc->irq_data); irq_state_set_masked(desc); } diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 6534ff6ce02e..43f3be6fac70 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -23,6 +23,10 @@ static DEFINE_MUTEX(irq_domain_mutex); static DEFINE_MUTEX(revmap_trees_mutex); static struct irq_domain *irq_default_domain; +static int irq_domain_alloc_descs(int virq, unsigned int nr_irqs, + irq_hw_number_t hwirq, int node); +static void irq_domain_check_hierarchy(struct irq_domain *domain); + /** * __irq_domain_add() - Allocate a new irq_domain data structure * @of_node: optional device-tree node of the interrupt controller @@ -30,7 +34,7 @@ static struct irq_domain *irq_default_domain; * @hwirq_max: Maximum number of interrupts supported by controller * @direct_max: Maximum value of direct maps; Use ~0 for no limit; 0 for no * direct mapping - * @ops: map/unmap domain callbacks + * @ops: domain callbacks * @host_data: Controller private data pointer * * Allocates and initialize and irq_domain structure. @@ -56,6 +60,7 @@ struct irq_domain *__irq_domain_add(struct device_node *of_node, int size, domain->hwirq_max = hwirq_max; domain->revmap_size = size; domain->revmap_direct_max_irq = direct_max; + irq_domain_check_hierarchy(domain); mutex_lock(&irq_domain_mutex); list_add(&domain->link, &irq_domain_list); @@ -109,7 +114,7 @@ EXPORT_SYMBOL_GPL(irq_domain_remove); * @first_irq: first number of irq block assigned to the domain, * pass zero to assign irqs on-the-fly. If first_irq is non-zero, then * pre-map all of the irqs in the domain to virqs starting at first_irq. - * @ops: map/unmap domain callbacks + * @ops: domain callbacks * @host_data: Controller private data pointer * * Allocates an irq_domain, and optionally if first_irq is positive then also @@ -174,10 +179,8 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node, domain = __irq_domain_add(of_node, first_hwirq + size, first_hwirq + size, 0, ops, host_data); - if (!domain) - return NULL; - - irq_domain_associate_many(domain, first_irq, first_hwirq, size); + if (domain) + irq_domain_associate_many(domain, first_irq, first_hwirq, size); return domain; } @@ -388,7 +391,6 @@ EXPORT_SYMBOL_GPL(irq_create_direct_mapping); unsigned int irq_create_mapping(struct irq_domain *domain, irq_hw_number_t hwirq) { - unsigned int hint; int virq; pr_debug("irq_create_mapping(0x%p, 0x%lx)\n", domain, hwirq); @@ -410,12 +412,8 @@ unsigned int irq_create_mapping(struct irq_domain *domain, } /* Allocate a virtual interrupt number */ - hint = hwirq % nr_irqs; - if (hint == 0) - hint++; - virq = irq_alloc_desc_from(hint, of_node_to_nid(domain->of_node)); - if (virq <= 0) - virq = irq_alloc_desc_from(1, of_node_to_nid(domain->of_node)); + virq = irq_domain_alloc_descs(-1, 1, hwirq, + of_node_to_nid(domain->of_node)); if (virq <= 0) { pr_debug("-> virq allocation failed\n"); return 0; @@ -471,7 +469,7 @@ unsigned int irq_create_of_mapping(struct of_phandle_args *irq_data) struct irq_domain *domain; irq_hw_number_t hwirq; unsigned int type = IRQ_TYPE_NONE; - unsigned int virq; + int virq; domain = irq_data->np ? irq_find_host(irq_data->np) : irq_default_domain; if (!domain) { @@ -480,6 +478,11 @@ unsigned int irq_create_of_mapping(struct of_phandle_args *irq_data) return 0; } + if (irq_domain_is_hierarchy(domain)) { + virq = irq_domain_alloc_irqs(domain, 1, NUMA_NO_NODE, irq_data); + return virq <= 0 ? 0 : virq; + } + /* If domain has no translation, then we assume interrupt line */ if (domain->ops->xlate == NULL) hwirq = irq_data->args[0]; @@ -540,8 +543,8 @@ unsigned int irq_find_mapping(struct irq_domain *domain, return 0; if (hwirq < domain->revmap_direct_max_irq) { - data = irq_get_irq_data(hwirq); - if (data && (data->domain == domain) && (data->hwirq == hwirq)) + data = irq_domain_get_irq_data(domain, hwirq); + if (data && data->hwirq == hwirq) return hwirq; } @@ -709,3 +712,383 @@ const struct irq_domain_ops irq_domain_simple_ops = { .xlate = irq_domain_xlate_onetwocell, }; EXPORT_SYMBOL_GPL(irq_domain_simple_ops); + +static int irq_domain_alloc_descs(int virq, unsigned int cnt, + irq_hw_number_t hwirq, int node) +{ + unsigned int hint; + + if (virq >= 0) { + virq = irq_alloc_descs(virq, virq, cnt, node); + } else { + hint = hwirq % nr_irqs; + if (hint == 0) + hint++; + virq = irq_alloc_descs_from(hint, cnt, node); + if (virq <= 0 && hint > 1) + virq = irq_alloc_descs_from(1, cnt, node); + } + + return virq; +} + +#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY +static void irq_domain_insert_irq(int virq) +{ + struct irq_data *data; + + for (data = irq_get_irq_data(virq); data; data = data->parent_data) { + struct irq_domain *domain = data->domain; + irq_hw_number_t hwirq = data->hwirq; + + if (hwirq < domain->revmap_size) { + domain->linear_revmap[hwirq] = virq; + } else { + mutex_lock(&revmap_trees_mutex); + radix_tree_insert(&domain->revmap_tree, hwirq, data); + mutex_unlock(&revmap_trees_mutex); + } + + /* If not already assigned, give the domain the chip's name */ + if (!domain->name && data->chip) + domain->name = data->chip->name; + } + + irq_clear_status_flags(virq, IRQ_NOREQUEST); +} + +static void irq_domain_remove_irq(int virq) +{ + struct irq_data *data; + + irq_set_status_flags(virq, IRQ_NOREQUEST); + irq_set_chip_and_handler(virq, NULL, NULL); + synchronize_irq(virq); + smp_mb(); + + for (data = irq_get_irq_data(virq); data; data = data->parent_data) { + struct irq_domain *domain = data->domain; + irq_hw_number_t hwirq = data->hwirq; + + if (hwirq < domain->revmap_size) { + domain->linear_revmap[hwirq] = 0; + } else { + mutex_lock(&revmap_trees_mutex); + radix_tree_delete(&domain->revmap_tree, hwirq); + mutex_unlock(&revmap_trees_mutex); + } + } +} + +static struct irq_data *irq_domain_insert_irq_data(struct irq_domain *domain, + struct irq_data *child) +{ + struct irq_data *irq_data; + + irq_data = kzalloc_node(sizeof(*irq_data), GFP_KERNEL, child->node); + if (irq_data) { + child->parent_data = irq_data; + irq_data->irq = child->irq; + irq_data->node = child->node; + irq_data->domain = domain; + } + + return irq_data; +} + +static void irq_domain_free_irq_data(unsigned int virq, unsigned int nr_irqs) +{ + struct irq_data *irq_data, *tmp; + int i; + + for (i = 0; i < nr_irqs; i++) { + irq_data = irq_get_irq_data(virq + i); + tmp = irq_data->parent_data; + irq_data->parent_data = NULL; + irq_data->domain = NULL; + + while (tmp) { + irq_data = tmp; + tmp = tmp->parent_data; + kfree(irq_data); + } + } +} + +static int irq_domain_alloc_irq_data(struct irq_domain *domain, + unsigned int virq, unsigned int nr_irqs) +{ + struct irq_data *irq_data; + struct irq_domain *parent; + int i; + + /* The outermost irq_data is embedded in struct irq_desc */ + for (i = 0; i < nr_irqs; i++) { + irq_data = irq_get_irq_data(virq + i); + irq_data->domain = domain; + + for (parent = domain->parent; parent; parent = parent->parent) { + irq_data = irq_domain_insert_irq_data(parent, irq_data); + if (!irq_data) { + irq_domain_free_irq_data(virq, i + 1); + return -ENOMEM; + } + } + } + + return 0; +} + +/** + * irq_domain_get_irq_data - Get irq_data associated with @virq and @domain + * @domain: domain to match + * @virq: IRQ number to get irq_data + */ +struct irq_data *irq_domain_get_irq_data(struct irq_domain *domain, + unsigned int virq) +{ + struct irq_data *irq_data; + + for (irq_data = irq_get_irq_data(virq); irq_data; + irq_data = irq_data->parent_data) + if (irq_data->domain == domain) + return irq_data; + + return NULL; +} + +/** + * irq_domain_set_hwirq_and_chip - Set hwirq and irqchip of @virq at @domain + * @domain: Interrupt domain to match + * @virq: IRQ number + * @hwirq: The hwirq number + * @chip: The associated interrupt chip + * @chip_data: The associated chip data + */ +int irq_domain_set_hwirq_and_chip(struct irq_domain *domain, unsigned int virq, + irq_hw_number_t hwirq, struct irq_chip *chip, + void *chip_data) +{ + struct irq_data *irq_data = irq_domain_get_irq_data(domain, virq); + + if (!irq_data) + return -ENOENT; + + irq_data->hwirq = hwirq; + irq_data->chip = chip ? chip : &no_irq_chip; + irq_data->chip_data = chip_data; + + return 0; +} + +/** + * irq_domain_reset_irq_data - Clear hwirq, chip and chip_data in @irq_data + * @irq_data: The pointer to irq_data + */ +void irq_domain_reset_irq_data(struct irq_data *irq_data) +{ + irq_data->hwirq = 0; + irq_data->chip = &no_irq_chip; + irq_data->chip_data = NULL; +} + +/** + * irq_domain_free_irqs_common - Clear irq_data and free the parent + * @domain: Interrupt domain to match + * @virq: IRQ number to start with + * @nr_irqs: The number of irqs to free + */ +void irq_domain_free_irqs_common(struct irq_domain *domain, unsigned int virq, + unsigned int nr_irqs) +{ + struct irq_data *irq_data; + int i; + + for (i = 0; i < nr_irqs; i++) { + irq_data = irq_domain_get_irq_data(domain, virq + i); + if (irq_data) + irq_domain_reset_irq_data(irq_data); + } + irq_domain_free_irqs_parent(domain, virq, nr_irqs); +} + +/** + * irq_domain_free_irqs_top - Clear handler and handler data, clear irqdata and free parent + * @domain: Interrupt domain to match + * @virq: IRQ number to start with + * @nr_irqs: The number of irqs to free + */ +void irq_domain_free_irqs_top(struct irq_domain *domain, unsigned int virq, + unsigned int nr_irqs) +{ + int i; + + for (i = 0; i < nr_irqs; i++) { + irq_set_handler_data(virq + i, NULL); + irq_set_handler(virq + i, NULL); + } + irq_domain_free_irqs_common(domain, virq, nr_irqs); +} + +/** + * __irq_domain_alloc_irqs - Allocate IRQs from domain + * @domain: domain to allocate from + * @irq_base: allocate specified IRQ nubmer if irq_base >= 0 + * @nr_irqs: number of IRQs to allocate + * @node: NUMA node id for memory allocation + * @arg: domain specific argument + * @realloc: IRQ descriptors have already been allocated if true + * + * Allocate IRQ numbers and initialized all data structures to support + * hierarchy IRQ domains. + * Parameter @realloc is mainly to support legacy IRQs. + * Returns error code or allocated IRQ number + * + * The whole process to setup an IRQ has been split into two steps. + * The first step, __irq_domain_alloc_irqs(), is to allocate IRQ + * descriptor and required hardware resources. The second step, + * irq_domain_activate_irq(), is to program hardwares with preallocated + * resources. In this way, it's easier to rollback when failing to + * allocate resources. + */ +int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base, + unsigned int nr_irqs, int node, void *arg, + bool realloc) +{ + int i, ret, virq; + + if (domain == NULL) { + domain = irq_default_domain; + if (WARN(!domain, "domain is NULL; cannot allocate IRQ\n")) + return -EINVAL; + } + + if (!domain->ops->alloc) { + pr_debug("domain->ops->alloc() is NULL\n"); + return -ENOSYS; + } + + if (realloc && irq_base >= 0) { + virq = irq_base; + } else { + virq = irq_domain_alloc_descs(irq_base, nr_irqs, 0, node); + if (virq < 0) { + pr_debug("cannot allocate IRQ(base %d, count %d)\n", + irq_base, nr_irqs); + return virq; + } + } + + if (irq_domain_alloc_irq_data(domain, virq, nr_irqs)) { + pr_debug("cannot allocate memory for IRQ%d\n", virq); + ret = -ENOMEM; + goto out_free_desc; + } + + mutex_lock(&irq_domain_mutex); + ret = domain->ops->alloc(domain, virq, nr_irqs, arg); + if (ret < 0) { + mutex_unlock(&irq_domain_mutex); + goto out_free_irq_data; + } + for (i = 0; i < nr_irqs; i++) + irq_domain_insert_irq(virq + i); + mutex_unlock(&irq_domain_mutex); + + return virq; + +out_free_irq_data: + irq_domain_free_irq_data(virq, nr_irqs); +out_free_desc: + irq_free_descs(virq, nr_irqs); + return ret; +} + +/** + * irq_domain_free_irqs - Free IRQ number and associated data structures + * @virq: base IRQ number + * @nr_irqs: number of IRQs to free + */ +void irq_domain_free_irqs(unsigned int virq, unsigned int nr_irqs) +{ + struct irq_data *data = irq_get_irq_data(virq); + int i; + + if (WARN(!data || !data->domain || !data->domain->ops->free, + "NULL pointer, cannot free irq\n")) + return; + + mutex_lock(&irq_domain_mutex); + for (i = 0; i < nr_irqs; i++) + irq_domain_remove_irq(virq + i); + data->domain->ops->free(data->domain, virq, nr_irqs); + mutex_unlock(&irq_domain_mutex); + + irq_domain_free_irq_data(virq, nr_irqs); + irq_free_descs(virq, nr_irqs); +} + +/** + * irq_domain_activate_irq - Call domain_ops->activate recursively to activate + * interrupt + * @irq_data: outermost irq_data associated with interrupt + * + * This is the second step to call domain_ops->activate to program interrupt + * controllers, so the interrupt could actually get delivered. + */ +void irq_domain_activate_irq(struct irq_data *irq_data) +{ + if (irq_data && irq_data->domain) { + struct irq_domain *domain = irq_data->domain; + + if (irq_data->parent_data) + irq_domain_activate_irq(irq_data->parent_data); + if (domain->ops->activate) + domain->ops->activate(domain, irq_data); + } +} + +/** + * irq_domain_deactivate_irq - Call domain_ops->deactivate recursively to + * deactivate interrupt + * @irq_data: outermost irq_data associated with interrupt + * + * It calls domain_ops->deactivate to program interrupt controllers to disable + * interrupt delivery. + */ +void irq_domain_deactivate_irq(struct irq_data *irq_data) +{ + if (irq_data && irq_data->domain) { + struct irq_domain *domain = irq_data->domain; + + if (domain->ops->deactivate) + domain->ops->deactivate(domain, irq_data); + if (irq_data->parent_data) + irq_domain_deactivate_irq(irq_data->parent_data); + } +} + +static void irq_domain_check_hierarchy(struct irq_domain *domain) +{ + /* Hierarchy irq_domains must implement callback alloc() */ + if (domain->ops->alloc) + domain->flags |= IRQ_DOMAIN_FLAG_HIERARCHY; +} +#else /* CONFIG_IRQ_DOMAIN_HIERARCHY */ +/** + * irq_domain_get_irq_data - Get irq_data associated with @virq and @domain + * @domain: domain to match + * @virq: IRQ number to get irq_data + */ +struct irq_data *irq_domain_get_irq_data(struct irq_domain *domain, + unsigned int virq) +{ + struct irq_data *irq_data = irq_get_irq_data(virq); + + return (irq_data && irq_data->domain == domain) ? irq_data : NULL; +} + +static void irq_domain_check_hierarchy(struct irq_domain *domain) +{ +} +#endif /* CONFIG_IRQ_DOMAIN_HIERARCHY */ -- cgit v1.2.3-59-g8ed1b From eaa2e9804e9cbd0b46f74e39ca6f92e4834547db Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 6 Nov 2014 11:40:32 +0800 Subject: clk: sunxi: Removed unused/incorrect sun6i-a31-apb2-clk driver This driver does not match the hardware, which is actually compatible to sun4i-a10-apb1-clk. Since we've switch to the correct one, drop this driver. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- Documentation/devicetree/bindings/clock/sunxi.txt | 1 - drivers/clk/sunxi/clk-sunxi.c | 7 ------- 2 files changed, 8 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt index 6ddcf6e10eb8..d199f9153e04 100644 --- a/Documentation/devicetree/bindings/clock/sunxi.txt +++ b/Documentation/devicetree/bindings/clock/sunxi.txt @@ -52,7 +52,6 @@ Required properties: "allwinner,sun7i-a20-apb1-gates-clk" - for the APB1 gates on A20 "allwinner,sun8i-a23-apb1-gates-clk" - for the APB1 gates on A23 "allwinner,sun9i-a80-apb1-gates-clk" - for the APB1 gates on A80 - "allwinner,sun6i-a31-apb2-div-clk" - for the APB2 gates on A31 "allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31 "allwinner,sun8i-a23-apb2-gates-clk" - for the APB2 gates on A23 "allwinner,sun5i-a13-mbus-clk" - for the MBUS clock on A13 diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c index 4133e278212b..46d98e3b98ba 100644 --- a/drivers/clk/sunxi/clk-sunxi.c +++ b/drivers/clk/sunxi/clk-sunxi.c @@ -632,12 +632,6 @@ static const struct div_data sun4i_apb0_data __initconst = { .table = sun4i_apb0_table, }; -static const struct div_data sun6i_a31_apb2_div_data __initconst = { - .shift = 0, - .pow = 0, - .width = 4, -}; - static void __init sunxi_divider_clk_setup(struct device_node *node, struct div_data *data) { @@ -1093,7 +1087,6 @@ static const struct of_device_id clk_div_match[] __initconst = { {.compatible = "allwinner,sun8i-a23-axi-clk", .data = &sun8i_a23_axi_data,}, {.compatible = "allwinner,sun4i-a10-ahb-clk", .data = &sun4i_ahb_data,}, {.compatible = "allwinner,sun4i-a10-apb0-clk", .data = &sun4i_apb0_data,}, - {.compatible = "allwinner,sun6i-a31-apb2-div-clk", .data = &sun6i_a31_apb2_div_data,}, {} }; -- cgit v1.2.3-59-g8ed1b From 95e94c1fadcd1959857db45c2e11810a893badd0 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 13 Nov 2014 02:08:31 +0800 Subject: clk: sunxi: Implement A31 PLL6 as a divs clock for 2x output Some clock modules on the A31 use PLL6x2 as one of their inputs. This patch changes the PLL6 implementation for A31 to a divs clock, i.e. clock with multiple outputs that have different dividers. The first output will be the normal PLL6 output, and the second will be PLL6x2. This patch fixes the PLL6 N factor in the clock driver, and removes any /2 dividers in the PLL6 factors clock part. The N factor counts from 1 to 32, mapping to values 0 to 31, as shown in the A31 manual. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- Documentation/devicetree/bindings/clock/sunxi.txt | 19 +++++++++++++-- drivers/clk/sunxi/clk-sunxi.c | 28 +++++++++++++---------- 2 files changed, 33 insertions(+), 14 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt index d199f9153e04..67b2b99f2b33 100644 --- a/Documentation/devicetree/bindings/clock/sunxi.txt +++ b/Documentation/devicetree/bindings/clock/sunxi.txt @@ -71,8 +71,9 @@ Required properties for all clocks: multiplexed clocks, the list order must match the hardware programming order. - #clock-cells : from common clock binding; shall be set to 0 except for - "allwinner,*-gates-clk", "allwinner,sun4i-pll5-clk" and - "allwinner,sun4i-pll6-clk" where it shall be set to 1 + the following compatibles where it shall be set to 1: + "allwinner,*-gates-clk", "allwinner,sun4i-pll5-clk", + "allwinner,sun4i-pll6-clk", "allwinner,sun6i-a31-pll6-clk" - clock-output-names : shall be the corresponding names of the outputs. If the clock module only has one output, the name shall be the module name. @@ -87,6 +88,12 @@ Clock consumers should specify the desired clocks they use with a "clocks" phandle cell. Consumers that are using a gated clock should provide an additional ID in their clock property. This ID is the offset of the bit controlling this particular gate in the register. +For the other clocks with "#clock-cells" = 1, the additional ID shall +refer to the index of the output. + +For "allwinner,sun6i-a31-pll6-clk", there are 2 outputs. The first output +is the normal PLL6 output, or "pll6". The second output is rate doubled +PLL6, or "pll6x2". For example: @@ -114,6 +121,14 @@ pll5: clk@01c20020 { clock-output-names = "pll5_ddr", "pll5_other"; }; +pll6: clk@01c20028 { + #clock-cells = <1>; + compatible = "allwinner,sun6i-a31-pll6-clk"; + reg = <0x01c20028 0x4>; + clocks = <&osc24M>; + clock-output-names = "pll6", "pll6x2"; +}; + cpu: cpu@01c20054 { #clock-cells = <0>; compatible = "allwinner,sun4i-a10-cpu-clk"; diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c index d46949372762..570202582dcf 100644 --- a/drivers/clk/sunxi/clk-sunxi.c +++ b/drivers/clk/sunxi/clk-sunxi.c @@ -245,9 +245,9 @@ static void sun4i_get_pll5_factors(u32 *freq, u32 parent_rate, } /** - * sun6i_a31_get_pll6_factors() - calculates n, k factors for A31 PLL6 - * PLL6 rate is calculated as follows - * rate = parent_rate * n * (k + 1) / 2 + * sun6i_a31_get_pll6_factors() - calculates n, k factors for A31 PLL6x2 + * PLL6x2 rate is calculated as follows + * rate = parent_rate * (n + 1) * (k + 1) * parent_rate is always 24Mhz */ @@ -256,13 +256,7 @@ static void sun6i_a31_get_pll6_factors(u32 *freq, u32 parent_rate, { u8 div; - /* - * We always have 24MHz / 2, so we can just say that our - * parent clock is 12MHz. - */ - parent_rate = parent_rate / 2; - - /* Normalize value to a parent_rate multiple (24M / 2) */ + /* Normalize value to a parent_rate multiple (24M) */ div = *freq / parent_rate; *freq = parent_rate * div; @@ -274,7 +268,7 @@ static void sun6i_a31_get_pll6_factors(u32 *freq, u32 parent_rate, if (*k > 3) *k = 3; - *n = DIV_ROUND_UP(div, (*k+1)); + *n = DIV_ROUND_UP(div, (*k+1)) - 1; } /** @@ -445,6 +439,7 @@ static struct clk_factors_config sun6i_a31_pll6_config = { .nwidth = 5, .kshift = 4, .kwidth = 2, + .n_start = 1, }; static struct clk_factors_config sun4i_apb1_config = { @@ -504,6 +499,7 @@ static const struct factors_data sun6i_a31_pll6_data __initconst = { .enable = 31, .table = &sun6i_a31_pll6_config, .getter = sun6i_a31_get_pll6_factors, + .name = "pll6x2", }; static const struct factors_data sun4i_apb1_data __initconst = { @@ -942,6 +938,14 @@ static const struct divs_data pll6_divs_data __initconst = { } }; +static const struct divs_data sun6i_a31_pll6_divs_data __initconst = { + .factors = &sun6i_a31_pll6_data, + .ndivs = 1, + .div = { + { .fixed = 2 }, /* normal output */ + } +}; + /** * sunxi_divs_clk_setup() - Setup function for leaf divisors on clocks * @@ -1082,7 +1086,6 @@ static const struct of_device_id clk_factors_match[] __initconst = { {.compatible = "allwinner,sun6i-a31-pll1-clk", .data = &sun6i_a31_pll1_data,}, {.compatible = "allwinner,sun8i-a23-pll1-clk", .data = &sun8i_a23_pll1_data,}, {.compatible = "allwinner,sun7i-a20-pll4-clk", .data = &sun7i_a20_pll4_data,}, - {.compatible = "allwinner,sun6i-a31-pll6-clk", .data = &sun6i_a31_pll6_data,}, {.compatible = "allwinner,sun4i-a10-apb1-clk", .data = &sun4i_apb1_data,}, {.compatible = "allwinner,sun7i-a20-out-clk", .data = &sun7i_a20_out_data,}, {} @@ -1101,6 +1104,7 @@ static const struct of_device_id clk_div_match[] __initconst = { static const struct of_device_id clk_divs_match[] __initconst = { {.compatible = "allwinner,sun4i-a10-pll5-clk", .data = &pll5_divs_data,}, {.compatible = "allwinner,sun4i-a10-pll6-clk", .data = &pll6_divs_data,}, + {.compatible = "allwinner,sun6i-a31-pll6-clk", .data = &sun6i_a31_pll6_divs_data,}, {} }; -- cgit v1.2.3-59-g8ed1b From afe8dc254711b72ba8144295f4a8fcc66d30572d Mon Sep 17 00:00:00 2001 From: Andrew Bresticker Date: Thu, 18 Sep 2014 14:47:08 -0700 Subject: MIPS: Rename mips_cpu_intc_init() -> mips_cpu_irq_of_init() mips_cpu_intc_init() is used for DT-based initialization of the CPU IRQ domain. Give it a more appropriate name. Signed-off-by: Andrew Bresticker Reviewed-by: Qais Yousef Tested-by: Qais Yousef Cc: Thomas Gleixner Cc: Jason Cooper Cc: Andrew Bresticker Cc: Jeffrey Deans Cc: Markos Chandras Cc: Paul Burton Cc: Qais Yousef Cc: Jonas Gorski Cc: John Crispin Cc: David Daney Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/7800/ Signed-off-by: Ralf Baechle --- Documentation/devicetree/bindings/mips/cpu_irq.txt | 4 ++-- arch/mips/include/asm/irq_cpu.h | 4 ++-- arch/mips/kernel/irq_cpu.c | 4 ++-- arch/mips/ralink/irq.c | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mips/cpu_irq.txt b/Documentation/devicetree/bindings/mips/cpu_irq.txt index 13aa4b62c62a..fc149f326dae 100644 --- a/Documentation/devicetree/bindings/mips/cpu_irq.txt +++ b/Documentation/devicetree/bindings/mips/cpu_irq.txt @@ -1,6 +1,6 @@ MIPS CPU interrupt controller -On MIPS the mips_cpu_intc_init() helper can be used to initialize the 8 CPU +On MIPS the mips_cpu_irq_of_init() helper can be used to initialize the 8 CPU IRQs from a devicetree file and create a irq_domain for IRQ controller. With the irq_domain in place we can describe how the 8 IRQs are wired to the @@ -36,7 +36,7 @@ Example devicetree: Example platform irq.c: static struct of_device_id __initdata of_irq_ids[] = { - { .compatible = "mti,cpu-interrupt-controller", .data = mips_cpu_intc_init }, + { .compatible = "mti,cpu-interrupt-controller", .data = mips_cpu_irq_of_init }, { .compatible = "ralink,rt2880-intc", .data = intc_of_init }, {}, }; diff --git a/arch/mips/include/asm/irq_cpu.h b/arch/mips/include/asm/irq_cpu.h index 3f11fdb3ed8c..39a160bb41dc 100644 --- a/arch/mips/include/asm/irq_cpu.h +++ b/arch/mips/include/asm/irq_cpu.h @@ -19,8 +19,8 @@ extern void rm9k_cpu_irq_init(void); #ifdef CONFIG_IRQ_DOMAIN struct device_node; -extern int mips_cpu_intc_init(struct device_node *of_node, - struct device_node *parent); +extern int mips_cpu_irq_of_init(struct device_node *of_node, + struct device_node *parent); #endif #endif /* _ASM_IRQ_CPU_H */ diff --git a/arch/mips/kernel/irq_cpu.c b/arch/mips/kernel/irq_cpu.c index b097f7df7a29..ca98a9f837d4 100644 --- a/arch/mips/kernel/irq_cpu.c +++ b/arch/mips/kernel/irq_cpu.c @@ -135,8 +135,8 @@ void __init mips_cpu_irq_init(void) __mips_cpu_irq_init(NULL); } -int __init mips_cpu_intc_init(struct device_node *of_node, - struct device_node *parent) +int __init mips_cpu_irq_of_init(struct device_node *of_node, + struct device_node *parent) { __mips_cpu_irq_init(of_node); return 0; diff --git a/arch/mips/ralink/irq.c b/arch/mips/ralink/irq.c index 781b3d14a489..0495011a19df 100644 --- a/arch/mips/ralink/irq.c +++ b/arch/mips/ralink/irq.c @@ -173,7 +173,7 @@ static int __init intc_of_init(struct device_node *node, } static struct of_device_id __initdata of_irq_ids[] = { - { .compatible = "mti,cpu-interrupt-controller", .data = mips_cpu_intc_init }, + { .compatible = "mti,cpu-interrupt-controller", .data = mips_cpu_irq_of_init }, { .compatible = "ralink,rt2880-intc", .data = intc_of_init }, {}, }; -- cgit v1.2.3-59-g8ed1b From 846deacebfe1c77f6448868ae961c2a6d60e1e45 Mon Sep 17 00:00:00 2001 From: Kevin Cernekee Date: Mon, 20 Oct 2014 21:28:03 -0700 Subject: Documentation: DT: Add entries for BCM3384 and its peripherals This covers the new "brcm,*" devices added in the upcoming bcm3384 commit. Signed-off-by: Kevin Cernekee Cc: f.fainelli@gmail.com Cc: mbizon@freebox.fr Cc: jogo@openwrt.org Cc: jfraser@broadcom.com Cc: linux-mips@linux-mips.org Cc: devicetree@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/8168/ Signed-off-by: Ralf Baechle --- .../devicetree/bindings/mips/brcm/bcm3384-intc.txt | 37 ++++++++++++++++++++++ .../devicetree/bindings/mips/brcm/bmips.txt | 8 +++++ .../devicetree/bindings/mips/brcm/cm-dsl.txt | 11 +++++++ .../devicetree/bindings/mips/brcm/usb.txt | 11 +++++++ 4 files changed, 67 insertions(+) create mode 100644 Documentation/devicetree/bindings/mips/brcm/bcm3384-intc.txt create mode 100644 Documentation/devicetree/bindings/mips/brcm/bmips.txt create mode 100644 Documentation/devicetree/bindings/mips/brcm/cm-dsl.txt create mode 100644 Documentation/devicetree/bindings/mips/brcm/usb.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mips/brcm/bcm3384-intc.txt b/Documentation/devicetree/bindings/mips/brcm/bcm3384-intc.txt new file mode 100644 index 000000000000..d4e0141d3620 --- /dev/null +++ b/Documentation/devicetree/bindings/mips/brcm/bcm3384-intc.txt @@ -0,0 +1,37 @@ +* 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/Documentation/devicetree/bindings/mips/brcm/bmips.txt b/Documentation/devicetree/bindings/mips/brcm/bmips.txt new file mode 100644 index 000000000000..8ef71b4085ca --- /dev/null +++ b/Documentation/devicetree/bindings/mips/brcm/bmips.txt @@ -0,0 +1,8 @@ +* Broadcom MIPS (BMIPS) CPUs + +Required properties: +- compatible: "brcm,bmips3300", "brcm,bmips4350", "brcm,bmips4380", + "brcm,bmips5000" + +- mips-hpt-frequency: This is common to all CPUs in the system so it lives + under the "cpus" node. diff --git a/Documentation/devicetree/bindings/mips/brcm/cm-dsl.txt b/Documentation/devicetree/bindings/mips/brcm/cm-dsl.txt new file mode 100644 index 000000000000..8a139cb3c0b5 --- /dev/null +++ b/Documentation/devicetree/bindings/mips/brcm/cm-dsl.txt @@ -0,0 +1,11 @@ +* 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/usb.txt b/Documentation/devicetree/bindings/mips/brcm/usb.txt new file mode 100644 index 000000000000..452c45c7bf29 --- /dev/null +++ b/Documentation/devicetree/bindings/mips/brcm/usb.txt @@ -0,0 +1,11 @@ +* Broadcom USB controllers + +Required properties: +- compatible: "brcm,bcm3384-ohci", "brcm,bcm3384-ehci" + + These currently use the generic-ohci and generic-ehci drivers. On some + systems, special handling may be needed in the following cases: + + - Restoring state after systemwide power save modes + - Sharing PHYs with the USBD (UDC) hardware + - Figuring out which controllers are disabled on ASIC bondout variants -- cgit v1.2.3-59-g8ed1b From ab81ce62178c14e883b8cfa9773b289f22e99489 Mon Sep 17 00:00:00 2001 From: Kevin Cernekee Date: Mon, 20 Oct 2014 21:28:04 -0700 Subject: Documentation: DT: Add "mti" vendor prefix We have a bunch of platforms using "mti,cpu-interrupt-controller" but the "mti" prefix isn't documented. Fix this. Signed-off-by: Kevin Cernekee Cc: f.fainelli@gmail.com Cc: mbizon@freebox.fr Cc: jogo@openwrt.org Cc: jfraser@broadcom.com Cc: linux-mips@linux-mips.org Cc: devicetree@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/8169/ Signed-off-by: Ralf Baechle --- 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 a344ec2713a5..88536391916b 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -98,6 +98,7 @@ mitsubishi Mitsubishi Electric Corporation mosaixtech Mosaix Technologies, Inc. moxa Moxa mpl MPL AG +mti Imagination Technologies Ltd. (formerly MIPS Technologies Inc.) mundoreader Mundo Reader S.L. murata Murata Manufacturing Co., Ltd. mxicy Macronix International Co., Ltd. -- cgit v1.2.3-59-g8ed1b From 2ff404005e9f94ee3d05b6b0dac8204c1fcc2346 Mon Sep 17 00:00:00 2001 From: Andrew Bresticker Date: Wed, 12 Nov 2014 11:43:37 -0800 Subject: of: Add binding document for MIPS GIC The Global Interrupt Controller (GIC) present on certain MIPS systems can be used to route external interrupts to individual VPEs and CPU interrupt vectors. It also supports a timer and software-generated interrupts. Signed-off-by: Andrew Bresticker Acked-by: Arnd Bergmann Cc: Rob Herring Cc: Pawel Moll Cc: Mark Rutland Cc: Ian Campbell Cc: Kumar Gala Cc: Thomas Gleixner Cc: Jason Cooper Cc: Daniel Lezcano Cc: John Crispin Cc: David Daney Cc: Qais Yousef Cc: James Hogan Cc: linux-mips@linux-mips.org Cc: devicetree@vger.kernel.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/8420/ Signed-off-by: Ralf Baechle --- .../bindings/interrupt-controller/mips-gic.txt | 55 ++++++++++++++++++++++ .../dt-bindings/interrupt-controller/mips-gic.h | 9 ++++ 2 files changed, 64 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/mips-gic.txt create mode 100644 include/dt-bindings/interrupt-controller/mips-gic.h (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/interrupt-controller/mips-gic.txt b/Documentation/devicetree/bindings/interrupt-controller/mips-gic.txt new file mode 100644 index 000000000000..5a65478e5d40 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/mips-gic.txt @@ -0,0 +1,55 @@ +MIPS Global Interrupt Controller (GIC) + +The MIPS GIC routes external interrupts to individual VPEs and IRQ pins. +It also supports local (per-processor) interrupts and software-generated +interrupts which can be used as IPIs. The GIC also includes a free-running +global timer, per-CPU count/compare timers, and a watchdog. + +Required properties: +- compatible : Should be "mti,gic". +- interrupt-controller : Identifies the node as an interrupt controller +- #interrupt-cells : Specifies the number of cells needed to encode an + interrupt specifier. Should be 3. + - The first cell is the type of interrupt, local or shared. + See . + - The second cell is the GIC interrupt number. + - The third cell encodes the interrupt flags. + See for a list of valid + flags. + +Optional properties: +- reg : Base address and length of the GIC registers. If not present, + the base address reported by the hardware GCR_GIC_BASE will be used. +- mti,reserved-cpu-vectors : Specifies the list of CPU interrupt vectors + to which the GIC may not route interrupts. Valid values are 2 - 7. + This property is ignored if the CPU is started in EIC mode. + +Required properties for timer sub-node: +- compatible : Should be "mti,gic-timer". +- interrupts : Interrupt for the GIC local timer. +- clock-frequency : Clock frequency at which the GIC timers operate. + +Example: + + gic: interrupt-controller@1bdc0000 { + compatible = "mti,gic"; + reg = <0x1bdc0000 0x20000>; + + interrupt-controller; + #interrupt-cells = <3>; + + mti,reserved-cpu-vectors = <7>; + + timer { + compatible = "mti,gic-timer"; + interrupts = ; + clock-frequency = <50000000>; + }; + }; + + uart@18101400 { + ... + interrupt-parent = <&gic>; + interrupts = ; + ... + }; diff --git a/include/dt-bindings/interrupt-controller/mips-gic.h b/include/dt-bindings/interrupt-controller/mips-gic.h new file mode 100644 index 000000000000..cf35a577e371 --- /dev/null +++ b/include/dt-bindings/interrupt-controller/mips-gic.h @@ -0,0 +1,9 @@ +#ifndef _DT_BINDINGS_INTERRUPT_CONTROLLER_MIPS_GIC_H +#define _DT_BINDINGS_INTERRUPT_CONTROLLER_MIPS_GIC_H + +#include + +#define GIC_SHARED 0 +#define GIC_LOCAL 1 + +#endif -- cgit v1.2.3-59-g8ed1b From db5ed4dfd5dd0142ec36ff7b335e0ec3b836b3e6 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 13 Nov 2014 15:08:42 +0100 Subject: scsi: drop reason argument from ->change_queue_depth Drop the now unused reason argument from the ->change_queue_depth method. Also add a return value to scsi_adjust_queue_depth, and rename it to scsi_change_queue_depth now that it can be used as the default ->change_queue_depth implementation. Signed-off-by: Christoph Hellwig Reviewed-by: Mike Christie Reviewed-by: Hannes Reinecke --- Documentation/scsi/scsi_mid_low_api.txt | 20 +++++++-------- drivers/ata/libata-scsi.c | 17 ++++--------- drivers/ata/sata_nv.c | 2 +- drivers/infiniband/ulp/iser/iscsi_iser.c | 2 +- drivers/infiniband/ulp/srp/ib_srp.c | 7 ++---- drivers/message/fusion/mptscsih.c | 12 +++------ drivers/message/fusion/mptscsih.h | 3 +-- drivers/s390/scsi/zfcp_scsi.c | 11 ++------- drivers/scsi/3w-9xxx.c | 13 +--------- drivers/scsi/3w-sas.c | 13 +--------- drivers/scsi/3w-xxxx.c | 13 +--------- drivers/scsi/53c700.c | 19 ++++++-------- drivers/scsi/BusLogic.c | 4 +-- drivers/scsi/aacraid/linit.c | 18 ++++++-------- drivers/scsi/advansys.c | 8 +++--- drivers/scsi/aic7xxx/aic79xx_osm.c | 4 +-- drivers/scsi/aic7xxx/aic7xxx_osm.c | 4 +-- drivers/scsi/arcmsr/arcmsr_hba.c | 9 ++----- drivers/scsi/be2iscsi/be_main.c | 2 +- drivers/scsi/bfa/bfad_im.c | 4 +-- drivers/scsi/bnx2fc/bnx2fc_fcoe.c | 2 +- drivers/scsi/bnx2i/bnx2i_iscsi.c | 2 +- drivers/scsi/csiostor/csio_scsi.c | 2 +- drivers/scsi/cxgbi/cxgb3i/cxgb3i.c | 2 +- drivers/scsi/cxgbi/cxgb4i/cxgb4i.c | 2 +- drivers/scsi/dpt_i2o.c | 2 +- drivers/scsi/eata.c | 6 ++--- drivers/scsi/esas2r/esas2r.h | 1 - drivers/scsi/esas2r/esas2r_main.c | 11 +-------- drivers/scsi/esp_scsi.c | 2 +- drivers/scsi/fcoe/fcoe.c | 2 +- drivers/scsi/fnic/fnic_main.c | 4 +-- drivers/scsi/hpsa.c | 16 +----------- drivers/scsi/hptiop.c | 8 ++---- drivers/scsi/ibmvscsi/ibmvfc.c | 9 ++----- drivers/scsi/ibmvscsi/ibmvscsi.c | 10 ++------ drivers/scsi/ipr.c | 10 +++----- drivers/scsi/ips.c | 2 +- drivers/scsi/iscsi_tcp.c | 2 +- drivers/scsi/libfc/fc_fcp.c | 15 +---------- drivers/scsi/libiscsi.c | 7 ------ drivers/scsi/libsas/sas_scsi_host.c | 12 ++++----- drivers/scsi/lpfc/lpfc_scsi.c | 26 +++----------------- drivers/scsi/megaraid/megaraid_mbox.c | 21 +--------------- drivers/scsi/megaraid/megaraid_sas_base.c | 13 +--------- drivers/scsi/mpt2sas/mpt2sas_scsih.c | 10 +++----- drivers/scsi/mpt3sas/mpt3sas_scsih.c | 10 +++----- drivers/scsi/ncr53c8xx.c | 2 +- drivers/scsi/pmcraid.c | 12 ++------- drivers/scsi/qla1280.c | 4 +-- drivers/scsi/qla2xxx/qla_os.c | 12 ++------- drivers/scsi/qla4xxx/ql4_os.c | 4 +-- drivers/scsi/scsi.c | 41 +++++++++++-------------------- drivers/scsi/scsi_debug.c | 4 +-- drivers/scsi/scsi_error.c | 2 +- drivers/scsi/scsi_scan.c | 2 +- drivers/scsi/scsi_sysfs.c | 3 +-- drivers/scsi/storvsc_drv.c | 2 +- drivers/scsi/sym53c8xx_2/sym_glue.c | 2 +- drivers/scsi/tmscsim.c | 2 +- drivers/scsi/u14-34f.c | 10 ++++---- drivers/scsi/ufs/ufshcd.c | 13 +++------- drivers/scsi/virtio_scsi.c | 8 ++---- drivers/scsi/vmw_pvscsi.c | 12 ++------- drivers/scsi/wd7000.c | 1 - drivers/target/loopback/tcm_loop.c | 15 +---------- drivers/usb/storage/uas.c | 2 +- include/linux/libata.h | 4 +-- include/scsi/libfc.h | 1 - include/scsi/libiscsi.h | 2 -- include/scsi/libsas.h | 3 +-- include/scsi/scsi_device.h | 2 +- include/scsi/scsi_host.h | 8 ++---- 73 files changed, 155 insertions(+), 412 deletions(-) (limited to 'Documentation') diff --git a/Documentation/scsi/scsi_mid_low_api.txt b/Documentation/scsi/scsi_mid_low_api.txt index bee7d86b9dcc..731bc4f4c5e6 100644 --- a/Documentation/scsi/scsi_mid_low_api.txt +++ b/Documentation/scsi/scsi_mid_low_api.txt @@ -149,7 +149,7 @@ scsi_add_host() ----> scsi_scan_host() -------+ | slave_alloc() - slave_configure() --> scsi_adjust_queue_depth() + slave_configure() --> scsi_change_queue_depth() | slave_alloc() slave_configure() @@ -159,7 +159,7 @@ scsi_scan_host() -------+ ------------------------------------------------------------ If the LLD wants to adjust the default queue settings, it can invoke -scsi_adjust_queue_depth() in its slave_configure() routine. +scsi_change_queue_depth() in its slave_configure() routine. *** For scsi devices that the mid level tries to scan but do not respond, a slave_alloc(), slave_destroy() pair is called. @@ -203,7 +203,7 @@ LLD mid level LLD scsi_add_device() ------+ | slave_alloc() - slave_configure() [--> scsi_adjust_queue_depth()] + slave_configure() [--> scsi_change_queue_depth()] ------------------------------------------------------------ In a similar fashion, an LLD may become aware that a SCSI device has been @@ -261,7 +261,7 @@ init_this_scsi_driver() ----+ | scsi_register() | slave_alloc() - slave_configure() --> scsi_adjust_queue_depth() + slave_configure() --> scsi_change_queue_depth() slave_alloc() *** slave_destroy() *** | @@ -271,7 +271,7 @@ init_this_scsi_driver() ----+ slave_destroy() *** ------------------------------------------------------------ -The mid level invokes scsi_adjust_queue_depth() with "cmd_per_lun" for that +The mid level invokes scsi_change_queue_depth() with "cmd_per_lun" for that host as the queue length. These settings can be overridden by a slave_configure() supplied by the LLD. @@ -368,7 +368,7 @@ names all start with "scsi_". Summary: scsi_add_device - creates new scsi device (lu) instance scsi_add_host - perform sysfs registration and set up transport class - scsi_adjust_queue_depth - change the queue depth on a SCSI device + scsi_change_queue_depth - change the queue depth on a SCSI device scsi_bios_ptable - return copy of block device's partition table scsi_block_requests - prevent further commands being queued to given host scsi_host_alloc - return a new scsi_host instance whose refcount==1 @@ -436,7 +436,7 @@ int scsi_add_host(struct Scsi_Host *shost, struct device * dev) /** - * scsi_adjust_queue_depth - allow LLD to change queue depth on a SCSI device + * scsi_change_queue_depth - allow LLD to change queue depth on a SCSI device * @sdev: pointer to SCSI device to change queue depth on * @tags Number of tags allowed if tagged queuing enabled, * or number of commands the LLD can queue up @@ -453,7 +453,7 @@ int scsi_add_host(struct Scsi_Host *shost, struct device * dev) * Defined in: drivers/scsi/scsi.c [see source code for more notes] * **/ -void scsi_adjust_queue_depth(struct scsi_device *sdev, int tags) +int scsi_change_queue_depth(struct scsi_device *sdev, int tags) /** @@ -1214,7 +1214,7 @@ of interest: for disk firmware uploads. cmd_per_lun - maximum number of commands that can be queued on devices controlled by the host. Overridden by LLD calls to - scsi_adjust_queue_depth(). + scsi_change_queue_depth(). unchecked_isa_dma - 1=>only use bottom 16 MB of ram (ISA DMA addressing restriction), 0=>can use full 32 bit (or better) DMA address space @@ -1254,7 +1254,7 @@ struct scsi_cmnd Instances of this structure convey SCSI commands to the LLD and responses back to the mid level. The SCSI mid level will ensure that no more SCSI commands become queued against the LLD than are indicated by -scsi_adjust_queue_depth() (or struct Scsi_Host::cmd_per_lun). There will +scsi_change_queue_depth() (or struct Scsi_Host::cmd_per_lun). There will be at least one instance of struct scsi_cmnd available for each SCSI device. Members of interest: cmnd - array containing SCSI command diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index c8bb6abbf12c..de46385dbe71 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1164,7 +1164,7 @@ static int ata_scsi_dev_config(struct scsi_device *sdev, depth = min(sdev->host->can_queue, ata_id_queue_depth(dev->id)); depth = min(ATA_MAX_QUEUE - 1, depth); - scsi_adjust_queue_depth(sdev, depth); + scsi_change_queue_depth(sdev, depth); } blk_queue_flush_queueable(q, false); @@ -1243,21 +1243,17 @@ void ata_scsi_slave_destroy(struct scsi_device *sdev) * @ap: ATA port to which the device change the queue depth * @sdev: SCSI device to configure queue depth for * @queue_depth: new queue depth - * @reason: calling context * * libsas and libata have different approaches for associating a sdev to * its ata_port. * */ int __ata_change_queue_depth(struct ata_port *ap, struct scsi_device *sdev, - int queue_depth, int reason) + int queue_depth) { struct ata_device *dev; unsigned long flags; - if (reason != SCSI_QDEPTH_DEFAULT) - return -EOPNOTSUPP; - if (queue_depth < 1 || queue_depth == sdev->queue_depth) return sdev->queue_depth; @@ -1282,15 +1278,13 @@ int __ata_change_queue_depth(struct ata_port *ap, struct scsi_device *sdev, if (sdev->queue_depth == queue_depth) return -EINVAL; - scsi_adjust_queue_depth(sdev, queue_depth); - return queue_depth; + return scsi_change_queue_depth(sdev, queue_depth); } /** * ata_scsi_change_queue_depth - SCSI callback for queue depth config * @sdev: SCSI device to configure queue depth for * @queue_depth: new queue depth - * @reason: calling context * * This is libata standard hostt->change_queue_depth callback. * SCSI will call into this callback when user tries to set queue @@ -1302,12 +1296,11 @@ int __ata_change_queue_depth(struct ata_port *ap, struct scsi_device *sdev, * RETURNS: * Newly configured queue depth. */ -int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth, - int reason) +int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth) { struct ata_port *ap = ata_shost_to_port(sdev->host); - return __ata_change_queue_depth(ap, sdev, queue_depth, reason); + return __ata_change_queue_depth(ap, sdev, queue_depth); } /** diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index cdf99fac139a..1db6f5ce5e89 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -1951,7 +1951,7 @@ static int nv_swncq_slave_config(struct scsi_device *sdev) ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num)); if (strncmp(model_num, "Maxtor", 6) == 0) { - ata_scsi_change_queue_depth(sdev, 1, SCSI_QDEPTH_DEFAULT); + ata_scsi_change_queue_depth(sdev, 1); ata_dev_notice(dev, "Disabling SWNCQ mode (depth %x)\n", sdev->queue_depth); } diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index 812a2891de58..20ca6a619476 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -911,7 +911,7 @@ static struct scsi_host_template iscsi_iser_sht = { .module = THIS_MODULE, .name = "iSCSI Initiator over iSER", .queuecommand = iscsi_queuecommand, - .change_queue_depth = iscsi_change_queue_depth, + .change_queue_depth = scsi_change_queue_depth, .sg_tablesize = ISCSI_ISER_SG_TABLESIZE, .max_sectors = 1024, .cmd_per_lun = ISER_DEF_CMD_PER_LUN, diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 8d13a19e04b2..5461924c9f10 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -2402,18 +2402,15 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event) * srp_change_queue_depth - setting device queue depth * @sdev: scsi device struct * @qdepth: requested queue depth - * @reason: SCSI_QDEPTH_DEFAULT - * (see include/scsi/scsi_host.h for definition) * * Returns queue depth. */ static int -srp_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason) +srp_change_queue_depth(struct scsi_device *sdev, int qdepth) { if (!sdev->tagged_supported) qdepth = 1; - scsi_adjust_queue_depth(sdev, qdepth); - return sdev->queue_depth; + return scsi_change_queue_depth(sdev, qdepth); } static int srp_send_tsk_mgmt(struct srp_rdma_ch *ch, u64 req_tag, diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index dee06d6f0b68..6c9fc11efb87 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -2311,12 +2311,11 @@ mptscsih_slave_destroy(struct scsi_device *sdev) * mptscsih_change_queue_depth - This function will set a devices queue depth * @sdev: per scsi_device pointer * @qdepth: requested queue depth - * @reason: calling context * * Adding support for new 'change_queue_depth' api. */ int -mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason) +mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth) { MPT_SCSI_HOST *hd = shost_priv(sdev->host); VirtTarget *vtarget; @@ -2327,9 +2326,6 @@ mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason) starget = scsi_target(sdev); vtarget = starget->hostdata; - if (reason != SCSI_QDEPTH_DEFAULT) - return -EOPNOTSUPP; - if (ioc->bus_type == SPI) { if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)) max_depth = 1; @@ -2347,8 +2343,7 @@ mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason) if (qdepth > max_depth) qdepth = max_depth; - scsi_adjust_queue_depth(sdev, qdepth); - return sdev->queue_depth; + return scsi_change_queue_depth(sdev, qdepth); } /* @@ -2392,8 +2387,7 @@ mptscsih_slave_configure(struct scsi_device *sdev) ioc->name, vtarget->negoFlags, vtarget->maxOffset, vtarget->minSyncFactor)); - mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH, - SCSI_QDEPTH_DEFAULT); + mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH); dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "tagged %d, simple %d\n", ioc->name,sdev->tagged_supported, sdev->simple_tags)); diff --git a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h index e1b1a198a62a..2baeefd9be7a 100644 --- a/drivers/message/fusion/mptscsih.h +++ b/drivers/message/fusion/mptscsih.h @@ -128,8 +128,7 @@ extern int mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_F extern int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r); extern int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply); extern int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset); -extern int mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth, - int reason); +extern int mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth); extern u8 mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id); extern int mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id); extern struct device_attribute *mptscsih_host_attrs[]; diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 179bf3d8af6c..75f4bfc2b98a 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -32,13 +32,6 @@ static bool allow_lun_scan = 1; module_param(allow_lun_scan, bool, 0600); MODULE_PARM_DESC(allow_lun_scan, "For NPIV, scan and attach all storage LUNs"); -static int zfcp_scsi_change_queue_depth(struct scsi_device *sdev, int depth, - int reason) -{ - scsi_adjust_queue_depth(sdev, depth); - return sdev->queue_depth; -} - static void zfcp_scsi_slave_destroy(struct scsi_device *sdev) { struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); @@ -54,7 +47,7 @@ static void zfcp_scsi_slave_destroy(struct scsi_device *sdev) static int zfcp_scsi_slave_configure(struct scsi_device *sdp) { if (sdp->tagged_supported) - scsi_adjust_queue_depth(sdp, default_depth); + scsi_change_queue_depth(sdp, default_depth); return 0; } @@ -293,7 +286,7 @@ static struct scsi_host_template zfcp_scsi_host_template = { .slave_alloc = zfcp_scsi_slave_alloc, .slave_configure = zfcp_scsi_slave_configure, .slave_destroy = zfcp_scsi_slave_destroy, - .change_queue_depth = zfcp_scsi_change_queue_depth, + .change_queue_depth = scsi_change_queue_depth, .proc_name = "zfcp", .can_queue = 4096, .this_id = -1, diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c index 1cf37032290a..cd4129ff7ae4 100644 --- a/drivers/scsi/3w-9xxx.c +++ b/drivers/scsi/3w-9xxx.c @@ -189,17 +189,6 @@ static ssize_t twa_show_stats(struct device *dev, return len; } /* End twa_show_stats() */ -/* This function will set a devices queue depth */ -static int twa_change_queue_depth(struct scsi_device *sdev, int queue_depth, - int reason) -{ - if (reason != SCSI_QDEPTH_DEFAULT) - return -EOPNOTSUPP; - - scsi_adjust_queue_depth(sdev, queue_depth); - return queue_depth; -} /* End twa_change_queue_depth() */ - /* Create sysfs 'stats' entry */ static struct device_attribute twa_host_stats_attr = { .attr = { @@ -2014,7 +2003,7 @@ static struct scsi_host_template driver_template = { .queuecommand = twa_scsi_queue, .eh_host_reset_handler = twa_scsi_eh_reset, .bios_param = twa_scsi_biosparam, - .change_queue_depth = twa_change_queue_depth, + .change_queue_depth = scsi_change_queue_depth, .can_queue = TW_Q_LENGTH-2, .slave_configure = twa_slave_configure, .this_id = -1, diff --git a/drivers/scsi/3w-sas.c b/drivers/scsi/3w-sas.c index 547756b7d5bf..2361772d5909 100644 --- a/drivers/scsi/3w-sas.c +++ b/drivers/scsi/3w-sas.c @@ -191,17 +191,6 @@ static ssize_t twl_show_stats(struct device *dev, return len; } /* End twl_show_stats() */ -/* This function will set a devices queue depth */ -static int twl_change_queue_depth(struct scsi_device *sdev, int queue_depth, - int reason) -{ - if (reason != SCSI_QDEPTH_DEFAULT) - return -EOPNOTSUPP; - - scsi_adjust_queue_depth(sdev, queue_depth); - return queue_depth; -} /* End twl_change_queue_depth() */ - /* stats sysfs attribute initializer */ static struct device_attribute twl_host_stats_attr = { .attr = { @@ -1588,7 +1577,7 @@ static struct scsi_host_template driver_template = { .queuecommand = twl_scsi_queue, .eh_host_reset_handler = twl_scsi_eh_reset, .bios_param = twl_scsi_biosparam, - .change_queue_depth = twl_change_queue_depth, + .change_queue_depth = scsi_change_queue_depth, .can_queue = TW_Q_LENGTH-2, .slave_configure = twl_slave_configure, .this_id = -1, diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c index 261a4c1da962..c75f2048319f 100644 --- a/drivers/scsi/3w-xxxx.c +++ b/drivers/scsi/3w-xxxx.c @@ -523,17 +523,6 @@ static ssize_t tw_show_stats(struct device *dev, struct device_attribute *attr, return len; } /* End tw_show_stats() */ -/* This function will set a devices queue depth */ -static int tw_change_queue_depth(struct scsi_device *sdev, int queue_depth, - int reason) -{ - if (reason != SCSI_QDEPTH_DEFAULT) - return -EOPNOTSUPP; - - scsi_adjust_queue_depth(sdev, queue_depth); - return queue_depth; -} /* End tw_change_queue_depth() */ - /* Create sysfs 'stats' entry */ static struct device_attribute tw_host_stats_attr = { .attr = { @@ -2268,7 +2257,7 @@ static struct scsi_host_template driver_template = { .queuecommand = tw_scsi_queue, .eh_host_reset_handler = tw_scsi_eh_reset, .bios_param = tw_scsi_biosparam, - .change_queue_depth = tw_change_queue_depth, + .change_queue_depth = scsi_change_queue_depth, .can_queue = TW_Q_LENGTH-2, .slave_configure = tw_slave_configure, .this_id = -1, diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c index d7557b932113..aa915da2a5e5 100644 --- a/drivers/scsi/53c700.c +++ b/drivers/scsi/53c700.c @@ -175,7 +175,7 @@ STATIC void NCR_700_chip_reset(struct Scsi_Host *host); STATIC int NCR_700_slave_alloc(struct scsi_device *SDpnt); STATIC int NCR_700_slave_configure(struct scsi_device *SDpnt); STATIC void NCR_700_slave_destroy(struct scsi_device *SDpnt); -static int NCR_700_change_queue_depth(struct scsi_device *SDpnt, int depth, int reason); +static int NCR_700_change_queue_depth(struct scsi_device *SDpnt, int depth); static int NCR_700_change_queue_type(struct scsi_device *SDpnt, int depth); STATIC struct device_attribute *NCR_700_dev_attrs[]; @@ -904,7 +904,7 @@ process_message(struct Scsi_Host *host, struct NCR_700_Host_Parameters *hostdata hostdata->tag_negotiated &= ~(1<device->tagged_supported = 0; - scsi_adjust_queue_depth(SCp->device, host->cmd_per_lun); + scsi_change_queue_depth(SCp->device, host->cmd_per_lun); scsi_set_tag_type(SCp->device, 0); } else { shost_printk(KERN_WARNING, host, @@ -2052,7 +2052,7 @@ NCR_700_slave_configure(struct scsi_device *SDp) /* to do here: allocate memory; build a queue_full list */ if(SDp->tagged_supported) { - scsi_adjust_queue_depth(SDp, NCR_700_DEFAULT_TAGS); + scsi_change_queue_depth(SDp, NCR_700_DEFAULT_TAGS); NCR_700_set_tag_neg_state(SDp, NCR_700_START_TAG_NEGOTIATION); } @@ -2075,16 +2075,11 @@ NCR_700_slave_destroy(struct scsi_device *SDp) } static int -NCR_700_change_queue_depth(struct scsi_device *SDp, int depth, int reason) +NCR_700_change_queue_depth(struct scsi_device *SDp, int depth) { - if (reason != SCSI_QDEPTH_DEFAULT) - return -EOPNOTSUPP; - if (depth > NCR_700_MAX_TAGS) depth = NCR_700_MAX_TAGS; - - scsi_adjust_queue_depth(SDp, depth); - return depth; + return scsi_change_queue_depth(SDp, depth); } static int NCR_700_change_queue_type(struct scsi_device *SDp, int tag_type) @@ -2105,12 +2100,12 @@ static int NCR_700_change_queue_type(struct scsi_device *SDp, int tag_type) if (!tag_type) { /* shift back to the default unqueued number of commands * (the user can still raise this) */ - scsi_adjust_queue_depth(SDp, SDp->host->cmd_per_lun); + scsi_change_queue_depth(SDp, SDp->host->cmd_per_lun); hostdata->tag_negotiated &= ~(1 << sdev_id(SDp)); } else { /* Here, we cleared the negotiation flag above, so this * will force the driver to renegotiate */ - scsi_adjust_queue_depth(SDp, SDp->queue_depth); + scsi_change_queue_depth(SDp, SDp->queue_depth); if (change_tag) NCR_700_set_tag_neg_state(SDp, NCR_700_START_TAG_NEGOTIATION); } diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c index 5aa476b6b8a8..8d66a6469e29 100644 --- a/drivers/scsi/BusLogic.c +++ b/drivers/scsi/BusLogic.c @@ -2327,12 +2327,12 @@ static int blogic_slaveconfig(struct scsi_device *dev) if (qdepth == 0) qdepth = BLOGIC_MAX_AUTO_TAG_DEPTH; adapter->qdepth[tgt_id] = qdepth; - scsi_adjust_queue_depth(dev, qdepth); + scsi_change_queue_depth(dev, qdepth); } else { adapter->tagq_ok &= ~(1 << tgt_id); qdepth = adapter->untag_qdepth; adapter->qdepth[tgt_id] = qdepth; - scsi_adjust_queue_depth(dev, qdepth); + scsi_change_queue_depth(dev, qdepth); } qdepth = 0; for (tgt_id = 0; tgt_id < adapter->maxdev; tgt_id++) diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 41b9c68bca67..d11c23aad046 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -462,9 +462,9 @@ static int aac_slave_configure(struct scsi_device *sdev) depth = 256; else if (depth < 2) depth = 2; - scsi_adjust_queue_depth(sdev, depth); + scsi_change_queue_depth(sdev, depth); } else - scsi_adjust_queue_depth(sdev, 1); + scsi_change_queue_depth(sdev, 1); return 0; } @@ -478,12 +478,8 @@ static int aac_slave_configure(struct scsi_device *sdev) * total capacity and the queue depth supported by the target device. */ -static int aac_change_queue_depth(struct scsi_device *sdev, int depth, - int reason) +static int aac_change_queue_depth(struct scsi_device *sdev, int depth) { - if (reason != SCSI_QDEPTH_DEFAULT) - return -EOPNOTSUPP; - if (sdev->tagged_supported && (sdev->type == TYPE_DISK) && (sdev_channel(sdev) == CONTAINER_CHANNEL)) { struct scsi_device * dev; @@ -504,10 +500,10 @@ static int aac_change_queue_depth(struct scsi_device *sdev, int depth, depth = 256; else if (depth < 2) depth = 2; - scsi_adjust_queue_depth(sdev, depth); - } else - scsi_adjust_queue_depth(sdev, 1); - return sdev->queue_depth; + return scsi_change_queue_depth(sdev, depth); + } + + return scsi_change_queue_depth(sdev, 1); } static ssize_t aac_show_raid_level(struct device *dev, struct device_attribute *attr, char *buf) diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index ae4840e4c1c5..6719a3390ebd 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -7706,7 +7706,7 @@ advansys_narrow_slave_configure(struct scsi_device *sdev, ASC_DVC_VAR *asc_dvc) asc_dvc->cfg->can_tagged_qng |= tid_bit; asc_dvc->use_tagged_qng |= tid_bit; } - scsi_adjust_queue_depth(sdev, + scsi_change_queue_depth(sdev, asc_dvc->max_dvc_qng[sdev->id]); } } else { @@ -7847,10 +7847,8 @@ advansys_wide_slave_configure(struct scsi_device *sdev, ADV_DVC_VAR *adv_dvc) } } - if ((adv_dvc->tagqng_able & tidmask) && sdev->tagged_supported) { - scsi_adjust_queue_depth(sdev, - adv_dvc->max_dvc_qng); - } + if ((adv_dvc->tagqng_able & tidmask) && sdev->tagged_supported) + scsi_change_queue_depth(sdev, adv_dvc->max_dvc_qng); } /* diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index 80cb4fd7caaa..d5c7b193d8d3 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -1470,7 +1470,7 @@ ahd_platform_set_tags(struct ahd_softc *ahd, struct scsi_device *sdev, switch ((dev->flags & (AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED))) { case AHD_DEV_Q_BASIC: case AHD_DEV_Q_TAGGED: - scsi_adjust_queue_depth(sdev, + scsi_change_queue_depth(sdev, dev->openings + dev->active); break; default: @@ -1480,7 +1480,7 @@ ahd_platform_set_tags(struct ahd_softc *ahd, struct scsi_device *sdev, * serially on the controller/device. This should * remove some latency. */ - scsi_adjust_queue_depth(sdev, 1); + scsi_change_queue_depth(sdev, 1); break; } } diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index a6a27d5398dd..88360116dbcb 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -1336,7 +1336,7 @@ ahc_platform_set_tags(struct ahc_softc *ahc, struct scsi_device *sdev, switch ((dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED))) { case AHC_DEV_Q_BASIC: case AHC_DEV_Q_TAGGED: - scsi_adjust_queue_depth(sdev, + scsi_change_queue_depth(sdev, dev->openings + dev->active); default: /* @@ -1345,7 +1345,7 @@ ahc_platform_set_tags(struct ahc_softc *ahc, struct scsi_device *sdev, * serially on the controller/device. This should * remove some latency. */ - scsi_adjust_queue_depth(sdev, 2); + scsi_change_queue_depth(sdev, 2); break; } } diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index 209f77162d06..914c39f9f388 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -114,16 +114,11 @@ static void arcmsr_hardware_reset(struct AdapterControlBlock *acb); static const char *arcmsr_info(struct Scsi_Host *); static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb); static void arcmsr_free_irq(struct pci_dev *, struct AdapterControlBlock *); -static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev, - int queue_depth, int reason) +static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev, int queue_depth) { - if (reason != SCSI_QDEPTH_DEFAULT) - return -EOPNOTSUPP; - if (queue_depth > ARCMSR_MAX_CMD_PERLUN) queue_depth = ARCMSR_MAX_CMD_PERLUN; - scsi_adjust_queue_depth(sdev, queue_depth); - return queue_depth; + return scsi_change_queue_depth(sdev, queue_depth); } static struct scsi_host_template arcmsr_scsi_host_template = { diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index d9b999a3416f..f3193406776c 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -556,7 +556,7 @@ static struct scsi_host_template beiscsi_sht = { .name = "Emulex 10Gbe open-iscsi Initiator Driver", .proc_name = DRV_NAME, .queuecommand = iscsi_queuecommand, - .change_queue_depth = iscsi_change_queue_depth, + .change_queue_depth = scsi_change_queue_depth, .slave_configure = beiscsi_slave_configure, .target_alloc = iscsi_target_alloc, .eh_abort_handler = beiscsi_eh_abort, diff --git a/drivers/scsi/bfa/bfad_im.c b/drivers/scsi/bfa/bfad_im.c index 87b09cd232cc..7223b0006740 100644 --- a/drivers/scsi/bfa/bfad_im.c +++ b/drivers/scsi/bfa/bfad_im.c @@ -776,7 +776,7 @@ bfad_thread_workq(struct bfad_s *bfad) static int bfad_im_slave_configure(struct scsi_device *sdev) { - scsi_adjust_queue_depth(sdev, bfa_lun_queue_depth); + scsi_change_queue_depth(sdev, bfa_lun_queue_depth); return 0; } @@ -866,7 +866,7 @@ bfad_ramp_up_qdepth(struct bfad_itnim_s *itnim, struct scsi_device *sdev) if (bfa_lun_queue_depth > tmp_sdev->queue_depth) { if (tmp_sdev->id != sdev->id) continue; - scsi_adjust_queue_depth(tmp_sdev, + scsi_change_queue_depth(tmp_sdev, tmp_sdev->queue_depth + 1); itnim->last_ramp_up_time = jiffies; diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index cc537972f3ea..386c2cfad306 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -2784,7 +2784,7 @@ static struct scsi_host_template bnx2fc_shost_template = { .eh_target_reset_handler = bnx2fc_eh_target_reset, /* tgt reset */ .eh_host_reset_handler = fc_eh_host_reset, .slave_alloc = fc_slave_alloc, - .change_queue_depth = fc_change_queue_depth, + .change_queue_depth = scsi_change_queue_depth, .change_queue_type = scsi_change_queue_type, .this_id = -1, .cmd_per_lun = 3, diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c index 9de1c20bb0f8..e53078d03309 100644 --- a/drivers/scsi/bnx2i/bnx2i_iscsi.c +++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c @@ -2259,7 +2259,7 @@ static struct scsi_host_template bnx2i_host_template = { .eh_abort_handler = iscsi_eh_abort, .eh_device_reset_handler = iscsi_eh_device_reset, .eh_target_reset_handler = iscsi_eh_recover_target, - .change_queue_depth = iscsi_change_queue_depth, + .change_queue_depth = scsi_change_queue_depth, .target_alloc = iscsi_target_alloc, .can_queue = 2048, .max_sectors = 127, diff --git a/drivers/scsi/csiostor/csio_scsi.c b/drivers/scsi/csiostor/csio_scsi.c index 44a8cc51428f..4d0b6ce55f20 100644 --- a/drivers/scsi/csiostor/csio_scsi.c +++ b/drivers/scsi/csiostor/csio_scsi.c @@ -2241,7 +2241,7 @@ csio_slave_alloc(struct scsi_device *sdev) static int csio_slave_configure(struct scsi_device *sdev) { - scsi_adjust_queue_depth(sdev, csio_lun_qdepth); + scsi_change_queue_depth(sdev, csio_lun_qdepth); return 0; } diff --git a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c index 99ea67dcdd2a..3db4c63978c5 100644 --- a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c +++ b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c @@ -86,7 +86,7 @@ static struct scsi_host_template cxgb3i_host_template = { .proc_name = DRV_MODULE_NAME, .can_queue = CXGB3I_SCSI_HOST_QDEPTH, .queuecommand = iscsi_queuecommand, - .change_queue_depth = iscsi_change_queue_depth, + .change_queue_depth = scsi_change_queue_depth, .sg_tablesize = SG_ALL, .max_sectors = 0xFFFF, .cmd_per_lun = ISCSI_DEF_CMD_PER_LUN, diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c index af86e8f57b84..efe42ef7d92b 100644 --- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c +++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c @@ -89,7 +89,7 @@ static struct scsi_host_template cxgb4i_host_template = { .proc_name = DRV_MODULE_NAME, .can_queue = CXGB4I_SCSI_HOST_QDEPTH, .queuecommand = iscsi_queuecommand, - .change_queue_depth = iscsi_change_queue_depth, + .change_queue_depth = scsi_change_queue_depth, .sg_tablesize = SG_ALL, .max_sectors = 0xFFFF, .cmd_per_lun = ISCSI_DEF_CMD_PER_LUN, diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c index 1af8d54bcded..0bf976936a10 100644 --- a/drivers/scsi/dpt_i2o.c +++ b/drivers/scsi/dpt_i2o.c @@ -415,7 +415,7 @@ static int adpt_slave_configure(struct scsi_device * device) pHba = (adpt_hba *) host->hostdata[0]; if (host->can_queue && device->tagged_supported) { - scsi_adjust_queue_depth(device, + scsi_change_queue_depth(device, host->can_queue - 1); } return 0; diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c index bc0f918f1729..227dd2c2ec2f 100644 --- a/drivers/scsi/eata.c +++ b/drivers/scsi/eata.c @@ -952,12 +952,12 @@ static int eata2x_slave_configure(struct scsi_device *dev) } else { tag_suffix = ", no tags"; } - scsi_adjust_queue_depth(dev, tqd); + scsi_change_queue_depth(dev, tqd); } else if (TLDEV(dev->type) && linked_comm) { - scsi_adjust_queue_depth(dev, tqd); + scsi_change_queue_depth(dev, tqd); tag_suffix = ", untagged"; } else { - scsi_adjust_queue_depth(dev, utqd); + scsi_change_queue_depth(dev, utqd); tag_suffix = ""; } diff --git a/drivers/scsi/esas2r/esas2r.h b/drivers/scsi/esas2r/esas2r.h index 1941d837f6f2..b6030e3edd01 100644 --- a/drivers/scsi/esas2r/esas2r.h +++ b/drivers/scsi/esas2r/esas2r.h @@ -972,7 +972,6 @@ u8 handle_hba_ioctl(struct esas2r_adapter *a, struct atto_ioctl *ioctl_hba); int esas2r_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd); int esas2r_show_info(struct seq_file *m, struct Scsi_Host *sh); -int esas2r_change_queue_depth(struct scsi_device *dev, int depth, int reason); long esas2r_proc_ioctl(struct file *fp, unsigned int cmd, unsigned long arg); /* SCSI error handler (eh) functions */ diff --git a/drivers/scsi/esas2r/esas2r_main.c b/drivers/scsi/esas2r/esas2r_main.c index 30fce64faf75..593ff8a63c70 100644 --- a/drivers/scsi/esas2r/esas2r_main.c +++ b/drivers/scsi/esas2r/esas2r_main.c @@ -254,7 +254,7 @@ static struct scsi_host_template driver_template = { .use_clustering = ENABLE_CLUSTERING, .emulated = 0, .proc_name = ESAS2R_DRVR_NAME, - .change_queue_depth = esas2r_change_queue_depth, + .change_queue_depth = scsi_change_queue_depth, .change_queue_type = scsi_change_queue_type, .max_sectors = 0xFFFF, .use_blk_tags = 1, @@ -1257,15 +1257,6 @@ int esas2r_target_reset(struct scsi_cmnd *cmd) return esas2r_dev_targ_reset(cmd, true); } -int esas2r_change_queue_depth(struct scsi_device *dev, int depth, int reason) -{ - esas2r_log(ESAS2R_LOG_INFO, "change_queue_depth %p, %d", dev, depth); - - scsi_adjust_queue_depth(dev, depth); - - return dev->queue_depth; -} - void esas2r_log_request_failure(struct esas2r_adapter *a, struct esas2r_request *rq) { diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c index 38c23e0b73af..7e7687f73deb 100644 --- a/drivers/scsi/esp_scsi.c +++ b/drivers/scsi/esp_scsi.c @@ -2407,7 +2407,7 @@ static int esp_slave_configure(struct scsi_device *dev) /* XXX make this configurable somehow XXX */ int goal_tags = min(ESP_DEFAULT_TAGS, ESP_MAX_TAG); - scsi_adjust_queue_depth(dev, goal_tags); + scsi_change_queue_depth(dev, goal_tags); } tp->flags |= ESP_TGT_DISCONNECT; diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 97229860398f..308a016fdaea 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -280,7 +280,7 @@ static struct scsi_host_template fcoe_shost_template = { .eh_device_reset_handler = fc_eh_device_reset, .eh_host_reset_handler = fc_eh_host_reset, .slave_alloc = fc_slave_alloc, - .change_queue_depth = fc_change_queue_depth, + .change_queue_depth = scsi_change_queue_depth, .change_queue_type = scsi_change_queue_type, .this_id = -1, .cmd_per_lun = 3, diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c index 86b496c8633d..0c1f8177b5b7 100644 --- a/drivers/scsi/fnic/fnic_main.c +++ b/drivers/scsi/fnic/fnic_main.c @@ -98,7 +98,7 @@ static int fnic_slave_alloc(struct scsi_device *sdev) if (!rport || fc_remote_port_chkready(rport)) return -ENXIO; - scsi_adjust_queue_depth(sdev, fnic_max_qdepth); + scsi_change_queue_depth(sdev, fnic_max_qdepth); return 0; } @@ -110,7 +110,7 @@ static struct scsi_host_template fnic_host_template = { .eh_device_reset_handler = fnic_device_reset, .eh_host_reset_handler = fnic_host_reset, .slave_alloc = fnic_slave_alloc, - .change_queue_depth = fc_change_queue_depth, + .change_queue_depth = scsi_change_queue_depth, .change_queue_type = scsi_change_queue_type, .this_id = -1, .cmd_per_lun = 3, diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 617f218e2a16..6bb4611b238a 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -216,8 +216,6 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *h, struct scsi_cmnd *cmd); static void hpsa_scan_start(struct Scsi_Host *); static int hpsa_scan_finished(struct Scsi_Host *sh, unsigned long elapsed_time); -static int hpsa_change_queue_depth(struct scsi_device *sdev, - int qdepth, int reason); static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd); static int hpsa_eh_abort_handler(struct scsi_cmnd *scsicmd); @@ -673,7 +671,7 @@ static struct scsi_host_template hpsa_driver_template = { .queuecommand = hpsa_scsi_queue_command, .scan_start = hpsa_scan_start, .scan_finished = hpsa_scan_finished, - .change_queue_depth = hpsa_change_queue_depth, + .change_queue_depth = scsi_change_queue_depth, .this_id = -1, .use_clustering = ENABLE_CLUSTERING, .eh_abort_handler = hpsa_eh_abort_handler, @@ -4074,18 +4072,6 @@ static int hpsa_scan_finished(struct Scsi_Host *sh, return finished; } -static int hpsa_change_queue_depth(struct scsi_device *sdev, - int qdepth, int reason) -{ - struct ctlr_info *h = sdev_to_hba(sdev); - - if (reason != SCSI_QDEPTH_DEFAULT) - return -ENOTSUPP; - - scsi_adjust_queue_depth(sdev, qdepth); - return sdev->queue_depth; -} - static void hpsa_unregister_scsi(struct ctlr_info *h) { /* we are being forcibly unloaded, and may not refuse. */ diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c index 151893148abd..e995218476ed 100644 --- a/drivers/scsi/hptiop.c +++ b/drivers/scsi/hptiop.c @@ -1118,17 +1118,13 @@ static int hptiop_reset(struct scsi_cmnd *scp) } static int hptiop_adjust_disk_queue_depth(struct scsi_device *sdev, - int queue_depth, int reason) + int queue_depth) { struct hptiop_hba *hba = (struct hptiop_hba *)sdev->host->hostdata; - if (reason != SCSI_QDEPTH_DEFAULT) - return -EOPNOTSUPP; - if (queue_depth > hba->max_requests) queue_depth = hba->max_requests; - scsi_adjust_queue_depth(sdev, queue_depth); - return queue_depth; + return scsi_change_queue_depth(sdev, queue_depth); } static ssize_t hptiop_show_version(struct device *dev, diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index 381449d5be76..f58c6d8e0264 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -2900,17 +2900,12 @@ static int ibmvfc_slave_configure(struct scsi_device *sdev) * Return value: * actual depth set **/ -static int ibmvfc_change_queue_depth(struct scsi_device *sdev, int qdepth, - int reason) +static int ibmvfc_change_queue_depth(struct scsi_device *sdev, int qdepth) { - if (reason != SCSI_QDEPTH_DEFAULT) - return -EOPNOTSUPP; - if (qdepth > IBMVFC_MAX_CMDS_PER_LUN) qdepth = IBMVFC_MAX_CMDS_PER_LUN; - scsi_adjust_queue_depth(sdev, qdepth); - return sdev->queue_depth; + return scsi_change_queue_depth(sdev, qdepth); } static ssize_t ibmvfc_show_host_partition_name(struct device *dev, diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index e8c3cdf0d03b..acea5d6eebd0 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -1941,17 +1941,11 @@ static int ibmvscsi_slave_configure(struct scsi_device *sdev) * Return value: * actual depth set **/ -static int ibmvscsi_change_queue_depth(struct scsi_device *sdev, int qdepth, - int reason) +static int ibmvscsi_change_queue_depth(struct scsi_device *sdev, int qdepth) { - if (reason != SCSI_QDEPTH_DEFAULT) - return -EOPNOTSUPP; - if (qdepth > IBMVSCSI_MAX_CMDS_PER_LUN) qdepth = IBMVSCSI_MAX_CMDS_PER_LUN; - - scsi_adjust_queue_depth(sdev, qdepth); - return sdev->queue_depth; + return scsi_change_queue_depth(sdev, qdepth); } /* ------------------------------------------------------------ diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index d8d16625a876..540294389355 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -4328,16 +4328,12 @@ static int ipr_free_dump(struct ipr_ioa_cfg *ioa_cfg) { return 0; }; * Return value: * actual depth set **/ -static int ipr_change_queue_depth(struct scsi_device *sdev, int qdepth, - int reason) +static int ipr_change_queue_depth(struct scsi_device *sdev, int qdepth) { struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)sdev->host->hostdata; struct ipr_resource_entry *res; unsigned long lock_flags = 0; - if (reason != SCSI_QDEPTH_DEFAULT) - return -EOPNOTSUPP; - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); res = (struct ipr_resource_entry *)sdev->hostdata; @@ -4345,7 +4341,7 @@ static int ipr_change_queue_depth(struct scsi_device *sdev, int qdepth, qdepth = IPR_MAX_CMD_PER_ATA_LUN; spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - scsi_adjust_queue_depth(sdev, qdepth); + scsi_change_queue_depth(sdev, qdepth); return sdev->queue_depth; } @@ -4752,7 +4748,7 @@ static int ipr_slave_configure(struct scsi_device *sdev) spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); if (ap) { - scsi_adjust_queue_depth(sdev, IPR_MAX_CMD_PER_ATA_LUN); + scsi_change_queue_depth(sdev, IPR_MAX_CMD_PER_ATA_LUN); ata_sas_slave_configure(sdev, ap); } diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c index 454741a8da45..e5c28435d768 100644 --- a/drivers/scsi/ips.c +++ b/drivers/scsi/ips.c @@ -1210,7 +1210,7 @@ ips_slave_configure(struct scsi_device * SDptr) min = ha->max_cmds / 2; if (ha->enq->ucLogDriveCount <= 2) min = ha->max_cmds - 1; - scsi_adjust_queue_depth(SDptr, min); + scsi_change_queue_depth(SDptr, min); } SDptr->skip_ms_page_8 = 1; diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index a575d845b667..0b8af186e707 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -952,7 +952,7 @@ static struct scsi_host_template iscsi_sw_tcp_sht = { .module = THIS_MODULE, .name = "iSCSI Initiator over TCP/IP", .queuecommand = iscsi_queuecommand, - .change_queue_depth = iscsi_change_queue_depth, + .change_queue_depth = scsi_change_queue_depth, .can_queue = ISCSI_DEF_XMIT_CMDS_MAX - 1, .sg_tablesize = 4096, .max_sectors = 0xFFFF, diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index 0d2d024e77c5..c6795941b45d 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -2160,24 +2160,11 @@ int fc_slave_alloc(struct scsi_device *sdev) if (!rport || fc_remote_port_chkready(rport)) return -ENXIO; - scsi_adjust_queue_depth(sdev, FC_FCP_DFLT_QUEUE_DEPTH); + scsi_change_queue_depth(sdev, FC_FCP_DFLT_QUEUE_DEPTH); return 0; } EXPORT_SYMBOL(fc_slave_alloc); -/** - * fc_change_queue_depth() - Change a device's queue depth - * @sdev: The SCSI device whose queue depth is to change - * @qdepth: The new queue depth - * @reason: The resason for the change - */ -int fc_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason) -{ - scsi_adjust_queue_depth(sdev, qdepth); - return sdev->queue_depth; -} -EXPORT_SYMBOL(fc_change_queue_depth); - /** * fc_fcp_destory() - Tear down the FCP layer for a given local port * @lport: The local port that no longer needs the FCP layer diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 79e977484ad5..8053f24f0349 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1771,13 +1771,6 @@ fault: } EXPORT_SYMBOL_GPL(iscsi_queuecommand); -int iscsi_change_queue_depth(struct scsi_device *sdev, int depth, int reason) -{ - scsi_adjust_queue_depth(sdev, depth); - return sdev->queue_depth; -} -EXPORT_SYMBOL_GPL(iscsi_change_queue_depth); - int iscsi_target_alloc(struct scsi_target *starget) { struct iscsi_cls_session *cls_session = starget_to_session(starget); diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index 914e41165137..b492293d51f2 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -940,12 +940,12 @@ int sas_slave_configure(struct scsi_device *scsi_dev) sas_read_port_mode_page(scsi_dev); if (scsi_dev->tagged_supported) { - scsi_adjust_queue_depth(scsi_dev, SAS_DEF_QD); + scsi_change_queue_depth(scsi_dev, SAS_DEF_QD); } else { SAS_DPRINTK("device %llx, LUN %llx doesn't support " "TCQ\n", SAS_ADDR(dev->sas_addr), scsi_dev->lun); - scsi_adjust_queue_depth(scsi_dev, 1); + scsi_change_queue_depth(scsi_dev, 1); } scsi_dev->allow_restart = 1; @@ -953,18 +953,16 @@ int sas_slave_configure(struct scsi_device *scsi_dev) return 0; } -int sas_change_queue_depth(struct scsi_device *sdev, int depth, int reason) +int sas_change_queue_depth(struct scsi_device *sdev, int depth) { struct domain_device *dev = sdev_to_domain_dev(sdev); if (dev_is_sata(dev)) - return __ata_change_queue_depth(dev->sata_dev.ap, sdev, depth, - reason); + return __ata_change_queue_depth(dev->sata_dev.ap, sdev, depth); if (!sdev->tagged_supported) depth = 1; - scsi_adjust_queue_depth(sdev, depth); - return depth; + return scsi_change_queue_depth(sdev, depth); } int sas_change_queue_type(struct scsi_device *scsi_dev, int type) diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 522854920369..fd85952b621d 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -242,23 +242,6 @@ lpfc_update_stats(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd) spin_unlock_irqrestore(shost->host_lock, flags); } -/** - * lpfc_change_queue_depth - Alter scsi device queue depth - * @sdev: Pointer the scsi device on which to change the queue depth. - * @qdepth: New queue depth to set the sdev to. - * @reason: The reason for the queue depth change. - * - * This function is called by the midlayer and the LLD to alter the queue - * depth for a scsi device. This function sets the queue depth to the new - * value and sends an event out to log the queue depth change. - **/ -static int -lpfc_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason) -{ - scsi_adjust_queue_depth(sdev, qdepth); - return sdev->queue_depth; -} - /** * lpfc_rampdown_queue_depth - Post RAMP_DOWN_QUEUE event to worker thread * @phba: The Hba for which this call is being executed. @@ -344,8 +327,7 @@ lpfc_ramp_down_queue_handler(struct lpfc_hba *phba) else new_queue_depth = sdev->queue_depth - new_queue_depth; - lpfc_change_queue_depth(sdev, new_queue_depth, - SCSI_QDEPTH_DEFAULT); + scsi_change_queue_depth(sdev, new_queue_depth); } } lpfc_destroy_vport_work_array(phba, vports); @@ -5513,7 +5495,7 @@ lpfc_slave_configure(struct scsi_device *sdev) struct lpfc_vport *vport = (struct lpfc_vport *) sdev->host->hostdata; struct lpfc_hba *phba = vport->phba; - scsi_adjust_queue_depth(sdev, vport->cfg_lun_queue_depth); + scsi_change_queue_depth(sdev, vport->cfg_lun_queue_depth); if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) { lpfc_sli_handle_fast_ring_event(phba, @@ -5896,7 +5878,7 @@ struct scsi_host_template lpfc_template = { .shost_attrs = lpfc_hba_attrs, .max_sectors = 0xFFFF, .vendor_id = LPFC_NL_VENDOR_ID, - .change_queue_depth = lpfc_change_queue_depth, + .change_queue_depth = scsi_change_queue_depth, .change_queue_type = scsi_change_queue_type, .use_blk_tags = 1, .track_queue_depth = 1, @@ -5921,7 +5903,7 @@ struct scsi_host_template lpfc_vport_template = { .use_clustering = ENABLE_CLUSTERING, .shost_attrs = lpfc_vport_attrs, .max_sectors = 0xFFFF, - .change_queue_depth = lpfc_change_queue_depth, + .change_queue_depth = scsi_change_queue_depth, .change_queue_type = scsi_change_queue_type, .use_blk_tags = 1, .track_queue_depth = 1, diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c index d56eb9d3d40c..f0987f22ea70 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.c +++ b/drivers/scsi/megaraid/megaraid_mbox.c @@ -332,25 +332,6 @@ static struct device_attribute *megaraid_sdev_attrs[] = { NULL, }; -/** - * megaraid_change_queue_depth - Change the device's queue depth - * @sdev: scsi device struct - * @qdepth: depth to set - * @reason: calling context - * - * Return value: - * actual depth set - */ -static int megaraid_change_queue_depth(struct scsi_device *sdev, int qdepth, - int reason) -{ - if (reason != SCSI_QDEPTH_DEFAULT) - return -EOPNOTSUPP; - - scsi_adjust_queue_depth(sdev, qdepth); - return sdev->queue_depth; -} - /* * Scsi host template for megaraid unified driver */ @@ -363,7 +344,7 @@ static struct scsi_host_template megaraid_template_g = { .eh_device_reset_handler = megaraid_reset_handler, .eh_bus_reset_handler = megaraid_reset_handler, .eh_host_reset_handler = megaraid_reset_handler, - .change_queue_depth = megaraid_change_queue_depth, + .change_queue_depth = scsi_change_queue_depth, .use_clustering = ENABLE_CLUSTERING, .no_write_same = 1, .sdev_attrs = megaraid_sdev_attrs, diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 69a9dd6ae04c..f05580e693d0 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -2591,17 +2591,6 @@ megasas_service_aen(struct megasas_instance *instance, struct megasas_cmd *cmd) } } -static int megasas_change_queue_depth(struct scsi_device *sdev, - int queue_depth, int reason) -{ - if (reason != SCSI_QDEPTH_DEFAULT) - return -EOPNOTSUPP; - - scsi_adjust_queue_depth(sdev, queue_depth); - - return queue_depth; -} - static ssize_t megasas_fw_crash_buffer_store(struct device *cdev, struct device_attribute *attr, const char *buf, size_t count) @@ -2766,7 +2755,7 @@ static struct scsi_host_template megasas_template = { .shost_attrs = megaraid_host_attrs, .bios_param = megasas_bios_param, .use_clustering = ENABLE_CLUSTERING, - .change_queue_depth = megasas_change_queue_depth, + .change_queue_depth = scsi_change_queue_depth, .no_write_same = 1, }; diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index b006e1e9fcb8..12229de433bf 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -1222,20 +1222,18 @@ _scsih_adjust_queue_depth(struct scsi_device *sdev, int qdepth) max_depth = 1; if (qdepth > max_depth) qdepth = max_depth; - scsi_adjust_queue_depth(sdev, qdepth); + scsi_change_queue_depth(sdev, qdepth); } /** * _scsih_change_queue_depth - setting device queue depth * @sdev: scsi device struct * @qdepth: requested queue depth - * @reason: SCSI_QDEPTH_DEFAULT - * (see include/scsi/scsi_host.h for definition) * * Returns queue depth. */ static int -_scsih_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason) +_scsih_change_queue_depth(struct scsi_device *sdev, int qdepth) { _scsih_adjust_queue_depth(sdev, qdepth); @@ -2077,7 +2075,7 @@ _scsih_slave_configure(struct scsi_device *sdev) r_level, raid_device->handle, (unsigned long long)raid_device->wwid, raid_device->num_pds, ds); - _scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT); + _scsih_change_queue_depth(sdev, qdepth); /* raid transport support */ if (!ioc->is_warpdrive) _scsih_set_level(sdev, raid_device->volume_type); @@ -2142,7 +2140,7 @@ _scsih_slave_configure(struct scsi_device *sdev) _scsih_display_sata_capabilities(ioc, handle, sdev); - _scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT); + _scsih_change_queue_depth(sdev, qdepth); if (ssp_target) { sas_read_port_mode_page(sdev); diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 568dcaed36cb..de175b9915e2 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -1090,20 +1090,18 @@ _scsih_adjust_queue_depth(struct scsi_device *sdev, int qdepth) max_depth = 1; if (qdepth > max_depth) qdepth = max_depth; - scsi_adjust_queue_depth(sdev, qdepth); + scsi_change_queue_depth(sdev, qdepth); } /** * _scsih_change_queue_depth - setting device queue depth * @sdev: scsi device struct * @qdepth: requested queue depth - * @reason: SCSI_QDEPTH_DEFAULT - * (see include/scsi/scsi_host.h for definition) * * Returns queue depth. */ static int -_scsih_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason) +_scsih_change_queue_depth(struct scsi_device *sdev, int qdepth) { _scsih_adjust_queue_depth(sdev, qdepth); @@ -1734,7 +1732,7 @@ _scsih_slave_configure(struct scsi_device *sdev) raid_device->num_pds, ds); - _scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT); + _scsih_change_queue_depth(sdev, qdepth); /* raid transport support */ _scsih_set_level(sdev, raid_device->volume_type); @@ -1800,7 +1798,7 @@ _scsih_slave_configure(struct scsi_device *sdev) _scsih_display_sata_capabilities(ioc, handle, sdev); - _scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT); + _scsih_change_queue_depth(sdev, qdepth); if (ssp_target) { sas_read_port_mode_page(sdev); diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c index 9c331b7bfdcd..5b93ed810f6e 100644 --- a/drivers/scsi/ncr53c8xx.c +++ b/drivers/scsi/ncr53c8xx.c @@ -7997,7 +7997,7 @@ static int ncr53c8xx_slave_configure(struct scsi_device *device) if (depth_to_use > MAX_TAGS) depth_to_use = MAX_TAGS; - scsi_adjust_queue_depth(device, depth_to_use); + scsi_change_queue_depth(device, depth_to_use); /* ** Since the queue depth is not tunable under Linux, diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c index d8b9ba251fbd..b1b1f66b1ab7 100644 --- a/drivers/scsi/pmcraid.c +++ b/drivers/scsi/pmcraid.c @@ -285,23 +285,15 @@ static void pmcraid_slave_destroy(struct scsi_device *scsi_dev) * pmcraid_change_queue_depth - Change the device's queue depth * @scsi_dev: scsi device struct * @depth: depth to set - * @reason: calling context * * Return value * actual depth set */ -static int pmcraid_change_queue_depth(struct scsi_device *scsi_dev, int depth, - int reason) +static int pmcraid_change_queue_depth(struct scsi_device *scsi_dev, int depth) { - if (reason != SCSI_QDEPTH_DEFAULT) - return -EOPNOTSUPP; - if (depth > PMCRAID_MAX_CMD_PER_LUN) depth = PMCRAID_MAX_CMD_PER_LUN; - - scsi_adjust_queue_depth(scsi_dev, depth); - - return scsi_dev->queue_depth; + return scsi_change_queue_depth(scsi_dev, depth); } /** diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index adedb6ef8eec..c68a66e8cfc1 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -1224,9 +1224,9 @@ qla1280_slave_configure(struct scsi_device *device) if (device->tagged_supported && (ha->bus_settings[bus].qtag_enables & (BIT_0 << target))) { - scsi_adjust_queue_depth(device, ha->bus_settings[bus].hiwat); + scsi_change_queue_depth(device, ha->bus_settings[bus].hiwat); } else { - scsi_adjust_queue_depth(device, default_depth); + scsi_change_queue_depth(device, default_depth); } nv->bus[bus].target[target].parameter.enable_sync = device->sdtr; diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 20049b176b64..6b4d9235368a 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -236,7 +236,6 @@ static int qla2xxx_eh_target_reset(struct scsi_cmnd *); static int qla2xxx_eh_bus_reset(struct scsi_cmnd *); static int qla2xxx_eh_host_reset(struct scsi_cmnd *); -static int qla2x00_change_queue_depth(struct scsi_device *, int, int); static void qla2x00_clear_drv_active(struct qla_hw_data *); static void qla2x00_free_device(scsi_qla_host_t *); static void qla83xx_disable_laser(scsi_qla_host_t *vha); @@ -258,7 +257,7 @@ struct scsi_host_template qla2xxx_driver_template = { .slave_destroy = qla2xxx_slave_destroy, .scan_finished = qla2xxx_scan_finished, .scan_start = qla2xxx_scan_start, - .change_queue_depth = qla2x00_change_queue_depth, + .change_queue_depth = scsi_change_queue_depth, .change_queue_type = scsi_change_queue_type, .this_id = -1, .cmd_per_lun = 3, @@ -1406,7 +1405,7 @@ qla2xxx_slave_configure(struct scsi_device *sdev) if (IS_T10_PI_CAPABLE(vha->hw)) blk_queue_update_dma_alignment(sdev->request_queue, 0x7); - scsi_adjust_queue_depth(sdev, req->max_q_depth); + scsi_change_queue_depth(sdev, req->max_q_depth); return 0; } @@ -1416,13 +1415,6 @@ qla2xxx_slave_destroy(struct scsi_device *sdev) sdev->hostdata = NULL; } -static int -qla2x00_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason) -{ - scsi_adjust_queue_depth(sdev, qdepth); - return sdev->queue_depth; -} - /** * qla2x00_config_dma_addressing() - Configure OS DMA addressing method. * @ha: HA context diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 2bfde373ea2b..6d25879d87c8 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -201,7 +201,7 @@ static struct scsi_host_template qla4xxx_driver_template = { .eh_timed_out = qla4xxx_eh_cmd_timed_out, .slave_alloc = qla4xxx_slave_alloc, - .change_queue_depth = iscsi_change_queue_depth, + .change_queue_depth = scsi_change_queue_depth, .this_id = -1, .cmd_per_lun = 3, @@ -9059,7 +9059,7 @@ static int qla4xxx_slave_alloc(struct scsi_device *sdev) if (ql4xmaxqdepth != 0 && ql4xmaxqdepth <= 0xffffU) queue_depth = ql4xmaxqdepth; - scsi_adjust_queue_depth(sdev, queue_depth); + scsi_change_queue_depth(sdev, queue_depth); return 0; } diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 106fa2f886d2..5ea15fc7d2fb 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -742,30 +742,18 @@ void scsi_finish_command(struct scsi_cmnd *cmd) } /** - * scsi_adjust_queue_depth - Let low level drivers change a device's queue depth + * scsi_change_queue_depth - change a device's queue depth * @sdev: SCSI Device in question - * @tags: Number of tags allowed if tagged queueing enabled, - * or number of commands the low level driver can - * queue up in non-tagged mode (as per cmd_per_lun). + * @depth: number of commands allowed to be queued to the driver * - * Returns: Nothing - * - * Lock Status: None held on entry - * - * Notes: Low level drivers may call this at any time and we will do - * the right thing depending on whether or not the device is - * currently active and whether or not it even has the - * command blocks built yet. + * Sets the device queue depth and returns the new value. */ -void scsi_adjust_queue_depth(struct scsi_device *sdev, int tags) +int scsi_change_queue_depth(struct scsi_device *sdev, int depth) { unsigned long flags; - /* - * refuse to set tagged depth to an unworkable size - */ - if (tags <= 0) - return; + if (depth <= 0) + goto out; spin_lock_irqsave(sdev->request_queue->queue_lock, flags); @@ -780,15 +768,17 @@ void scsi_adjust_queue_depth(struct scsi_device *sdev, int tags) */ if (!shost_use_blk_mq(sdev->host) && !sdev->host->bqt) { if (blk_queue_tagged(sdev->request_queue) && - blk_queue_resize_tags(sdev->request_queue, tags) != 0) - goto out; + blk_queue_resize_tags(sdev->request_queue, depth) != 0) + goto out_unlock; } - sdev->queue_depth = tags; - out: + sdev->queue_depth = depth; +out_unlock: spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); +out: + return sdev->queue_depth; } -EXPORT_SYMBOL(scsi_adjust_queue_depth); +EXPORT_SYMBOL(scsi_change_queue_depth); /** * scsi_track_queue_full - track QUEUE_FULL events to adjust queue depth @@ -833,12 +823,11 @@ int scsi_track_queue_full(struct scsi_device *sdev, int depth) if (sdev->last_queue_full_depth < 8) { /* Drop back to untagged */ scsi_set_tag_type(sdev, 0); - scsi_adjust_queue_depth(sdev, sdev->host->cmd_per_lun); + scsi_change_queue_depth(sdev, sdev->host->cmd_per_lun); return -1; } - scsi_adjust_queue_depth(sdev, depth); - return depth; + return scsi_change_queue_depth(sdev, depth); } EXPORT_SYMBOL(scsi_track_queue_full); diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 84cf82e0782d..ce71b6d4393c 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -4469,7 +4469,7 @@ sdebug_queuecommand_lock_or_not(struct Scsi_Host *shost, struct scsi_cmnd *cmd) } static int -sdebug_change_qdepth(struct scsi_device *sdev, int qdepth, int reason) +sdebug_change_qdepth(struct scsi_device *sdev, int qdepth) { int num_in_q = 0; unsigned long iflags; @@ -4489,7 +4489,7 @@ sdebug_change_qdepth(struct scsi_device *sdev, int qdepth, int reason) /* allow to exceed max host queued_arr elements for testing */ if (qdepth > SCSI_DEBUG_CANQUEUE + 10) qdepth = SCSI_DEBUG_CANQUEUE + 10; - scsi_adjust_queue_depth(sdev, qdepth); + scsi_change_queue_depth(sdev, qdepth); if (SCSI_DEBUG_OPT_Q_NOISE & scsi_debug_opts) { sdev_printk(KERN_INFO, sdev, diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 2d0f5155ee51..1f63559184b9 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -632,7 +632,7 @@ static void scsi_handle_queue_ramp_up(struct scsi_device *sdev) tmp_sdev->queue_depth == sdev->max_queue_depth) continue; - scsi_adjust_queue_depth(tmp_sdev, tmp_sdev->queue_depth + 1); + scsi_change_queue_depth(tmp_sdev, tmp_sdev->queue_depth + 1); sdev->last_queue_ramp_up = jiffies; } } diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index d97597e6337e..0af713375db5 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -292,7 +292,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget, blk_queue_init_tags(sdev->request_queue, sdev->host->cmd_per_lun, shost->bqt); } - scsi_adjust_queue_depth(sdev, sdev->host->cmd_per_lun); + scsi_change_queue_depth(sdev, sdev->host->cmd_per_lun); scsi_sysfs_device_initialize(sdev); diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index bffd5abdcd1f..1cb64a8e18c9 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -880,8 +880,7 @@ sdev_store_queue_depth(struct device *dev, struct device_attribute *attr, if (depth < 1 || depth > sht->can_queue) return -EINVAL; - retval = sht->change_queue_depth(sdev, depth, - SCSI_QDEPTH_DEFAULT); + retval = sht->change_queue_depth(sdev, depth); if (retval < 0) return retval; diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index ff8befbdf17c..e3ba251fb6e7 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -1429,7 +1429,7 @@ static void storvsc_device_destroy(struct scsi_device *sdevice) static int storvsc_device_configure(struct scsi_device *sdevice) { - scsi_adjust_queue_depth(sdevice, STORVSC_MAX_IO_REQUESTS); + scsi_change_queue_depth(sdevice, STORVSC_MAX_IO_REQUESTS); blk_queue_max_segment_size(sdevice->request_queue, PAGE_SIZE); diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c index 3557b385251a..5d00e514ff28 100644 --- a/drivers/scsi/sym53c8xx_2/sym_glue.c +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c @@ -820,7 +820,7 @@ static int sym53c8xx_slave_configure(struct scsi_device *sdev) if (reqtags > SYM_CONF_MAX_TAG) reqtags = SYM_CONF_MAX_TAG; depth_to_use = reqtags ? reqtags : 1; - scsi_adjust_queue_depth(sdev, depth_to_use); + scsi_change_queue_depth(sdev, depth_to_use); lp->s.scdev_depth = depth_to_use; sym_tune_dev_queuing(tp, sdev->lun, reqtags); diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c index 844c9a048c00..6c3c2cef3891 100644 --- a/drivers/scsi/tmscsim.c +++ b/drivers/scsi/tmscsim.c @@ -2194,7 +2194,7 @@ static int dc390_slave_configure(struct scsi_device *sdev) if (sdev->tagged_supported && (dcb->DevMode & TAG_QUEUEING_)) { dcb->SyncMode |= EN_TAG_QUEUEING; - scsi_adjust_queue_depth(sdev, acb->TagMaxNum); + scsi_change_queue_depth(sdev, acb->TagMaxNum); } return 0; diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c index aa0f4035afaf..14eb50b95a1e 100644 --- a/drivers/scsi/u14-34f.c +++ b/drivers/scsi/u14-34f.c @@ -696,25 +696,25 @@ static int u14_34f_slave_configure(struct scsi_device *dev) { if (TLDEV(dev->type) && dev->tagged_supported) if (tag_mode == TAG_SIMPLE) { - scsi_adjust_queue_depth(dev, tqd); + scsi_change_queue_depth(dev, tqd); tag_suffix = ", simple tags"; } else if (tag_mode == TAG_ORDERED) { - scsi_adjust_queue_depth(dev, tqd); + scsi_change_queue_depth(dev, tqd); tag_suffix = ", ordered tags"; } else { - scsi_adjust_queue_depth(dev, tqd); + scsi_change_queue_depth(dev, tqd); tag_suffix = ", no tags"; } else if (TLDEV(dev->type) && linked_comm) { - scsi_adjust_queue_depth(dev, tqd); + scsi_change_queue_depth(dev, tqd); tag_suffix = ", untagged"; } else { - scsi_adjust_queue_depth(dev, utqd); + scsi_change_queue_depth(dev, utqd); tag_suffix = ""; } diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index e96ab253e3e5..0c4f98ee6047 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -2695,7 +2695,7 @@ static void ufshcd_set_queue_depth(struct scsi_device *sdev) dev_dbg(hba->dev, "%s: activate tcq with queue depth %d\n", __func__, lun_qdepth); - scsi_adjust_queue_depth(sdev, lun_qdepth); + scsi_change_queue_depth(sdev, lun_qdepth); } /* @@ -2787,21 +2787,16 @@ static int ufshcd_slave_alloc(struct scsi_device *sdev) * ufshcd_change_queue_depth - change queue depth * @sdev: pointer to SCSI device * @depth: required depth to set - * @reason: reason for changing the depth * - * Change queue depth according to the reason and make sure - * the max. limits are not crossed. + * Change queue depth and make sure the max. limits are not crossed. */ -static int ufshcd_change_queue_depth(struct scsi_device *sdev, - int depth, int reason) +static int ufshcd_change_queue_depth(struct scsi_device *sdev, int depth) { struct ufs_hba *hba = shost_priv(sdev->host); if (depth > hba->nutrs) depth = hba->nutrs; - - scsi_adjust_queue_depth(sdev, depth); - return depth; + return scsi_change_queue_depth(sdev, depth); } /** diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c index 0f7e4c7ff8c2..22e70126425b 100644 --- a/drivers/scsi/virtio_scsi.c +++ b/drivers/scsi/virtio_scsi.c @@ -682,17 +682,13 @@ static int virtscsi_device_reset(struct scsi_cmnd *sc) * virtscsi_change_queue_depth() - Change a virtscsi target's queue depth * @sdev: Virtscsi target whose queue depth to change * @qdepth: New queue depth - * @reason: Reason for the queue depth change. */ -static int virtscsi_change_queue_depth(struct scsi_device *sdev, - int qdepth, - int reason) +static int virtscsi_change_queue_depth(struct scsi_device *sdev, int qdepth) { struct Scsi_Host *shost = sdev->host; int max_depth = shost->cmd_per_lun; - scsi_adjust_queue_depth(sdev, min(max_depth, qdepth)); - return sdev->queue_depth; + return scsi_change_queue_depth(sdev, min(max_depth, qdepth)); } static int virtscsi_abort(struct scsi_cmnd *sc) diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c index 03ad24be728e..ade1f1d013b1 100644 --- a/drivers/scsi/vmw_pvscsi.c +++ b/drivers/scsi/vmw_pvscsi.c @@ -504,19 +504,11 @@ static void pvscsi_setup_all_rings(const struct pvscsi_adapter *adapter) } } -static int pvscsi_change_queue_depth(struct scsi_device *sdev, - int qdepth, - int reason) +static int pvscsi_change_queue_depth(struct scsi_device *sdev, int qdepth) { - if (reason != SCSI_QDEPTH_DEFAULT) - /* - * We support only changing default. - */ - return -EOPNOTSUPP; - if (!sdev->tagged_supported) qdepth = 1; - scsi_adjust_queue_depth(sdev, qdepth); + scsi_change_queue_depth(sdev, qdepth); if (sdev->inquiry_len > 7) sdev_printk(KERN_INFO, sdev, diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c index 32674236fec7..f94d73611ab4 100644 --- a/drivers/scsi/wd7000.c +++ b/drivers/scsi/wd7000.c @@ -1653,7 +1653,6 @@ static struct scsi_host_template driver_template = { .can_queue = WD7000_Q, .this_id = 7, .sg_tablesize = WD7000_SG, - .cmd_per_lun = 1, .unchecked_isa_dma = 1, .use_clustering = ENABLE_CLUSTERING, }; diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index 670b75a62243..4d1b7224a7f2 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -110,19 +110,6 @@ static struct device_driver tcm_loop_driverfs = { */ struct device *tcm_loop_primary; -/* - * Copied from drivers/scsi/libfc/fc_fcp.c:fc_change_queue_depth() and - * drivers/scsi/libiscsi.c:iscsi_change_queue_depth() - */ -static int tcm_loop_change_queue_depth( - struct scsi_device *sdev, - int depth, - int reason) -{ - scsi_adjust_queue_depth(sdev, depth); - return sdev->queue_depth; -} - static void tcm_loop_submission_work(struct work_struct *work) { struct tcm_loop_cmd *tl_cmd = @@ -397,7 +384,7 @@ static struct scsi_host_template tcm_loop_driver_template = { .proc_name = "tcm_loopback", .name = "TCM_Loopback", .queuecommand = tcm_loop_queuecommand, - .change_queue_depth = tcm_loop_change_queue_depth, + .change_queue_depth = scsi_change_queue_depth, .change_queue_type = scsi_change_queue_type, .eh_abort_handler = tcm_loop_abort_task, .eh_device_reset_handler = tcm_loop_device_reset, diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index 33f211b56a42..4047edfb64e1 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c @@ -799,7 +799,7 @@ static int uas_slave_configure(struct scsi_device *sdev) if (devinfo->flags & US_FL_NO_REPORT_OPCODES) sdev->no_report_opcodes = 1; - scsi_adjust_queue_depth(sdev, devinfo->qdepth - 2); + scsi_change_queue_depth(sdev, devinfo->qdepth - 2); return 0; } diff --git a/include/linux/libata.h b/include/linux/libata.h index bd5fefeaf548..bfbc817c34ee 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -1191,9 +1191,9 @@ extern void ata_scsi_unlock_native_capacity(struct scsi_device *sdev); extern int ata_scsi_slave_config(struct scsi_device *sdev); extern void ata_scsi_slave_destroy(struct scsi_device *sdev); extern int ata_scsi_change_queue_depth(struct scsi_device *sdev, - int queue_depth, int reason); + int queue_depth); extern int __ata_change_queue_depth(struct ata_port *ap, struct scsi_device *sdev, - int queue_depth, int reason); + int queue_depth); extern struct ata_device *ata_dev_pair(struct ata_device *adev); extern int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev); extern void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap); diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index 2e0cf568a9c1..93d14daf0994 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -1105,7 +1105,6 @@ int fc_eh_abort(struct scsi_cmnd *); int fc_eh_device_reset(struct scsi_cmnd *); int fc_eh_host_reset(struct scsi_cmnd *); int fc_slave_alloc(struct scsi_device *); -int fc_change_queue_depth(struct scsi_device *, int qdepth, int reason); /* * ELS/CT interface diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h index 728c9ad9feb0..4d1c46aac331 100644 --- a/include/scsi/libiscsi.h +++ b/include/scsi/libiscsi.h @@ -378,8 +378,6 @@ struct iscsi_host { /* * scsi host template */ -extern int iscsi_change_queue_depth(struct scsi_device *sdev, int depth, - int reason); extern int iscsi_eh_abort(struct scsi_cmnd *sc); extern int iscsi_eh_recover_target(struct scsi_cmnd *sc); extern int iscsi_eh_session_reset(struct scsi_cmnd *sc); diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index ef7872c20da9..1f8b33ec612f 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h @@ -704,8 +704,7 @@ int sas_queue_up(struct sas_task *task); extern int sas_queuecommand(struct Scsi_Host * ,struct scsi_cmnd *); extern int sas_target_alloc(struct scsi_target *); extern int sas_slave_configure(struct scsi_device *); -extern int sas_change_queue_depth(struct scsi_device *, int new_depth, - int reason); +extern int sas_change_queue_depth(struct scsi_device *, int new_depth); extern int sas_change_queue_type(struct scsi_device *, int qt); extern int sas_bios_param(struct scsi_device *, struct block_device *, diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 0aeaa003c3c1..6364e23454dd 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -380,7 +380,7 @@ extern struct scsi_device *__scsi_iterate_devices(struct Scsi_Host *, #define __shost_for_each_device(sdev, shost) \ list_for_each_entry((sdev), &((shost)->__devices), siblings) -extern void scsi_adjust_queue_depth(struct scsi_device *, int); +extern int scsi_change_queue_depth(struct scsi_device *, int); extern int scsi_track_queue_full(struct scsi_device *, int); extern int scsi_set_medium_removal(struct scsi_device *, char); diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index a0b13a5cd25e..c8a462ef9a4e 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -46,10 +46,6 @@ struct blk_queue_tags; #define DISABLE_CLUSTERING 0 #define ENABLE_CLUSTERING 1 -enum { - SCSI_QDEPTH_DEFAULT, /* default requested change, e.g. from sysfs */ -}; - struct scsi_host_template { struct module *module; const char *name; @@ -193,7 +189,7 @@ struct scsi_host_template { * Things currently recommended to be handled at this time include: * * 1. Setting the device queue depth. Proper setting of this is - * described in the comments for scsi_adjust_queue_depth. + * described in the comments for scsi_change_queue_depth. * 2. Determining if the device supports the various synchronous * negotiation protocols. The device struct will already have * responded to INQUIRY and the results of the standard items @@ -279,7 +275,7 @@ struct scsi_host_template { * * Status: OPTIONAL */ - int (* change_queue_depth)(struct scsi_device *, int, int); + int (* change_queue_depth)(struct scsi_device *, int); /* * Fill in this function to allow the changing of tag types -- cgit v1.2.3-59-g8ed1b From 690b0543a813b0ecfc51b0374c0ce6c8275435f0 Mon Sep 17 00:00:00 2001 From: Maisa Roponen Date: Mon, 24 Nov 2014 09:54:17 +0200 Subject: Documentation: fix formatting to make 's' happy "That letter [the last s] is sad because all the others have those things [=] below them and it does not." This patch fixes the tragedy so all the letters can be happy again. Signed-off-by: Maisa Roponen [The author being 4 years old needed some assistance] Signed-off-by: Tero Roponen Signed-off-by: Jonathan Corbet --- Documentation/filesystems/proc.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt index eb8a10e22f7c..aae9dd13c91f 100644 --- a/Documentation/filesystems/proc.txt +++ b/Documentation/filesystems/proc.txt @@ -1272,7 +1272,7 @@ softirq. 1.9 Ext4 file system parameters ------------------------------- +------------------------------- Information about mounted ext4 file systems can be found in /proc/fs/ext4. Each mounted filesystem will have a directory in -- cgit v1.2.3-59-g8ed1b From 3c415707b37f1e4483c418c77f57692b89bcfd5e Mon Sep 17 00:00:00 2001 From: Tim Bird Date: Wed, 19 Nov 2014 16:16:16 -0800 Subject: kselftest: Move the docs to the Documentation dir Also, adjust the formatting a bit, and expand the section about using TARGETS= on the make command line. Signed-off-by: Tim Bird Acked-by: Shuah Khan Signed-off-by: Jonathan Corbet --- Documentation/kselftest.txt | 69 ++++++++++++++++++++++++++++++++++++++ tools/testing/selftests/README.txt | 61 --------------------------------- 2 files changed, 69 insertions(+), 61 deletions(-) create mode 100644 Documentation/kselftest.txt delete mode 100644 tools/testing/selftests/README.txt (limited to 'Documentation') diff --git a/Documentation/kselftest.txt b/Documentation/kselftest.txt new file mode 100644 index 000000000000..a87d840bacfe --- /dev/null +++ b/Documentation/kselftest.txt @@ -0,0 +1,69 @@ +Linux Kernel Selftests + +The kernel contains a set of "self tests" under the tools/testing/selftests/ +directory. These are intended to be small unit tests to exercise individual +code paths in the kernel. + +On some systems, hot-plug tests could hang forever waiting for cpu and +memory to be ready to be offlined. A special hot-plug target is created +to run full range of hot-plug tests. In default mode, hot-plug tests run +in safe mode with a limited scope. In limited mode, cpu-hotplug test is +run on a single cpu as opposed to all hotplug capable cpus, and memory +hotplug test is run on 2% of hotplug capable memory instead of 10%. + +Running the selftests (hotplug tests are run in limited mode) +============================================================= + +To build the tests: + $ make -C tools/testing/selftests + + +To run the tests: + $ make -C tools/testing/selftests run_tests + +To build and run the tests with a single command, use: + $ make kselftest + +- note that some tests will require root privileges. + + +Running a subset of selftests +======================================== +You can use the "TARGETS" variable on the make command line to specify +single test to run, or a list of tests to run. + +To run only tests targeted for a single subsystem: + $ make -C tools/testing/selftests TARGETS=ptrace run_tests + +You can specify multiple tests to build and run: + $ make TARGETS="size timers" kselftest + +See the top-level tools/testing/selftests/Makefile for the list of all +possible targets. + + +Running the full range hotplug selftests +======================================== + +To build the hotplug tests: + $ make -C tools/testing/selftests hotplug + +To run the hotplug tests: + $ make -C tools/testing/selftests run_hotplug + +- note that some tests will require root privileges. + + +Contributing new tests +====================== + +In general, the rules for for selftests are + + * Do as much as you can if you're not root; + + * Don't take too long; + + * Don't break the build on any architecture, and + + * Don't cause the top-level "make run_tests" to fail if your feature is + unconfigured. diff --git a/tools/testing/selftests/README.txt b/tools/testing/selftests/README.txt deleted file mode 100644 index 2660d5ff9179..000000000000 --- a/tools/testing/selftests/README.txt +++ /dev/null @@ -1,61 +0,0 @@ -Linux Kernel Selftests - -The kernel contains a set of "self tests" under the tools/testing/selftests/ -directory. These are intended to be small unit tests to exercise individual -code paths in the kernel. - -On some systems, hot-plug tests could hang forever waiting for cpu and -memory to be ready to be offlined. A special hot-plug target is created -to run full range of hot-plug tests. In default mode, hot-plug tests run -in safe mode with a limited scope. In limited mode, cpu-hotplug test is -run on a single cpu as opposed to all hotplug capable cpus, and memory -hotplug test is run on 2% of hotplug capable memory instead of 10%. - -Running the selftests (hotplug tests are run in limited mode) -============================================================= - -To build the tests: - - $ make -C tools/testing/selftests - - -To run the tests: - - $ make -C tools/testing/selftests run_tests - -- note that some tests will require root privileges. - -To run only tests targeted for a single subsystem: (including -hotplug targets in limited mode) - - $ make -C tools/testing/selftests TARGETS=cpu-hotplug run_tests - -See the top-level tools/testing/selftests/Makefile for the list of all possible -targets. - -Running the full range hotplug selftests -======================================== - -To build the tests: - - $ make -C tools/testing/selftests hotplug - -To run the tests: - - $ make -C tools/testing/selftests run_hotplug - -- note that some tests will require root privileges. - -Contributing new tests -====================== - -In general, the rules for for selftests are - - * Do as much as you can if you're not root; - - * Don't take too long; - - * Don't break the build on any architecture, and - - * Don't cause the top-level "make run_tests" to fail if your feature is - unconfigured. -- cgit v1.2.3-59-g8ed1b From 6962ad52a5971dc2c91b3afe7b8124c4a197bef0 Mon Sep 17 00:00:00 2001 From: Caesar Wang Date: Mon, 24 Nov 2014 12:58:58 +0800 Subject: dt-bindings: document Rockchip thermal This add the necessary binding documentation for the thermal found on Rockchip SoCs Signed-off-by: zhaoyifeng Signed-off-by: Caesar Wang Reviewed-by: Dmitry Torokhov Signed-off-by: Eduardo Valentin --- .../bindings/thermal/rockchip-thermal.txt | 68 ++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 Documentation/devicetree/bindings/thermal/rockchip-thermal.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt new file mode 100644 index 000000000000..ef802de4957a --- /dev/null +++ b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt @@ -0,0 +1,68 @@ +* Temperature Sensor ADC (TSADC) on rockchip SoCs + +Required properties: +- compatible : "rockchip,rk3288-tsadc" +- reg : physical base address of the controller and length of memory mapped + region. +- interrupts : The interrupt number to the cpu. The interrupt specifier format + depends on the interrupt controller. +- clocks : Must contain an entry for each entry in clock-names. +- clock-names : Shall be "tsadc" for the converter-clock, and "apb_pclk" for + the peripheral clock. +- resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names : Must include the name "tsadc-apb". +- #thermal-sensor-cells : Should be 1. See ./thermal.txt for a description. +- rockchip,hw-tshut-temp : The hardware-controlled shutdown temperature value. +- rockchip,hw-tshut-mode : The hardware-controlled shutdown mode 0:CRU 1:GPIO. +- rockchip,hw-tshut-polarity : The hardware-controlled active polarity 0:LOW + 1:HIGH. + +Exiample: +tsadc: tsadc@ff280000 { + compatible = "rockchip,rk3288-tsadc"; + reg = <0xff280000 0x100>; + interrupts = ; + clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>; + clock-names = "tsadc", "apb_pclk"; + resets = <&cru SRST_TSADC>; + reset-names = "tsadc-apb"; + pinctrl-names = "default"; + pinctrl-0 = <&otp_out>; + #thermal-sensor-cells = <1>; + rockchip,hw-tshut-temp = <95000>; + rockchip,hw-tshut-mode = <0>; + rockchip,hw-tshut-polarity = <0>; +}; + +Example: referring to thermal sensors: +thermal-zones { + cpu_thermal: cpu_thermal { + polling-delay-passive = <1000>; /* milliseconds */ + polling-delay = <5000>; /* milliseconds */ + + /* sensor ID */ + thermal-sensors = <&tsadc 1>; + + trips { + cpu_alert0: cpu_alert { + temperature = <70000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "passive"; + }; + cpu_crit: cpu_crit { + temperature = <90000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&cpu_alert0>; + cooling-device = + <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + }; +}; -- cgit v1.2.3-59-g8ed1b From 56da2aafe0a6db710c38a2fbf6aa9352a7b9fa4d Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Sat, 22 Nov 2014 16:21:40 +0100 Subject: spi: meson: Add device tree bindings documentation for SPIFC This adds documentation of device tree bindings for the Amlogic Meson SPIFC (SPI Flash Controller). Signed-off-by: Beniamino Galvani Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/spi-meson.txt | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 Documentation/devicetree/bindings/spi/spi-meson.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/spi/spi-meson.txt b/Documentation/devicetree/bindings/spi/spi-meson.txt new file mode 100644 index 000000000000..bb52a86f3365 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi-meson.txt @@ -0,0 +1,22 @@ +Amlogic Meson SPI controllers + +* SPIFC (SPI Flash Controller) + +The Meson SPIFC is a controller optimized for communication with SPI +NOR memories, without DMA support and a 64-byte unified transmit / +receive buffer. + +Required properties: + - compatible: should be "amlogic,meson6-spifc" + - reg: physical base address and length of the controller registers + - clocks: phandle of the input clock for the baud rate generator + - #address-cells: should be 1 + - #size-cells: should be 0 + + spi@c1108c80 { + compatible = "amlogic,meson6-spifc"; + reg = <0xc1108c80 0x80>; + clocks = <&clk81>; + #address-cells = <1>; + #size-cells = <0>; + }; -- cgit v1.2.3-59-g8ed1b From bbac3297c6712f061853e3e11d5e21aa4164968f Mon Sep 17 00:00:00 2001 From: Frank Rowand Date: Fri, 14 Nov 2014 14:07:15 -0800 Subject: tty: serial: msm_serial: document DT alias Update devicetree binding for msm_serial to reflect msm_serial_probe() getting line id (port number) from the serialN alias. Signed-off-by: Frank Rowand Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/serial/qcom,msm-uartdm.txt | 69 +++++++++++++++------- 1 file changed, 47 insertions(+), 22 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/serial/qcom,msm-uartdm.txt b/Documentation/devicetree/bindings/serial/qcom,msm-uartdm.txt index ffa5b784c66e..a2114c217376 100644 --- a/Documentation/devicetree/bindings/serial/qcom,msm-uartdm.txt +++ b/Documentation/devicetree/bindings/serial/qcom,msm-uartdm.txt @@ -27,27 +27,52 @@ Optional properties: - dmas: Should contain dma specifiers for transmit and receive channels - dma-names: Should contain "tx" for transmit and "rx" for receive channels +Note: Aliases may be defined to ensure the correct ordering of the UARTs. +The alias serialN will result in the UART being assigned port N. If any +serialN alias exists, then an alias must exist for each enabled UART. The +serialN aliases should be in a .dts file instead of in a .dtsi file. + Examples: -A uartdm v1.4 device with dma capabilities. - -serial@f991e000 { - compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm"; - reg = <0xf991e000 0x1000>; - interrupts = <0 108 0x0>; - clocks = <&blsp1_uart2_apps_cxc>, <&blsp1_ahb_cxc>; - clock-names = "core", "iface"; - dmas = <&dma0 0>, <&dma0 1>; - dma-names = "tx", "rx"; -}; - -A uartdm v1.3 device without dma capabilities and part of a GSBI complex. - -serial@19c40000 { - compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm"; - reg = <0x19c40000 0x1000>, - <0x19c00000 0x1000>; - interrupts = <0 195 0x0>; - clocks = <&gsbi5_uart_cxc>, <&gsbi5_ahb_cxc>; - clock-names = "core", "iface"; -}; +- A uartdm v1.4 device with dma capabilities. + + serial@f991e000 { + compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm"; + reg = <0xf991e000 0x1000>; + interrupts = <0 108 0x0>; + clocks = <&blsp1_uart2_apps_cxc>, <&blsp1_ahb_cxc>; + clock-names = "core", "iface"; + dmas = <&dma0 0>, <&dma0 1>; + dma-names = "tx", "rx"; + }; + +- A uartdm v1.3 device without dma capabilities and part of a GSBI complex. + + serial@19c40000 { + compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm"; + reg = <0x19c40000 0x1000>, + <0x19c00000 0x1000>; + interrupts = <0 195 0x0>; + clocks = <&gsbi5_uart_cxc>, <&gsbi5_ahb_cxc>; + clock-names = "core", "iface"; + }; + +- serialN alias. + + aliases { + serial0 = &uarta; + serial1 = &uartc; + serial2 = &uartb; + }; + + uarta: serial@12490000 { + status = "ok"; + }; + + uartb: serial@16340000 { + status = "ok"; + }; + + uartc: serial@1a240000 { + status = "ok"; + }; -- cgit v1.2.3-59-g8ed1b From 2ad7bf3638411cb547f2823df08166c13ab04269 Mon Sep 17 00:00:00 2001 From: Mahesh Bandewar Date: Sun, 23 Nov 2014 23:07:46 -0800 Subject: ipvlan: Initial check-in of the IPVLAN driver. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This driver is very similar to the macvlan driver except that it uses L3 on the frame to determine the logical interface while functioning as packet dispatcher. It inherits L2 of the master device hence the packets on wire will have the same L2 for all the packets originating from all virtual devices off of the same master device. This driver was developed keeping the namespace use-case in mind. Hence most of the examples given here take that as the base setup where main-device belongs to the default-ns and virtual devices are assigned to the additional namespaces. The device operates in two different modes and the difference in these two modes in primarily in the TX side. (a) L2 mode : In this mode, the device behaves as a L2 device. TX processing upto L2 happens on the stack of the virtual device associated with (namespace). Packets are switched after that into the main device (default-ns) and queued for xmit. RX processing is simple and all multicast, broadcast (if applicable), and unicast belonging to the address(es) are delivered to the virtual devices. (b) L3 mode : In this mode, the device behaves like a L3 device. TX processing upto L3 happens on the stack of the virtual device associated with (namespace). Packets are switched to the main-device (default-ns) for the L2 processing. Hence the routing table of the default-ns will be used in this mode. RX processins is somewhat similar to the L2 mode except that in this mode only Unicast packets are delivered to the virtual device while main-dev will handle all other packets. The devices can be added using the "ip" command from the iproute2 package - ip link add link type ipvlan mode [ l2 | l3 ] Signed-off-by: Mahesh Bandewar Cc: Eric Dumazet Cc: Maciej Żenczykowski Cc: Laurent Chavey Cc: Tim Hockin Cc: Brandon Philips Cc: Pavel Emelianov Signed-off-by: David S. Miller --- Documentation/networking/ipvlan.txt | 107 +++++ drivers/net/Kconfig | 18 + drivers/net/Makefile | 1 + drivers/net/ipvlan/Makefile | 7 + drivers/net/ipvlan/ipvlan.h | 130 ++++++ drivers/net/ipvlan/ipvlan_core.c | 607 +++++++++++++++++++++++++++ drivers/net/ipvlan/ipvlan_main.c | 789 ++++++++++++++++++++++++++++++++++++ include/linux/netdevice.h | 4 + include/uapi/linux/if_link.h | 15 + 9 files changed, 1678 insertions(+) create mode 100644 Documentation/networking/ipvlan.txt create mode 100644 drivers/net/ipvlan/Makefile create mode 100644 drivers/net/ipvlan/ipvlan.h create mode 100644 drivers/net/ipvlan/ipvlan_core.c create mode 100644 drivers/net/ipvlan/ipvlan_main.c (limited to 'Documentation') diff --git a/Documentation/networking/ipvlan.txt b/Documentation/networking/ipvlan.txt new file mode 100644 index 000000000000..cf996394e466 --- /dev/null +++ b/Documentation/networking/ipvlan.txt @@ -0,0 +1,107 @@ + + IPVLAN Driver HOWTO + +Initial Release: + Mahesh Bandewar + +1. Introduction: + This is conceptually very similar to the macvlan driver with one major +exception of using L3 for mux-ing /demux-ing among slaves. This property makes +the master device share the L2 with it's slave devices. I have developed this +driver in conjuntion with network namespaces and not sure if there is use case +outside of it. + + +2. Building and Installation: + In order to build the driver, please select the config item CONFIG_IPVLAN. +The driver can be built into the kernel (CONFIG_IPVLAN=y) or as a module +(CONFIG_IPVLAN=m). + + +3. Configuration: + There are no module parameters for this driver and it can be configured +using IProute2/ip utility. + + ip link add link type ipvlan mode { l2 | L3 } + + e.g. ip link add link ipvl0 eth0 type ipvlan mode l2 + + +4. Operating modes: + IPvlan has two modes of operation - L2 and L3. For a given master device, +you can select one of these two modes and all slaves on that master will +operate in the same (selected) mode. The RX mode is almost identical except +that in L3 mode the slaves wont receive any multicast / broadcast traffic. +L3 mode is more restrictive since routing is controlled from the other (mostly) +default namespace. + +4.1 L2 mode: + In this mode TX processing happens on the stack instance attached to the +slave device and packets are switched and queued to the master device to send +out. In this mode the slaves will RX/TX multicast and broadcast (if applicable) +as well. + +4.2 L3 mode: + In this mode TX processing upto L3 happens on the stack instance attached +to the slave device and packets are switched to the stack instance of the +master device for the L2 processing and routing from that instance will be +used before packets are queued on the outbound device. In this mode the slaves +will not receive nor can send multicast / broadcast traffic. + + +5. What to choose (macvlan vs. ipvlan)? + These two devices are very similar in many regards and the specific use +case could very well define which device to choose. if one of the following +situations defines your use case then you can choose to use ipvlan - + (a) The Linux host that is connected to the external switch / router has +policy configured that allows only one mac per port. + (b) No of virtual devices created on a master exceed the mac capacity and +puts the NIC in promiscous mode and degraded performance is a concern. + (c) If the slave device is to be put into the hostile / untrusted network +namespace where L2 on the slave could be changed / misused. + + +6. Example configuration: + + +=============================================================+ + | Host: host1 | + | | + | +----------------------+ +----------------------+ | + | | NS:ns0 | | NS:ns1 | | + | | | | | | + | | | | | | + | | ipvl0 | | ipvl1 | | + | +----------#-----------+ +-----------#----------+ | + | # # | + | ################################ | + | # eth0 | + +==============================#==============================+ + + + (a) Create two network namespaces - ns0, ns1 + ip netns add ns0 + ip netns add ns1 + + (b) Create two ipvlan slaves on eth0 (master device) + ip link add link eth0 ipvl0 type ipvlan mode l2 + ip link add link eth0 ipvl1 type ipvlan mode l2 + + (c) Assign slaves to the respective network namespaces + ip link set dev ipvl0 netns ns0 + ip link set dev ipvl1 netns ns1 + + (d) Now switch to the namespace (ns0 or ns1) to configure the slave devices + - For ns0 + (1) ip netns exec ns0 bash + (2) ip link set dev ipvl0 up + (3) ip link set dev lo up + (4) ip -4 addr add 127.0.0.1 dev lo + (5) ip -4 addr add $IPADDR dev ipvl0 + (6) ip -4 route add default via $ROUTER dev ipvl0 + - For ns1 + (1) ip netns exec ns1 bash + (2) ip link set dev ipvl1 up + (3) ip link set dev lo up + (4) ip -4 addr add 127.0.0.1 dev lo + (5) ip -4 addr add $IPADDR dev ipvl1 + (6) ip -4 route add default via $ROUTER dev ipvl1 diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index f9009be3f307..b6d64f546574 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -145,6 +145,24 @@ config MACVTAP To compile this driver as a module, choose M here: the module will be called macvtap. + +config IPVLAN + tristate "IP-VLAN support" + ---help--- + This allows one to create virtual devices off of a main interface + and packets will be delivered based on the dest L3 (IPv6/IPv4 addr) + on packets. All interfaces (including the main interface) share L2 + making it transparent to the connected L2 switch. + + Ipvlan devices can be added using the "ip" command from the + iproute2 package starting with the iproute2-X.Y.ZZ release: + + "ip link add link [ NAME ] type ipvlan" + + To compile this driver as a module, choose M here: the module + will be called ipvlan. + + config VXLAN tristate "Virtual eXtensible Local Area Network (VXLAN)" depends on INET diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 61aefdd1e173..e25fdd7d905e 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -6,6 +6,7 @@ # Networking Core Drivers # obj-$(CONFIG_BONDING) += bonding/ +obj-$(CONFIG_IPVLAN) += ipvlan/ obj-$(CONFIG_DUMMY) += dummy.o obj-$(CONFIG_EQUALIZER) += eql.o obj-$(CONFIG_IFB) += ifb.o diff --git a/drivers/net/ipvlan/Makefile b/drivers/net/ipvlan/Makefile new file mode 100644 index 000000000000..df79910192d6 --- /dev/null +++ b/drivers/net/ipvlan/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for the Ethernet Ipvlan driver +# + +obj-$(CONFIG_IPVLAN) += ipvlan.o + +ipvlan-objs := ipvlan_core.o ipvlan_main.o diff --git a/drivers/net/ipvlan/ipvlan.h b/drivers/net/ipvlan/ipvlan.h new file mode 100644 index 000000000000..ab3e7614ed71 --- /dev/null +++ b/drivers/net/ipvlan/ipvlan.h @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2014 Mahesh Bandewar + * + * 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. + * + */ +#ifndef __IPVLAN_H +#define __IPVLAN_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IPVLAN_DRV "ipvlan" +#define IPV_DRV_VER "0.1" + +#define IPVLAN_HASH_SIZE (1 << BITS_PER_BYTE) +#define IPVLAN_HASH_MASK (IPVLAN_HASH_SIZE - 1) + +#define IPVLAN_MAC_FILTER_BITS 8 +#define IPVLAN_MAC_FILTER_SIZE (1 << IPVLAN_MAC_FILTER_BITS) +#define IPVLAN_MAC_FILTER_MASK (IPVLAN_MAC_FILTER_SIZE - 1) + +typedef enum { + IPVL_IPV6 = 0, + IPVL_ICMPV6, + IPVL_IPV4, + IPVL_ARP, +} ipvl_hdr_type; + +struct ipvl_pcpu_stats { + u64 rx_pkts; + u64 rx_bytes; + u64 rx_mcast; + u64 tx_pkts; + u64 tx_bytes; + struct u64_stats_sync syncp; + u32 rx_errs; + u32 tx_drps; +}; + +struct ipvl_port; + +struct ipvl_dev { + struct net_device *dev; + struct list_head pnode; + struct ipvl_port *port; + struct net_device *phy_dev; + struct list_head addrs; + int ipv4cnt; + int ipv6cnt; + struct ipvl_pcpu_stats *pcpu_stats; + DECLARE_BITMAP(mac_filters, IPVLAN_MAC_FILTER_SIZE); + netdev_features_t sfeatures; + u32 msg_enable; + u16 mtu_adj; +}; + +struct ipvl_addr { + struct ipvl_dev *master; /* Back pointer to master */ + union { + struct in6_addr ip6; /* IPv6 address on logical interface */ + struct in_addr ip4; /* IPv4 address on logical interface */ + } ipu; +#define ip6addr ipu.ip6 +#define ip4addr ipu.ip4 + struct hlist_node hlnode; /* Hash-table linkage */ + struct list_head anode; /* logical-interface linkage */ + struct rcu_head rcu; + ipvl_hdr_type atype; +}; + +struct ipvl_port { + struct net_device *dev; + struct hlist_head hlhead[IPVLAN_HASH_SIZE]; + struct list_head ipvlans; + struct rcu_head rcu; + int count; + u16 mode; +}; + +static inline struct ipvl_port *ipvlan_port_get_rcu(const struct net_device *d) +{ + return rcu_dereference(d->rx_handler_data); +} + +static inline struct ipvl_port *ipvlan_port_get_rtnl(const struct net_device *d) +{ + return rtnl_dereference(d->rx_handler_data); +} + +static inline bool ipvlan_dev_master(struct net_device *d) +{ + return d->priv_flags & IFF_IPVLAN_MASTER; +} + +static inline bool ipvlan_dev_slave(struct net_device *d) +{ + return d->priv_flags & IFF_IPVLAN_SLAVE; +} + +void ipvlan_adjust_mtu(struct ipvl_dev *ipvlan, struct net_device *dev); +void ipvlan_set_port_mode(struct ipvl_port *port, u32 nval); +void ipvlan_init_secret(void); +unsigned int ipvlan_mac_hash(const unsigned char *addr); +rx_handler_result_t ipvlan_handle_frame(struct sk_buff **pskb); +int ipvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev); +void ipvlan_ht_addr_add(struct ipvl_dev *ipvlan, struct ipvl_addr *addr); +bool ipvlan_addr_busy(struct ipvl_dev *ipvlan, void *iaddr, bool is_v6); +struct ipvl_addr *ipvlan_ht_addr_lookup(const struct ipvl_port *port, + const void *iaddr, bool is_v6); +void ipvlan_ht_addr_del(struct ipvl_addr *addr, bool sync); +#endif /* __IPVLAN_H */ diff --git a/drivers/net/ipvlan/ipvlan_core.c b/drivers/net/ipvlan/ipvlan_core.c new file mode 100644 index 000000000000..a14d87783245 --- /dev/null +++ b/drivers/net/ipvlan/ipvlan_core.c @@ -0,0 +1,607 @@ +/* Copyright (c) 2014 Mahesh Bandewar + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + */ + +#include "ipvlan.h" + +static u32 ipvlan_jhash_secret; + +void ipvlan_init_secret(void) +{ + net_get_random_once(&ipvlan_jhash_secret, sizeof(ipvlan_jhash_secret)); +} + +static void ipvlan_count_rx(const struct ipvl_dev *ipvlan, + unsigned int len, bool success, bool mcast) +{ + if (!ipvlan) + return; + + if (likely(success)) { + struct ipvl_pcpu_stats *pcptr; + + pcptr = this_cpu_ptr(ipvlan->pcpu_stats); + u64_stats_update_begin(&pcptr->syncp); + pcptr->rx_pkts++; + pcptr->rx_bytes += len; + if (mcast) + pcptr->rx_mcast++; + u64_stats_update_end(&pcptr->syncp); + } else { + this_cpu_inc(ipvlan->pcpu_stats->rx_errs); + } +} + +static u8 ipvlan_get_v6_hash(const void *iaddr) +{ + const struct in6_addr *ip6_addr = iaddr; + + return __ipv6_addr_jhash(ip6_addr, ipvlan_jhash_secret) & + IPVLAN_HASH_MASK; +} + +static u8 ipvlan_get_v4_hash(const void *iaddr) +{ + const struct in_addr *ip4_addr = iaddr; + + return jhash_1word(ip4_addr->s_addr, ipvlan_jhash_secret) & + IPVLAN_HASH_MASK; +} + +struct ipvl_addr *ipvlan_ht_addr_lookup(const struct ipvl_port *port, + const void *iaddr, bool is_v6) +{ + struct ipvl_addr *addr; + u8 hash; + + hash = is_v6 ? ipvlan_get_v6_hash(iaddr) : + ipvlan_get_v4_hash(iaddr); + hlist_for_each_entry_rcu(addr, &port->hlhead[hash], hlnode) { + if (is_v6 && addr->atype == IPVL_IPV6 && + ipv6_addr_equal(&addr->ip6addr, iaddr)) + return addr; + else if (!is_v6 && addr->atype == IPVL_IPV4 && + addr->ip4addr.s_addr == + ((struct in_addr *)iaddr)->s_addr) + return addr; + } + return NULL; +} + +void ipvlan_ht_addr_add(struct ipvl_dev *ipvlan, struct ipvl_addr *addr) +{ + struct ipvl_port *port = ipvlan->port; + u8 hash; + + hash = (addr->atype == IPVL_IPV6) ? + ipvlan_get_v6_hash(&addr->ip6addr) : + ipvlan_get_v4_hash(&addr->ip4addr); + hlist_add_head_rcu(&addr->hlnode, &port->hlhead[hash]); +} + +void ipvlan_ht_addr_del(struct ipvl_addr *addr, bool sync) +{ + hlist_del_rcu(&addr->hlnode); + if (sync) + synchronize_rcu(); +} + +bool ipvlan_addr_busy(struct ipvl_dev *ipvlan, void *iaddr, bool is_v6) +{ + struct ipvl_port *port = ipvlan->port; + struct ipvl_addr *addr; + + list_for_each_entry(addr, &ipvlan->addrs, anode) { + if ((is_v6 && addr->atype == IPVL_IPV6 && + ipv6_addr_equal(&addr->ip6addr, iaddr)) || + (!is_v6 && addr->atype == IPVL_IPV4 && + addr->ip4addr.s_addr == ((struct in_addr *)iaddr)->s_addr)) + return true; + } + + if (ipvlan_ht_addr_lookup(port, iaddr, is_v6)) + return true; + + return false; +} + +static void *ipvlan_get_L3_hdr(struct sk_buff *skb, int *type) +{ + void *lyr3h = NULL; + + switch (skb->protocol) { + case htons(ETH_P_ARP): { + struct arphdr *arph; + + if (unlikely(!pskb_may_pull(skb, sizeof(*arph)))) + return NULL; + + arph = arp_hdr(skb); + *type = IPVL_ARP; + lyr3h = arph; + break; + } + case htons(ETH_P_IP): { + u32 pktlen; + struct iphdr *ip4h; + + if (unlikely(!pskb_may_pull(skb, sizeof(*ip4h)))) + return NULL; + + ip4h = ip_hdr(skb); + pktlen = ntohs(ip4h->tot_len); + if (ip4h->ihl < 5 || ip4h->version != 4) + return NULL; + if (skb->len < pktlen || pktlen < (ip4h->ihl * 4)) + return NULL; + + *type = IPVL_IPV4; + lyr3h = ip4h; + break; + } + case htons(ETH_P_IPV6): { + struct ipv6hdr *ip6h; + + if (unlikely(!pskb_may_pull(skb, sizeof(*ip6h)))) + return NULL; + + ip6h = ipv6_hdr(skb); + if (ip6h->version != 6) + return NULL; + + *type = IPVL_IPV6; + lyr3h = ip6h; + /* Only Neighbour Solicitation pkts need different treatment */ + if (ipv6_addr_any(&ip6h->saddr) && + ip6h->nexthdr == NEXTHDR_ICMP) { + *type = IPVL_ICMPV6; + lyr3h = ip6h + 1; + } + break; + } + default: + return NULL; + } + + return lyr3h; +} + +unsigned int ipvlan_mac_hash(const unsigned char *addr) +{ + u32 hash = jhash_1word(__get_unaligned_cpu32(addr+2), + ipvlan_jhash_secret); + + return hash & IPVLAN_MAC_FILTER_MASK; +} + +static void ipvlan_multicast_frame(struct ipvl_port *port, struct sk_buff *skb, + const struct ipvl_dev *in_dev, bool local) +{ + struct ethhdr *eth = eth_hdr(skb); + struct ipvl_dev *ipvlan; + struct sk_buff *nskb; + unsigned int len; + unsigned int mac_hash; + int ret; + + if (skb->protocol == htons(ETH_P_PAUSE)) + return; + + list_for_each_entry(ipvlan, &port->ipvlans, pnode) { + if (local && (ipvlan == in_dev)) + continue; + + mac_hash = ipvlan_mac_hash(eth->h_dest); + if (!test_bit(mac_hash, ipvlan->mac_filters)) + continue; + + ret = NET_RX_DROP; + len = skb->len + ETH_HLEN; + nskb = skb_clone(skb, GFP_ATOMIC); + if (!nskb) + goto mcast_acct; + + if (ether_addr_equal(eth->h_dest, ipvlan->phy_dev->broadcast)) + nskb->pkt_type = PACKET_BROADCAST; + else + nskb->pkt_type = PACKET_MULTICAST; + + nskb->dev = ipvlan->dev; + if (local) + ret = dev_forward_skb(ipvlan->dev, nskb); + else + ret = netif_rx(nskb); +mcast_acct: + ipvlan_count_rx(ipvlan, len, ret == NET_RX_SUCCESS, true); + } + + /* Locally generated? ...Forward a copy to the main-device as + * well. On the RX side we'll ignore it (wont give it to any + * of the virtual devices. + */ + if (local) { + nskb = skb_clone(skb, GFP_ATOMIC); + if (nskb) { + if (ether_addr_equal(eth->h_dest, port->dev->broadcast)) + nskb->pkt_type = PACKET_BROADCAST; + else + nskb->pkt_type = PACKET_MULTICAST; + + dev_forward_skb(port->dev, nskb); + } + } +} + +static int ipvlan_rcv_frame(struct ipvl_addr *addr, struct sk_buff *skb, + bool local) +{ + struct ipvl_dev *ipvlan = addr->master; + struct net_device *dev = ipvlan->dev; + unsigned int len; + rx_handler_result_t ret = RX_HANDLER_CONSUMED; + bool success = false; + + len = skb->len + ETH_HLEN; + if (unlikely(!(dev->flags & IFF_UP))) { + kfree_skb(skb); + goto out; + } + + skb = skb_share_check(skb, GFP_ATOMIC); + if (!skb) + goto out; + + skb->dev = dev; + skb->pkt_type = PACKET_HOST; + + if (local) { + if (dev_forward_skb(ipvlan->dev, skb) == NET_RX_SUCCESS) + success = true; + } else { + ret = RX_HANDLER_ANOTHER; + success = true; + } + +out: + ipvlan_count_rx(ipvlan, len, success, false); + return ret; +} + +static struct ipvl_addr *ipvlan_addr_lookup(struct ipvl_port *port, + void *lyr3h, int addr_type, + bool use_dest) +{ + struct ipvl_addr *addr = NULL; + + if (addr_type == IPVL_IPV6) { + struct ipv6hdr *ip6h; + struct in6_addr *i6addr; + + ip6h = (struct ipv6hdr *)lyr3h; + i6addr = use_dest ? &ip6h->daddr : &ip6h->saddr; + addr = ipvlan_ht_addr_lookup(port, i6addr, true); + } else if (addr_type == IPVL_ICMPV6) { + struct nd_msg *ndmh; + struct in6_addr *i6addr; + + /* Make sure that the NeighborSolicitation ICMPv6 packets + * are handled to avoid DAD issue. + */ + ndmh = (struct nd_msg *)lyr3h; + if (ndmh->icmph.icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) { + i6addr = &ndmh->target; + addr = ipvlan_ht_addr_lookup(port, i6addr, true); + } + } else if (addr_type == IPVL_IPV4) { + struct iphdr *ip4h; + __be32 *i4addr; + + ip4h = (struct iphdr *)lyr3h; + i4addr = use_dest ? &ip4h->daddr : &ip4h->saddr; + addr = ipvlan_ht_addr_lookup(port, i4addr, false); + } else if (addr_type == IPVL_ARP) { + struct arphdr *arph; + unsigned char *arp_ptr; + __be32 dip; + + arph = (struct arphdr *)lyr3h; + arp_ptr = (unsigned char *)(arph + 1); + if (use_dest) + arp_ptr += (2 * port->dev->addr_len) + 4; + else + arp_ptr += port->dev->addr_len; + + memcpy(&dip, arp_ptr, 4); + addr = ipvlan_ht_addr_lookup(port, &dip, false); + } + + return addr; +} + +static int ipvlan_process_v4_outbound(struct sk_buff *skb) +{ + const struct iphdr *ip4h = ip_hdr(skb); + struct net_device *dev = skb->dev; + struct rtable *rt; + int err, ret = NET_XMIT_DROP; + struct flowi4 fl4 = { + .flowi4_oif = dev->iflink, + .flowi4_tos = RT_TOS(ip4h->tos), + .flowi4_flags = FLOWI_FLAG_ANYSRC, + .daddr = ip4h->daddr, + .saddr = ip4h->saddr, + }; + + rt = ip_route_output_flow(dev_net(dev), &fl4, NULL); + if (IS_ERR(rt)) + goto err; + + if (rt->rt_type != RTN_UNICAST && rt->rt_type != RTN_LOCAL) { + ip_rt_put(rt); + goto err; + } + skb_dst_drop(skb); + skb_dst_set(skb, &rt->dst); + err = ip_local_out(skb); + if (unlikely(net_xmit_eval(err))) + dev->stats.tx_errors++; + else + ret = NET_XMIT_SUCCESS; + goto out; +err: + dev->stats.tx_errors++; + kfree_skb(skb); +out: + return ret; +} + +static int ipvlan_process_v6_outbound(struct sk_buff *skb) +{ + const struct ipv6hdr *ip6h = ipv6_hdr(skb); + struct net_device *dev = skb->dev; + struct dst_entry *dst; + int err, ret = NET_XMIT_DROP; + struct flowi6 fl6 = { + .flowi6_iif = skb->dev->ifindex, + .daddr = ip6h->daddr, + .saddr = ip6h->saddr, + .flowi6_flags = FLOWI_FLAG_ANYSRC, + .flowlabel = ip6_flowinfo(ip6h), + .flowi6_mark = skb->mark, + .flowi6_proto = ip6h->nexthdr, + }; + + dst = ip6_route_output(dev_net(dev), NULL, &fl6); + if (IS_ERR(dst)) + goto err; + + skb_dst_drop(skb); + skb_dst_set(skb, dst); + err = ip6_local_out(skb); + if (unlikely(net_xmit_eval(err))) + dev->stats.tx_errors++; + else + ret = NET_XMIT_SUCCESS; + goto out; +err: + dev->stats.tx_errors++; + kfree_skb(skb); +out: + return ret; +} + +static int ipvlan_process_outbound(struct sk_buff *skb, + const struct ipvl_dev *ipvlan) +{ + struct ethhdr *ethh = eth_hdr(skb); + int ret = NET_XMIT_DROP; + + /* In this mode we dont care about multicast and broadcast traffic */ + if (is_multicast_ether_addr(ethh->h_dest)) { + pr_warn_ratelimited("Dropped {multi|broad}cast of type= [%x]\n", + ntohs(skb->protocol)); + kfree_skb(skb); + goto out; + } + + /* The ipvlan is a pseudo-L2 device, so the packets that we receive + * will have L2; which need to discarded and processed further + * in the net-ns of the main-device. + */ + if (skb_mac_header_was_set(skb)) { + skb_pull(skb, sizeof(*ethh)); + skb->mac_header = (typeof(skb->mac_header))~0U; + skb_reset_network_header(skb); + } + + if (skb->protocol == htons(ETH_P_IPV6)) + ret = ipvlan_process_v6_outbound(skb); + else if (skb->protocol == htons(ETH_P_IP)) + ret = ipvlan_process_v4_outbound(skb); + else { + pr_warn_ratelimited("Dropped outbound packet type=%x\n", + ntohs(skb->protocol)); + kfree_skb(skb); + } +out: + return ret; +} + +static int ipvlan_xmit_mode_l3(struct sk_buff *skb, struct net_device *dev) +{ + const struct ipvl_dev *ipvlan = netdev_priv(dev); + void *lyr3h; + struct ipvl_addr *addr; + int addr_type; + + lyr3h = ipvlan_get_L3_hdr(skb, &addr_type); + if (!lyr3h) + goto out; + + addr = ipvlan_addr_lookup(ipvlan->port, lyr3h, addr_type, true); + if (addr) + return ipvlan_rcv_frame(addr, skb, true); + +out: + skb->dev = ipvlan->phy_dev; + return ipvlan_process_outbound(skb, ipvlan); +} + +static int ipvlan_xmit_mode_l2(struct sk_buff *skb, struct net_device *dev) +{ + const struct ipvl_dev *ipvlan = netdev_priv(dev); + struct ethhdr *eth = eth_hdr(skb); + struct ipvl_addr *addr; + void *lyr3h; + int addr_type; + + if (ether_addr_equal(eth->h_dest, eth->h_source)) { + lyr3h = ipvlan_get_L3_hdr(skb, &addr_type); + if (lyr3h) { + addr = ipvlan_addr_lookup(ipvlan->port, lyr3h, addr_type, true); + if (addr) + return ipvlan_rcv_frame(addr, skb, true); + } + skb = skb_share_check(skb, GFP_ATOMIC); + if (!skb) + return NET_XMIT_DROP; + + /* Packet definitely does not belong to any of the + * virtual devices, but the dest is local. So forward + * the skb for the main-dev. At the RX side we just return + * RX_PASS for it to be processed further on the stack. + */ + return dev_forward_skb(ipvlan->phy_dev, skb); + + } else if (is_multicast_ether_addr(eth->h_dest)) { + u8 ip_summed = skb->ip_summed; + + skb->ip_summed = CHECKSUM_UNNECESSARY; + ipvlan_multicast_frame(ipvlan->port, skb, ipvlan, true); + skb->ip_summed = ip_summed; + } + + skb->dev = ipvlan->phy_dev; + return dev_queue_xmit(skb); +} + +int ipvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct ipvl_dev *ipvlan = netdev_priv(dev); + struct ipvl_port *port = ipvlan_port_get_rcu(ipvlan->phy_dev); + + if (!port) + goto out; + + if (unlikely(!pskb_may_pull(skb, sizeof(struct ethhdr)))) + goto out; + + switch(port->mode) { + case IPVLAN_MODE_L2: + return ipvlan_xmit_mode_l2(skb, dev); + case IPVLAN_MODE_L3: + return ipvlan_xmit_mode_l3(skb, dev); + } + + /* Should not reach here */ + WARN_ONCE(true, "ipvlan_queue_xmit() called for mode = [%hx]\n", + port->mode); +out: + kfree_skb(skb); + return NET_XMIT_DROP; +} + +static bool ipvlan_external_frame(struct sk_buff *skb, struct ipvl_port *port) +{ + struct ethhdr *eth = eth_hdr(skb); + struct ipvl_addr *addr; + void *lyr3h; + int addr_type; + + if (ether_addr_equal(eth->h_source, skb->dev->dev_addr)) { + lyr3h = ipvlan_get_L3_hdr(skb, &addr_type); + if (!lyr3h) + return true; + + addr = ipvlan_addr_lookup(port, lyr3h, addr_type, false); + if (addr) + return false; + } + + return true; +} + +static rx_handler_result_t ipvlan_handle_mode_l3(struct sk_buff **pskb, + struct ipvl_port *port) +{ + void *lyr3h; + int addr_type; + struct ipvl_addr *addr; + struct sk_buff *skb = *pskb; + rx_handler_result_t ret = RX_HANDLER_PASS; + + lyr3h = ipvlan_get_L3_hdr(skb, &addr_type); + if (!lyr3h) + goto out; + + addr = ipvlan_addr_lookup(port, lyr3h, addr_type, true); + if (addr) + ret = ipvlan_rcv_frame(addr, skb, false); + +out: + return ret; +} + +static rx_handler_result_t ipvlan_handle_mode_l2(struct sk_buff **pskb, + struct ipvl_port *port) +{ + struct sk_buff *skb = *pskb; + struct ethhdr *eth = eth_hdr(skb); + rx_handler_result_t ret = RX_HANDLER_PASS; + void *lyr3h; + int addr_type; + + if (is_multicast_ether_addr(eth->h_dest)) { + if (ipvlan_external_frame(skb, port)) + ipvlan_multicast_frame(port, skb, NULL, false); + } else { + struct ipvl_addr *addr; + + lyr3h = ipvlan_get_L3_hdr(skb, &addr_type); + if (!lyr3h) + return ret; + + addr = ipvlan_addr_lookup(port, lyr3h, addr_type, true); + if (addr) + ret = ipvlan_rcv_frame(addr, skb, false); + } + + return ret; +} + +rx_handler_result_t ipvlan_handle_frame(struct sk_buff **pskb) +{ + struct sk_buff *skb = *pskb; + struct ipvl_port *port = ipvlan_port_get_rcu(skb->dev); + + if (!port) + return RX_HANDLER_PASS; + + switch (port->mode) { + case IPVLAN_MODE_L2: + return ipvlan_handle_mode_l2(pskb, port); + case IPVLAN_MODE_L3: + return ipvlan_handle_mode_l3(pskb, port); + } + + /* Should not reach here */ + WARN_ONCE(true, "ipvlan_handle_frame() called for mode = [%hx]\n", + port->mode); + kfree_skb(skb); + return NET_RX_DROP; +} diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c new file mode 100644 index 000000000000..c3df84bd2857 --- /dev/null +++ b/drivers/net/ipvlan/ipvlan_main.c @@ -0,0 +1,789 @@ +/* Copyright (c) 2014 Mahesh Bandewar + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + */ + +#include "ipvlan.h" + +void ipvlan_adjust_mtu(struct ipvl_dev *ipvlan, struct net_device *dev) +{ + ipvlan->dev->mtu = dev->mtu - ipvlan->mtu_adj; +} + +void ipvlan_set_port_mode(struct ipvl_port *port, u32 nval) +{ + struct ipvl_dev *ipvlan; + + if (port->mode != nval) { + list_for_each_entry(ipvlan, &port->ipvlans, pnode) { + if (nval == IPVLAN_MODE_L3) + ipvlan->dev->flags |= IFF_NOARP; + else + ipvlan->dev->flags &= ~IFF_NOARP; + } + port->mode = nval; + } +} + +static int ipvlan_port_create(struct net_device *dev) +{ + struct ipvl_port *port; + int err, idx; + + if (dev->type != ARPHRD_ETHER || dev->flags & IFF_LOOPBACK) { + netdev_err(dev, "Master is either lo or non-ether device\n"); + return -EINVAL; + } + port = kzalloc(sizeof(struct ipvl_port), GFP_KERNEL); + if (!port) + return -ENOMEM; + + port->dev = dev; + port->mode = IPVLAN_MODE_L3; + INIT_LIST_HEAD(&port->ipvlans); + for (idx = 0; idx < IPVLAN_HASH_SIZE; idx++) + INIT_HLIST_HEAD(&port->hlhead[idx]); + + err = netdev_rx_handler_register(dev, ipvlan_handle_frame, port); + if (err) + goto err; + + dev->priv_flags |= IFF_IPVLAN_MASTER; + return 0; + +err: + kfree_rcu(port, rcu); + return err; +} + +static void ipvlan_port_destroy(struct net_device *dev) +{ + struct ipvl_port *port = ipvlan_port_get_rtnl(dev); + + dev->priv_flags &= ~IFF_IPVLAN_MASTER; + netdev_rx_handler_unregister(dev); + kfree_rcu(port, rcu); +} + +/* ipvlan network devices have devices nesting below it and are a special + * "super class" of normal network devices; split their locks off into a + * separate class since they always nest. + */ +static struct lock_class_key ipvlan_netdev_xmit_lock_key; +static struct lock_class_key ipvlan_netdev_addr_lock_key; + +#define IPVLAN_FEATURES \ + (NETIF_F_SG | NETIF_F_ALL_CSUM | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | \ + NETIF_F_GSO | NETIF_F_TSO | NETIF_F_UFO | NETIF_F_GSO_ROBUST | \ + NETIF_F_TSO_ECN | NETIF_F_TSO6 | NETIF_F_GRO | NETIF_F_RXCSUM | \ + NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_VLAN_STAG_FILTER) + +#define IPVLAN_STATE_MASK \ + ((1<<__LINK_STATE_NOCARRIER) | (1<<__LINK_STATE_DORMANT)) + +static void ipvlan_set_lockdep_class_one(struct net_device *dev, + struct netdev_queue *txq, + void *_unused) +{ + lockdep_set_class(&txq->_xmit_lock, &ipvlan_netdev_xmit_lock_key); +} + +static void ipvlan_set_lockdep_class(struct net_device *dev) +{ + lockdep_set_class(&dev->addr_list_lock, &ipvlan_netdev_addr_lock_key); + netdev_for_each_tx_queue(dev, ipvlan_set_lockdep_class_one, NULL); +} + +static int ipvlan_init(struct net_device *dev) +{ + struct ipvl_dev *ipvlan = netdev_priv(dev); + const struct net_device *phy_dev = ipvlan->phy_dev; + + dev->state = (dev->state & ~IPVLAN_STATE_MASK) | + (phy_dev->state & IPVLAN_STATE_MASK); + dev->features = phy_dev->features & IPVLAN_FEATURES; + dev->features |= NETIF_F_LLTX; + dev->gso_max_size = phy_dev->gso_max_size; + dev->iflink = phy_dev->ifindex; + dev->hard_header_len = phy_dev->hard_header_len; + + ipvlan_set_lockdep_class(dev); + + ipvlan->pcpu_stats = alloc_percpu(struct ipvl_pcpu_stats); + if (!ipvlan->pcpu_stats) + return -ENOMEM; + + return 0; +} + +static void ipvlan_uninit(struct net_device *dev) +{ + struct ipvl_dev *ipvlan = netdev_priv(dev); + struct ipvl_port *port = ipvlan->port; + + if (ipvlan->pcpu_stats) + free_percpu(ipvlan->pcpu_stats); + + port->count -= 1; + if (!port->count) + ipvlan_port_destroy(port->dev); +} + +static int ipvlan_open(struct net_device *dev) +{ + struct ipvl_dev *ipvlan = netdev_priv(dev); + struct net_device *phy_dev = ipvlan->phy_dev; + struct ipvl_addr *addr; + + if (ipvlan->port->mode == IPVLAN_MODE_L3) + dev->flags |= IFF_NOARP; + else + dev->flags &= ~IFF_NOARP; + + if (ipvlan->ipv6cnt > 0 || ipvlan->ipv4cnt > 0) { + list_for_each_entry(addr, &ipvlan->addrs, anode) + ipvlan_ht_addr_add(ipvlan, addr); + } + return dev_uc_add(phy_dev, phy_dev->dev_addr); +} + +static int ipvlan_stop(struct net_device *dev) +{ + struct ipvl_dev *ipvlan = netdev_priv(dev); + struct net_device *phy_dev = ipvlan->phy_dev; + struct ipvl_addr *addr; + + dev_uc_unsync(phy_dev, dev); + dev_mc_unsync(phy_dev, dev); + + dev_uc_del(phy_dev, phy_dev->dev_addr); + + if (ipvlan->ipv6cnt > 0 || ipvlan->ipv4cnt > 0) { + list_for_each_entry(addr, &ipvlan->addrs, anode) + ipvlan_ht_addr_del(addr, !dev->dismantle); + } + return 0; +} + +netdev_tx_t ipvlan_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + const struct ipvl_dev *ipvlan = netdev_priv(dev); + int skblen = skb->len; + int ret; + + ret = ipvlan_queue_xmit(skb, dev); + if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) { + struct ipvl_pcpu_stats *pcptr; + + pcptr = this_cpu_ptr(ipvlan->pcpu_stats); + + u64_stats_update_begin(&pcptr->syncp); + pcptr->tx_pkts++; + pcptr->tx_bytes += skblen; + u64_stats_update_end(&pcptr->syncp); + } else { + this_cpu_inc(ipvlan->pcpu_stats->tx_drps); + } + return ret; +} + +static netdev_features_t ipvlan_fix_features(struct net_device *dev, + netdev_features_t features) +{ + struct ipvl_dev *ipvlan = netdev_priv(dev); + + return features & (ipvlan->sfeatures | ~IPVLAN_FEATURES); +} + +static void ipvlan_change_rx_flags(struct net_device *dev, int change) +{ + struct ipvl_dev *ipvlan = netdev_priv(dev); + struct net_device *phy_dev = ipvlan->phy_dev; + + if (change & IFF_ALLMULTI) + dev_set_allmulti(phy_dev, dev->flags & IFF_ALLMULTI? 1 : -1); +} + +static void ipvlan_set_broadcast_mac_filter(struct ipvl_dev *ipvlan, bool set) +{ + struct net_device *dev = ipvlan->dev; + unsigned int hashbit = ipvlan_mac_hash(dev->broadcast); + + if (set && !test_bit(hashbit, ipvlan->mac_filters)) + __set_bit(hashbit, ipvlan->mac_filters); + else if (!set && test_bit(hashbit, ipvlan->mac_filters)) + __clear_bit(hashbit, ipvlan->mac_filters); +} + +static void ipvlan_set_multicast_mac_filter(struct net_device *dev) +{ + struct ipvl_dev *ipvlan = netdev_priv(dev); + + if (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) { + bitmap_fill(ipvlan->mac_filters, IPVLAN_MAC_FILTER_SIZE); + } else { + struct netdev_hw_addr *ha; + DECLARE_BITMAP(mc_filters, IPVLAN_MAC_FILTER_SIZE); + + bitmap_zero(mc_filters, IPVLAN_MAC_FILTER_SIZE); + netdev_for_each_mc_addr(ha, dev) + __set_bit(ipvlan_mac_hash(ha->addr), mc_filters); + + bitmap_copy(ipvlan->mac_filters, mc_filters, + IPVLAN_MAC_FILTER_SIZE); + } + dev_uc_sync(ipvlan->phy_dev, dev); + dev_mc_sync(ipvlan->phy_dev, dev); +} + +static struct rtnl_link_stats64 *ipvlan_get_stats64(struct net_device *dev, + struct rtnl_link_stats64 *s) +{ + struct ipvl_dev *ipvlan = netdev_priv(dev); + + if (ipvlan->pcpu_stats) { + struct ipvl_pcpu_stats *pcptr; + u64 rx_pkts, rx_bytes, rx_mcast, tx_pkts, tx_bytes; + u32 rx_errs = 0, tx_drps = 0; + u32 strt; + int idx; + + for_each_possible_cpu(idx) { + pcptr = per_cpu_ptr(ipvlan->pcpu_stats, idx); + do { + strt= u64_stats_fetch_begin_irq(&pcptr->syncp); + rx_pkts = pcptr->rx_pkts; + rx_bytes = pcptr->rx_bytes; + rx_mcast = pcptr->rx_mcast; + tx_pkts = pcptr->tx_pkts; + tx_bytes = pcptr->tx_bytes; + } while (u64_stats_fetch_retry_irq(&pcptr->syncp, + strt)); + + s->rx_packets += rx_pkts; + s->rx_bytes += rx_bytes; + s->multicast += rx_mcast; + s->tx_packets += tx_pkts; + s->tx_bytes += tx_bytes; + + /* u32 values are updated without syncp protection. */ + rx_errs += pcptr->rx_errs; + tx_drps += pcptr->tx_drps; + } + s->rx_errors = rx_errs; + s->rx_dropped = rx_errs; + s->tx_dropped = tx_drps; + } + return s; +} + +static int ipvlan_vlan_rx_add_vid(struct net_device *dev, __be16 proto, u16 vid) +{ + struct ipvl_dev *ipvlan = netdev_priv(dev); + struct net_device *phy_dev = ipvlan->phy_dev; + + return vlan_vid_add(phy_dev, proto, vid); +} + +static int ipvlan_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, + u16 vid) +{ + struct ipvl_dev *ipvlan = netdev_priv(dev); + struct net_device *phy_dev = ipvlan->phy_dev; + + vlan_vid_del(phy_dev, proto, vid); + return 0; +} + +static const struct net_device_ops ipvlan_netdev_ops = { + .ndo_init = ipvlan_init, + .ndo_uninit = ipvlan_uninit, + .ndo_open = ipvlan_open, + .ndo_stop = ipvlan_stop, + .ndo_start_xmit = ipvlan_start_xmit, + .ndo_fix_features = ipvlan_fix_features, + .ndo_change_rx_flags = ipvlan_change_rx_flags, + .ndo_set_rx_mode = ipvlan_set_multicast_mac_filter, + .ndo_get_stats64 = ipvlan_get_stats64, + .ndo_vlan_rx_add_vid = ipvlan_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = ipvlan_vlan_rx_kill_vid, +}; + +static int ipvlan_hard_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, const void *daddr, + const void *saddr, unsigned len) +{ + const struct ipvl_dev *ipvlan = netdev_priv(dev); + struct net_device *phy_dev = ipvlan->phy_dev; + + /* TODO Probably use a different field than dev_addr so that the + * mac-address on the virtual device is portable and can be carried + * while the packets use the mac-addr on the physical device. + */ + return dev_hard_header(skb, phy_dev, type, daddr, + saddr ? : dev->dev_addr, len); +} + +static const struct header_ops ipvlan_header_ops = { + .create = ipvlan_hard_header, + .rebuild = eth_rebuild_header, + .parse = eth_header_parse, + .cache = eth_header_cache, + .cache_update = eth_header_cache_update, +}; + +static int ipvlan_ethtool_get_settings(struct net_device *dev, + struct ethtool_cmd *cmd) +{ + const struct ipvl_dev *ipvlan = netdev_priv(dev); + + return __ethtool_get_settings(ipvlan->phy_dev, cmd); +} + +static void ipvlan_ethtool_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *drvinfo) +{ + strlcpy(drvinfo->driver, IPVLAN_DRV, sizeof(drvinfo->driver)); + strlcpy(drvinfo->version, IPV_DRV_VER, sizeof(drvinfo->version)); +} + +static u32 ipvlan_ethtool_get_msglevel(struct net_device *dev) +{ + const struct ipvl_dev *ipvlan = netdev_priv(dev); + + return ipvlan->msg_enable; +} + +static void ipvlan_ethtool_set_msglevel(struct net_device *dev, u32 value) +{ + struct ipvl_dev *ipvlan = netdev_priv(dev); + + ipvlan->msg_enable = value; +} + +static const struct ethtool_ops ipvlan_ethtool_ops = { + .get_link = ethtool_op_get_link, + .get_settings = ipvlan_ethtool_get_settings, + .get_drvinfo = ipvlan_ethtool_get_drvinfo, + .get_msglevel = ipvlan_ethtool_get_msglevel, + .set_msglevel = ipvlan_ethtool_set_msglevel, +}; + +static int ipvlan_nl_changelink(struct net_device *dev, + struct nlattr *tb[], struct nlattr *data[]) +{ + struct ipvl_dev *ipvlan = netdev_priv(dev); + struct ipvl_port *port = ipvlan_port_get_rtnl(ipvlan->phy_dev); + + if (data && data[IFLA_IPVLAN_MODE]) { + u16 nmode = nla_get_u16(data[IFLA_IPVLAN_MODE]); + + ipvlan_set_port_mode(port, nmode); + } + return 0; +} + +static size_t ipvlan_nl_getsize(const struct net_device *dev) +{ + return (0 + + nla_total_size(2) /* IFLA_IPVLAN_MODE */ + ); +} + +static int ipvlan_nl_validate(struct nlattr *tb[], struct nlattr *data[]) +{ + if (data && data[IFLA_IPVLAN_MODE]) { + u16 mode = nla_get_u16(data[IFLA_IPVLAN_MODE]); + + if (mode < IPVLAN_MODE_L2 || mode >= IPVLAN_MODE_MAX) + return -EINVAL; + } + return 0; +} + +static int ipvlan_nl_fillinfo(struct sk_buff *skb, + const struct net_device *dev) +{ + struct ipvl_dev *ipvlan = netdev_priv(dev); + struct ipvl_port *port = ipvlan_port_get_rtnl(ipvlan->phy_dev); + int ret = -EINVAL; + + if (!port) + goto err; + + ret = -EMSGSIZE; + if (nla_put_u16(skb, IFLA_IPVLAN_MODE, port->mode)) + goto err; + + return 0; + +err: + return ret; +} + +static int ipvlan_link_new(struct net *src_net, struct net_device *dev, + struct nlattr *tb[], struct nlattr *data[]) +{ + struct ipvl_dev *ipvlan = netdev_priv(dev); + struct ipvl_port *port; + struct net_device *phy_dev; + int err; + + if (!tb[IFLA_LINK]) + return -EINVAL; + + phy_dev = __dev_get_by_index(src_net, nla_get_u32(tb[IFLA_LINK])); + if (!phy_dev) + return -ENODEV; + + if (ipvlan_dev_slave(phy_dev)) { + struct ipvl_dev *tmp = netdev_priv(phy_dev); + + phy_dev = tmp->phy_dev; + } else if (!ipvlan_dev_master(phy_dev)) { + err = ipvlan_port_create(phy_dev); + if (err < 0) + return err; + } + + port = ipvlan_port_get_rtnl(phy_dev); + if (data && data[IFLA_IPVLAN_MODE]) + port->mode = nla_get_u16(data[IFLA_IPVLAN_MODE]); + + ipvlan->phy_dev = phy_dev; + ipvlan->dev = dev; + ipvlan->port = port; + ipvlan->sfeatures = IPVLAN_FEATURES; + INIT_LIST_HEAD(&ipvlan->addrs); + ipvlan->ipv4cnt = 0; + ipvlan->ipv6cnt = 0; + + /* TODO Probably put random address here to be presented to the + * world but keep using the physical-dev address for the outgoing + * packets. + */ + memcpy(dev->dev_addr, phy_dev->dev_addr, ETH_ALEN); + + dev->priv_flags |= IFF_IPVLAN_SLAVE; + + port->count += 1; + err = register_netdevice(dev); + if (err < 0) + goto ipvlan_destroy_port; + + err = netdev_upper_dev_link(phy_dev, dev); + if (err) + goto ipvlan_destroy_port; + + list_add_tail_rcu(&ipvlan->pnode, &port->ipvlans); + netif_stacked_transfer_operstate(phy_dev, dev); + return 0; + +ipvlan_destroy_port: + port->count -= 1; + if (!port->count) + ipvlan_port_destroy(phy_dev); + + return err; +} + +static void ipvlan_link_delete(struct net_device *dev, struct list_head *head) +{ + struct ipvl_dev *ipvlan = netdev_priv(dev); + struct ipvl_addr *addr, *next; + + if (ipvlan->ipv6cnt > 0 || ipvlan->ipv4cnt > 0) { + list_for_each_entry_safe(addr, next, &ipvlan->addrs, anode) { + ipvlan_ht_addr_del(addr, !dev->dismantle); + list_del_rcu(&addr->anode); + } + } + list_del_rcu(&ipvlan->pnode); + unregister_netdevice_queue(dev, head); + netdev_upper_dev_unlink(ipvlan->phy_dev, dev); +} + +static void ipvlan_link_setup(struct net_device *dev) +{ + ether_setup(dev); + + dev->priv_flags &= ~(IFF_XMIT_DST_RELEASE | IFF_TX_SKB_SHARING); + dev->priv_flags |= IFF_UNICAST_FLT; + dev->netdev_ops = &ipvlan_netdev_ops; + dev->destructor = free_netdev; + dev->header_ops = &ipvlan_header_ops; + dev->ethtool_ops = &ipvlan_ethtool_ops; + dev->tx_queue_len = 0; +} + +static const struct nla_policy ipvlan_nl_policy[IFLA_IPVLAN_MAX + 1] = +{ + [IFLA_IPVLAN_MODE] = { .type = NLA_U16 }, +}; + +static struct rtnl_link_ops ipvlan_link_ops = { + .kind = "ipvlan", + .priv_size = sizeof(struct ipvl_dev), + + .get_size = ipvlan_nl_getsize, + .policy = ipvlan_nl_policy, + .validate = ipvlan_nl_validate, + .fill_info = ipvlan_nl_fillinfo, + .changelink = ipvlan_nl_changelink, + .maxtype = IFLA_IPVLAN_MAX, + + .setup = ipvlan_link_setup, + .newlink = ipvlan_link_new, + .dellink = ipvlan_link_delete, +}; + +int ipvlan_link_register(struct rtnl_link_ops *ops) +{ + return rtnl_link_register(ops); +} + +static int ipvlan_device_event(struct notifier_block *unused, + unsigned long event, void *ptr) +{ + struct net_device *dev = netdev_notifier_info_to_dev(ptr); + struct ipvl_dev *ipvlan, *next; + struct ipvl_port *port; + LIST_HEAD(lst_kill); + + if (!ipvlan_dev_master(dev)) + return NOTIFY_DONE; + + port = ipvlan_port_get_rtnl(dev); + + switch (event) { + case NETDEV_CHANGE: + list_for_each_entry(ipvlan, &port->ipvlans, pnode) + netif_stacked_transfer_operstate(ipvlan->phy_dev, + ipvlan->dev); + break; + + case NETDEV_UNREGISTER: + if (dev->reg_state != NETREG_UNREGISTERING) + break; + + list_for_each_entry_safe(ipvlan, next, &port->ipvlans, + pnode) + ipvlan->dev->rtnl_link_ops->dellink(ipvlan->dev, + &lst_kill); + unregister_netdevice_many(&lst_kill); + break; + + case NETDEV_FEAT_CHANGE: + list_for_each_entry(ipvlan, &port->ipvlans, pnode) { + ipvlan->dev->features = dev->features & IPVLAN_FEATURES; + ipvlan->dev->gso_max_size = dev->gso_max_size; + netdev_features_change(ipvlan->dev); + } + break; + + case NETDEV_CHANGEMTU: + list_for_each_entry(ipvlan, &port->ipvlans, pnode) + ipvlan_adjust_mtu(ipvlan, dev); + break; + + case NETDEV_PRE_TYPE_CHANGE: + /* Forbid underlying device to change its type. */ + return NOTIFY_BAD; + } + return NOTIFY_DONE; +} + +static int ipvlan_add_addr6(struct ipvl_dev *ipvlan, struct in6_addr *ip6_addr) +{ + struct ipvl_addr *addr; + + if (ipvlan_addr_busy(ipvlan, ip6_addr, true)) { + netif_err(ipvlan, ifup, ipvlan->dev, + "Failed to add IPv6=%pI6c addr for %s intf\n", + ip6_addr, ipvlan->dev->name); + return -EINVAL; + } + addr = kzalloc(sizeof(struct ipvl_addr), GFP_ATOMIC); + if (!addr) + return -ENOMEM; + + addr->master = ipvlan; + memcpy(&addr->ip6addr, ip6_addr, sizeof(struct in6_addr)); + addr->atype = IPVL_IPV6; + list_add_tail_rcu(&addr->anode, &ipvlan->addrs); + ipvlan->ipv6cnt++; + ipvlan_ht_addr_add(ipvlan, addr); + + return 0; +} + +static void ipvlan_del_addr6(struct ipvl_dev *ipvlan, struct in6_addr *ip6_addr) +{ + struct ipvl_addr *addr; + + addr = ipvlan_ht_addr_lookup(ipvlan->port, ip6_addr, true); + if (!addr) + return; + + ipvlan_ht_addr_del(addr, true); + list_del_rcu(&addr->anode); + ipvlan->ipv6cnt--; + WARN_ON(ipvlan->ipv6cnt < 0); + kfree_rcu(addr, rcu); + + return; +} + +static int ipvlan_addr6_event(struct notifier_block *unused, + unsigned long event, void *ptr) +{ + struct inet6_ifaddr *if6 = (struct inet6_ifaddr *)ptr; + struct net_device *dev = (struct net_device *)if6->idev->dev; + struct ipvl_dev *ipvlan = netdev_priv(dev); + + if (!ipvlan_dev_slave(dev)) + return NOTIFY_DONE; + + if (!ipvlan || !ipvlan->port) + return NOTIFY_DONE; + + switch (event) { + case NETDEV_UP: + if (ipvlan_add_addr6(ipvlan, &if6->addr)) + return NOTIFY_BAD; + break; + + case NETDEV_DOWN: + ipvlan_del_addr6(ipvlan, &if6->addr); + break; + } + + return NOTIFY_OK; +} + +static int ipvlan_add_addr4(struct ipvl_dev *ipvlan, struct in_addr *ip4_addr) +{ + struct ipvl_addr *addr; + + if (ipvlan_addr_busy(ipvlan, ip4_addr, false)) { + netif_err(ipvlan, ifup, ipvlan->dev, + "Failed to add IPv4=%pI4 on %s intf.\n", + ip4_addr, ipvlan->dev->name); + return -EINVAL; + } + addr = kzalloc(sizeof(struct ipvl_addr), GFP_KERNEL); + if (!addr) + return -ENOMEM; + + addr->master = ipvlan; + memcpy(&addr->ip4addr, ip4_addr, sizeof(struct in_addr)); + addr->atype = IPVL_IPV4; + list_add_tail_rcu(&addr->anode, &ipvlan->addrs); + ipvlan->ipv4cnt++; + ipvlan_ht_addr_add(ipvlan, addr); + ipvlan_set_broadcast_mac_filter(ipvlan, true); + + return 0; +} + +static void ipvlan_del_addr4(struct ipvl_dev *ipvlan, struct in_addr *ip4_addr) +{ + struct ipvl_addr *addr; + + addr = ipvlan_ht_addr_lookup(ipvlan->port, ip4_addr, false); + if (!addr) + return; + + ipvlan_ht_addr_del(addr, true); + list_del_rcu(&addr->anode); + ipvlan->ipv4cnt--; + WARN_ON(ipvlan->ipv4cnt < 0); + if (!ipvlan->ipv4cnt) + ipvlan_set_broadcast_mac_filter(ipvlan, false); + kfree_rcu(addr, rcu); + + return; +} + +static int ipvlan_addr4_event(struct notifier_block *unused, + unsigned long event, void *ptr) +{ + struct in_ifaddr *if4 = (struct in_ifaddr *)ptr; + struct net_device *dev = (struct net_device *)if4->ifa_dev->dev; + struct ipvl_dev *ipvlan = netdev_priv(dev); + struct in_addr ip4_addr; + + if (!ipvlan_dev_slave(dev)) + return NOTIFY_DONE; + + if (!ipvlan || !ipvlan->port) + return NOTIFY_DONE; + + switch (event) { + case NETDEV_UP: + ip4_addr.s_addr = if4->ifa_address; + if (ipvlan_add_addr4(ipvlan, &ip4_addr)) + return NOTIFY_BAD; + break; + + case NETDEV_DOWN: + ip4_addr.s_addr = if4->ifa_address; + ipvlan_del_addr4(ipvlan, &ip4_addr); + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block ipvlan_addr4_notifier_block __read_mostly = { + .notifier_call = ipvlan_addr4_event, +}; + +static struct notifier_block ipvlan_notifier_block __read_mostly = { + .notifier_call = ipvlan_device_event, +}; + +static struct notifier_block ipvlan_addr6_notifier_block __read_mostly = { + .notifier_call = ipvlan_addr6_event, +}; + +static int __init ipvlan_init_module(void) +{ + int err; + + ipvlan_init_secret(); + register_netdevice_notifier(&ipvlan_notifier_block); + register_inet6addr_notifier(&ipvlan_addr6_notifier_block); + register_inetaddr_notifier(&ipvlan_addr4_notifier_block); + + err = ipvlan_link_register(&ipvlan_link_ops); + if (err < 0) + goto error; + + return 0; +error: + unregister_inetaddr_notifier(&ipvlan_addr4_notifier_block); + unregister_inet6addr_notifier(&ipvlan_addr6_notifier_block); + unregister_netdevice_notifier(&ipvlan_notifier_block); + return err; +} + +static void __exit ipvlan_cleanup_module(void) +{ + rtnl_link_unregister(&ipvlan_link_ops); + unregister_netdevice_notifier(&ipvlan_notifier_block); + unregister_inetaddr_notifier(&ipvlan_addr4_notifier_block); + unregister_inet6addr_notifier(&ipvlan_addr6_notifier_block); +} + +module_init(ipvlan_init_module); +module_exit(ipvlan_cleanup_module); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mahesh Bandewar "); +MODULE_DESCRIPTION("Driver for L3 (IPv6/IPv4) based VLANs"); +MODULE_ALIAS_RTNL_LINK("ipvlan"); diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 5cd508787572..2cb772495f7a 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1230,6 +1230,8 @@ enum netdev_priv_flags { IFF_LIVE_ADDR_CHANGE = 1<<20, IFF_MACVLAN = 1<<21, IFF_XMIT_DST_RELEASE_PERM = 1<<22, + IFF_IPVLAN_MASTER = 1<<23, + IFF_IPVLAN_SLAVE = 1<<24, }; #define IFF_802_1Q_VLAN IFF_802_1Q_VLAN @@ -1255,6 +1257,8 @@ enum netdev_priv_flags { #define IFF_LIVE_ADDR_CHANGE IFF_LIVE_ADDR_CHANGE #define IFF_MACVLAN IFF_MACVLAN #define IFF_XMIT_DST_RELEASE_PERM IFF_XMIT_DST_RELEASE_PERM +#define IFF_IPVLAN_MASTER IFF_IPVLAN_MASTER +#define IFF_IPVLAN_SLAVE IFF_IPVLAN_SLAVE /** * struct net_device - The DEVICE structure. diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 7072d8325016..36bddc233633 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -330,6 +330,21 @@ enum macvlan_macaddr_mode { #define MACVLAN_FLAG_NOPROMISC 1 +/* IPVLAN section */ +enum { + IFLA_IPVLAN_UNSPEC, + IFLA_IPVLAN_MODE, + __IFLA_IPVLAN_MAX +}; + +#define IFLA_IPVLAN_MAX (__IFLA_IPVLAN_MAX - 1) + +enum ipvlan_mode { + IPVLAN_MODE_L2 = 0, + IPVLAN_MODE_L3, + IPVLAN_MODE_MAX +}; + /* VXLAN section */ enum { IFLA_VXLAN_UNSPEC, -- cgit v1.2.3-59-g8ed1b From e920f9b632a687834de5a78c60ac5c4c62327b1d Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Tue, 4 Nov 2014 13:00:38 -0300 Subject: thermal: armada: Remove support for A375-Z1 SoC The Armada 375 Z1 SoC revision is no longer supported. This commit removes the quirk needed for the thermal sensor. Acked-by: Jason Cooper Signed-off-by: Ezequiel Garcia Signed-off-by: Eduardo Valentin --- .../devicetree/bindings/thermal/armada-thermal.txt | 8 -------- drivers/thermal/armada_thermal.c | 20 -------------------- 2 files changed, 28 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/thermal/armada-thermal.txt b/Documentation/devicetree/bindings/thermal/armada-thermal.txt index 4cf024929a3f..4698e0edc205 100644 --- a/Documentation/devicetree/bindings/thermal/armada-thermal.txt +++ b/Documentation/devicetree/bindings/thermal/armada-thermal.txt @@ -5,17 +5,9 @@ Required properties: - compatible: Should be set to one of the following: marvell,armada370-thermal marvell,armada375-thermal - marvell,armada375-z1-thermal marvell,armada380-thermal marvell,armadaxp-thermal - Note: As the name suggests, "marvell,armada375-z1-thermal" - applies for the SoC Z1 stepping only. On such stepping - some quirks need to be done and the register offset differs - from the one in the A0 stepping. - The operating system may auto-detect the SoC stepping and - update the compatible and register offsets at runtime. - - reg: Device's register space. Two entries are expected, see the examples below. The first one is required for the sensor register; diff --git a/drivers/thermal/armada_thermal.c b/drivers/thermal/armada_thermal.c index 9d1420acb391..9c8e7834e4ae 100644 --- a/drivers/thermal/armada_thermal.c +++ b/drivers/thermal/armada_thermal.c @@ -35,10 +35,6 @@ #define PMU_TDC0_OTF_CAL_MASK (0x1 << 30) #define PMU_TDC0_START_CAL_MASK (0x1 << 25) -#define A375_Z1_CAL_RESET_LSB 0x8011e214 -#define A375_Z1_CAL_RESET_MSB 0x30a88019 -#define A375_Z1_WORKAROUND_BIT BIT(9) - #define A375_UNIT_CONTROL_SHIFT 27 #define A375_UNIT_CONTROL_MASK 0x7 #define A375_READOUT_INVERT BIT(15) @@ -124,24 +120,12 @@ static void armada375_init_sensor(struct platform_device *pdev, struct armada_thermal_priv *priv) { unsigned long reg; - bool quirk_needed = - !!of_device_is_compatible(pdev->dev.of_node, - "marvell,armada375-z1-thermal"); - - if (quirk_needed) { - /* Ensure these registers have the default (reset) values */ - writel(A375_Z1_CAL_RESET_LSB, priv->control); - writel(A375_Z1_CAL_RESET_MSB, priv->control + 0x4); - } reg = readl(priv->control + 4); reg &= ~(A375_UNIT_CONTROL_MASK << A375_UNIT_CONTROL_SHIFT); reg &= ~A375_READOUT_INVERT; reg &= ~A375_HW_RESETn; - if (quirk_needed) - reg |= A375_Z1_WORKAROUND_BIT; - writel(reg, priv->control + 4); mdelay(20); @@ -259,10 +243,6 @@ static const struct of_device_id armada_thermal_id_table[] = { .compatible = "marvell,armada375-thermal", .data = &armada375_data, }, - { - .compatible = "marvell,armada375-z1-thermal", - .data = &armada375_data, - }, { .compatible = "marvell,armada380-thermal", .data = &armada380_data, -- cgit v1.2.3-59-g8ed1b From 7518b5890d8ac366faa2326ce2356ef6392ce63d Mon Sep 17 00:00:00 2001 From: Pantelis Antoniou Date: Tue, 28 Oct 2014 22:35:58 +0200 Subject: of/overlay: Introduce DT overlay support Overlays are a method to dynamically modify part of the kernel's device tree with dynamically loaded data. Add the core functionality to parse, apply and remove an overlay changeset. The core functionality takes care of managing the overlay data format and performing the add and remove. Drivers are expected to use the overlay functionality to support custom expansion busses commonly found on consumer development boards like the BeagleBone or Raspberry Pi. The overlay code uses CONFIG_OF_DYNAMIC changesets to perform the low level work of modifying the devicetree. Documentation about internal and APIs is provided in Documentation/devicetree/overlay-notes.txt v2: - Switch from __of_node_alloc() to __of_node_dup() - Documentation fixups - Remove 2-pass processing of properties - Remove separate ov_lock; just use the DT mutex. v1: - Drop delete capability using '-' prefix. The '-' prefixed names are valid properties and nodes and there is no need for it just yet. - Do not update special properties - name & phandle ones. - Change order of node attachment, so that the special property update works. Signed-off-by: Pantelis Antoniou Signed-off-by: Grant Likely --- Documentation/devicetree/overlay-notes.txt | 133 +++++++ drivers/of/Kconfig | 7 + drivers/of/Makefile | 1 + drivers/of/overlay.c | 562 +++++++++++++++++++++++++++++ include/linux/of.h | 31 ++ 5 files changed, 734 insertions(+) create mode 100644 Documentation/devicetree/overlay-notes.txt create mode 100644 drivers/of/overlay.c (limited to 'Documentation') diff --git a/Documentation/devicetree/overlay-notes.txt b/Documentation/devicetree/overlay-notes.txt new file mode 100644 index 000000000000..30ae758e3eef --- /dev/null +++ b/Documentation/devicetree/overlay-notes.txt @@ -0,0 +1,133 @@ +Device Tree Overlay Notes +------------------------- + +This document describes the implementation of the in-kernel +device tree overlay functionality residing in drivers/of/overlay.c and is a +companion document to Documentation/devicetree/dt-object-internal.txt[1] & +Documentation/devicetree/dynamic-resolution-notes.txt[2] + +How overlays work +----------------- + +A Device Tree's overlay purpose is to modify the kernel's live tree, and +have the modification affecting the state of the the kernel in a way that +is reflecting the changes. +Since the kernel mainly deals with devices, any new device node that result +in an active device should have it created while if the device node is either +disabled or removed all together, the affected device should be deregistered. + +Lets take an example where we have a foo board with the following base tree +which is taken from [1]. + +---- foo.dts ----------------------------------------------------------------- + /* FOO platform */ + / { + compatible = "corp,foo"; + + /* shared resources */ + res: res { + }; + + /* On chip peripherals */ + ocp: ocp { + /* peripherals that are always instantiated */ + peripheral1 { ... }; + } + }; +---- foo.dts ----------------------------------------------------------------- + +The overlay bar.dts, when loaded (and resolved as described in [2]) should + +---- bar.dts ----------------------------------------------------------------- +/plugin/; /* allow undefined label references and record them */ +/ { + .... /* various properties for loader use; i.e. part id etc. */ + fragment@0 { + target = <&ocp>; + __overlay__ { + /* bar peripheral */ + bar { + compatible = "corp,bar"; + ... /* various properties and child nodes */ + } + }; + }; +}; +---- bar.dts ----------------------------------------------------------------- + +result in foo+bar.dts + +---- foo+bar.dts ------------------------------------------------------------- + /* FOO platform + bar peripheral */ + / { + compatible = "corp,foo"; + + /* shared resources */ + res: res { + }; + + /* On chip peripherals */ + ocp: ocp { + /* peripherals that are always instantiated */ + peripheral1 { ... }; + + /* bar peripheral */ + bar { + compatible = "corp,bar"; + ... /* various properties and child nodes */ + } + } + }; +---- foo+bar.dts ------------------------------------------------------------- + +As a result of the the overlay, a new device node (bar) has been created +so a bar platform device will be registered and if a matching device driver +is loaded the device will be created as expected. + +Overlay in-kernel API +-------------------------------- + +The API is quite easy to use. + +1. Call of_overlay_create() to create and apply an overlay. The return value +is a cookie identifying this overlay. + +2. Call of_overlay_destroy() to remove and cleanup the overlay previously +created via the call to of_overlay_create(). Removal of an overlay that +is stacked by another will not be permitted. + +Finally, if you need to remove all overlays in one-go, just call +of_overlay_destroy_all() which will remove every single one in the correct +order. + +Overlay DTS Format +------------------ + +The DTS of an overlay should have the following format: + +{ + /* ignored properties by the overlay */ + + fragment@0 { /* first child node */ + + target=; /* phandle target of the overlay */ + or + target-path="/path"; /* target path of the overlay */ + + __overlay__ { + property-a; /* add property-a to the target */ + node-a { /* add to an existing, or create a node-a */ + ... + }; + }; + } + fragment@1 { /* second child node */ + ... + }; + /* more fragments follow */ +} + +Using the non-phandle based target method allows one to use a base DT which does +not contain a __symbols__ node, i.e. it was not compiled with the -@ option. +The __symbols__ node is only required for the target= method, since it +contains the information required to map from a phandle to a tree location. diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index fbe8f8d418f7..18b2e2539f84 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -84,4 +84,11 @@ config OF_RESERVED_MEM config OF_RESOLVE bool +config OF_OVERLAY + bool + depends on OF + select OF_DYNAMIC + select OF_DEVICE + select OF_RESOLVE + endmenu # OF diff --git a/drivers/of/Makefile b/drivers/of/Makefile index d90553fcd37f..7563f36c71db 100644 --- a/drivers/of/Makefile +++ b/drivers/of/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o obj-$(CONFIG_OF_MTD) += of_mtd.o obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o obj-$(CONFIG_OF_RESOLVE) += resolver.o +obj-$(CONFIG_OF_OVERLAY) += overlay.o CFLAGS_fdt.o = -I$(src)/../../scripts/dtc/libfdt CFLAGS_fdt_address.o = -I$(src)/../../scripts/dtc/libfdt diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c new file mode 100644 index 000000000000..ea63fbd228ed --- /dev/null +++ b/drivers/of/overlay.c @@ -0,0 +1,562 @@ +/* + * Functions for working with device tree overlays + * + * Copyright (C) 2012 Pantelis Antoniou + * Copyright (C) 2012 Texas Instruments Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ +#undef DEBUG +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "of_private.h" + +/** + * struct of_overlay_info - Holds a single overlay info + * @target: target of the overlay operation + * @overlay: pointer to the overlay contents node + * + * Holds a single overlay state, including all the overlay logs & + * records. + */ +struct of_overlay_info { + struct device_node *target; + struct device_node *overlay; +}; + +/** + * struct of_overlay - Holds a complete overlay transaction + * @node: List on which we are located + * @count: Count of ovinfo structures + * @ovinfo_tab: Overlay info table (count sized) + * @cset: Changeset to be used + * + * Holds a complete overlay transaction + */ +struct of_overlay { + int id; + struct list_head node; + int count; + struct of_overlay_info *ovinfo_tab; + struct of_changeset cset; +}; + +static int of_overlay_apply_one(struct of_overlay *ov, + struct device_node *target, const struct device_node *overlay); + +static int of_overlay_apply_single_property(struct of_overlay *ov, + struct device_node *target, struct property *prop) +{ + struct property *propn, *tprop; + + /* NOTE: Multiple changes of single properties not supported */ + tprop = of_find_property(target, prop->name, NULL); + + /* special properties are not meant to be updated (silent NOP) */ + if (of_prop_cmp(prop->name, "name") == 0 || + of_prop_cmp(prop->name, "phandle") == 0 || + of_prop_cmp(prop->name, "linux,phandle") == 0) + return 0; + + propn = __of_prop_dup(prop, GFP_KERNEL); + if (propn == NULL) + return -ENOMEM; + + /* not found? add */ + if (tprop == NULL) + return of_changeset_add_property(&ov->cset, target, propn); + + /* found? update */ + return of_changeset_update_property(&ov->cset, target, propn); +} + +static int of_overlay_apply_single_device_node(struct of_overlay *ov, + struct device_node *target, struct device_node *child) +{ + const char *cname; + struct device_node *tchild, *grandchild; + int ret = 0; + + cname = kbasename(child->full_name); + if (cname == NULL) + return -ENOMEM; + + /* NOTE: Multiple mods of created nodes not supported */ + tchild = of_get_child_by_name(target, cname); + if (tchild != NULL) { + /* apply overlay recursively */ + ret = of_overlay_apply_one(ov, tchild, child); + of_node_put(tchild); + } else { + /* create empty tree as a target */ + tchild = __of_node_dup(child, "%s/%s", target->full_name, cname); + if (!tchild) + return -ENOMEM; + + /* point to parent */ + tchild->parent = target; + + ret = of_changeset_attach_node(&ov->cset, tchild); + if (ret) + return ret; + + ret = of_overlay_apply_one(ov, tchild, child); + if (ret) + return ret; + + /* The properties are already copied, now do the child nodes */ + for_each_child_of_node(child, grandchild) { + ret = of_overlay_apply_single_device_node(ov, tchild, grandchild); + if (ret) { + pr_err("%s: Failed to apply single node @%s/%s\n", + __func__, tchild->full_name, + grandchild->name); + return ret; + } + } + } + + return ret; +} + +/* + * Apply a single overlay node recursively. + * + * Note that the in case of an error the target node is left + * in a inconsistent state. Error recovery should be performed + * by using the changeset. + */ +static int of_overlay_apply_one(struct of_overlay *ov, + struct device_node *target, const struct device_node *overlay) +{ + struct device_node *child; + struct property *prop; + int ret; + + for_each_property_of_node(overlay, prop) { + ret = of_overlay_apply_single_property(ov, target, prop); + if (ret) { + pr_err("%s: Failed to apply prop @%s/%s\n", + __func__, target->full_name, prop->name); + return ret; + } + } + + for_each_child_of_node(overlay, child) { + ret = of_overlay_apply_single_device_node(ov, target, child); + if (ret != 0) { + pr_err("%s: Failed to apply single node @%s/%s\n", + __func__, target->full_name, + child->name); + return ret; + } + } + + return 0; +} + +/** + * of_overlay_apply() - Apply @count overlays pointed at by @ovinfo_tab + * @ov: Overlay to apply + * + * Applies the overlays given, while handling all error conditions + * appropriately. Either the operation succeeds, or if it fails the + * live tree is reverted to the state before the attempt. + * Returns 0, or an error if the overlay attempt failed. + */ +static int of_overlay_apply(struct of_overlay *ov) +{ + int i, err; + + /* first we apply the overlays atomically */ + for (i = 0; i < ov->count; i++) { + struct of_overlay_info *ovinfo = &ov->ovinfo_tab[i]; + + err = of_overlay_apply_one(ov, ovinfo->target, ovinfo->overlay); + if (err != 0) { + pr_err("%s: overlay failed '%s'\n", + __func__, ovinfo->target->full_name); + return err; + } + } + + return 0; +} + +/* + * Find the target node using a number of different strategies + * in order of preference + * + * "target" property containing the phandle of the target + * "target-path" property containing the path of the target + */ +static struct device_node *find_target_node(struct device_node *info_node) +{ + const char *path; + u32 val; + int ret; + + /* first try to go by using the target as a phandle */ + ret = of_property_read_u32(info_node, "target", &val); + if (ret == 0) + return of_find_node_by_phandle(val); + + /* now try to locate by path */ + ret = of_property_read_string(info_node, "target-path", &path); + if (ret == 0) + return of_find_node_by_path(path); + + pr_err("%s: Failed to find target for node %p (%s)\n", __func__, + info_node, info_node->name); + + return NULL; +} + +/** + * of_fill_overlay_info() - Fill an overlay info structure + * @ov Overlay to fill + * @info_node: Device node containing the overlay + * @ovinfo: Pointer to the overlay info structure to fill + * + * Fills an overlay info structure with the overlay information + * from a device node. This device node must have a target property + * which contains a phandle of the overlay target node, and an + * __overlay__ child node which has the overlay contents. + * Both ovinfo->target & ovinfo->overlay have their references taken. + * + * Returns 0 on success, or a negative error value. + */ +static int of_fill_overlay_info(struct of_overlay *ov, + struct device_node *info_node, struct of_overlay_info *ovinfo) +{ + ovinfo->overlay = of_get_child_by_name(info_node, "__overlay__"); + if (ovinfo->overlay == NULL) + goto err_fail; + + ovinfo->target = find_target_node(info_node); + if (ovinfo->target == NULL) + goto err_fail; + + return 0; + +err_fail: + of_node_put(ovinfo->target); + of_node_put(ovinfo->overlay); + + memset(ovinfo, 0, sizeof(*ovinfo)); + return -EINVAL; +} + +/** + * of_build_overlay_info() - Build an overlay info array + * @ov Overlay to build + * @tree: Device node containing all the overlays + * + * Helper function that given a tree containing overlay information, + * allocates and builds an overlay info array containing it, ready + * for use using of_overlay_apply. + * + * Returns 0 on success with the @cntp @ovinfop pointers valid, + * while on error a negative error value is returned. + */ +static int of_build_overlay_info(struct of_overlay *ov, + struct device_node *tree) +{ + struct device_node *node; + struct of_overlay_info *ovinfo; + int cnt, err; + + /* worst case; every child is a node */ + cnt = 0; + for_each_child_of_node(tree, node) + cnt++; + + ovinfo = kcalloc(cnt, sizeof(*ovinfo), GFP_KERNEL); + if (ovinfo == NULL) + return -ENOMEM; + + cnt = 0; + for_each_child_of_node(tree, node) { + memset(&ovinfo[cnt], 0, sizeof(*ovinfo)); + err = of_fill_overlay_info(ov, node, &ovinfo[cnt]); + if (err == 0) + cnt++; + } + + /* if nothing filled, return error */ + if (cnt == 0) { + kfree(ovinfo); + return -ENODEV; + } + + ov->count = cnt; + ov->ovinfo_tab = ovinfo; + + return 0; +} + +/** + * of_free_overlay_info() - Free an overlay info array + * @ov Overlay to free the overlay info from + * @ovinfo_tab: Array of overlay_info's to free + * + * Releases the memory of a previously allocated ovinfo array + * by of_build_overlay_info. + * Returns 0, or an error if the arguments are bogus. + */ +static int of_free_overlay_info(struct of_overlay *ov) +{ + struct of_overlay_info *ovinfo; + int i; + + /* do it in reverse */ + for (i = ov->count - 1; i >= 0; i--) { + ovinfo = &ov->ovinfo_tab[i]; + + of_node_put(ovinfo->target); + of_node_put(ovinfo->overlay); + } + kfree(ov->ovinfo_tab); + + return 0; +} + +static LIST_HEAD(ov_list); +static DEFINE_IDR(ov_idr); + +/** + * of_overlay_create() - Create and apply an overlay + * @tree: Device node containing all the overlays + * + * Creates and applies an overlay while also keeping track + * of the overlay in a list. This list can be used to prevent + * illegal overlay removals. + * + * Returns the id of the created overlay, or an negative error number + */ +int of_overlay_create(struct device_node *tree) +{ + struct of_overlay *ov; + int err, id; + + /* allocate the overlay structure */ + ov = kzalloc(sizeof(*ov), GFP_KERNEL); + if (ov == NULL) + return -ENOMEM; + ov->id = -1; + + INIT_LIST_HEAD(&ov->node); + + of_changeset_init(&ov->cset); + + mutex_lock(&of_mutex); + + id = idr_alloc(&ov_idr, ov, 0, 0, GFP_KERNEL); + if (id < 0) { + pr_err("%s: idr_alloc() failed for tree@%s\n", + __func__, tree->full_name); + err = id; + goto err_destroy_trans; + } + ov->id = id; + + /* build the overlay info structures */ + err = of_build_overlay_info(ov, tree); + if (err) { + pr_err("%s: of_build_overlay_info() failed for tree@%s\n", + __func__, tree->full_name); + goto err_free_idr; + } + + /* apply the overlay */ + err = of_overlay_apply(ov); + if (err) { + pr_err("%s: of_overlay_apply() failed for tree@%s\n", + __func__, tree->full_name); + goto err_abort_trans; + } + + /* apply the changeset */ + err = of_changeset_apply(&ov->cset); + if (err) { + pr_err("%s: of_changeset_apply() failed for tree@%s\n", + __func__, tree->full_name); + goto err_revert_overlay; + } + + /* add to the tail of the overlay list */ + list_add_tail(&ov->node, &ov_list); + + mutex_unlock(&of_mutex); + + return id; + +err_revert_overlay: +err_abort_trans: + of_free_overlay_info(ov); +err_free_idr: + idr_remove(&ov_idr, ov->id); +err_destroy_trans: + of_changeset_destroy(&ov->cset); + kfree(ov); + mutex_unlock(&of_mutex); + + return err; +} +EXPORT_SYMBOL_GPL(of_overlay_create); + +/* check whether the given node, lies under the given tree */ +static int overlay_subtree_check(struct device_node *tree, + struct device_node *dn) +{ + struct device_node *child; + + /* match? */ + if (tree == dn) + return 1; + + for_each_child_of_node(tree, child) { + if (overlay_subtree_check(child, dn)) + return 1; + } + + return 0; +} + +/* check whether this overlay is the topmost */ +static int overlay_is_topmost(struct of_overlay *ov, struct device_node *dn) +{ + struct of_overlay *ovt; + struct of_changeset_entry *ce; + + list_for_each_entry_reverse(ovt, &ov_list, node) { + /* if we hit ourselves, we're done */ + if (ovt == ov) + break; + + /* check against each subtree affected by this overlay */ + list_for_each_entry(ce, &ovt->cset.entries, node) { + if (overlay_subtree_check(ce->np, dn)) { + pr_err("%s: #%d clashes #%d @%s\n", + __func__, ov->id, ovt->id, + dn->full_name); + return 0; + } + } + } + + /* overlay is topmost */ + return 1; +} + +/* + * We can safely remove the overlay only if it's the top-most one. + * Newly applied overlays are inserted at the tail of the overlay list, + * so a top most overlay is the one that is closest to the tail. + * + * The topmost check is done by exploiting this property. For each + * affected device node in the log list we check if this overlay is + * the one closest to the tail. If another overlay has affected this + * device node and is closest to the tail, then removal is not permited. + */ +static int overlay_removal_is_ok(struct of_overlay *ov) +{ + struct of_changeset_entry *ce; + + list_for_each_entry(ce, &ov->cset.entries, node) { + if (!overlay_is_topmost(ov, ce->np)) { + pr_err("%s: overlay #%d is not topmost\n", + __func__, ov->id); + return 0; + } + } + + return 1; +} + +/** + * of_overlay_destroy() - Removes an overlay + * @id: Overlay id number returned by a previous call to of_overlay_create + * + * Removes an overlay if it is permissible. + * + * Returns 0 on success, or an negative error number + */ +int of_overlay_destroy(int id) +{ + struct of_overlay *ov; + int err; + + mutex_lock(&of_mutex); + + ov = idr_find(&ov_idr, id); + if (ov == NULL) { + err = -ENODEV; + pr_err("%s: Could not find overlay #%d\n", + __func__, id); + goto out; + } + + /* check whether the overlay is safe to remove */ + if (!overlay_removal_is_ok(ov)) { + err = -EBUSY; + pr_err("%s: removal check failed for overlay #%d\n", + __func__, id); + goto out; + } + + + list_del(&ov->node); + of_changeset_revert(&ov->cset); + of_free_overlay_info(ov); + idr_remove(&ov_idr, id); + of_changeset_destroy(&ov->cset); + kfree(ov); + + err = 0; + +out: + mutex_unlock(&of_mutex); + + return err; +} +EXPORT_SYMBOL_GPL(of_overlay_destroy); + +/** + * of_overlay_destroy_all() - Removes all overlays from the system + * + * Removes all overlays from the system in the correct order. + * + * Returns 0 on success, or an negative error number + */ +int of_overlay_destroy_all(void) +{ + struct of_overlay *ov, *ovn; + + mutex_lock(&of_mutex); + + /* the tail of list is guaranteed to be safe to remove */ + list_for_each_entry_safe_reverse(ov, ovn, &ov_list, node) { + list_del(&ov->node); + of_changeset_revert(&ov->cset); + of_free_overlay_info(ov); + idr_remove(&ov_idr, ov->id); + kfree(ov); + } + + mutex_unlock(&of_mutex); + + return 0; +} +EXPORT_SYMBOL_GPL(of_overlay_destroy_all); diff --git a/include/linux/of.h b/include/linux/of.h index fe1dec87fd68..aa01cf5852f8 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -957,4 +958,34 @@ static inline int of_reconfig_get_state_change(unsigned long action, /* CONFIG_OF_RESOLVE api */ extern int of_resolve_phandles(struct device_node *tree); +/** + * Overlay support + */ + +#ifdef CONFIG_OF_OVERLAY + +/* ID based overlays; the API for external users */ +int of_overlay_create(struct device_node *tree); +int of_overlay_destroy(int id); +int of_overlay_destroy_all(void); + +#else + +static inline int of_overlay_create(struct device_node *tree) +{ + return -ENOTSUPP; +} + +static inline int of_overlay_destroy(int id) +{ + return -ENOTSUPP; +} + +static inline int of_overlay_destroy_all(void) +{ + return -ENOTSUPP; +} + +#endif + #endif /* _LINUX_OF_H */ -- cgit v1.2.3-59-g8ed1b From 177d271cf3171bb6826ee5189f67dc1f7d34f1da Mon Sep 17 00:00:00 2001 From: Pantelis Antoniou Date: Tue, 28 Oct 2014 22:35:59 +0200 Subject: of/overlay: Add overlay unittests Add unittests for OF overlays. It tests overlay device addition/removal and whether the apply revert sequence is correct. Changes since V1: * Added local fixups entries. Signed-off-by: Pantelis Antoniou Signed-off-by: Grant Likely --- Documentation/devicetree/bindings/unittest.txt | 14 + drivers/of/unittest-data/testcases.dts | 16 + drivers/of/unittest-data/tests-overlay.dtsi | 180 +++++++++ drivers/of/unittest.c | 481 +++++++++++++++++++++++++ 4 files changed, 691 insertions(+) create mode 100644 Documentation/devicetree/bindings/unittest.txt create mode 100644 drivers/of/unittest-data/tests-overlay.dtsi (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/unittest.txt b/Documentation/devicetree/bindings/unittest.txt new file mode 100644 index 000000000000..0f92a22fddfa --- /dev/null +++ b/Documentation/devicetree/bindings/unittest.txt @@ -0,0 +1,14 @@ +* OF selftest platform device + +** selftest + +Required properties: +- compatible: must be "selftest" + +All other properties are optional. + +Example: + selftest { + compatible = "selftest"; + status = "okay"; + }; diff --git a/drivers/of/unittest-data/testcases.dts b/drivers/of/unittest-data/testcases.dts index b6bc41b2a185..12f7c3d649c8 100644 --- a/drivers/of/unittest-data/testcases.dts +++ b/drivers/of/unittest-data/testcases.dts @@ -13,6 +13,7 @@ #include "tests-interrupts.dtsi" #include "tests-match.dtsi" #include "tests-platform.dtsi" +#include "tests-overlay.dtsi" /* * phandle fixup data - generated by dtc patches that aren't upstream. @@ -59,5 +60,20 @@ testcase-device2 { interrupt-parent = <0x00000000>; }; + overlay2 { + fragment@0 { + target = <0x00000000>; + }; + }; + overlay3 { + fragment@0 { + target = <0x00000000>; + }; + }; + overlay4 { + fragment@0 { + target = <0x00000000>; + }; + }; }; }; }; diff --git a/drivers/of/unittest-data/tests-overlay.dtsi b/drivers/of/unittest-data/tests-overlay.dtsi new file mode 100644 index 000000000000..75976da22b2e --- /dev/null +++ b/drivers/of/unittest-data/tests-overlay.dtsi @@ -0,0 +1,180 @@ + +/ { + testcase-data { + overlay-node { + + /* test bus */ + selftestbus: test-bus { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + selftest100: test-selftest100 { + compatible = "selftest"; + status = "okay"; + reg = <100>; + }; + + selftest101: test-selftest101 { + compatible = "selftest"; + status = "disabled"; + reg = <101>; + }; + + selftest0: test-selftest0 { + compatible = "selftest"; + status = "disabled"; + reg = <0>; + }; + + selftest1: test-selftest1 { + compatible = "selftest"; + status = "okay"; + reg = <1>; + }; + + selftest2: test-selftest2 { + compatible = "selftest"; + status = "disabled"; + reg = <2>; + }; + + selftest3: test-selftest3 { + compatible = "selftest"; + status = "okay"; + reg = <3>; + }; + + selftest5: test-selftest5 { + compatible = "selftest"; + status = "disabled"; + reg = <5>; + }; + + selftest6: test-selftest6 { + compatible = "selftest"; + status = "disabled"; + reg = <6>; + }; + + selftest7: test-selftest7 { + compatible = "selftest"; + status = "disabled"; + reg = <7>; + }; + + selftest8: test-selftest8 { + compatible = "selftest"; + status = "disabled"; + reg = <8>; + }; + }; + }; + + /* test enable using absolute target path */ + overlay0 { + fragment@0 { + target-path = "/testcase-data/overlay-node/test-bus/test-selftest0"; + __overlay__ { + status = "okay"; + }; + }; + }; + + /* test disable using absolute target path */ + overlay1 { + fragment@0 { + target-path = "/testcase-data/overlay-node/test-bus/test-selftest1"; + __overlay__ { + status = "disabled"; + }; + }; + }; + + /* test enable using label */ + overlay2 { + fragment@0 { + target = <&selftest2>; + __overlay__ { + status = "okay"; + }; + }; + }; + + /* test disable using label */ + overlay3 { + fragment@0 { + target = <&selftest3>; + __overlay__ { + status = "disabled"; + }; + }; + }; + + /* test insertion of a full node */ + overlay4 { + fragment@0 { + target = <&selftestbus>; + __overlay__ { + + /* suppress DTC warning */ + #address-cells = <1>; + #size-cells = <0>; + + test-selftest4 { + compatible = "selftest"; + status = "okay"; + reg = <4>; + }; + }; + }; + }; + + /* test overlay apply revert */ + overlay5 { + fragment@0 { + target-path = "/testcase-data/overlay-node/test-bus/test-selftest5"; + __overlay__ { + status = "okay"; + }; + }; + }; + + /* test overlays application and removal in sequence */ + overlay6 { + fragment@0 { + target-path = "/testcase-data/overlay-node/test-bus/test-selftest6"; + __overlay__ { + status = "okay"; + }; + }; + }; + overlay7 { + fragment@0 { + target-path = "/testcase-data/overlay-node/test-bus/test-selftest7"; + __overlay__ { + status = "okay"; + }; + }; + }; + + /* test overlays application and removal in bad sequence */ + overlay8 { + fragment@0 { + target-path = "/testcase-data/overlay-node/test-bus/test-selftest8"; + __overlay__ { + status = "okay"; + }; + }; + }; + overlay9 { + fragment@0 { + target-path = "/testcase-data/overlay-node/test-bus/test-selftest8"; + __overlay__ { + property-foo = "bar"; + }; + }; + }; + + }; +}; diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c index 1720b039cac7..cc0c5ec5d464 100644 --- a/drivers/of/unittest.c +++ b/drivers/of/unittest.c @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include "of_private.h" @@ -933,6 +935,484 @@ static void selftest_data_remove(void) } } +#ifdef CONFIG_OF_OVERLAY + +static int selftest_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + + if (np == NULL) { + dev_err(dev, "No OF data for device\n"); + return -EINVAL; + + } + + dev_dbg(dev, "%s for node @%s\n", __func__, np->full_name); + return 0; +} + +static int selftest_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + + dev_dbg(dev, "%s for node @%s\n", __func__, np->full_name); + return 0; +} + +static struct of_device_id selftest_match[] = { + { .compatible = "selftest", }, + {}, +}; +MODULE_DEVICE_TABLE(of, altera_jtaguart_match); + +static struct platform_driver selftest_driver = { + .probe = selftest_probe, + .remove = selftest_remove, + .driver = { + .name = "selftest", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(selftest_match), + }, +}; + +/* get the platform device instantiated at the path */ +static struct platform_device *of_path_to_platform_device(const char *path) +{ + struct device_node *np; + struct platform_device *pdev; + + np = of_find_node_by_path(path); + if (np == NULL) + return NULL; + + pdev = of_find_device_by_node(np); + of_node_put(np); + + return pdev; +} + +/* find out if a platform device exists at that path */ +static int of_path_platform_device_exists(const char *path) +{ + struct platform_device *pdev; + + pdev = of_path_to_platform_device(path); + platform_device_put(pdev); + return pdev != NULL; +} + +static const char *selftest_path(int nr) +{ + static char buf[256]; + + snprintf(buf, sizeof(buf) - 1, + "/testcase-data/overlay-node/test-bus/test-selftest%d", nr); + buf[sizeof(buf) - 1] = '\0'; + + return buf; +} + +static const char *overlay_path(int nr) +{ + static char buf[256]; + + snprintf(buf, sizeof(buf) - 1, + "/testcase-data/overlay%d", nr); + buf[sizeof(buf) - 1] = '\0'; + + return buf; +} + +static const char *bus_path = "/testcase-data/overlay-node/test-bus"; + +static int of_selftest_apply_overlay(int selftest_nr, int overlay_nr, + int *overlay_id) +{ + struct device_node *np = NULL; + int ret, id = -1; + + np = of_find_node_by_path(overlay_path(overlay_nr)); + if (np == NULL) { + selftest(0, "could not find overlay node @\"%s\"\n", + overlay_path(overlay_nr)); + ret = -EINVAL; + goto out; + } + + ret = of_overlay_create(np); + if (ret < 0) { + selftest(0, "could not create overlay from \"%s\"\n", + overlay_path(overlay_nr)); + goto out; + } + id = ret; + + ret = 0; + +out: + of_node_put(np); + + if (overlay_id) + *overlay_id = id; + + return ret; +} + +/* apply an overlay while checking before and after states */ +static int of_selftest_apply_overlay_check(int overlay_nr, int selftest_nr, + int before, int after) +{ + int ret; + + /* selftest device must not be in before state */ + if (of_path_platform_device_exists(selftest_path(selftest_nr)) + != before) { + selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n", + overlay_path(overlay_nr), + selftest_path(selftest_nr), + !before ? "enabled" : "disabled"); + return -EINVAL; + } + + ret = of_selftest_apply_overlay(overlay_nr, selftest_nr, NULL); + if (ret != 0) { + /* of_selftest_apply_overlay already called selftest() */ + return ret; + } + + /* selftest device must be to set to after state */ + if (of_path_platform_device_exists(selftest_path(selftest_nr)) + != after) { + selftest(0, "overlay @\"%s\" failed to create @\"%s\" %s\n", + overlay_path(overlay_nr), + selftest_path(selftest_nr), + !after ? "enabled" : "disabled"); + return -EINVAL; + } + + return 0; +} + +/* apply an overlay and then revert it while checking before, after states */ +static int of_selftest_apply_revert_overlay_check(int overlay_nr, + int selftest_nr, int before, int after) +{ + int ret, ov_id; + + /* selftest device must be in before state */ + if (of_path_platform_device_exists(selftest_path(selftest_nr)) + != before) { + selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n", + overlay_path(overlay_nr), + selftest_path(selftest_nr), + !before ? "enabled" : "disabled"); + return -EINVAL; + } + + /* apply the overlay */ + ret = of_selftest_apply_overlay(overlay_nr, selftest_nr, &ov_id); + if (ret != 0) { + /* of_selftest_apply_overlay already called selftest() */ + return ret; + } + + /* selftest device must be in after state */ + if (of_path_platform_device_exists(selftest_path(selftest_nr)) + != after) { + selftest(0, "overlay @\"%s\" failed to create @\"%s\" %s\n", + overlay_path(overlay_nr), + selftest_path(selftest_nr), + !after ? "enabled" : "disabled"); + return -EINVAL; + } + + ret = of_overlay_destroy(ov_id); + if (ret != 0) { + selftest(0, "overlay @\"%s\" failed to be destroyed @\"%s\"\n", + overlay_path(overlay_nr), + selftest_path(selftest_nr)); + return ret; + } + + /* selftest device must be again in before state */ + if (of_path_platform_device_exists(selftest_path(selftest_nr)) + != before) { + selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n", + overlay_path(overlay_nr), + selftest_path(selftest_nr), + !before ? "enabled" : "disabled"); + return -EINVAL; + } + + return 0; +} + +/* test activation of device */ +static void of_selftest_overlay_0(void) +{ + int ret; + + /* device should enable */ + ret = of_selftest_apply_overlay_check(0, 0, 0, 1); + if (ret != 0) + return; + + selftest(1, "overlay test %d passed\n", 0); +} + +/* test deactivation of device */ +static void of_selftest_overlay_1(void) +{ + int ret; + + /* device should disable */ + ret = of_selftest_apply_overlay_check(1, 1, 1, 0); + if (ret != 0) + return; + + selftest(1, "overlay test %d passed\n", 1); +} + +/* test activation of device */ +static void of_selftest_overlay_2(void) +{ + int ret; + + /* device should enable */ + ret = of_selftest_apply_overlay_check(2, 2, 0, 1); + if (ret != 0) + return; + + selftest(1, "overlay test %d passed\n", 2); +} + +/* test deactivation of device */ +static void of_selftest_overlay_3(void) +{ + int ret; + + /* device should disable */ + ret = of_selftest_apply_overlay_check(3, 3, 1, 0); + if (ret != 0) + return; + + selftest(1, "overlay test %d passed\n", 3); +} + +/* test activation of a full device node */ +static void of_selftest_overlay_4(void) +{ + int ret; + + /* device should disable */ + ret = of_selftest_apply_overlay_check(4, 4, 0, 1); + if (ret != 0) + return; + + selftest(1, "overlay test %d passed\n", 4); +} + +/* test overlay apply/revert sequence */ +static void of_selftest_overlay_5(void) +{ + int ret; + + /* device should disable */ + ret = of_selftest_apply_revert_overlay_check(5, 5, 0, 1); + if (ret != 0) + return; + + selftest(1, "overlay test %d passed\n", 5); +} + +/* test overlay application in sequence */ +static void of_selftest_overlay_6(void) +{ + struct device_node *np; + int ret, i, ov_id[2]; + int overlay_nr = 6, selftest_nr = 6; + int before = 0, after = 1; + + /* selftest device must be in before state */ + for (i = 0; i < 2; i++) { + if (of_path_platform_device_exists( + selftest_path(selftest_nr + i)) + != before) { + selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n", + overlay_path(overlay_nr + i), + selftest_path(selftest_nr + i), + !before ? "enabled" : "disabled"); + return; + } + } + + /* apply the overlays */ + for (i = 0; i < 2; i++) { + + np = of_find_node_by_path(overlay_path(overlay_nr + i)); + if (np == NULL) { + selftest(0, "could not find overlay node @\"%s\"\n", + overlay_path(overlay_nr + i)); + return; + } + + ret = of_overlay_create(np); + if (ret < 0) { + selftest(0, "could not create overlay from \"%s\"\n", + overlay_path(overlay_nr + i)); + return; + } + ov_id[i] = ret; + } + + for (i = 0; i < 2; i++) { + /* selftest device must be in after state */ + if (of_path_platform_device_exists( + selftest_path(selftest_nr + i)) + != after) { + selftest(0, "overlay @\"%s\" failed @\"%s\" %s\n", + overlay_path(overlay_nr + i), + selftest_path(selftest_nr + i), + !after ? "enabled" : "disabled"); + return; + } + } + + for (i = 1; i >= 0; i--) { + ret = of_overlay_destroy(ov_id[i]); + if (ret != 0) { + selftest(0, "overlay @\"%s\" failed destroy @\"%s\"\n", + overlay_path(overlay_nr + i), + selftest_path(selftest_nr + i)); + return; + } + } + + for (i = 0; i < 2; i++) { + /* selftest device must be again in before state */ + if (of_path_platform_device_exists( + selftest_path(selftest_nr + i)) + != before) { + selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n", + overlay_path(overlay_nr + i), + selftest_path(selftest_nr + i), + !before ? "enabled" : "disabled"); + return; + } + } + + selftest(1, "overlay test %d passed\n", 6); +} + +/* test overlay application in sequence */ +static void of_selftest_overlay_8(void) +{ + struct device_node *np; + int ret, i, ov_id[2]; + int overlay_nr = 8, selftest_nr = 8; + + /* we don't care about device state in this test */ + + /* apply the overlays */ + for (i = 0; i < 2; i++) { + + np = of_find_node_by_path(overlay_path(overlay_nr + i)); + if (np == NULL) { + selftest(0, "could not find overlay node @\"%s\"\n", + overlay_path(overlay_nr + i)); + return; + } + + ret = of_overlay_create(np); + if (ret < 0) { + selftest(0, "could not create overlay from \"%s\"\n", + overlay_path(overlay_nr + i)); + return; + } + ov_id[i] = ret; + } + + /* now try to remove first overlay (it should fail) */ + ret = of_overlay_destroy(ov_id[0]); + if (ret == 0) { + selftest(0, "overlay @\"%s\" was destroyed @\"%s\"\n", + overlay_path(overlay_nr + 0), + selftest_path(selftest_nr)); + return; + } + + /* removing them in order should work */ + for (i = 1; i >= 0; i--) { + ret = of_overlay_destroy(ov_id[i]); + if (ret != 0) { + selftest(0, "overlay @\"%s\" not destroyed @\"%s\"\n", + overlay_path(overlay_nr + i), + selftest_path(selftest_nr)); + return; + } + } + + selftest(1, "overlay test %d passed\n", 8); +} + +static void __init of_selftest_overlay(void) +{ + struct device_node *bus_np = NULL; + int ret; + + ret = platform_driver_register(&selftest_driver); + if (ret != 0) { + selftest(0, "could not register selftest driver\n"); + goto out; + } + + bus_np = of_find_node_by_path(bus_path); + if (bus_np == NULL) { + selftest(0, "could not find bus_path \"%s\"\n", bus_path); + goto out; + } + + ret = of_platform_populate(bus_np, of_default_bus_match_table, + NULL, NULL); + if (ret != 0) { + selftest(0, "could not populate bus @ \"%s\"\n", bus_path); + goto out; + } + + if (!of_path_platform_device_exists(selftest_path(100))) { + selftest(0, "could not find selftest0 @ \"%s\"\n", + selftest_path(100)); + goto out; + } + + if (of_path_platform_device_exists(selftest_path(101))) { + selftest(0, "selftest1 @ \"%s\" should not exist\n", + selftest_path(101)); + goto out; + } + + selftest(1, "basic infrastructure of overlays passed"); + + /* tests in sequence */ + of_selftest_overlay_0(); + of_selftest_overlay_1(); + of_selftest_overlay_2(); + of_selftest_overlay_3(); + of_selftest_overlay_4(); + of_selftest_overlay_5(); + of_selftest_overlay_6(); + of_selftest_overlay_8(); + +out: + of_node_put(bus_np); +} + +#else +static inline void __init of_selftest_overlay(void) { } +#endif + static int __init of_selftest(void) { struct device_node *np; @@ -965,6 +1445,7 @@ static int __init of_selftest(void) of_selftest_parse_interrupts_extended(); of_selftest_match_node(); of_selftest_platform_populate(); + of_selftest_overlay(); /* removing selftest data from live tree */ selftest_data_remove(); -- cgit v1.2.3-59-g8ed1b From 84021c90771b4582883900d19a52cdde1f453802 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Mon, 24 Nov 2014 23:24:42 +0100 Subject: wd719x: Add firmware documentation Add documentation and script to obtain required firmware. Signed-off-by: Ondrej Zary Reviewed-by: Hannes Reinecke Signed-off-by: Christoph Hellwig --- Documentation/scsi/wd719x.txt | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 Documentation/scsi/wd719x.txt (limited to 'Documentation') diff --git a/Documentation/scsi/wd719x.txt b/Documentation/scsi/wd719x.txt new file mode 100644 index 000000000000..0816b0220238 --- /dev/null +++ b/Documentation/scsi/wd719x.txt @@ -0,0 +1,21 @@ +Driver for Western Digital WD7193, WD7197 and WD7296 SCSI cards +--------------------------------------------------------------- + +The card requires firmware that can be cut out of the Windows NT driver that +can be downloaded from WD at: +http://support.wdc.com/product/download.asp?groupid=801&sid=27&lang=en + +There is no license anywhere in the file or on the page - so the firmware +probably cannot be added to linux-firmware. + +This script downloads and extracts the firmware, creating wd719x-risc.bin and +d719x-wcs.bin files. Put them in /lib/firmware/. + +#!/bin/sh +wget http://support.wdc.com/download/archive/pciscsi.exe +lha xi pciscsi.exe pci-scsi.exe +lha xi pci-scsi.exe nt/wd7296a.sys +rm pci-scsi.exe +dd if=wd7296a.sys of=wd719x-risc.bin bs=1 skip=5760 count=14336 +dd if=wd7296a.sys of=wd719x-wcs.bin bs=1 skip=20096 count=514 +rm wd7296a.sys -- cgit v1.2.3-59-g8ed1b From 159a5e920446aed12fe373ecc3c7b3dc667091ae Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Tue, 18 Nov 2014 17:59:43 +0900 Subject: mfd: s2mps11: Add binding documentation for Samsung S2MPS13 PMIC This patch adds the binding documentation for Samsung S2MPS13 PMIC which is similiar with existing S2MPS14 PMIC. S2MPS13 has the different number of regulators from S2MPS14 and RTC/Clock is the same with the S2MPS14. Signed-off-by: Chanwoo Choi Acked-by: Sangbeom Kim Reviewed-by: Krzysztof Kozlowski Signed-off-by: Lee Jones --- Documentation/devicetree/bindings/mfd/s2mps11.txt | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mfd/s2mps11.txt b/Documentation/devicetree/bindings/mfd/s2mps11.txt index 0e4026a6cbbf..57a045016fca 100644 --- a/Documentation/devicetree/bindings/mfd/s2mps11.txt +++ b/Documentation/devicetree/bindings/mfd/s2mps11.txt @@ -1,5 +1,5 @@ -* Samsung S2MPS11, S2MPS14 and S2MPU02 Voltage and Current Regulator +* Samsung S2MPS11, S2MPS13, S2MPS14 and S2MPU02 Voltage and Current Regulator The Samsung S2MPS11 is a multi-function device which includes voltage and current regulators, RTC, charger controller and other sub-blocks. It is @@ -7,8 +7,8 @@ interfaced to the host controller using an I2C interface. Each sub-block is addressed by the host system using different I2C slave addresses. Required properties: -- compatible: Should be "samsung,s2mps11-pmic" or "samsung,s2mps14-pmic" - or "samsung,s2mpu02-pmic". +- compatible: Should be "samsung,s2mps11-pmic" or "samsung,s2mps13-pmic" + or "samsung,s2mps14-pmic" or "samsung,s2mpu02-pmic". - reg: Specifies the I2C slave address of the pmic block. It should be 0x66. Optional properties: @@ -17,8 +17,8 @@ Optional properties: - interrupts: Interrupt specifiers for interrupt sources. Optional nodes: -- clocks: s2mps11 and s5m8767 provide three(AP/CP/BT) buffered 32.768 KHz - outputs, so to register these as clocks with common clock framework +- clocks: s2mps11, s2mps13 and s5m8767 provide three(AP/CP/BT) buffered 32.768 + KHz outputs, so to register these as clocks with common clock framework instantiate a sub-node named "clocks". It uses the common clock binding documented in : [Documentation/devicetree/bindings/clock/clock-bindings.txt] @@ -30,12 +30,12 @@ Optional nodes: the clock which they consume. Clock ID Devices ---------------------------------------------------------- - 32KhzAP 0 S2MPS11, S2MPS14, S5M8767 - 32KhzCP 1 S2MPS11, S5M8767 - 32KhzBT 2 S2MPS11, S2MPS14, S5M8767 + 32KhzAP 0 S2MPS11, S2MPS13, S2MPS14, S5M8767 + 32KhzCP 1 S2MPS11, S2MPS13, S5M8767 + 32KhzBT 2 S2MPS11, S2MPS13, S2MPS14, S5M8767 - - compatible: Should be one of: "samsung,s2mps11-clk", "samsung,s2mps14-clk", - "samsung,s5m8767-clk" + - compatible: Should be one of: "samsung,s2mps11-clk", "samsung,s2mps13-clk", + "samsung,s2mps14-clk", "samsung,s5m8767-clk" - regulators: The regulators of s2mps11 that have to be instantiated should be included in a sub-node named 'regulators'. Regulator nodes included in this @@ -81,12 +81,14 @@ as per the datasheet of s2mps11. - LDOn - valid values for n are: - S2MPS11: 1 to 38 + - S2MPS13: 1 to 40 - S2MPS14: 1 to 25 - S2MPU02: 1 to 28 - Example: LDO1, LDO2, LDO28 - BUCKn - valid values for n are: - S2MPS11: 1 to 10 + - S2MPS13: 1 to 10 - S2MPS14: 1 to 5 - S2MPU02: 1 to 7 - Example: BUCK1, BUCK2, BUCK9 -- cgit v1.2.3-59-g8ed1b From ee828d02611f325a70ef6a3c1fd2dd1eb3bc9704 Mon Sep 17 00:00:00 2001 From: Jaewon Kim Date: Thu, 18 Sep 2014 01:40:26 +0900 Subject: mfd: max77693: Update DT binding to support haptic This patch add haptic DT binding documentation and example to support haptic driver in max77693 Multifunction device. Signed-off-by: Jaewon Kim Acked-by: Chanwoo Choi Signed-off-by: Lee Jones --- Documentation/devicetree/bindings/mfd/max77693.txt | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mfd/max77693.txt b/Documentation/devicetree/bindings/mfd/max77693.txt index 11921cc417bf..01e9f30fe678 100644 --- a/Documentation/devicetree/bindings/mfd/max77693.txt +++ b/Documentation/devicetree/bindings/mfd/max77693.txt @@ -27,6 +27,20 @@ Optional properties: [*] refer Documentation/devicetree/bindings/regulator/regulator.txt +- haptic : The MAX77693 haptic device utilises a PWM controlled motor to provide + users with tactile feedback. PWM period and duty-cycle are varied in + order to provide the approprite level of feedback. + + Required properties: + - compatible : Must be "maxim,max77693-hpatic" + - haptic-supply : power supply for the haptic motor + [*] refer Documentation/devicetree/bindings/regulator/regulator.txt + - pwms : phandle to the physical PWM(Pulse Width Modulation) device. + PWM properties should be named "pwms". And number of cell is different + for each pwm device. + To get more informations, please refer to documentaion. + [*] refer Documentation/devicetree/bindings/pwm/pwm.txt + Example: max77693@66 { compatible = "maxim,max77693"; @@ -52,4 +66,11 @@ Example: regulator-boot-on; }; }; + + haptic { + compatible = "maxim,max77693-haptic"; + haptic-supply = <&haptic_supply>; + pwms = <&pwm 0 40000 0>; + pwm-names = "haptic"; + }; }; -- cgit v1.2.3-59-g8ed1b From 590b7795b3dc293a36136a4321ba59da60e5853c Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Mon, 6 Oct 2014 15:48:44 +0200 Subject: mfd: Add documentation for atmel-hlcdc DT bindings The HLCDC IP available on some Atmel SoCs (i.e. at91sam9n12, at91sam9x5 family or sama5d3 family) exposes 2 subdevices: - a display controller (controlled by a DRM driver) - a PWM chip This patch adds documentation for atmel-hlcdc DT bindings. Signed-off-by: Boris Brezillon Tested-by: Anthony Harivel Tested-by: Ludovic Desroches Signed-off-by: Lee Jones --- .../devicetree/bindings/mfd/atmel-hlcdc.txt | 51 ++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt b/Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt new file mode 100644 index 000000000000..f64de95a8e8b --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt @@ -0,0 +1,51 @@ +Device-Tree bindings for Atmel's HLCDC (High LCD Controller) MFD driver + +Required properties: + - compatible: value should be one of the following: + "atmel,sama5d3-hlcdc" + - reg: base address and size of the HLCDC device registers. + - clock-names: the name of the 3 clocks requested by the HLCDC device. + Should contain "periph_clk", "sys_clk" and "slow_clk". + - clocks: should contain the 3 clocks requested by the HLCDC device. + - interrupts: should contain the description of the HLCDC interrupt line + +The HLCDC IP exposes two subdevices: + - a PWM chip: see ../pwm/atmel-hlcdc-pwm.txt + - a Display Controller: see ../drm/atmel-hlcdc-dc.txt + +Example: + + hlcdc: hlcdc@f0030000 { + compatible = "atmel,sama5d3-hlcdc"; + reg = <0xf0030000 0x2000>; + clocks = <&lcdc_clk>, <&lcdck>, <&clk32k>; + clock-names = "periph_clk","sys_clk", "slow_clk"; + interrupts = <36 IRQ_TYPE_LEVEL_HIGH 0>; + status = "disabled"; + + hlcdc-display-controller { + compatible = "atmel,hlcdc-display-controller"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lcd_base &pinctrl_lcd_rgb888>; + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + hlcdc_panel_output: endpoint@0 { + reg = <0>; + remote-endpoint = <&panel_input>; + }; + }; + }; + + hlcdc_pwm: hlcdc-pwm { + compatible = "atmel,hlcdc-pwm"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lcd_pwm>; + #pwm-cells = <3>; + }; + }; -- cgit v1.2.3-59-g8ed1b From 130dd5b039dcbab7bcb2fdce0bb3cc7347b08b29 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 21 Oct 2014 13:23:16 +0200 Subject: mfd/regulator: dt-bindings: max77686: Document regulators off in suspend Add information which regulators can be disabled during system suspend. Suggested-by: Javier Martinez Canillas Signed-off-by: Krzysztof Kozlowski Signed-off-by: Lee Jones --- Documentation/devicetree/bindings/mfd/max77686.txt | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mfd/max77686.txt b/Documentation/devicetree/bindings/mfd/max77686.txt index 678f3cf0b8f0..75fdfaf41831 100644 --- a/Documentation/devicetree/bindings/mfd/max77686.txt +++ b/Documentation/devicetree/bindings/mfd/max77686.txt @@ -34,6 +34,12 @@ to get matched with their hardware counterparts as follow: -BUCKn : for BUCKs, where n can lie in range 1 to 9. example: BUCK1, BUCK5, BUCK9. + Regulators which can be turned off during system suspend: + -LDOn : 2, 6-8, 10-12, 14-16, + -BUCKn : 1-4. + Use standard regulator bindings for it ('regulator-off-in-suspend'). + + Example: max77686@09 { -- cgit v1.2.3-59-g8ed1b From c556522e89fb00ee1e1efd2e1d29ed092243cf66 Mon Sep 17 00:00:00 2001 From: Ulrich Hecht Date: Fri, 14 Nov 2014 16:59:31 +0100 Subject: serial: sh-sci: Add device tree support for r8a7794 Simply document the new compat string. There appears to be no need for a driver update. Signed-off-by: Ulrich Hecht [geert: Reworded to match previous commits] Signed-off-by: Geert Uytterhoeven Acked-by: Simon Horman Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/renesas,sci-serial.txt | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt b/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt index b3556609a06f..7b87eb2c66be 100644 --- a/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt +++ b/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt @@ -20,6 +20,10 @@ Required properties: - "renesas,scifa-r8a7791" for R8A7791 (R-Car M2) SCIFA compatible UART. - "renesas,scifb-r8a7791" for R8A7791 (R-Car M2) SCIFB compatible UART. - "renesas,hscif-r8a7791" for R8A7791 (R-Car M2) HSCIF compatible UART. + - "renesas,scif-r8a7794" for R8A7794 (R-Car E2) SCIF compatible UART. + - "renesas,scifa-r8a7794" for R8A7794 (R-Car E2) SCIFA compatible UART. + - "renesas,scifb-r8a7794" for R8A7794 (R-Car E2) SCIFB compatible UART. + - "renesas,hscif-r8a7794" for R8A7794 (R-Car E2) HSCIF compatible UART. - "renesas,scif" for generic SCIF compatible UART. - "renesas,scifa" for generic SCIFA compatible UART. - "renesas,scifb" for generic SCIFB compatible UART. -- cgit v1.2.3-59-g8ed1b From 681b05f58f0cd13ea21ee46600a9ad679199214c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 14 Nov 2014 16:59:32 +0100 Subject: serial: sh-sci: Add device tree support for r7s72100 Simply document the new compat string (and keep the list sorted by SoC). There appears to be no need for a driver update. Signed-off-by: Geert Uytterhoeven Acked-by: Simon Horman Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/renesas,sci-serial.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt b/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt index 7b87eb2c66be..ae73bb0e9ad9 100644 --- a/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt +++ b/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt @@ -4,8 +4,7 @@ Required properties: - compatible: Must contain one of the following: - - "renesas,scifa-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFA compatible UART. - - "renesas,scifb-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFB compatible UART. + - "renesas,scif-r7s72100" for R7S72100 (RZ/A1H) SCIF compatible UART. - "renesas,scifa-r8a73a4" for R8A73A4 (R-Mobile APE6) SCIFA compatible UART. - "renesas,scifb-r8a73a4" for R8A73A4 (R-Mobile APE6) SCIFB compatible UART. - "renesas,scifa-r8a7740" for R8A7740 (R-Mobile A1) SCIFA compatible UART. @@ -24,6 +23,8 @@ Required properties: - "renesas,scifa-r8a7794" for R8A7794 (R-Car E2) SCIFA compatible UART. - "renesas,scifb-r8a7794" for R8A7794 (R-Car E2) SCIFB compatible UART. - "renesas,hscif-r8a7794" for R8A7794 (R-Car E2) HSCIF compatible UART. + - "renesas,scifa-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFA compatible UART. + - "renesas,scifb-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFB compatible UART. - "renesas,scif" for generic SCIF compatible UART. - "renesas,scifa" for generic SCIFA compatible UART. - "renesas,scifb" for generic SCIFB compatible UART. -- cgit v1.2.3-59-g8ed1b From 52bec4ed4ef83f1a14dbcfd1a97e35f77c6e261e Mon Sep 17 00:00:00 2001 From: Qipan Li Date: Tue, 11 Nov 2014 20:44:58 +0800 Subject: serial: sirf: add a new uart type support in CSR A7DA SoC, uart6 located at BT module and it need multiple clock sources, so for "sirf,marco-bt-uart" compatible uarts, drivers take 3 clock sources and enable them. this patch also replaces clk_get by devm_clk_get function and fix DT binding document in which we missed to fix when we added marco platform in commit 909102db44f "serial: sirf: add support for Marco chip". Signed-off-by: Qipan Li Signed-off-by: Barry Song Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/serial/sirf-uart.txt | 16 +++++++++- drivers/tty/serial/sirfsoc_uart.c | 34 +++++++++++++++++----- drivers/tty/serial/sirfsoc_uart.h | 4 +++ 3 files changed, 46 insertions(+), 8 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/serial/sirf-uart.txt b/Documentation/devicetree/bindings/serial/sirf-uart.txt index a2dfc6522a91..3acdd969edf1 100644 --- a/Documentation/devicetree/bindings/serial/sirf-uart.txt +++ b/Documentation/devicetree/bindings/serial/sirf-uart.txt @@ -1,7 +1,9 @@ * CSR SiRFprimaII/atlasVI Universal Synchronous Asynchronous Receiver/Transmitter * Required properties: -- compatible : Should be "sirf,prima2-uart" or "sirf, prima2-usp-uart" +- compatible : Should be "sirf,prima2-uart", "sirf, prima2-usp-uart", + "sirf,marco-uart" or "sirf,marco-bt-uart" which means + uart located in BT module and used for BT. - reg : Offset and length of the register set for the device - interrupts : Should contain uart interrupt - fifosize : Should define hardware rx/tx fifo size @@ -31,3 +33,15 @@ usp@b0090000 { rts-gpios = <&gpio 15 0>; cts-gpios = <&gpio 46 0>; }; + +for uart use in BT module, +uart6: uart@11000000 { + cell-index = <6>; + compatible = "sirf,marco-bt-uart", "sirf,marco-uart"; + reg = <0x11000000 0x1000>; + interrupts = <0 100 0>; + clocks = <&clks 138>, <&clks 140>, <&clks 141>; + clock-names = "uart", "general", "noc"; + fifosize = <128>; + status = "disabled"; +} diff --git a/drivers/tty/serial/sirfsoc_uart.c b/drivers/tty/serial/sirfsoc_uart.c index 4102192687ee..2f6c6b04cc8d 100644 --- a/drivers/tty/serial/sirfsoc_uart.c +++ b/drivers/tty/serial/sirfsoc_uart.c @@ -1032,10 +1032,19 @@ static void sirfsoc_uart_pm(struct uart_port *port, unsigned int state, unsigned int oldstate) { struct sirfsoc_uart_port *sirfport = to_sirfport(port); - if (!state) + if (!state) { + if (sirfport->is_bt_uart) { + clk_prepare_enable(sirfport->clk_noc); + clk_prepare_enable(sirfport->clk_general); + } clk_prepare_enable(sirfport->clk); - else + } else { clk_disable_unprepare(sirfport->clk); + if (sirfport->is_bt_uart) { + clk_disable_unprepare(sirfport->clk_general); + clk_disable_unprepare(sirfport->clk_noc); + } + } } static int sirfsoc_uart_startup(struct uart_port *port) @@ -1378,12 +1387,26 @@ usp_no_flow_control: } port->irq = res->start; - sirfport->clk = clk_get(&pdev->dev, NULL); + sirfport->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(sirfport->clk)) { ret = PTR_ERR(sirfport->clk); goto err; } port->uartclk = clk_get_rate(sirfport->clk); + if (of_device_is_compatible(pdev->dev.of_node, "sirf,marco-bt-uart")) { + sirfport->clk_general = devm_clk_get(&pdev->dev, "general"); + if (IS_ERR(sirfport->clk_general)) { + ret = PTR_ERR(sirfport->clk_general); + goto err; + } + sirfport->clk_noc = devm_clk_get(&pdev->dev, "noc"); + if (IS_ERR(sirfport->clk_noc)) { + ret = PTR_ERR(sirfport->clk_noc); + goto err; + } + sirfport->is_bt_uart = true; + } else + sirfport->is_bt_uart = false; port->ops = &sirfsoc_uart_ops; spin_lock_init(&port->lock); @@ -1392,7 +1415,7 @@ usp_no_flow_control: ret = uart_add_one_port(&sirfsoc_uart_drv, port); if (ret != 0) { dev_err(&pdev->dev, "Cannot add UART port(%d).\n", pdev->id); - goto port_err; + goto err; } sirfport->rx_dma_chan = dma_request_slave_channel(port->dev, "rx"); @@ -1421,8 +1444,6 @@ alloc_coherent_err: sirfport->rx_dma_items[j].xmit.buf, sirfport->rx_dma_items[j].dma_addr); dma_release_channel(sirfport->rx_dma_chan); -port_err: - clk_put(sirfport->clk); err: return ret; } @@ -1431,7 +1452,6 @@ static int sirfsoc_uart_remove(struct platform_device *pdev) { struct sirfsoc_uart_port *sirfport = platform_get_drvdata(pdev); struct uart_port *port = &sirfport->port; - clk_put(sirfport->clk); uart_remove_one_port(&sirfsoc_uart_drv, port); if (sirfport->rx_dma_chan) { int i; diff --git a/drivers/tty/serial/sirfsoc_uart.h b/drivers/tty/serial/sirfsoc_uart.h index 6a7ebf7ef130..275d03893990 100644 --- a/drivers/tty/serial/sirfsoc_uart.h +++ b/drivers/tty/serial/sirfsoc_uart.h @@ -417,6 +417,10 @@ struct sirfsoc_uart_port { struct uart_port port; struct clk *clk; + /* UART6 for BT usage in A7DA platform need multi-clock source */ + bool is_bt_uart; + struct clk *clk_general; + struct clk *clk_noc; /* for SiRFmarco, there are SET/CLR for UART_INT_EN */ bool is_marco; struct sirfsoc_uart_register *uart_reg; -- cgit v1.2.3-59-g8ed1b From aa1facbd2847263cf168ec7d66e6c8951c413905 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Thu, 13 Nov 2014 12:47:44 +0100 Subject: Phy: DT binding documentation for Marvell MVEBU SATA phy. Describe the binding for the Marvell MVEBU SATA phy. This driver can be used at least with Kirkwood, Dove and maybe others. Additionally, update the SATA binding with the properties to link to the phy nodes. Signed-off-by: Andrew Lunn Acked-by: Jason Cooper Signed-off-by: Kishon Vijay Abraham I --- Documentation/devicetree/bindings/ata/marvell.txt | 6 ++++++ .../devicetree/bindings/phy/phy-mvebu.txt | 22 ++++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/phy-mvebu.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/ata/marvell.txt b/Documentation/devicetree/bindings/ata/marvell.txt index 1c8351604d38..b460edd12766 100644 --- a/Documentation/devicetree/bindings/ata/marvell.txt +++ b/Documentation/devicetree/bindings/ata/marvell.txt @@ -6,11 +6,17 @@ Required Properties: - interrupts : Interrupt controller is using - nr-ports : Number of SATA ports in use. +Optional Properties: +- phys : List of phandles to sata phys +- phy-names : Should be "0", "1", etc, one number per phandle + Example: sata@80000 { compatible = "marvell,orion-sata"; reg = <0x80000 0x5000>; interrupts = <21>; + phys = <&sata_phy0>, <&sata_phy1>; + phy-names = "0", "1"; nr-ports = <2>; } diff --git a/Documentation/devicetree/bindings/phy/phy-mvebu.txt b/Documentation/devicetree/bindings/phy/phy-mvebu.txt new file mode 100644 index 000000000000..6cb3364aeafb --- /dev/null +++ b/Documentation/devicetree/bindings/phy/phy-mvebu.txt @@ -0,0 +1,22 @@ +* Marvell MVEBU SATA PHY + +Power control for the SATA phy found on Marvell MVEBU SoCs. + +This document extends the binding described in phy-bindings.txt + +Required properties : + + - reg : Offset and length of the register set for the SATA device + - compatible : Should be "marvell,mvebu-sata-phy" + - clocks : phandle of clock and specifier that supplies the device + - clock-names : Should be "sata" + +Example: + sata-phy@84000 { + compatible = "marvell,mvebu-sata-phy"; + reg = <0x84000 0x0334>; + clocks = <&gate_clk 15>; + clock-names = "sata"; + #phy-cells = <0>; + status = "ok"; + }; -- cgit v1.2.3-59-g8ed1b From 1a6ab1c0e844041524f8edd1acf0de94df991aaa Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Thu, 13 Nov 2014 12:47:45 +0100 Subject: Phy: DT binding documentation for the Armada 375 USB cluster binding Armada 375 comes with an USB2 host and device controller and an USB3 controller. The USB cluster control register allows to manage common features of both USB controllers. This commit adds the Device Tree binding documentation for this piece of hardware. Signed-off-by: Gregory CLEMENT Acked-by: Jason Cooper Signed-off-by: Kishon Vijay Abraham I --- Documentation/devicetree/bindings/phy/phy-mvebu.txt | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/phy/phy-mvebu.txt b/Documentation/devicetree/bindings/phy/phy-mvebu.txt index 6cb3364aeafb..f95b6260a3b3 100644 --- a/Documentation/devicetree/bindings/phy/phy-mvebu.txt +++ b/Documentation/devicetree/bindings/phy/phy-mvebu.txt @@ -20,3 +20,24 @@ Example: #phy-cells = <0>; status = "ok"; }; + +Armada 375 USB cluster +---------------------- + +Armada 375 comes with an USB2 host and device controller and an USB3 +controller. The USB cluster control register allows to manage common +features of both USB controllers. + +Required properties: + +- compatible: "marvell,armada-375-usb-cluster" +- reg: Should contain usb cluster register location and length. +- #phy-cells : from the generic phy bindings, must be 1. Possible +values are 1 (USB2), 2 (USB3). + +Example: + usbcluster: usb-cluster@18400 { + compatible = "marvell,armada-375-usb-cluster"; + reg = <0x18400 0x4>; + #phy-cells = <1> + }; -- cgit v1.2.3-59-g8ed1b From 5d85a8478ec8a1956f08ad72d1601a3c5cb60b1e Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 18 Nov 2014 12:10:50 +0100 Subject: dt-bindings: simplefb: Drop the advice about using a specific path for nodes This goes contrary to how devicetree usually works, so drop it. Instead if the firmware needs to be able to find a specific node it should use a platform specific compatible + properties for this. Signed-off-by: Hans de Goede Acked-by: Grant Likely Signed-off-by: Tomi Valkeinen --- Documentation/devicetree/bindings/video/simple-framebuffer.txt | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/video/simple-framebuffer.txt b/Documentation/devicetree/bindings/video/simple-framebuffer.txt index f8fb7e6e5609..4474ef6e0b95 100644 --- a/Documentation/devicetree/bindings/video/simple-framebuffer.txt +++ b/Documentation/devicetree/bindings/video/simple-framebuffer.txt @@ -31,12 +31,10 @@ enable them. This way if e.g. later on support for more display clocks get added, the simplefb nodes will already contain this info and the firmware does not need to be updated. -If pre-filled framebuffer nodes are used, they should be named -"framebuffer#-", e.g. "framebuffer0-hdmi". The output should be -included in the name since different outputs typically require different -clocks and the clocks are part of the pre-populated nodes. The firmware must -rename the nodes to the standard "framebuffer@
" name using the -runtime chosen address when enabling the nodes. +If pre-filled framebuffer nodes are used, the firmware may need extra +information to find the right node. In that case an extra platform specific +compatible and platform specific properties should be used and documented, +see e.g. simple-framebuffer-sunxi.txt . Required properties: - compatible: "simple-framebuffer" -- cgit v1.2.3-59-g8ed1b From b14c99299b9e11615f512ddadd6ca98dc41f2cb8 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 18 Nov 2014 12:10:51 +0100 Subject: dt-bindings: simplefb-sunxi: Add sunxi simplefb extensions If pre-filled framebuffer nodes are used, the firmware may need extra properties to find the right node. This documents the properties to use for this on sunxi platforms. Signed-off-by: Hans de Goede Acked-by: Grant Likely Signed-off-by: Tomi Valkeinen --- .../bindings/video/simple-framebuffer-sunxi.txt | 33 ++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 Documentation/devicetree/bindings/video/simple-framebuffer-sunxi.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/video/simple-framebuffer-sunxi.txt b/Documentation/devicetree/bindings/video/simple-framebuffer-sunxi.txt new file mode 100644 index 000000000000..c46ba641a1df --- /dev/null +++ b/Documentation/devicetree/bindings/video/simple-framebuffer-sunxi.txt @@ -0,0 +1,33 @@ +Sunxi specific Simple Framebuffer bindings + +This binding documents sunxi specific extensions to the simple-framebuffer +bindings. The sunxi simplefb u-boot code relies on the devicetree containing +pre-populated simplefb nodes. + +These extensions are intended so that u-boot can select the right node based +on which pipeline is being used. As such they are solely intended for +firmware / bootloader use, and the OS should ignore them. + +Required properties: +- compatible: "allwinner,simple-framebuffer" +- allwinner,pipeline, one of: + "de_be0-lcd0" + "de_be1-lcd1" + "de_be0-lcd0-hdmi" + "de_be1-lcd1-hdmi" + +Example: + +chosen { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + framebuffer@0 { + compatible = "allwinner,simple-framebuffer", "simple-framebuffer"; + allwinner,pipeline = "de_be0-lcd0-hdmi"; + clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 43>, + <&ahb_gates 44>; + status = "disabled"; + }; +}; -- cgit v1.2.3-59-g8ed1b From 4bc567dd60a1cfa9abd8484cff2de31cdf51649d Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 26 Jun 2014 21:18:53 +0200 Subject: of: Add NVIDIA Tegra memory controller binding The memory controller on NVIDIA Tegra exposes various knobs that can be used to tune the behaviour of the clients attached to it. In addition, the memory controller implements an SMMU (IOMMU) which can translate I/O virtual addresses to physical addresses for clients. This is useful for scatter-gather operation on devices that don't support it natively and for virtualization or process separation. Signed-off-by: Thierry Reding --- .../memory-controllers/nvidia,tegra-mc.txt | 36 ++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 Documentation/devicetree/bindings/memory-controllers/nvidia,tegra-mc.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra-mc.txt b/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra-mc.txt new file mode 100644 index 000000000000..f3db93c85eea --- /dev/null +++ b/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra-mc.txt @@ -0,0 +1,36 @@ +NVIDIA Tegra Memory Controller device tree bindings +=================================================== + +Required properties: +- compatible: Should be "nvidia,tegra-mc" +- reg: Physical base address and length of the controller's registers. +- clocks: Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. +- clock-names: Must include the following entries: + - mc: the module's clock input +- interrupts: The interrupt outputs from the controller. +- #iommu-cells: Should be 1. The single cell of the IOMMU specifier defines + the SWGROUP of the master. + +This device implements an IOMMU that complies with the generic IOMMU binding. +See ../iommu/iommu.txt for details. + +Example: +-------- + + mc: memory-controller@0,70019000 { + compatible = "nvidia,tegra124-mc"; + reg = <0x0 0x70019000 0x0 0x1000>; + clocks = <&tegra_car TEGRA124_CLK_MC>; + clock-names = "mc"; + + interrupts = ; + + #iommu-cells = <1>; + }; + + sdhci@0,700b0000 { + compatible = "nvidia,tegra124-sdhci"; + ... + iommus = <&mc TEGRA_SWGROUP_SDMMC1A>; + }; -- cgit v1.2.3-59-g8ed1b From 8067042ad9543b410b7dc355ec312c2b61979eec Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Tue, 4 Nov 2014 10:21:32 -0300 Subject: watchdog: orion: Use the reference clock on Armada 375 SoC The 25 MHz reference clock has better stability so its use is prefered over the core clock. Change the Armada 375 clock initialization to use this reference clock. To ensure the driver is compatible with an old devicetree, also provide a fallback path which will silently return to the previous behavior. While here, add the clock specification to the binding documentation. Acked-by: Jason Cooper Acked-by: Gregory CLEMENT Acked-by: Wim Van Sebroeck Reviewed-by: Thomas Petazzoni Tested-by: Thomas Petazzoni Signed-off-by: Ezequiel Garcia Signed-off-by: Daniel Lezcano --- .../devicetree/bindings/watchdog/marvel.txt | 13 +++++++ drivers/watchdog/orion_wdt.c | 42 +++++++++++++++++++++- 2 files changed, 54 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/watchdog/marvel.txt b/Documentation/devicetree/bindings/watchdog/marvel.txt index 97223fddb7bd..858ed9221ac4 100644 --- a/Documentation/devicetree/bindings/watchdog/marvel.txt +++ b/Documentation/devicetree/bindings/watchdog/marvel.txt @@ -17,6 +17,18 @@ For "marvell,armada-375-wdt" and "marvell,armada-380-wdt": - reg : A third entry is mandatory and should contain the shared mask/unmask RSTOUT address. +Clocks required for compatibles = "marvell,orion-wdt", + "marvell,armada-370-wdt": +- clocks : Must contain a single entry describing the clock input + +Clocks required for compatibles = "marvell,armada-xp-wdt" + "marvell,armada-375-wdt" + "marvell,armada-380-wdt": +- clocks : Must contain an entry for each entry in clock-names. +- clock-names : Must include the following entries: + "nbclk" (L2/coherency fabric clock), + "fixed" (Reference 25 MHz fixed-clock). + Optional properties: - interrupts : Contains the IRQ for watchdog expiration @@ -30,4 +42,5 @@ Example: interrupts = <3>; timeout-sec = <10>; status = "okay"; + clocks = <&gate_clk 7>; }; diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c index 00d0741228fc..8cb1ff3bcd90 100644 --- a/drivers/watchdog/orion_wdt.c +++ b/drivers/watchdog/orion_wdt.c @@ -114,6 +114,46 @@ static int armada370_wdt_clock_init(struct platform_device *pdev, return 0; } +static int armada375_wdt_clock_init(struct platform_device *pdev, + struct orion_watchdog *dev) +{ + int ret; + + dev->clk = of_clk_get_by_name(pdev->dev.of_node, "fixed"); + if (!IS_ERR(dev->clk)) { + ret = clk_prepare_enable(dev->clk); + if (ret) { + clk_put(dev->clk); + return ret; + } + + atomic_io_modify(dev->reg + TIMER_CTRL, + WDT_AXP_FIXED_ENABLE_BIT, + WDT_AXP_FIXED_ENABLE_BIT); + dev->clk_rate = clk_get_rate(dev->clk); + + return 0; + } + + /* Mandatory fallback for proper devicetree backward compatibility */ + dev->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(dev->clk)) + return PTR_ERR(dev->clk); + + ret = clk_prepare_enable(dev->clk); + if (ret) { + clk_put(dev->clk); + return ret; + } + + atomic_io_modify(dev->reg + TIMER_CTRL, + WDT_A370_RATIO_MASK(WDT_A370_RATIO_SHIFT), + WDT_A370_RATIO_MASK(WDT_A370_RATIO_SHIFT)); + dev->clk_rate = clk_get_rate(dev->clk) / WDT_A370_RATIO; + + return 0; +} + static int armadaxp_wdt_clock_init(struct platform_device *pdev, struct orion_watchdog *dev) { @@ -394,7 +434,7 @@ static const struct orion_watchdog_data armada375_data = { .rstout_mask_bit = BIT(10), .wdt_enable_bit = BIT(8), .wdt_counter_offset = 0x34, - .clock_init = armada370_wdt_clock_init, + .clock_init = armada375_wdt_clock_init, .enabled = armada375_enabled, .start = armada375_start, .stop = armada375_stop, -- cgit v1.2.3-59-g8ed1b From 4a22d9c93af1f2b2c40354c4bc59fd007f33f05e Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Tue, 4 Nov 2014 10:21:33 -0300 Subject: clocksource: armada-370-xp: Use the reference clock on A375 SoC The 25 MHz reference clock has better stability so its use is preferred over the core clock. This commit takes advantage of the already introduced Armada 375 devicetree compatible string and adds a new timer initialization. If available, the timer will use the reference clock (named as 'fixed'). Otherwise, it falls back to the previous behavior. Acked-by: Jason Cooper Acked-by: Gregory CLEMENT Acked-by: Wim Van Sebroeck Reviewed-by: Thomas Petazzoni Tested-by: Thomas Petazzoni Signed-off-by: Ezequiel Garcia Signed-off-by: Daniel Lezcano --- .../bindings/timer/marvell,armada-370-xp-timer.txt | 9 ++++--- drivers/clocksource/time-armada-370-xp.c | 28 ++++++++++++++++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/timer/marvell,armada-370-xp-timer.txt b/Documentation/devicetree/bindings/timer/marvell,armada-370-xp-timer.txt index f455182b1086..e9c78ce880e6 100644 --- a/Documentation/devicetree/bindings/timer/marvell,armada-370-xp-timer.txt +++ b/Documentation/devicetree/bindings/timer/marvell,armada-370-xp-timer.txt @@ -2,8 +2,10 @@ Marvell Armada 370 and Armada XP Timers --------------------------------------- Required properties: -- compatible: Should be either "marvell,armada-370-timer" or - "marvell,armada-xp-timer" as appropriate. +- compatible: Should be one of the following + "marvell,armada-370-timer", + "marvell,armada-375-timer", + "marvell,armada-xp-timer". - interrupts: Should contain the list of Global Timer interrupts and then local timer interrupts - reg: Should contain location and length for timers register. First @@ -13,7 +15,8 @@ Required properties: Clocks required for compatible = "marvell,armada-370-timer": - clocks : Must contain a single entry describing the clock input -Clocks required for compatible = "marvell,armada-xp-timer": +Clocks required for compatibles = "marvell,armada-xp-timer", + "marvell,armada-375-timer": - clocks : Must contain an entry for each entry in clock-names. - clock-names : Must include the following entries: "nbclk" (L2/coherency fabric clock), diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c index d8555f9edc50..3a0704b0d739 100644 --- a/drivers/clocksource/time-armada-370-xp.c +++ b/drivers/clocksource/time-armada-370-xp.c @@ -301,6 +301,34 @@ static void __init armada_xp_timer_init(struct device_node *np) CLOCKSOURCE_OF_DECLARE(armada_xp, "marvell,armada-xp-timer", armada_xp_timer_init); +static void __init armada_375_timer_init(struct device_node *np) +{ + struct clk *clk; + + clk = of_clk_get_by_name(np, "fixed"); + if (!IS_ERR(clk)) { + clk_prepare_enable(clk); + timer_clk = clk_get_rate(clk); + } else { + + /* + * This fallback is required in order to retain proper + * devicetree backwards compatibility. + */ + clk = of_clk_get(np, 0); + + /* Must have at least a clock */ + BUG_ON(IS_ERR(clk)); + clk_prepare_enable(clk); + timer_clk = clk_get_rate(clk) / TIMER_DIVIDER; + timer25Mhz = false; + } + + armada_370_xp_timer_common_init(np); +} +CLOCKSOURCE_OF_DECLARE(armada_375, "marvell,armada-375-timer", + armada_375_timer_init); + static void __init armada_370_timer_init(struct device_node *np) { struct clk *clk = of_clk_get(np, 0); -- cgit v1.2.3-59-g8ed1b From 89ad2be75a4287126f9f5473ecf167bd9b91093d Mon Sep 17 00:00:00 2001 From: Abhilash Kesavan Date: Thu, 28 Aug 2014 18:48:53 +0530 Subject: mmc: dw_mmc: exynos: Add support for exynos7 The Exynos7 has a DWMMC controller (v2.70a) which is different from prior versions. This patch adds new compatible strings for exynos7. This patch also fixes the CLKSEL register offset on exynos7. Signed-off-by: Abhilash Kesavan Signed-off-by: Yuvaraj Kumar C D Tested-by: Vivek Gautam Acked-by: Jaehoon Chung Signed-off-by: Ulf Hansson --- .../devicetree/bindings/mmc/exynos-dw-mshc.txt | 4 + drivers/mmc/host/dw_mmc-exynos.c | 91 ++++++++++++++++++---- 2 files changed, 82 insertions(+), 13 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 6cd3525d0e09..ee4fc0576c7d 100644 --- a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt +++ b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt @@ -18,6 +18,10 @@ Required Properties: specific extensions. - "samsung,exynos5420-dw-mshc": for controllers with Samsung Exynos5420 specific extensions. + - "samsung,exynos7-dw-mshc": for controllers with Samsung Exynos7 + specific extensions. + - "samsung,exynos7-dw-mshc-smu": for controllers with Samsung Exynos7 + specific extensions having an SMU. * samsung,dw-mshc-ciu-div: Specifies the divider value for the card interface unit (ciu) clock. This property is applicable only for Exynos5 SoC's and diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c index 0fbc53ac7eae..509365cb22c6 100644 --- a/drivers/mmc/host/dw_mmc-exynos.c +++ b/drivers/mmc/host/dw_mmc-exynos.c @@ -25,6 +25,7 @@ #define NUM_PINS(x) (x + 2) #define SDMMC_CLKSEL 0x09C +#define SDMMC_CLKSEL64 0x0A8 #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) @@ -65,6 +66,8 @@ enum dw_mci_exynos_type { DW_MCI_TYPE_EXYNOS5250, DW_MCI_TYPE_EXYNOS5420, DW_MCI_TYPE_EXYNOS5420_SMU, + DW_MCI_TYPE_EXYNOS7, + DW_MCI_TYPE_EXYNOS7_SMU, }; /* Exynos implementation specific driver private data */ @@ -95,6 +98,12 @@ static struct dw_mci_exynos_compatible { }, { .compatible = "samsung,exynos5420-dw-mshc-smu", .ctrl_type = DW_MCI_TYPE_EXYNOS5420_SMU, + }, { + .compatible = "samsung,exynos7-dw-mshc", + .ctrl_type = DW_MCI_TYPE_EXYNOS7, + }, { + .compatible = "samsung,exynos7-dw-mshc-smu", + .ctrl_type = DW_MCI_TYPE_EXYNOS7_SMU, }, }; @@ -102,7 +111,8 @@ static int dw_mci_exynos_priv_init(struct dw_mci *host) { struct dw_mci_exynos_priv_data *priv = host->priv; - if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS5420_SMU) { + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS5420_SMU || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) { mci_writel(host, MPSBEGIN0, 0); mci_writel(host, MPSEND0, DWMCI_BLOCK_NUM); mci_writel(host, MPSCTRL0, DWMCI_MPSCTRL_SECURE_WRITE_BIT | @@ -153,11 +163,22 @@ static int dw_mci_exynos_resume(struct device *dev) static int dw_mci_exynos_resume_noirq(struct device *dev) { struct dw_mci *host = dev_get_drvdata(dev); + struct dw_mci_exynos_priv_data *priv = host->priv; u32 clksel; - clksel = mci_readl(host, CLKSEL); - if (clksel & SDMMC_CLKSEL_WAKEUP_INT) - mci_writel(host, CLKSEL, 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); + + if (clksel & SDMMC_CLKSEL_WAKEUP_INT) { + 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 0; } @@ -169,6 +190,7 @@ static int dw_mci_exynos_resume_noirq(struct device *dev) static void dw_mci_exynos_prepare_command(struct dw_mci *host, u32 *cmdr) { + struct dw_mci_exynos_priv_data *priv = host->priv; /* * Exynos4412 and Exynos5250 extends the use of CMD register with the * use of bit 29 (which is reserved on standard MSHC controllers) for @@ -176,8 +198,14 @@ static void dw_mci_exynos_prepare_command(struct dw_mci *host, u32 *cmdr) * HOLD register should be bypassed in case there is no phase shift * applied on CMD/DATA that is sent to the card. */ - if (SDMMC_CLKSEL_GET_DRV_WD3(mci_readl(host, CLKSEL))) - *cmdr |= SDMMC_CMD_USE_HOLD_REG; + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) { + if (SDMMC_CLKSEL_GET_DRV_WD3(mci_readl(host, CLKSEL64))) + *cmdr |= SDMMC_CMD_USE_HOLD_REG; + } else { + if (SDMMC_CLKSEL_GET_DRV_WD3(mci_readl(host, CLKSEL))) + *cmdr |= SDMMC_CMD_USE_HOLD_REG; + } } static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios) @@ -188,12 +216,20 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios) u8 div = priv->ciu_div + 1; if (ios->timing == MMC_TIMING_MMC_DDR52) { - mci_writel(host, CLKSEL, priv->ddr_timing); + 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; } else { - mci_writel(host, CLKSEL, priv->sdr_timing); + 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); } /* Don't care if wanted clock is zero */ @@ -265,26 +301,51 @@ static int dw_mci_exynos_parse_dt(struct dw_mci *host) static inline u8 dw_mci_exynos_get_clksmpl(struct dw_mci *host) { - return SDMMC_CLKSEL_CCLK_SAMPLE(mci_readl(host, CLKSEL)); + struct dw_mci_exynos_priv_data *priv = host->priv; + + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) + return SDMMC_CLKSEL_CCLK_SAMPLE(mci_readl(host, CLKSEL64)); + else + return SDMMC_CLKSEL_CCLK_SAMPLE(mci_readl(host, CLKSEL)); } static inline void dw_mci_exynos_set_clksmpl(struct dw_mci *host, u8 sample) { u32 clksel; - clksel = mci_readl(host, CLKSEL); + struct dw_mci_exynos_priv_data *priv = host->priv; + + 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 & ~0x7) | SDMMC_CLKSEL_CCLK_SAMPLE(sample); - mci_writel(host, CLKSEL, clksel); + 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); } static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host) { + struct dw_mci_exynos_priv_data *priv = host->priv; u32 clksel; u8 sample; - clksel = mci_readl(host, 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); sample = (clksel + 1) & 0x7; clksel = (clksel & ~0x7) | sample; - mci_writel(host, CLKSEL, clksel); + 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; } @@ -411,6 +472,10 @@ static const struct of_device_id dw_mci_exynos_match[] = { .data = &exynos_drv_data, }, { .compatible = "samsung,exynos5420-dw-mshc-smu", .data = &exynos_drv_data, }, + { .compatible = "samsung,exynos7-dw-mshc", + .data = &exynos_drv_data, }, + { .compatible = "samsung,exynos7-dw-mshc-smu", + .data = &exynos_drv_data, }, {}, }; MODULE_DEVICE_TABLE(of, dw_mci_exynos_match); -- cgit v1.2.3-59-g8ed1b From 4d7c07cd6c0379228e65c52776f22250e8f4a962 Mon Sep 17 00:00:00 2001 From: Andrew Bresticker Date: Thu, 13 Nov 2014 10:50:21 -0800 Subject: mmc: dw_mmc: Add support for IMG Pistachio Add support for the DW MMC host found on the Imagination Pistachio SoC. Like the DW MMC hosts found on SOCFPGA and Rockchip SoCs, the DW MMC host on Pistachio requires the use of SDMMC_CMD_USE_HOLD_REG. Signed-off-by: Andrew Bresticker Reviewed-by: Doug Anderson Acked-by: Jaehoon Chung Signed-off-by: Ulf Hansson --- .../devicetree/bindings/mmc/img-dw-mshc.txt | 29 ++++++++++++++++++++++ drivers/mmc/host/dw_mmc-pltfm.c | 6 +++++ 2 files changed, 35 insertions(+) create mode 100644 Documentation/devicetree/bindings/mmc/img-dw-mshc.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mmc/img-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/img-dw-mshc.txt new file mode 100644 index 000000000000..85de99fcaa2f --- /dev/null +++ b/Documentation/devicetree/bindings/mmc/img-dw-mshc.txt @@ -0,0 +1,29 @@ +* Imagination specific extensions to the Synopsys Designware Mobile Storage + Host Controller + +The Synopsys designware mobile storage host controller is used to interface +a SoC with storage medium such as eMMC or SD/MMC cards. This file documents +differences between the core Synopsys dw mshc controller properties described +by synopsys-dw-mshc.txt and the properties used by the Imagination specific +extensions to the Synopsys Designware Mobile Storage Host Controller. + +Required Properties: + +* compatible: should be + - "img,pistachio-dw-mshc": for Pistachio SoCs + +Example: + + mmc@18142000 { + compatible = "img,pistachio-dw-mshc"; + reg = <0x18142000 0x400>; + interrupts = ; + + clocks = <&system_clk>, <&sdhost_clk>; + clock-names = "biu", "ciu"; + + fifo-depth = <0x20>; + bus-width = <4>; + num-slots = <1>; + disable-wp; + }; diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c index 8b6572162ed9..ec6dbcdec693 100644 --- a/drivers/mmc/host/dw_mmc-pltfm.c +++ b/drivers/mmc/host/dw_mmc-pltfm.c @@ -35,6 +35,10 @@ static const struct dw_mci_drv_data socfpga_drv_data = { .prepare_command = dw_mci_pltfm_prepare_command, }; +static const struct dw_mci_drv_data pistachio_drv_data = { + .prepare_command = dw_mci_pltfm_prepare_command, +}; + int dw_mci_pltfm_register(struct platform_device *pdev, const struct dw_mci_drv_data *drv_data) { @@ -90,6 +94,8 @@ static const struct of_device_id dw_mci_pltfm_match[] = { { .compatible = "snps,dw-mshc", }, { .compatible = "altr,socfpga-dw-mshc", .data = &socfpga_drv_data }, + { .compatible = "img,pistachio-dw-mshc", + .data = &pistachio_drv_data }, {}, }; MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match); -- cgit v1.2.3-59-g8ed1b From 36cdfa76635b502c8c7bb7df695d7d5117eca7de Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Tue, 18 Nov 2014 17:22:33 -0300 Subject: [media] media: rc: meson: document device tree bindings This adds binding documentation for the infrared remote control receiver available in Amlogic Meson SoCs. Signed-off-by: Beniamino Galvani Signed-off-by: Mauro Carvalho Chehab --- Documentation/devicetree/bindings/media/meson-ir.txt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/meson-ir.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/media/meson-ir.txt b/Documentation/devicetree/bindings/media/meson-ir.txt new file mode 100644 index 000000000000..407848e85f31 --- /dev/null +++ b/Documentation/devicetree/bindings/media/meson-ir.txt @@ -0,0 +1,14 @@ +* Amlogic Meson IR remote control receiver + +Required properties: + - compatible : should be "amlogic,meson6-ir" + - reg : physical base address and length of the device registers + - interrupts : a single specifier for the interrupt from the device + +Example: + + ir-receiver@c8100480 { + compatible= "amlogic,meson6-ir"; + reg = <0xc8100480 0x20>; + interrupts = <0 15 1>; + }; -- cgit v1.2.3-59-g8ed1b From b3a92e2c4441affceca9e05905723532e4a61e4d Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 24 Nov 2014 14:35:20 +0000 Subject: irqchip: GICv3: Binding updates for ITS Add the documentation for the bindings describing the GICv3 ITS. Signed-off-by: Marc Zyngier Link: https://lkml.kernel.org/r/1416839720-18400-14-git-send-email-marc.zyngier@arm.com Signed-off-by: Jason Cooper --- Documentation/devicetree/bindings/arm/gic-v3.txt | 39 ++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/gic-v3.txt b/Documentation/devicetree/bindings/arm/gic-v3.txt index 33cd05e6c125..ddfade40ac59 100644 --- a/Documentation/devicetree/bindings/arm/gic-v3.txt +++ b/Documentation/devicetree/bindings/arm/gic-v3.txt @@ -49,11 +49,29 @@ Optional occupied by the redistributors. Required if more than one such region is present. +Sub-nodes: + +GICv3 has one or more Interrupt Translation Services (ITS) that are +used to route Message Signalled Interrupts (MSI) to the CPUs. + +These nodes must have the following properties: +- compatible : Should at least contain "arm,gic-v3-its". +- msi-controller : Boolean property. Identifies the node as an MSI controller +- reg: Specifies the base physical address and size of the ITS + registers. + +The main GIC node must contain the appropriate #address-cells, +#size-cells and ranges properties for the reg property of all ITS +nodes. + Examples: gic: interrupt-controller@2cf00000 { compatible = "arm,gic-v3"; #interrupt-cells = <3>; + #address-cells = <2>; + #size-cells = <2>; + ranges; interrupt-controller; reg = <0x0 0x2f000000 0 0x10000>, // GICD <0x0 0x2f100000 0 0x200000>, // GICR @@ -61,11 +79,20 @@ Examples: <0x0 0x2c010000 0 0x2000>, // GICH <0x0 0x2c020000 0 0x2000>; // GICV interrupts = <1 9 4>; + + gic-its@2c200000 { + compatible = "arm,gic-v3-its"; + msi-controller; + reg = <0x0 0x2c200000 0 0x200000>; + }; }; gic: interrupt-controller@2c010000 { compatible = "arm,gic-v3"; #interrupt-cells = <3>; + #address-cells = <2>; + #size-cells = <2>; + ranges; interrupt-controller; redistributor-stride = <0x0 0x40000>; // 256kB stride #redistributor-regions = <2>; @@ -76,4 +103,16 @@ Examples: <0x0 0x2c060000 0 0x2000>, // GICH <0x0 0x2c080000 0 0x2000>; // GICV interrupts = <1 9 4>; + + gic-its@2c200000 { + compatible = "arm,gic-v3-its"; + msi-controller; + reg = <0x0 0x2c200000 0 0x200000>; + }; + + gic-its@2c400000 { + compatible = "arm,gic-v3-its"; + msi-controller; + reg = <0x0 0x2c400000 0 0x200000>; + }; }; -- cgit v1.2.3-59-g8ed1b From f4e27e30b3663a8652746d1c7d1649a5fa8c0e6c Mon Sep 17 00:00:00 2001 From: Yingjoe Chen Date: Tue, 25 Nov 2014 16:04:22 +0800 Subject: irqchip: mtk-sysirq: dt-bindings: Add bindings for mediatek sysirq Add binding documentation for Mediatek SoC SYSIRQ. Signed-off-by: Yingjoe Chen Link: https://lkml.kernel.org/r/1416902662-19281-5-git-send-email-yingjoe.chen@mediatek.com Signed-off-by: Jason Cooper --- .../bindings/arm/mediatek/mediatek,sysirq.txt | 28 ++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/mediatek/mediatek,sysirq.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,sysirq.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,sysirq.txt new file mode 100644 index 000000000000..d680b07ec6e8 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,sysirq.txt @@ -0,0 +1,28 @@ +Mediatek 65xx/81xx sysirq + +Mediatek SOCs sysirq support controllable irq inverter for each GIC SPI +interrupt. + +Required properties: +- compatible: should be one of: + "mediatek,mt8135-sysirq" + "mediatek,mt8127-sysirq" + "mediatek,mt6589-sysirq" + "mediatek,mt6582-sysirq" + "mediatek,mt6577-sysirq" +- interrupt-controller : Identifies the node as an interrupt controller +- #interrupt-cells : Use the same format as specified by GIC in + Documentation/devicetree/bindings/arm/gic.txt +- interrupt-parent: phandle of irq parent for sysirq. The parent must + use the same interrupt-cells format as GIC. +- reg: Physical base address of the intpol registers and length of memory + mapped region. + +Example: + sysirq: interrupt-controller@10200100 { + compatible = "mediatek,mt6589-sysirq", "mediatek,mt6577-sysirq"; + interrupt-controller; + #interrupt-cells = <3>; + interrupt-parent = <&gic>; + reg = <0 0x10200100 0 0x1c>; + }; -- cgit v1.2.3-59-g8ed1b From e684e258d831781fd89d2047a272fdb0b0ffe7f4 Mon Sep 17 00:00:00 2001 From: Suravee Suthikulpanit Date: Tue, 25 Nov 2014 18:47:23 +0000 Subject: irqchip: gic-v2m: Add DT bindings for GICv2m Update the GIC DT bindings to support GICv2m. Signed-off-by: Suravee Suthikulpanit [maz: split DT patch from main driver, updated changelog] Signed-off-by: Marc Zyngier Link: https://lkml.kernel.org/r/1416941243-7181-3-git-send-email-marc.zyngier@arm.com Signed-off-by: Jason Cooper --- Documentation/devicetree/bindings/arm/gic.txt | 53 +++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/gic.txt b/Documentation/devicetree/bindings/arm/gic.txt index c7d2fa156678..375147e5a5fb 100644 --- a/Documentation/devicetree/bindings/arm/gic.txt +++ b/Documentation/devicetree/bindings/arm/gic.txt @@ -96,3 +96,56 @@ Example: <0x2c006000 0x2000>; interrupts = <1 9 0xf04>; }; + + +* GICv2m extension for MSI/MSI-x support (Optional) + +Certain revisions of GIC-400 supports MSI/MSI-x via V2M register frame(s). +This is enabled by specifying v2m sub-node(s). + +Required properties: + +- compatible : The value here should contain "arm,gic-v2m-frame". + +- msi-controller : Identifies the node as an MSI controller. + +- reg : GICv2m MSI interface register base and size + +Optional properties: + +- arm,msi-base-spi : When the MSI_TYPER register contains an incorrect + value, this property should contain the SPI base of + the MSI frame, overriding the HW value. + +- arm,msi-num-spis : When the MSI_TYPER register contains an incorrect + value, this property should contain the number of + SPIs assigned to the frame, overriding the HW value. + +Example: + + interrupt-controller@e1101000 { + compatible = "arm,gic-400"; + #interrupt-cells = <3>; + #address-cells = <2>; + #size-cells = <2>; + interrupt-controller; + interrupts = <1 8 0xf04>; + ranges = <0 0 0 0xe1100000 0 0x100000>; + reg = <0x0 0xe1110000 0 0x01000>, + <0x0 0xe112f000 0 0x02000>, + <0x0 0xe1140000 0 0x10000>, + <0x0 0xe1160000 0 0x10000>; + v2m0: v2m@0x8000 { + compatible = "arm,gic-v2m-frame"; + msi-controller; + reg = <0x0 0x80000 0 0x1000>; + }; + + .... + + v2mN: v2m@0x9000 { + compatible = "arm,gic-v2m-frame"; + msi-controller; + reg = <0x0 0x90000 0 0x1000>; + }; + }; -- cgit v1.2.3-59-g8ed1b From d683d0b690c13437d752ccce47963ac64119b07a Mon Sep 17 00:00:00 2001 From: Krishna Mohan Dani Date: Wed, 26 Nov 2014 14:53:04 +0530 Subject: ASoC: Samsung: Add arndale_rt5631 machine driver and binding Adding machine driver to instantiate I2S based realtek's ALC5631 sound card on Arndale board. There are other variants of Audio Daughter Cards for Arndale Board for which support already exists but there is no support for Realtek's alc5631 codec hence support for ALC5631 based machine driver is being added. This patch also documents the device tree binding for the Arndale board based machine driver. Signed-off-by: Claude Youn Signed-off-by: Krishna Mohan Dani Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/arndale.txt | 24 ++++ sound/soc/samsung/Kconfig | 6 + sound/soc/samsung/Makefile | 2 + sound/soc/samsung/arndale_rt5631.c | 150 +++++++++++++++++++++ 4 files changed, 182 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/arndale.txt create mode 100644 sound/soc/samsung/arndale_rt5631.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/arndale.txt b/Documentation/devicetree/bindings/sound/arndale.txt new file mode 100644 index 000000000000..0e76946385ae --- /dev/null +++ b/Documentation/devicetree/bindings/sound/arndale.txt @@ -0,0 +1,24 @@ +Audio Binding for Arndale boards + +Required properties: +- compatible : Can be the following, + "samsung,arndale-rt5631" + +- samsung,audio-cpu: The phandle of the Samsung I2S controller +- samsung,audio-codec: The phandle of the audio codec + +Optional: +- samsung,model: The name of the sound-card + +Arndale Boards has many audio daughter cards, one of them is +rt5631/alc5631. Below example shows audio bindings for rt5631/ +alc5631 based codec. + +Example: + +sound { + compatible = "samsung,arndale-rt5631"; + + samsung,audio-cpu = <&i2s0> + samsung,audio-codec = <&rt5631>; +}; diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index e0e737faadd9..fc67f97f19f6 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig @@ -239,3 +239,9 @@ config SND_SOC_ODROIDX2 select SND_SAMSUNG_I2S help Say Y here to enable audio support for the Odroid-X2/U3. + +config SND_SOC_ARNDALE_RT5631_ALC5631 + tristate "Audio support for RT5631(ALC5631) on Arndale Board" + depends on SND_SOC_SAMSUNG + select SND_SAMSUNG_I2S + select SND_SOC_RT5631 diff --git a/sound/soc/samsung/Makefile b/sound/soc/samsung/Makefile index 91505ddaaf95..31e3dba7e3b5 100644 --- a/sound/soc/samsung/Makefile +++ b/sound/soc/samsung/Makefile @@ -45,6 +45,7 @@ snd-soc-lowland-objs := lowland.o snd-soc-littlemill-objs := littlemill.o snd-soc-bells-objs := bells.o snd-soc-odroidx2-max98090-objs := odroidx2_max98090.o +snd-soc-arndale-rt5631-objs := arndale_rt5631.o obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o @@ -71,3 +72,4 @@ obj-$(CONFIG_SND_SOC_LOWLAND) += snd-soc-lowland.o obj-$(CONFIG_SND_SOC_LITTLEMILL) += snd-soc-littlemill.o obj-$(CONFIG_SND_SOC_BELLS) += snd-soc-bells.o obj-$(CONFIG_SND_SOC_ODROIDX2) += snd-soc-odroidx2-max98090.o +obj-$(CONFIG_SND_SOC_ARNDALE_RT5631_ALC5631) += snd-soc-arndale-rt5631.o diff --git a/sound/soc/samsung/arndale_rt5631.c b/sound/soc/samsung/arndale_rt5631.c new file mode 100644 index 000000000000..1e2b61ca8db2 --- /dev/null +++ b/sound/soc/samsung/arndale_rt5631.c @@ -0,0 +1,150 @@ +/* + * arndale_rt5631.c + * + * Copyright (c) 2014, Insignal Co., Ltd. + * + * Author: Claude + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include "i2s.h" + +static int arndale_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + int rfs, ret; + unsigned long rclk; + + rfs = 256; + + rclk = params_rate(params) * rfs; + + ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_CDCLK, + 0, SND_SOC_CLOCK_OUT); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_RCLKSRC_0, + 0, SND_SOC_CLOCK_OUT); + + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_sysclk(codec_dai, 0, rclk, SND_SOC_CLOCK_OUT); + if (ret < 0) + return ret; + + return 0; +} + +static struct snd_soc_ops arndale_ops = { + .hw_params = arndale_hw_params, +}; + +static struct snd_soc_dai_link arndale_rt5631_dai[] = { + { + .name = "RT5631 HiFi", + .stream_name = "Primary", + .codec_dai_name = "rt5631-hifi", + .dai_fmt = SND_SOC_DAIFMT_I2S + | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBS_CFS, + .ops = &arndale_ops, + }, +}; + +static struct snd_soc_card arndale_rt5631 = { + .name = "Arndale RT5631", + .dai_link = arndale_rt5631_dai, + .num_links = ARRAY_SIZE(arndale_rt5631_dai), +}; + +static int arndale_audio_probe(struct platform_device *pdev) +{ + int n, ret; + struct device_node *np = pdev->dev.of_node; + struct snd_soc_card *card = &arndale_rt5631; + + card->dev = &pdev->dev; + + for (n = 0; np && n < ARRAY_SIZE(arndale_rt5631_dai); n++) { + if (!arndale_rt5631_dai[n].cpu_dai_name) { + arndale_rt5631_dai[n].cpu_of_node = of_parse_phandle(np, + "samsung,audio-cpu", n); + + if (!arndale_rt5631_dai[n].cpu_of_node) { + dev_err(&pdev->dev, + "Property 'samsung,audio-cpu' missing or invalid\n"); + return -EINVAL; + } + } + if (!arndale_rt5631_dai[n].platform_name) + arndale_rt5631_dai[n].platform_of_node = + arndale_rt5631_dai[n].cpu_of_node; + + arndale_rt5631_dai[n].codec_name = NULL; + arndale_rt5631_dai[n].codec_of_node = of_parse_phandle(np, + "samsung,audio-codec", n); + if (!arndale_rt5631_dai[0].codec_of_node) { + dev_err(&pdev->dev, + "Property 'samsung,audio-codec' missing or invalid\n"); + return -EINVAL; + } + } + + ret = devm_snd_soc_register_card(card->dev, card); + + if (ret) + dev_err(&pdev->dev, "snd_soc_register_card() failed:%d\n", ret); + + return ret; +} + +static int arndale_audio_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + + snd_soc_unregister_card(card); + + return 0; +} + +static const struct of_device_id samsung_arndale_rt5631_of_match[] __maybe_unused = { + { .compatible = "samsung,arndale-rt5631", }, + { .compatible = "samsung,arndale-alc5631", }, + {}, +}; +MODULE_DEVICE_TABLE(of, samsung_arndale_rt5631_of_match); + +static struct platform_driver arndale_audio_driver = { + .driver = { + .name = "arndale-audio", + .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, + .of_match_table = of_match_ptr(samsung_arndale_rt5631_of_match), + }, + .probe = arndale_audio_probe, + .remove = arndale_audio_remove, +}; + +module_platform_driver(arndale_audio_driver); + +MODULE_AUTHOR("Claude "); +MODULE_DESCRIPTION("ALSA SoC Driver for Arndale Board"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-59-g8ed1b From d7d30c911dd957e274c3da6910d4286862ab1d78 Mon Sep 17 00:00:00 2001 From: Antoine Tenart Date: Wed, 26 Nov 2014 13:44:37 +0800 Subject: Documentation: bindings: add doc for the USB2 ChipIdea USB driver Document the USB2 ChipIdea driver (ci13xxx) bindings. Signed-off-by: Antoine Tenart Acked-by: Peter Chen Signed-off-by: Peter Chen Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/usb/ci-hdrc-usb2.txt | 24 ++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt new file mode 100644 index 000000000000..27f8b1e5ee46 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt @@ -0,0 +1,24 @@ +* USB2 ChipIdea USB controller for ci13xxx + +Required properties: +- compatible: should be "chipidea,usb2" +- reg: base address and length of the registers +- interrupts: interrupt for the USB controller + +Optional properties: +- clocks: reference to the USB clock +- phys: reference to the USB PHY +- phy-names: should be "usb-phy" +- vbus-supply: reference to the VBUS regulator + +Example: + + usb@f7ed0000 { + compatible = "chipidea,usb2"; + reg = <0xf7ed0000 0x10000>; + interrupts = ; + clocks = <&chip CLKID_USB0>; + phys = <&usb_phy0>; + phy-names = "usb-phy"; + vbus-supply = <®_usb0_vbus>; + }; -- cgit v1.2.3-59-g8ed1b From 388c44a379f7f5832a3e7b39a41cc2b68f937021 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Thu, 27 Nov 2014 02:43:39 +0900 Subject: Documentation: devicetree: Add Exynos-based boards compatible string This patch adds the missing compatible/description of Exynos-based boards to remove following build warning. WARNING: DT compatible string "samsung,..." appears un-documented -- check ./Documentation/devicetree/bindings/ Signed-off-by: Chanwoo Choi Signed-off-by: Kukjin Kim --- .../devicetree/bindings/arm/samsung-boards.txt | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/samsung-boards.txt b/Documentation/devicetree/bindings/arm/samsung-boards.txt index 2168ed31e1b0..1f8287ea5cc7 100644 --- a/Documentation/devicetree/bindings/arm/samsung-boards.txt +++ b/Documentation/devicetree/bindings/arm/samsung-boards.txt @@ -1,11 +1,19 @@ -* Samsung's Exynos4210 based SMDKV310 evaluation board - -SMDKV310 evaluation board is based on Samsung's Exynos4210 SoC. +* Samsung's Exynos SoC based boards Required root node properties: - compatible = should be one or more of the following. - (a) "samsung,smdkv310" - for Samsung's SMDKV310 eval board. - (b) "samsung,exynos4210" - for boards based on Exynos4210 SoC. + - "samsung,rinato" - for Exynos3250-based Samsung Gear2 board. + - "samsung,smdkv310" - for Exynos4210-based Samsung SMDKV310 eval board. + - "samsung,trats" - for Exynos4210-based Tizen Reference board. + - "samsung,universal_c210" - for Exynos4210-based Samsung board. + - "samsung,smdk4412", - for Exynos4412-based Samsung SMDK4412 eval board. + - "samsung,trats2" - for Exynos4412-based Tizen Reference board. + - "samsung,smdk5250" - for Exynos5250-based Samsung SMDK5250 eval board. + - "samsung,xyref5260" - for Exynos5260-based Samsung board. + - "samsung,smdk5410" - for Exynos5410-based Samsung SMDK5410 eval board. + - "samsung,smdk5420" - for Exynos5420-based Samsung SMDK5420 eval board. + - "samsung,sd5v1" - for Exynos5440-based Samsung board. + - "samsung,ssdk5440" - for Exynos5440-based Samsung board. Optional: - firmware node, specifying presence and type of secure firmware: -- cgit v1.2.3-59-g8ed1b From e0cefb3f79d375c58150c78d6bfe665f999d9d85 Mon Sep 17 00:00:00 2001 From: Youngjun Cho Date: Thu, 27 Nov 2014 02:43:39 +0900 Subject: ARM: dts: add board dts file for Exynos3250-based Monk board This patch adds new board dts file to support Samsung Monk board which is based on Exynos3250 SoC and has different H/W configuration from Rinato. This dts file support following features: - eMMC - Main PMIC (Samsung S2MPS14) - Interface PMIC (Maxim MAX77836, MUIC, fuel-gauge, charger) - RTC of Exynos3250 - ADC of Exynos3250 with NTC thermistor - I2S of Exynos3250 - TMU of Exynos3250 - Secure firmware for Exynos3250 secondary cpu boot - Serial ports of Exynos3250 - gpio-key for power key Signed-off-by: Youngjun Cho Signed-off-by: Chanwoo Choi Signed-off-by: Inki Dae Signed-off-by: Seung-Woo Kim Signed-off-by: Jaehoon Chung Signed-off-by: Kyungmin Park Signed-off-by: Kukjin Kim --- .../devicetree/bindings/arm/samsung-boards.txt | 1 + arch/arm/boot/dts/Makefile | 3 +- arch/arm/boot/dts/exynos3250-monk.dts | 579 +++++++++++++++++++++ 3 files changed, 582 insertions(+), 1 deletion(-) create mode 100644 arch/arm/boot/dts/exynos3250-monk.dts (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/samsung-boards.txt b/Documentation/devicetree/bindings/arm/samsung-boards.txt index 1f8287ea5cc7..43589d2466a7 100644 --- a/Documentation/devicetree/bindings/arm/samsung-boards.txt +++ b/Documentation/devicetree/bindings/arm/samsung-boards.txt @@ -2,6 +2,7 @@ Required root node properties: - compatible = should be one or more of the following. + - "samsung,monk" - for Exynos3250-based Samsung Simband board. - "samsung,rinato" - for Exynos3250-based Samsung Gear2 board. - "samsung,smdkv310" - for Exynos4210-based Samsung SMDKV310 eval board. - "samsung,trats" - for Exynos4210-based Tizen Reference board. diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 91cd4d08b7f1..0e4839ea6cc1 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -67,7 +67,8 @@ dtb-$(CONFIG_ARCH_BRCMSTB) += \ dtb-$(CONFIG_ARCH_DAVINCI) += da850-enbw-cmc.dtb \ da850-evm.dtb dtb-$(CONFIG_ARCH_EFM32) += efm32gg-dk3750.dtb -dtb-$(CONFIG_ARCH_EXYNOS) += exynos3250-rinato.dtb \ +dtb-$(CONFIG_ARCH_EXYNOS) += exynos3250-monk.dtb \ + exynos3250-rinato.dtb \ exynos4210-origen.dtb \ exynos4210-smdkv310.dtb \ exynos4210-trats.dtb \ diff --git a/arch/arm/boot/dts/exynos3250-monk.dts b/arch/arm/boot/dts/exynos3250-monk.dts new file mode 100644 index 000000000000..24822aa98057 --- /dev/null +++ b/arch/arm/boot/dts/exynos3250-monk.dts @@ -0,0 +1,579 @@ +/* + * Samsung's Exynos3250 based Monk board device tree source + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Device tree source file for Samsung's Monk board which is based on + * Samsung Exynos3250 SoC. + * + * 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. + */ + +/dts-v1/; +#include "exynos3250.dtsi" +#include + +/ { + model = "Samsung Monk board"; + compatible = "samsung,monk", "samsung,exynos3250", "samsung,exynos3"; + + aliases { + i2c7 = &i2c_max77836; + }; + + memory { + reg = <0x40000000 0x1ff00000>; + }; + + firmware@0205F000 { + compatible = "samsung,secure-firmware"; + reg = <0x0205F000 0x1000>; + }; + + gpio_keys { + compatible = "gpio-keys"; + + power_key { + interrupt-parent = <&gpx2>; + interrupts = <7 0>; + gpios = <&gpx2 7 1>; + linux,code = ; + label = "power key"; + debounce-interval = <10>; + gpio-key,wakeup; + }; + }; + + vemmc_reg: voltage-regulator-0 { + compatible = "regulator-fixed"; + regulator-name = "V_EMMC_2.8V-fixed"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + gpio = <&gpk0 2 0>; + enable-active-high; + }; + + i2c_max77836: i2c-gpio-0 { + compatible = "i2c-gpio"; + gpios = <&gpd0 2 0>, <&gpd0 3 0>; + #address-cells = <1>; + #size-cells = <0>; + + max77836: subpmic@25 { + compatible = "maxim,max77836"; + interrupt-parent = <&gpx1>; + interrupts = <5 0>; + reg = <0x25>; + wakeup; + + muic: max77836-muic { + compatible = "maxim,max77836-muic"; + }; + + regulators { + compatible = "maxim,max77836-regulator"; + safeout_reg: SAFEOUT { + regulator-name = "SAFEOUT"; + }; + + charger_reg: CHARGER { + regulator-name = "CHARGER"; + regulator-min-microamp = <45000>; + regulator-max-microamp = <475000>; + regulator-boot-on; + }; + + motor_reg: LDO1 { + regulator-name = "MOT_2.7V"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <2700000>; + }; + + LDO2 { + regulator-name = "UNUSED_LDO2"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3950000>; + }; + }; + + charger { + compatible = "maxim,max77836-charger"; + + maxim,constant-uvolt = <4350000>; + maxim,fast-charge-uamp = <225000>; + maxim,eoc-uamp = <7500>; + maxim,ovp-uvolt = <6500000>; + }; + }; + }; +}; + +&adc { + vdd-supply = <&ldo3_reg>; + status = "okay"; + assigned-clocks = <&cmu CLK_SCLK_TSADC>; + assigned-clock-rates = <6000000>; + + thermistor-ap { + compatible = "ntc,ncp15wb473"; + pullup-uv = <1800000>; + pullup-ohm = <100000>; + pulldown-ohm = <100000>; + io-channels = <&adc 0>; + }; + + thermistor-battery { + compatible = "ntc,ncp15wb473"; + pullup-uv = <1800000>; + pullup-ohm = <100000>; + pulldown-ohm = <100000>; + io-channels = <&adc 1>; + }; +}; + +&i2c_0 { + #address-cells = <1>; + #size-cells = <0>; + samsung,i2c-sda-delay = <100>; + samsung,i2c-slave-addr = <0x10>; + samsung,i2c-max-bus-freq = <100000>; + status = "okay"; + + s2mps14_pmic@66 { + compatible = "samsung,s2mps14-pmic"; + interrupt-parent = <&gpx0>; + interrupts = <7 0>; + reg = <0x66>; + wakeup; + + s2mps14_osc: clocks { + compatible = "samsung,s2mps14-clk"; + #clock-cells = <1>; + clock-output-names = "s2mps14_ap", "unused", + "s2mps14_bt"; + }; + + regulators { + ldo1_reg: LDO1 { + regulator-name = "VAP_ALIVE_1.0V"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + }; + + ldo2_reg: LDO2 { + regulator-name = "VAP_M1_1.2V"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + }; + + ldo3_reg: LDO3 { + regulator-name = "VCC_AP_1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + }; + + ldo4_reg: LDO4 { + regulator-name = "VAP_AVDD_PLL1"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + }; + + ldo5_reg: LDO5 { + regulator-name = "VAP_PLL_ISO_1.0V"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + }; + + ldo6_reg: LDO6 { + regulator-name = "VAP_MIPI_1.0V"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + }; + + ldo7_reg: LDO7 { + regulator-name = "VAP_AVDD_1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + }; + + ldo8_reg: LDO8 { + regulator-name = "VAP_USB_3.0V"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + regulator-always-on; + }; + + ldo9_reg: LDO9 { + regulator-name = "V_LPDDR_1.2V"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + }; + + ldo10_reg: LDO10 { + regulator-name = "UNUSED_LDO10"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + }; + + ldo11_reg: LDO11 { + regulator-name = "V_EMMC_1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + samsung,ext-control-gpios = <&gpk0 2 0>; + }; + + ldo12_reg: LDO12 { + regulator-name = "V_EMMC_2.8V"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + samsung,ext-control-gpios = <&gpk0 2 0>; + }; + + ldo13_reg: LDO13 { + regulator-name = "VSENSOR_2.85V"; + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2850000>; + regulator-always-on; + }; + + ldo14_reg: LDO14 { + regulator-name = "UNUSED_LDO14"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + ldo15_reg: LDO15 { + regulator-name = "TSP_AVDD_3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + ldo16_reg: LDO16 { + regulator-name = "LCD_VDD_3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + ldo17_reg: LDO17 { + regulator-name = "UNUSED_LDO17"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + ldo18_reg: LDO18 { + regulator-name = "UNUSED_LDO18"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + ldo19_reg: LDO19 { + regulator-name = "TSP_VDD_1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + ldo20_reg: LDO20 { + regulator-name = "LCD_VDD_1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + ldo21_reg: LDO21 { + regulator-name = "UNUSED_LDO21"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + }; + + ldo22_reg: LDO22 { + regulator-name = "UNUSED_LDO22"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + }; + + ldo23_reg: LDO23 { + regulator-name = "UNUSED_LDO23"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + }; + + ldo24_reg: LDO24 { + regulator-name = "UNUSED_LDO24"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + ldo25_reg: LDO25 { + regulator-name = "UNUSED_LDO25"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + buck1_reg: BUCK1 { + regulator-name = "VAP_MIF_1.0V"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <900000>; + regulator-always-on; + }; + + buck2_reg: BUCK2 { + regulator-name = "VAP_ARM_1.0V"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <1150000>; + regulator-always-on; + }; + + buck3_reg: BUCK3 { + regulator-name = "VAP_INT3D_1.0V"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + }; + + buck4_reg: BUCK4 { + regulator-name = "VCC_SUB_1.95V"; + regulator-min-microvolt = <1950000>; + regulator-max-microvolt = <1950000>; + regulator-always-on; + }; + + buck5_reg: BUCK5 { + regulator-name = "VCC_SUB_1.35V"; + regulator-min-microvolt = <1350000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + }; + }; + }; +}; + +&i2c_1 { + #address-cells = <1>; + #size-cells = <0>; + samsung,i2c-sda-delay = <100>; + samsung,i2c-slave-addr = <0x10>; + samsung,i2c-max-bus-freq = <400000>; + status = "okay"; + + fuelgauge@36 { + compatible = "maxim,max77836-battery"; + interrupt-parent = <&gpx1>; + interrupts = <2 8>; + reg = <0x36>; + }; +}; + +&i2s2 { + status = "okay"; +}; + +&mshc_0 { + #address-cells = <1>; + #size-cells = <0>; + num-slots = <1>; + broken-cd; + non-removable; + cap-mmc-highspeed; + desc-num = <4>; + mmc-hs200-1_8v; + card-detect-delay = <200>; + vmmc-supply = <&vemmc_reg>; + clock-frequency = <100000000>; + clock-freq-min-max = <400000 100000000>; + samsung,dw-mshc-ciu-div = <1>; + samsung,dw-mshc-sdr-timing = <0 1>; + samsung,dw-mshc-ddr-timing = <1 2>; + pinctrl-names = "default"; + pinctrl-0 = <&sd0_cmd &sd0_bus1 &sd0_bus4 &sd0_bus8>; + bus-width = <8>; + status = "okay"; +}; + +&serial_0 { + assigned-clocks = <&cmu CLK_SCLK_UART0>; + assigned-clock-rates = <100000000>; + status = "okay"; +}; + +&serial_1 { + status = "okay"; +}; + +&tmu { + vtmu-supply = <&ldo7_reg>; + status = "okay"; +}; + +&rtc { + clocks = <&cmu CLK_RTC>, <&s2mps14_osc 0>; + clock-names = "rtc", "rtc_src"; + status = "okay"; +}; + +&xusbxti { + clock-frequency = <24000000>; +}; + +&pinctrl_0 { + pinctrl-names = "default"; + pinctrl-0 = <&sleep0>; + + sleep0: sleep-state { + PIN_SLP(gpa0-0, INPUT, DOWN); + PIN_SLP(gpa0-1, INPUT, DOWN); + PIN_SLP(gpa0-2, INPUT, DOWN); + PIN_SLP(gpa0-3, INPUT, DOWN); + PIN_SLP(gpa0-4, INPUT, DOWN); + PIN_SLP(gpa0-5, INPUT, DOWN); + PIN_SLP(gpa0-6, INPUT, DOWN); + PIN_SLP(gpa0-7, INPUT, DOWN); + + PIN_SLP(gpa1-0, INPUT, DOWN); + PIN_SLP(gpa1-1, INPUT, DOWN); + PIN_SLP(gpa1-2, INPUT, DOWN); + PIN_SLP(gpa1-3, INPUT, DOWN); + PIN_SLP(gpa1-4, INPUT, DOWN); + PIN_SLP(gpa1-5, INPUT, DOWN); + + PIN_SLP(gpb-0, PREV, NONE); + PIN_SLP(gpb-1, PREV, NONE); + PIN_SLP(gpb-2, PREV, NONE); + PIN_SLP(gpb-3, PREV, NONE); + PIN_SLP(gpb-4, INPUT, DOWN); + PIN_SLP(gpb-5, INPUT, DOWN); + PIN_SLP(gpb-6, INPUT, DOWN); + PIN_SLP(gpb-7, INPUT, DOWN); + + PIN_SLP(gpc0-0, INPUT, DOWN); + PIN_SLP(gpc0-1, INPUT, DOWN); + PIN_SLP(gpc0-2, INPUT, DOWN); + PIN_SLP(gpc0-3, INPUT, DOWN); + PIN_SLP(gpc0-4, INPUT, DOWN); + + PIN_SLP(gpc1-0, INPUT, DOWN); + PIN_SLP(gpc1-1, INPUT, DOWN); + PIN_SLP(gpc1-2, INPUT, DOWN); + PIN_SLP(gpc1-3, INPUT, DOWN); + PIN_SLP(gpc1-4, INPUT, DOWN); + + PIN_SLP(gpd0-0, INPUT, DOWN); + PIN_SLP(gpd0-1, INPUT, DOWN); + PIN_SLP(gpd0-2, INPUT, NONE); + PIN_SLP(gpd0-3, INPUT, NONE); + + PIN_SLP(gpd1-0, INPUT, NONE); + PIN_SLP(gpd1-1, INPUT, NONE); + PIN_SLP(gpd1-2, INPUT, NONE); + PIN_SLP(gpd1-3, INPUT, NONE); + }; +}; + +&pinctrl_1 { + pinctrl-names = "default"; + pinctrl-0 = <&sleep1>; + + sleep1: sleep-state { + PIN_SLP(gpe0-0, PREV, NONE); + PIN_SLP(gpe0-1, PREV, NONE); + PIN_SLP(gpe0-2, INPUT, DOWN); + PIN_SLP(gpe0-3, INPUT, DOWN); + PIN_SLP(gpe0-4, PREV, NONE); + PIN_SLP(gpe0-5, INPUT, DOWN); + PIN_SLP(gpe0-6, INPUT, DOWN); + PIN_SLP(gpe0-7, INPUT, DOWN); + + PIN_SLP(gpe1-0, INPUT, DOWN); + PIN_SLP(gpe1-1, PREV, NONE); + PIN_SLP(gpe1-2, INPUT, DOWN); + PIN_SLP(gpe1-3, INPUT, DOWN); + PIN_SLP(gpe1-4, INPUT, DOWN); + PIN_SLP(gpe1-5, INPUT, DOWN); + PIN_SLP(gpe1-6, INPUT, DOWN); + PIN_SLP(gpe1-7, INPUT, NONE); + + PIN_SLP(gpe2-0, INPUT, NONE); + PIN_SLP(gpe2-1, INPUT, NONE); + PIN_SLP(gpe2-2, INPUT, NONE); + + PIN_SLP(gpk0-0, INPUT, DOWN); + PIN_SLP(gpk0-1, INPUT, DOWN); + PIN_SLP(gpk0-2, OUT0, NONE); + PIN_SLP(gpk0-3, INPUT, DOWN); + PIN_SLP(gpk0-4, INPUT, DOWN); + PIN_SLP(gpk0-5, INPUT, DOWN); + PIN_SLP(gpk0-6, INPUT, DOWN); + PIN_SLP(gpk0-7, INPUT, DOWN); + + PIN_SLP(gpk1-0, PREV, NONE); + PIN_SLP(gpk1-1, PREV, NONE); + PIN_SLP(gpk1-2, INPUT, DOWN); + PIN_SLP(gpk1-3, PREV, NONE); + PIN_SLP(gpk1-4, PREV, NONE); + PIN_SLP(gpk1-5, PREV, NONE); + PIN_SLP(gpk1-6, PREV, NONE); + + PIN_SLP(gpk2-0, INPUT, DOWN); + PIN_SLP(gpk2-1, INPUT, DOWN); + PIN_SLP(gpk2-2, INPUT, DOWN); + PIN_SLP(gpk2-3, INPUT, DOWN); + PIN_SLP(gpk2-4, INPUT, DOWN); + PIN_SLP(gpk2-5, INPUT, DOWN); + PIN_SLP(gpk2-6, INPUT, DOWN); + + PIN_SLP(gpl0-0, INPUT, DOWN); + PIN_SLP(gpl0-1, INPUT, DOWN); + PIN_SLP(gpl0-2, INPUT, DOWN); + PIN_SLP(gpl0-3, INPUT, DOWN); + + PIN_SLP(gpm0-0, INPUT, DOWN); + PIN_SLP(gpm0-1, INPUT, DOWN); + PIN_SLP(gpm0-2, INPUT, DOWN); + PIN_SLP(gpm0-3, INPUT, DOWN); + PIN_SLP(gpm0-4, INPUT, DOWN); + PIN_SLP(gpm0-5, INPUT, DOWN); + PIN_SLP(gpm0-6, INPUT, DOWN); + PIN_SLP(gpm0-7, INPUT, DOWN); + + PIN_SLP(gpm1-0, INPUT, DOWN); + PIN_SLP(gpm1-1, INPUT, DOWN); + PIN_SLP(gpm1-2, INPUT, DOWN); + PIN_SLP(gpm1-3, INPUT, DOWN); + PIN_SLP(gpm1-4, INPUT, DOWN); + PIN_SLP(gpm1-5, INPUT, DOWN); + PIN_SLP(gpm1-6, INPUT, DOWN); + + PIN_SLP(gpm2-0, INPUT, DOWN); + PIN_SLP(gpm2-1, INPUT, DOWN); + PIN_SLP(gpm2-2, INPUT, DOWN); + PIN_SLP(gpm2-3, INPUT, DOWN); + PIN_SLP(gpm2-4, INPUT, DOWN); + + PIN_SLP(gpm3-0, INPUT, DOWN); + PIN_SLP(gpm3-1, INPUT, DOWN); + PIN_SLP(gpm3-2, INPUT, DOWN); + PIN_SLP(gpm3-3, INPUT, DOWN); + PIN_SLP(gpm3-4, INPUT, DOWN); + PIN_SLP(gpm3-5, INPUT, DOWN); + PIN_SLP(gpm3-6, INPUT, DOWN); + PIN_SLP(gpm3-7, INPUT, DOWN); + + PIN_SLP(gpm4-0, INPUT, DOWN); + PIN_SLP(gpm4-1, INPUT, DOWN); + PIN_SLP(gpm4-2, INPUT, DOWN); + PIN_SLP(gpm4-3, INPUT, DOWN); + PIN_SLP(gpm4-4, INPUT, DOWN); + PIN_SLP(gpm4-5, INPUT, DOWN); + PIN_SLP(gpm4-6, INPUT, DOWN); + PIN_SLP(gpm4-7, INPUT, DOWN); + }; +}; -- cgit v1.2.3-59-g8ed1b From 1888eb75e68caceaab2fe0db820bd6ed574a468f Mon Sep 17 00:00:00 2001 From: Pankaj Dubey Date: Thu, 27 Nov 2014 03:24:45 +0900 Subject: ARM: dts: add sysreg phandle to i2c device nodes for exynos This patch adds syscon based phandle to i2c device nodes of exynos5250 and exynos5420. These phandles will be used to save restore i2c sysreg configuration register during s2r from i2c driver. CC: Rob Herring CC: Randy Dunlap CC: Russell King CC: devicetree@vger.kernel.org CC: linux-doc@vger.kernel.org Signed-off-by: Pankaj Dubey Signed-off-by: Kukjin Kim --- Documentation/devicetree/bindings/i2c/i2c-s3c2410.txt | 1 + arch/arm/boot/dts/exynos5250.dtsi | 4 ++++ arch/arm/boot/dts/exynos5420.dtsi | 4 ++++ 3 files changed, 9 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/i2c/i2c-s3c2410.txt b/Documentation/devicetree/bindings/i2c/i2c-s3c2410.txt index 278de8e64bbf..89b3250f049b 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-s3c2410.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-s3c2410.txt @@ -32,6 +32,7 @@ Optional properties: specified, default value is 0. - samsung,i2c-max-bus-freq: Desired frequency in Hz of the bus. If not specified, the default value in Hz is 100000. + - samsung,sysreg-phandle - handle to syscon used to control the system registers Example: diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi index 012b0211afed..6a32d50070c1 100644 --- a/arch/arm/boot/dts/exynos5250.dtsi +++ b/arch/arm/boot/dts/exynos5250.dtsi @@ -293,6 +293,7 @@ clock-names = "i2c"; pinctrl-names = "default"; pinctrl-0 = <&i2c0_bus>; + samsung,sysreg-phandle = <&sysreg_system_controller>; status = "disabled"; }; @@ -306,6 +307,7 @@ clock-names = "i2c"; pinctrl-names = "default"; pinctrl-0 = <&i2c1_bus>; + samsung,sysreg-phandle = <&sysreg_system_controller>; status = "disabled"; }; @@ -319,6 +321,7 @@ clock-names = "i2c"; pinctrl-names = "default"; pinctrl-0 = <&i2c2_bus>; + samsung,sysreg-phandle = <&sysreg_system_controller>; status = "disabled"; }; @@ -332,6 +335,7 @@ clock-names = "i2c"; pinctrl-names = "default"; pinctrl-0 = <&i2c3_bus>; + samsung,sysreg-phandle = <&sysreg_system_controller>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/exynos5420.dtsi b/arch/arm/boot/dts/exynos5420.dtsi index 8617a031cbc0..90bf4011e319 100644 --- a/arch/arm/boot/dts/exynos5420.dtsi +++ b/arch/arm/boot/dts/exynos5420.dtsi @@ -560,6 +560,7 @@ clock-names = "i2c"; pinctrl-names = "default"; pinctrl-0 = <&i2c0_bus>; + samsung,sysreg-phandle = <&sysreg_system_controller>; status = "disabled"; }; @@ -573,6 +574,7 @@ clock-names = "i2c"; pinctrl-names = "default"; pinctrl-0 = <&i2c1_bus>; + samsung,sysreg-phandle = <&sysreg_system_controller>; status = "disabled"; }; @@ -586,6 +588,7 @@ clock-names = "i2c"; pinctrl-names = "default"; pinctrl-0 = <&i2c2_bus>; + samsung,sysreg-phandle = <&sysreg_system_controller>; status = "disabled"; }; @@ -599,6 +602,7 @@ clock-names = "i2c"; pinctrl-names = "default"; pinctrl-0 = <&i2c3_bus>; + samsung,sysreg-phandle = <&sysreg_system_controller>; status = "disabled"; }; -- cgit v1.2.3-59-g8ed1b From 218094c975e03b3b202663901a3bbf91041fdd20 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Mon, 10 Nov 2014 14:43:51 +0100 Subject: regulator: Document binding for initial and suspend modes Some regulators can run on different operating modes (opmodes). This allows systems to choose the most efficient opmode for each regulator. This patch builds on top of (291d761 regulator: Document binding for regulator suspend state for PM state) adding a regulator-initial-mode DT property to configure at startup the operating mode for regulators that support changing its mode during normal operation and a property regulator-mode to be used in the regulator-state-[mem/disk] nodes for regulators that supports changing its operating mode when the system enters in a suspend state. The set of possible modes that a regulator can operate depends on the hardware capabilities so a list of generic operating modes can't be provided. Instead, each hardware binding should define the list of valid operating modes for the regulators found on that device. Signed-off-by: Javier Martinez Canillas Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/regulator/regulator.txt | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/regulator/regulator.txt b/Documentation/devicetree/bindings/regulator/regulator.txt index 4e7ed762b3bb..abb26b58c83e 100644 --- a/Documentation/devicetree/bindings/regulator/regulator.txt +++ b/Documentation/devicetree/bindings/regulator/regulator.txt @@ -30,6 +30,13 @@ Optional properties: - regulator-off-in-suspend: regulator should be off in suspend state. - regulator-suspend-microvolt: regulator should be set to this voltage in suspend. + - regulator-mode: operating mode in the given suspend state. + The set of possible operating modes depends on the capabilities of + every hardware so the valid modes are documented on each regulator + device tree binding document. +- regulator-initial-mode: initial operating mode. The set of possible operating + modes depends on the capabilities of every hardware so each device binding + documentation explains which values the regulator supports. Deprecated properties: - regulator-compatible: If a regulator chip contains multiple -- cgit v1.2.3-59-g8ed1b From bf77cba95f8c06bbf76869d3bdfb03e18a33e673 Mon Sep 17 00:00:00 2001 From: Padmavathi Venna Date: Thu, 6 Nov 2014 15:21:49 +0530 Subject: spi: s3c64xx: add support for exynos7 SPI controller Exynos7 SPI controller supports only the auto Selection of CS toggle mode and Exynos7 SoC includes six SPI controllers. Add support for these changes in Exynos7 SPI controller driver. Signed-off-by: Padmavathi Venna Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/spi-samsung.txt | 2 +- drivers/spi/Kconfig | 2 +- drivers/spi/spi-s3c64xx.c | 32 ++++++++++++++++++---- 3 files changed, 29 insertions(+), 7 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/spi/spi-samsung.txt b/Documentation/devicetree/bindings/spi/spi-samsung.txt index 1e8a8578148f..6dbdeb3c361a 100644 --- a/Documentation/devicetree/bindings/spi/spi-samsung.txt +++ b/Documentation/devicetree/bindings/spi/spi-samsung.txt @@ -9,7 +9,7 @@ Required SoC Specific Properties: - samsung,s3c2443-spi: for s3c2443, s3c2416 and s3c2450 platforms - samsung,s3c6410-spi: for s3c6410 platforms - samsung,s5pv210-spi: for s5pv210 and s5pc110 platforms - - samsung,exynos4210-spi: for exynos4 and exynos5 platforms + - samsung,exynos7-spi: for exynos7 platforms - reg: physical base address of the controller and length of memory mapped region. diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 84e7c9e6ccef..de2d33dea8b8 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -444,7 +444,7 @@ config SPI_S3C24XX_FIQ config SPI_S3C64XX tristate "Samsung S3C64XX series type SPI" - depends on PLAT_SAMSUNG + depends on (PLAT_SAMSUNG || ARCH_EXYNOS) select S3C64XX_PL080 if ARCH_S3C64XX help SPI driver for Samsung S3C64XX and newer SoCs. diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 480133ee1eb3..59e07cf31598 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -33,8 +33,9 @@ #include -#define MAX_SPI_PORTS 3 +#define MAX_SPI_PORTS 6 #define S3C64XX_SPI_QUIRK_POLL (1 << 0) +#define S3C64XX_SPI_QUIRK_CS_AUTO (1 << 1) /* Registers and bit-fields */ @@ -78,6 +79,7 @@ #define S3C64XX_SPI_SLAVE_AUTO (1<<1) #define S3C64XX_SPI_SLAVE_SIG_INACT (1<<0) +#define S3C64XX_SPI_SLAVE_NSC_CNT_2 (2<<4) #define S3C64XX_SPI_INT_TRAILING_EN (1<<6) #define S3C64XX_SPI_INT_RX_OVERRUN_EN (1<<5) @@ -717,7 +719,12 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master, enable_datapath(sdd, spi, xfer, use_dma); /* Start the signals */ - writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL); + if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO)) + writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL); + else + writel(readl(sdd->regs + S3C64XX_SPI_SLAVE_SEL) + | S3C64XX_SPI_SLAVE_AUTO | S3C64XX_SPI_SLAVE_NSC_CNT_2, + sdd->regs + S3C64XX_SPI_SLAVE_SEL); spin_unlock_irqrestore(&sdd->lock, flags); @@ -866,13 +873,15 @@ static int s3c64xx_spi_setup(struct spi_device *spi) } pm_runtime_put(&sdd->pdev->dev); - writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL); + if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO)) + writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL); return 0; setup_exit: pm_runtime_put(&sdd->pdev->dev); /* setup() returns with device de-selected */ - writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL); + if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO)) + writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL); if (gpio_is_valid(spi->cs_gpio)) gpio_free(spi->cs_gpio); @@ -946,7 +955,8 @@ static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel) sdd->cur_speed = 0; - writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL); + if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO)) + writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL); /* Disable Interrupts - we use Polling if not DMA mode */ writel(0, regs + S3C64XX_SPI_INT_EN); @@ -1341,6 +1351,15 @@ static struct s3c64xx_spi_port_config exynos5440_spi_port_config = { .quirks = S3C64XX_SPI_QUIRK_POLL, }; +static struct s3c64xx_spi_port_config exynos7_spi_port_config = { + .fifo_lvl_mask = { 0x1ff, 0x7F, 0x7F, 0x7F, 0x7F, 0x1ff}, + .rx_lvl_offset = 15, + .tx_st_done = 25, + .high_speed = true, + .clk_from_cmu = true, + .quirks = S3C64XX_SPI_QUIRK_CS_AUTO, +}; + static struct platform_device_id s3c64xx_spi_driver_ids[] = { { .name = "s3c2443-spi", @@ -1374,6 +1393,9 @@ static const struct of_device_id s3c64xx_spi_dt_match[] = { { .compatible = "samsung,exynos5440-spi", .data = (void *)&exynos5440_spi_port_config, }, + { .compatible = "samsung,exynos7-spi", + .data = (void *)&exynos7_spi_port_config, + }, { }, }; MODULE_DEVICE_TABLE(of, s3c64xx_spi_dt_match); -- cgit v1.2.3-59-g8ed1b From bf66c48d026d0ea20a3e04fc32fb470e692707a9 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Tue, 11 Nov 2014 13:04:43 +0100 Subject: regulator: max77802: Document binding for regulator operating modes Some regulators from the max77802 PMIC support to be configured in one of two operating mode: Output ON (normal) and Output On Low Power Mode. Not all regulators support these two modes and for some of them, the mode can be changed while the system is running in normal operation while others only support their mode to be changed on system suspend. Extend the max77802 PMIC binding by documenting the possible operating modes values so the regulators modes can be configured correctly. Signed-off-by: Javier Martinez Canillas Signed-off-by: Mark Brown --- .../devicetree/bindings/regulator/max77802.txt | 35 ++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/regulator/max77802.txt b/Documentation/devicetree/bindings/regulator/max77802.txt index 5aeaffc0f1f0..79e5476444f7 100644 --- a/Documentation/devicetree/bindings/regulator/max77802.txt +++ b/Documentation/devicetree/bindings/regulator/max77802.txt @@ -25,6 +25,29 @@ with their hardware counterparts as follow. The valid names are: example: LDO1, LDO2, LDO35. -BUCKn : for BUCKs, where n can lie in range 1 to 10. example: BUCK1, BUCK5, BUCK10. + +The max77802 regulator supports two different operating modes: Normal and Low +Power Mode. Some regulators support the modes to be changed at startup or by +the consumers during normal operation while others only support to change the +mode during system suspend. The standard regulator suspend states binding can +be used to configure the regulator operating mode. + +The regulators that support the standard "regulator-initial-mode" property, +changing their mode during normal operation are: LDOs 1, 3, 20 and 21. + +The possible values for "regulator-initial-mode" and "regulator-mode" are: + 1: Normal regulator voltage output mode. + 3: Low Power which reduces the quiescent current down to only 1uA + +The list of valid modes are defined in the dt-bindings/clock/maxim,max77802.h +header and can be included by device tree source files. + +The standard "regulator-mode" property can only be used for regulators that +support changing their mode to Low Power Mode during suspend. These regulators +are: BUCKs 2-4 and LDOs 1-35. Also, it only takes effect if the regulator has +been enabled for the given suspend state using "regulator-on-in-suspend" and +has not been disabled for that state using "regulator-off-in-suspend". + Example: max77802@09 { @@ -36,11 +59,23 @@ Example: #size-cells = <0>; regulators { + ldo1_reg: LDO1 { + regulator-name = "vdd_1v0"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + regulator-initial-mode = ; + }; + ldo11_reg: LDO11 { regulator-name = "vdd_ldo11"; regulator-min-microvolt = <1900000>; regulator-max-microvolt = <1900000>; regulator-always-on; + regulator-state-mem { + regulator-on-in-suspend; + regulator-mode = ; + }; }; buck1_reg: BUCK1 { -- cgit v1.2.3-59-g8ed1b From 7a25ec8e481e9c14de13dcacca0d8ee33bfe5f3c Mon Sep 17 00:00:00 2001 From: Mathieu Poirier Date: Mon, 10 Nov 2014 14:06:42 -0700 Subject: coresight: Adding ABI documentation Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- .../ABI/testing/sysfs-bus-coresight-devices-etb10 | 24 ++ .../ABI/testing/sysfs-bus-coresight-devices-etm3x | 253 +++++++++++++++++++++ .../ABI/testing/sysfs-bus-coresight-devices-funnel | 12 + .../ABI/testing/sysfs-bus-coresight-devices-tmc | 8 + MAINTAINERS | 1 + 5 files changed, 298 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-bus-coresight-devices-etb10 create mode 100644 Documentation/ABI/testing/sysfs-bus-coresight-devices-etm3x create mode 100644 Documentation/ABI/testing/sysfs-bus-coresight-devices-funnel create mode 100644 Documentation/ABI/testing/sysfs-bus-coresight-devices-tmc (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-etb10 b/Documentation/ABI/testing/sysfs-bus-coresight-devices-etb10 new file mode 100644 index 000000000000..4b8d6ec92e2b --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-etb10 @@ -0,0 +1,24 @@ +What: /sys/bus/coresight/devices/.etb/enable_sink +Date: November 2014 +KernelVersion: 3.19 +Contact: Mathieu Poirier +Description: (RW) Add/remove a sink from a trace path. There can be multiple + source for a single sink. + ex: echo 1 > /sys/bus/coresight/devices/20010000.etb/enable_sink + +What: /sys/bus/coresight/devices/.etb/status +Date: November 2014 +KernelVersion: 3.19 +Contact: Mathieu Poirier +Description: (R) List various control and status registers. The specific + layout and content is driver specific. + +What: /sys/bus/coresight/devices/.etb/trigger_cntr +Date: November 2014 +KernelVersion: 3.19 +Contact: Mathieu Poirier +Description: (RW) Disables write access to the Trace RAM by stopping the + formatter after a defined number of words have been stored + following the trigger event. The number of 32-bit words written + into the Trace RAM following the trigger event is equal to the + value stored in this register+1 (from ARM ETB-TRM). diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm3x b/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm3x new file mode 100644 index 000000000000..b4d0b99afffb --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm3x @@ -0,0 +1,253 @@ +What: /sys/bus/coresight/devices/.[etm|ptm]/enable_source +Date: November 2014 +KernelVersion: 3.19 +Contact: Mathieu Poirier +Description: (RW) Enable/disable tracing on this specific trace entiry. + Enabling a source implies the source has been configured + properly and a sink has been identidifed for it. The path + of coresight components linking the source to the sink is + configured and managed automatically by the coresight framework. + +What: /sys/bus/coresight/devices/.[etm|ptm]/status +Date: November 2014 +KernelVersion: 3.19 +Contact: Mathieu Poirier +Description: (R) List various control and status registers. The specific + layout and content is driver specific. + +What: /sys/bus/coresight/devices/.[etm|ptm]/addr_idx +Date: November 2014 +KernelVersion: 3.19 +Contact: Mathieu Poirier +Description: Select which address comparator or pair (of comparators) to + work with. + +What: /sys/bus/coresight/devices/.[etm|ptm]/addr_acctype +Date: November 2014 +KernelVersion: 3.19 +Contact: Mathieu Poirier +Description: (RW) Used in conjunction with @addr_idx. Specifies + characteristics about the address comparator being configure, + for example the access type, the kind of instruction to trace, + processor contect ID to trigger on, etc. Individual fields in + the access type register may vary on the version of the trace + entity. + +What: /sys/bus/coresight/devices/.[etm|ptm]/addr_range +Date: November 2014 +KernelVersion: 3.19 +Contact: Mathieu Poirier +Description: (RW) Used in conjunction with @addr_idx. Specifies the range of + addresses to trigger on. Inclusion or exclusion is specificed + in the corresponding access type register. + +What: /sys/bus/coresight/devices/.[etm|ptm]/addr_single +Date: November 2014 +KernelVersion: 3.19 +Contact: Mathieu Poirier +Description: (RW) Used in conjunction with @addr_idx. Specifies the single + address to trigger on, highly influenced by the configuration + options of the corresponding access type register. + +What: /sys/bus/coresight/devices/.[etm|ptm]/addr_start +Date: November 2014 +KernelVersion: 3.19 +Contact: Mathieu Poirier +Description: (RW) Used in conjunction with @addr_idx. Specifies the single + address to start tracing on, highly influenced by the + configuration options of the corresponding access type register. + +What: /sys/bus/coresight/devices/.[etm|ptm]/addr_stop +Date: November 2014 +KernelVersion: 3.19 +Contact: Mathieu Poirier +Description: (RW) Used in conjunction with @addr_idx. Specifies the single + address to stop tracing on, highly influenced by the + configuration options of the corresponding access type register. + +What: /sys/bus/coresight/devices/.[etm|ptm]/cntr_idx +Date: November 2014 +KernelVersion: 3.19 +Contact: Mathieu Poirier +Description: (RW) Specifies the counter to work on. + +What: /sys/bus/coresight/devices/.[etm|ptm]/cntr_event +Date: November 2014 +KernelVersion: 3.19 +Contact: Mathieu Poirier +Description: (RW) Used in conjunction with cntr_idx, give access to the + counter event register. + +What: /sys/bus/coresight/devices/.[etm|ptm]/cntr_val +Date: November 2014 +KernelVersion: 3.19 +Contact: Mathieu Poirier +Description: (RW) Used in conjunction with cntr_idx, give access to the + counter value register. + +What: /sys/bus/coresight/devices/.[etm|ptm]/cntr_rld_val +Date: November 2014 +KernelVersion: 3.19 +Contact: Mathieu Poirier +Description: (RW) Used in conjunction with cntr_idx, give access to the + counter reload value register. + +What: /sys/bus/coresight/devices/.[etm|ptm]/cntr_rld_event +Date: November 2014 +KernelVersion: 3.19 +Contact: Mathieu Poirier +Description: (RW) Used in conjunction with cntr_idx, give access to the + counter reload event register. + +What: /sys/bus/coresight/devices/.[etm|ptm]/ctxid_idx +Date: November 2014 +KernelVersion: 3.19 +Contact: Mathieu Poirier +Description: (RW) Specifies the index of the context ID register to be + selected. + +What: /sys/bus/coresight/devices/.[etm|ptm]/ctxid_mask +Date: November 2014 +KernelVersion: 3.19 +Contact: Mathieu Poirier +Description: (RW) Mask to apply to all the context ID comparator. + +What: /sys/bus/coresight/devices/.[etm|ptm]/ctxid_val +Date: November 2014 +KernelVersion: 3.19 +Contact: Mathieu Poirier +Description: (RW) Used with the ctxid_idx, specify with context ID to trigger + on. + +What: /sys/bus/coresight/devices/.[etm|ptm]/enable_event +Date: November 2014 +KernelVersion: 3.19 +Contact: Mathieu Poirier +Description: (RW) Defines which event triggers a trace. + +What: /sys/bus/coresight/devices/.[etm|ptm]/etmsr +Date: November 2014 +KernelVersion: 3.19 +Contact: Mathieu Poirier +Description: (RW) Gives access to the ETM status register, which holds + programming information and status on certains events. + +What: /sys/bus/coresight/devices/.[etm|ptm]/fifofull_level +Date: November 2014 +KernelVersion: 3.19 +Contact: Mathieu Poirier +Description: (RW) Number of byte left in the fifo before considering it full. + Depending on the tracer's version, can also hold threshold for + data suppression. + +What: /sys/bus/coresight/devices/.[etm|ptm]/mode +Date: November 2014 +KernelVersion: 3.19 +Contact: Mathieu Poirier +Description: (RW) Interface with the driver's 'mode' field, controlling + various aspect of the trace entity such as time stamping, + context ID size and cycle accurate tracing. Driver specific + and bound to change depending on the driver. + +What: /sys/bus/coresight/devices/.[etm|ptm]/nr_addr_cmp +Date: November 2014 +KernelVersion: 3.19 +Contact: Mathieu Poirier +Description: (R) Provides the number of address comparators pairs accessible + on a trace unit, as specified by bit 3:0 of register ETMCCR. + +What: /sys/bus/coresight/devices/.[etm|ptm]/nr_cntr +Date: November 2014 +KernelVersion: 3.19 +Contact: Mathieu Poirier +Description: (R) Provides the number of counters accessible on a trace unit, + as specified by bit 15:13 of register ETMCCR. + +What: /sys/bus/coresight/devices/.[etm|ptm]/nr_ctxid_cmp +Date: November 2014 +KernelVersion: 3.19 +Contact: Mathieu Poirier +Description: (R) Provides the number of context ID comparator available on a + trace unit, as specified by bit 25:24 of register ETMCCR. + +What: /sys/bus/coresight/devices/.[etm|ptm]/reset +Date: November 2014 +KernelVersion: 3.19 +Contact: Mathieu Poirier +Description: (W) Cancels all configuration on a trace unit and set it back + to its boot configuration. + +What: /sys/bus/coresight/devices/.[etm|ptm]/seq_12_event +Date: November 2014 +KernelVersion: 3.19 +Contact: Mathieu Poirier +Description: (RW) Defines the event that causes the sequencer to transition + from state 1 to state 2. + +What: /sys/bus/coresight/devices/.[etm|ptm]/seq_13_event +Date: November 2014 +KernelVersion: 3.19 +Contact: Mathieu Poirier +Description: (RW) Defines the event that causes the sequencer to transition + from state 1 to state 3. + +What: /sys/bus/coresight/devices/.[etm|ptm]/seq_21_event +Date: November 2014 +KernelVersion: 3.19 +Contact: Mathieu Poirier +Description: (RW) Defines the event that causes the sequencer to transition + from state 2 to state 1. + +What: /sys/bus/coresight/devices/.[etm|ptm]/seq_23_event +Date: November 2014 +KernelVersion: 3.19 +Contact: Mathieu Poirier +Description: (RW) Defines the event that causes the sequencer to transition + from state 2 to state 3. + +What: /sys/bus/coresight/devices/.[etm|ptm]/seq_31_event +Date: November 2014 +KernelVersion: 3.19 +Contact: Mathieu Poirier +Description: (RW) Defines the event that causes the sequencer to transition + from state 3 to state 1. + +What: /sys/bus/coresight/devices/.[etm|ptm]/seq_32_event +Date: November 2014 +KernelVersion: 3.19 +Contact: Mathieu Poirier +Description: (RW) Defines the event that causes the sequencer to transition + from state 3 to state 2. + +What: /sys/bus/coresight/devices/.[etm|ptm]/curr_seq_state +Date: November 2014 +KernelVersion: 3.19 +Contact: Mathieu Poirier +Description: (R) Holds the current state of the sequencer. + +What: /sys/bus/coresight/devices/.[etm|ptm]/sync_freq +Date: November 2014 +KernelVersion: 3.19 +Contact: Mathieu Poirier +Description: (RW) Holds the trace synchronization frequency value - must be + programmed with the various implementation behavior in mind. + +What: /sys/bus/coresight/devices/.[etm|ptm]/timestamp_event +Date: November 2014 +KernelVersion: 3.19 +Contact: Mathieu Poirier +Description: (RW) Defines an event that requests the insertion of a timestamp + into the trace stream. + +What: /sys/bus/coresight/devices/.[etm|ptm]/traceid +Date: November 2014 +KernelVersion: 3.19 +Contact: Mathieu Poirier +Description: (RW) Holds the trace ID that will appear in the trace stream + coming from this trace entity. + +What: /sys/bus/coresight/devices/.[etm|ptm]/trigger_event +Date: November 2014 +KernelVersion: 3.19 +Contact: Mathieu Poirier +Description: (RW) Define the event that controls the trigger. diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-funnel b/Documentation/ABI/testing/sysfs-bus-coresight-devices-funnel new file mode 100644 index 000000000000..d75acda5e1b3 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-funnel @@ -0,0 +1,12 @@ +What: /sys/bus/coresight/devices/.funnel/funnel_ctrl +Date: November 2014 +KernelVersion: 3.19 +Contact: Mathieu Poirier +Description: (RW) Enables the slave ports and defines the hold time of the + slave ports. + +What: /sys/bus/coresight/devices/.funnel/priority +Date: November 2014 +KernelVersion: 3.19 +Contact: Mathieu Poirier +Description: (RW) Defines input port priority order. diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tmc b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tmc new file mode 100644 index 000000000000..f38cded5fa22 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tmc @@ -0,0 +1,8 @@ +What: /sys/bus/coresight/devices/.tmc/trigger_cntr +Date: November 2014 +KernelVersion: 3.19 +Contact: Mathieu Poirier +Description: (RW) Disables write access to the Trace RAM by stopping the + formatter after a defined number of words have been stored + following the trigger event. Additional interface for this + driver are expected to be added as it matures. diff --git a/MAINTAINERS b/MAINTAINERS index 39952634be8a..7d180809cae3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -925,6 +925,7 @@ S: Maintained F: drivers/coresight/* F: Documentation/trace/coresight.txt F: Documentation/devicetree/bindings/arm/coresight.txt +F: Documentation/ABI/testing/sysfs-bus-coresight-devices-* ARM/CORGI MACHINE SUPPORT M: Richard Purdie -- cgit v1.2.3-59-g8ed1b From 799656de6f6587cecc0b05477501e41c211a75fa Mon Sep 17 00:00:00 2001 From: Mathieu Poirier Date: Wed, 12 Nov 2014 16:36:59 -0700 Subject: coresight: bindings for coresight drivers Coresight IP blocks allow for the support of HW assisted tracing on ARM SoCs. Bindings for the currently available blocks are presented herein. Signed-off-by: Pratik Patel Signed-off-by: Mathieu Poirier Acked-by: Rob Herring Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/arm/coresight.txt | 204 +++++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/coresight.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/coresight.txt b/Documentation/devicetree/bindings/arm/coresight.txt new file mode 100644 index 000000000000..d790f49066f3 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/coresight.txt @@ -0,0 +1,204 @@ +* CoreSight Components: + +CoreSight components are compliant with the ARM CoreSight architecture +specification and can be connected in various topologies to suit a particular +SoCs tracing needs. These trace components can generally be classified as +sinks, links and sources. Trace data produced by one or more sources flows +through the intermediate links connecting the source to the currently selected +sink. Each CoreSight component device should use these properties to describe +its hardware characteristcs. + +* Required properties for all components *except* non-configurable replicators: + + * compatible: These have to be supplemented with "arm,primecell" as + drivers are using the AMBA bus interface. Possible values include: + - "arm,coresight-etb10", "arm,primecell"; + - "arm,coresight-tpiu", "arm,primecell"; + - "arm,coresight-tmc", "arm,primecell"; + - "arm,coresight-funnel", "arm,primecell"; + - "arm,coresight-etm3x", "arm,primecell"; + + * reg: physical base address and length of the register + set(s) of the component. + + * clocks: the clock associated to this component. + + * clock-names: the name of the clock as referenced by the code. + Since we are using the AMBA framework, the name should be + "apb_pclk". + + * port or ports: The representation of the component's port + layout using the generic DT graph presentation found in + "bindings/graph.txt". + +* Required properties for devices that don't show up on the AMBA bus, such as + non-configurable replicators: + + * compatible: Currently supported value is (note the absence of the + AMBA markee): + - "arm,coresight-replicator" + + * id: a unique number that will identify this replicator. + + * port or ports: same as above. + +* Optional properties for ETM/PTMs: + + * arm,cp14: must be present if the system accesses ETM/PTM management + registers via co-processor 14. + + * cpu: the cpu phandle this ETM/PTM is affined to. When omitted the + source is considered to belong to CPU0. + +* Optional property for TMC: + + * arm,buffer-size: size of contiguous buffer space for TMC ETR + (embedded trace router) + + +Example: + +1. Sinks + etb@20010000 { + compatible = "arm,coresight-etb10", "arm,primecell"; + reg = <0 0x20010000 0 0x1000>; + + coresight-default-sink; + clocks = <&oscclk6a>; + clock-names = "apb_pclk"; + port { + etb_in_port: endpoint@0 { + slave-mode; + remote-endpoint = <&replicator_out_port0>; + }; + }; + }; + + tpiu@20030000 { + compatible = "arm,coresight-tpiu", "arm,primecell"; + reg = <0 0x20030000 0 0x1000>; + + clocks = <&oscclk6a>; + clock-names = "apb_pclk"; + port { + tpiu_in_port: endpoint@0 { + slave-mode; + remote-endpoint = <&replicator_out_port1>; + }; + }; + }; + +2. Links + replicator { + /* non-configurable replicators don't show up on the + * AMBA bus. As such no need to add "arm,primecell". + */ + compatible = "arm,coresight-replicator"; + /* this will show up in debugfs as "0.replicator" */ + id = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + /* replicator output ports */ + port@0 { + reg = <0>; + replicator_out_port0: endpoint { + remote-endpoint = <&etb_in_port>; + }; + }; + + port@1 { + reg = <1>; + replicator_out_port1: endpoint { + remote-endpoint = <&tpiu_in_port>; + }; + }; + + /* replicator input port */ + port@2 { + reg = <0>; + replicator_in_port0: endpoint { + slave-mode; + remote-endpoint = <&funnel_out_port0>; + }; + }; + }; + }; + + funnel@20040000 { + compatible = "arm,coresight-funnel", "arm,primecell"; + reg = <0 0x20040000 0 0x1000>; + + clocks = <&oscclk6a>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + + /* funnel output port */ + port@0 { + reg = <0>; + funnel_out_port0: endpoint { + remote-endpoint = + <&replicator_in_port0>; + }; + }; + + /* funnel input ports */ + port@1 { + reg = <0>; + funnel_in_port0: endpoint { + slave-mode; + remote-endpoint = <&ptm0_out_port>; + }; + }; + + port@2 { + reg = <1>; + funnel_in_port1: endpoint { + slave-mode; + remote-endpoint = <&ptm1_out_port>; + }; + }; + + port@3 { + reg = <2>; + funnel_in_port2: endpoint { + slave-mode; + remote-endpoint = <&etm0_out_port>; + }; + }; + + }; + }; + +3. Sources + ptm@2201c000 { + compatible = "arm,coresight-etm3x", "arm,primecell"; + reg = <0 0x2201c000 0 0x1000>; + + cpu = <&cpu0>; + clocks = <&oscclk6a>; + clock-names = "apb_pclk"; + port { + ptm0_out_port: endpoint { + remote-endpoint = <&funnel_in_port0>; + }; + }; + }; + + ptm@2201d000 { + compatible = "arm,coresight-etm3x", "arm,primecell"; + reg = <0 0x2201d000 0 0x1000>; + + cpu = <&cpu1>; + clocks = <&oscclk6a>; + clock-names = "apb_pclk"; + port { + ptm1_out_port: endpoint { + remote-endpoint = <&funnel_in_port1>; + }; + }; + }; -- cgit v1.2.3-59-g8ed1b From 8841a66aaa7c3b1dfeeb4192d05f2ca86df58f00 Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Mon, 3 Nov 2014 17:05:50 -0600 Subject: mailbox/omap: adapt to the new mailbox framework The OMAP mailbox driver and its existing clients (remoteproc for OMAP4+) are adapted to use the generic mailbox framework. The main changes for the adaptation are: - The tasklet used for Tx is replaced with the state machine from the generic mailbox framework. The workqueue used for processing the received messages stays intact for minimizing the effects on the OMAP mailbox clients. - The existing exported client API, omap_mbox_get, omap_mbox_put and omap_mbox_send_msg are deleted, as the framework provides equivalent functionality. A OMAP-specific omap_mbox_request_channel is added though to support non-DT way of requesting mailboxes. - The OMAP mailbox driver is integrated with the mailbox framework through the proper implementations of mbox_chan_ops, except for .last_tx_done and .peek_data. The OMAP mailbox driver does not need these ops, as it is completely interrupt driven. - The OMAP mailbox driver uses a custom of_xlate controller ops that allows phandles for the pargs specifier instead of indexing to avoid any channel registration order dependencies. - The new framework does not support multiple clients operating on a single channel, so the reference counting logic is simplified. - The remoteproc driver (current client) is adapted to use the new API. The notifier callbacks used within this client is replaced with the regular callbacks from the newer framework. - The exported OMAP mailbox API are limited to omap_mbox_save_ctx, omap_mbox_restore_ctx, omap_mbox_enable_irq & omap_mbox_disable_irq, with the signature modified to take in the new mbox_chan handle instead of the OMAP specific omap_mbox handle. The first 2 will be removed when the OMAP mailbox driver is adapted to runtime_pm. The other exported API omap_mbox_request_channel will be removed once existing legacy users are converted to DT. Signed-off-by: Suman Anna Cc: Ohad Ben-Cohen Signed-off-by: Jassi Brar --- .../devicetree/bindings/mailbox/omap-mailbox.txt | 23 ++ drivers/mailbox/omap-mailbox.c | 346 ++++++++++++--------- drivers/remoteproc/omap_remoteproc.c | 51 +-- include/linux/omap-mailbox.h | 16 +- 4 files changed, 256 insertions(+), 180 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mailbox/omap-mailbox.txt b/Documentation/devicetree/bindings/mailbox/omap-mailbox.txt index 48edc4b92afb..d1a043339c11 100644 --- a/Documentation/devicetree/bindings/mailbox/omap-mailbox.txt +++ b/Documentation/devicetree/bindings/mailbox/omap-mailbox.txt @@ -43,6 +43,9 @@ Required properties: device. The format is dependent on which interrupt controller the OMAP device uses - ti,hwmods: Name of the hwmod associated with the mailbox +- #mbox-cells: Common mailbox binding property to identify the number + of cells required for the mailbox specifier. Should be + 1 - ti,mbox-num-users: Number of targets (processor devices) that the mailbox device can interrupt - ti,mbox-num-fifos: Number of h/w fifo queues within the mailbox IP block @@ -72,6 +75,18 @@ data that represent the following: Cell #3 (usr_id) - mailbox user id for identifying the interrupt line associated with generating a tx/rx fifo interrupt. +Mailbox Users: +============== +A device needing to communicate with a target processor device should specify +them using the common mailbox binding properties, "mboxes" and the optional +"mbox-names" (please see Documentation/devicetree/bindings/mailbox/mailbox.txt +for details). Each value of the mboxes property should contain a phandle to the +mailbox controller device node and an args specifier that will be the phandle to +the intended sub-mailbox child node to be used for communication. The equivalent +"mbox-names" property value can be used to give a name to the communication channel +to be used by the client user. + + Example: -------- @@ -81,6 +96,7 @@ mailbox: mailbox@4a0f4000 { reg = <0x4a0f4000 0x200>; interrupts = ; ti,hwmods = "mailbox"; + #mbox-cells = <1>; ti,mbox-num-users = <3>; ti,mbox-num-fifos = <8>; mbox_ipu: mbox_ipu { @@ -93,12 +109,19 @@ mailbox: mailbox@4a0f4000 { }; }; +dsp { + ... + mboxes = <&mailbox &mbox_dsp>; + ... +}; + /* AM33xx */ mailbox: mailbox@480C8000 { compatible = "ti,omap4-mailbox"; reg = <0x480C8000 0x200>; interrupts = <77>; ti,hwmods = "mailbox"; + #mbox-cells = <1>; ti,mbox-num-users = <4>; ti,mbox-num-fifos = <8>; mbox_wkupm3: wkup_m3 { diff --git a/drivers/mailbox/omap-mailbox.c b/drivers/mailbox/omap-mailbox.c index bcc7ee129276..66b83ca94dcf 100644 --- a/drivers/mailbox/omap-mailbox.c +++ b/drivers/mailbox/omap-mailbox.c @@ -29,13 +29,14 @@ #include #include #include -#include #include #include #include #include #include #include +#include +#include #define MAILBOX_REVISION 0x000 #define MAILBOX_MESSAGE(m) (0x040 + 4 * (m)) @@ -80,7 +81,6 @@ struct omap_mbox_queue { spinlock_t lock; struct kfifo fifo; struct work_struct work; - struct tasklet_struct tasklet; struct omap_mbox *mbox; bool full; }; @@ -92,6 +92,7 @@ struct omap_mbox_device { u32 num_users; u32 num_fifos; struct omap_mbox **mboxes; + struct mbox_controller controller; struct list_head elem; }; @@ -110,15 +111,14 @@ struct omap_mbox_fifo_info { struct omap_mbox { const char *name; int irq; - struct omap_mbox_queue *txq, *rxq; + struct omap_mbox_queue *rxq; struct device *dev; struct omap_mbox_device *parent; struct omap_mbox_fifo tx_fifo; struct omap_mbox_fifo rx_fifo; u32 ctx[OMAP4_MBOX_NR_REGS]; u32 intr_type; - int use_count; - struct blocking_notifier_head notifier; + struct mbox_chan *chan; }; /* global variables for the mailbox devices */ @@ -129,6 +129,14 @@ static unsigned int mbox_kfifo_size = CONFIG_OMAP_MBOX_KFIFO_SIZE; module_param(mbox_kfifo_size, uint, S_IRUGO); MODULE_PARM_DESC(mbox_kfifo_size, "Size of omap's mailbox kfifo (bytes)"); +static struct omap_mbox *mbox_chan_to_omap_mbox(struct mbox_chan *chan) +{ + if (!chan || !chan->con_priv) + return NULL; + + return (struct omap_mbox *)chan->con_priv; +} + static inline unsigned int mbox_read_reg(struct omap_mbox_device *mdev, size_t ofs) { @@ -194,41 +202,14 @@ static int is_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) return (int)(enable & status & bit); } -/* - * message sender - */ -int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg) -{ - struct omap_mbox_queue *mq = mbox->txq; - int ret = 0, len; - - spin_lock_bh(&mq->lock); - - if (kfifo_avail(&mq->fifo) < sizeof(msg)) { - ret = -ENOMEM; - goto out; - } - - if (kfifo_is_empty(&mq->fifo) && !mbox_fifo_full(mbox)) { - mbox_fifo_write(mbox, msg); - goto out; - } - - len = kfifo_in(&mq->fifo, (unsigned char *)&msg, sizeof(msg)); - WARN_ON(len != sizeof(msg)); - - tasklet_schedule(&mbox->txq->tasklet); - -out: - spin_unlock_bh(&mq->lock); - return ret; -} -EXPORT_SYMBOL(omap_mbox_msg_send); - -void omap_mbox_save_ctx(struct omap_mbox *mbox) +void omap_mbox_save_ctx(struct mbox_chan *chan) { int i; int nr_regs; + struct omap_mbox *mbox = mbox_chan_to_omap_mbox(chan); + + if (WARN_ON(!mbox)) + return; if (mbox->intr_type) nr_regs = OMAP4_MBOX_NR_REGS; @@ -243,10 +224,14 @@ void omap_mbox_save_ctx(struct omap_mbox *mbox) } EXPORT_SYMBOL(omap_mbox_save_ctx); -void omap_mbox_restore_ctx(struct omap_mbox *mbox) +void omap_mbox_restore_ctx(struct mbox_chan *chan) { int i; int nr_regs; + struct omap_mbox *mbox = mbox_chan_to_omap_mbox(chan); + + if (WARN_ON(!mbox)) + return; if (mbox->intr_type) nr_regs = OMAP4_MBOX_NR_REGS; @@ -254,14 +239,13 @@ void omap_mbox_restore_ctx(struct omap_mbox *mbox) nr_regs = MBOX_NR_REGS; for (i = 0; i < nr_regs; i++) { mbox_write_reg(mbox->parent, mbox->ctx[i], i * sizeof(u32)); - dev_dbg(mbox->dev, "%s: [%02x] %08x\n", __func__, i, mbox->ctx[i]); } } EXPORT_SYMBOL(omap_mbox_restore_ctx); -void omap_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) +static void _omap_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) { u32 l; struct omap_mbox_fifo *fifo = (irq == IRQ_TX) ? @@ -273,9 +257,8 @@ void omap_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) l |= bit; mbox_write_reg(mbox->parent, l, irqenable); } -EXPORT_SYMBOL(omap_mbox_enable_irq); -void omap_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) +static void _omap_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) { struct omap_mbox_fifo *fifo = (irq == IRQ_TX) ? &mbox->tx_fifo : &mbox->rx_fifo; @@ -291,28 +274,28 @@ void omap_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) mbox_write_reg(mbox->parent, bit, irqdisable); } -EXPORT_SYMBOL(omap_mbox_disable_irq); -static void mbox_tx_tasklet(unsigned long tx_data) +void omap_mbox_enable_irq(struct mbox_chan *chan, omap_mbox_irq_t irq) { - struct omap_mbox *mbox = (struct omap_mbox *)tx_data; - struct omap_mbox_queue *mq = mbox->txq; - mbox_msg_t msg; - int ret; + struct omap_mbox *mbox = mbox_chan_to_omap_mbox(chan); - while (kfifo_len(&mq->fifo)) { - if (mbox_fifo_full(mbox)) { - omap_mbox_enable_irq(mbox, IRQ_TX); - break; - } + if (WARN_ON(!mbox)) + return; - ret = kfifo_out(&mq->fifo, (unsigned char *)&msg, - sizeof(msg)); - WARN_ON(ret != sizeof(msg)); + _omap_mbox_enable_irq(mbox, irq); +} +EXPORT_SYMBOL(omap_mbox_enable_irq); - mbox_fifo_write(mbox, msg); - } +void omap_mbox_disable_irq(struct mbox_chan *chan, omap_mbox_irq_t irq) +{ + struct omap_mbox *mbox = mbox_chan_to_omap_mbox(chan); + + if (WARN_ON(!mbox)) + return; + + _omap_mbox_disable_irq(mbox, irq); } +EXPORT_SYMBOL(omap_mbox_disable_irq); /* * Message receiver(workqueue) @@ -328,12 +311,11 @@ static void mbox_rx_work(struct work_struct *work) len = kfifo_out(&mq->fifo, (unsigned char *)&msg, sizeof(msg)); WARN_ON(len != sizeof(msg)); - blocking_notifier_call_chain(&mq->mbox->notifier, len, - (void *)msg); + mbox_chan_received_data(mq->mbox->chan, (void *)msg); spin_lock_irq(&mq->lock); if (mq->full) { mq->full = false; - omap_mbox_enable_irq(mq->mbox, IRQ_RX); + _omap_mbox_enable_irq(mq->mbox, IRQ_RX); } spin_unlock_irq(&mq->lock); } @@ -344,9 +326,9 @@ static void mbox_rx_work(struct work_struct *work) */ static void __mbox_tx_interrupt(struct omap_mbox *mbox) { - omap_mbox_disable_irq(mbox, IRQ_TX); + _omap_mbox_disable_irq(mbox, IRQ_TX); ack_mbox_irq(mbox, IRQ_TX); - tasklet_schedule(&mbox->txq->tasklet); + mbox_chan_txdone(mbox->chan, 0); } static void __mbox_rx_interrupt(struct omap_mbox *mbox) @@ -357,7 +339,7 @@ static void __mbox_rx_interrupt(struct omap_mbox *mbox) while (!mbox_fifo_empty(mbox)) { if (unlikely(kfifo_avail(&mq->fifo) < sizeof(msg))) { - omap_mbox_disable_irq(mbox, IRQ_RX); + _omap_mbox_disable_irq(mbox, IRQ_RX); mq->full = true; goto nomem; } @@ -388,11 +370,13 @@ static irqreturn_t mbox_interrupt(int irq, void *p) } static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox, - void (*work) (struct work_struct *), - void (*tasklet)(unsigned long)) + void (*work)(struct work_struct *)) { struct omap_mbox_queue *mq; + if (!work) + return NULL; + mq = kzalloc(sizeof(struct omap_mbox_queue), GFP_KERNEL); if (!mq) return NULL; @@ -402,12 +386,9 @@ static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox, if (kfifo_alloc(&mq->fifo, mbox_kfifo_size, GFP_KERNEL)) goto error; - if (work) - INIT_WORK(&mq->work, work); - - if (tasklet) - tasklet_init(&mq->tasklet, tasklet, (unsigned long)mbox); + INIT_WORK(&mq->work, work); return mq; + error: kfree(mq); return NULL; @@ -423,71 +404,35 @@ static int omap_mbox_startup(struct omap_mbox *mbox) { int ret = 0; struct omap_mbox_queue *mq; - struct omap_mbox_device *mdev = mbox->parent; - mutex_lock(&mdev->cfg_lock); - ret = pm_runtime_get_sync(mdev->dev); - if (unlikely(ret < 0)) - goto fail_startup; - - if (!mbox->use_count++) { - mq = mbox_queue_alloc(mbox, NULL, mbox_tx_tasklet); - if (!mq) { - ret = -ENOMEM; - goto fail_alloc_txq; - } - mbox->txq = mq; + mq = mbox_queue_alloc(mbox, mbox_rx_work); + if (!mq) + return -ENOMEM; + mbox->rxq = mq; + mq->mbox = mbox; + + ret = request_irq(mbox->irq, mbox_interrupt, IRQF_SHARED, + mbox->name, mbox); + if (unlikely(ret)) { + pr_err("failed to register mailbox interrupt:%d\n", ret); + goto fail_request_irq; + } - mq = mbox_queue_alloc(mbox, mbox_rx_work, NULL); - if (!mq) { - ret = -ENOMEM; - goto fail_alloc_rxq; - } - mbox->rxq = mq; - mq->mbox = mbox; - ret = request_irq(mbox->irq, mbox_interrupt, IRQF_SHARED, - mbox->name, mbox); - if (unlikely(ret)) { - pr_err("failed to register mailbox interrupt:%d\n", - ret); - goto fail_request_irq; - } + _omap_mbox_enable_irq(mbox, IRQ_RX); - omap_mbox_enable_irq(mbox, IRQ_RX); - } - mutex_unlock(&mdev->cfg_lock); return 0; fail_request_irq: mbox_queue_free(mbox->rxq); -fail_alloc_rxq: - mbox_queue_free(mbox->txq); -fail_alloc_txq: - pm_runtime_put_sync(mdev->dev); - mbox->use_count--; -fail_startup: - mutex_unlock(&mdev->cfg_lock); return ret; } static void omap_mbox_fini(struct omap_mbox *mbox) { - struct omap_mbox_device *mdev = mbox->parent; - - mutex_lock(&mdev->cfg_lock); - - if (!--mbox->use_count) { - omap_mbox_disable_irq(mbox, IRQ_RX); - free_irq(mbox->irq, mbox); - tasklet_kill(&mbox->txq->tasklet); - flush_work(&mbox->rxq->work); - mbox_queue_free(mbox->txq); - mbox_queue_free(mbox->rxq); - } - - pm_runtime_put_sync(mdev->dev); - - mutex_unlock(&mdev->cfg_lock); + _omap_mbox_disable_irq(mbox, IRQ_RX); + free_irq(mbox->irq, mbox); + flush_work(&mbox->rxq->work); + mbox_queue_free(mbox->rxq); } static struct omap_mbox *omap_mbox_device_find(struct omap_mbox_device *mdev, @@ -509,42 +454,55 @@ static struct omap_mbox *omap_mbox_device_find(struct omap_mbox_device *mdev, return mbox; } -struct omap_mbox *omap_mbox_get(const char *name, struct notifier_block *nb) +struct mbox_chan *omap_mbox_request_channel(struct mbox_client *cl, + const char *chan_name) { + struct device *dev = cl->dev; struct omap_mbox *mbox = NULL; struct omap_mbox_device *mdev; + struct mbox_chan *chan; + unsigned long flags; int ret; + if (!dev) + return ERR_PTR(-ENODEV); + + if (dev->of_node) { + pr_err("%s: please use mbox_request_channel(), this API is supported only for OMAP non-DT usage\n", + __func__); + return ERR_PTR(-ENODEV); + } + mutex_lock(&omap_mbox_devices_lock); list_for_each_entry(mdev, &omap_mbox_devices, elem) { - mbox = omap_mbox_device_find(mdev, name); + mbox = omap_mbox_device_find(mdev, chan_name); if (mbox) break; } mutex_unlock(&omap_mbox_devices_lock); - if (!mbox) + if (!mbox || !mbox->chan) return ERR_PTR(-ENOENT); - if (nb) - blocking_notifier_chain_register(&mbox->notifier, nb); + chan = mbox->chan; + spin_lock_irqsave(&chan->lock, flags); + chan->msg_free = 0; + chan->msg_count = 0; + chan->active_req = NULL; + chan->cl = cl; + init_completion(&chan->tx_complete); + spin_unlock_irqrestore(&chan->lock, flags); - ret = omap_mbox_startup(mbox); + ret = chan->mbox->ops->startup(chan); if (ret) { - blocking_notifier_chain_unregister(&mbox->notifier, nb); - return ERR_PTR(-ENODEV); + pr_err("Unable to startup the chan (%d)\n", ret); + mbox_free_channel(chan); + chan = ERR_PTR(ret); } - return mbox; -} -EXPORT_SYMBOL(omap_mbox_get); - -void omap_mbox_put(struct omap_mbox *mbox, struct notifier_block *nb) -{ - blocking_notifier_chain_unregister(&mbox->notifier, nb); - omap_mbox_fini(mbox); + return chan; } -EXPORT_SYMBOL(omap_mbox_put); +EXPORT_SYMBOL(omap_mbox_request_channel); static struct class omap_mbox_class = { .name = "mbox", }; @@ -560,25 +518,25 @@ static int omap_mbox_register(struct omap_mbox_device *mdev) mboxes = mdev->mboxes; for (i = 0; mboxes[i]; i++) { struct omap_mbox *mbox = mboxes[i]; - mbox->dev = device_create(&omap_mbox_class, - mdev->dev, 0, mbox, "%s", mbox->name); + mbox->dev = device_create(&omap_mbox_class, mdev->dev, + 0, mbox, "%s", mbox->name); if (IS_ERR(mbox->dev)) { ret = PTR_ERR(mbox->dev); goto err_out; } - - BLOCKING_INIT_NOTIFIER_HEAD(&mbox->notifier); } mutex_lock(&omap_mbox_devices_lock); list_add(&mdev->elem, &omap_mbox_devices); mutex_unlock(&omap_mbox_devices_lock); - return 0; + ret = mbox_controller_register(&mdev->controller); err_out: - while (i--) - device_unregister(mboxes[i]->dev); + if (ret) { + while (i--) + device_unregister(mboxes[i]->dev); + } return ret; } @@ -594,12 +552,64 @@ static int omap_mbox_unregister(struct omap_mbox_device *mdev) list_del(&mdev->elem); mutex_unlock(&omap_mbox_devices_lock); + mbox_controller_unregister(&mdev->controller); + mboxes = mdev->mboxes; for (i = 0; mboxes[i]; i++) device_unregister(mboxes[i]->dev); return 0; } +static int omap_mbox_chan_startup(struct mbox_chan *chan) +{ + struct omap_mbox *mbox = mbox_chan_to_omap_mbox(chan); + struct omap_mbox_device *mdev = mbox->parent; + int ret = 0; + + mutex_lock(&mdev->cfg_lock); + pm_runtime_get_sync(mdev->dev); + ret = omap_mbox_startup(mbox); + if (ret) + pm_runtime_put_sync(mdev->dev); + mutex_unlock(&mdev->cfg_lock); + return ret; +} + +static void omap_mbox_chan_shutdown(struct mbox_chan *chan) +{ + struct omap_mbox *mbox = mbox_chan_to_omap_mbox(chan); + struct omap_mbox_device *mdev = mbox->parent; + + mutex_lock(&mdev->cfg_lock); + omap_mbox_fini(mbox); + pm_runtime_put_sync(mdev->dev); + mutex_unlock(&mdev->cfg_lock); +} + +static int omap_mbox_chan_send_data(struct mbox_chan *chan, void *data) +{ + struct omap_mbox *mbox = mbox_chan_to_omap_mbox(chan); + int ret = -EBUSY; + + if (!mbox) + return -EINVAL; + + if (!mbox_fifo_full(mbox)) { + mbox_fifo_write(mbox, (mbox_msg_t)data); + ret = 0; + } + + /* always enable the interrupt */ + _omap_mbox_enable_irq(mbox, IRQ_TX); + return ret; +} + +static struct mbox_chan_ops omap_mbox_chan_ops = { + .startup = omap_mbox_chan_startup, + .send_data = omap_mbox_chan_send_data, + .shutdown = omap_mbox_chan_shutdown, +}; + static const struct of_device_id omap_mailbox_of_match[] = { { .compatible = "ti,omap2-mailbox", @@ -619,10 +629,35 @@ static const struct of_device_id omap_mailbox_of_match[] = { }; MODULE_DEVICE_TABLE(of, omap_mailbox_of_match); +static struct mbox_chan *omap_mbox_of_xlate(struct mbox_controller *controller, + const struct of_phandle_args *sp) +{ + phandle phandle = sp->args[0]; + struct device_node *node; + struct omap_mbox_device *mdev; + struct omap_mbox *mbox; + + mdev = container_of(controller, struct omap_mbox_device, controller); + if (WARN_ON(!mdev)) + return NULL; + + node = of_find_node_by_phandle(phandle); + if (!node) { + pr_err("%s: could not find node phandle 0x%x\n", + __func__, phandle); + return NULL; + } + + mbox = omap_mbox_device_find(mdev, node->name); + of_node_put(node); + return mbox ? mbox->chan : NULL; +} + static int omap_mbox_probe(struct platform_device *pdev) { struct resource *mem; int ret; + struct mbox_chan *chnls; struct omap_mbox **list, *mbox, *mboxblk; struct omap_mbox_pdata *pdata = pdev->dev.platform_data; struct omap_mbox_dev_info *info = NULL; @@ -727,6 +762,11 @@ static int omap_mbox_probe(struct platform_device *pdev) if (!list) return -ENOMEM; + chnls = devm_kzalloc(&pdev->dev, (info_count + 1) * sizeof(*chnls), + GFP_KERNEL); + if (!chnls) + return -ENOMEM; + mboxblk = devm_kzalloc(&pdev->dev, info_count * sizeof(*mbox), GFP_KERNEL); if (!mboxblk) @@ -758,6 +798,8 @@ static int omap_mbox_probe(struct platform_device *pdev) mbox->irq = platform_get_irq(pdev, finfo->tx_irq); if (mbox->irq < 0) return mbox->irq; + mbox->chan = &chnls[i]; + chnls[i].con_priv = mbox; list[i] = mbox++; } @@ -766,6 +808,14 @@ static int omap_mbox_probe(struct platform_device *pdev) mdev->num_users = num_users; mdev->num_fifos = num_fifos; mdev->mboxes = list; + + /* OMAP does not have a Tx-Done IRQ, but rather a Tx-Ready IRQ */ + mdev->controller.txdone_irq = true; + mdev->controller.dev = mdev->dev; + mdev->controller.ops = &omap_mbox_chan_ops; + mdev->controller.chans = chnls; + mdev->controller.num_chans = info_count; + mdev->controller.of_xlate = omap_mbox_of_xlate; ret = omap_mbox_register(mdev); if (ret) return ret; diff --git a/drivers/remoteproc/omap_remoteproc.c b/drivers/remoteproc/omap_remoteproc.c index 51689721ea7a..cf92f6e7c5dc 100644 --- a/drivers/remoteproc/omap_remoteproc.c +++ b/drivers/remoteproc/omap_remoteproc.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -36,20 +37,19 @@ /** * struct omap_rproc - omap remote processor state - * @mbox: omap mailbox handle - * @nb: notifier block that will be invoked on inbound mailbox messages + * @mbox: mailbox channel handle + * @client: mailbox client to request the mailbox channel * @rproc: rproc handle */ struct omap_rproc { - struct omap_mbox *mbox; - struct notifier_block nb; + struct mbox_chan *mbox; + struct mbox_client client; struct rproc *rproc; }; /** * omap_rproc_mbox_callback() - inbound mailbox message handler - * @this: notifier block - * @index: unused + * @client: mailbox client pointer used for requesting the mailbox channel * @data: mailbox payload * * This handler is invoked by omap's mailbox driver whenever a mailbox @@ -61,13 +61,13 @@ struct omap_rproc { * that indicates different events. Those values are deliberately very * big so they don't coincide with virtqueue indices. */ -static int omap_rproc_mbox_callback(struct notifier_block *this, - unsigned long index, void *data) +static void omap_rproc_mbox_callback(struct mbox_client *client, void *data) { - mbox_msg_t msg = (mbox_msg_t) data; - struct omap_rproc *oproc = container_of(this, struct omap_rproc, nb); + struct omap_rproc *oproc = container_of(client, struct omap_rproc, + client); struct device *dev = oproc->rproc->dev.parent; const char *name = oproc->rproc->name; + u32 msg = (u32)data; dev_dbg(dev, "mbox msg: 0x%x\n", msg); @@ -84,8 +84,6 @@ static int omap_rproc_mbox_callback(struct notifier_block *this, if (rproc_vq_interrupt(oproc->rproc, msg) == IRQ_NONE) dev_dbg(dev, "no message was found in vqid %d\n", msg); } - - return NOTIFY_DONE; } /* kick a virtqueue */ @@ -96,8 +94,8 @@ static void omap_rproc_kick(struct rproc *rproc, int vqid) int ret; /* send the index of the triggered virtqueue in the mailbox payload */ - ret = omap_mbox_msg_send(oproc->mbox, vqid); - if (ret) + ret = mbox_send_message(oproc->mbox, (void *)vqid); + if (ret < 0) dev_err(dev, "omap_mbox_msg_send failed: %d\n", ret); } @@ -115,17 +113,22 @@ static int omap_rproc_start(struct rproc *rproc) struct platform_device *pdev = to_platform_device(dev); struct omap_rproc_pdata *pdata = pdev->dev.platform_data; int ret; + struct mbox_client *client = &oproc->client; if (pdata->set_bootaddr) pdata->set_bootaddr(rproc->bootaddr); - oproc->nb.notifier_call = omap_rproc_mbox_callback; + client->dev = dev; + client->tx_done = NULL; + client->rx_callback = omap_rproc_mbox_callback; + client->tx_block = false; + client->knows_txdone = false; - /* every omap rproc is assigned a mailbox instance for messaging */ - oproc->mbox = omap_mbox_get(pdata->mbox_name, &oproc->nb); + oproc->mbox = omap_mbox_request_channel(client, pdata->mbox_name); if (IS_ERR(oproc->mbox)) { - ret = PTR_ERR(oproc->mbox); - dev_err(dev, "omap_mbox_get failed: %d\n", ret); + ret = -EBUSY; + dev_err(dev, "mbox_request_channel failed: %ld\n", + PTR_ERR(oproc->mbox)); return ret; } @@ -136,9 +139,9 @@ static int omap_rproc_start(struct rproc *rproc) * Note that the reply will _not_ arrive immediately: this message * will wait in the mailbox fifo until the remote processor is booted. */ - ret = omap_mbox_msg_send(oproc->mbox, RP_MBOX_ECHO_REQUEST); - if (ret) { - dev_err(dev, "omap_mbox_get failed: %d\n", ret); + ret = mbox_send_message(oproc->mbox, (void *)RP_MBOX_ECHO_REQUEST); + if (ret < 0) { + dev_err(dev, "mbox_send_message failed: %d\n", ret); goto put_mbox; } @@ -151,7 +154,7 @@ static int omap_rproc_start(struct rproc *rproc) return 0; put_mbox: - omap_mbox_put(oproc->mbox, &oproc->nb); + mbox_free_channel(oproc->mbox); return ret; } @@ -168,7 +171,7 @@ static int omap_rproc_stop(struct rproc *rproc) if (ret) return ret; - omap_mbox_put(oproc->mbox, &oproc->nb); + mbox_free_channel(oproc->mbox); return 0; } diff --git a/include/linux/omap-mailbox.h b/include/linux/omap-mailbox.h index f8322d9cd235..587bbdd31f5a 100644 --- a/include/linux/omap-mailbox.h +++ b/include/linux/omap-mailbox.h @@ -10,20 +10,20 @@ #define OMAP_MAILBOX_H typedef u32 mbox_msg_t; -struct omap_mbox; typedef int __bitwise omap_mbox_irq_t; #define IRQ_TX ((__force omap_mbox_irq_t) 1) #define IRQ_RX ((__force omap_mbox_irq_t) 2) -int omap_mbox_msg_send(struct omap_mbox *, mbox_msg_t msg); +struct mbox_chan; +struct mbox_client; -struct omap_mbox *omap_mbox_get(const char *, struct notifier_block *nb); -void omap_mbox_put(struct omap_mbox *mbox, struct notifier_block *nb); +struct mbox_chan *omap_mbox_request_channel(struct mbox_client *cl, + const char *chan_name); -void omap_mbox_save_ctx(struct omap_mbox *mbox); -void omap_mbox_restore_ctx(struct omap_mbox *mbox); -void omap_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq); -void omap_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq); +void omap_mbox_save_ctx(struct mbox_chan *chan); +void omap_mbox_restore_ctx(struct mbox_chan *chan); +void omap_mbox_enable_irq(struct mbox_chan *chan, omap_mbox_irq_t irq); +void omap_mbox_disable_irq(struct mbox_chan *chan, omap_mbox_irq_t irq); #endif /* OMAP_MAILBOX_H */ -- cgit v1.2.3-59-g8ed1b From d0c3d95ae27a54f283a7acc5ead5bd8a15441a92 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Fri, 14 Nov 2014 15:45:53 +0000 Subject: pinctrl: tz1090-pinctrl.txt: Fix typo in binding Fix a typo, s/which which/which/ in the img,tz1090-pinctrl.txt binding. Signed-off-by: James Hogan Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org Signed-off-by: Linus Walleij --- Documentation/devicetree/bindings/pinctrl/img,tz1090-pinctrl.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/pinctrl/img,tz1090-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/img,tz1090-pinctrl.txt index 4b27c99f7f9d..0a3f50217a17 100644 --- a/Documentation/devicetree/bindings/pinctrl/img,tz1090-pinctrl.txt +++ b/Documentation/devicetree/bindings/pinctrl/img,tz1090-pinctrl.txt @@ -67,7 +67,7 @@ Valid values for pin and group names are: They also all support the some form of muxing. Any pins which are contained in one of the mux groups (see below) can be muxed only to the functions supported by the mux group. All other pins can be muxed to the "perip" - function which which enables them with their intended peripheral. + function which enables them with their intended peripheral. Different pins in the same mux group cannot be muxed to different functions, however it is possible to mux only a subset of the pins in a mux group to a -- cgit v1.2.3-59-g8ed1b From ae76f13b9b4931cf143670524a6c68b891fd30bc Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Sun, 16 Nov 2014 21:14:14 +0100 Subject: pinctrl: meson: add device tree bindings documentation Add device tree bindings documentation for Amlogic Meson pin and GPIO controller. Signed-off-by: Beniamino Galvani Signed-off-by: Linus Walleij --- .../devicetree/bindings/pinctrl/meson,pinctrl.txt | 96 ++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt new file mode 100644 index 000000000000..17e7240c6998 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt @@ -0,0 +1,96 @@ +== Amlogic Meson pinmux controller == + +Required properties for the root node: + - compatible: "amlogic,meson8-pinctrl" + - reg: address and size of registers controlling irq functionality + +=== GPIO sub-nodes === + +The 2 power domains of the controller (regular and always-on) are +represented as sub-nodes and each of them acts as a GPIO controller. + +Required properties for sub-nodes are: + - reg: should contain address and size for mux, pull-enable, pull and + gpio register sets + - reg-names: an array of strings describing the "reg" entries. Must + contain "mux", "pull" and "gpio". "pull-enable" is optional and + when it is missing the "pull" registers are used instead + - gpio-controller: identifies the node as a gpio controller + - #gpio-cells: must be 2 + +Valid sub-node names are: + - "banks" for the regular domain + - "ao-bank" for the always-on domain + +=== Other sub-nodes === + +Child nodes without the "gpio-controller" represent some desired +configuration for a pin or a group. Those nodes can be pinmux nodes or +configuration nodes. + +Required properties for pinmux nodes are: + - groups: a list of pinmux groups. The list of all available groups + depends on the SoC and can be found in driver sources. + - function: the name of a function to activate for the specified set + of groups. The list of all available functions depends on the SoC + and can be found in driver sources. + +Required properties for configuration nodes: + - pins: a list of pin names + +Configuration nodes support the generic properties "bias-disable", +"bias-pull-up" and "bias-pull-down", described in file +pinctrl-bindings.txt + +=== Example === + + pinctrl: pinctrl@c1109880 { + compatible = "amlogic,meson8-pinctrl"; + reg = <0xc1109880 0x10>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + gpio: banks@c11080b0 { + reg = <0xc11080b0 0x28>, + <0xc11080e8 0x18>, + <0xc1108120 0x18>, + <0xc1108030 0x30>; + reg-names = "mux", "pull", "pull-enable", "gpio"; + gpio-controller; + #gpio-cells = <2>; + }; + + gpio_ao: ao-bank@c1108030 { + reg = <0xc8100014 0x4>, + <0xc810002c 0x4>, + <0xc8100024 0x8>; + reg-names = "mux", "pull", "gpio"; + gpio-controller; + #gpio-cells = <2>; + }; + + nand { + mux { + groups = "nand_io", "nand_io_ce0", "nand_io_ce1", + "nand_io_rb0", "nand_ale", "nand_cle", + "nand_wen_clk", "nand_ren_clk", "nand_dqs", + "nand_ce2", "nand_ce3"; + function = "nand"; + }; + }; + + uart_ao_a { + mux { + groups = "uart_tx_ao_a", "uart_rx_ao_a", + "uart_cts_ao_a", "uart_rts_ao_a"; + function = "uart_ao"; + }; + + conf { + pins = "GPIOAO_0", "GPIOAO_1", + "GPIOAO_2", "GPIOAO_3"; + bias-disable; + }; + }; + }; -- cgit v1.2.3-59-g8ed1b From 5f42424354f5b0ca5413b4fb8528d150692c85b7 Mon Sep 17 00:00:00 2001 From: Rojhalat Ibrahim Date: Tue, 4 Nov 2014 17:12:06 +0100 Subject: gpiolib: allow simultaneous setting of multiple GPIO outputs Introduce new functions gpiod_set_array & gpiod_set_raw_array to the consumer interface which allow setting multiple outputs with just one function call. Also add an optional set_multiple function to the driver interface. Without an implementation of that function in the chip driver outputs are set sequentially. Implementing the set_multiple function in a chip driver allows for: - Improved performance for certain use cases. The original motivation for this was the task of configuring an FPGA. In that specific case, where 9 GPIO lines have to be set many times, configuration time goes down from 48 s to 20 s when using the new function. - Simultaneous glitch-free setting of multiple pins on any kind of parallel bus attached to GPIOs provided they all reside on the same chip and bank. Limitations: Performance is only improved for normal high-low outputs. Open drain and open source outputs are always set separately from each other. Those kinds of outputs could probably be accelerated in a similar way if we could forgo the error checking when setting GPIO directions. Change log: v6: - rebase on current linux-gpio devel branch v5: - check can_sleep property per chip - remove superfluous checks - supplement documentation v4: - add gpiod_set_array function for setting logical values - change interface of the set_multiple driver function to use unsigned long as type for the bit fields - use generic bitops (which also use unsigned long for bit fields) - do not use ARCH_NR_GPIOS any more v3: - add documentation - change commit message v2: - use descriptor interface - allow arbitrary groups of GPIOs spanning multiple chips Signed-off-by: Rojhalat Ibrahim Reviewed-by: Alexandre Courbot Reviewed-by: Mark Brown Signed-off-by: Linus Walleij --- Documentation/gpio/consumer.txt | 27 +++++++ drivers/gpio/gpiolib.c | 168 ++++++++++++++++++++++++++++++++++++++++ include/linux/gpio/consumer.h | 38 +++++++++ include/linux/gpio/driver.h | 4 + 4 files changed, 237 insertions(+) (limited to 'Documentation') diff --git a/Documentation/gpio/consumer.txt b/Documentation/gpio/consumer.txt index 6ce544191ca6..c67f806401a5 100644 --- a/Documentation/gpio/consumer.txt +++ b/Documentation/gpio/consumer.txt @@ -199,6 +199,33 @@ The active-low state of a GPIO can also be queried using the following call: Note that these functions should only be used with great moderation ; a driver should not have to care about the physical line level. + +Set multiple GPIO outputs with a single function call +----------------------------------------------------- +The following functions set the output values of an array of GPIOs: + + void gpiod_set_array(unsigned int array_size, + struct gpio_desc **desc_array, + int *value_array) + void gpiod_set_raw_array(unsigned int array_size, + struct gpio_desc **desc_array, + int *value_array) + void gpiod_set_array_cansleep(unsigned int array_size, + struct gpio_desc **desc_array, + int *value_array) + void gpiod_set_raw_array_cansleep(unsigned int array_size, + struct gpio_desc **desc_array, + int *value_array) + +The array can be an arbitrary set of GPIOs. The functions will try to set +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. +Note that for optimal performance GPIOs belonging to the same chip should be +contiguous within the array of descriptors. + + GPIOs mapped to IRQs -------------------- GPIO lines can quite often be used as IRQs. You can get the IRQ number diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 50e18a4b3a9f..eb739a51e774 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1254,6 +1254,88 @@ static void _gpiod_set_raw_value(struct gpio_desc *desc, bool value) chip->set(chip, gpio_chip_hwgpio(desc), value); } +/* + * set multiple outputs on the same chip; + * use the chip's set_multiple function if available; + * otherwise set the outputs sequentially; + * @mask: bit mask array; one bit per output; BITS_PER_LONG bits per word + * defines which outputs are to be changed + * @bits: bit value array; one bit per output; BITS_PER_LONG bits per word + * defines the values the outputs specified by mask are to be set to + */ +static void gpio_chip_set_multiple(struct gpio_chip *chip, + unsigned long *mask, unsigned long *bits) +{ + if (chip->set_multiple) { + chip->set_multiple(chip, mask, bits); + } else { + int i; + for (i = 0; i < chip->ngpio; i++) { + if (mask[BIT_WORD(i)] == 0) { + /* no more set bits in this mask word; + * skip ahead to the next word */ + i = (BIT_WORD(i) + 1) * BITS_PER_LONG - 1; + continue; + } + /* set outputs if the corresponding mask bit is set */ + if (__test_and_clear_bit(i, mask)) { + chip->set(chip, i, test_bit(i, bits)); + } + } + } +} + +static void gpiod_set_array_priv(bool raw, bool can_sleep, + unsigned int array_size, + struct gpio_desc **desc_array, + int *value_array) +{ + int i = 0; + + while (i < array_size) { + struct gpio_chip *chip = desc_array[i]->chip; + unsigned long mask[BITS_TO_LONGS(chip->ngpio)]; + unsigned long bits[BITS_TO_LONGS(chip->ngpio)]; + int count = 0; + + if (!can_sleep) { + WARN_ON(chip->can_sleep); + } + memset(mask, 0, sizeof(mask)); + do { + struct gpio_desc *desc = desc_array[i]; + int hwgpio = gpio_chip_hwgpio(desc); + int value = value_array[i]; + + if (!raw && test_bit(FLAG_ACTIVE_LOW, &desc->flags)) + value = !value; + trace_gpio_value(desc_to_gpio(desc), 0, value); + /* + * collect all normal outputs belonging to the same chip + * open drain and open source outputs are set individually + */ + if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) { + _gpio_set_open_drain_value(desc,value); + } else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) { + _gpio_set_open_source_value(desc, value); + } else { + __set_bit(hwgpio, mask); + if (value) { + __set_bit(hwgpio, bits); + } else { + __clear_bit(hwgpio, bits); + } + count++; + } + i++; + } while ((i < array_size) && (desc_array[i]->chip == chip)); + /* push collected bits to outputs */ + if (count != 0) { + gpio_chip_set_multiple(chip, mask, bits); + } + } +} + /** * gpiod_set_raw_value() - assign a gpio's raw value * @desc: gpio whose value will be assigned @@ -1298,6 +1380,48 @@ void gpiod_set_value(struct gpio_desc *desc, int value) } EXPORT_SYMBOL_GPL(gpiod_set_value); +/** + * gpiod_set_raw_array() - assign values to an array of GPIOs + * @array_size: number of elements in the descriptor / value arrays + * @desc_array: array of GPIO descriptors whose values will be assigned + * @value_array: array of values to assign + * + * Set the raw values of the GPIOs, i.e. the values of the physical lines + * without regard for their ACTIVE_LOW status. + * + * This function should be called from contexts where we cannot sleep, and will + * complain if the GPIO chip functions potentially sleep. + */ +void gpiod_set_raw_array(unsigned int array_size, + struct gpio_desc **desc_array, int *value_array) +{ + if (!desc_array) + return; + gpiod_set_array_priv(true, false, array_size, desc_array, value_array); +} +EXPORT_SYMBOL_GPL(gpiod_set_raw_array); + +/** + * gpiod_set_array() - assign values to an array of GPIOs + * @array_size: number of elements in the descriptor / value arrays + * @desc_array: array of GPIO descriptors whose values will be assigned + * @value_array: array of values to assign + * + * Set the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status + * into account. + * + * This function should be called from contexts where we cannot sleep, and will + * complain if the GPIO chip functions potentially sleep. + */ +void gpiod_set_array(unsigned int array_size, + struct gpio_desc **desc_array, int *value_array) +{ + if (!desc_array) + return; + gpiod_set_array_priv(false, false, array_size, desc_array, value_array); +} +EXPORT_SYMBOL_GPL(gpiod_set_array); + /** * gpiod_cansleep() - report whether gpio value access may sleep * @desc: gpio to check @@ -1457,6 +1581,50 @@ void gpiod_set_value_cansleep(struct gpio_desc *desc, int value) } EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep); +/** + * gpiod_set_raw_array_cansleep() - assign values to an array of GPIOs + * @array_size: number of elements in the descriptor / value arrays + * @desc_array: array of GPIO descriptors whose values will be assigned + * @value_array: array of values to assign + * + * Set the raw values of the GPIOs, i.e. the values of the physical lines + * without regard for their ACTIVE_LOW status. + * + * This function is to be called from contexts that can sleep. + */ +void gpiod_set_raw_array_cansleep(unsigned int array_size, + struct gpio_desc **desc_array, + int *value_array) +{ + might_sleep_if(extra_checks); + if (!desc_array) + return; + gpiod_set_array_priv(true, true, array_size, desc_array, value_array); +} +EXPORT_SYMBOL_GPL(gpiod_set_raw_array_cansleep); + +/** + * gpiod_set_array_cansleep() - assign values to an array of GPIOs + * @array_size: number of elements in the descriptor / value arrays + * @desc_array: array of GPIO descriptors whose values will be assigned + * @value_array: array of values to assign + * + * Set the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status + * into account. + * + * This function is to be called from contexts that can sleep. + */ +void gpiod_set_array_cansleep(unsigned int array_size, + struct gpio_desc **desc_array, + int *value_array) +{ + might_sleep_if(extra_checks); + if (!desc_array) + return; + gpiod_set_array_priv(false, true, array_size, desc_array, value_array); +} +EXPORT_SYMBOL_GPL(gpiod_set_array_cansleep); + /** * gpiod_add_lookup_table() - register GPIO device consumers * @table: table of consumers to register diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h index 12f146fa6604..83c0a61c605d 100644 --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h @@ -74,14 +74,24 @@ int gpiod_direction_output_raw(struct gpio_desc *desc, int value); /* Value get/set from non-sleeping context */ int gpiod_get_value(const struct gpio_desc *desc); void gpiod_set_value(struct gpio_desc *desc, int value); +void gpiod_set_array(unsigned int array_size, + struct gpio_desc **desc_array, int *value_array); int gpiod_get_raw_value(const struct gpio_desc *desc); void gpiod_set_raw_value(struct gpio_desc *desc, int value); +void gpiod_set_raw_array(unsigned int array_size, + struct gpio_desc **desc_array, int *value_array); /* Value get/set from sleeping context */ int gpiod_get_value_cansleep(const struct gpio_desc *desc); void gpiod_set_value_cansleep(struct gpio_desc *desc, int value); +void gpiod_set_array_cansleep(unsigned int array_size, + struct gpio_desc **desc_array, + int *value_array); int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc); void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value); +void gpiod_set_raw_array_cansleep(unsigned int array_size, + struct gpio_desc **desc_array, + int *value_array); int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce); @@ -210,6 +220,13 @@ static inline void gpiod_set_value(struct gpio_desc *desc, int value) /* GPIO can never have been requested */ WARN_ON(1); } +static inline void gpiod_set_array(unsigned int array_size, + struct gpio_desc **desc_array, + int *value_array) +{ + /* GPIO can never have been requested */ + WARN_ON(1); +} static inline int gpiod_get_raw_value(const struct gpio_desc *desc) { /* GPIO can never have been requested */ @@ -221,6 +238,13 @@ static inline void gpiod_set_raw_value(struct gpio_desc *desc, int value) /* GPIO can never have been requested */ WARN_ON(1); } +static inline void gpiod_set_raw_array(unsigned int array_size, + struct gpio_desc **desc_array, + int *value_array) +{ + /* GPIO can never have been requested */ + WARN_ON(1); +} static inline int gpiod_get_value_cansleep(const struct gpio_desc *desc) { @@ -233,6 +257,13 @@ static inline void gpiod_set_value_cansleep(struct gpio_desc *desc, int value) /* GPIO can never have been requested */ WARN_ON(1); } +static inline void gpiod_set_array_cansleep(unsigned int array_size, + struct gpio_desc **desc_array, + int *value_array) +{ + /* GPIO can never have been requested */ + WARN_ON(1); +} static inline int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc) { /* GPIO can never have been requested */ @@ -245,6 +276,13 @@ static inline void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, /* GPIO can never have been requested */ WARN_ON(1); } +static inline void gpiod_set_raw_array_cansleep(unsigned int array_size, + struct gpio_desc **desc_array, + int *value_array) +{ + /* GPIO can never have been requested */ + WARN_ON(1); +} static inline int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce) { diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index ff200a75501e..c497c62889d1 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -32,6 +32,7 @@ struct seq_file; * @get: returns value for signal "offset"; for output signals this * returns either the value actually sensed, or zero * @set: assigns output value for signal "offset" + * @set_multiple: assigns output values for multiple signals defined by "mask" * @set_debounce: optional hook for setting debounce time for specified gpio in * interrupt triggered gpio chips * @to_irq: optional hook supporting non-static gpio_to_irq() mappings; @@ -89,6 +90,9 @@ struct gpio_chip { unsigned offset); void (*set)(struct gpio_chip *chip, unsigned offset, int value); + void (*set_multiple)(struct gpio_chip *chip, + unsigned long *mask, + unsigned long *bits); int (*set_debounce)(struct gpio_chip *chip, unsigned offset, unsigned debounce); -- cgit v1.2.3-59-g8ed1b From 1fd2b49d0bd986fb22dd0a36910f24823e7bb0a0 Mon Sep 17 00:00:00 2001 From: Hisashi Nakamura Date: Fri, 7 Nov 2014 20:54:08 +0900 Subject: gpio: rcar: Add r8a7793 and r8a7794 support The device tree probing for R-Car M2-N (r8a7793) and R-Car E2 (r8a7794) is added. Signed-off-by: Hisashi Nakamura Signed-off-by: Yoshihiro Kaneko Acked-by: Geert Uytterhoeven Signed-off-by: Linus Walleij --- .../devicetree/bindings/gpio/renesas,gpio-rcar.txt | 4 +++- drivers/gpio/gpio-rcar.c | 27 ++++++++++++++-------- 2 files changed, 21 insertions(+), 10 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt b/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt index 941a26aa4322..38fb86f28ba2 100644 --- a/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt +++ b/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt @@ -6,7 +6,9 @@ Required Properties: - "renesas,gpio-r8a7778": for R8A7778 (R-Mobile M1) compatible GPIO controller. - "renesas,gpio-r8a7779": for R8A7779 (R-Car H1) compatible GPIO controller. - "renesas,gpio-r8a7790": for R8A7790 (R-Car H2) compatible GPIO controller. - - "renesas,gpio-r8a7791": for R8A7791 (R-Car M2) compatible GPIO controller. + - "renesas,gpio-r8a7791": for R8A7791 (R-Car M2-W) compatible GPIO controller. + - "renesas,gpio-r8a7793": for R8A7793 (R-Car M2-N) compatible GPIO controller. + - "renesas,gpio-r8a7794": for R8A7794 (R-Car E2) compatible GPIO controller. - "renesas,gpio-rcar": for generic R-Car GPIO controller. - reg: Base address and length of each memory resource used by the GPIO diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index bf6c09450fee..584484e3f1e3 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -1,6 +1,7 @@ /* * Renesas R-Car GPIO Support * + * Copyright (C) 2014 Renesas Electronics Corporation * Copyright (C) 2013 Magnus Damm * * This program is free software; you can redistribute it and/or modify @@ -291,22 +292,30 @@ struct gpio_rcar_info { bool has_both_edge_trigger; }; +static const struct gpio_rcar_info gpio_rcar_info_gen1 = { + .has_both_edge_trigger = false, +}; + +static const struct gpio_rcar_info gpio_rcar_info_gen2 = { + .has_both_edge_trigger = true, +}; + static const struct of_device_id gpio_rcar_of_table[] = { { .compatible = "renesas,gpio-r8a7790", - .data = (void *)&(const struct gpio_rcar_info) { - .has_both_edge_trigger = true, - }, + .data = &gpio_rcar_info_gen2, }, { .compatible = "renesas,gpio-r8a7791", - .data = (void *)&(const struct gpio_rcar_info) { - .has_both_edge_trigger = true, - }, + .data = &gpio_rcar_info_gen2, + }, { + .compatible = "renesas,gpio-r8a7793", + .data = &gpio_rcar_info_gen2, + }, { + .compatible = "renesas,gpio-r8a7794", + .data = &gpio_rcar_info_gen2, }, { .compatible = "renesas,gpio-rcar", - .data = (void *)&(const struct gpio_rcar_info) { - .has_both_edge_trigger = false, - }, + .data = &gpio_rcar_info_gen1, }, { /* Terminator */ }, -- cgit v1.2.3-59-g8ed1b From 79855d178557cc3e3ffd179fd26a64cef48dfb30 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 5 Nov 2014 10:36:28 +0100 Subject: libsas: remove task_collector mode The task_collector mode (or "latency_injector", (C) Dan Willians) is an optional I/O path in libsas that queues up scsi commands instead of directly sending it to the hardware. It generall increases latencies to in the optiomal case slightly reduce mmio traffic to the hardware. Only the obsolete aic94xx driver and the mvsas driver allowed to use it without recompiling the kernel, and most drivers didn't support it at all. Remove the giant blob of code to allow better optimizations for scsi-mq in the future. Signed-off-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Acked-by: Dan Williams --- Documentation/scsi/libsas.txt | 82 +---------------- drivers/scsi/aic94xx/aic94xx.h | 2 +- drivers/scsi/aic94xx/aic94xx_hwi.c | 3 +- drivers/scsi/aic94xx/aic94xx_init.c | 11 --- drivers/scsi/aic94xx/aic94xx_task.c | 13 ++- drivers/scsi/isci/init.c | 2 - drivers/scsi/isci/task.c | 147 ++++++++++++++---------------- drivers/scsi/isci/task.h | 1 - drivers/scsi/libsas/sas_ata.c | 9 +- drivers/scsi/libsas/sas_expander.c | 2 +- drivers/scsi/libsas/sas_init.c | 21 ----- drivers/scsi/libsas/sas_internal.h | 2 - drivers/scsi/libsas/sas_scsi_host.c | 176 +----------------------------------- drivers/scsi/mvsas/mv_init.c | 22 ----- drivers/scsi/mvsas/mv_sas.c | 109 +--------------------- drivers/scsi/mvsas/mv_sas.h | 10 +- drivers/scsi/pm8001/pm8001_init.c | 2 - drivers/scsi/pm8001/pm8001_sas.c | 22 +---- drivers/scsi/pm8001/pm8001_sas.h | 3 +- include/scsi/libsas.h | 14 +-- 20 files changed, 97 insertions(+), 556 deletions(-) (limited to 'Documentation') diff --git a/Documentation/scsi/libsas.txt b/Documentation/scsi/libsas.txt index 3cc9c7843e15..8cac6492aade 100644 --- a/Documentation/scsi/libsas.txt +++ b/Documentation/scsi/libsas.txt @@ -226,9 +226,6 @@ static int register_sas_ha(struct my_sas_ha *my_ha) my_ha->sas_ha.lldd_dev_found = my_dev_found; my_ha->sas_ha.lldd_dev_gone = my_dev_gone; - my_ha->sas_ha.lldd_max_execute_num = lldd_max_execute_num; (1) - - my_ha->sas_ha.lldd_queue_size = ha_can_queue; my_ha->sas_ha.lldd_execute_task = my_execute_task; my_ha->sas_ha.lldd_abort_task = my_abort_task; @@ -247,28 +244,6 @@ static int register_sas_ha(struct my_sas_ha *my_ha) return sas_register_ha(&my_ha->sas_ha); } -(1) This is normally a LLDD parameter, something of the -lines of a task collector. What it tells the SAS Layer is -whether the SAS layer should run in Direct Mode (default: -value 0 or 1) or Task Collector Mode (value greater than 1). - -In Direct Mode, the SAS Layer calls Execute Task as soon as -it has a command to send to the SDS, _and_ this is a single -command, i.e. not linked. - -Some hardware (e.g. aic94xx) has the capability to DMA more -than one task at a time (interrupt) from host memory. Task -Collector Mode is an optional feature for HAs which support -this in their hardware. (Again, it is completely optional -even if your hardware supports it.) - -In Task Collector Mode, the SAS Layer would do _natural_ -coalescing of tasks and at the appropriate moment it would -call your driver to DMA more than one task in a single HA -interrupt. DMBS may want to use this by insmod/modprobe -setting the lldd_max_execute_num to something greater than -1. - (2) SAS 1.1 does not define I_T Nexus Reset TMF. Events @@ -325,71 +300,22 @@ PHYE_SPINUP_HOLD -- SATA is present, COMWAKE not sent. The Execute Command SCSI RPC: - int (*lldd_execute_task)(struct sas_task *, int num, - unsigned long gfp_flags); + int (*lldd_execute_task)(struct sas_task *, gfp_t gfp_flags); -Used to queue a task to the SAS LLDD. @task is the tasks to -be executed. @num should be the number of tasks being -queued at this function call (they are linked listed via -task::list), @gfp_mask should be the gfp_mask defining the -context of the caller. +Used to queue a task to the SAS LLDD. @task is the task to be executed. +@gfp_mask is the gfp_mask defining the context of the caller. This function should implement the Execute Command SCSI RPC, -or if you're sending a SCSI Task as linked commands, you -should also use this function. -That is, when lldd_execute_task() is called, the command(s) +That is, when lldd_execute_task() is called, the command go out on the transport *immediately*. There is *no* queuing of any sort and at any level in a SAS LLDD. -The use of task::list is two-fold, one for linked commands, -the other discussed below. - -It is possible to queue up more than one task at a time, by -initializing the list element of struct sas_task, and -passing the number of tasks enlisted in this manner in num. - Returns: -SAS_QUEUE_FULL, -ENOMEM, nothing was queued; 0, the task(s) were queued. -If you want to pass num > 1, then either -A) you're the only caller of this function and keep track - of what you've queued to the LLDD, or -B) you know what you're doing and have a strategy of - retrying. - -As opposed to queuing one task at a time (function call), -batch queuing of tasks, by having num > 1, greatly -simplifies LLDD code, sequencer code, and _hardware design_, -and has some performance advantages in certain situations -(DBMS). - -The LLDD advertises if it can take more than one command at -a time at lldd_execute_task(), by setting the -lldd_max_execute_num parameter (controlled by "collector" -module parameter in aic94xx SAS LLDD). - -You should leave this to the default 1, unless you know what -you're doing. - -This is a function of the LLDD, to which the SAS layer can -cater to. - -int lldd_queue_size - The host adapter's queue size. This is the maximum -number of commands the lldd can have pending to domain -devices on behalf of all upper layers submitting through -lldd_execute_task(). - -You really want to set this to something (much) larger than -1. - -This _really_ has absolutely nothing to do with queuing. -There is no queuing in SAS LLDDs. - struct sas_task { dev -- the device this task is destined to - list -- must be initialized (INIT_LIST_HEAD) task_proto -- _one_ of enum sas_proto scatter -- pointer to scatter gather list array num_scatter -- number of elements in scatter diff --git a/drivers/scsi/aic94xx/aic94xx.h b/drivers/scsi/aic94xx/aic94xx.h index 66cda669b417..26d4ad9ede2e 100644 --- a/drivers/scsi/aic94xx/aic94xx.h +++ b/drivers/scsi/aic94xx/aic94xx.h @@ -78,7 +78,7 @@ void asd_dev_gone(struct domain_device *dev); void asd_invalidate_edb(struct asd_ascb *ascb, int edb_id); -int asd_execute_task(struct sas_task *, int num, gfp_t gfp_flags); +int asd_execute_task(struct sas_task *task, gfp_t gfp_flags); void asd_set_dmamode(struct domain_device *dev); diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.c b/drivers/scsi/aic94xx/aic94xx_hwi.c index 4df867e07b20..9f636a34d595 100644 --- a/drivers/scsi/aic94xx/aic94xx_hwi.c +++ b/drivers/scsi/aic94xx/aic94xx_hwi.c @@ -1200,8 +1200,7 @@ static void asd_start_scb_timers(struct list_head *list) * Case A: we can send the whole batch at once. Increment "pending" * in the beginning of this function, when it is checked, in order to * eliminate races when this function is called by multiple processes. - * Case B: should never happen if the managing layer considers - * lldd_queue_size. + * Case B: should never happen. */ int asd_post_ascb_list(struct asd_ha_struct *asd_ha, struct asd_ascb *ascb, int num) diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c index a64cf932d03d..14fc018436c2 100644 --- a/drivers/scsi/aic94xx/aic94xx_init.c +++ b/drivers/scsi/aic94xx/aic94xx_init.c @@ -49,14 +49,6 @@ MODULE_PARM_DESC(use_msi, "\n" "\tEnable(1) or disable(0) using PCI MSI.\n" "\tDefault: 0"); -static int lldd_max_execute_num = 0; -module_param_named(collector, lldd_max_execute_num, int, S_IRUGO); -MODULE_PARM_DESC(collector, "\n" - "\tIf greater than one, tells the SAS Layer to run in Task Collector\n" - "\tMode. If 1 or 0, tells the SAS Layer to run in Direct Mode.\n" - "\tThe aic94xx SAS LLDD supports both modes.\n" - "\tDefault: 0 (Direct Mode).\n"); - static struct scsi_transport_template *aic94xx_transport_template; static int asd_scan_finished(struct Scsi_Host *, unsigned long); static void asd_scan_start(struct Scsi_Host *); @@ -711,9 +703,6 @@ static int asd_register_sas_ha(struct asd_ha_struct *asd_ha) asd_ha->sas_ha.sas_port= sas_ports; asd_ha->sas_ha.num_phys= ASD_MAX_PHYS; - asd_ha->sas_ha.lldd_queue_size = asd_ha->seq.can_queue; - asd_ha->sas_ha.lldd_max_execute_num = lldd_max_execute_num; - return sas_register_ha(&asd_ha->sas_ha); } diff --git a/drivers/scsi/aic94xx/aic94xx_task.c b/drivers/scsi/aic94xx/aic94xx_task.c index 59b86e260ce9..5ff1ce7ba1f4 100644 --- a/drivers/scsi/aic94xx/aic94xx_task.c +++ b/drivers/scsi/aic94xx/aic94xx_task.c @@ -543,8 +543,7 @@ static int asd_can_queue(struct asd_ha_struct *asd_ha, int num) return res; } -int asd_execute_task(struct sas_task *task, const int num, - gfp_t gfp_flags) +int asd_execute_task(struct sas_task *task, gfp_t gfp_flags) { int res = 0; LIST_HEAD(alist); @@ -553,11 +552,11 @@ int asd_execute_task(struct sas_task *task, const int num, struct asd_ha_struct *asd_ha = task->dev->port->ha->lldd_ha; unsigned long flags; - res = asd_can_queue(asd_ha, num); + res = asd_can_queue(asd_ha, 1); if (res) return res; - res = num; + res = 1; ascb = asd_ascb_alloc_list(asd_ha, &res, gfp_flags); if (res) { res = -ENOMEM; @@ -568,7 +567,7 @@ int asd_execute_task(struct sas_task *task, const int num, list_for_each_entry(a, &alist, list) { a->uldd_task = t; t->lldd_task = a; - t = list_entry(t->list.next, struct sas_task, list); + break; } list_for_each_entry(a, &alist, list) { t = a->uldd_task; @@ -601,7 +600,7 @@ int asd_execute_task(struct sas_task *task, const int num, } list_del_init(&alist); - res = asd_post_ascb_list(asd_ha, ascb, num); + res = asd_post_ascb_list(asd_ha, ascb, 1); if (unlikely(res)) { a = NULL; __list_add(&alist, ascb->list.prev, &ascb->list); @@ -639,6 +638,6 @@ out_err_unmap: out_err: if (ascb) asd_ascb_free_list(ascb); - asd_can_dequeue(asd_ha, num); + asd_can_dequeue(asd_ha, 1); return res; } diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c index a81e546595dd..724c6265b667 100644 --- a/drivers/scsi/isci/init.c +++ b/drivers/scsi/isci/init.c @@ -260,8 +260,6 @@ static int isci_register_sas_ha(struct isci_host *isci_host) sas_ha->sas_port = sas_ports; sas_ha->num_phys = SCI_MAX_PHYS; - sas_ha->lldd_queue_size = ISCI_CAN_QUEUE_VAL; - sas_ha->lldd_max_execute_num = 1; sas_ha->strict_wide_ports = 1; sas_register_ha(sas_ha); diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 5d6fda72d659..3f63c6318b0d 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -117,104 +117,97 @@ static inline int isci_device_io_ready(struct isci_remote_device *idev, * functions. This function is called by libsas to send a task down to * hardware. * @task: This parameter specifies the SAS task to send. - * @num: This parameter specifies the number of tasks to queue. * @gfp_flags: This parameter specifies the context of this call. * * status, zero indicates success. */ -int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags) +int isci_task_execute_task(struct sas_task *task, gfp_t gfp_flags) { struct isci_host *ihost = dev_to_ihost(task->dev); struct isci_remote_device *idev; unsigned long flags; + enum sci_status status = SCI_FAILURE; bool io_ready; u16 tag; - dev_dbg(&ihost->pdev->dev, "%s: num=%d\n", __func__, num); + spin_lock_irqsave(&ihost->scic_lock, flags); + idev = isci_lookup_device(task->dev); + io_ready = isci_device_io_ready(idev, task); + tag = isci_alloc_tag(ihost); + spin_unlock_irqrestore(&ihost->scic_lock, flags); - for_each_sas_task(num, task) { - enum sci_status status = SCI_FAILURE; + dev_dbg(&ihost->pdev->dev, + "task: %p, dev: %p idev: %p:%#lx cmd = %p\n", + task, task->dev, idev, idev ? idev->flags : 0, + task->uldd_task); - spin_lock_irqsave(&ihost->scic_lock, flags); - idev = isci_lookup_device(task->dev); - io_ready = isci_device_io_ready(idev, task); - tag = isci_alloc_tag(ihost); - spin_unlock_irqrestore(&ihost->scic_lock, flags); + if (!idev) { + isci_task_refuse(ihost, task, SAS_TASK_UNDELIVERED, + SAS_DEVICE_UNKNOWN); + } else if (!io_ready || tag == SCI_CONTROLLER_INVALID_IO_TAG) { + /* Indicate QUEUE_FULL so that the scsi midlayer + * retries. + */ + isci_task_refuse(ihost, task, SAS_TASK_COMPLETE, + SAS_QUEUE_FULL); + } else { + /* There is a device and it's ready for I/O. */ + spin_lock_irqsave(&task->task_state_lock, flags); - dev_dbg(&ihost->pdev->dev, - "task: %p, num: %d dev: %p idev: %p:%#lx cmd = %p\n", - task, num, task->dev, idev, idev ? idev->flags : 0, - task->uldd_task); - - if (!idev) { - isci_task_refuse(ihost, task, SAS_TASK_UNDELIVERED, - SAS_DEVICE_UNKNOWN); - } else if (!io_ready || tag == SCI_CONTROLLER_INVALID_IO_TAG) { - /* Indicate QUEUE_FULL so that the scsi midlayer - * retries. - */ - isci_task_refuse(ihost, task, SAS_TASK_COMPLETE, - SAS_QUEUE_FULL); + if (task->task_state_flags & SAS_TASK_STATE_ABORTED) { + /* The I/O was aborted. */ + spin_unlock_irqrestore(&task->task_state_lock, flags); + + isci_task_refuse(ihost, task, + SAS_TASK_UNDELIVERED, + SAM_STAT_TASK_ABORTED); } else { - /* There is a device and it's ready for I/O. */ - spin_lock_irqsave(&task->task_state_lock, flags); - - if (task->task_state_flags & SAS_TASK_STATE_ABORTED) { - /* The I/O was aborted. */ - spin_unlock_irqrestore(&task->task_state_lock, - flags); - - isci_task_refuse(ihost, task, - SAS_TASK_UNDELIVERED, - SAM_STAT_TASK_ABORTED); - } else { - task->task_state_flags |= SAS_TASK_AT_INITIATOR; + task->task_state_flags |= SAS_TASK_AT_INITIATOR; + spin_unlock_irqrestore(&task->task_state_lock, flags); + + /* build and send the request. */ + status = isci_request_execute(ihost, idev, task, tag); + + if (status != SCI_SUCCESS) { + spin_lock_irqsave(&task->task_state_lock, flags); + /* Did not really start this command. */ + task->task_state_flags &= ~SAS_TASK_AT_INITIATOR; spin_unlock_irqrestore(&task->task_state_lock, flags); - /* build and send the request. */ - status = isci_request_execute(ihost, idev, task, tag); - - if (status != SCI_SUCCESS) { - - spin_lock_irqsave(&task->task_state_lock, flags); - /* Did not really start this command. */ - task->task_state_flags &= ~SAS_TASK_AT_INITIATOR; - spin_unlock_irqrestore(&task->task_state_lock, flags); - - if (test_bit(IDEV_GONE, &idev->flags)) { - - /* Indicate that the device - * is gone. - */ - isci_task_refuse(ihost, task, - SAS_TASK_UNDELIVERED, - SAS_DEVICE_UNKNOWN); - } else { - /* Indicate QUEUE_FULL so that - * the scsi midlayer retries. - * If the request failed for - * remote device reasons, it - * gets returned as - * SAS_TASK_UNDELIVERED next - * time through. - */ - isci_task_refuse(ihost, task, - SAS_TASK_COMPLETE, - SAS_QUEUE_FULL); - } + if (test_bit(IDEV_GONE, &idev->flags)) { + /* Indicate that the device + * is gone. + */ + isci_task_refuse(ihost, task, + SAS_TASK_UNDELIVERED, + SAS_DEVICE_UNKNOWN); + } else { + /* Indicate QUEUE_FULL so that + * the scsi midlayer retries. + * If the request failed for + * remote device reasons, it + * gets returned as + * SAS_TASK_UNDELIVERED next + * time through. + */ + isci_task_refuse(ihost, task, + SAS_TASK_COMPLETE, + SAS_QUEUE_FULL); } } } - if (status != SCI_SUCCESS && tag != SCI_CONTROLLER_INVALID_IO_TAG) { - spin_lock_irqsave(&ihost->scic_lock, flags); - /* command never hit the device, so just free - * the tci and skip the sequence increment - */ - isci_tci_free(ihost, ISCI_TAG_TCI(tag)); - spin_unlock_irqrestore(&ihost->scic_lock, flags); - } - isci_put_device(idev); } + + if (status != SCI_SUCCESS && tag != SCI_CONTROLLER_INVALID_IO_TAG) { + spin_lock_irqsave(&ihost->scic_lock, flags); + /* command never hit the device, so just free + * the tci and skip the sequence increment + */ + isci_tci_free(ihost, ISCI_TAG_TCI(tag)); + spin_unlock_irqrestore(&ihost->scic_lock, flags); + } + + isci_put_device(idev); return 0; } diff --git a/drivers/scsi/isci/task.h b/drivers/scsi/isci/task.h index 9c06cbad1d26..8f4531f22ac2 100644 --- a/drivers/scsi/isci/task.h +++ b/drivers/scsi/isci/task.h @@ -131,7 +131,6 @@ static inline void isci_print_tmf(struct isci_host *ihost, struct isci_tmf *tmf) int isci_task_execute_task( struct sas_task *task, - int num, gfp_t gfp_flags); int isci_task_abort_task( diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index 766098af4eb7..577770fdee86 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -171,7 +171,6 @@ static void sas_ata_task_done(struct sas_task *task) spin_unlock_irqrestore(ap->lock, flags); qc_already_gone: - list_del_init(&task->list); sas_free_task(task); } @@ -244,12 +243,7 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc) if (qc->scsicmd) ASSIGN_SAS_TASK(qc->scsicmd, task); - if (sas_ha->lldd_max_execute_num < 2) - ret = i->dft->lldd_execute_task(task, 1, GFP_ATOMIC); - else - ret = sas_queue_up(task); - - /* Examine */ + ret = i->dft->lldd_execute_task(task, GFP_ATOMIC); if (ret) { SAS_DPRINTK("lldd_execute_task returned: %d\n", ret); @@ -485,7 +479,6 @@ static void sas_ata_internal_abort(struct sas_task *task) return; out: - list_del_init(&task->list); sas_free_task(task); } diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 0cac7d8fd0f7..022bb6e10d98 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -96,7 +96,7 @@ static int smp_execute_task(struct domain_device *dev, void *req, int req_size, task->slow_task->timer.expires = jiffies + SMP_TIMEOUT*HZ; add_timer(&task->slow_task->timer); - res = i->dft->lldd_execute_task(task, 1, GFP_KERNEL); + res = i->dft->lldd_execute_task(task, GFP_KERNEL); if (res) { del_timer(&task->slow_task->timer); diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c index dbc8a793fd86..362da44f2948 100644 --- a/drivers/scsi/libsas/sas_init.c +++ b/drivers/scsi/libsas/sas_init.c @@ -45,7 +45,6 @@ struct sas_task *sas_alloc_task(gfp_t flags) struct sas_task *task = kmem_cache_zalloc(sas_task_cache, flags); if (task) { - INIT_LIST_HEAD(&task->list); spin_lock_init(&task->task_state_lock); task->task_state_flags = SAS_TASK_STATE_PENDING; } @@ -77,7 +76,6 @@ EXPORT_SYMBOL_GPL(sas_alloc_slow_task); void sas_free_task(struct sas_task *task) { if (task) { - BUG_ON(!list_empty(&task->list)); kfree(task->slow_task); kmem_cache_free(sas_task_cache, task); } @@ -127,11 +125,6 @@ int sas_register_ha(struct sas_ha_struct *sas_ha) spin_lock_init(&sas_ha->phy_port_lock); sas_hash_addr(sas_ha->hashed_sas_addr, sas_ha->sas_addr); - if (sas_ha->lldd_queue_size == 0) - sas_ha->lldd_queue_size = 1; - else if (sas_ha->lldd_queue_size == -1) - sas_ha->lldd_queue_size = 128; /* Sanity */ - set_bit(SAS_HA_REGISTERED, &sas_ha->state); spin_lock_init(&sas_ha->lock); mutex_init(&sas_ha->drain_mutex); @@ -157,15 +150,6 @@ int sas_register_ha(struct sas_ha_struct *sas_ha) goto Undo_ports; } - if (sas_ha->lldd_max_execute_num > 1) { - error = sas_init_queue(sas_ha); - if (error) { - printk(KERN_NOTICE "couldn't start queue thread:%d, " - "running in direct mode\n", error); - sas_ha->lldd_max_execute_num = 1; - } - } - INIT_LIST_HEAD(&sas_ha->eh_done_q); INIT_LIST_HEAD(&sas_ha->eh_ata_q); @@ -201,11 +185,6 @@ int sas_unregister_ha(struct sas_ha_struct *sas_ha) __sas_drain_work(sas_ha); mutex_unlock(&sas_ha->drain_mutex); - if (sas_ha->lldd_max_execute_num > 1) { - sas_shutdown_queue(sas_ha); - sas_ha->lldd_max_execute_num = 1; - } - return 0; } diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h index 7e7ba83f0a21..9cf0bc260b0e 100644 --- a/drivers/scsi/libsas/sas_internal.h +++ b/drivers/scsi/libsas/sas_internal.h @@ -66,9 +66,7 @@ void sas_unregister_ports(struct sas_ha_struct *sas_ha); enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *); -int sas_init_queue(struct sas_ha_struct *sas_ha); int sas_init_events(struct sas_ha_struct *sas_ha); -void sas_shutdown_queue(struct sas_ha_struct *sas_ha); void sas_disable_revalidation(struct sas_ha_struct *ha); void sas_enable_revalidation(struct sas_ha_struct *ha); void __sas_drain_work(struct sas_ha_struct *ha); diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index b492293d51f2..72918d227ead 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -112,7 +112,6 @@ static void sas_end_task(struct scsi_cmnd *sc, struct sas_task *task) sc->result = (hs << 16) | stat; ASSIGN_SAS_TASK(sc, NULL); - list_del_init(&task->list); sas_free_task(task); } @@ -138,7 +137,6 @@ static void sas_scsi_task_done(struct sas_task *task) if (unlikely(!sc)) { SAS_DPRINTK("task_done called with non existing SCSI cmnd!\n"); - list_del_init(&task->list); sas_free_task(task); return; } @@ -179,31 +177,10 @@ static struct sas_task *sas_create_task(struct scsi_cmnd *cmd, return task; } -int sas_queue_up(struct sas_task *task) -{ - struct sas_ha_struct *sas_ha = task->dev->port->ha; - struct scsi_core *core = &sas_ha->core; - unsigned long flags; - LIST_HEAD(list); - - spin_lock_irqsave(&core->task_queue_lock, flags); - if (sas_ha->lldd_queue_size < core->task_queue_size + 1) { - spin_unlock_irqrestore(&core->task_queue_lock, flags); - return -SAS_QUEUE_FULL; - } - list_add_tail(&task->list, &core->task_queue); - core->task_queue_size += 1; - spin_unlock_irqrestore(&core->task_queue_lock, flags); - wake_up_process(core->queue_thread); - - return 0; -} - int sas_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) { struct sas_internal *i = to_sas_internal(host->transportt); struct domain_device *dev = cmd_to_domain_dev(cmd); - struct sas_ha_struct *sas_ha = dev->port->ha; struct sas_task *task; int res = 0; @@ -224,12 +201,7 @@ int sas_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) if (!task) return SCSI_MLQUEUE_HOST_BUSY; - /* Queue up, Direct Mode or Task Collector Mode. */ - if (sas_ha->lldd_max_execute_num < 2) - res = i->dft->lldd_execute_task(task, 1, GFP_ATOMIC); - else - res = sas_queue_up(task); - + res = i->dft->lldd_execute_task(task, GFP_ATOMIC); if (res) goto out_free_task; return 0; @@ -323,37 +295,17 @@ enum task_disposition { TASK_IS_DONE, TASK_IS_ABORTED, TASK_IS_AT_LU, - TASK_IS_NOT_AT_HA, TASK_IS_NOT_AT_LU, TASK_ABORT_FAILED, }; static enum task_disposition sas_scsi_find_task(struct sas_task *task) { - struct sas_ha_struct *ha = task->dev->port->ha; unsigned long flags; int i, res; struct sas_internal *si = to_sas_internal(task->dev->port->ha->core.shost->transportt); - if (ha->lldd_max_execute_num > 1) { - struct scsi_core *core = &ha->core; - struct sas_task *t, *n; - - mutex_lock(&core->task_queue_flush); - spin_lock_irqsave(&core->task_queue_lock, flags); - list_for_each_entry_safe(t, n, &core->task_queue, list) - if (task == t) { - list_del_init(&t->list); - break; - } - spin_unlock_irqrestore(&core->task_queue_lock, flags); - mutex_unlock(&core->task_queue_flush); - - if (task == t) - return TASK_IS_NOT_AT_HA; - } - for (i = 0; i < 5; i++) { SAS_DPRINTK("%s: aborting task 0x%p\n", __func__, task); res = si->dft->lldd_abort_task(task); @@ -667,14 +619,6 @@ static void sas_eh_handle_sas_errors(struct Scsi_Host *shost, struct list_head * cmd->eh_eflags = 0; switch (res) { - case TASK_IS_NOT_AT_HA: - SAS_DPRINTK("%s: task 0x%p is not at ha: %s\n", - __func__, task, - cmd->retries ? "retry" : "aborted"); - if (cmd->retries) - cmd->retries--; - sas_eh_finish_cmd(cmd); - continue; case TASK_IS_DONE: SAS_DPRINTK("%s: task 0x%p is done\n", __func__, task); @@ -836,9 +780,6 @@ retry: scsi_eh_ready_devs(shost, &eh_work_q, &ha->eh_done_q); out: - if (ha->lldd_max_execute_num > 1) - wake_up_process(ha->core.queue_thread); - sas_eh_handle_resets(shost); /* now link into libata eh --- if we have any ata devices */ @@ -984,121 +925,6 @@ int sas_bios_param(struct scsi_device *scsi_dev, return 0; } -/* ---------- Task Collector Thread implementation ---------- */ - -static void sas_queue(struct sas_ha_struct *sas_ha) -{ - struct scsi_core *core = &sas_ha->core; - unsigned long flags; - LIST_HEAD(q); - int can_queue; - int res; - struct sas_internal *i = to_sas_internal(core->shost->transportt); - - mutex_lock(&core->task_queue_flush); - spin_lock_irqsave(&core->task_queue_lock, flags); - while (!kthread_should_stop() && - !list_empty(&core->task_queue) && - !test_bit(SAS_HA_FROZEN, &sas_ha->state)) { - - can_queue = sas_ha->lldd_queue_size - core->task_queue_size; - if (can_queue >= 0) { - can_queue = core->task_queue_size; - list_splice_init(&core->task_queue, &q); - } else { - struct list_head *a, *n; - - can_queue = sas_ha->lldd_queue_size; - list_for_each_safe(a, n, &core->task_queue) { - list_move_tail(a, &q); - if (--can_queue == 0) - break; - } - can_queue = sas_ha->lldd_queue_size; - } - core->task_queue_size -= can_queue; - spin_unlock_irqrestore(&core->task_queue_lock, flags); - { - struct sas_task *task = list_entry(q.next, - struct sas_task, - list); - list_del_init(&q); - res = i->dft->lldd_execute_task(task, can_queue, - GFP_KERNEL); - if (unlikely(res)) - __list_add(&q, task->list.prev, &task->list); - } - spin_lock_irqsave(&core->task_queue_lock, flags); - if (res) { - list_splice_init(&q, &core->task_queue); /*at head*/ - core->task_queue_size += can_queue; - } - } - spin_unlock_irqrestore(&core->task_queue_lock, flags); - mutex_unlock(&core->task_queue_flush); -} - -/** - * sas_queue_thread -- The Task Collector thread - * @_sas_ha: pointer to struct sas_ha - */ -static int sas_queue_thread(void *_sas_ha) -{ - struct sas_ha_struct *sas_ha = _sas_ha; - - while (1) { - set_current_state(TASK_INTERRUPTIBLE); - schedule(); - sas_queue(sas_ha); - if (kthread_should_stop()) - break; - } - - return 0; -} - -int sas_init_queue(struct sas_ha_struct *sas_ha) -{ - struct scsi_core *core = &sas_ha->core; - - spin_lock_init(&core->task_queue_lock); - mutex_init(&core->task_queue_flush); - core->task_queue_size = 0; - INIT_LIST_HEAD(&core->task_queue); - - core->queue_thread = kthread_run(sas_queue_thread, sas_ha, - "sas_queue_%d", core->shost->host_no); - if (IS_ERR(core->queue_thread)) - return PTR_ERR(core->queue_thread); - return 0; -} - -void sas_shutdown_queue(struct sas_ha_struct *sas_ha) -{ - unsigned long flags; - struct scsi_core *core = &sas_ha->core; - struct sas_task *task, *n; - - kthread_stop(core->queue_thread); - - if (!list_empty(&core->task_queue)) - SAS_DPRINTK("HA: %llx: scsi core task queue is NOT empty!?\n", - SAS_ADDR(sas_ha->sas_addr)); - - spin_lock_irqsave(&core->task_queue_lock, flags); - list_for_each_entry_safe(task, n, &core->task_queue, list) { - struct scsi_cmnd *cmd = task->uldd_task; - - list_del_init(&task->list); - - ASSIGN_SAS_TASK(cmd, NULL); - sas_free_task(task); - cmd->result = DID_ABORT << 16; - cmd->scsi_done(cmd); - } - spin_unlock_irqrestore(&core->task_queue_lock, flags); -} - /* * Tell an upper layer that it needs to initiate an abort for a given task. * This should only ever be called by an LLDD. diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c index ac7c03078409..f15df3de6790 100644 --- a/drivers/scsi/mvsas/mv_init.c +++ b/drivers/scsi/mvsas/mv_init.c @@ -26,18 +26,9 @@ #include "mv_sas.h" -static int lldd_max_execute_num = 1; -module_param_named(collector, lldd_max_execute_num, int, S_IRUGO); -MODULE_PARM_DESC(collector, "\n" - "\tIf greater than one, tells the SAS Layer to run in Task Collector\n" - "\tMode. If 1 or 0, tells the SAS Layer to run in Direct Mode.\n" - "\tThe mvsas SAS LLDD supports both modes.\n" - "\tDefault: 1 (Direct Mode).\n"); - int interrupt_coalescing = 0x80; static struct scsi_transport_template *mvs_stt; -struct kmem_cache *mvs_task_list_cache; static const struct mvs_chip_info mvs_chips[] = { [chip_6320] = { 1, 2, 0x400, 17, 16, 6, 9, &mvs_64xx_dispatch, }, [chip_6440] = { 1, 4, 0x400, 17, 16, 6, 9, &mvs_64xx_dispatch, }, @@ -513,14 +504,11 @@ static void mvs_post_sas_ha_init(struct Scsi_Host *shost, sha->num_phys = nr_core * chip_info->n_phy; - sha->lldd_max_execute_num = lldd_max_execute_num; - if (mvi->flags & MVF_FLAG_SOC) can_queue = MVS_SOC_CAN_QUEUE; else can_queue = MVS_CHIP_SLOT_SZ; - sha->lldd_queue_size = can_queue; shost->sg_tablesize = min_t(u16, SG_ALL, MVS_MAX_SG); shost->can_queue = can_queue; mvi->shost->cmd_per_lun = MVS_QUEUE_SIZE; @@ -833,16 +821,7 @@ static int __init mvs_init(void) if (!mvs_stt) return -ENOMEM; - mvs_task_list_cache = kmem_cache_create("mvs_task_list", sizeof(struct mvs_task_list), - 0, SLAB_HWCACHE_ALIGN, NULL); - if (!mvs_task_list_cache) { - rc = -ENOMEM; - mv_printk("%s: mvs_task_list_cache alloc failed! \n", __func__); - goto err_out; - } - rc = pci_register_driver(&mvs_pci_driver); - if (rc) goto err_out; @@ -857,7 +836,6 @@ static void __exit mvs_exit(void) { pci_unregister_driver(&mvs_pci_driver); sas_release_transport(mvs_stt); - kmem_cache_destroy(mvs_task_list_cache); } struct device_attribute *mvst_host_attrs[] = { diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c index ac52f7c99513..85d86a5cdb60 100644 --- a/drivers/scsi/mvsas/mv_sas.c +++ b/drivers/scsi/mvsas/mv_sas.c @@ -852,43 +852,7 @@ prep_out: return rc; } -static struct mvs_task_list *mvs_task_alloc_list(int *num, gfp_t gfp_flags) -{ - struct mvs_task_list *first = NULL; - - for (; *num > 0; --*num) { - struct mvs_task_list *mvs_list = kmem_cache_zalloc(mvs_task_list_cache, gfp_flags); - - if (!mvs_list) - break; - - INIT_LIST_HEAD(&mvs_list->list); - if (!first) - first = mvs_list; - else - list_add_tail(&mvs_list->list, &first->list); - - } - - return first; -} - -static inline void mvs_task_free_list(struct mvs_task_list *mvs_list) -{ - LIST_HEAD(list); - struct list_head *pos, *a; - struct mvs_task_list *mlist = NULL; - - __list_add(&list, mvs_list->list.prev, &mvs_list->list); - - list_for_each_safe(pos, a, &list) { - list_del_init(pos); - mlist = list_entry(pos, struct mvs_task_list, list); - kmem_cache_free(mvs_task_list_cache, mlist); - } -} - -static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags, +static int mvs_task_exec(struct sas_task *task, gfp_t gfp_flags, struct completion *completion, int is_tmf, struct mvs_tmf_task *tmf) { @@ -912,74 +876,9 @@ static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags, return rc; } -static int mvs_collector_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags, - struct completion *completion, int is_tmf, - struct mvs_tmf_task *tmf) +int mvs_queue_command(struct sas_task *task, gfp_t gfp_flags) { - struct domain_device *dev = task->dev; - struct mvs_prv_info *mpi = dev->port->ha->lldd_ha; - struct mvs_info *mvi = NULL; - struct sas_task *t = task; - struct mvs_task_list *mvs_list = NULL, *a; - LIST_HEAD(q); - int pass[2] = {0}; - u32 rc = 0; - u32 n = num; - unsigned long flags = 0; - - mvs_list = mvs_task_alloc_list(&n, gfp_flags); - if (n) { - printk(KERN_ERR "%s: mvs alloc list failed.\n", __func__); - rc = -ENOMEM; - goto free_list; - } - - __list_add(&q, mvs_list->list.prev, &mvs_list->list); - - list_for_each_entry(a, &q, list) { - a->task = t; - t = list_entry(t->list.next, struct sas_task, list); - } - - list_for_each_entry(a, &q , list) { - - t = a->task; - mvi = ((struct mvs_device *)t->dev->lldd_dev)->mvi_info; - - spin_lock_irqsave(&mvi->lock, flags); - rc = mvs_task_prep(t, mvi, is_tmf, tmf, &pass[mvi->id]); - if (rc) - dev_printk(KERN_ERR, mvi->dev, "mvsas exec failed[%d]!\n", rc); - spin_unlock_irqrestore(&mvi->lock, flags); - } - - if (likely(pass[0])) - MVS_CHIP_DISP->start_delivery(mpi->mvi[0], - (mpi->mvi[0]->tx_prod - 1) & (MVS_CHIP_SLOT_SZ - 1)); - - if (likely(pass[1])) - MVS_CHIP_DISP->start_delivery(mpi->mvi[1], - (mpi->mvi[1]->tx_prod - 1) & (MVS_CHIP_SLOT_SZ - 1)); - - list_del_init(&q); - -free_list: - if (mvs_list) - mvs_task_free_list(mvs_list); - - return rc; -} - -int mvs_queue_command(struct sas_task *task, const int num, - gfp_t gfp_flags) -{ - struct mvs_device *mvi_dev = task->dev->lldd_dev; - struct sas_ha_struct *sas = mvi_dev->mvi_info->sas; - - if (sas->lldd_max_execute_num < 2) - return mvs_task_exec(task, num, gfp_flags, NULL, 0, NULL); - else - return mvs_collector_task_exec(task, num, gfp_flags, NULL, 0, NULL); + return mvs_task_exec(task, gfp_flags, NULL, 0, NULL); } static void mvs_slot_free(struct mvs_info *mvi, u32 rx_desc) @@ -1411,7 +1310,7 @@ static int mvs_exec_internal_tmf_task(struct domain_device *dev, task->slow_task->timer.expires = jiffies + MVS_TASK_TIMEOUT*HZ; add_timer(&task->slow_task->timer); - res = mvs_task_exec(task, 1, GFP_KERNEL, NULL, 1, tmf); + res = mvs_task_exec(task, GFP_KERNEL, NULL, 1, tmf); if (res) { del_timer(&task->slow_task->timer); diff --git a/drivers/scsi/mvsas/mv_sas.h b/drivers/scsi/mvsas/mv_sas.h index d6b19dc80bee..dc409c04747a 100644 --- a/drivers/scsi/mvsas/mv_sas.h +++ b/drivers/scsi/mvsas/mv_sas.h @@ -65,7 +65,6 @@ extern struct mvs_tgt_initiator mvs_tgt; extern struct mvs_info *tgt_mvi; extern const struct mvs_dispatch mvs_64xx_dispatch; extern const struct mvs_dispatch mvs_94xx_dispatch; -extern struct kmem_cache *mvs_task_list_cache; #define DEV_IS_EXPANDER(type) \ ((type == SAS_EDGE_EXPANDER_DEVICE) || (type == SAS_FANOUT_EXPANDER_DEVICE)) @@ -440,12 +439,6 @@ struct mvs_task_exec_info { int n_elem; }; -struct mvs_task_list { - struct sas_task *task; - struct list_head list; -}; - - /******************** function prototype *********************/ void mvs_get_sas_addr(void *buf, u32 buflen); void mvs_tag_clear(struct mvs_info *mvi, u32 tag); @@ -462,8 +455,7 @@ void mvs_set_sas_addr(struct mvs_info *mvi, int port_id, u32 off_lo, u32 off_hi, u64 sas_addr); void mvs_scan_start(struct Scsi_Host *shost); int mvs_scan_finished(struct Scsi_Host *shost, unsigned long time); -int mvs_queue_command(struct sas_task *task, const int num, - gfp_t gfp_flags); +int mvs_queue_command(struct sas_task *task, gfp_t gfp_flags); int mvs_abort_task(struct sas_task *task); int mvs_abort_task_set(struct domain_device *dev, u8 *lun); int mvs_clear_aca(struct domain_device *dev, u8 *lun); diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c index 19ae6cab5e44..329aba0083ab 100644 --- a/drivers/scsi/pm8001/pm8001_init.c +++ b/drivers/scsi/pm8001/pm8001_init.c @@ -601,8 +601,6 @@ static void pm8001_post_sas_ha_init(struct Scsi_Host *shost, sha->lldd_module = THIS_MODULE; sha->sas_addr = &pm8001_ha->sas_addr[0]; sha->num_phys = chip_info->n_phy; - sha->lldd_max_execute_num = 1; - sha->lldd_queue_size = PM8001_CAN_QUEUE; sha->core.shost = shost; } diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index 76570e6a547d..b93f289b42b3 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c @@ -350,7 +350,7 @@ static int sas_find_local_port_id(struct domain_device *dev) */ #define DEV_IS_GONE(pm8001_dev) \ ((!pm8001_dev || (pm8001_dev->dev_type == SAS_PHY_UNUSED))) -static int pm8001_task_exec(struct sas_task *task, const int num, +static int pm8001_task_exec(struct sas_task *task, gfp_t gfp_flags, int is_tmf, struct pm8001_tmf_task *tmf) { struct domain_device *dev = task->dev; @@ -360,7 +360,6 @@ static int pm8001_task_exec(struct sas_task *task, const int num, struct sas_task *t = task; struct pm8001_ccb_info *ccb; u32 tag = 0xdeadbeef, rc, n_elem = 0; - u32 n = num; unsigned long flags = 0; if (!dev->port) { @@ -387,18 +386,12 @@ static int pm8001_task_exec(struct sas_task *task, const int num, spin_unlock_irqrestore(&pm8001_ha->lock, flags); t->task_done(t); spin_lock_irqsave(&pm8001_ha->lock, flags); - if (n > 1) - t = list_entry(t->list.next, - struct sas_task, list); continue; } else { struct task_status_struct *ts = &t->task_status; ts->resp = SAS_TASK_UNDELIVERED; ts->stat = SAS_PHY_DOWN; t->task_done(t); - if (n > 1) - t = list_entry(t->list.next, - struct sas_task, list); continue; } } @@ -460,9 +453,7 @@ static int pm8001_task_exec(struct sas_task *task, const int num, t->task_state_flags |= SAS_TASK_AT_INITIATOR; spin_unlock(&t->task_state_lock); pm8001_dev->running_req++; - if (n > 1) - t = list_entry(t->list.next, struct sas_task, list); - } while (--n); + } while (0); rc = 0; goto out_done; @@ -483,14 +474,11 @@ out_done: * pm8001_queue_command - register for upper layer used, all IO commands sent * to HBA are from this interface. * @task: the task to be execute. - * @num: if can_queue great than 1, the task can be queued up. for SMP task, - * we always execute one one time * @gfp_flags: gfp_flags */ -int pm8001_queue_command(struct sas_task *task, const int num, - gfp_t gfp_flags) +int pm8001_queue_command(struct sas_task *task, gfp_t gfp_flags) { - return pm8001_task_exec(task, num, gfp_flags, 0, NULL); + return pm8001_task_exec(task, gfp_flags, 0, NULL); } /** @@ -708,7 +696,7 @@ static int pm8001_exec_internal_tmf_task(struct domain_device *dev, task->slow_task->timer.expires = jiffies + PM8001_TASK_TIMEOUT*HZ; add_timer(&task->slow_task->timer); - res = pm8001_task_exec(task, 1, GFP_KERNEL, 1, tmf); + res = pm8001_task_exec(task, GFP_KERNEL, 1, tmf); if (res) { del_timer(&task->slow_task->timer); diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h index f6b2ac59dae4..8dd8b7840f04 100644 --- a/drivers/scsi/pm8001/pm8001_sas.h +++ b/drivers/scsi/pm8001/pm8001_sas.h @@ -623,8 +623,7 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func, void *funcdata); void pm8001_scan_start(struct Scsi_Host *shost); int pm8001_scan_finished(struct Scsi_Host *shost, unsigned long time); -int pm8001_queue_command(struct sas_task *task, const int num, - gfp_t gfp_flags); +int pm8001_queue_command(struct sas_task *task, gfp_t gfp_flags); int pm8001_abort_task(struct sas_task *task); int pm8001_abort_task_set(struct domain_device *dev, u8 *lun); int pm8001_clear_aca(struct domain_device *dev, u8 *lun); diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index 1f8b33ec612f..832dcc9f86ec 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h @@ -365,12 +365,6 @@ struct asd_sas_phy { struct scsi_core { struct Scsi_Host *shost; - struct mutex task_queue_flush; - spinlock_t task_queue_lock; - struct list_head task_queue; - int task_queue_size; - - struct task_struct *queue_thread; }; struct sas_ha_event { @@ -422,9 +416,6 @@ struct sas_ha_struct { struct asd_sas_port **sas_port; /* array of valid pointers, must be set */ int num_phys; /* must be set, gt 0, static */ - /* The class calls this to send a task for execution. */ - int lldd_max_execute_num; - int lldd_queue_size; int strict_wide_ports; /* both sas_addr and attached_sas_addr must match * their siblings when forming wide ports */ @@ -612,7 +603,6 @@ struct sas_ssp_task { struct sas_task { struct domain_device *dev; - struct list_head list; spinlock_t task_state_lock; unsigned task_state_flags; @@ -665,8 +655,7 @@ struct sas_domain_function_template { int (*lldd_dev_found)(struct domain_device *); void (*lldd_dev_gone)(struct domain_device *); - int (*lldd_execute_task)(struct sas_task *, int num, - gfp_t gfp_flags); + int (*lldd_execute_task)(struct sas_task *, gfp_t gfp_flags); /* Task Management Functions. Must be called from process context. */ int (*lldd_abort_task)(struct sas_task *); @@ -700,7 +689,6 @@ extern void sas_suspend_ha(struct sas_ha_struct *sas_ha); int sas_set_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates); int sas_phy_reset(struct sas_phy *phy, int hard_reset); -int sas_queue_up(struct sas_task *task); extern int sas_queuecommand(struct Scsi_Host * ,struct scsi_cmnd *); extern int sas_target_alloc(struct scsi_target *); extern int sas_slave_configure(struct scsi_device *); -- cgit v1.2.3-59-g8ed1b From a81a6c654bbe129af529d11b4763367af90d1152 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 12 May 2014 11:37:17 +0200 Subject: ARM: dt: fix up PL011 device tree bindings Make the map match the reality, the current binding text is nonsense: - The clock required for the clocking of the serial port must come first and is not optional (as the driver will otherwise proceed to grab and use the apb_pclk as uartclk), and the apb_pclk that clocks the logic must come second as the code will retrieve the first clock by index, whereas the PrimeCell but will explicitly look for "apb_pclk" so this can be specified later, as it is looked up by name. - The pin control state "default" is the only mandated state, the sleep state is entirely optional. We also add an example to avoid further confusion. Reported-by: Arnd Bergmann Signed-off-by: Linus Walleij Signed-off-by: Grant Likely --- Documentation/devicetree/bindings/serial/pl011.txt | 28 +++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/serial/pl011.txt b/Documentation/devicetree/bindings/serial/pl011.txt index 5d2e840ae65c..52464918cfe2 100644 --- a/Documentation/devicetree/bindings/serial/pl011.txt +++ b/Documentation/devicetree/bindings/serial/pl011.txt @@ -6,12 +6,34 @@ Required properties: - interrupts: exactly one interrupt specifier Optional properties: -- pinctrl: When present, must have one state named "sleep" - and one state named "default" -- clocks: When present, must refer to exactly one clock named +- pinctrl: When present, must have one state named "default", + and may contain a second name named "sleep". The former + state sets up pins for ordinary operation whereas + the latter state will put the associated pins to sleep + when the UART is unused +- clocks: When present, the first clock listed must correspond to + the clock named UARTCLK on the IP block, i.e. the clock + to the external serial line, whereas the second clock + must correspond to the PCLK clocking the internal logic + of the block. Just listing one clock (the first one) is + deprecated. +- clocks-names: When present, the first clock listed must be named + "uartclk" and the second clock listed must be named "apb_pclk" - dmas: When present, may have one or two dma channels. The first one must be named "rx", the second one must be named "tx". See also bindings/arm/primecell.txt + +Example: + +uart@80120000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x80120000 0x1000>; + interrupts = <0 11 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&dma 13 0 0x2>, <&dma 13 0 0x0>; + dma-names = "rx", "tx"; + clocks = <&foo_clk>, <&bar_clk>; + clock-names = "uartclk", "apb_pclk"; +}; -- cgit v1.2.3-59-g8ed1b From 62421645bb702c077ee5a462815525106cb53bcf Mon Sep 17 00:00:00 2001 From: Phillip Lougher Date: Thu, 27 Nov 2014 18:48:44 +0000 Subject: Squashfs: Add LZ4 compression configuration option Add the glue code, and also update the documentation. Signed-off-by: Phillip Lougher --- Documentation/filesystems/squashfs.txt | 8 ++++---- fs/squashfs/Kconfig | 15 +++++++++++++++ fs/squashfs/Makefile | 1 + fs/squashfs/decompressor.c | 7 +++++++ fs/squashfs/decompressor.h | 4 ++++ 5 files changed, 31 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/squashfs.txt b/Documentation/filesystems/squashfs.txt index 403c090aca39..e5274f84dc56 100644 --- a/Documentation/filesystems/squashfs.txt +++ b/Documentation/filesystems/squashfs.txt @@ -2,10 +2,10 @@ SQUASHFS 4.0 FILESYSTEM ======================= Squashfs is a compressed read-only filesystem for Linux. -It uses zlib/lzo/xz compression to compress files, inodes and directories. -Inodes in the system are very small and all blocks are packed to minimise -data overhead. Block sizes greater than 4K are supported up to a maximum -of 1Mbytes (default block size 128K). +It uses zlib, lz4, lzo, or xz compression to compress files, inodes and +directories. Inodes in the system are very small and all blocks are packed to +minimise data overhead. Block sizes greater than 4K are supported up to a +maximum of 1Mbytes (default block size 128K). Squashfs is intended for general read-only filesystem use, for archival use (i.e. in cases where a .tar.gz file may be used), and in constrained diff --git a/fs/squashfs/Kconfig b/fs/squashfs/Kconfig index b6fa8657dcbc..ffb093e72b6c 100644 --- a/fs/squashfs/Kconfig +++ b/fs/squashfs/Kconfig @@ -120,6 +120,21 @@ config SQUASHFS_ZLIB If unsure, say Y. +config SQUASHFS_LZ4 + bool "Include support for LZ4 compressed file systems" + depends on SQUASHFS + select LZ4_DECOMPRESS + help + Saying Y here includes support for reading Squashfs file systems + compressed with LZ4 compression. LZ4 compression is mainly + aimed at embedded systems with slower CPUs where the overheads + of zlib are too high. + + LZ4 is not the standard compression used in Squashfs and so most + file systems will be readable without selecting this option. + + If unsure, say N. + config SQUASHFS_LZO bool "Include support for LZO compressed file systems" depends on SQUASHFS diff --git a/fs/squashfs/Makefile b/fs/squashfs/Makefile index 4132520b4ff2..246a6f329d89 100644 --- a/fs/squashfs/Makefile +++ b/fs/squashfs/Makefile @@ -11,6 +11,7 @@ squashfs-$(CONFIG_SQUASHFS_DECOMP_SINGLE) += decompressor_single.o squashfs-$(CONFIG_SQUASHFS_DECOMP_MULTI) += decompressor_multi.o squashfs-$(CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU) += decompressor_multi_percpu.o squashfs-$(CONFIG_SQUASHFS_XATTR) += xattr.o xattr_id.o +squashfs-$(CONFIG_SQUASHFS_LZ4) += lz4_wrapper.o squashfs-$(CONFIG_SQUASHFS_LZO) += lzo_wrapper.o squashfs-$(CONFIG_SQUASHFS_XZ) += xz_wrapper.o squashfs-$(CONFIG_SQUASHFS_ZLIB) += zlib_wrapper.o diff --git a/fs/squashfs/decompressor.c b/fs/squashfs/decompressor.c index ac22fe73b0ad..e9034bf6e5ae 100644 --- a/fs/squashfs/decompressor.c +++ b/fs/squashfs/decompressor.c @@ -41,6 +41,12 @@ static const struct squashfs_decompressor squashfs_lzma_unsupported_comp_ops = { NULL, NULL, NULL, NULL, LZMA_COMPRESSION, "lzma", 0 }; +#ifndef CONFIG_SQUASHFS_LZ4 +static const struct squashfs_decompressor squashfs_lz4_comp_ops = { + NULL, NULL, NULL, NULL, LZ4_COMPRESSION, "lz4", 0 +}; +#endif + #ifndef CONFIG_SQUASHFS_LZO static const struct squashfs_decompressor squashfs_lzo_comp_ops = { NULL, NULL, NULL, NULL, LZO_COMPRESSION, "lzo", 0 @@ -65,6 +71,7 @@ static const struct squashfs_decompressor squashfs_unknown_comp_ops = { static const struct squashfs_decompressor *decompressor[] = { &squashfs_zlib_comp_ops, + &squashfs_lz4_comp_ops, &squashfs_lzo_comp_ops, &squashfs_xz_comp_ops, &squashfs_lzma_unsupported_comp_ops, diff --git a/fs/squashfs/decompressor.h b/fs/squashfs/decompressor.h index af0985321808..a25713c031a5 100644 --- a/fs/squashfs/decompressor.h +++ b/fs/squashfs/decompressor.h @@ -46,6 +46,10 @@ static inline void *squashfs_comp_opts(struct squashfs_sb_info *msblk, extern const struct squashfs_decompressor squashfs_xz_comp_ops; #endif +#ifdef CONFIG_SQUASHFS_LZ4 +extern const struct squashfs_decompressor squashfs_lz4_comp_ops; +#endif + #ifdef CONFIG_SQUASHFS_LZO extern const struct squashfs_decompressor squashfs_lzo_comp_ops; #endif -- cgit v1.2.3-59-g8ed1b From d1d6786846e1c40f780edb83569597a8a7769e95 Mon Sep 17 00:00:00 2001 From: Kevin Cernekee Date: Tue, 25 Nov 2014 16:49:52 -0800 Subject: bus: brcmstb_gisb: Add register offset tables for older chips This will select the appropriate register layout based on the DT "compatible" string. Signed-off-by: Kevin Cernekee Signed-off-by: Florian Fainelli --- .../devicetree/bindings/bus/brcm,gisb-arb.txt | 6 ++- drivers/bus/brcmstb_gisb.c | 52 +++++++++++++++++++--- 2 files changed, 51 insertions(+), 7 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/bus/brcm,gisb-arb.txt b/Documentation/devicetree/bindings/bus/brcm,gisb-arb.txt index e2d501d20c9a..1eceefb20f01 100644 --- a/Documentation/devicetree/bindings/bus/brcm,gisb-arb.txt +++ b/Documentation/devicetree/bindings/bus/brcm,gisb-arb.txt @@ -2,7 +2,11 @@ Broadcom GISB bus Arbiter controller Required properties: -- compatible: should be "brcm,gisb-arb" +- compatible: + "brcm,gisb-arb" or "brcm,bcm7445-gisb-arb" for 28nm chips + "brcm,bcm7435-gisb-arb" for newer 40nm chips + "brcm,bcm7400-gisb-arb" for older 40nm chips and all 65nm chips + "brcm,bcm7038-gisb-arb" for 130nm chips - reg: specifies the base physical address and size of the registers - interrupt-parent: specifies the phandle to the parent interrupt controller this arbiter gets interrupt line from diff --git a/drivers/bus/brcmstb_gisb.c b/drivers/bus/brcmstb_gisb.c index ef1e4238ef5f..172908da5957 100644 --- a/drivers/bus/brcmstb_gisb.c +++ b/drivers/bus/brcmstb_gisb.c @@ -47,6 +47,36 @@ enum { ARB_ERR_CAP_MASTER, }; +static const int gisb_offsets_bcm7038[] = { + [ARB_TIMER] = 0x00c, + [ARB_ERR_CAP_CLR] = 0x0c4, + [ARB_ERR_CAP_HI_ADDR] = -1, + [ARB_ERR_CAP_ADDR] = 0x0c8, + [ARB_ERR_CAP_DATA] = 0x0cc, + [ARB_ERR_CAP_STATUS] = 0x0d0, + [ARB_ERR_CAP_MASTER] = -1, +}; + +static const int gisb_offsets_bcm7400[] = { + [ARB_TIMER] = 0x00c, + [ARB_ERR_CAP_CLR] = 0x0c8, + [ARB_ERR_CAP_HI_ADDR] = -1, + [ARB_ERR_CAP_ADDR] = 0x0cc, + [ARB_ERR_CAP_DATA] = 0x0d0, + [ARB_ERR_CAP_STATUS] = 0x0d4, + [ARB_ERR_CAP_MASTER] = 0x0d8, +}; + +static const int gisb_offsets_bcm7435[] = { + [ARB_TIMER] = 0x00c, + [ARB_ERR_CAP_CLR] = 0x168, + [ARB_ERR_CAP_HI_ADDR] = -1, + [ARB_ERR_CAP_ADDR] = 0x16c, + [ARB_ERR_CAP_DATA] = 0x170, + [ARB_ERR_CAP_STATUS] = 0x174, + [ARB_ERR_CAP_MASTER] = 0x178, +}; + static const int gisb_offsets_bcm7445[] = { [ARB_TIMER] = 0x008, [ARB_ERR_CAP_CLR] = 0x7e4, @@ -230,10 +260,20 @@ static struct attribute_group gisb_arb_sysfs_attr_group = { .attrs = gisb_arb_sysfs_attrs, }; +static const struct of_device_id brcmstb_gisb_arb_of_match[] = { + { .compatible = "brcm,gisb-arb", .data = gisb_offsets_bcm7445 }, + { .compatible = "brcm,bcm7445-gisb-arb", .data = gisb_offsets_bcm7445 }, + { .compatible = "brcm,bcm7435-gisb-arb", .data = gisb_offsets_bcm7435 }, + { .compatible = "brcm,bcm7400-gisb-arb", .data = gisb_offsets_bcm7400 }, + { .compatible = "brcm,bcm7038-gisb-arb", .data = gisb_offsets_bcm7038 }, + { }, +}; + static int brcmstb_gisb_arb_probe(struct platform_device *pdev) { struct device_node *dn = pdev->dev.of_node; struct brcmstb_gisb_arb_device *gdev; + const struct of_device_id *of_id; struct resource *r; int err, timeout_irq, tea_irq; unsigned int num_masters, j = 0; @@ -254,7 +294,12 @@ static int brcmstb_gisb_arb_probe(struct platform_device *pdev) if (IS_ERR(gdev->base)) return PTR_ERR(gdev->base); - gdev->gisb_offsets = gisb_offsets_bcm7445; + of_id = of_match_node(brcmstb_gisb_arb_of_match, dn); + if (!of_id) { + pr_err("failed to look up compatible string\n"); + return -EINVAL; + } + gdev->gisb_offsets = of_id->data; err = devm_request_irq(&pdev->dev, timeout_irq, brcmstb_gisb_timeout_handler, 0, pdev->name, @@ -307,11 +352,6 @@ static int brcmstb_gisb_arb_probe(struct platform_device *pdev) return 0; } -static const struct of_device_id brcmstb_gisb_arb_of_match[] = { - { .compatible = "brcm,gisb-arb" }, - { }, -}; - static struct platform_driver brcmstb_gisb_arb_driver = { .probe = brcmstb_gisb_arb_probe, .driver = { -- cgit v1.2.3-59-g8ed1b From a0e89c02da974838053a3604025e43600dc6ac45 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Fri, 21 Nov 2014 17:00:03 +0100 Subject: bus: mvebu-mbus: suspend/resume support This commit extends the mvebu-mbus driver to provide suspend/resume support. Since mvebu-mbus is not a platform_driver, the syscore_ops mechanism is used to get ->suspend() and ->resume() hooks called into the driver. In those hooks, we save and restore the MBus windows state, to make sure after resume all Mbus windows are properly restored. Note that while the state of some windows could be gathered by looking again at the Device Tree (for statically described windows), it is not the case of dynamically described windows such as the PCIe memory and I/O windows. Therefore, we take the simple approach of saving and restoring the registers for all MBus windows. In addition, the commit extends the Device Tree binding of the MBus controller, to control the MBus bridge registers (which define which parts of the physical address space is routed to MBus windows vs. normal RAM memory). Those registers must be saved and restored during suspend/resume. The Device Tree binding extension is made is a backward compatible fashion, but of course, suspend/resume will not work without the Device Tree update. Signed-off-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1416585613-2113-7-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- .../devicetree/bindings/bus/mvebu-mbus.txt | 17 +-- drivers/bus/mvebu-mbus.c | 124 ++++++++++++++++++++- 2 files changed, 130 insertions(+), 11 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/bus/mvebu-mbus.txt b/Documentation/devicetree/bindings/bus/mvebu-mbus.txt index 5fa44f52a0b8..5e16c3ccb061 100644 --- a/Documentation/devicetree/bindings/bus/mvebu-mbus.txt +++ b/Documentation/devicetree/bindings/bus/mvebu-mbus.txt @@ -48,9 +48,12 @@ Required properties: - compatible: Should be set to "marvell,mbus-controller". - reg: Device's register space. - Two entries are expected (see the examples below): - the first one controls the devices decoding window and - the second one controls the SDRAM decoding window. + Two or three entries are expected (see the examples below): + the first one controls the devices decoding window, + the second one controls the SDRAM decoding window and + the third controls the MBus bridge (only with the + marvell,armada370-mbus and marvell,armadaxp-mbus + compatible strings) Example: @@ -67,7 +70,7 @@ Example: mbusc: mbus-controller@20000 { compatible = "marvell,mbus-controller"; - reg = <0x20000 0x100>, <0x20180 0x20>; + reg = <0x20000 0x100>, <0x20180 0x20>, <0x20250 0x8>; }; /* more children ...*/ @@ -126,7 +129,7 @@ are skipped. mbusc: mbus-controller@20000 { compatible = "marvell,mbus-controller"; - reg = <0x20000 0x100>, <0x20180 0x20>; + reg = <0x20000 0x100>, <0x20180 0x20>, <0x20250 0x8>; }; /* more children ...*/ @@ -170,7 +173,7 @@ Using this macro, the above example would be: mbusc: mbus-controller@20000 { compatible = "marvell,mbus-controller"; - reg = <0x20000 0x100>, <0x20180 0x20>; + reg = <0x20000 0x100>, <0x20180 0x20>, <0x20250 0x8>; }; /* other children */ @@ -266,7 +269,7 @@ See the example below, where a more complete device tree is shown: ranges = <0 MBUS_ID(0xf0, 0x01) 0 0x100000>; mbusc: mbus-controller@20000 { - reg = <0x20000 0x100>, <0x20180 0x20>; + reg = <0x20000 0x100>, <0x20180 0x20>, <0x20250 0x8>; }; interrupt-controller@20000 { diff --git a/drivers/bus/mvebu-mbus.c b/drivers/bus/mvebu-mbus.c index 26c3779d871d..e8c159399c82 100644 --- a/drivers/bus/mvebu-mbus.c +++ b/drivers/bus/mvebu-mbus.c @@ -57,6 +57,7 @@ #include #include #include +#include /* * DDR target is the same on all platforms. @@ -94,20 +95,39 @@ #define DOVE_DDR_BASE_CS_OFF(n) ((n) << 4) +/* Relative to mbusbridge_base */ +#define MBUS_BRIDGE_CTRL_OFF 0x0 +#define MBUS_BRIDGE_BASE_OFF 0x4 + +/* Maximum number of windows, for all known platforms */ +#define MBUS_WINS_MAX 20 + struct mvebu_mbus_state; struct mvebu_mbus_soc_data { unsigned int num_wins; unsigned int num_remappable_wins; + bool has_mbus_bridge; unsigned int (*win_cfg_offset)(const int win); void (*setup_cpu_target)(struct mvebu_mbus_state *s); int (*show_cpu_target)(struct mvebu_mbus_state *s, struct seq_file *seq, void *v); }; +/* + * Used to store the state of one MBus window accross suspend/resume. + */ +struct mvebu_mbus_win_data { + u32 ctrl; + u32 base; + u32 remap_lo; + u32 remap_hi; +}; + struct mvebu_mbus_state { void __iomem *mbuswins_base; void __iomem *sdramwins_base; + void __iomem *mbusbridge_base; struct dentry *debugfs_root; struct dentry *debugfs_sdram; struct dentry *debugfs_devs; @@ -115,6 +135,11 @@ struct mvebu_mbus_state { struct resource pcie_io_aperture; const struct mvebu_mbus_soc_data *soc; int hw_io_coherency; + + /* Used during suspend/resume */ + u32 mbus_bridge_ctrl; + u32 mbus_bridge_base; + struct mvebu_mbus_win_data wins[MBUS_WINS_MAX]; }; static struct mvebu_mbus_state mbus_state; @@ -549,6 +574,7 @@ mvebu_mbus_dove_setup_cpu_target(struct mvebu_mbus_state *mbus) static const struct mvebu_mbus_soc_data armada_370_xp_mbus_data = { .num_wins = 20, .num_remappable_wins = 8, + .has_mbus_bridge = true, .win_cfg_offset = armada_370_xp_mbus_win_offset, .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, .show_cpu_target = mvebu_sdram_debug_show_orion, @@ -698,11 +724,73 @@ static __init int mvebu_mbus_debugfs_init(void) } fs_initcall(mvebu_mbus_debugfs_init); +static int mvebu_mbus_suspend(void) +{ + struct mvebu_mbus_state *s = &mbus_state; + int win; + + if (!s->mbusbridge_base) + return -ENODEV; + + for (win = 0; win < s->soc->num_wins; win++) { + void __iomem *addr = s->mbuswins_base + + s->soc->win_cfg_offset(win); + + s->wins[win].base = readl(addr + WIN_BASE_OFF); + s->wins[win].ctrl = readl(addr + WIN_CTRL_OFF); + + if (win >= s->soc->num_remappable_wins) + continue; + + s->wins[win].remap_lo = readl(addr + WIN_REMAP_LO_OFF); + s->wins[win].remap_hi = readl(addr + WIN_REMAP_HI_OFF); + } + + s->mbus_bridge_ctrl = readl(s->mbusbridge_base + + MBUS_BRIDGE_CTRL_OFF); + s->mbus_bridge_base = readl(s->mbusbridge_base + + MBUS_BRIDGE_BASE_OFF); + + return 0; +} + +static void mvebu_mbus_resume(void) +{ + struct mvebu_mbus_state *s = &mbus_state; + int win; + + writel(s->mbus_bridge_ctrl, + s->mbusbridge_base + MBUS_BRIDGE_CTRL_OFF); + writel(s->mbus_bridge_base, + s->mbusbridge_base + MBUS_BRIDGE_BASE_OFF); + + for (win = 0; win < s->soc->num_wins; win++) { + void __iomem *addr = s->mbuswins_base + + s->soc->win_cfg_offset(win); + + writel(s->wins[win].base, addr + WIN_BASE_OFF); + writel(s->wins[win].ctrl, addr + WIN_CTRL_OFF); + + if (win >= s->soc->num_remappable_wins) + continue; + + writel(s->wins[win].remap_lo, addr + WIN_REMAP_LO_OFF); + writel(s->wins[win].remap_hi, addr + WIN_REMAP_HI_OFF); + } +} + +struct syscore_ops mvebu_mbus_syscore_ops = { + .suspend = mvebu_mbus_suspend, + .resume = mvebu_mbus_resume, +}; + static int __init mvebu_mbus_common_init(struct mvebu_mbus_state *mbus, phys_addr_t mbuswins_phys_base, size_t mbuswins_size, phys_addr_t sdramwins_phys_base, - size_t sdramwins_size) + size_t sdramwins_size, + phys_addr_t mbusbridge_phys_base, + size_t mbusbridge_size) { int win; @@ -716,11 +804,24 @@ static int __init mvebu_mbus_common_init(struct mvebu_mbus_state *mbus, return -ENOMEM; } + if (mbusbridge_phys_base) { + mbus->mbusbridge_base = ioremap(mbusbridge_phys_base, + mbusbridge_size); + if (!mbus->mbusbridge_base) { + iounmap(mbus->sdramwins_base); + iounmap(mbus->mbuswins_base); + return -ENOMEM; + } + } else + mbus->mbusbridge_base = NULL; + for (win = 0; win < mbus->soc->num_wins; win++) mvebu_mbus_disable_window(mbus, win); mbus->soc->setup_cpu_target(mbus); + register_syscore_ops(&mvebu_mbus_syscore_ops); + return 0; } @@ -746,7 +847,7 @@ int __init mvebu_mbus_init(const char *soc, phys_addr_t mbuswins_phys_base, mbuswins_phys_base, mbuswins_size, sdramwins_phys_base, - sdramwins_size); + sdramwins_size, 0, 0); } #ifdef CONFIG_OF @@ -887,7 +988,7 @@ static void __init mvebu_mbus_get_pcie_resources(struct device_node *np, int __init mvebu_mbus_dt_init(bool is_coherent) { - struct resource mbuswins_res, sdramwins_res; + struct resource mbuswins_res, sdramwins_res, mbusbridge_res; struct device_node *np, *controller; const struct of_device_id *of_id; const __be32 *prop; @@ -923,6 +1024,19 @@ int __init mvebu_mbus_dt_init(bool is_coherent) return -EINVAL; } + /* + * Set the resource to 0 so that it can be left unmapped by + * mvebu_mbus_common_init() if the DT doesn't carry the + * necessary information. This is needed to preserve backward + * compatibility. + */ + memset(&mbusbridge_res, 0, sizeof(mbusbridge_res)); + + if (mbus_state.soc->has_mbus_bridge) { + if (of_address_to_resource(controller, 2, &mbusbridge_res)) + pr_warn(FW_WARN "deprecated mbus-mvebu Device Tree, suspend/resume will not work\n"); + } + mbus_state.hw_io_coherency = is_coherent; /* Get optional pcie-{mem,io}-aperture properties */ @@ -933,7 +1047,9 @@ int __init mvebu_mbus_dt_init(bool is_coherent) mbuswins_res.start, resource_size(&mbuswins_res), sdramwins_res.start, - resource_size(&sdramwins_res)); + resource_size(&sdramwins_res), + mbusbridge_res.start, + resource_size(&mbusbridge_res)); if (ret) return ret; -- cgit v1.2.3-59-g8ed1b From 7e9d62d3878654f485bde016f54d1b9d2c84cf6b Mon Sep 17 00:00:00 2001 From: Alan Tull Date: Wed, 15 Oct 2014 13:55:07 -0500 Subject: hwmon: (ltc2978) device tree bindings documentation Add device tree bindings documentation for ltc2978. Signed-off-by: Alan Tull Cc: Mark Rutland Cc: Mark Brown [Guenter Roeck: Minor correction of 'compatible' example] Signed-off-by: Guenter Roeck --- .../devicetree/bindings/hwmon/ltc2978.txt | 39 ++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 Documentation/devicetree/bindings/hwmon/ltc2978.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/hwmon/ltc2978.txt b/Documentation/devicetree/bindings/hwmon/ltc2978.txt new file mode 100644 index 000000000000..ed2f09dc2483 --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/ltc2978.txt @@ -0,0 +1,39 @@ +ltc2978 + +Required properties: +- compatible: should contain one of: + * "lltc,ltc2974" + * "lltc,ltc2977" + * "lltc,ltc2978" + * "lltc,ltc3880" + * "lltc,ltc3883" + * "lltc,ltm4676" +- reg: I2C slave address + +Optional properties: +- regulators: A node that houses a sub-node for each regulator controlled by + the device. Each sub-node is identified using the node's name, with valid + values listed below. The content of each sub-node is defined by the + standard binding for regulators; see regulator.txt. + +Valid names of regulators depend on number of supplies supported per device: + * ltc2974 : vout0 - vout3 + * ltc2977 : vout0 - vout7 + * ltc2978 : vout0 - vout7 + * ltc3880 : vout0 - vout1 + * ltc3883 : vout0 + * ltm4676 : vout0 - vout1 + +Example: +ltc2978@5e { + compatible = "lltc,ltc2978"; + reg = <0x5e>; + regulators { + vout0 { + regulator-name = "FPGA-2.5V"; + }; + vout2 { + regulator-name = "FPGA-1.5V"; + }; + }; +}; -- cgit v1.2.3-59-g8ed1b From 3434f37835804331dd505722cd0010d708305837 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 29 Jun 2014 19:38:45 -0700 Subject: hwmon: Driver for Nuvoton NCT7802Y NCT7802Y is an I2C based hardware monitoring chip from Nuvoton. Signed-off-by: Guenter Roeck --- Documentation/hwmon/nct7802 | 32 ++ drivers/hwmon/Kconfig | 11 + drivers/hwmon/Makefile | 1 + drivers/hwmon/nct7802.c | 860 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 904 insertions(+) create mode 100644 Documentation/hwmon/nct7802 create mode 100644 drivers/hwmon/nct7802.c (limited to 'Documentation') diff --git a/Documentation/hwmon/nct7802 b/Documentation/hwmon/nct7802 new file mode 100644 index 000000000000..2e00f5e344bc --- /dev/null +++ b/Documentation/hwmon/nct7802 @@ -0,0 +1,32 @@ +Kernel driver nct7802 +===================== + +Supported chips: + * Nuvoton NCT7802Y + Prefix: 'nct7802' + Addresses scanned: I2C 0x28..0x2f + Datasheet: Available from Nuvoton web site + +Authors: + Guenter Roeck + +Description +----------- + +This driver implements support for the Nuvoton NCT7802Y hardware monitoring +chip. NCT7802Y supports 6 temperature sensors, 5 voltage sensors, and 3 fan +speed sensors. + +The chip also supports intelligent fan speed control. This functionality is +not currently supported by the driver. + +Tested Boards and BIOS Versions +------------------------------- + +The driver has been reported to work with the following boards and +BIOS versions. + +Board BIOS version +--------------------------------------------------------------- +Kontron COMe-bSC2 CHR2E934.001.GGO +Kontron COMe-bIP2 CCR2E212 diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 5286d7ce1f9e..f893e0ff0081 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1123,6 +1123,17 @@ config SENSORS_NCT6775 This driver can also be built as a module. If so, the module will be called nct6775. +config SENSORS_NCT7802 + tristate "Nuvoton NCT7802Y" + depends on I2C + select REGMAP_I2C + help + If you say yes here you get support for the Nuvoton NCT7802Y + hardware monitoring chip. + + This driver can also be built as a module. If so, the module + will be called nct7802. + config SENSORS_PCF8591 tristate "Philips PCF8591 ADC/DAC" depends on I2C diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index c90a7611efaa..67280643bcf0 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -118,6 +118,7 @@ obj-$(CONFIG_SENSORS_MCP3021) += mcp3021.o 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_NTC_THERMISTOR) += ntc_thermistor.o obj-$(CONFIG_SENSORS_PC87360) += pc87360.o obj-$(CONFIG_SENSORS_PC87427) += pc87427.o diff --git a/drivers/hwmon/nct7802.c b/drivers/hwmon/nct7802.c new file mode 100644 index 000000000000..ec5678289e4a --- /dev/null +++ b/drivers/hwmon/nct7802.c @@ -0,0 +1,860 @@ +/* + * nct7802 - Driver for Nuvoton NCT7802Y + * + * Copyright (C) 2014 Guenter Roeck + * + * 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. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRVNAME "nct7802" + +static const u8 REG_VOLTAGE[5] = { 0x09, 0x0a, 0x0c, 0x0d, 0x0e }; + +static const u8 REG_VOLTAGE_LIMIT_LSB[2][5] = { + { 0x40, 0x00, 0x42, 0x44, 0x46 }, + { 0x3f, 0x00, 0x41, 0x43, 0x45 }, +}; + +static const u8 REG_VOLTAGE_LIMIT_MSB[5] = { 0x48, 0x00, 0x47, 0x47, 0x48 }; + +static const u8 REG_VOLTAGE_LIMIT_MSB_SHIFT[2][5] = { + { 0, 0, 4, 0, 4 }, + { 2, 0, 6, 2, 6 }, +}; + +#define REG_BANK 0x00 +#define REG_TEMP_LSB 0x05 +#define REG_TEMP_PECI_LSB 0x08 +#define REG_VOLTAGE_LOW 0x0f +#define REG_FANCOUNT_LOW 0x13 +#define REG_START 0x21 +#define REG_MODE 0x22 +#define REG_PECI_ENABLE 0x23 +#define REG_FAN_ENABLE 0x24 +#define REG_VMON_ENABLE 0x25 +#define REG_VENDOR_ID 0xfd +#define REG_CHIP_ID 0xfe +#define REG_VERSION_ID 0xff + +/* + * Data structures and manipulation thereof + */ + +struct nct7802_data { + struct regmap *regmap; + struct mutex access_lock; /* for multi-byte read and write operations */ +}; + +static int nct7802_read_temp(struct nct7802_data *data, + u8 reg_temp, u8 reg_temp_low, int *temp) +{ + unsigned int t1, t2 = 0; + int err; + + *temp = 0; + + mutex_lock(&data->access_lock); + err = regmap_read(data->regmap, reg_temp, &t1); + if (err < 0) + goto abort; + t1 <<= 8; + if (reg_temp_low) { /* 11 bit data */ + err = regmap_read(data->regmap, reg_temp_low, &t2); + if (err < 0) + goto abort; + } + t1 |= t2 & 0xe0; + *temp = (s16)t1 / 32 * 125; +abort: + mutex_unlock(&data->access_lock); + return err; +} + +static int nct7802_read_fan(struct nct7802_data *data, u8 reg_fan) +{ + unsigned int f1, f2; + int ret; + + mutex_lock(&data->access_lock); + ret = regmap_read(data->regmap, reg_fan, &f1); + if (ret < 0) + goto abort; + ret = regmap_read(data->regmap, REG_FANCOUNT_LOW, &f2); + if (ret < 0) + goto abort; + ret = (f1 << 5) | (f2 >> 3); + /* convert fan count to rpm */ + if (ret == 0x1fff) /* maximum value, assume fan is stopped */ + ret = 0; + else if (ret) + ret = DIV_ROUND_CLOSEST(1350000U, ret); +abort: + mutex_unlock(&data->access_lock); + return ret; +} + +static int nct7802_read_fan_min(struct nct7802_data *data, u8 reg_fan_low, + u8 reg_fan_high) +{ + unsigned int f1, f2; + int ret; + + mutex_lock(&data->access_lock); + ret = regmap_read(data->regmap, reg_fan_low, &f1); + if (ret < 0) + goto abort; + ret = regmap_read(data->regmap, reg_fan_high, &f2); + if (ret < 0) + goto abort; + ret = f1 | ((f2 & 0xf8) << 5); + /* convert fan count to rpm */ + if (ret == 0x1fff) /* maximum value, assume no limit */ + ret = 0; + else if (ret) + ret = DIV_ROUND_CLOSEST(1350000U, ret); +abort: + mutex_unlock(&data->access_lock); + return ret; +} + +static int nct7802_write_fan_min(struct nct7802_data *data, u8 reg_fan_low, + u8 reg_fan_high, unsigned int limit) +{ + int err; + + if (limit) + limit = DIV_ROUND_CLOSEST(1350000U, limit); + else + limit = 0x1fff; + limit = clamp_val(limit, 0, 0x1fff); + + mutex_lock(&data->access_lock); + err = regmap_write(data->regmap, reg_fan_low, limit & 0xff); + if (err < 0) + goto abort; + + err = regmap_write(data->regmap, reg_fan_high, (limit & 0x1f00) >> 5); +abort: + mutex_unlock(&data->access_lock); + return err; +} + +static u8 nct7802_vmul[] = { 4, 2, 2, 2, 2 }; + +static int nct7802_read_voltage(struct nct7802_data *data, int nr, int index) +{ + unsigned int v1, v2; + int ret; + + mutex_lock(&data->access_lock); + if (index == 0) { /* voltage */ + ret = regmap_read(data->regmap, REG_VOLTAGE[nr], &v1); + if (ret < 0) + goto abort; + ret = regmap_read(data->regmap, REG_VOLTAGE_LOW, &v2); + if (ret < 0) + goto abort; + ret = ((v1 << 2) | (v2 >> 6)) * nct7802_vmul[nr]; + } else { /* limit */ + int shift = 8 - REG_VOLTAGE_LIMIT_MSB_SHIFT[index - 1][nr]; + + ret = regmap_read(data->regmap, + REG_VOLTAGE_LIMIT_LSB[index - 1][nr], &v1); + if (ret < 0) + goto abort; + ret = regmap_read(data->regmap, REG_VOLTAGE_LIMIT_MSB[nr], + &v2); + if (ret < 0) + goto abort; + ret = (v1 | ((v2 << shift) & 0x300)) * nct7802_vmul[nr]; + } +abort: + mutex_unlock(&data->access_lock); + return ret; +} + +static int nct7802_write_voltage(struct nct7802_data *data, int nr, int index, + unsigned int voltage) +{ + int shift = 8 - REG_VOLTAGE_LIMIT_MSB_SHIFT[index - 1][nr]; + int err; + + voltage = DIV_ROUND_CLOSEST(voltage, nct7802_vmul[nr]); + voltage = clamp_val(voltage, 0, 0x3ff); + + mutex_lock(&data->access_lock); + err = regmap_write(data->regmap, + REG_VOLTAGE_LIMIT_LSB[index - 1][nr], + voltage & 0xff); + if (err < 0) + goto abort; + + err = regmap_update_bits(data->regmap, REG_VOLTAGE_LIMIT_MSB[nr], + 0x0300 >> shift, (voltage & 0x0300) >> shift); +abort: + mutex_unlock(&data->access_lock); + return err; +} + +static ssize_t show_in(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); + struct nct7802_data *data = dev_get_drvdata(dev); + int voltage; + + voltage = nct7802_read_voltage(data, sattr->nr, sattr->index); + if (voltage < 0) + return voltage; + + return sprintf(buf, "%d\n", voltage); +} + +static ssize_t store_in(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); + struct nct7802_data *data = dev_get_drvdata(dev); + int index = sattr->index; + int nr = sattr->nr; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err < 0) + return err; + + err = nct7802_write_voltage(data, nr, index, val); + return err ? : count; +} + +static ssize_t show_temp(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct nct7802_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); + int err, temp; + + err = nct7802_read_temp(data, sattr->nr, sattr->index, &temp); + if (err < 0) + return err; + + return sprintf(buf, "%d\n", temp); +} + +static ssize_t store_temp(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); + struct nct7802_data *data = dev_get_drvdata(dev); + int nr = sattr->nr; + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err < 0) + return err; + + val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127); + + err = regmap_write(data->regmap, nr, val & 0xff); + return err ? : count; +} + +static ssize_t show_fan(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); + struct nct7802_data *data = dev_get_drvdata(dev); + int speed; + + speed = nct7802_read_fan(data, sattr->index); + if (speed < 0) + return speed; + + return sprintf(buf, "%d\n", speed); +} + +static ssize_t show_fan_min(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); + struct nct7802_data *data = dev_get_drvdata(dev); + int speed; + + speed = nct7802_read_fan_min(data, sattr->nr, sattr->index); + if (speed < 0) + return speed; + + return sprintf(buf, "%d\n", speed); +} + +static ssize_t store_fan_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); + struct nct7802_data *data = dev_get_drvdata(dev); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err < 0) + return err; + + err = nct7802_write_fan_min(data, sattr->nr, sattr->index, val); + return err ? : count; +} + +static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct nct7802_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); + int bit = sattr->index; + unsigned int val; + int ret; + + ret = regmap_read(data->regmap, sattr->nr, &val); + if (ret < 0) + return ret; + + return sprintf(buf, "%u\n", !!(val & (1 << bit))); +} + +static ssize_t +show_beep(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); + struct nct7802_data *data = dev_get_drvdata(dev); + unsigned int regval; + int err; + + err = regmap_read(data->regmap, sattr->nr, ®val); + if (err) + return err; + + return sprintf(buf, "%u\n", !!(regval & (1 << sattr->index))); +} + +static ssize_t +store_beep(struct device *dev, struct device_attribute *attr, const char *buf, + size_t count) +{ + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); + struct nct7802_data *data = dev_get_drvdata(dev); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err < 0) + return err; + if (val > 1) + return -EINVAL; + + err = regmap_update_bits(data->regmap, sattr->nr, 1 << sattr->index, + val ? 1 << sattr->index : 0); + return err ? : count; +} + +static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0x01, + REG_TEMP_LSB); +static SENSOR_DEVICE_ATTR_2(temp1_min, S_IRUGO | S_IWUSR, show_temp, + store_temp, 0x31, 0); +static SENSOR_DEVICE_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, show_temp, + store_temp, 0x30, 0); +static SENSOR_DEVICE_ATTR_2(temp1_crit, S_IRUGO | S_IWUSR, show_temp, + store_temp, 0x3a, 0); + +static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0x02, + REG_TEMP_LSB); +static SENSOR_DEVICE_ATTR_2(temp2_min, S_IRUGO | S_IWUSR, show_temp, + store_temp, 0x33, 0); +static SENSOR_DEVICE_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp, + store_temp, 0x32, 0); +static SENSOR_DEVICE_ATTR_2(temp2_crit, S_IRUGO | S_IWUSR, show_temp, + store_temp, 0x3b, 0); + +static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0x03, + REG_TEMP_LSB); +static SENSOR_DEVICE_ATTR_2(temp3_min, S_IRUGO | S_IWUSR, show_temp, + store_temp, 0x35, 0); +static SENSOR_DEVICE_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp, + store_temp, 0x34, 0); +static SENSOR_DEVICE_ATTR_2(temp3_crit, S_IRUGO | S_IWUSR, show_temp, + store_temp, 0x3c, 0); + +static SENSOR_DEVICE_ATTR_2(temp4_input, S_IRUGO, show_temp, NULL, 0x04, 0); +static SENSOR_DEVICE_ATTR_2(temp4_min, S_IRUGO | S_IWUSR, show_temp, + store_temp, 0x37, 0); +static SENSOR_DEVICE_ATTR_2(temp4_max, S_IRUGO | S_IWUSR, show_temp, + store_temp, 0x36, 0); +static SENSOR_DEVICE_ATTR_2(temp4_crit, S_IRUGO | S_IWUSR, show_temp, + store_temp, 0x3d, 0); + +static SENSOR_DEVICE_ATTR_2(temp5_input, S_IRUGO, show_temp, NULL, 0x06, + REG_TEMP_PECI_LSB); +static SENSOR_DEVICE_ATTR_2(temp5_min, S_IRUGO | S_IWUSR, show_temp, + store_temp, 0x39, 0); +static SENSOR_DEVICE_ATTR_2(temp5_max, S_IRUGO | S_IWUSR, show_temp, + store_temp, 0x38, 0); +static SENSOR_DEVICE_ATTR_2(temp5_crit, S_IRUGO | S_IWUSR, show_temp, + store_temp, 0x3e, 0); + +static SENSOR_DEVICE_ATTR_2(temp6_input, S_IRUGO, show_temp, NULL, 0x07, + REG_TEMP_PECI_LSB); + +static SENSOR_DEVICE_ATTR_2(temp1_min_alarm, S_IRUGO, show_alarm, NULL, + 0x18, 0); +static SENSOR_DEVICE_ATTR_2(temp2_min_alarm, S_IRUGO, show_alarm, NULL, + 0x18, 1); +static SENSOR_DEVICE_ATTR_2(temp3_min_alarm, S_IRUGO, show_alarm, NULL, + 0x18, 2); +static SENSOR_DEVICE_ATTR_2(temp4_min_alarm, S_IRUGO, show_alarm, NULL, + 0x18, 3); +static SENSOR_DEVICE_ATTR_2(temp5_min_alarm, S_IRUGO, show_alarm, NULL, + 0x18, 4); + +static SENSOR_DEVICE_ATTR_2(temp1_max_alarm, S_IRUGO, show_alarm, NULL, + 0x19, 0); +static SENSOR_DEVICE_ATTR_2(temp2_max_alarm, S_IRUGO, show_alarm, NULL, + 0x19, 1); +static SENSOR_DEVICE_ATTR_2(temp3_max_alarm, S_IRUGO, show_alarm, NULL, + 0x19, 2); +static SENSOR_DEVICE_ATTR_2(temp4_max_alarm, S_IRUGO, show_alarm, NULL, + 0x19, 3); +static SENSOR_DEVICE_ATTR_2(temp5_max_alarm, S_IRUGO, show_alarm, NULL, + 0x19, 4); + +static SENSOR_DEVICE_ATTR_2(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, + 0x1b, 0); +static SENSOR_DEVICE_ATTR_2(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, + 0x1b, 1); +static SENSOR_DEVICE_ATTR_2(temp3_crit_alarm, S_IRUGO, show_alarm, NULL, + 0x1b, 2); +static SENSOR_DEVICE_ATTR_2(temp4_crit_alarm, S_IRUGO, show_alarm, NULL, + 0x1b, 3); +static SENSOR_DEVICE_ATTR_2(temp5_crit_alarm, S_IRUGO, show_alarm, NULL, + 0x1b, 4); + +static SENSOR_DEVICE_ATTR_2(temp1_fault, S_IRUGO, show_alarm, NULL, 0x17, 0); +static SENSOR_DEVICE_ATTR_2(temp2_fault, S_IRUGO, show_alarm, NULL, 0x17, 1); +static SENSOR_DEVICE_ATTR_2(temp3_fault, S_IRUGO, show_alarm, NULL, 0x17, 2); + +static SENSOR_DEVICE_ATTR_2(temp1_beep, S_IRUGO | S_IWUSR, show_beep, + store_beep, 0x5c, 0); +static SENSOR_DEVICE_ATTR_2(temp2_beep, S_IRUGO | S_IWUSR, show_beep, + store_beep, 0x5c, 1); +static SENSOR_DEVICE_ATTR_2(temp3_beep, S_IRUGO | S_IWUSR, show_beep, + store_beep, 0x5c, 2); +static SENSOR_DEVICE_ATTR_2(temp4_beep, S_IRUGO | S_IWUSR, show_beep, + store_beep, 0x5c, 3); +static SENSOR_DEVICE_ATTR_2(temp5_beep, S_IRUGO | S_IWUSR, show_beep, + store_beep, 0x5c, 4); +static SENSOR_DEVICE_ATTR_2(temp6_beep, S_IRUGO | S_IWUSR, show_beep, + store_beep, 0x5c, 5); + +static struct attribute *nct7802_temp_attrs[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_min.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp1_crit.dev_attr.attr, + &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_fault.dev_attr.attr, + &sensor_dev_attr_temp1_beep.dev_attr.attr, + + &sensor_dev_attr_temp2_input.dev_attr.attr, /* 9 */ + &sensor_dev_attr_temp2_min.dev_attr.attr, + &sensor_dev_attr_temp2_max.dev_attr.attr, + &sensor_dev_attr_temp2_crit.dev_attr.attr, + &sensor_dev_attr_temp2_min_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_fault.dev_attr.attr, + &sensor_dev_attr_temp2_beep.dev_attr.attr, + + &sensor_dev_attr_temp3_input.dev_attr.attr, /* 18 */ + &sensor_dev_attr_temp3_min.dev_attr.attr, + &sensor_dev_attr_temp3_max.dev_attr.attr, + &sensor_dev_attr_temp3_crit.dev_attr.attr, + &sensor_dev_attr_temp3_min_alarm.dev_attr.attr, + &sensor_dev_attr_temp3_max_alarm.dev_attr.attr, + &sensor_dev_attr_temp3_crit_alarm.dev_attr.attr, + &sensor_dev_attr_temp3_fault.dev_attr.attr, + &sensor_dev_attr_temp3_beep.dev_attr.attr, + + &sensor_dev_attr_temp4_input.dev_attr.attr, /* 27 */ + &sensor_dev_attr_temp4_min.dev_attr.attr, + &sensor_dev_attr_temp4_max.dev_attr.attr, + &sensor_dev_attr_temp4_crit.dev_attr.attr, + &sensor_dev_attr_temp4_min_alarm.dev_attr.attr, + &sensor_dev_attr_temp4_max_alarm.dev_attr.attr, + &sensor_dev_attr_temp4_crit_alarm.dev_attr.attr, + &sensor_dev_attr_temp4_beep.dev_attr.attr, + + &sensor_dev_attr_temp5_input.dev_attr.attr, /* 35 */ + &sensor_dev_attr_temp5_min.dev_attr.attr, + &sensor_dev_attr_temp5_max.dev_attr.attr, + &sensor_dev_attr_temp5_crit.dev_attr.attr, + &sensor_dev_attr_temp5_min_alarm.dev_attr.attr, + &sensor_dev_attr_temp5_max_alarm.dev_attr.attr, + &sensor_dev_attr_temp5_crit_alarm.dev_attr.attr, + &sensor_dev_attr_temp5_beep.dev_attr.attr, + + &sensor_dev_attr_temp6_input.dev_attr.attr, /* 43 */ + &sensor_dev_attr_temp6_beep.dev_attr.attr, + + NULL +}; + +static umode_t nct7802_temp_is_visible(struct kobject *kobj, + struct attribute *attr, int index) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct nct7802_data *data = dev_get_drvdata(dev); + unsigned int reg; + int err; + + err = regmap_read(data->regmap, REG_MODE, ®); + if (err < 0) + return 0; + + if (index < 9 && + (reg & 03) != 0x01 && (reg & 0x03) != 0x02) /* RD1 */ + return 0; + if (index >= 9 && index < 18 && + (reg & 0x0c) != 0x04 && (reg & 0x0c) != 0x08) /* RD2 */ + return 0; + if (index >= 18 && index < 27 && (reg & 0x30) != 0x10) /* RD3 */ + return 0; + if (index >= 27 && index < 35) /* local */ + return attr->mode; + + err = regmap_read(data->regmap, REG_PECI_ENABLE, ®); + if (err < 0) + return 0; + + if (index >= 35 && index < 43 && !(reg & 0x01)) /* PECI 0 */ + return 0; + + if (index >= 0x43 && (!(reg & 0x02))) /* PECI 1 */ + return 0; + + return attr->mode; +} + +static struct attribute_group nct7802_temp_group = { + .attrs = nct7802_temp_attrs, + .is_visible = nct7802_temp_is_visible, +}; + +static SENSOR_DEVICE_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0); +static SENSOR_DEVICE_ATTR_2(in0_min, S_IRUGO | S_IWUSR, show_in, store_in, + 0, 1); +static SENSOR_DEVICE_ATTR_2(in0_max, S_IRUGO | S_IWUSR, show_in, store_in, + 0, 2); +static SENSOR_DEVICE_ATTR_2(in0_alarm, S_IRUGO, show_alarm, NULL, 0x1e, 3); +static SENSOR_DEVICE_ATTR_2(in0_beep, S_IRUGO | S_IWUSR, show_beep, store_beep, + 0x5a, 3); + +static SENSOR_DEVICE_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 1, 0); + +static SENSOR_DEVICE_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 2, 0); +static SENSOR_DEVICE_ATTR_2(in2_min, S_IRUGO | S_IWUSR, show_in, store_in, + 2, 1); +static SENSOR_DEVICE_ATTR_2(in2_max, S_IRUGO | S_IWUSR, show_in, store_in, + 2, 2); +static SENSOR_DEVICE_ATTR_2(in2_alarm, S_IRUGO, show_alarm, NULL, 0x1e, 0); +static SENSOR_DEVICE_ATTR_2(in2_beep, S_IRUGO | S_IWUSR, show_beep, store_beep, + 0x5a, 0); + +static SENSOR_DEVICE_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 3, 0); +static SENSOR_DEVICE_ATTR_2(in3_min, S_IRUGO | S_IWUSR, show_in, store_in, + 3, 1); +static SENSOR_DEVICE_ATTR_2(in3_max, S_IRUGO | S_IWUSR, show_in, store_in, + 3, 2); +static SENSOR_DEVICE_ATTR_2(in3_alarm, S_IRUGO, show_alarm, NULL, 0x1e, 1); +static SENSOR_DEVICE_ATTR_2(in3_beep, S_IRUGO | S_IWUSR, show_beep, store_beep, + 0x5a, 1); + +static SENSOR_DEVICE_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 4, 0); +static SENSOR_DEVICE_ATTR_2(in4_min, S_IRUGO | S_IWUSR, show_in, store_in, + 4, 1); +static SENSOR_DEVICE_ATTR_2(in4_max, S_IRUGO | S_IWUSR, show_in, store_in, + 4, 2); +static SENSOR_DEVICE_ATTR_2(in4_alarm, S_IRUGO, show_alarm, NULL, 0x1e, 2); +static SENSOR_DEVICE_ATTR_2(in4_beep, S_IRUGO | S_IWUSR, show_beep, store_beep, + 0x5a, 2); + +static struct attribute *nct7802_in_attrs[] = { + &sensor_dev_attr_in0_input.dev_attr.attr, + &sensor_dev_attr_in0_min.dev_attr.attr, + &sensor_dev_attr_in0_max.dev_attr.attr, + &sensor_dev_attr_in0_alarm.dev_attr.attr, + &sensor_dev_attr_in0_beep.dev_attr.attr, + + &sensor_dev_attr_in1_input.dev_attr.attr, /* 5 */ + + &sensor_dev_attr_in2_input.dev_attr.attr, /* 6 */ + &sensor_dev_attr_in2_min.dev_attr.attr, + &sensor_dev_attr_in2_max.dev_attr.attr, + &sensor_dev_attr_in2_alarm.dev_attr.attr, + &sensor_dev_attr_in2_beep.dev_attr.attr, + + &sensor_dev_attr_in3_input.dev_attr.attr, /* 11 */ + &sensor_dev_attr_in3_min.dev_attr.attr, + &sensor_dev_attr_in3_max.dev_attr.attr, + &sensor_dev_attr_in3_alarm.dev_attr.attr, + &sensor_dev_attr_in3_beep.dev_attr.attr, + + &sensor_dev_attr_in4_input.dev_attr.attr, /* 17 */ + &sensor_dev_attr_in4_min.dev_attr.attr, + &sensor_dev_attr_in4_max.dev_attr.attr, + &sensor_dev_attr_in4_alarm.dev_attr.attr, + &sensor_dev_attr_in4_beep.dev_attr.attr, + + NULL, +}; + +static umode_t nct7802_in_is_visible(struct kobject *kobj, + struct attribute *attr, int index) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct nct7802_data *data = dev_get_drvdata(dev); + unsigned int reg; + int err; + + if (index < 6) /* VCC, VCORE */ + return attr->mode; + + err = regmap_read(data->regmap, REG_MODE, ®); + if (err < 0) + return 0; + + if (index >= 6 && index < 11 && (reg & 0x03) != 0x03) /* VSEN1 */ + return 0; + if (index >= 11 && index < 17 && (reg & 0x0c) != 0x0c) /* VSEN2 */ + return 0; + if (index >= 17 && (reg & 0x30) != 0x30) /* VSEN3 */ + return 0; + + return attr->mode; +} + +static struct attribute_group nct7802_in_group = { + .attrs = nct7802_in_attrs, + .is_visible = nct7802_in_is_visible, +}; + +static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0x10); +static SENSOR_DEVICE_ATTR_2(fan1_min, S_IRUGO | S_IWUSR, show_fan_min, + store_fan_min, 0x49, 0x4c); +static SENSOR_DEVICE_ATTR_2(fan1_alarm, S_IRUGO, show_alarm, NULL, 0x1a, 0); +static SENSOR_DEVICE_ATTR_2(fan1_beep, S_IRUGO | S_IWUSR, show_beep, store_beep, + 0x5b, 0); +static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 0x11); +static SENSOR_DEVICE_ATTR_2(fan2_min, S_IRUGO | S_IWUSR, show_fan_min, + store_fan_min, 0x4a, 0x4d); +static SENSOR_DEVICE_ATTR_2(fan2_alarm, S_IRUGO, show_alarm, NULL, 0x1a, 1); +static SENSOR_DEVICE_ATTR_2(fan2_beep, S_IRUGO | S_IWUSR, show_beep, store_beep, + 0x5b, 1); +static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 0x12); +static SENSOR_DEVICE_ATTR_2(fan3_min, S_IRUGO | S_IWUSR, show_fan_min, + store_fan_min, 0x4b, 0x4e); +static SENSOR_DEVICE_ATTR_2(fan3_alarm, S_IRUGO, show_alarm, NULL, 0x1a, 2); +static SENSOR_DEVICE_ATTR_2(fan3_beep, S_IRUGO | S_IWUSR, show_beep, store_beep, + 0x5b, 2); + +static struct attribute *nct7802_fan_attrs[] = { + &sensor_dev_attr_fan1_input.dev_attr.attr, + &sensor_dev_attr_fan1_min.dev_attr.attr, + &sensor_dev_attr_fan1_alarm.dev_attr.attr, + &sensor_dev_attr_fan1_beep.dev_attr.attr, + &sensor_dev_attr_fan2_input.dev_attr.attr, + &sensor_dev_attr_fan2_min.dev_attr.attr, + &sensor_dev_attr_fan2_alarm.dev_attr.attr, + &sensor_dev_attr_fan2_beep.dev_attr.attr, + &sensor_dev_attr_fan3_input.dev_attr.attr, + &sensor_dev_attr_fan3_min.dev_attr.attr, + &sensor_dev_attr_fan3_alarm.dev_attr.attr, + &sensor_dev_attr_fan3_beep.dev_attr.attr, + + NULL +}; + +static umode_t nct7802_fan_is_visible(struct kobject *kobj, + struct attribute *attr, int index) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct nct7802_data *data = dev_get_drvdata(dev); + int fan = index / 4; /* 4 attributes per fan */ + unsigned int reg; + int err; + + err = regmap_read(data->regmap, REG_FAN_ENABLE, ®); + if (err < 0 || !(reg & (1 << fan))) + return 0; + + return attr->mode; +} + +static struct attribute_group nct7802_fan_group = { + .attrs = nct7802_fan_attrs, + .is_visible = nct7802_fan_is_visible, +}; + +static const struct attribute_group *nct7802_groups[] = { + &nct7802_temp_group, + &nct7802_in_group, + &nct7802_fan_group, + NULL +}; + +static int nct7802_detect(struct i2c_client *client, + struct i2c_board_info *info) +{ + int reg; + + /* + * Chip identification registers are only available in bank 0, + * so only attempt chip detection if bank 0 is selected + */ + reg = i2c_smbus_read_byte_data(client, REG_BANK); + if (reg != 0x00) + return -ENODEV; + + reg = i2c_smbus_read_byte_data(client, REG_VENDOR_ID); + if (reg != 0x50) + return -ENODEV; + + reg = i2c_smbus_read_byte_data(client, REG_CHIP_ID); + if (reg != 0xc3) + return -ENODEV; + + reg = i2c_smbus_read_byte_data(client, REG_VERSION_ID); + if (reg < 0 || (reg & 0xf0) != 0x20) + return -ENODEV; + + /* Also validate lower bits of voltage and temperature registers */ + reg = i2c_smbus_read_byte_data(client, REG_TEMP_LSB); + if (reg < 0 || (reg & 0x1f)) + return -ENODEV; + + reg = i2c_smbus_read_byte_data(client, REG_TEMP_PECI_LSB); + if (reg < 0 || (reg & 0x3f)) + return -ENODEV; + + reg = i2c_smbus_read_byte_data(client, REG_VOLTAGE_LOW); + if (reg < 0 || (reg & 0x3f)) + return -ENODEV; + + strlcpy(info->type, "nct7802", I2C_NAME_SIZE); + return 0; +} + +static bool nct7802_regmap_is_volatile(struct device *dev, unsigned int reg) +{ + return reg != REG_BANK && reg <= 0x20; +} + +static struct regmap_config nct7802_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, + .volatile_reg = nct7802_regmap_is_volatile, +}; + +static int nct7802_init_chip(struct nct7802_data *data) +{ + int err; + + /* Enable ADC */ + err = regmap_update_bits(data->regmap, REG_START, 0x01, 0x01); + if (err) + return err; + + /* Enable local temperature sensor */ + err = regmap_update_bits(data->regmap, REG_MODE, 0x40, 0x40); + if (err) + return err; + + /* Enable Vcore and VCC voltage monitoring */ + return regmap_update_bits(data->regmap, REG_VMON_ENABLE, 0x03, 0x03); +} + +static int nct7802_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct nct7802_data *data; + struct device *hwmon_dev; + int ret; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (data == NULL) + return -ENOMEM; + + data->regmap = devm_regmap_init_i2c(client, &nct7802_regmap_config); + if (IS_ERR(data->regmap)) + return PTR_ERR(data->regmap); + + mutex_init(&data->access_lock); + + ret = nct7802_init_chip(data); + if (ret < 0) + return ret; + + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, + data, + nct7802_groups); + return PTR_ERR_OR_ZERO(hwmon_dev); +} + +static const unsigned short nct7802_address_list[] = { + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END +}; + +static const struct i2c_device_id nct7802_idtable[] = { + { "nct7802", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, nct7802_idtable); + +static struct i2c_driver nct7802_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = DRVNAME, + }, + .detect = nct7802_detect, + .probe = nct7802_probe, + .id_table = nct7802_idtable, + .address_list = nct7802_address_list, +}; + +module_i2c_driver(nct7802_driver); + +MODULE_AUTHOR("Guenter Roeck "); +MODULE_DESCRIPTION("NCT7802Y Hardware Monitoring Driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-59-g8ed1b From 799fc6021430243592ea8390aa4865713a12fd5f Mon Sep 17 00:00:00 2001 From: Michael Thalmeier Date: Tue, 18 Nov 2014 17:08:04 +0100 Subject: hwmon: (lm75) Add support for the NXP LM75B It is basically a faster lm75 with improved (11 bit) resolution. Signed-off-by: Michael Thalmeier Signed-off-by: Guenter Roeck --- Documentation/hwmon/lm75 | 5 +++++ drivers/hwmon/lm75.c | 6 ++++++ 2 files changed, 11 insertions(+) (limited to 'Documentation') diff --git a/Documentation/hwmon/lm75 b/Documentation/hwmon/lm75 index c6a5ff1b4641..67691a0aa41d 100644 --- a/Documentation/hwmon/lm75 +++ b/Documentation/hwmon/lm75 @@ -53,6 +53,11 @@ Supported chips: http://www.ti.com/product/tmp75 http://www.ti.com/product/tmp175 http://www.ti.com/product/tmp275 + * NXP LM75B + Prefix: 'lm75b' + Addresses scanned: none + Datasheet: Publicly available at the NXP website + http://www.nxp.com/documents/data_sheet/LM75B.pdf Author: Frodo Looijaard diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index d16dbb33a531..f58439b817b5 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -44,6 +44,7 @@ enum lm75_type { /* keep sorted in alphabetical order */ g751, lm75, lm75a, + lm75b, max6625, max6626, mcp980x, @@ -233,6 +234,10 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id) data->resolution = 9; data->sample_time = HZ / 2; break; + case lm75b: + data->resolution = 11; + data->sample_time = HZ / 4; + break; case max6625: data->resolution = 9; data->sample_time = HZ / 4; @@ -322,6 +327,7 @@ static const struct i2c_device_id lm75_ids[] = { { "g751", g751, }, { "lm75", lm75, }, { "lm75a", lm75a, }, + { "lm75b", lm75b, }, { "max6625", max6625, }, { "max6626", max6626, }, { "mcp980x", mcp980x, }, -- cgit v1.2.3-59-g8ed1b From b6e6dd8e9f6adf9765db2bb93e6a11f92811369a Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 17 Nov 2014 06:43:55 -0800 Subject: hwmon: (nct6775) Documentation updates Document support for NCT6102D/NCT6104D/NCT6106D and NCT6791D. Document that NCT5573D is compatible to NCT6775F with the same chip ID. Reviewed-by: Jean Delvare Signed-off-by: Guenter Roeck --- Documentation/hwmon/nct6775 | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/hwmon/nct6775 b/Documentation/hwmon/nct6775 index 4e9ef60e8c6c..345d11a2b526 100644 --- a/Documentation/hwmon/nct6775 +++ b/Documentation/hwmon/nct6775 @@ -8,11 +8,15 @@ Kernel driver NCT6775 ===================== Supported chips: + * Nuvoton NCT6102D/NCT6104D/NCT6106D + Prefix: 'nct6106' + Addresses scanned: ISA address retrieved from Super I/O registers + Datasheet: Available from the Nuvoton web site * Nuvoton NCT5572D/NCT6771F/NCT6772F/NCT6775F/W83677HG-I Prefix: 'nct6775' Addresses scanned: ISA address retrieved from Super I/O registers Datasheet: Available from Nuvoton upon request - * Nuvoton NCT5577D/NCT6776D/NCT6776F + * Nuvoton NCT5573D/NCT5577D/NCT6776D/NCT6776F Prefix: 'nct6776' Addresses scanned: ISA address retrieved from Super I/O registers Datasheet: Available from Nuvoton upon request @@ -20,6 +24,10 @@ Supported chips: Prefix: 'nct6779' Addresses scanned: ISA address retrieved from Super I/O registers Datasheet: Available from Nuvoton upon request + * Nuvoton NCT6791D + Prefix: 'nct6791' + Addresses scanned: ISA address retrieved from Super I/O registers + Datasheet: Available from Nuvoton upon request Authors: Guenter Roeck -- cgit v1.2.3-59-g8ed1b From 8aefb93f09bf4464f6da8ee071edcede9517d4bf Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 16 Nov 2014 09:50:04 -0800 Subject: hwmon: (nct6775) Add support for NCT6792D NCT6792D is similar to NCT6791D. Only beep control and temperature monitoring registers are different. Reviewed-by: Jean Delvare Signed-off-by: Guenter Roeck --- Documentation/hwmon/nct6775 | 4 ++++ drivers/hwmon/Kconfig | 4 ++-- drivers/hwmon/nct6775.c | 47 +++++++++++++++++++++++++++++++++++---------- 3 files changed, 43 insertions(+), 12 deletions(-) (limited to 'Documentation') diff --git a/Documentation/hwmon/nct6775 b/Documentation/hwmon/nct6775 index 345d11a2b526..f0dd3d2fec96 100644 --- a/Documentation/hwmon/nct6775 +++ b/Documentation/hwmon/nct6775 @@ -28,6 +28,10 @@ Supported chips: Prefix: 'nct6791' Addresses scanned: ISA address retrieved from Super I/O registers Datasheet: Available from Nuvoton upon request + * Nuvoton NCT6792D + Prefix: 'nct6792' + Addresses scanned: ISA address retrieved from Super I/O registers + Datasheet: Available from Nuvoton upon request Authors: Guenter Roeck diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index f893e0ff0081..fcca19b53bd2 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1117,8 +1117,8 @@ config SENSORS_NCT6775 help If you say yes here you get support for the hardware monitoring functionality of the Nuvoton NCT6106D, NCT6775F, NCT6776F, NCT6779D, - NCT6791D and compatible Super-I/O chips. This driver replaces the - w83627ehf driver for NCT6775F and NCT6776F. + NCT6791D, NCT6792D and compatible Super-I/O chips. This driver + replaces the w83627ehf driver for NCT6775F and NCT6776F. This driver can also be built as a module. If so, the module will be called nct6775. diff --git a/drivers/hwmon/nct6775.c b/drivers/hwmon/nct6775.c index 504cbddbdd90..c0dd307001c9 100644 --- a/drivers/hwmon/nct6775.c +++ b/drivers/hwmon/nct6775.c @@ -38,6 +38,7 @@ * nct6776f 9 5 3 6+3 0xc330 0xc1 0x5ca3 * nct6779d 15 5 5 2+6 0xc560 0xc1 0x5ca3 * nct6791d 15 6 6 2+6 0xc800 0xc1 0x5ca3 + * nct6792d 15 6 6 2+6 0xc910 0xc1 0x5ca3 * * #temp lists the number of monitored temperature sources (first value) plus * the number of directly connectable temperature sensors (second value). @@ -61,7 +62,7 @@ #define USE_ALTERNATE -enum kinds { nct6106, nct6775, nct6776, nct6779, nct6791 }; +enum kinds { nct6106, nct6775, nct6776, nct6779, nct6791, nct6792 }; /* used to set data->name = nct6775_device_names[data->sio_kind] */ static const char * const nct6775_device_names[] = { @@ -70,6 +71,7 @@ static const char * const nct6775_device_names[] = { "nct6776", "nct6779", "nct6791", + "nct6792", }; static unsigned short force_id; @@ -100,6 +102,7 @@ MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal"); #define SIO_NCT6776_ID 0xc330 #define SIO_NCT6779_ID 0xc560 #define SIO_NCT6791_ID 0xc800 +#define SIO_NCT6792_ID 0xc910 #define SIO_ID_MASK 0xFFF0 enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 }; @@ -529,6 +532,12 @@ static const s8 NCT6791_ALARM_BITS[] = { 4, 5, 13, -1, -1, -1, /* temp1..temp6 */ 12, 9 }; /* intrusion0, intrusion1 */ +/* NCT6792 specific data */ + +static const u16 NCT6792_REG_TEMP_MON[] = { + 0x73, 0x75, 0x77, 0x79, 0x7b, 0x7d }; +static const u16 NCT6792_REG_BEEP[NUM_REG_BEEP] = { + 0xb2, 0xb3, 0xb4, 0xb5, 0xbf }; /* NCT6102D/NCT6106D specific data */ @@ -1043,13 +1052,14 @@ static bool is_word_sized(struct nct6775_data *data, u16 reg) reg == 0x73 || reg == 0x75 || reg == 0x77; case nct6779: case nct6791: + case nct6792: return reg == 0x150 || reg == 0x153 || reg == 0x155 || ((reg & 0xfff0) == 0x4b0 && (reg & 0x000f) < 0x0b) || reg == 0x402 || reg == 0x63a || reg == 0x63c || reg == 0x63e || reg == 0x640 || reg == 0x642 || reg == 0x73 || reg == 0x75 || reg == 0x77 || reg == 0x79 || - reg == 0x7b; + reg == 0x7b || reg == 0x7d; } return false; } @@ -1391,6 +1401,7 @@ static void nct6775_update_pwm_limits(struct device *dev) case nct6106: case nct6779: case nct6791: + case nct6792: reg = nct6775_read_value(data, data->REG_CRITICAL_PWM_ENABLE[i]); if (reg & data->CRITICAL_PWM_ENABLE_MASK) @@ -2790,6 +2801,7 @@ store_auto_pwm(struct device *dev, struct device_attribute *attr, case nct6106: case nct6779: case nct6791: + case nct6792: nct6775_write_value(data, data->REG_CRITICAL_PWM[nr], val); reg = nct6775_read_value(data, @@ -3202,7 +3214,7 @@ nct6775_check_fan_inputs(struct nct6775_data *data) pwm4pin = false; pwm5pin = false; pwm6pin = false; - } else { /* NCT6779D or NCT6791D */ + } else { /* NCT6779D, NCT6791D, or NCT6792D */ regval = superio_inb(sioreg, 0x1c); fan3pin = !(regval & (1 << 5)); @@ -3215,7 +3227,7 @@ nct6775_check_fan_inputs(struct nct6775_data *data) fan4min = fan4pin; - if (data->kind == nct6791) { + if (data->kind == nct6791 || data->kind == nct6792) { regval = superio_inb(sioreg, 0x2d); fan6pin = (regval & (1 << 1)); pwm6pin = (regval & (1 << 0)); @@ -3588,6 +3600,7 @@ static int nct6775_probe(struct platform_device *pdev) break; case nct6791: + case nct6792: data->in_num = 15; data->pwm_num = 6; data->auto_pwm_num = 4; @@ -3650,12 +3663,20 @@ static int nct6775_probe(struct platform_device *pdev) data->REG_WEIGHT_TEMP[1] = NCT6791_REG_WEIGHT_TEMP_STEP_TOL; data->REG_WEIGHT_TEMP[2] = NCT6791_REG_WEIGHT_TEMP_BASE; data->REG_ALARM = NCT6791_REG_ALARM; - data->REG_BEEP = NCT6776_REG_BEEP; + if (data->kind == nct6791) + data->REG_BEEP = NCT6776_REG_BEEP; + else + data->REG_BEEP = NCT6792_REG_BEEP; reg_temp = NCT6779_REG_TEMP; - reg_temp_mon = NCT6779_REG_TEMP_MON; num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP); - num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON); + if (data->kind == nct6791) { + reg_temp_mon = NCT6779_REG_TEMP_MON; + num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON); + } else { + reg_temp_mon = NCT6792_REG_TEMP_MON; + num_reg_temp_mon = ARRAY_SIZE(NCT6792_REG_TEMP_MON); + } reg_temp_over = NCT6779_REG_TEMP_OVER; reg_temp_hyst = NCT6779_REG_TEMP_HYST; reg_temp_config = NCT6779_REG_TEMP_CONFIG; @@ -3854,6 +3875,7 @@ static int nct6775_probe(struct platform_device *pdev) case nct6106: case nct6779: case nct6791: + case nct6792: break; } @@ -3885,6 +3907,7 @@ static int nct6775_probe(struct platform_device *pdev) tmp |= 0x3e; break; case nct6791: + case nct6792: tmp |= 0x7e; break; } @@ -3972,7 +3995,7 @@ static int nct6775_resume(struct device *dev) mutex_lock(&data->update_lock); data->bank = 0xff; /* Force initial bank selection */ - if (data->kind == nct6791) { + if (data->kind == nct6791 || data->kind == nct6792) { err = superio_enter(data->sioreg); if (err) goto abort; @@ -4052,6 +4075,7 @@ static const char * const nct6775_sio_names[] __initconst = { "NCT6776D/F", "NCT6779D", "NCT6791D", + "NCT6792D", }; /* nct6775_find() looks for a '627 in the Super-I/O config space */ @@ -4086,6 +4110,9 @@ static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data) case SIO_NCT6791_ID: sio_data->kind = nct6791; break; + case SIO_NCT6792_ID: + sio_data->kind = nct6792; + break; default: if (val != 0xffff) pr_debug("unsupported chip ID: 0x%04x\n", val); @@ -4111,7 +4138,7 @@ static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data) superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01); } - if (sio_data->kind == nct6791) + if (sio_data->kind == nct6791 || sio_data->kind == nct6792) nct6791_enable_io_mapping(sioaddr); superio_exit(sioaddr); @@ -4221,7 +4248,7 @@ static void __exit sensors_nct6775_exit(void) } MODULE_AUTHOR("Guenter Roeck "); -MODULE_DESCRIPTION("NCT6106D/NCT6775F/NCT6776F/NCT6779D/NCT6791D driver"); +MODULE_DESCRIPTION("NCT6106D/NCT6775F/NCT6776F/NCT6779D/NCT6791D/NCT6792D driver"); MODULE_LICENSE("GPL"); module_init(sensors_nct6775_init); -- cgit v1.2.3-59-g8ed1b From 6eb48c818d352fcd6fcae7b878b01d2fd8c17eb6 Mon Sep 17 00:00:00 2001 From: Andreas Färber Date: Wed, 12 Nov 2014 14:51:16 +0100 Subject: Documentation: devicetree: Fix Xilinx VDMA specification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The specification requires xlnx,data-width, but example and driver use xlnx,datawidth. Change the specification to match the implementation. Reviewed-by: Michal Simek Fixes: eebeac03db93 ("dma: Add Xilinx Video DMA DT Binding Documentation") Signed-off-by: Andreas Färber Reviewed-by: Soren Brinkmann Signed-off-by: Michal Simek --- Documentation/devicetree/bindings/dma/xilinx/xilinx_vdma.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/dma/xilinx/xilinx_vdma.txt b/Documentation/devicetree/bindings/dma/xilinx/xilinx_vdma.txt index 1405ed071bb4..e4c4d47f8137 100644 --- a/Documentation/devicetree/bindings/dma/xilinx/xilinx_vdma.txt +++ b/Documentation/devicetree/bindings/dma/xilinx/xilinx_vdma.txt @@ -25,7 +25,7 @@ Required child node properties: - compatible: It should be either "xlnx,axi-vdma-mm2s-channel" or "xlnx,axi-vdma-s2mm-channel". - interrupts: Should contain per channel VDMA interrupts. -- xlnx,data-width: Should contain the stream data width, take values +- xlnx,datawidth: Should contain the stream data width, take values {32,64...1024}. Optional child node properties: -- cgit v1.2.3-59-g8ed1b From d86e3104e8066a5412ad3f9790592477a947a77e Mon Sep 17 00:00:00 2001 From: Peter Crosthwaite Date: Mon, 1 Dec 2014 10:25:48 +1000 Subject: doc: dt: vendor-prefixes: Add Digilent Inc Digilent is a board designer, making various Linux capabable FPGA and processor boards. Add to the vendor list. Acked-by: Soren Brinkmann Signed-off-by: Peter Crosthwaite Signed-off-by: Michal Simek --- 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 723999d73744..c6f934d69d48 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -40,6 +40,7 @@ dallas Maxim Integrated Products (formerly Dallas Semiconductor) davicom DAVICOM Semiconductor, Inc. denx Denx Software Engineering digi Digi International Inc. +digilent Diglent, Inc. dlg Dialog Semiconductor dlink D-Link Corporation dmo Data Modul AG -- cgit v1.2.3-59-g8ed1b From 1afed88381bb332040f2cb80ab1fa1d70506d593 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 27 Nov 2014 10:16:08 -0300 Subject: [media] DocBook media: rewrite the Colorspace chapter The colorspace chapter in the V4L2 Specification was always poorly written. This patch rewrites it, documenting the new Y'CbCr encoding and quantization defines and going into much more detail with respect to how colorspaces are used and what it all means. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/biblio.xml | 85 ++ Documentation/DocBook/media/v4l/pixfmt.xml | 1274 +++++++++++++++++++++------- 2 files changed, 1052 insertions(+), 307 deletions(-) (limited to 'Documentation') diff --git a/Documentation/DocBook/media/v4l/biblio.xml b/Documentation/DocBook/media/v4l/biblio.xml index d2eb79e41a01..7ff01a23c2fe 100644 --- a/Documentation/DocBook/media/v4l/biblio.xml +++ b/Documentation/DocBook/media/v4l/biblio.xml @@ -178,6 +178,75 @@ Signal - NTSC for Studio Applications" 1125-Line High-Definition Production" + + sRGB + + International Electrotechnical Commission +(http://www.iec.ch) + + IEC 61966-2-1 ed1.0 "Multimedia systems and equipment - Colour measurement +and management - Part 2-1: Colour management - Default RGB colour space - sRGB" + + + + sYCC + + International Electrotechnical Commission +(http://www.iec.ch) + + IEC 61966-2-1-am1 ed1.0 "Amendment 1 - Multimedia systems and equipment - Colour measurement +and management - Part 2-1: Colour management - Default RGB colour space - sRGB" + + + + xvYCC + + International Electrotechnical Commission +(http://www.iec.ch) + + IEC 61966-2-4 ed1.0 "Multimedia systems and equipment - Colour measurement +and management - Part 2-4: Colour management - Extended-gamut YCC colour space for video +applications - xvYCC" + + + + AdobeRGB + + Adobe Systems Incorporated (http://www.adobe.com) + + Adobe© RGB (1998) Color Image Encoding Version 2005-05 + + + + opRGB + + International Electrotechnical Commission +(http://www.iec.ch) + + IEC 61966-2-5 "Multimedia systems and equipment - Colour measurement +and management - Part 2-5: Colour management - Optional RGB colour space - opRGB" + + + + ITU BT.2020 + + International Telecommunication Union (http://www.itu.ch) + + ITU-R Recommendation BT.2020 (08/2012) "Parameter values for ultra-high +definition television systems for production and international programme exchange" + + + + + EBU Tech 3213 + + European Broadcast Union (http://www.ebu.ch) + + E.B.U. Standard for Chromaticity Tolerances for Studio Monitors" + + IEC 62106 @@ -266,4 +335,20 @@ in the frequency range from 87,5 to 108,0 MHz Version 1, Revision 2 + + poynton + + Charles Poynton + + Digital Video and HDTV, Algorithms and Interfaces + + + + colimg + + Erik Reinhard et al. + + Color Imaging: Fundamentals and Applications + + diff --git a/Documentation/DocBook/media/v4l/pixfmt.xml b/Documentation/DocBook/media/v4l/pixfmt.xml index df5b23d46552..ccf6053c1ae4 100644 --- a/Documentation/DocBook/media/v4l/pixfmt.xml +++ b/Documentation/DocBook/media/v4l/pixfmt.xml @@ -296,343 +296,1003 @@ in the 2-planar version or with each component in its own buffer in the
Colorspaces - [intro] + 'Color' is a very complex concept and depends on physics, chemistry and +biology. Just because you have three numbers that describe the 'red', 'green' +and 'blue' components of the color of a pixel does not mean that you can accurately +display that color. A colorspace defines what it actually means +to have an RGB value of e.g. (255, 0, 0). That is, which color should be +reproduced on the screen in a perfectly calibrated environment. - + In order to do that we first need to have a good definition of +color, i.e. some way to uniquely and unambiguously define a color so that someone +else can reproduce it. Human color vision is trichromatic since the human eye has +color receptors that are sensitive to three different wavelengths of light. Hence +the need to use three numbers to describe color. Be glad you are not a mantis shrimp +as those are sensitive to 12 different wavelengths, so instead of RGB we would be +using the ABCDEFGHIJKL colorspace... - - - - Gamma Correction - - [to do] - E'R = f(R) - E'G = f(G) - E'B = f(B) - - - - Construction of luminance and color-difference -signals - - [to do] - E'Y = -CoeffR E'R -+ CoeffG E'G -+ CoeffB E'B - (E'R - E'Y) = E'R -- CoeffR E'R -- CoeffG E'G -- CoeffB E'B - (E'B - E'Y) = E'B -- CoeffR E'R -- CoeffG E'G -- CoeffB E'B - - - - Re-normalized color-difference signals - - The color-difference signals are scaled back to unity -range [-0.5;+0.5]: - KB = 0.5 / (1 - CoeffB) - KR = 0.5 / (1 - CoeffR) - PB = -KB (E'B - E'Y) = - 0.5 (CoeffR / CoeffB) E'R -+ 0.5 (CoeffG / CoeffB) E'G -+ 0.5 E'B - PR = -KR (E'R - E'Y) = - 0.5 E'R -+ 0.5 (CoeffG / CoeffR) E'G -+ 0.5 (CoeffB / CoeffR) E'B - - - - Quantization - - [to do] - Y' = (Lum. Levels - 1) · E'Y + Lum. Offset - CB = (Chrom. Levels - 1) -· PB + Chrom. Offset - CR = (Chrom. Levels - 1) -· PR + Chrom. Offset - Rounding to the nearest integer and clamping to the range -[0;255] finally yields the digital color components Y'CbCr -stored in YUV images. - - - - - - - ITU-R Rec. BT.601 color conversion - - Forward Transformation - - -int ER, EG, EB; /* gamma corrected RGB input [0;255] */ -int Y1, Cb, Cr; /* output [0;255] */ - -double r, g, b; /* temporaries */ -double y1, pb, pr; - -int -clamp (double x) -{ - int r = x; /* round to nearest */ - - if (r < 0) return 0; - else if (r > 255) return 255; - else return r; -} - -r = ER / 255.0; -g = EG / 255.0; -b = EB / 255.0; - -y1 = 0.299 * r + 0.587 * g + 0.114 * b; -pb = -0.169 * r - 0.331 * g + 0.5 * b; -pr = 0.5 * r - 0.419 * g - 0.081 * b; - -Y1 = clamp (219 * y1 + 16); -Cb = clamp (224 * pb + 128); -Cr = clamp (224 * pr + 128); - -/* or shorter */ - -y1 = 0.299 * ER + 0.587 * EG + 0.114 * EB; - -Y1 = clamp ( (219 / 255.0) * y1 + 16); -Cb = clamp (((224 / 255.0) / (2 - 2 * 0.114)) * (EB - y1) + 128); -Cr = clamp (((224 / 255.0) / (2 - 2 * 0.299)) * (ER - y1) + 128); - - - Inverse Transformation - - -int Y1, Cb, Cr; /* gamma pre-corrected input [0;255] */ -int ER, EG, EB; /* output [0;255] */ - -double r, g, b; /* temporaries */ -double y1, pb, pr; - -int -clamp (double x) -{ - int r = x; /* round to nearest */ - - if (r < 0) return 0; - else if (r > 255) return 255; - else return r; -} - -y1 = (Y1 - 16) / 219.0; -pb = (Cb - 128) / 224.0; -pr = (Cr - 128) / 224.0; - -r = 1.0 * y1 + 0 * pb + 1.402 * pr; -g = 1.0 * y1 - 0.344 * pb - 0.714 * pr; -b = 1.0 * y1 + 1.772 * pb + 0 * pr; - -ER = clamp (r * 255); /* [ok? one should prob. limit y1,pb,pr] */ -EG = clamp (g * 255); -EB = clamp (b * 255); - - - - - enum v4l2_colorspace - - - - - - - - - - - - - - - + Color exists only in the eye and brain and is the result of how strongly +color receptors are stimulated. This is based on the Spectral +Power Distribution (SPD) which is a graph showing the intensity (radiant power) +of the light at wavelengths covering the visible spectrum as it enters the eye. +The science of colorimetry is about the relationship between the SPD and color as +perceived by the human brain. + + Since the human eye has only three color receptors it is perfectly +possible that different SPDs will result in the same stimulation of those receptors +and are perceived as the same color, even though the SPD of the light is +different. + + In the 1920s experiments were devised to determine the relationship +between SPDs and the perceived color and that resulted in the CIE 1931 standard +that defines spectral weighting functions that model the perception of color. +Specifically that standard defines functions that can take an SPD and calculate +the stimulus for each color receptor. After some further mathematical transforms +these stimuli are known as the CIE XYZ tristimulus values +and these X, Y and Z values describe a color as perceived by a human unambiguously. +These X, Y and Z values are all in the range [0…1]. + + The Y value in the CIE XYZ colorspace corresponds to luminance. Often +the CIE XYZ colorspace is transformed to the normalized CIE xyY colorspace: + + x = X / (X + Y + Z) + y = Y / (X + Y + Z) + + The x and y values are the chromaticity coordinates and can be used to +define a color without the luminance component Y. It is very confusing to +have such similar names for these colorspaces. Just be aware that if colors +are specified with lower case 'x' and 'y', then the CIE xyY colorspace is +used. Upper case 'X' and 'Y' refer to the CIE XYZ colorspace. Also, y has nothing +to do with luminance. Together x and y specify a color, and Y the luminance. +That is really all you need to remember from a practical point of view. At +the end of this section you will find reading resources that go into much more +detail if you are interested. + + + A monitor or TV will reproduce colors by emitting light at three +different wavelengths, the combination of which will stimulate the color receptors +in the eye and thus cause the perception of color. Historically these wavelengths +were defined by the red, green and blue phosphors used in the displays. These +color primaries are part of what defines a colorspace. + + Different display devices will have different primaries and some +primaries are more suitable for some display technologies than others. This has +resulted in a variety of colorspaces that are used for different display +technologies or uses. To define a colorspace you need to define the three +color primaries (these are typically defined as x, y chromaticity coordinates +from the CIE xyY colorspace) but also the white reference: that is the color obtained +when all three primaries are at maximum power. This determines the relative power +or energy of the primaries. This is usually chosen to be close to daylight which has +been defined as the CIE D65 Illuminant. + + To recapitulate: the CIE XYZ colorspace uniquely identifies colors. +Other colorspaces are defined by three chromaticity coordinates defined in the +CIE xyY colorspace. Based on those a 3x3 matrix can be constructed that +transforms CIE XYZ colors to colors in the new colorspace. + + + Both the CIE XYZ and the RGB colorspace that are derived from the +specific chromaticity primaries are linear colorspaces. But neither the eye, +nor display technology is linear. Doubling the values of all components in +the linear colorspace will not be perceived as twice the intensity of the color. +So each colorspace also defines a transfer function that takes a linear color +component value and transforms it to the non-linear component value, which is a +closer match to the non-linear performance of both the eye and displays. Linear +component values are denoted RGB, non-linear are denoted as R'G'B'. In general +colors used in graphics are all R'G'B', except in openGL which uses linear RGB. +Special care should be taken when dealing with openGL to provide linear RGB colors +or to use the built-in openGL support to apply the inverse transfer function. + + The final piece that defines a colorspace is a function that +transforms non-linear R'G'B' to non-linear Y'CbCr. This function is determined +by the so-called luma coefficients. There may be multiple possible Y'CbCr +encodings allowed for the same colorspace. Many encodings of color +prefer to use luma (Y') and chroma (CbCr) instead of R'G'B'. Since the human +eye is more sensitive to differences in luminance than in color this encoding +allows one to reduce the amount of color information compared to the luma +data. Note that the luma (Y') is unrelated to the Y in the CIE XYZ colorspace. +Also note that Y'CbCr is often called YCbCr or YUV even though these are +strictly speaking wrong. + + Sometimes people confuse Y'CbCr as being a colorspace. This is not +correct, it is just an encoding of an R'G'B' color into luma and chroma +values. The underlying colorspace that is associated with the R'G'B' color +is also associated with the Y'CbCr color. + + The final step is how the RGB, R'G'B' or Y'CbCr values are +quantized. The CIE XYZ colorspace where X, Y and Z are in the range +[0…1] describes all colors that humans can perceive, but the transform to +another colorspace will produce colors that are outside the [0…1] range. +Once clamped to the [0…1] range those colors can no longer be reproduced +in that colorspace. This clamping is what reduces the extent or gamut of the +colorspace. How the range of [0…1] is translated to integer values in the +range of [0…255] (or higher, depending on the color depth) is called the +quantization. This is not part of the colorspace +definition. In practice RGB or R'G'B' values are full range, i.e. they +use the full [0…255] range. Y'CbCr values on the other hand are limited +range with Y' using [16…235] and Cb and Cr using [16…240]. + + Unfortunately, in some cases limited range RGB is also used +where the components use the range [16…235]. And full range Y'CbCr also exists +using the [0…255] range. + + In order to correctly interpret a color you need to know the +quantization range, whether it is R'G'B' or Y'CbCr, the used Y'CbCr encoding +and the colorspace. +From that information you can calculate the corresponding CIE XYZ color +and map that again to whatever colorspace your display device uses. + + The colorspace definition itself consists of the three +chromaticity primaries, the white reference chromaticity, a transfer +function and the luma coefficients needed to transform R'G'B' to Y'CbCr. While +some colorspace standards correctly define all four, quite often the colorspace +standard only defines some, and you have to rely on other standards for +the missing pieces. The fact that colorspaces are often a mix of different +standards also led to very confusing naming conventions where the name of +a standard was used to name a colorspace when in fact that standard was +part of various other colorspaces as well. + + If you want to read more about colors and colorspaces, then the +following resources are useful: is a good practical +book for video engineers, has a much broader scope and +describes many more aspects of color (physics, chemistry, biology, etc.). +The http://www.brucelindbloom.com +website is an excellent resource, especially with respect to the mathematics behind +colorspace conversions. The wikipedia CIE 1931 colorspace article +is also very useful. + + +
+ Defining Colorspaces in V4L2 + In V4L2 colorspaces are defined by three values. The first is the colorspace +identifier (&v4l2-colorspace;) which defines the chromaticities, the transfer +function, the default Y'CbCr encoding and the default quantization method. The second +is the Y'CbCr encoding identifier (&v4l2-ycbcr-encoding;) to specify non-standard +Y'CbCr encodings and the third is the quantization identifier (&v4l2-quantization;) +to specify non-standard quantization methods. Most of the time only the colorspace +field of &v4l2-pix-format; or &v4l2-pix-format-mplane; needs to be filled in. Note +that the default R'G'B' quantization is always full range for all colorspaces, +so this won't be mentioned explicitly for each colorspace description. + +
+ V4L2 Colorspaces + + &cs-def; - Identifier - Value - Description - Chromaticities - The coordinates of the color primaries are -given in the CIE system (1931) - - White Point - Gamma Correction - Luminance E'Y - Quantization - - - Red - Green - Blue - Y' - Cb, Cr + Identifier + Details V4L2_COLORSPACE_SMPTE170M - 1 - NTSC/PAL according to , - - x = 0.630, y = 0.340 - x = 0.310, y = 0.595 - x = 0.155, y = 0.070 - x = 0.3127, y = 0.3290, - Illuminant D65 - E' = 4.5 I for I ≤0.018, -1.099 I0.45 - 0.099 for 0.018 < I - 0.299 E'R -+ 0.587 E'G -+ 0.114 E'B - 219 E'Y + 16 - 224 PB,R + 128 + See . - V4L2_COLORSPACE_SMPTE240M - 2 - 1125-Line (US) HDTV, see - x = 0.630, y = 0.340 - x = 0.310, y = 0.595 - x = 0.155, y = 0.070 - x = 0.3127, y = 0.3290, - Illuminant D65 - E' = 4 I for I ≤0.0228, -1.1115 I0.45 - 0.1115 for 0.0228 < I - 0.212 E'R -+ 0.701 E'G -+ 0.087 E'B - 219 E'Y + 16 - 224 PB,R + 128 + V4L2_COLORSPACE_REC709 + See . - V4L2_COLORSPACE_REC709 - 3 - HDTV and modern devices, see - x = 0.640, y = 0.330 - x = 0.300, y = 0.600 - x = 0.150, y = 0.060 - x = 0.3127, y = 0.3290, - Illuminant D65 - E' = 4.5 I for I ≤0.018, -1.099 I0.45 - 0.099 for 0.018 < I - 0.2125 E'R -+ 0.7154 E'G -+ 0.0721 E'B - 219 E'Y + 16 - 224 PB,R + 128 + V4L2_COLORSPACE_SRGB + See . - V4L2_COLORSPACE_BT878 - 4 - Broken Bt878 extents - The ubiquitous Bt878 video capture chip -quantizes E'Y to 238 levels, yielding a range -of Y' = 16 … 253, unlike Rec. 601 Y' = 16 … -235. This is not a typo in the Bt878 documentation, it has been -implemented in silicon. The chroma extents are unclear. - , - ? - ? - ? - ? - ? - 0.299 E'R -+ 0.587 E'G -+ 0.114 E'B - 237 E'Y + 16 - 224 PB,R + 128 (probably) + V4L2_COLORSPACE_ADOBERGB + See . + + + V4L2_COLORSPACE_BT2020 + See . + + + V4L2_COLORSPACE_SMPTE240M + See . V4L2_COLORSPACE_470_SYSTEM_M - 5 - M/NTSC - No identifier exists for M/PAL which uses -the chromaticities of M/NTSC, the remaining parameters are equal to B and -G/PAL. - according to , - x = 0.67, y = 0.33 - x = 0.21, y = 0.71 - x = 0.14, y = 0.08 - x = 0.310, y = 0.316, Illuminant C - ? - 0.299 E'R -+ 0.587 E'G -+ 0.114 E'B - 219 E'Y + 16 - 224 PB,R + 128 + See . V4L2_COLORSPACE_470_SYSTEM_BG - 6 - 625-line PAL and SECAM systems according to , - x = 0.64, y = 0.33 - x = 0.29, y = 0.60 - x = 0.15, y = 0.06 - x = 0.313, y = 0.329, -Illuminant D65 - ? - 0.299 E'R -+ 0.587 E'G -+ 0.114 E'B - 219 E'Y + 16 - 224 PB,R + 128 + See . V4L2_COLORSPACE_JPEG - 7 - JPEG Y'CbCr, see , - ? - ? - ? - ? - ? - 0.299 E'R -+ 0.587 E'G -+ 0.114 E'B - 256 E'Y + 16 - Note JFIF quantizes -Y'PBPR in range [0;+1] and -[-0.5;+0.5] to 257 levels, however Y'CbCr signals -are still clamped to [0;255]. - - 256 PB,R + 128 + See . + + + +
+ + + V4L2 Y'CbCr Encodings + + &cs-def; + + + Identifier + Details + + - V4L2_COLORSPACE_SRGB - 8 - [?] - x = 0.640, y = 0.330 - x = 0.300, y = 0.600 - x = 0.150, y = 0.060 - x = 0.3127, y = 0.3290, - Illuminant D65 - E' = 4.5 I for I ≤0.018, -1.099 I0.45 - 0.099 for 0.018 < I - n/a + V4L2_YCBCR_ENC_DEFAULT + Use the default Y'CbCr encoding as defined by the colorspace. + + + V4L2_YCBCR_ENC_601 + Use the BT.601 Y'CbCr encoding. + + + V4L2_YCBCR_ENC_709 + Use the Rec. 709 Y'CbCr encoding. + + + V4L2_YCBCR_ENC_XV601 + Use the extended gamut xvYCC BT.601 encoding. + + + V4L2_YCBCR_ENC_XV709 + Use the extended gamut xvYCC Rec. 709 encoding. + + + V4L2_YCBCR_ENC_SYCC + Use the extended gamut sYCC encoding. + + + V4L2_YCBCR_ENC_BT2020 + Use the default non-constant luminance BT.2020 Y'CbCr encoding. + + + V4L2_YCBCR_ENC_BT2020_CONST_LUM + Use the constant luminance BT.2020 Yc'CbcCrc encoding.
+ + + V4L2 Quantization Methods + + &cs-def; + + + Identifier + Details + + + + + V4L2_QUANTIZATION_DEFAULT + Use the default quantization encoding as defined by the colorspace. +This is always full range for R'G'B' and usually limited range for Y'CbCr. + + + V4L2_QUANTIZATION_FULL_RANGE + Use the full range quantization encoding. I.e. the range [0…1] +is mapped to [0…255] (with possible clipping to [1…254] to avoid the +0x00 and 0xff values). Cb and Cr are mapped from [-0.5…0.5] to [0…255] +(with possible clipping to [1…254] to avoid the 0x00 and 0xff values). + + + V4L2_QUANTIZATION_LIM_RANGE + Use the limited range quantization encoding. I.e. the range [0…1] +is mapped to [16…235]. Cb and Cr are mapped from [-0.5…0.5] to [16…240]. + + + + +
+
+ +
+ Detailed Colorspace Descriptions +
+ Colorspace SMPTE 170M (<constant>V4L2_COLORSPACE_SMPTE170M</constant>) + The standard defines the colorspace used by NTSC and PAL and by SDTV +in general. The default Y'CbCr encoding is V4L2_YCBCR_ENC_601. +The default Y'CbCr quantization is limited range. The chromaticities of the primary colors and +the white reference are: + + SMPTE 170M Chromaticities + + &cs-str; + + + Color + x + y + + + + + Red + 0.630 + 0.340 + + + Green + 0.310 + 0.595 + + + Blue + 0.155 + 0.070 + + + White Reference (D65) + 0.3127 + 0.3290 + + + +
+ The red, green and blue chromaticities are also often referred to +as the SMPTE C set, so this colorspace is sometimes called SMPTE C as well. + + + The transfer function defined for SMPTE 170M is the same as the +one defined in Rec. 709. Normally L is in the range [0…1], but for the extended +gamut xvYCC encoding values outside that range are allowed. + + L' = -1.099(-L)0.45 + 0.099 for L ≤ -0.018 + L' = 4.5L for -0.018 < L < 0.018 + L' = 1.099L0.45 - 0.099 for L ≥ 0.018 + + + + + + Inverse Transfer function: + + L = -((L' - 0.099) / -1.099)1/0.45 for L' ≤ -0.081 + L = L' / 4.5 for -0.081 < L' < 0.081 + L = ((L' + 0.099) / 1.099)1/0.45 for L' ≥ 0.081 + + + + + + The luminance (Y') and color difference (Cb and Cr) are obtained with +the following V4L2_YCBCR_ENC_601 encoding: + + Y' = 0.299R' + 0.587G' + 0.114B' + Cb = -0.169R' - 0.331G' + 0.5B' + Cr = 0.5R' - 0.419G' - 0.081B' + + + + Y' is clamped to the range [0…1] and Cb and Cr are +clamped to the range [-0.5…0.5]. This conversion to Y'CbCr is identical to the one +defined in the standard and this colorspace is sometimes called BT.601 as well, even +though BT.601 does not mention any color primaries. + The default quantization is limited range, but full range is possible although +rarely seen. + The V4L2_YCBCR_ENC_601 encoding as described above is the +default for this colorspace, but it can be overridden with V4L2_YCBCR_ENC_709, +in which case the Rec. 709 Y'CbCr encoding is used. + + + The xvYCC 601 encoding (V4L2_YCBCR_ENC_XV601, ) is similar +to the BT.601 encoding, but it allows for R', G' and B' values that are outside the range +[0…1]. The resulting Y', Cb and Cr values are scaled and offset: + + Y' = (219 / 255) * (0.299R' + 0.587G' + 0.114B') + (16 / 255) + Cb = (224 / 255) * (-0.169R' - 0.331G' + 0.5B') + Cr = (224 / 255) * (0.5R' - 0.419G' - 0.081B') + + + + Y' is clamped to the range [0…1] and Cb and Cr are clamped +to the range [-0.5…0.5]. The non-standard xvYCC 709 encoding can also be used by selecting +V4L2_YCBCR_ENC_XV709. The xvYCC encodings always use full range +quantization. +
+ +
+ Colorspace Rec. 709 (<constant>V4L2_COLORSPACE_REC709</constant>) + The standard defines the colorspace used by HDTV in general. The default +Y'CbCr encoding is V4L2_YCBCR_ENC_709. The default Y'CbCr quantization is +limited range. The chromaticities of the primary colors and the white reference are: + + Rec. 709 Chromaticities + + &cs-str; + + + Color + x + y + + + + + Red + 0.640 + 0.330 + + + Green + 0.300 + 0.600 + + + Blue + 0.150 + 0.060 + + + White Reference (D65) + 0.3127 + 0.3290 + + + +
+ The full name of this standard is Rec. ITU-R BT.709-5. + + + Transfer function. Normally L is in the range [0…1], but for the extended +gamut xvYCC encoding values outside that range are allowed. + + L' = -1.099(-L)0.45 + 0.099 for L ≤ -0.018 + L' = 4.5L for -0.018 < L < 0.018 + L' = 1.099L0.45 - 0.099 for L ≥ 0.018 + + + + + + Inverse Transfer function: + + L = -((L' - 0.099) / -1.099)1/0.45 for L' ≤ -0.081 + L = L' / 4.5 for -0.081 < L' < 0.081 + L = ((L' + 0.099) / 1.099)1/0.45 for L' ≥ 0.081 + + + + + + The luminance (Y') and color difference (Cb and Cr) are obtained with the following +V4L2_YCBCR_ENC_709 encoding: + + Y' = 0.2126R' + 0.7152G' + 0.0722B' + Cb = -0.1146R' - 0.3854G' + 0.5B' + Cr = 0.5R' - 0.4542G' - 0.0458B' + + + + Y' is clamped to the range [0…1] and Cb and Cr are +clamped to the range [-0.5…0.5]. + The default quantization is limited range, but full range is possible although +rarely seen. + The V4L2_YCBCR_ENC_709 encoding described above is the default +for this colorspace, but it can be overridden with V4L2_YCBCR_ENC_601, in which +case the BT.601 Y'CbCr encoding is used. + + + The xvYCC 709 encoding (V4L2_YCBCR_ENC_XV709, ) +is similar to the Rec. 709 encoding, but it allows for R', G' and B' values that are outside the range +[0…1]. The resulting Y', Cb and Cr values are scaled and offset: + + Y' = (219 / 255) * (0.2126R' + 0.7152G' + 0.0722B') + (16 / 255) + Cb = (224 / 255) * (-0.1146R' - 0.3854G' + 0.5B') + Cr = (224 / 255) * (0.5R' - 0.4542G' - 0.0458B') + + + + Y' is clamped to the range [0…1] and Cb and Cr are clamped +to the range [-0.5…0.5]. The non-standard xvYCC 601 encoding can also be used by +selecting V4L2_YCBCR_ENC_XV601. The xvYCC encodings always use full +range quantization. +
+ +
+ Colorspace sRGB (<constant>V4L2_COLORSPACE_SRGB</constant>) + The standard defines the colorspace used by most webcams and computer graphics. The +default Y'CbCr encoding is V4L2_YCBCR_ENC_SYCC. The default Y'CbCr quantization +is full range. The chromaticities of the primary colors and the white reference are: + + sRGB Chromaticities + + &cs-str; + + + Color + x + y + + + + + Red + 0.640 + 0.330 + + + Green + 0.300 + 0.600 + + + Blue + 0.150 + 0.060 + + + White Reference (D65) + 0.3127 + 0.3290 + + + +
+ These chromaticities are identical to the Rec. 709 colorspace. + + + Transfer function. Note that negative values for L are only used by the Y'CbCr conversion. + + L' = -1.055(-L)1/2.4 + 0.055 for L < -0.0031308 + L' = 12.92L for -0.0031308 ≤ L ≤ 0.0031308 + L' = 1.055L1/2.4 - 0.055 for 0.0031308 < L ≤ 1 + + + + Inverse Transfer function: + + L = -((-L' + 0.055) / 1.055)2.4 for L' < -0.04045 + L = L' / 12.92 for -0.04045 ≤ L' ≤ 0.04045 + L = ((L' + 0.055) / 1.055)2.4 for L' > 0.04045 + + + + + + The luminance (Y') and color difference (Cb and Cr) are obtained with the following +V4L2_YCBCR_ENC_SYCC encoding as defined by : + + Y' = 0.2990R' + 0.5870G' + 0.1140B' + Cb = -0.1687R' - 0.3313G' + 0.5B' + Cr = 0.5R' - 0.4187G' - 0.0813B' + + + + Y' is clamped to the range [0…1] and Cb and Cr are clamped +to the range [-0.5…0.5]. The V4L2_YCBCR_ENC_SYCC quantization is always +full range. Although this Y'CbCr encoding looks very similar to the V4L2_YCBCR_ENC_XV601 +encoding, it is not. The V4L2_YCBCR_ENC_XV601 scales and offsets the Y'CbCr +values before quantization, but this encoding does not do that. +
+ +
+ Colorspace Adobe RGB (<constant>V4L2_COLORSPACE_ADOBERGB</constant>) + The standard defines the colorspace used by computer graphics +that use the AdobeRGB colorspace. This is also known as the standard. +The default Y'CbCr encoding is V4L2_YCBCR_ENC_601. The default Y'CbCr +quantization is limited range. The chromaticities of the primary colors and the white reference +are: + + Adobe RGB Chromaticities + + &cs-str; + + + Color + x + y + + + + + Red + 0.6400 + 0.3300 + + + Green + 0.2100 + 0.7100 + + + Blue + 0.1500 + 0.0600 + + + White Reference (D65) + 0.3127 + 0.3290 + + + +
+ + + Transfer function: + + L' = L1/2.19921875 + + + + Inverse Transfer function: + + L = L'2.19921875 + + + + + + The luminance (Y') and color difference (Cb and Cr) are obtained with the +following V4L2_YCBCR_ENC_601 encoding: + + Y' = 0.299R' + 0.587G' + 0.114B' + Cb = -0.169R' - 0.331G' + 0.5B' + Cr = 0.5R' - 0.419G' - 0.081B' + + + + Y' is clamped to the range [0…1] and Cb and Cr are +clamped to the range [-0.5…0.5]. This transform is identical to one defined in +SMPTE 170M/BT.601. The Y'CbCr quantization is limited range. +
+ +
+ Colorspace BT.2020 (<constant>V4L2_COLORSPACE_BT2020</constant>) + The standard defines the colorspace used by Ultra-high definition +television (UHDTV). The default Y'CbCr encoding is V4L2_YCBCR_ENC_BT2020. +The default Y'CbCr quantization is limited range. The chromaticities of the primary colors and +the white reference are: + + BT.2020 Chromaticities + + &cs-str; + + + Color + x + y + + + + + Red + 0.708 + 0.292 + + + Green + 0.170 + 0.797 + + + Blue + 0.131 + 0.046 + + + White Reference (D65) + 0.3127 + 0.3290 + + + +
+ + + Transfer function (same as Rec. 709): + + L' = 4.5L for 0 ≤ L < 0.018 + L' = 1.099L0.45 - 0.099 for 0.018 ≤ L ≤ 1 + + + + Inverse Transfer function: + + L = L' / 4.5 for L' < 0.081 + L = ((L' + 0.099) / 1.099)1/0.45 for L' ≥ 0.081 + + + + + + The luminance (Y') and color difference (Cb and Cr) are obtained with the +following V4L2_YCBCR_ENC_BT2020 encoding: + + Y' = 0.2627R' + 0.6789G' + 0.0593B' + Cb = -0.1396R' - 0.3604G' + 0.5B' + Cr = 0.5R' - 0.4598G' - 0.0402B' + + + + Y' is clamped to the range [0…1] and Cb and Cr are +clamped to the range [-0.5…0.5]. The Y'CbCr quantization is limited range. + There is also an alternate constant luminance R'G'B' to Yc'CbcCrc +(V4L2_YCBCR_ENC_BT2020_CONST_LUM) encoding: + + + Luma: + + Yc' = (0.2627R + 0.6789G + 0.0593B)' + + + + + + B' - Yc' ≤ 0: + + Cbc = (B' - Y') / 1.9404 + + + + + + B' - Yc' > 0: + + Cbc = (B' - Y') / 1.5816 + + + + + + R' - Yc' ≤ 0: + + Crc = (R' - Y') / 1.7184 + + + + + + R' - Yc' > 0: + + Crc = (R' - Y') / 0.9936 + + + + Yc' is clamped to the range [0…1] and Cbc and Crc are +clamped to the range [-0.5…0.5]. The Yc'CbcCrc quantization is limited range. +
+ +
+ Colorspace SMPTE 240M (<constant>V4L2_COLORSPACE_SMPTE240M</constant>) + The standard was an interim standard used during the early days of HDTV (1988-1998). +It has been superseded by Rec. 709. The default Y'CbCr encoding is V4L2_YCBCR_ENC_SMPTE240M. +The default Y'CbCr quantization is limited range. The chromaticities of the primary colors and the +white reference are: + + SMPTE 240M Chromaticities + + &cs-str; + + + Color + x + y + + + + + Red + 0.630 + 0.340 + + + Green + 0.310 + 0.595 + + + Blue + 0.155 + 0.070 + + + White Reference (D65) + 0.3127 + 0.3290 + + + +
+ These chromaticities are identical to the SMPTE 170M colorspace. + + + Transfer function: + + L' = 4L for 0 ≤ L < 0.0228 + L' = 1.1115L0.45 - 0.1115 for 0.0228 ≤ L ≤ 1 + + + + Inverse Transfer function: + + L = L' / 4 for 0 ≤ L' < 0.0913 + L = ((L' + 0.1115) / 1.1115)1/0.45 for L' ≥ 0.0913 + + + + + + The luminance (Y') and color difference (Cb and Cr) are obtained with the +following V4L2_YCBCR_ENC_SMPTE240M encoding: + + Y' = 0.2122R' + 0.7013G' + 0.0865B' + Cb = -0.1161R' - 0.3839G' + 0.5B' + Cr = 0.5R' - 0.4451G' - 0.0549B' + + + + Yc' is clamped to the range [0…1] and Cbc and Crc are +clamped to the range [-0.5…0.5]. The Y'CbCr quantization is limited range. +
+ +
+ Colorspace NTSC 1953 (<constant>V4L2_COLORSPACE_470_SYSTEM_M</constant>) + This standard defines the colorspace used by NTSC in 1953. In practice this +colorspace is obsolete and SMPTE 170M should be used instead. The default Y'CbCr encoding +is V4L2_YCBCR_ENC_601. The default Y'CbCr quantization is limited range. +The chromaticities of the primary colors and the white reference are: + + NTSC 1953 Chromaticities + + &cs-str; + + + Color + x + y + + + + + Red + 0.67 + 0.33 + + + Green + 0.21 + 0.71 + + + Blue + 0.14 + 0.08 + + + White Reference (C) + 0.310 + 0.316 + + + +
+ Note that this colorspace uses Illuminant C instead of D65 as the +white reference. To correctly convert an image in this colorspace to another +that uses D65 you need to apply a chromatic adaptation algorithm such as the +Bradford method. + + + The transfer function was never properly defined for NTSC 1953. The +Rec. 709 transfer function is recommended in the literature: + + L' = 4.5L for 0 ≤ L < 0.018 + L' = 1.099L0.45 - 0.099 for 0.018 ≤ L ≤ 1 + + + + Inverse Transfer function: + + L = L' / 4.5 for L' < 0.081 + L = ((L' + 0.099) / 1.099)1/0.45 for L' ≥ 0.081 + + + + + + The luminance (Y') and color difference (Cb and Cr) are obtained with the +following V4L2_YCBCR_ENC_601 encoding: + + Y' = 0.299R' + 0.587G' + 0.114B' + Cb = -0.169R' - 0.331G' + 0.5B' + Cr = 0.5R' - 0.419G' - 0.081B' + + + + Y' is clamped to the range [0…1] and Cb and Cr are +clamped to the range [-0.5…0.5]. The Y'CbCr quantization is limited range. +This transform is identical to one defined in SMPTE 170M/BT.601. +
+ +
+ Colorspace EBU Tech. 3213 (<constant>V4L2_COLORSPACE_470_SYSTEM_BG</constant>) + The standard defines the colorspace used by PAL/SECAM in 1975. In practice this +colorspace is obsolete and SMPTE 170M should be used instead. The default Y'CbCr encoding +is V4L2_YCBCR_ENC_601. The default Y'CbCr quantization is limited range. +The chromaticities of the primary colors and the white reference are: + + EBU Tech. 3213 Chromaticities + + &cs-str; + + + Color + x + y + + + + + Red + 0.64 + 0.33 + + + Green + 0.29 + 0.60 + + + Blue + 0.15 + 0.06 + + + White Reference (D65) + 0.3127 + 0.3290 + + + +
+ + + The transfer function was never properly defined for this colorspace. +The Rec. 709 transfer function is recommended in the literature: + + L' = 4.5L for 0 ≤ L < 0.018 + L' = 1.099L0.45 - 0.099 for 0.018 ≤ L ≤ 1 + + + + Inverse Transfer function: + + L = L' / 4.5 for L' < 0.081 + L = ((L' + 0.099) / 1.099)1/0.45 for L' ≥ 0.081 + + + + + + The luminance (Y') and color difference (Cb and Cr) are obtained with the +following V4L2_YCBCR_ENC_601 encoding: + + Y' = 0.299R' + 0.587G' + 0.114B' + Cb = -0.169R' - 0.331G' + 0.5B' + Cr = 0.5R' - 0.419G' - 0.081B' + + + + Y' is clamped to the range [0…1] and Cb and Cr are +clamped to the range [-0.5…0.5]. The Y'CbCr quantization is limited range. +This transform is identical to one defined in SMPTE 170M/BT.601. +
+ +
+ Colorspace JPEG (<constant>V4L2_COLORSPACE_JPEG</constant>) + This colorspace defines the colorspace used by most (Motion-)JPEG formats. The chromaticities +of the primary colors and the white reference are identical to sRGB. The Y'CbCr encoding is +V4L2_YCBCR_ENC_601 with full range quantization where +Y' is scaled to [0…255] and Cb/Cr are scaled to [-128…128] and +then clipped to [-128…127]. + Note that the JPEG standard does not actually store colorspace information. +So if something other than sRGB is used, then the driver will have to set that information +explicitly. Effectively V4L2_COLORSPACE_JPEG can be considered to be +an abbreviation for V4L2_COLORSPACE_SRGB, V4L2_YCBCR_ENC_601 +and V4L2_QUANTIZATION_FULL_RANGE. +
+
-- cgit v1.2.3-59-g8ed1b From 8f73110f6bac043026bc923b0a66abe24dd48058 Mon Sep 17 00:00:00 2001 From: Romain Perier Date: Tue, 25 Nov 2014 12:28:25 +0000 Subject: of: Rename "poweroff-source" property to "system-power-controller" It reverts commit a4b4e0461ec5 ("of: Add standard property for poweroff capability"). As discussed on the mailing list, it makes more sense to rename back to the old established property name, without the vendor prefix. Problem being that the word "source" usually tends to be used for inputs and that is out of control of the OS. The poweroff capability is an output which simply turns the system-power off. Also, this property might be used by drivers which power-off the system and power back on subsequent RTC alarms. This seems to suggest to remove "poweroff" from the property name and to choose "system-power-controller" as the more generic name. This patchs adds the required renaming changes and defines an helper function which checks if this property is set. Signed-off-by: Romain Perier Acked-by: Grant Likely Acked-by: Johan Hovold Signed-off-by: Mark Brown --- .../devicetree/bindings/power/power-controller.txt | 18 ++++++++++++++++++ Documentation/devicetree/bindings/power/poweroff.txt | 18 ------------------ .../bindings/regulator/act8865-regulator.txt | 4 ++-- drivers/regulator/act8865-regulator.c | 2 +- include/linux/of.h | 6 +++--- 5 files changed, 24 insertions(+), 24 deletions(-) create mode 100644 Documentation/devicetree/bindings/power/power-controller.txt delete mode 100644 Documentation/devicetree/bindings/power/poweroff.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/power/power-controller.txt b/Documentation/devicetree/bindings/power/power-controller.txt new file mode 100644 index 000000000000..845868bf3273 --- /dev/null +++ b/Documentation/devicetree/bindings/power/power-controller.txt @@ -0,0 +1,18 @@ +* Generic Poweroff capability + +Power-management integrated circuits or miscellaneous harware components are +sometimes able to control the system power. The device driver associated to these +components might needs to define poweroff capability, which tells to the kernel +how to switch off the system. The corresponding driver must have the standard +property "poweroff-source" in its device node. This property marks the device as +able to shutdown the system. In order to test if this property is found +programmatically, use the helper function "of_system_has_poweroff_source" from +of.h . + +Example: + +act8846: act8846@5 { + compatible = "active-semi,act8846"; + status = "okay"; + poweroff-source; +} diff --git a/Documentation/devicetree/bindings/power/poweroff.txt b/Documentation/devicetree/bindings/power/poweroff.txt deleted file mode 100644 index 845868bf3273..000000000000 --- a/Documentation/devicetree/bindings/power/poweroff.txt +++ /dev/null @@ -1,18 +0,0 @@ -* Generic Poweroff capability - -Power-management integrated circuits or miscellaneous harware components are -sometimes able to control the system power. The device driver associated to these -components might needs to define poweroff capability, which tells to the kernel -how to switch off the system. The corresponding driver must have the standard -property "poweroff-source" in its device node. This property marks the device as -able to shutdown the system. In order to test if this property is found -programmatically, use the helper function "of_system_has_poweroff_source" from -of.h . - -Example: - -act8846: act8846@5 { - compatible = "active-semi,act8846"; - status = "okay"; - poweroff-source; -} diff --git a/Documentation/devicetree/bindings/regulator/act8865-regulator.txt b/Documentation/devicetree/bindings/regulator/act8865-regulator.txt index 01a5b0766e53..dad6358074ac 100644 --- a/Documentation/devicetree/bindings/regulator/act8865-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/act8865-regulator.txt @@ -6,8 +6,8 @@ Required properties: - reg: I2C slave address Optional properties: -- poweroff-source: Telling whether or not this pmic is controlling - the system power. See Documentation/devicetree/bindings/power/poweroff.txt . +- system-power-controller: Telling whether or not this pmic is controlling + the system power. See Documentation/devicetree/bindings/power/power-controller.txt . Any standard regulator properties can be used to configure the single regulator. diff --git a/drivers/regulator/act8865-regulator.c b/drivers/regulator/act8865-regulator.c index 76301ed0f8d4..9eec453b745d 100644 --- a/drivers/regulator/act8865-regulator.c +++ b/drivers/regulator/act8865-regulator.c @@ -365,7 +365,7 @@ static int act8865_pmic_probe(struct i2c_client *client, return ret; } - if (of_system_has_poweroff_source(dev->of_node)) { + if (of_device_is_system_power_controller(dev->of_node)) { if (!pm_power_off) { act8865_i2c_client = client; act8865->off_reg = off_reg; diff --git a/include/linux/of.h b/include/linux/of.h index 27b3ba1e9e59..257677256612 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -867,14 +867,14 @@ static inline int of_changeset_update_property(struct of_changeset *ocs, extern int of_resolve_phandles(struct device_node *tree); /** - * of_system_has_poweroff_source - Tells if poweroff-source is found for device_node + * of_device_is_system_power_controller - Tells if system-power-controller is found for device_node * @np: Pointer to the given device_node * * return true if present false otherwise */ -static inline bool of_system_has_poweroff_source(const struct device_node *np) +static inline bool of_device_is_system_power_controller(const struct device_node *np) { - return of_property_read_bool(np, "poweroff-source"); + return of_property_read_bool(np, "system-power-controller"); } #endif /* _LINUX_OF_H */ -- cgit v1.2.3-59-g8ed1b From 0ce5b30763fb2a0e8cdc24311bb833003d35dc05 Mon Sep 17 00:00:00 2001 From: Romain Perier Date: Tue, 25 Nov 2014 12:28:26 +0000 Subject: dt-bindings: Update documentation for "system-power-controller" and fix misspellings Signed-off-by: Romain Perier Acked-by: Johan Hovold Acked-by: Grant Likely Signed-off-by: Mark Brown --- .../devicetree/bindings/power/power-controller.txt | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/power/power-controller.txt b/Documentation/devicetree/bindings/power/power-controller.txt index 845868bf3273..4f7a3bc9c407 100644 --- a/Documentation/devicetree/bindings/power/power-controller.txt +++ b/Documentation/devicetree/bindings/power/power-controller.txt @@ -1,18 +1,18 @@ -* Generic Poweroff capability +* Generic system power control capability -Power-management integrated circuits or miscellaneous harware components are -sometimes able to control the system power. The device driver associated to these -components might needs to define poweroff capability, which tells to the kernel -how to switch off the system. The corresponding driver must have the standard -property "poweroff-source" in its device node. This property marks the device as -able to shutdown the system. In order to test if this property is found -programmatically, use the helper function "of_system_has_poweroff_source" from -of.h . +Power-management integrated circuits or miscellaneous hardware components are +sometimes able to control the system power. The device driver associated with these +components might need to define this capability, which tells the kernel that +it can be used to switch off the system. The corresponding device must have the +standard property "system-power-controller" in its device node. This property +marks the device as able to control the system power. In order to test if this +property is found programmatically, use the helper function +"of_device_is_system_power_controller" from of.h . Example: act8846: act8846@5 { compatible = "active-semi,act8846"; status = "okay"; - poweroff-source; + system-power-controller; } -- cgit v1.2.3-59-g8ed1b From 344ebae602e60e34b406fc47020a573a5060bafe Mon Sep 17 00:00:00 2001 From: Mark Yao Date: Fri, 5 Sep 2014 14:50:43 +0800 Subject: dt-bindings: video: Add for rockchip display subsytem This add a display subsystem comprise the all display interface nodes. Signed-off-by: Mark Yao --- .../devicetree/bindings/video/rockchip-drm.txt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 Documentation/devicetree/bindings/video/rockchip-drm.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/video/rockchip-drm.txt b/Documentation/devicetree/bindings/video/rockchip-drm.txt new file mode 100644 index 000000000000..7fff582495a2 --- /dev/null +++ b/Documentation/devicetree/bindings/video/rockchip-drm.txt @@ -0,0 +1,19 @@ +Rockchip DRM master device +================================ + +The Rockchip DRM master device is a virtual device needed to list all +vop devices or other display interface nodes that comprise the +graphics subsystem. + +Required properties: +- compatible: Should be "rockchip,display-subsystem" +- ports: Should contain a list of phandles pointing to display interface port + of vop devices. vop definitions as defined in + Documentation/devicetree/bindings/video/rockchip-vop.txt + +example: + +display-subsystem { + compatible = "rockchip,display-subsystem"; + ports = <&vopl_out>, <&vopb_out>; +}; -- cgit v1.2.3-59-g8ed1b From 5ac4837b12f533de5d9f8f66b45494c58e805536 Mon Sep 17 00:00:00 2001 From: Mark Yao Date: Fri, 29 Aug 2014 12:38:41 +0800 Subject: dt-bindings: video: Add documentation for rockchip vop This adds binding documentation for Rockchip SoC VOP driver. Signed-off-by: Mark Yao --- .../devicetree/bindings/video/rockchip-vop.txt | 58 ++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 Documentation/devicetree/bindings/video/rockchip-vop.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/video/rockchip-vop.txt b/Documentation/devicetree/bindings/video/rockchip-vop.txt new file mode 100644 index 000000000000..d15351f2313d --- /dev/null +++ b/Documentation/devicetree/bindings/video/rockchip-vop.txt @@ -0,0 +1,58 @@ +device-tree bindings for rockchip soc display controller (vop) + +VOP (Visual Output Processor) is the Display Controller for the Rockchip +series of SoCs which transfers the image data from a video memory +buffer to an external LCD interface. + +Required properties: +- compatible: value should be one of the following + "rockchip,rk3288-vop"; + +- interrupts: should contain a list of all VOP IP block interrupts in the + order: VSYNC, LCD_SYSTEM. The interrupt specifier + format depends on the interrupt controller used. + +- clocks: must include clock specifiers corresponding to entries in the + clock-names property. + +- clock-names: Must contain + aclk_vop: for ddr buffer transfer. + hclk_vop: for ahb bus to R/W the phy regs. + dclk_vop: pixel clock. + +- resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names: Must include the following entries: + - axi + - ahb + - dclk + +- iommus: required a iommu node + +- port: A port node with endpoint definitions as defined in + Documentation/devicetree/bindings/media/video-interfaces.txt. + +Example: +SoC specific DT entry: + vopb: vopb@ff930000 { + compatible = "rockchip,rk3288-vop"; + reg = <0xff930000 0x19c>; + interrupts = ; + clocks = <&cru ACLK_VOP0>, <&cru DCLK_VOP0>, <&cru HCLK_VOP0>; + clock-names = "aclk_vop", "dclk_vop", "hclk_vop"; + resets = <&cru SRST_LCDC1_AXI>, <&cru SRST_LCDC1_AHB>, <&cru SRST_LCDC1_DCLK>; + reset-names = "axi", "ahb", "dclk"; + iommus = <&vopb_mmu>; + vopb_out: port { + #address-cells = <1>; + #size-cells = <0>; + vopb_out_edp: endpoint@0 { + reg = <0>; + remote-endpoint=<&edp_in_vopb>; + }; + vopb_out_hdmi: endpoint@1 { + reg = <1>; + remote-endpoint=<&hdmi_in_vopb>; + }; + }; + }; -- cgit v1.2.3-59-g8ed1b From 162a8dfe73df95e59265e350b2f247b8b35490d1 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 22 Apr 2014 08:48:57 -0700 Subject: hwmon: (lm95245) Add support for LM95235 LM95235 is register compatible to LM95245. Also update link to LM95245 data sheet, and drop the link to the datasheet from the driver source to simplify code maintenance. Reviewed-by: Jean Delvare Signed-off-by: Guenter Roeck --- Documentation/hwmon/lm95245 | 14 +++++++++----- drivers/hwmon/Kconfig | 5 +++-- drivers/hwmon/lm95245.c | 41 +++++++++++++++++++++++++++-------------- 3 files changed, 39 insertions(+), 21 deletions(-) (limited to 'Documentation') diff --git a/Documentation/hwmon/lm95245 b/Documentation/hwmon/lm95245 index 77eaf2812d25..d755901f58c4 100644 --- a/Documentation/hwmon/lm95245 +++ b/Documentation/hwmon/lm95245 @@ -2,10 +2,14 @@ Kernel driver lm95245 ================== Supported chips: - * National Semiconductor LM95245 + * TI LM95235 + Addresses scanned: I2C 0x18, 0x29, 0x4c + Datasheet: Publicly available at the TI website + http://www.ti.com/lit/ds/symlink/lm95235.pdf + * TI / National Semiconductor LM95245 Addresses scanned: I2C 0x18, 0x19, 0x29, 0x4c, 0x4d - Datasheet: Publicly available at the National Semiconductor website - http://www.national.com/mpf/LM/LM95245.html + Datasheet: Publicly available at the TI website + http://www.ti.com/lit/ds/symlink/lm95245.pdf Author: Alexander Stein @@ -13,10 +17,10 @@ Author: Alexander Stein Description ----------- -The LM95245 is an 11-bit digital temperature sensor with a 2-wire System +LM95235 and LM95245 are 11-bit digital temperature sensors with a 2-wire System Management Bus (SMBus) interface and TruTherm technology that can monitor the temperature of a remote diode as well as its own temperature. -The LM95245 can be used to very accurately monitor the temperature of +The chips can be used to very accurately monitor the temperature of external devices such as microprocessors. All temperature values are given in millidegrees Celsius. Local temperature diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index fcca19b53bd2..085f5a853618 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1048,10 +1048,11 @@ config SENSORS_LM95241 will be called lm95241. config SENSORS_LM95245 - tristate "National Semiconductor LM95245 sensor chip" + tristate "National Semiconductor LM95245 and compatibles" depends on I2C help - If you say yes here you get support for LM95245 sensor chip. + If you say yes here you get support for LM95235 and LM95245 + temperature sensor chips. This driver can also be built as a module. If so, the module will be called lm95245. diff --git a/drivers/hwmon/lm95245.c b/drivers/hwmon/lm95245.c index 0ae0dfdafdff..e7aef4561c83 100644 --- a/drivers/hwmon/lm95245.c +++ b/drivers/hwmon/lm95245.c @@ -1,10 +1,8 @@ /* * Copyright (C) 2011 Alexander Stein * - * The LM95245 is a sensor chip made by National Semiconductors. + * The LM95245 is a sensor chip made by TI / National Semiconductor. * It reports up to two temperatures (its own plus an external one). - * Complete datasheet can be obtained from National's website at: - * http://www.national.com/ds.cgi/LM/LM95245.pdf * * This driver is based on lm95241.c * @@ -34,8 +32,6 @@ #include #include -#define DEVNAME "lm95245" - static const unsigned short normal_i2c[] = { 0x18, 0x19, 0x29, 0x4c, 0x4d, I2C_CLIENT_END }; @@ -98,7 +94,8 @@ static const unsigned short normal_i2c[] = { #define STATUS1_LOC 0x01 #define MANUFACTURER_ID 0x01 -#define DEFAULT_REVISION 0xB3 +#define LM95235_REVISION 0xB1 +#define LM95245_REVISION 0xB3 static const u8 lm95245_reg_address[] = { LM95245_REG_R_LOCAL_TEMPH_S, @@ -427,17 +424,32 @@ static int lm95245_detect(struct i2c_client *new_client, struct i2c_board_info *info) { struct i2c_adapter *adapter = new_client->adapter; + int address = new_client->addr; + const char *name; + int rev, id; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -ENODEV; - if (i2c_smbus_read_byte_data(new_client, LM95245_REG_R_MAN_ID) - != MANUFACTURER_ID - || i2c_smbus_read_byte_data(new_client, LM95245_REG_R_CHIP_ID) - != DEFAULT_REVISION) + id = i2c_smbus_read_byte_data(new_client, LM95245_REG_R_MAN_ID); + if (id != MANUFACTURER_ID) return -ENODEV; - strlcpy(info->type, DEVNAME, I2C_NAME_SIZE); + rev = i2c_smbus_read_byte_data(new_client, LM95245_REG_R_CHIP_ID); + switch (rev) { + case LM95235_REVISION: + if (address != 0x18 && address != 0x29 && address != 0x4c) + return -ENODEV; + name = "lm95235"; + break; + case LM95245_REVISION: + name = "lm95245"; + break; + default: + return -ENODEV; + } + + strlcpy(info->type, name, I2C_NAME_SIZE); return 0; } @@ -484,7 +496,8 @@ static int lm95245_probe(struct i2c_client *client, /* Driver data (common to all clients) */ static const struct i2c_device_id lm95245_id[] = { - { DEVNAME, 0 }, + { "lm95235", 0 }, + { "lm95245", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, lm95245_id); @@ -492,7 +505,7 @@ MODULE_DEVICE_TABLE(i2c, lm95245_id); static struct i2c_driver lm95245_driver = { .class = I2C_CLASS_HWMON, .driver = { - .name = DEVNAME, + .name = "lm95245", }, .probe = lm95245_probe, .id_table = lm95245_id, @@ -503,5 +516,5 @@ static struct i2c_driver lm95245_driver = { module_i2c_driver(lm95245_driver); MODULE_AUTHOR("Alexander Stein "); -MODULE_DESCRIPTION("LM95245 sensor driver"); +MODULE_DESCRIPTION("LM95235/LM95245 sensor driver"); MODULE_LICENSE("GPL"); -- cgit v1.2.3-59-g8ed1b From 8b7daad3da2b36f5fe494f5d0c5ef25b33d56b96 Mon Sep 17 00:00:00 2001 From: Gyungoh Yoo Date: Tue, 2 Dec 2014 17:05:29 +0900 Subject: regulator: sky81452: Modify Device Tree structure Signed-off-by: Gyungoh Yoo Signed-off-by: Mark Brown --- .../devicetree/bindings/regulator/sky81452-regulator.txt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/regulator/sky81452-regulator.txt b/Documentation/devicetree/bindings/regulator/sky81452-regulator.txt index 882455e9b36d..f9acbc1f3c6b 100644 --- a/Documentation/devicetree/bindings/regulator/sky81452-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/sky81452-regulator.txt @@ -1,6 +1,7 @@ SKY81452 voltage regulator Required properties: +- regulator node named lout. - any required generic properties defined in regulator.txt Optional properties: @@ -9,8 +10,9 @@ Optional properties: Example: regulator { - /* generic regulator properties */ - regulator-name = "touch_en"; - regulator-min-microvolt = <4500000>; - regulator-max-microvolt = <8000000>; + lout { + regulator-name = "sky81452-lout"; + regulator-min-microvolt = <4500000>; + regulator-max-microvolt = <8000000>; + }; }; -- cgit v1.2.3-59-g8ed1b From ea04036032edda6f771c1381d03832d2ed0f6c31 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 2 Dec 2014 11:59:50 +0300 Subject: CodingStyle: add some more error handling guidelines I added a paragraph on choosing label names, and updated the example code to use a better label name. I also cleaned up the example code to more modern style by moving the allocation out of the initializer and changing the NULL check. Perhaps the most common type of error handling bug in the kernel is "one err bugs". CodingStyle already says that we should "avoid nesting" by using error labels and one err style error handling tends to have multiple indent levels, so this was already bad style. But I've added a new paragraph explaining how to avoid one err bugs by using multiple error labels which is, hopefully, more clear. Signed-off-by: Dan Carpenter Acked-by: Julia Lawall [jc: added GFP_KERNEL to kmalloc() call] Signed-off-by: Jonathan Corbet --- Documentation/CodingStyle | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/CodingStyle b/Documentation/CodingStyle index 9f28b140dc89..618a33c940df 100644 --- a/Documentation/CodingStyle +++ b/Documentation/CodingStyle @@ -392,7 +392,12 @@ The goto statement comes in handy when a function exits from multiple locations and some common work such as cleanup has to be done. If there is no cleanup needed then just return directly. -The rationale is: +Choose label names which say what the goto does or why the goto exists. An +example of a good name could be "out_buffer:" if the goto frees "buffer". Avoid +using GW-BASIC names like "err1:" and "err2:". Also don't name them after the +goto location like "err_kmalloc_failed:" + +The rationale for using gotos is: - unconditional statements are easier to understand and follow - nesting is reduced @@ -403,9 +408,10 @@ The rationale is: int fun(int a) { int result = 0; - char *buffer = kmalloc(SIZE); + char *buffer; - if (buffer == NULL) + buffer = kmalloc(SIZE, GFP_KERNEL); + if (!buffer) return -ENOMEM; if (condition1) { @@ -413,14 +419,25 @@ int fun(int a) ... } result = 1; - goto out; + goto out_buffer; } ... -out: +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; + +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:". + + Chapter 8: Commenting Comments are good, but there is also a danger of over-commenting. NEVER -- cgit v1.2.3-59-g8ed1b From dfcd4c53be1da9e297bba340ec46f3269cbc239e Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 22 Apr 2014 09:34:14 -0700 Subject: hwmon: (lm95234) Add support for LM95233 LM95233 is similar to LM95234, but it only supports two instead of four external temperature sensors. Reviewed-by: Jean Delvare Signed-off-by: Guenter Roeck --- Documentation/hwmon/lm95234 | 15 +++++--- drivers/hwmon/Kconfig | 6 +-- drivers/hwmon/lm95234.c | 91 ++++++++++++++++++++++++++++++++------------- 3 files changed, 78 insertions(+), 34 deletions(-) (limited to 'Documentation') diff --git a/Documentation/hwmon/lm95234 b/Documentation/hwmon/lm95234 index a0e95ddfd372..32b777ef224c 100644 --- a/Documentation/hwmon/lm95234 +++ b/Documentation/hwmon/lm95234 @@ -2,6 +2,10 @@ Kernel driver lm95234 ===================== Supported chips: + * National Semiconductor / Texas Instruments LM95233 + Addresses scanned: I2C 0x18, 0x2a, 0x2b + Datasheet: Publicly available at the Texas Instruments website + http://www.ti.com/product/lm95233 * National Semiconductor / Texas Instruments LM95234 Addresses scanned: I2C 0x18, 0x4d, 0x4e Datasheet: Publicly available at the Texas Instruments website @@ -13,11 +17,12 @@ Author: Guenter Roeck Description ----------- -LM95234 is an 11-bit digital temperature sensor with a 2-wire System Management -Bus (SMBus) interface and TrueTherm technology that can very accurately monitor -the temperature of four remote diodes as well as its own temperature. -The four remote diodes can be external devices such as microprocessors, -graphics processors or diode-connected 2N3904s. The LM95234's TruTherm +LM95233 and LM95234 are 11-bit digital temperature sensors with a 2-wire +System Management Bus (SMBus) interface and TrueTherm technology +that can very accurately monitor the temperature of two (LM95233) +or four (LM95234) remote diodes as well as its own temperature. +The remote diodes can be external devices such as microprocessors, +graphics processors or diode-connected 2N3904s. The chip's TruTherm beta compensation technology allows sensing of 90 nm or 65 nm process thermal diodes accurately. diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 085f5a853618..b1ce6a093a93 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1028,11 +1028,11 @@ config SENSORS_LM93 will be called lm93. config SENSORS_LM95234 - tristate "National Semiconductor LM95234" + tristate "National Semiconductor LM95234 and compatibles" depends on I2C help - If you say yes here you get support for the LM95234 temperature - sensor. + If you say yes here you get support for the LM95233 and LM95234 + temperature sensor chips. This driver can also be built as a module. If so, the module will be called lm95234. diff --git a/drivers/hwmon/lm95234.c b/drivers/hwmon/lm95234.c index 411202bdaf6b..8796de39ff9b 100644 --- a/drivers/hwmon/lm95234.c +++ b/drivers/hwmon/lm95234.c @@ -1,7 +1,7 @@ /* * Driver for Texas Instruments / National Semiconductor LM95234 * - * Copyright (c) 2013 Guenter Roeck + * Copyright (c) 2013, 2014 Guenter Roeck * * Derived from lm95241.c * Copyright (C) 2008, 2010 Davide Rizzo @@ -30,7 +30,10 @@ #define DRVNAME "lm95234" -static const unsigned short normal_i2c[] = { 0x18, 0x4d, 0x4e, I2C_CLIENT_END }; +enum chips { lm95233, lm95234 }; + +static const unsigned short normal_i2c[] = { + 0x18, 0x2a, 0x2b, 0x4d, 0x4e, I2C_CLIENT_END }; /* LM95234 registers */ #define LM95234_REG_MAN_ID 0xFE @@ -53,11 +56,13 @@ static const unsigned short normal_i2c[] = { 0x18, 0x4d, 0x4e, I2C_CLIENT_END }; #define LM95234_REG_TCRIT_HYST 0x5a #define NATSEMI_MAN_ID 0x01 +#define LM95233_CHIP_ID 0x89 #define LM95234_CHIP_ID 0x79 /* Client data (each client gets its own) */ struct lm95234_data { struct i2c_client *client; + const struct attribute_group *groups[3]; struct mutex update_lock; unsigned long last_updated, interval; /* in jiffies */ bool valid; /* false until following fields are valid */ @@ -564,35 +569,23 @@ static SENSOR_DEVICE_ATTR(temp5_offset, S_IWUSR | S_IRUGO, show_offset, static DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO, show_interval, set_interval); -static struct attribute *lm95234_attrs[] = { +static struct attribute *lm95234_common_attrs[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, &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_temp2_fault.dev_attr.attr, &sensor_dev_attr_temp3_fault.dev_attr.attr, - &sensor_dev_attr_temp4_fault.dev_attr.attr, - &sensor_dev_attr_temp5_fault.dev_attr.attr, &sensor_dev_attr_temp2_type.dev_attr.attr, &sensor_dev_attr_temp3_type.dev_attr.attr, - &sensor_dev_attr_temp4_type.dev_attr.attr, - &sensor_dev_attr_temp5_type.dev_attr.attr, &sensor_dev_attr_temp1_max.dev_attr.attr, &sensor_dev_attr_temp2_max.dev_attr.attr, &sensor_dev_attr_temp3_max.dev_attr.attr, - &sensor_dev_attr_temp4_max.dev_attr.attr, - &sensor_dev_attr_temp5_max.dev_attr.attr, &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, &sensor_dev_attr_temp2_max_hyst.dev_attr.attr, &sensor_dev_attr_temp3_max_hyst.dev_attr.attr, - &sensor_dev_attr_temp4_max_hyst.dev_attr.attr, - &sensor_dev_attr_temp5_max_hyst.dev_attr.attr, &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, &sensor_dev_attr_temp3_max_alarm.dev_attr.attr, - &sensor_dev_attr_temp4_max_alarm.dev_attr.attr, - &sensor_dev_attr_temp5_max_alarm.dev_attr.attr, &sensor_dev_attr_temp2_crit.dev_attr.attr, &sensor_dev_attr_temp3_crit.dev_attr.attr, &sensor_dev_attr_temp2_crit_hyst.dev_attr.attr, @@ -601,18 +594,44 @@ static struct attribute *lm95234_attrs[] = { &sensor_dev_attr_temp3_crit_alarm.dev_attr.attr, &sensor_dev_attr_temp2_offset.dev_attr.attr, &sensor_dev_attr_temp3_offset.dev_attr.attr, + &dev_attr_update_interval.attr, + NULL +}; + +static const struct attribute_group lm95234_common_group = { + .attrs = lm95234_common_attrs, +}; + +static struct attribute *lm95234_attrs[] = { + &sensor_dev_attr_temp4_input.dev_attr.attr, + &sensor_dev_attr_temp5_input.dev_attr.attr, + &sensor_dev_attr_temp4_fault.dev_attr.attr, + &sensor_dev_attr_temp5_fault.dev_attr.attr, + &sensor_dev_attr_temp4_type.dev_attr.attr, + &sensor_dev_attr_temp5_type.dev_attr.attr, + &sensor_dev_attr_temp4_max.dev_attr.attr, + &sensor_dev_attr_temp5_max.dev_attr.attr, + &sensor_dev_attr_temp4_max_hyst.dev_attr.attr, + &sensor_dev_attr_temp5_max_hyst.dev_attr.attr, + &sensor_dev_attr_temp4_max_alarm.dev_attr.attr, + &sensor_dev_attr_temp5_max_alarm.dev_attr.attr, &sensor_dev_attr_temp4_offset.dev_attr.attr, &sensor_dev_attr_temp5_offset.dev_attr.attr, - &dev_attr_update_interval.attr, NULL }; -ATTRIBUTE_GROUPS(lm95234); + +static const struct attribute_group lm95234_group = { + .attrs = lm95234_attrs, +}; static int lm95234_detect(struct i2c_client *client, struct i2c_board_info *info) { struct i2c_adapter *adapter = client->adapter; + int address = client->addr; + u8 config_mask, model_mask; int mfg_id, chip_id, val; + const char *name; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -ENODEV; @@ -622,15 +641,31 @@ static int lm95234_detect(struct i2c_client *client, return -ENODEV; chip_id = i2c_smbus_read_byte_data(client, LM95234_REG_CHIP_ID); - if (chip_id != LM95234_CHIP_ID) + switch (chip_id) { + case LM95233_CHIP_ID: + if (address != 0x18 && address != 0x2a && address != 0x2b) + return -ENODEV; + config_mask = 0xbf; + model_mask = 0xf9; + name = "lm95233"; + break; + case LM95234_CHIP_ID: + if (address != 0x18 && address != 0x4d && address != 0x4e) + return -ENODEV; + config_mask = 0xbc; + model_mask = 0xe1; + name = "lm95234"; + break; + default: return -ENODEV; + } val = i2c_smbus_read_byte_data(client, LM95234_REG_STATUS); if (val & 0x30) return -ENODEV; val = i2c_smbus_read_byte_data(client, LM95234_REG_CONFIG); - if (val & 0xbc) + if (val & config_mask) return -ENODEV; val = i2c_smbus_read_byte_data(client, LM95234_REG_CONVRATE); @@ -638,14 +673,14 @@ static int lm95234_detect(struct i2c_client *client, return -ENODEV; val = i2c_smbus_read_byte_data(client, LM95234_REG_REM_MODEL); - if (val & 0xe1) + if (val & model_mask) return -ENODEV; val = i2c_smbus_read_byte_data(client, LM95234_REG_REM_MODEL_STS); - if (val & 0xe1) + if (val & model_mask) return -ENODEV; - strlcpy(info->type, "lm95234", I2C_NAME_SIZE); + strlcpy(info->type, name, I2C_NAME_SIZE); return 0; } @@ -698,15 +733,19 @@ static int lm95234_probe(struct i2c_client *client, if (err < 0) return err; + data->groups[0] = &lm95234_common_group; + if (id->driver_data == lm95234) + data->groups[1] = &lm95234_group; + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, - data, - lm95234_groups); + data, data->groups); return PTR_ERR_OR_ZERO(hwmon_dev); } /* Driver data (common to all clients) */ static const struct i2c_device_id lm95234_id[] = { - { "lm95234", 0 }, + { "lm95233", lm95233 }, + { "lm95234", lm95234 }, { } }; MODULE_DEVICE_TABLE(i2c, lm95234_id); @@ -725,5 +764,5 @@ static struct i2c_driver lm95234_driver = { module_i2c_driver(lm95234_driver); MODULE_AUTHOR("Guenter Roeck "); -MODULE_DESCRIPTION("LM95234 sensor driver"); +MODULE_DESCRIPTION("LM95233/LM95234 sensor driver"); MODULE_LICENSE("GPL"); -- cgit v1.2.3-59-g8ed1b From 04a3302b5ff4225ac59302c5995276cacdd6da4a Mon Sep 17 00:00:00 2001 From: Richard Leitner Date: Tue, 2 Dec 2014 17:44:36 +0100 Subject: Documentation/email-clients.txt: add info about Claws Mail Claws Mail GUI client works. The client is available at http://www.claws-mail.org Signed-off-by: Richard Leitner Signed-off-by: Jonathan Corbet --- Documentation/email-clients.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'Documentation') diff --git a/Documentation/email-clients.txt b/Documentation/email-clients.txt index 9af538be3751..eede6088f978 100644 --- a/Documentation/email-clients.txt +++ b/Documentation/email-clients.txt @@ -76,6 +76,17 @@ When composing the message, the cursor should be placed where the patch should appear, and then pressing CTRL-R let you specify the patch file to insert into the message. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Claws Mail (GUI) + +Works. Some people use this successfully for patches. + +To insert a patch use Message->Insert File (CTRL+i) or an external editor. + +If the inserted patch has to be edited in the Claws composition window +"Auto wrapping" in Configuration->Preferences->Compose->Wrapping should be +disabled. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Evolution (GUI) -- cgit v1.2.3-59-g8ed1b From 007f790c8276271de26416f90d55561bcc96588a Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 28 Nov 2014 14:34:17 +0100 Subject: net: introduce generic switch devices support The goal of this is to provide a possibility to support various switch chips. Drivers should implement relevant ndos to do so. Now there is only one ndo defined: - for getting physical switch id is in place. Note that user can use random port netdevice to access the switch. Signed-off-by: Jiri Pirko Reviewed-by: Thomas Graf Acked-by: Andy Gospodarek Signed-off-by: David S. Miller --- Documentation/networking/switchdev.txt | 59 ++++++++++++++++++++++++++++++++++ MAINTAINERS | 7 ++++ include/linux/netdevice.h | 10 ++++++ include/net/switchdev.h | 30 +++++++++++++++++ net/Kconfig | 1 + net/Makefile | 3 ++ net/switchdev/Kconfig | 13 ++++++++ net/switchdev/Makefile | 5 +++ net/switchdev/switchdev.c | 33 +++++++++++++++++++ 9 files changed, 161 insertions(+) create mode 100644 Documentation/networking/switchdev.txt create mode 100644 include/net/switchdev.h create mode 100644 net/switchdev/Kconfig create mode 100644 net/switchdev/Makefile create mode 100644 net/switchdev/switchdev.c (limited to 'Documentation') diff --git a/Documentation/networking/switchdev.txt b/Documentation/networking/switchdev.txt new file mode 100644 index 000000000000..f981a9295a39 --- /dev/null +++ b/Documentation/networking/switchdev.txt @@ -0,0 +1,59 @@ +Switch (and switch-ish) device drivers HOWTO +=========================== + +Please note that the word "switch" is here used in very generic meaning. +This include devices supporting L2/L3 but also various flow offloading chips, +including switches embedded into SR-IOV NICs. + +Lets describe a topology a bit. Imagine the following example: + + +----------------------------+ +---------------+ + | SOME switch chip | | CPU | + +----------------------------+ +---------------+ + port1 port2 port3 port4 MNGMNT | PCI-E | + | | | | | +---------------+ + PHY PHY | | | | NIC0 NIC1 + | | | | | | + | | +- PCI-E -+ | | + | +------- MII -------+ | + +------------- MII ------------+ + +In this example, there are two independent lines between the switch silicon +and CPU. NIC0 and NIC1 drivers are not aware of a switch presence. They are +separate from the switch driver. SOME switch chip is by managed by a driver +via PCI-E device MNGMNT. Note that MNGMNT device, NIC0 and NIC1 may be +connected to some other type of bus. + +Now, for the previous example show the representation in kernel: + + +----------------------------+ +---------------+ + | SOME switch chip | | CPU | + +----------------------------+ +---------------+ + sw0p0 sw0p1 sw0p2 sw0p3 MNGMNT | PCI-E | + | | | | | +---------------+ + PHY PHY | | | | eth0 eth1 + | | | | | | + | | +- PCI-E -+ | | + | +------- MII -------+ | + +------------- MII ------------+ + +Lets call the example switch driver for SOME switch chip "SOMEswitch". This +driver takes care of PCI-E device MNGMNT. There is a netdevice instance sw0pX +created for each port of a switch. These netdevices are instances +of "SOMEswitch" driver. sw0pX netdevices serve as a "representation" +of the switch chip. eth0 and eth1 are instances of some other existing driver. + +The only difference of the switch-port netdevice from the ordinary netdevice +is that is implements couple more NDOs: + + ndo_switch_parent_id_get - This returns the same ID for two port netdevices + of the same physical switch chip. This is + mandatory to be implemented by all switch drivers + and serves the caller for recognition of a port + netdevice. + ndo_switch_parent_* - Functions that serve for a manipulation of the switch + chip itself (it can be though of as a "parent" of the + port, therefore the name). They are not port-specific. + Caller might use arbitrary port netdevice of the same + switch and it will make no difference. + ndo_switch_port_* - Functions that serve for a port-specific manipulation. diff --git a/MAINTAINERS b/MAINTAINERS index 6b880deae3d2..3aba0ac2d5a3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9059,6 +9059,13 @@ F: lib/swiotlb.c F: arch/*/kernel/pci-swiotlb.c F: include/linux/swiotlb.h +SWITCHDEV +M: Jiri Pirko +L: netdev@vger.kernel.org +S: Supported +F: net/switchdev/ +F: include/net/switchdev.h + SYNOPSYS ARC ARCHITECTURE M: Vineet Gupta S: Supported diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 4bd41d72559d..3603f31e78f3 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1018,6 +1018,12 @@ typedef u16 (*select_queue_fallback_t)(struct net_device *dev, * performing GSO on a packet. The device returns true if it is * able to GSO the packet, false otherwise. If the return value is * false the stack will do software GSO. + * + * int (*ndo_switch_parent_id_get)(struct net_device *dev, + * struct netdev_phys_item_id *psid); + * Called to get an ID of the switch chip this port is part of. + * If driver implements this, it indicates that it represents a port + * of a switch chip. */ struct net_device_ops { int (*ndo_init)(struct net_device *dev); @@ -1171,6 +1177,10 @@ struct net_device_ops { int (*ndo_get_lock_subclass)(struct net_device *dev); bool (*ndo_gso_check) (struct sk_buff *skb, struct net_device *dev); +#ifdef CONFIG_NET_SWITCHDEV + int (*ndo_switch_parent_id_get)(struct net_device *dev, + struct netdev_phys_item_id *psid); +#endif }; /** diff --git a/include/net/switchdev.h b/include/net/switchdev.h new file mode 100644 index 000000000000..7a52360a1446 --- /dev/null +++ b/include/net/switchdev.h @@ -0,0 +1,30 @@ +/* + * include/net/switchdev.h - Switch device API + * Copyright (c) 2014 Jiri Pirko + * + * 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. + */ +#ifndef _LINUX_SWITCHDEV_H_ +#define _LINUX_SWITCHDEV_H_ + +#include + +#ifdef CONFIG_NET_SWITCHDEV + +int netdev_switch_parent_id_get(struct net_device *dev, + struct netdev_phys_item_id *psid); + +#else + +static inline int netdev_switch_parent_id_get(struct net_device *dev, + struct netdev_phys_item_id *psid) +{ + return -EOPNOTSUPP; +} + +#endif + +#endif /* _LINUX_SWITCHDEV_H_ */ diff --git a/net/Kconfig b/net/Kconfig index 99815b5454bf..ff9ffc17fa0e 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -228,6 +228,7 @@ source "net/vmw_vsock/Kconfig" source "net/netlink/Kconfig" source "net/mpls/Kconfig" source "net/hsr/Kconfig" +source "net/switchdev/Kconfig" config RPS boolean diff --git a/net/Makefile b/net/Makefile index 7ed1970074b0..95fc694e4ddc 100644 --- a/net/Makefile +++ b/net/Makefile @@ -73,3 +73,6 @@ obj-$(CONFIG_OPENVSWITCH) += openvswitch/ obj-$(CONFIG_VSOCKETS) += vmw_vsock/ obj-$(CONFIG_NET_MPLS_GSO) += mpls/ obj-$(CONFIG_HSR) += hsr/ +ifneq ($(CONFIG_NET_SWITCHDEV),) +obj-y += switchdev/ +endif diff --git a/net/switchdev/Kconfig b/net/switchdev/Kconfig new file mode 100644 index 000000000000..155754588fd6 --- /dev/null +++ b/net/switchdev/Kconfig @@ -0,0 +1,13 @@ +# +# Configuration for Switch device support +# + +config NET_SWITCHDEV + boolean "Switch (and switch-ish) device support (EXPERIMENTAL)" + depends on INET + ---help--- + This module provides glue between core networking code and device + drivers in order to support hardware switch chips in very generic + meaning of the word "switch". This include devices supporting L2/L3 but + also various flow offloading chips, including switches embedded into + SR-IOV NICs. diff --git a/net/switchdev/Makefile b/net/switchdev/Makefile new file mode 100644 index 000000000000..5ed63ed324d0 --- /dev/null +++ b/net/switchdev/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the Switch device API +# + +obj-$(CONFIG_NET_SWITCHDEV) += switchdev.o diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c new file mode 100644 index 000000000000..66973deaae56 --- /dev/null +++ b/net/switchdev/switchdev.c @@ -0,0 +1,33 @@ +/* + * net/switchdev/switchdev.c - Switch device API + * Copyright (c) 2014 Jiri Pirko + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include + +/** + * netdev_switch_parent_id_get - Get ID of a switch + * @dev: port device + * @psid: switch ID + * + * Get ID of a switch this port is part of. + */ +int netdev_switch_parent_id_get(struct net_device *dev, + struct netdev_phys_item_id *psid) +{ + const struct net_device_ops *ops = dev->netdev_ops; + + if (!ops->ndo_switch_parent_id_get) + return -EOPNOTSUPP; + return ops->ndo_switch_parent_id_get(dev, psid); +} +EXPORT_SYMBOL(netdev_switch_parent_id_get); -- cgit v1.2.3-59-g8ed1b From aecbe01e7410ad2de022796472f531ae6941f15e Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 28 Nov 2014 14:34:19 +0100 Subject: net-sysfs: expose physical switch id for particular device Signed-off-by: Jiri Pirko Reviewed-by: Thomas Graf Acked-by: John Fastabend Acked-by: Andy Gospodarek Acked-by: Florian Fainelli Signed-off-by: David S. Miller --- Documentation/ABI/testing/sysfs-class-net | 8 ++++++++ net/core/net-sysfs.c | 24 ++++++++++++++++++++++++ 2 files changed, 32 insertions(+) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-class-net b/Documentation/ABI/testing/sysfs-class-net index e1b2e785bba8..beb8ec4dabbc 100644 --- a/Documentation/ABI/testing/sysfs-class-net +++ b/Documentation/ABI/testing/sysfs-class-net @@ -216,3 +216,11 @@ Contact: netdev@vger.kernel.org Description: Indicates the interface protocol type as a decimal value. See include/uapi/linux/if_arp.h for all possible values. + +What: /sys/class/net//phys_switch_id +Date: November 2014 +KernelVersion: 3.19 +Contact: netdev@vger.kernel.org +Description: + Indicates the unique physical switch identifier of a switch this + port belongs to, as a string. diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 26c46f4726c5..999341244434 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -416,6 +417,28 @@ static ssize_t phys_port_id_show(struct device *dev, } static DEVICE_ATTR_RO(phys_port_id); +static ssize_t phys_switch_id_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)) { + struct netdev_phys_item_id ppid; + + ret = netdev_switch_parent_id_get(netdev, &ppid); + if (!ret) + ret = sprintf(buf, "%*phN\n", ppid.id_len, ppid.id); + } + rtnl_unlock(); + + return ret; +} +static DEVICE_ATTR_RO(phys_switch_id); + static struct attribute *net_class_attrs[] = { &dev_attr_netdev_group.attr, &dev_attr_type.attr, @@ -441,6 +464,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_switch_id.attr, NULL, }; ATTRIBUTE_GROUPS(net_class); -- cgit v1.2.3-59-g8ed1b From a4e635544f65021c346f2097daa0c8dd63dd6221 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Mon, 1 Dec 2014 08:26:00 +0100 Subject: gpio: mcp23s08: Add option to configure IRQ output polarity as active high Default is active low, but if property is specified in DT set INTPOL flag. Signed-off-by: Alexander Stein Signed-off-by: Linus Walleij --- .../devicetree/bindings/gpio/gpio-mcp23s08.txt | 2 ++ drivers/gpio/gpio-mcp23s08.c | 30 +++++++++++++++++----- 2 files changed, 25 insertions(+), 7 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/gpio/gpio-mcp23s08.txt b/Documentation/devicetree/bindings/gpio/gpio-mcp23s08.txt index c306a2d0f2b1..f3332b9a8ed4 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-mcp23s08.txt +++ b/Documentation/devicetree/bindings/gpio/gpio-mcp23s08.txt @@ -57,6 +57,8 @@ Optional device specific properties: occurred on. If it is not set, the interrupt are only generated for the bank they belong to. On devices with only one interrupt output this property is useless. +- microchip,irq-active-high: Sets the INTPOL flag in the IOCON register. This + configures the IRQ output polarity as active high. Example I2C (with interrupt): gpiom1: gpio@20 { diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c index 0d58440eb8da..93ee7da2d8b0 100644 --- a/drivers/gpio/gpio-mcp23s08.c +++ b/drivers/gpio/gpio-mcp23s08.c @@ -65,6 +65,7 @@ struct mcp23s08_ops { struct mcp23s08 { u8 addr; + bool irq_active_high; u16 cache[11]; u16 irq_rise; @@ -476,6 +477,7 @@ static int mcp23s08_irq_setup(struct mcp23s08 *mcp) { struct gpio_chip *chip = &mcp->chip; int err, irq, j; + unsigned long irqflags = IRQF_ONESHOT | IRQF_SHARED; mutex_init(&mcp->irq_lock); @@ -484,10 +486,13 @@ static int mcp23s08_irq_setup(struct mcp23s08 *mcp) if (!mcp->irq_domain) return -ENODEV; + if (mcp->irq_active_high) + irqflags |= IRQF_TRIGGER_HIGH; + else + irqflags |= IRQF_TRIGGER_LOW; + err = devm_request_threaded_irq(chip->dev, mcp->irq, NULL, mcp23s08_irq, - IRQF_TRIGGER_LOW | IRQF_ONESHOT | - IRQF_SHARED, - dev_name(chip->dev), mcp); + irqflags, dev_name(chip->dev), mcp); if (err != 0) { dev_err(chip->dev, "unable to request IRQ#%d: %d\n", mcp->irq, err); @@ -589,6 +594,7 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, mcp->data = data; mcp->addr = addr; + mcp->irq_active_high = false; mcp->chip.direction_input = mcp23s08_direction_input; mcp->chip.get = mcp23s08_get; @@ -648,14 +654,24 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, goto fail; mcp->irq_controller = pdata->irq_controller; - if (mcp->irq && mcp->irq_controller && (type == MCP_TYPE_017)) - mirror = pdata->mirror; + if (mcp->irq && mcp->irq_controller) { + mcp->irq_active_high = of_property_read_bool(mcp->chip.of_node, + "microchip,irq-active-high"); - if ((status & IOCON_SEQOP) || !(status & IOCON_HAEN) || mirror) { + if (type == MCP_TYPE_017) + mirror = pdata->mirror; + } + + if ((status & IOCON_SEQOP) || !(status & IOCON_HAEN) || mirror || + mcp->irq_active_high) { /* mcp23s17 has IOCON twice, make sure they are in sync */ status &= ~(IOCON_SEQOP | (IOCON_SEQOP << 8)); status |= IOCON_HAEN | (IOCON_HAEN << 8); - status &= ~(IOCON_INTPOL | (IOCON_INTPOL << 8)); + if (mcp->irq_active_high) + status |= IOCON_INTPOL | (IOCON_INTPOL << 8); + else + status &= ~(IOCON_INTPOL | (IOCON_INTPOL << 8)); + if (mirror) status |= IOCON_MIRROR | (IOCON_MIRROR << 8); -- cgit v1.2.3-59-g8ed1b From 256965d724347a9fa1cce42dc30987e7d92addb3 Mon Sep 17 00:00:00 2001 From: Yunlei He Date: Tue, 2 Dec 2014 12:33:00 +0800 Subject: gpio: pl061: document gpio-ranges property for bindings file Document gpio-ranges property in pl061-gpio.txt Signed-off-by: Yunlei He Signed-off-by: Xinwei Kong Signed-off-by: Haojian Zhuang Signed-off-by: Linus Walleij --- Documentation/devicetree/bindings/gpio/pl061-gpio.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/gpio/pl061-gpio.txt b/Documentation/devicetree/bindings/gpio/pl061-gpio.txt index a2c416bcbccc..89058d375b7c 100644 --- a/Documentation/devicetree/bindings/gpio/pl061-gpio.txt +++ b/Documentation/devicetree/bindings/gpio/pl061-gpio.txt @@ -7,4 +7,4 @@ Required properties: - bit 0 specifies polarity (0 for normal, 1 for inverted) - gpio-controller : Marks the device node as a GPIO controller. - interrupts : Interrupt mapping for GPIO IRQ. - +- gpio-ranges : Interaction with the PINCTRL subsystem. -- cgit v1.2.3-59-g8ed1b From 845502d26301f8c37e2a57ad867672f306e674fb Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Wed, 3 Dec 2014 20:53:44 +0900 Subject: cgroups: Documentation: fix wrong cgroupfs paths Few paths used as example to describe cgroupfs usage have been wrong from f6e07d38078e ("Documentation: update cgroupfs mount point") by mistake. This patch fix those trivial wrong paths. Signed-off-by: SeongJae Park Signed-off-by: Jonathan Corbet --- Documentation/cgroups/cgroups.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/cgroups/cgroups.txt b/Documentation/cgroups/cgroups.txt index 10c949b293e4..f935fac1e73b 100644 --- a/Documentation/cgroups/cgroups.txt +++ b/Documentation/cgroups/cgroups.txt @@ -312,10 +312,10 @@ the "cpuset" cgroup subsystem, the steps are something like: 2) mkdir /sys/fs/cgroup/cpuset 3) mount -t cgroup -ocpuset cpuset /sys/fs/cgroup/cpuset 4) Create the new cgroup by doing mkdir's and write's (or echo's) in - the /sys/fs/cgroup virtual file system. + the /sys/fs/cgroup/cpuset virtual file system. 5) Start a task that will be the "founding father" of the new job. 6) Attach that task to the new cgroup by writing its PID to the - /sys/fs/cgroup/cpuset/tasks file for that cgroup. + /sys/fs/cgroup/cpuset tasks file for that cgroup. 7) fork, exec or clone the job tasks from this founding father task. For example, the following sequence of commands will setup a cgroup -- cgit v1.2.3-59-g8ed1b From 5ed903b3f567616deddf6bfa513ee7b1fcef64d2 Mon Sep 17 00:00:00 2001 From: Steffen Trumtrar Date: Mon, 1 Dec 2014 13:26:32 +0100 Subject: crypto: sahara - add support for i.MX53 The Sahara on the i.MX53 is of version 4. Add support for probing the device. Signed-off-by: Steffen Trumtrar Signed-off-by: Herbert Xu --- .../devicetree/bindings/crypto/fsl-imx-sahara.txt | 2 +- drivers/crypto/sahara.c | 20 +++++++++++++++++--- 2 files changed, 18 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/crypto/fsl-imx-sahara.txt b/Documentation/devicetree/bindings/crypto/fsl-imx-sahara.txt index 5c65eccd0e56..e8a35c71e947 100644 --- a/Documentation/devicetree/bindings/crypto/fsl-imx-sahara.txt +++ b/Documentation/devicetree/bindings/crypto/fsl-imx-sahara.txt @@ -1,5 +1,5 @@ Freescale SAHARA Cryptographic Accelerator included in some i.MX chips. -Currently only i.MX27 is supported. +Currently only i.MX27 and i.MX53 are supported. Required properties: - compatible : Should be "fsl,-sahara" diff --git a/drivers/crypto/sahara.c b/drivers/crypto/sahara.c index 6fb16fe7eea5..55c0d2bea426 100644 --- a/drivers/crypto/sahara.c +++ b/drivers/crypto/sahara.c @@ -24,10 +24,12 @@ #include #include #include +#include #include #define SAHARA_NAME "sahara" #define SAHARA_VERSION_3 3 +#define SAHARA_VERSION_4 4 #define SAHARA_TIMEOUT_MS 1000 #define SAHARA_MAX_HW_DESC 2 #define SAHARA_MAX_HW_LINK 20 @@ -130,6 +132,7 @@ struct sahara_aes_reqctx { struct sahara_dev { struct device *device; + unsigned int version; void __iomem *regs_base; struct clk *clk_ipg; struct clk *clk_ahb; @@ -860,6 +863,7 @@ static struct platform_device_id sahara_platform_ids[] = { MODULE_DEVICE_TABLE(platform, sahara_platform_ids); static struct of_device_id sahara_dt_ids[] = { + { .compatible = "fsl,imx53-sahara" }, { .compatible = "fsl,imx27-sahara" }, { /* sentinel */ } }; @@ -973,13 +977,23 @@ static int sahara_probe(struct platform_device *pdev) clk_prepare_enable(dev->clk_ahb); version = sahara_read(dev, SAHARA_REG_VERSION); - if (version != SAHARA_VERSION_3) { + if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx27-sahara")) { + if (version != SAHARA_VERSION_3) + err = -ENODEV; + } else if (of_device_is_compatible(pdev->dev.of_node, + "fsl,imx53-sahara")) { + if (((version >> 8) & 0xff) != SAHARA_VERSION_4) + err = -ENODEV; + version = (version >> 8) & 0xff; + } + if (err == -ENODEV) { dev_err(&pdev->dev, "SAHARA version %d not supported\n", - version); - err = -ENODEV; + version); goto err_algs; } + dev->version = version; + sahara_write(dev, SAHARA_CMD_RESET | SAHARA_CMD_MODE_BATCH, SAHARA_REG_CMD); sahara_write(dev, SAHARA_CONTROL_SET_THROTTLE(0) | -- cgit v1.2.3-59-g8ed1b From 3e6fb8e94329270c70ea00867112a2c6f348207f Mon Sep 17 00:00:00 2001 From: Joonsoo Kim Date: Wed, 3 Dec 2014 10:39:20 +0900 Subject: Documentation: describe trace_buf_size parameter more accurately I'm stuck into panic that too litte free memory is left when I boot with trace_buf_size parameter. After digging into the problem, I found that trace_buf_size is the size of trace buffer on each cpu rather than total size of trace buffer. To prevent victim like me, change description of trace_buf_size parameter more accurately. Link: http://lkml.kernel.org/r/1417570760-10620-1-git-send-email-iamjoonsoo.kim@lge.com Signed-off-by: Joonsoo Kim Signed-off-by: Steven Rostedt --- 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 7dbe5ec9d9cd..1d09eb37c562 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -3477,7 +3477,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted. are saved. trace_buf_size=nn[KMG] - [FTRACE] will set tracing buffer size. + [FTRACE] will set tracing buffer size on each cpu. trace_event=[event-list] [FTRACE] Set and start specified trace events in order -- cgit v1.2.3-59-g8ed1b From 8e1e1df29d837c589c8b4d7b49864481ff7795b8 Mon Sep 17 00:00:00 2001 From: Byungchul Park Date: Mon, 24 Nov 2014 09:34:19 +0900 Subject: tracing: Add additional marks to signal very large time deltas Currently, function graph tracer prints "!" or "+" just before function execution time to signal a function overhead, depending on the time. And some tracers tracing latency also print "!" or "+" just after time to signal overhead, depending on the interval between events. Even it is usually enough to do that, we sometimes need to signal for bigger execution time than 100 micro seconds. For example, I used function graph tracer to detect if there is any case that exit_mm() takes too much time. I did following steps in /sys/kernel/debug/tracing. It was easier to detect very large excution time with patched kernel than with original kernel. $ echo exit_mm > set_graph_function $ echo function_graph > current_tracer $ echo > trace $ cat trace_pipe > $LOGFILE ... (do something and terminate logging) $ grep "\\$" $LOGFILE 3) $ 22082032 us | } /* kernel_map_pages */ 3) $ 22082040 us | } /* free_pages_prepare */ 3) $ 22082113 us | } /* free_hot_cold_page */ 3) $ 22083455 us | } /* free_hot_cold_page_list */ 3) $ 22083895 us | } /* release_pages */ 3) $ 22177873 us | } /* free_pages_and_swap_cache */ 3) $ 22178929 us | } /* unmap_single_vma */ 3) $ 22198885 us | } /* unmap_vmas */ 3) $ 22206949 us | } /* exit_mmap */ 3) $ 22207659 us | } /* mmput */ 3) $ 22207793 us | } /* exit_mm */ And then, it was easy to find out that a schedule-out occured by sub_preempt_count() within kernel_map_pages(). To detect very large function exection time caused by either problematic function implementation or scheduling issues, this patch can be useful. Link: http://lkml.kernel.org/r/1416789259-24038-1-git-send-email-byungchul.park@lge.com Signed-off-by: Byungchul Park Signed-off-by: Steven Rostedt --- Documentation/trace/ftrace.txt | 10 +++++++--- kernel/trace/trace.h | 2 ++ kernel/trace/trace_functions_graph.c | 23 +++-------------------- kernel/trace/trace_output.c | 34 +++++++++++++++++++++++++++++----- 4 files changed, 41 insertions(+), 28 deletions(-) (limited to 'Documentation') diff --git a/Documentation/trace/ftrace.txt b/Documentation/trace/ftrace.txt index f10f5f5d260d..8408e040f06f 100644 --- a/Documentation/trace/ftrace.txt +++ b/Documentation/trace/ftrace.txt @@ -685,9 +685,11 @@ The above is mostly meaningful for kernel developers. needs to be fixed to be only relative to the same CPU. The marks are determined by the difference between this current trace and the next trace. - '!' - greater than preempt_mark_thresh (default 100) - '+' - greater than 1 microsecond - ' ' - less than or equal to 1 microsecond. + '$' - greater than 1 second + '#' - greater than 1000 microsecond + '!' - greater than 100 microsecond + '+' - greater than 10 microsecond + ' ' - less than or equal to 10 microsecond. The rest is the same as the 'trace' file. @@ -1956,6 +1958,8 @@ want, depending on your needs. + means that the function exceeded 10 usecs. ! means that the function exceeded 100 usecs. + # means that the function exceeded 1000 usecs. + $ means that the function exceeded 1 sec. - The task/pid field displays the thread cmdline and pid which diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index c3a37e55ec8b..3255dfb054a0 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -708,6 +708,8 @@ enum print_line_t print_trace_line(struct trace_iterator *iter); extern unsigned long trace_flags; +extern char trace_find_mark(unsigned long long duration); + /* Standard output formatting function used for function return traces */ #ifdef CONFIG_FUNCTION_GRAPH_TRACER diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c index 100288d10e1f..6c2ab955018c 100644 --- a/kernel/trace/trace_functions_graph.c +++ b/kernel/trace/trace_functions_graph.c @@ -730,8 +730,6 @@ static void print_graph_duration(unsigned long long duration, struct trace_seq *s, u32 flags) { - bool duration_printed = false; - if (!(flags & TRACE_GRAPH_PRINT_DURATION) || !(trace_flags & TRACE_ITER_CONTEXT_INFO)) return; @@ -750,24 +748,9 @@ print_graph_duration(unsigned long long duration, struct trace_seq *s, } /* Signal a overhead of time execution to the output */ - if (flags & TRACE_GRAPH_PRINT_OVERHEAD) { - /* Duration exceeded 100 usecs */ - if (duration > 100000ULL) { - trace_seq_puts(s, "! "); - duration_printed = true; - - /* Duration exceeded 10 usecs */ - } else if (duration > 10000ULL) { - trace_seq_puts(s, "+ "); - duration_printed = true; - } - } - - /* - * If we did not exceed the duration tresholds or we dont want - * to print out the overhead. Either way we need to fill out the space. - */ - if (!duration_printed) + if (flags & TRACE_GRAPH_PRINT_OVERHEAD) + trace_seq_printf(s, "%c ", trace_find_mark(duration)); + else trace_seq_puts(s, " "); trace_print_graph_duration(duration, s); diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c index 723818bc83b4..b77b9a697619 100644 --- a/kernel/trace/trace_output.c +++ b/kernel/trace/trace_output.c @@ -115,7 +115,7 @@ ftrace_print_symbols_seq(struct trace_seq *p, unsigned long val, if (ret == (const char *)(trace_seq_buffer_ptr(p))) trace_seq_printf(p, "0x%lx", val); - + trace_seq_putc(p, 0); return ret; @@ -443,7 +443,32 @@ lat_print_generic(struct trace_seq *s, struct trace_entry *entry, int cpu) return trace_print_lat_fmt(s, entry); } -static unsigned long preempt_mark_thresh_us = 100; +#undef MARK +#define MARK(v, s) {.val = v, .sym = s} +/* trace overhead mark */ +static const struct trace_mark { + unsigned long long val; /* unit: nsec */ + char sym; +} mark[] = { + MARK(1000000000ULL , '$'), /* 1 sec */ + MARK(1000000ULL , '#'), /* 1000 usecs */ + MARK(100000ULL , '!'), /* 100 usecs */ + MARK(10000ULL , '+'), /* 10 usecs */ +}; +#undef MARK + +char trace_find_mark(unsigned long long d) +{ + int i; + int size = ARRAY_SIZE(mark); + + for (i = 0; i < size; i++) { + if (d >= mark[i].val) + break; + } + + return (i == size) ? ' ' : mark[i].sym; +} static int lat_print_timestamp(struct trace_iterator *iter, u64 next_ts) @@ -480,8 +505,7 @@ lat_print_timestamp(struct trace_iterator *iter, u64 next_ts) trace_seq_printf( s, " %4lldus%c: ", abs_ts, - rel_ts > preempt_mark_thresh_us ? '!' : - rel_ts > 1 ? '+' : ' '); + trace_find_mark(rel_ts * NSEC_PER_USEC)); } else { /* !verbose && !in_ns */ trace_seq_printf(s, " %4lld: ", abs_ts); @@ -663,7 +687,7 @@ int register_ftrace_event(struct trace_event *event) goto out; } else { - + event->type = next_event_type++; list = &ftrace_event_list; } -- cgit v1.2.3-59-g8ed1b From 2a9d832cc9aae21ea827520fef635b6c49a06c6d Mon Sep 17 00:00:00 2001 From: Leif Lindholm Date: Thu, 27 Nov 2014 17:56:05 +0000 Subject: of: Add bindings for chosen node, stdout-path Add a global binding for the chosen node. Include a description of the stdout-path, and an explicit statement on its extra options in the context of a UART console. Opening description stolen from www.devicetree.org, and part of the remaining text provided by Mark Rutland. Signed-off-by: Leif Lindholm [grant.likely: remove reference to uart_parse_options] Reviewed-by: Mark Rutland Signed-off-by: Grant Likely --- Documentation/devicetree/bindings/chosen.txt | 46 ++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 Documentation/devicetree/bindings/chosen.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/chosen.txt b/Documentation/devicetree/bindings/chosen.txt new file mode 100644 index 000000000000..ed838f453f7a --- /dev/null +++ b/Documentation/devicetree/bindings/chosen.txt @@ -0,0 +1,46 @@ +The chosen node +--------------- + +The chosen node does not represent a real device, but serves as a place +for passing data between firmware and the operating system, like boot +arguments. Data in the chosen node does not represent the hardware. + + +stdout-path property +-------------------- + +Device trees may specify the device to be used for boot console output +with a stdout-path property under /chosen, as described in ePAPR, e.g. + +/ { + chosen { + stdout-path = "/serial@f00:115200"; + }; + + serial@f00 { + compatible = "vendor,some-uart"; + reg = <0xf00 0x10>; + }; +}; + +If the character ":" is present in the value, this terminates the path. +The meaning of any characters following the ":" is device-specific, and +must be specified in the relevant binding documentation. + +For UART devices, the preferred binding is a string in the form: + + {{{}}} + +where + + baud - baud rate in decimal + parity - 'n' (none), 'o', (odd) or 'e' (even) + bits - number of data bits + flow - 'r' (rts) + +For example: 115200n8r + +Implementation note: Linux will look for the property "linux,stdout-path" or +on PowerPC "stdout" if "stdout-path" is not found. However, the +"linux,stdout-path" and "stdout" properties are deprecated. New platforms +should only use the "stdout-path" property. -- cgit v1.2.3-59-g8ed1b From f2d347ff70be453e861304448cb2f32ff94d40e9 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Tue, 25 Nov 2014 11:53:45 -0800 Subject: Input: gpio_keys - add device tree support for interrupt only keys This features already exists for board config setups. Add support for device tree based systems. Signed-off-by: Alexander Stein Signed-off-by: Dmitry Torokhov --- .../devicetree/bindings/input/gpio-keys.txt | 10 ++++++- drivers/input/keyboard/gpio_keys.c | 34 +++++++++++++--------- 2 files changed, 29 insertions(+), 15 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/input/gpio-keys.txt b/Documentation/devicetree/bindings/input/gpio-keys.txt index 5c2c02140a62..a4a38fcf2ed6 100644 --- a/Documentation/devicetree/bindings/input/gpio-keys.txt +++ b/Documentation/devicetree/bindings/input/gpio-keys.txt @@ -10,10 +10,13 @@ Optional properties: Each button (key) is represented as a sub-node of "gpio-keys": Subnode properties: - - gpios: OF device-tree gpio specification. - label: Descriptive name of the key. - linux,code: Keycode to emit. +Required mutual exclusive subnode-properties: + - gpios: OF device-tree gpio specification. + - interrupts: the interrupt line for that input + Optional subnode-properties: - linux,input-type: Specify event type this button/key generates. If not specified defaults to <1> == EV_KEY. @@ -33,4 +36,9 @@ Example nodes: linux,code = <103>; gpios = <&gpio1 0 1>; }; + button@22 { + label = "GPIO Key DOWN"; + linux,code = <108>; + interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; + }; ... diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 8c98e97f8e41..ce0d9090bbe9 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -29,6 +29,7 @@ #include #include #include +#include #include struct gpio_button_data { @@ -617,28 +618,33 @@ gpio_keys_get_devtree_pdata(struct device *dev) i = 0; for_each_child_of_node(node, pp) { - int gpio; + int gpio = -1; + int irq; enum of_gpio_flags flags; if (!of_find_property(pp, "gpios", NULL)) { - pdata->nbuttons--; - dev_warn(dev, "Found button without gpios\n"); - continue; - } - - gpio = of_get_gpio_flags(pp, 0, &flags); - if (gpio < 0) { - error = gpio; - if (error != -EPROBE_DEFER) - dev_err(dev, - "Failed to get gpio flags, error: %d\n", - error); - return ERR_PTR(error); + irq = irq_of_parse_and_map(pp, 0); + if (irq == 0) { + pdata->nbuttons--; + dev_warn(dev, "Found button without gpios or irqs\n"); + continue; + } + } else { + gpio = of_get_gpio_flags(pp, 0, &flags); + if (gpio < 0) { + error = gpio; + if (error != -EPROBE_DEFER) + dev_err(dev, + "Failed to get gpio flags, error: %d\n", + error); + return ERR_PTR(error); + } } button = &pdata->buttons[i++]; button->gpio = gpio; + button->irq = irq; button->active_low = flags & OF_GPIO_ACTIVE_LOW; if (of_property_read_u32(pp, "linux,code", &button->code)) { -- cgit v1.2.3-59-g8ed1b From ceb6c9c862c86423f41c1e20ecf8d454f837f519 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 29 Nov 2014 23:47:05 +0100 Subject: USB / PM: Drop CONFIG_PM_RUNTIME from the USB core After commit b2b49ccbdd54 (PM: Kconfig: Set PM_RUNTIME if PM_SLEEP is selected) PM_RUNTIME is always set if PM is set, so quite a few depend on CONFIG_PM (or even dropped in some cases). Replace CONFIG_PM_RUNTIME with CONFIG_PM in the USB core code and documentation. Signed-off-by: Rafael J. Wysocki Acked-by: Alan Stern Acked-by: Greg Kroah-Hartman --- Documentation/ABI/stable/sysfs-bus-usb | 14 ++++++-------- Documentation/ABI/testing/sysfs-bus-usb | 19 +++++++++---------- Documentation/usb/power-management.txt | 17 +++++++++-------- drivers/usb/core/driver.c | 6 +----- drivers/usb/core/hcd-pci.c | 11 ----------- drivers/usb/core/hcd.c | 12 ++++-------- drivers/usb/core/hub.c | 6 +++--- drivers/usb/core/port.c | 4 ++-- drivers/usb/core/sysfs.c | 13 ++++--------- drivers/usb/core/usb.c | 4 +--- drivers/usb/core/usb.h | 23 +++++++++-------------- drivers/usb/host/ehci-pci.c | 2 +- drivers/usb/host/sl811-hcd.c | 5 ++--- drivers/usb/host/u132-hcd.c | 3 +-- drivers/usb/host/xhci-hub.c | 2 +- drivers/usb/host/xhci.c | 29 ++++++++++++----------------- drivers/usb/phy/phy-msm-usb.c | 2 +- include/linux/usb.h | 2 +- include/linux/usb/hcd.h | 7 ++----- 19 files changed, 69 insertions(+), 112 deletions(-) (limited to 'Documentation') diff --git a/Documentation/ABI/stable/sysfs-bus-usb b/Documentation/ABI/stable/sysfs-bus-usb index e2bc700a6f9c..831f15d9672f 100644 --- a/Documentation/ABI/stable/sysfs-bus-usb +++ b/Documentation/ABI/stable/sysfs-bus-usb @@ -32,10 +32,9 @@ Date: January 2008 KernelVersion: 2.6.25 Contact: Sarah Sharp Description: - If CONFIG_PM_RUNTIME is enabled then this file - is present. When read, it returns the total time (in msec) - that the USB device has been connected to the machine. This - file is read-only. + If CONFIG_PM is enabled, then this file is present. When read, + it returns the total time (in msec) that the USB device has been + connected to the machine. This file is read-only. Users: PowerTOP https://01.org/powertop/ @@ -45,10 +44,9 @@ Date: January 2008 KernelVersion: 2.6.25 Contact: Sarah Sharp Description: - If CONFIG_PM_RUNTIME is enabled then this file - is present. When read, it returns the total time (in msec) - that the USB device has been active, i.e. not in a suspended - state. This file is read-only. + If CONFIG_PM is enabled, then this file is present. When read, + it returns the total time (in msec) that the USB device has been + active, i.e. not in a suspended state. This file is read-only. Tools can use this file and the connected_duration file to compute the percentage of time that a device has been active. diff --git a/Documentation/ABI/testing/sysfs-bus-usb b/Documentation/ABI/testing/sysfs-bus-usb index 614d451cee41..e5cc7633d013 100644 --- a/Documentation/ABI/testing/sysfs-bus-usb +++ b/Documentation/ABI/testing/sysfs-bus-usb @@ -104,16 +104,15 @@ What: /sys/bus/usb/devices/.../power/usb2_hardware_lpm Date: September 2011 Contact: Andiry Xu Description: - If CONFIG_PM_RUNTIME is set and a USB 2.0 lpm-capable device - is plugged in to a xHCI host which support link PM, it will - perform a LPM test; if the test is passed and host supports - USB2 hardware LPM (xHCI 1.0 feature), USB2 hardware LPM will - be enabled for the device and the USB device directory will - contain a file named power/usb2_hardware_lpm. The file holds - a string value (enable or disable) indicating whether or not - USB2 hardware LPM is enabled for the device. Developer can - write y/Y/1 or n/N/0 to the file to enable/disable the - feature. + If CONFIG_PM is set and a USB 2.0 lpm-capable device is plugged + in to a xHCI host which support link PM, it will perform a LPM + test; if the test is passed and host supports USB2 hardware LPM + (xHCI 1.0 feature), USB2 hardware LPM will be enabled for the + device and the USB device directory will contain a file named + power/usb2_hardware_lpm. The file holds a string value (enable + or disable) indicating whether or not USB2 hardware LPM is + enabled for the device. Developer can write y/Y/1 or n/N/0 to + the file to enable/disable the feature. What: /sys/bus/usb/devices/.../removable Date: February 2012 diff --git a/Documentation/usb/power-management.txt b/Documentation/usb/power-management.txt index 7b90fe034c4b..b5f83911732a 100644 --- a/Documentation/usb/power-management.txt +++ b/Documentation/usb/power-management.txt @@ -47,14 +47,15 @@ dynamic PM is implemented in the USB subsystem, although system PM is covered to some extent (see Documentation/power/*.txt for more information about system PM). -Note: Dynamic PM support for USB is present only if the kernel was -built with CONFIG_USB_SUSPEND enabled (which depends on -CONFIG_PM_RUNTIME). System PM support is present only if the kernel -was built with CONFIG_SUSPEND or CONFIG_HIBERNATION enabled. - -(Starting with the 3.10 kernel release, dynamic PM support for USB is -present whenever the kernel was built with CONFIG_PM_RUNTIME enabled. -The CONFIG_USB_SUSPEND option has been eliminated.) +System PM support is present only if the kernel was built with CONFIG_SUSPEND +or CONFIG_HIBERNATION enabled. Dynamic PM support for USB is present whenever +the kernel was built with CONFIG_PM enabled. + +[Historically, dynamic PM support for USB was present only if the +kernel had been built with CONFIG_USB_SUSPEND enabled (which depended on +CONFIG_PM_RUNTIME). Starting with the 3.10 kernel release, dynamic PM support +for USB was present whenever the kernel was built with CONFIG_PM_RUNTIME +enabled. The CONFIG_USB_SUSPEND option had been eliminated.] What is Remote Wakeup? diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 9bffd26cea05..874dec31a111 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1493,10 +1493,6 @@ int usb_resume(struct device *dev, pm_message_t msg) return status; } -#endif /* CONFIG_PM */ - -#ifdef CONFIG_PM_RUNTIME - /** * usb_enable_autosuspend - allow a USB device to be autosuspended * @udev: the USB device which may be autosuspended @@ -1876,7 +1872,7 @@ int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable) return ret; } -#endif /* CONFIG_PM_RUNTIME */ +#endif /* CONFIG_PM */ struct bus_type usb_bus_type = { .name = "usb", diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index efc953119ce2..9eb1cff28bd4 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -429,7 +429,6 @@ static int check_root_hub_suspended(struct device *dev) return 0; } -#if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM_RUNTIME) static int suspend_common(struct device *dev, bool do_wakeup) { struct pci_dev *pci_dev = to_pci_dev(dev); @@ -528,7 +527,6 @@ static int resume_common(struct device *dev, int event) } return retval; } -#endif /* SLEEP || RUNTIME */ #ifdef CONFIG_PM_SLEEP @@ -607,8 +605,6 @@ static int hcd_pci_restore(struct device *dev) #endif /* CONFIG_PM_SLEEP */ -#ifdef CONFIG_PM_RUNTIME - static int hcd_pci_runtime_suspend(struct device *dev) { int retval; @@ -630,13 +626,6 @@ static int hcd_pci_runtime_resume(struct device *dev) return retval; } -#else - -#define hcd_pci_runtime_suspend NULL -#define hcd_pci_runtime_resume NULL - -#endif /* CONFIG_PM_RUNTIME */ - const struct dev_pm_ops usb_hcd_pci_pm_ops = { .suspend = hcd_pci_suspend, .suspend_noirq = hcd_pci_suspend_noirq, diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index a6efb4184f2b..278be0515e8e 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -2258,10 +2258,6 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg) return status; } -#endif /* CONFIG_PM */ - -#ifdef CONFIG_PM_RUNTIME - /* Workqueue routine for root-hub remote wakeup */ static void hcd_resume_work(struct work_struct *work) { @@ -2293,7 +2289,7 @@ void usb_hcd_resume_root_hub (struct usb_hcd *hcd) } EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub); -#endif /* CONFIG_PM_RUNTIME */ +#endif /* CONFIG_PM */ /*-------------------------------------------------------------------------*/ @@ -2476,7 +2472,7 @@ struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver, init_timer(&hcd->rh_timer); hcd->rh_timer.function = rh_timer_func; hcd->rh_timer.data = (unsigned long) hcd; -#ifdef CONFIG_PM_RUNTIME +#ifdef CONFIG_PM INIT_WORK(&hcd->wakeup_work, hcd_resume_work); #endif @@ -2790,7 +2786,7 @@ error_create_attr_group: hcd->rh_registered = 0; spin_unlock_irq(&hcd_root_hub_lock); -#ifdef CONFIG_PM_RUNTIME +#ifdef CONFIG_PM cancel_work_sync(&hcd->wakeup_work); #endif mutex_lock(&usb_bus_list_lock); @@ -2858,7 +2854,7 @@ void usb_remove_hcd(struct usb_hcd *hcd) hcd->rh_registered = 0; spin_unlock_irq (&hcd_root_hub_lock); -#ifdef CONFIG_PM_RUNTIME +#ifdef CONFIG_PM cancel_work_sync(&hcd->wakeup_work); #endif diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index b649fef2e35d..c9596525ba8c 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1737,7 +1737,7 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) * - If user has indicated to prevent autosuspend by passing * usbcore.autosuspend = -1 then keep autosuspend disabled. */ -#ifdef CONFIG_PM_RUNTIME +#ifdef CONFIG_PM if (hdev->dev.power.autosuspend_delay >= 0) pm_runtime_set_autosuspend_delay(&hdev->dev, 0); #endif @@ -3449,7 +3449,7 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) return status; } -#ifdef CONFIG_PM_RUNTIME +#ifdef CONFIG_PM int usb_remote_wakeup(struct usb_device *udev) { @@ -4856,7 +4856,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, udev->state != USB_STATE_NOTATTACHED) { if (portstatus & USB_PORT_STAT_ENABLE) { status = 0; /* Nothing to do */ -#ifdef CONFIG_PM_RUNTIME +#ifdef CONFIG_PM } else if (udev->state == USB_STATE_SUSPENDED && udev->persist_enabled) { /* For a suspended device, treat this as a diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c index cd3f9dc24a06..210618319f10 100644 --- a/drivers/usb/core/port.c +++ b/drivers/usb/core/port.c @@ -72,7 +72,7 @@ static void usb_port_device_release(struct device *dev) kfree(port_dev); } -#ifdef CONFIG_PM_RUNTIME +#ifdef CONFIG_PM static int usb_port_runtime_resume(struct device *dev) { struct usb_port *port_dev = to_usb_port(dev); @@ -171,7 +171,7 @@ static int usb_port_runtime_suspend(struct device *dev) #endif static const struct dev_pm_ops usb_port_pm_ops = { -#ifdef CONFIG_PM_RUNTIME +#ifdef CONFIG_PM .runtime_suspend = usb_port_runtime_suspend, .runtime_resume = usb_port_runtime_resume, #endif diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 1236c6011c70..d26973844a4d 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -334,14 +334,6 @@ static void remove_persist_attributes(struct device *dev) &dev_attr_persist.attr, power_group_name); } -#else - -#define add_persist_attributes(dev) 0 -#define remove_persist_attributes(dev) do {} while (0) - -#endif /* CONFIG_PM */ - -#ifdef CONFIG_PM_RUNTIME static ssize_t connected_duration_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -585,10 +577,13 @@ static void remove_power_attributes(struct device *dev) #else +#define add_persist_attributes(dev) 0 +#define remove_persist_attributes(dev) do {} while (0) + #define add_power_attributes(dev) 0 #define remove_power_attributes(dev) do {} while (0) -#endif /* CONFIG_PM_RUNTIME */ +#endif /* CONFIG_PM */ /* Descriptor fields */ diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 2dd2362198d2..2a92b97f0144 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -49,7 +49,7 @@ const char *usbcore_name = "usbcore"; static bool nousb; /* Disable USB when built into kernel image */ -#ifdef CONFIG_PM_RUNTIME +#ifdef CONFIG_PM static int usb_autosuspend_delay = 2; /* Default delay value, * in seconds */ module_param_named(autosuspend, usb_autosuspend_delay, int, 0644); @@ -348,11 +348,9 @@ static const struct dev_pm_ops usb_device_pm_ops = { .thaw = usb_dev_thaw, .poweroff = usb_dev_poweroff, .restore = usb_dev_restore, -#ifdef CONFIG_PM_RUNTIME .runtime_suspend = usb_runtime_suspend, .runtime_resume = usb_runtime_resume, .runtime_idle = usb_runtime_idle, -#endif }; #endif /* CONFIG_PM */ diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index b1b34d0557c9..7eb1e26798e5 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -75,6 +75,14 @@ extern int usb_resume_complete(struct device *dev); extern int usb_port_suspend(struct usb_device *dev, pm_message_t msg); extern int usb_port_resume(struct usb_device *dev, pm_message_t msg); +extern void usb_autosuspend_device(struct usb_device *udev); +extern int usb_autoresume_device(struct usb_device *udev); +extern int usb_remote_wakeup(struct usb_device *dev); +extern int usb_runtime_suspend(struct device *dev); +extern int usb_runtime_resume(struct device *dev); +extern int usb_runtime_idle(struct device *dev); +extern int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable); + #else static inline int usb_port_suspend(struct usb_device *udev, pm_message_t msg) @@ -87,20 +95,6 @@ static inline int usb_port_resume(struct usb_device *udev, pm_message_t msg) return 0; } -#endif - -#ifdef CONFIG_PM_RUNTIME - -extern void usb_autosuspend_device(struct usb_device *udev); -extern int usb_autoresume_device(struct usb_device *udev); -extern int usb_remote_wakeup(struct usb_device *dev); -extern int usb_runtime_suspend(struct device *dev); -extern int usb_runtime_resume(struct device *dev); -extern int usb_runtime_idle(struct device *dev); -extern int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable); - -#else - #define usb_autosuspend_device(udev) do {} while (0) static inline int usb_autoresume_device(struct usb_device *udev) { @@ -111,6 +105,7 @@ static inline int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable) { return 0; } + #endif extern struct bus_type usb_bus_type; diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index ca7b964124af..851006a0d97b 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -305,7 +305,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd) } } -#ifdef CONFIG_PM_RUNTIME +#ifdef CONFIG_PM if (ehci->no_selective_suspend && device_can_wakeup(&pdev->dev)) ehci_warn(ehci, "selective suspend/wakeup unavailable\n"); #endif diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index ad0c348e68e9..25fb1da8d3d7 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -22,7 +22,7 @@ * and usb-storage. * * TODO: - * - usb suspend/resume triggered by sl811 (with PM_RUNTIME) + * - usb suspend/resume triggered by sl811 * - various issues noted in the code * - performance work; use both register banks; ... * - use urb->iso_frame_desc[] with ISO transfers @@ -1752,8 +1752,7 @@ sl811h_probe(struct platform_device *dev) #ifdef CONFIG_PM /* for this device there's no useful distinction between the controller - * and its root hub, except that the root hub only gets direct PM calls - * when CONFIG_PM_RUNTIME is enabled. + * and its root hub. */ static int diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index c0671750671f..bf86630b3cea 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -3144,8 +3144,7 @@ static int u132_probe(struct platform_device *pdev) #ifdef CONFIG_PM /* * for this device there's no useful distinction between the controller - * and its root hub, except that the root hub only gets direct PM calls - * when CONFIG_PM_RUNTIME is enabled. + * and its root hub. */ static int u132_suspend(struct platform_device *pdev, pm_message_t state) { diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 696160d48ae8..f674abd76865 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -1146,7 +1146,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd) set_bit(port_index, &bus_state->bus_suspended); } /* USB core sets remote wake mask for USB 3.0 hubs, - * including the USB 3.0 roothub, but only if CONFIG_PM_RUNTIME + * including the USB 3.0 roothub, but only if CONFIG_PM * is enabled, so also enable remote wake here. */ if (hcd->self.root_hub->do_remote_wakeup diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 2a5d45b4cb15..61173ca9cb8f 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -4024,7 +4024,7 @@ static int __maybe_unused xhci_change_max_exit_latency(struct xhci_hcd *xhci, return ret; } -#ifdef CONFIG_PM_RUNTIME +#ifdef CONFIG_PM /* BESL to HIRD Encoding array for USB2 LPM */ static int xhci_besl_encoding[16] = {125, 150, 200, 300, 400, 500, 1000, 2000, @@ -4239,24 +4239,8 @@ int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev) return 0; } -#else - -int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd, - struct usb_device *udev, int enable) -{ - return 0; -} - -int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev) -{ - return 0; -} - -#endif /* CONFIG_PM_RUNTIME */ - /*---------------------- USB 3.0 Link PM functions ------------------------*/ -#ifdef CONFIG_PM /* Service interval in nanoseconds = 2^(bInterval - 1) * 125us * 1000ns / 1us */ static unsigned long long xhci_service_interval_to_ns( struct usb_endpoint_descriptor *desc) @@ -4687,6 +4671,17 @@ int xhci_disable_usb3_lpm_timeout(struct usb_hcd *hcd, } #else /* CONFIG_PM */ +int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd, + struct usb_device *udev, int enable) +{ + return 0; +} + +int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev) +{ + return 0; +} + int xhci_enable_usb3_lpm_timeout(struct usb_hcd *hcd, struct usb_device *udev, enum usb3_link_state state) { diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index 7843ef7dd0ff..29be0e654ecc 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -1761,7 +1761,7 @@ static int msm_otg_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM_RUNTIME +#ifdef CONFIG_PM static int msm_otg_runtime_idle(struct device *dev) { struct msm_otg *motg = dev_get_drvdata(dev); diff --git a/include/linux/usb.h b/include/linux/usb.h index 447a7e2fc19b..f89c24a03bd9 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -637,7 +637,7 @@ static inline bool usb_acpi_power_manageable(struct usb_device *hdev, int index) #endif /* USB autosuspend and autoresume */ -#ifdef CONFIG_PM_RUNTIME +#ifdef CONFIG_PM extern void usb_enable_autosuspend(struct usb_device *udev); extern void usb_disable_autosuspend(struct usb_device *udev); diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index cd96a2bc3388..668898e29d0e 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -93,7 +93,7 @@ struct usb_hcd { struct timer_list rh_timer; /* drives root-hub polling */ struct urb *status_urb; /* the current status urb */ -#ifdef CONFIG_PM_RUNTIME +#ifdef CONFIG_PM struct work_struct wakeup_work; /* for remote wakeup */ #endif @@ -625,16 +625,13 @@ extern int usb_find_interface_driver(struct usb_device *dev, extern void usb_root_hub_lost_power(struct usb_device *rhdev); extern int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg); extern int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg); -#endif /* CONFIG_PM */ - -#ifdef CONFIG_PM_RUNTIME extern void usb_hcd_resume_root_hub(struct usb_hcd *hcd); #else static inline void usb_hcd_resume_root_hub(struct usb_hcd *hcd) { return; } -#endif /* CONFIG_PM_RUNTIME */ +#endif /* CONFIG_PM */ /*-------------------------------------------------------------------------*/ -- cgit v1.2.3-59-g8ed1b From 646cafc6aa4d6004d189de1cdc267ab562069ba9 Mon Sep 17 00:00:00 2001 From: Tomeu Vizoso Date: Tue, 2 Dec 2014 08:54:22 +0100 Subject: clk: Change clk_ops->determine_rate to return a clk_hw as the best parent This is in preparation for clock providers to not have to deal with struct clk. Signed-off-by: Tomeu Vizoso Reviewed-by: Stephen Boyd Signed-off-by: Michael Turquette --- Documentation/clk.txt | 2 +- arch/mips/alchemy/common/clock.c | 10 +++++----- drivers/clk/at91/clk-programmable.c | 4 ++-- drivers/clk/bcm/clk-kona.c | 4 ++-- drivers/clk/clk-composite.c | 9 +++++---- drivers/clk/clk.c | 17 +++++++++++------ drivers/clk/hisilicon/clk-hi3620.c | 2 +- drivers/clk/mmp/clk-mix.c | 4 ++-- drivers/clk/qcom/clk-pll.c | 2 +- drivers/clk/qcom/clk-rcg.c | 20 ++++++++++++-------- drivers/clk/qcom/clk-rcg2.c | 28 +++++++++++++++++----------- drivers/clk/sunxi/clk-factors.c | 4 ++-- drivers/clk/sunxi/clk-sun6i-ar100.c | 4 ++-- include/linux/clk-provider.h | 4 ++-- 14 files changed, 65 insertions(+), 49 deletions(-) (limited to 'Documentation') diff --git a/Documentation/clk.txt b/Documentation/clk.txt index 1fee72f4d331..4ff84623d5e1 100644 --- a/Documentation/clk.txt +++ b/Documentation/clk.txt @@ -74,7 +74,7 @@ the operations defined in clk.h: long (*determine_rate)(struct clk_hw *hw, unsigned long rate, unsigned long *best_parent_rate, - struct clk **best_parent_clk); + struct clk_hw **best_parent_clk); int (*set_parent)(struct clk_hw *hw, u8 index); u8 (*get_parent)(struct clk_hw *hw); int (*set_rate)(struct clk_hw *hw, diff --git a/arch/mips/alchemy/common/clock.c b/arch/mips/alchemy/common/clock.c index d7557cde271a..f42dd0a4af20 100644 --- a/arch/mips/alchemy/common/clock.c +++ b/arch/mips/alchemy/common/clock.c @@ -375,7 +375,7 @@ static long alchemy_calc_div(unsigned long rate, unsigned long prate, static long alchemy_clk_fgcs_detr(struct clk_hw *hw, unsigned long rate, unsigned long *best_parent_rate, - struct clk **best_parent_clk, + struct clk_hw **best_parent_clk, int scale, int maxdiv) { struct clk *pc, *bpc, *free; @@ -454,7 +454,7 @@ static long alchemy_clk_fgcs_detr(struct clk_hw *hw, unsigned long rate, } *best_parent_rate = bpr; - *best_parent_clk = bpc; + *best_parent_clk = __clk_get_hw(bpc); return br; } @@ -548,7 +548,7 @@ static unsigned long alchemy_clk_fgv1_recalc(struct clk_hw *hw, static long alchemy_clk_fgv1_detr(struct clk_hw *hw, unsigned long rate, unsigned long *best_parent_rate, - struct clk **best_parent_clk) + struct clk_hw **best_parent_clk) { return alchemy_clk_fgcs_detr(hw, rate, best_parent_rate, best_parent_clk, 2, 512); @@ -680,7 +680,7 @@ static unsigned long alchemy_clk_fgv2_recalc(struct clk_hw *hw, static long alchemy_clk_fgv2_detr(struct clk_hw *hw, unsigned long rate, unsigned long *best_parent_rate, - struct clk **best_parent_clk) + struct clk_hw **best_parent_clk) { struct alchemy_fgcs_clk *c = to_fgcs_clk(hw); int scale, maxdiv; @@ -899,7 +899,7 @@ static int alchemy_clk_csrc_setr(struct clk_hw *hw, unsigned long rate, static long alchemy_clk_csrc_detr(struct clk_hw *hw, unsigned long rate, unsigned long *best_parent_rate, - struct clk **best_parent_clk) + struct clk_hw **best_parent_clk) { struct alchemy_fgcs_clk *c = to_fgcs_clk(hw); int scale = c->dt[2] == 3 ? 1 : 2; /* au1300 check */ diff --git a/drivers/clk/at91/clk-programmable.c b/drivers/clk/at91/clk-programmable.c index 62e2509f9df1..bbdb1b985c91 100644 --- a/drivers/clk/at91/clk-programmable.c +++ b/drivers/clk/at91/clk-programmable.c @@ -57,7 +57,7 @@ static unsigned long clk_programmable_recalc_rate(struct clk_hw *hw, static long clk_programmable_determine_rate(struct clk_hw *hw, unsigned long rate, unsigned long *best_parent_rate, - struct clk **best_parent_clk) + struct clk_hw **best_parent_hw) { struct clk *parent = NULL; long best_rate = -EINVAL; @@ -84,7 +84,7 @@ static long clk_programmable_determine_rate(struct clk_hw *hw, if (best_rate < 0 || (rate - tmp_rate) < (rate - best_rate)) { best_rate = tmp_rate; *best_parent_rate = parent_rate; - *best_parent_clk = parent; + *best_parent_hw = __clk_get_hw(parent); } if (!best_rate) diff --git a/drivers/clk/bcm/clk-kona.c b/drivers/clk/bcm/clk-kona.c index 95af2e665dd3..1c06f6f3a8c5 100644 --- a/drivers/clk/bcm/clk-kona.c +++ b/drivers/clk/bcm/clk-kona.c @@ -1032,7 +1032,7 @@ static long kona_peri_clk_round_rate(struct clk_hw *hw, unsigned long rate, } static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *best_parent_rate, struct clk **best_parent) + unsigned long *best_parent_rate, struct clk_hw **best_parent) { struct kona_clk *bcm_clk = to_kona_clk(hw); struct clk *clk = hw->clk; @@ -1075,7 +1075,7 @@ static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate, if (delta < best_delta) { best_delta = delta; best_rate = other_rate; - *best_parent = parent; + *best_parent = __clk_get_hw(parent); *best_parent_rate = parent_rate; } } diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c index b9355daf8065..4386697236a7 100644 --- a/drivers/clk/clk-composite.c +++ b/drivers/clk/clk-composite.c @@ -57,7 +57,7 @@ static unsigned long clk_composite_recalc_rate(struct clk_hw *hw, static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate, unsigned long *best_parent_rate, - struct clk **best_parent_p) + struct clk_hw **best_parent_p) { struct clk_composite *composite = to_clk_composite(hw); const struct clk_ops *rate_ops = composite->rate_ops; @@ -80,8 +80,9 @@ static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate, *best_parent_p = NULL; if (__clk_get_flags(hw->clk) & CLK_SET_RATE_NO_REPARENT) { - *best_parent_p = clk_get_parent(mux_hw->clk); - *best_parent_rate = __clk_get_rate(*best_parent_p); + parent = clk_get_parent(mux_hw->clk); + *best_parent_p = __clk_get_hw(parent); + *best_parent_rate = __clk_get_rate(parent); return rate_ops->round_rate(rate_hw, rate, best_parent_rate); @@ -103,7 +104,7 @@ static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate, if (!rate_diff || !*best_parent_p || best_rate_diff > rate_diff) { - *best_parent_p = parent; + *best_parent_p = __clk_get_hw(parent); *best_parent_rate = parent_rate; best_rate_diff = rate_diff; best_rate = tmp_rate; diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index f549e8b1d5ed..44cdc47a6cc5 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -702,7 +702,7 @@ struct clk *__clk_lookup(const char *name) */ long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate, unsigned long *best_parent_rate, - struct clk **best_parent_p) + struct clk_hw **best_parent_p) { struct clk *clk = hw->clk, *parent, *best_parent = NULL; int i, num_parents; @@ -738,7 +738,7 @@ long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate, out: if (best_parent) - *best_parent_p = best_parent; + *best_parent_p = best_parent->hw; *best_parent_rate = best; return best; @@ -946,6 +946,7 @@ unsigned long __clk_round_rate(struct clk *clk, unsigned long rate) { unsigned long parent_rate = 0; struct clk *parent; + struct clk_hw *parent_hw; if (!clk) return 0; @@ -954,10 +955,11 @@ unsigned long __clk_round_rate(struct clk *clk, unsigned long rate) if (parent) parent_rate = parent->rate; - if (clk->ops->determine_rate) + if (clk->ops->determine_rate) { + parent_hw = parent ? parent->hw : NULL; return clk->ops->determine_rate(clk->hw, rate, &parent_rate, - &parent); - else if (clk->ops->round_rate) + &parent_hw); + } else if (clk->ops->round_rate) return clk->ops->round_rate(clk->hw, rate, &parent_rate); else if (clk->flags & CLK_SET_RATE_PARENT) return __clk_round_rate(clk->parent, rate); @@ -1345,6 +1347,7 @@ static struct clk *clk_calc_new_rates(struct clk *clk, unsigned long rate) { struct clk *top = clk; struct clk *old_parent, *parent; + struct clk_hw *parent_hw; unsigned long best_parent_rate = 0; unsigned long new_rate; int p_index = 0; @@ -1360,9 +1363,11 @@ static struct clk *clk_calc_new_rates(struct clk *clk, unsigned long rate) /* find the closest rate and parent clk/rate */ if (clk->ops->determine_rate) { + parent_hw = parent ? parent->hw : NULL; new_rate = clk->ops->determine_rate(clk->hw, rate, &best_parent_rate, - &parent); + &parent_hw); + parent = parent_hw->clk; } else if (clk->ops->round_rate) { new_rate = clk->ops->round_rate(clk->hw, rate, &best_parent_rate); diff --git a/drivers/clk/hisilicon/clk-hi3620.c b/drivers/clk/hisilicon/clk-hi3620.c index 640ea3327c3e..007144f81f50 100644 --- a/drivers/clk/hisilicon/clk-hi3620.c +++ b/drivers/clk/hisilicon/clk-hi3620.c @@ -296,7 +296,7 @@ static unsigned long mmc_clk_recalc_rate(struct clk_hw *hw, static long mmc_clk_determine_rate(struct clk_hw *hw, unsigned long rate, unsigned long *best_parent_rate, - struct clk **best_parent_p) + struct clk_hw **best_parent_p) { struct clk_mmc *mclk = to_mmc(hw); unsigned long best = 0; diff --git a/drivers/clk/mmp/clk-mix.c b/drivers/clk/mmp/clk-mix.c index b79742c47d53..48fa53c7ce5e 100644 --- a/drivers/clk/mmp/clk-mix.c +++ b/drivers/clk/mmp/clk-mix.c @@ -203,7 +203,7 @@ error: static long mmp_clk_mix_determine_rate(struct clk_hw *hw, unsigned long rate, unsigned long *best_parent_rate, - struct clk **best_parent_clk) + struct clk_hw **best_parent_clk) { struct mmp_clk_mix *mix = to_clk_mix(hw); struct mmp_clk_mix_clk_table *item; @@ -264,7 +264,7 @@ static long mmp_clk_mix_determine_rate(struct clk_hw *hw, unsigned long rate, found: *best_parent_rate = parent_rate_best; - *best_parent_clk = parent_best; + *best_parent_clk = __clk_get_hw(parent_best); return mix_rate_best; } diff --git a/drivers/clk/qcom/clk-pll.c b/drivers/clk/qcom/clk-pll.c index b823bc3b6250..60873a7f45d9 100644 --- a/drivers/clk/qcom/clk-pll.c +++ b/drivers/clk/qcom/clk-pll.c @@ -141,7 +141,7 @@ struct pll_freq_tbl *find_freq(const struct pll_freq_tbl *f, unsigned long rate) static long clk_pll_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *p_rate, struct clk **p) + unsigned long *p_rate, struct clk_hw **p) { struct clk_pll *pll = to_clk_pll(hw); const struct pll_freq_tbl *f; diff --git a/drivers/clk/qcom/clk-rcg.c b/drivers/clk/qcom/clk-rcg.c index b6e6959e89aa..0b93972c8807 100644 --- a/drivers/clk/qcom/clk-rcg.c +++ b/drivers/clk/qcom/clk-rcg.c @@ -368,16 +368,17 @@ clk_dyn_rcg_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) static long _freq_tbl_determine_rate(struct clk_hw *hw, const struct freq_tbl *f, unsigned long rate, - unsigned long *p_rate, struct clk **p) + unsigned long *p_rate, struct clk_hw **p_hw) { unsigned long clk_flags; + struct clk *p; f = qcom_find_freq(f, rate); if (!f) return -EINVAL; clk_flags = __clk_get_flags(hw->clk); - *p = clk_get_parent_by_index(hw->clk, f->src); + p = clk_get_parent_by_index(hw->clk, f->src); if (clk_flags & CLK_SET_RATE_PARENT) { rate = rate * f->pre_div; if (f->n) { @@ -387,15 +388,16 @@ static long _freq_tbl_determine_rate(struct clk_hw *hw, rate = tmp; } } else { - rate = __clk_get_rate(*p); + rate = __clk_get_rate(p); } + *p_hw = __clk_get_hw(p); *p_rate = rate; return f->freq; } static long clk_rcg_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *p_rate, struct clk **p) + unsigned long *p_rate, struct clk_hw **p) { struct clk_rcg *rcg = to_clk_rcg(hw); @@ -403,7 +405,7 @@ static long clk_rcg_determine_rate(struct clk_hw *hw, unsigned long rate, } static long clk_dyn_rcg_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *p_rate, struct clk **p) + unsigned long *p_rate, struct clk_hw **p) { struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw); @@ -411,13 +413,15 @@ static long clk_dyn_rcg_determine_rate(struct clk_hw *hw, unsigned long rate, } static long clk_rcg_bypass_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *p_rate, struct clk **p) + unsigned long *p_rate, struct clk_hw **p_hw) { struct clk_rcg *rcg = to_clk_rcg(hw); const struct freq_tbl *f = rcg->freq_tbl; + struct clk *p; - *p = clk_get_parent_by_index(hw->clk, f->src); - *p_rate = __clk_round_rate(*p, rate); + p = clk_get_parent_by_index(hw->clk, f->src); + *p_hw = __clk_get_hw(p); + *p_rate = __clk_round_rate(p, rate); return *p_rate; } diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index cfa9eb4fe9ca..08b8b3729f53 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -175,16 +175,17 @@ clk_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) static long _freq_tbl_determine_rate(struct clk_hw *hw, const struct freq_tbl *f, unsigned long rate, - unsigned long *p_rate, struct clk **p) + unsigned long *p_rate, struct clk_hw **p_hw) { unsigned long clk_flags; + struct clk *p; f = qcom_find_freq(f, rate); if (!f) return -EINVAL; clk_flags = __clk_get_flags(hw->clk); - *p = clk_get_parent_by_index(hw->clk, f->src); + p = clk_get_parent_by_index(hw->clk, f->src); if (clk_flags & CLK_SET_RATE_PARENT) { if (f->pre_div) { rate /= 2; @@ -198,15 +199,16 @@ static long _freq_tbl_determine_rate(struct clk_hw *hw, rate = tmp; } } else { - rate = __clk_get_rate(*p); + rate = __clk_get_rate(p); } + *p_hw = __clk_get_hw(p); *p_rate = rate; return f->freq; } static long clk_rcg2_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *p_rate, struct clk **p) + unsigned long *p_rate, struct clk_hw **p) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); @@ -359,7 +361,7 @@ static int clk_edp_pixel_set_rate_and_parent(struct clk_hw *hw, } static long clk_edp_pixel_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *p_rate, struct clk **p) + unsigned long *p_rate, struct clk_hw **p) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); const struct freq_tbl *f = rcg->freq_tbl; @@ -371,7 +373,7 @@ static long clk_edp_pixel_determine_rate(struct clk_hw *hw, unsigned long rate, u32 hid_div; /* Force the correct parent */ - *p = clk_get_parent_by_index(hw->clk, f->src); + *p = __clk_get_hw(clk_get_parent_by_index(hw->clk, f->src)); if (src_rate == 810000000) frac = frac_table_810m; @@ -410,18 +412,20 @@ const struct clk_ops clk_edp_pixel_ops = { EXPORT_SYMBOL_GPL(clk_edp_pixel_ops); static long clk_byte_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *p_rate, struct clk **p) + unsigned long *p_rate, struct clk_hw **p_hw) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); const struct freq_tbl *f = rcg->freq_tbl; unsigned long parent_rate, div; u32 mask = BIT(rcg->hid_width) - 1; + struct clk *p; if (rate == 0) return -EINVAL; - *p = clk_get_parent_by_index(hw->clk, f->src); - *p_rate = parent_rate = __clk_round_rate(*p, rate); + p = clk_get_parent_by_index(hw->clk, f->src); + *p_hw = __clk_get_hw(p); + *p_rate = parent_rate = __clk_round_rate(p, rate); div = DIV_ROUND_UP((2 * parent_rate), rate) - 1; div = min_t(u32, div, mask); @@ -472,14 +476,16 @@ static const struct frac_entry frac_table_pixel[] = { }; static long clk_pixel_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *p_rate, struct clk **p) + unsigned long *p_rate, struct clk_hw **p) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); unsigned long request, src_rate; int delta = 100000; const struct freq_tbl *f = rcg->freq_tbl; const struct frac_entry *frac = frac_table_pixel; - struct clk *parent = *p = clk_get_parent_by_index(hw->clk, f->src); + struct clk *parent = clk_get_parent_by_index(hw->clk, f->src); + + *p = __clk_get_hw(parent); for (; frac->num; frac++) { request = (rate * frac->den) / frac->num; diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c index 5521e866fa5e..62e08fb58554 100644 --- a/drivers/clk/sunxi/clk-factors.c +++ b/drivers/clk/sunxi/clk-factors.c @@ -81,7 +81,7 @@ static long clk_factors_round_rate(struct clk_hw *hw, unsigned long rate, static long clk_factors_determine_rate(struct clk_hw *hw, unsigned long rate, unsigned long *best_parent_rate, - struct clk **best_parent_p) + struct clk_hw **best_parent_p) { struct clk *clk = hw->clk, *parent, *best_parent = NULL; int i, num_parents; @@ -108,7 +108,7 @@ static long clk_factors_determine_rate(struct clk_hw *hw, unsigned long rate, } if (best_parent) - *best_parent_p = best_parent; + *best_parent_p = __clk_get_hw(best_parent); *best_parent_rate = best; return best_child_rate; diff --git a/drivers/clk/sunxi/clk-sun6i-ar100.c b/drivers/clk/sunxi/clk-sun6i-ar100.c index acca53290be2..3d282fb8f85c 100644 --- a/drivers/clk/sunxi/clk-sun6i-ar100.c +++ b/drivers/clk/sunxi/clk-sun6i-ar100.c @@ -46,7 +46,7 @@ static unsigned long ar100_recalc_rate(struct clk_hw *hw, static long ar100_determine_rate(struct clk_hw *hw, unsigned long rate, unsigned long *best_parent_rate, - struct clk **best_parent_clk) + struct clk_hw **best_parent_clk) { int nparents = __clk_get_num_parents(hw->clk); long best_rate = -EINVAL; @@ -100,7 +100,7 @@ static long ar100_determine_rate(struct clk_hw *hw, unsigned long rate, tmp_rate = (parent_rate >> shift) / div; if (!*best_parent_clk || tmp_rate > best_rate) { - *best_parent_clk = parent; + *best_parent_clk = __clk_get_hw(parent); *best_parent_rate = parent_rate; best_rate = tmp_rate; } diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 5e06f23eed41..d936409520f8 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -176,7 +176,7 @@ struct clk_ops { unsigned long *parent_rate); long (*determine_rate)(struct clk_hw *hw, unsigned long rate, unsigned long *best_parent_rate, - struct clk **best_parent_clk); + struct clk_hw **best_parent_hw); int (*set_parent)(struct clk_hw *hw, u8 index); u8 (*get_parent)(struct clk_hw *hw); int (*set_rate)(struct clk_hw *hw, unsigned long rate, @@ -551,7 +551,7 @@ bool __clk_is_enabled(struct clk *clk); struct clk *__clk_lookup(const char *name); long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate, unsigned long *best_parent_rate, - struct clk **best_parent_p); + struct clk_hw **best_parent_p); /* * FIXME clock api without lock protection -- cgit v1.2.3-59-g8ed1b From e2beb6cd5d0f6f0f6e71fe200a674932194a8e84 Mon Sep 17 00:00:00 2001 From: Sean Paul Date: Wed, 3 Dec 2014 11:57:40 -0800 Subject: drm/Documentation: Fix rowspan value in drm-kms-properties The "DRM" rowspan wasn't updated in commit cc7096fb6d1d (drm/mode: document path property and function to set it. (v1.1)), so increment it by one to fix the table. Cc: Dave Airlie Signed-off-by: Sean Paul Signed-off-by: Daniel Vetter --- 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 3789f2db3c21..b344bc3b0d77 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -2546,7 +2546,7 @@ void intel_crt_init(struct drm_device *dev) Description/Restrictions - DRM + DRM Generic “EDID” BLOB | IMMUTABLE -- cgit v1.2.3-59-g8ed1b From 6936d74fb511b2d75720d6c15e8296d65988aaa2 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 15 Oct 2014 10:08:19 -0300 Subject: [media] v4l: Clean up sub-device format documentation The sub-device format documentation documented scaling configuration through formats. Instead the compose selection rectangle is elsewhere documented to be used for the purpose. Remove scaling related part of the documentation. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/dev-subdev.xml | 109 ++++++++++++++----------- 1 file changed, 63 insertions(+), 46 deletions(-) (limited to 'Documentation') diff --git a/Documentation/DocBook/media/v4l/dev-subdev.xml b/Documentation/DocBook/media/v4l/dev-subdev.xml index d15aaf83f56f..4f0ba58c9bd9 100644 --- a/Documentation/DocBook/media/v4l/dev-subdev.xml +++ b/Documentation/DocBook/media/v4l/dev-subdev.xml @@ -195,53 +195,59 @@ Sample Pipeline Configuration - - - - - + + + + + + - Sensor/0 - Frontend/0 - Frontend/1 - Scaler/0 - Scaler/1 + Sensor/0 format + Frontend/0 format + Frontend/1 format + Scaler/0 format + Scaler/0 compose selection rectangle + Scaler/1 format Initial state - 2048x1536 - - - - - - - - + 2048x1536/SGRBG8_1X8 + (default) + (default) + (default) + (default) + (default) - Configure frontend input - 2048x1536 - 2048x1536 - 2046x1534 - - - - + Configure frontend sink format + 2048x1536/SGRBG8_1X8 + 2048x1536/SGRBG8_1X8 + 2046x1534/SGRBG8_1X8 + (default) + (default) + (default) - Configure scaler input - 2048x1536 - 2048x1536 - 2046x1534 - 2046x1534 - 2046x1534 + Configure scaler sink format + 2048x1536/SGRBG8_1X8 + 2048x1536/SGRBG8_1X8 + 2046x1534/SGRBG8_1X8 + 2046x1534/SGRBG8_1X8 + 0,0/2046x1534 + 2046x1534/SGRBG8_1X8 - Configure scaler output - 2048x1536 - 2048x1536 - 2046x1534 - 2046x1534 - 1280x960 + Configure scaler sink compose selection + 2048x1536/SGRBG8_1X8 + 2048x1536/SGRBG8_1X8 + 2046x1534/SGRBG8_1X8 + 2046x1534/SGRBG8_1X8 + 0,0/1280x960 + 1280x960/SGRBG8_1X8 @@ -249,19 +255,30 @@ - Initial state. The sensor output is set to its native 3MP - resolution. Resolutions on the host frontend and scaler input and output - pads are undefined. - The application configures the frontend input pad resolution to - 2048x1536. The driver propagates the format to the frontend output pad. - Note that the propagated output format can be different, as in this case, - than the input format, as the hardware might need to crop pixels (for - instance when converting a Bayer filter pattern to RGB or YUV). - The application configures the scaler input pad resolution to - 2046x1534 to match the frontend output resolution. The driver propagates - the format to the scaler output pad. - The application configures the scaler output pad resolution to - 1280x960. + Initial state. The sensor source pad format is + set to its native 3MP size and V4L2_MBUS_FMT_SGRBG8_1X8 + media bus code. Formats on the host frontend and scaler sink + and source pads have the default values, as well as the + compose rectangle on the scaler's sink pad. + + The application configures the frontend sink + pad format's size to 2048x1536 and its media bus code to + V4L2_MBUS_FMT_SGRBG_1X8. The driver propagates the format to + the frontend source pad. + + The application configures the scaler sink pad + format's size to 2046x1534 and the media bus code to + V4L2_MBUS_FMT_SGRBG_1X8 to match the frontend source size and + media bus code. The media bus code on the sink pad is set to + V4L2_MBUS_FMT_SGRBG_1X8. The driver propagates the size to the + compose selection rectangle on the scaler's sink pad, and the + format to the scaler source pad. + + The application configures the size of the compose + selection rectangle of the scaler's sink pad 1280x960. The driver + propagates the size to the scaler's source pad + format. + -- cgit v1.2.3-59-g8ed1b From 0b4bc768dc289731983ba5223555ffabe08eefdd Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 15 Oct 2014 13:38:15 -0300 Subject: [media] v4l: Add V4L2_SEL_TGT_NATIVE_SIZE selection target The V4L2_SEL_TGT_NATIVE_SIZE target is used to denote e.g. the size of a sensor's pixel array. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/selections-common.xml | 16 ++++++++++++++++ include/uapi/linux/v4l2-common.h | 2 ++ 2 files changed, 18 insertions(+) (limited to 'Documentation') diff --git a/Documentation/DocBook/media/v4l/selections-common.xml b/Documentation/DocBook/media/v4l/selections-common.xml index 7502f784b8cc..d6d56fb6f9c0 100644 --- a/Documentation/DocBook/media/v4l/selections-common.xml +++ b/Documentation/DocBook/media/v4l/selections-common.xml @@ -62,6 +62,22 @@ Yes Yes + + V4L2_SEL_TGT_NATIVE_SIZE + 0x0003 + The native size of the device, e.g. a sensor's + pixel array. left and + top fields are zero for this + target. Setting the native size will generally only make + sense for memory to memory devices where the software can + create a canvas of a given size in which for example a + video frame can be composed. In that case + V4L2_SEL_TGT_NATIVE_SIZE can be used to configure the size + of that canvas. + + Yes + Yes + V4L2_SEL_TGT_COMPOSE 0x0100 diff --git a/include/uapi/linux/v4l2-common.h b/include/uapi/linux/v4l2-common.h index 2f6f8cafe773..15273987093e 100644 --- a/include/uapi/linux/v4l2-common.h +++ b/include/uapi/linux/v4l2-common.h @@ -43,6 +43,8 @@ #define V4L2_SEL_TGT_CROP_DEFAULT 0x0001 /* Cropping bounds */ #define V4L2_SEL_TGT_CROP_BOUNDS 0x0002 +/* Native frame size */ +#define V4L2_SEL_TGT_NATIVE_SIZE 0x0003 /* Current composing area */ #define V4L2_SEL_TGT_COMPOSE 0x0100 /* Default composing area */ -- cgit v1.2.3-59-g8ed1b From 8af0345926c8cdbbf80102aa3eab8a6519c23272 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 18 Nov 2014 02:27:00 -0300 Subject: [media] v4l: Add input and output capability flags for native size setting Add input and output capability flags for setting native size of the device, and document them. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/vidioc-enuminput.xml | 8 ++++++++ Documentation/DocBook/media/v4l/vidioc-enumoutput.xml | 8 ++++++++ include/uapi/linux/videodev2.h | 2 ++ 3 files changed, 18 insertions(+) (limited to 'Documentation') diff --git a/Documentation/DocBook/media/v4l/vidioc-enuminput.xml b/Documentation/DocBook/media/v4l/vidioc-enuminput.xml index 493a39a8ef21..603fecef9083 100644 --- a/Documentation/DocBook/media/v4l/vidioc-enuminput.xml +++ b/Documentation/DocBook/media/v4l/vidioc-enuminput.xml @@ -287,6 +287,14 @@ input/output interface to linux-media@vger.kernel.org on 19 Oct 2009. 0x00000004 This input supports setting the TV standard by using VIDIOC_S_STD. + + V4L2_IN_CAP_NATIVE_SIZE + 0x00000008 + This input supports setting the native size using + the V4L2_SEL_TGT_NATIVE_SIZE + selection target, see . + diff --git a/Documentation/DocBook/media/v4l/vidioc-enumoutput.xml b/Documentation/DocBook/media/v4l/vidioc-enumoutput.xml index 2654e097df39..773fb1258c24 100644 --- a/Documentation/DocBook/media/v4l/vidioc-enumoutput.xml +++ b/Documentation/DocBook/media/v4l/vidioc-enumoutput.xml @@ -172,6 +172,14 @@ input/output interface to linux-media@vger.kernel.org on 19 Oct 2009. 0x00000004 This output supports setting the TV standard by using VIDIOC_S_STD. + + V4L2_OUT_CAP_NATIVE_SIZE + 0x00000008 + This output supports setting the native size using + the V4L2_SEL_TGT_NATIVE_SIZE + selection target, see . + diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index ced659e1b9f6..d279c1b75cf7 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -1324,6 +1324,7 @@ struct v4l2_input { #define V4L2_IN_CAP_DV_TIMINGS 0x00000002 /* Supports S_DV_TIMINGS */ #define V4L2_IN_CAP_CUSTOM_TIMINGS V4L2_IN_CAP_DV_TIMINGS /* For compatibility */ #define V4L2_IN_CAP_STD 0x00000004 /* Supports S_STD */ +#define V4L2_IN_CAP_NATIVE_SIZE 0x00000008 /* Supports setting native size */ /* * V I D E O O U T P U T S @@ -1347,6 +1348,7 @@ struct v4l2_output { #define V4L2_OUT_CAP_DV_TIMINGS 0x00000002 /* Supports S_DV_TIMINGS */ #define V4L2_OUT_CAP_CUSTOM_TIMINGS V4L2_OUT_CAP_DV_TIMINGS /* For compatibility */ #define V4L2_OUT_CAP_STD 0x00000004 /* Supports S_STD */ +#define V4L2_OUT_CAP_NATIVE_SIZE 0x00000008 /* Supports setting native size */ /* * C O N T R O L S -- cgit v1.2.3-59-g8ed1b From 5f835cef770fc71263ace29198a9e6743033a705 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 30 Nov 2014 17:52:31 +0100 Subject: Documentation: i2c: Use PM ops instead of legacy suspend/resume New drivers should use PM ops instead of the legacy suspend/resume callbacks. Update the I2C device driver guides to reflect this. Signed-off-by: Lars-Peter Clausen Signed-off-by: Wolfram Sang --- Documentation/i2c/upgrading-clients | 6 ++---- Documentation/i2c/writing-clients | 8 ++++---- 2 files changed, 6 insertions(+), 8 deletions(-) (limited to 'Documentation') diff --git a/Documentation/i2c/upgrading-clients b/Documentation/i2c/upgrading-clients index 8e5fbd88c7d1..ccba3ffd6e80 100644 --- a/Documentation/i2c/upgrading-clients +++ b/Documentation/i2c/upgrading-clients @@ -79,11 +79,10 @@ static struct i2c_driver example_driver = { .driver = { .owner = THIS_MODULE, .name = "example", + .pm = &example_pm_ops, }, .attach_adapter = example_attach_adapter, .detach_client = example_detach, - .suspend = example_suspend, - .resume = example_resume, }; @@ -272,10 +271,9 @@ static struct i2c_driver example_driver = { .driver = { .owner = THIS_MODULE, .name = "example", + .pm = &example_pm_ops, }, .id_table = example_idtable, .probe = example_probe, .remove = example_remove, - .suspend = example_suspend, - .resume = example_resume, }; diff --git a/Documentation/i2c/writing-clients b/Documentation/i2c/writing-clients index 6b344b516bff..a755b141fa4a 100644 --- a/Documentation/i2c/writing-clients +++ b/Documentation/i2c/writing-clients @@ -36,6 +36,7 @@ MODULE_DEVICE_TABLE(i2c, foo_idtable); static struct i2c_driver foo_driver = { .driver = { .name = "foo", + .pm = &foo_pm_ops, /* optional */ }, .id_table = foo_idtable, @@ -47,8 +48,6 @@ static struct i2c_driver foo_driver = { .address_list = normal_i2c, .shutdown = foo_shutdown, /* optional */ - .suspend = foo_suspend, /* optional */ - .resume = foo_resume, /* optional */ .command = foo_command, /* optional, deprecated */ } @@ -279,8 +278,9 @@ Power Management If your I2C device needs special handling when entering a system low power state -- like putting a transceiver into a low power mode, or -activating a system wakeup mechanism -- do that in the suspend() method. -The resume() method should reverse what the suspend() method does. +activating a system wakeup mechanism -- do that by implementing the +appropriate callbacks for the dev_pm_ops of the driver (like suspend +and resume). These are standard driver model calls, and they work just like they would for any other driver stack. The calls can sleep, and can use -- cgit v1.2.3-59-g8ed1b From 06adbaec2a7a3d04741557b411e264c7f9c91c85 Mon Sep 17 00:00:00 2001 From: Patrick Titiano Date: Thu, 4 Dec 2014 17:45:51 +0100 Subject: hwmon: (tmp401) Add support for TI TMP435 Signed-off-by: Patrick Titiano [Bartosz Golaszewski: prepared for submission, code review fixes] Signed-off-by: Bartosz Golaszewski [Guenter Roeck: Merged two patches into one] Signed-off-by: Guenter Roeck --- Documentation/hwmon/tmp401 | 8 ++++++-- drivers/hwmon/Kconfig | 2 +- drivers/hwmon/tmp401.c | 13 +++++++++++-- 3 files changed, 18 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/hwmon/tmp401 b/Documentation/hwmon/tmp401 index f91e3fa7e5ec..445ff7b0f6a7 100644 --- a/Documentation/hwmon/tmp401 +++ b/Documentation/hwmon/tmp401 @@ -18,6 +18,10 @@ Supported chips: Prefix: 'tmp432' Addresses scanned: I2C 0x4c, 0x4d Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp432.html + * Texas Instruments TMP435 + Prefix: 'tmp435' + Addresses scanned: I2C 0x4c + Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp435.html Authors: Hans de Goede @@ -27,8 +31,8 @@ Description ----------- This driver implements support for Texas Instruments TMP401, TMP411, -TMP431, and TMP432 chips. These chips implement one or two remote and -one local temperature sensors. Temperature is measured in degrees +TMP431, TMP432 and TMP435 chips. These chips implement one or two remote +and one local temperature sensors. Temperature is measured in degrees Celsius. Resolution of the remote sensor is 0.0625 degree. Local sensor resolution can be set to 0.5, 0.25, 0.125 or 0.0625 degree (not supported by the driver so far, so using the default resolution of 0.5 diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index b1ce6a093a93..6529c09c46f0 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1466,7 +1466,7 @@ config SENSORS_TMP401 depends on I2C help If you say yes here you get support for Texas Instruments TMP401, - TMP411, TMP431, and TMP432 temperature sensor chips. + TMP411, TMP431, TMP432 and TMP435 temperature sensor chips. This driver can also be built as a module. If so, the module will be called tmp401. diff --git a/drivers/hwmon/tmp401.c b/drivers/hwmon/tmp401.c index 7fa6e7d0b9b6..ccd993880d74 100644 --- a/drivers/hwmon/tmp401.c +++ b/drivers/hwmon/tmp401.c @@ -46,7 +46,7 @@ /* Addresses to scan */ static const unsigned short normal_i2c[] = { 0x4c, 0x4d, 0x4e, I2C_CLIENT_END }; -enum chips { tmp401, tmp411, tmp431, tmp432 }; +enum chips { tmp401, tmp411, tmp431, tmp432, tmp435 }; /* * The TMP401 registers, note some registers have different addresses for @@ -136,6 +136,7 @@ static const u8 TMP432_STATUS_REG[] = { #define TMP411C_DEVICE_ID 0x10 #define TMP431_DEVICE_ID 0x31 #define TMP432_DEVICE_ID 0x32 +#define TMP435_DEVICE_ID 0x35 /* * Driver data (common to all clients) @@ -146,6 +147,7 @@ static const struct i2c_device_id tmp401_id[] = { { "tmp411", tmp411 }, { "tmp431", tmp431 }, { "tmp432", tmp432 }, + { "tmp435", tmp435 }, { } }; MODULE_DEVICE_TABLE(i2c, tmp401_id); @@ -684,6 +686,11 @@ static int tmp401_detect(struct i2c_client *client, return -ENODEV; kind = tmp432; break; + case TMP435_DEVICE_ID: + if (client->addr != 0x4c) + return -ENODEV; + kind = tmp435; + break; default: return -ENODEV; } @@ -705,7 +712,9 @@ static int tmp401_detect(struct i2c_client *client, static int tmp401_probe(struct i2c_client *client, const struct i2c_device_id *id) { - const char *names[] = { "TMP401", "TMP411", "TMP431", "TMP432" }; + static const char * const names[] = { + "TMP401", "TMP411", "TMP431", "TMP432", "TMP435" + }; struct device *dev = &client->dev; struct device *hwmon_dev; struct tmp401_data *data; -- cgit v1.2.3-59-g8ed1b From 65b5732d241b8b39e07653794eefffd0d8028cbb Mon Sep 17 00:00:00 2001 From: Doug Anderson Date: Wed, 8 Oct 2014 00:33:47 -0700 Subject: clocksource: arch_timer: Allow the device tree to specify uninitialized timer registers Some 32-bit (ARMv7) systems are architected like this: * The firmware doesn't know and doesn't care about hypervisor mode and we don't want to add the complexity of hypervisor there. * The firmware isn't involved in SMP bringup or resume. * The ARCH timer come up with an uninitialized offset (CNTVOFF) between the virtual and physical counters. Each core gets a different random offset. * The device boots in "Secure SVC" mode. * Nothing has touched the reset value of CNTHCTL.PL1PCEN or CNTHCTL.PL1PCTEN (both default to 1 at reset) On systems like the above, it doesn't make sense to use the virtual counter. There's nobody managing the offset and each time a core goes down and comes back up it will get reinitialized to some other random value. This adds an optional property which can inform the kernel of this situation, and firmware is free to remove the property if it is going to initialize the CNTVOFF registers when each CPU comes out of reset. Currently, the best course of action in this case is to use the physical timer, which is why it is important that CNTHCTL hasn't been changed from its reset value and it's a reasonable assumption given that the firmware has never entered HYP mode. Note that it's been said that on ARMv8 systems the firmware and kernel really can't be architected as described above. That means using the physical timer like this really only makes sense for ARMv7 systems. Signed-off-by: Doug Anderson Signed-off-by: Sonny Rao Reviewed-by: Mark Rutland Acked-by: Daniel Lezcano Acked-by: Catalin Marinas Signed-off-by: Olof Johansson --- Documentation/devicetree/bindings/arm/arch_timer.txt | 8 ++++++++ drivers/clocksource/arm_arch_timer.c | 8 ++++++++ 2 files changed, 16 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/arch_timer.txt b/Documentation/devicetree/bindings/arm/arch_timer.txt index 37b2cafa4e52..256b4d8bab7b 100644 --- a/Documentation/devicetree/bindings/arm/arch_timer.txt +++ b/Documentation/devicetree/bindings/arm/arch_timer.txt @@ -22,6 +22,14 @@ to deliver its interrupts via SPIs. - always-on : a boolean property. If present, the timer is powered through an always-on power domain, therefore it never loses context. +** Optional properties: + +- arm,cpu-registers-not-fw-configured : Firmware does not initialize + any of the generic timer CPU registers, which contain their + architecturally-defined reset values. Only supported for 32-bit + systems which follow the ARMv7 architected reset values. + + Example: timer { diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 55256e4fb641..6967cb026b9e 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -704,6 +704,14 @@ static void __init arch_timer_init(struct device_node *np) arch_timer_ppi[i] = irq_of_parse_and_map(np, i); arch_timer_detect_rate(NULL, np); + /* + * If we cannot rely on firmware initializing the timer registers then + * we should use the physical timers instead. + */ + if (IS_ENABLED(CONFIG_ARM) && + of_property_read_bool(np, "arm,cpu-registers-not-fw-configured")) + arch_timer_use_virtual = false; + /* * If HYP mode is available, we know that the physical timer * has been configured to be accessible from PL1. Use it, so -- cgit v1.2.3-59-g8ed1b From d47fb4ec7e101a63754939fa49d75fd7e81e94f8 Mon Sep 17 00:00:00 2001 From: Ashutosh Dixit Date: Thu, 4 Dec 2014 13:27:29 -0800 Subject: Documentation: Build mic/mpssd only for x86_64 mic/mpssd along with MIC drivers are currently only usable on x86_64. So build mic/mpssd only for x86_64 to avoid build breaks on big-endian systems. Reported-by: Daniel Borkmann Reported-by: Dan Streetman Suggested-by: Peter Foley Signed-off-by: Ashutosh Dixit Signed-off-by: Jonathan Corbet --- Documentation/mic/mpssd/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/mic/mpssd/Makefile b/Documentation/mic/mpssd/Makefile index 0f3156888048..f47fe6ba7300 100644 --- a/Documentation/mic/mpssd/Makefile +++ b/Documentation/mic/mpssd/Makefile @@ -1,5 +1,5 @@ # List of programs to build -hostprogs-y := mpssd +hostprogs-$(CONFIG_X86_64) := mpssd mpssd-objs := mpssd.o sysfs.o -- cgit v1.2.3-59-g8ed1b From 5469b196507a72cba35aad9db657562d809fd383 Mon Sep 17 00:00:00 2001 From: Daniel Dressler Date: Mon, 10 Nov 2014 16:18:18 +0900 Subject: Input: xpad - update docs to reflect current state The last time this documentation was accurate was just over 8 years ago. In this time we've added support for two new generations of Xbox console controllers and dozens of third-party controllers. This patch unifies terminology and makes it explicit which model of controller a sentence refers to. It also expands certain sections to address the latest versions of Xbox controllers. Thus this documentation should now be useful to end users and not contain out-right untruths. This is the patch's second revision. Prior versions of this patch altered the driver's TODO list. That change has been pulled out of this documentation update patch. Signed-off-by: Daniel Dressler Signed-off-by: Jonathan Corbet --- Documentation/input/xpad.txt | 123 +++++++++++++++++++++++++++++-------------- 1 file changed, 83 insertions(+), 40 deletions(-) (limited to 'Documentation') diff --git a/Documentation/input/xpad.txt b/Documentation/input/xpad.txt index 7cc9a436e6a1..d1b23f295db4 100644 --- a/Documentation/input/xpad.txt +++ b/Documentation/input/xpad.txt @@ -1,18 +1,22 @@ -xpad - Linux USB driver for X-Box gamepads +xpad - Linux USB driver for Xbox compatible controllers -This is the very first release of a driver for X-Box gamepads. -Basically, this was hacked away in just a few hours, so don't expect -miracles. +This driver exposes all first-party and third-party Xbox compatible +controllers. It has a long history and has enjoyed considerable usage +as Window's xinput library caused most PC games to focus on Xbox +controller compatibility. -In particular, there is currently NO support for the rumble pack. -You won't find many ff-aware linux applications anyway. +Due to backwards compatibility all buttons are reported as digital. +This only effects Original Xbox controllers. All later controller models +have only digital face buttons. + +Rumble is supported on some models of Xbox 360 controllers but not of +Original Xbox controllers nor on Xbox One controllers. As of writing +the Xbox One's rumble protocol has not been reverse engineered but in +the future could be supported. 0. Notes -------- - -Driver updated for kernel 2.6.17.11. (Based on a patch for 2.6.11.4.) - The number of buttons/axes reported varies based on 3 things: - if you are using a known controller - if you are using a known dance pad @@ -20,12 +24,16 @@ The number of buttons/axes reported varies based on 3 things: module configuration for "Map D-PAD to buttons rather than axes for unknown pads" (module option dpad_to_buttons) -If you set dpad_to_buttons to 0 and you are using an unknown device (one -not listed below), the driver will map the directional pad to axes (X/Y), -if you said N it will map the d-pad to buttons, which is needed for dance -style games to function correctly. The default is Y. +If you set dpad_to_buttons to N and you are using an unknown device +the driver will map the directional pad to axes (X/Y). +If you said Y it will map the d-pad to buttons, which is needed for dance +style games to function correctly. The default is Y. + +dpad_to_buttons has no effect for known pads. A erroneous commit message +claimed dpad_to_buttons could be used to force behavior on known devices. +This is not true. Both dpad_to_buttons and triggers_to_buttons only affect +unknown controllers. -dpad_to_buttons has no effect for known pads. 0.1 Normal Controllers ---------------------- @@ -80,17 +88,29 @@ to the list of supported devices, ensuring that it will work out of the box in the future. -1. USB adapter +1. USB adapters -------------- +All generations of Xbox controllers speak USB over the wire. +- Original Xbox controllers use a proprietary connector and require adapters. +- Wireless Xbox 360 controllers require a 'Xbox 360 Wireless Gaming Receiver + for Windows' +- Wired Xbox 360 controllers use standard USB connectors. +- Xbox One controllers can be wireless but speak Wi-Fi Direct and are not + yet supported. +- Xbox One controllers can be wired and use standard Micro-USB connectors. + -Before you can actually use the driver, you need to get yourself an -adapter cable to connect the X-Box controller to your Linux-Box. You -can buy these online fairly cheap, or build your own. + +1.1 Original Xbox USB adapters +-------------- +Using this driver with an Original Xbox controller requires an +adapter cable to break out the proprietary connector's pins to USB. +You can buy these online fairly cheap, or build your own. Such a cable is pretty easy to build. The Controller itself is a USB compound device (a hub with three ports for two expansion slots and the controller device) with the only difference in a nonstandard connector -(5 pins vs. 4 on standard USB connector). +(5 pins vs. 4 on standard USB 1.0 connectors). You just need to solder a USB connector onto the cable and keep the yellow wire unconnected. The other pins have the same order on both @@ -102,26 +122,41 @@ original one. You can buy an extension cable and cut that instead. That way, you can still use the controller with your X-Box, if you have one ;) + 2. Driver Installation ---------------------- -Once you have the adapter cable and the controller is connected, you need -to load your USB subsystem and should cat /proc/bus/usb/devices. -There should be an entry like the one at the end [4]. +Once you have the adapter cable, if needed, and the controller connected +the xpad module should be auto loaded. To confirm you can cat +/proc/bus/usb/devices. There should be an entry like the one at the end [4]. + + -Currently (as of version 0.0.6), the following devices are included: - original Microsoft XBOX controller (US), vendor=0x045e, product=0x0202 - smaller Microsoft XBOX controller (US), vendor=0x045e, product=0x0289 +3. Supported Controllers +------------------------ +For a full list of supported controllers and associated vendor and product +IDs see the xpad_device[] array[6]. + +As of the historic version 0.0.6 (2006-10-10) the following devices +were supported: + original Microsoft XBOX controller (US), vendor=0x045e, product=0x0202 + smaller Microsoft XBOX controller (US), vendor=0x045e, product=0x0289 original Microsoft XBOX controller (Japan), vendor=0x045e, product=0x0285 - InterAct PowerPad Pro (Germany), vendor=0x05fd, product=0x107a - RedOctane Xbox Dance Pad (US), vendor=0x0c12, product=0x8809 + InterAct PowerPad Pro (Germany), vendor=0x05fd, product=0x107a + RedOctane Xbox Dance Pad (US), vendor=0x0c12, product=0x8809 + +Unrecognized models of Xbox controllers should function as Generic +Xbox controllers. Unrecognized Dance Pad controllers require setting +the module option 'dpad_to_buttons'. + +If you have an unrecognized controller please see 0.3 - Unknown Controllers -The driver should work with xbox pads not listed above as well, however -you will need to do something extra for dance pads to work. -If you have a controller not listed above, see 0.3 - Unknown Controllers +4. Manual Testing +----------------- +To test this driver's functionality you may use 'jstest'. -If you compiled and installed the driver, test the functionality: +For example: > modprobe xpad > modprobe joydev > jstest /dev/js0 @@ -134,7 +169,8 @@ show 20 inputs (6 axes, 14 buttons). It works? Voila, you're done ;) -3. Thanks + +5. Thanks --------- I have to thank ITO Takayuki for the detailed info on his site @@ -145,14 +181,14 @@ His useful info and both the usb-skeleton as well as the iforce input driver the basic functionality. -4. References -------------- -1. http://euc.jp/periphs/xbox-controller.ja.html (ITO Takayuki) -2. http://xpad.xbox-scene.com/ -3. http://www.markosweb.com/www/xboxhackz.com/ +6. References +------------- -4. /proc/bus/usb/devices - dump from InterAct PowerPad Pro (Germany): +[1]: http://euc.jp/periphs/xbox-controller.ja.html (ITO Takayuki) +[2]: http://xpad.xbox-scene.com/ +[3]: http://www.markosweb.com/www/xboxhackz.com/ +[4]: /proc/bus/usb/devices - dump from InterAct PowerPad Pro (Germany): T: Bus=01 Lev=03 Prnt=04 Port=00 Cnt=01 Dev#= 5 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=32 #Cfgs= 1 @@ -162,7 +198,7 @@ I: If#= 0 Alt= 0 #EPs= 2 Cls=58(unk. ) Sub=42 Prot=00 Driver=(none) E: Ad=81(I) Atr=03(Int.) MxPS= 32 Ivl= 10ms E: Ad=02(O) Atr=03(Int.) MxPS= 32 Ivl= 10ms -5. /proc/bus/usb/devices - dump from Redoctane Xbox Dance Pad (US): +[5]: /proc/bus/usb/devices - dump from Redoctane Xbox Dance Pad (US): T: Bus=01 Lev=02 Prnt=09 Port=00 Cnt=01 Dev#= 10 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1 @@ -173,7 +209,12 @@ I: If#= 0 Alt= 0 #EPs= 2 Cls=58(unk. ) Sub=42 Prot=00 Driver=xpad E: Ad=82(I) Atr=03(Int.) MxPS= 32 Ivl=4ms E: Ad=02(O) Atr=03(Int.) MxPS= 32 Ivl=4ms --- +[6]: http://lxr.free-electrons.com/ident?i=xpad_device + + + +7. Historic Edits +----------------- Marko Friedemann 2002-07-16 - original doc @@ -181,3 +222,5 @@ Marko Friedemann Dominic Cerquetti 2005-03-19 - added stuff for dance pads, new d-pad->axes mappings + +Later changes may be viewed with 'git log Documentation/input/xpad.txt' -- cgit v1.2.3-59-g8ed1b From 294a665e30c1897b2cbbc26a03eaf650485758cc Mon Sep 17 00:00:00 2001 From: Andreas Färber Date: Wed, 12 Nov 2014 14:51:16 +0100 Subject: Documentation: devicetree: Fix Xilinx VDMA specification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The specification requires xlnx,data-width, but example and driver use xlnx,datawidth. Change the specification to match the implementation. Reviewed-by: Michal Simek Fixes: eebeac03db93 ("dma: Add Xilinx Video DMA DT Binding Documentation") Signed-off-by: Andreas Färber Reviewed-by: Soren Brinkmann Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/dma/xilinx/xilinx_vdma.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/dma/xilinx/xilinx_vdma.txt b/Documentation/devicetree/bindings/dma/xilinx/xilinx_vdma.txt index 1405ed071bb4..e4c4d47f8137 100644 --- a/Documentation/devicetree/bindings/dma/xilinx/xilinx_vdma.txt +++ b/Documentation/devicetree/bindings/dma/xilinx/xilinx_vdma.txt @@ -25,7 +25,7 @@ Required child node properties: - compatible: It should be either "xlnx,axi-vdma-mm2s-channel" or "xlnx,axi-vdma-s2mm-channel". - interrupts: Should contain per channel VDMA interrupts. -- xlnx,data-width: Should contain the stream data width, take values +- xlnx,datawidth: Should contain the stream data width, take values {32,64...1024}. Optional child node properties: -- cgit v1.2.3-59-g8ed1b From 95acd4c7b69c9b250d901d154390ec4c8b7b51c1 Mon Sep 17 00:00:00 2001 From: Ley Foon Tan Date: Thu, 6 Nov 2014 15:20:03 +0800 Subject: nios2: Device tree support Add device tree support to arch/nios2. Signed-off-by: Ley Foon Tan --- Documentation/devicetree/bindings/nios2/nios2.txt | 62 ++++++++ Documentation/devicetree/bindings/nios2/timer.txt | 19 +++ arch/nios2/boot/dts/3c120_devboard.dts | 164 ++++++++++++++++++++++ arch/nios2/boot/linked_dtb.S | 19 +++ arch/nios2/kernel/prom.c | 65 +++++++++ arch/nios2/platform/platform.c | 46 ++++++ 6 files changed, 375 insertions(+) create mode 100644 Documentation/devicetree/bindings/nios2/nios2.txt create mode 100644 Documentation/devicetree/bindings/nios2/timer.txt create mode 100644 arch/nios2/boot/dts/3c120_devboard.dts create mode 100644 arch/nios2/boot/linked_dtb.S create mode 100644 arch/nios2/kernel/prom.c create mode 100644 arch/nios2/platform/platform.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/nios2/nios2.txt b/Documentation/devicetree/bindings/nios2/nios2.txt new file mode 100644 index 000000000000..d6d0a94cb3bb --- /dev/null +++ b/Documentation/devicetree/bindings/nios2/nios2.txt @@ -0,0 +1,62 @@ +* Nios II Processor Binding + +This binding specifies what properties available in the device tree +representation of a Nios II Processor Core. + +Users can use sopc2dts tool for generating device tree sources (dts) from a +Qsys system. See more detail in: http://www.alterawiki.com/wiki/Sopc2dts + +Required properties: + +- compatible: Compatible property value should be "altr,nios2-1.0". +- reg: Contains CPU index. +- interrupt-controller: Specifies that the node is an interrupt controller +- #interrupt-cells: Specifies the number of cells needed to encode an + interrupt source, should be 1. +- clock-frequency: Contains the clock frequency for CPU, in Hz. +- dcache-line-size: Contains data cache line size. +- icache-line-size: Contains instruction line size. +- dcache-size: Contains data cache size. +- icache-size: Contains instruction cache size. +- altr,pid-num-bits: Specifies the number of bits to use to represent the process + identifier (PID). +- altr,tlb-num-ways: Specifies the number of set-associativity ways in the TLB. +- altr,tlb-num-entries: Specifies the number of entries in the TLB. +- altr,tlb-ptr-sz: Specifies size of TLB pointer. +- altr,has-mul: Specifies CPU hardware multipy support, should be 1. +- altr,has-mmu: Specifies CPU support MMU support, should be 1. +- altr,has-initda: Specifies CPU support initda instruction, should be 1. +- altr,reset-addr: Specifies CPU reset address +- altr,fast-tlb-miss-addr: Specifies CPU fast TLB miss exception address +- altr,exception-addr: Specifies CPU exception address + +Optional properties: +- altr,has-div: Specifies CPU hardware divide support +- altr,implementation: Nios II core implementation, this should be "fast"; + +Example: + +cpu@0x0 { + device_type = "cpu"; + compatible = "altr,nios2-1.0"; + reg = <0>; + interrupt-controller; + #interrupt-cells = <1>; + clock-frequency = <125000000>; + dcache-line-size = <32>; + icache-line-size = <32>; + dcache-size = <32768>; + icache-size = <32768>; + altr,implementation = "fast"; + altr,pid-num-bits = <8>; + altr,tlb-num-ways = <16>; + altr,tlb-num-entries = <128>; + altr,tlb-ptr-sz = <7>; + altr,has-div = <1>; + altr,has-mul = <1>; + altr,reset-addr = <0xc2800000>; + altr,fast-tlb-miss-addr = <0xc7fff400>; + altr,exception-addr = <0xd0000020>; + altr,has-initda = <1>; + altr,has-mmu = <1>; +}; diff --git a/Documentation/devicetree/bindings/nios2/timer.txt b/Documentation/devicetree/bindings/nios2/timer.txt new file mode 100644 index 000000000000..904a5846d7ac --- /dev/null +++ b/Documentation/devicetree/bindings/nios2/timer.txt @@ -0,0 +1,19 @@ +Altera Timer + +Required properties: + +- compatible : should be "altr,timer-1.0" +- reg : Specifies base physical address and size of the registers. +- interrupt-parent: phandle of the interrupt controller +- interrupts : Should contain the timer interrupt number +- clock-frequency : The frequency of the clock that drives the counter, in Hz. + +Example: + +timer { + compatible = "altr,timer-1.0"; + reg = <0x00400000 0x00000020>; + interrupt-parent = <&cpu>; + interrupts = <11>; + clock-frequency = <125000000>; +}; diff --git a/arch/nios2/boot/dts/3c120_devboard.dts b/arch/nios2/boot/dts/3c120_devboard.dts new file mode 100644 index 000000000000..31c51f9a2f09 --- /dev/null +++ b/arch/nios2/boot/dts/3c120_devboard.dts @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2013 Altera Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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 . + * + * This file is generated by sopc2dts. + */ + +/dts-v1/; + +/ { + model = "altr,qsys_ghrd_3c120"; + compatible = "altr,qsys_ghrd_3c120"; + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu: cpu@0x0 { + device_type = "cpu"; + compatible = "altr,nios2-1.0"; + reg = <0x00000000>; + interrupt-controller; + #interrupt-cells = <1>; + clock-frequency = <125000000>; + dcache-line-size = <32>; + icache-line-size = <32>; + dcache-size = <32768>; + icache-size = <32768>; + altr,implementation = "fast"; + altr,pid-num-bits = <8>; + altr,tlb-num-ways = <16>; + altr,tlb-num-entries = <128>; + altr,tlb-ptr-sz = <7>; + altr,has-div = <1>; + altr,has-mul = <1>; + altr,reset-addr = <0xc2800000>; + altr,fast-tlb-miss-addr = <0xc7fff400>; + altr,exception-addr = <0xd0000020>; + altr,has-initda = <1>; + altr,has-mmu = <1>; + }; + }; + + memory@0 { + device_type = "memory"; + reg = <0x10000000 0x08000000>, + <0x07fff400 0x00000400>; + }; + + sopc@0 { + device_type = "soc"; + ranges; + #address-cells = <1>; + #size-cells = <1>; + compatible = "altr,avalon", "simple-bus"; + bus-frequency = <125000000>; + + pb_cpu_to_io: bridge@0x8000000 { + compatible = "simple-bus"; + reg = <0x08000000 0x00800000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x00002000 0x08002000 0x00002000>, + <0x00004000 0x08004000 0x00000400>, + <0x00004400 0x08004400 0x00000040>, + <0x00004800 0x08004800 0x00000040>, + <0x00004c80 0x08004c80 0x00000020>, + <0x00004d50 0x08004d50 0x00000008>, + <0x00008000 0x08008000 0x00000020>, + <0x00400000 0x08400000 0x00000020>; + + timer_1ms: timer@0x400000 { + compatible = "altr,timer-1.0"; + reg = <0x00400000 0x00000020>; + interrupt-parent = <&cpu>; + interrupts = <11>; + clock-frequency = <125000000>; + }; + + timer_0: timer@0x8000 { + compatible = "altr,timer-1.0"; + reg = < 0x00008000 0x00000020 >; + interrupt-parent = < &cpu >; + interrupts = < 5 >; + clock-frequency = < 125000000 >; + }; + + jtag_uart: serial@0x4d50 { + compatible = "altr,juart-1.0"; + reg = <0x00004d50 0x00000008>; + interrupt-parent = <&cpu>; + interrupts = <1>; + }; + + tse_mac: ethernet@0x4000 { + compatible = "altr,tse-1.0"; + reg = <0x00004000 0x00000400>, + <0x00004400 0x00000040>, + <0x00004800 0x00000040>, + <0x00002000 0x00002000>; + reg-names = "control_port", "rx_csr", "tx_csr", "s1"; + interrupt-parent = <&cpu>; + interrupts = <2 3>; + interrupt-names = "rx_irq", "tx_irq"; + rx-fifo-depth = <8192>; + tx-fifo-depth = <8192>; + max-frame-size = <1518>; + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-mode = "rgmii-id"; + phy-handle = <&phy0>; + tse_mac_mdio: mdio { + compatible = "altr,tse-mdio"; + #address-cells = <1>; + #size-cells = <0>; + phy0: ethernet-phy@18 { + reg = <18>; + device_type = "ethernet-phy"; + }; + }; + }; + + uart: serial@0x4c80 { + compatible = "altr,uart-1.0"; + reg = <0x00004c80 0x00000020>; + interrupt-parent = <&cpu>; + interrupts = <10>; + current-speed = <115200>; + clock-frequency = <62500000>; + }; + }; + + cfi_flash_64m: flash@0x0 { + compatible = "cfi-flash"; + reg = <0x00000000 0x04000000>; + bank-width = <2>; + device-width = <1>; + #address-cells = <1>; + #size-cells = <1>; + + partition@800000 { + reg = <0x00800000 0x01e00000>; + label = "JFFS2 Filesystem"; + }; + }; + }; + + chosen { + bootargs = "debug console=ttyJ0,115200"; + }; +}; diff --git a/arch/nios2/boot/linked_dtb.S b/arch/nios2/boot/linked_dtb.S new file mode 100644 index 000000000000..071f922db338 --- /dev/null +++ b/arch/nios2/boot/linked_dtb.S @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2011 Thomas Chou + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +.section .dtb.init.rodata,"a" +.incbin "arch/nios2/boot/system.dtb" diff --git a/arch/nios2/kernel/prom.c b/arch/nios2/kernel/prom.c new file mode 100644 index 000000000000..0522d3378e3f --- /dev/null +++ b/arch/nios2/kernel/prom.c @@ -0,0 +1,65 @@ +/* + * Device tree support + * + * Copyright (C) 2013 Altera Corporation + * Copyright (C) 2010 Thomas Chou + * + * Based on MIPS support for CONFIG_OF device tree support + * + * Copyright (C) 2010 Cisco Systems Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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 . + * + */ + +#include +#include +#include +#include +#include +#include + +#include + +void __init early_init_dt_add_memory_arch(u64 base, u64 size) +{ + u64 kernel_start = (u64)virt_to_phys(_text); + + if (!memory_size && + (kernel_start >= base) && (kernel_start < (base + size))) + memory_size = size; + +} + +void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align) +{ + return alloc_bootmem_align(size, align); +} + +void __init early_init_devtree(void *params) +{ + __be32 *dtb = (u32 *)__dtb_start; +#if defined(CONFIG_NIOS2_DTB_AT_PHYS_ADDR) + if (be32_to_cpup((__be32 *)CONFIG_NIOS2_DTB_PHYS_ADDR) == + OF_DT_HEADER) { + params = (void *)CONFIG_NIOS2_DTB_PHYS_ADDR; + early_init_dt_scan(params); + return; + } +#endif + if (be32_to_cpu((__be32) *dtb) == OF_DT_HEADER) + params = (void *)__dtb_start; + + early_init_dt_scan(params); +} diff --git a/arch/nios2/platform/platform.c b/arch/nios2/platform/platform.c new file mode 100644 index 000000000000..d478773f758a --- /dev/null +++ b/arch/nios2/platform/platform.c @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2013 Altera Corporation + * Copyright (C) 2011 Thomas Chou + * Copyright (C) 2011 Walter Goossens + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static int __init nios2_soc_device_init(void) +{ + struct soc_device *soc_dev; + struct soc_device_attribute *soc_dev_attr; + const char *machine; + + soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); + if (soc_dev_attr) { + machine = of_flat_dt_get_machine_name(); + if (machine) + soc_dev_attr->machine = kasprintf(GFP_KERNEL, "%s", + machine); + + soc_dev_attr->family = "Nios II"; + + soc_dev = soc_device_register(soc_dev_attr); + if (IS_ERR(soc_dev)) { + kfree(soc_dev_attr->machine); + kfree(soc_dev_attr); + } + } + + return of_platform_populate(NULL, of_default_bus_match_table, + NULL, NULL); +} + +device_initcall(nios2_soc_device_init); -- cgit v1.2.3-59-g8ed1b From 9cce02ec7146248862ba63a41bf8eb32d9e4fb63 Mon Sep 17 00:00:00 2001 From: Ley Foon Tan Date: Thu, 6 Nov 2014 15:20:15 +0800 Subject: Documentation: Add documentation for Nios2 architecture Signed-off-by: Ley Foon Tan --- Documentation/nios2/README | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 Documentation/nios2/README (limited to 'Documentation') diff --git a/Documentation/nios2/README b/Documentation/nios2/README new file mode 100644 index 000000000000..054a67d55563 --- /dev/null +++ b/Documentation/nios2/README @@ -0,0 +1,23 @@ +Linux on the Nios II architecture +================================= + +This is a port of Linux to Nios II (nios2) processor. + +In order to compile for Nios II, you need a version of GCC with support for the generic +system call ABI. Please see this link for more information on how compiling and booting +software for the Nios II platform: +http://www.rocketboards.org/foswiki/Documentation/NiosIILinuxUserManual + +For reference, please see the following link: +http://www.altera.com/literature/lit-nio2.jsp + +What is Nios II? +================ +Nios II is a 32-bit embedded-processor architecture designed specifically for the +Altera family of FPGAs. In order to support Linux, Nios II needs to be configured +with MMU and hardware multiplier enabled. + +Nios II ABI +=========== +Please refer to chapter "Application Binary Interface" in Nios II Processor Reference +Handbook. -- cgit v1.2.3-59-g8ed1b From 66aee90088da2f5fb73ba97ee8b5f4fda92e2b53 Mon Sep 17 00:00:00 2001 From: Scott Liu Date: Wed, 19 Nov 2014 17:26:44 -0800 Subject: Input: add support for Elan eKTH I2C touchscreens This driver supports Elan eKTH I2C touchscreen controllers. Note that these are using custom protocol, as opposed to other Elan parts that use HID-over-I2C and are supported by the standard HID-multitouch driver. Signed-off-by: Scott Liu Signed-off-by: Dmitry Torokhov --- .../devicetree/bindings/input/elants_i2c.txt | 33 + drivers/input/touchscreen/Kconfig | 12 + drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/elants_i2c.c | 1271 ++++++++++++++++++++ 4 files changed, 1317 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/elants_i2c.txt create mode 100644 drivers/input/touchscreen/elants_i2c.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/input/elants_i2c.txt b/Documentation/devicetree/bindings/input/elants_i2c.txt new file mode 100644 index 000000000000..a765232e6446 --- /dev/null +++ b/Documentation/devicetree/bindings/input/elants_i2c.txt @@ -0,0 +1,33 @@ +Elantech I2C Touchscreen + +Required properties: +- compatible: must be "elan,ekth3500". +- reg: I2C address of the chip. +- interrupt-parent: a phandle for the interrupt controller (see interrupt + binding[0]). +- interrupts: interrupt to which the chip is connected (see interrupt + binding[0]). + +Optional properties: +- wakeup-source: touchscreen can be used as a wakeup source. +- pinctrl-names: should be "default" (see pinctrl binding [1]). +- pinctrl-0: a phandle pointing to the pin settings for the device (see + pinctrl binding [1]). + +[0]: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt +[1]: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt + +Example: + &i2c1 { + /* ... */ + + touchscreen@10 { + compatible = "elan,ekth3500"; + reg = <0x10>; + interrupt-parent = <&gpio4>; + interrupts = <0x0 IRQ_TYPE_EDGE_FALLING>; + wakeup-source; + }; + + /* ... */ + }; diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 568a0200fbc2..58917525126e 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -347,6 +347,18 @@ config TOUCHSCREEN_GUNZE To compile this driver as a module, choose M here: the module will be called gunze. +config TOUCHSCREEN_ELAN + tristate "Elan eKTH I2C touchscreen" + depends on I2C + help + Say Y here if you have an Elan eKTH I2C touchscreen + connected to your system. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called elants_i2c. + config TOUCHSCREEN_ELO tristate "Elo serial touchscreens" select SERIO diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index dab4a56ac98e..0242fea2102a 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_TOUCHSCREEN_EDT_FT5X06) += edt-ft5x06.o obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE) += hampshire.o obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o +obj-$(CONFIG_TOUCHSCREEN_ELAN) += elants_i2c.o obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_ts.o obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c new file mode 100644 index 000000000000..a510f7ef9b66 --- /dev/null +++ b/drivers/input/touchscreen/elants_i2c.c @@ -0,0 +1,1271 @@ +/* + * Elan Microelectronics touch panels with I2C interface + * + * Copyright (C) 2014 Elan Microelectronics Corporation. + * Scott Liu + * + * This code is partly based on hid-multitouch.c: + * + * Copyright (c) 2010-2012 Stephane Chatty + * Copyright (c) 2010-2012 Benjamin Tissoires + * Copyright (c) 2010-2012 Ecole Nationale de l'Aviation Civile, France + * + * + * This code is partly based on i2c-hid.c: + * + * Copyright (c) 2012 Benjamin Tissoires + * Copyright (c) 2012 Ecole Nationale de l'Aviation Civile, France + * Copyright (c) 2012 Red Hat, Inc + */ + +/* + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Device, Driver information */ +#define DEVICE_NAME "elants_i2c" +#define DRV_VERSION "1.0.9" + +/* Convert from rows or columns into resolution */ +#define ELAN_TS_RESOLUTION(n, m) (((n) - 1) * (m)) + +/* FW header data */ +#define HEADER_SIZE 4 +#define FW_HDR_TYPE 0 +#define FW_HDR_COUNT 1 +#define FW_HDR_LENGTH 2 + +/* Buffer mode Queue Header information */ +#define QUEUE_HEADER_SINGLE 0x62 +#define QUEUE_HEADER_NORMAL 0X63 +#define QUEUE_HEADER_WAIT 0x64 + +/* Command header definition */ +#define CMD_HEADER_WRITE 0x54 +#define CMD_HEADER_READ 0x53 +#define CMD_HEADER_6B_READ 0x5B +#define CMD_HEADER_RESP 0x52 +#define CMD_HEADER_6B_RESP 0x9B +#define CMD_HEADER_HELLO 0x55 +#define CMD_HEADER_REK 0x66 + +/* FW position data */ +#define PACKET_SIZE 55 +#define MAX_CONTACT_NUM 10 +#define FW_POS_HEADER 0 +#define FW_POS_STATE 1 +#define FW_POS_TOTAL 2 +#define FW_POS_XY 3 +#define FW_POS_CHECKSUM 34 +#define FW_POS_WIDTH 35 +#define FW_POS_PRESSURE 45 + +#define HEADER_REPORT_10_FINGER 0x62 + +/* Header (4 bytes) plus 3 fill 10-finger packets */ +#define MAX_PACKET_SIZE 169 + +#define BOOT_TIME_DELAY_MS 50 + +/* FW read command, 0x53 0x?? 0x0, 0x01 */ +#define E_ELAN_INFO_FW_VER 0x00 +#define E_ELAN_INFO_BC_VER 0x10 +#define E_ELAN_INFO_TEST_VER 0xE0 +#define E_ELAN_INFO_FW_ID 0xF0 +#define E_INFO_OSR 0xD6 +#define E_INFO_PHY_SCAN 0xD7 +#define E_INFO_PHY_DRIVER 0xD8 + +#define MAX_RETRIES 3 +#define MAX_FW_UPDATE_RETRIES 30 + +#define ELAN_FW_PAGESIZE 132 +#define ELAN_FW_FILENAME "elants_i2c.bin" + +/* calibration timeout definition */ +#define ELAN_CALI_TIMEOUT_MSEC 10000 + +enum elants_state { + ELAN_STATE_NORMAL, + ELAN_WAIT_QUEUE_HEADER, + ELAN_WAIT_RECALIBRATION, +}; + +enum elants_iap_mode { + ELAN_IAP_OPERATIONAL, + ELAN_IAP_RECOVERY, +}; + +/* struct elants_data - represents state of Elan touchscreen device */ +struct elants_data { + struct i2c_client *client; + struct input_dev *input; + + u16 fw_version; + u8 test_version; + u8 solution_version; + u8 bc_version; + u8 iap_version; + u16 hw_version; + unsigned int x_res; /* resolution in units/mm */ + unsigned int y_res; + unsigned int x_max; + unsigned int y_max; + + enum elants_state state; + enum elants_iap_mode iap_mode; + + /* Guards against concurrent access to the device via sysfs */ + struct mutex sysfs_mutex; + + u8 cmd_resp[HEADER_SIZE]; + struct completion cmd_done; + + u8 buf[MAX_PACKET_SIZE]; + + bool wake_irq_enabled; +}; + +static int elants_i2c_send(struct i2c_client *client, + const void *data, size_t size) +{ + int ret; + + ret = i2c_master_send(client, data, size); + if (ret == size) + return 0; + + if (ret >= 0) + ret = -EIO; + + dev_err(&client->dev, "%s failed (%*ph): %d\n", + __func__, (int)size, data, ret); + + return ret; +} + +static int elants_i2c_read(struct i2c_client *client, void *data, size_t size) +{ + int ret; + + ret = i2c_master_recv(client, data, size); + if (ret == size) + return 0; + + if (ret >= 0) + ret = -EIO; + + dev_err(&client->dev, "%s failed: %d\n", __func__, ret); + + return ret; +} + +static int elants_i2c_execute_command(struct i2c_client *client, + const u8 *cmd, size_t cmd_size, + u8 *resp, size_t resp_size) +{ + struct i2c_msg msgs[2]; + int ret; + u8 expected_response; + + switch (cmd[0]) { + case CMD_HEADER_READ: + expected_response = CMD_HEADER_RESP; + break; + + case CMD_HEADER_6B_READ: + expected_response = CMD_HEADER_6B_RESP; + break; + + default: + dev_err(&client->dev, "%s: invalid command %*ph\n", + __func__, (int)cmd_size, cmd); + return -EINVAL; + } + + msgs[0].addr = client->addr; + msgs[0].flags = client->flags & I2C_M_TEN; + msgs[0].len = cmd_size; + msgs[0].buf = (u8 *)cmd; + + msgs[1].addr = client->addr; + msgs[1].flags = client->flags & I2C_M_TEN; + msgs[1].flags |= I2C_M_RD; + msgs[1].len = resp_size; + msgs[1].buf = resp; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret < 0) + return ret; + + if (ret != ARRAY_SIZE(msgs) || resp[FW_HDR_TYPE] != expected_response) + return -EIO; + + return 0; +} + +static int elants_i2c_calibrate(struct elants_data *ts) +{ + struct i2c_client *client = ts->client; + int ret, error; + static const u8 w_flashkey[] = { 0x54, 0xC0, 0xE1, 0x5A }; + static const u8 rek[] = { 0x54, 0x29, 0x00, 0x01 }; + static const u8 rek_resp[] = { CMD_HEADER_REK, 0x66, 0x66, 0x66 }; + + disable_irq(client->irq); + + ts->state = ELAN_WAIT_RECALIBRATION; + reinit_completion(&ts->cmd_done); + + elants_i2c_send(client, w_flashkey, sizeof(w_flashkey)); + elants_i2c_send(client, rek, sizeof(rek)); + + enable_irq(client->irq); + + ret = wait_for_completion_interruptible_timeout(&ts->cmd_done, + msecs_to_jiffies(ELAN_CALI_TIMEOUT_MSEC)); + + ts->state = ELAN_STATE_NORMAL; + + if (ret <= 0) { + error = ret < 0 ? ret : -ETIMEDOUT; + dev_err(&client->dev, + "error while waiting for calibration to complete: %d\n", + error); + return error; + } + + if (memcmp(rek_resp, ts->cmd_resp, sizeof(rek_resp))) { + dev_err(&client->dev, + "unexpected calibration response: %*ph\n", + (int)sizeof(ts->cmd_resp), ts->cmd_resp); + return -EINVAL; + } + + return 0; +} + +static int elants_i2c_sw_reset(struct i2c_client *client) +{ + const u8 soft_rst_cmd[] = { 0x77, 0x77, 0x77, 0x77 }; + int error; + + error = elants_i2c_send(client, soft_rst_cmd, + sizeof(soft_rst_cmd)); + if (error) { + dev_err(&client->dev, "software reset failed: %d\n", error); + return error; + } + + /* + * We should wait at least 10 msec (but no more than 40) before + * sending fastboot or IAP command to the device. + */ + msleep(30); + + return 0; +} + +static u16 elants_i2c_parse_version(u8 *buf) +{ + return get_unaligned_be32(buf) >> 4; +} + +static int elants_i2c_query_fw_id(struct elants_data *ts) +{ + struct i2c_client *client = ts->client; + int error, retry_cnt; + const u8 cmd[] = { CMD_HEADER_READ, E_ELAN_INFO_FW_ID, 0x00, 0x01 }; + u8 resp[HEADER_SIZE]; + + for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { + error = elants_i2c_execute_command(client, cmd, sizeof(cmd), + resp, sizeof(resp)); + if (!error) { + ts->hw_version = elants_i2c_parse_version(resp); + if (ts->hw_version != 0xffff) + return 0; + } + + dev_dbg(&client->dev, "read fw id error=%d, buf=%*phC\n", + error, (int)sizeof(resp), resp); + } + + dev_err(&client->dev, + "Failed to read fw id or fw id is invalid\n"); + + return -EINVAL; +} + +static int elants_i2c_query_fw_version(struct elants_data *ts) +{ + struct i2c_client *client = ts->client; + int error, retry_cnt; + const u8 cmd[] = { CMD_HEADER_READ, E_ELAN_INFO_FW_VER, 0x00, 0x01 }; + u8 resp[HEADER_SIZE]; + + for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { + error = elants_i2c_execute_command(client, cmd, sizeof(cmd), + resp, sizeof(resp)); + if (!error) { + ts->fw_version = elants_i2c_parse_version(resp); + if (ts->fw_version != 0x0000 && + ts->fw_version != 0xffff) + return 0; + } + + dev_dbg(&client->dev, "read fw version error=%d, buf=%*phC\n", + error, (int)sizeof(resp), resp); + } + + dev_err(&client->dev, + "Failed to read fw version or fw version is invalid\n"); + + return -EINVAL; +} + +static int elants_i2c_query_test_version(struct elants_data *ts) +{ + struct i2c_client *client = ts->client; + int error, retry_cnt; + u16 version; + const u8 cmd[] = { CMD_HEADER_READ, E_ELAN_INFO_TEST_VER, 0x00, 0x01 }; + u8 resp[HEADER_SIZE]; + + for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { + error = elants_i2c_execute_command(client, cmd, sizeof(cmd), + resp, sizeof(resp)); + if (!error) { + version = elants_i2c_parse_version(resp); + ts->test_version = version >> 8; + ts->solution_version = version & 0xff; + + return 0; + } + + dev_dbg(&client->dev, + "read test version error rc=%d, buf=%*phC\n", + error, (int)sizeof(resp), resp); + } + + dev_err(&client->dev, "Failed to read test version\n"); + + return -EINVAL; +} + +static int elants_i2c_query_bc_version(struct elants_data *ts) +{ + struct i2c_client *client = ts->client; + const u8 cmd[] = { CMD_HEADER_READ, E_ELAN_INFO_BC_VER, 0x00, 0x01 }; + u8 resp[HEADER_SIZE]; + u16 version; + int error; + + error = elants_i2c_execute_command(client, cmd, sizeof(cmd), + resp, sizeof(resp)); + if (error) { + dev_err(&client->dev, + "read BC version error=%d, buf=%*phC\n", + error, (int)sizeof(resp), resp); + return error; + } + + version = elants_i2c_parse_version(resp); + ts->bc_version = version >> 8; + ts->iap_version = version & 0xff; + + return 0; +} + +static int elants_i2c_query_ts_info(struct elants_data *ts) +{ + struct i2c_client *client = ts->client; + int error; + u8 resp[17]; + u16 phy_x, phy_y, rows, cols, osr; + const u8 get_resolution_cmd[] = { + CMD_HEADER_6B_READ, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + const u8 get_osr_cmd[] = { + CMD_HEADER_READ, E_INFO_OSR, 0x00, 0x01 + }; + const u8 get_physical_scan_cmd[] = { + CMD_HEADER_READ, E_INFO_PHY_SCAN, 0x00, 0x01 + }; + const u8 get_physical_drive_cmd[] = { + CMD_HEADER_READ, E_INFO_PHY_DRIVER, 0x00, 0x01 + }; + + /* Get trace number */ + error = elants_i2c_execute_command(client, + get_resolution_cmd, + sizeof(get_resolution_cmd), + resp, sizeof(resp)); + if (error) { + dev_err(&client->dev, "get resolution command failed: %d\n", + error); + return error; + } + + rows = resp[2] + resp[6] + resp[10]; + cols = resp[3] + resp[7] + resp[11]; + + /* Process mm_to_pixel information */ + error = elants_i2c_execute_command(client, + get_osr_cmd, sizeof(get_osr_cmd), + resp, sizeof(resp)); + if (error) { + dev_err(&client->dev, "get osr command failed: %d\n", + error); + return error; + } + + osr = resp[3]; + + error = elants_i2c_execute_command(client, + get_physical_scan_cmd, + sizeof(get_physical_scan_cmd), + resp, sizeof(resp)); + if (error) { + dev_err(&client->dev, "get physical scan command failed: %d\n", + error); + return error; + } + + phy_x = get_unaligned_be16(&resp[2]); + + error = elants_i2c_execute_command(client, + get_physical_drive_cmd, + sizeof(get_physical_drive_cmd), + resp, sizeof(resp)); + if (error) { + dev_err(&client->dev, "get physical drive command failed: %d\n", + error); + return error; + } + + phy_y = get_unaligned_be16(&resp[2]); + + dev_dbg(&client->dev, "phy_x=%d, phy_y=%d\n", phy_x, phy_y); + + if (rows == 0 || cols == 0 || osr == 0) { + dev_warn(&client->dev, + "invalid trace number data: %d, %d, %d\n", + rows, cols, osr); + } else { + /* translate trace number to TS resolution */ + ts->x_max = ELAN_TS_RESOLUTION(rows, osr); + ts->x_res = DIV_ROUND_CLOSEST(ts->x_max, phy_x); + ts->y_max = ELAN_TS_RESOLUTION(cols, osr); + ts->y_res = DIV_ROUND_CLOSEST(ts->y_max, phy_y); + } + + return 0; +} + +static int elants_i2c_fastboot(struct i2c_client *client) +{ + const u8 boot_cmd[] = { 0x4D, 0x61, 0x69, 0x6E }; + int error; + + error = elants_i2c_send(client, boot_cmd, sizeof(boot_cmd)); + if (error) { + dev_err(&client->dev, "boot failed: %d\n", error); + return error; + } + + dev_dbg(&client->dev, "boot success -- 0x%x\n", client->addr); + return 0; +} + +static int elants_i2c_initialize(struct elants_data *ts) +{ + struct i2c_client *client = ts->client; + int error, retry_cnt; + const u8 hello_packet[] = { 0x55, 0x55, 0x55, 0x55 }; + const u8 recov_packet[] = { 0x55, 0x55, 0x80, 0x80 }; + u8 buf[HEADER_SIZE]; + + for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { + error = elants_i2c_sw_reset(client); + if (error) { + /* Continue initializing if it's the last try */ + if (retry_cnt < MAX_RETRIES - 1) + continue; + } + + error = elants_i2c_fastboot(client); + if (error) { + /* Continue initializing if it's the last try */ + if (retry_cnt < MAX_RETRIES - 1) + continue; + } + + /* Wait for Hello packet */ + msleep(BOOT_TIME_DELAY_MS); + + error = elants_i2c_read(client, buf, sizeof(buf)); + if (error) { + dev_err(&client->dev, + "failed to read 'hello' packet: %d\n", error); + } else if (!memcmp(buf, hello_packet, sizeof(hello_packet))) { + ts->iap_mode = ELAN_IAP_OPERATIONAL; + break; + } else if (!memcmp(buf, recov_packet, sizeof(recov_packet))) { + /* + * Setting error code will mark device + * in recovery mode below. + */ + error = -EIO; + break; + } else { + error = -EINVAL; + dev_err(&client->dev, + "invalid 'hello' packet: %*ph\n", + (int)sizeof(buf), buf); + } + } + + if (!error) + error = elants_i2c_query_fw_id(ts); + if (!error) + error = elants_i2c_query_fw_version(ts); + + if (error) { + ts->iap_mode = ELAN_IAP_RECOVERY; + } else { + elants_i2c_query_test_version(ts); + elants_i2c_query_bc_version(ts); + elants_i2c_query_ts_info(ts); + } + + return 0; +} + +/* + * Firmware update interface. + */ + +static int elants_i2c_fw_write_page(struct i2c_client *client, + const void *page) +{ + const u8 ack_ok[] = { 0xaa, 0xaa }; + u8 buf[2]; + int retry; + int error; + + for (retry = 0; retry < MAX_FW_UPDATE_RETRIES; retry++) { + error = elants_i2c_send(client, page, ELAN_FW_PAGESIZE); + if (error) { + dev_err(&client->dev, + "IAP Write Page failed: %d\n", error); + continue; + } + + error = elants_i2c_read(client, buf, 2); + if (error) { + dev_err(&client->dev, + "IAP Ack read failed: %d\n", error); + return error; + } + + if (!memcmp(buf, ack_ok, sizeof(ack_ok))) + return 0; + + error = -EIO; + dev_err(&client->dev, + "IAP Get Ack Error [%02x:%02x]\n", + buf[0], buf[1]); + } + + return error; +} + +static int elants_i2c_do_update_firmware(struct i2c_client *client, + const struct firmware *fw, + bool force) +{ + const u8 enter_iap[] = { 0x45, 0x49, 0x41, 0x50 }; + const u8 enter_iap2[] = { 0x54, 0x00, 0x12, 0x34 }; + const u8 iap_ack[] = { 0x55, 0xaa, 0x33, 0xcc }; + u8 buf[HEADER_SIZE]; + u16 send_id; + int page, n_fw_pages; + int error; + + /* Recovery mode detection! */ + if (force) { + dev_dbg(&client->dev, "Recovery mode procedure\n"); + error = elants_i2c_send(client, enter_iap2, sizeof(enter_iap2)); + } else { + /* Start IAP Procedure */ + dev_dbg(&client->dev, "Normal IAP procedure\n"); + elants_i2c_sw_reset(client); + + error = elants_i2c_send(client, enter_iap, sizeof(enter_iap)); + } + + if (error) { + dev_err(&client->dev, "failed to enter IAP mode: %d\n", error); + return error; + } + + msleep(20); + + /* check IAP state */ + error = elants_i2c_read(client, buf, 4); + if (error) { + dev_err(&client->dev, + "failed to read IAP acknowledgement: %d\n", + error); + return error; + } + + if (memcmp(buf, iap_ack, sizeof(iap_ack))) { + dev_err(&client->dev, + "failed to enter IAP: %*ph (expected %*ph)\n", + (int)sizeof(buf), buf, (int)sizeof(iap_ack), iap_ack); + return -EIO; + } + + dev_info(&client->dev, "successfully entered IAP mode"); + + send_id = client->addr; + error = elants_i2c_send(client, &send_id, 1); + if (error) { + dev_err(&client->dev, "sending dummy byte failed: %d\n", + error); + return error; + } + + /* Clear the last page of Master */ + error = elants_i2c_send(client, fw->data, ELAN_FW_PAGESIZE); + if (error) { + dev_err(&client->dev, "clearing of the last page failed: %d\n", + error); + return error; + } + + error = elants_i2c_read(client, buf, 2); + if (error) { + dev_err(&client->dev, + "failed to read ACK for clearing the last page: %d\n", + error); + return error; + } + + n_fw_pages = fw->size / ELAN_FW_PAGESIZE; + dev_dbg(&client->dev, "IAP Pages = %d\n", n_fw_pages); + + for (page = 0; page < n_fw_pages; page++) { + error = elants_i2c_fw_write_page(client, + fw->data + page * ELAN_FW_PAGESIZE); + if (error) { + dev_err(&client->dev, + "failed to write FW page %d: %d\n", + page, error); + return error; + } + } + + /* Old iap needs to wait 200ms for WDT and rest is for hello packets */ + msleep(300); + + dev_info(&client->dev, "firmware update completed\n"); + return 0; +} + +static int elants_i2c_fw_update(struct elants_data *ts) +{ + struct i2c_client *client = ts->client; + const struct firmware *fw; + int error; + + error = request_firmware(&fw, ELAN_FW_FILENAME, &client->dev); + if (error) { + dev_err(&client->dev, "failed to request firmware %s: %d\n", + ELAN_FW_FILENAME, error); + return error; + } + + if (fw->size % ELAN_FW_PAGESIZE) { + dev_err(&client->dev, "invalid firmware length: %zu\n", + fw->size); + error = -EINVAL; + goto out; + } + + disable_irq(client->irq); + + error = elants_i2c_do_update_firmware(client, fw, + ts->iap_mode == ELAN_IAP_RECOVERY); + if (error) { + dev_err(&client->dev, "firmware update failed: %d\n", error); + ts->iap_mode = ELAN_IAP_RECOVERY; + goto out_enable_irq; + } + + error = elants_i2c_initialize(ts); + if (error) { + dev_err(&client->dev, + "failed to initialize device after firmware update: %d\n", + error); + ts->iap_mode = ELAN_IAP_RECOVERY; + goto out_enable_irq; + } + + ts->iap_mode = ELAN_IAP_OPERATIONAL; + +out_enable_irq: + ts->state = ELAN_STATE_NORMAL; + enable_irq(client->irq); + msleep(100); + + if (!error) + elants_i2c_calibrate(ts); +out: + release_firmware(fw); + return error; +} + +/* + * Event reporting. + */ + +static void elants_i2c_mt_event(struct elants_data *ts, u8 *buf) +{ + struct input_dev *input = ts->input; + unsigned int n_fingers; + u16 finger_state; + int i; + + n_fingers = buf[FW_POS_STATE + 1] & 0x0f; + finger_state = ((buf[FW_POS_STATE + 1] & 0x30) << 4) | + buf[FW_POS_STATE]; + + dev_dbg(&ts->client->dev, + "n_fingers: %u, state: %04x\n", n_fingers, finger_state); + + for (i = 0; i < MAX_CONTACT_NUM && n_fingers; i++) { + if (finger_state & 1) { + unsigned int x, y, p, w; + u8 *pos; + + pos = &buf[FW_POS_XY + i * 3]; + x = (((u16)pos[0] & 0xf0) << 4) | pos[1]; + y = (((u16)pos[0] & 0x0f) << 8) | pos[2]; + p = buf[FW_POS_PRESSURE + i]; + w = buf[FW_POS_WIDTH + i]; + + dev_dbg(&ts->client->dev, "i=%d x=%d y=%d p=%d w=%d\n", + i, x, y, p, w); + + input_mt_slot(input, i); + input_mt_report_slot_state(input, MT_TOOL_FINGER, true); + input_event(input, EV_ABS, ABS_MT_POSITION_X, x); + input_event(input, EV_ABS, ABS_MT_POSITION_Y, y); + input_event(input, EV_ABS, ABS_MT_PRESSURE, p); + input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, w); + + n_fingers--; + } + + finger_state >>= 1; + } + + input_mt_sync_frame(input); + input_sync(input); +} + +static u8 elants_i2c_calculate_checksum(u8 *buf) +{ + u8 checksum = 0; + u8 i; + + for (i = 0; i < FW_POS_CHECKSUM; i++) + checksum += buf[i]; + + return checksum; +} + +static void elants_i2c_event(struct elants_data *ts, u8 *buf) +{ + u8 checksum = elants_i2c_calculate_checksum(buf); + + if (unlikely(buf[FW_POS_CHECKSUM] != checksum)) + dev_warn(&ts->client->dev, + "%s: invalid checksum for packet %02x: %02x vs. %02x\n", + __func__, buf[FW_POS_HEADER], + checksum, buf[FW_POS_CHECKSUM]); + else if (unlikely(buf[FW_POS_HEADER] != HEADER_REPORT_10_FINGER)) + dev_warn(&ts->client->dev, + "%s: unknown packet type: %02x\n", + __func__, buf[FW_POS_HEADER]); + else + elants_i2c_mt_event(ts, buf); +} + +static irqreturn_t elants_i2c_irq(int irq, void *_dev) +{ + const u8 wait_packet[] = { 0x64, 0x64, 0x64, 0x64 }; + struct elants_data *ts = _dev; + struct i2c_client *client = ts->client; + int report_count, report_len; + int i; + int len; + + len = i2c_master_recv(client, ts->buf, sizeof(ts->buf)); + if (len < 0) { + dev_err(&client->dev, "%s: failed to read data: %d\n", + __func__, len); + goto out; + } + + dev_dbg(&client->dev, "%s: packet %*ph\n", + __func__, HEADER_SIZE, ts->buf); + + switch (ts->state) { + case ELAN_WAIT_RECALIBRATION: + if (ts->buf[FW_HDR_TYPE] == CMD_HEADER_REK) { + memcpy(ts->cmd_resp, ts->buf, sizeof(ts->cmd_resp)); + complete(&ts->cmd_done); + ts->state = ELAN_STATE_NORMAL; + } + break; + + case ELAN_WAIT_QUEUE_HEADER: + if (ts->buf[FW_HDR_TYPE] != QUEUE_HEADER_NORMAL) + break; + + ts->state = ELAN_STATE_NORMAL; + /* fall through */ + + case ELAN_STATE_NORMAL: + + switch (ts->buf[FW_HDR_TYPE]) { + case CMD_HEADER_HELLO: + case CMD_HEADER_RESP: + case CMD_HEADER_REK: + break; + + case QUEUE_HEADER_WAIT: + if (memcmp(ts->buf, wait_packet, sizeof(wait_packet))) { + dev_err(&client->dev, + "invalid wait packet %*ph\n", + HEADER_SIZE, ts->buf); + } else { + ts->state = ELAN_WAIT_QUEUE_HEADER; + udelay(30); + } + break; + + case QUEUE_HEADER_SINGLE: + elants_i2c_event(ts, &ts->buf[HEADER_SIZE]); + break; + + case QUEUE_HEADER_NORMAL: + report_count = ts->buf[FW_HDR_COUNT]; + if (report_count > 3) { + dev_err(&client->dev, + "too large report count: %*ph\n", + HEADER_SIZE, ts->buf); + break; + } + + report_len = ts->buf[FW_HDR_LENGTH] / report_count; + if (report_len != PACKET_SIZE) { + dev_err(&client->dev, + "mismatching report length: %*ph\n", + HEADER_SIZE, ts->buf); + break; + } + + for (i = 0; i < report_count; i++) { + u8 *buf = ts->buf + HEADER_SIZE + + i * PACKET_SIZE; + elants_i2c_event(ts, buf); + } + break; + + default: + dev_err(&client->dev, "unknown packet %*ph\n", + HEADER_SIZE, ts->buf); + break; + } + break; + } + +out: + return IRQ_HANDLED; +} + +/* + * sysfs interface + */ +static ssize_t calibrate_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct elants_data *ts = i2c_get_clientdata(client); + int error; + + error = mutex_lock_interruptible(&ts->sysfs_mutex); + if (error) + return error; + + error = elants_i2c_calibrate(ts); + + mutex_unlock(&ts->sysfs_mutex); + return error ?: count; +} + +static ssize_t write_update_fw(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct elants_data *ts = i2c_get_clientdata(client); + int error; + + error = mutex_lock_interruptible(&ts->sysfs_mutex); + if (error) + return error; + + error = elants_i2c_fw_update(ts); + dev_dbg(dev, "firmware update result: %d\n", error); + + mutex_unlock(&ts->sysfs_mutex); + return error ?: count; +} + +static ssize_t show_iap_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct elants_data *ts = i2c_get_clientdata(client); + + return sprintf(buf, "%s\n", + ts->iap_mode == ELAN_IAP_OPERATIONAL ? + "Normal" : "Recovery"); +} + +static DEVICE_ATTR(calibrate, S_IWUSR, NULL, calibrate_store); +static DEVICE_ATTR(iap_mode, S_IRUGO, show_iap_mode, NULL); +static DEVICE_ATTR(update_fw, S_IWUSR, NULL, write_update_fw); + +struct elants_version_attribute { + struct device_attribute dattr; + size_t field_offset; + size_t field_size; +}; + +#define __ELANTS_FIELD_SIZE(_field) \ + sizeof(((struct elants_data *)NULL)->_field) +#define __ELANTS_VERIFY_SIZE(_field) \ + (BUILD_BUG_ON_ZERO(__ELANTS_FIELD_SIZE(_field) > 2) + \ + __ELANTS_FIELD_SIZE(_field)) +#define ELANTS_VERSION_ATTR(_field) \ + struct elants_version_attribute elants_ver_attr_##_field = { \ + .dattr = __ATTR(_field, S_IRUGO, \ + elants_version_attribute_show, NULL), \ + .field_offset = offsetof(struct elants_data, _field), \ + .field_size = __ELANTS_VERIFY_SIZE(_field), \ + } + +static ssize_t elants_version_attribute_show(struct device *dev, + struct device_attribute *dattr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct elants_data *ts = i2c_get_clientdata(client); + struct elants_version_attribute *attr = + container_of(dattr, struct elants_version_attribute, dattr); + u8 *field = (u8 *)((char *)ts + attr->field_offset); + unsigned int fmt_size; + unsigned int val; + + if (attr->field_size == 1) { + val = *field; + fmt_size = 2; /* 2 HEX digits */ + } else { + val = *(u16 *)field; + fmt_size = 4; /* 4 HEX digits */ + } + + return sprintf(buf, "%0*x\n", fmt_size, val); +} + +static ELANTS_VERSION_ATTR(fw_version); +static ELANTS_VERSION_ATTR(hw_version); +static ELANTS_VERSION_ATTR(test_version); +static ELANTS_VERSION_ATTR(solution_version); +static ELANTS_VERSION_ATTR(bc_version); +static ELANTS_VERSION_ATTR(iap_version); + +static struct attribute *elants_attributes[] = { + &dev_attr_calibrate.attr, + &dev_attr_update_fw.attr, + &dev_attr_iap_mode.attr, + + &elants_ver_attr_fw_version.dattr.attr, + &elants_ver_attr_hw_version.dattr.attr, + &elants_ver_attr_test_version.dattr.attr, + &elants_ver_attr_solution_version.dattr.attr, + &elants_ver_attr_bc_version.dattr.attr, + &elants_ver_attr_iap_version.dattr.attr, + NULL +}; + +static struct attribute_group elants_attribute_group = { + .attrs = elants_attributes, +}; + +static void elants_i2c_remove_sysfs_group(void *_data) +{ + struct elants_data *ts = _data; + + sysfs_remove_group(&ts->client->dev.kobj, &elants_attribute_group); +} + +static int elants_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + union i2c_smbus_data dummy; + struct elants_data *ts; + unsigned long irqflags; + int error; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, + "%s: i2c check functionality error\n", DEVICE_NAME); + return -ENXIO; + } + + /* Make sure there is something at this address */ + if (i2c_smbus_xfer(client->adapter, client->addr, 0, + I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &dummy) < 0) { + dev_err(&client->dev, "nothing at this address\n"); + return -ENXIO; + } + + ts = devm_kzalloc(&client->dev, sizeof(struct elants_data), GFP_KERNEL); + if (!ts) + return -ENOMEM; + + mutex_init(&ts->sysfs_mutex); + init_completion(&ts->cmd_done); + + ts->client = client; + i2c_set_clientdata(client, ts); + + error = elants_i2c_initialize(ts); + if (error) { + dev_err(&client->dev, "failed to initialize: %d\n", error); + return error; + } + + ts->input = devm_input_allocate_device(&client->dev); + if (!ts->input) { + dev_err(&client->dev, "Failed to allocate input device\n"); + return -ENOMEM; + } + + ts->input->name = "Elan Touchscreen"; + ts->input->id.bustype = BUS_I2C; + + __set_bit(BTN_TOUCH, ts->input->keybit); + __set_bit(EV_ABS, ts->input->evbit); + __set_bit(EV_KEY, ts->input->evbit); + + /* Single touch input params setup */ + input_set_abs_params(ts->input, ABS_X, 0, ts->x_max, 0, 0); + input_set_abs_params(ts->input, ABS_Y, 0, ts->y_max, 0, 0); + input_set_abs_params(ts->input, ABS_PRESSURE, 0, 255, 0, 0); + input_abs_set_res(ts->input, ABS_X, ts->x_res); + input_abs_set_res(ts->input, ABS_Y, ts->y_res); + + /* Multitouch input params setup */ + error = input_mt_init_slots(ts->input, MAX_CONTACT_NUM, + INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); + if (error) { + dev_err(&client->dev, + "failed to initialize MT slots: %d\n", error); + return error; + } + + input_set_abs_params(ts->input, ABS_MT_POSITION_X, 0, ts->x_max, 0, 0); + input_set_abs_params(ts->input, ABS_MT_POSITION_Y, 0, ts->y_max, 0, 0); + input_set_abs_params(ts->input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); + input_set_abs_params(ts->input, ABS_MT_PRESSURE, 0, 255, 0, 0); + input_abs_set_res(ts->input, ABS_MT_POSITION_X, ts->x_res); + input_abs_set_res(ts->input, ABS_MT_POSITION_Y, ts->y_res); + + input_set_drvdata(ts->input, ts); + + error = input_register_device(ts->input); + if (error) { + dev_err(&client->dev, + "unable to register input device: %d\n", error); + return error; + } + + /* + * Systems using device tree should set up interrupt via DTS, + * the rest will use the default falling edge interrupts. + */ + irqflags = client->dev.of_node ? 0 : IRQF_TRIGGER_FALLING; + + error = devm_request_threaded_irq(&client->dev, client->irq, + NULL, elants_i2c_irq, + irqflags | IRQF_ONESHOT, + client->name, ts); + if (error) { + dev_err(&client->dev, "Failed to register interrupt\n"); + return error; + } + + /* + * Systems using device tree should set up wakeup via DTS, + * the rest will configure device as wakeup source by default. + */ + if (!client->dev.of_node) + device_init_wakeup(&client->dev, true); + + error = sysfs_create_group(&client->dev.kobj, &elants_attribute_group); + if (error) { + dev_err(&client->dev, "failed to create sysfs attributes: %d\n", + error); + return error; + } + + error = devm_add_action(&client->dev, + elants_i2c_remove_sysfs_group, ts); + if (error) { + elants_i2c_remove_sysfs_group(ts); + dev_err(&client->dev, + "Failed to add sysfs cleanup action: %d\n", + error); + return error; + } + + return 0; +} + +static int __maybe_unused elants_i2c_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct elants_data *ts = i2c_get_clientdata(client); + const u8 set_sleep_cmd[] = { 0x54, 0x50, 0x00, 0x01 }; + int retry_cnt; + int error; + + /* Command not support in IAP recovery mode */ + if (ts->iap_mode != ELAN_IAP_OPERATIONAL) + return -EBUSY; + + disable_irq(client->irq); + + for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { + error = elants_i2c_send(client, set_sleep_cmd, + sizeof(set_sleep_cmd)); + if (!error) + break; + + dev_err(&client->dev, "suspend command failed: %d\n", error); + } + + if (device_may_wakeup(dev)) + ts->wake_irq_enabled = (enable_irq_wake(client->irq) == 0); + + return 0; +} + +static int __maybe_unused elants_i2c_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct elants_data *ts = i2c_get_clientdata(client); + const u8 set_active_cmd[] = { 0x54, 0x58, 0x00, 0x01 }; + int retry_cnt; + int error; + + if (device_may_wakeup(dev) && ts->wake_irq_enabled) + disable_irq_wake(client->irq); + + for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { + error = elants_i2c_send(client, set_active_cmd, + sizeof(set_active_cmd)); + if (!error) + break; + + dev_err(&client->dev, "resume command failed: %d\n", error); + } + + ts->state = ELAN_STATE_NORMAL; + enable_irq(client->irq); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(elants_i2c_pm_ops, + elants_i2c_suspend, elants_i2c_resume); + +static const struct i2c_device_id elants_i2c_id[] = { + { DEVICE_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, elants_i2c_id); + +#ifdef CONFIG_ACPI +static const struct acpi_device_id elants_acpi_id[] = { + { "ELAN0001", 0 }, + { } +}; +MODULE_DEVICE_TABLE(acpi, elants_acpi_id); +#endif + +#ifdef CONFIG_OF +static const struct of_device_id elants_of_match[] = { + { .compatible = "elan,ekth3500" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, elants_of_match); +#endif + +static struct i2c_driver elants_i2c_driver = { + .probe = elants_i2c_probe, + .id_table = elants_i2c_id, + .driver = { + .name = DEVICE_NAME, + .owner = THIS_MODULE, + .pm = &elants_i2c_pm_ops, + .acpi_match_table = ACPI_PTR(elants_acpi_id), + .of_match_table = of_match_ptr(elants_of_match), + }, +}; +module_i2c_driver(elants_i2c_driver); + +MODULE_AUTHOR("Scott Liu "); +MODULE_DESCRIPTION("Elan I2c Touchscreen driver"); +MODULE_VERSION(DRV_VERSION); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-59-g8ed1b From 9fd7fc34cfcaf9f6c932ee1710cce83da3b7bd59 Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Mon, 8 Dec 2014 09:33:26 +0100 Subject: locking/lglocks: Add documentation of current lglocks implementation Local/global locks are currently not documented anywhere other than in an somewhat out-of-date LWN article - this is an attempt to document the current state of lglocks. This patch is against linux-next 3.18.0-rc6 Signed-off-by: Nicholas Mc Guire Cc: Paul E. McKenney Cc: Carsten Emde Cc: Steven Rostedt Cc: Jonathan Corbet Cc: Linus Torvalds Cc: Andrew Morton Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20141208083326.GA29895@opentech.at Signed-off-by: Ingo Molnar --- Documentation/locking/lglock.txt | 166 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 Documentation/locking/lglock.txt (limited to 'Documentation') diff --git a/Documentation/locking/lglock.txt b/Documentation/locking/lglock.txt new file mode 100644 index 000000000000..a6971e34fabe --- /dev/null +++ b/Documentation/locking/lglock.txt @@ -0,0 +1,166 @@ +lglock - local/global locks for mostly local access patterns +------------------------------------------------------------ + +Origin: Nick Piggin's VFS scalability series introduced during + 2.6.35++ [1] [2] +Location: kernel/locking/lglock.c + include/linux/lglock.h +Users: currently only the VFS and stop_machine related code + +Design Goal: +------------ + +Improve scalability of globally used large data sets that are +distributed over all CPUs as per_cpu elements. + +To manage global data structures that are partitioned over all CPUs +as per_cpu elements but can be mostly handled by CPU local actions +lglock will be used where the majority of accesses are cpu local +reading and occasional cpu local writing with very infrequent +global write access. + + +* deal with things locally whenever possible + - very fast access to the local per_cpu data + - reasonably fast access to specific per_cpu data on a different + CPU +* while making global action possible when needed + - by expensive access to all CPUs locks - effectively + resulting in a globally visible critical section. + +Design: +------- + +Basically it is an array of per_cpu spinlocks with the +lg_local_lock/unlock accessing the local CPUs lock object and the +lg_local_lock_cpu/unlock_cpu accessing a remote CPUs lock object +the lg_local_lock has to disable preemption as migration protection so +that the reference to the local CPUs lock does not go out of scope. +Due to the lg_local_lock/unlock only touching cpu-local resources it +is fast. Taking the local lock on a different CPU will be more +expensive but still relatively cheap. + +One can relax the migration constraints by acquiring the current +CPUs lock with lg_local_lock_cpu, remember the cpu, and release that +lock at the end of the critical section even if migrated. This should +give most of the performance benefits without inhibiting migration +though needs careful considerations for nesting of lglocks and +consideration of deadlocks with lg_global_lock. + +The lg_global_lock/unlock locks all underlying spinlocks of all +possible CPUs (including those off-line). The preemption disable/enable +are needed in the non-RT kernels to prevent deadlocks like: + + on cpu 1 + + task A task B + lg_global_lock + got cpu 0 lock + <<<< preempt <<<< + lg_local_lock_cpu for cpu 0 + spin on cpu 0 lock + +On -RT this deadlock scenario is resolved by the arch_spin_locks in the +lglocks being replaced by rt_mutexes which resolve the above deadlock +by boosting the lock-holder. + + +Implementation: +--------------- + +The initial lglock implementation from Nick Piggin used some complex +macros to generate the lglock/brlock in lglock.h - they were later +turned into a set of functions by Andi Kleen [7]. The change to functions +was motivated by the presence of multiple lock users and also by them +being easier to maintain than the generating macros. This change to +functions is also the basis to eliminated the restriction of not +being initializeable in kernel modules (the remaining problem is that +locks are not explicitly initialized - see lockdep-design.txt) + +Declaration and initialization: +------------------------------- + + #include + + DEFINE_LGLOCK(name) + or: + DEFINE_STATIC_LGLOCK(name); + + lg_lock_init(&name, "lockdep_name_string"); + + on UP this is mapped to DEFINE_SPINLOCK(name) in both cases, note + also that as of 3.18-rc6 all declaration in use are of the _STATIC_ + variant (and it seems that the non-static was never in use). + lg_lock_init is initializing the lockdep map only. + +Usage: +------ + +From the locking semantics it is a spinlock. It could be called a +locality aware spinlock. lg_local_* behaves like a per_cpu +spinlock and lg_global_* like a global spinlock. +No surprises in the API. + + lg_local_lock(*lglock); + access to protected per_cpu object on this CPU + lg_local_unlock(*lglock); + + lg_local_lock_cpu(*lglock, cpu); + access to protected per_cpu object on other CPU cpu + lg_local_unlock_cpu(*lglock, cpu); + + lg_global_lock(*lglock); + access all protected per_cpu objects on all CPUs + lg_global_unlock(*lglock); + + There are no _trylock variants of the lglocks. + +Note that the lg_global_lock/unlock has to iterate over all possible +CPUs rather than the actually present CPUs or a CPU could go off-line +with a held lock [4] and that makes it very expensive. A discussion on +these issues can be found at [5] + +Constraints: +------------ + + * currently the declaration of lglocks in kernel modules is not + possible, though this should be doable with little change. + * lglocks are not recursive. + * suitable for code that can do most operations on the CPU local + data and will very rarely need the global lock + * lg_global_lock/unlock is *very* expensive and does not scale + * on UP systems all lg_* primitives are simply spinlocks + * in PREEMPT_RT the spinlock becomes an rt-mutex and can sleep but + does not change the tasks state while sleeping [6]. + * in PREEMPT_RT the preempt_disable/enable in lg_local_lock/unlock + is downgraded to a migrate_disable/enable, the other + preempt_disable/enable are downgraded to barriers [6]. + The deadlock noted for non-RT above is resolved due to rt_mutexes + boosting the lock-holder in this case which arch_spin_locks do + not do. + +lglocks were designed for very specific problems in the VFS and probably +only are the right answer in these corner cases. Any new user that looks +at lglocks probably wants to look at the seqlock and RCU alternatives as +her first choice. There are also efforts to resolve the RCU issues that +currently prevent using RCU in place of view remaining lglocks. + +Note on brlock history: +----------------------- + +The 'Big Reader' read-write spinlocks were originally introduced by +Ingo Molnar in 2000 (2.4/2.5 kernel series) and removed in 2003. They +later were introduced by the VFS scalability patch set in 2.6 series +again as the "big reader lock" brlock [2] variant of lglock which has +been replaced by seqlock primitives or by RCU based primitives in the +3.13 kernel series as was suggested in [3] in 2003. The brlock was +entirely removed in the 3.13 kernel series. + +Link: 1 http://lkml.org/lkml/2010/8/2/81 +Link: 2 http://lwn.net/Articles/401738/ +Link: 3 http://lkml.org/lkml/2003/3/9/205 +Link: 4 https://lkml.org/lkml/2011/8/24/185 +Link: 5 http://lkml.org/lkml/2011/12/18/189 +Link: 6 https://www.kernel.org/pub/linux/kernel/projects/rt/ + patch series - lglocks-rt.patch.patch +Link: 7 http://lkml.org/lkml/2012/3/5/26 -- cgit v1.2.3-59-g8ed1b From 8e2596e81a9dd8f9efcf78476f3990f211e25edb Mon Sep 17 00:00:00 2001 From: Doug Anderson Date: Fri, 5 Dec 2014 10:49:39 -0800 Subject: i2c: designware: Fix falling time bindings doc In (6468276 i2c: designware: make SCL and SDA falling time configurable) new device tree properties were added for setting the falling time of SDA and SCL. The device tree bindings doc had a typo in it: it forgot the "-ns" suffix for both properies in the prose of the bindings. I assume this is a typo because: * The source code includes the "-ns" * The example in the bindings includes the "-ns". Fix the typo. Signed-off-by: Doug Anderson Fixes: 6468276b2206 ("i2c: designware: make SCL and SDA falling time configurable") Acked-by: Romain Baeriswyl Signed-off-by: Wolfram Sang Cc: stable@kernel.org --- Documentation/devicetree/bindings/i2c/i2c-designware.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/i2c/i2c-designware.txt b/Documentation/devicetree/bindings/i2c/i2c-designware.txt index 5199b0c8cf7a..fee26dc3e858 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-designware.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-designware.txt @@ -14,10 +14,10 @@ Optional properties : - i2c-sda-hold-time-ns : should contain the SDA hold time in nanoseconds. This option is only supported in hardware blocks version 1.11a or newer. - - i2c-scl-falling-time : should contain the SCL falling time in nanoseconds. + - i2c-scl-falling-time-ns : should contain the SCL falling time in nanoseconds. This value which is by default 300ns is used to compute the tLOW period. - - i2c-sda-falling-time : should contain the SDA falling time in nanoseconds. + - i2c-sda-falling-time-ns : should contain the SDA falling time in nanoseconds. This value which is by default 300ns is used to compute the tHIGH period. Example : -- cgit v1.2.3-59-g8ed1b From 9b64c09bb960b4ccae2a42e204cd70f83b115e3d Mon Sep 17 00:00:00 2001 From: John de la Garza Date: Sat, 6 Dec 2014 16:38:57 -0500 Subject: kobject: grammar fix Signed-off-by: John de la Garza Signed-off-by: Jonathan Corbet --- Documentation/kobject.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/kobject.txt b/Documentation/kobject.txt index f87241dfed87..1be59a3a521c 100644 --- a/Documentation/kobject.txt +++ b/Documentation/kobject.txt @@ -173,7 +173,7 @@ This should be done only after any attributes or children of the kobject have been initialized properly, as userspace will instantly start to look for them when this call happens. -When the kobject is removed from the kernel (details on how to do that is +When the kobject is removed from the kernel (details on how to do that are below), the uevent for KOBJ_REMOVE will be automatically created by the kobject core, so the caller does not have to worry about doing that by hand. -- cgit v1.2.3-59-g8ed1b From 907a6d5824599d09e986105a5a880d119a996c4b Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Fri, 5 Dec 2014 10:15:03 -0800 Subject: hwmon: (tmp401) Detect TMP435 on all addresses it supports TMP435 supports a range of I2C addresses, not just 0x4c. Cc: Patrick Titiano Cc: Bartosz Golaszewski Reviewed-by: Jean Delvare Signed-off-by: Guenter Roeck --- Documentation/hwmon/tmp401 | 2 +- drivers/hwmon/tmp401.c | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/hwmon/tmp401 b/Documentation/hwmon/tmp401 index 445ff7b0f6a7..8eb88e974055 100644 --- a/Documentation/hwmon/tmp401 +++ b/Documentation/hwmon/tmp401 @@ -20,7 +20,7 @@ Supported chips: Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp432.html * Texas Instruments TMP435 Prefix: 'tmp435' - Addresses scanned: I2C 0x4c + Addresses scanned: I2C 0x37, 0x48 - 0x4f Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp435.html Authors: diff --git a/drivers/hwmon/tmp401.c b/drivers/hwmon/tmp401.c index f2182ee80830..99664ebc738d 100644 --- a/drivers/hwmon/tmp401.c +++ b/drivers/hwmon/tmp401.c @@ -44,7 +44,8 @@ #include /* Addresses to scan */ -static const unsigned short normal_i2c[] = { 0x4c, 0x4d, 0x4e, I2C_CLIENT_END }; +static const unsigned short normal_i2c[] = { 0x37, 0x48, 0x49, 0x4a, 0x4c, 0x4d, + 0x4e, 0x4f, I2C_CLIENT_END }; enum chips { tmp401, tmp411, tmp431, tmp432, tmp435 }; @@ -679,18 +680,16 @@ static int tmp401_detect(struct i2c_client *client, kind = tmp411; break; case TMP431_DEVICE_ID: - if (client->addr == 0x4e) + if (client->addr != 0x4c && client->addr != 0x4d) return -ENODEV; kind = tmp431; break; case TMP432_DEVICE_ID: - if (client->addr == 0x4e) + if (client->addr != 0x4c && client->addr != 0x4d) return -ENODEV; kind = tmp432; break; case TMP435_DEVICE_ID: - if (client->addr != 0x4c) - return -ENODEV; kind = tmp435; break; default: -- cgit v1.2.3-59-g8ed1b From 138f9ebb9755a8cf09fd6a9ff8d011aaf5fb478f Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 20 Oct 2014 16:17:17 +1000 Subject: drm: add tile_group support. (v3) A tile group is an identifier shared by a single monitor, DisplayID topology has 8 bytes we can use for this, just use those for now until something else comes up in the future. We assign these to an idr and use the idr to tell userspace what connectors are in the same tile group. DisplayID v1.3 says the serial number must be unique for displays from the same manufacturer. v2: destroy idr (dvdhrm) add docbook (danvet) airlied:- not sure how to make docbook add fns to tile group section. v3: fix missing unlock. Reviewed-by: Daniel Vetter Signed-off-by: Dave Airlie --- Documentation/DocBook/drm.tmpl | 4 ++ drivers/gpu/drm/drm_crtc.c | 99 ++++++++++++++++++++++++++++++++++++++++++ include/drm/drm_crtc.h | 16 +++++++ 3 files changed, 119 insertions(+) (limited to 'Documentation') diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 56e2a9b65c68..bc4b5ab5848e 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -2412,6 +2412,10 @@ void intel_crt_init(struct drm_device *dev) !Edrivers/gpu/drm/drm_plane_helper.c !Pdrivers/gpu/drm/drm_plane_helper.c overview + + Tile group +!Pdrivers/gpu/drm/drm_crtc.c Tile group + diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index de79283eaea7..0d1eaa9966e9 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -5152,6 +5152,7 @@ void drm_mode_config_init(struct drm_device *dev) INIT_LIST_HEAD(&dev->mode_config.property_blob_list); INIT_LIST_HEAD(&dev->mode_config.plane_list); idr_init(&dev->mode_config.crtc_idr); + idr_init(&dev->mode_config.tile_idr); drm_modeset_lock_all(dev); drm_mode_create_standard_connector_properties(dev); @@ -5239,6 +5240,7 @@ void drm_mode_config_cleanup(struct drm_device *dev) crtc->funcs->destroy(crtc); } + idr_destroy(&dev->mode_config.tile_idr); idr_destroy(&dev->mode_config.crtc_idr); drm_modeset_lock_fini(&dev->mode_config.connection_mutex); } @@ -5261,3 +5263,100 @@ struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev, supported_rotations); } EXPORT_SYMBOL(drm_mode_create_rotation_property); + +/** + * DOC: Tile group + * + * Tile groups are used to represent tiled monitors with a unique + * integer identifier. Tiled monitors using DisplayID v1.3 have + * a unique 8-byte handle, we store this in a tile group, so we + * have a common identifier for all tiles in a monitor group. + */ +static void drm_tile_group_free(struct kref *kref) +{ + struct drm_tile_group *tg = container_of(kref, struct drm_tile_group, refcount); + struct drm_device *dev = tg->dev; + mutex_lock(&dev->mode_config.idr_mutex); + idr_remove(&dev->mode_config.tile_idr, tg->id); + mutex_unlock(&dev->mode_config.idr_mutex); + kfree(tg); +} + +/** + * drm_mode_put_tile_group - drop a reference to a tile group. + * @dev: DRM device + * @tg: tile group to drop reference to. + * + * drop reference to tile group and free if 0. + */ +void drm_mode_put_tile_group(struct drm_device *dev, + struct drm_tile_group *tg) +{ + kref_put(&tg->refcount, drm_tile_group_free); +} + +/** + * drm_mode_get_tile_group - get a reference to an existing tile group + * @dev: DRM device + * @topology: 8-bytes unique per monitor. + * + * Use the unique bytes to get a reference to an existing tile group. + * + * RETURNS: + * tile group or NULL if not found. + */ +struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev, + char topology[8]) +{ + struct drm_tile_group *tg; + int id; + mutex_lock(&dev->mode_config.idr_mutex); + idr_for_each_entry(&dev->mode_config.tile_idr, tg, id) { + if (!memcmp(tg->group_data, topology, 8)) { + if (!kref_get_unless_zero(&tg->refcount)) + tg = NULL; + mutex_unlock(&dev->mode_config.idr_mutex); + return tg; + } + } + mutex_unlock(&dev->mode_config.idr_mutex); + return NULL; +} + +/** + * drm_mode_create_tile_group - create a tile group from a displayid description + * @dev: DRM device + * @topology: 8-bytes unique per monitor. + * + * Create a tile group for the unique monitor, and get a unique + * identifier for the tile group. + * + * RETURNS: + * new tile group or error. + */ +struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev, + char topology[8]) +{ + struct drm_tile_group *tg; + int ret; + + tg = kzalloc(sizeof(*tg), GFP_KERNEL); + if (!tg) + return ERR_PTR(-ENOMEM); + + kref_init(&tg->refcount); + memcpy(tg->group_data, topology, 8); + tg->dev = dev; + + mutex_lock(&dev->mode_config.idr_mutex); + ret = idr_alloc(&dev->mode_config.tile_idr, tg, 1, 0, GFP_KERNEL); + if (ret >= 0) { + tg->id = ret; + } else { + kfree(tg); + tg = ERR_PTR(ret); + } + + mutex_unlock(&dev->mode_config.idr_mutex); + return tg; +} diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index dd2c16e43333..8f760a2373f9 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -137,6 +137,14 @@ struct drm_display_info { u8 cea_rev; }; +/* data corresponds to displayid vend/prod/serial */ +struct drm_tile_group { + struct kref refcount; + struct drm_device *dev; + int id; + u8 group_data[8]; +}; + struct drm_framebuffer_funcs { /* note: use drm_framebuffer_remove() */ void (*destroy)(struct drm_framebuffer *framebuffer); @@ -978,6 +986,7 @@ struct drm_mode_config { struct drm_modeset_acquire_ctx *acquire_ctx; /* for legacy _lock_all() / _unlock_all() */ struct mutex idr_mutex; /* for IDR management */ struct idr crtc_idr; /* use this idr for all IDs, fb, crtc, connector, modes - just makes life easier */ + struct idr tile_idr; /* use this idr for all IDs, fb, crtc, connector, modes - just makes life easier */ /* this is limited to one for now */ struct mutex fb_lock; /* proctects global and per-file fb lists */ @@ -1326,6 +1335,13 @@ extern void drm_set_preferred_mode(struct drm_connector *connector, extern int drm_edid_header_is_valid(const u8 *raw_edid); extern bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid); extern bool drm_edid_is_valid(struct edid *edid); + +extern struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev, + char topology[8]); +extern struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev, + char topology[8]); +extern void drm_mode_put_tile_group(struct drm_device *dev, + struct drm_tile_group *tg); struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev, int hsize, int vsize, int fresh, bool rb); -- cgit v1.2.3-59-g8ed1b From 6f134d7bb4347ab4c66ef123efb838fedb54186f Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 20 Oct 2014 16:30:50 +1000 Subject: drm/tile: expose the tile property to userspace (v3) This takes the tiling info from the connector and exposes it to userspace, as a blob object in a connector property. The contents of the blob is ABI. v2: add property + function documentation. v3: move property setup from previous patch. add boilerplate + fix long line (Daniel) Reviewed-by: Daniel Vetter Signed-off-by: Dave Airlie --- Documentation/DocBook/drm.tmpl | 9 ++++++- drivers/gpu/drm/drm_crtc.c | 51 +++++++++++++++++++++++++++++++++++ drivers/gpu/drm/drm_dp_mst_topology.c | 1 + drivers/gpu/drm/i915/intel_dp_mst.c | 2 ++ include/drm/drm_crtc.h | 4 +++ 5 files changed, 66 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index bc4b5ab5848e..60c1063d4178 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -2551,7 +2551,7 @@ void intel_crt_init(struct drm_device *dev) DRM - Generic + Generic “EDID” BLOB | IMMUTABLE 0 @@ -2573,6 +2573,13 @@ void intel_crt_init(struct drm_device *dev) Contains topology path to a connector. + “TILE” + BLOB | IMMUTABLE + 0 + Connector + Contains tiling information for a connector. + + Plane “type” ENUM | IMMUTABLE diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index eb89327fb737..4a44f894f631 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1344,6 +1344,11 @@ static int drm_mode_create_standard_connector_properties(struct drm_device *dev) "PATH", 0); dev->mode_config.path_property = dev_path; + dev->mode_config.tile_property = drm_property_create(dev, + DRM_MODE_PROP_BLOB | + DRM_MODE_PROP_IMMUTABLE, + "TILE", 0); + return 0; } @@ -4087,6 +4092,52 @@ int drm_mode_connector_set_path_property(struct drm_connector *connector, } EXPORT_SYMBOL(drm_mode_connector_set_path_property); +/** + * drm_mode_connector_set_tile_property - set tile property on connector + * @connector: connector to set property on. + * + * This looks up the tile information for a connector, and creates a + * property for userspace to parse if it exists. The property is of + * the form of 8 integers using ':' as a separator. + * + * Returns: + * Zero on success, errno on failure. + */ +int drm_mode_connector_set_tile_property(struct drm_connector *connector) +{ + struct drm_device *dev = connector->dev; + int ret, size; + char tile[256]; + + if (connector->tile_blob_ptr) + drm_property_destroy_blob(dev, connector->tile_blob_ptr); + + if (!connector->has_tile) { + connector->tile_blob_ptr = NULL; + ret = drm_object_property_set_value(&connector->base, + dev->mode_config.tile_property, 0); + return ret; + } + + snprintf(tile, 256, "%d:%d:%d:%d:%d:%d:%d:%d", + connector->tile_group->id, connector->tile_is_single_monitor, + connector->num_h_tile, connector->num_v_tile, + connector->tile_h_loc, connector->tile_v_loc, + connector->tile_h_size, connector->tile_v_size); + size = strlen(tile) + 1; + + connector->tile_blob_ptr = drm_property_create_blob(connector->dev, + size, tile); + if (!connector->tile_blob_ptr) + return -EINVAL; + + ret = drm_object_property_set_value(&connector->base, + dev->mode_config.tile_property, + connector->tile_blob_ptr->base.id); + return ret; +} +EXPORT_SYMBOL(drm_mode_connector_set_tile_property); + /** * drm_mode_connector_update_edid_property - update the edid property of a connector * @connector: drm connector diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 0a9d3aad3cba..9a5b68717ec8 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -2236,6 +2236,7 @@ struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_ else edid = drm_get_edid(connector, &port->aux.ddc); + drm_mode_connector_set_tile_property(connector); drm_dp_put_port(port); return edid; } diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index 428bb3041621..7f8c6a66680a 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c @@ -414,6 +414,8 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo intel_dp_add_properties(intel_dp, connector); drm_object_attach_property(&connector->base, dev->mode_config.path_property, 0); + drm_object_attach_property(&connector->base, dev->mode_config.tile_property, 0); + drm_mode_connector_set_path_property(connector, pathprop); drm_reinit_primary_mode_group(dev); mutex_lock(&dev->mode_config.mutex); diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 01744ed79250..b86329813ad3 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -651,6 +651,8 @@ struct drm_connector { struct drm_property_blob *path_blob_ptr; + struct drm_property_blob *tile_blob_ptr; + uint8_t polled; /* DRM_CONNECTOR_POLL_* */ /* requested DPMS state */ @@ -1048,6 +1050,7 @@ struct drm_mode_config { struct drm_property *edid_property; struct drm_property *dpms_property; struct drm_property *path_property; + struct drm_property *tile_property; struct drm_property *plane_type_property; struct drm_property *rotation_property; @@ -1217,6 +1220,7 @@ extern void drm_mode_config_cleanup(struct drm_device *dev); extern int drm_mode_connector_set_path_property(struct drm_connector *connector, const char *path); +int drm_mode_connector_set_tile_property(struct drm_connector *connector); extern int drm_mode_connector_update_edid_property(struct drm_connector *connector, const struct edid *edid); -- cgit v1.2.3-59-g8ed1b From 829ae9d611651467fe6cd7be834bd33ca6b28dfe Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Sun, 30 Nov 2014 22:22:34 -0500 Subject: net-timestamp: allow reading recv cmsg on errqueue with origin tstamp Allow reading of timestamps and cmsg at the same time on all relevant socket families. One use is to correlate timestamps with egress device, by asking for cmsg IP_PKTINFO. on AF_INET sockets, call the relevant function (ip_cmsg_recv). To avoid changing legacy expectations, only do so if the caller sets a new timestamping flag SOF_TIMESTAMPING_OPT_CMSG. on AF_INET6 sockets, IPV6_PKTINFO and all other recv cmsg are already returned for all origins. only change is to set ifindex, which is not initialized for all error origins. In both cases, only generate the pktinfo message if an ifindex is known. This is not the case for ACK timestamps. The difference between the protocol families is probably a historical accident as a result of the different conditions for generating cmsg in the relevant ip(v6)_recv_error function: ipv4: if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP) { ipv6: if (serr->ee.ee_origin != SO_EE_ORIGIN_LOCAL) { At one time, this was the same test bar for the ICMP/ICMP6 distinction. This is no longer true. Signed-off-by: Willem de Bruijn ---- Changes v1 -> v2 large rewrite - integrate with existing pktinfo cmsg generation code - on ipv4: only send with new flag, to maintain legacy behavior - on ipv6: send at most a single pktinfo cmsg - on ipv6: initialize fields if not yet initialized The recv cmsg interfaces are also relevant to the discussion of whether looping packet headers is problematic. For v6, cmsgs that identify many headers are already returned. This patch expands that to v4. If it sounds reasonable, I will follow with patches 1. request timestamps without payload with SOF_TIMESTAMPING_OPT_TSONLY (http://patchwork.ozlabs.org/patch/366967/) 2. sysctl to conditionally drop all timestamps that have payload or cmsg from users without CAP_NET_RAW. Signed-off-by: David S. Miller --- Documentation/networking/timestamping.txt | 12 +++++++++++- include/uapi/linux/net_tstamp.h | 3 ++- net/ipv4/ip_sockglue.c | 22 ++++++++++++++++++++-- net/ipv6/datagram.c | 21 +++++++++++++++++++-- 4 files changed, 52 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/timestamping.txt b/Documentation/networking/timestamping.txt index 1d6d02d6ba52..b08e27261ff9 100644 --- a/Documentation/networking/timestamping.txt +++ b/Documentation/networking/timestamping.txt @@ -122,7 +122,7 @@ SOF_TIMESTAMPING_RAW_HARDWARE: 1.3.3 Timestamp Options -The interface supports one option +The interface supports the options SOF_TIMESTAMPING_OPT_ID: @@ -145,6 +145,16 @@ SOF_TIMESTAMPING_OPT_ID: stream sockets, it increments with every byte. +SOF_TIMESTAMPING_OPT_CMSG: + + Support recv() cmsg for all timestamped packets. Control messages + are already supported unconditionally on all packets with receive + timestamps and on IPv6 packets with transmit timestamp. This option + extends them to IPv4 packets with transmit timestamp. One use case + is to correlate packets with their egress device, by enabling socket + option IP_PKTINFO simultaneously. + + 1.4 Bytestream Timestamps The SO_TIMESTAMPING interface supports timestamping of bytes in a diff --git a/include/uapi/linux/net_tstamp.h b/include/uapi/linux/net_tstamp.h index ff354021bb69..edbc888ceb51 100644 --- a/include/uapi/linux/net_tstamp.h +++ b/include/uapi/linux/net_tstamp.h @@ -23,8 +23,9 @@ enum { SOF_TIMESTAMPING_OPT_ID = (1<<7), SOF_TIMESTAMPING_TX_SCHED = (1<<8), SOF_TIMESTAMPING_TX_ACK = (1<<9), + SOF_TIMESTAMPING_OPT_CMSG = (1<<10), - SOF_TIMESTAMPING_LAST = SOF_TIMESTAMPING_TX_ACK, + SOF_TIMESTAMPING_LAST = SOF_TIMESTAMPING_OPT_CMSG, SOF_TIMESTAMPING_MASK = (SOF_TIMESTAMPING_LAST - 1) | SOF_TIMESTAMPING_LAST }; diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 59eba6c7a512..640f26c6a9fe 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -399,6 +399,22 @@ void ip_local_error(struct sock *sk, int err, __be32 daddr, __be16 port, u32 inf kfree_skb(skb); } +static bool ipv4_pktinfo_prepare_errqueue(const struct sock *sk, + const struct sk_buff *skb, + int ee_origin) +{ + struct in_pktinfo *info = PKTINFO_SKB_CB(skb); + + if ((ee_origin != SO_EE_ORIGIN_TIMESTAMPING) || + (!(sk->sk_tsflags & SOF_TIMESTAMPING_OPT_CMSG)) || + (!skb->dev)) + return false; + + info->ipi_spec_dst.s_addr = ip_hdr(skb)->saddr; + info->ipi_ifindex = skb->dev->ifindex; + return true; +} + /* * Handle MSG_ERRQUEUE */ @@ -446,7 +462,9 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err)); sin = &errhdr.offender; sin->sin_family = AF_UNSPEC; - if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP) { + + if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP || + ipv4_pktinfo_prepare_errqueue(sk, skb, serr->ee.ee_origin)) { struct inet_sock *inet = inet_sk(sk); sin->sin_family = AF_INET; @@ -1051,7 +1069,7 @@ e_inval: } /** - * ipv4_pktinfo_prepare - transfert some info from rtable to skb + * ipv4_pktinfo_prepare - transfer some info from rtable to skb * @sk: socket * @skb: buffer * diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index cc1139687fd7..2464a00e36ab 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -325,6 +325,16 @@ void ipv6_local_rxpmtu(struct sock *sk, struct flowi6 *fl6, u32 mtu) kfree_skb(skb); } +static void ip6_datagram_prepare_pktinfo_errqueue(struct sk_buff *skb) +{ + int ifindex = skb->dev ? skb->dev->ifindex : -1; + + if (skb->protocol == htons(ETH_P_IPV6)) + IP6CB(skb)->iif = ifindex; + else + PKTINFO_SKB_CB(skb)->ipi_ifindex = ifindex; +} + /* * Handle MSG_ERRQUEUE */ @@ -388,8 +398,12 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) sin->sin6_family = AF_INET6; sin->sin6_flowinfo = 0; sin->sin6_port = 0; - if (np->rxopt.all) + if (np->rxopt.all) { + if (serr->ee.ee_origin != SO_EE_ORIGIN_ICMP && + serr->ee.ee_origin != SO_EE_ORIGIN_ICMP6) + ip6_datagram_prepare_pktinfo_errqueue(skb); ip6_datagram_recv_common_ctl(sk, msg, skb); + } if (skb->protocol == htons(ETH_P_IPV6)) { sin->sin6_addr = ipv6_hdr(skb)->saddr; if (np->rxopt.all) @@ -491,7 +505,10 @@ void ip6_datagram_recv_common_ctl(struct sock *sk, struct msghdr *msg, ipv6_addr_set_v4mapped(ip_hdr(skb)->daddr, &src_info.ipi6_addr); } - put_cmsg(msg, SOL_IPV6, IPV6_PKTINFO, sizeof(src_info), &src_info); + + if (src_info.ipi6_ifindex >= 0) + put_cmsg(msg, SOL_IPV6, IPV6_PKTINFO, + sizeof(src_info), &src_info); } } -- cgit v1.2.3-59-g8ed1b From cbd3aad5ce66f5a266a185aa37e0eb9be9ba4154 Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Sun, 30 Nov 2014 22:22:35 -0500 Subject: net-timestamp: expand documentation and test Documentation: expand explanation of timestamp counter Test: new: flag -I requests and prints PKTINFO new: flag -x prints payload (possibly truncated) fix: remove pretty print that breaks common flag '-l 1' Signed-off-by: Willem de Bruijn Signed-off-by: David S. Miller --- Documentation/networking/timestamping.txt | 23 ++++-- .../networking/timestamping/txtimestamp.c | 90 +++++++++++++++++++--- 2 files changed, 93 insertions(+), 20 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/timestamping.txt b/Documentation/networking/timestamping.txt index b08e27261ff9..a5c784c89312 100644 --- a/Documentation/networking/timestamping.txt +++ b/Documentation/networking/timestamping.txt @@ -130,19 +130,26 @@ SOF_TIMESTAMPING_OPT_ID: have multiple concurrent timestamping requests outstanding. Packets can be reordered in the transmit path, for instance in the packet scheduler. In that case timestamps will be queued onto the error - queue out of order from the original send() calls. This option - embeds a counter that is incremented at send() time, to order - timestamps within a flow. + queue out of order from the original send() calls. It is not always + possible to uniquely match timestamps to the original send() calls + based on timestamp order or payload inspection alone, then. + + This option associates each packet at send() with a unique + identifier and returns that along with the timestamp. The identifier + is derived from a per-socket u32 counter (that wraps). For datagram + sockets, the counter increments with each sent packet. For stream + sockets, it increments with every byte. + + The counter starts at zero. It is initialized the first time that + the socket option is enabled. It is reset each time the option is + enabled after having been disabled. Resetting the counter does not + change the identifiers of existing packets in the system. This option is implemented only for transmit timestamps. There, the timestamp is always looped along with a struct sock_extended_err. The option modifies field ee_data to pass an id that is unique among all possibly concurrently outstanding timestamp requests for - that socket. In practice, it is a monotonically increasing u32 - (that wraps). - - In datagram sockets, the counter increments on each send call. In - stream sockets, it increments with every byte. + that socket. SOF_TIMESTAMPING_OPT_CMSG: diff --git a/Documentation/networking/timestamping/txtimestamp.c b/Documentation/networking/timestamping/txtimestamp.c index b32fc2a07734..876f71c5625a 100644 --- a/Documentation/networking/timestamping/txtimestamp.c +++ b/Documentation/networking/timestamping/txtimestamp.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -58,6 +59,14 @@ #include #include +/* ugly hack to work around netinet/in.h and linux/ipv6.h conflicts */ +#ifndef in6_pktinfo +struct in6_pktinfo { + struct in6_addr ipi6_addr; + int ipi6_ifindex; +}; +#endif + /* command line parameters */ static int cfg_proto = SOCK_STREAM; static int cfg_ipproto = IPPROTO_TCP; @@ -65,6 +74,8 @@ static int cfg_num_pkts = 4; static int do_ipv4 = 1; static int do_ipv6 = 1; static int cfg_payload_len = 10; +static bool cfg_show_payload; +static bool cfg_do_pktinfo; static uint16_t dest_port = 9000; static struct sockaddr_in daddr; @@ -131,6 +142,30 @@ static void print_timestamp(struct scm_timestamping *tss, int tstype, __print_timestamp(tsname, &tss->ts[0], tskey, payload_len); } +/* TODO: convert to check_and_print payload once API is stable */ +static void print_payload(char *data, int len) +{ + int i; + + if (len > 70) + len = 70; + + fprintf(stderr, "payload: "); + for (i = 0; i < len; i++) + fprintf(stderr, "%02hhx ", data[i]); + fprintf(stderr, "\n"); +} + +static void print_pktinfo(int family, int ifindex, void *saddr, void *daddr) +{ + char sa[INET6_ADDRSTRLEN], da[INET6_ADDRSTRLEN]; + + fprintf(stderr, " pktinfo: ifindex=%u src=%s dst=%s\n", + ifindex, + saddr ? inet_ntop(family, saddr, sa, sizeof(sa)) : "unknown", + daddr ? inet_ntop(family, daddr, da, sizeof(da)) : "unknown"); +} + static void __poll(int fd) { struct pollfd pollfd; @@ -156,10 +191,9 @@ static void __recv_errmsg_cmsg(struct msghdr *msg, int payload_len) cm->cmsg_type == SCM_TIMESTAMPING) { tss = (void *) CMSG_DATA(cm); } else if ((cm->cmsg_level == SOL_IP && - cm->cmsg_type == IP_RECVERR) || - (cm->cmsg_level == SOL_IPV6 && - cm->cmsg_type == IPV6_RECVERR)) { - + cm->cmsg_type == IP_RECVERR) || + (cm->cmsg_level == SOL_IPV6 && + cm->cmsg_type == IPV6_RECVERR)) { serr = (void *) CMSG_DATA(cm); if (serr->ee_errno != ENOMSG || serr->ee_origin != SO_EE_ORIGIN_TIMESTAMPING) { @@ -168,6 +202,16 @@ static void __recv_errmsg_cmsg(struct msghdr *msg, int payload_len) serr->ee_origin); serr = NULL; } + } else if (cm->cmsg_level == SOL_IP && + cm->cmsg_type == IP_PKTINFO) { + struct in_pktinfo *info = (void *) CMSG_DATA(cm); + print_pktinfo(AF_INET, info->ipi_ifindex, + &info->ipi_spec_dst, &info->ipi_addr); + } else if (cm->cmsg_level == SOL_IPV6 && + cm->cmsg_type == IPV6_PKTINFO) { + struct in6_pktinfo *info6 = (void *) CMSG_DATA(cm); + print_pktinfo(AF_INET6, info6->ipi6_ifindex, + NULL, &info6->ipi6_addr); } else fprintf(stderr, "unknown cmsg %d,%d\n", cm->cmsg_level, cm->cmsg_type); @@ -206,7 +250,11 @@ static int recv_errmsg(int fd) if (ret == -1 && errno != EAGAIN) error(1, errno, "recvmsg"); - __recv_errmsg_cmsg(&msg, ret); + if (ret > 0) { + __recv_errmsg_cmsg(&msg, ret); + if (cfg_show_payload) + print_payload(data, cfg_payload_len); + } free(data); return ret == -1; @@ -215,9 +263,9 @@ static int recv_errmsg(int fd) static void do_test(int family, unsigned int opt) { char *buf; - int fd, i, val, total_len; + int fd, i, val = 1, total_len; - if (family == IPPROTO_IPV6 && cfg_proto != SOCK_STREAM) { + if (family == AF_INET6 && cfg_proto != SOCK_STREAM) { /* due to lack of checksum generation code */ fprintf(stderr, "test: skipping datagram over IPv6\n"); return; @@ -239,7 +287,6 @@ static void do_test(int family, unsigned int opt) error(1, errno, "socket"); if (cfg_proto == SOCK_STREAM) { - val = 1; if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*) &val, sizeof(val))) error(1, 0, "setsockopt no nagle"); @@ -253,7 +300,20 @@ static void do_test(int family, unsigned int opt) } } + if (cfg_do_pktinfo) { + if (family == AF_INET6) { + if (setsockopt(fd, SOL_IPV6, IPV6_RECVPKTINFO, + &val, sizeof(val))) + error(1, errno, "setsockopt pktinfo ipv6"); + } else { + if (setsockopt(fd, SOL_IP, IP_PKTINFO, + &val, sizeof(val))) + error(1, errno, "setsockopt pktinfo ipv4"); + } + } + opt |= SOF_TIMESTAMPING_SOFTWARE | + SOF_TIMESTAMPING_OPT_CMSG | SOF_TIMESTAMPING_OPT_ID; if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPING, (char *) &opt, sizeof(opt))) @@ -262,8 +322,6 @@ static void do_test(int family, unsigned int opt) for (i = 0; i < cfg_num_pkts; i++) { memset(&ts_prev, 0, sizeof(ts_prev)); memset(buf, 'a' + i, total_len); - buf[total_len - 2] = '\n'; - buf[total_len - 1] = '\0'; if (cfg_proto == SOCK_RAW) { struct udphdr *udph; @@ -324,11 +382,13 @@ static void __attribute__((noreturn)) usage(const char *filepath) " -4: only IPv4\n" " -6: only IPv6\n" " -h: show this message\n" + " -I: request PKTINFO\n" " -l N: send N bytes at a time\n" " -r: use raw\n" " -R: use raw (IP_HDRINCL)\n" " -p N: connect to port N\n" - " -u: use udp\n", + " -u: use udp\n" + " -x: show payload (up to 70 bytes)\n", filepath); exit(1); } @@ -338,7 +398,7 @@ static void parse_opt(int argc, char **argv) int proto_count = 0; char c; - while ((c = getopt(argc, argv, "46hl:p:rRu")) != -1) { + while ((c = getopt(argc, argv, "46hIl:p:rRux")) != -1) { switch (c) { case '4': do_ipv6 = 0; @@ -346,6 +406,9 @@ static void parse_opt(int argc, char **argv) case '6': do_ipv4 = 0; break; + case 'I': + cfg_do_pktinfo = true; + break; case 'r': proto_count++; cfg_proto = SOCK_RAW; @@ -367,6 +430,9 @@ static void parse_opt(int argc, char **argv) case 'p': dest_port = strtoul(optarg, NULL, 10); break; + case 'x': + cfg_show_payload = true; + break; case 'h': default: usage(argv[0]); -- cgit v1.2.3-59-g8ed1b From 829b030e58f8349a63909c0fff2fa1913d79314c Mon Sep 17 00:00:00 2001 From: Sean Paul Date: Tue, 2 Dec 2014 17:39:12 -0800 Subject: backlight: lp855x: Add supply regulator to lp855x MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds a supply regulator to the lp855x platform data to facilitate powering on/off the 3V rail attached to the controller. Cc: Stéphane Marchesin Cc: Aaron Durbin Signed-off-by: Sean Paul Acked-by: Milo Kim Acked-by: Bryan Wu Acked-by: Jingoo Han Signed-off-by: Lee Jones --- .../devicetree/bindings/video/backlight/lp855x.txt | 2 ++ drivers/video/backlight/lp855x_bl.c | 18 ++++++++++++++++++ include/linux/platform_data/lp855x.h | 2 ++ 3 files changed, 22 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/video/backlight/lp855x.txt b/Documentation/devicetree/bindings/video/backlight/lp855x.txt index 96e83a56048e..0a3ecbc3a1b9 100644 --- a/Documentation/devicetree/bindings/video/backlight/lp855x.txt +++ b/Documentation/devicetree/bindings/video/backlight/lp855x.txt @@ -12,6 +12,7 @@ Optional properties: - pwm-period: PWM period value. Set only PWM input mode used (u32) - rom-addr: Register address of ROM area to be updated (u8) - rom-val: Register value to be updated (u8) + - power-supply: Regulator which controls the 3V rail Example: @@ -56,6 +57,7 @@ Example: backlight@2c { compatible = "ti,lp8557"; reg = <0x2c>; + power-supply = <&backlight_vdd>; dev-ctrl = /bits/ 8 <0x41>; init-brt = /bits/ 8 <0x0a>; diff --git a/drivers/video/backlight/lp855x_bl.c b/drivers/video/backlight/lp855x_bl.c index 257b3badd8e4..a26d3bb25650 100644 --- a/drivers/video/backlight/lp855x_bl.c +++ b/drivers/video/backlight/lp855x_bl.c @@ -17,6 +17,7 @@ #include #include #include +#include /* LP8550/1/2/3/6 Registers */ #define LP855X_BRIGHTNESS_CTRL 0x00 @@ -383,6 +384,13 @@ static int lp855x_parse_dt(struct lp855x *lp) pdata->rom_data = &rom[0]; } + pdata->supply = devm_regulator_get(dev, "power"); + if (IS_ERR(pdata->supply)) { + if (PTR_ERR(pdata->supply) == -EPROBE_DEFER) + return -EPROBE_DEFER; + pdata->supply = NULL; + } + lp->pdata = pdata; return 0; @@ -423,6 +431,14 @@ static int lp855x_probe(struct i2c_client *cl, const struct i2c_device_id *id) else lp->mode = REGISTER_BASED; + if (lp->pdata->supply) { + ret = regulator_enable(lp->pdata->supply); + if (ret < 0) { + dev_err(&cl->dev, "failed to enable supply: %d\n", ret); + return ret; + } + } + i2c_set_clientdata(cl, lp); ret = lp855x_configure(lp); @@ -454,6 +470,8 @@ static int lp855x_remove(struct i2c_client *cl) lp->bl->props.brightness = 0; backlight_update_status(lp->bl); + if (lp->pdata->supply) + regulator_disable(lp->pdata->supply); sysfs_remove_group(&lp->dev->kobj, &lp855x_attr_group); return 0; diff --git a/include/linux/platform_data/lp855x.h b/include/linux/platform_data/lp855x.h index 1b2ba24e4e03..9c7fd1efe495 100644 --- a/include/linux/platform_data/lp855x.h +++ b/include/linux/platform_data/lp855x.h @@ -136,6 +136,7 @@ struct lp855x_rom_data { Only valid when mode is PWM_BASED. * @size_program : total size of lp855x_rom_data * @rom_data : list of new eeprom/eprom registers + * @supply : regulator that supplies 3V input */ struct lp855x_platform_data { const char *name; @@ -144,6 +145,7 @@ struct lp855x_platform_data { unsigned int period_ns; int size_program; struct lp855x_rom_data *rom_data; + struct regulator *supply; }; #endif -- cgit v1.2.3-59-g8ed1b From 5d330cddb907df0911652c447baf9ee1a137245d Mon Sep 17 00:00:00 2001 From: Andrew Shewmaker Date: Wed, 3 Dec 2014 14:07:31 -0800 Subject: Update old iproute2 and Xen Remus links Signed-off-by: Andrew Shewmaker Acked-by: Stephen Hemminger Signed-off-by: David S. Miller --- Documentation/Changes | 2 +- net/sched/Kconfig | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/Changes b/Documentation/Changes index 1de131bb49fb..74bdda9272a4 100644 --- a/Documentation/Changes +++ b/Documentation/Changes @@ -383,7 +383,7 @@ o Ip-route2 --------- -o +o OProfile -------- diff --git a/net/sched/Kconfig b/net/sched/Kconfig index a1a8e29e5fc9..d17053d9e9e2 100644 --- a/net/sched/Kconfig +++ b/net/sched/Kconfig @@ -22,8 +22,9 @@ menuconfig NET_SCHED This code is considered to be experimental. To administer these schedulers, you'll need the user-level utilities - from the package iproute2+tc at . - That package also contains some documentation; for more, check out + from the package iproute2+tc at + . That package + also contains some documentation; for more, check out . This Quality of Service (QoS) support will enable you to use @@ -336,7 +337,7 @@ config NET_SCH_PLUG of virtual machines by allowing the generated network output to be rolled back if needed. - For more information, please refer to http://wiki.xensource.com/xenwiki/Remus + For more information, please refer to Say Y here if you are using this kernel for Xen dom0 and want to protect Xen guests with Remus. -- cgit v1.2.3-59-g8ed1b From 6dc696401a819d01428301bb0236f47ab14b7cda Mon Sep 17 00:00:00 2001 From: Rami Rosen Date: Fri, 5 Dec 2014 19:35:43 +0200 Subject: Documentation (ixgbe.txt): use a decimal address. This patch fixes the erronous usage of an hexadecimal address in the example, by replacing it with a decimal address. Signed-off-by: Rami Rosen Acked-by: Jeff Kirsher Signed-off-by: David S. Miller --- Documentation/networking/ixgbe.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/networking/ixgbe.txt b/Documentation/networking/ixgbe.txt index 96cccebb839b..0ace6e776ac8 100644 --- a/Documentation/networking/ixgbe.txt +++ b/Documentation/networking/ixgbe.txt @@ -138,7 +138,7 @@ Other ethtool Commands: To enable Flow Director ethtool -K ethX ntuple on To add a filter - Use -U switch. e.g., ethtool -U ethX flow-type tcp4 src-ip 0x178000a + Use -U switch. e.g., ethtool -U ethX flow-type tcp4 src-ip 10.0.128.23 action 1 To see the list of filters currently present: ethtool -u ethX -- cgit v1.2.3-59-g8ed1b From 9faa73f06ec2408cf86d20758d879b8d928ab30a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 Dec 2014 13:58:37 +0100 Subject: ALSA: hda - Add "eapd" model string for AD1986A codec Also update the documentation to the latest state. Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/HD-Audio-Models.txt | 8 ++------ sound/pci/hda/patch_analog.c | 1 + 2 files changed, 3 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt index a5e754714344..5a3163cac6c3 100644 --- a/Documentation/sound/alsa/HD-Audio-Models.txt +++ b/Documentation/sound/alsa/HD-Audio-Models.txt @@ -113,14 +113,10 @@ AD1984 AD1986A ======= - 6stack 6-jack, separate surrounds (default) 3stack 3-stack, shared surrounds laptop 2-channel only (FSC V2060, Samsung M50) - laptop-eapd 2-channel with EAPD (ASUS A6J) - laptop-automute 2-channel with EAPD and HP-automute (Lenovo N100) - ultra 2-channel with EAPD (Samsung Ultra tablet PC) - samsung 2-channel with EAPD (Samsung R65) - samsung-p50 2-channel with HP-automute (Samsung P50) + laptop-imic 2-channel with built-in mic + eapd Turn on EAPD constantly AD1988/AD1988B/AD1989A/AD1989B ============================== diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 4714ff92f15e..c81b715d6c98 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -352,6 +352,7 @@ static const struct hda_model_fixup ad1986a_fixup_models[] = { { .id = AD1986A_FIXUP_LAPTOP, .name = "laptop" }, { .id = AD1986A_FIXUP_LAPTOP_IMIC, .name = "laptop-imic" }, { .id = AD1986A_FIXUP_LAPTOP_IMIC, .name = "laptop-eapd" }, /* alias */ + { .id = AD1986A_FIXUP_EAPD, .name = "eapd" }, {} }; -- cgit v1.2.3-59-g8ed1b From aa4ea34da9e7a2bc0fb98f5add3e4e52872b7d45 Mon Sep 17 00:00:00 2001 From: Ethan Zhao Date: Tue, 9 Dec 2014 10:43:19 +0900 Subject: intel_pstate: add kernel parameter to force loading To force loading on Oracle Sun X86 servers, provide one kernel command line parameter intel_pstate = force For those who are aware of the risk of no power capping capabily working and try to get better performance with this driver. Signed-off-by: Ethan Zhao Tested-by: Alexey Kodanev Reviewed-by: Linda Knippers Acked-by: Kristen Carlson Accardi Signed-off-by: Rafael J. Wysocki --- Documentation/kernel-parameters.txt | 9 +++++++++ drivers/cpufreq/intel_pstate.c | 6 +++++- 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 5fdf714f40a0..d006bb22f3ca 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1446,6 +1446,15 @@ bytes respectively. Such letter suffixes can also be entirely omitted. disable Do not enable intel_pstate as the default scaling driver for the supported processors + force + Enable intel_pstate on systems that prohibit it by default + in favor of acpi-cpufreq. Forcing the intel_pstate driver + instead of acpi-cpufreq may disable platform features, such + as thermal controls and power capping, that rely on ACPI + P-States information being indicated to OSPM and therefore + should be used with caution. This option does not work with + processors that aren't supported by the intel_pstate driver + or on platforms that use pcc-cpufreq instead of acpi-cpufreq. no_hwp Do not enable hardware P state control (HWP) if available. diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 1405b393c93d..0e841eecb743 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -948,6 +948,7 @@ static struct cpufreq_driver intel_pstate_driver = { static int __initdata no_load; static int __initdata no_hwp; +static unsigned int force_load; static int intel_pstate_msrs_not_valid(void) { @@ -1094,7 +1095,8 @@ static bool intel_pstate_platform_pwr_mgmt_exists(void) case PSS: return intel_pstate_no_acpi_pss(); case PPC: - return intel_pstate_has_acpi_ppc(); + return intel_pstate_has_acpi_ppc() && + (!force_load); } } @@ -1175,6 +1177,8 @@ static int __init intel_pstate_setup(char *str) no_load = 1; if (!strcmp(str, "no_hwp")) no_hwp = 1; + if (!strcmp(str, "force")) + force_load = 1; return 0; } early_param("intel_pstate", intel_pstate_setup); -- cgit v1.2.3-59-g8ed1b From f41c2581bc2b6b21f774596845952a7cb4c15c74 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 10 Dec 2014 21:11:31 +0200 Subject: drm/doc: Document drm_add_modes_noedid() usage And fix a spelling mistake. Signed-off-by: Laurent Pinchart Reviewed-by: Alex Deucher Signed-off-by: Dave Airlie --- Documentation/DocBook/drm.tmpl | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 7a44d9d43c49..4b592ffbafee 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -1947,10 +1947,16 @@ void intel_crt_init(struct drm_device *dev) and then retrieves a list of modes by calling the connector get_modes helper operation. + + If the helper operation returns no mode, and if the connector status + is connector_status_connected, standard VESA DMT modes up to + 1024x768 are automatically added to the modes list by a call to + drm_add_modes_noedid. + - The function filters out modes larger than + The function then filters out modes larger than max_width and max_height - if specified. It then calls the optional connector + if specified. It finally calls the optional connector mode_valid helper operation for each mode in the probed list to check whether the mode is valid for the connector. @@ -2090,11 +2096,19 @@ void intel_crt_init(struct drm_device *dev) int (*get_modes)(struct drm_connector *connector); Fill the connector's probed_modes list - by parsing EDID data with drm_add_edid_modes or - calling drm_mode_probed_add directly for every + by parsing EDID data with drm_add_edid_modes, + adding standard VESA DMT modes with drm_add_modes_noedid, + or calling drm_mode_probed_add directly for every supported mode and return the number of modes it has detected. This operation is mandatory. + + Note that the caller function will automatically add standard VESA + DMT modes up to 1024x768 if the get_modes + helper operation returns no mode and if the connector status is + connector_status_connected. There is no need to call + drm_add_edid_modes manually in that case. + When adding modes manually the driver creates each mode with a call to drm_mode_create and must fill the following fields. @@ -2292,7 +2306,7 @@ void intel_crt_init(struct drm_device *dev) drm_helper_probe_single_connector_modes. - When parsing EDID data, drm_add_edid_modes fill the + When parsing EDID data, drm_add_edid_modes fills the connector display_info width_mm and height_mm fields. When creating modes -- cgit v1.2.3-59-g8ed1b From 3e32cb2e0a12b6915056ff04601cf1bb9b44f967 Mon Sep 17 00:00:00 2001 From: Johannes Weiner Date: Wed, 10 Dec 2014 15:42:31 -0800 Subject: mm: memcontrol: lockless page counters Memory is internally accounted in bytes, using spinlock-protected 64-bit counters, even though the smallest accounting delta is a page. The counter interface is also convoluted and does too many things. Introduce a new lockless word-sized page counter API, then change all memory accounting over to it. The translation from and to bytes then only happens when interfacing with userspace. The removed locking overhead is noticable when scaling beyond the per-cpu charge caches - on a 4-socket machine with 144-threads, the following test shows the performance differences of 288 memcgs concurrently running a page fault benchmark: vanilla: 18631648.500498 task-clock (msec) # 140.643 CPUs utilized ( +- 0.33% ) 1,380,638 context-switches # 0.074 K/sec ( +- 0.75% ) 24,390 cpu-migrations # 0.001 K/sec ( +- 8.44% ) 1,843,305,768 page-faults # 0.099 M/sec ( +- 0.00% ) 50,134,994,088,218 cycles # 2.691 GHz ( +- 0.33% ) stalled-cycles-frontend stalled-cycles-backend 8,049,712,224,651 instructions # 0.16 insns per cycle ( +- 0.04% ) 1,586,970,584,979 branches # 85.176 M/sec ( +- 0.05% ) 1,724,989,949 branch-misses # 0.11% of all branches ( +- 0.48% ) 132.474343877 seconds time elapsed ( +- 0.21% ) lockless: 12195979.037525 task-clock (msec) # 133.480 CPUs utilized ( +- 0.18% ) 832,850 context-switches # 0.068 K/sec ( +- 0.54% ) 15,624 cpu-migrations # 0.001 K/sec ( +- 10.17% ) 1,843,304,774 page-faults # 0.151 M/sec ( +- 0.00% ) 32,811,216,801,141 cycles # 2.690 GHz ( +- 0.18% ) stalled-cycles-frontend stalled-cycles-backend 9,999,265,091,727 instructions # 0.30 insns per cycle ( +- 0.10% ) 2,076,759,325,203 branches # 170.282 M/sec ( +- 0.12% ) 1,656,917,214 branch-misses # 0.08% of all branches ( +- 0.55% ) 91.369330729 seconds time elapsed ( +- 0.45% ) On top of improved scalability, this also gets rid of the icky long long types in the very heart of memcg, which is great for 32 bit and also makes the code a lot more readable. Notable differences between the old and new API: - res_counter_charge() and res_counter_charge_nofail() become page_counter_try_charge() and page_counter_charge() resp. to match the more common kernel naming scheme of try_do()/do() - res_counter_uncharge_until() is only ever used to cancel a local counter and never to uncharge bigger segments of a hierarchy, so it's replaced by the simpler page_counter_cancel() - res_counter_set_limit() is replaced by page_counter_limit(), which expects its callers to serialize against themselves - res_counter_memparse_write_strategy() is replaced by page_counter_limit(), which rounds down to the nearest page size - rather than up. This is more reasonable for explicitely requested hard upper limits. - to keep charging light-weight, page_counter_try_charge() charges speculatively, only to roll back if the result exceeds the limit. Because of this, a failing bigger charge can temporarily lock out smaller charges that would otherwise succeed. The error is bounded to the difference between the smallest and the biggest possible charge size, so for memcg, this means that a failing THP charge can send base page charges into reclaim upto 2MB (4MB) before the limit would have been reached. This should be acceptable. [akpm@linux-foundation.org: add includes for WARN_ON_ONCE and memparse] [akpm@linux-foundation.org: add includes for WARN_ON_ONCE, memparse, strncmp, and PAGE_SIZE] Signed-off-by: Johannes Weiner Acked-by: Michal Hocko Acked-by: Vladimir Davydov Cc: Tejun Heo Cc: David Rientjes Cc: Stephen Rothwell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/cgroups/memory.txt | 4 +- include/linux/memcontrol.h | 5 +- include/linux/page_counter.h | 51 ++++ include/net/sock.h | 26 +- init/Kconfig | 5 +- mm/Makefile | 1 + mm/memcontrol.c | 633 ++++++++++++++++++--------------------- mm/page_counter.c | 207 +++++++++++++ net/ipv4/tcp_memcontrol.c | 87 +++--- 9 files changed, 615 insertions(+), 404 deletions(-) create mode 100644 include/linux/page_counter.h create mode 100644 mm/page_counter.c (limited to 'Documentation') diff --git a/Documentation/cgroups/memory.txt b/Documentation/cgroups/memory.txt index 02ab997a1ed2..f624727ab404 100644 --- a/Documentation/cgroups/memory.txt +++ b/Documentation/cgroups/memory.txt @@ -52,9 +52,9 @@ Brief summary of control files. tasks # attach a task(thread) and show list of threads cgroup.procs # show list of processes cgroup.event_control # an interface for event_fd() - memory.usage_in_bytes # show current res_counter usage for memory + memory.usage_in_bytes # show current usage for memory (See 5.5 for details) - memory.memsw.usage_in_bytes # show current res_counter usage for memory+Swap + memory.memsw.usage_in_bytes # show current usage for memory+Swap (See 5.5 for details) memory.limit_in_bytes # set/show limit of memory usage memory.memsw.limit_in_bytes # set/show limit of memory+Swap usage diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h index 6b75640ef5ab..ea007615e8f9 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h @@ -447,9 +447,8 @@ memcg_kmem_newpage_charge(gfp_t gfp, struct mem_cgroup **memcg, int order) /* * __GFP_NOFAIL allocations will move on even if charging is not * possible. Therefore we don't even try, and have this allocation - * unaccounted. We could in theory charge it with - * res_counter_charge_nofail, but we hope those allocations are rare, - * and won't be worth the trouble. + * unaccounted. We could in theory charge it forcibly, but we hope + * those allocations are rare, and won't be worth the trouble. */ if (gfp & __GFP_NOFAIL) return true; diff --git a/include/linux/page_counter.h b/include/linux/page_counter.h new file mode 100644 index 000000000000..7cce3be99ff3 --- /dev/null +++ b/include/linux/page_counter.h @@ -0,0 +1,51 @@ +#ifndef _LINUX_PAGE_COUNTER_H +#define _LINUX_PAGE_COUNTER_H + +#include +#include +#include + +struct page_counter { + atomic_long_t count; + unsigned long limit; + struct page_counter *parent; + + /* legacy */ + unsigned long watermark; + unsigned long failcnt; +}; + +#if BITS_PER_LONG == 32 +#define PAGE_COUNTER_MAX LONG_MAX +#else +#define PAGE_COUNTER_MAX (LONG_MAX / PAGE_SIZE) +#endif + +static inline void page_counter_init(struct page_counter *counter, + struct page_counter *parent) +{ + atomic_long_set(&counter->count, 0); + counter->limit = PAGE_COUNTER_MAX; + counter->parent = parent; +} + +static inline unsigned long page_counter_read(struct page_counter *counter) +{ + return atomic_long_read(&counter->count); +} + +int page_counter_cancel(struct page_counter *counter, unsigned long nr_pages); +void page_counter_charge(struct page_counter *counter, unsigned long nr_pages); +int page_counter_try_charge(struct page_counter *counter, + unsigned long nr_pages, + struct page_counter **fail); +int page_counter_uncharge(struct page_counter *counter, unsigned long nr_pages); +int page_counter_limit(struct page_counter *counter, unsigned long limit); +int page_counter_memparse(const char *buf, unsigned long *nr_pages); + +static inline void page_counter_reset_watermark(struct page_counter *counter) +{ + counter->watermark = page_counter_read(counter); +} + +#endif /* _LINUX_PAGE_COUNTER_H */ diff --git a/include/net/sock.h b/include/net/sock.h index e6f235ebf6c9..7ff44e062a38 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -54,8 +54,8 @@ #include #include #include +#include #include -#include #include #include #include @@ -1062,7 +1062,7 @@ enum cg_proto_flags { }; struct cg_proto { - struct res_counter memory_allocated; /* Current allocated memory. */ + struct page_counter memory_allocated; /* Current allocated memory. */ struct percpu_counter sockets_allocated; /* Current number of sockets. */ int memory_pressure; long sysctl_mem[3]; @@ -1214,34 +1214,26 @@ static inline void memcg_memory_allocated_add(struct cg_proto *prot, unsigned long amt, int *parent_status) { - struct res_counter *fail; - int ret; + page_counter_charge(&prot->memory_allocated, amt); - ret = res_counter_charge_nofail(&prot->memory_allocated, - amt << PAGE_SHIFT, &fail); - if (ret < 0) + if (page_counter_read(&prot->memory_allocated) > + prot->memory_allocated.limit) *parent_status = OVER_LIMIT; } static inline void memcg_memory_allocated_sub(struct cg_proto *prot, unsigned long amt) { - res_counter_uncharge(&prot->memory_allocated, amt << PAGE_SHIFT); -} - -static inline u64 memcg_memory_allocated_read(struct cg_proto *prot) -{ - u64 ret; - ret = res_counter_read_u64(&prot->memory_allocated, RES_USAGE); - return ret >> PAGE_SHIFT; + page_counter_uncharge(&prot->memory_allocated, amt); } static inline long sk_memory_allocated(const struct sock *sk) { struct proto *prot = sk->sk_prot; + if (mem_cgroup_sockets_enabled && sk->sk_cgrp) - return memcg_memory_allocated_read(sk->sk_cgrp); + return page_counter_read(&sk->sk_cgrp->memory_allocated); return atomic_long_read(prot->memory_allocated); } @@ -1255,7 +1247,7 @@ sk_memory_allocated_add(struct sock *sk, int amt, int *parent_status) memcg_memory_allocated_add(sk->sk_cgrp, amt, parent_status); /* update the root cgroup regardless */ atomic_long_add_return(amt, prot->memory_allocated); - return memcg_memory_allocated_read(sk->sk_cgrp); + return page_counter_read(&sk->sk_cgrp->memory_allocated); } return atomic_long_add_return(amt, prot->memory_allocated); diff --git a/init/Kconfig b/init/Kconfig index 903505e66d1d..fd9e88791ba4 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -978,9 +978,12 @@ config RESOURCE_COUNTERS This option enables controller independent resource accounting infrastructure that works with cgroups. +config PAGE_COUNTER + bool + config MEMCG bool "Memory Resource Controller for Control Groups" - depends on RESOURCE_COUNTERS + select PAGE_COUNTER select EVENTFD help Provides a memory resource controller that manages both anonymous diff --git a/mm/Makefile b/mm/Makefile index 8405eb0023a9..6d9f40e922f7 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -55,6 +55,7 @@ obj-$(CONFIG_FS_XIP) += filemap_xip.o obj-$(CONFIG_MIGRATION) += migrate.o obj-$(CONFIG_QUICKLIST) += quicklist.o obj-$(CONFIG_TRANSPARENT_HUGEPAGE) += huge_memory.o +obj-$(CONFIG_PAGE_COUNTER) += page_counter.o obj-$(CONFIG_MEMCG) += memcontrol.o page_cgroup.o vmpressure.o obj-$(CONFIG_CGROUP_HUGETLB) += hugetlb_cgroup.o obj-$(CONFIG_MEMORY_FAILURE) += memory-failure.o diff --git a/mm/memcontrol.c b/mm/memcontrol.c index d6ac0e33e150..4129ad74e93b 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -25,7 +25,7 @@ * GNU General Public License for more details. */ -#include +#include #include #include #include @@ -165,7 +165,7 @@ struct mem_cgroup_per_zone { struct mem_cgroup_reclaim_iter reclaim_iter[DEF_PRIORITY + 1]; struct rb_node tree_node; /* RB tree node */ - unsigned long long usage_in_excess;/* Set to the value by which */ + unsigned long usage_in_excess;/* Set to the value by which */ /* the soft limit is exceeded*/ bool on_tree; struct mem_cgroup *memcg; /* Back pointer, we cannot */ @@ -198,7 +198,7 @@ static struct mem_cgroup_tree soft_limit_tree __read_mostly; struct mem_cgroup_threshold { struct eventfd_ctx *eventfd; - u64 threshold; + unsigned long threshold; }; /* For threshold */ @@ -284,10 +284,13 @@ static void mem_cgroup_oom_notify(struct mem_cgroup *memcg); */ struct mem_cgroup { struct cgroup_subsys_state css; - /* - * the counter to account for memory usage - */ - struct res_counter res; + + /* Accounted resources */ + struct page_counter memory; + struct page_counter memsw; + struct page_counter kmem; + + unsigned long soft_limit; /* vmpressure notifications */ struct vmpressure vmpressure; @@ -295,15 +298,6 @@ struct mem_cgroup { /* css_online() has been completed */ int initialized; - /* - * the counter to account for mem+swap usage. - */ - struct res_counter memsw; - - /* - * the counter to account for kernel memory usage. - */ - struct res_counter kmem; /* * Should the accounting and control be hierarchical, per subtree? */ @@ -650,7 +644,7 @@ static void disarm_kmem_keys(struct mem_cgroup *memcg) * This check can't live in kmem destruction function, * since the charges will outlive the cgroup */ - WARN_ON(res_counter_read_u64(&memcg->kmem, RES_USAGE) != 0); + WARN_ON(page_counter_read(&memcg->kmem)); } #else static void disarm_kmem_keys(struct mem_cgroup *memcg) @@ -706,7 +700,7 @@ soft_limit_tree_from_page(struct page *page) static void __mem_cgroup_insert_exceeded(struct mem_cgroup_per_zone *mz, struct mem_cgroup_tree_per_zone *mctz, - unsigned long long new_usage_in_excess) + unsigned long new_usage_in_excess) { struct rb_node **p = &mctz->rb_root.rb_node; struct rb_node *parent = NULL; @@ -755,10 +749,21 @@ static void mem_cgroup_remove_exceeded(struct mem_cgroup_per_zone *mz, spin_unlock_irqrestore(&mctz->lock, flags); } +static unsigned long soft_limit_excess(struct mem_cgroup *memcg) +{ + unsigned long nr_pages = page_counter_read(&memcg->memory); + unsigned long soft_limit = ACCESS_ONCE(memcg->soft_limit); + unsigned long excess = 0; + + if (nr_pages > soft_limit) + excess = nr_pages - soft_limit; + + return excess; +} static void mem_cgroup_update_tree(struct mem_cgroup *memcg, struct page *page) { - unsigned long long excess; + unsigned long excess; struct mem_cgroup_per_zone *mz; struct mem_cgroup_tree_per_zone *mctz; @@ -769,7 +774,7 @@ static void mem_cgroup_update_tree(struct mem_cgroup *memcg, struct page *page) */ for (; memcg; memcg = parent_mem_cgroup(memcg)) { mz = mem_cgroup_page_zoneinfo(memcg, page); - excess = res_counter_soft_limit_excess(&memcg->res); + excess = soft_limit_excess(memcg); /* * We have to update the tree if mz is on RB-tree or * mem is over its softlimit. @@ -825,7 +830,7 @@ retry: * position in the tree. */ __mem_cgroup_remove_exceeded(mz, mctz); - if (!res_counter_soft_limit_excess(&mz->memcg->res) || + if (!soft_limit_excess(mz->memcg) || !css_tryget_online(&mz->memcg->css)) goto retry; done: @@ -1492,7 +1497,7 @@ int mem_cgroup_inactive_anon_is_low(struct lruvec *lruvec) return inactive * inactive_ratio < active; } -#define mem_cgroup_from_res_counter(counter, member) \ +#define mem_cgroup_from_counter(counter, member) \ container_of(counter, struct mem_cgroup, member) /** @@ -1504,12 +1509,23 @@ int mem_cgroup_inactive_anon_is_low(struct lruvec *lruvec) */ static unsigned long mem_cgroup_margin(struct mem_cgroup *memcg) { - unsigned long long margin; + unsigned long margin = 0; + unsigned long count; + unsigned long limit; - margin = res_counter_margin(&memcg->res); - if (do_swap_account) - margin = min(margin, res_counter_margin(&memcg->memsw)); - return margin >> PAGE_SHIFT; + count = page_counter_read(&memcg->memory); + limit = ACCESS_ONCE(memcg->memory.limit); + if (count < limit) + margin = limit - count; + + if (do_swap_account) { + count = page_counter_read(&memcg->memsw); + limit = ACCESS_ONCE(memcg->memsw.limit); + if (count <= limit) + margin = min(margin, limit - count); + } + + return margin; } int mem_cgroup_swappiness(struct mem_cgroup *memcg) @@ -1644,18 +1660,15 @@ void mem_cgroup_print_oom_info(struct mem_cgroup *memcg, struct task_struct *p) rcu_read_unlock(); - pr_info("memory: usage %llukB, limit %llukB, failcnt %llu\n", - res_counter_read_u64(&memcg->res, RES_USAGE) >> 10, - res_counter_read_u64(&memcg->res, RES_LIMIT) >> 10, - res_counter_read_u64(&memcg->res, RES_FAILCNT)); - pr_info("memory+swap: usage %llukB, limit %llukB, failcnt %llu\n", - res_counter_read_u64(&memcg->memsw, RES_USAGE) >> 10, - res_counter_read_u64(&memcg->memsw, RES_LIMIT) >> 10, - res_counter_read_u64(&memcg->memsw, RES_FAILCNT)); - pr_info("kmem: usage %llukB, limit %llukB, failcnt %llu\n", - res_counter_read_u64(&memcg->kmem, RES_USAGE) >> 10, - res_counter_read_u64(&memcg->kmem, RES_LIMIT) >> 10, - res_counter_read_u64(&memcg->kmem, RES_FAILCNT)); + pr_info("memory: usage %llukB, limit %llukB, failcnt %lu\n", + K((u64)page_counter_read(&memcg->memory)), + K((u64)memcg->memory.limit), memcg->memory.failcnt); + pr_info("memory+swap: usage %llukB, limit %llukB, failcnt %lu\n", + K((u64)page_counter_read(&memcg->memsw)), + K((u64)memcg->memsw.limit), memcg->memsw.failcnt); + pr_info("kmem: usage %llukB, limit %llukB, failcnt %lu\n", + K((u64)page_counter_read(&memcg->kmem)), + K((u64)memcg->kmem.limit), memcg->kmem.failcnt); for_each_mem_cgroup_tree(iter, memcg) { pr_info("Memory cgroup stats for "); @@ -1695,28 +1708,17 @@ static int mem_cgroup_count_children(struct mem_cgroup *memcg) /* * Return the memory (and swap, if configured) limit for a memcg. */ -static u64 mem_cgroup_get_limit(struct mem_cgroup *memcg) +static unsigned long mem_cgroup_get_limit(struct mem_cgroup *memcg) { - u64 limit; + unsigned long limit; - limit = res_counter_read_u64(&memcg->res, RES_LIMIT); - - /* - * Do not consider swap space if we cannot swap due to swappiness - */ + limit = memcg->memory.limit; if (mem_cgroup_swappiness(memcg)) { - u64 memsw; + unsigned long memsw_limit; - limit += total_swap_pages << PAGE_SHIFT; - memsw = res_counter_read_u64(&memcg->memsw, RES_LIMIT); - - /* - * If memsw is finite and limits the amount of swap space - * available to this memcg, return that limit. - */ - limit = min(limit, memsw); + memsw_limit = memcg->memsw.limit; + limit = min(limit + total_swap_pages, memsw_limit); } - return limit; } @@ -1740,7 +1742,7 @@ static void mem_cgroup_out_of_memory(struct mem_cgroup *memcg, gfp_t gfp_mask, } check_panic_on_oom(CONSTRAINT_MEMCG, gfp_mask, order, NULL); - totalpages = mem_cgroup_get_limit(memcg) >> PAGE_SHIFT ? : 1; + totalpages = mem_cgroup_get_limit(memcg) ? : 1; for_each_mem_cgroup_tree(iter, memcg) { struct css_task_iter it; struct task_struct *task; @@ -1943,7 +1945,7 @@ static int mem_cgroup_soft_reclaim(struct mem_cgroup *root_memcg, .priority = 0, }; - excess = res_counter_soft_limit_excess(&root_memcg->res) >> PAGE_SHIFT; + excess = soft_limit_excess(root_memcg); while (1) { victim = mem_cgroup_iter(root_memcg, victim, &reclaim); @@ -1974,7 +1976,7 @@ static int mem_cgroup_soft_reclaim(struct mem_cgroup *root_memcg, total += mem_cgroup_shrink_node_zone(victim, gfp_mask, false, zone, &nr_scanned); *total_scanned += nr_scanned; - if (!res_counter_soft_limit_excess(&root_memcg->res)) + if (!soft_limit_excess(root_memcg)) break; } mem_cgroup_iter_break(root_memcg, victim); @@ -2316,33 +2318,31 @@ static DEFINE_MUTEX(percpu_charge_mutex); static bool consume_stock(struct mem_cgroup *memcg, unsigned int nr_pages) { struct memcg_stock_pcp *stock; - bool ret = true; + bool ret = false; if (nr_pages > CHARGE_BATCH) - return false; + return ret; stock = &get_cpu_var(memcg_stock); - if (memcg == stock->cached && stock->nr_pages >= nr_pages) + if (memcg == stock->cached && stock->nr_pages >= nr_pages) { stock->nr_pages -= nr_pages; - else /* need to call res_counter_charge */ - ret = false; + ret = true; + } put_cpu_var(memcg_stock); return ret; } /* - * Returns stocks cached in percpu to res_counter and reset cached information. + * Returns stocks cached in percpu and reset cached information. */ static void drain_stock(struct memcg_stock_pcp *stock) { struct mem_cgroup *old = stock->cached; if (stock->nr_pages) { - unsigned long bytes = stock->nr_pages * PAGE_SIZE; - - res_counter_uncharge(&old->res, bytes); + page_counter_uncharge(&old->memory, stock->nr_pages); if (do_swap_account) - res_counter_uncharge(&old->memsw, bytes); + page_counter_uncharge(&old->memsw, stock->nr_pages); stock->nr_pages = 0; } stock->cached = NULL; @@ -2371,7 +2371,7 @@ static void __init memcg_stock_init(void) } /* - * Cache charges(val) which is from res_counter, to local per_cpu area. + * Cache charges(val) to local per_cpu area. * This will be consumed by consume_stock() function, later. */ static void refill_stock(struct mem_cgroup *memcg, unsigned int nr_pages) @@ -2431,8 +2431,7 @@ out: /* * Tries to drain stocked charges in other cpus. This function is asynchronous * and just put a work per cpu for draining localy on each cpu. Caller can - * expects some charges will be back to res_counter later but cannot wait for - * it. + * expects some charges will be back later but cannot wait for it. */ static void drain_all_stock_async(struct mem_cgroup *root_memcg) { @@ -2506,9 +2505,8 @@ static int try_charge(struct mem_cgroup *memcg, gfp_t gfp_mask, unsigned int batch = max(CHARGE_BATCH, nr_pages); int nr_retries = MEM_CGROUP_RECLAIM_RETRIES; struct mem_cgroup *mem_over_limit; - struct res_counter *fail_res; + struct page_counter *counter; unsigned long nr_reclaimed; - unsigned long long size; bool may_swap = true; bool drained = false; int ret = 0; @@ -2519,16 +2517,15 @@ retry: if (consume_stock(memcg, nr_pages)) goto done; - size = batch * PAGE_SIZE; if (!do_swap_account || - !res_counter_charge(&memcg->memsw, size, &fail_res)) { - if (!res_counter_charge(&memcg->res, size, &fail_res)) + !page_counter_try_charge(&memcg->memsw, batch, &counter)) { + if (!page_counter_try_charge(&memcg->memory, batch, &counter)) goto done_restock; if (do_swap_account) - res_counter_uncharge(&memcg->memsw, size); - mem_over_limit = mem_cgroup_from_res_counter(fail_res, res); + page_counter_uncharge(&memcg->memsw, batch); + mem_over_limit = mem_cgroup_from_counter(counter, memory); } else { - mem_over_limit = mem_cgroup_from_res_counter(fail_res, memsw); + mem_over_limit = mem_cgroup_from_counter(counter, memsw); may_swap = false; } @@ -2611,32 +2608,12 @@ done: static void cancel_charge(struct mem_cgroup *memcg, unsigned int nr_pages) { - unsigned long bytes = nr_pages * PAGE_SIZE; - if (mem_cgroup_is_root(memcg)) return; - res_counter_uncharge(&memcg->res, bytes); + page_counter_uncharge(&memcg->memory, nr_pages); if (do_swap_account) - res_counter_uncharge(&memcg->memsw, bytes); -} - -/* - * Cancel chrages in this cgroup....doesn't propagate to parent cgroup. - * This is useful when moving usage to parent cgroup. - */ -static void __mem_cgroup_cancel_local_charge(struct mem_cgroup *memcg, - unsigned int nr_pages) -{ - unsigned long bytes = nr_pages * PAGE_SIZE; - - if (mem_cgroup_is_root(memcg)) - return; - - res_counter_uncharge_until(&memcg->res, memcg->res.parent, bytes); - if (do_swap_account) - res_counter_uncharge_until(&memcg->memsw, - memcg->memsw.parent, bytes); + page_counter_uncharge(&memcg->memsw, nr_pages); } /* @@ -2760,8 +2737,6 @@ static void commit_charge(struct page *page, struct mem_cgroup *memcg, unlock_page_lru(page, isolated); } -static DEFINE_MUTEX(set_limit_mutex); - #ifdef CONFIG_MEMCG_KMEM /* * The memcg_slab_mutex is held whenever a per memcg kmem cache is created or @@ -2804,16 +2779,17 @@ static int mem_cgroup_slabinfo_read(struct seq_file *m, void *v) } #endif -static int memcg_charge_kmem(struct mem_cgroup *memcg, gfp_t gfp, u64 size) +static int memcg_charge_kmem(struct mem_cgroup *memcg, gfp_t gfp, + unsigned long nr_pages) { - struct res_counter *fail_res; + struct page_counter *counter; int ret = 0; - ret = res_counter_charge(&memcg->kmem, size, &fail_res); - if (ret) + ret = page_counter_try_charge(&memcg->kmem, nr_pages, &counter); + if (ret < 0) return ret; - ret = try_charge(memcg, gfp, size >> PAGE_SHIFT); + ret = try_charge(memcg, gfp, nr_pages); if (ret == -EINTR) { /* * try_charge() chose to bypass to root due to OOM kill or @@ -2830,25 +2806,25 @@ static int memcg_charge_kmem(struct mem_cgroup *memcg, gfp_t gfp, u64 size) * when the allocation triggers should have been already * directed to the root cgroup in memcontrol.h */ - res_counter_charge_nofail(&memcg->res, size, &fail_res); + page_counter_charge(&memcg->memory, nr_pages); if (do_swap_account) - res_counter_charge_nofail(&memcg->memsw, size, - &fail_res); + page_counter_charge(&memcg->memsw, nr_pages); ret = 0; } else if (ret) - res_counter_uncharge(&memcg->kmem, size); + page_counter_uncharge(&memcg->kmem, nr_pages); return ret; } -static void memcg_uncharge_kmem(struct mem_cgroup *memcg, u64 size) +static void memcg_uncharge_kmem(struct mem_cgroup *memcg, + unsigned long nr_pages) { - res_counter_uncharge(&memcg->res, size); + page_counter_uncharge(&memcg->memory, nr_pages); if (do_swap_account) - res_counter_uncharge(&memcg->memsw, size); + page_counter_uncharge(&memcg->memsw, nr_pages); /* Not down to 0 */ - if (res_counter_uncharge(&memcg->kmem, size)) + if (page_counter_uncharge(&memcg->kmem, nr_pages)) return; /* @@ -3124,19 +3100,21 @@ static void memcg_schedule_register_cache(struct mem_cgroup *memcg, int __memcg_charge_slab(struct kmem_cache *cachep, gfp_t gfp, int order) { + unsigned int nr_pages = 1 << order; int res; - res = memcg_charge_kmem(cachep->memcg_params->memcg, gfp, - PAGE_SIZE << order); + res = memcg_charge_kmem(cachep->memcg_params->memcg, gfp, nr_pages); if (!res) - atomic_add(1 << order, &cachep->memcg_params->nr_pages); + atomic_add(nr_pages, &cachep->memcg_params->nr_pages); return res; } void __memcg_uncharge_slab(struct kmem_cache *cachep, int order) { - memcg_uncharge_kmem(cachep->memcg_params->memcg, PAGE_SIZE << order); - atomic_sub(1 << order, &cachep->memcg_params->nr_pages); + unsigned int nr_pages = 1 << order; + + memcg_uncharge_kmem(cachep->memcg_params->memcg, nr_pages); + atomic_sub(nr_pages, &cachep->memcg_params->nr_pages); } /* @@ -3257,7 +3235,7 @@ __memcg_kmem_newpage_charge(gfp_t gfp, struct mem_cgroup **_memcg, int order) return true; } - ret = memcg_charge_kmem(memcg, gfp, PAGE_SIZE << order); + ret = memcg_charge_kmem(memcg, gfp, 1 << order); if (!ret) *_memcg = memcg; @@ -3274,7 +3252,7 @@ void __memcg_kmem_commit_charge(struct page *page, struct mem_cgroup *memcg, /* The page allocation failed. Revert */ if (!page) { - memcg_uncharge_kmem(memcg, PAGE_SIZE << order); + memcg_uncharge_kmem(memcg, 1 << order); return; } /* @@ -3307,7 +3285,7 @@ void __memcg_kmem_uncharge_pages(struct page *page, int order) return; VM_BUG_ON_PAGE(mem_cgroup_is_root(memcg), page); - memcg_uncharge_kmem(memcg, PAGE_SIZE << order); + memcg_uncharge_kmem(memcg, 1 << order); } #else static inline void memcg_unregister_all_caches(struct mem_cgroup *memcg) @@ -3485,8 +3463,12 @@ static int mem_cgroup_move_parent(struct page *page, ret = mem_cgroup_move_account(page, nr_pages, pc, child, parent); - if (!ret) - __mem_cgroup_cancel_local_charge(child, nr_pages); + if (!ret) { + /* Take charge off the local counters */ + page_counter_cancel(&child->memory, nr_pages); + if (do_swap_account) + page_counter_cancel(&child->memsw, nr_pages); + } if (nr_pages > 1) compound_unlock_irqrestore(page, flags); @@ -3516,7 +3498,7 @@ static void mem_cgroup_swap_statistics(struct mem_cgroup *memcg, * * Returns 0 on success, -EINVAL on failure. * - * The caller must have charged to @to, IOW, called res_counter_charge() about + * The caller must have charged to @to, IOW, called page_counter_charge() about * both res and memsw, and called css_get(). */ static int mem_cgroup_move_swap_account(swp_entry_t entry, @@ -3532,7 +3514,7 @@ static int mem_cgroup_move_swap_account(swp_entry_t entry, mem_cgroup_swap_statistics(to, true); /* * This function is only called from task migration context now. - * It postpones res_counter and refcount handling till the end + * It postpones page_counter and refcount handling till the end * of task migration(mem_cgroup_clear_mc()) for performance * improvement. But we cannot postpone css_get(to) because if * the process that has been moved to @to does swap-in, the @@ -3590,60 +3572,57 @@ void mem_cgroup_print_bad_page(struct page *page) } #endif +static DEFINE_MUTEX(memcg_limit_mutex); + static int mem_cgroup_resize_limit(struct mem_cgroup *memcg, - unsigned long long val) + unsigned long limit) { + unsigned long curusage; + unsigned long oldusage; + bool enlarge = false; int retry_count; - int ret = 0; - int children = mem_cgroup_count_children(memcg); - u64 curusage, oldusage; - int enlarge; + int ret; /* * For keeping hierarchical_reclaim simple, how long we should retry * is depends on callers. We set our retry-count to be function * of # of children which we should visit in this loop. */ - retry_count = MEM_CGROUP_RECLAIM_RETRIES * children; + retry_count = MEM_CGROUP_RECLAIM_RETRIES * + mem_cgroup_count_children(memcg); - oldusage = res_counter_read_u64(&memcg->res, RES_USAGE); + oldusage = page_counter_read(&memcg->memory); - enlarge = 0; - while (retry_count) { + do { if (signal_pending(current)) { ret = -EINTR; break; } - /* - * Rather than hide all in some function, I do this in - * open coded manner. You see what this really does. - * We have to guarantee memcg->res.limit <= memcg->memsw.limit. - */ - mutex_lock(&set_limit_mutex); - if (res_counter_read_u64(&memcg->memsw, RES_LIMIT) < val) { + + mutex_lock(&memcg_limit_mutex); + if (limit > memcg->memsw.limit) { + mutex_unlock(&memcg_limit_mutex); ret = -EINVAL; - mutex_unlock(&set_limit_mutex); break; } - - if (res_counter_read_u64(&memcg->res, RES_LIMIT) < val) - enlarge = 1; - - ret = res_counter_set_limit(&memcg->res, val); - mutex_unlock(&set_limit_mutex); + if (limit > memcg->memory.limit) + enlarge = true; + ret = page_counter_limit(&memcg->memory, limit); + mutex_unlock(&memcg_limit_mutex); if (!ret) break; try_to_free_mem_cgroup_pages(memcg, 1, GFP_KERNEL, true); - curusage = res_counter_read_u64(&memcg->res, RES_USAGE); + curusage = page_counter_read(&memcg->memory); /* Usage is reduced ? */ if (curusage >= oldusage) retry_count--; else oldusage = curusage; - } + } while (retry_count); + if (!ret && enlarge) memcg_oom_recover(memcg); @@ -3651,52 +3630,53 @@ static int mem_cgroup_resize_limit(struct mem_cgroup *memcg, } static int mem_cgroup_resize_memsw_limit(struct mem_cgroup *memcg, - unsigned long long val) + unsigned long limit) { + unsigned long curusage; + unsigned long oldusage; + bool enlarge = false; int retry_count; - u64 oldusage, curusage; - int children = mem_cgroup_count_children(memcg); - int ret = -EBUSY; - int enlarge = 0; + int ret; /* see mem_cgroup_resize_res_limit */ - retry_count = children * MEM_CGROUP_RECLAIM_RETRIES; - oldusage = res_counter_read_u64(&memcg->memsw, RES_USAGE); - while (retry_count) { + retry_count = MEM_CGROUP_RECLAIM_RETRIES * + mem_cgroup_count_children(memcg); + + oldusage = page_counter_read(&memcg->memsw); + + do { if (signal_pending(current)) { ret = -EINTR; break; } - /* - * Rather than hide all in some function, I do this in - * open coded manner. You see what this really does. - * We have to guarantee memcg->res.limit <= memcg->memsw.limit. - */ - mutex_lock(&set_limit_mutex); - if (res_counter_read_u64(&memcg->res, RES_LIMIT) > val) { + + mutex_lock(&memcg_limit_mutex); + if (limit < memcg->memory.limit) { + mutex_unlock(&memcg_limit_mutex); ret = -EINVAL; - mutex_unlock(&set_limit_mutex); break; } - if (res_counter_read_u64(&memcg->memsw, RES_LIMIT) < val) - enlarge = 1; - ret = res_counter_set_limit(&memcg->memsw, val); - mutex_unlock(&set_limit_mutex); + if (limit > memcg->memsw.limit) + enlarge = true; + ret = page_counter_limit(&memcg->memsw, limit); + mutex_unlock(&memcg_limit_mutex); if (!ret) break; try_to_free_mem_cgroup_pages(memcg, 1, GFP_KERNEL, false); - curusage = res_counter_read_u64(&memcg->memsw, RES_USAGE); + curusage = page_counter_read(&memcg->memsw); /* Usage is reduced ? */ if (curusage >= oldusage) retry_count--; else oldusage = curusage; - } + } while (retry_count); + if (!ret && enlarge) memcg_oom_recover(memcg); + return ret; } @@ -3709,7 +3689,7 @@ unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order, unsigned long reclaimed; int loop = 0; struct mem_cgroup_tree_per_zone *mctz; - unsigned long long excess; + unsigned long excess; unsigned long nr_scanned; if (order > 0) @@ -3763,7 +3743,7 @@ unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order, } while (1); } __mem_cgroup_remove_exceeded(mz, mctz); - excess = res_counter_soft_limit_excess(&mz->memcg->res); + excess = soft_limit_excess(mz->memcg); /* * One school of thought says that we should not add * back the node to the tree if reclaim returns 0. @@ -3856,7 +3836,6 @@ static void mem_cgroup_force_empty_list(struct mem_cgroup *memcg, static void mem_cgroup_reparent_charges(struct mem_cgroup *memcg) { int node, zid; - u64 usage; do { /* This is for making all *used* pages to be on LRU. */ @@ -3888,9 +3867,8 @@ static void mem_cgroup_reparent_charges(struct mem_cgroup *memcg) * right after the check. RES_USAGE should be safe as we always * charge before adding to the LRU. */ - usage = res_counter_read_u64(&memcg->res, RES_USAGE) - - res_counter_read_u64(&memcg->kmem, RES_USAGE); - } while (usage > 0); + } while (page_counter_read(&memcg->memory) - + page_counter_read(&memcg->kmem) > 0); } /* @@ -3930,7 +3908,7 @@ static int mem_cgroup_force_empty(struct mem_cgroup *memcg) /* we call try-to-free pages for make this cgroup empty */ lru_add_drain_all(); /* try to free all pages in this cgroup */ - while (nr_retries && res_counter_read_u64(&memcg->res, RES_USAGE) > 0) { + while (nr_retries && page_counter_read(&memcg->memory)) { int progress; if (signal_pending(current)) @@ -4001,8 +3979,8 @@ out: return retval; } -static unsigned long mem_cgroup_recursive_stat(struct mem_cgroup *memcg, - enum mem_cgroup_stat_index idx) +static unsigned long tree_stat(struct mem_cgroup *memcg, + enum mem_cgroup_stat_index idx) { struct mem_cgroup *iter; long val = 0; @@ -4020,55 +3998,72 @@ static inline u64 mem_cgroup_usage(struct mem_cgroup *memcg, bool swap) { u64 val; - if (!mem_cgroup_is_root(memcg)) { + if (mem_cgroup_is_root(memcg)) { + val = tree_stat(memcg, MEM_CGROUP_STAT_CACHE); + val += tree_stat(memcg, MEM_CGROUP_STAT_RSS); + if (swap) + val += tree_stat(memcg, MEM_CGROUP_STAT_SWAP); + } else { if (!swap) - return res_counter_read_u64(&memcg->res, RES_USAGE); + val = page_counter_read(&memcg->memory); else - return res_counter_read_u64(&memcg->memsw, RES_USAGE); + val = page_counter_read(&memcg->memsw); } - - /* - * Transparent hugepages are still accounted for in MEM_CGROUP_STAT_RSS - * as well as in MEM_CGROUP_STAT_RSS_HUGE. - */ - val = mem_cgroup_recursive_stat(memcg, MEM_CGROUP_STAT_CACHE); - val += mem_cgroup_recursive_stat(memcg, MEM_CGROUP_STAT_RSS); - - if (swap) - val += mem_cgroup_recursive_stat(memcg, MEM_CGROUP_STAT_SWAP); - return val << PAGE_SHIFT; } +enum { + RES_USAGE, + RES_LIMIT, + RES_MAX_USAGE, + RES_FAILCNT, + RES_SOFT_LIMIT, +}; static u64 mem_cgroup_read_u64(struct cgroup_subsys_state *css, struct cftype *cft) { struct mem_cgroup *memcg = mem_cgroup_from_css(css); - enum res_type type = MEMFILE_TYPE(cft->private); - int name = MEMFILE_ATTR(cft->private); + struct page_counter *counter; - switch (type) { + switch (MEMFILE_TYPE(cft->private)) { case _MEM: - if (name == RES_USAGE) - return mem_cgroup_usage(memcg, false); - return res_counter_read_u64(&memcg->res, name); + counter = &memcg->memory; + break; case _MEMSWAP: - if (name == RES_USAGE) - return mem_cgroup_usage(memcg, true); - return res_counter_read_u64(&memcg->memsw, name); + counter = &memcg->memsw; + break; case _KMEM: - return res_counter_read_u64(&memcg->kmem, name); + counter = &memcg->kmem; break; default: BUG(); } + + switch (MEMFILE_ATTR(cft->private)) { + case RES_USAGE: + if (counter == &memcg->memory) + return mem_cgroup_usage(memcg, false); + if (counter == &memcg->memsw) + return mem_cgroup_usage(memcg, true); + return (u64)page_counter_read(counter) * PAGE_SIZE; + case RES_LIMIT: + return (u64)counter->limit * PAGE_SIZE; + case RES_MAX_USAGE: + return (u64)counter->watermark * PAGE_SIZE; + case RES_FAILCNT: + return counter->failcnt; + case RES_SOFT_LIMIT: + return (u64)memcg->soft_limit * PAGE_SIZE; + default: + BUG(); + } } #ifdef CONFIG_MEMCG_KMEM /* should be called with activate_kmem_mutex held */ static int __memcg_activate_kmem(struct mem_cgroup *memcg, - unsigned long long limit) + unsigned long nr_pages) { int err = 0; int memcg_id; @@ -4115,7 +4110,7 @@ static int __memcg_activate_kmem(struct mem_cgroup *memcg, * We couldn't have accounted to this cgroup, because it hasn't got the * active bit set yet, so this should succeed. */ - err = res_counter_set_limit(&memcg->kmem, limit); + err = page_counter_limit(&memcg->kmem, nr_pages); VM_BUG_ON(err); static_key_slow_inc(&memcg_kmem_enabled_key); @@ -4131,25 +4126,27 @@ out: } static int memcg_activate_kmem(struct mem_cgroup *memcg, - unsigned long long limit) + unsigned long nr_pages) { int ret; mutex_lock(&activate_kmem_mutex); - ret = __memcg_activate_kmem(memcg, limit); + ret = __memcg_activate_kmem(memcg, nr_pages); mutex_unlock(&activate_kmem_mutex); return ret; } static int memcg_update_kmem_limit(struct mem_cgroup *memcg, - unsigned long long val) + unsigned long limit) { int ret; + mutex_lock(&memcg_limit_mutex); if (!memcg_kmem_is_active(memcg)) - ret = memcg_activate_kmem(memcg, val); + ret = memcg_activate_kmem(memcg, limit); else - ret = res_counter_set_limit(&memcg->kmem, val); + ret = page_counter_limit(&memcg->kmem, limit); + mutex_unlock(&memcg_limit_mutex); return ret; } @@ -4167,13 +4164,13 @@ static int memcg_propagate_kmem(struct mem_cgroup *memcg) * after this point, because it has at least one child already. */ if (memcg_kmem_is_active(parent)) - ret = __memcg_activate_kmem(memcg, RES_COUNTER_MAX); + ret = __memcg_activate_kmem(memcg, PAGE_COUNTER_MAX); mutex_unlock(&activate_kmem_mutex); return ret; } #else static int memcg_update_kmem_limit(struct mem_cgroup *memcg, - unsigned long long val) + unsigned long limit) { return -EINVAL; } @@ -4187,110 +4184,69 @@ static ssize_t mem_cgroup_write(struct kernfs_open_file *of, char *buf, size_t nbytes, loff_t off) { struct mem_cgroup *memcg = mem_cgroup_from_css(of_css(of)); - enum res_type type; - int name; - unsigned long long val; + unsigned long nr_pages; int ret; buf = strstrip(buf); - type = MEMFILE_TYPE(of_cft(of)->private); - name = MEMFILE_ATTR(of_cft(of)->private); + ret = page_counter_memparse(buf, &nr_pages); + if (ret) + return ret; - switch (name) { + switch (MEMFILE_ATTR(of_cft(of)->private)) { case RES_LIMIT: if (mem_cgroup_is_root(memcg)) { /* Can't set limit on root */ ret = -EINVAL; break; } - /* This function does all necessary parse...reuse it */ - ret = res_counter_memparse_write_strategy(buf, &val); - if (ret) + switch (MEMFILE_TYPE(of_cft(of)->private)) { + case _MEM: + ret = mem_cgroup_resize_limit(memcg, nr_pages); break; - if (type == _MEM) - ret = mem_cgroup_resize_limit(memcg, val); - else if (type == _MEMSWAP) - ret = mem_cgroup_resize_memsw_limit(memcg, val); - else if (type == _KMEM) - ret = memcg_update_kmem_limit(memcg, val); - else - return -EINVAL; - break; - case RES_SOFT_LIMIT: - ret = res_counter_memparse_write_strategy(buf, &val); - if (ret) + case _MEMSWAP: + ret = mem_cgroup_resize_memsw_limit(memcg, nr_pages); break; - /* - * For memsw, soft limits are hard to implement in terms - * of semantics, for now, we support soft limits for - * control without swap - */ - if (type == _MEM) - ret = res_counter_set_soft_limit(&memcg->res, val); - else - ret = -EINVAL; + case _KMEM: + ret = memcg_update_kmem_limit(memcg, nr_pages); + break; + } break; - default: - ret = -EINVAL; /* should be BUG() ? */ + case RES_SOFT_LIMIT: + memcg->soft_limit = nr_pages; + ret = 0; break; } return ret ?: nbytes; } -static void memcg_get_hierarchical_limit(struct mem_cgroup *memcg, - unsigned long long *mem_limit, unsigned long long *memsw_limit) -{ - unsigned long long min_limit, min_memsw_limit, tmp; - - min_limit = res_counter_read_u64(&memcg->res, RES_LIMIT); - min_memsw_limit = res_counter_read_u64(&memcg->memsw, RES_LIMIT); - if (!memcg->use_hierarchy) - goto out; - - while (memcg->css.parent) { - memcg = mem_cgroup_from_css(memcg->css.parent); - if (!memcg->use_hierarchy) - break; - tmp = res_counter_read_u64(&memcg->res, RES_LIMIT); - min_limit = min(min_limit, tmp); - tmp = res_counter_read_u64(&memcg->memsw, RES_LIMIT); - min_memsw_limit = min(min_memsw_limit, tmp); - } -out: - *mem_limit = min_limit; - *memsw_limit = min_memsw_limit; -} - static ssize_t mem_cgroup_reset(struct kernfs_open_file *of, char *buf, size_t nbytes, loff_t off) { struct mem_cgroup *memcg = mem_cgroup_from_css(of_css(of)); - int name; - enum res_type type; + struct page_counter *counter; - type = MEMFILE_TYPE(of_cft(of)->private); - name = MEMFILE_ATTR(of_cft(of)->private); + switch (MEMFILE_TYPE(of_cft(of)->private)) { + case _MEM: + counter = &memcg->memory; + break; + case _MEMSWAP: + counter = &memcg->memsw; + break; + case _KMEM: + counter = &memcg->kmem; + break; + default: + BUG(); + } - switch (name) { + switch (MEMFILE_ATTR(of_cft(of)->private)) { case RES_MAX_USAGE: - if (type == _MEM) - res_counter_reset_max(&memcg->res); - else if (type == _MEMSWAP) - res_counter_reset_max(&memcg->memsw); - else if (type == _KMEM) - res_counter_reset_max(&memcg->kmem); - else - return -EINVAL; + page_counter_reset_watermark(counter); break; case RES_FAILCNT: - if (type == _MEM) - res_counter_reset_failcnt(&memcg->res); - else if (type == _MEMSWAP) - res_counter_reset_failcnt(&memcg->memsw); - else if (type == _KMEM) - res_counter_reset_failcnt(&memcg->kmem); - else - return -EINVAL; + counter->failcnt = 0; break; + default: + BUG(); } return nbytes; @@ -4387,6 +4343,7 @@ static inline void mem_cgroup_lru_names_not_uptodate(void) static int memcg_stat_show(struct seq_file *m, void *v) { struct mem_cgroup *memcg = mem_cgroup_from_css(seq_css(m)); + unsigned long memory, memsw; struct mem_cgroup *mi; unsigned int i; @@ -4406,14 +4363,16 @@ static int memcg_stat_show(struct seq_file *m, void *v) mem_cgroup_nr_lru_pages(memcg, BIT(i)) * PAGE_SIZE); /* Hierarchical information */ - { - unsigned long long limit, memsw_limit; - memcg_get_hierarchical_limit(memcg, &limit, &memsw_limit); - seq_printf(m, "hierarchical_memory_limit %llu\n", limit); - if (do_swap_account) - seq_printf(m, "hierarchical_memsw_limit %llu\n", - memsw_limit); + memory = memsw = PAGE_COUNTER_MAX; + for (mi = memcg; mi; mi = parent_mem_cgroup(mi)) { + memory = min(memory, mi->memory.limit); + memsw = min(memsw, mi->memsw.limit); } + seq_printf(m, "hierarchical_memory_limit %llu\n", + (u64)memory * PAGE_SIZE); + if (do_swap_account) + seq_printf(m, "hierarchical_memsw_limit %llu\n", + (u64)memsw * PAGE_SIZE); for (i = 0; i < MEM_CGROUP_STAT_NSTATS; i++) { long long val = 0; @@ -4497,7 +4456,7 @@ static int mem_cgroup_swappiness_write(struct cgroup_subsys_state *css, static void __mem_cgroup_threshold(struct mem_cgroup *memcg, bool swap) { struct mem_cgroup_threshold_ary *t; - u64 usage; + unsigned long usage; int i; rcu_read_lock(); @@ -4596,10 +4555,11 @@ static int __mem_cgroup_usage_register_event(struct mem_cgroup *memcg, { struct mem_cgroup_thresholds *thresholds; struct mem_cgroup_threshold_ary *new; - u64 threshold, usage; + unsigned long threshold; + unsigned long usage; int i, size, ret; - ret = res_counter_memparse_write_strategy(args, &threshold); + ret = page_counter_memparse(args, &threshold); if (ret) return ret; @@ -4689,7 +4649,7 @@ static void __mem_cgroup_usage_unregister_event(struct mem_cgroup *memcg, { struct mem_cgroup_thresholds *thresholds; struct mem_cgroup_threshold_ary *new; - u64 usage; + unsigned long usage; int i, j, size; mutex_lock(&memcg->thresholds_lock); @@ -4883,7 +4843,7 @@ static void kmem_cgroup_css_offline(struct mem_cgroup *memcg) memcg_kmem_mark_dead(memcg); - if (res_counter_read_u64(&memcg->kmem, RES_USAGE) != 0) + if (page_counter_read(&memcg->kmem)) return; if (memcg_kmem_test_and_clear_dead(memcg)) @@ -5363,9 +5323,9 @@ static void __mem_cgroup_free(struct mem_cgroup *memcg) */ struct mem_cgroup *parent_mem_cgroup(struct mem_cgroup *memcg) { - if (!memcg->res.parent) + if (!memcg->memory.parent) return NULL; - return mem_cgroup_from_res_counter(memcg->res.parent, res); + return mem_cgroup_from_counter(memcg->memory.parent, memory); } EXPORT_SYMBOL(parent_mem_cgroup); @@ -5410,9 +5370,9 @@ mem_cgroup_css_alloc(struct cgroup_subsys_state *parent_css) /* root ? */ if (parent_css == NULL) { root_mem_cgroup = memcg; - res_counter_init(&memcg->res, NULL); - res_counter_init(&memcg->memsw, NULL); - res_counter_init(&memcg->kmem, NULL); + page_counter_init(&memcg->memory, NULL); + page_counter_init(&memcg->memsw, NULL); + page_counter_init(&memcg->kmem, NULL); } memcg->last_scanned_node = MAX_NUMNODES; @@ -5451,18 +5411,18 @@ mem_cgroup_css_online(struct cgroup_subsys_state *css) memcg->swappiness = mem_cgroup_swappiness(parent); if (parent->use_hierarchy) { - res_counter_init(&memcg->res, &parent->res); - res_counter_init(&memcg->memsw, &parent->memsw); - res_counter_init(&memcg->kmem, &parent->kmem); + page_counter_init(&memcg->memory, &parent->memory); + page_counter_init(&memcg->memsw, &parent->memsw); + page_counter_init(&memcg->kmem, &parent->kmem); /* * No need to take a reference to the parent because cgroup * core guarantees its existence. */ } else { - res_counter_init(&memcg->res, NULL); - res_counter_init(&memcg->memsw, NULL); - res_counter_init(&memcg->kmem, NULL); + page_counter_init(&memcg->memory, NULL); + page_counter_init(&memcg->memsw, NULL); + page_counter_init(&memcg->kmem, NULL); /* * Deeper hierachy with use_hierarchy == false doesn't make * much sense so let cgroup subsystem know about this @@ -5544,7 +5504,7 @@ static void mem_cgroup_css_free(struct cgroup_subsys_state *css) /* * XXX: css_offline() would be where we should reparent all * memory to prepare the cgroup for destruction. However, - * memcg does not do css_tryget_online() and res_counter charging + * memcg does not do css_tryget_online() and page_counter charging * under the same RCU lock region, which means that charging * could race with offlining. Offlining only happens to * cgroups with no tasks in them but charges can show up @@ -5564,7 +5524,7 @@ static void mem_cgroup_css_free(struct cgroup_subsys_state *css) * call_rcu() * offline_css() * reparent_charges() - * res_counter_charge() + * page_counter_try_charge() * css_put() * css_free() * pc->mem_cgroup = dead memcg @@ -5599,10 +5559,10 @@ static void mem_cgroup_css_reset(struct cgroup_subsys_state *css) { struct mem_cgroup *memcg = mem_cgroup_from_css(css); - mem_cgroup_resize_limit(memcg, ULLONG_MAX); - mem_cgroup_resize_memsw_limit(memcg, ULLONG_MAX); - memcg_update_kmem_limit(memcg, ULLONG_MAX); - res_counter_set_soft_limit(&memcg->res, ULLONG_MAX); + mem_cgroup_resize_limit(memcg, PAGE_COUNTER_MAX); + mem_cgroup_resize_memsw_limit(memcg, PAGE_COUNTER_MAX); + memcg_update_kmem_limit(memcg, PAGE_COUNTER_MAX); + memcg->soft_limit = 0; } #ifdef CONFIG_MMU @@ -5916,19 +5876,18 @@ static void __mem_cgroup_clear_mc(void) if (mc.moved_swap) { /* uncharge swap account from the old cgroup */ if (!mem_cgroup_is_root(mc.from)) - res_counter_uncharge(&mc.from->memsw, - PAGE_SIZE * mc.moved_swap); - - for (i = 0; i < mc.moved_swap; i++) - css_put(&mc.from->css); + page_counter_uncharge(&mc.from->memsw, mc.moved_swap); /* - * we charged both to->res and to->memsw, so we should - * uncharge to->res. + * we charged both to->memory and to->memsw, so we + * should uncharge to->memory. */ if (!mem_cgroup_is_root(mc.to)) - res_counter_uncharge(&mc.to->res, - PAGE_SIZE * mc.moved_swap); + page_counter_uncharge(&mc.to->memory, mc.moved_swap); + + for (i = 0; i < mc.moved_swap; i++) + css_put(&mc.from->css); + /* we've already done css_get(mc.to) */ mc.moved_swap = 0; } @@ -6294,7 +6253,7 @@ void mem_cgroup_uncharge_swap(swp_entry_t entry) memcg = mem_cgroup_lookup(id); if (memcg) { if (!mem_cgroup_is_root(memcg)) - res_counter_uncharge(&memcg->memsw, PAGE_SIZE); + page_counter_uncharge(&memcg->memsw, 1); mem_cgroup_swap_statistics(memcg, false); css_put(&memcg->css); } @@ -6460,11 +6419,9 @@ static void uncharge_batch(struct mem_cgroup *memcg, unsigned long pgpgout, if (!mem_cgroup_is_root(memcg)) { if (nr_mem) - res_counter_uncharge(&memcg->res, - nr_mem * PAGE_SIZE); + page_counter_uncharge(&memcg->memory, nr_mem); if (nr_memsw) - res_counter_uncharge(&memcg->memsw, - nr_memsw * PAGE_SIZE); + page_counter_uncharge(&memcg->memsw, nr_memsw); memcg_oom_recover(memcg); } diff --git a/mm/page_counter.c b/mm/page_counter.c new file mode 100644 index 000000000000..f0cbc0825426 --- /dev/null +++ b/mm/page_counter.c @@ -0,0 +1,207 @@ +/* + * Lockless hierarchical page accounting & limiting + * + * Copyright (C) 2014 Red Hat, Inc., Johannes Weiner + */ + +#include +#include +#include +#include +#include +#include +#include + +/** + * page_counter_cancel - take pages out of the local counter + * @counter: counter + * @nr_pages: number of pages to cancel + * + * Returns whether there are remaining pages in the counter. + */ +int page_counter_cancel(struct page_counter *counter, unsigned long nr_pages) +{ + long new; + + new = atomic_long_sub_return(nr_pages, &counter->count); + + /* More uncharges than charges? */ + WARN_ON_ONCE(new < 0); + + return new > 0; +} + +/** + * page_counter_charge - hierarchically charge pages + * @counter: counter + * @nr_pages: number of pages to charge + * + * NOTE: This does not consider any configured counter limits. + */ +void page_counter_charge(struct page_counter *counter, unsigned long nr_pages) +{ + struct page_counter *c; + + for (c = counter; c; c = c->parent) { + long new; + + new = atomic_long_add_return(nr_pages, &c->count); + /* + * This is indeed racy, but we can live with some + * inaccuracy in the watermark. + */ + if (new > c->watermark) + c->watermark = new; + } +} + +/** + * page_counter_try_charge - try to hierarchically charge pages + * @counter: counter + * @nr_pages: number of pages to charge + * @fail: points first counter to hit its limit, if any + * + * Returns 0 on success, or -ENOMEM and @fail if the counter or one of + * its ancestors has hit its configured limit. + */ +int page_counter_try_charge(struct page_counter *counter, + unsigned long nr_pages, + struct page_counter **fail) +{ + struct page_counter *c; + + for (c = counter; c; c = c->parent) { + long new; + /* + * Charge speculatively to avoid an expensive CAS. If + * a bigger charge fails, it might falsely lock out a + * racing smaller charge and send it into reclaim + * early, but the error is limited to the difference + * between the two sizes, which is less than 2M/4M in + * case of a THP locking out a regular page charge. + * + * The atomic_long_add_return() implies a full memory + * barrier between incrementing the count and reading + * the limit. When racing with page_counter_limit(), + * we either see the new limit or the setter sees the + * counter has changed and retries. + */ + new = atomic_long_add_return(nr_pages, &c->count); + if (new > c->limit) { + atomic_long_sub(nr_pages, &c->count); + /* + * This is racy, but we can live with some + * inaccuracy in the failcnt. + */ + c->failcnt++; + *fail = c; + goto failed; + } + /* + * Just like with failcnt, we can live with some + * inaccuracy in the watermark. + */ + if (new > c->watermark) + c->watermark = new; + } + return 0; + +failed: + for (c = counter; c != *fail; c = c->parent) + page_counter_cancel(c, nr_pages); + + return -ENOMEM; +} + +/** + * page_counter_uncharge - hierarchically uncharge pages + * @counter: counter + * @nr_pages: number of pages to uncharge + * + * Returns whether there are remaining charges in @counter. + */ +int page_counter_uncharge(struct page_counter *counter, unsigned long nr_pages) +{ + struct page_counter *c; + int ret = 1; + + for (c = counter; c; c = c->parent) { + int remainder; + + remainder = page_counter_cancel(c, nr_pages); + if (c == counter && !remainder) + ret = 0; + } + + return ret; +} + +/** + * page_counter_limit - limit the number of pages allowed + * @counter: counter + * @limit: limit to set + * + * Returns 0 on success, -EBUSY if the current number of pages on the + * counter already exceeds the specified limit. + * + * The caller must serialize invocations on the same counter. + */ +int page_counter_limit(struct page_counter *counter, unsigned long limit) +{ + for (;;) { + unsigned long old; + long count; + + /* + * Update the limit while making sure that it's not + * below the concurrently-changing counter value. + * + * The xchg implies two full memory barriers before + * and after, so the read-swap-read is ordered and + * ensures coherency with page_counter_try_charge(): + * that function modifies the count before checking + * the limit, so if it sees the old limit, we see the + * modified counter and retry. + */ + count = atomic_long_read(&counter->count); + + if (count > limit) + return -EBUSY; + + old = xchg(&counter->limit, limit); + + if (atomic_long_read(&counter->count) <= count) + return 0; + + counter->limit = old; + cond_resched(); + } +} + +/** + * page_counter_memparse - memparse() for page counter limits + * @buf: string to parse + * @nr_pages: returns the result in number of pages + * + * Returns -EINVAL, or 0 and @nr_pages on success. @nr_pages will be + * limited to %PAGE_COUNTER_MAX. + */ +int page_counter_memparse(const char *buf, unsigned long *nr_pages) +{ + char unlimited[] = "-1"; + char *end; + u64 bytes; + + if (!strncmp(buf, unlimited, sizeof(unlimited))) { + *nr_pages = PAGE_COUNTER_MAX; + return 0; + } + + bytes = memparse(buf, &end); + if (*end != '\0') + return -EINVAL; + + *nr_pages = min(bytes / PAGE_SIZE, (u64)PAGE_COUNTER_MAX); + + return 0; +} diff --git a/net/ipv4/tcp_memcontrol.c b/net/ipv4/tcp_memcontrol.c index 1d191357bf88..272327134a1b 100644 --- a/net/ipv4/tcp_memcontrol.c +++ b/net/ipv4/tcp_memcontrol.c @@ -9,13 +9,13 @@ int tcp_init_cgroup(struct mem_cgroup *memcg, struct cgroup_subsys *ss) { /* - * The root cgroup does not use res_counters, but rather, + * The root cgroup does not use page_counters, but rather, * rely on the data already collected by the network * subsystem */ - struct res_counter *res_parent = NULL; - struct cg_proto *cg_proto, *parent_cg; struct mem_cgroup *parent = parent_mem_cgroup(memcg); + struct page_counter *counter_parent = NULL; + struct cg_proto *cg_proto, *parent_cg; cg_proto = tcp_prot.proto_cgroup(memcg); if (!cg_proto) @@ -29,9 +29,9 @@ int tcp_init_cgroup(struct mem_cgroup *memcg, struct cgroup_subsys *ss) parent_cg = tcp_prot.proto_cgroup(parent); if (parent_cg) - res_parent = &parent_cg->memory_allocated; + counter_parent = &parent_cg->memory_allocated; - res_counter_init(&cg_proto->memory_allocated, res_parent); + page_counter_init(&cg_proto->memory_allocated, counter_parent); percpu_counter_init(&cg_proto->sockets_allocated, 0, GFP_KERNEL); return 0; @@ -50,7 +50,7 @@ void tcp_destroy_cgroup(struct mem_cgroup *memcg) } EXPORT_SYMBOL(tcp_destroy_cgroup); -static int tcp_update_limit(struct mem_cgroup *memcg, u64 val) +static int tcp_update_limit(struct mem_cgroup *memcg, unsigned long nr_pages) { struct cg_proto *cg_proto; int i; @@ -60,20 +60,17 @@ static int tcp_update_limit(struct mem_cgroup *memcg, u64 val) if (!cg_proto) return -EINVAL; - if (val > RES_COUNTER_MAX) - val = RES_COUNTER_MAX; - - ret = res_counter_set_limit(&cg_proto->memory_allocated, val); + ret = page_counter_limit(&cg_proto->memory_allocated, nr_pages); if (ret) return ret; for (i = 0; i < 3; i++) - cg_proto->sysctl_mem[i] = min_t(long, val >> PAGE_SHIFT, + cg_proto->sysctl_mem[i] = min_t(long, nr_pages, sysctl_tcp_mem[i]); - if (val == RES_COUNTER_MAX) + if (nr_pages == PAGE_COUNTER_MAX) clear_bit(MEMCG_SOCK_ACTIVE, &cg_proto->flags); - else if (val != RES_COUNTER_MAX) { + else { /* * The active bit needs to be written after the static_key * update. This is what guarantees that the socket activation @@ -102,11 +99,20 @@ static int tcp_update_limit(struct mem_cgroup *memcg, u64 val) return 0; } +enum { + RES_USAGE, + RES_LIMIT, + RES_MAX_USAGE, + RES_FAILCNT, +}; + +static DEFINE_MUTEX(tcp_limit_mutex); + static ssize_t tcp_cgroup_write(struct kernfs_open_file *of, char *buf, size_t nbytes, loff_t off) { struct mem_cgroup *memcg = mem_cgroup_from_css(of_css(of)); - unsigned long long val; + unsigned long nr_pages; int ret = 0; buf = strstrip(buf); @@ -114,10 +120,12 @@ static ssize_t tcp_cgroup_write(struct kernfs_open_file *of, switch (of_cft(of)->private) { case RES_LIMIT: /* see memcontrol.c */ - ret = res_counter_memparse_write_strategy(buf, &val); + ret = page_counter_memparse(buf, &nr_pages); if (ret) break; - ret = tcp_update_limit(memcg, val); + mutex_lock(&tcp_limit_mutex); + ret = tcp_update_limit(memcg, nr_pages); + mutex_unlock(&tcp_limit_mutex); break; default: ret = -EINVAL; @@ -126,43 +134,36 @@ static ssize_t tcp_cgroup_write(struct kernfs_open_file *of, return ret ?: nbytes; } -static u64 tcp_read_stat(struct mem_cgroup *memcg, int type, u64 default_val) -{ - struct cg_proto *cg_proto; - - cg_proto = tcp_prot.proto_cgroup(memcg); - if (!cg_proto) - return default_val; - - return res_counter_read_u64(&cg_proto->memory_allocated, type); -} - -static u64 tcp_read_usage(struct mem_cgroup *memcg) -{ - struct cg_proto *cg_proto; - - cg_proto = tcp_prot.proto_cgroup(memcg); - if (!cg_proto) - return atomic_long_read(&tcp_memory_allocated) << PAGE_SHIFT; - - return res_counter_read_u64(&cg_proto->memory_allocated, RES_USAGE); -} - static u64 tcp_cgroup_read(struct cgroup_subsys_state *css, struct cftype *cft) { struct mem_cgroup *memcg = mem_cgroup_from_css(css); + struct cg_proto *cg_proto = tcp_prot.proto_cgroup(memcg); u64 val; switch (cft->private) { case RES_LIMIT: - val = tcp_read_stat(memcg, RES_LIMIT, RES_COUNTER_MAX); + if (!cg_proto) + return PAGE_COUNTER_MAX; + val = cg_proto->memory_allocated.limit; + val *= PAGE_SIZE; break; case RES_USAGE: - val = tcp_read_usage(memcg); + if (!cg_proto) + val = atomic_long_read(&tcp_memory_allocated); + else + val = page_counter_read(&cg_proto->memory_allocated); + val *= PAGE_SIZE; break; case RES_FAILCNT: + if (!cg_proto) + return 0; + val = cg_proto->memory_allocated.failcnt; + break; case RES_MAX_USAGE: - val = tcp_read_stat(memcg, cft->private, 0); + if (!cg_proto) + return 0; + val = cg_proto->memory_allocated.watermark; + val *= PAGE_SIZE; break; default: BUG(); @@ -183,10 +184,10 @@ static ssize_t tcp_cgroup_reset(struct kernfs_open_file *of, switch (of_cft(of)->private) { case RES_MAX_USAGE: - res_counter_reset_max(&cg_proto->memory_allocated); + page_counter_reset_watermark(&cg_proto->memory_allocated); break; case RES_FAILCNT: - res_counter_reset_failcnt(&cg_proto->memory_allocated); + cg_proto->memory_allocated.failcnt = 0; break; } -- cgit v1.2.3-59-g8ed1b From 71f87bee38edddb21d97895fa938744cf3f477bb Mon Sep 17 00:00:00 2001 From: Johannes Weiner Date: Wed, 10 Dec 2014 15:42:34 -0800 Subject: mm: hugetlb_cgroup: convert to lockless page counters Abandon the spinlock-protected byte counters in favor of the unlocked page counters in the hugetlb controller as well. Signed-off-by: Johannes Weiner Reviewed-by: Vladimir Davydov Acked-by: Michal Hocko Cc: Tejun Heo Cc: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/cgroups/hugetlb.txt | 2 +- include/linux/hugetlb_cgroup.h | 1 - init/Kconfig | 3 +- mm/hugetlb_cgroup.c | 103 +++++++++++++++++++++----------------- 4 files changed, 61 insertions(+), 48 deletions(-) (limited to 'Documentation') diff --git a/Documentation/cgroups/hugetlb.txt b/Documentation/cgroups/hugetlb.txt index a9faaca1f029..106245c3aecc 100644 --- a/Documentation/cgroups/hugetlb.txt +++ b/Documentation/cgroups/hugetlb.txt @@ -29,7 +29,7 @@ Brief summary of control files hugetlb..limit_in_bytes # set/show limit of "hugepagesize" hugetlb usage hugetlb..max_usage_in_bytes # show max "hugepagesize" hugetlb usage recorded - hugetlb..usage_in_bytes # show current res_counter usage for "hugepagesize" hugetlb + hugetlb..usage_in_bytes # show current usage for "hugepagesize" hugetlb hugetlb..failcnt # show the number of allocation failure due to HugeTLB limit For a system supporting two hugepage size (16M and 16G) the control diff --git a/include/linux/hugetlb_cgroup.h b/include/linux/hugetlb_cgroup.h index 0129f89cf98d..bcc853eccc85 100644 --- a/include/linux/hugetlb_cgroup.h +++ b/include/linux/hugetlb_cgroup.h @@ -16,7 +16,6 @@ #define _LINUX_HUGETLB_CGROUP_H #include -#include struct hugetlb_cgroup; /* diff --git a/init/Kconfig b/init/Kconfig index fd9e88791ba4..a60d1442d1df 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1051,7 +1051,8 @@ config MEMCG_KMEM config CGROUP_HUGETLB bool "HugeTLB Resource Controller for Control Groups" - depends on RESOURCE_COUNTERS && HUGETLB_PAGE + depends on HUGETLB_PAGE + select PAGE_COUNTER default n help Provides a cgroup Resource Controller for HugeTLB pages. diff --git a/mm/hugetlb_cgroup.c b/mm/hugetlb_cgroup.c index a67c26e0f360..037e1c00a5b7 100644 --- a/mm/hugetlb_cgroup.c +++ b/mm/hugetlb_cgroup.c @@ -14,6 +14,7 @@ */ #include +#include #include #include #include @@ -23,7 +24,7 @@ struct hugetlb_cgroup { /* * the counter to account for hugepages from hugetlb. */ - struct res_counter hugepage[HUGE_MAX_HSTATE]; + struct page_counter hugepage[HUGE_MAX_HSTATE]; }; #define MEMFILE_PRIVATE(x, val) (((x) << 16) | (val)) @@ -60,7 +61,7 @@ static inline bool hugetlb_cgroup_have_usage(struct hugetlb_cgroup *h_cg) int idx; for (idx = 0; idx < hugetlb_max_hstate; idx++) { - if ((res_counter_read_u64(&h_cg->hugepage[idx], RES_USAGE)) > 0) + if (page_counter_read(&h_cg->hugepage[idx])) return true; } return false; @@ -79,12 +80,12 @@ hugetlb_cgroup_css_alloc(struct cgroup_subsys_state *parent_css) if (parent_h_cgroup) { for (idx = 0; idx < HUGE_MAX_HSTATE; idx++) - res_counter_init(&h_cgroup->hugepage[idx], - &parent_h_cgroup->hugepage[idx]); + page_counter_init(&h_cgroup->hugepage[idx], + &parent_h_cgroup->hugepage[idx]); } else { root_h_cgroup = h_cgroup; for (idx = 0; idx < HUGE_MAX_HSTATE; idx++) - res_counter_init(&h_cgroup->hugepage[idx], NULL); + page_counter_init(&h_cgroup->hugepage[idx], NULL); } return &h_cgroup->css; } @@ -108,9 +109,8 @@ static void hugetlb_cgroup_css_free(struct cgroup_subsys_state *css) static void hugetlb_cgroup_move_parent(int idx, struct hugetlb_cgroup *h_cg, struct page *page) { - int csize; - struct res_counter *counter; - struct res_counter *fail_res; + unsigned int nr_pages; + struct page_counter *counter; struct hugetlb_cgroup *page_hcg; struct hugetlb_cgroup *parent = parent_hugetlb_cgroup(h_cg); @@ -123,15 +123,15 @@ static void hugetlb_cgroup_move_parent(int idx, struct hugetlb_cgroup *h_cg, if (!page_hcg || page_hcg != h_cg) goto out; - csize = PAGE_SIZE << compound_order(page); + nr_pages = 1 << compound_order(page); if (!parent) { parent = root_h_cgroup; /* root has no limit */ - res_counter_charge_nofail(&parent->hugepage[idx], - csize, &fail_res); + page_counter_charge(&parent->hugepage[idx], nr_pages); } counter = &h_cg->hugepage[idx]; - res_counter_uncharge_until(counter, counter->parent, csize); + /* Take the pages off the local counter */ + page_counter_cancel(counter, nr_pages); set_hugetlb_cgroup(page, parent); out: @@ -166,9 +166,8 @@ int hugetlb_cgroup_charge_cgroup(int idx, unsigned long nr_pages, struct hugetlb_cgroup **ptr) { int ret = 0; - struct res_counter *fail_res; + struct page_counter *counter; struct hugetlb_cgroup *h_cg = NULL; - unsigned long csize = nr_pages * PAGE_SIZE; if (hugetlb_cgroup_disabled()) goto done; @@ -187,7 +186,7 @@ again: } rcu_read_unlock(); - ret = res_counter_charge(&h_cg->hugepage[idx], csize, &fail_res); + ret = page_counter_try_charge(&h_cg->hugepage[idx], nr_pages, &counter); css_put(&h_cg->css); done: *ptr = h_cg; @@ -213,7 +212,6 @@ void hugetlb_cgroup_uncharge_page(int idx, unsigned long nr_pages, struct page *page) { struct hugetlb_cgroup *h_cg; - unsigned long csize = nr_pages * PAGE_SIZE; if (hugetlb_cgroup_disabled()) return; @@ -222,61 +220,76 @@ void hugetlb_cgroup_uncharge_page(int idx, unsigned long nr_pages, if (unlikely(!h_cg)) return; set_hugetlb_cgroup(page, NULL); - res_counter_uncharge(&h_cg->hugepage[idx], csize); + page_counter_uncharge(&h_cg->hugepage[idx], nr_pages); return; } void hugetlb_cgroup_uncharge_cgroup(int idx, unsigned long nr_pages, struct hugetlb_cgroup *h_cg) { - unsigned long csize = nr_pages * PAGE_SIZE; - if (hugetlb_cgroup_disabled() || !h_cg) return; if (huge_page_order(&hstates[idx]) < HUGETLB_CGROUP_MIN_ORDER) return; - res_counter_uncharge(&h_cg->hugepage[idx], csize); + page_counter_uncharge(&h_cg->hugepage[idx], nr_pages); return; } +enum { + RES_USAGE, + RES_LIMIT, + RES_MAX_USAGE, + RES_FAILCNT, +}; + static u64 hugetlb_cgroup_read_u64(struct cgroup_subsys_state *css, struct cftype *cft) { - int idx, name; + struct page_counter *counter; struct hugetlb_cgroup *h_cg = hugetlb_cgroup_from_css(css); - idx = MEMFILE_IDX(cft->private); - name = MEMFILE_ATTR(cft->private); + counter = &h_cg->hugepage[MEMFILE_IDX(cft->private)]; - return res_counter_read_u64(&h_cg->hugepage[idx], name); + switch (MEMFILE_ATTR(cft->private)) { + case RES_USAGE: + return (u64)page_counter_read(counter) * PAGE_SIZE; + case RES_LIMIT: + return (u64)counter->limit * PAGE_SIZE; + case RES_MAX_USAGE: + return (u64)counter->watermark * PAGE_SIZE; + case RES_FAILCNT: + return counter->failcnt; + default: + BUG(); + } } +static DEFINE_MUTEX(hugetlb_limit_mutex); + static ssize_t hugetlb_cgroup_write(struct kernfs_open_file *of, char *buf, size_t nbytes, loff_t off) { - int idx, name, ret; - unsigned long long val; + int ret, idx; + unsigned long nr_pages; struct hugetlb_cgroup *h_cg = hugetlb_cgroup_from_css(of_css(of)); + if (hugetlb_cgroup_is_root(h_cg)) /* Can't set limit on root */ + return -EINVAL; + buf = strstrip(buf); + ret = page_counter_memparse(buf, &nr_pages); + if (ret) + return ret; + idx = MEMFILE_IDX(of_cft(of)->private); - name = MEMFILE_ATTR(of_cft(of)->private); - switch (name) { + switch (MEMFILE_ATTR(of_cft(of)->private)) { case RES_LIMIT: - if (hugetlb_cgroup_is_root(h_cg)) { - /* Can't set limit on root */ - ret = -EINVAL; - break; - } - /* This function does all necessary parse...reuse it */ - ret = res_counter_memparse_write_strategy(buf, &val); - if (ret) - break; - val = ALIGN(val, 1ULL << huge_page_shift(&hstates[idx])); - ret = res_counter_set_limit(&h_cg->hugepage[idx], val); + mutex_lock(&hugetlb_limit_mutex); + ret = page_counter_limit(&h_cg->hugepage[idx], nr_pages); + mutex_unlock(&hugetlb_limit_mutex); break; default: ret = -EINVAL; @@ -288,18 +301,18 @@ static ssize_t hugetlb_cgroup_write(struct kernfs_open_file *of, static ssize_t hugetlb_cgroup_reset(struct kernfs_open_file *of, char *buf, size_t nbytes, loff_t off) { - int idx, name, ret = 0; + int ret = 0; + struct page_counter *counter; struct hugetlb_cgroup *h_cg = hugetlb_cgroup_from_css(of_css(of)); - idx = MEMFILE_IDX(of_cft(of)->private); - name = MEMFILE_ATTR(of_cft(of)->private); + counter = &h_cg->hugepage[MEMFILE_IDX(of_cft(of)->private)]; - switch (name) { + switch (MEMFILE_ATTR(of_cft(of)->private)) { case RES_MAX_USAGE: - res_counter_reset_max(&h_cg->hugepage[idx]); + page_counter_reset_watermark(counter); break; case RES_FAILCNT: - res_counter_reset_failcnt(&h_cg->hugepage[idx]); + counter->failcnt = 0; break; default: ret = -EINVAL; -- cgit v1.2.3-59-g8ed1b From 5b1efc027c0b51ca3e76f4e00c83358f8349f543 Mon Sep 17 00:00:00 2001 From: Johannes Weiner Date: Wed, 10 Dec 2014 15:42:37 -0800 Subject: kernel: res_counter: remove the unused API All memory accounting and limiting has been switched over to the lockless page counters. Bye, res_counter! [akpm@linux-foundation.org: update Documentation/cgroups/memory.txt] [mhocko@suse.cz: ditch the last remainings of res_counter] Signed-off-by: Johannes Weiner Acked-by: Vladimir Davydov Acked-by: Michal Hocko Cc: Tejun Heo Cc: David Rientjes Cc: Paul Bolle Signed-off-by: Michal Hocko Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/cgroups/memory.txt | 17 ++- Documentation/cgroups/resource_counter.txt | 197 ------------------------- include/linux/res_counter.h | 223 ----------------------------- init/Kconfig | 6 - kernel/Makefile | 1 - kernel/res_counter.c | 211 --------------------------- 6 files changed, 8 insertions(+), 647 deletions(-) delete mode 100644 Documentation/cgroups/resource_counter.txt delete mode 100644 include/linux/res_counter.h delete mode 100644 kernel/res_counter.c (limited to 'Documentation') diff --git a/Documentation/cgroups/memory.txt b/Documentation/cgroups/memory.txt index f624727ab404..67613ff0270c 100644 --- a/Documentation/cgroups/memory.txt +++ b/Documentation/cgroups/memory.txt @@ -116,16 +116,16 @@ The memory controller is the first controller developed. 2.1. Design -The core of the design is a counter called the res_counter. The res_counter -tracks the current memory usage and limit of the group of processes associated -with the controller. Each cgroup has a memory controller specific data -structure (mem_cgroup) associated with it. +The core of the design is a counter called the page_counter. The +page_counter tracks the current memory usage and limit of the group of +processes associated with the controller. Each cgroup has a memory controller +specific data structure (mem_cgroup) associated with it. 2.2. Accounting +--------------------+ - | mem_cgroup | - | (res_counter) | + | mem_cgroup | + | (page_counter) | +--------------------+ / ^ \ / | \ @@ -352,9 +352,8 @@ set: 0. Configuration a. Enable CONFIG_CGROUPS -b. Enable CONFIG_RESOURCE_COUNTERS -c. Enable CONFIG_MEMCG -d. Enable CONFIG_MEMCG_SWAP (to use swap extension) +b. Enable CONFIG_MEMCG +c. Enable CONFIG_MEMCG_SWAP (to use swap extension) d. Enable CONFIG_MEMCG_KMEM (to use kmem extension) 1. Prepare the cgroups (see cgroups.txt, Why are cgroups needed?) diff --git a/Documentation/cgroups/resource_counter.txt b/Documentation/cgroups/resource_counter.txt deleted file mode 100644 index 762ca54eb929..000000000000 --- a/Documentation/cgroups/resource_counter.txt +++ /dev/null @@ -1,197 +0,0 @@ - - The Resource Counter - -The resource counter, declared at include/linux/res_counter.h, -is supposed to facilitate the resource management by controllers -by providing common stuff for accounting. - -This "stuff" includes the res_counter structure and routines -to work with it. - - - -1. Crucial parts of the res_counter structure - - a. unsigned long long usage - - The usage value shows the amount of a resource that is consumed - by a group at a given time. The units of measurement should be - determined by the controller that uses this counter. E.g. it can - be bytes, items or any other unit the controller operates on. - - b. unsigned long long max_usage - - The maximal value of the usage over time. - - This value is useful when gathering statistical information about - the particular group, as it shows the actual resource requirements - for a particular group, not just some usage snapshot. - - c. unsigned long long limit - - The maximal allowed amount of resource to consume by the group. In - case the group requests for more resources, so that the usage value - would exceed the limit, the resource allocation is rejected (see - the next section). - - d. unsigned long long failcnt - - The failcnt stands for "failures counter". This is the number of - resource allocation attempts that failed. - - c. spinlock_t lock - - Protects changes of the above values. - - - -2. Basic accounting routines - - a. void res_counter_init(struct res_counter *rc, - struct res_counter *rc_parent) - - Initializes the resource counter. As usual, should be the first - routine called for a new counter. - - The struct res_counter *parent can be used to define a hierarchical - child -> parent relationship directly in the res_counter structure, - NULL can be used to define no relationship. - - c. int res_counter_charge(struct res_counter *rc, unsigned long val, - struct res_counter **limit_fail_at) - - When a resource is about to be allocated it has to be accounted - with the appropriate resource counter (controller should determine - which one to use on its own). This operation is called "charging". - - This is not very important which operation - resource allocation - or charging - is performed first, but - * if the allocation is performed first, this may create a - temporary resource over-usage by the time resource counter is - charged; - * if the charging is performed first, then it should be uncharged - on error path (if the one is called). - - If the charging fails and a hierarchical dependency exists, the - limit_fail_at parameter is set to the particular res_counter element - where the charging failed. - - d. u64 res_counter_uncharge(struct res_counter *rc, unsigned long val) - - When a resource is released (freed) it should be de-accounted - from the resource counter it was accounted to. This is called - "uncharging". The return value of this function indicate the amount - of charges still present in the counter. - - The _locked routines imply that the res_counter->lock is taken. - - e. u64 res_counter_uncharge_until - (struct res_counter *rc, struct res_counter *top, - unsigned long val) - - Almost same as res_counter_uncharge() but propagation of uncharge - stops when rc == top. This is useful when kill a res_counter in - child cgroup. - - 2.1 Other accounting routines - - There are more routines that may help you with common needs, like - checking whether the limit is reached or resetting the max_usage - value. They are all declared in include/linux/res_counter.h. - - - -3. Analyzing the resource counter registrations - - a. If the failcnt value constantly grows, this means that the counter's - limit is too tight. Either the group is misbehaving and consumes too - many resources, or the configuration is not suitable for the group - and the limit should be increased. - - b. The max_usage value can be used to quickly tune the group. One may - set the limits to maximal values and either load the container with - a common pattern or leave one for a while. After this the max_usage - value shows the amount of memory the container would require during - its common activity. - - Setting the limit a bit above this value gives a pretty good - configuration that works in most of the cases. - - c. If the max_usage is much less than the limit, but the failcnt value - is growing, then the group tries to allocate a big chunk of resource - at once. - - d. If the max_usage is much less than the limit, but the failcnt value - is 0, then this group is given too high limit, that it does not - require. It is better to lower the limit a bit leaving more resource - for other groups. - - - -4. Communication with the control groups subsystem (cgroups) - -All the resource controllers that are using cgroups and resource counters -should provide files (in the cgroup filesystem) to work with the resource -counter fields. They are recommended to adhere to the following rules: - - a. File names - - Field name File name - --------------------------------------------------- - usage usage_in_ - max_usage max_usage_in_ - limit limit_in_ - failcnt failcnt - lock no file :) - - b. Reading from file should show the corresponding field value in the - appropriate format. - - c. Writing to file - - Field Expected behavior - ---------------------------------- - usage prohibited - max_usage reset to usage - limit set the limit - failcnt reset to zero - - - -5. Usage example - - a. Declare a task group (take a look at cgroups subsystem for this) and - fold a res_counter into it - - struct my_group { - struct res_counter res; - - - } - - b. Put hooks in resource allocation/release paths - - int alloc_something(...) - { - if (res_counter_charge(res_counter_ptr, amount) < 0) - return -ENOMEM; - - - } - - void release_something(...) - { - res_counter_uncharge(res_counter_ptr, amount); - - - } - - In order to keep the usage value self-consistent, both the - "res_counter_ptr" and the "amount" in release_something() should be - the same as they were in the alloc_something() when the releasing - resource was allocated. - - c. Provide the way to read res_counter values and set them (the cgroups - still can help with it). - - c. Compile and run :) diff --git a/include/linux/res_counter.h b/include/linux/res_counter.h deleted file mode 100644 index 56b7bc32db4f..000000000000 --- a/include/linux/res_counter.h +++ /dev/null @@ -1,223 +0,0 @@ -#ifndef __RES_COUNTER_H__ -#define __RES_COUNTER_H__ - -/* - * Resource Counters - * Contain common data types and routines for resource accounting - * - * Copyright 2007 OpenVZ SWsoft Inc - * - * Author: Pavel Emelianov - * - * See Documentation/cgroups/resource_counter.txt for more - * info about what this counter is. - */ - -#include -#include - -/* - * The core object. the cgroup that wishes to account for some - * resource may include this counter into its structures and use - * the helpers described beyond - */ - -struct res_counter { - /* - * the current resource consumption level - */ - unsigned long long usage; - /* - * the maximal value of the usage from the counter creation - */ - unsigned long long max_usage; - /* - * the limit that usage cannot exceed - */ - unsigned long long limit; - /* - * the limit that usage can be exceed - */ - unsigned long long soft_limit; - /* - * the number of unsuccessful attempts to consume the resource - */ - unsigned long long failcnt; - /* - * the lock to protect all of the above. - * the routines below consider this to be IRQ-safe - */ - spinlock_t lock; - /* - * Parent counter, used for hierarchial resource accounting - */ - struct res_counter *parent; -}; - -#define RES_COUNTER_MAX ULLONG_MAX - -/** - * Helpers to interact with userspace - * res_counter_read_u64() - returns the value of the specified member. - * res_counter_read/_write - put/get the specified fields from the - * res_counter struct to/from the user - * - * @counter: the counter in question - * @member: the field to work with (see RES_xxx below) - * @buf: the buffer to opeate on,... - * @nbytes: its size... - * @pos: and the offset. - */ - -u64 res_counter_read_u64(struct res_counter *counter, int member); - -ssize_t res_counter_read(struct res_counter *counter, int member, - const char __user *buf, size_t nbytes, loff_t *pos, - int (*read_strategy)(unsigned long long val, char *s)); - -int res_counter_memparse_write_strategy(const char *buf, - unsigned long long *res); - -/* - * the field descriptors. one for each member of res_counter - */ - -enum { - RES_USAGE, - RES_MAX_USAGE, - RES_LIMIT, - RES_FAILCNT, - RES_SOFT_LIMIT, -}; - -/* - * helpers for accounting - */ - -void res_counter_init(struct res_counter *counter, struct res_counter *parent); - -/* - * charge - try to consume more resource. - * - * @counter: the counter - * @val: the amount of the resource. each controller defines its own - * units, e.g. numbers, bytes, Kbytes, etc - * - * returns 0 on success and <0 if the counter->usage will exceed the - * counter->limit - * - * charge_nofail works the same, except that it charges the resource - * counter unconditionally, and returns < 0 if the after the current - * charge we are over limit. - */ - -int __must_check res_counter_charge(struct res_counter *counter, - unsigned long val, struct res_counter **limit_fail_at); -int res_counter_charge_nofail(struct res_counter *counter, - unsigned long val, struct res_counter **limit_fail_at); - -/* - * uncharge - tell that some portion of the resource is released - * - * @counter: the counter - * @val: the amount of the resource - * - * these calls check for usage underflow and show a warning on the console - * - * returns the total charges still present in @counter. - */ - -u64 res_counter_uncharge(struct res_counter *counter, unsigned long val); - -u64 res_counter_uncharge_until(struct res_counter *counter, - struct res_counter *top, - unsigned long val); -/** - * res_counter_margin - calculate chargeable space of a counter - * @cnt: the counter - * - * Returns the difference between the hard limit and the current usage - * of resource counter @cnt. - */ -static inline unsigned long long res_counter_margin(struct res_counter *cnt) -{ - unsigned long long margin; - unsigned long flags; - - spin_lock_irqsave(&cnt->lock, flags); - if (cnt->limit > cnt->usage) - margin = cnt->limit - cnt->usage; - else - margin = 0; - spin_unlock_irqrestore(&cnt->lock, flags); - return margin; -} - -/** - * Get the difference between the usage and the soft limit - * @cnt: The counter - * - * Returns 0 if usage is less than or equal to soft limit - * The difference between usage and soft limit, otherwise. - */ -static inline unsigned long long -res_counter_soft_limit_excess(struct res_counter *cnt) -{ - unsigned long long excess; - unsigned long flags; - - spin_lock_irqsave(&cnt->lock, flags); - if (cnt->usage <= cnt->soft_limit) - excess = 0; - else - excess = cnt->usage - cnt->soft_limit; - spin_unlock_irqrestore(&cnt->lock, flags); - return excess; -} - -static inline void res_counter_reset_max(struct res_counter *cnt) -{ - unsigned long flags; - - spin_lock_irqsave(&cnt->lock, flags); - cnt->max_usage = cnt->usage; - spin_unlock_irqrestore(&cnt->lock, flags); -} - -static inline void res_counter_reset_failcnt(struct res_counter *cnt) -{ - unsigned long flags; - - spin_lock_irqsave(&cnt->lock, flags); - cnt->failcnt = 0; - spin_unlock_irqrestore(&cnt->lock, flags); -} - -static inline int res_counter_set_limit(struct res_counter *cnt, - unsigned long long limit) -{ - unsigned long flags; - int ret = -EBUSY; - - spin_lock_irqsave(&cnt->lock, flags); - if (cnt->usage <= limit) { - cnt->limit = limit; - ret = 0; - } - spin_unlock_irqrestore(&cnt->lock, flags); - return ret; -} - -static inline int -res_counter_set_soft_limit(struct res_counter *cnt, - unsigned long long soft_limit) -{ - unsigned long flags; - - spin_lock_irqsave(&cnt->lock, flags); - cnt->soft_limit = soft_limit; - spin_unlock_irqrestore(&cnt->lock, flags); - return 0; -} - -#endif diff --git a/init/Kconfig b/init/Kconfig index a60d1442d1df..1761c72bc1a0 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -972,12 +972,6 @@ config CGROUP_CPUACCT Provides a simple Resource Controller for monitoring the total CPU consumed by the tasks in a cgroup. -config RESOURCE_COUNTERS - bool "Resource counters" - help - This option enables controller independent resource accounting - infrastructure that works with cgroups. - config PAGE_COUNTER bool diff --git a/kernel/Makefile b/kernel/Makefile index 17ea6d4a9a24..a59481a3fa6c 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -57,7 +57,6 @@ obj-$(CONFIG_UTS_NS) += utsname.o obj-$(CONFIG_USER_NS) += user_namespace.o obj-$(CONFIG_PID_NS) += pid_namespace.o obj-$(CONFIG_IKCONFIG) += configs.o -obj-$(CONFIG_RESOURCE_COUNTERS) += res_counter.o obj-$(CONFIG_SMP) += stop_machine.o obj-$(CONFIG_KPROBES_SANITY_TEST) += test_kprobes.o obj-$(CONFIG_AUDIT) += audit.o auditfilter.o diff --git a/kernel/res_counter.c b/kernel/res_counter.c deleted file mode 100644 index e791130f85a7..000000000000 --- a/kernel/res_counter.c +++ /dev/null @@ -1,211 +0,0 @@ -/* - * resource cgroups - * - * Copyright 2007 OpenVZ SWsoft Inc - * - * Author: Pavel Emelianov - * - */ - -#include -#include -#include -#include -#include -#include - -void res_counter_init(struct res_counter *counter, struct res_counter *parent) -{ - spin_lock_init(&counter->lock); - counter->limit = RES_COUNTER_MAX; - counter->soft_limit = RES_COUNTER_MAX; - counter->parent = parent; -} - -static u64 res_counter_uncharge_locked(struct res_counter *counter, - unsigned long val) -{ - if (WARN_ON(counter->usage < val)) - val = counter->usage; - - counter->usage -= val; - return counter->usage; -} - -static int res_counter_charge_locked(struct res_counter *counter, - unsigned long val, bool force) -{ - int ret = 0; - - if (counter->usage + val > counter->limit) { - counter->failcnt++; - ret = -ENOMEM; - if (!force) - return ret; - } - - counter->usage += val; - if (counter->usage > counter->max_usage) - counter->max_usage = counter->usage; - return ret; -} - -static int __res_counter_charge(struct res_counter *counter, unsigned long val, - struct res_counter **limit_fail_at, bool force) -{ - int ret, r; - unsigned long flags; - struct res_counter *c, *u; - - r = ret = 0; - *limit_fail_at = NULL; - local_irq_save(flags); - for (c = counter; c != NULL; c = c->parent) { - spin_lock(&c->lock); - r = res_counter_charge_locked(c, val, force); - spin_unlock(&c->lock); - if (r < 0 && !ret) { - ret = r; - *limit_fail_at = c; - if (!force) - break; - } - } - - if (ret < 0 && !force) { - for (u = counter; u != c; u = u->parent) { - spin_lock(&u->lock); - res_counter_uncharge_locked(u, val); - spin_unlock(&u->lock); - } - } - local_irq_restore(flags); - - return ret; -} - -int res_counter_charge(struct res_counter *counter, unsigned long val, - struct res_counter **limit_fail_at) -{ - return __res_counter_charge(counter, val, limit_fail_at, false); -} - -int res_counter_charge_nofail(struct res_counter *counter, unsigned long val, - struct res_counter **limit_fail_at) -{ - return __res_counter_charge(counter, val, limit_fail_at, true); -} - -u64 res_counter_uncharge_until(struct res_counter *counter, - struct res_counter *top, - unsigned long val) -{ - unsigned long flags; - struct res_counter *c; - u64 ret = 0; - - local_irq_save(flags); - for (c = counter; c != top; c = c->parent) { - u64 r; - spin_lock(&c->lock); - r = res_counter_uncharge_locked(c, val); - if (c == counter) - ret = r; - spin_unlock(&c->lock); - } - local_irq_restore(flags); - return ret; -} - -u64 res_counter_uncharge(struct res_counter *counter, unsigned long val) -{ - return res_counter_uncharge_until(counter, NULL, val); -} - -static inline unsigned long long * -res_counter_member(struct res_counter *counter, int member) -{ - switch (member) { - case RES_USAGE: - return &counter->usage; - case RES_MAX_USAGE: - return &counter->max_usage; - case RES_LIMIT: - return &counter->limit; - case RES_FAILCNT: - return &counter->failcnt; - case RES_SOFT_LIMIT: - return &counter->soft_limit; - }; - - BUG(); - return NULL; -} - -ssize_t res_counter_read(struct res_counter *counter, int member, - const char __user *userbuf, size_t nbytes, loff_t *pos, - int (*read_strategy)(unsigned long long val, char *st_buf)) -{ - unsigned long long *val; - char buf[64], *s; - - s = buf; - val = res_counter_member(counter, member); - if (read_strategy) - s += read_strategy(*val, s); - else - s += sprintf(s, "%llu\n", *val); - return simple_read_from_buffer((void __user *)userbuf, nbytes, - pos, buf, s - buf); -} - -#if BITS_PER_LONG == 32 -u64 res_counter_read_u64(struct res_counter *counter, int member) -{ - unsigned long flags; - u64 ret; - - spin_lock_irqsave(&counter->lock, flags); - ret = *res_counter_member(counter, member); - spin_unlock_irqrestore(&counter->lock, flags); - - return ret; -} -#else -u64 res_counter_read_u64(struct res_counter *counter, int member) -{ - return *res_counter_member(counter, member); -} -#endif - -int res_counter_memparse_write_strategy(const char *buf, - unsigned long long *resp) -{ - char *end; - unsigned long long res; - - /* return RES_COUNTER_MAX(unlimited) if "-1" is specified */ - if (*buf == '-') { - int rc = kstrtoull(buf + 1, 10, &res); - - if (rc) - return rc; - if (res != 1) - return -EINVAL; - *resp = RES_COUNTER_MAX; - return 0; - } - - res = memparse(buf, &end); - if (*end != '\0') - return -EINVAL; - - if (PAGE_ALIGN(res) >= res) - res = PAGE_ALIGN(res); - else - res = RES_COUNTER_MAX; - - *resp = res; - - return 0; -} -- cgit v1.2.3-59-g8ed1b From 1306a85aed3ec3db98945aafb7dfbe5648a1203c Mon Sep 17 00:00:00 2001 From: Johannes Weiner Date: Wed, 10 Dec 2014 15:44:52 -0800 Subject: mm: embed the memcg pointer directly into struct page Memory cgroups used to have 5 per-page pointers. To allow users to disable that amount of overhead during runtime, those pointers were allocated in a separate array, with a translation layer between them and struct page. There is now only one page pointer remaining: the memcg pointer, that indicates which cgroup the page is associated with when charged. The complexity of runtime allocation and the runtime translation overhead is no longer justified to save that *potential* 0.19% of memory. With CONFIG_SLUB, page->mem_cgroup actually sits in the doubleword padding after the page->private member and doesn't even increase struct page, and then this patch actually saves space. Remaining users that care can still compile their kernels without CONFIG_MEMCG. text data bss dec hex filename 8828345 1725264 983040 11536649 b00909 vmlinux.old 8827425 1725264 966656 11519345 afc571 vmlinux.new [mhocko@suse.cz: update Documentation/cgroups/memory.txt] Signed-off-by: Johannes Weiner Acked-by: Michal Hocko Acked-by: Vladimir Davydov Acked-by: David S. Miller Acked-by: KAMEZAWA Hiroyuki Cc: "Kirill A. Shutemov" Cc: Michal Hocko Cc: Vladimir Davydov Cc: Tejun Heo Cc: Joonsoo Kim Acked-by: Konstantin Khlebnikov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/cgroups/memory.txt | 5 + include/linux/memcontrol.h | 6 +- include/linux/mm_types.h | 5 + include/linux/mmzone.h | 12 -- include/linux/page_cgroup.h | 53 ------- init/main.c | 7 - mm/memcontrol.c | 124 +++++---------- mm/page_alloc.c | 2 - mm/page_cgroup.c | 319 --------------------------------------- 9 files changed, 46 insertions(+), 487 deletions(-) (limited to 'Documentation') diff --git a/Documentation/cgroups/memory.txt b/Documentation/cgroups/memory.txt index 67613ff0270c..46b2b5080317 100644 --- a/Documentation/cgroups/memory.txt +++ b/Documentation/cgroups/memory.txt @@ -1,5 +1,10 @@ Memory Resource Controller +NOTE: This document is hopelessly outdated and it asks for a complete + rewrite. It still contains a useful information so we are keeping it + here but make sure to check the current code if you need a deeper + understanding. + NOTE: The Memory Resource Controller has generically been referred to as the memory controller in this document. Do not confuse memory controller used here with the memory controller that is used in hardware. diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h index de018766be45..c4d080875164 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h @@ -25,7 +25,6 @@ #include struct mem_cgroup; -struct page_cgroup; struct page; struct mm_struct; struct kmem_cache; @@ -466,8 +465,6 @@ memcg_kmem_newpage_charge(gfp_t gfp, struct mem_cgroup **memcg, int order) * memcg_kmem_uncharge_pages: uncharge pages from memcg * @page: pointer to struct page being freed * @order: allocation order. - * - * there is no need to specify memcg here, since it is embedded in page_cgroup */ static inline void memcg_kmem_uncharge_pages(struct page *page, int order) @@ -484,8 +481,7 @@ memcg_kmem_uncharge_pages(struct page *page, int order) * * Needs to be called after memcg_kmem_newpage_charge, regardless of success or * failure of the allocation. if @page is NULL, this function will revert the - * charges. Otherwise, it will commit the memcg given by @memcg to the - * corresponding page_cgroup. + * charges. Otherwise, it will commit @page to @memcg. */ static inline void memcg_kmem_commit_charge(struct page *page, struct mem_cgroup *memcg, int order) diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index 004e9d17b47e..bf9f57529dcf 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -22,6 +22,7 @@ #define AT_VECTOR_SIZE (2*(AT_VECTOR_SIZE_ARCH + AT_VECTOR_SIZE_BASE + 1)) struct address_space; +struct mem_cgroup; #define USE_SPLIT_PTE_PTLOCKS (NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS) #define USE_SPLIT_PMD_PTLOCKS (USE_SPLIT_PTE_PTLOCKS && \ @@ -167,6 +168,10 @@ struct page { struct page *first_page; /* Compound tail pages */ }; +#ifdef CONFIG_MEMCG + struct mem_cgroup *mem_cgroup; +#endif + /* * On machines where all RAM is mapped into kernel address space, * we can simply calculate the virtual address. On machines with diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index ffe66e381c04..3879d7664dfc 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -722,9 +722,6 @@ typedef struct pglist_data { int nr_zones; #ifdef CONFIG_FLAT_NODE_MEM_MAP /* means !SPARSEMEM */ struct page *node_mem_map; -#ifdef CONFIG_MEMCG - struct page_cgroup *node_page_cgroup; -#endif #endif #ifndef CONFIG_NO_BOOTMEM struct bootmem_data *bdata; @@ -1078,7 +1075,6 @@ static inline unsigned long early_pfn_to_nid(unsigned long pfn) #define SECTION_ALIGN_DOWN(pfn) ((pfn) & PAGE_SECTION_MASK) struct page; -struct page_cgroup; struct mem_section { /* * This is, logically, a pointer to an array of struct @@ -1096,14 +1092,6 @@ struct mem_section { /* See declaration of similar field in struct zone */ unsigned long *pageblock_flags; -#ifdef CONFIG_MEMCG - /* - * If !SPARSEMEM, pgdat doesn't have page_cgroup pointer. We use - * section. (see memcontrol.h/page_cgroup.h about this.) - */ - struct page_cgroup *page_cgroup; - unsigned long pad; -#endif /* * WARNING: mem_section must be a power-of-2 in size for the * calculation and use of SECTION_ROOT_MASK to make sense. diff --git a/include/linux/page_cgroup.h b/include/linux/page_cgroup.h index 1289be6b436c..65be35785c86 100644 --- a/include/linux/page_cgroup.h +++ b/include/linux/page_cgroup.h @@ -1,59 +1,6 @@ #ifndef __LINUX_PAGE_CGROUP_H #define __LINUX_PAGE_CGROUP_H -struct pglist_data; - -#ifdef CONFIG_MEMCG -struct mem_cgroup; - -/* - * Page Cgroup can be considered as an extended mem_map. - * A page_cgroup page is associated with every page descriptor. The - * page_cgroup helps us identify information about the cgroup - * All page cgroups are allocated at boot or memory hotplug event, - * then the page cgroup for pfn always exists. - */ -struct page_cgroup { - struct mem_cgroup *mem_cgroup; -}; - -extern void pgdat_page_cgroup_init(struct pglist_data *pgdat); - -#ifdef CONFIG_SPARSEMEM -static inline void page_cgroup_init_flatmem(void) -{ -} -extern void page_cgroup_init(void); -#else -extern void page_cgroup_init_flatmem(void); -static inline void page_cgroup_init(void) -{ -} -#endif - -struct page_cgroup *lookup_page_cgroup(struct page *page); - -#else /* !CONFIG_MEMCG */ -struct page_cgroup; - -static inline void pgdat_page_cgroup_init(struct pglist_data *pgdat) -{ -} - -static inline struct page_cgroup *lookup_page_cgroup(struct page *page) -{ - return NULL; -} - -static inline void page_cgroup_init(void) -{ -} - -static inline void page_cgroup_init_flatmem(void) -{ -} -#endif /* CONFIG_MEMCG */ - #include #ifdef CONFIG_MEMCG_SWAP diff --git a/init/main.c b/init/main.c index 321d0ceb26d3..d2e4ead4891f 100644 --- a/init/main.c +++ b/init/main.c @@ -51,7 +51,6 @@ #include #include #include -#include #include #include #include @@ -485,11 +484,6 @@ void __init __weak thread_info_cache_init(void) */ static void __init mm_init(void) { - /* - * page_cgroup requires contiguous pages, - * bigger than MAX_ORDER unless SPARSEMEM. - */ - page_cgroup_init_flatmem(); mem_init(); kmem_cache_init(); percpu_init_late(); @@ -627,7 +621,6 @@ asmlinkage __visible void __init start_kernel(void) initrd_start = 0; } #endif - page_cgroup_init(); debug_objects_mem_init(); kmemleak_init(); setup_per_cpu_pageset(); diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 78cb3b05a9fa..b864067791dc 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -1274,7 +1274,6 @@ struct lruvec *mem_cgroup_page_lruvec(struct page *page, struct zone *zone) { struct mem_cgroup_per_zone *mz; struct mem_cgroup *memcg; - struct page_cgroup *pc; struct lruvec *lruvec; if (mem_cgroup_disabled()) { @@ -1282,8 +1281,7 @@ struct lruvec *mem_cgroup_page_lruvec(struct page *page, struct zone *zone) goto out; } - pc = lookup_page_cgroup(page); - memcg = pc->mem_cgroup; + memcg = page->mem_cgroup; /* * Swapcache readahead pages are added to the LRU - and * possibly migrated - before they are charged. @@ -2020,16 +2018,13 @@ struct mem_cgroup *mem_cgroup_begin_page_stat(struct page *page, unsigned long *flags) { struct mem_cgroup *memcg; - struct page_cgroup *pc; rcu_read_lock(); if (mem_cgroup_disabled()) return NULL; - - pc = lookup_page_cgroup(page); again: - memcg = pc->mem_cgroup; + memcg = page->mem_cgroup; if (unlikely(!memcg)) return NULL; @@ -2038,7 +2033,7 @@ again: return memcg; spin_lock_irqsave(&memcg->move_lock, *flags); - if (memcg != pc->mem_cgroup) { + if (memcg != page->mem_cgroup) { spin_unlock_irqrestore(&memcg->move_lock, *flags); goto again; } @@ -2405,15 +2400,12 @@ static struct mem_cgroup *mem_cgroup_lookup(unsigned short id) struct mem_cgroup *try_get_mem_cgroup_from_page(struct page *page) { struct mem_cgroup *memcg; - struct page_cgroup *pc; unsigned short id; swp_entry_t ent; VM_BUG_ON_PAGE(!PageLocked(page), page); - pc = lookup_page_cgroup(page); - memcg = pc->mem_cgroup; - + memcg = page->mem_cgroup; if (memcg) { if (!css_tryget_online(&memcg->css)) memcg = NULL; @@ -2463,10 +2455,9 @@ static void unlock_page_lru(struct page *page, int isolated) static void commit_charge(struct page *page, struct mem_cgroup *memcg, bool lrucare) { - struct page_cgroup *pc = lookup_page_cgroup(page); int isolated; - VM_BUG_ON_PAGE(pc->mem_cgroup, page); + VM_BUG_ON_PAGE(page->mem_cgroup, page); /* * In some cases, SwapCache and FUSE(splice_buf->radixtree), the page @@ -2477,7 +2468,7 @@ static void commit_charge(struct page *page, struct mem_cgroup *memcg, /* * Nobody should be changing or seriously looking at - * pc->mem_cgroup at this point: + * page->mem_cgroup at this point: * * - the page is uncharged * @@ -2489,7 +2480,7 @@ static void commit_charge(struct page *page, struct mem_cgroup *memcg, * - a page cache insertion, a swapin fault, or a migration * have the page locked */ - pc->mem_cgroup = memcg; + page->mem_cgroup = memcg; if (lrucare) unlock_page_lru(page, isolated); @@ -2972,8 +2963,6 @@ __memcg_kmem_newpage_charge(gfp_t gfp, struct mem_cgroup **_memcg, int order) void __memcg_kmem_commit_charge(struct page *page, struct mem_cgroup *memcg, int order) { - struct page_cgroup *pc; - VM_BUG_ON(mem_cgroup_is_root(memcg)); /* The page allocation failed. Revert */ @@ -2981,14 +2970,12 @@ void __memcg_kmem_commit_charge(struct page *page, struct mem_cgroup *memcg, memcg_uncharge_kmem(memcg, 1 << order); return; } - pc = lookup_page_cgroup(page); - pc->mem_cgroup = memcg; + page->mem_cgroup = memcg; } void __memcg_kmem_uncharge_pages(struct page *page, int order) { - struct page_cgroup *pc = lookup_page_cgroup(page); - struct mem_cgroup *memcg = pc->mem_cgroup; + struct mem_cgroup *memcg = page->mem_cgroup; if (!memcg) return; @@ -2996,7 +2983,7 @@ void __memcg_kmem_uncharge_pages(struct page *page, int order) VM_BUG_ON_PAGE(mem_cgroup_is_root(memcg), page); memcg_uncharge_kmem(memcg, 1 << order); - pc->mem_cgroup = NULL; + page->mem_cgroup = NULL; } #else static inline void memcg_unregister_all_caches(struct mem_cgroup *memcg) @@ -3014,16 +3001,15 @@ static inline void memcg_unregister_all_caches(struct mem_cgroup *memcg) */ void mem_cgroup_split_huge_fixup(struct page *head) { - struct page_cgroup *pc = lookup_page_cgroup(head); int i; if (mem_cgroup_disabled()) return; for (i = 1; i < HPAGE_PMD_NR; i++) - pc[i].mem_cgroup = pc[0].mem_cgroup; + head[i].mem_cgroup = head->mem_cgroup; - __this_cpu_sub(pc[0].mem_cgroup->stat->count[MEM_CGROUP_STAT_RSS_HUGE], + __this_cpu_sub(head->mem_cgroup->stat->count[MEM_CGROUP_STAT_RSS_HUGE], HPAGE_PMD_NR); } #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ @@ -3032,7 +3018,6 @@ void mem_cgroup_split_huge_fixup(struct page *head) * mem_cgroup_move_account - move account of the page * @page: the page * @nr_pages: number of regular pages (>1 for huge pages) - * @pc: page_cgroup of the page. * @from: mem_cgroup which the page is moved from. * @to: mem_cgroup which the page is moved to. @from != @to. * @@ -3045,7 +3030,6 @@ void mem_cgroup_split_huge_fixup(struct page *head) */ static int mem_cgroup_move_account(struct page *page, unsigned int nr_pages, - struct page_cgroup *pc, struct mem_cgroup *from, struct mem_cgroup *to) { @@ -3065,7 +3049,7 @@ static int mem_cgroup_move_account(struct page *page, goto out; /* - * Prevent mem_cgroup_migrate() from looking at pc->mem_cgroup + * Prevent mem_cgroup_migrate() from looking at page->mem_cgroup * of its source page while we change it: page migration takes * both pages off the LRU, but page cache replacement doesn't. */ @@ -3073,7 +3057,7 @@ static int mem_cgroup_move_account(struct page *page, goto out; ret = -EINVAL; - if (pc->mem_cgroup != from) + if (page->mem_cgroup != from) goto out_unlock; spin_lock_irqsave(&from->move_lock, flags); @@ -3093,13 +3077,13 @@ static int mem_cgroup_move_account(struct page *page, } /* - * It is safe to change pc->mem_cgroup here because the page + * It is safe to change page->mem_cgroup here because the page * is referenced, charged, and isolated - we can't race with * uncharging, charging, migration, or LRU putback. */ /* caller should have done css_get */ - pc->mem_cgroup = to; + page->mem_cgroup = to; spin_unlock_irqrestore(&from->move_lock, flags); ret = 0; @@ -3174,36 +3158,17 @@ static inline int mem_cgroup_move_swap_account(swp_entry_t entry, #endif #ifdef CONFIG_DEBUG_VM -static struct page_cgroup *lookup_page_cgroup_used(struct page *page) -{ - struct page_cgroup *pc; - - pc = lookup_page_cgroup(page); - /* - * Can be NULL while feeding pages into the page allocator for - * the first time, i.e. during boot or memory hotplug; - * or when mem_cgroup_disabled(). - */ - if (likely(pc) && pc->mem_cgroup) - return pc; - return NULL; -} - bool mem_cgroup_bad_page_check(struct page *page) { if (mem_cgroup_disabled()) return false; - return lookup_page_cgroup_used(page) != NULL; + return page->mem_cgroup != NULL; } void mem_cgroup_print_bad_page(struct page *page) { - struct page_cgroup *pc; - - pc = lookup_page_cgroup_used(page); - if (pc) - pr_alert("pc:%p pc->mem_cgroup:%p\n", pc, pc->mem_cgroup); + pr_alert("page->mem_cgroup:%p\n", page->mem_cgroup); } #endif @@ -5123,7 +5088,6 @@ static enum mc_target_type get_mctgt_type(struct vm_area_struct *vma, unsigned long addr, pte_t ptent, union mc_target *target) { struct page *page = NULL; - struct page_cgroup *pc; enum mc_target_type ret = MC_TARGET_NONE; swp_entry_t ent = { .val = 0 }; @@ -5137,13 +5101,12 @@ static enum mc_target_type get_mctgt_type(struct vm_area_struct *vma, if (!page && !ent.val) return ret; if (page) { - pc = lookup_page_cgroup(page); /* * Do only loose check w/o serialization. - * mem_cgroup_move_account() checks the pc is valid or + * mem_cgroup_move_account() checks the page is valid or * not under LRU exclusion. */ - if (pc->mem_cgroup == mc.from) { + if (page->mem_cgroup == mc.from) { ret = MC_TARGET_PAGE; if (target) target->page = page; @@ -5171,15 +5134,13 @@ static enum mc_target_type get_mctgt_type_thp(struct vm_area_struct *vma, unsigned long addr, pmd_t pmd, union mc_target *target) { struct page *page = NULL; - struct page_cgroup *pc; enum mc_target_type ret = MC_TARGET_NONE; page = pmd_page(pmd); VM_BUG_ON_PAGE(!page || !PageHead(page), page); if (!move_anon()) return ret; - pc = lookup_page_cgroup(page); - if (pc->mem_cgroup == mc.from) { + if (page->mem_cgroup == mc.from) { ret = MC_TARGET_PAGE; if (target) { get_page(page); @@ -5378,7 +5339,6 @@ static int mem_cgroup_move_charge_pte_range(pmd_t *pmd, enum mc_target_type target_type; union mc_target target; struct page *page; - struct page_cgroup *pc; /* * We don't take compound_lock() here but no race with splitting thp @@ -5399,9 +5359,8 @@ static int mem_cgroup_move_charge_pte_range(pmd_t *pmd, if (target_type == MC_TARGET_PAGE) { page = target.page; if (!isolate_lru_page(page)) { - pc = lookup_page_cgroup(page); if (!mem_cgroup_move_account(page, HPAGE_PMD_NR, - pc, mc.from, mc.to)) { + mc.from, mc.to)) { mc.precharge -= HPAGE_PMD_NR; mc.moved_charge += HPAGE_PMD_NR; } @@ -5429,9 +5388,7 @@ retry: page = target.page; if (isolate_lru_page(page)) goto put; - pc = lookup_page_cgroup(page); - if (!mem_cgroup_move_account(page, 1, pc, - mc.from, mc.to)) { + if (!mem_cgroup_move_account(page, 1, mc.from, mc.to)) { mc.precharge--; /* we uncharge from mc.from later. */ mc.moved_charge++; @@ -5619,7 +5576,6 @@ static void __init enable_swap_cgroup(void) void mem_cgroup_swapout(struct page *page, swp_entry_t entry) { struct mem_cgroup *memcg; - struct page_cgroup *pc; unsigned short oldid; VM_BUG_ON_PAGE(PageLRU(page), page); @@ -5628,8 +5584,7 @@ void mem_cgroup_swapout(struct page *page, swp_entry_t entry) if (!do_swap_account) return; - pc = lookup_page_cgroup(page); - memcg = pc->mem_cgroup; + memcg = page->mem_cgroup; /* Readahead page, never charged */ if (!memcg) @@ -5639,7 +5594,7 @@ void mem_cgroup_swapout(struct page *page, swp_entry_t entry) VM_BUG_ON_PAGE(oldid, page); mem_cgroup_swap_statistics(memcg, true); - pc->mem_cgroup = NULL; + page->mem_cgroup = NULL; if (!mem_cgroup_is_root(memcg)) page_counter_uncharge(&memcg->memory, 1); @@ -5706,7 +5661,6 @@ int mem_cgroup_try_charge(struct page *page, struct mm_struct *mm, goto out; if (PageSwapCache(page)) { - struct page_cgroup *pc = lookup_page_cgroup(page); /* * Every swap fault against a single page tries to charge the * page, bail as early as possible. shmem_unuse() encounters @@ -5714,7 +5668,7 @@ int mem_cgroup_try_charge(struct page *page, struct mm_struct *mm, * the page lock, which serializes swap cache removal, which * in turn serializes uncharging. */ - if (pc->mem_cgroup) + if (page->mem_cgroup) goto out; } @@ -5867,7 +5821,6 @@ static void uncharge_list(struct list_head *page_list) next = page_list->next; do { unsigned int nr_pages = 1; - struct page_cgroup *pc; page = list_entry(next, struct page, lru); next = page->lru.next; @@ -5875,23 +5828,22 @@ static void uncharge_list(struct list_head *page_list) VM_BUG_ON_PAGE(PageLRU(page), page); VM_BUG_ON_PAGE(page_count(page), page); - pc = lookup_page_cgroup(page); - if (!pc->mem_cgroup) + if (!page->mem_cgroup) continue; /* * Nobody should be changing or seriously looking at - * pc->mem_cgroup at this point, we have fully + * page->mem_cgroup at this point, we have fully * exclusive access to the page. */ - if (memcg != pc->mem_cgroup) { + if (memcg != page->mem_cgroup) { if (memcg) { uncharge_batch(memcg, pgpgout, nr_anon, nr_file, nr_huge, page); pgpgout = nr_anon = nr_file = nr_huge = 0; } - memcg = pc->mem_cgroup; + memcg = page->mem_cgroup; } if (PageTransHuge(page)) { @@ -5905,7 +5857,7 @@ static void uncharge_list(struct list_head *page_list) else nr_file += nr_pages; - pc->mem_cgroup = NULL; + page->mem_cgroup = NULL; pgpgout++; } while (next != page_list); @@ -5924,14 +5876,11 @@ static void uncharge_list(struct list_head *page_list) */ void mem_cgroup_uncharge(struct page *page) { - struct page_cgroup *pc; - if (mem_cgroup_disabled()) return; /* Don't touch page->lru of any random page, pre-check: */ - pc = lookup_page_cgroup(page); - if (!pc->mem_cgroup) + if (!page->mem_cgroup) return; INIT_LIST_HEAD(&page->lru); @@ -5968,7 +5917,6 @@ void mem_cgroup_migrate(struct page *oldpage, struct page *newpage, bool lrucare) { struct mem_cgroup *memcg; - struct page_cgroup *pc; int isolated; VM_BUG_ON_PAGE(!PageLocked(oldpage), oldpage); @@ -5983,8 +5931,7 @@ void mem_cgroup_migrate(struct page *oldpage, struct page *newpage, return; /* Page cache replacement: new page already charged? */ - pc = lookup_page_cgroup(newpage); - if (pc->mem_cgroup) + if (newpage->mem_cgroup) return; /* @@ -5993,15 +5940,14 @@ void mem_cgroup_migrate(struct page *oldpage, struct page *newpage, * uncharged page when the PFN walker finds a page that * reclaim just put back on the LRU but has not released yet. */ - pc = lookup_page_cgroup(oldpage); - memcg = pc->mem_cgroup; + memcg = oldpage->mem_cgroup; if (!memcg) return; if (lrucare) lock_page_lru(oldpage, &isolated); - pc->mem_cgroup = NULL; + oldpage->mem_cgroup = NULL; if (lrucare) unlock_page_lru(oldpage, isolated); diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 97b6966816e5..22cfdeffbf69 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -48,7 +48,6 @@ #include #include #include -#include #include #include #include @@ -4853,7 +4852,6 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat, #endif init_waitqueue_head(&pgdat->kswapd_wait); init_waitqueue_head(&pgdat->pfmemalloc_wait); - pgdat_page_cgroup_init(pgdat); for (j = 0; j < MAX_NR_ZONES; j++) { struct zone *zone = pgdat->node_zones + j; diff --git a/mm/page_cgroup.c b/mm/page_cgroup.c index 5331c2bd85a2..f0f31c1d4d0c 100644 --- a/mm/page_cgroup.c +++ b/mm/page_cgroup.c @@ -1,326 +1,7 @@ #include -#include -#include -#include #include -#include -#include -#include #include -#include #include -#include - -static unsigned long total_usage; - -#if !defined(CONFIG_SPARSEMEM) - - -void __meminit pgdat_page_cgroup_init(struct pglist_data *pgdat) -{ - pgdat->node_page_cgroup = NULL; -} - -struct page_cgroup *lookup_page_cgroup(struct page *page) -{ - unsigned long pfn = page_to_pfn(page); - unsigned long offset; - struct page_cgroup *base; - - base = NODE_DATA(page_to_nid(page))->node_page_cgroup; -#ifdef CONFIG_DEBUG_VM - /* - * The sanity checks the page allocator does upon freeing a - * page can reach here before the page_cgroup arrays are - * allocated when feeding a range of pages to the allocator - * for the first time during bootup or memory hotplug. - */ - if (unlikely(!base)) - return NULL; -#endif - offset = pfn - NODE_DATA(page_to_nid(page))->node_start_pfn; - return base + offset; -} - -static int __init alloc_node_page_cgroup(int nid) -{ - struct page_cgroup *base; - unsigned long table_size; - unsigned long nr_pages; - - nr_pages = NODE_DATA(nid)->node_spanned_pages; - if (!nr_pages) - return 0; - - table_size = sizeof(struct page_cgroup) * nr_pages; - - base = memblock_virt_alloc_try_nid_nopanic( - table_size, PAGE_SIZE, __pa(MAX_DMA_ADDRESS), - BOOTMEM_ALLOC_ACCESSIBLE, nid); - if (!base) - return -ENOMEM; - NODE_DATA(nid)->node_page_cgroup = base; - total_usage += table_size; - return 0; -} - -void __init page_cgroup_init_flatmem(void) -{ - - int nid, fail; - - if (mem_cgroup_disabled()) - return; - - for_each_online_node(nid) { - fail = alloc_node_page_cgroup(nid); - if (fail) - goto fail; - } - printk(KERN_INFO "allocated %ld bytes of page_cgroup\n", total_usage); - printk(KERN_INFO "please try 'cgroup_disable=memory' option if you" - " don't want memory cgroups\n"); - return; -fail: - printk(KERN_CRIT "allocation of page_cgroup failed.\n"); - printk(KERN_CRIT "please try 'cgroup_disable=memory' boot option\n"); - panic("Out of memory"); -} - -#else /* CONFIG_FLAT_NODE_MEM_MAP */ - -struct page_cgroup *lookup_page_cgroup(struct page *page) -{ - unsigned long pfn = page_to_pfn(page); - struct mem_section *section = __pfn_to_section(pfn); -#ifdef CONFIG_DEBUG_VM - /* - * The sanity checks the page allocator does upon freeing a - * page can reach here before the page_cgroup arrays are - * allocated when feeding a range of pages to the allocator - * for the first time during bootup or memory hotplug. - */ - if (!section->page_cgroup) - return NULL; -#endif - return section->page_cgroup + pfn; -} - -static void *__meminit alloc_page_cgroup(size_t size, int nid) -{ - gfp_t flags = GFP_KERNEL | __GFP_ZERO | __GFP_NOWARN; - void *addr = NULL; - - addr = alloc_pages_exact_nid(nid, size, flags); - if (addr) { - kmemleak_alloc(addr, size, 1, flags); - return addr; - } - - if (node_state(nid, N_HIGH_MEMORY)) - addr = vzalloc_node(size, nid); - else - addr = vzalloc(size); - - return addr; -} - -static int __meminit init_section_page_cgroup(unsigned long pfn, int nid) -{ - struct mem_section *section; - struct page_cgroup *base; - unsigned long table_size; - - section = __pfn_to_section(pfn); - - if (section->page_cgroup) - return 0; - - table_size = sizeof(struct page_cgroup) * PAGES_PER_SECTION; - base = alloc_page_cgroup(table_size, nid); - - /* - * The value stored in section->page_cgroup is (base - pfn) - * and it does not point to the memory block allocated above, - * causing kmemleak false positives. - */ - kmemleak_not_leak(base); - - if (!base) { - printk(KERN_ERR "page cgroup allocation failure\n"); - return -ENOMEM; - } - - /* - * The passed "pfn" may not be aligned to SECTION. For the calculation - * we need to apply a mask. - */ - pfn &= PAGE_SECTION_MASK; - section->page_cgroup = base - pfn; - total_usage += table_size; - return 0; -} -#ifdef CONFIG_MEMORY_HOTPLUG -static void free_page_cgroup(void *addr) -{ - if (is_vmalloc_addr(addr)) { - vfree(addr); - } else { - struct page *page = virt_to_page(addr); - size_t table_size = - sizeof(struct page_cgroup) * PAGES_PER_SECTION; - - BUG_ON(PageReserved(page)); - kmemleak_free(addr); - free_pages_exact(addr, table_size); - } -} - -static void __free_page_cgroup(unsigned long pfn) -{ - struct mem_section *ms; - struct page_cgroup *base; - - ms = __pfn_to_section(pfn); - if (!ms || !ms->page_cgroup) - return; - base = ms->page_cgroup + pfn; - free_page_cgroup(base); - ms->page_cgroup = NULL; -} - -static int __meminit online_page_cgroup(unsigned long start_pfn, - unsigned long nr_pages, - int nid) -{ - unsigned long start, end, pfn; - int fail = 0; - - start = SECTION_ALIGN_DOWN(start_pfn); - end = SECTION_ALIGN_UP(start_pfn + nr_pages); - - if (nid == -1) { - /* - * In this case, "nid" already exists and contains valid memory. - * "start_pfn" passed to us is a pfn which is an arg for - * online__pages(), and start_pfn should exist. - */ - nid = pfn_to_nid(start_pfn); - VM_BUG_ON(!node_state(nid, N_ONLINE)); - } - - for (pfn = start; !fail && pfn < end; pfn += PAGES_PER_SECTION) { - if (!pfn_present(pfn)) - continue; - fail = init_section_page_cgroup(pfn, nid); - } - if (!fail) - return 0; - - /* rollback */ - for (pfn = start; pfn < end; pfn += PAGES_PER_SECTION) - __free_page_cgroup(pfn); - - return -ENOMEM; -} - -static int __meminit offline_page_cgroup(unsigned long start_pfn, - unsigned long nr_pages, int nid) -{ - unsigned long start, end, pfn; - - start = SECTION_ALIGN_DOWN(start_pfn); - end = SECTION_ALIGN_UP(start_pfn + nr_pages); - - for (pfn = start; pfn < end; pfn += PAGES_PER_SECTION) - __free_page_cgroup(pfn); - return 0; - -} - -static int __meminit page_cgroup_callback(struct notifier_block *self, - unsigned long action, void *arg) -{ - struct memory_notify *mn = arg; - int ret = 0; - switch (action) { - case MEM_GOING_ONLINE: - ret = online_page_cgroup(mn->start_pfn, - mn->nr_pages, mn->status_change_nid); - break; - case MEM_OFFLINE: - offline_page_cgroup(mn->start_pfn, - mn->nr_pages, mn->status_change_nid); - break; - case MEM_CANCEL_ONLINE: - offline_page_cgroup(mn->start_pfn, - mn->nr_pages, mn->status_change_nid); - break; - case MEM_GOING_OFFLINE: - break; - case MEM_ONLINE: - case MEM_CANCEL_OFFLINE: - break; - } - - return notifier_from_errno(ret); -} - -#endif - -void __init page_cgroup_init(void) -{ - unsigned long pfn; - int nid; - - if (mem_cgroup_disabled()) - return; - - for_each_node_state(nid, N_MEMORY) { - unsigned long start_pfn, end_pfn; - - start_pfn = node_start_pfn(nid); - end_pfn = node_end_pfn(nid); - /* - * start_pfn and end_pfn may not be aligned to SECTION and the - * page->flags of out of node pages are not initialized. So we - * scan [start_pfn, the biggest section's pfn < end_pfn) here. - */ - for (pfn = start_pfn; - pfn < end_pfn; - pfn = ALIGN(pfn + 1, PAGES_PER_SECTION)) { - - if (!pfn_valid(pfn)) - continue; - /* - * Nodes's pfns can be overlapping. - * We know some arch can have a nodes layout such as - * -------------pfn--------------> - * N0 | N1 | N2 | N0 | N1 | N2|.... - */ - if (pfn_to_nid(pfn) != nid) - continue; - if (init_section_page_cgroup(pfn, nid)) - goto oom; - } - } - hotplug_memory_notifier(page_cgroup_callback, 0); - printk(KERN_INFO "allocated %ld bytes of page_cgroup\n", total_usage); - printk(KERN_INFO "please try 'cgroup_disable=memory' option if you " - "don't want memory cgroups\n"); - return; -oom: - printk(KERN_CRIT "try 'cgroup_disable=memory' boot option\n"); - panic("Out of memory"); -} - -void __meminit pgdat_page_cgroup_init(struct pglist_data *pgdat) -{ - return; -} - -#endif - #ifdef CONFIG_MEMCG_SWAP -- cgit v1.2.3-59-g8ed1b From 9e3961a0979817c612b10b2da4f3045ec9faa779 Mon Sep 17 00:00:00 2001 From: Prarit Bhargava Date: Wed, 10 Dec 2014 15:45:50 -0800 Subject: kernel: add panic_on_warn There have been several times where I have had to rebuild a kernel to cause a panic when hitting a WARN() in the code in order to get a crash dump from a system. Sometimes this is easy to do, other times (such as in the case of a remote admin) it is not trivial to send new images to the user. A much easier method would be a switch to change the WARN() over to a panic. This makes debugging easier in that I can now test the actual image the WARN() was seen on and I do not have to engage in remote debugging. This patch adds a panic_on_warn kernel parameter and /proc/sys/kernel/panic_on_warn calls panic() in the warn_slowpath_common() path. The function will still print out the location of the warning. An example of the panic_on_warn output: The first line below is from the WARN_ON() to output the WARN_ON()'s location. After that the panic() output is displayed. WARNING: CPU: 30 PID: 11698 at /home/prarit/dummy_module/dummy-module.c:25 init_dummy+0x1f/0x30 [dummy_module]() Kernel panic - not syncing: panic_on_warn set ... CPU: 30 PID: 11698 Comm: insmod Tainted: G W OE 3.17.0+ #57 Hardware name: Intel Corporation S2600CP/S2600CP, BIOS RMLSDP.86I.00.29.D696.1311111329 11/11/2013 0000000000000000 000000008e3f87df ffff88080f093c38 ffffffff81665190 0000000000000000 ffffffff818aea3d ffff88080f093cb8 ffffffff8165e2ec ffffffff00000008 ffff88080f093cc8 ffff88080f093c68 000000008e3f87df Call Trace: [] dump_stack+0x46/0x58 [] panic+0xd0/0x204 [] ? init_dummy+0x1f/0x30 [dummy_module] [] warn_slowpath_common+0xd0/0xd0 [] ? dummy_greetings+0x40/0x40 [dummy_module] [] warn_slowpath_null+0x1a/0x20 [] init_dummy+0x1f/0x30 [dummy_module] [] do_one_initcall+0xd4/0x210 [] ? __vunmap+0xc2/0x110 [] load_module+0x16a9/0x1b30 [] ? store_uevent+0x70/0x70 [] ? copy_module_from_fd.isra.44+0x129/0x180 [] SyS_finit_module+0xa6/0xd0 [] system_call_fastpath+0x12/0x17 Successfully tested by me. hpa said: There is another very valid use for this: many operators would rather a machine shuts down than being potentially compromised either functionally or security-wise. Signed-off-by: Prarit Bhargava Cc: Jonathan Corbet Cc: Rusty Russell Cc: "H. Peter Anvin" Cc: Andi Kleen Cc: Masami Hiramatsu Acked-by: Yasuaki Ishimatsu Cc: Fabian Frederick Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/kdump/kdump.txt | 7 +++++++ Documentation/kernel-parameters.txt | 3 +++ Documentation/sysctl/kernel.txt | 40 ++++++++++++++++++++++++------------- include/linux/kernel.h | 1 + include/uapi/linux/sysctl.h | 1 + kernel/panic.c | 13 ++++++++++++ kernel/sysctl.c | 9 +++++++++ kernel/sysctl_binary.c | 1 + 8 files changed, 61 insertions(+), 14 deletions(-) (limited to 'Documentation') diff --git a/Documentation/kdump/kdump.txt b/Documentation/kdump/kdump.txt index 6c0b9f27e465..bc4bd5a44b88 100644 --- a/Documentation/kdump/kdump.txt +++ b/Documentation/kdump/kdump.txt @@ -471,6 +471,13 @@ format. Crash is available on Dave Anderson's site at the following URL: http://people.redhat.com/~anderson/ +Trigger Kdump on WARN() +======================= + +The kernel parameter, panic_on_warn, calls panic() in all WARN() paths. This +will cause a kdump to occur at the panic() call. In cases where a user wants +to specify this during runtime, /proc/sys/kernel/panic_on_warn can be set to 1 +to achieve the same behaviour. Contact ======= diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 838f3776c924..d6eb3636fe5a 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -2509,6 +2509,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted. timeout < 0: reboot immediately Format: + panic_on_warn panic() instead of WARN(). Useful to cause kdump + on a WARN(). + crash_kexec_post_notifiers Run kdump after running panic-notifiers and dumping kmsg. This only for the users who doubt kdump always diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt index 57baff5bdb80..b5d0c8501a18 100644 --- a/Documentation/sysctl/kernel.txt +++ b/Documentation/sysctl/kernel.txt @@ -54,8 +54,9 @@ show up in /proc/sys/kernel: - overflowuid - panic - panic_on_oops -- panic_on_unrecovered_nmi - panic_on_stackoverflow +- panic_on_unrecovered_nmi +- panic_on_warn - pid_max - powersave-nap [ PPC only ] - printk @@ -527,19 +528,6 @@ the recommended setting is 60. ============================================================== -panic_on_unrecovered_nmi: - -The default Linux behaviour on an NMI of either memory or unknown is -to continue operation. For many environments such as scientific -computing it is preferable that the box is taken out and the error -dealt with than an uncorrected parity/ECC error get propagated. - -A small number of systems do generate NMI's for bizarre random reasons -such as power management so the default is off. That sysctl works like -the existing panic controls already in that directory. - -============================================================== - panic_on_oops: Controls the kernel's behaviour when an oops or BUG is encountered. @@ -563,6 +551,30 @@ This file shows up if CONFIG_DEBUG_STACKOVERFLOW is enabled. ============================================================== +panic_on_unrecovered_nmi: + +The default Linux behaviour on an NMI of either memory or unknown is +to continue operation. For many environments such as scientific +computing it is preferable that the box is taken out and the error +dealt with than an uncorrected parity/ECC error get propagated. + +A small number of systems do generate NMI's for bizarre random reasons +such as power management so the default is off. That sysctl works like +the existing panic controls already in that directory. + +============================================================== + +panic_on_warn: + +Calls panic() in the WARN() path when set to 1. This is useful to avoid +a kernel rebuild when attempting to kdump at the location of a WARN(). + +0: only WARN(), default behaviour. + +1: call panic() after printing out WARN() location. + +============================================================== + perf_cpu_time_max_percent: Hints to the kernel how much CPU time it should be allowed to diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 446d76a87ba1..233ea8107038 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -427,6 +427,7 @@ extern int panic_timeout; extern int panic_on_oops; extern int panic_on_unrecovered_nmi; extern int panic_on_io_nmi; +extern int panic_on_warn; extern int sysctl_panic_on_stackoverflow; /* * Only to be used by arch init code. If the user over-wrote the default diff --git a/include/uapi/linux/sysctl.h b/include/uapi/linux/sysctl.h index 43aaba1cc037..0956373b56db 100644 --- a/include/uapi/linux/sysctl.h +++ b/include/uapi/linux/sysctl.h @@ -153,6 +153,7 @@ enum KERN_MAX_LOCK_DEPTH=74, /* int: rtmutex's maximum lock depth */ KERN_NMI_WATCHDOG=75, /* int: enable/disable nmi watchdog */ KERN_PANIC_ON_NMI=76, /* int: whether we will panic on an unrecovered */ + KERN_PANIC_ON_WARN=77, /* int: call panic() in WARN() functions */ }; diff --git a/kernel/panic.c b/kernel/panic.c index cf80672b7924..4d8d6f906dec 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -33,6 +33,7 @@ static int pause_on_oops; static int pause_on_oops_flag; static DEFINE_SPINLOCK(pause_on_oops_lock); static bool crash_kexec_post_notifiers; +int panic_on_warn __read_mostly; int panic_timeout = CONFIG_PANIC_TIMEOUT; EXPORT_SYMBOL_GPL(panic_timeout); @@ -428,6 +429,17 @@ static void warn_slowpath_common(const char *file, int line, void *caller, if (args) vprintk(args->fmt, args->args); + if (panic_on_warn) { + /* + * This thread may hit another WARN() in the panic path. + * Resetting this prevents additional WARN() from panicking the + * system on this thread. Other threads are blocked by the + * panic_mutex in panic(). + */ + panic_on_warn = 0; + panic("panic_on_warn set ...\n"); + } + print_modules(); dump_stack(); print_oops_end_marker(); @@ -485,6 +497,7 @@ EXPORT_SYMBOL(__stack_chk_fail); core_param(panic, panic_timeout, int, 0644); core_param(pause_on_oops, pause_on_oops, int, 0644); +core_param(panic_on_warn, panic_on_warn, int, 0644); static int __init setup_crash_kexec_post_notifiers(char *s) { diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 15f2511a1b7c..7c54ff79afd7 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -1104,6 +1104,15 @@ static struct ctl_table kern_table[] = { .proc_handler = proc_dointvec, }, #endif + { + .procname = "panic_on_warn", + .data = &panic_on_warn, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = &zero, + .extra2 = &one, + }, { } }; diff --git a/kernel/sysctl_binary.c b/kernel/sysctl_binary.c index 9a4f750a2963..7e7746a42a62 100644 --- a/kernel/sysctl_binary.c +++ b/kernel/sysctl_binary.c @@ -137,6 +137,7 @@ static const struct bin_table bin_kern_table[] = { { CTL_INT, KERN_COMPAT_LOG, "compat-log" }, { CTL_INT, KERN_MAX_LOCK_DEPTH, "max_lock_depth" }, { CTL_INT, KERN_PANIC_ON_NMI, "panic_on_unrecovered_nmi" }, + { CTL_INT, KERN_PANIC_ON_WARN, "panic_on_warn" }, {} }; -- cgit v1.2.3-59-g8ed1b From 222a12fca6048249d9007f2a4c5fbcea532e8522 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 10 Dec 2014 15:53:13 -0800 Subject: rtc: omap: add support for pmic_power_en Add new property "ti,system-power-controller" to register the RTC as a power-off handler. Some RTC IP revisions can control an external PMIC via the pmic_power_en pin, which can be configured to transition to OFF on ALARM2 events and back to ON on subsequent ALARM (wakealarm) events. This is based on earlier work by Colin Foe-Parker and AnilKumar Ch. [1] [1] https://www.mail-archive.com/linux-omap@vger.kernel.org/msg82127.html [akpm@linux-foundation.org: add comment] Signed-off-by: Johan Hovold Cc: Colin Foe-Parker Cc: AnilKumar Ch Cc: Alessandro Zummo Cc: Tony Lindgren Cc: Benot Cousson Cc: Lokesh Vutla Cc: Guenter Roeck Cc: Sekhar Nori Cc: Tero Kristo Cc: Keerthy J Tested-by: Felipe Balbi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/devicetree/bindings/rtc/rtc-omap.txt | 9 +- drivers/rtc/rtc-omap.c | 100 +++++++++++++++++++++ 2 files changed, 108 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/rtc/rtc-omap.txt b/Documentation/devicetree/bindings/rtc/rtc-omap.txt index 5a0f02d34d95..750efd40c72e 100644 --- a/Documentation/devicetree/bindings/rtc/rtc-omap.txt +++ b/Documentation/devicetree/bindings/rtc/rtc-omap.txt @@ -5,11 +5,17 @@ Required properties: - "ti,da830-rtc" - for RTC IP used similar to that on DA8xx SoC family. - "ti,am3352-rtc" - for RTC IP used similar to that on AM335x SoC family. This RTC IP has special WAKE-EN Register to enable - Wakeup generation for event Alarm. + Wakeup generation for event Alarm. It can also be + used to control an external PMIC via the + pmic_power_en pin. - reg: Address range of rtc register set - interrupts: rtc timer, alarm interrupts in order - interrupt-parent: phandle for the interrupt controller +Optional properties: +- ti,system-power-controller: whether the rtc is controlling the system power + through pmic_power_en + Example: rtc@1c23000 { @@ -18,4 +24,5 @@ rtc@1c23000 { interrupts = <19 19>; interrupt-parent = <&intc>; + ti,system-power-controller; }; diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index c508e45ca3ce..e83f51ae7f63 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -68,6 +68,15 @@ #define OMAP_RTC_IRQWAKEEN 0x7c +#define OMAP_RTC_ALARM2_SECONDS_REG 0x80 +#define OMAP_RTC_ALARM2_MINUTES_REG 0x84 +#define OMAP_RTC_ALARM2_HOURS_REG 0x88 +#define OMAP_RTC_ALARM2_DAYS_REG 0x8c +#define OMAP_RTC_ALARM2_MONTHS_REG 0x90 +#define OMAP_RTC_ALARM2_YEARS_REG 0x94 + +#define OMAP_RTC_PMIC_REG 0x98 + /* OMAP_RTC_CTRL_REG bit fields: */ #define OMAP_RTC_CTRL_SPLIT BIT(7) #define OMAP_RTC_CTRL_DISABLE BIT(6) @@ -80,6 +89,7 @@ /* OMAP_RTC_STATUS_REG bit fields: */ #define OMAP_RTC_STATUS_POWER_UP BIT(7) +#define OMAP_RTC_STATUS_ALARM2 BIT(7) #define OMAP_RTC_STATUS_ALARM BIT(6) #define OMAP_RTC_STATUS_1D_EVENT BIT(5) #define OMAP_RTC_STATUS_1H_EVENT BIT(4) @@ -89,6 +99,7 @@ #define OMAP_RTC_STATUS_BUSY BIT(0) /* OMAP_RTC_INTERRUPTS_REG bit fields: */ +#define OMAP_RTC_INTERRUPTS_IT_ALARM2 BIT(4) #define OMAP_RTC_INTERRUPTS_IT_ALARM BIT(3) #define OMAP_RTC_INTERRUPTS_IT_TIMER BIT(2) @@ -98,6 +109,9 @@ /* OMAP_RTC_IRQWAKEEN bit fields: */ #define OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN BIT(1) +/* OMAP_RTC_PMIC bit fields: */ +#define OMAP_RTC_PMIC_POWER_EN_EN BIT(16) + /* OMAP_RTC_KICKER values */ #define KICK0_VALUE 0x83e70b13 #define KICK1_VALUE 0x95a4f1e0 @@ -106,6 +120,7 @@ struct omap_rtc_device_type { bool has_32kclk_en; bool has_kicker; bool has_irqwakeen; + bool has_pmic_mode; bool has_power_up_reset; }; @@ -115,6 +130,7 @@ struct omap_rtc { int irq_alarm; int irq_timer; u8 interrupts_reg; + bool is_pmic_controller; const struct omap_rtc_device_type *type; }; @@ -345,6 +361,70 @@ static int omap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) return 0; } +static struct omap_rtc *omap_rtc_power_off_rtc; + +/* + * omap_rtc_poweroff: RTC-controlled power off + * + * The RTC can be used to control an external PMIC via the pmic_power_en pin, + * which can be configured to transition to OFF on ALARM2 events. + * + * Notes: + * The two-second alarm offset is the shortest offset possible as the alarm + * registers must be set before the next timer update and the offset + * calculation is too heavy for everything to be done within a single access + * period (~15 us). + * + * Called with local interrupts disabled. + */ +static void omap_rtc_power_off(void) +{ + struct omap_rtc *rtc = omap_rtc_power_off_rtc; + struct rtc_time tm; + unsigned long now; + u32 val; + + /* enable pmic_power_en control */ + val = rtc_readl(rtc, OMAP_RTC_PMIC_REG); + rtc_writel(rtc, OMAP_RTC_PMIC_REG, val | OMAP_RTC_PMIC_POWER_EN_EN); + + /* set alarm two seconds from now */ + omap_rtc_read_time_raw(rtc, &tm); + bcd2tm(&tm); + rtc_tm_to_time(&tm, &now); + rtc_time_to_tm(now + 2, &tm); + + if (tm2bcd(&tm) < 0) { + dev_err(&rtc->rtc->dev, "power off failed\n"); + return; + } + + rtc_wait_not_busy(rtc); + + rtc_write(rtc, OMAP_RTC_ALARM2_SECONDS_REG, tm.tm_sec); + rtc_write(rtc, OMAP_RTC_ALARM2_MINUTES_REG, tm.tm_min); + rtc_write(rtc, OMAP_RTC_ALARM2_HOURS_REG, tm.tm_hour); + rtc_write(rtc, OMAP_RTC_ALARM2_DAYS_REG, tm.tm_mday); + rtc_write(rtc, OMAP_RTC_ALARM2_MONTHS_REG, tm.tm_mon); + rtc_write(rtc, OMAP_RTC_ALARM2_YEARS_REG, tm.tm_year); + + /* + * enable ALARM2 interrupt + * + * NOTE: this fails on AM3352 if rtc_write (writeb) is used + */ + val = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG); + rtc_writel(rtc, OMAP_RTC_INTERRUPTS_REG, + val | OMAP_RTC_INTERRUPTS_IT_ALARM2); + + /* + * Wait for alarm to trigger (within two seconds) and external PMIC to + * power off the system. Add a 500 ms margin for external latencies + * (e.g. debounce circuits). + */ + mdelay(2500); +} + static struct rtc_class_ops omap_rtc_ops = { .read_time = omap_rtc_read_time, .set_time = omap_rtc_set_time, @@ -361,6 +441,7 @@ static const struct omap_rtc_device_type omap_rtc_am3352_type = { .has_32kclk_en = true, .has_kicker = true, .has_irqwakeen = true, + .has_pmic_mode = true, }; static const struct omap_rtc_device_type omap_rtc_da830_type = { @@ -412,6 +493,9 @@ static int __init omap_rtc_probe(struct platform_device *pdev) of_id = of_match_device(omap_rtc_of_match, &pdev->dev); if (of_id) { rtc->type = of_id->data; + rtc->is_pmic_controller = rtc->type->has_pmic_mode && + of_property_read_bool(pdev->dev.of_node, + "ti,system-power-controller"); } else { id_entry = platform_get_device_id(pdev); rtc->type = (void *)id_entry->driver_data; @@ -460,6 +544,9 @@ static int __init omap_rtc_probe(struct platform_device *pdev) mask = OMAP_RTC_STATUS_ALARM; + if (rtc->type->has_pmic_mode) + mask |= OMAP_RTC_STATUS_ALARM2; + if (rtc->type->has_power_up_reset) { mask |= OMAP_RTC_STATUS_POWER_UP; if (reg & OMAP_RTC_STATUS_POWER_UP) @@ -520,6 +607,13 @@ static int __init omap_rtc_probe(struct platform_device *pdev) goto err; } + if (rtc->is_pmic_controller) { + if (!pm_power_off) { + omap_rtc_power_off_rtc = rtc; + pm_power_off = omap_rtc_power_off; + } + } + return 0; err: @@ -536,6 +630,12 @@ static int __exit omap_rtc_remove(struct platform_device *pdev) { struct omap_rtc *rtc = platform_get_drvdata(pdev); + if (pm_power_off == omap_rtc_power_off && + omap_rtc_power_off_rtc == rtc) { + pm_power_off = NULL; + omap_rtc_power_off_rtc = NULL; + } + device_init_wakeup(&pdev->dev, 0); /* leave rtc running, but disable irqs */ -- cgit v1.2.3-59-g8ed1b From dd01a1c526d200b25b421460550f67d5a9c6874b Mon Sep 17 00:00:00 2001 From: Tomas Novotny Date: Wed, 10 Dec 2014 15:53:59 -0800 Subject: of: add vendor prefix for Pericom Technology Signed-off-by: Tomas Novotny Cc: Alessandro Zummo Cc: Grant Likely Cc: Rob Herring Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- 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 0d354625299c..2417cb0b493b 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -115,6 +115,7 @@ nxp NXP Semiconductors onnn ON Semiconductor Corp. opencores OpenCores.org panasonic Panasonic Corporation +pericom Pericom Technology Inc. phytec PHYTEC Messtechnik GmbH picochip Picochip Ltd plathome Plat'Home Co., Ltd. -- cgit v1.2.3-59-g8ed1b From 094d3ee3ce8c30756446518cc1895b6bbbca12ef Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 10 Dec 2014 15:54:14 -0800 Subject: rtc: omap: drop vendor-prefix from power-controller dt property Drop the vendor-prefix from the "ti,system-power-controller" device-tree property name. It has been agreed to make "system-power-controller" a standard property and to drop the vendor-prefix that is currently used by several drivers. Note that drivers that have used ",system-power-controller" in a released kernel will need to support both versions. Signed-off-by: Johan Hovold Cc: Tony Lindgren Cc: Benot Cousson Cc: Alessandro Zummo Cc: Felipe Balbi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/devicetree/bindings/rtc/rtc-omap.txt | 4 ++-- arch/arm/boot/dts/am335x-boneblack.dts | 2 +- drivers/rtc/rtc-omap.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/rtc/rtc-omap.txt b/Documentation/devicetree/bindings/rtc/rtc-omap.txt index 750efd40c72e..4ba4dbd34289 100644 --- a/Documentation/devicetree/bindings/rtc/rtc-omap.txt +++ b/Documentation/devicetree/bindings/rtc/rtc-omap.txt @@ -13,7 +13,7 @@ Required properties: - interrupt-parent: phandle for the interrupt controller Optional properties: -- ti,system-power-controller: whether the rtc is controlling the system power +- system-power-controller: whether the rtc is controlling the system power through pmic_power_en Example: @@ -24,5 +24,5 @@ rtc@1c23000 { interrupts = <19 19>; interrupt-parent = <&intc>; - ti,system-power-controller; + system-power-controller; }; diff --git a/arch/arm/boot/dts/am335x-boneblack.dts b/arch/arm/boot/dts/am335x-boneblack.dts index 520b63605eb6..5c42d259fa68 100644 --- a/arch/arm/boot/dts/am335x-boneblack.dts +++ b/arch/arm/boot/dts/am335x-boneblack.dts @@ -82,5 +82,5 @@ }; &rtc { - ti,system-power-controller; + system-power-controller; }; diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index fba13e53c278..4f1c6ca97211 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -502,7 +502,7 @@ static int __init omap_rtc_probe(struct platform_device *pdev) rtc->type = of_id->data; rtc->is_pmic_controller = rtc->type->has_pmic_mode && of_property_read_bool(pdev->dev.of_node, - "ti,system-power-controller"); + "system-power-controller"); } else { id_entry = platform_get_device_id(pdev); rtc->type = (void *)id_entry->driver_data; -- cgit v1.2.3-59-g8ed1b From 3161293ba6dfceee9c1efe75185677445def05d4 Mon Sep 17 00:00:00 2001 From: Gabriele Mazzotta Date: Wed, 3 Dec 2014 18:41:33 +0100 Subject: Documentation: Add entry for dell-laptop sysfs interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the documentation for the new sysfs interface of dell-laptop that allows to configure the keyboard illumination on Dell systems. Signed-off-by: Gabriele Mazzotta Signed-off-by: Pali Rohár Signed-off-by: Darren Hart --- .../ABI/testing/sysfs-platform-dell-laptop | 60 ++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-platform-dell-laptop (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-platform-dell-laptop b/Documentation/ABI/testing/sysfs-platform-dell-laptop new file mode 100644 index 000000000000..7969443ef0ef --- /dev/null +++ b/Documentation/ABI/testing/sysfs-platform-dell-laptop @@ -0,0 +1,60 @@ +What: /sys/class/leds/dell::kbd_backlight/als_setting +Date: December 2014 +KernelVersion: 3.19 +Contact: Gabriele Mazzotta , + Pali Rohár +Description: + This file allows to control the automatic keyboard + illumination mode on some systems that have an ambient + light sensor. Write 1 to this file to enable the auto + mode, 0 to disable it. + +What: /sys/class/leds/dell::kbd_backlight/start_triggers +Date: December 2014 +KernelVersion: 3.19 +Contact: Gabriele Mazzotta , + Pali Rohár +Description: + This file allows to control the input triggers that + turn on the keyboard backlight illumination that is + disabled because of inactivity. + Read the file to see the triggers available. The ones + enabled are preceded by '+', those disabled by '-'. + + To enable a trigger, write its name preceded by '+' to + this file. To disable a trigger, write its name preceded + by '-' instead. + + For example, to enable the keyboard as trigger run: + echo +keyboard > /sys/class/leds/dell::kbd_backlight/start_triggers + To disable it: + echo -keyboard > /sys/class/leds/dell::kbd_backlight/start_triggers + + Note that not all the available triggers can be configured. + +What: /sys/class/leds/dell::kbd_backlight/stop_timeout +Date: December 2014 +KernelVersion: 3.19 +Contact: Gabriele Mazzotta , + Pali Rohár +Description: + This file allows to specify the interval after which the + keyboard illumination is disabled because of inactivity. + The timeouts are expressed in seconds, minutes, hours and + days, for which the symbols are 's', 'm', 'h' and 'd' + respectively. + + To configure the timeout, write to this file a value along + with any the above units. If no unit is specified, the value + is assumed to be expressed in seconds. + + For example, to set the timeout to 10 minutes run: + echo 10m > /sys/class/leds/dell::kbd_backlight/stop_timeout + + Note that when this file is read, the returned value might be + expressed in a different unit than the one used when the timeout + was set. + + Also note that only some timeouts are supported and that + some systems might fall back to a specific timeout in case + an invalid timeout is written to this file. -- cgit v1.2.3-59-g8ed1b From 96ed4cd0aa86ac1a753baeef26c911a9449493e9 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 9 Dec 2014 14:54:44 -0800 Subject: x86/doc: Update documentation after file shuffling While at it, also refer to the 32 bit entry file. Signed-off-by: Luis R. Rodriguez Cc: H. Peter Anvin Cc: Borislav Petkov Cc: linux-doc@vger.kernel.org Cc: bpoirier@suse.de Link: http://lkml.kernel.org/r/1418165684-6226-1-git-send-email-mcgrof@do-not-panic.com Signed-off-by: Ingo Molnar --- Documentation/x86/entry_64.txt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/x86/entry_64.txt b/Documentation/x86/entry_64.txt index bc7226ef5055..4a1c5c2dc5a9 100644 --- a/Documentation/x86/entry_64.txt +++ b/Documentation/x86/entry_64.txt @@ -7,9 +7,12 @@ http://lkml.kernel.org/r/<20110529191055.GC9835%40elte.hu> The x86 architecture has quite a few different ways to jump into kernel code. Most of these entry points are registered in arch/x86/kernel/traps.c and implemented in arch/x86/kernel/entry_64.S -and arch/x86/ia32/ia32entry.S. +for 64-bit, arch/x86/kernel/entry_32.S for 32-bit and finally +arch/x86/ia32/ia32entry.S which implements the 32-bit compatibility +syscall entry points and thus provides for 32-bit processes the +ability to execute syscalls when running on 64-bit kernels. -The IDT vector assignments are listed in arch/x86/include/irq_vectors.h. +The IDT vector assignments are listed in arch/x86/include/asm/irq_vectors.h. Some of these entries are: -- cgit v1.2.3-59-g8ed1b From 41a14623bd7345017b62f167110cf95808a4891a Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Mon, 8 Sep 2014 15:52:08 +0200 Subject: drm: sti: allow to change hdmi ddc i2c adapter Depending of the board configuration i2c for ddc could change, this patch allow to use a phandle to specify which i2c controller to use. Signed-off-by: Benjamin Gaignard --- .../devicetree/bindings/gpu/st,stih4xx.txt | 1 + drivers/gpu/drm/sti/sti_hdmi.c | 40 +++++++++++++++------- drivers/gpu/drm/sti/sti_hdmi.h | 1 + 3 files changed, 29 insertions(+), 13 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/gpu/st,stih4xx.txt b/Documentation/devicetree/bindings/gpu/st,stih4xx.txt index 2d150c311a05..8885d9e203fc 100644 --- a/Documentation/devicetree/bindings/gpu/st,stih4xx.txt +++ b/Documentation/devicetree/bindings/gpu/st,stih4xx.txt @@ -69,6 +69,7 @@ STMicroelectronics stih4xx platforms - clock-names: names of the clocks listed in clocks property in the same order. - hdmi,hpd-gpio: gpio id to detect if an hdmi cable is plugged or not. + - ddc: phandle of an I2C controller used for DDC EDID probing sti-hda: Required properties: diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c index b22968c08d1f..fed1b5fe4842 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.c +++ b/drivers/gpu/drm/sti/sti_hdmi.c @@ -480,17 +480,15 @@ static const struct drm_bridge_funcs sti_hdmi_bridge_funcs = { static int sti_hdmi_connector_get_modes(struct drm_connector *connector) { - struct i2c_adapter *i2c_adap; + struct sti_hdmi_connector *hdmi_connector + = to_sti_hdmi_connector(connector); + struct sti_hdmi *hdmi = hdmi_connector->hdmi; struct edid *edid; int count; DRM_DEBUG_DRIVER("\n"); - i2c_adap = i2c_get_adapter(1); - if (!i2c_adap) - goto fail; - - edid = drm_get_edid(connector, i2c_adap); + edid = drm_get_edid(connector, hdmi->ddc_adapt); if (!edid) goto fail; @@ -603,29 +601,38 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data) struct sti_hdmi_connector *connector; struct drm_connector *drm_connector; struct drm_bridge *bridge; - struct i2c_adapter *i2c_adap; + struct device_node *ddc; int err; - i2c_adap = i2c_get_adapter(1); - if (!i2c_adap) - return -EPROBE_DEFER; + ddc = of_parse_phandle(dev->of_node, "ddc", 0); + if (ddc) { + hdmi->ddc_adapt = of_find_i2c_adapter_by_node(ddc); + if (!hdmi->ddc_adapt) { + err = -EPROBE_DEFER; + of_node_put(ddc); + return err; + } + + of_node_put(ddc); + } /* Set the drm device handle */ hdmi->drm_dev = drm_dev; encoder = sti_hdmi_find_encoder(drm_dev); if (!encoder) - return -ENOMEM; + goto err_adapt; connector = devm_kzalloc(dev, sizeof(*connector), GFP_KERNEL); if (!connector) - return -ENOMEM; + goto err_adapt; + connector->hdmi = hdmi; bridge = devm_kzalloc(dev, sizeof(*bridge), GFP_KERNEL); if (!bridge) - return -ENOMEM; + goto err_adapt; bridge->driver_private = hdmi; drm_bridge_init(drm_dev, bridge, &sti_hdmi_bridge_funcs); @@ -662,6 +669,8 @@ err_sysfs: err_connector: drm_bridge_cleanup(bridge); drm_connector_cleanup(drm_connector); +err_adapt: + put_device(&hdmi->ddc_adapt->dev); return -EINVAL; } @@ -788,6 +797,11 @@ static int sti_hdmi_probe(struct platform_device *pdev) static int sti_hdmi_remove(struct platform_device *pdev) { + struct sti_hdmi *hdmi = dev_get_drvdata(&pdev->dev); + + if (hdmi->ddc_adapt) + put_device(&hdmi->ddc_adapt->dev); + component_del(&pdev->dev, &sti_hdmi_ops); return 0; } diff --git a/drivers/gpu/drm/sti/sti_hdmi.h b/drivers/gpu/drm/sti/sti_hdmi.h index 61bec6557ceb..d00a3e0d807f 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.h +++ b/drivers/gpu/drm/sti/sti_hdmi.h @@ -62,6 +62,7 @@ struct sti_hdmi { wait_queue_head_t wait_event; bool event_received; struct reset_control *reset; + struct i2c_adapter *ddc_adapt; }; u32 hdmi_read(struct sti_hdmi *hdmi, int offset); -- cgit v1.2.3-59-g8ed1b From 765692078f08d0229e545d3c1a50bddbc16c800c Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Oct 2014 08:53:35 +0200 Subject: drm: sti: remove gpio for HDMI hot plug detection gpio used for HDMI hot plug detection is useless, HDMI_STI register contains an hot plug detection status bit. Fix binding documentation. Signed-off-by: Benjamin Gaignard --- Documentation/devicetree/bindings/gpu/st,stih4xx.txt | 2 -- drivers/gpu/drm/sti/sti_hdmi.c | 11 ++--------- drivers/gpu/drm/sti/sti_hdmi.h | 5 +++-- 3 files changed, 5 insertions(+), 13 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/gpu/st,stih4xx.txt b/Documentation/devicetree/bindings/gpu/st,stih4xx.txt index 8885d9e203fc..32cfc7b7631b 100644 --- a/Documentation/devicetree/bindings/gpu/st,stih4xx.txt +++ b/Documentation/devicetree/bindings/gpu/st,stih4xx.txt @@ -68,7 +68,6 @@ STMicroelectronics stih4xx platforms number of clocks may depend of the SoC type. - clock-names: names of the clocks listed in clocks property in the same order. - - hdmi,hpd-gpio: gpio id to detect if an hdmi cable is plugged or not. - ddc: phandle of an I2C controller used for DDC EDID probing sti-hda: @@ -174,7 +173,6 @@ Example: interrupt-names = "irq"; clock-names = "pix", "tmds", "phy", "audio"; clocks = <&clockgen_c_vcc CLK_S_PIX_HDMI>, <&clockgen_c_vcc CLK_S_TMDS_HDMI>, <&clockgen_c_vcc CLK_S_HDMI_REJECT_PLL>, <&clockgen_b1 CLK_S_PCM_0>; - hdmi,hpd-gpio = <&PIO2 5>; }; sti-hda@fe85a000 { diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c index fed1b5fe4842..192119761c14 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.c +++ b/drivers/gpu/drm/sti/sti_hdmi.c @@ -130,8 +130,7 @@ static irqreturn_t hdmi_irq_thread(int irq, void *arg) /* Hot plug/unplug IRQ */ if (hdmi->irq_status & HDMI_INT_HOT_PLUG) { - /* read gpio to get the status */ - hdmi->hpd = gpio_get_value(hdmi->hpd_gpio); + hdmi->hpd = readl(hdmi->regs + HDMI_STA) & HDMI_STA_HOT_PLUG; if (hdmi->drm_dev) drm_helper_hpd_irq_event(hdmi->drm_dev); } @@ -766,13 +765,7 @@ static int sti_hdmi_probe(struct platform_device *pdev) return PTR_ERR(hdmi->clk_audio); } - hdmi->hpd_gpio = of_get_named_gpio(np, "hdmi,hpd-gpio", 0); - if (hdmi->hpd_gpio < 0) { - DRM_ERROR("Failed to get hdmi hpd-gpio\n"); - return -EIO; - } - - hdmi->hpd = gpio_get_value(hdmi->hpd_gpio); + hdmi->hpd = readl(hdmi->regs + HDMI_STA) & HDMI_STA_HOT_PLUG; init_waitqueue_head(&hdmi->wait_event); diff --git a/drivers/gpu/drm/sti/sti_hdmi.h b/drivers/gpu/drm/sti/sti_hdmi.h index d00a3e0d807f..3d22390e1f3b 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.h +++ b/drivers/gpu/drm/sti/sti_hdmi.h @@ -14,6 +14,9 @@ #define HDMI_STA 0x0010 #define HDMI_STA_DLL_LCK BIT(5) +#define HDMI_STA_HOT_PLUG_SHIFT 4 +#define HDMI_STA_HOT_PLUG (1 << HDMI_STA_HOT_PLUG_SHIFT) + struct sti_hdmi; struct hdmi_phy_ops { @@ -37,7 +40,6 @@ struct hdmi_phy_ops { * @irq_status: interrupt status register * @phy_ops: phy start/stop operations * @enabled: true if hdmi is enabled else false - * @hpd_gpio: hdmi hot plug detect gpio number * @hpd: hot plug detect status * @wait_event: wait event * @event_received: wait event status @@ -57,7 +59,6 @@ struct sti_hdmi { u32 irq_status; struct hdmi_phy_ops *phy_ops; bool enabled; - int hpd_gpio; bool hpd; wait_queue_head_t wait_event; bool event_received; -- cgit v1.2.3-59-g8ed1b From 4fdbc678fe4dc18cbf1d97e1b45660f91c3089b4 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 11 Dec 2014 11:38:59 +0100 Subject: drm: sti: add HQVDP plane High Quality Video Data Plane is hardware IP dedicated to video rendering. Compare to GPD (graphic planes) it have better scaler capabilities. HQVDP use VID layer to push data into hardware compositor without going into DDR. From data flow point of view HQVDP and VID are nested so HQVPD update/disable VID. Signed-off-by: Benjamin Gaignard --- .../devicetree/bindings/gpu/st,stih4xx.txt | 26 + drivers/gpu/drm/sti/Kconfig | 1 + drivers/gpu/drm/sti/Makefile | 3 +- drivers/gpu/drm/sti/sti_compositor.c | 1 + drivers/gpu/drm/sti/sti_drm_crtc.c | 6 +- drivers/gpu/drm/sti/sti_drm_plane.c | 3 +- drivers/gpu/drm/sti/sti_hqvdp.c | 1072 ++++++++++++++++++++ drivers/gpu/drm/sti/sti_hqvdp.h | 12 + drivers/gpu/drm/sti/sti_hqvdp_lut.h | 373 +++++++ drivers/gpu/drm/sti/sti_layer.c | 11 +- drivers/gpu/drm/sti/sti_layer.h | 10 +- drivers/gpu/drm/sti/sti_mixer.c | 2 + 12 files changed, 1513 insertions(+), 7 deletions(-) create mode 100644 drivers/gpu/drm/sti/sti_hqvdp.c create mode 100644 drivers/gpu/drm/sti/sti_hqvdp.h create mode 100644 drivers/gpu/drm/sti/sti_hqvdp_lut.h (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/gpu/st,stih4xx.txt b/Documentation/devicetree/bindings/gpu/st,stih4xx.txt index 32cfc7b7631b..c99eb34e640b 100644 --- a/Documentation/devicetree/bindings/gpu/st,stih4xx.txt +++ b/Documentation/devicetree/bindings/gpu/st,stih4xx.txt @@ -83,6 +83,22 @@ sti-hda: - clock-names: names of the clocks listed in clocks property in the same order. +sti-hqvdp: + must be a child of sti-display-subsystem + Required properties: + - compatible: "st,stih-hqvdp" + - reg: Physical base address of the IP registers and length of memory mapped region. + - clocks: from common clock binding: handle hardware IP needed clocks, the + number of clocks may depend of the SoC type. + See ../clocks/clock-bindings.txt for details. + - clock-names: names of the clocks listed in clocks property in the same + order. + - resets: resets to be used by the device + See ../reset/reset.txt for details. + - reset-names: names of the resets listed in resets property in the same + order. + - st,vtg: phandle on vtg main device node. + Example: / { @@ -183,6 +199,16 @@ Example: clocks = <&clockgen_c_vcc CLK_S_PIX_HD>, <&clockgen_c_vcc CLK_S_HDDAC>; }; }; + + sti-hqvdp@9c000000 { + compatible = "st,stih407-hqvdp"; + reg = <0x9C00000 0x100000>; + clock-names = "hqvdp", "pix_main"; + clocks = <&clk_s_c0_flexgen CLK_MAIN_DISP>, <&clk_s_d2_flexgen CLK_PIX_MAIN_DISP>; + reset-names = "hqvdp"; + resets = <&softreset STIH407_HDQVDP_SOFTRESET>; + st,vtg = <&vtg_main>; + }; }; ... }; diff --git a/drivers/gpu/drm/sti/Kconfig b/drivers/gpu/drm/sti/Kconfig index ae8850f3e63b..d6d6b705b8c1 100644 --- a/drivers/gpu/drm/sti/Kconfig +++ b/drivers/gpu/drm/sti/Kconfig @@ -5,6 +5,7 @@ config DRM_STI select DRM_KMS_HELPER select DRM_GEM_CMA_HELPER select DRM_KMS_CMA_HELPER + select FW_LOADER_USER_HELPER_FALLBACK help Choose this option to enable DRM on STM stiH41x chipset diff --git a/drivers/gpu/drm/sti/Makefile b/drivers/gpu/drm/sti/Makefile index d6128f7fa12c..6ba9d27c1b90 100644 --- a/drivers/gpu/drm/sti/Makefile +++ b/drivers/gpu/drm/sti/Makefile @@ -19,4 +19,5 @@ obj-$(CONFIG_DRM_STI) = \ sti_hda.o \ sti_tvout.o \ sticompositor.o \ - sti_drm_drv.o \ No newline at end of file + sti_hqvdp.o \ + sti_drm_drv.o diff --git a/drivers/gpu/drm/sti/sti_compositor.c b/drivers/gpu/drm/sti/sti_compositor.c index b9415b3f3720..c5cf4aea9694 100644 --- a/drivers/gpu/drm/sti/sti_compositor.c +++ b/drivers/gpu/drm/sti/sti_compositor.c @@ -122,6 +122,7 @@ static int sti_compositor_bind(struct device *dev, struct device *master, plane++; break; case STI_BCK: + case STI_VDP: break; } diff --git a/drivers/gpu/drm/sti/sti_drm_crtc.c b/drivers/gpu/drm/sti/sti_drm_crtc.c index 928b44fd3717..4c651c200f20 100644 --- a/drivers/gpu/drm/sti/sti_drm_crtc.c +++ b/drivers/gpu/drm/sti/sti_drm_crtc.c @@ -148,7 +148,8 @@ sti_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, w = crtc->primary->fb->width - x; h = crtc->primary->fb->height - y; - return sti_layer_prepare(layer, crtc->primary->fb, &crtc->mode, + return sti_layer_prepare(layer, crtc, + crtc->primary->fb, &crtc->mode, mixer->id, 0, 0, w, h, x, y, w, h); } @@ -175,7 +176,8 @@ static int sti_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, w = crtc->primary->fb->width - crtc->x; h = crtc->primary->fb->height - crtc->y; - ret = sti_layer_prepare(layer, crtc->primary->fb, &crtc->mode, + ret = sti_layer_prepare(layer, crtc, + crtc->primary->fb, &crtc->mode, mixer->id, 0, 0, w, h, crtc->x, crtc->y, w, h); if (ret) { diff --git a/drivers/gpu/drm/sti/sti_drm_plane.c b/drivers/gpu/drm/sti/sti_drm_plane.c index f4118d4cac22..c9dd0e57cac1 100644 --- a/drivers/gpu/drm/sti/sti_drm_plane.c +++ b/drivers/gpu/drm/sti/sti_drm_plane.c @@ -45,7 +45,8 @@ sti_drm_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, } /* src_x are in 16.16 format. */ - res = sti_layer_prepare(layer, fb, &crtc->mode, mixer->id, + res = sti_layer_prepare(layer, crtc, fb, + &crtc->mode, mixer->id, crtc_x, crtc_y, crtc_w, crtc_h, src_x >> 16, src_y >> 16, src_w >> 16, src_h >> 16); diff --git a/drivers/gpu/drm/sti/sti_hqvdp.c b/drivers/gpu/drm/sti/sti_hqvdp.c new file mode 100644 index 000000000000..200d02014575 --- /dev/null +++ b/drivers/gpu/drm/sti/sti_hqvdp.c @@ -0,0 +1,1072 @@ +/* + * Copyright (C) STMicroelectronics SA 2014 + * Authors: Fabien Dessenne for STMicroelectronics. + * License terms: GNU General Public License (GPL), version 2 + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "sti_drm_plane.h" +#include "sti_hqvdp.h" +#include "sti_hqvdp_lut.h" +#include "sti_layer.h" +#include "sti_vtg.h" + +/* Firmware name */ +#define HQVDP_FMW_NAME "hqvdp-stih407.bin" + +/* Regs address */ +#define HQVDP_DMEM 0x00000000 /* 0x00000000 */ +#define HQVDP_PMEM 0x00040000 /* 0x00040000 */ +#define HQVDP_RD_PLUG 0x000E0000 /* 0x000E0000 */ +#define HQVDP_RD_PLUG_CONTROL (HQVDP_RD_PLUG + 0x1000) /* 0x000E1000 */ +#define HQVDP_RD_PLUG_PAGE_SIZE (HQVDP_RD_PLUG + 0x1004) /* 0x000E1004 */ +#define HQVDP_RD_PLUG_MIN_OPC (HQVDP_RD_PLUG + 0x1008) /* 0x000E1008 */ +#define HQVDP_RD_PLUG_MAX_OPC (HQVDP_RD_PLUG + 0x100C) /* 0x000E100C */ +#define HQVDP_RD_PLUG_MAX_CHK (HQVDP_RD_PLUG + 0x1010) /* 0x000E1010 */ +#define HQVDP_RD_PLUG_MAX_MSG (HQVDP_RD_PLUG + 0x1014) /* 0x000E1014 */ +#define HQVDP_RD_PLUG_MIN_SPACE (HQVDP_RD_PLUG + 0x1018) /* 0x000E1018 */ +#define HQVDP_WR_PLUG 0x000E2000 /* 0x000E2000 */ +#define HQVDP_WR_PLUG_CONTROL (HQVDP_WR_PLUG + 0x1000) /* 0x000E3000 */ +#define HQVDP_WR_PLUG_PAGE_SIZE (HQVDP_WR_PLUG + 0x1004) /* 0x000E3004 */ +#define HQVDP_WR_PLUG_MIN_OPC (HQVDP_WR_PLUG + 0x1008) /* 0x000E3008 */ +#define HQVDP_WR_PLUG_MAX_OPC (HQVDP_WR_PLUG + 0x100C) /* 0x000E300C */ +#define HQVDP_WR_PLUG_MAX_CHK (HQVDP_WR_PLUG + 0x1010) /* 0x000E3010 */ +#define HQVDP_WR_PLUG_MAX_MSG (HQVDP_WR_PLUG + 0x1014) /* 0x000E3014 */ +#define HQVDP_WR_PLUG_MIN_SPACE (HQVDP_WR_PLUG + 0x1018) /* 0x000E3018 */ +#define HQVDP_MBX 0x000E4000 /* 0x000E4000 */ +#define HQVDP_MBX_IRQ_TO_XP70 (HQVDP_MBX + 0x0000) /* 0x000E4000 */ +#define HQVDP_MBX_INFO_HOST (HQVDP_MBX + 0x0004) /* 0x000E4004 */ +#define HQVDP_MBX_IRQ_TO_HOST (HQVDP_MBX + 0x0008) /* 0x000E4008 */ +#define HQVDP_MBX_INFO_XP70 (HQVDP_MBX + 0x000C) /* 0x000E400C */ +#define HQVDP_MBX_SW_RESET_CTRL (HQVDP_MBX + 0x0010) /* 0x000E4010 */ +#define HQVDP_MBX_STARTUP_CTRL1 (HQVDP_MBX + 0x0014) /* 0x000E4014 */ +#define HQVDP_MBX_STARTUP_CTRL2 (HQVDP_MBX + 0x0018) /* 0x000E4018 */ +#define HQVDP_MBX_GP_STATUS (HQVDP_MBX + 0x001C) /* 0x000E401C */ +#define HQVDP_MBX_NEXT_CMD (HQVDP_MBX + 0x0020) /* 0x000E4020 */ +#define HQVDP_MBX_CURRENT_CMD (HQVDP_MBX + 0x0024) /* 0x000E4024 */ +#define HQVDP_MBX_SOFT_VSYNC (HQVDP_MBX + 0x0028) /* 0x000E4028 */ + +/* Plugs config */ +#define PLUG_CONTROL_ENABLE 0x00000001 +#define PLUG_PAGE_SIZE_256 0x00000002 +#define PLUG_MIN_OPC_8 0x00000003 +#define PLUG_MAX_OPC_64 0x00000006 +#define PLUG_MAX_CHK_2X 0x00000001 +#define PLUG_MAX_MSG_1X 0x00000000 +#define PLUG_MIN_SPACE_1 0x00000000 + +/* SW reset CTRL */ +#define SW_RESET_CTRL_FULL BIT(0) +#define SW_RESET_CTRL_CORE BIT(1) + +/* Startup ctrl 1 */ +#define STARTUP_CTRL1_RST_DONE BIT(0) +#define STARTUP_CTRL1_AUTH_IDLE BIT(2) + +/* Startup ctrl 2 */ +#define STARTUP_CTRL2_FETCH_EN BIT(1) + +/* Info xP70 */ +#define INFO_XP70_FW_READY BIT(15) +#define INFO_XP70_FW_PROCESSING BIT(14) +#define INFO_XP70_FW_INITQUEUES BIT(13) + +/* SOFT_VSYNC */ +#define SOFT_VSYNC_HW 0x00000000 +#define SOFT_VSYNC_SW_CMD 0x00000001 +#define SOFT_VSYNC_SW_CTRL_IRQ 0x00000003 + +/* Reset & boot poll config */ +#define POLL_MAX_ATTEMPT 50 +#define POLL_DELAY_MS 20 + +#define SCALE_FACTOR 8192 +#define SCALE_MAX_FOR_LEG_LUT_F 4096 +#define SCALE_MAX_FOR_LEG_LUT_E 4915 +#define SCALE_MAX_FOR_LEG_LUT_D 6654 +#define SCALE_MAX_FOR_LEG_LUT_C 8192 + +enum sti_hvsrc_orient { + HVSRC_HORI, + HVSRC_VERT +}; + +/* Command structures */ +struct sti_hqvdp_top { + u32 config; + u32 mem_format; + u32 current_luma; + u32 current_enh_luma; + u32 current_right_luma; + u32 current_enh_right_luma; + u32 current_chroma; + u32 current_enh_chroma; + u32 current_right_chroma; + u32 current_enh_right_chroma; + u32 output_luma; + u32 output_chroma; + u32 luma_src_pitch; + u32 luma_enh_src_pitch; + u32 luma_right_src_pitch; + u32 luma_enh_right_src_pitch; + u32 chroma_src_pitch; + u32 chroma_enh_src_pitch; + u32 chroma_right_src_pitch; + u32 chroma_enh_right_src_pitch; + u32 luma_processed_pitch; + u32 chroma_processed_pitch; + u32 input_frame_size; + u32 input_viewport_ori; + u32 input_viewport_ori_right; + u32 input_viewport_size; + u32 left_view_border_width; + u32 right_view_border_width; + u32 left_view_3d_offset_width; + u32 right_view_3d_offset_width; + u32 side_stripe_color; + u32 crc_reset_ctrl; +}; + +/* Configs for interlaced : no IT, no pass thru, 3 fields */ +#define TOP_CONFIG_INTER_BTM 0x00000000 +#define TOP_CONFIG_INTER_TOP 0x00000002 + +/* Config for progressive : no IT, no pass thru, 3 fields */ +#define TOP_CONFIG_PROGRESSIVE 0x00000001 + +/* Default MemFormat: in=420_raster_dual out=444_raster;opaque Mem2Tv mode */ +#define TOP_MEM_FORMAT_DFLT 0x00018060 + +/* Min/Max size */ +#define MAX_WIDTH 0x1FFF +#define MAX_HEIGHT 0x0FFF +#define MIN_WIDTH 0x0030 +#define MIN_HEIGHT 0x0010 + +struct sti_hqvdp_vc1re { + u32 ctrl_prv_csdi; + u32 ctrl_cur_csdi; + u32 ctrl_nxt_csdi; + u32 ctrl_cur_fmd; + u32 ctrl_nxt_fmd; +}; + +struct sti_hqvdp_fmd { + u32 config; + u32 viewport_ori; + u32 viewport_size; + u32 next_next_luma; + u32 next_next_right_luma; + u32 next_next_next_luma; + u32 next_next_next_right_luma; + u32 threshold_scd; + u32 threshold_rfd; + u32 threshold_move; + u32 threshold_cfd; +}; + +struct sti_hqvdp_csdi { + u32 config; + u32 config2; + u32 dcdi_config; + u32 prev_luma; + u32 prev_enh_luma; + u32 prev_right_luma; + u32 prev_enh_right_luma; + u32 next_luma; + u32 next_enh_luma; + u32 next_right_luma; + u32 next_enh_right_luma; + u32 prev_chroma; + u32 prev_enh_chroma; + u32 prev_right_chroma; + u32 prev_enh_right_chroma; + u32 next_chroma; + u32 next_enh_chroma; + u32 next_right_chroma; + u32 next_enh_right_chroma; + u32 prev_motion; + u32 prev_right_motion; + u32 cur_motion; + u32 cur_right_motion; + u32 next_motion; + u32 next_right_motion; +}; + +/* Config for progressive: by pass */ +#define CSDI_CONFIG_PROG 0x00000000 +/* Config for directional deinterlacing without motion */ +#define CSDI_CONFIG_INTER_DIR 0x00000016 +/* Additional configs for fader, blender, motion,... deinterlace algorithms */ +#define CSDI_CONFIG2_DFLT 0x000001B3 +#define CSDI_DCDI_CONFIG_DFLT 0x00203803 + +struct sti_hqvdp_hvsrc { + u32 hor_panoramic_ctrl; + u32 output_picture_size; + u32 init_horizontal; + u32 init_vertical; + u32 param_ctrl; + u32 yh_coef[NB_COEF]; + u32 ch_coef[NB_COEF]; + u32 yv_coef[NB_COEF]; + u32 cv_coef[NB_COEF]; + u32 hori_shift; + u32 vert_shift; +}; + +/* Default ParamCtrl: all controls enabled */ +#define HVSRC_PARAM_CTRL_DFLT 0xFFFFFFFF + +struct sti_hqvdp_iqi { + u32 config; + u32 demo_wind_size; + u32 pk_config; + u32 coeff0_coeff1; + u32 coeff2_coeff3; + u32 coeff4; + u32 pk_lut; + u32 pk_gain; + u32 pk_coring_level; + u32 cti_config; + u32 le_config; + u32 le_lut[64]; + u32 con_bri; + u32 sat_gain; + u32 pxf_conf; + u32 default_color; +}; + +/* Default Config : IQI bypassed */ +#define IQI_CONFIG_DFLT 0x00000001 +/* Default Contrast & Brightness gain = 256 */ +#define IQI_CON_BRI_DFLT 0x00000100 +/* Default Saturation gain = 256 */ +#define IQI_SAT_GAIN_DFLT 0x00000100 +/* Default PxfConf : P2I bypassed */ +#define IQI_PXF_CONF_DFLT 0x00000001 + +struct sti_hqvdp_top_status { + u32 processing_time; + u32 input_y_crc; + u32 input_uv_crc; +}; + +struct sti_hqvdp_fmd_status { + u32 fmd_repeat_move_status; + u32 fmd_scene_count_status; + u32 cfd_sum; + u32 field_sum; + u32 next_y_fmd_crc; + u32 next_next_y_fmd_crc; + u32 next_next_next_y_fmd_crc; +}; + +struct sti_hqvdp_csdi_status { + u32 prev_y_csdi_crc; + u32 cur_y_csdi_crc; + u32 next_y_csdi_crc; + u32 prev_uv_csdi_crc; + u32 cur_uv_csdi_crc; + u32 next_uv_csdi_crc; + u32 y_csdi_crc; + u32 uv_csdi_crc; + u32 uv_cup_crc; + u32 mot_csdi_crc; + u32 mot_cur_csdi_crc; + u32 mot_prev_csdi_crc; +}; + +struct sti_hqvdp_hvsrc_status { + u32 y_hvsrc_crc; + u32 u_hvsrc_crc; + u32 v_hvsrc_crc; +}; + +struct sti_hqvdp_iqi_status { + u32 pxf_it_status; + u32 y_iqi_crc; + u32 u_iqi_crc; + u32 v_iqi_crc; +}; + +/* Main commands. We use 2 commands one being processed by the firmware, one + * ready to be fetched upon next Vsync*/ +#define NB_VDP_CMD 2 + +struct sti_hqvdp_cmd { + struct sti_hqvdp_top top; + struct sti_hqvdp_vc1re vc1re; + struct sti_hqvdp_fmd fmd; + struct sti_hqvdp_csdi csdi; + struct sti_hqvdp_hvsrc hvsrc; + struct sti_hqvdp_iqi iqi; + struct sti_hqvdp_top_status top_status; + struct sti_hqvdp_fmd_status fmd_status; + struct sti_hqvdp_csdi_status csdi_status; + struct sti_hqvdp_hvsrc_status hvsrc_status; + struct sti_hqvdp_iqi_status iqi_status; +}; + +/* + * STI HQVDP structure + * + * @dev: driver device + * @drm_dev: the drm device + * @regs: registers + * @layer: layer structure for hqvdp it self + * @vid_plane: VID plug used as link with compositor IP + * @clk: IP clock + * @clk_pix_main: pix main clock + * @reset: reset control + * @vtg_nb: notifier to handle VTG Vsync + * @btm_field_pending: is there any bottom field (interlaced frame) to display + * @curr_field_count: number of field updates + * @last_field_count: number of field updates since last fps measure + * @hqvdp_cmd: buffer of commands + * @hqvdp_cmd_paddr: physical address of hqvdp_cmd + * @vtg: vtg for main data path + */ +struct sti_hqvdp { + struct device *dev; + struct drm_device *drm_dev; + void __iomem *regs; + struct sti_layer layer; + struct drm_plane *vid_plane; + struct clk *clk; + struct clk *clk_pix_main; + struct reset_control *reset; + struct notifier_block vtg_nb; + bool btm_field_pending; + unsigned int curr_field_count; + unsigned int last_field_count; + void *hqvdp_cmd; + dma_addr_t hqvdp_cmd_paddr; + struct sti_vtg *vtg; +}; + +#define to_sti_hqvdp(x) container_of(x, struct sti_hqvdp, layer) + +static const uint32_t hqvdp_supported_formats[] = { + DRM_FORMAT_NV12, +}; + +static const uint32_t *sti_hqvdp_get_formats(struct sti_layer *layer) +{ + return hqvdp_supported_formats; +} + +static unsigned int sti_hqvdp_get_nb_formats(struct sti_layer *layer) +{ + return ARRAY_SIZE(hqvdp_supported_formats); +} + +/** + * sti_hqvdp_get_free_cmd + * @hqvdp: hqvdp structure + * + * Look for a hqvdp_cmd that is not being used (or about to be used) by the FW. + * + * RETURNS: + * the offset of the command to be used. + * -1 in error cases + */ +static int sti_hqvdp_get_free_cmd(struct sti_hqvdp *hqvdp) +{ + int curr_cmd, next_cmd; + dma_addr_t cmd = hqvdp->hqvdp_cmd_paddr; + int i; + + curr_cmd = readl(hqvdp->regs + HQVDP_MBX_CURRENT_CMD); + next_cmd = readl(hqvdp->regs + HQVDP_MBX_NEXT_CMD); + + for (i = 0; i < NB_VDP_CMD; i++) { + if ((cmd != curr_cmd) && (cmd != next_cmd)) + return i * sizeof(struct sti_hqvdp_cmd); + cmd += sizeof(struct sti_hqvdp_cmd); + } + + return -1; +} + +/** + * sti_hqvdp_get_curr_cmd + * @hqvdp: hqvdp structure + * + * Look for the hqvdp_cmd that is being used by the FW. + * + * RETURNS: + * the offset of the command to be used. + * -1 in error cases + */ +static int sti_hqvdp_get_curr_cmd(struct sti_hqvdp *hqvdp) +{ + int curr_cmd; + dma_addr_t cmd = hqvdp->hqvdp_cmd_paddr; + unsigned int i; + + curr_cmd = readl(hqvdp->regs + HQVDP_MBX_CURRENT_CMD); + + for (i = 0; i < NB_VDP_CMD; i++) { + if (cmd == curr_cmd) + return i * sizeof(struct sti_hqvdp_cmd); + + cmd += sizeof(struct sti_hqvdp_cmd); + } + + return -1; +} + +/** + * sti_hqvdp_update_hvsrc + * @orient: horizontal or vertical + * @scale: scaling/zoom factor + * @hvsrc: the structure containing the LUT coef + * + * Update the Y and C Lut coef, as well as the shift param + * + * RETURNS: + * None. + */ +static void sti_hqvdp_update_hvsrc(enum sti_hvsrc_orient orient, int scale, + struct sti_hqvdp_hvsrc *hvsrc) +{ + const int *coef_c, *coef_y; + int shift_c, shift_y; + + /* Get the appropriate coef tables */ + if (scale < SCALE_MAX_FOR_LEG_LUT_F) { + coef_y = coef_lut_f_y_legacy; + coef_c = coef_lut_f_c_legacy; + shift_y = SHIFT_LUT_F_Y_LEGACY; + shift_c = SHIFT_LUT_F_C_LEGACY; + } else if (scale < SCALE_MAX_FOR_LEG_LUT_E) { + coef_y = coef_lut_e_y_legacy; + coef_c = coef_lut_e_c_legacy; + shift_y = SHIFT_LUT_E_Y_LEGACY; + shift_c = SHIFT_LUT_E_C_LEGACY; + } else if (scale < SCALE_MAX_FOR_LEG_LUT_D) { + coef_y = coef_lut_d_y_legacy; + coef_c = coef_lut_d_c_legacy; + shift_y = SHIFT_LUT_D_Y_LEGACY; + shift_c = SHIFT_LUT_D_C_LEGACY; + } else if (scale < SCALE_MAX_FOR_LEG_LUT_C) { + coef_y = coef_lut_c_y_legacy; + coef_c = coef_lut_c_c_legacy; + shift_y = SHIFT_LUT_C_Y_LEGACY; + shift_c = SHIFT_LUT_C_C_LEGACY; + } else if (scale == SCALE_MAX_FOR_LEG_LUT_C) { + coef_y = coef_c = coef_lut_b; + shift_y = shift_c = SHIFT_LUT_B; + } else { + coef_y = coef_c = coef_lut_a_legacy; + shift_y = shift_c = SHIFT_LUT_A_LEGACY; + } + + if (orient == HVSRC_HORI) { + hvsrc->hori_shift = (shift_c << 16) | shift_y; + memcpy(hvsrc->yh_coef, coef_y, sizeof(hvsrc->yh_coef)); + memcpy(hvsrc->ch_coef, coef_c, sizeof(hvsrc->ch_coef)); + } else { + hvsrc->vert_shift = (shift_c << 16) | shift_y; + memcpy(hvsrc->yv_coef, coef_y, sizeof(hvsrc->yv_coef)); + memcpy(hvsrc->cv_coef, coef_c, sizeof(hvsrc->cv_coef)); + } +} + +/** + * sti_hqvdp_check_hw_scaling + * @layer: hqvdp layer + * + * Check if the HW is able to perform the scaling request + * The firmware scaling limitation is "CEIL(1/Zy) <= FLOOR(LFW)" where: + * Zy = OutputHeight / InputHeight + * LFW = (Tx * IPClock) / (MaxNbCycles * Cp) + * Tx : Total video mode horizontal resolution + * IPClock : HQVDP IP clock (Mhz) + * MaxNbCycles: max(InputWidth, OutputWidth) + * Cp: Video mode pixel clock (Mhz) + * + * RETURNS: + * True if the HW can scale. + */ +static bool sti_hqvdp_check_hw_scaling(struct sti_layer *layer) +{ + struct sti_hqvdp *hqvdp = to_sti_hqvdp(layer); + unsigned long lfw; + unsigned int inv_zy; + + lfw = layer->mode->htotal * (clk_get_rate(hqvdp->clk) / 1000000); + lfw /= max(layer->src_w, layer->dst_w) * layer->mode->clock / 1000; + + inv_zy = DIV_ROUND_UP(layer->src_h, layer->dst_h); + + return (inv_zy <= lfw) ? true : false; +} + +/** + * sti_hqvdp_prepare_layer + * @layer: hqvdp layer + * @first_prepare: true if it is the first time this function is called + * + * Prepares a command for the firmware + * + * RETURNS: + * 0 on success. + */ +static int sti_hqvdp_prepare_layer(struct sti_layer *layer, bool first_prepare) +{ + struct sti_hqvdp *hqvdp = to_sti_hqvdp(layer); + struct sti_hqvdp_cmd *cmd; + int scale_h, scale_v; + int cmd_offset; + + dev_dbg(hqvdp->dev, "%s %s\n", __func__, sti_layer_to_str(layer)); + + /* prepare and commit VID plane */ + hqvdp->vid_plane->funcs->update_plane(hqvdp->vid_plane, + layer->crtc, layer->fb, + layer->dst_x, layer->dst_y, + layer->dst_w, layer->dst_h, + layer->src_x, layer->src_y, + layer->src_w, layer->src_h); + + cmd_offset = sti_hqvdp_get_free_cmd(hqvdp); + if (cmd_offset == -1) { + DRM_ERROR("No available hqvdp_cmd now\n"); + return -EBUSY; + } + cmd = hqvdp->hqvdp_cmd + cmd_offset; + + if (!sti_hqvdp_check_hw_scaling(layer)) { + DRM_ERROR("Scaling beyond HW capabilities\n"); + return -EINVAL; + } + + /* Static parameters, defaulting to progressive mode */ + cmd->top.config = TOP_CONFIG_PROGRESSIVE; + cmd->top.mem_format = TOP_MEM_FORMAT_DFLT; + cmd->hvsrc.param_ctrl = HVSRC_PARAM_CTRL_DFLT; + cmd->csdi.config = CSDI_CONFIG_PROG; + + /* VC1RE, FMD bypassed : keep everything set to 0 + * IQI/P2I bypassed */ + cmd->iqi.config = IQI_CONFIG_DFLT; + cmd->iqi.con_bri = IQI_CON_BRI_DFLT; + cmd->iqi.sat_gain = IQI_SAT_GAIN_DFLT; + cmd->iqi.pxf_conf = IQI_PXF_CONF_DFLT; + + /* Buffer planes address */ + cmd->top.current_luma = (u32) layer->paddr + layer->offsets[0]; + cmd->top.current_chroma = (u32) layer->paddr + layer->offsets[1]; + + /* Pitches */ + cmd->top.luma_processed_pitch = cmd->top.luma_src_pitch = + layer->pitches[0]; + cmd->top.chroma_processed_pitch = cmd->top.chroma_src_pitch = + layer->pitches[1]; + + /* Input / output size + * Align to upper even value */ + layer->dst_w = ALIGN(layer->dst_w, 2); + layer->dst_h = ALIGN(layer->dst_h, 2); + + if ((layer->src_w > MAX_WIDTH) || (layer->src_w < MIN_WIDTH) || + (layer->src_h > MAX_HEIGHT) || (layer->src_h < MIN_HEIGHT) || + (layer->dst_w > MAX_WIDTH) || (layer->dst_w < MIN_WIDTH) || + (layer->dst_h > MAX_HEIGHT) || (layer->dst_h < MIN_HEIGHT)) { + DRM_ERROR("Invalid in/out size %dx%d -> %dx%d\n", + layer->src_w, layer->src_h, + layer->dst_w, layer->dst_h); + return -EINVAL; + } + cmd->top.input_viewport_size = cmd->top.input_frame_size = + layer->src_h << 16 | layer->src_w; + cmd->hvsrc.output_picture_size = layer->dst_h << 16 | layer->dst_w; + cmd->top.input_viewport_ori = layer->src_y << 16 | layer->src_x; + + /* Handle interlaced */ + if (layer->fb->flags & DRM_MODE_FB_INTERLACED) { + /* Top field to display */ + cmd->top.config = TOP_CONFIG_INTER_TOP; + + /* Update pitches and vert size */ + cmd->top.input_frame_size = (layer->src_h / 2) << 16 | + layer->src_w; + cmd->top.luma_processed_pitch *= 2; + cmd->top.luma_src_pitch *= 2; + cmd->top.chroma_processed_pitch *= 2; + cmd->top.chroma_src_pitch *= 2; + + /* Enable directional deinterlacing processing */ + cmd->csdi.config = CSDI_CONFIG_INTER_DIR; + cmd->csdi.config2 = CSDI_CONFIG2_DFLT; + cmd->csdi.dcdi_config = CSDI_DCDI_CONFIG_DFLT; + } + + /* Update hvsrc lut coef */ + scale_h = SCALE_FACTOR * layer->dst_w / layer->src_w; + sti_hqvdp_update_hvsrc(HVSRC_HORI, scale_h, &cmd->hvsrc); + + scale_v = SCALE_FACTOR * layer->dst_h / layer->src_h; + sti_hqvdp_update_hvsrc(HVSRC_VERT, scale_v, &cmd->hvsrc); + + if (first_prepare) { + /* Prevent VTG shutdown */ + if (clk_prepare_enable(hqvdp->clk_pix_main)) { + DRM_ERROR("Failed to prepare/enable pix main clk\n"); + return -ENXIO; + } + + /* Register VTG Vsync callback to handle bottom fields */ + if ((layer->fb->flags & DRM_MODE_FB_INTERLACED) && + sti_vtg_register_client(hqvdp->vtg, + &hqvdp->vtg_nb, layer->mixer_id)) { + DRM_ERROR("Cannot register VTG notifier\n"); + return -ENXIO; + } + } + + return 0; +} + +static int sti_hqvdp_commit_layer(struct sti_layer *layer) +{ + struct sti_hqvdp *hqvdp = to_sti_hqvdp(layer); + int cmd_offset; + + dev_dbg(hqvdp->dev, "%s %s\n", __func__, sti_layer_to_str(layer)); + + cmd_offset = sti_hqvdp_get_free_cmd(hqvdp); + if (cmd_offset == -1) { + DRM_ERROR("No available hqvdp_cmd now\n"); + return -EBUSY; + } + + writel(hqvdp->hqvdp_cmd_paddr + cmd_offset, + hqvdp->regs + HQVDP_MBX_NEXT_CMD); + + hqvdp->curr_field_count++; + + /* Interlaced : get ready to display the bottom field at next Vsync */ + if (layer->fb->flags & DRM_MODE_FB_INTERLACED) + hqvdp->btm_field_pending = true; + + dev_dbg(hqvdp->dev, "%s Posted command:0x%x\n", + __func__, hqvdp->hqvdp_cmd_paddr + cmd_offset); + + return 0; +} + +static int sti_hqvdp_disable_layer(struct sti_layer *layer) +{ + struct sti_hqvdp *hqvdp = to_sti_hqvdp(layer); + int i; + + DRM_DEBUG_DRIVER("%s\n", sti_layer_to_str(layer)); + + /* Unregister VTG Vsync callback */ + if ((layer->fb->flags & DRM_MODE_FB_INTERLACED) && + sti_vtg_unregister_client(hqvdp->vtg, &hqvdp->vtg_nb)) + DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n"); + + /* Set next cmd to NULL */ + writel(0, hqvdp->regs + HQVDP_MBX_NEXT_CMD); + + for (i = 0; i < POLL_MAX_ATTEMPT; i++) { + if (readl(hqvdp->regs + HQVDP_MBX_INFO_XP70) + & INFO_XP70_FW_READY) + break; + msleep(POLL_DELAY_MS); + } + + /* VTG can stop now */ + clk_disable_unprepare(hqvdp->clk_pix_main); + + if (i == POLL_MAX_ATTEMPT) { + DRM_ERROR("XP70 could not revert to idle\n"); + return -ENXIO; + } + + /* disable VID plane */ + hqvdp->vid_plane->funcs->disable_plane(hqvdp->vid_plane); + + return 0; +} + +/** + * sti_vdp_vtg_cb + * @nb: notifier block + * @evt: event message + * @data: private data + * + * Handle VTG Vsync event, display pending bottom field + * + * RETURNS: + * 0 on success. + */ +int sti_hqvdp_vtg_cb(struct notifier_block *nb, unsigned long evt, void *data) +{ + struct sti_hqvdp *hqvdp = container_of(nb, struct sti_hqvdp, vtg_nb); + int btm_cmd_offset, top_cmd_offest; + struct sti_hqvdp_cmd *btm_cmd, *top_cmd; + + if ((evt != VTG_TOP_FIELD_EVENT) && (evt != VTG_BOTTOM_FIELD_EVENT)) { + DRM_DEBUG_DRIVER("Unknown event\n"); + return 0; + } + + if (hqvdp->btm_field_pending) { + /* Create the btm field command from the current one */ + btm_cmd_offset = sti_hqvdp_get_free_cmd(hqvdp); + top_cmd_offest = sti_hqvdp_get_curr_cmd(hqvdp); + if ((btm_cmd_offset == -1) || (top_cmd_offest == -1)) { + DRM_ERROR("Cannot get cmds, skip btm field\n"); + return -EBUSY; + } + + btm_cmd = hqvdp->hqvdp_cmd + btm_cmd_offset; + top_cmd = hqvdp->hqvdp_cmd + top_cmd_offest; + + memcpy(btm_cmd, top_cmd, sizeof(*btm_cmd)); + + btm_cmd->top.config = TOP_CONFIG_INTER_BTM; + btm_cmd->top.current_luma += + btm_cmd->top.luma_src_pitch / 2; + btm_cmd->top.current_chroma += + btm_cmd->top.chroma_src_pitch / 2; + + /* Post the command to mailbox */ + writel(hqvdp->hqvdp_cmd_paddr + btm_cmd_offset, + hqvdp->regs + HQVDP_MBX_NEXT_CMD); + + hqvdp->curr_field_count++; + hqvdp->btm_field_pending = false; + + dev_dbg(hqvdp->dev, "%s Posted command:0x%x\n", + __func__, hqvdp->hqvdp_cmd_paddr); + } + + return 0; +} + +static struct drm_plane *sti_hqvdp_find_vid(struct drm_device *dev, int id) +{ + struct drm_plane *plane; + + list_for_each_entry(plane, &dev->mode_config.plane_list, head) { + struct sti_layer *layer = to_sti_layer(plane); + + if (layer->desc == id) + return plane; + } + + return NULL; +} + +static void sti_hqvd_init(struct sti_layer *layer) +{ + struct sti_hqvdp *hqvdp = to_sti_hqvdp(layer); + int size; + + /* find the plane macthing with vid 0 */ + hqvdp->vid_plane = sti_hqvdp_find_vid(hqvdp->drm_dev, STI_VID_0); + if (!hqvdp->vid_plane) { + DRM_ERROR("Cannot find Main video layer\n"); + return; + } + + hqvdp->vtg_nb.notifier_call = sti_hqvdp_vtg_cb; + + /* Allocate memory for the VDP commands */ + size = NB_VDP_CMD * sizeof(struct sti_hqvdp_cmd); + hqvdp->hqvdp_cmd = dma_alloc_writecombine(hqvdp->dev, size, + &hqvdp->hqvdp_cmd_paddr, + GFP_KERNEL | GFP_DMA); + if (!hqvdp->hqvdp_cmd) { + DRM_ERROR("Failed to allocate memory for VDP cmd\n"); + return; + } + + memset(hqvdp->hqvdp_cmd, 0, size); +} + +static const struct sti_layer_funcs hqvdp_ops = { + .get_formats = sti_hqvdp_get_formats, + .get_nb_formats = sti_hqvdp_get_nb_formats, + .init = sti_hqvd_init, + .prepare = sti_hqvdp_prepare_layer, + .commit = sti_hqvdp_commit_layer, + .disable = sti_hqvdp_disable_layer, +}; + +struct sti_layer *sti_hqvdp_create(struct device *dev) +{ + struct sti_hqvdp *hqvdp = dev_get_drvdata(dev); + + hqvdp->layer.ops = &hqvdp_ops; + + return &hqvdp->layer; +} + +static void sti_hqvdp_init_plugs(struct sti_hqvdp *hqvdp) +{ + /* Configure Plugs (same for RD & WR) */ + writel(PLUG_PAGE_SIZE_256, hqvdp->regs + HQVDP_RD_PLUG_PAGE_SIZE); + writel(PLUG_MIN_OPC_8, hqvdp->regs + HQVDP_RD_PLUG_MIN_OPC); + writel(PLUG_MAX_OPC_64, hqvdp->regs + HQVDP_RD_PLUG_MAX_OPC); + writel(PLUG_MAX_CHK_2X, hqvdp->regs + HQVDP_RD_PLUG_MAX_CHK); + writel(PLUG_MAX_MSG_1X, hqvdp->regs + HQVDP_RD_PLUG_MAX_MSG); + writel(PLUG_MIN_SPACE_1, hqvdp->regs + HQVDP_RD_PLUG_MIN_SPACE); + writel(PLUG_CONTROL_ENABLE, hqvdp->regs + HQVDP_RD_PLUG_CONTROL); + + writel(PLUG_PAGE_SIZE_256, hqvdp->regs + HQVDP_WR_PLUG_PAGE_SIZE); + writel(PLUG_MIN_OPC_8, hqvdp->regs + HQVDP_WR_PLUG_MIN_OPC); + writel(PLUG_MAX_OPC_64, hqvdp->regs + HQVDP_WR_PLUG_MAX_OPC); + writel(PLUG_MAX_CHK_2X, hqvdp->regs + HQVDP_WR_PLUG_MAX_CHK); + writel(PLUG_MAX_MSG_1X, hqvdp->regs + HQVDP_WR_PLUG_MAX_MSG); + writel(PLUG_MIN_SPACE_1, hqvdp->regs + HQVDP_WR_PLUG_MIN_SPACE); + writel(PLUG_CONTROL_ENABLE, hqvdp->regs + HQVDP_WR_PLUG_CONTROL); +} + +/** + * sti_hqvdp_start_xp70 + * @firmware: firmware found + * @ctxt: hqvdp structure + * + * Run the xP70 initialization sequence + */ +static void sti_hqvdp_start_xp70(const struct firmware *firmware, void *ctxt) +{ + struct sti_hqvdp *hqvdp = ctxt; + u32 *fw_rd_plug, *fw_wr_plug, *fw_pmem, *fw_dmem; + u8 *data; + int i; + struct fw_header { + int rd_size; + int wr_size; + int pmem_size; + int dmem_size; + } *header; + + DRM_DEBUG_DRIVER("\n"); + /* Check firmware parts */ + if (!firmware) { + DRM_ERROR("Firmware not available\n"); + return; + } + + header = (struct fw_header *) firmware->data; + if (firmware->size < sizeof(*header)) { + DRM_ERROR("Invalid firmware size (%d)\n", firmware->size); + goto out; + } + if ((sizeof(*header) + header->rd_size + header->wr_size + + header->pmem_size + header->dmem_size) != firmware->size) { + DRM_ERROR("Invalid fmw structure (%d+%d+%d+%d+%d != %d)\n", + sizeof(*header), header->rd_size, header->wr_size, + header->pmem_size, header->dmem_size, + firmware->size); + goto out; + } + + data = (u8 *) firmware->data; + data += sizeof(*header); + fw_rd_plug = (void *) data; + data += header->rd_size; + fw_wr_plug = (void *) data; + data += header->wr_size; + fw_pmem = (void *) data; + data += header->pmem_size; + fw_dmem = (void *) data; + + /* Enable clock */ + if (clk_prepare_enable(hqvdp->clk)) + DRM_ERROR("Failed to prepare/enable HQVDP clk\n"); + + /* Reset */ + writel(SW_RESET_CTRL_FULL, hqvdp->regs + HQVDP_MBX_SW_RESET_CTRL); + + for (i = 0; i < POLL_MAX_ATTEMPT; i++) { + if (readl(hqvdp->regs + HQVDP_MBX_STARTUP_CTRL1) + & STARTUP_CTRL1_RST_DONE) + break; + msleep(POLL_DELAY_MS); + } + if (i == POLL_MAX_ATTEMPT) { + DRM_ERROR("Could not reset\n"); + goto out; + } + + /* Init Read & Write plugs */ + for (i = 0; i < header->rd_size / 4; i++) + writel(fw_rd_plug[i], hqvdp->regs + HQVDP_RD_PLUG + i * 4); + for (i = 0; i < header->wr_size / 4; i++) + writel(fw_wr_plug[i], hqvdp->regs + HQVDP_WR_PLUG + i * 4); + + sti_hqvdp_init_plugs(hqvdp); + + /* Authorize Idle Mode */ + writel(STARTUP_CTRL1_AUTH_IDLE, hqvdp->regs + HQVDP_MBX_STARTUP_CTRL1); + + /* Prevent VTG interruption during the boot */ + writel(SOFT_VSYNC_SW_CTRL_IRQ, hqvdp->regs + HQVDP_MBX_SOFT_VSYNC); + writel(0, hqvdp->regs + HQVDP_MBX_NEXT_CMD); + + /* Download PMEM & DMEM */ + for (i = 0; i < header->pmem_size / 4; i++) + writel(fw_pmem[i], hqvdp->regs + HQVDP_PMEM + i * 4); + for (i = 0; i < header->dmem_size / 4; i++) + writel(fw_dmem[i], hqvdp->regs + HQVDP_DMEM + i * 4); + + /* Enable fetch */ + writel(STARTUP_CTRL2_FETCH_EN, hqvdp->regs + HQVDP_MBX_STARTUP_CTRL2); + + /* Wait end of boot */ + for (i = 0; i < POLL_MAX_ATTEMPT; i++) { + if (readl(hqvdp->regs + HQVDP_MBX_INFO_XP70) + & INFO_XP70_FW_READY) + break; + msleep(POLL_DELAY_MS); + } + if (i == POLL_MAX_ATTEMPT) { + DRM_ERROR("Could not boot\n"); + goto out; + } + + /* Launch Vsync */ + writel(SOFT_VSYNC_HW, hqvdp->regs + HQVDP_MBX_SOFT_VSYNC); + + DRM_INFO("HQVDP XP70 started\n"); +out: + release_firmware(firmware); +} + +int sti_hqvdp_bind(struct device *dev, struct device *master, void *data) +{ + struct sti_hqvdp *hqvdp = dev_get_drvdata(dev); + struct drm_device *drm_dev = data; + struct sti_layer *layer; + int err; + + DRM_DEBUG_DRIVER("\n"); + + hqvdp->drm_dev = drm_dev; + + /* Request for firmware */ + err = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, + HQVDP_FMW_NAME, hqvdp->dev, + GFP_KERNEL, hqvdp, sti_hqvdp_start_xp70); + if (err) { + DRM_ERROR("Can't get HQVDP firmware\n"); + return err; + } + + layer = sti_layer_create(hqvdp->dev, STI_HQVDP_0, hqvdp->regs); + if (!layer) { + DRM_ERROR("Can't create HQVDP plane\n"); + return -ENOMEM; + } + + sti_drm_plane_init(drm_dev, layer, 1, DRM_PLANE_TYPE_OVERLAY); + + return 0; +} + +static void sti_hqvdp_unbind(struct device *dev, + struct device *master, void *data) +{ + /* do nothing */ +} + +static const struct component_ops sti_hqvdp_ops = { + .bind = sti_hqvdp_bind, + .unbind = sti_hqvdp_unbind, +}; + +static int sti_hqvdp_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *vtg_np; + struct sti_hqvdp *hqvdp; + struct resource *res; + + DRM_DEBUG_DRIVER("\n"); + + hqvdp = devm_kzalloc(dev, sizeof(*hqvdp), GFP_KERNEL); + if (!hqvdp) { + DRM_ERROR("Failed to allocate HQVDP context\n"); + return -ENOMEM; + } + + hqvdp->dev = dev; + + /* Get Memory resources */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + DRM_ERROR("Get memory resource failed\n"); + return -ENXIO; + } + hqvdp->regs = devm_ioremap(dev, res->start, resource_size(res)); + if (hqvdp->regs == NULL) { + DRM_ERROR("Register mapping failed\n"); + return -ENXIO; + } + + /* Get clock resources */ + hqvdp->clk = devm_clk_get(dev, "hqvdp"); + hqvdp->clk_pix_main = devm_clk_get(dev, "pix_main"); + if (IS_ERR(hqvdp->clk) || IS_ERR(hqvdp->clk)) { + DRM_ERROR("Cannot get clocks\n"); + return -ENXIO; + } + + /* Get reset resources */ + hqvdp->reset = devm_reset_control_get(dev, "hqvdp"); + if (!IS_ERR(hqvdp->reset)) + reset_control_deassert(hqvdp->reset); + + vtg_np = of_parse_phandle(pdev->dev.of_node, "st,vtg", 0); + if (vtg_np) + hqvdp->vtg = of_vtg_find(vtg_np); + + platform_set_drvdata(pdev, hqvdp); + + return component_add(&pdev->dev, &sti_hqvdp_ops); +} + +static int sti_hqvdp_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &sti_hqvdp_ops); + return 0; +} + +static struct of_device_id hqvdp_of_match[] = { + { .compatible = "st,stih407-hqvdp", }, + { /* end node */ } +}; +MODULE_DEVICE_TABLE(of, hqvdp_of_match); + +struct platform_driver sti_hqvdp_driver = { + .driver = { + .name = "sti-hqvdp", + .owner = THIS_MODULE, + .of_match_table = hqvdp_of_match, + }, + .probe = sti_hqvdp_probe, + .remove = sti_hqvdp_remove, +}; + +module_platform_driver(sti_hqvdp_driver); + +MODULE_AUTHOR("Benjamin Gaignard "); +MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/sti/sti_hqvdp.h b/drivers/gpu/drm/sti/sti_hqvdp.h new file mode 100644 index 000000000000..cd5ecd0a6dea --- /dev/null +++ b/drivers/gpu/drm/sti/sti_hqvdp.h @@ -0,0 +1,12 @@ +/* + * Copyright (C) STMicroelectronics SA 2014 + * Authors: Fabien Dessenne for STMicroelectronics. + * License terms: GNU General Public License (GPL), version 2 + */ + +#ifndef _STI_HQVDP_H_ +#define _STI_HQVDP_H_ + +struct sti_layer *sti_hqvdp_create(struct device *dev); + +#endif diff --git a/drivers/gpu/drm/sti/sti_hqvdp_lut.h b/drivers/gpu/drm/sti/sti_hqvdp_lut.h new file mode 100644 index 000000000000..619af7f4384e --- /dev/null +++ b/drivers/gpu/drm/sti/sti_hqvdp_lut.h @@ -0,0 +1,373 @@ +/* + * Copyright (C) STMicroelectronics SA 2014 + * Authors: Fabien Dessenne for STMicroelectronics. + * License terms: GNU General Public License (GPL), version 2 + */ + +#ifndef _STI_HQVDP_LUT_H_ +#define _STI_HQVDP_LUT_H_ + +#define NB_COEF 128 + +#define SHIFT_LUT_A_LEGACY 8 +#define SHIFT_LUT_B 8 +#define SHIFT_LUT_C_Y_LEGACY 8 +#define SHIFT_LUT_C_C_LEGACY 8 +#define SHIFT_LUT_D_Y_LEGACY 8 +#define SHIFT_LUT_D_C_LEGACY 8 +#define SHIFT_LUT_E_Y_LEGACY 8 +#define SHIFT_LUT_E_C_LEGACY 8 +#define SHIFT_LUT_F_Y_LEGACY 8 +#define SHIFT_LUT_F_C_LEGACY 8 + +static const u32 coef_lut_a_legacy[NB_COEF] = { + 0x0000ffff, 0x00010000, 0x000100ff, 0x00000000, + 0x00000000, 0x00050000, 0xfffc00ff, 0x00000000, + 0x00000000, 0x00090000, 0xfff900fe, 0x00000000, + 0x00000000, 0x0010ffff, 0xfff600fb, 0x00000000, + 0x00000000, 0x0017fffe, 0xfff400f7, 0x00000000, + 0x00000000, 0x001ffffd, 0xfff200f2, 0x00000000, + 0x00000000, 0x0027fffc, 0xfff100ec, 0x00000000, + 0x00000000, 0x0030fffb, 0xfff000e5, 0x00000000, + 0x00000000, 0x003afffa, 0xffee00de, 0x00000000, + 0x00000000, 0x0044fff9, 0xffed00d6, 0x00000000, + 0x00000000, 0x004efff8, 0xffed00cd, 0x00000000, + 0x00000000, 0x0059fff6, 0xffed00c4, 0x00000000, + 0x00000000, 0x0064fff5, 0xffed00ba, 0x00000000, + 0x00000000, 0x006ffff3, 0xffee00b0, 0x00000000, + 0x00000000, 0x007afff2, 0xffee00a6, 0x00000000, + 0x00000000, 0x0085fff1, 0xffef009b, 0x00000000, + 0x00000000, 0x0090fff0, 0xfff00090, 0x00000000, + 0x00000000, 0x009bffef, 0xfff10085, 0x00000000, + 0x00000000, 0x00a6ffee, 0xfff2007a, 0x00000000, + 0x00000000, 0x00b0ffee, 0xfff3006f, 0x00000000, + 0x00000000, 0x00baffed, 0xfff50064, 0x00000000, + 0x00000000, 0x00c4ffed, 0xfff60059, 0x00000000, + 0x00000000, 0x00cdffed, 0xfff8004e, 0x00000000, + 0x00000000, 0x00d6ffed, 0xfff90044, 0x00000000, + 0x00000000, 0x00deffee, 0xfffa003a, 0x00000000, + 0x00000000, 0x00e5fff0, 0xfffb0030, 0x00000000, + 0x00000000, 0x00ecfff1, 0xfffc0027, 0x00000000, + 0x00000000, 0x00f2fff2, 0xfffd001f, 0x00000000, + 0x00000000, 0x00f7fff4, 0xfffe0017, 0x00000000, + 0x00000000, 0x00fbfff6, 0xffff0010, 0x00000000, + 0x00000000, 0x00fefff9, 0x00000009, 0x00000000, + 0x00000000, 0x00fffffc, 0x00000005, 0x00000000 +}; + +static const u32 coef_lut_b[NB_COEF] = { + 0x00000000, 0x00000000, 0x00000100, 0x00000000, + 0x00000000, 0x00000000, 0x00000100, 0x00000000, + 0x00000000, 0x00000000, 0x00000100, 0x00000000, + 0x00000000, 0x00000000, 0x00000100, 0x00000000, + 0x00000000, 0x00000000, 0x00000100, 0x00000000, + 0x00000000, 0x00000000, 0x00000100, 0x00000000, + 0x00000000, 0x00000000, 0x00000100, 0x00000000, + 0x00000000, 0x00000000, 0x00000100, 0x00000000, + 0x00000000, 0x00000000, 0x00000100, 0x00000000, + 0x00000000, 0x00000000, 0x00000100, 0x00000000, + 0x00000000, 0x00000000, 0x00000100, 0x00000000, + 0x00000000, 0x00000000, 0x00000100, 0x00000000, + 0x00000000, 0x00000000, 0x00000100, 0x00000000, + 0x00000000, 0x00000000, 0x00000100, 0x00000000, + 0x00000000, 0x00000000, 0x00000100, 0x00000000, + 0x00000000, 0x00000000, 0x00000100, 0x00000000, + 0x00000000, 0x00000000, 0x00000100, 0x00000000, + 0x00000000, 0x00000000, 0x00000100, 0x00000000, + 0x00000000, 0x00000000, 0x00000100, 0x00000000, + 0x00000000, 0x00000000, 0x00000100, 0x00000000, + 0x00000000, 0x00000000, 0x00000100, 0x00000000, + 0x00000000, 0x00000000, 0x00000100, 0x00000000, + 0x00000000, 0x00000000, 0x00000100, 0x00000000, + 0x00000000, 0x00000000, 0x00000100, 0x00000000, + 0x00000000, 0x00000000, 0x00000100, 0x00000000, + 0x00000000, 0x00000000, 0x00000100, 0x00000000, + 0x00000000, 0x00000000, 0x00000100, 0x00000000, + 0x00000000, 0x00000000, 0x00000100, 0x00000000, + 0x00000000, 0x00000000, 0x00000100, 0x00000000, + 0x00000000, 0x00000000, 0x00000100, 0x00000000, + 0x00000000, 0x00000000, 0x00000100, 0x00000000, + 0x00000000, 0x00000000, 0x00000100, 0x00000000 +}; + +static const u32 coef_lut_c_y_legacy[NB_COEF] = { + 0x00060004, 0x0038ffe1, 0x003800be, 0x0006ffe1, + 0x00050005, 0x0042ffe1, 0x003800b3, 0x0007ffe1, + 0x00040006, 0x0046ffe1, 0x003300b2, 0x0008ffe2, + 0x00030007, 0x004cffe1, 0x002e00b1, 0x0008ffe2, + 0x00020006, 0x0051ffe2, 0x002900b0, 0x0009ffe3, + 0x00010008, 0x0056ffe2, 0x002400ae, 0x0009ffe4, + 0xffff0008, 0x005cffe3, 0x001f00ad, 0x000affe4, + 0xfffe0008, 0x0062ffe4, 0x001a00ab, 0x000affe5, + 0xfffd000a, 0x0066ffe5, 0x001500a8, 0x000bffe6, + 0xfffc0009, 0x006bffe7, 0x001100a5, 0x000bffe8, + 0xfffa000a, 0x0070ffe8, 0x000d00a3, 0x000bffe9, + 0xfff9000b, 0x0076ffea, 0x0008009f, 0x000bffea, + 0xfff7000b, 0x007affec, 0x0005009b, 0x000cffec, + 0xfff6000b, 0x007effef, 0x00010098, 0x000cffed, + 0xfff4000b, 0x0084fff1, 0xfffd0095, 0x000cffee, + 0xfff3000b, 0x0088fff4, 0xfffa0090, 0x000cfff0, + 0xfff1000b, 0x008dfff7, 0xfff7008d, 0x000bfff1, + 0xfff0000c, 0x0090fffa, 0xfff40088, 0x000bfff3, + 0xffee000c, 0x0095fffd, 0xfff10084, 0x000bfff4, + 0xffed000c, 0x00980001, 0xffef007e, 0x000bfff6, + 0xffec000c, 0x009b0005, 0xffec007a, 0x000bfff7, + 0xffea000b, 0x009f0008, 0xffea0076, 0x000bfff9, + 0xffe9000b, 0x00a3000d, 0xffe80070, 0x000afffa, + 0xffe8000b, 0x00a50011, 0xffe7006b, 0x0009fffc, + 0xffe6000b, 0x00a80015, 0xffe50066, 0x000afffd, + 0xffe5000a, 0x00ab001a, 0xffe40062, 0x0008fffe, + 0xffe4000a, 0x00ad001f, 0xffe3005c, 0x0008ffff, + 0xffe40009, 0x00ae0024, 0xffe20056, 0x00080001, + 0xffe30009, 0x00b00029, 0xffe20051, 0x00060002, + 0xffe20008, 0x00b1002e, 0xffe1004c, 0x00070003, + 0xffe20008, 0x00b20033, 0xffe10046, 0x00060004, + 0xffe10007, 0x00b30038, 0xffe10042, 0x00050005 +}; + +static const u32 coef_lut_c_c_legacy[NB_COEF] = { + 0x0001fff3, 0x003afffb, 0x003a00a1, 0x0001fffb, + 0x0001fff5, 0x0041fffb, 0x0038009a, 0x0001fffb, + 0x0001fff5, 0x0046fffb, 0x00340099, 0x0001fffb, + 0x0001fff7, 0x0049fffb, 0x00300098, 0x0001fffb, + 0x0001fff9, 0x004cfffb, 0x002d0096, 0x0001fffb, + 0x0001fffa, 0x004ffffc, 0x00290095, 0x0001fffb, + 0x0001fff9, 0x0054fffd, 0x00250093, 0x0001fffc, + 0x0001fffa, 0x0058fffd, 0x00220092, 0x0000fffc, + 0x0001fffb, 0x005bfffe, 0x001f0090, 0x0000fffc, + 0x0001fffd, 0x005effff, 0x001c008c, 0x0000fffd, + 0x0001fffd, 0x00620000, 0x0019008a, 0x0000fffd, + 0x0001fffe, 0x00660001, 0x00160088, 0xfffffffd, + 0x0000fffe, 0x006a0003, 0x00130085, 0xfffffffe, + 0x0000fffe, 0x006e0004, 0x00100083, 0xfffffffe, + 0x0000fffe, 0x00710006, 0x000e007f, 0xffffffff, + 0x0000fffe, 0x00750008, 0x000c007c, 0xfffeffff, + 0xfffffffe, 0x0079000a, 0x000a0079, 0xfffeffff, + 0xfffffffe, 0x007c000c, 0x00080075, 0xfffe0000, + 0xffffffff, 0x007f000e, 0x00060071, 0xfffe0000, + 0xfffeffff, 0x00830010, 0x0004006e, 0xfffe0000, + 0xfffeffff, 0x00850013, 0x0003006a, 0xfffe0000, + 0xfffdffff, 0x00880016, 0x00010066, 0xfffe0001, + 0xfffd0000, 0x008a0019, 0x00000062, 0xfffd0001, + 0xfffd0000, 0x008c001c, 0xffff005e, 0xfffd0001, + 0xfffc0000, 0x0090001f, 0xfffe005b, 0xfffb0001, + 0xfffc0000, 0x00920022, 0xfffd0058, 0xfffa0001, + 0xfffc0001, 0x00930025, 0xfffd0054, 0xfff90001, + 0xfffb0001, 0x00950029, 0xfffc004f, 0xfffa0001, + 0xfffb0001, 0x0096002d, 0xfffb004c, 0xfff90001, + 0xfffb0001, 0x00980030, 0xfffb0049, 0xfff70001, + 0xfffb0001, 0x00990034, 0xfffb0046, 0xfff50001, + 0xfffb0001, 0x009a0038, 0xfffb0041, 0xfff50001 +}; + +static const u32 coef_lut_d_y_legacy[NB_COEF] = { + 0xfff80009, 0x0046ffec, 0x004600a3, 0xfff8ffec, + 0xfff70009, 0x004effed, 0x0044009d, 0xfff9ffeb, + 0xfff6000a, 0x0052ffee, 0x003f009d, 0xfffaffea, + 0xfff50009, 0x0057ffef, 0x003b009d, 0xfffbffe9, + 0xfff50008, 0x005bfff0, 0x0037009c, 0xfffcffe9, + 0xfff40008, 0x005ffff2, 0x0033009b, 0xfffcffe9, + 0xfff30007, 0x0064fff3, 0x002f009b, 0xfffdffe8, + 0xfff20007, 0x0068fff5, 0x002b0099, 0xfffeffe8, + 0xfff10008, 0x006bfff7, 0x00270097, 0xffffffe8, + 0xfff00007, 0x006ffff9, 0x00230097, 0xffffffe8, + 0xffef0006, 0x0073fffb, 0x00200095, 0x0000ffe8, + 0xffee0005, 0x0077fffe, 0x001c0093, 0x0000ffe9, + 0xffee0005, 0x007a0000, 0x00180091, 0x0001ffe9, + 0xffed0005, 0x007d0003, 0x0015008e, 0x0002ffe9, + 0xffec0005, 0x00800006, 0x0012008b, 0x0002ffea, + 0xffeb0004, 0x00840008, 0x000e008a, 0x0003ffea, + 0xffeb0003, 0x0087000b, 0x000b0087, 0x0003ffeb, + 0xffea0003, 0x008a000e, 0x00080084, 0x0004ffeb, + 0xffea0002, 0x008b0012, 0x00060080, 0x0005ffec, + 0xffe90002, 0x008e0015, 0x0003007d, 0x0005ffed, + 0xffe90001, 0x00910018, 0x0000007a, 0x0005ffee, + 0xffe90000, 0x0093001c, 0xfffe0077, 0x0005ffee, + 0xffe80000, 0x00950020, 0xfffb0073, 0x0006ffef, + 0xffe8ffff, 0x00970023, 0xfff9006f, 0x0007fff0, + 0xffe8ffff, 0x00970027, 0xfff7006b, 0x0008fff1, + 0xffe8fffe, 0x0099002b, 0xfff50068, 0x0007fff2, + 0xffe8fffd, 0x009b002f, 0xfff30064, 0x0007fff3, + 0xffe9fffc, 0x009b0033, 0xfff2005f, 0x0008fff4, + 0xffe9fffc, 0x009c0037, 0xfff0005b, 0x0008fff5, + 0xffe9fffb, 0x009d003b, 0xffef0057, 0x0009fff5, + 0xffeafffa, 0x009d003f, 0xffee0052, 0x000afff6, + 0xffebfff9, 0x009d0044, 0xffed004e, 0x0009fff7 +}; + +static const u32 coef_lut_d_c_legacy[NB_COEF] = { + 0xfffeffff, 0x003fffff, 0x003f0089, 0xfffeffff, + 0xfffe0000, 0x00460000, 0x0042007d, 0xfffffffe, + 0xfffe0000, 0x00490001, 0x003f007d, 0xfffffffd, + 0xfffd0001, 0x004b0002, 0x003c007d, 0x0000fffc, + 0xfffd0001, 0x004e0003, 0x0039007c, 0x0000fffc, + 0xfffc0001, 0x00510005, 0x0036007c, 0x0000fffb, + 0xfffc0001, 0x00540006, 0x0033007b, 0x0001fffa, + 0xfffc0003, 0x00550008, 0x00310078, 0x0001fffa, + 0xfffb0003, 0x00580009, 0x002e0078, 0x0001fffa, + 0xfffb0002, 0x005b000b, 0x002b0077, 0x0002fff9, + 0xfffa0003, 0x005e000d, 0x00280075, 0x0002fff9, + 0xfffa0002, 0x0060000f, 0x00260074, 0x0002fff9, + 0xfffa0004, 0x00610011, 0x00230072, 0x0002fff9, + 0xfffa0004, 0x00640013, 0x00200070, 0x0002fff9, + 0xfff90004, 0x00660015, 0x001e006e, 0x0003fff9, + 0xfff90004, 0x00680017, 0x001c006c, 0x0003fff9, + 0xfff90003, 0x006b0019, 0x0019006b, 0x0003fff9, + 0xfff90003, 0x006c001c, 0x00170068, 0x0004fff9, + 0xfff90003, 0x006e001e, 0x00150066, 0x0004fff9, + 0xfff90002, 0x00700020, 0x00130064, 0x0004fffa, + 0xfff90002, 0x00720023, 0x00110061, 0x0004fffa, + 0xfff90002, 0x00740026, 0x000f0060, 0x0002fffa, + 0xfff90002, 0x00750028, 0x000d005e, 0x0003fffa, + 0xfff90002, 0x0077002b, 0x000b005b, 0x0002fffb, + 0xfffa0001, 0x0078002e, 0x00090058, 0x0003fffb, + 0xfffa0001, 0x00780031, 0x00080055, 0x0003fffc, + 0xfffa0001, 0x007b0033, 0x00060054, 0x0001fffc, + 0xfffb0000, 0x007c0036, 0x00050051, 0x0001fffc, + 0xfffc0000, 0x007c0039, 0x0003004e, 0x0001fffd, + 0xfffc0000, 0x007d003c, 0x0002004b, 0x0001fffd, + 0xfffdffff, 0x007d003f, 0x00010049, 0x0000fffe, + 0xfffeffff, 0x007d0042, 0x00000046, 0x0000fffe +}; + +static const u32 coef_lut_e_y_legacy[NB_COEF] = { + 0xfff10001, 0x00490004, 0x00490083, 0xfff10004, + 0xfff10000, 0x00500006, 0x004b007b, 0xfff10002, + 0xfff10000, 0x00530007, 0x0048007b, 0xfff10001, + 0xfff10000, 0x00550009, 0x0046007a, 0xfff10000, + 0xfff1fffe, 0x0058000b, 0x0043007b, 0xfff2fffe, + 0xfff1ffff, 0x005a000d, 0x0040007a, 0xfff2fffd, + 0xfff1fffd, 0x005d000f, 0x003e007a, 0xfff2fffc, + 0xfff1fffd, 0x005f0011, 0x003b0079, 0xfff3fffb, + 0xfff1fffc, 0x00610013, 0x00390079, 0xfff3fffa, + 0xfff1fffb, 0x00640015, 0x00360079, 0xfff3fff9, + 0xfff1fffa, 0x00660017, 0x00340078, 0xfff4fff8, + 0xfff1fffb, 0x00680019, 0x00310077, 0xfff4fff7, + 0xfff2fff9, 0x006a001b, 0x002f0076, 0xfff5fff6, + 0xfff2fff9, 0x006c001e, 0x002c0075, 0xfff5fff5, + 0xfff2fff9, 0x006d0020, 0x002a0073, 0xfff6fff5, + 0xfff3fff7, 0x00700022, 0x00270073, 0xfff6fff4, + 0xfff3fff7, 0x00710025, 0x00250071, 0xfff7fff3, + 0xfff4fff6, 0x00730027, 0x00220070, 0xfff7fff3, + 0xfff5fff6, 0x0073002a, 0x0020006d, 0xfff9fff2, + 0xfff5fff5, 0x0075002c, 0x001e006c, 0xfff9fff2, + 0xfff6fff5, 0x0076002f, 0x001b006a, 0xfff9fff2, + 0xfff7fff4, 0x00770031, 0x00190068, 0xfffbfff1, + 0xfff8fff4, 0x00780034, 0x00170066, 0xfffafff1, + 0xfff9fff3, 0x00790036, 0x00150064, 0xfffbfff1, + 0xfffafff3, 0x00790039, 0x00130061, 0xfffcfff1, + 0xfffbfff3, 0x0079003b, 0x0011005f, 0xfffdfff1, + 0xfffcfff2, 0x007a003e, 0x000f005d, 0xfffdfff1, + 0xfffdfff2, 0x007a0040, 0x000d005a, 0xfffffff1, + 0xfffefff2, 0x007b0043, 0x000b0058, 0xfffefff1, + 0x0000fff1, 0x007a0046, 0x00090055, 0x0000fff1, + 0x0001fff1, 0x007b0048, 0x00070053, 0x0000fff1, + 0x0002fff1, 0x007b004b, 0x00060050, 0x0000fff1 +}; + +static const u32 coef_lut_e_c_legacy[NB_COEF] = { + 0xfffa0001, 0x003f0010, 0x003f006d, 0xfffa0010, + 0xfffb0002, 0x00440011, 0x00440062, 0xfffa000e, + 0xfffb0001, 0x00460013, 0x00420062, 0xfffa000d, + 0xfffb0000, 0x00480014, 0x00410062, 0xfffa000c, + 0xfffb0001, 0x00490015, 0x003f0061, 0xfffb000b, + 0xfffb0000, 0x004b0017, 0x003d0061, 0xfffb000a, + 0xfffb0000, 0x004d0018, 0x003b0062, 0xfffb0008, + 0xfffcffff, 0x004f001a, 0x00390061, 0xfffb0007, + 0xfffc0000, 0x004f001c, 0x00380060, 0xfffb0006, + 0xfffcffff, 0x0052001d, 0x00360060, 0xfffb0005, + 0xfffdfffe, 0x0053001f, 0x00340060, 0xfffb0004, + 0xfffdfffe, 0x00540021, 0x0032005e, 0xfffc0004, + 0xfffeffff, 0x00550022, 0x0030005d, 0xfffc0003, + 0xfffeffff, 0x00560024, 0x002f005c, 0xfffc0002, + 0xfffffffd, 0x00580026, 0x002d005c, 0xfffc0001, + 0xfffffffd, 0x005a0027, 0x002b005c, 0xfffc0000, + 0x0000fffd, 0x005a0029, 0x0029005a, 0xfffd0000, + 0x0000fffc, 0x005c002b, 0x0027005a, 0xfffdffff, + 0x0001fffc, 0x005c002d, 0x00260058, 0xfffdffff, + 0x0002fffc, 0x005c002f, 0x00240056, 0xfffffffe, + 0x0003fffc, 0x005d0030, 0x00220055, 0xfffffffe, + 0x0004fffc, 0x005e0032, 0x00210054, 0xfffefffd, + 0x0004fffb, 0x00600034, 0x001f0053, 0xfffefffd, + 0x0005fffb, 0x00600036, 0x001d0052, 0xfffffffc, + 0x0006fffb, 0x00600038, 0x001c004f, 0x0000fffc, + 0x0007fffb, 0x00610039, 0x001a004f, 0xfffffffc, + 0x0008fffb, 0x0062003b, 0x0018004d, 0x0000fffb, + 0x000afffb, 0x0061003d, 0x0017004b, 0x0000fffb, + 0x000bfffb, 0x0061003f, 0x00150049, 0x0001fffb, + 0x000cfffa, 0x00620041, 0x00140048, 0x0000fffb, + 0x000dfffa, 0x00620042, 0x00130046, 0x0001fffb, + 0x000efffa, 0x00620044, 0x00110044, 0x0002fffb +}; + +static const u32 coef_lut_f_y_legacy[NB_COEF] = { + 0xfff6fff0, 0x00490012, 0x0049006e, 0xfff60012, + 0xfff7fff1, 0x004e0013, 0x00490068, 0xfff60010, + 0xfff7fff2, 0x004f0015, 0x00470067, 0xfff6000f, + 0xfff7fff5, 0x004f0017, 0x00450065, 0xfff6000e, + 0xfff8fff5, 0x00500018, 0x00440065, 0xfff6000c, + 0xfff8fff6, 0x0051001a, 0x00420064, 0xfff6000b, + 0xfff8fff6, 0x0052001c, 0x00400064, 0xfff6000a, + 0xfff9fff6, 0x0054001d, 0x003e0064, 0xfff60008, + 0xfff9fff8, 0x0054001f, 0x003c0063, 0xfff60007, + 0xfffafff8, 0x00550021, 0x003a0062, 0xfff60006, + 0xfffbfff7, 0x00560022, 0x00390062, 0xfff60005, + 0xfffbfff8, 0x00570024, 0x00370061, 0xfff60004, + 0xfffcfff8, 0x00580026, 0x00350060, 0xfff60003, + 0xfffdfff8, 0x00590028, 0x0033005f, 0xfff60002, + 0xfffdfff7, 0x005b002a, 0x0031005f, 0xfff60001, + 0xfffefff7, 0x005c002c, 0x002f005e, 0xfff60000, + 0xfffffff6, 0x005e002d, 0x002d005e, 0xfff6ffff, + 0x0000fff6, 0x005e002f, 0x002c005c, 0xfff7fffe, + 0x0001fff6, 0x005f0031, 0x002a005b, 0xfff7fffd, + 0x0002fff6, 0x005f0033, 0x00280059, 0xfff8fffd, + 0x0003fff6, 0x00600035, 0x00260058, 0xfff8fffc, + 0x0004fff6, 0x00610037, 0x00240057, 0xfff8fffb, + 0x0005fff6, 0x00620039, 0x00220056, 0xfff7fffb, + 0x0006fff6, 0x0062003a, 0x00210055, 0xfff8fffa, + 0x0007fff6, 0x0063003c, 0x001f0054, 0xfff8fff9, + 0x0008fff6, 0x0064003e, 0x001d0054, 0xfff6fff9, + 0x000afff6, 0x00640040, 0x001c0052, 0xfff6fff8, + 0x000bfff6, 0x00640042, 0x001a0051, 0xfff6fff8, + 0x000cfff6, 0x00650044, 0x00180050, 0xfff5fff8, + 0x000efff6, 0x00650045, 0x0017004f, 0xfff5fff7, + 0x000ffff6, 0x00670047, 0x0015004f, 0xfff2fff7, + 0x0010fff6, 0x00680049, 0x0013004e, 0xfff1fff7 +}; + +static const u32 coef_lut_f_c_legacy[NB_COEF] = { + 0x0000fffb, 0x003a001a, 0x003a005d, 0x0000001a, + 0x0001fffb, 0x003f001b, 0x00400051, 0x00000019, + 0x0001fffc, 0x0040001c, 0x003f0051, 0x00000017, + 0x0002fffb, 0x0042001d, 0x003e0051, 0xffff0016, + 0x0002fffb, 0x0043001e, 0x003d0051, 0xffff0015, + 0x0003fffc, 0x00430020, 0x003b0050, 0xffff0014, + 0x0003fffb, 0x00450021, 0x003a0051, 0xfffe0013, + 0x0004fffc, 0x00450022, 0x00390050, 0xfffe0012, + 0x0005fffc, 0x00460023, 0x0038004f, 0xfffe0011, + 0x0005fffb, 0x00480025, 0x00360050, 0xfffd0010, + 0x0006fffc, 0x00480026, 0x0035004f, 0xfffd000f, + 0x0006fffc, 0x00490027, 0x0034004f, 0xfffd000e, + 0x0007fffd, 0x00490028, 0x0033004e, 0xfffd000d, + 0x0008fffc, 0x004a002a, 0x0031004d, 0xfffd000d, + 0x0009fffd, 0x004a002b, 0x0030004d, 0xfffc000c, + 0x0009fffc, 0x004c002c, 0x002f004d, 0xfffc000b, + 0x000afffc, 0x004c002e, 0x002e004c, 0xfffc000a, + 0x000bfffc, 0x004d002f, 0x002c004c, 0xfffc0009, + 0x000cfffc, 0x004d0030, 0x002b004a, 0xfffd0009, + 0x000dfffd, 0x004d0031, 0x002a004a, 0xfffc0008, + 0x000dfffd, 0x004e0033, 0x00280049, 0xfffd0007, + 0x000efffd, 0x004f0034, 0x00270049, 0xfffc0006, + 0x000ffffd, 0x004f0035, 0x00260048, 0xfffc0006, + 0x0010fffd, 0x00500036, 0x00250048, 0xfffb0005, + 0x0011fffe, 0x004f0038, 0x00230046, 0xfffc0005, + 0x0012fffe, 0x00500039, 0x00220045, 0xfffc0004, + 0x0013fffe, 0x0051003a, 0x00210045, 0xfffb0003, + 0x0014ffff, 0x0050003b, 0x00200043, 0xfffc0003, + 0x0015ffff, 0x0051003d, 0x001e0043, 0xfffb0002, + 0x0016ffff, 0x0051003e, 0x001d0042, 0xfffb0002, + 0x00170000, 0x0051003f, 0x001c0040, 0xfffc0001, + 0x00190000, 0x00510040, 0x001b003f, 0xfffb0001 +}; + +#endif diff --git a/drivers/gpu/drm/sti/sti_layer.c b/drivers/gpu/drm/sti/sti_layer.c index 5051b4cfc46b..480ec1c974e2 100644 --- a/drivers/gpu/drm/sti/sti_layer.c +++ b/drivers/gpu/drm/sti/sti_layer.c @@ -13,6 +13,7 @@ #include "sti_compositor.h" #include "sti_cursor.h" #include "sti_gdp.h" +#include "sti_hqvdp.h" #include "sti_layer.h" #include "sti_vid.h" @@ -33,6 +34,8 @@ const char *sti_layer_to_str(struct sti_layer *layer) return "VID1"; case STI_CURSOR: return "CURSOR"; + case STI_HQVDP_0: + return "HQVDP0"; default: return ""; } @@ -54,6 +57,9 @@ struct sti_layer *sti_layer_create(struct device *dev, int desc, case STI_CUR: layer = sti_cursor_create(dev); break; + case STI_VDP: + layer = sti_hqvdp_create(dev); + break; } if (!layer) { @@ -72,7 +78,9 @@ struct sti_layer *sti_layer_create(struct device *dev, int desc, return layer; } -int sti_layer_prepare(struct sti_layer *layer, struct drm_framebuffer *fb, +int sti_layer_prepare(struct sti_layer *layer, + struct drm_crtc *crtc, + struct drm_framebuffer *fb, struct drm_display_mode *mode, int mixer_id, int dest_x, int dest_y, int dest_w, int dest_h, int src_x, int src_y, int src_w, int src_h) @@ -92,6 +100,7 @@ int sti_layer_prepare(struct sti_layer *layer, struct drm_framebuffer *fb, return 1; } + layer->crtc = crtc; layer->fb = fb; layer->mode = mode; layer->mixer_id = mixer_id; diff --git a/drivers/gpu/drm/sti/sti_layer.h b/drivers/gpu/drm/sti/sti_layer.h index 68bfdca4d738..ceff497f557e 100644 --- a/drivers/gpu/drm/sti/sti_layer.h +++ b/drivers/gpu/drm/sti/sti_layer.h @@ -22,7 +22,8 @@ enum sti_layer_type { STI_GDP = 1 << STI_LAYER_TYPE_SHIFT, STI_VID = 2 << STI_LAYER_TYPE_SHIFT, STI_CUR = 3 << STI_LAYER_TYPE_SHIFT, - STI_BCK = 4 << STI_LAYER_TYPE_SHIFT + STI_BCK = 4 << STI_LAYER_TYPE_SHIFT, + STI_VDP = 5 << STI_LAYER_TYPE_SHIFT }; enum sti_layer_id_of_type { @@ -39,6 +40,7 @@ enum sti_layer_desc { STI_GDP_3 = STI_GDP | STI_ID_3, STI_VID_0 = STI_VID | STI_ID_0, STI_VID_1 = STI_VID | STI_ID_1, + STI_HQVDP_0 = STI_VDP | STI_ID_0, STI_CURSOR = STI_CUR, STI_BACK = STI_BCK }; @@ -67,6 +69,7 @@ struct sti_layer_funcs { * * @plane: drm plane it is bound to (if any) * @fb: drm fb it is bound to + * @crtc: crtc it is bound to * @mode: display mode * @desc: layer type & id * @device: driver device @@ -88,6 +91,7 @@ struct sti_layer_funcs { struct sti_layer { struct drm_plane plane; struct drm_framebuffer *fb; + struct drm_crtc *crtc; struct drm_display_mode *mode; enum sti_layer_desc desc; struct device *dev; @@ -109,7 +113,9 @@ struct sti_layer { struct sti_layer *sti_layer_create(struct device *dev, int desc, void __iomem *baseaddr); -int sti_layer_prepare(struct sti_layer *layer, struct drm_framebuffer *fb, +int sti_layer_prepare(struct sti_layer *layer, + struct drm_crtc *crtc, + struct drm_framebuffer *fb, struct drm_display_mode *mode, int mixer_id, int dest_x, int dest_y, diff --git a/drivers/gpu/drm/sti/sti_mixer.c b/drivers/gpu/drm/sti/sti_mixer.c index 9a4ce74ac329..13a4b84deab6 100644 --- a/drivers/gpu/drm/sti/sti_mixer.c +++ b/drivers/gpu/drm/sti/sti_mixer.c @@ -123,6 +123,7 @@ int sti_mixer_set_layer_depth(struct sti_mixer *mixer, struct sti_layer *layer) layer_id = GAM_DEPTH_GDP3_ID; break; case STI_VID_0: + case STI_HQVDP_0: layer_id = GAM_DEPTH_VID0_ID; break; case STI_VID_1: @@ -189,6 +190,7 @@ static u32 sti_mixer_get_layer_mask(struct sti_layer *layer) case STI_GDP_3: return GAM_CTL_GDP3_MASK; case STI_VID_0: + case STI_HQVDP_0: return GAM_CTL_VID0_MASK; case STI_VID_1: return GAM_CTL_VID1_MASK; -- cgit v1.2.3-59-g8ed1b From 259307074bfcf1ff88016e12c68f057aee6cb694 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Mon, 19 Mar 2012 16:00:55 -0500 Subject: ipmi: Add SMBus interface driver (SSIF) This patch adds the SMBus interface to the IPMI driver. Signed-off-by: Corey Minyard Documentation/IPMI.txt | 32 drivers/char/ipmi/Kconfig | 11 drivers/char/ipmi/Makefile | 1 drivers/char/ipmi/ipmi_smb.c | 1737 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1769 insertions(+), 12 deletions(-) --- Documentation/IPMI.txt | 74 +- drivers/char/ipmi/Kconfig | 8 + drivers/char/ipmi/Makefile | 1 + drivers/char/ipmi/ipmi_ssif.c | 1870 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1950 insertions(+), 3 deletions(-) create mode 100644 drivers/char/ipmi/ipmi_ssif.c (limited to 'Documentation') diff --git a/Documentation/IPMI.txt b/Documentation/IPMI.txt index f13c9132e9f2..653d5d739d7f 100644 --- a/Documentation/IPMI.txt +++ b/Documentation/IPMI.txt @@ -42,7 +42,13 @@ The driver interface depends on your hardware. If your system properly provides the SMBIOS info for IPMI, the driver will detect it and just work. If you have a board with a standard interface (These will generally be either "KCS", "SMIC", or "BT", consult your hardware -manual), choose the 'IPMI SI handler' option. +manual), choose the 'IPMI SI handler' option. A driver also exists +for direct I2C access to the IPMI management controller. Some boards +support this, but it is unknown if it will work on every board. For +this, choose 'IPMI SMBus handler', but be ready to try to do some +figuring to see if it will work on your system if the SMBIOS/APCI +information is wrong or not present. It is fairly safe to have both +these enabled and let the drivers auto-detect what is present. You should generally enable ACPI on your system, as systems with IPMI can have ACPI tables describing them. @@ -52,7 +58,8 @@ their job correctly, the IPMI controller should be automatically detected (via ACPI or SMBIOS tables) and should just work. Sadly, many boards do not have this information. The driver attempts standard defaults, but they may not work. If you fall into this -situation, you need to read the section below named 'The SI Driver'. +situation, you need to read the section below named 'The SI Driver' or +"The SMBus Driver" on how to hand-configure your system. IPMI defines a standard watchdog timer. You can enable this with the 'IPMI Watchdog Timer' config option. If you compile the driver into @@ -97,7 +104,12 @@ driver, each open file for this device ties in to the message handler as an IPMI user. ipmi_si - A driver for various system interfaces. This supports KCS, -SMIC, and BT interfaces. +SMIC, and BT interfaces. Unless you have an SMBus interface or your +own custom interface, you probably need to use this. + +ipmi_ssif - A driver for accessing BMCs on the SMBus. It uses the +I2C kernel driver's SMBus interfaces to send and receive IPMI messages +over the SMBus. ipmi_watchdog - IPMI requires systems to have a very capable watchdog timer. This driver implements the standard Linux watchdog timer @@ -476,6 +488,62 @@ for specifying an interface. Note that when removing an interface, only the first three parameters (si type, address type, and address) are used for the comparison. Any options are ignored for removing. +The SMBus Driver (SSIF) +----------------------- + +The SMBus driver allows up to 4 SMBus devices to be configured in the +system. By default, the driver will only register with something it +finds in DMI or ACPI tables. You can change this +at module load time (for a module) with: + + modprobe ipmi_ssif.o + addr=[,[,...]] + adapter=[,[...]] + dbg=,... + slave_addrs=,,... + [dbg_probe=1] + +The addresses are normal I2C addresses. The adapter is the string +name of the adapter, as shown in /sys/class/i2c-adapter/i2c-/name. +It is *NOT* i2c- itself. + +The debug flags are bit flags for each BMC found, they are: +IPMI messages: 1, driver state: 2, timing: 4, I2C probe: 8 + +Setting dbg_probe to 1 will enable debugging of the probing and +detection process for BMCs on the SMBusses. + +The slave_addrs specifies the IPMI address of the local BMC. This is +usually 0x20 and the driver defaults to that, but in case it's not, it +can be specified when the driver starts up. + +Discovering the IPMI compliant BMC on the SMBus can cause devices on +the I2C bus to fail. The SMBus driver writes a "Get Device ID" IPMI +message as a block write to the I2C bus and waits for a response. +This action can be detrimental to some I2C devices. It is highly +recommended that the known I2C address be given to the SMBus driver in +the smb_addr parameter unless you have DMI or ACPI data to tell the +driver what to use. + +When compiled into the kernel, the addresses can be specified on the +kernel command line as: + + ipmb_ssif.addr=[,[...]] + ipmi_ssif.adapter=[,[...]] + ipmi_ssif.dbg=[,[...]] + ipmi_ssif.dbg_probe=1 + ipmi_ssif.slave_addrs=[,[...]] + +These are the same options as on the module command line. + +The I2C driver does not support non-blocking access or polling, so +this driver cannod to IPMI panic events, extend the watchdog at panic +time, or other panic-related IPMI functions without special kernel +patches and driver modifications. You can get those at the openipmi +web page. + +The driver supports a hot add and remove of interfaces through the I2C +sysfs interface. Other Pieces ------------ diff --git a/drivers/char/ipmi/Kconfig b/drivers/char/ipmi/Kconfig index db1c9b7adaa6..809d28328c6f 100644 --- a/drivers/char/ipmi/Kconfig +++ b/drivers/char/ipmi/Kconfig @@ -62,6 +62,14 @@ config IPMI_SI_PROBE_DEFAULTS only be available on older systems if the "ipmi_si_intf.trydefaults=1" boot argument is passed. +config IPMI_SSIF + tristate 'IPMI SMBus handler (SSIF)' + select I2C + help + Provides a driver for a SMBus interface to a BMC, meaning that you + have a driver that must be accessed over an I2C bus instead of a + standard interface. This module requires I2C support. + config IPMI_WATCHDOG tristate 'IPMI Watchdog Timer' help diff --git a/drivers/char/ipmi/Makefile b/drivers/char/ipmi/Makefile index 16a93648d54e..115c08da7117 100644 --- a/drivers/char/ipmi/Makefile +++ b/drivers/char/ipmi/Makefile @@ -7,5 +7,6 @@ ipmi_si-y := ipmi_si_intf.o ipmi_kcs_sm.o ipmi_smic_sm.o ipmi_bt_sm.o obj-$(CONFIG_IPMI_HANDLER) += ipmi_msghandler.o obj-$(CONFIG_IPMI_DEVICE_INTERFACE) += ipmi_devintf.o obj-$(CONFIG_IPMI_SI) += ipmi_si.o +obj-$(CONFIG_IPMI_SSIF) += ipmi_ssif.o obj-$(CONFIG_IPMI_WATCHDOG) += ipmi_watchdog.o obj-$(CONFIG_IPMI_POWEROFF) += ipmi_poweroff.o diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c new file mode 100644 index 000000000000..e178ac27e73c --- /dev/null +++ b/drivers/char/ipmi/ipmi_ssif.c @@ -0,0 +1,1870 @@ +/* + * ipmi_ssif.c + * + * The interface to the IPMI driver for SMBus access to a SMBus + * compliant device. Called SSIF by the IPMI spec. + * + * Author: Intel Corporation + * Todd Davis + * + * Rewritten by Corey Minyard to support the + * non-blocking I2C interface, add support for multi-part + * transactions, add PEC support, and general clenaup. + * + * Copyright 2003 Intel Corporation + * Copyright 2005 MontaVista Software + * + * 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 file holds the "policy" for the interface to the SSIF state + * machine. It does the configuration, handles timers and interrupts, + * and drives the real SSIF state machine. + */ + +/* + * TODO: Figure out how to use SMB alerts. This will require a new + * interface into the I2C driver, I believe. + */ + +#include +#if defined(MODVERSIONS) +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PFX "ipmi_ssif: " +#define DEVICE_NAME "ipmi_ssif" + +#define IPMI_GET_SYSTEM_INTERFACE_CAPABILITIES_CMD 0x57 + +#define SSIF_IPMI_REQUEST 2 +#define SSIF_IPMI_MULTI_PART_REQUEST_START 6 +#define SSIF_IPMI_MULTI_PART_REQUEST_MIDDLE 7 +#define SSIF_IPMI_RESPONSE 3 +#define SSIF_IPMI_MULTI_PART_RESPONSE_MIDDLE 9 + +/* ssif_debug is a bit-field + * SSIF_DEBUG_MSG - commands and their responses + * SSIF_DEBUG_STATES - message states + * SSIF_DEBUG_TIMING - Measure times between events in the driver + */ +#define SSIF_DEBUG_TIMING 4 +#define SSIF_DEBUG_STATE 2 +#define SSIF_DEBUG_MSG 1 +#define SSIF_NODEBUG 0 +#define SSIF_DEFAULT_DEBUG (SSIF_NODEBUG) + +/* + * Timer values + */ +#define SSIF_MSG_USEC 20000 /* 20ms between message tries. */ +#define SSIF_MSG_PART_USEC 5000 /* 5ms for a message part */ + +/* How many times to we retry sending/receiving the message. */ +#define SSIF_SEND_RETRIES 5 +#define SSIF_RECV_RETRIES 250 + +#define SSIF_MSG_MSEC (SSIF_MSG_USEC / 1000) +#define SSIF_MSG_JIFFIES ((SSIF_MSG_USEC * 1000) / TICK_NSEC) +#define SSIF_MSG_PART_JIFFIES ((SSIF_MSG_PART_USEC * 1000) / TICK_NSEC) + +enum ssif_intf_state { + SSIF_NORMAL, + SSIF_GETTING_FLAGS, + SSIF_GETTING_EVENTS, + SSIF_CLEARING_FLAGS, + SSIF_GETTING_MESSAGES, + /* FIXME - add watchdog stuff. */ +}; + +#define SSIF_IDLE(ssif) ((ssif)->ssif_state == SSIF_NORMAL \ + && (ssif)->curr_msg == NULL) + +/* + * Indexes into stats[] in ssif_info below. + */ +enum ssif_stat_indexes { + /* Number of total messages sent. */ + SSIF_STAT_sent_messages = 0, + + /* + * Number of message parts sent. Messages may be broken into + * parts if they are long. + */ + SSIF_STAT_sent_messages_parts, + + /* + * Number of time a message was retried. + */ + SSIF_STAT_send_retries, + + /* + * Number of times the send of a message failed. + */ + SSIF_STAT_send_errors, + + /* + * Number of message responses received. + */ + SSIF_STAT_received_messages, + + /* + * Number of message fragments received. + */ + SSIF_STAT_received_message_parts, + + /* + * Number of times the receive of a message was retried. + */ + SSIF_STAT_receive_retries, + + /* + * Number of errors receiving messages. + */ + SSIF_STAT_receive_errors, + + /* + * Number of times a flag fetch was requested. + */ + SSIF_STAT_flag_fetches, + + /* + * Number of times the hardware didn't follow the state machine. + */ + SSIF_STAT_hosed, + + /* + * Number of received events. + */ + SSIF_STAT_events, + + /* Number of asyncronous messages received. */ + SSIF_STAT_incoming_messages, + + /* Number of watchdog pretimeouts. */ + SSIF_STAT_watchdog_pretimeouts, + + /* Always add statistics before this value, it must be last. */ + SSIF_NUM_STATS +}; + +struct ssif_addr_info { + unsigned short addr; + struct i2c_board_info binfo; + char *adapter_name; + int debug; + int slave_addr; + enum ipmi_addr_src addr_src; + union ipmi_smi_info_union addr_info; + + struct mutex clients_mutex; + struct list_head clients; + + struct list_head link; +}; + +struct ssif_info; + +typedef void (*ssif_i2c_done)(struct ssif_info *ssif_info, int result, + unsigned char *data, unsigned int len); + +struct ssif_info { + ipmi_smi_t intf; + int intf_num; + spinlock_t lock; + struct ipmi_smi_msg *waiting_msg; + struct ipmi_smi_msg *curr_msg; + enum ssif_intf_state ssif_state; + unsigned long ssif_debug; + + struct ipmi_smi_handlers handlers; + + enum ipmi_addr_src addr_source; /* ACPI, PCI, SMBIOS, hardcode, etc. */ + union ipmi_smi_info_union addr_info; + + /* + * Flags from the last GET_MSG_FLAGS command, used when an ATTN + * is set to hold the flags until we are done handling everything + * from the flags. + */ +#define RECEIVE_MSG_AVAIL 0x01 +#define EVENT_MSG_BUFFER_FULL 0x02 +#define WDT_PRE_TIMEOUT_INT 0x08 + unsigned char msg_flags; + + bool has_event_buffer; + + /* + * If set to true, this will request events the next time the + * state machine is idle. + */ + bool req_events; + + /* + * If set to true, this will request flags the next time the + * state machine is idle. + */ + bool req_flags; + + /* + * Used to perform timer operations when run-to-completion + * mode is on. This is a countdown timer. + */ + int rtc_us_timer; + + /* Used for sending/receiving data. +1 for the length. */ + unsigned char data[IPMI_MAX_MSG_LENGTH + 1]; + unsigned int data_len; + + /* Temp receive buffer, gets copied into data. */ + unsigned char recv[I2C_SMBUS_BLOCK_MAX]; + + struct i2c_client *client; + ssif_i2c_done done_handler; + + /* Thread interface handling */ + struct task_struct *thread; + struct completion wake_thread; + bool stopping; + int i2c_read_write; + int i2c_command; + unsigned char *i2c_data; + unsigned int i2c_size; + + /* From the device id response. */ + struct ipmi_device_id device_id; + + struct timer_list retry_timer; + int retries_left; + + /* Info from SSIF cmd */ + unsigned char max_xmit_msg_size; + unsigned char max_recv_msg_size; + unsigned int multi_support; + int supports_pec; + +#define SSIF_NO_MULTI 0 +#define SSIF_MULTI_2_PART 1 +#define SSIF_MULTI_n_PART 2 + unsigned char *multi_data; + unsigned int multi_len; + unsigned int multi_pos; + + atomic_t stats[SSIF_NUM_STATS]; +}; + +#define ssif_inc_stat(ssif, stat) \ + atomic_inc(&(ssif)->stats[SSIF_STAT_ ## stat]) +#define ssif_get_stat(ssif, stat) \ + ((unsigned int) atomic_read(&(ssif)->stats[SSIF_STAT_ ## stat])) + +static bool initialized; + +static atomic_t next_intf = ATOMIC_INIT(0); + +static void return_hosed_msg(struct ssif_info *ssif_info, + struct ipmi_smi_msg *msg); +static void start_next_msg(struct ssif_info *ssif_info, unsigned long *flags); +static int start_send(struct ssif_info *ssif_info, + unsigned char *data, + unsigned int len); + +static unsigned long *ipmi_ssif_lock_cond(struct ssif_info *ssif_info, + unsigned long *flags) +{ + spin_lock_irqsave(&ssif_info->lock, *flags); + return flags; +} + +static void ipmi_ssif_unlock_cond(struct ssif_info *ssif_info, + unsigned long *flags) +{ + spin_unlock_irqrestore(&ssif_info->lock, *flags); +} + +static void deliver_recv_msg(struct ssif_info *ssif_info, + struct ipmi_smi_msg *msg) +{ + ipmi_smi_t intf = ssif_info->intf; + + if (!intf) { + ipmi_free_smi_msg(msg); + } else if (msg->rsp_size < 0) { + return_hosed_msg(ssif_info, msg); + pr_err(PFX + "Malformed message in deliver_recv_msg: rsp_size = %d\n", + msg->rsp_size); + } else { + ipmi_smi_msg_received(intf, msg); + } +} + +static void return_hosed_msg(struct ssif_info *ssif_info, + struct ipmi_smi_msg *msg) +{ + ssif_inc_stat(ssif_info, hosed); + + /* Make it a response */ + msg->rsp[0] = msg->data[0] | 4; + msg->rsp[1] = msg->data[1]; + msg->rsp[2] = 0xFF; /* Unknown error. */ + msg->rsp_size = 3; + + deliver_recv_msg(ssif_info, msg); +} + +/* + * Must be called with the message lock held. This will release the + * message lock. Note that the caller will check SSIF_IDLE and start a + * new operation, so there is no need to check for new messages to + * start in here. + */ +static void start_clear_flags(struct ssif_info *ssif_info, unsigned long *flags) +{ + unsigned char msg[3]; + + ssif_info->msg_flags &= ~WDT_PRE_TIMEOUT_INT; + ssif_info->ssif_state = SSIF_CLEARING_FLAGS; + ipmi_ssif_unlock_cond(ssif_info, flags); + + /* Make sure the watchdog pre-timeout flag is not set at startup. */ + msg[0] = (IPMI_NETFN_APP_REQUEST << 2); + msg[1] = IPMI_CLEAR_MSG_FLAGS_CMD; + msg[2] = WDT_PRE_TIMEOUT_INT; + + if (start_send(ssif_info, msg, 3) != 0) { + /* Error, just go to normal state. */ + ssif_info->ssif_state = SSIF_NORMAL; + } +} + +static void start_flag_fetch(struct ssif_info *ssif_info, unsigned long *flags) +{ + unsigned char mb[2]; + + ssif_info->req_flags = false; + ssif_info->ssif_state = SSIF_GETTING_FLAGS; + ipmi_ssif_unlock_cond(ssif_info, flags); + + mb[0] = (IPMI_NETFN_APP_REQUEST << 2); + mb[1] = IPMI_GET_MSG_FLAGS_CMD; + if (start_send(ssif_info, mb, 2) != 0) + ssif_info->ssif_state = SSIF_NORMAL; +} + +static void check_start_send(struct ssif_info *ssif_info, unsigned long *flags, + struct ipmi_smi_msg *msg) +{ + if (start_send(ssif_info, msg->data, msg->data_size) != 0) { + unsigned long oflags; + + flags = ipmi_ssif_lock_cond(ssif_info, &oflags); + ssif_info->curr_msg = NULL; + ssif_info->ssif_state = SSIF_NORMAL; + ipmi_ssif_unlock_cond(ssif_info, flags); + ipmi_free_smi_msg(msg); + } +} + +static void start_event_fetch(struct ssif_info *ssif_info, unsigned long *flags) +{ + struct ipmi_smi_msg *msg; + + ssif_info->req_events = false; + + msg = ipmi_alloc_smi_msg(); + if (!msg) { + ssif_info->ssif_state = SSIF_NORMAL; + return; + } + + ssif_info->curr_msg = msg; + ssif_info->ssif_state = SSIF_GETTING_EVENTS; + ipmi_ssif_unlock_cond(ssif_info, flags); + + msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2); + msg->data[1] = IPMI_READ_EVENT_MSG_BUFFER_CMD; + msg->data_size = 2; + + check_start_send(ssif_info, flags, msg); +} + +static void start_recv_msg_fetch(struct ssif_info *ssif_info, + unsigned long *flags) +{ + struct ipmi_smi_msg *msg; + + msg = ipmi_alloc_smi_msg(); + if (!msg) { + ssif_info->ssif_state = SSIF_NORMAL; + return; + } + + ssif_info->curr_msg = msg; + ssif_info->ssif_state = SSIF_GETTING_MESSAGES; + ipmi_ssif_unlock_cond(ssif_info, flags); + + msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2); + msg->data[1] = IPMI_GET_MSG_CMD; + msg->data_size = 2; + + check_start_send(ssif_info, flags, msg); +} + +/* + * Must be called with the message lock held. This will release the + * message lock. Note that the caller will check SSIF_IDLE and start a + * new operation, so there is no need to check for new messages to + * start in here. + */ +static void handle_flags(struct ssif_info *ssif_info, unsigned long *flags) +{ + if (ssif_info->msg_flags & WDT_PRE_TIMEOUT_INT) { + ipmi_smi_t intf = ssif_info->intf; + /* Watchdog pre-timeout */ + ssif_inc_stat(ssif_info, watchdog_pretimeouts); + start_clear_flags(ssif_info, flags); + if (intf) + ipmi_smi_watchdog_pretimeout(intf); + } else if (ssif_info->msg_flags & RECEIVE_MSG_AVAIL) + /* Messages available. */ + start_recv_msg_fetch(ssif_info, flags); + else if (ssif_info->msg_flags & EVENT_MSG_BUFFER_FULL) + /* Events available. */ + start_event_fetch(ssif_info, flags); + else { + ssif_info->ssif_state = SSIF_NORMAL; + ipmi_ssif_unlock_cond(ssif_info, flags); + } +} + +static int ipmi_ssif_thread(void *data) +{ + struct ssif_info *ssif_info = data; + + while (!kthread_should_stop()) { + int result; + + /* Wait for something to do */ + wait_for_completion(&ssif_info->wake_thread); + init_completion(&ssif_info->wake_thread); + + if (ssif_info->stopping) + break; + + if (ssif_info->i2c_read_write == I2C_SMBUS_WRITE) { + result = i2c_smbus_write_block_data( + ssif_info->client, SSIF_IPMI_REQUEST, + ssif_info->i2c_data[0], + ssif_info->i2c_data + 1); + ssif_info->done_handler(ssif_info, result, NULL, 0); + } else { + result = i2c_smbus_read_block_data( + ssif_info->client, SSIF_IPMI_RESPONSE, + ssif_info->i2c_data); + if (result < 0) + ssif_info->done_handler(ssif_info, result, + NULL, 0); + else + ssif_info->done_handler(ssif_info, 0, + ssif_info->i2c_data, + result); + } + } + + return 0; +} + +static int ssif_i2c_send(struct ssif_info *ssif_info, + ssif_i2c_done handler, + int read_write, int command, + unsigned char *data, unsigned int size) +{ + ssif_info->done_handler = handler; + + ssif_info->i2c_read_write = read_write; + ssif_info->i2c_command = command; + ssif_info->i2c_data = data; + ssif_info->i2c_size = size; + complete(&ssif_info->wake_thread); + return 0; +} + + +static void msg_done_handler(struct ssif_info *ssif_info, int result, + unsigned char *data, unsigned int len); + +static void retry_timeout(unsigned long data) +{ + struct ssif_info *ssif_info = (void *) data; + int rv; + + if (ssif_info->stopping) + return; + + ssif_info->rtc_us_timer = 0; + + rv = ssif_i2c_send(ssif_info, msg_done_handler, I2C_SMBUS_READ, + SSIF_IPMI_RESPONSE, + ssif_info->recv, I2C_SMBUS_BLOCK_DATA); + if (rv < 0) { + /* request failed, just return the error. */ + if (ssif_info->ssif_debug & SSIF_DEBUG_MSG) + pr_info("Error from i2c_non_blocking_op(5)\n"); + + msg_done_handler(ssif_info, -EIO, NULL, 0); + } +} + +static int start_resend(struct ssif_info *ssif_info); + +static void msg_done_handler(struct ssif_info *ssif_info, int result, + unsigned char *data, unsigned int len) +{ + struct ipmi_smi_msg *msg; + unsigned long oflags, *flags; + int rv; + + /* + * We are single-threaded here, so no need for a lock until we + * start messing with driver states or the queues. + */ + + if (result < 0) { + ssif_info->retries_left--; + if (ssif_info->retries_left > 0) { + ssif_inc_stat(ssif_info, receive_retries); + + mod_timer(&ssif_info->retry_timer, + jiffies + SSIF_MSG_JIFFIES); + ssif_info->rtc_us_timer = SSIF_MSG_USEC; + return; + } + + ssif_inc_stat(ssif_info, receive_errors); + + if (ssif_info->ssif_debug & SSIF_DEBUG_MSG) + pr_info("Error in msg_done_handler: %d\n", result); + len = 0; + goto continue_op; + } + + if ((len > 1) && (ssif_info->multi_pos == 0) + && (data[0] == 0x00) && (data[1] == 0x01)) { + /* Start of multi-part read. Start the next transaction. */ + int i; + + ssif_inc_stat(ssif_info, received_message_parts); + + /* Remove the multi-part read marker. */ + for (i = 0; i < (len-2); i++) + ssif_info->data[i] = data[i+2]; + len -= 2; + ssif_info->multi_len = len; + ssif_info->multi_pos = 1; + + rv = ssif_i2c_send(ssif_info, msg_done_handler, I2C_SMBUS_READ, + SSIF_IPMI_MULTI_PART_RESPONSE_MIDDLE, + ssif_info->recv, I2C_SMBUS_BLOCK_DATA); + if (rv < 0) { + if (ssif_info->ssif_debug & SSIF_DEBUG_MSG) + pr_info("Error from i2c_non_blocking_op(1)\n"); + + result = -EIO; + } else + return; + } else if (ssif_info->multi_pos) { + /* Middle of multi-part read. Start the next transaction. */ + int i; + unsigned char blocknum; + + if (len == 0) { + result = -EIO; + if (ssif_info->ssif_debug & SSIF_DEBUG_MSG) + pr_info(PFX "Middle message with no data\n"); + + goto continue_op; + } + + blocknum = data[ssif_info->multi_len]; + + if (ssif_info->multi_len+len-1 > IPMI_MAX_MSG_LENGTH) { + /* Received message too big, abort the operation. */ + result = -E2BIG; + if (ssif_info->ssif_debug & SSIF_DEBUG_MSG) + pr_info("Received message too big\n"); + + goto continue_op; + } + + /* Remove the blocknum from the data. */ + for (i = 0; i < (len-1); i++) + ssif_info->data[i+ssif_info->multi_len] = data[i+1]; + len--; + ssif_info->multi_len += len; + if (blocknum == 0xff) { + /* End of read */ + len = ssif_info->multi_len; + data = ssif_info->data; + } else if ((blocknum+1) != ssif_info->multi_pos) { + /* + * Out of sequence block, just abort. Block + * numbers start at zero for the second block, + * but multi_pos starts at one, so the +1. + */ + result = -EIO; + } else { + ssif_inc_stat(ssif_info, received_message_parts); + + ssif_info->multi_pos++; + + rv = ssif_i2c_send(ssif_info, msg_done_handler, + I2C_SMBUS_READ, + SSIF_IPMI_MULTI_PART_RESPONSE_MIDDLE, + ssif_info->recv, + I2C_SMBUS_BLOCK_DATA); + if (rv < 0) { + if (ssif_info->ssif_debug & SSIF_DEBUG_MSG) + pr_info(PFX + "Error from i2c_non_blocking_op(2)\n"); + + result = -EIO; + } else + return; + } + } + + if (result < 0) { + ssif_inc_stat(ssif_info, receive_errors); + } else { + ssif_inc_stat(ssif_info, received_messages); + ssif_inc_stat(ssif_info, received_message_parts); + } + + + continue_op: + if (ssif_info->ssif_debug & SSIF_DEBUG_STATE) + pr_info(PFX "DONE 1: state = %d, result=%d.\n", + ssif_info->ssif_state, result); + + flags = ipmi_ssif_lock_cond(ssif_info, &oflags); + msg = ssif_info->curr_msg; + if (msg) { + msg->rsp_size = len; + if (msg->rsp_size > IPMI_MAX_MSG_LENGTH) + msg->rsp_size = IPMI_MAX_MSG_LENGTH; + memcpy(msg->rsp, data, msg->rsp_size); + ssif_info->curr_msg = NULL; + } + + switch (ssif_info->ssif_state) { + case SSIF_NORMAL: + ipmi_ssif_unlock_cond(ssif_info, flags); + if (!msg) + break; + + if (result < 0) + return_hosed_msg(ssif_info, msg); + else + deliver_recv_msg(ssif_info, msg); + break; + + case SSIF_GETTING_FLAGS: + /* We got the flags from the SSIF, now handle them. */ + if ((result < 0) || (len < 4) || (data[2] != 0)) { + /* + * Error fetching flags, or invalid length, + * just give up for now. + */ + ssif_info->ssif_state = SSIF_NORMAL; + ipmi_ssif_unlock_cond(ssif_info, flags); + pr_warn(PFX "Error getting flags: %d %d, %x\n", + result, len, data[2]); + } else if (data[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 + || data[1] != IPMI_GET_MSG_FLAGS_CMD) { + pr_warn(PFX "Invalid response getting flags: %x %x\n", + data[0], data[1]); + } else { + ssif_inc_stat(ssif_info, flag_fetches); + ssif_info->msg_flags = data[3]; + handle_flags(ssif_info, flags); + } + break; + + case SSIF_CLEARING_FLAGS: + /* We cleared the flags. */ + if ((result < 0) || (len < 3) || (data[2] != 0)) { + /* Error clearing flags */ + pr_warn(PFX "Error clearing flags: %d %d, %x\n", + result, len, data[2]); + } else if (data[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 + || data[1] != IPMI_CLEAR_MSG_FLAGS_CMD) { + pr_warn(PFX "Invalid response clearing flags: %x %x\n", + data[0], data[1]); + } + ssif_info->ssif_state = SSIF_NORMAL; + ipmi_ssif_unlock_cond(ssif_info, flags); + break; + + case SSIF_GETTING_EVENTS: + if ((result < 0) || (len < 3) || (msg->rsp[2] != 0)) { + /* Error getting event, probably done. */ + msg->done(msg); + + /* Take off the event flag. */ + ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL; + handle_flags(ssif_info, flags); + } else if (msg->rsp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 + || msg->rsp[1] != IPMI_READ_EVENT_MSG_BUFFER_CMD) { + pr_warn(PFX "Invalid response getting events: %x %x\n", + msg->rsp[0], msg->rsp[1]); + msg->done(msg); + /* Take off the event flag. */ + ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL; + handle_flags(ssif_info, flags); + } else { + handle_flags(ssif_info, flags); + ssif_inc_stat(ssif_info, events); + deliver_recv_msg(ssif_info, msg); + } + break; + + case SSIF_GETTING_MESSAGES: + if ((result < 0) || (len < 3) || (msg->rsp[2] != 0)) { + /* Error getting event, probably done. */ + msg->done(msg); + + /* Take off the msg flag. */ + ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL; + handle_flags(ssif_info, flags); + } else if (msg->rsp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 + || msg->rsp[1] != IPMI_GET_MSG_CMD) { + pr_warn(PFX "Invalid response clearing flags: %x %x\n", + msg->rsp[0], msg->rsp[1]); + msg->done(msg); + + /* Take off the msg flag. */ + ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL; + handle_flags(ssif_info, flags); + } else { + ssif_inc_stat(ssif_info, incoming_messages); + handle_flags(ssif_info, flags); + deliver_recv_msg(ssif_info, msg); + } + break; + } + + flags = ipmi_ssif_lock_cond(ssif_info, &oflags); + if (SSIF_IDLE(ssif_info) && !ssif_info->stopping) { + if (ssif_info->req_events) + start_event_fetch(ssif_info, flags); + else if (ssif_info->req_flags) + start_flag_fetch(ssif_info, flags); + else + start_next_msg(ssif_info, flags); + } else + ipmi_ssif_unlock_cond(ssif_info, flags); + + if (ssif_info->ssif_debug & SSIF_DEBUG_STATE) + pr_info(PFX "DONE 2: state = %d.\n", ssif_info->ssif_state); +} + +static void msg_written_handler(struct ssif_info *ssif_info, int result, + unsigned char *data, unsigned int len) +{ + int rv; + + /* We are single-threaded here, so no need for a lock. */ + if (result < 0) { + ssif_info->retries_left--; + if (ssif_info->retries_left > 0) { + if (!start_resend(ssif_info)) { + ssif_inc_stat(ssif_info, send_retries); + return; + } + /* request failed, just return the error. */ + ssif_inc_stat(ssif_info, send_errors); + + if (ssif_info->ssif_debug & SSIF_DEBUG_MSG) + pr_info(PFX + "Out of retries in msg_written_handler\n"); + msg_done_handler(ssif_info, -EIO, NULL, 0); + return; + } + + ssif_inc_stat(ssif_info, send_errors); + + /* + * Got an error on transmit, let the done routine + * handle it. + */ + if (ssif_info->ssif_debug & SSIF_DEBUG_MSG) + pr_info("Error in msg_written_handler: %d\n", result); + + msg_done_handler(ssif_info, result, NULL, 0); + return; + } + + if (ssif_info->multi_data) { + /* In the middle of a multi-data write. */ + int left; + + ssif_inc_stat(ssif_info, sent_messages_parts); + + left = ssif_info->multi_len - ssif_info->multi_pos; + if (left > 32) + left = 32; + /* Length byte. */ + ssif_info->multi_data[ssif_info->multi_pos] = left; + ssif_info->multi_pos += left; + if (left < 32) + /* + * Write is finished. Note that we must end + * with a write of less than 32 bytes to + * complete the transaction, even if it is + * zero bytes. + */ + ssif_info->multi_data = NULL; + + rv = ssif_i2c_send(ssif_info, msg_written_handler, + I2C_SMBUS_WRITE, + SSIF_IPMI_MULTI_PART_REQUEST_MIDDLE, + ssif_info->multi_data + ssif_info->multi_pos, + I2C_SMBUS_BLOCK_DATA); + if (rv < 0) { + /* request failed, just return the error. */ + ssif_inc_stat(ssif_info, send_errors); + + if (ssif_info->ssif_debug & SSIF_DEBUG_MSG) + pr_info("Error from i2c_non_blocking_op(3)\n"); + msg_done_handler(ssif_info, -EIO, NULL, 0); + } + } else { + ssif_inc_stat(ssif_info, sent_messages); + ssif_inc_stat(ssif_info, sent_messages_parts); + + /* Wait a jiffie then request the next message */ + ssif_info->retries_left = SSIF_RECV_RETRIES; + ssif_info->rtc_us_timer = SSIF_MSG_PART_USEC; + mod_timer(&ssif_info->retry_timer, + jiffies + SSIF_MSG_PART_JIFFIES); + return; + } +} + +static int start_resend(struct ssif_info *ssif_info) +{ + int rv; + int command; + + if (ssif_info->data_len > 32) { + command = SSIF_IPMI_MULTI_PART_REQUEST_START; + ssif_info->multi_data = ssif_info->data; + ssif_info->multi_len = ssif_info->data_len; + /* + * Subtle thing, this is 32, not 33, because we will + * overwrite the thing at position 32 (which was just + * transmitted) with the new length. + */ + ssif_info->multi_pos = 32; + ssif_info->data[0] = 32; + } else { + ssif_info->multi_data = NULL; + command = SSIF_IPMI_REQUEST; + ssif_info->data[0] = ssif_info->data_len; + } + + rv = ssif_i2c_send(ssif_info, msg_written_handler, I2C_SMBUS_WRITE, + command, ssif_info->data, I2C_SMBUS_BLOCK_DATA); + if (rv && (ssif_info->ssif_debug & SSIF_DEBUG_MSG)) + pr_info("Error from i2c_non_blocking_op(4)\n"); + return rv; +} + +static int start_send(struct ssif_info *ssif_info, + unsigned char *data, + unsigned int len) +{ + if (len > IPMI_MAX_MSG_LENGTH) + return -E2BIG; + if (len > ssif_info->max_xmit_msg_size) + return -E2BIG; + + ssif_info->retries_left = SSIF_SEND_RETRIES; + memcpy(ssif_info->data+1, data, len); + ssif_info->data_len = len; + return start_resend(ssif_info); +} + +/* Must be called with the message lock held. */ +static void start_next_msg(struct ssif_info *ssif_info, unsigned long *flags) +{ + struct ipmi_smi_msg *msg; + unsigned long oflags; + + restart: + if (!SSIF_IDLE(ssif_info)) { + ipmi_ssif_unlock_cond(ssif_info, flags); + return; + } + + if (!ssif_info->waiting_msg) { + ssif_info->curr_msg = NULL; + ipmi_ssif_unlock_cond(ssif_info, flags); + } else { + int rv; + + ssif_info->curr_msg = ssif_info->waiting_msg; + ssif_info->waiting_msg = NULL; + ipmi_ssif_unlock_cond(ssif_info, flags); + rv = start_send(ssif_info, + ssif_info->curr_msg->data, + ssif_info->curr_msg->data_size); + if (rv) { + msg = ssif_info->curr_msg; + ssif_info->curr_msg = NULL; + return_hosed_msg(ssif_info, msg); + flags = ipmi_ssif_lock_cond(ssif_info, &oflags); + goto restart; + } + } +} + +static void sender(void *send_info, + struct ipmi_smi_msg *msg) +{ + struct ssif_info *ssif_info = (struct ssif_info *) send_info; + unsigned long oflags, *flags; + + BUG_ON(ssif_info->waiting_msg); + ssif_info->waiting_msg = msg; + + flags = ipmi_ssif_lock_cond(ssif_info, &oflags); + start_next_msg(ssif_info, flags); + + if (ssif_info->ssif_debug & SSIF_DEBUG_TIMING) { + struct timeval t; + + do_gettimeofday(&t); + pr_info("**Enqueue %02x %02x: %ld.%6.6ld\n", + msg->data[0], msg->data[1], t.tv_sec, t.tv_usec); + } +} + +static int get_smi_info(void *send_info, struct ipmi_smi_info *data) +{ + struct ssif_info *ssif_info = send_info; + + data->addr_src = ssif_info->addr_source; + data->dev = &ssif_info->client->dev; + data->addr_info = ssif_info->addr_info; + get_device(data->dev); + + return 0; +} + +/* + * Instead of having our own timer to periodically check the message + * flags, we let the message handler drive us. + */ +static void request_events(void *send_info) +{ + struct ssif_info *ssif_info = (struct ssif_info *) send_info; + unsigned long oflags, *flags; + + if (!ssif_info->has_event_buffer) + return; + + flags = ipmi_ssif_lock_cond(ssif_info, &oflags); + /* + * Request flags first, not events, because the lower layer + * doesn't have a way to send an attention. But make sure + * event checking still happens. + */ + ssif_info->req_events = true; + if (SSIF_IDLE(ssif_info)) + start_flag_fetch(ssif_info, flags); + else { + ssif_info->req_flags = true; + ipmi_ssif_unlock_cond(ssif_info, flags); + } +} + +static int inc_usecount(void *send_info) +{ + struct ssif_info *ssif_info = send_info; + + if (!i2c_get_adapter(ssif_info->client->adapter->nr)) + return -ENODEV; + + i2c_use_client(ssif_info->client); + return 0; +} + +static void dec_usecount(void *send_info) +{ + struct ssif_info *ssif_info = send_info; + + i2c_release_client(ssif_info->client); + i2c_put_adapter(ssif_info->client->adapter); +} + +static int ssif_start_processing(void *send_info, + ipmi_smi_t intf) +{ + struct ssif_info *ssif_info = send_info; + + ssif_info->intf = intf; + + return 0; +} + +#define MAX_SSIF_BMCS 4 + +static unsigned short addr[MAX_SSIF_BMCS]; +static int num_addrs; +module_param_array(addr, ushort, &num_addrs, 0); +MODULE_PARM_DESC(addr, "The addresses to scan for IPMI BMCs on the SSIFs."); + +static char *adapter_name[MAX_SSIF_BMCS]; +static int num_adapter_names; +module_param_array(adapter_name, charp, &num_adapter_names, 0); +MODULE_PARM_DESC(adapter_name, "The string name of the I2C device that has the BMC. By default all devices are scanned."); + +static int slave_addrs[MAX_SSIF_BMCS]; +static int num_slave_addrs; +module_param_array(slave_addrs, int, &num_slave_addrs, 0); +MODULE_PARM_DESC(slave_addrs, + "The default IPMB slave address for the controller."); + +/* + * Bit 0 enables message debugging, bit 1 enables state debugging, and + * bit 2 enables timing debugging. This is an array indexed by + * interface number" + */ +static int dbg[MAX_SSIF_BMCS]; +static int num_dbg; +module_param_array(dbg, int, &num_dbg, 0); +MODULE_PARM_DESC(dbg, "Turn on debugging."); + +static bool ssif_dbg_probe; +module_param_named(dbg_probe, ssif_dbg_probe, bool, 0); +MODULE_PARM_DESC(dbg_probe, "Enable debugging of probing of adapters."); + +static int use_thread; +module_param(use_thread, int, 0); +MODULE_PARM_DESC(use_thread, "Use the thread interface."); + +static bool ssif_tryacpi = 1; +module_param_named(tryacpi, ssif_tryacpi, bool, 0); +MODULE_PARM_DESC(tryacpi, "Setting this to zero will disable the default scan of the interfaces identified via ACPI"); + +static bool ssif_trydmi = 1; +module_param_named(trydmi, ssif_trydmi, bool, 0); +MODULE_PARM_DESC(trydmi, "Setting this to zero will disable the default scan of the interfaces identified via DMI (SMBIOS)"); + +static DEFINE_MUTEX(ssif_infos_mutex); +static LIST_HEAD(ssif_infos); + +static int ssif_remove(struct i2c_client *client) +{ + struct ssif_info *ssif_info = i2c_get_clientdata(client); + int rv; + + if (!ssif_info) + return 0; + + i2c_set_clientdata(client, NULL); + + /* + * After this point, we won't deliver anything asychronously + * to the message handler. We can unregister ourself. + */ + rv = ipmi_unregister_smi(ssif_info->intf); + if (rv) { + pr_err(PFX "Unable to unregister device: errno=%d\n", rv); + return rv; + } + ssif_info->intf = NULL; + + /* make sure the driver is not looking for flags any more. */ + while (ssif_info->ssif_state != SSIF_NORMAL) + schedule_timeout(1); + + ssif_info->stopping = true; + del_timer_sync(&ssif_info->retry_timer); + if (ssif_info->thread) { + complete(&ssif_info->wake_thread); + kthread_stop(ssif_info->thread); + } + + /* + * No message can be outstanding now, we have removed the + * upper layer and it permitted us to do so. + */ + kfree(ssif_info); + return 0; +} + +static int do_cmd(struct i2c_client *client, int len, unsigned char *msg, + int *resp_len, unsigned char *resp) +{ + int retry_cnt; + int ret; + + retry_cnt = SSIF_SEND_RETRIES; + retry1: + ret = i2c_smbus_write_block_data(client, SSIF_IPMI_REQUEST, len, msg); + if (ret) { + retry_cnt--; + if (retry_cnt > 0) + goto retry1; + return -ENODEV; + } + + ret = -ENODEV; + retry_cnt = SSIF_RECV_RETRIES; + while (retry_cnt > 0) { + ret = i2c_smbus_read_block_data(client, SSIF_IPMI_RESPONSE, + resp); + if (ret > 0) + break; + msleep(SSIF_MSG_MSEC); + retry_cnt--; + if (retry_cnt <= 0) + break; + } + + if (ret > 0) { + /* Validate that the response is correct. */ + if (ret < 3 || + (resp[0] != (msg[0] | (1 << 2))) || + (resp[1] != msg[1])) + ret = -EINVAL; + else { + *resp_len = ret; + ret = 0; + } + } + + return ret; +} + +static int ssif_detect(struct i2c_client *client, struct i2c_board_info *info) +{ + unsigned char *resp; + unsigned char msg[3]; + int rv; + int len; + + resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL); + if (!resp) + return -ENOMEM; + + /* Do a Get Device ID command, since it is required. */ + msg[0] = IPMI_NETFN_APP_REQUEST << 2; + msg[1] = IPMI_GET_DEVICE_ID_CMD; + rv = do_cmd(client, 2, msg, &len, resp); + if (rv) + rv = -ENODEV; + else + strlcpy(info->type, DEVICE_NAME, I2C_NAME_SIZE); + kfree(resp); + return rv; +} + +static int smi_type_proc_show(struct seq_file *m, void *v) +{ + return seq_puts(m, "ssif\n"); +} + +static int smi_type_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, smi_type_proc_show, inode->i_private); +} + +static const struct file_operations smi_type_proc_ops = { + .open = smi_type_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int smi_stats_proc_show(struct seq_file *m, void *v) +{ + struct ssif_info *ssif_info = m->private; + + seq_printf(m, "sent_messages: %u\n", + ssif_get_stat(ssif_info, sent_messages)); + seq_printf(m, "sent_messages_parts: %u\n", + ssif_get_stat(ssif_info, sent_messages_parts)); + seq_printf(m, "send_retries: %u\n", + ssif_get_stat(ssif_info, send_retries)); + seq_printf(m, "send_errors: %u\n", + ssif_get_stat(ssif_info, send_errors)); + seq_printf(m, "received_messages: %u\n", + ssif_get_stat(ssif_info, received_messages)); + seq_printf(m, "received_message_parts: %u\n", + ssif_get_stat(ssif_info, received_message_parts)); + seq_printf(m, "receive_retries: %u\n", + ssif_get_stat(ssif_info, receive_retries)); + seq_printf(m, "receive_errors: %u\n", + ssif_get_stat(ssif_info, receive_errors)); + seq_printf(m, "flag_fetches: %u\n", + ssif_get_stat(ssif_info, flag_fetches)); + seq_printf(m, "hosed: %u\n", + ssif_get_stat(ssif_info, hosed)); + seq_printf(m, "events: %u\n", + ssif_get_stat(ssif_info, events)); + seq_printf(m, "watchdog_pretimeouts: %u\n", + ssif_get_stat(ssif_info, watchdog_pretimeouts)); + return 0; +} + +static int smi_stats_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, smi_stats_proc_show, PDE_DATA(inode)); +} + +static const struct file_operations smi_stats_proc_ops = { + .open = smi_stats_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static struct ssif_addr_info *ssif_info_find(unsigned short addr, + char *adapter_name, + bool match_null_name) +{ + struct ssif_addr_info *info, *found = NULL; + +restart: + list_for_each_entry(info, &ssif_infos, link) { + if (info->binfo.addr == addr) { + if (info->adapter_name || adapter_name) { + if (!info->adapter_name != !adapter_name) { + /* One is NULL and one is not */ + continue; + } + if (strcmp(info->adapter_name, adapter_name)) + /* Names to not match */ + continue; + } + found = info; + break; + } + } + + if (!found && match_null_name) { + /* Try to get an exact match first, then try with a NULL name */ + adapter_name = NULL; + match_null_name = false; + goto restart; + } + + return found; +} + +static bool check_acpi(struct ssif_info *ssif_info, struct device *dev) +{ +#ifdef CONFIG_ACPI + acpi_handle acpi_handle; + + acpi_handle = ACPI_HANDLE(dev); + if (acpi_handle) { + ssif_info->addr_source = SI_ACPI; + ssif_info->addr_info.acpi_info.acpi_handle = acpi_handle; + return true; + } +#endif + return false; +} + +static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + unsigned char msg[3]; + unsigned char *resp; + struct ssif_info *ssif_info; + int rv = 0; + int len; + int i; + u8 slave_addr = 0; + struct ssif_addr_info *addr_info = NULL; + + + resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL); + if (!resp) + return -ENOMEM; + + ssif_info = kzalloc(sizeof(*ssif_info), GFP_KERNEL); + if (!ssif_info) { + kfree(resp); + return -ENOMEM; + } + + if (!check_acpi(ssif_info, &client->dev)) { + addr_info = ssif_info_find(client->addr, client->adapter->name, + true); + if (!addr_info) { + /* Must have come in through sysfs. */ + ssif_info->addr_source = SI_HOTMOD; + } else { + ssif_info->addr_source = addr_info->addr_src; + ssif_info->ssif_debug = addr_info->debug; + ssif_info->addr_info = addr_info->addr_info; + slave_addr = addr_info->slave_addr; + } + } + + pr_info(PFX "Trying %s-specified SSIF interface at i2c address 0x%x, adapter %s, slave address 0x%x\n", + ipmi_addr_src_to_str(ssif_info->addr_source), + client->addr, client->adapter->name, slave_addr); + + /* + * Do a Get Device ID command, since it comes back with some + * useful info. + */ + msg[0] = IPMI_NETFN_APP_REQUEST << 2; + msg[1] = IPMI_GET_DEVICE_ID_CMD; + rv = do_cmd(client, 2, msg, &len, resp); + if (rv) + goto out; + + rv = ipmi_demangle_device_id(resp, len, &ssif_info->device_id); + if (rv) + goto out; + + ssif_info->client = client; + i2c_set_clientdata(client, ssif_info); + + /* Now check for system interface capabilities */ + msg[0] = IPMI_NETFN_APP_REQUEST << 2; + msg[1] = IPMI_GET_SYSTEM_INTERFACE_CAPABILITIES_CMD; + msg[2] = 0; /* SSIF */ + rv = do_cmd(client, 3, msg, &len, resp); + if (!rv && (len >= 3) && (resp[2] == 0)) { + if (len < 7) { + if (ssif_dbg_probe) + pr_info(PFX "SSIF info too short: %d\n", len); + goto no_support; + } + + /* Got a good SSIF response, handle it. */ + ssif_info->max_xmit_msg_size = resp[5]; + ssif_info->max_recv_msg_size = resp[6]; + ssif_info->multi_support = (resp[4] >> 6) & 0x3; + ssif_info->supports_pec = (resp[4] >> 3) & 0x1; + + /* Sanitize the data */ + switch (ssif_info->multi_support) { + case SSIF_NO_MULTI: + if (ssif_info->max_xmit_msg_size > 32) + ssif_info->max_xmit_msg_size = 32; + if (ssif_info->max_recv_msg_size > 32) + ssif_info->max_recv_msg_size = 32; + break; + + case SSIF_MULTI_2_PART: + if (ssif_info->max_xmit_msg_size > 64) + ssif_info->max_xmit_msg_size = 64; + if (ssif_info->max_recv_msg_size > 62) + ssif_info->max_recv_msg_size = 62; + break; + + case SSIF_MULTI_n_PART: + break; + + default: + /* Data is not sane, just give up. */ + goto no_support; + } + } else { + no_support: + /* Assume no multi-part or PEC support */ + pr_info(PFX "Error fetching SSIF: %d %d %2.2x, your system probably doesn't support this command so using defaults\n", + rv, len, resp[2]); + + ssif_info->max_xmit_msg_size = 32; + ssif_info->max_recv_msg_size = 32; + ssif_info->multi_support = SSIF_NO_MULTI; + ssif_info->supports_pec = 0; + } + + /* Make sure the NMI timeout is cleared. */ + msg[0] = IPMI_NETFN_APP_REQUEST << 2; + msg[1] = IPMI_CLEAR_MSG_FLAGS_CMD; + msg[2] = WDT_PRE_TIMEOUT_INT; + rv = do_cmd(client, 3, msg, &len, resp); + if (rv || (len < 3) || (resp[2] != 0)) + pr_warn(PFX "Unable to clear message flags: %d %d %2.2x\n", + rv, len, resp[2]); + + /* Attempt to enable the event buffer. */ + msg[0] = IPMI_NETFN_APP_REQUEST << 2; + msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD; + rv = do_cmd(client, 2, msg, &len, resp); + if (rv || (len < 4) || (resp[2] != 0)) { + pr_warn(PFX "Error getting global enables: %d %d %2.2x\n", + rv, len, resp[2]); + rv = 0; /* Not fatal */ + goto found; + } + + if (resp[3] & IPMI_BMC_EVT_MSG_BUFF) { + ssif_info->has_event_buffer = true; + /* buffer is already enabled, nothing to do. */ + goto found; + } + + msg[0] = IPMI_NETFN_APP_REQUEST << 2; + msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD; + msg[2] = resp[3] | IPMI_BMC_EVT_MSG_BUFF; + rv = do_cmd(client, 3, msg, &len, resp); + if (rv || (len < 2)) { + pr_warn(PFX "Error getting global enables: %d %d %2.2x\n", + rv, len, resp[2]); + rv = 0; /* Not fatal */ + goto found; + } + + if (resp[2] == 0) + /* A successful return means the event buffer is supported. */ + ssif_info->has_event_buffer = true; + + found: + ssif_info->intf_num = atomic_inc_return(&next_intf); + + if (ssif_dbg_probe) { + pr_info("ssif_probe: i2c_probe found device at i2c address %x\n", + client->addr); + } + + spin_lock_init(&ssif_info->lock); + ssif_info->ssif_state = SSIF_NORMAL; + init_timer(&ssif_info->retry_timer); + ssif_info->retry_timer.data = (unsigned long) ssif_info; + ssif_info->retry_timer.function = retry_timeout; + + for (i = 0; i < SSIF_NUM_STATS; i++) + atomic_set(&ssif_info->stats[i], 0); + + if (ssif_info->supports_pec) + ssif_info->client->flags |= I2C_CLIENT_PEC; + + ssif_info->handlers.owner = THIS_MODULE; + ssif_info->handlers.start_processing = ssif_start_processing; + ssif_info->handlers.get_smi_info = get_smi_info; + ssif_info->handlers.sender = sender; + ssif_info->handlers.request_events = request_events; + ssif_info->handlers.inc_usecount = inc_usecount; + ssif_info->handlers.dec_usecount = dec_usecount; + + { + unsigned int thread_num; + + thread_num = ((ssif_info->client->adapter->nr << 8) | + ssif_info->client->addr); + init_completion(&ssif_info->wake_thread); + ssif_info->thread = kthread_run(ipmi_ssif_thread, ssif_info, + "kssif%4.4x", thread_num); + if (IS_ERR(ssif_info->thread)) { + rv = PTR_ERR(ssif_info->thread); + dev_notice(&ssif_info->client->dev, + "Could not start kernel thread: error %d\n", + rv); + goto out; + } + } + + rv = ipmi_register_smi(&ssif_info->handlers, + ssif_info, + &ssif_info->device_id, + &ssif_info->client->dev, + slave_addr); + if (rv) { + pr_err(PFX "Unable to register device: error %d\n", rv); + goto out; + } + + rv = ipmi_smi_add_proc_entry(ssif_info->intf, "type", + &smi_type_proc_ops, + ssif_info); + if (rv) { + pr_err(PFX "Unable to create proc entry: %d\n", rv); + goto out_err_unreg; + } + + rv = ipmi_smi_add_proc_entry(ssif_info->intf, "ssif_stats", + &smi_stats_proc_ops, + ssif_info); + if (rv) { + pr_err(PFX "Unable to create proc entry: %d\n", rv); + goto out_err_unreg; + } + + out: + if (rv) + kfree(ssif_info); + kfree(resp); + return rv; + + out_err_unreg: + ipmi_unregister_smi(ssif_info->intf); + goto out; +} + +static int ssif_adapter_handler(struct device *adev, void *opaque) +{ + struct ssif_addr_info *addr_info = opaque; + + if (adev->type != &i2c_adapter_type) + return 0; + + i2c_new_device(to_i2c_adapter(adev), &addr_info->binfo); + + if (!addr_info->adapter_name) + return 1; /* Only try the first I2C adapter by default. */ + return 0; +} + +static int new_ssif_client(int addr, char *adapter_name, + int debug, int slave_addr, + enum ipmi_addr_src addr_src) +{ + struct ssif_addr_info *addr_info; + int rv = 0; + + mutex_lock(&ssif_infos_mutex); + if (ssif_info_find(addr, adapter_name, false)) { + rv = -EEXIST; + goto out_unlock; + } + + addr_info = kzalloc(sizeof(*addr_info), GFP_KERNEL); + if (!addr_info) { + rv = -ENOMEM; + goto out_unlock; + } + + if (adapter_name) { + addr_info->adapter_name = kstrdup(adapter_name, GFP_KERNEL); + if (!addr_info->adapter_name) { + kfree(addr_info); + rv = -ENOMEM; + goto out_unlock; + } + } + + strncpy(addr_info->binfo.type, DEVICE_NAME, + sizeof(addr_info->binfo.type)); + addr_info->binfo.addr = addr; + addr_info->binfo.platform_data = addr_info; + addr_info->debug = debug; + addr_info->slave_addr = slave_addr; + addr_info->addr_src = addr_src; + + list_add_tail(&addr_info->link, &ssif_infos); + + if (initialized) + i2c_for_each_dev(addr_info, ssif_adapter_handler); + /* Otherwise address list will get it */ + +out_unlock: + mutex_unlock(&ssif_infos_mutex); + return rv; +} + +static void free_ssif_clients(void) +{ + struct ssif_addr_info *info, *tmp; + + mutex_lock(&ssif_infos_mutex); + list_for_each_entry_safe(info, tmp, &ssif_infos, link) { + list_del(&info->link); + kfree(info->adapter_name); + kfree(info); + } + mutex_unlock(&ssif_infos_mutex); +} + +static unsigned short *ssif_address_list(void) +{ + struct ssif_addr_info *info; + unsigned int count = 0, i; + unsigned short *address_list; + + list_for_each_entry(info, &ssif_infos, link) + count++; + + address_list = kzalloc(sizeof(*address_list) * (count + 1), GFP_KERNEL); + if (!address_list) + return NULL; + + i = 0; + list_for_each_entry(info, &ssif_infos, link) { + unsigned short addr = info->binfo.addr; + int j; + + for (j = 0; j < i; j++) { + if (address_list[j] == addr) + goto skip_addr; + } + address_list[i] = addr; +skip_addr: + i++; + } + address_list[i] = I2C_CLIENT_END; + + return address_list; +} + +#ifdef CONFIG_ACPI +static struct acpi_device_id ssif_acpi_match[] = { + { "IPI0001", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, ssif_acpi_match); + +/* + * Once we get an ACPI failure, we don't try any more, because we go + * through the tables sequentially. Once we don't find a table, there + * are no more. + */ +static int acpi_failure; + +/* + * Defined in the IPMI 2.0 spec. + */ +struct SPMITable { + s8 Signature[4]; + u32 Length; + u8 Revision; + u8 Checksum; + s8 OEMID[6]; + s8 OEMTableID[8]; + s8 OEMRevision[4]; + s8 CreatorID[4]; + s8 CreatorRevision[4]; + u8 InterfaceType; + u8 IPMIlegacy; + s16 SpecificationRevision; + + /* + * Bit 0 - SCI interrupt supported + * Bit 1 - I/O APIC/SAPIC + */ + u8 InterruptType; + + /* + * If bit 0 of InterruptType is set, then this is the SCI + * interrupt in the GPEx_STS register. + */ + u8 GPE; + + s16 Reserved; + + /* + * If bit 1 of InterruptType is set, then this is the I/O + * APIC/SAPIC interrupt. + */ + u32 GlobalSystemInterrupt; + + /* The actual register address. */ + struct acpi_generic_address addr; + + u8 UID[4]; + + s8 spmi_id[1]; /* A '\0' terminated array starts here. */ +}; + +static int try_init_spmi(struct SPMITable *spmi) +{ + unsigned short myaddr; + + if (num_addrs >= MAX_SSIF_BMCS) + return -1; + + if (spmi->IPMIlegacy != 1) { + pr_warn("IPMI: Bad SPMI legacy: %d\n", spmi->IPMIlegacy); + return -ENODEV; + } + + if (spmi->InterfaceType != 4) + return -ENODEV; + + if (spmi->addr.space_id != ACPI_ADR_SPACE_SMBUS) { + pr_warn(PFX "Invalid ACPI SSIF I/O Address type: %d\n", + spmi->addr.space_id); + return -EIO; + } + + myaddr = spmi->addr.address >> 1; + + return new_ssif_client(myaddr, NULL, 0, 0, SI_SPMI); +} + +static void spmi_find_bmc(void) +{ + acpi_status status; + struct SPMITable *spmi; + int i; + + if (acpi_disabled) + return; + + if (acpi_failure) + return; + + for (i = 0; ; i++) { + status = acpi_get_table(ACPI_SIG_SPMI, i+1, + (struct acpi_table_header **)&spmi); + if (status != AE_OK) + return; + + try_init_spmi(spmi); + } +} +#else +static void spmi_find_bmc(void) { } +#endif + +#ifdef CONFIG_DMI +static int decode_dmi(const struct dmi_device *dmi_dev) +{ + struct dmi_header *dm = dmi_dev->device_data; + u8 *data = (u8 *) dm; + u8 len = dm->length; + unsigned short myaddr; + int slave_addr; + + if (num_addrs >= MAX_SSIF_BMCS) + return -1; + + if (len < 9) + return -1; + + if (data[0x04] != 4) /* Not SSIF */ + return -1; + + if ((data[8] >> 1) == 0) { + /* + * Some broken systems put the I2C address in + * the slave address field. We try to + * accommodate them here. + */ + myaddr = data[6] >> 1; + slave_addr = 0; + } else { + myaddr = data[8] >> 1; + slave_addr = data[6]; + } + + return new_ssif_client(myaddr, NULL, 0, 0, SI_SMBIOS); +} + +static void dmi_iterator(void) +{ + const struct dmi_device *dev = NULL; + + while ((dev = dmi_find_device(DMI_DEV_TYPE_IPMI, NULL, dev))) + decode_dmi(dev); +} +#else +static void dmi_iterator(void) { } +#endif + +static const struct i2c_device_id ssif_id[] = { + { DEVICE_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ssif_id); + +static struct i2c_driver ssif_i2c_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .owner = THIS_MODULE, + .name = DEVICE_NAME + }, + .probe = ssif_probe, + .remove = ssif_remove, + .id_table = ssif_id, + .detect = ssif_detect +}; + +static int init_ipmi_ssif(void) +{ + int i; + int rv; + + if (initialized) + return 0; + + pr_info("IPMI SSIF Interface driver\n"); + + /* build list for i2c from addr list */ + for (i = 0; i < num_addrs; i++) { + rv = new_ssif_client(addr[i], adapter_name[i], + dbg[i], slave_addrs[i], + SI_HARDCODED); + if (!rv) + pr_err(PFX + "Couldn't add hardcoded device at addr 0x%x\n", + addr[i]); + } + + if (ssif_tryacpi) + ssif_i2c_driver.driver.acpi_match_table = + ACPI_PTR(ssif_acpi_match); + if (ssif_trydmi) + dmi_iterator(); + if (ssif_tryacpi) + spmi_find_bmc(); + + ssif_i2c_driver.address_list = ssif_address_list(); + + rv = i2c_add_driver(&ssif_i2c_driver); + if (!rv) + initialized = true; + + return rv; +} +module_init(init_ipmi_ssif); + +static void cleanup_ipmi_ssif(void) +{ + if (!initialized) + return; + + initialized = false; + + i2c_del_driver(&ssif_i2c_driver); + + free_ssif_clients(); +} +module_exit(cleanup_ipmi_ssif); + +MODULE_AUTHOR("Todd C Davis , Corey Minyard "); +MODULE_DESCRIPTION("IPMI driver for management controllers on a SMBus"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-59-g8ed1b From 027bc8b08242c59e19356b4b2c189f2d849ab660 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Tue, 16 Sep 2014 13:50:01 -0700 Subject: pstore-ram: Allow optional mapping with pgprot_noncached On some ARMs the memory can be mapped pgprot_noncached() and still be working for atomic operations. As pointed out by Colin Cross , in some cases you do want to use pgprot_noncached() if the SoC supports it to see a debug printk just before a write hanging the system. On ARMs, the atomic operations on strongly ordered memory are implementation defined. So let's provide an optional kernel parameter for configuring pgprot_noncached(), and use pgprot_writecombine() by default. Cc: Arnd Bergmann Cc: Rob Herring Cc: Randy Dunlap Cc: Anton Vorontsov Cc: Colin Cross Cc: Olof Johansson Cc: Russell King Cc: stable@vger.kernel.org Acked-by: Kees Cook Signed-off-by: Tony Lindgren Signed-off-by: Tony Luck --- Documentation/ramoops.txt | 13 +++++++++++-- fs/pstore/ram.c | 13 +++++++++++-- fs/pstore/ram_core.c | 31 ++++++++++++++++++++++--------- include/linux/pstore_ram.h | 4 +++- 4 files changed, 47 insertions(+), 14 deletions(-) (limited to 'Documentation') diff --git a/Documentation/ramoops.txt b/Documentation/ramoops.txt index 69b3cac4749d..5d8675615e59 100644 --- a/Documentation/ramoops.txt +++ b/Documentation/ramoops.txt @@ -14,11 +14,19 @@ survive after a restart. 1. Ramoops concepts -Ramoops uses a predefined memory area to store the dump. The start and size of -the memory area are set using two variables: +Ramoops uses a predefined memory area to store the dump. The start and size +and type of the memory area are set using three variables: * "mem_address" for the start * "mem_size" for the size. The memory size will be rounded down to a power of two. + * "mem_type" to specifiy if the memory type (default is pgprot_writecombine). + +Typically the default value of mem_type=0 should be used as that sets the pstore +mapping to pgprot_writecombine. Setting mem_type=1 attempts to use +pgprot_noncached, which only works on some platforms. This is because pstore +depends on atomic operations. At least on ARM, pgprot_noncached causes the +memory to be mapped strongly ordered, and atomic operations on strongly ordered +memory are implementation defined, and won't work on many ARMs such as omaps. The memory area is divided into "record_size" chunks (also rounded down to power of two) and each oops/panic writes a "record_size" chunk of @@ -55,6 +63,7 @@ Setting the ramoops parameters can be done in 2 different manners: static struct ramoops_platform_data ramoops_data = { .mem_size = <...>, .mem_address = <...>, + .mem_type = <...>, .record_size = <...>, .dump_oops = <...>, .ecc = <...>, diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index ec881b312700..2f389ce5023c 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -61,6 +61,11 @@ module_param(mem_size, ulong, 0400); MODULE_PARM_DESC(mem_size, "size of reserved RAM used to store oops/panic logs"); +static unsigned int mem_type; +module_param(mem_type, uint, 0600); +MODULE_PARM_DESC(mem_type, + "set to 1 to try to use unbuffered memory (default 0)"); + static int dump_oops = 1; module_param(dump_oops, int, 0600); MODULE_PARM_DESC(dump_oops, @@ -79,6 +84,7 @@ struct ramoops_context { struct persistent_ram_zone *fprz; phys_addr_t phys_addr; unsigned long size; + unsigned int memtype; size_t record_size; size_t console_size; size_t ftrace_size; @@ -366,7 +372,8 @@ static int ramoops_init_przs(struct device *dev, struct ramoops_context *cxt, size_t sz = cxt->record_size; cxt->przs[i] = persistent_ram_new(*paddr, sz, 0, - &cxt->ecc_info); + &cxt->ecc_info, + cxt->memtype); if (IS_ERR(cxt->przs[i])) { err = PTR_ERR(cxt->przs[i]); dev_err(dev, "failed to request mem region (0x%zx@0x%llx): %d\n", @@ -396,7 +403,7 @@ static int ramoops_init_prz(struct device *dev, struct ramoops_context *cxt, return -ENOMEM; } - *prz = persistent_ram_new(*paddr, sz, sig, &cxt->ecc_info); + *prz = persistent_ram_new(*paddr, sz, sig, &cxt->ecc_info, cxt->memtype); if (IS_ERR(*prz)) { int err = PTR_ERR(*prz); @@ -443,6 +450,7 @@ static int ramoops_probe(struct platform_device *pdev) cxt->size = pdata->mem_size; cxt->phys_addr = pdata->mem_address; + cxt->memtype = pdata->mem_type; cxt->record_size = pdata->record_size; cxt->console_size = pdata->console_size; cxt->ftrace_size = pdata->ftrace_size; @@ -572,6 +580,7 @@ static void ramoops_register_dummy(void) dummy_data->mem_size = mem_size; dummy_data->mem_address = mem_address; + dummy_data->mem_type = 0; dummy_data->record_size = record_size; dummy_data->console_size = ramoops_console_size; dummy_data->ftrace_size = ramoops_ftrace_size; diff --git a/fs/pstore/ram_core.c b/fs/pstore/ram_core.c index 24f94b0f2270..76c3f80efdfa 100644 --- a/fs/pstore/ram_core.c +++ b/fs/pstore/ram_core.c @@ -380,7 +380,8 @@ void persistent_ram_zap(struct persistent_ram_zone *prz) persistent_ram_update_header_ecc(prz); } -static void *persistent_ram_vmap(phys_addr_t start, size_t size) +static void *persistent_ram_vmap(phys_addr_t start, size_t size, + unsigned int memtype) { struct page **pages; phys_addr_t page_start; @@ -392,7 +393,10 @@ static void *persistent_ram_vmap(phys_addr_t start, size_t size) page_start = start - offset_in_page(start); page_count = DIV_ROUND_UP(size + offset_in_page(start), PAGE_SIZE); - prot = pgprot_writecombine(PAGE_KERNEL); + if (memtype) + prot = pgprot_noncached(PAGE_KERNEL); + else + prot = pgprot_writecombine(PAGE_KERNEL); pages = kmalloc_array(page_count, sizeof(struct page *), GFP_KERNEL); if (!pages) { @@ -411,8 +415,11 @@ static void *persistent_ram_vmap(phys_addr_t start, size_t size) return vaddr; } -static void *persistent_ram_iomap(phys_addr_t start, size_t size) +static void *persistent_ram_iomap(phys_addr_t start, size_t size, + unsigned int memtype) { + void *va; + if (!request_mem_region(start, size, "persistent_ram")) { pr_err("request mem region (0x%llx@0x%llx) failed\n", (unsigned long long)size, (unsigned long long)start); @@ -422,19 +429,24 @@ static void *persistent_ram_iomap(phys_addr_t start, size_t size) buffer_start_add = buffer_start_add_locked; buffer_size_add = buffer_size_add_locked; - return ioremap_wc(start, size); + if (memtype) + va = ioremap(start, size); + else + va = ioremap_wc(start, size); + + return va; } static int persistent_ram_buffer_map(phys_addr_t start, phys_addr_t size, - struct persistent_ram_zone *prz) + struct persistent_ram_zone *prz, int memtype) { prz->paddr = start; prz->size = size; if (pfn_valid(start >> PAGE_SHIFT)) - prz->vaddr = persistent_ram_vmap(start, size); + prz->vaddr = persistent_ram_vmap(start, size, memtype); else - prz->vaddr = persistent_ram_iomap(start, size); + prz->vaddr = persistent_ram_iomap(start, size, memtype); if (!prz->vaddr) { pr_err("%s: Failed to map 0x%llx pages at 0x%llx\n", __func__, @@ -500,7 +512,8 @@ void persistent_ram_free(struct persistent_ram_zone *prz) } struct persistent_ram_zone *persistent_ram_new(phys_addr_t start, size_t size, - u32 sig, struct persistent_ram_ecc_info *ecc_info) + u32 sig, struct persistent_ram_ecc_info *ecc_info, + unsigned int memtype) { struct persistent_ram_zone *prz; int ret = -ENOMEM; @@ -511,7 +524,7 @@ struct persistent_ram_zone *persistent_ram_new(phys_addr_t start, size_t size, goto err; } - ret = persistent_ram_buffer_map(start, size, prz); + ret = persistent_ram_buffer_map(start, size, prz, memtype); if (ret) goto err; diff --git a/include/linux/pstore_ram.h b/include/linux/pstore_ram.h index 9974975d40db..4af3fdc85b01 100644 --- a/include/linux/pstore_ram.h +++ b/include/linux/pstore_ram.h @@ -53,7 +53,8 @@ struct persistent_ram_zone { }; struct persistent_ram_zone *persistent_ram_new(phys_addr_t start, size_t size, - u32 sig, struct persistent_ram_ecc_info *ecc_info); + u32 sig, struct persistent_ram_ecc_info *ecc_info, + unsigned int memtype); void persistent_ram_free(struct persistent_ram_zone *prz); void persistent_ram_zap(struct persistent_ram_zone *prz); @@ -76,6 +77,7 @@ ssize_t persistent_ram_ecc_string(struct persistent_ram_zone *prz, struct ramoops_platform_data { unsigned long mem_size; unsigned long mem_address; + unsigned int mem_type; unsigned long record_size; unsigned long console_size; unsigned long ftrace_size; -- cgit v1.2.3-59-g8ed1b From 1077fa36f23e259858caf6f269a47393a5aff523 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 11 Dec 2014 15:02:06 -0800 Subject: arch: Add lightweight memory barriers dma_rmb() and dma_wmb() There are a number of situations where the mandatory barriers rmb() and wmb() are used to order memory/memory operations in the device drivers and those barriers are much heavier than they actually need to be. For example in the case of PowerPC wmb() calls the heavy-weight sync instruction when for coherent memory operations all that is really needed is an lsync or eieio instruction. This commit adds a coherent only version of the mandatory memory barriers rmb() and wmb(). In most cases this should result in the barrier being the same as the SMP barriers for the SMP case, however in some cases we use a barrier that is somewhere in between rmb() and smp_rmb(). For example on ARM the rmb barriers break down as follows: Barrier Call Explanation --------- -------- ---------------------------------- rmb() dsb() Data synchronization barrier - system dma_rmb() dmb(osh) data memory barrier - outer sharable smp_rmb() dmb(ish) data memory barrier - inner sharable These new barriers are not as safe as the standard rmb() and wmb(). Specifically they do not guarantee ordering between coherent and incoherent memories. The primary use case for these would be to enforce ordering of reads and writes when accessing coherent memory that is shared between the CPU and a device. It may also be noted that there is no dma_mb(). Most architectures don't provide a good mechanism for performing a coherent only full barrier without resorting to the same mechanism used in mb(). As such there isn't much to be gained in trying to define such a function. Cc: Frederic Weisbecker Cc: Mathieu Desnoyers Cc: Michael Ellerman Cc: Michael Neuling Cc: Russell King Cc: Geert Uytterhoeven Cc: Heiko Carstens Cc: Linus Torvalds Cc: Martin Schwidefsky Cc: Tony Luck Cc: Oleg Nesterov Cc: "Paul E. McKenney" Cc: Peter Zijlstra Cc: Ingo Molnar Cc: David Miller Acked-by: Benjamin Herrenschmidt Acked-by: Will Deacon Signed-off-by: Alexander Duyck Signed-off-by: David S. Miller --- Documentation/memory-barriers.txt | 42 +++++++++++++++++++++++++++++++++++++ arch/arm/include/asm/barrier.h | 4 ++++ arch/arm64/include/asm/barrier.h | 3 +++ arch/ia64/include/asm/barrier.h | 3 +++ arch/metag/include/asm/barrier.h | 14 ++++++------- arch/mips/include/asm/barrier.h | 9 ++++---- arch/powerpc/include/asm/barrier.h | 13 +++++++----- arch/s390/include/asm/barrier.h | 2 ++ arch/sparc/include/asm/barrier_64.h | 3 +++ arch/x86/include/asm/barrier.h | 11 ++++++---- arch/x86/um/asm/barrier.h | 13 ++++++------ include/asm-generic/barrier.h | 8 +++++++ 12 files changed, 99 insertions(+), 26 deletions(-) (limited to 'Documentation') diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt index 7ee2ae6d5451..70a09f8a0383 100644 --- a/Documentation/memory-barriers.txt +++ b/Documentation/memory-barriers.txt @@ -1633,6 +1633,48 @@ There are some more advanced barrier functions: operations" subsection for information on where to use these. + (*) dma_wmb(); + (*) dma_rmb(); + + These are for use with consistent memory to guarantee the ordering + of writes or reads of shared memory accessible to both the CPU and a + DMA capable device. + + For example, consider a device driver that shares memory with a device + and uses a descriptor status value to indicate if the descriptor belongs + to the device or the CPU, and a doorbell to notify it when new + descriptors are available: + + if (desc->status != DEVICE_OWN) { + /* do not read data until we own descriptor */ + dma_rmb(); + + /* read/modify data */ + read_data = desc->data; + desc->data = write_data; + + /* flush modifications before status update */ + dma_wmb(); + + /* assign ownership */ + desc->status = DEVICE_OWN; + + /* force memory to sync before notifying device via MMIO */ + wmb(); + + /* notify device of new descriptors */ + writel(DESC_NOTIFY, doorbell); + } + + The dma_rmb() allows us guarantee the device has released ownership + before we read the data from the descriptor, and he 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 + the cache incoherent MMIO region. + + See Documentation/DMA-API.txt for more information on consistent memory. + MMIO WRITE BARRIER ------------------ diff --git a/arch/arm/include/asm/barrier.h b/arch/arm/include/asm/barrier.h index c6a3e73a6e24..d2f81e6b8c1c 100644 --- a/arch/arm/include/asm/barrier.h +++ b/arch/arm/include/asm/barrier.h @@ -43,10 +43,14 @@ #define mb() do { dsb(); outer_sync(); } while (0) #define rmb() dsb() #define wmb() do { dsb(st); outer_sync(); } while (0) +#define dma_rmb() dmb(osh) +#define dma_wmb() dmb(oshst) #else #define mb() barrier() #define rmb() barrier() #define wmb() barrier() +#define dma_rmb() barrier() +#define dma_wmb() barrier() #endif #ifndef CONFIG_SMP diff --git a/arch/arm64/include/asm/barrier.h b/arch/arm64/include/asm/barrier.h index 6389d60574d9..a5abb0062d6e 100644 --- a/arch/arm64/include/asm/barrier.h +++ b/arch/arm64/include/asm/barrier.h @@ -32,6 +32,9 @@ #define rmb() dsb(ld) #define wmb() dsb(st) +#define dma_rmb() dmb(oshld) +#define dma_wmb() dmb(oshst) + #ifndef CONFIG_SMP #define smp_mb() barrier() #define smp_rmb() barrier() diff --git a/arch/ia64/include/asm/barrier.h b/arch/ia64/include/asm/barrier.h index e8fffb03963c..f6769eb2bbf9 100644 --- a/arch/ia64/include/asm/barrier.h +++ b/arch/ia64/include/asm/barrier.h @@ -39,6 +39,9 @@ #define rmb() mb() #define wmb() mb() +#define dma_rmb() mb() +#define dma_wmb() mb() + #ifdef CONFIG_SMP # define smp_mb() mb() #else diff --git a/arch/metag/include/asm/barrier.h b/arch/metag/include/asm/barrier.h index 6d8b8c9b7c25..d703d8e26a65 100644 --- a/arch/metag/include/asm/barrier.h +++ b/arch/metag/include/asm/barrier.h @@ -4,8 +4,6 @@ #include #define nop() asm volatile ("NOP") -#define mb() wmb() -#define rmb() barrier() #ifdef CONFIG_METAG_META21 @@ -41,11 +39,13 @@ static inline void wr_fence(void) #endif /* !CONFIG_METAG_META21 */ -static inline void wmb(void) -{ - /* flush writes through the write combiner */ - wr_fence(); -} +/* flush writes through the write combiner */ +#define mb() wr_fence() +#define rmb() barrier() +#define wmb() mb() + +#define dma_rmb() rmb() +#define dma_wmb() wmb() #ifndef CONFIG_SMP #define fence() do { } while (0) diff --git a/arch/mips/include/asm/barrier.h b/arch/mips/include/asm/barrier.h index 3d69aa829a76..2b8bbbcb9be0 100644 --- a/arch/mips/include/asm/barrier.h +++ b/arch/mips/include/asm/barrier.h @@ -75,20 +75,21 @@ #include -#define wmb() fast_wmb() -#define rmb() fast_rmb() #define mb() wbflush() #define iob() wbflush() #else /* !CONFIG_CPU_HAS_WB */ -#define wmb() fast_wmb() -#define rmb() fast_rmb() #define mb() fast_mb() #define iob() fast_iob() #endif /* !CONFIG_CPU_HAS_WB */ +#define wmb() fast_wmb() +#define rmb() fast_rmb() +#define dma_wmb() fast_wmb() +#define dma_rmb() fast_rmb() + #if defined(CONFIG_WEAK_ORDERING) && defined(CONFIG_SMP) # ifdef CONFIG_CPU_CAVIUM_OCTEON # define smp_mb() __sync() diff --git a/arch/powerpc/include/asm/barrier.h b/arch/powerpc/include/asm/barrier.h index cb6d66c6e3e1..a3bf5be111ff 100644 --- a/arch/powerpc/include/asm/barrier.h +++ b/arch/powerpc/include/asm/barrier.h @@ -36,8 +36,6 @@ #define set_mb(var, value) do { var = value; mb(); } while (0) -#ifdef CONFIG_SMP - #ifdef __SUBARCH_HAS_LWSYNC # define SMPWMB LWSYNC #else @@ -45,12 +43,17 @@ #endif #define __lwsync() __asm__ __volatile__ (stringify_in_c(LWSYNC) : : :"memory") +#define dma_rmb() __lwsync() +#define dma_wmb() __asm__ __volatile__ (stringify_in_c(SMPWMB) : : :"memory") + +#ifdef CONFIG_SMP +#define smp_lwsync() __lwsync() #define smp_mb() mb() #define smp_rmb() __lwsync() #define smp_wmb() __asm__ __volatile__ (stringify_in_c(SMPWMB) : : :"memory") #else -#define __lwsync() barrier() +#define smp_lwsync() barrier() #define smp_mb() barrier() #define smp_rmb() barrier() @@ -72,7 +75,7 @@ #define smp_store_release(p, v) \ do { \ compiletime_assert_atomic_type(*p); \ - __lwsync(); \ + smp_lwsync(); \ ACCESS_ONCE(*p) = (v); \ } while (0) @@ -80,7 +83,7 @@ do { \ ({ \ typeof(*p) ___p1 = ACCESS_ONCE(*p); \ compiletime_assert_atomic_type(*p); \ - __lwsync(); \ + smp_lwsync(); \ ___p1; \ }) diff --git a/arch/s390/include/asm/barrier.h b/arch/s390/include/asm/barrier.h index 33d191d295e4..8d724718ec21 100644 --- a/arch/s390/include/asm/barrier.h +++ b/arch/s390/include/asm/barrier.h @@ -24,6 +24,8 @@ #define rmb() mb() #define wmb() mb() +#define dma_rmb() rmb() +#define dma_wmb() wmb() #define smp_mb() mb() #define smp_rmb() rmb() #define smp_wmb() wmb() diff --git a/arch/sparc/include/asm/barrier_64.h b/arch/sparc/include/asm/barrier_64.h index 6c974c0977ad..76648941fea7 100644 --- a/arch/sparc/include/asm/barrier_64.h +++ b/arch/sparc/include/asm/barrier_64.h @@ -37,6 +37,9 @@ do { __asm__ __volatile__("ba,pt %%xcc, 1f\n\t" \ #define rmb() __asm__ __volatile__("":::"memory") #define wmb() __asm__ __volatile__("":::"memory") +#define dma_rmb() rmb() +#define dma_wmb() wmb() + #define set_mb(__var, __value) \ do { __var = __value; membar_safe("#StoreLoad"); } while(0) diff --git a/arch/x86/include/asm/barrier.h b/arch/x86/include/asm/barrier.h index 5238000285c1..2ab1eb33106e 100644 --- a/arch/x86/include/asm/barrier.h +++ b/arch/x86/include/asm/barrier.h @@ -24,13 +24,16 @@ #define wmb() asm volatile("sfence" ::: "memory") #endif -#ifdef CONFIG_SMP -#define smp_mb() mb() #ifdef CONFIG_X86_PPRO_FENCE -# define smp_rmb() rmb() +#define dma_rmb() rmb() #else -# define smp_rmb() barrier() +#define dma_rmb() barrier() #endif +#define dma_wmb() barrier() + +#ifdef CONFIG_SMP +#define smp_mb() mb() +#define smp_rmb() dma_rmb() #define smp_wmb() barrier() #define set_mb(var, value) do { (void)xchg(&var, value); } while (0) #else /* !SMP */ diff --git a/arch/x86/um/asm/barrier.h b/arch/x86/um/asm/barrier.h index d6511d954e2b..2d7d9a1f5b53 100644 --- a/arch/x86/um/asm/barrier.h +++ b/arch/x86/um/asm/barrier.h @@ -29,17 +29,18 @@ #endif /* CONFIG_X86_32 */ -#ifdef CONFIG_SMP - -#define smp_mb() mb() #ifdef CONFIG_X86_PPRO_FENCE -#define smp_rmb() rmb() +#define dma_rmb() rmb() #else /* CONFIG_X86_PPRO_FENCE */ -#define smp_rmb() barrier() +#define dma_rmb() barrier() #endif /* CONFIG_X86_PPRO_FENCE */ +#define dma_wmb() barrier() -#define smp_wmb() barrier() +#ifdef CONFIG_SMP +#define smp_mb() mb() +#define smp_rmb() dma_rmb() +#define smp_wmb() barrier() #define set_mb(var, value) do { (void)xchg(&var, value); } while (0) #else /* CONFIG_SMP */ diff --git a/include/asm-generic/barrier.h b/include/asm-generic/barrier.h index 1402fa855388..f5c40b0fadc2 100644 --- a/include/asm-generic/barrier.h +++ b/include/asm-generic/barrier.h @@ -42,6 +42,14 @@ #define wmb() mb() #endif +#ifndef dma_rmb +#define dma_rmb() rmb() +#endif + +#ifndef dma_wmb +#define dma_wmb() wmb() +#endif + #ifndef read_barrier_depends #define read_barrier_depends() do { } while (0) #endif -- cgit v1.2.3-59-g8ed1b From 76deaff8085304e9f6a4ce165b61ff467bbcd888 Mon Sep 17 00:00:00 2001 From: Yoshihiro Kaneko Date: Sun, 19 Oct 2014 23:51:29 -0300 Subject: [media] rcar_vin: Add DT support for r8a7793 and r8a7794 SoCs Based on platform device work by Matsuoka-san. Signed-off-by: Yoshihiro Kaneko Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- Documentation/devicetree/bindings/media/rcar_vin.txt | 2 ++ drivers/media/platform/soc_camera/rcar_vin.c | 2 ++ 2 files changed, 4 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/media/rcar_vin.txt b/Documentation/devicetree/bindings/media/rcar_vin.txt index ba61782c2af9..9dafe6b06cd2 100644 --- a/Documentation/devicetree/bindings/media/rcar_vin.txt +++ b/Documentation/devicetree/bindings/media/rcar_vin.txt @@ -6,6 +6,8 @@ family of devices. The current blocks are always slaves and suppot one input channel which can be either RGB, YUYV or BT656. - compatible: Must be one of the following + - "renesas,vin-r8a7794" for the R8A7794 device + - "renesas,vin-r8a7793" for the R8A7793 device - "renesas,vin-r8a7791" for the R8A7791 device - "renesas,vin-r8a7790" for the R8A7790 device - "renesas,vin-r8a7779" for the R8A7779 device diff --git a/drivers/media/platform/soc_camera/rcar_vin.c b/drivers/media/platform/soc_camera/rcar_vin.c index 0891679ab835..c60560a4445a 100644 --- a/drivers/media/platform/soc_camera/rcar_vin.c +++ b/drivers/media/platform/soc_camera/rcar_vin.c @@ -1403,6 +1403,8 @@ static struct soc_camera_host_ops rcar_vin_host_ops = { #ifdef CONFIG_OF static struct of_device_id rcar_vin_of_table[] = { + { .compatible = "renesas,vin-r8a7794", .data = (void *)RCAR_GEN2 }, + { .compatible = "renesas,vin-r8a7793", .data = (void *)RCAR_GEN2 }, { .compatible = "renesas,vin-r8a7791", .data = (void *)RCAR_GEN2 }, { .compatible = "renesas,vin-r8a7790", .data = (void *)RCAR_GEN2 }, { .compatible = "renesas,vin-r8a7779", .data = (void *)RCAR_H1 }, -- cgit v1.2.3-59-g8ed1b From 3ad8b3de526a76fbe9466b366059e4958957b88f Mon Sep 17 00:00:00 2001 From: Christoffer Dall Date: Thu, 16 Oct 2014 16:14:43 +0200 Subject: arm/arm64: KVM: Correct KVM_ARM_VCPU_INIT power off option The implementation of KVM_ARM_VCPU_INIT is currently not doing what userspace expects, namely making sure that a vcpu which may have been turned off using PSCI is returned to its initial state, which would be powered on if userspace does not set the KVM_ARM_VCPU_POWER_OFF flag. Implement the expected functionality and clarify the ABI. Acked-by: Marc Zyngier Signed-off-by: Christoffer Dall --- Documentation/virtual/kvm/api.txt | 3 ++- arch/arm/kvm/arm.c | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 7610eaa4d491..bb82a906e51e 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -2455,7 +2455,8 @@ should be created before this ioctl is invoked. Possible features: - KVM_ARM_VCPU_POWER_OFF: Starts the CPU in a power-off state. - Depends on KVM_CAP_ARM_PSCI. + Depends on KVM_CAP_ARM_PSCI. If not set, the CPU will be powered on + and execute guest code when KVM_RUN is called. - KVM_ARM_VCPU_EL1_32BIT: Starts the CPU in a 32bit mode. Depends on KVM_CAP_ARM_EL1_32BIT (arm64 only). - KVM_ARM_VCPU_PSCI_0_2: Emulate PSCI v0.2 for the CPU. diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index b160beadc956..edc196412abe 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -663,6 +663,8 @@ static int kvm_arch_vcpu_ioctl_vcpu_init(struct kvm_vcpu *vcpu, */ if (test_bit(KVM_ARM_VCPU_POWER_OFF, vcpu->arch.features)) vcpu->arch.pause = true; + else + vcpu->arch.pause = false; return 0; } -- cgit v1.2.3-59-g8ed1b From f7fa034dc8559c7d7326bfc8bd1a26175abd931a Mon Sep 17 00:00:00 2001 From: Christoffer Dall Date: Thu, 16 Oct 2014 16:40:53 +0200 Subject: arm/arm64: KVM: Clarify KVM_ARM_VCPU_INIT ABI It is not clear that this ioctl can be called multiple times for a given vcpu. Userspace already does this, so clarify the ABI. Also specify that userspace is expected to always make secondary and subsequent calls to the ioctl with the same parameters for the VCPU as the initial call (which userspace also already does). Add code to check that userspace doesn't violate that ABI in the future, and move the kvm_vcpu_set_target() function which is currently duplicated between the 32-bit and 64-bit versions in guest.c to a common static function in arm.c, shared between both architectures. Acked-by: Marc Zyngier Signed-off-by: Christoffer Dall --- Documentation/virtual/kvm/api.txt | 5 +++++ arch/arm/include/asm/kvm_host.h | 2 -- arch/arm/kvm/arm.c | 43 +++++++++++++++++++++++++++++++++++++++ arch/arm/kvm/guest.c | 25 ----------------------- arch/arm64/include/asm/kvm_host.h | 2 -- arch/arm64/kvm/guest.c | 25 ----------------------- 6 files changed, 48 insertions(+), 54 deletions(-) (limited to 'Documentation') diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index bb82a906e51e..81f1b974c06a 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -2453,6 +2453,11 @@ return ENOEXEC for that vcpu. Note that because some registers reflect machine topology, all vcpus should be created before this ioctl is invoked. +Userspace can call this function multiple times for a given vcpu, including +after the vcpu has been run. This will reset the vcpu to its initial +state. All calls to this function after the initial call must use the same +target and same set of feature flags, otherwise EINVAL will be returned. + Possible features: - KVM_ARM_VCPU_POWER_OFF: Starts the CPU in a power-off state. Depends on KVM_CAP_ARM_PSCI. If not set, the CPU will be powered on diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h index 53036e21756b..254e0650e48b 100644 --- a/arch/arm/include/asm/kvm_host.h +++ b/arch/arm/include/asm/kvm_host.h @@ -150,8 +150,6 @@ struct kvm_vcpu_stat { u32 halt_wakeup; }; -int kvm_vcpu_set_target(struct kvm_vcpu *vcpu, - const struct kvm_vcpu_init *init); int kvm_vcpu_preferred_target(struct kvm_vcpu_init *init); unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu); int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices); diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index 24c9ca4076b2..4043769583e7 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -263,6 +263,7 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) { /* Force users to call KVM_ARM_VCPU_INIT */ vcpu->arch.target = -1; + bitmap_zero(vcpu->arch.features, KVM_VCPU_MAX_FEATURES); /* Set up the timer */ kvm_timer_vcpu_init(vcpu); @@ -649,6 +650,48 @@ int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_level, return -EINVAL; } +static int kvm_vcpu_set_target(struct kvm_vcpu *vcpu, + const struct kvm_vcpu_init *init) +{ + unsigned int i; + int phys_target = kvm_target_cpu(); + + if (init->target != phys_target) + return -EINVAL; + + /* + * Secondary and subsequent calls to KVM_ARM_VCPU_INIT must + * use the same target. + */ + if (vcpu->arch.target != -1 && vcpu->arch.target != init->target) + return -EINVAL; + + /* -ENOENT for unknown features, -EINVAL for invalid combinations. */ + for (i = 0; i < sizeof(init->features) * 8; i++) { + bool set = (init->features[i / 32] & (1 << (i % 32))); + + if (set && i >= KVM_VCPU_MAX_FEATURES) + return -ENOENT; + + /* + * Secondary and subsequent calls to KVM_ARM_VCPU_INIT must + * use the same feature set. + */ + if (vcpu->arch.target != -1 && i < KVM_VCPU_MAX_FEATURES && + test_bit(i, vcpu->arch.features) != set) + return -EINVAL; + + if (set) + set_bit(i, vcpu->arch.features); + } + + vcpu->arch.target = phys_target; + + /* Now we know what it is, we can reset it. */ + return kvm_reset_vcpu(vcpu); +} + + static int kvm_arch_vcpu_ioctl_vcpu_init(struct kvm_vcpu *vcpu, struct kvm_vcpu_init *init) { diff --git a/arch/arm/kvm/guest.c b/arch/arm/kvm/guest.c index 8c97208b9b97..384bab67c462 100644 --- a/arch/arm/kvm/guest.c +++ b/arch/arm/kvm/guest.c @@ -273,31 +273,6 @@ int __attribute_const__ kvm_target_cpu(void) } } -int kvm_vcpu_set_target(struct kvm_vcpu *vcpu, - const struct kvm_vcpu_init *init) -{ - unsigned int i; - - /* We can only cope with guest==host and only on A15/A7 (for now). */ - if (init->target != kvm_target_cpu()) - return -EINVAL; - - vcpu->arch.target = init->target; - bitmap_zero(vcpu->arch.features, KVM_VCPU_MAX_FEATURES); - - /* -ENOENT for unknown features, -EINVAL for invalid combinations. */ - for (i = 0; i < sizeof(init->features) * 8; i++) { - if (test_bit(i, (void *)init->features)) { - if (i >= KVM_VCPU_MAX_FEATURES) - return -ENOENT; - set_bit(i, vcpu->arch.features); - } - } - - /* Now we know what it is, we can reset it. */ - return kvm_reset_vcpu(vcpu); -} - int kvm_vcpu_preferred_target(struct kvm_vcpu_init *init) { int target = kvm_target_cpu(); diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 2012c4ba8d67..65c615294589 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -165,8 +165,6 @@ struct kvm_vcpu_stat { u32 halt_wakeup; }; -int kvm_vcpu_set_target(struct kvm_vcpu *vcpu, - const struct kvm_vcpu_init *init); int kvm_vcpu_preferred_target(struct kvm_vcpu_init *init); unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu); int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices); diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c index 84d5959ff874..9535bd555d1d 100644 --- a/arch/arm64/kvm/guest.c +++ b/arch/arm64/kvm/guest.c @@ -296,31 +296,6 @@ int __attribute_const__ kvm_target_cpu(void) return -EINVAL; } -int kvm_vcpu_set_target(struct kvm_vcpu *vcpu, - const struct kvm_vcpu_init *init) -{ - unsigned int i; - int phys_target = kvm_target_cpu(); - - if (init->target != phys_target) - return -EINVAL; - - vcpu->arch.target = phys_target; - bitmap_zero(vcpu->arch.features, KVM_VCPU_MAX_FEATURES); - - /* -ENOENT for unknown features, -EINVAL for invalid combinations. */ - for (i = 0; i < sizeof(init->features) * 8; i++) { - if (init->features[i / 32] & (1 << (i % 32))) { - if (i >= KVM_VCPU_MAX_FEATURES) - return -ENOENT; - set_bit(i, vcpu->arch.features); - } - } - - /* Now we know what it is, we can reset it. */ - return kvm_reset_vcpu(vcpu); -} - int kvm_vcpu_preferred_target(struct kvm_vcpu_init *init) { int target = kvm_target_cpu(); -- cgit v1.2.3-59-g8ed1b From cf5d318865e25f887d49a0c6083bbc6dcd1905b1 Mon Sep 17 00:00:00 2001 From: Christoffer Dall Date: Thu, 16 Oct 2014 17:00:18 +0200 Subject: arm/arm64: KVM: Turn off vcpus on PSCI shutdown/reboot When a vcpu calls SYSTEM_OFF or SYSTEM_RESET with PSCI v0.2, the vcpus should really be turned off for the VM adhering to the suggestions in the PSCI spec, and it's the sane thing to do. Also, clarify the behavior and expectations for exits to user space with the KVM_EXIT_SYSTEM_EVENT case. Acked-by: Marc Zyngier Signed-off-by: Christoffer Dall --- Documentation/virtual/kvm/api.txt | 9 +++++++++ arch/arm/kvm/psci.c | 18 ++++++++++++++++++ arch/arm64/include/asm/kvm_host.h | 1 + 3 files changed, 28 insertions(+) (limited to 'Documentation') diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 81f1b974c06a..228f9cf5a5b5 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -2957,6 +2957,15 @@ HVC instruction based PSCI call from the vcpu. The 'type' field describes the system-level event type. The 'flags' field describes architecture specific flags for the system-level event. +Valid values for 'type' are: + KVM_SYSTEM_EVENT_SHUTDOWN -- the guest has requested a shutdown of the + VM. Userspace is not obliged to honour this, and if it does honour + this does not need to destroy the VM synchronously (ie it may call + KVM_RUN again before shutdown finally occurs). + KVM_SYSTEM_EVENT_RESET -- the guest has requested a reset of the VM. + As with SHUTDOWN, userspace can choose to ignore the request, or + to schedule the reset to occur in the future and may call KVM_RUN again. + /* Fix the size of the union. */ char padding[256]; }; diff --git a/arch/arm/kvm/psci.c b/arch/arm/kvm/psci.c index 09cf37737ee2..58cb3248d277 100644 --- a/arch/arm/kvm/psci.c +++ b/arch/arm/kvm/psci.c @@ -15,6 +15,7 @@ * along with this program. If not, see . */ +#include #include #include @@ -166,6 +167,23 @@ static unsigned long kvm_psci_vcpu_affinity_info(struct kvm_vcpu *vcpu) static void kvm_prepare_system_event(struct kvm_vcpu *vcpu, u32 type) { + int i; + struct kvm_vcpu *tmp; + + /* + * The KVM ABI specifies that a system event exit may call KVM_RUN + * again and may perform shutdown/reboot at a later time that when the + * actual request is made. Since we are implementing PSCI and a + * caller of PSCI reboot and shutdown expects that the system shuts + * down or reboots immediately, let's make sure that VCPUs are not run + * after this call is handled and before the VCPUs have been + * re-initialized. + */ + kvm_for_each_vcpu(i, tmp, vcpu->kvm) { + tmp->arch.pause = true; + kvm_vcpu_kick(tmp); + } + memset(&vcpu->run->system_event, 0, sizeof(vcpu->run->system_event)); vcpu->run->system_event.type = type; vcpu->run->exit_reason = KVM_EXIT_SYSTEM_EVENT; diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 65c615294589..0b7dfdb931df 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -198,6 +198,7 @@ struct kvm_vcpu *kvm_arm_get_running_vcpu(void); struct kvm_vcpu * __percpu *kvm_get_running_vcpus(void); u64 kvm_call_hyp(void *hypfn, ...); +void force_vm_exit(const cpumask_t *mask); int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run, int exception_index); -- cgit v1.2.3-59-g8ed1b From 27ec26ecdca956a32e89a22a148f1c16b5c0becf Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Fri, 12 Dec 2014 16:55:18 -0800 Subject: hugetlb: fix hugepages= entry in kernel-parameters.txt The hugepages= entry in kernel-parameters.txt states that 1GB pages can only be allocated at boot time and not freed afterwards. This is not true since commit 944d9fec8d7a ("hugetlb: add support for gigantic page allocation at runtime"), at least for x86_64. Instead of adding arch-specifc observations to the hugepages= entry, this commit just drops the out of date information. Further information about arch-specific support and available features can be obtained in the hugetlb documentation. Signed-off-by: Luiz Capitulino Cc: Andi Kleen Acked-by: David Rientjes Cc: Rik van Riel Cc: Yasuaki Ishimatsu Cc: Yinghai Lu Cc: Davidlohr Bueso Acked-by: Naoya Horiguchi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/kernel-parameters.txt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index eacb2e0397ae..24539d1c7d25 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1228,9 +1228,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted. multiple times interleaved with hugepages= to reserve huge pages of different sizes. Valid pages sizes on x86-64 are 2M (when the CPU supports "pse") and 1G - (when the CPU supports the "pdpe1gb" cpuinfo flag) - Note that 1GB pages can only be allocated at boot time - using hugepages= and not freed afterwards. + (when the CPU supports the "pdpe1gb" cpuinfo flag). hvc_iucv= [S390] Number of z/VM IUCV hypervisor console (HVC) terminal devices. Valid values: 0..8 -- cgit v1.2.3-59-g8ed1b From 031bc5743f158b2d5498294f489e534a31251626 Mon Sep 17 00:00:00 2001 From: Joonsoo Kim Date: Fri, 12 Dec 2014 16:55:52 -0800 Subject: mm/debug-pagealloc: make debug-pagealloc boottime configurable Now, we have prepared to avoid using debug-pagealloc in boottime. So introduce new kernel-parameter to disable debug-pagealloc in boottime, and makes related functions to be disabled in this case. Only non-intuitive part is change of guard page functions. Because guard page is effective only if debug-pagealloc is enabled, turning off according to debug-pagealloc is reasonable thing to do. Signed-off-by: Joonsoo Kim Cc: Mel Gorman Cc: Johannes Weiner Cc: Minchan Kim Cc: Dave Hansen Cc: Michal Nazarewicz Cc: Jungsoo Son Cc: Ingo Molnar Cc: Joonsoo Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/kernel-parameters.txt | 9 +++++++++ arch/powerpc/mm/hash_utils_64.c | 2 +- arch/powerpc/mm/pgtable_32.c | 2 +- arch/s390/mm/pageattr.c | 2 +- arch/sparc/mm/init_64.c | 2 +- arch/x86/mm/pageattr.c | 2 +- include/linux/mm.h | 17 ++++++++++++++++- mm/debug-pagealloc.c | 8 +++++++- mm/page_alloc.c | 20 ++++++++++++++++++++ 9 files changed, 57 insertions(+), 7 deletions(-) (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 24539d1c7d25..6f067954675b 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -829,6 +829,15 @@ bytes respectively. Such letter suffixes can also be entirely omitted. CONFIG_DEBUG_PAGEALLOC, hence this option will not help tracking down these problems. + debug_pagealloc= + [KNL] When CONFIG_DEBUG_PAGEALLOC is set, this + parameter enables the feature at boot time. In + default, it is disabled. We can avoid allocating huge + chunk of memory for debug pagealloc if we don't enable + it at boot time and the system will work mostly same + with the kernel built without CONFIG_DEBUG_PAGEALLOC. + on: enable the feature + debugpat [X86] Enable PAT debugging decnet.addr= [HW,NET] diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index e56a307bc676..2c2022d16059 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c @@ -1514,7 +1514,7 @@ static void kernel_unmap_linear_page(unsigned long vaddr, unsigned long lmi) mmu_kernel_ssize, 0); } -void kernel_map_pages(struct page *page, int numpages, int enable) +void __kernel_map_pages(struct page *page, int numpages, int enable) { unsigned long flags, vaddr, lmi; int i; diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c index d545b1231594..50fad3801f30 100644 --- a/arch/powerpc/mm/pgtable_32.c +++ b/arch/powerpc/mm/pgtable_32.c @@ -429,7 +429,7 @@ static int change_page_attr(struct page *page, int numpages, pgprot_t prot) } -void kernel_map_pages(struct page *page, int numpages, int enable) +void __kernel_map_pages(struct page *page, int numpages, int enable) { if (PageHighMem(page)) return; diff --git a/arch/s390/mm/pageattr.c b/arch/s390/mm/pageattr.c index 3fef3b299665..426c9d462d1c 100644 --- a/arch/s390/mm/pageattr.c +++ b/arch/s390/mm/pageattr.c @@ -120,7 +120,7 @@ static void ipte_range(pte_t *pte, unsigned long address, int nr) } } -void kernel_map_pages(struct page *page, int numpages, int enable) +void __kernel_map_pages(struct page *page, int numpages, int enable) { unsigned long address; int nr, i, j; diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c index 2d91c62f7f5f..3ea267c53320 100644 --- a/arch/sparc/mm/init_64.c +++ b/arch/sparc/mm/init_64.c @@ -1621,7 +1621,7 @@ static void __init kernel_physical_mapping_init(void) } #ifdef CONFIG_DEBUG_PAGEALLOC -void kernel_map_pages(struct page *page, int numpages, int enable) +void __kernel_map_pages(struct page *page, int numpages, int enable) { unsigned long phys_start = page_to_pfn(page) << PAGE_SHIFT; unsigned long phys_end = phys_start + (numpages * PAGE_SIZE); diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index a3a5d46605d2..dfaf2e0f5f8f 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c @@ -1817,7 +1817,7 @@ static int __set_pages_np(struct page *page, int numpages) return __change_page_attr_set_clr(&cpa, 0); } -void kernel_map_pages(struct page *page, int numpages, int enable) +void __kernel_map_pages(struct page *page, int numpages, int enable) { if (PageHighMem(page)) return; diff --git a/include/linux/mm.h b/include/linux/mm.h index 66560f1a0564..8b8d77a1532f 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -2061,7 +2061,22 @@ static inline void vm_stat_account(struct mm_struct *mm, #endif /* CONFIG_PROC_FS */ #ifdef CONFIG_DEBUG_PAGEALLOC -extern void kernel_map_pages(struct page *page, int numpages, int enable); +extern bool _debug_pagealloc_enabled; +extern void __kernel_map_pages(struct page *page, int numpages, int enable); + +static inline bool debug_pagealloc_enabled(void) +{ + return _debug_pagealloc_enabled; +} + +static inline void +kernel_map_pages(struct page *page, int numpages, int enable) +{ + if (!debug_pagealloc_enabled()) + return; + + __kernel_map_pages(page, numpages, enable); +} #ifdef CONFIG_HIBERNATION extern bool kernel_page_present(struct page *page); #endif /* CONFIG_HIBERNATION */ diff --git a/mm/debug-pagealloc.c b/mm/debug-pagealloc.c index 0072f2c53331..5bf5906ce13b 100644 --- a/mm/debug-pagealloc.c +++ b/mm/debug-pagealloc.c @@ -10,11 +10,17 @@ static bool page_poisoning_enabled __read_mostly; static bool need_page_poisoning(void) { + if (!debug_pagealloc_enabled()) + return false; + return true; } static void init_page_poisoning(void) { + if (!debug_pagealloc_enabled()) + return; + page_poisoning_enabled = true; } @@ -119,7 +125,7 @@ static void unpoison_pages(struct page *page, int n) unpoison_page(page + i); } -void kernel_map_pages(struct page *page, int numpages, int enable) +void __kernel_map_pages(struct page *page, int numpages, int enable) { if (!page_poisoning_enabled) return; diff --git a/mm/page_alloc.c b/mm/page_alloc.c index e0a39d328ca1..303d38516807 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -425,15 +425,35 @@ static inline void prep_zero_page(struct page *page, unsigned int order, #ifdef CONFIG_DEBUG_PAGEALLOC unsigned int _debug_guardpage_minorder; +bool _debug_pagealloc_enabled __read_mostly; bool _debug_guardpage_enabled __read_mostly; +static int __init early_debug_pagealloc(char *buf) +{ + if (!buf) + return -EINVAL; + + if (strcmp(buf, "on") == 0) + _debug_pagealloc_enabled = true; + + return 0; +} +early_param("debug_pagealloc", early_debug_pagealloc); + static bool need_debug_guardpage(void) { + /* If we don't use debug_pagealloc, we don't need guard page */ + if (!debug_pagealloc_enabled()) + return false; + return true; } static void init_debug_guardpage(void) { + if (!debug_pagealloc_enabled()) + return; + _debug_guardpage_enabled = true; } -- cgit v1.2.3-59-g8ed1b From 48c96a3685795e52903e60c7ee115e5e22e7d640 Mon Sep 17 00:00:00 2001 From: Joonsoo Kim Date: Fri, 12 Dec 2014 16:56:01 -0800 Subject: mm/page_owner: keep track of page owners This is the page owner tracking code which is introduced so far ago. It is resident on Andrew's tree, though, nobody tried to upstream so it remain as is. Our company uses this feature actively to debug memory leak or to find a memory hogger so I decide to upstream this feature. This functionality help us to know who allocates the page. When allocating a page, we store some information about allocation in extra memory. Later, if we need to know status of all pages, we can get and analyze it from this stored information. In previous version of this feature, extra memory is statically defined in struct page, but, in this version, extra memory is allocated outside of struct page. It enables us to turn on/off this feature at boottime without considerable memory waste. Although we already have tracepoint for tracing page allocation/free, using it to analyze page owner is rather complex. We need to enlarge the trace buffer for preventing overlapping until userspace program launched. And, launched program continually dump out the trace buffer for later analysis and it would change system behaviour with more possibility rather than just keeping it in memory, so bad for debug. Moreover, we can use page_owner feature further for various purposes. For example, we can use it for fragmentation statistics implemented in this patch. And, I also plan to implement some CMA failure debugging feature using this interface. I'd like to give the credit for all developers contributed this feature, but, it's not easy because I don't know exact history. Sorry about that. Below is people who has "Signed-off-by" in the patches in Andrew's tree. Contributor: Alexander Nyberg Mel Gorman Dave Hansen Minchan Kim Michal Nazarewicz Andrew Morton Jungsoo Son Signed-off-by: Joonsoo Kim Cc: Mel Gorman Cc: Johannes Weiner Cc: Minchan Kim Cc: Dave Hansen Cc: Michal Nazarewicz Cc: Jungsoo Son Cc: Ingo Molnar Cc: Joonsoo Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/kernel-parameters.txt | 6 + include/linux/page_ext.h | 10 ++ include/linux/page_owner.h | 38 ++++++ lib/Kconfig.debug | 16 +++ mm/Makefile | 1 + mm/page_alloc.c | 11 +- mm/page_ext.c | 4 + mm/page_owner.c | 222 ++++++++++++++++++++++++++++++++++++ mm/vmstat.c | 101 ++++++++++++++++ tools/vm/Makefile | 4 +- tools/vm/page_owner_sort.c | 144 +++++++++++++++++++++++ 11 files changed, 554 insertions(+), 3 deletions(-) create mode 100644 include/linux/page_owner.h create mode 100644 mm/page_owner.c create mode 100644 tools/vm/page_owner_sort.c (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 6f067954675b..68153642c44e 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -2513,6 +2513,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted. OSS [HW,OSS] See Documentation/sound/oss/oss-parameters.txt + page_owner= [KNL] Boot-time page_owner enabling option. + Storage of the information about who allocated + each page is disabled in default. With this switch, + we can turn it on. + on: enable the feature + panic= [KNL] Kernel behaviour on panic: delay timeout > 0: seconds before rebooting timeout = 0: wait forever diff --git a/include/linux/page_ext.h b/include/linux/page_ext.h index 61c0f05f9069..d2a2c84c72d0 100644 --- a/include/linux/page_ext.h +++ b/include/linux/page_ext.h @@ -1,6 +1,9 @@ #ifndef __LINUX_PAGE_EXT_H #define __LINUX_PAGE_EXT_H +#include +#include + struct pglist_data; struct page_ext_operations { bool (*need)(void); @@ -22,6 +25,7 @@ struct page_ext_operations { enum page_ext_flags { PAGE_EXT_DEBUG_POISON, /* Page is poisoned */ PAGE_EXT_DEBUG_GUARD, + PAGE_EXT_OWNER, }; /* @@ -33,6 +37,12 @@ enum page_ext_flags { */ struct page_ext { unsigned long flags; +#ifdef CONFIG_PAGE_OWNER + unsigned int order; + gfp_t gfp_mask; + struct stack_trace trace; + unsigned long trace_entries[8]; +#endif }; extern void pgdat_page_ext_init(struct pglist_data *pgdat); diff --git a/include/linux/page_owner.h b/include/linux/page_owner.h new file mode 100644 index 000000000000..b48c3471c254 --- /dev/null +++ b/include/linux/page_owner.h @@ -0,0 +1,38 @@ +#ifndef __LINUX_PAGE_OWNER_H +#define __LINUX_PAGE_OWNER_H + +#ifdef CONFIG_PAGE_OWNER +extern bool page_owner_inited; +extern struct page_ext_operations page_owner_ops; + +extern void __reset_page_owner(struct page *page, unsigned int order); +extern void __set_page_owner(struct page *page, + unsigned int order, gfp_t gfp_mask); + +static inline void reset_page_owner(struct page *page, unsigned int order) +{ + if (likely(!page_owner_inited)) + return; + + __reset_page_owner(page, order); +} + +static inline void set_page_owner(struct page *page, + unsigned int order, gfp_t gfp_mask) +{ + if (likely(!page_owner_inited)) + return; + + __set_page_owner(page, order, gfp_mask); +} +#else +static inline void reset_page_owner(struct page *page, unsigned int order) +{ +} +static inline void set_page_owner(struct page *page, + unsigned int order, gfp_t gfp_mask) +{ +} + +#endif /* CONFIG_PAGE_OWNER */ +#endif /* __LINUX_PAGE_OWNER_H */ diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index d780351835e9..5f2ce616c046 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -227,6 +227,22 @@ config UNUSED_SYMBOLS you really need it, and what the merge plan to the mainline kernel for your module is. +config PAGE_OWNER + bool "Track page owner" + depends on DEBUG_KERNEL && STACKTRACE_SUPPORT + select DEBUG_FS + select STACKTRACE + select PAGE_EXTENSION + help + This keeps track of what call chain is the owner of a page, may + help to find bare alloc_page(s) leaks. Even if you include this + feature on your build, it is disabled in default. You should pass + "page_owner=on" to boot parameter in order to enable it. Eats + a fair amount of memory if enabled. See tools/vm/page_owner_sort.c + for user-space helper. + + If unsure, say N. + config DEBUG_FS bool "Debug Filesystem" help diff --git a/mm/Makefile b/mm/Makefile index 580cd3f392af..4bf586e66378 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -63,6 +63,7 @@ obj-$(CONFIG_MEMORY_FAILURE) += memory-failure.o obj-$(CONFIG_HWPOISON_INJECT) += hwpoison-inject.o obj-$(CONFIG_DEBUG_KMEMLEAK) += kmemleak.o obj-$(CONFIG_DEBUG_KMEMLEAK_TEST) += kmemleak-test.o +obj-$(CONFIG_PAGE_OWNER) += page_owner.o obj-$(CONFIG_CLEANCACHE) += cleancache.o obj-$(CONFIG_MEMORY_ISOLATION) += page_isolation.o obj-$(CONFIG_ZPOOL) += zpool.o diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 303d38516807..c13b6b29add2 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -59,6 +59,7 @@ #include #include #include +#include #include #include @@ -813,6 +814,8 @@ static bool free_pages_prepare(struct page *page, unsigned int order) if (bad) return false; + reset_page_owner(page, order); + if (!PageHighMem(page)) { debug_check_no_locks_freed(page_address(page), PAGE_SIZE << order); @@ -988,6 +991,8 @@ static int prep_new_page(struct page *page, unsigned int order, gfp_t gfp_flags) if (order && (gfp_flags & __GFP_COMP)) prep_compound_page(page, order); + set_page_owner(page, order, gfp_flags); + return 0; } @@ -1560,8 +1565,11 @@ void split_page(struct page *page, unsigned int order) split_page(virt_to_page(page[0].shadow), order); #endif - for (i = 1; i < (1 << order); i++) + set_page_owner(page, 0, 0); + for (i = 1; i < (1 << order); i++) { set_page_refcounted(page + i); + set_page_owner(page + i, 0, 0); + } } EXPORT_SYMBOL_GPL(split_page); @@ -1601,6 +1609,7 @@ int __isolate_free_page(struct page *page, unsigned int order) } } + set_page_owner(page, order, 0); return 1UL << order; } diff --git a/mm/page_ext.c b/mm/page_ext.c index c2cd7b15f0de..d86fd2f5353f 100644 --- a/mm/page_ext.c +++ b/mm/page_ext.c @@ -5,6 +5,7 @@ #include #include #include +#include /* * struct page extension @@ -55,6 +56,9 @@ static struct page_ext_operations *page_ext_ops[] = { #ifdef CONFIG_PAGE_POISONING &page_poisoning_ops, #endif +#ifdef CONFIG_PAGE_OWNER + &page_owner_ops, +#endif }; static unsigned long total_usage; diff --git a/mm/page_owner.c b/mm/page_owner.c new file mode 100644 index 000000000000..85eec7ea6735 --- /dev/null +++ b/mm/page_owner.c @@ -0,0 +1,222 @@ +#include +#include +#include +#include +#include +#include +#include +#include "internal.h" + +static bool page_owner_disabled = true; +bool page_owner_inited __read_mostly; + +static int early_page_owner_param(char *buf) +{ + if (!buf) + return -EINVAL; + + if (strcmp(buf, "on") == 0) + page_owner_disabled = false; + + return 0; +} +early_param("page_owner", early_page_owner_param); + +static bool need_page_owner(void) +{ + if (page_owner_disabled) + return false; + + return true; +} + +static void init_page_owner(void) +{ + if (page_owner_disabled) + return; + + page_owner_inited = true; +} + +struct page_ext_operations page_owner_ops = { + .need = need_page_owner, + .init = init_page_owner, +}; + +void __reset_page_owner(struct page *page, unsigned int order) +{ + int i; + struct page_ext *page_ext; + + for (i = 0; i < (1 << order); i++) { + page_ext = lookup_page_ext(page + i); + __clear_bit(PAGE_EXT_OWNER, &page_ext->flags); + } +} + +void __set_page_owner(struct page *page, unsigned int order, gfp_t gfp_mask) +{ + struct page_ext *page_ext; + struct stack_trace *trace; + + page_ext = lookup_page_ext(page); + + trace = &page_ext->trace; + trace->nr_entries = 0; + trace->max_entries = ARRAY_SIZE(page_ext->trace_entries); + trace->entries = &page_ext->trace_entries[0]; + trace->skip = 3; + save_stack_trace(&page_ext->trace); + + page_ext->order = order; + page_ext->gfp_mask = gfp_mask; + + __set_bit(PAGE_EXT_OWNER, &page_ext->flags); +} + +static ssize_t +print_page_owner(char __user *buf, size_t count, unsigned long pfn, + struct page *page, struct page_ext *page_ext) +{ + int ret; + int pageblock_mt, page_mt; + char *kbuf; + + kbuf = kmalloc(count, GFP_KERNEL); + if (!kbuf) + return -ENOMEM; + + ret = snprintf(kbuf, count, + "Page allocated via order %u, mask 0x%x\n", + page_ext->order, page_ext->gfp_mask); + + if (ret >= count) + goto err; + + /* Print information relevant to grouping pages by mobility */ + pageblock_mt = get_pfnblock_migratetype(page, pfn); + page_mt = gfpflags_to_migratetype(page_ext->gfp_mask); + ret += snprintf(kbuf + ret, count - ret, + "PFN %lu Block %lu type %d %s Flags %s%s%s%s%s%s%s%s%s%s%s%s\n", + pfn, + pfn >> pageblock_order, + pageblock_mt, + pageblock_mt != page_mt ? "Fallback" : " ", + PageLocked(page) ? "K" : " ", + PageError(page) ? "E" : " ", + PageReferenced(page) ? "R" : " ", + PageUptodate(page) ? "U" : " ", + PageDirty(page) ? "D" : " ", + PageLRU(page) ? "L" : " ", + PageActive(page) ? "A" : " ", + PageSlab(page) ? "S" : " ", + PageWriteback(page) ? "W" : " ", + PageCompound(page) ? "C" : " ", + PageSwapCache(page) ? "B" : " ", + PageMappedToDisk(page) ? "M" : " "); + + if (ret >= count) + goto err; + + ret += snprint_stack_trace(kbuf + ret, count - ret, + &page_ext->trace, 0); + if (ret >= count) + goto err; + + ret += snprintf(kbuf + ret, count - ret, "\n"); + if (ret >= count) + goto err; + + if (copy_to_user(buf, kbuf, ret)) + ret = -EFAULT; + + kfree(kbuf); + return ret; + +err: + kfree(kbuf); + return -ENOMEM; +} + +static ssize_t +read_page_owner(struct file *file, char __user *buf, size_t count, loff_t *ppos) +{ + unsigned long pfn; + struct page *page; + struct page_ext *page_ext; + + if (!page_owner_inited) + return -EINVAL; + + page = NULL; + pfn = min_low_pfn + *ppos; + + /* Find a valid PFN or the start of a MAX_ORDER_NR_PAGES area */ + while (!pfn_valid(pfn) && (pfn & (MAX_ORDER_NR_PAGES - 1)) != 0) + pfn++; + + drain_all_pages(NULL); + + /* Find an allocated page */ + for (; pfn < max_pfn; pfn++) { + /* + * If the new page is in a new MAX_ORDER_NR_PAGES area, + * validate the area as existing, skip it if not + */ + if ((pfn & (MAX_ORDER_NR_PAGES - 1)) == 0 && !pfn_valid(pfn)) { + pfn += MAX_ORDER_NR_PAGES - 1; + continue; + } + + /* Check for holes within a MAX_ORDER area */ + if (!pfn_valid_within(pfn)) + continue; + + page = pfn_to_page(pfn); + if (PageBuddy(page)) { + unsigned long freepage_order = page_order_unsafe(page); + + if (freepage_order < MAX_ORDER) + pfn += (1UL << freepage_order) - 1; + continue; + } + + page_ext = lookup_page_ext(page); + + /* + * Pages allocated before initialization of page_owner are + * non-buddy and have no page_owner info. + */ + if (!test_bit(PAGE_EXT_OWNER, &page_ext->flags)) + continue; + + /* Record the next PFN to read in the file offset */ + *ppos = (pfn - min_low_pfn) + 1; + + return print_page_owner(buf, count, pfn, page, page_ext); + } + + return 0; +} + +static const struct file_operations proc_page_owner_operations = { + .read = read_page_owner, +}; + +static int __init pageowner_init(void) +{ + struct dentry *dentry; + + if (!page_owner_inited) { + pr_info("page_owner is disabled\n"); + return 0; + } + + dentry = debugfs_create_file("page_owner", S_IRUSR, NULL, + NULL, &proc_page_owner_operations); + if (IS_ERR(dentry)) + return PTR_ERR(dentry); + + return 0; +} +module_init(pageowner_init) diff --git a/mm/vmstat.c b/mm/vmstat.c index 1b12d390dc68..b090e9e3d626 100644 --- a/mm/vmstat.c +++ b/mm/vmstat.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include "internal.h" @@ -1017,6 +1019,104 @@ static int pagetypeinfo_showblockcount(struct seq_file *m, void *arg) return 0; } +#ifdef CONFIG_PAGE_OWNER +static void pagetypeinfo_showmixedcount_print(struct seq_file *m, + pg_data_t *pgdat, + struct zone *zone) +{ + struct page *page; + struct page_ext *page_ext; + unsigned long pfn = zone->zone_start_pfn, block_end_pfn; + unsigned long end_pfn = pfn + zone->spanned_pages; + unsigned long count[MIGRATE_TYPES] = { 0, }; + int pageblock_mt, page_mt; + int i; + + /* Scan block by block. First and last block may be incomplete */ + pfn = zone->zone_start_pfn; + + /* + * Walk the zone in pageblock_nr_pages steps. If a page block spans + * a zone boundary, it will be double counted between zones. This does + * not matter as the mixed block count will still be correct + */ + for (; pfn < end_pfn; ) { + if (!pfn_valid(pfn)) { + pfn = ALIGN(pfn + 1, MAX_ORDER_NR_PAGES); + continue; + } + + block_end_pfn = ALIGN(pfn + 1, pageblock_nr_pages); + block_end_pfn = min(block_end_pfn, end_pfn); + + page = pfn_to_page(pfn); + pageblock_mt = get_pfnblock_migratetype(page, pfn); + + for (; pfn < block_end_pfn; pfn++) { + if (!pfn_valid_within(pfn)) + continue; + + page = pfn_to_page(pfn); + if (PageBuddy(page)) { + pfn += (1UL << page_order(page)) - 1; + continue; + } + + if (PageReserved(page)) + continue; + + page_ext = lookup_page_ext(page); + + if (!test_bit(PAGE_EXT_OWNER, &page_ext->flags)) + continue; + + page_mt = gfpflags_to_migratetype(page_ext->gfp_mask); + if (pageblock_mt != page_mt) { + if (is_migrate_cma(pageblock_mt)) + count[MIGRATE_MOVABLE]++; + else + count[pageblock_mt]++; + + pfn = block_end_pfn; + break; + } + pfn += (1UL << page_ext->order) - 1; + } + } + + /* Print counts */ + seq_printf(m, "Node %d, zone %8s ", pgdat->node_id, zone->name); + for (i = 0; i < MIGRATE_TYPES; i++) + seq_printf(m, "%12lu ", count[i]); + seq_putc(m, '\n'); +} +#endif /* CONFIG_PAGE_OWNER */ + +/* + * Print out the number of pageblocks for each migratetype that contain pages + * of other types. This gives an indication of how well fallbacks are being + * contained by rmqueue_fallback(). It requires information from PAGE_OWNER + * to determine what is going on + */ +static void pagetypeinfo_showmixedcount(struct seq_file *m, pg_data_t *pgdat) +{ +#ifdef CONFIG_PAGE_OWNER + int mtype; + + if (!page_owner_inited) + return; + + drain_all_pages(NULL); + + seq_printf(m, "\n%-23s", "Number of mixed blocks "); + for (mtype = 0; mtype < MIGRATE_TYPES; mtype++) + seq_printf(m, "%12s ", migratetype_names[mtype]); + seq_putc(m, '\n'); + + walk_zones_in_node(m, pgdat, pagetypeinfo_showmixedcount_print); +#endif /* CONFIG_PAGE_OWNER */ +} + /* * This prints out statistics in relation to grouping pages by mobility. * It is expensive to collect so do not constantly read the file. @@ -1034,6 +1134,7 @@ static int pagetypeinfo_show(struct seq_file *m, void *arg) seq_putc(m, '\n'); pagetypeinfo_showfree(m, pgdat); pagetypeinfo_showblockcount(m, pgdat); + pagetypeinfo_showmixedcount(m, pgdat); return 0; } diff --git a/tools/vm/Makefile b/tools/vm/Makefile index 3d907dacf2ac..ac884b65a072 100644 --- a/tools/vm/Makefile +++ b/tools/vm/Makefile @@ -1,6 +1,6 @@ # Makefile for vm tools # -TARGETS=page-types slabinfo +TARGETS=page-types slabinfo page_owner_sort LIB_DIR = ../lib/api LIBS = $(LIB_DIR)/libapikfs.a @@ -18,5 +18,5 @@ $(LIBS): $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) clean: - $(RM) page-types slabinfo + $(RM) page-types slabinfo page_owner_sort make -C $(LIB_DIR) clean diff --git a/tools/vm/page_owner_sort.c b/tools/vm/page_owner_sort.c new file mode 100644 index 000000000000..77147b42d598 --- /dev/null +++ b/tools/vm/page_owner_sort.c @@ -0,0 +1,144 @@ +/* + * User-space helper to sort the output of /sys/kernel/debug/page_owner + * + * Example use: + * cat /sys/kernel/debug/page_owner > page_owner_full.txt + * grep -v ^PFN page_owner_full.txt > page_owner.txt + * ./sort page_owner.txt sorted_page_owner.txt +*/ + +#include +#include +#include +#include +#include +#include +#include + +struct block_list { + char *txt; + int len; + int num; +}; + + +static struct block_list *list; +static int list_size; +static int max_size; + +struct block_list *block_head; + +int read_block(char *buf, int buf_size, FILE *fin) +{ + char *curr = buf, *const buf_end = buf + buf_size; + + while (buf_end - curr > 1 && fgets(curr, buf_end - curr, fin)) { + if (*curr == '\n') /* empty line */ + return curr - buf; + curr += strlen(curr); + } + + return -1; /* EOF or no space left in buf. */ +} + +static int compare_txt(const void *p1, const void *p2) +{ + const struct block_list *l1 = p1, *l2 = p2; + + return strcmp(l1->txt, l2->txt); +} + +static int compare_num(const void *p1, const void *p2) +{ + const struct block_list *l1 = p1, *l2 = p2; + + return l2->num - l1->num; +} + +static void add_list(char *buf, int len) +{ + if (list_size != 0 && + len == list[list_size-1].len && + memcmp(buf, list[list_size-1].txt, len) == 0) { + list[list_size-1].num++; + return; + } + if (list_size == max_size) { + printf("max_size too small??\n"); + exit(1); + } + list[list_size].txt = malloc(len+1); + list[list_size].len = len; + list[list_size].num = 1; + memcpy(list[list_size].txt, buf, len); + list[list_size].txt[len] = 0; + list_size++; + if (list_size % 1000 == 0) { + printf("loaded %d\r", list_size); + fflush(stdout); + } +} + +#define BUF_SIZE 1024 + +int main(int argc, char **argv) +{ + FILE *fin, *fout; + char buf[BUF_SIZE]; + int ret, i, count; + struct block_list *list2; + struct stat st; + + if (argc < 3) { + printf("Usage: ./program \n"); + perror("open: "); + exit(1); + } + + fin = fopen(argv[1], "r"); + fout = fopen(argv[2], "w"); + if (!fin || !fout) { + printf("Usage: ./program \n"); + perror("open: "); + exit(1); + } + + fstat(fileno(fin), &st); + max_size = st.st_size / 100; /* hack ... */ + + list = malloc(max_size * sizeof(*list)); + + for ( ; ; ) { + ret = read_block(buf, BUF_SIZE, fin); + if (ret < 0) + break; + + add_list(buf, ret); + } + + printf("loaded %d\n", list_size); + + printf("sorting ....\n"); + + qsort(list, list_size, sizeof(list[0]), compare_txt); + + list2 = malloc(sizeof(*list) * list_size); + + printf("culling\n"); + + for (i = count = 0; i < list_size; i++) { + if (count == 0 || + strcmp(list2[count-1].txt, list[i].txt) != 0) { + list2[count++] = list[i]; + } else { + list2[count-1].num += list[i].num; + } + } + + qsort(list2, count, sizeof(list[0]), compare_num); + + for (i = 0; i < count; i++) + fprintf(fout, "%d times:\n%s\n", list2[i].num, list2[i].txt); + + return 0; +} -- cgit v1.2.3-59-g8ed1b From 16a7ade8af3b4ad30aec880177ff291bb5ea86d1 Mon Sep 17 00:00:00 2001 From: Joonsoo Kim Date: Fri, 12 Dec 2014 16:56:07 -0800 Subject: Documentation: add new page_owner document page owner is for the tracking about who allocated each page. This document explains what is the page owner feature and what is the merit of it. And, simple HOW-TO is also explained. See the document for detailed information. Signed-off-by: Joonsoo Kim Cc: Mel Gorman Cc: Johannes Weiner Cc: Minchan Kim Cc: Dave Hansen Cc: Michal Nazarewicz Cc: Jungsoo Son Cc: Ingo Molnar Cc: Joonsoo Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/vm/page_owner.txt | 81 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 Documentation/vm/page_owner.txt (limited to 'Documentation') diff --git a/Documentation/vm/page_owner.txt b/Documentation/vm/page_owner.txt new file mode 100644 index 000000000000..8f3ce9b3aa11 --- /dev/null +++ b/Documentation/vm/page_owner.txt @@ -0,0 +1,81 @@ +page owner: Tracking about who allocated each page +----------------------------------------------------------- + +* Introduction + +page owner is for the tracking about who allocated each page. +It can be used to debug memory leak or to find a memory hogger. +When allocation happens, information about allocation such as call stack +and order of pages is stored into certain storage for each page. +When we need to know about status of all pages, we can get and analyze +this information. + +Although we already have tracepoint for tracing page allocation/free, +using it for analyzing who allocate each page is rather complex. We need +to enlarge the trace buffer for preventing overlapping until userspace +program launched. And, launched program continually dump out the trace +buffer for later analysis and it would change system behviour with more +possibility rather than just keeping it in memory, so bad for debugging. + +page owner can also be used for various purposes. For example, accurate +fragmentation statistics can be obtained through gfp flag information of +each page. It is already implemented and activated if page owner is +enabled. Other usages are more than welcome. + +page owner is disabled in default. So, if you'd like to use it, you need +to add "page_owner=on" into your boot cmdline. If the kernel is built +with page owner and page owner is disabled in runtime due to no enabling +boot option, runtime overhead is marginal. If disabled in runtime, it +doesn't require memory to store owner information, so there is no runtime +memory overhead. And, page owner inserts just two unlikely branches into +the page allocator hotpath and if it returns false then allocation is +done like as the kernel without page owner. These two unlikely branches +would not affect to allocation performance. Following is the kernel's +code size change due to this facility. + +- Without page owner + text data bss dec hex filename + 40662 1493 644 42799 a72f mm/page_alloc.o + +- With page owner + text data bss dec hex filename + 40892 1493 644 43029 a815 mm/page_alloc.o + 1427 24 8 1459 5b3 mm/page_ext.o + 2722 50 0 2772 ad4 mm/page_owner.o + +Although, roughly, 4 KB code is added in total, page_alloc.o increase by +230 bytes and only half of it is in hotpath. Building the kernel with +page owner and turning it on if needed would be great option to debug +kernel memory problem. + +There is one notice that is caused by implementation detail. page owner +stores information into the memory from struct page extension. This memory +is initialized some time later than that page allocator starts in sparse +memory system, so, until initialization, many pages can be allocated and +they would have no owner information. To fix it up, these early allocated +pages are investigated and marked as allocated in initialization phase. +Although it doesn't mean that they have the right owner information, +at least, we can tell whether the page is allocated or not, +more accurately. On 2GB memory x86-64 VM box, 13343 early allocated pages +are catched and marked, although they are mostly allocated from struct +page extension feature. Anyway, after that, no page is left in +un-tracking state. + +* Usage + +1) Build user-space helper + cd tools/vm + make page_owner_sort + +2) Enable page owner + Add "page_owner=on" to boot cmdline. + +3) Do the job what you want to debug + +4) Analyze information from page owner + cat /sys/kernel/debug/page_owner > page_owner_full.txt + grep -v ^PFN page_owner_full.txt > page_owner.txt + ./page_owner_sort page_owner.txt sorted_page_owner.txt + + See the result about who allocated each page + in the sorted_page_owner.txt. -- cgit v1.2.3-59-g8ed1b From 0050ee059f7fc86b1df2527aaa14ed5dc72f9973 Mon Sep 17 00:00:00 2001 From: Manfred Spraul Date: Fri, 12 Dec 2014 16:58:17 -0800 Subject: ipc/msg: increase MSGMNI, remove scaling SysV can be abused to allocate locked kernel memory. For most systems, a small limit doesn't make sense, see the discussion with regards to SHMMAX. Therefore: increase MSGMNI to the maximum supported. And: If we ignore the risk of locking too much memory, then an automatic scaling of MSGMNI doesn't make sense. Therefore the logic can be removed. The code preserves auto_msgmni to avoid breaking any user space applications that expect that the value exists. Notes: 1) If an administrator must limit the memory allocations, then he can set MSGMNI as necessary. Or he can disable sysv entirely (as e.g. done by Android). 2) MSGMAX and MSGMNB are intentionally not increased, as these values are used to control latency vs. throughput: If MSGMNB is large, then msgsnd() just returns and more messages can be queued before a task switch to a task that calls msgrcv() is forced. [akpm@linux-foundation.org: coding-style fixes] Signed-off-by: Manfred Spraul Cc: Davidlohr Bueso Cc: Rafael Aquini Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/sysctl/kernel.txt | 10 +++-- include/linux/ipc_namespace.h | 20 --------- include/uapi/linux/msg.h | 28 +++++++++---- ipc/Makefile | 2 +- ipc/ipc_sysctl.c | 93 ++++++++--------------------------------- ipc/ipcns_notifier.c | 92 ---------------------------------------- ipc/msg.c | 36 +--------------- ipc/namespace.c | 22 ---------- ipc/util.c | 40 ------------------ 9 files changed, 45 insertions(+), 298 deletions(-) delete mode 100644 ipc/ipcns_notifier.c (limited to 'Documentation') diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt index b5d0c8501a18..75511efefc64 100644 --- a/Documentation/sysctl/kernel.txt +++ b/Documentation/sysctl/kernel.txt @@ -116,10 +116,12 @@ set during run time. auto_msgmni: -Enables/Disables automatic recomputing of msgmni upon memory add/remove -or upon ipc namespace creation/removal (see the msgmni description -above). Echoing "1" into this file enables msgmni automatic recomputing. -Echoing "0" turns it off. auto_msgmni default value is 1. +This variable has no effect and may be removed in future kernel +releases. Reading it always returns 0. +Up to Linux 3.17, it enabled/disabled automatic recomputing of msgmni +upon memory add/remove or upon ipc namespace creation/removal. +Echoing "1" into this file enabled msgmni automatic recomputing. +Echoing "0" turned it off. auto_msgmni default value was 1. ============================================================== diff --git a/include/linux/ipc_namespace.h b/include/linux/ipc_namespace.h index 35e7eca4e33b..e365d5ec69cb 100644 --- a/include/linux/ipc_namespace.h +++ b/include/linux/ipc_namespace.h @@ -7,15 +7,6 @@ #include #include -/* - * ipc namespace events - */ -#define IPCNS_MEMCHANGED 0x00000001 /* Notify lowmem size changed */ -#define IPCNS_CREATED 0x00000002 /* Notify new ipc namespace created */ -#define IPCNS_REMOVED 0x00000003 /* Notify ipc namespace removed */ - -#define IPCNS_CALLBACK_PRI 0 - struct user_namespace; struct ipc_ids { @@ -38,7 +29,6 @@ struct ipc_namespace { unsigned int msg_ctlmni; atomic_t msg_bytes; atomic_t msg_hdrs; - int auto_msgmni; size_t shm_ctlmax; size_t shm_ctlall; @@ -77,18 +67,8 @@ extern atomic_t nr_ipc_ns; extern spinlock_t mq_lock; #ifdef CONFIG_SYSVIPC -extern int register_ipcns_notifier(struct ipc_namespace *); -extern int cond_register_ipcns_notifier(struct ipc_namespace *); -extern void unregister_ipcns_notifier(struct ipc_namespace *); -extern int ipcns_notify(unsigned long); extern void shm_destroy_orphaned(struct ipc_namespace *ns); #else /* CONFIG_SYSVIPC */ -static inline int register_ipcns_notifier(struct ipc_namespace *ns) -{ return 0; } -static inline int cond_register_ipcns_notifier(struct ipc_namespace *ns) -{ return 0; } -static inline void unregister_ipcns_notifier(struct ipc_namespace *ns) { } -static inline int ipcns_notify(unsigned long l) { return 0; } static inline void shm_destroy_orphaned(struct ipc_namespace *ns) {} #endif /* CONFIG_SYSVIPC */ diff --git a/include/uapi/linux/msg.h b/include/uapi/linux/msg.h index a70375526578..f51c8001dbe5 100644 --- a/include/uapi/linux/msg.h +++ b/include/uapi/linux/msg.h @@ -51,16 +51,28 @@ struct msginfo { }; /* - * Scaling factor to compute msgmni: - * the memory dedicated to msg queues (msgmni * msgmnb) should occupy - * at most 1/MSG_MEM_SCALE of the lowmem (see the formula in ipc/msg.c): - * up to 8MB : msgmni = 16 (MSGMNI) - * 4 GB : msgmni = 8K - * more than 16 GB : msgmni = 32K (IPCMNI) + * MSGMNI, MSGMAX and MSGMNB are default values which can be + * modified by sysctl. + * + * MSGMNI is the upper limit for the number of messages queues per + * namespace. + * It has been chosen to be as large possible without facilitating + * scenarios where userspace causes overflows when adjusting the limits via + * operations of the form retrieve current limit; add X; update limit". + * + * MSGMNB is the default size of a new message queue. Non-root tasks can + * decrease the size with msgctl(IPC_SET), root tasks + * (actually: CAP_SYS_RESOURCE) can both increase and decrease the queue + * size. The optimal value is application dependent. + * 16384 is used because it was always used (since 0.99.10) + * + * MAXMAX is the maximum size of an individual message, it's a global + * (per-namespace) limit that applies for all message queues. + * It's set to 1/2 of MSGMNB, to ensure that at least two messages fit into + * the queue. This is also an arbitrary choice (since 2.6.0). */ -#define MSG_MEM_SCALE 32 -#define MSGMNI 16 /* <= IPCMNI */ /* max # of msg queue identifiers */ +#define MSGMNI 32000 /* <= IPCMNI */ /* max # of msg queue identifiers */ #define MSGMAX 8192 /* <= INT_MAX */ /* max size of message (bytes) */ #define MSGMNB 16384 /* <= INT_MAX */ /* default max size of a message queue */ diff --git a/ipc/Makefile b/ipc/Makefile index 9075e172e52c..86c7300ecdf5 100644 --- a/ipc/Makefile +++ b/ipc/Makefile @@ -3,7 +3,7 @@ # obj-$(CONFIG_SYSVIPC_COMPAT) += compat.o -obj-$(CONFIG_SYSVIPC) += util.o msgutil.o msg.o sem.o shm.o ipcns_notifier.o syscall.o +obj-$(CONFIG_SYSVIPC) += util.o msgutil.o msg.o sem.o shm.o syscall.o obj-$(CONFIG_SYSVIPC_SYSCTL) += ipc_sysctl.o obj_mq-$(CONFIG_COMPAT) += compat_mq.o obj-$(CONFIG_POSIX_MQUEUE) += mqueue.o msgutil.o $(obj_mq-y) diff --git a/ipc/ipc_sysctl.c b/ipc/ipc_sysctl.c index e8075b247497..8ad93c29f511 100644 --- a/ipc/ipc_sysctl.c +++ b/ipc/ipc_sysctl.c @@ -62,29 +62,6 @@ static int proc_ipc_dointvec_minmax_orphans(struct ctl_table *table, int write, return err; } -static int proc_ipc_callback_dointvec_minmax(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - struct ctl_table ipc_table; - size_t lenp_bef = *lenp; - int rc; - - memcpy(&ipc_table, table, sizeof(ipc_table)); - ipc_table.data = get_ipc(table); - - rc = proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos); - - if (write && !rc && lenp_bef == *lenp) - /* - * Tunable has successfully been changed by hand. Disable its - * automatic adjustment. This simply requires unregistering - * the notifiers that trigger recalculation. - */ - unregister_ipcns_notifier(current->nsproxy->ipc_ns); - - return rc; -} - static int proc_ipc_doulongvec_minmax(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { @@ -96,54 +73,19 @@ static int proc_ipc_doulongvec_minmax(struct ctl_table *table, int write, lenp, ppos); } -/* - * Routine that is called when the file "auto_msgmni" has successfully been - * written. - * Two values are allowed: - * 0: unregister msgmni's callback routine from the ipc namespace notifier - * chain. This means that msgmni won't be recomputed anymore upon memory - * add/remove or ipc namespace creation/removal. - * 1: register back the callback routine. - */ -static void ipc_auto_callback(int val) -{ - if (!val) - unregister_ipcns_notifier(current->nsproxy->ipc_ns); - else { - /* - * Re-enable automatic recomputing only if not already - * enabled. - */ - recompute_msgmni(current->nsproxy->ipc_ns); - cond_register_ipcns_notifier(current->nsproxy->ipc_ns); - } -} - -static int proc_ipcauto_dointvec_minmax(struct ctl_table *table, int write, +static int proc_ipc_auto_msgmni(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { struct ctl_table ipc_table; - int oldval; - int rc; + int dummy = 0; memcpy(&ipc_table, table, sizeof(ipc_table)); - ipc_table.data = get_ipc(table); - oldval = *((int *)(ipc_table.data)); + ipc_table.data = &dummy; - rc = proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos); + if (write) + pr_info_once("writing to auto_msgmni has no effect"); - if (write && !rc) { - int newval = *((int *)(ipc_table.data)); - /* - * The file "auto_msgmni" has correctly been set. - * React by (un)registering the corresponding tunable, if the - * value has changed. - */ - if (newval != oldval) - ipc_auto_callback(newval); - } - - return rc; + return proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos); } #else @@ -151,8 +93,7 @@ static int proc_ipcauto_dointvec_minmax(struct ctl_table *table, int write, #define proc_ipc_dointvec NULL #define proc_ipc_dointvec_minmax NULL #define proc_ipc_dointvec_minmax_orphans NULL -#define proc_ipc_callback_dointvec_minmax NULL -#define proc_ipcauto_dointvec_minmax NULL +#define proc_ipc_auto_msgmni NULL #endif static int zero; @@ -204,10 +145,19 @@ static struct ctl_table ipc_kern_table[] = { .data = &init_ipc_ns.msg_ctlmni, .maxlen = sizeof(init_ipc_ns.msg_ctlmni), .mode = 0644, - .proc_handler = proc_ipc_callback_dointvec_minmax, + .proc_handler = proc_ipc_dointvec_minmax, .extra1 = &zero, .extra2 = &int_max, }, + { + .procname = "auto_msgmni", + .data = NULL, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_ipc_auto_msgmni, + .extra1 = &zero, + .extra2 = &one, + }, { .procname = "msgmnb", .data = &init_ipc_ns.msg_ctlmnb, @@ -224,15 +174,6 @@ static struct ctl_table ipc_kern_table[] = { .mode = 0644, .proc_handler = proc_ipc_dointvec, }, - { - .procname = "auto_msgmni", - .data = &init_ipc_ns.auto_msgmni, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_ipcauto_dointvec_minmax, - .extra1 = &zero, - .extra2 = &one, - }, #ifdef CONFIG_CHECKPOINT_RESTORE { .procname = "sem_next_id", diff --git a/ipc/ipcns_notifier.c b/ipc/ipcns_notifier.c deleted file mode 100644 index b9b31a4f77e1..000000000000 --- a/ipc/ipcns_notifier.c +++ /dev/null @@ -1,92 +0,0 @@ -/* - * linux/ipc/ipcns_notifier.c - * Copyright (C) 2007 BULL SA. Nadia Derbey - * - * Notification mechanism for ipc namespaces: - * The callback routine registered in the memory chain invokes the ipcns - * notifier chain with the IPCNS_MEMCHANGED event. - * Each callback routine registered in the ipcns namespace recomputes msgmni - * for the owning namespace. - */ - -#include -#include -#include -#include -#include - -#include "util.h" - - - -static BLOCKING_NOTIFIER_HEAD(ipcns_chain); - - -static int ipcns_callback(struct notifier_block *self, - unsigned long action, void *arg) -{ - struct ipc_namespace *ns; - - switch (action) { - case IPCNS_MEMCHANGED: /* amount of lowmem has changed */ - case IPCNS_CREATED: - case IPCNS_REMOVED: - /* - * It's time to recompute msgmni - */ - ns = container_of(self, struct ipc_namespace, ipcns_nb); - /* - * No need to get a reference on the ns: the 1st job of - * free_ipc_ns() is to unregister the callback routine. - * blocking_notifier_chain_unregister takes the wr lock to do - * it. - * When this callback routine is called the rd lock is held by - * blocking_notifier_call_chain. - * So the ipc ns cannot be freed while we are here. - */ - recompute_msgmni(ns); - break; - default: - break; - } - - return NOTIFY_OK; -} - -int register_ipcns_notifier(struct ipc_namespace *ns) -{ - int rc; - - memset(&ns->ipcns_nb, 0, sizeof(ns->ipcns_nb)); - ns->ipcns_nb.notifier_call = ipcns_callback; - ns->ipcns_nb.priority = IPCNS_CALLBACK_PRI; - rc = blocking_notifier_chain_register(&ipcns_chain, &ns->ipcns_nb); - if (!rc) - ns->auto_msgmni = 1; - return rc; -} - -int cond_register_ipcns_notifier(struct ipc_namespace *ns) -{ - int rc; - - memset(&ns->ipcns_nb, 0, sizeof(ns->ipcns_nb)); - ns->ipcns_nb.notifier_call = ipcns_callback; - ns->ipcns_nb.priority = IPCNS_CALLBACK_PRI; - rc = blocking_notifier_chain_cond_register(&ipcns_chain, - &ns->ipcns_nb); - if (!rc) - ns->auto_msgmni = 1; - return rc; -} - -void unregister_ipcns_notifier(struct ipc_namespace *ns) -{ - blocking_notifier_chain_unregister(&ipcns_chain, &ns->ipcns_nb); - ns->auto_msgmni = 0; -} - -int ipcns_notify(unsigned long val) -{ - return blocking_notifier_call_chain(&ipcns_chain, val, NULL); -} diff --git a/ipc/msg.c b/ipc/msg.c index c5d8e3749985..a7261d5cbc89 100644 --- a/ipc/msg.c +++ b/ipc/msg.c @@ -989,43 +989,12 @@ SYSCALL_DEFINE5(msgrcv, int, msqid, struct msgbuf __user *, msgp, size_t, msgsz, return do_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg, do_msg_fill); } -/* - * Scale msgmni with the available lowmem size: the memory dedicated to msg - * queues should occupy at most 1/MSG_MEM_SCALE of lowmem. - * Also take into account the number of nsproxies created so far. - * This should be done staying within the (MSGMNI , IPCMNI/nr_ipc_ns) range. - */ -void recompute_msgmni(struct ipc_namespace *ns) -{ - struct sysinfo i; - unsigned long allowed; - int nb_ns; - - si_meminfo(&i); - allowed = (((i.totalram - i.totalhigh) / MSG_MEM_SCALE) * i.mem_unit) - / MSGMNB; - nb_ns = atomic_read(&nr_ipc_ns); - allowed /= nb_ns; - - if (allowed < MSGMNI) { - ns->msg_ctlmni = MSGMNI; - return; - } - - if (allowed > IPCMNI / nb_ns) { - ns->msg_ctlmni = IPCMNI / nb_ns; - return; - } - - ns->msg_ctlmni = allowed; -} void msg_init_ns(struct ipc_namespace *ns) { ns->msg_ctlmax = MSGMAX; ns->msg_ctlmnb = MSGMNB; - - recompute_msgmni(ns); + ns->msg_ctlmni = MSGMNI; atomic_set(&ns->msg_bytes, 0); atomic_set(&ns->msg_hdrs, 0); @@ -1069,9 +1038,6 @@ void __init msg_init(void) { msg_init_ns(&init_ipc_ns); - printk(KERN_INFO "msgmni has been set to %d\n", - init_ipc_ns.msg_ctlmni); - ipc_init_proc_interface("sysvipc/msg", " key msqid perms cbytes qnum lspid lrpid uid gid cuid cgid stime rtime ctime\n", IPC_MSG_IDS, sysvipc_msg_proc_show); diff --git a/ipc/namespace.c b/ipc/namespace.c index b54468e48e32..1a3ffd40356e 100644 --- a/ipc/namespace.c +++ b/ipc/namespace.c @@ -45,14 +45,6 @@ static struct ipc_namespace *create_ipc_ns(struct user_namespace *user_ns, msg_init_ns(ns); shm_init_ns(ns); - /* - * msgmni has already been computed for the new ipc ns. - * Thus, do the ipcns creation notification before registering that - * new ipcns in the chain. - */ - ipcns_notify(IPCNS_CREATED); - register_ipcns_notifier(ns); - ns->user_ns = get_user_ns(user_ns); return ns; @@ -99,25 +91,11 @@ void free_ipcs(struct ipc_namespace *ns, struct ipc_ids *ids, static void free_ipc_ns(struct ipc_namespace *ns) { - /* - * Unregistering the hotplug notifier at the beginning guarantees - * that the ipc namespace won't be freed while we are inside the - * callback routine. Since the blocking_notifier_chain_XXX routines - * hold a rw lock on the notifier list, unregister_ipcns_notifier() - * won't take the rw lock before blocking_notifier_call_chain() has - * released the rd lock. - */ - unregister_ipcns_notifier(ns); sem_exit_ns(ns); msg_exit_ns(ns); shm_exit_ns(ns); atomic_dec(&nr_ipc_ns); - /* - * Do the ipcns removal notification after decrementing nr_ipc_ns in - * order to have a correct value when recomputing msgmni. - */ - ipcns_notify(IPCNS_REMOVED); put_user_ns(ns->user_ns); proc_free_inum(ns->proc_inum); kfree(ns); diff --git a/ipc/util.c b/ipc/util.c index 88adc329888c..106bed0378ab 100644 --- a/ipc/util.c +++ b/ipc/util.c @@ -71,44 +71,6 @@ struct ipc_proc_iface { int (*show)(struct seq_file *, void *); }; -static void ipc_memory_notifier(struct work_struct *work) -{ - ipcns_notify(IPCNS_MEMCHANGED); -} - -static int ipc_memory_callback(struct notifier_block *self, - unsigned long action, void *arg) -{ - static DECLARE_WORK(ipc_memory_wq, ipc_memory_notifier); - - switch (action) { - case MEM_ONLINE: /* memory successfully brought online */ - case MEM_OFFLINE: /* or offline: it's time to recompute msgmni */ - /* - * This is done by invoking the ipcns notifier chain with the - * IPC_MEMCHANGED event. - * In order not to keep the lock on the hotplug memory chain - * for too long, queue a work item that will, when waken up, - * activate the ipcns notification chain. - */ - schedule_work(&ipc_memory_wq); - break; - case MEM_GOING_ONLINE: - case MEM_GOING_OFFLINE: - case MEM_CANCEL_ONLINE: - case MEM_CANCEL_OFFLINE: - default: - break; - } - - return NOTIFY_OK; -} - -static struct notifier_block ipc_memory_nb = { - .notifier_call = ipc_memory_callback, - .priority = IPC_CALLBACK_PRI, -}; - /** * ipc_init - initialise ipc subsystem * @@ -124,8 +86,6 @@ static int __init ipc_init(void) sem_init(); msg_init(); shm_init(); - register_hotmemory_notifier(&ipc_memory_nb); - register_ipcns_notifier(&init_ipc_ns); return 0; } device_initcall(ipc_init); -- cgit v1.2.3-59-g8ed1b From 7d94a82e45157318568d839902f46b2085de9e90 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Fri, 12 Dec 2014 16:58:45 -0800 Subject: percpu: update local_ops.txt to reflect this_cpu operations Update the documentation to reflect changes due to the availability of this_cpu operations. Signed-off-by: Christoph Lameter Cc: Tejun Heo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/local_ops.txt | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/local_ops.txt b/Documentation/local_ops.txt index 300da4bdfdbd..407576a23317 100644 --- a/Documentation/local_ops.txt +++ b/Documentation/local_ops.txt @@ -8,6 +8,11 @@ to implement them for any given architecture and shows how they can be used properly. It also stresses on the precautions that must be taken when reading those local variables across CPUs when the order of memory writes matters. +Note that local_t based operations are not recommended for general kernel use. +Please use the this_cpu operations instead unless there is really a special purpose. +Most uses of local_t in the kernel have been replaced by this_cpu operations. +this_cpu operations combine the relocation with the local_t like semantics in +a single instruction and yield more compact and faster executing code. * Purpose of local atomic operations @@ -87,10 +92,10 @@ the per cpu variable. For instance : local_inc(&get_cpu_var(counters)); put_cpu_var(counters); -If you are already in a preemption-safe context, you can directly use -__get_cpu_var() instead. +If you are already in a preemption-safe context, you can use +this_cpu_ptr() instead. - local_inc(&__get_cpu_var(counters)); + local_inc(this_cpu_ptr(&counters)); @@ -134,7 +139,7 @@ static void test_each(void *info) { /* Increment the counter from a non preemptible context */ printk("Increment on cpu %d\n", smp_processor_id()); - local_inc(&__get_cpu_var(counters)); + local_inc(this_cpu_ptr(&counters)); /* This is what incrementing the variable would look like within a * preemptible context (it disables preemption) : -- cgit v1.2.3-59-g8ed1b From 29d293b6007b91a4463f05bc8d0b26e0e65c5816 Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Fri, 12 Dec 2014 16:58:50 -0800 Subject: cgroups: Documentation: fix trivial typos and wrong paragraph numberings Signed-off-by: SeongJae Park Cc: Jonathan Corbet Cc: Tejun Heo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/cgroups/cpusets.txt | 6 +++--- Documentation/cgroups/memory.txt | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'Documentation') diff --git a/Documentation/cgroups/cpusets.txt b/Documentation/cgroups/cpusets.txt index 3c94ff3f9693..f2235a162529 100644 --- a/Documentation/cgroups/cpusets.txt +++ b/Documentation/cgroups/cpusets.txt @@ -445,7 +445,7 @@ across partially overlapping sets of CPUs would risk unstable dynamics that would be beyond our understanding. So if each of two partially overlapping cpusets enables the flag 'cpuset.sched_load_balance', then we form a single sched domain that is a superset of both. We won't move -a task to a CPU outside it cpuset, but the scheduler load balancing +a task to a CPU outside its cpuset, but the scheduler load balancing code might waste some compute cycles considering that possibility. This mismatch is why there is not a simple one-to-one relation @@ -552,8 +552,8 @@ otherwise initial value -1 that indicates the cpuset has no request. 1 : search siblings (hyperthreads in a core). 2 : search cores in a package. 3 : search cpus in a node [= system wide on non-NUMA system] - ( 4 : search nodes in a chunk of node [on NUMA system] ) - ( 5 : search system wide [on NUMA system] ) + 4 : search nodes in a chunk of node [on NUMA system] + 5 : search system wide [on NUMA system] The system default is architecture dependent. The system default can be changed using the relax_domain_level= boot parameter. diff --git a/Documentation/cgroups/memory.txt b/Documentation/cgroups/memory.txt index 46b2b5080317..a22df3ad35ff 100644 --- a/Documentation/cgroups/memory.txt +++ b/Documentation/cgroups/memory.txt @@ -326,7 +326,7 @@ per cgroup, instead of globally. * tcp memory pressure: sockets memory pressure for the tcp protocol. -2.7.3 Common use cases +2.7.2 Common use cases Because the "kmem" counter is fed to the main user counter, kernel memory can never be limited completely independently of user memory. Say "U" is the user @@ -354,19 +354,19 @@ set: 3. User Interface -0. Configuration +3.0. Configuration a. Enable CONFIG_CGROUPS b. Enable CONFIG_MEMCG c. Enable CONFIG_MEMCG_SWAP (to use swap extension) d. Enable CONFIG_MEMCG_KMEM (to use kmem extension) -1. Prepare the cgroups (see cgroups.txt, Why are cgroups needed?) +3.1. Prepare the cgroups (see cgroups.txt, Why are cgroups needed?) # mount -t tmpfs none /sys/fs/cgroup # mkdir /sys/fs/cgroup/memory # mount -t cgroup none /sys/fs/cgroup/memory -o memory -2. Make the new group and move bash into it +3.2. Make the new group and move bash into it # mkdir /sys/fs/cgroup/memory/0 # echo $$ > /sys/fs/cgroup/memory/0/tasks -- cgit v1.2.3-59-g8ed1b From 470834508f87877f680738a10a305280582c7aed Mon Sep 17 00:00:00 2001 From: Neelesh Gupta Date: Sat, 13 Dec 2014 23:31:05 +0530 Subject: i2c: Driver to expose PowerNV platform i2c busses The patch exposes the available i2c busses on the PowerNV platform to the kernel and implements the bus driver to support i2c and smbus commands. The driver uses the platform device infrastructure to probe the busses on the platform and registers them with the i2c driver framework. Signed-off-by: Neelesh Gupta Signed-off-by: Benjamin Herrenschmidt Acked-by: Wolfram Sang (I2C part, excluding the bindings) Signed-off-by: Michael Ellerman --- Documentation/devicetree/bindings/i2c/i2c-opal.txt | 37 +++ arch/powerpc/include/asm/opal.h | 29 ++ arch/powerpc/platforms/powernv/opal-wrappers.S | 1 + arch/powerpc/platforms/powernv/opal.c | 12 + drivers/i2c/busses/Kconfig | 11 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-opal.c | 294 +++++++++++++++++++++ 7 files changed, 385 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/i2c-opal.txt create mode 100644 drivers/i2c/busses/i2c-opal.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/i2c/i2c-opal.txt b/Documentation/devicetree/bindings/i2c/i2c-opal.txt new file mode 100644 index 000000000000..12bc61465ee5 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-opal.txt @@ -0,0 +1,37 @@ +Device-tree bindings for I2C OPAL driver +---------------------------------------- + +Most of the device node and properties layout is specific to the firmware and +used by the firmware itself for configuring the port. From the linux +perspective, the properties of use are "ibm,port-name" and "ibm,opal-id". + +Required properties: + +- reg: Port-id within a given master +- compatible: must be "ibm,opal-i2c" +- ibm,opal-id: Refers to a specific bus and used to identify it when calling + the relevant OPAL functions. +- bus-frequency: Operating frequency of the i2c bus (in HZ). Informational for + linux, used by the FW though. + +Optional properties: +- ibm,port-name: Firmware provides this name that uniquely identifies the i2c + port. + +The node contains a number of other properties that are used by the FW itself +and depend on the specific hardware implementation. The example below depicts +a P8 on-chip bus. + +Example: + +i2c-bus@0 { + reg = <0x0>; + bus-frequency = <0x61a80>; + compatible = "ibm,power8-i2c-port", "ibm,opal-i2c"; + ibm,opal-id = <0x1>; + ibm,port-name = "p8_00000000_e1p0"; + #address-cells = <0x1>; + phandle = <0x10000006>; + #size-cells = <0x0>; + linux,phandle = <0x10000006>; +}; diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h index 5cd8d2fddba9..4095749c973f 100644 --- a/arch/powerpc/include/asm/opal.h +++ b/arch/powerpc/include/asm/opal.h @@ -56,6 +56,14 @@ struct opal_sg_list { #define OPAL_HARDWARE_FROZEN -13 #define OPAL_WRONG_STATE -14 #define OPAL_ASYNC_COMPLETION -15 +#define OPAL_I2C_TIMEOUT -17 +#define OPAL_I2C_INVALID_CMD -18 +#define OPAL_I2C_LBUS_PARITY -19 +#define OPAL_I2C_BKEND_OVERRUN -20 +#define OPAL_I2C_BKEND_ACCESS -21 +#define OPAL_I2C_ARBT_LOST -22 +#define OPAL_I2C_NACK_RCVD -23 +#define OPAL_I2C_STOP_ERR -24 /* API Tokens (in r0) */ #define OPAL_INVALID_CALL -1 @@ -158,6 +166,7 @@ struct opal_sg_list { #define OPAL_READ_TPO 104 #define OPAL_IPMI_SEND 107 #define OPAL_IPMI_RECV 108 +#define OPAL_I2C_REQUEST 109 #ifndef __ASSEMBLY__ @@ -712,6 +721,24 @@ typedef struct oppanel_line { uint64_t line_len; } oppanel_line_t; +/* OPAL I2C request */ +struct opal_i2c_request { + uint8_t type; +#define OPAL_I2C_RAW_READ 0 +#define OPAL_I2C_RAW_WRITE 1 +#define OPAL_I2C_SM_READ 2 +#define OPAL_I2C_SM_WRITE 3 + uint8_t flags; +#define OPAL_I2C_ADDR_10 0x01 /* Not supported yet */ + uint8_t subaddr_sz; /* Max 4 */ + uint8_t reserved; + __be16 addr; /* 7 or 10 bit address */ + __be16 reserved2; + __be32 subaddr; /* Sub-address if any */ + __be32 size; /* Data size */ + __be64 buffer_ra; /* Buffer real address */ +}; + /* /sys/firmware/opal */ extern struct kobject *opal_kobj; @@ -881,6 +908,8 @@ int64_t opal_ipmi_send(uint64_t interface, struct opal_ipmi_msg *msg, uint64_t msg_len); int64_t opal_ipmi_recv(uint64_t interface, struct opal_ipmi_msg *msg, uint64_t *msg_len); +int64_t opal_i2c_request(uint64_t async_token, uint32_t bus_id, + struct opal_i2c_request *oreq); /* Internal functions */ extern int early_init_dt_scan_opal(unsigned long node, const char *uname, diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S index 0a299be588af..2111e08d406b 100644 --- a/arch/powerpc/platforms/powernv/opal-wrappers.S +++ b/arch/powerpc/platforms/powernv/opal-wrappers.S @@ -254,3 +254,4 @@ OPAL_CALL(opal_tpo_write, OPAL_WRITE_TPO); OPAL_CALL(opal_tpo_read, OPAL_READ_TPO); OPAL_CALL(opal_ipmi_send, OPAL_IPMI_SEND); OPAL_CALL(opal_ipmi_recv, OPAL_IPMI_RECV); +OPAL_CALL(opal_i2c_request, OPAL_I2C_REQUEST); diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c index cb0b6de79cd4..aa316d820736 100644 --- a/arch/powerpc/platforms/powernv/opal.c +++ b/arch/powerpc/platforms/powernv/opal.c @@ -653,6 +653,14 @@ static void opal_ipmi_init(struct device_node *opal_node) of_platform_device_create(np, NULL, NULL); } +static void opal_i2c_create_devs(void) +{ + struct device_node *np; + + for_each_compatible_node(np, NULL, "ibm,opal-i2c") + of_platform_device_create(np, NULL, NULL); +} + static int __init opal_init(void) { struct device_node *np, *consoles; @@ -679,6 +687,9 @@ static int __init opal_init(void) of_node_put(consoles); } + /* Create i2c platform devices */ + opal_i2c_create_devs(); + /* Find all OPAL interrupts and request them */ irqs = of_get_property(opal_node, "opal-interrupts", &irqlen); pr_debug("opal: Found %d interrupts reserved for OPAL\n", @@ -824,3 +835,4 @@ EXPORT_SYMBOL_GPL(opal_rtc_read); EXPORT_SYMBOL_GPL(opal_rtc_write); EXPORT_SYMBOL_GPL(opal_tpo_read); EXPORT_SYMBOL_GPL(opal_tpo_write); +EXPORT_SYMBOL_GPL(opal_i2c_request); diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 917c3585f45b..71ad6e11efb7 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -1044,4 +1044,15 @@ config SCx200_ACB This support is also available as a module. If so, the module will be called scx200_acb. +config I2C_OPAL + tristate "IBM OPAL I2C driver" + depends on PPC_POWERNV + default y + help + This exposes the PowerNV platform i2c busses to the linux i2c layer, + the driver is based on the OPAL interfaces. + + This driver can also be built as a module. If so, the module will be + called as i2c-opal. + endmenu diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 78d56c54ba2b..e23ec815e21f 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -99,6 +99,7 @@ obj-$(CONFIG_I2C_ACORN) += i2c-acorn.o obj-$(CONFIG_I2C_BCM_KONA) += i2c-bcm-kona.o obj-$(CONFIG_I2C_CROS_EC_TUNNEL) += i2c-cros-ec-tunnel.o obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o +obj-$(CONFIG_I2C_OPAL) += i2c-opal.o obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o obj-$(CONFIG_SCx200_ACB) += scx200_acb.o diff --git a/drivers/i2c/busses/i2c-opal.c b/drivers/i2c/busses/i2c-opal.c new file mode 100644 index 000000000000..16f90b1a7508 --- /dev/null +++ b/drivers/i2c/busses/i2c-opal.c @@ -0,0 +1,294 @@ +/* + * IBM OPAL I2C driver + * Copyright (C) 2014 IBM + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static int i2c_opal_translate_error(int rc) +{ + switch (rc) { + case OPAL_NO_MEM: + return -ENOMEM; + case OPAL_PARAMETER: + return -EINVAL; + case OPAL_I2C_ARBT_LOST: + return -EAGAIN; + case OPAL_I2C_TIMEOUT: + return -ETIMEDOUT; + case OPAL_I2C_NACK_RCVD: + return -ENXIO; + case OPAL_I2C_STOP_ERR: + return -EBUSY; + default: + return -EIO; + } +} + +static int i2c_opal_send_request(u32 bus_id, struct opal_i2c_request *req) +{ + struct opal_msg msg; + int token, rc; + + token = opal_async_get_token_interruptible(); + if (token < 0) { + if (token != -ERESTARTSYS) + pr_err("Failed to get the async token\n"); + + return token; + } + + rc = opal_i2c_request(token, bus_id, req); + if (rc != OPAL_ASYNC_COMPLETION) { + rc = i2c_opal_translate_error(rc); + goto exit; + } + + rc = opal_async_wait_response(token, &msg); + if (rc) + goto exit; + + rc = be64_to_cpu(msg.params[1]); + if (rc != OPAL_SUCCESS) { + rc = i2c_opal_translate_error(rc); + goto exit; + } + +exit: + opal_async_release_token(token); + return rc; +} + +static int i2c_opal_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + int num) +{ + unsigned long opal_id = (unsigned long)adap->algo_data; + struct opal_i2c_request req; + int rc, i; + + /* We only support fairly simple combinations here of one + * or two messages + */ + memset(&req, 0, sizeof(req)); + switch(num) { + case 0: + return 0; + case 1: + req.type = (msgs[0].flags & I2C_M_RD) ? + OPAL_I2C_RAW_READ : OPAL_I2C_RAW_WRITE; + req.addr = cpu_to_be16(msgs[0].addr); + req.size = cpu_to_be32(msgs[0].len); + req.buffer_ra = cpu_to_be64(__pa(msgs[0].buf)); + break; + case 2: + /* For two messages, we basically support only simple + * smbus transactions of a write plus a read. We might + * want to allow also two writes but we'd have to bounce + * the data into a single buffer. + */ + if ((msgs[0].flags & I2C_M_RD) || !(msgs[1].flags & I2C_M_RD)) + return -EOPNOTSUPP; + if (msgs[0].len > 4) + return -EOPNOTSUPP; + if (msgs[0].addr != msgs[1].addr) + return -EOPNOTSUPP; + req.type = OPAL_I2C_SM_READ; + req.addr = cpu_to_be16(msgs[0].addr); + req.subaddr_sz = msgs[0].len; + for (i = 0; i < msgs[0].len; i++) + req.subaddr = (req.subaddr << 8) | msgs[0].buf[i]; + req.subaddr = cpu_to_be32(req.subaddr); + req.size = cpu_to_be32(msgs[1].len); + req.buffer_ra = cpu_to_be64(__pa(msgs[1].buf)); + break; + default: + return -EOPNOTSUPP; + } + + rc = i2c_opal_send_request(opal_id, &req); + if (rc) + return rc; + + return num; +} + +static int i2c_opal_smbus_xfer(struct i2c_adapter *adap, u16 addr, + unsigned short flags, char read_write, + u8 command, int size, union i2c_smbus_data *data) +{ + unsigned long opal_id = (unsigned long)adap->algo_data; + struct opal_i2c_request req; + u8 local[2]; + int rc; + + memset(&req, 0, sizeof(req)); + + req.addr = cpu_to_be16(addr); + switch (size) { + case I2C_SMBUS_BYTE: + req.buffer_ra = cpu_to_be64(__pa(&data->byte)); + req.size = cpu_to_be32(1); + /* Fall through */ + case I2C_SMBUS_QUICK: + req.type = (read_write == I2C_SMBUS_READ) ? + OPAL_I2C_RAW_READ : OPAL_I2C_RAW_WRITE; + break; + case I2C_SMBUS_BYTE_DATA: + req.buffer_ra = cpu_to_be64(__pa(&data->byte)); + req.size = cpu_to_be32(1); + req.subaddr = cpu_to_be32(command); + req.subaddr_sz = 1; + req.type = (read_write == I2C_SMBUS_READ) ? + OPAL_I2C_SM_READ : OPAL_I2C_SM_WRITE; + break; + case I2C_SMBUS_WORD_DATA: + if (!read_write) { + local[0] = data->word & 0xff; + local[1] = (data->word >> 8) & 0xff; + } + req.buffer_ra = cpu_to_be64(__pa(local)); + req.size = cpu_to_be32(2); + req.subaddr = cpu_to_be32(command); + req.subaddr_sz = 1; + req.type = (read_write == I2C_SMBUS_READ) ? + OPAL_I2C_SM_READ : OPAL_I2C_SM_WRITE; + break; + case I2C_SMBUS_I2C_BLOCK_DATA: + req.buffer_ra = cpu_to_be64(__pa(&data->block[1])); + req.size = cpu_to_be32(data->block[0]); + req.subaddr = cpu_to_be32(command); + req.subaddr_sz = 1; + req.type = (read_write == I2C_SMBUS_READ) ? + OPAL_I2C_SM_READ : OPAL_I2C_SM_WRITE; + break; + default: + return -EINVAL; + } + + rc = i2c_opal_send_request(opal_id, &req); + if (!rc && read_write && size == I2C_SMBUS_WORD_DATA) { + data->word = ((u16)local[1]) << 8; + data->word |= local[0]; + } + + return rc; +} + +static u32 i2c_opal_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_I2C_BLOCK; +} + +static const struct i2c_algorithm i2c_opal_algo = { + .master_xfer = i2c_opal_master_xfer, + .smbus_xfer = i2c_opal_smbus_xfer, + .functionality = i2c_opal_func, +}; + +static int i2c_opal_probe(struct platform_device *pdev) +{ + struct i2c_adapter *adapter; + const char *pname; + u32 opal_id; + int rc; + + if (!pdev->dev.of_node) + return -ENODEV; + + rc = of_property_read_u32(pdev->dev.of_node, "ibm,opal-id", &opal_id); + if (rc) { + dev_err(&pdev->dev, "Missing ibm,opal-id property !\n"); + return -EIO; + } + + adapter = devm_kzalloc(&pdev->dev, sizeof(*adapter), GFP_KERNEL); + if (!adapter) + return -ENOMEM; + + adapter->algo = &i2c_opal_algo; + adapter->algo_data = (void *)(unsigned long)opal_id; + adapter->dev.parent = &pdev->dev; + adapter->dev.of_node = of_node_get(pdev->dev.of_node); + pname = of_get_property(pdev->dev.of_node, "ibm,port-name", NULL); + if (pname) + strlcpy(adapter->name, pname, sizeof(adapter->name)); + else + strlcpy(adapter->name, "opal", sizeof(adapter->name)); + + platform_set_drvdata(pdev, adapter); + rc = i2c_add_adapter(adapter); + if (rc) + dev_err(&pdev->dev, "Failed to register the i2c adapter\n"); + + return rc; +} + +static int i2c_opal_remove(struct platform_device *pdev) +{ + struct i2c_adapter *adapter = platform_get_drvdata(pdev); + + i2c_del_adapter(adapter); + + return 0; +} + +static const struct of_device_id i2c_opal_of_match[] = { + { + .compatible = "ibm,opal-i2c", + }, + { } +}; +MODULE_DEVICE_TABLE(of, i2c_opal_of_match); + +static struct platform_driver i2c_opal_driver = { + .probe = i2c_opal_probe, + .remove = i2c_opal_remove, + .driver = { + .name = "i2c-opal", + .of_match_table = i2c_opal_of_match, + }, +}; + +static int __init i2c_opal_init(void) +{ + if (!firmware_has_feature(FW_FEATURE_OPAL)) + return -ENODEV; + + return platform_driver_register(&i2c_opal_driver); +} +module_init(i2c_opal_init); + +static void __exit i2c_opal_exit(void) +{ + return platform_driver_unregister(&i2c_opal_driver); +} +module_exit(i2c_opal_exit); + +MODULE_AUTHOR("Neelesh Gupta "); +MODULE_DESCRIPTION("IBM OPAL I2C driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-59-g8ed1b From 010e593b140decdc16bb0c1c754b07b1fccb6999 Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Fri, 12 Dec 2014 10:38:35 -0800 Subject: x86, mpx: Update documentation I was writing some MPX test programs and realized that the current design makes it tricky. I did something like: bndcfgu |= bnd_dir | BNDCFGU_ENABLE; xrstor(); printf("xrstor done"); // #BR bounds exception here prctl(MPX_ENABLE_MANAGEMENT); and then compiled the app with "-fcheck-pointer-bounds -mmpx" to enable MPX instrumentation. The problem is that there is MPX instrumentation inserted in to the area of the printf(). The kernel gets a bounds exception and since management isn't yet enabled, it SIGSEGV's. Add a bit to the documentation to explain a way around this and where apps need to be careful. Signed-off-by: Dave Hansen Cc: Dave Hansen Link: http://lkml.kernel.org/r/20141212183835.8C581B3E@viggo.jf.intel.com Signed-off-by: Thomas Gleixner --- Documentation/x86/intel_mpx.txt | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/x86/intel_mpx.txt b/Documentation/x86/intel_mpx.txt index 4472ed2ad921..6ca6e2bd9ae9 100644 --- a/Documentation/x86/intel_mpx.txt +++ b/Documentation/x86/intel_mpx.txt @@ -30,9 +30,15 @@ is how we expect the compiler, application and kernel to work together. instrumentation as well as some setup code called early after the app starts. New instruction prefixes are noops for old CPUs. 2) That setup code allocates (virtual) space for the "bounds directory", - points the "bndcfgu" register to the directory and notifies the kernel - (via the new prctl(PR_MPX_ENABLE_MANAGEMENT)) that the app will be using - MPX. + points the "bndcfgu" register to the directory (must also set the valid + bit) and notifies the kernel (via the new prctl(PR_MPX_ENABLE_MANAGEMENT)) + that the app will be using MPX. The app must be careful not to access + the bounds tables between the time when it populates "bndcfgu" and + when it calls the prctl(). This might be hard to guarantee if the app + is compiled with MPX. You can add "__attribute__((bnd_legacy))" to + the function to disable MPX instrumentation to help guarantee this. + Also be careful not to call out to any other code which might be + MPX-instrumented. 3) The kernel detects that the CPU has MPX, allows the new prctl() to succeed, and notes the location of the bounds directory. Userspace is expected to keep the bounds directory at that locationWe note it -- cgit v1.2.3-59-g8ed1b From 72e9b5fe9bee0826e7ce7599adbdc64e544780ef Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Fri, 12 Dec 2014 10:38:36 -0800 Subject: x86, mpx: Give MPX a real config option prompt Give MPX a real config option. The CPUs that support it (referenced here): https://software.intel.com/en-us/forums/topic/402393 are not available publicly yet. Right now only the software emulator provides MPX for the general public. [ tglx: Make it default off. There is no point in having it on right now as no hardware and no proper tooling support are available ] Signed-off-by: Dave Hansen Cc: Dave Hansen Link: http://lkml.kernel.org/r/20141212183836.2569D58D@viggo.jf.intel.com Signed-off-by: Thomas Gleixner --- Documentation/x86/intel_mpx.txt | 6 +++++- arch/x86/Kconfig | 30 ++++++++++++++++++++++++++---- 2 files changed, 31 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/x86/intel_mpx.txt b/Documentation/x86/intel_mpx.txt index 6ca6e2bd9ae9..818518a3ff01 100644 --- a/Documentation/x86/intel_mpx.txt +++ b/Documentation/x86/intel_mpx.txt @@ -7,11 +7,15 @@ that can be used in conjunction with compiler changes to check memory references, for those references whose compile-time normal intentions are usurped at runtime due to buffer overflow or underflow. +You can tell if your CPU supports MPX by looking in /proc/cpuinfo: + + cat /proc/cpuinfo | grep ' mpx ' + For more information, please refer to Intel(R) Architecture Instruction Set Extensions Programming Reference, Chapter 9: Intel(R) Memory Protection Extensions. -Note: Currently no hardware with MPX ISA is available but it is always +Note: As of December 2014, no hardware with MPX is available but it is possible to use SDE (Intel(R) Software Development Emulator) instead, which can be downloaded from http://software.intel.com/en-us/articles/intel-software-development-emulator diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 967dfe0ba85e..cc91e5e55d13 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -248,10 +248,6 @@ config HAVE_INTEL_TXT def_bool y depends on INTEL_IOMMU && ACPI -config X86_INTEL_MPX - def_bool y - depends on CPU_SUP_INTEL - config X86_32_SMP def_bool y depends on X86_32 && SMP @@ -1575,6 +1571,32 @@ config X86_SMAP If unsure, say Y. +config X86_INTEL_MPX + prompt "Intel MPX (Memory Protection Extensions)" + def_bool n + depends on CPU_SUP_INTEL + ---help--- + MPX provides hardware features that can be used in + conjunction with compiler-instrumented code to check + memory references. It is designed to detect buffer + overflow or underflow bugs. + + This option enables running applications which are + instrumented or otherwise use MPX. It does not use MPX + itself inside the kernel or to protect the kernel + against bad memory references. + + Enabling this option will make the kernel larger: + ~8k of kernel text and 36 bytes of data on a 64-bit + defconfig. It adds a long to the 'mm_struct' which + will increase the kernel memory overhead of each + process and adds some branches to paths used during + exec() and munmap(). + + For details, see Documentation/x86/intel_mpx.txt + + If unsure, say N. + config EFI bool "EFI runtime service support" depends on ACPI -- cgit v1.2.3-59-g8ed1b From 0daa2302968c13b657118d6ac92471f8fd2f3f28 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Fri, 12 Dec 2014 22:27:10 -0500 Subject: tracing: Add tp_printk cmdline to have tracepoints go to printk() Add the kernel command line tp_printk option that will have tracepoints that are active sent to printk() as well as to the trace buffer. Passing "tp_printk" will activate this. To turn it off, the sysctl /proc/sys/kernel/tracepoint_printk can have '0' echoed into it. Note, this only works if the cmdline option is used. Echoing 1 into the sysctl file without the cmdline option will have no affect. Note, this is a dangerous option. Having high frequency tracepoints send their data to printk() can possibly cause a live lock. This is another reason why this is only active if the command line option is used. Link: http://lkml.kernel.org/r/alpine.DEB.2.11.1412121539300.16494@nanos Suggested-by: Thomas Gleixner Tested-by: Thomas Gleixner Acked-by: Thomas Gleixner Signed-off-by: Steven Rostedt --- Documentation/kernel-parameters.txt | 18 ++++++++++++++++++ include/linux/ftrace.h | 1 + kernel/sysctl.c | 7 +++++++ kernel/trace/trace.c | 17 +++++++++++++++++ kernel/trace/trace.h | 1 + kernel/trace/trace_events.c | 32 ++++++++++++++++++++++++++++++++ 6 files changed, 76 insertions(+) (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 1d09eb37c562..ae41f1181e9a 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -3500,6 +3500,24 @@ bytes respectively. Such letter suffixes can also be entirely omitted. See also Documentation/trace/ftrace.txt "trace options" section. + tp_printk[FTRACE] + Have the tracepoints sent to printk as well as the + tracing ring buffer. This is useful for early boot up + where the system hangs or reboots and does not give the + option for reading the tracing buffer or performing a + ftrace_dump_on_oops. + + To turn off having tracepoints sent to printk, + echo 0 > /proc/sys/kernel/tracepoint_printk + Note, echoing 1 into this file without the + tracepoint_printk kernel cmdline option has no effect. + + ** CAUTION ** + + Having tracepoints sent to printk() and activating high + frequency tracepoints such as irq or sched, can cause + the system to live lock. + traceoff_on_warning [FTRACE] enable this option to disable tracing when a warning is hit. This turns off "tracing_on". Tracing can diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index f4bc14b7d444..1da602982cf9 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h @@ -879,6 +879,7 @@ static inline int test_tsk_trace_graph(struct task_struct *tsk) enum ftrace_dump_mode; extern enum ftrace_dump_mode ftrace_dump_on_oops; +extern int tracepoint_printk; extern void disable_trace_on_warning(void); extern int __disable_trace_on_warning; diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 4aada6d9fe74..bb50c2187194 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -622,6 +622,13 @@ static struct ctl_table kern_table[] = { .mode = 0644, .proc_handler = proc_dointvec, }, + { + .procname = "tracepoint_printk", + .data = &tracepoint_printk, + .maxlen = sizeof(tracepoint_printk), + .mode = 0644, + .proc_handler = proc_dointvec, + }, #endif #ifdef CONFIG_KEXEC { diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index ec3ca694665f..e890d2d4ec89 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -63,6 +63,10 @@ static bool __read_mostly tracing_selftest_running; */ bool __read_mostly tracing_selftest_disabled; +/* Pipe tracepoints to printk */ +struct trace_iterator *tracepoint_print_iter; +int tracepoint_printk; + /* For tracers that don't implement custom flags */ static struct tracer_opt dummy_tracer_opt[] = { { } @@ -193,6 +197,13 @@ static int __init set_trace_boot_clock(char *str) } __setup("trace_clock=", set_trace_boot_clock); +static int __init set_tracepoint_printk(char *str) +{ + if ((strcmp(str, "=0") != 0 && strcmp(str, "=off") != 0)) + tracepoint_printk = 1; + return 1; +} +__setup("tp_printk", set_tracepoint_printk); unsigned long long ns2usecs(cycle_t nsec) { @@ -6878,6 +6889,12 @@ out: void __init trace_init(void) { + if (tracepoint_printk) { + tracepoint_print_iter = + kmalloc(sizeof(*tracepoint_print_iter), GFP_KERNEL); + if (WARN_ON(!tracepoint_print_iter)) + tracepoint_printk = 0; + } tracer_alloc_buffers(); init_ftrace_syscalls(); trace_event_init(); diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index c138c149d6ef..8de48bac1ce2 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -1313,5 +1313,6 @@ void trace_event_init(void); static inline void __init trace_event_init(void) { } #endif +extern struct trace_iterator *tracepoint_print_iter; #endif /* _LINUX_KERNEL_TRACE_H */ diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index fd9deb0e03f0..9f7175a3df71 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -212,8 +212,40 @@ void *ftrace_event_buffer_reserve(struct ftrace_event_buffer *fbuffer, } EXPORT_SYMBOL_GPL(ftrace_event_buffer_reserve); +static DEFINE_SPINLOCK(tracepoint_iter_lock); + +static void output_printk(struct ftrace_event_buffer *fbuffer) +{ + struct ftrace_event_call *event_call; + struct trace_event *event; + unsigned long flags; + struct trace_iterator *iter = tracepoint_print_iter; + + if (!iter) + return; + + event_call = fbuffer->ftrace_file->event_call; + if (!event_call || !event_call->event.funcs || + !event_call->event.funcs->trace) + return; + + event = &fbuffer->ftrace_file->event_call->event; + + spin_lock_irqsave(&tracepoint_iter_lock, flags); + trace_seq_init(&iter->seq); + iter->ent = fbuffer->entry; + event_call->event.funcs->trace(iter, 0, event); + trace_seq_putc(&iter->seq, 0); + printk("%s", iter->seq.buffer); + + spin_unlock_irqrestore(&tracepoint_iter_lock, flags); +} + void ftrace_event_buffer_commit(struct ftrace_event_buffer *fbuffer) { + if (tracepoint_printk) + output_printk(fbuffer); + event_trigger_unlock_commit(fbuffer->ftrace_file, fbuffer->buffer, fbuffer->event, fbuffer->entry, fbuffer->flags, fbuffer->pc); -- cgit v1.2.3-59-g8ed1b From fd223068fc3467e10ecbba52e1bdb10aad3988b3 Mon Sep 17 00:00:00 2001 From: Duan Jiong Date: Mon, 15 Dec 2014 14:58:53 +0800 Subject: fib_trie.txt: fix typo Fix the typo, there should be "It". On the other hand, fix whitespace errors detected by checkpatch.pl Signed-off-by: Duan Jiong Signed-off-by: David S. Miller --- Documentation/networking/fib_trie.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/fib_trie.txt b/Documentation/networking/fib_trie.txt index 0723db7f8495..fe719388518b 100644 --- a/Documentation/networking/fib_trie.txt +++ b/Documentation/networking/fib_trie.txt @@ -73,8 +73,8 @@ trie_leaf_remove() trie_rebalance() The key function for the dynamic trie after any change in the trie - it is run to optimize and reorganize. Tt will walk the trie upwards - towards the root from a given tnode, doing a resize() at each step + it is run to optimize and reorganize. It will walk the trie upwards + towards the root from a given tnode, doing a resize() at each step to implement level compression. resize() -- cgit v1.2.3-59-g8ed1b From 97d86e07b71643086a6d22a60efae2fb095fa82a Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 14 Nov 2014 15:57:09 -0800 Subject: Input: gpio_keys - allow separating gpio and irq in device tree This change allows specify interrupt for buttons separately form gpio, potentially allowing to form several "clusters" of buttons on different interrupts. Button defined without both gpio and irq in device tree is a hared error instead of a warning now. Tested-by: Andy Shevchenko Reviewed-by: Linus Walleij Signed-off-by: Dmitry Torokhov --- .../devicetree/bindings/input/gpio-keys.txt | 10 +++-- drivers/input/keyboard/gpio_keys.c | 49 ++++++++++++---------- 2 files changed, 33 insertions(+), 26 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/input/gpio-keys.txt b/Documentation/devicetree/bindings/input/gpio-keys.txt index a4a38fcf2ed6..44b705767aca 100644 --- a/Documentation/devicetree/bindings/input/gpio-keys.txt +++ b/Documentation/devicetree/bindings/input/gpio-keys.txt @@ -10,12 +10,13 @@ Optional properties: Each button (key) is represented as a sub-node of "gpio-keys": Subnode properties: + - gpios: OF device-tree gpio specification. + - interrupts: the interrupt line for that input. - label: Descriptive name of the key. - linux,code: Keycode to emit. -Required mutual exclusive subnode-properties: - - gpios: OF device-tree gpio specification. - - interrupts: the interrupt line for that input +Note that either "interrupts" or "gpios" properties can be omitted, but not +both at the same time. Specifying both properties is allowed. Optional subnode-properties: - linux,input-type: Specify event type this button/key generates. @@ -23,6 +24,9 @@ Optional subnode-properties: - debounce-interval: Debouncing interval time in milliseconds. If not specified defaults to 5. - gpio-key,wakeup: Boolean, button can wake-up the system. + - linux,can-disable: Boolean, indicates that button is connected + to dedicated (not shared) interrupt which can be disabled to + suppress events from the button. Example nodes: diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index f44f05b70ee0..a5ece3ff19cb 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -470,15 +470,19 @@ static int gpio_keys_setup_key(struct platform_device *pdev, button->debounce_interval; } - irq = gpio_to_irq(button->gpio); - if (irq < 0) { - error = irq; - dev_err(dev, - "Unable to get irq number for GPIO %d, error %d\n", - button->gpio, error); - return error; + if (button->irq) { + bdata->irq = button->irq; + } else { + irq = gpio_to_irq(button->gpio); + if (irq < 0) { + error = irq; + dev_err(dev, + "Unable to get irq number for GPIO %d, error %d\n", + button->gpio, error); + return error; + } + bdata->irq = irq; } - bdata->irq = irq; INIT_WORK(&bdata->work, gpio_keys_gpio_work_func); setup_timer(&bdata->timer, @@ -618,33 +622,30 @@ gpio_keys_get_devtree_pdata(struct device *dev) i = 0; for_each_child_of_node(node, pp) { - int gpio = -1; enum of_gpio_flags flags; button = &pdata->buttons[i++]; - if (!of_find_property(pp, "gpios", NULL)) { - button->irq = irq_of_parse_and_map(pp, 0); - if (button->irq == 0) { - i--; - pdata->nbuttons--; - dev_warn(dev, "Found button without gpios or irqs\n"); - continue; - } - } else { - gpio = of_get_gpio_flags(pp, 0, &flags); - if (gpio < 0) { - error = gpio; + button->gpio = of_get_gpio_flags(pp, 0, &flags); + if (button->gpio < 0) { + error = button->gpio; + if (error != -ENOENT) { if (error != -EPROBE_DEFER) dev_err(dev, "Failed to get gpio flags, error: %d\n", error); return ERR_PTR(error); } + } else { + button->active_low = flags & OF_GPIO_ACTIVE_LOW; } - button->gpio = gpio; - button->active_low = flags & OF_GPIO_ACTIVE_LOW; + button->irq = irq_of_parse_and_map(pp, 0); + + if (!gpio_is_valid(button->gpio) && !button->irq) { + dev_err(dev, "Found button without gpios or irqs\n"); + return ERR_PTR(-EINVAL); + } if (of_property_read_u32(pp, "linux,code", &button->code)) { dev_err(dev, "Button without keycode: 0x%x\n", @@ -659,6 +660,8 @@ gpio_keys_get_devtree_pdata(struct device *dev) button->wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL); + button->can_disable = !!of_get_property(pp, "linux,can-disable", NULL); + if (of_property_read_u32(pp, "debounce-interval", &button->debounce_interval)) button->debounce_interval = 5; -- cgit v1.2.3-59-g8ed1b From a4164863e150c4991d2ac965e3fc52f9d8df3d7e Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 3 Nov 2014 16:51:26 -0800 Subject: Input: stmpe - enforce device tree only mode The STMPE keypad controller is only used with device tree configured systems, so force the configuration to come from device tree only, and now actually get the rows and cols from the device tree too. Signed-off-by: Linus Walleij Acked-by: Lee Jones Signed-off-by: Dmitry Torokhov --- .../devicetree/bindings/input/stmpe-keypad.txt | 2 + drivers/input/keyboard/Kconfig | 1 + drivers/input/keyboard/stmpe-keypad.c | 104 +++++++++------------ include/linux/mfd/stmpe.h | 20 ---- 4 files changed, 48 insertions(+), 79 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/input/stmpe-keypad.txt b/Documentation/devicetree/bindings/input/stmpe-keypad.txt index 1b97222e8a0b..12bb771d66d4 100644 --- a/Documentation/devicetree/bindings/input/stmpe-keypad.txt +++ b/Documentation/devicetree/bindings/input/stmpe-keypad.txt @@ -8,6 +8,8 @@ Optional properties: - debounce-interval : Debouncing interval time in milliseconds - st,scan-count : Scanning cycles elapsed before key data is updated - st,no-autorepeat : If specified device will not autorepeat + - keypad,num-rows : See ./matrix-keymap.txt + - keypad,num-columns : See ./matrix-keymap.txt Example: diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 96ee26c555e0..a5d9b3f3c871 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -559,6 +559,7 @@ config KEYBOARD_SH_KEYSC config KEYBOARD_STMPE tristate "STMPE keypad support" depends on MFD_STMPE + depends on OF select INPUT_MATRIXKMAP help Say Y here if you want to use the keypad controller on STMPE I/O diff --git a/drivers/input/keyboard/stmpe-keypad.c b/drivers/input/keyboard/stmpe-keypad.c index c6727dda68f2..8d1e7af3c5b1 100644 --- a/drivers/input/keyboard/stmpe-keypad.c +++ b/drivers/input/keyboard/stmpe-keypad.c @@ -45,7 +45,7 @@ #define STMPE_KEYPAD_MAX_ROWS 8 #define STMPE_KEYPAD_MAX_COLS 8 #define STMPE_KEYPAD_ROW_SHIFT 3 -#define STMPE_KEYPAD_KEYMAP_SIZE \ +#define STMPE_KEYPAD_KEYMAP_MAX_SIZE \ (STMPE_KEYPAD_MAX_ROWS * STMPE_KEYPAD_MAX_COLS) /** @@ -99,16 +99,30 @@ static const struct stmpe_keypad_variant stmpe_keypad_variants[] = { }, }; +/** + * struct stmpe_keypad - STMPE keypad state container + * @stmpe: pointer to parent STMPE device + * @input: spawned input device + * @variant: STMPE variant + * @debounce_ms: debounce interval, in ms. Maximum is + * %STMPE_KEYPAD_MAX_DEBOUNCE. + * @scan_count: number of key scanning cycles to confirm key data. + * Maximum is %STMPE_KEYPAD_MAX_SCAN_COUNT. + * @no_autorepeat: disable key autorepeat + * @rows: bitmask for the rows + * @cols: bitmask for the columns + * @keymap: the keymap + */ struct stmpe_keypad { struct stmpe *stmpe; struct input_dev *input; const struct stmpe_keypad_variant *variant; - const struct stmpe_keypad_platform_data *plat; - + unsigned int debounce_ms; + unsigned int scan_count; + bool no_autorepeat; unsigned int rows; unsigned int cols; - - unsigned short keymap[STMPE_KEYPAD_KEYMAP_SIZE]; + unsigned short keymap[STMPE_KEYPAD_KEYMAP_MAX_SIZE]; }; static int stmpe_keypad_read_data(struct stmpe_keypad *keypad, u8 *data) @@ -208,15 +222,14 @@ static int stmpe_keypad_altfunc_init(struct stmpe_keypad *keypad) static int stmpe_keypad_chip_init(struct stmpe_keypad *keypad) { - const struct stmpe_keypad_platform_data *plat = keypad->plat; const struct stmpe_keypad_variant *variant = keypad->variant; struct stmpe *stmpe = keypad->stmpe; int ret; - if (plat->debounce_ms > STMPE_KEYPAD_MAX_DEBOUNCE) + if (keypad->debounce_ms > STMPE_KEYPAD_MAX_DEBOUNCE) return -EINVAL; - if (plat->scan_count > STMPE_KEYPAD_MAX_SCAN_COUNT) + if (keypad->scan_count > STMPE_KEYPAD_MAX_SCAN_COUNT) return -EINVAL; ret = stmpe_enable(stmpe, STMPE_BLOCK_KEYPAD); @@ -245,7 +258,7 @@ static int stmpe_keypad_chip_init(struct stmpe_keypad *keypad) ret = stmpe_set_bits(stmpe, STMPE_KPC_CTRL_MSB, STMPE_KPC_CTRL_MSB_SCAN_COUNT, - plat->scan_count << 4); + keypad->scan_count << 4); if (ret < 0) return ret; @@ -253,17 +266,18 @@ static int stmpe_keypad_chip_init(struct stmpe_keypad *keypad) STMPE_KPC_CTRL_LSB_SCAN | STMPE_KPC_CTRL_LSB_DEBOUNCE, STMPE_KPC_CTRL_LSB_SCAN | - (plat->debounce_ms << 1)); + (keypad->debounce_ms << 1)); } -static void stmpe_keypad_fill_used_pins(struct stmpe_keypad *keypad) +static void stmpe_keypad_fill_used_pins(struct stmpe_keypad *keypad, + u32 used_rows, u32 used_cols) { int row, col; - for (row = 0; row < STMPE_KEYPAD_MAX_ROWS; row++) { - for (col = 0; col < STMPE_KEYPAD_MAX_COLS; col++) { + for (row = 0; row < used_rows; row++) { + for (col = 0; col < used_cols; col++) { int code = MATRIX_SCAN_CODE(row, col, - STMPE_KEYPAD_ROW_SHIFT); + STMPE_KEYPAD_ROW_SHIFT); if (keypad->keymap[code] != KEY_RESERVED) { keypad->rows |= 1 << row; keypad->cols |= 1 << col; @@ -272,51 +286,17 @@ static void stmpe_keypad_fill_used_pins(struct stmpe_keypad *keypad) } } -#ifdef CONFIG_OF -static const struct stmpe_keypad_platform_data * -stmpe_keypad_of_probe(struct device *dev) -{ - struct device_node *np = dev->of_node; - struct stmpe_keypad_platform_data *plat; - - if (!np) - return ERR_PTR(-ENODEV); - - plat = devm_kzalloc(dev, sizeof(*plat), GFP_KERNEL); - if (!plat) - return ERR_PTR(-ENOMEM); - - of_property_read_u32(np, "debounce-interval", &plat->debounce_ms); - of_property_read_u32(np, "st,scan-count", &plat->scan_count); - - plat->no_autorepeat = of_property_read_bool(np, "st,no-autorepeat"); - - return plat; -} -#else -static inline const struct stmpe_keypad_platform_data * -stmpe_keypad_of_probe(struct device *dev) -{ - return ERR_PTR(-EINVAL); -} -#endif - static int stmpe_keypad_probe(struct platform_device *pdev) { struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent); - const struct stmpe_keypad_platform_data *plat; + struct device_node *np = pdev->dev.of_node; struct stmpe_keypad *keypad; struct input_dev *input; + u32 rows; + u32 cols; int error; int irq; - plat = stmpe->pdata->keypad; - if (!plat) { - plat = stmpe_keypad_of_probe(&pdev->dev); - if (IS_ERR(plat)) - return PTR_ERR(plat); - } - irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; @@ -326,6 +306,13 @@ static int stmpe_keypad_probe(struct platform_device *pdev) if (!keypad) return -ENOMEM; + keypad->stmpe = stmpe; + keypad->variant = &stmpe_keypad_variants[stmpe->partnum]; + + of_property_read_u32(np, "debounce-interval", &keypad->debounce_ms); + of_property_read_u32(np, "st,scan-count", &keypad->scan_count); + keypad->no_autorepeat = of_property_read_bool(np, "st,no-autorepeat"); + input = devm_input_allocate_device(&pdev->dev); if (!input) return -ENOMEM; @@ -334,23 +321,22 @@ static int stmpe_keypad_probe(struct platform_device *pdev) input->id.bustype = BUS_I2C; input->dev.parent = &pdev->dev; - error = matrix_keypad_build_keymap(plat->keymap_data, NULL, - STMPE_KEYPAD_MAX_ROWS, - STMPE_KEYPAD_MAX_COLS, + error = matrix_keypad_parse_of_params(&pdev->dev, &rows, &cols); + if (error) + return error; + + error = matrix_keypad_build_keymap(NULL, NULL, rows, cols, keypad->keymap, input); if (error) return error; input_set_capability(input, EV_MSC, MSC_SCAN); - if (!plat->no_autorepeat) + if (!keypad->no_autorepeat) __set_bit(EV_REP, input->evbit); - stmpe_keypad_fill_used_pins(keypad); + stmpe_keypad_fill_used_pins(keypad, rows, cols); - keypad->stmpe = stmpe; - keypad->plat = plat; keypad->input = input; - keypad->variant = &stmpe_keypad_variants[stmpe->partnum]; error = stmpe_keypad_chip_init(keypad); if (error < 0) diff --git a/include/linux/mfd/stmpe.h b/include/linux/mfd/stmpe.h index cc0deb72e46b..f742b6717d52 100644 --- a/include/linux/mfd/stmpe.h +++ b/include/linux/mfd/stmpe.h @@ -115,24 +115,6 @@ extern int stmpe_set_altfunc(struct stmpe *stmpe, u32 pins, extern int stmpe_enable(struct stmpe *stmpe, unsigned int blocks); extern int stmpe_disable(struct stmpe *stmpe, unsigned int blocks); -struct matrix_keymap_data; - -/** - * struct stmpe_keypad_platform_data - STMPE keypad platform data - * @keymap_data: key map table and size - * @debounce_ms: debounce interval, in ms. Maximum is - * %STMPE_KEYPAD_MAX_DEBOUNCE. - * @scan_count: number of key scanning cycles to confirm key data. - * Maximum is %STMPE_KEYPAD_MAX_SCAN_COUNT. - * @no_autorepeat: disable key autorepeat - */ -struct stmpe_keypad_platform_data { - const struct matrix_keymap_data *keymap_data; - unsigned int debounce_ms; - unsigned int scan_count; - bool no_autorepeat; -}; - #define STMPE_GPIO_NOREQ_811_TOUCH (0xf0) /** @@ -201,7 +183,6 @@ struct stmpe_ts_platform_data { * @irq_gpio: gpio number over which irq will be requested (significant only if * irq_over_gpio is true) * @gpio: GPIO-specific platform data - * @keypad: keypad-specific platform data * @ts: touchscreen-specific platform data */ struct stmpe_platform_data { @@ -214,7 +195,6 @@ struct stmpe_platform_data { int autosleep_timeout; struct stmpe_gpio_platform_data *gpio; - struct stmpe_keypad_platform_data *keypad; struct stmpe_ts_platform_data *ts; }; -- cgit v1.2.3-59-g8ed1b From cc0363120b1f0c939bb7c61d5b7d2b616ad27783 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 5 Dec 2014 10:04:47 -0300 Subject: [media] DocBook media: add missing ycbcr_enc and quantization fields I forgot to add these fields to the relevant structs. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/pixfmt.xml | 36 ++++++++++++++++++++-- Documentation/DocBook/media/v4l/subdev-formats.xml | 18 ++++++++++- 2 files changed, 51 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/DocBook/media/v4l/pixfmt.xml b/Documentation/DocBook/media/v4l/pixfmt.xml index ccf6053c1ae4..d5eca4b8f74b 100644 --- a/Documentation/DocBook/media/v4l/pixfmt.xml +++ b/Documentation/DocBook/media/v4l/pixfmt.xml @@ -138,9 +138,25 @@ applicable values. __u32 flags - Flags set by the application or driver, see Flags set by the application or driver, see . + + &v4l2-ycbcr-encoding; + ycbcr_enc + This information supplements the +colorspace and must be set by the driver for +capture streams and by the application for output streams, +see . + + + &v4l2-quantization; + quantization + This information supplements the +colorspace and must be set by the driver for +capture streams and by the application for output streams, +see . + @@ -231,10 +247,26 @@ codes can be used. flags Flags set by the application or driver, see . + + + &v4l2-ycbcr-encoding; + ycbcr_enc + This information supplements the +colorspace and must be set by the driver for +capture streams and by the application for output streams, +see . + + + &v4l2-quantization; + quantization + This information supplements the +colorspace and must be set by the driver for +capture streams and by the application for output streams, +see . __u8 - reserved[10] + reserved[8] Reserved for future extensions. Should be zeroed by the application. diff --git a/Documentation/DocBook/media/v4l/subdev-formats.xml b/Documentation/DocBook/media/v4l/subdev-formats.xml index 18730b96e1e6..c5ea868e3909 100644 --- a/Documentation/DocBook/media/v4l/subdev-formats.xml +++ b/Documentation/DocBook/media/v4l/subdev-formats.xml @@ -33,9 +33,25 @@ Image colorspace, from &v4l2-colorspace;. See for details. + + &v4l2-ycbcr-encoding; + ycbcr_enc + This information supplements the +colorspace and must be set by the driver for +capture streams and by the application for output streams, +see . + + + &v4l2-quantization; + quantization + This information supplements the +colorspace and must be set by the driver for +capture streams and by the application for output streams, +see . + __u32 - reserved[7] + reserved[6] Reserved for future extensions. Applications and drivers must set the array to zero. -- cgit v1.2.3-59-g8ed1b From 38913a5cc58c26b96182799442f96e992301816c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 5 Dec 2014 10:18:38 -0300 Subject: [media] vivid.txt: document new controls Document the new 'Y'CbCr Encoding' and 'Quantization' controls. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/vivid.txt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'Documentation') diff --git a/Documentation/video4linux/vivid.txt b/Documentation/video4linux/vivid.txt index e5a940e3d304..6cfc8541a362 100644 --- a/Documentation/video4linux/vivid.txt +++ b/Documentation/video4linux/vivid.txt @@ -640,6 +640,21 @@ Colorspace: selects which colorspace should be used when generating the image. Changing the colorspace will result in the V4L2_EVENT_SOURCE_CHANGE to be sent since it emulates a detected colorspace change. +Y'CbCr Encoding: selects which Y'CbCr encoding should be used when generating + a Y'CbCr image. This only applies if the CSC Colorbar test pattern is + selected, and if the format is set to a Y'CbCr format as opposed to an + RGB format. + + Changing the Y'CbCr encoding will result in the V4L2_EVENT_SOURCE_CHANGE + to be sent since it emulates a detected colorspace change. + +Quantization: selects which quantization should be used for the RGB or Y'CbCr + encoding when generating the test pattern. This only applies if the CSC + Colorbar test pattern is selected. + + Changing the quantization will result in the V4L2_EVENT_SOURCE_CHANGE + to be sent since it emulates a detected colorspace change. + Limited RGB Range (16-235): selects if the RGB range of the HDMI source should be limited or full range. This combines with the Digital Video 'Rx RGB Quantization Range' control and can be used to test what happens if -- cgit v1.2.3-59-g8ed1b From 5fdb9679b94ed74f5e9376bc289d840bd4f73f16 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 5 Dec 2014 11:23:55 -0300 Subject: [media] DocBook media: update version number and document changes Update the version to 3.19. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/compat.xml | 12 ++++++++++++ Documentation/DocBook/media/v4l/v4l2.xml | 11 ++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/DocBook/media/v4l/compat.xml b/Documentation/DocBook/media/v4l/compat.xml index 0a2debfa68f6..350dfb3d71ea 100644 --- a/Documentation/DocBook/media/v4l/compat.xml +++ b/Documentation/DocBook/media/v4l/compat.xml @@ -2579,6 +2579,18 @@ fields changed from _s32 to _u32.
+
+ V4L2 in Linux 3.19 + + + Rewrote Colorspace chapter, added new &v4l2-ycbcr-encoding; +and &v4l2-quantization; fields to &v4l2-pix-format;, &v4l2-pix-format-mplane; +and &v4l2-mbus-framefmt;. + + + +
+
Relation of V4L2 to other Linux multimedia APIs diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml index 7cfe618f754d..ac0f8d9d2a49 100644 --- a/Documentation/DocBook/media/v4l/v4l2.xml +++ b/Documentation/DocBook/media/v4l/v4l2.xml @@ -151,6 +151,15 @@ structs, ioctls) must be noted in more detail in the history chapter (compat.xml), along with the possible impact on existing drivers and applications. --> + + 3.19 + 2014-12-05 + hv + Rewrote Colorspace chapter, added new &v4l2-ycbcr-encoding; and &v4l2-quantization; fields +to &v4l2-pix-format;, &v4l2-pix-format-mplane; and &v4l2-mbus-framefmt;. + + + 3.17 2014-08-04 @@ -539,7 +548,7 @@ and discussions on the V4L mailing list. Video for Linux Two API Specification - Revision 3.17 + Revision 3.19 &sub-common; -- cgit v1.2.3-59-g8ed1b