// SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
|
/*
|
*
|
* (C) COPYRIGHT 2019-2021 ARM Limited. All rights reserved.
|
*
|
* This program is free software and is provided to you under the terms of the
|
* GNU General Public License version 2 as published by the Free Software
|
* Foundation, and any use by you of this program is subject to the terms
|
* of such GNU license.
|
*
|
* 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.
|
*
|
* You should have received a copy of the GNU General Public License
|
* along with this program; if not, you can access it online at
|
* http://www.gnu.org/licenses/gpl-2.0.html.
|
*
|
*/
|
|
/**
|
* DOC: Mali arbiter interface APIs to share GPU between Virtual Machines
|
*/
|
|
#include <mali_kbase.h>
|
#include "mali_kbase_arbif.h"
|
#include <tl/mali_kbase_tracepoints.h>
|
#include <linux/of.h>
|
#include <linux/of_platform.h>
|
#include "mali_kbase_arbiter_interface.h"
|
|
/* Arbiter interface version against which was implemented this module */
|
#define MALI_REQUIRED_KBASE_ARBITER_INTERFACE_VERSION 5
|
#if MALI_REQUIRED_KBASE_ARBITER_INTERFACE_VERSION != \
|
MALI_KBASE_ARBITER_INTERFACE_VERSION
|
#error "Unsupported Mali Arbiter interface version."
|
#endif
|
|
static void on_max_config(struct device *dev, uint32_t max_l2_slices,
|
uint32_t max_core_mask)
|
{
|
struct kbase_device *kbdev;
|
|
if (!dev) {
|
pr_err("%s(): dev is NULL", __func__);
|
return;
|
}
|
|
kbdev = dev_get_drvdata(dev);
|
if (!kbdev) {
|
dev_err(dev, "%s(): kbdev is NULL", __func__);
|
return;
|
}
|
|
if (!max_l2_slices || !max_core_mask) {
|
dev_dbg(dev,
|
"%s(): max_config ignored as one of the fields is zero",
|
__func__);
|
return;
|
}
|
|
/* set the max config info in the kbase device */
|
kbase_arbiter_set_max_config(kbdev, max_l2_slices, max_core_mask);
|
}
|
|
/**
|
* on_update_freq() - Updates GPU clock frequency
|
* @dev: arbiter interface device handle
|
* @freq: GPU clock frequency value reported from arbiter
|
*
|
* call back function to update GPU clock frequency with
|
* new value from arbiter
|
*/
|
static void on_update_freq(struct device *dev, uint32_t freq)
|
{
|
struct kbase_device *kbdev;
|
|
if (!dev) {
|
pr_err("%s(): dev is NULL", __func__);
|
return;
|
}
|
|
kbdev = dev_get_drvdata(dev);
|
if (!kbdev) {
|
dev_err(dev, "%s(): kbdev is NULL", __func__);
|
return;
|
}
|
|
kbase_arbiter_pm_update_gpu_freq(&kbdev->arb.arb_freq, freq);
|
}
|
|
/**
|
* on_gpu_stop() - sends KBASE_VM_GPU_STOP_EVT event on VM stop
|
* @dev: arbiter interface device handle
|
*
|
* call back function to signal a GPU STOP event from arbiter interface
|
*/
|
static void on_gpu_stop(struct device *dev)
|
{
|
struct kbase_device *kbdev;
|
|
if (!dev) {
|
pr_err("%s(): dev is NULL", __func__);
|
return;
|
}
|
|
kbdev = dev_get_drvdata(dev);
|
if (!kbdev) {
|
dev_err(dev, "%s(): kbdev is NULL", __func__);
|
return;
|
}
|
|
KBASE_TLSTREAM_TL_ARBITER_STOP_REQUESTED(kbdev, kbdev);
|
kbase_arbiter_pm_vm_event(kbdev, KBASE_VM_GPU_STOP_EVT);
|
}
|
|
/**
|
* on_gpu_granted() - sends KBASE_VM_GPU_GRANTED_EVT event on GPU granted
|
* @dev: arbiter interface device handle
|
*
|
* call back function to signal a GPU GRANT event from arbiter interface
|
*/
|
static void on_gpu_granted(struct device *dev)
|
{
|
struct kbase_device *kbdev;
|
|
if (!dev) {
|
pr_err("%s(): dev is NULL", __func__);
|
return;
|
}
|
|
kbdev = dev_get_drvdata(dev);
|
if (!kbdev) {
|
dev_err(dev, "%s(): kbdev is NULL", __func__);
|
return;
|
}
|
|
KBASE_TLSTREAM_TL_ARBITER_GRANTED(kbdev, kbdev);
|
kbase_arbiter_pm_vm_event(kbdev, KBASE_VM_GPU_GRANTED_EVT);
|
}
|
|
/**
|
* on_gpu_lost() - sends KBASE_VM_GPU_LOST_EVT event on GPU granted
|
* @dev: arbiter interface device handle
|
*
|
* call back function to signal a GPU LOST event from arbiter interface
|
*/
|
static void on_gpu_lost(struct device *dev)
|
{
|
struct kbase_device *kbdev;
|
|
if (!dev) {
|
pr_err("%s(): dev is NULL", __func__);
|
return;
|
}
|
|
kbdev = dev_get_drvdata(dev);
|
if (!kbdev) {
|
dev_err(dev, "%s(): kbdev is NULL", __func__);
|
return;
|
}
|
|
kbase_arbiter_pm_vm_event(kbdev, KBASE_VM_GPU_LOST_EVT);
|
}
|
|
/**
|
* kbase_arbif_init() - Kbase Arbiter interface initialisation.
|
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
*
|
* Initialise Kbase Arbiter interface and assign callback functions.
|
*
|
* Return:
|
* * 0 - the interface was initialized or was not specified
|
* * in the device tree.
|
* * -EFAULT - the interface was specified but failed to initialize.
|
* * -EPROBE_DEFER - module dependencies are not yet available.
|
*/
|
int kbase_arbif_init(struct kbase_device *kbdev)
|
{
|
#if IS_ENABLED(CONFIG_OF)
|
struct arbiter_if_arb_vm_ops ops;
|
struct arbiter_if_dev *arb_if;
|
struct device_node *arbiter_if_node;
|
struct platform_device *pdev;
|
int err;
|
|
dev_dbg(kbdev->dev, "%s\n", __func__);
|
|
arbiter_if_node = of_parse_phandle(kbdev->dev->of_node,
|
"arbiter_if", 0);
|
if (!arbiter_if_node) {
|
dev_dbg(kbdev->dev, "No arbiter_if in Device Tree\n");
|
/* no arbiter interface defined in device tree */
|
kbdev->arb.arb_dev = NULL;
|
kbdev->arb.arb_if = NULL;
|
return 0;
|
}
|
|
pdev = of_find_device_by_node(arbiter_if_node);
|
if (!pdev) {
|
dev_err(kbdev->dev, "Failed to find arbiter_if device\n");
|
return -EPROBE_DEFER;
|
}
|
|
if (!pdev->dev.driver || !try_module_get(pdev->dev.driver->owner)) {
|
dev_err(kbdev->dev, "arbiter_if driver not available\n");
|
return -EPROBE_DEFER;
|
}
|
kbdev->arb.arb_dev = &pdev->dev;
|
arb_if = platform_get_drvdata(pdev);
|
if (!arb_if) {
|
dev_err(kbdev->dev, "arbiter_if driver not ready\n");
|
module_put(pdev->dev.driver->owner);
|
return -EPROBE_DEFER;
|
}
|
|
kbdev->arb.arb_if = arb_if;
|
ops.arb_vm_gpu_stop = on_gpu_stop;
|
ops.arb_vm_gpu_granted = on_gpu_granted;
|
ops.arb_vm_gpu_lost = on_gpu_lost;
|
ops.arb_vm_max_config = on_max_config;
|
ops.arb_vm_update_freq = on_update_freq;
|
|
kbdev->arb.arb_freq.arb_freq = 0;
|
kbdev->arb.arb_freq.freq_updated = false;
|
mutex_init(&kbdev->arb.arb_freq.arb_freq_lock);
|
|
/* register kbase arbiter_if callbacks */
|
if (arb_if->vm_ops.vm_arb_register_dev) {
|
err = arb_if->vm_ops.vm_arb_register_dev(arb_if,
|
kbdev->dev, &ops);
|
if (err) {
|
dev_err(&pdev->dev, "Failed to register with arbiter\n");
|
module_put(pdev->dev.driver->owner);
|
if (err != -EPROBE_DEFER)
|
err = -EFAULT;
|
return err;
|
}
|
}
|
|
#else /* CONFIG_OF */
|
dev_dbg(kbdev->dev, "No arbiter without Device Tree support\n");
|
kbdev->arb.arb_dev = NULL;
|
kbdev->arb.arb_if = NULL;
|
#endif
|
return 0;
|
}
|
|
/**
|
* kbase_arbif_destroy() - De-init Kbase arbiter interface
|
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
*
|
* De-initialise Kbase arbiter interface
|
*/
|
void kbase_arbif_destroy(struct kbase_device *kbdev)
|
{
|
struct arbiter_if_dev *arb_if = kbdev->arb.arb_if;
|
|
if (arb_if && arb_if->vm_ops.vm_arb_unregister_dev) {
|
dev_dbg(kbdev->dev, "%s\n", __func__);
|
arb_if->vm_ops.vm_arb_unregister_dev(kbdev->arb.arb_if);
|
}
|
kbdev->arb.arb_if = NULL;
|
if (kbdev->arb.arb_dev)
|
module_put(kbdev->arb.arb_dev->driver->owner);
|
kbdev->arb.arb_dev = NULL;
|
}
|
|
/**
|
* kbase_arbif_get_max_config() - Request max config info
|
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
*
|
* call back function from arb interface to arbiter requesting max config info
|
*/
|
void kbase_arbif_get_max_config(struct kbase_device *kbdev)
|
{
|
struct arbiter_if_dev *arb_if = kbdev->arb.arb_if;
|
|
if (arb_if && arb_if->vm_ops.vm_arb_get_max_config) {
|
dev_dbg(kbdev->dev, "%s\n", __func__);
|
arb_if->vm_ops.vm_arb_get_max_config(arb_if);
|
}
|
}
|
|
/**
|
* kbase_arbif_gpu_request() - Request GPU from
|
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
*
|
* call back function from arb interface to arbiter requesting GPU for VM
|
*/
|
void kbase_arbif_gpu_request(struct kbase_device *kbdev)
|
{
|
struct arbiter_if_dev *arb_if = kbdev->arb.arb_if;
|
|
if (arb_if && arb_if->vm_ops.vm_arb_gpu_request) {
|
dev_dbg(kbdev->dev, "%s\n", __func__);
|
KBASE_TLSTREAM_TL_ARBITER_REQUESTED(kbdev, kbdev);
|
arb_if->vm_ops.vm_arb_gpu_request(arb_if);
|
}
|
}
|
|
/**
|
* kbase_arbif_gpu_stopped() - send GPU stopped message to the arbiter
|
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
* @gpu_required: GPU request flag
|
*
|
*/
|
void kbase_arbif_gpu_stopped(struct kbase_device *kbdev, u8 gpu_required)
|
{
|
struct arbiter_if_dev *arb_if = kbdev->arb.arb_if;
|
|
if (arb_if && arb_if->vm_ops.vm_arb_gpu_stopped) {
|
dev_dbg(kbdev->dev, "%s\n", __func__);
|
KBASE_TLSTREAM_TL_ARBITER_STOPPED(kbdev, kbdev);
|
if (gpu_required)
|
KBASE_TLSTREAM_TL_ARBITER_REQUESTED(kbdev, kbdev);
|
arb_if->vm_ops.vm_arb_gpu_stopped(arb_if, gpu_required);
|
}
|
}
|
|
/**
|
* kbase_arbif_gpu_active() - Sends a GPU_ACTIVE message to the Arbiter
|
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
*
|
* Informs the arbiter VM is active
|
*/
|
void kbase_arbif_gpu_active(struct kbase_device *kbdev)
|
{
|
struct arbiter_if_dev *arb_if = kbdev->arb.arb_if;
|
|
if (arb_if && arb_if->vm_ops.vm_arb_gpu_active) {
|
dev_dbg(kbdev->dev, "%s\n", __func__);
|
arb_if->vm_ops.vm_arb_gpu_active(arb_if);
|
}
|
}
|
|
/**
|
* kbase_arbif_gpu_idle() - Inform the arbiter that the VM has gone idle
|
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
*
|
* Informs the arbiter VM is idle
|
*/
|
void kbase_arbif_gpu_idle(struct kbase_device *kbdev)
|
{
|
struct arbiter_if_dev *arb_if = kbdev->arb.arb_if;
|
|
if (arb_if && arb_if->vm_ops.vm_arb_gpu_idle) {
|
dev_dbg(kbdev->dev, "vm_arb_gpu_idle\n");
|
arb_if->vm_ops.vm_arb_gpu_idle(arb_if);
|
}
|
}
|