mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-26 22:24:09 +08:00
spi: Add a PTP API
For detailed timestamping of operations. -----BEGIN PGP SIGNATURE----- iQFHBAABCgAxFiEEreZoqmdXGLWf4p/qJNaLcl1Uh9AFAl2cu5ATHGJyb29uaWVA a2VybmVsLm9yZwAKCRAk1otyXVSH0HYXB/49vT69JJt0wGHR9HOjThnyUHU8s5D2 dJE6lsAbOY8zmGGE5b8yF78fHSA6NrXUWIK6/bNExSfNjwdwrJuVEcxJoi3HtcZA AWxAvpgR55HETiwudEN5ZxUw6FG5O+XAt0Eh7I4Gd+NaMbKrVDfy/cy3J78NK5Cr tDsOamv/nuaCVmoXxthU/u4wQTctBSvbeHMJWUePC/TOMnhxBmNrbsv6kDaQoE2A dWIYjgeUY4s/518Zv//AAhMUsi11N6V3pDyr3MIZJLTh7DDiDgaxx5OUpn6Xgi6Z vSeq7+elh5C9Ta6yg/DQnk8ZPhrHbFdvUiBps8+u1E/tAo6z70YISfcs =P2Sr -----END PGP SIGNATURE----- Merge tag 'spi-ptp-api' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi Pull in a dependency for Vladimir's work on more precise packet time stamping. Mark Brown says: ==================== spi: Add a PTP API For detailed timestamping of operations. ==================== Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
This commit is contained in:
commit
31d7c17e3f
@ -1171,6 +1171,11 @@ static int spi_transfer_one_message(struct spi_controller *ctlr,
|
||||
spi_statistics_add_transfer_stats(statm, xfer, ctlr);
|
||||
spi_statistics_add_transfer_stats(stats, xfer, ctlr);
|
||||
|
||||
if (!ctlr->ptp_sts_supported) {
|
||||
xfer->ptp_sts_word_pre = 0;
|
||||
ptp_read_system_prets(xfer->ptp_sts);
|
||||
}
|
||||
|
||||
if (xfer->tx_buf || xfer->rx_buf) {
|
||||
reinit_completion(&ctlr->xfer_completion);
|
||||
|
||||
@ -1197,6 +1202,11 @@ static int spi_transfer_one_message(struct spi_controller *ctlr,
|
||||
xfer->len);
|
||||
}
|
||||
|
||||
if (!ctlr->ptp_sts_supported) {
|
||||
ptp_read_system_postts(xfer->ptp_sts);
|
||||
xfer->ptp_sts_word_post = xfer->len;
|
||||
}
|
||||
|
||||
trace_spi_transfer_stop(msg, xfer);
|
||||
|
||||
if (msg->status != -EINPROGRESS)
|
||||
@ -1265,6 +1275,7 @@ EXPORT_SYMBOL_GPL(spi_finalize_current_transfer);
|
||||
*/
|
||||
static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread)
|
||||
{
|
||||
struct spi_transfer *xfer;
|
||||
struct spi_message *msg;
|
||||
bool was_busy = false;
|
||||
unsigned long flags;
|
||||
@ -1391,6 +1402,13 @@ static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!ctlr->ptp_sts_supported && !ctlr->transfer_one) {
|
||||
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
|
||||
xfer->ptp_sts_word_pre = 0;
|
||||
ptp_read_system_prets(xfer->ptp_sts);
|
||||
}
|
||||
}
|
||||
|
||||
ret = ctlr->transfer_one_message(ctlr, msg);
|
||||
if (ret) {
|
||||
dev_err(&ctlr->dev,
|
||||
@ -1418,6 +1436,99 @@ static void spi_pump_messages(struct kthread_work *work)
|
||||
__spi_pump_messages(ctlr, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* spi_take_timestamp_pre - helper for drivers to collect the beginning of the
|
||||
* TX timestamp for the requested byte from the SPI
|
||||
* transfer. The frequency with which this function
|
||||
* must be called (once per word, once for the whole
|
||||
* transfer, once per batch of words etc) is arbitrary
|
||||
* as long as the @tx buffer offset is greater than or
|
||||
* equal to the requested byte at the time of the
|
||||
* call. The timestamp is only taken once, at the
|
||||
* first such call. It is assumed that the driver
|
||||
* 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.
|
||||
* @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
|
||||
* spi_take_timestamp_post or otherwise system will crash.
|
||||
* WARNING: for fully predictable results, the CPU frequency must
|
||||
* also be under control (governor).
|
||||
*/
|
||||
void spi_take_timestamp_pre(struct spi_controller *ctlr,
|
||||
struct spi_transfer *xfer,
|
||||
const void *tx, 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))
|
||||
return;
|
||||
|
||||
/* Capture the resolution of the timestamp */
|
||||
xfer->ptp_sts_word_pre = (tx - xfer->tx_buf) / bytes_per_word;
|
||||
|
||||
xfer->timestamped_pre = true;
|
||||
|
||||
if (irqs_off) {
|
||||
local_irq_save(ctlr->irq_flags);
|
||||
preempt_disable();
|
||||
}
|
||||
|
||||
ptp_read_system_prets(xfer->ptp_sts);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(spi_take_timestamp_pre);
|
||||
|
||||
/**
|
||||
* spi_take_timestamp_post - helper for drivers to collect the end of the
|
||||
* TX timestamp for the requested byte from the SPI
|
||||
* transfer. Can be called with an arbitrary
|
||||
* frequency: only the first call where @tx exceeds
|
||||
* or is equal to the requested word will be
|
||||
* 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.
|
||||
* @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)
|
||||
{
|
||||
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))
|
||||
return;
|
||||
|
||||
ptp_read_system_postts(xfer->ptp_sts);
|
||||
|
||||
if (irqs_off) {
|
||||
local_irq_restore(ctlr->irq_flags);
|
||||
preempt_enable();
|
||||
}
|
||||
|
||||
/* Capture the resolution of the timestamp */
|
||||
xfer->ptp_sts_word_post = (tx - xfer->tx_buf) / bytes_per_word;
|
||||
|
||||
xfer->timestamped_post = true;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(spi_take_timestamp_post);
|
||||
|
||||
/**
|
||||
* spi_set_thread_rt - set the controller to pump at realtime priority
|
||||
* @ctlr: controller to boost priority of
|
||||
@ -1503,6 +1614,7 @@ EXPORT_SYMBOL_GPL(spi_get_next_queued_message);
|
||||
*/
|
||||
void spi_finalize_current_message(struct spi_controller *ctlr)
|
||||
{
|
||||
struct spi_transfer *xfer;
|
||||
struct spi_message *mesg;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
@ -1511,6 +1623,13 @@ void spi_finalize_current_message(struct spi_controller *ctlr)
|
||||
mesg = ctlr->cur_msg;
|
||||
spin_unlock_irqrestore(&ctlr->queue_lock, flags);
|
||||
|
||||
if (!ctlr->ptp_sts_supported && !ctlr->transfer_one) {
|
||||
list_for_each_entry(xfer, &mesg->transfers, transfer_list) {
|
||||
ptp_read_system_postts(xfer->ptp_sts);
|
||||
xfer->ptp_sts_word_post = xfer->len;
|
||||
}
|
||||
}
|
||||
|
||||
spi_unmap_msg(ctlr, mesg);
|
||||
|
||||
if (ctlr->cur_msg_prepared && ctlr->unprepare_message) {
|
||||
@ -3273,6 +3392,7 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
|
||||
static int __spi_async(struct spi_device *spi, struct spi_message *message)
|
||||
{
|
||||
struct spi_controller *ctlr = spi->controller;
|
||||
struct spi_transfer *xfer;
|
||||
|
||||
/*
|
||||
* Some controllers do not support doing regular SPI transfers. Return
|
||||
@ -3288,6 +3408,13 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message)
|
||||
|
||||
trace_spi_message_submit(message);
|
||||
|
||||
if (!ctlr->ptp_sts_supported) {
|
||||
list_for_each_entry(xfer, &message->transfers, transfer_list) {
|
||||
xfer->ptp_sts_word_pre = 0;
|
||||
ptp_read_system_prets(xfer->ptp_sts);
|
||||
}
|
||||
}
|
||||
|
||||
return ctlr->transfer(spi, message);
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <linux/completion.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/ptp_clock_kernel.h>
|
||||
|
||||
struct dma_chan;
|
||||
struct property_entry;
|
||||
@ -409,6 +410,12 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
|
||||
* @fw_translate_cs: If the boot firmware uses different numbering scheme
|
||||
* what Linux expects, this optional hook can be used to translate
|
||||
* between the two.
|
||||
* @ptp_sts_supported: If the driver sets this to true, it must provide a
|
||||
* time snapshot in @spi_transfer->ptp_sts as close as possible to the
|
||||
* moment in time when @spi_transfer->ptp_sts_word_pre and
|
||||
* @spi_transfer->ptp_sts_word_post were transmitted.
|
||||
* If the driver does not set this, the SPI core takes the snapshot as
|
||||
* close to the driver hand-over as possible.
|
||||
*
|
||||
* Each SPI controller can communicate with one or more @spi_device
|
||||
* children. These make a small bus, sharing MOSI, MISO and SCK signals
|
||||
@ -604,6 +611,15 @@ struct spi_controller {
|
||||
void *dummy_tx;
|
||||
|
||||
int (*fw_translate_cs)(struct spi_controller *ctlr, unsigned cs);
|
||||
|
||||
/*
|
||||
* Driver sets this field to indicate it is able to snapshot SPI
|
||||
* transfers (needed e.g. for reading the time of POSIX clocks)
|
||||
*/
|
||||
bool ptp_sts_supported;
|
||||
|
||||
/* Interrupt enable state during PTP system timestamping */
|
||||
unsigned long irq_flags;
|
||||
};
|
||||
|
||||
static inline void *spi_controller_get_devdata(struct spi_controller *ctlr)
|
||||
@ -644,6 +660,14 @@ extern struct spi_message *spi_get_next_queued_message(struct spi_controller *ct
|
||||
extern void spi_finalize_current_message(struct spi_controller *ctlr);
|
||||
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);
|
||||
void spi_take_timestamp_post(struct spi_controller *ctlr,
|
||||
struct spi_transfer *xfer,
|
||||
const void *tx, bool irqs_off);
|
||||
|
||||
/* the spi driver core manages memory for the spi_controller classdev */
|
||||
extern struct spi_controller *__spi_alloc_controller(struct device *host,
|
||||
unsigned int size, bool slave);
|
||||
@ -753,6 +777,35 @@ extern void spi_res_release(struct spi_controller *ctlr,
|
||||
* @transfer_list: transfers are sequenced through @spi_message.transfers
|
||||
* @tx_sg: Scatterlist for transmit, currently not for client use
|
||||
* @rx_sg: Scatterlist for receive, currently not for client use
|
||||
* @ptp_sts_word_pre: The word (subject to bits_per_word semantics) offset
|
||||
* within @tx_buf for which the SPI device is requesting that the time
|
||||
* snapshot for this transfer begins. Upon completing the SPI transfer,
|
||||
* this value may have changed compared to what was requested, depending
|
||||
* on the available snapshotting resolution (DMA transfer,
|
||||
* @ptp_sts_supported is false, etc).
|
||||
* @ptp_sts_word_post: See @ptp_sts_word_post. The two can be equal (meaning
|
||||
* that a single byte should be snapshotted).
|
||||
* If the core takes care of the timestamp (if @ptp_sts_supported is false
|
||||
* for this controller), it will set @ptp_sts_word_pre to 0, and
|
||||
* @ptp_sts_word_post to the length of the transfer. This is done
|
||||
* purposefully (instead of setting to spi_transfer->len - 1) to denote
|
||||
* that a transfer-level snapshot taken from within the driver may still
|
||||
* be of higher quality.
|
||||
* @ptp_sts: Pointer to a memory location held by the SPI slave device where a
|
||||
* PTP system timestamp structure may lie. If drivers use PIO or their
|
||||
* hardware has some sort of assist for retrieving exact transfer timing,
|
||||
* they can (and should) assert @ptp_sts_supported and populate this
|
||||
* structure using the ptp_read_system_*ts helper functions.
|
||||
* The timestamp must represent the time at which the SPI slave device has
|
||||
* processed the word, i.e. the "pre" timestamp should be taken before
|
||||
* transmitting the "pre" word, and the "post" timestamp after receiving
|
||||
* transmit confirmation from the controller for the "post" word.
|
||||
* @timestamped_pre: Set by the SPI controller driver to denote it has acted
|
||||
* upon the @ptp_sts request. Not set when the SPI core has taken care of
|
||||
* the task. SPI device drivers are free to print a warning if this comes
|
||||
* back unset and they need the better resolution.
|
||||
* @timestamped_post: See above. The reason why both exist is that these
|
||||
* booleans are also used to keep state in the core SPI logic.
|
||||
*
|
||||
* SPI transfers always write the same number of bytes as they read.
|
||||
* Protocol drivers should always provide @rx_buf and/or @tx_buf.
|
||||
@ -842,6 +895,14 @@ struct spi_transfer {
|
||||
|
||||
u32 effective_speed_hz;
|
||||
|
||||
unsigned int ptp_sts_word_pre;
|
||||
unsigned int ptp_sts_word_post;
|
||||
|
||||
struct ptp_system_timestamp *ptp_sts;
|
||||
|
||||
bool timestamped_pre;
|
||||
bool timestamped_post;
|
||||
|
||||
struct list_head transfer_list;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user