spi: Don't look at TX buffer for PTP system timestamping
authorVladimir Oltean <olteanv@gmail.com>
Fri, 27 Dec 2019 01:24:17 +0000 (03:24 +0200)
committerMark Brown <broonie@kernel.org>
Fri, 27 Dec 2019 23:03:43 +0000 (23:03 +0000)
The API for PTP system timestamping (associating a SPI transaction with
the system time at which it was transferred) is flawed: it assumes that
the xfer->tx_buf pointer will always be present.

This is, of course, not always the case.

So introduce a "progress" variable that denotes how many word have been
transferred.

Fix the Freescale DSPI driver, the only user of the API so far, in the
same patch.

Fixes: b42faeee718c ("spi: Add a PTP system timestamp to the transfer structure")
Fixes: d6b71dfaeeba ("spi: spi-fsl-dspi: Implement the PTP system timestamping for TCFQ mode")
Signed-off-by: Vladimir Oltean <olteanv@gmail.com>
Link: https://lore.kernel.org/r/20191227012417.1057-1-olteanv@gmail.com
Signed-off-by: Mark Brown <broonie@kernel.org>
drivers/spi/spi-fsl-dspi.c
drivers/spi/spi.c
include/linux/spi/spi.h

index 442cff7..9c3934e 100644 (file)
@@ -185,6 +185,7 @@ struct fsl_dspi {
        struct spi_transfer                     *cur_transfer;
        struct spi_message                      *cur_msg;
        struct chip_data                        *cur_chip;
+       size_t                                  progress;
        size_t                                  len;
        const void                              *tx;
        void                                    *rx;
@@ -658,7 +659,7 @@ static int dspi_rxtx(struct fsl_dspi *dspi)
        u32 spi_tcr;
 
        spi_take_timestamp_post(dspi->ctlr, dspi->cur_transfer,
-                               dspi->tx - dspi->bytes_per_word, !dspi->irq);
+                               dspi->progress, !dspi->irq);
 
        /* Get transfer counter (in number of SPI transfers). It was
         * reset to 0 when transfer(s) were started.
@@ -667,6 +668,7 @@ static int dspi_rxtx(struct fsl_dspi *dspi)
        spi_tcnt = SPI_TCR_GET_TCNT(spi_tcr);
        /* Update total number of bytes that were transferred */
        msg->actual_length += spi_tcnt * dspi->bytes_per_word;
+       dspi->progress += spi_tcnt;
 
        trans_mode = dspi->devtype_data->trans_mode;
        if (trans_mode == DSPI_EOQ_MODE)
@@ -679,7 +681,7 @@ static int dspi_rxtx(struct fsl_dspi *dspi)
                return 0;
 
        spi_take_timestamp_pre(dspi->ctlr, dspi->cur_transfer,
-                              dspi->tx, !dspi->irq);
+                              dspi->progress, !dspi->irq);
 
        if (trans_mode == DSPI_EOQ_MODE)
                dspi_eoq_write(dspi);
@@ -768,6 +770,7 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr,
                dspi->rx = transfer->rx_buf;
                dspi->rx_end = dspi->rx + transfer->len;
                dspi->len = transfer->len;
+               dspi->progress = 0;
                /* Validated transfer specific frame size (defaults applied) */
                dspi->bits_per_word = transfer->bits_per_word;
                if (transfer->bits_per_word <= 8)
@@ -789,7 +792,7 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr,
                                     SPI_CTARE_DTCP(1));
 
                spi_take_timestamp_pre(dspi->ctlr, dspi->cur_transfer,
-                                      dspi->tx, !dspi->irq);
+                                      dspi->progress, !dspi->irq);
 
                trans_mode = dspi->devtype_data->trans_mode;
                switch (trans_mode) {
index 0d40953..6b95cd9 100644 (file)
@@ -1499,8 +1499,7 @@ static void spi_pump_messages(struct kthread_work *work)
  *                         advances its @tx buffer pointer monotonically.
  * @ctlr: Pointer to the spi_controller structure of the driver
  * @xfer: Pointer to the transfer being timestamped
- * @tx: Pointer to the current word within the xfer->tx_buf that the driver is
- *     preparing to transmit right now.
+ * @progress: How many words (not bytes) have been transferred so far
  * @irqs_off: If true, will disable IRQs and preemption for the duration of the
  *           transfer, for less jitter in time measurement. Only compatible
  *           with PIO drivers. If true, must follow up with
@@ -1510,21 +1509,19 @@ static void spi_pump_messages(struct kthread_work *work)
  */
 void spi_take_timestamp_pre(struct spi_controller *ctlr,
                            struct spi_transfer *xfer,
-                           const void *tx, bool irqs_off)
+                           size_t progress, bool irqs_off)
 {
-       u8 bytes_per_word = DIV_ROUND_UP(xfer->bits_per_word, 8);
-
        if (!xfer->ptp_sts)
                return;
 
        if (xfer->timestamped_pre)
                return;
 
-       if (tx < (xfer->tx_buf + xfer->ptp_sts_word_pre * bytes_per_word))
+       if (progress < xfer->ptp_sts_word_pre)
                return;
 
        /* Capture the resolution of the timestamp */
-       xfer->ptp_sts_word_pre = (tx - xfer->tx_buf) / bytes_per_word;
+       xfer->ptp_sts_word_pre = progress;
 
        xfer->timestamped_pre = true;
 
@@ -1546,23 +1543,20 @@ EXPORT_SYMBOL_GPL(spi_take_timestamp_pre);
  *                          timestamped.
  * @ctlr: Pointer to the spi_controller structure of the driver
  * @xfer: Pointer to the transfer being timestamped
- * @tx: Pointer to the current word within the xfer->tx_buf that the driver has
- *     just transmitted.
+ * @progress: How many words (not bytes) have been transferred so far
  * @irqs_off: If true, will re-enable IRQs and preemption for the local CPU.
  */
 void spi_take_timestamp_post(struct spi_controller *ctlr,
                             struct spi_transfer *xfer,
-                            const void *tx, bool irqs_off)
+                            size_t progress, bool irqs_off)
 {
-       u8 bytes_per_word = DIV_ROUND_UP(xfer->bits_per_word, 8);
-
        if (!xfer->ptp_sts)
                return;
 
        if (xfer->timestamped_post)
                return;
 
-       if (tx < (xfer->tx_buf + xfer->ptp_sts_word_post * bytes_per_word))
+       if (progress < xfer->ptp_sts_word_post)
                return;
 
        ptp_read_system_postts(xfer->ptp_sts);
@@ -1573,7 +1567,7 @@ void spi_take_timestamp_post(struct spi_controller *ctlr,
        }
 
        /* Capture the resolution of the timestamp */
-       xfer->ptp_sts_word_post = (tx - xfer->tx_buf) / bytes_per_word;
+       xfer->ptp_sts_word_post = progress;
 
        xfer->timestamped_post = true;
 }
index 98fe866..3a67a7e 100644 (file)
@@ -689,10 +689,10 @@ extern void spi_finalize_current_transfer(struct spi_controller *ctlr);
 /* Helper calls for driver to timestamp transfer */
 void spi_take_timestamp_pre(struct spi_controller *ctlr,
                            struct spi_transfer *xfer,
-                           const void *tx, bool irqs_off);
+                           size_t progress, bool irqs_off);
 void spi_take_timestamp_post(struct spi_controller *ctlr,
                             struct spi_transfer *xfer,
-                            const void *tx, bool irqs_off);
+                            size_t progress, bool irqs_off);
 
 /* the spi driver core manages memory for the spi_controller classdev */
 extern struct spi_controller *__spi_alloc_controller(struct device *host,