Re: [PATCH v9 6/8] drivers:input:ads7846(+tsc2046): fix spi module table
Hi Dmitry, > Am 28.01.2017 um 20:35 schrieb Dmitry Torokhov : > > On Wed, Dec 28, 2016 at 03:53:21PM +0100, H. Nikolaus Schaller wrote: >> Fix module table so that the driver is loaded if compiled >> as module and requested by DT. >> > > I believe I already replied to a similar patch: we alreadyhave necessary > aliases in this driver, we need to fix module loading to use it. Yes, you did comment on [PATCH v6 7/8] (19 Nov 2016): >> We really need to fix it between spi/i23c core and module utils instead >> of keeping adding duplicate IDs all over drivers. We already have OF >> module device table containing the same data, we should be able to use >> it. And Javier Martinez Canillas replied (23 Nov 2016): > Agreed, unfortunately until the I2C and SPI core are changed to properly > report OF modaliases, we will have to keep adding these duplicated IDs. > > And changing the I2C and SPI core isn't trivial since it could break a > lot of drivers that rely on a platform modalias being reported (i.e: no > OF device IDs present in the drivers even when are registered via DT). Therefore I didn't see a need to change it. BR, Nikolaus
Re: [PATCH 2/2] iio: distance: add devantech us ranger srf04
> This patch adds support for the ultrasonic ranger srf04 of devantech. comments below > This device is measuring the distance of objects in a range between 1 cm > and 3 meters and a theoretical resolution of 3 mm. > > There are two GPIOs used: > - trigger: set when the measurement should start > - echo: set when the ultrasonic wave is sent out and reset when the echo > is recognized; needs to be an interrupt input > > The time between setting and resetting the echo pin is the time the > waveform needed for one round trip. This time is recorded in the interrupt > handler. > > The distance is calculated in the read function by using the ultrasonic > speed at 20 degrees celsius which is about 343 m/s. > > Signed-off-by: Andreas Klinger > --- > MAINTAINERS| 6 + > drivers/iio/proximity/Kconfig | 11 ++ > drivers/iio/proximity/Makefile | 1 + > drivers/iio/proximity/srf04.c | 269 > + > 4 files changed, 287 insertions(+) > create mode 100644 drivers/iio/proximity/srf04.c > > diff --git a/MAINTAINERS b/MAINTAINERS > index fa6af014fd72..ba979cc48fd8 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -3469,6 +3469,12 @@ T: git > git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git > S: Maintained > F: drivers/usb/dwc3/ > > +DEVANTECH SRF ULTRASONIC RANGER IIO DRIVER > +M: Andreas Klinger > +L: linux-...@vger.kernel.org > +S: Maintained > +F: drivers/iio/proximity/srf*.c > + > DEVICE COREDUMP (DEV_COREDUMP) > M: Johannes Berg > L: linux-kernel@vger.kernel.org > diff --git a/drivers/iio/proximity/Kconfig b/drivers/iio/proximity/Kconfig > index ef4c73db5b53..0bcbc66eae6e 100644 > --- a/drivers/iio/proximity/Kconfig > +++ b/drivers/iio/proximity/Kconfig > @@ -32,6 +32,17 @@ config LIDAR_LITE_V2 > To compile this driver as a module, choose M here: the > module will be called pulsedlight-lite-v2 > > +config SRF04 > + tristate "Devantech SRF04 ultrasonic ranger sensor" > + depends on GPIOLIB > + help > + Say Y here to build a driver for Devantech SRF04 ultrasonic > + ranger sensor. This driver can be used to measure the distance > + of objects. It is using two GPIOs. > + > + To compile this driver as a module, choose M here: the > + module will be called srf04. > + > config SX9500 > tristate "SX9500 Semtech proximity sensor" > select IIO_BUFFER > diff --git a/drivers/iio/proximity/Makefile b/drivers/iio/proximity/Makefile > index 9aadd9a8ee99..97c046c1dfc5 100644 > --- a/drivers/iio/proximity/Makefile > +++ b/drivers/iio/proximity/Makefile > @@ -5,4 +5,5 @@ > # When adding new entries keep the list in alphabetical order > obj-$(CONFIG_AS3935) += as3935.o > obj-$(CONFIG_LIDAR_LITE_V2) += pulsedlight-lidar-lite-v2.o > +obj-$(CONFIG_SRF04) += srf04.o > obj-$(CONFIG_SX9500) += sx9500.o > diff --git a/drivers/iio/proximity/srf04.c b/drivers/iio/proximity/srf04.c > new file mode 100644 > index ..f458c3d9084b > --- /dev/null > +++ b/drivers/iio/proximity/srf04.c > @@ -0,0 +1,269 @@ > +/* > + * SRF04: ultrasonic sensor for distance measuring by using GPIOs > + * > + * Copyright (c) 2017 Andreas Klinger > + * > + * 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. > + * > + * For details about the device see: > + * http://www.robot-electronics.co.uk/htm/srf04tech.htm > + */ > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +struct srf04_data { > + struct device *dev; > + struct gpio_desc*gpiod_trig; > + struct gpio_desc*gpiod_echo; > + struct mutexlock; > + int irqnr; > + ktime_t ts_rising; > + ktime_t ts_falling; > + struct completion rising; > + struct completion falling; > +}; > + > +static irqreturn_t srf04_handle_irq(int irq, void *dev_id) > +{ > + struct iio_dev *indio_dev = dev_id; > + struct srf04_data *data = iio_priv(indio_dev); > + > + if (gpiod_get_value(data->gpiod_echo)) { > + data->ts_rising = ktime_get(); > + complete(&data->rising); > + } else { > + data->ts_falling = ktime_get(); > + complete(&data->falling); > + } > + > + return IRQ_HANDLED; > +} > + > +static int srf04
Re: [PATCH 37/50] x86/boot/e820: Use 'enum e820_type' in 'struct e820_entry'
* Linus Torvalds wrote: > On Sat, Jan 28, 2017 at 2:11 PM, Ingo Molnar wrote: > > Use a stricter type for struct e820_entry. Add a build-time check to make > > sure the compiler won't ever pack the enum into a field smaller than > > 'int'. > > I'm not sure this is a good idea. In fact, I'm pretty sure it's a horrible > idea. > > The compiler that *users* use might decide that the "enum" fits in a > 8-bit unsigned char, and decide to use that. The kernel build won't > notice and the BUG_ON() won't help, because we use a different > compiler. Hm, good point, have not considered that. > (Or even if it's the same compiler you can have build flags - the size > of an enum very much depends on various compiler options, particularly > "--short-enums" for gcc). > > Basically, we should not use "enum"s in types exported to user space. > The size just isn't sufficiently well defined, and it's a maintenance > nightmare. > > Use explicitly sized members only, please. No "enum". Ok. Would it be acceptable to use enum for the kernel internal representation (our e820_table structures never actually comes directly, we construct it ourselves), and maintain the very explicitly sized ABI type for the boot protocol only (i.e. uapi/asm/bootparam.h)? ( I actually partially implemented that originally, but chickened out after running into header dependency hell - but I think it could be tackled with a bit more effort. ) The vagueness of the C spec about enum size and the resulting enum auto-packing efforts of compilers is annoying and a real problem for ABIs, but the reason I'm pushing them in this case is that enums also have some advantages within the kernel: 1) they are pretty good self-documenting types 2) GCC at least has some useful enum warnings for switch() statements, one of which we use in the kernel today: -Wswitch Warn whenever a "switch" statement has an index of enumerated type and lacks a "case" for one or more of the named codes of that enumeration. (The presence of a "default" label prevents this warning.) "case" labels outside the enumeration range also provoke warnings when this option is used (even if there is a "default" label). This warning is enabled by -Wall. There are also more intrusive warnings which found/prevented quite a few bugs in various user-space efforts I've been involved with (such as tools/perf): -Wswitch-default Warn whenever a "switch" statement does not have a "default" case. -Wswitch-enum Warn whenever a "switch" statement has an index of enumerated type and lacks a "case" for one or more of the named codes of that enumeration. "case" labels outside the enumeration range also provoke warnings when this option is used. The only difference between -Wswitch and this option is that this option gives a warning about an omitted enumeration code even if there is a "default" label. So if say one of the e820 functions didn't handle E820_TYPE_PMEM, we'd today generate this warning in the kernel build: arch/x86/kernel/e820.c: In function ‘e820_print_type’: arch/x86/kernel/e820.c:143:2: warning: enumeration value ‘E820_TYPE_PMEM’ not handled in switch [-Wswitch] switch (type) { ^ arch/x86/kernel/e820.c:143:2: warning: enumeration value ‘E820_TYPE_PRAM’ not handled in switch [-Wswitch] And in fact, we could go further than that - the kernel does not enable -Wswitch-enum right now (because there are valid patterns that it warns about, such as enums with extensive list of values where listing all the values would make thecode worse), but when enabled for e820.c it generates this warning: arch/x86/kernel/e820.c: In function ‘e820_type_to_string’: arch/x86/kernel/e820.c:965:2: warning: enumeration value ‘E820_TYPE_RESERVED’ not handled in switch [-Wswitch-enum] switch (entry->type) { ^ arch/x86/kernel/e820.c: In function ‘e820_type_to_iomem_type’: arch/x86/kernel/e820.c:979:2: warning: enumeration value ‘E820_TYPE_RESERVED’ not handled in switch [-Wswitch-enum] switch (entry->type) { ^ arch/x86/kernel/e820.c: In function ‘e820_type_to_iores_desc’: arch/x86/kernel/e820.c:993:2: warning: enumeration value ‘E820_TYPE_RESERVED’ not handled in switch [-Wswitch-enum] switch (entry->type) { ^ arch/x86/kernel/e820.c: In function ‘do_mark_busy’: arch/x86/kernel/e820.c:1015:2: warning: enumeration value ‘E820_TYPE_RAM’ not handled in switch [-Wswitch-enum] switch (type) { ^ All four warnings are interesting IMHO: The one in e820_type_to_string() should be fixed this way I think: diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c index d2c6468a8d38..20834a81854e 100644 --- a/arch/x86/kernel/e820.c +++ b/arch/x86/kernel/e820.c @@ -970,7 +970,8 @@ static const char *__init e820_typ
Re: [PATCH 1/2] iio: distance: add dt binding for devantech-srf04
On Sun, 29 Jan 2017, Andreas Klinger wrote: > This patch adds dt binding for devantech ultrasonic ranger srf04. comments below > The vendor "devantech" was already added to the vendor list with > "[PATCH v4 1/3] iio: distance: srf08: add trivial DT binding" > > Signed-off-by: Andreas Klinger > --- > .../bindings/iio/proximity/devantech-srf04.txt | 17 > + > 1 file changed, 17 insertions(+) > create mode 100644 > Documentation/devicetree/bindings/iio/proximity/devantech-srf04.txt > > diff --git > a/Documentation/devicetree/bindings/iio/proximity/devantech-srf04.txt > b/Documentation/devicetree/bindings/iio/proximity/devantech-srf04.txt > new file mode 100644 > index ..4ea29ef3ff89 > --- /dev/null > +++ b/Documentation/devicetree/bindings/iio/proximity/devantech-srf04.txt > @@ -0,0 +1,17 @@ > +* Devantech SRF04 ultrasonic range finder > + Bit-banging driver > + > +Required properties: > + - compatible: Should be "devantech,srf04" > + - trig-gpios: Definition of the GPIO for the triggering input > + - echo-gpios: Definition of the GPIO for the echo "for the echo" maybe some more explanation? it sounds somewhat incomplete to me in the driver you have "failed to get echo-gpiod", maybe it should be gpios there? > + needs to be an interrupt input > + See Documentation/devicetree/bindings/gpio/gpio.txt > + > +Example: > +srf04@0 { > + compatible = "devantech,srf04"; > + trig-gpios = <&gpio1 15 GPIO_ACTIVE_HIGH>; > + echo-gpios = <&gpio2 6 GPIO_ACTIVE_HIGH>; > +}; > + > -- Peter Meerwald-Stadler +43-664-218 (mobile)
Re: [PATCH v2 0/2] scsi: storvsc: Add support for FC lightweight host.
On Sun, Jan 29, 2017 at 12:35:32AM +, KY Srinivasan wrote: > Windows has chosen this model for virtualizing FC devices to the guest - > without rports (or vports). As I noted in my earlier email, James came > up with this notion of a lightweight template almost a year ago. We can > certainly pick a more appropriate name and include better documentation. Can we take a step back and figure out what you're trying to archive here. storsvc is a paravirtualized device interface, and whatever underlies it should be of no relevance for the guest. Despite that fact Microsoft apparently wants to expose a FC-like port_name and node_name to guests for some virtual disks. Can you please explain what the guest is supposed to use them for? And second I'd like to understand what the fascination with the FC transport class is to expose these two attributes. Given that your sysfs layout will be entirely different from real FC devices I simply don't see any need for that. Why can't this whole thing simply be solved by adding sdev_attrs for the port_name and node_name to storsvc directly?
[PATCH] rtc: sun6i: Fix compatibility with old DT binding
Commit 847b8bf62eb4 ("rtc: sun6i: Expose the 32kHz oscillator") adds a new clock for the rtc block with a 2 step probe mechanism. To share the register region between both the clock and rtc instance, a static pointer is used to keep the related data structure. To preserve compatibility with the old binding, the data structure should be saved as soon as the registers are mapped in, regardless of the presence of the clock bindings, so that the rtc device can retrieve it when it is probed. This fixes the rtc device not probing when we use the updated driver with an old device tree blob. Fixes: 847b8bf62eb4 ("rtc: sun6i: Expose the 32kHz oscillator") Signed-off-by: Chen-Yu Tsai --- drivers/rtc/rtc-sun6i.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/rtc/rtc-sun6i.c b/drivers/rtc/rtc-sun6i.c index 613f42ade533..08510ca58996 100644 --- a/drivers/rtc/rtc-sun6i.c +++ b/drivers/rtc/rtc-sun6i.c @@ -211,6 +211,9 @@ static void __init sun6i_rtc_clk_init(struct device_node *node) writel(SUN6I_LOSC_CTRL_KEY | SUN6I_LOSC_CTRL_EXT_OSC, rtc->base + SUN6I_LOSC_CTRL); + /* Yes, I know, this is ugly. */ + sun6i_rtc = rtc; + /* Deal with old DTs */ if (!of_get_property(node, "clocks", NULL)) return; @@ -243,9 +246,6 @@ static void __init sun6i_rtc_clk_init(struct device_node *node) clk_data->num = 1; clk_data->hws[0] = &rtc->hw; of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); - - /* Yes, I know, this is ugly. */ - sun6i_rtc = rtc; } CLK_OF_DECLARE_DRIVER(sun6i_rtc_clk, "allwinner,sun6i-a31-rtc", sun6i_rtc_clk_init); -- 2.11.0
Re: BUG at net/sctp/socket.c:7425
On Sun, Jan 29, 2017 at 03:35:31AM +0300, Alexander Popov wrote: > Hello, > > I'm running the syzkaller fuzzer for v4.10-rc4 > (0aa0313f9d576affd7747cc3f179feb097d28990) > and have such a crash in sctp code: > ... > > Unfortunately, I didn't manage to get a C program reproducing the crash > (looks like race). > However, I stably hit it on my setup - so I can help fixing the issue. > > The crash happens here: > /* Let another process have a go. Since we are going >* to sleep anyway. >*/ > release_sock(sk); > current_timeo = schedule_timeout(current_timeo); > > BUG_ON(sk != asoc->base.sk); > lock_sock(sk); > > I've added some debugging output and see, that the original value of > asoc->base.sk is > changed to the address of another struct sock, which appeared in > sctp_endpoint_init() > shortly before the crash. You need some threading for this to happen. asoc->base.sk will change if you peeloff the association. It seems you had one thread waiting for some sndbuf to be available on a sendmsg() call and another thread did a peeloff on the association that the first thread was using. Yeah I think this will reproduce it. And in this case, it's probably better if we just return -EPIPE as the association doesn't exist in that socket anymore instead of the BUG_ON. Marcelo ---8<--- diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 26a514269b92..e9870aead88b 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -6838,7 +6838,8 @@ static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p, */ sctp_release_sock(sk); current_timeo = schedule_timeout(current_timeo); - BUG_ON(sk != asoc->base.sk); + if (sk != asoc->base.sk) + goto do_error; sctp_lock_sock(sk); *timeo_p = current_timeo;
next-20170125 hangs on aarch64
Hi all, I pulled next-20170125 kernel, and found it hanged on boot. The exact reason is panic on dereferencing of the 0xffc8 address, which is most probably the attempt to dereference the ENOSYS error code as the address. next-20170124 works fine, at least it boots. Does anyone have details on that? Yury #0 arch_counter_get_cntvct () at ./arch/arm64/include/asm/arch_timer.h:151 #1 __delay (cycles=1024) at arch/arm64/lib/delay.c:31 #2 0x0838b430 in __const_udelay (xloops=) at arch/arm64/lib/delay.c:41 #3 0x0816a894 in panic (fmt=) at kernel/panic.c:295 #4 0x080c1238 in do_exit (code=11) at kernel/exit.c:780 #5 0x080888f0 in die (str=, regs=0x08d63d30 , err=) at arch/arm64/kernel/traps.c:295 #6 0x080998c4 in __do_kernel_fault (mm=0x0, addr=4294967240, esr=2483027972, regs=0x08d63d30 ) at arch/arm64/mm/fault.c:185 #7 0x08097244 in __do_kernel_fault (regs=, esr=, addr=, mm=) at arch/arm64/mm/fault.c:419 #8 do_page_fault (addr=4294967240, esr=2483027972, regs=0x08d63d30 ) at arch/arm64/mm/fault.c:443 #9 0x08097334 in do_translation_fault (addr=, esr=, regs=) at arch/arm64/mm/fault.c:469 #10 0x08081298 in do_mem_abort (addr=4294967240, esr=2483027972, regs=0x08d63d30 ) at arch/arm64/mm/fault.c:577 #11 0x08082604 in el1_sync () at arch/arm64/kernel/entry.S:438 #12 0x08082604 in el1_sync () at arch/arm64/kernel/entry.S:438 [...]
Re: [PATCH] i2c: busses: constify i2c_algorithm structures
Hello, On Fri, Jan 27, 2017 at 11:36:17PM +0530, Bhumika Goyal wrote: > drivers/i2c/busses/i2c-imx.c | 2 +- Acked-by: Uwe Kleine-König for i2c-imx.c Thanks Uwe -- Pengutronix e.K. | Uwe Kleine-König| Industrial Linux Solutions | http://www.pengutronix.de/ |
[PATCH v4] mm: add arch-independent testcases for RODATA
This patch makes arch-independent testcases for RODATA. Both x86 and x86_64 already have testcases for RODATA, But they are arch-specific because using inline assembly directly. and cacheflush.h is not suitable location for rodata-test related things. Since they were in cacheflush.h, If someone change the state of CONFIG_DEBUG_RODATA_TEST, It cause overhead of kernel build. To solve above issue, write arch-independent testcases and move it to shared location. Signed-off-by: Jinbum Park --- v4: Move the rodata_test() call out into mark_readonly() Delete some comment v3: Use probe_kernel_write() instead of put_user() Move declaration of rodata_test_data to separate header (rodata_test.h) Fix a kbuild-test-robot-error related to DEBUG_NX_TEST v2: Restore original credit of mm/rodata_test.c arch/x86/Kconfig.debug| 10 +- arch/x86/include/asm/cacheflush.h | 10 -- arch/x86/kernel/Makefile | 1 - arch/x86/kernel/test_rodata.c | 75 --- arch/x86/mm/init_32.c | 4 --- arch/x86/mm/init_64.c | 5 --- include/linux/rodata_test.h | 24 + init/main.c | 6 ++-- mm/Kconfig.debug | 7 mm/Makefile | 1 + mm/rodata_test.c | 56 + 11 files changed, 93 insertions(+), 106 deletions(-) delete mode 100644 arch/x86/kernel/test_rodata.c create mode 100644 include/linux/rodata_test.h create mode 100644 mm/rodata_test.c diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug index 67eec55..3fa469c 100644 --- a/arch/x86/Kconfig.debug +++ b/arch/x86/Kconfig.debug @@ -74,14 +74,6 @@ config EFI_PGT_DUMP issues with the mapping of the EFI runtime regions into that table. -config DEBUG_RODATA_TEST - bool "Testcase for the marking rodata read-only" - default y - ---help--- - This option enables a testcase for the setting rodata read-only - as well as for the change_page_attr() infrastructure. - If in doubt, say "N" - config DEBUG_WX bool "Warn on W+X mappings at boot" select X86_PTDUMP_CORE @@ -122,7 +114,7 @@ config DEBUG_SET_MODULE_RONX config DEBUG_NX_TEST tristate "Testcase for the NX non-executable stack feature" - depends on DEBUG_KERNEL && m + depends on DEBUG_KERNEL && DEBUG_RODATA_TEST && m ---help--- This option enables a testcase for the CPU NX capability and the software setup of this feature. diff --git a/arch/x86/include/asm/cacheflush.h b/arch/x86/include/asm/cacheflush.h index 872877d..e7e1942e 100644 --- a/arch/x86/include/asm/cacheflush.h +++ b/arch/x86/include/asm/cacheflush.h @@ -90,18 +90,8 @@ #define mmio_flush_range(addr, size) clflush_cache_range(addr, size) -extern const int rodata_test_data; extern int kernel_set_to_readonly; void set_kernel_text_rw(void); void set_kernel_text_ro(void); -#ifdef CONFIG_DEBUG_RODATA_TEST -int rodata_test(void); -#else -static inline int rodata_test(void) -{ - return 0; -} -#endif - #endif /* _ASM_X86_CACHEFLUSH_H */ diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 581386c..f6caf82 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -100,7 +100,6 @@ obj-$(CONFIG_HPET_TIMER)+= hpet.o obj-$(CONFIG_APB_TIMER)+= apb_timer.o obj-$(CONFIG_AMD_NB) += amd_nb.o -obj-$(CONFIG_DEBUG_RODATA_TEST)+= test_rodata.o obj-$(CONFIG_DEBUG_NX_TEST)+= test_nx.o obj-$(CONFIG_DEBUG_NMI_SELFTEST) += nmi_selftest.o diff --git a/arch/x86/kernel/test_rodata.c b/arch/x86/kernel/test_rodata.c deleted file mode 100644 index 222e84e..000 --- a/arch/x86/kernel/test_rodata.c +++ /dev/null @@ -1,75 +0,0 @@ -/* - * test_rodata.c: functional test for mark_rodata_ro function - * - * (C) Copyright 2008 Intel Corporation - * Author: Arjan van de Ven - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; version 2 - * of the License. - */ -#include -#include -#include - -int rodata_test(void) -{ - unsigned long result; - unsigned long start, end; - - /* test 1: read the value */ - /* If this test fails, some previous testrun has clobbered the state */ - if (!rodata_test_data) { - printk(KERN_ERR "rodata_test: test 1 fails (start data)\n"); - return -ENODEV; - } - - /* test 2: write to the variable; this should fault */ - /* -* If this test fails, we managed to overwrite the data -* -* This is written in assembly to be able to catch the -* exception that is supposed to happen in the correct -* case -*/ - - result = 1; - asm volatile( - "0:
undefined reference to `physical_memsize'
Hi Hauke, It's probably a bug fix that unveils the link errors. tree: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git master head: 53cd1ad1a68fd10f677445e04ed63aa9ce39b36b commit: a2724663494f7313f53da10d8c0a729c5e3c4dea mtd: nand: xway: fix build because of module functions date: 4 weeks ago config: mips-xway_defconfig (attached as .config) compiler: mips-linux-gnu-gcc (Debian 6.1.1-9) 6.1.1 20160705 reproduce: wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross git checkout a2724663494f7313f53da10d8c0a729c5e3c4dea # save the attached .config to linux build tree make.cross ARCH=mips All errors (new ones prefixed by >>): arch/mips/built-in.o: In function `vpe_run': >> (.text+0x14990): undefined reference to `physical_memsize' arch/mips/built-in.o: In function `vpe_run': (.text+0x14994): undefined reference to `physical_memsize' --- 0-DAY kernel test infrastructureOpen Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation .config.gz Description: application/gzip
Re: [RFC v2 01/10] KVM: arm/arm64: Abstract virtual timer context into separate structure
On Fri, Jan 27 2017 at 01:04:51 AM, Jintack Lim wrote: > Abstract virtual timer context into a separate structure and change all > callers referring to timer registers, irq state and so on. No change in > functionality. > > This is about to become very handy when adding the EL1 physical timer. > > Signed-off-by: Jintack Lim > Acked-by: Christoffer Dall Acked-by: Marc Zyngier M. -- Jazz is not dead. It just smells funny.
Re: [PATCH 2/2] iio: distance: add devantech us ranger srf04
On 01/29/2017 12:58 AM, Andreas Klinger wrote: > This patch adds support for the ultrasonic ranger srf04 of devantech. Thanks for the patch. Looks mostly good, a few small comments inline. > diff --git a/drivers/iio/proximity/srf04.c b/drivers/iio/proximity/srf04.c > new file mode 100644 > index ..f458c3d9084b > --- /dev/null > +++ b/drivers/iio/proximity/srf04.c > @@ -0,0 +1,269 @@ [...] > +#include > +#include Your driver is only a GPIO consumer, so the above include should not be necessary. > +#include > +#include > +#include > +#include As far as I can see nothing from bitops.h is used in this driver. > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + [...] > +static int srf04_read(struct srf04_data *data) > +{ > + int ret; > + ktime_t ktime_dt; > + u64 dt_ns; > + u32 time_ns; > + u32 distance_mm; > + > + mutex_lock(&data->lock); Maybe a stupid question, but what does the lock protect? > + > + reinit_completion(&data->rising); > + reinit_completion(&data->falling); > + > + gpiod_set_value(data->gpiod_trig, 1); > + udelay(10); > + gpiod_set_value(data->gpiod_trig, 0); > + > + mutex_unlock(&data->lock); > + > + /* it cannot take more than 20 ms */ > + ret = wait_for_completion_killable_timeout(&data->rising, HZ/50); > + if (ret < 0) In case of a timeout wait_for_... will return 0. In case of an interrupt (kill event) a negative value. In the later case we should typically propagate the error rather than replacing it. > + return -ETIMEDOUT; > + > + ret = wait_for_completion_killable_timeout(&data->falling, HZ/50); > + if (ret < 0) > + return -ETIMEDOUT; > + > + ktime_dt = ktime_sub(data->ts_falling, data->ts_rising); > + > + dt_ns = ktime_to_ns(ktime_dt); > + /* > + * measuring more than 3 meters is beyond the posibilities of > + * the sensor > + */ > + if (dt_ns > 875) { > + return -EFAULT; EFAULT means that "An invalid user space address was specified for an argument". EIO is usually used to indicate that there was a communication issue with the device. > + } > + time_ns = dt_ns; > + > + /* > + * the speed as function of the temperature is approximately: > + * speed = 331,5 + 0,6 * Temp > + * with Temp in °C > + * and speed in m/s > + * > + * use 343 m/s as ultrasonic speed at 20 °C here in absence of the > + * temperature > + * > + * therefore: > + * distance = time / 10^6 * 343 / 2 > + * with time in ns > + * and distance in mm (one way) > + * > + * because we limit to 3 meters the multiplication with 343 just > + * fits into 32 bit > + */ > + distance_mm = time_ns * 343 / 200; > + > + dev_info (data->dev, "ns: %llu, dist: %d\n", dt_ns, distance_mm); dev_dbg probably. > + > + return distance_mm; > +} > + > +static int srf04_read_raw(struct iio_dev *indio_dev, > + struct iio_chan_spec const *channel, int *val, > + int *val2, long mask) I know lots of drivers use the name 'mask' here, but that is a relict from a long long time ago and the implementation was changed and the old name it is not really appropriate anymore. The recommendation is to use 'info' for new drivers. > +{ [...] > +static int srf04_probe(struct platform_device *pdev) > +{ > + struct device *dev = &pdev->dev; > + struct srf04_data *data = NULL; The NULL initialization is not really necessary. The variable is never used until it is initialized again a few lines below. The compiler will just remove this. > + struct iio_dev *indio_dev; > + int ret = 0; Same here. > + > + indio_dev = devm_iio_device_alloc(dev, sizeof(struct srf04_data)); > + if (!indio_dev) { > + dev_err(dev, "failed to allocate IIO device\n"); > + return -ENOMEM; > + } > + > + data = iio_priv(indio_dev); > + data->dev = dev; > + > + mutex_init(&data->lock); > + init_completion(&data->rising); > + init_completion(&data->falling); > + > + data->gpiod_trig = devm_gpiod_get(dev, "trig", GPIOD_OUT_LOW); > + if (IS_ERR(data->gpiod_trig)) { > + dev_err(dev, "failed to get trig-gpiod: err=%ld\n", > + PTR_ERR(data->gpiod_trig)); > + return PTR_ERR(data->gpiod_trig); > + } > + > + data->gpiod_echo = devm_gpiod_get(dev, "echo", GPIOD_IN); > + if (IS_ERR(data->gpiod_echo)) { > + dev_err(dev, "failed to get echo-gpiod: err=%ld\n", > + PTR_ERR(data->gpiod_echo)); > + return PTR_ERR(data->gpiod_echo); > + } > + > + if (gpiod_cansleep(data->gpiod_echo)) { > + dev_err(data->dev, "cansleep-GPIOs not supported\n"); > + return -ENODEV; > + } > + > +
Re: [RFC v2 02/10] KVM: arm/arm64: Move cntvoff to each timer context
On Fri, Jan 27 2017 at 01:04:52 AM, Jintack Lim wrote: > Make cntvoff per each timer context. This is helpful to abstract kvm > timer functions to work with timer context without considering timer > types (e.g. physical timer or virtual timer). > > This also would pave the way for ever doing adjustments of the cntvoff > on a per-CPU basis if that should ever make sense. > > Signed-off-by: Jintack Lim > --- > arch/arm/include/asm/kvm_host.h | 6 +++--- > arch/arm64/include/asm/kvm_host.h | 4 ++-- > include/kvm/arm_arch_timer.h | 8 +++- > virt/kvm/arm/arch_timer.c | 26 -- > virt/kvm/arm/hyp/timer-sr.c | 3 +-- > 5 files changed, 29 insertions(+), 18 deletions(-) > > diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h > index d5423ab..f5456a9 100644 > --- a/arch/arm/include/asm/kvm_host.h > +++ b/arch/arm/include/asm/kvm_host.h > @@ -60,9 +60,6 @@ struct kvm_arch { > /* The last vcpu id that ran on each physical CPU */ > int __percpu *last_vcpu_ran; > > - /* Timer */ > - struct arch_timer_kvm timer; > - > /* >* Anything that is not used directly from assembly code goes >* here. > @@ -75,6 +72,9 @@ struct kvm_arch { > /* Stage-2 page table */ > pgd_t *pgd; > > + /* A lock to synchronize cntvoff among all vtimer context of vcpus */ > + spinlock_t cntvoff_lock; Is there any condition where we need this to be a spinlock? I would have thought that a mutex should have been enough, as this should only be updated on migration or initialization. Not that it matters much in this case, but I wondered if there is something I'm missing. > + > /* Interrupt controller */ > struct vgic_distvgic; > int max_vcpus; > diff --git a/arch/arm64/include/asm/kvm_host.h > b/arch/arm64/include/asm/kvm_host.h > index e505038..23749a8 100644 > --- a/arch/arm64/include/asm/kvm_host.h > +++ b/arch/arm64/include/asm/kvm_host.h > @@ -71,8 +71,8 @@ struct kvm_arch { > /* Interrupt controller */ > struct vgic_distvgic; > > - /* Timer */ > - struct arch_timer_kvm timer; > + /* A lock to synchronize cntvoff among all vtimer context of vcpus */ > + spinlock_t cntvoff_lock; > }; > > #define KVM_NR_MEM_OBJS 40 > diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h > index daad3c1..1b9c988 100644 > --- a/include/kvm/arm_arch_timer.h > +++ b/include/kvm/arm_arch_timer.h > @@ -23,11 +23,6 @@ > #include > #include > > -struct arch_timer_kvm { > - /* Virtual offset */ > - u64 cntvoff; > -}; > - > struct arch_timer_context { > /* Registers: control register, timer value */ > u32 cnt_ctl; > @@ -38,6 +33,9 @@ struct arch_timer_context { > > /* Active IRQ state caching */ > boolactive_cleared_last; > + > + /* Virtual offset */ > + u64 cntvoff; > }; > > struct arch_timer_cpu { > diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c > index 6740efa..fa4c042 100644 > --- a/virt/kvm/arm/arch_timer.c > +++ b/virt/kvm/arm/arch_timer.c > @@ -101,9 +101,10 @@ static void kvm_timer_inject_irq_work(struct work_struct > *work) > static u64 kvm_timer_compute_delta(struct kvm_vcpu *vcpu) > { > u64 cval, now; > + struct arch_timer_context *vtimer = vcpu_vtimer(vcpu); > > - cval = vcpu_vtimer(vcpu)->cnt_cval; > - now = kvm_phys_timer_read() - vcpu->kvm->arch.timer.cntvoff; > + cval = vtimer->cnt_cval; > + now = kvm_phys_timer_read() - vtimer->cntvoff; > > if (now < cval) { > u64 ns; > @@ -159,7 +160,7 @@ bool kvm_timer_should_fire(struct kvm_vcpu *vcpu) > return false; > > cval = vtimer->cnt_cval; > - now = kvm_phys_timer_read() - vcpu->kvm->arch.timer.cntvoff; > + now = kvm_phys_timer_read() - vtimer->cntvoff; > > return cval <= now; > } > @@ -353,10 +354,23 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu, > return 0; > } > > +/* Make the updates of cntvoff for all vtimer contexts atomic */ > +static void update_vtimer_cntvoff(struct kvm_vcpu *vcpu, u64 cntvoff) Arguably, this acts on the VM itself and not a single vcpu. maybe you should consider passing the struct kvm pointer to reflect this. > +{ > + int i; > + > + spin_lock(&vcpu->kvm->arch.cntvoff_lock); > + kvm_for_each_vcpu(i, vcpu, vcpu->kvm) > + vcpu_vtimer(vcpu)->cntvoff = cntvoff; > + spin_unlock(&vcpu->kvm->arch.cntvoff_lock); > +} > + > void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu) > { > struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu; > > + update_vtimer_cntvoff(vcpu, kvm_phys_timer_read()); Maybe a comment indicating that we recompute CNTVOFF for all vcpus would be welcome (this is not a change in semantics, but it was never obvious in the existing c
Re: [RFC v2 03/10] KVM: arm/arm64: Decouple kvm timer functions from virtual timer
On Fri, Jan 27 2017 at 01:04:53 AM, Jintack Lim wrote: > Now that we have a separate structure for timer context, make functions > general so that they can work with any timer context, not just the generic? > virtual timer context. This does not change the virtual timer > functionality. > > Signed-off-by: Jintack Lim > --- > arch/arm/kvm/arm.c | 2 +- > include/kvm/arm_arch_timer.h | 3 ++- > virt/kvm/arm/arch_timer.c| 55 > ++-- > 3 files changed, 30 insertions(+), 30 deletions(-) > > diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c > index 9d74464..9a34a3c 100644 > --- a/arch/arm/kvm/arm.c > +++ b/arch/arm/kvm/arm.c > @@ -301,7 +301,7 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu) > > int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu) > { > - return kvm_timer_should_fire(vcpu); > + return kvm_timer_should_fire(vcpu, vcpu_vtimer(vcpu)); > } > > void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu) > diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h > index 1b9c988..d921d20 100644 > --- a/include/kvm/arm_arch_timer.h > +++ b/include/kvm/arm_arch_timer.h > @@ -67,7 +67,8 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu, > u64 kvm_arm_timer_get_reg(struct kvm_vcpu *, u64 regid); > int kvm_arm_timer_set_reg(struct kvm_vcpu *, u64 regid, u64 value); > > -bool kvm_timer_should_fire(struct kvm_vcpu *vcpu); > +bool kvm_timer_should_fire(struct kvm_vcpu *vcpu, > +struct arch_timer_context *timer_ctx); > void kvm_timer_schedule(struct kvm_vcpu *vcpu); > void kvm_timer_unschedule(struct kvm_vcpu *vcpu); > > diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c > index fa4c042..f72005a 100644 > --- a/virt/kvm/arm/arch_timer.c > +++ b/virt/kvm/arm/arch_timer.c > @@ -98,13 +98,13 @@ static void kvm_timer_inject_irq_work(struct work_struct > *work) > kvm_vcpu_kick(vcpu); > } > > -static u64 kvm_timer_compute_delta(struct kvm_vcpu *vcpu) > +static u64 kvm_timer_compute_delta(struct kvm_vcpu *vcpu, > +struct arch_timer_context *timer_ctx) > { > u64 cval, now; > - struct arch_timer_context *vtimer = vcpu_vtimer(vcpu); > > - cval = vtimer->cnt_cval; > - now = kvm_phys_timer_read() - vtimer->cntvoff; > + cval = timer_ctx->cnt_cval; > + now = kvm_phys_timer_read() - timer_ctx->cntvoff; > > if (now < cval) { > u64 ns; > @@ -133,7 +133,7 @@ static enum hrtimer_restart kvm_timer_expire(struct > hrtimer *hrt) >* PoV (NTP on the host may have forced it to expire >* early). If we should have slept longer, restart it. >*/ > - ns = kvm_timer_compute_delta(vcpu); > + ns = kvm_timer_compute_delta(vcpu, vcpu_vtimer(vcpu)); > if (unlikely(ns)) { > hrtimer_forward_now(hrt, ns_to_ktime(ns)); > return HRTIMER_RESTART; > @@ -143,42 +143,40 @@ static enum hrtimer_restart kvm_timer_expire(struct > hrtimer *hrt) > return HRTIMER_NORESTART; > } > > -static bool kvm_timer_irq_can_fire(struct kvm_vcpu *vcpu) > +static bool kvm_timer_irq_can_fire(struct arch_timer_context *timer_ctx) > { > - struct arch_timer_context *vtimer = vcpu_vtimer(vcpu); > - > - return !(vtimer->cnt_ctl & ARCH_TIMER_CTRL_IT_MASK) && > - (vtimer->cnt_ctl & ARCH_TIMER_CTRL_ENABLE); > + return !(timer_ctx->cnt_ctl & ARCH_TIMER_CTRL_IT_MASK) && > + (timer_ctx->cnt_ctl & ARCH_TIMER_CTRL_ENABLE); > } > > -bool kvm_timer_should_fire(struct kvm_vcpu *vcpu) > +bool kvm_timer_should_fire(struct kvm_vcpu *vcpu, > +struct arch_timer_context *timer_ctx) > { > - struct arch_timer_context *vtimer = vcpu_vtimer(vcpu); > u64 cval, now; > > - if (!kvm_timer_irq_can_fire(vcpu)) > + if (!kvm_timer_irq_can_fire(timer_ctx)) > return false; > > - cval = vtimer->cnt_cval; > - now = kvm_phys_timer_read() - vtimer->cntvoff; > + cval = timer_ctx->cnt_cval; > + now = kvm_phys_timer_read() - timer_ctx->cntvoff; > > return cval <= now; > } > > -static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level) > +static void kvm_timer_update_mapped_irq(struct kvm_vcpu *vcpu, bool > new_level, > + struct arch_timer_context *timer_ctx) > { > int ret; > - struct arch_timer_context *vtimer = vcpu_vtimer(vcpu); > > BUG_ON(!vgic_initialized(vcpu->kvm)); > > - vtimer->active_cleared_last = false; > - vtimer->irq.level = new_level; > - trace_kvm_timer_update_irq(vcpu->vcpu_id, vtimer->irq.irq, > -vtimer->irq.level); > + timer_ctx->active_cleared_last = false; > + timer_ctx->irq.level = new_level; > + trace_kvm_timer_update_irq(vcpu->vcpu_id, timer_ctx->irq.irq, > +timer_ctx->irq.level); > ret = kvm_vgic_injec
Re: [RFC v2 05/10] KVM: arm/arm64: Initialize the emulated EL1 physical timer
On Fri, Jan 27 2017 at 01:04:55 AM, Jintack Lim wrote: > Initialize the emulated EL1 physical timer with the default irq number. > > Signed-off-by: Jintack Lim > --- > arch/arm/kvm/reset.c | 9 - > arch/arm64/kvm/reset.c | 9 - > include/kvm/arm_arch_timer.h | 3 ++- > virt/kvm/arm/arch_timer.c| 9 +++-- > 4 files changed, 25 insertions(+), 5 deletions(-) > > diff --git a/arch/arm/kvm/reset.c b/arch/arm/kvm/reset.c > index 4b5e802..1da8b2d 100644 > --- a/arch/arm/kvm/reset.c > +++ b/arch/arm/kvm/reset.c > @@ -37,6 +37,11 @@ > .usr_regs.ARM_cpsr = SVC_MODE | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT, > }; > > +static const struct kvm_irq_level cortexa_ptimer_irq = { > + { .irq = 30 }, > + .level = 1, > +}; At some point, we'll have to make that discoverable/configurable. Maybe the time for a discoverable arch timer has come (see below). > + > static const struct kvm_irq_level cortexa_vtimer_irq = { > { .irq = 27 }, > .level = 1, > @@ -58,6 +63,7 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu) > { > struct kvm_regs *reset_regs; > const struct kvm_irq_level *cpu_vtimer_irq; > + const struct kvm_irq_level *cpu_ptimer_irq; > > switch (vcpu->arch.target) { > case KVM_ARM_TARGET_CORTEX_A7: > @@ -65,6 +71,7 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu) > reset_regs = &cortexa_regs_reset; > vcpu->arch.midr = read_cpuid_id(); > cpu_vtimer_irq = &cortexa_vtimer_irq; > + cpu_ptimer_irq = &cortexa_ptimer_irq; > break; > default: > return -ENODEV; > @@ -77,5 +84,5 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu) > kvm_reset_coprocs(vcpu); > > /* Reset arch_timer context */ > - return kvm_timer_vcpu_reset(vcpu, cpu_vtimer_irq); > + return kvm_timer_vcpu_reset(vcpu, cpu_vtimer_irq, cpu_ptimer_irq); > } > diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c > index e95d4f6..d9e9697 100644 > --- a/arch/arm64/kvm/reset.c > +++ b/arch/arm64/kvm/reset.c > @@ -46,6 +46,11 @@ > COMPAT_PSR_I_BIT | COMPAT_PSR_F_BIT), > }; > > +static const struct kvm_irq_level default_ptimer_irq = { > + .irq= 30, > + .level = 1, > +}; > + > static const struct kvm_irq_level default_vtimer_irq = { > .irq= 27, > .level = 1, > @@ -104,6 +109,7 @@ int kvm_arch_dev_ioctl_check_extension(struct kvm *kvm, > long ext) > int kvm_reset_vcpu(struct kvm_vcpu *vcpu) > { > const struct kvm_irq_level *cpu_vtimer_irq; > + const struct kvm_irq_level *cpu_ptimer_irq; > const struct kvm_regs *cpu_reset; > > switch (vcpu->arch.target) { > @@ -117,6 +123,7 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu) > } > > cpu_vtimer_irq = &default_vtimer_irq; > + cpu_ptimer_irq = &default_ptimer_irq; > break; > } > > @@ -130,5 +137,5 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu) > kvm_pmu_vcpu_reset(vcpu); > > /* Reset timer */ > - return kvm_timer_vcpu_reset(vcpu, cpu_vtimer_irq); > + return kvm_timer_vcpu_reset(vcpu, cpu_vtimer_irq, cpu_ptimer_irq); > } > diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h > index 69f648b..a364593 100644 > --- a/include/kvm/arm_arch_timer.h > +++ b/include/kvm/arm_arch_timer.h > @@ -59,7 +59,8 @@ struct arch_timer_cpu { > int kvm_timer_enable(struct kvm_vcpu *vcpu); > void kvm_timer_init(struct kvm *kvm); > int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu, > - const struct kvm_irq_level *irq); > + const struct kvm_irq_level *virt_irq, > + const struct kvm_irq_level *phys_irq); > void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu); > void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu); > void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu); > diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c > index f72005a..0f6e935 100644 > --- a/virt/kvm/arm/arch_timer.c > +++ b/virt/kvm/arm/arch_timer.c > @@ -329,9 +329,11 @@ void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu) > } > > int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu, > - const struct kvm_irq_level *irq) > + const struct kvm_irq_level *virt_irq, > + const struct kvm_irq_level *phys_irq) > { > struct arch_timer_context *vtimer = vcpu_vtimer(vcpu); > + struct arch_timer_context *ptimer = vcpu_ptimer(vcpu); > > /* >* The vcpu timer irq number cannot be determined in > @@ -339,7 +341,8 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu, >* kvm_vcpu_set_target(). To handle this, we determine >* vcpu timer irq number when the vcpu is reset. >*/ > - vtimer->irq.irq = irq->irq; > + vtimer->irq.irq = virt_irq->irq; > + ptimer->irq.irq = phys_irq->irq; > > /* >* The bits in CNTV_CTL are architectural
Re: next-20170125 hangs on aarch64
On Sun, Jan 29, 2017 at 03:42:55PM +0530, Yury Norov wrote: > Hi all, > > I pulled next-20170125 kernel, and found it hanged on boot. The exact reason > is > panic on dereferencing of the 0xffc8 address, which is most probably the > attempt to dereference the ENOSYS error code as the address. next-20170124 > works > fine, at least it boots. > > Does anyone have details on that? > > Yury UPD: I run qemu for testing. The true failure backtrace is like below. The bad dereference happens for me in arm_smccc_hvc() function in macro SMCCC. Yury Backtrace: #0 0x0808f7a8 in arm_smccc_hvc () at arch/arm64/kernel/smccc-call.S:50 #1 0x08745ea0 in __invoke_psci_fn_hvc (function_id=, arg0=, arg1=, arg2=) at drivers/firmware/psci.c:119 #2 0x08745d18 in psci_migrate_info_type () at drivers/firmware/psci.c:204 #3 0x08ca150c in psci_init_migrate () at drivers/firmware/psci.c:465 #4 psci_probe () at drivers/firmware/psci.c:539 #5 0x08ca1684 in psci_0_2_init (np=) at drivers/firmware/psci.c:571 #6 0x08ca16d8 in psci_dt_init () at drivers/firmware/psci.c:637 #7 0x08c62914 in setup_arch (cmdline_p=) at arch/arm64/kernel/setup.c:287 #8 0x08c6082c in start_kernel () at init/main.c:509 #9 0x08c601e0 in __primary_switched () at arch/arm64/kernel/head.S:452 Listing: │0x0808f790 hvc#0x0 │0x0808f794 ldrx4, [sp] │0x0808f798 stpx0, x1, [x4] │0x0808f79c stp x2, x3, [x4,#16] │0x0808f7a0 ldr x4, [sp,#8] │0x0808f7a4 cbz x4, 0x0808f7b8 >│0x0808f7a8 cmpx9, #0x1 │0x0808f7b0 b.ne 0x0808f7b8 │0x0808f7b4 strx6, [x4,#8] │0x0808f7b8 ret
mm: deadlock between get_online_cpus/pcpu_alloc
Hello, I've got the following deadlock report while running syzkaller fuzzer on f37208bc3c9c2f811460ef264909dfbc7f605a60: [ INFO: possible circular locking dependency detected ] 4.10.0-rc5-next-20170125 #1 Not tainted --- syz-executor3/14255 is trying to acquire lock: (cpu_hotplug.dep_map){++}, at: [] get_online_cpus+0x37/0x90 kernel/cpu.c:239 but task is already holding lock: (pcpu_alloc_mutex){+.+.+.}, at: [] pcpu_alloc+0xbfe/0x1290 mm/percpu.c:897 which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #2 (pcpu_alloc_mutex){+.+.+.}: [] validate_chain kernel/locking/lockdep.c:2265 [inline] [] __lock_acquire+0x2149/0x3430 kernel/locking/lockdep.c:3338 [] lock_acquire+0x2a1/0x630 kernel/locking/lockdep.c:3753 [] __mutex_lock_common kernel/locking/mutex.c:757 [inline] [] __mutex_lock+0x382/0x25c0 kernel/locking/mutex.c:894 [] mutex_lock_nested+0x16/0x20 kernel/locking/mutex.c:909 [] pcpu_alloc+0xbfe/0x1290 mm/percpu.c:897 [] __alloc_percpu+0x24/0x30 mm/percpu.c:1076 [] smpcfd_prepare_cpu+0x73/0xd0 kernel/smp.c:47 [] cpuhp_invoke_callback+0x256/0x1480 kernel/cpu.c:136 [] cpuhp_up_callbacks+0x81/0x2a0 kernel/cpu.c:425 [] _cpu_up+0x1e3/0x2a0 kernel/cpu.c:940 [] do_cpu_up+0x73/0xa0 kernel/cpu.c:970 [] cpu_up+0x18/0x20 kernel/cpu.c:978 [] smp_init+0x148/0x160 kernel/smp.c:565 [] kernel_init_freeable+0x43e/0x695 init/main.c:1026 [] kernel_init+0x13/0x180 init/main.c:955 [] ret_from_fork+0x31/0x40 arch/x86/entry/entry_64.S:430 -> #1 (cpu_hotplug.lock){+.+.+.}: [] validate_chain kernel/locking/lockdep.c:2265 [inline] [] __lock_acquire+0x2149/0x3430 kernel/locking/lockdep.c:3338 [] lock_acquire+0x2a1/0x630 kernel/locking/lockdep.c:3753 [] __mutex_lock_common kernel/locking/mutex.c:757 [inline] [] __mutex_lock+0x382/0x25c0 kernel/locking/mutex.c:894 [] mutex_lock_nested+0x16/0x20 kernel/locking/mutex.c:909 [] cpu_hotplug_begin+0x206/0x2e0 kernel/cpu.c:297 [] _cpu_up+0xca/0x2a0 kernel/cpu.c:894 [] do_cpu_up+0x73/0xa0 kernel/cpu.c:970 [] cpu_up+0x18/0x20 kernel/cpu.c:978 [] smp_init+0x148/0x160 kernel/smp.c:565 [] kernel_init_freeable+0x43e/0x695 init/main.c:1026 [] kernel_init+0x13/0x180 init/main.c:955 [] ret_from_fork+0x31/0x40 arch/x86/entry/entry_64.S:430 -> #0 (cpu_hotplug.dep_map){++}: [] check_prev_add kernel/locking/lockdep.c:1828 [inline] [] check_prevs_add+0xa8f/0x19f0 kernel/locking/lockdep.c:1938 [] validate_chain kernel/locking/lockdep.c:2265 [inline] [] __lock_acquire+0x2149/0x3430 kernel/locking/lockdep.c:3338 [] lock_acquire+0x2a1/0x630 kernel/locking/lockdep.c:3753 [] get_online_cpus+0x62/0x90 kernel/cpu.c:241 [] drain_all_pages.part.98+0x8c/0x8f0 mm/page_alloc.c:2371 [] drain_all_pages mm/page_alloc.c:2364 [inline] [] __alloc_pages_direct_reclaim mm/page_alloc.c:3435 [inline] [] __alloc_pages_slowpath+0x966/0x23d0 mm/page_alloc.c:3773 [] __alloc_pages_nodemask+0x8f5/0xc60 mm/page_alloc.c:3975 [] __alloc_pages include/linux/gfp.h:426 [inline] [] __alloc_pages_node include/linux/gfp.h:439 [inline] [] alloc_pages_node include/linux/gfp.h:453 [inline] [] pcpu_alloc_pages mm/percpu-vm.c:93 [inline] [] pcpu_populate_chunk+0x1e1/0x900 mm/percpu-vm.c:282 [] pcpu_alloc+0xe15/0x1290 mm/percpu.c:999 [] __alloc_percpu_gfp+0x27/0x30 mm/percpu.c:1063 [] bpf_array_alloc_percpu kernel/bpf/arraymap.c:33 [inline] [] array_map_alloc+0x543/0x700 kernel/bpf/arraymap.c:94 [] find_and_alloc_map kernel/bpf/syscall.c:37 [inline] [] map_create kernel/bpf/syscall.c:228 [inline] [] SYSC_bpf kernel/bpf/syscall.c:1040 [inline] [] SyS_bpf+0x108d/0x27c0 kernel/bpf/syscall.c:997 [] entry_SYSCALL_64_fastpath+0x1f/0xc2 other info that might help us debug this: Chain exists of: cpu_hotplug.dep_map --> cpu_hotplug.lock --> pcpu_alloc_mutex Possible unsafe locking scenario: CPU0CPU1 lock(pcpu_alloc_mutex); lock(cpu_hotplug.lock); lock(pcpu_alloc_mutex); lock(cpu_hotplug.dep_map); *** DEADLOCK *** 1 lock held by syz-executor3/14255: #0: (pcpu_alloc_mutex){+.+.+.}, at: [] pcpu_alloc+0xbfe/0x1290 mm/percpu.c:897 stack backtrace: CPU: 1 PID: 14255 Comm: syz-executor3 Not tainted 4.10.0-rc5-next-20170125 #1 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:15 [inline] dump_stack+0x2ee/0x3ef lib/dump_stack.c:51 print_circular_bug+0x307/0x3b0 kernel/locking/lockdep.c:1202 check_prev_add kernel/locking/lockdep.c:1828 [inline] check_prevs_add+0xa8f/0x19f0 kernel/locking/lockdep.c:1938 validate_chain kernel/locking/lockdep.c:2265 [inline] __lock_acquire+0x2149/0x3430 kernel/locking/lockdep.c:3338 lock_acquire+0x2a1/0x630 kernel/locking/lockdep.c:3753 get_online_cpus+0x62/0x90 kernel/cpu.c:241 drain_all_pages.part.98+0x8c/0x8f0 mm/page_alloc.c:2371 drain_all_pages mm/page_alloc.c:2364 [inline] __alloc
[PATCH] gianfar: synchronize DMA API usage by free_skb_rx_queue w/ gfar_new_page
From: Arseny Solokha In spite of switching to paged allocation of Rx buffers, the driver still called dma_unmap_single() in the Rx queues tear-down path. The DMA region unmapping code in free_skb_rx_queue() basically predates the introduction of paged allocation to the driver. While being refactored, it apparently hasn't reflected the change in the DMA API usage by its counterpart gfar_new_page(). As a result, setting an interface to the DOWN state now yields the following: # ip link set eth2 down fsl-gianfar ffe24000.ethernet: DMA-API: device driver frees DMA memory with wrong function [device address=0x1ecd] [size=40] [ cut here ] WARNING: CPU: 1 PID: 189 at lib/dma-debug.c:1123 check_unmap+0x8e0/0xa28 CPU: 1 PID: 189 Comm: ip Tainted: G O4.9.5 #1 task: dee73400 task.stack: dede2000 NIP: c02101e8 LR: c02101e8 CTR: c0260d74 REGS: dede3bb0 TRAP: 0700 Tainted: G O (4.9.5) MSR: 00021000 CR: 2800 XER: GPR00: c02101e8 dede3c60 dee73400 00b6 dfbd033c dfbd36c4 1f622000 dede2000 GPR08: 0007 c05b1634 1f622000 22002484 100a9904 GPR16: db4c849c 0002 db4c8480 0001 df142240 db4c84bc GPR24: c0706148 c070 00029000 c07552e8 c07323b4 dede3cb8 c07605e0 db535540 NIP [c02101e8] check_unmap+0x8e0/0xa28 LR [c02101e8] check_unmap+0x8e0/0xa28 Call Trace: [dede3c60] [c02101e8] check_unmap+0x8e0/0xa28 (unreliable) [dede3cb0] [c02103b8] debug_dma_unmap_page+0x88/0x9c [dede3d30] [c02dffbc] free_skb_resources+0x2c4/0x404 [dede3d80] [c02e39b4] gfar_close+0x24/0xc8 [dede3da0] [c0361550] __dev_close_many+0xa0/0xf8 [dede3dd0] [c03616f0] __dev_close+0x2c/0x4c [dede3df0] [c036b1b8] __dev_change_flags+0xa0/0x174 [dede3e10] [c036b2ac] dev_change_flags+0x20/0x60 [dede3e30] [c03e130c] devinet_ioctl+0x540/0x824 [dede3e90] [c0347dcc] sock_ioctl+0x134/0x298 [dede3eb0] [c0111814] do_vfs_ioctl+0xac/0x854 [dede3f20] [c0111ffc] SyS_ioctl+0x40/0x74 [dede3f40] [c000f290] ret_from_syscall+0x0/0x3c --- interrupt: c01 at 0xff45da0 LR = 0xff45cd0 Instruction dump: 811d001c 7c66482e 813d0020 9061000c 807f000c 5463103a 7cc6182e 3c60c052 386309ac 90c10008 4cc63182 4826b845 <0fe0> 4bfffa60 3c80c052 388402c4 ---[ end trace 695ae6d7ac1d0c47 ]--- Mapped at: [] gfar_alloc_rx_buffs+0x178/0x248 [] startup_gfar+0x368/0x570 [] __dev_open+0xdc/0x150 [] __dev_change_flags+0xa0/0x174 [] dev_change_flags+0x20/0x60 Even though the issue was discovered in 4.9 kernel, the code in question is identical in the current net and net-next trees. Fixes: 75354148ce69 ("gianfar: Add paged allocation and Rx S/G") Signed-off-by: Arseny Solokha --- drivers/net/ethernet/freescale/gianfar.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index c1b671667920..957bfc220978 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -2010,8 +2010,8 @@ static void free_skb_rx_queue(struct gfar_priv_rx_q *rx_queue) if (!rxb->page) continue; - dma_unmap_single(rx_queue->dev, rxb->dma, -PAGE_SIZE, DMA_FROM_DEVICE); + dma_unmap_page(rx_queue->dev, rxb->dma, + PAGE_SIZE, DMA_FROM_DEVICE); __free_page(rxb->page); rxb->page = NULL; -- 2.11.0
Re: net: deadlock on genl_mutex
On Fri, Dec 9, 2016 at 6:08 AM, Cong Wang wrote: >>> Chain exists of: >>> Possible unsafe locking scenario: >>> >>>CPU0CPU1 >>> >>> lock(genl_mutex); >>>lock(nlk->cb_mutex); >>>lock(genl_mutex); >>> lock(rtnl_mutex); >>> >>> *** DEADLOCK *** >> >> This one looks legitimate, because nlk->cb_mutex could be rtnl_mutex. >> Let me think about it. > > Never mind. Actually both reports in this thread are legitimate. > > I know what happened now, the lock chain is so long, 4 locks are involved > to form a chain!!! > > Let me think about how to break the chain. Cong, any success with breaking the chain? Still happenning on f0ad17712b9f71c24e2b8b9725230ef57232377f. Or is it a different one? [ INFO: possible circular locking dependency detected ] 4.10.0-rc3+ #4 Not tainted --- syz-executor9/2705 is trying to acquire lock: (genl_mutex){+.+.+.}, at: [] genl_lock net/netlink/genetlink.c:32 [inline] (genl_mutex){+.+.+.}, at: [] genl_family_rcv_msg+0xdae/0x1040 net/netlink/genetlink.c:547 but task is already holding lock: (rtnl_mutex){+.+.+.}, at: [] rtnl_lock+0x17/0x20 net/core/rtnetlink.c:70 which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #1 (rtnl_mutex){+.+.+.}: [] validate_chain kernel/locking/lockdep.c:2265 [inline] [] __lock_acquire+0x2149/0x3430 kernel/locking/lockdep.c:3338 [] lock_acquire+0x2a1/0x630 kernel/locking/lockdep.c:3753 [] __mutex_lock_common kernel/locking/mutex.c:639 [inline] [] mutex_lock_nested+0x290/0x1730 kernel/locking/mutex.c:753 [] rtnl_lock+0x17/0x20 net/core/rtnetlink.c:70 [] nl80211_pre_doit+0x2fe/0x570 net/wireless/nl80211.c:11847 [] genl_family_rcv_msg+0x760/0x1040 net/netlink/genetlink.c:591 [] genl_rcv_msg+0x19a/0x330 net/netlink/genetlink.c:620 [] netlink_rcv_skb+0x2ab/0x390 net/netlink/af_netlink.c:2298 [] genl_rcv+0x28/0x40 net/netlink/genetlink.c:631 [] netlink_unicast_kernel net/netlink/af_netlink.c:1231 [inline] [] netlink_unicast+0x514/0x730 net/netlink/af_netlink.c:1257 [] netlink_sendmsg+0xa9f/0xe50 net/netlink/af_netlink.c:1803 [] sock_sendmsg_nosec net/socket.c:635 [inline] [] sock_sendmsg+0xca/0x110 net/socket.c:645 [] ___sys_sendmsg+0x8fa/0x9f0 net/socket.c:1985 [] __sys_sendmsg+0x138/0x300 net/socket.c:2019 [] SYSC_sendmsg net/socket.c:2030 [inline] [] SyS_sendmsg+0x2d/0x50 net/socket.c:2026 [] entry_SYSCALL_64_fastpath+0x1f/0xc2 -> #0 (genl_mutex){+.+.+.}: [] check_prev_add kernel/locking/lockdep.c:1828 [inline] [] check_prevs_add+0xa8f/0x19f0 kernel/locking/lockdep.c:1938 [] validate_chain kernel/locking/lockdep.c:2265 [inline] [] __lock_acquire+0x2149/0x3430 kernel/locking/lockdep.c:3338 [] lock_acquire+0x2a1/0x630 kernel/locking/lockdep.c:3753 [] __mutex_lock_common kernel/locking/mutex.c:639 [inline] [] mutex_lock_nested+0x290/0x1730 kernel/locking/mutex.c:753 [] genl_lock net/netlink/genetlink.c:32 [inline] [] genl_family_rcv_msg+0xdae/0x1040 net/netlink/genetlink.c:547 [] genl_rcv_msg+0x19a/0x330 net/netlink/genetlink.c:620 [] netlink_rcv_skb+0x2ab/0x390 net/netlink/af_netlink.c:2298 [] genl_rcv+0x28/0x40 net/netlink/genetlink.c:631 [] netlink_unicast_kernel net/netlink/af_netlink.c:1231 [inline] [] netlink_unicast+0x514/0x730 net/netlink/af_netlink.c:1257 [] netlink_sendmsg+0xa9f/0xe50 net/netlink/af_netlink.c:1803 [] sock_sendmsg_nosec net/socket.c:635 [inline] [] sock_sendmsg+0xca/0x110 net/socket.c:645 [] sock_write_iter+0x326/0x600 net/socket.c:848 [] new_sync_write fs/read_write.c:499 [inline] [] __vfs_write+0x483/0x740 fs/read_write.c:512 [] vfs_write+0x187/0x530 fs/read_write.c:560 [] SYSC_write fs/read_write.c:607 [inline] [] SyS_write+0xfb/0x230 fs/read_write.c:599 [] entry_SYSCALL_64_fastpath+0x1f/0xc2 other info that might help us debug this: Possible unsafe locking scenario: CPU0CPU1 lock(rtnl_mutex); lock(genl_mutex); lock(rtnl_mutex); lock(genl_mutex); *** DEADLOCK *** 2 locks held by syz-executor9/2705: #0: (cb_lock){++}, at: [] genl_rcv+0x19/0x40 net/netlink/genetlink.c:630 #1: (rtnl_mutex){+.+.+.}, at: [] rtnl_lock+0x17/0x20 net/core/rtnetlink.c:70 stack backtrace: CPU: 1 PID: 2705 Comm: syz-executor9 Not tainted 4.10.0-rc3+ #4 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:15 [inline] dump_stack+0x2ee/0x3ef lib/dump_stack.c:51 print_circular_bug+0x307/0x3b0 kernel/locking/lockdep.c:1202 check_prev_add kernel/locking/lockdep.c:1828 [inline] check_prevs_add+0xa8f/0x19f0 kernel/locking/lockdep.c:1938 validate_chain kernel/locking/lockdep.c:2265 [inline] __lock_acquire+0x2149/0x3430 kernel/locking/lockdep.c:3338 lock_acquire+0x2a1/0x630 kernel/locking/lockdep.c:3753 __
Exynos5422 EHCI (USB 2.0) - Odroid XU4 - port 1 resume error -110
Hi, On Odroid XU4 with an external usb2514 hub (evaluation board from SMSC or TI) connected to the USB2.0 port of EHCI controller, whenever I plug some USB device into the usb2514 hub I see errors like: [ 73.969179] exynos-ehci 1211.usb: port 1 resume error -110 [ 74.003259] usb 1-1: USB disconnect, device number 2 [ 74.017432] usb usb1-port1: cannot reset (err = -32) [ 74.021141] usb usb1-port1: cannot reset (err = -32) [ 74.026832] usb usb1-port1: cannot reset (err = -32) [ 74.030974] usb usb1-port1: cannot reset (err = -32) [ 74.036677] usb usb1-port1: cannot reset (err = -32) [ 74.041919] usb usb1-port1: Cannot enable. Maybe the USB cable is bad? [ 74.140923] usb usb1-port1: unable to enumerate USB device Flooding the console. USB device does not work. Tested: 1. next-20170125, 2. mainline v4.10-rc5-393-g53cd1ad1a68f, 3. Hardkernel vendor kernel 3.10 It does not look like an issue of usb2514 but rather a combination of usb2514 + Exynos EHCI because: 1. Happens only when usb2514 hub is directly connected to the USB2.0 port of EHCI controller. 2. If usb2514 is connected through other hub (like to other ports on the board) - everything works fine. 3. I tested two different usb2514 hubs - one from TI, second from SMSC. Both behave the same. 4. I had the same issue on DWC3 controller (USB 3.0 port) and in that case helped ENABLING bits DWC3_GUSB2PHYCFG_SUSPHY and DWC3_GUSB3PIPECTL_SUSPHY which is I think equal to disabling the snps,dis_u3_susphy_quirk quirks. It seems that issue is strictly related to Exynos5422 USB 2.0 driver (phy?) and this hub. The drivers involved: - drivers/phy/phy-exynos5250-usb2.c - drivers/phy/phy-samsung-usb2.c - drivers/usb/host/ehci-exynos.c Any ideas? Best regards, Krzysztof
[PATCH v3 21/24] drm/rockchip: dw-mipi-dsi: defer probe if panel is not loaded
This ensures that the output resolution is known before fbcon loads. Signed-off-by: John Keeping --- Unchanged in v3 Unchanged in v2 drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 11 +-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c index f5b15377ef85..5bad92e2370e 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c @@ -1176,10 +1176,17 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master, dsi->dsi_host.ops = &dw_mipi_dsi_host_ops; dsi->dsi_host.dev = dev; - return mipi_dsi_host_register(&dsi->dsi_host); + ret = mipi_dsi_host_register(&dsi->dsi_host); + if (!ret && !dsi->panel) { + mipi_dsi_host_unregister(&dsi->dsi_host); + drm_encoder_cleanup(&dsi->encoder); + drm_connector_cleanup(&dsi->connector); + ret = -EPROBE_DEFER; + } err_pllref: - clk_disable_unprepare(dsi->pllref_clk); + if (ret) + clk_disable_unprepare(dsi->pllref_clk); return ret; } -- 2.11.0.197.gb556de5.dirty
[PATCH v3 08/24] drm/rockchip: dw-mipi-dsi: respect message flags
Instead of always sending commands in LP mode, respect the MIPI_DSI_MSG_USE_LPM flag to decide how to send each message. Also request acks if MIPI_DSI_MSG_REQ_ACK is set. Signed-off-by: John Keeping Reviewed-by: Chris Zhong --- v3: - Add Chris' Reviewed-by Unchanged in v2 drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 16 +++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c index 92dbc3e56603..15d33c3c8cb7 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c @@ -542,6 +542,19 @@ static int dw_mipi_dsi_host_detach(struct mipi_dsi_host *host, return 0; } +static void dw_mipi_message_config(struct dw_mipi_dsi *dsi, + const struct mipi_dsi_msg *msg) +{ + u32 val = 0; + + if (msg->flags & MIPI_DSI_MSG_REQ_ACK) + val |= EN_ACK_RQST; + if (msg->flags & MIPI_DSI_MSG_USE_LPM) + val |= CMD_MODE_ALL_LP; + + dsi_write(dsi, DSI_CMD_MODE_CFG, val); +} + static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val) { int ret; @@ -634,6 +647,8 @@ static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host, struct dw_mipi_dsi *dsi = host_to_dsi(host); int ret; + dw_mipi_message_config(dsi, msg); + switch (msg->type) { case MIPI_DSI_DCS_SHORT_WRITE: case MIPI_DSI_DCS_SHORT_WRITE_PARAM: @@ -745,7 +760,6 @@ static void dw_mipi_dsi_command_mode_config(struct dw_mipi_dsi *dsi) { dsi_write(dsi, DSI_TO_CNT_CFG, HSTX_TO_CNT(1000) | LPRX_TO_CNT(1000)); dsi_write(dsi, DSI_BTA_TO_CNT, 0xd00); - dsi_write(dsi, DSI_CMD_MODE_CFG, CMD_MODE_ALL_LP); dsi_write(dsi, DSI_MODE_CFG, ENABLE_CMD_MODE); } -- 2.11.0.197.gb556de5.dirty
[PATCH v3 06/24] drm/rockchip: dw-mipi-dsi: avoid out-of-bounds read on tx_buf
As a side-effect of this, encode the endianness explicitly rather than casting a u16. Signed-off-by: John Keeping Reviewed-by: Chris Zhong --- v3: - Add Chris' Reviewed-by Unchanged in v2 drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 9 +++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c index 4be1ff3a42bb..2e6ad4591ebf 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c @@ -572,8 +572,13 @@ static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val) static int dw_mipi_dsi_dcs_short_write(struct dw_mipi_dsi *dsi, const struct mipi_dsi_msg *msg) { - const u16 *tx_buf = msg->tx_buf; - u32 val = GEN_HDATA(*tx_buf) | GEN_HTYPE(msg->type); + const u8 *tx_buf = msg->tx_buf; + u32 val = GEN_HTYPE(msg->type); + + if (msg->tx_len > 0) + val |= GEN_HDATA(tx_buf[0]); + if (msg->tx_len > 1) + val |= GEN_HDATA(tx_buf[1] << 8); if (msg->tx_len > 2) { dev_err(dsi->dev, "too long tx buf length %zu for short write\n", -- 2.11.0.197.gb556de5.dirty
[PATCH v3 01/24] drm/rockchip: dw-mipi-dsi: don't configure hardware in mode_set for MIPI
With atomic modesetting the hardware will be powered off when the mode_set function is called. We should configure the hardware in the enable function, which is the atomic version of "commit" so let's use the enable hook rather than commit while we're at it. Signed-off-by: John Keeping --- v3: - Squash together with the commit to s/commit/enable/ Unchanged in v2 drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 49 +++--- 1 file changed, 21 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c index d9aa382bb629..bbd992299f73 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c @@ -819,34 +819,8 @@ static void dw_mipi_dsi_encoder_mode_set(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode) { struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder); - int ret; dsi->mode = adjusted_mode; - - ret = dw_mipi_dsi_get_lane_bps(dsi); - if (ret < 0) - return; - - if (clk_prepare_enable(dsi->pclk)) { - dev_err(dsi->dev, "%s: Failed to enable pclk\n", __func__); - return; - } - - dw_mipi_dsi_init(dsi); - dw_mipi_dsi_dpi_config(dsi, mode); - dw_mipi_dsi_packet_handler_config(dsi); - dw_mipi_dsi_video_mode_config(dsi); - dw_mipi_dsi_video_packet_config(dsi, mode); - dw_mipi_dsi_command_mode_config(dsi); - dw_mipi_dsi_line_timer_config(dsi); - dw_mipi_dsi_vertical_timing_config(dsi); - dw_mipi_dsi_dphy_timing_config(dsi); - dw_mipi_dsi_dphy_interface_config(dsi); - dw_mipi_dsi_clear_err(dsi); - if (drm_panel_prepare(dsi->panel)) - dev_err(dsi->dev, "failed to prepare panel\n"); - - clk_disable_unprepare(dsi->pclk); } static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder) @@ -875,17 +849,36 @@ static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder) clk_disable_unprepare(dsi->pclk); } -static void dw_mipi_dsi_encoder_commit(struct drm_encoder *encoder) +static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder) { struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder); int mux = drm_of_encoder_active_endpoint_id(dsi->dev->of_node, encoder); u32 val; + int ret; + + ret = dw_mipi_dsi_get_lane_bps(dsi); + if (ret < 0) + return; if (clk_prepare_enable(dsi->pclk)) { dev_err(dsi->dev, "%s: Failed to enable pclk\n", __func__); return; } + dw_mipi_dsi_init(dsi); + dw_mipi_dsi_dpi_config(dsi, dsi->mode); + dw_mipi_dsi_packet_handler_config(dsi); + dw_mipi_dsi_video_mode_config(dsi); + dw_mipi_dsi_video_packet_config(dsi, dsi->mode); + dw_mipi_dsi_command_mode_config(dsi); + dw_mipi_dsi_line_timer_config(dsi); + dw_mipi_dsi_vertical_timing_config(dsi); + dw_mipi_dsi_dphy_timing_config(dsi); + dw_mipi_dsi_dphy_interface_config(dsi); + dw_mipi_dsi_clear_err(dsi); + if (drm_panel_prepare(dsi->panel)) + dev_err(dsi->dev, "failed to prepare panel\n"); + dw_mipi_dsi_phy_init(dsi); dw_mipi_dsi_wait_for_two_frames(dsi); @@ -933,7 +926,7 @@ dw_mipi_dsi_encoder_atomic_check(struct drm_encoder *encoder, static struct drm_encoder_helper_funcs dw_mipi_dsi_encoder_helper_funcs = { - .commit = dw_mipi_dsi_encoder_commit, + .enable = dw_mipi_dsi_encoder_enable, .mode_set = dw_mipi_dsi_encoder_mode_set, .disable = dw_mipi_dsi_encoder_disable, .atomic_check = dw_mipi_dsi_encoder_atomic_check, -- 2.11.0.197.gb556de5.dirty
[PATCH v3 00/24] drm/rockchip: MIPI fixes & improvements
This re-roll mostly just gather up reviewed-by tags, although I have also wrapped some long lines and squashed together some commits as suggested by Chris Zhong. Version 2 was posted here: https://www.spinics.net/lists/arm-kernel/msg556683.html John Keeping (24): drm/rockchip: dw-mipi-dsi: don't configure hardware in mode_set for MIPI drm/rockchip: dw-mipi-dsi: pass mode in where needed drm/rockchip: dw-mipi-dsi: remove mode_set hook drm/rockchip: dw-mipi-dsi: fix command header writes drm/rockchip: dw-mipi-dsi: fix generic packet status check drm/rockchip: dw-mipi-dsi: avoid out-of-bounds read on tx_buf drm/rockchip: dw-mipi-dsi: include bad value in error message drm/rockchip: dw-mipi-dsi: respect message flags drm/rockchip: dw-mipi-dsi: only request HS clock when required drm/rockchip: dw-mipi-dsi: don't assume buffer is aligned drm/rockchip: dw-mipi-dsi: prepare panel after phy init drm/rockchip: dw-mipi-dsi: allow commands in panel_disable drm/rockchip: dw-mipi-dsi: fix escape clock rate drm/rockchip: dw-mipi-dsi: ensure PHY is reset drm/rockchip: dw-mipi-dsi: configure PHY before enabling drm/rockchip: dw-mipi-dsi: properly configure PHY timing drm/rockchip: dw-mipi-dsi: improve PLL configuration drm/rockchip: dw-mipi-dsi: use specific poll helper drm/rockchip: dw-mipi-dsi: use positive check for N{H,V}SYNC drm/rockchip: vop: test for P{H,V}SYNC drm/rockchip: dw-mipi-dsi: defer probe if panel is not loaded drm/rockchip: dw-mipi-dsi: support non-burst modes drm/rockchip: dw-mipi-dsi: add reset control drm/rockchip: dw-mipi-dsi: support read commands drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 348 +++- drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 4 +- 2 files changed, 245 insertions(+), 107 deletions(-) -- 2.11.0.197.gb556de5.dirty
[PATCH v3 10/24] drm/rockchip: dw-mipi-dsi: don't assume buffer is aligned
By dereferencing the MIPI command buffer as a u32* we rely on it being correctly aligned on ARM, but this may not be the case. Copy it into a stack variable that will be correctly aligned. Signed-off-by: John Keeping Reviewed-by: Chris Zhong --- v3: - Add Chris' Reviewed-by Unchanged in v2 drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 12 +++- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c index 03fc096fe1bd..ddbc037e7ced 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c @@ -607,10 +607,10 @@ static int dw_mipi_dsi_dcs_short_write(struct dw_mipi_dsi *dsi, static int dw_mipi_dsi_dcs_long_write(struct dw_mipi_dsi *dsi, const struct mipi_dsi_msg *msg) { - const u32 *tx_buf = msg->tx_buf; - int len = msg->tx_len, pld_data_bytes = sizeof(*tx_buf), ret; + const u8 *tx_buf = msg->tx_buf; + int len = msg->tx_len, pld_data_bytes = sizeof(u32), ret; u32 hdr_val = GEN_HDATA(msg->tx_len) | GEN_HTYPE(msg->type); - u32 remainder = 0; + u32 remainder; u32 val; if (msg->tx_len < 3) { @@ -621,12 +621,14 @@ static int dw_mipi_dsi_dcs_long_write(struct dw_mipi_dsi *dsi, while (DIV_ROUND_UP(len, pld_data_bytes)) { if (len < pld_data_bytes) { + remainder = 0; memcpy(&remainder, tx_buf, len); dsi_write(dsi, DSI_GEN_PLD_DATA, remainder); len = 0; } else { - dsi_write(dsi, DSI_GEN_PLD_DATA, *tx_buf); - tx_buf++; + memcpy(&remainder, tx_buf, pld_data_bytes); + dsi_write(dsi, DSI_GEN_PLD_DATA, remainder); + tx_buf += pld_data_bytes; len -= pld_data_bytes; } -- 2.11.0.197.gb556de5.dirty
[PATCH v3 09/24] drm/rockchip: dw-mipi-dsi: only request HS clock when required
Requesting the HS clock from the PHY before we initialize it causes an invalid signal to be sent out since the input clock is not yet configured. The PHY databook suggests only asserting this signal when performing HS transfers, so let's do that. Signed-off-by: John Keeping Reviewed-by: Chris Zhong --- v3: - Add Chris' Reviewed-by Unchanged in v2 drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 6 -- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c index 15d33c3c8cb7..03fc096fe1bd 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c @@ -545,13 +545,15 @@ static int dw_mipi_dsi_host_detach(struct mipi_dsi_host *host, static void dw_mipi_message_config(struct dw_mipi_dsi *dsi, const struct mipi_dsi_msg *msg) { + bool lpm = msg->flags & MIPI_DSI_MSG_USE_LPM; u32 val = 0; if (msg->flags & MIPI_DSI_MSG_REQ_ACK) val |= EN_ACK_RQST; - if (msg->flags & MIPI_DSI_MSG_USE_LPM) + if (lpm) val |= CMD_MODE_ALL_LP; + dsi_write(dsi, DSI_LPCLK_CTRL, lpm ? 0 : PHY_TXREQUESTCLKHS); dsi_write(dsi, DSI_CMD_MODE_CFG, val); } @@ -693,6 +695,7 @@ static void dw_mipi_dsi_set_mode(struct dw_mipi_dsi *dsi, dsi_write(dsi, DSI_PWR_UP, RESET); dsi_write(dsi, DSI_MODE_CFG, ENABLE_VIDEO_MODE); dw_mipi_dsi_video_mode_config(dsi); + dsi_write(dsi, DSI_LPCLK_CTRL, PHY_TXREQUESTCLKHS); dsi_write(dsi, DSI_PWR_UP, POWERUP); } } @@ -710,7 +713,6 @@ static void dw_mipi_dsi_init(struct dw_mipi_dsi *dsi) | PHY_RSTZ | PHY_SHUTDOWNZ); dsi_write(dsi, DSI_CLKMGR_CFG, TO_CLK_DIVIDSION(10) | TX_ESC_CLK_DIVIDSION(7)); - dsi_write(dsi, DSI_LPCLK_CTRL, PHY_TXREQUESTCLKHS); } static void dw_mipi_dsi_dpi_config(struct dw_mipi_dsi *dsi, -- 2.11.0.197.gb556de5.dirty
[PATCH v3 02/24] drm/rockchip: dw-mipi-dsi: pass mode in where needed
This shows that we only use the mode from the enable function and prepares us to remove the "mode" field and the mode_set hook in the next commit. Signed-off-by: John Keeping Reviewed-by: Chris Zhong --- v3: - Add Chris' Reviewed-by New in v2 drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 41 ++ 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c index bbd992299f73..cdbd25087e83 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c @@ -330,11 +330,11 @@ static int max_mbps_to_testdin(unsigned int max_mbps) * The controller should generate 2 frames before * preparing the peripheral. */ -static void dw_mipi_dsi_wait_for_two_frames(struct dw_mipi_dsi *dsi) +static void dw_mipi_dsi_wait_for_two_frames(struct drm_display_mode *mode) { int refresh, two_frames; - refresh = drm_mode_vrefresh(dsi->mode); + refresh = drm_mode_vrefresh(mode); two_frames = DIV_ROUND_UP(MSEC_PER_SEC, refresh) * 2; msleep(two_frames); } @@ -459,7 +459,8 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi) return ret; } -static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi) +static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi, + struct drm_display_mode *mode) { unsigned int i, pre; unsigned long mpclk, pllref, tmp; @@ -474,7 +475,7 @@ static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi) return bpp; } - mpclk = DIV_ROUND_UP(dsi->mode->clock, MSEC_PER_SEC); + mpclk = DIV_ROUND_UP(mode->clock, MSEC_PER_SEC); if (mpclk) { /* take 1 / 0.9, since mbps must big than bandwidth of RGB */ tmp = mpclk * (bpp / dsi->lanes) * 10 / 9; @@ -742,43 +743,44 @@ static void dw_mipi_dsi_command_mode_config(struct dw_mipi_dsi *dsi) /* Get lane byte clock cycles. */ static u32 dw_mipi_dsi_get_hcomponent_lbcc(struct dw_mipi_dsi *dsi, + struct drm_display_mode *mode, u32 hcomponent) { u32 frac, lbcc; lbcc = hcomponent * dsi->lane_mbps * MSEC_PER_SEC / 8; - frac = lbcc % dsi->mode->clock; - lbcc = lbcc / dsi->mode->clock; + frac = lbcc % mode->clock; + lbcc = lbcc / mode->clock; if (frac) lbcc++; return lbcc; } -static void dw_mipi_dsi_line_timer_config(struct dw_mipi_dsi *dsi) +static void dw_mipi_dsi_line_timer_config(struct dw_mipi_dsi *dsi, + struct drm_display_mode *mode) { u32 htotal, hsa, hbp, lbcc; - struct drm_display_mode *mode = dsi->mode; htotal = mode->htotal; hsa = mode->hsync_end - mode->hsync_start; hbp = mode->htotal - mode->hsync_end; - lbcc = dw_mipi_dsi_get_hcomponent_lbcc(dsi, htotal); + lbcc = dw_mipi_dsi_get_hcomponent_lbcc(dsi, mode, htotal); dsi_write(dsi, DSI_VID_HLINE_TIME, lbcc); - lbcc = dw_mipi_dsi_get_hcomponent_lbcc(dsi, hsa); + lbcc = dw_mipi_dsi_get_hcomponent_lbcc(dsi, mode, hsa); dsi_write(dsi, DSI_VID_HSA_TIME, lbcc); - lbcc = dw_mipi_dsi_get_hcomponent_lbcc(dsi, hbp); + lbcc = dw_mipi_dsi_get_hcomponent_lbcc(dsi, mode, hbp); dsi_write(dsi, DSI_VID_HBP_TIME, lbcc); } -static void dw_mipi_dsi_vertical_timing_config(struct dw_mipi_dsi *dsi) +static void dw_mipi_dsi_vertical_timing_config(struct dw_mipi_dsi *dsi, + struct drm_display_mode *mode) { u32 vactive, vsa, vfp, vbp; - struct drm_display_mode *mode = dsi->mode; vactive = mode->vdisplay; vsa = mode->vsync_end - mode->vsync_start; @@ -852,11 +854,12 @@ static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder) static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder) { struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder); + struct drm_display_mode *mode = dsi->mode; int mux = drm_of_encoder_active_endpoint_id(dsi->dev->of_node, encoder); u32 val; int ret; - ret = dw_mipi_dsi_get_lane_bps(dsi); + ret = dw_mipi_dsi_get_lane_bps(dsi, mode); if (ret < 0) return; @@ -866,13 +869,13 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder) } dw_mipi_dsi_init(dsi); - dw_mipi_dsi_dpi_config(dsi, dsi->mode); + dw_mipi_dsi_dpi_config(dsi, mode); dw_mipi_dsi_packet_handler_config(dsi); dw_mipi_dsi_video_mode_config(dsi); - dw_mipi_dsi_video_packet_config(dsi, dsi->mode); + dw_mipi_dsi_video_packet_config(dsi, mode); dw_mipi_dsi_command_mode_config(dsi); - dw_mipi_dsi_line_timer_config(dsi); - dw_mipi_dsi_vertical_timing_config(dsi)
[PATCH v3 14/24] drm/rockchip: dw-mipi-dsi: ensure PHY is reset
Also don't power up the DSI host at this point since this is not necessary in order to configure the PHY and we do so later when selecting video or command mode. Signed-off-by: John Keeping Reviewed-by: Chris Zhong --- v3: - Add Chris' Reviewed-by Unchanged in v2 drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 5 - 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c index c2e0ba96e0a0..5b3068e9e8db 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c @@ -397,7 +397,10 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi) return testdin; } - dsi_write(dsi, DSI_PWR_UP, POWERUP); + /* Start by clearing PHY state */ + dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_UNTESTCLR); + dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_TESTCLR); + dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_UNTESTCLR); dw_mipi_dsi_phy_write(dsi, 0x10, BYPASS_VCO_RANGE | VCO_RANGE_CON_SEL(vco) | -- 2.11.0.197.gb556de5.dirty
[PATCH v3 16/24] drm/rockchip: dw-mipi-dsi: properly configure PHY timing
These values are specified as constant time periods but the PHY configuration is in terms of the current lane byte clock so using constant values guarantees that the timings will be outside the specification with some display configurations. Derive the necessary configuration from the byte clock in order to ensure that the PHY configuration is correct. Signed-off-by: John Keeping --- v3: - Wrap some long lines Unchanged in v2 drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 39 ++ 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c index cfe7e4ba305c..85edf6dd2bac 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c @@ -383,6 +383,26 @@ static void dw_mipi_dsi_phy_write(struct dw_mipi_dsi *dsi, u8 test_code, dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_TESTCLK | PHY_UNTESTCLR); } +/** + * ns2bc - Nanoseconds to byte clock cycles + */ +static inline unsigned int ns2bc(struct dw_mipi_dsi *dsi, int ns) +{ + unsigned long byte_clk_khz = dsi->lane_mbps * MSEC_PER_SEC / 8; + + return (ns * (byte_clk_khz / 1000) + 999) / 1000; +} + +/** + * ns2ui - Nanoseconds to UI time periods + */ +static inline unsigned int ns2ui(struct dw_mipi_dsi *dsi, int ns) +{ + unsigned long byte_clk_khz = dsi->lane_mbps * MSEC_PER_SEC; + + return (ns * (byte_clk_khz / 1000) + 999) / 1000; +} + static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi) { int ret, testdin, vco, val; @@ -434,10 +454,21 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi) SETRD_MAX | POWER_MANAGE | TER_RESISTORS_ON); - - dw_mipi_dsi_phy_write(dsi, 0x70, TLP_PROGRAM_EN | 0xf); - dw_mipi_dsi_phy_write(dsi, 0x71, THS_PRE_PROGRAM_EN | 0x55); - dw_mipi_dsi_phy_write(dsi, 0x72, THS_ZERO_PROGRAM_EN | 0xa); + dw_mipi_dsi_phy_write(dsi, 0x60, TLP_PROGRAM_EN | ns2bc(dsi, 500)); + dw_mipi_dsi_phy_write(dsi, 0x61, THS_PRE_PROGRAM_EN | ns2ui(dsi, 40)); + dw_mipi_dsi_phy_write(dsi, 0x62, THS_ZERO_PROGRAM_EN | ns2bc(dsi, 300)); + dw_mipi_dsi_phy_write(dsi, 0x63, THS_PRE_PROGRAM_EN | ns2ui(dsi, 100)); + dw_mipi_dsi_phy_write(dsi, 0x64, BIT(5) | ns2bc(dsi, 100)); + dw_mipi_dsi_phy_write(dsi, 0x65, BIT(5) | (ns2bc(dsi, 60) + 7)); + + dw_mipi_dsi_phy_write(dsi, 0x70, TLP_PROGRAM_EN | ns2bc(dsi, 500)); + dw_mipi_dsi_phy_write(dsi, 0x71, + THS_PRE_PROGRAM_EN | (ns2ui(dsi, 50) + 5)); + dw_mipi_dsi_phy_write(dsi, 0x72, + THS_ZERO_PROGRAM_EN | (ns2bc(dsi, 140) + 2)); + dw_mipi_dsi_phy_write(dsi, 0x73, + THS_PRE_PROGRAM_EN | (ns2ui(dsi, 60) + 8)); + dw_mipi_dsi_phy_write(dsi, 0x74, BIT(5) | ns2bc(dsi, 100)); dsi_write(dsi, DSI_PHY_RSTZ, PHY_ENFORCEPLL | PHY_ENABLECLK | PHY_UNRSTZ | PHY_UNSHUTDOWNZ); -- 2.11.0.197.gb556de5.dirty
Re: [PATCH 3/6] staging: bcm2835-v4l2: Add a build system for the module.
On Fri, 2017-01-27 at 13:55 -0800, Eric Anholt wrote: > This is derived from the downstream tree's build system, but with > just > a single Kconfig option. > > For now the driver only builds on 32-bit arm -- the aarch64 build > breaks due to the driver using arm-specific cache flushing functions. > > If you are referring to this: /* enqueue a bulk receive for a given message context */ static int bulk_receive(struct vchiq_mmal_instance *instance, struct mmal_msg *msg, struct mmal_msg_context *msg_context) ... // only need to flush L1 cache here, as VCHIQ takes care of the L2 // cache. __cpuc_flush_dcache_area(msg_context->u.bulk.buffer->buffer, rd_len); It should be possible to simply remove the __cpuc_flash_dcache_area call as VCHIQ should now be flushing all the needed caches. This is due to the DMA API clean that was necessary to make it multiplatform. The driver does have a few nasty issues with stuffing callback pointers into fixed 32 bit sized integers that would need to be fixed to make it work on 64 bit.
[PATCH v3 11/24] drm/rockchip: dw-mipi-dsi: prepare panel after phy init
Some panels need to be configured with commands sent over the MIPI link, which they will do in the prepare hook. Call this after the PHY has been initialized so that we are able to send commands to the panel. Signed-off-by: John Keeping Reviewed-by: Chris Zhong --- v3: - Add Chris' Reviewed-by Unchanged in v2 drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 6 -- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c index ddbc037e7ced..7ada6d8ed143 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c @@ -896,12 +896,14 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder) dw_mipi_dsi_dphy_timing_config(dsi); dw_mipi_dsi_dphy_interface_config(dsi); dw_mipi_dsi_clear_err(dsi); - if (drm_panel_prepare(dsi->panel)) - dev_err(dsi->dev, "failed to prepare panel\n"); dw_mipi_dsi_phy_init(dsi); dw_mipi_dsi_wait_for_two_frames(mode); + dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_CMD_MODE); + if (drm_panel_prepare(dsi->panel)) + dev_err(dsi->dev, "failed to prepare panel\n"); + dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_VID_MODE); drm_panel_enable(dsi->panel); -- 2.11.0.197.gb556de5.dirty
[PATCH v3 07/24] drm/rockchip: dw-mipi-dsi: include bad value in error message
As an aid to debugging. Signed-off-by: John Keeping Reviewed-by: Chris Zhong --- v3: - Add Chris' Reviewed-by Unchanged in v2 drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c index 2e6ad4591ebf..92dbc3e56603 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c @@ -644,7 +644,8 @@ static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host, ret = dw_mipi_dsi_dcs_long_write(dsi, msg); break; default: - dev_err(dsi->dev, "unsupported message type\n"); + dev_err(dsi->dev, "unsupported message type 0x%02x\n", + msg->type); ret = -EINVAL; } -- 2.11.0.197.gb556de5.dirty
[PATCH v3 05/24] drm/rockchip: dw-mipi-dsi: fix generic packet status check
We want to check that both the GEN_CMD_EMPTY and GEN_PLD_W_EMPTY bits are set so we can't just check "val & mask" because that will be true if either bit is set. Signed-off-by: John Keeping Reviewed-by: Chris Zhong --- v3: - Add Chris' Reviewed-by Unchanged in v2 drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c index 4cbbbcb619b7..4be1ff3a42bb 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c @@ -545,7 +545,7 @@ static int dw_mipi_dsi_host_detach(struct mipi_dsi_host *host, static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val) { int ret; - u32 val; + u32 val, mask; ret = readx_poll_timeout(readl, dsi->base + DSI_CMD_PKT_STATUS, val, !(val & GEN_CMD_FULL), 1000, @@ -557,8 +557,9 @@ static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val) dsi_write(dsi, DSI_GEN_HDR, hdr_val); + mask = GEN_CMD_EMPTY | GEN_PLD_W_EMPTY; ret = readx_poll_timeout(readl, dsi->base + DSI_CMD_PKT_STATUS, -val, val & (GEN_CMD_EMPTY | GEN_PLD_W_EMPTY), +val, (val & mask) == mask, 1000, CMD_PKT_STATUS_TIMEOUT_US); if (ret < 0) { dev_err(dsi->dev, "failed to write command FIFO\n"); -- 2.11.0.197.gb556de5.dirty
[PATCH v3 13/24] drm/rockchip: dw-mipi-dsi: fix escape clock rate
This clock rate is derived from the PHY PLL, so it should be calculated dynamically. Use the same calculation as the vendor kernel to derive the escape clock speed. Signed-off-by: John Keeping Reviewed-by: Chris Zhong --- v3: - Improve the commit message a bit - Add Chris' Reviewed-by Unchanged in v2 drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c index 290282e86d16..c2e0ba96e0a0 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c @@ -710,11 +710,13 @@ static void dw_mipi_dsi_disable(struct dw_mipi_dsi *dsi) static void dw_mipi_dsi_init(struct dw_mipi_dsi *dsi) { + u32 esc_clk_division = (dsi->lane_mbps >> 3) / 20 + 1; + dsi_write(dsi, DSI_PWR_UP, RESET); dsi_write(dsi, DSI_PHY_RSTZ, PHY_DISFORCEPLL | PHY_DISABLECLK | PHY_RSTZ | PHY_SHUTDOWNZ); dsi_write(dsi, DSI_CLKMGR_CFG, TO_CLK_DIVIDSION(10) | - TX_ESC_CLK_DIVIDSION(7)); + TX_ESC_CLK_DIVIDSION(esc_clk_division)); } static void dw_mipi_dsi_dpi_config(struct dw_mipi_dsi *dsi, -- 2.11.0.197.gb556de5.dirty
[PATCH v3 04/24] drm/rockchip: dw-mipi-dsi: fix command header writes
In a couple of places here we use "val" for the value that is about to be written to a register but then reuse the same variable for the value of a status register before we get around to writing it. Rename the value to be written to so that we write the value we intend to and not what we have just read from the status register. Signed-off-by: John Keeping Tested-by: Chris Zhong Reviewed-by: Chris Zhong --- Unchanged in v3 Unchanged in v2 drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 10 ++ 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c index bd92e58b64f3..4cbbbcb619b7 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c @@ -542,9 +542,10 @@ static int dw_mipi_dsi_host_detach(struct mipi_dsi_host *host, return 0; } -static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 val) +static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val) { int ret; + u32 val; ret = readx_poll_timeout(readl, dsi->base + DSI_CMD_PKT_STATUS, val, !(val & GEN_CMD_FULL), 1000, @@ -554,7 +555,7 @@ static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 val) return ret; } - dsi_write(dsi, DSI_GEN_HDR, val); + dsi_write(dsi, DSI_GEN_HDR, hdr_val); ret = readx_poll_timeout(readl, dsi->base + DSI_CMD_PKT_STATUS, val, val & (GEN_CMD_EMPTY | GEN_PLD_W_EMPTY), @@ -587,8 +588,9 @@ static int dw_mipi_dsi_dcs_long_write(struct dw_mipi_dsi *dsi, { const u32 *tx_buf = msg->tx_buf; int len = msg->tx_len, pld_data_bytes = sizeof(*tx_buf), ret; - u32 val = GEN_HDATA(msg->tx_len) | GEN_HTYPE(msg->type); + u32 hdr_val = GEN_HDATA(msg->tx_len) | GEN_HTYPE(msg->type); u32 remainder = 0; + u32 val; if (msg->tx_len < 3) { dev_err(dsi->dev, "wrong tx buf length %zu for long write\n", @@ -617,7 +619,7 @@ static int dw_mipi_dsi_dcs_long_write(struct dw_mipi_dsi *dsi, } } - return dw_mipi_dsi_gen_pkt_hdr_write(dsi, val); + return dw_mipi_dsi_gen_pkt_hdr_write(dsi, hdr_val); } static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host, -- 2.11.0.197.gb556de5.dirty
[PATCH v3 12/24] drm/rockchip: dw-mipi-dsi: allow commands in panel_disable
Panel drivers may want to sent commands during the disable function, for example MIPI_DCS_SET_DISPLAY_OFF before the video signal ends. In order to send commands we need to write to registers, so pclk must be enabled. While changing this, remove the unnecessary code after the panel unprepare call which seems to be a workaround for a specific panel and thus belongs in the panel driver. Signed-off-by: John Keeping Reviewed-by: Chris Zhong --- v3: - Add Chris' Reviewed-by Unchanged in v2 drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 12 ++-- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c index 7ada6d8ed143..290282e86d16 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c @@ -846,24 +846,16 @@ static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder) { struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder); - drm_panel_disable(dsi->panel); - if (clk_prepare_enable(dsi->pclk)) { dev_err(dsi->dev, "%s: Failed to enable pclk\n", __func__); return; } + drm_panel_disable(dsi->panel); + dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_CMD_MODE); drm_panel_unprepare(dsi->panel); - dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_VID_MODE); - /* -* This is necessary to make sure the peripheral will be driven -* normally when the display is enabled again later. -*/ - msleep(120); - - dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_CMD_MODE); dw_mipi_dsi_disable(dsi); clk_disable_unprepare(dsi->pclk); } -- 2.11.0.197.gb556de5.dirty
[PATCH v3 15/24] drm/rockchip: dw-mipi-dsi: configure PHY before enabling
The bias, bandgap and PLL should all be configured before we enable them. Signed-off-by: John Keeping --- v3: - Squash together two patches that both affect initialization order of the PHY Unchanged in v2 drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 11 ++- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c index 5b3068e9e8db..cfe7e4ba305c 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c @@ -413,12 +413,17 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi) dw_mipi_dsi_phy_write(dsi, 0x44, HSFREQRANGE_SEL(testdin)); - dw_mipi_dsi_phy_write(dsi, 0x19, PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN); dw_mipi_dsi_phy_write(dsi, 0x17, INPUT_DIVIDER(dsi->input_div)); dw_mipi_dsi_phy_write(dsi, 0x18, LOOP_DIV_LOW_SEL(dsi->feedback_div) | LOW_PROGRAM_EN); dw_mipi_dsi_phy_write(dsi, 0x18, LOOP_DIV_HIGH_SEL(dsi->feedback_div) | HIGH_PROGRAM_EN); + dw_mipi_dsi_phy_write(dsi, 0x19, PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN); + + dw_mipi_dsi_phy_write(dsi, 0x22, LOW_PROGRAM_EN | +BIASEXTR_SEL(BIASEXTR_127_7)); + dw_mipi_dsi_phy_write(dsi, 0x22, HIGH_PROGRAM_EN | +BANDGAP_SEL(BANDGAP_96_10)); dw_mipi_dsi_phy_write(dsi, 0x20, POWER_CONTROL | INTERNAL_REG_CURRENT | BIAS_BLOCK_ON | BANDGAP_ON); @@ -429,10 +434,6 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi) SETRD_MAX | POWER_MANAGE | TER_RESISTORS_ON); - dw_mipi_dsi_phy_write(dsi, 0x22, LOW_PROGRAM_EN | -BIASEXTR_SEL(BIASEXTR_127_7)); - dw_mipi_dsi_phy_write(dsi, 0x22, HIGH_PROGRAM_EN | -BANDGAP_SEL(BANDGAP_96_10)); dw_mipi_dsi_phy_write(dsi, 0x70, TLP_PROGRAM_EN | 0xf); dw_mipi_dsi_phy_write(dsi, 0x71, THS_PRE_PROGRAM_EN | 0x55); -- 2.11.0.197.gb556de5.dirty
[PATCH v3 18/24] drm/rockchip: dw-mipi-dsi: use specific poll helper
As the documentation for readx_poll_timeout says, we want to use the specialized macro for readl rather than using the generic version directly. Signed-off-by: John Keeping Reviewed-by: Chris Zhong --- v3: - Add Chris' Reviewed-by Unchanged in v2 drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 10 +- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c index dcb66a21e1f1..be395c3c5c06 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c @@ -474,14 +474,14 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi) PHY_UNRSTZ | PHY_UNSHUTDOWNZ); - ret = readx_poll_timeout(readl, dsi->base + DSI_PHY_STATUS, + ret = readl_poll_timeout(dsi->base + DSI_PHY_STATUS, val, val & LOCK, 1000, PHY_STATUS_TIMEOUT_US); if (ret < 0) { dev_err(dsi->dev, "failed to wait for phy lock state\n"); return ret; } - ret = readx_poll_timeout(readl, dsi->base + DSI_PHY_STATUS, + ret = readl_poll_timeout(dsi->base + DSI_PHY_STATUS, val, val & STOP_STATE_CLK_LANE, 1000, PHY_STATUS_TIMEOUT_US); if (ret < 0) { @@ -597,7 +597,7 @@ static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val) int ret; u32 val, mask; - ret = readx_poll_timeout(readl, dsi->base + DSI_CMD_PKT_STATUS, + ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS, val, !(val & GEN_CMD_FULL), 1000, CMD_PKT_STATUS_TIMEOUT_US); if (ret < 0) { @@ -608,7 +608,7 @@ static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val) dsi_write(dsi, DSI_GEN_HDR, hdr_val); mask = GEN_CMD_EMPTY | GEN_PLD_W_EMPTY; - ret = readx_poll_timeout(readl, dsi->base + DSI_CMD_PKT_STATUS, + ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS, val, (val & mask) == mask, 1000, CMD_PKT_STATUS_TIMEOUT_US); if (ret < 0) { @@ -667,7 +667,7 @@ static int dw_mipi_dsi_dcs_long_write(struct dw_mipi_dsi *dsi, len -= pld_data_bytes; } - ret = readx_poll_timeout(readl, dsi->base + DSI_CMD_PKT_STATUS, + ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS, val, !(val & GEN_PLD_W_FULL), 1000, CMD_PKT_STATUS_TIMEOUT_US); if (ret < 0) { -- 2.11.0.197.gb556de5.dirty
[PATCH v3 24/24] drm/rockchip: dw-mipi-dsi: support read commands
I haven't found any method for getting the length of a response, so this just uses the requested rx_len Signed-off-by: John Keeping --- v3: - Fix checkpatch warnings Unchanged in v2 drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 56 ++ 1 file changed, 56 insertions(+) diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c index cf3ca6b0cbdb..cc58ada75425 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c @@ -678,6 +678,56 @@ static int dw_mipi_dsi_dcs_long_write(struct dw_mipi_dsi *dsi, return dw_mipi_dsi_gen_pkt_hdr_write(dsi, hdr_val); } +static int dw_mipi_dsi_dcs_read(struct dw_mipi_dsi *dsi, + const struct mipi_dsi_msg *msg) +{ + const u8 *tx_buf = msg->tx_buf; + u8 *rx_buf = msg->rx_buf; + size_t i; + int ret, val; + + dsi_write(dsi, DSI_PCKHDL_CFG, EN_CRC_RX | EN_ECC_RX | EN_BTA); + dsi_write(dsi, DSI_GEN_HDR, + GEN_HDATA(tx_buf[0]) | GEN_HTYPE(msg->type)); + + ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS, +val, !(val & GEN_RD_CMD_BUSY), 1000, +CMD_PKT_STATUS_TIMEOUT_US); + if (ret < 0) { + dev_err(dsi->dev, "failed to read command response\n"); + return ret; + } + + for (i = 0; i < msg->rx_len;) { + u32 pld = dsi_read(dsi, DSI_GEN_PLD_DATA); + + while (i < msg->rx_len) { + rx_buf[i] = pld & 0xff; + pld >>= 8; + i++; + } + } + + return msg->rx_len; +} + +static int dw_mipi_dsi_set_max_return_packet_size(struct dw_mipi_dsi *dsi, + size_t len) +{ + u8 val[] = { len & 0xff, (len >> 8) & 0xff }; + struct mipi_dsi_msg msg = { + .channel = dsi->channel, + .type = MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, + .tx_buf = val, + .tx_len = 2, + }; + + if (len > 0x) + return -EINVAL; + + return dw_mipi_dsi_dcs_short_write(dsi, &msg); +} + static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host, const struct mipi_dsi_msg *msg) { @@ -695,6 +745,12 @@ static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host, case MIPI_DSI_DCS_LONG_WRITE: ret = dw_mipi_dsi_dcs_long_write(dsi, msg); break; + case MIPI_DSI_DCS_READ: + ret = dw_mipi_dsi_set_max_return_packet_size(dsi, msg->rx_len); + if (ret < 0) + return ret; + ret = dw_mipi_dsi_dcs_read(dsi, msg); + break; default: dev_err(dsi->dev, "unsupported message type 0x%02x\n", msg->type); -- 2.11.0.197.gb556de5.dirty
[PATCH v3 20/24] drm/rockchip: vop: test for P{H,V}SYNC
When connected to the MIPI DSI output, we need to use N{H,V}SYNC for the internal connection but these flags are meaningless for DSI panels. Switch the test so that we do not set the P{H,V}SYNC bits unless the mode requires it. Signed-off-by: John Keeping Reviewed-by: Mark Yao --- v3: - Add Mark's Reviewed-by Unchanged in v2 drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index c7eba305c488..67aefc6d4e9a 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -933,8 +933,8 @@ static void vop_crtc_enable(struct drm_crtc *crtc) } pin_pol = 0x8; - pin_pol |= (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) ? 0 : 1; - pin_pol |= (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) ? 0 : (1 << 1); + pin_pol |= (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) ? 1 : 0; + pin_pol |= (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) ? (1 << 1) : 0; VOP_CTRL_SET(vop, pin_pol, pin_pol); switch (s->output_type) { -- 2.11.0.197.gb556de5.dirty
pull-request: wireless-drivers 2017-01-29
Hi Dave, small but important fixes for 4.10. Hopefully is the last pull request for 4.10. Please let me know if there are any problems. Kalle The following changes since commit 60f59ce0278557f7896d5158ae6d12a4855a72cc: rtlwifi: rtl_usb: Fix missing entry in USB driver's private data (2016-12-30 15:38:13 +0200) are available in the git repository at: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers.git tags/wireless-drivers-for-davem-2017-01-29 for you to fetch changes up to 2b1d530cb3157f828fcaadd259613f59db3c6d1c: MAINTAINERS: ath9k-devel is closed (2017-01-28 09:15:50 +0200) wireless-drivers fixes for 4.10 Most important here are fixes to two iwlwifi crashes, but there's also a firmware naming fix for iwlwifi and a revert of an older bcma patch. Jens Axboe (1): iwlwifi: fix kernel crash when unregistering thermal zone Johannes Berg (1): iwlwifi: mvm: avoid crash on restart w/o reserved queues Jürg Billeter (1): iwlwifi: fix double hyphen in MODULE_FIRMWARE for 8000 Kalle Valo (2): Merge tag 'iwlwifi-for-kalle-2017-01-23' of git://git.kernel.org/.../iwlwifi/iwlwifi-fixes MAINTAINERS: ath9k-devel is closed Rafał Miłecki (1): Revert "bcma: init serial console directly from ChipCommon code" MAINTAINERS | 1 - drivers/bcma/bcma_private.h | 3 +++ drivers/bcma/driver_chipcommon.c | 11 +++ drivers/bcma/driver_mips.c| 3 +++ drivers/net/wireless/intel/iwlwifi/iwl-8000.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 7 --- drivers/net/wireless/intel/iwlwifi/mvm/tt.c | 12 7 files changed, 22 insertions(+), 17 deletions(-)
Re: [PATCH 1/3] intel_sgx: do not use BUG() in sgx_free_page()
On Fri, Jan 27, 2017 at 05:45:03PM +0200, Andy Shevchenko wrote: > On Thu, Jan 26, 2017 at 11:20 PM, Jarkko Sakkinen > wrote: > > EREMOVE fails on non-EPC page or when a SECS page with children is to be > > removed. These do not happen if the driver is working correctly. Log the > > error but do not crash the driver. > > > > Signed-off-by: Jarkko Sakkinen > > --- > > drivers/platform/x86/intel_sgx_page_cache.c | 6 ++ > > 1 file changed, 2 insertions(+), 4 deletions(-) > > > > diff --git a/drivers/platform/x86/intel_sgx_page_cache.c > > b/drivers/platform/x86/intel_sgx_page_cache.c > > index d073057..7f73ac7 100644 > > --- a/drivers/platform/x86/intel_sgx_page_cache.c > > +++ b/drivers/platform/x86/intel_sgx_page_cache.c > > @@ -551,10 +551,8 @@ void sgx_free_page(struct sgx_epc_page *entry, > > ret = __eremove(epc); > > sgx_put_epc_page(epc); > > > > - if (ret) { > > - pr_err("EREMOVE returned %d\n", ret); > > - BUG(); > > - } > > + if (ret) > > + sgx_err(encl, "EREMOVE returned %d\n", ret); > > Do you have something like critical level? For me seems reasonable to > increase the level of message if BUG() was somehow related to actual > situation. Hmm... I think that would make sense. This could only happen when the driver implementation is working incorrectly. /Jarkko
Re: [PATCH] tpm: add buffer access validation in tpm2_get_pcr_allocation()
On Fri, Jan 27, 2017 at 10:25:49AM -0500, Nayna Jain wrote: > This patch add validation in tpm2_get_pcr_allocation to avoid > access beyond response buffer length. > > Suggested-by: Stefan Berger > Signed-off-by: Nayna Jain This validation looks broken to me. > --- > drivers/char/tpm/tpm2-cmd.c | 28 +++- > 1 file changed, 23 insertions(+), 5 deletions(-) > > diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c > index 4aad84c..02c1ea7 100644 > --- a/drivers/char/tpm/tpm2-cmd.c > +++ b/drivers/char/tpm/tpm2-cmd.c > @@ -1008,9 +1008,13 @@ static ssize_t tpm2_get_pcr_allocation(struct tpm_chip > *chip) > struct tpm2_pcr_selection pcr_selection; > struct tpm_buf buf; > void *marker; > - unsigned int count = 0; > + void *end; > + void *pcr_select_offset; > + unsigned int count; > + u32 sizeof_pcr_selection; > + u32 resp_len; Very cosmetic but we almos almost universally use the acronym 'rsp' in the TPM driver. > int rc; > - int i; > + int i = 0; Why do you need to initialize it? > > rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY); > if (rc) > @@ -1034,15 +1038,29 @@ static ssize_t tpm2_get_pcr_allocation(struct > tpm_chip *chip) > } > > marker = &buf.data[TPM_HEADER_SIZE + 9]; > + > + resp_len = be32_to_cpup((__be32 *)&buf.data[2]); > + end = &buf.data[resp_len]; What if the response contains larger length than the buffer size? > + > for (i = 0; i < count; i++) { > + pcr_select_offset = marker + > + offsetof(struct tpm2_pcr_selection, size_of_select); > + if (pcr_select_offset >= end) { > + rc = -EFAULT; > + break; > + } > + > memcpy(&pcr_selection, marker, sizeof(pcr_selection)); > chip->active_banks[i] = be16_to_cpu(pcr_selection.hash_alg); > - marker = marker + sizeof(struct tpm2_pcr_selection); > + sizeof_pcr_selection = sizeof(pcr_selection.hash_alg) + > + sizeof(pcr_selection.size_of_select) + > + sizeof(u8) * pcr_selection.size_of_select; Remove "sizeof(u8) * ". > + marker = marker + sizeof_pcr_selection; > } > > out: > - if (count < ARRAY_SIZE(chip->active_banks)) > - chip->active_banks[count] = TPM2_ALG_ERROR; > + if (i < ARRAY_SIZE(chip->active_banks)) > + chip->active_banks[i] = TPM2_ALG_ERROR; > > tpm_buf_destroy(&buf); > > -- > 2.5.0 > I'm sorry but this commit is changing too much. You need to redo the whole commit and resend the patch set with these fixes. You can keep Reviewed-by and Tested-by in 1/2 but have to remove them from 2/2. /Jarkko
Re: [PATCH] tpm: fix RC value check in tpm2_seal_trusted
On Fri, Jan 27, 2017 at 09:24:16AM -0700, Jason Gunthorpe wrote: > On Fri, Jan 27, 2017 at 08:43:27AM +0200, Jarkko Sakkinen wrote: > > On Thu, Jan 26, 2017 at 11:32:52AM -0700, Jason Gunthorpe wrote: > > > On Thu, Jan 26, 2017 at 01:27:14PM +0200, Jarkko Sakkinen wrote: > > > > > > > "The error code handling is bogus as any error code that has the bits > > > > set that TPM_RC_HASH could pass. Implemented tpm2_rc_value() helper to > > > > parse the error value from FMT0 and FMT1 error codes to use to check the > > > > error so that these types of mistakes is prevented in the future." > > > > > > Great thanks > > > > > > Jason > > > > Can I put your Reviewed-by? I would like to get this into 4.11. > > I'm not up to speed on the TPM2 parsing, but it looks OK based on your > description. > > Reviewed-by: Jason Gunthorpe > > Jason Thanks I applied this patch to master. /Jarkko
squashfs-tools: Add -offset option to skip n bytes at the start of the file
On Sun, 2017-01-29 at 03:33 -0800, probonopd wrote: > Yes, I am not happy about that. > You could either push your change to the squashfs folks > Sent a PR half a year ago but no reaction: plougher/squashfs-tools#13 - is > something wrong with it? That repo seems inactive. So does the git repo at kernel.org. but I would rely on that one. Let's try fresh now. Given there's been not much development in the upstream repo, I've just taken your patch, as is, for submission. > Or you could just carry the delta and ask the user to fetch the > squashfs-tools > source themselves > Do you mean "carry the delta" as in "provide a diff"? Doing now. Dear Squashfs Team, Can you please review/include the attached patch into squashfs-tools ? The mentioned changes are needed by AppImageKit. What is AppImage The AppImage format is a format for packaging applications in a way that allows them to run on a variety of different target systems (base operating systems, distributions) without further modification. https://en.wikipedia.org/wiki/AppImage AppImageKit is a concrete implementation of the AppImage format and provides tools such as appimagetool and appimaged for conveniently handling AppImages. https://github.com/probonopd/AppImageKit -- Ritesh Raj Sarraf RESEARCHUT - http://www.researchut.com "Necessity is the mother of invention."From f72f32b0fe7929e71edd9e6589fa1fcec1d86adc Mon Sep 17 00:00:00 2001 From: probonopd Date: Thu, 15 Sep 2016 18:24:10 +0200 Subject: [PATCH 1/2] Add -offset option to skip n bytes at the start of the input file --- squashfs-tools/unsquashfs.c | 13 - 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/squashfs-tools/unsquashfs.c b/squashfs-tools/unsquashfs.c index 1323dd6..b6ba452 100644 --- a/squashfs-tools/unsquashfs.c +++ b/squashfs-tools/unsquashfs.c @@ -42,6 +42,7 @@ struct cache *fragment_cache, *data_cache; struct queue *to_reader, *to_inflate, *to_writer, *from_writer; pthread_t *thread, *inflator_thread; pthread_mutex_t fragment_mutex; +static off_t squashfs_start_offset = 0; /* user options that control parallelisation */ int processors = -1; @@ -631,7 +632,7 @@ int read_fs_bytes(int fd, long long byte, int bytes, void *buff) TRACE("read_bytes: reading from position 0x%llx, bytes %d\n", byte, bytes); - if(lseek(fd, off, SEEK_SET) == -1) { + if(lseek(fd, off + squashfs_start_offset, SEEK_SET) == -1) { ERROR("Lseek failed because %s\n", strerror(errno)); return FALSE; } @@ -2544,6 +2545,14 @@ int main(int argc, char *argv[]) exit(1); } dest = argv[i]; + } else if (strcmp(argv[i], "-offset") == 0 || +strcmp(argv[i], "-o") == 0) { + if(++i == argc) { +fprintf(stderr, "%s: -offset missing argument\n", + argv[0]); +exit(1); + } + squashfs_start_offset = (off_t)atol(argv[i]); } else if(strcmp(argv[i], "-processors") == 0 || strcmp(argv[i], "-p") == 0) { if((++i == argc) || @@ -2636,6 +2645,8 @@ int main(int argc, char *argv[]) "copyright information\n"); ERROR("\t-d[est] \tunsquash to , " "default \"squashfs-root\"\n"); + ERROR("\t-o[ffset] \tskip at start of input file, " +"default \"0\"\n"); ERROR("\t-n[o-progress]\t\tdon't display the progress " "bar\n"); ERROR("\t-no[-xattrs]\t\tdon't extract xattrs in file system" From 5a498ad24dcfeac9f3d747e894f22901f3ac10ef Mon Sep 17 00:00:00 2001 From: probonopd Date: Thu, 15 Sep 2016 21:09:52 +0200 Subject: [PATCH 2/2] Add -offset function to skip n bytes at the beginning of the squashfs file --- squashfs-tools/mksquashfs.c | 25 +++-- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/squashfs-tools/mksquashfs.c b/squashfs-tools/mksquashfs.c index d221c35..92b6a31 100644 --- a/squashfs-tools/mksquashfs.c +++ b/squashfs-tools/mksquashfs.c @@ -98,6 +98,7 @@ int old_exclude = TRUE; int use_regex = FALSE; int nopad = FALSE; int exit_on_error = FALSE; +static off_t squashfs_start_offset = 0; long long global_uid = -1, global_gid = -1; @@ -516,9 +517,9 @@ int read_fs_bytes(int fd, long long byte, int bytes, void *buff) pthread_cleanup_push((void *) pthread_mutex_unlock, &pos_mutex); pthread_mutex_lock(&pos_mutex); - if(lseek(fd, off, SEEK_SET) == -1) { + if(lseek(fd, off+squashfs_start_offset, SEEK_SET) == -1) { ERROR("read_fs_bytes: Lseek on destination failed because %s, " - "offset=0x%llx\n", strerror(errno), off); + "offset=0x%llx\n", strerror(errno), off+squashfs_start_offset); res = 0; } else if(read_bytes(fd, buff, bytes) < bytes) { ERROR("Read on destination failed\n"); @@ -557,10 +558,10 @@ void write_destination(int fd, long long byte, int bytes, void *buff) pthread_cleanup_push((void *) pthread_mutex_unlock, &pos_mutex); pthread_mutex_lock(&pos_mutex); - if(lseek(fd, off, SEEK_SET) == -1) { + if(lseek(fd, off+squashfs_start_offset, SEEK_SET) == -1) { ERROR("write_destination: Lseek on destination " "failed beca
[PATCH v3 19/24] drm/rockchip: dw-mipi-dsi: use positive check for N{H,V}SYNC
This matches other drivers. Signed-off-by: John Keeping --- Unchanged in v3 Unchanged in v2 drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c index be395c3c5c06..f5b15377ef85 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c @@ -774,9 +774,9 @@ static void dw_mipi_dsi_dpi_config(struct dw_mipi_dsi *dsi, break; } - if (!(mode->flags & DRM_MODE_FLAG_PVSYNC)) + if (mode->flags & DRM_MODE_FLAG_NVSYNC) val |= VSYNC_ACTIVE_LOW; - if (!(mode->flags & DRM_MODE_FLAG_PHSYNC)) + if (mode->flags & DRM_MODE_FLAG_NHSYNC) val |= HSYNC_ACTIVE_LOW; dsi_write(dsi, DSI_DPI_VCID, DPI_VID(dsi->channel)); -- 2.11.0.197.gb556de5.dirty
[PATCH v3 17/24] drm/rockchip: dw-mipi-dsi: improve PLL configuration
The multiplication ratio for the PLL is required to be even due to the use of a "by 2 pre-scaler". Currently we are likely to end up with an odd multiplier even though there is an equivalent set of parameters with an even multiplier. For example, using the 324MHz bit rate with a reference clock of 24MHz we end up with M = 27, N = 2 whereas the example in the PHY databook gives M = 54, N = 4 for this bit rate and reference clock. By walking down through the available multiplier instead of up we are more likely to hit an even multiplier. With the above example we do now get M = 54, N = 4 as given by the databook. While doing this, change the loop limits to encode the actual limits on the divisor, which are: 40MHz >= (pllref / N) >= 5MHz Signed-off-by: John Keeping --- Unchanged in v3 Unchanged in v2 drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c index 85edf6dd2bac..dcb66a21e1f1 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c @@ -522,7 +522,7 @@ static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi, pllref = DIV_ROUND_UP(clk_get_rate(dsi->pllref_clk), USEC_PER_SEC); tmp = pllref; - for (i = 1; i < 6; i++) { + for (i = pllref / 5; i > (pllref / 40); i--) { pre = pllref / i; if ((tmp > (target_mbps % pre)) && (target_mbps / pre < 512)) { tmp = target_mbps % pre; -- 2.11.0.197.gb556de5.dirty
Re: [PATCH v6 0/2] enhance TPM 2.0 extend function to support multiple PCR banks
On Fri, Jan 27, 2017 at 10:53:11PM +0530, Nayna wrote: > > > On 01/26/2017 02:15 AM, Jarkko Sakkinen wrote: > > On Fri, Jan 20, 2017 at 12:05:11PM -0500, Nayna Jain wrote: > > > IMA extends its hash measurements in the TPM PCRs, based on policy. > > > The existing in-kernel TPM extend function extends only the SHA1 > > > PCR bank. TPM 2.0 defines multiple PCR banks, to support different > > > hash algorithms. The TCG TPM 2.0 Specification[1] recommends > > > extending all active PCR banks to prevent malicious users from > > > setting unused PCR banks with fake measurements and quoting them. > > > This patch set adds support for extending all active PCR banks, > > > as recommended. > > > > > > The first patch implements the TPM 2.0 capability to retrieve > > > the list of active PCR banks. > > > > > > The second patch modifies the tpm_pcr_extend() and tpm2_pcr_extend() > > > interface to support extending multiple PCR banks. The existing > > > tpm_pcr_extend() interface expects only a SHA1 digest. Hence, to > > > extend all active PCR banks with differing digest sizes for TPM 2.0, > > > the SHA1 digest is padded with 0's as needed. > > > > > > [1] TPM 2.0 Specification referred here is "TCG PC Client Specific > > > Platform Firmware Profile for TPM 2.0" > > > > I pushed these patches. I had to resolve merge conflicts caused > > by the min_rsp_body_length parameter in tpm_transmit_cmd. Can you > > verify that I didn't break anything? > > > > Yes, it looks fine, also tested with it. > > Just to understand.. how did you decide min_rsp_body_length to be 9. > If I understood correctly, I think it is the size after header, till last > fixed parameter i.e. till count. > Is the assumption is that count can be zero, such that there is no active > bank for PCR and so no struct tpm2_pcr_selection ? > > Thanks & Regards, >- Nayna Hmm.. I got it from "marker = &buf.data[TPM_HEADER_SIZE + 9];" i.e. must have at last 9 bytes after the header. /Jarkko
[PATCH v3 03/24] drm/rockchip: dw-mipi-dsi: remove mode_set hook
This is not needed since we can access the mode via the CRTC from the enable hook. Also remove the "mode" field that is no longer used. Signed-off-by: John Keeping Reviewed-by: Chris Zhong --- v3: - Add Chris' Reviewed-by New in v2 drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 13 + 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c index cdbd25087e83..bd92e58b64f3 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c @@ -286,7 +286,6 @@ struct dw_mipi_dsi { u32 format; u16 input_div; u16 feedback_div; - struct drm_display_mode *mode; const struct dw_mipi_dsi_plat_data *pdata; }; @@ -816,15 +815,6 @@ static void dw_mipi_dsi_clear_err(struct dw_mipi_dsi *dsi) dsi_write(dsi, DSI_INT_MSK1, 0); } -static void dw_mipi_dsi_encoder_mode_set(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder); - - dsi->mode = adjusted_mode; -} - static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder) { struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder); @@ -854,7 +844,7 @@ static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder) static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder) { struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder); - struct drm_display_mode *mode = dsi->mode; + struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode; int mux = drm_of_encoder_active_endpoint_id(dsi->dev->of_node, encoder); u32 val; int ret; @@ -930,7 +920,6 @@ dw_mipi_dsi_encoder_atomic_check(struct drm_encoder *encoder, static struct drm_encoder_helper_funcs dw_mipi_dsi_encoder_helper_funcs = { .enable = dw_mipi_dsi_encoder_enable, - .mode_set = dw_mipi_dsi_encoder_mode_set, .disable = dw_mipi_dsi_encoder_disable, .atomic_check = dw_mipi_dsi_encoder_atomic_check, }; -- 2.11.0.197.gb556de5.dirty
[PATCH v3 23/24] drm/rockchip: dw-mipi-dsi: add reset control
In order to fully reset the state of the MIPI controller we must assert this reset. This is slightly more complicated than it could be in order to maintain compatibility with device trees that do not specify the reset property. Signed-off-by: John Keeping Reviewed-by: Chris Zhong --- v3: - Add Chris' Reviewed-by Unchanged in v2 drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 30 ++ 1 file changed, 30 insertions(+) diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c index 58cb8ace2fe8..cf3ca6b0cbdb 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -1124,6 +1125,7 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master, of_match_device(dw_mipi_dsi_dt_ids, dev); const struct dw_mipi_dsi_plat_data *pdata = of_id->data; struct platform_device *pdev = to_platform_device(dev); + struct reset_control *apb_rst; struct drm_device *drm = data; struct dw_mipi_dsi *dsi; struct resource *res; @@ -1162,6 +1164,34 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master, return ret; } + /* +* Note that the reset was not defined in the initial device tree, so +* we have to be prepared for it not being found. +*/ + apb_rst = devm_reset_control_get(dev, "apb"); + if (IS_ERR(apb_rst)) { + if (PTR_ERR(apb_rst) == -ENODEV) { + apb_rst = NULL; + } else { + dev_err(dev, "Unable to get reset control: %d\n", ret); + return PTR_ERR(apb_rst); + } + } + + if (apb_rst) { + ret = clk_prepare_enable(dsi->pclk); + if (ret) { + dev_err(dev, "%s: Failed to enable pclk\n", __func__); + return ret; + } + + reset_control_assert(apb_rst); + usleep_range(10, 20); + reset_control_deassert(apb_rst); + + clk_disable_unprepare(dsi->pclk); + } + ret = clk_prepare_enable(dsi->pllref_clk); if (ret) { dev_err(dev, "%s: Failed to enable pllref_clk\n", __func__); -- 2.11.0.197.gb556de5.dirty
[PATCH v3 22/24] drm/rockchip: dw-mipi-dsi: support non-burst modes
Signed-off-by: John Keeping Reviewed-by: Chris Zhong --- v3: - Add Chris' Reviewed-by Unchanged in v2 drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 16 +--- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c index 5bad92e2370e..58cb8ace2fe8 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c @@ -82,6 +82,7 @@ #define FRAME_BTA_ACK BIT(14) #define ENABLE_LOW_POWER (0x3f << 8) #define ENABLE_LOW_POWER_MASK (0x3f << 8) +#define VID_MODE_TYPE_NON_BURST_SYNC_EVENTS0x1 #define VID_MODE_TYPE_BURST_SYNC_PULSES0x2 #define VID_MODE_TYPE_MASK 0x3 @@ -286,6 +287,7 @@ struct dw_mipi_dsi { u32 format; u16 input_div; u16 feedback_div; + unsigned long mode_flags; const struct dw_mipi_dsi_plat_data *pdata; }; @@ -551,15 +553,10 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host, return -EINVAL; } - if (!(device->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) || - !(device->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)) { - dev_err(dsi->dev, "device mode is unsupported\n"); - return -EINVAL; - } - dsi->lanes = device->lanes; dsi->channel = device->channel; dsi->format = device->format; + dsi->mode_flags = device->mode_flags; dsi->panel = of_drm_find_panel(device->dev.of_node); if (dsi->panel) return drm_panel_attach(dsi->panel, &dsi->connector); @@ -716,7 +713,12 @@ static void dw_mipi_dsi_video_mode_config(struct dw_mipi_dsi *dsi) { u32 val; - val = VID_MODE_TYPE_BURST_SYNC_PULSES | ENABLE_LOW_POWER; + val = ENABLE_LOW_POWER; + + if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) + val |= VID_MODE_TYPE_BURST_SYNC_PULSES; + else if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)) + val |= VID_MODE_TYPE_NON_BURST_SYNC_EVENTS; dsi_write(dsi, DSI_VID_MODE_CFG, val); } -- 2.11.0.197.gb556de5.dirty
Re: [PATCH] power: supply: bq2415x: check for NULL acpi_id to avoid null pointer dereference
Hi, On Fri, Jan 20, 2017 at 01:25:06PM +, Colin King wrote: > acpi_match_device can potentially return NULL, so it is prudent to > check if acpi_id is null before it is dereferenced. Add a check > and an error message to indicate the failure. > > Signed-off-by: Colin Ian King Thanks, queued into power-supply's for-next branch. -- Sebastian signature.asc Description: PGP signature
Re: [PATCH 08/22] power: supply: add AC power supply driver for AXP20X and AXP22X PMICs
Hi, On Sat, Jan 28, 2017 at 02:30:22PM +, Jonathan Cameron wrote: > On 27/01/17 08:20, Maxime Ripard wrote: > > On Thu, Jan 26, 2017 at 02:32:21PM +0100, Quentin Schulz wrote: > >> I've come with this solution: > >> > >> > >> diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c > >> index 012c064..117eacb 100644 > >> --- a/drivers/mfd/axp20x.c > >> +++ b/drivers/mfd/axp20x.c > >> @@ -882,7 +882,7 @@ EXPORT_SYMBOL(axp20x_match_device); > >> > >> int axp20x_device_probe(struct axp20x_dev *axp20x) > >> { > >> - int ret; > >> + int ret, irq_base; > >> > >>ret = regmap_add_irq_chip(axp20x->regmap, axp20x->irq, > >> IRQF_ONESHOT | IRQF_SHARED, -1, > >> @@ -893,8 +893,9 @@ int axp20x_device_probe(struct axp20x_dev *axp20x) > >>return ret; > >>} > >> > >> + irq_base = regmap_irq_chip_get_base(axp20x->regmap_irqc); > >>ret = mfd_add_devices(axp20x->dev, -1, axp20x->cells, > >> -axp20x->nr_cells, NULL, 0, NULL); > >> +axp20x->nr_cells, NULL, irq_base, NULL); > >> > >>if (ret) { > >>dev_err(axp20x->dev, "failed to add MFD devices: %d\n", ret); > >> > >> > >> However, this implies that all cells added by the mfd driver which are > >> requesting irqs will need to be changed in the same commit to remove the > >> regmap_irq_get_virq calls. If we don't modify the drivers, they will > >> purely fail to request the irqs. > >> > >> The impacted drivers are the following: > >> > >> - drivers/extcon/extcon-axp288.c > >> - drivers/input/misc/axp20x-pek.c > >> - drivers/power/supply/axp20x_usb_power.c > >> - drivers/power/supply/axp288_charger.c > >> - drivers/power/supply/axp288_fuel_gauge.c So mostly power-supply, which is affected by this series anyways. Only input & extcon are added. > >> Is it really worth to do such a cleanup? > > > > Yes. The current behaviour goes against what everyone is expecting > > from the API. > > > >> I'm assuming that impacting four different subsystems at the same > >> time might require a bit of time to make the patch into the > >> kernel. I don't see also another way than doing one single patch for > >> all changes since the changes in the mfd driver will break all > >> aforementioned drivers. > > > > However, I think that can be fixed in a later, independant serie. This > > serie is quite big already and this has been long overdue, so I'd > > really like not to delay it once again because of a dependency on a > > cross-tree cleanup. > > It's not that cross tree really. Lining up this level of change to > go through an immutable branch pulled into each of the relevant trees > isn't too hard to arrange. I'm fine with doing this as a separate series, if it follows directly behind this one. Mainlined drivers tend to be used as template for new ones and this invalid IRQ resources are a bad example. -- Sebastian signature.asc Description: PGP signature
[PATCH] x86/boot/e820: Separate the E820 ABI structures from the in-kernel structures
* Ingo Molnar wrote: > > Use explicitly sized members only, please. No "enum". > > Ok. > > Would it be acceptable to use enum for the kernel internal representation > (our > e820_table structures never actually comes directly, we construct it > ourselves), ^-- from the firmware > and maintain the very explicitly sized ABI type for the boot protocol only > (i.e. > uapi/asm/bootparam.h)? I.e. my proposed solution would be to decouple struct e820_table (and thus struct e820_entry) by making them kernel internal and thus decoupling them from the boot protocol (struct boot_params) - and not expose the enum to UAPI at all, only the raw __u32/__u64 fields of the boot protocol. We already have some pain in the code from the fact that the e820 table of the boot protocol is not actually the same as e820_table: table->nr_entries is at a different offset in struct boot_params.h. So struct e820_table is already a de facto artificial in-kernel construct and has been for a decade or so. I.e. something like the patch below. (Lightly boot tested on a couple of systems.) This actually makes things simpler and cleaner all around: - Now boot_params is not modified anymore (previous we'd call e820__update_table() on the boot parameters structure itself!). - The ugly low level __e820__update_table() is not used anymore (because all e820_table structures now have a standard layout) and can be eliminated in a future patch. - Grepping for boot_e820_entry will now actually show all the very low level E820 code that directly interfaces with the BIOS or the bootloader. This is a plus. - 'struct e820_entry' is now independent of the boot ABI. I boot tested the following experimental change: | | --- a/arch/x86/include/asm/e820/types.h | +++ b/arch/x86/include/asm/e820/types.h | @@ -44,10 +44,10 @@ enum e820_type { | * (We pack it because there can be thousands of them on large systems.) | */ | struct e820_entry { | + enum e820_type type; | u64 addr; | u64 size; | - enum e820_type type; | -} __attribute__((packed)); | +}; | | /* | * The legacy E820 BIOS limits us to 128 (E820_MAX_ENTRIES_ZEROPAGE) nodes | ... which changes both the layout and the size of e820_entry on 64-bit systems, and successfully boot-tested it - which is proof that the types are decoupled in practice as well. I don't actually think we want to change the ordering and size right now, as distro kernels can have thousands of these entries and their memory efficiency matters, but it's nice to know that the decoupling appears to be complete. Maybe some future firmware interface requires a new field, which would now be possible. - And of course this patch should also fix the problem you pointed out, the fragility of enum sizes in ABI data structures. So ... would this be an acceptable approach? (Assuming it works on all systems, etc.) Thanks, Ingo ==> >From c88a9c7e933dd665a47591ebd049a5046c7871c5 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Sun, 29 Jan 2017 12:56:13 +0100 Subject: [PATCH] x86/boot/e820: Separate the E820 ABI structures from the in-kernel structures Linus pointed out that relying on the compiler to pack structures with enums is fragile not just for the kernel, but for external tooling as well which might rely on our UAPI headers. So separate the two from each other: introduce 'struct boot_e820_entry', which is the boot protocol entry format. This actually simplifies the code, as e820__update_table() is now never called directly with boot protocol table entries - we can rely on append_e820_table() and do a e820__update_table() call afterwards. ( This will allow further simplifications of __e820__update_table(), but that will be done in a separate patch. ) This change also has the side effect of not modifying the bootparams structure anymore - which might be useful for debugging. In theory we could even constify the boot_params structure - at least from the E820 code's point of view. Remove the uapi/asm/e820/types.h file, as it's not used anymore - all kernel side E820 types are defined in asm/e820/types.h. Reported-by: Linus Torvalds Cc: Alex Thorlton Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Dan Williams Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Huang, Ying Cc: Josh Poimboeuf Cc: Juergen Gross Cc: Paul Jackson Cc: Peter Zijlstra Cc: Rafael J. Wysocki Cc: Tejun Heo Cc: Thomas Gleixner Cc: Wei Yang Cc: Yinghai Lu Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar --- arch/x86/boot/compressed/eboot.c | 16 +- arch/x86/boot/compressed/kaslr.c | 2 +- arch/x86/boot/memory.c | 4 +-- arch/x86/include/asm/e820/types.h | 48 - arch/x86/include/uapi/asm/bootparam.h | 18 +++
Re: [RFC v2 06/10] KVM: arm/arm64: Update the physical timer interrupt level
On Fri, Jan 27 2017 at 01:04:56 AM, Jintack Lim wrote: > Now that we maintain the EL1 physical timer register states of VMs, > update the physical timer interrupt level along with the virtual one. > > Note that the emulated EL1 physical timer is not mapped to any hardware > timer, so we call a proper vgic function. > > Signed-off-by: Jintack Lim > --- > virt/kvm/arm/arch_timer.c | 20 > 1 file changed, 20 insertions(+) > > diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c > index 0f6e935..3b6bd50 100644 > --- a/virt/kvm/arm/arch_timer.c > +++ b/virt/kvm/arm/arch_timer.c > @@ -180,6 +180,21 @@ static void kvm_timer_update_mapped_irq(struct kvm_vcpu > *vcpu, bool new_level, > WARN_ON(ret); > } > > +static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level, > + struct arch_timer_context *timer) > +{ > + int ret; > + > + BUG_ON(!vgic_initialized(vcpu->kvm)); Although I've added my fair share of BUG_ON() in the code base, I've since reconsidered my position. If we get in a situation where the vgic is not initialized, maybe it would be better to just WARN_ON and return early rather than killing the whole box. Thoughts? > + > + timer->irq.level = new_level; > + trace_kvm_timer_update_irq(vcpu->vcpu_id, timer->irq.irq, > +timer->irq.level); > + ret = kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id, timer->irq.irq, > + timer->irq.level); > + WARN_ON(ret); > +} > + > /* > * Check if there was a change in the timer state (should we raise or lower > * the line level to the GIC). > @@ -188,6 +203,7 @@ static int kvm_timer_update_state(struct kvm_vcpu *vcpu) > { > struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu; > struct arch_timer_context *vtimer = vcpu_vtimer(vcpu); > + struct arch_timer_context *ptimer = vcpu_ptimer(vcpu); > > /* >* If userspace modified the timer registers via SET_ONE_REG before > @@ -201,6 +217,10 @@ static int kvm_timer_update_state(struct kvm_vcpu *vcpu) > if (kvm_timer_should_fire(vcpu, vtimer) != vtimer->irq.level) > kvm_timer_update_mapped_irq(vcpu, !vtimer->irq.level, vtimer); > > + /* The emulated EL1 physical timer irq is not mapped to hardware */ Maybe a slightly better comment would be saying that we're using a purely virtual interrupt, unrelated to the hardware interrupt. > + if (kvm_timer_should_fire(vcpu, ptimer) != ptimer->irq.level) > + kvm_timer_update_irq(vcpu, !ptimer->irq.level, ptimer); > + > return 0; > } Otherwise looks good. M. -- Jazz is not dead. It just smells funny.
[PATCH -tip] sched/wake_q: Clarify queue reinit
As of bcc9a76d5ac (locking/rwsem: Reinit wake_q after use), the comment regarding the list reinitialization no longer applies, update it with the new wake_q_init() helper. Signed-off-by: Davidlohr Bueso --- include/linux/sched.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/sched.h b/include/linux/sched.h index 3640bde9f982..c0bc626c531f 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -998,8 +998,8 @@ enum cpu_idle_type { * * The DEFINE_WAKE_Q macro declares and initializes the list head. * wake_up_q() does NOT reinitialize the list; it's expected to be - * called near the end of a function, where the fact that the queue is - * not used again will be easy to see by inspection. + * called near the end of a function. Otherwise, the list can be + * re-initialized for later re-use by wake_q_init(). * * Note that this can cause spurious wakeups. schedule() callers * must ensure the call is done inside a loop, confirming that the -- 2.6.6
Re: [RFC v2 10/10] KVM: arm/arm64: Emulate the EL1 phys timer register access
On Fri, Jan 27 2017 at 01:05:00 AM, Jintack Lim wrote: > Emulate read and write operations to CNTP_TVAL, CNTP_CVAL and CNTP_CTL. > Now VMs are able to use the EL1 physical timer. > > Signed-off-by: Jintack Lim > --- > arch/arm64/kvm/sys_regs.c| 32 +--- > include/kvm/arm_arch_timer.h | 2 ++ > virt/kvm/arm/arch_timer.c| 2 +- > 3 files changed, 32 insertions(+), 4 deletions(-) > > diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c > index fd9e747..adf009f 100644 > --- a/arch/arm64/kvm/sys_regs.c > +++ b/arch/arm64/kvm/sys_regs.c > @@ -824,7 +824,14 @@ static bool access_cntp_tval(struct kvm_vcpu *vcpu, > struct sys_reg_params *p, > const struct sys_reg_desc *r) > { > - kvm_inject_undefined(vcpu); > + struct arch_timer_context *ptimer = vcpu_ptimer(vcpu); > + u64 now = kvm_phys_timer_read(); > + > + if (p->is_write) > + ptimer->cnt_cval = p->regval + now; > + else > + p->regval = ptimer->cnt_cval - now; > + > return true; > } > > @@ -832,7 +839,20 @@ static bool access_cntp_ctl(struct kvm_vcpu *vcpu, > struct sys_reg_params *p, > const struct sys_reg_desc *r) > { > - kvm_inject_undefined(vcpu); > + struct arch_timer_context *ptimer = vcpu_ptimer(vcpu); > + > + if (p->is_write) { > + /* ISTATUS bit is read-only */ > + ptimer->cnt_ctl = p->regval & ~ARCH_TIMER_CTRL_IT_STAT; > + } else { > + u64 now = kvm_phys_timer_read(); > + > + p->regval = ptimer->cnt_ctl; > + /* Set ISTATUS bit if it's expired */ > + if (ptimer->cnt_cval <= now) > + p->regval |= ARCH_TIMER_CTRL_IT_STAT; > + } Shouldn't we take the ENABLE bit into account? The ARMv8 ARM version I have at hand (version h) seems to indicate that we should, but we should check with the latest and greatest... > + > return true; > } > > @@ -840,7 +860,13 @@ static bool access_cntp_cval(struct kvm_vcpu *vcpu, > struct sys_reg_params *p, > const struct sys_reg_desc *r) > { > - kvm_inject_undefined(vcpu); > + struct arch_timer_context *ptimer = vcpu_ptimer(vcpu); > + > + if (p->is_write) > + ptimer->cnt_cval = p->regval; > + else > + p->regval = ptimer->cnt_cval; > + > return true; > } > > diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h > index a364593..fec99f2 100644 > --- a/include/kvm/arm_arch_timer.h > +++ b/include/kvm/arm_arch_timer.h > @@ -74,6 +74,8 @@ bool kvm_timer_should_fire(struct kvm_vcpu *vcpu, > void kvm_timer_schedule(struct kvm_vcpu *vcpu); > void kvm_timer_unschedule(struct kvm_vcpu *vcpu); > > +u64 kvm_phys_timer_read(void); > + > void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu); > > void kvm_timer_init_vhe(void); > diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c > index b366bb2..9eec063 100644 > --- a/virt/kvm/arm/arch_timer.c > +++ b/virt/kvm/arm/arch_timer.c > @@ -40,7 +40,7 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu) > vcpu_vtimer(vcpu)->active_cleared_last = false; > } > > -static u64 kvm_phys_timer_read(void) > +u64 kvm_phys_timer_read(void) > { > return timecounter->cc->read(timecounter->cc); > } Thanks, M. -- Jazz is not dead. It just smells funny.
Re: [RFC v2 00/10] Provide the EL1 physical timer to the VM
Hi Jintack, On Fri, Jan 27 2017 at 01:04:50 AM, Jintack Lim wrote: > The ARM architecture defines the EL1 physical timer and the virtual timer, > and it is reasonable for an OS to expect to be able to access both. > However, the current KVM implementation does not provide the EL1 physical > timer to VMs but terminates VMs on access to the timer. > > This patch series enables VMs to use the EL1 physical timer through > trap-and-emulate. The KVM host emulates each EL1 physical timer register > access and sets up the background timer accordingly. When the background > timer expires, the KVM host injects EL1 physical timer interrupts to the > VM. Alternatively, it's also possible to allow VMs to access the EL1 > physical timer without trapping. However, this requires somehow using the > EL2 physical timer for the Linux host while running the VM instead of the > EL1 physical timer. Right now I just implemented trap-and-emulate because > this was straightforward to do, and I leave it to future work to determine > if transferring the EL1 physical timer state to the EL2 timer provides any > performance benefit. > > This feature will be useful for any OS that wishes to access the EL1 > physical timer. Nested virtualization is one of those use cases. A nested > hypervisor running inside a VM would think it has full access to the > hardware and naturally tries to use the EL1 physical timer as Linux would > do. Other nested hypervisors may try to use the EL2 physical timer as Xen > would do, but supporting the EL2 physical timer to the VM is out of scope > of this patch series. This patch series will make it easy to add the EL2 > timer support in the future, though. > > Note that Linux VMs booting in EL1 will be unaffected by this patch series > and will continue to use only the virtual timer and this patch series will > therefore not introduce any performance degredation as a result of > trap-and-emulate. Thanks for respining this series. Overall, this looks quite good, and the couple of comments I have should be easy to address. My main concern is that we do expose a timer that doesn't hide CNTVOFF. I appreciate that that was already the case, since CNTPCT was always available (and this avoided trapping the counter), but maybe we should have a way for userspace to ask for a mode where CNTPCT=CNTVCT, byt trapping the physical counter and taking CNTVOFF in all physical timer calculations. I'm pretty sure you've addressed this one way or another in your nested virt series, so maybe extracting the relevant patches and adding them on top of this series could be an option? Thanks, M. -- Jazz is not dead. It just smells funny.
Re: [PATCH] clk: add more managed APIs
On 01/28/2017 03:39 PM, Russell King - ARM Linux wrote: On Sat, Jan 28, 2017 at 01:44:35PM -0800, Guenter Roeck wrote: On 01/28/2017 11:22 AM, Dmitry Torokhov wrote: Guenter, I know you are a coccinelle wizard, can you cook a script that can find current users of clk_enable() in probe paths? Then we can make informed decision on devm_clk_enable. Questionable use: drivers/input/keyboard/st-keyscan.c clk_enable() without preceding clk_prepare() - buggy. clk_enable() in probe, clk_disable() in remove: drivers/i2c/busses/i2c-tegra.c Could be converted to use clk_prepare_enable() or clk_prepare() depending on i2c_dev->is_multimaster_mode in the initialisation path (and their devm_* equivalents.) drivers/media/platform/exynos4-is/fimc-core.c drivers/media/platform/exynos4-is/mipi-csis.c Looks like it does a sequence of: devm_clk_get() clk_prepare() clk_set_rate() clk_enable() which seems a little wrong - clk_set_rate() should be before clk_prepare() if you care about not having the clock output. Remember that clk_prepare() _may_ result in the clock output being enabled. So these two look buggy, and when fixed could use devm_clk_prepare_enable(). drivers/thermal/spear_thermal.c clk_enable() without a preceding clk_prepare(). Buggy driver. drivers/usb/musb/am35x.c Ditto. drivers/usb/musb/davinci.c Ditto. Not that many. A quick browse suggests that clk_enable()/clk_disable() is more commonly used to temporarily enable the clock while needed. So out of all those, there's probably only _one_ which is legit - the rest are all technically buggy. Given that, I'd say there's real reason _not_ to provide devm_clk_enable() to persuade people to use the correct interfaces in the probe path. I tend to agree, after looking into its existing use. Do we have agreement on the other two ? I would like to see those in the next release so we can start using them. Thanks, Guenter
Re: [PATCH] power: supply: max14656: Export I2C and OF device ID as module aliases
Hi Javier, On Wed, Jan 25, 2017 at 10:38:55AM -0300, Javier Martinez Canillas wrote: > If the driver is built as a module, I2C module alias information is not > filled so the module won't be autoloaded. Export the I2C and OF devices > ID to the module by using the MODULE_DEVICE_TABLE() macro. > > Before this patch: > > $ modinfo drivers/power/supply/max14656_charger_detector.ko | grep alias > $ > > After this patch: > > $ modinfo drivers/power/supply/max14656_charger_detector.ko | grep alias > alias: i2c:max14656 > alias: of:N*T*Cmaxim,max14656C* > alias: of:N*T*Cmaxim,max14656 > > Signed-off-by: Javier Martinez Canillas Thanks, queued into power-supply's for-next. -- Sebastian signature.asc Description: PGP signature
Re: [PATCH -tip] sched/wake_q: Clarify queue reinit
On 01/29/2017 10:15 AM, Davidlohr Bueso wrote: > As of bcc9a76d5ac (locking/rwsem: Reinit wake_q after use), the > comment regarding the list reinitialization no longer applies, > update it with the new wake_q_init() helper. > > Signed-off-by: Davidlohr Bueso > --- > include/linux/sched.h | 4 ++-- > 1 file changed, 2 insertions(+), 2 deletions(-) > > diff --git a/include/linux/sched.h b/include/linux/sched.h > index 3640bde9f982..c0bc626c531f 100644 > --- a/include/linux/sched.h > +++ b/include/linux/sched.h > @@ -998,8 +998,8 @@ enum cpu_idle_type { > * > * The DEFINE_WAKE_Q macro declares and initializes the list head. > * wake_up_q() does NOT reinitialize the list; it's expected to be > - * called near the end of a function, where the fact that the queue is > - * not used again will be easy to see by inspection. > + * called near the end of a function. Otherwise, the list can be > + * re-initialized for later re-use by wake_q_init(). > * > * Note that this can cause spurious wakeups. schedule() callers > * must ensure the call is done inside a loop, confirming that the Acked-by: Waiman Long
Re: [PATCH 10/10] slab: use memcg_kmem_cache_wq for slab destruction operations
On Tue, Jan 17, 2017 at 03:54:11PM -0800, Tejun Heo wrote: > If there's contention on slab_mutex, queueing the per-cache > destruction work item on the system_wq can unnecessarily create and > tie up a lot of kworkers. > > Rename memcg_kmem_cache_create_wq to memcg_kmem_cache_wq and make it > global and use that workqueue for the destruction work items too. > While at it, convert the workqueue from an unbound workqueue to a > per-cpu one with concurrency limited to 1. It's generally preferable > to use per-cpu workqueues and concurrency limit of 1 is safe enough. > > This is suggested by Joonsoo Kim. > > Signed-off-by: Tejun Heo > Reported-by: Jay Vana > Cc: Vladimir Davydov > Cc: Christoph Lameter > Cc: Pekka Enberg > Cc: David Rientjes > Cc: Joonsoo Kim > Cc: Andrew Morton Acked-by: Vladimir Davydov
Re: [PATCH v2 10/25] power: supply: add AC power supply driver for AXP20X and AXP22X PMICs
Hi, On Fri, Jan 27, 2017 at 09:54:43AM +0100, Quentin Schulz wrote: > The X-Powers AXP20X and AXP22X PMICs expose the status of AC power > supply. > > Moreover, the AXP20X can also expose the current current and voltage > values of the AC power supply. > > This adds the driver which exposes the status of the AC power supply of > the AXP20X and AXP22X PMICs. > > Signed-off-by: Quentin Schulz > Acked-by: Jonathan Cameron Thanks, I queued this into power-supply's for-next branch. I removed "struct device_node *np" and "int axp20x_id" from "struct axp20x_ac_power", since they were unused. -- Sebastian signature.asc Description: PGP signature
Re: [PATCH v2 09/25] iio: adc: axp20x_adc: map acin_i and acin_v
Hi, On Fri, Jan 27, 2017 at 09:54:42AM +0100, Quentin Schulz wrote: > This maps the IIO channels acin_i and acin_v (respectively exposing the > current current and voltage measures of the AC power supply) to the AC > power supply driver. > > Only the AXP20X PMICs have these ADC channels and thus they are only > mapped for this version of the PMIC. > > Signed-off-by: Quentin Schulz > --- > > added in v2 > > drivers/iio/adc/axp20x_adc.c | 8 > 1 file changed, 8 insertions(+) > > diff --git a/drivers/iio/adc/axp20x_adc.c b/drivers/iio/adc/axp20x_adc.c > index bacde92..14f4ec0 100644 > --- a/drivers/iio/adc/axp20x_adc.c > +++ b/drivers/iio/adc/axp20x_adc.c > @@ -104,6 +104,14 @@ static struct iio_map axp20x_maps[] = { > .consumer_dev_name = "axp20x-usb-power-supply", > .consumer_channel = "vbus_i", > .adc_channel_label = "vbus_i", > + }, { > + .consumer_dev_name = "axp20x-ac-power-supply", > + .consumer_channel = "acin_v", > + .adc_channel_label = "acin_v", > + }, { > + .consumer_dev_name = "axp20x-ac-power-supply", > + .consumer_channel = "acin_i", > + .adc_channel_label = "acin_i", > }, { /* sentinel */ } > }; I suggest to merge this into Patch 4 before resending the series. -- Sebastian signature.asc Description: PGP signature
Re: [PATCH v2 11/25] mfd: axp20x: add AC power supply cells for AXP22X PMICs
Hi, On Fri, Jan 27, 2017 at 09:54:44AM +0100, Quentin Schulz wrote: > The X-Powers AXP20X and AXP22X PMICs expose the status of AC power > supply. > > This adds the AC power supply driver to the MFD cells of the AXP22X > PMICs. > > Signed-off-by: Quentin Schulz > Acked-for-MFD-by: Lee Jones Acked-By: Sebastian Reichel -- Sebastian signature.asc Description: PGP signature
Re: [PATCH] staging: rtl8188eu: checkpatch fixes: removed not necessary braces {}
Greg KH writes: > Please take some time, and go read Documentation/SubmittingPatches. That's quickly done nowadays: bjorn@miraculix:/usr/local/src/git/linux$ cat Documentation/SubmittingPatches This file has moved to process/submitting-patches.rst I don't know why it was necessary to move that file, but it looks like you, and the gazillion links and references to this document, just have to adopt to a new location. Or submit a patch to fix it :) Bjørn
Re: [PATCH v2 16/25] dt-bindings: power: supply: add AXP20X/AXP22X battery DT binding
Hi, On Fri, Jan 27, 2017 at 09:54:49AM +0100, Quentin Schulz wrote: > - added x-powers,constant-charge-current property to set the > maximal default constant current charge of the battery, Since this is information about the battery and not the fuel-gauge, it should use the WIP "framework" for information about batteries. Have a look at the following patchset: http://marc.info/?l=linux-pm&m=148411561025684&w=2 -- Sebastian signature.asc Description: PGP signature
RE: [PATCH 2/2] perf,core: use parent avg sample period as child initial period
> > On Wed, Jan 18, 2017 at 08:21:02AM -0500, kan.li...@intel.com wrote: > > From: Kan Liang > > > > perf brings additional overhead when monitoring the task which > > frequently generates child task. > > > > When inheriting a event from parent task to child task, the > > sample_period of original parent event (parent_event->parent) will be > > assigned to child event as its initial period, which is usually the > > default sample_period 1. > > > Why is that mostly 1? I would expect the parent event's sample_period to > ramp up as well. The conclusion is based on the observation in the specific test case mentioned in the description. The sample_period is for the original parent event (parent_event->parent), not the direct parent. I did several tests these days, it can be 100% reproduced by this particular test case in multiplexing. I think the reason is that the original parent event is scheduled out shortly and never gets a chance to trigger interrupt in the first round. So its sample_period doesn't get updated. Then the test case repeatedly generates child tasks and child events. The new child events will be scheduled in/out continually. The original parent event never gets a change to be scheduled again. So the original parent event's sample_period is kept1. Thanks, Kan
Re: [PATCH 01/50] x86/boot/e820: Introduce arch/x86/include/asm/e820/types.h
On Sat, Jan 28, 2017 at 11:11:22PM +0100, Ingo Molnar wrote: > > The plan is to keep the old UAPI header in place but the kernel won't > use it anymore - and after some time we'll try to remove it. (User-space > tools better have local copies of headers anyway, instead of relying > on kernel headers.) The idea with uapi is the the kernel provides a sane set of headers to be used by user space. So we avoid random copies that is maintained by random people in random ways resulting in random bugs. The step(s) outlined here can only result in inconsistency and cannot benefit neither user space nor the kernel in the long run. The uapi shall be lean and clean headers, and shall include no info whatsoever that is not relevant for user space. But requiring all user space programs (diverse libc variants, other programs) to maintain their own copy can only result in inconsistencies that is the benefit for no one. Sam
Re: [PATCH] tpm: add buffer access validation in tpm2_get_pcr_allocation()
On 01/29/2017 08:10 PM, Jarkko Sakkinen wrote: On Fri, Jan 27, 2017 at 10:25:49AM -0500, Nayna Jain wrote: This patch add validation in tpm2_get_pcr_allocation to avoid access beyond response buffer length. Suggested-by: Stefan Berger Signed-off-by: Nayna Jain This validation looks broken to me. --- drivers/char/tpm/tpm2-cmd.c | 28 +++- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index 4aad84c..02c1ea7 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -1008,9 +1008,13 @@ static ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip) struct tpm2_pcr_selection pcr_selection; struct tpm_buf buf; void *marker; - unsigned int count = 0; + void *end; + void *pcr_select_offset; + unsigned int count; + u32 sizeof_pcr_selection; + u32 resp_len; Very cosmetic but we almos almost universally use the acronym 'rsp' in the TPM driver. Sure will update. int rc; - int i; + int i = 0; Why do you need to initialize it? Because in out: count is replaced with i. And it is replaced because now for loop can break even before reaching count, because of new buffer checks. rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY); if (rc) @@ -1034,15 +1038,29 @@ static ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip) } marker = &buf.data[TPM_HEADER_SIZE + 9]; + + resp_len = be32_to_cpup((__be32 *)&buf.data[2]); + end = &buf.data[resp_len]; What if the response contains larger length than the buffer size? Isn't this check need to be done in tpm_transmit_cmd for all responses ? Though, it seems it is not done there as well. And to understand what do we expect max buffer length. PAGE_SIZE or TPM_BUFSIZE ? + for (i = 0; i < count; i++) { + pcr_select_offset = marker + + offsetof(struct tpm2_pcr_selection, size_of_select); + if (pcr_select_offset >= end) { + rc = -EFAULT; + break; + } + memcpy(&pcr_selection, marker, sizeof(pcr_selection)); chip->active_banks[i] = be16_to_cpu(pcr_selection.hash_alg); - marker = marker + sizeof(struct tpm2_pcr_selection); + sizeof_pcr_selection = sizeof(pcr_selection.hash_alg) + + sizeof(pcr_selection.size_of_select) + + sizeof(u8) * pcr_selection.size_of_select; Remove "sizeof(u8) * ". Sure. + marker = marker + sizeof_pcr_selection; } out: - if (count < ARRAY_SIZE(chip->active_banks)) - chip->active_banks[count] = TPM2_ALG_ERROR; + if (i < ARRAY_SIZE(chip->active_banks)) + chip->active_banks[i] = TPM2_ALG_ERROR; tpm_buf_destroy(&buf); -- 2.5.0 I'm sorry but this commit is changing too much. You need to redo the whole commit and resend the patch set with these fixes. You can keep Reviewed-by and Tested-by in 1/2 but have to remove them from 2/2. Sure, will do. Thanks & Regards, - Nayna /Jarkko
Re: [PATCH 2/6] wl1251: Use request_firmware_prefer_user() for loading NVS calibration data
On Fri, Jan 27, 2017 at 02:11:46PM +0100, Pali Rohár wrote: > So there are only two options: > > 1) Disallow it and so these users will have non-working wifi. > > 2) Allow those data to be used as fallback mechanism. There is one "custom fallback" user in kernel which we recently determined was a total mistake. A sysfs interface should have been defined to enable custom LED settings. Can't a series of sysfs interfaces be used to enable override ? So is that not a third option worth consideration? Luis
[PATCH -tip] rcuwait: Fix wake_up typo
Forgot to update the comment after renaming the call. Signed-off-by: Davidlohr Bueso --- include/linux/rcuwait.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/rcuwait.h b/include/linux/rcuwait.h index 0e93d56c7ab2..a4ede51b3e7c 100644 --- a/include/linux/rcuwait.h +++ b/include/linux/rcuwait.h @@ -47,7 +47,7 @@ extern void rcuwait_wake_up(struct rcuwait *w); for (;;) { \ /* \ * Implicit barrier (A) pairs with (B) in \ -* rcuwait_trywake(). \ +* rcuwait_wake_up(). \ */ \ set_current_state(TASK_UNINTERRUPTIBLE);\ if (condition) \ -- 2.6.6
Re: [PATCH v2 08/25] dt-bindings: power: supply: add AXP20X/AXP22X AC power supply
Hi, On Fri, Jan 27, 2017 at 09:54:41AM +0100, Quentin Schulz wrote: > The X-Powers AXP20X and AXP22X PMICs have an AC entry to supply power to > the board. They have a few registers dedicated to the status of the AC > power supply. > > This adds the DT binding documentation for the AC power supply for > AXP20X and AXP22X PMICs. > > Signed-off-by: Quentin Schulz Thanks, I queued this into power-supply's for-next branch. -- Sebastian signature.asc Description: PGP signature
[GIT PULL] parisc architecture fixes for v4.10-rc6
Hi Linus, please pull two fixes for the parisc architecture for kernel 4.10-rc6 from: git://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux.git parisc-4.10-3 One fix to avoid usage of BITS_PER_LONG in user-space exported swab.h header which breaks compiling qemu, and one trivial fix for printk continuation in the parisc parport driver. Thanks, Helge Helge Deller (2): parisc, parport_gsc: Fixes for printk continuation lines parisc: Don't use BITS_PER_LONG in userspace-exported swab.h header arch/parisc/include/asm/bitops.h | 8 +++- arch/parisc/include/uapi/asm/bitsperlong.h | 2 -- arch/parisc/include/uapi/asm/swab.h| 5 +++-- drivers/parport/parport_gsc.c | 8 4 files changed, 14 insertions(+), 9 deletions(-)
[PATCH] macintosh: windfarm_smu_sensors: constify wf_sensor_ops structures
Declare wf_sensor_ops structures as const as they are only stored in the ops field of a wf_sensor structure. This field is of type const, so wf_sensor_ops structures having this property can be made const too. Done using Coccinelle: @r disable optional_qualifier@ identifier x; position p; @@ static struct wf_sensor_ops x@p={...}; @ok@ struct smu_ad_sensor ads; struct smu_cpu_power_sensor pow; identifier r.x; position p; @@ ( ads.sens.ops=&x@p; | pow.sens.ops=&x@p; ) @bad@ position p != {r.p,ok.p}; identifier r.x; @@ x@p @depends on !bad disable optional_qualifier@ identifier r.x; @@ +const struct wf_sensor_ops x; Size details after cross compiling the .o file for powerpc architecture. File size before: text data bss dec hex filename 3700 408 484156103c macintosh/windfarm_smu_sensors.o File size after: text data bss dec hex filename 3832 288 4841681048 macintosh/windfarm_smu_sensors.o Signed-off-by: Bhumika Goyal --- drivers/macintosh/windfarm_smu_sensors.c | 10 +- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/macintosh/windfarm_smu_sensors.c b/drivers/macintosh/windfarm_smu_sensors.c index 1cc4e49..172fd26 100644 --- a/drivers/macintosh/windfarm_smu_sensors.c +++ b/drivers/macintosh/windfarm_smu_sensors.c @@ -172,22 +172,22 @@ static int smu_slotspow_get(struct wf_sensor *sr, s32 *value) } -static struct wf_sensor_ops smu_cputemp_ops = { +static const struct wf_sensor_ops smu_cputemp_ops = { .get_value = smu_cputemp_get, .release= smu_ads_release, .owner = THIS_MODULE, }; -static struct wf_sensor_ops smu_cpuamp_ops = { +static const struct wf_sensor_ops smu_cpuamp_ops = { .get_value = smu_cpuamp_get, .release= smu_ads_release, .owner = THIS_MODULE, }; -static struct wf_sensor_ops smu_cpuvolt_ops = { +static const struct wf_sensor_ops smu_cpuvolt_ops = { .get_value = smu_cpuvolt_get, .release= smu_ads_release, .owner = THIS_MODULE, }; -static struct wf_sensor_ops smu_slotspow_ops = { +static const struct wf_sensor_ops smu_slotspow_ops = { .get_value = smu_slotspow_get, .release= smu_ads_release, .owner = THIS_MODULE, @@ -327,7 +327,7 @@ static int smu_cpu_power_get(struct wf_sensor *sr, s32 *value) return 0; } -static struct wf_sensor_ops smu_cpu_power_ops = { +static const struct wf_sensor_ops smu_cpu_power_ops = { .get_value = smu_cpu_power_get, .release= smu_cpu_power_release, .owner = THIS_MODULE, -- 2.7.4
[PATCHv3 06/12] mm: convert page_mkclean_one() to use page_vma_mapped_walk()
For consistency, it worth converting all page_check_address() to page_vma_mapped_walk(), so we could drop the former. PMD handling here is future-proofing, we don't have users yet. ext4 with huge pages will be the first. Signed-off-by: Kirill A. Shutemov --- mm/rmap.c | 68 ++- 1 file changed, 45 insertions(+), 23 deletions(-) diff --git a/mm/rmap.c b/mm/rmap.c index c4bad599cc7b..58597de049fd 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -1017,34 +1017,56 @@ int page_referenced(struct page *page, static int page_mkclean_one(struct page *page, struct vm_area_struct *vma, unsigned long address, void *arg) { - struct mm_struct *mm = vma->vm_mm; - pte_t *pte; - spinlock_t *ptl; - int ret = 0; + struct page_vma_mapped_walk pvmw = { + .page = page, + .vma = vma, + .address = address, + .flags = PVMW_SYNC, + }; int *cleaned = arg; - pte = page_check_address(page, mm, address, &ptl, 1); - if (!pte) - goto out; - - if (pte_dirty(*pte) || pte_write(*pte)) { - pte_t entry; + while (page_vma_mapped_walk(&pvmw)) { + int ret = 0; + address = pvmw.address; + if (pvmw.pte) { + pte_t entry; + pte_t *pte = pvmw.pte; + + if (!pte_dirty(*pte) && !pte_write(*pte)) + continue; + + flush_cache_page(vma, address, pte_pfn(*pte)); + entry = ptep_clear_flush(vma, address, pte); + entry = pte_wrprotect(entry); + entry = pte_mkclean(entry); + set_pte_at(vma->vm_mm, address, pte, entry); + ret = 1; + } else { +#ifdef CONFIG_TRANSPARENT_HUGE_PAGECACHE + pmd_t *pmd = pvmw.pmd; + pmd_t entry; + + if (!pmd_dirty(*pmd) && !pmd_write(*pmd)) + continue; + + flush_cache_page(vma, address, page_to_pfn(page)); + entry = pmdp_huge_clear_flush(vma, address, pmd); + entry = pmd_wrprotect(entry); + entry = pmd_mkclean(entry); + set_pmd_at(vma->vm_mm, address, pmd, entry); + ret = 1; +#else + /* unexpected pmd-mapped page? */ + WARN_ON_ONCE(1); +#endif + } - flush_cache_page(vma, address, pte_pfn(*pte)); - entry = ptep_clear_flush(vma, address, pte); - entry = pte_wrprotect(entry); - entry = pte_mkclean(entry); - set_pte_at(mm, address, pte, entry); - ret = 1; + if (ret) { + mmu_notifier_invalidate_page(vma->vm_mm, address); + (*cleaned)++; + } } - pte_unmap_unlock(pte, ptl); - - if (ret) { - mmu_notifier_invalidate_page(mm, address); - (*cleaned)++; - } -out: return SWAP_AGAIN; } -- 2.11.0
[PATCHv3 07/12] mm: convert try_to_unmap_one() to use page_vma_mapped_walk()
For consistency, it worth converting all page_check_address() to page_vma_mapped_walk(), so we could drop the former. It also makes freeze_page() as we walk though rmap only once. Signed-off-by: Kirill A. Shutemov --- mm/huge_memory.c | 16 +--- mm/rmap.c| 260 --- 2 files changed, 137 insertions(+), 139 deletions(-) diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 16820e001d79..ca7855f857fa 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -1839,24 +1839,16 @@ void vma_adjust_trans_huge(struct vm_area_struct *vma, static void freeze_page(struct page *page) { enum ttu_flags ttu_flags = TTU_IGNORE_MLOCK | TTU_IGNORE_ACCESS | - TTU_RMAP_LOCKED; - int i, ret; + TTU_RMAP_LOCKED | TTU_SPLIT_HUGE_PMD; + int ret; VM_BUG_ON_PAGE(!PageHead(page), page); if (PageAnon(page)) ttu_flags |= TTU_MIGRATION; - /* We only need TTU_SPLIT_HUGE_PMD once */ - ret = try_to_unmap(page, ttu_flags | TTU_SPLIT_HUGE_PMD); - for (i = 1; !ret && i < HPAGE_PMD_NR; i++) { - /* Cut short if the page is unmapped */ - if (page_count(page) == 1) - return; - - ret = try_to_unmap(page + i, ttu_flags); - } - VM_BUG_ON_PAGE(ret, page + i - 1); + ret = try_to_unmap(page, ttu_flags); + VM_BUG_ON_PAGE(ret, page); } static void unfreeze_page(struct page *page) diff --git a/mm/rmap.c b/mm/rmap.c index 58597de049fd..11668fb881d8 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -607,8 +607,7 @@ void try_to_unmap_flush_dirty(void) try_to_unmap_flush(); } -static void set_tlb_ubc_flush_pending(struct mm_struct *mm, - struct page *page, bool writable) +static void set_tlb_ubc_flush_pending(struct mm_struct *mm, bool writable) { struct tlbflush_unmap_batch *tlb_ubc = ¤t->tlb_ubc; @@ -643,8 +642,7 @@ static bool should_defer_flush(struct mm_struct *mm, enum ttu_flags flags) return should_defer; } #else -static void set_tlb_ubc_flush_pending(struct mm_struct *mm, - struct page *page, bool writable) +static void set_tlb_ubc_flush_pending(struct mm_struct *mm, bool writable) { } @@ -1459,155 +1457,163 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma, unsigned long address, void *arg) { struct mm_struct *mm = vma->vm_mm; - pte_t *pte; + struct page_vma_mapped_walk pvmw = { + .page = page, + .vma = vma, + .address = address, + }; pte_t pteval; - spinlock_t *ptl; + struct page *subpage; int ret = SWAP_AGAIN; struct rmap_private *rp = arg; enum ttu_flags flags = rp->flags; /* munlock has nothing to gain from examining un-locked vmas */ if ((flags & TTU_MUNLOCK) && !(vma->vm_flags & VM_LOCKED)) - goto out; + return SWAP_AGAIN; if (flags & TTU_SPLIT_HUGE_PMD) { split_huge_pmd_address(vma, address, flags & TTU_MIGRATION, page); - /* check if we have anything to do after split */ - if (page_mapcount(page) == 0) - goto out; } - pte = page_check_address(page, mm, address, &ptl, -PageTransCompound(page)); - if (!pte) - goto out; + while (page_vma_mapped_walk(&pvmw)) { + subpage = page - page_to_pfn(page) + pte_pfn(*pvmw.pte); + address = pvmw.address; - /* -* If the page is mlock()d, we cannot swap it out. -* If it's recently referenced (perhaps page_referenced -* skipped over this mm) then we should reactivate it. -*/ - if (!(flags & TTU_IGNORE_MLOCK)) { - if (vma->vm_flags & VM_LOCKED) { - /* PTE-mapped THP are never mlocked */ - if (!PageTransCompound(page)) { - /* -* Holding pte lock, we do *not* need -* mmap_sem here -*/ - mlock_vma_page(page); + /* Unexpected PMD-mapped THP? */ + VM_BUG_ON_PAGE(!pvmw.pte, page); + + /* +* If the page is mlock()d, we cannot swap it out. +* If it's recently referenced (perhaps page_referenced +* skipped over this mm) then we should reactivate it. +*/ + if (!(flags & TTU_IGNORE_MLOCK)) { + if (vma->vm_flags & VM_LOCKED) { + /* PTE-mapped THP are never mlocked */ + if (!PageTransCompound(page)) { +
[PATCHv3 02/12] mm: introduce page_vma_mapped_walk()
The patch introduces new interface to check if a page is mapped into a vma. It aims to address shortcomings of page_check_address{,_transhuge}. Existing interface is not able to handle PTE-mapped THPs: it only finds the first PTE. The rest lefted unnoticed. page_vma_mapped_walk() iterates over all possible mapping of the page in the vma. Signed-off-by: Kirill A. Shutemov --- include/linux/rmap.h | 26 +++ mm/Makefile | 6 +- mm/huge_memory.c | 9 ++- mm/page_vma_mapped.c | 188 +++ 4 files changed, 224 insertions(+), 5 deletions(-) create mode 100644 mm/page_vma_mapped.c diff --git a/include/linux/rmap.h b/include/linux/rmap.h index 15321fb1df6b..b76343610653 100644 --- a/include/linux/rmap.h +++ b/include/linux/rmap.h @@ -9,6 +9,7 @@ #include #include #include +#include /* * The anon_vma heads a list of private "related" vmas, to scan if @@ -232,6 +233,31 @@ static inline bool page_check_address_transhuge(struct page *page, } #endif +/* Avoid racy checks */ +#define PVMW_SYNC (1 << 0) +/* Look for migarion entries rather than present PTEs */ +#define PVMW_MIGRATION (1 << 1) + +struct page_vma_mapped_walk { + struct page *page; + struct vm_area_struct *vma; + unsigned long address; + pmd_t *pmd; + pte_t *pte; + spinlock_t *ptl; + unsigned int flags; +}; + +static inline void page_vma_mapped_walk_done(struct page_vma_mapped_walk *pvmw) +{ + if (pvmw->pte) + pte_unmap(pvmw->pte); + if (pvmw->ptl) + spin_unlock(pvmw->ptl); +} + +bool page_vma_mapped_walk(struct page_vma_mapped_walk *pvmw); + /* * Used by swapoff to help locate where page is expected in vma. */ diff --git a/mm/Makefile b/mm/Makefile index 295bd7a9f76b..e375745a88a5 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -23,8 +23,10 @@ KCOV_INSTRUMENT_vmstat.o := n mmu-y := nommu.o mmu-$(CONFIG_MMU) := gup.o highmem.o memory.o mincore.o \ - mlock.o mmap.o mprotect.o mremap.o msync.o rmap.o \ - vmalloc.o pagewalk.o pgtable-generic.o + mlock.o mmap.o mprotect.o mremap.o msync.o \ + page_vma_mapped.o pagewalk.o pgtable-generic.o \ + rmap.o vmalloc.o + ifdef CONFIG_CROSS_MEMORY_ATTACH mmu-$(CONFIG_MMU) += process_vm_access.o diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 9a6bd6c8d55a..16820e001d79 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -1862,9 +1862,12 @@ static void freeze_page(struct page *page) static void unfreeze_page(struct page *page) { int i; - - for (i = 0; i < HPAGE_PMD_NR; i++) - remove_migration_ptes(page + i, page + i, true); + if (PageTransHuge(page)) { + remove_migration_ptes(page, page, true); + } else { + for (i = 0; i < HPAGE_PMD_NR; i++) + remove_migration_ptes(page + i, page + i, true); + } } static void __split_huge_page_tail(struct page *head, int tail, diff --git a/mm/page_vma_mapped.c b/mm/page_vma_mapped.c new file mode 100644 index ..bbd2a39e985d --- /dev/null +++ b/mm/page_vma_mapped.c @@ -0,0 +1,188 @@ +#include +#include +#include +#include +#include + +#include "internal.h" + +static inline bool check_pmd(struct page_vma_mapped_walk *pvmw) +{ + pmd_t pmde; + /* +* Make sure we don't re-load pmd between present and !trans_huge check. +* We need a consistent view. +*/ + pmde = READ_ONCE(*pvmw->pmd); + return pmd_present(pmde) && !pmd_trans_huge(pmde); +} + +static inline bool not_found(struct page_vma_mapped_walk *pvmw) +{ + page_vma_mapped_walk_done(pvmw); + return false; +} + +static bool map_pte(struct page_vma_mapped_walk *pvmw) +{ + pvmw->pte = pte_offset_map(pvmw->pmd, pvmw->address); + if (!(pvmw->flags & PVMW_SYNC)) { + if (pvmw->flags & PVMW_MIGRATION) { + if (!is_swap_pte(*pvmw->pte)) + return false; + } else { + if (!pte_present(*pvmw->pte)) + return false; + } + } + pvmw->ptl = pte_lockptr(pvmw->vma->vm_mm, pvmw->pmd); + spin_lock(pvmw->ptl); + return true; +} + +static bool check_pte(struct page_vma_mapped_walk *pvmw) +{ + if (pvmw->flags & PVMW_MIGRATION) { +#ifdef CONFIG_MIGRATION + swp_entry_t entry; + if (!is_swap_pte(*pvmw->pte)) + return false; + entry = pte_to_swp_entry(*pvmw->pte); + if (!is_migration_entry(entry)) + return false; + if (migration_entry_to_page(entry) - pvmw->page >= + hpage_nr_pages(pvmw->page)) { +
[PATCHv3 01/12] uprobes: split THPs before trying replace them
For THPs page_check_address() always fails. It leads to endless loop in uprobe_write_opcode(). Testcase with huge-tmpfs (not sure if it's possible to trigger this uprobe codepath for anon memory): mount -t debugfs none /sys/kernel/debug mount -t tmpfs -o huge=always none /mnt gcc -Wall -O2 -o /mnt/test -x c - < /sys/kernel/debug/tracing/uprobe_events echo 1 > /sys/kernel/debug/tracing/events/uprobes/enable /mnt/test Let's split THPs before trying to replace. Signed-off-by: Kirill A. Shutemov Acked-by: Rik van Riel Acked-by: Johannes Weiner Cc: Oleg Nesterov Cc: Peter Zijlstra --- kernel/events/uprobes.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index d416f3baf392..1e65c79e52a6 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c @@ -300,8 +300,8 @@ int uprobe_write_opcode(struct mm_struct *mm, unsigned long vaddr, retry: /* Read the page with vaddr into memory */ - ret = get_user_pages_remote(NULL, mm, vaddr, 1, FOLL_FORCE, &old_page, - &vma, NULL); + ret = get_user_pages_remote(NULL, mm, vaddr, 1, + FOLL_FORCE | FOLL_SPLIT, &old_page, &vma, NULL); if (ret <= 0) return ret; -- 2.11.0
[PATCHv3 05/12] mm, rmap: check all VMAs that PTE-mapped THP can be part of
Current rmap code can miss a VMA that maps PTE-mapped THP if the first suppage of the THP was unmapped from the VMA. We need to walk rmap for the whole range of offsets that THP covers, not only the first one. vma_address() also need to be corrected to check the range instead of the first subpage. Signed-off-by: Kirill A. Shutemov Acked-by: Hillf Danton --- mm/internal.h | 9 ++--- mm/rmap.c | 16 ++-- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/mm/internal.h b/mm/internal.h index 03763f5c42c5..1f90c65df7fb 100644 --- a/mm/internal.h +++ b/mm/internal.h @@ -333,12 +333,15 @@ __vma_address(struct page *page, struct vm_area_struct *vma) static inline unsigned long vma_address(struct page *page, struct vm_area_struct *vma) { - unsigned long address = __vma_address(page, vma); + unsigned long start, end; + + start = __vma_address(page, vma); + end = start + PAGE_SIZE * (hpage_nr_pages(page) - 1); /* page should be within @vma mapping range */ - VM_BUG_ON_VMA(address < vma->vm_start || address >= vma->vm_end, vma); + VM_BUG_ON_VMA(end < vma->vm_start || start >= vma->vm_end, vma); - return address; + return max(start, vma->vm_start); } #else /* !CONFIG_MMU */ diff --git a/mm/rmap.c b/mm/rmap.c index 0dff8accd629..c4bad599cc7b 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -1757,7 +1757,7 @@ static int rmap_walk_anon(struct page *page, struct rmap_walk_control *rwc, bool locked) { struct anon_vma *anon_vma; - pgoff_t pgoff; + pgoff_t pgoff_start, pgoff_end; struct anon_vma_chain *avc; int ret = SWAP_AGAIN; @@ -1771,8 +1771,10 @@ static int rmap_walk_anon(struct page *page, struct rmap_walk_control *rwc, if (!anon_vma) return ret; - pgoff = page_to_pgoff(page); - anon_vma_interval_tree_foreach(avc, &anon_vma->rb_root, pgoff, pgoff) { + pgoff_start = page_to_pgoff(page); + pgoff_end = pgoff_start + hpage_nr_pages(page) - 1; + anon_vma_interval_tree_foreach(avc, &anon_vma->rb_root, + pgoff_start, pgoff_end) { struct vm_area_struct *vma = avc->vma; unsigned long address = vma_address(page, vma); @@ -1810,7 +1812,7 @@ static int rmap_walk_file(struct page *page, struct rmap_walk_control *rwc, bool locked) { struct address_space *mapping = page_mapping(page); - pgoff_t pgoff; + pgoff_t pgoff_start, pgoff_end; struct vm_area_struct *vma; int ret = SWAP_AGAIN; @@ -1825,10 +1827,12 @@ static int rmap_walk_file(struct page *page, struct rmap_walk_control *rwc, if (!mapping) return ret; - pgoff = page_to_pgoff(page); + pgoff_start = page_to_pgoff(page); + pgoff_end = pgoff_start + hpage_nr_pages(page) - 1; if (!locked) i_mmap_lock_read(mapping); - vma_interval_tree_foreach(vma, &mapping->i_mmap, pgoff, pgoff) { + vma_interval_tree_foreach(vma, &mapping->i_mmap, + pgoff_start, pgoff_end) { unsigned long address = vma_address(page, vma); cond_resched(); -- 2.11.0
[PATCHv3 09/12] mm, uprobes: convert __replace_page() to use page_vma_mapped_walk()
For consistency, it worth converting all page_check_address() to page_vma_mapped_walk(), so we could drop the former. Signed-off-by: Kirill A. Shutemov Reviewed-by: Srikar Dronamraju --- kernel/events/uprobes.c | 22 ++ 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index 1e65c79e52a6..18c6b23edd3c 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c @@ -153,14 +153,19 @@ static int __replace_page(struct vm_area_struct *vma, unsigned long addr, struct page *old_page, struct page *new_page) { struct mm_struct *mm = vma->vm_mm; - spinlock_t *ptl; - pte_t *ptep; + struct page_vma_mapped_walk pvmw = { + .page = old_page, + .vma = vma, + .address = addr, + }; int err; /* For mmu_notifiers */ const unsigned long mmun_start = addr; const unsigned long mmun_end = addr + PAGE_SIZE; struct mem_cgroup *memcg; + VM_BUG_ON_PAGE(PageTransHuge(old_page), old_page); + err = mem_cgroup_try_charge(new_page, vma->vm_mm, GFP_KERNEL, &memcg, false); if (err) @@ -171,11 +176,11 @@ static int __replace_page(struct vm_area_struct *vma, unsigned long addr, mmu_notifier_invalidate_range_start(mm, mmun_start, mmun_end); err = -EAGAIN; - ptep = page_check_address(old_page, mm, addr, &ptl, 0); - if (!ptep) { + if (!page_vma_mapped_walk(&pvmw)) { mem_cgroup_cancel_charge(new_page, memcg, false); goto unlock; } + VM_BUG_ON_PAGE(addr != pvmw.address, old_page); get_page(new_page); page_add_new_anon_rmap(new_page, vma, addr, false); @@ -187,14 +192,15 @@ static int __replace_page(struct vm_area_struct *vma, unsigned long addr, inc_mm_counter(mm, MM_ANONPAGES); } - flush_cache_page(vma, addr, pte_pfn(*ptep)); - ptep_clear_flush_notify(vma, addr, ptep); - set_pte_at_notify(mm, addr, ptep, mk_pte(new_page, vma->vm_page_prot)); + flush_cache_page(vma, addr, pte_pfn(*pvmw.pte)); + ptep_clear_flush_notify(vma, addr, pvmw.pte); + set_pte_at_notify(mm, addr, pvmw.pte, + mk_pte(new_page, vma->vm_page_prot)); page_remove_rmap(old_page, false); if (!page_mapped(old_page)) try_to_free_swap(old_page); - pte_unmap_unlock(ptep, ptl); + page_vma_mapped_walk_done(&pvmw); if (vma->vm_flags & VM_LOCKED) munlock_vma_page(old_page); -- 2.11.0
[PATCHv3 04/12] mm: fix handling PTE-mapped THPs in page_idle_clear_pte_refs()
For PTE-mapped THP page_check_address_transhuge() is not adequate: it cannot find all relevant PTEs, only the first one.i Let's switch it to page_vma_mapped_walk(). I don't think it's subject for stable@: it's not fatal. Signed-off-by: Kirill A. Shutemov Cc: Vladimir Davydov --- mm/page_idle.c | 34 +- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/mm/page_idle.c b/mm/page_idle.c index ae11aa914e55..b0ee56c56b58 100644 --- a/mm/page_idle.c +++ b/mm/page_idle.c @@ -54,27 +54,27 @@ static int page_idle_clear_pte_refs_one(struct page *page, struct vm_area_struct *vma, unsigned long addr, void *arg) { - struct mm_struct *mm = vma->vm_mm; - pmd_t *pmd; - pte_t *pte; - spinlock_t *ptl; + struct page_vma_mapped_walk pvmw = { + .page = page, + .vma = vma, + .address = addr, + }; bool referenced = false; - if (!page_check_address_transhuge(page, mm, addr, &pmd, &pte, &ptl)) - return SWAP_AGAIN; - - if (pte) { - referenced = ptep_clear_young_notify(vma, addr, pte); - pte_unmap(pte); - } else if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) { - referenced = pmdp_clear_young_notify(vma, addr, pmd); - } else { - /* unexpected pmd-mapped page? */ - WARN_ON_ONCE(1); + while (page_vma_mapped_walk(&pvmw)) { + addr = pvmw.address; + if (pvmw.pte) { + referenced = ptep_clear_young_notify(vma, addr, + pvmw.pte); + } else if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) { + referenced = pmdp_clear_young_notify(vma, addr, + pvmw.pmd); + } else { + /* unexpected pmd-mapped page? */ + WARN_ON_ONCE(1); + } } - spin_unlock(ptl); - if (referenced) { clear_page_idle(page); /* -- 2.11.0
[PATCHv3 11/12] mm: drop page_check_address{,_transhuge}
All users are gone. Let's drop them. Signed-off-by: Kirill A. Shutemov --- include/linux/rmap.h | 36 -- mm/rmap.c| 138 --- 2 files changed, 174 deletions(-) diff --git a/include/linux/rmap.h b/include/linux/rmap.h index b76343610653..8c89e902df3e 100644 --- a/include/linux/rmap.h +++ b/include/linux/rmap.h @@ -197,42 +197,6 @@ int page_referenced(struct page *, int is_locked, int try_to_unmap(struct page *, enum ttu_flags flags); -/* - * Used by uprobes to replace a userspace page safely - */ -pte_t *__page_check_address(struct page *, struct mm_struct *, - unsigned long, spinlock_t **, int); - -static inline pte_t *page_check_address(struct page *page, struct mm_struct *mm, - unsigned long address, - spinlock_t **ptlp, int sync) -{ - pte_t *ptep; - - __cond_lock(*ptlp, ptep = __page_check_address(page, mm, address, - ptlp, sync)); - return ptep; -} - -/* - * Used by idle page tracking to check if a page was referenced via page - * tables. - */ -#ifdef CONFIG_TRANSPARENT_HUGEPAGE -bool page_check_address_transhuge(struct page *page, struct mm_struct *mm, - unsigned long address, pmd_t **pmdp, - pte_t **ptep, spinlock_t **ptlp); -#else -static inline bool page_check_address_transhuge(struct page *page, - struct mm_struct *mm, unsigned long address, - pmd_t **pmdp, pte_t **ptep, spinlock_t **ptlp) -{ - *ptep = page_check_address(page, mm, address, ptlp, 0); - *pmdp = NULL; - return !!*ptep; -} -#endif - /* Avoid racy checks */ #define PVMW_SYNC (1 << 0) /* Look for migarion entries rather than present PTEs */ diff --git a/mm/rmap.c b/mm/rmap.c index 80525820aada..8774791e2809 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -708,144 +708,6 @@ pmd_t *mm_find_pmd(struct mm_struct *mm, unsigned long address) return pmd; } -/* - * Check that @page is mapped at @address into @mm. - * - * If @sync is false, page_check_address may perform a racy check to avoid - * the page table lock when the pte is not present (helpful when reclaiming - * highly shared pages). - * - * On success returns with pte mapped and locked. - */ -pte_t *__page_check_address(struct page *page, struct mm_struct *mm, - unsigned long address, spinlock_t **ptlp, int sync) -{ - pmd_t *pmd; - pte_t *pte; - spinlock_t *ptl; - - if (unlikely(PageHuge(page))) { - /* when pud is not present, pte will be NULL */ - pte = huge_pte_offset(mm, address); - if (!pte) - return NULL; - - ptl = huge_pte_lockptr(page_hstate(page), mm, pte); - goto check; - } - - pmd = mm_find_pmd(mm, address); - if (!pmd) - return NULL; - - pte = pte_offset_map(pmd, address); - /* Make a quick check before getting the lock */ - if (!sync && !pte_present(*pte)) { - pte_unmap(pte); - return NULL; - } - - ptl = pte_lockptr(mm, pmd); -check: - spin_lock(ptl); - if (pte_present(*pte) && page_to_pfn(page) == pte_pfn(*pte)) { - *ptlp = ptl; - return pte; - } - pte_unmap_unlock(pte, ptl); - return NULL; -} - -#ifdef CONFIG_TRANSPARENT_HUGEPAGE -/* - * Check that @page is mapped at @address into @mm. In contrast to - * page_check_address(), this function can handle transparent huge pages. - * - * On success returns true with pte mapped and locked. For PMD-mapped - * transparent huge pages *@ptep is set to NULL. - */ -bool page_check_address_transhuge(struct page *page, struct mm_struct *mm, - unsigned long address, pmd_t **pmdp, - pte_t **ptep, spinlock_t **ptlp) -{ - pgd_t *pgd; - pud_t *pud; - pmd_t *pmd; - pte_t *pte; - spinlock_t *ptl; - - if (unlikely(PageHuge(page))) { - /* when pud is not present, pte will be NULL */ - pte = huge_pte_offset(mm, address); - if (!pte) - return false; - - ptl = huge_pte_lockptr(page_hstate(page), mm, pte); - pmd = NULL; - goto check_pte; - } - - pgd = pgd_offset(mm, address); - if (!pgd_present(*pgd)) - return false; - pud = pud_offset(pgd, address); - if (!pud_present(*pud)) - return false; - pmd = pmd_offset(pud, address); - - if (pmd_trans_huge(*pmd)) { - ptl = pmd_lock(mm, pmd); - if (!pmd_present(*pmd)) - goto unlock_pmd; -
[PATCHv3 03/12] mm: fix handling PTE-mapped THPs in page_referenced()
For PTE-mapped THP page_check_address_transhuge() is not adequate: it cannot find all relevant PTEs, only the first one. It means we can miss some references of the page and it can result in suboptimal decisions by vmscan. Let's switch it to page_vma_mapped_walk(). I don't think it's subject for stable@: it's not fatal. The only side effect is that THP can be swapped out when it shouldn't. Signed-off-by: Kirill A. Shutemov --- mm/rmap.c | 66 --- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/mm/rmap.c b/mm/rmap.c index 91619fd70939..0dff8accd629 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -886,45 +886,48 @@ struct page_referenced_arg { static int page_referenced_one(struct page *page, struct vm_area_struct *vma, unsigned long address, void *arg) { - struct mm_struct *mm = vma->vm_mm; struct page_referenced_arg *pra = arg; - pmd_t *pmd; - pte_t *pte; - spinlock_t *ptl; + struct page_vma_mapped_walk pvmw = { + .page = page, + .vma = vma, + .address = address, + }; int referenced = 0; - if (!page_check_address_transhuge(page, mm, address, &pmd, &pte, &ptl)) - return SWAP_AGAIN; + while (page_vma_mapped_walk(&pvmw)) { + address = pvmw.address; - if (vma->vm_flags & VM_LOCKED) { - if (pte) - pte_unmap(pte); - spin_unlock(ptl); - pra->vm_flags |= VM_LOCKED; - return SWAP_FAIL; /* To break the loop */ - } + if (vma->vm_flags & VM_LOCKED) { + page_vma_mapped_walk_done(&pvmw); + pra->vm_flags |= VM_LOCKED; + return SWAP_FAIL; /* To break the loop */ + } - if (pte) { - if (ptep_clear_flush_young_notify(vma, address, pte)) { - /* -* Don't treat a reference through a sequentially read -* mapping as such. If the page has been used in -* another mapping, we will catch it; if this other -* mapping is already gone, the unmap path will have -* set PG_referenced or activated the page. -*/ - if (likely(!(vma->vm_flags & VM_SEQ_READ))) + if (pvmw.pte) { + if (ptep_clear_flush_young_notify(vma, address, + pvmw.pte)) { + /* +* Don't treat a reference through +* a sequentially read mapping as such. +* If the page has been used in another mapping, +* we will catch it; if this other mapping is +* already gone, the unmap path will have set +* PG_referenced or activated the page. +*/ + if (likely(!(vma->vm_flags & VM_SEQ_READ))) + referenced++; + } + } else if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) { + if (pmdp_clear_flush_young_notify(vma, address, + pvmw.pmd)) referenced++; + } else { + /* unexpected pmd-mapped page? */ + WARN_ON_ONCE(1); } - pte_unmap(pte); - } else if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) { - if (pmdp_clear_flush_young_notify(vma, address, pmd)) - referenced++; - } else { - /* unexpected pmd-mapped page? */ - WARN_ON_ONCE(1); + + pra->mapcount--; } - spin_unlock(ptl); if (referenced) clear_page_idle(page); @@ -936,7 +939,6 @@ static int page_referenced_one(struct page *page, struct vm_area_struct *vma, pra->vm_flags |= vma->vm_flags; } - pra->mapcount--; if (!pra->mapcount) return SWAP_SUCCESS; /* To break the loop */ -- 2.11.0
[PATCHv3 12/12] mm: convert remove_migration_pte() to use page_vma_mapped_walk()
remove_migration_pte() also can easily be converted to page_vma_mapped_walk(). Signed-off-by: Kirill A. Shutemov --- mm/migrate.c | 104 +++ 1 file changed, 41 insertions(+), 63 deletions(-) diff --git a/mm/migrate.c b/mm/migrate.c index 87f4d0f81819..366466ed7fdc 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -193,82 +193,60 @@ void putback_movable_pages(struct list_head *l) /* * Restore a potential migration pte to a working pte entry */ -static int remove_migration_pte(struct page *new, struct vm_area_struct *vma, +static int remove_migration_pte(struct page *page, struct vm_area_struct *vma, unsigned long addr, void *old) { - struct mm_struct *mm = vma->vm_mm; + struct page_vma_mapped_walk pvmw = { + .page = old, + .vma = vma, + .address = addr, + .flags = PVMW_SYNC | PVMW_MIGRATION, + }; + struct page *new; + pte_t pte; swp_entry_t entry; - pmd_t *pmd; - pte_t *ptep, pte; - spinlock_t *ptl; - if (unlikely(PageHuge(new))) { - ptep = huge_pte_offset(mm, addr); - if (!ptep) - goto out; - ptl = huge_pte_lockptr(hstate_vma(vma), mm, ptep); - } else { - pmd = mm_find_pmd(mm, addr); - if (!pmd) - goto out; + VM_BUG_ON_PAGE(PageTail(page), page); + while (page_vma_mapped_walk(&pvmw)) { + new = page - pvmw.page->index + + linear_page_index(vma, pvmw.address); - ptep = pte_offset_map(pmd, addr); + get_page(new); + pte = pte_mkold(mk_pte(new, READ_ONCE(vma->vm_page_prot))); + if (pte_swp_soft_dirty(*pvmw.pte)) + pte = pte_mksoft_dirty(pte); - /* -* Peek to check is_swap_pte() before taking ptlock? No, we -* can race mremap's move_ptes(), which skips anon_vma lock. -*/ - - ptl = pte_lockptr(mm, pmd); - } - - spin_lock(ptl); - pte = *ptep; - if (!is_swap_pte(pte)) - goto unlock; - - entry = pte_to_swp_entry(pte); - - if (!is_migration_entry(entry) || - migration_entry_to_page(entry) != old) - goto unlock; - - get_page(new); - pte = pte_mkold(mk_pte(new, READ_ONCE(vma->vm_page_prot))); - if (pte_swp_soft_dirty(*ptep)) - pte = pte_mksoft_dirty(pte); - - /* Recheck VMA as permissions can change since migration started */ - if (is_write_migration_entry(entry)) - pte = maybe_mkwrite(pte, vma); + /* Recheck VMA as permissions can change since migration started */ + entry = pte_to_swp_entry(*pvmw.pte); + if (is_write_migration_entry(entry)) + pte = maybe_mkwrite(pte, vma); #ifdef CONFIG_HUGETLB_PAGE - if (PageHuge(new)) { - pte = pte_mkhuge(pte); - pte = arch_make_huge_pte(pte, vma, new, 0); - } + if (PageHuge(new)) { + pte = pte_mkhuge(pte); + pte = arch_make_huge_pte(pte, vma, new, 0); + } #endif - flush_dcache_page(new); - set_pte_at(mm, addr, ptep, pte); + flush_dcache_page(new); + set_pte_at(vma->vm_mm, pvmw.address, pvmw.pte, pte); - if (PageHuge(new)) { - if (PageAnon(new)) - hugepage_add_anon_rmap(new, vma, addr); + if (PageHuge(new)) { + if (PageAnon(new)) + hugepage_add_anon_rmap(new, vma, pvmw.address); + else + page_dup_rmap(new, true); + } else if (PageAnon(new)) + page_add_anon_rmap(new, vma, pvmw.address, false); else - page_dup_rmap(new, true); - } else if (PageAnon(new)) - page_add_anon_rmap(new, vma, addr, false); - else - page_add_file_rmap(new, false); + page_add_file_rmap(new, false); - if (vma->vm_flags & VM_LOCKED && !PageTransCompound(new)) - mlock_vma_page(new); + if (vma->vm_flags & VM_LOCKED && !PageTransCompound(new)) + mlock_vma_page(new); + + /* No need to invalidate - it was non-present before */ + update_mmu_cache(vma, pvmw.address, pvmw.pte); + } - /* No need to invalidate - it was non-present before */ - update_mmu_cache(vma, addr, ptep); -unlock: - pte_unmap_unlock(ptep, ptl); -out: return SWAP_AGAIN; } -- 2.11.0
[PATCHv3 00/12] Fix few rmap-related THP bugs
The patch fixes handing PTE-mapped THPs in page_referenced() and page_idle_clear_pte_refs(). To achieve that I've intrdocued new helper -- page_vma_mapped_walk() -- which replaces all page_check_address{,_transhuge}() and covers all THP cases. Patchset overview: - First patch fixes one uprobe bug (unrelated to the rest of the patchset, just spotted it at the same time); - Patches 2-5 fix handling PTE-mapped THPs in page_referenced(), page_idle_clear_pte_refs() and rmap core; - Patches 6-12 convert all page_check_address{,_transhuge}() users (plus remove_migration_pte()) to page_vma_mapped_walk() and drop unused helpers. I think the fixes are not critical enough for stable@ as they don't lead to crashes or hangs, only suboptimal behaviour. Please review and consider applying. v3: - fix page_vma_mapped_walk() breakage; - fix one more build error reported by 0-day testing; - Add few Acked-by/Reviewed-by; v2: - address feedback from Andrew; - fix build errors noticed by 0-day testing. Kirill A. Shutemov (12): uprobes: split THPs before trying replace them mm: introduce page_vma_mapped_walk() mm: fix handling PTE-mapped THPs in page_referenced() mm: fix handling PTE-mapped THPs in page_idle_clear_pte_refs() mm, rmap: check all VMAs that PTE-mapped THP can be part of mm: convert page_mkclean_one() to use page_vma_mapped_walk() mm: convert try_to_unmap_one() to use page_vma_mapped_walk() mm, ksm: convert write_protect_page() to use page_vma_mapped_walk() mm, uprobes: convert __replace_page() to use page_vma_mapped_walk() mm: convert page_mapped_in_vma() to use page_vma_mapped_walk() mm: drop page_check_address{,_transhuge} mm: convert remove_migration_pte() to use page_vma_mapped_walk() include/linux/rmap.h| 52 ++--- kernel/events/uprobes.c | 26 ++- mm/Makefile | 6 +- mm/huge_memory.c| 25 +-- mm/internal.h | 9 +- mm/ksm.c| 34 +-- mm/migrate.c| 104 - mm/page_idle.c | 34 +-- mm/page_vma_mapped.c| 218 ++ mm/rmap.c | 574 +++- 10 files changed, 573 insertions(+), 509 deletions(-) create mode 100644 mm/page_vma_mapped.c -- 2.11.0
Re: mm: deadlock between get_online_cpus/pcpu_alloc
On 29.1.2017 13:44, Dmitry Vyukov wrote: > Hello, > > I've got the following deadlock report while running syzkaller fuzzer > on f37208bc3c9c2f811460ef264909dfbc7f605a60: > > [ INFO: possible circular locking dependency detected ] > 4.10.0-rc5-next-20170125 #1 Not tainted > --- > syz-executor3/14255 is trying to acquire lock: > (cpu_hotplug.dep_map){++}, at: [] > get_online_cpus+0x37/0x90 kernel/cpu.c:239 > > but task is already holding lock: > (pcpu_alloc_mutex){+.+.+.}, at: [] > pcpu_alloc+0xbfe/0x1290 mm/percpu.c:897 > > which lock already depends on the new lock. I suspect the dependency comes from recent changes in drain_all_pages(). They were later redone (for other reasons, but nice to have another validation) in the mmots patch [1], which AFAICS is not yet in mmotm and thus linux-next. Could you try if it helps? Vlastimil [1] http://ozlabs.org/~akpm/mmots/broken-out/mm-page_alloc-use-static-global-work_struct-for-draining-per-cpu-pages.patch > > the existing dependency chain (in reverse order) is: > > -> #2 (pcpu_alloc_mutex){+.+.+.}: > > [] validate_chain kernel/locking/lockdep.c:2265 [inline] > [] __lock_acquire+0x2149/0x3430 > kernel/locking/lockdep.c:3338 > [] lock_acquire+0x2a1/0x630 kernel/locking/lockdep.c:3753 > [] __mutex_lock_common kernel/locking/mutex.c:757 [inline] > [] __mutex_lock+0x382/0x25c0 kernel/locking/mutex.c:894 > [] mutex_lock_nested+0x16/0x20 kernel/locking/mutex.c:909 > [] pcpu_alloc+0xbfe/0x1290 mm/percpu.c:897 > [] __alloc_percpu+0x24/0x30 mm/percpu.c:1076 > [] smpcfd_prepare_cpu+0x73/0xd0 kernel/smp.c:47 > [] cpuhp_invoke_callback+0x256/0x1480 kernel/cpu.c:136 > [] cpuhp_up_callbacks+0x81/0x2a0 kernel/cpu.c:425 > [] _cpu_up+0x1e3/0x2a0 kernel/cpu.c:940 > [] do_cpu_up+0x73/0xa0 kernel/cpu.c:970 > [] cpu_up+0x18/0x20 kernel/cpu.c:978 > [] smp_init+0x148/0x160 kernel/smp.c:565 > [] kernel_init_freeable+0x43e/0x695 init/main.c:1026 > [] kernel_init+0x13/0x180 init/main.c:955 > [] ret_from_fork+0x31/0x40 arch/x86/entry/entry_64.S:430 > > -> #1 (cpu_hotplug.lock){+.+.+.}: > > [] validate_chain kernel/locking/lockdep.c:2265 [inline] > [] __lock_acquire+0x2149/0x3430 > kernel/locking/lockdep.c:3338 > [] lock_acquire+0x2a1/0x630 kernel/locking/lockdep.c:3753 > [] __mutex_lock_common kernel/locking/mutex.c:757 [inline] > [] __mutex_lock+0x382/0x25c0 kernel/locking/mutex.c:894 > [] mutex_lock_nested+0x16/0x20 kernel/locking/mutex.c:909 > [] cpu_hotplug_begin+0x206/0x2e0 kernel/cpu.c:297 > [] _cpu_up+0xca/0x2a0 kernel/cpu.c:894 > [] do_cpu_up+0x73/0xa0 kernel/cpu.c:970 > [] cpu_up+0x18/0x20 kernel/cpu.c:978 > [] smp_init+0x148/0x160 kernel/smp.c:565 > [] kernel_init_freeable+0x43e/0x695 init/main.c:1026 > [] kernel_init+0x13/0x180 init/main.c:955 > [] ret_from_fork+0x31/0x40 arch/x86/entry/entry_64.S:430 > > -> #0 (cpu_hotplug.dep_map){++}: > > [] check_prev_add kernel/locking/lockdep.c:1828 [inline] > [] check_prevs_add+0xa8f/0x19f0 > kernel/locking/lockdep.c:1938 > [] validate_chain kernel/locking/lockdep.c:2265 [inline] > [] __lock_acquire+0x2149/0x3430 > kernel/locking/lockdep.c:3338 > [] lock_acquire+0x2a1/0x630 kernel/locking/lockdep.c:3753 > [] get_online_cpus+0x62/0x90 kernel/cpu.c:241 > [] drain_all_pages.part.98+0x8c/0x8f0 mm/page_alloc.c:2371 > [] drain_all_pages mm/page_alloc.c:2364 [inline] > [] __alloc_pages_direct_reclaim mm/page_alloc.c:3435 > [inline] > [] __alloc_pages_slowpath+0x966/0x23d0 mm/page_alloc.c:3773 > [] __alloc_pages_nodemask+0x8f5/0xc60 mm/page_alloc.c:3975 > [] __alloc_pages include/linux/gfp.h:426 [inline] > [] __alloc_pages_node include/linux/gfp.h:439 [inline] > [] alloc_pages_node include/linux/gfp.h:453 [inline] > [] pcpu_alloc_pages mm/percpu-vm.c:93 [inline] > [] pcpu_populate_chunk+0x1e1/0x900 mm/percpu-vm.c:282 > [] pcpu_alloc+0xe15/0x1290 mm/percpu.c:999 > [] __alloc_percpu_gfp+0x27/0x30 mm/percpu.c:1063 > [] bpf_array_alloc_percpu kernel/bpf/arraymap.c:33 [inline] > [] array_map_alloc+0x543/0x700 kernel/bpf/arraymap.c:94 > [] find_and_alloc_map kernel/bpf/syscall.c:37 [inline] > [] map_create kernel/bpf/syscall.c:228 [inline] > [] SYSC_bpf kernel/bpf/syscall.c:1040 [inline] > [] SyS_bpf+0x108d/0x27c0 kernel/bpf/syscall.c:997 > [] entry_SYSCALL_64_fastpath+0x1f/0xc2 > > other info that might help us debug this: > > Chain exists of: > cpu_hotplug.dep_map --> cpu_hotplug.lock --> pcpu_alloc_mutex > > Possible unsafe locking scenario: > >CPU0CPU1 > > lock(pcpu_alloc_mutex); >lock(cpu_hotplug.lock); >lock(pcpu_alloc_mutex); > lock(cpu_hotplug.dep_map); > > *** DEADLOCK *** > > 1 lock held by syz-executor3/14255: > #0: (pcpu_alloc_mutex){+.+.+.}, at: [] > pcpu_alloc+0xbfe/0x1290 mm/percpu.c:897 > > stack backtrace: > CPU: 1 PID: 14255 Comm: syz-executor3 Not tainted 4.10.0-rc5-next-20170125 #1 > Hardware name: Google Goo
[PATCHv3 08/12] mm, ksm: convert write_protect_page() to use page_vma_mapped_walk()
For consistency, it worth converting all page_check_address() to page_vma_mapped_walk(), so we could drop the former. Signed-off-by: Kirill A. Shutemov --- mm/ksm.c | 34 ++ 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/mm/ksm.c b/mm/ksm.c index 9ae6011a41f8..91a2eb048516 100644 --- a/mm/ksm.c +++ b/mm/ksm.c @@ -850,33 +850,35 @@ static int write_protect_page(struct vm_area_struct *vma, struct page *page, pte_t *orig_pte) { struct mm_struct *mm = vma->vm_mm; - unsigned long addr; - pte_t *ptep; - spinlock_t *ptl; + struct page_vma_mapped_walk pvmw = { + .page = page, + .vma = vma, + }; int swapped; int err = -EFAULT; unsigned long mmun_start; /* For mmu_notifiers */ unsigned long mmun_end; /* For mmu_notifiers */ - addr = page_address_in_vma(page, vma); - if (addr == -EFAULT) + pvmw.address = page_address_in_vma(page, vma); + if (pvmw.address == -EFAULT) goto out; BUG_ON(PageTransCompound(page)); - mmun_start = addr; - mmun_end = addr + PAGE_SIZE; + mmun_start = pvmw.address; + mmun_end = pvmw.address + PAGE_SIZE; mmu_notifier_invalidate_range_start(mm, mmun_start, mmun_end); - ptep = page_check_address(page, mm, addr, &ptl, 0); - if (!ptep) + if (!page_vma_mapped_walk(&pvmw)) goto out_mn; + if (WARN_ONCE(!pvmw.pte, "Unexpected PMD mapping?")) + goto out_unlock; - if (pte_write(*ptep) || pte_dirty(*ptep)) { + if (pte_write(*pvmw.pte) || pte_dirty(*pvmw.pte)) { pte_t entry; swapped = PageSwapCache(page); - flush_cache_page(vma, addr, page_to_pfn(page)); + flush_cache_page(vma, pvmw.address, page_to_pfn(page)); /* * Ok this is tricky, when get_user_pages_fast() run it doesn't * take any lock, therefore the check that we are going to make @@ -886,25 +888,25 @@ static int write_protect_page(struct vm_area_struct *vma, struct page *page, * this assure us that no O_DIRECT can happen after the check * or in the middle of the check. */ - entry = ptep_clear_flush_notify(vma, addr, ptep); + entry = ptep_clear_flush_notify(vma, pvmw.address, pvmw.pte); /* * Check that no O_DIRECT or similar I/O is in progress on the * page */ if (page_mapcount(page) + 1 + swapped != page_count(page)) { - set_pte_at(mm, addr, ptep, entry); + set_pte_at(mm, pvmw.address, pvmw.pte, entry); goto out_unlock; } if (pte_dirty(entry)) set_page_dirty(page); entry = pte_mkclean(pte_wrprotect(entry)); - set_pte_at_notify(mm, addr, ptep, entry); + set_pte_at_notify(mm, pvmw.address, pvmw.pte, entry); } - *orig_pte = *ptep; + *orig_pte = *pvmw.pte; err = 0; out_unlock: - pte_unmap_unlock(ptep, ptl); + page_vma_mapped_walk_done(&pvmw); out_mn: mmu_notifier_invalidate_range_end(mm, mmun_start, mmun_end); out: -- 2.11.0
Re: [PATCH v2 03/25] power: supply: axp20x_usb_power: use IIO channels when available
Hi, On Fri, Jan 27, 2017 at 09:54:36AM +0100, Quentin Schulz wrote: > The X-Powers AXP20X PMIC exposes the current current and voltage > measures via an internal ADC. > > This adds the possibility to read IIO channels directly for processed > values rather than reading the registers and computing the value. > > For backward compatibility purpose, if the IIO driver is not compiled, > this driver will fall back on previous behaviour which is direct > register readings. > > Signed-off-by: Quentin Schulz I queued this into power-supply's for next branch. -- Sebastian signature.asc Description: PGP signature
[PATCHv3 10/12] mm: convert page_mapped_in_vma() to use page_vma_mapped_walk()
For consistency, it worth converting all page_check_address() to page_vma_mapped_walk(), so we could drop the former. Signed-off-by: Kirill A. Shutemov Acked-by: Hillf Danton --- mm/page_vma_mapped.c | 30 ++ mm/rmap.c| 26 -- 2 files changed, 30 insertions(+), 26 deletions(-) diff --git a/mm/page_vma_mapped.c b/mm/page_vma_mapped.c index bbd2a39e985d..dc4756f878be 100644 --- a/mm/page_vma_mapped.c +++ b/mm/page_vma_mapped.c @@ -186,3 +186,33 @@ next_pte: do { } } } + +/** + * page_mapped_in_vma - check whether a page is really mapped in a VMA + * @page: the page to test + * @vma: the VMA to test + * + * Returns 1 if the page is mapped into the page tables of the VMA, 0 + * if the page is not mapped into the page tables of this VMA. Only + * valid for normal file or anonymous VMAs. + */ +int page_mapped_in_vma(struct page *page, struct vm_area_struct *vma) +{ + struct page_vma_mapped_walk pvmw = { + .page = page, + .vma = vma, + .flags = PVMW_SYNC, + }; + unsigned long start, end; + + start = __vma_address(page, vma); + end = start + PAGE_SIZE * (hpage_nr_pages(page) - 1); + + if (unlikely(end < vma->vm_start || start >= vma->vm_end)) + return 0; + pvmw.address = max(start, vma->vm_start); + if (!page_vma_mapped_walk(&pvmw)) + return 0; + page_vma_mapped_walk_done(&pvmw); + return 1; +} diff --git a/mm/rmap.c b/mm/rmap.c index 11668fb881d8..80525820aada 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -756,32 +756,6 @@ pte_t *__page_check_address(struct page *page, struct mm_struct *mm, return NULL; } -/** - * page_mapped_in_vma - check whether a page is really mapped in a VMA - * @page: the page to test - * @vma: the VMA to test - * - * Returns 1 if the page is mapped into the page tables of the VMA, 0 - * if the page is not mapped into the page tables of this VMA. Only - * valid for normal file or anonymous VMAs. - */ -int page_mapped_in_vma(struct page *page, struct vm_area_struct *vma) -{ - unsigned long address; - pte_t *pte; - spinlock_t *ptl; - - address = __vma_address(page, vma); - if (unlikely(address < vma->vm_start || address >= vma->vm_end)) - return 0; - pte = page_check_address(page, vma->vm_mm, address, &ptl, 1); - if (!pte) /* the page is not in this mm */ - return 0; - pte_unmap_unlock(pte, ptl); - - return 1; -} - #ifdef CONFIG_TRANSPARENT_HUGEPAGE /* * Check that @page is mapped at @address into @mm. In contrast to -- 2.11.0
Re: [PATCH v9 6/8] drivers:input:ads7846(+tsc2046): fix spi module table
On Sun, Jan 29, 2017 at 09:39:39AM +0100, H. Nikolaus Schaller wrote: > Hi Dmitry, > > > Am 28.01.2017 um 20:35 schrieb Dmitry Torokhov : > > > > On Wed, Dec 28, 2016 at 03:53:21PM +0100, H. Nikolaus Schaller wrote: > >> Fix module table so that the driver is loaded if compiled > >> as module and requested by DT. > >> > > > > I believe I already replied to a similar patch: we alreadyhave necessary > > aliases in this driver, we need to fix module loading to use it. > > Yes, you did comment on [PATCH v6 7/8] (19 Nov 2016): > > >> We really need to fix it between spi/i23c core and module utils instead > >> of keeping adding duplicate IDs all over drivers. We already have OF > >> module device table containing the same data, we should be able to use > >> it. > > And Javier Martinez Canillas replied (23 Nov 2016): > > > Agreed, unfortunately until the I2C and SPI core are changed to properly > > report OF modaliases, we will have to keep adding these duplicated IDs. > > > > And changing the I2C and SPI core isn't trivial since it could break a > > lot of drivers that rely on a platform modalias being reported (i.e: no > > OF device IDs present in the drivers even when are registered via DT). > > Therefore I didn't see a need to change it. I agree that changing I2C and SPI core is not trivial, however this is no reason for piling up workarounds in all drivers. Are you seriously advocating going though *every* driver and copying OF data into I2C/SPI instead of doing the right thing and fixing the root of the issue? Thanks. -- Dmitry
[PATCH v13 0/5] mxs-lradc: Split driver into MFD
Split existing driver mxs-lradc into MFD with touchscreen and IIO part. Tested on I.MX28 Ksenija Stanojevic (5): mfd: mxs-lradc: Add support for mxs-lradc MFD iio: adc: mxs-lradc: Add support for adc driver input: touchscreen: mxs-lradc: Add support for touchscreen iio: adc: mxs-lradc: Remove driver mfd: Move binding document .../bindings/{iio/adc => mfd}/mxs-lradc.txt|0 drivers/iio/adc/Kconfig| 27 +- drivers/iio/adc/Makefile |2 +- drivers/iio/adc/mxs-lradc-adc.c| 843 ++ drivers/iio/adc/mxs-lradc.c| 1750 drivers/input/touchscreen/Kconfig | 10 + drivers/input/touchscreen/Makefile |1 + drivers/input/touchscreen/mxs-lradc-ts.c | 718 drivers/mfd/Kconfig| 17 + drivers/mfd/Makefile |1 + drivers/mfd/mxs-lradc.c| 264 +++ include/linux/mfd/mxs-lradc.h | 187 +++ 12 files changed, 2055 insertions(+), 1765 deletions(-) rename Documentation/devicetree/bindings/{iio/adc => mfd}/mxs-lradc.txt (100%) create mode 100644 drivers/iio/adc/mxs-lradc-adc.c delete mode 100644 drivers/iio/adc/mxs-lradc.c create mode 100644 drivers/input/touchscreen/mxs-lradc-ts.c create mode 100644 drivers/mfd/mxs-lradc.c create mode 100644 include/linux/mfd/mxs-lradc.h -- 1.9.1
[PATCH v13 3/5] input: touchscreen: mxs-lradc: Add support for touchscreen
Add 4-wire/5-wire touchscreen controller. Signed-off-by: Ksenija Stanojevic --- Changes in v13: - use struct state_info instead of using functions for doing conditionals on every operation. - call mxs_lradc_ts_stop() before requesting interrupts. Changes in v12: - none Changes in v11: - use dev_get_drvdata instead dev_get_platdata - use writel instead mxs_lradc_reg_* functions Changes in v10: - none Changes in v9: - none Changes in v8: - rebase onto 4.9-rc1 Changes in v7: - remove touch_ret variable in probe and use ret instead - make error check on of_property_read_u32 in probe Changes in v6: - update copyright Changes in v5: - add field void __iomem *base to struct mxs_lradc_adc - change arguments in all functions for accessing I/O memory to follow the previous change. - use devm_ioremap for mapping I/O memory Changes in v4: - update copyright - use platform_get_irq_byname - use irq_of_parse_and_map Changes in v3: - make buffer large enough for timestamps - remove unnecessary blank lines Changes in v2: - improve commit message - do not change spacing in Kconfig - impove formating - remove wrapper show_scale_avail - use correct syntax for comments - use devm_iio_trigger_alloc - do not allocate buffer dynamically - use iio_device_claim_*_mode helpers - add spinlock in struct mxs_lradc_ts to enable locking in interrupt handler - only grab irqs that are relevant to adc - remove blank line at the end of the file - change licence to GPL - add copyright drivers/input/touchscreen/Kconfig| 10 + drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/mxs-lradc-ts.c | 718 +++ 3 files changed, 729 insertions(+) create mode 100644 drivers/input/touchscreen/mxs-lradc-ts.c diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index efca013..8ff915e 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -841,6 +841,16 @@ config TOUCHSCREEN_USB_COMPOSITE To compile this driver as a module, choose M here: the module will be called usbtouchscreen. +config TOUCHSCREEN_MXS_LRADC + tristate "Freescale i.MX23/i.MX28 LRADC touchscreen" + depends on MFD_MXS_LRADC + help + Say Y here if you have a touchscreen connected to the low-resolution + analog-to-digital converter (LRADC) on an i.MX23 or i.MX28 processor. + + To compile this driver as a module, choose M here: the module will be + called mxs-lradc-ts. + config TOUCHSCREEN_MX25 tristate "Freescale i.MX25 touchscreen input driver" depends on MFD_MX25_TSADC diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 81b8645..97e1bb7 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -46,6 +46,7 @@ obj-$(CONFIG_TOUCHSCREEN_INTEL_MID) += intel-mid-touch.o obj-$(CONFIG_TOUCHSCREEN_IPROC)+= bcm_iproc_tsc.o obj-$(CONFIG_TOUCHSCREEN_LPC32XX) += lpc32xx_ts.o obj-$(CONFIG_TOUCHSCREEN_MAX11801) += max11801_ts.o +obj-$(CONFIG_TOUCHSCREEN_MXS_LRADC) += mxs-lradc-ts.o obj-$(CONFIG_TOUCHSCREEN_MX25) += fsl-imx25-tcq.o obj-$(CONFIG_TOUCHSCREEN_MC13783) += mc13783_ts.o obj-$(CONFIG_TOUCHSCREEN_MCS5000) += mcs5000_ts.o diff --git a/drivers/input/touchscreen/mxs-lradc-ts.c b/drivers/input/touchscreen/mxs-lradc-ts.c new file mode 100644 index 000..2cea025 --- /dev/null +++ b/drivers/input/touchscreen/mxs-lradc-ts.c @@ -0,0 +1,718 @@ +/* + * Freescale MXS LRADC touchscreen driver + * + * Copyright (c) 2012 DENX Software Engineering, GmbH. + * Copyright (c) 2017 Ksenija Stanojevic + * + * Authors: + * Marek Vasut + * Ksenija Stanojevic + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +const char *mxs_lradc_ts_irq_names[] = { + "mxs-lradc-touchscreen", + "mxs-lradc-channel6", + "mxs-lradc-channel7", +}; + +/* + * Touchscreen handling + */ +enum mxs_lradc_ts_plate { + LRADC_TOUCH = 0, + LRADC_SAMPLE_X, + LRADC_SAMPLE_Y, + LRADC_SAMPLE_PRESSURE, + LRADC_SAMPLE_VALID, +}; + +struct mxs_lradc_ts { + struct mxs_lradc*lradc; + struct device *dev; + + void __iomem*base; + /* +* When the touchscreen is enabled, we give it two pr
[PATCH v13 5/5] mfd: Move binding document
The bindings, which are now used in MFD, need also to be documented in the MFD binding document. Signed-off-by: Ksenija Stanojevic Reviewed-by: Marek Vasut Acked-by: Lee Jones --- Changes in v13: - none Changes in v12: - none Changes in v11: - none Changes in v10: - none Changes in v9: - format patch using -M option Changes in v8: - rebase onto 4.9-rc1 Changes in v7: - add to the patchset Documentation/devicetree/bindings/{iio/adc => mfd}/mxs-lradc.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Documentation/devicetree/bindings/{iio/adc => mfd}/mxs-lradc.txt (100%) diff --git a/Documentation/devicetree/bindings/iio/adc/mxs-lradc.txt b/Documentation/devicetree/bindings/mfd/mxs-lradc.txt similarity index 100% rename from Documentation/devicetree/bindings/iio/adc/mxs-lradc.txt rename to Documentation/devicetree/bindings/mfd/mxs-lradc.txt -- 1.9.1
[PATCH v13 1/5] mfd: mxs-lradc: Add support for mxs-lradc MFD
Add core files for low resolution analog-to-digital converter (mxs-lradc) MFD driver. Signed-off-by: Ksenija Stanojevic Acked-by: Lee Jones --- Changes in v13: - none Changes in v12: - use BIT macro Changes in v11: - create static struct mfd_cells - don't set platform data in mfd cells, set driver data instead - remove mxs_lradc_reg_* functions, use writel function instead Changes in v10: - fetch base address from DT - add a NULL check for of_match_device Changes in v9: - improve commit message. Changes in v8: - rebase onto 4.9-rc1 Changes in v7: - define macros ADC_CELL and TSC_CELL - remove one cell and dynamically set them in the switch() - fail in the touchscreen driver instead of mfd driver if hardware doesn't contain a touchscreen Changes in v6: - update copyright - add kernel-doc header for struct mxs-lradc - add error message - change EINVAL to ENODEV - use PLATFORM_DEVID_NONE instead -1 - cosmetic fixes Changes in v5: - use DEFINE_RES_MEM - don't pass ioreammaped adress to platform cells - move comment outside of struct mxs_lradc - change type of argument in mxs_lradc_reg_set, mxs_lradc_reg_clear, mxs_lradc_reg_wrt (struct mxs_lradc * -> void __iomem *) Changes in v4: - update copyright - use DEFINE_RES_IRQ_NAMED - remove mxs_lradc_add_device function - use struct mfd_cell in static form - improve spacing - remove unnecessary comment - remove platform_get_irq - remove touch_ret and use ret instead - rename use_touchscreen to touchscreen_wire - use goto statements - remove irq[13], irq_count and irq_name from struct mxs_lradc - remove all defines from inside the struct definition Changes in v3: - add note to commit message - move switch statement into if(touch_ret == 0) branch - add MODULE_AUTHOR Changes in v2: - do not change spacing in Kconfig - make struct mfd_cell part of struct mxs_lradc - use switch instead of if in mxs_lradc_irq_mask - use only necessary header files in mxs_lradc.h - use devm_mfd_add_device - use separate function to register mfd device - change licence to GPL - add copyright drivers/mfd/Kconfig | 17 +++ drivers/mfd/Makefile | 1 + drivers/mfd/mxs-lradc.c | 264 ++ include/linux/mfd/mxs-lradc.h | 187 ++ 4 files changed, 469 insertions(+) create mode 100644 drivers/mfd/mxs-lradc.c create mode 100644 include/linux/mfd/mxs-lradc.h diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 4ce3b6f..1bb80f7 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -343,6 +343,23 @@ config MFD_MC13XXX_I2C help Select this if your MC13xxx is connected via an I2C bus. +config MFD_MXS_LRADC + tristate "Freescale i.MX23/i.MX28 LRADC" + depends on ARCH_MXS || COMPILE_TEST + select MFD_CORE + select STMP_DEVICE + help + Say yes here to build support for the Low Resolution + Analog-to-Digital Converter (LRADC) found on the i.MX23 and i.MX28 + processors. This driver provides common support for accessing the + device, additional drivers must be enabled in order to use the + functionality of the device: + mxs-lradc-adc for ADC readings + mxs-lradc-ts for touchscreen support + + This driver can also be built as a module. If so, the module will be + called mxs-lradc. + config MFD_MX25_TSADC tristate "Freescale i.MX25 integrated Touchscreen and ADC unit" select REGMAP_MMIO diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index dda4d4f..29a8405 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -212,3 +212,4 @@ obj-$(CONFIG_MFD_MT6397)+= mt6397-core.o obj-$(CONFIG_MFD_ALTERA_A10SR) += altera-a10sr.o obj-$(CONFIG_MFD_SUN4I_GPADC) += sun4i-gpadc.o +obj-$(CONFIG_MFD_MXS_LRADC) += mxs-lradc.o diff --git a/drivers/mfd/mxs-lradc.c b/drivers/mfd/mxs-lradc.c new file mode 100644 index 000..2ae8487 --- /dev/null +++ b/drivers/mfd/mxs-lradc.c @@ -0,0 +1,264 @@ +/* + * Freescale MXS Low Resolution Analog-to-Digital Converter driver + * + * Copyright (c) 2012 DENX Software Engineering, GmbH. + * Copyright (c) 2017 Ksenija Stanojevic + * + * Authors: + * Marek Vasut + * Ksenija Stanojevic + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ADC_CELL 0 +#define TSC_
[PATCH v13 4/5] iio: adc: mxs-lradc: Remove driver
Since the driver has been split into mfd there is no reason for it to stay, so remove it. Signed-off-by: Ksenija Stanojevic Acked-by: Jonathan Cameron Reviewed-by: Marek Vasut --- Changes in v13: - none Changes in v12: - none Changes in v11: - none Changes in v10: - none Changes in v9: - none Changes in v8: - rebase onto 4.9-rc1 Changes in v7: - none Changes in v6: - none Changes in v5: - none Changes in v4: - none Changes in v3: - none Changes in v2: - add to the patchset drivers/iio/adc/Kconfig | 14 - drivers/iio/adc/Makefile|1 - drivers/iio/adc/mxs-lradc.c | 1750 --- 3 files changed, 1765 deletions(-) delete mode 100644 drivers/iio/adc/mxs-lradc.c diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 6784ab7..8ecdcae 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -412,20 +412,6 @@ config MEN_Z188_ADC This driver can also be built as a module. If so, the module will be called men_z188_adc. -config MXS_LRADC -tristate "Freescale i.MX23/i.MX28 LRADC" -depends on (ARCH_MXS || COMPILE_TEST) && HAS_IOMEM -depends on INPUT -select STMP_DEVICE -select IIO_BUFFER -select IIO_TRIGGERED_BUFFER -help - Say yes here to build support for i.MX23/i.MX28 LRADC convertor - built into these chips. - - To compile this driver as a module, choose M here: the - module will be called mxs-lradc. - config NAU7802 tristate "Nuvoton NAU7802 ADC driver" depends on I2C diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index ad19ba6..fa94669 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -39,7 +39,6 @@ obj-$(CONFIG_MCP3422) += mcp3422.o obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o obj-$(CONFIG_MXS_LRADC_ADC) += mxs-lradc-adc.o -obj-$(CONFIG_MXS_LRADC) += mxs-lradc.o obj-$(CONFIG_NAU7802) += nau7802.o obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o diff --git a/drivers/iio/adc/mxs-lradc.c b/drivers/iio/adc/mxs-lradc.c deleted file mode 100644 index b84d37c..000 --- a/drivers/iio/adc/mxs-lradc.c +++ /dev/null @@ -1,1750 +0,0 @@ -/* - * Freescale MXS LRADC driver - * - * Copyright (c) 2012 DENX Software Engineering, GmbH. - * Marek Vasut - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#define DRIVER_NAME"mxs-lradc" - -#define LRADC_MAX_DELAY_CHANS 4 -#define LRADC_MAX_MAPPED_CHANS 8 -#define LRADC_MAX_TOTAL_CHANS 16 - -#define LRADC_DELAY_TIMER_HZ 2000 - -/* - * Make this runtime configurable if necessary. Currently, if the buffered mode - * is enabled, the LRADC takes LRADC_DELAY_TIMER_LOOP samples of data before - * triggering IRQ. The sampling happens every (LRADC_DELAY_TIMER_PER / 2000) - * seconds. The result is that the samples arrive every 500mS. - */ -#define LRADC_DELAY_TIMER_PER 200 -#define LRADC_DELAY_TIMER_LOOP 5 - -/* - * Once the pen touches the touchscreen, the touchscreen switches from - * IRQ-driven mode to polling mode to prevent interrupt storm. The polling - * is realized by worker thread, which is called every 20 or so milliseconds. - * This gives the touchscreen enough fluency and does not strain the system - * too much. - */ -#define LRADC_TS_SAMPLE_DELAY_MS 5 - -/* - * The LRADC reads the following amount of samples from each touchscreen - * channel and the driver then computes average of these. - */ -#define LRADC_TS_SAMPLE_AMOUNT 4 - -enum mxs_lradc_id { - IMX23_LRADC, - IMX28_LRADC, -}; - -static const char * const mx23_lradc_irq_names[] = { - "mxs-lradc-touchscreen", - "mxs-lradc-channel0", - "mxs-lradc-channel1", - "mxs-lradc-channel2", - "mxs-lradc-channel3", - "mxs-lradc-channel4", - "mxs-lradc-channel5", - "mxs-lradc-channel6", - "mxs-lradc-channel7", -}; - -static const char * const mx28_lradc_irq_names[] = { - "mxs-lradc-touchscreen", - "mxs-lradc-thresh0", - "mxs-lradc-thresh1", - "mxs-lradc-channel0", - "mxs-lradc-channel1", - "mxs-lradc-channel2", -
[PATCH v13 2/5] iio: adc: mxs-lradc: Add support for adc driver
Add support for sixteen-channel 12-bit resolution ADC and its functions, which include general-purpose ADC readings, battery voltage measurement, and die temperature measurement. Signed-off-by: Ksenija Stanojevic Reviewed-by: Jonathan Cameron Reviewed-by: Marek Vasut --- Changes in v13: - none Changes in v12: - none Changes in v11: - use dev_get_drvdata instead dev_get_platdata - use writel instead mxs_lradc_reg_* functions Changes in v10: - none Changes in v9: - none Changes in v8: - rebase onto 4.9-rc1 Changes in v7: - none Changes in v6: - update copyright Changes in v5: - add field void __iomem *base to struct mxs_lradc_adc - change arguments in all functions for accessing I/O memory to follow the previous change. - use devm_ioremap for mapping I/O memory Changes in v4: - update copyright - use platform_get_irq_byname - use irq_of_parse_and_map Changes in v3: - make buffer large enough for timestamps - remove unnecessary blank lines Changes in v2: - improve commit message - do not change spacing in Kconfig - impove formating - remove wrapper show_scale_avail - use correct syntax for comments - use devm_iio_trigger_alloc - do not allocate buffer dynamically - use iio_device_claim_*_mode helpers - add spinlock in struct mxs_lradc_ts to enable locking in interrupt handler - only grab irqs that are relevant to adc - remove blank line at the end of the file - change licence to GPL - add copyright drivers/iio/adc/Kconfig | 13 + drivers/iio/adc/Makefile| 1 + drivers/iio/adc/mxs-lradc-adc.c | 843 3 files changed, 857 insertions(+) create mode 100644 drivers/iio/adc/mxs-lradc-adc.c diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 1a73e03..6784ab7 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -229,6 +229,19 @@ config EXYNOS_ADC To compile this driver as a module, choose M here: the module will be called exynos_adc. +config MXS_LRADC_ADC + tristate "Freescale i.MX23/i.MX28 LRADC ADC" + depends on MFD_MXS_LRADC + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + Say yes here to build support for the ADC functions of the + i.MX23/i.MX28 LRADC. This includes general-purpose ADC readings, + battery voltage measurement, and die temperature measurement. + + This driver can also be built as a module. If so, the module will be + called mxs-lradc-adc. + config FSL_MX25_ADC tristate "Freescale MX25 ADC driver" depends on MFD_MX25_TSADC diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 9475fd5..ad19ba6 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_MCP320X) += mcp320x.o obj-$(CONFIG_MCP3422) += mcp3422.o obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o +obj-$(CONFIG_MXS_LRADC_ADC) += mxs-lradc-adc.o obj-$(CONFIG_MXS_LRADC) += mxs-lradc.o obj-$(CONFIG_NAU7802) += nau7802.o obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o diff --git a/drivers/iio/adc/mxs-lradc-adc.c b/drivers/iio/adc/mxs-lradc-adc.c new file mode 100644 index 000..cc8d6af --- /dev/null +++ b/drivers/iio/adc/mxs-lradc-adc.c @@ -0,0 +1,843 @@ +/* + * Freescale MXS LRADC ADC driver + * + * Copyright (c) 2012 DENX Software Engineering, GmbH. + * Copyright (c) 2017 Ksenija Stanojevic + * + * Authors: + * Marek Vasut + * Ksenija Stanojevic + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/* + * Make this runtime configurable if necessary. Currently, if the buffered mode + * is enabled, the LRADC takes LRADC_DELAY_TIMER_LOOP samples of data before + * triggering IRQ. The sampling happens every (LRADC_DELAY_TIMER_PER / 2000) + * seconds. The result is that the samples arrive every 500mS. + */ +#define LRADC_DELAY_TIMER_PER 200 +#define LRADC_DELAY_TIMER_LOOP 5 + +#define VREF_MV_BASE 1850 + +const char *mx23_lradc_adc_irq_names[] = { + "mxs-lradc-channel0", + "mxs-lradc-channel1", + "mxs-lradc-channel2", + "mxs-lradc-channel3", + "mxs-lradc-channel4", + "mxs-lradc-channel5", +}; + +const char *mx28_lradc_adc_irq_names[] = { + "mxs-lradc-thresh0", + "mxs-lradc-thresh1", +
[PATCH v2] clk: add more managed APIs
When converting a driver to managed resources it is desirable to be able to manage all resources in the same fashion. This change allows managing clocks in the same way we manage many other resources. This adds the following managed APIs: - devm_clk_prepare()/devm_clk_unprepare(); - devm_clk_prepare_enable()/devm_clk_disable_unprepare(). Signed-off-by: Dmitry Torokhov --- v2: dropped devm_clk_enable() and devm_clk_disable() drivers/clk/clk-devres.c | 98 +++--- include/linux/clk.h | 68 2 files changed, 134 insertions(+), 32 deletions(-) diff --git a/drivers/clk/clk-devres.c b/drivers/clk/clk-devres.c index 3a218c3a06ae..2ff94ffe11d3 100644 --- a/drivers/clk/clk-devres.c +++ b/drivers/clk/clk-devres.c @@ -9,30 +9,20 @@ #include #include -static void devm_clk_release(struct device *dev, void *res) +static int devm_clk_create_devres(struct device *dev, struct clk *clk, + void (*release)(struct device *, void *)) { - clk_put(*(struct clk **)res); -} + struct clk **ptr; -struct clk *devm_clk_get(struct device *dev, const char *id) -{ - struct clk **ptr, *clk; - - ptr = devres_alloc(devm_clk_release, sizeof(*ptr), GFP_KERNEL); + ptr = devres_alloc(release, sizeof(*ptr), GFP_KERNEL); if (!ptr) - return ERR_PTR(-ENOMEM); + return -ENOMEM; - clk = clk_get(dev, id); - if (!IS_ERR(clk)) { - *ptr = clk; - devres_add(dev, ptr); - } else { - devres_free(ptr); - } + *ptr = clk; + devres_add(dev, ptr); - return clk; + return 0; } -EXPORT_SYMBOL(devm_clk_get); static int devm_clk_match(struct device *dev, void *res, void *data) { @@ -44,31 +34,75 @@ static int devm_clk_match(struct device *dev, void *res, void *data) return *c == data; } -void devm_clk_put(struct device *dev, struct clk *clk) +#define DEFINE_DEVM_CLK_DESTROY_OP(destroy_op) \ +static void devm_##destroy_op##_release(struct device *dev, void *res) \ +{ \ + destroy_op(*(struct clk **)res);\ +} \ + \ +void devm_##destroy_op(struct device *dev, struct clk *clk)\ +{ \ + WARN_ON(devres_release(dev, devm_##destroy_op##_release,\ + devm_clk_match, clk)); \ +} \ +EXPORT_SYMBOL(devm_##destroy_op) + +#define DEFINE_DEVM_CLK_OP(create_op, destroy_op) \ +DEFINE_DEVM_CLK_DESTROY_OP(destroy_op); \ +int devm_##create_op(struct device *dev, struct clk *clk) \ +{ \ + int error; \ + \ + error = create_op(clk); \ + if (error) \ + return error; \ + \ + error = devm_clk_create_devres(dev, clk,\ + devm_##destroy_op##_release); \ + if (error) {\ + destroy_op(clk);\ + return error; \ + } \ + \ + return 0; \ +} \ +EXPORT_SYMBOL(devm_##create_op) + +DEFINE_DEVM_CLK_DESTROY_OP(clk_put); +DEFINE_DEVM_CLK_OP(clk_prepare, clk_unprepare); +DEFINE_DEVM_CLK_OP(clk_prepare_enable, clk_disable_unprepare); + +struct clk *devm_clk_get(struct device *dev, const char *id) { - int ret; + struct clk *clk; + int error; - ret = devres_release(dev, devm_clk_release, devm_clk_match, clk); + clk = clk_get(dev, id); + if (!IS_ERR(clk)) { + error = devm_clk_create_devres(dev, clk, devm_clk_put_release); + if (error) { + clk_put(clk); + return ERR_PTR(error); + } + } - WARN_ON(ret); + return clk; }