Re: [PATCH 4.14 000/164] 4.14.6-stable review
On Wed, Dec 13, 2017 at 07:48:43AM +0100, Marek Szyprowski wrote: > Hi Shuah and Greg, > > On 2017-12-12 15:47, Shuah Khan wrote: > > On 12/12/2017 05:43 AM, Greg Kroah-Hartman wrote: > > > This is the start of the stable review cycle for the 4.14.6 release. > > > There are 164 patches in this series, all will be posted as a response > > > to this one. If anyone has any issues with these being applied, please > > > let me know. > > > > > > Responses should be made by Thu Dec 14 12:34:08 UTC 2017. > > > Anything received after that time might be too late. > > > > > > The whole patch series can be found in one patch at: > > > kernel.org/pub/linux/kernel/v4.x/stable-review/patch-4.14.6-rc1.gz > > > or in the git tree and branch at: > > > > > > git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git > > > linux-4.14.y > > > and the diffstat can be found below. > > > > > > thanks, > > > > > > greg k-h > > > > > > Daniel Vetter> > > drm: safely free connectors from connector_iter > > > > > > Marek Szyprowski > > > drm/bridge: analogix dp: Fix runtime PM state in get_modes() callback > > > > > The above two patches have been found to be the cause of boot hang on > > exynos Peach Pi(t) chromebooks. > > > > I am adding Daniel and Marek to the thread. > > The deadlock is caused by the Daniels patch. My patch only changes the order > of device initialization what might hide or reveal bug related to Daniels > patch. So should I revert Daniel's patch? Or is there already a fix for that in Linus's tree? thanks, greg k-h
Re: [PATCH 4.14 000/164] 4.14.6-stable review
On Wed, Dec 13, 2017 at 07:48:43AM +0100, Marek Szyprowski wrote: > Hi Shuah and Greg, > > On 2017-12-12 15:47, Shuah Khan wrote: > > On 12/12/2017 05:43 AM, Greg Kroah-Hartman wrote: > > > This is the start of the stable review cycle for the 4.14.6 release. > > > There are 164 patches in this series, all will be posted as a response > > > to this one. If anyone has any issues with these being applied, please > > > let me know. > > > > > > Responses should be made by Thu Dec 14 12:34:08 UTC 2017. > > > Anything received after that time might be too late. > > > > > > The whole patch series can be found in one patch at: > > > kernel.org/pub/linux/kernel/v4.x/stable-review/patch-4.14.6-rc1.gz > > > or in the git tree and branch at: > > > > > > git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git > > > linux-4.14.y > > > and the diffstat can be found below. > > > > > > thanks, > > > > > > greg k-h > > > > > > Daniel Vetter > > > drm: safely free connectors from connector_iter > > > > > > Marek Szyprowski > > > drm/bridge: analogix dp: Fix runtime PM state in get_modes() callback > > > > > The above two patches have been found to be the cause of boot hang on > > exynos Peach Pi(t) chromebooks. > > > > I am adding Daniel and Marek to the thread. > > The deadlock is caused by the Daniels patch. My patch only changes the order > of device initialization what might hide or reveal bug related to Daniels > patch. So should I revert Daniel's patch? Or is there already a fix for that in Linus's tree? thanks, greg k-h
Re: [rtc-linux] Re: [PATCH v4 0/2] Add support for cros-ec-rtc driver.
On Tue, 12 Dec 2017, Alexandre Belloni wrote: > On 12/12/2017 at 17:05:37 +0100, Alexandre Belloni wrote: > > On 12/12/2017 at 16:41:39 +0100, Enric Balletbo Serra wrote: > > > + Alessandro Zummo > > > + Alexandre Belloni > > > > > > 2017-11-10 22:55 GMT+01:00 Enric Balletbo i Serra > > >: > > > > Dear all, > > > > > > > > This is an attempt to revive some patches from that [1] patchset, some > > > > of them are still under discussion but I think there is no reason to not > > > > have the other two in this fourth version to land upstream meanwhile we > > > > discuss about the others. > > > > > > > > [1] https://lkml.org/lkml/2017/7/12/182 > > > > > > > > Changes since v3: > > > > * Rebased an retested with current mainline using a Samsung Chromebook > > > > Plus > > > > * Removed from patchset > > > > * 1/4 mfd: cros_ec: Get rid of cros_ec_check_features from > > > > cros_ec_dev. > > > > * 4/4 mfd: cros_ec: add RTC as mfd subdevice. > > > > > > > > Changes since v2: > > > > - Rebase on top of mainline. > > > > - Removed patch 'mfd: cros-ec: Fix host command buffer size' from series > > > > as was already picked. > > > > > > > > Changes since v1: > > > > - Removed patch 'iio: cros_ec_sensors: Fix return value to get raw and > > > > calibbias data' from series as was already picked. > > > > - Removed patch 'iio: cros_ec_sensors: Fix return value to get raw and > > > > calibbias data' from series as was already picked. > > > > - Patch 2/5: Acked-by: Jonathan Cameron <***@kernel.org> > > > > > > > > Best regards, > > > > > > > > Enric > > > > > > > > Stephen Barber (2): > > > > mfd: cros_ec: Introduce RTC commands and events definitions. > > > > rtc: cros-ec: add cros-ec-rtc driver. > > > > > > > > drivers/rtc/Kconfig | 10 + > > > > drivers/rtc/Makefile | 1 + > > > > drivers/rtc/rtc-cros-ec.c| 413 > > > > +++ > > > > include/linux/mfd/cros_ec_commands.h | 8 + > > > > 4 files changed, 432 insertions(+) > > > > create mode 100644 drivers/rtc/rtc-cros-ec.c > > > > > > > > > > > > > > Sorry, I just noticed that my script to add the email recipients > > > failed and I did not add the RTC maintainers :( So this is a gentle > > > ping cc'ing the maintainers to take in consideration these patches. If > > > you want I resend or something else just let me know please. > > > > > > > I don't remember the specifics but I think the patches have the > > necessary acks from me to go through the mfd tree (didn't we agree on > > that ?) > > > > This was the reply from Lee a while ago: > > > On Wed, 18 Jan 2017, Alexandre Belloni wrote: > > > I don't think that one has your ack, is it ok for me to take it? > > > > This set looks MFD heavy, so it's probably best that the set goes > > through MFD. Once the RTC patch has been fixed of course. > > The series doesn't look MFD heavy anymore so it can also go through my > tree. I'll let Lee decide. Fine by me. -- Lee Jones Linaro Services Technical Lead Linaro.org │ Open source software for ARM SoCs Follow Linaro: Facebook | Twitter | Blog
Re: [rtc-linux] Re: [PATCH v4 0/2] Add support for cros-ec-rtc driver.
On Tue, 12 Dec 2017, Alexandre Belloni wrote: > On 12/12/2017 at 17:05:37 +0100, Alexandre Belloni wrote: > > On 12/12/2017 at 16:41:39 +0100, Enric Balletbo Serra wrote: > > > + Alessandro Zummo > > > + Alexandre Belloni > > > > > > 2017-11-10 22:55 GMT+01:00 Enric Balletbo i Serra > > > : > > > > Dear all, > > > > > > > > This is an attempt to revive some patches from that [1] patchset, some > > > > of them are still under discussion but I think there is no reason to not > > > > have the other two in this fourth version to land upstream meanwhile we > > > > discuss about the others. > > > > > > > > [1] https://lkml.org/lkml/2017/7/12/182 > > > > > > > > Changes since v3: > > > > * Rebased an retested with current mainline using a Samsung Chromebook > > > > Plus > > > > * Removed from patchset > > > > * 1/4 mfd: cros_ec: Get rid of cros_ec_check_features from > > > > cros_ec_dev. > > > > * 4/4 mfd: cros_ec: add RTC as mfd subdevice. > > > > > > > > Changes since v2: > > > > - Rebase on top of mainline. > > > > - Removed patch 'mfd: cros-ec: Fix host command buffer size' from series > > > > as was already picked. > > > > > > > > Changes since v1: > > > > - Removed patch 'iio: cros_ec_sensors: Fix return value to get raw and > > > > calibbias data' from series as was already picked. > > > > - Removed patch 'iio: cros_ec_sensors: Fix return value to get raw and > > > > calibbias data' from series as was already picked. > > > > - Patch 2/5: Acked-by: Jonathan Cameron <***@kernel.org> > > > > > > > > Best regards, > > > > > > > > Enric > > > > > > > > Stephen Barber (2): > > > > mfd: cros_ec: Introduce RTC commands and events definitions. > > > > rtc: cros-ec: add cros-ec-rtc driver. > > > > > > > > drivers/rtc/Kconfig | 10 + > > > > drivers/rtc/Makefile | 1 + > > > > drivers/rtc/rtc-cros-ec.c| 413 > > > > +++ > > > > include/linux/mfd/cros_ec_commands.h | 8 + > > > > 4 files changed, 432 insertions(+) > > > > create mode 100644 drivers/rtc/rtc-cros-ec.c > > > > > > > > > > > > > > Sorry, I just noticed that my script to add the email recipients > > > failed and I did not add the RTC maintainers :( So this is a gentle > > > ping cc'ing the maintainers to take in consideration these patches. If > > > you want I resend or something else just let me know please. > > > > > > > I don't remember the specifics but I think the patches have the > > necessary acks from me to go through the mfd tree (didn't we agree on > > that ?) > > > > This was the reply from Lee a while ago: > > > On Wed, 18 Jan 2017, Alexandre Belloni wrote: > > > I don't think that one has your ack, is it ok for me to take it? > > > > This set looks MFD heavy, so it's probably best that the set goes > > through MFD. Once the RTC patch has been fixed of course. > > The series doesn't look MFD heavy anymore so it can also go through my > tree. I'll let Lee decide. Fine by me. -- Lee Jones Linaro Services Technical Lead Linaro.org │ Open source software for ARM SoCs Follow Linaro: Facebook | Twitter | Blog
Re: [PATCH] cgroup/cpuset: fix circular locking dependency
On 12/11/2017 08:50 PM, Tejun Heo wrote: > Hello, Peter. > > On Tue, Dec 05, 2017 at 12:01:17AM +0100, Peter Zijlstra wrote: >>> AFAICS, this should remove the circular dependency you originally >>> reported. I'll revert the two cpuset commits for now. >> >> So I liked his patches in that we would be able to go back to >> synchronous sched_domain building. > > Ah, yeah, that's a separate issue but didn't we intentionally make > that asynchronous? IIRC, cpuset migration can take a really long time > when the memory migration is turned on and doing that synchronously > could mess up the system. > > Thanks. > Hi TJ, This change makes the usage of cpuset_hotplug_workfn() from cpu hotplug path synchronous. For memory hotplug it still remains asynchronous. Memory migration happening from cpuset_hotplug_workfn() is already asynchronous by queuing cpuset_migrate_mm_workfn() in cpuset_migrate_mm_wq. cpuset_hotplug_workfn() cpuset_hotplug_workfn(() cpuset_migrate_mm() queue_work(cpuset_migrate_mm_wq) It seems that memory migration latency might not have impact with this change. Please let me know if you meant something else by cpuset migration taking time when memory migration is turned on. Thanks -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc., is a member of Code Aurora Forum, a Linux Foundation Collaborative Project
Re: [PATCH] cgroup/cpuset: fix circular locking dependency
On 12/11/2017 08:50 PM, Tejun Heo wrote: > Hello, Peter. > > On Tue, Dec 05, 2017 at 12:01:17AM +0100, Peter Zijlstra wrote: >>> AFAICS, this should remove the circular dependency you originally >>> reported. I'll revert the two cpuset commits for now. >> >> So I liked his patches in that we would be able to go back to >> synchronous sched_domain building. > > Ah, yeah, that's a separate issue but didn't we intentionally make > that asynchronous? IIRC, cpuset migration can take a really long time > when the memory migration is turned on and doing that synchronously > could mess up the system. > > Thanks. > Hi TJ, This change makes the usage of cpuset_hotplug_workfn() from cpu hotplug path synchronous. For memory hotplug it still remains asynchronous. Memory migration happening from cpuset_hotplug_workfn() is already asynchronous by queuing cpuset_migrate_mm_workfn() in cpuset_migrate_mm_wq. cpuset_hotplug_workfn() cpuset_hotplug_workfn(() cpuset_migrate_mm() queue_work(cpuset_migrate_mm_wq) It seems that memory migration latency might not have impact with this change. Please let me know if you meant something else by cpuset migration taking time when memory migration is turned on. Thanks -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc., is a member of Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH 1/1] arm: sunxi: Add alternative pins for spi0
Allwinner A10/A13/A20 SoCs have pinmux for spi0 on port C. The patch adds these pins in the respective dts includes. Signed-off-by: Stefan Mavrodiev--- arch/arm/boot/dts/sun4i-a10.dtsi | 10 ++ arch/arm/boot/dts/sun5i.dtsi | 10 ++ arch/arm/boot/dts/sun7i-a20.dtsi | 10 ++ 3 files changed, 30 insertions(+) diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi index 5840f5c..d835741 100644 --- a/arch/arm/boot/dts/sun4i-a10.dtsi +++ b/arch/arm/boot/dts/sun4i-a10.dtsi @@ -705,11 +705,21 @@ bias-pull-up; }; + spi0_pc_pins: spi0-pc-pins { + pins = "PC0", "PC1", "PC2"; + function = "spi0"; + }; + spi0_pi_pins: spi0-pi-pins { pins = "PI11", "PI12", "PI13"; function = "spi0"; }; + spi0_cs0_pc_pin: spi0-cs0-pc-pin { + pins = "PC23"; + function = "spi0"; + }; + spi0_cs0_pi_pin: spi0-cs0-pi-pin { pins = "PI10"; function = "spi0"; diff --git a/arch/arm/boot/dts/sun5i.dtsi b/arch/arm/boot/dts/sun5i.dtsi index 07f2248..9290e26 100644 --- a/arch/arm/boot/dts/sun5i.dtsi +++ b/arch/arm/boot/dts/sun5i.dtsi @@ -492,6 +492,16 @@ function = "nand0"; }; + spi0_pins_a: spi0@0 { + pins = "PC0", "PC1", "PC2"; + function = "spi0"; + }; + + spi0_cs0_pins_a: spi0-cs0@0 { + pins = "PC3"; + function = "spi0"; + }; + spi2_pins_a: spi2@0 { pins = "PE1", "PE2", "PE3"; function = "spi2"; diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi index 59655e4..6930527 100644 --- a/arch/arm/boot/dts/sun7i-a20.dtsi +++ b/arch/arm/boot/dts/sun7i-a20.dtsi @@ -838,11 +838,21 @@ function = "spi0"; }; + spi0_pins_b: spi0@1 { + pins = "PC0", "PC1", "PC2"; + function = "spi0"; + }; + spi0_cs0_pins_a: spi0_cs0@0 { pins = "PI10"; function = "spi0"; }; + spi0_cs0_pins_b: spi0_cs0@1 { + pins = "PC23"; + function = "spi0"; + }; + spi0_cs1_pins_a: spi0_cs1@0 { pins = "PI14"; function = "spi0"; -- 2.7.4
[PATCH 1/1] arm: sunxi: Add alternative pins for spi0
Allwinner A10/A13/A20 SoCs have pinmux for spi0 on port C. The patch adds these pins in the respective dts includes. Signed-off-by: Stefan Mavrodiev --- arch/arm/boot/dts/sun4i-a10.dtsi | 10 ++ arch/arm/boot/dts/sun5i.dtsi | 10 ++ arch/arm/boot/dts/sun7i-a20.dtsi | 10 ++ 3 files changed, 30 insertions(+) diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi index 5840f5c..d835741 100644 --- a/arch/arm/boot/dts/sun4i-a10.dtsi +++ b/arch/arm/boot/dts/sun4i-a10.dtsi @@ -705,11 +705,21 @@ bias-pull-up; }; + spi0_pc_pins: spi0-pc-pins { + pins = "PC0", "PC1", "PC2"; + function = "spi0"; + }; + spi0_pi_pins: spi0-pi-pins { pins = "PI11", "PI12", "PI13"; function = "spi0"; }; + spi0_cs0_pc_pin: spi0-cs0-pc-pin { + pins = "PC23"; + function = "spi0"; + }; + spi0_cs0_pi_pin: spi0-cs0-pi-pin { pins = "PI10"; function = "spi0"; diff --git a/arch/arm/boot/dts/sun5i.dtsi b/arch/arm/boot/dts/sun5i.dtsi index 07f2248..9290e26 100644 --- a/arch/arm/boot/dts/sun5i.dtsi +++ b/arch/arm/boot/dts/sun5i.dtsi @@ -492,6 +492,16 @@ function = "nand0"; }; + spi0_pins_a: spi0@0 { + pins = "PC0", "PC1", "PC2"; + function = "spi0"; + }; + + spi0_cs0_pins_a: spi0-cs0@0 { + pins = "PC3"; + function = "spi0"; + }; + spi2_pins_a: spi2@0 { pins = "PE1", "PE2", "PE3"; function = "spi2"; diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi index 59655e4..6930527 100644 --- a/arch/arm/boot/dts/sun7i-a20.dtsi +++ b/arch/arm/boot/dts/sun7i-a20.dtsi @@ -838,11 +838,21 @@ function = "spi0"; }; + spi0_pins_b: spi0@1 { + pins = "PC0", "PC1", "PC2"; + function = "spi0"; + }; + spi0_cs0_pins_a: spi0_cs0@0 { pins = "PI10"; function = "spi0"; }; + spi0_cs0_pins_b: spi0_cs0@1 { + pins = "PC23"; + function = "spi0"; + }; + spi0_cs1_pins_a: spi0_cs1@0 { pins = "PI14"; function = "spi0"; -- 2.7.4
Re: [BUG] skge: a possible sleep-in-atomic bug in skge_remove
On 2017/12/13 13:18, Stephen Hemminger wrote: On Tue, 12 Dec 2017 20:57:01 -0500 (EST) David Millerwrote: From: Stephen Hemminger Date: Tue, 12 Dec 2017 10:22:40 -0800 On Tue, 12 Dec 2017 08:34:45 -0500 (EST) David Miller wrote: From: Jia-Ju Bai Date: Tue, 12 Dec 2017 16:38:12 +0800 According to drivers/net/ethernet/marvell/skge.c, the driver may sleep under a spinlock. The function call path is: skge_remove (acquire the spinlock) free_irq --> may sleep I do not find a good way to fix it, so I only report. This possible bug is found by my static analysis tool (DSAC) and checked by my code review. This was added by: commit a9e9fd7182332d0cf5f3e601df3e71dd431b70d7 Author: Stephen Hemminger Date: Tue Sep 27 13:41:37 2011 -0400 skge: handle irq better on single port card I think the free_irq() can be moved below the unlock. Stephen, please take a look. The IRQ was being free twice. How did you see it, I really doubt any multi-port SKGE cards still exist. He sees it by reading the code, please take a look at this and move the free_irq() out of the spin locked section since it can sleep. Thanks, I was hoping for some automated static analysis tool. This bug was found by an automated static analysis tool named DSAC, which is written by myself. Then I manually checked driver source code, and finally sent the bug report. Thanks, Jia-Ju Bai
Re: [BUG] skge: a possible sleep-in-atomic bug in skge_remove
On 2017/12/13 13:18, Stephen Hemminger wrote: On Tue, 12 Dec 2017 20:57:01 -0500 (EST) David Miller wrote: From: Stephen Hemminger Date: Tue, 12 Dec 2017 10:22:40 -0800 On Tue, 12 Dec 2017 08:34:45 -0500 (EST) David Miller wrote: From: Jia-Ju Bai Date: Tue, 12 Dec 2017 16:38:12 +0800 According to drivers/net/ethernet/marvell/skge.c, the driver may sleep under a spinlock. The function call path is: skge_remove (acquire the spinlock) free_irq --> may sleep I do not find a good way to fix it, so I only report. This possible bug is found by my static analysis tool (DSAC) and checked by my code review. This was added by: commit a9e9fd7182332d0cf5f3e601df3e71dd431b70d7 Author: Stephen Hemminger Date: Tue Sep 27 13:41:37 2011 -0400 skge: handle irq better on single port card I think the free_irq() can be moved below the unlock. Stephen, please take a look. The IRQ was being free twice. How did you see it, I really doubt any multi-port SKGE cards still exist. He sees it by reading the code, please take a look at this and move the free_irq() out of the spin locked section since it can sleep. Thanks, I was hoping for some automated static analysis tool. This bug was found by an automated static analysis tool named DSAC, which is written by myself. Then I manually checked driver source code, and finally sent the bug report. Thanks, Jia-Ju Bai
Re: [PATCH v2 04/13] dt-bindings: pinctrl: Add bindings for Microsemi Ocelot
On Fri, Dec 8, 2017 at 4:46 PM, Alexandre Belloniwrote: > Add the documentation for the Microsemi Ocelot pinmuxing and gpio > controller. > > Cc: Linus Walleij > Cc: linux-g...@vger.kernel.org > Signed-off-by: Alexandre Belloni > Acked-by: Rob Herring Patch applied. Yours, Linus Walleij
Re: [PATCH v2 04/13] dt-bindings: pinctrl: Add bindings for Microsemi Ocelot
On Fri, Dec 8, 2017 at 4:46 PM, Alexandre Belloni wrote: > Add the documentation for the Microsemi Ocelot pinmuxing and gpio > controller. > > Cc: Linus Walleij > Cc: linux-g...@vger.kernel.org > Signed-off-by: Alexandre Belloni > Acked-by: Rob Herring Patch applied. Yours, Linus Walleij
Re: [BUG] scsi/qla2xxx: a possible sleep-in-atomic bug in qlt_get_tag
On 2017/12/13 12:42, James Bottomley wrote: On Wed, 2017-12-13 at 11:18 +0800, Jia-Ju Bai wrote: The driver may sleep under a spinlock. The function call paths are: qlt_handle_abts_recv_work (acquire the spinlock) qlt_response_pkt_all_vps qlt_response_pkt qlt_handle_cmd_for_atio qlt_get_tag percpu_ida_alloc --> may sleep qla82xx_msix_rsp_q (acquire the spinlock) qla24xx_process_response_queue qlt_handle_abts_recv qlt_response_pkt_all_vps qlt_response_pkt qlt_handle_cmd_for_atio qlt_get_tag percpu_ida_alloc --> may sleep-in-atomic qla24xx_intr_handler (acquire the spinlock) qla24xx_process_response_queue qlt_handle_abts_recv qlt_response_pkt qlt_handle_cmd_for_atio qlt_get_tag percpu_ida_alloc --> may sleep I do not find a good way to fix it, so I only report. This possible bug is found by my static analysis tool (DSAC) and checked by my code review. The report is incorrect: percpu_ida_alloc with state==TASK_RUNNING is atomic (and interrupt) safe which appears to be the case here. James Thanks for your reply :) I have checked the definition of percpu_ida_alloc, and I think you are right. Sorry for my incorrect bug report. Thanks, Jia-Ju Bai
Re: [BUG] scsi/qla2xxx: a possible sleep-in-atomic bug in qlt_get_tag
On 2017/12/13 12:42, James Bottomley wrote: On Wed, 2017-12-13 at 11:18 +0800, Jia-Ju Bai wrote: The driver may sleep under a spinlock. The function call paths are: qlt_handle_abts_recv_work (acquire the spinlock) qlt_response_pkt_all_vps qlt_response_pkt qlt_handle_cmd_for_atio qlt_get_tag percpu_ida_alloc --> may sleep qla82xx_msix_rsp_q (acquire the spinlock) qla24xx_process_response_queue qlt_handle_abts_recv qlt_response_pkt_all_vps qlt_response_pkt qlt_handle_cmd_for_atio qlt_get_tag percpu_ida_alloc --> may sleep-in-atomic qla24xx_intr_handler (acquire the spinlock) qla24xx_process_response_queue qlt_handle_abts_recv qlt_response_pkt qlt_handle_cmd_for_atio qlt_get_tag percpu_ida_alloc --> may sleep I do not find a good way to fix it, so I only report. This possible bug is found by my static analysis tool (DSAC) and checked by my code review. The report is incorrect: percpu_ida_alloc with state==TASK_RUNNING is atomic (and interrupt) safe which appears to be the case here. James Thanks for your reply :) I have checked the definition of percpu_ida_alloc, and I think you are right. Sorry for my incorrect bug report. Thanks, Jia-Ju Bai
Re: general protection fault in page_mapping
On 12/12/2017 06:03 PM, syzbot wrote: > Hello, > > syzkaller hit the following crash on > 82bcf1def3b5f1251177ad47c44f7e17af039b4b > git://git.cmpxchg.org/linux-mmots.git/master > compiler: gcc (GCC) 7.1.1 20170620 > .config is attached > Raw console output is attached. > C reproducer is attached > syzkaller reproducer is attached. See https://goo.gl/kgGztJ > for information about syzkaller reproducers > > > audit: type=1400 audit(1512751226.892:7): avc: denied { map } for > pid=3149 comm="syzkaller233597" path="/root/syzkaller233597068" dev="sda1" > ino=16481 scontext=unconfined_u:system_r:insmod_t:s0-s0:c0.c1023 > tcontext=unconfined_u:object_r:user_home_t:s0 tclass=file permissive=1 > kasan: CONFIG_KASAN_INLINE enabled > kasan: GPF could be caused by NULL-ptr deref or user memory access > general protection fault: [#1] SMP KASAN > Dumping ftrace buffer: > (ftrace buffer empty) > Modules linked in: > CPU: 0 PID: 3149 Comm: syzkaller233597 Not tainted 4.15.0-rc2-mm1+ #39 > Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS > Google 01/01/2011 > RIP: 0010:__read_once_size include/linux/compiler.h:183 [inline] > RIP: 0010:compound_head include/linux/page-flags.h:147 [inline] > RIP: 0010:page_mapping+0xa4/0x530 mm/util.c:475 > RSP: 0018:8801c5177320 EFLAGS: 00010202 > RAX: 0004 RBX: 110038a2ee65 RCX: 81950c5d > RDX: RSI: 110038a2ef03 RDI: > RBP: 8801c5177470 R08: ed0038a6fbac R09: 8801c537dd40 > R10: 8801d6e8c518 R11: ed0038a6fbab R12: > R13: 8801c5177448 R14: dc00 R15: 0020 > FS: 021da880() GS:8801db20() knlGS: > CS: 0010 DS: ES: CR0: 80050033 > CR2: 20a23000 CR3: 0001c6bf5000 CR4: 001406f0 > DR0: DR1: DR2: > DR3: DR6: fffe0ff0 DR7: 0400 > Call Trace: > set_page_dirty+0xb9/0x5d0 mm/page-writeback.c:2544 > rds_atomic_free_op+0xc2/0x330 net/rds/rdma.c:481 The NULL page pointer was obtained in the function above, so CCing rdma. > rds_message_purge net/rds/message.c:79 [inline] > rds_message_put+0x53c/0x6b0 net/rds/message.c:91 > rds_sendmsg+0x14ee/0x1f90 net/rds/send.c:1204 > sock_sendmsg_nosec net/socket.c:636 [inline] > sock_sendmsg+0xca/0x110 net/socket.c:646 > ___sys_sendmsg+0x75b/0x8a0 net/socket.c:2026 > __sys_sendmsg+0xe5/0x210 net/socket.c:2060 > SYSC_sendmsg net/socket.c:2071 [inline] > SyS_sendmsg+0x2d/0x50 net/socket.c:2067 > entry_SYSCALL_64_fastpath+0x1f/0x96 > RIP: 0033:0x43fe49 > RSP: 002b:7fffab075338 EFLAGS: 0217 ORIG_RAX: 002e > RAX: ffda RBX: 004002c8 RCX: 0043fe49 > RDX: RSI: 20159fc8 RDI: 0003 > RBP: 006ca018 R08: R09: > R10: R11: 0217 R12: 004017b0 > R13: 00401840 R14: R15: > Code: f2 f2 f2 c7 40 14 00 f2 f2 f2 c7 40 18 f2 f2 f2 f2 c7 40 1c 00 f2 f2 > f2 c7 40 20 f3 f3 f3 f3 e8 43 29 db ff 4c 89 f8 48 c1 e8 03 <42> 80 3c 30 > 00 0f 85 41 04 00 00 4d 8d b5 00 ff ff ff 48 ba 00 > RIP: __read_once_size include/linux/compiler.h:183 [inline] RSP: > 8801c5177320 > RIP: compound_head include/linux/page-flags.h:147 [inline] RSP: > 8801c5177320 > RIP: page_mapping+0xa4/0x530 mm/util.c:475 RSP: 8801c5177320 > ---[ end trace f878597b0d0664a0 ]--- > Kernel panic - not syncing: Fatal exception > Dumping ftrace buffer: > (ftrace buffer empty) > Kernel Offset: disabled > Rebooting in 86400 seconds.. > > > --- > This bug is generated by a dumb bot. It may contain errors. > See https://goo.gl/tpsmEJ for details. > Direct all questions to syzkal...@googlegroups.com. > Please credit me with: Reported-by: syzbot> > syzbot will keep track of this bug report. > Once a fix for this bug is merged into any tree, reply to this email with: > #syz fix: exact-commit-title > If you want to test a patch for this bug, please reply with: > #syz test: git://repo/address.git branch > and provide the patch inline or as an attachment. > To mark this as a duplicate of another syzbot report, please reply with: > #syz dup: exact-subject-of-another-report > If it's a one-off invalid bug report, please reply with: > #syz invalid > Note: if the crash happens again, it will cause creation of a new bug > report. > Note: all commands must start from beginning of the line in the email body. > > > config.txt > > > # > # Automatically generated file; DO NOT EDIT. > # Linux/x86 4.15.0-rc2 Kernel Configuration > # > CONFIG_64BIT=y > CONFIG_X86_64=y > CONFIG_X86=y > CONFIG_INSTRUCTION_DECODER=y > CONFIG_OUTPUT_FORMAT="elf64-x86-64" > CONFIG_ARCH_DEFCONFIG="arch/x86/configs/x86_64_defconfig" >
Re: general protection fault in page_mapping
On 12/12/2017 06:03 PM, syzbot wrote: > Hello, > > syzkaller hit the following crash on > 82bcf1def3b5f1251177ad47c44f7e17af039b4b > git://git.cmpxchg.org/linux-mmots.git/master > compiler: gcc (GCC) 7.1.1 20170620 > .config is attached > Raw console output is attached. > C reproducer is attached > syzkaller reproducer is attached. See https://goo.gl/kgGztJ > for information about syzkaller reproducers > > > audit: type=1400 audit(1512751226.892:7): avc: denied { map } for > pid=3149 comm="syzkaller233597" path="/root/syzkaller233597068" dev="sda1" > ino=16481 scontext=unconfined_u:system_r:insmod_t:s0-s0:c0.c1023 > tcontext=unconfined_u:object_r:user_home_t:s0 tclass=file permissive=1 > kasan: CONFIG_KASAN_INLINE enabled > kasan: GPF could be caused by NULL-ptr deref or user memory access > general protection fault: [#1] SMP KASAN > Dumping ftrace buffer: > (ftrace buffer empty) > Modules linked in: > CPU: 0 PID: 3149 Comm: syzkaller233597 Not tainted 4.15.0-rc2-mm1+ #39 > Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS > Google 01/01/2011 > RIP: 0010:__read_once_size include/linux/compiler.h:183 [inline] > RIP: 0010:compound_head include/linux/page-flags.h:147 [inline] > RIP: 0010:page_mapping+0xa4/0x530 mm/util.c:475 > RSP: 0018:8801c5177320 EFLAGS: 00010202 > RAX: 0004 RBX: 110038a2ee65 RCX: 81950c5d > RDX: RSI: 110038a2ef03 RDI: > RBP: 8801c5177470 R08: ed0038a6fbac R09: 8801c537dd40 > R10: 8801d6e8c518 R11: ed0038a6fbab R12: > R13: 8801c5177448 R14: dc00 R15: 0020 > FS: 021da880() GS:8801db20() knlGS: > CS: 0010 DS: ES: CR0: 80050033 > CR2: 20a23000 CR3: 0001c6bf5000 CR4: 001406f0 > DR0: DR1: DR2: > DR3: DR6: fffe0ff0 DR7: 0400 > Call Trace: > set_page_dirty+0xb9/0x5d0 mm/page-writeback.c:2544 > rds_atomic_free_op+0xc2/0x330 net/rds/rdma.c:481 The NULL page pointer was obtained in the function above, so CCing rdma. > rds_message_purge net/rds/message.c:79 [inline] > rds_message_put+0x53c/0x6b0 net/rds/message.c:91 > rds_sendmsg+0x14ee/0x1f90 net/rds/send.c:1204 > sock_sendmsg_nosec net/socket.c:636 [inline] > sock_sendmsg+0xca/0x110 net/socket.c:646 > ___sys_sendmsg+0x75b/0x8a0 net/socket.c:2026 > __sys_sendmsg+0xe5/0x210 net/socket.c:2060 > SYSC_sendmsg net/socket.c:2071 [inline] > SyS_sendmsg+0x2d/0x50 net/socket.c:2067 > entry_SYSCALL_64_fastpath+0x1f/0x96 > RIP: 0033:0x43fe49 > RSP: 002b:7fffab075338 EFLAGS: 0217 ORIG_RAX: 002e > RAX: ffda RBX: 004002c8 RCX: 0043fe49 > RDX: RSI: 20159fc8 RDI: 0003 > RBP: 006ca018 R08: R09: > R10: R11: 0217 R12: 004017b0 > R13: 00401840 R14: R15: > Code: f2 f2 f2 c7 40 14 00 f2 f2 f2 c7 40 18 f2 f2 f2 f2 c7 40 1c 00 f2 f2 > f2 c7 40 20 f3 f3 f3 f3 e8 43 29 db ff 4c 89 f8 48 c1 e8 03 <42> 80 3c 30 > 00 0f 85 41 04 00 00 4d 8d b5 00 ff ff ff 48 ba 00 > RIP: __read_once_size include/linux/compiler.h:183 [inline] RSP: > 8801c5177320 > RIP: compound_head include/linux/page-flags.h:147 [inline] RSP: > 8801c5177320 > RIP: page_mapping+0xa4/0x530 mm/util.c:475 RSP: 8801c5177320 > ---[ end trace f878597b0d0664a0 ]--- > Kernel panic - not syncing: Fatal exception > Dumping ftrace buffer: > (ftrace buffer empty) > Kernel Offset: disabled > Rebooting in 86400 seconds.. > > > --- > This bug is generated by a dumb bot. It may contain errors. > See https://goo.gl/tpsmEJ for details. > Direct all questions to syzkal...@googlegroups.com. > Please credit me with: Reported-by: syzbot > > syzbot will keep track of this bug report. > Once a fix for this bug is merged into any tree, reply to this email with: > #syz fix: exact-commit-title > If you want to test a patch for this bug, please reply with: > #syz test: git://repo/address.git branch > and provide the patch inline or as an attachment. > To mark this as a duplicate of another syzbot report, please reply with: > #syz dup: exact-subject-of-another-report > If it's a one-off invalid bug report, please reply with: > #syz invalid > Note: if the crash happens again, it will cause creation of a new bug > report. > Note: all commands must start from beginning of the line in the email body. > > > config.txt > > > # > # Automatically generated file; DO NOT EDIT. > # Linux/x86 4.15.0-rc2 Kernel Configuration > # > CONFIG_64BIT=y > CONFIG_X86_64=y > CONFIG_X86=y > CONFIG_INSTRUCTION_DECODER=y > CONFIG_OUTPUT_FORMAT="elf64-x86-64" > CONFIG_ARCH_DEFCONFIG="arch/x86/configs/x86_64_defconfig" > CONFIG_LOCKDEP_SUPPORT=y >
Re: [PATCH v5 8/9] pinctrl: axp209: add support for AXP813 GPIOs
On Fri, Dec 8, 2017 at 2:41 PM, Quentin Schulzwrote: >> - pctl->desc = _data; >> + pctl->desc = (struct axp20x_pctrl_desc *)of_device_get_match_data(dev); >> pctl->regmap = axp20x->regmap; >> pctl->dev = >dev; >> > > I am using pctl->desc before retrieving it, thus dereferencing from a > null pointer. > > We just have to move > pctl->chip.ngpio= pctl->desc->npins; > after > pctl->desc = (struct axp20x_pctrl_desc *)of_device_get_match_data(dev); > > Linus, I guess that I should send a patch to fix this or is there an > other way not to have to apply such a small and dumb patch? Just send a patch based on my pin control tree "devel" branch or linux-next, it's cool. Things like this happens all the time. Yours, Linus Walleij
Re: [PATCH v5 8/9] pinctrl: axp209: add support for AXP813 GPIOs
On Fri, Dec 8, 2017 at 2:41 PM, Quentin Schulz wrote: >> - pctl->desc = _data; >> + pctl->desc = (struct axp20x_pctrl_desc *)of_device_get_match_data(dev); >> pctl->regmap = axp20x->regmap; >> pctl->dev = >dev; >> > > I am using pctl->desc before retrieving it, thus dereferencing from a > null pointer. > > We just have to move > pctl->chip.ngpio= pctl->desc->npins; > after > pctl->desc = (struct axp20x_pctrl_desc *)of_device_get_match_data(dev); > > Linus, I guess that I should send a patch to fix this or is there an > other way not to have to apply such a small and dumb patch? Just send a patch based on my pin control tree "devel" branch or linux-next, it's cool. Things like this happens all the time. Yours, Linus Walleij
Re: [PATCH v5 0/4] ARM: ep93xx: ts72xx: Add support for BK3 board
On Tue, Dec 12, 2017 at 12:36 AM, Lukasz Majewskiwrote: > This patch series adds support for Liebherr's BK3 board, being > a derivative of TS72XX design. All looks good. Acked-by: Linus Walleij Out of curiosity: Liebherr is obviously doing heavy-duty industrial control systems. Likewise Hartley is doing similar business over at Vision Engravings. Is the situation such that there is a whole bunch of industrial systems out there, in active use and needing future upgrades, that use the EP93xx? Arnd has been nudging me to do DT conversion for EP93xx so if there are many active industrial users of these I should prioritize it, because these things have 20+ years support cycles. We also need to think about upholding support in GCC for ARMv4(t) for the foreseeable future if there is a big web of random deeply embedded systems out there that will need updates. Yours, Linus Walleij
Re: [PATCH v5 0/4] ARM: ep93xx: ts72xx: Add support for BK3 board
On Tue, Dec 12, 2017 at 12:36 AM, Lukasz Majewski wrote: > This patch series adds support for Liebherr's BK3 board, being > a derivative of TS72XX design. All looks good. Acked-by: Linus Walleij Out of curiosity: Liebherr is obviously doing heavy-duty industrial control systems. Likewise Hartley is doing similar business over at Vision Engravings. Is the situation such that there is a whole bunch of industrial systems out there, in active use and needing future upgrades, that use the EP93xx? Arnd has been nudging me to do DT conversion for EP93xx so if there are many active industrial users of these I should prioritize it, because these things have 20+ years support cycles. We also need to think about upholding support in GCC for ARMv4(t) for the foreseeable future if there is a big web of random deeply embedded systems out there that will need updates. Yours, Linus Walleij
Re: [PATCH] spi: s3c64xx: add SPDX identifier
On Wed, Dec 13, 2017 at 2:48 AM, Andi Shytiwrote: > Hi Krzysztof, > >> > Here, this should be as a top line: >> > >> > // SPDX-License-Identifier: GPL-2.0+ >> > >> > >> > So I agree with the SPDX id but also pointing to the use of the C++ // >> > comment style as requested by Linus [1] >> >> Thanks for the reference. I see that Linus prefers converting entire >> comment into // style. I was not arguing about SPDX line but entire >> existing copyright comment which follows it: >> >> > +// >> > +// Copyright (c) 2009 Samsung Electronics Co., Ltd. >> > +// Jaswinder Singh > > it just looks ugly to me to have something like > > // SPDX... > > /* >* Copyright (c)... >* Jasw... >*/ > > I would make everything of the '//' style (I've also seen that > this is the trend also in other subsystems), but honestly I don't > really care. If you're strong on not moving entirely in '//' style > then I can resend it with the double comment style. Let's follow Linus' preference - entire commend converted as you did already. Thanks, Krzysztof
Re: [PATCH] spi: s3c64xx: add SPDX identifier
On Wed, Dec 13, 2017 at 2:48 AM, Andi Shyti wrote: > Hi Krzysztof, > >> > Here, this should be as a top line: >> > >> > // SPDX-License-Identifier: GPL-2.0+ >> > >> > >> > So I agree with the SPDX id but also pointing to the use of the C++ // >> > comment style as requested by Linus [1] >> >> Thanks for the reference. I see that Linus prefers converting entire >> comment into // style. I was not arguing about SPDX line but entire >> existing copyright comment which follows it: >> >> > +// >> > +// Copyright (c) 2009 Samsung Electronics Co., Ltd. >> > +// Jaswinder Singh > > it just looks ugly to me to have something like > > // SPDX... > > /* >* Copyright (c)... >* Jasw... >*/ > > I would make everything of the '//' style (I've also seen that > this is the trend also in other subsystems), but honestly I don't > really care. If you're strong on not moving entirely in '//' style > then I can resend it with the double comment style. Let's follow Linus' preference - entire commend converted as you did already. Thanks, Krzysztof
[PATCH V8 3/7] device property: Introduce a common API to fetch device match data
There is an OF/ACPI function to obtain the driver data. We want to hide OF/ACPI details from the device drivers and abstract following the device family of functions. Signed-off-by: Sinan KayaReviewed-by: Rob Herring Acked-by: Sakari Ailus --- drivers/base/property.c | 7 +++ include/linux/fwnode.h | 4 include/linux/property.h | 2 ++ 3 files changed, 13 insertions(+) diff --git a/drivers/base/property.c b/drivers/base/property.c index 851b1b6..09eaac9 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -1340,3 +1340,10 @@ int fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode, return fwnode_call_int_op(fwnode, graph_parse_endpoint, endpoint); } EXPORT_SYMBOL(fwnode_graph_parse_endpoint); + +void *device_get_match_data(struct device *dev) +{ + return fwnode_call_ptr_op(dev_fwnode(dev), device_get_match_data, + dev); +} +EXPORT_SYMBOL_GPL(device_get_match_data); diff --git a/include/linux/fwnode.h b/include/linux/fwnode.h index 411a84c..4fa1a48 100644 --- a/include/linux/fwnode.h +++ b/include/linux/fwnode.h @@ -15,6 +15,7 @@ #include struct fwnode_operations; +struct device; struct fwnode_handle { struct fwnode_handle *secondary; @@ -51,6 +52,7 @@ struct fwnode_reference_args { * struct fwnode_operations - Operations for fwnode interface * @get: Get a reference to an fwnode. * @put: Put a reference to an fwnode. + * @device_get_match_data: Return the device driver match data. * @property_present: Return true if a property is present. * @property_read_integer_array: Read an array of integer properties. Return * zero on success, a negative error code @@ -71,6 +73,8 @@ struct fwnode_operations { struct fwnode_handle *(*get)(struct fwnode_handle *fwnode); void (*put)(struct fwnode_handle *fwnode); bool (*device_is_available)(const struct fwnode_handle *fwnode); + void *(*device_get_match_data)(const struct fwnode_handle *fwnode, + const struct device *dev); bool (*property_present)(const struct fwnode_handle *fwnode, const char *propname); int (*property_read_int_array)(const struct fwnode_handle *fwnode, diff --git a/include/linux/property.h b/include/linux/property.h index f6189a3..6653ed4 100644 --- a/include/linux/property.h +++ b/include/linux/property.h @@ -275,6 +275,8 @@ int device_add_properties(struct device *dev, enum dev_dma_attr device_get_dma_attr(struct device *dev); +void *device_get_match_data(struct device *dev); + int device_get_phy_mode(struct device *dev); void *device_get_mac_address(struct device *dev, char *addr, int alen); -- 1.9.1
[PATCH V8 3/7] device property: Introduce a common API to fetch device match data
There is an OF/ACPI function to obtain the driver data. We want to hide OF/ACPI details from the device drivers and abstract following the device family of functions. Signed-off-by: Sinan Kaya Reviewed-by: Rob Herring Acked-by: Sakari Ailus --- drivers/base/property.c | 7 +++ include/linux/fwnode.h | 4 include/linux/property.h | 2 ++ 3 files changed, 13 insertions(+) diff --git a/drivers/base/property.c b/drivers/base/property.c index 851b1b6..09eaac9 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -1340,3 +1340,10 @@ int fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode, return fwnode_call_int_op(fwnode, graph_parse_endpoint, endpoint); } EXPORT_SYMBOL(fwnode_graph_parse_endpoint); + +void *device_get_match_data(struct device *dev) +{ + return fwnode_call_ptr_op(dev_fwnode(dev), device_get_match_data, + dev); +} +EXPORT_SYMBOL_GPL(device_get_match_data); diff --git a/include/linux/fwnode.h b/include/linux/fwnode.h index 411a84c..4fa1a48 100644 --- a/include/linux/fwnode.h +++ b/include/linux/fwnode.h @@ -15,6 +15,7 @@ #include struct fwnode_operations; +struct device; struct fwnode_handle { struct fwnode_handle *secondary; @@ -51,6 +52,7 @@ struct fwnode_reference_args { * struct fwnode_operations - Operations for fwnode interface * @get: Get a reference to an fwnode. * @put: Put a reference to an fwnode. + * @device_get_match_data: Return the device driver match data. * @property_present: Return true if a property is present. * @property_read_integer_array: Read an array of integer properties. Return * zero on success, a negative error code @@ -71,6 +73,8 @@ struct fwnode_operations { struct fwnode_handle *(*get)(struct fwnode_handle *fwnode); void (*put)(struct fwnode_handle *fwnode); bool (*device_is_available)(const struct fwnode_handle *fwnode); + void *(*device_get_match_data)(const struct fwnode_handle *fwnode, + const struct device *dev); bool (*property_present)(const struct fwnode_handle *fwnode, const char *propname); int (*property_read_int_array)(const struct fwnode_handle *fwnode, diff --git a/include/linux/property.h b/include/linux/property.h index f6189a3..6653ed4 100644 --- a/include/linux/property.h +++ b/include/linux/property.h @@ -275,6 +275,8 @@ int device_add_properties(struct device *dev, enum dev_dma_attr device_get_dma_attr(struct device *dev); +void *device_get_match_data(struct device *dev); + int device_get_phy_mode(struct device *dev); void *device_get_mac_address(struct device *dev, char *addr, int alen); -- 1.9.1
[PATCH V8 1/7] Documentation: DT: qcom_hidma: Bump HW revision for the bugfixed HW
A new version of the HIDMA IP has been released with bug fixes. Bumping the hardware version to differentiate from others. Signed-off-by: Sinan KayaReviewed-by: Rob Herring --- Documentation/devicetree/bindings/dma/qcom_hidma_mgmt.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/dma/qcom_hidma_mgmt.txt b/Documentation/devicetree/bindings/dma/qcom_hidma_mgmt.txt index 55492c2..5d93d6d 100644 --- a/Documentation/devicetree/bindings/dma/qcom_hidma_mgmt.txt +++ b/Documentation/devicetree/bindings/dma/qcom_hidma_mgmt.txt @@ -47,8 +47,8 @@ When the OS is not in control of the management interface (i.e. it's a guest), the channel nodes appear on their own, not under a management node. Required properties: -- compatible: must contain "qcom,hidma-1.0" for initial HW or "qcom,hidma-1.1" -for MSI capable HW. +- compatible: must contain "qcom,hidma-1.0" for initial HW or + "qcom,hidma-1.1"/"qcom,hidma-1.2" for MSI capable HW. - reg: Addresses for the transfer and event channel - interrupts: Should contain the event interrupt - desc-count: Number of asynchronous requests this channel can handle -- 1.9.1
Re: [PATCH V2 2/3] perf/x86/intel/bm.c: Add Intel Branch Monitoring support
On Tue, Dec 12, 2017 at 03:08:00PM -0800, Megha Dey wrote: > > > > There's work on the way to allow multiple HW PMUs. You'll either have to > > wait for that or help in making that happen. What you do not do is > > silently hack around it. > > Could I get a pointer to the code implementing this? > There isn't much code now; but it could be build on top of the stuff here: git://git.kernel.org/pub/scm/linux/kernel/git/peterz/queue.git perf/core It was mostly Mark I think who wanted this for big litte stuffs.
[PATCH V8 1/7] Documentation: DT: qcom_hidma: Bump HW revision for the bugfixed HW
A new version of the HIDMA IP has been released with bug fixes. Bumping the hardware version to differentiate from others. Signed-off-by: Sinan Kaya Reviewed-by: Rob Herring --- Documentation/devicetree/bindings/dma/qcom_hidma_mgmt.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/dma/qcom_hidma_mgmt.txt b/Documentation/devicetree/bindings/dma/qcom_hidma_mgmt.txt index 55492c2..5d93d6d 100644 --- a/Documentation/devicetree/bindings/dma/qcom_hidma_mgmt.txt +++ b/Documentation/devicetree/bindings/dma/qcom_hidma_mgmt.txt @@ -47,8 +47,8 @@ When the OS is not in control of the management interface (i.e. it's a guest), the channel nodes appear on their own, not under a management node. Required properties: -- compatible: must contain "qcom,hidma-1.0" for initial HW or "qcom,hidma-1.1" -for MSI capable HW. +- compatible: must contain "qcom,hidma-1.0" for initial HW or + "qcom,hidma-1.1"/"qcom,hidma-1.2" for MSI capable HW. - reg: Addresses for the transfer and event channel - interrupts: Should contain the event interrupt - desc-count: Number of asynchronous requests this channel can handle -- 1.9.1
Re: [PATCH V2 2/3] perf/x86/intel/bm.c: Add Intel Branch Monitoring support
On Tue, Dec 12, 2017 at 03:08:00PM -0800, Megha Dey wrote: > > > > There's work on the way to allow multiple HW PMUs. You'll either have to > > wait for that or help in making that happen. What you do not do is > > silently hack around it. > > Could I get a pointer to the code implementing this? > There isn't much code now; but it could be build on top of the stuff here: git://git.kernel.org/pub/scm/linux/kernel/git/peterz/queue.git perf/core It was mostly Mark I think who wanted this for big litte stuffs.
[PATCH V8 5/7] ACPI: properties: Implement get_match_data() callback
Now that we have a get_match_data() callback as part of the firmware node, implement the ACPI specific piece for it. Signed-off-by: Sinan KayaAcked-by: Sakari Ailus --- drivers/acpi/property.c | 8 1 file changed, 8 insertions(+) diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index e26ea20..466d150 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -1271,9 +1271,17 @@ static int acpi_fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode, return 0; } +static void * +acpi_fwnode_device_get_match_data(const struct fwnode_handle *fwnode, + const struct device *dev) +{ + return acpi_get_match_data(dev); +} + #define DECLARE_ACPI_FWNODE_OPS(ops) \ const struct fwnode_operations ops = { \ .device_is_available = acpi_fwnode_device_is_available, \ + .device_get_match_data = acpi_fwnode_device_get_match_data, \ .property_present = acpi_fwnode_property_present, \ .property_read_int_array = \ acpi_fwnode_property_read_int_array,\ -- 1.9.1
[PATCH V8 6/7] dmaengine: qcom_hidma: Add support for the new revision
Add support for probing the newer HW and also organize MSI capable hardware into an array for maintenance reasons. Signed-off-by: Sinan Kaya--- drivers/dma/qcom/hidma.c | 34 +- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/drivers/dma/qcom/hidma.c b/drivers/dma/qcom/hidma.c index e366985..c146c6d 100644 --- a/drivers/dma/qcom/hidma.c +++ b/drivers/dma/qcom/hidma.c @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -104,6 +105,9 @@ static void hidma_free(struct hidma_dev *dmadev) module_param(nr_desc_prm, uint, 0644); MODULE_PARM_DESC(nr_desc_prm, "number of descriptors (default: 0)"); +enum hidma_cap { + HIDMA_MSI_CAP = 1, +}; /* process completed descriptors */ static void hidma_process_completed(struct hidma_chan *mchan) @@ -736,25 +740,12 @@ static int hidma_request_msi(struct hidma_dev *dmadev, #endif } -static bool hidma_msi_capable(struct device *dev) +static bool hidma_test_capability(struct device *dev, enum hidma_cap test_cap) { - struct acpi_device *adev = ACPI_COMPANION(dev); - const char *of_compat; - int ret = -EINVAL; - - if (!adev || acpi_disabled) { - ret = device_property_read_string(dev, "compatible", - _compat); - if (ret) - return false; + enum hidma_cap cap; - ret = strcmp(of_compat, "qcom,hidma-1.1"); - } else { -#ifdef CONFIG_ACPI - ret = strcmp(acpi_device_hid(adev), "QCOM8062"); -#endif - } - return ret == 0; + cap = (enum hidma_cap) device_get_match_data(dev); + return cap ? ((cap & test_cap) > 0) : 0; } static int hidma_probe(struct platform_device *pdev) @@ -834,8 +825,7 @@ static int hidma_probe(struct platform_device *pdev) * Determine the MSI capability of the platform. Old HW doesn't * support MSI. */ - msi = hidma_msi_capable(>dev); - + msi = hidma_test_capability(>dev, HIDMA_MSI_CAP); device_property_read_u32(>dev, "desc-count", >nr_descriptors); @@ -953,7 +943,8 @@ static int hidma_remove(struct platform_device *pdev) #if IS_ENABLED(CONFIG_ACPI) static const struct acpi_device_id hidma_acpi_ids[] = { {"QCOM8061"}, - {"QCOM8062"}, + {"QCOM8062", HIDMA_MSI_CAP}, + {"QCOM8063", HIDMA_MSI_CAP}, {}, }; MODULE_DEVICE_TABLE(acpi, hidma_acpi_ids); @@ -961,7 +952,8 @@ static int hidma_remove(struct platform_device *pdev) static const struct of_device_id hidma_match[] = { {.compatible = "qcom,hidma-1.0",}, - {.compatible = "qcom,hidma-1.1",}, + {.compatible = "qcom,hidma-1.1", .data = (void *)(HIDMA_MSI_CAP),}, + {.compatible = "qcom,hidma-1.2", .data = (void *)(HIDMA_MSI_CAP),}, {}, }; MODULE_DEVICE_TABLE(of, hidma_match); -- 1.9.1
[PATCH V8 5/7] ACPI: properties: Implement get_match_data() callback
Now that we have a get_match_data() callback as part of the firmware node, implement the ACPI specific piece for it. Signed-off-by: Sinan Kaya Acked-by: Sakari Ailus --- drivers/acpi/property.c | 8 1 file changed, 8 insertions(+) diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index e26ea20..466d150 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -1271,9 +1271,17 @@ static int acpi_fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode, return 0; } +static void * +acpi_fwnode_device_get_match_data(const struct fwnode_handle *fwnode, + const struct device *dev) +{ + return acpi_get_match_data(dev); +} + #define DECLARE_ACPI_FWNODE_OPS(ops) \ const struct fwnode_operations ops = { \ .device_is_available = acpi_fwnode_device_is_available, \ + .device_get_match_data = acpi_fwnode_device_get_match_data, \ .property_present = acpi_fwnode_property_present, \ .property_read_int_array = \ acpi_fwnode_property_read_int_array,\ -- 1.9.1
[PATCH V8 6/7] dmaengine: qcom_hidma: Add support for the new revision
Add support for probing the newer HW and also organize MSI capable hardware into an array for maintenance reasons. Signed-off-by: Sinan Kaya --- drivers/dma/qcom/hidma.c | 34 +- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/drivers/dma/qcom/hidma.c b/drivers/dma/qcom/hidma.c index e366985..c146c6d 100644 --- a/drivers/dma/qcom/hidma.c +++ b/drivers/dma/qcom/hidma.c @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -104,6 +105,9 @@ static void hidma_free(struct hidma_dev *dmadev) module_param(nr_desc_prm, uint, 0644); MODULE_PARM_DESC(nr_desc_prm, "number of descriptors (default: 0)"); +enum hidma_cap { + HIDMA_MSI_CAP = 1, +}; /* process completed descriptors */ static void hidma_process_completed(struct hidma_chan *mchan) @@ -736,25 +740,12 @@ static int hidma_request_msi(struct hidma_dev *dmadev, #endif } -static bool hidma_msi_capable(struct device *dev) +static bool hidma_test_capability(struct device *dev, enum hidma_cap test_cap) { - struct acpi_device *adev = ACPI_COMPANION(dev); - const char *of_compat; - int ret = -EINVAL; - - if (!adev || acpi_disabled) { - ret = device_property_read_string(dev, "compatible", - _compat); - if (ret) - return false; + enum hidma_cap cap; - ret = strcmp(of_compat, "qcom,hidma-1.1"); - } else { -#ifdef CONFIG_ACPI - ret = strcmp(acpi_device_hid(adev), "QCOM8062"); -#endif - } - return ret == 0; + cap = (enum hidma_cap) device_get_match_data(dev); + return cap ? ((cap & test_cap) > 0) : 0; } static int hidma_probe(struct platform_device *pdev) @@ -834,8 +825,7 @@ static int hidma_probe(struct platform_device *pdev) * Determine the MSI capability of the platform. Old HW doesn't * support MSI. */ - msi = hidma_msi_capable(>dev); - + msi = hidma_test_capability(>dev, HIDMA_MSI_CAP); device_property_read_u32(>dev, "desc-count", >nr_descriptors); @@ -953,7 +943,8 @@ static int hidma_remove(struct platform_device *pdev) #if IS_ENABLED(CONFIG_ACPI) static const struct acpi_device_id hidma_acpi_ids[] = { {"QCOM8061"}, - {"QCOM8062"}, + {"QCOM8062", HIDMA_MSI_CAP}, + {"QCOM8063", HIDMA_MSI_CAP}, {}, }; MODULE_DEVICE_TABLE(acpi, hidma_acpi_ids); @@ -961,7 +952,8 @@ static int hidma_remove(struct platform_device *pdev) static const struct of_device_id hidma_match[] = { {.compatible = "qcom,hidma-1.0",}, - {.compatible = "qcom,hidma-1.1",}, + {.compatible = "qcom,hidma-1.1", .data = (void *)(HIDMA_MSI_CAP),}, + {.compatible = "qcom,hidma-1.2", .data = (void *)(HIDMA_MSI_CAP),}, {}, }; MODULE_DEVICE_TABLE(of, hidma_match); -- 1.9.1
[PATCH V8 7/7] dmaengine: qcom_hidma: Add identity register support
The location for destination event channel register has been relocated from offset 0x28 to 0x40. Update the code accordingly. Signed-off-by: Sinan Kaya--- drivers/dma/qcom/hidma.c | 11 --- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/dma/qcom/hidma.c b/drivers/dma/qcom/hidma.c index c146c6d..963cc52 100644 --- a/drivers/dma/qcom/hidma.c +++ b/drivers/dma/qcom/hidma.c @@ -107,6 +107,7 @@ static void hidma_free(struct hidma_dev *dmadev) enum hidma_cap { HIDMA_MSI_CAP = 1, + HIDMA_IDENTITY_CAP, }; /* process completed descriptors */ @@ -838,7 +839,10 @@ static int hidma_probe(struct platform_device *pdev) if (!dmadev->nr_descriptors) dmadev->nr_descriptors = HIDMA_NR_DEFAULT_DESC; - dmadev->chidx = readl(dmadev->dev_trca + 0x28); + if (hidma_test_capability(>dev, HIDMA_IDENTITY_CAP)) + dmadev->chidx = readl(dmadev->dev_trca + 0x40); + else + dmadev->chidx = readl(dmadev->dev_trca + 0x28); /* Set DMA mask to 64 bits. */ rc = dma_set_mask_and_coherent(>dev, DMA_BIT_MASK(64)); @@ -944,7 +948,7 @@ static int hidma_remove(struct platform_device *pdev) static const struct acpi_device_id hidma_acpi_ids[] = { {"QCOM8061"}, {"QCOM8062", HIDMA_MSI_CAP}, - {"QCOM8063", HIDMA_MSI_CAP}, + {"QCOM8063", (HIDMA_MSI_CAP | HIDMA_IDENTITY_CAP)}, {}, }; MODULE_DEVICE_TABLE(acpi, hidma_acpi_ids); @@ -953,7 +957,8 @@ static int hidma_remove(struct platform_device *pdev) static const struct of_device_id hidma_match[] = { {.compatible = "qcom,hidma-1.0",}, {.compatible = "qcom,hidma-1.1", .data = (void *)(HIDMA_MSI_CAP),}, - {.compatible = "qcom,hidma-1.2", .data = (void *)(HIDMA_MSI_CAP),}, + {.compatible = "qcom,hidma-1.2", +.data = (void *)(HIDMA_MSI_CAP | HIDMA_IDENTITY_CAP),}, {}, }; MODULE_DEVICE_TABLE(of, hidma_match); -- 1.9.1
[PATCH V8 7/7] dmaengine: qcom_hidma: Add identity register support
The location for destination event channel register has been relocated from offset 0x28 to 0x40. Update the code accordingly. Signed-off-by: Sinan Kaya --- drivers/dma/qcom/hidma.c | 11 --- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/dma/qcom/hidma.c b/drivers/dma/qcom/hidma.c index c146c6d..963cc52 100644 --- a/drivers/dma/qcom/hidma.c +++ b/drivers/dma/qcom/hidma.c @@ -107,6 +107,7 @@ static void hidma_free(struct hidma_dev *dmadev) enum hidma_cap { HIDMA_MSI_CAP = 1, + HIDMA_IDENTITY_CAP, }; /* process completed descriptors */ @@ -838,7 +839,10 @@ static int hidma_probe(struct platform_device *pdev) if (!dmadev->nr_descriptors) dmadev->nr_descriptors = HIDMA_NR_DEFAULT_DESC; - dmadev->chidx = readl(dmadev->dev_trca + 0x28); + if (hidma_test_capability(>dev, HIDMA_IDENTITY_CAP)) + dmadev->chidx = readl(dmadev->dev_trca + 0x40); + else + dmadev->chidx = readl(dmadev->dev_trca + 0x28); /* Set DMA mask to 64 bits. */ rc = dma_set_mask_and_coherent(>dev, DMA_BIT_MASK(64)); @@ -944,7 +948,7 @@ static int hidma_remove(struct platform_device *pdev) static const struct acpi_device_id hidma_acpi_ids[] = { {"QCOM8061"}, {"QCOM8062", HIDMA_MSI_CAP}, - {"QCOM8063", HIDMA_MSI_CAP}, + {"QCOM8063", (HIDMA_MSI_CAP | HIDMA_IDENTITY_CAP)}, {}, }; MODULE_DEVICE_TABLE(acpi, hidma_acpi_ids); @@ -953,7 +957,8 @@ static int hidma_remove(struct platform_device *pdev) static const struct of_device_id hidma_match[] = { {.compatible = "qcom,hidma-1.0",}, {.compatible = "qcom,hidma-1.1", .data = (void *)(HIDMA_MSI_CAP),}, - {.compatible = "qcom,hidma-1.2", .data = (void *)(HIDMA_MSI_CAP),}, + {.compatible = "qcom,hidma-1.2", +.data = (void *)(HIDMA_MSI_CAP | HIDMA_IDENTITY_CAP),}, {}, }; MODULE_DEVICE_TABLE(of, hidma_match); -- 1.9.1
[PATCH V8 4/7] OF: properties: Implement get_match_data() callback
Now that we have a get_match_data() callback as part of the firmware node, implement the OF specific piece for it. Signed-off-by: Sinan KayaReviewed-by: Rob Herring Acked-by: Sakari Ailus --- drivers/of/property.c | 8 1 file changed, 8 insertions(+) diff --git a/drivers/of/property.c b/drivers/of/property.c index 8ad33a4..f25d363 100644 --- a/drivers/of/property.c +++ b/drivers/of/property.c @@ -981,10 +981,18 @@ static int of_fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode, return 0; } +static void * +of_fwnode_device_get_match_data(const struct fwnode_handle *fwnode, + const struct device *dev) +{ + return (void *)of_device_get_match_data(dev); +} + const struct fwnode_operations of_fwnode_ops = { .get = of_fwnode_get, .put = of_fwnode_put, .device_is_available = of_fwnode_device_is_available, + .device_get_match_data = of_fwnode_device_get_match_data, .property_present = of_fwnode_property_present, .property_read_int_array = of_fwnode_property_read_int_array, .property_read_string_array = of_fwnode_property_read_string_array, -- 1.9.1
[PATCH V8 4/7] OF: properties: Implement get_match_data() callback
Now that we have a get_match_data() callback as part of the firmware node, implement the OF specific piece for it. Signed-off-by: Sinan Kaya Reviewed-by: Rob Herring Acked-by: Sakari Ailus --- drivers/of/property.c | 8 1 file changed, 8 insertions(+) diff --git a/drivers/of/property.c b/drivers/of/property.c index 8ad33a4..f25d363 100644 --- a/drivers/of/property.c +++ b/drivers/of/property.c @@ -981,10 +981,18 @@ static int of_fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode, return 0; } +static void * +of_fwnode_device_get_match_data(const struct fwnode_handle *fwnode, + const struct device *dev) +{ + return (void *)of_device_get_match_data(dev); +} + const struct fwnode_operations of_fwnode_ops = { .get = of_fwnode_get, .put = of_fwnode_put, .device_is_available = of_fwnode_device_is_available, + .device_get_match_data = of_fwnode_device_get_match_data, .property_present = of_fwnode_property_present, .property_read_int_array = of_fwnode_property_read_int_array, .property_read_string_array = of_fwnode_property_read_string_array, -- 1.9.1
[PATCH V8 2/7] ACPI / bus: Introduce acpi_get_match_data() function
OF has of_device_get_match_data() function to extract driver specific data structure. Add a similar function for ACPI. Signed-off-by: Sinan KayaAcked-by: Rafael J. Wysocki --- drivers/acpi/bus.c | 18 ++ include/linux/acpi.h | 6 ++ 2 files changed, 24 insertions(+) diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 4d0979e..f87ed3b 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -785,6 +785,24 @@ const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids, } EXPORT_SYMBOL_GPL(acpi_match_device); +void *acpi_get_match_data(const struct device *dev) +{ + const struct acpi_device_id *match; + + if (!dev->driver) + return NULL; + + if (!dev->driver->acpi_match_table) + return NULL; + + match = acpi_match_device(dev->driver->acpi_match_table, dev); + if (!match) + return NULL; + + return (void *)match->driver_data; +} +EXPORT_SYMBOL_GPL(acpi_get_match_data); + int acpi_match_device_ids(struct acpi_device *device, const struct acpi_device_id *ids) { diff --git a/include/linux/acpi.h b/include/linux/acpi.h index dc1ebfe..9278737 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -584,6 +584,7 @@ extern int acpi_nvs_for_each_region(int (*func)(__u64, __u64, void *), const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids, const struct device *dev); +void *acpi_get_match_data(const struct device *dev); extern bool acpi_driver_match_device(struct device *dev, const struct device_driver *drv); int acpi_device_uevent_modalias(struct device *, struct kobj_uevent_env *); @@ -755,6 +756,11 @@ static inline const struct acpi_device_id *acpi_match_device( return NULL; } +static inline void *acpi_get_match_data(const struct device *dev) +{ + return NULL; +} + static inline bool acpi_driver_match_device(struct device *dev, const struct device_driver *drv) { -- 1.9.1
[PATCH V8 2/7] ACPI / bus: Introduce acpi_get_match_data() function
OF has of_device_get_match_data() function to extract driver specific data structure. Add a similar function for ACPI. Signed-off-by: Sinan Kaya Acked-by: Rafael J. Wysocki --- drivers/acpi/bus.c | 18 ++ include/linux/acpi.h | 6 ++ 2 files changed, 24 insertions(+) diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 4d0979e..f87ed3b 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -785,6 +785,24 @@ const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids, } EXPORT_SYMBOL_GPL(acpi_match_device); +void *acpi_get_match_data(const struct device *dev) +{ + const struct acpi_device_id *match; + + if (!dev->driver) + return NULL; + + if (!dev->driver->acpi_match_table) + return NULL; + + match = acpi_match_device(dev->driver->acpi_match_table, dev); + if (!match) + return NULL; + + return (void *)match->driver_data; +} +EXPORT_SYMBOL_GPL(acpi_get_match_data); + int acpi_match_device_ids(struct acpi_device *device, const struct acpi_device_id *ids) { diff --git a/include/linux/acpi.h b/include/linux/acpi.h index dc1ebfe..9278737 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -584,6 +584,7 @@ extern int acpi_nvs_for_each_region(int (*func)(__u64, __u64, void *), const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids, const struct device *dev); +void *acpi_get_match_data(const struct device *dev); extern bool acpi_driver_match_device(struct device *dev, const struct device_driver *drv); int acpi_device_uevent_modalias(struct device *, struct kobj_uevent_env *); @@ -755,6 +756,11 @@ static inline const struct acpi_device_id *acpi_match_device( return NULL; } +static inline void *acpi_get_match_data(const struct device *dev) +{ + return NULL; +} + static inline bool acpi_driver_match_device(struct device *dev, const struct device_driver *drv) { -- 1.9.1
Re: [PATCH -mm] mm, swap: Fix race between swapoff and some swap operations
Hi Huang, Sorry for the late response. I'm in middle of long vacation. On Fri, Dec 08, 2017 at 08:32:16PM +0800, Huang, Ying wrote: > Minchan Kimwrites: > > > On Fri, Dec 08, 2017 at 04:41:38PM +0800, Huang, Ying wrote: > >> Minchan Kim writes: > >> > >> > On Fri, Dec 08, 2017 at 01:41:10PM +0800, Huang, Ying wrote: > >> >> Minchan Kim writes: > >> >> > >> >> > On Thu, Dec 07, 2017 at 04:29:37PM -0800, Andrew Morton wrote: > >> >> >> On Thu, 7 Dec 2017 09:14:26 +0800 "Huang, Ying" > >> >> >> wrote: > >> >> >> > >> >> >> > When the swapin is performed, after getting the swap entry > >> >> >> > information > >> >> >> > from the page table, the PTL (page table lock) will be released, > >> >> >> > then > >> >> >> > system will go to swap in the swap entry, without any lock held to > >> >> >> > prevent the swap device from being swapoff. This may cause the > >> >> >> > race > >> >> >> > like below, > >> >> >> > > >> >> >> > CPU 1 CPU 2 > >> >> >> > - - > >> >> >> >do_swap_page > >> >> >> > swapin_readahead > >> >> >> >__read_swap_cache_async > >> >> >> > swapoff swapcache_prepare > >> >> >> > p->swap_map = NULL __swap_duplicate > >> >> >> > p->swap_map[?] /* !!! NULL > >> >> >> > pointer access */ > >> >> >> > > >> >> >> > Because swap off is usually done when system shutdown only, the > >> >> >> > race > >> >> >> > may not hit many people in practice. But it is still a race need > >> >> >> > to > >> >> >> > be fixed. > >> >> >> > >> >> >> swapoff is so rare that it's hard to get motivated about any fix > >> >> >> which > >> >> >> adds overhead to the regular codepaths. > >> >> > > >> >> > That was my concern, too when I see this patch. > >> >> > > >> >> >> > >> >> >> Is there something we can do to ensure that all the overhead of this > >> >> >> fix is placed into the swapoff side? stop_machine() may be a bit > >> >> >> brutal, but a surprising amount of code uses it. Any other ideas? > >> >> > > >> >> > How about this? > >> >> > > >> >> > I think It's same approach with old where we uses si->lock everywhere > >> >> > instead of more fine-grained cluster lock. > >> >> > > >> >> > The reason I repeated to reset p->max to zero in the loop is to avoid > >> >> > using lockdep annotation(maybe, spin_lock_nested(something) to prevent > >> >> > false positive. > >> >> > > >> >> > diff --git a/mm/swapfile.c b/mm/swapfile.c > >> >> > index 42fe5653814a..9ce007a42bbc 100644 > >> >> > --- a/mm/swapfile.c > >> >> > +++ b/mm/swapfile.c > >> >> > @@ -2644,6 +2644,19 @@ SYSCALL_DEFINE1(swapoff, const char __user *, > >> >> > specialfile) > >> >> > swap_file = p->swap_file; > >> >> > old_block_size = p->old_block_size; > >> >> > p->swap_file = NULL; > >> >> > + > >> >> > + if (p->flags & SWP_SOLIDSTATE) { > >> >> > + unsigned long ci, nr_cluster; > >> >> > + > >> >> > + nr_cluster = DIV_ROUND_UP(p->max, SWAPFILE_CLUSTER); > >> >> > + for (ci = 0; ci < nr_cluster; ci++) { > >> >> > + struct swap_cluster_info *sci; > >> >> > + > >> >> > + sci = lock_cluster(p, ci * SWAPFILE_CLUSTER); > >> >> > + p->max = 0; > >> >> > + unlock_cluster(sci); > >> >> > + } > >> >> > + } > >> >> > p->max = 0; > >> >> > swap_map = p->swap_map; > >> >> > p->swap_map = NULL; > >> >> > @@ -3369,10 +3382,10 @@ static int __swap_duplicate(swp_entry_t > >> >> > entry, unsigned char usage) > >> >> > goto bad_file; > >> >> > p = swap_info[type]; > >> >> > offset = swp_offset(entry); > >> >> > - if (unlikely(offset >= p->max)) > >> >> > - goto out; > >> >> > > >> >> > ci = lock_cluster_or_swap_info(p, offset); > >> >> > + if (unlikely(offset >= p->max)) > >> >> > + goto unlock_out; > >> >> > > >> >> > count = p->swap_map[offset]; > >> >> > > >> >> > >> >> Sorry, this doesn't work, because > >> >> > >> >> lock_cluster_or_swap_info() > >> >> > >> >> Need to read p->cluster_info, which may be freed during swapoff too. > >> >> > >> >> > >> >> To reduce the added overhead in regular code path, Maybe we can use SRCU > >> >> to implement get_swap_device() and put_swap_device()? There is only > >> >> increment/decrement on CPU local variable in srcu_read_lock/unlock(). > >> >> Should be acceptable in not so hot swap path? > >> >> > >> >> This needs to select CONFIG_SRCU if CONFIG_SWAP is enabled. But I guess > >> >> that should be acceptable too? > >> >> > >> > > >> > Why do we need srcu here? Is it enough with rcu like below? > >> > > >> > It might have a
Re: [PATCH -mm] mm, swap: Fix race between swapoff and some swap operations
Hi Huang, Sorry for the late response. I'm in middle of long vacation. On Fri, Dec 08, 2017 at 08:32:16PM +0800, Huang, Ying wrote: > Minchan Kim writes: > > > On Fri, Dec 08, 2017 at 04:41:38PM +0800, Huang, Ying wrote: > >> Minchan Kim writes: > >> > >> > On Fri, Dec 08, 2017 at 01:41:10PM +0800, Huang, Ying wrote: > >> >> Minchan Kim writes: > >> >> > >> >> > On Thu, Dec 07, 2017 at 04:29:37PM -0800, Andrew Morton wrote: > >> >> >> On Thu, 7 Dec 2017 09:14:26 +0800 "Huang, Ying" > >> >> >> wrote: > >> >> >> > >> >> >> > When the swapin is performed, after getting the swap entry > >> >> >> > information > >> >> >> > from the page table, the PTL (page table lock) will be released, > >> >> >> > then > >> >> >> > system will go to swap in the swap entry, without any lock held to > >> >> >> > prevent the swap device from being swapoff. This may cause the > >> >> >> > race > >> >> >> > like below, > >> >> >> > > >> >> >> > CPU 1 CPU 2 > >> >> >> > - - > >> >> >> >do_swap_page > >> >> >> > swapin_readahead > >> >> >> >__read_swap_cache_async > >> >> >> > swapoff swapcache_prepare > >> >> >> > p->swap_map = NULL __swap_duplicate > >> >> >> > p->swap_map[?] /* !!! NULL > >> >> >> > pointer access */ > >> >> >> > > >> >> >> > Because swap off is usually done when system shutdown only, the > >> >> >> > race > >> >> >> > may not hit many people in practice. But it is still a race need > >> >> >> > to > >> >> >> > be fixed. > >> >> >> > >> >> >> swapoff is so rare that it's hard to get motivated about any fix > >> >> >> which > >> >> >> adds overhead to the regular codepaths. > >> >> > > >> >> > That was my concern, too when I see this patch. > >> >> > > >> >> >> > >> >> >> Is there something we can do to ensure that all the overhead of this > >> >> >> fix is placed into the swapoff side? stop_machine() may be a bit > >> >> >> brutal, but a surprising amount of code uses it. Any other ideas? > >> >> > > >> >> > How about this? > >> >> > > >> >> > I think It's same approach with old where we uses si->lock everywhere > >> >> > instead of more fine-grained cluster lock. > >> >> > > >> >> > The reason I repeated to reset p->max to zero in the loop is to avoid > >> >> > using lockdep annotation(maybe, spin_lock_nested(something) to prevent > >> >> > false positive. > >> >> > > >> >> > diff --git a/mm/swapfile.c b/mm/swapfile.c > >> >> > index 42fe5653814a..9ce007a42bbc 100644 > >> >> > --- a/mm/swapfile.c > >> >> > +++ b/mm/swapfile.c > >> >> > @@ -2644,6 +2644,19 @@ SYSCALL_DEFINE1(swapoff, const char __user *, > >> >> > specialfile) > >> >> > swap_file = p->swap_file; > >> >> > old_block_size = p->old_block_size; > >> >> > p->swap_file = NULL; > >> >> > + > >> >> > + if (p->flags & SWP_SOLIDSTATE) { > >> >> > + unsigned long ci, nr_cluster; > >> >> > + > >> >> > + nr_cluster = DIV_ROUND_UP(p->max, SWAPFILE_CLUSTER); > >> >> > + for (ci = 0; ci < nr_cluster; ci++) { > >> >> > + struct swap_cluster_info *sci; > >> >> > + > >> >> > + sci = lock_cluster(p, ci * SWAPFILE_CLUSTER); > >> >> > + p->max = 0; > >> >> > + unlock_cluster(sci); > >> >> > + } > >> >> > + } > >> >> > p->max = 0; > >> >> > swap_map = p->swap_map; > >> >> > p->swap_map = NULL; > >> >> > @@ -3369,10 +3382,10 @@ static int __swap_duplicate(swp_entry_t > >> >> > entry, unsigned char usage) > >> >> > goto bad_file; > >> >> > p = swap_info[type]; > >> >> > offset = swp_offset(entry); > >> >> > - if (unlikely(offset >= p->max)) > >> >> > - goto out; > >> >> > > >> >> > ci = lock_cluster_or_swap_info(p, offset); > >> >> > + if (unlikely(offset >= p->max)) > >> >> > + goto unlock_out; > >> >> > > >> >> > count = p->swap_map[offset]; > >> >> > > >> >> > >> >> Sorry, this doesn't work, because > >> >> > >> >> lock_cluster_or_swap_info() > >> >> > >> >> Need to read p->cluster_info, which may be freed during swapoff too. > >> >> > >> >> > >> >> To reduce the added overhead in regular code path, Maybe we can use SRCU > >> >> to implement get_swap_device() and put_swap_device()? There is only > >> >> increment/decrement on CPU local variable in srcu_read_lock/unlock(). > >> >> Should be acceptable in not so hot swap path? > >> >> > >> >> This needs to select CONFIG_SRCU if CONFIG_SWAP is enabled. But I guess > >> >> that should be acceptable too? > >> >> > >> > > >> > Why do we need srcu here? Is it enough with rcu like below? > >> > > >> > It might have a bug/room to be optimized about performance/naming. > >> > I just wanted to show my
Re: [PATCH] iommu/vt-d: Fix shift overflow in qi_flush_dev_iotlb
On Tue, Dec 12, 2017 at 03:43:08PM -0700, Alex Williamson wrote: [...] > diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c > index 9a7ffd13c7f0..87888b102057 100644 > --- a/drivers/iommu/dmar.c > +++ b/drivers/iommu/dmar.c > @@ -1345,7 +1345,9 @@ void qi_flush_dev_iotlb(struct intel_iommu *iommu, u16 > sid, u16 qdep, > struct qi_desc desc; > > if (mask) { > - BUG_ON(addr & ((1 << (VTD_PAGE_SHIFT + mask)) - 1)); > + BUG_ON((mask > MAX_AGAW_PFN_WIDTH) || > +((mask == MAX_AGAW_PFN_WIDTH) && addr) || > +(addr & ((1 << (VTD_PAGE_SHIFT + mask)) - 1))); Could it work if we just use 1ULL instead of 1 here? Thanks, -- Peter Xu
Re: [PATCH] iommu/vt-d: Fix shift overflow in qi_flush_dev_iotlb
On Tue, Dec 12, 2017 at 03:43:08PM -0700, Alex Williamson wrote: [...] > diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c > index 9a7ffd13c7f0..87888b102057 100644 > --- a/drivers/iommu/dmar.c > +++ b/drivers/iommu/dmar.c > @@ -1345,7 +1345,9 @@ void qi_flush_dev_iotlb(struct intel_iommu *iommu, u16 > sid, u16 qdep, > struct qi_desc desc; > > if (mask) { > - BUG_ON(addr & ((1 << (VTD_PAGE_SHIFT + mask)) - 1)); > + BUG_ON((mask > MAX_AGAW_PFN_WIDTH) || > +((mask == MAX_AGAW_PFN_WIDTH) && addr) || > +(addr & ((1 << (VTD_PAGE_SHIFT + mask)) - 1))); Could it work if we just use 1ULL instead of 1 here? Thanks, -- Peter Xu
Re: About the try to remove cross-release feature entirely by Ingo
On Wed, Dec 13, 2017 at 3:24 PM, Byungchul Parkwrote: > Lockdep works, based on the following: > >(1) Classifying locks properly >(2) Checking relationship between the classes > > If (1) is not good or (2) is not good, then we > might get false positives. > > For (1), we don't have to classify locks 100% > properly but need as enough as lockdep works. > > For (2), we should have a mechanism w/o > logical defects. > > Cross-release added an additional capacity to > (2) and requires (1) to get more precisely classified. > > Since the current classification level is too low for > cross-release to work, false positives are being > reported frequently with enabling cross-release. > Yes. It's a obvious problem. It needs to be off by > default until the classification is done by the level > that cross-release requires. > > But, the logic (2) is valid and logically true. Please > keep the code, mechanism, and logic. In addition, I want to say that the current level of classification is much less than 100% but, since we have annotated well to suppress wrong reports by rough classifications, finally it does not come into view by original lockdep for now. But since cross-release makes the dependency graph more fine-grained, it easily comes into view. Even w/o cross-release, it can happen by adding additional dependencies connecting two roughly classified lock classes in the future. Furthermore, I can see many places in kernel to consider wait_for_completion() using manual lock_acquire()/lock_release() and the rate using it raises. In other words, even without cross-release, the more we add manual annotations for wait_for_completion() the more we definitely suffer same problems someday, we are facing now through cross-release. Therefore, I want to say the fundamental problem comes from classification, not cross-release specific. Of course, since cross-release accelerates the condition, I agree with it to be off for now. -- Thanks, Byungchul
Re: About the try to remove cross-release feature entirely by Ingo
On Wed, Dec 13, 2017 at 3:24 PM, Byungchul Park wrote: > Lockdep works, based on the following: > >(1) Classifying locks properly >(2) Checking relationship between the classes > > If (1) is not good or (2) is not good, then we > might get false positives. > > For (1), we don't have to classify locks 100% > properly but need as enough as lockdep works. > > For (2), we should have a mechanism w/o > logical defects. > > Cross-release added an additional capacity to > (2) and requires (1) to get more precisely classified. > > Since the current classification level is too low for > cross-release to work, false positives are being > reported frequently with enabling cross-release. > Yes. It's a obvious problem. It needs to be off by > default until the classification is done by the level > that cross-release requires. > > But, the logic (2) is valid and logically true. Please > keep the code, mechanism, and logic. In addition, I want to say that the current level of classification is much less than 100% but, since we have annotated well to suppress wrong reports by rough classifications, finally it does not come into view by original lockdep for now. But since cross-release makes the dependency graph more fine-grained, it easily comes into view. Even w/o cross-release, it can happen by adding additional dependencies connecting two roughly classified lock classes in the future. Furthermore, I can see many places in kernel to consider wait_for_completion() using manual lock_acquire()/lock_release() and the rate using it raises. In other words, even without cross-release, the more we add manual annotations for wait_for_completion() the more we definitely suffer same problems someday, we are facing now through cross-release. Therefore, I want to say the fundamental problem comes from classification, not cross-release specific. Of course, since cross-release accelerates the condition, I agree with it to be off for now. -- Thanks, Byungchul
[PATCH v3] perf evsel: Enable ignore_missing_thread for pid option
While monitoring a multithread process with pid option, perf sometimes may return sys_perf_event_open failure with 3(No such process) if any of the process's threads die before we open the event. However, we want perf continue monitoring the remaining threads and do not exit with error. Here, the patch enables perf_evsel::ignore_missing_thread for -p option to ignore complete failure if any of threads die before we open the event. But it may still return sys_perf_event_open failure with 22(Invalid) if we monitors several event groups. sys_perf_event_open: pid 28960 cpu 40 group_fd 118202 flags 0x8 sys_perf_event_open: pid 28961 cpu 40 group_fd 118203 flags 0x8 WARNING: Ignored open failure for pid 28962 sys_perf_event_open: pid 28962 cpu 40 group_fd [118203] flags 0x8 sys_perf_event_open failed, error -22 That is because when we ignore a missing thread, we change the thread_idx without dealing with its fds, FD(evsel, cpu, thread). Then get_group_fd() may return a wrong group_fd for the next thread and sys_perf_event_open() return with 22. sys_perf_event_open(){ ... if (group_fd != -1) perf_fget_light()//to get corresponding group_leader by group_fd ... if (group_leader) if (group_leader->ctx->task != ctx->task)//should on the same task goto err_context ... } This patch also fixes this bug by introducing perf_evsel__remove_fd() and update_fds to allow removing fds for the missing thread. Changes since v1: - Change group_fd__remove() into a more genetic way without changing code logic - Remove redundant condition Changes since v2: - Use a proper function name and add some comment. - Multiline comment style fixes. Signed-off-by: Mengting Zhang--- tools/perf/builtin-record.c | 4 ++-- tools/perf/util/evsel.c | 48 +++-- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 0032559..36b6213 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -1781,8 +1781,8 @@ int cmd_record(int argc, const char **argv) goto out; } - /* Enable ignoring missing threads when -u option is defined. */ - rec->opts.ignore_missing_thread = rec->opts.target.uid != UINT_MAX; + /* Enable ignoring missing threads when -u/-p option is defined. */ + rec->opts.ignore_missing_thread = rec->opts.target.uid != UINT_MAX || rec->opts.target.pid; err = -ENOMEM; if (perf_evlist__create_maps(rec->evlist, >opts.target) < 0) diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index d5fbcf8..a0a3df7 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -1596,10 +1596,47 @@ static int __open_attr__fprintf(FILE *fp, const char *name, const char *val, return fprintf(fp, " %-32s %s\n", name, val); } +static void perf_evsel__remove_fd(struct perf_evsel *pos, + int nr_cpus, int nr_threads, + int thread_idx) +{ + for (int cpu = 0; cpu < nr_cpus; cpu++) + for (int thread = thread_idx; thread < nr_threads - 1; thread++) + FD(pos, cpu, thread) = FD(pos, cpu, thread + 1); +} + +static int update_fds(struct perf_evsel *evsel, + int nr_cpus, int cpu_idx, + int nr_threads, int thread_idx) +{ + struct perf_evsel *pos; + struct perf_evlist *evlist = evsel->evlist; + + if (cpu_idx >= nr_cpus || thread_idx >= nr_threads) + return -EINVAL; + + evlist__for_each_entry(evlist, pos) { + nr_cpus = pos != evsel ? nr_cpus : cpu_idx; + + perf_evsel__remove_fd(pos, nr_cpus, nr_threads, thread_idx); + + /* +* Since fds for next evsel has not been created, +* there is no need to iterate whole event list. +*/ + if (pos == evsel) + break; + } + return 0; +} + static bool ignore_missing_thread(struct perf_evsel *evsel, + int nr_cpus, int cpu, struct thread_map *threads, int thread, int err) { + pid_t ignore_pid = thread_map__pid(threads, thread); + if (!evsel->ignore_missing_thread) return false; @@ -1615,11 +1652,18 @@ static bool ignore_missing_thread(struct perf_evsel *evsel, if (threads->nr == 1) return false; + /* +* We should remove fd for missing_thread first +* because thread_map__remove() will decrease threads->nr. +*/ + if (update_fds(evsel, nr_cpus, cpu, threads->nr, thread)) + return false; +
[PATCH v3] perf evsel: Enable ignore_missing_thread for pid option
While monitoring a multithread process with pid option, perf sometimes may return sys_perf_event_open failure with 3(No such process) if any of the process's threads die before we open the event. However, we want perf continue monitoring the remaining threads and do not exit with error. Here, the patch enables perf_evsel::ignore_missing_thread for -p option to ignore complete failure if any of threads die before we open the event. But it may still return sys_perf_event_open failure with 22(Invalid) if we monitors several event groups. sys_perf_event_open: pid 28960 cpu 40 group_fd 118202 flags 0x8 sys_perf_event_open: pid 28961 cpu 40 group_fd 118203 flags 0x8 WARNING: Ignored open failure for pid 28962 sys_perf_event_open: pid 28962 cpu 40 group_fd [118203] flags 0x8 sys_perf_event_open failed, error -22 That is because when we ignore a missing thread, we change the thread_idx without dealing with its fds, FD(evsel, cpu, thread). Then get_group_fd() may return a wrong group_fd for the next thread and sys_perf_event_open() return with 22. sys_perf_event_open(){ ... if (group_fd != -1) perf_fget_light()//to get corresponding group_leader by group_fd ... if (group_leader) if (group_leader->ctx->task != ctx->task)//should on the same task goto err_context ... } This patch also fixes this bug by introducing perf_evsel__remove_fd() and update_fds to allow removing fds for the missing thread. Changes since v1: - Change group_fd__remove() into a more genetic way without changing code logic - Remove redundant condition Changes since v2: - Use a proper function name and add some comment. - Multiline comment style fixes. Signed-off-by: Mengting Zhang --- tools/perf/builtin-record.c | 4 ++-- tools/perf/util/evsel.c | 48 +++-- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 0032559..36b6213 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -1781,8 +1781,8 @@ int cmd_record(int argc, const char **argv) goto out; } - /* Enable ignoring missing threads when -u option is defined. */ - rec->opts.ignore_missing_thread = rec->opts.target.uid != UINT_MAX; + /* Enable ignoring missing threads when -u/-p option is defined. */ + rec->opts.ignore_missing_thread = rec->opts.target.uid != UINT_MAX || rec->opts.target.pid; err = -ENOMEM; if (perf_evlist__create_maps(rec->evlist, >opts.target) < 0) diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index d5fbcf8..a0a3df7 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -1596,10 +1596,47 @@ static int __open_attr__fprintf(FILE *fp, const char *name, const char *val, return fprintf(fp, " %-32s %s\n", name, val); } +static void perf_evsel__remove_fd(struct perf_evsel *pos, + int nr_cpus, int nr_threads, + int thread_idx) +{ + for (int cpu = 0; cpu < nr_cpus; cpu++) + for (int thread = thread_idx; thread < nr_threads - 1; thread++) + FD(pos, cpu, thread) = FD(pos, cpu, thread + 1); +} + +static int update_fds(struct perf_evsel *evsel, + int nr_cpus, int cpu_idx, + int nr_threads, int thread_idx) +{ + struct perf_evsel *pos; + struct perf_evlist *evlist = evsel->evlist; + + if (cpu_idx >= nr_cpus || thread_idx >= nr_threads) + return -EINVAL; + + evlist__for_each_entry(evlist, pos) { + nr_cpus = pos != evsel ? nr_cpus : cpu_idx; + + perf_evsel__remove_fd(pos, nr_cpus, nr_threads, thread_idx); + + /* +* Since fds for next evsel has not been created, +* there is no need to iterate whole event list. +*/ + if (pos == evsel) + break; + } + return 0; +} + static bool ignore_missing_thread(struct perf_evsel *evsel, + int nr_cpus, int cpu, struct thread_map *threads, int thread, int err) { + pid_t ignore_pid = thread_map__pid(threads, thread); + if (!evsel->ignore_missing_thread) return false; @@ -1615,11 +1652,18 @@ static bool ignore_missing_thread(struct perf_evsel *evsel, if (threads->nr == 1) return false; + /* +* We should remove fd for missing_thread first +* because thread_map__remove() will decrease threads->nr. +*/ + if (update_fds(evsel, nr_cpus, cpu, threads->nr, thread)) + return false; + if
Re: [PATCH] vfio: Simplify capability helper
On 2017.12.13 12:13:34 +1100, Alexey Kardashevskiy wrote: > On 13/12/17 06:59, Alex Williamson wrote: > > The vfio_info_add_capability() helper requires the caller to pass a > > capability ID, which it then uses to fill in header fields, assuming > > hard coded versions. This makes for an awkward and rigid interface. > > The only thing we want this helper to do is allocate sufficient > > space in the caps buffer and chain this capability into the list. > > Reduce it to that simple task. > > > > Signed-off-by: Alex Williamson> > > Makes more sense now, thanks. I'll repost mine on top of this. > > > Reviewed-by: Alexey Kardashevskiy > > Looks good for KVMGT part. Acked-by: Zhenyu Wang > Below one observation, unrelated to this patch. > > > --- > > drivers/gpu/drm/i915/gvt/kvmgt.c | 15 +++ > > drivers/vfio/pci/vfio_pci.c | 14 ++ > > drivers/vfio/vfio.c | 52 > > +++--- > > include/linux/vfio.h |3 +- > > 4 files changed, 24 insertions(+), 60 deletions(-) > > > > diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c > > b/drivers/gpu/drm/i915/gvt/kvmgt.c > > index 96060920a6fe..0a7d084da1a2 100644 > > --- a/drivers/gpu/drm/i915/gvt/kvmgt.c > > +++ b/drivers/gpu/drm/i915/gvt/kvmgt.c > > @@ -1012,6 +1012,8 @@ static long intel_vgpu_ioctl(struct mdev_device > > *mdev, unsigned int cmd, > > if (!sparse) > > return -ENOMEM; > > > > + sparse->header.id = VFIO_REGION_INFO_CAP_SPARSE_MMAP; > > + sparse->header.version = 1; > > sparse->nr_areas = nr_areas; > > cap_type_id = VFIO_REGION_INFO_CAP_SPARSE_MMAP; > > > @cap_type_id is initialized in just one of many cases of switch > (info.index) and after the entire switch, there is switch (cap_type_id). I > wonder why compiler missed "potentially uninitialized variable here, > although there is no bug - @cap_type_id is in sync with @spapse. It would > make it cleaner imho just to have vfio_info_add_capability() next to the > header initialization. > yeah, we could clean that up, thanks for pointing out. > > > > sparse->areas[0].offset = > > @@ -1033,7 +1035,9 @@ static long intel_vgpu_ioctl(struct mdev_device > > *mdev, unsigned int cmd, > > break; > > default: > > { > > - struct vfio_region_info_cap_type cap_type; > > + struct vfio_region_info_cap_type cap_type = { > > + .header.id = VFIO_REGION_INFO_CAP_TYPE, > > + .header.version = 1 }; > > > > if (info.index >= VFIO_PCI_NUM_REGIONS + > > vgpu->vdev.num_regions) > > @@ -1050,8 +1054,8 @@ static long intel_vgpu_ioctl(struct mdev_device > > *mdev, unsigned int cmd, > > cap_type.subtype = vgpu->vdev.region[i].subtype; > > > > ret = vfio_info_add_capability(, > > - VFIO_REGION_INFO_CAP_TYPE, > > - _type); > > + _type.header, > > + sizeof(cap_type)); > > if (ret) > > return ret; > > } > > @@ -1061,8 +1065,9 @@ static long intel_vgpu_ioctl(struct mdev_device > > *mdev, unsigned int cmd, > > switch (cap_type_id) { > > case VFIO_REGION_INFO_CAP_SPARSE_MMAP: > > ret = vfio_info_add_capability(, > > - VFIO_REGION_INFO_CAP_SPARSE_MMAP, > > - sparse); > > + >header, sizeof(*sparse) + > > + (sparse->nr_areas * > > + sizeof(*sparse->areas))); > > kfree(sparse); > > if (ret) > > return ret; > > diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c > > index f041b1a6cf66..a73e40983880 100644 > > --- a/drivers/vfio/pci/vfio_pci.c > > +++ b/drivers/vfio/pci/vfio_pci.c > > @@ -582,6 +582,8 @@ static int msix_sparse_mmap_cap(struct vfio_pci_device > > *vdev, > > if (!sparse) > > return -ENOMEM; > > > > + sparse->header.id = VFIO_REGION_INFO_CAP_SPARSE_MMAP; > > + sparse->header.version = 1; > > sparse->nr_areas = nr_areas; > > > > if (vdev->msix_offset & PAGE_MASK) { > > @@ -597,8 +599,7 @@ static int msix_sparse_mmap_cap(struct vfio_pci_device > > *vdev, > > i++;
Re: [PATCH] vfio: Simplify capability helper
On 2017.12.13 12:13:34 +1100, Alexey Kardashevskiy wrote: > On 13/12/17 06:59, Alex Williamson wrote: > > The vfio_info_add_capability() helper requires the caller to pass a > > capability ID, which it then uses to fill in header fields, assuming > > hard coded versions. This makes for an awkward and rigid interface. > > The only thing we want this helper to do is allocate sufficient > > space in the caps buffer and chain this capability into the list. > > Reduce it to that simple task. > > > > Signed-off-by: Alex Williamson > > > Makes more sense now, thanks. I'll repost mine on top of this. > > > Reviewed-by: Alexey Kardashevskiy > > Looks good for KVMGT part. Acked-by: Zhenyu Wang > Below one observation, unrelated to this patch. > > > --- > > drivers/gpu/drm/i915/gvt/kvmgt.c | 15 +++ > > drivers/vfio/pci/vfio_pci.c | 14 ++ > > drivers/vfio/vfio.c | 52 > > +++--- > > include/linux/vfio.h |3 +- > > 4 files changed, 24 insertions(+), 60 deletions(-) > > > > diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c > > b/drivers/gpu/drm/i915/gvt/kvmgt.c > > index 96060920a6fe..0a7d084da1a2 100644 > > --- a/drivers/gpu/drm/i915/gvt/kvmgt.c > > +++ b/drivers/gpu/drm/i915/gvt/kvmgt.c > > @@ -1012,6 +1012,8 @@ static long intel_vgpu_ioctl(struct mdev_device > > *mdev, unsigned int cmd, > > if (!sparse) > > return -ENOMEM; > > > > + sparse->header.id = VFIO_REGION_INFO_CAP_SPARSE_MMAP; > > + sparse->header.version = 1; > > sparse->nr_areas = nr_areas; > > cap_type_id = VFIO_REGION_INFO_CAP_SPARSE_MMAP; > > > @cap_type_id is initialized in just one of many cases of switch > (info.index) and after the entire switch, there is switch (cap_type_id). I > wonder why compiler missed "potentially uninitialized variable here, > although there is no bug - @cap_type_id is in sync with @spapse. It would > make it cleaner imho just to have vfio_info_add_capability() next to the > header initialization. > yeah, we could clean that up, thanks for pointing out. > > > > sparse->areas[0].offset = > > @@ -1033,7 +1035,9 @@ static long intel_vgpu_ioctl(struct mdev_device > > *mdev, unsigned int cmd, > > break; > > default: > > { > > - struct vfio_region_info_cap_type cap_type; > > + struct vfio_region_info_cap_type cap_type = { > > + .header.id = VFIO_REGION_INFO_CAP_TYPE, > > + .header.version = 1 }; > > > > if (info.index >= VFIO_PCI_NUM_REGIONS + > > vgpu->vdev.num_regions) > > @@ -1050,8 +1054,8 @@ static long intel_vgpu_ioctl(struct mdev_device > > *mdev, unsigned int cmd, > > cap_type.subtype = vgpu->vdev.region[i].subtype; > > > > ret = vfio_info_add_capability(, > > - VFIO_REGION_INFO_CAP_TYPE, > > - _type); > > + _type.header, > > + sizeof(cap_type)); > > if (ret) > > return ret; > > } > > @@ -1061,8 +1065,9 @@ static long intel_vgpu_ioctl(struct mdev_device > > *mdev, unsigned int cmd, > > switch (cap_type_id) { > > case VFIO_REGION_INFO_CAP_SPARSE_MMAP: > > ret = vfio_info_add_capability(, > > - VFIO_REGION_INFO_CAP_SPARSE_MMAP, > > - sparse); > > + >header, sizeof(*sparse) + > > + (sparse->nr_areas * > > + sizeof(*sparse->areas))); > > kfree(sparse); > > if (ret) > > return ret; > > diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c > > index f041b1a6cf66..a73e40983880 100644 > > --- a/drivers/vfio/pci/vfio_pci.c > > +++ b/drivers/vfio/pci/vfio_pci.c > > @@ -582,6 +582,8 @@ static int msix_sparse_mmap_cap(struct vfio_pci_device > > *vdev, > > if (!sparse) > > return -ENOMEM; > > > > + sparse->header.id = VFIO_REGION_INFO_CAP_SPARSE_MMAP; > > + sparse->header.version = 1; > > sparse->nr_areas = nr_areas; > > > > if (vdev->msix_offset & PAGE_MASK) { > > @@ -597,8 +599,7 @@ static int msix_sparse_mmap_cap(struct vfio_pci_device > > *vdev, > > i++; > > } > > > > - ret = vfio_info_add_capability(caps,
[PATCH] KVM: arm/arm64: don't set vtimer->cnt_ctl in kvm_arch_timer_handler
In our Armv8a server (qualcomm Amberwing, non VHE), after applying Christoffer's timer optimizing patchset(Optimize arch timer register handling), the guest is hang during kernel booting. The error root cause might be as follows: 1. in kvm_arch_timer_handler, it reset vtimer->cnt_ctl with current cntv_ctl register value. And then it missed some cases to update timer's irq (irq.level) when kvm_timer_irq_can_fire() is false 2. It causes kvm_vcpu_check_block return 0 instead of -EINTR kvm_vcpu_check_block kvm_cpu_has_pending_timer kvm_timer_is_pending kvm_timer_should_fire 3. Thus, the kvm hyp code can not break the loop in kvm_vcpu_block (halt poll process) and the guest is hang forever Fixes: b103cc3f10c0 ("KVM: arm/arm64: Avoid timer save/restore in vcpu entry/exit") Signed-off-by: Jia He--- virt/kvm/arm/arch_timer.c | 1 - 1 file changed, 1 deletion(-) diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c index f9555b1..bb86433 100644 --- a/virt/kvm/arm/arch_timer.c +++ b/virt/kvm/arm/arch_timer.c @@ -100,7 +100,6 @@ static irqreturn_t kvm_arch_timer_handler(int irq, void *dev_id) vtimer = vcpu_vtimer(vcpu); if (!vtimer->irq.level) { - vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl); if (kvm_timer_irq_can_fire(vtimer)) kvm_timer_update_irq(vcpu, true, vtimer); } -- 2.7.4
[PATCH] KVM: arm/arm64: don't set vtimer->cnt_ctl in kvm_arch_timer_handler
In our Armv8a server (qualcomm Amberwing, non VHE), after applying Christoffer's timer optimizing patchset(Optimize arch timer register handling), the guest is hang during kernel booting. The error root cause might be as follows: 1. in kvm_arch_timer_handler, it reset vtimer->cnt_ctl with current cntv_ctl register value. And then it missed some cases to update timer's irq (irq.level) when kvm_timer_irq_can_fire() is false 2. It causes kvm_vcpu_check_block return 0 instead of -EINTR kvm_vcpu_check_block kvm_cpu_has_pending_timer kvm_timer_is_pending kvm_timer_should_fire 3. Thus, the kvm hyp code can not break the loop in kvm_vcpu_block (halt poll process) and the guest is hang forever Fixes: b103cc3f10c0 ("KVM: arm/arm64: Avoid timer save/restore in vcpu entry/exit") Signed-off-by: Jia He --- virt/kvm/arm/arch_timer.c | 1 - 1 file changed, 1 deletion(-) diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c index f9555b1..bb86433 100644 --- a/virt/kvm/arm/arch_timer.c +++ b/virt/kvm/arm/arch_timer.c @@ -100,7 +100,6 @@ static irqreturn_t kvm_arch_timer_handler(int irq, void *dev_id) vtimer = vcpu_vtimer(vcpu); if (!vtimer->irq.level) { - vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl); if (kvm_timer_irq_can_fire(vtimer)) kvm_timer_update_irq(vcpu, true, vtimer); } -- 2.7.4
[v3 PATCH 0/3] powernv-cpufreq: Multiple pstate related fixes.
From: "Gautham R. Shenoy"This is a third version of the patch to fix pstate related issues in the powernv-cpufreq driver. The previous versions can be found here: [v2]: https://lkml.org/lkml/2017/12/7/1562 [v1]: https://lkml.org/lkml/2017/11/29/1338 On POWERNV platform, Pstates are 8-bit values. On POWER8 they are negatively numbered while on POWER9 they are positively numbered. Thus, on POWER9, the maximum number of pstates could be as high as 256. In multiple places, the current code interprets pstates as a signed 8-bit value which subsequently gets assigned to a signed integer variable. This causes a problem on POWER9 platforms which have more than 128 pstates. On such systems, on a CPU that is in a lower pstate whose number is greater than 128, querying the current pstate via the pstate_to_idx() returns a "pstate X is out of bound" error message and the current pstate is reported as the nominal pstate. This is due to the manner in which the bounds are checked in pstate_to_idx which again depends on the sign of pstates and whether the pstates max to min are monotonically increasing or decreasing. Further the current code makes a couple of assumptions which is not guaranteed by the device-tree bindings: 1) Pstate ids are continguous. 2) Every Pstate should always lie between the max and the min pstates that are explicitly reported in the device tree. Both these assumptions are unwarranted and can change on future platforms. In this patch-series, we fix the implementation via the following changes: PATCH 1: Define a helper function to correctly extract the pstates from the PMCR and take care of any sign extentions. This is an immediate fix to add the ability to handle more than 128 pstates on POWER9 systems. PATCH 2: Define a hash-map which will return the index into the cpufreq frequency table for a given pstate. Use this hashmap in the implementation of pstate_to_idx(). This does away with the assumptions (1) mentioned above, and will work with non continguous pstate ids. If no entry exists for a particular pstate, then such a pstate is treated as being out of bounds. This gets rid of assumption (2). PATCH 3: Treat pstates as opaque 8-bit values consistent with the definitions in the PMSR and PMCR. We no longer need any sign-extentions nor do we require to interpret the sign of the pstates anywhere in the code. Gautham R. Shenoy (3): powernv-cpufreq: Add helper to extract pstate from PMSR powernv-cpufreq: Fix pstate_to_idx() to handle non-continguous pstates powernv-cpufreq: Treat pstates as opaque 8-bit values drivers/cpufreq/powernv-cpufreq.c | 139 -- 1 file changed, 90 insertions(+), 49 deletions(-) -- 1.9.4
[v3 PATCH 0/3] powernv-cpufreq: Multiple pstate related fixes.
From: "Gautham R. Shenoy" This is a third version of the patch to fix pstate related issues in the powernv-cpufreq driver. The previous versions can be found here: [v2]: https://lkml.org/lkml/2017/12/7/1562 [v1]: https://lkml.org/lkml/2017/11/29/1338 On POWERNV platform, Pstates are 8-bit values. On POWER8 they are negatively numbered while on POWER9 they are positively numbered. Thus, on POWER9, the maximum number of pstates could be as high as 256. In multiple places, the current code interprets pstates as a signed 8-bit value which subsequently gets assigned to a signed integer variable. This causes a problem on POWER9 platforms which have more than 128 pstates. On such systems, on a CPU that is in a lower pstate whose number is greater than 128, querying the current pstate via the pstate_to_idx() returns a "pstate X is out of bound" error message and the current pstate is reported as the nominal pstate. This is due to the manner in which the bounds are checked in pstate_to_idx which again depends on the sign of pstates and whether the pstates max to min are monotonically increasing or decreasing. Further the current code makes a couple of assumptions which is not guaranteed by the device-tree bindings: 1) Pstate ids are continguous. 2) Every Pstate should always lie between the max and the min pstates that are explicitly reported in the device tree. Both these assumptions are unwarranted and can change on future platforms. In this patch-series, we fix the implementation via the following changes: PATCH 1: Define a helper function to correctly extract the pstates from the PMCR and take care of any sign extentions. This is an immediate fix to add the ability to handle more than 128 pstates on POWER9 systems. PATCH 2: Define a hash-map which will return the index into the cpufreq frequency table for a given pstate. Use this hashmap in the implementation of pstate_to_idx(). This does away with the assumptions (1) mentioned above, and will work with non continguous pstate ids. If no entry exists for a particular pstate, then such a pstate is treated as being out of bounds. This gets rid of assumption (2). PATCH 3: Treat pstates as opaque 8-bit values consistent with the definitions in the PMSR and PMCR. We no longer need any sign-extentions nor do we require to interpret the sign of the pstates anywhere in the code. Gautham R. Shenoy (3): powernv-cpufreq: Add helper to extract pstate from PMSR powernv-cpufreq: Fix pstate_to_idx() to handle non-continguous pstates powernv-cpufreq: Treat pstates as opaque 8-bit values drivers/cpufreq/powernv-cpufreq.c | 139 -- 1 file changed, 90 insertions(+), 49 deletions(-) -- 1.9.4
[v3 PATCH 2/3] powernv-cpufreq: Fix pstate_to_idx() to handle non-continguous pstates
From: "Gautham R. Shenoy"The code in powernv-cpufreq, makes the following two assumptions which are not guaranteed by the device-tree bindings: 1) Pstate ids are continguous: This is used in pstate_to_idx() to obtain the reverse map from a pstate to it's corresponding entry into the cpufreq frequency table. 2) Every Pstate should always lie between the max and the min pstates that are explicitly reported in the device tree: This is used to determine whether a pstate reported by the PMSR is out of bounds. Both these assumptions are unwarranted and can change on future platforms. In this patch, we maintain the reverse map from a pstate to it's index in the cpufreq frequency table and use this in pstate_to_idx(). This does away with the assumptions (1) mentioned above, and will work with non continguous pstate ids. If no entry exists for a particular pstate, then such a pstate is treated as being out of bounds. This gets rid of assumption (2). On all the existing platforms, where the pstates are 8-bit long values, the new implementation of pstate_to_idx() takes constant time. Signed-off-by: Gautham R. Shenoy --- drivers/cpufreq/powernv-cpufreq.c | 85 +-- 1 file changed, 63 insertions(+), 22 deletions(-) diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c index f46b60f..8e3dbca 100644 --- a/drivers/cpufreq/powernv-cpufreq.c +++ b/drivers/cpufreq/powernv-cpufreq.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -38,7 +39,8 @@ #include #include -#define POWERNV_MAX_PSTATES256 +#define POWERNV_MAX_PSTATES_ORDER 8 +#define POWERNV_MAX_PSTATES(1UL << (POWERNV_MAX_PSTATES_ORDER)) #define PMSR_PSAFE_ENABLE (1UL << 30) #define PMSR_SPR_EM_DISABLE(1UL << 31) #define MAX_PSTATE_SHIFT 32 @@ -92,6 +94,27 @@ struct global_pstate_info { }; static struct cpufreq_frequency_table powernv_freqs[POWERNV_MAX_PSTATES+1]; + +DEFINE_HASHTABLE(pstate_revmap, POWERNV_MAX_PSTATES_ORDER); +/** + * struct pstate_idx_revmap_data: Entry in the hashmap pstate_revmap + * indexed by a function of pstate id. + * + * @pstate_id: pstate id for this entry. + * + * @cpufreq_table_idx: Index into the powernv_freqs + *cpufreq_frequency_table for frequency + *corresponding to pstate_id. + * + * @hentry: hlist_node that hooks this entry into the pstate_revmap + * hashtable + */ +struct pstate_idx_revmap_data { + int pstate_id; + unsigned int cpufreq_table_idx; + struct hlist_node hentry; +}; + u32 pstate_sign_prefix; static bool rebooting, throttled, occ_reset; @@ -161,39 +184,47 @@ static inline int extract_pstate(u64 pmsr_val, unsigned int shift) #define extract_global_pstate(x) extract_pstate(x, GPSTATE_SHIFT) #define extract_max_pstate(x) extract_pstate(x, MAX_PSTATE_SHIFT) -/* Use following macros for conversions between pstate_id and index */ +/* Use following functions for conversions between pstate_id and index */ + +/** + * idx_to_pstate : Returns the pstate id corresponding to the + *frequency in the cpufreq frequency table + *powernv_freqs indexed by @i. + * + *If @i is out of bound, this will return the pstate + *corresponding to the nominal frequency. + */ static inline int idx_to_pstate(unsigned int i) { if (unlikely(i >= powernv_pstate_info.nr_pstates)) { - pr_warn_once("index %u is out of bound\n", i); + pr_warn_once("idx_to_pstate: index %u is out of bound\n", i); return powernv_freqs[powernv_pstate_info.nominal].driver_data; } return powernv_freqs[i].driver_data; } -static inline unsigned int pstate_to_idx(int pstate) +/** + * pstate_to_idx : Returns the index in the cpufreq frequencytable + *powernv_freqs for the frequency whose corresponding + *pstate id is @pstate. + * + *If no frequency corresponding to @pstate is found, + *this will return the index of the nominal + *frequency. + */ +static unsigned int pstate_to_idx(int pstate) { - int min = powernv_freqs[powernv_pstate_info.min].driver_data; - int max = powernv_freqs[powernv_pstate_info.max].driver_data; + unsigned int key = pstate % POWERNV_MAX_PSTATES; + struct pstate_idx_revmap_data *revmap_data; - if (min > 0) { - if (unlikely((pstate < max) || (pstate > min))) { - pr_warn_once("pstate %d is out of bound\n", pstate); - return powernv_pstate_info.nominal; - } - } else { - if (unlikely((pstate > max) || (pstate < min))) { - pr_warn_once("pstate %d is out of
[v3 PATCH 1/3] powernv-cpufreq: Add helper to extract pstate from PMSR
From: "Gautham R. Shenoy"On POWERNV platform, the fields for pstates in the Power Management Status Register (PMSR) and the Power Management Control Register (PMCR) are 8-bits wide. On POWER8 the pstates are negatively numbered while on POWER9 they are positively numbered. The device-tree exports pstates as 32-bit entries. The device-tree implementation sign-extends the 8-bit pstate values to obtain the corresponding 32-bit entry. Eg: On POWER8, a pstate value 0x82 [-126] is represented in the device-tree as 0xfff82 while on POWER9, the same value 0x82 [130] is represented in the device-tree as 0x0082. The powernv-cpufreq driver implementation represents pstates using the integer type. In multiple places in the driver, the code interprets the pstates extracted from the PMSR as a signed byte and assigns it to a integer variable to get the sign-extention. On POWER9 platforms which have greater than 128 pstates, this results in the driver performing incorrect sign-extention, and thereby treating a legitimate pstate (say 130) as an invalid pstates (since it is interpreted as -126). This patch fixes the issue by implementing a helper function to extract Pstates from PMSR register, and correctly sign-extend it to be consistent with the values provided by the device-tree. Signed-off-by: Gautham R. Shenoy --- drivers/cpufreq/powernv-cpufreq.c | 37 +++-- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c index b6d7c4c..f46b60f 100644 --- a/drivers/cpufreq/powernv-cpufreq.c +++ b/drivers/cpufreq/powernv-cpufreq.c @@ -41,11 +41,9 @@ #define POWERNV_MAX_PSTATES256 #define PMSR_PSAFE_ENABLE (1UL << 30) #define PMSR_SPR_EM_DISABLE(1UL << 31) -#define PMSR_MAX(x)((x >> 32) & 0xFF) +#define MAX_PSTATE_SHIFT 32 #define LPSTATE_SHIFT 48 #define GPSTATE_SHIFT 56 -#define GET_LPSTATE(x) (((x) >> LPSTATE_SHIFT) & 0xFF) -#define GET_GPSTATE(x) (((x) >> GPSTATE_SHIFT) & 0xFF) #define MAX_RAMP_DOWN_TIME 5120 /* @@ -94,6 +92,7 @@ struct global_pstate_info { }; static struct cpufreq_frequency_table powernv_freqs[POWERNV_MAX_PSTATES+1]; +u32 pstate_sign_prefix; static bool rebooting, throttled, occ_reset; static const char * const throttle_reason[] = { @@ -148,6 +147,20 @@ enum throttle_reason_type { bool wof_enabled; } powernv_pstate_info; +static inline int extract_pstate(u64 pmsr_val, unsigned int shift) +{ + int ret = ((pmsr_val >> shift) & 0xFF); + + if (!ret) + return ret; + + return (pstate_sign_prefix | ret); +} + +#define extract_local_pstate(x) extract_pstate(x, LPSTATE_SHIFT) +#define extract_global_pstate(x) extract_pstate(x, GPSTATE_SHIFT) +#define extract_max_pstate(x) extract_pstate(x, MAX_PSTATE_SHIFT) + /* Use following macros for conversions between pstate_id and index */ static inline int idx_to_pstate(unsigned int i) { @@ -278,6 +291,9 @@ static int init_powernv_pstates(void) powernv_pstate_info.nr_pstates = nr_pstates; pr_debug("NR PStates %d\n", nr_pstates); + + pstate_sign_prefix = pstate_min & ~0xFF; + for (i = 0; i < nr_pstates; i++) { u32 id = be32_to_cpu(pstate_ids[i]); u32 freq = be32_to_cpu(pstate_freqs[i]); @@ -438,17 +454,10 @@ struct powernv_smp_call_data { static void powernv_read_cpu_freq(void *arg) { unsigned long pmspr_val; - s8 local_pstate_id; struct powernv_smp_call_data *freq_data = arg; pmspr_val = get_pmspr(SPRN_PMSR); - - /* -* The local pstate id corresponds bits 48..55 in the PMSR. -* Note: Watch out for the sign! -*/ - local_pstate_id = (pmspr_val >> 48) & 0xFF; - freq_data->pstate_id = local_pstate_id; + freq_data->pstate_id = extract_local_pstate(pmspr_val); freq_data->freq = pstate_id_to_freq(freq_data->pstate_id); pr_debug("cpu %d pmsr %016lX pstate_id %d frequency %d kHz\n", @@ -522,7 +531,7 @@ static void powernv_cpufreq_throttle_check(void *data) chip = this_cpu_read(chip_info); /* Check for Pmax Capping */ - pmsr_pmax = (s8)PMSR_MAX(pmsr); + pmsr_pmax = extract_max_pstate(pmsr); pmsr_pmax_idx = pstate_to_idx(pmsr_pmax); if (pmsr_pmax_idx != powernv_pstate_info.max) { if (chip->throttled) @@ -645,8 +654,8 @@ void gpstate_timer_handler(struct timer_list *t) * value. Hence, read from PMCR to get correct data. */ val = get_pmspr(SPRN_PMCR); - freq_data.gpstate_id = (s8)GET_GPSTATE(val); - freq_data.pstate_id = (s8)GET_LPSTATE(val); + freq_data.gpstate_id = extract_global_pstate(val); + freq_data.pstate_id = extract_local_pstate(val); if (freq_data.gpstate_id ==
[v3 PATCH 2/3] powernv-cpufreq: Fix pstate_to_idx() to handle non-continguous pstates
From: "Gautham R. Shenoy" The code in powernv-cpufreq, makes the following two assumptions which are not guaranteed by the device-tree bindings: 1) Pstate ids are continguous: This is used in pstate_to_idx() to obtain the reverse map from a pstate to it's corresponding entry into the cpufreq frequency table. 2) Every Pstate should always lie between the max and the min pstates that are explicitly reported in the device tree: This is used to determine whether a pstate reported by the PMSR is out of bounds. Both these assumptions are unwarranted and can change on future platforms. In this patch, we maintain the reverse map from a pstate to it's index in the cpufreq frequency table and use this in pstate_to_idx(). This does away with the assumptions (1) mentioned above, and will work with non continguous pstate ids. If no entry exists for a particular pstate, then such a pstate is treated as being out of bounds. This gets rid of assumption (2). On all the existing platforms, where the pstates are 8-bit long values, the new implementation of pstate_to_idx() takes constant time. Signed-off-by: Gautham R. Shenoy --- drivers/cpufreq/powernv-cpufreq.c | 85 +-- 1 file changed, 63 insertions(+), 22 deletions(-) diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c index f46b60f..8e3dbca 100644 --- a/drivers/cpufreq/powernv-cpufreq.c +++ b/drivers/cpufreq/powernv-cpufreq.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -38,7 +39,8 @@ #include #include -#define POWERNV_MAX_PSTATES256 +#define POWERNV_MAX_PSTATES_ORDER 8 +#define POWERNV_MAX_PSTATES(1UL << (POWERNV_MAX_PSTATES_ORDER)) #define PMSR_PSAFE_ENABLE (1UL << 30) #define PMSR_SPR_EM_DISABLE(1UL << 31) #define MAX_PSTATE_SHIFT 32 @@ -92,6 +94,27 @@ struct global_pstate_info { }; static struct cpufreq_frequency_table powernv_freqs[POWERNV_MAX_PSTATES+1]; + +DEFINE_HASHTABLE(pstate_revmap, POWERNV_MAX_PSTATES_ORDER); +/** + * struct pstate_idx_revmap_data: Entry in the hashmap pstate_revmap + * indexed by a function of pstate id. + * + * @pstate_id: pstate id for this entry. + * + * @cpufreq_table_idx: Index into the powernv_freqs + *cpufreq_frequency_table for frequency + *corresponding to pstate_id. + * + * @hentry: hlist_node that hooks this entry into the pstate_revmap + * hashtable + */ +struct pstate_idx_revmap_data { + int pstate_id; + unsigned int cpufreq_table_idx; + struct hlist_node hentry; +}; + u32 pstate_sign_prefix; static bool rebooting, throttled, occ_reset; @@ -161,39 +184,47 @@ static inline int extract_pstate(u64 pmsr_val, unsigned int shift) #define extract_global_pstate(x) extract_pstate(x, GPSTATE_SHIFT) #define extract_max_pstate(x) extract_pstate(x, MAX_PSTATE_SHIFT) -/* Use following macros for conversions between pstate_id and index */ +/* Use following functions for conversions between pstate_id and index */ + +/** + * idx_to_pstate : Returns the pstate id corresponding to the + *frequency in the cpufreq frequency table + *powernv_freqs indexed by @i. + * + *If @i is out of bound, this will return the pstate + *corresponding to the nominal frequency. + */ static inline int idx_to_pstate(unsigned int i) { if (unlikely(i >= powernv_pstate_info.nr_pstates)) { - pr_warn_once("index %u is out of bound\n", i); + pr_warn_once("idx_to_pstate: index %u is out of bound\n", i); return powernv_freqs[powernv_pstate_info.nominal].driver_data; } return powernv_freqs[i].driver_data; } -static inline unsigned int pstate_to_idx(int pstate) +/** + * pstate_to_idx : Returns the index in the cpufreq frequencytable + *powernv_freqs for the frequency whose corresponding + *pstate id is @pstate. + * + *If no frequency corresponding to @pstate is found, + *this will return the index of the nominal + *frequency. + */ +static unsigned int pstate_to_idx(int pstate) { - int min = powernv_freqs[powernv_pstate_info.min].driver_data; - int max = powernv_freqs[powernv_pstate_info.max].driver_data; + unsigned int key = pstate % POWERNV_MAX_PSTATES; + struct pstate_idx_revmap_data *revmap_data; - if (min > 0) { - if (unlikely((pstate < max) || (pstate > min))) { - pr_warn_once("pstate %d is out of bound\n", pstate); - return powernv_pstate_info.nominal; - } - } else { - if (unlikely((pstate > max) || (pstate < min))) { - pr_warn_once("pstate %d is out of bound\n", pstate); - return
[v3 PATCH 1/3] powernv-cpufreq: Add helper to extract pstate from PMSR
From: "Gautham R. Shenoy" On POWERNV platform, the fields for pstates in the Power Management Status Register (PMSR) and the Power Management Control Register (PMCR) are 8-bits wide. On POWER8 the pstates are negatively numbered while on POWER9 they are positively numbered. The device-tree exports pstates as 32-bit entries. The device-tree implementation sign-extends the 8-bit pstate values to obtain the corresponding 32-bit entry. Eg: On POWER8, a pstate value 0x82 [-126] is represented in the device-tree as 0xfff82 while on POWER9, the same value 0x82 [130] is represented in the device-tree as 0x0082. The powernv-cpufreq driver implementation represents pstates using the integer type. In multiple places in the driver, the code interprets the pstates extracted from the PMSR as a signed byte and assigns it to a integer variable to get the sign-extention. On POWER9 platforms which have greater than 128 pstates, this results in the driver performing incorrect sign-extention, and thereby treating a legitimate pstate (say 130) as an invalid pstates (since it is interpreted as -126). This patch fixes the issue by implementing a helper function to extract Pstates from PMSR register, and correctly sign-extend it to be consistent with the values provided by the device-tree. Signed-off-by: Gautham R. Shenoy --- drivers/cpufreq/powernv-cpufreq.c | 37 +++-- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c index b6d7c4c..f46b60f 100644 --- a/drivers/cpufreq/powernv-cpufreq.c +++ b/drivers/cpufreq/powernv-cpufreq.c @@ -41,11 +41,9 @@ #define POWERNV_MAX_PSTATES256 #define PMSR_PSAFE_ENABLE (1UL << 30) #define PMSR_SPR_EM_DISABLE(1UL << 31) -#define PMSR_MAX(x)((x >> 32) & 0xFF) +#define MAX_PSTATE_SHIFT 32 #define LPSTATE_SHIFT 48 #define GPSTATE_SHIFT 56 -#define GET_LPSTATE(x) (((x) >> LPSTATE_SHIFT) & 0xFF) -#define GET_GPSTATE(x) (((x) >> GPSTATE_SHIFT) & 0xFF) #define MAX_RAMP_DOWN_TIME 5120 /* @@ -94,6 +92,7 @@ struct global_pstate_info { }; static struct cpufreq_frequency_table powernv_freqs[POWERNV_MAX_PSTATES+1]; +u32 pstate_sign_prefix; static bool rebooting, throttled, occ_reset; static const char * const throttle_reason[] = { @@ -148,6 +147,20 @@ enum throttle_reason_type { bool wof_enabled; } powernv_pstate_info; +static inline int extract_pstate(u64 pmsr_val, unsigned int shift) +{ + int ret = ((pmsr_val >> shift) & 0xFF); + + if (!ret) + return ret; + + return (pstate_sign_prefix | ret); +} + +#define extract_local_pstate(x) extract_pstate(x, LPSTATE_SHIFT) +#define extract_global_pstate(x) extract_pstate(x, GPSTATE_SHIFT) +#define extract_max_pstate(x) extract_pstate(x, MAX_PSTATE_SHIFT) + /* Use following macros for conversions between pstate_id and index */ static inline int idx_to_pstate(unsigned int i) { @@ -278,6 +291,9 @@ static int init_powernv_pstates(void) powernv_pstate_info.nr_pstates = nr_pstates; pr_debug("NR PStates %d\n", nr_pstates); + + pstate_sign_prefix = pstate_min & ~0xFF; + for (i = 0; i < nr_pstates; i++) { u32 id = be32_to_cpu(pstate_ids[i]); u32 freq = be32_to_cpu(pstate_freqs[i]); @@ -438,17 +454,10 @@ struct powernv_smp_call_data { static void powernv_read_cpu_freq(void *arg) { unsigned long pmspr_val; - s8 local_pstate_id; struct powernv_smp_call_data *freq_data = arg; pmspr_val = get_pmspr(SPRN_PMSR); - - /* -* The local pstate id corresponds bits 48..55 in the PMSR. -* Note: Watch out for the sign! -*/ - local_pstate_id = (pmspr_val >> 48) & 0xFF; - freq_data->pstate_id = local_pstate_id; + freq_data->pstate_id = extract_local_pstate(pmspr_val); freq_data->freq = pstate_id_to_freq(freq_data->pstate_id); pr_debug("cpu %d pmsr %016lX pstate_id %d frequency %d kHz\n", @@ -522,7 +531,7 @@ static void powernv_cpufreq_throttle_check(void *data) chip = this_cpu_read(chip_info); /* Check for Pmax Capping */ - pmsr_pmax = (s8)PMSR_MAX(pmsr); + pmsr_pmax = extract_max_pstate(pmsr); pmsr_pmax_idx = pstate_to_idx(pmsr_pmax); if (pmsr_pmax_idx != powernv_pstate_info.max) { if (chip->throttled) @@ -645,8 +654,8 @@ void gpstate_timer_handler(struct timer_list *t) * value. Hence, read from PMCR to get correct data. */ val = get_pmspr(SPRN_PMCR); - freq_data.gpstate_id = (s8)GET_GPSTATE(val); - freq_data.pstate_id = (s8)GET_LPSTATE(val); + freq_data.gpstate_id = extract_global_pstate(val); + freq_data.pstate_id = extract_local_pstate(val); if (freq_data.gpstate_id == freq_data.pstate_id) {
[v3 PATCH 3/3] powernv-cpufreq: Treat pstates as opaque 8-bit values
From: "Gautham R. Shenoy"On POWER8 and POWER9, the PMSR and the PMCR registers define pstates to be 8-bit wide values. The device-tree exports pstates as 32-bit wide values of which the lower byte is the actual pstate. The current implementation in the kernel treats pstates as integer type, since it used to use the sign of the pstate for performing some boundary-checks. This is no longer required after the patch "powernv-cpufreq: Fix pstate_to_idx() to handle non-continguous pstates". So, in this patch, we modify the powernv-cpufreq driver to uniformly treat pstates as opaque 8-bit values obtained from the device-tree or the PMCR. This simplifies the extract_pstate() helper function since we no longer no longer require to worry about the sign-extentions. Signed-off-by: Gautham R. Shenoy --- drivers/cpufreq/powernv-cpufreq.c | 47 --- 1 file changed, 19 insertions(+), 28 deletions(-) diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c index 8e3dbca..8a4e2ce 100644 --- a/drivers/cpufreq/powernv-cpufreq.c +++ b/drivers/cpufreq/powernv-cpufreq.c @@ -110,12 +110,11 @@ struct global_pstate_info { * hashtable */ struct pstate_idx_revmap_data { - int pstate_id; + u8 pstate_id; unsigned int cpufreq_table_idx; struct hlist_node hentry; }; -u32 pstate_sign_prefix; static bool rebooting, throttled, occ_reset; static const char * const throttle_reason[] = { @@ -170,14 +169,9 @@ enum throttle_reason_type { bool wof_enabled; } powernv_pstate_info; -static inline int extract_pstate(u64 pmsr_val, unsigned int shift) +static inline u8 extract_pstate(u64 pmsr_val, unsigned int shift) { - int ret = ((pmsr_val >> shift) & 0xFF); - - if (!ret) - return ret; - - return (pstate_sign_prefix | ret); + return ((pmsr_val >> shift) & 0xFF); } #define extract_local_pstate(x) extract_pstate(x, LPSTATE_SHIFT) @@ -194,7 +188,7 @@ static inline int extract_pstate(u64 pmsr_val, unsigned int shift) *If @i is out of bound, this will return the pstate *corresponding to the nominal frequency. */ -static inline int idx_to_pstate(unsigned int i) +static inline u8 idx_to_pstate(unsigned int i) { if (unlikely(i >= powernv_pstate_info.nr_pstates)) { pr_warn_once("idx_to_pstate: index %u is out of bound\n", i); @@ -213,7 +207,7 @@ static inline int idx_to_pstate(unsigned int i) *this will return the index of the nominal *frequency. */ -static unsigned int pstate_to_idx(int pstate) +static unsigned int pstate_to_idx(u8 pstate) { unsigned int key = pstate % POWERNV_MAX_PSTATES; struct pstate_idx_revmap_data *revmap_data; @@ -223,7 +217,7 @@ static unsigned int pstate_to_idx(int pstate) return revmap_data->cpufreq_table_idx; } - pr_warn_once("pstate_to_idx: pstate %d not found\n", pstate); + pr_warn_once("pstate_to_idx: pstate 0x%x not found\n", pstate); return powernv_pstate_info.nominal; } @@ -291,7 +285,7 @@ static int init_powernv_pstates(void) powernv_pstate_info.wof_enabled = true; next: - pr_info("cpufreq pstate min %d nominal %d max %d\n", pstate_min, + pr_info("cpufreq pstate min 0x%x nominal 0x%x max 0x%x\n", pstate_min, pstate_nominal, pstate_max); pr_info("Workload Optimized Frequency is %s in the platform\n", (powernv_pstate_info.wof_enabled) ? "enabled" : "disabled"); @@ -323,8 +317,6 @@ static int init_powernv_pstates(void) powernv_pstate_info.nr_pstates = nr_pstates; pr_debug("NR PStates %d\n", nr_pstates); - pstate_sign_prefix = pstate_min & ~0xFF; - for (i = 0; i < nr_pstates; i++) { u32 id = be32_to_cpu(pstate_ids[i]); u32 freq = be32_to_cpu(pstate_freqs[i]); @@ -333,14 +325,14 @@ static int init_powernv_pstates(void) pr_debug("PState id %d freq %d MHz\n", id, freq); powernv_freqs[i].frequency = freq * 1000; /* kHz */ - powernv_freqs[i].driver_data = id; + powernv_freqs[i].driver_data = id & 0xFF; revmap_data = (struct pstate_idx_revmap_data *) kmalloc(sizeof(*revmap_data), GFP_KERNEL); - revmap_data->pstate_id = id; + revmap_data->pstate_id = id & 0xFF; revmap_data->cpufreq_table_idx = i; - key = id % POWERNV_MAX_PSTATES; + key = (revmap_data->pstate_id) % POWERNV_MAX_PSTATES; hash_add(pstate_revmap, _data->hentry, key); if (id == pstate_max) @@ -364,14 +356,13 @@ static int init_powernv_pstates(void) } /* Returns the CPU frequency corresponding to the pstate_id. */ -static unsigned
[v3 PATCH 3/3] powernv-cpufreq: Treat pstates as opaque 8-bit values
From: "Gautham R. Shenoy" On POWER8 and POWER9, the PMSR and the PMCR registers define pstates to be 8-bit wide values. The device-tree exports pstates as 32-bit wide values of which the lower byte is the actual pstate. The current implementation in the kernel treats pstates as integer type, since it used to use the sign of the pstate for performing some boundary-checks. This is no longer required after the patch "powernv-cpufreq: Fix pstate_to_idx() to handle non-continguous pstates". So, in this patch, we modify the powernv-cpufreq driver to uniformly treat pstates as opaque 8-bit values obtained from the device-tree or the PMCR. This simplifies the extract_pstate() helper function since we no longer no longer require to worry about the sign-extentions. Signed-off-by: Gautham R. Shenoy --- drivers/cpufreq/powernv-cpufreq.c | 47 --- 1 file changed, 19 insertions(+), 28 deletions(-) diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c index 8e3dbca..8a4e2ce 100644 --- a/drivers/cpufreq/powernv-cpufreq.c +++ b/drivers/cpufreq/powernv-cpufreq.c @@ -110,12 +110,11 @@ struct global_pstate_info { * hashtable */ struct pstate_idx_revmap_data { - int pstate_id; + u8 pstate_id; unsigned int cpufreq_table_idx; struct hlist_node hentry; }; -u32 pstate_sign_prefix; static bool rebooting, throttled, occ_reset; static const char * const throttle_reason[] = { @@ -170,14 +169,9 @@ enum throttle_reason_type { bool wof_enabled; } powernv_pstate_info; -static inline int extract_pstate(u64 pmsr_val, unsigned int shift) +static inline u8 extract_pstate(u64 pmsr_val, unsigned int shift) { - int ret = ((pmsr_val >> shift) & 0xFF); - - if (!ret) - return ret; - - return (pstate_sign_prefix | ret); + return ((pmsr_val >> shift) & 0xFF); } #define extract_local_pstate(x) extract_pstate(x, LPSTATE_SHIFT) @@ -194,7 +188,7 @@ static inline int extract_pstate(u64 pmsr_val, unsigned int shift) *If @i is out of bound, this will return the pstate *corresponding to the nominal frequency. */ -static inline int idx_to_pstate(unsigned int i) +static inline u8 idx_to_pstate(unsigned int i) { if (unlikely(i >= powernv_pstate_info.nr_pstates)) { pr_warn_once("idx_to_pstate: index %u is out of bound\n", i); @@ -213,7 +207,7 @@ static inline int idx_to_pstate(unsigned int i) *this will return the index of the nominal *frequency. */ -static unsigned int pstate_to_idx(int pstate) +static unsigned int pstate_to_idx(u8 pstate) { unsigned int key = pstate % POWERNV_MAX_PSTATES; struct pstate_idx_revmap_data *revmap_data; @@ -223,7 +217,7 @@ static unsigned int pstate_to_idx(int pstate) return revmap_data->cpufreq_table_idx; } - pr_warn_once("pstate_to_idx: pstate %d not found\n", pstate); + pr_warn_once("pstate_to_idx: pstate 0x%x not found\n", pstate); return powernv_pstate_info.nominal; } @@ -291,7 +285,7 @@ static int init_powernv_pstates(void) powernv_pstate_info.wof_enabled = true; next: - pr_info("cpufreq pstate min %d nominal %d max %d\n", pstate_min, + pr_info("cpufreq pstate min 0x%x nominal 0x%x max 0x%x\n", pstate_min, pstate_nominal, pstate_max); pr_info("Workload Optimized Frequency is %s in the platform\n", (powernv_pstate_info.wof_enabled) ? "enabled" : "disabled"); @@ -323,8 +317,6 @@ static int init_powernv_pstates(void) powernv_pstate_info.nr_pstates = nr_pstates; pr_debug("NR PStates %d\n", nr_pstates); - pstate_sign_prefix = pstate_min & ~0xFF; - for (i = 0; i < nr_pstates; i++) { u32 id = be32_to_cpu(pstate_ids[i]); u32 freq = be32_to_cpu(pstate_freqs[i]); @@ -333,14 +325,14 @@ static int init_powernv_pstates(void) pr_debug("PState id %d freq %d MHz\n", id, freq); powernv_freqs[i].frequency = freq * 1000; /* kHz */ - powernv_freqs[i].driver_data = id; + powernv_freqs[i].driver_data = id & 0xFF; revmap_data = (struct pstate_idx_revmap_data *) kmalloc(sizeof(*revmap_data), GFP_KERNEL); - revmap_data->pstate_id = id; + revmap_data->pstate_id = id & 0xFF; revmap_data->cpufreq_table_idx = i; - key = id % POWERNV_MAX_PSTATES; + key = (revmap_data->pstate_id) % POWERNV_MAX_PSTATES; hash_add(pstate_revmap, _data->hentry, key); if (id == pstate_max) @@ -364,14 +356,13 @@ static int init_powernv_pstates(void) } /* Returns the CPU frequency corresponding to the pstate_id. */ -static unsigned int pstate_id_to_freq(int pstate_id) +static
Re: [RFC PATCH 5/9] ethtool: implement GET_DRVINFO message
Wed, Dec 13, 2017 at 12:54:39AM CET, mkube...@suse.cz wrote: >On Mon, Dec 11, 2017 at 05:16:01PM +0100, Jiri Pirko wrote: >> Mon, Dec 11, 2017 at 02:54:01PM CET, mkube...@suse.cz wrote: >> >+ >> >+ETHA_DRVINFO_DRIVER(string)driver name >> >+ETHA_DRVINFO_VERSION (string)driver version >> >> You use 3 prefixes: >> ETHTOOL_ for cmd >> ETHA_ for attrs >> ethnl_ for function >> >> I suggest to sync this, perhaps to: >> ETHNL_CMD_* >> ETHNL_ATTR_* >> ethnl_* >> ? > >Switching to ETHNL_CMD_* is certainly a good idea. For attributes, I'm a >bit worried that ETHNL_ATTR_ prefix might make it even harder to fit >into the 80 characters per line limit. I'll try and see what it would >look like. > >> >+ETHA_DRVINFO_FWVERSION (string)firmware version >> >+ETHA_DRVINFO_BUSINFO (string)device bus address >> >+ETHA_DRVINFO_EROM_VER (string)expansion ROM version >> >+ETHA_DRVINFO_N_PRIV_FLAGS (u32) number of private flags >> >+ETHA_DRVINFO_N_STATS (u32) number of device stats >> >+ETHA_DRVINFO_TESTINFO_LEN (u32) number of test results >> >+ETHA_DRVINFO_EEDUMP_LEN(u32) EEPROM dump size >> >+ETHA_DRVINFO_REGDUMP_LEN (u32) register dump size >> >> We are now working on providing various fw memory regions dump in >> devlink. It makes sense to have it in devlink for couple of reasons: >> 1) per-asic, not netdev specific, therefore does not really make sense >>to have netdev as handle, but rather devlink handle. >> 2) snapshot support - we need to provide support for getting snapshot >>(for example on failure), transferring to user and deleting it >>(remove from driver memory). >> >> Also, driver name, version, fwversion, etc is per-asic. Would make sense >> to have it in devlink as well. >> >> I think this is great opprotunity to move things where they should be to >> be alligned with the current world and kernel infrastructure. > >IMHO this depends on the question whether we are going to rework also >the interface between kernel and NIC drivers (currently ethtool_ops). >If we are, it would make good sense to split the information in both >interfaces. If not, it doesn't seem to make userspace do two queries, >each getting one part of the same information provided by NIC. Yeah, agreed. I believe we should. > >Also, I must admit that one thing I dislike about the iw tool is that it >pushes me to distinguish between operations on "phy" and "dev". While >I understand that it makes perfect sense for someone familiar with the >internals, it's quite annoying for an occasional "consumer". It would be >sad if we created a set of perfectly logical and clean tools and >(almost) 20 years later, people still used old ioctl based ethtool >because "it's what they are used to and it works just fine for them" >(like they do with ifconfig, netstat or brctl). Good documentation should take care of that. > >Michal
Re: [RFC PATCH 5/9] ethtool: implement GET_DRVINFO message
Wed, Dec 13, 2017 at 12:54:39AM CET, mkube...@suse.cz wrote: >On Mon, Dec 11, 2017 at 05:16:01PM +0100, Jiri Pirko wrote: >> Mon, Dec 11, 2017 at 02:54:01PM CET, mkube...@suse.cz wrote: >> >+ >> >+ETHA_DRVINFO_DRIVER(string)driver name >> >+ETHA_DRVINFO_VERSION (string)driver version >> >> You use 3 prefixes: >> ETHTOOL_ for cmd >> ETHA_ for attrs >> ethnl_ for function >> >> I suggest to sync this, perhaps to: >> ETHNL_CMD_* >> ETHNL_ATTR_* >> ethnl_* >> ? > >Switching to ETHNL_CMD_* is certainly a good idea. For attributes, I'm a >bit worried that ETHNL_ATTR_ prefix might make it even harder to fit >into the 80 characters per line limit. I'll try and see what it would >look like. > >> >+ETHA_DRVINFO_FWVERSION (string)firmware version >> >+ETHA_DRVINFO_BUSINFO (string)device bus address >> >+ETHA_DRVINFO_EROM_VER (string)expansion ROM version >> >+ETHA_DRVINFO_N_PRIV_FLAGS (u32) number of private flags >> >+ETHA_DRVINFO_N_STATS (u32) number of device stats >> >+ETHA_DRVINFO_TESTINFO_LEN (u32) number of test results >> >+ETHA_DRVINFO_EEDUMP_LEN(u32) EEPROM dump size >> >+ETHA_DRVINFO_REGDUMP_LEN (u32) register dump size >> >> We are now working on providing various fw memory regions dump in >> devlink. It makes sense to have it in devlink for couple of reasons: >> 1) per-asic, not netdev specific, therefore does not really make sense >>to have netdev as handle, but rather devlink handle. >> 2) snapshot support - we need to provide support for getting snapshot >>(for example on failure), transferring to user and deleting it >>(remove from driver memory). >> >> Also, driver name, version, fwversion, etc is per-asic. Would make sense >> to have it in devlink as well. >> >> I think this is great opprotunity to move things where they should be to >> be alligned with the current world and kernel infrastructure. > >IMHO this depends on the question whether we are going to rework also >the interface between kernel and NIC drivers (currently ethtool_ops). >If we are, it would make good sense to split the information in both >interfaces. If not, it doesn't seem to make userspace do two queries, >each getting one part of the same information provided by NIC. Yeah, agreed. I believe we should. > >Also, I must admit that one thing I dislike about the iw tool is that it >pushes me to distinguish between operations on "phy" and "dev". While >I understand that it makes perfect sense for someone familiar with the >internals, it's quite annoying for an occasional "consumer". It would be >sad if we created a set of perfectly logical and clean tools and >(almost) 20 years later, people still used old ioctl based ethtool >because "it's what they are used to and it works just fine for them" >(like they do with ifconfig, netstat or brctl). Good documentation should take care of that. > >Michal
Re: [PATCH] vfio: Simplify capability helper
On Tue, Dec 12, 2017 at 12:59:39PM -0700, Alex Williamson wrote: > The vfio_info_add_capability() helper requires the caller to pass a > capability ID, which it then uses to fill in header fields, assuming > hard coded versions. This makes for an awkward and rigid interface. > The only thing we want this helper to do is allocate sufficient > space in the caps buffer and chain this capability into the list. > Reduce it to that simple task. > > Signed-off-by: Alex WilliamsonReviewed-by: Peter Xu Though during review I had a question related to the function msix_sparse_mmap_cap(): Is it possible that one PCI device BAR is very small (e.g., 4K) that only contains the MSI-X table (and another small PBA area)? If so, should we just mark that region unmappable instead of setting vfio_region_info_cap_sparse_mmap.nr_areas to 1 in msix_sparse_mmap_cap()? /* If MSI-X table is aligned to the start or end, only one area */ if (((vdev->msix_offset & PAGE_MASK) == 0) || (PAGE_ALIGN(vdev->msix_offset + vdev->msix_size) >= end)) nr_areas = 1; Thanks, -- Peter Xu
Re: [PATCH] vfio: Simplify capability helper
On Tue, Dec 12, 2017 at 12:59:39PM -0700, Alex Williamson wrote: > The vfio_info_add_capability() helper requires the caller to pass a > capability ID, which it then uses to fill in header fields, assuming > hard coded versions. This makes for an awkward and rigid interface. > The only thing we want this helper to do is allocate sufficient > space in the caps buffer and chain this capability into the list. > Reduce it to that simple task. > > Signed-off-by: Alex Williamson Reviewed-by: Peter Xu Though during review I had a question related to the function msix_sparse_mmap_cap(): Is it possible that one PCI device BAR is very small (e.g., 4K) that only contains the MSI-X table (and another small PBA area)? If so, should we just mark that region unmappable instead of setting vfio_region_info_cap_sparse_mmap.nr_areas to 1 in msix_sparse_mmap_cap()? /* If MSI-X table is aligned to the start or end, only one area */ if (((vdev->msix_offset & PAGE_MASK) == 0) || (PAGE_ALIGN(vdev->msix_offset + vdev->msix_size) >= end)) nr_areas = 1; Thanks, -- Peter Xu
Re: [PATCH 4.14 000/164] 4.14.6-stable review
Hi Shuah and Greg, On 2017-12-12 15:47, Shuah Khan wrote: On 12/12/2017 05:43 AM, Greg Kroah-Hartman wrote: This is the start of the stable review cycle for the 4.14.6 release. There are 164 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know. Responses should be made by Thu Dec 14 12:34:08 UTC 2017. Anything received after that time might be too late. The whole patch series can be found in one patch at: kernel.org/pub/linux/kernel/v4.x/stable-review/patch-4.14.6-rc1.gz or in the git tree and branch at: git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git linux-4.14.y and the diffstat can be found below. thanks, greg k-h Daniel Vetterdrm: safely free connectors from connector_iter Marek Szyprowski drm/bridge: analogix dp: Fix runtime PM state in get_modes() callback The above two patches have been found to be the cause of boot hang on exynos Peach Pi(t) chromebooks. I am adding Daniel and Marek to the thread. The deadlock is caused by the Daniels patch. My patch only changes the order of device initialization what might hide or reveal bug related to Daniels patch. My drm/bridge patch it is definitely needed for v4.14 stable to fix boot issue on Samsung Snow Chromebooks (Exynos 5250 based). Best regards -- Marek Szyprowski, PhD Samsung R Institute Poland
Re: [PATCH 4.14 000/164] 4.14.6-stable review
Hi Shuah and Greg, On 2017-12-12 15:47, Shuah Khan wrote: On 12/12/2017 05:43 AM, Greg Kroah-Hartman wrote: This is the start of the stable review cycle for the 4.14.6 release. There are 164 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know. Responses should be made by Thu Dec 14 12:34:08 UTC 2017. Anything received after that time might be too late. The whole patch series can be found in one patch at: kernel.org/pub/linux/kernel/v4.x/stable-review/patch-4.14.6-rc1.gz or in the git tree and branch at: git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git linux-4.14.y and the diffstat can be found below. thanks, greg k-h Daniel Vetter drm: safely free connectors from connector_iter Marek Szyprowski drm/bridge: analogix dp: Fix runtime PM state in get_modes() callback The above two patches have been found to be the cause of boot hang on exynos Peach Pi(t) chromebooks. I am adding Daniel and Marek to the thread. The deadlock is caused by the Daniels patch. My patch only changes the order of device initialization what might hide or reveal bug related to Daniels patch. My drm/bridge patch it is definitely needed for v4.14 stable to fix boot issue on Samsung Snow Chromebooks (Exynos 5250 based). Best regards -- Marek Szyprowski, PhD Samsung R Institute Poland
[PATCH v2 01/11] ASoC: fsl_ssi: Rename fsl_ssi_private to fsl_ssi
Shorten the private data structure to save some wrapped lines. Signed-off-by: Nicolin Chen--- sound/soc/fsl/fsl_ssi.c | 456 +++- 1 file changed, 220 insertions(+), 236 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index c350117..84d2f7e 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -185,7 +185,7 @@ struct fsl_ssi_soc_data { }; /** - * fsl_ssi_private: per-SSI private data + * fsl_ssi: per-SSI private data * * @reg: Pointer to the regmap registers * @irq: IRQ of this SSI @@ -224,7 +224,7 @@ struct fsl_ssi_soc_data { * @dma_maxburst: max number of words to transfer in one go. So far, * this is always the same as fifo_watermark. */ -struct fsl_ssi_private { +struct fsl_ssi { struct regmap *regs; int irq; struct snd_soc_dai_driver cpu_dai_drv; @@ -325,21 +325,21 @@ static const struct of_device_id fsl_ssi_ids[] = { }; MODULE_DEVICE_TABLE(of, fsl_ssi_ids); -static bool fsl_ssi_is_ac97(struct fsl_ssi_private *ssi_private) +static bool fsl_ssi_is_ac97(struct fsl_ssi *ssi) { - return (ssi_private->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) == + return (ssi->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_AC97; } -static bool fsl_ssi_is_i2s_master(struct fsl_ssi_private *ssi_private) +static bool fsl_ssi_is_i2s_master(struct fsl_ssi *ssi) { - return (ssi_private->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) == + return (ssi->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBS_CFS; } -static bool fsl_ssi_is_i2s_cbm_cfs(struct fsl_ssi_private *ssi_private) +static bool fsl_ssi_is_i2s_cbm_cfs(struct fsl_ssi *ssi) { - return (ssi_private->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) == + return (ssi->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFS; } /** @@ -352,12 +352,12 @@ static bool fsl_ssi_is_i2s_cbm_cfs(struct fsl_ssi_private *ssi_private) * This interrupt handler is used only to gather statistics. * * @irq: IRQ of the SSI device - * @dev_id: pointer to the ssi_private structure for this SSI device + * @dev_id: pointer to the fsl_ssi structure for this SSI device */ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id) { - struct fsl_ssi_private *ssi_private = dev_id; - struct regmap *regs = ssi_private->regs; + struct fsl_ssi *ssi = dev_id; + struct regmap *regs = ssi->regs; __be32 sisr; __be32 sisr2; @@ -367,12 +367,12 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id) */ regmap_read(regs, CCSR_SSI_SISR, ); - sisr2 = sisr & ssi_private->soc->sisr_write_mask; + sisr2 = sisr & ssi->soc->sisr_write_mask; /* Clear the bits that we set */ if (sisr2) regmap_write(regs, CCSR_SSI_SISR, sisr2); - fsl_ssi_dbg_isr(_private->dbg_stats, sisr); + fsl_ssi_dbg_isr(>dbg_stats, sisr); return IRQ_HANDLED; } @@ -380,11 +380,10 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id) /* * Enable/Disable all rx/tx config flags at once. */ -static void fsl_ssi_rxtx_config(struct fsl_ssi_private *ssi_private, - bool enable) +static void fsl_ssi_rxtx_config(struct fsl_ssi *ssi, bool enable) { - struct regmap *regs = ssi_private->regs; - struct fsl_ssi_rxtx_reg_val *vals = _private->rxtx_reg_val; + struct regmap *regs = ssi->regs; + struct fsl_ssi_rxtx_reg_val *vals = >rxtx_reg_val; if (enable) { regmap_update_bits(regs, CCSR_SSI_SIER, @@ -414,14 +413,13 @@ static void fsl_ssi_rxtx_config(struct fsl_ssi_private *ssi_private, * Note: The SOR is not documented in recent IMX datasheet, but * is described in IMX51 reference manual at section 56.3.3.15. */ -static void fsl_ssi_fifo_clear(struct fsl_ssi_private *ssi_private, - bool is_rx) +static void fsl_ssi_fifo_clear(struct fsl_ssi *ssi, bool is_rx) { if (is_rx) { - regmap_update_bits(ssi_private->regs, CCSR_SSI_SOR, + regmap_update_bits(ssi->regs, CCSR_SSI_SOR, CCSR_SSI_SOR_RX_CLR, CCSR_SSI_SOR_RX_CLR); } else { - regmap_update_bits(ssi_private->regs, CCSR_SSI_SOR, + regmap_update_bits(ssi->regs, CCSR_SSI_SOR, CCSR_SSI_SOR_TX_CLR, CCSR_SSI_SOR_TX_CLR); } } @@ -448,12 +446,12 @@ static void fsl_ssi_fifo_clear(struct fsl_ssi_private *ssi_private, /* * Enable/Disable a ssi configuration. You have to pass either - * ssi_private->rxtx_reg_val.rx or tx as vals parameter. + * ssi->rxtx_reg_val.rx or tx as vals parameter. */ -static void fsl_ssi_config(struct fsl_ssi_private *ssi_private, bool enable, +static void fsl_ssi_config(struct fsl_ssi *ssi, bool enable, struct fsl_ssi_reg_val *vals) { - struct regmap *regs
[PATCH v2 01/11] ASoC: fsl_ssi: Rename fsl_ssi_private to fsl_ssi
Shorten the private data structure to save some wrapped lines. Signed-off-by: Nicolin Chen --- sound/soc/fsl/fsl_ssi.c | 456 +++- 1 file changed, 220 insertions(+), 236 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index c350117..84d2f7e 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -185,7 +185,7 @@ struct fsl_ssi_soc_data { }; /** - * fsl_ssi_private: per-SSI private data + * fsl_ssi: per-SSI private data * * @reg: Pointer to the regmap registers * @irq: IRQ of this SSI @@ -224,7 +224,7 @@ struct fsl_ssi_soc_data { * @dma_maxburst: max number of words to transfer in one go. So far, * this is always the same as fifo_watermark. */ -struct fsl_ssi_private { +struct fsl_ssi { struct regmap *regs; int irq; struct snd_soc_dai_driver cpu_dai_drv; @@ -325,21 +325,21 @@ static const struct of_device_id fsl_ssi_ids[] = { }; MODULE_DEVICE_TABLE(of, fsl_ssi_ids); -static bool fsl_ssi_is_ac97(struct fsl_ssi_private *ssi_private) +static bool fsl_ssi_is_ac97(struct fsl_ssi *ssi) { - return (ssi_private->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) == + return (ssi->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_AC97; } -static bool fsl_ssi_is_i2s_master(struct fsl_ssi_private *ssi_private) +static bool fsl_ssi_is_i2s_master(struct fsl_ssi *ssi) { - return (ssi_private->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) == + return (ssi->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBS_CFS; } -static bool fsl_ssi_is_i2s_cbm_cfs(struct fsl_ssi_private *ssi_private) +static bool fsl_ssi_is_i2s_cbm_cfs(struct fsl_ssi *ssi) { - return (ssi_private->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) == + return (ssi->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFS; } /** @@ -352,12 +352,12 @@ static bool fsl_ssi_is_i2s_cbm_cfs(struct fsl_ssi_private *ssi_private) * This interrupt handler is used only to gather statistics. * * @irq: IRQ of the SSI device - * @dev_id: pointer to the ssi_private structure for this SSI device + * @dev_id: pointer to the fsl_ssi structure for this SSI device */ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id) { - struct fsl_ssi_private *ssi_private = dev_id; - struct regmap *regs = ssi_private->regs; + struct fsl_ssi *ssi = dev_id; + struct regmap *regs = ssi->regs; __be32 sisr; __be32 sisr2; @@ -367,12 +367,12 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id) */ regmap_read(regs, CCSR_SSI_SISR, ); - sisr2 = sisr & ssi_private->soc->sisr_write_mask; + sisr2 = sisr & ssi->soc->sisr_write_mask; /* Clear the bits that we set */ if (sisr2) regmap_write(regs, CCSR_SSI_SISR, sisr2); - fsl_ssi_dbg_isr(_private->dbg_stats, sisr); + fsl_ssi_dbg_isr(>dbg_stats, sisr); return IRQ_HANDLED; } @@ -380,11 +380,10 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id) /* * Enable/Disable all rx/tx config flags at once. */ -static void fsl_ssi_rxtx_config(struct fsl_ssi_private *ssi_private, - bool enable) +static void fsl_ssi_rxtx_config(struct fsl_ssi *ssi, bool enable) { - struct regmap *regs = ssi_private->regs; - struct fsl_ssi_rxtx_reg_val *vals = _private->rxtx_reg_val; + struct regmap *regs = ssi->regs; + struct fsl_ssi_rxtx_reg_val *vals = >rxtx_reg_val; if (enable) { regmap_update_bits(regs, CCSR_SSI_SIER, @@ -414,14 +413,13 @@ static void fsl_ssi_rxtx_config(struct fsl_ssi_private *ssi_private, * Note: The SOR is not documented in recent IMX datasheet, but * is described in IMX51 reference manual at section 56.3.3.15. */ -static void fsl_ssi_fifo_clear(struct fsl_ssi_private *ssi_private, - bool is_rx) +static void fsl_ssi_fifo_clear(struct fsl_ssi *ssi, bool is_rx) { if (is_rx) { - regmap_update_bits(ssi_private->regs, CCSR_SSI_SOR, + regmap_update_bits(ssi->regs, CCSR_SSI_SOR, CCSR_SSI_SOR_RX_CLR, CCSR_SSI_SOR_RX_CLR); } else { - regmap_update_bits(ssi_private->regs, CCSR_SSI_SOR, + regmap_update_bits(ssi->regs, CCSR_SSI_SOR, CCSR_SSI_SOR_TX_CLR, CCSR_SSI_SOR_TX_CLR); } } @@ -448,12 +446,12 @@ static void fsl_ssi_fifo_clear(struct fsl_ssi_private *ssi_private, /* * Enable/Disable a ssi configuration. You have to pass either - * ssi_private->rxtx_reg_val.rx or tx as vals parameter. + * ssi->rxtx_reg_val.rx or tx as vals parameter. */ -static void fsl_ssi_config(struct fsl_ssi_private *ssi_private, bool enable, +static void fsl_ssi_config(struct fsl_ssi *ssi, bool enable, struct fsl_ssi_reg_val *vals) { - struct regmap *regs = ssi_private->regs; +
[PATCH v2 06/11] ASoC: fsl_ssi: Refine printk outputs
This patches unifies the error message in the "failed to " format. It also reduces the length of one line and adds spaces to an operator. Signed-off-by: Nicolin Chen--- sound/soc/fsl/fsl_ssi.c | 16 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 9a3db08..d3bb662 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -701,7 +701,7 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, * never greater than 1/5 IPG clock rate */ if (freq * 5 > clk_get_rate(ssi->clk)) { - dev_err(cpu_dai->dev, "bitclk > ipgclk/5\n"); + dev_err(cpu_dai->dev, "bitclk > ipgclk / 5\n"); return -EINVAL; } @@ -868,7 +868,7 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev, ssi->dai_fmt = fmt; if (fsl_ssi_is_i2s_master(ssi) && IS_ERR(ssi->baudclk)) { - dev_err(dev, "baudclk is missing which is necessary for master mode\n"); + dev_err(dev, "missing baudclk for master mode\n"); return -EINVAL; } @@ -1284,7 +1284,7 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev, ssi->clk = devm_clk_get(dev, NULL); if (IS_ERR(ssi->clk)) { ret = PTR_ERR(ssi->clk); - dev_err(dev, "could not get clock: %d\n", ret); + dev_err(dev, "failed to get clock: %d\n", ret); return ret; } @@ -1300,7 +1300,7 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev, /* Do not error out for slave cases that live without a baud clock */ ssi->baudclk = devm_clk_get(dev, "baud"); if (IS_ERR(ssi->baudclk)) - dev_dbg(dev, "could not get baud clock: %ld\n", + dev_dbg(dev, "failed to get baud clock: %ld\n", PTR_ERR(ssi->baudclk)); ssi->dma_params_tx.maxburst = ssi->dma_maxburst; @@ -1421,7 +1421,7 @@ static int fsl_ssi_probe(struct platform_device *pdev) ); } if (IS_ERR(ssi->regs)) { - dev_err(dev, "Failed to init register map\n"); + dev_err(dev, "failed to init register map\n"); return PTR_ERR(ssi->regs); } @@ -1480,7 +1480,7 @@ static int fsl_ssi_probe(struct platform_device *pdev) mutex_init(>ac97_reg_lock); ret = snd_soc_set_ac97_ops_of_reset(_ssi_ac97_ops, pdev); if (ret) { - dev_err(dev, "could not set AC'97 ops\n"); + dev_err(dev, "failed to set AC'97 ops\n"); goto error_ac97_ops; } } @@ -1496,7 +1496,7 @@ static int fsl_ssi_probe(struct platform_device *pdev) ret = devm_request_irq(dev, ssi->irq, fsl_ssi_isr, 0, dev_name(dev), ssi); if (ret < 0) { - dev_err(dev, "could not claim irq %u\n", ssi->irq); + dev_err(dev, "failed to claim irq %u\n", ssi->irq); goto error_asoc_register; } } @@ -1538,7 +1538,7 @@ static int fsl_ssi_probe(struct platform_device *pdev) ret = of_property_read_u32(np, "cell-index", _idx); if (ret) { - dev_err(dev, "cannot get SSI index property\n"); + dev_err(dev, "failed to get SSI index property\n"); goto error_sound_card; } -- 2.7.4
[PATCH v2 06/11] ASoC: fsl_ssi: Refine printk outputs
This patches unifies the error message in the "failed to " format. It also reduces the length of one line and adds spaces to an operator. Signed-off-by: Nicolin Chen --- sound/soc/fsl/fsl_ssi.c | 16 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 9a3db08..d3bb662 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -701,7 +701,7 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, * never greater than 1/5 IPG clock rate */ if (freq * 5 > clk_get_rate(ssi->clk)) { - dev_err(cpu_dai->dev, "bitclk > ipgclk/5\n"); + dev_err(cpu_dai->dev, "bitclk > ipgclk / 5\n"); return -EINVAL; } @@ -868,7 +868,7 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev, ssi->dai_fmt = fmt; if (fsl_ssi_is_i2s_master(ssi) && IS_ERR(ssi->baudclk)) { - dev_err(dev, "baudclk is missing which is necessary for master mode\n"); + dev_err(dev, "missing baudclk for master mode\n"); return -EINVAL; } @@ -1284,7 +1284,7 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev, ssi->clk = devm_clk_get(dev, NULL); if (IS_ERR(ssi->clk)) { ret = PTR_ERR(ssi->clk); - dev_err(dev, "could not get clock: %d\n", ret); + dev_err(dev, "failed to get clock: %d\n", ret); return ret; } @@ -1300,7 +1300,7 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev, /* Do not error out for slave cases that live without a baud clock */ ssi->baudclk = devm_clk_get(dev, "baud"); if (IS_ERR(ssi->baudclk)) - dev_dbg(dev, "could not get baud clock: %ld\n", + dev_dbg(dev, "failed to get baud clock: %ld\n", PTR_ERR(ssi->baudclk)); ssi->dma_params_tx.maxburst = ssi->dma_maxburst; @@ -1421,7 +1421,7 @@ static int fsl_ssi_probe(struct platform_device *pdev) ); } if (IS_ERR(ssi->regs)) { - dev_err(dev, "Failed to init register map\n"); + dev_err(dev, "failed to init register map\n"); return PTR_ERR(ssi->regs); } @@ -1480,7 +1480,7 @@ static int fsl_ssi_probe(struct platform_device *pdev) mutex_init(>ac97_reg_lock); ret = snd_soc_set_ac97_ops_of_reset(_ssi_ac97_ops, pdev); if (ret) { - dev_err(dev, "could not set AC'97 ops\n"); + dev_err(dev, "failed to set AC'97 ops\n"); goto error_ac97_ops; } } @@ -1496,7 +1496,7 @@ static int fsl_ssi_probe(struct platform_device *pdev) ret = devm_request_irq(dev, ssi->irq, fsl_ssi_isr, 0, dev_name(dev), ssi); if (ret < 0) { - dev_err(dev, "could not claim irq %u\n", ssi->irq); + dev_err(dev, "failed to claim irq %u\n", ssi->irq); goto error_asoc_register; } } @@ -1538,7 +1538,7 @@ static int fsl_ssi_probe(struct platform_device *pdev) ret = of_property_read_u32(np, "cell-index", _idx); if (ret) { - dev_err(dev, "cannot get SSI index property\n"); + dev_err(dev, "failed to get SSI index property\n"); goto error_sound_card; } -- 2.7.4
[PATCH v2 07/11] ASoC: fsl_ssi: Rename cpu_dai parameter to dai
Shortens the variable name to save space, useful for dev_err outputs. Signed-off-by: Nicolin Chen--- sound/soc/fsl/fsl_ssi.c | 32 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index d3bb662..69fa86d 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -668,10 +668,10 @@ static void fsl_ssi_shutdown(struct snd_pcm_substream *substream, * (In 2-channel I2S Master mode, slot_width is fixed 32) */ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, - struct snd_soc_dai *cpu_dai, + struct snd_soc_dai *dai, struct snd_pcm_hw_params *hw_params) { - struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai); + struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(dai); struct regmap *regs = ssi->regs; int synchronous = ssi->cpu_dai_drv.symmetric_rates, ret; u32 pm = 999, div2, psr, stccr, mask, afreq, factor, i; @@ -701,7 +701,7 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, * never greater than 1/5 IPG clock rate */ if (freq * 5 > clk_get_rate(ssi->clk)) { - dev_err(cpu_dai->dev, "bitclk > ipgclk / 5\n"); + dev_err(dai->dev, "bitclk > ipgclk / 5\n"); return -EINVAL; } @@ -750,7 +750,7 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, /* No proper pm found if it is still remaining the initial value */ if (pm == 999) { - dev_err(cpu_dai->dev, "failed to handle the required sysclk\n"); + dev_err(dai->dev, "failed to handle the required sysclk\n"); return -EINVAL; } @@ -766,7 +766,7 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, if (!baudclk_is_used) { ret = clk_set_rate(ssi->baudclk, baudrate); if (ret) { - dev_err(cpu_dai->dev, "failed to set baudclk rate\n"); + dev_err(dai->dev, "failed to set baudclk rate\n"); return -EINVAL; } } @@ -787,9 +787,9 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, */ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params, -struct snd_soc_dai *cpu_dai) +struct snd_soc_dai *dai) { - struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai); + struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(dai); struct regmap *regs = ssi->regs; unsigned int channels = params_channels(hw_params); unsigned int sample_size = params_width(hw_params); @@ -806,7 +806,7 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, return 0; if (fsl_ssi_is_i2s_master(ssi)) { - ret = fsl_ssi_set_bclk(substream, cpu_dai, hw_params); + ret = fsl_ssi_set_bclk(substream, dai, hw_params); if (ret) return ret; @@ -844,7 +844,7 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, } static int fsl_ssi_hw_free(struct snd_pcm_substream *substream, - struct snd_soc_dai *cpu_dai) + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(rtd->cpu_dai); @@ -1013,30 +1013,30 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev, /** * Configure Digital Audio Interface (DAI) Format */ -static int fsl_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) +static int fsl_ssi_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) { - struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai); + struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(dai); /* AC97 configured DAIFMT earlier in the probe() */ if (fsl_ssi_is_ac97(ssi)) return 0; - return _fsl_ssi_set_dai_fmt(cpu_dai->dev, ssi, fmt); + return _fsl_ssi_set_dai_fmt(dai->dev, ssi, fmt); } /** * Set TDM slot number and slot width */ -static int fsl_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask, +static int fsl_ssi_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mask, int slots, int slot_width) { - struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai); + struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(dai); struct regmap *regs = ssi->regs; u32 val; /* The word length should be 8, 10, 12, 16, 18, 20, 22 or 24 */ if (slot_width & 1 || slot_width < 8 || slot_width > 24) { - dev_err(cpu_dai->dev, "invalid slot width: %d\n",
[PATCH v2 05/11] ASoC: fsl_ssi: Refine indentations and wrappings
This patch just simply unifies the coding style. Signed-off-by: Nicolin Chen--- Changelog v1->v2 * Added two missing indentation changes * Removed two extra blank lines. sound/soc/fsl/fsl_ssi.c | 239 +--- sound/soc/fsl/fsl_ssi.h | 2 +- sound/soc/fsl/fsl_ssi_dbg.c | 3 +- 3 files changed, 118 insertions(+), 126 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 8b5407d..9a3db08 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -69,21 +69,35 @@ * samples will be written to STX properly. */ #ifdef __BIG_ENDIAN -#define FSLSSI_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE | \ -SNDRV_PCM_FMTBIT_S18_3BE | SNDRV_PCM_FMTBIT_S20_3BE | \ -SNDRV_PCM_FMTBIT_S24_3BE | SNDRV_PCM_FMTBIT_S24_BE) +#define FSLSSI_I2S_FORMATS \ + (SNDRV_PCM_FMTBIT_S8 | \ +SNDRV_PCM_FMTBIT_S16_BE | \ +SNDRV_PCM_FMTBIT_S18_3BE | \ +SNDRV_PCM_FMTBIT_S20_3BE | \ +SNDRV_PCM_FMTBIT_S24_3BE | \ +SNDRV_PCM_FMTBIT_S24_BE) #else -#define FSLSSI_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \ -SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE | \ -SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE) +#define FSLSSI_I2S_FORMATS \ + (SNDRV_PCM_FMTBIT_S8 | \ +SNDRV_PCM_FMTBIT_S16_LE | \ +SNDRV_PCM_FMTBIT_S18_3LE | \ +SNDRV_PCM_FMTBIT_S20_3LE | \ +SNDRV_PCM_FMTBIT_S24_3LE | \ +SNDRV_PCM_FMTBIT_S24_LE) #endif -#define FSLSSI_SIER_DBG_RX_FLAGS (SSI_SIER_RFF0_EN | \ - SSI_SIER_RLS_EN | SSI_SIER_RFS_EN | \ - SSI_SIER_ROE0_EN | SSI_SIER_RFRC_EN) -#define FSLSSI_SIER_DBG_TX_FLAGS (SSI_SIER_TFE0_EN | \ - SSI_SIER_TLS_EN | SSI_SIER_TFS_EN | \ - SSI_SIER_TUE0_EN | SSI_SIER_TFRC_EN) +#define FSLSSI_SIER_DBG_RX_FLAGS \ + (SSI_SIER_RFF0_EN | \ +SSI_SIER_RLS_EN | \ +SSI_SIER_RFS_EN | \ +SSI_SIER_ROE0_EN | \ +SSI_SIER_RFRC_EN) +#define FSLSSI_SIER_DBG_TX_FLAGS \ + (SSI_SIER_TFE0_EN | \ +SSI_SIER_TLS_EN | \ +SSI_SIER_TFS_EN | \ +SSI_SIER_TUE0_EN | \ +SSI_SIER_TFRC_EN) enum fsl_ssi_type { FSL_SSI_MCP8610, @@ -291,8 +305,8 @@ static struct fsl_ssi_soc_data fsl_ssi_mpc8610 = { .imx = false, .offline_config = true, .sisr_write_mask = SSI_SISR_RFRC | SSI_SISR_TFRC | - SSI_SISR_ROE0 | SSI_SISR_ROE1 | - SSI_SISR_TUE0 | SSI_SISR_TUE1, + SSI_SISR_ROE0 | SSI_SISR_ROE1 | + SSI_SISR_TUE0 | SSI_SISR_TUE1, }; static struct fsl_ssi_soc_data fsl_ssi_imx21 = { @@ -306,15 +320,15 @@ static struct fsl_ssi_soc_data fsl_ssi_imx35 = { .imx = true, .offline_config = true, .sisr_write_mask = SSI_SISR_RFRC | SSI_SISR_TFRC | - SSI_SISR_ROE0 | SSI_SISR_ROE1 | - SSI_SISR_TUE0 | SSI_SISR_TUE1, + SSI_SISR_ROE0 | SSI_SISR_ROE1 | + SSI_SISR_TUE0 | SSI_SISR_TUE1, }; static struct fsl_ssi_soc_data fsl_ssi_imx51 = { .imx = true, .offline_config = false, .sisr_write_mask = SSI_SISR_ROE0 | SSI_SISR_ROE1 | - SSI_SISR_TUE0 | SSI_SISR_TUE1, + SSI_SISR_TUE0 | SSI_SISR_TUE1, }; static const struct of_device_id fsl_ssi_ids[] = { @@ -373,21 +387,21 @@ static void fsl_ssi_rxtx_config(struct fsl_ssi *ssi, bool enable) if (enable) { regmap_update_bits(regs, REG_SSI_SIER, - vals->rx.sier | vals->tx.sier, - vals->rx.sier | vals->tx.sier); + vals->rx.sier | vals->tx.sier, + vals->rx.sier | vals->tx.sier); regmap_update_bits(regs, REG_SSI_SRCR, - vals->rx.srcr | vals->tx.srcr, - vals->rx.srcr | vals->tx.srcr); + vals->rx.srcr | vals->tx.srcr, + vals->rx.srcr | vals->tx.srcr); regmap_update_bits(regs, REG_SSI_STCR, - vals->rx.stcr | vals->tx.stcr, - vals->rx.stcr | vals->tx.stcr); + vals->rx.stcr | vals->tx.stcr, + vals->rx.stcr | vals->tx.stcr); } else { regmap_update_bits(regs, REG_SSI_SRCR, - vals->rx.srcr | vals->tx.srcr, 0); + vals->rx.srcr | vals->tx.srcr, 0); regmap_update_bits(regs, REG_SSI_STCR, - vals->rx.stcr | vals->tx.stcr, 0); + vals->rx.stcr | vals->tx.stcr, 0);
[PATCH v2 07/11] ASoC: fsl_ssi: Rename cpu_dai parameter to dai
Shortens the variable name to save space, useful for dev_err outputs. Signed-off-by: Nicolin Chen --- sound/soc/fsl/fsl_ssi.c | 32 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index d3bb662..69fa86d 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -668,10 +668,10 @@ static void fsl_ssi_shutdown(struct snd_pcm_substream *substream, * (In 2-channel I2S Master mode, slot_width is fixed 32) */ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, - struct snd_soc_dai *cpu_dai, + struct snd_soc_dai *dai, struct snd_pcm_hw_params *hw_params) { - struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai); + struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(dai); struct regmap *regs = ssi->regs; int synchronous = ssi->cpu_dai_drv.symmetric_rates, ret; u32 pm = 999, div2, psr, stccr, mask, afreq, factor, i; @@ -701,7 +701,7 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, * never greater than 1/5 IPG clock rate */ if (freq * 5 > clk_get_rate(ssi->clk)) { - dev_err(cpu_dai->dev, "bitclk > ipgclk / 5\n"); + dev_err(dai->dev, "bitclk > ipgclk / 5\n"); return -EINVAL; } @@ -750,7 +750,7 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, /* No proper pm found if it is still remaining the initial value */ if (pm == 999) { - dev_err(cpu_dai->dev, "failed to handle the required sysclk\n"); + dev_err(dai->dev, "failed to handle the required sysclk\n"); return -EINVAL; } @@ -766,7 +766,7 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, if (!baudclk_is_used) { ret = clk_set_rate(ssi->baudclk, baudrate); if (ret) { - dev_err(cpu_dai->dev, "failed to set baudclk rate\n"); + dev_err(dai->dev, "failed to set baudclk rate\n"); return -EINVAL; } } @@ -787,9 +787,9 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, */ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params, -struct snd_soc_dai *cpu_dai) +struct snd_soc_dai *dai) { - struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai); + struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(dai); struct regmap *regs = ssi->regs; unsigned int channels = params_channels(hw_params); unsigned int sample_size = params_width(hw_params); @@ -806,7 +806,7 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, return 0; if (fsl_ssi_is_i2s_master(ssi)) { - ret = fsl_ssi_set_bclk(substream, cpu_dai, hw_params); + ret = fsl_ssi_set_bclk(substream, dai, hw_params); if (ret) return ret; @@ -844,7 +844,7 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, } static int fsl_ssi_hw_free(struct snd_pcm_substream *substream, - struct snd_soc_dai *cpu_dai) + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(rtd->cpu_dai); @@ -1013,30 +1013,30 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev, /** * Configure Digital Audio Interface (DAI) Format */ -static int fsl_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) +static int fsl_ssi_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) { - struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai); + struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(dai); /* AC97 configured DAIFMT earlier in the probe() */ if (fsl_ssi_is_ac97(ssi)) return 0; - return _fsl_ssi_set_dai_fmt(cpu_dai->dev, ssi, fmt); + return _fsl_ssi_set_dai_fmt(dai->dev, ssi, fmt); } /** * Set TDM slot number and slot width */ -static int fsl_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask, +static int fsl_ssi_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mask, int slots, int slot_width) { - struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai); + struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(dai); struct regmap *regs = ssi->regs; u32 val; /* The word length should be 8, 10, 12, 16, 18, 20, 22 or 24 */ if (slot_width & 1 || slot_width < 8 || slot_width > 24) { - dev_err(cpu_dai->dev, "invalid slot width: %d\n", slot_width); +
[PATCH v2 05/11] ASoC: fsl_ssi: Refine indentations and wrappings
This patch just simply unifies the coding style. Signed-off-by: Nicolin Chen --- Changelog v1->v2 * Added two missing indentation changes * Removed two extra blank lines. sound/soc/fsl/fsl_ssi.c | 239 +--- sound/soc/fsl/fsl_ssi.h | 2 +- sound/soc/fsl/fsl_ssi_dbg.c | 3 +- 3 files changed, 118 insertions(+), 126 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 8b5407d..9a3db08 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -69,21 +69,35 @@ * samples will be written to STX properly. */ #ifdef __BIG_ENDIAN -#define FSLSSI_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE | \ -SNDRV_PCM_FMTBIT_S18_3BE | SNDRV_PCM_FMTBIT_S20_3BE | \ -SNDRV_PCM_FMTBIT_S24_3BE | SNDRV_PCM_FMTBIT_S24_BE) +#define FSLSSI_I2S_FORMATS \ + (SNDRV_PCM_FMTBIT_S8 | \ +SNDRV_PCM_FMTBIT_S16_BE | \ +SNDRV_PCM_FMTBIT_S18_3BE | \ +SNDRV_PCM_FMTBIT_S20_3BE | \ +SNDRV_PCM_FMTBIT_S24_3BE | \ +SNDRV_PCM_FMTBIT_S24_BE) #else -#define FSLSSI_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \ -SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE | \ -SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE) +#define FSLSSI_I2S_FORMATS \ + (SNDRV_PCM_FMTBIT_S8 | \ +SNDRV_PCM_FMTBIT_S16_LE | \ +SNDRV_PCM_FMTBIT_S18_3LE | \ +SNDRV_PCM_FMTBIT_S20_3LE | \ +SNDRV_PCM_FMTBIT_S24_3LE | \ +SNDRV_PCM_FMTBIT_S24_LE) #endif -#define FSLSSI_SIER_DBG_RX_FLAGS (SSI_SIER_RFF0_EN | \ - SSI_SIER_RLS_EN | SSI_SIER_RFS_EN | \ - SSI_SIER_ROE0_EN | SSI_SIER_RFRC_EN) -#define FSLSSI_SIER_DBG_TX_FLAGS (SSI_SIER_TFE0_EN | \ - SSI_SIER_TLS_EN | SSI_SIER_TFS_EN | \ - SSI_SIER_TUE0_EN | SSI_SIER_TFRC_EN) +#define FSLSSI_SIER_DBG_RX_FLAGS \ + (SSI_SIER_RFF0_EN | \ +SSI_SIER_RLS_EN | \ +SSI_SIER_RFS_EN | \ +SSI_SIER_ROE0_EN | \ +SSI_SIER_RFRC_EN) +#define FSLSSI_SIER_DBG_TX_FLAGS \ + (SSI_SIER_TFE0_EN | \ +SSI_SIER_TLS_EN | \ +SSI_SIER_TFS_EN | \ +SSI_SIER_TUE0_EN | \ +SSI_SIER_TFRC_EN) enum fsl_ssi_type { FSL_SSI_MCP8610, @@ -291,8 +305,8 @@ static struct fsl_ssi_soc_data fsl_ssi_mpc8610 = { .imx = false, .offline_config = true, .sisr_write_mask = SSI_SISR_RFRC | SSI_SISR_TFRC | - SSI_SISR_ROE0 | SSI_SISR_ROE1 | - SSI_SISR_TUE0 | SSI_SISR_TUE1, + SSI_SISR_ROE0 | SSI_SISR_ROE1 | + SSI_SISR_TUE0 | SSI_SISR_TUE1, }; static struct fsl_ssi_soc_data fsl_ssi_imx21 = { @@ -306,15 +320,15 @@ static struct fsl_ssi_soc_data fsl_ssi_imx35 = { .imx = true, .offline_config = true, .sisr_write_mask = SSI_SISR_RFRC | SSI_SISR_TFRC | - SSI_SISR_ROE0 | SSI_SISR_ROE1 | - SSI_SISR_TUE0 | SSI_SISR_TUE1, + SSI_SISR_ROE0 | SSI_SISR_ROE1 | + SSI_SISR_TUE0 | SSI_SISR_TUE1, }; static struct fsl_ssi_soc_data fsl_ssi_imx51 = { .imx = true, .offline_config = false, .sisr_write_mask = SSI_SISR_ROE0 | SSI_SISR_ROE1 | - SSI_SISR_TUE0 | SSI_SISR_TUE1, + SSI_SISR_TUE0 | SSI_SISR_TUE1, }; static const struct of_device_id fsl_ssi_ids[] = { @@ -373,21 +387,21 @@ static void fsl_ssi_rxtx_config(struct fsl_ssi *ssi, bool enable) if (enable) { regmap_update_bits(regs, REG_SSI_SIER, - vals->rx.sier | vals->tx.sier, - vals->rx.sier | vals->tx.sier); + vals->rx.sier | vals->tx.sier, + vals->rx.sier | vals->tx.sier); regmap_update_bits(regs, REG_SSI_SRCR, - vals->rx.srcr | vals->tx.srcr, - vals->rx.srcr | vals->tx.srcr); + vals->rx.srcr | vals->tx.srcr, + vals->rx.srcr | vals->tx.srcr); regmap_update_bits(regs, REG_SSI_STCR, - vals->rx.stcr | vals->tx.stcr, - vals->rx.stcr | vals->tx.stcr); + vals->rx.stcr | vals->tx.stcr, + vals->rx.stcr | vals->tx.stcr); } else { regmap_update_bits(regs, REG_SSI_SRCR, - vals->rx.srcr | vals->tx.srcr, 0); + vals->rx.srcr | vals->tx.srcr, 0); regmap_update_bits(regs, REG_SSI_STCR, - vals->rx.stcr | vals->tx.stcr, 0); + vals->rx.stcr | vals->tx.stcr, 0);
[PATCH v2 02/11] ASoC: fsl_ssi: Cache pdev->dev pointer
There should be no trouble to understand dev = pdev->dev. This can save some space to have more print info or save some wrapped lines. Signed-off-by: Nicolin Chen--- sound/soc/fsl/fsl_ssi.c | 64 - 1 file changed, 31 insertions(+), 33 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 84d2f7e..e903c92 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -1379,23 +1379,24 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev, struct fsl_ssi *ssi, void __iomem *iomem) { struct device_node *np = pdev->dev.of_node; + struct device *dev = >dev; u32 dmas[4]; int ret; if (ssi->has_ipg_clk_name) - ssi->clk = devm_clk_get(>dev, "ipg"); + ssi->clk = devm_clk_get(dev, "ipg"); else - ssi->clk = devm_clk_get(>dev, NULL); + ssi->clk = devm_clk_get(dev, NULL); if (IS_ERR(ssi->clk)) { ret = PTR_ERR(ssi->clk); - dev_err(>dev, "could not get clock: %d\n", ret); + dev_err(dev, "could not get clock: %d\n", ret); return ret; } if (!ssi->has_ipg_clk_name) { ret = clk_prepare_enable(ssi->clk); if (ret) { - dev_err(>dev, "clk_prepare_enable failed: %d\n", ret); + dev_err(dev, "clk_prepare_enable failed: %d\n", ret); return ret; } } @@ -1403,9 +1404,9 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev, /* For those SLAVE implementations, we ignore non-baudclk cases * and, instead, abandon MASTER mode that needs baud clock. */ - ssi->baudclk = devm_clk_get(>dev, "baud"); + ssi->baudclk = devm_clk_get(dev, "baud"); if (IS_ERR(ssi->baudclk)) - dev_dbg(>dev, "could not get baud clock: %ld\n", + dev_dbg(dev, "could not get baud clock: %ld\n", PTR_ERR(ssi->baudclk)); ssi->dma_params_tx.maxburst = ssi->dma_maxburst; @@ -1469,6 +1470,7 @@ static int fsl_ssi_probe(struct platform_device *pdev) struct fsl_ssi *ssi; int ret = 0; struct device_node *np = pdev->dev.of_node; + struct device *dev = >dev; const struct of_device_id *of_id; const char *p, *sprop; const uint32_t *iprop; @@ -1477,17 +1479,16 @@ static int fsl_ssi_probe(struct platform_device *pdev) char name[64]; struct regmap_config regconfig = fsl_ssi_regconfig; - of_id = of_match_device(fsl_ssi_ids, >dev); + of_id = of_match_device(fsl_ssi_ids, dev); if (!of_id || !of_id->data) return -EINVAL; - ssi = devm_kzalloc(>dev, sizeof(*ssi), - GFP_KERNEL); + ssi = devm_kzalloc(dev, sizeof(*ssi), GFP_KERNEL); if (!ssi) return -ENOMEM; ssi->soc = of_id->data; - ssi->dev = >dev; + ssi->dev = dev; sprop = of_get_property(np, "fsl,mode", NULL); if (sprop) { @@ -1507,10 +1508,10 @@ static int fsl_ssi_probe(struct platform_device *pdev) memcpy(>cpu_dai_drv, _ssi_dai_template, sizeof(fsl_ssi_dai_template)); } - ssi->cpu_dai_drv.name = dev_name(>dev); + ssi->cpu_dai_drv.name = dev_name(dev); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - iomem = devm_ioremap_resource(>dev, res); + iomem = devm_ioremap_resource(dev, res); if (IS_ERR(iomem)) return PTR_ERR(iomem); ssi->ssi_phys = res->start; @@ -1528,21 +1529,20 @@ static int fsl_ssi_probe(struct platform_device *pdev) ret = of_property_match_string(np, "clock-names", "ipg"); if (ret < 0) { ssi->has_ipg_clk_name = false; - ssi->regs = devm_regmap_init_mmio(>dev, iomem, - ); + ssi->regs = devm_regmap_init_mmio(dev, iomem, ); } else { ssi->has_ipg_clk_name = true; - ssi->regs = devm_regmap_init_mmio_clk(>dev, - "ipg", iomem, ); + ssi->regs = devm_regmap_init_mmio_clk(dev, "ipg", iomem, + ); } if (IS_ERR(ssi->regs)) { - dev_err(>dev, "Failed to init register map\n"); + dev_err(dev, "Failed to init register map\n"); return PTR_ERR(ssi->regs); } ssi->irq = platform_get_irq(pdev, 0); if (ssi->irq < 0) { - dev_err(>dev, "no irq for node %s\n", pdev->name); + dev_err(dev, "no irq for node %s\n", pdev->name); return ssi->irq; } @@ -1605,7 +1605,7 @@ static int fsl_ssi_probe(struct platform_device *pdev)
[PATCH v2 02/11] ASoC: fsl_ssi: Cache pdev->dev pointer
There should be no trouble to understand dev = pdev->dev. This can save some space to have more print info or save some wrapped lines. Signed-off-by: Nicolin Chen --- sound/soc/fsl/fsl_ssi.c | 64 - 1 file changed, 31 insertions(+), 33 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 84d2f7e..e903c92 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -1379,23 +1379,24 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev, struct fsl_ssi *ssi, void __iomem *iomem) { struct device_node *np = pdev->dev.of_node; + struct device *dev = >dev; u32 dmas[4]; int ret; if (ssi->has_ipg_clk_name) - ssi->clk = devm_clk_get(>dev, "ipg"); + ssi->clk = devm_clk_get(dev, "ipg"); else - ssi->clk = devm_clk_get(>dev, NULL); + ssi->clk = devm_clk_get(dev, NULL); if (IS_ERR(ssi->clk)) { ret = PTR_ERR(ssi->clk); - dev_err(>dev, "could not get clock: %d\n", ret); + dev_err(dev, "could not get clock: %d\n", ret); return ret; } if (!ssi->has_ipg_clk_name) { ret = clk_prepare_enable(ssi->clk); if (ret) { - dev_err(>dev, "clk_prepare_enable failed: %d\n", ret); + dev_err(dev, "clk_prepare_enable failed: %d\n", ret); return ret; } } @@ -1403,9 +1404,9 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev, /* For those SLAVE implementations, we ignore non-baudclk cases * and, instead, abandon MASTER mode that needs baud clock. */ - ssi->baudclk = devm_clk_get(>dev, "baud"); + ssi->baudclk = devm_clk_get(dev, "baud"); if (IS_ERR(ssi->baudclk)) - dev_dbg(>dev, "could not get baud clock: %ld\n", + dev_dbg(dev, "could not get baud clock: %ld\n", PTR_ERR(ssi->baudclk)); ssi->dma_params_tx.maxburst = ssi->dma_maxburst; @@ -1469,6 +1470,7 @@ static int fsl_ssi_probe(struct platform_device *pdev) struct fsl_ssi *ssi; int ret = 0; struct device_node *np = pdev->dev.of_node; + struct device *dev = >dev; const struct of_device_id *of_id; const char *p, *sprop; const uint32_t *iprop; @@ -1477,17 +1479,16 @@ static int fsl_ssi_probe(struct platform_device *pdev) char name[64]; struct regmap_config regconfig = fsl_ssi_regconfig; - of_id = of_match_device(fsl_ssi_ids, >dev); + of_id = of_match_device(fsl_ssi_ids, dev); if (!of_id || !of_id->data) return -EINVAL; - ssi = devm_kzalloc(>dev, sizeof(*ssi), - GFP_KERNEL); + ssi = devm_kzalloc(dev, sizeof(*ssi), GFP_KERNEL); if (!ssi) return -ENOMEM; ssi->soc = of_id->data; - ssi->dev = >dev; + ssi->dev = dev; sprop = of_get_property(np, "fsl,mode", NULL); if (sprop) { @@ -1507,10 +1508,10 @@ static int fsl_ssi_probe(struct platform_device *pdev) memcpy(>cpu_dai_drv, _ssi_dai_template, sizeof(fsl_ssi_dai_template)); } - ssi->cpu_dai_drv.name = dev_name(>dev); + ssi->cpu_dai_drv.name = dev_name(dev); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - iomem = devm_ioremap_resource(>dev, res); + iomem = devm_ioremap_resource(dev, res); if (IS_ERR(iomem)) return PTR_ERR(iomem); ssi->ssi_phys = res->start; @@ -1528,21 +1529,20 @@ static int fsl_ssi_probe(struct platform_device *pdev) ret = of_property_match_string(np, "clock-names", "ipg"); if (ret < 0) { ssi->has_ipg_clk_name = false; - ssi->regs = devm_regmap_init_mmio(>dev, iomem, - ); + ssi->regs = devm_regmap_init_mmio(dev, iomem, ); } else { ssi->has_ipg_clk_name = true; - ssi->regs = devm_regmap_init_mmio_clk(>dev, - "ipg", iomem, ); + ssi->regs = devm_regmap_init_mmio_clk(dev, "ipg", iomem, + ); } if (IS_ERR(ssi->regs)) { - dev_err(>dev, "Failed to init register map\n"); + dev_err(dev, "Failed to init register map\n"); return PTR_ERR(ssi->regs); } ssi->irq = platform_get_irq(pdev, 0); if (ssi->irq < 0) { - dev_err(>dev, "no irq for node %s\n", pdev->name); + dev_err(dev, "no irq for node %s\n", pdev->name); return ssi->irq; } @@ -1605,7 +1605,7 @@ static int fsl_ssi_probe(struct platform_device *pdev) break; } -
[PATCH v2 09/11] ASoC: fsl_ssi: Replace fsl_ssi_rxtx_reg_val with fsl_ssi_regvals
The name fsl_ssi_rxtx_reg_val is too long to read comfortably. So this patch shortens it by using an array (fsl_ssi_regvals, renamed from fsl_ssi_reg_val). To do that, it also introduces two macros (TX and RX) to replace the wrapper structure. This will also help further cleanups. Meanwhile, it unifies all local variable with the name "vals" to get rid of the name "reg" -- could be confusing with "regs" in the private struct for regmap. Signed-off-by: Nicolin Chen--- sound/soc/fsl/fsl_ssi.c | 79 +++-- sound/soc/fsl/fsl_ssi.h | 3 ++ 2 files changed, 40 insertions(+), 42 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 7fcc6bd..7a8a768 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -106,18 +106,13 @@ enum fsl_ssi_type { FSL_SSI_MX51, }; -struct fsl_ssi_reg_val { +struct fsl_ssi_regvals { u32 sier; u32 srcr; u32 stcr; u32 scr; }; -struct fsl_ssi_rxtx_reg_val { - struct fsl_ssi_reg_val rx; - struct fsl_ssi_reg_val tx; -}; - static bool fsl_ssi_readable_reg(struct device *dev, unsigned int reg) { switch (reg) { @@ -213,7 +208,7 @@ struct fsl_ssi_soc_data { * @fifo_depth: Depth of the SSI FIFOs * @slot_width: Width of each DAI slot * @slots: Number of slots - * @rxtx_reg_val: Specific RX/TX register settings + * @regvals: Specific RX/TX register settings * * @clk: Clock source to access register * @baudclk: Clock source to generate bit and frame-sync clocks @@ -257,7 +252,7 @@ struct fsl_ssi { unsigned int fifo_depth; unsigned int slot_width; unsigned int slots; - struct fsl_ssi_rxtx_reg_val rxtx_reg_val; + struct fsl_ssi_regvals regvals[2]; struct clk *clk; struct clk *baudclk; @@ -383,25 +378,25 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id) static void fsl_ssi_rxtx_config(struct fsl_ssi *ssi, bool enable) { struct regmap *regs = ssi->regs; - struct fsl_ssi_rxtx_reg_val *vals = >rxtx_reg_val; + struct fsl_ssi_regvals *vals = ssi->regvals; if (enable) { regmap_update_bits(regs, REG_SSI_SIER, - vals->rx.sier | vals->tx.sier, - vals->rx.sier | vals->tx.sier); + vals[RX].sier | vals[TX].sier, + vals[RX].sier | vals[TX].sier); regmap_update_bits(regs, REG_SSI_SRCR, - vals->rx.srcr | vals->tx.srcr, - vals->rx.srcr | vals->tx.srcr); + vals[RX].srcr | vals[TX].srcr, + vals[RX].srcr | vals[TX].srcr); regmap_update_bits(regs, REG_SSI_STCR, - vals->rx.stcr | vals->tx.stcr, - vals->rx.stcr | vals->tx.stcr); + vals[RX].stcr | vals[TX].stcr, + vals[RX].stcr | vals[TX].stcr); } else { regmap_update_bits(regs, REG_SSI_SRCR, - vals->rx.srcr | vals->tx.srcr, 0); + vals[RX].srcr | vals[TX].srcr, 0); regmap_update_bits(regs, REG_SSI_STCR, - vals->rx.stcr | vals->tx.stcr, 0); + vals[RX].stcr | vals[TX].stcr, 0); regmap_update_bits(regs, REG_SSI_SIER, - vals->rx.sier | vals->tx.sier, 0); + vals[RX].sier | vals[TX].sier, 0); } } @@ -443,10 +438,10 @@ static void fsl_ssi_fifo_clear(struct fsl_ssi *ssi, bool is_rx) * Enable or disable SSI configuration. */ static void fsl_ssi_config(struct fsl_ssi *ssi, bool enable, - struct fsl_ssi_reg_val *vals) + struct fsl_ssi_regvals *vals) { struct regmap *regs = ssi->regs; - struct fsl_ssi_reg_val *avals; + struct fsl_ssi_regvals *avals; int nr_active_streams; u32 scr; int keep_active; @@ -461,10 +456,10 @@ static void fsl_ssi_config(struct fsl_ssi *ssi, bool enable, keep_active = 0; /* Get the opposite direction to keep its values untouched */ - if (>rxtx_reg_val.rx == vals) - avals = >rxtx_reg_val.tx; + if (>regvals[RX] == vals) + avals = >regvals[TX]; else - avals = >rxtx_reg_val.rx; + avals = >regvals[RX]; if (!enable) { /* Exclude necessary bits for the opposite stream */ @@ -543,7 +538,7 @@ static void fsl_ssi_config(struct fsl_ssi *ssi, bool enable, static void fsl_ssi_rx_config(struct fsl_ssi *ssi, bool enable) { - fsl_ssi_config(ssi, enable,
[PATCH v2 09/11] ASoC: fsl_ssi: Replace fsl_ssi_rxtx_reg_val with fsl_ssi_regvals
The name fsl_ssi_rxtx_reg_val is too long to read comfortably. So this patch shortens it by using an array (fsl_ssi_regvals, renamed from fsl_ssi_reg_val). To do that, it also introduces two macros (TX and RX) to replace the wrapper structure. This will also help further cleanups. Meanwhile, it unifies all local variable with the name "vals" to get rid of the name "reg" -- could be confusing with "regs" in the private struct for regmap. Signed-off-by: Nicolin Chen --- sound/soc/fsl/fsl_ssi.c | 79 +++-- sound/soc/fsl/fsl_ssi.h | 3 ++ 2 files changed, 40 insertions(+), 42 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 7fcc6bd..7a8a768 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -106,18 +106,13 @@ enum fsl_ssi_type { FSL_SSI_MX51, }; -struct fsl_ssi_reg_val { +struct fsl_ssi_regvals { u32 sier; u32 srcr; u32 stcr; u32 scr; }; -struct fsl_ssi_rxtx_reg_val { - struct fsl_ssi_reg_val rx; - struct fsl_ssi_reg_val tx; -}; - static bool fsl_ssi_readable_reg(struct device *dev, unsigned int reg) { switch (reg) { @@ -213,7 +208,7 @@ struct fsl_ssi_soc_data { * @fifo_depth: Depth of the SSI FIFOs * @slot_width: Width of each DAI slot * @slots: Number of slots - * @rxtx_reg_val: Specific RX/TX register settings + * @regvals: Specific RX/TX register settings * * @clk: Clock source to access register * @baudclk: Clock source to generate bit and frame-sync clocks @@ -257,7 +252,7 @@ struct fsl_ssi { unsigned int fifo_depth; unsigned int slot_width; unsigned int slots; - struct fsl_ssi_rxtx_reg_val rxtx_reg_val; + struct fsl_ssi_regvals regvals[2]; struct clk *clk; struct clk *baudclk; @@ -383,25 +378,25 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id) static void fsl_ssi_rxtx_config(struct fsl_ssi *ssi, bool enable) { struct regmap *regs = ssi->regs; - struct fsl_ssi_rxtx_reg_val *vals = >rxtx_reg_val; + struct fsl_ssi_regvals *vals = ssi->regvals; if (enable) { regmap_update_bits(regs, REG_SSI_SIER, - vals->rx.sier | vals->tx.sier, - vals->rx.sier | vals->tx.sier); + vals[RX].sier | vals[TX].sier, + vals[RX].sier | vals[TX].sier); regmap_update_bits(regs, REG_SSI_SRCR, - vals->rx.srcr | vals->tx.srcr, - vals->rx.srcr | vals->tx.srcr); + vals[RX].srcr | vals[TX].srcr, + vals[RX].srcr | vals[TX].srcr); regmap_update_bits(regs, REG_SSI_STCR, - vals->rx.stcr | vals->tx.stcr, - vals->rx.stcr | vals->tx.stcr); + vals[RX].stcr | vals[TX].stcr, + vals[RX].stcr | vals[TX].stcr); } else { regmap_update_bits(regs, REG_SSI_SRCR, - vals->rx.srcr | vals->tx.srcr, 0); + vals[RX].srcr | vals[TX].srcr, 0); regmap_update_bits(regs, REG_SSI_STCR, - vals->rx.stcr | vals->tx.stcr, 0); + vals[RX].stcr | vals[TX].stcr, 0); regmap_update_bits(regs, REG_SSI_SIER, - vals->rx.sier | vals->tx.sier, 0); + vals[RX].sier | vals[TX].sier, 0); } } @@ -443,10 +438,10 @@ static void fsl_ssi_fifo_clear(struct fsl_ssi *ssi, bool is_rx) * Enable or disable SSI configuration. */ static void fsl_ssi_config(struct fsl_ssi *ssi, bool enable, - struct fsl_ssi_reg_val *vals) + struct fsl_ssi_regvals *vals) { struct regmap *regs = ssi->regs; - struct fsl_ssi_reg_val *avals; + struct fsl_ssi_regvals *avals; int nr_active_streams; u32 scr; int keep_active; @@ -461,10 +456,10 @@ static void fsl_ssi_config(struct fsl_ssi *ssi, bool enable, keep_active = 0; /* Get the opposite direction to keep its values untouched */ - if (>rxtx_reg_val.rx == vals) - avals = >rxtx_reg_val.tx; + if (>regvals[RX] == vals) + avals = >regvals[TX]; else - avals = >rxtx_reg_val.rx; + avals = >regvals[RX]; if (!enable) { /* Exclude necessary bits for the opposite stream */ @@ -543,7 +538,7 @@ static void fsl_ssi_config(struct fsl_ssi *ssi, bool enable, static void fsl_ssi_rx_config(struct fsl_ssi *ssi, bool enable) { - fsl_ssi_config(ssi, enable, >rxtx_reg_val.rx); +
[PATCH v2 11/11] ASoC: fsl_ssi: Define ternary macros to simplify code
Some regmap code looks redudant. So simplify it. Signed-off-by: Nicolin Chen--- sound/soc/fsl/fsl_ssi.c | 27 +++ sound/soc/fsl/fsl_ssi.h | 4 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index dd091eb..5b4fa43 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -405,13 +405,10 @@ static void fsl_ssi_rxtx_config(struct fsl_ssi *ssi, bool enable) */ static void fsl_ssi_fifo_clear(struct fsl_ssi *ssi, bool is_rx) { - if (is_rx) { - regmap_update_bits(ssi->regs, REG_SSI_SOR, - SSI_SOR_RX_CLR, SSI_SOR_RX_CLR); - } else { - regmap_update_bits(ssi->regs, REG_SSI_SOR, - SSI_SOR_TX_CLR, SSI_SOR_TX_CLR); - } + bool tx = !is_rx; + + regmap_update_bits(ssi->regs, REG_SSI_SOR, + SSI_SOR_xX_CLR(tx), SSI_SOR_xX_CLR(tx)); } /** @@ -666,6 +663,7 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, struct snd_soc_dai *dai, struct snd_pcm_hw_params *hw_params) { + bool tx2, tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(dai); struct regmap *regs = ssi->regs; int synchronous = ssi->cpu_dai_drv.symmetric_rates, ret; @@ -753,10 +751,9 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, (psr ? SSI_SxCCR_PSR : 0); mask = SSI_SxCCR_PM_MASK | SSI_SxCCR_DIV2 | SSI_SxCCR_PSR; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK || synchronous) - regmap_update_bits(regs, REG_SSI_STCCR, mask, stccr); - else - regmap_update_bits(regs, REG_SSI_SRCCR, mask, stccr); + /* STCCR is used for RX in synchronous mode */ + tx2 = tx || synchronous; + regmap_update_bits(regs, REG_SSI_SxCCR(tx2), mask, stccr); if (!baudclk_is_used) { ret = clk_set_rate(ssi->baudclk, baudrate); @@ -784,6 +781,7 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *dai) { + bool tx2, tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(dai); struct regmap *regs = ssi->regs; unsigned int channels = params_channels(hw_params); @@ -829,11 +827,8 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, } /* In synchronous mode, the SSI uses STCCR for capture */ - if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) || - ssi->cpu_dai_drv.symmetric_rates) - regmap_update_bits(regs, REG_SSI_STCCR, SSI_SxCCR_WL_MASK, wl); - else - regmap_update_bits(regs, REG_SSI_SRCCR, SSI_SxCCR_WL_MASK, wl); + tx2 = tx || ssi->cpu_dai_drv.symmetric_rates; + regmap_update_bits(regs, REG_SSI_SxCCR(tx2), SSI_SxCCR_WL_MASK, wl); return 0; } diff --git a/sound/soc/fsl/fsl_ssi.h b/sound/soc/fsl/fsl_ssi.h index b610087..de2fdc5 100644 --- a/sound/soc/fsl/fsl_ssi.h +++ b/sound/soc/fsl/fsl_ssi.h @@ -35,10 +35,12 @@ #define REG_SSI_STCR 0x1c /* SSI Receive Configuration Register */ #define REG_SSI_SRCR 0x20 +#define REG_SSI_SxCR(tx) ((tx) ? REG_SSI_STCR : REG_SSI_SRCR) /* SSI Transmit Clock Control Register */ #define REG_SSI_STCCR 0x24 /* SSI Receive Clock Control Register */ #define REG_SSI_SRCCR 0x28 +#define REG_SSI_SxCCR(tx) ((tx) ? REG_SSI_STCCR : REG_SSI_SRCCR) /* SSI FIFO Control/Status Register */ #define REG_SSI_SFCSR 0x2c /* @@ -67,6 +69,7 @@ #define REG_SSI_STMSK 0x48 /* SSI Receive Time Slot Mask Register */ #define REG_SSI_SRMSK 0x4c +#define REG_SSI_SxMSK(tx) ((tx) ? REG_SSI_STMSK : REG_SSI_SRMSK) /* * SSI AC97 Channel Status Register * @@ -249,6 +252,7 @@ #define SSI_SOR_CLKOFF 0x0040 #define SSI_SOR_RX_CLR 0x0020 #define SSI_SOR_TX_CLR 0x0010 +#define SSI_SOR_xX_CLR(tx) ((tx) ? SSI_SOR_TX_CLR : SSI_SOR_RX_CLR) #define SSI_SOR_INIT 0x0008 #define SSI_SOR_WAIT_SHIFT 1 #define SSI_SOR_WAIT_MASK 0x0006 -- 2.7.4
[PATCH v2 11/11] ASoC: fsl_ssi: Define ternary macros to simplify code
Some regmap code looks redudant. So simplify it. Signed-off-by: Nicolin Chen --- sound/soc/fsl/fsl_ssi.c | 27 +++ sound/soc/fsl/fsl_ssi.h | 4 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index dd091eb..5b4fa43 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -405,13 +405,10 @@ static void fsl_ssi_rxtx_config(struct fsl_ssi *ssi, bool enable) */ static void fsl_ssi_fifo_clear(struct fsl_ssi *ssi, bool is_rx) { - if (is_rx) { - regmap_update_bits(ssi->regs, REG_SSI_SOR, - SSI_SOR_RX_CLR, SSI_SOR_RX_CLR); - } else { - regmap_update_bits(ssi->regs, REG_SSI_SOR, - SSI_SOR_TX_CLR, SSI_SOR_TX_CLR); - } + bool tx = !is_rx; + + regmap_update_bits(ssi->regs, REG_SSI_SOR, + SSI_SOR_xX_CLR(tx), SSI_SOR_xX_CLR(tx)); } /** @@ -666,6 +663,7 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, struct snd_soc_dai *dai, struct snd_pcm_hw_params *hw_params) { + bool tx2, tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(dai); struct regmap *regs = ssi->regs; int synchronous = ssi->cpu_dai_drv.symmetric_rates, ret; @@ -753,10 +751,9 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, (psr ? SSI_SxCCR_PSR : 0); mask = SSI_SxCCR_PM_MASK | SSI_SxCCR_DIV2 | SSI_SxCCR_PSR; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK || synchronous) - regmap_update_bits(regs, REG_SSI_STCCR, mask, stccr); - else - regmap_update_bits(regs, REG_SSI_SRCCR, mask, stccr); + /* STCCR is used for RX in synchronous mode */ + tx2 = tx || synchronous; + regmap_update_bits(regs, REG_SSI_SxCCR(tx2), mask, stccr); if (!baudclk_is_used) { ret = clk_set_rate(ssi->baudclk, baudrate); @@ -784,6 +781,7 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *dai) { + bool tx2, tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(dai); struct regmap *regs = ssi->regs; unsigned int channels = params_channels(hw_params); @@ -829,11 +827,8 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, } /* In synchronous mode, the SSI uses STCCR for capture */ - if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) || - ssi->cpu_dai_drv.symmetric_rates) - regmap_update_bits(regs, REG_SSI_STCCR, SSI_SxCCR_WL_MASK, wl); - else - regmap_update_bits(regs, REG_SSI_SRCCR, SSI_SxCCR_WL_MASK, wl); + tx2 = tx || ssi->cpu_dai_drv.symmetric_rates; + regmap_update_bits(regs, REG_SSI_SxCCR(tx2), SSI_SxCCR_WL_MASK, wl); return 0; } diff --git a/sound/soc/fsl/fsl_ssi.h b/sound/soc/fsl/fsl_ssi.h index b610087..de2fdc5 100644 --- a/sound/soc/fsl/fsl_ssi.h +++ b/sound/soc/fsl/fsl_ssi.h @@ -35,10 +35,12 @@ #define REG_SSI_STCR 0x1c /* SSI Receive Configuration Register */ #define REG_SSI_SRCR 0x20 +#define REG_SSI_SxCR(tx) ((tx) ? REG_SSI_STCR : REG_SSI_SRCR) /* SSI Transmit Clock Control Register */ #define REG_SSI_STCCR 0x24 /* SSI Receive Clock Control Register */ #define REG_SSI_SRCCR 0x28 +#define REG_SSI_SxCCR(tx) ((tx) ? REG_SSI_STCCR : REG_SSI_SRCCR) /* SSI FIFO Control/Status Register */ #define REG_SSI_SFCSR 0x2c /* @@ -67,6 +69,7 @@ #define REG_SSI_STMSK 0x48 /* SSI Receive Time Slot Mask Register */ #define REG_SSI_SRMSK 0x4c +#define REG_SSI_SxMSK(tx) ((tx) ? REG_SSI_STMSK : REG_SSI_SRMSK) /* * SSI AC97 Channel Status Register * @@ -249,6 +252,7 @@ #define SSI_SOR_CLKOFF 0x0040 #define SSI_SOR_RX_CLR 0x0020 #define SSI_SOR_TX_CLR 0x0010 +#define SSI_SOR_xX_CLR(tx) ((tx) ? SSI_SOR_TX_CLR : SSI_SOR_RX_CLR) #define SSI_SOR_INIT 0x0008 #define SSI_SOR_WAIT_SHIFT 1 #define SSI_SOR_WAIT_MASK 0x0006 -- 2.7.4
[PATCH v2 08/11] ASoC: fsl_ssi: Rename scr_val to scr
Simplify the variable name. This reduces one over-80-character line. Signed-off-by: Nicolin Chen--- sound/soc/fsl/fsl_ssi.c | 12 ++-- 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 69fa86d..7fcc6bd 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -448,12 +448,12 @@ static void fsl_ssi_config(struct fsl_ssi *ssi, bool enable, struct regmap *regs = ssi->regs; struct fsl_ssi_reg_val *avals; int nr_active_streams; - u32 scr_val; + u32 scr; int keep_active; - regmap_read(regs, REG_SSI_SCR, _val); + regmap_read(regs, REG_SSI_SCR, ); - nr_active_streams = !!(scr_val & SSI_SCR_TE) + !!(scr_val & SSI_SCR_RE); + nr_active_streams = !!(scr & SSI_SCR_TE) + !!(scr & SSI_SCR_RE); if (nr_active_streams - 1 > 0) keep_active = 1; @@ -795,11 +795,11 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, unsigned int sample_size = params_width(hw_params); u32 wl = SSI_SxCCR_WL(sample_size); int ret; - u32 scr_val; + u32 scr; int enabled; - regmap_read(regs, REG_SSI_SCR, _val); - enabled = scr_val & SSI_SCR_SSIEN; + regmap_read(regs, REG_SSI_SCR, ); + enabled = scr & SSI_SCR_SSIEN; /* To support simultaneous TX and RX, bypass it if SSI is enabled */ if (enabled && ssi->cpu_dai_drv.symmetric_rates) -- 2.7.4
[PATCH v2 08/11] ASoC: fsl_ssi: Rename scr_val to scr
Simplify the variable name. This reduces one over-80-character line. Signed-off-by: Nicolin Chen --- sound/soc/fsl/fsl_ssi.c | 12 ++-- 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 69fa86d..7fcc6bd 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -448,12 +448,12 @@ static void fsl_ssi_config(struct fsl_ssi *ssi, bool enable, struct regmap *regs = ssi->regs; struct fsl_ssi_reg_val *avals; int nr_active_streams; - u32 scr_val; + u32 scr; int keep_active; - regmap_read(regs, REG_SSI_SCR, _val); + regmap_read(regs, REG_SSI_SCR, ); - nr_active_streams = !!(scr_val & SSI_SCR_TE) + !!(scr_val & SSI_SCR_RE); + nr_active_streams = !!(scr & SSI_SCR_TE) + !!(scr & SSI_SCR_RE); if (nr_active_streams - 1 > 0) keep_active = 1; @@ -795,11 +795,11 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, unsigned int sample_size = params_width(hw_params); u32 wl = SSI_SxCCR_WL(sample_size); int ret; - u32 scr_val; + u32 scr; int enabled; - regmap_read(regs, REG_SSI_SCR, _val); - enabled = scr_val & SSI_SCR_SSIEN; + regmap_read(regs, REG_SSI_SCR, ); + enabled = scr & SSI_SCR_SSIEN; /* To support simultaneous TX and RX, bypass it if SSI is enabled */ if (enabled && ssi->cpu_dai_drv.symmetric_rates) -- 2.7.4
[PATCH v2 03/11] ASoC: fsl_ssi: Refine all comments
This patch refines the comments by: 1) Removing all out-of-date comments 2) Removing all not-so-useful comments 3) Unifying the styles of all comments 4) Simplifying over-descriptive comments 5) Adding comments to improve code readablity 6) Moving all register related comments to fsl_ssi.h 7) Adding comments to all register and field defines Signed-off-by: Nicolin Chen--- Changelog v1->v2 * Added some new comments at "SoC specific data" to be more precise. * Revised one comment in fsl_ssi_config(). * Revised the comment of fsl_ssi_setup_reg_vals(). * Added one comment for AC97 in fsl_ssi_setup_reg_vals(). * Revised the comment of fsl_ssi_hw_params() to be more precise. * Added some comments in _fsl_ssi_set_dai_fmt() to help understand the formats. * Added one comment in fsl_ssi_set_dai_fmt() to state why AC97 needs to bypass it. * Revised comments in fsl_ssi_set_dai_tdm_slot() to be more precise. * Revised comments around dual FIFO code in fsl_ssi_imx_probe() to be more precise. sound/soc/fsl/fsl_ssi.c | 376 ++-- sound/soc/fsl/fsl_ssi.h | 67 +++- sound/soc/fsl/fsl_ssi_dbg.c | 12 +- 3 files changed, 188 insertions(+), 267 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index e903c92..796a7ea 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -187,42 +187,48 @@ struct fsl_ssi_soc_data { /** * fsl_ssi: per-SSI private data * - * @reg: Pointer to the regmap registers + * @regs: Pointer to the regmap registers * @irq: IRQ of this SSI * @cpu_dai_drv: CPU DAI driver for this device * * @dai_fmt: DAI configuration this device is currently used with - * @i2s_mode: i2s and network mode configuration of the device. Is used to - * switch between normal and i2s/network mode - * mode depending on the number of channels + * @i2s_mode: I2S and Network mode configuration of SCR register * @use_dma: DMA is used or FIQ with stream filter - * @use_dual_fifo: DMA with support for both FIFOs used - * @fifo_deph: Depth of the SSI FIFOs - * @slot_width: width of each DAI slot - * @slots: number of slots - * @rxtx_reg_val: Specific register settings for receive/transmit configuration + * @use_dual_fifo: DMA with support for dual FIFO mode + * @has_ipg_clk_name: If "ipg" is in the clock name list of device tree + * @fifo_depth: Depth of the SSI FIFOs + * @slot_width: Width of each DAI slot + * @slots: Number of slots + * @rxtx_reg_val: Specific RX/TX register settings * - * @clk: SSI clock - * @baudclk: SSI baud clock for master mode + * @clk: Clock source to access register + * @baudclk: Clock source to generate bit and frame-sync clocks * @baudclk_streams: Active streams that are using baudclk * + * @regcache_sfcsr: Cache sfcsr register value during suspend and resume + * @regcache_sacnt: Cache sacnt register value during suspend and resume + * * @dma_params_tx: DMA transmit parameters * @dma_params_rx: DMA receive parameters * @ssi_phys: physical address of the SSI registers * * @fiq_params: FIQ stream filtering parameters * - * @pdev: Pointer to pdev used for deprecated fsl-ssi sound card + * @pdev: Pointer to pdev when using fsl-ssi as sound card (ppc only) + *TODO: Should be replaced with simple-sound-card * * @dbg_stats: Debugging statistics * * @soc: SoC specific data + * @dev: Pointer to >dev + * + * @fifo_watermark: The FIFO watermark setting. Notifies DMA when there are + * @fifo_watermark or fewer words in TX fifo or + * @fifo_watermark or more empty words in RX fifo. + * @dma_maxburst: Max number of words to transfer in one go. So far, + *this is always the same as fifo_watermark. * - * @fifo_watermark: the FIFO watermark setting. Notifies DMA when - * there are @fifo_watermark or fewer words in TX fifo or - * @fifo_watermark or more empty words in RX fifo. - * @dma_maxburst: max number of words to transfer in one go. So far, - * this is always the same as fifo_watermark. + * @ac97_reg_lock: Mutex lock to serialize AC97 register access operations */ struct fsl_ssi { struct regmap *regs; @@ -243,20 +249,15 @@ struct fsl_ssi { struct clk *baudclk; unsigned int baudclk_streams; - /* regcache for volatile regs */ u32 regcache_sfcsr; u32 regcache_sacnt; - /* DMA params */ struct snd_dmaengine_dai_dma_data dma_params_tx; struct snd_dmaengine_dai_dma_data dma_params_rx; dma_addr_t ssi_phys; - /* params for non-dma FIQ stream filtered mode */ struct imx_pcm_fiq_params fiq_params; - /* Used when using fsl-ssi as sound-card. This is only used by ppc and -* should be replaced with simple-sound-card. */ struct platform_device *pdev; struct fsl_ssi_dbg dbg_stats; @@ -271,19 +272,19 @@ struct fsl_ssi { }; /* - * imx51
[PATCH v2 03/11] ASoC: fsl_ssi: Refine all comments
This patch refines the comments by: 1) Removing all out-of-date comments 2) Removing all not-so-useful comments 3) Unifying the styles of all comments 4) Simplifying over-descriptive comments 5) Adding comments to improve code readablity 6) Moving all register related comments to fsl_ssi.h 7) Adding comments to all register and field defines Signed-off-by: Nicolin Chen --- Changelog v1->v2 * Added some new comments at "SoC specific data" to be more precise. * Revised one comment in fsl_ssi_config(). * Revised the comment of fsl_ssi_setup_reg_vals(). * Added one comment for AC97 in fsl_ssi_setup_reg_vals(). * Revised the comment of fsl_ssi_hw_params() to be more precise. * Added some comments in _fsl_ssi_set_dai_fmt() to help understand the formats. * Added one comment in fsl_ssi_set_dai_fmt() to state why AC97 needs to bypass it. * Revised comments in fsl_ssi_set_dai_tdm_slot() to be more precise. * Revised comments around dual FIFO code in fsl_ssi_imx_probe() to be more precise. sound/soc/fsl/fsl_ssi.c | 376 ++-- sound/soc/fsl/fsl_ssi.h | 67 +++- sound/soc/fsl/fsl_ssi_dbg.c | 12 +- 3 files changed, 188 insertions(+), 267 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index e903c92..796a7ea 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -187,42 +187,48 @@ struct fsl_ssi_soc_data { /** * fsl_ssi: per-SSI private data * - * @reg: Pointer to the regmap registers + * @regs: Pointer to the regmap registers * @irq: IRQ of this SSI * @cpu_dai_drv: CPU DAI driver for this device * * @dai_fmt: DAI configuration this device is currently used with - * @i2s_mode: i2s and network mode configuration of the device. Is used to - * switch between normal and i2s/network mode - * mode depending on the number of channels + * @i2s_mode: I2S and Network mode configuration of SCR register * @use_dma: DMA is used or FIQ with stream filter - * @use_dual_fifo: DMA with support for both FIFOs used - * @fifo_deph: Depth of the SSI FIFOs - * @slot_width: width of each DAI slot - * @slots: number of slots - * @rxtx_reg_val: Specific register settings for receive/transmit configuration + * @use_dual_fifo: DMA with support for dual FIFO mode + * @has_ipg_clk_name: If "ipg" is in the clock name list of device tree + * @fifo_depth: Depth of the SSI FIFOs + * @slot_width: Width of each DAI slot + * @slots: Number of slots + * @rxtx_reg_val: Specific RX/TX register settings * - * @clk: SSI clock - * @baudclk: SSI baud clock for master mode + * @clk: Clock source to access register + * @baudclk: Clock source to generate bit and frame-sync clocks * @baudclk_streams: Active streams that are using baudclk * + * @regcache_sfcsr: Cache sfcsr register value during suspend and resume + * @regcache_sacnt: Cache sacnt register value during suspend and resume + * * @dma_params_tx: DMA transmit parameters * @dma_params_rx: DMA receive parameters * @ssi_phys: physical address of the SSI registers * * @fiq_params: FIQ stream filtering parameters * - * @pdev: Pointer to pdev used for deprecated fsl-ssi sound card + * @pdev: Pointer to pdev when using fsl-ssi as sound card (ppc only) + *TODO: Should be replaced with simple-sound-card * * @dbg_stats: Debugging statistics * * @soc: SoC specific data + * @dev: Pointer to >dev + * + * @fifo_watermark: The FIFO watermark setting. Notifies DMA when there are + * @fifo_watermark or fewer words in TX fifo or + * @fifo_watermark or more empty words in RX fifo. + * @dma_maxburst: Max number of words to transfer in one go. So far, + *this is always the same as fifo_watermark. * - * @fifo_watermark: the FIFO watermark setting. Notifies DMA when - * there are @fifo_watermark or fewer words in TX fifo or - * @fifo_watermark or more empty words in RX fifo. - * @dma_maxburst: max number of words to transfer in one go. So far, - * this is always the same as fifo_watermark. + * @ac97_reg_lock: Mutex lock to serialize AC97 register access operations */ struct fsl_ssi { struct regmap *regs; @@ -243,20 +249,15 @@ struct fsl_ssi { struct clk *baudclk; unsigned int baudclk_streams; - /* regcache for volatile regs */ u32 regcache_sfcsr; u32 regcache_sacnt; - /* DMA params */ struct snd_dmaengine_dai_dma_data dma_params_tx; struct snd_dmaengine_dai_dma_data dma_params_rx; dma_addr_t ssi_phys; - /* params for non-dma FIQ stream filtered mode */ struct imx_pcm_fiq_params fiq_params; - /* Used when using fsl-ssi as sound-card. This is only used by ppc and -* should be replaced with simple-sound-card. */ struct platform_device *pdev; struct fsl_ssi_dbg dbg_stats; @@ -271,19 +272,19 @@ struct fsl_ssi { }; /* - * imx51 and later SoCs have a
[PATCH v2 10/11] ASoC: fsl_ssi: Rename i2smode to i2s_net
Since this i2smode also includes the setting of Network mode, it should have it in the name. This patch also adds its MASK define. Signed-off-by: Nicolin Chen--- sound/soc/fsl/fsl_ssi.c | 24 sound/soc/fsl/fsl_ssi.h | 1 + 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 7a8a768..dd091eb 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -201,7 +201,7 @@ struct fsl_ssi_soc_data { * @cpu_dai_drv: CPU DAI driver for this device * * @dai_fmt: DAI configuration this device is currently used with - * @i2s_mode: I2S and Network mode configuration of SCR register + * @i2s_net: I2S and Network mode configurations of SCR register * @use_dma: DMA is used or FIQ with stream filter * @use_dual_fifo: DMA with support for dual FIFO mode * @has_ipg_clk_name: If "ipg" is in the clock name list of device tree @@ -245,7 +245,7 @@ struct fsl_ssi { struct snd_soc_dai_driver cpu_dai_drv; unsigned int dai_fmt; - u8 i2s_mode; + u8 i2s_net; bool use_dma; bool use_dual_fifo; bool has_ipg_clk_name; @@ -816,16 +816,16 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, } if (!fsl_ssi_is_ac97(ssi)) { - u8 i2smode; + u8 i2s_net; /* Normal + Network mode to send 16-bit data in 32-bit frames */ if (fsl_ssi_is_i2s_cbm_cfs(ssi) && sample_size == 16) - i2smode = SSI_SCR_I2S_MODE_NORMAL | SSI_SCR_NET; + i2s_net = SSI_SCR_I2S_MODE_NORMAL | SSI_SCR_NET; else - i2smode = ssi->i2s_mode; + i2s_net = ssi->i2s_net; regmap_update_bits(regs, REG_SSI_SCR, - SSI_SCR_NET | SSI_SCR_I2S_MODE_MASK, - channels == 1 ? 0 : i2smode); + SSI_SCR_I2S_NET_MASK, + channels == 1 ? 0 : i2s_net); } /* In synchronous mode, the SSI uses STCCR for capture */ @@ -882,7 +882,7 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev, srcr &= ~mask; /* Use Network mode as default */ - ssi->i2s_mode = SSI_SCR_NET; + ssi->i2s_net = SSI_SCR_NET; switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: regmap_update_bits(regs, REG_SSI_STCCR, @@ -892,10 +892,10 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev, switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBM_CFS: case SND_SOC_DAIFMT_CBS_CFS: - ssi->i2s_mode |= SSI_SCR_I2S_MODE_MASTER; + ssi->i2s_net |= SSI_SCR_I2S_MODE_MASTER; break; case SND_SOC_DAIFMT_CBM_CFM: - ssi->i2s_mode |= SSI_SCR_I2S_MODE_SLAVE; + ssi->i2s_net |= SSI_SCR_I2S_MODE_SLAVE; break; default: return -EINVAL; @@ -920,12 +920,12 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev, break; case SND_SOC_DAIFMT_AC97: /* Data on falling edge of bclk, frame high, 1clk before data */ - ssi->i2s_mode |= SSI_SCR_I2S_MODE_NORMAL; + ssi->i2s_net |= SSI_SCR_I2S_MODE_NORMAL; break; default: return -EINVAL; } - scr |= ssi->i2s_mode; + scr |= ssi->i2s_net; /* DAI clock inversion */ switch (fmt & SND_SOC_DAIFMT_INV_MASK) { diff --git a/sound/soc/fsl/fsl_ssi.h b/sound/soc/fsl/fsl_ssi.h index 52b88f1..b610087 100644 --- a/sound/soc/fsl/fsl_ssi.h +++ b/sound/soc/fsl/fsl_ssi.h @@ -95,6 +95,7 @@ #define SSI_SCR_I2S_MODE_SLAVE 0x0040 #define SSI_SCR_SYN0x0010 #define SSI_SCR_NET0x0008 +#define SSI_SCR_I2S_NET_MASK (SSI_SCR_NET | SSI_SCR_I2S_MODE_MASK) #define SSI_SCR_RE 0x0004 #define SSI_SCR_TE 0x0002 #define SSI_SCR_SSIEN 0x0001 -- 2.7.4
[PATCH v2 04/11] ASoC: fsl_ssi: Rename registers and fields macros
This patch renames CCSR_SSI_xxx to REG_SSI_xxx and SSI_xxx_yyy style. It also slightly reduces the length of them to save some space. Signed-off-by: Nicolin Chen--- sound/soc/fsl/fsl_ssi.c | 374 +-- sound/soc/fsl/fsl_ssi.h | 376 ++-- sound/soc/fsl/fsl_ssi_dbg.c | 44 +++--- 3 files changed, 397 insertions(+), 397 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 796a7ea..8b5407d 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -78,12 +78,12 @@ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE) #endif -#define FSLSSI_SIER_DBG_RX_FLAGS (CCSR_SSI_SIER_RFF0_EN | \ - CCSR_SSI_SIER_RLS_EN | CCSR_SSI_SIER_RFS_EN | \ - CCSR_SSI_SIER_ROE0_EN | CCSR_SSI_SIER_RFRC_EN) -#define FSLSSI_SIER_DBG_TX_FLAGS (CCSR_SSI_SIER_TFE0_EN | \ - CCSR_SSI_SIER_TLS_EN | CCSR_SSI_SIER_TFS_EN | \ - CCSR_SSI_SIER_TUE0_EN | CCSR_SSI_SIER_TFRC_EN) +#define FSLSSI_SIER_DBG_RX_FLAGS (SSI_SIER_RFF0_EN | \ + SSI_SIER_RLS_EN | SSI_SIER_RFS_EN | \ + SSI_SIER_ROE0_EN | SSI_SIER_RFRC_EN) +#define FSLSSI_SIER_DBG_TX_FLAGS (SSI_SIER_TFE0_EN | \ + SSI_SIER_TLS_EN | SSI_SIER_TFS_EN | \ + SSI_SIER_TUE0_EN | SSI_SIER_TFRC_EN) enum fsl_ssi_type { FSL_SSI_MCP8610, @@ -107,8 +107,8 @@ struct fsl_ssi_rxtx_reg_val { static bool fsl_ssi_readable_reg(struct device *dev, unsigned int reg) { switch (reg) { - case CCSR_SSI_SACCEN: - case CCSR_SSI_SACCDIS: + case REG_SSI_SACCEN: + case REG_SSI_SACCDIS: return false; default: return true; @@ -118,18 +118,18 @@ static bool fsl_ssi_readable_reg(struct device *dev, unsigned int reg) static bool fsl_ssi_volatile_reg(struct device *dev, unsigned int reg) { switch (reg) { - case CCSR_SSI_STX0: - case CCSR_SSI_STX1: - case CCSR_SSI_SRX0: - case CCSR_SSI_SRX1: - case CCSR_SSI_SISR: - case CCSR_SSI_SFCSR: - case CCSR_SSI_SACNT: - case CCSR_SSI_SACADD: - case CCSR_SSI_SACDAT: - case CCSR_SSI_SATAG: - case CCSR_SSI_SACCST: - case CCSR_SSI_SOR: + case REG_SSI_STX0: + case REG_SSI_STX1: + case REG_SSI_SRX0: + case REG_SSI_SRX1: + case REG_SSI_SISR: + case REG_SSI_SFCSR: + case REG_SSI_SACNT: + case REG_SSI_SACADD: + case REG_SSI_SACDAT: + case REG_SSI_SATAG: + case REG_SSI_SACCST: + case REG_SSI_SOR: return true; default: return false; @@ -139,12 +139,12 @@ static bool fsl_ssi_volatile_reg(struct device *dev, unsigned int reg) static bool fsl_ssi_precious_reg(struct device *dev, unsigned int reg) { switch (reg) { - case CCSR_SSI_SRX0: - case CCSR_SSI_SRX1: - case CCSR_SSI_SISR: - case CCSR_SSI_SACADD: - case CCSR_SSI_SACDAT: - case CCSR_SSI_SATAG: + case REG_SSI_SRX0: + case REG_SSI_SRX1: + case REG_SSI_SISR: + case REG_SSI_SACADD: + case REG_SSI_SACDAT: + case REG_SSI_SATAG: return true; default: return false; @@ -154,9 +154,9 @@ static bool fsl_ssi_precious_reg(struct device *dev, unsigned int reg) static bool fsl_ssi_writeable_reg(struct device *dev, unsigned int reg) { switch (reg) { - case CCSR_SSI_SRX0: - case CCSR_SSI_SRX1: - case CCSR_SSI_SACCST: + case REG_SSI_SRX0: + case REG_SSI_SRX1: + case REG_SSI_SACCST: return false; default: return true; @@ -164,12 +164,12 @@ static bool fsl_ssi_writeable_reg(struct device *dev, unsigned int reg) } static const struct regmap_config fsl_ssi_regconfig = { - .max_register = CCSR_SSI_SACCDIS, + .max_register = REG_SSI_SACCDIS, .reg_bits = 32, .val_bits = 32, .reg_stride = 4, .val_format_endian = REGMAP_ENDIAN_NATIVE, - .num_reg_defaults_raw = CCSR_SSI_SACCDIS / sizeof(uint32_t) + 1, + .num_reg_defaults_raw = REG_SSI_SACCDIS / sizeof(uint32_t) + 1, .readable_reg = fsl_ssi_readable_reg, .volatile_reg = fsl_ssi_volatile_reg, .precious_reg = fsl_ssi_precious_reg, @@ -290,9 +290,9 @@ struct fsl_ssi { static struct fsl_ssi_soc_data fsl_ssi_mpc8610 = { .imx = false, .offline_config = true, - .sisr_write_mask = CCSR_SSI_SISR_RFRC | CCSR_SSI_SISR_TFRC | - CCSR_SSI_SISR_ROE0 | CCSR_SSI_SISR_ROE1 | - CCSR_SSI_SISR_TUE0 | CCSR_SSI_SISR_TUE1, + .sisr_write_mask = SSI_SISR_RFRC | SSI_SISR_TFRC | + SSI_SISR_ROE0 | SSI_SISR_ROE1 | + SSI_SISR_TUE0 | SSI_SISR_TUE1, }; static struct fsl_ssi_soc_data fsl_ssi_imx21 = { @@
[PATCH v2 10/11] ASoC: fsl_ssi: Rename i2smode to i2s_net
Since this i2smode also includes the setting of Network mode, it should have it in the name. This patch also adds its MASK define. Signed-off-by: Nicolin Chen --- sound/soc/fsl/fsl_ssi.c | 24 sound/soc/fsl/fsl_ssi.h | 1 + 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 7a8a768..dd091eb 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -201,7 +201,7 @@ struct fsl_ssi_soc_data { * @cpu_dai_drv: CPU DAI driver for this device * * @dai_fmt: DAI configuration this device is currently used with - * @i2s_mode: I2S and Network mode configuration of SCR register + * @i2s_net: I2S and Network mode configurations of SCR register * @use_dma: DMA is used or FIQ with stream filter * @use_dual_fifo: DMA with support for dual FIFO mode * @has_ipg_clk_name: If "ipg" is in the clock name list of device tree @@ -245,7 +245,7 @@ struct fsl_ssi { struct snd_soc_dai_driver cpu_dai_drv; unsigned int dai_fmt; - u8 i2s_mode; + u8 i2s_net; bool use_dma; bool use_dual_fifo; bool has_ipg_clk_name; @@ -816,16 +816,16 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, } if (!fsl_ssi_is_ac97(ssi)) { - u8 i2smode; + u8 i2s_net; /* Normal + Network mode to send 16-bit data in 32-bit frames */ if (fsl_ssi_is_i2s_cbm_cfs(ssi) && sample_size == 16) - i2smode = SSI_SCR_I2S_MODE_NORMAL | SSI_SCR_NET; + i2s_net = SSI_SCR_I2S_MODE_NORMAL | SSI_SCR_NET; else - i2smode = ssi->i2s_mode; + i2s_net = ssi->i2s_net; regmap_update_bits(regs, REG_SSI_SCR, - SSI_SCR_NET | SSI_SCR_I2S_MODE_MASK, - channels == 1 ? 0 : i2smode); + SSI_SCR_I2S_NET_MASK, + channels == 1 ? 0 : i2s_net); } /* In synchronous mode, the SSI uses STCCR for capture */ @@ -882,7 +882,7 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev, srcr &= ~mask; /* Use Network mode as default */ - ssi->i2s_mode = SSI_SCR_NET; + ssi->i2s_net = SSI_SCR_NET; switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: regmap_update_bits(regs, REG_SSI_STCCR, @@ -892,10 +892,10 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev, switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBM_CFS: case SND_SOC_DAIFMT_CBS_CFS: - ssi->i2s_mode |= SSI_SCR_I2S_MODE_MASTER; + ssi->i2s_net |= SSI_SCR_I2S_MODE_MASTER; break; case SND_SOC_DAIFMT_CBM_CFM: - ssi->i2s_mode |= SSI_SCR_I2S_MODE_SLAVE; + ssi->i2s_net |= SSI_SCR_I2S_MODE_SLAVE; break; default: return -EINVAL; @@ -920,12 +920,12 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev, break; case SND_SOC_DAIFMT_AC97: /* Data on falling edge of bclk, frame high, 1clk before data */ - ssi->i2s_mode |= SSI_SCR_I2S_MODE_NORMAL; + ssi->i2s_net |= SSI_SCR_I2S_MODE_NORMAL; break; default: return -EINVAL; } - scr |= ssi->i2s_mode; + scr |= ssi->i2s_net; /* DAI clock inversion */ switch (fmt & SND_SOC_DAIFMT_INV_MASK) { diff --git a/sound/soc/fsl/fsl_ssi.h b/sound/soc/fsl/fsl_ssi.h index 52b88f1..b610087 100644 --- a/sound/soc/fsl/fsl_ssi.h +++ b/sound/soc/fsl/fsl_ssi.h @@ -95,6 +95,7 @@ #define SSI_SCR_I2S_MODE_SLAVE 0x0040 #define SSI_SCR_SYN0x0010 #define SSI_SCR_NET0x0008 +#define SSI_SCR_I2S_NET_MASK (SSI_SCR_NET | SSI_SCR_I2S_MODE_MASK) #define SSI_SCR_RE 0x0004 #define SSI_SCR_TE 0x0002 #define SSI_SCR_SSIEN 0x0001 -- 2.7.4
[PATCH v2 04/11] ASoC: fsl_ssi: Rename registers and fields macros
This patch renames CCSR_SSI_xxx to REG_SSI_xxx and SSI_xxx_yyy style. It also slightly reduces the length of them to save some space. Signed-off-by: Nicolin Chen --- sound/soc/fsl/fsl_ssi.c | 374 +-- sound/soc/fsl/fsl_ssi.h | 376 ++-- sound/soc/fsl/fsl_ssi_dbg.c | 44 +++--- 3 files changed, 397 insertions(+), 397 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 796a7ea..8b5407d 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -78,12 +78,12 @@ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE) #endif -#define FSLSSI_SIER_DBG_RX_FLAGS (CCSR_SSI_SIER_RFF0_EN | \ - CCSR_SSI_SIER_RLS_EN | CCSR_SSI_SIER_RFS_EN | \ - CCSR_SSI_SIER_ROE0_EN | CCSR_SSI_SIER_RFRC_EN) -#define FSLSSI_SIER_DBG_TX_FLAGS (CCSR_SSI_SIER_TFE0_EN | \ - CCSR_SSI_SIER_TLS_EN | CCSR_SSI_SIER_TFS_EN | \ - CCSR_SSI_SIER_TUE0_EN | CCSR_SSI_SIER_TFRC_EN) +#define FSLSSI_SIER_DBG_RX_FLAGS (SSI_SIER_RFF0_EN | \ + SSI_SIER_RLS_EN | SSI_SIER_RFS_EN | \ + SSI_SIER_ROE0_EN | SSI_SIER_RFRC_EN) +#define FSLSSI_SIER_DBG_TX_FLAGS (SSI_SIER_TFE0_EN | \ + SSI_SIER_TLS_EN | SSI_SIER_TFS_EN | \ + SSI_SIER_TUE0_EN | SSI_SIER_TFRC_EN) enum fsl_ssi_type { FSL_SSI_MCP8610, @@ -107,8 +107,8 @@ struct fsl_ssi_rxtx_reg_val { static bool fsl_ssi_readable_reg(struct device *dev, unsigned int reg) { switch (reg) { - case CCSR_SSI_SACCEN: - case CCSR_SSI_SACCDIS: + case REG_SSI_SACCEN: + case REG_SSI_SACCDIS: return false; default: return true; @@ -118,18 +118,18 @@ static bool fsl_ssi_readable_reg(struct device *dev, unsigned int reg) static bool fsl_ssi_volatile_reg(struct device *dev, unsigned int reg) { switch (reg) { - case CCSR_SSI_STX0: - case CCSR_SSI_STX1: - case CCSR_SSI_SRX0: - case CCSR_SSI_SRX1: - case CCSR_SSI_SISR: - case CCSR_SSI_SFCSR: - case CCSR_SSI_SACNT: - case CCSR_SSI_SACADD: - case CCSR_SSI_SACDAT: - case CCSR_SSI_SATAG: - case CCSR_SSI_SACCST: - case CCSR_SSI_SOR: + case REG_SSI_STX0: + case REG_SSI_STX1: + case REG_SSI_SRX0: + case REG_SSI_SRX1: + case REG_SSI_SISR: + case REG_SSI_SFCSR: + case REG_SSI_SACNT: + case REG_SSI_SACADD: + case REG_SSI_SACDAT: + case REG_SSI_SATAG: + case REG_SSI_SACCST: + case REG_SSI_SOR: return true; default: return false; @@ -139,12 +139,12 @@ static bool fsl_ssi_volatile_reg(struct device *dev, unsigned int reg) static bool fsl_ssi_precious_reg(struct device *dev, unsigned int reg) { switch (reg) { - case CCSR_SSI_SRX0: - case CCSR_SSI_SRX1: - case CCSR_SSI_SISR: - case CCSR_SSI_SACADD: - case CCSR_SSI_SACDAT: - case CCSR_SSI_SATAG: + case REG_SSI_SRX0: + case REG_SSI_SRX1: + case REG_SSI_SISR: + case REG_SSI_SACADD: + case REG_SSI_SACDAT: + case REG_SSI_SATAG: return true; default: return false; @@ -154,9 +154,9 @@ static bool fsl_ssi_precious_reg(struct device *dev, unsigned int reg) static bool fsl_ssi_writeable_reg(struct device *dev, unsigned int reg) { switch (reg) { - case CCSR_SSI_SRX0: - case CCSR_SSI_SRX1: - case CCSR_SSI_SACCST: + case REG_SSI_SRX0: + case REG_SSI_SRX1: + case REG_SSI_SACCST: return false; default: return true; @@ -164,12 +164,12 @@ static bool fsl_ssi_writeable_reg(struct device *dev, unsigned int reg) } static const struct regmap_config fsl_ssi_regconfig = { - .max_register = CCSR_SSI_SACCDIS, + .max_register = REG_SSI_SACCDIS, .reg_bits = 32, .val_bits = 32, .reg_stride = 4, .val_format_endian = REGMAP_ENDIAN_NATIVE, - .num_reg_defaults_raw = CCSR_SSI_SACCDIS / sizeof(uint32_t) + 1, + .num_reg_defaults_raw = REG_SSI_SACCDIS / sizeof(uint32_t) + 1, .readable_reg = fsl_ssi_readable_reg, .volatile_reg = fsl_ssi_volatile_reg, .precious_reg = fsl_ssi_precious_reg, @@ -290,9 +290,9 @@ struct fsl_ssi { static struct fsl_ssi_soc_data fsl_ssi_mpc8610 = { .imx = false, .offline_config = true, - .sisr_write_mask = CCSR_SSI_SISR_RFRC | CCSR_SSI_SISR_TFRC | - CCSR_SSI_SISR_ROE0 | CCSR_SSI_SISR_ROE1 | - CCSR_SSI_SISR_TUE0 | CCSR_SSI_SISR_TUE1, + .sisr_write_mask = SSI_SISR_RFRC | SSI_SISR_TFRC | + SSI_SISR_ROE0 | SSI_SISR_ROE1 | + SSI_SISR_TUE0 | SSI_SISR_TUE1, }; static struct fsl_ssi_soc_data fsl_ssi_imx21 = { @@ -305,16 +305,16 @@ static
[PATCH v2 00/11] ASoC: fsl_ssi: Clean up - coding style level
==Changelog== v1->v2 * Dropped one patch to remove "struct device" * Revised PATCH-03 "Refine all comments" * Revised PATCH-05 "Refine indentations and wrappings" * Rebased all other patches * Added PATCH-10 "Rename i2smode to i2s_net" * Added PATCH-11 "Define ternary macros to simplify code" # Detialed changes are described in each updated patch. ==Background== The fsl_ssi driver was designed for PPC originally and then it has been updated to support different modes for i.MX Series, including SDMA, I2S Master mode, AC97 and older i.MXs with FIQ, by different contributors for different use cases in different coding styles. Additionally, in order to fix/work-around hardware bugs and design flaws, the driver made a lot of compromise so now its program flow looks very complicated and it's getting hard to maintain or update. So I am going to clean up the driver on both coding style level and program flow level. ==Introduction== This series of patches is the first set to clean up fsl_ssi driver in the coding style level. Any patch here is not supposed to change the program flow. ==Verification== Theoretically, since these patches do not change program flow, they only need code review, build or sanity tests. I have done build and sanity tests on an i.MX6SoloX with WM8962 using imx_v6_v7_defconfig and playback/record tests in I2S Master/Slave modes. Nicolin Chen (11): ASoC: fsl_ssi: Rename fsl_ssi_private to fsl_ssi ASoC: fsl_ssi: Cache pdev->dev pointer ASoC: fsl_ssi: Refine all comments ASoC: fsl_ssi: Rename registers and fields macros ASoC: fsl_ssi: Refine indentations and wrappings ASoC: fsl_ssi: Refine printk outputs ASoC: fsl_ssi: Rename cpu_dai parameter to dai ASoC: fsl_ssi: Rename scr_val to scr ASoC: fsl_ssi: Replace fsl_ssi_rxtx_reg_val with fsl_ssi_regvals ASoC: fsl_ssi: Rename i2smode to i2s_net ASoC: fsl_ssi: Define ternary macros to simplify code sound/soc/fsl/fsl_ssi.c | 1373 +++ sound/soc/fsl/fsl_ssi.h | 427 -- sound/soc/fsl/fsl_ssi_dbg.c | 59 +- 3 files changed, 876 insertions(+), 983 deletions(-) -- 2.7.4
[PATCH v2 00/11] ASoC: fsl_ssi: Clean up - coding style level
==Changelog== v1->v2 * Dropped one patch to remove "struct device" * Revised PATCH-03 "Refine all comments" * Revised PATCH-05 "Refine indentations and wrappings" * Rebased all other patches * Added PATCH-10 "Rename i2smode to i2s_net" * Added PATCH-11 "Define ternary macros to simplify code" # Detialed changes are described in each updated patch. ==Background== The fsl_ssi driver was designed for PPC originally and then it has been updated to support different modes for i.MX Series, including SDMA, I2S Master mode, AC97 and older i.MXs with FIQ, by different contributors for different use cases in different coding styles. Additionally, in order to fix/work-around hardware bugs and design flaws, the driver made a lot of compromise so now its program flow looks very complicated and it's getting hard to maintain or update. So I am going to clean up the driver on both coding style level and program flow level. ==Introduction== This series of patches is the first set to clean up fsl_ssi driver in the coding style level. Any patch here is not supposed to change the program flow. ==Verification== Theoretically, since these patches do not change program flow, they only need code review, build or sanity tests. I have done build and sanity tests on an i.MX6SoloX with WM8962 using imx_v6_v7_defconfig and playback/record tests in I2S Master/Slave modes. Nicolin Chen (11): ASoC: fsl_ssi: Rename fsl_ssi_private to fsl_ssi ASoC: fsl_ssi: Cache pdev->dev pointer ASoC: fsl_ssi: Refine all comments ASoC: fsl_ssi: Rename registers and fields macros ASoC: fsl_ssi: Refine indentations and wrappings ASoC: fsl_ssi: Refine printk outputs ASoC: fsl_ssi: Rename cpu_dai parameter to dai ASoC: fsl_ssi: Rename scr_val to scr ASoC: fsl_ssi: Replace fsl_ssi_rxtx_reg_val with fsl_ssi_regvals ASoC: fsl_ssi: Rename i2smode to i2s_net ASoC: fsl_ssi: Define ternary macros to simplify code sound/soc/fsl/fsl_ssi.c | 1373 +++ sound/soc/fsl/fsl_ssi.h | 427 -- sound/soc/fsl/fsl_ssi_dbg.c | 59 +- 3 files changed, 876 insertions(+), 983 deletions(-) -- 2.7.4
[PATCH 4/5] phy: renesas: rcar-gen3-usb2: add rcar_gen3_role_swap_ops
This patch add rcar_gen3_role_swap_ops to support other feature (e.g. gpio handling) easily. Signed-off-by: Yoshihiro Shimoda--- drivers/phy/renesas/phy-rcar-gen3-usb2.c | 51 +++- 1 file changed, 43 insertions(+), 8 deletions(-) diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c index 6d6f3eb..5e509a9 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c @@ -83,11 +83,23 @@ #define RCAR_GEN3_PHY_HAS_DEDICATED_PINS 1 +struct rcar_gen3_chan; +struct rcar_gen3_role_swap_ops { + void (*init)(struct rcar_gen3_chan *ch); + void (*set_host)(struct rcar_gen3_chan *ch, int host); + bool (*is_host)(struct rcar_gen3_chan *ch); + void (*enable_vbus)(struct rcar_gen3_chan *ch, int vbus); + bool (*check_id)(struct rcar_gen3_chan *ch); + void (*enable_irq)(struct rcar_gen3_chan *ch, int enable); + irqreturn_t (*irq_handler)(struct rcar_gen3_chan *ch); +}; + struct rcar_gen3_chan { void __iomem *base; struct extcon_dev *extcon; struct phy *phy; struct regulator *vbus; + const struct rcar_gen3_role_swap_ops *rs_ops; struct work_struct work; bool extcon_host; bool has_otg_pins; @@ -203,17 +215,20 @@ static void rcar_gen3_phy_usb2_work(struct work_struct *work) static void rcar_gen3_set_host_mode(struct rcar_gen3_chan *ch, int host) { - has_otg_pins_set_host(ch, host); + if (ch->rs_ops && ch->rs_ops->set_host) + ch->rs_ops->set_host(ch, host); } static void rcar_gen3_enable_vbus_ctrl(struct rcar_gen3_chan *ch, int vbus) { - has_otg_pins_enable_vbus(ch, vbus); + if (ch->rs_ops && ch->rs_ops->enable_vbus) + ch->rs_ops->enable_vbus(ch, vbus); } static void rcar_gen3_enable_otg_irq(struct rcar_gen3_chan *ch, int enable) { - has_otg_pins_enable_irq(ch, enable); + if (ch->rs_ops && ch->rs_ops->enable_irq) + ch->rs_ops->enable_irq(ch, enable); } static void rcar_gen3_init_for_host(struct rcar_gen3_chan *ch) @@ -271,7 +286,10 @@ static void rcar_gen3_init_from_a_peri_to_a_host(struct rcar_gen3_chan *ch) static bool rcar_gen3_check_id(struct rcar_gen3_chan *ch) { - return has_otg_pins_check_id(ch); + if (ch->rs_ops && ch->rs_ops->check_id) + return ch->rs_ops->check_id(ch); + + return false; } static void rcar_gen3_device_recognition(struct rcar_gen3_chan *ch) @@ -284,7 +302,10 @@ static void rcar_gen3_device_recognition(struct rcar_gen3_chan *ch) static bool rcar_gen3_is_host(struct rcar_gen3_chan *ch) { - return has_otg_pins_is_host(ch); + if (ch->rs_ops && ch->rs_ops->is_host) + return ch->rs_ops->is_host(ch); + + return false; } static enum phy_mode rcar_gen3_get_phy_mode(struct rcar_gen3_chan *ch) @@ -350,7 +371,8 @@ static ssize_t role_show(struct device *dev, struct device_attribute *attr, static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch) { - has_otg_pins_init(ch); + if (ch->rs_ops && ch->rs_ops->init) + ch->rs_ops->init(ch); rcar_gen3_device_recognition(ch); } @@ -425,9 +447,10 @@ static int rcar_gen3_phy_usb2_power_off(struct phy *p) static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch) { struct rcar_gen3_chan *ch = _ch; - irqreturn_t ret; + irqreturn_t ret = IRQ_NONE; - ret = has_otg_pins_irq_handler(ch); + if (ch->rs_ops && ch->rs_ops->irq_handler) + ret = ch->rs_ops->irq_handler(ch); if (ret == IRQ_HANDLED) rcar_gen3_device_recognition(ch); @@ -456,6 +479,16 @@ static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch) EXTCON_NONE, }; +static const struct rcar_gen3_role_swap_ops has_otg_pins_ops = { + .init = has_otg_pins_init, + .set_host = has_otg_pins_set_host, + .is_host= has_otg_pins_is_host, + .enable_vbus= has_otg_pins_enable_vbus, + .check_id = has_otg_pins_check_id, + .enable_irq = has_otg_pins_enable_irq, + .irq_handler= has_otg_pins_irq_handler, +}; + static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) { struct device *dev = >dev; @@ -493,6 +526,8 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) int ret; channel->has_otg_pins = (uintptr_t)of_device_get_match_data(dev); + if (channel->has_otg_pins) + channel->rs_ops = _otg_pins_ops; channel->extcon = devm_extcon_dev_allocate(dev, rcar_gen3_phy_cable); if (IS_ERR(channel->extcon)) -- 1.9.1
[PATCH 4/5] phy: renesas: rcar-gen3-usb2: add rcar_gen3_role_swap_ops
This patch add rcar_gen3_role_swap_ops to support other feature (e.g. gpio handling) easily. Signed-off-by: Yoshihiro Shimoda --- drivers/phy/renesas/phy-rcar-gen3-usb2.c | 51 +++- 1 file changed, 43 insertions(+), 8 deletions(-) diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c index 6d6f3eb..5e509a9 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c @@ -83,11 +83,23 @@ #define RCAR_GEN3_PHY_HAS_DEDICATED_PINS 1 +struct rcar_gen3_chan; +struct rcar_gen3_role_swap_ops { + void (*init)(struct rcar_gen3_chan *ch); + void (*set_host)(struct rcar_gen3_chan *ch, int host); + bool (*is_host)(struct rcar_gen3_chan *ch); + void (*enable_vbus)(struct rcar_gen3_chan *ch, int vbus); + bool (*check_id)(struct rcar_gen3_chan *ch); + void (*enable_irq)(struct rcar_gen3_chan *ch, int enable); + irqreturn_t (*irq_handler)(struct rcar_gen3_chan *ch); +}; + struct rcar_gen3_chan { void __iomem *base; struct extcon_dev *extcon; struct phy *phy; struct regulator *vbus; + const struct rcar_gen3_role_swap_ops *rs_ops; struct work_struct work; bool extcon_host; bool has_otg_pins; @@ -203,17 +215,20 @@ static void rcar_gen3_phy_usb2_work(struct work_struct *work) static void rcar_gen3_set_host_mode(struct rcar_gen3_chan *ch, int host) { - has_otg_pins_set_host(ch, host); + if (ch->rs_ops && ch->rs_ops->set_host) + ch->rs_ops->set_host(ch, host); } static void rcar_gen3_enable_vbus_ctrl(struct rcar_gen3_chan *ch, int vbus) { - has_otg_pins_enable_vbus(ch, vbus); + if (ch->rs_ops && ch->rs_ops->enable_vbus) + ch->rs_ops->enable_vbus(ch, vbus); } static void rcar_gen3_enable_otg_irq(struct rcar_gen3_chan *ch, int enable) { - has_otg_pins_enable_irq(ch, enable); + if (ch->rs_ops && ch->rs_ops->enable_irq) + ch->rs_ops->enable_irq(ch, enable); } static void rcar_gen3_init_for_host(struct rcar_gen3_chan *ch) @@ -271,7 +286,10 @@ static void rcar_gen3_init_from_a_peri_to_a_host(struct rcar_gen3_chan *ch) static bool rcar_gen3_check_id(struct rcar_gen3_chan *ch) { - return has_otg_pins_check_id(ch); + if (ch->rs_ops && ch->rs_ops->check_id) + return ch->rs_ops->check_id(ch); + + return false; } static void rcar_gen3_device_recognition(struct rcar_gen3_chan *ch) @@ -284,7 +302,10 @@ static void rcar_gen3_device_recognition(struct rcar_gen3_chan *ch) static bool rcar_gen3_is_host(struct rcar_gen3_chan *ch) { - return has_otg_pins_is_host(ch); + if (ch->rs_ops && ch->rs_ops->is_host) + return ch->rs_ops->is_host(ch); + + return false; } static enum phy_mode rcar_gen3_get_phy_mode(struct rcar_gen3_chan *ch) @@ -350,7 +371,8 @@ static ssize_t role_show(struct device *dev, struct device_attribute *attr, static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch) { - has_otg_pins_init(ch); + if (ch->rs_ops && ch->rs_ops->init) + ch->rs_ops->init(ch); rcar_gen3_device_recognition(ch); } @@ -425,9 +447,10 @@ static int rcar_gen3_phy_usb2_power_off(struct phy *p) static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch) { struct rcar_gen3_chan *ch = _ch; - irqreturn_t ret; + irqreturn_t ret = IRQ_NONE; - ret = has_otg_pins_irq_handler(ch); + if (ch->rs_ops && ch->rs_ops->irq_handler) + ret = ch->rs_ops->irq_handler(ch); if (ret == IRQ_HANDLED) rcar_gen3_device_recognition(ch); @@ -456,6 +479,16 @@ static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch) EXTCON_NONE, }; +static const struct rcar_gen3_role_swap_ops has_otg_pins_ops = { + .init = has_otg_pins_init, + .set_host = has_otg_pins_set_host, + .is_host= has_otg_pins_is_host, + .enable_vbus= has_otg_pins_enable_vbus, + .check_id = has_otg_pins_check_id, + .enable_irq = has_otg_pins_enable_irq, + .irq_handler= has_otg_pins_irq_handler, +}; + static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) { struct device *dev = >dev; @@ -493,6 +526,8 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) int ret; channel->has_otg_pins = (uintptr_t)of_device_get_match_data(dev); + if (channel->has_otg_pins) + channel->rs_ops = _otg_pins_ops; channel->extcon = devm_extcon_dev_allocate(dev, rcar_gen3_phy_cable); if (IS_ERR(channel->extcon)) -- 1.9.1
[PATCH 0/5] phy: renesas: rcar-gen3-usb2: add gpio handling for R-Car D3
This patch set is based on the latest linux-phy / next branch (commit id = 4fbd8d194f06c8a3fd2af1ce560ddb31f7ec8323). This new feature will be used by the renesas_usbhs driver on R-Car D3. Yoshihiro Shimoda (5): phy: renesas: rcar-gen3-usb2: call INIT_WORK() anyway phy: renesas: rcar-gen3-usb2: unify OBINTEN handling phy: renesas: rcar-gen3-usb2: use prefix "has_otg_pins_" for dedicated pins handling phy: renesas: rcar-gen3-usb2: add rcar_gen3_role_swap_ops phy: renesas: rcar-gen3-usb2: add gpio handlings .../devicetree/bindings/phy/rcar-gen3-phy-usb2.txt | 2 + drivers/phy/renesas/phy-rcar-gen3-usb2.c | 262 - 2 files changed, 206 insertions(+), 58 deletions(-) -- 1.9.1
[PATCH 0/5] phy: renesas: rcar-gen3-usb2: add gpio handling for R-Car D3
This patch set is based on the latest linux-phy / next branch (commit id = 4fbd8d194f06c8a3fd2af1ce560ddb31f7ec8323). This new feature will be used by the renesas_usbhs driver on R-Car D3. Yoshihiro Shimoda (5): phy: renesas: rcar-gen3-usb2: call INIT_WORK() anyway phy: renesas: rcar-gen3-usb2: unify OBINTEN handling phy: renesas: rcar-gen3-usb2: use prefix "has_otg_pins_" for dedicated pins handling phy: renesas: rcar-gen3-usb2: add rcar_gen3_role_swap_ops phy: renesas: rcar-gen3-usb2: add gpio handlings .../devicetree/bindings/phy/rcar-gen3-phy-usb2.txt | 2 + drivers/phy/renesas/phy-rcar-gen3-usb2.c | 262 - 2 files changed, 206 insertions(+), 58 deletions(-) -- 1.9.1
[PATCH 2/5] phy: renesas: rcar-gen3-usb2: unify OBINTEN handling
This patch unifies the OBINTEN handling to clean-up the code. Signed-off-by: Yoshihiro Shimoda--- drivers/phy/renesas/phy-rcar-gen3-usb2.c | 23 +++ 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c index c22d65a..beeaa30 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c @@ -147,6 +147,18 @@ static void rcar_gen3_enable_vbus_ctrl(struct rcar_gen3_chan *ch, int vbus) writel(val, usb2_base + USB2_ADPCTRL); } +static void rcar_gen3_enable_otg_irq(struct rcar_gen3_chan *ch, int enable) +{ + void __iomem *usb2_base = ch->base; + u32 val = readl(usb2_base + USB2_OBINTEN); + + if (enable) + val |= USB2_OBINT_BITS; + else + val &= ~USB2_OBINT_BITS; + writel(val, usb2_base + USB2_OBINTEN); +} + static void rcar_gen3_init_for_host(struct rcar_gen3_chan *ch) { rcar_gen3_set_linectrl(ch, 1, 1); @@ -192,16 +204,12 @@ static void rcar_gen3_init_for_a_peri(struct rcar_gen3_chan *ch) static void rcar_gen3_init_from_a_peri_to_a_host(struct rcar_gen3_chan *ch) { - void __iomem *usb2_base = ch->base; - u32 val; - - val = readl(usb2_base + USB2_OBINTEN); - writel(val & ~USB2_OBINT_BITS, usb2_base + USB2_OBINTEN); + rcar_gen3_enable_otg_irq(ch, 0); rcar_gen3_enable_vbus_ctrl(ch, 0); rcar_gen3_init_for_host(ch); - writel(val | USB2_OBINT_BITS, usb2_base + USB2_OBINTEN); + rcar_gen3_enable_otg_irq(ch, 1); } static bool rcar_gen3_check_id(struct rcar_gen3_chan *ch) @@ -291,8 +299,7 @@ static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch) val = readl(usb2_base + USB2_VBCTRL); writel(val | USB2_VBCTRL_DRVVBUSSEL, usb2_base + USB2_VBCTRL); writel(USB2_OBINT_BITS, usb2_base + USB2_OBINTSTA); - val = readl(usb2_base + USB2_OBINTEN); - writel(val | USB2_OBINT_BITS, usb2_base + USB2_OBINTEN); + rcar_gen3_enable_otg_irq(ch, 1); val = readl(usb2_base + USB2_ADPCTRL); writel(val | USB2_ADPCTRL_IDPULLUP, usb2_base + USB2_ADPCTRL); val = readl(usb2_base + USB2_LINECTRL1); -- 1.9.1
[PATCH 2/5] phy: renesas: rcar-gen3-usb2: unify OBINTEN handling
This patch unifies the OBINTEN handling to clean-up the code. Signed-off-by: Yoshihiro Shimoda --- drivers/phy/renesas/phy-rcar-gen3-usb2.c | 23 +++ 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c index c22d65a..beeaa30 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c @@ -147,6 +147,18 @@ static void rcar_gen3_enable_vbus_ctrl(struct rcar_gen3_chan *ch, int vbus) writel(val, usb2_base + USB2_ADPCTRL); } +static void rcar_gen3_enable_otg_irq(struct rcar_gen3_chan *ch, int enable) +{ + void __iomem *usb2_base = ch->base; + u32 val = readl(usb2_base + USB2_OBINTEN); + + if (enable) + val |= USB2_OBINT_BITS; + else + val &= ~USB2_OBINT_BITS; + writel(val, usb2_base + USB2_OBINTEN); +} + static void rcar_gen3_init_for_host(struct rcar_gen3_chan *ch) { rcar_gen3_set_linectrl(ch, 1, 1); @@ -192,16 +204,12 @@ static void rcar_gen3_init_for_a_peri(struct rcar_gen3_chan *ch) static void rcar_gen3_init_from_a_peri_to_a_host(struct rcar_gen3_chan *ch) { - void __iomem *usb2_base = ch->base; - u32 val; - - val = readl(usb2_base + USB2_OBINTEN); - writel(val & ~USB2_OBINT_BITS, usb2_base + USB2_OBINTEN); + rcar_gen3_enable_otg_irq(ch, 0); rcar_gen3_enable_vbus_ctrl(ch, 0); rcar_gen3_init_for_host(ch); - writel(val | USB2_OBINT_BITS, usb2_base + USB2_OBINTEN); + rcar_gen3_enable_otg_irq(ch, 1); } static bool rcar_gen3_check_id(struct rcar_gen3_chan *ch) @@ -291,8 +299,7 @@ static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch) val = readl(usb2_base + USB2_VBCTRL); writel(val | USB2_VBCTRL_DRVVBUSSEL, usb2_base + USB2_VBCTRL); writel(USB2_OBINT_BITS, usb2_base + USB2_OBINTSTA); - val = readl(usb2_base + USB2_OBINTEN); - writel(val | USB2_OBINT_BITS, usb2_base + USB2_OBINTEN); + rcar_gen3_enable_otg_irq(ch, 1); val = readl(usb2_base + USB2_ADPCTRL); writel(val | USB2_ADPCTRL_IDPULLUP, usb2_base + USB2_ADPCTRL); val = readl(usb2_base + USB2_LINECTRL1); -- 1.9.1
[PATCH 5/5] phy: renesas: rcar-gen3-usb2: add gpio handling
Some R-Car SoCs (e.g. R-Car D3) doesn't have dedicated pins of VBUS and ID. So, they may be connected to gpio pins. To handle the gpio pins, this patch adds the handling of VBUS and ID pins instead of dedicated pins. Signed-off-by: Yoshihiro Shimoda--- .../devicetree/bindings/phy/rcar-gen3-phy-usb2.txt | 2 + drivers/phy/renesas/phy-rcar-gen3-usb2.c | 77 -- 2 files changed, 72 insertions(+), 7 deletions(-) diff --git a/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt b/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt index 99b651b..851582f 100644 --- a/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt +++ b/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt @@ -27,6 +27,8 @@ channel as USB OTG: - interrupts: interrupt specifier for the PHY. - vbus-supply: Phandle to a regulator that provides power to the VBUS. This regulator will be managed during the PHY power on/off sequence. +- renesas,vbus-gpios: use gpio to control vbus instead of dedicated pin. +- renesas,id-gpios: use gpio to detect id instead of dedicated pin. Example (R-Car H3): diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c index 5e509a9..0b6333d 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c @@ -13,6 +13,7 @@ */ #include +#include #include #include #include @@ -100,9 +101,12 @@ struct rcar_gen3_chan { struct phy *phy; struct regulator *vbus; const struct rcar_gen3_role_swap_ops *rs_ops; + struct gpio_desc *gpio_vbus; + struct gpio_desc *gpio_id; struct work_struct work; bool extcon_host; bool has_otg_pins; + bool has_gpio; }; static void rcar_gen3_set_linectrl(struct rcar_gen3_chan *ch, int dp, int dm) @@ -199,6 +203,36 @@ static void has_otg_pins_init(struct rcar_gen3_chan *ch) usb2_base + USB2_LINECTRL1); } +static void gpio_enable_vbus(struct rcar_gen3_chan *ch, int vbus) +{ + gpiod_set_value(ch->gpio_vbus, vbus); +} + +static bool gpio_check_id(struct rcar_gen3_chan *ch) +{ + return gpiod_get_value(ch->gpio_id); +} + +static void gpio_set_host(struct rcar_gen3_chan *ch, int host) +{ + /* In gpio ops, this driver will modify the extcon_host by sysfs */ + if (ch->extcon_host != !!host) { + ch->extcon_host = !!host; + schedule_work(>work); + } +} + +static bool gpio_is_host(struct rcar_gen3_chan *ch) +{ + return ch->extcon_host; +} + +static irqreturn_t gpio_irq_handler(struct rcar_gen3_chan *ch) +{ + /* Nop because the driver will get gpio value after exited */ + return IRQ_HANDLED; +} + static void rcar_gen3_phy_usb2_work(struct work_struct *work) { struct rcar_gen3_chan *ch = container_of(work, struct rcar_gen3_chan, @@ -323,7 +357,7 @@ static ssize_t role_store(struct device *dev, struct device_attribute *attr, bool is_b_device; enum phy_mode cur_mode, new_mode; - if (!ch->has_otg_pins || !ch->phy->init_count) + if (!(ch->has_otg_pins || ch->has_gpio) || !ch->phy->init_count) return -EIO; if (!strncmp(buf, "host", strlen("host"))) @@ -361,7 +395,7 @@ static ssize_t role_show(struct device *dev, struct device_attribute *attr, { struct rcar_gen3_chan *ch = dev_get_drvdata(dev); - if (!ch->has_otg_pins || !ch->phy->init_count) + if (!(ch->has_otg_pins || ch->has_gpio) || !ch->phy->init_count) return -EIO; return sprintf(buf, "%s\n", rcar_gen3_is_host(ch) ? "host" : @@ -388,7 +422,7 @@ static int rcar_gen3_phy_usb2_init(struct phy *p) writel(USB2_OC_TIMSET_INIT, usb2_base + USB2_OC_TIMSET); /* Initialize otg part */ - if (channel->has_otg_pins) + if (channel->has_otg_pins || channel->has_gpio) rcar_gen3_init_otg(channel); return 0; @@ -489,6 +523,14 @@ static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch) .irq_handler= has_otg_pins_irq_handler, }; +static const struct rcar_gen3_role_swap_ops gpio_ops = { + .set_host = gpio_set_host, + .is_host= gpio_is_host, + .enable_vbus= gpio_enable_vbus, + .check_id = gpio_check_id, + .irq_handler= gpio_irq_handler, +}; + static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) { struct device *dev = >dev; @@ -513,9 +555,30 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) INIT_WORK(>work, rcar_gen3_phy_usb2_work); - /* call request_irq for OTG */ + channel->gpio_vbus = devm_gpiod_get(dev, "renesas,vbus", GPIOD_OUT_LOW); + if (IS_ERR(channel->gpio_vbus) && + PTR_ERR(channel->gpio_vbus) == -EPROBE_DEFER) + return PTR_ERR(channel->gpio_vbus); + +
[PATCH 5/5] phy: renesas: rcar-gen3-usb2: add gpio handling
Some R-Car SoCs (e.g. R-Car D3) doesn't have dedicated pins of VBUS and ID. So, they may be connected to gpio pins. To handle the gpio pins, this patch adds the handling of VBUS and ID pins instead of dedicated pins. Signed-off-by: Yoshihiro Shimoda --- .../devicetree/bindings/phy/rcar-gen3-phy-usb2.txt | 2 + drivers/phy/renesas/phy-rcar-gen3-usb2.c | 77 -- 2 files changed, 72 insertions(+), 7 deletions(-) diff --git a/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt b/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt index 99b651b..851582f 100644 --- a/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt +++ b/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt @@ -27,6 +27,8 @@ channel as USB OTG: - interrupts: interrupt specifier for the PHY. - vbus-supply: Phandle to a regulator that provides power to the VBUS. This regulator will be managed during the PHY power on/off sequence. +- renesas,vbus-gpios: use gpio to control vbus instead of dedicated pin. +- renesas,id-gpios: use gpio to detect id instead of dedicated pin. Example (R-Car H3): diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c index 5e509a9..0b6333d 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c @@ -13,6 +13,7 @@ */ #include +#include #include #include #include @@ -100,9 +101,12 @@ struct rcar_gen3_chan { struct phy *phy; struct regulator *vbus; const struct rcar_gen3_role_swap_ops *rs_ops; + struct gpio_desc *gpio_vbus; + struct gpio_desc *gpio_id; struct work_struct work; bool extcon_host; bool has_otg_pins; + bool has_gpio; }; static void rcar_gen3_set_linectrl(struct rcar_gen3_chan *ch, int dp, int dm) @@ -199,6 +203,36 @@ static void has_otg_pins_init(struct rcar_gen3_chan *ch) usb2_base + USB2_LINECTRL1); } +static void gpio_enable_vbus(struct rcar_gen3_chan *ch, int vbus) +{ + gpiod_set_value(ch->gpio_vbus, vbus); +} + +static bool gpio_check_id(struct rcar_gen3_chan *ch) +{ + return gpiod_get_value(ch->gpio_id); +} + +static void gpio_set_host(struct rcar_gen3_chan *ch, int host) +{ + /* In gpio ops, this driver will modify the extcon_host by sysfs */ + if (ch->extcon_host != !!host) { + ch->extcon_host = !!host; + schedule_work(>work); + } +} + +static bool gpio_is_host(struct rcar_gen3_chan *ch) +{ + return ch->extcon_host; +} + +static irqreturn_t gpio_irq_handler(struct rcar_gen3_chan *ch) +{ + /* Nop because the driver will get gpio value after exited */ + return IRQ_HANDLED; +} + static void rcar_gen3_phy_usb2_work(struct work_struct *work) { struct rcar_gen3_chan *ch = container_of(work, struct rcar_gen3_chan, @@ -323,7 +357,7 @@ static ssize_t role_store(struct device *dev, struct device_attribute *attr, bool is_b_device; enum phy_mode cur_mode, new_mode; - if (!ch->has_otg_pins || !ch->phy->init_count) + if (!(ch->has_otg_pins || ch->has_gpio) || !ch->phy->init_count) return -EIO; if (!strncmp(buf, "host", strlen("host"))) @@ -361,7 +395,7 @@ static ssize_t role_show(struct device *dev, struct device_attribute *attr, { struct rcar_gen3_chan *ch = dev_get_drvdata(dev); - if (!ch->has_otg_pins || !ch->phy->init_count) + if (!(ch->has_otg_pins || ch->has_gpio) || !ch->phy->init_count) return -EIO; return sprintf(buf, "%s\n", rcar_gen3_is_host(ch) ? "host" : @@ -388,7 +422,7 @@ static int rcar_gen3_phy_usb2_init(struct phy *p) writel(USB2_OC_TIMSET_INIT, usb2_base + USB2_OC_TIMSET); /* Initialize otg part */ - if (channel->has_otg_pins) + if (channel->has_otg_pins || channel->has_gpio) rcar_gen3_init_otg(channel); return 0; @@ -489,6 +523,14 @@ static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch) .irq_handler= has_otg_pins_irq_handler, }; +static const struct rcar_gen3_role_swap_ops gpio_ops = { + .set_host = gpio_set_host, + .is_host= gpio_is_host, + .enable_vbus= gpio_enable_vbus, + .check_id = gpio_check_id, + .irq_handler= gpio_irq_handler, +}; + static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) { struct device *dev = >dev; @@ -513,9 +555,30 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) INIT_WORK(>work, rcar_gen3_phy_usb2_work); - /* call request_irq for OTG */ + channel->gpio_vbus = devm_gpiod_get(dev, "renesas,vbus", GPIOD_OUT_LOW); + if (IS_ERR(channel->gpio_vbus) && + PTR_ERR(channel->gpio_vbus) == -EPROBE_DEFER) + return PTR_ERR(channel->gpio_vbus); + + channel->gpio_id =
[PATCH 1/5] phy: renesas: rcar-gen3-usb2: call INIT_WORK() anyway
In the future, the work struct will be used by non-irq related code. So, this patch moves the INIT_WORK() timing. Signed-off-by: Yoshihiro Shimoda--- drivers/phy/renesas/phy-rcar-gen3-usb2.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c index 9c90e7d..c22d65a 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c @@ -431,10 +431,11 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) if (IS_ERR(channel->base)) return PTR_ERR(channel->base); + INIT_WORK(>work, rcar_gen3_phy_usb2_work); + /* call request_irq for OTG */ irq = platform_get_irq(pdev, 0); if (irq >= 0) { - INIT_WORK(>work, rcar_gen3_phy_usb2_work); irq = devm_request_irq(dev, irq, rcar_gen3_phy_usb2_irq, IRQF_SHARED, dev_name(dev), channel); if (irq < 0) -- 1.9.1
[PATCH 3/5] phy: renesas: rcar-gen3-usb2: use prefix "has_otg_pins_" for dedicated pins handling
To support gpio handling in the future, this patch clean-ups the code to use prefix "has_otg_pins_" functions. Signed-off-by: Yoshihiro Shimoda--- drivers/phy/renesas/phy-rcar-gen3-usb2.c | 130 --- 1 file changed, 85 insertions(+), 45 deletions(-) diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c index beeaa30..6d6f3eb 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c @@ -93,21 +93,21 @@ struct rcar_gen3_chan { bool has_otg_pins; }; -static void rcar_gen3_phy_usb2_work(struct work_struct *work) +static void rcar_gen3_set_linectrl(struct rcar_gen3_chan *ch, int dp, int dm) { - struct rcar_gen3_chan *ch = container_of(work, struct rcar_gen3_chan, -work); + void __iomem *usb2_base = ch->base; + u32 val = readl(usb2_base + USB2_LINECTRL1); - if (ch->extcon_host) { - extcon_set_state_sync(ch->extcon, EXTCON_USB_HOST, true); - extcon_set_state_sync(ch->extcon, EXTCON_USB, false); - } else { - extcon_set_state_sync(ch->extcon, EXTCON_USB_HOST, false); - extcon_set_state_sync(ch->extcon, EXTCON_USB, true); - } + dev_vdbg(>phy->dev, "%s: %08x, %d, %d\n", __func__, val, dp, dm); + val &= ~(USB2_LINECTRL1_DP_RPD | USB2_LINECTRL1_DM_RPD); + if (dp) + val |= USB2_LINECTRL1_DP_RPD; + if (dm) + val |= USB2_LINECTRL1_DM_RPD; + writel(val, usb2_base + USB2_LINECTRL1); } -static void rcar_gen3_set_host_mode(struct rcar_gen3_chan *ch, int host) +static void has_otg_pins_set_host(struct rcar_gen3_chan *ch, int host) { void __iomem *usb2_base = ch->base; u32 val = readl(usb2_base + USB2_COMMCTRL); @@ -120,21 +120,27 @@ static void rcar_gen3_set_host_mode(struct rcar_gen3_chan *ch, int host) writel(val, usb2_base + USB2_COMMCTRL); } -static void rcar_gen3_set_linectrl(struct rcar_gen3_chan *ch, int dp, int dm) +static bool has_otg_pins_is_host(struct rcar_gen3_chan *ch) +{ + return !(readl(ch->base + USB2_COMMCTRL) & USB2_COMMCTRL_OTG_PERI); +} + +static irqreturn_t has_otg_pins_irq_handler(struct rcar_gen3_chan *ch) { void __iomem *usb2_base = ch->base; - u32 val = readl(usb2_base + USB2_LINECTRL1); + u32 status = readl(usb2_base + USB2_OBINTSTA); + irqreturn_t ret = IRQ_NONE; - dev_vdbg(>phy->dev, "%s: %08x, %d, %d\n", __func__, val, dp, dm); - val &= ~(USB2_LINECTRL1_DP_RPD | USB2_LINECTRL1_DM_RPD); - if (dp) - val |= USB2_LINECTRL1_DP_RPD; - if (dm) - val |= USB2_LINECTRL1_DM_RPD; - writel(val, usb2_base + USB2_LINECTRL1); + if (status & USB2_OBINT_BITS) { + dev_vdbg(>phy->dev, "%s: %08x\n", __func__, status); + writel(USB2_OBINT_BITS, usb2_base + USB2_OBINTSTA); + ret = IRQ_HANDLED; + } + + return ret; } -static void rcar_gen3_enable_vbus_ctrl(struct rcar_gen3_chan *ch, int vbus) +static void has_otg_pins_enable_vbus(struct rcar_gen3_chan *ch, int vbus) { void __iomem *usb2_base = ch->base; u32 val = readl(usb2_base + USB2_ADPCTRL); @@ -147,7 +153,7 @@ static void rcar_gen3_enable_vbus_ctrl(struct rcar_gen3_chan *ch, int vbus) writel(val, usb2_base + USB2_ADPCTRL); } -static void rcar_gen3_enable_otg_irq(struct rcar_gen3_chan *ch, int enable) +static void has_otg_pins_enable_irq(struct rcar_gen3_chan *ch, int enable) { void __iomem *usb2_base = ch->base; u32 val = readl(usb2_base + USB2_OBINTEN); @@ -159,6 +165,57 @@ static void rcar_gen3_enable_otg_irq(struct rcar_gen3_chan *ch, int enable) writel(val, usb2_base + USB2_OBINTEN); } +static bool has_otg_pins_check_id(struct rcar_gen3_chan *ch) +{ + return !!(readl(ch->base + USB2_ADPCTRL) & USB2_ADPCTRL_IDDIG); +} + +static void has_otg_pins_init(struct rcar_gen3_chan *ch) +{ + void __iomem *usb2_base = ch->base; + u32 val; + + val = readl(usb2_base + USB2_VBCTRL); + writel(val | USB2_VBCTRL_DRVVBUSSEL, usb2_base + USB2_VBCTRL); + writel(USB2_OBINT_BITS, usb2_base + USB2_OBINTSTA); + has_otg_pins_enable_irq(ch, 1); + val = readl(usb2_base + USB2_ADPCTRL); + writel(val | USB2_ADPCTRL_IDPULLUP, usb2_base + USB2_ADPCTRL); + val = readl(usb2_base + USB2_LINECTRL1); + rcar_gen3_set_linectrl(ch, 0, 0); + writel(val | USB2_LINECTRL1_DPRPD_EN | USB2_LINECTRL1_DMRPD_EN, + usb2_base + USB2_LINECTRL1); +} + +static void rcar_gen3_phy_usb2_work(struct work_struct *work) +{ + struct rcar_gen3_chan *ch = container_of(work, struct rcar_gen3_chan, +work); + + if (ch->extcon_host) { + extcon_set_state_sync(ch->extcon,
[PATCH 1/5] phy: renesas: rcar-gen3-usb2: call INIT_WORK() anyway
In the future, the work struct will be used by non-irq related code. So, this patch moves the INIT_WORK() timing. Signed-off-by: Yoshihiro Shimoda --- drivers/phy/renesas/phy-rcar-gen3-usb2.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c index 9c90e7d..c22d65a 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c @@ -431,10 +431,11 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) if (IS_ERR(channel->base)) return PTR_ERR(channel->base); + INIT_WORK(>work, rcar_gen3_phy_usb2_work); + /* call request_irq for OTG */ irq = platform_get_irq(pdev, 0); if (irq >= 0) { - INIT_WORK(>work, rcar_gen3_phy_usb2_work); irq = devm_request_irq(dev, irq, rcar_gen3_phy_usb2_irq, IRQF_SHARED, dev_name(dev), channel); if (irq < 0) -- 1.9.1
[PATCH 3/5] phy: renesas: rcar-gen3-usb2: use prefix "has_otg_pins_" for dedicated pins handling
To support gpio handling in the future, this patch clean-ups the code to use prefix "has_otg_pins_" functions. Signed-off-by: Yoshihiro Shimoda --- drivers/phy/renesas/phy-rcar-gen3-usb2.c | 130 --- 1 file changed, 85 insertions(+), 45 deletions(-) diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c index beeaa30..6d6f3eb 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c @@ -93,21 +93,21 @@ struct rcar_gen3_chan { bool has_otg_pins; }; -static void rcar_gen3_phy_usb2_work(struct work_struct *work) +static void rcar_gen3_set_linectrl(struct rcar_gen3_chan *ch, int dp, int dm) { - struct rcar_gen3_chan *ch = container_of(work, struct rcar_gen3_chan, -work); + void __iomem *usb2_base = ch->base; + u32 val = readl(usb2_base + USB2_LINECTRL1); - if (ch->extcon_host) { - extcon_set_state_sync(ch->extcon, EXTCON_USB_HOST, true); - extcon_set_state_sync(ch->extcon, EXTCON_USB, false); - } else { - extcon_set_state_sync(ch->extcon, EXTCON_USB_HOST, false); - extcon_set_state_sync(ch->extcon, EXTCON_USB, true); - } + dev_vdbg(>phy->dev, "%s: %08x, %d, %d\n", __func__, val, dp, dm); + val &= ~(USB2_LINECTRL1_DP_RPD | USB2_LINECTRL1_DM_RPD); + if (dp) + val |= USB2_LINECTRL1_DP_RPD; + if (dm) + val |= USB2_LINECTRL1_DM_RPD; + writel(val, usb2_base + USB2_LINECTRL1); } -static void rcar_gen3_set_host_mode(struct rcar_gen3_chan *ch, int host) +static void has_otg_pins_set_host(struct rcar_gen3_chan *ch, int host) { void __iomem *usb2_base = ch->base; u32 val = readl(usb2_base + USB2_COMMCTRL); @@ -120,21 +120,27 @@ static void rcar_gen3_set_host_mode(struct rcar_gen3_chan *ch, int host) writel(val, usb2_base + USB2_COMMCTRL); } -static void rcar_gen3_set_linectrl(struct rcar_gen3_chan *ch, int dp, int dm) +static bool has_otg_pins_is_host(struct rcar_gen3_chan *ch) +{ + return !(readl(ch->base + USB2_COMMCTRL) & USB2_COMMCTRL_OTG_PERI); +} + +static irqreturn_t has_otg_pins_irq_handler(struct rcar_gen3_chan *ch) { void __iomem *usb2_base = ch->base; - u32 val = readl(usb2_base + USB2_LINECTRL1); + u32 status = readl(usb2_base + USB2_OBINTSTA); + irqreturn_t ret = IRQ_NONE; - dev_vdbg(>phy->dev, "%s: %08x, %d, %d\n", __func__, val, dp, dm); - val &= ~(USB2_LINECTRL1_DP_RPD | USB2_LINECTRL1_DM_RPD); - if (dp) - val |= USB2_LINECTRL1_DP_RPD; - if (dm) - val |= USB2_LINECTRL1_DM_RPD; - writel(val, usb2_base + USB2_LINECTRL1); + if (status & USB2_OBINT_BITS) { + dev_vdbg(>phy->dev, "%s: %08x\n", __func__, status); + writel(USB2_OBINT_BITS, usb2_base + USB2_OBINTSTA); + ret = IRQ_HANDLED; + } + + return ret; } -static void rcar_gen3_enable_vbus_ctrl(struct rcar_gen3_chan *ch, int vbus) +static void has_otg_pins_enable_vbus(struct rcar_gen3_chan *ch, int vbus) { void __iomem *usb2_base = ch->base; u32 val = readl(usb2_base + USB2_ADPCTRL); @@ -147,7 +153,7 @@ static void rcar_gen3_enable_vbus_ctrl(struct rcar_gen3_chan *ch, int vbus) writel(val, usb2_base + USB2_ADPCTRL); } -static void rcar_gen3_enable_otg_irq(struct rcar_gen3_chan *ch, int enable) +static void has_otg_pins_enable_irq(struct rcar_gen3_chan *ch, int enable) { void __iomem *usb2_base = ch->base; u32 val = readl(usb2_base + USB2_OBINTEN); @@ -159,6 +165,57 @@ static void rcar_gen3_enable_otg_irq(struct rcar_gen3_chan *ch, int enable) writel(val, usb2_base + USB2_OBINTEN); } +static bool has_otg_pins_check_id(struct rcar_gen3_chan *ch) +{ + return !!(readl(ch->base + USB2_ADPCTRL) & USB2_ADPCTRL_IDDIG); +} + +static void has_otg_pins_init(struct rcar_gen3_chan *ch) +{ + void __iomem *usb2_base = ch->base; + u32 val; + + val = readl(usb2_base + USB2_VBCTRL); + writel(val | USB2_VBCTRL_DRVVBUSSEL, usb2_base + USB2_VBCTRL); + writel(USB2_OBINT_BITS, usb2_base + USB2_OBINTSTA); + has_otg_pins_enable_irq(ch, 1); + val = readl(usb2_base + USB2_ADPCTRL); + writel(val | USB2_ADPCTRL_IDPULLUP, usb2_base + USB2_ADPCTRL); + val = readl(usb2_base + USB2_LINECTRL1); + rcar_gen3_set_linectrl(ch, 0, 0); + writel(val | USB2_LINECTRL1_DPRPD_EN | USB2_LINECTRL1_DMRPD_EN, + usb2_base + USB2_LINECTRL1); +} + +static void rcar_gen3_phy_usb2_work(struct work_struct *work) +{ + struct rcar_gen3_chan *ch = container_of(work, struct rcar_gen3_chan, +work); + + if (ch->extcon_host) { + extcon_set_state_sync(ch->extcon, EXTCON_USB_HOST, true); +