mirror of
https://github.com/torvalds/linux.git
synced 2026-05-28 17:13:52 +02:00
spi: spi-qpic-snand: avoid memory corruption
Merge series from Gabor Juhos <j4g8y7@gmail.com>: The 'spi-qpic-nand' driver may cause memory corruption under some circumstances. The first patch in the series changes the driver to avoid that, whereas the second adds some sanity checks to the common QPIC code in order to make detecting such errors easier in the future.
This commit is contained in:
commit
4ec24e9601
|
|
@ -57,14 +57,15 @@ qcom_alloc_bam_transaction(struct qcom_nand_controller *nandc)
|
|||
bam_txn_buf += sizeof(*bam_txn);
|
||||
|
||||
bam_txn->bam_ce = bam_txn_buf;
|
||||
bam_txn_buf +=
|
||||
sizeof(*bam_txn->bam_ce) * QPIC_PER_CW_CMD_ELEMENTS * num_cw;
|
||||
bam_txn->bam_ce_nitems = QPIC_PER_CW_CMD_ELEMENTS * num_cw;
|
||||
bam_txn_buf += sizeof(*bam_txn->bam_ce) * bam_txn->bam_ce_nitems;
|
||||
|
||||
bam_txn->cmd_sgl = bam_txn_buf;
|
||||
bam_txn_buf +=
|
||||
sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL * num_cw;
|
||||
bam_txn->cmd_sgl_nitems = QPIC_PER_CW_CMD_SGL * num_cw;
|
||||
bam_txn_buf += sizeof(*bam_txn->cmd_sgl) * bam_txn->cmd_sgl_nitems;
|
||||
|
||||
bam_txn->data_sgl = bam_txn_buf;
|
||||
bam_txn->data_sgl_nitems = QPIC_PER_CW_DATA_SGL * num_cw;
|
||||
|
||||
init_completion(&bam_txn->txn_done);
|
||||
|
||||
|
|
@ -238,6 +239,11 @@ int qcom_prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read,
|
|||
struct bam_transaction *bam_txn = nandc->bam_txn;
|
||||
u32 offset;
|
||||
|
||||
if (bam_txn->bam_ce_pos + size > bam_txn->bam_ce_nitems) {
|
||||
dev_err(nandc->dev, "BAM %s array is full\n", "CE");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_pos];
|
||||
|
||||
/* fill the command desc */
|
||||
|
|
@ -258,6 +264,12 @@ int qcom_prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read,
|
|||
|
||||
/* use the separate sgl after this command */
|
||||
if (flags & NAND_BAM_NEXT_SGL) {
|
||||
if (bam_txn->cmd_sgl_pos >= bam_txn->cmd_sgl_nitems) {
|
||||
dev_err(nandc->dev, "BAM %s array is full\n",
|
||||
"CMD sgl");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_start];
|
||||
bam_ce_size = (bam_txn->bam_ce_pos -
|
||||
bam_txn->bam_ce_start) *
|
||||
|
|
@ -297,10 +309,20 @@ int qcom_prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read,
|
|||
struct bam_transaction *bam_txn = nandc->bam_txn;
|
||||
|
||||
if (read) {
|
||||
if (bam_txn->rx_sgl_pos >= bam_txn->data_sgl_nitems) {
|
||||
dev_err(nandc->dev, "BAM %s array is full\n", "RX sgl");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sg_set_buf(&bam_txn->data_sgl[bam_txn->rx_sgl_pos],
|
||||
vaddr, size);
|
||||
bam_txn->rx_sgl_pos++;
|
||||
} else {
|
||||
if (bam_txn->tx_sgl_pos >= bam_txn->data_sgl_nitems) {
|
||||
dev_err(nandc->dev, "BAM %s array is full\n", "TX sgl");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sg_set_buf(&bam_txn->data_sgl[bam_txn->tx_sgl_pos],
|
||||
vaddr, size);
|
||||
bam_txn->tx_sgl_pos++;
|
||||
|
|
|
|||
|
|
@ -315,6 +315,22 @@ static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand)
|
|||
|
||||
mtd_set_ooblayout(mtd, &qcom_spi_ooblayout);
|
||||
|
||||
/*
|
||||
* Free the temporary BAM transaction allocated initially by
|
||||
* qcom_nandc_alloc(), and allocate a new one based on the
|
||||
* updated max_cwperpage value.
|
||||
*/
|
||||
qcom_free_bam_transaction(snandc);
|
||||
|
||||
snandc->max_cwperpage = cwperpage;
|
||||
|
||||
snandc->bam_txn = qcom_alloc_bam_transaction(snandc);
|
||||
if (!snandc->bam_txn) {
|
||||
dev_err(snandc->dev, "failed to allocate BAM transaction\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_free_ecc_cfg;
|
||||
}
|
||||
|
||||
ecc_cfg->cfg0 = FIELD_PREP(CW_PER_PAGE_MASK, (cwperpage - 1)) |
|
||||
FIELD_PREP(UD_SIZE_BYTES_MASK, ecc_cfg->cw_data) |
|
||||
FIELD_PREP(DISABLE_STATUS_AFTER_WRITE, 1) |
|
||||
|
|
|
|||
|
|
@ -237,6 +237,9 @@
|
|||
* @last_data_desc - last DMA desc in data channel (tx/rx).
|
||||
* @last_cmd_desc - last DMA desc in command channel.
|
||||
* @txn_done - completion for NAND transfer.
|
||||
* @bam_ce_nitems - the number of elements in the @bam_ce array
|
||||
* @cmd_sgl_nitems - the number of elements in the @cmd_sgl array
|
||||
* @data_sgl_nitems - the number of elements in the @data_sgl array
|
||||
* @bam_ce_pos - the index in bam_ce which is available for next sgl
|
||||
* @bam_ce_start - the index in bam_ce which marks the start position ce
|
||||
* for current sgl. It will be used for size calculation
|
||||
|
|
@ -255,6 +258,11 @@ struct bam_transaction {
|
|||
struct dma_async_tx_descriptor *last_data_desc;
|
||||
struct dma_async_tx_descriptor *last_cmd_desc;
|
||||
struct completion txn_done;
|
||||
|
||||
unsigned int bam_ce_nitems;
|
||||
unsigned int cmd_sgl_nitems;
|
||||
unsigned int data_sgl_nitems;
|
||||
|
||||
struct_group(bam_positions,
|
||||
u32 bam_ce_pos;
|
||||
u32 bam_ce_start;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user