Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8c61b7a7 authored by Segher Boessenkool's avatar Segher Boessenkool Committed by David Woodhouse
Browse files

[MTD] [NAND] Use rslib for CAFÉ ECC

parent d7e5a546
Loading
Loading
Loading
Loading
+7 −5
Original line number Original line Diff line number Diff line
@@ -234,6 +234,8 @@ config MTD_NAND_BASLER_EXCITE
config MTD_NAND_CAFE
config MTD_NAND_CAFE
	tristate "NAND support for OLPC CAFÉ chip"
	tristate "NAND support for OLPC CAFÉ chip"
	depends on PCI
	depends on PCI
	select REED_SOLOMON
	select REED_SOLOMON_DEC16
	help
	help
	  Use NAND flash attached to the CAFÉ chip designed for the $100
	  Use NAND flash attached to the CAFÉ chip designed for the $100
	  laptop.
	  laptop.
+1 −1
Original line number Original line Diff line number Diff line
@@ -28,4 +28,4 @@ obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o
obj-$(CONFIG_MTD_NAND_BASLER_EXCITE)	+= excite_nandflash.o
obj-$(CONFIG_MTD_NAND_BASLER_EXCITE)	+= excite_nandflash.o


nand-objs := nand_base.o nand_bbt.o
nand-objs := nand_base.o nand_bbt.o
cafe_nand-objs := cafe.o cafe_ecc.o
cafe_nand-objs := cafe.o
+98 −12
Original line number Original line Diff line number Diff line
@@ -11,6 +11,7 @@
#undef DEBUG
#undef DEBUG
#include <linux/mtd/mtd.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/nand.h>
#include <linux/rslib.h>
#include <linux/pci.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/interrupt.h>
@@ -46,13 +47,11 @@
#define CAFE_GLOBAL_IRQ_MASK	0x300c
#define CAFE_GLOBAL_IRQ_MASK	0x300c
#define CAFE_NAND_RESET		0x3034
#define CAFE_NAND_RESET		0x3034


int cafe_correct_ecc(unsigned char *buf,
		     unsigned short *chk_syndrome_list);

struct cafe_priv {
struct cafe_priv {
	struct nand_chip nand;
	struct nand_chip nand;
	struct pci_dev *pdev;
	struct pci_dev *pdev;
	void __iomem *mmio;
	void __iomem *mmio;
	struct rs_control *rs;
	uint32_t ctl1;
	uint32_t ctl1;
	uint32_t ctl2;
	uint32_t ctl2;
	int datalen;
	int datalen;
@@ -374,28 +373,66 @@ static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);


	if (checkecc && cafe_readl(cafe, NAND_ECC_RESULT) & (1<<18)) {
	if (checkecc && cafe_readl(cafe, NAND_ECC_RESULT) & (1<<18)) {
		unsigned short syn[8];
		unsigned short syn[8], pat[4];
		int i;
		int pos[4];
		u8 *oob = chip->oob_poi;
		int i, n;


		for (i=0; i<8; i+=2) {
		for (i=0; i<8; i+=2) {
			uint32_t tmp = cafe_readl(cafe, NAND_ECC_SYN01 + (i*2));
			uint32_t tmp = cafe_readl(cafe, NAND_ECC_SYN01 + (i*2));
			syn[i] = tmp & 0xfff;
			syn[i] = cafe->rs->index_of[tmp & 0xfff];
			syn[i+1] = (tmp >> 16) & 0xfff;
			syn[i+1] = cafe->rs->index_of[(tmp >> 16) & 0xfff];
		}
		}


		if ((i = cafe_correct_ecc(buf, syn)) < 0) {
		n = decode_rs16(cafe->rs, NULL, NULL, 1367, syn, 0, pos, 0,
		                pat);

		for (i = 0; i < n; i++) {
			int p = pos[i];

			/* The 12-bit symbols are mapped to bytes here */

			if (p > 1374) {
				/* out of range */
				n = -1374;
			} else if (p == 0) {
				/* high four bits do not correspond to data */
				if (pat[i] > 0xff)
					n = -2048;
				else
					buf[0] ^= pat[i];
			} else if (p == 1365) {
				buf[2047] ^= pat[i] >> 4;
				oob[0] ^= pat[i] << 4;
			} else if (p > 1365) {
				if ((p & 1) == 1) {
					oob[3*p/2 - 2048] ^= pat[i] >> 4;
					oob[3*p/2 - 2047] ^= pat[i] << 4;
				} else {
					oob[3*p/2 - 2049] ^= pat[i] >> 8;
					oob[3*p/2 - 2048] ^= pat[i];
				}
			} else if ((p & 1) == 1) {
				buf[3*p/2] ^= pat[i] >> 4;
				buf[3*p/2 + 1] ^= pat[i] << 4;
			} else {
				buf[3*p/2 - 1] ^= pat[i] >> 8;
				buf[3*p/2] ^= pat[i];
			}
		}

		if (n < 0) {
			dev_dbg(&cafe->pdev->dev, "Failed to correct ECC at %08x\n",
			dev_dbg(&cafe->pdev->dev, "Failed to correct ECC at %08x\n",
				cafe_readl(cafe, NAND_ADDR2) * 2048);
				cafe_readl(cafe, NAND_ADDR2) * 2048);
			for (i = 0; i < 0x5c; i += 4)
			for (i = 0; i < 0x5c; i += 4)
				printk("Register %x: %08x\n", i, readl(cafe->mmio + i));
				printk("Register %x: %08x\n", i, readl(cafe->mmio + i));
			mtd->ecc_stats.failed++;
			mtd->ecc_stats.failed++;
		} else {
		} else {
			dev_dbg(&cafe->pdev->dev, "Corrected %d symbol errors\n", i);
			dev_dbg(&cafe->pdev->dev, "Corrected %d symbol errors\n", n);
			mtd->ecc_stats.corrected += i;
			mtd->ecc_stats.corrected += n;
		}
		}
	}
	}



	return 0;
	return 0;
}
}


@@ -525,6 +562,48 @@ static int cafe_nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
	return 0;
	return 0;
}
}


/* F_2[X]/(X**6+X+1)  */
static unsigned short __devinit gf64_mul(u8 a, u8 b)
{
	u8 c;
	unsigned int i;

	c = 0;
	for (i = 0; i < 6; i++) {
		if (a & 1)
			c ^= b;
		a >>= 1;
		b <<= 1;
		if ((b & 0x40) != 0)
			b ^= 0x43;
	}

	return c;
}

/* F_64[X]/(X**2+X+A**-1) with A the generator of F_64[X]  */
static u16 __devinit gf4096_mul(u16 a, u16 b)
{
	u8 ah, al, bh, bl, ch, cl;

	ah = a >> 6;
	al = a & 0x3f;
	bh = b >> 6;
	bl = b & 0x3f;

	ch = gf64_mul(ah ^ al, bh ^ bl) ^ gf64_mul(al, bl);
	cl = gf64_mul(gf64_mul(ah, bh), 0x21) ^ gf64_mul(al, bl);

	return (ch << 6) ^ cl;
}

static int __devinit cafe_mul(int x)
{
	if (x == 0)
		return 1;
	return gf4096_mul(x, 0xe01);
}

static int __devinit cafe_nand_probe(struct pci_dev *pdev,
static int __devinit cafe_nand_probe(struct pci_dev *pdev,
				     const struct pci_device_id *ent)
				     const struct pci_device_id *ent)
{
{
@@ -564,6 +643,12 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev,
	}
	}
	cafe->nand.buffers = (void *)cafe->dmabuf + 2112;
	cafe->nand.buffers = (void *)cafe->dmabuf + 2112;


	cafe->rs = init_rs_non_canonical(12, &cafe_mul, 0, 1, 8);
	if (!cafe->rs) {
		err = -ENOMEM;
		goto out_ior;
	}

	cafe->nand.cmdfunc = cafe_nand_cmdfunc;
	cafe->nand.cmdfunc = cafe_nand_cmdfunc;
	cafe->nand.dev_ready = cafe_device_ready;
	cafe->nand.dev_ready = cafe_device_ready;
	cafe->nand.read_byte = cafe_read_byte;
	cafe->nand.read_byte = cafe_read_byte;
@@ -713,6 +798,7 @@ static void __devexit cafe_nand_remove(struct pci_dev *pdev)
	cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK);
	cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK);
	free_irq(pdev->irq, mtd);
	free_irq(pdev->irq, mtd);
	nand_release(mtd);
	nand_release(mtd);
	free_rs(cafe->rs);
	pci_iounmap(pdev, cafe->mmio);
	pci_iounmap(pdev, cafe->mmio);
	dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr);
	dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr);
	kfree(mtd);
	kfree(mtd);

drivers/mtd/nand/cafe_ecc.c

deleted100644 → 0
+0 −1381

File deleted.

Preview size limit exceeded, changes collapsed.