@@ -4523,6 +4523,226 @@ static int nand_set_ecc_soft_ops(struct mtd_info *mtd)
4523
4523
}
4524
4524
}
4525
4525
4526
+ /**
4527
+ * nand_check_ecc_caps - check the sanity of preset ECC settings
4528
+ * @chip: nand chip info structure
4529
+ * @caps: ECC caps info structure
4530
+ * @oobavail: OOB size that the ECC engine can use
4531
+ *
4532
+ * When ECC step size and strength are already set, check if they are supported
4533
+ * by the controller and the calculated ECC bytes fit within the chip's OOB.
4534
+ * On success, the calculated ECC bytes is set.
4535
+ */
4536
+ int nand_check_ecc_caps (struct nand_chip * chip ,
4537
+ const struct nand_ecc_caps * caps , int oobavail )
4538
+ {
4539
+ struct mtd_info * mtd = nand_to_mtd (chip );
4540
+ const struct nand_ecc_step_info * stepinfo ;
4541
+ int preset_step = chip -> ecc .size ;
4542
+ int preset_strength = chip -> ecc .strength ;
4543
+ int nsteps , ecc_bytes ;
4544
+ int i , j ;
4545
+
4546
+ if (WARN_ON (oobavail < 0 ))
4547
+ return - EINVAL ;
4548
+
4549
+ if (!preset_step || !preset_strength )
4550
+ return - ENODATA ;
4551
+
4552
+ nsteps = mtd -> writesize / preset_step ;
4553
+
4554
+ for (i = 0 ; i < caps -> nstepinfos ; i ++ ) {
4555
+ stepinfo = & caps -> stepinfos [i ];
4556
+
4557
+ if (stepinfo -> stepsize != preset_step )
4558
+ continue ;
4559
+
4560
+ for (j = 0 ; j < stepinfo -> nstrengths ; j ++ ) {
4561
+ if (stepinfo -> strengths [j ] != preset_strength )
4562
+ continue ;
4563
+
4564
+ ecc_bytes = caps -> calc_ecc_bytes (preset_step ,
4565
+ preset_strength );
4566
+ if (WARN_ON_ONCE (ecc_bytes < 0 ))
4567
+ return ecc_bytes ;
4568
+
4569
+ if (ecc_bytes * nsteps > oobavail ) {
4570
+ pr_err ("ECC (step, strength) = (%d, %d) does not fit in OOB" ,
4571
+ preset_step , preset_strength );
4572
+ return - ENOSPC ;
4573
+ }
4574
+
4575
+ chip -> ecc .bytes = ecc_bytes ;
4576
+
4577
+ return 0 ;
4578
+ }
4579
+ }
4580
+
4581
+ pr_err ("ECC (step, strength) = (%d, %d) not supported on this controller" ,
4582
+ preset_step , preset_strength );
4583
+
4584
+ return - ENOTSUPP ;
4585
+ }
4586
+ EXPORT_SYMBOL_GPL (nand_check_ecc_caps );
4587
+
4588
+ /**
4589
+ * nand_match_ecc_req - meet the chip's requirement with least ECC bytes
4590
+ * @chip: nand chip info structure
4591
+ * @caps: ECC engine caps info structure
4592
+ * @oobavail: OOB size that the ECC engine can use
4593
+ *
4594
+ * If a chip's ECC requirement is provided, try to meet it with the least
4595
+ * number of ECC bytes (i.e. with the largest number of OOB-free bytes).
4596
+ * On success, the chosen ECC settings are set.
4597
+ */
4598
+ int nand_match_ecc_req (struct nand_chip * chip ,
4599
+ const struct nand_ecc_caps * caps , int oobavail )
4600
+ {
4601
+ struct mtd_info * mtd = nand_to_mtd (chip );
4602
+ const struct nand_ecc_step_info * stepinfo ;
4603
+ int req_step = chip -> ecc_step_ds ;
4604
+ int req_strength = chip -> ecc_strength_ds ;
4605
+ int req_corr , step_size , strength , nsteps , ecc_bytes , ecc_bytes_total ;
4606
+ int best_step , best_strength , best_ecc_bytes ;
4607
+ int best_ecc_bytes_total = INT_MAX ;
4608
+ int i , j ;
4609
+
4610
+ if (WARN_ON (oobavail < 0 ))
4611
+ return - EINVAL ;
4612
+
4613
+ /* No information provided by the NAND chip */
4614
+ if (!req_step || !req_strength )
4615
+ return - ENOTSUPP ;
4616
+
4617
+ /* number of correctable bits the chip requires in a page */
4618
+ req_corr = mtd -> writesize / req_step * req_strength ;
4619
+
4620
+ for (i = 0 ; i < caps -> nstepinfos ; i ++ ) {
4621
+ stepinfo = & caps -> stepinfos [i ];
4622
+ step_size = stepinfo -> stepsize ;
4623
+
4624
+ for (j = 0 ; j < stepinfo -> nstrengths ; j ++ ) {
4625
+ strength = stepinfo -> strengths [j ];
4626
+
4627
+ /*
4628
+ * If both step size and strength are smaller than the
4629
+ * chip's requirement, it is not easy to compare the
4630
+ * resulted reliability.
4631
+ */
4632
+ if (step_size < req_step && strength < req_strength )
4633
+ continue ;
4634
+
4635
+ if (mtd -> writesize % step_size )
4636
+ continue ;
4637
+
4638
+ nsteps = mtd -> writesize / step_size ;
4639
+
4640
+ ecc_bytes = caps -> calc_ecc_bytes (step_size , strength );
4641
+ if (WARN_ON_ONCE (ecc_bytes < 0 ))
4642
+ continue ;
4643
+ ecc_bytes_total = ecc_bytes * nsteps ;
4644
+
4645
+ if (ecc_bytes_total > oobavail ||
4646
+ strength * nsteps < req_corr )
4647
+ continue ;
4648
+
4649
+ /*
4650
+ * We assume the best is to meet the chip's requrement
4651
+ * with the least number of ECC bytes.
4652
+ */
4653
+ if (ecc_bytes_total < best_ecc_bytes_total ) {
4654
+ best_ecc_bytes_total = ecc_bytes_total ;
4655
+ best_step = step_size ;
4656
+ best_strength = strength ;
4657
+ best_ecc_bytes = ecc_bytes ;
4658
+ }
4659
+ }
4660
+ }
4661
+
4662
+ if (best_ecc_bytes_total == INT_MAX )
4663
+ return - ENOTSUPP ;
4664
+
4665
+ chip -> ecc .size = best_step ;
4666
+ chip -> ecc .strength = best_strength ;
4667
+ chip -> ecc .bytes = best_ecc_bytes ;
4668
+
4669
+ return 0 ;
4670
+ }
4671
+ EXPORT_SYMBOL_GPL (nand_match_ecc_req );
4672
+
4673
+ /**
4674
+ * nand_maximize_ecc - choose the max ECC strength available
4675
+ * @chip: nand chip info structure
4676
+ * @caps: ECC engine caps info structure
4677
+ * @oobavail: OOB size that the ECC engine can use
4678
+ *
4679
+ * Choose the max ECC strength that is supported on the controller, and can fit
4680
+ * within the chip's OOB. On success, the chosen ECC settings are set.
4681
+ */
4682
+ int nand_maximize_ecc (struct nand_chip * chip ,
4683
+ const struct nand_ecc_caps * caps , int oobavail )
4684
+ {
4685
+ struct mtd_info * mtd = nand_to_mtd (chip );
4686
+ const struct nand_ecc_step_info * stepinfo ;
4687
+ int step_size , strength , nsteps , ecc_bytes , corr ;
4688
+ int best_corr = 0 ;
4689
+ int best_step = 0 ;
4690
+ int best_strength , best_ecc_bytes ;
4691
+ int i , j ;
4692
+
4693
+ if (WARN_ON (oobavail < 0 ))
4694
+ return - EINVAL ;
4695
+
4696
+ for (i = 0 ; i < caps -> nstepinfos ; i ++ ) {
4697
+ stepinfo = & caps -> stepinfos [i ];
4698
+ step_size = stepinfo -> stepsize ;
4699
+
4700
+ /* If chip->ecc.size is already set, respect it */
4701
+ if (chip -> ecc .size && step_size != chip -> ecc .size )
4702
+ continue ;
4703
+
4704
+ for (j = 0 ; j < stepinfo -> nstrengths ; j ++ ) {
4705
+ strength = stepinfo -> strengths [j ];
4706
+
4707
+ if (mtd -> writesize % step_size )
4708
+ continue ;
4709
+
4710
+ nsteps = mtd -> writesize / step_size ;
4711
+
4712
+ ecc_bytes = caps -> calc_ecc_bytes (step_size , strength );
4713
+ if (WARN_ON_ONCE (ecc_bytes < 0 ))
4714
+ continue ;
4715
+
4716
+ if (ecc_bytes * nsteps > oobavail )
4717
+ continue ;
4718
+
4719
+ corr = strength * nsteps ;
4720
+
4721
+ /*
4722
+ * If the number of correctable bits is the same,
4723
+ * bigger step_size has more reliability.
4724
+ */
4725
+ if (corr > best_corr ||
4726
+ (corr == best_corr && step_size > best_step )) {
4727
+ best_corr = corr ;
4728
+ best_step = step_size ;
4729
+ best_strength = strength ;
4730
+ best_ecc_bytes = ecc_bytes ;
4731
+ }
4732
+ }
4733
+ }
4734
+
4735
+ if (!best_corr )
4736
+ return - ENOTSUPP ;
4737
+
4738
+ chip -> ecc .size = best_step ;
4739
+ chip -> ecc .strength = best_strength ;
4740
+ chip -> ecc .bytes = best_ecc_bytes ;
4741
+
4742
+ return 0 ;
4743
+ }
4744
+ EXPORT_SYMBOL_GPL (nand_maximize_ecc );
4745
+
4526
4746
/*
4527
4747
* Check if the chip configuration meet the datasheet requirements.
4528
4748
0 commit comments