Loading drivers/media/platform/msm/vidc/venus_hfi.c +312 −191 Original line number Diff line number Diff line Loading @@ -849,6 +849,210 @@ static int venus_hfi_unvote_buses(void *dev) return rc; } static int venus_hfi_iface_cmdq_write_nolock(struct venus_hfi_device *device, void *pkt); static int venus_hfi_iface_cmdq_write(struct venus_hfi_device *device, void *pkt) { int result = -EPERM; if (!device || !pkt) { dprintk(VIDC_ERR, "Invalid Params"); return -EINVAL; } mutex_lock(&device->write_lock); mutex_lock(&device->clk_pwr_lock); result = venus_hfi_iface_cmdq_write_nolock(device, pkt); mutex_unlock(&device->clk_pwr_lock); mutex_unlock(&device->write_lock); return result; } static int venus_hfi_core_set_resource(void *device, struct vidc_resource_hdr *resource_hdr, void *resource_value, bool locked) { struct hfi_cmd_sys_set_resource_packet *pkt; u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE]; int rc = 0; struct venus_hfi_device *dev; if (!device || !resource_hdr || !resource_value) { dprintk(VIDC_ERR, "set_res: Invalid Params\n"); return -EINVAL; } else { dev = device; } pkt = (struct hfi_cmd_sys_set_resource_packet *) packet; rc = create_pkt_set_cmd_sys_resource(pkt, resource_hdr, resource_value); if (rc) { dprintk(VIDC_ERR, "set_res: failed to create packet\n"); goto err_create_pkt; } rc = locked ? venus_hfi_iface_cmdq_write(dev, pkt) : venus_hfi_iface_cmdq_write_nolock(dev, pkt); if (rc) rc = -ENOTEMPTY; err_create_pkt: return rc; } static int venus_hfi_core_release_resource(void *device, struct vidc_resource_hdr *resource_hdr) { struct hfi_cmd_sys_release_resource_packet pkt; int rc = 0; struct venus_hfi_device *dev; if (!device || !resource_hdr) { dprintk(VIDC_ERR, "Inv-Params in rel_res\n"); return -EINVAL; } else { dev = device; } rc = create_pkt_cmd_sys_release_resource(&pkt, resource_hdr); if (rc) { dprintk(VIDC_ERR, "release_res: failed to create packet\n"); goto err_create_pkt; } if (venus_hfi_iface_cmdq_write(dev, &pkt)) rc = -ENOTEMPTY; err_create_pkt: return rc; } static int venus_hfi_set_ocmem(void *dev, struct ocmem_buf *ocmem, bool locked) { struct vidc_resource_hdr rhdr; struct venus_hfi_device *device = dev; int rc = 0; if (!device || !ocmem) { dprintk(VIDC_ERR, "Invalid params, core:%p, ocmem: %p\n", device, ocmem); return -EINVAL; } rhdr.resource_id = VIDC_RESOURCE_OCMEM; /* * This handle is just used as a cookie and not(cannot be) * accessed by fw */ rhdr.resource_handle = (u32)(unsigned long)&device->resources.ocmem; rhdr.size = ocmem->len; rc = venus_hfi_core_set_resource(device, &rhdr, ocmem, locked); if (rc) { dprintk(VIDC_ERR, "Failed to set OCMEM on driver\n"); goto ocmem_set_failed; } dprintk(VIDC_DBG, "OCMEM set, addr = %lx, size: %ld\n", ocmem->addr, ocmem->len); ocmem_set_failed: return rc; } static int venus_hfi_unset_ocmem(void *dev) { struct vidc_resource_hdr rhdr; struct venus_hfi_device *device = dev; int rc = 0; if (!device) { dprintk(VIDC_ERR, "%s Invalid params, device:%p\n", __func__, device); rc = -EINVAL; goto ocmem_unset_failed; } if (!device->resources.ocmem.buf) { dprintk(VIDC_INFO, "%s Trying to free OCMEM which is not set\n", __func__); rc = -EINVAL; goto ocmem_unset_failed; } rhdr.resource_id = VIDC_RESOURCE_OCMEM; /* * This handle is just used as a cookie and not(cannot be) * accessed by fw */ rhdr.resource_handle = (u32)(unsigned long)&device->resources.ocmem; rc = venus_hfi_core_release_resource(device, &rhdr); if (rc) dprintk(VIDC_ERR, "Failed to unset OCMEM on driver\n"); ocmem_unset_failed: return rc; } static int __alloc_ocmem(void *dev, unsigned long size, bool locked) { int rc = 0; struct ocmem_buf *ocmem_buffer; struct venus_hfi_device *device = dev; if (!device || !size) { dprintk(VIDC_ERR, "%s Invalid param, core: %p, size: %lu\n", __func__, device, size); return -EINVAL; } ocmem_buffer = device->resources.ocmem.buf; if (!ocmem_buffer || ocmem_buffer->len < size) { ocmem_buffer = ocmem_allocate(OCMEM_VIDEO, size); if (IS_ERR_OR_NULL(ocmem_buffer)) { dprintk(VIDC_ERR, "ocmem_allocate_nb failed: %lu\n", (unsigned long) ocmem_buffer); rc = -ENOMEM; goto ocmem_alloc_failed; } device->resources.ocmem.buf = ocmem_buffer; rc = venus_hfi_set_ocmem(device, ocmem_buffer, locked); if (rc) { dprintk(VIDC_ERR, "Failed to set ocmem: %d\n", rc); goto ocmem_set_failed; } } else dprintk(VIDC_DBG, "OCMEM is enough. reqd: %lu, available: %lu\n", size, ocmem_buffer->len); return rc; ocmem_set_failed: ocmem_free(OCMEM_VIDEO, device->resources.ocmem.buf); device->resources.ocmem.buf = NULL; ocmem_alloc_failed: return rc; } static int venus_hfi_alloc_ocmem(void *dev, unsigned long size) { return __alloc_ocmem(dev, size, true); } static int venus_hfi_free_ocmem(void *dev) { struct venus_hfi_device *device = dev; int rc = 0; if (!device) { dprintk(VIDC_ERR, "%s invalid device handle %p\n", __func__, device); return -EINVAL; } if (device->resources.ocmem.buf) { rc = ocmem_free(OCMEM_VIDEO, device->resources.ocmem.buf); if (rc) dprintk(VIDC_ERR, "Failed to free ocmem\n"); device->resources.ocmem.buf = NULL; } return rc; } static inline int venus_hfi_tzbsp_set_video_state(enum tzbsp_video_state state) { struct tzbsp_video_set_state_req cmd = {0}; Loading Loading @@ -912,7 +1116,6 @@ static unsigned long venus_hfi_get_clock_rate(struct clock_info *clock, return ret; } /*Calling function is responsible to acquire device->clk_pwr_lock*/ static inline int venus_hfi_clk_enable(struct venus_hfi_device *device) { int rc = 0; Loading @@ -923,6 +1126,8 @@ static inline int venus_hfi_clk_enable(struct venus_hfi_device *device) dprintk(VIDC_ERR, "Invalid params: %p\n", device); return -EINVAL; } WARN(!mutex_is_locked(&device->clk_pwr_lock), "Clock/power lock must be acquired"); if (device->clocks_enabled) { dprintk(VIDC_DBG, "Clocks already enabled\n"); return 0; Loading Loading @@ -960,7 +1165,6 @@ fail_clk_enable: return rc; } /*Calling function is responsible to acquire device->clk_pwr_lock*/ static inline void venus_hfi_clk_disable(struct venus_hfi_device *device) { struct clock_info *cl; Loading @@ -969,6 +1173,8 @@ static inline void venus_hfi_clk_disable(struct venus_hfi_device *device) dprintk(VIDC_ERR, "Invalid params: %p\n", device); return; } WARN(!mutex_is_locked(&device->clk_pwr_lock), "Clock/power lock must be acquired"); if (!device->clocks_enabled) { dprintk(VIDC_DBG, "Clocks already disabled\n"); return; Loading Loading @@ -999,6 +1205,7 @@ static inline void venus_hfi_clk_disable(struct venus_hfi_device *device) } static DECLARE_COMPLETION(pc_prep_done); static DECLARE_COMPLETION(release_resources_done); static int venus_hfi_halt_axi(struct venus_hfi_device *device) { Loading Loading @@ -1137,9 +1344,21 @@ static inline int venus_hfi_power_on(struct venus_hfi_device *device) goto err_reset_core; } /* * write_lock is already acquired at this point, so to avoid * recursive lock in cmdq_write function, call nolock version * of alloc_ocmem */ WARN_ON(!mutex_is_locked(&device->write_lock)); rc = __alloc_ocmem(device, device->res->ocmem_size, false); if (rc) { dprintk(VIDC_ERR, "Failed to allocate OCMEM"); goto err_alloc_ocmem; } device->power_enabled = 1; dprintk(VIDC_INFO, "resuming from power collapse\n"); return rc; err_alloc_ocmem: err_reset_core: venus_hfi_tzbsp_set_video_state(TZBSP_VIDEO_STATE_SUSPEND); err_set_video_state: Loading Loading @@ -1237,18 +1456,19 @@ static int venus_hfi_scale_clocks(void *dev, int load) return rc; } static int venus_hfi_iface_cmdq_write(struct venus_hfi_device *device, static int venus_hfi_iface_cmdq_write_nolock(struct venus_hfi_device *device, void *pkt) { u32 rx_req_is_set = 0; struct vidc_iface_q_info *q_info; int result = -EPERM; if (!device || !pkt) { dprintk(VIDC_ERR, "Invalid Params\n"); return -EINVAL; } mutex_lock(&device->write_lock); WARN(!mutex_is_locked(&device->write_lock), "Cmd queue write lock must be acquired"); q_info = &device->iface_queues[VIDC_IFACEQ_CMDQ_IDX]; if (!q_info) { dprintk(VIDC_ERR, "cannot write to shared Q's\n"); Loading @@ -1256,18 +1476,17 @@ static int venus_hfi_iface_cmdq_write(struct venus_hfi_device *device, } venus_hfi_sim_modify_cmd_packet((u8 *)pkt, device); if (!venus_hfi_write_queue(q_info, (u8 *)pkt, &rx_req_is_set)) { mutex_lock(&device->clk_pwr_lock); WARN(!mutex_is_locked(&device->clk_pwr_lock), "Clock/power lock must be acquired"); result = venus_hfi_clk_gating_off(device); if (result) { dprintk(VIDC_ERR, "%s : Clock enable failed\n", __func__); mutex_unlock(&device->clk_pwr_lock); goto err_q_write; } result = venus_hfi_scale_clocks(device, device->clk_load); if (result) { dprintk(VIDC_ERR, "Clock scaling failed\n"); mutex_unlock(&device->clk_pwr_lock); goto err_q_write; } if (rx_req_is_set) Loading @@ -1276,13 +1495,11 @@ static int venus_hfi_iface_cmdq_write(struct venus_hfi_device *device, VIDC_CPU_IC_SOFTINT, 1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT, 0); result = 0; mutex_unlock(&device->clk_pwr_lock); } else { dprintk(VIDC_ERR, "venus_hfi_iface_cmdq_write:queue_full\n"); } err_q_write: err_q_null: mutex_unlock(&device->write_lock); return result; } Loading Loading @@ -1970,63 +2187,6 @@ err_clk_gating_off: mutex_unlock(&device->write_lock); } static int venus_hfi_core_set_resource(void *device, struct vidc_resource_hdr *resource_hdr, void *resource_value) { struct hfi_cmd_sys_set_resource_packet *pkt; u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE]; int rc = 0; struct venus_hfi_device *dev; if (!device || !resource_hdr || !resource_value) { dprintk(VIDC_ERR, "set_res: Invalid Params\n"); return -EINVAL; } else { dev = device; } pkt = (struct hfi_cmd_sys_set_resource_packet *) packet; rc = create_pkt_set_cmd_sys_resource(pkt, resource_hdr, resource_value); if (rc) { dprintk(VIDC_ERR, "set_res: failed to create packet\n"); goto err_create_pkt; } if (venus_hfi_iface_cmdq_write(dev, pkt)) rc = -ENOTEMPTY; err_create_pkt: return rc; } static int venus_hfi_core_release_resource(void *device, struct vidc_resource_hdr *resource_hdr) { struct hfi_cmd_sys_release_resource_packet pkt; int rc = 0; struct venus_hfi_device *dev; if (!device || !resource_hdr) { dprintk(VIDC_ERR, "Inv-Params in rel_res\n"); return -EINVAL; } else { dev = device; } rc = create_pkt_cmd_sys_release_resource(&pkt, resource_hdr); if (rc) { dprintk(VIDC_ERR, "release_res: failed to create packet\n"); goto err_create_pkt; } if (venus_hfi_iface_cmdq_write(dev, &pkt)) rc = -ENOTEMPTY; err_create_pkt: return rc; } static int venus_hfi_core_ping(void *device) { struct hfi_cmd_sys_ping_packet pkt; Loading Loading @@ -2631,6 +2791,67 @@ err_create_pkt: return rc; } static int venus_hfi_unset_free_ocmem(struct venus_hfi_device *device) { int rc = 0; if (!device) { dprintk(VIDC_ERR, "Invalid param: %p\n", device); return -EINVAL; } init_completion(&release_resources_done); rc = venus_hfi_unset_ocmem(device); if (rc) { dprintk(VIDC_ERR, "Failed to unset OCMEM during PC %d\n", rc); goto ocmem_unset_failed; } rc = wait_for_completion_timeout(&release_resources_done, msecs_to_jiffies(msm_vidc_hw_rsp_timeout)); if (!rc) { dprintk(VIDC_ERR, "Wait interrupted or timeout for RELEASE_RESOURCES: %d\n", rc); rc = -EIO; goto release_resources_failed; } rc = venus_hfi_free_ocmem(device); if (rc) { dprintk(VIDC_ERR, "Failed to free OCMEM during PC\n"); goto ocmem_free_failed; } return rc; ocmem_free_failed: venus_hfi_alloc_ocmem(device, device->res->ocmem_size); release_resources_failed: ocmem_unset_failed: return rc; } static int venus_hfi_prepare_pc(struct venus_hfi_device *device) { int rc = 0; init_completion(&pc_prep_done); rc = venus_hfi_core_pc_prep(device); if (rc) { dprintk(VIDC_ERR, "Failed to prepare venus for power off"); goto err_pc_prep; } rc = wait_for_completion_timeout(&pc_prep_done, msecs_to_jiffies(msm_vidc_hw_rsp_timeout)); if (!rc) { dprintk(VIDC_ERR, "Wait interrupted or timeout for PC_PREP_DONE: %d\n", rc); rc = -EIO; goto err_pc_prep; } rc = 0; err_pc_prep: return rc; } static void venus_hfi_pm_hndlr(struct work_struct *work) { Loading @@ -2645,17 +2866,19 @@ static void venus_hfi_pm_hndlr(struct work_struct *work) goto clks_enabled; } mutex_unlock(&device->clk_pwr_lock); init_completion(&pc_prep_done); rc = venus_hfi_core_pc_prep(device); rc = venus_hfi_unset_free_ocmem(device); if (rc) { dprintk(VIDC_ERR, "Failed to prepare venus for power off\n"); dprintk(VIDC_ERR, "Failed to unset and free OCMEM for PC %d\n", rc); return; } rc = wait_for_completion_timeout(&pc_prep_done, msecs_to_jiffies(msm_vidc_hw_rsp_timeout)); if (!rc) { dprintk(VIDC_ERR, "%s: Wait interrupted or timeout: %d\n", __func__, rc); rc = venus_hfi_prepare_pc(device); if (rc) { dprintk(VIDC_ERR, "Failed to prepare for PC %d\n", rc); venus_hfi_alloc_ocmem(device, device->res->ocmem_size); return; } Loading Loading @@ -2759,9 +2982,14 @@ static void venus_hfi_response_handler(struct venus_hfi_device *device) device->device_id, (struct vidc_hal_msg_pkt_hdr *) packet, &device->sess_head, &device->session_lock); if (rc == HFI_MSG_EVENT_NOTIFY) if (rc == HFI_MSG_EVENT_NOTIFY) { venus_hfi_process_msg_event_notify( device, (void *)packet); } else if (rc == HFI_MSG_SYS_RELEASE_RESOURCE) { dprintk(VIDC_DBG, "Received HFI_MSG_SYS_RELEASE_RESOURCE\n"); complete(&release_resources_done); } } while (!venus_hfi_iface_dbgq_read(device, packet)) { struct hfi_msg_sys_coverage_packet *pkt = Loading @@ -2782,10 +3010,13 @@ static void venus_hfi_response_handler(struct venus_hfi_device *device) dprintk(VIDC_FW, "%s", pkt->rg_msg_data); } } if (rc == HFI_MSG_SYS_IDLE) { dprintk(VIDC_DBG, "Received HFI_MSG_SYS_IDLE\n"); switch (rc) { case HFI_MSG_SYS_IDLE: dprintk(VIDC_DBG, "Received HFI_MSG_SYS_IDLE\n"); rc = venus_hfi_try_clk_gating(device); } else if (rc == HFI_MSG_SYS_PC_PREP_DONE) { break; case HFI_MSG_SYS_PC_PREP_DONE: dprintk(VIDC_DBG, "Received HFI_MSG_SYS_PC_PREP_DONE\n"); rc = venus_hfi_try_clk_gating(device); Loading @@ -2793,6 +3024,7 @@ static void venus_hfi_response_handler(struct venus_hfi_device *device) dprintk(VIDC_ERR, "Failed clk gating after PC_PREP_DONE\n"); complete(&pc_prep_done); break; } } else { dprintk(VIDC_ERR, "SPURIOUS_INTERRUPT\n"); Loading Loading @@ -3151,61 +3383,6 @@ err_init_bus: return rc; } static int venus_hfi_set_ocmem(void *dev, struct ocmem_buf *ocmem) { struct vidc_resource_hdr rhdr; struct venus_hfi_device *device = dev; int rc = 0; if (!device || !ocmem) { dprintk(VIDC_ERR, "Invalid params, core:%p, ocmem: %p\n", device, ocmem); return -EINVAL; } rhdr.resource_id = VIDC_RESOURCE_OCMEM; /* This handle is just used as a cookie and not(cannot be) * accessed by fw */ rhdr.resource_handle = (u32)(unsigned long)&device->resources.ocmem; rhdr.size = ocmem->len; rc = venus_hfi_core_set_resource(device, &rhdr, ocmem); if (rc) { dprintk(VIDC_ERR, "Failed to set OCMEM on driver\n"); goto ocmem_set_failed; } dprintk(VIDC_DBG, "OCMEM set, addr = %lx, size: %ld\n", ocmem->addr, ocmem->len); ocmem_set_failed: return rc; } static int venus_hfi_unset_ocmem(void *dev) { struct vidc_resource_hdr rhdr; struct venus_hfi_device *device = dev; int rc = 0; if (!device) { dprintk(VIDC_ERR, "%s Invalid params, device:%p\n", __func__, device); rc = -EINVAL; goto ocmem_unset_failed; } if (!device->resources.ocmem.buf) { dprintk(VIDC_INFO, "%s Trying to free OCMEM which is not set\n", __func__); rc = -EINVAL; goto ocmem_unset_failed; } rhdr.resource_id = VIDC_RESOURCE_OCMEM; /* This handle is just used as a cookie and not(cannot be) * accessed by fw */ rhdr.resource_handle = (u32)(unsigned long)&device->resources.ocmem; rc = venus_hfi_core_release_resource(device, &rhdr); if (rc) dprintk(VIDC_ERR, "Failed to unset OCMEM on driver\n"); ocmem_unset_failed: return rc; } static int venus_hfi_ocmem_notify_handler(struct notifier_block *this, unsigned long event, void *data) { Loading @@ -3225,7 +3402,7 @@ static int venus_hfi_ocmem_notify_handler(struct notifier_block *this, struct venus_resources, ocmem); device = container_of(resources, struct venus_hfi_device, resources); if (venus_hfi_set_ocmem(device, buff)) { if (venus_hfi_set_ocmem(device, buff, true)) { dprintk(VIDC_ERR, "Failed to set ocmem: %d\n", rc); goto err_ocmem_notify; } Loading @@ -3251,62 +3428,6 @@ static void venus_hfi_ocmem_init(struct venus_hfi_device *device) } } static int venus_hfi_alloc_ocmem(void *dev, unsigned long size) { int rc = 0; struct ocmem_buf *ocmem_buffer; struct venus_hfi_device *device = dev; if (!device || !size) { dprintk(VIDC_ERR, "%s Invalid param, core: %p, size: %lu\n", __func__, device, size); return -EINVAL; } ocmem_buffer = device->resources.ocmem.buf; if (!ocmem_buffer || ocmem_buffer->len < size) { ocmem_buffer = ocmem_allocate(OCMEM_VIDEO, size); if (IS_ERR_OR_NULL(ocmem_buffer)) { dprintk(VIDC_ERR, "ocmem_allocate_nb failed: %lu\n", (unsigned long) ocmem_buffer); rc = -ENOMEM; goto ocmem_set_failed; } device->resources.ocmem.buf = ocmem_buffer; rc = venus_hfi_set_ocmem(device, ocmem_buffer); if (rc) { dprintk(VIDC_ERR, "Failed to set ocmem: %d\n", rc); goto ocmem_set_failed; } } else dprintk(VIDC_DBG, "OCMEM is enough. reqd: %lu, available: %lu\n", size, ocmem_buffer->len); ocmem_set_failed: return rc; } static int venus_hfi_free_ocmem(void *dev) { struct venus_hfi_device *device = dev; int rc = 0; if (!device) { dprintk(VIDC_ERR, "%s invalid device handle %p\n", __func__, device); return -EINVAL; } if (device->resources.ocmem.buf) { rc = ocmem_free(OCMEM_VIDEO, device->resources.ocmem.buf); if (rc) dprintk(VIDC_ERR, "Failed to free ocmem\n"); device->resources.ocmem.buf = NULL; } return rc; } static void venus_hfi_deinit_ocmem(struct venus_hfi_device *device) { if (device->resources.ocmem.handle) Loading Loading
drivers/media/platform/msm/vidc/venus_hfi.c +312 −191 Original line number Diff line number Diff line Loading @@ -849,6 +849,210 @@ static int venus_hfi_unvote_buses(void *dev) return rc; } static int venus_hfi_iface_cmdq_write_nolock(struct venus_hfi_device *device, void *pkt); static int venus_hfi_iface_cmdq_write(struct venus_hfi_device *device, void *pkt) { int result = -EPERM; if (!device || !pkt) { dprintk(VIDC_ERR, "Invalid Params"); return -EINVAL; } mutex_lock(&device->write_lock); mutex_lock(&device->clk_pwr_lock); result = venus_hfi_iface_cmdq_write_nolock(device, pkt); mutex_unlock(&device->clk_pwr_lock); mutex_unlock(&device->write_lock); return result; } static int venus_hfi_core_set_resource(void *device, struct vidc_resource_hdr *resource_hdr, void *resource_value, bool locked) { struct hfi_cmd_sys_set_resource_packet *pkt; u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE]; int rc = 0; struct venus_hfi_device *dev; if (!device || !resource_hdr || !resource_value) { dprintk(VIDC_ERR, "set_res: Invalid Params\n"); return -EINVAL; } else { dev = device; } pkt = (struct hfi_cmd_sys_set_resource_packet *) packet; rc = create_pkt_set_cmd_sys_resource(pkt, resource_hdr, resource_value); if (rc) { dprintk(VIDC_ERR, "set_res: failed to create packet\n"); goto err_create_pkt; } rc = locked ? venus_hfi_iface_cmdq_write(dev, pkt) : venus_hfi_iface_cmdq_write_nolock(dev, pkt); if (rc) rc = -ENOTEMPTY; err_create_pkt: return rc; } static int venus_hfi_core_release_resource(void *device, struct vidc_resource_hdr *resource_hdr) { struct hfi_cmd_sys_release_resource_packet pkt; int rc = 0; struct venus_hfi_device *dev; if (!device || !resource_hdr) { dprintk(VIDC_ERR, "Inv-Params in rel_res\n"); return -EINVAL; } else { dev = device; } rc = create_pkt_cmd_sys_release_resource(&pkt, resource_hdr); if (rc) { dprintk(VIDC_ERR, "release_res: failed to create packet\n"); goto err_create_pkt; } if (venus_hfi_iface_cmdq_write(dev, &pkt)) rc = -ENOTEMPTY; err_create_pkt: return rc; } static int venus_hfi_set_ocmem(void *dev, struct ocmem_buf *ocmem, bool locked) { struct vidc_resource_hdr rhdr; struct venus_hfi_device *device = dev; int rc = 0; if (!device || !ocmem) { dprintk(VIDC_ERR, "Invalid params, core:%p, ocmem: %p\n", device, ocmem); return -EINVAL; } rhdr.resource_id = VIDC_RESOURCE_OCMEM; /* * This handle is just used as a cookie and not(cannot be) * accessed by fw */ rhdr.resource_handle = (u32)(unsigned long)&device->resources.ocmem; rhdr.size = ocmem->len; rc = venus_hfi_core_set_resource(device, &rhdr, ocmem, locked); if (rc) { dprintk(VIDC_ERR, "Failed to set OCMEM on driver\n"); goto ocmem_set_failed; } dprintk(VIDC_DBG, "OCMEM set, addr = %lx, size: %ld\n", ocmem->addr, ocmem->len); ocmem_set_failed: return rc; } static int venus_hfi_unset_ocmem(void *dev) { struct vidc_resource_hdr rhdr; struct venus_hfi_device *device = dev; int rc = 0; if (!device) { dprintk(VIDC_ERR, "%s Invalid params, device:%p\n", __func__, device); rc = -EINVAL; goto ocmem_unset_failed; } if (!device->resources.ocmem.buf) { dprintk(VIDC_INFO, "%s Trying to free OCMEM which is not set\n", __func__); rc = -EINVAL; goto ocmem_unset_failed; } rhdr.resource_id = VIDC_RESOURCE_OCMEM; /* * This handle is just used as a cookie and not(cannot be) * accessed by fw */ rhdr.resource_handle = (u32)(unsigned long)&device->resources.ocmem; rc = venus_hfi_core_release_resource(device, &rhdr); if (rc) dprintk(VIDC_ERR, "Failed to unset OCMEM on driver\n"); ocmem_unset_failed: return rc; } static int __alloc_ocmem(void *dev, unsigned long size, bool locked) { int rc = 0; struct ocmem_buf *ocmem_buffer; struct venus_hfi_device *device = dev; if (!device || !size) { dprintk(VIDC_ERR, "%s Invalid param, core: %p, size: %lu\n", __func__, device, size); return -EINVAL; } ocmem_buffer = device->resources.ocmem.buf; if (!ocmem_buffer || ocmem_buffer->len < size) { ocmem_buffer = ocmem_allocate(OCMEM_VIDEO, size); if (IS_ERR_OR_NULL(ocmem_buffer)) { dprintk(VIDC_ERR, "ocmem_allocate_nb failed: %lu\n", (unsigned long) ocmem_buffer); rc = -ENOMEM; goto ocmem_alloc_failed; } device->resources.ocmem.buf = ocmem_buffer; rc = venus_hfi_set_ocmem(device, ocmem_buffer, locked); if (rc) { dprintk(VIDC_ERR, "Failed to set ocmem: %d\n", rc); goto ocmem_set_failed; } } else dprintk(VIDC_DBG, "OCMEM is enough. reqd: %lu, available: %lu\n", size, ocmem_buffer->len); return rc; ocmem_set_failed: ocmem_free(OCMEM_VIDEO, device->resources.ocmem.buf); device->resources.ocmem.buf = NULL; ocmem_alloc_failed: return rc; } static int venus_hfi_alloc_ocmem(void *dev, unsigned long size) { return __alloc_ocmem(dev, size, true); } static int venus_hfi_free_ocmem(void *dev) { struct venus_hfi_device *device = dev; int rc = 0; if (!device) { dprintk(VIDC_ERR, "%s invalid device handle %p\n", __func__, device); return -EINVAL; } if (device->resources.ocmem.buf) { rc = ocmem_free(OCMEM_VIDEO, device->resources.ocmem.buf); if (rc) dprintk(VIDC_ERR, "Failed to free ocmem\n"); device->resources.ocmem.buf = NULL; } return rc; } static inline int venus_hfi_tzbsp_set_video_state(enum tzbsp_video_state state) { struct tzbsp_video_set_state_req cmd = {0}; Loading Loading @@ -912,7 +1116,6 @@ static unsigned long venus_hfi_get_clock_rate(struct clock_info *clock, return ret; } /*Calling function is responsible to acquire device->clk_pwr_lock*/ static inline int venus_hfi_clk_enable(struct venus_hfi_device *device) { int rc = 0; Loading @@ -923,6 +1126,8 @@ static inline int venus_hfi_clk_enable(struct venus_hfi_device *device) dprintk(VIDC_ERR, "Invalid params: %p\n", device); return -EINVAL; } WARN(!mutex_is_locked(&device->clk_pwr_lock), "Clock/power lock must be acquired"); if (device->clocks_enabled) { dprintk(VIDC_DBG, "Clocks already enabled\n"); return 0; Loading Loading @@ -960,7 +1165,6 @@ fail_clk_enable: return rc; } /*Calling function is responsible to acquire device->clk_pwr_lock*/ static inline void venus_hfi_clk_disable(struct venus_hfi_device *device) { struct clock_info *cl; Loading @@ -969,6 +1173,8 @@ static inline void venus_hfi_clk_disable(struct venus_hfi_device *device) dprintk(VIDC_ERR, "Invalid params: %p\n", device); return; } WARN(!mutex_is_locked(&device->clk_pwr_lock), "Clock/power lock must be acquired"); if (!device->clocks_enabled) { dprintk(VIDC_DBG, "Clocks already disabled\n"); return; Loading Loading @@ -999,6 +1205,7 @@ static inline void venus_hfi_clk_disable(struct venus_hfi_device *device) } static DECLARE_COMPLETION(pc_prep_done); static DECLARE_COMPLETION(release_resources_done); static int venus_hfi_halt_axi(struct venus_hfi_device *device) { Loading Loading @@ -1137,9 +1344,21 @@ static inline int venus_hfi_power_on(struct venus_hfi_device *device) goto err_reset_core; } /* * write_lock is already acquired at this point, so to avoid * recursive lock in cmdq_write function, call nolock version * of alloc_ocmem */ WARN_ON(!mutex_is_locked(&device->write_lock)); rc = __alloc_ocmem(device, device->res->ocmem_size, false); if (rc) { dprintk(VIDC_ERR, "Failed to allocate OCMEM"); goto err_alloc_ocmem; } device->power_enabled = 1; dprintk(VIDC_INFO, "resuming from power collapse\n"); return rc; err_alloc_ocmem: err_reset_core: venus_hfi_tzbsp_set_video_state(TZBSP_VIDEO_STATE_SUSPEND); err_set_video_state: Loading Loading @@ -1237,18 +1456,19 @@ static int venus_hfi_scale_clocks(void *dev, int load) return rc; } static int venus_hfi_iface_cmdq_write(struct venus_hfi_device *device, static int venus_hfi_iface_cmdq_write_nolock(struct venus_hfi_device *device, void *pkt) { u32 rx_req_is_set = 0; struct vidc_iface_q_info *q_info; int result = -EPERM; if (!device || !pkt) { dprintk(VIDC_ERR, "Invalid Params\n"); return -EINVAL; } mutex_lock(&device->write_lock); WARN(!mutex_is_locked(&device->write_lock), "Cmd queue write lock must be acquired"); q_info = &device->iface_queues[VIDC_IFACEQ_CMDQ_IDX]; if (!q_info) { dprintk(VIDC_ERR, "cannot write to shared Q's\n"); Loading @@ -1256,18 +1476,17 @@ static int venus_hfi_iface_cmdq_write(struct venus_hfi_device *device, } venus_hfi_sim_modify_cmd_packet((u8 *)pkt, device); if (!venus_hfi_write_queue(q_info, (u8 *)pkt, &rx_req_is_set)) { mutex_lock(&device->clk_pwr_lock); WARN(!mutex_is_locked(&device->clk_pwr_lock), "Clock/power lock must be acquired"); result = venus_hfi_clk_gating_off(device); if (result) { dprintk(VIDC_ERR, "%s : Clock enable failed\n", __func__); mutex_unlock(&device->clk_pwr_lock); goto err_q_write; } result = venus_hfi_scale_clocks(device, device->clk_load); if (result) { dprintk(VIDC_ERR, "Clock scaling failed\n"); mutex_unlock(&device->clk_pwr_lock); goto err_q_write; } if (rx_req_is_set) Loading @@ -1276,13 +1495,11 @@ static int venus_hfi_iface_cmdq_write(struct venus_hfi_device *device, VIDC_CPU_IC_SOFTINT, 1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT, 0); result = 0; mutex_unlock(&device->clk_pwr_lock); } else { dprintk(VIDC_ERR, "venus_hfi_iface_cmdq_write:queue_full\n"); } err_q_write: err_q_null: mutex_unlock(&device->write_lock); return result; } Loading Loading @@ -1970,63 +2187,6 @@ err_clk_gating_off: mutex_unlock(&device->write_lock); } static int venus_hfi_core_set_resource(void *device, struct vidc_resource_hdr *resource_hdr, void *resource_value) { struct hfi_cmd_sys_set_resource_packet *pkt; u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE]; int rc = 0; struct venus_hfi_device *dev; if (!device || !resource_hdr || !resource_value) { dprintk(VIDC_ERR, "set_res: Invalid Params\n"); return -EINVAL; } else { dev = device; } pkt = (struct hfi_cmd_sys_set_resource_packet *) packet; rc = create_pkt_set_cmd_sys_resource(pkt, resource_hdr, resource_value); if (rc) { dprintk(VIDC_ERR, "set_res: failed to create packet\n"); goto err_create_pkt; } if (venus_hfi_iface_cmdq_write(dev, pkt)) rc = -ENOTEMPTY; err_create_pkt: return rc; } static int venus_hfi_core_release_resource(void *device, struct vidc_resource_hdr *resource_hdr) { struct hfi_cmd_sys_release_resource_packet pkt; int rc = 0; struct venus_hfi_device *dev; if (!device || !resource_hdr) { dprintk(VIDC_ERR, "Inv-Params in rel_res\n"); return -EINVAL; } else { dev = device; } rc = create_pkt_cmd_sys_release_resource(&pkt, resource_hdr); if (rc) { dprintk(VIDC_ERR, "release_res: failed to create packet\n"); goto err_create_pkt; } if (venus_hfi_iface_cmdq_write(dev, &pkt)) rc = -ENOTEMPTY; err_create_pkt: return rc; } static int venus_hfi_core_ping(void *device) { struct hfi_cmd_sys_ping_packet pkt; Loading Loading @@ -2631,6 +2791,67 @@ err_create_pkt: return rc; } static int venus_hfi_unset_free_ocmem(struct venus_hfi_device *device) { int rc = 0; if (!device) { dprintk(VIDC_ERR, "Invalid param: %p\n", device); return -EINVAL; } init_completion(&release_resources_done); rc = venus_hfi_unset_ocmem(device); if (rc) { dprintk(VIDC_ERR, "Failed to unset OCMEM during PC %d\n", rc); goto ocmem_unset_failed; } rc = wait_for_completion_timeout(&release_resources_done, msecs_to_jiffies(msm_vidc_hw_rsp_timeout)); if (!rc) { dprintk(VIDC_ERR, "Wait interrupted or timeout for RELEASE_RESOURCES: %d\n", rc); rc = -EIO; goto release_resources_failed; } rc = venus_hfi_free_ocmem(device); if (rc) { dprintk(VIDC_ERR, "Failed to free OCMEM during PC\n"); goto ocmem_free_failed; } return rc; ocmem_free_failed: venus_hfi_alloc_ocmem(device, device->res->ocmem_size); release_resources_failed: ocmem_unset_failed: return rc; } static int venus_hfi_prepare_pc(struct venus_hfi_device *device) { int rc = 0; init_completion(&pc_prep_done); rc = venus_hfi_core_pc_prep(device); if (rc) { dprintk(VIDC_ERR, "Failed to prepare venus for power off"); goto err_pc_prep; } rc = wait_for_completion_timeout(&pc_prep_done, msecs_to_jiffies(msm_vidc_hw_rsp_timeout)); if (!rc) { dprintk(VIDC_ERR, "Wait interrupted or timeout for PC_PREP_DONE: %d\n", rc); rc = -EIO; goto err_pc_prep; } rc = 0; err_pc_prep: return rc; } static void venus_hfi_pm_hndlr(struct work_struct *work) { Loading @@ -2645,17 +2866,19 @@ static void venus_hfi_pm_hndlr(struct work_struct *work) goto clks_enabled; } mutex_unlock(&device->clk_pwr_lock); init_completion(&pc_prep_done); rc = venus_hfi_core_pc_prep(device); rc = venus_hfi_unset_free_ocmem(device); if (rc) { dprintk(VIDC_ERR, "Failed to prepare venus for power off\n"); dprintk(VIDC_ERR, "Failed to unset and free OCMEM for PC %d\n", rc); return; } rc = wait_for_completion_timeout(&pc_prep_done, msecs_to_jiffies(msm_vidc_hw_rsp_timeout)); if (!rc) { dprintk(VIDC_ERR, "%s: Wait interrupted or timeout: %d\n", __func__, rc); rc = venus_hfi_prepare_pc(device); if (rc) { dprintk(VIDC_ERR, "Failed to prepare for PC %d\n", rc); venus_hfi_alloc_ocmem(device, device->res->ocmem_size); return; } Loading Loading @@ -2759,9 +2982,14 @@ static void venus_hfi_response_handler(struct venus_hfi_device *device) device->device_id, (struct vidc_hal_msg_pkt_hdr *) packet, &device->sess_head, &device->session_lock); if (rc == HFI_MSG_EVENT_NOTIFY) if (rc == HFI_MSG_EVENT_NOTIFY) { venus_hfi_process_msg_event_notify( device, (void *)packet); } else if (rc == HFI_MSG_SYS_RELEASE_RESOURCE) { dprintk(VIDC_DBG, "Received HFI_MSG_SYS_RELEASE_RESOURCE\n"); complete(&release_resources_done); } } while (!venus_hfi_iface_dbgq_read(device, packet)) { struct hfi_msg_sys_coverage_packet *pkt = Loading @@ -2782,10 +3010,13 @@ static void venus_hfi_response_handler(struct venus_hfi_device *device) dprintk(VIDC_FW, "%s", pkt->rg_msg_data); } } if (rc == HFI_MSG_SYS_IDLE) { dprintk(VIDC_DBG, "Received HFI_MSG_SYS_IDLE\n"); switch (rc) { case HFI_MSG_SYS_IDLE: dprintk(VIDC_DBG, "Received HFI_MSG_SYS_IDLE\n"); rc = venus_hfi_try_clk_gating(device); } else if (rc == HFI_MSG_SYS_PC_PREP_DONE) { break; case HFI_MSG_SYS_PC_PREP_DONE: dprintk(VIDC_DBG, "Received HFI_MSG_SYS_PC_PREP_DONE\n"); rc = venus_hfi_try_clk_gating(device); Loading @@ -2793,6 +3024,7 @@ static void venus_hfi_response_handler(struct venus_hfi_device *device) dprintk(VIDC_ERR, "Failed clk gating after PC_PREP_DONE\n"); complete(&pc_prep_done); break; } } else { dprintk(VIDC_ERR, "SPURIOUS_INTERRUPT\n"); Loading Loading @@ -3151,61 +3383,6 @@ err_init_bus: return rc; } static int venus_hfi_set_ocmem(void *dev, struct ocmem_buf *ocmem) { struct vidc_resource_hdr rhdr; struct venus_hfi_device *device = dev; int rc = 0; if (!device || !ocmem) { dprintk(VIDC_ERR, "Invalid params, core:%p, ocmem: %p\n", device, ocmem); return -EINVAL; } rhdr.resource_id = VIDC_RESOURCE_OCMEM; /* This handle is just used as a cookie and not(cannot be) * accessed by fw */ rhdr.resource_handle = (u32)(unsigned long)&device->resources.ocmem; rhdr.size = ocmem->len; rc = venus_hfi_core_set_resource(device, &rhdr, ocmem); if (rc) { dprintk(VIDC_ERR, "Failed to set OCMEM on driver\n"); goto ocmem_set_failed; } dprintk(VIDC_DBG, "OCMEM set, addr = %lx, size: %ld\n", ocmem->addr, ocmem->len); ocmem_set_failed: return rc; } static int venus_hfi_unset_ocmem(void *dev) { struct vidc_resource_hdr rhdr; struct venus_hfi_device *device = dev; int rc = 0; if (!device) { dprintk(VIDC_ERR, "%s Invalid params, device:%p\n", __func__, device); rc = -EINVAL; goto ocmem_unset_failed; } if (!device->resources.ocmem.buf) { dprintk(VIDC_INFO, "%s Trying to free OCMEM which is not set\n", __func__); rc = -EINVAL; goto ocmem_unset_failed; } rhdr.resource_id = VIDC_RESOURCE_OCMEM; /* This handle is just used as a cookie and not(cannot be) * accessed by fw */ rhdr.resource_handle = (u32)(unsigned long)&device->resources.ocmem; rc = venus_hfi_core_release_resource(device, &rhdr); if (rc) dprintk(VIDC_ERR, "Failed to unset OCMEM on driver\n"); ocmem_unset_failed: return rc; } static int venus_hfi_ocmem_notify_handler(struct notifier_block *this, unsigned long event, void *data) { Loading @@ -3225,7 +3402,7 @@ static int venus_hfi_ocmem_notify_handler(struct notifier_block *this, struct venus_resources, ocmem); device = container_of(resources, struct venus_hfi_device, resources); if (venus_hfi_set_ocmem(device, buff)) { if (venus_hfi_set_ocmem(device, buff, true)) { dprintk(VIDC_ERR, "Failed to set ocmem: %d\n", rc); goto err_ocmem_notify; } Loading @@ -3251,62 +3428,6 @@ static void venus_hfi_ocmem_init(struct venus_hfi_device *device) } } static int venus_hfi_alloc_ocmem(void *dev, unsigned long size) { int rc = 0; struct ocmem_buf *ocmem_buffer; struct venus_hfi_device *device = dev; if (!device || !size) { dprintk(VIDC_ERR, "%s Invalid param, core: %p, size: %lu\n", __func__, device, size); return -EINVAL; } ocmem_buffer = device->resources.ocmem.buf; if (!ocmem_buffer || ocmem_buffer->len < size) { ocmem_buffer = ocmem_allocate(OCMEM_VIDEO, size); if (IS_ERR_OR_NULL(ocmem_buffer)) { dprintk(VIDC_ERR, "ocmem_allocate_nb failed: %lu\n", (unsigned long) ocmem_buffer); rc = -ENOMEM; goto ocmem_set_failed; } device->resources.ocmem.buf = ocmem_buffer; rc = venus_hfi_set_ocmem(device, ocmem_buffer); if (rc) { dprintk(VIDC_ERR, "Failed to set ocmem: %d\n", rc); goto ocmem_set_failed; } } else dprintk(VIDC_DBG, "OCMEM is enough. reqd: %lu, available: %lu\n", size, ocmem_buffer->len); ocmem_set_failed: return rc; } static int venus_hfi_free_ocmem(void *dev) { struct venus_hfi_device *device = dev; int rc = 0; if (!device) { dprintk(VIDC_ERR, "%s invalid device handle %p\n", __func__, device); return -EINVAL; } if (device->resources.ocmem.buf) { rc = ocmem_free(OCMEM_VIDEO, device->resources.ocmem.buf); if (rc) dprintk(VIDC_ERR, "Failed to free ocmem\n"); device->resources.ocmem.buf = NULL; } return rc; } static void venus_hfi_deinit_ocmem(struct venus_hfi_device *device) { if (device->resources.ocmem.handle) Loading