diff --git a/drivers/gpu/host1x/Makefile b/drivers/gpu/host1x/Makefile index 5b6bfcae..34344be2 100644 --- a/drivers/gpu/host1x/Makefile +++ b/drivers/gpu/host1x/Makefile @@ -14,7 +14,6 @@ host1x-next-y = \ job.o \ debug.o \ mipi.o \ - uapi.o \ fence.o \ hw/host1x01.o \ hw/host1x02.o \ diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c index a89f2350..2aed4592 100644 --- a/drivers/gpu/host1x/dev.c +++ b/drivers/gpu/host1x/dev.c @@ -528,12 +528,6 @@ static int host1x_probe(struct platform_device *pdev) goto deinit_syncpt; } - err = host1x_uapi_init(&host->uapi, host); - if (err) { - dev_err(&pdev->dev, "failed to initialize uapi\n"); - goto deinit_intr; - } - host1x_debug_init(host); if (host->info->has_hypervisor) @@ -553,8 +547,6 @@ unregister: host1x_unregister(host); deinit_debugfs: host1x_debug_deinit(host); - host1x_uapi_deinit(&host->uapi); -deinit_intr: host1x_intr_deinit(host); deinit_syncpt: host1x_syncpt_deinit(host); @@ -576,7 +568,6 @@ static int host1x_remove(struct platform_device *pdev) host1x_unregister(host); host1x_debug_deinit(host); - host1x_uapi_deinit(&host->uapi); host1x_intr_deinit(host); host1x_syncpt_deinit(host); reset_control_assert(host->rst); diff --git a/drivers/gpu/host1x/dev.h b/drivers/gpu/host1x/dev.h index 95c78451..5b7fdea5 100644 --- a/drivers/gpu/host1x/dev.h +++ b/drivers/gpu/host1x/dev.h @@ -17,7 +17,6 @@ #include "intr.h" #include "job.h" #include "syncpt.h" -#include "uapi.h" struct host1x_syncpt; struct host1x_syncpt_base; @@ -152,7 +151,6 @@ struct host1x { struct device_dma_parameters dma_parms; struct host1x_bo_cache cache; - struct host1x_uapi uapi; }; void host1x_hypervisor_writel(struct host1x *host1x, u32 r, u32 v); diff --git a/drivers/gpu/host1x/fence.c b/drivers/gpu/host1x/fence.c index ea4a0c7d..4a8fdbfb 100644 --- a/drivers/gpu/host1x/fence.c +++ b/drivers/gpu/host1x/fence.c @@ -31,20 +31,24 @@ struct host1x_syncpt_fence { struct delayed_work timeout_work; }; -static const char *syncpt_fence_get_driver_name(struct dma_fence *f) +static const char *host1x_syncpt_fence_get_driver_name(struct dma_fence *f) { return "host1x"; } -static const char *syncpt_fence_get_timeline_name(struct dma_fence *f) +static const char *host1x_syncpt_fence_get_timeline_name(struct dma_fence *f) { return "syncpoint"; } -static bool syncpt_fence_enable_signaling(struct dma_fence *f) +static struct host1x_syncpt_fence *to_host1x_fence(struct dma_fence *f) { - struct host1x_syncpt_fence *sf = - container_of(f, struct host1x_syncpt_fence, base); + return container_of(f, struct host1x_syncpt_fence, base); +} + +static bool host1x_syncpt_fence_enable_signaling(struct dma_fence *f) +{ + struct host1x_syncpt_fence *sf = to_host1x_fence(f); int err; if (host1x_syncpt_is_expired(sf->sp, sf->threshold)) @@ -56,7 +60,7 @@ static bool syncpt_fence_enable_signaling(struct dma_fence *f) * The dma_fence framework requires the fence driver to keep a * reference to any fences for which 'enable_signaling' has been * called (and that have not been signalled). - * + * * We provide a userspace API to create arbitrary syncpoint fences, * so we cannot normally guarantee that all fences get signalled. * As such, setup a timeout, so that long-lasting fences will get @@ -85,10 +89,9 @@ static bool syncpt_fence_enable_signaling(struct dma_fence *f) return true; } -static void syncpt_fence_release(struct dma_fence *f) +static void host1x_syncpt_fence_release(struct dma_fence *f) { - struct host1x_syncpt_fence *sf = - container_of(f, struct host1x_syncpt_fence, base); + struct host1x_syncpt_fence *sf = to_host1x_fence(f); if (sf->waiter) kfree(sf->waiter); @@ -96,11 +99,11 @@ static void syncpt_fence_release(struct dma_fence *f) dma_fence_free(f); } -const struct dma_fence_ops syncpt_fence_ops = { - .get_driver_name = syncpt_fence_get_driver_name, - .get_timeline_name = syncpt_fence_get_timeline_name, - .enable_signaling = syncpt_fence_enable_signaling, - .release = syncpt_fence_release, +const struct dma_fence_ops host1x_syncpt_fence_ops = { + .get_driver_name = host1x_syncpt_fence_get_driver_name, + .get_timeline_name = host1x_syncpt_fence_get_timeline_name, + .enable_signaling = host1x_syncpt_fence_enable_signaling, + .release = host1x_syncpt_fence_release, }; void host1x_fence_signal(struct host1x_syncpt_fence *f) @@ -157,7 +160,7 @@ struct dma_fence *host1x_fence_create(struct host1x_syncpt *sp, u32 threshold) fence->sp = sp; fence->threshold = threshold; - dma_fence_init(&fence->base, &syncpt_fence_ops, &lock, + dma_fence_init(&fence->base, &host1x_syncpt_fence_ops, &lock, dma_fence_context_alloc(1), 0); INIT_DELAYED_WORK(&fence->timeout_work, do_fence_timeout); @@ -165,46 +168,3 @@ struct dma_fence *host1x_fence_create(struct host1x_syncpt *sp, u32 threshold) return &fence->base; } EXPORT_SYMBOL(host1x_fence_create); - -int host1x_fence_create_fd(struct host1x_syncpt *sp, u32 threshold) -{ - struct sync_file *file; - struct dma_fence *f; - int fd; - - f = host1x_fence_create(sp, threshold); - if (IS_ERR(f)) - return PTR_ERR(f); - - fd = get_unused_fd_flags(O_CLOEXEC); - if (fd < 0) { - dma_fence_put(f); - return fd; - } - - file = sync_file_create(f); - dma_fence_put(f); - if (!file) - return -ENOMEM; - - fd_install(fd, file->file); - - return fd; -} -EXPORT_SYMBOL(host1x_fence_create_fd); - -int host1x_fence_extract(struct dma_fence *fence, u32 *id, u32 *threshold) -{ - struct host1x_syncpt_fence *f; - - if (fence->ops != &syncpt_fence_ops) - return -EINVAL; - - f = container_of(fence, struct host1x_syncpt_fence, base); - - *id = f->sp->id; - *threshold = f->threshold; - - return 0; -} -EXPORT_SYMBOL(host1x_fence_extract); diff --git a/drivers/gpu/host1x/hw/channel_hw.c b/drivers/gpu/host1x/hw/channel_hw.c index 1917e760..4eda10a3 100644 --- a/drivers/gpu/host1x/hw/channel_hw.c +++ b/drivers/gpu/host1x/hw/channel_hw.c @@ -47,27 +47,57 @@ static void trace_write_gather(struct host1x_cdma *cdma, struct host1x_bo *bo, } } -static void submit_gathers(struct host1x_job *job) +static void submit_wait(struct host1x_cdma *cdma, u32 id, u32 threshold, + u32 next_class) +{ +#if HOST1X_HW >= 2 + host1x_cdma_push_wide(cdma, + host1x_opcode_setclass( + HOST1X_CLASS_HOST1X, + HOST1X_UCLASS_LOAD_SYNCPT_PAYLOAD_32, + /* WAIT_SYNCPT_32 is at SYNCPT_PAYLOAD_32+2 */ + BIT(0) | BIT(2) + ), + threshold, + id, + host1x_opcode_setclass(next_class, 0, 0) + ); +#else + /* TODO add waitchk or use waitbases or other mitigation */ + host1x_cdma_push(cdma, + host1x_opcode_setclass( + HOST1X_CLASS_HOST1X, + host1x_uclass_wait_syncpt_r(), + BIT(0) + ), + host1x_class_host_wait_syncpt(id, threshold) + ); + host1x_cdma_push(cdma, + host1x_opcode_setclass(next_class, 0, 0), + HOST1X_OPCODE_NOP + ); +#endif +} + +static void submit_gathers(struct host1x_job *job, u32 job_syncpt_base) { struct host1x_cdma *cdma = &job->channel->cdma; #if HOST1X_HW < 6 struct device *dev = job->channel->dev; #endif unsigned int i; + u32 threshold; for (i = 0; i < job->num_cmds; i++) { struct host1x_job_cmd *cmd = &job->cmds[i]; if (cmd->is_wait) { - /* TODO use modern wait */ - host1x_cdma_push(cdma, - host1x_opcode_setclass(HOST1X_CLASS_HOST1X, - host1x_uclass_wait_syncpt_r(), 1), - host1x_class_host_wait_syncpt(cmd->wait.id, - cmd->wait.threshold)); - host1x_cdma_push( - cdma, host1x_opcode_setclass(job->class, 0, 0), - HOST1X_OPCODE_NOP); + if (cmd->wait.relative) + threshold = job_syncpt_base + cmd->wait.threshold; + else + threshold = cmd->wait.threshold; + + submit_wait(cdma, cmd->wait.id, threshold, cmd->wait.next_class); } else { struct host1x_job_gather *g = &cmd->gather; @@ -196,7 +226,7 @@ static int channel_submit(struct host1x_job *job) host1x_opcode_setclass(job->class, 0, 0), HOST1X_OPCODE_NOP); - submit_gathers(job); + submit_gathers(job, syncval - user_syncpt_incrs); /* end CDMA submit & stash pinned hMems into sync queue */ host1x_cdma_end(&ch->cdma, job); diff --git a/drivers/gpu/host1x/hw/debug_hw.c b/drivers/gpu/host1x/hw/debug_hw.c index 35952fd5..54e31d81 100644 --- a/drivers/gpu/host1x/hw/debug_hw.c +++ b/drivers/gpu/host1x/hw/debug_hw.c @@ -156,9 +156,9 @@ static unsigned int show_channel_command(struct output *o, u32 val, } } -static void show_gather(struct output *o, phys_addr_t phys_addr, +static void show_gather(struct output *o, dma_addr_t phys_addr, unsigned int words, struct host1x_cdma *cdma, - phys_addr_t pin_addr, u32 *map_addr) + dma_addr_t pin_addr, u32 *map_addr) { /* Map dmaget cursor to corresponding mem handle */ u32 offset = phys_addr - pin_addr; @@ -176,11 +176,11 @@ static void show_gather(struct output *o, phys_addr_t phys_addr, } for (i = 0; i < words; i++) { - u32 addr = phys_addr + i * 4; + dma_addr_t addr = phys_addr + i * 4; u32 val = *(map_addr + offset / 4 + i); if (!data_count) { - host1x_debug_output(o, "%08x: %08x: ", addr, val); + host1x_debug_output(o, " %pad: %08x: ", &addr, val); data_count = show_channel_command(o, val, &payload); } else { host1x_debug_cont(o, "%08x%s", val, @@ -195,19 +195,16 @@ static void show_channel_gathers(struct output *o, struct host1x_cdma *cdma) struct push_buffer *pb = &cdma->push_buffer; struct host1x_job *job; - host1x_debug_output(o, "PUSHBUF at %pad, %u words\n", - &pb->dma, pb->size / 4); - - show_gather(o, pb->dma, pb->size / 4, cdma, pb->dma, pb->mapped); - list_for_each_entry(job, &cdma->sync_queue, list) { unsigned int i; - host1x_debug_output(o, "\n%p: JOB, syncpt_id=%d, syncpt_val=%d, first_get=%08x, timeout=%d num_slots=%d, num_handles=%d\n", - job, job->syncpt->id, job->syncpt_end, - job->first_get, job->timeout, + host1x_debug_output(o, "JOB, syncpt %u: %u timeout: %u num_slots: %u num_handles: %u\n", + job->syncpt->id, job->syncpt_end, job->timeout, job->num_slots, job->num_unpins); + show_gather(o, pb->dma + job->first_get, job->num_slots * 2, cdma, + pb->dma + job->first_get, pb->mapped + job->first_get); + for (i = 0; i < job->num_cmds; i++) { struct host1x_job_gather *g; u32 *mapped; @@ -227,7 +224,7 @@ static void show_channel_gathers(struct output *o, struct host1x_cdma *cdma) continue; } - host1x_debug_output(o, " GATHER at %pad+%#x, %d words\n", + host1x_debug_output(o, " GATHER at %pad+%#x, %d words\n", &g->base, g->offset, g->words); show_gather(o, g->base + g->offset, g->words, cdma, diff --git a/drivers/gpu/host1x/hw/debug_hw_1x01.c b/drivers/gpu/host1x/hw/debug_hw_1x01.c index 02a93305..85242a59 100644 --- a/drivers/gpu/host1x/hw/debug_hw_1x01.c +++ b/drivers/gpu/host1x/hw/debug_hw_1x01.c @@ -16,10 +16,13 @@ static void host1x_debug_show_channel_cdma(struct host1x *host, struct output *o) { struct host1x_cdma *cdma = &ch->cdma; + dma_addr_t dmastart, dmaend; u32 dmaput, dmaget, dmactrl; u32 cbstat, cbread; u32 val, base, baseval; + dmastart = host1x_ch_readl(ch, HOST1X_CHANNEL_DMASTART); + dmaend = host1x_ch_readl(ch, HOST1X_CHANNEL_DMAEND); dmaput = host1x_ch_readl(ch, HOST1X_CHANNEL_DMAPUT); dmaget = host1x_ch_readl(ch, HOST1X_CHANNEL_DMAGET); dmactrl = host1x_ch_readl(ch, HOST1X_CHANNEL_DMACTRL); @@ -56,9 +59,10 @@ static void host1x_debug_show_channel_cdma(struct host1x *host, HOST1X_SYNC_CBSTAT_CBOFFSET_V(cbstat), cbread); - host1x_debug_output(o, "DMAPUT %08x, DMAGET %08x, DMACTL %08x\n", + host1x_debug_output(o, "DMASTART %pad, DMAEND %pad\n", &dmastart, &dmaend); + host1x_debug_output(o, "DMAPUT %08x DMAGET %08x DMACTL %08x\n", dmaput, dmaget, dmactrl); - host1x_debug_output(o, "CBREAD %08x, CBSTAT %08x\n", cbread, cbstat); + host1x_debug_output(o, "CBREAD %08x CBSTAT %08x\n", cbread, cbstat); show_channel_gathers(o, cdma); host1x_debug_output(o, "\n"); diff --git a/drivers/gpu/host1x/hw/debug_hw_1x06.c b/drivers/gpu/host1x/hw/debug_hw_1x06.c index 6d1b583a..9d066787 100644 --- a/drivers/gpu/host1x/hw/debug_hw_1x06.c +++ b/drivers/gpu/host1x/hw/debug_hw_1x06.c @@ -16,10 +16,23 @@ static void host1x_debug_show_channel_cdma(struct host1x *host, struct output *o) { struct host1x_cdma *cdma = &ch->cdma; + dma_addr_t dmastart = 0, dmaend = 0; u32 dmaput, dmaget, dmactrl; u32 offset, class; u32 ch_stat; +#if defined(CONFIG_ARCH_DMA_ADDR_T_64BIT) && HOST1X_HW >= 6 + dmastart = host1x_ch_readl(ch, HOST1X_CHANNEL_DMASTART_HI); + dmastart <<= 32; +#endif + dmastart |= host1x_ch_readl(ch, HOST1X_CHANNEL_DMASTART); + +#if defined(CONFIG_ARCH_DMA_ADDR_T_64BIT) && HOST1X_HW >= 6 + dmaend = host1x_ch_readl(ch, HOST1X_CHANNEL_DMAEND_HI); + dmaend <<= 32; +#endif + dmaend |= host1x_ch_readl(ch, HOST1X_CHANNEL_DMAEND); + dmaput = host1x_ch_readl(ch, HOST1X_CHANNEL_DMAPUT); dmaget = host1x_ch_readl(ch, HOST1X_CHANNEL_DMAGET); dmactrl = host1x_ch_readl(ch, HOST1X_CHANNEL_DMACTRL); @@ -41,7 +54,8 @@ static void host1x_debug_show_channel_cdma(struct host1x *host, host1x_debug_output(o, "active class %02x, offset %04x\n", class, offset); - host1x_debug_output(o, "DMAPUT %08x, DMAGET %08x, DMACTL %08x\n", + host1x_debug_output(o, "DMASTART %pad, DMAEND %pad\n", &dmastart, &dmaend); + host1x_debug_output(o, "DMAPUT %08x DMAGET %08x DMACTL %08x\n", dmaput, dmaget, dmactrl); host1x_debug_output(o, "CHANNELSTAT %02x\n", ch_stat); diff --git a/drivers/gpu/host1x/hw/hw_host1x02_uclass.h b/drivers/gpu/host1x/hw/hw_host1x02_uclass.h index 4fc51f70..0a2ab8f1 100644 --- a/drivers/gpu/host1x/hw/hw_host1x02_uclass.h +++ b/drivers/gpu/host1x/hw/hw_host1x02_uclass.h @@ -165,5 +165,17 @@ static inline u32 host1x_uclass_indoff_rwn_read_v(void) } #define HOST1X_UCLASS_INDOFF_INDROFFSET_F(v) \ host1x_uclass_indoff_indroffset_f(v) +static inline u32 host1x_uclass_load_syncpt_payload_32_r(void) +{ + return 0x4e; +} +#define HOST1X_UCLASS_LOAD_SYNCPT_PAYLOAD_32 \ + host1x_uclass_load_syncpt_payload_32_r() +static inline u32 host1x_uclass_wait_syncpt_32_r(void) +{ + return 0x50; +} +#define HOST1X_UCLASS_WAIT_SYNCPT_32 \ + host1x_uclass_wait_syncpt_32_r() #endif diff --git a/drivers/gpu/host1x/hw/hw_host1x04_uclass.h b/drivers/gpu/host1x/hw/hw_host1x04_uclass.h index 9e84a4ad..60c692b9 100644 --- a/drivers/gpu/host1x/hw/hw_host1x04_uclass.h +++ b/drivers/gpu/host1x/hw/hw_host1x04_uclass.h @@ -165,5 +165,17 @@ static inline u32 host1x_uclass_indoff_rwn_read_v(void) } #define HOST1X_UCLASS_INDOFF_INDROFFSET_F(v) \ host1x_uclass_indoff_indroffset_f(v) +static inline u32 host1x_uclass_load_syncpt_payload_32_r(void) +{ + return 0x4e; +} +#define HOST1X_UCLASS_LOAD_SYNCPT_PAYLOAD_32 \ + host1x_uclass_load_syncpt_payload_32_r() +static inline u32 host1x_uclass_wait_syncpt_32_r(void) +{ + return 0x50; +} +#define HOST1X_UCLASS_WAIT_SYNCPT_32 \ + host1x_uclass_wait_syncpt_32_r() #endif diff --git a/drivers/gpu/host1x/hw/hw_host1x05_uclass.h b/drivers/gpu/host1x/hw/hw_host1x05_uclass.h index aee5a4e3..2fcc9a2a 100644 --- a/drivers/gpu/host1x/hw/hw_host1x05_uclass.h +++ b/drivers/gpu/host1x/hw/hw_host1x05_uclass.h @@ -165,5 +165,17 @@ static inline u32 host1x_uclass_indoff_rwn_read_v(void) } #define HOST1X_UCLASS_INDOFF_INDROFFSET_F(v) \ host1x_uclass_indoff_indroffset_f(v) +static inline u32 host1x_uclass_load_syncpt_payload_32_r(void) +{ + return 0x4e; +} +#define HOST1X_UCLASS_LOAD_SYNCPT_PAYLOAD_32 \ + host1x_uclass_load_syncpt_payload_32_r() +static inline u32 host1x_uclass_wait_syncpt_32_r(void) +{ + return 0x50; +} +#define HOST1X_UCLASS_WAIT_SYNCPT_32 \ + host1x_uclass_wait_syncpt_32_r() #endif diff --git a/drivers/gpu/host1x/hw/hw_host1x06_uclass.h b/drivers/gpu/host1x/hw/hw_host1x06_uclass.h index c4bacdb7..5f831438 100644 --- a/drivers/gpu/host1x/hw/hw_host1x06_uclass.h +++ b/drivers/gpu/host1x/hw/hw_host1x06_uclass.h @@ -165,5 +165,17 @@ static inline u32 host1x_uclass_indoff_rwn_read_v(void) } #define HOST1X_UCLASS_INDOFF_INDROFFSET_F(v) \ host1x_uclass_indoff_indroffset_f(v) +static inline u32 host1x_uclass_load_syncpt_payload_32_r(void) +{ + return 0x4e; +} +#define HOST1X_UCLASS_LOAD_SYNCPT_PAYLOAD_32 \ + host1x_uclass_load_syncpt_payload_32_r() +static inline u32 host1x_uclass_wait_syncpt_32_r(void) +{ + return 0x50; +} +#define HOST1X_UCLASS_WAIT_SYNCPT_32 \ + host1x_uclass_wait_syncpt_32_r() #endif diff --git a/drivers/gpu/host1x/hw/hw_host1x07_uclass.h b/drivers/gpu/host1x/hw/hw_host1x07_uclass.h index c74070f3..8cd2ef08 100644 --- a/drivers/gpu/host1x/hw/hw_host1x07_uclass.h +++ b/drivers/gpu/host1x/hw/hw_host1x07_uclass.h @@ -165,5 +165,17 @@ static inline u32 host1x_uclass_indoff_rwn_read_v(void) } #define HOST1X_UCLASS_INDOFF_INDROFFSET_F(v) \ host1x_uclass_indoff_indroffset_f(v) +static inline u32 host1x_uclass_load_syncpt_payload_32_r(void) +{ + return 0x4e; +} +#define HOST1X_UCLASS_LOAD_SYNCPT_PAYLOAD_32 \ + host1x_uclass_load_syncpt_payload_32_r() +static inline u32 host1x_uclass_wait_syncpt_32_r(void) +{ + return 0x50; +} +#define HOST1X_UCLASS_WAIT_SYNCPT_32 \ + host1x_uclass_wait_syncpt_32_r() #endif diff --git a/drivers/gpu/host1x/include/linux/host1x-next.h b/drivers/gpu/host1x/include/linux/host1x-next.h index 45e0a712..c9f47fad 100644 --- a/drivers/gpu/host1x/include/linux/host1x-next.h +++ b/drivers/gpu/host1x/include/linux/host1x-next.h @@ -218,11 +218,7 @@ u32 host1x_syncpt_base_id(struct host1x_syncpt_base *base); void host1x_syncpt_release_vblank_reservation(struct host1x_client *client, u32 syncpt_id); -struct host1x_syncpt *host1x_syncpt_fd_get(int fd); - struct dma_fence *host1x_fence_create(struct host1x_syncpt *sp, u32 threshold); -int host1x_fence_create_fd(struct host1x_syncpt *sp, u32 threshold); -int host1x_fence_extract(struct dma_fence *fence, u32 *id, u32 *threshold); /* * host1x channel @@ -324,13 +320,18 @@ struct host1x_job { /* Callback called when job is freed */ void (*release)(struct host1x_job *job); void *user_data; + + /* Whether host1x-side firewall should be ran for this job or not */ + bool enable_firewall; }; struct host1x_job *host1x_job_alloc(struct host1x_channel *ch, - u32 num_cmdbufs, u32 num_relocs); + u32 num_cmdbufs, u32 num_relocs, + bool skip_firewall); void host1x_job_add_gather(struct host1x_job *job, struct host1x_bo *bo, unsigned int words, unsigned int offset); -void host1x_job_add_wait(struct host1x_job *job, u32 id, u32 thresh); +void host1x_job_add_wait(struct host1x_job *job, u32 id, u32 thresh, + bool relative, u32 next_class); struct host1x_job *host1x_job_get(struct host1x_job *job); void host1x_job_put(struct host1x_job *job); int host1x_job_pin(struct host1x_job *job, struct device *dev); diff --git a/drivers/gpu/host1x/include/uapi/linux/host1x-next.h b/drivers/gpu/host1x/include/uapi/linux/host1x-next.h deleted file mode 100644 index 9c8fb942..00000000 --- a/drivers/gpu/host1x/include/uapi/linux/host1x-next.h +++ /dev/null @@ -1,134 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* Copyright (c) 2020 NVIDIA Corporation */ - -#ifndef _UAPI__LINUX_HOST1X_H -#define _UAPI__LINUX_HOST1X_H - -#include -#include - -#if defined(__cplusplus) -extern "C" { -#endif - -struct host1x_allocate_syncpoint { - /** - * @fd: [out] - * - * New file descriptor representing the allocated syncpoint. - */ - __s32 fd; - - __u32 reserved[3]; -}; - -struct host1x_syncpoint_info { - /** - * @id: [out] - * - * System-global ID of the syncpoint. - */ - __u32 id; - - __u32 reserved[3]; -}; - -struct host1x_syncpoint_increment { - /** - * @count: [in] - * - * Number of times to increment the syncpoint. The syncpoint can - * be observed at in-between values, but each increment is atomic. - */ - __u32 count; -}; - -struct host1x_read_syncpoint { - /** - * @id: [in] - * - * ID of the syncpoint to read. - */ - __u32 id; - - /** - * @value: [out] - * - * Current value of the syncpoint. - */ - __u32 value; -}; - -struct host1x_create_fence { - /** - * @id: [in] - * - * ID of the syncpoint to create a fence for. - */ - __u32 id; - - /** - * @threshold: [in] - * - * When the syncpoint reaches this value, the fence will be signaled. - * The syncpoint is considered to have reached the threshold when the - * following condition is true: - * - * ((value - threshold) & 0x80000000U) == 0U - * - */ - __u32 threshold; - - /** - * @fence_fd: [out] - * - * New sync_file file descriptor containing the created fence. - */ - __s32 fence_fd; - - __u32 reserved[1]; -}; - -struct host1x_fence_extract_fence { - __u32 id; - __u32 threshold; -}; - -struct host1x_fence_extract { - /** - * @fence_fd: [in] - * - * sync_file file descriptor - */ - __s32 fence_fd; - - /** - * @num_fences: [in,out] - * - * In: size of the `fences_ptr` array counted in elements. - * Out: required size of the `fences_ptr` array counted in elements. - */ - __u32 num_fences; - - /** - * @fences_ptr: [in] - * - * Pointer to array of `struct host1x_fence_extract_fence`. - */ - __u64 fences_ptr; - - __u32 reserved[2]; -}; - -#define HOST1X_IOCTL_ALLOCATE_SYNCPOINT _IOWR('X', 0x00, struct host1x_allocate_syncpoint) -#define HOST1X_IOCTL_READ_SYNCPOINT _IOR ('X', 0x01, struct host1x_read_syncpoint) -#define HOST1X_IOCTL_CREATE_FENCE _IOWR('X', 0x02, struct host1x_create_fence) -#define HOST1X_IOCTL_SYNCPOINT_INFO _IOWR('X', 0x03, struct host1x_syncpoint_info) -#define HOST1X_IOCTL_SYNCPOINT_INCREMENT _IOWR('X', 0x04, struct host1x_syncpoint_increment) -#define HOST1X_IOCTL_FENCE_EXTRACT _IOWR('X', 0x05, struct host1x_fence_extract) - -#if defined(__cplusplus) -} -#endif - -#endif diff --git a/drivers/gpu/host1x/intr.c b/drivers/gpu/host1x/intr.c index 7a847545..45b6be92 100644 --- a/drivers/gpu/host1x/intr.c +++ b/drivers/gpu/host1x/intr.c @@ -273,7 +273,7 @@ void host1x_intr_put_ref(struct host1x *host, unsigned int id, void *ref, if (flush) { /* Wait until any concurrently executing handler has finished. */ while (atomic_read(&waiter->state) != WLS_HANDLED) - cpu_relax(); + schedule(); } kref_put(&waiter->refcount, waiter_release); diff --git a/drivers/gpu/host1x/job.c b/drivers/gpu/host1x/job.c index b5896749..ee47735a 100644 --- a/drivers/gpu/host1x/job.c +++ b/drivers/gpu/host1x/job.c @@ -24,14 +24,18 @@ #define HOST1X_WAIT_SYNCPT_OFFSET 0x8 struct host1x_job *host1x_job_alloc(struct host1x_channel *ch, - u32 num_cmdbufs, u32 num_relocs) + u32 num_cmdbufs, u32 num_relocs, + bool skip_firewall) { struct host1x_job *job = NULL; unsigned int num_unpins = num_relocs; + bool enable_firewall; u64 total; void *mem; - if (!IS_ENABLED(CONFIG_TEGRA_HOST1X_FIREWALL)) + enable_firewall = IS_ENABLED(CONFIG_TEGRA_HOST1X_FIREWALL) && !skip_firewall; + + if (!enable_firewall) num_unpins += num_cmdbufs; /* Check that we're not going to overflow */ @@ -48,6 +52,8 @@ struct host1x_job *host1x_job_alloc(struct host1x_channel *ch, if (!job) return NULL; + job->enable_firewall = enable_firewall; + kref_init(&job->ref); job->channel = ch; @@ -111,13 +117,16 @@ void host1x_job_add_gather(struct host1x_job *job, struct host1x_bo *bo, } EXPORT_SYMBOL(host1x_job_add_gather); -void host1x_job_add_wait(struct host1x_job *job, u32 id, u32 thresh) +void host1x_job_add_wait(struct host1x_job *job, u32 id, u32 thresh, + bool relative, u32 next_class) { struct host1x_job_cmd *cmd = &job->cmds[job->num_cmds]; cmd->is_wait = true; cmd->wait.id = id; cmd->wait.threshold = thresh; + cmd->wait.next_class = next_class; + cmd->wait.relative = relative; job->num_cmds++; } @@ -193,7 +202,7 @@ static unsigned int pin_job(struct host1x *host, struct host1x_job *job) * We will copy gathers BO content later, so there is no need to * hold and pin them. */ - if (IS_ENABLED(CONFIG_TEGRA_HOST1X_FIREWALL)) + if (job->enable_firewall) return 0; for (i = 0; i < job->num_cmds; i++) { @@ -280,7 +289,7 @@ static int do_relocs(struct host1x_job *job, struct host1x_job_gather *g) if (cmdbuf != reloc->cmdbuf.bo) continue; - if (IS_ENABLED(CONFIG_TEGRA_HOST1X_FIREWALL)) { + if (job->enable_firewall) { target = (u32 *)job->gather_copy_mapped + reloc->cmdbuf.offset / sizeof(u32) + g->offset / sizeof(u32); @@ -593,7 +602,7 @@ int host1x_job_pin(struct host1x_job *job, struct device *dev) if (err) goto out; - if (IS_ENABLED(CONFIG_TEGRA_HOST1X_FIREWALL)) { + if (job->enable_firewall) { err = copy_gathers(host->dev, job, dev); if (err) goto out; @@ -612,7 +621,7 @@ int host1x_job_pin(struct host1x_job *job, struct device *dev) continue; /* copy_gathers() sets gathers base if firewall is enabled */ - if (!IS_ENABLED(CONFIG_TEGRA_HOST1X_FIREWALL)) + if (!job->enable_firewall) g->base = job->gather_addr_phys[i]; for (j = i + 1; j < job->num_cmds; j++) { @@ -646,7 +655,7 @@ void host1x_job_unpin(struct host1x_job *job) struct host1x_bo_mapping *map = job->unpins[i].map; struct host1x_bo *bo = map->bo; - if (!IS_ENABLED(CONFIG_TEGRA_HOST1X_FIREWALL) && map->size && host->domain) { + if (!job->enable_firewall && map->size && host->domain) { iommu_unmap(host->domain, job->addr_phys[i], map->size); free_iova(&host->iova, iova_pfn(&host->iova, job->addr_phys[i])); } diff --git a/drivers/gpu/host1x/job.h b/drivers/gpu/host1x/job.h index 657e2400..dad5a194 100644 --- a/drivers/gpu/host1x/job.h +++ b/drivers/gpu/host1x/job.h @@ -21,6 +21,8 @@ struct host1x_job_gather { struct host1x_job_wait { u32 id; u32 threshold; + u32 next_class; + bool relative; }; struct host1x_job_cmd { diff --git a/drivers/gpu/host1x/syncpt.c b/drivers/gpu/host1x/syncpt.c index 100270ac..d198a108 100644 --- a/drivers/gpu/host1x/syncpt.c +++ b/drivers/gpu/host1x/syncpt.c @@ -42,6 +42,18 @@ static void host1x_syncpt_base_free(struct host1x_syncpt_base *base) base->requested = false; } +/** + * host1x_syncpt_alloc() - allocate a syncpoint + * @host: host1x device data + * @flags: bitfield of HOST1X_SYNCPT_* flags + * @name: name for the syncpoint for use in debug prints + * + * Allocates a hardware syncpoint for the caller's use. The caller then has + * the sole authority to mutate the syncpoint's value until it is freed again. + * + * If no free syncpoints are available, or a NULL name was specified, returns + * NULL. + */ struct host1x_syncpt *host1x_syncpt_alloc(struct host1x *host, unsigned long flags, const char *name) @@ -50,6 +62,9 @@ struct host1x_syncpt *host1x_syncpt_alloc(struct host1x *host, char *full_name; unsigned int i; + if (!name) + return NULL; + mutex_lock(&host->syncpt_mutex); for (i = 0; i < host->info->nb_pts && kref_read(&sp->ref); i++, sp++) @@ -391,6 +406,7 @@ static void syncpt_release(struct kref *ref) struct host1x_syncpt *sp = container_of(ref, struct host1x_syncpt, ref); atomic_set(&sp->max_val, host1x_syncpt_read(sp)); + sp->locked = false; mutex_lock(&sp->host->syncpt_mutex); @@ -560,6 +576,7 @@ static void do_nothing(struct kref *ref) * available for allocation * * @client: host1x bus client + * @syncpt_id: syncpoint ID to make available * * Makes VBLANK syncpoint available for allocatation if it was * reserved at initialization time. This should be called by the display diff --git a/drivers/gpu/host1x/syncpt.h b/drivers/gpu/host1x/syncpt.h index b42b4254..d6a4e3fb 100644 --- a/drivers/gpu/host1x/syncpt.h +++ b/drivers/gpu/host1x/syncpt.h @@ -41,7 +41,7 @@ struct host1x_syncpt { /* interrupt data */ struct host1x_syncpt_intr intr; - /* + /* * If a submission incrementing this syncpoint fails, lock it so that * further submission cannot be made until application has handled the * failure. diff --git a/drivers/gpu/host1x/uapi.c b/drivers/gpu/host1x/uapi.c deleted file mode 100644 index 6a12c183..00000000 --- a/drivers/gpu/host1x/uapi.c +++ /dev/null @@ -1,379 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * /dev/host1x syncpoint interface - * - * Copyright (c) 2020, NVIDIA Corporation. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "dev.h" -#include "fence.h" -#include "syncpt.h" -#include "uapi.h" - -#include - -static int syncpt_file_release(struct inode *inode, struct file *file) -{ - struct host1x_syncpt *sp = file->private_data; - - host1x_syncpt_put(sp); - - return 0; -} - -static int syncpt_file_ioctl_info(struct host1x_syncpt *sp, void __user *data) -{ - struct host1x_syncpoint_info args; - unsigned long copy_err; - - copy_err = copy_from_user(&args, data, sizeof(args)); - if (copy_err) - return -EFAULT; - - if (args.reserved[0] || args.reserved[1] || args.reserved[2]) - return -EINVAL; - - args.id = sp->id; - - copy_err = copy_to_user(data, &args, sizeof(args)); - if (copy_err) - return -EFAULT; - - return 0; -} - -static int syncpt_file_ioctl_incr(struct host1x_syncpt *sp, void __user *data) -{ - struct host1x_syncpoint_increment args; - unsigned long copy_err; - u32 i; - - copy_err = copy_from_user(&args, data, sizeof(args)); - if (copy_err) - return -EFAULT; - - for (i = 0; i < args.count; i++) { - host1x_syncpt_incr(sp); - if (signal_pending(current)) - return -EINTR; - } - - return 0; -} - -static long syncpt_file_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - void __user *data = (void __user *)arg; - long err; - - switch (cmd) { - case HOST1X_IOCTL_SYNCPOINT_INFO: - err = syncpt_file_ioctl_info(file->private_data, data); - break; - - case HOST1X_IOCTL_SYNCPOINT_INCREMENT: - err = syncpt_file_ioctl_incr(file->private_data, data); - break; - - default: - err = -ENOTTY; - } - - return err; -} - -static const struct file_operations syncpt_file_fops = { - .owner = THIS_MODULE, - .release = syncpt_file_release, - .unlocked_ioctl = syncpt_file_ioctl, - .compat_ioctl = syncpt_file_ioctl, -}; - -struct host1x_syncpt *host1x_syncpt_fd_get(int fd) -{ - struct host1x_syncpt *sp; - struct file *file = fget(fd); - - if (!file) - return ERR_PTR(-EINVAL); - - if (file->f_op != &syncpt_file_fops) { - fput(file); - return ERR_PTR(-EINVAL); - } - - sp = file->private_data; - - host1x_syncpt_get(sp); - - fput(file); - - return sp; -} -EXPORT_SYMBOL(host1x_syncpt_fd_get); - -static int dev_file_open(struct inode *inode, struct file *file) -{ - struct host1x_uapi *uapi = - container_of(inode->i_cdev, struct host1x_uapi, cdev); - - file->private_data = container_of(uapi, struct host1x, uapi); - - return 0; -} - -static int dev_file_ioctl_read_syncpoint(struct host1x *host1x, - void __user *data) -{ - struct host1x_read_syncpoint args; - unsigned long copy_err; - - copy_err = copy_from_user(&args, data, sizeof(args)); - if (copy_err) - return -EFAULT; - - if (args.id >= host1x_syncpt_nb_pts(host1x)) - return -EINVAL; - - args.id = array_index_nospec(args.id, host1x_syncpt_nb_pts(host1x)); - args.value = host1x_syncpt_read(&host1x->syncpt[args.id]); - - copy_err = copy_to_user(data, &args, sizeof(args)); - if (copy_err) - return -EFAULT; - - return 0; -} - -static int dev_file_ioctl_alloc_syncpoint(struct host1x *host1x, - void __user *data) -{ - struct host1x_allocate_syncpoint args; - struct host1x_syncpt *sp; - unsigned long copy_err; - int err; - - copy_err = copy_from_user(&args, data, sizeof(args)); - if (copy_err) - return -EFAULT; - - if (args.reserved[0] || args.reserved[1] || args.reserved[2]) - return -EINVAL; - - sp = host1x_syncpt_alloc(host1x, HOST1X_SYNCPT_CLIENT_MANAGED, - current->comm); - if (!sp) - return -EBUSY; - - err = anon_inode_getfd("host1x_syncpt", &syncpt_file_fops, sp, - O_CLOEXEC); - if (err < 0) - goto free_syncpt; - - args.fd = err; - - copy_err = copy_to_user(data, &args, sizeof(args)); - if (copy_err) { - err = -EFAULT; - goto put_fd; - } - - return 0; - -put_fd: - put_unused_fd(args.fd); -free_syncpt: - host1x_syncpt_put(sp); - - return err; -} - -static int dev_file_ioctl_create_fence(struct host1x *host1x, void __user *data) -{ - struct host1x_create_fence args; - unsigned long copy_err; - int fd; - - copy_err = copy_from_user(&args, data, sizeof(args)); - if (copy_err) - return -EFAULT; - - if (args.reserved[0]) - return -EINVAL; - - if (args.id >= host1x_syncpt_nb_pts(host1x)) - return -EINVAL; - - args.id = array_index_nospec(args.id, host1x_syncpt_nb_pts(host1x)); - - fd = host1x_fence_create_fd(&host1x->syncpt[args.id], args.threshold); - if (fd < 0) - return fd; - - args.fence_fd = fd; - - copy_err = copy_to_user(data, &args, sizeof(args)); - if (copy_err) - return -EFAULT; - - return 0; -} - -static int dev_file_ioctl_fence_extract(struct host1x *host1x, void __user *data) -{ - struct host1x_fence_extract_fence __user *fences_user_ptr; - struct dma_fence *fence, **fences; - struct host1x_fence_extract args; - struct dma_fence_array *array; - unsigned int num_fences, i; - unsigned long copy_err; - int err; - - copy_err = copy_from_user(&args, data, sizeof(args)); - if (copy_err) - return -EFAULT; - - fences_user_ptr = u64_to_user_ptr(args.fences_ptr); - - if (args.reserved[0] || args.reserved[1]) - return -EINVAL; - - fence = sync_file_get_fence(args.fence_fd); - if (!fence) - return -EINVAL; - - array = to_dma_fence_array(fence); - if (array) { - fences = array->fences; - num_fences = array->num_fences; - } else { - fences = &fence; - num_fences = 1; - } - - for (i = 0; i < min(num_fences, args.num_fences); i++) { - struct host1x_fence_extract_fence f; - - err = host1x_fence_extract(fences[i], &f.id, &f.threshold); - if (err) - goto put_fence; - - copy_err = copy_to_user(fences_user_ptr + i, &f, sizeof(f)); - if (copy_err) { - err = -EFAULT; - goto put_fence; - } - } - - args.num_fences = i+1; - - copy_err = copy_to_user(data, &args, sizeof(args)); - if (copy_err) { - err = -EFAULT; - goto put_fence; - } - - return 0; - -put_fence: - dma_fence_put(fence); - - return err; -} - -static long dev_file_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - void __user *data = (void __user *)arg; - long err; - - switch (cmd) { - case HOST1X_IOCTL_READ_SYNCPOINT: - err = dev_file_ioctl_read_syncpoint(file->private_data, data); - break; - - case HOST1X_IOCTL_ALLOCATE_SYNCPOINT: - err = dev_file_ioctl_alloc_syncpoint(file->private_data, data); - break; - - case HOST1X_IOCTL_CREATE_FENCE: - err = dev_file_ioctl_create_fence(file->private_data, data); - break; - - case HOST1X_IOCTL_FENCE_EXTRACT: - err = dev_file_ioctl_fence_extract(file->private_data, data); - break; - - default: - err = -ENOTTY; - } - - return err; -} - -static const struct file_operations dev_file_fops = { - .owner = THIS_MODULE, - .open = dev_file_open, - .unlocked_ioctl = dev_file_ioctl, - .compat_ioctl = dev_file_ioctl, -}; - -int host1x_uapi_init(struct host1x_uapi *uapi, struct host1x *host1x) -{ - int err; - dev_t dev_num; - - err = alloc_chrdev_region(&dev_num, 0, 1, "host1x"); - if (err) - return err; - - uapi->class = class_create(THIS_MODULE, "host1x"); - if (IS_ERR(uapi->class)) { - err = PTR_ERR(uapi->class); - goto unregister_chrdev_region; - } - - cdev_init(&uapi->cdev, &dev_file_fops); - err = cdev_add(&uapi->cdev, dev_num, 1); - if (err) - goto destroy_class; - - uapi->dev = device_create(uapi->class, host1x->dev, - dev_num, NULL, "host1x"); - if (IS_ERR(uapi->dev)) { - err = PTR_ERR(uapi->dev); - goto del_cdev; - } - - cdev_add(&uapi->cdev, dev_num, 1); - - uapi->dev_num = dev_num; - - return 0; - -del_cdev: - cdev_del(&uapi->cdev); -destroy_class: - class_destroy(uapi->class); -unregister_chrdev_region: - unregister_chrdev_region(dev_num, 1); - - return err; -} - -void host1x_uapi_deinit(struct host1x_uapi *uapi) -{ - device_destroy(uapi->class, uapi->dev_num); - cdev_del(&uapi->cdev); - class_destroy(uapi->class); - unregister_chrdev_region(uapi->dev_num, 1); -} diff --git a/drivers/gpu/host1x/uapi.h b/drivers/gpu/host1x/uapi.h deleted file mode 100644 index 7beb5e44..00000000 --- a/drivers/gpu/host1x/uapi.h +++ /dev/null @@ -1,22 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (c) 2020, NVIDIA Corporation. - */ - -#ifndef HOST1X_UAPI_H -#define HOST1X_UAPI_H - -#include - -struct host1x_uapi { - struct class *class; - - struct cdev cdev; - struct device *dev; - dev_t dev_num; -}; - -int host1x_uapi_init(struct host1x_uapi *uapi, struct host1x *host1x); -void host1x_uapi_deinit(struct host1x_uapi *uapi); - -#endif