Message ID | a948adcd9699f934734603c8ffc25ff6b4c9997d.1437426110.git.marcel.ziswiler@toradex.com |
---|---|
State | Superseded |
Delegated to: | Tom Warren |
Headers | show |
On Tue, 2015-07-21 at 00:35 +0200, Marcel Ziswiler wrote: > From: Marcel Ziswiler <marcel.ziswiler@toradex.com> > > Integrate cache alignment bounce buffer to workaround issues as follows: > > Loading file '/boot/zImage' to addr 0x01000000 with size 4499152 > (0x0044a6d0)... > ERROR: v7_dcache_inval_range - start address is not aligned - 0x1f7f0108 > ERROR: v7_dcache_inval_range - stop address is not aligned - 0x1f7f1108 > Done > Kernel image @ 0x1000000 [ 0x000000 - 0x44a6d0 ] > > Starting kernel ... > > undefined instruction > pc : [<005ff03c>] lr : [<0000800c>] > sp : 0144b6e8 ip : 01000188 fp : 0144a6c8 > r10: 00000000 r9 : 411fc090 r8 : 00000100 > r7 : 00000cfb r6 : 0144a6d0 r5 : 00000000 r4 : 00008000 > r3 : 0000000c r2 : 00000100 r1 : 00000cfb r0 : 00000000 > Flags: nZCv IRQs off FIQs off Mode SVC_32 > Resetting CPU ... > > Signed-off-by: Marcel Ziswiler <marcel.ziswiler@toradex.com> > --- > Changes in v2: > Migrated to using generic bounce buffer implementation as suggested by > Simon. I didn't see Simon's suggestion, but what is the general policy in U-Boot supposed to be for I/O alignment? Responsibility of the API user, or of the driver? Are there other drivers with the same problem? > - writel(virt_to_phys(buf), &info->reg->data_block_ptr); > + writel((u32)bbstate.bounce_buffer, &info->reg->data_block_ptr); Why are you converting usage of virt_to_phys() into a u32 cast? -Scott
Hi Scott, On 27 July 2015 at 13:57, Scott Wood <scottwood@freescale.com> wrote: > On Tue, 2015-07-21 at 00:35 +0200, Marcel Ziswiler wrote: >> From: Marcel Ziswiler <marcel.ziswiler@toradex.com> >> >> Integrate cache alignment bounce buffer to workaround issues as follows: >> >> Loading file '/boot/zImage' to addr 0x01000000 with size 4499152 >> (0x0044a6d0)... >> ERROR: v7_dcache_inval_range - start address is not aligned - 0x1f7f0108 >> ERROR: v7_dcache_inval_range - stop address is not aligned - 0x1f7f1108 >> Done >> Kernel image @ 0x1000000 [ 0x000000 - 0x44a6d0 ] >> >> Starting kernel ... >> >> undefined instruction >> pc : [<005ff03c>] lr : [<0000800c>] >> sp : 0144b6e8 ip : 01000188 fp : 0144a6c8 >> r10: 00000000 r9 : 411fc090 r8 : 00000100 >> r7 : 00000cfb r6 : 0144a6d0 r5 : 00000000 r4 : 00008000 >> r3 : 0000000c r2 : 00000100 r1 : 00000cfb r0 : 00000000 >> Flags: nZCv IRQs off FIQs off Mode SVC_32 >> Resetting CPU ... >> >> Signed-off-by: Marcel Ziswiler <marcel.ziswiler@toradex.com> >> --- >> Changes in v2: >> Migrated to using generic bounce buffer implementation as suggested by >> Simon. > > I didn't see Simon's suggestion, but what is the general policy in U-Boot > supposed to be for I/O alignment? Responsibility of the API user, or of the > driver? Are there other drivers with the same problem? MMC has it. I feel that in general we should be able to ask the higher-level systems to do the right thing and align their data. Otherwise it introduces inefficiencies into the stack. But at least if we do introduce this, we should use common infrastructure, hence my request. > >> - writel(virt_to_phys(buf), &info->reg->data_block_ptr); >> + writel((u32)bbstate.bounce_buffer, &info->reg->data_block_ptr); > > Why are you converting usage of virt_to_phys() into a u32 cast? > > -Scott > Regards, Simon
On Mon, 2015-07-27 at 17:28 -0600, Simon Glass wrote: > Hi Scott, > > On 27 July 2015 at 13:57, Scott Wood <scottwood@freescale.com> wrote: > > On Tue, 2015-07-21 at 00:35 +0200, Marcel Ziswiler wrote: > > > From: Marcel Ziswiler <marcel.ziswiler@toradex.com> > > > > > > Integrate cache alignment bounce buffer to workaround issues as follows: > > > > > > Loading file '/boot/zImage' to addr 0x01000000 with size 4499152 > > > (0x0044a6d0)... > > > ERROR: v7_dcache_inval_range - start address is not aligned - 0x1f7f0108 > > > ERROR: v7_dcache_inval_range - stop address is not aligned - 0x1f7f1108 > > > Done > > > Kernel image @ 0x1000000 [ 0x000000 - 0x44a6d0 ] > > > > > > Starting kernel ... > > > > > > undefined instruction > > > pc : [<005ff03c>] lr : [<0000800c>] > > > sp : 0144b6e8 ip : 01000188 fp : 0144a6c8 > > > r10: 00000000 r9 : 411fc090 r8 : 00000100 > > > r7 : 00000cfb r6 : 0144a6d0 r5 : 00000000 r4 : 00008000 > > > r3 : 0000000c r2 : 00000100 r1 : 00000cfb r0 : 00000000 > > > Flags: nZCv IRQs off FIQs off Mode SVC_32 > > > Resetting CPU ... > > > > > > Signed-off-by: Marcel Ziswiler <marcel.ziswiler@toradex.com> > > > --- > > > Changes in v2: > > > Migrated to using generic bounce buffer implementation as suggested by > > > Simon. > > > > I didn't see Simon's suggestion, but what is the general policy in U-Boot > > supposed to be for I/O alignment? Responsibility of the API user, or of > > the > > driver? Are there other drivers with the same problem? > > MMC has it. I feel that in general we should be able to ask the > higher-level systems to do the right thing and align their data. > Otherwise it introduces inefficiencies into the stack. But at least if > we do introduce this, we should use common infrastructure, hence my > request. OK, so your request wasn't to move this into the driver, just about how to implement it if it's done in the driver? Marcel, why did you change to handling this in the driver? -Scott
On 27 July 2015 21:57:14 CEST, Scott Wood <scottwood@freescale.com> wrote: >On Tue, 2015-07-21 at 00:35 +0200, Marcel Ziswiler wrote: >> From: Marcel Ziswiler <marcel.ziswiler@toradex.com> >> >> Integrate cache alignment bounce buffer to workaround issues as >follows: >> >> Loading file '/boot/zImage' to addr 0x01000000 with size 4499152 >> (0x0044a6d0)... >> ERROR: v7_dcache_inval_range - start address is not aligned - >0x1f7f0108 >> ERROR: v7_dcache_inval_range - stop address is not aligned - >0x1f7f1108 >> Done >> Kernel image @ 0x1000000 [ 0x000000 - 0x44a6d0 ] >> >> Starting kernel ... >> >> undefined instruction >> pc : [<005ff03c>] lr : [<0000800c>] >> sp : 0144b6e8 ip : 01000188 fp : 0144a6c8 >> r10: 00000000 r9 : 411fc090 r8 : 00000100 >> r7 : 00000cfb r6 : 0144a6d0 r5 : 00000000 r4 : 00008000 >> r3 : 0000000c r2 : 00000100 r1 : 00000cfb r0 : 00000000 >> Flags: nZCv IRQs off FIQs off Mode SVC_32 >> Resetting CPU ... >> >> Signed-off-by: Marcel Ziswiler <marcel.ziswiler@toradex.com> >> --- >> Changes in v2: >> Migrated to using generic bounce buffer implementation as suggested >by >> Simon. > >I didn't see Simon's suggestion, but what is the general policy in >U-Boot >supposed to be for I/O alignment? Responsibility of the API user, or >of the >driver? Are there other drivers with the same problem? Well, well. You got us into some ruff terrain right there. Remember I have some other alignment patches awaiting acceptance (e.g U-Boot's MTD and most possibly other subsystems are deeply broken in that respect) but even with those I failed booting a kernel loaded from UBIFS so I started having my doubts whether or not this is truly possible without bouncing. At least Tegra's MMC driver just bounces as well. >> - writel(virt_to_phys(buf), &info->reg->data_block_ptr); >> + writel((u32)bbstate.bounce_buffer, &info->reg->data_block_ptr); > >Why are you converting usage of virt_to_phys() into a u32 cast? Good question. I believe this I took straight from the MMC driver but will double check it again for a v3.
On 28 July 2015 01:32:10 CEST, Scott Wood <scottwood@freescale.com> wrote: >On Mon, 2015-07-27 at 17:28 -0600, Simon Glass wrote: >> Hi Scott, >> >> On 27 July 2015 at 13:57, Scott Wood <scottwood@freescale.com> wrote: >> > On Tue, 2015-07-21 at 00:35 +0200, Marcel Ziswiler wrote: >> > > From: Marcel Ziswiler <marcel.ziswiler@toradex.com> >> > > >> > > Integrate cache alignment bounce buffer to workaround issues as >follows: >> > > >> > > Loading file '/boot/zImage' to addr 0x01000000 with size 4499152 >> > > (0x0044a6d0)... >> > > ERROR: v7_dcache_inval_range - start address is not aligned - >0x1f7f0108 >> > > ERROR: v7_dcache_inval_range - stop address is not aligned - >0x1f7f1108 >> > > Done >> > > Kernel image @ 0x1000000 [ 0x000000 - 0x44a6d0 ] >> > > >> > > Starting kernel ... >> > > >> > > undefined instruction >> > > pc : [<005ff03c>] lr : [<0000800c>] >> > > sp : 0144b6e8 ip : 01000188 fp : 0144a6c8 >> > > r10: 00000000 r9 : 411fc090 r8 : 00000100 >> > > r7 : 00000cfb r6 : 0144a6d0 r5 : 00000000 r4 : 00008000 >> > > r3 : 0000000c r2 : 00000100 r1 : 00000cfb r0 : 00000000 >> > > Flags: nZCv IRQs off FIQs off Mode SVC_32 >> > > Resetting CPU ... >> > > >> > > Signed-off-by: Marcel Ziswiler <marcel.ziswiler@toradex.com> >> > > --- >> > > Changes in v2: >> > > Migrated to using generic bounce buffer implementation as >suggested by >> > > Simon. >> > >> > I didn't see Simon's suggestion, but what is the general policy in >U-Boot >> > supposed to be for I/O alignment? Responsibility of the API user, >or of >> > the >> > driver? Are there other drivers with the same problem? >> >> MMC has it. I feel that in general we should be able to ask the >> higher-level systems to do the right thing and align their data. >> Otherwise it introduces inefficiencies into the stack. But at least >if >> we do introduce this, we should use common infrastructure, hence my >> request. > >OK, so your request wasn't to move this into the driver, just about how >to >implement it if it's done in the driver? Marcel, why did you change to > >handling this in the driver? Maybe because U-Boot is deeply broken in that respect. Please also see my comment in my previous post.
On Tue, 2015-07-28 at 03:55 +0200, Marcel Ziswiler wrote: > On 27 July 2015 21:57:14 CEST, Scott Wood <scottwood@freescale.com> wrote: > > On Tue, 2015-07-21 at 00:35 +0200, Marcel Ziswiler wrote: > > > From: Marcel Ziswiler <marcel.ziswiler@toradex.com> > > > > > > Integrate cache alignment bounce buffer to workaround issues as > > follows: > > > > > > Loading file '/boot/zImage' to addr 0x01000000 with size 4499152 > > > (0x0044a6d0)... > > > ERROR: v7_dcache_inval_range - start address is not aligned - > > 0x1f7f0108 > > > ERROR: v7_dcache_inval_range - stop address is not aligned - > > 0x1f7f1108 > > > Done > > > Kernel image @ 0x1000000 [ 0x000000 - 0x44a6d0 ] > > > > > > Starting kernel ... > > > > > > undefined instruction > > > pc : [<005ff03c>] lr : [<0000800c>] > > > sp : 0144b6e8 ip : 01000188 fp : 0144a6c8 > > > r10: 00000000 r9 : 411fc090 r8 : 00000100 > > > r7 : 00000cfb r6 : 0144a6d0 r5 : 00000000 r4 : 00008000 > > > r3 : 0000000c r2 : 00000100 r1 : 00000cfb r0 : 00000000 > > > Flags: nZCv IRQs off FIQs off Mode SVC_32 > > > Resetting CPU ... > > > > > > Signed-off-by: Marcel Ziswiler <marcel.ziswiler@toradex.com> > > > --- > > > Changes in v2: > > > Migrated to using generic bounce buffer implementation as suggested > > by > > > Simon. > > > > I didn't see Simon's suggestion, but what is the general policy in > > U-Boot > > supposed to be for I/O alignment? Responsibility of the API user, or > > of the > > driver? Are there other drivers with the same problem? > > Well, well. You got us into some ruff terrain right there. Remember I have > some other alignment patches awaiting acceptance (e.g U-Boot's MTD and most > possibly other subsystems are deeply broken in that respect) but even with > those I failed booting a kernel loaded from UBIFS so I started having my > doubts whether or not this is truly possible without bouncing. At least > Tegra's MMC driver just bounces as well. OK. With users such as UBI that are shared with kernel code, it might be difficult to enforce a caller-aligns model. -Scott
On Tue, 2015-07-28 at 03:55 +0200, Marcel Ziswiler wrote: > > On 27 July 2015 21:57:14 CEST, Scott Wood <scottwood@freescale.com> > wrote: > > > - writel(virt_to_phys(buf), &info->reg->data_block_ptr); > > > + writel((u32)bbstate.bounce_buffer, &info->reg > > > ->data_block_ptr); > > > > Why are you converting usage of virt_to_phys() into a u32 cast? > > Good question. I believe this I took straight from the MMC driver but > will double check it again for a v3. Yes, the MMC driver actually even does a double cast. Don't knowexactly what that should bring but that's how it looks there: writel((u32)(unsigned long)bbstate->bounce_buffer, &host->reg->sysad); http://git.denx.de/?p=u-boot.git;a=blob;f=drivers/mmc/tegra_mmc.c;hb=HEAD#l70 Nonetheless I changed it back to using virt_to_phys() for the v3 to beposted soon.
On Wed, 2015-08-05 at 22:12 +0000, Marcel Ziswiler wrote: > On Tue, 2015-07-28 at 03:55 +0200, Marcel Ziswiler wrote: > > > > On 27 July 2015 21:57:14 CEST, Scott Wood <scottwood@freescale.com> > > wrote: > > > > - writel(virt_to_phys(buf), &info->reg->data_block_ptr); > > > > + writel((u32)bbstate.bounce_buffer, &info->reg > > > > ->data_block_ptr); > > > > > > Why are you converting usage of virt_to_phys() into a u32 cast? > > > > Good question. I believe this I took straight from the MMC driver but > > will double check it again for a v3. > > Yes, the MMC driver actually even does a double cast. Don't knowexactly > what that should bring but that's how it looks there: > writel((u32)(unsigned long)bbstate->bounce_buffer, &host->reg->sysad); > http://git.denx.de/?p=u-boot.git;a=blob;f=drivers/mmc/tegra_mmc.c;hb=HEAD#l70 > Nonetheless I changed it back to using virt_to_phys() for the v3 to > beposted soon. The double cast suppresses a warning in 64-bit builds (converting directly from a pointer to an integer of a different size), but ideally virt_to_phys() should be used. -Scott
diff --git a/drivers/mtd/nand/tegra_nand.c b/drivers/mtd/nand/tegra_nand.c index 9f90683..02d8aed 100644 --- a/drivers/mtd/nand/tegra_nand.c +++ b/drivers/mtd/nand/tegra_nand.c @@ -16,6 +16,7 @@ #include <asm/errno.h> #include <asm/gpio.h> #include <fdtdec.h> +#include <bouncebuf.h> #include "tegra_nand.h" DECLARE_GLOBAL_DATA_PTR; @@ -93,35 +94,6 @@ static struct nand_drv nand_ctrl; static struct mtd_info *our_mtd; static struct nand_chip nand_chip[CONFIG_SYS_MAX_NAND_DEVICE]; -#ifdef CONFIG_SYS_DCACHE_OFF -static inline void dma_prepare(void *start, unsigned long length, - int is_writing) -{ -} -#else -/** - * Prepare for a DMA transaction - * - * For a write we flush out our data. For a read we invalidate, since we - * need to do this before we read from the buffer after the DMA has - * completed, so may as well do it now. - * - * @param start Start address for DMA buffer (should be cache-aligned) - * @param length Length of DMA buffer in bytes - * @param is_writing 0 if reading, non-zero if writing - */ -static void dma_prepare(void *start, unsigned long length, int is_writing) -{ - unsigned long addr = (unsigned long)start; - - length = ALIGN(length, ARCH_DMA_MINALIGN); - if (is_writing) - flush_dcache_range(addr, addr + length); - else - invalidate_dcache_range(addr, addr + length); -} -#endif - /** * Wait for command completion * @@ -534,6 +506,8 @@ static int nand_rw_page(struct mtd_info *mtd, struct nand_chip *chip, char *tag_ptr; struct nand_drv *info; struct fdt_nand *config; + unsigned int bbflags; + struct bounce_buffer bbstate, bbstate_oob; if ((uintptr_t)buf & 0x03) { printf("buf %p has to be 4-byte aligned\n", buf); @@ -550,21 +524,21 @@ static int nand_rw_page(struct mtd_info *mtd, struct nand_chip *chip, stop_command(info->reg); + if (is_writing) + bbflags = GEN_BB_READ; + else + bbflags = GEN_BB_WRITE; + + bounce_buffer_start(&bbstate, (void *)buf, 1 << chip->page_shift, + bbflags); writel((1 << chip->page_shift) - 1, &info->reg->dma_cfg_a); - writel(virt_to_phys(buf), &info->reg->data_block_ptr); + writel((u32)bbstate.bounce_buffer, &info->reg->data_block_ptr); + /* Set ECC selection, configure ECC settings */ if (with_ecc) { - writel(virt_to_phys(tag_ptr), &info->reg->tag_ptr); if (is_writing) memcpy(tag_ptr, chip->oob_poi + free->offset, - chip->ecc.layout->oobavail + - TAG_ECC_BYTES); - } else { - writel(virt_to_phys(chip->oob_poi), &info->reg->tag_ptr); - } - - /* Set ECC selection, configure ECC settings */ - if (with_ecc) { + chip->ecc.layout->oobavail + TAG_ECC_BYTES); tag_size = chip->ecc.layout->oobavail + TAG_ECC_BYTES; reg_val |= (CFG_SKIP_SPARE_SEL_4 | CFG_SKIP_SPARE_ENABLE @@ -577,7 +551,8 @@ static int nand_rw_page(struct mtd_info *mtd, struct nand_chip *chip, if (!is_writing) tag_size += SKIPPED_SPARE_BYTES; - dma_prepare(tag_ptr, tag_size, is_writing); + bounce_buffer_start(&bbstate_oob, (void *)tag_ptr, tag_size, + bbflags); } else { tag_size = mtd->oobsize; reg_val |= (CFG_SKIP_SPARE_DISABLE @@ -585,14 +560,12 @@ static int nand_rw_page(struct mtd_info *mtd, struct nand_chip *chip, | CFG_ECC_EN_TAG_DISABLE | CFG_HW_ECC_DISABLE | (tag_size - 1)); - dma_prepare(chip->oob_poi, tag_size, is_writing); + bounce_buffer_start(&bbstate_oob, (void *)chip->oob_poi, + tag_size, bbflags); } writel(reg_val, &info->reg->config); - - dma_prepare(buf, 1 << chip->page_shift, is_writing); - + writel((u32)bbstate_oob.bounce_buffer, &info->reg->tag_ptr); writel(BCH_CONFIG_BCH_ECC_DISABLE, &info->reg->bch_config); - writel(tag_size - 1, &info->reg->dma_cfg_b); nand_clear_interrupt_status(info->reg); @@ -638,6 +611,9 @@ static int nand_rw_page(struct mtd_info *mtd, struct nand_chip *chip, return -EIO; } + bounce_buffer_stop(&bbstate_oob); + bounce_buffer_stop(&bbstate); + if (with_ecc && !is_writing) { memcpy(chip->oob_poi, tag_ptr, SKIPPED_SPARE_BYTES); @@ -755,6 +731,8 @@ static int nand_rw_oob(struct mtd_info *mtd, struct nand_chip *chip, int tag_size; struct nand_oobfree *free = chip->ecc.layout->oobfree; struct nand_drv *info; + unsigned int bbflags; + struct bounce_buffer bbstate_oob; if (((int)chip->oob_poi) & 0x03) return -EINVAL; @@ -764,8 +742,6 @@ static int nand_rw_oob(struct mtd_info *mtd, struct nand_chip *chip, stop_command(info->reg); - writel(virt_to_phys(chip->oob_poi), &info->reg->tag_ptr); - /* Set ECC selection */ tag_size = mtd->oobsize; if (with_ecc) @@ -779,13 +755,20 @@ static int nand_rw_oob(struct mtd_info *mtd, struct nand_chip *chip, CFG_HW_ECC_DISABLE); writel(reg_val, &info->reg->config); - dma_prepare(chip->oob_poi, tag_size, is_writing); - - writel(BCH_CONFIG_BCH_ECC_DISABLE, &info->reg->bch_config); - if (is_writing && with_ecc) tag_size -= TAG_ECC_BYTES; + if (is_writing) + bbflags = GEN_BB_READ; + else + bbflags = GEN_BB_WRITE; + + bounce_buffer_start(&bbstate_oob, (void *)chip->oob_poi, tag_size, + bbflags); + writel((u32)bbstate_oob.bounce_buffer, &info->reg->tag_ptr); + + writel(BCH_CONFIG_BCH_ECC_DISABLE, &info->reg->bch_config); + writel(tag_size - 1, &info->reg->dma_cfg_b); nand_clear_interrupt_status(info->reg); @@ -822,6 +805,8 @@ static int nand_rw_oob(struct mtd_info *mtd, struct nand_chip *chip, return -EIO; } + bounce_buffer_stop(&bbstate_oob); + if (with_ecc && !is_writing) { reg_val = (u32)check_ecc_error(info->reg, 0, 0, (u8 *)(chip->oob_poi + free->offset),