From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752546AbeBZKgM (ORCPT ); Mon, 26 Feb 2018 05:36:12 -0500 Received: from mx07-00178001.pphosted.com ([62.209.51.94]:41247 "EHLO mx07-00178001.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752365AbeBZKgF (ORCPT ); Mon, 26 Feb 2018 05:36:05 -0500 Subject: Re: [PATCH 2/5] mmc: add stm32 sdmmc controller driver To: Shawn Lin , Ulf Hansson , Rob Herring CC: Maxime Coquelin , Alexandre Torgue , Gerald Baeza , , , , References: <1518701697-14242-1-git-send-email-ludovic.Barre@st.com> <1518701697-14242-3-git-send-email-ludovic.Barre@st.com> From: Ludovic BARRE Message-ID: <0b7a72c9-a03f-e313-b675-d4d932735ca5@st.com> Date: Mon, 26 Feb 2018 11:35:35 +0100 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.5.0 MIME-Version: 1.0 In-Reply-To: Content-Type: text/plain; charset="UTF-8"; format=flowed Content-Language: en-US Content-Transfer-Encoding: 8bit X-Originating-IP: [10.75.127.50] X-ClientProxiedBy: SFHDAG6NODE1.st.com (10.75.127.16) To SFHDAG6NODE1.st.com (10.75.127.16) X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:,, definitions=2018-02-26_03:,, signatures=0 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org hi Shawn thanks for your review On 02/22/2018 05:20 PM, Shawn Lin wrote: > On 2018/2/15 21:34, Ludovic Barre wrote: >> From: Ludovic Barre >> > > ... > >> + >> +static ssize_t stm32_sdmmc_stat_reset(struct file *filp, >> +                      const char __user *ubuf, >> +                      size_t count, loff_t *ppos) >> +{ >> +    struct seq_file *seqf = filp->private_data; >> +    struct sdmmc_host *host = seqf->private; >> + >> +    mutex_lock(&seqf->lock); >> +    memset(&host->stat, 0, sizeof(host->stat)); >> +    mutex_unlock(&seqf->lock); >> + >> +    return count; >> +} >> + >> +static int stm32_sdmmc_stat_open(struct inode *inode, struct file *file) >> +{ >> +    return single_open(file, stm32_sdmmc_stat_show, inode->i_private); >> +} >> + >> +static const struct file_operations stm32_sdmmc_stat_fops = { >> +    .owner        = THIS_MODULE, >> +    .open        = stm32_sdmmc_stat_open, >> +    .read        = seq_read, >> +    .write        = stm32_sdmmc_stat_reset, >> +    .llseek        = seq_lseek, >> +    .release    = single_release, >> +}; >> + > > Could you simply use DEFINE_SHOW_ATTRIBUTE(stm32_sdmmc_stat) instead? DEFINE_SHOW_ATTRIBUTE has no ".write" file_operations. It's very useful to reset the statistic structure. So if it's possible to keep this feature, I would prefer. > >> +static void stm32_sdmmc_stat_init(struct sdmmc_host *host) >> +{ >> +    struct mmc_host    *mmc = host->mmc; >> +    struct dentry *root; >> + >> +    root = mmc->debugfs_root; >> +    if (!root) >> +        return; >> + >> +    if (!debugfs_create_file("stat", 0600, root, host, >> +                 &stm32_sdmmc_stat_fops)) >> +        dev_err(mmc_dev(host->mmc), "failed to initialize debugfs\n"); >> +} >> + >> +#define STAT_INC(stat) ((stat)++) >> +#else >> +static void stm32_sdmmc_stat_init(struct sdmmc_host *host) >> +{ >> +} >> + >> +#define STAT_INC(stat) >> +#endif >> + >> +static inline u32 enable_imask(struct sdmmc_host *host, u32 imask) >> +{ >> +    u32 newmask; >> + >> +    newmask = readl_relaxed(host->base + SDMMC_MASKR); >> +    newmask |= imask; >> + >> +    dev_vdbg(mmc_dev(host->mmc), "mask:%#x\n", newmask); >> + >> +    writel_relaxed(newmask, host->base + SDMMC_MASKR); >> + >> +    return newmask; >> +} >> + > > I don't see you use the return value eleswhere, perhaps > remove it? yes your right, I remove the return. > >> +static inline u32 disable_imask(struct sdmmc_host *host, u32 imask) >> +{ >> +    u32 newmask; >> + >> +    newmask = readl_relaxed(host->base + SDMMC_MASKR); >> +    newmask &= ~imask; >> + >> +    dev_vdbg(mmc_dev(host->mmc), "mask:%#x\n", newmask); >> + >> +    writel_relaxed(newmask, host->base + SDMMC_MASKR); >> + >> +    return newmask; >> +} >> + > > Ditto? yes your right, I remove the return. > >> +static inline void clear_imask(struct sdmmc_host *host) >> +{ >> +    u32 mask = readl_relaxed(host->base + SDMMC_MASKR); >> + >> +    /* preserve the SDIO IRQ mask state */ >> +    mask &= MASKR_SDIOITIE; >> + >> +    dev_vdbg(mmc_dev(host->mmc), "mask:%#x\n", mask); >> + >> +    writel_relaxed(mask, host->base + SDMMC_MASKR); >> +} >> + > > Not clear to me why couldn't you use : > imask = 0xffffffff ^ MASKR_SDIOITIE; > disable_imask(imask) In fact, I wish keep SDIOITIE enabled if and only if the SDIOTIE was already enabled (so SDIOITIE mask is not always set) > >> +static int stm32_sdmmc_card_busy(struct mmc_host *mmc) >> +{ >> +    struct sdmmc_host *host = mmc_priv(mmc); >> +    unsigned long flags; >> +    u32 status; >> + >> +    spin_lock_irqsave(&host->lock, flags); >> +    status = readl_relaxed(host->base + SDMMC_STAR); >> +    spin_unlock_irqrestore(&host->lock, flags); >> + >> +    return !!(status & STAR_BUSYD0); >> +} >> + > > I don't think you need to hold the lock here. just a protection with "stm32_sdmmc_irq" which could modify status value > >> +static void stm32_sdmmc_request_end(struct sdmmc_host *host, >> +                    struct mmc_request *mrq) >> +{ >> +    writel_relaxed(0, host->base + SDMMC_CMDR); >> +    writel_relaxed(ICR_STATIC_FLAG, host->base + SDMMC_ICR); >> + >> +    host->mrq = NULL; >> +    host->cmd = NULL; >> +    host->data = NULL; >> + >> +    clear_imask(host); >> + >> +    mmc_request_done(host->mmc, mrq); >> +} >> + >> +static void stm32_sdmmc_pwroff(struct sdmmc_host *host) >> +{ >> +    /* Only a reset could disable sdmmc */ >> +    reset_control_assert(host->rst); >> +    udelay(2); >> +    reset_control_deassert(host->rst); >> + >> +    /* >> +     * Set the SDMMC in Power-cycle state. This will make that the >> +     * SDMMC_D[7:0], SDMMC_CMD and SDMMC_CK are driven low, >> +     * to prevent the Card from being powered through the signal lines. >> +     */ >> +    writel_relaxed(POWERCTRL_CYC | host->pwr_reg_add, >> +               host->base + SDMMC_POWER); >> +} >> + >> +static void stm32_sdmmc_pwron(struct sdmmc_host *host) >> +{ >> +    /* >> +     * After a power-cycle state, we must set the SDMMC in Power-off. >> +     * The SDMMC_D[7:0], SDMMC_CMD and SDMMC_CK are driven high. >> +     * Then we can set the SDMMC to Power-on state >> +     */ >> +    writel_relaxed(POWERCTRL_OFF | host->pwr_reg_add, >> +               host->base + SDMMC_POWER); >> +    mdelay(1); >> +    writel_relaxed(POWERCTRL_ON | host->pwr_reg_add, >> +               host->base + SDMMC_POWER); >> +} >> + >> +static void stm32_sdmmc_set_clkreg(struct sdmmc_host *host, struct >> mmc_ios *ios) >> +{ >> +    u32 desired = ios->clock; >> +    u32 clk = 0; >> + >> +    /* >> +     * sdmmc_ck = sdmmcclk/(2*clkdiv) >> +     * clkdiv 0 => bypass >> +     */ >> +    if (desired) { >> +        if (desired >= host->sdmmcclk) { >> +            clk = 0; >> +            host->sdmmc_ck = host->sdmmcclk; >> +        } else { >> +            clk = DIV_ROUND_UP(host->sdmmcclk, 2 * desired); >> +            if (clk > CLKCR_CLKDIV_MAX) >> +                clk = CLKCR_CLKDIV_MAX; >> + > > Don't you need to check if the desired clock rate is the > same with the current clock rate? I'd rather not. I should save the prescaler into variable and manage this. I will add a dev_warn if clk > CLKCR_CLKDIV_MAX, because if it's happen the card is over clocked. > >> +            host->sdmmc_ck = host->sdmmcclk / (2 * clk); >> +        } >> +    } >> + >> +    if (ios->bus_width == MMC_BUS_WIDTH_4) >> +        clk |= CLKCR_WIDBUS_4; >> +    if (ios->bus_width == MMC_BUS_WIDTH_8) >> +        clk |= CLKCR_WIDBUS_8; >> + > > also it looks wired to me you set bus width in a function called > stm32_sdmmc_set_clkreg which seems do the clock setting. In fact, this function regroup settings of clk register, and there are buswith, clk, hardware flow control... > >> +    clk |= CLKCR_HWFC_EN; >> + >> +    writel_relaxed(clk | host->clk_reg_add, host->base + SDMMC_CLKCR); >> +} >> + >> +static void stm32_sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios >> *ios) >> +{ >> +    struct sdmmc_host *host = mmc_priv(mmc); >> + >> +    stm32_sdmmc_set_clkreg(host, ios); >> + >> +    switch (ios->power_mode) { >> +    case MMC_POWER_OFF: >> +        if (!IS_ERR(mmc->supply.vmmc)) >> +            mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); >> + >> +        stm32_sdmmc_pwroff(host); >> +        return; >> +    case MMC_POWER_UP: >> +        if (!IS_ERR(mmc->supply.vmmc)) >> +            mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd); >> +        break; >> +    case MMC_POWER_ON: >> +        stm32_sdmmc_pwron(host); >> +        break; >> +    } >> +} >> + >> +static int stm32_sdmmc_validate_data(struct sdmmc_host *host, >> +                     struct mmc_data *data, int cookie) >> +{ >> +    int n_elem; >> + >> +    if (!data || data->host_cookie == COOKIE_PRE_MAPPED) >> +        return 0; >> + >> +    if (!is_power_of_2(data->blksz)) { >> +        dev_err(mmc_dev(host->mmc), >> +            "unsupported block size (%d bytes)\n", data->blksz); >> +        return -EINVAL; >> +    } >> + >> +    if (data->sg->offset & 3 || data->sg->length & 3) { >> +        dev_err(mmc_dev(host->mmc), >> +            "unaligned scatterlist: ofst:%x length:%d\n", >> +            data->sg->offset, data->sg->length); >> +        return -EINVAL; >> +    } >> + >> +    n_elem = dma_map_sg(mmc_dev(host->mmc), >> +                data->sg, >> +                data->sg_len, >> +                mmc_get_dma_dir(data)); >> + >> +    if (n_elem != 1) { >> +        dev_err(mmc_dev(host->mmc), "nr segment >1 not supported\n"); > > I don't get this check. Your IDMA can't do scatter lists, but > n_elem == 0 means failed to do dma_map_sg. dma_map_sg return the number of elements mapped or 0 if error. like the max_segs is set in the probe, I will remove the overprotection on number of elements. So I will replace by if (!n_elem) { dev_err(mmc_dev(host->mmc), "dma_map_sg failed\n"); return -EINVAL; } > >> +        return -EINVAL; >> +    } >> + >> +    data->host_cookie = cookie; >> + >> +    return 0; >> +} >> + >> +static void stm32_sdmmc_start_data(struct sdmmc_host *host, >> +                   struct mmc_data *data) >> +{ >> +    u32 datactrl, timeout, imask, idmactrl; >> +    unsigned long long clks; >> + >> +    dev_dbg(mmc_dev(host->mmc), "blksz %d blks %d flags %08x\n", >> +        data->blksz, data->blocks, data->flags); >> + >> +    STAT_INC(host->stat.n_datareq); >> +    host->data = data; >> +    host->size = data->blksz * data->blocks; >> +    data->bytes_xfered = 0; >> + >> +    clks = (unsigned long long)data->timeout_ns * host->sdmmc_ck; >> +    do_div(clks, NSEC_PER_SEC); >> +    timeout = data->timeout_clks + (unsigned int)clks; >> + >> +    writel_relaxed(timeout, host->base + SDMMC_DTIMER); >> +    writel_relaxed(host->size, host->base + SDMMC_DLENR); >> + >> +    datactrl = FIELD_PREP(DCTRLR_DBLOCKSIZE_MASK, ilog2(data->blksz)); >> + >> +    if (data->flags & MMC_DATA_READ) { >> +        datactrl |= DCTRLR_DTDIR; >> +        imask = MASKR_RXOVERRIE; >> +    } else { >> +        imask = MASKR_TXUNDERRIE; >> +    } >> + >> +    if (host->mmc->card && mmc_card_sdio(host->mmc->card)) >> +        datactrl |= DCTRLR_SDIOEN | DCTRLR_DTMODE_SDIO; >> + >> +    idmactrl = IDMACTRLR_IDMAEN; >> + >> +    writel_relaxed(sg_dma_address(data->sg), >> +               host->base + SDMMC_IDMABASE0R); >> +    writel_relaxed(idmactrl, host->base + SDMMC_IDMACTRLR); >> + >> +    imask |= MASKR_DATAENDIE | MASKR_DTIMEOUTIE | MASKR_DCRCFAILIE; >> +    enable_imask(host, imask); >> + >> +    writel_relaxed(datactrl, host->base + SDMMC_DCTRLR); >> +} >> + >> +static void stm32_sdmmc_start_cmd(struct sdmmc_host *host, >> +                  struct mmc_command *cmd, u32 c) >> +{ >> +    void __iomem *base = host->base; > > Not need to introduce this variable. OK > >> +    u32 imsk; >> + >> +    dev_dbg(mmc_dev(host->mmc), "op %u arg %08x flags %08x\n", >> +        cmd->opcode, cmd->arg, cmd->flags); >> + >> +    STAT_INC(host->stat.n_req); >> + >> +    if (readl_relaxed(base + SDMMC_CMDR) & CMDR_CPSMEM) >> +        writel_relaxed(0, base + SDMMC_CMDR); >> + >> +    c |= cmd->opcode | CMDR_CPSMEM; >> +    if (cmd->flags & MMC_RSP_PRESENT) { >> +        imsk = MASKR_CMDRENDIE | MASKR_CTIMEOUTIE; >> +        if (cmd->flags & MMC_RSP_CRC) >> +            imsk |= MASKR_CCRCFAILIE; >> + >> +        if (cmd->flags & MMC_RSP_136) >> +            c |= CMDR_WAITRESP_LRSP_CRC; >> +        else if (cmd->flags & MMC_RSP_CRC) >> +            c |= CMDR_WAITRESP_SRSP_CRC; >> +        else >> +            c |= CMDR_WAITRESP_SRSP; >> +    } else { >> +        c &= ~CMDR_WAITRESP_MASK; >> +        imsk = MASKR_CMDSENTIE; >> +    } >> + >> +    host->cmd = cmd; >> + >> +    enable_imask(host, imsk); >> + >> +    writel_relaxed(cmd->arg, base + SDMMC_ARGR); >> +    writel_relaxed(c, base + SDMMC_CMDR); >> +} >> + >> +static void stm32_sdmmc_cmd_irq(struct sdmmc_host *host, u32 status) >> +{ >> +    struct mmc_command *cmd = host->cmd; >> + >> +    if (!cmd) >> +        return; >> + >> +    host->cmd = NULL; >> + >> +    if (status & STAR_CTIMEOUT) { >> +        STAT_INC(host->stat.n_ctimeout); >> +        cmd->error = -ETIMEDOUT; >> +        host->dpsm_abort = true; >> +    } else if (status & STAR_CCRCFAIL && cmd->flags & MMC_RSP_CRC) { >> +        STAT_INC(host->stat.n_ccrcfail); >> +        cmd->error = -EILSEQ; >> +        host->dpsm_abort = true; >> +    } else if (status & STAR_CMDREND && cmd->flags & MMC_RSP_PRESENT) { >> +        cmd->resp[0] = readl_relaxed(host->base + SDMMC_RESP1R); >> +        cmd->resp[1] = readl_relaxed(host->base + SDMMC_RESP2R); >> +        cmd->resp[2] = readl_relaxed(host->base + SDMMC_RESP3R); >> +        cmd->resp[3] = readl_relaxed(host->base + SDMMC_RESP4R); >> +    } >> + >> +    if (!host->data) >> +        stm32_sdmmc_request_end(host, host->mrq); >> +} >> + >> +static void stm32_sdmmc_data_irq(struct sdmmc_host *host, u32 status) >> +{ >> +    struct mmc_data    *data = host->data; >> +    struct mmc_command *stop = &host->stop_abort; >> + >> +    if (!data) >> +        return; >> + >> +    if (status & STAR_DCRCFAIL) { >> +        STAT_INC(host->stat.n_dcrcfail); >> +        data->error = -EILSEQ; >> +        if (readl_relaxed(host->base + SDMMC_DCNTR)) >> +            host->dpsm_abort = true; >> +    } else if (status & STAR_DTIMEOUT) { >> +        STAT_INC(host->stat.n_dtimeout); >> +        data->error = -ETIMEDOUT; >> +        host->dpsm_abort = true; >> +    } else if (status & STAR_TXUNDERR) { >> +        STAT_INC(host->stat.n_txunderrun); >> +        data->error = -EIO; >> +        host->dpsm_abort = true; >> +    } else if (status & STAR_RXOVERR) { >> +        STAT_INC(host->stat.n_rxoverrun); >> +        data->error = -EIO; >> +        host->dpsm_abort = true; >> +    } >> + >> +    if (status & STAR_DATAEND || data->error || host->dpsm_abort) { >> +        host->data = NULL; >> + >> +        writel_relaxed(0, host->base + SDMMC_IDMACTRLR); >> + >> +        if (!data->error) >> +            data->bytes_xfered = data->blocks * data->blksz; >> + >> +        /* >> +         * To stop Data Path State Machine, a stop_transmission command >> +         * shall be send on cmd or data errors of single, multi, >> +         * pre-defined block and stream request. >> +         */ >> +        if (host->dpsm_abort && !data->stop) { >> +            memset(stop, 0, sizeof(struct mmc_command)); >> +            stop->opcode = MMC_STOP_TRANSMISSION; >> +            stop->arg = 0; >> +            stop->flags = MMC_RSP_R1B | MMC_CMD_AC; >> +            data->stop = stop; >> +        } >> + >> +        disable_imask(host, MASKR_RXOVERRIE | MASKR_TXUNDERRIE >> +                  | MASKR_DCRCFAILIE | MASKR_DATAENDIE >> +                  | MASKR_DTIMEOUTIE); >> + >> +        if (!data->stop) >> +            stm32_sdmmc_request_end(host, data->mrq); >> +        else >> +            stm32_sdmmc_start_cmd(host, data->stop, CMDR_CMDSTOP); >> +    } >> +} >> + >> +static irqreturn_t stm32_sdmmc_irq(int irq, void *dev_id) >> +{ >> +    struct sdmmc_host *host = dev_id; >> +    u32 status; >> + >> +    spin_lock(&host->lock); >> + >> +    status = readl_relaxed(host->base + SDMMC_STAR); >> +    dev_dbg(mmc_dev(host->mmc), "irq sta:%#x\n", status); >> +    writel_relaxed(status & ICR_STATIC_FLAG, host->base + SDMMC_ICR); >> + >> +    stm32_sdmmc_cmd_irq(host, status); >> +    stm32_sdmmc_data_irq(host, status); >> + >> +    spin_unlock(&host->lock); >> + >> +    return IRQ_HANDLED; >> +} >> + >> +static void stm32_sdmmc_pre_req(struct mmc_host *mmc, struct >> mmc_request *mrq) >> +{ >> +    struct sdmmc_host *host = mmc_priv(mmc); >> +    struct mmc_data *data = mrq->data; >> + >> +    if (!data) >> +        return; >> + >> +    /* This data might be unmapped at this time */ >> +    data->host_cookie = COOKIE_UNMAPPED; >> + >> +    if (!stm32_sdmmc_validate_data(host, mrq->data, COOKIE_PRE_MAPPED)) >> +        data->host_cookie = COOKIE_UNMAPPED; >> +} >> + >> +static void stm32_sdmmc_post_req(struct mmc_host *mmc, struct >> mmc_request *mrq, >> +                 int err) >> +{ >> +    struct sdmmc_host *host = mmc_priv(mmc); >> +    struct mmc_data *data = mrq->data; >> + >> +    if (!data) >> +        return; >> + >> +    if (data->host_cookie != COOKIE_UNMAPPED) >> +        dma_unmap_sg(mmc_dev(host->mmc), >> +                 data->sg, >> +                 data->sg_len, >> +                 mmc_get_dma_dir(data)); >> + >> +    data->host_cookie = COOKIE_UNMAPPED; >> +} >> + >> +static void stm32_sdmmc_request(struct mmc_host *mmc, struct >> mmc_request *mrq) >> +{ >> +    unsigned int cmdat = 0; >> +    struct sdmmc_host *host = mmc_priv(mmc); >> +    unsigned long flags; >> + >> +    mrq->cmd->error = stm32_sdmmc_validate_data(host, mrq->data, >> +                            COOKIE_MAPPED); >> +    if (mrq->cmd->error) { >> +        mmc_request_done(mmc, mrq); >> +        return; >> +    } >> + >> +    spin_lock_irqsave(&host->lock, flags); >> + >> +    host->mrq = mrq; >> + >> +    if (mrq->data) { >> +        host->dpsm_abort = false; >> +        stm32_sdmmc_start_data(host, mrq->data); >> +        cmdat |= CMDR_CMDTRANS; >> +    } >> + >> +    stm32_sdmmc_start_cmd(host, mrq->cmd, cmdat); >> + >> +    spin_unlock_irqrestore(&host->lock, flags); >> +} >> + >> +static struct mmc_host_ops stm32_sdmmc_ops = { >> +    .request    = stm32_sdmmc_request, >> +    .pre_req    = stm32_sdmmc_pre_req, >> +    .post_req    = stm32_sdmmc_post_req, >> +    .set_ios    = stm32_sdmmc_set_ios, >> +    .get_cd        = mmc_gpio_get_cd, >> +    .card_busy    = stm32_sdmmc_card_busy, >> +}; >> + >> +static const struct of_device_id stm32_sdmmc_match[] = { >> +    { .compatible = "st,stm32h7-sdmmc",}, >> +    {}, >> +}; >> +MODULE_DEVICE_TABLE(of, stm32_sdmmc_match); >> + >> +static int stm32_sdmmc_of_parse(struct device_node *np, struct >> mmc_host *mmc) >> +{ >> +    struct sdmmc_host *host = mmc_priv(mmc); >> +    int ret = mmc_of_parse(mmc); >> + >> +    if (ret) >> +        return ret; >> + >> +    if (of_get_property(np, "st,negedge", NULL)) >> +        host->clk_reg_add |= CLKCR_NEGEDGE; >> +    if (of_get_property(np, "st,dirpol", NULL)) >> +        host->pwr_reg_add |= POWER_DIRPOL; >> +    if (of_get_property(np, "st,pin-ckin", NULL)) >> +        host->clk_reg_add |= CLKCR_SELCLKRX_CKIN; >> + > > Use device_property_present? OK, thanks > >> +    return 0; >> +} >> + >> +static int stm32_sdmmc_probe(struct platform_device *pdev) >> +{ >> +    struct device_node *np = pdev->dev.of_node; >> +    struct sdmmc_host *host; >> +    struct mmc_host *mmc; >> +    struct resource *res; >> +    int irq, ret; >> + >> +    if (!np) { >> +        dev_err(&pdev->dev, "No DT found\n"); >> +        return -EINVAL; >> +    } >> + >> +    res = platform_get_resource(pdev, IORESOURCE_MEM, 0); >> +    irq = platform_get_irq(pdev, 0); >> +    if (irq < 0) >> +        return -EINVAL; >> + >> +    mmc = mmc_alloc_host(sizeof(struct sdmmc_host), &pdev->dev); >> +    if (!mmc) >> +        return -ENOMEM; >> + >> +    host = mmc_priv(mmc); >> +    host->mmc = mmc; >> +    platform_set_drvdata(pdev, mmc); >> + >> +    host->base = devm_ioremap_resource(&pdev->dev, res); >> +    if (IS_ERR(host->base)) { >> +        ret = PTR_ERR(host->base); >> +        goto host_free; >> +    } >> + >> +    writel_relaxed(0, host->base + SDMMC_MASKR); >> +    writel_relaxed(~0UL, host->base + SDMMC_ICR); >> + >> +    ret = devm_request_irq(&pdev->dev, irq, stm32_sdmmc_irq, >> IRQF_SHARED, >> +                   DRIVER_NAME " (cmd)", host); >> +    if (ret) >> +        goto host_free; >> + >> +    host->clk = devm_clk_get(&pdev->dev, NULL); >> +    if (IS_ERR(host->clk)) { >> +        ret = PTR_ERR(host->clk); >> +        goto host_free; >> +    } >> + >> +    ret = clk_prepare_enable(host->clk); >> +    if (ret) >> +        goto host_free; >> + >> +    host->sdmmcclk = clk_get_rate(host->clk); >> +    mmc->f_min = DIV_ROUND_UP(host->sdmmcclk, 2 * CLKCR_CLKDIV_MAX); >> +    mmc->f_max = host->sdmmcclk; >> + >> +    ret = stm32_sdmmc_of_parse(np, mmc); >> +    if (ret) >> +        goto clk_disable; >> + >> +    host->rst = devm_reset_control_get(&pdev->dev, NULL); >> +    if (IS_ERR(host->rst)) { >> +        ret = PTR_ERR(host->rst); >> +        goto clk_disable; >> +    } >> + >> +    stm32_sdmmc_pwroff(host); >> + >> +    /* Get regulators and the supported OCR mask */ >> +    ret = mmc_regulator_get_supply(mmc); >> +    if (ret == -EPROBE_DEFER) >> +        goto clk_disable; >> + >> +    if (!mmc->ocr_avail) >> +        mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; >> + >> +    mmc->ops = &stm32_sdmmc_ops; >> + >> +    /* IDMA cannot do scatter lists */ >> +    mmc->max_segs = 1; >> +    mmc->max_req_size = DLENR_DATALENGHT_MAX; >> +    mmc->max_seg_size = mmc->max_req_size; >> +    mmc->max_blk_size = 1 << DCTRLR_DBLOCKSIZE_MAX; >> + >> +    /* >> +     * Limit the number of blocks transferred so that we don't overflow >> +     * the maximum request size. >> +     */ >> +    mmc->max_blk_count = mmc->max_req_size >> DCTRLR_DBLOCKSIZE_MAX; >> + >> +    spin_lock_init(&host->lock); >> + >> +    ret = mmc_add_host(mmc); >> +    if (ret) >> +        goto clk_disable; >> + >> +    stm32_sdmmc_stat_init(host); >> + >> +    host->ip_ver = readl_relaxed(host->base + SDMMC_IPVR); >> +    dev_info(&pdev->dev, "%s: rev:%ld.%ld irq:%d\n", >> +         mmc_hostname(mmc), >> +         FIELD_GET(IPVR_MAJREV_MASK, host->ip_ver), >> +         FIELD_GET(IPVR_MINREV_MASK, host->ip_ver), irq); >> + >> +    return 0; >> + >> +clk_disable: >> +    clk_disable_unprepare(host->clk); >> +host_free: >> +    mmc_free_host(mmc); >> +    return ret; >> +} >> + >> +static int stm32_sdmmc_remove(struct platform_device *pdev) >> +{ >> +    struct mmc_host *mmc = platform_get_drvdata(pdev); >> +    struct sdmmc_host *host = mmc_priv(mmc); >> + >> +    /* Debugfs stuff is cleaned up by mmc core */ >> +    mmc_remove_host(mmc); >> +    clk_disable_unprepare(host->clk); >> +    mmc_free_host(mmc); >> + >> +    return 0; >> +} >> + >> +static struct platform_driver stm32_sdmmc_driver = { >> +    .probe        = stm32_sdmmc_probe, >> +    .remove        = stm32_sdmmc_remove, >> +    .driver    = { >> +        .name    = DRIVER_NAME, >> +        .of_match_table = stm32_sdmmc_match, >> +    }, >> +}; >> + >> +module_platform_driver(stm32_sdmmc_driver); >> + >> +MODULE_DESCRIPTION("STMicroelectronics STM32 MMC/SD Card Interface >> driver"); >> +MODULE_LICENSE("GPL v2"); >> +MODULE_AUTHOR("Ludovic Barre "); >> diff --git a/drivers/mmc/host/stm32-sdmmc.h >> b/drivers/mmc/host/stm32-sdmmc.h >> new file mode 100644 >> index 0000000..e39578e >> --- /dev/null >> +++ b/drivers/mmc/host/stm32-sdmmc.h >> @@ -0,0 +1,220 @@ >> +/* SPDX-License-Identifier: GPL-2.0 */ >> +/* >> + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved >> + * Author: Ludovic Barre for STMicroelectronics. >> + */ >> +#define SDMMC_POWER            0x000 >> +#define POWERCTRL_MASK            GENMASK(1, 0) >> +#define POWERCTRL_OFF            0x00 >> +#define POWERCTRL_CYC            0x02 >> +#define POWERCTRL_ON            0x03 >> +#define POWER_VSWITCH            BIT(2) >> +#define POWER_VSWITCHEN            BIT(3) >> +#define POWER_DIRPOL            BIT(4) >> + >> +#define SDMMC_CLKCR            0x004 >> +#define CLKCR_CLKDIV_MASK        GENMASK(9, 0) >> +#define CLKCR_CLKDIV_MAX        CLKCR_CLKDIV_MASK >> +#define CLKCR_PWRSAV            BIT(12) >> +#define CLKCR_WIDBUS_4            BIT(14) >> +#define CLKCR_WIDBUS_8            BIT(15) >> +#define CLKCR_NEGEDGE            BIT(16) >> +#define CLKCR_HWFC_EN            BIT(17) >> +#define CLKCR_DDR            BIT(18) >> +#define CLKCR_BUSSPEED            BIT(19) >> +#define CLKCR_SELCLKRX_MASK        GENMASK(21, 20) >> +#define CLKCR_SELCLKRX_CK        (0 << 20) >> +#define CLKCR_SELCLKRX_CKIN        (1 << 20) >> +#define CLKCR_SELCLKRX_FBCK        (2 << 20) >> + >> +#define SDMMC_ARGR            0x008 >> + >> +#define SDMMC_CMDR            0x00c >> +#define CMDR_CMDTRANS            BIT(6) >> +#define CMDR_CMDSTOP            BIT(7) >> +#define CMDR_WAITRESP_MASK        GENMASK(9, 8) >> +#define CMDR_WAITRESP_NORSP        (0 << 8) >> +#define CMDR_WAITRESP_SRSP_CRC        (1 << 8) >> +#define CMDR_WAITRESP_SRSP        (2 << 8) >> +#define CMDR_WAITRESP_LRSP_CRC        (3 << 8) >> +#define CMDR_WAITINT            BIT(10) >> +#define CMDR_WAITPEND            BIT(11) >> +#define CMDR_CPSMEM            BIT(12) >> +#define CMDR_DTHOLD            BIT(13) >> +#define CMDR_BOOTMODE            BIT(14) >> +#define CMDR_BOOTEN            BIT(15) >> +#define CMDR_CMDSUSPEND            BIT(16) >> + >> +#define SDMMC_RESPCMDR            0x010 >> +#define SDMMC_RESP1R            0x014 >> +#define SDMMC_RESP2R            0x018 >> +#define SDMMC_RESP3R            0x01c >> +#define SDMMC_RESP4R            0x020 >> + >> +#define SDMMC_DTIMER            0x024 >> + >> +#define SDMMC_DLENR            0x028 >> +#define DLENR_DATALENGHT_MASK        GENMASK(24, 0) >> +#define DLENR_DATALENGHT_MAX        DLENR_DATALENGHT_MASK >> + >> +#define SDMMC_DCTRLR            0x02c >> +#define DCTRLR_DTEN            BIT(0) >> +#define DCTRLR_DTDIR            BIT(1) >> +#define DCTRLR_DTMODE_MASK        GENMASK(3, 2) >> +#define DCTRLR_DTMODE_BLOCK        (0 << 2) >> +#define DCTRLR_DTMODE_SDIO        (1 << 2) >> +#define DCTRLR_DTMODE_MMC        (2 << 2) >> +#define DCTRLR_DBLOCKSIZE_MASK        GENMASK(7, 4) >> +#define DCTRLR_DBLOCKSIZE_MAX        14 >> +#define DCTRLR_RWSTART            BIT(8) >> +#define DCTRLR_RWSTOP            BIT(9) >> +#define DCTRLR_RWMOD            BIT(10) >> +#define DCTRLR_SDIOEN            BIT(11) >> +#define DCTRLR_BOOTACKEN        BIT(12) >> +#define DCTRLR_FIFORST            BIT(13) >> + >> +#define SDMMC_DCNTR            0x030 >> + >> +#define SDMMC_STAR            0x034 >> +#define STAR_CCRCFAIL            BIT(0) >> +#define STAR_DCRCFAIL            BIT(1) >> +#define STAR_CTIMEOUT            BIT(2) >> +#define STAR_DTIMEOUT            BIT(3) >> +#define STAR_TXUNDERR            BIT(4) >> +#define STAR_RXOVERR            BIT(5) >> +#define STAR_CMDREND            BIT(6) >> +#define STAR_CMDSENT            BIT(7) >> +#define STAR_DATAEND            BIT(8) >> +#define STAR_DHOLD            BIT(9) >> +#define STAR_DBCKEND            BIT(10) >> +#define STAR_DABORT            BIT(11) >> +#define STAR_DPSMACT            BIT(12) >> +#define STAR_CPSMACT            BIT(13) >> +#define STAR_TXFIFOHE            BIT(14) >> +#define STAR_TXFIFOHF            BIT(15) >> +#define STAR_TXFIFOF            BIT(16) >> +#define STAR_RXFIFOF            BIT(17) >> +#define STAR_TXFIFOE            BIT(18) >> +#define STAR_RXFIFOE            BIT(19) >> +#define STAR_BUSYD0            BIT(20) >> +#define STAR_BUSYD0END            BIT(21) >> +#define STAR_SDIOIT            BIT(22) >> +#define STAR_ACKFAIL            BIT(23) >> +#define STAR_ACKTIMEOUT            BIT(24) >> +#define STAR_VSWEND            BIT(25) >> +#define STAR_CKSTOP            BIT(26) >> +#define STAR_IDMATE            BIT(27) >> +#define STAR_IDMABTC            BIT(28) >> + >> +#define SDMMC_ICR            0x038 >> +#define ICR_CCRCFAILC            BIT(0) >> +#define ICR_DCRCFAILC            BIT(1) >> +#define ICR_CTIMEOUTC            BIT(2) >> +#define ICR_DTIMEOUTC            BIT(3) >> +#define ICR_TXUNDERRC            BIT(4) >> +#define ICR_RXOVERRC            BIT(5) >> +#define ICR_CMDRENDC            BIT(6) >> +#define ICR_CMDSENTC            BIT(7) >> +#define ICR_DATAENDC            BIT(8) >> +#define ICR_DHOLDC            BIT(9) >> +#define ICR_DBCKENDC            BIT(10) >> +#define ICR_DABORTC            BIT(11) >> +#define ICR_BUSYD0ENDC            BIT(21) >> +#define ICR_SDIOITC            BIT(22) >> +#define ICR_ACKFAILC            BIT(23) >> +#define ICR_ACKTIMEOUTC            BIT(24) >> +#define ICR_VSWENDC            BIT(25) >> +#define ICR_CKSTOPC            BIT(26) >> +#define ICR_IDMATEC            BIT(27) >> +#define ICR_IDMABTCC            BIT(28) >> +#define ICR_STATIC_FLAG            ((GENMASK(28, 21)) | (GENMASK(11, >> 0))) >> + >> +#define SDMMC_MASKR            0x03c >> +#define MASKR_CCRCFAILIE        BIT(0) >> +#define MASKR_DCRCFAILIE        BIT(1) >> +#define MASKR_CTIMEOUTIE        BIT(2) >> +#define MASKR_DTIMEOUTIE        BIT(3) >> +#define MASKR_TXUNDERRIE        BIT(4) >> +#define MASKR_RXOVERRIE            BIT(5) >> +#define MASKR_CMDRENDIE            BIT(6) >> +#define MASKR_CMDSENTIE            BIT(7) >> +#define MASKR_DATAENDIE            BIT(8) >> +#define MASKR_DHOLDIE            BIT(9) >> +#define MASKR_DBCKENDIE            BIT(10) >> +#define MASKR_DABORTIE            BIT(11) >> +#define MASKR_TXFIFOHEIE        BIT(14) >> +#define MASKR_RXFIFOHFIE        BIT(15) >> +#define MASKR_RXFIFOFIE            BIT(17) >> +#define MASKR_TXFIFOEIE            BIT(18) >> +#define MASKR_BUSYD0ENDIE        BIT(21) >> +#define MASKR_SDIOITIE            BIT(22) >> +#define MASKR_ACKFAILIE            BIT(23) >> +#define MASKR_ACKTIMEOUTIE        BIT(24) >> +#define MASKR_VSWENDIE            BIT(25) >> +#define MASKR_CKSTOPIE            BIT(26) >> +#define MASKR_IDMABTCIE            BIT(28) >> + >> +#define SDMMC_ACKTIMER            0x040 >> +#define ACKTIMER_ACKTIME_MASK        GENMASK(24, 0) >> + >> +#define SDMMC_FIFOR            0x080 >> + >> +#define SDMMC_IDMACTRLR            0x050 >> +#define IDMACTRLR_IDMAEN        BIT(0) >> +#define IDMACTRLR_IDMABMODE        BIT(1) >> +#define IDMACTRLR_IDMABACT        BIT(2) >> + >> +#define SDMMC_IDMABSIZER        0x054 >> +#define IDMABSIZER_IDMABNDT_MASK    GENMASK(12, 5) >> + >> +#define SDMMC_IDMABASE0R        0x058 >> +#define SDMMC_IDMABASE1R        0x05c >> + >> +#define SDMMC_IPVR            0x3fc >> +#define IPVR_MINREV_MASK        GENMASK(3, 0) >> +#define IPVR_MAJREV_MASK        GENMASK(7, 4) >> + >> +enum stm32_sdmmc_cookie { >> +    COOKIE_UNMAPPED, >> +    COOKIE_PRE_MAPPED,    /* mapped by pre_req() of stm32 */ >> +    COOKIE_MAPPED,        /* mapped by prepare_data() of stm32 */ >> +}; >> + >> +struct sdmmc_stat { >> +    unsigned long        n_req; >> +    unsigned long        n_datareq; >> +    unsigned long        n_ctimeout; >> +    unsigned long        n_ccrcfail; >> +    unsigned long        n_dtimeout; >> +    unsigned long        n_dcrcfail; >> +    unsigned long        n_txunderrun; >> +    unsigned long        n_rxoverrun; >> +    unsigned long        nb_dma_err; >> +}; >> + >> +struct sdmmc_host { >> +    void __iomem        *base; >> +    struct mmc_host        *mmc; >> +    struct clk        *clk; >> +    struct reset_control    *rst; >> + >> +    u32            clk_reg_add; >> +    u32            pwr_reg_add; >> + >> +    struct mmc_request    *mrq; >> +    struct mmc_command    *cmd; >> +    struct mmc_data        *data; >> +    struct mmc_command    stop_abort; >> +    bool            dpsm_abort; >> + >> +    /* protect host registers access */ >> +    spinlock_t        lock; >> + >> +    unsigned int        sdmmcclk; >> +    unsigned int        sdmmc_ck; >> + >> +    u32            size; >> + >> +    u32            ip_ver; >> +    struct sdmmc_stat    stat; >> +}; >> > > BR Ludo From mboxrd@z Thu Jan 1 00:00:00 1970 From: Ludovic BARRE Subject: Re: [PATCH 2/5] mmc: add stm32 sdmmc controller driver Date: Mon, 26 Feb 2018 11:35:35 +0100 Message-ID: <0b7a72c9-a03f-e313-b675-d4d932735ca5@st.com> References: <1518701697-14242-1-git-send-email-ludovic.Barre@st.com> <1518701697-14242-3-git-send-email-ludovic.Barre@st.com> Mime-Version: 1.0 Content-Type: text/plain; charset="utf-8"; Format="flowed" Content-Transfer-Encoding: base64 Return-path: In-Reply-To: Content-Language: en-US List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=m.gmane.org@lists.infradead.org To: Shawn Lin , Ulf Hansson , Rob Herring Cc: devicetree@vger.kernel.org, Alexandre Torgue , linux-mmc@vger.kernel.org, linux-kernel@vger.kernel.org, Maxime Coquelin , Gerald Baeza , linux-arm-kernel@lists.infradead.org List-Id: devicetree@vger.kernel.org aGkgU2hhd24KCnRoYW5rcyBmb3IgeW91ciByZXZpZXcKCk9uIDAyLzIyLzIwMTggMDU6MjAgUE0s IFNoYXduIExpbiB3cm90ZToKPiBPbiAyMDE4LzIvMTUgMjE6MzQsIEx1ZG92aWMgQmFycmUgd3Jv dGU6Cj4+IEZyb206IEx1ZG92aWMgQmFycmUgPGx1ZG92aWMuYmFycmVAc3QuY29tPgo+Pgo+IAo+ IC4uLgo+IAo+PiArCj4+ICtzdGF0aWMgc3NpemVfdCBzdG0zMl9zZG1tY19zdGF0X3Jlc2V0KHN0 cnVjdCBmaWxlICpmaWxwLAo+PiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgIGNvbnN0IGNoYXIgX191c2VyICp1YnVmLAo+PiArwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgIHNpemVfdCBjb3VudCwgbG9mZl90ICpwcG9zKQo+PiArewo+ PiArwqDCoMKgIHN0cnVjdCBzZXFfZmlsZSAqc2VxZiA9IGZpbHAtPnByaXZhdGVfZGF0YTsKPj4g K8KgwqDCoCBzdHJ1Y3Qgc2RtbWNfaG9zdCAqaG9zdCA9IHNlcWYtPnByaXZhdGU7Cj4+ICsKPj4g K8KgwqDCoCBtdXRleF9sb2NrKCZzZXFmLT5sb2NrKTsKPj4gK8KgwqDCoCBtZW1zZXQoJmhvc3Qt PnN0YXQsIDAsIHNpemVvZihob3N0LT5zdGF0KSk7Cj4+ICvCoMKgwqAgbXV0ZXhfdW5sb2NrKCZz ZXFmLT5sb2NrKTsKPj4gKwo+PiArwqDCoMKgIHJldHVybiBjb3VudDsKPj4gK30KPj4gKwo+PiAr c3RhdGljIGludCBzdG0zMl9zZG1tY19zdGF0X29wZW4oc3RydWN0IGlub2RlICppbm9kZSwgc3Ry dWN0IGZpbGUgKmZpbGUpCj4+ICt7Cj4+ICvCoMKgwqAgcmV0dXJuIHNpbmdsZV9vcGVuKGZpbGUs IHN0bTMyX3NkbW1jX3N0YXRfc2hvdywgaW5vZGUtPmlfcHJpdmF0ZSk7Cj4+ICt9Cj4+ICsKPj4g K3N0YXRpYyBjb25zdCBzdHJ1Y3QgZmlsZV9vcGVyYXRpb25zIHN0bTMyX3NkbW1jX3N0YXRfZm9w cyA9IHsKPj4gK8KgwqDCoCAub3duZXLCoMKgwqDCoMKgwqDCoCA9IFRISVNfTU9EVUxFLAo+PiAr wqDCoMKgIC5vcGVuwqDCoMKgwqDCoMKgwqAgPSBzdG0zMl9zZG1tY19zdGF0X29wZW4sCj4+ICvC oMKgwqAgLnJlYWTCoMKgwqDCoMKgwqDCoCA9IHNlcV9yZWFkLAo+PiArwqDCoMKgIC53cml0ZcKg wqDCoMKgwqDCoMKgID0gc3RtMzJfc2RtbWNfc3RhdF9yZXNldCwKPj4gK8KgwqDCoCAubGxzZWVr wqDCoMKgwqDCoMKgwqAgPSBzZXFfbHNlZWssCj4+ICvCoMKgwqAgLnJlbGVhc2XCoMKgwqAgPSBz aW5nbGVfcmVsZWFzZSwKPj4gK307Cj4+ICsKPiAKPiBDb3VsZCB5b3Ugc2ltcGx5IHVzZSBERUZJ TkVfU0hPV19BVFRSSUJVVEUoc3RtMzJfc2RtbWNfc3RhdCkgaW5zdGVhZD8KCkRFRklORV9TSE9X X0FUVFJJQlVURSBoYXMgbm8gIi53cml0ZSIgZmlsZV9vcGVyYXRpb25zLgpJdCdzIHZlcnkgdXNl ZnVsIHRvIHJlc2V0IHRoZSBzdGF0aXN0aWMgc3RydWN0dXJlLgpTbyBpZiBpdCdzIHBvc3NpYmxl IHRvIGtlZXAgdGhpcyBmZWF0dXJlLCBJIHdvdWxkIHByZWZlci4KCj4gCj4+ICtzdGF0aWMgdm9p ZCBzdG0zMl9zZG1tY19zdGF0X2luaXQoc3RydWN0IHNkbW1jX2hvc3QgKmhvc3QpCj4+ICt7Cj4+ ICvCoMKgwqAgc3RydWN0IG1tY19ob3N0wqDCoMKgICptbWMgPSBob3N0LT5tbWM7Cj4+ICvCoMKg wqAgc3RydWN0IGRlbnRyeSAqcm9vdDsKPj4gKwo+PiArwqDCoMKgIHJvb3QgPSBtbWMtPmRlYnVn ZnNfcm9vdDsKPj4gK8KgwqDCoCBpZiAoIXJvb3QpCj4+ICvCoMKgwqDCoMKgwqDCoCByZXR1cm47 Cj4+ICsKPj4gK8KgwqDCoCBpZiAoIWRlYnVnZnNfY3JlYXRlX2ZpbGUoInN0YXQiLCAwNjAwLCBy b290LCBob3N0LAo+PiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgJnN0bTMyX3Nk bW1jX3N0YXRfZm9wcykpCj4+ICvCoMKgwqDCoMKgwqDCoCBkZXZfZXJyKG1tY19kZXYoaG9zdC0+ bW1jKSwgImZhaWxlZCB0byBpbml0aWFsaXplIGRlYnVnZnNcbiIpOwo+PiArfQo+PiArCj4+ICsj ZGVmaW5lIFNUQVRfSU5DKHN0YXQpICgoc3RhdCkrKykKPj4gKyNlbHNlCj4+ICtzdGF0aWMgdm9p ZCBzdG0zMl9zZG1tY19zdGF0X2luaXQoc3RydWN0IHNkbW1jX2hvc3QgKmhvc3QpCj4+ICt7Cj4+ ICt9Cj4+ICsKPj4gKyNkZWZpbmUgU1RBVF9JTkMoc3RhdCkKPj4gKyNlbmRpZgo+PiArCj4+ICtz dGF0aWMgaW5saW5lIHUzMiBlbmFibGVfaW1hc2soc3RydWN0IHNkbW1jX2hvc3QgKmhvc3QsIHUz MiBpbWFzaykKPj4gK3sKPj4gK8KgwqDCoCB1MzIgbmV3bWFzazsKPj4gKwo+PiArwqDCoMKgIG5l d21hc2sgPSByZWFkbF9yZWxheGVkKGhvc3QtPmJhc2UgKyBTRE1NQ19NQVNLUik7Cj4+ICvCoMKg wqAgbmV3bWFzayB8PSBpbWFzazsKPj4gKwo+PiArwqDCoMKgIGRldl92ZGJnKG1tY19kZXYoaG9z dC0+bW1jKSwgIm1hc2s6JSN4XG4iLCBuZXdtYXNrKTsKPj4gKwo+PiArwqDCoMKgIHdyaXRlbF9y ZWxheGVkKG5ld21hc2ssIGhvc3QtPmJhc2UgKyBTRE1NQ19NQVNLUik7Cj4+ICsKPj4gK8KgwqDC oCByZXR1cm4gbmV3bWFzazsKPj4gK30KPj4gKwo+IAo+IEkgZG9uJ3Qgc2VlIHlvdSB1c2UgdGhl IHJldHVybiB2YWx1ZSBlbGVzd2hlcmUsIHBlcmhhcHMKPiByZW1vdmUgaXQ/Cgp5ZXMgeW91ciBy aWdodCwgSSByZW1vdmUgdGhlIHJldHVybi4KCj4gCj4+ICtzdGF0aWMgaW5saW5lIHUzMiBkaXNh YmxlX2ltYXNrKHN0cnVjdCBzZG1tY19ob3N0ICpob3N0LCB1MzIgaW1hc2spCj4+ICt7Cj4+ICvC oMKgwqAgdTMyIG5ld21hc2s7Cj4+ICsKPj4gK8KgwqDCoCBuZXdtYXNrID0gcmVhZGxfcmVsYXhl ZChob3N0LT5iYXNlICsgU0RNTUNfTUFTS1IpOwo+PiArwqDCoMKgIG5ld21hc2sgJj0gfmltYXNr Owo+PiArCj4+ICvCoMKgwqAgZGV2X3ZkYmcobW1jX2Rldihob3N0LT5tbWMpLCAibWFzazolI3hc biIsIG5ld21hc2spOwo+PiArCj4+ICvCoMKgwqAgd3JpdGVsX3JlbGF4ZWQobmV3bWFzaywgaG9z dC0+YmFzZSArIFNETU1DX01BU0tSKTsKPj4gKwo+PiArwqDCoMKgIHJldHVybiBuZXdtYXNrOwo+ PiArfQo+PiArCj4gCj4gRGl0dG8/Cgp5ZXMgeW91ciByaWdodCwgSSByZW1vdmUgdGhlIHJldHVy bi4KCj4gCj4+ICtzdGF0aWMgaW5saW5lIHZvaWQgY2xlYXJfaW1hc2soc3RydWN0IHNkbW1jX2hv c3QgKmhvc3QpCj4+ICt7Cj4+ICvCoMKgwqAgdTMyIG1hc2sgPSByZWFkbF9yZWxheGVkKGhvc3Qt PmJhc2UgKyBTRE1NQ19NQVNLUik7Cj4+ICsKPj4gK8KgwqDCoCAvKiBwcmVzZXJ2ZSB0aGUgU0RJ TyBJUlEgbWFzayBzdGF0ZSAqLwo+PiArwqDCoMKgIG1hc2sgJj0gTUFTS1JfU0RJT0lUSUU7Cj4+ ICsKPj4gK8KgwqDCoCBkZXZfdmRiZyhtbWNfZGV2KGhvc3QtPm1tYyksICJtYXNrOiUjeFxuIiwg bWFzayk7Cj4+ICsKPj4gK8KgwqDCoCB3cml0ZWxfcmVsYXhlZChtYXNrLCBob3N0LT5iYXNlICsg U0RNTUNfTUFTS1IpOwo+PiArfQo+PiArCj4gCj4gTm90IGNsZWFyIHRvIG1lIHdoeSBjb3VsZG4n dCB5b3UgdXNlIDoKPiBpbWFzayA9IDB4ZmZmZmZmZmYgXiBNQVNLUl9TRElPSVRJRTsKPiBkaXNh YmxlX2ltYXNrKGltYXNrKQoKSW4gZmFjdCwgSSB3aXNoIGtlZXAgU0RJT0lUSUUgZW5hYmxlZCBp ZiBhbmQgb25seSBpZiB0aGUgU0RJT1RJRSB3YXMgCmFscmVhZHkgZW5hYmxlZCAoc28gU0RJT0lU SUUgbWFzayBpcyBub3QgYWx3YXlzIHNldCkKCj4gCj4+ICtzdGF0aWMgaW50IHN0bTMyX3NkbW1j X2NhcmRfYnVzeShzdHJ1Y3QgbW1jX2hvc3QgKm1tYykKPj4gK3sKPj4gK8KgwqDCoCBzdHJ1Y3Qg c2RtbWNfaG9zdCAqaG9zdCA9IG1tY19wcml2KG1tYyk7Cj4+ICvCoMKgwqAgdW5zaWduZWQgbG9u ZyBmbGFnczsKPj4gK8KgwqDCoCB1MzIgc3RhdHVzOwo+PiArCj4+ICvCoMKgwqAgc3Bpbl9sb2Nr X2lycXNhdmUoJmhvc3QtPmxvY2ssIGZsYWdzKTsKPj4gK8KgwqDCoCBzdGF0dXMgPSByZWFkbF9y ZWxheGVkKGhvc3QtPmJhc2UgKyBTRE1NQ19TVEFSKTsKPj4gK8KgwqDCoCBzcGluX3VubG9ja19p cnFyZXN0b3JlKCZob3N0LT5sb2NrLCBmbGFncyk7Cj4+ICsKPj4gK8KgwqDCoCByZXR1cm4gISEo c3RhdHVzICYgU1RBUl9CVVNZRDApOwo+PiArfQo+PiArCj4gCj4gSSBkb24ndCB0aGluayB5b3Ug bmVlZCB0byBob2xkIHRoZSBsb2NrIGhlcmUuCgpqdXN0IGEgcHJvdGVjdGlvbiB3aXRoICJzdG0z Ml9zZG1tY19pcnEiIHdoaWNoIGNvdWxkIG1vZGlmeSBzdGF0dXMgdmFsdWUKCj4gCj4+ICtzdGF0 aWMgdm9pZCBzdG0zMl9zZG1tY19yZXF1ZXN0X2VuZChzdHJ1Y3Qgc2RtbWNfaG9zdCAqaG9zdCwK Pj4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHN0cnVjdCBtbWNfcmVx dWVzdCAqbXJxKQo+PiArewo+PiArwqDCoMKgIHdyaXRlbF9yZWxheGVkKDAsIGhvc3QtPmJhc2Ug KyBTRE1NQ19DTURSKTsKPj4gK8KgwqDCoCB3cml0ZWxfcmVsYXhlZChJQ1JfU1RBVElDX0ZMQUcs IGhvc3QtPmJhc2UgKyBTRE1NQ19JQ1IpOwo+PiArCj4+ICvCoMKgwqAgaG9zdC0+bXJxID0gTlVM TDsKPj4gK8KgwqDCoCBob3N0LT5jbWQgPSBOVUxMOwo+PiArwqDCoMKgIGhvc3QtPmRhdGEgPSBO VUxMOwo+PiArCj4+ICvCoMKgwqAgY2xlYXJfaW1hc2soaG9zdCk7Cj4+ICsKPj4gK8KgwqDCoCBt bWNfcmVxdWVzdF9kb25lKGhvc3QtPm1tYywgbXJxKTsKPj4gK30KPj4gKwo+PiArc3RhdGljIHZv aWQgc3RtMzJfc2RtbWNfcHdyb2ZmKHN0cnVjdCBzZG1tY19ob3N0ICpob3N0KQo+PiArewo+PiAr wqDCoMKgIC8qIE9ubHkgYSByZXNldCBjb3VsZCBkaXNhYmxlIHNkbW1jICovCj4+ICvCoMKgwqAg cmVzZXRfY29udHJvbF9hc3NlcnQoaG9zdC0+cnN0KTsKPj4gK8KgwqDCoCB1ZGVsYXkoMik7Cj4+ ICvCoMKgwqAgcmVzZXRfY29udHJvbF9kZWFzc2VydChob3N0LT5yc3QpOwo+PiArCj4+ICvCoMKg wqAgLyoKPj4gK8KgwqDCoMKgICogU2V0IHRoZSBTRE1NQyBpbiBQb3dlci1jeWNsZSBzdGF0ZS4g VGhpcyB3aWxsIG1ha2UgdGhhdCB0aGUKPj4gK8KgwqDCoMKgICogU0RNTUNfRFs3OjBdLCBTRE1N Q19DTUQgYW5kIFNETU1DX0NLIGFyZSBkcml2ZW4gbG93LAo+PiArwqDCoMKgwqAgKiB0byBwcmV2 ZW50IHRoZSBDYXJkIGZyb20gYmVpbmcgcG93ZXJlZCB0aHJvdWdoIHRoZSBzaWduYWwgbGluZXMu Cj4+ICvCoMKgwqDCoCAqLwo+PiArwqDCoMKgIHdyaXRlbF9yZWxheGVkKFBPV0VSQ1RSTF9DWUMg fCBob3N0LT5wd3JfcmVnX2FkZCwKPj4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgaG9z dC0+YmFzZSArIFNETU1DX1BPV0VSKTsKPj4gK30KPj4gKwo+PiArc3RhdGljIHZvaWQgc3RtMzJf c2RtbWNfcHdyb24oc3RydWN0IHNkbW1jX2hvc3QgKmhvc3QpCj4+ICt7Cj4+ICvCoMKgwqAgLyoK Pj4gK8KgwqDCoMKgICogQWZ0ZXIgYSBwb3dlci1jeWNsZSBzdGF0ZSwgd2UgbXVzdCBzZXQgdGhl IFNETU1DIGluIFBvd2VyLW9mZi4KPj4gK8KgwqDCoMKgICogVGhlIFNETU1DX0RbNzowXSwgU0RN TUNfQ01EIGFuZCBTRE1NQ19DSyBhcmUgZHJpdmVuIGhpZ2guCj4+ICvCoMKgwqDCoCAqIFRoZW4g d2UgY2FuIHNldCB0aGUgU0RNTUMgdG8gUG93ZXItb24gc3RhdGUKPj4gK8KgwqDCoMKgICovCj4+ ICvCoMKgwqAgd3JpdGVsX3JlbGF4ZWQoUE9XRVJDVFJMX09GRiB8IGhvc3QtPnB3cl9yZWdfYWRk LAo+PiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBob3N0LT5iYXNlICsgU0RNTUNfUE9X RVIpOwo+PiArwqDCoMKgIG1kZWxheSgxKTsKPj4gK8KgwqDCoCB3cml0ZWxfcmVsYXhlZChQT1dF UkNUUkxfT04gfCBob3N0LT5wd3JfcmVnX2FkZCwKPj4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqAgaG9zdC0+YmFzZSArIFNETU1DX1BPV0VSKTsKPj4gK30KPj4gKwo+PiArc3RhdGljIHZv aWQgc3RtMzJfc2RtbWNfc2V0X2Nsa3JlZyhzdHJ1Y3Qgc2RtbWNfaG9zdCAqaG9zdCwgc3RydWN0 IAo+PiBtbWNfaW9zICppb3MpCj4+ICt7Cj4+ICvCoMKgwqAgdTMyIGRlc2lyZWQgPSBpb3MtPmNs b2NrOwo+PiArwqDCoMKgIHUzMiBjbGsgPSAwOwo+PiArCj4+ICvCoMKgwqAgLyoKPj4gK8KgwqDC oMKgICogc2RtbWNfY2sgPSBzZG1tY2Nsay8oMipjbGtkaXYpCj4+ICvCoMKgwqDCoCAqIGNsa2Rp diAwID0+IGJ5cGFzcwo+PiArwqDCoMKgwqAgKi8KPj4gK8KgwqDCoCBpZiAoZGVzaXJlZCkgewo+ PiArwqDCoMKgwqDCoMKgwqAgaWYgKGRlc2lyZWQgPj0gaG9zdC0+c2RtbWNjbGspIHsKPj4gK8Kg wqDCoMKgwqDCoMKgwqDCoMKgwqAgY2xrID0gMDsKPj4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqAg aG9zdC0+c2RtbWNfY2sgPSBob3N0LT5zZG1tY2NsazsKPj4gK8KgwqDCoMKgwqDCoMKgIH0gZWxz ZSB7Cj4+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGNsayA9IERJVl9ST1VORF9VUChob3N0LT5z ZG1tY2NsaywgMiAqIGRlc2lyZWQpOwo+PiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBpZiAoY2xr ID4gQ0xLQ1JfQ0xLRElWX01BWCkKPj4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBj bGsgPSBDTEtDUl9DTEtESVZfTUFYOwo+PiArCj4gCj4gRG9uJ3QgeW91IG5lZWQgdG8gY2hlY2sg aWYgdGhlIGRlc2lyZWQgY2xvY2sgcmF0ZSBpcyB0aGUKPiBzYW1lIHdpdGggdGhlIGN1cnJlbnQg Y2xvY2sgcmF0ZT8KCkknZCByYXRoZXIgbm90LgpJIHNob3VsZCBzYXZlIHRoZSBwcmVzY2FsZXIg aW50byB2YXJpYWJsZSBhbmQgbWFuYWdlIHRoaXMuCgpJIHdpbGwgYWRkIGEgZGV2X3dhcm4gaWYg Y2xrID4gQ0xLQ1JfQ0xLRElWX01BWCwgYmVjYXVzZQppZiBpdCdzIGhhcHBlbiB0aGUgY2FyZCBp cyBvdmVyIGNsb2NrZWQuCgo+IAo+PiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBob3N0LT5zZG1t Y19jayA9IGhvc3QtPnNkbW1jY2xrIC8gKDIgKiBjbGspOwo+PiArwqDCoMKgwqDCoMKgwqAgfQo+ PiArwqDCoMKgIH0KPj4gKwo+PiArwqDCoMKgIGlmIChpb3MtPmJ1c193aWR0aCA9PSBNTUNfQlVT X1dJRFRIXzQpCj4+ICvCoMKgwqDCoMKgwqDCoCBjbGsgfD0gQ0xLQ1JfV0lEQlVTXzQ7Cj4+ICvC oMKgwqAgaWYgKGlvcy0+YnVzX3dpZHRoID09IE1NQ19CVVNfV0lEVEhfOCkKPj4gK8KgwqDCoMKg wqDCoMKgIGNsayB8PSBDTEtDUl9XSURCVVNfODsKPj4gKwo+IAo+IGFsc28gaXQgbG9va3Mgd2ly ZWQgdG8gbWUgeW91IHNldCBidXMgd2lkdGggaW4gYSBmdW5jdGlvbiBjYWxsZWQKPiBzdG0zMl9z ZG1tY19zZXRfY2xrcmVnIHdoaWNoIHNlZW1zIGRvIHRoZSBjbG9jayBzZXR0aW5nLgoKSW4gZmFj dCwgdGhpcyBmdW5jdGlvbiByZWdyb3VwIHNldHRpbmdzIG9mIGNsayByZWdpc3RlciwgYW5kIHRo ZXJlIGFyZQpidXN3aXRoLCBjbGssIGhhcmR3YXJlIGZsb3cgY29udHJvbC4uLgoKPiAKPj4gK8Kg wqDCoCBjbGsgfD0gQ0xLQ1JfSFdGQ19FTjsKPj4gKwo+PiArwqDCoMKgIHdyaXRlbF9yZWxheGVk KGNsayB8IGhvc3QtPmNsa19yZWdfYWRkLCBob3N0LT5iYXNlICsgU0RNTUNfQ0xLQ1IpOwo+PiAr fQo+PiArCj4+ICtzdGF0aWMgdm9pZCBzdG0zMl9zZG1tY19zZXRfaW9zKHN0cnVjdCBtbWNfaG9z dCAqbW1jLCBzdHJ1Y3QgbW1jX2lvcyAKPj4gKmlvcykKPj4gK3sKPj4gK8KgwqDCoCBzdHJ1Y3Qg c2RtbWNfaG9zdCAqaG9zdCA9IG1tY19wcml2KG1tYyk7Cj4+ICsKPj4gK8KgwqDCoCBzdG0zMl9z ZG1tY19zZXRfY2xrcmVnKGhvc3QsIGlvcyk7Cj4+ICsKPj4gK8KgwqDCoCBzd2l0Y2ggKGlvcy0+ cG93ZXJfbW9kZSkgewo+PiArwqDCoMKgIGNhc2UgTU1DX1BPV0VSX09GRjoKPj4gK8KgwqDCoMKg wqDCoMKgIGlmICghSVNfRVJSKG1tYy0+c3VwcGx5LnZtbWMpKQo+PiArwqDCoMKgwqDCoMKgwqDC oMKgwqDCoCBtbWNfcmVndWxhdG9yX3NldF9vY3IobW1jLCBtbWMtPnN1cHBseS52bW1jLCAwKTsK Pj4gKwo+PiArwqDCoMKgwqDCoMKgwqAgc3RtMzJfc2RtbWNfcHdyb2ZmKGhvc3QpOwo+PiArwqDC oMKgwqDCoMKgwqAgcmV0dXJuOwo+PiArwqDCoMKgIGNhc2UgTU1DX1BPV0VSX1VQOgo+PiArwqDC oMKgwqDCoMKgwqAgaWYgKCFJU19FUlIobW1jLT5zdXBwbHkudm1tYykpCj4+ICvCoMKgwqDCoMKg wqDCoMKgwqDCoMKgIG1tY19yZWd1bGF0b3Jfc2V0X29jcihtbWMsIG1tYy0+c3VwcGx5LnZtbWMs IGlvcy0+dmRkKTsKPj4gK8KgwqDCoMKgwqDCoMKgIGJyZWFrOwo+PiArwqDCoMKgIGNhc2UgTU1D X1BPV0VSX09OOgo+PiArwqDCoMKgwqDCoMKgwqAgc3RtMzJfc2RtbWNfcHdyb24oaG9zdCk7Cj4+ ICvCoMKgwqDCoMKgwqDCoCBicmVhazsKPj4gK8KgwqDCoCB9Cj4+ICt9Cj4+ICsKPj4gK3N0YXRp YyBpbnQgc3RtMzJfc2RtbWNfdmFsaWRhdGVfZGF0YShzdHJ1Y3Qgc2RtbWNfaG9zdCAqaG9zdCwK Pj4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgc3RydWN0IG1tY19k YXRhICpkYXRhLCBpbnQgY29va2llKQo+PiArewo+PiArwqDCoMKgIGludCBuX2VsZW07Cj4+ICsK Pj4gK8KgwqDCoCBpZiAoIWRhdGEgfHwgZGF0YS0+aG9zdF9jb29raWUgPT0gQ09PS0lFX1BSRV9N QVBQRUQpCj4+ICvCoMKgwqDCoMKgwqDCoCByZXR1cm4gMDsKPj4gKwo+PiArwqDCoMKgIGlmICgh aXNfcG93ZXJfb2ZfMihkYXRhLT5ibGtzeikpIHsKPj4gK8KgwqDCoMKgwqDCoMKgIGRldl9lcnIo bW1jX2Rldihob3N0LT5tbWMpLAo+PiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCAidW5zdXBwb3J0 ZWQgYmxvY2sgc2l6ZSAoJWQgYnl0ZXMpXG4iLCBkYXRhLT5ibGtzeik7Cj4+ICvCoMKgwqDCoMKg wqDCoCByZXR1cm4gLUVJTlZBTDsKPj4gK8KgwqDCoCB9Cj4+ICsKPj4gK8KgwqDCoCBpZiAoZGF0 YS0+c2ctPm9mZnNldCAmIDMgfHwgZGF0YS0+c2ctPmxlbmd0aCAmIDMpIHsKPj4gK8KgwqDCoMKg wqDCoMKgIGRldl9lcnIobW1jX2Rldihob3N0LT5tbWMpLAo+PiArwqDCoMKgwqDCoMKgwqDCoMKg wqDCoCAidW5hbGlnbmVkIHNjYXR0ZXJsaXN0OiBvZnN0OiV4IGxlbmd0aDolZFxuIiwKPj4gK8Kg wqDCoMKgwqDCoMKgwqDCoMKgwqAgZGF0YS0+c2ctPm9mZnNldCwgZGF0YS0+c2ctPmxlbmd0aCk7 Cj4+ICvCoMKgwqDCoMKgwqDCoCByZXR1cm4gLUVJTlZBTDsKPj4gK8KgwqDCoCB9Cj4+ICsKPj4g K8KgwqDCoCBuX2VsZW0gPSBkbWFfbWFwX3NnKG1tY19kZXYoaG9zdC0+bW1jKSwKPj4gK8KgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBkYXRhLT5zZywKPj4gK8KgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoCBkYXRhLT5zZ19sZW4sCj4+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqAgbW1jX2dldF9kbWFfZGlyKGRhdGEpKTsKPj4gKwo+PiArwqDCoMKgIGlmIChuX2VsZW0g IT0gMSkgewo+PiArwqDCoMKgwqDCoMKgwqAgZGV2X2VycihtbWNfZGV2KGhvc3QtPm1tYyksICJu ciBzZWdtZW50ID4xIG5vdCBzdXBwb3J0ZWRcbiIpOwo+IAo+IEkgZG9uJ3QgZ2V0IHRoaXMgY2hl Y2suIFlvdXIgSURNQSBjYW4ndCBkbyBzY2F0dGVyIGxpc3RzLCBidXQKPiBuX2VsZW0gPT0gMCBt ZWFucyBmYWlsZWQgdG8gZG8gZG1hX21hcF9zZy4KCmRtYV9tYXBfc2cgcmV0dXJuIHRoZSBudW1i ZXIgb2YgZWxlbWVudHMgbWFwcGVkIG9yIDAgaWYgZXJyb3IuCmxpa2UgdGhlIG1heF9zZWdzIGlz IHNldCBpbiB0aGUgcHJvYmUsIEkgd2lsbCByZW1vdmUgdGhlIG92ZXJwcm90ZWN0aW9uIApvbiBu dW1iZXIgb2YgZWxlbWVudHMuCgpTbyBJIHdpbGwgcmVwbGFjZSBieQoJaWYgKCFuX2VsZW0pIHsK CQlkZXZfZXJyKG1tY19kZXYoaG9zdC0+bW1jKSwgImRtYV9tYXBfc2cgZmFpbGVkXG4iKTsKCQly ZXR1cm4gLUVJTlZBTDsKCX0KCj4gCj4+ICvCoMKgwqDCoMKgwqDCoCByZXR1cm4gLUVJTlZBTDsK Pj4gK8KgwqDCoCB9Cj4+ICsKPj4gK8KgwqDCoCBkYXRhLT5ob3N0X2Nvb2tpZSA9IGNvb2tpZTsK Pj4gKwo+PiArwqDCoMKgIHJldHVybiAwOwo+PiArfQo+PiArCj4+ICtzdGF0aWMgdm9pZCBzdG0z Ml9zZG1tY19zdGFydF9kYXRhKHN0cnVjdCBzZG1tY19ob3N0ICpob3N0LAo+PiArwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHN0cnVjdCBtbWNfZGF0YSAqZGF0YSkKPj4gK3sK Pj4gK8KgwqDCoCB1MzIgZGF0YWN0cmwsIHRpbWVvdXQsIGltYXNrLCBpZG1hY3RybDsKPj4gK8Kg wqDCoCB1bnNpZ25lZCBsb25nIGxvbmcgY2xrczsKPj4gKwo+PiArwqDCoMKgIGRldl9kYmcobW1j X2Rldihob3N0LT5tbWMpLCAiYmxrc3ogJWQgYmxrcyAlZCBmbGFncyAlMDh4XG4iLAo+PiArwqDC oMKgwqDCoMKgwqAgZGF0YS0+Ymxrc3osIGRhdGEtPmJsb2NrcywgZGF0YS0+ZmxhZ3MpOwo+PiAr Cj4+ICvCoMKgwqAgU1RBVF9JTkMoaG9zdC0+c3RhdC5uX2RhdGFyZXEpOwo+PiArwqDCoMKgIGhv c3QtPmRhdGEgPSBkYXRhOwo+PiArwqDCoMKgIGhvc3QtPnNpemUgPSBkYXRhLT5ibGtzeiAqIGRh dGEtPmJsb2NrczsKPj4gK8KgwqDCoCBkYXRhLT5ieXRlc194ZmVyZWQgPSAwOwo+PiArCj4+ICvC oMKgwqAgY2xrcyA9ICh1bnNpZ25lZCBsb25nIGxvbmcpZGF0YS0+dGltZW91dF9ucyAqIGhvc3Qt PnNkbW1jX2NrOwo+PiArwqDCoMKgIGRvX2RpdihjbGtzLCBOU0VDX1BFUl9TRUMpOwo+PiArwqDC oMKgIHRpbWVvdXQgPSBkYXRhLT50aW1lb3V0X2Nsa3MgKyAodW5zaWduZWQgaW50KWNsa3M7Cj4+ ICsKPj4gK8KgwqDCoCB3cml0ZWxfcmVsYXhlZCh0aW1lb3V0LCBob3N0LT5iYXNlICsgU0RNTUNf RFRJTUVSKTsKPj4gK8KgwqDCoCB3cml0ZWxfcmVsYXhlZChob3N0LT5zaXplLCBob3N0LT5iYXNl ICsgU0RNTUNfRExFTlIpOwo+PiArCj4+ICvCoMKgwqAgZGF0YWN0cmwgPSBGSUVMRF9QUkVQKERD VFJMUl9EQkxPQ0tTSVpFX01BU0ssIGlsb2cyKGRhdGEtPmJsa3N6KSk7Cj4+ICsKPj4gK8KgwqDC oCBpZiAoZGF0YS0+ZmxhZ3MgJiBNTUNfREFUQV9SRUFEKSB7Cj4+ICvCoMKgwqDCoMKgwqDCoCBk YXRhY3RybCB8PSBEQ1RSTFJfRFRESVI7Cj4+ICvCoMKgwqDCoMKgwqDCoCBpbWFzayA9IE1BU0tS X1JYT1ZFUlJJRTsKPj4gK8KgwqDCoCB9IGVsc2Ugewo+PiArwqDCoMKgwqDCoMKgwqAgaW1hc2sg PSBNQVNLUl9UWFVOREVSUklFOwo+PiArwqDCoMKgIH0KPj4gKwo+PiArwqDCoMKgIGlmIChob3N0 LT5tbWMtPmNhcmQgJiYgbW1jX2NhcmRfc2Rpbyhob3N0LT5tbWMtPmNhcmQpKQo+PiArwqDCoMKg wqDCoMKgwqAgZGF0YWN0cmwgfD0gRENUUkxSX1NESU9FTiB8IERDVFJMUl9EVE1PREVfU0RJTzsK Pj4gKwo+PiArwqDCoMKgIGlkbWFjdHJsID0gSURNQUNUUkxSX0lETUFFTjsKPj4gKwo+PiArwqDC oMKgIHdyaXRlbF9yZWxheGVkKHNnX2RtYV9hZGRyZXNzKGRhdGEtPnNnKSwKPj4gK8KgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqAgaG9zdC0+YmFzZSArIFNETU1DX0lETUFCQVNFMFIpOwo+PiAr wqDCoMKgIHdyaXRlbF9yZWxheGVkKGlkbWFjdHJsLCBob3N0LT5iYXNlICsgU0RNTUNfSURNQUNU UkxSKTsKPj4gKwo+PiArwqDCoMKgIGltYXNrIHw9IE1BU0tSX0RBVEFFTkRJRSB8IE1BU0tSX0RU SU1FT1VUSUUgfCBNQVNLUl9EQ1JDRkFJTElFOwo+PiArwqDCoMKgIGVuYWJsZV9pbWFzayhob3N0 LCBpbWFzayk7Cj4+ICsKPj4gK8KgwqDCoCB3cml0ZWxfcmVsYXhlZChkYXRhY3RybCwgaG9zdC0+ YmFzZSArIFNETU1DX0RDVFJMUik7Cj4+ICt9Cj4+ICsKPj4gK3N0YXRpYyB2b2lkIHN0bTMyX3Nk bW1jX3N0YXJ0X2NtZChzdHJ1Y3Qgc2RtbWNfaG9zdCAqaG9zdCwKPj4gK8KgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqAgc3RydWN0IG1tY19jb21tYW5kICpjbWQsIHUzMiBjKQo+PiAr ewo+PiArwqDCoMKgIHZvaWQgX19pb21lbSAqYmFzZSA9IGhvc3QtPmJhc2U7Cj4gCj4gTm90IG5l ZWQgdG8gaW50cm9kdWNlIHRoaXMgdmFyaWFibGUuCgpPSwoKPiAKPj4gK8KgwqDCoCB1MzIgaW1z azsKPj4gKwo+PiArwqDCoMKgIGRldl9kYmcobW1jX2Rldihob3N0LT5tbWMpLCAib3AgJXUgYXJn ICUwOHggZmxhZ3MgJTA4eFxuIiwKPj4gK8KgwqDCoMKgwqDCoMKgIGNtZC0+b3Bjb2RlLCBjbWQt PmFyZywgY21kLT5mbGFncyk7Cj4+ICsKPj4gK8KgwqDCoCBTVEFUX0lOQyhob3N0LT5zdGF0Lm5f cmVxKTsKPj4gKwo+PiArwqDCoMKgIGlmIChyZWFkbF9yZWxheGVkKGJhc2UgKyBTRE1NQ19DTURS KSAmIENNRFJfQ1BTTUVNKQo+PiArwqDCoMKgwqDCoMKgwqAgd3JpdGVsX3JlbGF4ZWQoMCwgYmFz ZSArIFNETU1DX0NNRFIpOwo+PiArCj4+ICvCoMKgwqAgYyB8PSBjbWQtPm9wY29kZSB8IENNRFJf Q1BTTUVNOwo+PiArwqDCoMKgIGlmIChjbWQtPmZsYWdzICYgTU1DX1JTUF9QUkVTRU5UKSB7Cj4+ ICvCoMKgwqDCoMKgwqDCoCBpbXNrID0gTUFTS1JfQ01EUkVORElFIHwgTUFTS1JfQ1RJTUVPVVRJ RTsKPj4gK8KgwqDCoMKgwqDCoMKgIGlmIChjbWQtPmZsYWdzICYgTU1DX1JTUF9DUkMpCj4+ICvC oMKgwqDCoMKgwqDCoMKgwqDCoMKgIGltc2sgfD0gTUFTS1JfQ0NSQ0ZBSUxJRTsKPj4gKwo+PiAr wqDCoMKgwqDCoMKgwqAgaWYgKGNtZC0+ZmxhZ3MgJiBNTUNfUlNQXzEzNikKPj4gK8KgwqDCoMKg wqDCoMKgwqDCoMKgwqAgYyB8PSBDTURSX1dBSVRSRVNQX0xSU1BfQ1JDOwo+PiArwqDCoMKgwqDC oMKgwqAgZWxzZSBpZiAoY21kLT5mbGFncyAmIE1NQ19SU1BfQ1JDKQo+PiArwqDCoMKgwqDCoMKg wqDCoMKgwqDCoCBjIHw9IENNRFJfV0FJVFJFU1BfU1JTUF9DUkM7Cj4+ICvCoMKgwqDCoMKgwqDC oCBlbHNlCj4+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGMgfD0gQ01EUl9XQUlUUkVTUF9TUlNQ Owo+PiArwqDCoMKgIH0gZWxzZSB7Cj4+ICvCoMKgwqDCoMKgwqDCoCBjICY9IH5DTURSX1dBSVRS RVNQX01BU0s7Cj4+ICvCoMKgwqDCoMKgwqDCoCBpbXNrID0gTUFTS1JfQ01EU0VOVElFOwo+PiAr wqDCoMKgIH0KPj4gKwo+PiArwqDCoMKgIGhvc3QtPmNtZCA9IGNtZDsKPj4gKwo+PiArwqDCoMKg IGVuYWJsZV9pbWFzayhob3N0LCBpbXNrKTsKPj4gKwo+PiArwqDCoMKgIHdyaXRlbF9yZWxheGVk KGNtZC0+YXJnLCBiYXNlICsgU0RNTUNfQVJHUik7Cj4+ICvCoMKgwqAgd3JpdGVsX3JlbGF4ZWQo YywgYmFzZSArIFNETU1DX0NNRFIpOwo+PiArfQo+PiArCj4+ICtzdGF0aWMgdm9pZCBzdG0zMl9z ZG1tY19jbWRfaXJxKHN0cnVjdCBzZG1tY19ob3N0ICpob3N0LCB1MzIgc3RhdHVzKQo+PiArewo+ PiArwqDCoMKgIHN0cnVjdCBtbWNfY29tbWFuZCAqY21kID0gaG9zdC0+Y21kOwo+PiArCj4+ICvC oMKgwqAgaWYgKCFjbWQpCj4+ICvCoMKgwqDCoMKgwqDCoCByZXR1cm47Cj4+ICsKPj4gK8KgwqDC oCBob3N0LT5jbWQgPSBOVUxMOwo+PiArCj4+ICvCoMKgwqAgaWYgKHN0YXR1cyAmIFNUQVJfQ1RJ TUVPVVQpIHsKPj4gK8KgwqDCoMKgwqDCoMKgIFNUQVRfSU5DKGhvc3QtPnN0YXQubl9jdGltZW91 dCk7Cj4+ICvCoMKgwqDCoMKgwqDCoCBjbWQtPmVycm9yID0gLUVUSU1FRE9VVDsKPj4gK8KgwqDC oMKgwqDCoMKgIGhvc3QtPmRwc21fYWJvcnQgPSB0cnVlOwo+PiArwqDCoMKgIH0gZWxzZSBpZiAo c3RhdHVzICYgU1RBUl9DQ1JDRkFJTCAmJiBjbWQtPmZsYWdzICYgTU1DX1JTUF9DUkMpIHsKPj4g K8KgwqDCoMKgwqDCoMKgIFNUQVRfSU5DKGhvc3QtPnN0YXQubl9jY3JjZmFpbCk7Cj4+ICvCoMKg wqDCoMKgwqDCoCBjbWQtPmVycm9yID0gLUVJTFNFUTsKPj4gK8KgwqDCoMKgwqDCoMKgIGhvc3Qt PmRwc21fYWJvcnQgPSB0cnVlOwo+PiArwqDCoMKgIH0gZWxzZSBpZiAoc3RhdHVzICYgU1RBUl9D TURSRU5EICYmIGNtZC0+ZmxhZ3MgJiBNTUNfUlNQX1BSRVNFTlQpIHsKPj4gK8KgwqDCoMKgwqDC oMKgIGNtZC0+cmVzcFswXSA9IHJlYWRsX3JlbGF4ZWQoaG9zdC0+YmFzZSArIFNETU1DX1JFU1Ax Uik7Cj4+ICvCoMKgwqDCoMKgwqDCoCBjbWQtPnJlc3BbMV0gPSByZWFkbF9yZWxheGVkKGhvc3Qt PmJhc2UgKyBTRE1NQ19SRVNQMlIpOwo+PiArwqDCoMKgwqDCoMKgwqAgY21kLT5yZXNwWzJdID0g cmVhZGxfcmVsYXhlZChob3N0LT5iYXNlICsgU0RNTUNfUkVTUDNSKTsKPj4gK8KgwqDCoMKgwqDC oMKgIGNtZC0+cmVzcFszXSA9IHJlYWRsX3JlbGF4ZWQoaG9zdC0+YmFzZSArIFNETU1DX1JFU1A0 Uik7Cj4+ICvCoMKgwqAgfQo+PiArCj4+ICvCoMKgwqAgaWYgKCFob3N0LT5kYXRhKQo+PiArwqDC oMKgwqDCoMKgwqAgc3RtMzJfc2RtbWNfcmVxdWVzdF9lbmQoaG9zdCwgaG9zdC0+bXJxKTsKPj4g K30KPj4gKwo+PiArc3RhdGljIHZvaWQgc3RtMzJfc2RtbWNfZGF0YV9pcnEoc3RydWN0IHNkbW1j X2hvc3QgKmhvc3QsIHUzMiBzdGF0dXMpCj4+ICt7Cj4+ICvCoMKgwqAgc3RydWN0IG1tY19kYXRh wqDCoMKgICpkYXRhID0gaG9zdC0+ZGF0YTsKPj4gK8KgwqDCoCBzdHJ1Y3QgbW1jX2NvbW1hbmQg KnN0b3AgPSAmaG9zdC0+c3RvcF9hYm9ydDsKPj4gKwo+PiArwqDCoMKgIGlmICghZGF0YSkKPj4g K8KgwqDCoMKgwqDCoMKgIHJldHVybjsKPj4gKwo+PiArwqDCoMKgIGlmIChzdGF0dXMgJiBTVEFS X0RDUkNGQUlMKSB7Cj4+ICvCoMKgwqDCoMKgwqDCoCBTVEFUX0lOQyhob3N0LT5zdGF0Lm5fZGNy Y2ZhaWwpOwo+PiArwqDCoMKgwqDCoMKgwqAgZGF0YS0+ZXJyb3IgPSAtRUlMU0VROwo+PiArwqDC oMKgwqDCoMKgwqAgaWYgKHJlYWRsX3JlbGF4ZWQoaG9zdC0+YmFzZSArIFNETU1DX0RDTlRSKSkK Pj4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqAgaG9zdC0+ZHBzbV9hYm9ydCA9IHRydWU7Cj4+ICvC oMKgwqAgfSBlbHNlIGlmIChzdGF0dXMgJiBTVEFSX0RUSU1FT1VUKSB7Cj4+ICvCoMKgwqDCoMKg wqDCoCBTVEFUX0lOQyhob3N0LT5zdGF0Lm5fZHRpbWVvdXQpOwo+PiArwqDCoMKgwqDCoMKgwqAg ZGF0YS0+ZXJyb3IgPSAtRVRJTUVET1VUOwo+PiArwqDCoMKgwqDCoMKgwqAgaG9zdC0+ZHBzbV9h Ym9ydCA9IHRydWU7Cj4+ICvCoMKgwqAgfSBlbHNlIGlmIChzdGF0dXMgJiBTVEFSX1RYVU5ERVJS KSB7Cj4+ICvCoMKgwqDCoMKgwqDCoCBTVEFUX0lOQyhob3N0LT5zdGF0Lm5fdHh1bmRlcnJ1bik7 Cj4+ICvCoMKgwqDCoMKgwqDCoCBkYXRhLT5lcnJvciA9IC1FSU87Cj4+ICvCoMKgwqDCoMKgwqDC oCBob3N0LT5kcHNtX2Fib3J0ID0gdHJ1ZTsKPj4gK8KgwqDCoCB9IGVsc2UgaWYgKHN0YXR1cyAm IFNUQVJfUlhPVkVSUikgewo+PiArwqDCoMKgwqDCoMKgwqAgU1RBVF9JTkMoaG9zdC0+c3RhdC5u X3J4b3ZlcnJ1bik7Cj4+ICvCoMKgwqDCoMKgwqDCoCBkYXRhLT5lcnJvciA9IC1FSU87Cj4+ICvC oMKgwqDCoMKgwqDCoCBob3N0LT5kcHNtX2Fib3J0ID0gdHJ1ZTsKPj4gK8KgwqDCoCB9Cj4+ICsK Pj4gK8KgwqDCoCBpZiAoc3RhdHVzICYgU1RBUl9EQVRBRU5EIHx8IGRhdGEtPmVycm9yIHx8IGhv c3QtPmRwc21fYWJvcnQpIHsKPj4gK8KgwqDCoMKgwqDCoMKgIGhvc3QtPmRhdGEgPSBOVUxMOwo+ PiArCj4+ICvCoMKgwqDCoMKgwqDCoCB3cml0ZWxfcmVsYXhlZCgwLCBob3N0LT5iYXNlICsgU0RN TUNfSURNQUNUUkxSKTsKPj4gKwo+PiArwqDCoMKgwqDCoMKgwqAgaWYgKCFkYXRhLT5lcnJvcikK Pj4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqAgZGF0YS0+Ynl0ZXNfeGZlcmVkID0gZGF0YS0+Ymxv Y2tzICogZGF0YS0+Ymxrc3o7Cj4+ICsKPj4gK8KgwqDCoMKgwqDCoMKgIC8qCj4+ICvCoMKgwqDC oMKgwqDCoMKgICogVG8gc3RvcCBEYXRhIFBhdGggU3RhdGUgTWFjaGluZSwgYSBzdG9wX3RyYW5z bWlzc2lvbiBjb21tYW5kCj4+ICvCoMKgwqDCoMKgwqDCoMKgICogc2hhbGwgYmUgc2VuZCBvbiBj bWQgb3IgZGF0YSBlcnJvcnMgb2Ygc2luZ2xlLCBtdWx0aSwKPj4gK8KgwqDCoMKgwqDCoMKgwqAg KiBwcmUtZGVmaW5lZCBibG9jayBhbmQgc3RyZWFtIHJlcXVlc3QuCj4+ICvCoMKgwqDCoMKgwqDC oMKgICovCj4+ICvCoMKgwqDCoMKgwqDCoCBpZiAoaG9zdC0+ZHBzbV9hYm9ydCAmJiAhZGF0YS0+ c3RvcCkgewo+PiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBtZW1zZXQoc3RvcCwgMCwgc2l6ZW9m KHN0cnVjdCBtbWNfY29tbWFuZCkpOwo+PiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBzdG9wLT5v cGNvZGUgPSBNTUNfU1RPUF9UUkFOU01JU1NJT047Cj4+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKg IHN0b3AtPmFyZyA9IDA7Cj4+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHN0b3AtPmZsYWdzID0g TU1DX1JTUF9SMUIgfCBNTUNfQ01EX0FDOwo+PiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBkYXRh LT5zdG9wID0gc3RvcDsKPj4gK8KgwqDCoMKgwqDCoMKgIH0KPj4gKwo+PiArwqDCoMKgwqDCoMKg wqAgZGlzYWJsZV9pbWFzayhob3N0LCBNQVNLUl9SWE9WRVJSSUUgfCBNQVNLUl9UWFVOREVSUklF Cj4+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHwgTUFTS1JfRENSQ0ZBSUxJ RSB8IE1BU0tSX0RBVEFFTkRJRQo+PiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oCB8IE1BU0tSX0RUSU1FT1VUSUUpOwo+PiArCj4+ICvCoMKgwqDCoMKgwqDCoCBpZiAoIWRhdGEt PnN0b3ApCj4+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHN0bTMyX3NkbW1jX3JlcXVlc3RfZW5k KGhvc3QsIGRhdGEtPm1ycSk7Cj4+ICvCoMKgwqDCoMKgwqDCoCBlbHNlCj4+ICvCoMKgwqDCoMKg wqDCoMKgwqDCoMKgIHN0bTMyX3NkbW1jX3N0YXJ0X2NtZChob3N0LCBkYXRhLT5zdG9wLCBDTURS X0NNRFNUT1ApOwo+PiArwqDCoMKgIH0KPj4gK30KPj4gKwo+PiArc3RhdGljIGlycXJldHVybl90 IHN0bTMyX3NkbW1jX2lycShpbnQgaXJxLCB2b2lkICpkZXZfaWQpCj4+ICt7Cj4+ICvCoMKgwqAg c3RydWN0IHNkbW1jX2hvc3QgKmhvc3QgPSBkZXZfaWQ7Cj4+ICvCoMKgwqAgdTMyIHN0YXR1czsK Pj4gKwo+PiArwqDCoMKgIHNwaW5fbG9jaygmaG9zdC0+bG9jayk7Cj4+ICsKPj4gK8KgwqDCoCBz dGF0dXMgPSByZWFkbF9yZWxheGVkKGhvc3QtPmJhc2UgKyBTRE1NQ19TVEFSKTsKPj4gK8KgwqDC oCBkZXZfZGJnKG1tY19kZXYoaG9zdC0+bW1jKSwgImlycSBzdGE6JSN4XG4iLCBzdGF0dXMpOwo+ PiArwqDCoMKgIHdyaXRlbF9yZWxheGVkKHN0YXR1cyAmIElDUl9TVEFUSUNfRkxBRywgaG9zdC0+ YmFzZSArIFNETU1DX0lDUik7Cj4+ICsKPj4gK8KgwqDCoCBzdG0zMl9zZG1tY19jbWRfaXJxKGhv c3QsIHN0YXR1cyk7Cj4+ICvCoMKgwqAgc3RtMzJfc2RtbWNfZGF0YV9pcnEoaG9zdCwgc3RhdHVz KTsKPj4gKwo+PiArwqDCoMKgIHNwaW5fdW5sb2NrKCZob3N0LT5sb2NrKTsKPj4gKwo+PiArwqDC oMKgIHJldHVybiBJUlFfSEFORExFRDsKPj4gK30KPj4gKwo+PiArc3RhdGljIHZvaWQgc3RtMzJf c2RtbWNfcHJlX3JlcShzdHJ1Y3QgbW1jX2hvc3QgKm1tYywgc3RydWN0IAo+PiBtbWNfcmVxdWVz dCAqbXJxKQo+PiArewo+PiArwqDCoMKgIHN0cnVjdCBzZG1tY19ob3N0ICpob3N0ID0gbW1jX3By aXYobW1jKTsKPj4gK8KgwqDCoCBzdHJ1Y3QgbW1jX2RhdGEgKmRhdGEgPSBtcnEtPmRhdGE7Cj4+ ICsKPj4gK8KgwqDCoCBpZiAoIWRhdGEpCj4+ICvCoMKgwqDCoMKgwqDCoCByZXR1cm47Cj4+ICsK Pj4gK8KgwqDCoCAvKiBUaGlzIGRhdGEgbWlnaHQgYmUgdW5tYXBwZWQgYXQgdGhpcyB0aW1lICov Cj4+ICvCoMKgwqAgZGF0YS0+aG9zdF9jb29raWUgPSBDT09LSUVfVU5NQVBQRUQ7Cj4+ICsKPj4g K8KgwqDCoCBpZiAoIXN0bTMyX3NkbW1jX3ZhbGlkYXRlX2RhdGEoaG9zdCwgbXJxLT5kYXRhLCBD T09LSUVfUFJFX01BUFBFRCkpCj4+ICvCoMKgwqDCoMKgwqDCoCBkYXRhLT5ob3N0X2Nvb2tpZSA9 IENPT0tJRV9VTk1BUFBFRDsKPj4gK30KPj4gKwo+PiArc3RhdGljIHZvaWQgc3RtMzJfc2RtbWNf cG9zdF9yZXEoc3RydWN0IG1tY19ob3N0ICptbWMsIHN0cnVjdCAKPj4gbW1jX3JlcXVlc3QgKm1y cSwKPj4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGludCBlcnIpCj4+ICt7Cj4+ ICvCoMKgwqAgc3RydWN0IHNkbW1jX2hvc3QgKmhvc3QgPSBtbWNfcHJpdihtbWMpOwo+PiArwqDC oMKgIHN0cnVjdCBtbWNfZGF0YSAqZGF0YSA9IG1ycS0+ZGF0YTsKPj4gKwo+PiArwqDCoMKgIGlm ICghZGF0YSkKPj4gK8KgwqDCoMKgwqDCoMKgIHJldHVybjsKPj4gKwo+PiArwqDCoMKgIGlmIChk YXRhLT5ob3N0X2Nvb2tpZSAhPSBDT09LSUVfVU5NQVBQRUQpCj4+ICvCoMKgwqDCoMKgwqDCoCBk bWFfdW5tYXBfc2cobW1jX2Rldihob3N0LT5tbWMpLAo+PiArwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqAgZGF0YS0+c2csCj4+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oCBkYXRhLT5zZ19sZW4sCj4+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBtbWNf Z2V0X2RtYV9kaXIoZGF0YSkpOwo+PiArCj4+ICvCoMKgwqAgZGF0YS0+aG9zdF9jb29raWUgPSBD T09LSUVfVU5NQVBQRUQ7Cj4+ICt9Cj4+ICsKPj4gK3N0YXRpYyB2b2lkIHN0bTMyX3NkbW1jX3Jl cXVlc3Qoc3RydWN0IG1tY19ob3N0ICptbWMsIHN0cnVjdCAKPj4gbW1jX3JlcXVlc3QgKm1ycSkK Pj4gK3sKPj4gK8KgwqDCoCB1bnNpZ25lZCBpbnQgY21kYXQgPSAwOwo+PiArwqDCoMKgIHN0cnVj dCBzZG1tY19ob3N0ICpob3N0ID0gbW1jX3ByaXYobW1jKTsKPj4gK8KgwqDCoCB1bnNpZ25lZCBs b25nIGZsYWdzOwo+PiArCj4+ICvCoMKgwqAgbXJxLT5jbWQtPmVycm9yID0gc3RtMzJfc2RtbWNf dmFsaWRhdGVfZGF0YShob3N0LCBtcnEtPmRhdGEsCj4+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgQ09PS0lFX01BUFBFRCk7Cj4+ICvCoMKg wqAgaWYgKG1ycS0+Y21kLT5lcnJvcikgewo+PiArwqDCoMKgwqDCoMKgwqAgbW1jX3JlcXVlc3Rf ZG9uZShtbWMsIG1ycSk7Cj4+ICvCoMKgwqDCoMKgwqDCoCByZXR1cm47Cj4+ICvCoMKgwqAgfQo+ PiArCj4+ICvCoMKgwqAgc3Bpbl9sb2NrX2lycXNhdmUoJmhvc3QtPmxvY2ssIGZsYWdzKTsKPj4g Kwo+PiArwqDCoMKgIGhvc3QtPm1ycSA9IG1ycTsKPj4gKwo+PiArwqDCoMKgIGlmIChtcnEtPmRh dGEpIHsKPj4gK8KgwqDCoMKgwqDCoMKgIGhvc3QtPmRwc21fYWJvcnQgPSBmYWxzZTsKPj4gK8Kg wqDCoMKgwqDCoMKgIHN0bTMyX3NkbW1jX3N0YXJ0X2RhdGEoaG9zdCwgbXJxLT5kYXRhKTsKPj4g K8KgwqDCoMKgwqDCoMKgIGNtZGF0IHw9IENNRFJfQ01EVFJBTlM7Cj4+ICvCoMKgwqAgfQo+PiAr Cj4+ICvCoMKgwqAgc3RtMzJfc2RtbWNfc3RhcnRfY21kKGhvc3QsIG1ycS0+Y21kLCBjbWRhdCk7 Cj4+ICsKPj4gK8KgwqDCoCBzcGluX3VubG9ja19pcnFyZXN0b3JlKCZob3N0LT5sb2NrLCBmbGFn cyk7Cj4+ICt9Cj4+ICsKPj4gK3N0YXRpYyBzdHJ1Y3QgbW1jX2hvc3Rfb3BzIHN0bTMyX3NkbW1j X29wcyA9IHsKPj4gK8KgwqDCoCAucmVxdWVzdMKgwqDCoCA9IHN0bTMyX3NkbW1jX3JlcXVlc3Qs Cj4+ICvCoMKgwqAgLnByZV9yZXHCoMKgwqAgPSBzdG0zMl9zZG1tY19wcmVfcmVxLAo+PiArwqDC oMKgIC5wb3N0X3JlccKgwqDCoCA9IHN0bTMyX3NkbW1jX3Bvc3RfcmVxLAo+PiArwqDCoMKgIC5z ZXRfaW9zwqDCoMKgID0gc3RtMzJfc2RtbWNfc2V0X2lvcywKPj4gK8KgwqDCoCAuZ2V0X2NkwqDC oMKgwqDCoMKgwqAgPSBtbWNfZ3Bpb19nZXRfY2QsCj4+ICvCoMKgwqAgLmNhcmRfYnVzecKgwqDC oCA9IHN0bTMyX3NkbW1jX2NhcmRfYnVzeSwKPj4gK307Cj4+ICsKPj4gK3N0YXRpYyBjb25zdCBz dHJ1Y3Qgb2ZfZGV2aWNlX2lkIHN0bTMyX3NkbW1jX21hdGNoW10gPSB7Cj4+ICvCoMKgwqAgeyAu Y29tcGF0aWJsZSA9ICJzdCxzdG0zMmg3LXNkbW1jIix9LAo+PiArwqDCoMKgIHt9LAo+PiArfTsK Pj4gK01PRFVMRV9ERVZJQ0VfVEFCTEUob2YsIHN0bTMyX3NkbW1jX21hdGNoKTsKPj4gKwo+PiAr c3RhdGljIGludCBzdG0zMl9zZG1tY19vZl9wYXJzZShzdHJ1Y3QgZGV2aWNlX25vZGUgKm5wLCBz dHJ1Y3QgCj4+IG1tY19ob3N0ICptbWMpCj4+ICt7Cj4+ICvCoMKgwqAgc3RydWN0IHNkbW1jX2hv c3QgKmhvc3QgPSBtbWNfcHJpdihtbWMpOwo+PiArwqDCoMKgIGludCByZXQgPSBtbWNfb2ZfcGFy c2UobW1jKTsKPj4gKwo+PiArwqDCoMKgIGlmIChyZXQpCj4+ICvCoMKgwqDCoMKgwqDCoCByZXR1 cm4gcmV0Owo+PiArCj4+ICvCoMKgwqAgaWYgKG9mX2dldF9wcm9wZXJ0eShucCwgInN0LG5lZ2Vk Z2UiLCBOVUxMKSkKPj4gK8KgwqDCoMKgwqDCoMKgIGhvc3QtPmNsa19yZWdfYWRkIHw9IENMS0NS X05FR0VER0U7Cj4+ICvCoMKgwqAgaWYgKG9mX2dldF9wcm9wZXJ0eShucCwgInN0LGRpcnBvbCIs IE5VTEwpKQo+PiArwqDCoMKgwqDCoMKgwqAgaG9zdC0+cHdyX3JlZ19hZGQgfD0gUE9XRVJfRElS UE9MOwo+PiArwqDCoMKgIGlmIChvZl9nZXRfcHJvcGVydHkobnAsICJzdCxwaW4tY2tpbiIsIE5V TEwpKQo+PiArwqDCoMKgwqDCoMKgwqAgaG9zdC0+Y2xrX3JlZ19hZGQgfD0gQ0xLQ1JfU0VMQ0xL UlhfQ0tJTjsKPj4gKwo+IAo+IFVzZSBkZXZpY2VfcHJvcGVydHlfcHJlc2VudD8KCk9LLCB0aGFu a3MKCj4gCj4+ICvCoMKgwqAgcmV0dXJuIDA7Cj4+ICt9Cj4+ICsKPj4gK3N0YXRpYyBpbnQgc3Rt MzJfc2RtbWNfcHJvYmUoc3RydWN0IHBsYXRmb3JtX2RldmljZSAqcGRldikKPj4gK3sKPj4gK8Kg wqDCoCBzdHJ1Y3QgZGV2aWNlX25vZGUgKm5wID0gcGRldi0+ZGV2Lm9mX25vZGU7Cj4+ICvCoMKg wqAgc3RydWN0IHNkbW1jX2hvc3QgKmhvc3Q7Cj4+ICvCoMKgwqAgc3RydWN0IG1tY19ob3N0ICpt bWM7Cj4+ICvCoMKgwqAgc3RydWN0IHJlc291cmNlICpyZXM7Cj4+ICvCoMKgwqAgaW50IGlycSwg cmV0Owo+PiArCj4+ICvCoMKgwqAgaWYgKCFucCkgewo+PiArwqDCoMKgwqDCoMKgwqAgZGV2X2Vy cigmcGRldi0+ZGV2LCAiTm8gRFQgZm91bmRcbiIpOwo+PiArwqDCoMKgwqDCoMKgwqAgcmV0dXJu IC1FSU5WQUw7Cj4+ICvCoMKgwqAgfQo+PiArCj4+ICvCoMKgwqAgcmVzID0gcGxhdGZvcm1fZ2V0 X3Jlc291cmNlKHBkZXYsIElPUkVTT1VSQ0VfTUVNLCAwKTsKPj4gK8KgwqDCoCBpcnEgPSBwbGF0 Zm9ybV9nZXRfaXJxKHBkZXYsIDApOwo+PiArwqDCoMKgIGlmIChpcnEgPCAwKQo+PiArwqDCoMKg wqDCoMKgwqAgcmV0dXJuIC1FSU5WQUw7Cj4+ICsKPj4gK8KgwqDCoCBtbWMgPSBtbWNfYWxsb2Nf aG9zdChzaXplb2Yoc3RydWN0IHNkbW1jX2hvc3QpLCAmcGRldi0+ZGV2KTsKPj4gK8KgwqDCoCBp ZiAoIW1tYykKPj4gK8KgwqDCoMKgwqDCoMKgIHJldHVybiAtRU5PTUVNOwo+PiArCj4+ICvCoMKg wqAgaG9zdCA9IG1tY19wcml2KG1tYyk7Cj4+ICvCoMKgwqAgaG9zdC0+bW1jID0gbW1jOwo+PiAr wqDCoMKgIHBsYXRmb3JtX3NldF9kcnZkYXRhKHBkZXYsIG1tYyk7Cj4+ICsKPj4gK8KgwqDCoCBo b3N0LT5iYXNlID0gZGV2bV9pb3JlbWFwX3Jlc291cmNlKCZwZGV2LT5kZXYsIHJlcyk7Cj4+ICvC oMKgwqAgaWYgKElTX0VSUihob3N0LT5iYXNlKSkgewo+PiArwqDCoMKgwqDCoMKgwqAgcmV0ID0g UFRSX0VSUihob3N0LT5iYXNlKTsKPj4gK8KgwqDCoMKgwqDCoMKgIGdvdG8gaG9zdF9mcmVlOwo+ PiArwqDCoMKgIH0KPj4gKwo+PiArwqDCoMKgIHdyaXRlbF9yZWxheGVkKDAsIGhvc3QtPmJhc2Ug KyBTRE1NQ19NQVNLUik7Cj4+ICvCoMKgwqAgd3JpdGVsX3JlbGF4ZWQofjBVTCwgaG9zdC0+YmFz ZSArIFNETU1DX0lDUik7Cj4+ICsKPj4gK8KgwqDCoCByZXQgPSBkZXZtX3JlcXVlc3RfaXJxKCZw ZGV2LT5kZXYsIGlycSwgc3RtMzJfc2RtbWNfaXJxLCAKPj4gSVJRRl9TSEFSRUQsCj4+ICvCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgRFJJVkVSX05BTUUgIiAoY21kKSIsIGhv c3QpOwo+PiArwqDCoMKgIGlmIChyZXQpCj4+ICvCoMKgwqDCoMKgwqDCoCBnb3RvIGhvc3RfZnJl ZTsKPj4gKwo+PiArwqDCoMKgIGhvc3QtPmNsayA9IGRldm1fY2xrX2dldCgmcGRldi0+ZGV2LCBO VUxMKTsKPj4gK8KgwqDCoCBpZiAoSVNfRVJSKGhvc3QtPmNsaykpIHsKPj4gK8KgwqDCoMKgwqDC oMKgIHJldCA9IFBUUl9FUlIoaG9zdC0+Y2xrKTsKPj4gK8KgwqDCoMKgwqDCoMKgIGdvdG8gaG9z dF9mcmVlOwo+PiArwqDCoMKgIH0KPj4gKwo+PiArwqDCoMKgIHJldCA9IGNsa19wcmVwYXJlX2Vu YWJsZShob3N0LT5jbGspOwo+PiArwqDCoMKgIGlmIChyZXQpCj4+ICvCoMKgwqDCoMKgwqDCoCBn b3RvIGhvc3RfZnJlZTsKPj4gKwo+PiArwqDCoMKgIGhvc3QtPnNkbW1jY2xrID0gY2xrX2dldF9y YXRlKGhvc3QtPmNsayk7Cj4+ICvCoMKgwqAgbW1jLT5mX21pbiA9IERJVl9ST1VORF9VUChob3N0 LT5zZG1tY2NsaywgMiAqIENMS0NSX0NMS0RJVl9NQVgpOwo+PiArwqDCoMKgIG1tYy0+Zl9tYXgg PSBob3N0LT5zZG1tY2NsazsKPj4gKwo+PiArwqDCoMKgIHJldCA9IHN0bTMyX3NkbW1jX29mX3Bh cnNlKG5wLCBtbWMpOwo+PiArwqDCoMKgIGlmIChyZXQpCj4+ICvCoMKgwqDCoMKgwqDCoCBnb3Rv IGNsa19kaXNhYmxlOwo+PiArCj4+ICvCoMKgwqAgaG9zdC0+cnN0ID0gZGV2bV9yZXNldF9jb250 cm9sX2dldCgmcGRldi0+ZGV2LCBOVUxMKTsKPj4gK8KgwqDCoCBpZiAoSVNfRVJSKGhvc3QtPnJz dCkpIHsKPj4gK8KgwqDCoMKgwqDCoMKgIHJldCA9IFBUUl9FUlIoaG9zdC0+cnN0KTsKPj4gK8Kg wqDCoMKgwqDCoMKgIGdvdG8gY2xrX2Rpc2FibGU7Cj4+ICvCoMKgwqAgfQo+PiArCj4+ICvCoMKg wqAgc3RtMzJfc2RtbWNfcHdyb2ZmKGhvc3QpOwo+PiArCj4+ICvCoMKgwqAgLyogR2V0IHJlZ3Vs YXRvcnMgYW5kIHRoZSBzdXBwb3J0ZWQgT0NSIG1hc2sgKi8KPj4gK8KgwqDCoCByZXQgPSBtbWNf cmVndWxhdG9yX2dldF9zdXBwbHkobW1jKTsKPj4gK8KgwqDCoCBpZiAocmV0ID09IC1FUFJPQkVf REVGRVIpCj4+ICvCoMKgwqDCoMKgwqDCoCBnb3RvIGNsa19kaXNhYmxlOwo+PiArCj4+ICvCoMKg wqAgaWYgKCFtbWMtPm9jcl9hdmFpbCkKPj4gK8KgwqDCoMKgwqDCoMKgIG1tYy0+b2NyX2F2YWls ID0gTU1DX1ZERF8zMl8zMyB8IE1NQ19WRERfMzNfMzQ7Cj4+ICsKPj4gK8KgwqDCoCBtbWMtPm9w cyA9ICZzdG0zMl9zZG1tY19vcHM7Cj4+ICsKPj4gK8KgwqDCoCAvKiBJRE1BIGNhbm5vdCBkbyBz Y2F0dGVyIGxpc3RzICovCj4+ICvCoMKgwqAgbW1jLT5tYXhfc2VncyA9IDE7Cj4+ICvCoMKgwqAg bW1jLT5tYXhfcmVxX3NpemUgPSBETEVOUl9EQVRBTEVOR0hUX01BWDsKPj4gK8KgwqDCoCBtbWMt Pm1heF9zZWdfc2l6ZSA9IG1tYy0+bWF4X3JlcV9zaXplOwo+PiArwqDCoMKgIG1tYy0+bWF4X2Js a19zaXplID0gMSA8PCBEQ1RSTFJfREJMT0NLU0laRV9NQVg7Cj4+ICsKPj4gK8KgwqDCoCAvKgo+ PiArwqDCoMKgwqAgKiBMaW1pdCB0aGUgbnVtYmVyIG9mIGJsb2NrcyB0cmFuc2ZlcnJlZCBzbyB0 aGF0IHdlIGRvbid0IG92ZXJmbG93Cj4+ICvCoMKgwqDCoCAqIHRoZSBtYXhpbXVtIHJlcXVlc3Qg c2l6ZS4KPj4gK8KgwqDCoMKgICovCj4+ICvCoMKgwqAgbW1jLT5tYXhfYmxrX2NvdW50ID0gbW1j LT5tYXhfcmVxX3NpemUgPj4gRENUUkxSX0RCTE9DS1NJWkVfTUFYOwo+PiArCj4+ICvCoMKgwqAg c3Bpbl9sb2NrX2luaXQoJmhvc3QtPmxvY2spOwo+PiArCj4+ICvCoMKgwqAgcmV0ID0gbW1jX2Fk ZF9ob3N0KG1tYyk7Cj4+ICvCoMKgwqAgaWYgKHJldCkKPj4gK8KgwqDCoMKgwqDCoMKgIGdvdG8g Y2xrX2Rpc2FibGU7Cj4+ICsKPj4gK8KgwqDCoCBzdG0zMl9zZG1tY19zdGF0X2luaXQoaG9zdCk7 Cj4+ICsKPj4gK8KgwqDCoCBob3N0LT5pcF92ZXIgPSByZWFkbF9yZWxheGVkKGhvc3QtPmJhc2Ug KyBTRE1NQ19JUFZSKTsKPj4gK8KgwqDCoCBkZXZfaW5mbygmcGRldi0+ZGV2LCAiJXM6IHJldjol bGQuJWxkIGlycTolZFxuIiwKPj4gK8KgwqDCoMKgwqDCoMKgwqAgbW1jX2hvc3RuYW1lKG1tYyks Cj4+ICvCoMKgwqDCoMKgwqDCoMKgIEZJRUxEX0dFVChJUFZSX01BSlJFVl9NQVNLLCBob3N0LT5p cF92ZXIpLAo+PiArwqDCoMKgwqDCoMKgwqDCoCBGSUVMRF9HRVQoSVBWUl9NSU5SRVZfTUFTSywg aG9zdC0+aXBfdmVyKSwgaXJxKTsKPj4gKwo+PiArwqDCoMKgIHJldHVybiAwOwo+PiArCj4+ICtj bGtfZGlzYWJsZToKPj4gK8KgwqDCoCBjbGtfZGlzYWJsZV91bnByZXBhcmUoaG9zdC0+Y2xrKTsK Pj4gK2hvc3RfZnJlZToKPj4gK8KgwqDCoCBtbWNfZnJlZV9ob3N0KG1tYyk7Cj4+ICvCoMKgwqAg cmV0dXJuIHJldDsKPj4gK30KPj4gKwo+PiArc3RhdGljIGludCBzdG0zMl9zZG1tY19yZW1vdmUo c3RydWN0IHBsYXRmb3JtX2RldmljZSAqcGRldikKPj4gK3sKPj4gK8KgwqDCoCBzdHJ1Y3QgbW1j X2hvc3QgKm1tYyA9IHBsYXRmb3JtX2dldF9kcnZkYXRhKHBkZXYpOwo+PiArwqDCoMKgIHN0cnVj dCBzZG1tY19ob3N0ICpob3N0ID0gbW1jX3ByaXYobW1jKTsKPj4gKwo+PiArwqDCoMKgIC8qIERl YnVnZnMgc3R1ZmYgaXMgY2xlYW5lZCB1cCBieSBtbWMgY29yZSAqLwo+PiArwqDCoMKgIG1tY19y ZW1vdmVfaG9zdChtbWMpOwo+PiArwqDCoMKgIGNsa19kaXNhYmxlX3VucHJlcGFyZShob3N0LT5j bGspOwo+PiArwqDCoMKgIG1tY19mcmVlX2hvc3QobW1jKTsKPj4gKwo+PiArwqDCoMKgIHJldHVy biAwOwo+PiArfQo+PiArCj4+ICtzdGF0aWMgc3RydWN0IHBsYXRmb3JtX2RyaXZlciBzdG0zMl9z ZG1tY19kcml2ZXIgPSB7Cj4+ICvCoMKgwqAgLnByb2JlwqDCoMKgwqDCoMKgwqAgPSBzdG0zMl9z ZG1tY19wcm9iZSwKPj4gK8KgwqDCoCAucmVtb3ZlwqDCoMKgwqDCoMKgwqAgPSBzdG0zMl9zZG1t Y19yZW1vdmUsCj4+ICvCoMKgwqAgLmRyaXZlcsKgwqDCoCA9IHsKPj4gK8KgwqDCoMKgwqDCoMKg IC5uYW1lwqDCoMKgID0gRFJJVkVSX05BTUUsCj4+ICvCoMKgwqDCoMKgwqDCoCAub2ZfbWF0Y2hf dGFibGUgPSBzdG0zMl9zZG1tY19tYXRjaCwKPj4gK8KgwqDCoCB9LAo+PiArfTsKPj4gKwo+PiAr bW9kdWxlX3BsYXRmb3JtX2RyaXZlcihzdG0zMl9zZG1tY19kcml2ZXIpOwo+PiArCj4+ICtNT0RV TEVfREVTQ1JJUFRJT04oIlNUTWljcm9lbGVjdHJvbmljcyBTVE0zMiBNTUMvU0QgQ2FyZCBJbnRl cmZhY2UgCj4+IGRyaXZlciIpOwo+PiArTU9EVUxFX0xJQ0VOU0UoIkdQTCB2MiIpOwo+PiArTU9E VUxFX0FVVEhPUigiTHVkb3ZpYyBCYXJyZSA8bHVkb3ZpYy5iYXJyZUBzdC5jb20+Iik7Cj4+IGRp ZmYgLS1naXQgYS9kcml2ZXJzL21tYy9ob3N0L3N0bTMyLXNkbW1jLmggCj4+IGIvZHJpdmVycy9t bWMvaG9zdC9zdG0zMi1zZG1tYy5oCj4+IG5ldyBmaWxlIG1vZGUgMTAwNjQ0Cj4+IGluZGV4IDAw MDAwMDAuLmUzOTU3OGUKPj4gLS0tIC9kZXYvbnVsbAo+PiArKysgYi9kcml2ZXJzL21tYy9ob3N0 L3N0bTMyLXNkbW1jLmgKPj4gQEAgLTAsMCArMSwyMjAgQEAKPj4gKy8qIFNQRFgtTGljZW5zZS1J ZGVudGlmaWVyOiBHUEwtMi4wICovCj4+ICsvKgo+PiArICogQ29weXJpZ2h0IChDKSBTVE1pY3Jv ZWxlY3Ryb25pY3MgMjAxOCAtIEFsbCBSaWdodHMgUmVzZXJ2ZWQKPj4gKyAqIEF1dGhvcjogTHVk b3ZpYyBCYXJyZSA8bHVkb3ZpYy5iYXJyZUBzdC5jb20+IGZvciBTVE1pY3JvZWxlY3Ryb25pY3Mu Cj4+ICsgKi8KPj4gKyNkZWZpbmUgU0RNTUNfUE9XRVLCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIDB4 MDAwCj4+ICsjZGVmaW5lIFBPV0VSQ1RSTF9NQVNLwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBHRU5N QVNLKDEsIDApCj4+ICsjZGVmaW5lIFBPV0VSQ1RSTF9PRkbCoMKgwqDCoMKgwqDCoMKgwqDCoMKg IDB4MDAKPj4gKyNkZWZpbmUgUE9XRVJDVFJMX0NZQ8KgwqDCoMKgwqDCoMKgwqDCoMKgwqAgMHgw Mgo+PiArI2RlZmluZSBQT1dFUkNUUkxfT07CoMKgwqDCoMKgwqDCoMKgwqDCoMKgIDB4MDMKPj4g KyNkZWZpbmUgUE9XRVJfVlNXSVRDSMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgQklUKDIpCj4+ICsj ZGVmaW5lIFBPV0VSX1ZTV0lUQ0hFTsKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgQklUKDMpCj4+ICsj ZGVmaW5lIFBPV0VSX0RJUlBPTMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgQklUKDQpCj4+ICsKPj4g KyNkZWZpbmUgU0RNTUNfQ0xLQ1LCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIDB4MDA0Cj4+ICsjZGVm aW5lIENMS0NSX0NMS0RJVl9NQVNLwqDCoMKgwqDCoMKgwqAgR0VOTUFTSyg5LCAwKQo+PiArI2Rl ZmluZSBDTEtDUl9DTEtESVZfTUFYwqDCoMKgwqDCoMKgwqAgQ0xLQ1JfQ0xLRElWX01BU0sKPj4g KyNkZWZpbmUgQ0xLQ1JfUFdSU0FWwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBCSVQoMTIpCj4+ICsj ZGVmaW5lIENMS0NSX1dJREJVU180wqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBCSVQoMTQpCj4+ICsj ZGVmaW5lIENMS0NSX1dJREJVU184wqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBCSVQoMTUpCj4+ICsj ZGVmaW5lIENMS0NSX05FR0VER0XCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIEJJVCgxNikKPj4gKyNk ZWZpbmUgQ0xLQ1JfSFdGQ19FTsKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgQklUKDE3KQo+PiArI2Rl ZmluZSBDTEtDUl9ERFLCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIEJJVCgxOCkKPj4gKyNkZWZpbmUg Q0xLQ1JfQlVTU1BFRUTCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIEJJVCgxOSkKPj4gKyNkZWZpbmUg Q0xLQ1JfU0VMQ0xLUlhfTUFTS8KgwqDCoMKgwqDCoMKgIEdFTk1BU0soMjEsIDIwKQo+PiArI2Rl ZmluZSBDTEtDUl9TRUxDTEtSWF9DS8KgwqDCoMKgwqDCoMKgICgwIDw8IDIwKQo+PiArI2RlZmlu ZSBDTEtDUl9TRUxDTEtSWF9DS0lOwqDCoMKgwqDCoMKgwqAgKDEgPDwgMjApCj4+ICsjZGVmaW5l IENMS0NSX1NFTENMS1JYX0ZCQ0vCoMKgwqDCoMKgwqDCoCAoMiA8PCAyMCkKPj4gKwo+PiArI2Rl ZmluZSBTRE1NQ19BUkdSwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCAweDAwOAo+PiArCj4+ICsjZGVm aW5lIFNETU1DX0NNRFLCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIDB4MDBjCj4+ICsjZGVmaW5lIENN RFJfQ01EVFJBTlPCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIEJJVCg2KQo+PiArI2RlZmluZSBDTURS X0NNRFNUT1DCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIEJJVCg3KQo+PiArI2RlZmluZSBDTURSX1dB SVRSRVNQX01BU0vCoMKgwqDCoMKgwqDCoCBHRU5NQVNLKDksIDgpCj4+ICsjZGVmaW5lIENNRFJf V0FJVFJFU1BfTk9SU1DCoMKgwqDCoMKgwqDCoCAoMCA8PCA4KQo+PiArI2RlZmluZSBDTURSX1dB SVRSRVNQX1NSU1BfQ1JDwqDCoMKgwqDCoMKgwqAgKDEgPDwgOCkKPj4gKyNkZWZpbmUgQ01EUl9X QUlUUkVTUF9TUlNQwqDCoMKgwqDCoMKgwqAgKDIgPDwgOCkKPj4gKyNkZWZpbmUgQ01EUl9XQUlU UkVTUF9MUlNQX0NSQ8KgwqDCoMKgwqDCoMKgICgzIDw8IDgpCj4+ICsjZGVmaW5lIENNRFJfV0FJ VElOVMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgQklUKDEwKQo+PiArI2RlZmluZSBDTURSX1dBSVRQ RU5EwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBCSVQoMTEpCj4+ICsjZGVmaW5lIENNRFJfQ1BTTUVN wqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBCSVQoMTIpCj4+ICsjZGVmaW5lIENNRFJfRFRIT0xEwqDC oMKgwqDCoMKgwqDCoMKgwqDCoCBCSVQoMTMpCj4+ICsjZGVmaW5lIENNRFJfQk9PVE1PREXCoMKg wqDCoMKgwqDCoMKgwqDCoMKgIEJJVCgxNCkKPj4gKyNkZWZpbmUgQ01EUl9CT09URU7CoMKgwqDC oMKgwqDCoMKgwqDCoMKgIEJJVCgxNSkKPj4gKyNkZWZpbmUgQ01EUl9DTURTVVNQRU5EwqDCoMKg wqDCoMKgwqDCoMKgwqDCoCBCSVQoMTYpCj4+ICsKPj4gKyNkZWZpbmUgU0RNTUNfUkVTUENNRFLC oMKgwqDCoMKgwqDCoMKgwqDCoMKgIDB4MDEwCj4+ICsjZGVmaW5lIFNETU1DX1JFU1AxUsKgwqDC oMKgwqDCoMKgwqDCoMKgwqAgMHgwMTQKPj4gKyNkZWZpbmUgU0RNTUNfUkVTUDJSwqDCoMKgwqDC oMKgwqDCoMKgwqDCoCAweDAxOAo+PiArI2RlZmluZSBTRE1NQ19SRVNQM1LCoMKgwqDCoMKgwqDC oMKgwqDCoMKgIDB4MDFjCj4+ICsjZGVmaW5lIFNETU1DX1JFU1A0UsKgwqDCoMKgwqDCoMKgwqDC oMKgwqAgMHgwMjAKPj4gKwo+PiArI2RlZmluZSBTRE1NQ19EVElNRVLCoMKgwqDCoMKgwqDCoMKg wqDCoMKgIDB4MDI0Cj4+ICsKPj4gKyNkZWZpbmUgU0RNTUNfRExFTlLCoMKgwqDCoMKgwqDCoMKg wqDCoMKgIDB4MDI4Cj4+ICsjZGVmaW5lIERMRU5SX0RBVEFMRU5HSFRfTUFTS8KgwqDCoMKgwqDC oMKgIEdFTk1BU0soMjQsIDApCj4+ICsjZGVmaW5lIERMRU5SX0RBVEFMRU5HSFRfTUFYwqDCoMKg wqDCoMKgwqAgRExFTlJfREFUQUxFTkdIVF9NQVNLCj4+ICsKPj4gKyNkZWZpbmUgU0RNTUNfRENU UkxSwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCAweDAyYwo+PiArI2RlZmluZSBEQ1RSTFJfRFRFTsKg wqDCoMKgwqDCoMKgwqDCoMKgwqAgQklUKDApCj4+ICsjZGVmaW5lIERDVFJMUl9EVERJUsKgwqDC oMKgwqDCoMKgwqDCoMKgwqAgQklUKDEpCj4+ICsjZGVmaW5lIERDVFJMUl9EVE1PREVfTUFTS8Kg wqDCoMKgwqDCoMKgIEdFTk1BU0soMywgMikKPj4gKyNkZWZpbmUgRENUUkxSX0RUTU9ERV9CTE9D S8KgwqDCoMKgwqDCoMKgICgwIDw8IDIpCj4+ICsjZGVmaW5lIERDVFJMUl9EVE1PREVfU0RJT8Kg wqDCoMKgwqDCoMKgICgxIDw8IDIpCj4+ICsjZGVmaW5lIERDVFJMUl9EVE1PREVfTU1DwqDCoMKg wqDCoMKgwqAgKDIgPDwgMikKPj4gKyNkZWZpbmUgRENUUkxSX0RCTE9DS1NJWkVfTUFTS8KgwqDC oMKgwqDCoMKgIEdFTk1BU0soNywgNCkKPj4gKyNkZWZpbmUgRENUUkxSX0RCTE9DS1NJWkVfTUFY wqDCoMKgwqDCoMKgwqAgMTQKPj4gKyNkZWZpbmUgRENUUkxSX1JXU1RBUlTCoMKgwqDCoMKgwqDC oMKgwqDCoMKgIEJJVCg4KQo+PiArI2RlZmluZSBEQ1RSTFJfUldTVE9QwqDCoMKgwqDCoMKgwqDC oMKgwqDCoCBCSVQoOSkKPj4gKyNkZWZpbmUgRENUUkxSX1JXTU9EwqDCoMKgwqDCoMKgwqDCoMKg wqDCoCBCSVQoMTApCj4+ICsjZGVmaW5lIERDVFJMUl9TRElPRU7CoMKgwqDCoMKgwqDCoMKgwqDC oMKgIEJJVCgxMSkKPj4gKyNkZWZpbmUgRENUUkxSX0JPT1RBQ0tFTsKgwqDCoMKgwqDCoMKgIEJJ VCgxMikKPj4gKyNkZWZpbmUgRENUUkxSX0ZJRk9SU1TCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIEJJ VCgxMykKPj4gKwo+PiArI2RlZmluZSBTRE1NQ19EQ05UUsKgwqDCoMKgwqDCoMKgwqDCoMKgwqAg MHgwMzAKPj4gKwo+PiArI2RlZmluZSBTRE1NQ19TVEFSwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCAw eDAzNAo+PiArI2RlZmluZSBTVEFSX0NDUkNGQUlMwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBCSVQo MCkKPj4gKyNkZWZpbmUgU1RBUl9EQ1JDRkFJTMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgQklUKDEp Cj4+ICsjZGVmaW5lIFNUQVJfQ1RJTUVPVVTCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIEJJVCgyKQo+ PiArI2RlZmluZSBTVEFSX0RUSU1FT1VUwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBCSVQoMykKPj4g KyNkZWZpbmUgU1RBUl9UWFVOREVSUsKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgQklUKDQpCj4+ICsj ZGVmaW5lIFNUQVJfUlhPVkVSUsKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgQklUKDUpCj4+ICsjZGVm aW5lIFNUQVJfQ01EUkVORMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgQklUKDYpCj4+ICsjZGVmaW5l IFNUQVJfQ01EU0VOVMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgQklUKDcpCj4+ICsjZGVmaW5lIFNU QVJfREFUQUVORMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgQklUKDgpCj4+ICsjZGVmaW5lIFNUQVJf REhPTETCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIEJJVCg5KQo+PiArI2RlZmluZSBTVEFSX0RCQ0tF TkTCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIEJJVCgxMCkKPj4gKyNkZWZpbmUgU1RBUl9EQUJPUlTC oMKgwqDCoMKgwqDCoMKgwqDCoMKgIEJJVCgxMSkKPj4gKyNkZWZpbmUgU1RBUl9EUFNNQUNUwqDC oMKgwqDCoMKgwqDCoMKgwqDCoCBCSVQoMTIpCj4+ICsjZGVmaW5lIFNUQVJfQ1BTTUFDVMKgwqDC oMKgwqDCoMKgwqDCoMKgwqAgQklUKDEzKQo+PiArI2RlZmluZSBTVEFSX1RYRklGT0hFwqDCoMKg wqDCoMKgwqDCoMKgwqDCoCBCSVQoMTQpCj4+ICsjZGVmaW5lIFNUQVJfVFhGSUZPSEbCoMKgwqDC oMKgwqDCoMKgwqDCoMKgIEJJVCgxNSkKPj4gKyNkZWZpbmUgU1RBUl9UWEZJRk9GwqDCoMKgwqDC oMKgwqDCoMKgwqDCoCBCSVQoMTYpCj4+ICsjZGVmaW5lIFNUQVJfUlhGSUZPRsKgwqDCoMKgwqDC oMKgwqDCoMKgwqAgQklUKDE3KQo+PiArI2RlZmluZSBTVEFSX1RYRklGT0XCoMKgwqDCoMKgwqDC oMKgwqDCoMKgIEJJVCgxOCkKPj4gKyNkZWZpbmUgU1RBUl9SWEZJRk9FwqDCoMKgwqDCoMKgwqDC oMKgwqDCoCBCSVQoMTkpCj4+ICsjZGVmaW5lIFNUQVJfQlVTWUQwwqDCoMKgwqDCoMKgwqDCoMKg wqDCoCBCSVQoMjApCj4+ICsjZGVmaW5lIFNUQVJfQlVTWUQwRU5EwqDCoMKgwqDCoMKgwqDCoMKg wqDCoCBCSVQoMjEpCj4+ICsjZGVmaW5lIFNUQVJfU0RJT0lUwqDCoMKgwqDCoMKgwqDCoMKgwqDC oCBCSVQoMjIpCj4+ICsjZGVmaW5lIFNUQVJfQUNLRkFJTMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAg QklUKDIzKQo+PiArI2RlZmluZSBTVEFSX0FDS1RJTUVPVVTCoMKgwqDCoMKgwqDCoMKgwqDCoMKg IEJJVCgyNCkKPj4gKyNkZWZpbmUgU1RBUl9WU1dFTkTCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIEJJ VCgyNSkKPj4gKyNkZWZpbmUgU1RBUl9DS1NUT1DCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIEJJVCgy NikKPj4gKyNkZWZpbmUgU1RBUl9JRE1BVEXCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIEJJVCgyNykK Pj4gKyNkZWZpbmUgU1RBUl9JRE1BQlRDwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBCSVQoMjgpCj4+ ICsKPj4gKyNkZWZpbmUgU0RNTUNfSUNSwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCAweDAzOAo+PiAr I2RlZmluZSBJQ1JfQ0NSQ0ZBSUxDwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBCSVQoMCkKPj4gKyNk ZWZpbmUgSUNSX0RDUkNGQUlMQ8KgwqDCoMKgwqDCoMKgwqDCoMKgwqAgQklUKDEpCj4+ICsjZGVm aW5lIElDUl9DVElNRU9VVEPCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIEJJVCgyKQo+PiArI2RlZmlu ZSBJQ1JfRFRJTUVPVVRDwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBCSVQoMykKPj4gKyNkZWZpbmUg SUNSX1RYVU5ERVJSQ8KgwqDCoMKgwqDCoMKgwqDCoMKgwqAgQklUKDQpCj4+ICsjZGVmaW5lIElD Ul9SWE9WRVJSQ8KgwqDCoMKgwqDCoMKgwqDCoMKgwqAgQklUKDUpCj4+ICsjZGVmaW5lIElDUl9D TURSRU5EQ8KgwqDCoMKgwqDCoMKgwqDCoMKgwqAgQklUKDYpCj4+ICsjZGVmaW5lIElDUl9DTURT RU5UQ8KgwqDCoMKgwqDCoMKgwqDCoMKgwqAgQklUKDcpCj4+ICsjZGVmaW5lIElDUl9EQVRBRU5E Q8KgwqDCoMKgwqDCoMKgwqDCoMKgwqAgQklUKDgpCj4+ICsjZGVmaW5lIElDUl9ESE9MREPCoMKg wqDCoMKgwqDCoMKgwqDCoMKgIEJJVCg5KQo+PiArI2RlZmluZSBJQ1JfREJDS0VOREPCoMKgwqDC oMKgwqDCoMKgwqDCoMKgIEJJVCgxMCkKPj4gKyNkZWZpbmUgSUNSX0RBQk9SVEPCoMKgwqDCoMKg wqDCoMKgwqDCoMKgIEJJVCgxMSkKPj4gKyNkZWZpbmUgSUNSX0JVU1lEMEVOREPCoMKgwqDCoMKg wqDCoMKgwqDCoMKgIEJJVCgyMSkKPj4gKyNkZWZpbmUgSUNSX1NESU9JVEPCoMKgwqDCoMKgwqDC oMKgwqDCoMKgIEJJVCgyMikKPj4gKyNkZWZpbmUgSUNSX0FDS0ZBSUxDwqDCoMKgwqDCoMKgwqDC oMKgwqDCoCBCSVQoMjMpCj4+ICsjZGVmaW5lIElDUl9BQ0tUSU1FT1VUQ8KgwqDCoMKgwqDCoMKg wqDCoMKgwqAgQklUKDI0KQo+PiArI2RlZmluZSBJQ1JfVlNXRU5EQ8KgwqDCoMKgwqDCoMKgwqDC oMKgwqAgQklUKDI1KQo+PiArI2RlZmluZSBJQ1JfQ0tTVE9QQ8KgwqDCoMKgwqDCoMKgwqDCoMKg wqAgQklUKDI2KQo+PiArI2RlZmluZSBJQ1JfSURNQVRFQ8KgwqDCoMKgwqDCoMKgwqDCoMKgwqAg QklUKDI3KQo+PiArI2RlZmluZSBJQ1JfSURNQUJUQ0PCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIEJJ VCgyOCkKPj4gKyNkZWZpbmUgSUNSX1NUQVRJQ19GTEFHwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCAo KEdFTk1BU0soMjgsIDIxKSkgfCAoR0VOTUFTSygxMSwgCj4+IDApKSkKPj4gKwo+PiArI2RlZmlu ZSBTRE1NQ19NQVNLUsKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgMHgwM2MKPj4gKyNkZWZpbmUgTUFT S1JfQ0NSQ0ZBSUxJRcKgwqDCoMKgwqDCoMKgIEJJVCgwKQo+PiArI2RlZmluZSBNQVNLUl9EQ1JD RkFJTElFwqDCoMKgwqDCoMKgwqAgQklUKDEpCj4+ICsjZGVmaW5lIE1BU0tSX0NUSU1FT1VUSUXC oMKgwqDCoMKgwqDCoCBCSVQoMikKPj4gKyNkZWZpbmUgTUFTS1JfRFRJTUVPVVRJRcKgwqDCoMKg wqDCoMKgIEJJVCgzKQo+PiArI2RlZmluZSBNQVNLUl9UWFVOREVSUklFwqDCoMKgwqDCoMKgwqAg QklUKDQpCj4+ICsjZGVmaW5lIE1BU0tSX1JYT1ZFUlJJRcKgwqDCoMKgwqDCoMKgwqDCoMKgwqAg QklUKDUpCj4+ICsjZGVmaW5lIE1BU0tSX0NNRFJFTkRJRcKgwqDCoMKgwqDCoMKgwqDCoMKgwqAg QklUKDYpCj4+ICsjZGVmaW5lIE1BU0tSX0NNRFNFTlRJRcKgwqDCoMKgwqDCoMKgwqDCoMKgwqAg QklUKDcpCj4+ICsjZGVmaW5lIE1BU0tSX0RBVEFFTkRJRcKgwqDCoMKgwqDCoMKgwqDCoMKgwqAg QklUKDgpCj4+ICsjZGVmaW5lIE1BU0tSX0RIT0xESUXCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIEJJ VCg5KQo+PiArI2RlZmluZSBNQVNLUl9EQkNLRU5ESUXCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIEJJ VCgxMCkKPj4gKyNkZWZpbmUgTUFTS1JfREFCT1JUSUXCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIEJJ VCgxMSkKPj4gKyNkZWZpbmUgTUFTS1JfVFhGSUZPSEVJRcKgwqDCoMKgwqDCoMKgIEJJVCgxNCkK Pj4gKyNkZWZpbmUgTUFTS1JfUlhGSUZPSEZJRcKgwqDCoMKgwqDCoMKgIEJJVCgxNSkKPj4gKyNk ZWZpbmUgTUFTS1JfUlhGSUZPRklFwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBCSVQoMTcpCj4+ICsj ZGVmaW5lIE1BU0tSX1RYRklGT0VJRcKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgQklUKDE4KQo+PiAr I2RlZmluZSBNQVNLUl9CVVNZRDBFTkRJRcKgwqDCoMKgwqDCoMKgIEJJVCgyMSkKPj4gKyNkZWZp bmUgTUFTS1JfU0RJT0lUSUXCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIEJJVCgyMikKPj4gKyNkZWZp bmUgTUFTS1JfQUNLRkFJTElFwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBCSVQoMjMpCj4+ICsjZGVm aW5lIE1BU0tSX0FDS1RJTUVPVVRJRcKgwqDCoMKgwqDCoMKgIEJJVCgyNCkKPj4gKyNkZWZpbmUg TUFTS1JfVlNXRU5ESUXCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIEJJVCgyNSkKPj4gKyNkZWZpbmUg TUFTS1JfQ0tTVE9QSUXCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIEJJVCgyNikKPj4gKyNkZWZpbmUg TUFTS1JfSURNQUJUQ0lFwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBCSVQoMjgpCj4+ICsKPj4gKyNk ZWZpbmUgU0RNTUNfQUNLVElNRVLCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIDB4MDQwCj4+ICsjZGVm aW5lIEFDS1RJTUVSX0FDS1RJTUVfTUFTS8KgwqDCoMKgwqDCoMKgIEdFTk1BU0soMjQsIDApCj4+ ICsKPj4gKyNkZWZpbmUgU0RNTUNfRklGT1LCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIDB4MDgwCj4+ ICsKPj4gKyNkZWZpbmUgU0RNTUNfSURNQUNUUkxSwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCAweDA1 MAo+PiArI2RlZmluZSBJRE1BQ1RSTFJfSURNQUVOwqDCoMKgwqDCoMKgwqAgQklUKDApCj4+ICsj ZGVmaW5lIElETUFDVFJMUl9JRE1BQk1PREXCoMKgwqDCoMKgwqDCoCBCSVQoMSkKPj4gKyNkZWZp bmUgSURNQUNUUkxSX0lETUFCQUNUwqDCoMKgwqDCoMKgwqAgQklUKDIpCj4+ICsKPj4gKyNkZWZp bmUgU0RNTUNfSURNQUJTSVpFUsKgwqDCoMKgwqDCoMKgIDB4MDU0Cj4+ICsjZGVmaW5lIElETUFC U0laRVJfSURNQUJORFRfTUFTS8KgwqDCoCBHRU5NQVNLKDEyLCA1KQo+PiArCj4+ICsjZGVmaW5l IFNETU1DX0lETUFCQVNFMFLCoMKgwqDCoMKgwqDCoCAweDA1OAo+PiArI2RlZmluZSBTRE1NQ19J RE1BQkFTRTFSwqDCoMKgwqDCoMKgwqAgMHgwNWMKPj4gKwo+PiArI2RlZmluZSBTRE1NQ19JUFZS wqDCoMKgwqDCoMKgwqDCoMKgwqDCoCAweDNmYwo+PiArI2RlZmluZSBJUFZSX01JTlJFVl9NQVNL wqDCoMKgwqDCoMKgwqAgR0VOTUFTSygzLCAwKQo+PiArI2RlZmluZSBJUFZSX01BSlJFVl9NQVNL wqDCoMKgwqDCoMKgwqAgR0VOTUFTSyg3LCA0KQo+PiArCj4+ICtlbnVtIHN0bTMyX3NkbW1jX2Nv b2tpZSB7Cj4+ICvCoMKgwqAgQ09PS0lFX1VOTUFQUEVELAo+PiArwqDCoMKgIENPT0tJRV9QUkVf TUFQUEVELMKgwqDCoCAvKiBtYXBwZWQgYnkgcHJlX3JlcSgpIG9mIHN0bTMyICovCj4+ICvCoMKg wqAgQ09PS0lFX01BUFBFRCzCoMKgwqDCoMKgwqDCoCAvKiBtYXBwZWQgYnkgcHJlcGFyZV9kYXRh KCkgb2Ygc3RtMzIgKi8KPj4gK307Cj4+ICsKPj4gK3N0cnVjdCBzZG1tY19zdGF0IHsKPj4gK8Kg wqDCoCB1bnNpZ25lZCBsb25nwqDCoMKgwqDCoMKgwqAgbl9yZXE7Cj4+ICvCoMKgwqAgdW5zaWdu ZWQgbG9uZ8KgwqDCoMKgwqDCoMKgIG5fZGF0YXJlcTsKPj4gK8KgwqDCoCB1bnNpZ25lZCBsb25n wqDCoMKgwqDCoMKgwqAgbl9jdGltZW91dDsKPj4gK8KgwqDCoCB1bnNpZ25lZCBsb25nwqDCoMKg wqDCoMKgwqAgbl9jY3JjZmFpbDsKPj4gK8KgwqDCoCB1bnNpZ25lZCBsb25nwqDCoMKgwqDCoMKg wqAgbl9kdGltZW91dDsKPj4gK8KgwqDCoCB1bnNpZ25lZCBsb25nwqDCoMKgwqDCoMKgwqAgbl9k Y3JjZmFpbDsKPj4gK8KgwqDCoCB1bnNpZ25lZCBsb25nwqDCoMKgwqDCoMKgwqAgbl90eHVuZGVy cnVuOwo+PiArwqDCoMKgIHVuc2lnbmVkIGxvbmfCoMKgwqDCoMKgwqDCoCBuX3J4b3ZlcnJ1bjsK Pj4gK8KgwqDCoCB1bnNpZ25lZCBsb25nwqDCoMKgwqDCoMKgwqAgbmJfZG1hX2VycjsKPj4gK307 Cj4+ICsKPj4gK3N0cnVjdCBzZG1tY19ob3N0IHsKPj4gK8KgwqDCoCB2b2lkIF9faW9tZW3CoMKg wqDCoMKgwqDCoCAqYmFzZTsKPj4gK8KgwqDCoCBzdHJ1Y3QgbW1jX2hvc3TCoMKgwqDCoMKgwqDC oCAqbW1jOwo+PiArwqDCoMKgIHN0cnVjdCBjbGvCoMKgwqDCoMKgwqDCoCAqY2xrOwo+PiArwqDC oMKgIHN0cnVjdCByZXNldF9jb250cm9swqDCoMKgICpyc3Q7Cj4+ICsKPj4gK8KgwqDCoCB1MzLC oMKgwqDCoMKgwqDCoMKgwqDCoMKgIGNsa19yZWdfYWRkOwo+PiArwqDCoMKgIHUzMsKgwqDCoMKg wqDCoMKgwqDCoMKgwqAgcHdyX3JlZ19hZGQ7Cj4+ICsKPj4gK8KgwqDCoCBzdHJ1Y3QgbW1jX3Jl cXVlc3TCoMKgwqAgKm1ycTsKPj4gK8KgwqDCoCBzdHJ1Y3QgbW1jX2NvbW1hbmTCoMKgwqAgKmNt ZDsKPj4gK8KgwqDCoCBzdHJ1Y3QgbW1jX2RhdGHCoMKgwqDCoMKgwqDCoCAqZGF0YTsKPj4gK8Kg wqDCoCBzdHJ1Y3QgbW1jX2NvbW1hbmTCoMKgwqAgc3RvcF9hYm9ydDsKPj4gK8KgwqDCoCBib29s wqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBkcHNtX2Fib3J0Owo+PiArCj4+ICvCoMKgwqAgLyogcHJv dGVjdCBob3N0IHJlZ2lzdGVycyBhY2Nlc3MgKi8KPj4gK8KgwqDCoCBzcGlubG9ja190wqDCoMKg wqDCoMKgwqAgbG9jazsKPj4gKwo+PiArwqDCoMKgIHVuc2lnbmVkIGludMKgwqDCoMKgwqDCoMKg IHNkbW1jY2xrOwo+PiArwqDCoMKgIHVuc2lnbmVkIGludMKgwqDCoMKgwqDCoMKgIHNkbW1jX2Nr Owo+PiArCj4+ICvCoMKgwqAgdTMywqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBzaXplOwo+PiArCj4+ ICvCoMKgwqAgdTMywqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBpcF92ZXI7Cj4+ICvCoMKgwqAgc3Ry dWN0IHNkbW1jX3N0YXTCoMKgwqAgc3RhdDsKPj4gK307Cj4+Cj4gCj4gCkJSCkx1ZG8KCl9fX19f X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fCmxpbnV4LWFybS1rZXJu ZWwgbWFpbGluZyBsaXN0CmxpbnV4LWFybS1rZXJuZWxAbGlzdHMuaW5mcmFkZWFkLm9yZwpodHRw Oi8vbGlzdHMuaW5mcmFkZWFkLm9yZy9tYWlsbWFuL2xpc3RpbmZvL2xpbnV4LWFybS1rZXJuZWwK From mboxrd@z Thu Jan 1 00:00:00 1970 From: ludovic.barre@st.com (Ludovic BARRE) Date: Mon, 26 Feb 2018 11:35:35 +0100 Subject: [PATCH 2/5] mmc: add stm32 sdmmc controller driver In-Reply-To: References: <1518701697-14242-1-git-send-email-ludovic.Barre@st.com> <1518701697-14242-3-git-send-email-ludovic.Barre@st.com> Message-ID: <0b7a72c9-a03f-e313-b675-d4d932735ca5@st.com> To: linux-arm-kernel@lists.infradead.org List-Id: linux-arm-kernel.lists.infradead.org hi Shawn thanks for your review On 02/22/2018 05:20 PM, Shawn Lin wrote: > On 2018/2/15 21:34, Ludovic Barre wrote: >> From: Ludovic Barre >> > > ... > >> + >> +static ssize_t stm32_sdmmc_stat_reset(struct file *filp, >> +????????????????????? const char __user *ubuf, >> +????????????????????? size_t count, loff_t *ppos) >> +{ >> +??? struct seq_file *seqf = filp->private_data; >> +??? struct sdmmc_host *host = seqf->private; >> + >> +??? mutex_lock(&seqf->lock); >> +??? memset(&host->stat, 0, sizeof(host->stat)); >> +??? mutex_unlock(&seqf->lock); >> + >> +??? return count; >> +} >> + >> +static int stm32_sdmmc_stat_open(struct inode *inode, struct file *file) >> +{ >> +??? return single_open(file, stm32_sdmmc_stat_show, inode->i_private); >> +} >> + >> +static const struct file_operations stm32_sdmmc_stat_fops = { >> +??? .owner??????? = THIS_MODULE, >> +??? .open??????? = stm32_sdmmc_stat_open, >> +??? .read??????? = seq_read, >> +??? .write??????? = stm32_sdmmc_stat_reset, >> +??? .llseek??????? = seq_lseek, >> +??? .release??? = single_release, >> +}; >> + > > Could you simply use DEFINE_SHOW_ATTRIBUTE(stm32_sdmmc_stat) instead? DEFINE_SHOW_ATTRIBUTE has no ".write" file_operations. It's very useful to reset the statistic structure. So if it's possible to keep this feature, I would prefer. > >> +static void stm32_sdmmc_stat_init(struct sdmmc_host *host) >> +{ >> +??? struct mmc_host??? *mmc = host->mmc; >> +??? struct dentry *root; >> + >> +??? root = mmc->debugfs_root; >> +??? if (!root) >> +??????? return; >> + >> +??? if (!debugfs_create_file("stat", 0600, root, host, >> +???????????????? &stm32_sdmmc_stat_fops)) >> +??????? dev_err(mmc_dev(host->mmc), "failed to initialize debugfs\n"); >> +} >> + >> +#define STAT_INC(stat) ((stat)++) >> +#else >> +static void stm32_sdmmc_stat_init(struct sdmmc_host *host) >> +{ >> +} >> + >> +#define STAT_INC(stat) >> +#endif >> + >> +static inline u32 enable_imask(struct sdmmc_host *host, u32 imask) >> +{ >> +??? u32 newmask; >> + >> +??? newmask = readl_relaxed(host->base + SDMMC_MASKR); >> +??? newmask |= imask; >> + >> +??? dev_vdbg(mmc_dev(host->mmc), "mask:%#x\n", newmask); >> + >> +??? writel_relaxed(newmask, host->base + SDMMC_MASKR); >> + >> +??? return newmask; >> +} >> + > > I don't see you use the return value eleswhere, perhaps > remove it? yes your right, I remove the return. > >> +static inline u32 disable_imask(struct sdmmc_host *host, u32 imask) >> +{ >> +??? u32 newmask; >> + >> +??? newmask = readl_relaxed(host->base + SDMMC_MASKR); >> +??? newmask &= ~imask; >> + >> +??? dev_vdbg(mmc_dev(host->mmc), "mask:%#x\n", newmask); >> + >> +??? writel_relaxed(newmask, host->base + SDMMC_MASKR); >> + >> +??? return newmask; >> +} >> + > > Ditto? yes your right, I remove the return. > >> +static inline void clear_imask(struct sdmmc_host *host) >> +{ >> +??? u32 mask = readl_relaxed(host->base + SDMMC_MASKR); >> + >> +??? /* preserve the SDIO IRQ mask state */ >> +??? mask &= MASKR_SDIOITIE; >> + >> +??? dev_vdbg(mmc_dev(host->mmc), "mask:%#x\n", mask); >> + >> +??? writel_relaxed(mask, host->base + SDMMC_MASKR); >> +} >> + > > Not clear to me why couldn't you use : > imask = 0xffffffff ^ MASKR_SDIOITIE; > disable_imask(imask) In fact, I wish keep SDIOITIE enabled if and only if the SDIOTIE was already enabled (so SDIOITIE mask is not always set) > >> +static int stm32_sdmmc_card_busy(struct mmc_host *mmc) >> +{ >> +??? struct sdmmc_host *host = mmc_priv(mmc); >> +??? unsigned long flags; >> +??? u32 status; >> + >> +??? spin_lock_irqsave(&host->lock, flags); >> +??? status = readl_relaxed(host->base + SDMMC_STAR); >> +??? spin_unlock_irqrestore(&host->lock, flags); >> + >> +??? return !!(status & STAR_BUSYD0); >> +} >> + > > I don't think you need to hold the lock here. just a protection with "stm32_sdmmc_irq" which could modify status value > >> +static void stm32_sdmmc_request_end(struct sdmmc_host *host, >> +??????????????????? struct mmc_request *mrq) >> +{ >> +??? writel_relaxed(0, host->base + SDMMC_CMDR); >> +??? writel_relaxed(ICR_STATIC_FLAG, host->base + SDMMC_ICR); >> + >> +??? host->mrq = NULL; >> +??? host->cmd = NULL; >> +??? host->data = NULL; >> + >> +??? clear_imask(host); >> + >> +??? mmc_request_done(host->mmc, mrq); >> +} >> + >> +static void stm32_sdmmc_pwroff(struct sdmmc_host *host) >> +{ >> +??? /* Only a reset could disable sdmmc */ >> +??? reset_control_assert(host->rst); >> +??? udelay(2); >> +??? reset_control_deassert(host->rst); >> + >> +??? /* >> +???? * Set the SDMMC in Power-cycle state. This will make that the >> +???? * SDMMC_D[7:0], SDMMC_CMD and SDMMC_CK are driven low, >> +???? * to prevent the Card from being powered through the signal lines. >> +???? */ >> +??? writel_relaxed(POWERCTRL_CYC | host->pwr_reg_add, >> +?????????????? host->base + SDMMC_POWER); >> +} >> + >> +static void stm32_sdmmc_pwron(struct sdmmc_host *host) >> +{ >> +??? /* >> +???? * After a power-cycle state, we must set the SDMMC in Power-off. >> +???? * The SDMMC_D[7:0], SDMMC_CMD and SDMMC_CK are driven high. >> +???? * Then we can set the SDMMC to Power-on state >> +???? */ >> +??? writel_relaxed(POWERCTRL_OFF | host->pwr_reg_add, >> +?????????????? host->base + SDMMC_POWER); >> +??? mdelay(1); >> +??? writel_relaxed(POWERCTRL_ON | host->pwr_reg_add, >> +?????????????? host->base + SDMMC_POWER); >> +} >> + >> +static void stm32_sdmmc_set_clkreg(struct sdmmc_host *host, struct >> mmc_ios *ios) >> +{ >> +??? u32 desired = ios->clock; >> +??? u32 clk = 0; >> + >> +??? /* >> +???? * sdmmc_ck = sdmmcclk/(2*clkdiv) >> +???? * clkdiv 0 => bypass >> +???? */ >> +??? if (desired) { >> +??????? if (desired >= host->sdmmcclk) { >> +??????????? clk = 0; >> +??????????? host->sdmmc_ck = host->sdmmcclk; >> +??????? } else { >> +??????????? clk = DIV_ROUND_UP(host->sdmmcclk, 2 * desired); >> +??????????? if (clk > CLKCR_CLKDIV_MAX) >> +??????????????? clk = CLKCR_CLKDIV_MAX; >> + > > Don't you need to check if the desired clock rate is the > same with the current clock rate? I'd rather not. I should save the prescaler into variable and manage this. I will add a dev_warn if clk > CLKCR_CLKDIV_MAX, because if it's happen the card is over clocked. > >> +??????????? host->sdmmc_ck = host->sdmmcclk / (2 * clk); >> +??????? } >> +??? } >> + >> +??? if (ios->bus_width == MMC_BUS_WIDTH_4) >> +??????? clk |= CLKCR_WIDBUS_4; >> +??? if (ios->bus_width == MMC_BUS_WIDTH_8) >> +??????? clk |= CLKCR_WIDBUS_8; >> + > > also it looks wired to me you set bus width in a function called > stm32_sdmmc_set_clkreg which seems do the clock setting. In fact, this function regroup settings of clk register, and there are buswith, clk, hardware flow control... > >> +??? clk |= CLKCR_HWFC_EN; >> + >> +??? writel_relaxed(clk | host->clk_reg_add, host->base + SDMMC_CLKCR); >> +} >> + >> +static void stm32_sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios >> *ios) >> +{ >> +??? struct sdmmc_host *host = mmc_priv(mmc); >> + >> +??? stm32_sdmmc_set_clkreg(host, ios); >> + >> +??? switch (ios->power_mode) { >> +??? case MMC_POWER_OFF: >> +??????? if (!IS_ERR(mmc->supply.vmmc)) >> +??????????? mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); >> + >> +??????? stm32_sdmmc_pwroff(host); >> +??????? return; >> +??? case MMC_POWER_UP: >> +??????? if (!IS_ERR(mmc->supply.vmmc)) >> +??????????? mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd); >> +??????? break; >> +??? case MMC_POWER_ON: >> +??????? stm32_sdmmc_pwron(host); >> +??????? break; >> +??? } >> +} >> + >> +static int stm32_sdmmc_validate_data(struct sdmmc_host *host, >> +???????????????????? struct mmc_data *data, int cookie) >> +{ >> +??? int n_elem; >> + >> +??? if (!data || data->host_cookie == COOKIE_PRE_MAPPED) >> +??????? return 0; >> + >> +??? if (!is_power_of_2(data->blksz)) { >> +??????? dev_err(mmc_dev(host->mmc), >> +??????????? "unsupported block size (%d bytes)\n", data->blksz); >> +??????? return -EINVAL; >> +??? } >> + >> +??? if (data->sg->offset & 3 || data->sg->length & 3) { >> +??????? dev_err(mmc_dev(host->mmc), >> +??????????? "unaligned scatterlist: ofst:%x length:%d\n", >> +??????????? data->sg->offset, data->sg->length); >> +??????? return -EINVAL; >> +??? } >> + >> +??? n_elem = dma_map_sg(mmc_dev(host->mmc), >> +??????????????? data->sg, >> +??????????????? data->sg_len, >> +??????????????? mmc_get_dma_dir(data)); >> + >> +??? if (n_elem != 1) { >> +??????? dev_err(mmc_dev(host->mmc), "nr segment >1 not supported\n"); > > I don't get this check. Your IDMA can't do scatter lists, but > n_elem == 0 means failed to do dma_map_sg. dma_map_sg return the number of elements mapped or 0 if error. like the max_segs is set in the probe, I will remove the overprotection on number of elements. So I will replace by if (!n_elem) { dev_err(mmc_dev(host->mmc), "dma_map_sg failed\n"); return -EINVAL; } > >> +??????? return -EINVAL; >> +??? } >> + >> +??? data->host_cookie = cookie; >> + >> +??? return 0; >> +} >> + >> +static void stm32_sdmmc_start_data(struct sdmmc_host *host, >> +?????????????????? struct mmc_data *data) >> +{ >> +??? u32 datactrl, timeout, imask, idmactrl; >> +??? unsigned long long clks; >> + >> +??? dev_dbg(mmc_dev(host->mmc), "blksz %d blks %d flags %08x\n", >> +??????? data->blksz, data->blocks, data->flags); >> + >> +??? STAT_INC(host->stat.n_datareq); >> +??? host->data = data; >> +??? host->size = data->blksz * data->blocks; >> +??? data->bytes_xfered = 0; >> + >> +??? clks = (unsigned long long)data->timeout_ns * host->sdmmc_ck; >> +??? do_div(clks, NSEC_PER_SEC); >> +??? timeout = data->timeout_clks + (unsigned int)clks; >> + >> +??? writel_relaxed(timeout, host->base + SDMMC_DTIMER); >> +??? writel_relaxed(host->size, host->base + SDMMC_DLENR); >> + >> +??? datactrl = FIELD_PREP(DCTRLR_DBLOCKSIZE_MASK, ilog2(data->blksz)); >> + >> +??? if (data->flags & MMC_DATA_READ) { >> +??????? datactrl |= DCTRLR_DTDIR; >> +??????? imask = MASKR_RXOVERRIE; >> +??? } else { >> +??????? imask = MASKR_TXUNDERRIE; >> +??? } >> + >> +??? if (host->mmc->card && mmc_card_sdio(host->mmc->card)) >> +??????? datactrl |= DCTRLR_SDIOEN | DCTRLR_DTMODE_SDIO; >> + >> +??? idmactrl = IDMACTRLR_IDMAEN; >> + >> +??? writel_relaxed(sg_dma_address(data->sg), >> +?????????????? host->base + SDMMC_IDMABASE0R); >> +??? writel_relaxed(idmactrl, host->base + SDMMC_IDMACTRLR); >> + >> +??? imask |= MASKR_DATAENDIE | MASKR_DTIMEOUTIE | MASKR_DCRCFAILIE; >> +??? enable_imask(host, imask); >> + >> +??? writel_relaxed(datactrl, host->base + SDMMC_DCTRLR); >> +} >> + >> +static void stm32_sdmmc_start_cmd(struct sdmmc_host *host, >> +????????????????? struct mmc_command *cmd, u32 c) >> +{ >> +??? void __iomem *base = host->base; > > Not need to introduce this variable. OK > >> +??? u32 imsk; >> + >> +??? dev_dbg(mmc_dev(host->mmc), "op %u arg %08x flags %08x\n", >> +??????? cmd->opcode, cmd->arg, cmd->flags); >> + >> +??? STAT_INC(host->stat.n_req); >> + >> +??? if (readl_relaxed(base + SDMMC_CMDR) & CMDR_CPSMEM) >> +??????? writel_relaxed(0, base + SDMMC_CMDR); >> + >> +??? c |= cmd->opcode | CMDR_CPSMEM; >> +??? if (cmd->flags & MMC_RSP_PRESENT) { >> +??????? imsk = MASKR_CMDRENDIE | MASKR_CTIMEOUTIE; >> +??????? if (cmd->flags & MMC_RSP_CRC) >> +??????????? imsk |= MASKR_CCRCFAILIE; >> + >> +??????? if (cmd->flags & MMC_RSP_136) >> +??????????? c |= CMDR_WAITRESP_LRSP_CRC; >> +??????? else if (cmd->flags & MMC_RSP_CRC) >> +??????????? c |= CMDR_WAITRESP_SRSP_CRC; >> +??????? else >> +??????????? c |= CMDR_WAITRESP_SRSP; >> +??? } else { >> +??????? c &= ~CMDR_WAITRESP_MASK; >> +??????? imsk = MASKR_CMDSENTIE; >> +??? } >> + >> +??? host->cmd = cmd; >> + >> +??? enable_imask(host, imsk); >> + >> +??? writel_relaxed(cmd->arg, base + SDMMC_ARGR); >> +??? writel_relaxed(c, base + SDMMC_CMDR); >> +} >> + >> +static void stm32_sdmmc_cmd_irq(struct sdmmc_host *host, u32 status) >> +{ >> +??? struct mmc_command *cmd = host->cmd; >> + >> +??? if (!cmd) >> +??????? return; >> + >> +??? host->cmd = NULL; >> + >> +??? if (status & STAR_CTIMEOUT) { >> +??????? STAT_INC(host->stat.n_ctimeout); >> +??????? cmd->error = -ETIMEDOUT; >> +??????? host->dpsm_abort = true; >> +??? } else if (status & STAR_CCRCFAIL && cmd->flags & MMC_RSP_CRC) { >> +??????? STAT_INC(host->stat.n_ccrcfail); >> +??????? cmd->error = -EILSEQ; >> +??????? host->dpsm_abort = true; >> +??? } else if (status & STAR_CMDREND && cmd->flags & MMC_RSP_PRESENT) { >> +??????? cmd->resp[0] = readl_relaxed(host->base + SDMMC_RESP1R); >> +??????? cmd->resp[1] = readl_relaxed(host->base + SDMMC_RESP2R); >> +??????? cmd->resp[2] = readl_relaxed(host->base + SDMMC_RESP3R); >> +??????? cmd->resp[3] = readl_relaxed(host->base + SDMMC_RESP4R); >> +??? } >> + >> +??? if (!host->data) >> +??????? stm32_sdmmc_request_end(host, host->mrq); >> +} >> + >> +static void stm32_sdmmc_data_irq(struct sdmmc_host *host, u32 status) >> +{ >> +??? struct mmc_data??? *data = host->data; >> +??? struct mmc_command *stop = &host->stop_abort; >> + >> +??? if (!data) >> +??????? return; >> + >> +??? if (status & STAR_DCRCFAIL) { >> +??????? STAT_INC(host->stat.n_dcrcfail); >> +??????? data->error = -EILSEQ; >> +??????? if (readl_relaxed(host->base + SDMMC_DCNTR)) >> +??????????? host->dpsm_abort = true; >> +??? } else if (status & STAR_DTIMEOUT) { >> +??????? STAT_INC(host->stat.n_dtimeout); >> +??????? data->error = -ETIMEDOUT; >> +??????? host->dpsm_abort = true; >> +??? } else if (status & STAR_TXUNDERR) { >> +??????? STAT_INC(host->stat.n_txunderrun); >> +??????? data->error = -EIO; >> +??????? host->dpsm_abort = true; >> +??? } else if (status & STAR_RXOVERR) { >> +??????? STAT_INC(host->stat.n_rxoverrun); >> +??????? data->error = -EIO; >> +??????? host->dpsm_abort = true; >> +??? } >> + >> +??? if (status & STAR_DATAEND || data->error || host->dpsm_abort) { >> +??????? host->data = NULL; >> + >> +??????? writel_relaxed(0, host->base + SDMMC_IDMACTRLR); >> + >> +??????? if (!data->error) >> +??????????? data->bytes_xfered = data->blocks * data->blksz; >> + >> +??????? /* >> +???????? * To stop Data Path State Machine, a stop_transmission command >> +???????? * shall be send on cmd or data errors of single, multi, >> +???????? * pre-defined block and stream request. >> +???????? */ >> +??????? if (host->dpsm_abort && !data->stop) { >> +??????????? memset(stop, 0, sizeof(struct mmc_command)); >> +??????????? stop->opcode = MMC_STOP_TRANSMISSION; >> +??????????? stop->arg = 0; >> +??????????? stop->flags = MMC_RSP_R1B | MMC_CMD_AC; >> +??????????? data->stop = stop; >> +??????? } >> + >> +??????? disable_imask(host, MASKR_RXOVERRIE | MASKR_TXUNDERRIE >> +????????????????? | MASKR_DCRCFAILIE | MASKR_DATAENDIE >> +????????????????? | MASKR_DTIMEOUTIE); >> + >> +??????? if (!data->stop) >> +??????????? stm32_sdmmc_request_end(host, data->mrq); >> +??????? else >> +??????????? stm32_sdmmc_start_cmd(host, data->stop, CMDR_CMDSTOP); >> +??? } >> +} >> + >> +static irqreturn_t stm32_sdmmc_irq(int irq, void *dev_id) >> +{ >> +??? struct sdmmc_host *host = dev_id; >> +??? u32 status; >> + >> +??? spin_lock(&host->lock); >> + >> +??? status = readl_relaxed(host->base + SDMMC_STAR); >> +??? dev_dbg(mmc_dev(host->mmc), "irq sta:%#x\n", status); >> +??? writel_relaxed(status & ICR_STATIC_FLAG, host->base + SDMMC_ICR); >> + >> +??? stm32_sdmmc_cmd_irq(host, status); >> +??? stm32_sdmmc_data_irq(host, status); >> + >> +??? spin_unlock(&host->lock); >> + >> +??? return IRQ_HANDLED; >> +} >> + >> +static void stm32_sdmmc_pre_req(struct mmc_host *mmc, struct >> mmc_request *mrq) >> +{ >> +??? struct sdmmc_host *host = mmc_priv(mmc); >> +??? struct mmc_data *data = mrq->data; >> + >> +??? if (!data) >> +??????? return; >> + >> +??? /* This data might be unmapped at this time */ >> +??? data->host_cookie = COOKIE_UNMAPPED; >> + >> +??? if (!stm32_sdmmc_validate_data(host, mrq->data, COOKIE_PRE_MAPPED)) >> +??????? data->host_cookie = COOKIE_UNMAPPED; >> +} >> + >> +static void stm32_sdmmc_post_req(struct mmc_host *mmc, struct >> mmc_request *mrq, >> +???????????????? int err) >> +{ >> +??? struct sdmmc_host *host = mmc_priv(mmc); >> +??? struct mmc_data *data = mrq->data; >> + >> +??? if (!data) >> +??????? return; >> + >> +??? if (data->host_cookie != COOKIE_UNMAPPED) >> +??????? dma_unmap_sg(mmc_dev(host->mmc), >> +???????????????? data->sg, >> +???????????????? data->sg_len, >> +???????????????? mmc_get_dma_dir(data)); >> + >> +??? data->host_cookie = COOKIE_UNMAPPED; >> +} >> + >> +static void stm32_sdmmc_request(struct mmc_host *mmc, struct >> mmc_request *mrq) >> +{ >> +??? unsigned int cmdat = 0; >> +??? struct sdmmc_host *host = mmc_priv(mmc); >> +??? unsigned long flags; >> + >> +??? mrq->cmd->error = stm32_sdmmc_validate_data(host, mrq->data, >> +??????????????????????????? COOKIE_MAPPED); >> +??? if (mrq->cmd->error) { >> +??????? mmc_request_done(mmc, mrq); >> +??????? return; >> +??? } >> + >> +??? spin_lock_irqsave(&host->lock, flags); >> + >> +??? host->mrq = mrq; >> + >> +??? if (mrq->data) { >> +??????? host->dpsm_abort = false; >> +??????? stm32_sdmmc_start_data(host, mrq->data); >> +??????? cmdat |= CMDR_CMDTRANS; >> +??? } >> + >> +??? stm32_sdmmc_start_cmd(host, mrq->cmd, cmdat); >> + >> +??? spin_unlock_irqrestore(&host->lock, flags); >> +} >> + >> +static struct mmc_host_ops stm32_sdmmc_ops = { >> +??? .request??? = stm32_sdmmc_request, >> +??? .pre_req??? = stm32_sdmmc_pre_req, >> +??? .post_req??? = stm32_sdmmc_post_req, >> +??? .set_ios??? = stm32_sdmmc_set_ios, >> +??? .get_cd??????? = mmc_gpio_get_cd, >> +??? .card_busy??? = stm32_sdmmc_card_busy, >> +}; >> + >> +static const struct of_device_id stm32_sdmmc_match[] = { >> +??? { .compatible = "st,stm32h7-sdmmc",}, >> +??? {}, >> +}; >> +MODULE_DEVICE_TABLE(of, stm32_sdmmc_match); >> + >> +static int stm32_sdmmc_of_parse(struct device_node *np, struct >> mmc_host *mmc) >> +{ >> +??? struct sdmmc_host *host = mmc_priv(mmc); >> +??? int ret = mmc_of_parse(mmc); >> + >> +??? if (ret) >> +??????? return ret; >> + >> +??? if (of_get_property(np, "st,negedge", NULL)) >> +??????? host->clk_reg_add |= CLKCR_NEGEDGE; >> +??? if (of_get_property(np, "st,dirpol", NULL)) >> +??????? host->pwr_reg_add |= POWER_DIRPOL; >> +??? if (of_get_property(np, "st,pin-ckin", NULL)) >> +??????? host->clk_reg_add |= CLKCR_SELCLKRX_CKIN; >> + > > Use device_property_present? OK, thanks > >> +??? return 0; >> +} >> + >> +static int stm32_sdmmc_probe(struct platform_device *pdev) >> +{ >> +??? struct device_node *np = pdev->dev.of_node; >> +??? struct sdmmc_host *host; >> +??? struct mmc_host *mmc; >> +??? struct resource *res; >> +??? int irq, ret; >> + >> +??? if (!np) { >> +??????? dev_err(&pdev->dev, "No DT found\n"); >> +??????? return -EINVAL; >> +??? } >> + >> +??? res = platform_get_resource(pdev, IORESOURCE_MEM, 0); >> +??? irq = platform_get_irq(pdev, 0); >> +??? if (irq < 0) >> +??????? return -EINVAL; >> + >> +??? mmc = mmc_alloc_host(sizeof(struct sdmmc_host), &pdev->dev); >> +??? if (!mmc) >> +??????? return -ENOMEM; >> + >> +??? host = mmc_priv(mmc); >> +??? host->mmc = mmc; >> +??? platform_set_drvdata(pdev, mmc); >> + >> +??? host->base = devm_ioremap_resource(&pdev->dev, res); >> +??? if (IS_ERR(host->base)) { >> +??????? ret = PTR_ERR(host->base); >> +??????? goto host_free; >> +??? } >> + >> +??? writel_relaxed(0, host->base + SDMMC_MASKR); >> +??? writel_relaxed(~0UL, host->base + SDMMC_ICR); >> + >> +??? ret = devm_request_irq(&pdev->dev, irq, stm32_sdmmc_irq, >> IRQF_SHARED, >> +?????????????????? DRIVER_NAME " (cmd)", host); >> +??? if (ret) >> +??????? goto host_free; >> + >> +??? host->clk = devm_clk_get(&pdev->dev, NULL); >> +??? if (IS_ERR(host->clk)) { >> +??????? ret = PTR_ERR(host->clk); >> +??????? goto host_free; >> +??? } >> + >> +??? ret = clk_prepare_enable(host->clk); >> +??? if (ret) >> +??????? goto host_free; >> + >> +??? host->sdmmcclk = clk_get_rate(host->clk); >> +??? mmc->f_min = DIV_ROUND_UP(host->sdmmcclk, 2 * CLKCR_CLKDIV_MAX); >> +??? mmc->f_max = host->sdmmcclk; >> + >> +??? ret = stm32_sdmmc_of_parse(np, mmc); >> +??? if (ret) >> +??????? goto clk_disable; >> + >> +??? host->rst = devm_reset_control_get(&pdev->dev, NULL); >> +??? if (IS_ERR(host->rst)) { >> +??????? ret = PTR_ERR(host->rst); >> +??????? goto clk_disable; >> +??? } >> + >> +??? stm32_sdmmc_pwroff(host); >> + >> +??? /* Get regulators and the supported OCR mask */ >> +??? ret = mmc_regulator_get_supply(mmc); >> +??? if (ret == -EPROBE_DEFER) >> +??????? goto clk_disable; >> + >> +??? if (!mmc->ocr_avail) >> +??????? mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; >> + >> +??? mmc->ops = &stm32_sdmmc_ops; >> + >> +??? /* IDMA cannot do scatter lists */ >> +??? mmc->max_segs = 1; >> +??? mmc->max_req_size = DLENR_DATALENGHT_MAX; >> +??? mmc->max_seg_size = mmc->max_req_size; >> +??? mmc->max_blk_size = 1 << DCTRLR_DBLOCKSIZE_MAX; >> + >> +??? /* >> +???? * Limit the number of blocks transferred so that we don't overflow >> +???? * the maximum request size. >> +???? */ >> +??? mmc->max_blk_count = mmc->max_req_size >> DCTRLR_DBLOCKSIZE_MAX; >> + >> +??? spin_lock_init(&host->lock); >> + >> +??? ret = mmc_add_host(mmc); >> +??? if (ret) >> +??????? goto clk_disable; >> + >> +??? stm32_sdmmc_stat_init(host); >> + >> +??? host->ip_ver = readl_relaxed(host->base + SDMMC_IPVR); >> +??? dev_info(&pdev->dev, "%s: rev:%ld.%ld irq:%d\n", >> +???????? mmc_hostname(mmc), >> +???????? FIELD_GET(IPVR_MAJREV_MASK, host->ip_ver), >> +???????? FIELD_GET(IPVR_MINREV_MASK, host->ip_ver), irq); >> + >> +??? return 0; >> + >> +clk_disable: >> +??? clk_disable_unprepare(host->clk); >> +host_free: >> +??? mmc_free_host(mmc); >> +??? return ret; >> +} >> + >> +static int stm32_sdmmc_remove(struct platform_device *pdev) >> +{ >> +??? struct mmc_host *mmc = platform_get_drvdata(pdev); >> +??? struct sdmmc_host *host = mmc_priv(mmc); >> + >> +??? /* Debugfs stuff is cleaned up by mmc core */ >> +??? mmc_remove_host(mmc); >> +??? clk_disable_unprepare(host->clk); >> +??? mmc_free_host(mmc); >> + >> +??? return 0; >> +} >> + >> +static struct platform_driver stm32_sdmmc_driver = { >> +??? .probe??????? = stm32_sdmmc_probe, >> +??? .remove??????? = stm32_sdmmc_remove, >> +??? .driver??? = { >> +??????? .name??? = DRIVER_NAME, >> +??????? .of_match_table = stm32_sdmmc_match, >> +??? }, >> +}; >> + >> +module_platform_driver(stm32_sdmmc_driver); >> + >> +MODULE_DESCRIPTION("STMicroelectronics STM32 MMC/SD Card Interface >> driver"); >> +MODULE_LICENSE("GPL v2"); >> +MODULE_AUTHOR("Ludovic Barre "); >> diff --git a/drivers/mmc/host/stm32-sdmmc.h >> b/drivers/mmc/host/stm32-sdmmc.h >> new file mode 100644 >> index 0000000..e39578e >> --- /dev/null >> +++ b/drivers/mmc/host/stm32-sdmmc.h >> @@ -0,0 +1,220 @@ >> +/* SPDX-License-Identifier: GPL-2.0 */ >> +/* >> + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved >> + * Author: Ludovic Barre for STMicroelectronics. >> + */ >> +#define SDMMC_POWER??????????? 0x000 >> +#define POWERCTRL_MASK??????????? GENMASK(1, 0) >> +#define POWERCTRL_OFF??????????? 0x00 >> +#define POWERCTRL_CYC??????????? 0x02 >> +#define POWERCTRL_ON??????????? 0x03 >> +#define POWER_VSWITCH??????????? BIT(2) >> +#define POWER_VSWITCHEN??????????? BIT(3) >> +#define POWER_DIRPOL??????????? BIT(4) >> + >> +#define SDMMC_CLKCR??????????? 0x004 >> +#define CLKCR_CLKDIV_MASK??????? GENMASK(9, 0) >> +#define CLKCR_CLKDIV_MAX??????? CLKCR_CLKDIV_MASK >> +#define CLKCR_PWRSAV??????????? BIT(12) >> +#define CLKCR_WIDBUS_4??????????? BIT(14) >> +#define CLKCR_WIDBUS_8??????????? BIT(15) >> +#define CLKCR_NEGEDGE??????????? BIT(16) >> +#define CLKCR_HWFC_EN??????????? BIT(17) >> +#define CLKCR_DDR??????????? BIT(18) >> +#define CLKCR_BUSSPEED??????????? BIT(19) >> +#define CLKCR_SELCLKRX_MASK??????? GENMASK(21, 20) >> +#define CLKCR_SELCLKRX_CK??????? (0 << 20) >> +#define CLKCR_SELCLKRX_CKIN??????? (1 << 20) >> +#define CLKCR_SELCLKRX_FBCK??????? (2 << 20) >> + >> +#define SDMMC_ARGR??????????? 0x008 >> + >> +#define SDMMC_CMDR??????????? 0x00c >> +#define CMDR_CMDTRANS??????????? BIT(6) >> +#define CMDR_CMDSTOP??????????? BIT(7) >> +#define CMDR_WAITRESP_MASK??????? GENMASK(9, 8) >> +#define CMDR_WAITRESP_NORSP??????? (0 << 8) >> +#define CMDR_WAITRESP_SRSP_CRC??????? (1 << 8) >> +#define CMDR_WAITRESP_SRSP??????? (2 << 8) >> +#define CMDR_WAITRESP_LRSP_CRC??????? (3 << 8) >> +#define CMDR_WAITINT??????????? BIT(10) >> +#define CMDR_WAITPEND??????????? BIT(11) >> +#define CMDR_CPSMEM??????????? BIT(12) >> +#define CMDR_DTHOLD??????????? BIT(13) >> +#define CMDR_BOOTMODE??????????? BIT(14) >> +#define CMDR_BOOTEN??????????? BIT(15) >> +#define CMDR_CMDSUSPEND??????????? BIT(16) >> + >> +#define SDMMC_RESPCMDR??????????? 0x010 >> +#define SDMMC_RESP1R??????????? 0x014 >> +#define SDMMC_RESP2R??????????? 0x018 >> +#define SDMMC_RESP3R??????????? 0x01c >> +#define SDMMC_RESP4R??????????? 0x020 >> + >> +#define SDMMC_DTIMER??????????? 0x024 >> + >> +#define SDMMC_DLENR??????????? 0x028 >> +#define DLENR_DATALENGHT_MASK??????? GENMASK(24, 0) >> +#define DLENR_DATALENGHT_MAX??????? DLENR_DATALENGHT_MASK >> + >> +#define SDMMC_DCTRLR??????????? 0x02c >> +#define DCTRLR_DTEN??????????? BIT(0) >> +#define DCTRLR_DTDIR??????????? BIT(1) >> +#define DCTRLR_DTMODE_MASK??????? GENMASK(3, 2) >> +#define DCTRLR_DTMODE_BLOCK??????? (0 << 2) >> +#define DCTRLR_DTMODE_SDIO??????? (1 << 2) >> +#define DCTRLR_DTMODE_MMC??????? (2 << 2) >> +#define DCTRLR_DBLOCKSIZE_MASK??????? GENMASK(7, 4) >> +#define DCTRLR_DBLOCKSIZE_MAX??????? 14 >> +#define DCTRLR_RWSTART??????????? BIT(8) >> +#define DCTRLR_RWSTOP??????????? BIT(9) >> +#define DCTRLR_RWMOD??????????? BIT(10) >> +#define DCTRLR_SDIOEN??????????? BIT(11) >> +#define DCTRLR_BOOTACKEN??????? BIT(12) >> +#define DCTRLR_FIFORST??????????? BIT(13) >> + >> +#define SDMMC_DCNTR??????????? 0x030 >> + >> +#define SDMMC_STAR??????????? 0x034 >> +#define STAR_CCRCFAIL??????????? BIT(0) >> +#define STAR_DCRCFAIL??????????? BIT(1) >> +#define STAR_CTIMEOUT??????????? BIT(2) >> +#define STAR_DTIMEOUT??????????? BIT(3) >> +#define STAR_TXUNDERR??????????? BIT(4) >> +#define STAR_RXOVERR??????????? BIT(5) >> +#define STAR_CMDREND??????????? BIT(6) >> +#define STAR_CMDSENT??????????? BIT(7) >> +#define STAR_DATAEND??????????? BIT(8) >> +#define STAR_DHOLD??????????? BIT(9) >> +#define STAR_DBCKEND??????????? BIT(10) >> +#define STAR_DABORT??????????? BIT(11) >> +#define STAR_DPSMACT??????????? BIT(12) >> +#define STAR_CPSMACT??????????? BIT(13) >> +#define STAR_TXFIFOHE??????????? BIT(14) >> +#define STAR_TXFIFOHF??????????? BIT(15) >> +#define STAR_TXFIFOF??????????? BIT(16) >> +#define STAR_RXFIFOF??????????? BIT(17) >> +#define STAR_TXFIFOE??????????? BIT(18) >> +#define STAR_RXFIFOE??????????? BIT(19) >> +#define STAR_BUSYD0??????????? BIT(20) >> +#define STAR_BUSYD0END??????????? BIT(21) >> +#define STAR_SDIOIT??????????? BIT(22) >> +#define STAR_ACKFAIL??????????? BIT(23) >> +#define STAR_ACKTIMEOUT??????????? BIT(24) >> +#define STAR_VSWEND??????????? BIT(25) >> +#define STAR_CKSTOP??????????? BIT(26) >> +#define STAR_IDMATE??????????? BIT(27) >> +#define STAR_IDMABTC??????????? BIT(28) >> + >> +#define SDMMC_ICR??????????? 0x038 >> +#define ICR_CCRCFAILC??????????? BIT(0) >> +#define ICR_DCRCFAILC??????????? BIT(1) >> +#define ICR_CTIMEOUTC??????????? BIT(2) >> +#define ICR_DTIMEOUTC??????????? BIT(3) >> +#define ICR_TXUNDERRC??????????? BIT(4) >> +#define ICR_RXOVERRC??????????? BIT(5) >> +#define ICR_CMDRENDC??????????? BIT(6) >> +#define ICR_CMDSENTC??????????? BIT(7) >> +#define ICR_DATAENDC??????????? BIT(8) >> +#define ICR_DHOLDC??????????? BIT(9) >> +#define ICR_DBCKENDC??????????? BIT(10) >> +#define ICR_DABORTC??????????? BIT(11) >> +#define ICR_BUSYD0ENDC??????????? BIT(21) >> +#define ICR_SDIOITC??????????? BIT(22) >> +#define ICR_ACKFAILC??????????? BIT(23) >> +#define ICR_ACKTIMEOUTC??????????? BIT(24) >> +#define ICR_VSWENDC??????????? BIT(25) >> +#define ICR_CKSTOPC??????????? BIT(26) >> +#define ICR_IDMATEC??????????? BIT(27) >> +#define ICR_IDMABTCC??????????? BIT(28) >> +#define ICR_STATIC_FLAG??????????? ((GENMASK(28, 21)) | (GENMASK(11, >> 0))) >> + >> +#define SDMMC_MASKR??????????? 0x03c >> +#define MASKR_CCRCFAILIE??????? BIT(0) >> +#define MASKR_DCRCFAILIE??????? BIT(1) >> +#define MASKR_CTIMEOUTIE??????? BIT(2) >> +#define MASKR_DTIMEOUTIE??????? BIT(3) >> +#define MASKR_TXUNDERRIE??????? BIT(4) >> +#define MASKR_RXOVERRIE??????????? BIT(5) >> +#define MASKR_CMDRENDIE??????????? BIT(6) >> +#define MASKR_CMDSENTIE??????????? BIT(7) >> +#define MASKR_DATAENDIE??????????? BIT(8) >> +#define MASKR_DHOLDIE??????????? BIT(9) >> +#define MASKR_DBCKENDIE??????????? BIT(10) >> +#define MASKR_DABORTIE??????????? BIT(11) >> +#define MASKR_TXFIFOHEIE??????? BIT(14) >> +#define MASKR_RXFIFOHFIE??????? BIT(15) >> +#define MASKR_RXFIFOFIE??????????? BIT(17) >> +#define MASKR_TXFIFOEIE??????????? BIT(18) >> +#define MASKR_BUSYD0ENDIE??????? BIT(21) >> +#define MASKR_SDIOITIE??????????? BIT(22) >> +#define MASKR_ACKFAILIE??????????? BIT(23) >> +#define MASKR_ACKTIMEOUTIE??????? BIT(24) >> +#define MASKR_VSWENDIE??????????? BIT(25) >> +#define MASKR_CKSTOPIE??????????? BIT(26) >> +#define MASKR_IDMABTCIE??????????? BIT(28) >> + >> +#define SDMMC_ACKTIMER??????????? 0x040 >> +#define ACKTIMER_ACKTIME_MASK??????? GENMASK(24, 0) >> + >> +#define SDMMC_FIFOR??????????? 0x080 >> + >> +#define SDMMC_IDMACTRLR??????????? 0x050 >> +#define IDMACTRLR_IDMAEN??????? BIT(0) >> +#define IDMACTRLR_IDMABMODE??????? BIT(1) >> +#define IDMACTRLR_IDMABACT??????? BIT(2) >> + >> +#define SDMMC_IDMABSIZER??????? 0x054 >> +#define IDMABSIZER_IDMABNDT_MASK??? GENMASK(12, 5) >> + >> +#define SDMMC_IDMABASE0R??????? 0x058 >> +#define SDMMC_IDMABASE1R??????? 0x05c >> + >> +#define SDMMC_IPVR??????????? 0x3fc >> +#define IPVR_MINREV_MASK??????? GENMASK(3, 0) >> +#define IPVR_MAJREV_MASK??????? GENMASK(7, 4) >> + >> +enum stm32_sdmmc_cookie { >> +??? COOKIE_UNMAPPED, >> +??? COOKIE_PRE_MAPPED,??? /* mapped by pre_req() of stm32 */ >> +??? COOKIE_MAPPED,??????? /* mapped by prepare_data() of stm32 */ >> +}; >> + >> +struct sdmmc_stat { >> +??? unsigned long??????? n_req; >> +??? unsigned long??????? n_datareq; >> +??? unsigned long??????? n_ctimeout; >> +??? unsigned long??????? n_ccrcfail; >> +??? unsigned long??????? n_dtimeout; >> +??? unsigned long??????? n_dcrcfail; >> +??? unsigned long??????? n_txunderrun; >> +??? unsigned long??????? n_rxoverrun; >> +??? unsigned long??????? nb_dma_err; >> +}; >> + >> +struct sdmmc_host { >> +??? void __iomem??????? *base; >> +??? struct mmc_host??????? *mmc; >> +??? struct clk??????? *clk; >> +??? struct reset_control??? *rst; >> + >> +??? u32??????????? clk_reg_add; >> +??? u32??????????? pwr_reg_add; >> + >> +??? struct mmc_request??? *mrq; >> +??? struct mmc_command??? *cmd; >> +??? struct mmc_data??????? *data; >> +??? struct mmc_command??? stop_abort; >> +??? bool??????????? dpsm_abort; >> + >> +??? /* protect host registers access */ >> +??? spinlock_t??????? lock; >> + >> +??? unsigned int??????? sdmmcclk; >> +??? unsigned int??????? sdmmc_ck; >> + >> +??? u32??????????? size; >> + >> +??? u32??????????? ip_ver; >> +??? struct sdmmc_stat??? stat; >> +}; >> > > BR Ludo