Пример #1
0
static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
			    uint8_t *buf, int oob_required, int page)
{
	unsigned int max_bitflips;
	struct denali_nand_info *denali = mtd_to_denali(mtd);

	dma_addr_t addr = denali->buf.dma_buf;
	size_t size = denali->mtd.writesize + denali->mtd.oobsize;

	uint32_t irq_status = 0;
	uint32_t irq_mask = INTR_STATUS__ECC_TRANSACTION_DONE |
			    INTR_STATUS__ECC_ERR;
	bool check_erased_page = false;

	if (page != denali->page) {
		dev_err(denali->dev, "IN %s: page %d is not"
				" equal to denali->page %d, investigate!!",
				__func__, page, denali->page);
		BUG();
	}

	setup_ecc_for_xfer(denali, true, false);

	denali_enable_dma(denali, true);
	dma_sync_single_for_device(denali->dev, addr, size, DMA_FROM_DEVICE);

	clear_interrupts(denali);
	denali_setup_dma(denali, DENALI_READ);

	/* wait for operation to complete */
	irq_status = wait_for_irq(denali, irq_mask);

	dma_sync_single_for_cpu(denali->dev, addr, size, DMA_FROM_DEVICE);

	memcpy(buf, denali->buf.buf, mtd->writesize);

	check_erased_page = handle_ecc(denali, buf, irq_status, &max_bitflips);
	denali_enable_dma(denali, false);

	if (check_erased_page) {
		read_oob_data(&denali->mtd, chip->oob_poi, denali->page);

		/* check ECC failures that may have occurred on erased pages */
		if (check_erased_page) {
			if (!is_erased(buf, denali->mtd.writesize))
				denali->mtd.ecc_stats.failed++;
			if (!is_erased(buf, denali->mtd.oobsize))
				denali->mtd.ecc_stats.failed++;
		}
	}
	return max_bitflips;
}
Пример #2
0
	// silly thing
	bool check_tuple()
	{
		return
			is_erased(host_i->value(0))
			|| is_erased(host_i->value(1))
			|| is_erased(host_i->value(2))
			|| is_erased(host_i->value(3))
			|| is_erased(host_i->value(4))
			|| is_erased(host_i->value(5))
			|| is_erased(host_i->value(6))
			|| is_erased(host_i->value(7))
			|| is_erased(host_i->value(8))
			|| is_erased(host_i->value(9));
	}
Пример #3
0
static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
				uint8_t *buf, int oob_required, int page)
{
	struct denali_nand_info *denali = mtd_to_denali(mtd);
	uint32_t irq_status, irq_mask =	INTR_STATUS__DMA_CMD_COMP;

	if (denali->page != page) {
		debug("Missing NAND_CMD_READ0 command\n");
		return -EIO;
	}

	if (oob_required)
		/* switch to main + spare access */
		denali_mode_main_spare_access(denali);
	else
		/* switch to main access only */
		denali_mode_main_access(denali);

	/* setting up the DMA where ecc_enable is true */
	irq_status = denali_dma_configuration(denali, DENALI_READ, false,
					      irq_mask, oob_required);

	memcpy(buf, denali->buf.dma_buf, mtd->writesize);

	/* check whether any ECC error */
	if (irq_status & INTR_STATUS__ECC_UNCOR_ERR) {
		/* is the ECC cause by erase page, check using read_page_raw */
		debug("  Uncorrected ECC detected\n");
		denali_read_page_raw(mtd, chip, buf, oob_required,
				     denali->page);

		if (is_erased(buf, mtd->writesize) == true &&
		    is_erased(chip->oob_poi, mtd->oobsize) == true) {
			debug("  ECC error cause by erased block\n");
			/* false alarm, return the 0xFF */
		} else {
			return -EBADMSG;
		}
	}
	memcpy(buf, denali->buf.dma_buf, mtd->writesize);
	return 0;
}
Пример #4
0
static void kill_block(NANDDriver *nandp, uint32_t block){

  size_t i = 0;
  size_t page = 0;
  uint8_t op_status;

  /* This test requires good block.*/
  osalDbgCheck(!nandIsBad(nandp, block));

  while(true){
    op_status = nandErase(&NAND, block);
    if (0 != (op_status & 1)){
      if(!is_erased(nandp, block))
        osalSysHalt("Block successfully killed");
    }
    if(!is_erased(nandp, block))
      osalSysHalt("Block block not erased, but erase operation report success");

    for (page=0; page<nandp->config->pages_per_block; page++){
      memset(nand_buf, 0, NAND_PAGE_SIZE);
      op_status = nandWritePageWhole(nandp, block, page, nand_buf, NAND_PAGE_SIZE);
      if (0 != (op_status & 1)){
        nandReadPageWhole(nandp, block, page, nand_buf, NAND_PAGE_SIZE);
        for (i=0; i<NAND_PAGE_SIZE; i++){
          if (nand_buf[i] != 0)
            osalSysHalt("Block successfully killed");
        }
      }

      nandReadPageWhole(nandp, block, page, nand_buf, NAND_PAGE_SIZE);
      for (i=0; i<NAND_PAGE_SIZE; i++){
        if (nand_buf[i] != 0)
          osalSysHalt("Page write failed, but write operation report success");
      }
    }
    KillCycle++;
  }
}
Пример #5
0
bool Flasher_::erase(PageID page) {

  // Unlock flash for write access
  if (!flash_unlock()) return false;
  flash_busy_wait();

  // Start deletion of page.
  FLASH->CR |= FLASH_CR_PER;
  FLASH->AR = reinterpret_cast<uint32_t>(address_of(page));
  FLASH->CR |= FLASH_CR_STRT;
  flash_busy_wait();

  // Page erase flag does not clear automatically.
  FLASH->CR &= !FLASH_CR_PER;

  flash_lock();
  return is_erased(page);
}
Пример #6
0
static void general_test (NANDDriver *nandp, size_t first,
                                      size_t last, size_t read_rounds){

  size_t block, page, round;
  bool status;
  uint8_t op_status;
  uint32_t recc, wecc;

  red_led_on();

  /* initialize time measurement units */
  chTMObjectInit(&tmu_erase);
  chTMObjectInit(&tmu_write_data);
  chTMObjectInit(&tmu_write_spare);
  chTMObjectInit(&tmu_read_data);
  chTMObjectInit(&tmu_read_spare);

  /* perform basic checks */
  for (block=first; block<last; block++){
    if (!nandIsBad(nandp, block)){
      if (!is_erased(nandp, block)){
        op_status = nandErase(nandp, block);
        osalDbgCheck(0 == (op_status & 1)); /* operation failed */
      }
    }
  }

  /* write block with pattern, read it back and compare */
  for (block=first; block<last; block++){
    if (!nandIsBad(nandp, block)){
      for (page=0; page<nandp->config->pages_per_block; page++){
        pattern_fill();

        chTMStartMeasurementX(&tmu_write_data);
        op_status = nandWritePageData(nandp, block, page,
                      nand_buf, nandp->config->page_data_size, &wecc);
        chTMStopMeasurementX(&tmu_write_data);
        osalDbgCheck(0 == (op_status & 1)); /* operation failed */

        chTMStartMeasurementX(&tmu_write_spare);
        op_status = nandWritePageSpare(nandp, block, page,
                      nand_buf + nandp->config->page_data_size,
                      nandp->config->page_spare_size);
        chTMStopMeasurementX(&tmu_write_spare);
        osalDbgCheck(0 == (op_status & 1)); /* operation failed */

        /* read back and compare */
        for (round=0; round<read_rounds; round++){
          memset(nand_buf, 0, NAND_PAGE_SIZE);

          chTMStartMeasurementX(&tmu_read_data);
          nandReadPageData(nandp, block, page,
                      nand_buf, nandp->config->page_data_size, &recc);
          chTMStopMeasurementX(&tmu_read_data);
          osalDbgCheck(0 == (recc ^ wecc)); /* ECC error detected */

          chTMStartMeasurementX(&tmu_read_spare);
          nandReadPageSpare(nandp, block, page,
                      nand_buf + nandp->config->page_data_size,
                      nandp->config->page_spare_size);
          chTMStopMeasurementX(&tmu_read_spare);

          osalDbgCheck(0 == memcmp(ref_buf, nand_buf, NAND_PAGE_SIZE)); /* Read back failed */
        }
      }

      /* make clean */
      chTMStartMeasurementX(&tmu_erase);
      op_status = nandErase(nandp, block);
      chTMStopMeasurementX(&tmu_erase);
      osalDbgCheck(0 == (op_status & 1)); /* operation failed */

      status = is_erased(nandp, block);
      osalDbgCheck(true == status); /* blocks was not erased successfully */
    }/* if (!nandIsBad(nandp, block)){ */
  }
  red_led_off();
}
Пример #7
0
static void ecc_test(NANDDriver *nandp, uint32_t block){

  uint32_t corrupted;
  uint32_t byte, bit;
  const uint32_t ecclen = 28;
  uint32_t ecc_ref, ecc_broken;
  uint8_t op_status;
  ecc_result_t ecc_result = ECC_NO_ERROR;

  /* This test requires good block.*/
  osalDbgCheck(!nandIsBad(nandp, block));
  if (!is_erased(nandp, block))
    nandErase(&NAND, block);

  pattern_fill();

  /*** Correctable errors ***/
  op_status = nandWritePageData(nandp, block, 0,
                nand_buf, nandp->config->page_data_size, &ecc_ref);
  osalDbgCheck(0 == (op_status & 1)); /* operation failed */
  nandReadPageData(nandp, block, 0,
                  nand_buf, nandp->config->page_data_size, &ecc_broken);
  ecc_result = parse_ecc(ecclen, ecc_ref, ecc_broken, &corrupted);
  osalDbgCheck(ECC_NO_ERROR == ecc_result); /* unexpected error */

  /**/
  byte = 0;
  bit = 7;
  invert_bit(nand_buf, byte, bit);
  op_status = nandWritePageData(nandp, block, 1,
                nand_buf, nandp->config->page_data_size, &ecc_broken);
  osalDbgCheck(0 == (op_status & 1)); /* operation failed */
  invert_bit(nand_buf, byte, bit);
  ecc_result = parse_ecc(ecclen, ecc_ref, ecc_broken, &corrupted);
  osalDbgCheck(ECC_CORRECTABLE_ERROR == ecc_result); /* this error must be correctable */
  osalDbgCheck(corrupted == (byte * 8 + bit)); /* wrong correction code */

  /**/
  byte = 2047;
  bit = 0;
  invert_bit(nand_buf, byte, bit);
  op_status = nandWritePageData(nandp, block, 2,
                nand_buf, nandp->config->page_data_size, &ecc_broken);
  osalDbgCheck(0 == (op_status & 1)); /* operation failed */
  invert_bit(nand_buf, byte, bit);
  ecc_result = parse_ecc(ecclen, ecc_ref, ecc_broken, &corrupted);
  osalDbgCheck(ECC_CORRECTABLE_ERROR == ecc_result); /* this error must be correctable */
  osalDbgCheck(corrupted == (byte * 8 + bit)); /* wrong correction code */

  /**/
  byte = 1027;
  bit = 3;
  invert_bit(nand_buf, byte, bit);
  op_status = nandWritePageData(nandp, block, 3,
                nand_buf, nandp->config->page_data_size, &ecc_broken);
  osalDbgCheck(0 == (op_status & 1)); /* operation failed */
  invert_bit(nand_buf, byte, bit);
  ecc_result = parse_ecc(ecclen, ecc_ref, ecc_broken, &corrupted);
  osalDbgCheck(ECC_CORRECTABLE_ERROR == ecc_result); /* this error must be correctable */
  osalDbgCheck(corrupted == (byte * 8 + bit)); /* wrong correction code */

  /*** Uncorrectable error ***/
  byte = 1027;
  invert_bit(nand_buf, byte, 3);
  invert_bit(nand_buf, byte, 4);
  op_status = nandWritePageData(nandp, block, 4,
                nand_buf, nandp->config->page_data_size, &ecc_broken);
  osalDbgCheck(0 == (op_status & 1)); /* operation failed */
  invert_bit(nand_buf, byte, 3);
  invert_bit(nand_buf, byte, 4);
  ecc_result = parse_ecc(28, ecc_ref, ecc_broken, &corrupted);
  osalDbgCheck(ECC_UNCORRECTABLE_ERROR == ecc_result); /* This error must be NOT correctable */

  /*** make clean ***/
  nandErase(&NAND, block);
}
Пример #8
0
static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
			    uint8_t *buf, int oob_required, int page)
{
	unsigned int max_bitflips = 0;
	struct denali_nand_info *denali = mtd_to_denali(mtd);

	dma_addr_t addr = (unsigned long)denali->buf.buf;
	size_t size = denali->mtd.writesize + denali->mtd.oobsize;

	uint32_t irq_status;
	uint32_t irq_mask = denali->have_hw_ecc_fixup ?
		(INTR_STATUS__DMA_CMD_COMP) :
		(INTR_STATUS__ECC_TRANSACTION_DONE | INTR_STATUS__ECC_ERR);
	bool check_erased_page = false;

	if (page != denali->page) {
		dev_err(denali->dev,
			"IN %s: page %d is not equal to denali->page %d",
			__func__, page, denali->page);
		BUG();
	}

	setup_ecc_for_xfer(denali, true, false);

	denali_enable_dma(denali, true);
	dma_sync_single_for_device(addr, size, DMA_FROM_DEVICE);

	clear_interrupts(denali);
	denali_setup_dma(denali, DENALI_READ);

	/* wait for operation to complete */
	irq_status = wait_for_irq(denali, irq_mask);

	dma_sync_single_for_cpu(addr, size, DMA_FROM_DEVICE);

	memcpy(buf, denali->buf.buf, mtd->writesize);

	check_erased_page = handle_ecc(denali, buf, irq_status, &max_bitflips);
	denali_enable_dma(denali, false);

	if (check_erased_page) {
		if (denali->have_hw_ecc_fixup) {
			/* When we have hw ecc fixup, don't check oob.
			 * That code below looks jacked up anyway.  I mean,
			 * look at it, wtf? */
			if (!is_erased(buf, denali->mtd.writesize))
				denali->mtd.ecc_stats.failed++;
		} else {
			read_oob_data(&denali->mtd, chip->oob_poi,
				denali->page);

			/* check ECC failures that may have occurred on
			 * erased pages */
			if (check_erased_page) {
				if (!is_erased(buf, denali->mtd.writesize))
					denali->mtd.ecc_stats.failed++;
				if (!is_erased(buf, denali->mtd.oobsize))
					denali->mtd.ecc_stats.failed++;
			}
		}
	}
	return max_bitflips;
}
Пример #9
0
bool test() {
  unsigned char buf[256], sig[256], buf2[8];
  unsigned long address, count, chipsize, blocksize;
  unsigned long usec;
  bool first;

  // Read the chip identification
  Serial.println();
  Serial.println("Read Chip Identification:");
  SerialFlash.readID(buf);
  Serial.print("  JEDEC ID:     ");
  Serial.print(buf[0], HEX);
  Serial.print(" ");
  Serial.print(buf[1], HEX);
  Serial.print(" ");
  Serial.println(buf[2], HEX);
  Serial.print("  Part Nummber: ");
  Serial.println(id2chip(buf));
  Serial.print("  Memory Size:  ");
  chipsize = SerialFlash.capacity(buf);
  Serial.print(chipsize);
  Serial.println(" bytes");
  if (chipsize == 0) return false;
  Serial.print("  Block Size:   ");
  blocksize = SerialFlash.blockSize();
  Serial.print(blocksize);
  Serial.println(" bytes");


  // Read the entire chip.  Every test location must be
  // erased, or have a previously tested signature
  Serial.println();
  Serial.println("Reading Chip...");
  memset(buf, 0, sizeof(buf));
  memset(sig, 0, sizeof(sig));
  memset(buf2, 0, sizeof(buf2));
  address = 0;
  count = 0;
  first = true;
  while (address < chipsize) {
    SerialFlash.read(address, buf, 8);
    //Serial.print("  addr = ");
    //Serial.print(address, HEX);
    //Serial.print(", data = ");
    //printbuf(buf, 8);
    create_signature(address, sig);
    if (is_erased(buf, 8) == false) {
      if (equal_signatures(buf, sig) == false) {
        Serial.print("  Previous data found at address ");
        Serial.println(address);
        Serial.println("  You must fully erase the chip before this test");
        Serial.print("  found this: ");
        printbuf(buf, 8);
        Serial.print("     correct: ");
        printbuf(sig, 8);
        return false;
      }
    } else {
      count = count + 1; // number of blank signatures
    }
    if (first) {
      address = address + (testIncrement - 8);
      first = false;
    } else {
      address = address + 8;
      first = true;
    }
  }


  // Write any signatures that were blank on the original check
  if (count > 0) {
    Serial.println();
    Serial.print("Writing ");
    Serial.print(count);
    Serial.println(" signatures");
    memset(buf, 0, sizeof(buf));
    memset(sig, 0, sizeof(sig));
    memset(buf2, 0, sizeof(buf2));
    address = 0;
    first = true;
    while (address < chipsize) {
      SerialFlash.read(address, buf, 8);
      if (is_erased(buf, 8)) {
        create_signature(address, sig);
        //Serial.printf("write %08X: data: ", address);
        //printbuf(sig, 8);
        SerialFlash.write(address, sig, 8);
        while (!SerialFlash.ready()) ; // wait
        SerialFlash.read(address, buf, 8);
        if (equal_signatures(buf, sig) == false) {
          Serial.print("  error writing signature at ");
          Serial.println(address);
          Serial.print("  Read this: ");
          printbuf(buf, 8);
          Serial.print("  Expected:  ");
          printbuf(sig, 8);
          return false;
        }
      }
      if (first) {
        address = address + (testIncrement - 8);
        first = false;
      } else {
        address = address + 8;
        first = true;
      }
    }
  } else {
    Serial.println("  all signatures present from prior tests");
  }


  // Read all the signatures again, just to be sure
  // checks prior writing didn't corrupt any other data
  Serial.println();
  Serial.println("Double Checking All Signatures:");
  memset(buf, 0, sizeof(buf));
  memset(sig, 0, sizeof(sig));
  memset(buf2, 0, sizeof(buf2));
  count = 0;
  address = 0;
  first = true;
  while (address < chipsize) {
    SerialFlash.read(address, buf, 8);
    create_signature(address, sig);
    if (equal_signatures(buf, sig) == false) {
      Serial.print("  error in signature at ");
      Serial.println(address);
      Serial.print("  Read this: ");
      printbuf(buf, 8);
      Serial.print("  Expected:  ");
      printbuf(sig, 8);
      return false;
    }
    count = count + 1;
    if (first) {
      address = address + (testIncrement - 8);
      first = false;
    } else {
      address = address + 8;
      first = true;
    }
  }
  Serial.print("  all ");
  Serial.print(count);
  Serial.println(" signatures read ok");


  // Read pairs of adjacent signatures
  // check read works across boundaries
  Serial.println();
  Serial.println("Checking Signature Pairs");
  memset(buf, 0, sizeof(buf));
  memset(sig, 0, sizeof(sig));
  memset(buf2, 0, sizeof(buf2));
  count = 0;
  address = testIncrement - 8;
  first = true;
  while (address < chipsize - 8) {
    SerialFlash.read(address, buf, 16);
    create_signature(address, sig);
    create_signature(address + 8, sig + 8);
    if (memcmp(buf, sig, 16) != 0) {
      Serial.print("  error in signature pair at ");
      Serial.println(address);
      Serial.print("  Read this: ");
      printbuf(buf, 16);
      Serial.print("  Expected:  ");
      printbuf(sig, 16);
      return false;
    }
    count = count + 1;
    address = address + testIncrement;
  }
  Serial.print("  all ");
  Serial.print(count);
  Serial.println(" signature pairs read ok");


  // Write data and read while write in progress
  Serial.println();
  Serial.println("Checking Read-While-Write (Program Suspend)");
  address = 256;
  while (address < chipsize) { // find a blank space
    SerialFlash.read(address, buf, 256);
    if (is_erased(buf, 256)) break;
    address = address + 256;
  }
  if (address >= chipsize) {
    Serial.println("  error, unable to find any blank space!");
    return false;
  }
  for (int i=0; i < 256; i += 8) {
    create_signature(address + i, sig + i);
  }
  Serial.print("  write 256 bytes at ");
  Serial.println(address);
  Serial.flush();
  SerialFlash.write(address, sig, 256);
  usec = micros();
  if (SerialFlash.ready()) {
    Serial.println("  error, chip did not become busy after write");
    return false;
  }
  SerialFlash.read(0, buf2, 8); // read while busy writing
  while (!SerialFlash.ready()) ; // wait
  usec = micros() - usec;
  Serial.print("  write time was ");
  Serial.print(usec);
  Serial.println(" microseconds.");
  SerialFlash.read(address, buf, 256);
  if (memcmp(buf, sig, 256) != 0) {
    Serial.println("  error writing to flash");
    Serial.print("  Read this: ");
    printbuf(buf, 256);
    Serial.print("  Expected:  ");
    printbuf(sig, 256);
    return false;
  }
  create_signature(0, sig);
  if (memcmp(buf2, sig, 8) != 0) {
    Serial.println("  error, incorrect read while writing");
    Serial.print("  Read this: ");
    printbuf(buf2, 256);
    Serial.print("  Expected:  ");
    printbuf(sig, 256);
    return false;
  }
  Serial.print("  read-while-writing: ");
  printbuf(buf2, 8);
  Serial.println("  test passed, good read while writing");



  // Erase a block and read while erase in progress
  if (chipsize >= 262144 + blocksize + testIncrement) {
    Serial.println();
    Serial.println("Checking Read-While-Erase (Erase Suspend)");
    memset(buf, 0, sizeof(buf));
    memset(sig, 0, sizeof(sig));
    memset(buf2, 0, sizeof(buf2));
    SerialFlash.eraseBlock(262144);
    usec = micros();
    delayMicroseconds(50);
    if (SerialFlash.ready()) {
      Serial.println("  error, chip did not become busy after erase");
      return false;
    }
    SerialFlash.read(0, buf2, 8); // read while busy writing
    while (!SerialFlash.ready()) ; // wait
    usec = micros() - usec;
    Serial.print("  erase time was ");
    Serial.print(usec);
    Serial.println(" microseconds.");
    // read all signatures, check ones in this block got
    // erased, and all the others are still intact
    address = 0;
    first = true;
    while (address < chipsize) {
      SerialFlash.read(address, buf, 8);
      if (address >= 262144 && address < 262144 + blocksize) {
        if (is_erased(buf, 8) == false) {
          Serial.print("  error in erasing at ");
          Serial.println(address);
          Serial.print("  Read this: ");
          printbuf(buf, 8);
          return false;
        }
      } else {
        create_signature(address, sig);
        if (equal_signatures(buf, sig) == false) {
          Serial.print("  error in signature at ");
          Serial.println(address);
          Serial.print("  Read this: ");
          printbuf(buf, 8);
          Serial.print("  Expected:  ");
          printbuf(sig, 8);
          return false;
        }
      }
      if (first) {
        address = address + (testIncrement - 8);
        first = false;
      } else {
        address = address + 8;
        first = true;
      }
    }
    Serial.print("  erase correctly erased ");
    Serial.print(blocksize);
    Serial.println(" bytes");
    // now check if the data we read during erase is good
    create_signature(0, sig);
    if (memcmp(buf2, sig, 8) != 0) {
      Serial.println("  error, incorrect read while erasing");
      Serial.print("  Read this: ");
      printbuf(buf2, 256);
      Serial.print("  Expected:  ");
      printbuf(sig, 256);
      return false;
    }
    Serial.print("  read-while-erasing: ");
    printbuf(buf2, 8);
    Serial.println("  test passed, good read while erasing");

  } else {
    Serial.println("Skip Read-While-Erase, this chip is too small");
  }




  return true;
}