Loading drivers/gpu/msm/adreno_a6xx_gmu.c +19 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include "adreno.h" #include "adreno_a6xx.h" #include "adreno_hwsched.h" #include "adreno_trace.h" #include "kgsl_bus.h" #include "kgsl_device.h" #include "kgsl_trace.h" Loading Loading @@ -415,6 +416,22 @@ static void a6xx_gmu_power_config(struct adreno_device *adreno_dev) RPMH_ENABLE_MASK); } static void gmu_ao_sync_event(struct adreno_device *adreno_dev) { unsigned long flags; u64 ticks; local_irq_save(flags); /* Read GMU always on register */ ticks = a6xx_read_alwayson(adreno_dev); /* Trace the GMU time to create a mapping to ftrace time */ trace_gmu_ao_sync(ticks); local_irq_restore(flags); } int a6xx_gmu_device_start(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); Loading @@ -422,6 +439,8 @@ int a6xx_gmu_device_start(struct adreno_device *adreno_dev) u32 val = 0x00000100; u32 mask = 0x000001FF; gmu_ao_sync_event(adreno_dev); /* Check for 0xBABEFACE on legacy targets */ if (gmu->ver.core <= 0x20010004) { val = 0xBABEFACE; Loading drivers/gpu/msm/adreno_a6xx_hfi.c +6 −6 Original line number Diff line number Diff line Loading @@ -473,7 +473,7 @@ static int a6xx_hfi_send_test(struct adreno_device *adreno_dev) return a6xx_hfi_send_generic_req(adreno_dev, &cmd); } static void receive_err_req(struct a6xx_gmu_device *gmu, void *rcvd) void adreno_a6xx_receive_err_req(struct a6xx_gmu_device *gmu, void *rcvd) { struct hfi_err_cmd *cmd = rcvd; Loading @@ -483,7 +483,7 @@ static void receive_err_req(struct a6xx_gmu_device *gmu, void *rcvd) (char *) cmd->data); } static void receive_debug_req(struct a6xx_gmu_device *gmu, void *rcvd) void adreno_a6xx_receive_debug_req(struct a6xx_gmu_device *gmu, void *rcvd) { struct hfi_debug_cmd *cmd = rcvd; Loading @@ -503,10 +503,10 @@ static void a6xx_hfi_v1_receiver(struct a6xx_gmu_device *gmu, uint32_t *rcvd, /* V1 Request Handler */ switch (MSG_HDR_GET_ID(rcvd[0])) { case F2H_MSG_ERR: /* No Reply */ receive_err_req(gmu, rcvd); adreno_a6xx_receive_err_req(gmu, rcvd); break; case F2H_MSG_DEBUG: /* No Reply */ receive_debug_req(gmu, rcvd); adreno_a6xx_receive_debug_req(gmu, rcvd); break; default: /* No Reply */ dev_err(&gmu->pdev->dev, Loading Loading @@ -540,10 +540,10 @@ int a6xx_hfi_process_queue(struct a6xx_gmu_device *gmu, /* V2 Request Handler */ switch (MSG_HDR_GET_ID(rcvd[0])) { case F2H_MSG_ERR: /* No Reply */ receive_err_req(gmu, rcvd); adreno_a6xx_receive_err_req(gmu, rcvd); break; case F2H_MSG_DEBUG: /* No Reply */ receive_debug_req(gmu, rcvd); adreno_a6xx_receive_debug_req(gmu, rcvd); break; default: /* No Reply */ dev_err(&gmu->pdev->dev, Loading drivers/gpu/msm/adreno_a6xx_hfi.h +8 −0 Original line number Diff line number Diff line Loading @@ -534,6 +534,12 @@ struct hfi_submit_cmd { u32 numibs; } __packed; struct hfi_log_block { u32 hdr; u32 version; u32 start_index; u32 stop_index; } __packed; /** * struct pending_cmd - data structure to track outstanding HFI Loading Loading @@ -717,4 +723,6 @@ int a6xx_hfi_process_queue(struct a6xx_gmu_device *gmu, * Return: 0 on success or negative error on failure */ int a6xx_hfi_cmdq_write(struct adreno_device *adreno_dev, u32 *msg); void adreno_a6xx_receive_err_req(struct a6xx_gmu_device *gmu, void *rcvd); void adreno_a6xx_receive_debug_req(struct a6xx_gmu_device *gmu, void *rcvd); #endif drivers/gpu/msm/adreno_a6xx_hwsched_hfi.c +79 −3 Original line number Diff line number Diff line Loading @@ -222,6 +222,45 @@ static void process_msgq_irq(struct adreno_device *adreno_dev) } } static void adreno_a6xx_add_log_block(struct adreno_device *adreno_dev, u32 *msg) { struct f2h_packet *pkt = kmem_cache_alloc(f2h_cache, GFP_ATOMIC); struct a6xx_hwsched_hfi *hfi = to_a6xx_hwsched_hfi(adreno_dev); u32 size = MSG_HDR_GET_SIZE(msg[0]) << 2; if (!pkt) return; memcpy(pkt->rcvd, msg, min_t(u32, size, sizeof(pkt->rcvd))); /* * Add the log block packets from GMU to a secondary list to ensure * the time critical TS_RETIRE packet processing on the primary list * is not delayed */ llist_add(&pkt->node, &hfi->f2h_secondary_list); wake_up_interruptible(&hfi->f2h_wq); } static void process_dbgq_irq(struct adreno_device *adreno_dev) { struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); u32 rcvd[MAX_RCVD_SIZE]; while (a6xx_hfi_queue_read(gmu, HFI_DBG_ID, rcvd, sizeof(rcvd)) > 0) { if (MSG_HDR_GET_ID(rcvd[0]) == F2H_MSG_ERR) adreno_a6xx_receive_err_req(gmu, rcvd); if (MSG_HDR_GET_ID(rcvd[0]) == F2H_MSG_DEBUG) adreno_a6xx_receive_debug_req(gmu, rcvd); if (MSG_HDR_GET_ID(rcvd[0]) == F2H_MSG_LOG_BLOCK) adreno_a6xx_add_log_block(adreno_dev, rcvd); } } /* HFI interrupt handler */ static irqreturn_t a6xx_hwsched_hfi_handler(int irq, void *data) { Loading @@ -234,10 +273,18 @@ static irqreturn_t a6xx_hwsched_hfi_handler(int irq, void *data) gmu_core_regread(device, A6XX_GMU_GMU2HOST_INTR_INFO, &status); gmu_core_regwrite(device, A6XX_GMU_GMU2HOST_INTR_CLR, hfi->irq_mask); /* * If interrupts are not enabled on the HFI message queue, * the inline message processing loop will process it, * else, process it here. */ if (!(hfi->irq_mask & HFI_IRQ_MSGQ_MASK)) status &= ~HFI_IRQ_MSGQ_MASK; if (status & HFI_IRQ_MSGQ_MASK) process_msgq_irq(adreno_dev); if (status & HFI_IRQ_DBGQ_MASK) a6xx_hfi_process_queue(gmu, HFI_DBG_ID, NULL); process_dbgq_irq(adreno_dev); if (status & HFI_IRQ_CM3_FAULT_MASK) { atomic_set(&gmu->cm3_fault, 1); Loading Loading @@ -832,6 +879,24 @@ static void process_ctx_bad(struct adreno_device *adreno_dev, void *rcvd) adreno_hwsched_mark_drawobj(adreno_dev, cmd->ctxt_id, cmd->ts); } static void process_log_block(struct adreno_device *adreno_dev, void *data) { struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); struct hfi_log_block *cmd = data; u32 *log_event = gmu->gmu_log->hostptr; u32 start, end; start = cmd->start_index; end = cmd->stop_index; log_event += start * 4; while (start != end) { trace_gmu_event(log_event); log_event += 4; start++; } } static int hfi_f2h_main(void *arg) { struct adreno_device *adreno_dev = arg; Loading @@ -841,8 +906,9 @@ static int hfi_f2h_main(void *arg) while (!kthread_should_stop()) { wait_event_interruptible(hfi->f2h_wq, (!llist_empty(&hfi->f2h_msglist) && !kthread_should_stop())); ((!llist_empty(&hfi->f2h_msglist) || !llist_empty(&hfi->f2h_secondary_list)) && !kthread_should_stop())); if (kthread_should_stop()) break; Loading @@ -860,6 +926,16 @@ static int hfi_f2h_main(void *arg) kmem_cache_free(f2h_cache, pkt); } /* Process packets on the secondary list after the primary list */ list = llist_del_all(&hfi->f2h_secondary_list); list = llist_reverse_order(list); llist_for_each_entry_safe(pkt, tmp, list, node) { if (MSG_HDR_GET_ID(pkt->rcvd[0]) == F2H_MSG_LOG_BLOCK) process_log_block(adreno_dev, pkt->rcvd); kmem_cache_free(f2h_cache, pkt); } } return 0; Loading drivers/gpu/msm/adreno_a6xx_hwsched_hfi.h +2 −0 Original line number Diff line number Diff line Loading @@ -117,6 +117,8 @@ struct a6xx_hwsched_hfi { struct task_struct *f2h_task; /** @f2h_msglist: List of gmu fw to host packets */ struct llist_head f2h_msglist; /** @f2h_secondary_list: List of host profile packets from GMU */ struct llist_head f2h_secondary_list; /** @f2h_wq: Waitqueue for the f2h_task */ wait_queue_head_t f2h_wq; }; Loading Loading
drivers/gpu/msm/adreno_a6xx_gmu.c +19 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include "adreno.h" #include "adreno_a6xx.h" #include "adreno_hwsched.h" #include "adreno_trace.h" #include "kgsl_bus.h" #include "kgsl_device.h" #include "kgsl_trace.h" Loading Loading @@ -415,6 +416,22 @@ static void a6xx_gmu_power_config(struct adreno_device *adreno_dev) RPMH_ENABLE_MASK); } static void gmu_ao_sync_event(struct adreno_device *adreno_dev) { unsigned long flags; u64 ticks; local_irq_save(flags); /* Read GMU always on register */ ticks = a6xx_read_alwayson(adreno_dev); /* Trace the GMU time to create a mapping to ftrace time */ trace_gmu_ao_sync(ticks); local_irq_restore(flags); } int a6xx_gmu_device_start(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); Loading @@ -422,6 +439,8 @@ int a6xx_gmu_device_start(struct adreno_device *adreno_dev) u32 val = 0x00000100; u32 mask = 0x000001FF; gmu_ao_sync_event(adreno_dev); /* Check for 0xBABEFACE on legacy targets */ if (gmu->ver.core <= 0x20010004) { val = 0xBABEFACE; Loading
drivers/gpu/msm/adreno_a6xx_hfi.c +6 −6 Original line number Diff line number Diff line Loading @@ -473,7 +473,7 @@ static int a6xx_hfi_send_test(struct adreno_device *adreno_dev) return a6xx_hfi_send_generic_req(adreno_dev, &cmd); } static void receive_err_req(struct a6xx_gmu_device *gmu, void *rcvd) void adreno_a6xx_receive_err_req(struct a6xx_gmu_device *gmu, void *rcvd) { struct hfi_err_cmd *cmd = rcvd; Loading @@ -483,7 +483,7 @@ static void receive_err_req(struct a6xx_gmu_device *gmu, void *rcvd) (char *) cmd->data); } static void receive_debug_req(struct a6xx_gmu_device *gmu, void *rcvd) void adreno_a6xx_receive_debug_req(struct a6xx_gmu_device *gmu, void *rcvd) { struct hfi_debug_cmd *cmd = rcvd; Loading @@ -503,10 +503,10 @@ static void a6xx_hfi_v1_receiver(struct a6xx_gmu_device *gmu, uint32_t *rcvd, /* V1 Request Handler */ switch (MSG_HDR_GET_ID(rcvd[0])) { case F2H_MSG_ERR: /* No Reply */ receive_err_req(gmu, rcvd); adreno_a6xx_receive_err_req(gmu, rcvd); break; case F2H_MSG_DEBUG: /* No Reply */ receive_debug_req(gmu, rcvd); adreno_a6xx_receive_debug_req(gmu, rcvd); break; default: /* No Reply */ dev_err(&gmu->pdev->dev, Loading Loading @@ -540,10 +540,10 @@ int a6xx_hfi_process_queue(struct a6xx_gmu_device *gmu, /* V2 Request Handler */ switch (MSG_HDR_GET_ID(rcvd[0])) { case F2H_MSG_ERR: /* No Reply */ receive_err_req(gmu, rcvd); adreno_a6xx_receive_err_req(gmu, rcvd); break; case F2H_MSG_DEBUG: /* No Reply */ receive_debug_req(gmu, rcvd); adreno_a6xx_receive_debug_req(gmu, rcvd); break; default: /* No Reply */ dev_err(&gmu->pdev->dev, Loading
drivers/gpu/msm/adreno_a6xx_hfi.h +8 −0 Original line number Diff line number Diff line Loading @@ -534,6 +534,12 @@ struct hfi_submit_cmd { u32 numibs; } __packed; struct hfi_log_block { u32 hdr; u32 version; u32 start_index; u32 stop_index; } __packed; /** * struct pending_cmd - data structure to track outstanding HFI Loading Loading @@ -717,4 +723,6 @@ int a6xx_hfi_process_queue(struct a6xx_gmu_device *gmu, * Return: 0 on success or negative error on failure */ int a6xx_hfi_cmdq_write(struct adreno_device *adreno_dev, u32 *msg); void adreno_a6xx_receive_err_req(struct a6xx_gmu_device *gmu, void *rcvd); void adreno_a6xx_receive_debug_req(struct a6xx_gmu_device *gmu, void *rcvd); #endif
drivers/gpu/msm/adreno_a6xx_hwsched_hfi.c +79 −3 Original line number Diff line number Diff line Loading @@ -222,6 +222,45 @@ static void process_msgq_irq(struct adreno_device *adreno_dev) } } static void adreno_a6xx_add_log_block(struct adreno_device *adreno_dev, u32 *msg) { struct f2h_packet *pkt = kmem_cache_alloc(f2h_cache, GFP_ATOMIC); struct a6xx_hwsched_hfi *hfi = to_a6xx_hwsched_hfi(adreno_dev); u32 size = MSG_HDR_GET_SIZE(msg[0]) << 2; if (!pkt) return; memcpy(pkt->rcvd, msg, min_t(u32, size, sizeof(pkt->rcvd))); /* * Add the log block packets from GMU to a secondary list to ensure * the time critical TS_RETIRE packet processing on the primary list * is not delayed */ llist_add(&pkt->node, &hfi->f2h_secondary_list); wake_up_interruptible(&hfi->f2h_wq); } static void process_dbgq_irq(struct adreno_device *adreno_dev) { struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); u32 rcvd[MAX_RCVD_SIZE]; while (a6xx_hfi_queue_read(gmu, HFI_DBG_ID, rcvd, sizeof(rcvd)) > 0) { if (MSG_HDR_GET_ID(rcvd[0]) == F2H_MSG_ERR) adreno_a6xx_receive_err_req(gmu, rcvd); if (MSG_HDR_GET_ID(rcvd[0]) == F2H_MSG_DEBUG) adreno_a6xx_receive_debug_req(gmu, rcvd); if (MSG_HDR_GET_ID(rcvd[0]) == F2H_MSG_LOG_BLOCK) adreno_a6xx_add_log_block(adreno_dev, rcvd); } } /* HFI interrupt handler */ static irqreturn_t a6xx_hwsched_hfi_handler(int irq, void *data) { Loading @@ -234,10 +273,18 @@ static irqreturn_t a6xx_hwsched_hfi_handler(int irq, void *data) gmu_core_regread(device, A6XX_GMU_GMU2HOST_INTR_INFO, &status); gmu_core_regwrite(device, A6XX_GMU_GMU2HOST_INTR_CLR, hfi->irq_mask); /* * If interrupts are not enabled on the HFI message queue, * the inline message processing loop will process it, * else, process it here. */ if (!(hfi->irq_mask & HFI_IRQ_MSGQ_MASK)) status &= ~HFI_IRQ_MSGQ_MASK; if (status & HFI_IRQ_MSGQ_MASK) process_msgq_irq(adreno_dev); if (status & HFI_IRQ_DBGQ_MASK) a6xx_hfi_process_queue(gmu, HFI_DBG_ID, NULL); process_dbgq_irq(adreno_dev); if (status & HFI_IRQ_CM3_FAULT_MASK) { atomic_set(&gmu->cm3_fault, 1); Loading Loading @@ -832,6 +879,24 @@ static void process_ctx_bad(struct adreno_device *adreno_dev, void *rcvd) adreno_hwsched_mark_drawobj(adreno_dev, cmd->ctxt_id, cmd->ts); } static void process_log_block(struct adreno_device *adreno_dev, void *data) { struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); struct hfi_log_block *cmd = data; u32 *log_event = gmu->gmu_log->hostptr; u32 start, end; start = cmd->start_index; end = cmd->stop_index; log_event += start * 4; while (start != end) { trace_gmu_event(log_event); log_event += 4; start++; } } static int hfi_f2h_main(void *arg) { struct adreno_device *adreno_dev = arg; Loading @@ -841,8 +906,9 @@ static int hfi_f2h_main(void *arg) while (!kthread_should_stop()) { wait_event_interruptible(hfi->f2h_wq, (!llist_empty(&hfi->f2h_msglist) && !kthread_should_stop())); ((!llist_empty(&hfi->f2h_msglist) || !llist_empty(&hfi->f2h_secondary_list)) && !kthread_should_stop())); if (kthread_should_stop()) break; Loading @@ -860,6 +926,16 @@ static int hfi_f2h_main(void *arg) kmem_cache_free(f2h_cache, pkt); } /* Process packets on the secondary list after the primary list */ list = llist_del_all(&hfi->f2h_secondary_list); list = llist_reverse_order(list); llist_for_each_entry_safe(pkt, tmp, list, node) { if (MSG_HDR_GET_ID(pkt->rcvd[0]) == F2H_MSG_LOG_BLOCK) process_log_block(adreno_dev, pkt->rcvd); kmem_cache_free(f2h_cache, pkt); } } return 0; Loading
drivers/gpu/msm/adreno_a6xx_hwsched_hfi.h +2 −0 Original line number Diff line number Diff line Loading @@ -117,6 +117,8 @@ struct a6xx_hwsched_hfi { struct task_struct *f2h_task; /** @f2h_msglist: List of gmu fw to host packets */ struct llist_head f2h_msglist; /** @f2h_secondary_list: List of host profile packets from GMU */ struct llist_head f2h_secondary_list; /** @f2h_wq: Waitqueue for the f2h_task */ wait_queue_head_t f2h_wq; }; Loading