mirror of
https://github.com/u-boot/u-boot.git
synced 2024-11-25 05:04:23 +08:00
sunxi: Remove mmc DMA support
The DMA code in sunxi_mmc.c is broken. mmc_trans_data_by_dma() allocates the dma descriptors on the stack, and then exits while the dma transfer is in progress, so the dma engine is reading stack memory which at that point may be re-used. So far we've gotten away with this by luck, but recent u-boot changes have shifted the stack start address by 16 bytes, which combined with dma alignment now exposes this problem. Since we end up just busy waiting for the dma engine anyway, this commit fixes things by simply removing the dma code, resulting in smaller bug-free code. Signed-off-by: Hans de Goede <hdegoede@redhat.com> Acked-by: Ian Campbell <ijc@hellion.org.uk>
This commit is contained in:
parent
9e5f80d823
commit
b6ae6765c5
@ -16,28 +16,6 @@
|
||||
#include <asm/arch/cpu.h>
|
||||
#include <asm/arch/mmc.h>
|
||||
|
||||
struct sunxi_mmc_des {
|
||||
u32 reserved1_1:1;
|
||||
u32 dic:1; /* disable interrupt on completion */
|
||||
u32 last_des:1; /* 1-this data buffer is the last buffer */
|
||||
u32 first_des:1; /* 1-data buffer is the first buffer,
|
||||
0-data buffer contained in the next
|
||||
descriptor is 1st buffer */
|
||||
u32 des_chain:1; /* 1-the 2nd address in the descriptor is the
|
||||
next descriptor address */
|
||||
u32 end_of_ring:1; /* 1-last descriptor flag when using dual
|
||||
data buffer in descriptor */
|
||||
u32 reserved1_2:24;
|
||||
u32 card_err_sum:1; /* transfer error flag */
|
||||
u32 own:1; /* des owner:1-idma owns it, 0-host owns it */
|
||||
#define SDXC_DES_NUM_SHIFT 16
|
||||
#define SDXC_DES_BUFFER_MAX_LEN (1 << SDXC_DES_NUM_SHIFT)
|
||||
u32 data_buf1_sz:16;
|
||||
u32 data_buf2_sz:16;
|
||||
u32 buf_addr_ptr1;
|
||||
u32 buf_addr_ptr2;
|
||||
};
|
||||
|
||||
struct sunxi_mmc_host {
|
||||
unsigned mmc_no;
|
||||
uint32_t *mclkreg;
|
||||
@ -189,6 +167,7 @@ static int mmc_core_init(struct mmc *mmc)
|
||||
|
||||
/* Reset controller */
|
||||
writel(SUNXI_MMC_GCTRL_RESET, &mmchost->reg->gctrl);
|
||||
udelay(1000);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -204,6 +183,9 @@ static int mmc_trans_data_by_cpu(struct mmc *mmc, struct mmc_data *data)
|
||||
unsigned timeout_msecs = 2000;
|
||||
unsigned *buff = (unsigned int *)(reading ? data->dest : data->src);
|
||||
|
||||
/* Always read / write data through the CPU */
|
||||
setbits_le32(&mmchost->reg->gctrl, SUNXI_MMC_GCTRL_ACCESS_BY_AHB);
|
||||
|
||||
for (i = 0; i < (byte_cnt >> 2); i++) {
|
||||
while (readl(&mmchost->reg->status) & status_bit) {
|
||||
if (!timeout_msecs--)
|
||||
@ -220,85 +202,6 @@ static int mmc_trans_data_by_cpu(struct mmc *mmc, struct mmc_data *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mmc_trans_data_by_dma(struct mmc *mmc, struct mmc_data *data)
|
||||
{
|
||||
struct sunxi_mmc_host *mmchost = mmc->priv;
|
||||
unsigned byte_cnt = data->blocksize * data->blocks;
|
||||
unsigned char *buff;
|
||||
unsigned des_idx = 0;
|
||||
unsigned buff_frag_num =
|
||||
(byte_cnt + SDXC_DES_BUFFER_MAX_LEN - 1) >> SDXC_DES_NUM_SHIFT;
|
||||
unsigned remain;
|
||||
unsigned i, rval;
|
||||
ALLOC_CACHE_ALIGN_BUFFER(struct sunxi_mmc_des, pdes, buff_frag_num);
|
||||
|
||||
buff = data->flags & MMC_DATA_READ ?
|
||||
(unsigned char *)data->dest : (unsigned char *)data->src;
|
||||
remain = byte_cnt & (SDXC_DES_BUFFER_MAX_LEN - 1);
|
||||
|
||||
flush_cache((unsigned long)buff, (unsigned long)byte_cnt);
|
||||
for (i = 0; i < buff_frag_num; i++, des_idx++) {
|
||||
memset((void *)&pdes[des_idx], 0, sizeof(struct sunxi_mmc_des));
|
||||
pdes[des_idx].des_chain = 1;
|
||||
pdes[des_idx].own = 1;
|
||||
pdes[des_idx].dic = 1;
|
||||
if (buff_frag_num > 1 && i != buff_frag_num - 1)
|
||||
pdes[des_idx].data_buf1_sz = 0; /* 0 == max_len */
|
||||
else
|
||||
pdes[des_idx].data_buf1_sz = remain;
|
||||
|
||||
pdes[des_idx].buf_addr_ptr1 =
|
||||
(u32) buff + i * SDXC_DES_BUFFER_MAX_LEN;
|
||||
if (i == 0)
|
||||
pdes[des_idx].first_des = 1;
|
||||
|
||||
if (i == buff_frag_num - 1) {
|
||||
pdes[des_idx].dic = 0;
|
||||
pdes[des_idx].last_des = 1;
|
||||
pdes[des_idx].end_of_ring = 1;
|
||||
pdes[des_idx].buf_addr_ptr2 = 0;
|
||||
} else {
|
||||
pdes[des_idx].buf_addr_ptr2 = (u32)&pdes[des_idx + 1];
|
||||
}
|
||||
}
|
||||
flush_cache((unsigned long)pdes,
|
||||
sizeof(struct sunxi_mmc_des) * (des_idx + 1));
|
||||
|
||||
rval = readl(&mmchost->reg->gctrl);
|
||||
/* Enable DMA */
|
||||
writel(rval | SUNXI_MMC_GCTRL_DMA_RESET | SUNXI_MMC_GCTRL_DMA_ENABLE,
|
||||
&mmchost->reg->gctrl);
|
||||
/* Reset iDMA */
|
||||
writel(SUNXI_MMC_IDMAC_RESET, &mmchost->reg->dmac);
|
||||
/* Enable iDMA */
|
||||
writel(SUNXI_MMC_IDMAC_FIXBURST | SUNXI_MMC_IDMAC_ENABLE,
|
||||
&mmchost->reg->dmac);
|
||||
rval = readl(&mmchost->reg->idie) &
|
||||
~(SUNXI_MMC_IDIE_TXIRQ|SUNXI_MMC_IDIE_RXIRQ);
|
||||
if (data->flags & MMC_DATA_WRITE)
|
||||
rval |= SUNXI_MMC_IDIE_TXIRQ;
|
||||
else
|
||||
rval |= SUNXI_MMC_IDIE_RXIRQ;
|
||||
writel(rval, &mmchost->reg->idie);
|
||||
writel((u32) pdes, &mmchost->reg->dlba);
|
||||
writel((0x2 << 28) | (0x7 << 16) | (0x01 << 3),
|
||||
&mmchost->reg->ftrglevel);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mmc_enable_dma_accesses(struct mmc *mmc, int dma)
|
||||
{
|
||||
struct sunxi_mmc_host *mmchost = mmc->priv;
|
||||
|
||||
unsigned int gctrl = readl(&mmchost->reg->gctrl);
|
||||
if (dma)
|
||||
gctrl &= ~SUNXI_MMC_GCTRL_ACCESS_BY_AHB;
|
||||
else
|
||||
gctrl |= SUNXI_MMC_GCTRL_ACCESS_BY_AHB;
|
||||
writel(gctrl, &mmchost->reg->gctrl);
|
||||
}
|
||||
|
||||
static int mmc_rint_wait(struct mmc *mmc, unsigned int timeout_msecs,
|
||||
unsigned int done_bit, const char *what)
|
||||
{
|
||||
@ -327,7 +230,6 @@ static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
|
||||
unsigned int timeout_msecs;
|
||||
int error = 0;
|
||||
unsigned int status = 0;
|
||||
unsigned int usedma = 0;
|
||||
unsigned int bytecnt = 0;
|
||||
|
||||
if (mmchost->fatal_err)
|
||||
@ -378,20 +280,8 @@ static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
|
||||
|
||||
bytecnt = data->blocksize * data->blocks;
|
||||
debug("trans data %d bytes\n", bytecnt);
|
||||
#if defined(CONFIG_MMC_SUNXI_USE_DMA) && !defined(CONFIG_SPL_BUILD)
|
||||
if (bytecnt > 64) {
|
||||
#else
|
||||
if (0) {
|
||||
#endif
|
||||
usedma = 1;
|
||||
mmc_enable_dma_accesses(mmc, 1);
|
||||
ret = mmc_trans_data_by_dma(mmc, data);
|
||||
writel(cmdval | cmd->cmdidx, &mmchost->reg->cmd);
|
||||
} else {
|
||||
mmc_enable_dma_accesses(mmc, 0);
|
||||
writel(cmdval | cmd->cmdidx, &mmchost->reg->cmd);
|
||||
ret = mmc_trans_data_by_cpu(mmc, data);
|
||||
}
|
||||
writel(cmdval | cmd->cmdidx, &mmchost->reg->cmd);
|
||||
ret = mmc_trans_data_by_cpu(mmc, data);
|
||||
if (ret) {
|
||||
error = readl(&mmchost->reg->rint) & \
|
||||
SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT;
|
||||
@ -405,7 +295,7 @@ static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
|
||||
goto out;
|
||||
|
||||
if (data) {
|
||||
timeout_msecs = usedma ? 120 * bytecnt : 120;
|
||||
timeout_msecs = 120;
|
||||
debug("cacl timeout %x msec\n", timeout_msecs);
|
||||
error = mmc_rint_wait(mmc, timeout_msecs,
|
||||
data->blocks > 1 ?
|
||||
@ -442,23 +332,6 @@ static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
|
||||
debug("mmc resp 0x%08x\n", cmd->response[0]);
|
||||
}
|
||||
out:
|
||||
if (data && usedma) {
|
||||
/* IDMASTAREG
|
||||
* IDST[0] : idma tx int
|
||||
* IDST[1] : idma rx int
|
||||
* IDST[2] : idma fatal bus error
|
||||
* IDST[4] : idma descriptor invalid
|
||||
* IDST[5] : idma error summary
|
||||
* IDST[8] : idma normal interrupt sumary
|
||||
* IDST[9] : idma abnormal interrupt sumary
|
||||
*/
|
||||
status = readl(&mmchost->reg->idst);
|
||||
writel(status, &mmchost->reg->idst);
|
||||
writel(0, &mmchost->reg->idie);
|
||||
writel(0, &mmchost->reg->dmac);
|
||||
writel(readl(&mmchost->reg->gctrl) & ~SUNXI_MMC_GCTRL_DMA_ENABLE,
|
||||
&mmchost->reg->gctrl);
|
||||
}
|
||||
if (error < 0) {
|
||||
writel(SUNXI_MMC_GCTRL_RESET, &mmchost->reg->gctrl);
|
||||
mmc_update_clk(mmc);
|
||||
|
@ -70,7 +70,6 @@
|
||||
#define CONFIG_CMD_MMC
|
||||
#define CONFIG_MMC_SUNXI
|
||||
#define CONFIG_MMC_SUNXI_SLOT 0
|
||||
#define CONFIG_MMC_SUNXI_USE_DMA
|
||||
#define CONFIG_ENV_IS_IN_MMC
|
||||
#define CONFIG_SYS_MMC_ENV_DEV 0 /* first detected MMC controller */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user