MMC子系统调用过程浅析(Core层)

来源:互联网 发布:网络在线测速度 编辑:程序博客网 时间:2024/06/07 23:45

Core层关系图:
Core层关系图


在Card层中,分析到调用mmc_start_req(card->host, areq, (int *) &status)来处理块设备数据请求。在Caed层实际上完成了一个复杂的封装过程,会把request_queue->reqeust上的信息转到areq(mmc_async_req)->mmc_request上。


下面继续对mmc_start_req分析:

/** *  mmc_start_req - start a non-blocking request *  @host: MMC host to start command *  @areq: async request to start *  @error: out parameter returns 0 for success, otherwise non zero * *  Start a new MMC custom command request for a host. *  If there is on ongoing async request wait for completion *  of that request and start the new one and return. *  Does not wait for the new request to complete. * *      Returns the completed request, NULL in case of none completed. *  Wait for the an ongoing request (previoulsy started) to complete and *  return the completed request. If there is no ongoing request, NULL *  is returned without waiting. NULL is not an error condition. */struct mmc_async_req *mmc_start_req(struct mmc_host *host,                    struct mmc_async_req *areq, int *error){    int err = 0;    int start_err = 0;    struct mmc_async_req *data = host->areq;    /* Prepare a new request */    if (areq)        mmc_pre_req(host, areq->mrq, !host->areq);    if (host->areq) {        err = mmc_wait_for_data_req_done(host, host->areq->mrq, areq);        if (err == MMC_BLK_NEW_REQUEST) {            if (error)                *error = err;            /*             * The previous request was not completed,             * nothing to return             */            return NULL;        }        /*         * Check BKOPS urgency for each R1 response         */        if (host->card && mmc_card_mmc(host->card) &&            ((mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1) ||             (mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1B)) &&            (host->areq->mrq->cmd->resp[0] & R1_EXCEPTION_EVENT)) {            /* Cancel the prepared request */            if (areq)                mmc_post_req(host, areq->mrq, -EINVAL);            mmc_start_bkops(host->card, true);            /* prepare the request again */            if (areq)                mmc_pre_req(host, areq->mrq, !host->areq);        }    }    if (!err && areq)        start_err = __mmc_start_data_req(host, areq->mrq);    if (host->areq)        mmc_post_req(host, host->areq->mrq, 0);     /* Cancel a prepared request if it was not started. */    if ((err || start_err) && areq)        mmc_post_req(host, areq->mrq, -EINVAL);    if (err)        host->areq = NULL;    else        host->areq = areq;    if (error)        *error = err;    return data;}

mmc_wait_for_data_req_done对数据进行处理:

/* * mmc_wait_for_data_req_done() - wait for request completed * @host: MMC host to prepare the command. * @mrq: MMC request to wait for * * Blocks MMC context till host controller will ack end of data request * execution or new request notification arrives from the block layer. * Handles command retries. * * Returns enum mmc_blk_status after checking errors. */static int mmc_wait_for_data_req_done(struct mmc_host *host,                      struct mmc_request *mrq,                      struct mmc_async_req *next_req){    struct mmc_command *cmd;    struct mmc_context_info *context_info = &host->context_info;    int err;    unsigned long flags;    while (1) {        wait_event_interruptible(context_info->wait,                (context_info->is_done_rcv ||                 context_info->is_new_req));        spin_lock_irqsave(&context_info->lock, flags);        context_info->is_waiting_last_req = false;        spin_unlock_irqrestore(&context_info->lock, flags);        if (context_info->is_done_rcv) {            context_info->is_done_rcv = false;            context_info->is_new_req = false;            cmd = mrq->cmd;            if (!cmd->error || !cmd->retries ||                mmc_card_removed(host->card)) {                err = host->areq->err_check(host->card,                                host->areq);                break; /* return err */            } else {                mmc_retune_recheck(host);                pr_info("%s: req failed (CMD%u): %d, retrying...\n",                    mmc_hostname(host),                    cmd->opcode, cmd->error);                cmd->retries--;                cmd->error = 0;                __mmc_start_request(host, mrq);                continue; /* wait for done/new event again */            }        } else if (context_info->is_new_req) {            context_info->is_new_req = false;            if (!next_req)                return MMC_BLK_NEW_REQUEST;        }    }    mmc_retune_release(host);    return err;}

mmc_wait_for_data_req_done中调用__mmc_start_request(host, mrq)来执行一个请求。

static void __mmc_start_request(struct mmc_host *host, struct mmc_request *mrq){    int err;    /* Assumes host controller has been runtime resumed by mmc_claim_host */    err = mmc_retune(host);    if (err) {        mrq->cmd->error = err;        mmc_request_done(host, mrq);        return;    }    /*     * For sdio rw commands we must wait for card busy otherwise some     * sdio devices won't work properly.     */    if (mmc_is_io_op(mrq->cmd->opcode) && host->ops->card_busy) {        int tries = 500; /* Wait aprox 500ms at maximum */        while (host->ops->card_busy(host) && --tries)            mmc_delay(1);        if (tries == 0) {            mrq->cmd->error = -EBUSY;            mmc_request_done(host, mrq);            return;        }    }    host->ops->request(host, mrq);}

可以看到host->ops->request(host, mrq),来完成request。core层其实最终都是调用mmc_host->mmc_host_ops。mmc_host_ops中放着与硬件相关的操作。内核中封装好了Card和Core两层,厂商只要按照自己的mmc控制器,编写Host层操作方法即可。

原创粉丝点击