Linux Sound subsystem development
 help / color / mirror / Atom feed
From: Rodolfo Giometti <giometti@enneenne.com>
To: lakshmi.sowjanya.d@intel.com, tglx@linutronix.de,
	jstultz@google.com, corbet@lwn.net, linux-kernel@vger.kernel.org
Cc: x86@kernel.org, netdev@vger.kernel.org,
	linux-doc@vger.kernel.org, intel-wired-lan@lists.osuosl.org,
	andriy.shevchenko@linux.intel.com, eddie.dong@intel.com,
	christopher.s.hall@intel.com, jesse.brandeburg@intel.com,
	davem@davemloft.net, alexandre.torgue@foss.st.com,
	joabreu@synopsys.com, mcoquelin.stm32@gmail.com, perex@perex.cz,
	linux-sound@vger.kernel.org, anthony.l.nguyen@intel.com,
	peter.hilber@opensynergy.com, pandith.n@intel.com,
	mallikarjunappa.sangannavar@intel.com,
	subramanian.mohan@intel.com, basavaraj.goudar@intel.com,
	thejesh.reddy.t.r@intel.com
Subject: Re: [PATCH v5 09/11] pps: generators: Add PPS Generator TIO Driver
Date: Wed, 20 Mar 2024 17:17:49 +0100	[thread overview]
Message-ID: <27762fd2-123c-4286-904c-7ecaa748e9ff@enneenne.com> (raw)
In-Reply-To: <20240319130547.4195-10-lakshmi.sowjanya.d@intel.com>

On 19/03/24 14:05, lakshmi.sowjanya.d@intel.com wrote:
> From: Lakshmi Sowjanya D <lakshmi.sowjanya.d@intel.com>
> 
> The Intel Timed IO PPS generator driver outputs a PPS signal using
> dedicated hardware that is more accurate than software actuated PPS.
> The Timed IO hardware generates output events using the ART timer.
> The ART timer period varies based on platform type, but is less than 100
> nanoseconds for all current platforms. Timed IO output accuracy is
> within 1 ART period.
> 
> PPS output is enabled by writing '1' the 'enable' sysfs attribute. The
> driver uses hrtimers to schedule a wake-up 10 ms before each event
> (edge) target time. At wakeup, the driver converts the target time in
> terms of CLOCK_REALTIME to ART trigger time and writes this to the Timed
> IO hardware. The Timed IO hardware generates an event precisely at the
> requested system time without software involvement.
> 
> Co-developed-by: Christopher Hall <christopher.s.hall@intel.com>
> Signed-off-by: Christopher Hall <christopher.s.hall@intel.com>
> Co-developed-by: Pandith N <pandith.n@intel.com>
> Signed-off-by: Pandith N <pandith.n@intel.com>
> Co-developed-by: Thejesh Reddy T R <thejesh.reddy.t.r@intel.com>
> Signed-off-by: Thejesh Reddy T R <thejesh.reddy.t.r@intel.com>
> Signed-off-by: Lakshmi Sowjanya D <lakshmi.sowjanya.d@intel.com>
> Reviewed-by: Eddie Dong <eddie.dong@intel.com>
> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>

Acked-by: Rodolfo Giometti <giometti@enneenne.com>

> ---
>   drivers/pps/generators/Kconfig       |  16 ++
>   drivers/pps/generators/Makefile      |   1 +
>   drivers/pps/generators/pps_gen_tio.c | 245 +++++++++++++++++++++++++++
>   3 files changed, 262 insertions(+)
>   create mode 100644 drivers/pps/generators/pps_gen_tio.c
> 
> diff --git a/drivers/pps/generators/Kconfig b/drivers/pps/generators/Kconfig
> index d615e640fcad..0f090932336f 100644
> --- a/drivers/pps/generators/Kconfig
> +++ b/drivers/pps/generators/Kconfig
> @@ -12,3 +12,19 @@ config PPS_GENERATOR_PARPORT
>   	  If you say yes here you get support for a PPS signal generator which
>   	  utilizes STROBE pin of a parallel port to send PPS signals. It uses
>   	  parport abstraction layer and hrtimers to precisely control the signal.
> +
> +config PPS_GENERATOR_TIO
> +	tristate "TIO PPS signal generator"
> +	depends on X86 && CPU_SUP_INTEL
> +	help
> +	  If you say yes here you get support for a PPS TIO signal generator
> +	  which generates a pulse at a prescribed time based on the system clock.
> +	  It uses time translation and hrtimers to precisely generate a pulse.
> +	  This hardware is present on 2019 and newer Intel CPUs. However, this
> +	  driver is not useful without adding highly specialized hardware outside
> +	  the Linux system to observe these pulses.
> +
> +	  To compile this driver as a module, choose M here: the module
> +	  will be called pps_gen_tio.
> +
> +	  If unsure, say N.
> diff --git a/drivers/pps/generators/Makefile b/drivers/pps/generators/Makefile
> index 2d56dd0495d5..07004cfd3996 100644
> --- a/drivers/pps/generators/Makefile
> +++ b/drivers/pps/generators/Makefile
> @@ -4,6 +4,7 @@
>   #
>   
>   obj-$(CONFIG_PPS_GENERATOR_PARPORT) += pps_gen_parport.o
> +obj-$(CONFIG_PPS_GENERATOR_TIO) += pps_gen_tio.o
>   
>   ifeq ($(CONFIG_PPS_DEBUG),y)
>   EXTRA_CFLAGS += -DDEBUG
> diff --git a/drivers/pps/generators/pps_gen_tio.c b/drivers/pps/generators/pps_gen_tio.c
> new file mode 100644
> index 000000000000..3ee271524482
> --- /dev/null
> +++ b/drivers/pps/generators/pps_gen_tio.c
> @@ -0,0 +1,245 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Intel PPS signal Generator Driver
> + *
> + * Copyright (C) 2023 Intel Corporation
> + */
> +
> +#include <linux/bits.h>
> +#include <linux/bitfield.h>
> +#include <linux/cleanup.h>
> +#include <linux/container_of.h>
> +#include <linux/cpu.h>
> +#include <linux/device.h>
> +#include <linux/err.h>
> +#include <linux/hrtimer.h>
> +#include <linux/io-64-nonatomic-hi-lo.h>
> +#include <linux/kstrtox.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/spinlock.h>
> +#include <linux/sysfs.h>
> +#include <linux/timekeeping.h>
> +#include <linux/types.h>
> +
> +#include <asm/cpu_device_id.h>
> +
> +#define TIOCTL			0x00
> +#define TIOCOMPV		0x10
> +
> +/* Control Register */
> +#define TIOCTL_EN			BIT(0)
> +#define TIOCTL_DIR			BIT(1)
> +#define TIOCTL_EP			GENMASK(3, 2)
> +#define TIOCTL_EP_RISING_EDGE		FIELD_PREP(TIOCTL_EP, 0)
> +#define TIOCTL_EP_FALLING_EDGE		FIELD_PREP(TIOCTL_EP, 1)
> +#define TIOCTL_EP_TOGGLE_EDGE		FIELD_PREP(TIOCTL_EP, 2)
> +
> +#define SAFE_TIME_NS			(10 * NSEC_PER_MSEC) /* Safety time to set hrtimer early */
> +#define MAGIC_CONST			(NSEC_PER_SEC - SAFE_TIME_NS)
> +#define ART_HW_DELAY_CYCLES		2
> +
> +struct pps_tio {
> +	struct hrtimer timer;
> +	struct device *dev;
> +	spinlock_t lock;
> +	struct attribute_group attrs;
> +	void __iomem *base;
> +	bool enabled;
> +};
> +
> +static inline u32 pps_ctl_read(struct pps_tio *tio)
> +{
> +	return readl(tio->base + TIOCTL);
> +}
> +
> +static inline void pps_ctl_write(struct pps_tio *tio, u32 value)
> +{
> +	writel(value, tio->base + TIOCTL);
> +}
> +
> +/* For COMPV register, It's safer to write higher 32-bit followed by lower 32-bit */
> +static inline void pps_compv_write(struct pps_tio *tio, u64 value)
> +{
> +	hi_lo_writeq(value, tio->base + TIOCOMPV);
> +}
> +
> +static inline ktime_t first_event(struct pps_tio *tio)
> +{
> +	return ktime_set(ktime_get_real_seconds() + 1, MAGIC_CONST);
> +}
> +
> +static u32 pps_tio_disable(struct pps_tio *tio)
> +{
> +	u32 ctrl;
> +
> +	ctrl = pps_ctl_read(tio);
> +	pps_compv_write(tio, 0);
> +
> +	ctrl &= ~TIOCTL_EN;
> +	pps_ctl_write(tio, ctrl);
> +
> +	return ctrl;
> +}
> +
> +static void pps_tio_direction_output(struct pps_tio *tio)
> +{
> +	u32 ctrl;
> +
> +	ctrl = pps_tio_disable(tio);
> +
> +	/* We enable the device, be sure that the 'compare' value is invalid */
> +	pps_compv_write(tio, 0);
> +
> +	ctrl &= ~(TIOCTL_DIR | TIOCTL_EP);
> +	ctrl |= TIOCTL_EP_TOGGLE_EDGE;
> +	pps_ctl_write(tio, ctrl);
> +
> +	ctrl |= TIOCTL_EN;
> +	pps_ctl_write(tio, ctrl);
> +}
> +
> +static bool pps_generate_next_pulse(struct pps_tio *tio, ktime_t expires)
> +{
> +	u64 art;
> +
> +	if (!ktime_real_to_base_clock(expires, CSID_X86_ART, &art)) {
> +		pps_tio_disable(tio);
> +		return false;
> +	}
> +
> +	pps_compv_write(tio, art - ART_HW_DELAY_CYCLES);
> +	return true;
> +}
> +
> +static enum hrtimer_restart hrtimer_callback(struct hrtimer *timer)
> +{
> +	struct pps_tio *tio = container_of(timer, struct pps_tio, timer);
> +	ktime_t expires, now;
> +
> +	guard(spinlock)(&tio->lock);
> +
> +	expires = hrtimer_get_expires(timer);
> +	now = ktime_get_real();
> +
> +	if (now - expires < SAFE_TIME_NS) {
> +		if (!pps_generate_next_pulse(tio, expires + SAFE_TIME_NS))
> +			return HRTIMER_NORESTART;
> +	}
> +
> +	hrtimer_forward(timer, now, NSEC_PER_SEC / 2);
> +	return HRTIMER_RESTART;
> +}
> +
> +static ssize_t enable_store(struct device *dev, struct device_attribute *attr, const char *buf,
> +			    size_t count)
> +{
> +	struct pps_tio *tio = dev_get_drvdata(dev);
> +	bool enable;
> +	int err;
> +
> +	err = kstrtobool(buf, &enable);
> +	if (err)
> +		return err;
> +
> +	guard(spinlock_irqsave)(&tio->lock);
> +	if (enable && !tio->enabled) {
> +		if (!timekeeping_clocksource_has_base(CSID_X86_ART)) {
> +			dev_err(tio->dev, "PPS cannot be started as clock is not related to ART");
> +			return -EPERM;
> +		}
> +		pps_tio_direction_output(tio);
> +		hrtimer_start(&tio->timer, first_event(tio), HRTIMER_MODE_ABS);
> +		tio->enabled = true;
> +	} else if (!enable && tio->enabled) {
> +		hrtimer_cancel(&tio->timer);
> +		pps_tio_disable(tio);
> +		tio->enabled = false;
> +	}
> +	return count;
> +}
> +
> +static ssize_t enable_show(struct device *dev, struct device_attribute *devattr, char *buf)
> +{
> +	struct pps_tio *tio = dev_get_drvdata(dev);
> +	u32 ctrl;
> +
> +	ctrl = pps_ctl_read(tio);
> +	ctrl &= TIOCTL_EN;
> +
> +	return sysfs_emit(buf, "%u\n", ctrl);
> +}
> +static DEVICE_ATTR_RW(enable);
> +
> +static struct attribute *pps_tio_attrs[] = {
> +	&dev_attr_enable.attr,
> +	NULL
> +};
> +ATTRIBUTE_GROUPS(pps_tio);
> +
> +static int pps_tio_probe(struct platform_device *pdev)
> +{
> +	struct pps_tio *tio;
> +
> +	if (!(cpu_feature_enabled(X86_FEATURE_TSC_KNOWN_FREQ) &&
> +	      cpu_feature_enabled(X86_FEATURE_ART))) {
> +		dev_warn(&pdev->dev, "TSC/ART is not enabled");
> +		return -ENODEV;
> +	}
> +
> +	tio = devm_kzalloc(&pdev->dev, sizeof(*tio), GFP_KERNEL);
> +	if (!tio)
> +		return -ENOMEM;
> +
> +	tio->dev = &pdev->dev;
> +	tio->base = devm_platform_ioremap_resource(pdev, 0);
> +	if (IS_ERR(tio->base))
> +		return PTR_ERR(tio->base);
> +
> +	pps_tio_disable(tio);
> +	hrtimer_init(&tio->timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
> +	tio->timer.function = hrtimer_callback;
> +	spin_lock_init(&tio->lock);
> +	tio->enabled = false;
> +	platform_set_drvdata(pdev, tio);
> +
> +	return 0;
> +}
> +
> +static int pps_tio_remove(struct platform_device *pdev)
> +{
> +	struct pps_tio *tio = platform_get_drvdata(pdev);
> +
> +	hrtimer_cancel(&tio->timer);
> +	pps_tio_disable(tio);
> +
> +	return 0;
> +}
> +
> +static const struct acpi_device_id intel_pmc_tio_acpi_match[] = {
> +	{ "INTC1021" },
> +	{ "INTC1022" },
> +	{ "INTC1023" },
> +	{ "INTC1024" },
> +	{}
> +};
> +MODULE_DEVICE_TABLE(acpi, intel_pmc_tio_acpi_match);
> +
> +static struct platform_driver pps_tio_driver = {
> +	.probe          = pps_tio_probe,
> +	.remove         = pps_tio_remove,
> +	.driver         = {
> +		.name                   = "intel-pps-generator",
> +		.acpi_match_table       = intel_pmc_tio_acpi_match,
> +		.dev_groups             = pps_tio_groups,
> +	},
> +};
> +module_platform_driver(pps_tio_driver);
> +
> +MODULE_AUTHOR("Lakshmi Sowjanya D <lakshmi.sowjanya.d@intel.com>");
> +MODULE_AUTHOR("Christopher Hall <christopher.s.hall@intel.com>");
> +MODULE_AUTHOR("Pandith N <pandith.n@intel.com>");
> +MODULE_AUTHOR("Thejesh Reddy T R <thejesh.reddy.t.r@intel.com>");
> +MODULE_DESCRIPTION("Intel PMC Time-Aware IO Generator Driver");
> +MODULE_LICENSE("GPL");

-- 
GNU/Linux Solutions                  e-mail: giometti@enneenne.com
Linux Device Driver                          giometti@linux.it
Embedded Systems                     phone:  +39 349 2432127
UNIX programming


  reply	other threads:[~2024-03-20 16:21 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-03-19 13:05 [PATCH v5 00/11] Add support for Intel PPS Generator lakshmi.sowjanya.d
2024-03-19 13:05 ` [PATCH v5 01/11] x86/tsc: Add base clock properties in clocksource structure lakshmi.sowjanya.d
2024-03-20 11:23   ` Thomas Gleixner
2024-03-20 11:30     ` Thomas Gleixner
2024-03-19 13:05 ` [PATCH v5 02/11] timekeeping: Add function to convert realtime to base clock lakshmi.sowjanya.d
2024-03-19 22:29   ` John Stultz
2024-03-20 11:29   ` Thomas Gleixner
2024-03-21 14:53   ` Thomas Gleixner
2024-04-01 13:07     ` D, Lakshmi Sowjanya
2024-03-19 13:05 ` [PATCH v5 03/11] e1000e: remove convert_art_to_tsc() lakshmi.sowjanya.d
2024-03-19 13:05 ` [PATCH v5 04/11] igc: " lakshmi.sowjanya.d
2024-03-19 13:05 ` [PATCH v5 05/11] stmmac: intel: " lakshmi.sowjanya.d
2024-03-19 13:05 ` [PATCH v5 06/11] ALSA: hda: " lakshmi.sowjanya.d
2024-03-19 13:05 ` [PATCH v5 07/11] ice/ptp: " lakshmi.sowjanya.d
2024-03-19 13:05 ` [PATCH v5 08/11] x86/tsc: Remove art to tsc conversion functions which are obsolete lakshmi.sowjanya.d
2024-03-19 13:05 ` [PATCH v5 09/11] pps: generators: Add PPS Generator TIO Driver lakshmi.sowjanya.d
2024-03-20 16:17   ` Rodolfo Giometti [this message]
2024-03-19 13:05 ` [PATCH v5 10/11] Documentation: driver-api: pps: Add Intel Timed I/O PPS generator lakshmi.sowjanya.d
2024-03-20 16:18   ` Rodolfo Giometti
2024-03-19 13:05 ` [PATCH v5 11/11] ABI: pps: Add ABI documentation for Intel TIO lakshmi.sowjanya.d
2024-03-20 16:09   ` Simon Horman
2024-03-19 22:48 ` [Intel-wired-lan] [PATCH v5 00/11] Add support for Intel PPS Generator Paul Menzel

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=27762fd2-123c-4286-904c-7ecaa748e9ff@enneenne.com \
    --to=giometti@enneenne.com \
    --cc=alexandre.torgue@foss.st.com \
    --cc=andriy.shevchenko@linux.intel.com \
    --cc=anthony.l.nguyen@intel.com \
    --cc=basavaraj.goudar@intel.com \
    --cc=christopher.s.hall@intel.com \
    --cc=corbet@lwn.net \
    --cc=davem@davemloft.net \
    --cc=eddie.dong@intel.com \
    --cc=intel-wired-lan@lists.osuosl.org \
    --cc=jesse.brandeburg@intel.com \
    --cc=joabreu@synopsys.com \
    --cc=jstultz@google.com \
    --cc=lakshmi.sowjanya.d@intel.com \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-sound@vger.kernel.org \
    --cc=mallikarjunappa.sangannavar@intel.com \
    --cc=mcoquelin.stm32@gmail.com \
    --cc=netdev@vger.kernel.org \
    --cc=pandith.n@intel.com \
    --cc=perex@perex.cz \
    --cc=peter.hilber@opensynergy.com \
    --cc=subramanian.mohan@intel.com \
    --cc=tglx@linutronix.de \
    --cc=thejesh.reddy.t.r@intel.com \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox