Skip to contentSkip to conversation

spi: spi-geni-qcom: Add SPI driver support for GENI based QUP

PATCH In review Dilip Kota 6 participants 15 messages Aug 24, 2018 – Sep 10, 2018

Subsystems (4)
lore
Share & tools
lore

Dilip Kota

author
#0 lore raw

PATCH v3 1/1 spi: spi-geni-qcom: Add SPI driver support for GENI based QUP

From: Girish Mahadevan <[email protected]>

This driver supports GENI based SPI Controller in the Qualcomm SOCs. The Qualcomm Generic Interface (GENI) is a programmable module supporting a wide range of serial interfaces including SPI. This driver supports SPI operations using FIFO mode of transfer.

---
Addressing all the reviewer commets given in Patchset1. Summerizing all the comments below:

MAKEFILE: Arrange SPI-GENI driver in alphabetical order
Kconfig: Mark SPI_GENI driver dependent on QCOM_GENI_SE
Enable SPI core auto runtime pm, and remove runtime pm calls.
Remove spi_geni_unprepare_message(), spi_geni_unprepare_transfer_hardware()
Remove likely/unlikely keywords.
Remove get_spi_master() and use dev_get_drvdata()
Move request_irq to probe()
Mark bus number assignment to -1 as SPI core framework will assign dynamically
Use devm_spi_register_master()
Include platform_device.h instead of of_platform.h
Removing macros which are used only once:
#define SPI_NUM_CHIPSELECT 4
#define SPI_XFER_TIMEOUT_MS 250
Place Register field definitions next to respective Register definitions.
Replace int and u32 declerations to unsigned int.
Remove Hex numbers in debug prints.
Declare mode as u16 in spi_setup_word_len()
Remove the labels: setup_fifo_params_exit: exit_prepare_transfer_hardware:
Declaring struct spi_master as spi everywhere in the file.
Calling spi_finalize_current_transfer() for end of transfer.
Hard code the SPI controller max frequency instead of reading from DTSI node.
Spinlock not required, removed it.
Removed unrequired error prints.
Fix KASAN error in geni_spi_isr().
Remove spi-geni-qcom.h
Remove inter words delay and CS to Clock toggle delay logic in the driver, as of now no clients are using it. Will submit this logic in the next patchset.
Use major, minor and step macros to read from hardware version register.

 .../devicetree/bindings/soc/qcom/qcom,geni-se.txt  |   2 -
 drivers/spi/Kconfig                                |  12 +
 drivers/spi/Makefile                               |   1 +
 drivers/spi/spi-geni-qcom.c                        | 678 +++++++++++++++++++++
 4 files changed, 691 insertions(+), 2 deletions(-)
 create mode 100644 drivers/spi/spi-geni-qcom.c
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +0 -2
index 68b7d62..16467ed 100644
@@ -60,7 +60,6 @@ Required properties:
 - interrupts:		Must contain SPI controller interrupts.
 - clock-names:		Must contain "se".
 - clocks:		Serial engine core clock needed by the device.
-- spi-max-frequency:	Specifies maximum SPI clock frequency, units - Hz.
 - #address-cells:	Must be <1> to define a chip select address on
 			the SPI bus.
 - #size-cells:		Must be <0>.
@@ -112,7 +111,6 @@ Example:
 			pinctrl-names = "default", "sleep";
 			pinctrl-0 = <&qup_1_spi_2_active>;
 			pinctrl-1 = <&qup_1_spi_2_sleep>;
-			spi-max-frequency = <19200000>;
 			#address-cells = <1>;
 			#size-cells = <0>;
 		};
drivers/spi/Kconfig +12 -0
index ad5d68e..4f7f86f 100644
@@ -533,6 +533,18 @@ config SPI_QUP
 	  This driver can also be built as a module.  If so, the module
 	  will be called spi_qup.
 
+config SPI_QCOM_GENI
+	tristate "Qualcomm SPI controller with QUP interface"
+	depends on QCOM_GENI_SE
+	help
+	  This driver supports GENI serial engine based SPI controller in
+	  master mode on the Qualcomm Technologies Inc.'s SoCs. If you say
+	  yes to this option, support will be included for the SPI interface
+	  on the Qualcomm Technologies Inc.'s SoCs.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called spi-geni-qcom.
+
 config SPI_S3C24XX
 	tristate "Samsung S3C24XX series SPI"
 	depends on ARCH_S3C24XX
drivers/spi/Makefile +1 -0
index cb1f437..98337cf 100644
@@ -74,6 +74,7 @@ obj-$(CONFIG_SPI_PPC4xx)		+= spi-ppc4xx.o
 spi-pxa2xx-platform-objs		:= spi-pxa2xx.o spi-pxa2xx-dma.o
 obj-$(CONFIG_SPI_PXA2XX)		+= spi-pxa2xx-platform.o
 obj-$(CONFIG_SPI_PXA2XX_PCI)		+= spi-pxa2xx-pci.o
+obj-$(CONFIG_SPI_QCOM_GENI)		+= spi-geni-qcom.o
 obj-$(CONFIG_SPI_QUP)			+= spi-qup.o
 obj-$(CONFIG_SPI_ROCKCHIP)		+= spi-rockchip.o
 obj-$(CONFIG_SPI_RB4XX)			+= spi-rb4xx.o
drivers/spi/spi-geni-qcom.c new file +678 -0

678 lines not on this page · raw message

Signature · 3 lines
Qualcomm Datacenter Technologies as an affiliate of Qualcomm Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the
Code Aurora Forum, a Linux Foundation Collaborative Project.
#1 lore raw
Thank you for the patch! Yet something to improve:

Hi Girish,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on spi/for-next]
[also build test ERROR on v4.18]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Dilip-Kota/spi-spi-geni-qcom-Add-SPI-driver-support-for-GENI-based-QUP/20180824-190528
base:   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-next
config: i386-allmodconfig
compiler: gcc-7 (Debian 7.3.0-16) 7.3.0

reproduce:
make ARCH=i386 allmodconfig
make ARCH=i386

All errors (new ones prefixed by >>):

vim +239 drivers/spi/spi-geni-qcom.c

212
213 static int spi_geni_prepare_transfer_hardware(struct spi_master *spi)
214 {
215 struct spi_geni_master *mas = spi_master_get_devdata(spi);
216 struct geni_se *se = &mas->se;
217
218 if (!mas->setup) {
219 unsigned int proto = geni_se_read_proto(se);
220 unsigned int major, minor, step, ver;
221
222 if (proto != GENI_SE_SPI) {
223 dev_err(mas->dev, "Invalid proto %d\n", proto);
224 return -ENXIO;
225 }
226 mas->tx_fifo_depth = geni_se_get_tx_fifo_depth(se);
227 mas->rx_fifo_depth = geni_se_get_rx_fifo_depth(se);
228 mas->tx_fifo_width = geni_se_get_tx_fifo_width(se);
229
230 /*
231 * Hardware programming guide suggests to configure
232 * RX FIFO RFR level to fifo_depth-2.
233 */
234 geni_se_init(se, 0x0, mas->tx_fifo_depth - 2);
235 mas->oversampling = 1;
236 /* Transmit an entire FIFO worth of data per IRQ */
237 mas->tx_wm = 1;
238 ver = geni_se_get_qup_hw_version(se);

 > 239			major = GENI_SE_VERSION_MAJOR(ver);
 > 240			minor = GENI_SE_VERSION_MINOR(ver);
 > 241			step = GENI_SE_VERSION_STEP(ver);

242
243 if (major == 1 && minor == 0)
244 mas->oversampling = 2;
245 mas->setup = 1;
246 }
247 return 0;
248 }
249

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation

#2 lore raw
In reply to Dilip Kota
Thank you for the patch! Yet something to improve:

Hi Girish,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on spi/for-next]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Dilip-Kota/spi-spi-geni-qcom-Add-SPI-driver-support-for-GENI-based-QUP/20180824-190528
base:   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-next
config: i386-allyesconfig
compiler: gcc-7 (Debian 7.3.0-16) 7.3.0

reproduce:
make ARCH=i386 allyesconfig
make ARCH=i386

All errors (new ones prefixed by >>):

vim +/GENI_SE_VERSION_MAJOR +239 drivers/spi/spi-geni-qcom.c

212
213 static int spi_geni_prepare_transfer_hardware(struct spi_master *spi)
214 {
215 struct spi_geni_master *mas = spi_master_get_devdata(spi);
216 struct geni_se *se = &mas->se;
217
218 if (!mas->setup) {
219 unsigned int proto = geni_se_read_proto(se);
220 unsigned int major, minor, step, ver;
221
222 if (proto != GENI_SE_SPI) {
223 dev_err(mas->dev, "Invalid proto %d\n", proto);
224 return -ENXIO;
225 }
226 mas->tx_fifo_depth = geni_se_get_tx_fifo_depth(se);
227 mas->rx_fifo_depth = geni_se_get_rx_fifo_depth(se);
228 mas->tx_fifo_width = geni_se_get_tx_fifo_width(se);
229
230 /*
231 * Hardware programming guide suggests to configure
232 * RX FIFO RFR level to fifo_depth-2.
233 */
234 geni_se_init(se, 0x0, mas->tx_fifo_depth - 2);
235 mas->oversampling = 1;
236 /* Transmit an entire FIFO worth of data per IRQ */
237 mas->tx_wm = 1;
238 ver = geni_se_get_qup_hw_version(se);

 > 239			major = GENI_SE_VERSION_MAJOR(ver);
 > 240			minor = GENI_SE_VERSION_MINOR(ver);
 > 241			step = GENI_SE_VERSION_STEP(ver);

242
243 if (major == 1 && minor == 0)
244 mas->oversampling = 2;
245 mas->setup = 1;
246 }
247 return 0;
248 }
249

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation

maintainer
#3 lore raw
In reply to Dilip Kota
Quoted 42 lines · Dilip Kota

From: Girish Mahadevan <[email protected]>

This driver supports GENI based SPI Controller in the Qualcomm SOCs. The Qualcomm Generic Interface (GENI) is a programmable module supporting a wide range of serial interfaces including SPI. This driver supports SPI operations using FIFO mode of transfer.

---
Addressing all the reviewer commets given in Patchset1. Summerizing all the comments below:

MAKEFILE: Arrange SPI-GENI driver in alphabetical order
Kconfig: Mark SPI_GENI driver dependent on QCOM_GENI_SE
Enable SPI core auto runtime pm, and remove runtime pm calls.
Remove spi_geni_unprepare_message(), spi_geni_unprepare_transfer_hardware()
Remove likely/unlikely keywords.
Remove get_spi_master() and use dev_get_drvdata()
Move request_irq to probe()
Mark bus number assignment to -1 as SPI core framework will assign dynamically
Use devm_spi_register_master()
Include platform_device.h instead of of_platform.h
Removing macros which are used only once:
#define SPI_NUM_CHIPSELECT 4
#define SPI_XFER_TIMEOUT_MS 250
Place Register field definitions next to respective Register definitions.
Replace int and u32 declerations to unsigned int.
Remove Hex numbers in debug prints.
Declare mode as u16 in spi_setup_word_len()
Remove the labels: setup_fifo_params_exit: exit_prepare_transfer_hardware:
Declaring struct spi_master as spi everywhere in the file.
Calling spi_finalize_current_transfer() for end of transfer.
Hard code the SPI controller max frequency instead of reading from DTSI node.
Spinlock not required, removed it.
Removed unrequired error prints.
Fix KASAN error in geni_spi_isr().
Remove spi-geni-qcom.h
Remove inter words delay and CS to Clock toggle delay logic in the driver, as of now no clients are using it. Will submit this logic in the next patchset.
Use major, minor and step macros to read from hardware version register.

Quoted 1 line
 .../devicetree/bindings/soc/qcom/qcom,geni-se.txt  |   2 -

Please split to a separate patch and explain why you are removing spi-max-frequency?

Quoted 5 lines
 drivers/spi/Kconfig                                |  12 +
 drivers/spi/Makefile                               |   1 +
 drivers/spi/spi-geni-qcom.c                        | 678 +++++++++++++++++++++
 4 files changed, 691 insertions(+), 2 deletions(-)
 create mode 100644 drivers/spi/spi-geni-qcom.c
#4 lore raw
Quoted 50 lines · Rob Herring
Quoted 49 lines · Dilip Kota

From: Girish Mahadevan <[email protected]>

This driver supports GENI based SPI Controller in the Qualcomm SOCs. The Qualcomm Generic Interface (GENI) is a programmable module supporting a wide range of serial interfaces including SPI. This driver supports SPI operations using FIFO mode of transfer.

---
Addressing all the reviewer commets given in Patchset1. Summerizing all the comments below:

MAKEFILE: Arrange SPI-GENI driver in alphabetical order
Kconfig: Mark SPI_GENI driver dependent on QCOM_GENI_SE Enable SPI core auto runtime pm, and remove runtime pm calls. Remove spi_geni_unprepare_message(),
spi_geni_unprepare_transfer_hardware()
Remove likely/unlikely keywords.
Remove get_spi_master() and use dev_get_drvdata()
Move request_irq to probe()
Mark bus number assignment to -1 as SPI core framework will assign
dynamically
Use devm_spi_register_master()
Include platform_device.h instead of of_platform.h Removing macros which are used only once:
#define SPI_NUM_CHIPSELECT 4
#define SPI_XFER_TIMEOUT_MS 250
Place Register field definitions next to respective Register
definitions.
Replace int and u32 declerations to unsigned int. Remove Hex numbers in debug prints.
Declare mode as u16 in spi_setup_word_len()
Remove the labels: setup_fifo_params_exit:
exit_prepare_transfer_hardware:
Declaring struct spi_master as spi everywhere in the file. Calling spi_finalize_current_transfer() for end of transfer. Hard code the SPI controller max frequency instead of reading from
DTSI node.
Spinlock not required, removed it.
Removed unrequired error prints.
Fix KASAN error in geni_spi_isr().
Remove spi-geni-qcom.h
Remove inter words delay and CS to Clock toggle delay logic in the
driver, as of now no clients are using it.
Will submit this logic in the next patchset.
Use major, minor and step macros to read from hardware version
register.

Quoted 4 lines
Quoted 1 line
 .../devicetree/bindings/soc/qcom/qcom,geni-se.txt  |   2 -

Please split to a separate patch and explain why you are removing spi-max-frequency?

Hi Rob Herring,

In this patch, added changes for Driver not to read the SPI controller Maximum frequency from the device tree. Accordingly I removed it in the device tree documentation file. As both the files need to updated so did in the same patch. Could you please let me know the reason for making a separate patch.

--Dilip

Quoted 7 lines
Quoted 7 lines
 drivers/spi/Kconfig                                |  12 +
 drivers/spi/Makefile                               |   1 +
 drivers/spi/spi-geni-qcom.c                        | 678 
+++++++++++++++++++++
 4 files changed, 691 insertions(+), 2 deletions(-)
 create mode 100644 drivers/spi/spi-geni-qcom.c
maintainer
#5 lore raw
Quoted 60 lines · On Wed, Aug 29, 2018 at 6:19 AM <[email protected]> wrote:
Quoted 53 lines · Rob Herring
Quoted 52 lines · Dilip Kota

From: Girish Mahadevan <[email protected]>

This driver supports GENI based SPI Controller in the Qualcomm SOCs. The
Qualcomm Generic Interface (GENI) is a programmable module supporting a
wide range of serial interfaces including SPI. This driver supports SPI
operations using FIFO mode of transfer.

---
Addressing all the reviewer commets given in Patchset1. Summerizing all the comments below:

MAKEFILE: Arrange SPI-GENI driver in alphabetical order
Kconfig: Mark SPI_GENI driver dependent on QCOM_GENI_SE Enable SPI core auto runtime pm, and remove runtime pm calls. Remove spi_geni_unprepare_message(),
spi_geni_unprepare_transfer_hardware()
Remove likely/unlikely keywords.
Remove get_spi_master() and use dev_get_drvdata()
Move request_irq to probe()
Mark bus number assignment to -1 as SPI core framework will assign
dynamically
Use devm_spi_register_master()
Include platform_device.h instead of of_platform.h Removing macros which are used only once:
#define SPI_NUM_CHIPSELECT 4
#define SPI_XFER_TIMEOUT_MS 250
Place Register field definitions next to respective Register
definitions.
Replace int and u32 declerations to unsigned int. Remove Hex numbers in debug prints.
Declare mode as u16 in spi_setup_word_len()
Remove the labels: setup_fifo_params_exit:
exit_prepare_transfer_hardware:
Declaring struct spi_master as spi everywhere in the file. Calling spi_finalize_current_transfer() for end of transfer. Hard code the SPI controller max frequency instead of reading from
DTSI node.
Spinlock not required, removed it.
Removed unrequired error prints.
Fix KASAN error in geni_spi_isr().
Remove spi-geni-qcom.h
Remove inter words delay and CS to Clock toggle delay logic in the
driver, as of now no clients are using it.
Will submit this logic in the next patchset.
Use major, minor and step macros to read from hardware version
register.

Quoted 4 lines
Quoted 1 line
 .../devicetree/bindings/soc/qcom/qcom,geni-se.txt  |   2 -

Please split to a separate patch and explain why you are removing spi-max-frequency?

Quoted 6 lines

Hi Rob Herring,

In this patch, added changes for Driver not to read the SPI controller Maximum frequency from the device tree. Accordingly I removed it in the device tree documentation file. As both the files need to updated so did in the same patch.

Just because the Linux driver doesn't use it isn't a reason. What if there is another OS driver for it? The binding is the h/w description, not what the driver uses currently.

Quoted 1 line

Could you please let me know the reason for making a separate patch.

- Step 1 of Documentation/devicetree/bindings/submitting-patches.txt says so
- I only review the binding generally, so my ack or reviewed by only applies to it.
- It makes the commit history of the DT only tree[1] more logical.

Rob

[1] https://git.kernel.org/pub/scm/linux/kernel/git/devicetree/devicetree-rebasing.git/

#6 lore raw
In reply to Dilip Kota

Quoting Dilip Kota (2018-08-24 03:42:15)

drivers/spi/spi-geni-qcom.c line 651

Quoted 5 lines
drivers/spi/spi-geni-qcom.c new file +5 -0
+
+static int __maybe_unused spi_geni_suspend(struct device *dev)
+{
+       if (!pm_runtime_status_suspended(dev))
+               return -EBUSY;

This looks odd. Why are we doing this? The i2c driver had a recent fix from Evan squashed in that removed this logic so that suspend wouldn't be called twice. Can this driver support the direct_complete PM mechanism instead? Maybe that works to make this check unnecessary and also allows us to avoid suspending subdevices and resuming on system resume? It would be good if the i2c/uart/spi drivers could all agree on how to handle this.

Quoted 9 lines
drivers/spi/spi-geni-qcom.c new file +9 -0
+       return 0;
+}
+
+static const struct dev_pm_ops spi_geni_pm_ops = {
+       SET_RUNTIME_PM_OPS(spi_geni_runtime_suspend,
+                                       spi_geni_runtime_resume, NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(spi_geni_suspend, NULL)
+};
+
#7 lore raw
In reply to Dilip Kota

Hi,

Quoted 42 lines · Dilip Kota

From: Girish Mahadevan <[email protected]>

This driver supports GENI based SPI Controller in the Qualcomm SOCs. The Qualcomm Generic Interface (GENI) is a programmable module supporting a wide range of serial interfaces including SPI. This driver supports SPI operations using FIFO mode of transfer.

---
Addressing all the reviewer commets given in Patchset1. Summerizing all the comments below:

MAKEFILE: Arrange SPI-GENI driver in alphabetical order
Kconfig: Mark SPI_GENI driver dependent on QCOM_GENI_SE
Enable SPI core auto runtime pm, and remove runtime pm calls.
Remove spi_geni_unprepare_message(), spi_geni_unprepare_transfer_hardware()
Remove likely/unlikely keywords.
Remove get_spi_master() and use dev_get_drvdata()
Move request_irq to probe()
Mark bus number assignment to -1 as SPI core framework will assign dynamically
Use devm_spi_register_master()
Include platform_device.h instead of of_platform.h
Removing macros which are used only once:
#define SPI_NUM_CHIPSELECT 4
#define SPI_XFER_TIMEOUT_MS 250
Place Register field definitions next to respective Register definitions.
Replace int and u32 declerations to unsigned int.
Remove Hex numbers in debug prints.
Declare mode as u16 in spi_setup_word_len()
Remove the labels: setup_fifo_params_exit: exit_prepare_transfer_hardware:
Declaring struct spi_master as spi everywhere in the file.
Calling spi_finalize_current_transfer() for end of transfer.
Hard code the SPI controller max frequency instead of reading from DTSI node.
Spinlock not required, removed it.
Removed unrequired error prints.
Fix KASAN error in geni_spi_isr().
Remove spi-geni-qcom.h
Remove inter words delay and CS to Clock toggle delay logic in the driver, as of now no clients are using it. Will submit this logic in the next patchset.
Use major, minor and step macros to read from hardware version register.

Quoted 5 lines
 .../devicetree/bindings/soc/qcom/qcom,geni-se.txt  |   2 -
 drivers/spi/Kconfig                                |  12 +
 drivers/spi/Makefile                               |   1 +
 drivers/spi/spi-geni-qcom.c                        | 678 +++++++++++++++++++++
 4 files changed, 691 insertions(+), 2 deletions(-)

See below for comments. In general I've tried to post patches to address my own comments. See the series ending at
<https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201142/1>.

Quoted 1 line

From there you can download patch files by using the "DOWNLOAD" link

at the bottom. Yell if you have problems. Hopefully that's useful. I expect that you can squash many of these into your patch to give you a leg up on v3.

NOTE: I won't promise that I made no mistakes on my fixup patches nor that I caught everything or did everything right. I'll plan to take a fresh look at the whole patch when I see your v3.

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt Required properties: · line 63

Quoted 7 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +0 -1
@@ -60,7 +60,6 @@ Required properties:
 - interrupts:          Must contain SPI controller interrupts.
 - clock-names:         Must contain "se".
 - clocks:              Serial engine core clock needed by the device.
-- spi-max-frequency:   Specifies maximum SPI clock frequency, units - Hz.

As per Rob's feedback, please split the device tree change into a separate patch and justify it. Perhaps the commit message could be something like:

---

dt-bindings: spi: Remove spi-max-frequency from qcom,geni-se controller

No other SPI controllers have a "spi-max-frequency" at the controller level. The normal "spi-max-frequency" property is something that is used when defining the nodes for SPI slaves. While it is possible that someone might want to define a controller-level max frequency it should be done in other ways (perhaps by keying off a compatible string?)

---

I think in the past Mark Brown has also requested that the bindings actually live under "Documentation/devicetree/bindings/spi/", so perhaps you should also add a patch to your series that moves this documentation there and changes the "soc/qcom/qcom,geni-se.txt" to reference that.

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt Required properties:

Quoted 5 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +5 -0
+static irqreturn_t geni_spi_isr(int irq, void *data);
+
+struct spi_geni_master {
+       struct geni_se se;
+       unsigned int irq;

In v1 Stephen requested that many things in this struct become "unsigned int", but he didn't mean the "irq". Please change this back to an int. As you have things right now the code "if (spi_geni->irq < 0)" you have below is a no-op. :(

...oh, and as Stephen pointed out to me offline you don't even need to store irq.

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201065

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt

Quoted 5 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +5 -0
+       struct device *dev;
+       unsigned int rx_fifo_depth;
+       unsigned int tx_fifo_depth;
+       unsigned int tx_fifo_width;
+       unsigned int tx_wm;

Anything that is effectively the contents of a hardware register should be of type 'u32'.

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201066

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt

Quoted 12 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +12 -0
+static int get_spi_clk_cfg(unsigned int speed_hz,
+                       struct spi_geni_master *mas,
+                       unsigned int *clk_idx,
+                       unsigned int *clk_div)
+{
+       unsigned long sclk_freq;
+       struct geni_se *se = &mas->se;
+       int ret;
+
+       ret = geni_se_clk_freq_match(&mas->se,
+                               (speed_hz * mas->oversampling), clk_idx,
+                               &sclk_freq, true);

Pass "false" as the last parameter after picking my geni patch to make this work right. For my geni patch see
<https://lkml.kernel.org/r/[email protected]>.

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201064

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt

Quoted 3 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +3 -0
+       if (ret) {
+               dev_err(mas->dev, "%s: Failed(%d) to find src clk for %dHz\n",
+                                               __func__, ret, speed_hz);

As I said in previous reviews: printing __func__ is generally discouraged for dev_xx printouts. They've already got the device name and that together with the string should be enough. Remove it here and elsewhere in this file.

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201067

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt

Quoted 4 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +4 -0
+               return ret;
+       }
+
+       *clk_div = ((sclk_freq / mas->oversampling) / speed_hz);

After changing exact to false, you'll want:

  *clk_div = DIV_ROUND_UP(sclk_freq, mas->oversampling * speed_hz);
  actual_hz = sclk_freq / (mas->oversampling * *clk_div);

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201064

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt

Quoted 5 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +5 -0
+       if (!(*clk_div)) {
+               dev_err(mas->dev, "%s:Err:sclk:%lu oversampling:%d speed:%u\n",
+                       __func__, sclk_freq, mas->oversampling, speed_hz);
+               return -EINVAL;
+       }

After change above to use DIV_ROUND_UP() you no longer need to check for a zero clk_div.

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201064

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt

Quoted 8 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +8 -0
+static void spi_setup_word_len(struct spi_geni_master *mas, u16 mode,
+                                       unsigned int bits_per_word)
+{
+       unsigned int word_len, pack_words;
+       bool msb_first = (mode & SPI_LSB_FIRST) ? false : true;
+       struct geni_se *se = &mas->se;
+
+       word_len = readl_relaxed(se->base + SE_SPI_WORD_LEN);

Gratuitously using the __relaxed versions of readl() and writel() is discouraged in Linux because it gives very little performance gain in 99.9% of the cases and it makes the code significantly harder to reason about it. Remove it in spi-geni-qcom. If it is shown that a particular read or write is in a performance critical section then that one instance can be added back in after carefully analysis and documentation.

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201068

Quoted 11 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +11 -0
+static int setup_fifo_params(struct spi_device *spi_slv,
+                                       struct spi_master *spi)
+{
+       struct spi_geni_master *mas = spi_master_get_devdata(spi);
+       struct geni_se *se = &mas->se;
+       unsigned int mode = spi_slv->mode;
+       unsigned int loopback_cfg = readl_relaxed(se->base + SE_SPI_LOOPBACK);
+       unsigned int cpol = readl_relaxed(se->base + SE_SPI_CPOL);
+       unsigned int cpha = readl_relaxed(se->base + SE_SPI_CPHA);
+       unsigned int demux_sel, clk_sel, m_clk_cfg, idx, div;
+       int ret = 0;
Quoted 1 line · In v1 Stephen said:

Don't initialize variables and then overwrite them.

This is in lots of places in your code. I've found and fixed them for you:

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201070

Quoted 21 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +21 -0
+       unsigned int demux_output_inv = 0;
+
+       loopback_cfg &= ~LOOPBACK_MSK;
+       cpol &= ~CPOL;
+       cpha &= ~CPHA;
+
+       if (mode & SPI_LOOP)
+               loopback_cfg |= LOOPBACK_ENABLE;
+
+       if (mode & SPI_CPOL)
+               cpol |= CPOL;
+
+       if (mode & SPI_CPHA)
+               cpha |= CPHA;
+
+       if (spi_slv->mode & SPI_CS_HIGH)
+               demux_output_inv = BIT(spi_slv->chip_select);
+
+       demux_sel = spi_slv->chip_select;
+       mas->cur_speed_hz = spi_slv->max_speed_hz;
+       mas->cur_word_len = spi_slv->bits_per_word;

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt

Quoted 10 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +10 -0
+
+       ret = get_spi_clk_cfg(mas->cur_speed_hz, mas, &idx, &div);
+       if (ret) {
+               dev_err(mas->dev, "Err setting clks ret(%d) for %d\n",
+                                                       ret, mas->cur_speed_hz);
+               return ret;
+       }
+
+       clk_sel = (idx & CLK_SEL_MSK);
+       m_clk_cfg = ((div << CLK_DIV_SHFT) | SER_CLK_EN);

Please avoid useless parenthesis everywhere in this file. Stephen pointed out many of these in v1 but the correct thing to do would have been to search for all instances and fix them, not just fix the ones that Stephen pointed out. I've now done it for you:

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201071

Quoted 19 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +19 -0
+static int spi_geni_prepare_transfer_hardware(struct spi_master *spi)
+{
+       struct spi_geni_master *mas = spi_master_get_devdata(spi);
+       struct geni_se *se = &mas->se;
+
+       if (!mas->setup) {
+               unsigned int proto = geni_se_read_proto(se);
+               unsigned int major, minor, step, ver;
+
+               if (proto != GENI_SE_SPI) {
+                       dev_err(mas->dev, "Invalid proto %d\n", proto);
+                       return -ENXIO;
+               }
+               mas->tx_fifo_depth = geni_se_get_tx_fifo_depth(se);
+               mas->rx_fifo_depth = geni_se_get_rx_fifo_depth(se);
+               mas->tx_fifo_width = geni_se_get_tx_fifo_width(se);
+
+               /*
+                * Hardware programming guide suggests to configure

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt

Quoted 10 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +10 -0
+                * RX FIFO RFR level to fifo_depth-2.
+                */
+               geni_se_init(se, 0x0, mas->tx_fifo_depth - 2);
+               mas->oversampling = 1;
+               /* Transmit an entire FIFO worth of data per IRQ */
+               mas->tx_wm = 1;
+               ver = geni_se_get_qup_hw_version(se);
+               major = GENI_SE_VERSION_MAJOR(ver);
+               minor = GENI_SE_VERSION_MINOR(ver);
+               step = GENI_SE_VERSION_STEP(ver);

You don't use "step". Kill it.

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201069

Quoted 13 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +13 -0
+       /*
+        * If CS change flag is set, then toggle the CS line in between
+        * transfers and keep CS asserted after the last transfer.
+        * Else if keep CS flag asserted in between transfers and de-assert
+        * CS after the last message.
+        */
+       if (xfer->cs_change) {
+               if (list_is_last(&xfer->transfer_list,
+                               &spi->cur_msg->transfers))
+                       m_param |= FRAGMENTATION;
+       } else {
+               if (!list_is_last(&xfer->transfer_list,
+                               &spi->cur_msg->transfers))
Quoted 1 line · In v1 Stephen said:

Combine else and if here into an else if.

...but really I think you could just do:

/*
* Keep the CS asserted in either of the two cases:
* - It's not the last transfer (and cs_change is not set)
* - It is the last transfer (and cs_change is set)
*
* ...AKA keep it asserted whenever the "last transfer" and cs_change
* booleans agree.
*/
if (!!xfer->cs_change ==

    !!list_is_last(&xfer->transfer_list, &spi->cur_msg->transfers))
        m_param |= FRAGMENTATION;

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201072

Quoted 13 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +13 -0
+       if (m_cmd & SPI_TX_ONLY) {
+               mas->tx_rem_bytes = xfer->len;
+               writel_relaxed(trans_len, se->base + SE_SPI_TX_TRANS_LEN);
+       }
+
+       if (m_cmd & SPI_RX_ONLY) {
+               writel_relaxed(trans_len, se->base + SE_SPI_RX_TRANS_LEN);
+               mas->rx_rem_bytes = xfer->len;
+       }
+       writel_relaxed(spi_tx_cfg, se->base + SE_SPI_TRANS_CFG);
+       geni_se_setup_m_cmd(se, m_cmd, m_param);
+       if (m_cmd & SPI_TX_ONLY)
+               writel_relaxed(mas->tx_wm, se->base + SE_GENI_TX_WATERMARK_REG);
Quoted 1 line · In v1 Stephen said:

This can't be combined with above m_cmd & SPI_TX_ONLY statement?

Quoted 3 lines · In v2 I said:

Girish said it can't. ...but IMO if it really can't then please add a comment in the code so someone doesn't later go back and try to combine.

I don't see a comment. An example of an appropriate comment (assuming that the geni hardware really does need the services of a dark wizard) would be:

/*
* NOTE: we have to write the SE_GENI_TX_WATERMARK_REG _after_ the
* write to SE_SPI_TRANS_CFG and the call to geni_se_setup_m_cmd()
* because these two things perform a special incantation to summon a
* dark wizard and we're not allowed to set the watermark until the
* dark wizard arrives.
*/

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201073

Presumably writing to the watermark kicks off the interrupt happening so it has to be last. That would be something to say instead of talking about magic.

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt

Quoted 4 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +4 -0
+static irqreturn_t geni_spi_handle_tx(struct spi_geni_master *mas)
+{
+       unsigned int i = 0;
+       unsigned int tx_fifo_width = mas->tx_fifo_width / BITS_PER_BYTE;

This is super confusing. You have two things with the same name "tx_fifo_width" one that's in terms of bits and one that's in terms of bytes. ...in general it's really hard to figure out the units of all your variables here. For things that it's not clear you should rename variables.

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201075

Quoted 10 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +10 -0
+       unsigned int max_bytes;
+       const u8 *tx_buf;
+       struct geni_se *se = &mas->se;
+
+       if (!mas->cur_xfer)
+               return IRQ_NONE;
+
+       /*
+        * For non-byte aligned bits-per-word values(e.g 9).
+        * The FIFO packing is set to 1 SPI word per FIFO word.
Quoted 1 line · In v1 Stephen said:

Decapitalize "The"

You added a "." at the end of the first line so I guess it's not quite as wrong as it was but it's still better grammar to just have one sentence.

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201074

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt

Quoted 9 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +9 -0
+        * Assumption is that each SPI word will be accomodated in
+        * ceil (bits_per_word / bits_per_byte)
+        * and the next SPI word starts at the next byte.
+        * In such cases, we can fit 1 SPI word per FIFO word so adjust the
+        * max byte that can be sent per IRQ accordingly.
+        */
+       max_bytes = (mas->tx_fifo_depth - mas->tx_wm);
+       if (mas->tx_fifo_width % mas->cur_word_len)
+               max_bytes *= ((mas->cur_word_len / BITS_PER_BYTE) + 1);

Even though the math should be the same (since you should you'll never divide cur_word_len evenly), the above is clearer as:

  max_bytes *= DIV_ROUND_UP(mas->cur_word_len, BITS_PER_BYTE);

...oh, but even that is wrong. SPI framework documents that we need the nearest power of 2, so a 20-bit transfer will not take up 3 bytes but will actually take up 4.

...and of course this same assumption is replicated twice in both the tx and rx functions. I'm just going to rewrite these two functions.

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201076

Quoted 9 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +9 -0
+       while (i < max_bytes) {
+               unsigned int j;
+               unsigned int fifo_word = 0;
+               u8 *fifo_byte;
+               unsigned int bytes_per_fifo = tx_fifo_width;
+               unsigned int bytes_to_write = 0;
+
+               if (mas->tx_fifo_width % mas->cur_word_len)
+                       bytes_per_fifo =

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt

Quoted 10 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +10 -0
+                               (mas->cur_word_len / BITS_PER_BYTE) + 1;
+
+               if (bytes_per_fifo < (max_bytes - i))
+                       bytes_to_write = bytes_per_fifo;
+               else
+                       bytes_to_write = max_bytes - i;
+
+               fifo_byte = (u8 *)&fifo_word;
+               for (j = 0; j < bytes_to_write; j++)
+                       fifo_byte[j] = tx_buf[i++];

In previous reviews Stephen pointed out that he's not super keen on this manual copy of bytes, but IMO it's not a huge deal and we can find a better way to do it later. ...but if someone wants to propose a patch that makes it nicer then I won't object.

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt

Quoted 5 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +5 -0
+static irqreturn_t geni_spi_handle_rx(struct spi_geni_master *mas)
+{
+       unsigned int i = 0;
+       struct geni_se *se = &mas->se;
+       unsigned int fifo_width = mas->tx_fifo_width / BITS_PER_BYTE;

You're assuming TX and RX FIFO widths are the same. Let's make that explicit.

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201075

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt

Quoted 12 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +12 -0
+static int spi_geni_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct spi_master *spi;
+       struct spi_geni_master *spi_geni;
+       struct resource *res;
+       struct geni_se *se;
+
+       spi = spi_alloc_master(&pdev->dev, sizeof(struct spi_geni_master));
+       if (!spi) {
+               ret = -ENOMEM;
+               goto spi_geni_probe_err;

When spi_alloc_master() fails you don't want spi_master_put().

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201078

Quoted 1 line

+ spi->prepare_transfer_hardware = spi_geni_prepare_transfer_hardware;

IMO this is wrong. You're using prepare_transfer_hardware() to do one-time init. Just do it at probe.

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201079

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt

Quoted 5 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +5 -0
+       init_completion(&spi_geni->xfer_done);
+       pm_runtime_enable(&pdev->dev);
+       ret = devm_spi_register_master(&pdev->dev, spi);
+       if (ret)
+               goto spi_geni_probe_unmap;

In this error case I believe you need pm_runtime_disable().

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201078

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt

Quoted 3 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +3 -0
+       return ret;
+spi_geni_probe_unmap:
+       devm_iounmap(&pdev->dev, se->base);

The whole point of devm is that you don't need this kind of the error handling.

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201078

Quoted 6 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +6 -0
+static int spi_geni_remove(struct platform_device *pdev)
+{
+       struct spi_master *spi = platform_get_drvdata(pdev);
+       struct spi_geni_master *spi_geni = spi_master_get_devdata(spi);
+
+       geni_se_resources_off(&spi_geni->se);
Quoted 5 lines · In v2 I said:

Why would you need to call geni_se_resources_off()? Isn't it handled by pm_runtime?

+ pm_runtime_put_noidle(&pdev->dev);

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt

Quoted 6 lines · In v2 I said:

I'm curious: why would you have a "put" here? Won't that result in an imbalance since you don't exit probe with "get"? ...or did pm_runtime throw me for a loop again?

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +2 -0
+       pm_runtime_disable(&pdev->dev);
+       return 0;

So testing:

      cd /sys/bus/platform/drivers/geni_spi/
      echo 880000.spi > unbind
      sleep 2
      echo 880000.spi > bind

...in fact it yells a lot. To me this means that you didn't test spi_geni_remove() at all.

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201077

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt

Quoted 4 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +4 -0
+static int __maybe_unused spi_geni_suspend(struct device *dev)
+{
+       if (!pm_runtime_status_suspended(dev))
+               return -EBUSY;

I didn't have time to dig into Stephen Boyd's feedback, but please make sure you address it here. I agree that something seems fishy here.

---

Quoted 9 lines · In v2, I said:

I'm not sure where to comment about this, so adding it to the end:

Between v1 and v2 you totally removed all the locking. Presumably this is because you didn't want to hold the lock in handle_fifo_timeout() while waiting for the completion. IMO taking the lock out was the wrong thing to do. You should keep it, but just drop the lock before wait_for_completion_timeout() and add it back afterwards. Specifically you _don't_ want the IRQ and timeout code stomping on each other.

...but still no spinlock?

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201081

---

As we've discussed offline, your current driver doesn't deal with chip select in a correct enough way to make cros_ec_spi work. I've applied and fixed up your WIP patch to fix this.

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201142

-Doug

#8 lore raw
Quoted 85 lines · Doug Anderson

Hi,

Quoted 49 lines · Dilip Kota

From: Girish Mahadevan <[email protected]>

This driver supports GENI based SPI Controller in the Qualcomm SOCs. The Qualcomm Generic Interface (GENI) is a programmable module supporting a wide range of serial interfaces including SPI. This driver supports SPI operations using FIFO mode of transfer.

---
Addressing all the reviewer commets given in Patchset1. Summerizing all the comments below:

MAKEFILE: Arrange SPI-GENI driver in alphabetical order
Kconfig: Mark SPI_GENI driver dependent on QCOM_GENI_SE Enable SPI core auto runtime pm, and remove runtime pm calls. Remove spi_geni_unprepare_message(),
spi_geni_unprepare_transfer_hardware()
Remove likely/unlikely keywords.
Remove get_spi_master() and use dev_get_drvdata() Move request_irq to probe()
Mark bus number assignment to -1 as SPI core framework will
assign dynamically
Use devm_spi_register_master()
Include platform_device.h instead of of_platform.h Removing macros which are used only once:
#define SPI_NUM_CHIPSELECT 4
#define SPI_XFER_TIMEOUT_MS 250
Place Register field definitions next to respective Register
definitions.
Replace int and u32 declerations to unsigned int. Remove Hex numbers in debug prints.
Declare mode as u16 in spi_setup_word_len()
Remove the labels: setup_fifo_params_exit:
exit_prepare_transfer_hardware:
Declaring struct spi_master as spi everywhere in the file. Calling spi_finalize_current_transfer() for end of transfer. Hard code the SPI controller max frequency instead of reading
from DTSI node.
Spinlock not required, removed it.
Removed unrequired error prints.
Fix KASAN error in geni_spi_isr().
Remove spi-geni-qcom.h
Remove inter words delay and CS to Clock toggle delay logic in
the driver, as of now no clients are using it.
Will submit this logic in the next patchset.
Use major, minor and step macros to read from hardware version
register.

Quoted 6 lines
 .../devicetree/bindings/soc/qcom/qcom,geni-se.txt  |   2 -
 drivers/spi/Kconfig                                |  12 +
 drivers/spi/Makefile                               |   1 +
 drivers/spi/spi-geni-qcom.c                        | 678 
+++++++++++++++++++++
 4 files changed, 691 insertions(+), 2 deletions(-)

See below for comments. In general I've tried to post patches to address my own comments. See the series ending at
<https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201142/1>.
From there you can download patch files by using the "DOWNLOAD" link at the bottom. Yell if you have problems. Hopefully that's useful. I expect that you can squash many of these into your patch to give you a leg up on v3.

NOTE: I won't promise that I made no mistakes on my fixup patches nor that I caught everything or did everything right. I'll plan to take a fresh look at the whole patch when I see your v3.

Quoted 8 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +0 -1
@@ -60,7 +60,6 @@ Required properties:
 - interrupts:          Must contain SPI controller interrupts.
 - clock-names:         Must contain "se".
 - clocks:              Serial engine core clock needed by the device.
-- spi-max-frequency:   Specifies maximum SPI clock frequency, units - 

Hz.

As per Rob's feedback, please split the device tree change into a separate patch and justify it. Perhaps the commit message could be something like:

Quoted 1 line

---

Ok, will submit as separate patch.

Quoted 30 lines

dt-bindings: spi: Remove spi-max-frequency from qcom,geni-se controller

No other SPI controllers have a "spi-max-frequency" at the controller level. The normal "spi-max-frequency" property is something that is used when defining the nodes for SPI slaves. While it is possible that someone might want to define a controller-level max frequency it should be done in other ways (perhaps by keying off a compatible string?)

---

I think in the past Mark Brown has also requested that the bindings actually live under "Documentation/devicetree/bindings/spi/", so perhaps you should also add a patch to your series that moves this documentation there and changes the "soc/qcom/qcom,geni-se.txt" to reference that.

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt

Quoted 5 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +5 -0
+static irqreturn_t geni_spi_isr(int irq, void *data);
+
+struct spi_geni_master {
+       struct geni_se se;
+       unsigned int irq;

In v1 Stephen requested that many things in this struct become "unsigned int", but he didn't mean the "irq". Please change this back to an int. As you have things right now the code "if (spi_geni->irq < 0)" you have below is a no-op. :(

Quoted 3 lines

...oh, and as Stephen pointed out to me offline you don't even need to store irq.

Ok

Quoted 11 lines

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201065

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt

Quoted 5 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +5 -0
+       struct device *dev;
+       unsigned int rx_fifo_depth;
+       unsigned int tx_fifo_depth;
+       unsigned int tx_fifo_width;
+       unsigned int tx_wm;

Anything that is effectively the contents of a hardware register should be of type 'u32'.

Ok, will update it

Quoted 31 lines

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201066

Quoted 11 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +11 -0
+static int get_spi_clk_cfg(unsigned int speed_hz,
+                       struct spi_geni_master *mas,
+                       unsigned int *clk_idx,
+                       unsigned int *clk_div)
+{
+       unsigned long sclk_freq;
+       struct geni_se *se = &mas->se;
+       int ret;
+
+       ret = geni_se_clk_freq_match(&mas->se,
+                               (speed_hz * mas->oversampling), 
Quoted 2 lines

clk_idx,
+ &sclk_freq, true);

Pass "false" as the last parameter after picking my geni patch to make this work right. For my geni patch see
<https://lkml.kernel.org/r/[email protected]>.

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201064
Agree. Will mark it to False.

Quoted 5 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +2 -0
+       if (ret) {
+               dev_err(mas->dev, "%s: Failed(%d) to find src clk for 

%dHz\n",
+ __func__, ret,
speed_hz);

Quoted 5 lines

As I said in previous reviews: printing __func__ is generally discouraged for dev_xx printouts. They've already got the device name and that together with the string should be enough. Remove it here and elsewhere in this file.

Ok, will traverse the driver and remove __func__

Quoted 8 lines

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201067

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt

Quoted 4 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +4 -0
+               return ret;
+       }
+
+       *clk_div = ((sclk_freq / mas->oversampling) / speed_hz);
Quoted 7 lines

After changing exact to false, you'll want:

  *clk_div = DIV_ROUND_UP(sclk_freq, mas->oversampling * speed_hz);
  actual_hz = sclk_freq / (mas->oversampling * *clk_div);

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201064

Ok. I see actual_hz variable for debug prints itself.

Quoted 11 lines

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt

Quoted 8 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +2 -0
+       if (!(*clk_div)) {
+               dev_err(mas->dev, "%s:Err:sclk:%lu oversampling:%d 

speed:%u\n",
+ __func__, sclk_freq, mas->oversampling,
speed_hz);

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +2 -0
+               return -EINVAL;
+       }

After change above to use DIV_ROUND_UP() you no longer need to check for a zero clk_div.

Ok

Quoted 21 lines

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201064

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt

Quoted 8 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +8 -0
+static void spi_setup_word_len(struct spi_geni_master *mas, u16 mode,
+                                       unsigned int bits_per_word)
+{
+       unsigned int word_len, pack_words;
+       bool msb_first = (mode & SPI_LSB_FIRST) ? false : true;
+       struct geni_se *se = &mas->se;
+
+       word_len = readl_relaxed(se->base + SE_SPI_WORD_LEN);

Gratuitously using the __relaxed versions of readl() and writel() is discouraged in Linux because it gives very little performance gain in 99.9% of the cases and it makes the code significantly harder to reason about it. Remove it in spi-geni-qcom. If it is shown that a particular read or write is in a performance critical section then that one instance can be added back in after carefully analysis and documentation.

Quoted 1 line

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201068

Ok

Quoted 17 lines
Quoted 10 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +7 -0
+static int setup_fifo_params(struct spi_device *spi_slv,
+                                       struct spi_master *spi)
+{
+       struct spi_geni_master *mas = spi_master_get_devdata(spi);
+       struct geni_se *se = &mas->se;
+       unsigned int mode = spi_slv->mode;
+       unsigned int loopback_cfg = readl_relaxed(se->base + 

SE_SPI_LOOPBACK);

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt

Quoted 4 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +4 -0
+       unsigned int cpol = readl_relaxed(se->base + SE_SPI_CPOL);
+       unsigned int cpha = readl_relaxed(se->base + SE_SPI_CPHA);
+       unsigned int demux_sel, clk_sel, m_clk_cfg, idx, div;
+       int ret = 0;

In v1 Stephen said:

Quoted 5 lines
Quoted 1 line

Don't initialize variables and then overwrite them.

This is in lots of places in your code. I've found and fixed them for you:

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201070

Ok

Quoted 40 lines
Quoted 29 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +26 -0
+       unsigned int demux_output_inv = 0;
+
+       loopback_cfg &= ~LOOPBACK_MSK;
+       cpol &= ~CPOL;
+       cpha &= ~CPHA;
+
+       if (mode & SPI_LOOP)
+               loopback_cfg |= LOOPBACK_ENABLE;
+
+       if (mode & SPI_CPOL)
+               cpol |= CPOL;
+
+       if (mode & SPI_CPHA)
+               cpha |= CPHA;
+
+       if (spi_slv->mode & SPI_CS_HIGH)
+               demux_output_inv = BIT(spi_slv->chip_select);
+
+       demux_sel = spi_slv->chip_select;
+       mas->cur_speed_hz = spi_slv->max_speed_hz;
+       mas->cur_word_len = spi_slv->bits_per_word;
+
+       ret = get_spi_clk_cfg(mas->cur_speed_hz, mas, &idx, &div);
+       if (ret) {
+               dev_err(mas->dev, "Err setting clks ret(%d) for %d\n",
+                                                       ret, 

mas->cur_speed_hz);

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt

Quoted 5 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +5 -0
+               return ret;
+       }
+
+       clk_sel = (idx & CLK_SEL_MSK);
+       m_clk_cfg = ((div << CLK_DIV_SHFT) | SER_CLK_EN);

Please avoid useless parenthesis everywhere in this file. Stephen pointed out many of these in v1 but the correct thing to do would have been to search for all instances and fix them, not just fix the ones that Stephen pointed out. I've now done it for you:

Quoted 3 lines

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201071

Ok

Quoted 24 lines
Quoted 24 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +11 -0
+static int spi_geni_prepare_transfer_hardware(struct spi_master *spi)
+{
+       struct spi_geni_master *mas = spi_master_get_devdata(spi);
+       struct geni_se *se = &mas->se;
+
+       if (!mas->setup) {
+               unsigned int proto = geni_se_read_proto(se);
+               unsigned int major, minor, step, ver;
+
+               if (proto != GENI_SE_SPI) {
+                       dev_err(mas->dev, "Invalid proto %d\n", 

proto);

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +12 -0
+                       return -ENXIO;
+               }
+               mas->tx_fifo_depth = geni_se_get_tx_fifo_depth(se);
+               mas->rx_fifo_depth = geni_se_get_rx_fifo_depth(se);
+               mas->tx_fifo_width = geni_se_get_tx_fifo_width(se);
+
+               /*
+                * Hardware programming guide suggests to configure
+                * RX FIFO RFR level to fifo_depth-2.
+                */
+               geni_se_init(se, 0x0, mas->tx_fifo_depth - 2);
+               mas->oversampling = 1;
Quoted 9 lines

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt

Quoted 6 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +6 -0
+               /* Transmit an entire FIFO worth of data per IRQ */
+               mas->tx_wm = 1;
+               ver = geni_se_get_qup_hw_version(se);
+               major = GENI_SE_VERSION_MAJOR(ver);
+               minor = GENI_SE_VERSION_MINOR(ver);
+               step = GENI_SE_VERSION_STEP(ver);

You don't use "step". Kill it.

Ok

Quoted 34 lines

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201069

Quoted 15 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +2 -0
+       /*
+        * If CS change flag is set, then toggle the CS line in 

between

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +2 -0
+        * transfers and keep CS asserted after the last transfer.
+        * Else if keep CS flag asserted in between transfers and 

de-assert

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +9 -0
+        * CS after the last message.
+        */
+       if (xfer->cs_change) {
+               if (list_is_last(&xfer->transfer_list,
+                               &spi->cur_msg->transfers))
+                       m_param |= FRAGMENTATION;
+       } else {
+               if (!list_is_last(&xfer->transfer_list,
+                               &spi->cur_msg->transfers))
Quoted 1 line · In v1 Stephen said:

Combine else and if here into an else if.

...but really I think you could just do:

/*
* Keep the CS asserted in either of the two cases:
* - It's not the last transfer (and cs_change is not set)
* - It is the last transfer (and cs_change is set)
*
* ...AKA keep it asserted whenever the "last transfer" and cs_change
* booleans agree.
*/
if (!!xfer->cs_change ==

Quoted 3 lines
    !!list_is_last(&xfer->transfer_list, &spi->cur_msg->transfers))
        m_param |= FRAGMENTATION;

This complete logic will be removed with set_cs() change, because m_param |= FRAGMENTATION; should set in all the cases.

Quoted 26 lines

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201072

Quoted 16 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +3 -0
+       if (m_cmd & SPI_TX_ONLY) {
+               mas->tx_rem_bytes = xfer->len;
+               writel_relaxed(trans_len, se->base + 

SE_SPI_TX_TRANS_LEN);

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +4 -0
+       }
+
+       if (m_cmd & SPI_RX_ONLY) {
+               writel_relaxed(trans_len, se->base + 

SE_SPI_RX_TRANS_LEN);

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +6 -0
+               mas->rx_rem_bytes = xfer->len;
+       }
+       writel_relaxed(spi_tx_cfg, se->base + SE_SPI_TRANS_CFG);
+       geni_se_setup_m_cmd(se, m_cmd, m_param);
+       if (m_cmd & SPI_TX_ONLY)
+               writel_relaxed(mas->tx_wm, se->base + 

SE_GENI_TX_WATERMARK_REG);

Quoted 1 line · In v1 Stephen said:

This can't be combined with above m_cmd & SPI_TX_ONLY statement?

In v2 I said:

Quoted 8 lines
Quoted 3 lines

Girish said it can't. ...but IMO if it really can't then please add a comment in the code so someone doesn't later go back and try to combine.

I don't see a comment. An example of an appropriate comment (assuming that the geni hardware really does need the services of a dark wizard) would be:

I will add the detailed comments.

Quoted 15 lines

/*
* NOTE: we have to write the SE_GENI_TX_WATERMARK_REG _after_ the
* write to SE_SPI_TRANS_CFG and the call to geni_se_setup_m_cmd()
* because these two things perform a special incantation to summon a
* dark wizard and we're not allowed to set the watermark until the
* dark wizard arrives.
*/

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201073

Presumably writing to the watermark kicks off the interrupt happening so it has to be last. That would be something to say instead of talking about magic.

Quoted 12 lines
Quoted 5 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +4 -0
+static irqreturn_t geni_spi_handle_tx(struct spi_geni_master *mas)
+{
+       unsigned int i = 0;
+       unsigned int tx_fifo_width = mas->tx_fifo_width / 

BITS_PER_BYTE;

This is super confusing. You have two things with the same name "tx_fifo_width" one that's in terms of bits and one that's in terms of bytes. ...in general it's really hard to figure out the units of all your variables here. For things that it's not clear you should rename variables.

Ok, will rename it.

Quoted 16 lines

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201075

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt

Quoted 10 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +10 -0
+       unsigned int max_bytes;
+       const u8 *tx_buf;
+       struct geni_se *se = &mas->se;
+
+       if (!mas->cur_xfer)
+               return IRQ_NONE;
+
+       /*
+        * For non-byte aligned bits-per-word values(e.g 9).
+        * The FIFO packing is set to 1 SPI word per FIFO word.

In v1 Stephen said:

Quoted 9 lines
Quoted 1 line

Decapitalize "The"

You added a "." at the end of the first line so I guess it's not quite as wrong as it was but it's still better grammar to just have one sentence.

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201074

Ok

Quoted 62 lines
Quoted 11 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +4 -0
+        * Assumption is that each SPI word will be accomodated in
+        * ceil (bits_per_word / bits_per_byte)
+        * and the next SPI word starts at the next byte.
+        * In such cases, we can fit 1 SPI word per FIFO word so 

adjust the

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +5 -0
+        * max byte that can be sent per IRQ accordingly.
+        */
+       max_bytes = (mas->tx_fifo_depth - mas->tx_wm);
+       if (mas->tx_fifo_width % mas->cur_word_len)
+               max_bytes *= ((mas->cur_word_len / BITS_PER_BYTE) + 

1);

Even though the math should be the same (since you should you'll never divide cur_word_len evenly), the above is clearer as:

  max_bytes *= DIV_ROUND_UP(mas->cur_word_len, BITS_PER_BYTE);

...oh, but even that is wrong. SPI framework documents that we need the nearest power of 2, so a 20-bit transfer will not take up 3 bytes but will actually take up 4.

...and of course this same assumption is replicated twice in both the tx and rx functions. I'm just going to rewrite these two functions.

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201076

Quoted 11 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +10 -0
+       while (i < max_bytes) {
+               unsigned int j;
+               unsigned int fifo_word = 0;
+               u8 *fifo_byte;
+               unsigned int bytes_per_fifo = tx_fifo_width;
+               unsigned int bytes_to_write = 0;
+
+               if (mas->tx_fifo_width % mas->cur_word_len)
+                       bytes_per_fifo =
+                               (mas->cur_word_len / BITS_PER_BYTE) + 

1;

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt

Quoted 9 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +9 -0
+
+               if (bytes_per_fifo < (max_bytes - i))
+                       bytes_to_write = bytes_per_fifo;
+               else
+                       bytes_to_write = max_bytes - i;
+
+               fifo_byte = (u8 *)&fifo_word;
+               for (j = 0; j < bytes_to_write; j++)
+                       fifo_byte[j] = tx_buf[i++];

In previous reviews Stephen pointed out that he's not super keen on this manual copy of bytes, but IMO it's not a huge deal and we can find a better way to do it later. ...but if someone wants to propose a patch that makes it nicer then I won't object.

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt

Quoted 5 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +5 -0
+static irqreturn_t geni_spi_handle_rx(struct spi_geni_master *mas)
+{
+       unsigned int i = 0;
+       struct geni_se *se = &mas->se;
+       unsigned int fifo_width = mas->tx_fifo_width / BITS_PER_BYTE;

You're assuming TX and RX FIFO widths are the same. Let's make that explicit.

Quoted 2 lines

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201075

Agree

Quoted 20 lines
Quoted 11 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +9 -0
+static int spi_geni_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct spi_master *spi;
+       struct spi_geni_master *spi_geni;
+       struct resource *res;
+       struct geni_se *se;
+
+       spi = spi_alloc_master(&pdev->dev, sizeof(struct 

spi_geni_master));

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt

Quoted 3 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +3 -0
+       if (!spi) {
+               ret = -ENOMEM;
+               goto spi_geni_probe_err;

When spi_alloc_master() fails you don't want spi_master_put().

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201078

Quoted 8 lines
Quoted 2 lines

+ spi->prepare_transfer_hardware =
spi_geni_prepare_transfer_hardware;

IMO this is wrong. You're using prepare_transfer_hardware() to do one-time init. Just do it at probe.

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201079

Agree, will move it to probe.

Quoted 9 lines

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt

Quoted 6 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +5 -0
+       init_completion(&spi_geni->xfer_done);
+       pm_runtime_enable(&pdev->dev);
+       ret = devm_spi_register_master(&pdev->dev, spi);
+       if (ret)
+               goto spi_geni_probe_unmap;

In this error case I believe you need pm_runtime_disable().

Yes, I will update it.

Quoted 9 lines

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201078

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt

Quoted 3 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +3 -0
+       return ret;
+spi_geni_probe_unmap:
+       devm_iounmap(&pdev->dev, se->base);

The whole point of devm is that you don't need this kind of the error handling.

Agree

Quoted 5 lines

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201078

Quoted 12 lines
Quoted 7 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +4 -0
+static int spi_geni_remove(struct platform_device *pdev)
+{
+       struct spi_master *spi = platform_get_drvdata(pdev);
+       struct spi_geni_master *spi_geni = 

spi_master_get_devdata(spi);

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +2 -0
+
+       geni_se_resources_off(&spi_geni->se);
Quoted 2 lines · In v2 I said:

Why would you need to call geni_se_resources_off()? Isn't it handled by pm_runtime?

IMO, runtime_pm may not be called during unbind operation. Anyhow I will run the test and check it.

Quoted 20 lines
Quoted 3 lines

+ pm_runtime_put_noidle(&pdev->dev);

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt

Quoted 6 lines · In v2 I said:

I'm curious: why would you have a "put" here? Won't that result in an imbalance since you don't exit probe with "get"? ...or did pm_runtime throw me for a loop again?

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +2 -0
+       pm_runtime_disable(&pdev->dev);
+       return 0;

So testing:

      cd /sys/bus/platform/drivers/geni_spi/
      echo 880000.spi > unbind
      sleep 2
      echo 880000.spi > bind
Quoted 5 lines

...in fact it yells a lot. To me this means that you didn't test spi_geni_remove() at all.

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201077

I will test and update it.

Quoted 10 lines

Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt

Quoted 5 lines
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +4 -0
+static int __maybe_unused spi_geni_suspend(struct device *dev)
+{
+       if (!pm_runtime_status_suspended(dev))
+               return -EBUSY;

I didn't have time to dig into Stephen Boyd's feedback, but please make sure you address it here. I agree that something seems fishy here.

I will check it.

Quoted 14 lines

---

Quoted 9 lines · In v2, I said:

I'm not sure where to comment about this, so adding it to the end:

Between v1 and v2 you totally removed all the locking. Presumably this is because you didn't want to hold the lock in handle_fifo_timeout() while waiting for the completion. IMO taking the lock out was the wrong thing to do. You should keep it, but just drop the lock before wait_for_completion_timeout() and add it back afterwards. Specifically you _don't_ want the IRQ and timeout code stomping on each other.

Quoted 1 line

...but still no spinlock?

I see there is no need of taking the spinlock as timeout will be handled after the calculated time as per data size and speed. There is 99.9% less chances of interrupt during the timeout handler.

Quoted 8 lines

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201081

---

As we've discussed offline, your current driver doesn't deal with chip select in a correct enough way to make cros_ec_spi work. I've applied and fixed up your WIP patch to fix this.

You are correct, runtime_pm wont be called by spi framework during the setup call. And, in ISR flag is required to differentiate between set_cs and actual transfer.

Quoted 5 lines

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201142

-Doug

#9 lore raw
Quoted 2 lines

When spi_alloc_master() fails you don't want spi_master_put().

Agree, will update it.

--Dilip

#10 lore raw
In reply to [email protected]

Hi,

Quoted 13 lines · On Fri, Sep 7, 2018 at 3:00 AM, <[email protected]> wrote:
Quoted 13 lines
Quoted 9 lines · In v2, I said:

I'm not sure where to comment about this, so adding it to the end:

Between v1 and v2 you totally removed all the locking. Presumably this is because you didn't want to hold the lock in handle_fifo_timeout() while waiting for the completion. IMO taking the lock out was the wrong thing to do. You should keep it, but just drop the lock before wait_for_completion_timeout() and add it back afterwards. Specifically you _don't_ want the IRQ and timeout code stomping on each other.

Quoted 9 lines
Quoted 1 line

...but still no spinlock?

I see there is no need of taking the spinlock as timeout will be handled after the calculated time as per data size and speed.
There is 99.9% less chances of interrupt during the timeout handler.

Quoted 4 lines

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201081

The thing is, we want it to be 100% reliable, not 99.9% reliable. Is it somehow wrong to add the spinlock? ...or are you noticing performance problems with the spinlock there? It's just nice not to have to think about it.

-Doug

#11 lore raw
In reply to [email protected]

Hi,

Quoted 13 lines · On Fri, Sep 7, 2018 at 3:00 AM, <[email protected]> wrote:
Quoted 13 lines
Quoted 9 lines · In v2, I said:

I'm not sure where to comment about this, so adding it to the end:

Between v1 and v2 you totally removed all the locking. Presumably this is because you didn't want to hold the lock in handle_fifo_timeout() while waiting for the completion. IMO taking the lock out was the wrong thing to do. You should keep it, but just drop the lock before wait_for_completion_timeout() and add it back afterwards. Specifically you _don't_ want the IRQ and timeout code stomping on each other.

Quoted 9 lines
Quoted 1 line

...but still no spinlock?

I see there is no need of taking the spinlock as timeout will be handled after the calculated time as per data size and speed.
There is 99.9% less chances of interrupt during the timeout handler.

Quoted 4 lines

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201081

The thing is, we want it to be 100% reliable, not 99.9% reliable. Is it somehow wrong to add the spinlock? ...or are you noticing performance problems with the spinlock there? It's just nice not to have to think about it.

-Doug

#12 lore raw
Quoted 7 lines
Quoted 7 lines

I see there is no need of taking the spinlock as timeout will be handled after the calculated time as per data size and speed.
There is 99.9% less chances of interrupt during the timeout handler.

Quoted 3 lines
Quoted 6 lines
Quoted 1 line
Quoted 1 line

https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1201081

The thing is, we want it to be 100% reliable, not 99.9% reliable. Is it somehow wrong to add the spinlock? ...or are you noticing performance problems with the spinlock there? It's just nice not to have to think about it.

As I said, timeout will be handled after the calculated time as per data size and speed. Enough time is given for interrupt, there is no chance of interrupt occurrence during the handle_fifo_timeout(). So there is no need of spinlock.

maintainer
#13 lore raw
Quoted 9 lines · On Mon, Sep 10, 2018 at 09:27:09AM +0530, [email protected] wrote:
Quoted 4 lines

The thing is, we want it to be 100% reliable, not 99.9% reliable. Is it somehow wrong to add the spinlock? ...or are you noticing performance problems with the spinlock there? It's just nice not to have to think about it.

As I said, timeout will be handled after the calculated time as per data size and speed. Enough time is given for interrupt, there is no chance of interrupt occurrence during the handle_fifo_timeout(). So there is no need of spinlock.

Assuming nothing goes wrong - the system isn't under unusually heavy load for example, there's some oversight in the code, there's no impact from power management causing things to run more slowly than you were expecting, someone uses the driver on a new bit of hardware where there are extra considerations or whatever else might go wrong. Like Doug says unless we're in some performance critical situation where it's worth thinking *really* hard about how things really are actually safe even though they might not look it it's both easier and more maintainable to just write software that's obviously safe to inspection.

#14 lore raw
Quoted 12 lines · Mark Brown
Quoted 9 lines · On Mon, Sep 10, 2018 at 09:27:09AM +0530, [email protected] wrote:
Quoted 4 lines

The thing is, we want it to be 100% reliable, not 99.9% reliable. Is it somehow wrong to add the spinlock? ...or are you noticing performance problems with the spinlock there? It's just nice not to have to think about it.

As I said, timeout will be handled after the calculated time as per data size and speed. Enough time is given for interrupt, there is no chance of interrupt occurrence during the handle_fifo_timeout(). So there is no need of spinlock.

Quoted 9 lines

Assuming nothing goes wrong - the system isn't under unusually heavy load for example, there's some oversight in the code, there's no impact from power management causing things to run more slowly than you were expecting, someone uses the driver on a new bit of hardware where there are extra considerations or whatever else might go wrong. Like Doug says unless we're in some performance critical situation where it's worth thinking *really* hard about how things really are actually safe even though they might not look it it's both easier and more maintainable to just write software that's obviously safe to inspection.

Agree with this perspective. There wont be any performance impact with spinlock. I will include the spinlock in the code.