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中有多少个device
enum cam_pipeline_delay max_delay;
...
struct cam_req_mgr_core_workq *workq;//自定义的workqueue,处理工作队列中work
int32_t pd_mask;
struct cam_req_mgr_connected_device *l_dev;//存放link中device
struct cam_req_mgr_req_data req; //req_data
struct 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 queue
struct cam_req_mgr_req_tbl *l_tbl;//保存request table
int32_t num_tbl;//保存req table的个数
struct cam_req_mgr_apply apply_data[CAM_PIPELINE_DELAY_MAX];//保存apply data,就是req是setting
struct 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=48
int32_t rd_idx;//读索引下标。每当收到SOF或EOF,要对req处理时,从rd_idx读取req
int32_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 delay
int32_t dev_count; //相同pd的设备有几个
int32_t dev_mask; //
int32_t skip_traverse;
struct cam_req_mgr_req_tbl *next; //指向下一个pd的req tbl
int32_t pd_delta; //两个req tbl他们的pd差值
int32_t num_slots; //当前req tbl有多少个slot
//slot数组,存放当前req tbl中具体存放的slot。MAX_REQ_SLOTS=48
struct 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中做不同处理
... //这里流程和上面一样