diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2022-06-05 09:12:28 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2022-06-05 09:12:28 -0700 |
commit | 2981436374177f78539b026ce5bcbab8c251818e (patch) | |
tree | d9d7c4854d4461bec86ca9c0695617a2baeb8e81 /include | |
parent | 71e80720dbf0f08c6979e54f21ddaa5735ce742d (diff) | |
parent | 5dad4eccd2b4316a84209603a28d34c6346392bb (diff) |
Merge tag 'hte/for-5.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux
Pull hardware timestamping subsystem from Thierry Reding:
"This contains the new HTE (hardware timestamping engine) subsystem
that has been in the works for a couple of months now.
The infrastructure provided allows for drivers to register as hardware
timestamp providers, while consumers will be able to request events
that they are interested in (such as GPIOs and IRQs) to be timestamped
by the hardware providers.
Note that this currently supports only one provider, but there seems
to be enough interest in this functionality and we expect to see more
drivers added once this is merged"
[ Linus Walleij mentions the Intel PMC in the Elkhart and Tiger Lake
platforms as another future timestamp provider ]
* tag 'hte/for-5.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux:
dt-bindings: timestamp: Correct id path
dt-bindings: Renamed hte directory to timestamp
hte: Uninitialized variable in hte_ts_get()
hte: Fix off by one in hte_push_ts_ns()
hte: Fix possible use-after-free in tegra_hte_test_remove()
hte: Remove unused including <linux/version.h>
MAINTAINERS: Add HTE Subsystem
hte: Add Tegra HTE test driver
tools: gpio: Add new hardware clock type
gpiolib: cdev: Add hardware timestamp clock type
gpio: tegra186: Add HTE support
gpiolib: Add HTE support
dt-bindings: Add HTE bindings
hte: Add Tegra194 HTE kernel provider
drivers: Add hardware timestamp engine (HTE) subsystem
Documentation: Add HTE subsystem guide
Diffstat (limited to 'include')
-rw-r--r-- | include/linux/gpio/consumer.h | 16 | ||||
-rw-r--r-- | include/linux/gpio/driver.h | 10 | ||||
-rw-r--r-- | include/linux/hte.h | 271 | ||||
-rw-r--r-- | include/uapi/linux/gpio.h | 3 |
4 files changed, 298 insertions, 2 deletions
diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h index e71f6e1bfafe..fe0f460d9a3b 100644 --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h @@ -109,6 +109,8 @@ int gpiod_get_direction(struct gpio_desc *desc); int gpiod_direction_input(struct gpio_desc *desc); int gpiod_direction_output(struct gpio_desc *desc, int value); int gpiod_direction_output_raw(struct gpio_desc *desc, int value); +int gpiod_enable_hw_timestamp_ns(struct gpio_desc *desc, unsigned long flags); +int gpiod_disable_hw_timestamp_ns(struct gpio_desc *desc, unsigned long flags); /* Value get/set from non-sleeping context */ int gpiod_get_value(const struct gpio_desc *desc); @@ -350,8 +352,18 @@ static inline int gpiod_direction_output_raw(struct gpio_desc *desc, int value) WARN_ON(desc); return -ENOSYS; } - - +static inline int gpiod_enable_hw_timestamp_ns(struct gpio_desc *desc, + unsigned long flags) +{ + WARN_ON(desc); + return -ENOSYS; +} +static inline int gpiod_disable_hw_timestamp_ns(struct gpio_desc *desc, + unsigned long flags) +{ + WARN_ON(desc); + return -ENOSYS; +} static inline int gpiod_get_value(const struct gpio_desc *desc) { /* GPIO can never have been requested */ diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 654184cdb719..b1e0f1f8ee2e 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -333,6 +333,10 @@ struct gpio_irq_chip { * @add_pin_ranges: optional routine to initialize pin ranges, to be used when * requires special mapping of the pins that provides GPIO functionality. * It is called after adding GPIO chip and before adding IRQ chip. + * @en_hw_timestamp: Dependent on GPIO chip, an optional routine to + * enable hardware timestamp. + * @dis_hw_timestamp: Dependent on GPIO chip, an optional routine to + * disable hardware timestamp. * @base: identifies the first GPIO number handled by this chip; * or, if negative during registration, requests dynamic ID allocation. * DEPRECATION: providing anything non-negative and nailing the base @@ -429,6 +433,12 @@ struct gpio_chip { int (*add_pin_ranges)(struct gpio_chip *gc); + int (*en_hw_timestamp)(struct gpio_chip *gc, + u32 offset, + unsigned long flags); + int (*dis_hw_timestamp)(struct gpio_chip *gc, + u32 offset, + unsigned long flags); int base; u16 ngpio; u16 offset; diff --git a/include/linux/hte.h b/include/linux/hte.h new file mode 100644 index 000000000000..8289055061ab --- /dev/null +++ b/include/linux/hte.h @@ -0,0 +1,271 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __LINUX_HTE_H +#define __LINUX_HTE_H + +#include <linux/errno.h> + +struct hte_chip; +struct hte_device; +struct of_phandle_args; + +/** + * enum hte_edge - HTE line edge flags. + * + * @HTE_EDGE_NO_SETUP: No edge setup. In this case consumer will setup edges, + * for example during request irq call. + * @HTE_RISING_EDGE_TS: Rising edge. + * @HTE_FALLING_EDGE_TS: Falling edge. + * + */ +enum hte_edge { + HTE_EDGE_NO_SETUP = 1U << 0, + HTE_RISING_EDGE_TS = 1U << 1, + HTE_FALLING_EDGE_TS = 1U << 2, +}; + +/** + * enum hte_return - HTE subsystem return values used during callback. + * + * @HTE_CB_HANDLED: The consumer handled the data. + * @HTE_RUN_SECOND_CB: The consumer needs further processing, in that case + * HTE subsystem calls secondary callback provided by the consumer where it + * is allowed to sleep. + */ +enum hte_return { + HTE_CB_HANDLED, + HTE_RUN_SECOND_CB, +}; + +/** + * struct hte_ts_data - HTE timestamp data. + * + * @tsc: Timestamp value. + * @seq: Sequence counter of the timestamps. + * @raw_level: Level of the line at the timestamp if provider supports it, + * -1 otherwise. + */ +struct hte_ts_data { + u64 tsc; + u64 seq; + int raw_level; +}; + +/** + * struct hte_clk_info - Clock source info that HTE provider uses to timestamp. + * + * @hz: Supported clock rate in HZ, for example 1KHz clock = 1000. + * @type: Supported clock type. + */ +struct hte_clk_info { + u64 hz; + clockid_t type; +}; + +/** + * typedef hte_ts_cb_t - HTE timestamp data processing primary callback. + * + * The callback is used to push timestamp data to the client and it is + * not allowed to sleep. + * + * @ts: HW timestamp data. + * @data: Client supplied data. + */ +typedef enum hte_return (*hte_ts_cb_t)(struct hte_ts_data *ts, void *data); + +/** + * typedef hte_ts_sec_cb_t - HTE timestamp data processing secondary callback. + * + * This is used when the client needs further processing where it is + * allowed to sleep. + * + * @data: Client supplied data. + * + */ +typedef enum hte_return (*hte_ts_sec_cb_t)(void *data); + +/** + * struct hte_line_attr - Line attributes. + * + * @line_id: The logical ID understood by the consumers and providers. + * @line_data: Line data related to line_id. + * @edge_flags: Edge setup flags. + * @name: Descriptive name of the entity that is being monitored for the + * hardware timestamping. If null, HTE core will construct the name. + * + */ +struct hte_line_attr { + u32 line_id; + void *line_data; + unsigned long edge_flags; + const char *name; +}; + +/** + * struct hte_ts_desc - HTE timestamp descriptor. + * + * This structure is a communication token between consumers to subsystem + * and subsystem to providers. + * + * @attr: The line attributes. + * @hte_data: Subsystem's private data, set by HTE subsystem. + */ +struct hte_ts_desc { + struct hte_line_attr attr; + void *hte_data; +}; + +/** + * struct hte_ops - HTE operations set by providers. + * + * @request: Hook for requesting a HTE timestamp. Returns 0 on success, + * non-zero for failures. + * @release: Hook for releasing a HTE timestamp. Returns 0 on success, + * non-zero for failures. + * @enable: Hook to enable the specified timestamp. Returns 0 on success, + * non-zero for failures. + * @disable: Hook to disable specified timestamp. Returns 0 on success, + * non-zero for failures. + * @get_clk_src_info: Hook to get the clock information the provider uses + * to timestamp. Returns 0 for success and negative error code for failure. On + * success HTE subsystem fills up provided struct hte_clk_info. + * + * xlated_id parameter is used to communicate between HTE subsystem and the + * providers and is translated by the provider. + */ +struct hte_ops { + int (*request)(struct hte_chip *chip, struct hte_ts_desc *desc, + u32 xlated_id); + int (*release)(struct hte_chip *chip, struct hte_ts_desc *desc, + u32 xlated_id); + int (*enable)(struct hte_chip *chip, u32 xlated_id); + int (*disable)(struct hte_chip *chip, u32 xlated_id); + int (*get_clk_src_info)(struct hte_chip *chip, + struct hte_clk_info *ci); +}; + +/** + * struct hte_chip - Abstract HTE chip. + * + * @name: functional name of the HTE IP block. + * @dev: device providing the HTE. + * @ops: callbacks for this HTE. + * @nlines: number of lines/signals supported by this chip. + * @xlate_of: Callback which translates consumer supplied logical ids to + * physical ids, return 0 for the success and negative for the failures. + * It stores (between 0 to @nlines) in xlated_id parameter for the success. + * @xlate_plat: Same as above but for the consumers with no DT node. + * @match_from_linedata: Match HTE device using the line_data. + * @of_hte_n_cells: Number of cells used to form the HTE specifier. + * @gdev: HTE subsystem abstract device, internal to the HTE subsystem. + * @data: chip specific private data. + */ +struct hte_chip { + const char *name; + struct device *dev; + const struct hte_ops *ops; + u32 nlines; + int (*xlate_of)(struct hte_chip *gc, + const struct of_phandle_args *args, + struct hte_ts_desc *desc, u32 *xlated_id); + int (*xlate_plat)(struct hte_chip *gc, struct hte_ts_desc *desc, + u32 *xlated_id); + bool (*match_from_linedata)(const struct hte_chip *chip, + const struct hte_ts_desc *hdesc); + u8 of_hte_n_cells; + + struct hte_device *gdev; + void *data; +}; + +#if IS_ENABLED(CONFIG_HTE) +/* HTE APIs for the providers */ +int devm_hte_register_chip(struct hte_chip *chip); +int hte_push_ts_ns(const struct hte_chip *chip, u32 xlated_id, + struct hte_ts_data *data); + +/* HTE APIs for the consumers */ +int hte_init_line_attr(struct hte_ts_desc *desc, u32 line_id, + unsigned long edge_flags, const char *name, + void *data); +int hte_ts_get(struct device *dev, struct hte_ts_desc *desc, int index); +int hte_ts_put(struct hte_ts_desc *desc); +int hte_request_ts_ns(struct hte_ts_desc *desc, hte_ts_cb_t cb, + hte_ts_sec_cb_t tcb, void *data); +int devm_hte_request_ts_ns(struct device *dev, struct hte_ts_desc *desc, + hte_ts_cb_t cb, hte_ts_sec_cb_t tcb, void *data); +int of_hte_req_count(struct device *dev); +int hte_enable_ts(struct hte_ts_desc *desc); +int hte_disable_ts(struct hte_ts_desc *desc); +int hte_get_clk_src_info(const struct hte_ts_desc *desc, + struct hte_clk_info *ci); + +#else /* !CONFIG_HTE */ +static inline int devm_hte_register_chip(struct hte_chip *chip) +{ + return -EOPNOTSUPP; +} + +static inline int hte_push_ts_ns(const struct hte_chip *chip, + u32 xlated_id, + const struct hte_ts_data *data) +{ + return -EOPNOTSUPP; +} + +static inline int hte_init_line_attr(struct hte_ts_desc *desc, u32 line_id, + unsigned long edge_flags, + const char *name, void *data) +{ + return -EOPNOTSUPP; +} + +static inline int hte_ts_get(struct device *dev, struct hte_ts_desc *desc, + int index) +{ + return -EOPNOTSUPP; +} + +static inline int hte_ts_put(struct hte_ts_desc *desc) +{ + return -EOPNOTSUPP; +} + +static inline int hte_request_ts_ns(struct hte_ts_desc *desc, hte_ts_cb_t cb, + hte_ts_sec_cb_t tcb, void *data) +{ + return -EOPNOTSUPP; +} + +static inline int devm_hte_request_ts_ns(struct device *dev, + struct hte_ts_desc *desc, + hte_ts_cb_t cb, + hte_ts_sec_cb_t tcb, + void *data) +{ + return -EOPNOTSUPP; +} + +static inline int of_hte_req_count(struct device *dev) +{ + return -EOPNOTSUPP; +} + +static inline int hte_enable_ts(struct hte_ts_desc *desc) +{ + return -EOPNOTSUPP; +} + +static inline int hte_disable_ts(struct hte_ts_desc *desc) +{ + return -EOPNOTSUPP; +} + +static inline int hte_get_clk_src_info(const struct hte_ts_desc *desc, + struct hte_clk_info *ci) +{ + return -EOPNOTSUPP; +} +#endif /* !CONFIG_HTE */ + +#endif diff --git a/include/uapi/linux/gpio.h b/include/uapi/linux/gpio.h index eaaea3d8e6b4..cb9966d49a16 100644 --- a/include/uapi/linux/gpio.h +++ b/include/uapi/linux/gpio.h @@ -66,6 +66,8 @@ struct gpiochip_info { * @GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN: line has pull-down bias enabled * @GPIO_V2_LINE_FLAG_BIAS_DISABLED: line has bias disabled * @GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME: line events contain REALTIME timestamps + * @GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE: line events contain timestamps from + * hardware timestamp engine */ enum gpio_v2_line_flag { GPIO_V2_LINE_FLAG_USED = _BITULL(0), @@ -80,6 +82,7 @@ enum gpio_v2_line_flag { GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN = _BITULL(9), GPIO_V2_LINE_FLAG_BIAS_DISABLED = _BITULL(10), GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME = _BITULL(11), + GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE = _BITULL(12), }; /** |