nvidia-oot: nvpps: Use HTE driver

Refactor NVPPS driver to use HTE APIs instead of GTE

Bug 3961133

Change-Id: I0a38fb6fd42217515410a610d1900cb036086cf5
Signed-off-by: Gautham Srinivasan <gauthams@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3067331
Reviewed-by: Dipen Patel <dipenp@nvidia.com>
Reviewed-by: Jon Hunter <jonathanh@nvidia.com>
GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
This commit is contained in:
Gautham Srinivasan
2024-01-31 20:44:54 +00:00
committed by mobile promotions
parent cccf65a229
commit 8e5cebeb9e

View File

@@ -1,16 +1,5 @@
/* // SPDX-License-Identifier: GPL-2.0-only
* Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. // SPDX-FileCopyrightText: Copyright (c) 2018-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <nvidia/conftest.h> #include <nvidia/conftest.h>
@@ -31,13 +20,13 @@
#include <linux/time.h> #include <linux/time.h>
#include <linux/version.h> #include <linux/version.h>
#include <uapi/linux/nvpps_ioctl.h> #include <uapi/linux/nvpps_ioctl.h>
#include <linux/tegra-gte.h> #include <linux/hte.h>
#include <linux/nvpps.h> #include <linux/nvpps.h>
/* the following contrl flags are for /* the following control flags are for
* debugging pirpose only * debugging purpose only
*/ */
/* #define NVPPS_ARM_COUNTER_PROFILING */ /* #define NVPPS_ARM_COUNTER_PROFILING */
/* #define NVPPS_EQOS_REG_PROFILING */ /* #define NVPPS_EQOS_REG_PROFILING */
@@ -66,8 +55,7 @@ struct nvpps_device_data {
unsigned int gpio_pin; unsigned int gpio_pin;
int irq; int irq;
bool irq_registered; bool irq_registered;
bool use_gpio_int_timesatmp; bool use_gpio_int_timestamp;
bool pps_event_id_valid; bool pps_event_id_valid;
unsigned int pps_event_id; unsigned int pps_event_id;
u32 actual_evt_mode; u32 actual_evt_mode;
@@ -89,7 +77,6 @@ struct nvpps_device_data {
wait_queue_head_t pps_event_queue; wait_queue_head_t pps_event_queue;
struct fasync_struct *pps_event_async_queue; struct fasync_struct *pps_event_async_queue;
struct tegra_gte_ev_desc *gte_ev_desc;
bool memmap_phc_regs; bool memmap_phc_regs;
char *iface_nm; char *iface_nm;
@@ -105,6 +92,8 @@ struct nvpps_device_data {
bool sec_ptp_failed; bool sec_ptp_failed;
uint8_t k_int_val; uint8_t k_int_val;
uint16_t lock_threshold_val; uint16_t lock_threshold_val;
struct hte_ts_desc desc;
struct gpio_desc *gpio_in;
}; };
@@ -237,56 +226,18 @@ static inline u64 get_systime(struct nvpps_device_data *pdev_data, u64 *tsc)
return ns; return ns;
} }
/* /*
* Report the PPS event * Report the PPS event
*/ */
static void nvpps_get_ts(struct nvpps_device_data *pdev_data, bool in_isr) static void nvpps_get_ts(struct nvpps_device_data *pdev_data, u64 irq_tsc)
{ {
u64 tsc = 0; u64 tsc = 0;
u64 irq_tsc = 0;
u64 phc = 0; u64 phc = 0;
u64 secondary_phc = 0; u64 secondary_phc = 0;
u64 irq_latency = 0; u64 irq_latency = 0;
unsigned long flags; unsigned long flags;
struct ptp_tsc_data ptp_tsc_ts = {0}, sec_ptp_tsc_ts = {0}; struct ptp_tsc_data ptp_tsc_ts = {0}, sec_ptp_tsc_ts = {0};
if (in_isr) {
/* initialize irq_tsc to the current TSC just in case the
* gpio_timestamp_read call failed so the irq_tsc can be
* closer to when the interrupt actually occured
*/
irq_tsc = __arch_counter_get_cntvct();
if (pdev_data->use_gpio_int_timesatmp) {
int err;
int gte_event_found = 0;
int safety = 33; /* GTE driver fifo depth is 32, plus one for margin */
struct tegra_gte_ev_detail hts;
/* 1PPS TSC timestamp is isochronous in nature
* we only need the last event
*/
do {
err = tegra_gte_retrieve_event(pdev_data->gte_ev_desc, &hts);
if (!err) {
irq_tsc = hts.ts_raw;
gte_event_found = 1;
}
/* decrement the count so we don't risk looping
* here forever
*/
safety--;
} while (!err && (safety >= 0));
if (gte_event_found == 0) {
dev_err(pdev_data->dev, "failed to read timestamp data err(%d)\n", err);
}
if (safety < 0) {
dev_err(pdev_data->dev, "tegra_gte_retrieve_event succeed beyond its fifo size err(%d)!)\n", err);
}
}
}
/* get the PTP timestamp */ /* get the PTP timestamp */
if (pdev_data->memmap_phc_regs) { if (pdev_data->memmap_phc_regs) {
/* get both the phc(using memmap reg) and tsc */ /* get both the phc(using memmap reg) and tsc */
@@ -365,7 +316,7 @@ static void nvpps_get_ts(struct nvpps_device_data *pdev_data, bool in_isr)
pdev_data->phc = phc ? phc - irq_latency : phc; pdev_data->phc = phc ? phc - irq_latency : phc;
#endif /* NVPPS_ARM_COUNTER_PROFILING || NVPPS_EQOS_REG_PROFILING */ #endif /* NVPPS_ARM_COUNTER_PROFILING || NVPPS_EQOS_REG_PROFILING */
pdev_data->irq_latency = irq_latency; pdev_data->irq_latency = irq_latency;
pdev_data->actual_evt_mode = in_isr ? NVPPS_MODE_GPIO : NVPPS_MODE_TIMER; pdev_data->actual_evt_mode = irq_tsc ? NVPPS_MODE_GPIO : NVPPS_MODE_TIMER;
/* Re-adjust secondary iface's PTP TS to irq_tsc TS, /* Re-adjust secondary iface's PTP TS to irq_tsc TS,
* irq_latency will be 0 if TIMER mode, >0 if GPIO mode * irq_latency will be 0 if TIMER mode, >0 if GPIO mode
*/ */
@@ -377,18 +328,17 @@ static void nvpps_get_ts(struct nvpps_device_data *pdev_data, bool in_isr)
kill_fasync(&pdev_data->pps_event_async_queue, SIGIO, POLL_IN); kill_fasync(&pdev_data->pps_event_async_queue, SIGIO, POLL_IN);
} }
static irqreturn_t nvpps_gpio_isr(int irq, void *data) static irqreturn_t nvpps_gpio_isr(int irq, void *data)
{ {
struct nvpps_device_data *pdev_data = (struct nvpps_device_data *)data; struct nvpps_device_data *pdev_data = (struct nvpps_device_data *)data;
/* Incase, if an interrupt is generated /* If the current mode is TIMER mode, ignore the interrupt.
* then check current mode in use. Ignore the * If HTE is not enabled, use TSC and process the interrupt.
* interrupt if current mode is TIMER mode * If HTE is enabled, ignore the interrupt and process it in HTE callback
*/ */
if (!pdev_data->timer_inited) { if (!pdev_data->timer_inited) {
/* get timestamps for this event */ if (!(pdev_data->use_gpio_int_timestamp))
nvpps_get_ts(pdev_data, true); nvpps_get_ts(pdev_data, __arch_counter_get_cntvct());
} }
return IRQ_HANDLED; return IRQ_HANDLED;
@@ -438,7 +388,7 @@ static void nvpps_timer_callback(struct timer_list *t)
struct nvpps_device_data *pdev_data = (struct nvpps_device_data *)from_timer(pdev_data, t, timer); struct nvpps_device_data *pdev_data = (struct nvpps_device_data *)from_timer(pdev_data, t, timer);
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0) */ #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0) */
/* get timestamps for this event */ /* get timestamps for this event */
nvpps_get_ts(pdev_data, false); nvpps_get_ts(pdev_data, 0);
/* set the next expire time */ /* set the next expire time */
if (pdev_data->timer_inited) { if (pdev_data->timer_inited) {
@@ -464,6 +414,23 @@ static int set_mode_tsc(struct nvpps_device_data *pdev_data)
return 0; return 0;
} }
/*
* Store hardware timestamp
*/
static enum hte_return process_hw_ts(struct hte_ts_data *ts, void *p)
{
struct nvpps_device_data *pdev_data = (struct nvpps_device_data *)p;
/* If an callback is generated then check
* current mode in use. Ignore the callback
* if current mode is TIMER mode
*/
if (!pdev_data->timer_inited)
nvpps_get_ts(pdev_data, ts->tsc);
return HTE_CB_HANDLED;
}
static int set_mode(struct nvpps_device_data *pdev_data, u32 mode) static int set_mode(struct nvpps_device_data *pdev_data, u32 mode)
{ {
int err = 0; int err = 0;
@@ -645,7 +612,8 @@ static long nvpps_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
time_event.secondary_ptp = pdev_data->secondary_phc; time_event.secondary_ptp = pdev_data->secondary_phc;
time_event.irq_latency = pdev_data->irq_latency; time_event.irq_latency = pdev_data->irq_latency;
raw_spin_unlock_irqrestore(&pdev_data->lock, flags); raw_spin_unlock_irqrestore(&pdev_data->lock, flags);
if (NVPPS_TSC_NSEC == pdev_data->tsc_mode) { if (pdev_data->tsc_mode == NVPPS_TSC_NSEC &&
!pdev_data->use_gpio_int_timestamp) {
time_event.tsc *= pdev_data->tsc_res_ns; time_event.tsc *= pdev_data->tsc_res_ns;
} }
time_event.tsc_res_ns = pdev_data->tsc_res_ns; time_event.tsc_res_ns = pdev_data->tsc_res_ns;
@@ -899,6 +867,64 @@ static void nvpps_fill_default_mac_phc_info(struct platform_device *pdev,
interface_name = devm_kstrdup(&pdev->dev, pdev_data->iface_nm, GFP_KERNEL); interface_name = devm_kstrdup(&pdev->dev, pdev_data->iface_nm, GFP_KERNEL);
} }
static int nvpps_gpio_hte_setup(struct nvpps_device_data *pdev_data)
{
int err;
struct platform_device *pdev = pdev_data->pdev;
pdev_data->use_gpio_int_timestamp = false;
pdev_data->gpio_in = devm_gpiod_get_optional(&pdev->dev, "nvpps", 0);
if (!pdev_data->gpio_in) {
dev_warn(&pdev->dev, "PPS GPIO not provided in DT, only Timer mode available\n");
pdev_data->only_timer_mode = true;
return 0;
}
err = gpiod_direction_input(pdev_data->gpio_in);
if (err < 0) {
dev_err(&pdev->dev, "failed to set pin direction\n");
return err;
}
/* IRQ setup */
err = gpiod_to_irq(pdev_data->gpio_in);
if (err < 0) {
dev_err(&pdev->dev, "failed to map GPIO to IRQ: %d\n", err);
return err;
}
pdev_data->irq = err;
dev_info(&pdev->dev, "gpio_to_irq(%d)\n", pdev_data->irq);
/*
* Setup HTE. Note that HTE support is optional and so if it fails,
* still allow the driver to operate without it.
*/
err = hte_init_line_attr(&pdev_data->desc, 0, 0, NULL, pdev_data->gpio_in);
if (err < 0) {
dev_warn(&pdev->dev, "hte_init_line_attr failed\n");
return 0;
}
err = hte_ts_get(&pdev->dev, &pdev_data->desc, 0);
if (err < 0) {
dev_warn(&pdev->dev, "hte_ts_get failed\n");
return 0;
}
err = devm_hte_request_ts_ns(&pdev->dev, &pdev_data->desc,
process_hw_ts, NULL, pdev_data);
if (err < 0) {
dev_warn(&pdev->dev, "devm_hte_request_ts_ns failed\n");
return 0;
}
pdev_data->use_gpio_int_timestamp = true;
dev_info(&pdev->dev, "HTE request timestamp succeed\n");
return 0;
}
static void nvpps_ptp_tsc_sync_config(struct platform_device *pdev) static void nvpps_ptp_tsc_sync_config(struct platform_device *pdev)
{ {
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.of_node;
@@ -972,7 +998,6 @@ static int nvpps_probe(struct platform_device *pdev)
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.of_node;
dev_t devt; dev_t devt;
int err; int err;
struct device_node *np_gte;
dev_info(&pdev->dev, "%s\n", __FUNCTION__); dev_info(&pdev->dev, "%s\n", __FUNCTION__);
@@ -986,42 +1011,6 @@ static int nvpps_probe(struct platform_device *pdev)
return -ENOMEM; return -ENOMEM;
} }
err = of_get_named_gpio(np, "gpios", 0);
if (err == -EPROBE_DEFER) {
return err;
} else if (err < 0) {
dev_warn(&pdev->dev, "PPS GPIO not provided in DT, only Timer mode available\n");
pdev_data->only_timer_mode = true;
} else {
pdev_data->gpio_pin = (unsigned int)err;
dev_info(&pdev->dev, "gpio_pin(%d)\n", pdev_data->gpio_pin);
/* GPIO setup */
if (gpio_is_valid(pdev_data->gpio_pin)) {
err = devm_gpio_request(&pdev->dev, pdev_data->gpio_pin, "gpio_pps");
if (err) {
dev_err(&pdev->dev, "failed to request GPIO %u\n",
pdev_data->gpio_pin);
return err;
}
err = gpio_direction_input(pdev_data->gpio_pin);
if (err) {
dev_err(&pdev->dev, "failed to set pin direction\n");
return -EINVAL;
}
/* IRQ setup */
err = gpio_to_irq(pdev_data->gpio_pin);
if (err < 0) {
dev_err(&pdev->dev, "failed to map GPIO to IRQ: %d\n", err);
return -EINVAL;
}
pdev_data->irq = err;
dev_info(&pdev->dev, "gpio_to_irq(%d)\n", pdev_data->irq);
}
}
nvpps_fill_default_mac_phc_info(pdev, pdev_data); nvpps_fill_default_mac_phc_info(pdev, pdev_data);
init_waitqueue_head(&pdev_data->pps_event_queue); init_waitqueue_head(&pdev_data->pps_event_queue);
@@ -1035,6 +1024,11 @@ static int nvpps_probe(struct platform_device *pdev)
#undef _PICO_SECS #undef _PICO_SECS
dev_info(&pdev->dev, "tsc_res_ns(%llu)\n", pdev_data->tsc_res_ns); dev_info(&pdev->dev, "tsc_res_ns(%llu)\n", pdev_data->tsc_res_ns);
/* Set up GPIO and HTE */
err = nvpps_gpio_hte_setup(pdev_data);
if (err < 0)
return err;
/* character device setup */ /* character device setup */
#ifndef NVPPS_NO_DT #ifndef NVPPS_NO_DT
#if defined(NV_CLASS_CREATE_HAS_NO_OWNER_ARG) /* Linux v6.4 */ #if defined(NV_CLASS_CREATE_HAS_NO_OWNER_ARG) /* Linux v6.4 */
@@ -1096,24 +1090,6 @@ static int nvpps_probe(struct platform_device *pdev)
dev_info(&pdev->dev, "nvpps cdev(%d:%d)\n", MAJOR(s_nvpps_devt), pdev_data->id); dev_info(&pdev->dev, "nvpps cdev(%d:%d)\n", MAJOR(s_nvpps_devt), pdev_data->id);
platform_set_drvdata(pdev, pdev_data); platform_set_drvdata(pdev, pdev_data);
np_gte = of_find_compatible_node(NULL, NULL, "nvidia,tegra234-gte-aon");
if (!np_gte) {
np_gte = of_find_compatible_node(NULL, NULL, "nvidia,tegra194-gte-aon");
}
if (!np_gte) {
pdev_data->use_gpio_int_timesatmp = false;
dev_err(&pdev->dev, "of_find_compatible_node failed\n");
} else {
pdev_data->gte_ev_desc = tegra_gte_register_event(np_gte, pdev_data->gpio_pin);
if (IS_ERR(pdev_data->gte_ev_desc)) {
pdev_data->use_gpio_int_timesatmp = false;
dev_err(&pdev->dev, "tegra_gte_register_event err = %d\n", (int)PTR_ERR(pdev_data->gte_ev_desc));
} else {
pdev_data->use_gpio_int_timesatmp = true;
dev_info(pdev_data->dev, "tegra_gte_register_event succeed\n");
}
}
/* setup PPS event hndler */ /* setup PPS event hndler */
err = set_mode(pdev_data, err = set_mode(pdev_data,
(pdev_data->only_timer_mode) ? NVPPS_MODE_TIMER : NVPPS_MODE_GPIO); (pdev_data->only_timer_mode) ? NVPPS_MODE_TIMER : NVPPS_MODE_GPIO);
@@ -1173,12 +1149,6 @@ static int nvpps_remove(struct platform_device *pdev)
pdev_data->timer_inited = false; pdev_data->timer_inited = false;
del_timer_sync(&pdev_data->timer); del_timer_sync(&pdev_data->timer);
} }
if (pdev_data->use_gpio_int_timesatmp) {
if (!IS_ERR_OR_NULL(pdev_data->gte_ev_desc)) {
tegra_gte_unregister_event(pdev_data->gte_ev_desc);
}
pdev_data->use_gpio_int_timesatmp = false;
}
if (pdev_data->memmap_phc_regs) { if (pdev_data->memmap_phc_regs) {
devm_iounmap(&pdev->dev, pdev_data->mac_base_addr); devm_iounmap(&pdev->dev, pdev_data->mac_base_addr);
dev_info(&pdev->dev, "unmap MAC reg space %p for nvpps\n", dev_info(&pdev->dev, "unmap MAC reg space %p for nvpps\n",