15a5e9c02SRob Herring (Arm) // SPDX-License-Identifier: GPL-2.0-only OR MIT 25a5e9c02SRob Herring (Arm) /* Copyright 2024-2025 Tomeu Vizoso <tomeu@tomeuvizoso.net> */ 35a5e9c02SRob Herring (Arm) /* Copyright 2025 Arm, Ltd. */ 45a5e9c02SRob Herring (Arm) 55a5e9c02SRob Herring (Arm) #include <linux/bitfield.h> 65a5e9c02SRob Herring (Arm) #include <linux/genalloc.h> 75a5e9c02SRob Herring (Arm) #include <linux/interrupt.h> 85a5e9c02SRob Herring (Arm) #include <linux/iopoll.h> 95a5e9c02SRob Herring (Arm) #include <linux/platform_device.h> 105a5e9c02SRob Herring (Arm) #include <linux/pm_runtime.h> 115a5e9c02SRob Herring (Arm) 125a5e9c02SRob Herring (Arm) #include <drm/drm_file.h> 135a5e9c02SRob Herring (Arm) #include <drm/drm_gem.h> 145a5e9c02SRob Herring (Arm) #include <drm/drm_gem_dma_helper.h> 15*f6e8dc9eSJani Nikula #include <drm/drm_print.h> 165a5e9c02SRob Herring (Arm) #include <drm/ethosu_accel.h> 175a5e9c02SRob Herring (Arm) 185a5e9c02SRob Herring (Arm) #include "ethosu_device.h" 195a5e9c02SRob Herring (Arm) #include "ethosu_drv.h" 205a5e9c02SRob Herring (Arm) #include "ethosu_gem.h" 215a5e9c02SRob Herring (Arm) #include "ethosu_job.h" 225a5e9c02SRob Herring (Arm) 235a5e9c02SRob Herring (Arm) #define JOB_TIMEOUT_MS 500 245a5e9c02SRob Herring (Arm) 255a5e9c02SRob Herring (Arm) static struct ethosu_job *to_ethosu_job(struct drm_sched_job *sched_job) 265a5e9c02SRob Herring (Arm) { 275a5e9c02SRob Herring (Arm) return container_of(sched_job, struct ethosu_job, base); 285a5e9c02SRob Herring (Arm) } 295a5e9c02SRob Herring (Arm) 305a5e9c02SRob Herring (Arm) static const char *ethosu_fence_get_driver_name(struct dma_fence *fence) 315a5e9c02SRob Herring (Arm) { 325a5e9c02SRob Herring (Arm) return "ethosu"; 335a5e9c02SRob Herring (Arm) } 345a5e9c02SRob Herring (Arm) 355a5e9c02SRob Herring (Arm) static const char *ethosu_fence_get_timeline_name(struct dma_fence *fence) 365a5e9c02SRob Herring (Arm) { 375a5e9c02SRob Herring (Arm) return "ethosu-npu"; 385a5e9c02SRob Herring (Arm) } 395a5e9c02SRob Herring (Arm) 405a5e9c02SRob Herring (Arm) static const struct dma_fence_ops ethosu_fence_ops = { 415a5e9c02SRob Herring (Arm) .get_driver_name = ethosu_fence_get_driver_name, 425a5e9c02SRob Herring (Arm) .get_timeline_name = ethosu_fence_get_timeline_name, 435a5e9c02SRob Herring (Arm) }; 445a5e9c02SRob Herring (Arm) 455a5e9c02SRob Herring (Arm) static void ethosu_job_hw_submit(struct ethosu_device *dev, struct ethosu_job *job) 465a5e9c02SRob Herring (Arm) { 475a5e9c02SRob Herring (Arm) struct drm_gem_dma_object *cmd_bo = to_drm_gem_dma_obj(job->cmd_bo); 485a5e9c02SRob Herring (Arm) struct ethosu_validated_cmdstream_info *cmd_info = to_ethosu_bo(job->cmd_bo)->info; 495a5e9c02SRob Herring (Arm) 505a5e9c02SRob Herring (Arm) for (int i = 0; i < job->region_cnt; i++) { 515a5e9c02SRob Herring (Arm) struct drm_gem_dma_object *bo; 525a5e9c02SRob Herring (Arm) int region = job->region_bo_num[i]; 535a5e9c02SRob Herring (Arm) 545a5e9c02SRob Herring (Arm) bo = to_drm_gem_dma_obj(job->region_bo[i]); 555a5e9c02SRob Herring (Arm) writel_relaxed(lower_32_bits(bo->dma_addr), dev->regs + NPU_REG_BASEP(region)); 565a5e9c02SRob Herring (Arm) writel_relaxed(upper_32_bits(bo->dma_addr), dev->regs + NPU_REG_BASEP_HI(region)); 575a5e9c02SRob Herring (Arm) dev_dbg(dev->base.dev, "Region %d base addr = %pad\n", region, &bo->dma_addr); 585a5e9c02SRob Herring (Arm) } 595a5e9c02SRob Herring (Arm) 605a5e9c02SRob Herring (Arm) if (job->sram_size) { 615a5e9c02SRob Herring (Arm) writel_relaxed(lower_32_bits(dev->sramphys), 625a5e9c02SRob Herring (Arm) dev->regs + NPU_REG_BASEP(ETHOSU_SRAM_REGION)); 635a5e9c02SRob Herring (Arm) writel_relaxed(upper_32_bits(dev->sramphys), 645a5e9c02SRob Herring (Arm) dev->regs + NPU_REG_BASEP_HI(ETHOSU_SRAM_REGION)); 655a5e9c02SRob Herring (Arm) dev_dbg(dev->base.dev, "Region %d base addr = %pad (SRAM)\n", 665a5e9c02SRob Herring (Arm) ETHOSU_SRAM_REGION, &dev->sramphys); 675a5e9c02SRob Herring (Arm) } 685a5e9c02SRob Herring (Arm) 695a5e9c02SRob Herring (Arm) writel_relaxed(lower_32_bits(cmd_bo->dma_addr), dev->regs + NPU_REG_QBASE); 705a5e9c02SRob Herring (Arm) writel_relaxed(upper_32_bits(cmd_bo->dma_addr), dev->regs + NPU_REG_QBASE_HI); 715a5e9c02SRob Herring (Arm) writel_relaxed(cmd_info->cmd_size, dev->regs + NPU_REG_QSIZE); 725a5e9c02SRob Herring (Arm) 735a5e9c02SRob Herring (Arm) writel(CMD_TRANSITION_TO_RUN, dev->regs + NPU_REG_CMD); 745a5e9c02SRob Herring (Arm) 755a5e9c02SRob Herring (Arm) dev_dbg(dev->base.dev, 765a5e9c02SRob Herring (Arm) "Submitted cmd at %pad to core\n", &cmd_bo->dma_addr); 775a5e9c02SRob Herring (Arm) } 785a5e9c02SRob Herring (Arm) 795a5e9c02SRob Herring (Arm) static int ethosu_acquire_object_fences(struct ethosu_job *job) 805a5e9c02SRob Herring (Arm) { 815a5e9c02SRob Herring (Arm) int i, ret; 825a5e9c02SRob Herring (Arm) struct drm_gem_object **bos = job->region_bo; 835a5e9c02SRob Herring (Arm) struct ethosu_validated_cmdstream_info *info = to_ethosu_bo(job->cmd_bo)->info; 845a5e9c02SRob Herring (Arm) 855a5e9c02SRob Herring (Arm) for (i = 0; i < job->region_cnt; i++) { 865a5e9c02SRob Herring (Arm) bool is_write; 875a5e9c02SRob Herring (Arm) 885a5e9c02SRob Herring (Arm) if (!bos[i]) 895a5e9c02SRob Herring (Arm) break; 905a5e9c02SRob Herring (Arm) 915a5e9c02SRob Herring (Arm) ret = dma_resv_reserve_fences(bos[i]->resv, 1); 925a5e9c02SRob Herring (Arm) if (ret) 935a5e9c02SRob Herring (Arm) return ret; 945a5e9c02SRob Herring (Arm) 955a5e9c02SRob Herring (Arm) is_write = info->output_region[job->region_bo_num[i]]; 965a5e9c02SRob Herring (Arm) ret = drm_sched_job_add_implicit_dependencies(&job->base, bos[i], 975a5e9c02SRob Herring (Arm) is_write); 985a5e9c02SRob Herring (Arm) if (ret) 995a5e9c02SRob Herring (Arm) return ret; 1005a5e9c02SRob Herring (Arm) } 1015a5e9c02SRob Herring (Arm) 1025a5e9c02SRob Herring (Arm) return 0; 1035a5e9c02SRob Herring (Arm) } 1045a5e9c02SRob Herring (Arm) 1055a5e9c02SRob Herring (Arm) static void ethosu_attach_object_fences(struct ethosu_job *job) 1065a5e9c02SRob Herring (Arm) { 1075a5e9c02SRob Herring (Arm) int i; 1085a5e9c02SRob Herring (Arm) struct dma_fence *fence = job->inference_done_fence; 1095a5e9c02SRob Herring (Arm) struct drm_gem_object **bos = job->region_bo; 1105a5e9c02SRob Herring (Arm) struct ethosu_validated_cmdstream_info *info = to_ethosu_bo(job->cmd_bo)->info; 1115a5e9c02SRob Herring (Arm) 1125a5e9c02SRob Herring (Arm) for (i = 0; i < job->region_cnt; i++) 1135a5e9c02SRob Herring (Arm) if (info->output_region[job->region_bo_num[i]]) 1145a5e9c02SRob Herring (Arm) dma_resv_add_fence(bos[i]->resv, fence, DMA_RESV_USAGE_WRITE); 1155a5e9c02SRob Herring (Arm) } 1165a5e9c02SRob Herring (Arm) 1175a5e9c02SRob Herring (Arm) static int ethosu_job_push(struct ethosu_job *job) 1185a5e9c02SRob Herring (Arm) { 1195a5e9c02SRob Herring (Arm) struct ww_acquire_ctx acquire_ctx; 1205a5e9c02SRob Herring (Arm) int ret; 1215a5e9c02SRob Herring (Arm) 1225a5e9c02SRob Herring (Arm) ret = drm_gem_lock_reservations(job->region_bo, job->region_cnt, &acquire_ctx); 1235a5e9c02SRob Herring (Arm) if (ret) 1245a5e9c02SRob Herring (Arm) return ret; 1255a5e9c02SRob Herring (Arm) 1265a5e9c02SRob Herring (Arm) ret = ethosu_acquire_object_fences(job); 1275a5e9c02SRob Herring (Arm) if (ret) 1285a5e9c02SRob Herring (Arm) goto out; 1295a5e9c02SRob Herring (Arm) 1305a5e9c02SRob Herring (Arm) ret = pm_runtime_resume_and_get(job->dev->base.dev); 1315a5e9c02SRob Herring (Arm) if (!ret) { 1325a5e9c02SRob Herring (Arm) guard(mutex)(&job->dev->sched_lock); 1335a5e9c02SRob Herring (Arm) 1345a5e9c02SRob Herring (Arm) drm_sched_job_arm(&job->base); 1355a5e9c02SRob Herring (Arm) job->inference_done_fence = dma_fence_get(&job->base.s_fence->finished); 1365a5e9c02SRob Herring (Arm) kref_get(&job->refcount); /* put by scheduler job completion */ 1375a5e9c02SRob Herring (Arm) drm_sched_entity_push_job(&job->base); 1385a5e9c02SRob Herring (Arm) ethosu_attach_object_fences(job); 1395a5e9c02SRob Herring (Arm) } 1405a5e9c02SRob Herring (Arm) 1415a5e9c02SRob Herring (Arm) out: 1425a5e9c02SRob Herring (Arm) drm_gem_unlock_reservations(job->region_bo, job->region_cnt, &acquire_ctx); 1435a5e9c02SRob Herring (Arm) return ret; 1445a5e9c02SRob Herring (Arm) } 1455a5e9c02SRob Herring (Arm) 1465a5e9c02SRob Herring (Arm) static void ethosu_job_cleanup(struct kref *ref) 1475a5e9c02SRob Herring (Arm) { 1485a5e9c02SRob Herring (Arm) struct ethosu_job *job = container_of(ref, struct ethosu_job, 1495a5e9c02SRob Herring (Arm) refcount); 1505a5e9c02SRob Herring (Arm) unsigned int i; 1515a5e9c02SRob Herring (Arm) 1525a5e9c02SRob Herring (Arm) pm_runtime_put_autosuspend(job->dev->base.dev); 1535a5e9c02SRob Herring (Arm) 1545a5e9c02SRob Herring (Arm) dma_fence_put(job->done_fence); 1555a5e9c02SRob Herring (Arm) dma_fence_put(job->inference_done_fence); 1565a5e9c02SRob Herring (Arm) 1575a5e9c02SRob Herring (Arm) for (i = 0; i < job->region_cnt; i++) 1585a5e9c02SRob Herring (Arm) drm_gem_object_put(job->region_bo[i]); 1595a5e9c02SRob Herring (Arm) 1605a5e9c02SRob Herring (Arm) drm_gem_object_put(job->cmd_bo); 1615a5e9c02SRob Herring (Arm) 1625a5e9c02SRob Herring (Arm) kfree(job); 1635a5e9c02SRob Herring (Arm) } 1645a5e9c02SRob Herring (Arm) 1655a5e9c02SRob Herring (Arm) static void ethosu_job_put(struct ethosu_job *job) 1665a5e9c02SRob Herring (Arm) { 1675a5e9c02SRob Herring (Arm) kref_put(&job->refcount, ethosu_job_cleanup); 1685a5e9c02SRob Herring (Arm) } 1695a5e9c02SRob Herring (Arm) 1705a5e9c02SRob Herring (Arm) static void ethosu_job_free(struct drm_sched_job *sched_job) 1715a5e9c02SRob Herring (Arm) { 1725a5e9c02SRob Herring (Arm) struct ethosu_job *job = to_ethosu_job(sched_job); 1735a5e9c02SRob Herring (Arm) 1745a5e9c02SRob Herring (Arm) drm_sched_job_cleanup(sched_job); 1755a5e9c02SRob Herring (Arm) ethosu_job_put(job); 1765a5e9c02SRob Herring (Arm) } 1775a5e9c02SRob Herring (Arm) 1785a5e9c02SRob Herring (Arm) static struct dma_fence *ethosu_job_run(struct drm_sched_job *sched_job) 1795a5e9c02SRob Herring (Arm) { 1805a5e9c02SRob Herring (Arm) struct ethosu_job *job = to_ethosu_job(sched_job); 1815a5e9c02SRob Herring (Arm) struct ethosu_device *dev = job->dev; 1825a5e9c02SRob Herring (Arm) struct dma_fence *fence = job->done_fence; 1835a5e9c02SRob Herring (Arm) 1845a5e9c02SRob Herring (Arm) if (unlikely(job->base.s_fence->finished.error)) 1855a5e9c02SRob Herring (Arm) return NULL; 1865a5e9c02SRob Herring (Arm) 1875a5e9c02SRob Herring (Arm) dma_fence_init(fence, ðosu_fence_ops, &dev->fence_lock, 1885a5e9c02SRob Herring (Arm) dev->fence_context, ++dev->emit_seqno); 1895a5e9c02SRob Herring (Arm) dma_fence_get(fence); 1905a5e9c02SRob Herring (Arm) 1915a5e9c02SRob Herring (Arm) scoped_guard(mutex, &dev->job_lock) { 1925a5e9c02SRob Herring (Arm) dev->in_flight_job = job; 1935a5e9c02SRob Herring (Arm) ethosu_job_hw_submit(dev, job); 1945a5e9c02SRob Herring (Arm) } 1955a5e9c02SRob Herring (Arm) 1965a5e9c02SRob Herring (Arm) return fence; 1975a5e9c02SRob Herring (Arm) } 1985a5e9c02SRob Herring (Arm) 1995a5e9c02SRob Herring (Arm) static void ethosu_job_handle_irq(struct ethosu_device *dev) 2005a5e9c02SRob Herring (Arm) { 2015a5e9c02SRob Herring (Arm) u32 status = readl_relaxed(dev->regs + NPU_REG_STATUS); 2025a5e9c02SRob Herring (Arm) 2035a5e9c02SRob Herring (Arm) if (status & (STATUS_BUS_STATUS | STATUS_CMD_PARSE_ERR)) { 2045a5e9c02SRob Herring (Arm) dev_err(dev->base.dev, "Error IRQ - %x\n", status); 2055a5e9c02SRob Herring (Arm) drm_sched_fault(&dev->sched); 2065a5e9c02SRob Herring (Arm) return; 2075a5e9c02SRob Herring (Arm) } 2085a5e9c02SRob Herring (Arm) 2095a5e9c02SRob Herring (Arm) scoped_guard(mutex, &dev->job_lock) { 2105a5e9c02SRob Herring (Arm) if (dev->in_flight_job) { 2115a5e9c02SRob Herring (Arm) dma_fence_signal(dev->in_flight_job->done_fence); 2125a5e9c02SRob Herring (Arm) dev->in_flight_job = NULL; 2135a5e9c02SRob Herring (Arm) } 2145a5e9c02SRob Herring (Arm) } 2155a5e9c02SRob Herring (Arm) } 2165a5e9c02SRob Herring (Arm) 2175a5e9c02SRob Herring (Arm) static irqreturn_t ethosu_job_irq_handler_thread(int irq, void *data) 2185a5e9c02SRob Herring (Arm) { 2195a5e9c02SRob Herring (Arm) struct ethosu_device *dev = data; 2205a5e9c02SRob Herring (Arm) 2215a5e9c02SRob Herring (Arm) ethosu_job_handle_irq(dev); 2225a5e9c02SRob Herring (Arm) 2235a5e9c02SRob Herring (Arm) return IRQ_HANDLED; 2245a5e9c02SRob Herring (Arm) } 2255a5e9c02SRob Herring (Arm) 2265a5e9c02SRob Herring (Arm) static irqreturn_t ethosu_job_irq_handler(int irq, void *data) 2275a5e9c02SRob Herring (Arm) { 2285a5e9c02SRob Herring (Arm) struct ethosu_device *dev = data; 2295a5e9c02SRob Herring (Arm) u32 status = readl_relaxed(dev->regs + NPU_REG_STATUS); 2305a5e9c02SRob Herring (Arm) 2315a5e9c02SRob Herring (Arm) if (!(status & STATUS_IRQ_RAISED)) 2325a5e9c02SRob Herring (Arm) return IRQ_NONE; 2335a5e9c02SRob Herring (Arm) 2345a5e9c02SRob Herring (Arm) writel_relaxed(CMD_CLEAR_IRQ, dev->regs + NPU_REG_CMD); 2355a5e9c02SRob Herring (Arm) return IRQ_WAKE_THREAD; 2365a5e9c02SRob Herring (Arm) } 2375a5e9c02SRob Herring (Arm) 2385a5e9c02SRob Herring (Arm) static enum drm_gpu_sched_stat ethosu_job_timedout(struct drm_sched_job *bad) 2395a5e9c02SRob Herring (Arm) { 2405a5e9c02SRob Herring (Arm) struct ethosu_job *job = to_ethosu_job(bad); 2415a5e9c02SRob Herring (Arm) struct ethosu_device *dev = job->dev; 2425a5e9c02SRob Herring (Arm) bool running; 2435a5e9c02SRob Herring (Arm) u32 *bocmds = to_drm_gem_dma_obj(job->cmd_bo)->vaddr; 2445a5e9c02SRob Herring (Arm) u32 cmdaddr; 2455a5e9c02SRob Herring (Arm) 2465a5e9c02SRob Herring (Arm) cmdaddr = readl_relaxed(dev->regs + NPU_REG_QREAD); 2475a5e9c02SRob Herring (Arm) running = FIELD_GET(STATUS_STATE_RUNNING, readl_relaxed(dev->regs + NPU_REG_STATUS)); 2485a5e9c02SRob Herring (Arm) 2495a5e9c02SRob Herring (Arm) if (running) { 2505a5e9c02SRob Herring (Arm) int ret; 2515a5e9c02SRob Herring (Arm) u32 reg; 2525a5e9c02SRob Herring (Arm) 2535a5e9c02SRob Herring (Arm) ret = readl_relaxed_poll_timeout(dev->regs + NPU_REG_QREAD, 2545a5e9c02SRob Herring (Arm) reg, 2555a5e9c02SRob Herring (Arm) reg != cmdaddr, 2565a5e9c02SRob Herring (Arm) USEC_PER_MSEC, 100 * USEC_PER_MSEC); 2575a5e9c02SRob Herring (Arm) 2585a5e9c02SRob Herring (Arm) /* If still running and progress is being made, just return */ 2595a5e9c02SRob Herring (Arm) if (!ret) 2605a5e9c02SRob Herring (Arm) return DRM_GPU_SCHED_STAT_NO_HANG; 2615a5e9c02SRob Herring (Arm) } 2625a5e9c02SRob Herring (Arm) 2635a5e9c02SRob Herring (Arm) dev_err(dev->base.dev, "NPU sched timed out: NPU %s, cmdstream offset 0x%x: 0x%x\n", 2645a5e9c02SRob Herring (Arm) running ? "running" : "stopped", 2655a5e9c02SRob Herring (Arm) cmdaddr, bocmds[cmdaddr / 4]); 2665a5e9c02SRob Herring (Arm) 2675a5e9c02SRob Herring (Arm) drm_sched_stop(&dev->sched, bad); 2685a5e9c02SRob Herring (Arm) 2695a5e9c02SRob Herring (Arm) scoped_guard(mutex, &dev->job_lock) 2705a5e9c02SRob Herring (Arm) dev->in_flight_job = NULL; 2715a5e9c02SRob Herring (Arm) 2725a5e9c02SRob Herring (Arm) /* Proceed with reset now. */ 2735a5e9c02SRob Herring (Arm) pm_runtime_force_suspend(dev->base.dev); 2745a5e9c02SRob Herring (Arm) pm_runtime_force_resume(dev->base.dev); 2755a5e9c02SRob Herring (Arm) 2765a5e9c02SRob Herring (Arm) /* Restart the scheduler */ 2775a5e9c02SRob Herring (Arm) drm_sched_start(&dev->sched, 0); 2785a5e9c02SRob Herring (Arm) 2795a5e9c02SRob Herring (Arm) return DRM_GPU_SCHED_STAT_RESET; 2805a5e9c02SRob Herring (Arm) } 2815a5e9c02SRob Herring (Arm) 2825a5e9c02SRob Herring (Arm) static const struct drm_sched_backend_ops ethosu_sched_ops = { 2835a5e9c02SRob Herring (Arm) .run_job = ethosu_job_run, 2845a5e9c02SRob Herring (Arm) .timedout_job = ethosu_job_timedout, 2855a5e9c02SRob Herring (Arm) .free_job = ethosu_job_free 2865a5e9c02SRob Herring (Arm) }; 2875a5e9c02SRob Herring (Arm) 2885a5e9c02SRob Herring (Arm) int ethosu_job_init(struct ethosu_device *edev) 2895a5e9c02SRob Herring (Arm) { 2905a5e9c02SRob Herring (Arm) struct device *dev = edev->base.dev; 2915a5e9c02SRob Herring (Arm) struct drm_sched_init_args args = { 2925a5e9c02SRob Herring (Arm) .ops = ðosu_sched_ops, 2935a5e9c02SRob Herring (Arm) .num_rqs = DRM_SCHED_PRIORITY_COUNT, 2945a5e9c02SRob Herring (Arm) .credit_limit = 1, 2955a5e9c02SRob Herring (Arm) .timeout = msecs_to_jiffies(JOB_TIMEOUT_MS), 2965a5e9c02SRob Herring (Arm) .name = dev_name(dev), 2975a5e9c02SRob Herring (Arm) .dev = dev, 2985a5e9c02SRob Herring (Arm) }; 2995a5e9c02SRob Herring (Arm) int ret; 3005a5e9c02SRob Herring (Arm) 3015a5e9c02SRob Herring (Arm) spin_lock_init(&edev->fence_lock); 3025a5e9c02SRob Herring (Arm) ret = devm_mutex_init(dev, &edev->job_lock); 3035a5e9c02SRob Herring (Arm) if (ret) 3045a5e9c02SRob Herring (Arm) return ret; 3055a5e9c02SRob Herring (Arm) ret = devm_mutex_init(dev, &edev->sched_lock); 3065a5e9c02SRob Herring (Arm) if (ret) 3075a5e9c02SRob Herring (Arm) return ret; 3085a5e9c02SRob Herring (Arm) 3095a5e9c02SRob Herring (Arm) edev->irq = platform_get_irq(to_platform_device(dev), 0); 3105a5e9c02SRob Herring (Arm) if (edev->irq < 0) 3115a5e9c02SRob Herring (Arm) return edev->irq; 3125a5e9c02SRob Herring (Arm) 3135a5e9c02SRob Herring (Arm) ret = devm_request_threaded_irq(dev, edev->irq, 3145a5e9c02SRob Herring (Arm) ethosu_job_irq_handler, 3155a5e9c02SRob Herring (Arm) ethosu_job_irq_handler_thread, 3165a5e9c02SRob Herring (Arm) IRQF_SHARED, KBUILD_MODNAME, 3175a5e9c02SRob Herring (Arm) edev); 3185a5e9c02SRob Herring (Arm) if (ret) { 3195a5e9c02SRob Herring (Arm) dev_err(dev, "failed to request irq\n"); 3205a5e9c02SRob Herring (Arm) return ret; 3215a5e9c02SRob Herring (Arm) } 3225a5e9c02SRob Herring (Arm) 3235a5e9c02SRob Herring (Arm) edev->fence_context = dma_fence_context_alloc(1); 3245a5e9c02SRob Herring (Arm) 3255a5e9c02SRob Herring (Arm) ret = drm_sched_init(&edev->sched, &args); 3265a5e9c02SRob Herring (Arm) if (ret) { 3275a5e9c02SRob Herring (Arm) dev_err(dev, "Failed to create scheduler: %d\n", ret); 3285a5e9c02SRob Herring (Arm) goto err_sched; 3295a5e9c02SRob Herring (Arm) } 3305a5e9c02SRob Herring (Arm) 3315a5e9c02SRob Herring (Arm) return 0; 3325a5e9c02SRob Herring (Arm) 3335a5e9c02SRob Herring (Arm) err_sched: 3345a5e9c02SRob Herring (Arm) drm_sched_fini(&edev->sched); 3355a5e9c02SRob Herring (Arm) return ret; 3365a5e9c02SRob Herring (Arm) } 3375a5e9c02SRob Herring (Arm) 3385a5e9c02SRob Herring (Arm) void ethosu_job_fini(struct ethosu_device *dev) 3395a5e9c02SRob Herring (Arm) { 3405a5e9c02SRob Herring (Arm) drm_sched_fini(&dev->sched); 3415a5e9c02SRob Herring (Arm) } 3425a5e9c02SRob Herring (Arm) 3435a5e9c02SRob Herring (Arm) int ethosu_job_open(struct ethosu_file_priv *ethosu_priv) 3445a5e9c02SRob Herring (Arm) { 3455a5e9c02SRob Herring (Arm) struct ethosu_device *dev = ethosu_priv->edev; 3465a5e9c02SRob Herring (Arm) struct drm_gpu_scheduler *sched = &dev->sched; 3475a5e9c02SRob Herring (Arm) int ret; 3485a5e9c02SRob Herring (Arm) 3495a5e9c02SRob Herring (Arm) ret = drm_sched_entity_init(ðosu_priv->sched_entity, 3505a5e9c02SRob Herring (Arm) DRM_SCHED_PRIORITY_NORMAL, 3515a5e9c02SRob Herring (Arm) &sched, 1, NULL); 3525a5e9c02SRob Herring (Arm) return WARN_ON(ret); 3535a5e9c02SRob Herring (Arm) } 3545a5e9c02SRob Herring (Arm) 3555a5e9c02SRob Herring (Arm) void ethosu_job_close(struct ethosu_file_priv *ethosu_priv) 3565a5e9c02SRob Herring (Arm) { 3575a5e9c02SRob Herring (Arm) struct drm_sched_entity *entity = ðosu_priv->sched_entity; 3585a5e9c02SRob Herring (Arm) 3595a5e9c02SRob Herring (Arm) drm_sched_entity_destroy(entity); 3605a5e9c02SRob Herring (Arm) } 3615a5e9c02SRob Herring (Arm) 3625a5e9c02SRob Herring (Arm) static int ethosu_ioctl_submit_job(struct drm_device *dev, struct drm_file *file, 3635a5e9c02SRob Herring (Arm) struct drm_ethosu_job *job) 3645a5e9c02SRob Herring (Arm) { 3655a5e9c02SRob Herring (Arm) struct ethosu_device *edev = to_ethosu_device(dev); 3665a5e9c02SRob Herring (Arm) struct ethosu_file_priv *file_priv = file->driver_priv; 3675a5e9c02SRob Herring (Arm) struct ethosu_job *ejob = NULL; 3685a5e9c02SRob Herring (Arm) struct ethosu_validated_cmdstream_info *cmd_info; 3695a5e9c02SRob Herring (Arm) int ret = 0; 3705a5e9c02SRob Herring (Arm) 3715a5e9c02SRob Herring (Arm) /* BO region 2 is reserved if SRAM is used */ 3725a5e9c02SRob Herring (Arm) if (job->region_bo_handles[ETHOSU_SRAM_REGION] && job->sram_size) 3735a5e9c02SRob Herring (Arm) return -EINVAL; 3745a5e9c02SRob Herring (Arm) 3755a5e9c02SRob Herring (Arm) if (edev->npu_info.sram_size < job->sram_size) 3765a5e9c02SRob Herring (Arm) return -EINVAL; 3775a5e9c02SRob Herring (Arm) 3785a5e9c02SRob Herring (Arm) ejob = kzalloc(sizeof(*ejob), GFP_KERNEL); 3795a5e9c02SRob Herring (Arm) if (!ejob) 3805a5e9c02SRob Herring (Arm) return -ENOMEM; 3815a5e9c02SRob Herring (Arm) 3825a5e9c02SRob Herring (Arm) kref_init(&ejob->refcount); 3835a5e9c02SRob Herring (Arm) 3845a5e9c02SRob Herring (Arm) ejob->dev = edev; 3855a5e9c02SRob Herring (Arm) ejob->sram_size = job->sram_size; 3865a5e9c02SRob Herring (Arm) 3875a5e9c02SRob Herring (Arm) ejob->done_fence = kzalloc(sizeof(*ejob->done_fence), GFP_KERNEL); 3885a5e9c02SRob Herring (Arm) if (!ejob->done_fence) { 3895a5e9c02SRob Herring (Arm) ret = -ENOMEM; 3905a5e9c02SRob Herring (Arm) goto out_cleanup_job; 3915a5e9c02SRob Herring (Arm) } 3925a5e9c02SRob Herring (Arm) 3935a5e9c02SRob Herring (Arm) ret = drm_sched_job_init(&ejob->base, 3945a5e9c02SRob Herring (Arm) &file_priv->sched_entity, 3955a5e9c02SRob Herring (Arm) 1, NULL, file->client_id); 3965a5e9c02SRob Herring (Arm) if (ret) 3975a5e9c02SRob Herring (Arm) goto out_put_job; 3985a5e9c02SRob Herring (Arm) 3995a5e9c02SRob Herring (Arm) ejob->cmd_bo = drm_gem_object_lookup(file, job->cmd_bo); 4005a5e9c02SRob Herring (Arm) if (!ejob->cmd_bo) { 4015a5e9c02SRob Herring (Arm) ret = -ENOENT; 4025a5e9c02SRob Herring (Arm) goto out_cleanup_job; 4035a5e9c02SRob Herring (Arm) } 4045a5e9c02SRob Herring (Arm) cmd_info = to_ethosu_bo(ejob->cmd_bo)->info; 4055a5e9c02SRob Herring (Arm) if (!cmd_info) { 4065a5e9c02SRob Herring (Arm) ret = -EINVAL; 4075a5e9c02SRob Herring (Arm) goto out_cleanup_job; 4085a5e9c02SRob Herring (Arm) } 4095a5e9c02SRob Herring (Arm) 4105a5e9c02SRob Herring (Arm) for (int i = 0; i < NPU_BASEP_REGION_MAX; i++) { 4115a5e9c02SRob Herring (Arm) struct drm_gem_object *gem; 4125a5e9c02SRob Herring (Arm) 4135a5e9c02SRob Herring (Arm) /* Can only omit a BO handle if the region is not used or used for SRAM */ 4145a5e9c02SRob Herring (Arm) if (!job->region_bo_handles[i] && 4155a5e9c02SRob Herring (Arm) (!cmd_info->region_size[i] || (i == ETHOSU_SRAM_REGION && job->sram_size))) 4165a5e9c02SRob Herring (Arm) continue; 4175a5e9c02SRob Herring (Arm) 4185a5e9c02SRob Herring (Arm) if (job->region_bo_handles[i] && !cmd_info->region_size[i]) { 4195a5e9c02SRob Herring (Arm) dev_err(dev->dev, 4205a5e9c02SRob Herring (Arm) "Cmdstream BO handle %d set for unused region %d\n", 4215a5e9c02SRob Herring (Arm) job->region_bo_handles[i], i); 4225a5e9c02SRob Herring (Arm) ret = -EINVAL; 4235a5e9c02SRob Herring (Arm) goto out_cleanup_job; 4245a5e9c02SRob Herring (Arm) } 4255a5e9c02SRob Herring (Arm) 4265a5e9c02SRob Herring (Arm) gem = drm_gem_object_lookup(file, job->region_bo_handles[i]); 4275a5e9c02SRob Herring (Arm) if (!gem) { 4285a5e9c02SRob Herring (Arm) dev_err(dev->dev, 4295a5e9c02SRob Herring (Arm) "Invalid BO handle %d for region %d\n", 4305a5e9c02SRob Herring (Arm) job->region_bo_handles[i], i); 4315a5e9c02SRob Herring (Arm) ret = -ENOENT; 4325a5e9c02SRob Herring (Arm) goto out_cleanup_job; 4335a5e9c02SRob Herring (Arm) } 4345a5e9c02SRob Herring (Arm) 4355a5e9c02SRob Herring (Arm) ejob->region_bo[ejob->region_cnt] = gem; 4365a5e9c02SRob Herring (Arm) ejob->region_bo_num[ejob->region_cnt] = i; 4375a5e9c02SRob Herring (Arm) ejob->region_cnt++; 4385a5e9c02SRob Herring (Arm) 4395a5e9c02SRob Herring (Arm) if (to_ethosu_bo(gem)->info) { 4405a5e9c02SRob Herring (Arm) dev_err(dev->dev, 4415a5e9c02SRob Herring (Arm) "Cmdstream BO handle %d used for region %d\n", 4425a5e9c02SRob Herring (Arm) job->region_bo_handles[i], i); 4435a5e9c02SRob Herring (Arm) ret = -EINVAL; 4445a5e9c02SRob Herring (Arm) goto out_cleanup_job; 4455a5e9c02SRob Herring (Arm) } 4465a5e9c02SRob Herring (Arm) 4475a5e9c02SRob Herring (Arm) /* Verify the command stream doesn't have accesses outside the BO */ 4485a5e9c02SRob Herring (Arm) if (cmd_info->region_size[i] > gem->size) { 4495a5e9c02SRob Herring (Arm) dev_err(dev->dev, 4505a5e9c02SRob Herring (Arm) "cmd stream region %d size greater than BO size (%llu > %zu)\n", 4515a5e9c02SRob Herring (Arm) i, cmd_info->region_size[i], gem->size); 4525a5e9c02SRob Herring (Arm) ret = -EOVERFLOW; 4535a5e9c02SRob Herring (Arm) goto out_cleanup_job; 4545a5e9c02SRob Herring (Arm) } 4555a5e9c02SRob Herring (Arm) } 4565a5e9c02SRob Herring (Arm) ret = ethosu_job_push(ejob); 4575a5e9c02SRob Herring (Arm) 4585a5e9c02SRob Herring (Arm) out_cleanup_job: 4595a5e9c02SRob Herring (Arm) if (ret) 4605a5e9c02SRob Herring (Arm) drm_sched_job_cleanup(&ejob->base); 4615a5e9c02SRob Herring (Arm) out_put_job: 4625a5e9c02SRob Herring (Arm) ethosu_job_put(ejob); 4635a5e9c02SRob Herring (Arm) 4645a5e9c02SRob Herring (Arm) return ret; 4655a5e9c02SRob Herring (Arm) } 4665a5e9c02SRob Herring (Arm) 4675a5e9c02SRob Herring (Arm) int ethosu_ioctl_submit(struct drm_device *dev, void *data, struct drm_file *file) 4685a5e9c02SRob Herring (Arm) { 4695a5e9c02SRob Herring (Arm) struct drm_ethosu_submit *args = data; 4705a5e9c02SRob Herring (Arm) int ret = 0; 4715a5e9c02SRob Herring (Arm) unsigned int i = 0; 4725a5e9c02SRob Herring (Arm) 4735a5e9c02SRob Herring (Arm) if (args->pad) { 4745a5e9c02SRob Herring (Arm) drm_dbg(dev, "Reserved field in drm_ethosu_submit struct should be 0.\n"); 4755a5e9c02SRob Herring (Arm) return -EINVAL; 4765a5e9c02SRob Herring (Arm) } 4775a5e9c02SRob Herring (Arm) 4785a5e9c02SRob Herring (Arm) struct drm_ethosu_job __free(kvfree) *jobs = 4795a5e9c02SRob Herring (Arm) kvmalloc_array(args->job_count, sizeof(*jobs), GFP_KERNEL); 4805a5e9c02SRob Herring (Arm) if (!jobs) 4815a5e9c02SRob Herring (Arm) return -ENOMEM; 4825a5e9c02SRob Herring (Arm) 4835a5e9c02SRob Herring (Arm) if (copy_from_user(jobs, 4845a5e9c02SRob Herring (Arm) (void __user *)(uintptr_t)args->jobs, 4855a5e9c02SRob Herring (Arm) args->job_count * sizeof(*jobs))) { 4865a5e9c02SRob Herring (Arm) drm_dbg(dev, "Failed to copy incoming job array\n"); 4875a5e9c02SRob Herring (Arm) return -EFAULT; 4885a5e9c02SRob Herring (Arm) } 4895a5e9c02SRob Herring (Arm) 4905a5e9c02SRob Herring (Arm) for (i = 0; i < args->job_count; i++) { 4915a5e9c02SRob Herring (Arm) ret = ethosu_ioctl_submit_job(dev, file, &jobs[i]); 4925a5e9c02SRob Herring (Arm) if (ret) 4935a5e9c02SRob Herring (Arm) return ret; 4945a5e9c02SRob Herring (Arm) } 4955a5e9c02SRob Herring (Arm) 4965a5e9c02SRob Herring (Arm) return 0; 4975a5e9c02SRob Herring (Arm) } 498