mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 19:30:30 +09:00
driver: rknpu: Update rknpu driver, version: 0.6.4
* Add support for rk3588/rk3588s Signed-off-by: Felix Zeng <felix.zeng@rock-chips.com> Change-Id: I292cca4037367d21e88f05bb8a8b7cac93c2f91e
This commit is contained in:
@@ -20,10 +20,10 @@
|
||||
|
||||
#define DRIVER_NAME "rknpu"
|
||||
#define DRIVER_DESC "RKNPU driver"
|
||||
#define DRIVER_DATE "20210824"
|
||||
#define DRIVER_DATE "20211227"
|
||||
#define DRIVER_MAJOR 0
|
||||
#define DRIVER_MINOR 5
|
||||
#define DRIVER_PATCHLEVEL 0
|
||||
#define DRIVER_MINOR 6
|
||||
#define DRIVER_PATCHLEVEL 4
|
||||
|
||||
#define LOG_TAG "RKNPU"
|
||||
|
||||
@@ -42,10 +42,28 @@
|
||||
DRM_DEV_DEBUG_DRIVER(dev, LOG_TAG ": " fmt, ##args)
|
||||
#define LOG_DEV_ERROR(dev, fmt, args...) dev_err(dev, LOG_TAG ": " fmt, ##args)
|
||||
|
||||
struct npu_reset_data {
|
||||
const char *srst_a_name;
|
||||
const char *srst_h_name;
|
||||
};
|
||||
|
||||
struct rknpu_config {
|
||||
__u32 bw_priority_addr;
|
||||
__u32 bw_priority_length;
|
||||
__u64 dma_mask;
|
||||
__u32 pc_data_extra_amount;
|
||||
__u32 bw_enable;
|
||||
const struct npu_irqs_data *irqs;
|
||||
const struct npu_reset_data *resets;
|
||||
int num_irqs;
|
||||
int num_resets;
|
||||
};
|
||||
|
||||
struct rknpu_subcore_data {
|
||||
struct list_head todo_list;
|
||||
wait_queue_head_t job_done_wq;
|
||||
struct rknpu_job *job;
|
||||
uint64_t task_num;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -56,22 +74,20 @@ struct rknpu_config {
|
||||
* @drm_dev: DRM device instance
|
||||
*/
|
||||
struct rknpu_device {
|
||||
void __iomem *base;
|
||||
void __iomem *base[RKNPU_MAX_CORES];
|
||||
struct device *dev;
|
||||
struct device *fake_dev;
|
||||
struct drm_device *drm_dev;
|
||||
atomic_t sequence;
|
||||
spinlock_t lock;
|
||||
spinlock_t irq_lock;
|
||||
struct list_head todo_list;
|
||||
wait_queue_head_t job_done_wq;
|
||||
struct rknpu_subcore_data subcore_datas[RKNPU_MAX_CORES];
|
||||
const struct rknpu_config *config;
|
||||
void __iomem *bw_priority_base;
|
||||
struct rknpu_job *job;
|
||||
struct rknpu_fence_context *fence_ctx;
|
||||
bool iommu_en;
|
||||
struct reset_control *srst_a;
|
||||
struct reset_control *srst_h;
|
||||
struct reset_control *srst_a[RKNPU_MAX_CORES];
|
||||
struct reset_control *srst_h[RKNPU_MAX_CORES];
|
||||
struct clk_bulk_data *clks;
|
||||
int num_clks;
|
||||
struct regulator *vdd;
|
||||
|
||||
@@ -15,9 +15,7 @@ struct rknpu_fence_context {
|
||||
spinlock_t spinlock;
|
||||
};
|
||||
|
||||
struct rknpu_fence_context *rknpu_fence_context_alloc(void);
|
||||
|
||||
void rknpu_fence_context_free(struct rknpu_fence_context *fence_ctx);
|
||||
int rknpu_fence_context_alloc(struct rknpu_device *rknpu_dev);
|
||||
|
||||
int rknpu_fence_alloc(struct rknpu_job *job);
|
||||
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
#define __user
|
||||
#endif
|
||||
|
||||
#define RKNPU_PC_DATA_EXTRA_AMOUNT 4
|
||||
|
||||
#define RKNPU_OFFSET_VERSION 0x0
|
||||
#define RKNPU_OFFSET_PC_OP_EN 0x8
|
||||
#define RKNPU_OFFSET_PC_DATA_ADDR 0x10
|
||||
@@ -27,6 +25,7 @@
|
||||
#define RKNPU_OFFSET_INT_MASK 0x20
|
||||
#define RKNPU_OFFSET_INT_CLEAR 0x24
|
||||
#define RKNPU_OFFSET_INT_STATUS 0x28
|
||||
#define RKNPU_OFFSET_INT_RAW_STATUS 0x2c
|
||||
|
||||
#define RKNPU_OFFSET_CLR_ALL_RW_AMOUNT 0x8010
|
||||
#define RKNPU_OFFSET_DT_WR_AMOUNT 0x8034
|
||||
@@ -91,9 +90,11 @@ enum e_rknpu_job_mode {
|
||||
RKNPU_JOB_BLOCK = 0 << 1,
|
||||
RKNPU_JOB_NONBLOCK = 1 << 1,
|
||||
RKNPU_JOB_PINGPONG = 1 << 2,
|
||||
RKNPU_JOB_FENCE = 1 << 3,
|
||||
RKNPU_JOB_FENCE_IN = 1 << 3,
|
||||
RKNPU_JOB_FENCE_OUT = 1 << 4,
|
||||
RKNPU_JOB_MASK = RKNPU_JOB_PC | RKNPU_JOB_NONBLOCK |
|
||||
RKNPU_JOB_PINGPONG | RKNPU_JOB_FENCE
|
||||
RKNPU_JOB_PINGPONG | RKNPU_JOB_FENCE_IN |
|
||||
RKNPU_JOB_FENCE_OUT
|
||||
};
|
||||
|
||||
/* action definitions */
|
||||
@@ -206,6 +207,19 @@ struct rknpu_task {
|
||||
__u64 regcmd_data;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct rknpu_subcore_task structure for subcore task index
|
||||
*
|
||||
* @task_start: task start index
|
||||
* @task_number: task number
|
||||
*
|
||||
*/
|
||||
struct rknpu_subcore_task {
|
||||
__u32 task_start;
|
||||
__u32 task_number;
|
||||
__u32 task_end;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct rknpu_submit structure for job submit
|
||||
*
|
||||
@@ -219,7 +233,7 @@ struct rknpu_task {
|
||||
* @regcfg_obj_addr: address of register config object
|
||||
* @user_data: (optional) user data
|
||||
* @sequence: submit sequence
|
||||
* @core_id: core id of rknpu
|
||||
* @core_mask: core mask of rknpu
|
||||
* @fence_fd: dma fence fd
|
||||
*
|
||||
*/
|
||||
@@ -234,8 +248,9 @@ struct rknpu_submit {
|
||||
__u64 regcfg_obj_addr;
|
||||
__u64 user_data;
|
||||
__u64 sequence;
|
||||
__u32 core_id;
|
||||
__u32 core_mask;
|
||||
__s32 fence_fd;
|
||||
struct rknpu_subcore_task subcore_task[5];
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,12 +14,19 @@
|
||||
|
||||
#include "rknpu_ioctl.h"
|
||||
|
||||
#define RKNPU_MAX_CORES 3
|
||||
|
||||
#define RKNPU_JOB_DONE (1 << 0)
|
||||
#define RKNPU_JOB_ASYNC (1 << 1)
|
||||
|
||||
#define RKNPU_CORE_AUTO_MASK 0x00
|
||||
#define RKNPU_CORE0_MASK 0x01
|
||||
#define RKNPU_CORE1_MASK 0x02
|
||||
#define RKNPU_CORE2_MASK 0x04
|
||||
|
||||
struct rknpu_job {
|
||||
struct rknpu_device *rknpu_dev;
|
||||
struct list_head head;
|
||||
struct list_head head[RKNPU_MAX_CORES];
|
||||
struct work_struct cleanup_work;
|
||||
unsigned int flags;
|
||||
int ret;
|
||||
@@ -27,14 +34,18 @@ struct rknpu_job {
|
||||
bool args_owner;
|
||||
struct rknpu_task *first_task;
|
||||
struct rknpu_task *last_task;
|
||||
uint32_t int_mask;
|
||||
uint32_t int_status;
|
||||
uint32_t int_mask[RKNPU_MAX_CORES];
|
||||
uint32_t int_status[RKNPU_MAX_CORES];
|
||||
struct dma_fence *fence;
|
||||
spinlock_t fence_lock;
|
||||
ktime_t timestamp;
|
||||
uint32_t use_core_num;
|
||||
uint32_t run_count;
|
||||
uint32_t interrupt_count;
|
||||
};
|
||||
|
||||
irqreturn_t rknpu_irq_handler(int irq, void *data);
|
||||
irqreturn_t rknpu_core0_irq_handler(int irq, void *data);
|
||||
irqreturn_t rknpu_core1_irq_handler(int irq, void *data);
|
||||
irqreturn_t rknpu_core2_irq_handler(int irq, void *data);
|
||||
|
||||
int rknpu_submit_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
|
||||
@@ -36,9 +36,11 @@
|
||||
#include <drm/drm_file.h>
|
||||
#include <drm/drm_drv.h>
|
||||
|
||||
#ifndef FPGA_PLATFORM
|
||||
#include <soc/rockchip/rockchip_opp_select.h>
|
||||
#include <soc/rockchip/rockchip_system_monitor.h>
|
||||
#include <soc/rockchip/rockchip_ipa.h>
|
||||
#endif
|
||||
|
||||
#include "rknpu_ioctl.h"
|
||||
#include "rknpu_reset.h"
|
||||
@@ -56,10 +58,52 @@ module_param(bypass_soft_reset, int, 0644);
|
||||
MODULE_PARM_DESC(bypass_soft_reset,
|
||||
"bypass RKNPU soft reset if set it to 1, disabled by default");
|
||||
|
||||
struct npu_irqs_data {
|
||||
const char *name;
|
||||
irqreturn_t (*irq_hdl)(int irq, void *ctx);
|
||||
};
|
||||
|
||||
static const struct npu_irqs_data rk356x_npu_irqs[] = {
|
||||
{ "npu0_irq", rknpu_core0_irq_handler }
|
||||
};
|
||||
|
||||
static const struct npu_irqs_data rk3588_npu_irqs[] = {
|
||||
{ "npu0_irq", rknpu_core0_irq_handler },
|
||||
{ "npu1_irq", rknpu_core1_irq_handler },
|
||||
{ "npu2_irq", rknpu_core2_irq_handler }
|
||||
};
|
||||
|
||||
static const struct npu_reset_data rk356x_npu_resets[] = { { "srst_a",
|
||||
"srst_h" } };
|
||||
|
||||
static const struct npu_reset_data rk3588_npu_resets[] = {
|
||||
{ "srst_a0", "srst_h0" },
|
||||
{ "srst_a1", "srst_h1" },
|
||||
{ "srst_a2", "srst_h2" }
|
||||
};
|
||||
|
||||
static const struct rknpu_config rk356x_rknpu_config = {
|
||||
.bw_priority_addr = 0xfe180008,
|
||||
.bw_priority_length = 0x10,
|
||||
.dma_mask = DMA_BIT_MASK(32),
|
||||
.pc_data_extra_amount = 4,
|
||||
.bw_enable = 1,
|
||||
.irqs = rk356x_npu_irqs,
|
||||
.resets = rk356x_npu_resets,
|
||||
.num_irqs = ARRAY_SIZE(rk356x_npu_irqs),
|
||||
.num_resets = ARRAY_SIZE(rk356x_npu_resets)
|
||||
};
|
||||
|
||||
static const struct rknpu_config rk3588_rknpu_config = {
|
||||
.bw_priority_addr = 0x0,
|
||||
.bw_priority_length = 0x0,
|
||||
.dma_mask = DMA_BIT_MASK(40),
|
||||
.pc_data_extra_amount = 2,
|
||||
.bw_enable = 0,
|
||||
.irqs = rk3588_npu_irqs,
|
||||
.resets = rk3588_npu_resets,
|
||||
.num_irqs = ARRAY_SIZE(rk3588_npu_irqs),
|
||||
.num_resets = ARRAY_SIZE(rk3588_npu_resets)
|
||||
};
|
||||
|
||||
/* driver probe and init */
|
||||
@@ -72,6 +116,10 @@ static const struct of_device_id rknpu_of_match[] = {
|
||||
.compatible = "rockchip,rk3568-rknpu",
|
||||
.data = &rk356x_rknpu_config,
|
||||
},
|
||||
{
|
||||
.compatible = "rockchip,rk3588-rknpu",
|
||||
.data = &rk3588_rknpu_config,
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
||||
@@ -350,6 +398,7 @@ static int rknpu_power_on(struct rknpu_device *rknpu_dev)
|
||||
struct device *dev = rknpu_dev->dev;
|
||||
int ret = -EINVAL;
|
||||
|
||||
#ifndef FPGA_PLATFORM
|
||||
ret = regulator_enable(rknpu_dev->vdd);
|
||||
if (ret) {
|
||||
LOG_DEV_ERROR(
|
||||
@@ -357,6 +406,7 @@ static int rknpu_power_on(struct rknpu_device *rknpu_dev)
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
ret = clk_bulk_prepare_enable(rknpu_dev->num_clks, rknpu_dev->clks);
|
||||
if (ret) {
|
||||
@@ -428,11 +478,14 @@ static int rknpu_power_off(struct rknpu_device *rknpu_dev)
|
||||
|
||||
clk_bulk_disable_unprepare(rknpu_dev->num_clks, rknpu_dev->clks);
|
||||
|
||||
#ifndef FPGA_PLATFORM
|
||||
regulator_disable(rknpu_dev->vdd);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef FPGA_PLATFORM
|
||||
static struct monitor_dev_profile npu_mdevp = {
|
||||
.type = MONITOR_TPYE_DEV,
|
||||
.low_temp_adjust = rockchip_monitor_dev_low_temp_adjust,
|
||||
@@ -677,6 +730,57 @@ static int rknpu_devfreq_init(struct rknpu_device *rknpu_dev)
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int rknpu_register_irq(struct platform_device *pdev,
|
||||
struct rknpu_device *rknpu_dev)
|
||||
{
|
||||
const struct rknpu_config *config = rknpu_dev->config;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource *res;
|
||||
int i, ret, irq;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
|
||||
config->irqs[0].name);
|
||||
if (res) {
|
||||
/* there are irq names in dts */
|
||||
for (i = 0; i < config->num_irqs; i++) {
|
||||
irq = platform_get_irq_byname(pdev,
|
||||
config->irqs[i].name);
|
||||
if (irq < 0) {
|
||||
LOG_DEV_ERROR(dev, "no npu %s in dts\n",
|
||||
config->irqs[i].name);
|
||||
return irq;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(dev, irq,
|
||||
config->irqs[i].irq_hdl,
|
||||
IRQF_SHARED, dev_name(dev),
|
||||
rknpu_dev);
|
||||
if (ret < 0) {
|
||||
LOG_DEV_ERROR(dev, "request %s failed: %d\n",
|
||||
config->irqs[i].name, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* no irq names in dts */
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
LOG_DEV_ERROR(dev, "no npu irq in dts\n");
|
||||
return irq;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(dev, irq, rknpu_core0_irq_handler,
|
||||
IRQF_SHARED, dev_name(dev), rknpu_dev);
|
||||
if (ret < 0) {
|
||||
LOG_DEV_ERROR(dev, "request irq failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rknpu_probe(struct platform_device *pdev)
|
||||
{
|
||||
@@ -686,7 +790,7 @@ static int rknpu_probe(struct platform_device *pdev)
|
||||
struct device *virt_dev = NULL;
|
||||
const struct of_device_id *match = NULL;
|
||||
const struct rknpu_config *config = NULL;
|
||||
int ret = -EINVAL;
|
||||
int ret = -EINVAL, i = 0;
|
||||
|
||||
if (!pdev->dev.of_node) {
|
||||
LOG_DEV_ERROR(dev, "rknpu device-tree data is missing!\n");
|
||||
@@ -729,11 +833,8 @@ static int rknpu_probe(struct platform_device *pdev)
|
||||
rknpu_reset_get(rknpu_dev);
|
||||
|
||||
rknpu_dev->num_clks = devm_clk_bulk_get_all(dev, &rknpu_dev->clks);
|
||||
if (rknpu_dev->num_clks < 1) {
|
||||
LOG_DEV_ERROR(dev, "failed to get clk source for rknpu\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
#ifndef FPGA_PLATFORM
|
||||
rknpu_dev->vdd = devm_regulator_get_optional(dev, "rknpu");
|
||||
if (IS_ERR(rknpu_dev->vdd)) {
|
||||
if (PTR_ERR(rknpu_dev->vdd) != -ENODEV) {
|
||||
@@ -746,73 +847,68 @@ static int rknpu_probe(struct platform_device *pdev)
|
||||
}
|
||||
rknpu_dev->vdd = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
spin_lock_init(&rknpu_dev->lock);
|
||||
spin_lock_init(&rknpu_dev->irq_lock);
|
||||
INIT_LIST_HEAD(&rknpu_dev->todo_list);
|
||||
init_waitqueue_head(&rknpu_dev->job_done_wq);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
LOG_DEV_ERROR(dev, "failed to get memory resource for rknpu\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
rknpu_dev->base = devm_ioremap_resource(dev, res);
|
||||
if (PTR_ERR(rknpu_dev->base) == -EBUSY) {
|
||||
rknpu_dev->base =
|
||||
devm_ioremap(dev, res->start, resource_size(res));
|
||||
}
|
||||
|
||||
if (IS_ERR(rknpu_dev->base)) {
|
||||
LOG_DEV_ERROR(dev, "failed to remap register for rknpu\n");
|
||||
return PTR_ERR(rknpu_dev->base);
|
||||
}
|
||||
|
||||
rknpu_dev->bw_priority_base = devm_ioremap(
|
||||
dev, config->bw_priority_addr, config->bw_priority_length);
|
||||
if (IS_ERR(rknpu_dev->bw_priority_base)) {
|
||||
LOG_DEV_ERROR(
|
||||
rknpu_dev->dev,
|
||||
"failed to remap bw priority register for rknpu\n");
|
||||
rknpu_dev->bw_priority_base = NULL;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
if (!res) {
|
||||
LOG_DEV_ERROR(dev,
|
||||
"failed to get interrupt resource for rknpu\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
if (!rknpu_dev->bypass_irq_handler) {
|
||||
ret = devm_request_irq(dev, res->start, rknpu_irq_handler,
|
||||
IRQF_SHARED, dev_name(dev), rknpu_dev);
|
||||
if (ret) {
|
||||
LOG_DEV_ERROR(dev, "failed to request irq for rknpu\n");
|
||||
return ret;
|
||||
for (i = 0; i < config->num_irqs; i++) {
|
||||
INIT_LIST_HEAD(&rknpu_dev->subcore_datas[i].todo_list);
|
||||
init_waitqueue_head(&rknpu_dev->subcore_datas[i].job_done_wq);
|
||||
rknpu_dev->subcore_datas[i].task_num = 0;
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, i);
|
||||
if (!res) {
|
||||
LOG_DEV_ERROR(
|
||||
dev,
|
||||
"failed to get memory resource for rknpu\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
rknpu_dev->base[i] = devm_ioremap_resource(dev, res);
|
||||
if (PTR_ERR(rknpu_dev->base[i]) == -EBUSY) {
|
||||
rknpu_dev->base[i] = devm_ioremap(dev, res->start,
|
||||
resource_size(res));
|
||||
}
|
||||
|
||||
if (IS_ERR(rknpu_dev->base[i])) {
|
||||
LOG_DEV_ERROR(dev,
|
||||
"failed to remap register for rknpu\n");
|
||||
return PTR_ERR(rknpu_dev->base[i]);
|
||||
}
|
||||
} else {
|
||||
LOG_DEV_WARN(dev, "bypass irq handler!\n");
|
||||
}
|
||||
|
||||
if (config->bw_priority_length > 0) {
|
||||
rknpu_dev->bw_priority_base =
|
||||
devm_ioremap(dev, config->bw_priority_addr,
|
||||
config->bw_priority_length);
|
||||
if (IS_ERR(rknpu_dev->bw_priority_base)) {
|
||||
LOG_DEV_ERROR(
|
||||
rknpu_dev->dev,
|
||||
"failed to remap bw priority register for rknpu\n");
|
||||
rknpu_dev->bw_priority_base = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!rknpu_dev->bypass_irq_handler)
|
||||
rknpu_register_irq(pdev, rknpu_dev);
|
||||
|
||||
ret = rknpu_drm_probe(rknpu_dev);
|
||||
if (ret) {
|
||||
LOG_DEV_ERROR(dev, "failed to probe device for rknpu\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
rknpu_dev->fence_ctx = rknpu_fence_context_alloc();
|
||||
if (IS_ERR(rknpu_dev->fence_ctx)) {
|
||||
ret = rknpu_fence_context_alloc(rknpu_dev);
|
||||
if (ret) {
|
||||
LOG_DEV_ERROR(dev,
|
||||
"failed to allocate fence context for rknpu\n");
|
||||
ret = PTR_ERR(rknpu_dev->fence_ctx);
|
||||
goto err_remove_drm;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, rknpu_dev);
|
||||
|
||||
#ifndef FPGA_PLATFORM
|
||||
rknpu_devfreq_init(rknpu_dev);
|
||||
#endif
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
@@ -832,12 +928,10 @@ static int rknpu_probe(struct platform_device *pdev)
|
||||
|
||||
ret = rknpu_power_on(rknpu_dev);
|
||||
if (ret)
|
||||
goto err_free_fence_context;
|
||||
goto err_remove_drm;
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_fence_context:
|
||||
rknpu_fence_context_free(rknpu_dev->fence_ctx);
|
||||
err_remove_drm:
|
||||
rknpu_drm_remove(rknpu_dev);
|
||||
|
||||
@@ -847,14 +941,15 @@ err_remove_drm:
|
||||
static int rknpu_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct rknpu_device *rknpu_dev = platform_get_drvdata(pdev);
|
||||
int i = 0;
|
||||
|
||||
WARN_ON(rknpu_dev->job);
|
||||
WARN_ON(!list_empty(&rknpu_dev->todo_list));
|
||||
for (i = 0; i < rknpu_dev->config->num_irqs; i++) {
|
||||
WARN_ON(rknpu_dev->subcore_datas[i].job);
|
||||
WARN_ON(!list_empty(&rknpu_dev->subcore_datas[i].todo_list));
|
||||
}
|
||||
|
||||
rknpu_drm_remove(rknpu_dev);
|
||||
|
||||
rknpu_fence_context_free(rknpu_dev->fence_ctx);
|
||||
|
||||
rknpu_power_off(rknpu_dev);
|
||||
|
||||
if (rknpu_dev->multiple_domains) {
|
||||
|
||||
@@ -24,24 +24,21 @@ static const struct dma_fence_ops rknpu_fence_ops = {
|
||||
.get_timeline_name = rknpu_fence_get_name,
|
||||
};
|
||||
|
||||
struct rknpu_fence_context *rknpu_fence_context_alloc(void)
|
||||
int rknpu_fence_context_alloc(struct rknpu_device *rknpu_dev)
|
||||
{
|
||||
struct rknpu_fence_context *fence_ctx = NULL;
|
||||
|
||||
fence_ctx = kzalloc(sizeof(*fence_ctx), GFP_KERNEL);
|
||||
fence_ctx =
|
||||
devm_kzalloc(rknpu_dev->dev, sizeof(*fence_ctx), GFP_KERNEL);
|
||||
if (!fence_ctx)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
return -ENOMEM;
|
||||
|
||||
fence_ctx->context = dma_fence_context_alloc(1);
|
||||
spin_lock_init(&fence_ctx->spinlock);
|
||||
|
||||
return fence_ctx;
|
||||
}
|
||||
rknpu_dev->fence_ctx = fence_ctx;
|
||||
|
||||
void rknpu_fence_context_free(struct rknpu_fence_context *fence_ctx)
|
||||
{
|
||||
if (!IS_ERR(fence_ctx))
|
||||
kfree(fence_ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rknpu_fence_alloc(struct rknpu_job *job)
|
||||
@@ -53,7 +50,7 @@ int rknpu_fence_alloc(struct rknpu_job *job)
|
||||
if (!fence)
|
||||
return -ENOMEM;
|
||||
|
||||
dma_fence_init(fence, &rknpu_fence_ops, &job->fence_lock,
|
||||
dma_fence_init(fence, &rknpu_fence_ops, &fence_ctx->spinlock,
|
||||
fence_ctx->context, ++fence_ctx->seqno);
|
||||
|
||||
job->fence = fence;
|
||||
|
||||
@@ -130,9 +130,6 @@ static int rknpu_gem_alloc_buf(struct rknpu_gem_object *rknpu_obj)
|
||||
#endif
|
||||
#ifdef DMA_ATTR_SYS_CACHE_ONLY
|
||||
rknpu_obj->dma_attrs |= DMA_ATTR_SYS_CACHE_ONLY;
|
||||
#elif DMA_ATTR_FORCE_COHERENT
|
||||
// force coherent
|
||||
rknpu_obj->dma_attrs |= DMA_ATTR_FORCE_COHERENT;
|
||||
#endif
|
||||
} else if (rknpu_obj->flags & RKNPU_MEM_WRITE_COMBINE) {
|
||||
rknpu_obj->dma_attrs |= DMA_ATTR_WRITE_COMBINE;
|
||||
@@ -459,7 +456,7 @@ int rknpu_gem_create_ioctl(struct drm_device *dev, void *data,
|
||||
// rknpu_gem_object_get(&rknpu_obj->base);
|
||||
|
||||
args->size = rknpu_obj->size;
|
||||
args->obj_addr = (__u64)rknpu_obj;
|
||||
args->obj_addr = (__u64)(uintptr_t)rknpu_obj;
|
||||
args->dma_addr = rknpu_obj->dma_addr;
|
||||
|
||||
return 0;
|
||||
@@ -920,7 +917,7 @@ int rknpu_gem_sync_ioctl(struct drm_device *dev, void *data,
|
||||
unsigned long len = 0;
|
||||
int i;
|
||||
|
||||
rknpu_obj = (struct rknpu_gem_object *)args->obj_addr;
|
||||
rknpu_obj = (struct rknpu_gem_object *)(uintptr_t)args->obj_addr;
|
||||
if (!rknpu_obj)
|
||||
return -EINVAL;
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/sync_file.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include "rknpu_ioctl.h"
|
||||
#include "rknpu_drv.h"
|
||||
@@ -17,8 +19,41 @@
|
||||
#define _REG_READ(base, offset) readl(base + (offset))
|
||||
#define _REG_WRITE(base, value, offset) writel(value, base + (offset))
|
||||
|
||||
#define REG_READ(offset) _REG_READ(rknpu_dev->base, offset)
|
||||
#define REG_WRITE(value, offset) _REG_WRITE(rknpu_dev->base, value, offset)
|
||||
#define REG_READ(offset) _REG_READ(rknpu_core_base, offset)
|
||||
#define REG_WRITE(value, offset) _REG_WRITE(rknpu_core_base, value, offset)
|
||||
|
||||
static int rknpu_core_index(int core_mask)
|
||||
{
|
||||
int index = 0;
|
||||
|
||||
if (core_mask & RKNPU_CORE0_MASK)
|
||||
index = 0;
|
||||
else if (core_mask & RKNPU_CORE1_MASK)
|
||||
index = 1;
|
||||
else if (core_mask & RKNPU_CORE2_MASK)
|
||||
index = 2;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
static int rknpu_core_mask(int core_index)
|
||||
{
|
||||
int core_mask[3] = { RKNPU_CORE0_MASK, RKNPU_CORE1_MASK,
|
||||
RKNPU_CORE2_MASK };
|
||||
return core_mask[core_index];
|
||||
}
|
||||
|
||||
static int rknn_get_task_number(struct rknpu_job *job, int core_index)
|
||||
{
|
||||
int task_num = job->args->task_number;
|
||||
|
||||
if (job->use_core_num == 2)
|
||||
task_num = job->args->subcore_task[core_index].task_number;
|
||||
else if (job->use_core_num == 3)
|
||||
task_num = job->args->subcore_task[core_index + 2].task_number;
|
||||
|
||||
return task_num;
|
||||
}
|
||||
|
||||
static void rknpu_job_free(struct rknpu_job *job)
|
||||
{
|
||||
@@ -27,7 +62,8 @@ static void rknpu_job_free(struct rknpu_job *job)
|
||||
if (job->fence)
|
||||
dma_fence_put(job->fence);
|
||||
|
||||
task_obj = (struct rknpu_gem_object *)job->args->task_obj_addr;
|
||||
task_obj =
|
||||
(struct rknpu_gem_object *)(uintptr_t)job->args->task_obj_addr;
|
||||
if (task_obj)
|
||||
rknpu_gem_object_put(&task_obj->base);
|
||||
|
||||
@@ -58,14 +94,22 @@ static inline struct rknpu_job *rknpu_job_alloc(struct rknpu_device *rknpu_dev,
|
||||
struct rknpu_job *job = NULL;
|
||||
struct rknpu_gem_object *task_obj = NULL;
|
||||
|
||||
if (rknpu_dev->config->num_irqs == 1)
|
||||
args->core_mask = RKNPU_CORE0_MASK;
|
||||
|
||||
job = kzalloc(sizeof(*job), GFP_KERNEL);
|
||||
if (!job)
|
||||
return NULL;
|
||||
|
||||
job->timestamp = ktime_get();
|
||||
job->rknpu_dev = rknpu_dev;
|
||||
job->use_core_num = (args->core_mask & RKNPU_CORE0_MASK) +
|
||||
((args->core_mask & RKNPU_CORE1_MASK) >> 1) +
|
||||
((args->core_mask & RKNPU_CORE2_MASK) >> 2);
|
||||
job->run_count = job->use_core_num;
|
||||
job->interrupt_count = job->use_core_num;
|
||||
|
||||
task_obj = (struct rknpu_gem_object *)args->task_obj_addr;
|
||||
task_obj = (struct rknpu_gem_object *)(uintptr_t)args->task_obj_addr;
|
||||
if (task_obj)
|
||||
rknpu_gem_object_get(&task_obj->base);
|
||||
|
||||
@@ -93,9 +137,13 @@ static inline int rknpu_job_wait(struct rknpu_job *job)
|
||||
struct rknpu_device *rknpu_dev = job->rknpu_dev;
|
||||
struct rknpu_submit *args = job->args;
|
||||
struct rknpu_task *last_task = NULL;
|
||||
struct rknpu_subcore_data *subcore_data = NULL;
|
||||
void __iomem *rknpu_core_base = NULL;
|
||||
int core_index = rknpu_core_index(job->args->core_mask);
|
||||
int ret = -EINVAL;
|
||||
|
||||
ret = wait_event_interruptible_timeout(rknpu_dev->job_done_wq,
|
||||
subcore_data = &rknpu_dev->subcore_datas[core_index];
|
||||
ret = wait_event_interruptible_timeout(subcore_data->job_done_wq,
|
||||
job->flags & RKNPU_JOB_DONE,
|
||||
msecs_to_jiffies(args->timeout));
|
||||
|
||||
@@ -103,10 +151,11 @@ static inline int rknpu_job_wait(struct rknpu_job *job)
|
||||
if (!last_task)
|
||||
return -EINVAL;
|
||||
|
||||
last_task->int_status = job->int_status;
|
||||
last_task->int_status = job->int_status[core_index];
|
||||
|
||||
if (ret <= 0) {
|
||||
args->task_counter = 0;
|
||||
rknpu_core_base = rknpu_dev->base[core_index];
|
||||
if (args->flags & RKNPU_JOB_PC) {
|
||||
uint32_t task_status =
|
||||
REG_READ(RKNPU_OFFSET_PC_TASK_STATUS);
|
||||
@@ -120,25 +169,48 @@ static inline int rknpu_job_wait(struct rknpu_job *job)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int rknpu_job_commit_pc(struct rknpu_job *job)
|
||||
static inline int rknpu_job_commit_pc(struct rknpu_job *job, int core_index)
|
||||
{
|
||||
struct rknpu_device *rknpu_dev = job->rknpu_dev;
|
||||
struct rknpu_submit *args = job->args;
|
||||
struct rknpu_gem_object *task_obj =
|
||||
(struct rknpu_gem_object *)args->task_obj_addr;
|
||||
(struct rknpu_gem_object *)(uintptr_t)args->task_obj_addr;
|
||||
struct rknpu_task *task_base = NULL;
|
||||
struct rknpu_task *first_task = NULL;
|
||||
struct rknpu_task *last_task = NULL;
|
||||
void __iomem *rknpu_core_base = rknpu_dev->base[core_index];
|
||||
int task_start = args->task_start;
|
||||
int task_end = args->task_start + args->task_number - 1;
|
||||
int task_number = args->task_number;
|
||||
int task_pp_en = args->flags & RKNPU_JOB_PINGPONG ? 1 : 0;
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < rknpu_dev->config->num_irqs; i++) {
|
||||
if (i == core_index) {
|
||||
REG_WRITE((0xe + 0x10000000 * i), 0x1004);
|
||||
REG_WRITE((0xe + 0x10000000 * i), 0x3004);
|
||||
}
|
||||
}
|
||||
|
||||
if (!task_obj)
|
||||
return -EINVAL;
|
||||
|
||||
if ((task_start + 1) * sizeof(*task_base) > task_obj->size ||
|
||||
(task_end + 1) * sizeof(*task_base) > task_obj->size)
|
||||
return -EINVAL;
|
||||
if (job->use_core_num == 1) {
|
||||
task_start = args->subcore_task[core_index].task_start;
|
||||
task_end = args->subcore_task[core_index].task_start +
|
||||
args->subcore_task[core_index].task_end - 1;
|
||||
task_number = args->subcore_task[core_index].task_number;
|
||||
} else if (job->use_core_num == 2) {
|
||||
task_start = args->subcore_task[core_index].task_start;
|
||||
task_end = args->subcore_task[core_index].task_start +
|
||||
args->subcore_task[core_index].task_end - 1;
|
||||
task_number = args->subcore_task[core_index].task_number;
|
||||
} else if (job->use_core_num == 3) {
|
||||
task_start = args->subcore_task[core_index + 2].task_start;
|
||||
task_end = args->subcore_task[core_index + 2].task_start +
|
||||
args->subcore_task[core_index + 2].task_end - 1;
|
||||
task_number = args->subcore_task[core_index + 2].task_number;
|
||||
}
|
||||
|
||||
task_base = task_obj->kv_addr;
|
||||
|
||||
@@ -147,21 +219,22 @@ static inline int rknpu_job_commit_pc(struct rknpu_job *job)
|
||||
|
||||
REG_WRITE(first_task->regcmd_data, RKNPU_OFFSET_PC_DATA_ADDR);
|
||||
|
||||
REG_WRITE(first_task->regcfg_amount + RKNPU_PC_DATA_EXTRA_AMOUNT - 1,
|
||||
REG_WRITE(first_task->regcfg_amount +
|
||||
rknpu_dev->config->pc_data_extra_amount - 1,
|
||||
RKNPU_OFFSET_PC_DATA_AMOUNT);
|
||||
|
||||
REG_WRITE(last_task->int_mask, RKNPU_OFFSET_INT_MASK);
|
||||
|
||||
REG_WRITE(first_task->int_mask, RKNPU_OFFSET_INT_CLEAR);
|
||||
|
||||
REG_WRITE(((0x6 | task_pp_en) << 12) | args->task_number,
|
||||
REG_WRITE(((0x6 | task_pp_en) << 12) | task_number,
|
||||
RKNPU_OFFSET_PC_TASK_CONTROL);
|
||||
|
||||
REG_WRITE(0x0, RKNPU_OFFSET_PC_DMA_BASE_ADDR);
|
||||
|
||||
job->first_task = first_task;
|
||||
job->last_task = last_task;
|
||||
job->int_mask = last_task->int_mask;
|
||||
job->int_mask[core_index] = last_task->int_mask;
|
||||
|
||||
REG_WRITE(0x1, RKNPU_OFFSET_PC_OP_EN);
|
||||
REG_WRITE(0x0, RKNPU_OFFSET_PC_OP_EN);
|
||||
@@ -169,10 +242,11 @@ static inline int rknpu_job_commit_pc(struct rknpu_job *job)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rknpu_job_commit(struct rknpu_job *job)
|
||||
static int rknpu_job_commit(struct rknpu_job *job, int core_index)
|
||||
{
|
||||
struct rknpu_device *rknpu_dev = job->rknpu_dev;
|
||||
struct rknpu_submit *args = job->args;
|
||||
void __iomem *rknpu_core_base = rknpu_dev->base[core_index];
|
||||
|
||||
// switch to slave mode
|
||||
REG_WRITE(0x1, RKNPU_OFFSET_PC_DATA_ADDR);
|
||||
@@ -180,49 +254,73 @@ static int rknpu_job_commit(struct rknpu_job *job)
|
||||
if (!(args->flags & RKNPU_JOB_PC))
|
||||
return -EINVAL;
|
||||
|
||||
return rknpu_job_commit_pc(job);
|
||||
return rknpu_job_commit_pc(job, core_index);
|
||||
}
|
||||
|
||||
static void rknpu_job_next(struct rknpu_device *rknpu_dev)
|
||||
static void rknpu_job_next(struct rknpu_device *rknpu_dev, int core_index)
|
||||
{
|
||||
struct rknpu_job *job = NULL;
|
||||
struct rknpu_subcore_data *subcore_data = NULL;
|
||||
unsigned long flags;
|
||||
|
||||
subcore_data = &rknpu_dev->subcore_datas[core_index];
|
||||
|
||||
spin_lock_irqsave(&rknpu_dev->irq_lock, flags);
|
||||
|
||||
if (rknpu_dev->job || list_empty(&rknpu_dev->todo_list)) {
|
||||
if (subcore_data->job || list_empty(&subcore_data->todo_list)) {
|
||||
spin_unlock_irqrestore(&rknpu_dev->irq_lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
job = list_first_entry(&rknpu_dev->todo_list, struct rknpu_job, head);
|
||||
job = list_first_entry(&subcore_data->todo_list, struct rknpu_job,
|
||||
head[core_index]);
|
||||
|
||||
list_del_init(&job->head);
|
||||
list_del_init(&job->head[core_index]);
|
||||
|
||||
rknpu_dev->job = job;
|
||||
subcore_data->job = job;
|
||||
job->run_count--;
|
||||
|
||||
spin_unlock_irqrestore(&rknpu_dev->irq_lock, flags);
|
||||
|
||||
job->ret = rknpu_job_commit(job);
|
||||
if (job->run_count == 0) {
|
||||
if (job->args->core_mask & RKNPU_CORE0_MASK)
|
||||
job->ret = rknpu_job_commit(job, 0);
|
||||
if (job->args->core_mask & RKNPU_CORE1_MASK)
|
||||
job->ret = rknpu_job_commit(job, 1);
|
||||
if (job->args->core_mask & RKNPU_CORE2_MASK)
|
||||
job->ret = rknpu_job_commit(job, 2);
|
||||
}
|
||||
}
|
||||
|
||||
static void rknpu_job_done(struct rknpu_job *job, int ret)
|
||||
static void rknpu_job_done(struct rknpu_job *job, int ret, int core_index)
|
||||
{
|
||||
struct rknpu_device *rknpu_dev = job->rknpu_dev;
|
||||
struct rknpu_subcore_data *subcore_data = NULL;
|
||||
unsigned long flags;
|
||||
int task_num = 0;
|
||||
|
||||
subcore_data = &rknpu_dev->subcore_datas[core_index];
|
||||
task_num = rknn_get_task_number(job, core_index);
|
||||
spin_lock_irqsave(&rknpu_dev->irq_lock, flags);
|
||||
rknpu_dev->job = NULL;
|
||||
subcore_data->job = NULL;
|
||||
subcore_data->task_num = subcore_data->task_num - task_num;
|
||||
job->interrupt_count--;
|
||||
spin_unlock_irqrestore(&rknpu_dev->irq_lock, flags);
|
||||
|
||||
job->flags |= RKNPU_JOB_DONE;
|
||||
job->ret = ret;
|
||||
if (job->interrupt_count == 0) {
|
||||
job->flags |= RKNPU_JOB_DONE;
|
||||
job->ret = ret;
|
||||
|
||||
if (job->fence)
|
||||
dma_fence_signal(job->fence);
|
||||
if (job->fence)
|
||||
dma_fence_signal(job->fence);
|
||||
|
||||
wake_up(&rknpu_dev->job_done_wq);
|
||||
rknpu_job_next(rknpu_dev);
|
||||
if (job->use_core_num > 1)
|
||||
wake_up(&(&rknpu_dev->subcore_datas[0])->job_done_wq);
|
||||
else
|
||||
wake_up(&subcore_data->job_done_wq);
|
||||
}
|
||||
|
||||
rknpu_job_next(rknpu_dev, core_index);
|
||||
|
||||
if (job->flags & RKNPU_JOB_ASYNC)
|
||||
schedule_work(&job->cleanup_work);
|
||||
@@ -231,28 +329,97 @@ static void rknpu_job_done(struct rknpu_job *job, int ret)
|
||||
static void rknpu_job_schedule(struct rknpu_job *job)
|
||||
{
|
||||
struct rknpu_device *rknpu_dev = job->rknpu_dev;
|
||||
struct rknpu_subcore_data *subcore_data = NULL;
|
||||
int i = 0, core_index = 0;
|
||||
unsigned long flags;
|
||||
int task_num_list[3] = { 0, 1, 2 };
|
||||
int task_num = 0;
|
||||
int tmp = 0;
|
||||
|
||||
if ((job->args->core_mask & 0x07) == RKNPU_CORE_AUTO_MASK) {
|
||||
if (rknpu_dev->subcore_datas[0].task_num >
|
||||
rknpu_dev->subcore_datas[1].task_num) {
|
||||
tmp = task_num_list[1];
|
||||
task_num_list[1] = task_num_list[0];
|
||||
task_num_list[0] = tmp;
|
||||
}
|
||||
if (rknpu_dev->subcore_datas[task_num_list[0]].task_num >
|
||||
rknpu_dev->subcore_datas[2].task_num) {
|
||||
tmp = task_num_list[2];
|
||||
task_num_list[2] = task_num_list[1];
|
||||
task_num_list[1] = task_num_list[0];
|
||||
task_num_list[0] = tmp;
|
||||
} else if (rknpu_dev->subcore_datas[task_num_list[1]].task_num >
|
||||
rknpu_dev->subcore_datas[2].task_num) {
|
||||
tmp = task_num_list[2];
|
||||
task_num_list[2] = task_num_list[1];
|
||||
task_num_list[1] = tmp;
|
||||
}
|
||||
if (!rknpu_dev->subcore_datas[task_num_list[0]].job)
|
||||
core_index = task_num_list[0];
|
||||
else if (!rknpu_dev->subcore_datas[task_num_list[1]].job)
|
||||
core_index = task_num_list[1];
|
||||
else if (!rknpu_dev->subcore_datas[task_num_list[2]].job)
|
||||
core_index = task_num_list[2];
|
||||
else
|
||||
core_index = task_num_list[0];
|
||||
|
||||
job->args->core_mask = rknpu_core_mask(core_index);
|
||||
job->use_core_num = 1;
|
||||
job->interrupt_count = 1;
|
||||
job->run_count = 1;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&rknpu_dev->irq_lock, flags);
|
||||
list_add_tail(&job->head, &rknpu_dev->todo_list);
|
||||
for (i = 0; i < rknpu_dev->config->num_irqs; i++) {
|
||||
if (job->args->core_mask & rknpu_core_mask(i)) {
|
||||
subcore_data = &rknpu_dev->subcore_datas[i];
|
||||
task_num = rknn_get_task_number(job, i);
|
||||
subcore_data->task_num =
|
||||
subcore_data->task_num + task_num;
|
||||
list_add_tail(&job->head[i], &subcore_data->todo_list);
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&rknpu_dev->irq_lock, flags);
|
||||
|
||||
rknpu_job_next(rknpu_dev);
|
||||
for (i = 0; i < rknpu_dev->config->num_irqs; i++) {
|
||||
if (job->args->core_mask & rknpu_core_mask(i))
|
||||
rknpu_job_next(rknpu_dev, i);
|
||||
}
|
||||
}
|
||||
|
||||
static void rknpu_job_abort(struct rknpu_job *job)
|
||||
{
|
||||
struct rknpu_device *rknpu_dev = job->rknpu_dev;
|
||||
struct rknpu_subcore_data *subcore_data = NULL;
|
||||
int core_index = rknpu_core_index(job->args->core_mask);
|
||||
void __iomem *rknpu_core_base = rknpu_dev->base[core_index];
|
||||
unsigned long flags;
|
||||
int i = 0;
|
||||
int task_num = 0;
|
||||
|
||||
msleep(100);
|
||||
if (job->ret == -ETIMEDOUT)
|
||||
if (job->ret == -ETIMEDOUT) {
|
||||
LOG_ERROR(
|
||||
"job timeout, irq status: %#x, raw status: %#x, require mask: %#x\n",
|
||||
REG_READ(RKNPU_OFFSET_INT_STATUS),
|
||||
REG_READ(RKNPU_OFFSET_INT_RAW_STATUS),
|
||||
job->int_mask[core_index]);
|
||||
rknpu_soft_reset(rknpu_dev);
|
||||
|
||||
if (job == rknpu_dev->job) {
|
||||
spin_lock_irqsave(&rknpu_dev->irq_lock, flags);
|
||||
rknpu_dev->job = NULL;
|
||||
spin_unlock_irqrestore(&rknpu_dev->irq_lock, flags);
|
||||
}
|
||||
for (i = 0; i < rknpu_dev->config->num_irqs; i++) {
|
||||
if (job->args->core_mask & rknpu_core_mask(i)) {
|
||||
subcore_data = &rknpu_dev->subcore_datas[i];
|
||||
if (job == subcore_data->job) {
|
||||
spin_lock_irqsave(&rknpu_dev->irq_lock, flags);
|
||||
task_num = rknn_get_task_number(job, i);
|
||||
subcore_data->job = NULL;
|
||||
subcore_data->task_num =
|
||||
subcore_data->task_num - task_num;
|
||||
spin_unlock_irqrestore(&rknpu_dev->irq_lock,
|
||||
flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rknpu_job_cleanup(job);
|
||||
@@ -283,10 +450,11 @@ static inline uint32_t rknpu_fuzz_status(uint32_t status)
|
||||
return fuzz_status;
|
||||
}
|
||||
|
||||
irqreturn_t rknpu_irq_handler(int irq, void *data)
|
||||
static inline irqreturn_t rknpu_irq_handler(int irq, void *data, int core_index)
|
||||
{
|
||||
struct rknpu_device *rknpu_dev = data;
|
||||
struct rknpu_job *job = rknpu_dev->job;
|
||||
struct rknpu_job *job = rknpu_dev->subcore_datas[core_index].job;
|
||||
void __iomem *rknpu_core_base = rknpu_dev->base[core_index];
|
||||
uint32_t status = 0;
|
||||
|
||||
if (!job)
|
||||
@@ -295,49 +463,81 @@ irqreturn_t rknpu_irq_handler(int irq, void *data)
|
||||
status = REG_READ(RKNPU_OFFSET_INT_STATUS);
|
||||
REG_WRITE(RKNPU_INT_CLEAR, RKNPU_OFFSET_INT_CLEAR);
|
||||
|
||||
job->int_status = status;
|
||||
job->int_status[core_index] = status;
|
||||
|
||||
if (rknpu_fuzz_status(status) != job->int_mask) {
|
||||
LOG_DEBUG("irq: status = %#x, mask = %#x\n", status,
|
||||
job->int_mask);
|
||||
if (rknpu_fuzz_status(status) != job->int_mask[core_index]) {
|
||||
LOG_ERROR(
|
||||
"invalid irq status: %#x, raw status: %#x, require mask: %#x\n",
|
||||
status, REG_READ(RKNPU_OFFSET_INT_RAW_STATUS),
|
||||
job->int_mask[core_index]);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
rknpu_job_done(job, 0);
|
||||
rknpu_job_done(job, 0, core_index);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void rknpu_job_timeout_clean(struct rknpu_device *rknpu_dev)
|
||||
irqreturn_t rknpu_core0_irq_handler(int irq, void *data)
|
||||
{
|
||||
return rknpu_irq_handler(irq, data, 0);
|
||||
}
|
||||
|
||||
irqreturn_t rknpu_core1_irq_handler(int irq, void *data)
|
||||
{
|
||||
return rknpu_irq_handler(irq, data, 1);
|
||||
}
|
||||
|
||||
irqreturn_t rknpu_core2_irq_handler(int irq, void *data)
|
||||
{
|
||||
return rknpu_irq_handler(irq, data, 2);
|
||||
}
|
||||
|
||||
static void rknpu_job_timeout_clean(struct rknpu_device *rknpu_dev,
|
||||
int core_mask)
|
||||
{
|
||||
struct rknpu_job *job = NULL;
|
||||
unsigned long flags;
|
||||
ktime_t now = ktime_get();
|
||||
struct rknpu_subcore_data *subcore_data = NULL;
|
||||
int i = 0;
|
||||
|
||||
job = rknpu_dev->job;
|
||||
if (job &&
|
||||
ktime_to_ms(ktime_sub(now, job->timestamp)) >= job->args->timeout) {
|
||||
rknpu_soft_reset(rknpu_dev);
|
||||
for (i = 0; i < rknpu_dev->config->num_irqs; i++) {
|
||||
if (core_mask & rknpu_core_mask(i)) {
|
||||
subcore_data = &rknpu_dev->subcore_datas[i];
|
||||
job = subcore_data->job;
|
||||
if (job &&
|
||||
ktime_to_ms(ktime_sub(now, job->timestamp)) >=
|
||||
job->args->timeout) {
|
||||
rknpu_soft_reset(rknpu_dev);
|
||||
|
||||
spin_lock_irqsave(&rknpu_dev->irq_lock, flags);
|
||||
rknpu_dev->job = NULL;
|
||||
spin_unlock_irqrestore(&rknpu_dev->irq_lock, flags);
|
||||
spin_lock_irqsave(&rknpu_dev->irq_lock, flags);
|
||||
subcore_data->job = NULL;
|
||||
spin_unlock_irqrestore(&rknpu_dev->irq_lock,
|
||||
flags);
|
||||
|
||||
do {
|
||||
schedule_work(&job->cleanup_work);
|
||||
do {
|
||||
schedule_work(&job->cleanup_work);
|
||||
|
||||
spin_lock_irqsave(&rknpu_dev->irq_lock, flags);
|
||||
spin_lock_irqsave(&rknpu_dev->irq_lock,
|
||||
flags);
|
||||
|
||||
if (!list_empty(&rknpu_dev->todo_list)) {
|
||||
job = list_first_entry(&rknpu_dev->todo_list,
|
||||
struct rknpu_job, head);
|
||||
list_del_init(&job->head);
|
||||
} else {
|
||||
job = NULL;
|
||||
if (!list_empty(
|
||||
&subcore_data->todo_list)) {
|
||||
job = list_first_entry(
|
||||
&subcore_data->todo_list,
|
||||
struct rknpu_job,
|
||||
head[i]);
|
||||
list_del_init(&job->head[i]);
|
||||
} else {
|
||||
job = NULL;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(
|
||||
&rknpu_dev->irq_lock, flags);
|
||||
} while (job);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&rknpu_dev->irq_lock, flags);
|
||||
} while (job);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -360,7 +560,38 @@ int rknpu_submit_ioctl(struct drm_device *dev, void *data,
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (args->flags & RKNPU_JOB_FENCE) {
|
||||
if (args->flags & RKNPU_JOB_FENCE_IN) {
|
||||
struct dma_fence *in_fence;
|
||||
|
||||
in_fence = sync_file_get_fence(args->fence_fd);
|
||||
|
||||
if (!in_fence) {
|
||||
LOG_ERROR("invalid fence in fd, fd = %d\n",
|
||||
args->fence_fd);
|
||||
return -EINVAL;
|
||||
}
|
||||
args->fence_fd = -1;
|
||||
|
||||
/*
|
||||
* Wait if the fence is from a foreign context, or if the fence
|
||||
* array contains any fence from a foreign context.
|
||||
*/
|
||||
ret = 0;
|
||||
if (!dma_fence_match_context(in_fence,
|
||||
rknpu_dev->fence_ctx->context))
|
||||
ret = dma_fence_wait_timeout(in_fence, true,
|
||||
args->timeout);
|
||||
dma_fence_put(in_fence);
|
||||
if (ret < 0) {
|
||||
if (ret != -ERESTARTSYS)
|
||||
LOG_ERROR("Error (%d) waiting for fence!\n",
|
||||
ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (args->flags & RKNPU_JOB_FENCE_OUT) {
|
||||
ret = rknpu_fence_alloc(job);
|
||||
if (ret) {
|
||||
rknpu_job_free(job);
|
||||
@@ -372,7 +603,7 @@ int rknpu_submit_ioctl(struct drm_device *dev, void *data,
|
||||
|
||||
if (args->flags & RKNPU_JOB_NONBLOCK) {
|
||||
job->flags |= RKNPU_JOB_ASYNC;
|
||||
rknpu_job_timeout_clean(rknpu_dev);
|
||||
rknpu_job_timeout_clean(rknpu_dev, job->args->core_mask);
|
||||
rknpu_job_schedule(job);
|
||||
ret = job->ret;
|
||||
if (ret) {
|
||||
@@ -397,6 +628,8 @@ int rknpu_submit_ioctl(struct drm_device *dev, void *data,
|
||||
|
||||
int rknpu_get_hw_version(struct rknpu_device *rknpu_dev, uint32_t *version)
|
||||
{
|
||||
void __iomem *rknpu_core_base = rknpu_dev->base[0];
|
||||
|
||||
if (version != NULL)
|
||||
*version = REG_READ(RKNPU_OFFSET_VERSION);
|
||||
|
||||
@@ -408,6 +641,11 @@ int rknpu_get_bw_priority(struct rknpu_device *rknpu_dev, uint32_t *priority,
|
||||
{
|
||||
void __iomem *base = rknpu_dev->bw_priority_base;
|
||||
|
||||
if (!rknpu_dev->config->bw_enable) {
|
||||
LOG_WARN("Get bw_priority is not supported on this device!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!base)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -432,6 +670,11 @@ int rknpu_set_bw_priority(struct rknpu_device *rknpu_dev, uint32_t priority,
|
||||
{
|
||||
void __iomem *base = rknpu_dev->bw_priority_base;
|
||||
|
||||
if (!rknpu_dev->config->bw_enable) {
|
||||
LOG_WARN("Set bw_priority is not supported on this device!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!base)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -453,6 +696,13 @@ int rknpu_set_bw_priority(struct rknpu_device *rknpu_dev, uint32_t priority,
|
||||
|
||||
int rknpu_clear_rw_amount(struct rknpu_device *rknpu_dev)
|
||||
{
|
||||
void __iomem *rknpu_core_base = rknpu_dev->base[0];
|
||||
|
||||
if (!rknpu_dev->config->bw_enable) {
|
||||
LOG_WARN("Clear rw_amount is not supported on this device!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
spin_lock(&rknpu_dev->lock);
|
||||
|
||||
REG_WRITE(0x80000101, RKNPU_OFFSET_CLR_ALL_RW_AMOUNT);
|
||||
@@ -466,6 +716,13 @@ int rknpu_clear_rw_amount(struct rknpu_device *rknpu_dev)
|
||||
int rknpu_get_rw_amount(struct rknpu_device *rknpu_dev, uint32_t *dt_wr,
|
||||
uint32_t *dt_rd, uint32_t *wd_rd)
|
||||
{
|
||||
void __iomem *rknpu_core_base = rknpu_dev->base[0];
|
||||
|
||||
if (!rknpu_dev->config->bw_enable) {
|
||||
LOG_WARN("Get rw_amount is not supported on this device!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
spin_lock(&rknpu_dev->lock);
|
||||
|
||||
if (dt_wr != NULL)
|
||||
@@ -489,6 +746,12 @@ int rknpu_get_total_rw_amount(struct rknpu_device *rknpu_dev, uint32_t *amount)
|
||||
uint32_t wd_rd = 0;
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (!rknpu_dev->config->bw_enable) {
|
||||
LOG_WARN(
|
||||
"Get total_rw_amount is not supported on this device!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = rknpu_get_rw_amount(rknpu_dev, &dt_wr, &dt_rd, &wd_rd);
|
||||
|
||||
if (amount != NULL)
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "rknpu_reset.h"
|
||||
|
||||
#ifndef FPGA_PLATFORM
|
||||
static inline struct reset_control *rknpu_reset_control_get(struct device *dev,
|
||||
const char *name)
|
||||
{
|
||||
@@ -22,27 +23,38 @@ static inline struct reset_control *rknpu_reset_control_get(struct device *dev,
|
||||
|
||||
return rst;
|
||||
}
|
||||
#endif
|
||||
|
||||
int rknpu_reset_get(struct rknpu_device *rknpu_dev)
|
||||
{
|
||||
#ifndef FPGA_PLATFORM
|
||||
struct reset_control *srst_a = NULL;
|
||||
struct reset_control *srst_h = NULL;
|
||||
int i = 0;
|
||||
|
||||
srst_a = rknpu_reset_control_get(rknpu_dev->dev, "srst_a");
|
||||
if (IS_ERR(srst_a))
|
||||
return PTR_ERR(srst_a);
|
||||
for (i = 0; i < rknpu_dev->config->num_resets; i++) {
|
||||
srst_a = rknpu_reset_control_get(
|
||||
rknpu_dev->dev,
|
||||
rknpu_dev->config->resets[i].srst_a_name);
|
||||
if (IS_ERR(srst_a))
|
||||
return PTR_ERR(srst_a);
|
||||
|
||||
rknpu_dev->srst_a = srst_a;
|
||||
rknpu_dev->srst_a[i] = srst_a;
|
||||
|
||||
srst_h = devm_reset_control_get(rknpu_dev->dev, "srst_h");
|
||||
if (IS_ERR(srst_h))
|
||||
return PTR_ERR(srst_h);
|
||||
srst_h = rknpu_reset_control_get(
|
||||
rknpu_dev->dev,
|
||||
rknpu_dev->config->resets[i].srst_h_name);
|
||||
if (IS_ERR(srst_h))
|
||||
return PTR_ERR(srst_h);
|
||||
|
||||
rknpu_dev->srst_h = srst_h;
|
||||
rknpu_dev->srst_h[i] = srst_h;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef FPGA_PLATFORM
|
||||
static int rknpu_reset_assert(struct reset_control *rst)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
@@ -74,11 +86,13 @@ static int rknpu_reset_deassert(struct reset_control *rst)
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int rknpu_soft_reset(struct rknpu_device *rknpu_dev)
|
||||
{
|
||||
#ifndef FPGA_PLATFORM
|
||||
struct iommu_domain *domain = NULL;
|
||||
int ret = -EINVAL;
|
||||
int ret = -EINVAL, i = 0;
|
||||
|
||||
if (rknpu_dev->bypass_soft_reset) {
|
||||
LOG_WARN("bypass soft reset\n");
|
||||
@@ -87,13 +101,15 @@ int rknpu_soft_reset(struct rknpu_device *rknpu_dev)
|
||||
|
||||
LOG_INFO("soft reset\n");
|
||||
|
||||
ret = rknpu_reset_assert(rknpu_dev->srst_a);
|
||||
ret |= rknpu_reset_assert(rknpu_dev->srst_h);
|
||||
for (i = 0; i < rknpu_dev->config->num_resets; i++) {
|
||||
ret = rknpu_reset_assert(rknpu_dev->srst_a[i]);
|
||||
ret |= rknpu_reset_assert(rknpu_dev->srst_h[i]);
|
||||
|
||||
udelay(10);
|
||||
udelay(10);
|
||||
|
||||
ret |= rknpu_reset_deassert(rknpu_dev->srst_a);
|
||||
ret |= rknpu_reset_deassert(rknpu_dev->srst_h);
|
||||
ret |= rknpu_reset_deassert(rknpu_dev->srst_a[i]);
|
||||
ret |= rknpu_reset_deassert(rknpu_dev->srst_h[i]);
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
LOG_DEV_ERROR(rknpu_dev->dev,
|
||||
@@ -108,6 +124,7 @@ int rknpu_soft_reset(struct rknpu_device *rknpu_dev)
|
||||
iommu_detach_device(domain, rknpu_dev->dev);
|
||||
iommu_attach_device(domain, rknpu_dev->dev);
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user