spi: Don't look at TX buffer for PTP system timestamping
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:b42faeee71
("spi: Add a PTP system timestamp to the transfer structure") Fixes:d6b71dfaee
("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>
This commit is contained in:
parent
9cd34efbd3
commit
862dd2a946
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user