From e6245a54c34cbd24871cfb8d0f9abf0b8071dd61 Mon Sep 17 00:00:00 2001 From: Harshdeep Dhatt Date: Thu, 23 Jul 2020 13:39:39 -0600 Subject: [PATCH] msm: kgsl: Add the f2h daemon This daemon is a bottom half handler for asynchronous packets originating from GMU for example TS_RETIRE, CONTEXT_BAD and F2H_MSG_GMU_CNTR_REGISTER. The way it works is -the interrupt handler snoops all the packets coming from GMU, processes the acks inline but copies the aforementioned packets to a queue and wakes up the daemon to process those. Change-Id: Ib2c9d470a9c4c64bc44409015201adaff398edd8 Signed-off-by: Harshdeep Dhatt --- drivers/gpu/msm/adreno_a6xx_hwsched_hfi.c | 75 ++++++++++++++++++++++- drivers/gpu/msm/adreno_a6xx_hwsched_hfi.h | 7 ++- drivers/gpu/msm/adreno_hwsched.c | 2 +- drivers/gpu/msm/adreno_hwsched.h | 8 +++ 4 files changed, 89 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/msm/adreno_a6xx_hwsched_hfi.c b/drivers/gpu/msm/adreno_a6xx_hwsched_hfi.c index 42c741e6a0f0..c00d6d1bf554 100644 --- a/drivers/gpu/msm/adreno_a6xx_hwsched_hfi.c +++ b/drivers/gpu/msm/adreno_a6xx_hwsched_hfi.c @@ -15,6 +15,9 @@ #define HFI_QUEUE_MAX (HFI_QUEUE_DEFAULT_CNT + HFI_QUEUE_DISPATCH_MAX_CNT) +/* Use a kmem cache to speed up allocations for f2h packets */ +static struct kmem_cache *f2h_cache; + #define DEFINE_QHDR(gmuaddr, id, prio) \ {\ .status = 1, \ @@ -145,10 +148,38 @@ static void a6xx_receive_ack_async(struct adreno_device *adreno_dev, void *rcvd) MSG_HDR_GET_SEQNUM(waiters[i])); } +struct f2h_packet { + /** @rcvd: the contents of the fw to host packet */ + u32 rcvd[MAX_RCVD_SIZE]; + /** @node: To add to the fw to host msg list */ + struct llist_node node; +}; + +static void add_f2h_packet(struct adreno_device *adreno_dev, u32 *msg) +{ + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); + struct a6xx_hwsched_hfi *hfi = to_a6xx_hwsched_hfi(adreno_dev); + struct f2h_packet *pkt = kmem_cache_alloc(f2h_cache, GFP_ATOMIC); + u32 size = MSG_HDR_GET_SIZE(msg[0]) << 2; + + if (!pkt) + return; + + if (size > sizeof(pkt->rcvd)) + dev_err_ratelimited(&gmu->pdev->dev, + "f2h packet too big: %d allowed: %d\n", + size, sizeof(pkt->rcvd)); + + memcpy(pkt->rcvd, msg, min_t(u32, size, sizeof(pkt->rcvd))); + + llist_add(&pkt->node, &hfi->f2h_msglist); +} + static void process_msgq_irq(struct adreno_device *adreno_dev) { struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); u32 rcvd[MAX_RCVD_SIZE]; + struct a6xx_hwsched_hfi *hfi = to_a6xx_hwsched_hfi(adreno_dev); while (a6xx_hfi_queue_read(gmu, HFI_MSG_ID, rcvd, sizeof(rcvd)) > 0) { @@ -157,8 +188,12 @@ static void process_msgq_irq(struct adreno_device *adreno_dev) * because hfi sending thread waits for completion while * holding the device mutex */ - if (MSG_HDR_GET_TYPE(rcvd[0]) == HFI_MSG_ACK) + if (MSG_HDR_GET_TYPE(rcvd[0]) == HFI_MSG_ACK) { a6xx_receive_ack_async(adreno_dev, rcvd); + } else { + add_f2h_packet(adreno_dev, rcvd); + wake_up_interruptible(&hfi->f2h_wq); + } } } @@ -749,6 +784,36 @@ int a6xx_hwsched_cp_init(struct adreno_device *adreno_dev) return ret; } +static int hfi_f2h_main(void *arg) +{ + struct adreno_device *adreno_dev = arg; + struct a6xx_hwsched_hfi *hfi = to_a6xx_hwsched_hfi(adreno_dev); + struct llist_node *list; + struct f2h_packet *pkt, *tmp; + + while (!kthread_should_stop()) { + wait_event_interruptible(hfi->f2h_wq, + (!llist_empty(&hfi->f2h_msglist) && + !kthread_should_stop())); + + if (kthread_should_stop()) + break; + + list = llist_del_all(&hfi->f2h_msglist); + + list = llist_reverse_order(list); + + llist_for_each_entry_safe(pkt, tmp, list, node) { + if (MSG_HDR_GET_ID(pkt->rcvd[0]) == F2H_MSG_TS_RETIRE) + adreno_hwsched_trigger(adreno_dev); + + kmem_cache_free(f2h_cache, pkt); + } + } + + return 0; +} + int a6xx_hwsched_hfi_probe(struct adreno_device *adreno_dev) { struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); @@ -768,6 +833,14 @@ int a6xx_hwsched_hfi_probe(struct adreno_device *adreno_dev) INIT_LIST_HEAD(&hw_hfi->msglist); + init_llist_head(&hw_hfi->f2h_msglist); + + init_waitqueue_head(&hw_hfi->f2h_wq); + + hw_hfi->f2h_task = kthread_run(hfi_f2h_main, adreno_dev, "gmu_f2h"); + + f2h_cache = KMEM_CACHE(f2h_packet, 0); + return 0; } diff --git a/drivers/gpu/msm/adreno_a6xx_hwsched_hfi.h b/drivers/gpu/msm/adreno_a6xx_hwsched_hfi.h index 7a8e1ec48850..97f62fb68b1b 100644 --- a/drivers/gpu/msm/adreno_a6xx_hwsched_hfi.h +++ b/drivers/gpu/msm/adreno_a6xx_hwsched_hfi.h @@ -113,7 +113,12 @@ struct a6xx_hwsched_hfi { rwlock_t msglock; /** @msglist: List of un-ACKed hfi packets */ struct list_head msglist; - + /** @f2h_task: Task for processing gmu fw to host packets */ + struct task_struct *f2h_task; + /** @f2h_msglist: List of gmu fw to host packets */ + struct llist_head f2h_msglist; + /** @f2h_wq: Waitqueue for the f2h_task */ + wait_queue_head_t f2h_wq; }; struct kgsl_drawobj_cmd; diff --git a/drivers/gpu/msm/adreno_hwsched.c b/drivers/gpu/msm/adreno_hwsched.c index 8d30e49b8bfc..1f015e4fbde4 100644 --- a/drivers/gpu/msm/adreno_hwsched.c +++ b/drivers/gpu/msm/adreno_hwsched.c @@ -526,7 +526,7 @@ static void hwsched_issuecmds(struct adreno_device *adreno_dev) hwsched_handle_jobs(adreno_dev, i); } -static void adreno_hwsched_trigger(struct adreno_device *adreno_dev) +void adreno_hwsched_trigger(struct adreno_device *adreno_dev) { struct adreno_hwsched *hwsched = to_hwsched(adreno_dev); diff --git a/drivers/gpu/msm/adreno_hwsched.h b/drivers/gpu/msm/adreno_hwsched.h index 49d261ef77d0..7e1256c5e7a0 100644 --- a/drivers/gpu/msm/adreno_hwsched.h +++ b/drivers/gpu/msm/adreno_hwsched.h @@ -30,6 +30,14 @@ enum adreno_hwsched_flags { ADRENO_HWSCHED_POWER = 0, }; +/** + * adreno_hwsched_trigger - Function to schedule the hwsched thread + * @adreno_dev: A handle to adreno device + * + * Schedule the hw dispatcher for retiring and submitting command objects + */ +void adreno_hwsched_trigger(struct adreno_device *adreno_dev); + /** * adreno_hwsched_queue_cmds() - Queue a new draw object in the context * @dev_priv: Pointer to the device private struct