Re: [PATCH] x86/mm: fix compilation error for unknown type name pgprot_t

2020-05-13 Thread Abhishek Sahu
On 4/27/2020 8:41 PM, Abhishek Sahu wrote:
> On 4/21/2020 11:18 AM, Abhishek Sahu wrote:
>> On 4/20/2020 10:14 PM, Logan Gunthorpe wrote:
>>> On 2020-04-20 2:22 a.m., Abhishek Sahu wrote:
>>>> commit 30796e18c299 ("x86/mm: introduce __set_memory_prot()")
>>>> added the function __set_memory_prot() which uses pgprot_t in
>>>> function prototype. The currently included header files in
>>>>  do not include type name
>>>> pgprot_t. The pgprot_t is defined in .
>>>>
>>>> Fixes: 30796e18c299 ("x86/mm: introduce __set_memory_prot()")
>>>> Signed-off-by: Abhishek Sahu 
>>>
>>> I assume this is only hit with a specific driver or something that
>>> includes set_memory.h without including pgtable_types.h before hand.
>>>
>>> It certainly compiles fine for me and the kbuild robot has had lots of
>>> time to test it with random configs.
>>>
>>> Reviewed-by: Logan Gunthorpe 
>>
>>   Thanks Logan.
>>
>>   Yes. The mainline is compiling fine with default config.
>>   This problem is coming while compiling Out of tree NVIDIA driver.
>>   But this problem can happen for the drivers which don't include
>>   . I am not sure if this problem will come with
>>   some other configs. Normally, the header files should not be
>>   dependent upon the callers.
>>
> 
>  Is it possible to get this patch merged for next rc of 5.7.
>  This issue started coming from 5.7-rc1.
> 

 Could someone help in reviewing and getting this merged in the
 next rc of 5.7 version. The NVIDIA driver compilation is failing
 from 5.7-rc1. This issue can happen for any other driver also
 which is not including  in the driver.

 Thanks,
 Abhishek


 


Re: [PATCH v2 0/2] PCI: device link quirk for NVIDIA GPU

2019-06-17 Thread Abhishek Sahu
On 6/14/2019 2:27 AM, Bjorn Helgaas wrote:
> On Thu, Jun 06, 2019 at 02:52:23PM +0530, Abhishek Sahu wrote:
>> * v2:
>>
>> 1. Make the pci device link helper function generic which can be
>>used for other multi-function PCI devices also.
>> 2. Minor changes in comments and commit logs.
>>
>> * v1:
>>
>> NVIDIA Turing GPU [1] has hardware support for USB Type-C and
>> VirtualLink [2]. The Turing GPU is a multi-function PCI device
>> which has the following four functions:
>>
>>  - VGA display controller (Function 0)
>>  - Audio controller (Function 1)
>>  - USB xHCI Host controller (Function 2)
>>  - USB Type-C USCI controller (Function 3)
>>
>> Currently NVIDIA and Nouveau GPU drivers only manage function 0.
>> Rest of the functions are managed by other drivers. These functions
>> internally in the hardware are tightly coupled. When function 0 goes
>> in runtime suspended state, then it will do power gating for most of
>> the hardware blocks. Some of these hardware blocks are used by
>> the other PCI functions, which leads to functional failure. In the
>> mainline kernel, the device link is present between
>> function 0 and function 1.  This patch series deals with creating
>> a similar kind of device link between function 0 and
>> functions 2 and 3.
>>
>> [1] 
>> https://www.nvidia.com/content/dam/en-zz/Solutions/design-visualization/technologies/turing-architecture/NVIDIA-Turing-Architecture-Whitepaper.pdf
>> [2] https://en.wikipedia.org/wiki/VirtualLink
>>
>> Abhishek Sahu (2):
>>   PCI: Code reorganization for creating device link
>>   PCI: Create device link for NVIDIA GPU
> 
> Applied to pci/misc for v5.3, thanks!

 Thanks Bjorn for your review and support!

 The runtime PM changes in USB Type-C USCI driver is also
 applied for v5.3

 https://marc.info/?l=linux-usb=155994544705901=2

 It will help in achieving run-time PM for Turing GPUs
 in v5.3.

 Regards,
 Abhishek


[PATCH v2 2/2] PCI: Create device link for NVIDIA GPU

2019-06-06 Thread Abhishek Sahu
NVIDIA Turing GPUs include hardware support for USB Type-C and
VirtualLink. It helps in delivering the power, display, and data
required to power VR headsets through a single USB Type-C connector.
The Turing GPU is a multi-function PCI device. It has the following
four functions:

- VGA display controller (Function 0)
- Audio controller (Function 1)
- USB xHCI Host controller (Function 2)
- USB Type-C USCI controller (Function 3)

The function 0 is tightly coupled with other functions in the
hardware. When function 0 goes in D3 state, then it will do
power gating for most of the hardware blocks. Some of these
hardware blocks are being used by other functions which
leads to functional failure. So if any of these functions (1/2/3)
are in D0 state, then function 0 should also be in D0 state.

'commit 07f4f97d7b4b ("vga_switcheroo: Use device link for
HDA controller")' creates the device link from function 1 to
function 0. A similar kind of device link needs to be created
between function 0 and functions 2 and 3 for NVIDIA Turing GPU.

This patch does the same and creates the required device links. It
will make function 0 to be D0 state if any other function is in D0
state.

Signed-off-by: Abhishek Sahu 
---
* Changes from v1:

  1. Minor changes in commit log
  2. used pci_create_device_link() helper function

 drivers/pci/quirks.c | 26 ++
 1 file changed, 26 insertions(+)

diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 379cd7fbcb12..b9182c4e5e42 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -4966,6 +4966,32 @@ DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_AMD, 
PCI_ANY_ID,
 DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
  PCI_CLASS_MULTIMEDIA_HD_AUDIO, 8, quirk_gpu_hda);
 
+/*
+ * Create device link for NVIDIA GPU with integrated USB xHCI Host
+ * controller to VGA.
+ */
+static void quirk_gpu_usb(struct pci_dev *usb)
+{
+   pci_create_device_link(usb, 2, 0, PCI_BASE_CLASS_DISPLAY, 16);
+}
+DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
+ PCI_CLASS_SERIAL_USB, 8, quirk_gpu_usb);
+
+/*
+ * Create device link for NVIDIA GPU with integrated Type-C UCSI controller
+ * to VGA. Currently there is no class code defined for UCSI device over PCI
+ * so using UNKNOWN class for now and it will be updated when UCSI
+ * over PCI gets a class code.
+ */
+#define PCI_CLASS_SERIAL_UNKNOWN   0x0c80
+static void quirk_gpu_usb_typec_ucsi(struct pci_dev *ucsi)
+{
+   pci_create_device_link(ucsi, 3, 0, PCI_BASE_CLASS_DISPLAY, 16);
+}
+DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
+ PCI_CLASS_SERIAL_UNKNOWN, 8,
+ quirk_gpu_usb_typec_ucsi);
+
 /*
  * Some IDT switches incorrectly flag an ACS Source Validation error on
  * completions for config read requests even though PCIe r4.0, sec
-- 
2.17.1



[PATCH v2 1/2] PCI: Code reorganization for creating device link

2019-06-06 Thread Abhishek Sahu
In Multi-function PCI device, one function (consumer) can have
hardware functional dependencies on another function (supplier).
Whenever the consumer is active and in D0 state, the supplier should
also be in D0 state. Currently, the device link is being created from
HDA function to VGA function for GPU's. This patch does minor code
reorganization. It introduces a helper function which creates device
link from consumer pci device to supplier pci device and uses this
helper function for creating device link from HDA to VGA. This helper
function can be used in future for creating device link from one
function to another function.

Signed-off-by: Abhishek Sahu 
---
* Changes from v1:

  1. Make the helper function generic which takes supplier class,
 class shift and function number also.
  2. Minor changes in commit log

 drivers/pci/quirks.c | 53 +++-
 1 file changed, 33 insertions(+), 20 deletions(-)

diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index a077f67fe1da..379cd7fbcb12 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -4916,35 +4916,48 @@ static void quirk_fsl_no_msi(struct pci_dev *pdev)
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_FREESCALE, PCI_ANY_ID, quirk_fsl_no_msi);
 
 /*
- * GPUs with integrated HDA controller for streaming audio to attached displays
- * need a device link from the HDA controller (consumer) to the GPU (supplier)
- * so that the GPU is powered up whenever the HDA controller is accessed.
- * The GPU and HDA controller are functions 0 and 1 of the same PCI device.
- * The device link stays in place until shutdown (or removal of the PCI device
- * if it's hotplugged).  Runtime PM is allowed by default on the HDA controller
- * to prevent it from permanently keeping the GPU awake.
+ * Multi-function PCI devices can have hardware functional dependencies from
+ * one function (consumer) to another function (supplier). Whenever the
+ * consumer is in D0 state, the supplier should also be in D0 state. This is
+ * a helper function which creates device link from the consumer to the
+ * supplier.  The device link stays in place until shutdown (or removal of
+ * the PCI device if it's hotplugged). Runtime PM is allowed by default on
+ * consumers to prevent it from permanently keeping the supplier awake.
  */
-static void quirk_gpu_hda(struct pci_dev *hda)
+static void pci_create_device_link(struct pci_dev *pdev, unsigned int consumer,
+  unsigned int supplier, unsigned int class,
+  unsigned int class_shift)
 {
-   struct pci_dev *gpu;
+   struct pci_dev *supplier_pdev;
 
-   if (PCI_FUNC(hda->devfn) != 1)
+   if (PCI_FUNC(pdev->devfn) != consumer)
return;
 
-   gpu = pci_get_domain_bus_and_slot(pci_domain_nr(hda->bus),
- hda->bus->number,
- PCI_DEVFN(PCI_SLOT(hda->devfn), 0));
-   if (!gpu || (gpu->class >> 16) != PCI_BASE_CLASS_DISPLAY) {
-   pci_dev_put(gpu);
+   supplier_pdev = pci_get_domain_bus_and_slot(pci_domain_nr(pdev->bus),
+   pdev->bus->number,
+   PCI_DEVFN(PCI_SLOT(pdev->devfn), supplier));
+   if (!supplier_pdev || (supplier_pdev->class >> class_shift) != class) {
+   pci_dev_put(supplier_pdev);
return;
}
 
-   if (!device_link_add(>dev, >dev,
-DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME))
-   pci_err(hda, "cannot link HDA to GPU %s\n", pci_name(gpu));
+   if (device_link_add(>dev, _pdev->dev,
+   DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME))
+   pci_info(pdev, "Linked with %s\n", pci_name(supplier_pdev));
+   else
+   pci_err(pdev, "Cannot link with %s\n", pci_name(supplier_pdev));
+
+   pm_runtime_allow(>dev);
+   pci_dev_put(supplier_pdev);
+}
 
-   pm_runtime_allow(>dev);
-   pci_dev_put(gpu);
+/*
+ * Create device link for GPUs with integrated HDA controller for streaming
+ * audio to attached displays.
+ */
+static void quirk_gpu_hda(struct pci_dev *hda)
+{
+   pci_create_device_link(hda, 1, 0, PCI_BASE_CLASS_DISPLAY, 16);
 }
 DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_ATI, PCI_ANY_ID,
  PCI_CLASS_MULTIMEDIA_HD_AUDIO, 8, quirk_gpu_hda);
-- 
2.17.1



[PATCH v2 0/2] PCI: device link quirk for NVIDIA GPU

2019-06-06 Thread Abhishek Sahu
* v2:

1. Make the pci device link helper function generic which can be
   used for other multi-function PCI devices also.
2. Minor changes in comments and commit logs.

* v1:

NVIDIA Turing GPU [1] has hardware support for USB Type-C and
VirtualLink [2]. The Turing GPU is a multi-function PCI device
which has the following four functions:

- VGA display controller (Function 0)
- Audio controller (Function 1)
- USB xHCI Host controller (Function 2)
- USB Type-C USCI controller (Function 3)

Currently NVIDIA and Nouveau GPU drivers only manage function 0.
Rest of the functions are managed by other drivers. These functions
internally in the hardware are tightly coupled. When function 0 goes
in runtime suspended state, then it will do power gating for most of
the hardware blocks. Some of these hardware blocks are used by
the other PCI functions, which leads to functional failure. In the
mainline kernel, the device link is present between
function 0 and function 1.  This patch series deals with creating
a similar kind of device link between function 0 and
functions 2 and 3.

[1] 
https://www.nvidia.com/content/dam/en-zz/Solutions/design-visualization/technologies/turing-architecture/NVIDIA-Turing-Architecture-Whitepaper.pdf
[2] https://en.wikipedia.org/wiki/VirtualLink

Abhishek Sahu (2):
  PCI: Code reorganization for creating device link
  PCI: Create device link for NVIDIA GPU

 drivers/pci/quirks.c | 79 +---
 1 file changed, 59 insertions(+), 20 deletions(-)

-- 
2.17.1



Re: [PATCH 2/2] PCI: Create device link for NVIDIA GPU

2019-06-04 Thread Abhishek Sahu



On 6/3/2019 10:52 PM, Bjorn Helgaas wrote:
> [+cc Rafael, just FYI]
> 
> On Mon, Jun 03, 2019 at 01:30:51PM +0530, Abhishek Sahu wrote:
>> On 6/1/2019 2:09 AM, Bjorn Helgaas wrote:
>>> On Fri, May 31, 2019 at 10:31:09AM +0530, Abhishek Sahu wrote:
>>>> NVIDIA Turing GPUs include hardware support for USB Type-C and
>>>> VirtualLink. It helps in delivering the power, display, and data
>>>> required to power VR headsets through a single USB Type-C connector.
>>>> The Turing GPU is a multi-function PCI device has the following
>>>> four functions:
>>>>
>>>>- VGA display controller (Function 0)
>>>>- Audio controller (Function 1)
>>>>- USB xHCI Host controller (Function 2)
>>>>- USB Type-C USCI controller (Function 3)
>>>>
>>>> The function 0 is tightly coupled with other functions in the
>>>> hardware. When function 0 goes in runtime suspended state,
>>>> then it will do power gating for most of the hardware blocks.
>>>> Some of these hardware blocks are used by other functions which
>>>> leads to functional failure. So if any of these functions (1/2/3)
>>>> are active, then function 0 should also be in active state.
>>>
>>>> 'commit 07f4f97d7b4b ("vga_switcheroo: Use device link for
>>>> HDA controller")' creates the device link from function 1 to
>>>> function 0. A similar kind of device link needs to be created
>>>> between function 0 and functions 2 and 3 for NVIDIA Turing GPU.
>>>
>>> I can't point to language that addresses this, but this sounds like a
>>> case of the GPU not conforming to the PCI spec.  The general
>>> assumption is that the OS should be able to discover everything it
>>> needs to do power management directly from the architected PCI config
>>> space.
>>
>>  The GPU is following PCIe spec but following is the implementation
>>  from HW side
> 
> Unless you can find spec language that talks about D-state
> dependencies between functions, I claim this is not following the
> PCIe spec.  For example, PCIe r5.0, sec 1.4, says "the PCI/PCIe
> hardware/software model includes architectural constructs necessary to
> discover, configure, and use a Function, without needing Function-
> specific knowledge." Sec 5.1 says "D states are associated with a
> particular Function" and "PM provides ... a mechanism to identify
> power management capabilities of a given Function [and] the ability to
> transition a Function into a certain power management state."
> 

 Thanks Bjorn. Here in case of GPU's these functions are not
 completely independent so it is not following PCIe spec in
 that aspect.

> If there *is* something about dependencies between functions in the
> spec, we should improve the generic PCI core to pay attention to that,
> and then we wouldn't need this quirk.
> 
> If the spec doesn't provide a way to discover them, these dependencies
> are exceptions from the spec, and we have to handle them as hardware
> defects, using quirks like this.  That's fine, but let's not pretend
> that this is a conforming device and that adding quirks is the
> expected process.  Just call a spade a spade and say we're working
> around a defect in this particular device.
> 

 Yes. I am agree with that we need to be very careful in
 adding quirks like this. I will communicate the same to
 HW team so they can explore other options to handle this
 in HW design side for future chips.

> I think the best path forward would be to add this quirk for the
> existing device, and then pursue a spec change to add something like
> a new PCIe capability to describe the dependencies.  Then we could
> enhance the PCI core once and power management for future devices
> would "Just Work" without having to add quirks.
> 

 Yes. It will be long term process. If other HW has similar
 requirement then it would be good to have this.

 Regards,
 Abhishek



Re: [PATCH 1/2] PCI: Code reorganization for VGA device link

2019-06-04 Thread Abhishek Sahu



On 6/3/2019 10:45 PM, Bjorn Helgaas wrote:
> [+cc Lukas]
> 
> On Fri, May 31, 2019 at 10:31:08AM +0530, Abhishek Sahu wrote:
>> This patch does minor code reorganization. It introduces a helper
>> function which creates device link from the non-VGA controller
>> (consumer) to the VGA (supplier) and uses this helper function for
>> creating device link from integrated HDA controller to VGA. It will
>> help in subsequent patches which require a similar kind of device
>> link from USB/Type-C USCI controller to VGA.
>>
>> Signed-off-by: Abhishek Sahu 
>> ---
>>  drivers/pci/quirks.c | 44 +---
>>  1 file changed, 29 insertions(+), 15 deletions(-)
>>
>> diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
>> index a077f67fe1da..a20f7771a323 100644
>> --- a/drivers/pci/quirks.c
>> +++ b/drivers/pci/quirks.c
>> @@ -4916,36 +4916,50 @@ static void quirk_fsl_no_msi(struct pci_dev *pdev)
>>  DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_FREESCALE, PCI_ANY_ID, 
>> quirk_fsl_no_msi);
>>  
>>  /*
>> - * GPUs with integrated HDA controller for streaming audio to attached 
>> displays
>> - * need a device link from the HDA controller (consumer) to the GPU 
>> (supplier)
>> - * so that the GPU is powered up whenever the HDA controller is accessed.
>> - * The GPU and HDA controller are functions 0 and 1 of the same PCI device.
>> - * The device link stays in place until shutdown (or removal of the PCI 
>> device
>> - * if it's hotplugged).  Runtime PM is allowed by default on the HDA 
>> controller
>> - * to prevent it from permanently keeping the GPU awake.
>> + * GPUs can be multi-function PCI device which can contain controllers other
>> + * than VGA (like Audio, USB, etc.). Internally in the hardware, these 
>> non-VGA
>> + * controllers are tightly coupled with VGA controller. Whenever these
>> + * controllers are runtime active, the VGA controller should also be in 
>> active
>> + * state. Normally, in these GPUs, the VGA controller is present at 
>> function 0.
>> + *
>> + * This is a helper function which creates device link from the non-VGA
>> + * controller (consumer) to the VGA (supplier). The device link stays in 
>> place
>> + * until shutdown (or removal of the PCI device if it's hotplugged).
>> + * Runtime PM is allowed by default on these non-VGA controllers to prevent
>> + * it from permanently keeping the GPU awake.
>>   */
>> -static void quirk_gpu_hda(struct pci_dev *hda)
>> +static void
>> +pci_create_device_link_with_vga(struct pci_dev *pdev, unsigned int devfn)
> 
> There's nothing in this functionality that depends on VGA, so let's
> remove "GPU, "VGA", etc from the description, the function name, the
> local variable name, and the log message.  Maybe you need to allow the

 Thanks. Then we can make this function generic where we can pass
 device link supplier and supplier pci class mask. It will help
 in creating device link from one function (other than 0 also) to
 any another function. Later on, same can be used by non
 GPUs devices also, if required.

> caller to supply the class type (PCI_BASE_CLASS_DISPLAY for current
> users, but Lukas mentioned a NIC that might be able to use this too).
> 
> Follow the prevailing indentation style, with return type and function
> name on the same line, i.e.,
> 

 I will fix in v2.

>   static void pci_create_device_link(...)
> 
>>  {
>>  struct pci_dev *gpu;
>>  
>> -if (PCI_FUNC(hda->devfn) != 1)
>> +if (PCI_FUNC(pdev->devfn) != devfn)
>>  return;
>>  
>> -gpu = pci_get_domain_bus_and_slot(pci_domain_nr(hda->bus),
>> -  hda->bus->number,
>> -  PCI_DEVFN(PCI_SLOT(hda->devfn), 0));
>> +gpu = pci_get_domain_bus_and_slot(pci_domain_nr(pdev->bus),
>> +  pdev->bus->number,
>> +  PCI_DEVFN(PCI_SLOT(pdev->devfn), 0));
>>  if (!gpu || (gpu->class >> 16) != PCI_BASE_CLASS_DISPLAY) {
>>  pci_dev_put(gpu);
>>  return;
>>  }
>>  
>> -if (!device_link_add(>dev, >dev,
>> +if (!device_link_add(>dev, >dev,
>>   DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME))
>> -pci_err(hda, "cannot link HDA to GPU %s\n", pci_name(gpu));
>> +pci_err(pdev, "cannot link with VGA %s\n", pci_name(gpu));
> 
> I think we

Re: [PATCH 2/2] PCI: Create device link for NVIDIA GPU

2019-06-03 Thread Abhishek Sahu
 Thanks Bjorn for your review.

On 6/1/2019 2:09 AM, Bjorn Helgaas wrote:
> [+cc Lukas, author of 07f4f97d7b4b ("vga_switcheroo: Use device link
> for HDA controller")]
> 
> On Fri, May 31, 2019 at 10:31:09AM +0530, Abhishek Sahu wrote:
>> NVIDIA Turing GPUs include hardware support for USB Type-C and
>> VirtualLink. It helps in delivering the power, display, and data
>> required to power VR headsets through a single USB Type-C connector.
>> The Turing GPU is a multi-function PCI device has the following
>> four functions:
>>
>>  - VGA display controller (Function 0)
>>  - Audio controller (Function 1)
>>  - USB xHCI Host controller (Function 2)
>>  - USB Type-C USCI controller (Function 3)
>>
>> The function 0 is tightly coupled with other functions in the
>> hardware. When function 0 goes in runtime suspended state,
> 
> "Runtime suspended" is a Linux concept, not a PCI concept.  Please
> replace this with the appropriate PCI term, e.g., "D3hot" or whatever
> it is.

 Sure. I will change this.

> 
>> then it will do power gating for most of the hardware blocks.
>> Some of these hardware blocks are used by other functions which
>> leads to functional failure. So if any of these functions (1/2/3)
>> are active, then function 0 should also be in active state.
> 
> Instead of "active" and "active state", please use the specific states
> required in terms of PCI.

 Sure. I will use specific states name.

> 
>> 'commit 07f4f97d7b4b ("vga_switcheroo: Use device link for
>> HDA controller")' creates the device link from function 1 to
>> function 0. A similar kind of device link needs to be created
>> between function 0 and functions 2 and 3 for NVIDIA Turing GPU.
> 
> I can't point to language that addresses this, but this sounds like a
> case of the GPU not conforming to the PCI spec.  The general
> assumption is that the OS should be able to discover everything it
> needs to do power management directly from the architected PCI config
> space.

 The GPU is following PCIe spec but following is the implementation
 from HW side

 Normal GPU has VGA and Audio controller in which Audio is dependent
 upon VGA. For these GPU, the VGA is managed by GPU driver and Audio is
 managed by sound driver. Now the VGA driver can go to D3hot while
 Audio still in D0 if there was no device link (added in commit
 07f4f97d7b4b). It would lead to Audio functionality failure. The
 device link is making sure that GPU is in D0 while Audio is D0.

 Now the NVIDIA Turing GPU has one USB Type-C port mainly to support
 virtual reality headset. With default mode, this USB port will act as
 normal USB port and any USB device can be connected over it. It will
 be managed with PCI xHCI USB controller driver.  Now, to support VR
 headset, This USB Type-C alternate mode is going to be used. This
 alternate mode setting will be managed with [1] and [2] which is part
 of 5.2-rc1. More detail for this is available in [3] and virtual link
 open industry standard [4].  These VR frame-buffers are internally
 going to be rendered by GPU only and managed by function 0 (VGA)
 driver. Now, from HW side, we need to make sure VGA is in D0 while any
 of other functions are in D0.

 [1]
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/usb/typec/altmodes/nvidia.c
 [2]
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/i2c/busses/i2c-nvidia-gpu.c
 [3]
https://fullcirclemagazine.org/2019/04/30/nvidia-creates-free-virtual-link-driver-for-linux/
 [4] https://sites.google.com/view/virtuallink-consortium/home

> 
> It is definitely not ideal to have to add quirks like this for devices
> designed this way.  Such quirks force us to do otherwise unnecessary
> OS updates as new devices are released.

 I can understand but this is the HW requirement. To support,
 VR headset in GPU, the HW has provided USB Type-C. Now, from
 SW side, we are working on supporting this with runtime PM.
 Currently runtime PM is not possible without adding the
 dependencies between different functions.

> 
> If all the devices in a multi-function device were connected
> intimately enough that they all had to be managed by the same driver,
> I could imagine putting these non-discoverable dependencies in the
> driver.  But these devices don't seem to be related in that way.
> > If there *is* spec language that allows dependencies like this, please
> include the citation in your commit log.
> 

 The PCIe specification treats each function separately but GPU case is
 different. So, it won't be part of PCIe spec. in GPU, the different
 kind of devices are internally coupled in HW but still needs to be
 managed by different driver.

>&

[PATCH 1/2] PCI: Code reorganization for VGA device link

2019-05-30 Thread Abhishek Sahu
This patch does minor code reorganization. It introduces a helper
function which creates device link from the non-VGA controller
(consumer) to the VGA (supplier) and uses this helper function for
creating device link from integrated HDA controller to VGA. It will
help in subsequent patches which require a similar kind of device
link from USB/Type-C USCI controller to VGA.

Signed-off-by: Abhishek Sahu 
---
 drivers/pci/quirks.c | 44 +---
 1 file changed, 29 insertions(+), 15 deletions(-)

diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index a077f67fe1da..a20f7771a323 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -4916,36 +4916,50 @@ static void quirk_fsl_no_msi(struct pci_dev *pdev)
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_FREESCALE, PCI_ANY_ID, quirk_fsl_no_msi);
 
 /*
- * GPUs with integrated HDA controller for streaming audio to attached displays
- * need a device link from the HDA controller (consumer) to the GPU (supplier)
- * so that the GPU is powered up whenever the HDA controller is accessed.
- * The GPU and HDA controller are functions 0 and 1 of the same PCI device.
- * The device link stays in place until shutdown (or removal of the PCI device
- * if it's hotplugged).  Runtime PM is allowed by default on the HDA controller
- * to prevent it from permanently keeping the GPU awake.
+ * GPUs can be multi-function PCI device which can contain controllers other
+ * than VGA (like Audio, USB, etc.). Internally in the hardware, these non-VGA
+ * controllers are tightly coupled with VGA controller. Whenever these
+ * controllers are runtime active, the VGA controller should also be in active
+ * state. Normally, in these GPUs, the VGA controller is present at function 0.
+ *
+ * This is a helper function which creates device link from the non-VGA
+ * controller (consumer) to the VGA (supplier). The device link stays in place
+ * until shutdown (or removal of the PCI device if it's hotplugged).
+ * Runtime PM is allowed by default on these non-VGA controllers to prevent
+ * it from permanently keeping the GPU awake.
  */
-static void quirk_gpu_hda(struct pci_dev *hda)
+static void
+pci_create_device_link_with_vga(struct pci_dev *pdev, unsigned int devfn)
 {
struct pci_dev *gpu;
 
-   if (PCI_FUNC(hda->devfn) != 1)
+   if (PCI_FUNC(pdev->devfn) != devfn)
return;
 
-   gpu = pci_get_domain_bus_and_slot(pci_domain_nr(hda->bus),
- hda->bus->number,
- PCI_DEVFN(PCI_SLOT(hda->devfn), 0));
+   gpu = pci_get_domain_bus_and_slot(pci_domain_nr(pdev->bus),
+ pdev->bus->number,
+ PCI_DEVFN(PCI_SLOT(pdev->devfn), 0));
if (!gpu || (gpu->class >> 16) != PCI_BASE_CLASS_DISPLAY) {
pci_dev_put(gpu);
return;
}
 
-   if (!device_link_add(>dev, >dev,
+   if (!device_link_add(>dev, >dev,
 DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME))
-   pci_err(hda, "cannot link HDA to GPU %s\n", pci_name(gpu));
+   pci_err(pdev, "cannot link with VGA %s\n", pci_name(gpu));
 
-   pm_runtime_allow(>dev);
+   pm_runtime_allow(>dev);
pci_dev_put(gpu);
 }
+
+/*
+ * Create device link for GPUs with integrated HDA controller for streaming
+ * audio to attached displays.
+ */
+static void quirk_gpu_hda(struct pci_dev *hda)
+{
+   pci_create_device_link_with_vga(hda, 1);
+}
 DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_ATI, PCI_ANY_ID,
  PCI_CLASS_MULTIMEDIA_HD_AUDIO, 8, quirk_gpu_hda);
 DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_AMD, PCI_ANY_ID,
-- 
2.17.1



[PATCH 2/2] PCI: Create device link for NVIDIA GPU

2019-05-30 Thread Abhishek Sahu
NVIDIA Turing GPUs include hardware support for USB Type-C and
VirtualLink. It helps in delivering the power, display, and data
required to power VR headsets through a single USB Type-C connector.
The Turing GPU is a multi-function PCI device has the following
four functions:

- VGA display controller (Function 0)
- Audio controller (Function 1)
- USB xHCI Host controller (Function 2)
- USB Type-C USCI controller (Function 3)

The function 0 is tightly coupled with other functions in the
hardware. When function 0 goes in runtime suspended state,
then it will do power gating for most of the hardware blocks.
Some of these hardware blocks are used by other functions which
leads to functional failure. So if any of these functions (1/2/3)
are active, then function 0 should also be in active state.
'commit 07f4f97d7b4b ("vga_switcheroo: Use device link for
HDA controller")' creates the device link from function 1 to
function 0. A similar kind of device link needs to be created
between function 0 and functions 2 and 3 for NVIDIA Turing GPU.

This patch does the same and create the required device links. It
will make function 0 to be runtime PM active if other functions
are still active.

Signed-off-by: Abhishek Sahu 
---
 drivers/pci/quirks.c | 23 +++
 1 file changed, 23 insertions(+)

diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index a20f7771a323..afdbc199efc5 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -4967,6 +4967,29 @@ DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_AMD, 
PCI_ANY_ID,
 DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
  PCI_CLASS_MULTIMEDIA_HD_AUDIO, 8, quirk_gpu_hda);
 
+/* Create device link for NVIDIA GPU with integrated USB controller to VGA. */
+static void quirk_gpu_usb(struct pci_dev *usb)
+{
+   pci_create_device_link_with_vga(usb, 2);
+}
+DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
+ PCI_CLASS_SERIAL_USB, 8, quirk_gpu_usb);
+
+/*
+ * Create device link for NVIDIA GPU with integrated Type-C UCSI controller
+ * to VGA. Currently there is no class code defined for UCSI device over PCI
+ * so using UNKNOWN class for now and it will be updated when UCSI
+ * over PCI gets a class code.
+ */
+#define PCI_CLASS_SERIAL_UNKNOWN   0x0c80
+static void quirk_gpu_usb_typec_ucsi(struct pci_dev *ucsi)
+{
+   pci_create_device_link_with_vga(ucsi, 3);
+}
+DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
+ PCI_CLASS_SERIAL_UNKNOWN, 8,
+ quirk_gpu_usb_typec_ucsi);
+
 /*
  * Some IDT switches incorrectly flag an ACS Source Validation error on
  * completions for config read requests even though PCIe r4.0, sec
-- 
2.17.1



[PATCH 0/2] PCI: device link quirk for NVIDIA GPU

2019-05-30 Thread Abhishek Sahu
NVIDIA Turing GPU [1] has hardware support for USB Type-C and
VirtualLink [2]. The Turing GPU is a multi-function PCI device
which has the following four functions:

- VGA display controller (Function 0)
- Audio controller (Function 1)
- USB xHCI Host controller (Function 2)
- USB Type-C USCI controller (Function 3)

Currently NVIDIA and Nouveau GPU drivers only manage function 0.
Rest of the functions are managed by other drivers. These functions
internally in the hardware are tightly coupled. When function 0 goes
in runtime suspended state, then it will do power gating for most of
the hardware blocks. Some of these hardware blocks are used by
the other PCI functions, which leads to functional failure. In the
mainline kernel, the device link is present between
function 0 and function 1.  This patch series deals with creating
a similar kind of device link between function 0 and
functions 2 and 3.

[1] 
https://www.nvidia.com/content/dam/en-zz/Solutions/design-visualization/technologies/turing-architecture/NVIDIA-Turing-Architecture-Whitepaper.pdf
[2] https://en.wikipedia.org/wiki/VirtualLink

Abhishek Sahu (2):
  PCI: Code reorganization for VGA device link
  PCI: Create device link for NVIDIA GPU

 drivers/pci/quirks.c | 67 ++--
 1 file changed, 52 insertions(+), 15 deletions(-)

-- 
2.17.1



Re: [PATCH 2/5] mtd: rawnand: qcom: remove driver specific block_markbad function

2018-11-08 Thread Abhishek Sahu

On 2018-11-04 21:26, Boris Brezillon wrote:

Hi Abhishek,

On Fri, 20 Jul 2018 15:03:48 +0200
Boris Brezillon  wrote:


On Fri, 20 Jul 2018 17:46:38 +0530
Abhishek Sahu  wrote:

> Hi Boris,
>
> On 2018-07-19 03:13, Boris Brezillon wrote:
> > On Wed, 18 Jul 2018 23:23:50 +0200
> > Miquel Raynal  wrote:
> >
> >> Boris,
> >>
> >> Can you please check the change in qcom_nandc_write_oob() is
> >> valid? I think it is but as this is a bit of a hack I prefer double
> >> checking.
> >
> > Indeed, it's hack-ish.
> >
> >>
> >> Thanks,
> >> Miquèl
> >>
> >>
> >> Abhishek Sahu  wrote on Fri,  6 Jul 2018
> >> 13:21:56 +0530:
> >>
> >> > The NAND base layer calls write_oob() by setting bytes at
> >> > chip->badblockpos with value non 0xFF for updating bad block status.
> >> > The QCOM NAND controller skips the bad block bytes while doing normal
> >> > write with ECC enabled. When initial support for this driver was
> >> > added, the driver specific function was added temporarily for
> >> > block_markbad() with assumption to change for raw read in NAND base
> >> > layer. Moving to raw read for block_markbad() seems to take more time
> >> > so this patch removes driver specific block_markbad() function by
> >> > using following HACK in write_oob() function.
> >> >
> >> > Check for BBM bytes in OOB and accordingly do raw write for updating
> >> > BBM bytes in NAND flash or normal write for updating available OOB
> >> > bytes.
> >
> > Why don't we change that instead of patching the qcom driver to guess
> > when the core tries to mark a block bad? If you're afraid of breaking
> > existing drivers that might rely on the "write/read BBM in non-raw
> > mode" solution (I'm sure some drivers are), you can always add a new
> > flag in chip->options (NAND_ACCESS_BBM_IN_RAW_MODE) and only use raw
> > accessors when this flag is set.
> >
>
>   We started with that Only
>
>   http://patchwork.ozlabs.org/patch/508565/
>
>   and since we didn't conclude, we went for driver
>   specific bad block check and mark bad block functions.
>
>   Now, we wanted to get rid of driver specific functions
>
>   1. For bad block check, we found the way to get the BBM bytes
>  with ECC read. Controller updates BBM in separate register
>  which we can read and update the same in OOB. Patch #1 of
>  series does the same.
>
>   2. For bad block mark, there is no way to update in ECC mode
>  that's why we went for HACK to get rid of driver specific
>  function.
>
>   If adding flag is fine now then this HACK won't be required.

Yep. I'm fine with that. Can you rebase the patch you pointed out on 
top

of nand/next and move the flag to chip->options instead of
chip->bbt_options + prefix it with NAND_ instead of NAND_BBT_?


I'm currently trying to get rid of chip->block_bad() (now placed in
chip->legacy.block_bad()), and I wanted to know if you were still
planning to submit the changes we discussed in this thread. If you
don't have time, please let me know and I'll try to do it.



 Sorry Boris, I couldn't work on these patches.

 Currently, I am working on non open source projects so
 I can't submit any patches in open source till this project
 completion due to legal guidelines.

 If this is urgent then you can try. I will help in
 QCOM related stuffs and testing.

 Thanks,
 Abhishek



Re: [PATCH 2/5] mtd: rawnand: qcom: remove driver specific block_markbad function

2018-11-08 Thread Abhishek Sahu

On 2018-11-04 21:26, Boris Brezillon wrote:

Hi Abhishek,

On Fri, 20 Jul 2018 15:03:48 +0200
Boris Brezillon  wrote:


On Fri, 20 Jul 2018 17:46:38 +0530
Abhishek Sahu  wrote:

> Hi Boris,
>
> On 2018-07-19 03:13, Boris Brezillon wrote:
> > On Wed, 18 Jul 2018 23:23:50 +0200
> > Miquel Raynal  wrote:
> >
> >> Boris,
> >>
> >> Can you please check the change in qcom_nandc_write_oob() is
> >> valid? I think it is but as this is a bit of a hack I prefer double
> >> checking.
> >
> > Indeed, it's hack-ish.
> >
> >>
> >> Thanks,
> >> Miquèl
> >>
> >>
> >> Abhishek Sahu  wrote on Fri,  6 Jul 2018
> >> 13:21:56 +0530:
> >>
> >> > The NAND base layer calls write_oob() by setting bytes at
> >> > chip->badblockpos with value non 0xFF for updating bad block status.
> >> > The QCOM NAND controller skips the bad block bytes while doing normal
> >> > write with ECC enabled. When initial support for this driver was
> >> > added, the driver specific function was added temporarily for
> >> > block_markbad() with assumption to change for raw read in NAND base
> >> > layer. Moving to raw read for block_markbad() seems to take more time
> >> > so this patch removes driver specific block_markbad() function by
> >> > using following HACK in write_oob() function.
> >> >
> >> > Check for BBM bytes in OOB and accordingly do raw write for updating
> >> > BBM bytes in NAND flash or normal write for updating available OOB
> >> > bytes.
> >
> > Why don't we change that instead of patching the qcom driver to guess
> > when the core tries to mark a block bad? If you're afraid of breaking
> > existing drivers that might rely on the "write/read BBM in non-raw
> > mode" solution (I'm sure some drivers are), you can always add a new
> > flag in chip->options (NAND_ACCESS_BBM_IN_RAW_MODE) and only use raw
> > accessors when this flag is set.
> >
>
>   We started with that Only
>
>   http://patchwork.ozlabs.org/patch/508565/
>
>   and since we didn't conclude, we went for driver
>   specific bad block check and mark bad block functions.
>
>   Now, we wanted to get rid of driver specific functions
>
>   1. For bad block check, we found the way to get the BBM bytes
>  with ECC read. Controller updates BBM in separate register
>  which we can read and update the same in OOB. Patch #1 of
>  series does the same.
>
>   2. For bad block mark, there is no way to update in ECC mode
>  that's why we went for HACK to get rid of driver specific
>  function.
>
>   If adding flag is fine now then this HACK won't be required.

Yep. I'm fine with that. Can you rebase the patch you pointed out on 
top

of nand/next and move the flag to chip->options instead of
chip->bbt_options + prefix it with NAND_ instead of NAND_BBT_?


I'm currently trying to get rid of chip->block_bad() (now placed in
chip->legacy.block_bad()), and I wanted to know if you were still
planning to submit the changes we discussed in this thread. If you
don't have time, please let me know and I'll try to do it.



 Sorry Boris, I couldn't work on these patches.

 Currently, I am working on non open source projects so
 I can't submit any patches in open source till this project
 completion due to legal guidelines.

 If this is urgent then you can try. I will help in
 QCOM related stuffs and testing.

 Thanks,
 Abhishek



Re: [PATCH 5/5] mtd: rawnand: qcom: reorganization by removing read/write helpers

2018-07-28 Thread Abhishek Sahu

On 2018-07-19 03:24, Boris Brezillon wrote:

On Fri,  6 Jul 2018 13:21:59 +0530
Abhishek Sahu  wrote:


Driver does not send the commands to NAND device for page
read/write operations in ->cmdfunc(). It just does some
minor variable initialization and rest of the things
are being done in actual ->read/write_oob[_raw].

The generic helper function calls for invoking commands during
page read/write are making this driver complicated. For QCOM NAND
driver, ->cmdfunc() does minor part of initialization and rest of
the initialization is performed by actual page read/write
functions. Also, ->read/write_oob() does not calls helper
function and all the initialization is being done in
->read/write_oob() itself.


This sounds hazardous in the long run. Some vendor specific commands
are re-using the READ0/READSTART semantic to read particular
registers/OTP sections programmed at flash production time. For these
operations, we don't want to go through the regular
chip->ecc.read_page[_raw]() hooks, and instead use
->cmdfunc()/->exec_op(). You probably don't have setups with such
NANDs yet, but that might be the case at some point.



 Thanks Boris and Miquel for pointing this out.

 Yes. We don't have that setup yet and the current driver code
 also can't handle that condition since the command function was
 not doing anything in this regard.

 Since the current driver code was complicated with lot of
 code duplication, so this patch was raised to cleanup few things.


As already suggested by Miqule, I strongly recommend that you work on
supporting ->exec_op() instead of trying to clean things up 
prematurely.




 I did some analysis and it seems moving to ->exec_op() will help in
 long run. I will start working on that but it will take some
 time for us since It requires major code changes with lot of
 testing. I will update you when we have RFC patch ready for this.

 Meanwhile, I will address review comments in other patches of this
 series and will post v2 after removing this patch from patch series.

 Regards,
 Abhishek



Since after 'commit 25f815f66a14 ("mtd: nand: force drivers to
explicitly send READ/PROG commands")', sending of commands has
been moved to driver for page read/write, so this patch does
following changes to make code more readable:

1. Introduce qcom_nand_init_page_op() and qcom_nand_start_page_op()
   helper functions which helps in removing code duplication in each
   operation.

2. After issuing PROGRAM PAGE/BLOCK ERASE, QCOM NAND
   controller waits for BUSY signal to be de asserted and
   automatically issues the READ STATUS command. Currently, driver
   is storing this status privately and returns the same when status
   command comes from helper function after program/erase operation.
   Now, for write operations, the status can be returned from main
   function itself, so storing status can be removed for program
   operations.

Signed-off-by: Abhishek Sahu 
---
 drivers/mtd/nand/raw/qcom_nandc.c | 222 
--

 1 file changed, 91 insertions(+), 131 deletions(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c 
b/drivers/mtd/nand/raw/qcom_nandc.c

index 6fb85d3..f73ee0e 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -1382,39 +1382,37 @@ static void pre_command(struct qcom_nand_host 
*host, int command)

host->last_command = command;

clear_read_regs(nandc);
-
-   if (command == NAND_CMD_RESET || command == NAND_CMD_READID ||
-   command == NAND_CMD_PARAM || command == NAND_CMD_ERASE1)
-   clear_bam_transaction(nandc);
+   clear_bam_transaction(nandc);
 }

 /*
- * this is called after NAND_CMD_PAGEPROG and NAND_CMD_ERASE1 to set 
our
- * privately maintained status byte, this status byte can be read 
after

- * NAND_CMD_STATUS is called
+ * QCOM NAND controller by default issues READ STATUS command after 
PROGRAM
+ * PAGE/BLOCK ERASE operation and updates the same in its internal 
status
+ * register for last codeword. This function parses status for each 
CW and

+ * return actual status byte for write/erase operation.
  */
-static void parse_erase_write_errors(struct qcom_nand_host *host, int 
command)
+static u8 parse_erase_write_errors(struct qcom_nand_host *host, int 
num_cw)

 {
struct nand_chip *chip = >chip;
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-   struct nand_ecc_ctrl *ecc = >ecc;
-   int num_cw;
int i;
+   u8 status = 0;

-   num_cw = command == NAND_CMD_PAGEPROG ? ecc->steps : 1;
nandc_read_buffer_sync(nandc, true);

for (i = 0; i < num_cw; i++) {
u32 flash_status = le32_to_cpu(nandc->reg_read_buf[i]);

if (flash_status & FS_MPU_ERR)
-   host->status &= ~NAND_STATUS_WP;
+   status &= ~NAND_STAT

Re: [PATCH 5/5] mtd: rawnand: qcom: reorganization by removing read/write helpers

2018-07-28 Thread Abhishek Sahu

On 2018-07-19 03:24, Boris Brezillon wrote:

On Fri,  6 Jul 2018 13:21:59 +0530
Abhishek Sahu  wrote:


Driver does not send the commands to NAND device for page
read/write operations in ->cmdfunc(). It just does some
minor variable initialization and rest of the things
are being done in actual ->read/write_oob[_raw].

The generic helper function calls for invoking commands during
page read/write are making this driver complicated. For QCOM NAND
driver, ->cmdfunc() does minor part of initialization and rest of
the initialization is performed by actual page read/write
functions. Also, ->read/write_oob() does not calls helper
function and all the initialization is being done in
->read/write_oob() itself.


This sounds hazardous in the long run. Some vendor specific commands
are re-using the READ0/READSTART semantic to read particular
registers/OTP sections programmed at flash production time. For these
operations, we don't want to go through the regular
chip->ecc.read_page[_raw]() hooks, and instead use
->cmdfunc()/->exec_op(). You probably don't have setups with such
NANDs yet, but that might be the case at some point.



 Thanks Boris and Miquel for pointing this out.

 Yes. We don't have that setup yet and the current driver code
 also can't handle that condition since the command function was
 not doing anything in this regard.

 Since the current driver code was complicated with lot of
 code duplication, so this patch was raised to cleanup few things.


As already suggested by Miqule, I strongly recommend that you work on
supporting ->exec_op() instead of trying to clean things up 
prematurely.




 I did some analysis and it seems moving to ->exec_op() will help in
 long run. I will start working on that but it will take some
 time for us since It requires major code changes with lot of
 testing. I will update you when we have RFC patch ready for this.

 Meanwhile, I will address review comments in other patches of this
 series and will post v2 after removing this patch from patch series.

 Regards,
 Abhishek



Since after 'commit 25f815f66a14 ("mtd: nand: force drivers to
explicitly send READ/PROG commands")', sending of commands has
been moved to driver for page read/write, so this patch does
following changes to make code more readable:

1. Introduce qcom_nand_init_page_op() and qcom_nand_start_page_op()
   helper functions which helps in removing code duplication in each
   operation.

2. After issuing PROGRAM PAGE/BLOCK ERASE, QCOM NAND
   controller waits for BUSY signal to be de asserted and
   automatically issues the READ STATUS command. Currently, driver
   is storing this status privately and returns the same when status
   command comes from helper function after program/erase operation.
   Now, for write operations, the status can be returned from main
   function itself, so storing status can be removed for program
   operations.

Signed-off-by: Abhishek Sahu 
---
 drivers/mtd/nand/raw/qcom_nandc.c | 222 
--

 1 file changed, 91 insertions(+), 131 deletions(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c 
b/drivers/mtd/nand/raw/qcom_nandc.c

index 6fb85d3..f73ee0e 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -1382,39 +1382,37 @@ static void pre_command(struct qcom_nand_host 
*host, int command)

host->last_command = command;

clear_read_regs(nandc);
-
-   if (command == NAND_CMD_RESET || command == NAND_CMD_READID ||
-   command == NAND_CMD_PARAM || command == NAND_CMD_ERASE1)
-   clear_bam_transaction(nandc);
+   clear_bam_transaction(nandc);
 }

 /*
- * this is called after NAND_CMD_PAGEPROG and NAND_CMD_ERASE1 to set 
our
- * privately maintained status byte, this status byte can be read 
after

- * NAND_CMD_STATUS is called
+ * QCOM NAND controller by default issues READ STATUS command after 
PROGRAM
+ * PAGE/BLOCK ERASE operation and updates the same in its internal 
status
+ * register for last codeword. This function parses status for each 
CW and

+ * return actual status byte for write/erase operation.
  */
-static void parse_erase_write_errors(struct qcom_nand_host *host, int 
command)
+static u8 parse_erase_write_errors(struct qcom_nand_host *host, int 
num_cw)

 {
struct nand_chip *chip = >chip;
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-   struct nand_ecc_ctrl *ecc = >ecc;
-   int num_cw;
int i;
+   u8 status = 0;

-   num_cw = command == NAND_CMD_PAGEPROG ? ecc->steps : 1;
nandc_read_buffer_sync(nandc, true);

for (i = 0; i < num_cw; i++) {
u32 flash_status = le32_to_cpu(nandc->reg_read_buf[i]);

if (flash_status & FS_MPU_ERR)
-   host->status &= ~NAND_STATUS_WP;
+   status &= ~NAND_STAT

Re: [PATCH 2/5] mtd: rawnand: qcom: remove driver specific block_markbad function

2018-07-20 Thread Abhishek Sahu

Hi Boris,

On 2018-07-19 03:13, Boris Brezillon wrote:

On Wed, 18 Jul 2018 23:23:50 +0200
Miquel Raynal  wrote:


Boris,

Can you please check the change in qcom_nandc_write_oob() is
valid? I think it is but as this is a bit of a hack I prefer double 
checking.


Indeed, it's hack-ish.



Thanks,
Miquèl


Abhishek Sahu  wrote on Fri,  6 Jul 2018
13:21:56 +0530:

> The NAND base layer calls write_oob() by setting bytes at
> chip->badblockpos with value non 0xFF for updating bad block status.
> The QCOM NAND controller skips the bad block bytes while doing normal
> write with ECC enabled. When initial support for this driver was
> added, the driver specific function was added temporarily for
> block_markbad() with assumption to change for raw read in NAND base
> layer. Moving to raw read for block_markbad() seems to take more time
> so this patch removes driver specific block_markbad() function by
> using following HACK in write_oob() function.
>
> Check for BBM bytes in OOB and accordingly do raw write for updating
> BBM bytes in NAND flash or normal write for updating available OOB
> bytes.


Why don't we change that instead of patching the qcom driver to guess
when the core tries to mark a block bad? If you're afraid of breaking
existing drivers that might rely on the "write/read BBM in non-raw
mode" solution (I'm sure some drivers are), you can always add a new
flag in chip->options (NAND_ACCESS_BBM_IN_RAW_MODE) and only use raw
accessors when this flag is set.



 We started with that Only

 http://patchwork.ozlabs.org/patch/508565/

 and since we didn't conclude, we went for driver
 specific bad block check and mark bad block functions.

 Now, we wanted to get rid of driver specific functions

 1. For bad block check, we found the way to get the BBM bytes
with ECC read. Controller updates BBM in separate register
which we can read and update the same in OOB. Patch #1 of
series does the same.

 2. For bad block mark, there is no way to update in ECC mode
that's why we went for HACK to get rid of driver specific
function.

 If adding flag is fine now then this HACK won't be required.
 Moving to RAW mode for every one still looks risky.

 Thanks,
 Abhishek




Re: [PATCH 2/5] mtd: rawnand: qcom: remove driver specific block_markbad function

2018-07-20 Thread Abhishek Sahu

Hi Boris,

On 2018-07-19 03:13, Boris Brezillon wrote:

On Wed, 18 Jul 2018 23:23:50 +0200
Miquel Raynal  wrote:


Boris,

Can you please check the change in qcom_nandc_write_oob() is
valid? I think it is but as this is a bit of a hack I prefer double 
checking.


Indeed, it's hack-ish.



Thanks,
Miquèl


Abhishek Sahu  wrote on Fri,  6 Jul 2018
13:21:56 +0530:

> The NAND base layer calls write_oob() by setting bytes at
> chip->badblockpos with value non 0xFF for updating bad block status.
> The QCOM NAND controller skips the bad block bytes while doing normal
> write with ECC enabled. When initial support for this driver was
> added, the driver specific function was added temporarily for
> block_markbad() with assumption to change for raw read in NAND base
> layer. Moving to raw read for block_markbad() seems to take more time
> so this patch removes driver specific block_markbad() function by
> using following HACK in write_oob() function.
>
> Check for BBM bytes in OOB and accordingly do raw write for updating
> BBM bytes in NAND flash or normal write for updating available OOB
> bytes.


Why don't we change that instead of patching the qcom driver to guess
when the core tries to mark a block bad? If you're afraid of breaking
existing drivers that might rely on the "write/read BBM in non-raw
mode" solution (I'm sure some drivers are), you can always add a new
flag in chip->options (NAND_ACCESS_BBM_IN_RAW_MODE) and only use raw
accessors when this flag is set.



 We started with that Only

 http://patchwork.ozlabs.org/patch/508565/

 and since we didn't conclude, we went for driver
 specific bad block check and mark bad block functions.

 Now, we wanted to get rid of driver specific functions

 1. For bad block check, we found the way to get the BBM bytes
with ECC read. Controller updates BBM in separate register
which we can read and update the same in OOB. Patch #1 of
series does the same.

 2. For bad block mark, there is no way to update in ECC mode
that's why we went for HACK to get rid of driver specific
function.

 If adding flag is fine now then this HACK won't be required.
 Moving to RAW mode for every one still looks risky.

 Thanks,
 Abhishek




Re: [PATCH 4/5] mtd: rawnand: qcom: update BBT related flags

2018-07-20 Thread Abhishek Sahu

On 2018-07-19 03:12, Miquel Raynal wrote:

Abhishek,

Miquel Raynal  wrote on Wed, 18 Jul 2018
23:41:44 +0200:


Hi Boris,

Boris Brezillon  wrote on Wed, 18 Jul 
2018

23:36:37 +0200:

> On Wed, 18 Jul 2018 23:15:26 +0200
> Miquel Raynal  wrote:
>
> > Hi Abhishek,
> >
> > Abhishek Sahu  wrote on Fri,  6 Jul 2018
> > 13:21:58 +0530:
> >
> > > Remove the NAND_SKIP_BBTSCAN to use RAM based BBT.
> >
> > Unless I am understanding it the wrong way, NAND_SKIP_BBTSCAN will skip
> > the scan of the on-chip BBT and will scan every block to construct a
> > RAM, based BBT thanks to the BBM.
> >
> > So flash based BBT is already unused and removing this flag is a
> > mistake, right?
>
> ->scan_bbt() is also taking care of building the in-RAM BBT based on
> BBM when no on-flash BBT is provided, so I think it's the right thing
> to do.

Oh right. Then doing so is harmless.


Could you please update the commit log to reflect this aspect?



 Thanks Miquel and Boris.
 I will update the commit log.

 Regards,
 Abhishek


Re: [PATCH 4/5] mtd: rawnand: qcom: update BBT related flags

2018-07-20 Thread Abhishek Sahu

On 2018-07-19 03:12, Miquel Raynal wrote:

Abhishek,

Miquel Raynal  wrote on Wed, 18 Jul 2018
23:41:44 +0200:


Hi Boris,

Boris Brezillon  wrote on Wed, 18 Jul 
2018

23:36:37 +0200:

> On Wed, 18 Jul 2018 23:15:26 +0200
> Miquel Raynal  wrote:
>
> > Hi Abhishek,
> >
> > Abhishek Sahu  wrote on Fri,  6 Jul 2018
> > 13:21:58 +0530:
> >
> > > Remove the NAND_SKIP_BBTSCAN to use RAM based BBT.
> >
> > Unless I am understanding it the wrong way, NAND_SKIP_BBTSCAN will skip
> > the scan of the on-chip BBT and will scan every block to construct a
> > RAM, based BBT thanks to the BBM.
> >
> > So flash based BBT is already unused and removing this flag is a
> > mistake, right?
>
> ->scan_bbt() is also taking care of building the in-RAM BBT based on
> BBM when no on-flash BBT is provided, so I think it's the right thing
> to do.

Oh right. Then doing so is harmless.


Could you please update the commit log to reflect this aspect?



 Thanks Miquel and Boris.
 I will update the commit log.

 Regards,
 Abhishek


[PATCH] arm64: defconfig: Enable CONFIG_MTD_NAND_QCOM for IPQ8074

2018-07-06 Thread Abhishek Sahu
QCOM IPQ8074 boards contain NAND flash memory for which
this config needs to be enabled.

Signed-off-by: Abhishek Sahu 
---
 arch/arm64/configs/defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 6739fc7..339f3dd 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -179,6 +179,7 @@ CONFIG_MTD_M25P80=y
 CONFIG_MTD_NAND=y
 CONFIG_MTD_NAND_DENALI_DT=y
 CONFIG_MTD_NAND_MARVELL=y
+CONFIG_MTD_NAND_QCOM=y
 CONFIG_MTD_SPI_NOR=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_NBD=m
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc.
is a member of Code Aurora Forum, hosted by The Linux Foundation



[PATCH] arm64: defconfig: Enable CONFIG_MTD_NAND_QCOM for IPQ8074

2018-07-06 Thread Abhishek Sahu
QCOM IPQ8074 boards contain NAND flash memory for which
this config needs to be enabled.

Signed-off-by: Abhishek Sahu 
---
 arch/arm64/configs/defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 6739fc7..339f3dd 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -179,6 +179,7 @@ CONFIG_MTD_M25P80=y
 CONFIG_MTD_NAND=y
 CONFIG_MTD_NAND_DENALI_DT=y
 CONFIG_MTD_NAND_MARVELL=y
+CONFIG_MTD_NAND_QCOM=y
 CONFIG_MTD_SPI_NOR=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_NBD=m
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc.
is a member of Code Aurora Forum, hosted by The Linux Foundation



[PATCH] ARM: qcom_defconfig: Enable QCOM NAND related configs

2018-07-06 Thread Abhishek Sahu
IPQ8064 and IPQ4019 boards contain NAND flash
memory for which these configs need to be enabled.

Signed-off-by: Abhishek Sahu 
---
 arch/arm/configs/qcom_defconfig | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm/configs/qcom_defconfig b/arch/arm/configs/qcom_defconfig
index dd2a089..6aa7046 100644
--- a/arch/arm/configs/qcom_defconfig
+++ b/arch/arm/configs/qcom_defconfig
@@ -57,6 +57,8 @@ CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_M25P80=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_QCOM=y
 CONFIG_MTD_SPI_NOR=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc.
is a member of Code Aurora Forum, hosted by The Linux Foundation



[PATCH] ARM: qcom_defconfig: Enable QCOM NAND related configs

2018-07-06 Thread Abhishek Sahu
IPQ8064 and IPQ4019 boards contain NAND flash
memory for which these configs need to be enabled.

Signed-off-by: Abhishek Sahu 
---
 arch/arm/configs/qcom_defconfig | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm/configs/qcom_defconfig b/arch/arm/configs/qcom_defconfig
index dd2a089..6aa7046 100644
--- a/arch/arm/configs/qcom_defconfig
+++ b/arch/arm/configs/qcom_defconfig
@@ -57,6 +57,8 @@ CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_M25P80=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_QCOM=y
 CONFIG_MTD_SPI_NOR=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc.
is a member of Code Aurora Forum, hosted by The Linux Foundation



[PATCH 0/5] Update for removing driver specific BBM functions

2018-07-06 Thread Abhishek Sahu
This patch series deals mainly with removing driver specific bad block
functions and some minor fixing/cleanup.

1. When initial support for this driver was added [1], then the
   plan was to remove these driver specific functions when NAND base
   layer has support for doing raw read/write for bad block related
   things. Moving to raw read/write seems to take more time so this patch
   series implemented alternate logic for reading/writing bad block with
   normal read/write itself. This alternate logic relies on some
   assumption which seems to be better than driver specific functions and
   provide more functionality. Some discussion regarding it has already
   happened in [2].

2. Some part of code is duplicated in every read/write function
   so clean up the code by making helper function.

3. Bootloaders does access protection for some of the NAND
   registers which generates few write errors if it is enabled.

4. Create RAM based BBT table. Flash based BBT table can’t be
   used since our bootloader does not have support for the same.

**This patch series is rebased over linux-next with PATCH [3]

[1]: http://patchwork.ozlabs.org/patch/508565/
[2]: https://patchwork.ozlabs.org/patch/920563/
[3]: https://patchwork.ozlabs.org/patch/938631/

Abhishek Sahu (5):
  mtd: rawnand: qcom: remove driver specific bad block check function
  mtd: rawnand: qcom: remove driver specific block_markbad function
  mtd: rawnand: qcom: fix NAND register write errors
  mtd: rawnand: qcom: update BBT related flags
  mtd: rawnand: qcom: reorganization by removing read/write helpers

 drivers/mtd/nand/raw/qcom_nandc.c | 439 ++
 1 file changed, 162 insertions(+), 277 deletions(-)

-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc.
is a member of Code Aurora Forum, hosted by The Linux Foundation



[PATCH 0/5] Update for removing driver specific BBM functions

2018-07-06 Thread Abhishek Sahu
This patch series deals mainly with removing driver specific bad block
functions and some minor fixing/cleanup.

1. When initial support for this driver was added [1], then the
   plan was to remove these driver specific functions when NAND base
   layer has support for doing raw read/write for bad block related
   things. Moving to raw read/write seems to take more time so this patch
   series implemented alternate logic for reading/writing bad block with
   normal read/write itself. This alternate logic relies on some
   assumption which seems to be better than driver specific functions and
   provide more functionality. Some discussion regarding it has already
   happened in [2].

2. Some part of code is duplicated in every read/write function
   so clean up the code by making helper function.

3. Bootloaders does access protection for some of the NAND
   registers which generates few write errors if it is enabled.

4. Create RAM based BBT table. Flash based BBT table can’t be
   used since our bootloader does not have support for the same.

**This patch series is rebased over linux-next with PATCH [3]

[1]: http://patchwork.ozlabs.org/patch/508565/
[2]: https://patchwork.ozlabs.org/patch/920563/
[3]: https://patchwork.ozlabs.org/patch/938631/

Abhishek Sahu (5):
  mtd: rawnand: qcom: remove driver specific bad block check function
  mtd: rawnand: qcom: remove driver specific block_markbad function
  mtd: rawnand: qcom: fix NAND register write errors
  mtd: rawnand: qcom: update BBT related flags
  mtd: rawnand: qcom: reorganization by removing read/write helpers

 drivers/mtd/nand/raw/qcom_nandc.c | 439 ++
 1 file changed, 162 insertions(+), 277 deletions(-)

-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc.
is a member of Code Aurora Forum, hosted by The Linux Foundation



[PATCH 3/5] mtd: rawnand: qcom: fix NAND register write errors

2018-07-06 Thread Abhishek Sahu
Fix the following NAND register write errors which will
be generated if access protection is enabled.

1. SFLASHC_BURST_CFG register is not available for supported
   NAND contollers by this driver, so this can be removed.
2. NAND_CTRL is operational register and register writes to
   operational registers should always be done through
   command descriptors if BAM_MODE is already enabled.
   With full boot chain, bootloader already enables
   BAM_MODE so read the NAND_CTRL register value and write
   only if BAM_MODE is not set.

Signed-off-by: Abhishek Sahu 
---
 drivers/mtd/nand/raw/qcom_nandc.c | 11 ---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c 
b/drivers/mtd/nand/raw/qcom_nandc.c
index df12cf3..9e6b383 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -2693,15 +2693,20 @@ static int qcom_nandc_setup(struct qcom_nand_controller 
*nandc)
 {
u32 nand_ctrl;
 
-   /* kill onenand */
-   nandc_write(nandc, SFLASHC_BURST_CFG, 0);
nandc_write(nandc, dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD),
NAND_DEV_CMD_VLD_VAL);
 
/* enable ADM or BAM DMA */
if (nandc->props->is_bam) {
nand_ctrl = nandc_read(nandc, NAND_CTRL);
-   nandc_write(nandc, NAND_CTRL, nand_ctrl | BAM_MODE_EN);
+   /*
+* Once BAM_MODE_EN bit is set then QPIC_NAND_CTRL register
+* should be written with BAM instead of writel.
+* Check if BAM_MODE_EN is already set by bootloader and write
+* only if this bit is not set.
+*/
+   if (!(nand_ctrl & BAM_MODE_EN))
+   nandc_write(nandc, NAND_CTRL, nand_ctrl | BAM_MODE_EN);
} else {
nandc_write(nandc, NAND_FLASH_CHIP_SELECT, DM_EN);
}
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc.
is a member of Code Aurora Forum, hosted by The Linux Foundation



[PATCH 2/5] mtd: rawnand: qcom: remove driver specific block_markbad function

2018-07-06 Thread Abhishek Sahu
The NAND base layer calls write_oob() by setting bytes at
chip->badblockpos with value non 0xFF for updating bad block status.
The QCOM NAND controller skips the bad block bytes while doing normal
write with ECC enabled. When initial support for this driver was
added, the driver specific function was added temporarily for
block_markbad() with assumption to change for raw read in NAND base
layer. Moving to raw read for block_markbad() seems to take more time
so this patch removes driver specific block_markbad() function by
using following HACK in write_oob() function.

Check for BBM bytes in OOB and accordingly do raw write for updating
BBM bytes in NAND flash or normal write for updating available OOB
bytes.

Signed-off-by: Abhishek Sahu 
---
 drivers/mtd/nand/raw/qcom_nandc.c | 103 +++---
 1 file changed, 40 insertions(+), 63 deletions(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c 
b/drivers/mtd/nand/raw/qcom_nandc.c
index ea253ac..df12cf3 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -2138,28 +2138,57 @@ static int qcom_nandc_write_oob(struct mtd_info *mtd, 
struct nand_chip *chip,
struct qcom_nand_host *host = to_qcom_nand_host(chip);
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
struct nand_ecc_ctrl *ecc = >ecc;
-   u8 *oob = chip->oob_poi;
-   int data_size, oob_size;
+   u8 *oob = chip->oob_poi, bbm_byte;
+   int data_size, oob_size, bbm_offset, write_size;
int ret;
 
-   host->use_ecc = true;
clear_bam_transaction(nandc);
 
-   /* calculate the data and oob size for the last codeword/step */
-   data_size = ecc->size - ((ecc->steps - 1) << 2);
-   oob_size = mtd->oobavail;
+   /*
+* The NAND base layer calls ecc->write_oob() by setting bytes at
+* chip->badblockpos (chip->badblockpos will be 0 for QCOM NAND
+* controller layout) in OOB buffer with value other that 0xFF
+* for updating bad block status. QCOM NAND controller skips
+* BBM bytes while writing with ECC, so following HACK has been
+* added in this function for using generic block_markbad() function.
+*
+* Check for BBM bytes in OOB and accordingly do raw write for
+* updating BBM bytes in NAND flash or normal write with ECC for
+* updating available OOB bytes.
+*/
+   bbm_byte = oob[0];
+   if (chip->options & NAND_BUSWIDTH_16)
+   bbm_byte &= oob[1];
 
-   memset(nandc->data_buffer, 0xff, host->cw_data);
-   /* override new oob content to last codeword */
-   mtd_ooblayout_get_databytes(mtd, nandc->data_buffer + data_size, oob,
-   0, mtd->oobavail);
+   /* Write BBM bytes by doing raw write. */
+   if (bbm_byte != 0xff) {
+   host->use_ecc = false;
+   memset(nandc->data_buffer, 0xff, host->cw_size);
+   /* Determine the BBM bytes position and update the same */
+   bbm_offset = mtd->writesize - host->cw_size * (ecc->steps - 1);
+   memcpy(nandc->data_buffer + bbm_offset, oob, host->bbm_size);
+   write_size = host->cw_size;
+   /* Write OOB bytes by doing normal write with ECC */
+   } else {
+   host->use_ecc = true;
+   /* calculate the data and oob size for the last codeword/step */
+   data_size = ecc->size - ((ecc->steps - 1) << 2);
+   oob_size = mtd->oobavail;
+
+   memset(nandc->data_buffer, 0xff, host->cw_data);
+   /* override new oob content to last codeword */
+   mtd_ooblayout_get_databytes(mtd, nandc->data_buffer + data_size,
+   oob, 0, mtd->oobavail);
+
+   write_size = data_size + oob_size;
+   }
 
set_address(host, host->cw_size * (ecc->steps - 1), page);
update_rw_regs(host, 1, false);
 
config_nand_page_write(nandc);
write_data_dma(nandc, FLASH_BUF_ACC,
-  nandc->data_buffer, data_size + oob_size, 0);
+  nandc->data_buffer, write_size, 0);
config_nand_cw_write(nandc);
 
ret = submit_descs(nandc);
@@ -2174,48 +2203,6 @@ static int qcom_nandc_write_oob(struct mtd_info *mtd, 
struct nand_chip *chip,
return nand_prog_page_end_op(chip);
 }
 
-static int qcom_nandc_block_markbad(struct mtd_info *mtd, loff_t ofs)
-{
-   struct nand_chip *chip = mtd_to_nand(mtd);
-   struct qcom_nand_host *host = to_qcom_nand_host(chip);
-   struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-   struct nand_ecc_ctrl *ecc = >ecc;
-   int page, ret;
-
-   clear_read_regs(nandc);
-   clear_bam_transaction(nand

[PATCH 3/5] mtd: rawnand: qcom: fix NAND register write errors

2018-07-06 Thread Abhishek Sahu
Fix the following NAND register write errors which will
be generated if access protection is enabled.

1. SFLASHC_BURST_CFG register is not available for supported
   NAND contollers by this driver, so this can be removed.
2. NAND_CTRL is operational register and register writes to
   operational registers should always be done through
   command descriptors if BAM_MODE is already enabled.
   With full boot chain, bootloader already enables
   BAM_MODE so read the NAND_CTRL register value and write
   only if BAM_MODE is not set.

Signed-off-by: Abhishek Sahu 
---
 drivers/mtd/nand/raw/qcom_nandc.c | 11 ---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c 
b/drivers/mtd/nand/raw/qcom_nandc.c
index df12cf3..9e6b383 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -2693,15 +2693,20 @@ static int qcom_nandc_setup(struct qcom_nand_controller 
*nandc)
 {
u32 nand_ctrl;
 
-   /* kill onenand */
-   nandc_write(nandc, SFLASHC_BURST_CFG, 0);
nandc_write(nandc, dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD),
NAND_DEV_CMD_VLD_VAL);
 
/* enable ADM or BAM DMA */
if (nandc->props->is_bam) {
nand_ctrl = nandc_read(nandc, NAND_CTRL);
-   nandc_write(nandc, NAND_CTRL, nand_ctrl | BAM_MODE_EN);
+   /*
+* Once BAM_MODE_EN bit is set then QPIC_NAND_CTRL register
+* should be written with BAM instead of writel.
+* Check if BAM_MODE_EN is already set by bootloader and write
+* only if this bit is not set.
+*/
+   if (!(nand_ctrl & BAM_MODE_EN))
+   nandc_write(nandc, NAND_CTRL, nand_ctrl | BAM_MODE_EN);
} else {
nandc_write(nandc, NAND_FLASH_CHIP_SELECT, DM_EN);
}
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc.
is a member of Code Aurora Forum, hosted by The Linux Foundation



[PATCH 2/5] mtd: rawnand: qcom: remove driver specific block_markbad function

2018-07-06 Thread Abhishek Sahu
The NAND base layer calls write_oob() by setting bytes at
chip->badblockpos with value non 0xFF for updating bad block status.
The QCOM NAND controller skips the bad block bytes while doing normal
write with ECC enabled. When initial support for this driver was
added, the driver specific function was added temporarily for
block_markbad() with assumption to change for raw read in NAND base
layer. Moving to raw read for block_markbad() seems to take more time
so this patch removes driver specific block_markbad() function by
using following HACK in write_oob() function.

Check for BBM bytes in OOB and accordingly do raw write for updating
BBM bytes in NAND flash or normal write for updating available OOB
bytes.

Signed-off-by: Abhishek Sahu 
---
 drivers/mtd/nand/raw/qcom_nandc.c | 103 +++---
 1 file changed, 40 insertions(+), 63 deletions(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c 
b/drivers/mtd/nand/raw/qcom_nandc.c
index ea253ac..df12cf3 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -2138,28 +2138,57 @@ static int qcom_nandc_write_oob(struct mtd_info *mtd, 
struct nand_chip *chip,
struct qcom_nand_host *host = to_qcom_nand_host(chip);
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
struct nand_ecc_ctrl *ecc = >ecc;
-   u8 *oob = chip->oob_poi;
-   int data_size, oob_size;
+   u8 *oob = chip->oob_poi, bbm_byte;
+   int data_size, oob_size, bbm_offset, write_size;
int ret;
 
-   host->use_ecc = true;
clear_bam_transaction(nandc);
 
-   /* calculate the data and oob size for the last codeword/step */
-   data_size = ecc->size - ((ecc->steps - 1) << 2);
-   oob_size = mtd->oobavail;
+   /*
+* The NAND base layer calls ecc->write_oob() by setting bytes at
+* chip->badblockpos (chip->badblockpos will be 0 for QCOM NAND
+* controller layout) in OOB buffer with value other that 0xFF
+* for updating bad block status. QCOM NAND controller skips
+* BBM bytes while writing with ECC, so following HACK has been
+* added in this function for using generic block_markbad() function.
+*
+* Check for BBM bytes in OOB and accordingly do raw write for
+* updating BBM bytes in NAND flash or normal write with ECC for
+* updating available OOB bytes.
+*/
+   bbm_byte = oob[0];
+   if (chip->options & NAND_BUSWIDTH_16)
+   bbm_byte &= oob[1];
 
-   memset(nandc->data_buffer, 0xff, host->cw_data);
-   /* override new oob content to last codeword */
-   mtd_ooblayout_get_databytes(mtd, nandc->data_buffer + data_size, oob,
-   0, mtd->oobavail);
+   /* Write BBM bytes by doing raw write. */
+   if (bbm_byte != 0xff) {
+   host->use_ecc = false;
+   memset(nandc->data_buffer, 0xff, host->cw_size);
+   /* Determine the BBM bytes position and update the same */
+   bbm_offset = mtd->writesize - host->cw_size * (ecc->steps - 1);
+   memcpy(nandc->data_buffer + bbm_offset, oob, host->bbm_size);
+   write_size = host->cw_size;
+   /* Write OOB bytes by doing normal write with ECC */
+   } else {
+   host->use_ecc = true;
+   /* calculate the data and oob size for the last codeword/step */
+   data_size = ecc->size - ((ecc->steps - 1) << 2);
+   oob_size = mtd->oobavail;
+
+   memset(nandc->data_buffer, 0xff, host->cw_data);
+   /* override new oob content to last codeword */
+   mtd_ooblayout_get_databytes(mtd, nandc->data_buffer + data_size,
+   oob, 0, mtd->oobavail);
+
+   write_size = data_size + oob_size;
+   }
 
set_address(host, host->cw_size * (ecc->steps - 1), page);
update_rw_regs(host, 1, false);
 
config_nand_page_write(nandc);
write_data_dma(nandc, FLASH_BUF_ACC,
-  nandc->data_buffer, data_size + oob_size, 0);
+  nandc->data_buffer, write_size, 0);
config_nand_cw_write(nandc);
 
ret = submit_descs(nandc);
@@ -2174,48 +2203,6 @@ static int qcom_nandc_write_oob(struct mtd_info *mtd, 
struct nand_chip *chip,
return nand_prog_page_end_op(chip);
 }
 
-static int qcom_nandc_block_markbad(struct mtd_info *mtd, loff_t ofs)
-{
-   struct nand_chip *chip = mtd_to_nand(mtd);
-   struct qcom_nand_host *host = to_qcom_nand_host(chip);
-   struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-   struct nand_ecc_ctrl *ecc = >ecc;
-   int page, ret;
-
-   clear_read_regs(nandc);
-   clear_bam_transaction(nand

[PATCH 4/5] mtd: rawnand: qcom: update BBT related flags

2018-07-06 Thread Abhishek Sahu
Remove the NAND_SKIP_BBTSCAN to use RAM based BBT.
Flash based BBT is not used since bootloaders
doesn't have support for the same.

Signed-off-by: Abhishek Sahu 
---
 drivers/mtd/nand/raw/qcom_nandc.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c 
b/drivers/mtd/nand/raw/qcom_nandc.c
index 9e6b383..6fb85d3 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -2750,8 +2750,7 @@ static int qcom_nand_host_init(struct 
qcom_nand_controller *nandc,
chip->get_features  = nand_get_set_features_notsupp;
 
chip->controller = >controller;
-   chip->options |= NAND_NO_SUBPAGE_WRITE | NAND_USE_BOUNCE_BUFFER |
-NAND_SKIP_BBTSCAN;
+   chip->options |= NAND_NO_SUBPAGE_WRITE | NAND_USE_BOUNCE_BUFFER;
 
/* set up initial status value */
host->status = NAND_STATUS_READY | NAND_STATUS_WP;
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc.
is a member of Code Aurora Forum, hosted by The Linux Foundation



[PATCH 4/5] mtd: rawnand: qcom: update BBT related flags

2018-07-06 Thread Abhishek Sahu
Remove the NAND_SKIP_BBTSCAN to use RAM based BBT.
Flash based BBT is not used since bootloaders
doesn't have support for the same.

Signed-off-by: Abhishek Sahu 
---
 drivers/mtd/nand/raw/qcom_nandc.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c 
b/drivers/mtd/nand/raw/qcom_nandc.c
index 9e6b383..6fb85d3 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -2750,8 +2750,7 @@ static int qcom_nand_host_init(struct 
qcom_nand_controller *nandc,
chip->get_features  = nand_get_set_features_notsupp;
 
chip->controller = >controller;
-   chip->options |= NAND_NO_SUBPAGE_WRITE | NAND_USE_BOUNCE_BUFFER |
-NAND_SKIP_BBTSCAN;
+   chip->options |= NAND_NO_SUBPAGE_WRITE | NAND_USE_BOUNCE_BUFFER;
 
/* set up initial status value */
host->status = NAND_STATUS_READY | NAND_STATUS_WP;
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc.
is a member of Code Aurora Forum, hosted by The Linux Foundation



[PATCH 5/5] mtd: rawnand: qcom: reorganization by removing read/write helpers

2018-07-06 Thread Abhishek Sahu
Driver does not send the commands to NAND device for page
read/write operations in ->cmdfunc(). It just does some
minor variable initialization and rest of the things
are being done in actual ->read/write_oob[_raw].

The generic helper function calls for invoking commands during
page read/write are making this driver complicated. For QCOM NAND
driver, ->cmdfunc() does minor part of initialization and rest of
the initialization is performed by actual page read/write
functions. Also, ->read/write_oob() does not calls helper
function and all the initialization is being done in
->read/write_oob() itself.

Since after 'commit 25f815f66a14 ("mtd: nand: force drivers to
explicitly send READ/PROG commands")', sending of commands has
been moved to driver for page read/write, so this patch does
following changes to make code more readable:

1. Introduce qcom_nand_init_page_op() and qcom_nand_start_page_op()
   helper functions which helps in removing code duplication in each
   operation.

2. After issuing PROGRAM PAGE/BLOCK ERASE, QCOM NAND
   controller waits for BUSY signal to be de asserted and
   automatically issues the READ STATUS command. Currently, driver
   is storing this status privately and returns the same when status
   command comes from helper function after program/erase operation.
   Now, for write operations, the status can be returned from main
   function itself, so storing status can be removed for program
   operations.

Signed-off-by: Abhishek Sahu 
---
 drivers/mtd/nand/raw/qcom_nandc.c | 222 --
 1 file changed, 91 insertions(+), 131 deletions(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c 
b/drivers/mtd/nand/raw/qcom_nandc.c
index 6fb85d3..f73ee0e 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -1382,39 +1382,37 @@ static void pre_command(struct qcom_nand_host *host, 
int command)
host->last_command = command;
 
clear_read_regs(nandc);
-
-   if (command == NAND_CMD_RESET || command == NAND_CMD_READID ||
-   command == NAND_CMD_PARAM || command == NAND_CMD_ERASE1)
-   clear_bam_transaction(nandc);
+   clear_bam_transaction(nandc);
 }
 
 /*
- * this is called after NAND_CMD_PAGEPROG and NAND_CMD_ERASE1 to set our
- * privately maintained status byte, this status byte can be read after
- * NAND_CMD_STATUS is called
+ * QCOM NAND controller by default issues READ STATUS command after PROGRAM
+ * PAGE/BLOCK ERASE operation and updates the same in its internal status
+ * register for last codeword. This function parses status for each CW and
+ * return actual status byte for write/erase operation.
  */
-static void parse_erase_write_errors(struct qcom_nand_host *host, int command)
+static u8 parse_erase_write_errors(struct qcom_nand_host *host, int num_cw)
 {
struct nand_chip *chip = >chip;
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-   struct nand_ecc_ctrl *ecc = >ecc;
-   int num_cw;
int i;
+   u8 status = 0;
 
-   num_cw = command == NAND_CMD_PAGEPROG ? ecc->steps : 1;
nandc_read_buffer_sync(nandc, true);
 
for (i = 0; i < num_cw; i++) {
u32 flash_status = le32_to_cpu(nandc->reg_read_buf[i]);
 
if (flash_status & FS_MPU_ERR)
-   host->status &= ~NAND_STATUS_WP;
+   status &= ~NAND_STATUS_WP;
 
if (flash_status & FS_OP_ERR || (i == (num_cw - 1) &&
 (flash_status &
  FS_DEVICE_STS_ERR)))
-   host->status |= NAND_STATUS_FAIL;
+   status |= NAND_STATUS_FAIL;
}
+
+   return status;
 }
 
 static void post_command(struct qcom_nand_host *host, int command)
@@ -1428,9 +1426,12 @@ static void post_command(struct qcom_nand_host *host, 
int command)
memcpy(nandc->data_buffer, nandc->reg_read_buf,
   nandc->buf_count);
break;
-   case NAND_CMD_PAGEPROG:
case NAND_CMD_ERASE1:
-   parse_erase_write_errors(host, command);
+   /*
+* update privately maintained status byte, this status byte can
+* be read after NAND_CMD_STATUS is called.
+*/
+   host->status = parse_erase_write_errors(host, 1);
break;
default:
break;
@@ -1448,7 +1449,6 @@ static void qcom_nandc_command(struct mtd_info *mtd, 
unsigned int command,
 {
struct nand_chip *chip = mtd_to_nand(mtd);
struct qcom_nand_host *host = to_qcom_nand_host(chip);
-   struct nand_ecc_ctrl *ecc = >ecc;
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
bool wait = false;
int ret = 0;
@@ -1

[PATCH 5/5] mtd: rawnand: qcom: reorganization by removing read/write helpers

2018-07-06 Thread Abhishek Sahu
Driver does not send the commands to NAND device for page
read/write operations in ->cmdfunc(). It just does some
minor variable initialization and rest of the things
are being done in actual ->read/write_oob[_raw].

The generic helper function calls for invoking commands during
page read/write are making this driver complicated. For QCOM NAND
driver, ->cmdfunc() does minor part of initialization and rest of
the initialization is performed by actual page read/write
functions. Also, ->read/write_oob() does not calls helper
function and all the initialization is being done in
->read/write_oob() itself.

Since after 'commit 25f815f66a14 ("mtd: nand: force drivers to
explicitly send READ/PROG commands")', sending of commands has
been moved to driver for page read/write, so this patch does
following changes to make code more readable:

1. Introduce qcom_nand_init_page_op() and qcom_nand_start_page_op()
   helper functions which helps in removing code duplication in each
   operation.

2. After issuing PROGRAM PAGE/BLOCK ERASE, QCOM NAND
   controller waits for BUSY signal to be de asserted and
   automatically issues the READ STATUS command. Currently, driver
   is storing this status privately and returns the same when status
   command comes from helper function after program/erase operation.
   Now, for write operations, the status can be returned from main
   function itself, so storing status can be removed for program
   operations.

Signed-off-by: Abhishek Sahu 
---
 drivers/mtd/nand/raw/qcom_nandc.c | 222 --
 1 file changed, 91 insertions(+), 131 deletions(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c 
b/drivers/mtd/nand/raw/qcom_nandc.c
index 6fb85d3..f73ee0e 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -1382,39 +1382,37 @@ static void pre_command(struct qcom_nand_host *host, 
int command)
host->last_command = command;
 
clear_read_regs(nandc);
-
-   if (command == NAND_CMD_RESET || command == NAND_CMD_READID ||
-   command == NAND_CMD_PARAM || command == NAND_CMD_ERASE1)
-   clear_bam_transaction(nandc);
+   clear_bam_transaction(nandc);
 }
 
 /*
- * this is called after NAND_CMD_PAGEPROG and NAND_CMD_ERASE1 to set our
- * privately maintained status byte, this status byte can be read after
- * NAND_CMD_STATUS is called
+ * QCOM NAND controller by default issues READ STATUS command after PROGRAM
+ * PAGE/BLOCK ERASE operation and updates the same in its internal status
+ * register for last codeword. This function parses status for each CW and
+ * return actual status byte for write/erase operation.
  */
-static void parse_erase_write_errors(struct qcom_nand_host *host, int command)
+static u8 parse_erase_write_errors(struct qcom_nand_host *host, int num_cw)
 {
struct nand_chip *chip = >chip;
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-   struct nand_ecc_ctrl *ecc = >ecc;
-   int num_cw;
int i;
+   u8 status = 0;
 
-   num_cw = command == NAND_CMD_PAGEPROG ? ecc->steps : 1;
nandc_read_buffer_sync(nandc, true);
 
for (i = 0; i < num_cw; i++) {
u32 flash_status = le32_to_cpu(nandc->reg_read_buf[i]);
 
if (flash_status & FS_MPU_ERR)
-   host->status &= ~NAND_STATUS_WP;
+   status &= ~NAND_STATUS_WP;
 
if (flash_status & FS_OP_ERR || (i == (num_cw - 1) &&
 (flash_status &
  FS_DEVICE_STS_ERR)))
-   host->status |= NAND_STATUS_FAIL;
+   status |= NAND_STATUS_FAIL;
}
+
+   return status;
 }
 
 static void post_command(struct qcom_nand_host *host, int command)
@@ -1428,9 +1426,12 @@ static void post_command(struct qcom_nand_host *host, 
int command)
memcpy(nandc->data_buffer, nandc->reg_read_buf,
   nandc->buf_count);
break;
-   case NAND_CMD_PAGEPROG:
case NAND_CMD_ERASE1:
-   parse_erase_write_errors(host, command);
+   /*
+* update privately maintained status byte, this status byte can
+* be read after NAND_CMD_STATUS is called.
+*/
+   host->status = parse_erase_write_errors(host, 1);
break;
default:
break;
@@ -1448,7 +1449,6 @@ static void qcom_nandc_command(struct mtd_info *mtd, 
unsigned int command,
 {
struct nand_chip *chip = mtd_to_nand(mtd);
struct qcom_nand_host *host = to_qcom_nand_host(chip);
-   struct nand_ecc_ctrl *ecc = >ecc;
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
bool wait = false;
int ret = 0;
@@ -1

[PATCH 1/5] mtd: rawnand: qcom: remove driver specific bad block check function

2018-07-06 Thread Abhishek Sahu
The QCOM NAND controller skips the bad block bytes when reading
with ECC enabled. The NAND base layer invokes ->read_oob() function
for bad block check which expects the BBM bytes to be copied at
badblockpos offset in OOB buffer. When initial support for this
driver was added, the driver specific function was added
temporarily for bad block check with assumption to change
for raw read in NAND base layer. Moving to raw read for bad block
check seems to take more time so this patch removes driver specific
bad block check function and uses following logic.

The QCOM NAND controller updates the BAD_BLOCK_STATUS bits value in
NAND_BUFFER_STATUS register with every page read operation. The OOB
buffer can be updated with this value while checking the status for
last codeword.

QCOM NAND controller layout does not support BBM byte at offset
other than zero so check the chip’s badblockpos and return probe
failure for all these chips.

Signed-off-by: Abhishek Sahu 
---
 drivers/mtd/nand/raw/qcom_nandc.c | 118 ++
 1 file changed, 31 insertions(+), 87 deletions(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c 
b/drivers/mtd/nand/raw/qcom_nandc.c
index 994f980..ea253ac 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -80,6 +80,8 @@
 /* NAND_BUFFER_STATUS bits */
 #defineBS_UNCORRECTABLE_BITBIT(8)
 #defineBS_CORRECTABLE_ERR_MSK  0x1f
+#define BAD_BLK_STATUS 16
+#define BAD_BLK_STATUS_2   24
 
 /* NAND_DEVn_CFG0 bits */
 #defineDISABLE_STATUS_AFTER_WRITE  4
@@ -1742,16 +1744,14 @@ static int parse_read_errors(struct qcom_nand_host 
*host, u8 *data_buf,
unsigned int max_bitflips = 0, uncorrectable_cws = 0;
struct read_stats *buf;
bool flash_op_err = false, erased;
-   int i;
+   int i, data_len, oob_len;
+   u32 flash, erased_cw, buffer = 0;
u8 *data_buf_start = data_buf, *oob_buf_start = oob_buf;
 
buf = (struct read_stats *)nandc->reg_read_buf;
nandc_read_buffer_sync(nandc, true);
 
for (i = 0; i < ecc->steps; i++, buf++) {
-   u32 flash, buffer, erased_cw;
-   int data_len, oob_len;
-
if (i == (ecc->steps - 1)) {
data_len = ecc->size - ((ecc->steps - 1) << 2);
oob_len = ecc->steps << 2;
@@ -1824,12 +1824,24 @@ static int parse_read_errors(struct qcom_nand_host 
*host, u8 *data_buf,
if (flash_op_err)
return -EIO;
 
-   if (!uncorrectable_cws)
-   return max_bitflips;
+   if (uncorrectable_cws) {
+   max_bitflips = check_for_erased_page(host, data_buf_start,
+   oob_buf_start, uncorrectable_cws,
+   page, max_bitflips);
+   }
 
-   return check_for_erased_page(host, data_buf_start, oob_buf_start,
-uncorrectable_cws, page,
-max_bitflips);
+   /*
+* Updates the BBM bytes in OOB buffer with BAD_BLK_STATUS bits value
+* of NAND_BUFFER_STATUS register. With every page read operation,
+* controller updates the bad block status data into this register.
+*/
+   if (oob_buf_start) {
+   oob_buf_start[0] = (buffer >> BAD_BLK_STATUS) & 0xff;
+   if (chip->options & NAND_BUSWIDTH_16)
+   oob_buf_start[1] = (buffer >> BAD_BLK_STATUS_2) & 0xff;
+   }
+
+   return max_bitflips;
 }
 
 /*
@@ -1913,41 +1925,6 @@ static int read_page_ecc(struct qcom_nand_host *host, u8 
*data_buf,
return parse_read_errors(host, data_buf_start, oob_buf_start, page);
 }
 
-/*
- * a helper that copies the last step/codeword of a page (containing free oob)
- * into our local buffer
- */
-static int copy_last_cw(struct qcom_nand_host *host, int page)
-{
-   struct nand_chip *chip = >chip;
-   struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-   struct nand_ecc_ctrl *ecc = >ecc;
-   int size;
-   int ret;
-
-   clear_read_regs(nandc);
-
-   size = host->use_ecc ? host->cw_data : host->cw_size;
-
-   /* prepare a clean read buffer */
-   memset(nandc->data_buffer, 0xff, size);
-
-   set_address(host, host->cw_size * (ecc->steps - 1), page);
-   update_rw_regs(host, 1, true);
-
-   config_nand_single_cw_page_read(nandc, host->use_ecc);
-
-   read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, size, 0);
-
-   ret = submit_descs(nandc);
-   if (ret)
-   dev_err(nandc->dev, "failed to copy last codeword\n");
-
-   free_descs(nandc);
-
-   return ret;
-}
-
 /* implements ecc->read_page() */
 static int qcom_nandc_read_page(struct mtd_info *mtd, 

[PATCH 1/5] mtd: rawnand: qcom: remove driver specific bad block check function

2018-07-06 Thread Abhishek Sahu
The QCOM NAND controller skips the bad block bytes when reading
with ECC enabled. The NAND base layer invokes ->read_oob() function
for bad block check which expects the BBM bytes to be copied at
badblockpos offset in OOB buffer. When initial support for this
driver was added, the driver specific function was added
temporarily for bad block check with assumption to change
for raw read in NAND base layer. Moving to raw read for bad block
check seems to take more time so this patch removes driver specific
bad block check function and uses following logic.

The QCOM NAND controller updates the BAD_BLOCK_STATUS bits value in
NAND_BUFFER_STATUS register with every page read operation. The OOB
buffer can be updated with this value while checking the status for
last codeword.

QCOM NAND controller layout does not support BBM byte at offset
other than zero so check the chip’s badblockpos and return probe
failure for all these chips.

Signed-off-by: Abhishek Sahu 
---
 drivers/mtd/nand/raw/qcom_nandc.c | 118 ++
 1 file changed, 31 insertions(+), 87 deletions(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c 
b/drivers/mtd/nand/raw/qcom_nandc.c
index 994f980..ea253ac 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -80,6 +80,8 @@
 /* NAND_BUFFER_STATUS bits */
 #defineBS_UNCORRECTABLE_BITBIT(8)
 #defineBS_CORRECTABLE_ERR_MSK  0x1f
+#define BAD_BLK_STATUS 16
+#define BAD_BLK_STATUS_2   24
 
 /* NAND_DEVn_CFG0 bits */
 #defineDISABLE_STATUS_AFTER_WRITE  4
@@ -1742,16 +1744,14 @@ static int parse_read_errors(struct qcom_nand_host 
*host, u8 *data_buf,
unsigned int max_bitflips = 0, uncorrectable_cws = 0;
struct read_stats *buf;
bool flash_op_err = false, erased;
-   int i;
+   int i, data_len, oob_len;
+   u32 flash, erased_cw, buffer = 0;
u8 *data_buf_start = data_buf, *oob_buf_start = oob_buf;
 
buf = (struct read_stats *)nandc->reg_read_buf;
nandc_read_buffer_sync(nandc, true);
 
for (i = 0; i < ecc->steps; i++, buf++) {
-   u32 flash, buffer, erased_cw;
-   int data_len, oob_len;
-
if (i == (ecc->steps - 1)) {
data_len = ecc->size - ((ecc->steps - 1) << 2);
oob_len = ecc->steps << 2;
@@ -1824,12 +1824,24 @@ static int parse_read_errors(struct qcom_nand_host 
*host, u8 *data_buf,
if (flash_op_err)
return -EIO;
 
-   if (!uncorrectable_cws)
-   return max_bitflips;
+   if (uncorrectable_cws) {
+   max_bitflips = check_for_erased_page(host, data_buf_start,
+   oob_buf_start, uncorrectable_cws,
+   page, max_bitflips);
+   }
 
-   return check_for_erased_page(host, data_buf_start, oob_buf_start,
-uncorrectable_cws, page,
-max_bitflips);
+   /*
+* Updates the BBM bytes in OOB buffer with BAD_BLK_STATUS bits value
+* of NAND_BUFFER_STATUS register. With every page read operation,
+* controller updates the bad block status data into this register.
+*/
+   if (oob_buf_start) {
+   oob_buf_start[0] = (buffer >> BAD_BLK_STATUS) & 0xff;
+   if (chip->options & NAND_BUSWIDTH_16)
+   oob_buf_start[1] = (buffer >> BAD_BLK_STATUS_2) & 0xff;
+   }
+
+   return max_bitflips;
 }
 
 /*
@@ -1913,41 +1925,6 @@ static int read_page_ecc(struct qcom_nand_host *host, u8 
*data_buf,
return parse_read_errors(host, data_buf_start, oob_buf_start, page);
 }
 
-/*
- * a helper that copies the last step/codeword of a page (containing free oob)
- * into our local buffer
- */
-static int copy_last_cw(struct qcom_nand_host *host, int page)
-{
-   struct nand_chip *chip = >chip;
-   struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-   struct nand_ecc_ctrl *ecc = >ecc;
-   int size;
-   int ret;
-
-   clear_read_regs(nandc);
-
-   size = host->use_ecc ? host->cw_data : host->cw_size;
-
-   /* prepare a clean read buffer */
-   memset(nandc->data_buffer, 0xff, size);
-
-   set_address(host, host->cw_size * (ecc->steps - 1), page);
-   update_rw_regs(host, 1, true);
-
-   config_nand_single_cw_page_read(nandc, host->use_ecc);
-
-   read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, size, 0);
-
-   ret = submit_descs(nandc);
-   if (ret)
-   dev_err(nandc->dev, "failed to copy last codeword\n");
-
-   free_descs(nandc);
-
-   return ret;
-}
-
 /* implements ecc->read_page() */
 static int qcom_nandc_read_page(struct mtd_info *mtd, 

[PATCH v5] mtd: rawnand: qcom: erased page bitflips detection

2018-07-03 Thread Abhishek Sahu
NAND parts can have bitflips in an erased page due to the
process technology used. In this case, QCOM NAND controller
is not able to identify that page as an erased page.
Currently the driver calls nand_check_erased_ecc_chunk() for
identifying the erased pages but this won’t work always since the
checking is being with ECC engine returned data. In case of
bitflips, the ECC engine tries to correct the data and then it
generates the uncorrectable error. Now, this data is not equal to
original raw data. For erased CW identification, the raw data
should be read again from NAND device and this
nand_check_erased_ecc_chunk function() should be called for raw
data only.

Now following logic is being added to identify the erased
codeword bitflips.

1. In most of the cases, not all the codewords will have bitflips
   and only single CW will have bitflips. So, there is no need to
   read the complete raw page data. The NAND raw read can be
   scheduled for any CW in page. The NAND controller works on CW
   basis and it will update the status register after each CW read.
   Maintain the bitmask for the CW which generated the uncorrectable
   error.
2. Do raw read for all the CW's which generated the uncorrectable
   error.
3. Both DATA and OOB need to be checked for number of 0. The
   top-level API can be called with only data buf or OOB buf so use
   chip->databuf if data buf is null and chip->oob_poi if
   OOB buf is null for copying the raw bytes temporarily.
4. For each CW, check the number of 0 in cw_data and usable
   oob bytes, The bbm and spare (unused) bytes bit flip won’t
   affect the ECC so don’t check the number of bitflips in this area.

Signed-off-by: Abhishek Sahu 
---
* Changes from v4:

 1. Used for_each_set_bit for determining CW’s which generated
uncorrectable errors.
 2. Introduced cw_data_buf and cw_oob_buf which will have starting
buffer address for current codeword and used the same in helper
functions.
 3. Added new line before calling of nand_check_erased_ecc_chunk for
better code readability.

* Changes from v3:

 1. Major changes in erased codeword detection for
raw read function

* Changes from v2:
  NONE

* Changes from v1:
 1. Minor change in commit message
 2. invalidate pagebuf if databuf or oob_poi is used

 drivers/mtd/nand/raw/qcom_nandc.c | 126 +++---
 1 file changed, 89 insertions(+), 37 deletions(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c 
b/drivers/mtd/nand/raw/qcom_nandc.c
index 160acdf..994f980 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -1656,20 +1656,94 @@ static int check_flash_errors(struct qcom_nand_host 
*host, int cw_cnt)
 }
 
 /*
+ * Bitflips can happen in erased codewords also so this function counts the
+ * number of 0 in each CW for which ECC engine returns the uncorrectable
+ * error. The page will be assumed as erased if this count is less than or
+ * equal to the ecc->strength for each CW.
+ *
+ * 1. Both DATA and OOB need to be checked for number of 0. The
+ *top-level API can be called with only data buf or OOB buf so use
+ *chip->data_buf if data buf is null and chip->oob_poi if oob buf
+ *is null for copying the raw bytes.
+ * 2. Perform raw read for all the CW which has uncorrectable errors.
+ * 3. For each CW, check the number of 0 in cw_data and usable OOB bytes.
+ *The BBM and spare bytes bit flip won’t affect the ECC so don’t check
+ *the number of bitflips in this area.
+ */
+static int
+check_for_erased_page(struct qcom_nand_host *host, u8 *data_buf,
+ u8 *oob_buf, unsigned long uncorrectable_cws,
+ int page, unsigned int max_bitflips)
+{
+   struct nand_chip *chip = >chip;
+   struct mtd_info *mtd = nand_to_mtd(chip);
+   struct nand_ecc_ctrl *ecc = >ecc;
+   u8 *cw_data_buf, *cw_oob_buf;
+   int cw, data_size, oob_size, ret = 0;
+
+   if (!data_buf) {
+   data_buf = chip->data_buf;
+   chip->pagebuf = -1;
+   }
+
+   if (!oob_buf) {
+   oob_buf = chip->oob_poi;
+   chip->pagebuf = -1;
+   }
+
+   for_each_set_bit(cw, _cws, ecc->steps) {
+   if (cw == (ecc->steps - 1)) {
+   data_size = ecc->size - ((ecc->steps - 1) * 4);
+   oob_size = (ecc->steps * 4) + host->ecc_bytes_hw;
+   } else {
+   data_size = host->cw_data;
+   oob_size = host->ecc_bytes_hw;
+   }
+
+   /* determine starting buffer address for current CW */
+   cw_data_buf = data_buf + (cw * host->cw_data);
+   cw_oob_buf = oob_buf + (cw * ecc->bytes);
+
+   ret = qcom_nandc_read_cw_raw(mtd, chip, cw_data_buf,
+cw_oob_buf, page, c

[PATCH v5] mtd: rawnand: qcom: erased page bitflips detection

2018-07-03 Thread Abhishek Sahu
NAND parts can have bitflips in an erased page due to the
process technology used. In this case, QCOM NAND controller
is not able to identify that page as an erased page.
Currently the driver calls nand_check_erased_ecc_chunk() for
identifying the erased pages but this won’t work always since the
checking is being with ECC engine returned data. In case of
bitflips, the ECC engine tries to correct the data and then it
generates the uncorrectable error. Now, this data is not equal to
original raw data. For erased CW identification, the raw data
should be read again from NAND device and this
nand_check_erased_ecc_chunk function() should be called for raw
data only.

Now following logic is being added to identify the erased
codeword bitflips.

1. In most of the cases, not all the codewords will have bitflips
   and only single CW will have bitflips. So, there is no need to
   read the complete raw page data. The NAND raw read can be
   scheduled for any CW in page. The NAND controller works on CW
   basis and it will update the status register after each CW read.
   Maintain the bitmask for the CW which generated the uncorrectable
   error.
2. Do raw read for all the CW's which generated the uncorrectable
   error.
3. Both DATA and OOB need to be checked for number of 0. The
   top-level API can be called with only data buf or OOB buf so use
   chip->databuf if data buf is null and chip->oob_poi if
   OOB buf is null for copying the raw bytes temporarily.
4. For each CW, check the number of 0 in cw_data and usable
   oob bytes, The bbm and spare (unused) bytes bit flip won’t
   affect the ECC so don’t check the number of bitflips in this area.

Signed-off-by: Abhishek Sahu 
---
* Changes from v4:

 1. Used for_each_set_bit for determining CW’s which generated
uncorrectable errors.
 2. Introduced cw_data_buf and cw_oob_buf which will have starting
buffer address for current codeword and used the same in helper
functions.
 3. Added new line before calling of nand_check_erased_ecc_chunk for
better code readability.

* Changes from v3:

 1. Major changes in erased codeword detection for
raw read function

* Changes from v2:
  NONE

* Changes from v1:
 1. Minor change in commit message
 2. invalidate pagebuf if databuf or oob_poi is used

 drivers/mtd/nand/raw/qcom_nandc.c | 126 +++---
 1 file changed, 89 insertions(+), 37 deletions(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c 
b/drivers/mtd/nand/raw/qcom_nandc.c
index 160acdf..994f980 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -1656,20 +1656,94 @@ static int check_flash_errors(struct qcom_nand_host 
*host, int cw_cnt)
 }
 
 /*
+ * Bitflips can happen in erased codewords also so this function counts the
+ * number of 0 in each CW for which ECC engine returns the uncorrectable
+ * error. The page will be assumed as erased if this count is less than or
+ * equal to the ecc->strength for each CW.
+ *
+ * 1. Both DATA and OOB need to be checked for number of 0. The
+ *top-level API can be called with only data buf or OOB buf so use
+ *chip->data_buf if data buf is null and chip->oob_poi if oob buf
+ *is null for copying the raw bytes.
+ * 2. Perform raw read for all the CW which has uncorrectable errors.
+ * 3. For each CW, check the number of 0 in cw_data and usable OOB bytes.
+ *The BBM and spare bytes bit flip won’t affect the ECC so don’t check
+ *the number of bitflips in this area.
+ */
+static int
+check_for_erased_page(struct qcom_nand_host *host, u8 *data_buf,
+ u8 *oob_buf, unsigned long uncorrectable_cws,
+ int page, unsigned int max_bitflips)
+{
+   struct nand_chip *chip = >chip;
+   struct mtd_info *mtd = nand_to_mtd(chip);
+   struct nand_ecc_ctrl *ecc = >ecc;
+   u8 *cw_data_buf, *cw_oob_buf;
+   int cw, data_size, oob_size, ret = 0;
+
+   if (!data_buf) {
+   data_buf = chip->data_buf;
+   chip->pagebuf = -1;
+   }
+
+   if (!oob_buf) {
+   oob_buf = chip->oob_poi;
+   chip->pagebuf = -1;
+   }
+
+   for_each_set_bit(cw, _cws, ecc->steps) {
+   if (cw == (ecc->steps - 1)) {
+   data_size = ecc->size - ((ecc->steps - 1) * 4);
+   oob_size = (ecc->steps * 4) + host->ecc_bytes_hw;
+   } else {
+   data_size = host->cw_data;
+   oob_size = host->ecc_bytes_hw;
+   }
+
+   /* determine starting buffer address for current CW */
+   cw_data_buf = data_buf + (cw * host->cw_data);
+   cw_oob_buf = oob_buf + (cw * ecc->bytes);
+
+   ret = qcom_nandc_read_cw_raw(mtd, chip, cw_data_buf,
+cw_oob_buf, page, c

Re: [PATCH v4 00/15] Update for QCOM NAND driver

2018-07-02 Thread Abhishek Sahu

On 2018-07-01 23:39, Miquel Raynal wrote:

Hi Abhishek,

Abhishek Sahu  wrote on Wed, 20 Jun 2018
12:57:27 +0530:


* v4:

1. Added patch to make other ECC configurations function static.
2. Clubbed the DT update patches.
3. Removed the bad block related patch. Discussion is going on
   related with for proper solution so planning to submit separate
   patch series for all bad block related changes.
4. Made the single codeword raw read function and used the same
   for raw page read.
5. Changes in erased codeword detection to raw read function.

* v3:

1. Addressed all review comments in v2.
2. Added patch for removing redundant nand-ecc-step-size DT property.
3. Renamed ECC configuration setup function with minor code changes.
4. Modified comments and commit message for few patches.

* v2:

1. Addressed all review comments in v1.
1. Make the generic helper function for NAND ECC parameters setup
   and used this helper function for QCOM and Denali nand driver
   for ECC setup.
2. Modified commit message for some of the patches and added more
   comments.
3. Added new patch for fixing ‘return 0’ for raw read.
4. Removed the read last codeword part for nand oob write.
5. Reorganized bad block check function and removed the
   read_last_cw function completely.

* v1:

This patch series mainly deals with error handling and erased page
bitflip detection for QCOM NAND driver.

1. The error handling was missing for some of the cases so fixed
   the same.

2. Add the support for taking ECC strength from ONFI parameter.
   The earlier QCOM boards were coming with 4-bit ECC chip but
   now the same boards are coming with 8-bit ECC chip since the
   earlier 4-bit parts are obsolete from some vendors.

3. We got few issues related with NAND erased page bitflips. The
   QCOM NAND controller can’t detect the bitflip in completely erased
   page so added the support to detect the same. It implemented the
   logic mentioned in patch [1] which didn’t go in mainline and later
   the generic functions were provided [2] to count the number of
   bitflips and make all 0xff. This patch series did some optimization
   logic to prevent the unnecessary full page raw read and data copy
   from QCOM NAND controller to DMA.

4. Following are the testing done for these patches in QCOM IPQ8074
   HK01 (4-bit and 8-bit ECC chip) and IPQ806x AP148 boards.
a. Run all mtd test and check if it passes
b. Introduce custom bitflips in erased page and check if it
   returns no error/EUCLEAN/EBADMSG depending upon number of
   bitflips and position.
c. Introduce failure condition for operational failure and
   check if it detects the same.

[1]: https://patchwork.ozlabs.org/patch/328994/
[2]: https://patchwork.ozlabs.org/patch/509970/

Abhishek Sahu (15):
  mtd: rawnand: helper function for setting up ECC configuration
  mtd: rawnand: denali: use helper function for ecc setup
  dt-bindings: qcom_nandc: update for ECC strength and step size
  mtd: rawnand: qcom: remove dt property nand-ecc-step-size
  mtd: rawnand: qcom: use the ecc strength from device parameter
  mtd: rawnand: qcom: wait for desc completion in all BAM channels
  mtd: rawnand: qcom: erased page detection for uncorrectable errors
only
  mtd: rawnand: qcom: fix null pointer access for erased page 
detection

  mtd: rawnand: qcom: parse read errors for read oob also
  mtd: rawnand: qcom: modify write_oob to remove read codeword part
  mtd: rawnand: qcom: fix return value for raw page read
  mtd: rawnand: qcom: check for operation errors in case of raw read
  mtd: rawnand: qcom: code reorganization for raw read
  mtd: rawnand: qcom: erased page bitflips detection
  mtd: rawnand: provide only single helper function for ECC conf

 .../devicetree/bindings/mtd/qcom_nandc.txt |   7 +-
 drivers/mtd/nand/raw/denali.c  |  30 +-
 drivers/mtd/nand/raw/nand_base.c   |  72 ++-
 drivers/mtd/nand/raw/qcom_nandc.c  | 491 
++---

 include/linux/mtd/rawnand.h|  10 +-
 5 files changed, 380 insertions(+), 230 deletions(-)



Thank you very much for the series and the changes you have done.



 Thanks a lot Miquel for your great support and help in
 reviewing and merging these patches :-)


Applied all patches but "erased page bitflips detection" because I'm
waiting for one small modification on this one.


 Sure. I will send that updated patch.

 Regards,
 Abhishek


Re: [PATCH v4 00/15] Update for QCOM NAND driver

2018-07-02 Thread Abhishek Sahu

On 2018-07-01 23:39, Miquel Raynal wrote:

Hi Abhishek,

Abhishek Sahu  wrote on Wed, 20 Jun 2018
12:57:27 +0530:


* v4:

1. Added patch to make other ECC configurations function static.
2. Clubbed the DT update patches.
3. Removed the bad block related patch. Discussion is going on
   related with for proper solution so planning to submit separate
   patch series for all bad block related changes.
4. Made the single codeword raw read function and used the same
   for raw page read.
5. Changes in erased codeword detection to raw read function.

* v3:

1. Addressed all review comments in v2.
2. Added patch for removing redundant nand-ecc-step-size DT property.
3. Renamed ECC configuration setup function with minor code changes.
4. Modified comments and commit message for few patches.

* v2:

1. Addressed all review comments in v1.
1. Make the generic helper function for NAND ECC parameters setup
   and used this helper function for QCOM and Denali nand driver
   for ECC setup.
2. Modified commit message for some of the patches and added more
   comments.
3. Added new patch for fixing ‘return 0’ for raw read.
4. Removed the read last codeword part for nand oob write.
5. Reorganized bad block check function and removed the
   read_last_cw function completely.

* v1:

This patch series mainly deals with error handling and erased page
bitflip detection for QCOM NAND driver.

1. The error handling was missing for some of the cases so fixed
   the same.

2. Add the support for taking ECC strength from ONFI parameter.
   The earlier QCOM boards were coming with 4-bit ECC chip but
   now the same boards are coming with 8-bit ECC chip since the
   earlier 4-bit parts are obsolete from some vendors.

3. We got few issues related with NAND erased page bitflips. The
   QCOM NAND controller can’t detect the bitflip in completely erased
   page so added the support to detect the same. It implemented the
   logic mentioned in patch [1] which didn’t go in mainline and later
   the generic functions were provided [2] to count the number of
   bitflips and make all 0xff. This patch series did some optimization
   logic to prevent the unnecessary full page raw read and data copy
   from QCOM NAND controller to DMA.

4. Following are the testing done for these patches in QCOM IPQ8074
   HK01 (4-bit and 8-bit ECC chip) and IPQ806x AP148 boards.
a. Run all mtd test and check if it passes
b. Introduce custom bitflips in erased page and check if it
   returns no error/EUCLEAN/EBADMSG depending upon number of
   bitflips and position.
c. Introduce failure condition for operational failure and
   check if it detects the same.

[1]: https://patchwork.ozlabs.org/patch/328994/
[2]: https://patchwork.ozlabs.org/patch/509970/

Abhishek Sahu (15):
  mtd: rawnand: helper function for setting up ECC configuration
  mtd: rawnand: denali: use helper function for ecc setup
  dt-bindings: qcom_nandc: update for ECC strength and step size
  mtd: rawnand: qcom: remove dt property nand-ecc-step-size
  mtd: rawnand: qcom: use the ecc strength from device parameter
  mtd: rawnand: qcom: wait for desc completion in all BAM channels
  mtd: rawnand: qcom: erased page detection for uncorrectable errors
only
  mtd: rawnand: qcom: fix null pointer access for erased page 
detection

  mtd: rawnand: qcom: parse read errors for read oob also
  mtd: rawnand: qcom: modify write_oob to remove read codeword part
  mtd: rawnand: qcom: fix return value for raw page read
  mtd: rawnand: qcom: check for operation errors in case of raw read
  mtd: rawnand: qcom: code reorganization for raw read
  mtd: rawnand: qcom: erased page bitflips detection
  mtd: rawnand: provide only single helper function for ECC conf

 .../devicetree/bindings/mtd/qcom_nandc.txt |   7 +-
 drivers/mtd/nand/raw/denali.c  |  30 +-
 drivers/mtd/nand/raw/nand_base.c   |  72 ++-
 drivers/mtd/nand/raw/qcom_nandc.c  | 491 
++---

 include/linux/mtd/rawnand.h|  10 +-
 5 files changed, 380 insertions(+), 230 deletions(-)



Thank you very much for the series and the changes you have done.



 Thanks a lot Miquel for your great support and help in
 reviewing and merging these patches :-)


Applied all patches but "erased page bitflips detection" because I'm
waiting for one small modification on this one.


 Sure. I will send that updated patch.

 Regards,
 Abhishek


Re: [PATCH] arm: dts: qcom: Fix 'interrupts = <>' property to use proper macros

2018-06-22 Thread Abhishek Sahu

On 2018-06-20 14:53, Sricharan R wrote:

Fix all nodes to use proper GIC_* macros for the interrupt type and the
interrupt trigger settings to avoid the boot warnings.


 Thanks Sricharan for fixing these warnings.

 Applied over 4.18 rc1 and tested in IPQ8064 AP148 board.
 No backtraces are coming during boottime and IRQ seems OK.

 root@OpenWrt:/# cat /proc/interrupts
   CPU0   CPU1
 16:   2602   4750 GIC-0  18 Edge  gp_timer
 17:  0  0 GIC-0  26 Level arm-pmu
 23: 19  0 GIC-0 241 Level ahci[2900.sata]
 24:912  0 GIC-0 184 Level msm_serial0
 25:113  0 GIC-0 185 Level i2c_qup
 26:  6  0 GIC-0 187 Level 1a28.spi
IPI0:  0  0  CPU wakeup interrupts
IPI1:  0  0  Timer broadcast interrupts
IPI2:   2045   1713  Rescheduling interrupts
IPI3:  1  4  Function call interrupts
IPI4:  0  0  CPU stop interrupts
IPI5:  0  0  IRQ work interrupts
IPI6:  0  0  completion interrupts
Err:  0



Signed-off-by: Sricharan R 


Tested-by: Abhishek Sahu 



Re: [PATCH] arm: dts: qcom: Fix 'interrupts = <>' property to use proper macros

2018-06-22 Thread Abhishek Sahu

On 2018-06-20 14:53, Sricharan R wrote:

Fix all nodes to use proper GIC_* macros for the interrupt type and the
interrupt trigger settings to avoid the boot warnings.


 Thanks Sricharan for fixing these warnings.

 Applied over 4.18 rc1 and tested in IPQ8064 AP148 board.
 No backtraces are coming during boottime and IRQ seems OK.

 root@OpenWrt:/# cat /proc/interrupts
   CPU0   CPU1
 16:   2602   4750 GIC-0  18 Edge  gp_timer
 17:  0  0 GIC-0  26 Level arm-pmu
 23: 19  0 GIC-0 241 Level ahci[2900.sata]
 24:912  0 GIC-0 184 Level msm_serial0
 25:113  0 GIC-0 185 Level i2c_qup
 26:  6  0 GIC-0 187 Level 1a28.spi
IPI0:  0  0  CPU wakeup interrupts
IPI1:  0  0  Timer broadcast interrupts
IPI2:   2045   1713  Rescheduling interrupts
IPI3:  1  4  Function call interrupts
IPI4:  0  0  CPU stop interrupts
IPI5:  0  0  IRQ work interrupts
IPI6:  0  0  completion interrupts
Err:  0



Signed-off-by: Sricharan R 


Tested-by: Abhishek Sahu 



Re: [PATCH v3 13/16] mtd: rawnand: qcom: minor code reorganization for bad block check

2018-06-20 Thread Abhishek Sahu

On 2018-06-18 17:05, Miquel Raynal wrote:

Hi Abhishek,

Boris, one question for you below :)


>> >> >>   So for last CW, the 464 is BBM (i.e 2048th byte) in
>> >>   full page.
>> >> >> > >> >>   clear_bam_transaction(nandc);
>> >> >> -ret = copy_last_cw(host, page);
>> >> >> -if (ret)
>> >> >> +clear_read_regs(nandc);
>> >> >> +
>> >> >> +set_address(host, host->cw_size * (ecc->steps - 1), page);
>> >> >> +update_rw_regs(host, 1, true);
>> >> >> +
>> >> >> +/*
>> >> >> + * The last codeword data will be copied from NAND device to NAND
>> >> >> + * controller internal HW buffer. Copy only required BBM size 
bytes
>> >> >> + * from this HW buffer to bbm_bytes_buf which is present at
>> >> >> + * bbpos offset.
>> >> >> + */
>> >> >> +nandc_set_read_loc(nandc, 0, bbpos, host->bbm_size, 1);
>> >> >> +config_nand_single_cw_page_read(nandc);
>> >> >> +read_data_dma(nandc, FLASH_BUF_ACC + bbpos, bbm_bytes_buf,
>> >> >> +  host->bbm_size, 0);
>> >> >> +
>> >> >> +ret = submit_descs(nandc);
>> >> >> +free_descs(nandc);
>> >> >> +if (ret) {
>> >> >> +dev_err(nandc->dev, "failed to copy bad block bytes\n");
>> >> >>  goto err;
>> >> >> +}
>> >> >> >> flash_status = le32_to_cpu(nandc->reg_read_buf[0]);
>> >> >> >> @@ -2141,12 +2127,10 @@ static int qcom_nandc_block_bad(struct >> 
mtd_info *mtd, loff_t ofs)
>> >> >>  goto err;
>> >> >>  }
>> >> >> >> -   bbpos = mtd->writesize - host->cw_size * (ecc->steps - 1);
>> >> >> -
>> >> >> -bad = nandc->data_buffer[bbpos] != 0xff;
>> >> >> +bad = bbm_bytes_buf[0] != 0xff;
>> >> > > This is suspect as it still points to the beginning of the data 
buffer.
>> >> > Can you please check you did not meant bbm_bytes_buf[bbpos]?
>> >> >
>> >>   The main thing here is
>> >>   nandc_set_read_loc(nandc, 0, bbpos, host->bbm_size, 1);
>> >> >>   After reading one complete CW from NAND, the data will be still
>> >>   in NAND HW buffer.
>> >> >>   The above register tells that we need to read data from
>> >>   bbpos of size host->bbm_size (which is 1 byte for 8 bus witdh
>> >>   and 2 byte for 16 bus width) in bbm_bytes_buf.
>> > > I see: idx 0 in bbm_bytes_buf is the data at offset bbpos. Then
>> > it's ok.
>> > >> >>   So bbm_bytes_buf[0] will contain the BBM first byte.
>> >>   and bbm_bytes_buf[1] will contain the BBM second byte.
>> >> >>   Regards,
>> >>   Abhishek
>> >> >> >> >>if (chip->options & NAND_BUSWIDTH_16)
>> >> >> -bad = bad || (nandc->data_buffer[bbpos + 1] != 0xff);
>> >> >> +bad = bad || (bbm_bytes_buf[1] != 0xff);
>> > > Sorry, my mistake, I did not see the above line.
>> > > However, technically, the BBM could be located in the first, second or
>> > last page of the block. You should check the three of them are 0xFF
>> > before declaring the block is not bad.
>> > > The more I look at the function, the more I wonder if you actually need
>> > it. Why does the generic nand_block_bad() implementation in the core
>> > do not fit?
>> >>   The BBM bytes can be accessed in raw mode only for QCOM NAND
>>   Contoller. We started with following patch for initial patches
>> >>   http://patchwork.ozlabs.org/patch/508565/
>> >>   I am also not very much sure, how can we go ahead now.
>>   Ideally we need to use generic function only which
>>   requires raw_read.
>> > > I see, thanks for pointing this thread.
> > Well for now then let's keep our driver-specific implementation.
> > I will just ask you to do a consistent check as requested above (you
> can copy code from the core) and add a comment above this function
> explaining why it is needed (what you just told me).
>
  Hi Miquel,

  I explored more regarding making custom bad block functions in this
  thread and it looks like, we can move to generic block_bad function
  by small changes in QCOM NAND driver
  only. The main problem was, in read page with ECC, the bad block
  byte was skipped.

  But controller is copying the bad block bytes in another register
  with following status bytes.

  BAD_BLOCK_STATUS : With every page read operation, when the 
controller
  reads a page with a bad block, it writes the bad block status data 
into

  this register.

  We can update the BBM bytes at start of OOB data in read_oob 
function
  with these status bytes. It will help in getting rid of 
driver-specific

  implementation for chip->block_bad.


If think this is acceptable.



  For chip->block_markbad, if we want to get rid of
  driver-specific implementation then we can have
  following logic

  in write_oob function check for bad block bytes in oob
  and do the raw write for updating BBM bytes alone in
  flash if BBM bytes are non 0xff.


Ok but this will have to be properly explained in a descriptive 
comment!


Maybe Boris can give its point of view on the subject. Is it worth
adding the above 'hacks' in the qcom driver and get rid of the
driver-specific 

Re: [PATCH v3 13/16] mtd: rawnand: qcom: minor code reorganization for bad block check

2018-06-20 Thread Abhishek Sahu

On 2018-06-18 17:05, Miquel Raynal wrote:

Hi Abhishek,

Boris, one question for you below :)


>> >> >>   So for last CW, the 464 is BBM (i.e 2048th byte) in
>> >>   full page.
>> >> >> > >> >>   clear_bam_transaction(nandc);
>> >> >> -ret = copy_last_cw(host, page);
>> >> >> -if (ret)
>> >> >> +clear_read_regs(nandc);
>> >> >> +
>> >> >> +set_address(host, host->cw_size * (ecc->steps - 1), page);
>> >> >> +update_rw_regs(host, 1, true);
>> >> >> +
>> >> >> +/*
>> >> >> + * The last codeword data will be copied from NAND device to NAND
>> >> >> + * controller internal HW buffer. Copy only required BBM size 
bytes
>> >> >> + * from this HW buffer to bbm_bytes_buf which is present at
>> >> >> + * bbpos offset.
>> >> >> + */
>> >> >> +nandc_set_read_loc(nandc, 0, bbpos, host->bbm_size, 1);
>> >> >> +config_nand_single_cw_page_read(nandc);
>> >> >> +read_data_dma(nandc, FLASH_BUF_ACC + bbpos, bbm_bytes_buf,
>> >> >> +  host->bbm_size, 0);
>> >> >> +
>> >> >> +ret = submit_descs(nandc);
>> >> >> +free_descs(nandc);
>> >> >> +if (ret) {
>> >> >> +dev_err(nandc->dev, "failed to copy bad block bytes\n");
>> >> >>  goto err;
>> >> >> +}
>> >> >> >> flash_status = le32_to_cpu(nandc->reg_read_buf[0]);
>> >> >> >> @@ -2141,12 +2127,10 @@ static int qcom_nandc_block_bad(struct >> 
mtd_info *mtd, loff_t ofs)
>> >> >>  goto err;
>> >> >>  }
>> >> >> >> -   bbpos = mtd->writesize - host->cw_size * (ecc->steps - 1);
>> >> >> -
>> >> >> -bad = nandc->data_buffer[bbpos] != 0xff;
>> >> >> +bad = bbm_bytes_buf[0] != 0xff;
>> >> > > This is suspect as it still points to the beginning of the data 
buffer.
>> >> > Can you please check you did not meant bbm_bytes_buf[bbpos]?
>> >> >
>> >>   The main thing here is
>> >>   nandc_set_read_loc(nandc, 0, bbpos, host->bbm_size, 1);
>> >> >>   After reading one complete CW from NAND, the data will be still
>> >>   in NAND HW buffer.
>> >> >>   The above register tells that we need to read data from
>> >>   bbpos of size host->bbm_size (which is 1 byte for 8 bus witdh
>> >>   and 2 byte for 16 bus width) in bbm_bytes_buf.
>> > > I see: idx 0 in bbm_bytes_buf is the data at offset bbpos. Then
>> > it's ok.
>> > >> >>   So bbm_bytes_buf[0] will contain the BBM first byte.
>> >>   and bbm_bytes_buf[1] will contain the BBM second byte.
>> >> >>   Regards,
>> >>   Abhishek
>> >> >> >> >>if (chip->options & NAND_BUSWIDTH_16)
>> >> >> -bad = bad || (nandc->data_buffer[bbpos + 1] != 0xff);
>> >> >> +bad = bad || (bbm_bytes_buf[1] != 0xff);
>> > > Sorry, my mistake, I did not see the above line.
>> > > However, technically, the BBM could be located in the first, second or
>> > last page of the block. You should check the three of them are 0xFF
>> > before declaring the block is not bad.
>> > > The more I look at the function, the more I wonder if you actually need
>> > it. Why does the generic nand_block_bad() implementation in the core
>> > do not fit?
>> >>   The BBM bytes can be accessed in raw mode only for QCOM NAND
>>   Contoller. We started with following patch for initial patches
>> >>   http://patchwork.ozlabs.org/patch/508565/
>> >>   I am also not very much sure, how can we go ahead now.
>>   Ideally we need to use generic function only which
>>   requires raw_read.
>> > > I see, thanks for pointing this thread.
> > Well for now then let's keep our driver-specific implementation.
> > I will just ask you to do a consistent check as requested above (you
> can copy code from the core) and add a comment above this function
> explaining why it is needed (what you just told me).
>
  Hi Miquel,

  I explored more regarding making custom bad block functions in this
  thread and it looks like, we can move to generic block_bad function
  by small changes in QCOM NAND driver
  only. The main problem was, in read page with ECC, the bad block
  byte was skipped.

  But controller is copying the bad block bytes in another register
  with following status bytes.

  BAD_BLOCK_STATUS : With every page read operation, when the 
controller
  reads a page with a bad block, it writes the bad block status data 
into

  this register.

  We can update the BBM bytes at start of OOB data in read_oob 
function
  with these status bytes. It will help in getting rid of 
driver-specific

  implementation for chip->block_bad.


If think this is acceptable.



  For chip->block_markbad, if we want to get rid of
  driver-specific implementation then we can have
  following logic

  in write_oob function check for bad block bytes in oob
  and do the raw write for updating BBM bytes alone in
  flash if BBM bytes are non 0xff.


Ok but this will have to be properly explained in a descriptive 
comment!


Maybe Boris can give its point of view on the subject. Is it worth
adding the above 'hacks' in the qcom driver and get rid of the
driver-specific 

[PATCH v4 00/15] Update for QCOM NAND driver

2018-06-20 Thread Abhishek Sahu
* v4:

1. Added patch to make other ECC configurations function static.
2. Clubbed the DT update patches.
3. Removed the bad block related patch. Discussion is going on
   related with for proper solution so planning to submit separate
   patch series for all bad block related changes.
4. Made the single codeword raw read function and used the same
   for raw page read.
5. Changes in erased codeword detection to raw read function.

* v3:

1. Addressed all review comments in v2.
2. Added patch for removing redundant nand-ecc-step-size DT property.
3. Renamed ECC configuration setup function with minor code changes.
4. Modified comments and commit message for few patches.

* v2:

1. Addressed all review comments in v1.
1. Make the generic helper function for NAND ECC parameters setup
   and used this helper function for QCOM and Denali nand driver
   for ECC setup.
2. Modified commit message for some of the patches and added more
   comments.
3. Added new patch for fixing ‘return 0’ for raw read.
4. Removed the read last codeword part for nand oob write.
5. Reorganized bad block check function and removed the
   read_last_cw function completely.

* v1:

This patch series mainly deals with error handling and erased page
bitflip detection for QCOM NAND driver.

1. The error handling was missing for some of the cases so fixed
   the same.

2. Add the support for taking ECC strength from ONFI parameter.
   The earlier QCOM boards were coming with 4-bit ECC chip but
   now the same boards are coming with 8-bit ECC chip since the
   earlier 4-bit parts are obsolete from some vendors.

3. We got few issues related with NAND erased page bitflips. The
   QCOM NAND controller can’t detect the bitflip in completely erased
   page so added the support to detect the same. It implemented the
   logic mentioned in patch [1] which didn’t go in mainline and later
   the generic functions were provided [2] to count the number of
   bitflips and make all 0xff. This patch series did some optimization
   logic to prevent the unnecessary full page raw read and data copy
   from QCOM NAND controller to DMA.

4. Following are the testing done for these patches in QCOM IPQ8074
   HK01 (4-bit and 8-bit ECC chip) and IPQ806x AP148 boards.
a. Run all mtd test and check if it passes
b. Introduce custom bitflips in erased page and check if it
   returns no error/EUCLEAN/EBADMSG depending upon number of
   bitflips and position.
c. Introduce failure condition for operational failure and
   check if it detects the same.

[1]: https://patchwork.ozlabs.org/patch/328994/
[2]: https://patchwork.ozlabs.org/patch/509970/

Abhishek Sahu (15):
  mtd: rawnand: helper function for setting up ECC configuration
  mtd: rawnand: denali: use helper function for ecc setup
  dt-bindings: qcom_nandc: update for ECC strength and step size
  mtd: rawnand: qcom: remove dt property nand-ecc-step-size
  mtd: rawnand: qcom: use the ecc strength from device parameter
  mtd: rawnand: qcom: wait for desc completion in all BAM channels
  mtd: rawnand: qcom: erased page detection for uncorrectable errors
only
  mtd: rawnand: qcom: fix null pointer access for erased page detection
  mtd: rawnand: qcom: parse read errors for read oob also
  mtd: rawnand: qcom: modify write_oob to remove read codeword part
  mtd: rawnand: qcom: fix return value for raw page read
  mtd: rawnand: qcom: check for operation errors in case of raw read
  mtd: rawnand: qcom: code reorganization for raw read
  mtd: rawnand: qcom: erased page bitflips detection
  mtd: rawnand: provide only single helper function for ECC conf

 .../devicetree/bindings/mtd/qcom_nandc.txt |   7 +-
 drivers/mtd/nand/raw/denali.c  |  30 +-
 drivers/mtd/nand/raw/nand_base.c   |  72 ++-
 drivers/mtd/nand/raw/qcom_nandc.c  | 491 ++---
 include/linux/mtd/rawnand.h|  10 +-
 5 files changed, 380 insertions(+), 230 deletions(-)

-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc.
is a member of Code Aurora Forum, hosted by The Linux Foundation



[PATCH v4 00/15] Update for QCOM NAND driver

2018-06-20 Thread Abhishek Sahu
* v4:

1. Added patch to make other ECC configurations function static.
2. Clubbed the DT update patches.
3. Removed the bad block related patch. Discussion is going on
   related with for proper solution so planning to submit separate
   patch series for all bad block related changes.
4. Made the single codeword raw read function and used the same
   for raw page read.
5. Changes in erased codeword detection to raw read function.

* v3:

1. Addressed all review comments in v2.
2. Added patch for removing redundant nand-ecc-step-size DT property.
3. Renamed ECC configuration setup function with minor code changes.
4. Modified comments and commit message for few patches.

* v2:

1. Addressed all review comments in v1.
1. Make the generic helper function for NAND ECC parameters setup
   and used this helper function for QCOM and Denali nand driver
   for ECC setup.
2. Modified commit message for some of the patches and added more
   comments.
3. Added new patch for fixing ‘return 0’ for raw read.
4. Removed the read last codeword part for nand oob write.
5. Reorganized bad block check function and removed the
   read_last_cw function completely.

* v1:

This patch series mainly deals with error handling and erased page
bitflip detection for QCOM NAND driver.

1. The error handling was missing for some of the cases so fixed
   the same.

2. Add the support for taking ECC strength from ONFI parameter.
   The earlier QCOM boards were coming with 4-bit ECC chip but
   now the same boards are coming with 8-bit ECC chip since the
   earlier 4-bit parts are obsolete from some vendors.

3. We got few issues related with NAND erased page bitflips. The
   QCOM NAND controller can’t detect the bitflip in completely erased
   page so added the support to detect the same. It implemented the
   logic mentioned in patch [1] which didn’t go in mainline and later
   the generic functions were provided [2] to count the number of
   bitflips and make all 0xff. This patch series did some optimization
   logic to prevent the unnecessary full page raw read and data copy
   from QCOM NAND controller to DMA.

4. Following are the testing done for these patches in QCOM IPQ8074
   HK01 (4-bit and 8-bit ECC chip) and IPQ806x AP148 boards.
a. Run all mtd test and check if it passes
b. Introduce custom bitflips in erased page and check if it
   returns no error/EUCLEAN/EBADMSG depending upon number of
   bitflips and position.
c. Introduce failure condition for operational failure and
   check if it detects the same.

[1]: https://patchwork.ozlabs.org/patch/328994/
[2]: https://patchwork.ozlabs.org/patch/509970/

Abhishek Sahu (15):
  mtd: rawnand: helper function for setting up ECC configuration
  mtd: rawnand: denali: use helper function for ecc setup
  dt-bindings: qcom_nandc: update for ECC strength and step size
  mtd: rawnand: qcom: remove dt property nand-ecc-step-size
  mtd: rawnand: qcom: use the ecc strength from device parameter
  mtd: rawnand: qcom: wait for desc completion in all BAM channels
  mtd: rawnand: qcom: erased page detection for uncorrectable errors
only
  mtd: rawnand: qcom: fix null pointer access for erased page detection
  mtd: rawnand: qcom: parse read errors for read oob also
  mtd: rawnand: qcom: modify write_oob to remove read codeword part
  mtd: rawnand: qcom: fix return value for raw page read
  mtd: rawnand: qcom: check for operation errors in case of raw read
  mtd: rawnand: qcom: code reorganization for raw read
  mtd: rawnand: qcom: erased page bitflips detection
  mtd: rawnand: provide only single helper function for ECC conf

 .../devicetree/bindings/mtd/qcom_nandc.txt |   7 +-
 drivers/mtd/nand/raw/denali.c  |  30 +-
 drivers/mtd/nand/raw/nand_base.c   |  72 ++-
 drivers/mtd/nand/raw/qcom_nandc.c  | 491 ++---
 include/linux/mtd/rawnand.h|  10 +-
 5 files changed, 380 insertions(+), 230 deletions(-)

-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc.
is a member of Code Aurora Forum, hosted by The Linux Foundation



[PATCH v4 06/15] mtd: rawnand: qcom: wait for desc completion in all BAM channels

2018-06-20 Thread Abhishek Sahu
The BAM has 3 channels - tx, rx and command. command channel
is used for register read/writes, tx channel for data writes
and rx channel for data reads. Currently, the driver assumes the
transfer completion once it gets all the command descriptors
completed. Sometimes, there is race condition between data channel
(tx/rx) and command channel completion. In these cases,
the data present in buffer is not valid during small window
between command descriptor completion and data descriptor
completion.

This patch generates NAND transfer completion when both
(Data and Command) DMA channels have completed all its DMA
descriptors. It assigns completion callback in last
DMA descriptors of that channel and wait for completion.

Fixes: 8d6b6d7e135e ("mtd: nand: qcom: support for command descriptor 
formation")
Cc: sta...@vger.kernel.org
Acked-by: Miquel Raynal 
Signed-off-by: Abhishek Sahu 
---
* Changes from v3:
  1. NONE

* Changes from v2:
  1. Changed commit message and comments slightly
  2. Renamed wait_second_completion from first_chan_done and set
 it before submit desc
  3. Mark for stable tree

* Changes from v1:
  NONE

 drivers/mtd/nand/raw/qcom_nandc.c | 53 ++-
 1 file changed, 52 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c 
b/drivers/mtd/nand/raw/qcom_nandc.c
index 2375780..fc20149 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -213,6 +213,8 @@
 #define QPIC_PER_CW_CMD_SGL32
 #define QPIC_PER_CW_DATA_SGL   8
 
+#define QPIC_NAND_COMPLETION_TIMEOUT   msecs_to_jiffies(2000)
+
 /*
  * Flags used in DMA descriptor preparation helper functions
  * (i.e. read_reg_dma/write_reg_dma/read_data_dma/write_data_dma)
@@ -245,6 +247,11 @@
  * @tx_sgl_start - start index in data sgl for tx.
  * @rx_sgl_pos - current index in data sgl for rx.
  * @rx_sgl_start - start index in data sgl for rx.
+ * @wait_second_completion - wait for second DMA desc completion before making
+ *  the NAND transfer completion.
+ * @txn_done - completion for NAND transfer.
+ * @last_data_desc - last DMA desc in data channel (tx/rx).
+ * @last_cmd_desc - last DMA desc in command channel.
  */
 struct bam_transaction {
struct bam_cmd_element *bam_ce;
@@ -258,6 +265,10 @@ struct bam_transaction {
u32 tx_sgl_start;
u32 rx_sgl_pos;
u32 rx_sgl_start;
+   bool wait_second_completion;
+   struct completion txn_done;
+   struct dma_async_tx_descriptor *last_data_desc;
+   struct dma_async_tx_descriptor *last_cmd_desc;
 };
 
 /*
@@ -504,6 +515,8 @@ static void free_bam_transaction(struct 
qcom_nand_controller *nandc)
 
bam_txn->data_sgl = bam_txn_buf;
 
+   init_completion(_txn->txn_done);
+
return bam_txn;
 }
 
@@ -523,11 +536,33 @@ static void clear_bam_transaction(struct 
qcom_nand_controller *nandc)
bam_txn->tx_sgl_start = 0;
bam_txn->rx_sgl_pos = 0;
bam_txn->rx_sgl_start = 0;
+   bam_txn->last_data_desc = NULL;
+   bam_txn->wait_second_completion = false;
 
sg_init_table(bam_txn->cmd_sgl, nandc->max_cwperpage *
  QPIC_PER_CW_CMD_SGL);
sg_init_table(bam_txn->data_sgl, nandc->max_cwperpage *
  QPIC_PER_CW_DATA_SGL);
+
+   reinit_completion(_txn->txn_done);
+}
+
+/* Callback for DMA descriptor completion */
+static void qpic_bam_dma_done(void *data)
+{
+   struct bam_transaction *bam_txn = data;
+
+   /*
+* In case of data transfer with NAND, 2 callbacks will be generated.
+* One for command channel and another one for data channel.
+* If current transaction has data descriptors
+* (i.e. wait_second_completion is true), then set this to false
+* and wait for second DMA descriptor completion.
+*/
+   if (bam_txn->wait_second_completion)
+   bam_txn->wait_second_completion = false;
+   else
+   complete(_txn->txn_done);
 }
 
 static inline struct qcom_nand_host *to_qcom_nand_host(struct nand_chip *chip)
@@ -756,6 +791,12 @@ static int prepare_bam_async_desc(struct 
qcom_nand_controller *nandc,
 
desc->dma_desc = dma_desc;
 
+   /* update last data/command descriptor */
+   if (chan == nandc->cmd_chan)
+   bam_txn->last_cmd_desc = dma_desc;
+   else
+   bam_txn->last_data_desc = dma_desc;
+
list_add_tail(>node, >desc_list);
 
return 0;
@@ -1273,10 +1314,20 @@ static int submit_descs(struct qcom_nand_controller 
*nandc)
cookie = dmaengine_submit(desc->dma_desc);
 
if (nandc->props->is_bam) {
+   bam_txn->last_cmd_desc->callback = qpic_bam_dma_done;
+   bam_txn->last_cmd_desc->callback_param = bam_txn;
+   if (bam_txn-&g

[PATCH v4 10/15] mtd: rawnand: qcom: modify write_oob to remove read codeword part

2018-06-20 Thread Abhishek Sahu
QCOM NAND controller layout protects available OOB data bytes with
ECC also so when ecc->write_oob() is being called then it
can't update just OOB bytes. Currently, it first reads the last
codeword which includes old OOB bytes. Then it updates the old OOB
bytes with new ones and then again writes the codeword back.
The reading codeword is unnecessary since user is responsible to
have these bytes cleared to 0xFF.

This patch removes the read part and updates the OOB bytes with
data area padded with OxFF.

Acked-by: Miquel Raynal 
Signed-off-by: Abhishek Sahu 
---
* Changes from v3:
  NONE

* Changes from v2:

  1. Changed commit message and comments slightly
  2. Changed host->use_ecc assignment place

* Changes from v1:
  NEW CHANGE

 drivers/mtd/nand/raw/qcom_nandc.c | 16 
 1 file changed, 4 insertions(+), 12 deletions(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c 
b/drivers/mtd/nand/raw/qcom_nandc.c
index 285b2ad3..28361b5 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -2064,11 +2064,9 @@ static int qcom_nandc_write_page_raw(struct mtd_info 
*mtd,
 /*
  * implements ecc->write_oob()
  *
- * the NAND controller cannot write only data or only oob within a codeword,
- * since ecc is calculated for the combined codeword. we first copy the
- * entire contents for the last codeword(data + oob), replace the old oob
- * with the new one in chip->oob_poi, and then write the entire codeword.
- * this read-copy-write operation results in a slight performance loss.
+ * the NAND controller cannot write only data or only OOB within a codeword
+ * since ECC is calculated for the combined codeword. So update the OOB from
+ * chip->oob_poi, and pad the data area with OxFF before writing.
  */
 static int qcom_nandc_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
int page)
@@ -2081,19 +2079,13 @@ static int qcom_nandc_write_oob(struct mtd_info *mtd, 
struct nand_chip *chip,
int ret;
 
host->use_ecc = true;
-
-   clear_bam_transaction(nandc);
-   ret = copy_last_cw(host, page);
-   if (ret)
-   return ret;
-
-   clear_read_regs(nandc);
clear_bam_transaction(nandc);
 
/* calculate the data and oob size for the last codeword/step */
data_size = ecc->size - ((ecc->steps - 1) << 2);
oob_size = mtd->oobavail;
 
+   memset(nandc->data_buffer, 0xff, host->cw_data);
/* override new oob content to last codeword */
mtd_ooblayout_get_databytes(mtd, nandc->data_buffer + data_size, oob,
0, mtd->oobavail);
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc.
is a member of Code Aurora Forum, hosted by The Linux Foundation



[PATCH v4 06/15] mtd: rawnand: qcom: wait for desc completion in all BAM channels

2018-06-20 Thread Abhishek Sahu
The BAM has 3 channels - tx, rx and command. command channel
is used for register read/writes, tx channel for data writes
and rx channel for data reads. Currently, the driver assumes the
transfer completion once it gets all the command descriptors
completed. Sometimes, there is race condition between data channel
(tx/rx) and command channel completion. In these cases,
the data present in buffer is not valid during small window
between command descriptor completion and data descriptor
completion.

This patch generates NAND transfer completion when both
(Data and Command) DMA channels have completed all its DMA
descriptors. It assigns completion callback in last
DMA descriptors of that channel and wait for completion.

Fixes: 8d6b6d7e135e ("mtd: nand: qcom: support for command descriptor 
formation")
Cc: sta...@vger.kernel.org
Acked-by: Miquel Raynal 
Signed-off-by: Abhishek Sahu 
---
* Changes from v3:
  1. NONE

* Changes from v2:
  1. Changed commit message and comments slightly
  2. Renamed wait_second_completion from first_chan_done and set
 it before submit desc
  3. Mark for stable tree

* Changes from v1:
  NONE

 drivers/mtd/nand/raw/qcom_nandc.c | 53 ++-
 1 file changed, 52 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c 
b/drivers/mtd/nand/raw/qcom_nandc.c
index 2375780..fc20149 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -213,6 +213,8 @@
 #define QPIC_PER_CW_CMD_SGL32
 #define QPIC_PER_CW_DATA_SGL   8
 
+#define QPIC_NAND_COMPLETION_TIMEOUT   msecs_to_jiffies(2000)
+
 /*
  * Flags used in DMA descriptor preparation helper functions
  * (i.e. read_reg_dma/write_reg_dma/read_data_dma/write_data_dma)
@@ -245,6 +247,11 @@
  * @tx_sgl_start - start index in data sgl for tx.
  * @rx_sgl_pos - current index in data sgl for rx.
  * @rx_sgl_start - start index in data sgl for rx.
+ * @wait_second_completion - wait for second DMA desc completion before making
+ *  the NAND transfer completion.
+ * @txn_done - completion for NAND transfer.
+ * @last_data_desc - last DMA desc in data channel (tx/rx).
+ * @last_cmd_desc - last DMA desc in command channel.
  */
 struct bam_transaction {
struct bam_cmd_element *bam_ce;
@@ -258,6 +265,10 @@ struct bam_transaction {
u32 tx_sgl_start;
u32 rx_sgl_pos;
u32 rx_sgl_start;
+   bool wait_second_completion;
+   struct completion txn_done;
+   struct dma_async_tx_descriptor *last_data_desc;
+   struct dma_async_tx_descriptor *last_cmd_desc;
 };
 
 /*
@@ -504,6 +515,8 @@ static void free_bam_transaction(struct 
qcom_nand_controller *nandc)
 
bam_txn->data_sgl = bam_txn_buf;
 
+   init_completion(_txn->txn_done);
+
return bam_txn;
 }
 
@@ -523,11 +536,33 @@ static void clear_bam_transaction(struct 
qcom_nand_controller *nandc)
bam_txn->tx_sgl_start = 0;
bam_txn->rx_sgl_pos = 0;
bam_txn->rx_sgl_start = 0;
+   bam_txn->last_data_desc = NULL;
+   bam_txn->wait_second_completion = false;
 
sg_init_table(bam_txn->cmd_sgl, nandc->max_cwperpage *
  QPIC_PER_CW_CMD_SGL);
sg_init_table(bam_txn->data_sgl, nandc->max_cwperpage *
  QPIC_PER_CW_DATA_SGL);
+
+   reinit_completion(_txn->txn_done);
+}
+
+/* Callback for DMA descriptor completion */
+static void qpic_bam_dma_done(void *data)
+{
+   struct bam_transaction *bam_txn = data;
+
+   /*
+* In case of data transfer with NAND, 2 callbacks will be generated.
+* One for command channel and another one for data channel.
+* If current transaction has data descriptors
+* (i.e. wait_second_completion is true), then set this to false
+* and wait for second DMA descriptor completion.
+*/
+   if (bam_txn->wait_second_completion)
+   bam_txn->wait_second_completion = false;
+   else
+   complete(_txn->txn_done);
 }
 
 static inline struct qcom_nand_host *to_qcom_nand_host(struct nand_chip *chip)
@@ -756,6 +791,12 @@ static int prepare_bam_async_desc(struct 
qcom_nand_controller *nandc,
 
desc->dma_desc = dma_desc;
 
+   /* update last data/command descriptor */
+   if (chan == nandc->cmd_chan)
+   bam_txn->last_cmd_desc = dma_desc;
+   else
+   bam_txn->last_data_desc = dma_desc;
+
list_add_tail(>node, >desc_list);
 
return 0;
@@ -1273,10 +1314,20 @@ static int submit_descs(struct qcom_nand_controller 
*nandc)
cookie = dmaengine_submit(desc->dma_desc);
 
if (nandc->props->is_bam) {
+   bam_txn->last_cmd_desc->callback = qpic_bam_dma_done;
+   bam_txn->last_cmd_desc->callback_param = bam_txn;
+   if (bam_txn-&g

[PATCH v4 10/15] mtd: rawnand: qcom: modify write_oob to remove read codeword part

2018-06-20 Thread Abhishek Sahu
QCOM NAND controller layout protects available OOB data bytes with
ECC also so when ecc->write_oob() is being called then it
can't update just OOB bytes. Currently, it first reads the last
codeword which includes old OOB bytes. Then it updates the old OOB
bytes with new ones and then again writes the codeword back.
The reading codeword is unnecessary since user is responsible to
have these bytes cleared to 0xFF.

This patch removes the read part and updates the OOB bytes with
data area padded with OxFF.

Acked-by: Miquel Raynal 
Signed-off-by: Abhishek Sahu 
---
* Changes from v3:
  NONE

* Changes from v2:

  1. Changed commit message and comments slightly
  2. Changed host->use_ecc assignment place

* Changes from v1:
  NEW CHANGE

 drivers/mtd/nand/raw/qcom_nandc.c | 16 
 1 file changed, 4 insertions(+), 12 deletions(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c 
b/drivers/mtd/nand/raw/qcom_nandc.c
index 285b2ad3..28361b5 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -2064,11 +2064,9 @@ static int qcom_nandc_write_page_raw(struct mtd_info 
*mtd,
 /*
  * implements ecc->write_oob()
  *
- * the NAND controller cannot write only data or only oob within a codeword,
- * since ecc is calculated for the combined codeword. we first copy the
- * entire contents for the last codeword(data + oob), replace the old oob
- * with the new one in chip->oob_poi, and then write the entire codeword.
- * this read-copy-write operation results in a slight performance loss.
+ * the NAND controller cannot write only data or only OOB within a codeword
+ * since ECC is calculated for the combined codeword. So update the OOB from
+ * chip->oob_poi, and pad the data area with OxFF before writing.
  */
 static int qcom_nandc_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
int page)
@@ -2081,19 +2079,13 @@ static int qcom_nandc_write_oob(struct mtd_info *mtd, 
struct nand_chip *chip,
int ret;
 
host->use_ecc = true;
-
-   clear_bam_transaction(nandc);
-   ret = copy_last_cw(host, page);
-   if (ret)
-   return ret;
-
-   clear_read_regs(nandc);
clear_bam_transaction(nandc);
 
/* calculate the data and oob size for the last codeword/step */
data_size = ecc->size - ((ecc->steps - 1) << 2);
oob_size = mtd->oobavail;
 
+   memset(nandc->data_buffer, 0xff, host->cw_data);
/* override new oob content to last codeword */
mtd_ooblayout_get_databytes(mtd, nandc->data_buffer + data_size, oob,
0, mtd->oobavail);
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc.
is a member of Code Aurora Forum, hosted by The Linux Foundation



[PATCH v4 13/15] mtd: rawnand: qcom: code reorganization for raw read

2018-06-20 Thread Abhishek Sahu
Make separate function to perform raw read for one codeword and
call this function multiple times for each codeword in case of
raw page read. This separate function will help in subsequent
patches related with erased codeword bitflip detection.

It will decrease throughput for raw page read. Raw page read
is used for debug purpose so it won't affect normal flash
operations.

Signed-off-by: Abhishek Sahu 
---
* Changes from v3:
  1. Major code changes for making separate function for raw_read
  2. Changed commit message

* Changes from v2:
  NONE

* Changes from v1:
 1. Included more detail in function comment

 drivers/mtd/nand/raw/qcom_nandc.c | 146 --
 1 file changed, 78 insertions(+), 68 deletions(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c 
b/drivers/mtd/nand/raw/qcom_nandc.c
index 5999c39..160acdf 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -1587,6 +1587,74 @@ static int check_flash_errors(struct qcom_nand_host 
*host, int cw_cnt)
return 0;
 }
 
+/* performs raw read for one codeword */
+static int
+qcom_nandc_read_cw_raw(struct mtd_info *mtd, struct nand_chip *chip,
+  u8 *data_buf, u8 *oob_buf, int page, int cw)
+{
+   struct qcom_nand_host *host = to_qcom_nand_host(chip);
+   struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+   struct nand_ecc_ctrl *ecc = >ecc;
+   int data_size1, data_size2, oob_size1, oob_size2;
+   int ret, reg_off = FLASH_BUF_ACC, read_loc = 0;
+
+   nand_read_page_op(chip, page, 0, NULL, 0);
+   host->use_ecc = false;
+
+   clear_bam_transaction(nandc);
+   set_address(host, host->cw_size * cw, page);
+   update_rw_regs(host, 1, true);
+   config_nand_page_read(nandc);
+
+   data_size1 = mtd->writesize - host->cw_size * (ecc->steps - 1);
+   oob_size1 = host->bbm_size;
+
+   if (cw == (ecc->steps - 1)) {
+   data_size2 = ecc->size - data_size1 -
+((ecc->steps - 1) * 4);
+   oob_size2 = (ecc->steps * 4) + host->ecc_bytes_hw +
+   host->spare_bytes;
+   } else {
+   data_size2 = host->cw_data - data_size1;
+   oob_size2 = host->ecc_bytes_hw + host->spare_bytes;
+   }
+
+   if (nandc->props->is_bam) {
+   nandc_set_read_loc(nandc, 0, read_loc, data_size1, 0);
+   read_loc += data_size1;
+
+   nandc_set_read_loc(nandc, 1, read_loc, oob_size1, 0);
+   read_loc += oob_size1;
+
+   nandc_set_read_loc(nandc, 2, read_loc, data_size2, 0);
+   read_loc += data_size2;
+
+   nandc_set_read_loc(nandc, 3, read_loc, oob_size2, 1);
+   }
+
+   config_nand_cw_read(nandc, false);
+
+   read_data_dma(nandc, reg_off, data_buf, data_size1, 0);
+   reg_off += data_size1;
+
+   read_data_dma(nandc, reg_off, oob_buf, oob_size1, 0);
+   reg_off += oob_size1;
+
+   read_data_dma(nandc, reg_off, data_buf + data_size1, data_size2, 0);
+   reg_off += data_size2;
+
+   read_data_dma(nandc, reg_off, oob_buf + oob_size1, oob_size2, 0);
+
+   ret = submit_descs(nandc);
+   free_descs(nandc);
+   if (ret) {
+   dev_err(nandc->dev, "failure to read raw cw %d\n", cw);
+   return ret;
+   }
+
+   return check_flash_errors(host, 1);
+}
+
 /*
  * reads back status registers set by the controller to notify page read
  * errors. this is equivalent to what 'ecc->correct()' would do.
@@ -1851,79 +1919,21 @@ static int qcom_nandc_read_page_raw(struct mtd_info 
*mtd,
int oob_required, int page)
 {
struct qcom_nand_host *host = to_qcom_nand_host(chip);
-   struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-   u8 *data_buf, *oob_buf;
struct nand_ecc_ctrl *ecc = >ecc;
-   int i, ret;
-   int read_loc;
+   int cw, ret;
+   u8 *data_buf = buf, *oob_buf = chip->oob_poi;
 
-   nand_read_page_op(chip, page, 0, NULL, 0);
-   data_buf = buf;
-   oob_buf = chip->oob_poi;
+   for (cw = 0; cw < ecc->steps; cw++) {
+   ret = qcom_nandc_read_cw_raw(mtd, chip, data_buf, oob_buf,
+page, cw);
+   if (ret)
+   return ret;
 
-   host->use_ecc = false;
-
-   clear_bam_transaction(nandc);
-   update_rw_regs(host, ecc->steps, true);
-   config_nand_page_read(nandc);
-
-   for (i = 0; i < ecc->steps; i++) {
-   int data_size1, data_size2, oob_size1, oob_size2;
-   int reg_off = FLASH_BUF_ACC;
-
-   data_size1 = mtd->writesize - host->cw_size * (ecc->steps - 1);
-   oob_size1 = host->bbm_siz

[PATCH v4 13/15] mtd: rawnand: qcom: code reorganization for raw read

2018-06-20 Thread Abhishek Sahu
Make separate function to perform raw read for one codeword and
call this function multiple times for each codeword in case of
raw page read. This separate function will help in subsequent
patches related with erased codeword bitflip detection.

It will decrease throughput for raw page read. Raw page read
is used for debug purpose so it won't affect normal flash
operations.

Signed-off-by: Abhishek Sahu 
---
* Changes from v3:
  1. Major code changes for making separate function for raw_read
  2. Changed commit message

* Changes from v2:
  NONE

* Changes from v1:
 1. Included more detail in function comment

 drivers/mtd/nand/raw/qcom_nandc.c | 146 --
 1 file changed, 78 insertions(+), 68 deletions(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c 
b/drivers/mtd/nand/raw/qcom_nandc.c
index 5999c39..160acdf 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -1587,6 +1587,74 @@ static int check_flash_errors(struct qcom_nand_host 
*host, int cw_cnt)
return 0;
 }
 
+/* performs raw read for one codeword */
+static int
+qcom_nandc_read_cw_raw(struct mtd_info *mtd, struct nand_chip *chip,
+  u8 *data_buf, u8 *oob_buf, int page, int cw)
+{
+   struct qcom_nand_host *host = to_qcom_nand_host(chip);
+   struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+   struct nand_ecc_ctrl *ecc = >ecc;
+   int data_size1, data_size2, oob_size1, oob_size2;
+   int ret, reg_off = FLASH_BUF_ACC, read_loc = 0;
+
+   nand_read_page_op(chip, page, 0, NULL, 0);
+   host->use_ecc = false;
+
+   clear_bam_transaction(nandc);
+   set_address(host, host->cw_size * cw, page);
+   update_rw_regs(host, 1, true);
+   config_nand_page_read(nandc);
+
+   data_size1 = mtd->writesize - host->cw_size * (ecc->steps - 1);
+   oob_size1 = host->bbm_size;
+
+   if (cw == (ecc->steps - 1)) {
+   data_size2 = ecc->size - data_size1 -
+((ecc->steps - 1) * 4);
+   oob_size2 = (ecc->steps * 4) + host->ecc_bytes_hw +
+   host->spare_bytes;
+   } else {
+   data_size2 = host->cw_data - data_size1;
+   oob_size2 = host->ecc_bytes_hw + host->spare_bytes;
+   }
+
+   if (nandc->props->is_bam) {
+   nandc_set_read_loc(nandc, 0, read_loc, data_size1, 0);
+   read_loc += data_size1;
+
+   nandc_set_read_loc(nandc, 1, read_loc, oob_size1, 0);
+   read_loc += oob_size1;
+
+   nandc_set_read_loc(nandc, 2, read_loc, data_size2, 0);
+   read_loc += data_size2;
+
+   nandc_set_read_loc(nandc, 3, read_loc, oob_size2, 1);
+   }
+
+   config_nand_cw_read(nandc, false);
+
+   read_data_dma(nandc, reg_off, data_buf, data_size1, 0);
+   reg_off += data_size1;
+
+   read_data_dma(nandc, reg_off, oob_buf, oob_size1, 0);
+   reg_off += oob_size1;
+
+   read_data_dma(nandc, reg_off, data_buf + data_size1, data_size2, 0);
+   reg_off += data_size2;
+
+   read_data_dma(nandc, reg_off, oob_buf + oob_size1, oob_size2, 0);
+
+   ret = submit_descs(nandc);
+   free_descs(nandc);
+   if (ret) {
+   dev_err(nandc->dev, "failure to read raw cw %d\n", cw);
+   return ret;
+   }
+
+   return check_flash_errors(host, 1);
+}
+
 /*
  * reads back status registers set by the controller to notify page read
  * errors. this is equivalent to what 'ecc->correct()' would do.
@@ -1851,79 +1919,21 @@ static int qcom_nandc_read_page_raw(struct mtd_info 
*mtd,
int oob_required, int page)
 {
struct qcom_nand_host *host = to_qcom_nand_host(chip);
-   struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-   u8 *data_buf, *oob_buf;
struct nand_ecc_ctrl *ecc = >ecc;
-   int i, ret;
-   int read_loc;
+   int cw, ret;
+   u8 *data_buf = buf, *oob_buf = chip->oob_poi;
 
-   nand_read_page_op(chip, page, 0, NULL, 0);
-   data_buf = buf;
-   oob_buf = chip->oob_poi;
+   for (cw = 0; cw < ecc->steps; cw++) {
+   ret = qcom_nandc_read_cw_raw(mtd, chip, data_buf, oob_buf,
+page, cw);
+   if (ret)
+   return ret;
 
-   host->use_ecc = false;
-
-   clear_bam_transaction(nandc);
-   update_rw_regs(host, ecc->steps, true);
-   config_nand_page_read(nandc);
-
-   for (i = 0; i < ecc->steps; i++) {
-   int data_size1, data_size2, oob_size1, oob_size2;
-   int reg_off = FLASH_BUF_ACC;
-
-   data_size1 = mtd->writesize - host->cw_size * (ecc->steps - 1);
-   oob_size1 = host->bbm_siz

[PATCH v4 05/15] mtd: rawnand: qcom: use the ecc strength from device parameter

2018-06-20 Thread Abhishek Sahu
Currently the driver uses the ECC strength specified in DT.
The QPIC/EBI2 NAND supports 4 or 8-bit ECC correction. The same
kind of board can have different NAND parts so use the ECC
strength from device parameters if it is not specified in DT.

Acked-by: Miquel Raynal 
Signed-off-by: Abhishek Sahu 
---
* Changes from v3:
  1. Added parenthesis around (cwperpage * 4)

* Changes from v2:
  1. s/<< 2/* 4/
  2. Updated the cwperpage location
  3. The block handling the ecc-step-size property has been
 removed in a previous patch

* Changes from v1:

  1. Removed the custom logic and used the helper fuction.

 drivers/mtd/nand/raw/qcom_nandc.c | 29 +
 1 file changed, 21 insertions(+), 8 deletions(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c 
b/drivers/mtd/nand/raw/qcom_nandc.c
index bf80a61..2375780 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -2315,19 +2315,39 @@ static int qcom_nand_ooblayout_free(struct mtd_info 
*mtd, int section,
.free = qcom_nand_ooblayout_free,
 };
 
+static int
+qcom_nandc_calc_ecc_bytes(int step_size, int strength)
+{
+   return strength == 4 ? 12 : 16;
+}
+NAND_ECC_CAPS_SINGLE(qcom_nandc_ecc_caps, qcom_nandc_calc_ecc_bytes,
+NANDC_STEP_SIZE, 4, 8);
+
 static int qcom_nand_host_setup(struct qcom_nand_host *host)
 {
struct nand_chip *chip = >chip;
struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_ecc_ctrl *ecc = >ecc;
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-   int cwperpage, bad_block_byte;
+   int cwperpage, bad_block_byte, ret;
bool wide_bus;
int ecc_mode = 1;
 
/* controller only supports 512 bytes data steps */
ecc->size = NANDC_STEP_SIZE;
wide_bus = chip->options & NAND_BUSWIDTH_16 ? true : false;
+   cwperpage = mtd->writesize / NANDC_STEP_SIZE;
+
+   /*
+* Each CW has 4 available OOB bytes which will be protected with ECC
+* so remaining bytes can be used for ECC.
+*/
+   ret = nand_ecc_choose_conf(chip, _nandc_ecc_caps,
+  mtd->oobsize - (cwperpage * 4));
+   if (ret) {
+   dev_err(nandc->dev, "No valid ECC settings possible\n");
+   return ret;
+   }
 
if (ecc->strength >= 8) {
/* 8 bit ECC defaults to BCH ECC on all platforms */
@@ -2396,7 +2416,6 @@ static int qcom_nand_host_setup(struct qcom_nand_host 
*host)
 
mtd_set_ooblayout(mtd, _nand_ooblayout_ops);
 
-   cwperpage = mtd->writesize / ecc->size;
nandc->max_cwperpage = max_t(unsigned int, nandc->max_cwperpage,
 cwperpage);
 
@@ -2412,12 +2431,6 @@ static int qcom_nand_host_setup(struct qcom_nand_host 
*host)
 * for 8 bit ECC
 */
host->cw_size = host->cw_data + ecc->bytes;
-
-   if (ecc->bytes * (mtd->writesize / ecc->size) > mtd->oobsize) {
-   dev_err(nandc->dev, "ecc data doesn't fit in OOB area\n");
-   return -EINVAL;
-   }
-
bad_block_byte = mtd->writesize - host->cw_size * (cwperpage - 1) + 1;
 
host->cfg0 = (cwperpage - 1) << CW_PER_PAGE
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc.
is a member of Code Aurora Forum, hosted by The Linux Foundation



[PATCH v4 05/15] mtd: rawnand: qcom: use the ecc strength from device parameter

2018-06-20 Thread Abhishek Sahu
Currently the driver uses the ECC strength specified in DT.
The QPIC/EBI2 NAND supports 4 or 8-bit ECC correction. The same
kind of board can have different NAND parts so use the ECC
strength from device parameters if it is not specified in DT.

Acked-by: Miquel Raynal 
Signed-off-by: Abhishek Sahu 
---
* Changes from v3:
  1. Added parenthesis around (cwperpage * 4)

* Changes from v2:
  1. s/<< 2/* 4/
  2. Updated the cwperpage location
  3. The block handling the ecc-step-size property has been
 removed in a previous patch

* Changes from v1:

  1. Removed the custom logic and used the helper fuction.

 drivers/mtd/nand/raw/qcom_nandc.c | 29 +
 1 file changed, 21 insertions(+), 8 deletions(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c 
b/drivers/mtd/nand/raw/qcom_nandc.c
index bf80a61..2375780 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -2315,19 +2315,39 @@ static int qcom_nand_ooblayout_free(struct mtd_info 
*mtd, int section,
.free = qcom_nand_ooblayout_free,
 };
 
+static int
+qcom_nandc_calc_ecc_bytes(int step_size, int strength)
+{
+   return strength == 4 ? 12 : 16;
+}
+NAND_ECC_CAPS_SINGLE(qcom_nandc_ecc_caps, qcom_nandc_calc_ecc_bytes,
+NANDC_STEP_SIZE, 4, 8);
+
 static int qcom_nand_host_setup(struct qcom_nand_host *host)
 {
struct nand_chip *chip = >chip;
struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_ecc_ctrl *ecc = >ecc;
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-   int cwperpage, bad_block_byte;
+   int cwperpage, bad_block_byte, ret;
bool wide_bus;
int ecc_mode = 1;
 
/* controller only supports 512 bytes data steps */
ecc->size = NANDC_STEP_SIZE;
wide_bus = chip->options & NAND_BUSWIDTH_16 ? true : false;
+   cwperpage = mtd->writesize / NANDC_STEP_SIZE;
+
+   /*
+* Each CW has 4 available OOB bytes which will be protected with ECC
+* so remaining bytes can be used for ECC.
+*/
+   ret = nand_ecc_choose_conf(chip, _nandc_ecc_caps,
+  mtd->oobsize - (cwperpage * 4));
+   if (ret) {
+   dev_err(nandc->dev, "No valid ECC settings possible\n");
+   return ret;
+   }
 
if (ecc->strength >= 8) {
/* 8 bit ECC defaults to BCH ECC on all platforms */
@@ -2396,7 +2416,6 @@ static int qcom_nand_host_setup(struct qcom_nand_host 
*host)
 
mtd_set_ooblayout(mtd, _nand_ooblayout_ops);
 
-   cwperpage = mtd->writesize / ecc->size;
nandc->max_cwperpage = max_t(unsigned int, nandc->max_cwperpage,
 cwperpage);
 
@@ -2412,12 +2431,6 @@ static int qcom_nand_host_setup(struct qcom_nand_host 
*host)
 * for 8 bit ECC
 */
host->cw_size = host->cw_data + ecc->bytes;
-
-   if (ecc->bytes * (mtd->writesize / ecc->size) > mtd->oobsize) {
-   dev_err(nandc->dev, "ecc data doesn't fit in OOB area\n");
-   return -EINVAL;
-   }
-
bad_block_byte = mtd->writesize - host->cw_size * (cwperpage - 1) + 1;
 
host->cfg0 = (cwperpage - 1) << CW_PER_PAGE
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc.
is a member of Code Aurora Forum, hosted by The Linux Foundation



[PATCH v4 03/15] dt-bindings: qcom_nandc: update for ECC strength and step size

2018-06-20 Thread Abhishek Sahu
1. If nand-ecc-strength specified in DT, then controller will use
   this ECC strength otherwise ECC strength will be calculated
   according to chip requirement and available OOB size.

2. QCOM NAND controller supports only one step size (512 bytes) but
   nand-ecc-step-size is required property in DT. This DT property
   can be removed and ecc step size can be assigned in driver with
   512 bytes value.

Signed-off-by: Abhishek Sahu 
---

* Changes from v3:

1. Clubbed following 2 patches into one
   https://patchwork.ozlabs.org/patch/920465/
   https://patchwork.ozlabs.org/patch/920467/

* Changes from v2:
  NONE

* Changes from v1:
  NEW PATCH

 Documentation/devicetree/bindings/mtd/qcom_nandc.txt | 7 +++
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/Documentation/devicetree/bindings/mtd/qcom_nandc.txt 
b/Documentation/devicetree/bindings/mtd/qcom_nandc.txt
index 73d336be..1123cc6 100644
--- a/Documentation/devicetree/bindings/mtd/qcom_nandc.txt
+++ b/Documentation/devicetree/bindings/mtd/qcom_nandc.txt
@@ -45,11 +45,12 @@ Required properties:
number (e.g., 0, 1, 2, etc.)
 - #address-cells:  see partition.txt
 - #size-cells: see partition.txt
-- nand-ecc-strength:   see nand.txt
-- nand-ecc-step-size:  must be 512. see nand.txt for more details.
 
 Optional properties:
 - nand-bus-width:  see nand.txt
+- nand-ecc-strength:   see nand.txt. If not specified, then ECC strength will
+   be used according to chip requirement and available
+   OOB size.
 
 Each nandcs device node may optionally contain a 'partitions' sub-node, which
 further contains sub-nodes describing the flash partition mapping. See
@@ -77,7 +78,6 @@ nand-controller@1ac0 {
reg = <0>;
 
nand-ecc-strength = <4>;
-   nand-ecc-step-size = <512>;
nand-bus-width = <8>;
 
partitions {
@@ -117,7 +117,6 @@ nand-controller@79b {
nand@0 {
reg = <0>;
nand-ecc-strength = <4>;
-   nand-ecc-step-size = <512>;
nand-bus-width = <8>;
 
partitions {
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc.
is a member of Code Aurora Forum, hosted by The Linux Foundation



[PATCH v4 03/15] dt-bindings: qcom_nandc: update for ECC strength and step size

2018-06-20 Thread Abhishek Sahu
1. If nand-ecc-strength specified in DT, then controller will use
   this ECC strength otherwise ECC strength will be calculated
   according to chip requirement and available OOB size.

2. QCOM NAND controller supports only one step size (512 bytes) but
   nand-ecc-step-size is required property in DT. This DT property
   can be removed and ecc step size can be assigned in driver with
   512 bytes value.

Signed-off-by: Abhishek Sahu 
---

* Changes from v3:

1. Clubbed following 2 patches into one
   https://patchwork.ozlabs.org/patch/920465/
   https://patchwork.ozlabs.org/patch/920467/

* Changes from v2:
  NONE

* Changes from v1:
  NEW PATCH

 Documentation/devicetree/bindings/mtd/qcom_nandc.txt | 7 +++
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/Documentation/devicetree/bindings/mtd/qcom_nandc.txt 
b/Documentation/devicetree/bindings/mtd/qcom_nandc.txt
index 73d336be..1123cc6 100644
--- a/Documentation/devicetree/bindings/mtd/qcom_nandc.txt
+++ b/Documentation/devicetree/bindings/mtd/qcom_nandc.txt
@@ -45,11 +45,12 @@ Required properties:
number (e.g., 0, 1, 2, etc.)
 - #address-cells:  see partition.txt
 - #size-cells: see partition.txt
-- nand-ecc-strength:   see nand.txt
-- nand-ecc-step-size:  must be 512. see nand.txt for more details.
 
 Optional properties:
 - nand-bus-width:  see nand.txt
+- nand-ecc-strength:   see nand.txt. If not specified, then ECC strength will
+   be used according to chip requirement and available
+   OOB size.
 
 Each nandcs device node may optionally contain a 'partitions' sub-node, which
 further contains sub-nodes describing the flash partition mapping. See
@@ -77,7 +78,6 @@ nand-controller@1ac0 {
reg = <0>;
 
nand-ecc-strength = <4>;
-   nand-ecc-step-size = <512>;
nand-bus-width = <8>;
 
partitions {
@@ -117,7 +117,6 @@ nand-controller@79b {
nand@0 {
reg = <0>;
nand-ecc-strength = <4>;
-   nand-ecc-step-size = <512>;
nand-bus-width = <8>;
 
partitions {
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc.
is a member of Code Aurora Forum, hosted by The Linux Foundation



[PATCH v4 15/15] mtd: rawnand: provide only single helper function for ECC conf

2018-06-20 Thread Abhishek Sahu
Function nand_ecc_choose_conf() will be help for all the cases, so
other helper functions can be made static.

nand_check_ecc_caps(): Invoke nand_ecc_choose_conf() with
   both chip->ecc.size and chip->ecc.strength
   value set.

nand_maximize_ecc(): Invoke nand_ecc_choose_conf() with
 NAND_ECC_MAXIMIZE flag.

nand_match_ecc_req(): Invoke nand_ecc_choose_conf() with either
  chip->ecc.size or chip->ecc.strength value
  set and without NAND_ECC_MAXIMIZE flag.

CC: Masahiro Yamada 
Signed-off-by: Abhishek Sahu 
---
Changes from v3:

NEW PATCH

 drivers/mtd/nand/raw/nand_base.c | 39 +++
 include/linux/mtd/rawnand.h  |  9 -
 2 files changed, 15 insertions(+), 33 deletions(-)

diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index c64e3fc..f620236 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -6077,24 +6077,17 @@ static int nand_set_ecc_soft_ops(struct mtd_info *mtd)
  * by the controller and the calculated ECC bytes fit within the chip's OOB.
  * On success, the calculated ECC bytes is set.
  */
-int nand_check_ecc_caps(struct nand_chip *chip,
-   const struct nand_ecc_caps *caps, int oobavail)
+static int
+nand_check_ecc_caps(struct nand_chip *chip,
+   const struct nand_ecc_caps *caps, int oobavail)
 {
struct mtd_info *mtd = nand_to_mtd(chip);
const struct nand_ecc_step_info *stepinfo;
int preset_step = chip->ecc.size;
int preset_strength = chip->ecc.strength;
-   int nsteps, ecc_bytes;
+   int ecc_bytes, nsteps = mtd->writesize / preset_step;
int i, j;
 
-   if (WARN_ON(oobavail < 0))
-   return -EINVAL;
-
-   if (!preset_step || !preset_strength)
-   return -ENODATA;
-
-   nsteps = mtd->writesize / preset_step;
-
for (i = 0; i < caps->nstepinfos; i++) {
stepinfo = >stepinfos[i];
 
@@ -6127,7 +6120,6 @@ int nand_check_ecc_caps(struct nand_chip *chip,
 
return -ENOTSUPP;
 }
-EXPORT_SYMBOL_GPL(nand_check_ecc_caps);
 
 /**
  * nand_match_ecc_req - meet the chip's requirement with least ECC bytes
@@ -6139,8 +6131,9 @@ int nand_check_ecc_caps(struct nand_chip *chip,
  * number of ECC bytes (i.e. with the largest number of OOB-free bytes).
  * On success, the chosen ECC settings are set.
  */
-int nand_match_ecc_req(struct nand_chip *chip,
-  const struct nand_ecc_caps *caps, int oobavail)
+static int
+nand_match_ecc_req(struct nand_chip *chip,
+  const struct nand_ecc_caps *caps, int oobavail)
 {
struct mtd_info *mtd = nand_to_mtd(chip);
const struct nand_ecc_step_info *stepinfo;
@@ -6151,9 +6144,6 @@ int nand_match_ecc_req(struct nand_chip *chip,
int best_ecc_bytes_total = INT_MAX;
int i, j;
 
-   if (WARN_ON(oobavail < 0))
-   return -EINVAL;
-
/* No information provided by the NAND chip */
if (!req_step || !req_strength)
return -ENOTSUPP;
@@ -6212,7 +6202,6 @@ int nand_match_ecc_req(struct nand_chip *chip,
 
return 0;
 }
-EXPORT_SYMBOL_GPL(nand_match_ecc_req);
 
 /**
  * nand_maximize_ecc - choose the max ECC strength available
@@ -6223,8 +6212,9 @@ int nand_match_ecc_req(struct nand_chip *chip,
  * Choose the max ECC strength that is supported on the controller, and can fit
  * within the chip's OOB.  On success, the chosen ECC settings are set.
  */
-int nand_maximize_ecc(struct nand_chip *chip,
- const struct nand_ecc_caps *caps, int oobavail)
+static int
+nand_maximize_ecc(struct nand_chip *chip,
+ const struct nand_ecc_caps *caps, int oobavail)
 {
struct mtd_info *mtd = nand_to_mtd(chip);
const struct nand_ecc_step_info *stepinfo;
@@ -6234,9 +6224,6 @@ int nand_maximize_ecc(struct nand_chip *chip,
int best_strength, best_ecc_bytes;
int i, j;
 
-   if (WARN_ON(oobavail < 0))
-   return -EINVAL;
-
for (i = 0; i < caps->nstepinfos; i++) {
stepinfo = >stepinfos[i];
step_size = stepinfo->stepsize;
@@ -6285,7 +6272,6 @@ int nand_maximize_ecc(struct nand_chip *chip,
 
return 0;
 }
-EXPORT_SYMBOL_GPL(nand_maximize_ecc);
 
 /**
  * nand_ecc_choose_conf - Set the ECC strength and ECC step size
@@ -6307,6 +6293,11 @@ int nand_maximize_ecc(struct nand_chip *chip,
 int nand_ecc_choose_conf(struct nand_chip *chip,
 const struct nand_ecc_caps *caps, int oobavail)
 {
+   struct mtd_info *mtd = nand_to_mtd(chip);
+
+   if (WARN_ON(oobavail < 0 || oobavail > mtd->oobsize))
+   return -EINVAL;
+
if (chip->ecc.size && chip->ecc.strength)
return nand_check_ecc_cap

[PATCH v4 15/15] mtd: rawnand: provide only single helper function for ECC conf

2018-06-20 Thread Abhishek Sahu
Function nand_ecc_choose_conf() will be help for all the cases, so
other helper functions can be made static.

nand_check_ecc_caps(): Invoke nand_ecc_choose_conf() with
   both chip->ecc.size and chip->ecc.strength
   value set.

nand_maximize_ecc(): Invoke nand_ecc_choose_conf() with
 NAND_ECC_MAXIMIZE flag.

nand_match_ecc_req(): Invoke nand_ecc_choose_conf() with either
  chip->ecc.size or chip->ecc.strength value
  set and without NAND_ECC_MAXIMIZE flag.

CC: Masahiro Yamada 
Signed-off-by: Abhishek Sahu 
---
Changes from v3:

NEW PATCH

 drivers/mtd/nand/raw/nand_base.c | 39 +++
 include/linux/mtd/rawnand.h  |  9 -
 2 files changed, 15 insertions(+), 33 deletions(-)

diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index c64e3fc..f620236 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -6077,24 +6077,17 @@ static int nand_set_ecc_soft_ops(struct mtd_info *mtd)
  * by the controller and the calculated ECC bytes fit within the chip's OOB.
  * On success, the calculated ECC bytes is set.
  */
-int nand_check_ecc_caps(struct nand_chip *chip,
-   const struct nand_ecc_caps *caps, int oobavail)
+static int
+nand_check_ecc_caps(struct nand_chip *chip,
+   const struct nand_ecc_caps *caps, int oobavail)
 {
struct mtd_info *mtd = nand_to_mtd(chip);
const struct nand_ecc_step_info *stepinfo;
int preset_step = chip->ecc.size;
int preset_strength = chip->ecc.strength;
-   int nsteps, ecc_bytes;
+   int ecc_bytes, nsteps = mtd->writesize / preset_step;
int i, j;
 
-   if (WARN_ON(oobavail < 0))
-   return -EINVAL;
-
-   if (!preset_step || !preset_strength)
-   return -ENODATA;
-
-   nsteps = mtd->writesize / preset_step;
-
for (i = 0; i < caps->nstepinfos; i++) {
stepinfo = >stepinfos[i];
 
@@ -6127,7 +6120,6 @@ int nand_check_ecc_caps(struct nand_chip *chip,
 
return -ENOTSUPP;
 }
-EXPORT_SYMBOL_GPL(nand_check_ecc_caps);
 
 /**
  * nand_match_ecc_req - meet the chip's requirement with least ECC bytes
@@ -6139,8 +6131,9 @@ int nand_check_ecc_caps(struct nand_chip *chip,
  * number of ECC bytes (i.e. with the largest number of OOB-free bytes).
  * On success, the chosen ECC settings are set.
  */
-int nand_match_ecc_req(struct nand_chip *chip,
-  const struct nand_ecc_caps *caps, int oobavail)
+static int
+nand_match_ecc_req(struct nand_chip *chip,
+  const struct nand_ecc_caps *caps, int oobavail)
 {
struct mtd_info *mtd = nand_to_mtd(chip);
const struct nand_ecc_step_info *stepinfo;
@@ -6151,9 +6144,6 @@ int nand_match_ecc_req(struct nand_chip *chip,
int best_ecc_bytes_total = INT_MAX;
int i, j;
 
-   if (WARN_ON(oobavail < 0))
-   return -EINVAL;
-
/* No information provided by the NAND chip */
if (!req_step || !req_strength)
return -ENOTSUPP;
@@ -6212,7 +6202,6 @@ int nand_match_ecc_req(struct nand_chip *chip,
 
return 0;
 }
-EXPORT_SYMBOL_GPL(nand_match_ecc_req);
 
 /**
  * nand_maximize_ecc - choose the max ECC strength available
@@ -6223,8 +6212,9 @@ int nand_match_ecc_req(struct nand_chip *chip,
  * Choose the max ECC strength that is supported on the controller, and can fit
  * within the chip's OOB.  On success, the chosen ECC settings are set.
  */
-int nand_maximize_ecc(struct nand_chip *chip,
- const struct nand_ecc_caps *caps, int oobavail)
+static int
+nand_maximize_ecc(struct nand_chip *chip,
+ const struct nand_ecc_caps *caps, int oobavail)
 {
struct mtd_info *mtd = nand_to_mtd(chip);
const struct nand_ecc_step_info *stepinfo;
@@ -6234,9 +6224,6 @@ int nand_maximize_ecc(struct nand_chip *chip,
int best_strength, best_ecc_bytes;
int i, j;
 
-   if (WARN_ON(oobavail < 0))
-   return -EINVAL;
-
for (i = 0; i < caps->nstepinfos; i++) {
stepinfo = >stepinfos[i];
step_size = stepinfo->stepsize;
@@ -6285,7 +6272,6 @@ int nand_maximize_ecc(struct nand_chip *chip,
 
return 0;
 }
-EXPORT_SYMBOL_GPL(nand_maximize_ecc);
 
 /**
  * nand_ecc_choose_conf - Set the ECC strength and ECC step size
@@ -6307,6 +6293,11 @@ int nand_maximize_ecc(struct nand_chip *chip,
 int nand_ecc_choose_conf(struct nand_chip *chip,
 const struct nand_ecc_caps *caps, int oobavail)
 {
+   struct mtd_info *mtd = nand_to_mtd(chip);
+
+   if (WARN_ON(oobavail < 0 || oobavail > mtd->oobsize))
+   return -EINVAL;
+
if (chip->ecc.size && chip->ecc.strength)
return nand_check_ecc_cap

[PATCH v4 02/15] mtd: rawnand: denali: use helper function for ecc setup

2018-06-20 Thread Abhishek Sahu
Use the NAND core helper function nand_ecc_choose_conf to tune
the ECC parameters instead of the function locally defined.

Acked-by: Miquel Raynal 
Acked-by: Masahiro Yamada 
Signed-off-by: Abhishek Sahu 
---
* Changes from v3:
 NONE

* Changes from v2:

  1. Changed commit message

* Changes from v1:
  NEW PATCH

 drivers/mtd/nand/raw/denali.c | 30 ++
 1 file changed, 2 insertions(+), 28 deletions(-)

diff --git a/drivers/mtd/nand/raw/denali.c b/drivers/mtd/nand/raw/denali.c
index 2a302a1..a586a1d 100644
--- a/drivers/mtd/nand/raw/denali.c
+++ b/drivers/mtd/nand/raw/denali.c
@@ -1120,33 +1120,6 @@ int denali_calc_ecc_bytes(int step_size, int strength)
 }
 EXPORT_SYMBOL(denali_calc_ecc_bytes);
 
-static int denali_ecc_setup(struct mtd_info *mtd, struct nand_chip *chip,
-   struct denali_nand_info *denali)
-{
-   int oobavail = mtd->oobsize - denali->oob_skip_bytes;
-   int ret;
-
-   /*
-* If .size and .strength are already set (usually by DT),
-* check if they are supported by this controller.
-*/
-   if (chip->ecc.size && chip->ecc.strength)
-   return nand_check_ecc_caps(chip, denali->ecc_caps, oobavail);
-
-   /*
-* We want .size and .strength closest to the chip's requirement
-* unless NAND_ECC_MAXIMIZE is requested.
-*/
-   if (!(chip->ecc.options & NAND_ECC_MAXIMIZE)) {
-   ret = nand_match_ecc_req(chip, denali->ecc_caps, oobavail);
-   if (!ret)
-   return 0;
-   }
-
-   /* Max ECC strength is the last thing we can do */
-   return nand_maximize_ecc(chip, denali->ecc_caps, oobavail);
-}
-
 static int denali_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
 {
@@ -1317,7 +1290,8 @@ int denali_init(struct denali_nand_info *denali)
chip->ecc.mode = NAND_ECC_HW_SYNDROME;
chip->options |= NAND_NO_SUBPAGE_WRITE;
 
-   ret = denali_ecc_setup(mtd, chip, denali);
+   ret = nand_ecc_choose_conf(chip, denali->ecc_caps,
+  mtd->oobsize - denali->oob_skip_bytes);
if (ret) {
dev_err(denali->dev, "Failed to setup ECC settings.\n");
goto disable_irq;
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc.
is a member of Code Aurora Forum, hosted by The Linux Foundation



[PATCH v4 02/15] mtd: rawnand: denali: use helper function for ecc setup

2018-06-20 Thread Abhishek Sahu
Use the NAND core helper function nand_ecc_choose_conf to tune
the ECC parameters instead of the function locally defined.

Acked-by: Miquel Raynal 
Acked-by: Masahiro Yamada 
Signed-off-by: Abhishek Sahu 
---
* Changes from v3:
 NONE

* Changes from v2:

  1. Changed commit message

* Changes from v1:
  NEW PATCH

 drivers/mtd/nand/raw/denali.c | 30 ++
 1 file changed, 2 insertions(+), 28 deletions(-)

diff --git a/drivers/mtd/nand/raw/denali.c b/drivers/mtd/nand/raw/denali.c
index 2a302a1..a586a1d 100644
--- a/drivers/mtd/nand/raw/denali.c
+++ b/drivers/mtd/nand/raw/denali.c
@@ -1120,33 +1120,6 @@ int denali_calc_ecc_bytes(int step_size, int strength)
 }
 EXPORT_SYMBOL(denali_calc_ecc_bytes);
 
-static int denali_ecc_setup(struct mtd_info *mtd, struct nand_chip *chip,
-   struct denali_nand_info *denali)
-{
-   int oobavail = mtd->oobsize - denali->oob_skip_bytes;
-   int ret;
-
-   /*
-* If .size and .strength are already set (usually by DT),
-* check if they are supported by this controller.
-*/
-   if (chip->ecc.size && chip->ecc.strength)
-   return nand_check_ecc_caps(chip, denali->ecc_caps, oobavail);
-
-   /*
-* We want .size and .strength closest to the chip's requirement
-* unless NAND_ECC_MAXIMIZE is requested.
-*/
-   if (!(chip->ecc.options & NAND_ECC_MAXIMIZE)) {
-   ret = nand_match_ecc_req(chip, denali->ecc_caps, oobavail);
-   if (!ret)
-   return 0;
-   }
-
-   /* Max ECC strength is the last thing we can do */
-   return nand_maximize_ecc(chip, denali->ecc_caps, oobavail);
-}
-
 static int denali_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
 {
@@ -1317,7 +1290,8 @@ int denali_init(struct denali_nand_info *denali)
chip->ecc.mode = NAND_ECC_HW_SYNDROME;
chip->options |= NAND_NO_SUBPAGE_WRITE;
 
-   ret = denali_ecc_setup(mtd, chip, denali);
+   ret = nand_ecc_choose_conf(chip, denali->ecc_caps,
+  mtd->oobsize - denali->oob_skip_bytes);
if (ret) {
dev_err(denali->dev, "Failed to setup ECC settings.\n");
goto disable_irq;
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc.
is a member of Code Aurora Forum, hosted by The Linux Foundation



[PATCH v4 08/15] mtd: rawnand: qcom: fix null pointer access for erased page detection

2018-06-20 Thread Abhishek Sahu
parse_read_errors can be called with only oob_buf in which case
data_buf will be NULL.  If data_buf is NULL, then don’t
treat this page as completely erased in case of ECC uncorrectable
error for RS ECC. For BCH ECC, the controller itself tells
regarding erased page in status register.

Acked-by: Miquel Raynal 
Signed-off-by: Abhishek Sahu 
---
* Changes from v3:
  NONE

* Changes from v2:
  NONE

* Changes from v1:
  1. Added more detail in commit message
  2. Added comment before each if/else

 drivers/mtd/nand/raw/qcom_nandc.c | 18 +++---
 1 file changed, 15 insertions(+), 3 deletions(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c 
b/drivers/mtd/nand/raw/qcom_nandc.c
index 0d931d5..a831f9c 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -1611,13 +1611,24 @@ static int parse_read_errors(struct qcom_nand_host 
*host, u8 *data_buf,
int ret, ecclen, extraooblen;
void *eccbuf;
 
-   /* ignore erased codeword errors */
+   /*
+* For BCH ECC, ignore erased codeword errors, if
+* ERASED_CW bits are set.
+*/
if (host->bch_enabled) {
erased = (erased_cw & ERASED_CW) == ERASED_CW ?
 true : false;
-   } else {
+   /*
+* For RS ECC, HW reports the erased CW by placing
+* special characters at certain offsets in the buffer.
+* These special characters will be valid only if
+* complete page is read i.e. data_buf is not NULL.
+*/
+   } else if (data_buf) {
erased = erased_chunk_check_and_fixup(data_buf,
  data_len);
+   } else {
+   erased = false;
}
 
if (erased) {
@@ -1665,7 +1676,8 @@ static int parse_read_errors(struct qcom_nand_host *host, 
u8 *data_buf,
max_bitflips = max(max_bitflips, stat);
}
 
-   data_buf += data_len;
+   if (data_buf)
+   data_buf += data_len;
if (oob_buf)
oob_buf += oob_len + ecc->bytes;
}
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc.
is a member of Code Aurora Forum, hosted by The Linux Foundation



[PATCH v4 08/15] mtd: rawnand: qcom: fix null pointer access for erased page detection

2018-06-20 Thread Abhishek Sahu
parse_read_errors can be called with only oob_buf in which case
data_buf will be NULL.  If data_buf is NULL, then don’t
treat this page as completely erased in case of ECC uncorrectable
error for RS ECC. For BCH ECC, the controller itself tells
regarding erased page in status register.

Acked-by: Miquel Raynal 
Signed-off-by: Abhishek Sahu 
---
* Changes from v3:
  NONE

* Changes from v2:
  NONE

* Changes from v1:
  1. Added more detail in commit message
  2. Added comment before each if/else

 drivers/mtd/nand/raw/qcom_nandc.c | 18 +++---
 1 file changed, 15 insertions(+), 3 deletions(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c 
b/drivers/mtd/nand/raw/qcom_nandc.c
index 0d931d5..a831f9c 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -1611,13 +1611,24 @@ static int parse_read_errors(struct qcom_nand_host 
*host, u8 *data_buf,
int ret, ecclen, extraooblen;
void *eccbuf;
 
-   /* ignore erased codeword errors */
+   /*
+* For BCH ECC, ignore erased codeword errors, if
+* ERASED_CW bits are set.
+*/
if (host->bch_enabled) {
erased = (erased_cw & ERASED_CW) == ERASED_CW ?
 true : false;
-   } else {
+   /*
+* For RS ECC, HW reports the erased CW by placing
+* special characters at certain offsets in the buffer.
+* These special characters will be valid only if
+* complete page is read i.e. data_buf is not NULL.
+*/
+   } else if (data_buf) {
erased = erased_chunk_check_and_fixup(data_buf,
  data_len);
+   } else {
+   erased = false;
}
 
if (erased) {
@@ -1665,7 +1676,8 @@ static int parse_read_errors(struct qcom_nand_host *host, 
u8 *data_buf,
max_bitflips = max(max_bitflips, stat);
}
 
-   data_buf += data_len;
+   if (data_buf)
+   data_buf += data_len;
if (oob_buf)
oob_buf += oob_len + ecc->bytes;
}
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc.
is a member of Code Aurora Forum, hosted by The Linux Foundation



[PATCH v4 07/15] mtd: rawnand: qcom: erased page detection for uncorrectable errors only

2018-06-20 Thread Abhishek Sahu
Following is the flow in the HW if controller tries to read erased
page:

1. First ECC uncorrectable error will be generated from ECC engine
   since ECC engine first calculates the ECC with all 0xff and match
   the calculated ECC with ECC code in OOB (which is again all 0xff).
2. After getting ECC error, erased CW detection logic will be
   applied which is different for BCH and RS ECC
a. For BCH, HW checks if all the bytes in page are 0xff and then
   it updates the status in separate register
   NAND_ERASED_CW_DETECT_STATUS.
b. For RS ECC, the HW reports the same error when reading an
   erased CW, but it notifies that it is an erased CW by
   placing special characters at certain offsets in the
   buffer.

So the erased CW detect status should be checked only if ECC engine
generated the uncorrectable error.

Currently for all other operational errors also (like TIMEOUT, MPU
errors, etc.), the erased CW detect logic is being applied so fix this
and return EIO for other operational errors.

Acked-by: Miquel Raynal 
Signed-off-by: Abhishek Sahu 
---
* Changes from v3:
  NONE

* Changes from v2:
  1. Changed commit message slightly

* Changes from v1:
  1. Added more detail in commit message
  2. Added comment before each if/else
  3. Removed redundant check for BS_UNCORRECTABLE_BIT

 drivers/mtd/nand/raw/qcom_nandc.c | 65 ++-
 1 file changed, 43 insertions(+), 22 deletions(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c 
b/drivers/mtd/nand/raw/qcom_nandc.c
index fc20149..0d931d5 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -1576,6 +1576,7 @@ static int parse_read_errors(struct qcom_nand_host *host, 
u8 *data_buf,
struct nand_ecc_ctrl *ecc = >ecc;
unsigned int max_bitflips = 0;
struct read_stats *buf;
+   bool flash_op_err = false;
int i;
 
buf = (struct read_stats *)nandc->reg_read_buf;
@@ -1597,8 +1598,18 @@ static int parse_read_errors(struct qcom_nand_host 
*host, u8 *data_buf,
buffer = le32_to_cpu(buf->buffer);
erased_cw = le32_to_cpu(buf->erased_cw);
 
-   if (flash & (FS_OP_ERR | FS_MPU_ERR)) {
+   /*
+* Check ECC failure for each codeword. ECC failure can
+* happen in either of the following conditions
+* 1. If number of bitflips are greater than ECC engine
+*capability.
+* 2. If this codeword contains all 0xff for which erased
+*codeword detection check will be done.
+*/
+   if ((flash & FS_OP_ERR) && (buffer & BS_UNCORRECTABLE_BIT)) {
bool erased;
+   int ret, ecclen, extraooblen;
+   void *eccbuf;
 
/* ignore erased codeword errors */
if (host->bch_enabled) {
@@ -1616,29 +1627,36 @@ static int parse_read_errors(struct qcom_nand_host 
*host, u8 *data_buf,
continue;
}
 
-   if (buffer & BS_UNCORRECTABLE_BIT) {
-   int ret, ecclen, extraooblen;
-   void *eccbuf;
+   eccbuf = oob_buf ? oob_buf + oob_len : NULL;
+   ecclen = oob_buf ? host->ecc_bytes_hw : 0;
+   extraooblen = oob_buf ? oob_len : 0;
 
-   eccbuf = oob_buf ? oob_buf + oob_len : NULL;
-   ecclen = oob_buf ? host->ecc_bytes_hw : 0;
-   extraooblen = oob_buf ? oob_len : 0;
-
-   /*
-* make sure it isn't an erased page reported
-* as not-erased by HW because of a few bitflips
-*/
-   ret = nand_check_erased_ecc_chunk(data_buf,
-   data_len, eccbuf, ecclen, oob_buf,
-   extraooblen, ecc->strength);
-   if (ret < 0) {
-   mtd->ecc_stats.failed++;
-   } else {
-   mtd->ecc_stats.corrected += ret;
-   max_bitflips =
-   max_t(unsigned int, 
max_bitflips, ret);
-   }
+   /*
+* make sure it isn't an erased page reported
+* as not-erased by HW because of a few bitflips
+*/
+   ret = nand_check_erased_ecc_chunk(data_buf,
+   data_len, eccbuf, ecclen, oob_buf,
+

[PATCH v4 07/15] mtd: rawnand: qcom: erased page detection for uncorrectable errors only

2018-06-20 Thread Abhishek Sahu
Following is the flow in the HW if controller tries to read erased
page:

1. First ECC uncorrectable error will be generated from ECC engine
   since ECC engine first calculates the ECC with all 0xff and match
   the calculated ECC with ECC code in OOB (which is again all 0xff).
2. After getting ECC error, erased CW detection logic will be
   applied which is different for BCH and RS ECC
a. For BCH, HW checks if all the bytes in page are 0xff and then
   it updates the status in separate register
   NAND_ERASED_CW_DETECT_STATUS.
b. For RS ECC, the HW reports the same error when reading an
   erased CW, but it notifies that it is an erased CW by
   placing special characters at certain offsets in the
   buffer.

So the erased CW detect status should be checked only if ECC engine
generated the uncorrectable error.

Currently for all other operational errors also (like TIMEOUT, MPU
errors, etc.), the erased CW detect logic is being applied so fix this
and return EIO for other operational errors.

Acked-by: Miquel Raynal 
Signed-off-by: Abhishek Sahu 
---
* Changes from v3:
  NONE

* Changes from v2:
  1. Changed commit message slightly

* Changes from v1:
  1. Added more detail in commit message
  2. Added comment before each if/else
  3. Removed redundant check for BS_UNCORRECTABLE_BIT

 drivers/mtd/nand/raw/qcom_nandc.c | 65 ++-
 1 file changed, 43 insertions(+), 22 deletions(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c 
b/drivers/mtd/nand/raw/qcom_nandc.c
index fc20149..0d931d5 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -1576,6 +1576,7 @@ static int parse_read_errors(struct qcom_nand_host *host, 
u8 *data_buf,
struct nand_ecc_ctrl *ecc = >ecc;
unsigned int max_bitflips = 0;
struct read_stats *buf;
+   bool flash_op_err = false;
int i;
 
buf = (struct read_stats *)nandc->reg_read_buf;
@@ -1597,8 +1598,18 @@ static int parse_read_errors(struct qcom_nand_host 
*host, u8 *data_buf,
buffer = le32_to_cpu(buf->buffer);
erased_cw = le32_to_cpu(buf->erased_cw);
 
-   if (flash & (FS_OP_ERR | FS_MPU_ERR)) {
+   /*
+* Check ECC failure for each codeword. ECC failure can
+* happen in either of the following conditions
+* 1. If number of bitflips are greater than ECC engine
+*capability.
+* 2. If this codeword contains all 0xff for which erased
+*codeword detection check will be done.
+*/
+   if ((flash & FS_OP_ERR) && (buffer & BS_UNCORRECTABLE_BIT)) {
bool erased;
+   int ret, ecclen, extraooblen;
+   void *eccbuf;
 
/* ignore erased codeword errors */
if (host->bch_enabled) {
@@ -1616,29 +1627,36 @@ static int parse_read_errors(struct qcom_nand_host 
*host, u8 *data_buf,
continue;
}
 
-   if (buffer & BS_UNCORRECTABLE_BIT) {
-   int ret, ecclen, extraooblen;
-   void *eccbuf;
+   eccbuf = oob_buf ? oob_buf + oob_len : NULL;
+   ecclen = oob_buf ? host->ecc_bytes_hw : 0;
+   extraooblen = oob_buf ? oob_len : 0;
 
-   eccbuf = oob_buf ? oob_buf + oob_len : NULL;
-   ecclen = oob_buf ? host->ecc_bytes_hw : 0;
-   extraooblen = oob_buf ? oob_len : 0;
-
-   /*
-* make sure it isn't an erased page reported
-* as not-erased by HW because of a few bitflips
-*/
-   ret = nand_check_erased_ecc_chunk(data_buf,
-   data_len, eccbuf, ecclen, oob_buf,
-   extraooblen, ecc->strength);
-   if (ret < 0) {
-   mtd->ecc_stats.failed++;
-   } else {
-   mtd->ecc_stats.corrected += ret;
-   max_bitflips =
-   max_t(unsigned int, 
max_bitflips, ret);
-   }
+   /*
+* make sure it isn't an erased page reported
+* as not-erased by HW because of a few bitflips
+*/
+   ret = nand_check_erased_ecc_chunk(data_buf,
+   data_len, eccbuf, ecclen, oob_buf,
+

[PATCH v4 01/15] mtd: rawnand: helper function for setting up ECC configuration

2018-06-20 Thread Abhishek Sahu
commit 2c8f8afa7f92 ("mtd: nand: add generic helpers to check,
match, maximize ECC settings") provides generic helpers which
drivers can use for setting up ECC parameters.

Since same board can have different ECC strength nand chips so
following is the logic for setting up ECC strength and ECC step
size, which can be used by most of the drivers.

1. If both ECC step size and ECC strength are already set
   (usually by DT) then just check whether this setting
   is supported by NAND controller.
2. If NAND_ECC_MAXIMIZE is set, then select maximum ECC strength
   supported by NAND controller.
3. Otherwise, try to match the ECC step size and ECC strength closest
   to the chip's requirement. If available OOB size can't fit the chip
   requirement then select maximum ECC strength which can be fit with
   available OOB size.

This patch introduces nand_ecc_choose_conf function which calls the
required helper functions for the above logic. The drivers can use
this single function instead of calling the 3 helper functions
individually.

CC: Masahiro Yamada 
Signed-off-by: Abhishek Sahu 
---
* Changes from v3:
  1. call nand_maximize_ecc() 2 times to make code more clear.

* Changes from v2:

  1. Renamed function to nand_ecc_choose_conf.
  2. Minor code reorganization to remove warning and 2 function calls
 for nand_maximize_ecc.

* Changes from v1:
  NEW PATCH

 drivers/mtd/nand/raw/nand_base.c | 33 +
 include/linux/mtd/rawnand.h  |  3 +++
 2 files changed, 36 insertions(+)

diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index 10c4f991..c64e3fc 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -6287,6 +6287,39 @@ int nand_maximize_ecc(struct nand_chip *chip,
 }
 EXPORT_SYMBOL_GPL(nand_maximize_ecc);
 
+/**
+ * nand_ecc_choose_conf - Set the ECC strength and ECC step size
+ * @chip: nand chip info structure
+ * @caps: ECC engine caps info structure
+ * @oobavail: OOB size that the ECC engine can use
+ *
+ * Choose the ECC configuration according to following logic
+ *
+ * 1. If both ECC step size and ECC strength are already set (usually by DT)
+ *then check if it is supported by this controller.
+ * 2. If NAND_ECC_MAXIMIZE is set, then select maximum ECC strength.
+ * 3. Otherwise, try to match the ECC step size and ECC strength closest
+ *to the chip's requirement. If available OOB size can't fit the chip
+ *requirement then fallback to the maximum ECC step size and ECC strength.
+ *
+ * On success, the chosen ECC settings are set.
+ */
+int nand_ecc_choose_conf(struct nand_chip *chip,
+const struct nand_ecc_caps *caps, int oobavail)
+{
+   if (chip->ecc.size && chip->ecc.strength)
+   return nand_check_ecc_caps(chip, caps, oobavail);
+
+   if (chip->ecc.options & NAND_ECC_MAXIMIZE)
+   return nand_maximize_ecc(chip, caps, oobavail);
+
+   if (!nand_match_ecc_req(chip, caps, oobavail))
+   return 0;
+
+   return nand_maximize_ecc(chip, caps, oobavail);
+}
+EXPORT_SYMBOL_GPL(nand_ecc_choose_conf);
+
 /*
  * Check if the chip configuration meet the datasheet requirements.
 
diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h
index 3e8ec3b..03a0061 100644
--- a/include/linux/mtd/rawnand.h
+++ b/include/linux/mtd/rawnand.h
@@ -1650,6 +1650,9 @@ int nand_match_ecc_req(struct nand_chip *chip,
 int nand_maximize_ecc(struct nand_chip *chip,
  const struct nand_ecc_caps *caps, int oobavail);
 
+int nand_ecc_choose_conf(struct nand_chip *chip,
+const struct nand_ecc_caps *caps, int oobavail);
+
 /* Default write_oob implementation */
 int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page);
 
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc.
is a member of Code Aurora Forum, hosted by The Linux Foundation



[PATCH v4 01/15] mtd: rawnand: helper function for setting up ECC configuration

2018-06-20 Thread Abhishek Sahu
commit 2c8f8afa7f92 ("mtd: nand: add generic helpers to check,
match, maximize ECC settings") provides generic helpers which
drivers can use for setting up ECC parameters.

Since same board can have different ECC strength nand chips so
following is the logic for setting up ECC strength and ECC step
size, which can be used by most of the drivers.

1. If both ECC step size and ECC strength are already set
   (usually by DT) then just check whether this setting
   is supported by NAND controller.
2. If NAND_ECC_MAXIMIZE is set, then select maximum ECC strength
   supported by NAND controller.
3. Otherwise, try to match the ECC step size and ECC strength closest
   to the chip's requirement. If available OOB size can't fit the chip
   requirement then select maximum ECC strength which can be fit with
   available OOB size.

This patch introduces nand_ecc_choose_conf function which calls the
required helper functions for the above logic. The drivers can use
this single function instead of calling the 3 helper functions
individually.

CC: Masahiro Yamada 
Signed-off-by: Abhishek Sahu 
---
* Changes from v3:
  1. call nand_maximize_ecc() 2 times to make code more clear.

* Changes from v2:

  1. Renamed function to nand_ecc_choose_conf.
  2. Minor code reorganization to remove warning and 2 function calls
 for nand_maximize_ecc.

* Changes from v1:
  NEW PATCH

 drivers/mtd/nand/raw/nand_base.c | 33 +
 include/linux/mtd/rawnand.h  |  3 +++
 2 files changed, 36 insertions(+)

diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index 10c4f991..c64e3fc 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -6287,6 +6287,39 @@ int nand_maximize_ecc(struct nand_chip *chip,
 }
 EXPORT_SYMBOL_GPL(nand_maximize_ecc);
 
+/**
+ * nand_ecc_choose_conf - Set the ECC strength and ECC step size
+ * @chip: nand chip info structure
+ * @caps: ECC engine caps info structure
+ * @oobavail: OOB size that the ECC engine can use
+ *
+ * Choose the ECC configuration according to following logic
+ *
+ * 1. If both ECC step size and ECC strength are already set (usually by DT)
+ *then check if it is supported by this controller.
+ * 2. If NAND_ECC_MAXIMIZE is set, then select maximum ECC strength.
+ * 3. Otherwise, try to match the ECC step size and ECC strength closest
+ *to the chip's requirement. If available OOB size can't fit the chip
+ *requirement then fallback to the maximum ECC step size and ECC strength.
+ *
+ * On success, the chosen ECC settings are set.
+ */
+int nand_ecc_choose_conf(struct nand_chip *chip,
+const struct nand_ecc_caps *caps, int oobavail)
+{
+   if (chip->ecc.size && chip->ecc.strength)
+   return nand_check_ecc_caps(chip, caps, oobavail);
+
+   if (chip->ecc.options & NAND_ECC_MAXIMIZE)
+   return nand_maximize_ecc(chip, caps, oobavail);
+
+   if (!nand_match_ecc_req(chip, caps, oobavail))
+   return 0;
+
+   return nand_maximize_ecc(chip, caps, oobavail);
+}
+EXPORT_SYMBOL_GPL(nand_ecc_choose_conf);
+
 /*
  * Check if the chip configuration meet the datasheet requirements.
 
diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h
index 3e8ec3b..03a0061 100644
--- a/include/linux/mtd/rawnand.h
+++ b/include/linux/mtd/rawnand.h
@@ -1650,6 +1650,9 @@ int nand_match_ecc_req(struct nand_chip *chip,
 int nand_maximize_ecc(struct nand_chip *chip,
  const struct nand_ecc_caps *caps, int oobavail);
 
+int nand_ecc_choose_conf(struct nand_chip *chip,
+const struct nand_ecc_caps *caps, int oobavail);
+
 /* Default write_oob implementation */
 int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page);
 
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc.
is a member of Code Aurora Forum, hosted by The Linux Foundation



[PATCH v4 09/15] mtd: rawnand: qcom: parse read errors for read oob also

2018-06-20 Thread Abhishek Sahu
read_page and read_oob both calls the read_page_ecc function.
The QCOM NAND controller protect the OOB available bytes with
ECC so read errors should be checked for read_oob also.
This patch moves the error checking code inside read_page_ecc
so caller does not have to check explicitly for read errors.

Reviewed-by: Miquel Raynal 
Signed-off-by: Abhishek Sahu 
---
* Changes from v3:
  NONE

* Changes from v2:
  NONE

* Changes from v1:
  1. Minor code change for return early in case of error

 drivers/mtd/nand/raw/qcom_nandc.c | 26 +-
 1 file changed, 9 insertions(+), 17 deletions(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c 
b/drivers/mtd/nand/raw/qcom_nandc.c
index a831f9c..285b2ad3 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -1698,6 +1698,7 @@ static int read_page_ecc(struct qcom_nand_host *host, u8 
*data_buf,
struct nand_chip *chip = >chip;
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
struct nand_ecc_ctrl *ecc = >ecc;
+   u8 *data_buf_start = data_buf, *oob_buf_start = oob_buf;
int i, ret;
 
config_nand_page_read(nandc);
@@ -1758,12 +1759,14 @@ static int read_page_ecc(struct qcom_nand_host *host, 
u8 *data_buf,
}
 
ret = submit_descs(nandc);
-   if (ret)
+   free_descs(nandc);
+
+   if (ret) {
dev_err(nandc->dev, "failure to read page/oob\n");
+   return ret;
+   }
 
-   free_descs(nandc);
-
-   return ret;
+   return parse_read_errors(host, data_buf_start, oob_buf_start);
 }
 
 /*
@@ -1808,20 +1811,14 @@ static int qcom_nandc_read_page(struct mtd_info *mtd, 
struct nand_chip *chip,
struct qcom_nand_host *host = to_qcom_nand_host(chip);
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
u8 *data_buf, *oob_buf = NULL;
-   int ret;
 
nand_read_page_op(chip, page, 0, NULL, 0);
data_buf = buf;
oob_buf = oob_required ? chip->oob_poi : NULL;
 
clear_bam_transaction(nandc);
-   ret = read_page_ecc(host, data_buf, oob_buf);
-   if (ret) {
-   dev_err(nandc->dev, "failure to read page\n");
-   return ret;
-   }
 
-   return parse_read_errors(host, data_buf, oob_buf);
+   return read_page_ecc(host, data_buf, oob_buf);
 }
 
 /* implements ecc->read_page_raw() */
@@ -1911,7 +1908,6 @@ static int qcom_nandc_read_oob(struct mtd_info *mtd, 
struct nand_chip *chip,
struct qcom_nand_host *host = to_qcom_nand_host(chip);
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
struct nand_ecc_ctrl *ecc = >ecc;
-   int ret;
 
clear_read_regs(nandc);
clear_bam_transaction(nandc);
@@ -1920,11 +1916,7 @@ static int qcom_nandc_read_oob(struct mtd_info *mtd, 
struct nand_chip *chip,
set_address(host, 0, page);
update_rw_regs(host, ecc->steps, true);
 
-   ret = read_page_ecc(host, NULL, chip->oob_poi);
-   if (ret)
-   dev_err(nandc->dev, "failure to read oob\n");
-
-   return ret;
+   return read_page_ecc(host, NULL, chip->oob_poi);
 }
 
 /* implements ecc->write_page() */
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc.
is a member of Code Aurora Forum, hosted by The Linux Foundation



[PATCH v4 09/15] mtd: rawnand: qcom: parse read errors for read oob also

2018-06-20 Thread Abhishek Sahu
read_page and read_oob both calls the read_page_ecc function.
The QCOM NAND controller protect the OOB available bytes with
ECC so read errors should be checked for read_oob also.
This patch moves the error checking code inside read_page_ecc
so caller does not have to check explicitly for read errors.

Reviewed-by: Miquel Raynal 
Signed-off-by: Abhishek Sahu 
---
* Changes from v3:
  NONE

* Changes from v2:
  NONE

* Changes from v1:
  1. Minor code change for return early in case of error

 drivers/mtd/nand/raw/qcom_nandc.c | 26 +-
 1 file changed, 9 insertions(+), 17 deletions(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c 
b/drivers/mtd/nand/raw/qcom_nandc.c
index a831f9c..285b2ad3 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -1698,6 +1698,7 @@ static int read_page_ecc(struct qcom_nand_host *host, u8 
*data_buf,
struct nand_chip *chip = >chip;
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
struct nand_ecc_ctrl *ecc = >ecc;
+   u8 *data_buf_start = data_buf, *oob_buf_start = oob_buf;
int i, ret;
 
config_nand_page_read(nandc);
@@ -1758,12 +1759,14 @@ static int read_page_ecc(struct qcom_nand_host *host, 
u8 *data_buf,
}
 
ret = submit_descs(nandc);
-   if (ret)
+   free_descs(nandc);
+
+   if (ret) {
dev_err(nandc->dev, "failure to read page/oob\n");
+   return ret;
+   }
 
-   free_descs(nandc);
-
-   return ret;
+   return parse_read_errors(host, data_buf_start, oob_buf_start);
 }
 
 /*
@@ -1808,20 +1811,14 @@ static int qcom_nandc_read_page(struct mtd_info *mtd, 
struct nand_chip *chip,
struct qcom_nand_host *host = to_qcom_nand_host(chip);
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
u8 *data_buf, *oob_buf = NULL;
-   int ret;
 
nand_read_page_op(chip, page, 0, NULL, 0);
data_buf = buf;
oob_buf = oob_required ? chip->oob_poi : NULL;
 
clear_bam_transaction(nandc);
-   ret = read_page_ecc(host, data_buf, oob_buf);
-   if (ret) {
-   dev_err(nandc->dev, "failure to read page\n");
-   return ret;
-   }
 
-   return parse_read_errors(host, data_buf, oob_buf);
+   return read_page_ecc(host, data_buf, oob_buf);
 }
 
 /* implements ecc->read_page_raw() */
@@ -1911,7 +1908,6 @@ static int qcom_nandc_read_oob(struct mtd_info *mtd, 
struct nand_chip *chip,
struct qcom_nand_host *host = to_qcom_nand_host(chip);
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
struct nand_ecc_ctrl *ecc = >ecc;
-   int ret;
 
clear_read_regs(nandc);
clear_bam_transaction(nandc);
@@ -1920,11 +1916,7 @@ static int qcom_nandc_read_oob(struct mtd_info *mtd, 
struct nand_chip *chip,
set_address(host, 0, page);
update_rw_regs(host, ecc->steps, true);
 
-   ret = read_page_ecc(host, NULL, chip->oob_poi);
-   if (ret)
-   dev_err(nandc->dev, "failure to read oob\n");
-
-   return ret;
+   return read_page_ecc(host, NULL, chip->oob_poi);
 }
 
 /* implements ecc->write_page() */
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc.
is a member of Code Aurora Forum, hosted by The Linux Foundation



[PATCH v4 12/15] mtd: rawnand: qcom: check for operation errors in case of raw read

2018-06-20 Thread Abhishek Sahu
Currently there is no error checking for raw read. For raw
reads, there won’t be any ECC failure but the operational
failures are possible, so schedule the NAND_FLASH_STATUS read
after each codeword.

Acked-by: Miquel Raynal 
Signed-off-by: Abhishek Sahu 
---
* Changes from v3:
 1. Since bad block reorganization patch has removed from this
patch series so following change is required in copy_last_cw)
config_nand_single_cw_page_read(nandc);
-> config_nand_single_cw_page_read(nandc, host->use_ecc);

* Changes from v2:
  NONE

* Changes from v1:
 1. Removed the code for copy_last_cw.

 drivers/mtd/nand/raw/qcom_nandc.c | 58 +++
 1 file changed, 40 insertions(+), 18 deletions(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c 
b/drivers/mtd/nand/raw/qcom_nandc.c
index 887b1f6..5999c39 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -1096,7 +1096,8 @@ static void config_nand_page_read(struct 
qcom_nand_controller *nandc)
  * Helper to prepare DMA descriptors for configuring registers
  * before reading each codeword in NAND page.
  */
-static void config_nand_cw_read(struct qcom_nand_controller *nandc)
+static void
+config_nand_cw_read(struct qcom_nand_controller *nandc, bool use_ecc)
 {
if (nandc->props->is_bam)
write_reg_dma(nandc, NAND_READ_LOCATION_0, 4,
@@ -1105,19 +1106,25 @@ static void config_nand_cw_read(struct 
qcom_nand_controller *nandc)
write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
 
-   read_reg_dma(nandc, NAND_FLASH_STATUS, 2, 0);
-   read_reg_dma(nandc, NAND_ERASED_CW_DETECT_STATUS, 1,
-NAND_BAM_NEXT_SGL);
+   if (use_ecc) {
+   read_reg_dma(nandc, NAND_FLASH_STATUS, 2, 0);
+   read_reg_dma(nandc, NAND_ERASED_CW_DETECT_STATUS, 1,
+NAND_BAM_NEXT_SGL);
+   } else {
+   read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
+   }
 }
 
 /*
  * Helper to prepare dma descriptors to configure registers needed for reading 
a
  * single codeword in page
  */
-static void config_nand_single_cw_page_read(struct qcom_nand_controller *nandc)
+static void
+config_nand_single_cw_page_read(struct qcom_nand_controller *nandc,
+   bool use_ecc)
 {
config_nand_page_read(nandc);
-   config_nand_cw_read(nandc);
+   config_nand_cw_read(nandc, use_ecc);
 }
 
 /*
@@ -1198,7 +1205,7 @@ static int nandc_param(struct qcom_nand_host *host)
nandc->buf_count = 512;
memset(nandc->data_buffer, 0xff, nandc->buf_count);
 
-   config_nand_single_cw_page_read(nandc);
+   config_nand_single_cw_page_read(nandc, false);
 
read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer,
  nandc->buf_count, 0);
@@ -1563,6 +1570,23 @@ struct read_stats {
__le32 erased_cw;
 };
 
+/* reads back FLASH_STATUS register set by the controller */
+static int check_flash_errors(struct qcom_nand_host *host, int cw_cnt)
+{
+   struct nand_chip *chip = >chip;
+   struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+   int i;
+
+   for (i = 0; i < cw_cnt; i++) {
+   u32 flash = le32_to_cpu(nandc->reg_read_buf[i]);
+
+   if (flash & (FS_OP_ERR | FS_MPU_ERR))
+   return -EIO;
+   }
+
+   return 0;
+}
+
 /*
  * reads back status registers set by the controller to notify page read
  * errors. this is equivalent to what 'ecc->correct()' would do.
@@ -1729,7 +1753,7 @@ static int read_page_ecc(struct qcom_nand_host *host, u8 
*data_buf,
}
}
 
-   config_nand_cw_read(nandc);
+   config_nand_cw_read(nandc, true);
 
if (data_buf)
read_data_dma(nandc, FLASH_BUF_ACC, data_buf,
@@ -1791,7 +1815,7 @@ static int copy_last_cw(struct qcom_nand_host *host, int 
page)
set_address(host, host->cw_size * (ecc->steps - 1), page);
update_rw_regs(host, 1, true);
 
-   config_nand_single_cw_page_read(nandc);
+   config_nand_single_cw_page_read(nandc, host->use_ecc);
 
read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, size, 0);
 
@@ -1874,7 +1898,7 @@ static int qcom_nandc_read_page_raw(struct mtd_info *mtd,
nandc_set_read_loc(nandc, 3, read_loc, oob_size2, 1);
}
 
-   config_nand_cw_read(nandc);
+   config_nand_cw_read(nandc, false);
 
read_data_dma(nandc, reg_off, data_buf, data_size1, 0);
reg_off += data_size1;
@@ -1893,12 +1917,13 @@ static int qcom_nandc_read_page_raw(struct mtd_info 
*mtd,
}
 
ret = submit_descs(nandc);
-   if (ret)
+   free_descs(nandc);
+   if (ret)

[PATCH v4 12/15] mtd: rawnand: qcom: check for operation errors in case of raw read

2018-06-20 Thread Abhishek Sahu
Currently there is no error checking for raw read. For raw
reads, there won’t be any ECC failure but the operational
failures are possible, so schedule the NAND_FLASH_STATUS read
after each codeword.

Acked-by: Miquel Raynal 
Signed-off-by: Abhishek Sahu 
---
* Changes from v3:
 1. Since bad block reorganization patch has removed from this
patch series so following change is required in copy_last_cw)
config_nand_single_cw_page_read(nandc);
-> config_nand_single_cw_page_read(nandc, host->use_ecc);

* Changes from v2:
  NONE

* Changes from v1:
 1. Removed the code for copy_last_cw.

 drivers/mtd/nand/raw/qcom_nandc.c | 58 +++
 1 file changed, 40 insertions(+), 18 deletions(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c 
b/drivers/mtd/nand/raw/qcom_nandc.c
index 887b1f6..5999c39 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -1096,7 +1096,8 @@ static void config_nand_page_read(struct 
qcom_nand_controller *nandc)
  * Helper to prepare DMA descriptors for configuring registers
  * before reading each codeword in NAND page.
  */
-static void config_nand_cw_read(struct qcom_nand_controller *nandc)
+static void
+config_nand_cw_read(struct qcom_nand_controller *nandc, bool use_ecc)
 {
if (nandc->props->is_bam)
write_reg_dma(nandc, NAND_READ_LOCATION_0, 4,
@@ -1105,19 +1106,25 @@ static void config_nand_cw_read(struct 
qcom_nand_controller *nandc)
write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
 
-   read_reg_dma(nandc, NAND_FLASH_STATUS, 2, 0);
-   read_reg_dma(nandc, NAND_ERASED_CW_DETECT_STATUS, 1,
-NAND_BAM_NEXT_SGL);
+   if (use_ecc) {
+   read_reg_dma(nandc, NAND_FLASH_STATUS, 2, 0);
+   read_reg_dma(nandc, NAND_ERASED_CW_DETECT_STATUS, 1,
+NAND_BAM_NEXT_SGL);
+   } else {
+   read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
+   }
 }
 
 /*
  * Helper to prepare dma descriptors to configure registers needed for reading 
a
  * single codeword in page
  */
-static void config_nand_single_cw_page_read(struct qcom_nand_controller *nandc)
+static void
+config_nand_single_cw_page_read(struct qcom_nand_controller *nandc,
+   bool use_ecc)
 {
config_nand_page_read(nandc);
-   config_nand_cw_read(nandc);
+   config_nand_cw_read(nandc, use_ecc);
 }
 
 /*
@@ -1198,7 +1205,7 @@ static int nandc_param(struct qcom_nand_host *host)
nandc->buf_count = 512;
memset(nandc->data_buffer, 0xff, nandc->buf_count);
 
-   config_nand_single_cw_page_read(nandc);
+   config_nand_single_cw_page_read(nandc, false);
 
read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer,
  nandc->buf_count, 0);
@@ -1563,6 +1570,23 @@ struct read_stats {
__le32 erased_cw;
 };
 
+/* reads back FLASH_STATUS register set by the controller */
+static int check_flash_errors(struct qcom_nand_host *host, int cw_cnt)
+{
+   struct nand_chip *chip = >chip;
+   struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+   int i;
+
+   for (i = 0; i < cw_cnt; i++) {
+   u32 flash = le32_to_cpu(nandc->reg_read_buf[i]);
+
+   if (flash & (FS_OP_ERR | FS_MPU_ERR))
+   return -EIO;
+   }
+
+   return 0;
+}
+
 /*
  * reads back status registers set by the controller to notify page read
  * errors. this is equivalent to what 'ecc->correct()' would do.
@@ -1729,7 +1753,7 @@ static int read_page_ecc(struct qcom_nand_host *host, u8 
*data_buf,
}
}
 
-   config_nand_cw_read(nandc);
+   config_nand_cw_read(nandc, true);
 
if (data_buf)
read_data_dma(nandc, FLASH_BUF_ACC, data_buf,
@@ -1791,7 +1815,7 @@ static int copy_last_cw(struct qcom_nand_host *host, int 
page)
set_address(host, host->cw_size * (ecc->steps - 1), page);
update_rw_regs(host, 1, true);
 
-   config_nand_single_cw_page_read(nandc);
+   config_nand_single_cw_page_read(nandc, host->use_ecc);
 
read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, size, 0);
 
@@ -1874,7 +1898,7 @@ static int qcom_nandc_read_page_raw(struct mtd_info *mtd,
nandc_set_read_loc(nandc, 3, read_loc, oob_size2, 1);
}
 
-   config_nand_cw_read(nandc);
+   config_nand_cw_read(nandc, false);
 
read_data_dma(nandc, reg_off, data_buf, data_size1, 0);
reg_off += data_size1;
@@ -1893,12 +1917,13 @@ static int qcom_nandc_read_page_raw(struct mtd_info 
*mtd,
}
 
ret = submit_descs(nandc);
-   if (ret)
+   free_descs(nandc);
+   if (ret)

[PATCH v4 11/15] mtd: rawnand: qcom: fix return value for raw page read

2018-06-20 Thread Abhishek Sahu
Fix value returned by ->read_page_raw() to be the
actual operation status, instead of always 0.

Acked-by: Miquel Raynal 
Signed-off-by: Abhishek Sahu 
---
* Changes from v3:
  NONE

* Changes from v2:

  1. Changed commit message

* Changes from v1:
 NEW CHANGE

 drivers/mtd/nand/raw/qcom_nandc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c 
b/drivers/mtd/nand/raw/qcom_nandc.c
index 28361b5..887b1f6 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -1898,7 +1898,7 @@ static int qcom_nandc_read_page_raw(struct mtd_info *mtd,
 
free_descs(nandc);
 
-   return 0;
+   return ret;
 }
 
 /* implements ecc->read_oob() */
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc.
is a member of Code Aurora Forum, hosted by The Linux Foundation



[PATCH v4 11/15] mtd: rawnand: qcom: fix return value for raw page read

2018-06-20 Thread Abhishek Sahu
Fix value returned by ->read_page_raw() to be the
actual operation status, instead of always 0.

Acked-by: Miquel Raynal 
Signed-off-by: Abhishek Sahu 
---
* Changes from v3:
  NONE

* Changes from v2:

  1. Changed commit message

* Changes from v1:
 NEW CHANGE

 drivers/mtd/nand/raw/qcom_nandc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c 
b/drivers/mtd/nand/raw/qcom_nandc.c
index 28361b5..887b1f6 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -1898,7 +1898,7 @@ static int qcom_nandc_read_page_raw(struct mtd_info *mtd,
 
free_descs(nandc);
 
-   return 0;
+   return ret;
 }
 
 /* implements ecc->read_oob() */
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc.
is a member of Code Aurora Forum, hosted by The Linux Foundation



[PATCH v4 04/15] mtd: rawnand: qcom: remove dt property nand-ecc-step-size

2018-06-20 Thread Abhishek Sahu
QCOM NAND controller supports only one step size (512) so
nand-ecc-step-size DT property is redundant. This property
can be removed and ecc step size can be assigned with 512 value.

Acked-by: Miquel Raynal 
Signed-off-by: Abhishek Sahu 
---
* Changes from v3:

 1. Minor change in comment
(s/512 bytes of data in each step/512 bytes data steps)

* Changes from v2:

 NEW CHANGE

  1. Removed the custom logic and used the helper fuction.
 drivers/mtd/nand/raw/qcom_nandc.c | 11 ++-
 1 file changed, 2 insertions(+), 9 deletions(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c 
b/drivers/mtd/nand/raw/qcom_nandc.c
index 6a5519f..bf80a61 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -2325,15 +2325,8 @@ static int qcom_nand_host_setup(struct qcom_nand_host 
*host)
bool wide_bus;
int ecc_mode = 1;
 
-   /*
-* the controller requires each step consists of 512 bytes of data.
-* bail out if DT has populated a wrong step size.
-*/
-   if (ecc->size != NANDC_STEP_SIZE) {
-   dev_err(nandc->dev, "invalid ecc size\n");
-   return -EINVAL;
-   }
-
+   /* controller only supports 512 bytes data steps */
+   ecc->size = NANDC_STEP_SIZE;
wide_bus = chip->options & NAND_BUSWIDTH_16 ? true : false;
 
if (ecc->strength >= 8) {
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc.
is a member of Code Aurora Forum, hosted by The Linux Foundation



[PATCH v4 04/15] mtd: rawnand: qcom: remove dt property nand-ecc-step-size

2018-06-20 Thread Abhishek Sahu
QCOM NAND controller supports only one step size (512) so
nand-ecc-step-size DT property is redundant. This property
can be removed and ecc step size can be assigned with 512 value.

Acked-by: Miquel Raynal 
Signed-off-by: Abhishek Sahu 
---
* Changes from v3:

 1. Minor change in comment
(s/512 bytes of data in each step/512 bytes data steps)

* Changes from v2:

 NEW CHANGE

  1. Removed the custom logic and used the helper fuction.
 drivers/mtd/nand/raw/qcom_nandc.c | 11 ++-
 1 file changed, 2 insertions(+), 9 deletions(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c 
b/drivers/mtd/nand/raw/qcom_nandc.c
index 6a5519f..bf80a61 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -2325,15 +2325,8 @@ static int qcom_nand_host_setup(struct qcom_nand_host 
*host)
bool wide_bus;
int ecc_mode = 1;
 
-   /*
-* the controller requires each step consists of 512 bytes of data.
-* bail out if DT has populated a wrong step size.
-*/
-   if (ecc->size != NANDC_STEP_SIZE) {
-   dev_err(nandc->dev, "invalid ecc size\n");
-   return -EINVAL;
-   }
-
+   /* controller only supports 512 bytes data steps */
+   ecc->size = NANDC_STEP_SIZE;
wide_bus = chip->options & NAND_BUSWIDTH_16 ? true : false;
 
if (ecc->strength >= 8) {
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc.
is a member of Code Aurora Forum, hosted by The Linux Foundation



[PATCH v4 14/15] mtd: rawnand: qcom: erased page bitflips detection

2018-06-20 Thread Abhishek Sahu
NAND parts can have bitflips in an erased page due to the
process technology used. In this case, QCOM NAND controller
is not able to identify that page as an erased page.
Currently the driver calls nand_check_erased_ecc_chunk() for
identifying the erased pages but this won’t work always since the
checking is being with ECC engine returned data. In case of
bitflips, the ECC engine tries to correct the data and then it
generates the uncorrectable error. Now, this data is not equal to
original raw data. For erased CW identification, the raw data
should be read again from NAND device and this
nand_check_erased_ecc_chunk function() should be called for raw
data only.

Now following logic is being added to identify the erased
codeword bitflips.

1. In most of the cases, not all the codewords will have bitflips
   and only single CW will have bitflips. So, there is no need to
   read the complete raw page data. The NAND raw read can be
   scheduled for any CW in page. The NAND controller works on CW
   basis and it will update the status register after each CW read.
   Maintain the bitmask for the CW which generated the uncorrectable
   error.
2. Do raw read for all the CW's which generated the uncorrectable
   error.
3. Both DATA and OOB need to be checked for number of 0. The
   top-level API can be called with only data buf or OOB buf so use
   chip->databuf if data buf is null and chip->oob_poi if
   OOB buf is null for copying the raw bytes temporarily.
4. For each CW, check the number of 0 in cw_data and usable
   oob bytes, The bbm and spare (unused) bytes bit flip won’t
   affect the ECC so don’t check the number of bitflips in this area.

Signed-off-by: Abhishek Sahu 
---
* Changes from v3:

 1. Major changes in erased codeword detection for
raw read function

* Changes from v2:
  NONE

* Changes from v1:
 1. Minor change in commit message
 2. invalidate pagebuf if databuf or oob_poi is used

 drivers/mtd/nand/raw/qcom_nandc.c | 127 +++---
 1 file changed, 90 insertions(+), 37 deletions(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c 
b/drivers/mtd/nand/raw/qcom_nandc.c
index 160acdf..e34edf1 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -1656,20 +1656,95 @@ static int check_flash_errors(struct qcom_nand_host 
*host, int cw_cnt)
 }
 
 /*
+ * Bitflips can happen in erased codewords also so this function counts the
+ * number of 0 in each CW for which ECC engine returns the uncorrectable
+ * error. The page will be assumed as erased if this count is less than or
+ * equal to the ecc->strength for each CW.
+ *
+ * 1. Both DATA and OOB need to be checked for number of 0. The
+ *top-level API can be called with only data buf or OOB buf so use
+ *chip->data_buf if data buf is null and chip->oob_poi if oob buf
+ *is null for copying the raw bytes.
+ * 2. Perform raw read for all the CW which has uncorrectable errors.
+ * 3. For each CW, check the number of 0 in cw_data and usable OOB bytes.
+ *The BBM and spare bytes bit flip won’t affect the ECC so don’t check
+ *the number of bitflips in this area.
+ */
+static int
+check_for_erased_page(struct qcom_nand_host *host, u8 *data_buf,
+ u8 *oob_buf, unsigned long uncorrectable_cws,
+ int page, unsigned int max_bitflips)
+{
+   struct nand_chip *chip = >chip;
+   struct mtd_info *mtd = nand_to_mtd(chip);
+   struct nand_ecc_ctrl *ecc = >ecc;
+   int cw, data_size, oob_size, ret = 0;
+
+   if (!data_buf) {
+   data_buf = chip->data_buf;
+   chip->pagebuf = -1;
+   }
+
+   if (!oob_buf) {
+   oob_buf = chip->oob_poi;
+   chip->pagebuf = -1;
+   }
+
+   for (cw = 0; cw < ecc->steps && uncorrectable_cws; cw++) {
+   if (cw == (ecc->steps - 1)) {
+   data_size = ecc->size - ((ecc->steps - 1) * 4);
+   oob_size = (ecc->steps * 4) + host->ecc_bytes_hw;
+   } else {
+   data_size = host->cw_data;
+   oob_size = host->ecc_bytes_hw;
+   }
+
+   if (uncorrectable_cws & BIT(0)) {
+   ret = qcom_nandc_read_cw_raw(mtd, chip, data_buf,
+oob_buf, page, cw);
+   if (ret)
+   return ret;
+   /*
+* make sure it isn't an erased page reported
+* as not-erased by HW because of a few bitflips
+*/
+   ret = nand_check_erased_ecc_chunk(data_buf,
+   data_size, oob_buf + host->bbm_size,
+   oob_size, NULL,
+   0, ecc->strength);
+ 

[PATCH v4 14/15] mtd: rawnand: qcom: erased page bitflips detection

2018-06-20 Thread Abhishek Sahu
NAND parts can have bitflips in an erased page due to the
process technology used. In this case, QCOM NAND controller
is not able to identify that page as an erased page.
Currently the driver calls nand_check_erased_ecc_chunk() for
identifying the erased pages but this won’t work always since the
checking is being with ECC engine returned data. In case of
bitflips, the ECC engine tries to correct the data and then it
generates the uncorrectable error. Now, this data is not equal to
original raw data. For erased CW identification, the raw data
should be read again from NAND device and this
nand_check_erased_ecc_chunk function() should be called for raw
data only.

Now following logic is being added to identify the erased
codeword bitflips.

1. In most of the cases, not all the codewords will have bitflips
   and only single CW will have bitflips. So, there is no need to
   read the complete raw page data. The NAND raw read can be
   scheduled for any CW in page. The NAND controller works on CW
   basis and it will update the status register after each CW read.
   Maintain the bitmask for the CW which generated the uncorrectable
   error.
2. Do raw read for all the CW's which generated the uncorrectable
   error.
3. Both DATA and OOB need to be checked for number of 0. The
   top-level API can be called with only data buf or OOB buf so use
   chip->databuf if data buf is null and chip->oob_poi if
   OOB buf is null for copying the raw bytes temporarily.
4. For each CW, check the number of 0 in cw_data and usable
   oob bytes, The bbm and spare (unused) bytes bit flip won’t
   affect the ECC so don’t check the number of bitflips in this area.

Signed-off-by: Abhishek Sahu 
---
* Changes from v3:

 1. Major changes in erased codeword detection for
raw read function

* Changes from v2:
  NONE

* Changes from v1:
 1. Minor change in commit message
 2. invalidate pagebuf if databuf or oob_poi is used

 drivers/mtd/nand/raw/qcom_nandc.c | 127 +++---
 1 file changed, 90 insertions(+), 37 deletions(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c 
b/drivers/mtd/nand/raw/qcom_nandc.c
index 160acdf..e34edf1 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -1656,20 +1656,95 @@ static int check_flash_errors(struct qcom_nand_host 
*host, int cw_cnt)
 }
 
 /*
+ * Bitflips can happen in erased codewords also so this function counts the
+ * number of 0 in each CW for which ECC engine returns the uncorrectable
+ * error. The page will be assumed as erased if this count is less than or
+ * equal to the ecc->strength for each CW.
+ *
+ * 1. Both DATA and OOB need to be checked for number of 0. The
+ *top-level API can be called with only data buf or OOB buf so use
+ *chip->data_buf if data buf is null and chip->oob_poi if oob buf
+ *is null for copying the raw bytes.
+ * 2. Perform raw read for all the CW which has uncorrectable errors.
+ * 3. For each CW, check the number of 0 in cw_data and usable OOB bytes.
+ *The BBM and spare bytes bit flip won’t affect the ECC so don’t check
+ *the number of bitflips in this area.
+ */
+static int
+check_for_erased_page(struct qcom_nand_host *host, u8 *data_buf,
+ u8 *oob_buf, unsigned long uncorrectable_cws,
+ int page, unsigned int max_bitflips)
+{
+   struct nand_chip *chip = >chip;
+   struct mtd_info *mtd = nand_to_mtd(chip);
+   struct nand_ecc_ctrl *ecc = >ecc;
+   int cw, data_size, oob_size, ret = 0;
+
+   if (!data_buf) {
+   data_buf = chip->data_buf;
+   chip->pagebuf = -1;
+   }
+
+   if (!oob_buf) {
+   oob_buf = chip->oob_poi;
+   chip->pagebuf = -1;
+   }
+
+   for (cw = 0; cw < ecc->steps && uncorrectable_cws; cw++) {
+   if (cw == (ecc->steps - 1)) {
+   data_size = ecc->size - ((ecc->steps - 1) * 4);
+   oob_size = (ecc->steps * 4) + host->ecc_bytes_hw;
+   } else {
+   data_size = host->cw_data;
+   oob_size = host->ecc_bytes_hw;
+   }
+
+   if (uncorrectable_cws & BIT(0)) {
+   ret = qcom_nandc_read_cw_raw(mtd, chip, data_buf,
+oob_buf, page, cw);
+   if (ret)
+   return ret;
+   /*
+* make sure it isn't an erased page reported
+* as not-erased by HW because of a few bitflips
+*/
+   ret = nand_check_erased_ecc_chunk(data_buf,
+   data_size, oob_buf + host->bbm_size,
+   oob_size, NULL,
+   0, ecc->strength);
+ 

[PATCH] mtd: rawnand: fix return value check for bad block status

2018-06-13 Thread Abhishek Sahu
Positive return value from read_oob() is making false BAD
blocks. For some of the NAND controllers, OOB bytes will be
protected with ECC and read_oob() will return number of bitflips.
If there is any bitflip in ECC protected OOB bytes for BAD block
status page, then that block is getting treated as BAD.

Fixes: c120e75e0e7d ("mtd: nand: use read_oob() instead of cmdfunc() for bad 
block check")
Cc: 
Signed-off-by: Abhishek Sahu 
---
 drivers/mtd/nand/raw/nand_base.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index f28c3a5..4a73f73 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -440,7 +440,7 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs)
 
for (; page < page_end; page++) {
res = chip->ecc.read_oob(mtd, chip, page);
-   if (res)
+   if (res < 0)
return res;
 
bad = chip->oob_poi[chip->badblockpos];
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc.
is a member of Code Aurora Forum, hosted by The Linux Foundation



[PATCH] mtd: rawnand: fix return value check for bad block status

2018-06-13 Thread Abhishek Sahu
Positive return value from read_oob() is making false BAD
blocks. For some of the NAND controllers, OOB bytes will be
protected with ECC and read_oob() will return number of bitflips.
If there is any bitflip in ECC protected OOB bytes for BAD block
status page, then that block is getting treated as BAD.

Fixes: c120e75e0e7d ("mtd: nand: use read_oob() instead of cmdfunc() for bad 
block check")
Cc: 
Signed-off-by: Abhishek Sahu 
---
 drivers/mtd/nand/raw/nand_base.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index f28c3a5..4a73f73 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -440,7 +440,7 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs)
 
for (; page < page_end; page++) {
res = chip->ecc.read_oob(mtd, chip, page);
-   if (res)
+   if (res < 0)
return res;
 
bad = chip->oob_poi[chip->badblockpos];
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc.
is a member of Code Aurora Forum, hosted by The Linux Foundation



Re: [PATCH v3 13/16] mtd: rawnand: qcom: minor code reorganization for bad block check

2018-06-11 Thread Abhishek Sahu

On 2018-06-07 18:23, Miquel Raynal wrote:

Hi Abhishek,

On Mon, 28 May 2018 15:40:52 +0530, Abhishek Sahu
 wrote:


On 2018-05-28 12:33, Miquel Raynal wrote:
> Hi Abhishek,
> >> >>  /* implements ecc->read_page() */
>> >>  static int qcom_nandc_read_page(struct mtd_info *mtd, struct >> 
nand_chip *chip,
>> >>   uint8_t *buf, int oob_required, int page)
>> >> @@ -2118,6 +2083,7 @@ static int qcom_nandc_block_bad(struct mtd_info >> 
*mtd, loff_t ofs)
>> >>   struct nand_ecc_ctrl *ecc = >ecc;
>> >>   int page, ret, bbpos, bad = 0;
>> >>   u32 flash_status;
>> >> + u8 *bbm_bytes_buf = chip->data_buf;
>> >> >>  page = (int)(ofs >> chip->page_shift) & chip->pagemask;
>> >> >> @@ -2128,11 +2094,31 @@ static int qcom_nandc_block_bad(struct >> 
mtd_info *mtd, loff_t ofs)
>> >>* that contains the BBM
>> >>*/
>> >>   host->use_ecc = false;
>> >> + bbpos = mtd->writesize - host->cw_size * (ecc->steps - 1);
>> > > Are we sure there is no layout with only 1 step?
>> >>   All the layouts are such that, the BBM will come in
>>   first byte of spare area.
>> >>   For 4 bit ECC, the cw_size is 528 so for 2K page
>> >>2048 - 528 * 3 = 464
> > My question was more about small page NANDs. But I suppose it works
> too if ecc->steps == 1.
>
  Correct Miquel.





>> >>   So for last CW, the 464 is BBM (i.e 2048th byte) in
>>   full page.
>> >> > >> >>clear_bam_transaction(nandc);
>> >> - ret = copy_last_cw(host, page);
>> >> - if (ret)
>> >> + clear_read_regs(nandc);
>> >> +
>> >> + set_address(host, host->cw_size * (ecc->steps - 1), page);
>> >> + update_rw_regs(host, 1, true);
>> >> +
>> >> + /*
>> >> +  * The last codeword data will be copied from NAND device to NAND
>> >> +  * controller internal HW buffer. Copy only required BBM size bytes
>> >> +  * from this HW buffer to bbm_bytes_buf which is present at
>> >> +  * bbpos offset.
>> >> +  */
>> >> + nandc_set_read_loc(nandc, 0, bbpos, host->bbm_size, 1);
>> >> + config_nand_single_cw_page_read(nandc);
>> >> + read_data_dma(nandc, FLASH_BUF_ACC + bbpos, bbm_bytes_buf,
>> >> +   host->bbm_size, 0);
>> >> +
>> >> + ret = submit_descs(nandc);
>> >> + free_descs(nandc);
>> >> + if (ret) {
>> >> + dev_err(nandc->dev, "failed to copy bad block bytes\n");
>> >>   goto err;
>> >> + }
>> >> >>  flash_status = le32_to_cpu(nandc->reg_read_buf[0]);
>> >> >> @@ -2141,12 +2127,10 @@ static int qcom_nandc_block_bad(struct >> 
mtd_info *mtd, loff_t ofs)
>> >>   goto err;
>> >>   }
>> >> >> -bbpos = mtd->writesize - host->cw_size * (ecc->steps - 1);
>> >> -
>> >> - bad = nandc->data_buffer[bbpos] != 0xff;
>> >> + bad = bbm_bytes_buf[0] != 0xff;
>> > > This is suspect as it still points to the beginning of the data buffer.
>> > Can you please check you did not meant bbm_bytes_buf[bbpos]?
>> >
>>   The main thing here is
>>   nandc_set_read_loc(nandc, 0, bbpos, host->bbm_size, 1);
>> >>   After reading one complete CW from NAND, the data will be still
>>   in NAND HW buffer.
>> >>   The above register tells that we need to read data from
>>   bbpos of size host->bbm_size (which is 1 byte for 8 bus witdh
>>   and 2 byte for 16 bus width) in bbm_bytes_buf.
> > I see: idx 0 in bbm_bytes_buf is the data at offset bbpos. Then
> it's ok.
> >> >>   So bbm_bytes_buf[0] will contain the BBM first byte.
>>   and bbm_bytes_buf[1] will contain the BBM second byte.
>> >>   Regards,
>>   Abhishek
>> >> >> >> if (chip->options & NAND_BUSWIDTH_16)
>> >> - bad = bad || (nandc->data_buffer[bbpos + 1] != 0xff);
>> >> + bad = bad || (bbm_bytes_buf[1] != 0xff);
> > Sorry, my mistake, I did not see the above line.
> > However, technically, the BBM could be located in the first, second or
> last page of the block. You should check the three of them are 0xFF
> bef

Re: [PATCH v3 13/16] mtd: rawnand: qcom: minor code reorganization for bad block check

2018-06-11 Thread Abhishek Sahu

On 2018-06-07 18:23, Miquel Raynal wrote:

Hi Abhishek,

On Mon, 28 May 2018 15:40:52 +0530, Abhishek Sahu
 wrote:


On 2018-05-28 12:33, Miquel Raynal wrote:
> Hi Abhishek,
> >> >>  /* implements ecc->read_page() */
>> >>  static int qcom_nandc_read_page(struct mtd_info *mtd, struct >> 
nand_chip *chip,
>> >>   uint8_t *buf, int oob_required, int page)
>> >> @@ -2118,6 +2083,7 @@ static int qcom_nandc_block_bad(struct mtd_info >> 
*mtd, loff_t ofs)
>> >>   struct nand_ecc_ctrl *ecc = >ecc;
>> >>   int page, ret, bbpos, bad = 0;
>> >>   u32 flash_status;
>> >> + u8 *bbm_bytes_buf = chip->data_buf;
>> >> >>  page = (int)(ofs >> chip->page_shift) & chip->pagemask;
>> >> >> @@ -2128,11 +2094,31 @@ static int qcom_nandc_block_bad(struct >> 
mtd_info *mtd, loff_t ofs)
>> >>* that contains the BBM
>> >>*/
>> >>   host->use_ecc = false;
>> >> + bbpos = mtd->writesize - host->cw_size * (ecc->steps - 1);
>> > > Are we sure there is no layout with only 1 step?
>> >>   All the layouts are such that, the BBM will come in
>>   first byte of spare area.
>> >>   For 4 bit ECC, the cw_size is 528 so for 2K page
>> >>2048 - 528 * 3 = 464
> > My question was more about small page NANDs. But I suppose it works
> too if ecc->steps == 1.
>
  Correct Miquel.





>> >>   So for last CW, the 464 is BBM (i.e 2048th byte) in
>>   full page.
>> >> > >> >>clear_bam_transaction(nandc);
>> >> - ret = copy_last_cw(host, page);
>> >> - if (ret)
>> >> + clear_read_regs(nandc);
>> >> +
>> >> + set_address(host, host->cw_size * (ecc->steps - 1), page);
>> >> + update_rw_regs(host, 1, true);
>> >> +
>> >> + /*
>> >> +  * The last codeword data will be copied from NAND device to NAND
>> >> +  * controller internal HW buffer. Copy only required BBM size bytes
>> >> +  * from this HW buffer to bbm_bytes_buf which is present at
>> >> +  * bbpos offset.
>> >> +  */
>> >> + nandc_set_read_loc(nandc, 0, bbpos, host->bbm_size, 1);
>> >> + config_nand_single_cw_page_read(nandc);
>> >> + read_data_dma(nandc, FLASH_BUF_ACC + bbpos, bbm_bytes_buf,
>> >> +   host->bbm_size, 0);
>> >> +
>> >> + ret = submit_descs(nandc);
>> >> + free_descs(nandc);
>> >> + if (ret) {
>> >> + dev_err(nandc->dev, "failed to copy bad block bytes\n");
>> >>   goto err;
>> >> + }
>> >> >>  flash_status = le32_to_cpu(nandc->reg_read_buf[0]);
>> >> >> @@ -2141,12 +2127,10 @@ static int qcom_nandc_block_bad(struct >> 
mtd_info *mtd, loff_t ofs)
>> >>   goto err;
>> >>   }
>> >> >> -bbpos = mtd->writesize - host->cw_size * (ecc->steps - 1);
>> >> -
>> >> - bad = nandc->data_buffer[bbpos] != 0xff;
>> >> + bad = bbm_bytes_buf[0] != 0xff;
>> > > This is suspect as it still points to the beginning of the data buffer.
>> > Can you please check you did not meant bbm_bytes_buf[bbpos]?
>> >
>>   The main thing here is
>>   nandc_set_read_loc(nandc, 0, bbpos, host->bbm_size, 1);
>> >>   After reading one complete CW from NAND, the data will be still
>>   in NAND HW buffer.
>> >>   The above register tells that we need to read data from
>>   bbpos of size host->bbm_size (which is 1 byte for 8 bus witdh
>>   and 2 byte for 16 bus width) in bbm_bytes_buf.
> > I see: idx 0 in bbm_bytes_buf is the data at offset bbpos. Then
> it's ok.
> >> >>   So bbm_bytes_buf[0] will contain the BBM first byte.
>>   and bbm_bytes_buf[1] will contain the BBM second byte.
>> >>   Regards,
>>   Abhishek
>> >> >> >> if (chip->options & NAND_BUSWIDTH_16)
>> >> - bad = bad || (nandc->data_buffer[bbpos + 1] != 0xff);
>> >> + bad = bad || (bbm_bytes_buf[1] != 0xff);
> > Sorry, my mistake, I did not see the above line.
> > However, technically, the BBM could be located in the first, second or
> last page of the block. You should check the three of them are 0xFF
> bef

Re: [PATCH v3 15/16] mtd: rawnand: qcom: helper function for raw read

2018-06-11 Thread Abhishek Sahu

On 2018-06-07 18:13, Miquel Raynal wrote:

Hi Abhishek,

On Mon, 28 May 2018 13:04:45 +0530, Abhishek Sahu
 wrote:


On 2018-05-27 19:23, Miquel Raynal wrote:
> Hi Abhishek,
> > On Fri, 25 May 2018 17:51:43 +0530, Abhishek Sahu
>  wrote:
> >> This patch does minor code reorganization for raw reads.
>> Currently the raw read is required for complete page but for
>> subsequent patches related with erased codeword bit flips
>> detection, only few CW should be read. So, this patch adds
>> helper function and introduces the read CW bitmask which
>> specifies which CW reads are required in complete page.
>> >> Signed-off-by: Abhishek Sahu 
>> ---


 


>> +  for (i = start_step; i < last_step; i++) {
> > This comment applies for both patches 15 and 16:
> > I would really prefer having a qcom_nandc_read_cw_raw() that reads only
> one CW. From qcom_nandc_read_page_raw() you would loop over all the CW
> calling qcom_nandc_read_cw_raw() helper (it's raw reads, we don't care
> about performances)

  Doing that way will degrade performances hugely.

  Currently once we formed the descriptor, the DMA will take care
  of complete page data transfer from NAND device to buffer and will
  generate single interrupt.

  Now it will form one CW descriptor and wait for it to be finished.
  In background, the data transfer from NAND device will be also
  split and for every CW, it will give the PAGE_READ command again,
  which is again time consuming.

  Data transfer degradation is ok but it will increase CPU time
  and number of interrupts which will impact other peripherals
  performance that time.

  Most of the NAND parts has 4K page size i.e 8 CWs.

> and from ->read_page_raw() you would check
> CW with uncorrectable errors for being blank with that helper. You
> would avoid the not-so-nice logic where you read all the CW between the
> first bad one and the last bad one.
>
  The reading b/w first CW and last CW is only from NAND device to 
NAND

  HW buffers. The NAND controller has 2 HW buffers which is used to
  optimize the traffic throughput between the NAND device and
  system memory,in both directions. Each buffer is 544B in size: 512B
  for data + 32B spare bytes. Throughput optimization is achieved by
  executing internal data transfers (i.e. between NANDc buffers and
  system memory) simultaneously with NAND device operations.

  Making separate function won't help in improving performance for
  this case either since once every thing is set for reading page
  (descriptor formation, issue the PAGE_READ, Data transfer from
  Flash array to data register in NAND device), the read time from
  device to NAND HW buffer is very less. Again, we did optimization
  in which the copying from NAND HW buffer to actual buffer is being
  done only for those CW's only.

  Again, in this case CPU time will be more.




I understand the point and thanks for detailing it. But raw access
happen either during debug (we don't care about CPU time) or when there
is an uncorrectable error, which is very unlikely to happen very often
when using eg. UBI/UBIFS. So I'm still convinced it is better to have a
_simple_ and straightforward code for this path than something way
harder to understand and much faster.

You can add a comment to explain what would be the fastest way and
why though.



 Thanks Miquel. I will do the changes to make function for
 single codeword raw read.

 Regards,
 Abhishek


Re: [PATCH v3 15/16] mtd: rawnand: qcom: helper function for raw read

2018-06-11 Thread Abhishek Sahu

On 2018-06-07 18:13, Miquel Raynal wrote:

Hi Abhishek,

On Mon, 28 May 2018 13:04:45 +0530, Abhishek Sahu
 wrote:


On 2018-05-27 19:23, Miquel Raynal wrote:
> Hi Abhishek,
> > On Fri, 25 May 2018 17:51:43 +0530, Abhishek Sahu
>  wrote:
> >> This patch does minor code reorganization for raw reads.
>> Currently the raw read is required for complete page but for
>> subsequent patches related with erased codeword bit flips
>> detection, only few CW should be read. So, this patch adds
>> helper function and introduces the read CW bitmask which
>> specifies which CW reads are required in complete page.
>> >> Signed-off-by: Abhishek Sahu 
>> ---


 


>> +  for (i = start_step; i < last_step; i++) {
> > This comment applies for both patches 15 and 16:
> > I would really prefer having a qcom_nandc_read_cw_raw() that reads only
> one CW. From qcom_nandc_read_page_raw() you would loop over all the CW
> calling qcom_nandc_read_cw_raw() helper (it's raw reads, we don't care
> about performances)

  Doing that way will degrade performances hugely.

  Currently once we formed the descriptor, the DMA will take care
  of complete page data transfer from NAND device to buffer and will
  generate single interrupt.

  Now it will form one CW descriptor and wait for it to be finished.
  In background, the data transfer from NAND device will be also
  split and for every CW, it will give the PAGE_READ command again,
  which is again time consuming.

  Data transfer degradation is ok but it will increase CPU time
  and number of interrupts which will impact other peripherals
  performance that time.

  Most of the NAND parts has 4K page size i.e 8 CWs.

> and from ->read_page_raw() you would check
> CW with uncorrectable errors for being blank with that helper. You
> would avoid the not-so-nice logic where you read all the CW between the
> first bad one and the last bad one.
>
  The reading b/w first CW and last CW is only from NAND device to 
NAND

  HW buffers. The NAND controller has 2 HW buffers which is used to
  optimize the traffic throughput between the NAND device and
  system memory,in both directions. Each buffer is 544B in size: 512B
  for data + 32B spare bytes. Throughput optimization is achieved by
  executing internal data transfers (i.e. between NANDc buffers and
  system memory) simultaneously with NAND device operations.

  Making separate function won't help in improving performance for
  this case either since once every thing is set for reading page
  (descriptor formation, issue the PAGE_READ, Data transfer from
  Flash array to data register in NAND device), the read time from
  device to NAND HW buffer is very less. Again, we did optimization
  in which the copying from NAND HW buffer to actual buffer is being
  done only for those CW's only.

  Again, in this case CPU time will be more.




I understand the point and thanks for detailing it. But raw access
happen either during debug (we don't care about CPU time) or when there
is an uncorrectable error, which is very unlikely to happen very often
when using eg. UBI/UBIFS. So I'm still convinced it is better to have a
_simple_ and straightforward code for this path than something way
harder to understand and much faster.

You can add a comment to explain what would be the fastest way and
why though.



 Thanks Miquel. I will do the changes to make function for
 single codeword raw read.

 Regards,
 Abhishek


Re: [PATCH v3 01/16] mtd: rawnand: helper function for setting up ECC configuration

2018-06-11 Thread Abhishek Sahu

On 2018-06-07 18:07, Miquel Raynal wrote:

Hi Abhishek,

On Mon, 28 May 2018 11:16:29 +0530, Abhishek Sahu
 wrote:


On 2018-05-26 14:12, Miquel Raynal wrote:
> Hi Abhishek,
> > On Fri, 25 May 2018 17:51:29 +0530, Abhishek Sahu
>  wrote:
> >> commit 2c8f8afa7f92 ("mtd: nand: add generic helpers to check,
>> match, maximize ECC settings") provides generic helpers which
>> drivers can use for setting up ECC parameters.
>> >> Since same board can have different ECC strength nand chips so
>> following is the logic for setting up ECC strength and ECC step
>> size, which can be used by most of the drivers.
>> >> 1. If both ECC step size and ECC strength are already set
>>(usually by DT) then just check whether this setting
>>is supported by NAND controller.
>> 2. If NAND_ECC_MAXIMIZE is set, then select maximum ECC strength
>>supported by NAND controller.
>> 3. Otherwise, try to match the ECC step size and ECC strength closest
>>to the chip's requirement. If available OOB size can't fit the chip
>>requirement then select maximum ECC strength which can be fit with
>>available OOB size.
>> >> This patch introduces nand_ecc_choose_conf function which calls the
>> required helper functions for the above logic. The drivers can use
>> this single function instead of calling the 3 helper functions
>> individually.
>> >> CC: Masahiro Yamada 
>> Signed-off-by: Abhishek Sahu 
>> ---
>> * Changes from v2:
>> >>   1. Renamed function to nand_ecc_choose_conf.
>>   2. Minor code reorganization to remove warning and 2 function calls
>>  for nand_maximize_ecc.
>> >> * Changes from v1:
>>   NEW PATCH
>> >>  drivers/mtd/nand/raw/nand_base.c | 42 >> 

>>  drivers/mtd/nand/raw/nand_base.c | 31 +++
>>  include/linux/mtd/rawnand.h  |  3 +++
>>  2 files changed, 34 insertions(+)
>> >> diff --git a/drivers/mtd/nand/raw/nand_base.c >> 
b/drivers/mtd/nand/raw/nand_base.c
>> index 72f3a89..e52019d 100644
>> --- a/drivers/mtd/nand/raw/nand_base.c
>> +++ b/drivers/mtd/nand/raw/nand_base.c
>> @@ -6249,6 +6249,37 @@ int nand_maximize_ecc(struct nand_chip *chip,
>>  }
>>  EXPORT_SYMBOL_GPL(nand_maximize_ecc);
>> >> +/**
>> + * nand_ecc_choose_conf - Set the ECC strength and ECC step size
>> + * @chip: nand chip info structure
>> + * @caps: ECC engine caps info structure
>> + * @oobavail: OOB size that the ECC engine can use
>> + *
>> + * Choose the ECC configuration according to following logic
>> + *
>> + * 1. If both ECC step size and ECC strength are already set (usually >> by 
DT)
>> + *then check if it is supported by this controller.
>> + * 2. If NAND_ECC_MAXIMIZE is set, then select maximum ECC strength.
>> + * 3. Otherwise, try to match the ECC step size and ECC strength >> closest
>> + *to the chip's requirement. If available OOB size can't fit the >> chip
>> + *requirement then fallback to the maximum ECC step size and ECC >> 
strength.
>> + *
>> + * On success, the chosen ECC settings are set.
>> + */
>> +int nand_ecc_choose_conf(struct nand_chip *chip,
>> +   const struct nand_ecc_caps *caps, int oobavail)
>> +{
>> +  if (chip->ecc.size && chip->ecc.strength)
>> +  return nand_check_ecc_caps(chip, caps, oobavail);
>> +
>> +  if (!(chip->ecc.options & NAND_ECC_MAXIMIZE) &&
>> +  !nand_match_ecc_req(chip, caps, oobavail))
>> +  return 0;
>> +
>> +  return nand_maximize_ecc(chip, caps, oobavail);
> > I personally don't mind if nand_maximize_ecc() is called twice in
> the function if it clarifies the logic. Maybe the following will be
> more clear for the user?

  Thanks Miquel.
  Both the implementations are fine.
  The above implementation (which was in Denali NAND driver) code was 
also

  clear. We can go for any of these implementation.

  Shall I update this ?


Yes, please :)



 Thanks Miquel for confirming.
 I will update accordingly.

 Also, one more question.

 Shall I make other functions (nand_check_ecc_caps, nand_maximize_ecc
 and nand_match_ecc_req) static.  Since currently,
 Denali NAND driver was only using these functions.

 And Now, this nand_ecc_choose_conf will be help
 in all the cases.

 For nand_check_ecc_caps: call nand_ecc_choose_conf with
   chip->ecc.size && chip->ecc.strength

 For nand_maximize_ecc: call nand_ecc_choose_conf with
  

Re: [PATCH v3 01/16] mtd: rawnand: helper function for setting up ECC configuration

2018-06-11 Thread Abhishek Sahu

On 2018-06-07 18:07, Miquel Raynal wrote:

Hi Abhishek,

On Mon, 28 May 2018 11:16:29 +0530, Abhishek Sahu
 wrote:


On 2018-05-26 14:12, Miquel Raynal wrote:
> Hi Abhishek,
> > On Fri, 25 May 2018 17:51:29 +0530, Abhishek Sahu
>  wrote:
> >> commit 2c8f8afa7f92 ("mtd: nand: add generic helpers to check,
>> match, maximize ECC settings") provides generic helpers which
>> drivers can use for setting up ECC parameters.
>> >> Since same board can have different ECC strength nand chips so
>> following is the logic for setting up ECC strength and ECC step
>> size, which can be used by most of the drivers.
>> >> 1. If both ECC step size and ECC strength are already set
>>(usually by DT) then just check whether this setting
>>is supported by NAND controller.
>> 2. If NAND_ECC_MAXIMIZE is set, then select maximum ECC strength
>>supported by NAND controller.
>> 3. Otherwise, try to match the ECC step size and ECC strength closest
>>to the chip's requirement. If available OOB size can't fit the chip
>>requirement then select maximum ECC strength which can be fit with
>>available OOB size.
>> >> This patch introduces nand_ecc_choose_conf function which calls the
>> required helper functions for the above logic. The drivers can use
>> this single function instead of calling the 3 helper functions
>> individually.
>> >> CC: Masahiro Yamada 
>> Signed-off-by: Abhishek Sahu 
>> ---
>> * Changes from v2:
>> >>   1. Renamed function to nand_ecc_choose_conf.
>>   2. Minor code reorganization to remove warning and 2 function calls
>>  for nand_maximize_ecc.
>> >> * Changes from v1:
>>   NEW PATCH
>> >>  drivers/mtd/nand/raw/nand_base.c | 42 >> 

>>  drivers/mtd/nand/raw/nand_base.c | 31 +++
>>  include/linux/mtd/rawnand.h  |  3 +++
>>  2 files changed, 34 insertions(+)
>> >> diff --git a/drivers/mtd/nand/raw/nand_base.c >> 
b/drivers/mtd/nand/raw/nand_base.c
>> index 72f3a89..e52019d 100644
>> --- a/drivers/mtd/nand/raw/nand_base.c
>> +++ b/drivers/mtd/nand/raw/nand_base.c
>> @@ -6249,6 +6249,37 @@ int nand_maximize_ecc(struct nand_chip *chip,
>>  }
>>  EXPORT_SYMBOL_GPL(nand_maximize_ecc);
>> >> +/**
>> + * nand_ecc_choose_conf - Set the ECC strength and ECC step size
>> + * @chip: nand chip info structure
>> + * @caps: ECC engine caps info structure
>> + * @oobavail: OOB size that the ECC engine can use
>> + *
>> + * Choose the ECC configuration according to following logic
>> + *
>> + * 1. If both ECC step size and ECC strength are already set (usually >> by 
DT)
>> + *then check if it is supported by this controller.
>> + * 2. If NAND_ECC_MAXIMIZE is set, then select maximum ECC strength.
>> + * 3. Otherwise, try to match the ECC step size and ECC strength >> closest
>> + *to the chip's requirement. If available OOB size can't fit the >> chip
>> + *requirement then fallback to the maximum ECC step size and ECC >> 
strength.
>> + *
>> + * On success, the chosen ECC settings are set.
>> + */
>> +int nand_ecc_choose_conf(struct nand_chip *chip,
>> +   const struct nand_ecc_caps *caps, int oobavail)
>> +{
>> +  if (chip->ecc.size && chip->ecc.strength)
>> +  return nand_check_ecc_caps(chip, caps, oobavail);
>> +
>> +  if (!(chip->ecc.options & NAND_ECC_MAXIMIZE) &&
>> +  !nand_match_ecc_req(chip, caps, oobavail))
>> +  return 0;
>> +
>> +  return nand_maximize_ecc(chip, caps, oobavail);
> > I personally don't mind if nand_maximize_ecc() is called twice in
> the function if it clarifies the logic. Maybe the following will be
> more clear for the user?

  Thanks Miquel.
  Both the implementations are fine.
  The above implementation (which was in Denali NAND driver) code was 
also

  clear. We can go for any of these implementation.

  Shall I update this ?


Yes, please :)



 Thanks Miquel for confirming.
 I will update accordingly.

 Also, one more question.

 Shall I make other functions (nand_check_ecc_caps, nand_maximize_ecc
 and nand_match_ecc_req) static.  Since currently,
 Denali NAND driver was only using these functions.

 And Now, this nand_ecc_choose_conf will be help
 in all the cases.

 For nand_check_ecc_caps: call nand_ecc_choose_conf with
   chip->ecc.size && chip->ecc.strength

 For nand_maximize_ecc: call nand_ecc_choose_conf with
  

Re: [PATCH v3 01/16] mtd: rawnand: helper function for setting up ECC configuration

2018-05-30 Thread Abhishek Sahu

On 2018-05-30 13:08, Masahiro Yamada wrote:

2018-05-30 15:21 GMT+09:00 Abhishek Sahu :

On 2018-05-30 05:58, Masahiro Yamada wrote:


Hi.

2018-05-30 4:30 GMT+09:00 Boris Brezillon 
:


On Sat, 26 May 2018 10:42:47 +0200
Miquel Raynal  wrote:


Hi Abhishek,

On Fri, 25 May 2018 17:51:29 +0530, Abhishek Sahu
 wrote:

> commit 2c8f8afa7f92 ("mtd: nand: add generic helpers to check,
> match, maximize ECC settings") provides generic helpers which
> drivers can use for setting up ECC parameters.
>
> Since same board can have different ECC strength nand chips so
> following is the logic for setting up ECC strength and ECC step
> size, which can be used by most of the drivers.
>
> 1. If both ECC step size and ECC strength are already set
>(usually by DT) then just check whether this setting
>is supported by NAND controller.
> 2. If NAND_ECC_MAXIMIZE is set, then select maximum ECC strength
>supported by NAND controller.
> 3. Otherwise, try to match the ECC step size and ECC strength closest
>to the chip's requirement. If available OOB size can't fit the chip
>requirement then select maximum ECC strength which can be fit with
>available OOB size.
>
> This patch introduces nand_ecc_choose_conf function which calls the
> required helper functions for the above logic. The drivers can use
> this single function instead of calling the 3 helper functions
> individually.
>
> CC: Masahiro Yamada 
> Signed-off-by: Abhishek Sahu 
> ---
> * Changes from v2:
>
>   1. Renamed function to nand_ecc_choose_conf.
>   2. Minor code reorganization to remove warning and 2 function calls
>  for nand_maximize_ecc.
>
> * Changes from v1:
>   NEW PATCH
>
>  drivers/mtd/nand/raw/nand_base.c | 42
> 
>  drivers/mtd/nand/raw/nand_base.c | 31 +++
>  include/linux/mtd/rawnand.h  |  3 +++
>  2 files changed, 34 insertions(+)
>
> diff --git a/drivers/mtd/nand/raw/nand_base.c
> b/drivers/mtd/nand/raw/nand_base.c
> index 72f3a89..e52019d 100644
> --- a/drivers/mtd/nand/raw/nand_base.c
> +++ b/drivers/mtd/nand/raw/nand_base.c
> @@ -6249,6 +6249,37 @@ int nand_maximize_ecc(struct nand_chip *chip,
>  }
>  EXPORT_SYMBOL_GPL(nand_maximize_ecc);
>
> +/**
> + * nand_ecc_choose_conf - Set the ECC strength and ECC step size
> + * @chip: nand chip info structure
> + * @caps: ECC engine caps info structure
> + * @oobavail: OOB size that the ECC engine can use
> + *
> + * Choose the ECC configuration according to following logic
> + *
> + * 1. If both ECC step size and ECC strength are already set (usually
> by DT)
> + *then check if it is supported by this controller.
> + * 2. If NAND_ECC_MAXIMIZE is set, then select maximum ECC strength.
> + * 3. Otherwise, try to match the ECC step size and ECC strength
> closest
> + *to the chip's requirement. If available OOB size can't fit the
> chip
> + *requirement then fallback to the maximum ECC step size and ECC
> strength.
> + *
> + * On success, the chosen ECC settings are set.
> + */
> +int nand_ecc_choose_conf(struct nand_chip *chip,
> +const struct nand_ecc_caps *caps, int oobavail)
> +{
> +   if (chip->ecc.size && chip->ecc.strength)
> +   return nand_check_ecc_caps(chip, caps, oobavail);
> +
> +   if (!(chip->ecc.options & NAND_ECC_MAXIMIZE) &&
> +   !nand_match_ecc_req(chip, caps, oobavail))
> +   return 0;
> +
> +   return nand_maximize_ecc(chip, caps, oobavail);

I personally don't mind if nand_maximize_ecc() is called twice in
the function if it clarifies the logic. Maybe the following will be
more clear for the user?

  if (chip->ecc.size && chip->ecc.strength)
  return nand_check_ecc_caps(chip, caps, oobavail);

  if (chip->ecc.options & NAND_ECC_MAXIMIZE)
  return nand_maximize_ecc(chip, caps, oobavail);

  if (!nand_match_ecc_req(chip, caps, oobavail))
  return 0;

  return nand_maximize_ecc(chip, caps, oobavail);



I personally don't mind, and it seems Masahiro wanted to keep the 
logic

he had used in the denali driver.



Also, I'm not sure we should just error out when 
nand_check_ecc_caps()

fails. What about something more robust, like:

  int ret;

  if (chip->ecc.size && chip->ecc.strength) {
  ret = nand_check_ecc_caps(chip, caps, oobavail);
  if (ret)
  goto maximize_ecc;



Nope. When someone asked for a specific ECC config by passing the
nand-ecc-xxx props we should apply it or return an erro if it's not
supported. People passing those props should now what the ECC engine
supports and pick on

Re: [PATCH v3 01/16] mtd: rawnand: helper function for setting up ECC configuration

2018-05-30 Thread Abhishek Sahu

On 2018-05-30 13:08, Masahiro Yamada wrote:

2018-05-30 15:21 GMT+09:00 Abhishek Sahu :

On 2018-05-30 05:58, Masahiro Yamada wrote:


Hi.

2018-05-30 4:30 GMT+09:00 Boris Brezillon 
:


On Sat, 26 May 2018 10:42:47 +0200
Miquel Raynal  wrote:


Hi Abhishek,

On Fri, 25 May 2018 17:51:29 +0530, Abhishek Sahu
 wrote:

> commit 2c8f8afa7f92 ("mtd: nand: add generic helpers to check,
> match, maximize ECC settings") provides generic helpers which
> drivers can use for setting up ECC parameters.
>
> Since same board can have different ECC strength nand chips so
> following is the logic for setting up ECC strength and ECC step
> size, which can be used by most of the drivers.
>
> 1. If both ECC step size and ECC strength are already set
>(usually by DT) then just check whether this setting
>is supported by NAND controller.
> 2. If NAND_ECC_MAXIMIZE is set, then select maximum ECC strength
>supported by NAND controller.
> 3. Otherwise, try to match the ECC step size and ECC strength closest
>to the chip's requirement. If available OOB size can't fit the chip
>requirement then select maximum ECC strength which can be fit with
>available OOB size.
>
> This patch introduces nand_ecc_choose_conf function which calls the
> required helper functions for the above logic. The drivers can use
> this single function instead of calling the 3 helper functions
> individually.
>
> CC: Masahiro Yamada 
> Signed-off-by: Abhishek Sahu 
> ---
> * Changes from v2:
>
>   1. Renamed function to nand_ecc_choose_conf.
>   2. Minor code reorganization to remove warning and 2 function calls
>  for nand_maximize_ecc.
>
> * Changes from v1:
>   NEW PATCH
>
>  drivers/mtd/nand/raw/nand_base.c | 42
> 
>  drivers/mtd/nand/raw/nand_base.c | 31 +++
>  include/linux/mtd/rawnand.h  |  3 +++
>  2 files changed, 34 insertions(+)
>
> diff --git a/drivers/mtd/nand/raw/nand_base.c
> b/drivers/mtd/nand/raw/nand_base.c
> index 72f3a89..e52019d 100644
> --- a/drivers/mtd/nand/raw/nand_base.c
> +++ b/drivers/mtd/nand/raw/nand_base.c
> @@ -6249,6 +6249,37 @@ int nand_maximize_ecc(struct nand_chip *chip,
>  }
>  EXPORT_SYMBOL_GPL(nand_maximize_ecc);
>
> +/**
> + * nand_ecc_choose_conf - Set the ECC strength and ECC step size
> + * @chip: nand chip info structure
> + * @caps: ECC engine caps info structure
> + * @oobavail: OOB size that the ECC engine can use
> + *
> + * Choose the ECC configuration according to following logic
> + *
> + * 1. If both ECC step size and ECC strength are already set (usually
> by DT)
> + *then check if it is supported by this controller.
> + * 2. If NAND_ECC_MAXIMIZE is set, then select maximum ECC strength.
> + * 3. Otherwise, try to match the ECC step size and ECC strength
> closest
> + *to the chip's requirement. If available OOB size can't fit the
> chip
> + *requirement then fallback to the maximum ECC step size and ECC
> strength.
> + *
> + * On success, the chosen ECC settings are set.
> + */
> +int nand_ecc_choose_conf(struct nand_chip *chip,
> +const struct nand_ecc_caps *caps, int oobavail)
> +{
> +   if (chip->ecc.size && chip->ecc.strength)
> +   return nand_check_ecc_caps(chip, caps, oobavail);
> +
> +   if (!(chip->ecc.options & NAND_ECC_MAXIMIZE) &&
> +   !nand_match_ecc_req(chip, caps, oobavail))
> +   return 0;
> +
> +   return nand_maximize_ecc(chip, caps, oobavail);

I personally don't mind if nand_maximize_ecc() is called twice in
the function if it clarifies the logic. Maybe the following will be
more clear for the user?

  if (chip->ecc.size && chip->ecc.strength)
  return nand_check_ecc_caps(chip, caps, oobavail);

  if (chip->ecc.options & NAND_ECC_MAXIMIZE)
  return nand_maximize_ecc(chip, caps, oobavail);

  if (!nand_match_ecc_req(chip, caps, oobavail))
  return 0;

  return nand_maximize_ecc(chip, caps, oobavail);



I personally don't mind, and it seems Masahiro wanted to keep the 
logic

he had used in the denali driver.



Also, I'm not sure we should just error out when 
nand_check_ecc_caps()

fails. What about something more robust, like:

  int ret;

  if (chip->ecc.size && chip->ecc.strength) {
  ret = nand_check_ecc_caps(chip, caps, oobavail);
  if (ret)
  goto maximize_ecc;



Nope. When someone asked for a specific ECC config by passing the
nand-ecc-xxx props we should apply it or return an erro if it's not
supported. People passing those props should now what the ECC engine
supports and pick on

Re: [PATCH v3 01/16] mtd: rawnand: helper function for setting up ECC configuration

2018-05-30 Thread Abhishek Sahu

On 2018-05-30 05:58, Masahiro Yamada wrote:

Hi.

2018-05-30 4:30 GMT+09:00 Boris Brezillon 
:

On Sat, 26 May 2018 10:42:47 +0200
Miquel Raynal  wrote:


Hi Abhishek,

On Fri, 25 May 2018 17:51:29 +0530, Abhishek Sahu
 wrote:

> commit 2c8f8afa7f92 ("mtd: nand: add generic helpers to check,
> match, maximize ECC settings") provides generic helpers which
> drivers can use for setting up ECC parameters.
>
> Since same board can have different ECC strength nand chips so
> following is the logic for setting up ECC strength and ECC step
> size, which can be used by most of the drivers.
>
> 1. If both ECC step size and ECC strength are already set
>(usually by DT) then just check whether this setting
>is supported by NAND controller.
> 2. If NAND_ECC_MAXIMIZE is set, then select maximum ECC strength
>supported by NAND controller.
> 3. Otherwise, try to match the ECC step size and ECC strength closest
>to the chip's requirement. If available OOB size can't fit the chip
>requirement then select maximum ECC strength which can be fit with
>available OOB size.
>
> This patch introduces nand_ecc_choose_conf function which calls the
> required helper functions for the above logic. The drivers can use
> this single function instead of calling the 3 helper functions
> individually.
>
> CC: Masahiro Yamada 
> Signed-off-by: Abhishek Sahu 
> ---
> * Changes from v2:
>
>   1. Renamed function to nand_ecc_choose_conf.
>   2. Minor code reorganization to remove warning and 2 function calls
>  for nand_maximize_ecc.
>
> * Changes from v1:
>   NEW PATCH
>
>  drivers/mtd/nand/raw/nand_base.c | 42 

>  drivers/mtd/nand/raw/nand_base.c | 31 +++
>  include/linux/mtd/rawnand.h  |  3 +++
>  2 files changed, 34 insertions(+)
>
> diff --git a/drivers/mtd/nand/raw/nand_base.c 
b/drivers/mtd/nand/raw/nand_base.c
> index 72f3a89..e52019d 100644
> --- a/drivers/mtd/nand/raw/nand_base.c
> +++ b/drivers/mtd/nand/raw/nand_base.c
> @@ -6249,6 +6249,37 @@ int nand_maximize_ecc(struct nand_chip *chip,
>  }
>  EXPORT_SYMBOL_GPL(nand_maximize_ecc);
>
> +/**
> + * nand_ecc_choose_conf - Set the ECC strength and ECC step size
> + * @chip: nand chip info structure
> + * @caps: ECC engine caps info structure
> + * @oobavail: OOB size that the ECC engine can use
> + *
> + * Choose the ECC configuration according to following logic
> + *
> + * 1. If both ECC step size and ECC strength are already set (usually by DT)
> + *then check if it is supported by this controller.
> + * 2. If NAND_ECC_MAXIMIZE is set, then select maximum ECC strength.
> + * 3. Otherwise, try to match the ECC step size and ECC strength closest
> + *to the chip's requirement. If available OOB size can't fit the chip
> + *requirement then fallback to the maximum ECC step size and ECC 
strength.
> + *
> + * On success, the chosen ECC settings are set.
> + */
> +int nand_ecc_choose_conf(struct nand_chip *chip,
> +const struct nand_ecc_caps *caps, int oobavail)
> +{
> +   if (chip->ecc.size && chip->ecc.strength)
> +   return nand_check_ecc_caps(chip, caps, oobavail);
> +
> +   if (!(chip->ecc.options & NAND_ECC_MAXIMIZE) &&
> +   !nand_match_ecc_req(chip, caps, oobavail))
> +   return 0;
> +
> +   return nand_maximize_ecc(chip, caps, oobavail);

I personally don't mind if nand_maximize_ecc() is called twice in
the function if it clarifies the logic. Maybe the following will be
more clear for the user?

  if (chip->ecc.size && chip->ecc.strength)
  return nand_check_ecc_caps(chip, caps, oobavail);

  if (chip->ecc.options & NAND_ECC_MAXIMIZE)
  return nand_maximize_ecc(chip, caps, oobavail);

  if (!nand_match_ecc_req(chip, caps, oobavail))
  return 0;

  return nand_maximize_ecc(chip, caps, oobavail);


I personally don't mind, and it seems Masahiro wanted to keep the 
logic

he had used in the denali driver.



Also, I'm not sure we should just error out when 
nand_check_ecc_caps()

fails. What about something more robust, like:

  int ret;

  if (chip->ecc.size && chip->ecc.strength) {
  ret = nand_check_ecc_caps(chip, caps, oobavail);
  if (ret)
  goto maximize_ecc;


Nope. When someone asked for a specific ECC config by passing the
nand-ecc-xxx props we should apply it or return an erro if it's not
supported. People passing those props should now what the ECC engine
supports and pick one valid values.



  return 0;
  }

  if (chip->ecc.options & NAND_ECC_MAXIMIZE)
  goto maximize_ecc;

  

Re: [PATCH v3 01/16] mtd: rawnand: helper function for setting up ECC configuration

2018-05-30 Thread Abhishek Sahu

On 2018-05-30 05:58, Masahiro Yamada wrote:

Hi.

2018-05-30 4:30 GMT+09:00 Boris Brezillon 
:

On Sat, 26 May 2018 10:42:47 +0200
Miquel Raynal  wrote:


Hi Abhishek,

On Fri, 25 May 2018 17:51:29 +0530, Abhishek Sahu
 wrote:

> commit 2c8f8afa7f92 ("mtd: nand: add generic helpers to check,
> match, maximize ECC settings") provides generic helpers which
> drivers can use for setting up ECC parameters.
>
> Since same board can have different ECC strength nand chips so
> following is the logic for setting up ECC strength and ECC step
> size, which can be used by most of the drivers.
>
> 1. If both ECC step size and ECC strength are already set
>(usually by DT) then just check whether this setting
>is supported by NAND controller.
> 2. If NAND_ECC_MAXIMIZE is set, then select maximum ECC strength
>supported by NAND controller.
> 3. Otherwise, try to match the ECC step size and ECC strength closest
>to the chip's requirement. If available OOB size can't fit the chip
>requirement then select maximum ECC strength which can be fit with
>available OOB size.
>
> This patch introduces nand_ecc_choose_conf function which calls the
> required helper functions for the above logic. The drivers can use
> this single function instead of calling the 3 helper functions
> individually.
>
> CC: Masahiro Yamada 
> Signed-off-by: Abhishek Sahu 
> ---
> * Changes from v2:
>
>   1. Renamed function to nand_ecc_choose_conf.
>   2. Minor code reorganization to remove warning and 2 function calls
>  for nand_maximize_ecc.
>
> * Changes from v1:
>   NEW PATCH
>
>  drivers/mtd/nand/raw/nand_base.c | 42 

>  drivers/mtd/nand/raw/nand_base.c | 31 +++
>  include/linux/mtd/rawnand.h  |  3 +++
>  2 files changed, 34 insertions(+)
>
> diff --git a/drivers/mtd/nand/raw/nand_base.c 
b/drivers/mtd/nand/raw/nand_base.c
> index 72f3a89..e52019d 100644
> --- a/drivers/mtd/nand/raw/nand_base.c
> +++ b/drivers/mtd/nand/raw/nand_base.c
> @@ -6249,6 +6249,37 @@ int nand_maximize_ecc(struct nand_chip *chip,
>  }
>  EXPORT_SYMBOL_GPL(nand_maximize_ecc);
>
> +/**
> + * nand_ecc_choose_conf - Set the ECC strength and ECC step size
> + * @chip: nand chip info structure
> + * @caps: ECC engine caps info structure
> + * @oobavail: OOB size that the ECC engine can use
> + *
> + * Choose the ECC configuration according to following logic
> + *
> + * 1. If both ECC step size and ECC strength are already set (usually by DT)
> + *then check if it is supported by this controller.
> + * 2. If NAND_ECC_MAXIMIZE is set, then select maximum ECC strength.
> + * 3. Otherwise, try to match the ECC step size and ECC strength closest
> + *to the chip's requirement. If available OOB size can't fit the chip
> + *requirement then fallback to the maximum ECC step size and ECC 
strength.
> + *
> + * On success, the chosen ECC settings are set.
> + */
> +int nand_ecc_choose_conf(struct nand_chip *chip,
> +const struct nand_ecc_caps *caps, int oobavail)
> +{
> +   if (chip->ecc.size && chip->ecc.strength)
> +   return nand_check_ecc_caps(chip, caps, oobavail);
> +
> +   if (!(chip->ecc.options & NAND_ECC_MAXIMIZE) &&
> +   !nand_match_ecc_req(chip, caps, oobavail))
> +   return 0;
> +
> +   return nand_maximize_ecc(chip, caps, oobavail);

I personally don't mind if nand_maximize_ecc() is called twice in
the function if it clarifies the logic. Maybe the following will be
more clear for the user?

  if (chip->ecc.size && chip->ecc.strength)
  return nand_check_ecc_caps(chip, caps, oobavail);

  if (chip->ecc.options & NAND_ECC_MAXIMIZE)
  return nand_maximize_ecc(chip, caps, oobavail);

  if (!nand_match_ecc_req(chip, caps, oobavail))
  return 0;

  return nand_maximize_ecc(chip, caps, oobavail);


I personally don't mind, and it seems Masahiro wanted to keep the 
logic

he had used in the denali driver.



Also, I'm not sure we should just error out when 
nand_check_ecc_caps()

fails. What about something more robust, like:

  int ret;

  if (chip->ecc.size && chip->ecc.strength) {
  ret = nand_check_ecc_caps(chip, caps, oobavail);
  if (ret)
  goto maximize_ecc;


Nope. When someone asked for a specific ECC config by passing the
nand-ecc-xxx props we should apply it or return an erro if it's not
supported. People passing those props should now what the ECC engine
supports and pick one valid values.



  return 0;
  }

  if (chip->ecc.options & NAND_ECC_MAXIMIZE)
  goto maximize_ecc;

  

Re: [PATCH v3 13/16] mtd: rawnand: qcom: minor code reorganization for bad block check

2018-05-28 Thread Abhishek Sahu

On 2018-05-28 12:33, Miquel Raynal wrote:

Hi Abhishek,


>>  /* implements ecc->read_page() */
>>  static int qcom_nandc_read_page(struct mtd_info *mtd, struct >> nand_chip 
*chip,
>>uint8_t *buf, int oob_required, int page)
>> @@ -2118,6 +2083,7 @@ static int qcom_nandc_block_bad(struct mtd_info >> 
*mtd, loff_t ofs)
>>struct nand_ecc_ctrl *ecc = >ecc;
>>int page, ret, bbpos, bad = 0;
>>u32 flash_status;
>> +  u8 *bbm_bytes_buf = chip->data_buf;
>> >>   page = (int)(ofs >> chip->page_shift) & chip->pagemask;
>> >> @@ -2128,11 +2094,31 @@ static int qcom_nandc_block_bad(struct >> 
mtd_info *mtd, loff_t ofs)
>> * that contains the BBM
>> */
>>host->use_ecc = false;
>> +  bbpos = mtd->writesize - host->cw_size * (ecc->steps - 1);
> > Are we sure there is no layout with only 1 step?

  All the layouts are such that, the BBM will come in
  first byte of spare area.

  For 4 bit ECC, the cw_size is 528 so for 2K page

   2048 - 528 * 3 = 464


My question was more about small page NANDs. But I suppose it works
too if ecc->steps == 1.



 Correct Miquel.



  So for last CW, the 464 is BBM (i.e 2048th byte) in
  full page.

> >> >>  clear_bam_transaction(nandc);
>> -  ret = copy_last_cw(host, page);
>> -  if (ret)
>> +  clear_read_regs(nandc);
>> +
>> +  set_address(host, host->cw_size * (ecc->steps - 1), page);
>> +  update_rw_regs(host, 1, true);
>> +
>> +  /*
>> +   * The last codeword data will be copied from NAND device to NAND
>> +   * controller internal HW buffer. Copy only required BBM size bytes
>> +   * from this HW buffer to bbm_bytes_buf which is present at
>> +   * bbpos offset.
>> +   */
>> +  nandc_set_read_loc(nandc, 0, bbpos, host->bbm_size, 1);
>> +  config_nand_single_cw_page_read(nandc);
>> +  read_data_dma(nandc, FLASH_BUF_ACC + bbpos, bbm_bytes_buf,
>> +host->bbm_size, 0);
>> +
>> +  ret = submit_descs(nandc);
>> +  free_descs(nandc);
>> +  if (ret) {
>> +  dev_err(nandc->dev, "failed to copy bad block bytes\n");
>>goto err;
>> +  }
>> >>   flash_status = le32_to_cpu(nandc->reg_read_buf[0]);
>> >> @@ -2141,12 +2127,10 @@ static int qcom_nandc_block_bad(struct >> 
mtd_info *mtd, loff_t ofs)
>>goto err;
>>}
>> >> - bbpos = mtd->writesize - host->cw_size * (ecc->steps - 1);
>> -
>> -  bad = nandc->data_buffer[bbpos] != 0xff;
>> +  bad = bbm_bytes_buf[0] != 0xff;
> > This is suspect as it still points to the beginning of the data buffer.
> Can you please check you did not meant bbm_bytes_buf[bbpos]?
>
  The main thing here is
  nandc_set_read_loc(nandc, 0, bbpos, host->bbm_size, 1);

  After reading one complete CW from NAND, the data will be still
  in NAND HW buffer.

  The above register tells that we need to read data from
  bbpos of size host->bbm_size (which is 1 byte for 8 bus witdh
  and 2 byte for 16 bus width) in bbm_bytes_buf.


I see: idx 0 in bbm_bytes_buf is the data at offset bbpos. Then
it's ok.



  So bbm_bytes_buf[0] will contain the BBM first byte.
  and bbm_bytes_buf[1] will contain the BBM second byte.

  Regards,
  Abhishek

>> >>   if (chip->options & NAND_BUSWIDTH_16)
>> -  bad = bad || (nandc->data_buffer[bbpos + 1] != 0xff);
>> +  bad = bad || (bbm_bytes_buf[1] != 0xff);


Sorry, my mistake, I did not see the above line.

However, technically, the BBM could be located in the first, second or
last page of the block. You should check the three of them are 0xFF
before declaring the block is not bad.

The more I look at the function, the more I wonder if you actually need
it. Why does the generic nand_block_bad() implementation in the core
do not fit?


 The BBM bytes can be accessed in raw mode only for QCOM NAND
 Contoller. We started with following patch for initial patches

 http://patchwork.ozlabs.org/patch/508565/

 I am also not very much sure, how can we go ahead now.
 Ideally we need to use generic function only which
 requires raw_read.

 Thanks,
 Abhishek



Re: [PATCH v3 13/16] mtd: rawnand: qcom: minor code reorganization for bad block check

2018-05-28 Thread Abhishek Sahu

On 2018-05-28 12:33, Miquel Raynal wrote:

Hi Abhishek,


>>  /* implements ecc->read_page() */
>>  static int qcom_nandc_read_page(struct mtd_info *mtd, struct >> nand_chip 
*chip,
>>uint8_t *buf, int oob_required, int page)
>> @@ -2118,6 +2083,7 @@ static int qcom_nandc_block_bad(struct mtd_info >> 
*mtd, loff_t ofs)
>>struct nand_ecc_ctrl *ecc = >ecc;
>>int page, ret, bbpos, bad = 0;
>>u32 flash_status;
>> +  u8 *bbm_bytes_buf = chip->data_buf;
>> >>   page = (int)(ofs >> chip->page_shift) & chip->pagemask;
>> >> @@ -2128,11 +2094,31 @@ static int qcom_nandc_block_bad(struct >> 
mtd_info *mtd, loff_t ofs)
>> * that contains the BBM
>> */
>>host->use_ecc = false;
>> +  bbpos = mtd->writesize - host->cw_size * (ecc->steps - 1);
> > Are we sure there is no layout with only 1 step?

  All the layouts are such that, the BBM will come in
  first byte of spare area.

  For 4 bit ECC, the cw_size is 528 so for 2K page

   2048 - 528 * 3 = 464


My question was more about small page NANDs. But I suppose it works
too if ecc->steps == 1.



 Correct Miquel.



  So for last CW, the 464 is BBM (i.e 2048th byte) in
  full page.

> >> >>  clear_bam_transaction(nandc);
>> -  ret = copy_last_cw(host, page);
>> -  if (ret)
>> +  clear_read_regs(nandc);
>> +
>> +  set_address(host, host->cw_size * (ecc->steps - 1), page);
>> +  update_rw_regs(host, 1, true);
>> +
>> +  /*
>> +   * The last codeword data will be copied from NAND device to NAND
>> +   * controller internal HW buffer. Copy only required BBM size bytes
>> +   * from this HW buffer to bbm_bytes_buf which is present at
>> +   * bbpos offset.
>> +   */
>> +  nandc_set_read_loc(nandc, 0, bbpos, host->bbm_size, 1);
>> +  config_nand_single_cw_page_read(nandc);
>> +  read_data_dma(nandc, FLASH_BUF_ACC + bbpos, bbm_bytes_buf,
>> +host->bbm_size, 0);
>> +
>> +  ret = submit_descs(nandc);
>> +  free_descs(nandc);
>> +  if (ret) {
>> +  dev_err(nandc->dev, "failed to copy bad block bytes\n");
>>goto err;
>> +  }
>> >>   flash_status = le32_to_cpu(nandc->reg_read_buf[0]);
>> >> @@ -2141,12 +2127,10 @@ static int qcom_nandc_block_bad(struct >> 
mtd_info *mtd, loff_t ofs)
>>goto err;
>>}
>> >> - bbpos = mtd->writesize - host->cw_size * (ecc->steps - 1);
>> -
>> -  bad = nandc->data_buffer[bbpos] != 0xff;
>> +  bad = bbm_bytes_buf[0] != 0xff;
> > This is suspect as it still points to the beginning of the data buffer.
> Can you please check you did not meant bbm_bytes_buf[bbpos]?
>
  The main thing here is
  nandc_set_read_loc(nandc, 0, bbpos, host->bbm_size, 1);

  After reading one complete CW from NAND, the data will be still
  in NAND HW buffer.

  The above register tells that we need to read data from
  bbpos of size host->bbm_size (which is 1 byte for 8 bus witdh
  and 2 byte for 16 bus width) in bbm_bytes_buf.


I see: idx 0 in bbm_bytes_buf is the data at offset bbpos. Then
it's ok.



  So bbm_bytes_buf[0] will contain the BBM first byte.
  and bbm_bytes_buf[1] will contain the BBM second byte.

  Regards,
  Abhishek

>> >>   if (chip->options & NAND_BUSWIDTH_16)
>> -  bad = bad || (nandc->data_buffer[bbpos + 1] != 0xff);
>> +  bad = bad || (bbm_bytes_buf[1] != 0xff);


Sorry, my mistake, I did not see the above line.

However, technically, the BBM could be located in the first, second or
last page of the block. You should check the three of them are 0xFF
before declaring the block is not bad.

The more I look at the function, the more I wonder if you actually need
it. Why does the generic nand_block_bad() implementation in the core
do not fit?


 The BBM bytes can be accessed in raw mode only for QCOM NAND
 Contoller. We started with following patch for initial patches

 http://patchwork.ozlabs.org/patch/508565/

 I am also not very much sure, how can we go ahead now.
 Ideally we need to use generic function only which
 requires raw_read.

 Thanks,
 Abhishek



Re: [PATCH v3 15/16] mtd: rawnand: qcom: helper function for raw read

2018-05-28 Thread Abhishek Sahu

On 2018-05-27 19:23, Miquel Raynal wrote:

Hi Abhishek,

On Fri, 25 May 2018 17:51:43 +0530, Abhishek Sahu
<abs...@codeaurora.org> wrote:


This patch does minor code reorganization for raw reads.
Currently the raw read is required for complete page but for
subsequent patches related with erased codeword bit flips
detection, only few CW should be read. So, this patch adds
helper function and introduces the read CW bitmask which
specifies which CW reads are required in complete page.

Signed-off-by: Abhishek Sahu <abs...@codeaurora.org>
---
* Changes from v2:
  NONE

* Changes from v1:
 1. Included more detail in function comment

 drivers/mtd/nand/raw/qcom_nandc.c | 197 
--

 1 file changed, 123 insertions(+), 74 deletions(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c 
b/drivers/mtd/nand/raw/qcom_nandc.c

index 87f900e..34143a4 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -1588,6 +1588,127 @@ static int check_flash_errors(struct 
qcom_nand_host *host, int cw_cnt)

 }

 /*
+ * Helper to perform the page raw read operation. The read_cw_mask 
will be
+ * used to specify the codewords (CW) for which the data should be 
read. The

+ * single page contains multiple CW.
+ *
+ * Normally other NAND controllers store the data in main area and
+ * ecc bytes in OOB area. So, if page size is 2048+64 then 2048
+ * data bytes will go in main area followed by ECC bytes. The QCOM 
NAND
+ * controller follows different layout in which the data+OOB is 
internally
+ * divided in 528/532 bytes CW and each CW contains 516 bytes 
followed by
+ * ECC parity bytes for that CW. By this, 4 available OOB bytes per 
CW

+ * will also be protected with ECC.
+ *
+ * For each CW read, following are the 2 steps:
+ * 1. Read the codeword bytes from NAND chip to NAND controller 
internal HW

+ *buffer.
+ * 2. Copy all these bytes from this HW buffer to actual buffer.
+ *
+ * Sometime, only few CW data is required in complete page. The 
read_cw_mask
+ * specifies which CW in a page needs to be read. Start address will 
be
+ * determined with this CW mask to skip unnecessary data copy from 
NAND
+ * flash device. Then, actual data copy from NAND controller HW 
internal buffer
+ * to data buffer will be done only for the CWs, which have the mask 
set.

+ */
+static int
+nandc_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+   u8 *data_buf, u8 *oob_buf,
+   int page, unsigned long read_cw_mask)


Please prefix the helper with "qcom_nandc"



 Sure Miquel.
 I will update that.


+{
+   struct qcom_nand_host *host = to_qcom_nand_host(chip);
+   struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+   struct nand_ecc_ctrl *ecc = >ecc;
+   int i, ret;
+   int read_loc, start_step, last_step;
+
+   nand_read_page_op(chip, page, 0, NULL, 0);
+
+   host->use_ecc = false;
+   start_step = ffs(read_cw_mask) - 1;
+   last_step = fls(read_cw_mask);
+
+   clear_bam_transaction(nandc);
+   set_address(host, host->cw_size * start_step, page);
+   update_rw_regs(host, last_step - start_step, true);
+   config_nand_page_read(nandc);
+
+   for (i = start_step; i < last_step; i++) {


This comment applies for both patches 15 and 16:

I would really prefer having a qcom_nandc_read_cw_raw() that reads only
one CW. From qcom_nandc_read_page_raw() you would loop over all the CW
calling qcom_nandc_read_cw_raw() helper (it's raw reads, we don't care
about performances)


 Doing that way will degrade performances hugely.

 Currently once we formed the descriptor, the DMA will take care
 of complete page data transfer from NAND device to buffer and will
 generate single interrupt.

 Now it will form one CW descriptor and wait for it to be finished.
 In background, the data transfer from NAND device will be also
 split and for every CW, it will give the PAGE_READ command again,
 which is again time consuming.

 Data transfer degradation is ok but it will increase CPU time
 and number of interrupts which will impact other peripherals
 performance that time.

 Most of the NAND parts has 4K page size i.e 8 CWs.


and from ->read_page_raw() you would check
CW with uncorrectable errors for being blank with that helper. You
would avoid the not-so-nice logic where you read all the CW between the
first bad one and the last bad one.



 The reading b/w first CW and last CW is only from NAND device to NAND
 HW buffers. The NAND controller has 2 HW buffers which is used to
 optimize the traffic throughput between the NAND device and
 system memory,in both directions. Each buffer is 544B in size: 512B
 for data + 32B spare bytes. Throughput optimization is achieved by
 executing internal data transfers (i.e. between NANDc buffers and
 system memory) simultaneously with NAND device operations.

 Making separate function won't help in improv

Re: [PATCH v3 15/16] mtd: rawnand: qcom: helper function for raw read

2018-05-28 Thread Abhishek Sahu

On 2018-05-27 19:23, Miquel Raynal wrote:

Hi Abhishek,

On Fri, 25 May 2018 17:51:43 +0530, Abhishek Sahu
 wrote:


This patch does minor code reorganization for raw reads.
Currently the raw read is required for complete page but for
subsequent patches related with erased codeword bit flips
detection, only few CW should be read. So, this patch adds
helper function and introduces the read CW bitmask which
specifies which CW reads are required in complete page.

Signed-off-by: Abhishek Sahu 
---
* Changes from v2:
  NONE

* Changes from v1:
 1. Included more detail in function comment

 drivers/mtd/nand/raw/qcom_nandc.c | 197 
--

 1 file changed, 123 insertions(+), 74 deletions(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c 
b/drivers/mtd/nand/raw/qcom_nandc.c

index 87f900e..34143a4 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -1588,6 +1588,127 @@ static int check_flash_errors(struct 
qcom_nand_host *host, int cw_cnt)

 }

 /*
+ * Helper to perform the page raw read operation. The read_cw_mask 
will be
+ * used to specify the codewords (CW) for which the data should be 
read. The

+ * single page contains multiple CW.
+ *
+ * Normally other NAND controllers store the data in main area and
+ * ecc bytes in OOB area. So, if page size is 2048+64 then 2048
+ * data bytes will go in main area followed by ECC bytes. The QCOM 
NAND
+ * controller follows different layout in which the data+OOB is 
internally
+ * divided in 528/532 bytes CW and each CW contains 516 bytes 
followed by
+ * ECC parity bytes for that CW. By this, 4 available OOB bytes per 
CW

+ * will also be protected with ECC.
+ *
+ * For each CW read, following are the 2 steps:
+ * 1. Read the codeword bytes from NAND chip to NAND controller 
internal HW

+ *buffer.
+ * 2. Copy all these bytes from this HW buffer to actual buffer.
+ *
+ * Sometime, only few CW data is required in complete page. The 
read_cw_mask
+ * specifies which CW in a page needs to be read. Start address will 
be
+ * determined with this CW mask to skip unnecessary data copy from 
NAND
+ * flash device. Then, actual data copy from NAND controller HW 
internal buffer
+ * to data buffer will be done only for the CWs, which have the mask 
set.

+ */
+static int
+nandc_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+   u8 *data_buf, u8 *oob_buf,
+   int page, unsigned long read_cw_mask)


Please prefix the helper with "qcom_nandc"



 Sure Miquel.
 I will update that.


+{
+   struct qcom_nand_host *host = to_qcom_nand_host(chip);
+   struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+   struct nand_ecc_ctrl *ecc = >ecc;
+   int i, ret;
+   int read_loc, start_step, last_step;
+
+   nand_read_page_op(chip, page, 0, NULL, 0);
+
+   host->use_ecc = false;
+   start_step = ffs(read_cw_mask) - 1;
+   last_step = fls(read_cw_mask);
+
+   clear_bam_transaction(nandc);
+   set_address(host, host->cw_size * start_step, page);
+   update_rw_regs(host, last_step - start_step, true);
+   config_nand_page_read(nandc);
+
+   for (i = start_step; i < last_step; i++) {


This comment applies for both patches 15 and 16:

I would really prefer having a qcom_nandc_read_cw_raw() that reads only
one CW. From qcom_nandc_read_page_raw() you would loop over all the CW
calling qcom_nandc_read_cw_raw() helper (it's raw reads, we don't care
about performances)


 Doing that way will degrade performances hugely.

 Currently once we formed the descriptor, the DMA will take care
 of complete page data transfer from NAND device to buffer and will
 generate single interrupt.

 Now it will form one CW descriptor and wait for it to be finished.
 In background, the data transfer from NAND device will be also
 split and for every CW, it will give the PAGE_READ command again,
 which is again time consuming.

 Data transfer degradation is ok but it will increase CPU time
 and number of interrupts which will impact other peripherals
 performance that time.

 Most of the NAND parts has 4K page size i.e 8 CWs.


and from ->read_page_raw() you would check
CW with uncorrectable errors for being blank with that helper. You
would avoid the not-so-nice logic where you read all the CW between the
first bad one and the last bad one.



 The reading b/w first CW and last CW is only from NAND device to NAND
 HW buffers. The NAND controller has 2 HW buffers which is used to
 optimize the traffic throughput between the NAND device and
 system memory,in both directions. Each buffer is 544B in size: 512B
 for data + 32B spare bytes. Throughput optimization is achieved by
 executing internal data transfers (i.e. between NANDc buffers and
 system memory) simultaneously with NAND device operations.

 Making separate function won't help in improving performance for
 this case either since once every thin

Re: [PATCH v3 13/16] mtd: rawnand: qcom: minor code reorganization for bad block check

2018-05-28 Thread Abhishek Sahu

On 2018-05-26 14:28, Miquel Raynal wrote:

Hi Abhishek,


@@ -2141,12 +2127,10 @@ static int qcom_nandc_block_bad(struct 
mtd_info *mtd, loff_t ofs)

goto err;
}

-   bbpos = mtd->writesize - host->cw_size * (ecc->steps - 1);
-
-   bad = nandc->data_buffer[bbpos] != 0xff;
+   bad = bbm_bytes_buf[0] != 0xff;


BTW, as there are host->bbm_size bytes that can inform on the block
state, don't we need to check all of them?



 We are checking all of them.
 host->bbm_size will be either 1 (for NAND_BUSWIDTH_8) or
 2 (for NAND_BUSWIDTH_16).

 
https://elixir.bootlin.com/linux/v4.17-rc7/source/drivers/mtd/nand/raw/qcom_nandc.c#L2347


 Thanks,
 Abhishek



if (chip->options & NAND_BUSWIDTH_16)
-   bad = bad || (nandc->data_buffer[bbpos + 1] != 0xff);
+   bad = bad || (bbm_bytes_buf[1] != 0xff);
 err:
return bad;
 }


Thanks,
Miquèl


Re: [PATCH v3 13/16] mtd: rawnand: qcom: minor code reorganization for bad block check

2018-05-28 Thread Abhishek Sahu

On 2018-05-26 14:28, Miquel Raynal wrote:

Hi Abhishek,


@@ -2141,12 +2127,10 @@ static int qcom_nandc_block_bad(struct 
mtd_info *mtd, loff_t ofs)

goto err;
}

-   bbpos = mtd->writesize - host->cw_size * (ecc->steps - 1);
-
-   bad = nandc->data_buffer[bbpos] != 0xff;
+   bad = bbm_bytes_buf[0] != 0xff;


BTW, as there are host->bbm_size bytes that can inform on the block
state, don't we need to check all of them?



 We are checking all of them.
 host->bbm_size will be either 1 (for NAND_BUSWIDTH_8) or
 2 (for NAND_BUSWIDTH_16).

 
https://elixir.bootlin.com/linux/v4.17-rc7/source/drivers/mtd/nand/raw/qcom_nandc.c#L2347


 Thanks,
 Abhishek



if (chip->options & NAND_BUSWIDTH_16)
-   bad = bad || (nandc->data_buffer[bbpos + 1] != 0xff);
+   bad = bad || (bbm_bytes_buf[1] != 0xff);
 err:
return bad;
 }


Thanks,
Miquèl


Re: [PATCH v3 13/16] mtd: rawnand: qcom: minor code reorganization for bad block check

2018-05-28 Thread Abhishek Sahu

On 2018-05-26 14:16, Miquel Raynal wrote:

Hi Abhishek,

On Fri, 25 May 2018 17:51:41 +0530, Abhishek Sahu
<abs...@codeaurora.org> wrote:


The QCOM NAND controller layout is such that, the bad block byte
offset for last codeword will come to first byte in spare area.


"is the first spare byte"?



Currently, the raw read for last codeword is being done with
copy_last_cw function. It does following 2 things:


"It does the following:"



1. Read the last codeword bytes from NAND chip to NAND
   controller internal HW buffer.
2. Copy all these bytes from HW buffer to actual buffer.

For bad block check, maximum two bytes are required so instead of
copying the complete bytes in step 2, only those bbm_size bytes
can be copied.

This patch does minor code reorganization for the same. After
this, copy_last_cw function won’t be required.


"This patch does minor code reorganization to just retrieve these two
bytes when checking for bad blocks, allowing to remove
copy_last_cw() now useless."



 Thanks Miquel.
 I will update all these.



Signed-off-by: Abhishek Sahu <abs...@codeaurora.org>
---
* Changes from v2:
  1. Changed commit message and comments slightly

* Changes from v1:
  NEW CHANGE

 drivers/mtd/nand/raw/qcom_nandc.c | 66 
+++

 1 file changed, 25 insertions(+), 41 deletions(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c 
b/drivers/mtd/nand/raw/qcom_nandc.c

index d693b5f..f72bc8a 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -1769,41 +1769,6 @@ static int read_page_ecc(struct qcom_nand_host 
*host, u8 *data_buf,

return parse_read_errors(host, data_buf_start, oob_buf_start);
 }

-/*
- * a helper that copies the last step/codeword of a page (containing 
free oob)

- * into our local buffer
- */
-static int copy_last_cw(struct qcom_nand_host *host, int page)
-{
-   struct nand_chip *chip = >chip;
-   struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-   struct nand_ecc_ctrl *ecc = >ecc;
-   int size;
-   int ret;
-
-   clear_read_regs(nandc);
-
-   size = host->use_ecc ? host->cw_data : host->cw_size;
-
-   /* prepare a clean read buffer */
-   memset(nandc->data_buffer, 0xff, size);
-
-   set_address(host, host->cw_size * (ecc->steps - 1), page);
-   update_rw_regs(host, 1, true);
-
-   config_nand_single_cw_page_read(nandc);
-
-   read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, size, 0);
-
-   ret = submit_descs(nandc);
-   if (ret)
-   dev_err(nandc->dev, "failed to copy last codeword\n");
-
-   free_descs(nandc);
-
-   return ret;
-}
-
 /* implements ecc->read_page() */
 static int qcom_nandc_read_page(struct mtd_info *mtd, struct 
nand_chip *chip,

uint8_t *buf, int oob_required, int page)
@@ -2118,6 +2083,7 @@ static int qcom_nandc_block_bad(struct mtd_info 
*mtd, loff_t ofs)

struct nand_ecc_ctrl *ecc = >ecc;
int page, ret, bbpos, bad = 0;
u32 flash_status;
+   u8 *bbm_bytes_buf = chip->data_buf;

page = (int)(ofs >> chip->page_shift) & chip->pagemask;

@@ -2128,11 +2094,31 @@ static int qcom_nandc_block_bad(struct 
mtd_info *mtd, loff_t ofs)

 * that contains the BBM
 */
host->use_ecc = false;
+   bbpos = mtd->writesize - host->cw_size * (ecc->steps - 1);


Are we sure there is no layout with only 1 step?


 All the layouts are such that, the BBM will come in
 first byte of spare area.

 For 4 bit ECC, the cw_size is 528 so for 2K page

  2048 - 528 * 3 = 464

 So for last CW, the 464 is BBM (i.e 2048th byte) in
 full page.





clear_bam_transaction(nandc);
-   ret = copy_last_cw(host, page);
-   if (ret)
+   clear_read_regs(nandc);
+
+   set_address(host, host->cw_size * (ecc->steps - 1), page);
+   update_rw_regs(host, 1, true);
+
+   /*
+* The last codeword data will be copied from NAND device to NAND
+* controller internal HW buffer. Copy only required BBM size bytes
+* from this HW buffer to bbm_bytes_buf which is present at
+* bbpos offset.
+*/
+   nandc_set_read_loc(nandc, 0, bbpos, host->bbm_size, 1);
+   config_nand_single_cw_page_read(nandc);
+   read_data_dma(nandc, FLASH_BUF_ACC + bbpos, bbm_bytes_buf,
+ host->bbm_size, 0);
+
+   ret = submit_descs(nandc);
+   free_descs(nandc);
+   if (ret) {
+   dev_err(nandc->dev, "failed to copy bad block bytes\n");
goto err;
+   }

flash_status = le32_to_cpu(nandc->reg_read_buf[0]);

@@ -2141,12 +2127,10 @@ static int qcom_nandc_block_bad(struct 
mtd_info *mtd, loff_t ofs)

goto err;
}

-   bbpos = mtd->writesize - host

Re: [PATCH v3 13/16] mtd: rawnand: qcom: minor code reorganization for bad block check

2018-05-28 Thread Abhishek Sahu

On 2018-05-26 14:16, Miquel Raynal wrote:

Hi Abhishek,

On Fri, 25 May 2018 17:51:41 +0530, Abhishek Sahu
 wrote:


The QCOM NAND controller layout is such that, the bad block byte
offset for last codeword will come to first byte in spare area.


"is the first spare byte"?



Currently, the raw read for last codeword is being done with
copy_last_cw function. It does following 2 things:


"It does the following:"



1. Read the last codeword bytes from NAND chip to NAND
   controller internal HW buffer.
2. Copy all these bytes from HW buffer to actual buffer.

For bad block check, maximum two bytes are required so instead of
copying the complete bytes in step 2, only those bbm_size bytes
can be copied.

This patch does minor code reorganization for the same. After
this, copy_last_cw function won’t be required.


"This patch does minor code reorganization to just retrieve these two
bytes when checking for bad blocks, allowing to remove
copy_last_cw() now useless."



 Thanks Miquel.
 I will update all these.



Signed-off-by: Abhishek Sahu 
---
* Changes from v2:
  1. Changed commit message and comments slightly

* Changes from v1:
  NEW CHANGE

 drivers/mtd/nand/raw/qcom_nandc.c | 66 
+++

 1 file changed, 25 insertions(+), 41 deletions(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c 
b/drivers/mtd/nand/raw/qcom_nandc.c

index d693b5f..f72bc8a 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -1769,41 +1769,6 @@ static int read_page_ecc(struct qcom_nand_host 
*host, u8 *data_buf,

return parse_read_errors(host, data_buf_start, oob_buf_start);
 }

-/*
- * a helper that copies the last step/codeword of a page (containing 
free oob)

- * into our local buffer
- */
-static int copy_last_cw(struct qcom_nand_host *host, int page)
-{
-   struct nand_chip *chip = >chip;
-   struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-   struct nand_ecc_ctrl *ecc = >ecc;
-   int size;
-   int ret;
-
-   clear_read_regs(nandc);
-
-   size = host->use_ecc ? host->cw_data : host->cw_size;
-
-   /* prepare a clean read buffer */
-   memset(nandc->data_buffer, 0xff, size);
-
-   set_address(host, host->cw_size * (ecc->steps - 1), page);
-   update_rw_regs(host, 1, true);
-
-   config_nand_single_cw_page_read(nandc);
-
-   read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, size, 0);
-
-   ret = submit_descs(nandc);
-   if (ret)
-   dev_err(nandc->dev, "failed to copy last codeword\n");
-
-   free_descs(nandc);
-
-   return ret;
-}
-
 /* implements ecc->read_page() */
 static int qcom_nandc_read_page(struct mtd_info *mtd, struct 
nand_chip *chip,

uint8_t *buf, int oob_required, int page)
@@ -2118,6 +2083,7 @@ static int qcom_nandc_block_bad(struct mtd_info 
*mtd, loff_t ofs)

struct nand_ecc_ctrl *ecc = >ecc;
int page, ret, bbpos, bad = 0;
u32 flash_status;
+   u8 *bbm_bytes_buf = chip->data_buf;

page = (int)(ofs >> chip->page_shift) & chip->pagemask;

@@ -2128,11 +2094,31 @@ static int qcom_nandc_block_bad(struct 
mtd_info *mtd, loff_t ofs)

 * that contains the BBM
 */
host->use_ecc = false;
+   bbpos = mtd->writesize - host->cw_size * (ecc->steps - 1);


Are we sure there is no layout with only 1 step?


 All the layouts are such that, the BBM will come in
 first byte of spare area.

 For 4 bit ECC, the cw_size is 528 so for 2K page

  2048 - 528 * 3 = 464

 So for last CW, the 464 is BBM (i.e 2048th byte) in
 full page.





clear_bam_transaction(nandc);
-   ret = copy_last_cw(host, page);
-   if (ret)
+   clear_read_regs(nandc);
+
+   set_address(host, host->cw_size * (ecc->steps - 1), page);
+   update_rw_regs(host, 1, true);
+
+   /*
+* The last codeword data will be copied from NAND device to NAND
+* controller internal HW buffer. Copy only required BBM size bytes
+* from this HW buffer to bbm_bytes_buf which is present at
+* bbpos offset.
+*/
+   nandc_set_read_loc(nandc, 0, bbpos, host->bbm_size, 1);
+   config_nand_single_cw_page_read(nandc);
+   read_data_dma(nandc, FLASH_BUF_ACC + bbpos, bbm_bytes_buf,
+ host->bbm_size, 0);
+
+   ret = submit_descs(nandc);
+   free_descs(nandc);
+   if (ret) {
+   dev_err(nandc->dev, "failed to copy bad block bytes\n");
goto err;
+   }

flash_status = le32_to_cpu(nandc->reg_read_buf[0]);

@@ -2141,12 +2127,10 @@ static int qcom_nandc_block_bad(struct 
mtd_info *mtd, loff_t ofs)

goto err;
}

-   bbpos = mtd->writesize - host->cw_size * (ecc->steps - 1);
-
-   bad = nandc-&g

Re: [PATCH v3 06/16] mtd: rawnand: qcom: use the ecc strength from device parameter

2018-05-28 Thread Abhishek Sahu

On 2018-05-26 14:13, Miquel Raynal wrote:

Hi Abhishek,

On Fri, 25 May 2018 17:51:34 +0530, Abhishek Sahu
<abs...@codeaurora.org> wrote:


Currently the driver uses the ECC strength specified in DT.
The QPIC/EBI2 NAND supports 4 or 8-bit ECC correction. The same
kind of board can have different NAND parts so use the ECC
strength from device parameters if it is not specified in DT.

Signed-off-by: Abhishek Sahu <abs...@codeaurora.org>
---
* Changes from v2:
  NONE


Yes you did change things:

- s/<< 2/* 4/
- updated the cwperpage location
- the block handling the ecc-step-size property has been removed in a
  previous patch

Please be careful with that, it is time consuming to review the patches
all over again.



 Sorry Miquel for that.
 I Will pay more attention to this.
 I can understand the effort require in reviewing and how this can help
 in making review quicker.



* Changes from v1:

  1. Removed the custom logic and used the helper fuction.

 drivers/mtd/nand/raw/qcom_nandc.c | 29 +
 1 file changed, 21 insertions(+), 8 deletions(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c 
b/drivers/mtd/nand/raw/qcom_nandc.c

index b538390..7377923 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -2315,19 +2315,39 @@ static int qcom_nand_ooblayout_free(struct 
mtd_info *mtd, int section,

.free = qcom_nand_ooblayout_free,
 };

+static int
+qcom_nandc_calc_ecc_bytes(int step_size, int strength)
+{
+   return strength == 4 ? 12 : 16;
+}
+NAND_ECC_CAPS_SINGLE(qcom_nandc_ecc_caps, qcom_nandc_calc_ecc_bytes,
+NANDC_STEP_SIZE, 4, 8);
+
 static int qcom_nand_host_setup(struct qcom_nand_host *host)
 {
struct nand_chip *chip = >chip;
struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_ecc_ctrl *ecc = >ecc;
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-   int cwperpage, bad_block_byte;
+   int cwperpage, bad_block_byte, ret;
bool wide_bus;
int ecc_mode = 1;

/* controller only supports 512 bytes of data in each step */
ecc->size = NANDC_STEP_SIZE;
wide_bus = chip->options & NAND_BUSWIDTH_16 ? true : false;
+   cwperpage = mtd->writesize / NANDC_STEP_SIZE;
+
+   /*
+	 * Each CW has 4 available OOB bytes which will be protected with 
ECC

+* so remaining bytes can be used for ECC.
+*/
+   ret = nand_ecc_choose_conf(chip, _nandc_ecc_caps,
+  mtd->oobsize - cwperpage * 4);


Nitpick: could you add parenthesis around (cwperpage * 4) just for
clarity.



 Thanks Miquel.
 I will update that.

 Regards,
 Abhishek


+   if (ret) {
+   dev_err(nandc->dev, "No valid ECC settings possible\n");
+   return ret;
+   }

if (ecc->strength >= 8) {
/* 8 bit ECC defaults to BCH ECC on all platforms */
@@ -2396,7 +2416,6 @@ static int qcom_nand_host_setup(struct 
qcom_nand_host *host)


mtd_set_ooblayout(mtd, _nand_ooblayout_ops);

-   cwperpage = mtd->writesize / ecc->size;
nandc->max_cwperpage = max_t(unsigned int, nandc->max_cwperpage,
 cwperpage);

@@ -2412,12 +2431,6 @@ static int qcom_nand_host_setup(struct 
qcom_nand_host *host)

 * for 8 bit ECC
 */
host->cw_size = host->cw_data + ecc->bytes;
-
-   if (ecc->bytes * (mtd->writesize / ecc->size) > mtd->oobsize) {
-   dev_err(nandc->dev, "ecc data doesn't fit in OOB area\n");
-   return -EINVAL;
-   }
-
 	bad_block_byte = mtd->writesize - host->cw_size * (cwperpage - 1) + 
1;


host->cfg0 = (cwperpage - 1) << CW_PER_PAGE


Once corrected:

Acked-by: Miquel Raynal <miquel.ray...@bootlin.com>

Thanks,
Miquèl


Re: [PATCH v3 06/16] mtd: rawnand: qcom: use the ecc strength from device parameter

2018-05-28 Thread Abhishek Sahu

On 2018-05-26 14:13, Miquel Raynal wrote:

Hi Abhishek,

On Fri, 25 May 2018 17:51:34 +0530, Abhishek Sahu
 wrote:


Currently the driver uses the ECC strength specified in DT.
The QPIC/EBI2 NAND supports 4 or 8-bit ECC correction. The same
kind of board can have different NAND parts so use the ECC
strength from device parameters if it is not specified in DT.

Signed-off-by: Abhishek Sahu 
---
* Changes from v2:
  NONE


Yes you did change things:

- s/<< 2/* 4/
- updated the cwperpage location
- the block handling the ecc-step-size property has been removed in a
  previous patch

Please be careful with that, it is time consuming to review the patches
all over again.



 Sorry Miquel for that.
 I Will pay more attention to this.
 I can understand the effort require in reviewing and how this can help
 in making review quicker.



* Changes from v1:

  1. Removed the custom logic and used the helper fuction.

 drivers/mtd/nand/raw/qcom_nandc.c | 29 +
 1 file changed, 21 insertions(+), 8 deletions(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c 
b/drivers/mtd/nand/raw/qcom_nandc.c

index b538390..7377923 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -2315,19 +2315,39 @@ static int qcom_nand_ooblayout_free(struct 
mtd_info *mtd, int section,

.free = qcom_nand_ooblayout_free,
 };

+static int
+qcom_nandc_calc_ecc_bytes(int step_size, int strength)
+{
+   return strength == 4 ? 12 : 16;
+}
+NAND_ECC_CAPS_SINGLE(qcom_nandc_ecc_caps, qcom_nandc_calc_ecc_bytes,
+NANDC_STEP_SIZE, 4, 8);
+
 static int qcom_nand_host_setup(struct qcom_nand_host *host)
 {
struct nand_chip *chip = >chip;
struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_ecc_ctrl *ecc = >ecc;
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-   int cwperpage, bad_block_byte;
+   int cwperpage, bad_block_byte, ret;
bool wide_bus;
int ecc_mode = 1;

/* controller only supports 512 bytes of data in each step */
ecc->size = NANDC_STEP_SIZE;
wide_bus = chip->options & NAND_BUSWIDTH_16 ? true : false;
+   cwperpage = mtd->writesize / NANDC_STEP_SIZE;
+
+   /*
+	 * Each CW has 4 available OOB bytes which will be protected with 
ECC

+* so remaining bytes can be used for ECC.
+*/
+   ret = nand_ecc_choose_conf(chip, _nandc_ecc_caps,
+  mtd->oobsize - cwperpage * 4);


Nitpick: could you add parenthesis around (cwperpage * 4) just for
clarity.



 Thanks Miquel.
 I will update that.

 Regards,
 Abhishek


+   if (ret) {
+   dev_err(nandc->dev, "No valid ECC settings possible\n");
+   return ret;
+   }

if (ecc->strength >= 8) {
/* 8 bit ECC defaults to BCH ECC on all platforms */
@@ -2396,7 +2416,6 @@ static int qcom_nand_host_setup(struct 
qcom_nand_host *host)


mtd_set_ooblayout(mtd, _nand_ooblayout_ops);

-   cwperpage = mtd->writesize / ecc->size;
nandc->max_cwperpage = max_t(unsigned int, nandc->max_cwperpage,
 cwperpage);

@@ -2412,12 +2431,6 @@ static int qcom_nand_host_setup(struct 
qcom_nand_host *host)

 * for 8 bit ECC
 */
host->cw_size = host->cw_data + ecc->bytes;
-
-   if (ecc->bytes * (mtd->writesize / ecc->size) > mtd->oobsize) {
-   dev_err(nandc->dev, "ecc data doesn't fit in OOB area\n");
-   return -EINVAL;
-   }
-
 	bad_block_byte = mtd->writesize - host->cw_size * (cwperpage - 1) + 
1;


host->cfg0 = (cwperpage - 1) << CW_PER_PAGE


Once corrected:

Acked-by: Miquel Raynal 

Thanks,
Miquèl


Re: [PATCH v3 05/16] mtd: rawnand: qcom: remove dt property nand-ecc-step-size

2018-05-27 Thread Abhishek Sahu

On 2018-05-26 14:12, Miquel Raynal wrote:

Hi Abhishek,

On Fri, 25 May 2018 17:51:33 +0530, Abhishek Sahu
<abs...@codeaurora.org> wrote:


QCOM NAND controller supports only one step size (512) so
nand-ecc-step-size DT property is redundant. This property
can be removed and ecc step size can be assigned with 512 value.

Signed-off-by: Abhishek Sahu <abs...@codeaurora.org>
---
* Changes from v2:

 NEW CHANGE

  1. Removed the custom logic and used the helper fuction.
 drivers/mtd/nand/raw/qcom_nandc.c | 11 ++-
 1 file changed, 2 insertions(+), 9 deletions(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c 
b/drivers/mtd/nand/raw/qcom_nandc.c

index b554fb6..b538390 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -2325,15 +2325,8 @@ static int qcom_nand_host_setup(struct 
qcom_nand_host *host)

bool wide_bus;
int ecc_mode = 1;

-   /*
-* the controller requires each step consists of 512 bytes of data.
-* bail out if DT has populated a wrong step size.
-*/
-   if (ecc->size != NANDC_STEP_SIZE) {
-   dev_err(nandc->dev, "invalid ecc size\n");
-   return -EINVAL;
-   }
-
+   /* controller only supports 512 bytes of data in each step */


"512 bytes data steps"



 Thanks Miquel.
 Will update that.

 Regards,
 Abhishek


+   ecc->size = NANDC_STEP_SIZE;
wide_bus = chip->options & NAND_BUSWIDTH_16 ? true : false;

if (ecc->strength >= 8) {


Once corrected:

Acked-by: Miquel Raynal <miquel.ray...@bootlin.com>


Re: [PATCH v3 05/16] mtd: rawnand: qcom: remove dt property nand-ecc-step-size

2018-05-27 Thread Abhishek Sahu

On 2018-05-26 14:12, Miquel Raynal wrote:

Hi Abhishek,

On Fri, 25 May 2018 17:51:33 +0530, Abhishek Sahu
 wrote:


QCOM NAND controller supports only one step size (512) so
nand-ecc-step-size DT property is redundant. This property
can be removed and ecc step size can be assigned with 512 value.

Signed-off-by: Abhishek Sahu 
---
* Changes from v2:

 NEW CHANGE

  1. Removed the custom logic and used the helper fuction.
 drivers/mtd/nand/raw/qcom_nandc.c | 11 ++-
 1 file changed, 2 insertions(+), 9 deletions(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c 
b/drivers/mtd/nand/raw/qcom_nandc.c

index b554fb6..b538390 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -2325,15 +2325,8 @@ static int qcom_nand_host_setup(struct 
qcom_nand_host *host)

bool wide_bus;
int ecc_mode = 1;

-   /*
-* the controller requires each step consists of 512 bytes of data.
-* bail out if DT has populated a wrong step size.
-*/
-   if (ecc->size != NANDC_STEP_SIZE) {
-   dev_err(nandc->dev, "invalid ecc size\n");
-   return -EINVAL;
-   }
-
+   /* controller only supports 512 bytes of data in each step */


"512 bytes data steps"



 Thanks Miquel.
 Will update that.

 Regards,
 Abhishek


+   ecc->size = NANDC_STEP_SIZE;
wide_bus = chip->options & NAND_BUSWIDTH_16 ? true : false;

if (ecc->strength >= 8) {


Once corrected:

Acked-by: Miquel Raynal 


Re: [PATCH v3 03/16] dt-bindings: qcom_nandc: make nand-ecc-strength optional

2018-05-27 Thread Abhishek Sahu

On 2018-05-26 14:12, Miquel Raynal wrote:

Hi Abhishek,

On Fri, 25 May 2018 17:51:31 +0530, Abhishek Sahu
<abs...@codeaurora.org> wrote:


If nand-ecc-strength specified in DT, then controller will use
this ECC strength otherwise ECC strength will be calculated
according to chip requirement and available OOB size.

Signed-off-by: Abhishek Sahu <abs...@codeaurora.org>
---
* Changes from v2:
  NONE

* Changes from v1:
  NEW PATCH

 Documentation/devicetree/bindings/mtd/qcom_nandc.txt | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/mtd/qcom_nandc.txt 
b/Documentation/devicetree/bindings/mtd/qcom_nandc.txt

index 73d336be..f246aa0 100644
--- a/Documentation/devicetree/bindings/mtd/qcom_nandc.txt
+++ b/Documentation/devicetree/bindings/mtd/qcom_nandc.txt
@@ -45,11 +45,13 @@ Required properties:
number (e.g., 0, 1, 2, etc.)
 - #address-cells:  see partition.txt
 - #size-cells: see partition.txt
-- nand-ecc-strength:   see nand.txt
 - nand-ecc-step-size:  must be 512. see nand.txt for more details.


I think you can squash the two dt-bindings commits as they are tightly
related to each other.



 Sure Miquel.
 Earlier made one patch and then split into two.
 Will squash that and make single patch again :-)

 Thanks,
 Abhishek



 Optional properties:
 - nand-bus-width:  see nand.txt
+- nand-ecc-strength:	see nand.txt. If not specified, then ECC 
strength will

+   be used according to chip requirement and available
+   OOB size.

 Each nandcs device node may optionally contain a 'partitions' 
sub-node, which
 further contains sub-nodes describing the flash partition mapping. 
See


  1   2   3   4   5   6   7   8   9   10   >