234 lines
6.6 KiB
C
234 lines
6.6 KiB
C
/*
|
|
* SPDX-FileCopyrightText: Copyright (c) 2020-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
* SPDX-License-Identifier: MIT
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
* DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
|
|
#define __NO_VERSION__
|
|
|
|
#include <linux/kernel.h> // For container_of
|
|
#include <linux/hrtimer.h>
|
|
#include <linux/ktime.h>
|
|
#include <linux/timer.h>
|
|
#include "os-interface.h"
|
|
#include "nv-linux.h"
|
|
|
|
#if !defined(NVCPU_PPC64LE)
|
|
#define NV_NANO_TIMER_USE_HRTIMER 1
|
|
#else
|
|
#define NV_NANO_TIMER_USE_HRTIMER 0
|
|
#endif // !defined(NVCPU_PPC64LE)
|
|
|
|
struct nv_nano_timer
|
|
{
|
|
#if NV_NANO_TIMER_USE_HRTIMER
|
|
struct hrtimer hr_timer; // This parameter holds linux high resolution timer object
|
|
// can get replaced with platform specific timer object
|
|
#else
|
|
struct timer_list jiffy_timer;
|
|
#endif
|
|
nv_linux_state_t *nv_linux_state;
|
|
void (*nv_nano_timer_callback)(struct nv_nano_timer *nv_nstimer);
|
|
void *pTmrEvent;
|
|
};
|
|
|
|
/*!
|
|
* @brief runs nano second resolution timer callback
|
|
*
|
|
* @param[in] nv_nstimer Pointer to nv_nano_timer_t object
|
|
*/
|
|
static void
|
|
nvidia_nano_timer_callback(
|
|
nv_nano_timer_t *nv_nstimer)
|
|
{
|
|
nv_state_t *nv = NULL;
|
|
nv_linux_state_t *nvl = nv_nstimer->nv_linux_state;
|
|
nvidia_stack_t *sp = NULL;
|
|
|
|
if (nv_kmem_cache_alloc_stack(&sp) != 0)
|
|
{
|
|
nv_printf(NV_DBG_ERRORS, "NVRM: no cache memory \n");
|
|
return;
|
|
}
|
|
|
|
nv = NV_STATE_PTR(nvl);
|
|
|
|
if (rm_run_nano_timer_callback(sp, nv, nv_nstimer->pTmrEvent) != NV_OK)
|
|
{
|
|
nv_printf(NV_DBG_ERRORS, "NVRM: Error in service of callback \n");
|
|
}
|
|
|
|
nv_kmem_cache_free_stack(sp);
|
|
}
|
|
|
|
/*!
|
|
* @brief Allocates nano second resolution timer object
|
|
*
|
|
* @returns nv_nano_timer_t allocated pointer
|
|
*/
|
|
static nv_nano_timer_t *nv_alloc_nano_timer(void)
|
|
{
|
|
nv_nano_timer_t *nv_nstimer;
|
|
|
|
NV_KMALLOC(nv_nstimer, sizeof(nv_nano_timer_t));
|
|
|
|
if (nv_nstimer == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
memset(nv_nstimer, 0, sizeof(nv_nano_timer_t));
|
|
|
|
return nv_nstimer;
|
|
}
|
|
|
|
#if NV_NANO_TIMER_USE_HRTIMER
|
|
static enum hrtimer_restart nv_nano_timer_callback_typed_data(struct hrtimer *hrtmr)
|
|
{
|
|
struct nv_nano_timer *nv_nstimer =
|
|
container_of(hrtmr, struct nv_nano_timer, hr_timer);
|
|
|
|
nv_nstimer->nv_nano_timer_callback(nv_nstimer);
|
|
|
|
return HRTIMER_NORESTART;
|
|
}
|
|
#else
|
|
static inline void nv_jiffy_timer_callback_typed_data(struct timer_list *timer)
|
|
{
|
|
struct nv_nano_timer *nv_nstimer =
|
|
container_of(timer, struct nv_nano_timer, jiffy_timer);
|
|
|
|
nv_nstimer->nv_nano_timer_callback(nv_nstimer);
|
|
}
|
|
|
|
static inline void nv_jiffy_timer_callback_anon_data(unsigned long arg)
|
|
{
|
|
struct nv_nano_timer *nv_nstimer = (struct nv_nano_timer *)arg;
|
|
|
|
nv_nstimer->nv_nano_timer_callback(nv_nstimer);
|
|
}
|
|
#endif
|
|
|
|
/*!
|
|
* @brief Creates & initializes nano second resolution timer object
|
|
*
|
|
* @param[in] nv Per gpu linux state
|
|
* @param[in] tmrEvent pointer to TMR_EVENT
|
|
* @param[in] nv_nstimer Pointer to nv_nano_timer_t object
|
|
*/
|
|
void NV_API_CALL nv_create_nano_timer(
|
|
nv_state_t *nv,
|
|
void *pTmrEvent,
|
|
nv_nano_timer_t **pnv_nstimer)
|
|
{
|
|
nv_linux_state_t *nvl = NV_GET_NVL_FROM_NV_STATE(nv);
|
|
nv_nano_timer_t *nv_nstimer = nv_alloc_nano_timer();
|
|
|
|
if (nv_nstimer == NULL)
|
|
{
|
|
nv_printf(NV_DBG_ERRORS, "NVRM: Not able to create timer object \n");
|
|
*pnv_nstimer = NULL;
|
|
return;
|
|
}
|
|
|
|
nv_nstimer->nv_linux_state = nvl;
|
|
nv_nstimer->pTmrEvent = pTmrEvent;
|
|
|
|
nv_nstimer->nv_nano_timer_callback = nvidia_nano_timer_callback;
|
|
|
|
#if NV_NANO_TIMER_USE_HRTIMER
|
|
hrtimer_init(&nv_nstimer->hr_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
|
|
nv_nstimer->hr_timer.function = nv_nano_timer_callback_typed_data;
|
|
#else
|
|
#if defined(NV_TIMER_SETUP_PRESENT)
|
|
timer_setup(&nv_nstimer->jiffy_timer, nv_jiffy_timer_callback_typed_data, 0);
|
|
#else
|
|
init_timer(&nv_nstimer->jiffy_timer);
|
|
nv_nstimer->jiffy_timer.function = nv_jiffy_timer_callback_anon_data;
|
|
nv_nstimer->jiffy_timer.data = (unsigned long)nv_nstimer;
|
|
#endif // NV_TIMER_SETUP_PRESENT
|
|
#endif // NV_NANO_TIMER_USE_HRTIMER
|
|
|
|
*pnv_nstimer = nv_nstimer;
|
|
}
|
|
|
|
/*!
|
|
* @brief Starts nano second resolution timer
|
|
*
|
|
* @param[in] nv Per gpu linux state
|
|
* @param[in] nv_nstimer Pointer to nv_nano_timer_t object
|
|
* @param[in] time_ns Relative time in nano seconds
|
|
*/
|
|
void NV_API_CALL nv_start_nano_timer(
|
|
nv_state_t *nv,
|
|
nv_nano_timer_t *nv_nstimer,
|
|
NvU64 time_ns)
|
|
{
|
|
#if NV_NANO_TIMER_USE_HRTIMER
|
|
ktime_t ktime = ktime_set(0, time_ns);
|
|
hrtimer_start(&nv_nstimer->hr_timer, ktime, HRTIMER_MODE_REL);
|
|
#else
|
|
unsigned long time_jiffies;
|
|
NvU32 time_us;
|
|
|
|
time_us = (NvU32)(time_ns / 1000);
|
|
|
|
if (time_us == 0)
|
|
{
|
|
nv_printf(NV_DBG_WARNINGS, "NVRM: Timer value cannot be less than 1 usec.\n");
|
|
}
|
|
|
|
time_jiffies = usecs_to_jiffies(time_us);
|
|
mod_timer(&nv_nstimer->jiffy_timer, jiffies + time_jiffies);
|
|
#endif
|
|
}
|
|
|
|
/*!
|
|
* @brief Cancels nano second resolution timer
|
|
*
|
|
* @param[in] nv Per gpu linux state
|
|
* @param[in] nv_nstimer Pointer to nv_nano_timer_t object
|
|
*/
|
|
void NV_API_CALL nv_cancel_nano_timer(
|
|
nv_state_t *nv,
|
|
nv_nano_timer_t *nv_nstimer)
|
|
{
|
|
#if NV_NANO_TIMER_USE_HRTIMER
|
|
hrtimer_cancel(&nv_nstimer->hr_timer);
|
|
#else
|
|
del_timer_sync(&nv_nstimer->jiffy_timer);
|
|
#endif
|
|
|
|
}
|
|
|
|
/*!
|
|
* @brief Cancels & deletes nano second resolution timer object
|
|
*
|
|
* @param[in] nv Per gpu linux state
|
|
* @param[in] nv_nstimer Pointer to nv_nano_timer_t object
|
|
*/
|
|
void NV_API_CALL nv_destroy_nano_timer(
|
|
nv_state_t *nv,
|
|
nv_nano_timer_t *nv_nstimer)
|
|
{
|
|
nv_cancel_nano_timer(nv, nv_nstimer);
|
|
NV_KFREE(nv_nstimer, sizeof(nv_nano_timer_t));
|
|
}
|