1 request类型
request有两种,device request和link request。
- link request
 link req是对link进行精确控制。
 link req是对每个link的请求,比如某一帧是否需要bubble recovery、某一帧是否需要长曝光等feature。
- device request
 对一个设备进行每帧控制。设备包括:isp、flash、sensor、actuator等。
 camx node通过packet方式传递request的配置到kmd对应的驱动模块,驱动会保存好对应request配置。
 设备驱动会通知crm哪个request从umd已经加入到kmd了。(通过cam_req_mgr_cb_add_req函数通知)
link request数据原型
struct cam_req_mgr_sched_request_v2 {__s32 version;__s32 session_hdl;__s32 link_hdl;__s32 bubble_enable;__s32 sync_mode;__s32 additional_timeout;__s32 num_links;__s32 num_valid_params;__s64 req_id;__s32 link_hdls[MAX_LINKS_PER_SESSION];
};
2 link 中in_q介绍
-  什么是in_q,它的职责? 
 在link中存放的输入请求队列。
-  in_q在link中位置: 
 link持有req_data, req_data中包含了in_q和req_tbl。
  
link的结构体定义:
struct cam_req_mgr_core_link {int32_t                              link_hdl;int32_t                              num_devs;//link中有多少个deviceenum cam_pipeline_delay              max_delay;...struct cam_req_mgr_core_workq       *workq;//自定义的workqueue,处理工作队列中workint32_t                              pd_mask;struct cam_req_mgr_connected_device *l_dev;//存放link中devicestruct cam_req_mgr_req_data          req; //req_datastruct cam_req_mgr_timer            *watchdog;//看门狗,监控sof是否超时,sensor是否长时间没有出帧...
};
其中cam_req_mgr_req_data 定义中有in_q和 req_tbl。
struct cam_req_mgr_req_data {struct cam_req_mgr_req_queue *in_q; //保存Input request queuestruct cam_req_mgr_req_tbl   *l_tbl;//保存request tableint32_t                       num_tbl;//保存req table的个数struct cam_req_mgr_apply      apply_data[CAM_PIPELINE_DELAY_MAX];//保存apply data,就是req是settingstruct cam_req_mgr_apply      prev_apply_data[CAM_PIPELINE_DELAY_MAX];struct mutex                  lock;
};
- in_q定义
struct cam_req_mgr_req_queue {int32_t                     num_slots;  //当前存放slot个数struct cam_req_mgr_slot     slot[MAX_REQ_SLOTS]; //slot数组,用slot来存储每帧信息。MAX_REQ_SLOTS=48int32_t                     rd_idx;//读索引下标。每当收到SOF或EOF,要对req处理时,从rd_idx读取reqint32_t                     wr_idx;//写索引下标。每当有req从umd通过sche req下发时,就会写入到wr_idx中int32_t                     last_applied_idx;//最新位置的读索引下标
};
- in_q 图示
  
 umd中通过session的ProcessRequest,然后调用到pipeline的openrequest,进而一步步调用,最终调用sched_req的cmd命令,
 ioctl调用到kmd中,kmd的crm中响应SCHED_REQ命令,调用cam_req_mgr_schedule_request做进一步处理。
 cam_req_mgr_schedule_request()做了什么?
 1)根据umd传入数据,填充task_data。task_data中u此时存放的sched_req数据。
 2)在cam_req_mgr_process_sched_req()中,取出sched_req数据,设置给当前link的in_q中的slot数组中,对应索引是wd_idx
3 request table介绍
- 什么是req table,它的职责是?
 req tbl存在于link中,它是保存不同pipeline delay的link dev的req信息。判断当前link中pd值相同的dev的apply setting是否满足了。
request table定义
struct cam_req_mgr_req_tbl {int32_t                     id; //req tbl的id值int32_t                     pd; //当前req tbl对应哪个pipeline delayint32_t                     dev_count; //相同pd的设备有几个int32_t                     dev_mask; //int32_t                     skip_traverse;struct cam_req_mgr_req_tbl *next; //指向下一个pd的req tblint32_t                     pd_delta; //两个req tbl他们的pd差值int32_t                     num_slots; //当前req tbl有多少个slot//slot数组,存放当前req tbl中具体存放的slot。MAX_REQ_SLOTS=48struct cam_req_mgr_tbl_slot slot[MAX_REQ_SLOTS];
};
cam_req_mgr_tbl_slot 定义如下:
struct cam_req_mgr_tbl_slot {int32_t                                idx; //slot的索引uint32_t                               req_ready_map; //跟着当前pd值的req tbl中哪些设备req ready了enum crm_req_state                     state; //当前slot的状态uint32_t                               inject_delay_at_sof;uint32_t                               inject_delay_at_eof;struct  crm_tbl_slot_special_ops       ops;
};
link持有req_data, req_data中包含了in_q和req_tbl。
- 图解req tbl
 2个req tbl会共用一个idx。
  
4 in_q 和request table关系
in_q和req tbl会共享idx,通过idx建立联系。
 
5 add request
link 的device在add request后,dev会回调req通知crm。通过cam_req_mgr_cb_add_req(struct cam_req_mgr_add_request *add_req)回调的。
 以IFENode为例,调用流程
IFENode::ExecuteProcessRequest() @camxifenode.cpp->CommitAndSubmitPacket();-> GetHwContext()->Submit(GetCSLSession(), m_hDevice, m_pIQPacket)->Submit() @camxhwcontext.cpp->CSLSubmit()@camxcsl.cpp-> CSLSubmitHW() @@camxcslhw.cpp->CSLHwInternalDefaultSubmit()@camxcslhwinternal.cpp->ioctlCmd.op_code         = CAM_CONFIG_DEV;->pDevice->deviceOp.Ioctl(pDevice, VIDIOC_CAM_CONTROL, &ioctlCmd)
上面是umd调用流程,下面走到kmd的CONFIG_DEV ioctl中。
cam_node_handle_ioctl() @cam_node.c->case CAM_CONFIG_DEV:->__cam_node_handle_config_dev()->cam_context_handle_config_dev(ctx, config) @cam_context.c //ctx是cam context->ctx->state_machine[ctx->state].ioctl_ops.config_dev(ctx, cmd)-> __cam_isp_ctx_config_dev_in_top_state() @cam_isp_context.c->ctx->ctx_crm_intf->add_req(&add_req);					
因为之前crm中配置过
static struct cam_req_mgr_crm_cb cam_req_mgr_ops = {.notify_trigger = cam_req_mgr_cb_notify_trigger,.notify_err     = cam_req_mgr_cb_notify_err,.add_req        = cam_req_mgr_cb_add_req,.notify_timer   = cam_req_mgr_cb_notify_timer,.notify_stop    = cam_req_mgr_cb_notify_stop,
};
所以ctx->ctx_crm_intf->add_req()会调用到cam_req_mgr_cb_add_req(struct cam_req_mgr_add_request *add_req)。
 cam_req_mgr_cb_add_req()做了什么?
 当link device中收到的req,会通知crm ,crm中link的对应pipeline delay的req tbl中保存了到达req的信息,
 当某一帧的req tbl中slot state为ready,同时in_q中这一帧的req的slot state也为ready,表示这一帧的req已经准备好了,
 可以根据crm控制策略下发apply setting。
思考问题:
 上面的cam_req_mgr_cb_add_req()是link device调用的,对于非link device,会通知crm req到达吗?
 答案是会的,具体看下BPSNode的调用流程,最后也会走到camxhwcontext的Submit(),后面的调用流程和上面link device的相同。
 以BPSNode为例,看下调用流程:
BPSNode::ExecuteProcessRequest() @camxbpsnode.cpp->CommitAllCommandBuffers(pBPSCmdBuffer);->pIQPacket->CommitPacket();->pIQPacket->AddCmdBufferReference(pBPSCmdBuffer[BPSCmdBufferFrameProcess],...);->GetHwContext()->Submit(GetCSLSession(), m_hDevice, pIQPacket) //不同的Node,设置的packet不同,到kmd中做不同处理... //这里流程和上面一样