[PATCH v2 06/10] scsi: ufs: use devres functions for ufshcd

2013-06-26 Thread Seungwon Jeon
This patch replaces normal calls for resource allocation with devm_*()
derivative functions. It makes resource freeing simpler.

Signed-off-by: Seungwon Jeon 
Signed-off-by: Santosh Y 
---
Change in v2:
[NOTE: There are no conflicts with the following series(07~10)]
- Remove iounmap which is remained.
- Apply devres to ufshcd_memory_alloc[dmam_alloc_coherent, devm_kzalloc]
  Accordingly, 'free' related functions are removed.

 drivers/scsi/ufs/ufshcd-pci.c|1 -
 drivers/scsi/ufs/ufshcd-pltfrm.c |   72 +---
 drivers/scsi/ufs/ufshcd.c|   86 -
 3 files changed, 39 insertions(+), 120 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c
index 5cb1d75..48be39a 100644
--- a/drivers/scsi/ufs/ufshcd-pci.c
+++ b/drivers/scsi/ufs/ufshcd-pci.c
@@ -92,7 +92,6 @@ static void ufshcd_pci_remove(struct pci_dev *pdev)
struct ufs_hba *hba = pci_get_drvdata(pdev);
 
disable_irq(pdev->irq);
-   free_irq(pdev->irq, hba);
ufshcd_remove(hba);
pci_release_regions(pdev);
pci_set_drvdata(pdev, NULL);
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index 3db2ee1..0e48827 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -33,9 +33,10 @@
  * this program.
  */
 
-#include "ufshcd.h"
 #include 
 
+#include "ufshcd.h"
+
 #ifdef CONFIG_PM
 /**
  * ufshcd_pltfrm_suspend - suspend power management function
@@ -97,62 +98,45 @@ static int ufshcd_pltfrm_probe(struct platform_device *pdev)
struct ufs_hba *hba;
void __iomem *mmio_base;
struct resource *mem_res;
-   struct resource *irq_res;
-   resource_size_t mem_size;
-   int err;
+   int irq, err;
struct device *dev = &pdev->dev;
 
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem_res) {
-   dev_err(&pdev->dev,
-   "Memory resource not available\n");
+   dev_err(dev, "Memory resource not available\n");
err = -ENODEV;
-   goto out_error;
+   goto out;
}
 
-   mem_size = resource_size(mem_res);
-   if (!request_mem_region(mem_res->start, mem_size, "ufshcd")) {
-   dev_err(&pdev->dev,
-   "Cannot reserve the memory resource\n");
-   err = -EBUSY;
-   goto out_error;
+   mmio_base = devm_ioremap_resource(dev, mem_res);
+   if (IS_ERR(mmio_base)) {
+   dev_err(dev, "memory map failed\n");
+   err = PTR_ERR(mmio_base);
+   goto out;
}
 
-   mmio_base = ioremap_nocache(mem_res->start, mem_size);
-   if (!mmio_base) {
-   dev_err(&pdev->dev, "memory map failed\n");
-   err = -ENOMEM;
-   goto out_release_regions;
-   }
-
-   irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-   if (!irq_res) {
-   dev_err(&pdev->dev, "IRQ resource not available\n");
+   irq = platform_get_irq(pdev, 0);
+   if (irq < 0) {
+   dev_err(dev, "IRQ resource not available\n");
err = -ENODEV;
-   goto out_iounmap;
+   goto out;
}
 
err = dma_set_coherent_mask(dev, dev->coherent_dma_mask);
if (err) {
-   dev_err(&pdev->dev, "set dma mask failed\n");
-   goto out_iounmap;
+   dev_err(dev, "set dma mask failed\n");
+   goto out;
}
 
-   err = ufshcd_init(&pdev->dev, &hba, mmio_base, irq_res->start);
+   err = ufshcd_init(dev, &hba, mmio_base, irq);
if (err) {
-   dev_err(&pdev->dev, "Intialization failed\n");
-   goto out_iounmap;
+   dev_err(dev, "Intialization failed\n");
+   goto out;
}
 
platform_set_drvdata(pdev, hba);
 
-   return 0;
-
-out_iounmap:
-   iounmap(mmio_base);
-out_release_regions:
-   release_mem_region(mem_res->start, mem_size);
-out_error:
+out:
return err;
 }
 
@@ -164,26 +148,10 @@ out_error:
  */
 static int ufshcd_pltfrm_remove(struct platform_device *pdev)
 {
-   struct resource *mem_res;
-   resource_size_t mem_size;
struct ufs_hba *hba =  platform_get_drvdata(pdev);
 
disable_irq(hba->irq);
-
-   /* Some buggy controllers raise interrupt after
-* the resources are removed. So first we unregister the
-* irq handler and then the resources used by driver
-*/
-
-   free_irq(hba->irq, hba);
ufshcd_remove(hba);
-   mem_res = platform_get_resource

RE: [PATCH V3 1/2] scsi: ufs: Add support for sending NOP OUT UPIU

2013-07-10 Thread Seungwon Jeon
;   hba->outstanding_reqs = 0;
>   hba->outstanding_tasks = 0;
> @@ -1199,27 +1539,37 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, 
> struct ufshcd_lrb *lrbp)
> 
>   switch (ocs) {
>   case OCS_SUCCESS:
> -
>   /* check if the returned transfer response is valid */
As replaced with new function, comment isn't valid.
Remove or "get the TR response transaction type" seems proper.

> - result = ufshcd_is_valid_req_rsp(lrbp->ucd_rsp_ptr);
> - if (result) {
> + result = ufshcd_get_req_rsp(lrbp->ucd_rsp_ptr);
> +
> + switch (result) {
> + case UPIU_TRANSACTION_RESPONSE:
> + /*
> +  * get the response UPIU result to extract
> +  * the SCSI command status
> +  */
> + result = ufshcd_get_rsp_upiu_result(lrbp->ucd_rsp_ptr);
> +
> + /*
> +  * get the result based on SCSI status response
> +  * to notify the SCSI midlayer of the command status
> +  */
> + scsi_status = result & MASK_SCSI_STATUS;
> + result = ufshcd_scsi_cmd_status(lrbp, scsi_status);
> + break;
> + case UPIU_TRANSACTION_REJECT_UPIU:
> + /* TODO: handle Reject UPIU Response */
> + result = DID_ERROR << 16;
> + dev_err(hba->dev,
> + "Reject UPIU not fully implemented\n");
> + break;
> + default:
> + result = DID_ERROR << 16;
>   dev_err(hba->dev,
> - "Invalid response = %x\n", result);
> + "Unexpected request response code = %x\n",
> + result);
>   break;
>   }
> -
> - /*
> -  * get the response UPIU result to extract
> -  * the SCSI command status
> -  */
> - result = ufshcd_get_rsp_upiu_result(lrbp->ucd_rsp_ptr);
> -
> - /*
> -  * get the result based on SCSI status response
> -  * to notify the SCSI midlayer of the command status
> -  */
> - scsi_status = result & MASK_SCSI_STATUS;
> - result = ufshcd_scsi_cmd_status(lrbp, scsi_status);
>   break;
>   case OCS_ABORTED:
>   result |= DID_ABORT << 16;
> @@ -1259,28 +1609,37 @@ static void ufshcd_uic_cmd_compl(struct ufs_hba *hba)
>   */
>  static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
>  {
> - struct ufshcd_lrb *lrb;
> + struct ufshcd_lrb *lrbp;
> + struct scsi_cmnd *cmd;
>   unsigned long completed_reqs;
>   u32 tr_doorbell;
>   int result;
>   int index;
> + bool int_aggr_reset = false;
> 
> - lrb = hba->lrb;
>   tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
>   completed_reqs = tr_doorbell ^ hba->outstanding_reqs;
> 
>   for (index = 0; index < hba->nutrs; index++) {
>   if (test_bit(index, &completed_reqs)) {
> -
> - result = ufshcd_transfer_rsp_status(hba, &lrb[index]);
> -
> - if (lrb[index].cmd) {
> - scsi_dma_unmap(lrb[index].cmd);
> - lrb[index].cmd->result = result;
> - lrb[index].cmd->scsi_done(lrb[index].cmd);
> -
> + lrbp = &hba->lrb[index];
> + cmd = lrbp->cmd;
> + /* Don't reset counters for interrupt cmd */
> + int_aggr_reset |= !lrbp->intr_cmd;
> +
> + if (cmd) {
> + result = ufshcd_transfer_rsp_status(hba, lrbp);
> + scsi_dma_unmap(cmd);
> + cmd->result = result;
>   /* Mark completed command as NULL in LRB */
> - lrb[index].cmd = NULL;
> + lrbp->cmd = NULL;
> + clear_bit_unlock(index, &hba->lrb_in_use);
> + /* Do not touch lrbp after scsi done */
> + cmd->scsi_done(cmd);
> + } else if (lrbp->command_type ==
> + UTP_CMD_TYPE_DEV_MANAGE) {
> + 

RE: [PATCH V3 2/2] scsi: ufs: Set fDeviceInit flag to initiate device initialization

2013-07-10 Thread Seungwon Jeon
ance
> + * query_opcode: flag query to perform
> + * idn: flag idn to access
> + * flag_res: the flag value after the query request completes
> + *
> + * Returns 0 for success, non-zero in case of failure
> + */
> +static int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
> + enum flag_idn idn, bool *flag_res)
> +{
> + struct ufs_query_req *query;
> + struct ufs_query_res *response;
> + int err = -ENOMEM;
> +
> + query = kzalloc(sizeof(struct ufs_query_req), GFP_KERNEL);
> + if (!query) {
> + dev_err(hba->dev,
> + "%s: Failed allocating ufs_query_req instance\n",
> + __func__);
> + goto out_no_mem;
> + }
> + response = kzalloc(sizeof(struct ufs_query_res), GFP_KERNEL);
> + if (!response) {
> + dev_err(hba->dev,
> + "%s: Failed allocating ufs_query_res instance\n",
> + __func__);
> + goto out_free_query;
> + }
Can't stack local variable be permitted for query and response instead of 
dynamic allocation?

> +
> + switch (opcode) {
> + case UPIU_QUERY_OPCODE_SET_FLAG:
> + case UPIU_QUERY_OPCODE_CLEAR_FLAG:
> + case UPIU_QUERY_OPCODE_TOGGLE_FLAG:
> + query->query_func = UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST;
> + break;
> + case UPIU_QUERY_OPCODE_READ_FLAG:
> + query->query_func = UPIU_QUERY_FUNC_STANDARD_READ_REQUEST;
> + if (!flag_res) {
> + /* No dummy reads */
> + dev_err(hba->dev, "%s: Invalid argument for read 
> request\n",
> + __func__);
> + err = -EINVAL;
> + goto out;
> + }
> + break;
> + default:
> + dev_err(hba->dev,
> + "%s: Expected query flag opcode but got = %d\n",
> + __func__, opcode);
> + err = -EINVAL;
> + goto out;
> + }
> + query->upiu_req.opcode = opcode;
> + query->upiu_req.idn = idn;
> +
> + /* Send query request */
> + err = ufshcd_send_query_request(hba, query, NULL, response);
> +
> + if (err) {
> + dev_err(hba->dev,
> + "%s: Sending flag query for idn %d failed, err = %d\n",
> + __func__, idn, err);
> + goto out;
> + }
> +
> + if (flag_res)
> + *flag_res = (response->upiu_res.value &
> + MASK_QUERY_UPIU_FLAG_LOC) & 0x1;
> +
> +out:
> + kfree(response);
> +out_free_query:
> + kfree(query);
> +out_no_mem:
> + return err;
> +}
> +
> +/**
>   * ufshcd_memory_alloc - allocate memory for host memory space data 
> structures
>   * @hba: per adapter instance
>   *
> @@ -1110,6 +1343,59 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba)
>  }
> 
>  /**
> + * ufshcd_validate_device_init() - checks device readiness
> + * hba: per-adapter instance
> + *
> + * Set fDeviceInit flag, than, query the flag until the device clears the
> + * flag.
> + */
> +static int ufshcd_validate_device_init(struct ufs_hba *hba)
As standard description, this function is for initialization completion.
How  about ufshcd_complete_dev_init for function name?

> +{
> + int i, retries, err = 0;
> + bool flag_res = 0;
> +
> + for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) {
> + /* Set the fDeviceIntit flag */
> + err = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_SET_FLAG,
> + QUERY_FLAG_IDN_FDEVICEINIT, &flag_res);
There is no need to get  flag_res in case set flag.
Just passing NULL is good.

> + if (!err || err == -ETIMEDOUT)
> + break;
> + dev_dbg(hba->dev, "%s: error %d retrying\n", __func__, err);
> + }
> + if (err) {
> + dev_err(hba->dev,
> + "%s setting fDeviceInit flag failed with error %d\n",
> + __func__, err);
> + goto out;
> + }
> +
> + /* poll for max. 100 iterations for fDeviceInit flag to clear */
> + for (i = 0; i < 100 && !err && flag_res; i++) {
In first ufshcd_query_flag, if flag_res is updated with '0', this loop can't be 
executed.
Of course, we expect that flag_res has '1'.

> + retries = QUERY_REQ_RETRIES;
> + for (retries = QUERY_REQ_RETRIES; r

RE: [PATCH V3 1/2] scsi: ufs: Add support for host assisted background operations

2013-07-10 Thread Seungwon Jeon
I'm not sure that BKOPS with runtime-pm associates.
Do you think it's helpful for power management?
How about hibernation scheme for runtime-pm?
I'm testing and I can introduce soon.

On Tue, July 09, 2013, Sujit Reddy Thumma wrote:
> Background operations in the UFS device can be disabled by
> the host to reduce the response latency of transfer requests.
> Add support for enabling/disabling the background operations
> during runtime suspend/resume of the device.
> 
> If the device is in critical need of BKOPS it will raise an
> URGENT_BKOPS exception which should be handled by the host to
> make sure the device performs as expected.
> 
> During bootup, the BKOPS is enabled in the device by default.
> The disable of BKOPS is supported only when the driver supports
> runtime suspend/resume operations as the runtime PM framework
> provides a way to determine the device idleness and hence BKOPS
> can be managed effectively. During runtime resume the BKOPS is
> disabled to reduce latency and during runtime suspend the BKOPS
> is enabled to allow device to carry out idle time BKOPS.
> 
> In some cases where the BKOPS is disabled during runtime resume
> and due to continuous data transfers the runtime suspend is not
> triggered, the BKOPS is enabled when the device raises a level-2
> exception (outstanding operations - performance impact).
> 
> Signed-off-by: Sujit Reddy Thumma 
> ---
>  drivers/scsi/ufs/ufs.h|   25 -
>  drivers/scsi/ufs/ufshcd.c |  338 
> +
>  drivers/scsi/ufs/ufshcd.h |   10 ++
>  3 files changed, 372 insertions(+), 1 deletions(-)
> 
> diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
> index db5bde4..549a652 100644
> --- a/drivers/scsi/ufs/ufs.h
> +++ b/drivers/scsi/ufs/ufs.h
> @@ -107,7 +107,29 @@ enum {
> 
>  /* Flag idn for Query Requests*/
>  enum flag_idn {
> - QUERY_FLAG_IDN_FDEVICEINIT = 0x01,
> + QUERY_FLAG_IDN_FDEVICEINIT  = 0x01,
> + QUERY_FLAG_IDN_BKOPS_EN = 0x04,
> +};
> +
> +/* Attribute idn for Query requests */
> +enum attr_idn {
> + QUERY_ATTR_IDN_BKOPS_STATUS = 0x05,
> + QUERY_ATTR_IDN_EE_CONTROL   = 0x0D,
> + QUERY_ATTR_IDN_EE_STATUS= 0x0E,
> +};
> +
> +/* Exception event mask values */
> +enum {
> + MASK_EE_STATUS  = 0x,
> + MASK_EE_URGENT_BKOPS= (1 << 2),
> +};
> +
> +/* Background operation status */
> +enum {
> + BKOPS_STATUS_NO_OP   = 0x0,
> + BKOPS_STATUS_NON_CRITICAL= 0x1,
> + BKOPS_STATUS_PERF_IMPACT = 0x2,
> + BKOPS_STATUS_CRITICAL= 0x3,
>  };
> 
>  /* UTP QUERY Transaction Specific Fields OpCode */
> @@ -156,6 +178,7 @@ enum {
>   MASK_TASK_RESPONSE  = 0xFF00,
>   MASK_RSP_UPIU_RESULT= 0x,
>   MASK_QUERY_DATA_SEG_LEN = 0x,
> + MASK_RSP_EXCEPTION_EVENT = 0x1,
>  };
> 
>  /* Task management service response */
> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> index 96ccb28..a25de66 100644
> --- a/drivers/scsi/ufs/ufshcd.c
> +++ b/drivers/scsi/ufs/ufshcd.c
> @@ -268,6 +268,21 @@ ufshcd_get_rsp_upiu_result(struct utp_upiu_rsp 
> *ucd_rsp_ptr)
>  }
> 
>  /**
> + * ufshcd_is_exception_event - Check if the device raised an exception event
> + * @ucd_rsp_ptr: pointer to response UPIU
> + *
> + * The function checks if the device raised an exception event indicated in
> + * the Device Information field of response UPIU.
> + *
> + * Returns true if exception is raised, false otherwise.
> + */
> +static inline bool ufshcd_is_exception_event(struct utp_upiu_rsp 
> *ucd_rsp_ptr)
> +{
> + return be32_to_cpu(ucd_rsp_ptr->header.dword_2) &
> + MASK_RSP_EXCEPTION_EVENT ? true : false;
> +}
> +
> +/**
>   * ufshcd_config_int_aggr - Configure interrupt aggregation values.
>   *   Currently there is no use case where we want to configure
>   *   interrupt aggregation dynamically. So to configure interrupt
> @@ -1174,6 +1189,86 @@ out_no_mem:
>  }
> 
>  /**
> + * ufshcd_query_attr - Helper function for composing attribute requests
> + * hba: per-adapter instance
> + * opcode: attribute opcode
> + * idn: attribute idn to access
> + * index: index field
> + * selector: selector field
> + * attr_val: the attribute value after the query request completes
> + *
> + * Returns 0 for success, non-zero in case of failure
> +*/
> +int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode,
> + enum attr_idn idn, u8 index, u8 selector, u32 *attr_val)
> +{
> + struct ufs_query_req *q

RE: [PATCH V3 2/2] scsi: ufs: Add runtime PM support for UFS host controller driver

2013-07-10 Thread Seungwon Jeon
> --- a/drivers/scsi/ufs/ufshcd-pltfrm.c
> +++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
> @@ -34,6 +34,7 @@
>   */
> 
>  #include 
> +#include 
> 
>  #include "ufshcd.h"
> 
> @@ -87,6 +88,43 @@ static int ufshcd_pltfrm_resume(struct device *dev)
>  #define ufshcd_pltfrm_resume NULL
>  #endif
> 
> +#ifdef CONFIG_PM_RUNTIME
> +static int ufshcd_pltfrm_runtime_suspend(struct device *dev)
> +{
> + struct platform_device *pdev = to_platform_device(dev);
> + struct ufs_hba *hba =  platform_get_drvdata(pdev);
Same as above.

> +
> + if (!hba)
> + return 0;
> +
> + return ufshcd_runtime_suspend(hba);
> +}
> +static int ufshcd_pltfrm_runtime_resume(struct device *dev)
> +{
> + struct platform_device *pdev = to_platform_device(dev);
> + struct ufs_hba *hba =  platform_get_drvdata(pdev);
Same as above.

> +
> + if (!hba)
> + return 0;
> +
> + return ufshcd_runtime_resume(hba);
> +}
> +static int ufshcd_pltfrm_runtime_idle(struct device *dev)
> +{
> + struct platform_device *pdev = to_platform_device(dev);
> + struct ufs_hba *hba =  platform_get_drvdata(pdev);
Same as above.

> +
> + if (!hba)
> + return 0;
> +
> + return ufshcd_runtime_idle(hba);
> +}
> +#else /* !CONFIG_PM_RUNTIME */
> +#define ufshcd_pltfrm_runtime_suspendNULL
> +#define ufshcd_pltfrm_runtime_resume NULL
> +#define ufshcd_pltfrm_runtime_idle   NULL
> +#endif /* CONFIG_PM_RUNTIME */
> +
>  /**
>   * ufshcd_pltfrm_probe - probe routine of the driver
>   * @pdev: pointer to Platform device handle
> @@ -122,14 +160,20 @@ static int ufshcd_pltfrm_probe(struct platform_device 
> *pdev)
>   goto out;
>   }
> 
> + pm_runtime_set_active(&pdev->dev);
> + pm_runtime_enable(&pdev->dev);
> +
>   err = ufshcd_init(dev, &hba, mmio_base, irq);
>   if (err) {
>   dev_err(dev, "Intialization failed\n");
> - goto out;
> + goto out_disable_rpm;
>   }
> 
>   platform_set_drvdata(pdev, hba);
> 
> +out_disable_rpm:
> + pm_runtime_disable(&pdev->dev);
> + pm_runtime_set_suspended(&pdev->dev);
>  out:
>   return err;
>  }
> @@ -144,6 +188,8 @@ static int ufshcd_pltfrm_remove(struct platform_device 
> *pdev)
>  {
>   struct ufs_hba *hba =  platform_get_drvdata(pdev);
> 
> + pm_runtime_get_sync(&(pdev)->dev);
> +
>   disable_irq(hba->irq);
>   ufshcd_remove(hba);
>   return 0;
> @@ -157,6 +203,9 @@ static const struct of_device_id ufs_of_match[] = {
>  static const struct dev_pm_ops ufshcd_dev_pm_ops = {
>   .suspend= ufshcd_pltfrm_suspend,
>   .resume = ufshcd_pltfrm_resume,
> + .runtime_suspend = ufshcd_pltfrm_runtime_suspend,
> + .runtime_resume  = ufshcd_pltfrm_runtime_resume,
> + .runtime_idle= ufshcd_pltfrm_runtime_idle,
>  };
> 
>  static struct platform_driver ufshcd_pltfrm_driver = {
> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> index a25de66..af7d01d 100644
> --- a/drivers/scsi/ufs/ufshcd.c
> +++ b/drivers/scsi/ufs/ufshcd.c
> @@ -2230,6 +2230,7 @@ static void ufshcd_exception_event_handler(struct 
> work_struct *work)
>   u32 status = 0;
>   hba = container_of(work, struct ufs_hba, eeh_work);
> 
> + pm_runtime_get_sync(hba->dev);
>   err = ufshcd_get_ee_status(hba, &status);
>   if (err) {
>   dev_err(hba->dev, "%s: failed to get exception status %d\n",
> @@ -2245,6 +2246,7 @@ static void ufshcd_exception_event_handler(struct 
> work_struct *work)
>   __func__, err);
>   }
>  out:
> + pm_runtime_put_sync(hba->dev);
In ufshcd_urgent_bkops, ufshcd_enable_auto_bkops will be executed.

>   return;
>  }
> 
> @@ -2257,9 +2259,11 @@ static void ufshcd_fatal_err_handler(struct 
> work_struct *work)
>   struct ufs_hba *hba;
>   hba = container_of(work, struct ufs_hba, feh_workq);
> 
> + pm_runtime_get_sync(hba->dev);
>   /* check if reset is already in progress */
>   if (hba->ufshcd_state != UFSHCD_STATE_RESET)
>   ufshcd_do_reset(hba);
> + pm_runtime_put_sync(hba->dev);
>  }
> 
>  /**
> @@ -2562,6 +2566,7 @@ static void ufshcd_async_scan(void *data, 
> async_cookie_t cookie)
>   hba->auto_bkops_enabled = false;
In the end of 'ufshcd_init', pm_runtime_get_sync is called, hence 
auto_bkops_enabled may has false.
'auto_bkops_enabled = false' is needed?

>   ufshcd_enable_auto_bkops(h

RE: [PATCH V3 1/2] scsi: ufs: Add support for host assisted background operations

2013-07-17 Thread Seungwon Jeon
On Thu, July 11, 2013, Sujit Reddy Thumma wrote:
> On 7/10/2013 7:01 PM, Seungwon Jeon wrote:
> > I'm not sure that BKOPS with runtime-pm associates.
> > Do you think it's helpful for power management?
> > How about hibernation scheme for runtime-pm?
> > I'm testing and I can introduce soon.
> 
> Well, I am thinking on following approach when we introduce
> power management.
> 
> ufshcd_runtime_suspend() {
>   if (bkops_status >= NON_CRITICAL) { /* 0x1 */
>   ufshcd_enable_auto_bkops();
>   hibernate(); /* only the link and the device
>   should be able to cary out bkops */
>   } else {
>   hibernate(); /* Link and the device for more savings */
>   }
> }
> 
> Let me know if this is okay.
I still consider whether BKOPS is proper behavior with runtime-pm or not.
How about this scenario? It seems more simple.
If we concern a response latency of transfer requests, BKOPS can be disabled by 
default.
And then BKOPS can be enabled whenever device requests in some exception.
If you have any idea, let me know.

Thanks,
Seungwon Jeon

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: [PATCH V3 1/2] scsi: ufs: Add support for sending NOP OUT UPIU

2013-07-17 Thread Seungwon Jeon
On Thu, July 11, 2013, Sujit Reddy Thumma wrote:
> On 7/10/2013 6:58 PM, Seungwon Jeon wrote:
> > On Tue, July 09, 2013, Sujit Reddy Thumma wrote:
> >> As part of device initialization sequence, sending NOP OUT UPIU and
> >> waiting for NOP IN UPIU response is mandatory. This confirms that the
> >> device UFS Transport (UTP) layer is functional and the host can configure
> >> the device with further commands. Add support for sending NOP OUT UPIU to
> >> check the device connection path and test whether the UTP layer on the
> >> device side is functional during initialization.
> >>
> >> A tag is acquired from the SCSI tag map space in order to send the device
> >> management command. When the tag is acquired by internal command the scsi
> >> command is rejected with host busy flag in order to requeue the request.
> >> To avoid frequent collisions between internal commands and scsi commands
> >> the device management command tag is allocated in the opposite direction
> >> w.r.t block layer tag allocation.
> >>
> >> Signed-off-by: Sujit Reddy Thumma 
> >> Signed-off-by: Dolev Raviv 
> >> ---
> >>   drivers/scsi/ufs/ufs.h|   43 +++-
> >>   drivers/scsi/ufs/ufshcd.c |  596 
> >> +
> >>   drivers/scsi/ufs/ufshcd.h |   29 ++-
> >>   3 files changed, 552 insertions(+), 116 deletions(-)
> >>
> >> diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
> >> index 139bc06..14c0a4e 100644
> >> --- a/drivers/scsi/ufs/ufs.h
> >> +++ b/drivers/scsi/ufs/ufs.h
> >> @@ -36,10 +36,16 @@
> >>   #ifndef _UFS_H
> >>   #define _UFS_H
> >>
> >> +#include 
> >> +#include 
> >> +
> >>   #define MAX_CDB_SIZE 16
> >> +#define GENERAL_UPIU_REQUEST_SIZE 32
> >> +#define UPIU_HEADER_DATA_SEGMENT_MAX_SIZE ((ALIGNED_UPIU_SIZE) - \
> >> +  (GENERAL_UPIU_REQUEST_SIZE))
> >>
> >>   #define UPIU_HEADER_DWORD(byte3, byte2, byte1, byte0)\
> >> -  ((byte3 << 24) | (byte2 << 16) |\
> >> +  cpu_to_be32((byte3 << 24) | (byte2 << 16) |\
> >> (byte1 << 8) | (byte0))
> >>
> >>   /*
> >> @@ -73,6 +79,7 @@ enum {
> >>UPIU_TRANSACTION_TASK_RSP   = 0x24,
> >>UPIU_TRANSACTION_READY_XFER = 0x31,
> >>UPIU_TRANSACTION_QUERY_RSP  = 0x36,
> >> +  UPIU_TRANSACTION_REJECT_UPIU= 0x3F,
> >>   };
> >>
> >>   /* UPIU Read/Write flags */
> >> @@ -110,6 +117,12 @@ enum {
> >>UPIU_COMMAND_SET_TYPE_QUERY = 0x2,
> >>   };
> >>
> >> +/* UTP Transfer Request Command Offset */
> >> +#define UPIU_COMMAND_TYPE_OFFSET  28
> >> +
> >> +/* Offset of the response code in the UPIU header */
> >> +#define UPIU_RSP_CODE_OFFSET  8
> >> +
> >>   enum {
> >>MASK_SCSI_STATUS= 0xFF,
> >>MASK_TASK_RESPONSE  = 0xFF00,
> >> @@ -138,26 +151,32 @@ struct utp_upiu_header {
> >>
> >>   /**
> >>* struct utp_upiu_cmd - Command UPIU structure
> >> - * @header: UPIU header structure DW-0 to DW-2
> >>* @data_transfer_len: Data Transfer Length DW-3
> >>* @cdb: Command Descriptor Block CDB DW-4 to DW-7
> >>*/
> >>   struct utp_upiu_cmd {
> >> -  struct utp_upiu_header header;
> >>u32 exp_data_transfer_len;
> >>u8 cdb[MAX_CDB_SIZE];
> >>   };
> >>
> >>   /**
> >> - * struct utp_upiu_rsp - Response UPIU structure
> >> - * @header: UPIU header DW-0 to DW-2
> >> + * struct utp_upiu_req - general upiu request structure
> >> + * @header:UPIU header structure DW-0 to DW-2
> >> + * @sc: fields structure for scsi command DW-3 to DW-7
> >> + */
> >> +struct utp_upiu_req {
> >> +  struct utp_upiu_header header;
> >> +  struct utp_upiu_cmd sc;
> >> +};
> >> +
> >> +/**
> >> + * struct utp_cmd_rsp - Response UPIU structure
> >>* @residual_transfer_count: Residual transfer count DW-3
> >>* @reserved: Reserved double words DW-4 to DW-7
> >>* @sense_data_len: Sense data length DW-8 U16
> >>* @sense_data: Sense data field DW-8 to DW-12
> >>*/
> >> -struct utp_upiu_rsp {
> >> -  struct utp_upiu_header header;
> >> +struct utp_c

RE: [PATCH V3 2/2] scsi: ufs: Set fDeviceInit flag to initiate device initialization

2013-07-17 Thread Seungwon Jeon
ev, "%s: Invalid argument for read 
> >> request\n",
> + __func__);
> >> +  err = -EINVAL;
> >> +  goto out;
> >> +  }
> >> +  break;
> >> +  default:
> >> +  dev_err(hba->dev,
> >> +  "%s: Expected query flag opcode but got = %d\n",
> >> +  __func__, opcode);
> >> +  err = -EINVAL;
> >> +  goto out;
> >> +  }
> >> +  query->upiu_req.opcode = opcode;
> >> +  query->upiu_req.idn = idn;
> >> +
> >> +  /* Send query request */
> >> +  err = ufshcd_send_query_request(hba, query, NULL, response);
> >> +
> >> +  if (err) {
> >> +  dev_err(hba->dev,
> >> +  "%s: Sending flag query for idn %d failed, err = %d\n",
> >> +  __func__, idn, err);
> >> +  goto out;
> >> +  }
> >> +
> >> +  if (flag_res)
> >> +  *flag_res = (response->upiu_res.value &
> >> +  MASK_QUERY_UPIU_FLAG_LOC) & 0x1;
> >> +
> >> +out:
> >> +  kfree(response);
> >> +out_free_query:
> >> +  kfree(query);
> >> +out_no_mem:
> >> +  return err;
> >> +}
> >> +
> >> +/**
> >>   * ufshcd_memory_alloc - allocate memory for host memory space data
> >> structures
> >>   * @hba: per adapter instance
> >>   *
> >> @@ -1110,6 +1343,59 @@ static int ufshcd_dme_link_startup(struct
> ufs_hba
> >> *hba)
> >>  }
> >>  /**
> >> + * ufshcd_validate_device_init() - checks device readiness
> >> + * hba: per-adapter instance
> >> + *
> >> + * Set fDeviceInit flag, than, query the flag until the device clears the
> >> + * flag.
> >> + */
> >> +static int ufshcd_validate_device_init(struct ufs_hba *hba)
> > As standard description, this function is for initialization completion.
> How  about ufshcd_complete_dev_init for function name?
> You have a point.
> >> +{
> >> +  int i, retries, err = 0;
> >> +  bool flag_res = 0;
> >> +
> >> +  for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) {
> >> +  /* Set the fDeviceIntit flag */
> >> +  err = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_SET_FLAG,
> >> +  QUERY_FLAG_IDN_FDEVICEINIT, &flag_res);
> > There is no need to get  flag_res in case set flag.
> > Just passing NULL is good.
> Consider the following scenario: a device is already fully initialized
> when we init the driver, in this case setting the flag will return 0 since
> no further initialization is required. This means we don't have to query
> again or to poll for the fDeviceInit because we already now the
> initialization is completed.
It's not clear.
I think it may be a broad interpretation.
What's the meaning of returned flag_res?
1. original value 
2. value which is applied by setting the fDeviceInit flag
3. value which is applied by setting the fDeviceInit flag and reset 

In this step, query is not for read-flag but for set-flag.
Above all, spec. mentions polling the fDeviceInit using read-flag definitively.

> >> +  if (!err || err == -ETIMEDOUT)
> >> +  break;
> >> +  dev_dbg(hba->dev, "%s: error %d retrying\n", __func__, err); +  
> >> }
> >> +  if (err) {
> >> +  dev_err(hba->dev,
> >> +  "%s setting fDeviceInit flag failed with error %d\n",
> >> +  __func__, err);
> >> +  goto out;
> >> +  }
> >> +
> >> +  /* poll for max. 100 iterations for fDeviceInit flag to clear */
> + for (i = 0; i < 100 && !err && flag_res; i++) {
> > In first ufshcd_query_flag, if flag_res is updated with '0', this loop
> can't be executed.
> > Of course, we expect that flag_res has '1'.
> In the described case above, this condition allows us to skip the polling
> process.
> 
> >> +  retries = QUERY_REQ_RETRIES;
> >> +  for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) {
> >> +  err = ufshcd_query_flag(hba,
> >> +  UPIU_QUERY_OPCODE_READ_FLAG,
> >> +  QUERY_FLAG_IDN_FDEVICEINIT, &flag_res);
> >> +  if (!err || err == -ETIMEDOUT)
> >> +  break;
> > Normally, ufshcd_query_flag returns '0' to err while flag is not being
> cleared.
> > If these routine is repeated, inner for-loop is just executed and go to
> outer loop.
> > What is difference between two for-loop?
> Your analysis was correct, each loop has a different responsibility. The
> outer loop counts the poling retries, while the inner loop is responsible
> for passing the query request to the device without errors. So the inner
> loop will execute more then once iff there was an error and the request
> was not executed properly.
I wonder that valid result comes after error is happened and retry is taken.
Should we allow the retry in case errors?

Thanks,
Seungwon Jeon

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: [PATCH V3 1/2] scsi: ufs: Add support for sending NOP OUT UPIU

2013-07-19 Thread Seungwon Jeon
   usleep_range(interval_us, interval_us + 50);
> >>>> +tmp = ufshcd_readl(hba, reg);
> >>>> +diff = ktime_to_ms(ktime_sub(ktime_get(), start));
> >>>> +if (diff > timeout_ms) {
> >>>> +tmp = ufshcd_readl(hba, reg);
> >>>> +break;
> >>>> +}
> >>>> +}
> >>>> +out:
> >>>> +return tmp;
> >>>> +}
> >>>> +
> ..
> >>>> +static int
> >>>> +ufshcd_clear_cmd(struct ufs_hba *hba, int tag)
> >>>> +{
> >>>> +int err = 0;
> >>>> +unsigned long flags;
> >>>> +u32 reg;
> >>>> +u32 mask = 1 << tag;
> >>>> +
> >>>> +/* clear outstanding transaction before retry */
> >>>> +spin_lock_irqsave(hba->host->host_lock, flags);
> >>>> +ufshcd_utrl_clear(hba, tag);
> >>>> +spin_unlock_irqrestore(hba->host->host_lock, flags);
> >>>> +
> >>>> +/*
> >>>> + * wait for for h/w to clear corresponding bit in door-bell.
> >>>> + * max. wait is 1 sec.
> >>>> + */
> >>>> +reg = ufshcd_wait_for_register(hba,
> >>>> +REG_UTP_TRANSFER_REQ_DOOR_BELL,
> >>>> +mask, 0, 1000, 1000);
> >>> 4th argument should be (~mask) instead of '0', right?
> >>
> >> True, but not really for this implementation. It breaks the check in
> >> in wait_for_register -
> >> if ((val & mask) != val)
> >>  dev_err(...);
> > Hmm, it seems complicated to use.
> > Ok. Is right the following about val as 4th argument?
> > - clear: val  should be '0' regardless corresponding bit.
> > - set: val should be same with mask.
> > If the related comment is added, it will be helpful.
> 
> Thinking again it looks like it is complicated. How about changing
> the check to -
> 
> val = val & mask; /* ignore the bits we don't intend to wait on */
> while (ufshcd_readl() & mask != val) {
>   sleep
> }
> 
> Usage will be ~mask for clearing the bits, mask for setting the bits
> in the fourth argument.
Ok.
It's better for the caller.

> 
> >
> >>
> >>> Actually, mask value involves the corresponding bit to be cleared.
> >>> So, 4th argument may be unnecessary.
> >>
> >> As I described above, the wait_for_register can also be used to
> >> check if the value is set or not. In which case, we need 4th argument.
> >>
> >>>
> >>>> +if ((reg & mask) == mask)
> >>>> +err = -ETIMEDOUT;
> >>> Also, checking the result can be involved in ufshcd_wait_for_register.
> > Any comment?
> 
> Sorry I missed this. But the point was the same. To make
> wait_for_register() just to wait a definite time and not return any
> error condition when the bits don't turn as expected.
Comparing reg with mask can be done in 'ufshcd_wait_for_register' commonly.
Currently the caller do the same.

Thanks,
Seungwon Jeon

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: [PATCH V3 2/2] scsi: ufs: Set fDeviceInit flag to initiate device initialization

2013-07-19 Thread Seungwon Jeon
> know
> >> >> + * there is only one active query request or any device management
> >> command
> >> >> + * at all times.
> >> >> + */
> >> >> +static int ufshcd_send_query_request(struct ufs_hba *hba,
> >> >> +   struct ufs_query_req *query,
> >> >> +   u8 *descriptor,
> >> >> +   struct ufs_query_res *response)
> >> >> +{
> >> >> +   int ret;
> >> >> +
> >> >> +   BUG_ON(!hba);
> >> >> +   if (!query || !response) {
> >> >> +   dev_err(hba->dev,
> >> >> +   "%s: NULL pointer query = %p, response = %p\n",
> >> >> +   __func__, query, response);
> >> >> +   return -EINVAL;
> >> >> +   }
> >> >> +
> >> >> +   mutex_lock(&hba->dev_cmd.lock);
> >> >> +   hba->dev_cmd.query.request = query;
> >> >> +   hba->dev_cmd.query.response = response;
> >> >> +   hba->dev_cmd.query.descriptor = descriptor;
> >> >> +
> >> >> +   ret = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY,
> >> >> +   QUERY_REQ_TIMEOUT);
> >> >> +
> >> >> +   hba->dev_cmd.query.request = NULL;
> >> >> +   hba->dev_cmd.query.response = NULL;
> >> >> +   hba->dev_cmd.query.descriptor = NULL;
> >> >> +   mutex_unlock(&hba->dev_cmd.lock);
> >> >> +
> >> >> +   return ret;
> >> >> +}
> >> >> +
> >> >> +/**
> >> >> + * ufshcd_query_flag() - Helper function for composing flag query
> >> requests
> >> >> + * hba: per-adapter instance
> >> >> + * query_opcode: flag query to perform
> >> >> + * idn: flag idn to access
> >> >> + * flag_res: the flag value after the query request completes
> >> >> + *
> >> >> + * Returns 0 for success, non-zero in case of failure
> >> >> + */
> >> >> +static int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode
> >> opcode,
> >> >> +   enum flag_idn idn, bool *flag_res)
> >> >> +{
> >> >> +   struct ufs_query_req *query;
> >> >> +   struct ufs_query_res *response;
> >> >> +   int err = -ENOMEM;
> >> >> +
> >> >> +   query = kzalloc(sizeof(struct ufs_query_req), GFP_KERNEL);
> >> >> +   if (!query) {
> >> >> +   dev_err(hba->dev,
> >> >> +   "%s: Failed allocating ufs_query_req 
> >> >> instance\n",
> >> >> +   __func__);
> >> >> +   goto out_no_mem;
> >> >> +   }
> >> >> +   response = kzalloc(sizeof(struct ufs_query_res), GFP_KERNEL); + 
> >> >> if
> >> (!response) {
> >> >> +   dev_err(hba->dev,
> >> >> +   "%s: Failed allocating ufs_query_res 
> >> >> instance\n",
> >> >> +   __func__);
> >> >> +   goto out_free_query;
> >> >> +   }
> >> > Can't stack local variable be permitted for query and response instead
> >> of
> >> > dynamic allocation?
> >> It can, though I think it is safer this way. In addition, this code is
> >> not
> >> a bottle neck.
> > Yes, once may not be a problem. But I am seeing this function is called
> > from some loop routine.
> > Could you explain the reason dynamic allocation is needed?
> I don't like the idea of allocating it on stack, I suggest to statically
> allocate it on the query struct. What do you think?
Yes.

> >
> >> >> +
> >> >> +   switch (opcode) {
> >> >> +   case UPIU_QUERY_OPCODE_SET_FLAG:
> >> >> +   case UPIU_QUERY_OPCODE_CLEAR_FLAG:
> >> >> +   case UPIU_QUERY_OPCODE_TOGGLE_FLAG:
> >> >> +   query->query_func = 
> >> >> UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST;
> >> >> +   break;
> >> >>

RE: [PATCH V3 1/2] scsi: ufs: Add support for host assisted background operations

2013-07-19 Thread Seungwon Jeon
On Thu, July 18, 2013, Sujit Reddy Thumma wrote:
> >>> > >I'm not sure that BKOPS with runtime-pm associates.
> >>> > >Do you think it's helpful for power management?
> >>> > >How about hibernation scheme for runtime-pm?
> >>> > >I'm testing and I can introduce soon.
> >> >
> >> >Well, I am thinking on following approach when we introduce
> >> >power management.
> >> >
> >> >ufshcd_runtime_suspend() {
> >> >  if (bkops_status >= NON_CRITICAL) { /* 0x1 */
> >> >  ufshcd_enable_auto_bkops();
> >> >  hibernate(); /* only the link and the device
> >> >  should be able to cary out bkops */
> >> >  } else {
> >> >  hibernate(); /* Link and the device for more savings */
> >> >  }
> >> >}
> >> >
> >> >Let me know if this is okay.
> > I still consider whether BKOPS is proper behavior with runtime-pm or not.
> 
> The BKOPS is something that host allows the card to carry out
> when the host knows it is idle and not expecting back to back requests.
> Runtime PM idle is the only way to know whether the device is
> idle (unless we want to reinvent the wheel to detect the idleness of
> host and trigger bkops). There was a discussion on this in MMC mailing
> list as well, and folks have agreed to move idle time bkops to runtime
> PM (http://thread.gmane.org/gmane.linux.kernel.mmc/19444/)
It looks like different.
eMMC cannot execute BKOPS itself unlike UFS.
That's the way eMMC's host should trigger the BKOPS manually.

> 
> > How about this scenario? It seems more simple.
> > If we concern a response latency of transfer requests, BKOPS can be 
disabled by default.
> > And then BKOPS can be enabled whenever device requests in some exception.
> > If you have any idea, let me know.
> 
> Exceptions are raised only when the device is in critical need for
> bkops. Also the spec. recommends, host should ensure that the device
> doesn't go into such states.
> 
> With your suggestion, when we disable bkops, the exception is raised and
> we enable bkops after which there is no way to disable it again?
Yes, it's difficult to find proper time. 
Maybe, BKOPS can be disabled when request comes up.

Thanks,
Seungwon Jeon
> 
> --
> Regards,
> Sujit
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majord...@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: [PATCH V3 1/4] scsi: ufs: Fix broken task management command implementation

2013-07-19 Thread Seungwon Jeon
_param2 = lrbp->task_tag;
> - task_req_upiup->input_param2 =
> - cpu_to_be32(task_req_upiup->input_param2);
> + task_req_upiup->input_param1 = cpu_to_be32(lun_id);
> + task_req_upiup->input_param2 = cpu_to_be32(task_id);
> 
>   /* send command to the controller */
>   __set_bit(free_slot, &hba->outstanding_tasks);
> @@ -2411,20 +2453,24 @@ ufshcd_issue_tm_cmd(struct ufs_hba *hba,
>   spin_unlock_irqrestore(host->host_lock, flags);
> 
>   /* wait until the task management command is completed */
> - err =
> - wait_event_interruptible_timeout(hba->ufshcd_tm_wait_queue,
> -  (test_bit(free_slot,
> -  &hba->tm_condition) != 0),
> -  60 * HZ);
> + err = wait_event_timeout(hba->tm_wq,
> + test_bit(free_slot, &hba->tm_condition),
> + msecs_to_jiffies(TM_CMD_TIMEOUT));
>   if (!err) {
> - dev_err(hba->dev,
> - "Task management command timed-out\n");
> - err = FAILED;
> - goto out;
> + dev_err(hba->dev, "%s: task management cmd 0x%.2x timed-out\n",
> + __func__, tm_function);
> + if (ufshcd_clear_tm_cmd(hba, free_slot))
> + dev_WARN(hba->dev, "%s: unable clear tm cmd (slot %d) 
> after timeout\n",
> + __func__, free_slot);
> + err = -ETIMEDOUT;
> + } else {
> + err = ufshcd_task_req_compl(hba, free_slot, tm_response);
>   }
> +
>   clear_bit(free_slot, &hba->tm_condition);
> - err = ufshcd_task_req_compl(hba, free_slot);
> -out:
> + ufshcd_put_tm_slot(hba, free_slot);
> + wake_up(&hba->tm_tag_wq);
> +
>   return err;
>  }
> 
> @@ -2441,14 +2487,22 @@ static int ufshcd_device_reset(struct scsi_cmnd *cmd)
>   unsigned int tag;
>   u32 pos;
>   int err;
> + u8 resp;
> + struct ufshcd_lrb *lrbp;
> 
>   host = cmd->device->host;
>   hba = shost_priv(host);
>   tag = cmd->request->tag;
> 
> - err = ufshcd_issue_tm_cmd(hba, &hba->lrb[tag], UFS_LOGICAL_RESET);
> - if (err == FAILED)
> + lrbp = &hba->lrb[tag];
> + err = ufshcd_issue_tm_cmd(hba, lrbp->lun, lrbp->task_tag,
Argument 2nd, 3rd can be replaced by lrbp.
Then, we can reduce the number of argument.

Thanks,
Seungwon Jeon

> + UFS_LOGICAL_RESET, &resp);
> + if (err || resp != UPIU_TASK_MANAGEMENT_FUNC_COMPL) {
> + err = FAILED;
>   goto out;
> + } else {
> + err = SUCCESS;
> + }
> 
>   for (pos = 0; pos < hba->nutrs; pos++) {
>   if (test_bit(pos, &hba->outstanding_reqs) &&
> @@ -2505,6 +2559,8 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
>   unsigned long flags;
>   unsigned int tag;
>   int err;
> + u8 resp;
> + struct ufshcd_lrb *lrbp;
> 
>   host = cmd->device->host;
>   hba = shost_priv(host);
> @@ -2520,9 +2576,15 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
>   }
>   spin_unlock_irqrestore(host->host_lock, flags);
> 
> - err = ufshcd_issue_tm_cmd(hba, &hba->lrb[tag], UFS_ABORT_TASK);
> - if (err == FAILED)
> + lrbp = &hba->lrb[tag];
> + err = ufshcd_issue_tm_cmd(hba, lrbp->lun, lrbp->task_tag,
> + UFS_ABORT_TASK, &resp);
> + if (err || resp != UPIU_TASK_MANAGEMENT_FUNC_COMPL) {
> + err = FAILED;
>   goto out;
> + } else {
> + err = SUCCESS;
> + }
> 
>   scsi_dma_unmap(cmd);
> 
> @@ -2744,7 +2806,8 @@ int ufshcd_init(struct device *dev, struct ufs_hba 
> **hba_handle,
>   host->max_cmd_len = MAX_CDB_SIZE;
> 
>   /* Initailize wait queue for task management */
> - init_waitqueue_head(&hba->ufshcd_tm_wait_queue);
> + init_waitqueue_head(&hba->tm_wq);
> + init_waitqueue_head(&hba->tm_tag_wq);
> 
>   /* Initialize work queues */
>   INIT_WORK(&hba->feh_workq, ufshcd_fatal_err_handler);
> diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
> index 6c9bd35..5d4542c 100644
> --- a/drivers/scsi/ufs/ufshcd.h
> +++ b/drivers/scsi/ufs/ufshcd.h
> @@ -174,8 +174,10 @@ struct ufs_dev_cmd {
>   * @irq: Irq number of the controller
>   * @active_uic_cmd: handle of active UIC command
>   * @uic_cmd_mutex: mutex for uic command
> - * @ufshcd_tm_wait_queue: wait queue for task management
> + * @tm_wq: wait queue for task management
> + * @tm_tag_wq: wait queue for free task management slots
>   * @tm_condition: condition variable for task management
> + * @tm_slots_in_use: bit map of task management request slots in use
>   * @ufshcd_state: UFSHCD states
>   * @intr_mask: Interrupt Mask Bits
>   * @ee_ctrl_mask: Exception event control mask
> @@ -216,8 +218,10 @@ struct ufs_hba {
>   struct uic_command *active_uic_cmd;
>   struct mutex uic_cmd_mutex;
> 
> - wait_queue_head_t ufshcd_tm_wait_queue;
> + wait_queue_head_t tm_wq;
> + wait_queue_head_t tm_tag_wq;
>   unsigned long tm_condition;
> + unsigned long tm_slots_in_use;
> 
>   u32 ufshcd_state;
>   u32 intr_mask;
> --
> QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
> of Code Aurora Forum, hosted by The Linux Foundation.
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majord...@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: [PATCH V3 3/4] scsi: ufs: Fix device and host reset methods

2013-07-19 Thread Seungwon Jeon
st_lock, flags);
> + ufshcd_hba_stop(hba);
> + spin_unlock_irqrestore(hba->host->host_lock, flags);
> 
> - if (hba->ufshcd_state == UFSHCD_STATE_RESET)
> - return SUCCESS;
> + err = ufshcd_hba_enable(hba);
> + if (err)
> + goto out;
> 
> - return ufshcd_do_reset(hba);
> + /* Establish the link again and restore the device */
> + cookie = async_schedule(ufshcd_async_scan, hba);
> + /* wait for async scan to be completed */
> + async_synchronize_cookie(++cookie);
> + if (hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL)
> + err = -EIO;
> +out:
> + if (err)
> + dev_err(hba->dev, "%s: Host init failed %d\n", __func__, err);
> + else
> + ufshcd_clear_host_reset_pending(hba);
> +
> + dev_dbg(hba->dev, "%s: done err = %d\n", __func__, err);
> + return err;
>  }
> 
>  /**
> @@ -2644,6 +2861,134 @@ out:
>  }
> 
>  /**
> + * ufshcd_reset_and_restore - resets device or host or both
> + * @hba: per-adapter instance
> + *
> + * Reset and recover device, host and re-establish link. This
> + * is helpful to recover the communication in fatal error conditions.
> + *
> + * Returns zero on success, non-zero on failure
> + */
> +static int ufshcd_reset_and_restore(struct ufs_hba *hba)
> +{
> + int err = 0;
> +
> + if (ufshcd_device_reset_pending(hba) &&
> + !ufshcd_host_reset_pending(hba)) {
> + err = ufshcd_device_reset_and_restore(hba);
> + if (err) {
> + ufshcd_clear_device_reset_pending(hba);
> + ufshcd_set_host_reset_pending(hba);
> + }
> + }
> +
> + if (ufshcd_host_reset_pending(hba))
> + err = ufshcd_host_reset_and_restore(hba);
> +
> + /*
> +  * Due to reset the door-bell might be cleared, clear
> +  * outstanding requests in s/w here.
> +  */
> + ufshcd_complete_pending_reqs(hba);
After above, pending requests will be completed by ufshcd_transfer_req_compl.
'cmd->result' which is reported to scsi mid-layer should be a failure.
I think it may not be guaranteed.

> + ufshcd_complete_pending_tasks(hba);
> +
> + return err;
> +}
> +
> +/**
> + * ufshcd_eh_device_reset_handler - device reset handler registered to
> + *scsi layer.
> + * @cmd - SCSI command pointer
> + *
> + * Returns SUCCESS/FAILED
> + */
> +static int ufshcd_eh_device_reset_handler(struct scsi_cmnd *cmd)
> +{
> + struct ufs_hba *hba;
> + int err;
> + unsigned long flags;
> +
> + hba = shost_priv(cmd->device->host);
> +
> + /*
> +  * Check if there is any race with fatal error handling.
> +  * If so, wait for it to complete. Even though fatal error
> +  * handling does reset and restore in some cases, don't assume
> +  * anything out of it. We are just avoiding race here.
> +  */
> + do {
> + spin_lock_irqsave(hba->host->host_lock, flags);
> + if (!(work_pending(&hba->feh_workq) ||
> + hba->ufshcd_state == UFSHCD_STATE_RESET))
> + break;
> + spin_unlock_irqrestore(hba->host->host_lock, flags);
> + dev_dbg(hba->dev, "%s: reset in progress\n", __func__);
> + flush_work_sync(&hba->feh_workq);
> + } while (1);
> +
> + hba->ufshcd_state = UFSHCD_STATE_RESET;
> + ufshcd_set_device_reset_pending(hba);
> + spin_unlock_irqrestore(hba->host->host_lock, flags);
> +
> + err = ufshcd_reset_and_restore(hba);
> +
> + spin_lock_irqsave(hba->host->host_lock, flags);
> + if (!err) {
> + err = SUCCESS;
> + hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL;
> + } else {
> + err = FAILED;
> + hba->ufshcd_state = UFSHCD_STATE_ERROR;
> + }
> + spin_unlock_irqrestore(hba->host->host_lock, flags);
> +
> + return err;
> +}
> +
> +/**
> + * ufshcd_eh_host_reset_handler - host reset handler registered to scsi layer
> + * @cmd - SCSI command pointer
> + *
> + * Returns SUCCESS/FAILED
> + */
> +static int ufshcd_eh_host_reset_handler(struct scsi_cmnd *cmd)
> +{
> + struct ufs_hba *hba;
> + int err;
> + unsigned long flags;
> +
> + hba = shost_priv(cmd->device->host);
> +
> + do {
> + spin_lock_irqsave(hba->host->host_lock, flags);
> + if (!(work_pending(&hba->feh_workq) ||
> + 

RE: [PATCH V3 2/4] scsi: ufs: Fix hardware race conditions while aborting a command

2013-07-19 Thread Seungwon Jeon
On Tue, July 09, 2013, Sujit Reddy Thumma wrote:
> There is a possible race condition in the hardware when the abort
> command is issued to terminate the ongoing SCSI command as described
> below:
> 
> - A bit in the door-bell register is set in the controller for a
>   new SCSI command.
> - In some rare situations, before controller get a chance to issue
>   the command to the device, the software issued an abort command.
It's interesting.
I wonder when we can meet this situation.
Is it possible if SCSI mid layer should send abort command as soon as the 
transfer command is issued?
AFAIK abort command is followed if one command has timed out.
That means command have been already issued and no response?
If you had some problem, could you share?

> - If the device recieves abort command first then it returns success
receives

>   because the command itself is not present.
> - Now if the controller commits the command to device it will be
>   processed.
> - Software thinks that command is aborted and proceed while still
>   the device is processing it.
> - The software, controller and device may go out of sync because of
>   this race condition.
> 
> To avoid this, query task presence in the device before sending abort
> task command so that after the abort operation, the command is guaranteed
> to be non-existent in both controller and the device.
> 
> Signed-off-by: Sujit Reddy Thumma 
> ---
>  drivers/scsi/ufs/ufshcd.c |   70 +++-
>  1 files changed, 55 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> index a176421..51ce096 100644
> --- a/drivers/scsi/ufs/ufshcd.c
> +++ b/drivers/scsi/ufs/ufshcd.c
> @@ -2550,6 +2550,12 @@ static int ufshcd_host_reset(struct scsi_cmnd *cmd)
>   * ufshcd_abort - abort a specific command
>   * @cmd: SCSI command pointer
>   *
> + * Abort the pending command in device by sending UFS_ABORT_TASK task 
> management
> + * command, and in host controller by clearing the door-bell register. There 
> can
> + * be race between controller sending the command to the device while abort 
> is
> + * issued. To avoid that, first issue UFS_QUERY_TASK to check if the command 
> is
> + * really issued and then try to abort it.
> + *
>   * Returns SUCCESS/FAILED
>   */
>  static int ufshcd_abort(struct scsi_cmnd *cmd)
> @@ -2558,7 +2564,8 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
>   struct ufs_hba *hba;
>   unsigned long flags;
>   unsigned int tag;
> - int err;
> + int err = 0;
> + int poll_cnt;
>   u8 resp;
>   struct ufshcd_lrb *lrbp;
> 
> @@ -2566,33 +2573,59 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
>   hba = shost_priv(host);
>   tag = cmd->request->tag;
> 
> - spin_lock_irqsave(host->host_lock, flags);
> + /* If command is already aborted/completed, return SUCCESS */
> + if (!(test_bit(tag, &hba->outstanding_reqs)))
> + goto out;
> 
> - /* check if command is still pending */
> - if (!(test_bit(tag, &hba->outstanding_reqs))) {
> - err = FAILED;
> - spin_unlock_irqrestore(host->host_lock, flags);
> + lrbp = &hba->lrb[tag];
> + for (poll_cnt = 100; poll_cnt; poll_cnt--) {
> + err = ufshcd_issue_tm_cmd(hba, lrbp->lun, lrbp->task_tag,
> + UFS_QUERY_TASK, &resp);
> + if (!err && resp == UPIU_TASK_MANAGEMENT_FUNC_SUCCEEDED) {
> + /* cmd pending in the device */
> + break;
> + } else if (!err && resp == UPIU_TASK_MANAGEMENT_FUNC_COMPL) {
> + u32 reg;
> +
> + /*
> +  * cmd not pending in the device, check if it is
> +  * in transition.
> +  */
> + reg = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
> + if (reg & (1 << tag)) {
> + /* sleep for max. 2ms to stabilize */
> + usleep_range(1000, 2000);
> + continue;
> + }
> + /* command completed already */
> + goto out;
> + } else {
> + if (!err)
> + err = resp; /* service response error */
> + goto out;
> + }
> + }
> +
> + if (!poll_cnt) {
> + err = -EBUSY;
>   goto out;
>   }
> - spin_unlock_irqrestore(host->host_lock, flags);
> 
> - lrbp = &hba->lrb[tag];
>   err = ufshcd_issue_tm_cmd(hba, lrbp->lun, lrbp->task_tag,
>   UFS_ABORT_TASK, &resp);
>   if (err || resp != UPIU_TASK_MANAGEMENT_FUNC_COMPL) {
> - err = FAILED;
> + if (!err)
> + err = resp; /* service response error */
>   goto out;
> - } else {
> - err = SUCC

RE: [PATCH V3 4/4] scsi: ufs: Improve UFS fatal error handling

2013-07-19 Thread Seungwon Jeon
_ERROR |
> + UFSHCD_UIC_DME_ERROR)) {
> + /* non-fatal, report error to SCSI layer */
> + if (!hba->eh_flags) {
> + spin_unlock_irqrestore(
> + hba->host->host_lock, flags);
> + ufshcd_complete_pending_reqs(hba);
> + ufshcd_complete_pending_tasks(hba);
> + spin_lock_irqsave(hba->host->host_lock, flags);
> + }
> + }
> + }
> + spin_unlock_irqrestore(hba->host->host_lock, flags);
> +
> + if (hba->eh_flags) {
> + err = ufshcd_reset_and_restore(hba);
> + if (err) {
> + ufshcd_clear_host_reset_pending(hba);
> + ufshcd_clear_device_reset_pending(hba);
> + dev_err(hba->dev, "%s: reset and restore failed\n",
> + __func__);
> + hba->ufshcd_state = UFSHCD_STATE_ERROR;
> + }
> + /*
> +  * Inform scsi mid-layer that we did reset and allow to handle
> +  * Unit Attention properly.
> +  */
> + scsi_report_bus_reset(hba->host, 0);
> + hba->errors = 0;
> + hba->uic_error = 0;
> + }
> + scsi_unblock_requests(hba->host);
>   pm_runtime_put_sync(hba->dev);
>  }
> 
>  /**
> - * ufshcd_err_handler - Check for fatal errors
> - * @work: pointer to a work queue structure
> + * ufshcd_update_uic_error - check and set fatal UIC error flags.
> + * @hba: per-adapter instance
>   */
> -static void ufshcd_err_handler(struct ufs_hba *hba)
> +static void ufshcd_update_uic_error(struct ufs_hba *hba)
>  {
>   u32 reg;
> 
> + /* PA_INIT_ERROR is fatal and needs UIC reset */
> + reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_DATA_LINK_LAYER);
> + if (reg & UIC_DATA_LINK_LAYER_ERROR_PA_INIT)
> + hba->uic_error |= UFSHCD_UIC_DL_PA_INIT_ERROR;
> +
> + /* UIC NL/TL/DME errors needs software retry */
> + reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_NETWORK_LAYER);
> + if (reg)
> + hba->uic_error |= UFSHCD_UIC_NL_ERROR;
> +
> + reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_TRANSPORT_LAYER);
> + if (reg)
> + hba->uic_error |= UFSHCD_UIC_TL_ERROR;
> +
> + reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_DME);
> + if (reg)
> + hba->uic_error |= UFSHCD_UIC_DME_ERROR;
REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER is not handled.

> +
> + dev_dbg(hba->dev, "%s: UIC error flags = 0x%08x\n",
> + __func__, hba->uic_error);
> +}
> +
> +/**
> + * ufshcd_err_handler - Check for fatal errors
> + * @hba: per-adapter instance
> + */
> +static void ufshcd_err_handler(struct ufs_hba *hba)
> +{
>   if (hba->errors & INT_FATAL_ERRORS)
>   goto fatal_eh;
> 
>   if (hba->errors & UIC_ERROR) {
> - reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_DATA_LINK_LAYER);
> - if (reg & UIC_DATA_LINK_LAYER_ERROR_PA_INIT)
> + hba->uic_error = 0;
> + ufshcd_update_uic_error(hba);
> + if (hba->uic_error)
Except UFSHCD_UIC_DL_PA_INIT_ERROR, it's not fatal. Should it go to fatal_eh?

Thanks,
Seungwon Jeon

>   goto fatal_eh;
>   }
> + /*
> +  * Other errors are either non-fatal or completed by the
> +  * controller by updating OCS fields with success/failure.
> +  */
>   return;
> +
>  fatal_eh:
>   /* handle fatal errors only when link is functional */
>   if (hba->ufshcd_state == UFSHCD_STATE_OPERATIONAL) {
> + /* block commands from midlayer */
> + scsi_block_requests(hba->host);
>   /* block commands at driver layer until error is handled */
>   hba->ufshcd_state = UFSHCD_STATE_ERROR;
>   schedule_work(&hba->feh_workq);
> diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
> index 7fcedd0..4ee4d1a 100644
> --- a/drivers/scsi/ufs/ufshcd.h
> +++ b/drivers/scsi/ufs/ufshcd.h
> @@ -185,6 +185,7 @@ struct ufs_dev_cmd {
>   * @feh_workq: Work queue for fatal controller error handling
>   * @eeh_work: Worker to handle exception events
>   * @errors: HBA errors
> + * @uic_error: UFS interconnect layer error status
>   * @dev_cmd: ufs device management command information
>   * @auto_bkops_enabled: to track whether bkops is enabled in device

RE: [PATCH V3 1/4] scsi: ufs: Fix broken task management command implementation

2013-07-23 Thread Seungwon Jeon
On Sat, July 20, 2013, Sujit Reddy Thumma wrote:
> On 7/19/2013 7:26 PM, Seungwon Jeon wrote:
> > On Tue, July 09, 2013 Sujit Reddy Thumma wrote:
> >> Currently, sending Task Management (TM) command to the card might
> >> be broken in some scenarios as listed below:
> >>
> >> Problem: If there are more than 8 TM commands the implementation
> >>   returns error to the caller.
> >> Fix: Wait for one of the slots to be emptied and send the command.
> >>
> >> Problem: Sometimes it is necessary for the caller to know the TM service
> >>   response code to determine the task status.
> >> Fix: Propogate the service response to the caller.
> >>
> >> Problem: If the TM command times out no proper error recovery is
> >>   implemented.
> >> Fix: Clear the command in the controller door-bell register, so that
> >>   further commands for the same slot don't fail.
> >>
> >> Problem: While preparing the TM command descriptor, the task tag used
> >>   should be unique across SCSI/NOP/QUERY/TM commands and not the
> >> task tag of the command which the TM command is trying to manage.
> >> Fix: Use a unique task tag instead of task tag of SCSI command.
> >>
> >> Problem: Since the TM command involves H/W communication, abruptly ending
> >>   the request on kill interrupt signal might cause h/w malfunction.
> >> Fix: Wait for hardware completion interrupt with TASK_UNINTERRUPTIBLE
> >>   set.
> >>
> >> Signed-off-by: Sujit Reddy Thumma 
> >> ---
> >>   drivers/scsi/ufs/ufshcd.c |  177 
> >> ++---
> >>   drivers/scsi/ufs/ufshcd.h |8 ++-
> >>   2 files changed, 126 insertions(+), 59 deletions(-)
> >>
> >> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> >> index af7d01d..a176421 100644
> >> --- a/drivers/scsi/ufs/ufshcd.c
> >> +++ b/drivers/scsi/ufs/ufshcd.c
> >> @@ -53,6 +53,9 @@
> >>   /* Query request timeout */
> >>   #define QUERY_REQ_TIMEOUT 30 /* msec */
> >>
> >> +/* Task management command timeout */
> >> +#define TM_CMD_TIMEOUT100 /* msecs */
> >> +
> >>   /* Expose the flag value from utp_upiu_query.value */
> >>   #define MASK_QUERY_UPIU_FLAG_LOC 0xFF
> >>
> >> @@ -190,13 +193,35 @@ ufshcd_get_tmr_ocs(struct utp_task_req_desc 
> >> *task_req_descp)
> >>   /**
> >>* ufshcd_get_tm_free_slot - get a free slot for task management request
> >>* @hba: per adapter instance
> >> + * @free_slot: pointer to variable with available slot value
> >>*
> >> - * Returns maximum number of task management request slots in case of
> >> - * task management queue full or returns the free slot number
> >> + * Get a free tag and lock it until ufshcd_put_tm_slot() is called.
> >> + * Returns 0 if free slot is not available, else return 1 with tag value
> >> + * in @free_slot.
> >>*/
> >> -static inline int ufshcd_get_tm_free_slot(struct ufs_hba *hba)
> >> +static bool ufshcd_get_tm_free_slot(struct ufs_hba *hba, int *free_slot)
> >> +{
> >> +  int tag;
> >> +  bool ret = false;
> >> +
> >> +  if (!free_slot)
> >> +  goto out;
> >> +
> >> +  do {
> >> +  tag = find_first_zero_bit(&hba->tm_slots_in_use, hba->nutmrs);
> >> +  if (tag >= hba->nutmrs)
> >> +  goto out;
> >> +  } while (test_and_set_bit_lock(tag, &hba->tm_slots_in_use));
> >> +
> >> +  *free_slot = tag;
> >> +  ret = true;
> >> +out:
> >> +  return ret;
> >> +}
> >> +
> >> +static inline void ufshcd_put_tm_slot(struct ufs_hba *hba, int slot)
> >>   {
> >> -  return find_first_zero_bit(&hba->outstanding_tasks, hba->nutmrs);
> >> +  clear_bit_unlock(slot, &hba->tm_slots_in_use);
> >>   }
> >>
> >>   /**
> >> @@ -1778,10 +1803,11 @@ static void ufshcd_slave_destroy(struct 
> >> scsi_device *sdev)
> >>* ufshcd_task_req_compl - handle task management request completion
> >>* @hba: per adapter instance
> >>* @index: index of the completed request
> >> + * @resp: task management service response
> >>*
> >> - * Returns SUCCESS/FAILED
> >> + 

RE: [PATCH V3 3/4] scsi: ufs: Fix device and host reset methods

2013-07-23 Thread Seungwon Jeon
On Sat, July 20, 2013, Sujit Reddy Thumma wrote:
> On 7/19/2013 7:27 PM, Seungwon Jeon wrote:
> > On Tue, July 09, 2013, Sujit Reddy Thumma wrote:
> >> As of now SCSI initiated error handling is broken because,
> >> the reset APIs don't try to bring back the device initialized and
> >> ready for further transfers.
> >>
> >> In case of timeouts, the scsi error handler takes care of handling aborts
> >> and resets. Improve the error handling in such scenario by resetting the
> >> device and host and re-initializing them in proper manner.
> >>
> >> Signed-off-by: Sujit Reddy Thumma 
> >> ---
> >>   drivers/scsi/ufs/ufshcd.c |  467 
> >> +++--
> >>   drivers/scsi/ufs/ufshcd.h |2 +
> >>   2 files changed, 411 insertions(+), 58 deletions(-)
> >>
> >> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> >> index 51ce096..b4c9910 100644
> >> --- a/drivers/scsi/ufs/ufshcd.c
> >> +++ b/drivers/scsi/ufs/ufshcd.c
> >> @@ -69,9 +69,15 @@ enum {
> >>
> >>   /* UFSHCD states */
> >>   enum {
> >> -  UFSHCD_STATE_OPERATIONAL,
> >>UFSHCD_STATE_RESET,
> >>UFSHCD_STATE_ERROR,
> >> +  UFSHCD_STATE_OPERATIONAL,
> >> +};
> >> +
> >> +/* UFSHCD error handling flags */
> >> +enum {
> >> +  UFSHCD_EH_HOST_RESET_PENDING = (1 << 0),
> >> +  UFSHCD_EH_DEVICE_RESET_PENDING = (1 << 1),
> >>   };
> >>
> >>   /* Interrupt configuration options */
> >> @@ -87,6 +93,22 @@ enum {
> >>INT_AGGR_CONFIG,
> >>   };
> >>
> >> +#define ufshcd_set_device_reset_pending(h) \
> >> +  (h->eh_flags |= UFSHCD_EH_DEVICE_RESET_PENDING)
> >> +#define ufshcd_set_host_reset_pending(h) \
> >> +  (h->eh_flags |= UFSHCD_EH_HOST_RESET_PENDING)
> >> +#define ufshcd_device_reset_pending(h) \
> >> +  (h->eh_flags & UFSHCD_EH_DEVICE_RESET_PENDING)
> >> +#define ufshcd_host_reset_pending(h) \
> >> +  (h->eh_flags & UFSHCD_EH_HOST_RESET_PENDING)
> >> +#define ufshcd_clear_device_reset_pending(h) \
> >> +  (h->eh_flags &= ~UFSHCD_EH_DEVICE_RESET_PENDING)
> >> +#define ufshcd_clear_host_reset_pending(h) \
> >> +  (h->eh_flags &= ~UFSHCD_EH_HOST_RESET_PENDING)
> >> +
> >> +static void ufshcd_tmc_handler(struct ufs_hba *hba);
> >> +static void ufshcd_async_scan(void *data, async_cookie_t cookie);
> >> +
> >>   /*
> >>* ufshcd_wait_for_register - wait for register value to change
> >>* @hba - per-adapter interface
> >> @@ -851,9 +873,22 @@ static int ufshcd_queuecommand(struct Scsi_Host 
> >> *host, struct scsi_cmnd *cmd)
> >>
> >>tag = cmd->request->tag;
> >>
> >> -  if (hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL) {
> >> +  switch (hba->ufshcd_state) {
> > Lock is no needed for ufshcd_state?
Please check?

> >
> >> +  case UFSHCD_STATE_OPERATIONAL:
> >> +  break;
> >> +  case UFSHCD_STATE_RESET:
> >>err = SCSI_MLQUEUE_HOST_BUSY;
> >>goto out;
> >> +  case UFSHCD_STATE_ERROR:
> >> +  set_host_byte(cmd, DID_ERROR);
> >> +  cmd->scsi_done(cmd);
> >> +  goto out;
> >> +  default:
> >> +  dev_WARN_ONCE(hba->dev, 1, "%s: invalid state %d\n",
> >> +  __func__, hba->ufshcd_state);
> >> +  set_host_byte(cmd, DID_BAD_TARGET);
> >> +  cmd->scsi_done(cmd);
> >> +  goto out;
> >>}
> >>
> >>/* acquire the tag to make sure device cmds don't use it */
> >> @@ -1573,8 +1608,6 @@ static int ufshcd_make_hba_operational(struct 
> >> ufs_hba *hba)
> >>if (hba->ufshcd_state == UFSHCD_STATE_RESET)
> >>scsi_unblock_requests(hba->host);
> >>
> >> -  hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL;
> >> -
> >>   out:
> >>return err;
> >>   }
> >> @@ -2273,6 +2306,106 @@ out:
> >>   }
> >>
> >>   /**
> >> + * ufshcd_utrl_is_rsr_enabled - check if run-stop register is enabled
> >> + * @hba: per-adapter instance
> >> + */
> >> +static bool ufshcd_utrl_is_rsr_enabled(struct ufs_hba *hba)
> >> +{
> >> +  return ufs

RE: [PATCH V3 4/4] scsi: ufs: Improve UFS fatal error handling

2013-07-23 Thread Seungwon Jeon
On Sat, July 20, 2013, Sujit Reddy Thumma wrote:
> On 7/19/2013 7:28 PM, Seungwon Jeon wrote:
> > On Tue, July 09, 2013, Sujit Reddy Thumma wrote:
> >> Error handling in UFS driver is broken and resets the host controller
> >> for fatal errors without re-initialization. Correct the fatal error
> >> handling sequence according to UFS Host Controller Interface (HCI)
> >> v1.1 specification.
> >>
> >> o Upon determining fatal error condition the host controller may hang
> >>forever until a reset is applied, so just retrying the command doesn't
> >>work without a reset. So, the reset is applied in the driver context
> >>in a separate work and SCSI mid-layer isn't informed until reset is
> >>applied.
> >>
> >> o Processed requests which are completed without error are reported to
> >>SCSI layer as successful and any pending commands that are not started
> >>yet or are not cause of the error are re-queued into scsi midlayer 
> >> queue.
> >>For the command that caused error, host controller or device is reset
> >>and DID_ERROR is returned for command retry after applying reset.
> >>
> >> o SCSI is informed about the expected Unit-Attentioni exception from the
> > Attention'i',  typo.
> Okay.
> 
> >
> >>device for the immediate command after a reset so that the SCSI layer
> >>take necessary steps to establish communication with the device.
> >>
> >> Signed-off-by: Sujit Reddy Thumma 
> >> ---
> >>   drivers/scsi/ufs/ufshcd.c |  349 
> >> +++-
> >>   drivers/scsi/ufs/ufshcd.h |2 +
> >>   drivers/scsi/ufs/ufshci.h |   19 ++-
> >>   3 files changed, 295 insertions(+), 75 deletions(-)
> >>
> >> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> >> index b4c9910..2a3874f 100644
> >> --- a/drivers/scsi/ufs/ufshcd.c
> >> +++ b/drivers/scsi/ufs/ufshcd.c
> >> @@ -80,6 +80,14 @@ enum {
> >>UFSHCD_EH_DEVICE_RESET_PENDING = (1 << 1),
> >>   };
> >>
> >> +/* UFSHCD UIC layer error flags */
> >> +enum {
> >> +  UFSHCD_UIC_DL_PA_INIT_ERROR = (1 << 0), /* Data link layer error */
> >> +  UFSHCD_UIC_NL_ERROR = (1 << 1), /* Network layer error */
> >> +  UFSHCD_UIC_TL_ERROR = (1 << 2), /* Transport Layer error */
> >> +  UFSHCD_UIC_DME_ERROR = (1 << 3), /* DME error */
> >> +};
> >> +
> >>   /* Interrupt configuration options */
> >>   enum {
> >>UFSHCD_INT_DISABLE,
> >> @@ -108,6 +116,7 @@ enum {
> >>
> >>   static void ufshcd_tmc_handler(struct ufs_hba *hba);
> >>   static void ufshcd_async_scan(void *data, async_cookie_t cookie);
> >> +static int ufshcd_reset_and_restore(struct ufs_hba *hba);
> >>
> >>   /*
> >>* ufshcd_wait_for_register - wait for register value to change
> >> @@ -1605,9 +1614,6 @@ static int ufshcd_make_hba_operational(struct 
> >> ufs_hba *hba)
> >>goto out;
> >>}
> >>
> >> -  if (hba->ufshcd_state == UFSHCD_STATE_RESET)
> >> -  scsi_unblock_requests(hba->host);
> >> -
> >>   out:
> >>return err;
> >>   }
> >> @@ -1733,66 +1739,6 @@ static int ufshcd_validate_dev_connection(struct 
> >> ufs_hba *hba)
> >>   }
> >>
> >>   /**
> >> - * ufshcd_do_reset - reset the host controller
> >> - * @hba: per adapter instance
> >> - *
> >> - * Returns SUCCESS/FAILED
> >> - */
> >> -static int ufshcd_do_reset(struct ufs_hba *hba)
> >> -{
> >> -  struct ufshcd_lrb *lrbp;
> >> -  unsigned long flags;
> >> -  int tag;
> >> -
> >> -  /* block commands from midlayer */
> >> -  scsi_block_requests(hba->host);
> >> -
> >> -  spin_lock_irqsave(hba->host->host_lock, flags);
> >> -  hba->ufshcd_state = UFSHCD_STATE_RESET;
> >> -
> >> -  /* send controller to reset state */
> >> -  ufshcd_hba_stop(hba);
> >> -  spin_unlock_irqrestore(hba->host->host_lock, flags);
> >> -
> >> -  /* abort outstanding commands */
> >> -  for (tag = 0; tag < hba->nutrs; tag++) {
> >> -  if (test_bit(tag, &hba->outstanding_reqs)) {
> >> -  lrbp = &hba->lrb[tag];
> >> -  if (lrbp-

RE: [PATCH V3 3/4] scsi: ufs: Fix device and host reset methods

2013-07-24 Thread Seungwon Jeon
On Wed, July 24, 2013, Sujit Reddy Thumma wrote:
> On 7/23/2013 1:57 PM, Seungwon Jeon wrote:
> > On Sat, July 20, 2013, Sujit Reddy Thumma wrote:
> >> On 7/19/2013 7:27 PM, Seungwon Jeon wrote:
> >>> On Tue, July 09, 2013, Sujit Reddy Thumma wrote:
> >>>> As of now SCSI initiated error handling is broken because,
> >>>> the reset APIs don't try to bring back the device initialized and
> >>>> ready for further transfers.
> >>>>
> >>>> In case of timeouts, the scsi error handler takes care of handling aborts
> >>>> and resets. Improve the error handling in such scenario by resetting the
> >>>> device and host and re-initializing them in proper manner.
> >>>>
> >>>> Signed-off-by: Sujit Reddy Thumma 
> >>>> ---
> >>>>drivers/scsi/ufs/ufshcd.c |  467 
> >>>> +++--
> >>>>drivers/scsi/ufs/ufshcd.h |2 +
> >>>>2 files changed, 411 insertions(+), 58 deletions(-)
> >>>>
> >>>> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> >>>> index 51ce096..b4c9910 100644
> >>>> --- a/drivers/scsi/ufs/ufshcd.c
> >>>> +++ b/drivers/scsi/ufs/ufshcd.c
> >>>> @@ -69,9 +69,15 @@ enum {
> >>>>
> >>>>/* UFSHCD states */
> >>>>enum {
> >>>> -UFSHCD_STATE_OPERATIONAL,
> >>>>  UFSHCD_STATE_RESET,
> >>>>  UFSHCD_STATE_ERROR,
> >>>> +UFSHCD_STATE_OPERATIONAL,
> >>>> +};
> >>>> +
> >>>> +/* UFSHCD error handling flags */
> >>>> +enum {
> >>>> +UFSHCD_EH_HOST_RESET_PENDING = (1 << 0),
> >>>> +UFSHCD_EH_DEVICE_RESET_PENDING = (1 << 1),
> >>>>};
> >>>>
> >>>>/* Interrupt configuration options */
> >>>> @@ -87,6 +93,22 @@ enum {
> >>>>  INT_AGGR_CONFIG,
> >>>>};
> >>>>
> >>>> +#define ufshcd_set_device_reset_pending(h) \
> >>>> +(h->eh_flags |= UFSHCD_EH_DEVICE_RESET_PENDING)
> >>>> +#define ufshcd_set_host_reset_pending(h) \
> >>>> +(h->eh_flags |= UFSHCD_EH_HOST_RESET_PENDING)
> >>>> +#define ufshcd_device_reset_pending(h) \
> >>>> +(h->eh_flags & UFSHCD_EH_DEVICE_RESET_PENDING)
> >>>> +#define ufshcd_host_reset_pending(h) \
> >>>> +(h->eh_flags & UFSHCD_EH_HOST_RESET_PENDING)
> >>>> +#define ufshcd_clear_device_reset_pending(h) \
> >>>> +(h->eh_flags &= ~UFSHCD_EH_DEVICE_RESET_PENDING)
> >>>> +#define ufshcd_clear_host_reset_pending(h) \
> >>>> +(h->eh_flags &= ~UFSHCD_EH_HOST_RESET_PENDING)
> >>>> +
> >>>> +static void ufshcd_tmc_handler(struct ufs_hba *hba);
> >>>> +static void ufshcd_async_scan(void *data, async_cookie_t cookie);
> >>>> +
> >>>>/*
> >>>> * ufshcd_wait_for_register - wait for register value to change
> >>>> * @hba - per-adapter interface
> >>>> @@ -851,9 +873,22 @@ static int ufshcd_queuecommand(struct Scsi_Host 
> >>>> *host, struct scsi_cmnd *cmd)
> >>>>
> >>>>  tag = cmd->request->tag;
> >>>>
> >>>> -if (hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL) {
> >>>> +switch (hba->ufshcd_state) {
> >>> Lock is no needed for ufshcd_state?
> > Please check?
> 
> Yes, it is needed. Thanks for catching this.
> 
> >
> >>>
> >>>> +case UFSHCD_STATE_OPERATIONAL:
> >>>> +break;
> >>>> +case UFSHCD_STATE_RESET:
> >>>>  err = SCSI_MLQUEUE_HOST_BUSY;
> >>>>  goto out;
> >>>> +case UFSHCD_STATE_ERROR:
> >>>> +set_host_byte(cmd, DID_ERROR);
> >>>> +cmd->scsi_done(cmd);
> >>>> +goto out;
> >>>> +default:
> >>>> +dev_WARN_ONCE(hba->dev, 1, "%s: invalid state %d\n",
> >>>> +__func__, hba->ufshcd_state);
> >>>> +   

RE: [PATCH V3 4/4] scsi: ufs: Improve UFS fatal error handling

2013-07-24 Thread Seungwon Jeon
On Wed, July 24, 2013, Sujit Reddy Thumma wrote:
> On 7/23/2013 2:04 PM, Seungwon Jeon wrote:
> > On Sat, July 20, 2013, Sujit Reddy Thumma wrote:
> >> On 7/19/2013 7:28 PM, Seungwon Jeon wrote:
> >>> On Tue, July 09, 2013, Sujit Reddy Thumma wrote:
> >>>> Error handling in UFS driver is broken and resets the host controller
> >>>> for fatal errors without re-initialization. Correct the fatal error
> >>>> handling sequence according to UFS Host Controller Interface (HCI)
> >>>> v1.1 specification.
> >>>>
> >>>> o Upon determining fatal error condition the host controller may hang
> >>>> forever until a reset is applied, so just retrying the command 
> >>>> doesn't
> >>>> work without a reset. So, the reset is applied in the driver context
> >>>> in a separate work and SCSI mid-layer isn't informed until reset is
> >>>> applied.
> >>>>
> >>>> o Processed requests which are completed without error are reported to
> >>>> SCSI layer as successful and any pending commands that are not 
> >>>> started
> >>>> yet or are not cause of the error are re-queued into scsi midlayer 
> >>>> queue.
> >>>> For the command that caused error, host controller or device is reset
> >>>> and DID_ERROR is returned for command retry after applying reset.
> >>>>
> >>>> o SCSI is informed about the expected Unit-Attentioni exception from the
> >>> Attention'i',  typo.
> >> Okay.
> >>
> >>>
> >>>> device for the immediate command after a reset so that the SCSI layer
> >>>> take necessary steps to establish communication with the device.
> >>>>
> >>>> Signed-off-by: Sujit Reddy Thumma 
> >>>> ---
> >>>>drivers/scsi/ufs/ufshcd.c |  349 
> >>>> +++-
> >>>>drivers/scsi/ufs/ufshcd.h |2 +
> >>>>drivers/scsi/ufs/ufshci.h |   19 ++-
> >>>>3 files changed, 295 insertions(+), 75 deletions(-)
> >>>>
> >>>> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> >>>> index b4c9910..2a3874f 100644
> >>>> --- a/drivers/scsi/ufs/ufshcd.c
> >>>> +++ b/drivers/scsi/ufs/ufshcd.c
> >>>> @@ -80,6 +80,14 @@ enum {
> >>>>  UFSHCD_EH_DEVICE_RESET_PENDING = (1 << 1),
> >>>>};
> >>>>
> >>>> +/* UFSHCD UIC layer error flags */
> >>>> +enum {
> >>>> +UFSHCD_UIC_DL_PA_INIT_ERROR = (1 << 0), /* Data link layer 
> >>>> error */
> >>>> +UFSHCD_UIC_NL_ERROR = (1 << 1), /* Network layer error */
> >>>> +UFSHCD_UIC_TL_ERROR = (1 << 2), /* Transport Layer error */
> >>>> +UFSHCD_UIC_DME_ERROR = (1 << 3), /* DME error */
> >>>> +};
> >>>> +
> >>>>/* Interrupt configuration options */
> >>>>enum {
> >>>>  UFSHCD_INT_DISABLE,
> >>>> @@ -108,6 +116,7 @@ enum {
> >>>>
> >>>>static void ufshcd_tmc_handler(struct ufs_hba *hba);
> >>>>static void ufshcd_async_scan(void *data, async_cookie_t cookie);
> >>>> +static int ufshcd_reset_and_restore(struct ufs_hba *hba);
> >>>>
> >>>>/*
> >>>> * ufshcd_wait_for_register - wait for register value to change
> >>>> @@ -1605,9 +1614,6 @@ static int ufshcd_make_hba_operational(struct 
> >>>> ufs_hba *hba)
> >>>>  goto out;
> >>>>  }
> >>>>
> >>>> -if (hba->ufshcd_state == UFSHCD_STATE_RESET)
> >>>> -scsi_unblock_requests(hba->host);
> >>>> -
> >>>>out:
> >>>>  return err;
> >>>>}
> >>>> @@ -1733,66 +1739,6 @@ static int ufshcd_validate_dev_connection(struct 
> >>>> ufs_hba *hba)
> >>>>}
> >>>>
> >>>>/**
> >>>> - * ufshcd_do_reset - reset the host controller
> >>>> - * @hba: per adapter instance
> >>>> - *
> >>>> - * Returns SUCCESS/FAILED
> >>>> - */
> >

[PATCH 0/7] scsi: ufs: some fixes and updates

2013-07-26 Thread Seungwon Jeon
This path series contain driver's fixes and updates.

Seungwon Jeon (7):
  scsi: ufs: amend the ocs handling with fatal error
  scsi: ufs: find out sense data over scsi status values
  scsi: ufs: fix the setting interrupt aggregation counter
  scsi: ufs: add dme configuration primitives
  scsi: ufs: add unipro attribute IDs
  scsi: ufs: add operation for the uic power mode change
  scsi: ufs: configure the attribute for power mode

 drivers/scsi/ufs/ufs.h|1 +
 drivers/scsi/ufs/ufshcd.c |  325 +++--
 drivers/scsi/ufs/ufshcd.h |   54 
 drivers/scsi/ufs/ufshci.h |   22 +++-
 drivers/scsi/ufs/unipro.h |  151 +
 5 files changed, 507 insertions(+), 46 deletions(-)

Thanks,
Seungwon Jeon

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 1/7] scsi: ufs: amend the ocs handling with fatal error

2013-07-26 Thread Seungwon Jeon
Fatal error in OCS(overall command status) field indicates
error conditions which is not covered by UFSHCI.
It means that host cannot define the result of command status
and therefore host may need to check transfer response UPIU's
response and status field.
It was actually found that 'CHECK CONDITION' is stored in status
field of UPIU where OCS is 'FATAL ERROR'.

Signed-off-by: Seungwon Jeon 
---
 drivers/scsi/ufs/ufshcd.c |3 +--
 1 files changed, 1 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index b743bd6..4cf3a2d 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -1199,7 +1199,7 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct 
ufshcd_lrb *lrbp)
 
switch (ocs) {
case OCS_SUCCESS:
-
+   case OCS_FATAL_ERROR:
/* check if the returned transfer response is valid */
result = ufshcd_is_valid_req_rsp(lrbp->ucd_rsp_ptr);
if (result) {
@@ -1229,7 +1229,6 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct 
ufshcd_lrb *lrbp)
case OCS_MISMATCH_DATA_BUF_SIZE:
case OCS_MISMATCH_RESP_UPIU_SIZE:
case OCS_PEER_COMM_FAILURE:
-   case OCS_FATAL_ERROR:
default:
result |= DID_ERROR << 16;
dev_err(hba->dev,
-- 
1.7.0.4


--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 2/7] scsi: ufs: find out sense data over scsi status values

2013-07-26 Thread Seungwon Jeon
Except for 'GOOD' and 'CHECK CONDITION', other status value
in Response UPIU may or may contain sense data. If a non-zero
value is in the Data Segment Length field, it means that UPIU
has Sense Data in the Data Segment area.

Signed-off-by: Seungwon Jeon 
---
 drivers/scsi/ufs/ufs.h|1 +
 drivers/scsi/ufs/ufshcd.c |   27 +++
 2 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index 139bc06..737c31b 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -114,6 +114,7 @@ enum {
MASK_SCSI_STATUS= 0xFF,
MASK_TASK_RESPONSE  = 0xFF00,
MASK_RSP_UPIU_RESULT= 0x,
+   MASK_RSP_UPIU_DATA_SEG_LEN  = 0x,
 };
 
 /* Task management service response */
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 4cf3a2d..688ae0e 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -218,6 +218,20 @@ ufshcd_get_rsp_upiu_result(struct utp_upiu_rsp 
*ucd_rsp_ptr)
return be32_to_cpu(ucd_rsp_ptr->header.dword_1) & MASK_RSP_UPIU_RESULT;
 }
 
+/*
+ * ufshcd_get_rsp_upiu_data_seg_len - Get the data segment length
+ * from response UPIU
+ * @ucd_rsp_ptr: pointer to response UPIU
+ *
+ * Return the data segment length.
+ */
+static inline int
+ufshcd_get_rsp_upiu_data_seg_len(struct utp_upiu_rsp *ucd_rsp_ptr)
+{
+   return be32_to_cpu(ucd_rsp_ptr->header.dword_2) &
+   MASK_RSP_UPIU_DATA_SEG_LEN;
+}
+
 /**
  * ufshcd_config_int_aggr - Configure interrupt aggregation values.
  * Currently there is no use case where we want to configure
@@ -298,7 +312,8 @@ void ufshcd_send_command(struct ufs_hba *hba, unsigned int 
task_tag)
 static inline void ufshcd_copy_sense_data(struct ufshcd_lrb *lrbp)
 {
int len;
-   if (lrbp->sense_buffer) {
+   if (lrbp->sense_buffer &&
+   !ufshcd_get_rsp_upiu_data_seg_len(lrbp->ucd_rsp_ptr)) {
len = be16_to_cpu(lrbp->ucd_rsp_ptr->sense_data_len);
memcpy(lrbp->sense_buffer,
lrbp->ucd_rsp_ptr->sense_data,
@@ -1156,21 +1171,17 @@ ufshcd_scsi_cmd_status(struct ufshcd_lrb *lrbp, int 
scsi_status)
  SAM_STAT_CHECK_CONDITION;
ufshcd_copy_sense_data(lrbp);
break;
-   case SAM_STAT_BUSY:
-   result |= SAM_STAT_BUSY;
-   break;
case SAM_STAT_TASK_SET_FULL:
-
/*
 * If a LUN reports SAM_STAT_TASK_SET_FULL, then the LUN queue
 * depth needs to be adjusted to the exact number of
 * outstanding commands the LUN can handle at any given time.
 */
ufshcd_adjust_lun_qdepth(lrbp->cmd);
-   result |= SAM_STAT_TASK_SET_FULL;
-   break;
+   case SAM_STAT_BUSY:
case SAM_STAT_TASK_ABORTED:
-   result |= SAM_STAT_TASK_ABORTED;
+   result |= scsi_status;
+   ufshcd_copy_sense_data(lrbp);
break;
default:
result |= DID_ERROR << 16;
-- 
1.7.0.4


--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 3/7] scsi: ufs: fix the setting interrupt aggregation counter

2013-07-26 Thread Seungwon Jeon
LACTH(Interrupt aggregation counter threshold) value is allowed
up to 0x1F and current setting value is the maximum.
This value is related with NUTRS(max:0x20) of HCI's capability.
Considering HCI controller doesn't support the maximum, LATCH
setting should be adjusted with possible value.
For that, existing 'ufshcd_config_int_aggr' is split into two part
[reset, configure].

Signed-off-by: Seungwon Jeon 
---
 drivers/scsi/ufs/ufshcd.c |   53 +---
 drivers/scsi/ufs/ufshci.h |4 +-
 2 files changed, 27 insertions(+), 30 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 688ae0e..7152ec4 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -43,6 +43,9 @@
 /* UIC command timeout, unit: ms */
 #define UIC_CMD_TIMEOUT500
 
+/* Interrupt aggregation default timeout, unit: 40us */
+#define INT_AGGR_DEF_TO0x02
+
 enum {
UFSHCD_MAX_CHANNEL  = 0,
UFSHCD_MAX_ID   = 1,
@@ -65,12 +68,6 @@ enum {
UFSHCD_INT_CLEAR,
 };
 
-/* Interrupt aggregation options */
-enum {
-   INT_AGGR_RESET,
-   INT_AGGR_CONFIG,
-};
-
 /**
  * ufshcd_get_intr_mask - Get the interrupt bit mask
  * @hba - Pointer to adapter instance
@@ -233,30 +230,30 @@ ufshcd_get_rsp_upiu_data_seg_len(struct utp_upiu_rsp 
*ucd_rsp_ptr)
 }
 
 /**
- * ufshcd_config_int_aggr - Configure interrupt aggregation values.
- * Currently there is no use case where we want to configure
- * interrupt aggregation dynamically. So to configure interrupt
- * aggregation, #define INT_AGGR_COUNTER_THRESHOLD_VALUE and
- * INT_AGGR_TIMEOUT_VALUE are used.
+ * ufshcd_reset_intr_aggr - Reset interrupt aggregation values.
  * @hba: per adapter instance
- * @option: Interrupt aggregation option
  */
 static inline void
-ufshcd_config_int_aggr(struct ufs_hba *hba, int option)
+ufshcd_reset_intr_aggr(struct ufs_hba *hba)
 {
-   switch (option) {
-   case INT_AGGR_RESET:
-   ufshcd_writel(hba, INT_AGGR_ENABLE |
- INT_AGGR_COUNTER_AND_TIMER_RESET,
- REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
-   break;
-   case INT_AGGR_CONFIG:
-   ufshcd_writel(hba, INT_AGGR_ENABLE | INT_AGGR_PARAM_WRITE |
- INT_AGGR_COUNTER_THRESHOLD_VALUE |
- INT_AGGR_TIMEOUT_VALUE,
- REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
-   break;
-   }
+   ufshcd_writel(hba, INT_AGGR_ENABLE |
+ INT_AGGR_COUNTER_AND_TIMER_RESET,
+ REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
+}
+
+/**
+ * ufshcd_config_intr_aggr - Configure interrupt aggregation values.
+ * @hba: per adapter instance
+ * @cntr_thld: Interrupt aggregation counter threshold
+ * @timeout: Interrupt aggregation timeout value
+ */
+static inline void
+ufshcd_config_intr_aggr(struct ufs_hba *hba, u8 cnt, u8 timeout)
+{
+   ufshcd_writel(hba, INT_AGGR_ENABLE | INT_AGGR_PARAM_WRITE |
+ INT_AGGR_COUNTER_THLD_VAL(cnt) |
+ INT_AGGR_TIMEOUT_VAL(timeout),
+ REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
 }
 
 /**
@@ -853,7 +850,7 @@ static int ufshcd_make_hba_operational(struct ufs_hba *hba)
ufshcd_enable_intr(hba, UFSHCD_ENABLE_INTRS);
 
/* Configure interrupt aggregation */
-   ufshcd_config_int_aggr(hba, INT_AGGR_CONFIG);
+   ufshcd_config_intr_aggr(hba, hba->nutrs - 1, INT_AGGR_DEF_TO);
 
/* Configure UTRL and UTMRL base address registers */
ufshcd_writel(hba, lower_32_bits(hba->utrdl_dma_addr),
@@ -1299,7 +1296,7 @@ static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
hba->outstanding_reqs ^= completed_reqs;
 
/* Reset interrupt aggregation counters */
-   ufshcd_config_int_aggr(hba, INT_AGGR_RESET);
+   ufshcd_reset_intr_aggr(hba);
 }
 
 /**
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
index d5c5f14..a8f69cc 100644
--- a/drivers/scsi/ufs/ufshci.h
+++ b/drivers/scsi/ufs/ufshci.h
@@ -226,8 +226,8 @@ enum {
 
 #define MASK_UIC_COMMAND_RESULT0xFF
 
-#define INT_AGGR_COUNTER_THRESHOLD_VALUE   (0x1F << 8)
-#define INT_AGGR_TIMEOUT_VALUE (0x02)
+#define INT_AGGR_COUNTER_THLD_VAL(c)   (((c) & 0x1F) << 8)
+#define INT_AGGR_TIMEOUT_VAL(t)(((t) & 0xFF) << 0)
 
 /* Interrupt disable masks */
 enum {
-- 
1.7.0.4


--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 4/7] scsi: ufs: add dme configuration primitives

2013-07-26 Thread Seungwon Jeon
Implements to support GET and SET operations of the DME.
These operations are used to configure the behavior of
the UNIPRO. Along with basic operation, {Peer/AttrSetType}
can be mixed.

Signed-off-by: Seungwon Jeon 
---
 drivers/scsi/ufs/ufshcd.c |   88 +
 drivers/scsi/ufs/ufshcd.h |   51 ++
 drivers/scsi/ufs/ufshci.h |6 +++
 3 files changed, 145 insertions(+), 0 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 7152ec4..8277c40 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -188,6 +188,18 @@ static inline int ufshcd_get_uic_cmd_result(struct ufs_hba 
*hba)
 }
 
 /**
+ * ufshcd_get_dme_attr_val - Get the value of attribute returned by UIC command
+ * @hba: Pointer to adapter instance
+ *
+ * This function gets UIC command argument3
+ * Returns 0 on success, non zero value on error
+ */
+static inline u32 ufshcd_get_dme_attr_val(struct ufs_hba *hba)
+{
+   return ufshcd_readl(hba, REG_UIC_COMMAND_ARG_3);
+}
+
+/**
  * ufshcd_is_valid_req_rsp - checks if controller TR response is valid
  * @ucd_rsp_ptr: pointer to response UPIU
  *
@@ -821,6 +833,80 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba)
 }
 
 /**
+ * ufshcd_dme_set_attr - UIC command for DME_SET, DME_PEER_SET
+ * @hba: per adapter instance
+ * @attr_sel: uic command argument1
+ * @attr_set: attribute set type as uic command argument2
+ * @mib_val: setting value as uic command argument3
+ * @peer: indicate wherter peer or non-peer
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+int ufshcd_dme_set_attr(struct ufs_hba *hba, u32 attr_sel,
+   u8 attr_set, u32 mib_val, u8 peer)
+{
+   struct uic_command uic_cmd = {0};
+   static const char *const action[] = {
+   "dme-set",
+   "dme-peer-set"
+   };
+   const char *set = action[!!peer];
+   int ret;
+
+   uic_cmd.command = peer ?
+   UIC_CMD_DME_PEER_SET : UIC_CMD_DME_SET;
+   uic_cmd.argument1 = attr_sel;
+   uic_cmd.argument2 = UIC_ARG_ATTR_TYPE(attr_set);
+   uic_cmd.argument3 = mib_val;
+
+   ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
+   if (ret)
+   dev_err(hba->dev, "%s: attr-id 0x%x error code %d\n",
+   set, UIC_GET_ATTR_ID(attr_sel), ret);
+
+   return ret;
+}
+EXPORT_SYMBOL_GPL(ufshcd_dme_set_attr);
+
+/**
+ * ufshcd_dme_get_attr - UIC command for DME_GET, DME_PEER_GET
+ * @hba: per adapter instance
+ * @attr_sel: uic command argument1
+ * @mib_val: the value of the attribute as returned by the UIC command
+ * @peer: indicate wherter peer or non-peer
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel,
+   u32 *mib_val, u8 peer)
+{
+   struct uic_command uic_cmd = {0};
+   static const char *const action[] = {
+   "dme-get",
+   "dme-peer-get"
+   };
+   const char *get = action[!!peer];
+   int ret;
+
+   uic_cmd.command = peer ?
+   UIC_CMD_DME_PEER_GET : UIC_CMD_DME_GET;
+   uic_cmd.argument1 = attr_sel;
+
+   ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
+   if (ret) {
+   dev_err(hba->dev, "%s: attr-id 0x%x error code %d\n",
+   get, UIC_GET_ATTR_ID(attr_sel), ret);
+   goto out;
+   }
+
+   if (mib_val)
+   *mib_val = uic_cmd.argument3;
+out:
+   return ret;
+}
+EXPORT_SYMBOL_GPL(ufshcd_dme_get_attr);
+
+/**
  * ufshcd_make_hba_operational - Make UFS controller operational
  * @hba: per adapter instance
  *
@@ -1256,6 +1342,8 @@ static void ufshcd_uic_cmd_compl(struct ufs_hba *hba)
if (hba->active_uic_cmd) {
hba->active_uic_cmd->argument2 |=
ufshcd_get_uic_cmd_result(hba);
+   hba->active_uic_cmd->argument3 =
+   ufshcd_get_dme_attr_val(hba);
complete(&hba->active_uic_cmd->done);
}
 }
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 49590ee..50bcd29 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -199,6 +199,11 @@ int ufshcd_init(struct device *, struct ufs_hba ** , void 
__iomem * ,
unsigned int);
 void ufshcd_remove(struct ufs_hba *);
 
+extern int ufshcd_dme_set_attr(struct ufs_hba *hba, u32 attr_sel,
+  u8 attr_set, u32 mib_val, u8 peer);
+extern int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel,
+  u32 *mib_val, u8 peer);
+
 /**
  * ufshcd_hba_stop - Send controller to reset state
  * @hba: per adapter instance
@@ -208,4 +213,50 @@ static inline void ufshcd_hba_stop(struct ufs_hba *hba)
ufshcd_writel(hba, CONTROLLER_DISABLE

[PATCH 5/7] scsi: ufs: add unipro attribute IDs

2013-07-26 Thread Seungwon Jeon
'drivers/scsi/ufs/unipro.h' is added.
Attributes in the layers of the UNIPRO stack can be
read and written via the DME.

Signed-off-by: Seungwon Jeon 
---
 drivers/scsi/ufs/unipro.h |  130 +
 1 files changed, 130 insertions(+), 0 deletions(-)
 create mode 100644 drivers/scsi/ufs/unipro.h

diff --git a/drivers/scsi/ufs/unipro.h b/drivers/scsi/ufs/unipro.h
new file mode 100644
index 000..3a710eb
--- /dev/null
+++ b/drivers/scsi/ufs/unipro.h
@@ -0,0 +1,130 @@
+/*
+ * drivers/scsi/ufs/unipro.h
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef _UNIPRO_H_
+#define _UNIPRO_H_
+
+/*
+ * PHY Adpater attributes
+ */
+#define PA_ACTIVETXDATALANES   0x1560
+#define PA_ACTIVERXDATALANES   0x1580
+#define PA_TXTRAILINGCLOCKS0x1564
+#define PA_PHY_TYPE0x1500
+#define PA_AVAILTXDATALANES0x1520
+#define PA_AVAILRXDATALANES0x1540
+#define PA_MINRXTRAILINGCLOCKS 0x1543
+#define PA_TXPWRSTATUS 0x1567
+#define PA_RXPWRSTATUS 0x1582
+#define PA_TXFORCECLOCK0x1562
+#define PA_TXPWRMODE   0x1563
+#define PA_LEGACYDPHYESCDL 0x1570
+#define PA_MAXTXSPEEDFAST  0x1521
+#define PA_MAXTXSPEEDSLOW  0x1522
+#define PA_MAXRXSPEEDFAST  0x1541
+#define PA_MAXRXSPEEDSLOW  0x1542
+#define PA_TXLINKSTARTUPHS 0x1544
+#define PA_TXSPEEDFAST 0x1565
+#define PA_TXSPEEDSLOW 0x1566
+#define PA_REMOTEVERINFO   0x15A0
+#define PA_TXGEAR  0x1568
+#define PA_TXTERMINATION   0x1569
+#define PA_HSSERIES0x156A
+#define PA_PWRMODE 0x1571
+#define PA_RXGEAR  0x1583
+#define PA_RXTERMINATION   0x1584
+#define PA_MAXRXPWMGEAR0x1586
+#define PA_MAXRXHSGEAR 0x1587
+#define PA_RXHSUNTERMCAP   0x15A5
+#define PA_RXLSTERMCAP 0x15A6
+#define PA_PACPREQTIMEOUT  0x1590
+#define PA_PACPREQEOBTIMEOUT   0x1591
+#define PA_HIBERN8TIME 0x15A7
+#define PA_LOCALVERINFO0x15A9
+#define PA_TACTIVATE   0x15A8
+#define PA_PACPFRAMECOUNT  0x15C0
+#define PA_PACPERRORCOUNT  0x15C1
+#define PA_PHYTESTCONTROL  0x15C2
+#define PA_PWRMODEUSERDATA00x15B0
+#define PA_PWRMODEUSERDATA10x15B1
+#define PA_PWRMODEUSERDATA20x15B2
+#define PA_PWRMODEUSERDATA30x15B3
+#define PA_PWRMODEUSERDATA40x15B4
+#define PA_PWRMODEUSERDATA50x15B5
+#define PA_PWRMODEUSERDATA60x15B6
+#define PA_PWRMODEUSERDATA70x15B7
+#define PA_PWRMODEUSERDATA80x15B8
+#define PA_PWRMODEUSERDATA90x15B9
+#define PA_PWRMODEUSERDATA10   0x15BA
+#define PA_PWRMODEUSERDATA11   0x15BB
+#define PA_CONNECTEDTXDATALANES0x1561
+#define PA_CONNECTEDRXDATALANES0x1581
+#define PA_LOGICALLANEMAP  0x15A1
+#define PA_SLEEPNOCONFIGTIME   0x15A2
+#define PA_STALLNOCONFIGTIME   0x15A3
+#define PA_SAVECONFIGTIME  0x15A4
+
+/*
+ * Data Link Layer Attributes
+ */
+#define DL_TC0TXFCTHRESHOLD0x2040
+#define DL_FC0PROTTIMEOUTVAL   0x2041
+#define DL_TC0REPLAYTIMEOUTVAL 0x2042
+#define DL_AFC0REQTIMEOUTVAL   0x2043
+#define DL_AFC0CREDITTHRESHOLD 0x2044
+#define DL_TC0OUTACKTHRESHOLD  0x2045
+#define DL_TC1TXFCTHRESHOLD0x2060
+#define DL_FC1PROTTIMEOUTVAL   0x2061
+#define DL_TC1REPLAYTIMEOUTVAL 0x2062
+#define DL_AFC1REQTIMEOUTVAL   0x2063
+#define DL_AFC1CREDITTHRESHOLD 0x2064
+#define DL_TC1OUTACKTHRESHOLD  0x2065
+#define DL_TXPREEMPTIONCAP 0x2000
+#define DL_TC0TXMAXSDUSIZE 0x2001
+#define DL_TC0RXINITCREDITVAL  0x2002
+#define DL_TC0TXBUFFERSIZE 0x2005
+#define DL_PEERTC0PRESENT  0x2046
+#define DL_PEERTC0RXINITCREVAL 0x2047
+#define DL_TC1TXMAXSDUSIZE 0x2003
+#define DL_TC1RXINITCREDITVAL  0x2004
+#define DL_TC1TXBUFFERSIZE 0x2006
+#define DL_PEERTC1PRESENT  0x2066
+#define DL_PEERTC1RXINITCREVAL 0x2067
+
+/*
+ * Network Layer Attributes
+ */
+#define N_DEVICEID 0x3000
+#define N_DEVICEID_VALID   0x3001
+#define N_TC0TXMAXSDUSIZE  0x3020
+#define N_TC1TXMAXSDUSIZE  0x3021
+
+/*
+ * Transport Layer Attributes
+ */
+#define T_NUMCPORTS0x4000
+#define T_NUMTESTFEATURES  0x4001
+#define T_CONNECTIONSTATE  0x4020
+#define T_PEERDEVICEID 0x4021
+#define T_PEERCPORTID  0x4022
+#define T_TRAFFICCLASS 0x4023
+#define T_PROTOCOLID   0x4024
+#define T_CPORTFLAGS   0x4025
+#define T_TXTOKENVALUE 0x4026
+#define T_RXTOKENVALUE 0x4027
+#define T_LOCALBUFFERSPACE 0x4028
+#define T_PEERBUFFERSPACE  0x4029
+#define T_CREDITSTOSEND0x402A
+#define T_CPORTMODE0x402B
+#define T_TC0TXMAXSDUSIZE  0x4060
+#define T_TC1TXMAXSDUSIZE  0x4061

[PATCH 6/7] scsi: ufs: add operation for the uic power mode change

2013-07-26 Thread Seungwon Jeon
Setting PA_PWRMode using DME_SET triggers the power mode
change. And then the result will be given by the HCS.UPMCRS.
This operation should be done atomically.

Signed-off-by: Seungwon Jeon 
---
 drivers/scsi/ufs/ufshcd.c |   80 ++--
 drivers/scsi/ufs/ufshcd.h |3 ++
 drivers/scsi/ufs/ufshci.h |   12 +++
 3 files changed, 91 insertions(+), 4 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 8277c40..ffda72d 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -36,9 +36,11 @@
 #include 
 
 #include "ufshcd.h"
+#include "unipro.h"
 
 #define UFSHCD_ENABLE_INTRS(UTP_TRANSFER_REQ_COMPL |\
 UTP_TASK_REQ_COMPL |\
+UIC_POWER_MODE |\
 UFSHCD_ERROR_MASK)
 /* UIC command timeout, unit: ms */
 #define UIC_CMD_TIMEOUT500
@@ -359,6 +361,18 @@ static inline bool ufshcd_ready_for_uic_cmd(struct ufs_hba 
*hba)
 }
 
 /**
+ * ufshcd_get_upmcrs - Get the power mode change request status
+ * @hba: Pointer to adapter instance
+ *
+ * This function gets the UPMCRS field of HCS register
+ * Returns value of UPMCRS field
+ */
+static inline u8 ufshcd_get_upmcrs(struct ufs_hba *hba)
+{
+   return (ufshcd_readl(hba, REG_CONTROLLER_STATUS) >> 8) & 0x7;
+}
+
+/**
  * ufshcd_dispatch_uic_cmd - Dispatch UIC commands to unipro layers
  * @hba: per adapter instance
  * @uic_cmd: UIC command
@@ -907,6 +921,60 @@ out:
 EXPORT_SYMBOL_GPL(ufshcd_dme_get_attr);
 
 /**
+ * ufshcd_uic_change_pwr_mode - Perform the UIC power mode chage
+ * using DME_SET primitives.
+ * @hba: per adapter instance
+ * @mode: powr mode value
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+int ufshcd_uic_change_pwr_mode(struct ufs_hba *hba, u8 mode)
+{
+   struct uic_command uic_cmd = {0};
+   struct completion pwr_done;
+   unsigned long flags;
+   u8 status;
+   int ret;
+
+   uic_cmd.command = UIC_CMD_DME_SET;
+   uic_cmd.argument1 = UIC_ARG_MIB(PA_PWRMODE);
+   uic_cmd.argument3 = mode;
+   init_completion(&pwr_done);
+
+   mutex_lock(&hba->uic_cmd_mutex);
+
+   spin_lock_irqsave(hba->host->host_lock, flags);
+   hba->pwr_done = &pwr_done;
+   spin_unlock_irqrestore(hba->host->host_lock, flags);
+   ret = __ufshcd_send_uic_cmd(hba, &uic_cmd);
+   if (ret) {
+   dev_err(hba->dev, "pwr mode change uic error %d\n", ret);
+   goto out;
+   }
+
+   if (!wait_for_completion_timeout(hba->pwr_done,
+msecs_to_jiffies(UIC_CMD_TIMEOUT))) {
+   dev_err(hba->dev, "pwr mode change completion timeout\n");
+   ret = -ETIMEDOUT;
+   goto out;
+   }
+
+   status = ufshcd_get_upmcrs(hba);
+   if (status != PWR_LOCAL) {
+   dev_err(hba->dev,
+   "pwr mode change failed, host umpcrs:0x%x\n",
+   status);
+   ret = (status != PWR_OK) ? status : -1;
+   }
+out:
+   spin_lock_irqsave(hba->host->host_lock, flags);
+   hba->pwr_done = NULL;
+   spin_unlock_irqrestore(hba->host->host_lock, flags);
+   mutex_unlock(&hba->uic_cmd_mutex);
+   return ret;
+}
+
+/**
  * ufshcd_make_hba_operational - Make UFS controller operational
  * @hba: per adapter instance
  *
@@ -1336,16 +1404,20 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct 
ufshcd_lrb *lrbp)
 /**
  * ufshcd_uic_cmd_compl - handle completion of uic command
  * @hba: per adapter instance
+ * @intr_status: interrupt status generated by the controller
  */
-static void ufshcd_uic_cmd_compl(struct ufs_hba *hba)
+static void ufshcd_uic_cmd_compl(struct ufs_hba *hba, u32 intr_status)
 {
-   if (hba->active_uic_cmd) {
+   if ((intr_status & UIC_COMMAND_COMPL) && hba->active_uic_cmd) {
hba->active_uic_cmd->argument2 |=
ufshcd_get_uic_cmd_result(hba);
hba->active_uic_cmd->argument3 =
ufshcd_get_dme_attr_val(hba);
complete(&hba->active_uic_cmd->done);
}
+
+   if ((intr_status & UIC_POWER_MODE) && hba->pwr_done)
+   complete(hba->pwr_done);
 }
 
 /**
@@ -1447,8 +1519,8 @@ static void ufshcd_sl_intr(struct ufs_hba *hba, u32 
intr_status)
if (hba->errors)
ufshcd_err_handler(hba);
 
-   if (intr_status & UIC_COMMAND_COMPL)
-   ufshcd_uic_cmd_compl(hba);
+   if (intr_status & UFSHCD_UIC_MASK)
+   ufshcd_uic_cmd_compl(hba, intr_status);
 
if (intr_status & UTP_TASK_REQ_COMPL)
ufshcd_tmc_handler(hba);
diff --git a/drive

[PATCH 7/7] scsi: ufs: configure the attribute for power mode

2013-07-26 Thread Seungwon Jeon
UIC attributes can be set with using DME_SET command for
power mode change. For configuration the link capability
attributes are used, which is updated after successful
link startup.

Signed-off-by: Seungwon Jeon 
---
 drivers/scsi/ufs/ufshcd.c |   74 +++-
 drivers/scsi/ufs/unipro.h |   21 +
 2 files changed, 93 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index ffda72d..ebdb9ff 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -975,6 +975,70 @@ out:
 }
 
 /**
+ * ufshcd_config_max_pwr_mode - Set & Change power mode with
+ * maximum capability attribute information.
+ * @hba: per adapter instance
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+static int ufshcd_config_max_pwr_mode(struct ufs_hba *hba)
+{
+   enum {RX = 0, TX = 1};
+   u32 lanes[] = {1, 1};
+   u32 gear[] = {1, 1};
+   u8 pwr[] = {FASTAUTO_MODE, FASTAUTO_MODE};
+   int i, ret;
+
+   /* Get the connected lane count */
+   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDRXDATALANES), &lanes[RX]);
+   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES), &lanes[TX]);
+
+   /*
+* First, get the maximum gears of HS speed.
+* If a zero value, it means there is no HSGEAR capability.
+* Then, get the maximum gears of PWM speed.
+*/
+   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR), &gear[RX]);
+   if (!gear[RX]) {
+   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXPWMGEAR), &gear[RX]);
+   pwr[RX] = SLOWAUTO_MODE;
+   }
+
+   ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR), &gear[TX]);
+   if (!gear[TX]) {
+   ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_MAXRXPWMGEAR),
+   &gear[TX]);
+   pwr[TX] = SLOWAUTO_MODE;
+   }
+
+   /*
+* Configure attributes for power mode change with below.
+* - PA_RXGEAR, PA_ACTIVERXDATALANES, PA_RXTERMINATION,
+* - PA_TXGEAR, PA_ACTIVETXDATALANES, PA_TXTERMINATION,
+* - PA_HSSERIES
+*/
+   ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXGEAR), gear[RX]);
+   ufshcd_dme_set(hba, UIC_ARG_MIB(PA_ACTIVERXDATALANES), lanes[RX]);
+   if (pwr[RX] == FASTAUTO_MODE)
+   ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXTERMINATION), TRUE);
+
+   ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXGEAR), gear[TX]);
+   ufshcd_dme_set(hba, UIC_ARG_MIB(PA_ACTIVETXDATALANES), lanes[TX]);
+   if (pwr[TX] == FASTAUTO_MODE)
+   ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXTERMINATION), TRUE);
+
+   if (pwr[RX] == FASTAUTO_MODE || pwr[TX] == FASTAUTO_MODE)
+   ufshcd_dme_set(hba, UIC_ARG_MIB(PA_HSSERIES), PA_HS_MODE_B);
+
+   ret = ufshcd_uic_change_pwr_mode(hba, pwr[RX] << 4 | pwr[TX]);
+   if (ret)
+   dev_err(hba->dev,
+   "pwr_mode: power mode change failed %d\n", ret);
+
+   return ret;
+}
+
+/**
  * ufshcd_make_hba_operational - Make UFS controller operational
  * @hba: per adapter instance
  *
@@ -1754,8 +1818,14 @@ static void ufshcd_async_scan(void *data, async_cookie_t 
cookie)
int ret;
 
ret = ufshcd_link_startup(hba);
-   if (!ret)
-   scsi_scan_host(hba->host);
+   if (ret)
+   goto out;
+
+   ufshcd_config_max_pwr_mode(hba);
+
+   scsi_scan_host(hba->host);
+out:
+   return;
 }
 
 static struct scsi_host_template ufshcd_driver_template = {
diff --git a/drivers/scsi/ufs/unipro.h b/drivers/scsi/ufs/unipro.h
index 3a710eb..0bb8041 100644
--- a/drivers/scsi/ufs/unipro.h
+++ b/drivers/scsi/ufs/unipro.h
@@ -72,6 +72,21 @@
 #define PA_STALLNOCONFIGTIME   0x15A3
 #define PA_SAVECONFIGTIME  0x15A4
 
+/* PA power modes */
+enum {
+   FAST_MODE   = 1,
+   SLOW_MODE   = 2,
+   FASTAUTO_MODE   = 4,
+   SLOWAUTO_MODE   = 5,
+   UNCHANGED   = 7,
+};
+
+/* PA TX/RX Frequency Series */
+enum {
+   PA_HS_MODE_A= 1,
+   PA_HS_MODE_B= 2,
+};
+
 /*
  * Data Link Layer Attributes
  */
@@ -127,4 +142,10 @@
 #define T_TC0TXMAXSDUSIZE  0x4060
 #define T_TC1TXMAXSDUSIZE  0x4061
 
+/* Boolean attribute values */
+enum {
+   FALSE = 0,
+   TRUE,
+};
+
 #endif /* _UNIPRO_H_ */
-- 
1.7.0.4


--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: [PATCH 1/7] scsi: ufs: amend the ocs handling with fatal error

2013-07-29 Thread Seungwon Jeon
On Mon, July 29, 2013, Subhash Jadavani wrote:
> On 7/26/2013 7:15 PM, Seungwon Jeon wrote:
> > Fatal error in OCS(overall command status) field indicates
> > error conditions which is not covered by UFSHCI.
> > It means that host cannot define the result of command status
> > and therefore host may need to check transfer response UPIU's
> > response and status field.
> > It was actually found that 'CHECK CONDITION' is stored in status
> > field of UPIU where OCS is 'FATAL ERROR'.
> >
> > Signed-off-by: Seungwon Jeon 
> > ---
> >   drivers/scsi/ufs/ufshcd.c |3 +--
> >   1 files changed, 1 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> > index b743bd6..4cf3a2d 100644
> > --- a/drivers/scsi/ufs/ufshcd.c
> > +++ b/drivers/scsi/ufs/ufshcd.c
> > @@ -1199,7 +1199,7 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, 
> > struct ufshcd_lrb *lrbp)
> >
> > switch (ocs) {
> > case OCS_SUCCESS:
> > -
> > +   case OCS_FATAL_ERROR:
> > /* check if the returned transfer response is valid */
> > result = ufshcd_is_valid_req_rsp(lrbp->ucd_rsp_ptr);
> 
> I don't see the response UPIU data of the last command response is
> cleared anywhere in the driver. This means its quite possible that if
> the current command failed (and if it is using the same tag as the last
> succeeded command) with the OCS_FATAL_ERROR then response UPIU (pointed
> by lrbp->ucd_rsp_ptr) content may be still the same as the last one. If
> we ensure to clear the response UPIU data after every command completion
> then only we can rely on the response  UPIU content in case of fatal errors.
Response data of 'ucd_rsp_ptr' will be updated by UFS device if response UPIU 
is completed.
There is nowhere driver clears 'ucd_rsp_ptr', though.
But if it's really needed, it can be another patch?

Thanks,
Seungwon Jeon

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: [PATCH 3/7] scsi: ufs: fix the setting interrupt aggregation counter

2013-07-30 Thread Seungwon Jeon
On Mon, July 29, 2013, Subhash Jadavani wrote:
> On 7/26/2013 7:16 PM, Seungwon Jeon wrote:
> > LACTH(Interrupt aggregation counter threshold) value is allowed
> 
> I guess you mean "IACTH" not "LACTH". Other than this, change looks good
> to me.
> Reviewed-by: Subhash Jadavani 
Right, Typo will be fixed.

Thanks,
Seungwon Jeon

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: [PATCH 2/7] scsi: ufs: find out sense data over scsi status values

2013-07-30 Thread Seungwon Jeon
On Mon, July 29, 2013, Subhash Jadavani wrote:
> On 7/26/2013 7:16 PM, Seungwon Jeon wrote:
> > Except for 'GOOD' and 'CHECK CONDITION', other status value
> This is what UFS device spec says: "A GOOD status indicates successful
> SCSI completion and therefore no Sense Data will be returned." So please
> change the commit text accordingly.
Ok. It may seem vague.


> > in Response UPIU may or may contain sense data. If a non-zero
> 
> s/"may or may contain ..."/"may or may not contain"
Yes.

> > value is in the Data Segment Length field, it means that UPIU
> > has Sense Data in the Data Segment area.
> >
> > Signed-off-by: Seungwon Jeon 
> > ---
> >   drivers/scsi/ufs/ufs.h|1 +
> >   drivers/scsi/ufs/ufshcd.c |   27 +++
> >   2 files changed, 20 insertions(+), 8 deletions(-)
> >
> > diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
> > index 139bc06..737c31b 100644
> > --- a/drivers/scsi/ufs/ufs.h
> > +++ b/drivers/scsi/ufs/ufs.h
> > @@ -114,6 +114,7 @@ enum {
> > MASK_SCSI_STATUS= 0xFF,
> > MASK_TASK_RESPONSE  = 0xFF00,
> > MASK_RSP_UPIU_RESULT= 0x,
> > +   MASK_RSP_UPIU_DATA_SEG_LEN  = 0x,
> >   };
> >
> >   /* Task management service response */
> > diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> > index 4cf3a2d..688ae0e 100644
> > --- a/drivers/scsi/ufs/ufshcd.c
> > +++ b/drivers/scsi/ufs/ufshcd.c
> > @@ -218,6 +218,20 @@ ufshcd_get_rsp_upiu_result(struct utp_upiu_rsp 
> > *ucd_rsp_ptr)
> > return be32_to_cpu(ucd_rsp_ptr->header.dword_1) & MASK_RSP_UPIU_RESULT;
> >   }
> >
> > +/*
> > + * ufshcd_get_rsp_upiu_data_seg_len - Get the data segment length
> > + * from response UPIU
> > + * @ucd_rsp_ptr: pointer to response UPIU
> > + *
> > + * Return the data segment length.
> > + */
> > +static inline int
> > +ufshcd_get_rsp_upiu_data_seg_len(struct utp_upiu_rsp *ucd_rsp_ptr)
> > +{
> > +   return be32_to_cpu(ucd_rsp_ptr->header.dword_2) &
> > +   MASK_RSP_UPIU_DATA_SEG_LEN;
> > +}
> > +
> >   /**
> >* ufshcd_config_int_aggr - Configure interrupt aggregation values.
> >*Currently there is no use case where we want to 
> > configure
> > @@ -298,7 +312,8 @@ void ufshcd_send_command(struct ufs_hba *hba, unsigned 
> > int task_tag)
> >   static inline void ufshcd_copy_sense_data(struct ufshcd_lrb *lrbp)
> >   {
> > int len;
> > -   if (lrbp->sense_buffer) {
> > +   if (lrbp->sense_buffer &&
> > +   !ufshcd_get_rsp_upiu_data_seg_len(lrbp->ucd_rsp_ptr)) {
> 
> why if(!data_seg_len)? I guess you want to copy the sense data tot sense
> buffer only if the data segment length is non zero so in that case it
> should be "if(data_seg_len)".
Correct.

Thanks,
Seungwon Jeon

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: [PATCH 4/7] scsi: ufs: add dme configuration primitives

2013-07-30 Thread Seungwon Jeon
On Mon, July 29, 2013, Subhash Jadavani wrote:
> On 7/26/2013 7:17 PM, Seungwon Jeon wrote:
> > Implements to support GET and SET operations of the DME.
> > These operations are used to configure the behavior of
> > the UNIPRO. Along with basic operation, {Peer/AttrSetType}
> > can be mixed.
> >
> > Signed-off-by: Seungwon Jeon 
> > ---
> >   drivers/scsi/ufs/ufshcd.c |   88 
> > +
> >   drivers/scsi/ufs/ufshcd.h |   51 ++
> >   drivers/scsi/ufs/ufshci.h |6 +++
> >   3 files changed, 145 insertions(+), 0 deletions(-)
> >
> > diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> > index 7152ec4..8277c40 100644
> > --- a/drivers/scsi/ufs/ufshcd.c
> > +++ b/drivers/scsi/ufs/ufshcd.c
> > @@ -188,6 +188,18 @@ static inline int ufshcd_get_uic_cmd_result(struct 
> > ufs_hba *hba)
> >   }
> >
> >   /**
> > + * ufshcd_get_dme_attr_val - Get the value of attribute returned by UIC 
> > command
> > + * @hba: Pointer to adapter instance
> > + *
> > + * This function gets UIC command argument3
> > + * Returns 0 on success, non zero value on error
> > + */
> > +static inline u32 ufshcd_get_dme_attr_val(struct ufs_hba *hba)
> > +{
> > +   return ufshcd_readl(hba, REG_UIC_COMMAND_ARG_3);
> > +}
> > +
> > +/**
> >* ufshcd_is_valid_req_rsp - checks if controller TR response is valid
> >* @ucd_rsp_ptr: pointer to response UPIU
> >*
> > @@ -821,6 +833,80 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba)
> >   }
> >
> >   /**
> > + * ufshcd_dme_set_attr - UIC command for DME_SET, DME_PEER_SET
> > + * @hba: per adapter instance
> > + * @attr_sel: uic command argument1
> > + * @attr_set: attribute set type as uic command argument2
> > + * @mib_val: setting value as uic command argument3
> > + * @peer: indicate wherter peer or non-peer
> 
> typo: s/wtherter/whether
> This would sound better: s/non-peer/local
Ok.

> 
> Do above for ufshcd_dme_get_attr() function as well.
> > + *
> > + * Returns 0 on success, non-zero value on failure
> > + */
> > +int ufshcd_dme_set_attr(struct ufs_hba *hba, u32 attr_sel,
> > +   u8 attr_set, u32 mib_val, u8 peer)
> > +{
> > +   struct uic_command uic_cmd = {0};
> > +   static const char *const action[] = {
> > +   "dme-set",
> > +   "dme-peer-set"
> > +   };
> > +   const char *set = action[!!peer];
> > +   int ret;
> > +
> > +   uic_cmd.command = peer ?
> > +   UIC_CMD_DME_PEER_SET : UIC_CMD_DME_SET;
> > +   uic_cmd.argument1 = attr_sel;
> > +   uic_cmd.argument2 = UIC_ARG_ATTR_TYPE(attr_set);
> > +   uic_cmd.argument3 = mib_val;
> > +
> > +   ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
> > +   if (ret)
> > +   dev_err(hba->dev, "%s: attr-id 0x%x error code %d\n",
> > +   set, UIC_GET_ATTR_ID(attr_sel), ret);
> 
> Its also good to print the "mib_val" which we were trying to set. It
> might be possible that DME_SET failed because we are trying to set out
> of range value to MIB attribute.
I'll add it.

> 
> > +
> > +   return ret;
> > +}
> > +EXPORT_SYMBOL_GPL(ufshcd_dme_set_attr);
> > +
> > +/**
> > + * ufshcd_dme_get_attr - UIC command for DME_GET, DME_PEER_GET
> > + * @hba: per adapter instance
> > + * @attr_sel: uic command argument1
> > + * @mib_val: the value of the attribute as returned by the UIC command
> > + * @peer: indicate wherter peer or non-peer
> > + *
> > + * Returns 0 on success, non-zero value on failure
> > + */
> > +int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel,
> > +   u32 *mib_val, u8 peer)
> > +{
> > +   struct uic_command uic_cmd = {0};
> > +   static const char *const action[] = {
> > +   "dme-get",
> > +   "dme-peer-get"
> > +   };
> > +   const char *get = action[!!peer];
> > +   int ret;
> > +
> > +   uic_cmd.command = peer ?
> > +   UIC_CMD_DME_PEER_GET : UIC_CMD_DME_GET;
> > +   uic_cmd.argument1 = attr_sel;
> > +
> > +   ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
> > +   if (ret) {
> > +   dev_err(hba->dev, "%s: attr-id 0x%x error code %d\n",
> > +   get, UIC_GET_ATTR_ID(attr_sel), ret);
> > +   goto out;
> > +   }
> > +
> > +   if (mib_val)
> > + 

RE: [PATCH 2/7] scsi: ufs: find out sense data over scsi status values

2013-07-30 Thread Seungwon Jeon
On Mon, July 29, 2013, Sujit Reddy Thumma wrote:
> On 7/26/2013 7:16 PM, Seungwon Jeon wrote:
> > Except for 'GOOD' and 'CHECK CONDITION', other status value
> > in Response UPIU may or may contain sense data. If a non-zero
> > value is in the Data Segment Length field, it means that UPIU
> > has Sense Data in the Data Segment area.
> >
> > Signed-off-by: Seungwon Jeon 
> > ---
> >   drivers/scsi/ufs/ufs.h|1 +
> >   drivers/scsi/ufs/ufshcd.c |   27 +++
> >   2 files changed, 20 insertions(+), 8 deletions(-)
> >
> > diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
> > index 139bc06..737c31b 100644
> > --- a/drivers/scsi/ufs/ufs.h
> > +++ b/drivers/scsi/ufs/ufs.h
> > @@ -114,6 +114,7 @@ enum {
> > MASK_SCSI_STATUS= 0xFF,
> > MASK_TASK_RESPONSE  = 0xFF00,
> > MASK_RSP_UPIU_RESULT= 0x,
> > +   MASK_RSP_UPIU_DATA_SEG_LEN  = 0x,
> >   };
> >
> >   /* Task management service response */
> > diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> > index 4cf3a2d..688ae0e 100644
> > --- a/drivers/scsi/ufs/ufshcd.c
> > +++ b/drivers/scsi/ufs/ufshcd.c
> > @@ -218,6 +218,20 @@ ufshcd_get_rsp_upiu_result(struct utp_upiu_rsp 
> > *ucd_rsp_ptr)
> > return be32_to_cpu(ucd_rsp_ptr->header.dword_1) & MASK_RSP_UPIU_RESULT;
> >   }
> >
> > +/*
> > + * ufshcd_get_rsp_upiu_data_seg_len - Get the data segment length
> > + * from response UPIU
> > + * @ucd_rsp_ptr: pointer to response UPIU
> > + *
> > + * Return the data segment length.
> > + */
> > +static inline int
> > +ufshcd_get_rsp_upiu_data_seg_len(struct utp_upiu_rsp *ucd_rsp_ptr)
> > +{
> > +   return be32_to_cpu(ucd_rsp_ptr->header.dword_2) &
> > +   MASK_RSP_UPIU_DATA_SEG_LEN;
> > +}
> > +
> >   /**
> >* ufshcd_config_int_aggr - Configure interrupt aggregation values.
> >*Currently there is no use case where we want to 
> > configure
> > @@ -298,7 +312,8 @@ void ufshcd_send_command(struct ufs_hba *hba, unsigned 
> > int task_tag)
> >   static inline void ufshcd_copy_sense_data(struct ufshcd_lrb *lrbp)
> >   {
> > int len;
> > -   if (lrbp->sense_buffer) {
> > +   if (lrbp->sense_buffer &&
> > +   !ufshcd_get_rsp_upiu_data_seg_len(lrbp->ucd_rsp_ptr)) {
> > len = be16_to_cpu(lrbp->ucd_rsp_ptr->sense_data_len);
> > memcpy(lrbp->sense_buffer,
> > lrbp->ucd_rsp_ptr->sense_data,
> > @@ -1156,21 +1171,17 @@ ufshcd_scsi_cmd_status(struct ufshcd_lrb *lrbp, int 
> > scsi_status)
> >   SAM_STAT_CHECK_CONDITION;
> 
> The whole function is doing things wrong. It is redundant to interpret
> the scsi_status at the LLD layer and make decisions while otherwise the
> SCSI layer anyway knows how handle them properly.
Yes, scsi status can be set simply here.

> 
> Please see scsi_decide_disposition().
> 
> Ideally, this is what we should do -
> if (response_upiu_sense_data_len > 0 && lrbp->sense_buffer) {
>   ufshcd_copy_sense_data();
> }
> result = set_host_byte(DID_OK) |
How can we determine DID_OK in ufshcd_scsi_cmd_status?
I think we can add this only in case of OCS_SUCCESS in 
ufshcd_transfer_rsp_status.

>   set_msg_byte(COMMAND_COMPLETE) |
I'm not sure that we need to set COMMAND_COMPLETE?
Message is related to SCSI-2.
I didn't get this information on SAM, SBC and SPC.
Do you have any idea?

Thanks,
Seungwon Jeon

>   (scsi_status & 0xff);
> 
> > ufshcd_copy_sense_data(lrbp);
> > break;
> > -   case SAM_STAT_BUSY:
> > -   result |= SAM_STAT_BUSY;
> > -   break;
> > case SAM_STAT_TASK_SET_FULL:
> > -
> > /*
> >  * If a LUN reports SAM_STAT_TASK_SET_FULL, then the LUN queue
> >  * depth needs to be adjusted to the exact number of
> >  * outstanding commands the LUN can handle at any given time.
> >  */
> > ufshcd_adjust_lun_qdepth(lrbp->cmd);
> > -   result |= SAM_STAT_TASK_SET_FULL;
> > -   break;
> > +   case SAM_STAT_BUSY:
> > case SAM_STAT_TASK_ABORTED:
> > -   result |= SAM_STAT_TASK_ABORTED;
> > +   result |= scsi_status;
> > +   ufshcd_copy_sense_data(lrbp);
> > break;
> > default:
> > result |= DID_ERROR << 16;
> >
> 
> --
> Regards,
> Sujit
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majord...@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: [PATCH 6/7] scsi: ufs: add operation for the uic power mode change

2013-07-30 Thread Seungwon Jeon
On Mon, July 29, 2013, Subhash Jadavani wrote:
> Change looks good except few minor comments.
Thank you for comments.

> 
> On 7/26/2013 7:18 PM, Seungwon Jeon wrote:
> > Setting PA_PWRMode using DME_SET triggers the power mode
> > change. And then the result will be given by the HCS.UPMCRS.
> > This operation should be done atomically.
> >
> > Signed-off-by: Seungwon Jeon 
> > ---
> >   drivers/scsi/ufs/ufshcd.c |   80 
> > ++--
> >   drivers/scsi/ufs/ufshcd.h |3 ++
> >   drivers/scsi/ufs/ufshci.h |   12 +++
> >   3 files changed, 91 insertions(+), 4 deletions(-)
> >
> > diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> > index 8277c40..ffda72d 100644
> > --- a/drivers/scsi/ufs/ufshcd.c
> > +++ b/drivers/scsi/ufs/ufshcd.c
> > @@ -36,9 +36,11 @@
> >   #include 
> >
> >   #include "ufshcd.h"
> > +#include "unipro.h"
> >
> >   #define UFSHCD_ENABLE_INTRS   (UTP_TRANSFER_REQ_COMPL |\
> >  UTP_TASK_REQ_COMPL |\
> > +UIC_POWER_MODE |\
> >  UFSHCD_ERROR_MASK)
> >   /* UIC command timeout, unit: ms */
> >   #define UIC_CMD_TIMEOUT   500
> > @@ -359,6 +361,18 @@ static inline bool ufshcd_ready_for_uic_cmd(struct 
> > ufs_hba *hba)
> >   }
> >
> >   /**
> > + * ufshcd_get_upmcrs - Get the power mode change request status
> > + * @hba: Pointer to adapter instance
> > + *
> > + * This function gets the UPMCRS field of HCS register
> > + * Returns value of UPMCRS field
> > + */
> > +static inline u8 ufshcd_get_upmcrs(struct ufs_hba *hba)
> > +{
> > +   return (ufshcd_readl(hba, REG_CONTROLLER_STATUS) >> 8) & 0x7;
> > +}
> > +
> > +/**
> >* ufshcd_dispatch_uic_cmd - Dispatch UIC commands to unipro layers
> >* @hba: per adapter instance
> >* @uic_cmd: UIC command
> > @@ -907,6 +921,60 @@ out:
> >   EXPORT_SYMBOL_GPL(ufshcd_dme_get_attr);
> >
> >   /**
> > + * ufshcd_uic_change_pwr_mode - Perform the UIC power mode chage
> > + * using DME_SET primitives.
> > + * @hba: per adapter instance
> > + * @mode: powr mode value
> > + *
> > + * Returns 0 on success, non-zero value on failure
> > + */
> > +int ufshcd_uic_change_pwr_mode(struct ufs_hba *hba, u8 mode)
> > +{
> > +   struct uic_command uic_cmd = {0};
> > +   struct completion pwr_done;
> > +   unsigned long flags;
> > +   u8 status;
> > +   int ret;
> > +
> > +   uic_cmd.command = UIC_CMD_DME_SET;
> > +   uic_cmd.argument1 = UIC_ARG_MIB(PA_PWRMODE);
> > +   uic_cmd.argument3 = mode;
> > +   init_completion(&pwr_done);
> > +
> > +   mutex_lock(&hba->uic_cmd_mutex);
> > +
> > +   spin_lock_irqsave(hba->host->host_lock, flags);
> > +   hba->pwr_done = &pwr_done;
> > +   spin_unlock_irqrestore(hba->host->host_lock, flags);
> > +   ret = __ufshcd_send_uic_cmd(hba, &uic_cmd);
> > +   if (ret) {
> > +   dev_err(hba->dev, "pwr mode change uic error %d\n", ret);
> 
> we should also print the power "mode" which we were trying to set here.
> 
> > +   goto out;
> > +   }
> > +
> > +   if (!wait_for_completion_timeout(hba->pwr_done,
> > +msecs_to_jiffies(UIC_CMD_TIMEOUT))) {
> > +   dev_err(hba->dev, "pwr mode change completion timeout\n");
> 
> we should also print the power "mode" which we were trying to set here.
Ok with above.

> 
> > +   ret = -ETIMEDOUT;
> > +   goto out;
> > +   }
> > +
> > +   status = ufshcd_get_upmcrs(hba);
> > +   if (status != PWR_LOCAL) {
> > +   dev_err(hba->dev,
> > +   "pwr mode change failed, host umpcrs:0x%x\n",
> > +   status);
> > +   ret = (status != PWR_OK) ? status : -1;
> > +   }
> > +out:
> > +   spin_lock_irqsave(hba->host->host_lock, flags);
> > +   hba->pwr_done = NULL;
> > +   spin_unlock_irqrestore(hba->host->host_lock, flags);
> > +   mutex_unlock(&hba->uic_cmd_mutex);
> > +   return ret;
> > +}
> > +
> > +/**
> >* ufshcd_make_hba_operational - Make UFS controller operational
> >* @hba: per adapter instance
> >*
> > @@ -1336,16 +1404,20 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, 

RE: [PATCH 1/7] scsi: ufs: amend the ocs handling with fatal error

2013-07-30 Thread Seungwon Jeon
On Mon, July 29, 2013, Sujit Reddy Thumma wrote:
> On 7/29/2013 11:47 AM, Subhash Jadavani wrote:
> > On 7/26/2013 7:15 PM, Seungwon Jeon wrote:
> >> Fatal error in OCS(overall command status) field indicates
> >> error conditions which is not covered by UFSHCI.
> >> It means that host cannot define the result of command status
> >> and therefore host may need to check transfer response UPIU's
> >> response and status field.
> >> It was actually found that 'CHECK CONDITION' is stored in status
> >> field of UPIU where OCS is 'FATAL ERROR'.
> 
> It looks like you are assuming that there will be some kind of response
> from the device. But the spec. mentions - "OCS_FATAL ERROR: within host
> controller that is not covered by the error conditions described above
> in this table."
Yes, error interrupt doesn't happen actually.

> 
> So spec. left everything to implementers on how to trigger this error.
> Also, it says "within host controller" so ufshcd_is_valid_req_rsp()
> might fail as well.
> 
> I couldn't understand why there is a need for a host controller to
> interpret the SCSI command status and raise an OCS_FATAL_ERROR?
I feel like OCS values are related to syntax problem except OCS_FATAL_ERROR.
Basically, host controller may need to refer the Response field[Target 
Success/Target Failure] of response UPIU.
It's a overall result from response UPIU. 
When Response field is 'Target Failure', if host controller updates the OCS 
field with 'SUCCESS', it's not proper behavior.
In this case host may refer the Status field of response UPIU to decide the OCS 
result.
Of course, it's not clear thing and could depends on host's implementation,
because there is no obvious description for that.
But if we consider the way to report UTP error from UFSHCI 8.2.4,
we can check the Response UPIU for more detailed error condition regardless OCS 
value.
Could you check your host side?

Thanks,
Seungwon Jeon

> 
> If it is clarified by the spec. then we can have generic implementation
> otherwise I would prefer to make this specific to those host controllers
> that raise OCS_FATAL_ERROR for CHECK_CONDITION.
> 
> >>
> >> Signed-off-by: Seungwon Jeon 
> >> ---
> >>   drivers/scsi/ufs/ufshcd.c |3 +--
> >>   1 files changed, 1 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> >> index b743bd6..4cf3a2d 100644
> >> --- a/drivers/scsi/ufs/ufshcd.c
> >> +++ b/drivers/scsi/ufs/ufshcd.c
> >> @@ -1199,7 +1199,7 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba,
> >> struct ufshcd_lrb *lrbp)
> >>   switch (ocs) {
> >>   case OCS_SUCCESS:
> >> -
> >> +case OCS_FATAL_ERROR:
> >>   /* check if the returned transfer response is valid */
> >>   result = ufshcd_is_valid_req_rsp(lrbp->ucd_rsp_ptr);
> >
> > I don't see the response UPIU data of the last command response is
> > cleared anywhere in the driver. This means its quite possible that if
> > the current command failed (and if it is using the same tag as the last
> > succeeded command) with the OCS_FATAL_ERROR then response UPIU (pointed
> > by lrbp->ucd_rsp_ptr) content may be still the same as the last one. If
> > we ensure to clear the response UPIU data after every command completion
> > then only we can rely on the response  UPIU content in case of fatal
> > errors.
> >
> > Regards,
> > Subhash
> >>   if (result) {
> >> @@ -1229,7 +1229,6 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba,
> >> struct ufshcd_lrb *lrbp)
> >>   case OCS_MISMATCH_DATA_BUF_SIZE:
> >>   case OCS_MISMATCH_RESP_UPIU_SIZE:
> >>   case OCS_PEER_COMM_FAILURE:
> >> -case OCS_FATAL_ERROR:
> >>   default:
> >>   result |= DID_ERROR << 16;
> >>   dev_err(hba->dev,
> >
> 
> 
> --
> Regards,
> Sujit
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majord...@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: [PATCH 2/7] scsi: ufs: find out sense data over scsi status values

2013-07-30 Thread Seungwon Jeon
On Tue, July 30, 2013, Santosh Y wrote:
> On Fri, Jul 26, 2013 at 7:16 PM, Seungwon Jeon  wrote:
> > Except for 'GOOD' and 'CHECK CONDITION', other status value
> > in Response UPIU may or may contain sense data. If a non-zero
> > value is in the Data Segment Length field, it means that UPIU
> > has Sense Data in the Data Segment area.
> >
> > Signed-off-by: Seungwon Jeon 
> > ---
> >  drivers/scsi/ufs/ufs.h|1 +
> >  drivers/scsi/ufs/ufshcd.c |   27 +++
> >  2 files changed, 20 insertions(+), 8 deletions(-)
> >
> > diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
> > index 139bc06..737c31b 100644
> > --- a/drivers/scsi/ufs/ufs.h
> > +++ b/drivers/scsi/ufs/ufs.h
> > @@ -114,6 +114,7 @@ enum {
> > MASK_SCSI_STATUS= 0xFF,
> > MASK_TASK_RESPONSE  = 0xFF00,
> > MASK_RSP_UPIU_RESULT= 0x,
> > +   MASK_RSP_UPIU_DATA_SEG_LEN  = 0x,
> >  };
> >
> >  /* Task management service response */
> > diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> > index 4cf3a2d..688ae0e 100644
> > --- a/drivers/scsi/ufs/ufshcd.c
> > +++ b/drivers/scsi/ufs/ufshcd.c
> > @@ -218,6 +218,20 @@ ufshcd_get_rsp_upiu_result(struct utp_upiu_rsp 
> > *ucd_rsp_ptr)
> > return be32_to_cpu(ucd_rsp_ptr->header.dword_1) & 
> > MASK_RSP_UPIU_RESULT;
> >  }
> >
> > +/*
> > + * ufshcd_get_rsp_upiu_data_seg_len - Get the data segment length
> > + * from response UPIU
> > + * @ucd_rsp_ptr: pointer to response UPIU
> > + *
> > + * Return the data segment length.
> > + */
> > +static inline int
> > +ufshcd_get_rsp_upiu_data_seg_len(struct utp_upiu_rsp *ucd_rsp_ptr)
> > +{
> > +   return be32_to_cpu(ucd_rsp_ptr->header.dword_2) &
> > +   MASK_RSP_UPIU_DATA_SEG_LEN;
> > +}
> > +
> >  /**
> >   * ufshcd_config_int_aggr - Configure interrupt aggregation values.
> >   * Currently there is no use case where we want to configure
> > @@ -298,7 +312,8 @@ void ufshcd_send_command(struct ufs_hba *hba, unsigned 
> > int task_tag)
> >  static inline void ufshcd_copy_sense_data(struct ufshcd_lrb *lrbp)
> >  {
> > int len;
> > -   if (lrbp->sense_buffer) {
> > +   if (lrbp->sense_buffer &&
> > +   !ufshcd_get_rsp_upiu_data_seg_len(lrbp->ucd_rsp_ptr)) {
> > len = be16_to_cpu(lrbp->ucd_rsp_ptr->sense_data_len);
> > memcpy(lrbp->sense_buffer,
> > lrbp->ucd_rsp_ptr->sense_data,
> 
> Also please change the SCSI_SENSE_BUFFERSIZE to 18-bytes as per the
> spec, *in case* if wrong 'data segment length' is returned, there
> won't be a need to memcpy extra bytes ;-).
> 
> #define UFS_SENSE_BUFFERSIZE 18
> memcpy(lrbp->sense_buffer,
>   lrbp->ucd_rsp_ptr->sense_data,
>   min_t(int, len, UFS_SENSE_BUFFERSIZE));
Ok. I'll check.
But considering the extension with spec. revision, it's not bad to be kept.
Current: [#define SCSI_SENSE_BUFFERSIZE   96]

Thanks,
Seungwon Jeon

> 
> 
> > @@ -1156,21 +1171,17 @@ ufshcd_scsi_cmd_status(struct ufshcd_lrb *lrbp, int 
> > scsi_status)
> >   SAM_STAT_CHECK_CONDITION;
> > ufshcd_copy_sense_data(lrbp);
> > break;
> > -   case SAM_STAT_BUSY:
> > -   result |= SAM_STAT_BUSY;
> > -   break;
> > case SAM_STAT_TASK_SET_FULL:
> > -
> > /*
> >  * If a LUN reports SAM_STAT_TASK_SET_FULL, then the LUN 
> > queue
> >  * depth needs to be adjusted to the exact number of
> >  * outstanding commands the LUN can handle at any given 
> > time.
> >  */
> > ufshcd_adjust_lun_qdepth(lrbp->cmd);
> > -   result |= SAM_STAT_TASK_SET_FULL;
> > -   break;
> > +   case SAM_STAT_BUSY:
> > case SAM_STAT_TASK_ABORTED:
> > -   result |= SAM_STAT_TASK_ABORTED;
> > +   result |= scsi_status;
> > +   ufshcd_copy_sense_data(lrbp);
> > break;
> > default:
> > result |= DID_ERROR << 16;
> > --
> > 1.7.0.4
> >
> >
> 
> 
> 
> --
> ~Santosh
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majord...@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: [PATCH 2/7] scsi: ufs: find out sense data over scsi status values

2013-08-06 Thread Seungwon Jeon
Hi Elliott,

Thank you for information.
It might be considered, if UFS has the extension someday.

Thanks,
Seungwon Jeon

On Wed, July 31, 2013, Elliott, Robert wrote:
> I don't know how well UFS keeps up with SCSI architecture, but SCSI
> has expanded from the old 18-byte fixed format sense data to a
> variable-length descriptor format sense data, in which an 8 byte
> header precedes a variable number of descriptors.  This was devised
> to support 8-byte LBAs in the INFORMATION field and
> COMMAND-SPECIFIC INFORMATION field for >2 TiB drives.
> 
> A few other new features:
> 
> 1. Extended INQUIRY Data VPD page
> MAXIMUM SUPPORTED SENSE DATA LENGTH field:
> Report how much sense data the device server is capable of returning
> 2. Control Extensions mode page
> MAXIMUM SENSE DATA LENGTH field:
> Specify how much sense data the device server is allowed to return
> 3. Descriptor format sense data header
> SDAT_OVFL bit:
> Reports that the device server had to drop some descriptors
> to fit in the specified length
> 4.  "Direct-access block device sense data descriptor"
> Devised for the use by Base feature set compliant designs.
> Combined with the 8 byte header, results in 32 bytes of sense data.
> Always carries an INFORMATION field, COMMAND-SPECIFIC
> INFORMATION field, sense-key specific information, field
> replaceable unit code, and ILI bit.
> 
> 
> 
> 
> > -Original Message-
> > From: linux-scsi-ow...@vger.kernel.org [mailto:linux-scsi-
> > ow...@vger.kernel.org] On Behalf Of Seungwon Jeon
> > Sent: Tuesday, 30 July, 2013 8:03 AM
> > To: 'Santosh Y'
> > Cc: linux-scsi@vger.kernel.org; 'Vinayak Holikatti'; 'James E.J. Bottomley'
> > Subject: RE: [PATCH 2/7] scsi: ufs: find out sense data over scsi status 
> > values
> >
> > On Tue, July 30, 2013, Santosh Y wrote:
> > > On Fri, Jul 26, 2013 at 7:16 PM, Seungwon Jeon 
> > wrote:
> > > > Except for 'GOOD' and 'CHECK CONDITION', other status value
> > > > in Response UPIU may or may contain sense data. If a non-zero
> > > > value is in the Data Segment Length field, it means that UPIU
> > > > has Sense Data in the Data Segment area.
> > > >
> > > > Signed-off-by: Seungwon Jeon 
> > > > ---
> > > >  drivers/scsi/ufs/ufs.h|1 +
> > > >  drivers/scsi/ufs/ufshcd.c |   27 +++
> > > >  2 files changed, 20 insertions(+), 8 deletions(-)
> > > >
> > > > diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
> > > > index 139bc06..737c31b 100644
> > > > --- a/drivers/scsi/ufs/ufs.h
> > > > +++ b/drivers/scsi/ufs/ufs.h
> > > > @@ -114,6 +114,7 @@ enum {
> > > > MASK_SCSI_STATUS= 0xFF,
> > > > MASK_TASK_RESPONSE  = 0xFF00,
> > > > MASK_RSP_UPIU_RESULT= 0x,
> > > > +   MASK_RSP_UPIU_DATA_SEG_LEN  = 0x,
> > > >  };
> > > >
> > > >  /* Task management service response */
> > > > diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> > > > index 4cf3a2d..688ae0e 100644
> > > > --- a/drivers/scsi/ufs/ufshcd.c
> > > > +++ b/drivers/scsi/ufs/ufshcd.c
> > > > @@ -218,6 +218,20 @@ ufshcd_get_rsp_upiu_result(struct utp_upiu_rsp
> > *ucd_rsp_ptr)
> > > > return be32_to_cpu(ucd_rsp_ptr->header.dword_1) &
> > MASK_RSP_UPIU_RESULT;
> > > >  }
> > > >
> > > > +/*
> > > > + * ufshcd_get_rsp_upiu_data_seg_len - Get the data segment length
> > > > + * from response UPIU
> > > > + * @ucd_rsp_ptr: pointer to response UPIU
> > > > + *
> > > > + * Return the data segment length.
> > > > + */
> > > > +static inline int
> > > > +ufshcd_get_rsp_upiu_data_seg_len(struct utp_upiu_rsp *ucd_rsp_ptr)
> > > > +{
> > > > +   return be32_to_cpu(ucd_rsp_ptr->header.dword_2) &
> > > > +   MASK_RSP_UPIU_DATA_SEG_LEN;
> > > > +}
> > > > +
> > > >  /**
> > > >   * ufshcd_config_int_aggr - Configure interrupt aggregation values.
> > > >   * Currently there is no use case where we want to 
> > > > configure
> > > > @@ -298,7 +312,8 @@ void ufshcd_send_command(struct ufs_hba
> > *hba, unsigned int task_tag)
> > > >  stati

RE: [PATCH 7/7] scsi: ufs: configure the attribute for power mode

2013-08-06 Thread Seungwon Jeon
On Wednesday, July 31, 2013, Subhash Jadavani wrote:
> Change looks good (except one minor question).
> 
> Reviewed-by: Subhash Jadavani 
> 
> On 7/26/2013 7:19 PM, Seungwon Jeon wrote:
> > UIC attributes can be set with using DME_SET command for
> > power mode change. For configuration the link capability
> > attributes are used, which is updated after successful
> > link startup.
> >
> > Signed-off-by: Seungwon Jeon 
> > ---
> >   drivers/scsi/ufs/ufshcd.c |   74 
> > +++-
> >   drivers/scsi/ufs/unipro.h |   21 +
> >   2 files changed, 93 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> > index ffda72d..ebdb9ff 100644
> > --- a/drivers/scsi/ufs/ufshcd.c
> > +++ b/drivers/scsi/ufs/ufshcd.c
> > @@ -975,6 +975,70 @@ out:
> >   }
> >
> >   /**
> > + * ufshcd_config_max_pwr_mode - Set & Change power mode with
> > + * maximum capability attribute information.
> > + * @hba: per adapter instance
> > + *
> > + * Returns 0 on success, non-zero value on failure
> > + */
> > +static int ufshcd_config_max_pwr_mode(struct ufs_hba *hba)
> > +{
> > +   enum {RX = 0, TX = 1};
> > +   u32 lanes[] = {1, 1};
> > +   u32 gear[] = {1, 1};
> > +   u8 pwr[] = {FASTAUTO_MODE, FASTAUTO_MODE};
> > +   int i, ret;
> > +
> > +   /* Get the connected lane count */
> > +   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDRXDATALANES), &lanes[RX]);
> > +   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES), &lanes[TX]);
> > +
> > +   /*
> > +* First, get the maximum gears of HS speed.
> > +* If a zero value, it means there is no HSGEAR capability.
> > +* Then, get the maximum gears of PWM speed.
> > +*/
> > +   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR), &gear[RX]);
> > +   if (!gear[RX]) {
> > +   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXPWMGEAR), &gear[RX]);
> > +   pwr[RX] = SLOWAUTO_MODE;
> > +   }
> > +
> > +   ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR), &gear[TX]);
> > +   if (!gear[TX]) {
> > +   ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_MAXRXPWMGEAR),
> > +   &gear[TX]);
> > +   pwr[TX] = SLOWAUTO_MODE;
> > +   }
> > +
> > +   /*
> > +* Configure attributes for power mode change with below.
> > +* - PA_RXGEAR, PA_ACTIVERXDATALANES, PA_RXTERMINATION,
> > +* - PA_TXGEAR, PA_ACTIVETXDATALANES, PA_TXTERMINATION,
> > +* - PA_HSSERIES
> > +*/
> > +   ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXGEAR), gear[RX]);
> > +   ufshcd_dme_set(hba, UIC_ARG_MIB(PA_ACTIVERXDATALANES), lanes[RX]);
> > +   if (pwr[RX] == FASTAUTO_MODE)
> > +   ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXTERMINATION), TRUE);
> > +
> > +   ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXGEAR), gear[TX]);
> > +   ufshcd_dme_set(hba, UIC_ARG_MIB(PA_ACTIVETXDATALANES), lanes[TX]);
> > +   if (pwr[TX] == FASTAUTO_MODE)
> > +   ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXTERMINATION), TRUE);
> 
> Does this mean TX-RX Termination can be enabled only in HS gear mode?
> Somehow i couldn't find this
Basically, 'termination' in HS Mode and not termination in LS mode.
Spec. doesn't say clearly, though.
If you have any idea, please let me know.

Thanks,
Seungwon Jeon
> 
> > +
> > +   if (pwr[RX] == FASTAUTO_MODE || pwr[TX] == FASTAUTO_MODE)
> > +   ufshcd_dme_set(hba, UIC_ARG_MIB(PA_HSSERIES), PA_HS_MODE_B);
> > +
> > +   ret = ufshcd_uic_change_pwr_mode(hba, pwr[RX] << 4 | pwr[TX]);
> > +   if (ret)
> > +   dev_err(hba->dev,
> > +   "pwr_mode: power mode change failed %d\n", ret);
> > +
> > +   return ret;
> > +}
> > +
> > +/**
> >* ufshcd_make_hba_operational - Make UFS controller operational
> >* @hba: per adapter instance
> >*
> > @@ -1754,8 +1818,14 @@ static void ufshcd_async_scan(void *data, 
> > async_cookie_t cookie)
> > int ret;
> >
> > ret = ufshcd_link_startup(hba);
> > -   if (!ret)
> > -   scsi_scan_host(hba->host);
> > +   if (ret)
> > +   goto out;
> > +
> > +   ufshcd_config_max_pwr_mode(hba);
> > +
> > +   scsi_scan_host(hba->host);
> > +out:
> > +   return;
> >   }
> >
> >   static struct scsi_host_template ufshcd_driver_template = {
> > diff --git a/drivers/scsi

RE: [PATCH 1/7] scsi: ufs: amend the ocs handling with fatal error

2013-08-13 Thread Seungwon Jeon
On Mon, August 12, 2013, Subhash Jadavani wrote:
> On 7/30/2013 6:32 PM, Seungwon Jeon wrote:
> > On Mon, July 29, 2013, Sujit Reddy Thumma wrote:
> >> On 7/29/2013 11:47 AM, Subhash Jadavani wrote:
> >>> On 7/26/2013 7:15 PM, Seungwon Jeon wrote:
> >>>> Fatal error in OCS(overall command status) field indicates
> >>>> error conditions which is not covered by UFSHCI.
> >>>> It means that host cannot define the result of command status
> >>>> and therefore host may need to check transfer response UPIU's
> >>>> response and status field.
> >>>> It was actually found that 'CHECK CONDITION' is stored in status
> >>>> field of UPIU where OCS is 'FATAL ERROR'.
> >> It looks like you are assuming that there will be some kind of response
> >> from the device. But the spec. mentions - "OCS_FATAL ERROR: within host
> >> controller that is not covered by the error conditions described above
> >> in this table."
> > Yes, error interrupt doesn't happen actually.
> >
> >> So spec. left everything to implementers on how to trigger this error.
> >> Also, it says "within host controller" so ufshcd_is_valid_req_rsp()
> >> might fail as well.
> >>
> >> I couldn't understand why there is a need for a host controller to
> >> interpret the SCSI command status and raise an OCS_FATAL_ERROR?
> > I feel like OCS values are related to syntax problem except OCS_FATAL_ERROR.
> > Basically, host controller may need to refer the Response field[Target 
> > Success/Target Failure] of
> response UPIU.
> > It's a overall result from response UPIU.
> > When Response field is 'Target Failure', if host controller updates the OCS 
> > field with 'SUCCESS',
> it's not proper behavior.
> > In this case host may refer the Status field of response UPIU to decide the 
> > OCS result.
> > Of course, it's not clear thing and could depends on host's implementation,
> > because there is no obvious description for that.
> > But if we consider the way to report UTP error from UFSHCI 8.2.4,
> > we can check the Response UPIU for more detailed error condition regardless 
> > OCS value.
> > Could you check your host side?
> 
> This is what our host documentation says: " SW may check the contents of
> Response UPIU when OCS !=0 for debug purposes. It may (or may not) help
> to understand the error scenario better. This is needed only for debug.
> When system is stable, OCS should be 0." So this clearly means that we
> shouldn't rely on the response UPIU if the OCS is non-zero hence simply
> ignore it.
Isn't  there any description for FATAL ERROR of OCS?
Can I take like below?
Even though Response field is 'Target Failure', OCS field can get a success 
result.
I just has focused what spec. says below:
- FATAL ERROR within host controller that is not covered by the error 
conditions described above in this table.
- The field contains the status code for the request.
-  Host software may need to check Transfer Response UPIU's Response, and 
possibly Sense Data to find out more details for the cause of the error.
Because host doesn't know and decide the error status, host could need to check.

> 
>  > "When Response field is 'Target Failure', if host controller updates
> the OCS field with 'SUCCESS', it's not proper behavior."
> 
> I doubt whether your above understanding is true from Host controller
> specification point of view. Host controller would not decode the
> “Response” field of the “response UPIU”, it would only decode the
> “Transaction Type” & “Task Tag” (and may be “LUN”) from the response
> UPIU in order to find out the correct slot in the transfer/task request
> list. Even 7.3.2.3 in UFSHCI spec also mentions the same.
> 
> I guess with this i don't see a need for this patch unless you feel
> otherwise.
It may depend on host's implementation. HCI spec. doesn't guide for OCS in 
detail.
Anyway, it's not clear just now.

Thanks,
Seungwon Jeon

> 
> Regards,
> Subhash
> 
> >
> > Thanks,
> > Seungwon Jeon
> >
> >> If it is clarified by the spec. then we can have generic implementation
> >> otherwise I would prefer to make this specific to those host controllers
> >> that raise OCS_FATAL_ERROR for CHECK_CONDITION.
> >>
> >>>> Signed-off-by: Seungwon Jeon 
> >>>> ---
> >>>>drivers/scsi/ufs/ufshcd.c |3 +--
> >>>>1 files changed, 1 inserti

[PATCH v2 0/6] scsi: ufs: some fixes and updates

2013-08-23 Thread Seungwon Jeon
This path series contain driver's fixes and updates.

Changes in v2:
- [scsi: ufs: amend the ocs handling with fatal error] is excluded.
   Host behavior needs to be defined clearly in UFSHCI specification.
- Some minor changes are applied with comments from Subhash, Sujit and Santosh.

Seungwon Jeon (6):
  scsi: ufs: find out sense data over scsi status values
  scsi: ufs: fix the setting interrupt aggregation counter
  scsi: ufs: add dme configuration primitives
  scsi: ufs: add unipro attribute IDs
  scsi: ufs: add operation for the uic power mode change
  scsi: ufs: configure the attribute for power mode

 drivers/scsi/ufs/ufs.h|1 +
 drivers/scsi/ufs/ufshcd.c |  336 ++---
 drivers/scsi/ufs/ufshcd.h |   54 +++
 drivers/scsi/ufs/ufshci.h |   22 +++-
 drivers/scsi/ufs/unipro.h |  151 
 5 files changed, 513 insertions(+), 51 deletions(-)

Thanks,
Seungwon Jeon

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 1/6] scsi: ufs: find out sense data over scsi status values

2013-08-23 Thread Seungwon Jeon
Unlike 'GOOD' and 'CHECK CONDITION', other status values in
Response UPIU may or may not contain sense data. That is returning
sense data isn't obvious. So, in this case the Data Segment Length
field should be checked. If a non-zero value, it means that UPIU
has Sense Data in the Data Segment area.

Signed-off-by: Seungwon Jeon 
Reviewed-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufs.h|1 +
 drivers/scsi/ufs/ufshcd.c |   37 ++---
 2 files changed, 23 insertions(+), 15 deletions(-)

diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index 139bc06..737c31b 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -114,6 +114,7 @@ enum {
MASK_SCSI_STATUS= 0xFF,
MASK_TASK_RESPONSE  = 0xFF00,
MASK_RSP_UPIU_RESULT= 0x,
+   MASK_RSP_UPIU_DATA_SEG_LEN  = 0x,
 };
 
 /* Task management service response */
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index b743bd6..529a0fc 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -218,6 +218,20 @@ ufshcd_get_rsp_upiu_result(struct utp_upiu_rsp 
*ucd_rsp_ptr)
return be32_to_cpu(ucd_rsp_ptr->header.dword_1) & MASK_RSP_UPIU_RESULT;
 }
 
+/*
+ * ufshcd_get_rsp_upiu_data_seg_len - Get the data segment length
+ * from response UPIU
+ * @ucd_rsp_ptr: pointer to response UPIU
+ *
+ * Return the data segment length.
+ */
+static inline unsigned int
+ufshcd_get_rsp_upiu_data_seg_len(struct utp_upiu_rsp *ucd_rsp_ptr)
+{
+   return be32_to_cpu(ucd_rsp_ptr->header.dword_2) &
+   MASK_RSP_UPIU_DATA_SEG_LEN;
+}
+
 /**
  * ufshcd_config_int_aggr - Configure interrupt aggregation values.
  * Currently there is no use case where we want to configure
@@ -298,7 +312,8 @@ void ufshcd_send_command(struct ufs_hba *hba, unsigned int 
task_tag)
 static inline void ufshcd_copy_sense_data(struct ufshcd_lrb *lrbp)
 {
int len;
-   if (lrbp->sense_buffer) {
+   if (lrbp->sense_buffer &&
+   ufshcd_get_rsp_upiu_data_seg_len(lrbp->ucd_rsp_ptr)) {
len = be16_to_cpu(lrbp->ucd_rsp_ptr->sense_data_len);
memcpy(lrbp->sense_buffer,
lrbp->ucd_rsp_ptr->sense_data,
@@ -1145,32 +1160,24 @@ ufshcd_scsi_cmd_status(struct ufshcd_lrb *lrbp, int 
scsi_status)
int result = 0;
 
switch (scsi_status) {
-   case SAM_STAT_GOOD:
-   result |= DID_OK << 16 |
- COMMAND_COMPLETE << 8 |
- SAM_STAT_GOOD;
-   break;
case SAM_STAT_CHECK_CONDITION:
+   ufshcd_copy_sense_data(lrbp);
+   case SAM_STAT_GOOD:
result |= DID_OK << 16 |
  COMMAND_COMPLETE << 8 |
- SAM_STAT_CHECK_CONDITION;
-   ufshcd_copy_sense_data(lrbp);
-   break;
-   case SAM_STAT_BUSY:
-   result |= SAM_STAT_BUSY;
+ scsi_status;
break;
case SAM_STAT_TASK_SET_FULL:
-
/*
 * If a LUN reports SAM_STAT_TASK_SET_FULL, then the LUN queue
 * depth needs to be adjusted to the exact number of
 * outstanding commands the LUN can handle at any given time.
 */
ufshcd_adjust_lun_qdepth(lrbp->cmd);
-   result |= SAM_STAT_TASK_SET_FULL;
-   break;
+   case SAM_STAT_BUSY:
case SAM_STAT_TASK_ABORTED:
-   result |= SAM_STAT_TASK_ABORTED;
+   ufshcd_copy_sense_data(lrbp);
+   result |= scsi_status;
break;
default:
result |= DID_ERROR << 16;
-- 
1.7.0.4


--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 2/6] scsi: ufs: fix the setting interrupt aggregation counter

2013-08-23 Thread Seungwon Jeon
IACTH(Interrupt aggregation counter threshold) value is allowed
up to 0x1F and current setting value is the maximum.
This value is related with NUTRS(max:0x20) of HCI's capability.
Considering HCI controller doesn't support the maximum, IACTH
setting should be adjusted with possible value.
For that, existing 'ufshcd_config_int_aggr' is split into two part
[reset, configure].

Signed-off-by: Seungwon Jeon 
Reviewed-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufshcd.c |   53 +---
 drivers/scsi/ufs/ufshci.h |4 +-
 2 files changed, 27 insertions(+), 30 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 529a0fc..2263795 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -43,6 +43,9 @@
 /* UIC command timeout, unit: ms */
 #define UIC_CMD_TIMEOUT500
 
+/* Interrupt aggregation default timeout, unit: 40us */
+#define INT_AGGR_DEF_TO0x02
+
 enum {
UFSHCD_MAX_CHANNEL  = 0,
UFSHCD_MAX_ID   = 1,
@@ -65,12 +68,6 @@ enum {
UFSHCD_INT_CLEAR,
 };
 
-/* Interrupt aggregation options */
-enum {
-   INT_AGGR_RESET,
-   INT_AGGR_CONFIG,
-};
-
 /**
  * ufshcd_get_intr_mask - Get the interrupt bit mask
  * @hba - Pointer to adapter instance
@@ -233,30 +230,30 @@ ufshcd_get_rsp_upiu_data_seg_len(struct utp_upiu_rsp 
*ucd_rsp_ptr)
 }
 
 /**
- * ufshcd_config_int_aggr - Configure interrupt aggregation values.
- * Currently there is no use case where we want to configure
- * interrupt aggregation dynamically. So to configure interrupt
- * aggregation, #define INT_AGGR_COUNTER_THRESHOLD_VALUE and
- * INT_AGGR_TIMEOUT_VALUE are used.
+ * ufshcd_reset_intr_aggr - Reset interrupt aggregation values.
  * @hba: per adapter instance
- * @option: Interrupt aggregation option
  */
 static inline void
-ufshcd_config_int_aggr(struct ufs_hba *hba, int option)
+ufshcd_reset_intr_aggr(struct ufs_hba *hba)
 {
-   switch (option) {
-   case INT_AGGR_RESET:
-   ufshcd_writel(hba, INT_AGGR_ENABLE |
- INT_AGGR_COUNTER_AND_TIMER_RESET,
- REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
-   break;
-   case INT_AGGR_CONFIG:
-   ufshcd_writel(hba, INT_AGGR_ENABLE | INT_AGGR_PARAM_WRITE |
- INT_AGGR_COUNTER_THRESHOLD_VALUE |
- INT_AGGR_TIMEOUT_VALUE,
- REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
-   break;
-   }
+   ufshcd_writel(hba, INT_AGGR_ENABLE |
+ INT_AGGR_COUNTER_AND_TIMER_RESET,
+ REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
+}
+
+/**
+ * ufshcd_config_intr_aggr - Configure interrupt aggregation values.
+ * @hba: per adapter instance
+ * @cntr_thld: Interrupt aggregation counter threshold
+ * @timeout: Interrupt aggregation timeout value
+ */
+static inline void
+ufshcd_config_intr_aggr(struct ufs_hba *hba, u8 cnt, u8 timeout)
+{
+   ufshcd_writel(hba, INT_AGGR_ENABLE | INT_AGGR_PARAM_WRITE |
+ INT_AGGR_COUNTER_THLD_VAL(cnt) |
+ INT_AGGR_TIMEOUT_VAL(timeout),
+ REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
 }
 
 /**
@@ -853,7 +850,7 @@ static int ufshcd_make_hba_operational(struct ufs_hba *hba)
ufshcd_enable_intr(hba, UFSHCD_ENABLE_INTRS);
 
/* Configure interrupt aggregation */
-   ufshcd_config_int_aggr(hba, INT_AGGR_CONFIG);
+   ufshcd_config_intr_aggr(hba, hba->nutrs - 1, INT_AGGR_DEF_TO);
 
/* Configure UTRL and UTMRL base address registers */
ufshcd_writel(hba, lower_32_bits(hba->utrdl_dma_addr),
@@ -1296,7 +1293,7 @@ static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
hba->outstanding_reqs ^= completed_reqs;
 
/* Reset interrupt aggregation counters */
-   ufshcd_config_int_aggr(hba, INT_AGGR_RESET);
+   ufshcd_reset_intr_aggr(hba);
 }
 
 /**
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
index d5c5f14..a8f69cc 100644
--- a/drivers/scsi/ufs/ufshci.h
+++ b/drivers/scsi/ufs/ufshci.h
@@ -226,8 +226,8 @@ enum {
 
 #define MASK_UIC_COMMAND_RESULT0xFF
 
-#define INT_AGGR_COUNTER_THRESHOLD_VALUE   (0x1F << 8)
-#define INT_AGGR_TIMEOUT_VALUE (0x02)
+#define INT_AGGR_COUNTER_THLD_VAL(c)   (((c) & 0x1F) << 8)
+#define INT_AGGR_TIMEOUT_VAL(t)(((t) & 0xFF) << 0)
 
 /* Interrupt disable masks */
 enum {
-- 
1.7.0.4


--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 4/6] scsi: ufs: add unipro attribute IDs

2013-08-23 Thread Seungwon Jeon
'drivers/scsi/ufs/unipro.h' is added.
Attributes in the layers of the UNIPRO stack can be
read and written via the DME.

Signed-off-by: Seungwon Jeon 
Reviewed-by: Subhash Jadavani 
---
 drivers/scsi/ufs/unipro.h |  130 +
 1 files changed, 130 insertions(+), 0 deletions(-)
 create mode 100644 drivers/scsi/ufs/unipro.h

diff --git a/drivers/scsi/ufs/unipro.h b/drivers/scsi/ufs/unipro.h
new file mode 100644
index 000..3a710eb
--- /dev/null
+++ b/drivers/scsi/ufs/unipro.h
@@ -0,0 +1,130 @@
+/*
+ * drivers/scsi/ufs/unipro.h
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef _UNIPRO_H_
+#define _UNIPRO_H_
+
+/*
+ * PHY Adpater attributes
+ */
+#define PA_ACTIVETXDATALANES   0x1560
+#define PA_ACTIVERXDATALANES   0x1580
+#define PA_TXTRAILINGCLOCKS0x1564
+#define PA_PHY_TYPE0x1500
+#define PA_AVAILTXDATALANES0x1520
+#define PA_AVAILRXDATALANES0x1540
+#define PA_MINRXTRAILINGCLOCKS 0x1543
+#define PA_TXPWRSTATUS 0x1567
+#define PA_RXPWRSTATUS 0x1582
+#define PA_TXFORCECLOCK0x1562
+#define PA_TXPWRMODE   0x1563
+#define PA_LEGACYDPHYESCDL 0x1570
+#define PA_MAXTXSPEEDFAST  0x1521
+#define PA_MAXTXSPEEDSLOW  0x1522
+#define PA_MAXRXSPEEDFAST  0x1541
+#define PA_MAXRXSPEEDSLOW  0x1542
+#define PA_TXLINKSTARTUPHS 0x1544
+#define PA_TXSPEEDFAST 0x1565
+#define PA_TXSPEEDSLOW 0x1566
+#define PA_REMOTEVERINFO   0x15A0
+#define PA_TXGEAR  0x1568
+#define PA_TXTERMINATION   0x1569
+#define PA_HSSERIES0x156A
+#define PA_PWRMODE 0x1571
+#define PA_RXGEAR  0x1583
+#define PA_RXTERMINATION   0x1584
+#define PA_MAXRXPWMGEAR0x1586
+#define PA_MAXRXHSGEAR 0x1587
+#define PA_RXHSUNTERMCAP   0x15A5
+#define PA_RXLSTERMCAP 0x15A6
+#define PA_PACPREQTIMEOUT  0x1590
+#define PA_PACPREQEOBTIMEOUT   0x1591
+#define PA_HIBERN8TIME 0x15A7
+#define PA_LOCALVERINFO0x15A9
+#define PA_TACTIVATE   0x15A8
+#define PA_PACPFRAMECOUNT  0x15C0
+#define PA_PACPERRORCOUNT  0x15C1
+#define PA_PHYTESTCONTROL  0x15C2
+#define PA_PWRMODEUSERDATA00x15B0
+#define PA_PWRMODEUSERDATA10x15B1
+#define PA_PWRMODEUSERDATA20x15B2
+#define PA_PWRMODEUSERDATA30x15B3
+#define PA_PWRMODEUSERDATA40x15B4
+#define PA_PWRMODEUSERDATA50x15B5
+#define PA_PWRMODEUSERDATA60x15B6
+#define PA_PWRMODEUSERDATA70x15B7
+#define PA_PWRMODEUSERDATA80x15B8
+#define PA_PWRMODEUSERDATA90x15B9
+#define PA_PWRMODEUSERDATA10   0x15BA
+#define PA_PWRMODEUSERDATA11   0x15BB
+#define PA_CONNECTEDTXDATALANES0x1561
+#define PA_CONNECTEDRXDATALANES0x1581
+#define PA_LOGICALLANEMAP  0x15A1
+#define PA_SLEEPNOCONFIGTIME   0x15A2
+#define PA_STALLNOCONFIGTIME   0x15A3
+#define PA_SAVECONFIGTIME  0x15A4
+
+/*
+ * Data Link Layer Attributes
+ */
+#define DL_TC0TXFCTHRESHOLD0x2040
+#define DL_FC0PROTTIMEOUTVAL   0x2041
+#define DL_TC0REPLAYTIMEOUTVAL 0x2042
+#define DL_AFC0REQTIMEOUTVAL   0x2043
+#define DL_AFC0CREDITTHRESHOLD 0x2044
+#define DL_TC0OUTACKTHRESHOLD  0x2045
+#define DL_TC1TXFCTHRESHOLD0x2060
+#define DL_FC1PROTTIMEOUTVAL   0x2061
+#define DL_TC1REPLAYTIMEOUTVAL 0x2062
+#define DL_AFC1REQTIMEOUTVAL   0x2063
+#define DL_AFC1CREDITTHRESHOLD 0x2064
+#define DL_TC1OUTACKTHRESHOLD  0x2065
+#define DL_TXPREEMPTIONCAP 0x2000
+#define DL_TC0TXMAXSDUSIZE 0x2001
+#define DL_TC0RXINITCREDITVAL  0x2002
+#define DL_TC0TXBUFFERSIZE 0x2005
+#define DL_PEERTC0PRESENT  0x2046
+#define DL_PEERTC0RXINITCREVAL 0x2047
+#define DL_TC1TXMAXSDUSIZE 0x2003
+#define DL_TC1RXINITCREDITVAL  0x2004
+#define DL_TC1TXBUFFERSIZE 0x2006
+#define DL_PEERTC1PRESENT  0x2066
+#define DL_PEERTC1RXINITCREVAL 0x2067
+
+/*
+ * Network Layer Attributes
+ */
+#define N_DEVICEID 0x3000
+#define N_DEVICEID_VALID   0x3001
+#define N_TC0TXMAXSDUSIZE  0x3020
+#define N_TC1TXMAXSDUSIZE  0x3021
+
+/*
+ * Transport Layer Attributes
+ */
+#define T_NUMCPORTS0x4000
+#define T_NUMTESTFEATURES  0x4001
+#define T_CONNECTIONSTATE  0x4020
+#define T_PEERDEVICEID 0x4021
+#define T_PEERCPORTID  0x4022
+#define T_TRAFFICCLASS 0x4023
+#define T_PROTOCOLID   0x4024
+#define T_CPORTFLAGS   0x4025
+#define T_TXTOKENVALUE 0x4026
+#define T_RXTOKENVALUE 0x4027
+#define T_LOCALBUFFERSPACE 0x4028
+#define T_PEERBUFFERSPACE  0x4029
+#define T_CREDITSTOSEND0x402A
+#define T_CPORTMODE0x402B
+#define T_TC0TXMAXSDUSIZE  0x4060
+#define T_TC1TX

[PATCH v2 3/6] scsi: ufs: add dme configuration primitives

2013-08-23 Thread Seungwon Jeon
Implements to support GET and SET operations of the DME.
These operations are used to configure the behavior of
the UNIPRO. Along with basic operation, {Peer/AttrSetType}
can be mixed.

Signed-off-by: Seungwon Jeon 
Reviewed-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufshcd.c |   88 +
 drivers/scsi/ufs/ufshcd.h |   51 ++
 drivers/scsi/ufs/ufshci.h |6 +++
 3 files changed, 145 insertions(+), 0 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 2263795..7fc262e 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -188,6 +188,18 @@ static inline int ufshcd_get_uic_cmd_result(struct ufs_hba 
*hba)
 }
 
 /**
+ * ufshcd_get_dme_attr_val - Get the value of attribute returned by UIC command
+ * @hba: Pointer to adapter instance
+ *
+ * This function gets UIC command argument3
+ * Returns 0 on success, non zero value on error
+ */
+static inline u32 ufshcd_get_dme_attr_val(struct ufs_hba *hba)
+{
+   return ufshcd_readl(hba, REG_UIC_COMMAND_ARG_3);
+}
+
+/**
  * ufshcd_is_valid_req_rsp - checks if controller TR response is valid
  * @ucd_rsp_ptr: pointer to response UPIU
  *
@@ -821,6 +833,80 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba)
 }
 
 /**
+ * ufshcd_dme_set_attr - UIC command for DME_SET, DME_PEER_SET
+ * @hba: per adapter instance
+ * @attr_sel: uic command argument1
+ * @attr_set: attribute set type as uic command argument2
+ * @mib_val: setting value as uic command argument3
+ * @peer: indicate whether peer or local
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+int ufshcd_dme_set_attr(struct ufs_hba *hba, u32 attr_sel,
+   u8 attr_set, u32 mib_val, u8 peer)
+{
+   struct uic_command uic_cmd = {0};
+   static const char *const action[] = {
+   "dme-set",
+   "dme-peer-set"
+   };
+   const char *set = action[!!peer];
+   int ret;
+
+   uic_cmd.command = peer ?
+   UIC_CMD_DME_PEER_SET : UIC_CMD_DME_SET;
+   uic_cmd.argument1 = attr_sel;
+   uic_cmd.argument2 = UIC_ARG_ATTR_TYPE(attr_set);
+   uic_cmd.argument3 = mib_val;
+
+   ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
+   if (ret)
+   dev_err(hba->dev, "%s: attr-id 0x%x val 0x%x error code %d\n",
+   set, UIC_GET_ATTR_ID(attr_sel), mib_val, ret);
+
+   return ret;
+}
+EXPORT_SYMBOL_GPL(ufshcd_dme_set_attr);
+
+/**
+ * ufshcd_dme_get_attr - UIC command for DME_GET, DME_PEER_GET
+ * @hba: per adapter instance
+ * @attr_sel: uic command argument1
+ * @mib_val: the value of the attribute as returned by the UIC command
+ * @peer: indicate whether peer or local
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel,
+   u32 *mib_val, u8 peer)
+{
+   struct uic_command uic_cmd = {0};
+   static const char *const action[] = {
+   "dme-get",
+   "dme-peer-get"
+   };
+   const char *get = action[!!peer];
+   int ret;
+
+   uic_cmd.command = peer ?
+   UIC_CMD_DME_PEER_GET : UIC_CMD_DME_GET;
+   uic_cmd.argument1 = attr_sel;
+
+   ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
+   if (ret) {
+   dev_err(hba->dev, "%s: attr-id 0x%x error code %d\n",
+   get, UIC_GET_ATTR_ID(attr_sel), ret);
+   goto out;
+   }
+
+   if (mib_val)
+   *mib_val = uic_cmd.argument3;
+out:
+   return ret;
+}
+EXPORT_SYMBOL_GPL(ufshcd_dme_get_attr);
+
+/**
  * ufshcd_make_hba_operational - Make UFS controller operational
  * @hba: per adapter instance
  *
@@ -1253,6 +1339,8 @@ static void ufshcd_uic_cmd_compl(struct ufs_hba *hba)
if (hba->active_uic_cmd) {
hba->active_uic_cmd->argument2 |=
ufshcd_get_uic_cmd_result(hba);
+   hba->active_uic_cmd->argument3 =
+   ufshcd_get_dme_attr_val(hba);
complete(&hba->active_uic_cmd->done);
}
 }
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 49590ee..50bcd29 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -199,6 +199,11 @@ int ufshcd_init(struct device *, struct ufs_hba ** , void 
__iomem * ,
unsigned int);
 void ufshcd_remove(struct ufs_hba *);
 
+extern int ufshcd_dme_set_attr(struct ufs_hba *hba, u32 attr_sel,
+  u8 attr_set, u32 mib_val, u8 peer);
+extern int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel,
+  u32 *mib_val, u8 peer);
+
 /**
  * ufshcd_hba_stop - Send controller to reset state
  * @hba: per adapter instance
@@ -208,4 +213,50 @@ static inline void ufshcd_hba_stop(struct ufs_hba

[PATCH v2 5/6] scsi: ufs: add operation for the uic power mode change

2013-08-23 Thread Seungwon Jeon
Setting PA_PWRMode using DME_SET triggers the power mode
change. And then the result will be given by the HCS.UPMCRS.
This operation should be done atomically.

Signed-off-by: Seungwon Jeon 
---
 drivers/scsi/ufs/ufshcd.c |   84 ++--
 drivers/scsi/ufs/ufshcd.h |3 ++
 drivers/scsi/ufs/ufshci.h |   12 ++
 3 files changed, 95 insertions(+), 4 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 7fc262e..8f25df4 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -36,9 +36,11 @@
 #include 
 
 #include "ufshcd.h"
+#include "unipro.h"
 
 #define UFSHCD_ENABLE_INTRS(UTP_TRANSFER_REQ_COMPL |\
 UTP_TASK_REQ_COMPL |\
+UIC_POWER_MODE |\
 UFSHCD_ERROR_MASK)
 /* UIC command timeout, unit: ms */
 #define UIC_CMD_TIMEOUT500
@@ -359,6 +361,18 @@ static inline bool ufshcd_ready_for_uic_cmd(struct ufs_hba 
*hba)
 }
 
 /**
+ * ufshcd_get_upmcrs - Get the power mode change request status
+ * @hba: Pointer to adapter instance
+ *
+ * This function gets the UPMCRS field of HCS register
+ * Returns value of UPMCRS field
+ */
+static inline u8 ufshcd_get_upmcrs(struct ufs_hba *hba)
+{
+   return (ufshcd_readl(hba, REG_CONTROLLER_STATUS) >> 8) & 0x7;
+}
+
+/**
  * ufshcd_dispatch_uic_cmd - Dispatch UIC commands to unipro layers
  * @hba: per adapter instance
  * @uic_cmd: UIC command
@@ -907,6 +921,64 @@ out:
 EXPORT_SYMBOL_GPL(ufshcd_dme_get_attr);
 
 /**
+ * ufshcd_uic_change_pwr_mode - Perform the UIC power mode chage
+ * using DME_SET primitives.
+ * @hba: per adapter instance
+ * @mode: powr mode value
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+int ufshcd_uic_change_pwr_mode(struct ufs_hba *hba, u8 mode)
+{
+   struct uic_command uic_cmd = {0};
+   struct completion pwr_done;
+   unsigned long flags;
+   u8 status;
+   int ret;
+
+   uic_cmd.command = UIC_CMD_DME_SET;
+   uic_cmd.argument1 = UIC_ARG_MIB(PA_PWRMODE);
+   uic_cmd.argument3 = mode;
+   init_completion(&pwr_done);
+
+   mutex_lock(&hba->uic_cmd_mutex);
+
+   spin_lock_irqsave(hba->host->host_lock, flags);
+   hba->pwr_done = &pwr_done;
+   spin_unlock_irqrestore(hba->host->host_lock, flags);
+   ret = __ufshcd_send_uic_cmd(hba, &uic_cmd);
+   if (ret) {
+   dev_err(hba->dev,
+   "pwr mode change with mode 0x%x uic error %d\n",
+   mode, ret);
+   goto out;
+   }
+
+   if (!wait_for_completion_timeout(hba->pwr_done,
+msecs_to_jiffies(UIC_CMD_TIMEOUT))) {
+   dev_err(hba->dev,
+   "pwr mode change with mode 0x%x completion timeout\n",
+   mode);
+   ret = -ETIMEDOUT;
+   goto out;
+   }
+
+   status = ufshcd_get_upmcrs(hba);
+   if (status != PWR_LOCAL) {
+   dev_err(hba->dev,
+   "pwr mode change failed, host umpcrs:0x%x\n",
+   status);
+   ret = (status != PWR_OK) ? status : -1;
+   }
+out:
+   spin_lock_irqsave(hba->host->host_lock, flags);
+   hba->pwr_done = NULL;
+   spin_unlock_irqrestore(hba->host->host_lock, flags);
+   mutex_unlock(&hba->uic_cmd_mutex);
+   return ret;
+}
+
+/**
  * ufshcd_make_hba_operational - Make UFS controller operational
  * @hba: per adapter instance
  *
@@ -1333,16 +1405,20 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct 
ufshcd_lrb *lrbp)
 /**
  * ufshcd_uic_cmd_compl - handle completion of uic command
  * @hba: per adapter instance
+ * @intr_status: interrupt status generated by the controller
  */
-static void ufshcd_uic_cmd_compl(struct ufs_hba *hba)
+static void ufshcd_uic_cmd_compl(struct ufs_hba *hba, u32 intr_status)
 {
-   if (hba->active_uic_cmd) {
+   if ((intr_status & UIC_COMMAND_COMPL) && hba->active_uic_cmd) {
hba->active_uic_cmd->argument2 |=
ufshcd_get_uic_cmd_result(hba);
hba->active_uic_cmd->argument3 =
ufshcd_get_dme_attr_val(hba);
complete(&hba->active_uic_cmd->done);
}
+
+   if ((intr_status & UIC_POWER_MODE) && hba->pwr_done)
+   complete(hba->pwr_done);
 }
 
 /**
@@ -1444,8 +1520,8 @@ static void ufshcd_sl_intr(struct ufs_hba *hba, u32 
intr_status)
if (hba->errors)
ufshcd_err_handler(hba);
 
-   if (intr_status & UIC_COMMAND_COMPL)
-   ufshcd_uic_cmd_compl(hba);
+   if (intr_status & UFSHCD_UIC_MASK)
+   ufshcd_uic_c

[PATCH v2 6/6] scsi: ufs: configure the attribute for power mode

2013-08-23 Thread Seungwon Jeon
UIC attributes can be set with using DME_SET command for
power mode change. For configuration the link capability
attributes are used, which is updated after successful
link startup.

Signed-off-by: Seungwon Jeon 
Reviewed-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufshcd.c |   74 +++-
 drivers/scsi/ufs/unipro.h |   21 +
 2 files changed, 93 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 8f25df4..54fdbab 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -979,6 +979,70 @@ out:
 }
 
 /**
+ * ufshcd_config_max_pwr_mode - Set & Change power mode with
+ * maximum capability attribute information.
+ * @hba: per adapter instance
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+static int ufshcd_config_max_pwr_mode(struct ufs_hba *hba)
+{
+   enum {RX = 0, TX = 1};
+   u32 lanes[] = {1, 1};
+   u32 gear[] = {1, 1};
+   u8 pwr[] = {FASTAUTO_MODE, FASTAUTO_MODE};
+   int i, ret;
+
+   /* Get the connected lane count */
+   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDRXDATALANES), &lanes[RX]);
+   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES), &lanes[TX]);
+
+   /*
+* First, get the maximum gears of HS speed.
+* If a zero value, it means there is no HSGEAR capability.
+* Then, get the maximum gears of PWM speed.
+*/
+   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR), &gear[RX]);
+   if (!gear[RX]) {
+   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXPWMGEAR), &gear[RX]);
+   pwr[RX] = SLOWAUTO_MODE;
+   }
+
+   ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR), &gear[TX]);
+   if (!gear[TX]) {
+   ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_MAXRXPWMGEAR),
+   &gear[TX]);
+   pwr[TX] = SLOWAUTO_MODE;
+   }
+
+   /*
+* Configure attributes for power mode change with below.
+* - PA_RXGEAR, PA_ACTIVERXDATALANES, PA_RXTERMINATION,
+* - PA_TXGEAR, PA_ACTIVETXDATALANES, PA_TXTERMINATION,
+* - PA_HSSERIES
+*/
+   ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXGEAR), gear[RX]);
+   ufshcd_dme_set(hba, UIC_ARG_MIB(PA_ACTIVERXDATALANES), lanes[RX]);
+   if (pwr[RX] == FASTAUTO_MODE)
+   ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXTERMINATION), TRUE);
+
+   ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXGEAR), gear[TX]);
+   ufshcd_dme_set(hba, UIC_ARG_MIB(PA_ACTIVETXDATALANES), lanes[TX]);
+   if (pwr[TX] == FASTAUTO_MODE)
+   ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXTERMINATION), TRUE);
+
+   if (pwr[RX] == FASTAUTO_MODE || pwr[TX] == FASTAUTO_MODE)
+   ufshcd_dme_set(hba, UIC_ARG_MIB(PA_HSSERIES), PA_HS_MODE_B);
+
+   ret = ufshcd_uic_change_pwr_mode(hba, pwr[RX] << 4 | pwr[TX]);
+   if (ret)
+   dev_err(hba->dev,
+   "pwr_mode: power mode change failed %d\n", ret);
+
+   return ret;
+}
+
+/**
  * ufshcd_make_hba_operational - Make UFS controller operational
  * @hba: per adapter instance
  *
@@ -1755,8 +1819,14 @@ static void ufshcd_async_scan(void *data, async_cookie_t 
cookie)
int ret;
 
ret = ufshcd_link_startup(hba);
-   if (!ret)
-   scsi_scan_host(hba->host);
+   if (ret)
+   goto out;
+
+   ufshcd_config_max_pwr_mode(hba);
+
+   scsi_scan_host(hba->host);
+out:
+   return;
 }
 
 static struct scsi_host_template ufshcd_driver_template = {
diff --git a/drivers/scsi/ufs/unipro.h b/drivers/scsi/ufs/unipro.h
index 3a710eb..0bb8041 100644
--- a/drivers/scsi/ufs/unipro.h
+++ b/drivers/scsi/ufs/unipro.h
@@ -72,6 +72,21 @@
 #define PA_STALLNOCONFIGTIME   0x15A3
 #define PA_SAVECONFIGTIME  0x15A4
 
+/* PA power modes */
+enum {
+   FAST_MODE   = 1,
+   SLOW_MODE   = 2,
+   FASTAUTO_MODE   = 4,
+   SLOWAUTO_MODE   = 5,
+   UNCHANGED   = 7,
+};
+
+/* PA TX/RX Frequency Series */
+enum {
+   PA_HS_MODE_A= 1,
+   PA_HS_MODE_B= 2,
+};
+
 /*
  * Data Link Layer Attributes
  */
@@ -127,4 +142,10 @@
 #define T_TC0TXMAXSDUSIZE  0x4060
 #define T_TC1TXMAXSDUSIZE  0x4061
 
+/* Boolean attribute values */
+enum {
+   FALSE = 0,
+   TRUE,
+};
+
 #endif /* _UNIPRO_H_ */
-- 
1.7.0.4


--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 1/2] scsi: fix warning with unused variable

2013-08-26 Thread Seungwon Jeon
drivers/scsi/scsi_error.c:246:16: warning: unused variable 'flags' 
[-Wunused-variable]

Signed-off-by: Seungwon Jeon 
---
 drivers/scsi/scsi_error.c |1 -
 1 files changed, 0 insertions(+), 1 deletions(-)

diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index f16d1a6..83e591b 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -243,7 +243,6 @@ static void scsi_report_sense(struct scsi_device *sdev,
  struct scsi_sense_hdr *sshdr)
 {
enum scsi_device_event evt_type = SDEV_EVT_MAXBITS; /* i.e. none */
-   unsigned long flags;
 
if (sshdr->sense_key == UNIT_ATTENTION) {
if (sshdr->asc == 0x3f && sshdr->ascq == 0x03) {
-- 
1.7.0.4


--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 2/2] scsi: replace the deprecated flush_work_sync

2013-08-26 Thread Seungwon Jeon
flush_work_sync is replaced by flush_work with commit
4382973(workqueue: deprecate flush[_delayed]_work_sync()).

Signed-off-by: Seungwon Jeon 
---
 drivers/scsi/arcmsr/arcmsr_hba.c |4 ++--
 drivers/scsi/ufs/ufshcd.c|2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
index aac6378..e1ea1ca 100644
--- a/drivers/scsi/arcmsr/arcmsr_hba.c
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -1599,7 +1599,7 @@ arcmsr_remove(struct pci_dev *pdev)
int poll_count = 0, i;
arcmsr_free_sysfs_attr(acb);
scsi_remove_host(host);
-   flush_work_sync(&acb->arcmsr_do_message_isr_bh);
+   flush_work(&acb->arcmsr_do_message_isr_bh);
del_timer_sync(&acb->eternal_timer);
arcmsr_disable_outbound_ints(acb);
arcmsr_stop_adapter_bgrb(acb);
@@ -1661,7 +1661,7 @@ arcmsr_shutdown(struct pci_dev *pdev)
pci_disable_msix(pdev);
} else
free_irq(pdev->irq, acb);
-   flush_work_sync(&acb->arcmsr_do_message_isr_bh);
+   flush_work(&acb->arcmsr_do_message_isr_bh);
arcmsr_stop_adapter_bgrb(acb);
arcmsr_flush_adapter_cache(acb);
 }
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index a0f5ac2..1b99c0a 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -2737,7 +2737,7 @@ static int ufshcd_eh_host_reset_handler(struct scsi_cmnd 
*cmd)
break;
spin_unlock_irqrestore(hba->host->host_lock, flags);
dev_dbg(hba->dev, "%s: reset in progress\n", __func__);
-   flush_work_sync(&hba->eh_work);
+   flush_work(&hba->eh_work);
} while (1);
 
hba->ufshcd_state = UFSHCD_STATE_RESET;
-- 
1.7.0.4


--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v3 4/6] scsi: ufs: add unipro attribute IDs

2013-08-26 Thread Seungwon Jeon
'drivers/scsi/ufs/unipro.h' is added.
Attributes in the layers of the UNIPRO stack can be
read and written via the DME.

Signed-off-by: Seungwon Jeon 
Reviewed-by: Subhash Jadavani 
---
 drivers/scsi/ufs/unipro.h |  130 +
 1 files changed, 130 insertions(+), 0 deletions(-)
 create mode 100644 drivers/scsi/ufs/unipro.h

diff --git a/drivers/scsi/ufs/unipro.h b/drivers/scsi/ufs/unipro.h
new file mode 100644
index 000..3a710eb
--- /dev/null
+++ b/drivers/scsi/ufs/unipro.h
@@ -0,0 +1,130 @@
+/*
+ * drivers/scsi/ufs/unipro.h
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef _UNIPRO_H_
+#define _UNIPRO_H_
+
+/*
+ * PHY Adpater attributes
+ */
+#define PA_ACTIVETXDATALANES   0x1560
+#define PA_ACTIVERXDATALANES   0x1580
+#define PA_TXTRAILINGCLOCKS0x1564
+#define PA_PHY_TYPE0x1500
+#define PA_AVAILTXDATALANES0x1520
+#define PA_AVAILRXDATALANES0x1540
+#define PA_MINRXTRAILINGCLOCKS 0x1543
+#define PA_TXPWRSTATUS 0x1567
+#define PA_RXPWRSTATUS 0x1582
+#define PA_TXFORCECLOCK0x1562
+#define PA_TXPWRMODE   0x1563
+#define PA_LEGACYDPHYESCDL 0x1570
+#define PA_MAXTXSPEEDFAST  0x1521
+#define PA_MAXTXSPEEDSLOW  0x1522
+#define PA_MAXRXSPEEDFAST  0x1541
+#define PA_MAXRXSPEEDSLOW  0x1542
+#define PA_TXLINKSTARTUPHS 0x1544
+#define PA_TXSPEEDFAST 0x1565
+#define PA_TXSPEEDSLOW 0x1566
+#define PA_REMOTEVERINFO   0x15A0
+#define PA_TXGEAR  0x1568
+#define PA_TXTERMINATION   0x1569
+#define PA_HSSERIES0x156A
+#define PA_PWRMODE 0x1571
+#define PA_RXGEAR  0x1583
+#define PA_RXTERMINATION   0x1584
+#define PA_MAXRXPWMGEAR0x1586
+#define PA_MAXRXHSGEAR 0x1587
+#define PA_RXHSUNTERMCAP   0x15A5
+#define PA_RXLSTERMCAP 0x15A6
+#define PA_PACPREQTIMEOUT  0x1590
+#define PA_PACPREQEOBTIMEOUT   0x1591
+#define PA_HIBERN8TIME 0x15A7
+#define PA_LOCALVERINFO0x15A9
+#define PA_TACTIVATE   0x15A8
+#define PA_PACPFRAMECOUNT  0x15C0
+#define PA_PACPERRORCOUNT  0x15C1
+#define PA_PHYTESTCONTROL  0x15C2
+#define PA_PWRMODEUSERDATA00x15B0
+#define PA_PWRMODEUSERDATA10x15B1
+#define PA_PWRMODEUSERDATA20x15B2
+#define PA_PWRMODEUSERDATA30x15B3
+#define PA_PWRMODEUSERDATA40x15B4
+#define PA_PWRMODEUSERDATA50x15B5
+#define PA_PWRMODEUSERDATA60x15B6
+#define PA_PWRMODEUSERDATA70x15B7
+#define PA_PWRMODEUSERDATA80x15B8
+#define PA_PWRMODEUSERDATA90x15B9
+#define PA_PWRMODEUSERDATA10   0x15BA
+#define PA_PWRMODEUSERDATA11   0x15BB
+#define PA_CONNECTEDTXDATALANES0x1561
+#define PA_CONNECTEDRXDATALANES0x1581
+#define PA_LOGICALLANEMAP  0x15A1
+#define PA_SLEEPNOCONFIGTIME   0x15A2
+#define PA_STALLNOCONFIGTIME   0x15A3
+#define PA_SAVECONFIGTIME  0x15A4
+
+/*
+ * Data Link Layer Attributes
+ */
+#define DL_TC0TXFCTHRESHOLD0x2040
+#define DL_FC0PROTTIMEOUTVAL   0x2041
+#define DL_TC0REPLAYTIMEOUTVAL 0x2042
+#define DL_AFC0REQTIMEOUTVAL   0x2043
+#define DL_AFC0CREDITTHRESHOLD 0x2044
+#define DL_TC0OUTACKTHRESHOLD  0x2045
+#define DL_TC1TXFCTHRESHOLD0x2060
+#define DL_FC1PROTTIMEOUTVAL   0x2061
+#define DL_TC1REPLAYTIMEOUTVAL 0x2062
+#define DL_AFC1REQTIMEOUTVAL   0x2063
+#define DL_AFC1CREDITTHRESHOLD 0x2064
+#define DL_TC1OUTACKTHRESHOLD  0x2065
+#define DL_TXPREEMPTIONCAP 0x2000
+#define DL_TC0TXMAXSDUSIZE 0x2001
+#define DL_TC0RXINITCREDITVAL  0x2002
+#define DL_TC0TXBUFFERSIZE 0x2005
+#define DL_PEERTC0PRESENT  0x2046
+#define DL_PEERTC0RXINITCREVAL 0x2047
+#define DL_TC1TXMAXSDUSIZE 0x2003
+#define DL_TC1RXINITCREDITVAL  0x2004
+#define DL_TC1TXBUFFERSIZE 0x2006
+#define DL_PEERTC1PRESENT  0x2066
+#define DL_PEERTC1RXINITCREVAL 0x2067
+
+/*
+ * Network Layer Attributes
+ */
+#define N_DEVICEID 0x3000
+#define N_DEVICEID_VALID   0x3001
+#define N_TC0TXMAXSDUSIZE  0x3020
+#define N_TC1TXMAXSDUSIZE  0x3021
+
+/*
+ * Transport Layer Attributes
+ */
+#define T_NUMCPORTS0x4000
+#define T_NUMTESTFEATURES  0x4001
+#define T_CONNECTIONSTATE  0x4020
+#define T_PEERDEVICEID 0x4021
+#define T_PEERCPORTID  0x4022
+#define T_TRAFFICCLASS 0x4023
+#define T_PROTOCOLID   0x4024
+#define T_CPORTFLAGS   0x4025
+#define T_TXTOKENVALUE 0x4026
+#define T_RXTOKENVALUE 0x4027
+#define T_LOCALBUFFERSPACE 0x4028
+#define T_PEERBUFFERSPACE  0x4029
+#define T_CREDITSTOSEND0x402A
+#define T_CPORTMODE0x402B
+#define T_TC0TXMAXSDUSIZE  0x4060
+#define T_TC1TX

[PATCH v3 6/6] scsi: ufs: configure the attribute for power mode

2013-08-26 Thread Seungwon Jeon
UIC attributes can be set with using DME_SET command for
power mode change. For configuration the link capability
attributes are used, which is updated after successful
link startup.

Signed-off-by: Seungwon Jeon 
Reviewed-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufshcd.c |   66 +
 drivers/scsi/ufs/unipro.h |   21 ++
 2 files changed, 87 insertions(+), 0 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index c67118d..2ae845c 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -1598,6 +1598,70 @@ out:
 }
 
 /**
+ * ufshcd_config_max_pwr_mode - Set & Change power mode with
+ * maximum capability attribute information.
+ * @hba: per adapter instance
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+static int ufshcd_config_max_pwr_mode(struct ufs_hba *hba)
+{
+   enum {RX = 0, TX = 1};
+   u32 lanes[] = {1, 1};
+   u32 gear[] = {1, 1};
+   u8 pwr[] = {FASTAUTO_MODE, FASTAUTO_MODE};
+   int ret;
+
+   /* Get the connected lane count */
+   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDRXDATALANES), &lanes[RX]);
+   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES), &lanes[TX]);
+
+   /*
+* First, get the maximum gears of HS speed.
+* If a zero value, it means there is no HSGEAR capability.
+* Then, get the maximum gears of PWM speed.
+*/
+   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR), &gear[RX]);
+   if (!gear[RX]) {
+   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXPWMGEAR), &gear[RX]);
+   pwr[RX] = SLOWAUTO_MODE;
+   }
+
+   ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR), &gear[TX]);
+   if (!gear[TX]) {
+   ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_MAXRXPWMGEAR),
+   &gear[TX]);
+   pwr[TX] = SLOWAUTO_MODE;
+   }
+
+   /*
+* Configure attributes for power mode change with below.
+* - PA_RXGEAR, PA_ACTIVERXDATALANES, PA_RXTERMINATION,
+* - PA_TXGEAR, PA_ACTIVETXDATALANES, PA_TXTERMINATION,
+* - PA_HSSERIES
+*/
+   ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXGEAR), gear[RX]);
+   ufshcd_dme_set(hba, UIC_ARG_MIB(PA_ACTIVERXDATALANES), lanes[RX]);
+   if (pwr[RX] == FASTAUTO_MODE)
+   ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXTERMINATION), TRUE);
+
+   ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXGEAR), gear[TX]);
+   ufshcd_dme_set(hba, UIC_ARG_MIB(PA_ACTIVETXDATALANES), lanes[TX]);
+   if (pwr[TX] == FASTAUTO_MODE)
+   ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXTERMINATION), TRUE);
+
+   if (pwr[RX] == FASTAUTO_MODE || pwr[TX] == FASTAUTO_MODE)
+   ufshcd_dme_set(hba, UIC_ARG_MIB(PA_HSSERIES), PA_HS_MODE_B);
+
+   ret = ufshcd_uic_change_pwr_mode(hba, pwr[RX] << 4 | pwr[TX]);
+   if (ret)
+   dev_err(hba->dev,
+   "pwr_mode: power mode change failed %d\n", ret);
+
+   return ret;
+}
+
+/**
  * ufshcd_complete_dev_init() - checks device readiness
  * hba: per-adapter instance
  *
@@ -2942,6 +3006,8 @@ static void ufshcd_async_scan(void *data, async_cookie_t 
cookie)
if (ret)
goto out;
 
+   ufshcd_config_max_pwr_mode(hba);
+
ret = ufshcd_verify_dev_init(hba);
if (ret)
goto out;
diff --git a/drivers/scsi/ufs/unipro.h b/drivers/scsi/ufs/unipro.h
index 3a710eb..0bb8041 100644
--- a/drivers/scsi/ufs/unipro.h
+++ b/drivers/scsi/ufs/unipro.h
@@ -72,6 +72,21 @@
 #define PA_STALLNOCONFIGTIME   0x15A3
 #define PA_SAVECONFIGTIME  0x15A4
 
+/* PA power modes */
+enum {
+   FAST_MODE   = 1,
+   SLOW_MODE   = 2,
+   FASTAUTO_MODE   = 4,
+   SLOWAUTO_MODE   = 5,
+   UNCHANGED   = 7,
+};
+
+/* PA TX/RX Frequency Series */
+enum {
+   PA_HS_MODE_A= 1,
+   PA_HS_MODE_B= 2,
+};
+
 /*
  * Data Link Layer Attributes
  */
@@ -127,4 +142,10 @@
 #define T_TC0TXMAXSDUSIZE  0x4060
 #define T_TC1TXMAXSDUSIZE  0x4061
 
+/* Boolean attribute values */
+enum {
+   FALSE = 0,
+   TRUE,
+};
+
 #endif /* _UNIPRO_H_ */
-- 
1.7.0.4


--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v3 0/6] scsi: ufs: some fixes and updates

2013-08-26 Thread Seungwon Jeon
This path series contain driver's fixes and updates.

Changes in v3:
 - Rebased with scsi-next

Changes in v2:
- [scsi: ufs: amend the ocs handling with fatal error] is excluded.
   Host behavior needs to be defined clearly in UFSHCI specification.
- Some minor changes are applied with comments from Subhash, Sujit and Santosh.

Seungwon Jeon (6):
  scsi: ufs: find out sense data over scsi status values
  scsi: ufs: fix the setting interrupt aggregation counter
  scsi: ufs: add dme configuration primitives
  scsi: ufs: add unipro attribute IDs
  scsi: ufs: add operation for the uic power mode change
  scsi: ufs: configure the attribute for power mode

 drivers/scsi/ufs/ufs.h|1 +
 drivers/scsi/ufs/ufshcd.c |  328 ++---
 drivers/scsi/ufs/ufshcd.h |   54 
 drivers/scsi/ufs/ufshci.h |   22 +++-
 drivers/scsi/ufs/unipro.h |  151 +
 5 files changed, 507 insertions(+), 49 deletions(-)

Thanks,
Seungwon Jeon

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v3 2/6] scsi: ufs: fix the setting interrupt aggregation counter

2013-08-26 Thread Seungwon Jeon
IACTH(Interrupt aggregation counter threshold) value is allowed
up to 0x1F and current setting value is the maximum.
This value is related with NUTRS(max:0x20) of HCI's capability.
Considering HCI controller doesn't support the maximum, IACTH
setting should be adjusted with possible value.
For that, existing 'ufshcd_config_int_aggr' is split into two part
[reset, configure].

Signed-off-by: Seungwon Jeon 
Reviewed-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufshcd.c |   53 +---
 drivers/scsi/ufs/ufshci.h |4 +-
 2 files changed, 27 insertions(+), 30 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 6ff16c9..c90b88a 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -59,6 +59,9 @@
 /* Expose the flag value from utp_upiu_query.value */
 #define MASK_QUERY_UPIU_FLAG_LOC 0xFF
 
+/* Interrupt aggregation default timeout, unit: 40us */
+#define INT_AGGR_DEF_TO0x02
+
 enum {
UFSHCD_MAX_CHANNEL  = 0,
UFSHCD_MAX_ID   = 1,
@@ -94,12 +97,6 @@ enum {
UFSHCD_INT_CLEAR,
 };
 
-/* Interrupt aggregation options */
-enum {
-   INT_AGGR_RESET,
-   INT_AGGR_CONFIG,
-};
-
 #define ufshcd_set_eh_in_progress(h) \
(h->eh_flags |= UFSHCD_EH_IN_PROGRESS)
 #define ufshcd_eh_in_progress(h) \
@@ -340,30 +337,30 @@ static inline bool ufshcd_is_exception_event(struct 
utp_upiu_rsp *ucd_rsp_ptr)
 }
 
 /**
- * ufshcd_config_int_aggr - Configure interrupt aggregation values.
- * Currently there is no use case where we want to configure
- * interrupt aggregation dynamically. So to configure interrupt
- * aggregation, #define INT_AGGR_COUNTER_THRESHOLD_VALUE and
- * INT_AGGR_TIMEOUT_VALUE are used.
+ * ufshcd_reset_intr_aggr - Reset interrupt aggregation values.
  * @hba: per adapter instance
- * @option: Interrupt aggregation option
  */
 static inline void
-ufshcd_config_int_aggr(struct ufs_hba *hba, int option)
+ufshcd_reset_intr_aggr(struct ufs_hba *hba)
 {
-   switch (option) {
-   case INT_AGGR_RESET:
-   ufshcd_writel(hba, INT_AGGR_ENABLE |
- INT_AGGR_COUNTER_AND_TIMER_RESET,
- REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
-   break;
-   case INT_AGGR_CONFIG:
-   ufshcd_writel(hba, INT_AGGR_ENABLE | INT_AGGR_PARAM_WRITE |
- INT_AGGR_COUNTER_THRESHOLD_VALUE |
- INT_AGGR_TIMEOUT_VALUE,
- REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
-   break;
-   }
+   ufshcd_writel(hba, INT_AGGR_ENABLE |
+ INT_AGGR_COUNTER_AND_TIMER_RESET,
+ REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
+}
+
+/**
+ * ufshcd_config_intr_aggr - Configure interrupt aggregation values.
+ * @hba: per adapter instance
+ * @cnt: Interrupt aggregation counter threshold
+ * @tmout: Interrupt aggregation timeout value
+ */
+static inline void
+ufshcd_config_intr_aggr(struct ufs_hba *hba, u8 cnt, u8 tmout)
+{
+   ufshcd_writel(hba, INT_AGGR_ENABLE | INT_AGGR_PARAM_WRITE |
+ INT_AGGR_COUNTER_THLD_VAL(cnt) |
+ INT_AGGR_TIMEOUT_VAL(tmout),
+ REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
 }
 
 /**
@@ -1523,7 +1520,7 @@ static int ufshcd_make_hba_operational(struct ufs_hba 
*hba)
ufshcd_enable_intr(hba, UFSHCD_ENABLE_INTRS);
 
/* Configure interrupt aggregation */
-   ufshcd_config_int_aggr(hba, INT_AGGR_CONFIG);
+   ufshcd_config_intr_aggr(hba, hba->nutrs - 1, INT_AGGR_DEF_TO);
 
/* Configure UTRL and UTMRL base address registers */
ufshcd_writel(hba, lower_32_bits(hba->utrdl_dma_addr),
@@ -1971,7 +1968,7 @@ static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
 
/* Reset interrupt aggregation counters */
if (int_aggr_reset)
-   ufshcd_config_int_aggr(hba, INT_AGGR_RESET);
+   ufshcd_reset_intr_aggr(hba);
 }
 
 /**
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
index f1e1b74..739ae3a 100644
--- a/drivers/scsi/ufs/ufshci.h
+++ b/drivers/scsi/ufs/ufshci.h
@@ -226,8 +226,8 @@ enum {
 
 #define MASK_UIC_COMMAND_RESULT0xFF
 
-#define INT_AGGR_COUNTER_THRESHOLD_VALUE   (0x1F << 8)
-#define INT_AGGR_TIMEOUT_VALUE (0x02)
+#define INT_AGGR_COUNTER_THLD_VAL(c)   (((c) & 0x1F) << 8)
+#define INT_AGGR_TIMEOUT_VAL(t)(((t) & 0xFF) << 0)
 
 /* Interrupt disable masks */
 enum {
-- 
1.7.0.4


--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v3 3/6] scsi: ufs: add dme configuration primitives

2013-08-26 Thread Seungwon Jeon
Implements to support GET and SET operations of the DME.
These operations are used to configure the behavior of
the UNIPRO. Along with basic operation, {Peer/AttrSetType}
can be mixed.

Signed-off-by: Seungwon Jeon 
Reviewed-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufshcd.c |   88 +
 drivers/scsi/ufs/ufshcd.h |   51 ++
 drivers/scsi/ufs/ufshci.h |6 +++
 3 files changed, 145 insertions(+), 0 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index c90b88a..00bfc1a 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -285,6 +285,18 @@ static inline int ufshcd_get_uic_cmd_result(struct ufs_hba 
*hba)
 }
 
 /**
+ * ufshcd_get_dme_attr_val - Get the value of attribute returned by UIC command
+ * @hba: Pointer to adapter instance
+ *
+ * This function gets UIC command argument3
+ * Returns 0 on success, non zero value on error
+ */
+static inline u32 ufshcd_get_dme_attr_val(struct ufs_hba *hba)
+{
+   return ufshcd_readl(hba, REG_UIC_COMMAND_ARG_3);
+}
+
+/**
  * ufshcd_get_req_rsp - returns the TR response transaction type
  * @ucd_rsp_ptr: pointer to response UPIU
  */
@@ -1440,6 +1452,80 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba)
 }
 
 /**
+ * ufshcd_dme_set_attr - UIC command for DME_SET, DME_PEER_SET
+ * @hba: per adapter instance
+ * @attr_sel: uic command argument1
+ * @attr_set: attribute set type as uic command argument2
+ * @mib_val: setting value as uic command argument3
+ * @peer: indicate whether peer or local
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+int ufshcd_dme_set_attr(struct ufs_hba *hba, u32 attr_sel,
+   u8 attr_set, u32 mib_val, u8 peer)
+{
+   struct uic_command uic_cmd = {0};
+   static const char *const action[] = {
+   "dme-set",
+   "dme-peer-set"
+   };
+   const char *set = action[!!peer];
+   int ret;
+
+   uic_cmd.command = peer ?
+   UIC_CMD_DME_PEER_SET : UIC_CMD_DME_SET;
+   uic_cmd.argument1 = attr_sel;
+   uic_cmd.argument2 = UIC_ARG_ATTR_TYPE(attr_set);
+   uic_cmd.argument3 = mib_val;
+
+   ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
+   if (ret)
+   dev_err(hba->dev, "%s: attr-id 0x%x val 0x%x error code %d\n",
+   set, UIC_GET_ATTR_ID(attr_sel), mib_val, ret);
+
+   return ret;
+}
+EXPORT_SYMBOL_GPL(ufshcd_dme_set_attr);
+
+/**
+ * ufshcd_dme_get_attr - UIC command for DME_GET, DME_PEER_GET
+ * @hba: per adapter instance
+ * @attr_sel: uic command argument1
+ * @mib_val: the value of the attribute as returned by the UIC command
+ * @peer: indicate whether peer or local
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel,
+   u32 *mib_val, u8 peer)
+{
+   struct uic_command uic_cmd = {0};
+   static const char *const action[] = {
+   "dme-get",
+   "dme-peer-get"
+   };
+   const char *get = action[!!peer];
+   int ret;
+
+   uic_cmd.command = peer ?
+   UIC_CMD_DME_PEER_GET : UIC_CMD_DME_GET;
+   uic_cmd.argument1 = attr_sel;
+
+   ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
+   if (ret) {
+   dev_err(hba->dev, "%s: attr-id 0x%x error code %d\n",
+   get, UIC_GET_ATTR_ID(attr_sel), ret);
+   goto out;
+   }
+
+   if (mib_val)
+   *mib_val = uic_cmd.argument3;
+out:
+   return ret;
+}
+EXPORT_SYMBOL_GPL(ufshcd_dme_get_attr);
+
+/**
  * ufshcd_complete_dev_init() - checks device readiness
  * hba: per-adapter instance
  *
@@ -1912,6 +1998,8 @@ static void ufshcd_uic_cmd_compl(struct ufs_hba *hba)
if (hba->active_uic_cmd) {
hba->active_uic_cmd->argument2 |=
ufshcd_get_uic_cmd_result(hba);
+   hba->active_uic_cmd->argument3 =
+   ufshcd_get_dme_attr_val(hba);
complete(&hba->active_uic_cmd->done);
}
 }
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 8f5624e..ab1518d 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -275,4 +275,55 @@ static inline void check_upiu_size(void)
 extern int ufshcd_runtime_suspend(struct ufs_hba *hba);
 extern int ufshcd_runtime_resume(struct ufs_hba *hba);
 extern int ufshcd_runtime_idle(struct ufs_hba *hba);
+extern int ufshcd_dme_set_attr(struct ufs_hba *hba, u32 attr_sel,
+  u8 attr_set, u32 mib_val, u8 peer);
+extern int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel,
+  u32 *mib_val, u8 peer);
+
+/* UIC command interfaces for DME primitives */
+#define DME_LOCAL  0
+#define DME_PEER   1
+#define AT

[PATCH v3 1/6] scsi: ufs: find out sense data over scsi status values

2013-08-26 Thread Seungwon Jeon
Unlike 'GOOD' and 'CHECK CONDITION', other status values in
Response UPIU may or may not contain sense data. That is returning
sense data isn't obvious. So, in this case the Data Segment Length
field should be checked. If a non-zero value, it means that UPIU
has Sense Data in the Data Segment area.

Signed-off-by: Seungwon Jeon 
Reviewed-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufs.h|1 +
 drivers/scsi/ufs/ufshcd.c |   37 ++---
 2 files changed, 23 insertions(+), 15 deletions(-)

diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index bce09a6..7210500 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -177,6 +177,7 @@ enum {
MASK_TASK_RESPONSE  = 0xFF00,
MASK_RSP_UPIU_RESULT= 0x,
MASK_QUERY_DATA_SEG_LEN = 0x,
+   MASK_RSP_UPIU_DATA_SEG_LEN  = 0x,
MASK_RSP_EXCEPTION_EVENT= 0x1,
 };
 
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 1b99c0a..6ff16c9 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -310,6 +310,20 @@ ufshcd_get_rsp_upiu_result(struct utp_upiu_rsp 
*ucd_rsp_ptr)
return be32_to_cpu(ucd_rsp_ptr->header.dword_1) & MASK_RSP_UPIU_RESULT;
 }
 
+/*
+ * ufshcd_get_rsp_upiu_data_seg_len - Get the data segment length
+ * from response UPIU
+ * @ucd_rsp_ptr: pointer to response UPIU
+ *
+ * Return the data segment length.
+ */
+static inline unsigned int
+ufshcd_get_rsp_upiu_data_seg_len(struct utp_upiu_rsp *ucd_rsp_ptr)
+{
+   return be32_to_cpu(ucd_rsp_ptr->header.dword_2) &
+   MASK_RSP_UPIU_DATA_SEG_LEN;
+}
+
 /**
  * ufshcd_is_exception_event - Check if the device raised an exception event
  * @ucd_rsp_ptr: pointer to response UPIU
@@ -405,7 +419,8 @@ void ufshcd_send_command(struct ufs_hba *hba, unsigned int 
task_tag)
 static inline void ufshcd_copy_sense_data(struct ufshcd_lrb *lrbp)
 {
int len;
-   if (lrbp->sense_buffer) {
+   if (lrbp->sense_buffer &&
+   ufshcd_get_rsp_upiu_data_seg_len(lrbp->ucd_rsp_ptr)) {
len = be16_to_cpu(lrbp->ucd_rsp_ptr->sr.sense_data_len);
memcpy(lrbp->sense_buffer,
lrbp->ucd_rsp_ptr->sr.sense_data,
@@ -1789,32 +1804,24 @@ ufshcd_scsi_cmd_status(struct ufshcd_lrb *lrbp, int 
scsi_status)
int result = 0;
 
switch (scsi_status) {
-   case SAM_STAT_GOOD:
-   result |= DID_OK << 16 |
- COMMAND_COMPLETE << 8 |
- SAM_STAT_GOOD;
-   break;
case SAM_STAT_CHECK_CONDITION:
+   ufshcd_copy_sense_data(lrbp);
+   case SAM_STAT_GOOD:
result |= DID_OK << 16 |
  COMMAND_COMPLETE << 8 |
- SAM_STAT_CHECK_CONDITION;
-   ufshcd_copy_sense_data(lrbp);
-   break;
-   case SAM_STAT_BUSY:
-   result |= SAM_STAT_BUSY;
+ scsi_status;
break;
case SAM_STAT_TASK_SET_FULL:
-
/*
 * If a LUN reports SAM_STAT_TASK_SET_FULL, then the LUN queue
 * depth needs to be adjusted to the exact number of
 * outstanding commands the LUN can handle at any given time.
 */
ufshcd_adjust_lun_qdepth(lrbp->cmd);
-   result |= SAM_STAT_TASK_SET_FULL;
-   break;
+   case SAM_STAT_BUSY:
case SAM_STAT_TASK_ABORTED:
-   result |= SAM_STAT_TASK_ABORTED;
+   ufshcd_copy_sense_data(lrbp);
+   result |= scsi_status;
break;
default:
result |= DID_ERROR << 16;
-- 
1.7.0.4


--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v3 5/6] scsi: ufs: add operation for the uic power mode change

2013-08-26 Thread Seungwon Jeon
Setting PA_PWRMode using DME_SET triggers the power mode
change. And then the result will be given by the HCS.UPMCRS.
This operation should be done atomically.

Signed-off-by: Seungwon Jeon 
---
 drivers/scsi/ufs/ufshcd.c |   84 ++--
 drivers/scsi/ufs/ufshcd.h |3 ++
 drivers/scsi/ufs/ufshci.h |   12 ++
 3 files changed, 95 insertions(+), 4 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 00bfc1a..c67118d 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -36,9 +36,11 @@
 #include 
 
 #include "ufshcd.h"
+#include "unipro.h"
 
 #define UFSHCD_ENABLE_INTRS(UTP_TRANSFER_REQ_COMPL |\
 UTP_TASK_REQ_COMPL |\
+UIC_POWER_MODE |\
 UFSHCD_ERROR_MASK)
 /* UIC command timeout, unit: ms */
 #define UIC_CMD_TIMEOUT500
@@ -520,6 +522,18 @@ static inline bool ufshcd_ready_for_uic_cmd(struct ufs_hba 
*hba)
 }
 
 /**
+ * ufshcd_get_upmcrs - Get the power mode change request status
+ * @hba: Pointer to adapter instance
+ *
+ * This function gets the UPMCRS field of HCS register
+ * Returns value of UPMCRS field
+ */
+static inline u8 ufshcd_get_upmcrs(struct ufs_hba *hba)
+{
+   return (ufshcd_readl(hba, REG_CONTROLLER_STATUS) >> 8) & 0x7;
+}
+
+/**
  * ufshcd_dispatch_uic_cmd - Dispatch UIC commands to unipro layers
  * @hba: per adapter instance
  * @uic_cmd: UIC command
@@ -1526,6 +1540,64 @@ out:
 EXPORT_SYMBOL_GPL(ufshcd_dme_get_attr);
 
 /**
+ * ufshcd_uic_change_pwr_mode - Perform the UIC power mode chage
+ * using DME_SET primitives.
+ * @hba: per adapter instance
+ * @mode: powr mode value
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+int ufshcd_uic_change_pwr_mode(struct ufs_hba *hba, u8 mode)
+{
+   struct uic_command uic_cmd = {0};
+   struct completion pwr_done;
+   unsigned long flags;
+   u8 status;
+   int ret;
+
+   uic_cmd.command = UIC_CMD_DME_SET;
+   uic_cmd.argument1 = UIC_ARG_MIB(PA_PWRMODE);
+   uic_cmd.argument3 = mode;
+   init_completion(&pwr_done);
+
+   mutex_lock(&hba->uic_cmd_mutex);
+
+   spin_lock_irqsave(hba->host->host_lock, flags);
+   hba->pwr_done = &pwr_done;
+   spin_unlock_irqrestore(hba->host->host_lock, flags);
+   ret = __ufshcd_send_uic_cmd(hba, &uic_cmd);
+   if (ret) {
+   dev_err(hba->dev,
+   "pwr mode change with mode 0x%x uic error %d\n",
+   mode, ret);
+   goto out;
+   }
+
+   if (!wait_for_completion_timeout(hba->pwr_done,
+msecs_to_jiffies(UIC_CMD_TIMEOUT))) {
+   dev_err(hba->dev,
+   "pwr mode change with mode 0x%x completion timeout\n",
+   mode);
+   ret = -ETIMEDOUT;
+   goto out;
+   }
+
+   status = ufshcd_get_upmcrs(hba);
+   if (status != PWR_LOCAL) {
+   dev_err(hba->dev,
+   "pwr mode change failed, host umpcrs:0x%x\n",
+   status);
+   ret = (status != PWR_OK) ? status : -1;
+   }
+out:
+   spin_lock_irqsave(hba->host->host_lock, flags);
+   hba->pwr_done = NULL;
+   spin_unlock_irqrestore(hba->host->host_lock, flags);
+   mutex_unlock(&hba->uic_cmd_mutex);
+   return ret;
+}
+
+/**
  * ufshcd_complete_dev_init() - checks device readiness
  * hba: per-adapter instance
  *
@@ -1992,16 +2064,20 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct 
ufshcd_lrb *lrbp)
 /**
  * ufshcd_uic_cmd_compl - handle completion of uic command
  * @hba: per adapter instance
+ * @intr_status: interrupt status generated by the controller
  */
-static void ufshcd_uic_cmd_compl(struct ufs_hba *hba)
+static void ufshcd_uic_cmd_compl(struct ufs_hba *hba, u32 intr_status)
 {
-   if (hba->active_uic_cmd) {
+   if ((intr_status & UIC_COMMAND_COMPL) && hba->active_uic_cmd) {
hba->active_uic_cmd->argument2 |=
ufshcd_get_uic_cmd_result(hba);
hba->active_uic_cmd->argument3 =
ufshcd_get_dme_attr_val(hba);
complete(&hba->active_uic_cmd->done);
}
+
+   if ((intr_status & UIC_POWER_MODE) && hba->pwr_done)
+   complete(hba->pwr_done);
 }
 
 /**
@@ -2451,8 +2527,8 @@ static void ufshcd_sl_intr(struct ufs_hba *hba, u32 
intr_status)
if (hba->errors)
ufshcd_check_errors(hba);
 
-   if (intr_status & UIC_COMMAND_COMPL)
-   ufshcd_uic_cmd_compl(hba);
+   if (intr_status & UFSHCD_UIC_MASK)
+   ufshcd_uic_cmd_compl(

RE: [PATCH v3 5/6] scsi: ufs: add operation for the uic power mode change

2013-08-27 Thread Seungwon Jeon
On Tue, August 27, 2013, Subhash Jadavani wrote:
> On 8/26/2013 8:10 PM, Seungwon Jeon wrote:
> > Setting PA_PWRMode using DME_SET triggers the power mode
> > change. And then the result will be given by the HCS.UPMCRS.
> > This operation should be done atomically.
> >
> > Signed-off-by: Seungwon Jeon 
> > ---
> >   drivers/scsi/ufs/ufshcd.c |   84 
> > ++--
> >   drivers/scsi/ufs/ufshcd.h |3 ++
> >   drivers/scsi/ufs/ufshci.h |   12 ++
> >   3 files changed, 95 insertions(+), 4 deletions(-)
> >
> > diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> > index 00bfc1a..c67118d 100644
> > --- a/drivers/scsi/ufs/ufshcd.c
> > +++ b/drivers/scsi/ufs/ufshcd.c
> > @@ -36,9 +36,11 @@
> >   #include 
> >
> >   #include "ufshcd.h"
> > +#include "unipro.h"
> >
> >   #define UFSHCD_ENABLE_INTRS   (UTP_TRANSFER_REQ_COMPL |\
> >  UTP_TASK_REQ_COMPL |\
> > +UIC_POWER_MODE |\
> >  UFSHCD_ERROR_MASK)
> >   /* UIC command timeout, unit: ms */
> >   #define UIC_CMD_TIMEOUT   500
> > @@ -520,6 +522,18 @@ static inline bool ufshcd_ready_for_uic_cmd(struct 
> > ufs_hba *hba)
> >   }
> >
> >   /**
> > + * ufshcd_get_upmcrs - Get the power mode change request status
> > + * @hba: Pointer to adapter instance
> > + *
> > + * This function gets the UPMCRS field of HCS register
> > + * Returns value of UPMCRS field
> > + */
> > +static inline u8 ufshcd_get_upmcrs(struct ufs_hba *hba)
> > +{
> > +   return (ufshcd_readl(hba, REG_CONTROLLER_STATUS) >> 8) & 0x7;
> > +}
> > +
> > +/**
> >* ufshcd_dispatch_uic_cmd - Dispatch UIC commands to unipro layers
> >* @hba: per adapter instance
> >* @uic_cmd: UIC command
> > @@ -1526,6 +1540,64 @@ out:
> >   EXPORT_SYMBOL_GPL(ufshcd_dme_get_attr);
> >
> >   /**
> > + * ufshcd_uic_change_pwr_mode - Perform the UIC power mode chage
> > + * using DME_SET primitives.
> > + * @hba: per adapter instance
> > + * @mode: powr mode value
> > + *
> > + * Returns 0 on success, non-zero value on failure
> > + */
> > +int ufshcd_uic_change_pwr_mode(struct ufs_hba *hba, u8 mode)
> > +{
> > +   struct uic_command uic_cmd = {0};
> > +   struct completion pwr_done;
> > +   unsigned long flags;
> > +   u8 status;
> > +   int ret;
> > +
> > +   uic_cmd.command = UIC_CMD_DME_SET;
> > +   uic_cmd.argument1 = UIC_ARG_MIB(PA_PWRMODE);
> > +   uic_cmd.argument3 = mode;
> > +   init_completion(&pwr_done);
> > +
> > +   mutex_lock(&hba->uic_cmd_mutex);
> > +
> > +   spin_lock_irqsave(hba->host->host_lock, flags);
> > +   hba->pwr_done = &pwr_done;
> > +   spin_unlock_irqrestore(hba->host->host_lock, flags);
> > +   ret = __ufshcd_send_uic_cmd(hba, &uic_cmd);
> > +   if (ret) {
> > +   dev_err(hba->dev,
> > +   "pwr mode change with mode 0x%x uic error %d\n",
> > +   mode, ret);
> > +   goto out;
> > +   }
> > +
> > +   if (!wait_for_completion_timeout(hba->pwr_done,
> > +msecs_to_jiffies(UIC_CMD_TIMEOUT))) {
> > +   dev_err(hba->dev,
> > +   "pwr mode change with mode 0x%x completion timeout\n",
> > +   mode);
> > +   ret = -ETIMEDOUT;
> > +   goto out;
> > +   }
> > +
> > +   status = ufshcd_get_upmcrs(hba);
> 
> I have a doubt on the relation between UIC Power Mode Status (UPMS) bit
> & UIC Power Mode Change Request Status (UPMCRS) field.
> 
> Once we send the DME_SET(PA_PWRMODE) command, we will get the UIC
> command completion interrupt (with IS.UCCS bit set) which just indicate
> that the attribute is written but power mode change procedure will
> complete only after some delay which is indicated via IS.UPMS status bit
> and then we would read the HCS.UPMCRS field to know the status of power
> mode change.
> 
> This is my exact doubt: Currently UFSHCD driver first clears the IS.UPMS
> bit (ufshcd_intr() first clears the current interrupts in
> REG_INTERRUPT_STATUS and then calls the ufshcd_sl_intr() handler, and in
> your current patch we are anyway not reading the UPMCRS field from
> interrupt contex ) and then read the HCS.UPMCRS field. Will HCS.UPMCRS
> field retain its status value 

RE: [PATCH v3 5/6] scsi: ufs: add operation for the uic power mode change

2013-08-27 Thread Seungwon Jeon
On Tue, August 27, 2013, Subhash Jadavani wrote:
> On 8/27/2013 4:58 PM, Seungwon Jeon wrote:
> > On Tue, August 27, 2013, Subhash Jadavani wrote:
> >> On 8/26/2013 8:10 PM, Seungwon Jeon wrote:
> >>> Setting PA_PWRMode using DME_SET triggers the power mode
> >>> change. And then the result will be given by the HCS.UPMCRS.
> >>> This operation should be done atomically.
> >>>
> >>> Signed-off-by: Seungwon Jeon 
> >>> ---
> >>>drivers/scsi/ufs/ufshcd.c |   84 
> >>> ++--
> >>>drivers/scsi/ufs/ufshcd.h |3 ++
> >>>drivers/scsi/ufs/ufshci.h |   12 ++
> >>>3 files changed, 95 insertions(+), 4 deletions(-)
> >>>
> >>> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> >>> index 00bfc1a..c67118d 100644
> >>> --- a/drivers/scsi/ufs/ufshcd.c
> >>> +++ b/drivers/scsi/ufs/ufshcd.c
> >>> @@ -36,9 +36,11 @@
> >>>#include 
> >>>
> >>>#include "ufshcd.h"
> >>> +#include "unipro.h"
> >>>
> >>>#define UFSHCD_ENABLE_INTRS(UTP_TRANSFER_REQ_COMPL |\
> >>>UTP_TASK_REQ_COMPL |\
> >>> +  UIC_POWER_MODE |\
> >>>UFSHCD_ERROR_MASK)
> >>>/* UIC command timeout, unit: ms */
> >>>#define UIC_CMD_TIMEOUT500
> >>> @@ -520,6 +522,18 @@ static inline bool ufshcd_ready_for_uic_cmd(struct 
> >>> ufs_hba *hba)
> >>>}
> >>>
> >>>/**
> >>> + * ufshcd_get_upmcrs - Get the power mode change request status
> >>> + * @hba: Pointer to adapter instance
> >>> + *
> >>> + * This function gets the UPMCRS field of HCS register
> >>> + * Returns value of UPMCRS field
> >>> + */
> >>> +static inline u8 ufshcd_get_upmcrs(struct ufs_hba *hba)
> >>> +{
> >>> + return (ufshcd_readl(hba, REG_CONTROLLER_STATUS) >> 8) & 0x7;
> >>> +}
> >>> +
> >>> +/**
> >>> * ufshcd_dispatch_uic_cmd - Dispatch UIC commands to unipro layers
> >>> * @hba: per adapter instance
> >>> * @uic_cmd: UIC command
> >>> @@ -1526,6 +1540,64 @@ out:
> >>>EXPORT_SYMBOL_GPL(ufshcd_dme_get_attr);
> >>>
> >>>/**
> >>> + * ufshcd_uic_change_pwr_mode - Perform the UIC power mode chage
> >>> + *   using DME_SET primitives.
> >>> + * @hba: per adapter instance
> >>> + * @mode: powr mode value
> >>> + *
> >>> + * Returns 0 on success, non-zero value on failure
> >>> + */
> >>> +int ufshcd_uic_change_pwr_mode(struct ufs_hba *hba, u8 mode)
> >>> +{
> >>> + struct uic_command uic_cmd = {0};
> >>> + struct completion pwr_done;
> >>> + unsigned long flags;
> >>> + u8 status;
> >>> + int ret;
> >>> +
> >>> + uic_cmd.command = UIC_CMD_DME_SET;
> >>> + uic_cmd.argument1 = UIC_ARG_MIB(PA_PWRMODE);
> >>> + uic_cmd.argument3 = mode;
> >>> + init_completion(&pwr_done);
> >>> +
> >>> + mutex_lock(&hba->uic_cmd_mutex);
> >>> +
> >>> + spin_lock_irqsave(hba->host->host_lock, flags);
> >>> + hba->pwr_done = &pwr_done;
> >>> + spin_unlock_irqrestore(hba->host->host_lock, flags);
> >>> + ret = __ufshcd_send_uic_cmd(hba, &uic_cmd);
> >>> + if (ret) {
> >>> + dev_err(hba->dev,
> >>> + "pwr mode change with mode 0x%x uic error %d\n",
> >>> + mode, ret);
> >>> + goto out;
> >>> + }
> >>> +
> >>> + if (!wait_for_completion_timeout(hba->pwr_done,
> >>> +  msecs_to_jiffies(UIC_CMD_TIMEOUT))) {
> >>> + dev_err(hba->dev,
> >>> + "pwr mode change with mode 0x%x completion timeout\n",
> >>> + mode);
> >>> + ret = -ETIMEDOUT;
> >>> + goto out;
> >>> + }
> >>> +
> >>> + status = ufshcd_get_upmcrs(hba);
> >> I have a doubt on the relation between UIC Power Mode Status (UPMS) bit
> >> &am

[PATCH] scsi: ufs: replace the deprecated flush_work_sync

2013-09-03 Thread Seungwon Jeon
flush_work_sync is replaced by flush_work with commit
4382973(workqueue: deprecate flush[_delayed]_work_sync()).

Signed-off-by: Seungwon Jeon 
---
 drivers/scsi/ufs/ufshcd.c |2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index a0f5ac2..1b99c0a 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -2737,7 +2737,7 @@ static int ufshcd_eh_host_reset_handler(struct scsi_cmnd 
*cmd)
break;
spin_unlock_irqrestore(hba->host->host_lock, flags);
dev_dbg(hba->dev, "%s: reset in progress\n", __func__);
-   flush_work_sync(&hba->eh_work);
+   flush_work(&hba->eh_work);
} while (1);
 
hba->ufshcd_state = UFSHCD_STATE_RESET;
-- 
1.7.0.4


--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: [PATCH V2 1/3] scsi: ufs: Allow vendor specific initialization

2013-09-09 Thread Seungwon Jeon
d before and after Link startup is carried out
> + *   to allow variant specific Uni-Pro initialization.
> + */
> +struct ufs_hba_variant_ops {
> + const char *name;
> + int (*init)(struct ufs_hba *);
> + void(*exit)(struct ufs_hba *);
> + int (*setup_clocks)(struct ufs_hba *, bool);
> + int (*setup_regulators)(struct ufs_hba *, bool);
> + int (*hce_enable_notify)(struct ufs_hba *, bool);
I agree on specific link_startup as HCI specification mentions.
Actually we also have implemented similar thing in our host driver.
But I'm not sure of a necessity of hce_enable_notify. Could you explain for 
that?

> + int (*link_startup_notify)(struct ufs_hba *, bool);
If a host specific implementation doesn't have two fully,
one of them will be called with flag unnecessarily.
How about separating into two functions[pre_, post_] for link_startup?

> +};
> +
>  /**
>   * struct ufs_hba - per adapter private structure
>   * @mmio_base: UFSHCI base register address
> @@ -171,6 +197,8 @@ struct ufs_dev_cmd {
>   * @nutrs: Transfer Request Queue depth supported by controller
>   * @nutmrs: Task Management Queue depth supported by controller
>   * @ufs_version: UFS Version to which controller complies
> + * @vops: pointer to variant specific operations
> + * @priv: pointer to variant specific private data
>   * @irq: Irq number of the controller
>   * @active_uic_cmd: handle of active UIC command
>   * @uic_cmd_mutex: mutex for uic command
> @@ -217,6 +245,8 @@ struct ufs_hba {
>   int nutrs;
>   int nutmrs;
>   u32 ufs_version;
> + struct ufs_hba_variant_ops *vops;
'const' declaration is expected.

Thanks,
Seungwon Jeon

> + void *priv;
>   unsigned int irq;
> 
>   struct uic_command *active_uic_cmd;
> @@ -253,8 +283,8 @@ struct ufs_hba {
>  #define ufshcd_readl(hba, reg)   \
>   readl((hba)->mmio_base + (reg))
> 
> -int ufshcd_init(struct device *, struct ufs_hba ** , void __iomem * ,
> - unsigned int);
> +int ufshcd_alloc_host(struct device *, struct ufs_hba **);
> +int ufshcd_init(struct ufs_hba * , void __iomem * , unsigned int);
>  void ufshcd_remove(struct ufs_hba *);
> 
>  /**
> --
> QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
> of Code Aurora Forum, hosted by The Linux Foundation.
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majord...@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH] scsi: ufs: export the helper functions for vender probe/remove

2013-09-09 Thread Seungwon Jeon
This change provides the common routines for driver's probe/remove.
Especially host driver including specific operations can invoke the
initial routine at the own probing phase and pass its operations to
ufshcd's common part.

Signed-off-by: Seungwon Jeon 
---
 drivers/scsi/ufs/ufshcd-pltfrm.c |   49 +++--
 drivers/scsi/ufs/ufshcd-pltfrm.h |   19 ++
 2 files changed, 55 insertions(+), 13 deletions(-)
 create mode 100644 drivers/scsi/ufs/ufshcd-pltfrm.h

diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index 9c94052..4900597 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -38,6 +38,7 @@
 #include 
 
 #include "ufshcd.h"
+#include "ufshcd-pltfrm.h"
 
 static const struct of_device_id ufs_of_match[];
 static struct ufs_hba_variant_ops *get_variant_ops(struct device *dev)
@@ -137,12 +138,13 @@ static int ufshcd_pltfrm_runtime_idle(struct device *dev)
 #endif /* CONFIG_PM_RUNTIME */
 
 /**
- * ufshcd_pltfrm_probe - probe routine of the driver
+ * ufshcd_pltfrm_init - common routine for the driver's initialization
  * @pdev: pointer to Platform device handle
  *
  * Returns 0 on success, non-zero value on failure
  */
-static int ufshcd_pltfrm_probe(struct platform_device *pdev)
+int ufshcd_pltfrm_init(struct platform_device *pdev,
+  const struct ufs_hba_variant_ops *vops)
 {
struct ufs_hba *hba;
void __iomem *mmio_base;
@@ -166,14 +168,13 @@ static int ufshcd_pltfrm_probe(struct platform_device 
*pdev)
 
err = ufshcd_alloc_host(dev, &hba);
if (err) {
-   dev_err(&pdev->dev, "Allocation failed\n");
+   dev_err(dev, "Allocation failed\n");
goto out;
}
 
-   hba->vops = get_variant_ops(&pdev->dev);
-
-   pm_runtime_set_active(&pdev->dev);
-   pm_runtime_enable(&pdev->dev);
+   hba->vops = vops;
+   pm_runtime_set_active(dev);
+   pm_runtime_enable(dev);
 
err = ufshcd_init(hba, mmio_base, irq);
if (err) {
@@ -186,24 +187,46 @@ static int ufshcd_pltfrm_probe(struct platform_device 
*pdev)
return 0;
 
 out_disable_rpm:
-   pm_runtime_disable(&pdev->dev);
-   pm_runtime_set_suspended(&pdev->dev);
+   pm_runtime_disable(dev);
+   pm_runtime_set_suspended(dev);
 out:
return err;
 }
+EXPORT_SYMBOL_GPL(ufshcd_pltfrm_init);
 
 /**
- * ufshcd_pltfrm_remove - remove platform driver routine
+ * ufshcd_pltfrm_exit - common routine for the driver's exit
  * @pdev: pointer to platform device handle
- *
- * Returns 0 on success, non-zero value on failure
  */
-static int ufshcd_pltfrm_remove(struct platform_device *pdev)
+void ufshcd_pltfrm_exit(struct platform_device *pdev)
 {
struct ufs_hba *hba =  platform_get_drvdata(pdev);
 
pm_runtime_get_sync(&(pdev)->dev);
ufshcd_remove(hba);
+}
+EXPORT_SYMBOL_GPL(ufshcd_pltfrm_exit);
+
+/**
+ * ufshcd_pltfrm_probe - probe the platform driver
+ * @pdev: pointer to Platform device handle
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+static int ufshcd_pltfrm_probe(struct platform_device *pdev)
+{
+   return ufshcd_pltfrm_init(pdev, get_variant_ops(&pdev->dev));
+}
+
+/**
+ * ufshcd_pltfrm_remove - remove the platform driver
+ * @pdev: pointer to platform device handle
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+static int ufshcd_pltfrm_remove(struct platform_device *pdev)
+{
+   ufshcd_pltfrm_exit(pdev);
return 0;
 }
 
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.h b/drivers/scsi/ufs/ufshcd-pltfrm.h
new file mode 100644
index 000..6adab05
--- /dev/null
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.h
@@ -0,0 +1,19 @@
+/*
+ * Universal Flash Storage Host controller Platform bus based glue driver
+ *
+ * Copyright (C) 2013, Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * at your option) any later version.
+ */
+
+#ifndef _UFSHCD_PLTFRM_H_
+#define _UFSHCD_PLTFRM_H_
+
+extern int ufshcd_pltfrm_init(struct platform_device *pdev,
+ const struct ufs_hba_variant_ops *vops);
+extern void ufshcd_pltfrm_exit(struct platform_device *pdev);
+
+#endif /* _UFSHCD_PLTFRM_H_ */
-- 
1.7.0.4


--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 1/5] scsi: ufs: move the ufshcd_hba_stop to ufshcd.c

2013-04-24 Thread Seungwon Jeon
Move the ufshcd_hba_stop from header file.

Signed-off-by: Seungwon Jeon 
---
 drivers/scsi/ufs/ufshcd.c |9 +
 drivers/scsi/ufs/ufshcd.h |9 -
 2 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 60fd40c..41b9639 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -285,6 +285,15 @@ static inline void ufshcd_hba_start(struct ufs_hba *hba)
 }
 
 /**
+ * ufshcd_hba_stop - Send controller to reset state
+ * @hba: per adapter instance
+ */
+static inline void ufshcd_hba_stop(struct ufs_hba *hba)
+{
+   writel(CONTROLLER_DISABLE, (hba->mmio_base + REG_CONTROLLER_ENABLE));
+}
+
+/**
  * ufshcd_is_hba_active - Get controller state
  * @hba: per adapter instance
  *
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 6b99a42..1680394 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -190,13 +190,4 @@ int ufshcd_init(struct device *, struct ufs_hba ** , void 
__iomem * ,
unsigned int);
 void ufshcd_remove(struct ufs_hba *);
 
-/**
- * ufshcd_hba_stop - Send controller to reset state
- * @hba: per adapter instance
- */
-static inline void ufshcd_hba_stop(struct ufs_hba *hba)
-{
-   writel(CONTROLLER_DISABLE, (hba->mmio_base + REG_CONTROLLER_ENABLE));
-}
-
 #endif /* End of Header */
-- 
1.7.0.4


--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 3/5] scsi: ufs: amend interrupt configuration

2013-04-24 Thread Seungwon Jeon
It makes interrupt setting more flexible especially
for disabling. And wrong bit mask is fixed for ver 1.0.
[17:16] is added for mask.

Signed-off-by: Seungwon Jeon 
---
 drivers/scsi/ufs/ufshcd.c |   86 -
 drivers/scsi/ufs/ufshcd.h |4 +-
 drivers/scsi/ufs/ufshci.h |5 ++-
 3 files changed, 66 insertions(+), 29 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index b6c19b0..efe2256 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -35,6 +35,10 @@
 
 #include "ufshcd.h"
 
+#define UFSHCD_ENABLE_INTRS(UTP_TRANSFER_REQ_COMPL |\
+UTP_TASK_REQ_COMPL |\
+UFSHCD_ERROR_MASK)
+
 enum {
UFSHCD_MAX_CHANNEL  = 0,
UFSHCD_MAX_ID   = 1,
@@ -64,6 +68,20 @@ enum {
 };
 
 /**
+ * ufshcd_get_intr_mask - Get the interrupt bit mask
+ * @hba - Pointer to adapter instance
+ *
+ * Returns interrupt bit mask per version
+ */
+static inline u32 ufshcd_get_intr_mask(struct ufs_hba *hba)
+{
+   if (hba->ufs_version == UFSHCI_VERSION_10)
+   return INTERRUPT_MASK_ALL_VER_10;
+   else
+   return INTERRUPT_MASK_ALL_VER_11;
+}
+
+/**
  * ufshcd_get_ufs_version - Get the UFS version supported by the HBA
  * @hba - Pointer to adapter instance
  *
@@ -397,25 +415,45 @@ static int ufshcd_map_sg(struct ufshcd_lrb *lrbp)
 }
 
 /**
- * ufshcd_int_config - enable/disable interrupts
+ * ufshcd_enable_intr - enable interrupts
  * @hba: per adapter instance
- * @option: interrupt option
+ * @intrs: interrupt bits
  */
-static void ufshcd_int_config(struct ufs_hba *hba, u32 option)
+static void ufshcd_enable_intr(struct ufs_hba *hba, u32 intrs)
 {
-   switch (option) {
-   case UFSHCD_INT_ENABLE:
-   ufshcd_writel(hba, REG_INTERRUPT_ENABLE, hba->int_enable_mask);
-   break;
-   case UFSHCD_INT_DISABLE:
-   if (hba->ufs_version == UFSHCI_VERSION_10)
-   ufshcd_writel(hba, REG_INTERRUPT_ENABLE,
- INTERRUPT_DISABLE_MASK_10);
-   else
-   ufshcd_writel(hba, REG_INTERRUPT_ENABLE,
- INTERRUPT_DISABLE_MASK_11);
-   break;
+   u32 set = ufshcd_readl(hba, REG_INTERRUPT_ENABLE);
+
+   if (hba->ufs_version == UFSHCI_VERSION_10) {
+   u32 rw;
+   rw = set & INTERRUPT_MASK_RW_VER_10;
+   set = rw | ((set ^ intrs) & intrs);
+   } else {
+   set |= intrs;
+   }
+
+   ufshcd_writel(hba, REG_INTERRUPT_ENABLE, set);
+}
+
+/**
+ * ufshcd_disable_intr - disable interrupts
+ * @hba: per adapter instance
+ * @intrs: interrupt bits
+ */
+static void ufshcd_disable_intr(struct ufs_hba *hba, u32 intrs)
+{
+   u32 set = ufshcd_readl(hba, REG_INTERRUPT_ENABLE);
+
+   if (hba->ufs_version == UFSHCI_VERSION_10) {
+   u32 rw;
+   rw = (set & INTERRUPT_MASK_RW_VER_10) &
+   ~(intrs & INTERRUPT_MASK_RW_VER_10);
+   set = rw | ((set & intrs) & ~INTERRUPT_MASK_RW_VER_10);
+
+   } else {
+   set &= ~intrs;
}
+
+   ufshcd_writel(hba, REG_INTERRUPT_ENABLE, set);
 }
 
 /**
@@ -717,8 +755,7 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba)
uic_cmd->argument3 = 0;
 
/* enable UIC related interrupts */
-   hba->int_enable_mask |= UIC_COMMAND_COMPL;
-   ufshcd_int_config(hba, UFSHCD_INT_ENABLE);
+   ufshcd_enable_intr(hba, UIC_COMMAND_COMPL);
 
/* sending UIC commands to controller */
ufshcd_send_uic_command(hba, uic_cmd);
@@ -765,13 +802,9 @@ static int ufshcd_make_hba_operational(struct ufs_hba *hba)
}
 
/* Enable required interrupts */
-   hba->int_enable_mask |= (UTP_TRANSFER_REQ_COMPL |
-UIC_ERROR |
-UTP_TASK_REQ_COMPL |
-DEVICE_FATAL_ERROR |
-CONTROLLER_FATAL_ERROR |
-SYSTEM_BUS_FATAL_ERROR);
-   ufshcd_int_config(hba, UFSHCD_INT_ENABLE);
+   ufshcd_enable_intr(hba, UTP_TRANSFER_REQ_COMPL | UIC_ERROR |
+  UTP_TASK_REQ_COMPL | DEVICE_FATAL_ERROR |
+  CONTROLLER_FATAL_ERROR | SYSTEM_BUS_FATAL_ERROR);
 
/* Configure interrupt aggregation */
ufshcd_config_int_aggr(hba, INT_AGGR_CONFIG);
@@ -1578,7 +1611,7 @@ static void ufshcd_hba_free(struct ufs_hba *hba)
 void ufshcd_remove(struct ufs_hba *hba)
 {
/* disable interrupts */
-   ufshcd_int_config(hba, UFSHCD_INT_DISABLE);
+   ufshcd_disable_intr(hba, hba->intr_mask);
 
ufshcd_hba_stop(hba);
ufshcd_hba_free(hba);
@@ -1636,6 +1669,9 @@ int ufshcd_init(struct device *dev, 

[PATCH 2/5] scsi: ufs: wrap the i/o access operations

2013-04-24 Thread Seungwon Jeon
Simplify operations with hiding mmio_base.

Signed-off-by: Seungwon Jeon 
---
 drivers/scsi/ufs/ufshcd.c |  106 +++--
 drivers/scsi/ufs/ufshcd.h |5 ++
 2 files changed, 49 insertions(+), 62 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 41b9639..b6c19b0 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -71,7 +71,7 @@ enum {
  */
 static inline u32 ufshcd_get_ufs_version(struct ufs_hba *hba)
 {
-   return readl(hba->mmio_base + REG_UFS_VERSION);
+   return ufshcd_readl(hba, REG_UFS_VERSION);
 }
 
 /**
@@ -130,8 +130,7 @@ static inline int ufshcd_get_tm_free_slot(struct ufs_hba 
*hba)
  */
 static inline void ufshcd_utrl_clear(struct ufs_hba *hba, u32 pos)
 {
-   writel(~(1 << pos),
-   (hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_CLEAR));
+   ufshcd_writel(hba, REG_UTP_TRANSFER_REQ_LIST_CLEAR, ~(1 << pos));
 }
 
 /**
@@ -165,7 +164,7 @@ static inline int ufshcd_get_lists_status(u32 reg)
  */
 static inline int ufshcd_get_uic_cmd_result(struct ufs_hba *hba)
 {
-   return readl(hba->mmio_base + REG_UIC_COMMAND_ARG_2) &
+   return ufshcd_readl(hba, REG_UIC_COMMAND_ARG_2) &
   MASK_UIC_COMMAND_RESULT;
 }
 
@@ -243,18 +242,14 @@ ufshcd_config_int_aggr(struct ufs_hba *hba, int option)
 {
switch (option) {
case INT_AGGR_RESET:
-   writel((INT_AGGR_ENABLE |
-   INT_AGGR_COUNTER_AND_TIMER_RESET),
-   (hba->mmio_base +
-REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL));
+   ufshcd_writel(hba, REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL,
+ INT_AGGR_ENABLE | 
INT_AGGR_COUNTER_AND_TIMER_RESET);
break;
case INT_AGGR_CONFIG:
-   writel((INT_AGGR_ENABLE |
-   INT_AGGR_PARAM_WRITE |
-   INT_AGGR_COUNTER_THRESHOLD_VALUE |
-   INT_AGGR_TIMEOUT_VALUE),
-   (hba->mmio_base +
-REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL));
+   ufshcd_writel(hba, REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL,
+ INT_AGGR_ENABLE | INT_AGGR_PARAM_WRITE |
+ INT_AGGR_COUNTER_THRESHOLD_VALUE |
+ INT_AGGR_TIMEOUT_VALUE);
break;
}
 }
@@ -267,12 +262,10 @@ ufshcd_config_int_aggr(struct ufs_hba *hba, int option)
  */
 static void ufshcd_enable_run_stop_reg(struct ufs_hba *hba)
 {
-   writel(UTP_TASK_REQ_LIST_RUN_STOP_BIT,
-  (hba->mmio_base +
-   REG_UTP_TASK_REQ_LIST_RUN_STOP));
-   writel(UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT,
-  (hba->mmio_base +
-   REG_UTP_TRANSFER_REQ_LIST_RUN_STOP));
+   ufshcd_writel(hba, REG_UTP_TASK_REQ_LIST_RUN_STOP,
+ UTP_TASK_REQ_LIST_RUN_STOP_BIT);
+   ufshcd_writel(hba, REG_UTP_TRANSFER_REQ_LIST_RUN_STOP,
+ UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT);
 }
 
 /**
@@ -281,7 +274,7 @@ static void ufshcd_enable_run_stop_reg(struct ufs_hba *hba)
  */
 static inline void ufshcd_hba_start(struct ufs_hba *hba)
 {
-   writel(CONTROLLER_ENABLE , (hba->mmio_base + REG_CONTROLLER_ENABLE));
+   ufshcd_writel(hba, REG_CONTROLLER_ENABLE, CONTROLLER_ENABLE);
 }
 
 /**
@@ -290,7 +283,7 @@ static inline void ufshcd_hba_start(struct ufs_hba *hba)
  */
 static inline void ufshcd_hba_stop(struct ufs_hba *hba)
 {
-   writel(CONTROLLER_DISABLE, (hba->mmio_base + REG_CONTROLLER_ENABLE));
+   ufshcd_writel(hba, REG_CONTROLLER_ENABLE, CONTROLLER_DISABLE);
 }
 
 /**
@@ -301,7 +294,7 @@ static inline void ufshcd_hba_stop(struct ufs_hba *hba)
  */
 static inline int ufshcd_is_hba_active(struct ufs_hba *hba)
 {
-   return (readl(hba->mmio_base + REG_CONTROLLER_ENABLE) & 0x1) ? 0 : 1;
+   return (ufshcd_readl(hba, REG_CONTROLLER_ENABLE) & 0x1) ? 0 : 1;
 }
 
 /**
@@ -313,8 +306,7 @@ static inline
 void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag)
 {
__set_bit(task_tag, &hba->outstanding_reqs);
-   writel((1 << task_tag),
-  (hba->mmio_base + REG_UTP_TRANSFER_REQ_DOOR_BELL));
+   ufshcd_writel(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL, 1 << task_tag);
 }
 
 /**
@@ -338,8 +330,7 @@ static inline void ufshcd_copy_sense_data(struct ufshcd_lrb 
*lrbp)
  */
 static inline void ufshcd_hba_capabilities(struct ufs_hba *hba)
 {
-   hba->capabilities =
-   readl(hba->mmio_base + REG_CONTROLLER_CAPABILITIES);
+   hba->capabilities = ufshcd_readl(hba, REG_CONTROLLER_CAPABILITIES);
 
/* nutrs and nutmrs are 0 based values */
hba->nutrs = (hba->capabilities & MASK_TRANSFER_REQUESTS_SLOTS) + 1;
@@ -356,16 +347,13 @@ static inline void
 ufshcd_send_uic_command(struct ufs_hba

[PATCH 4/5] scsi: ufs: rework link start-up process

2013-04-24 Thread Seungwon Jeon
Link start-up requires long time with multiphase handshakes
between UFS host and device. This affects driver's probe time.
This patch let link start-up run asynchronously.
And completion time of uic command is defined to avoid a
permanent wait.

Signed-off-by: Seungwon Jeon 
---
 drivers/scsi/ufs/ufshcd.c |  114 +---
 drivers/scsi/ufs/ufshcd.h |6 ++-
 2 files changed, 89 insertions(+), 31 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index efe2256..76ff332 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -38,6 +38,7 @@
 #define UFSHCD_ENABLE_INTRS(UTP_TRANSFER_REQ_COMPL |\
 UTP_TASK_REQ_COMPL |\
 UFSHCD_ERROR_MASK)
+#define UIC_CMD_TIMEOUT100
 
 enum {
UFSHCD_MAX_CHANNEL  = 0,
@@ -357,13 +358,15 @@ static inline void ufshcd_hba_capabilities(struct ufs_hba 
*hba)
 }
 
 /**
- * ufshcd_send_uic_command - Send UIC commands to unipro layers
+ * ufshcd_dispatch_uic_cmd - Dispatch UIC commands to unipro layers
  * @hba: per adapter instance
  * @uic_command: UIC command
  */
 static inline void
-ufshcd_send_uic_command(struct ufs_hba *hba, struct uic_command *uic_cmnd)
+ufshcd_dispatch_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmnd)
 {
+   init_completion(&uic_cmnd->done);
+
/* Write Args */
ufshcd_writel(hba, REG_UIC_COMMAND_ARG_1, uic_cmnd->argument1);
ufshcd_writel(hba, REG_UIC_COMMAND_ARG_2, uic_cmnd->argument2);
@@ -375,6 +378,45 @@ ufshcd_send_uic_command(struct ufs_hba *hba, struct 
uic_command *uic_cmnd)
 }
 
 /**
+ * ufshcd_wait_for_uic_cmd - Wait complectioin of UIC command
+ * @hba: per adapter instance
+ * @uic_command: UIC command
+ *
+ * Returns 0 only if success.
+ */
+static int ufshcd_wait_for_uic_cmd(struct ufs_hba *hba)
+{
+   struct uic_command *uic_cmd = &hba->active_uic_cmd;
+   int ret;
+
+   if (wait_for_completion_timeout(&uic_cmd->done,
+   msecs_to_jiffies(UIC_CMD_TIMEOUT)))
+   ret = ufshcd_get_uic_cmd_result(hba);
+   else
+   ret = -ETIMEDOUT;
+
+   return ret;
+}
+
+/**
+ * ufshcd_ready_uic_cmd - Check if controller is ready
+ *to accept UIC commands
+ * @hba: per adapter instance
+ * Return true on success, else false
+ */
+static inline bool ufshcd_ready_uic_cmd(struct ufs_hba *hba)
+{
+   if (ufshcd_readl(hba, REG_CONTROLLER_STATUS) & UIC_COMMAND_READY) {
+   return true;
+   } else {
+   dev_err(hba->dev,
+   "Controller not ready"
+   " to accept UIC commands\n");
+   return false;
+   }
+}
+
+/**
  * ufshcd_map_sg - Map scatter-gather list to prdt
  * @lrbp - pointer to local reference block
  *
@@ -735,15 +777,10 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba)
 {
struct uic_command *uic_cmd;
unsigned long flags;
+   int ret;
 
-   /* check if controller is ready to accept UIC commands */
-   if (((ufshcd_readl(hba, REG_CONTROLLER_STATUS)) &
-   UIC_COMMAND_READY) == 0x0) {
-   dev_err(hba->dev,
-   "Controller not ready"
-   " to accept UIC commands\n");
+   if (!ufshcd_ready_uic_cmd(hba))
return -EIO;
-   }
 
spin_lock_irqsave(hba->host->host_lock, flags);
 
@@ -754,13 +791,16 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba)
uic_cmd->argument2 = 0;
uic_cmd->argument3 = 0;
 
-   /* enable UIC related interrupts */
-   ufshcd_enable_intr(hba, UIC_COMMAND_COMPL);
+   /* Dispatching UIC commands to controller */
+   ufshcd_dispatch_uic_cmd(hba, uic_cmd);
 
-   /* sending UIC commands to controller */
-   ufshcd_send_uic_command(hba, uic_cmd);
spin_unlock_irqrestore(hba->host->host_lock, flags);
-   return 0;
+
+   ret = ufshcd_wait_for_uic_cmd(hba);
+   if (ret)
+   dev_err(hba->dev, "link startup: error code %d returned\n", 
ret);
+
+   return ret;
 }
 
 /**
@@ -898,6 +938,9 @@ static int ufshcd_initialize_hba(struct ufs_hba *hba)
if (ufshcd_hba_enable(hba))
return -EIO;
 
+   /* enable UIC related interrupts */
+   ufshcd_enable_intr(hba, UIC_COMMAND_COMPL | UIC_ERROR);
+
/* Configure UTRL and UTMRL base address registers */
ufshcd_writel(hba, REG_UTP_TRANSFER_REQ_LIST_BASE_L,
  lower_32_bits(hba->utrdl_dma_addr));
@@ -909,7 +952,9 @@ static int ufshcd_initialize_hba(struct ufs_hba *hba)
  upper_32_bits(hba->utmrdl_dma_addr));
 
/* Initialize unipro link startup procedure */
-   return uf

[PATCH 5/5] scsi: ufs: add dme operations

2013-04-24 Thread Seungwon Jeon
Add uic command operations including DME_XXX series.

Signed-off-by: Seungwon Jeon 
---
 drivers/scsi/ufs/ufs-attrs.h |  129 
 drivers/scsi/ufs/ufshcd.c|  220 +-
 drivers/scsi/ufs/ufshcd.h|   55 +++
 drivers/scsi/ufs/ufshci.h|   19 
 4 files changed, 422 insertions(+), 1 deletions(-)
 create mode 100644 drivers/scsi/ufs/ufs-attrs.h

diff --git a/drivers/scsi/ufs/ufs-attrs.h b/drivers/scsi/ufs/ufs-attrs.h
new file mode 100644
index 000..562bb49
--- /dev/null
+++ b/drivers/scsi/ufs/ufs-attrs.h
@@ -0,0 +1,129 @@
+/*
+ * drivers/scsi/ufs/ufs-attrs.h
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef _UFS_ATTRS_H_
+#define _UFS_ATTRS_H_
+
+/*
+ * PHY Adpater attributes
+ */
+#define PA_ACTIVETXDATALANES   0x1560
+#define PA_ACTIVERXDATALANES   0x1580
+#define PA_TXTRAILINGCLOCKS0x1564
+#define PA_PHY_TYPE0x1500
+#define PA_AVAILTXDATALANES0x1520
+#define PA_AVAILRXDATALANES0x1540
+#define PA_MINRXTRAILINGCLOCKS 0x1543
+#define PA_TXPWRSTATUS 0x1567
+#define PA_RXPWRSTATUS 0x1582
+#define PA_TXFORCECLOCK0x1562
+#define PA_TXPWRMODE   0x1563
+#define PA_LEGACYDPHYESCDL 0x1570
+#define PA_MAXTXSPEEDFAST  0x1521
+#define PA_MAXTXSPEEDSLOW  0x1522
+#define PA_MAXRXSPEEDFAST  0x1541
+#define PA_MAXRXSPEEDSLOW  0x1542
+#define PA_TXLINKSTARTUPHS 0x1544
+#define PA_TXSPEEDFAST 0x1565
+#define PA_TXSPEEDSLOW 0x1566
+#define PA_REMOTEVERINFO   0x15A0
+#define PA_TXGEAR  0x1568
+#define PA_TXTERMINATION   0x1569
+#define PA_HSSERIES0x156A
+#define PA_PWRMODE 0x1571
+#define PA_RXGEAR  0x1583
+#define PA_RXTERMINATION   0x1584
+#define PA_MAXRXPWMGEAR0x1586
+#define PA_MAXRXHSGEAR 0x1587
+#define PA_RXHSUNTERMCAP   0x15A5
+#define PA_RXLSTERMCAP 0x15A6
+#define PA_PACPREQTIMEOUT  0x1590
+#define PA_PACPREQEOBTIMEOUT   0x1591
+#define PA_LOCALVERINFO0x15A9
+#define PA_TACTIVATE   0x15A8
+#define PA_PACPFRAMECOUNT  0x15C0
+#define PA_PACPERRORCOUNT  0x15C1
+#define PA_PHYTESTCONTROL  0x15C2
+#define PA_PWRMODEUSERDATA00x15B0
+#define PA_PWRMODEUSERDATA10x15B1
+#define PA_PWRMODEUSERDATA20x15B2
+#define PA_PWRMODEUSERDATA30x15B3
+#define PA_PWRMODEUSERDATA40x15B4
+#define PA_PWRMODEUSERDATA50x15B5
+#define PA_PWRMODEUSERDATA60x15B6
+#define PA_PWRMODEUSERDATA70x15B7
+#define PA_PWRMODEUSERDATA80x15B8
+#define PA_PWRMODEUSERDATA90x15B9
+#define PA_PWRMODEUSERDATA10   0x15BA
+#define PA_PWRMODEUSERDATA11   0x15BB
+#define PA_CONNECTEDTXDATALANE 0x1561
+#define PA_CONNECTEDRXDATALANE 0x1581
+#define PA_LOGICALLANEMAP  0x15A1
+#define PA_SLEEPNOCONFIGTIME   0x15A2
+#define PA_STALLNOCONFIGTIME   0x15A3
+#define PA_SAVECONFIGTIME  0x15A4
+
+/*
+ * Data Link Layer Attributes
+ */
+#define DL_TC0TXFCTHRESHOLD0x2040
+#define DL_FC0PROTTIMEOUTVAL   0x2041
+#define DL_TC0REPLAYTIMEOUTVAL 0x2042
+#define DL_AFC0REQTIMEOUTVAL   0x2043
+#define DL_AFC0CREDITTHRESHOLD 0x2044
+#define DL_TC0OUTACKTHRESHOLD  0x2045
+#define DL_TC1TXFCTHRESHOLD0x2060
+#define DL_FC1PROTTIMEOUTVAL   0x2061
+#define DL_TC1REPLAYTIMEOUTVAL 0x2062
+#define DL_AFC1REQTIMEOUTVAL   0x2063
+#define DL_AFC1CREDITTHRESHOLD 0x2064
+#define DL_TC1OUTACKTHRESHOLD  0x2065
+#define DL_TXPREEMPTIONCAP 0x2000
+#define DL_TC0TXMAXSDUSIZE 0x2001
+#define DL_TC0RXINITCREDITVAL  0x2002
+#define DL_TC0TXBUFFERSIZE 0x2005
+#define DL_PEERTC0PRESENT  0x2046
+#define DL_PEERTC0RXINITCREVAL 0x2047
+#define DL_TC1TXMAXSDUSIZE 0x2003
+#define DL_TC1RXINITCREDITVAL  0x2004
+#define DL_TC1TXBUFFERSIZE 0x2006
+#define DL_PEERTC1PRESENT  0x2066
+#define DL_PEERTC1RXINITCREVAL 0x2067
+
+/*
+ * Network Layer Attributes
+ */
+#define N_DEVICEID 0x3000
+#define N_DEVICEID_VALID   0x3001
+#define N_TC0TXMAXSDUSIZE  0x3020
+#define N_TC1TXMAXSDUSIZE  0x3021
+
+/*
+ * Transport Layer Attributes
+ */
+#define T_NUMCPORTS0x4000
+#define T_NUMTESTFEATURES  0x4001
+#define T_CONNECTIONSTATE  0x4020
+#define T_PEERDEVICEID 0x4021
+#define T_PEERCPORTID  0x4022
+#define T_TRAFFICCLASS 0x4023
+#define T_PROTOCOLID   0x4024
+#define T_CPORTFLAGS   0x4025
+#define T_TXTOKENVALUE 0x4026
+#define T_RXTOKENVALUE 0x4027
+#define T_LOCALBUFFERSPACE 0x4028
+#define T_PEERBUFFERSPACE  0x4029
+#define T_CREDITSTOSEND0x402A
+#define T_CPORTMODE0x402B
+#define T_TC0TXMAXSDUSIZE  0x4060

RE: [PATCH 2/5] scsi: ufs: wrap the i/o access operations

2013-04-25 Thread Seungwon Jeon
Hi,

On Thursday, April 25, 2013, Sujit Reddy Thumma wrote:
> On 4/24/2013 9:36 PM, Seungwon Jeon wrote:
> > Simplify operations with hiding mmio_base.
> >
> > Signed-off-by: Seungwon Jeon 
> > ---
> >   drivers/scsi/ufs/ufshcd.c |  106 
> > +++--
> >   drivers/scsi/ufs/ufshcd.h |5 ++
> >   2 files changed, 49 insertions(+), 62 deletions(-)
> >
> > diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
> > index 1680394..6728450 100644
> > --- a/drivers/scsi/ufs/ufshcd.h
> > +++ b/drivers/scsi/ufs/ufshcd.h
> > @@ -190,4 +190,9 @@ int ufshcd_init(struct device *, struct ufs_hba ** , 
> > void __iomem * ,
> > unsigned int);
> >   void ufshcd_remove(struct ufs_hba *);
> >
> > +#define ufshcd_writel(hba, reg, val)   \
> 
> Let this be consistent with writel() arguments - "val" as second arg and
> "reg" as third?
You got a point there.
When considering an array of arguments in two functions and value part can be 
some long expression,
I think it seems more coherent.
ufshcd_readl(hba, reg);
ufshcd_writel(hba, reg, val);
How about keeping these?

Thanks,
Seungwon Jeon

> 
> > +   writel((val), (hba)->mmio_base + (reg))
> > +#define ufshcd_readl(hba, reg) \
> > +   readl((hba)->mmio_base + (reg))
> > +
> >   #endif /* End of Header */
> >
> 
> --
> Regards,
> Sujit
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majord...@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: [PATCH 4/5] scsi: ufs: rework link start-up process

2013-04-25 Thread Seungwon Jeon
On Thursday, April 25, 2013 , Sujit Reddy Thumma wrote:
> On 4/24/2013 9:36 PM, Seungwon Jeon wrote:
> > Link start-up requires long time with multiphase handshakes
> > between UFS host and device. This affects driver's probe time.
> > This patch let link start-up run asynchronously.
> > And completion time of uic command is defined to avoid a
> > permanent wait.
> 
> I have similar patch posted few days back "scsi: ufs: Generalize UFS
> Interconnect Layer (UIC) command support" which does a bit more (mutex,
> error handling) than what is done here. Can that be used/improved?
I completed to check your patch to compare it now.
Though it's just my thought, the patch I sent is more intuitive on the whole.
Considering other dme operations which I have introduced, it looks like matched.
Of course, you may disagree.
But I think the part of mutex is needed. It's a good point.
In case of error handling, I didn't catch nothing special.
Rather, handling link lost case is not proper.
When ufs host meets link lost status, it should start with dme_reset not 
retried dme_linkstartup.
And it would be good if link start-up procedure is done in separate process, 
not in driver probe.
If it's all right with you, I'd like to update lock mechanism for uic command.
I can add your signed-off. Please let me know your opinion.

Thanks,
Seungwon Jeon
> 
> >
> > Signed-off-by: Seungwon Jeon 
> > ---
> >   drivers/scsi/ufs/ufshcd.c |  114 
> > +---
> >   drivers/scsi/ufs/ufshcd.h |6 ++-
> >   2 files changed, 89 insertions(+), 31 deletions(-)
> >
> > diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> > index efe2256..76ff332 100644
> > --- a/drivers/scsi/ufs/ufshcd.c
> > +++ b/drivers/scsi/ufs/ufshcd.c
> > @@ -38,6 +38,7 @@
> >   #define UFSHCD_ENABLE_INTRS   (UTP_TRANSFER_REQ_COMPL |\
> >  UTP_TASK_REQ_COMPL |\
> >  UFSHCD_ERROR_MASK)
> > +#define UIC_CMD_TIMEOUT100
> >
> >   enum {
> > UFSHCD_MAX_CHANNEL  = 0,
> > @@ -357,13 +358,15 @@ static inline void ufshcd_hba_capabilities(struct 
> > ufs_hba *hba)
> >   }
> >
> >   /**
> > - * ufshcd_send_uic_command - Send UIC commands to unipro layers
> > + * ufshcd_dispatch_uic_cmd - Dispatch UIC commands to unipro layers
> >* @hba: per adapter instance
> >* @uic_command: UIC command
> >*/
> >   static inline void
> > -ufshcd_send_uic_command(struct ufs_hba *hba, struct uic_command *uic_cmnd)
> > +ufshcd_dispatch_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmnd)
> >   {
> > +   init_completion(&uic_cmnd->done);
> > +
> > /* Write Args */
> > ufshcd_writel(hba, REG_UIC_COMMAND_ARG_1, uic_cmnd->argument1);
> > ufshcd_writel(hba, REG_UIC_COMMAND_ARG_2, uic_cmnd->argument2);
> > @@ -375,6 +378,45 @@ ufshcd_send_uic_command(struct ufs_hba *hba, struct 
> > uic_command *uic_cmnd)
> >   }
> >
> >   /**
> > + * ufshcd_wait_for_uic_cmd - Wait complectioin of UIC command
> > + * @hba: per adapter instance
> > + * @uic_command: UIC command
> > + *
> > + * Returns 0 only if success.
> > + */
> > +static int ufshcd_wait_for_uic_cmd(struct ufs_hba *hba)
> > +{
> > +   struct uic_command *uic_cmd = &hba->active_uic_cmd;
> > +   int ret;
> > +
> > +   if (wait_for_completion_timeout(&uic_cmd->done,
> > +   msecs_to_jiffies(UIC_CMD_TIMEOUT)))
> > +   ret = ufshcd_get_uic_cmd_result(hba);
> > +   else
> > +   ret = -ETIMEDOUT;
> > +
> > +   return ret;
> > +}
> > +
> > +/**
> > + * ufshcd_ready_uic_cmd - Check if controller is ready
> > + *to accept UIC commands
> > + * @hba: per adapter instance
> > + * Return true on success, else false
> > + */
> > +static inline bool ufshcd_ready_uic_cmd(struct ufs_hba *hba)
> > +{
> > +   if (ufshcd_readl(hba, REG_CONTROLLER_STATUS) & UIC_COMMAND_READY) {
> > +   return true;
> > +   } else {
> > +   dev_err(hba->dev,
> > +   "Controller not ready"
> > +   " to accept UIC commands\n");
> > +   return false;
> > +   }
> > +}
> > +
> > +/**
> >* ufshcd_map_sg - Map scatter-gather list to prdt
> >* @lrbp - pointer to local reference block
> >*
> > @@ -735,15 +777,10 @@ static int ufshcd_dm

RE: [PATCH 4/5] scsi: ufs: rework link start-up process

2013-04-29 Thread Seungwon Jeon
On Monday, April 29, 2013, Sujit Reddy Thumma wrote:
> On 4/26/2013 10:44 AM, Seungwon Jeon wrote:
> > On Thursday, April 25, 2013 , Sujit Reddy Thumma wrote:
> >> On 4/24/2013 9:36 PM, Seungwon Jeon wrote:
> >>> Link start-up requires long time with multiphase handshakes
> >>> between UFS host and device. This affects driver's probe time.
> >>> This patch let link start-up run asynchronously.
> >>> And completion time of uic command is defined to avoid a
> >>> permanent wait.
> >>
> >> I have similar patch posted few days back "scsi: ufs: Generalize UFS
> >> Interconnect Layer (UIC) command support" which does a bit more (mutex,
> >> error handling) than what is done here. Can that be used/improved?
> > I completed to check your patch to compare it now.
> > Though it's just my thought, the patch I sent is more intuitive on the 
> > whole.
> > Considering other dme operations which I have introduced, it looks like 
> > matched.
> 
> There are lot of code duplications you might want to minimize building a
> DME command.
> 
> > Of course, you may disagree.
> > But I think the part of mutex is needed. It's a good point.
> > In case of error handling, I didn't catch nothing special.
> > Rather, handling link lost case is not proper.
> > When ufs host meets link lost status, it should start with dme_reset not 
> > retried dme_linkstartup.
> 
> In section 7.2.1 (Host Controller Initialization) of JESD223A UFS HCI
> v1.1  specification I find this -
> 
> 6. Sent DME_LINKSTARTUP command to start the link startup procedure
> 9. Check value of HCS.DP and make sure that there is a device attached
> to the Link. If presence of a device is detected, go to step 10;
> otherwise, resend the DME_LINKSTARTUP command after IS.ULLS has been set
> to 1 (Go to step 6). IS.ULLS equal 1 indicates that the UFS Device is
> ready for a link startup.
> 
> Going by the spec. just retrying with DME_LINKSTARTUP is correct.
Yes, as you quoted above, HCI standard mentions that.
Also, the following is mentioned.
UIC Link Lost Status (ULLS) corresponds to the UniPro DME_LINKLOST.ind
I just referred unipro specification.
When DME_LINKLOST.ind is generated, this affects the Link is put in the 
LinkLost state.
Unipro spec says that DME User must apply a DME_RESET to redo the boot sequence.
If there is misunderstood meaning and I have something to miss, we can discuss 
more.
Please let me know.

> 
> In addition, it doesn't say what happens if IS.ULLS never sets to 1.
> Probably, the case which never happens.
> 
> > And it would be good if link start-up procedure is done in separate 
> > process, not in driver probe.
> True.
> 
> > If it's all right with you, I'd like to update lock mechanism for uic 
> > command.
> > I can add your signed-off. Please let me know your opinion.
> I would like to get a third opinion as both the patches needs modifications.
> 
> Some comments below:
> 
> >>
> >>>
> >>> Signed-off-by: Seungwon Jeon 
> >>> ---
> >>>drivers/scsi/ufs/ufshcd.c |  114 
> >>> +---
> >>>drivers/scsi/ufs/ufshcd.h |6 ++-
> >>>2 files changed, 89 insertions(+), 31 deletions(-)
> >>>
> >>> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> >>> index efe2256..76ff332 100644
> >>> --- a/drivers/scsi/ufs/ufshcd.c
> >>> +++ b/drivers/scsi/ufs/ufshcd.c
> >>> @@ -38,6 +38,7 @@
> >>>#define UFSHCD_ENABLE_INTRS(UTP_TRANSFER_REQ_COMPL |\
> >>>UTP_TASK_REQ_COMPL |\
> >>>UFSHCD_ERROR_MASK)
> >>> +#define UIC_CMD_TIMEOUT  100
> >>>
> >>>enum {
> >>>   UFSHCD_MAX_CHANNEL  = 0,
> >>> @@ -357,13 +358,15 @@ static inline void ufshcd_hba_capabilities(struct 
> >>> ufs_hba *hba)
> >>>}
> >>>
> >>>/**
> >>> - * ufshcd_send_uic_command - Send UIC commands to unipro layers
> >>> + * ufshcd_dispatch_uic_cmd - Dispatch UIC commands to unipro layers
> >>> * @hba: per adapter instance
> >>> * @uic_command: UIC command
> >>> */
> >>>static inline void
> >>> -ufshcd_send_uic_command(struct ufs_hba *hba, struct uic_command 
> >>> *uic_cmnd)
> >>> +ufshcd_dispatch_uic_cmd(struct ufs_hba *hba, struct uic_command 
> >>> *uic_cmnd

RE: [PATCH 4/5] scsi: ufs: rework link start-up process

2013-04-29 Thread Seungwon Jeon
On Monday, April 29, 2013, Sujit Reddy Thumma wrote:
> On 4/29/2013 3:54 PM, Seungwon Jeon wrote:
> > On Monday, April 29, 2013, Sujit Reddy Thumma wrote:
> >> On 4/26/2013 10:44 AM, Seungwon Jeon wrote:
> >>> On Thursday, April 25, 2013 , Sujit Reddy Thumma wrote:
> >>>> On 4/24/2013 9:36 PM, Seungwon Jeon wrote:
> >>>>> Link start-up requires long time with multiphase handshakes
> >>>>> between UFS host and device. This affects driver's probe time.
> >>>>> This patch let link start-up run asynchronously.
> >>>>> And completion time of uic command is defined to avoid a
> >>>>> permanent wait.
> >>>>
> >>>> I have similar patch posted few days back "scsi: ufs: Generalize UFS
> >>>> Interconnect Layer (UIC) command support" which does a bit more (mutex,
> >>>> error handling) than what is done here. Can that be used/improved?
> >>> I completed to check your patch to compare it now.
> >>> Though it's just my thought, the patch I sent is more intuitive on the 
> >>> whole.
> >>> Considering other dme operations which I have introduced, it looks like 
> >>> matched.
> >>
> >> There are lot of code duplications you might want to minimize building a
> >> DME command.
> >>
> >>> Of course, you may disagree.
> >>> But I think the part of mutex is needed. It's a good point.
> >>> In case of error handling, I didn't catch nothing special.
> >>> Rather, handling link lost case is not proper.
> >>> When ufs host meets link lost status, it should start with dme_reset not 
> >>> retried dme_linkstartup.
> >>
> >> In section 7.2.1 (Host Controller Initialization) of JESD223A UFS HCI
> >> v1.1  specification I find this -
> >>
> >> 6. Sent DME_LINKSTARTUP command to start the link startup procedure
> >> 9. Check value of HCS.DP and make sure that there is a device attached
> >> to the Link. If presence of a device is detected, go to step 10;
> >> otherwise, resend the DME_LINKSTARTUP command after IS.ULLS has been set
> >> to 1 (Go to step 6). IS.ULLS equal 1 indicates that the UFS Device is
> >> ready for a link startup.
> >>
> >> Going by the spec. just retrying with DME_LINKSTARTUP is correct.
> > Yes, as you quoted above, HCI standard mentions that.
> > Also, the following is mentioned.
> > UIC Link Lost Status (ULLS) corresponds to the UniPro DME_LINKLOST.ind
> > I just referred unipro specification.
> > When DME_LINKLOST.ind is generated, this affects the Link is put in the 
> > LinkLost state.
> > Unipro spec says that DME User must apply a DME_RESET to redo the boot 
> > sequence.
> > If there is misunderstood meaning and I have something to miss, we can 
> > discuss more.
> > Please let me know.
> 
> Yes, it looks like the two specs. are conflicting each other. I guess we
> need to take this to Jedec for clarification. Meanwhile, to be on safe
> side can we add a retry mechanism that does ufshcd_hba_enable() before
> sending DME_LINKSTARTUP again? This way we can be sure that the
> DME_RESET and DME_ENABLE is taken care by the host reset itself.
Yes, If the latter case is applied, 'ufshcd_hba_enable' will be start entry for 
retry.
Further, IS.ULLS could be handled through the interrupt instead of polling for 
retry mechanism?

> 
> >
> >>
> >> In addition, it doesn't say what happens if IS.ULLS never sets to 1.
> >> Probably, the case which never happens.
> >>
> >>> And it would be good if link start-up procedure is done in separate 
> >>> process, not in driver probe.
> >> True.
> >>
> >>> If it's all right with you, I'd like to update lock mechanism for uic 
> >>> command.
> >>> I can add your signed-off. Please let me know your opinion.
> >> I would like to get a third opinion as both the patches needs 
> >> modifications.
> >>
> >> Some comments below:
> >>
> >>>>
> >>>>>
> >>>>> Signed-off-by: Seungwon Jeon 
> >>>>> ---
> >>>>> drivers/scsi/ufs/ufshcd.c |  114 
> >>>>> +---
> >>>>> drivers/scsi/ufs/ufshcd.h |6 ++-
> >>>>> 2 files changed, 89 insertions(+), 31 deletions(-)
> >>>>>
> >>>>> diff --git a/drivers/s

RE: [PATCH 4/5] scsi: ufs: rework link start-up process

2013-05-01 Thread Seungwon Jeon
On Tuesday, April 30, 2013, Sujit Reddy Thumma wrote:
> On 4/30/2013 12:03 PM, Seungwon Jeon wrote:
> > On Monday, April 29, 2013, Sujit Reddy Thumma wrote:
> >> On 4/29/2013 3:54 PM, Seungwon Jeon wrote:
> >>> On Monday, April 29, 2013, Sujit Reddy Thumma wrote:
> >>>> On 4/26/2013 10:44 AM, Seungwon Jeon wrote:
> >>>>> On Thursday, April 25, 2013 , Sujit Reddy Thumma wrote:
> >>>>>> On 4/24/2013 9:36 PM, Seungwon Jeon wrote:
> >>>>>>> Link start-up requires long time with multiphase handshakes
> >>>>>>> between UFS host and device. This affects driver's probe time.
> >>>>>>> This patch let link start-up run asynchronously.
> >>>>>>> And completion time of uic command is defined to avoid a
> >>>>>>> permanent wait.
> >>>>>>
> >>>>>> I have similar patch posted few days back "scsi: ufs: Generalize UFS
> >>>>>> Interconnect Layer (UIC) command support" which does a bit more (mutex,
> >>>>>> error handling) than what is done here. Can that be used/improved?
> >>>>> I completed to check your patch to compare it now.
> >>>>> Though it's just my thought, the patch I sent is more intuitive on the 
> >>>>> whole.
> >>>>> Considering other dme operations which I have introduced, it looks like 
> >>>>> matched.
> >>>>
> >>>> There are lot of code duplications you might want to minimize building a
> >>>> DME command.
> >>>>
> >>>>> Of course, you may disagree.
> >>>>> But I think the part of mutex is needed. It's a good point.
> >>>>> In case of error handling, I didn't catch nothing special.
> >>>>> Rather, handling link lost case is not proper.
> >>>>> When ufs host meets link lost status, it should start with dme_reset 
> >>>>> not retried dme_linkstartup.
> >>>>
> >>>> In section 7.2.1 (Host Controller Initialization) of JESD223A UFS HCI
> >>>> v1.1  specification I find this -
> >>>>
> >>>> 6. Sent DME_LINKSTARTUP command to start the link startup procedure
> >>>> 9. Check value of HCS.DP and make sure that there is a device attached
> >>>> to the Link. If presence of a device is detected, go to step 10;
> >>>> otherwise, resend the DME_LINKSTARTUP command after IS.ULLS has been set
> >>>> to 1 (Go to step 6). IS.ULLS equal 1 indicates that the UFS Device is
> >>>> ready for a link startup.
> >>>>
> >>>> Going by the spec. just retrying with DME_LINKSTARTUP is correct.
> >>> Yes, as you quoted above, HCI standard mentions that.
> >>> Also, the following is mentioned.
> >>> UIC Link Lost Status (ULLS) corresponds to the UniPro DME_LINKLOST.ind
> >>> I just referred unipro specification.
> >>> When DME_LINKLOST.ind is generated, this affects the Link is put in the 
> >>> LinkLost state.
> >>> Unipro spec says that DME User must apply a DME_RESET to redo the boot 
> >>> sequence.
> >>> If there is misunderstood meaning and I have something to miss, we can 
> >>> discuss more.
> >>> Please let me know.
> >>
> >> Yes, it looks like the two specs. are conflicting each other. I guess we
> >> need to take this to Jedec for clarification. Meanwhile, to be on safe
> >> side can we add a retry mechanism that does ufshcd_hba_enable() before
> >> sending DME_LINKSTARTUP again? This way we can be sure that the
> >> DME_RESET and DME_ENABLE is taken care by the host reset itself.
> > Yes, If the latter case is applied, 'ufshcd_hba_enable' will be start entry 
> > for retry.
> > Further, IS.ULLS could be handled through the interrupt instead of polling 
> > for retry mechanism?
> 
> Agree, but the interrupt handling will be tailored for two things - 1)
> bootup case where scsi_scan_host is not yet called. 2) the case where
> link lost occurred after a long time after bootup where there is no need
> to do scsi_scan_host again.
Yes, it could be another patch.

> 
> >
> >>
> >>>
> >>>>
> >>>> In addition, it doesn't say what happens if IS.ULLS never sets to 1.
> >>>> Probably, the case which never happens.
> >>>>
> >>&g

RE: [PATCH 3/5] scsi: ufs: amend interrupt configuration

2013-05-02 Thread Seungwon Jeon
On Tuesday, April 30, 2013, Subhash Jadavani wrote:
> Patch looks good but one minor comment below.
> 
> On 4/24/2013 9:36 PM, Seungwon Jeon wrote:
> > It makes interrupt setting more flexible especially
> > for disabling. And wrong bit mask is fixed for ver 1.0.
> > [17:16] is added for mask.
> >
> > Signed-off-by: Seungwon Jeon 
> > ---
> >   drivers/scsi/ufs/ufshcd.c |   86 
> > -
> >   drivers/scsi/ufs/ufshcd.h |4 +-
> >   drivers/scsi/ufs/ufshci.h |5 ++-
> >   3 files changed, 66 insertions(+), 29 deletions(-)
> >
> > diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> > index b6c19b0..efe2256 100644
> > --- a/drivers/scsi/ufs/ufshcd.c
> > +++ b/drivers/scsi/ufs/ufshcd.c
> > @@ -35,6 +35,10 @@
> >
> >   #include "ufshcd.h"
> >
> > +#define UFSHCD_ENABLE_INTRS(UTP_TRANSFER_REQ_COMPL |\
> > +UTP_TASK_REQ_COMPL |\
> > +UFSHCD_ERROR_MASK)
> > +
> 
> I don't see any use of this macro in this patch. could you please remove
> it or move it to the patch-set where its really being used.
Good point. I'll apply it.

Thanks,
Seungwon Jeon
> 
> >   enum {
> > UFSHCD_MAX_CHANNEL  = 0,
> > UFSHCD_MAX_ID   = 1,
> > @@ -64,6 +68,20 @@ enum {
> >   };
> >
> >   /**
> > + * ufshcd_get_intr_mask - Get the interrupt bit mask
> > + * @hba - Pointer to adapter instance
> > + *
> > + * Returns interrupt bit mask per version
> > + */
> > +static inline u32 ufshcd_get_intr_mask(struct ufs_hba *hba)
> > +{
> > +   if (hba->ufs_version == UFSHCI_VERSION_10)
> > +   return INTERRUPT_MASK_ALL_VER_10;
> > +   else
> > +   return INTERRUPT_MASK_ALL_VER_11;
> > +}
> > +
> > +/**
> >* ufshcd_get_ufs_version - Get the UFS version supported by the HBA
> >* @hba - Pointer to adapter instance
> >*
> > @@ -397,25 +415,45 @@ static int ufshcd_map_sg(struct ufshcd_lrb *lrbp)
> >   }
> >
> >   /**
> > - * ufshcd_int_config - enable/disable interrupts
> > + * ufshcd_enable_intr - enable interrupts
> >* @hba: per adapter instance
> > - * @option: interrupt option
> > + * @intrs: interrupt bits
> >*/
> > -static void ufshcd_int_config(struct ufs_hba *hba, u32 option)
> > +static void ufshcd_enable_intr(struct ufs_hba *hba, u32 intrs)
> >   {
> > -   switch (option) {
> > -   case UFSHCD_INT_ENABLE:
> > -   ufshcd_writel(hba, REG_INTERRUPT_ENABLE, hba->int_enable_mask);
> > -   break;
> > -   case UFSHCD_INT_DISABLE:
> > -   if (hba->ufs_version == UFSHCI_VERSION_10)
> > -   ufshcd_writel(hba, REG_INTERRUPT_ENABLE,
> > - INTERRUPT_DISABLE_MASK_10);
> > -   else
> > -   ufshcd_writel(hba, REG_INTERRUPT_ENABLE,
> > - INTERRUPT_DISABLE_MASK_11);
> > -   break;
> > +   u32 set = ufshcd_readl(hba, REG_INTERRUPT_ENABLE);
> > +
> > +   if (hba->ufs_version == UFSHCI_VERSION_10) {
> > +   u32 rw;
> > +   rw = set & INTERRUPT_MASK_RW_VER_10;
> > +   set = rw | ((set ^ intrs) & intrs);
> > +   } else {
> > +   set |= intrs;
> > +   }
> > +
> > +   ufshcd_writel(hba, REG_INTERRUPT_ENABLE, set);
> > +}
> > +
> > +/**
> > + * ufshcd_disable_intr - disable interrupts
> > + * @hba: per adapter instance
> > + * @intrs: interrupt bits
> > + */
> > +static void ufshcd_disable_intr(struct ufs_hba *hba, u32 intrs)
> > +{
> > +   u32 set = ufshcd_readl(hba, REG_INTERRUPT_ENABLE);
> > +
> > +   if (hba->ufs_version == UFSHCI_VERSION_10) {
> > +   u32 rw;
> > +   rw = (set & INTERRUPT_MASK_RW_VER_10) &
> > +   ~(intrs & INTERRUPT_MASK_RW_VER_10);
> > +   set = rw | ((set & intrs) & ~INTERRUPT_MASK_RW_VER_10);
> > +
> > +   } else {
> > +   set &= ~intrs;
> > }
> > +
> > +   ufshcd_writel(hba, REG_INTERRUPT_ENABLE, set);
> >   }
> >
> >   /**
> > @@ -717,8 +755,7 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba)
> > uic_cmd->argument3 = 0;
> >
> > /* enable UIC related interrupts */
> > -   hba->int_enable_mask |= UIC_COMMAND_COMPL;
> > -   

RE: [PATCH 2/5] scsi: ufs: wrap the i/o access operations

2013-05-02 Thread Seungwon Jeon
On Wednesday, May 01, 2013, merez wrote:
> Tested-by: Maya Erez 
> 
> I also tend to agree with Sujit on the order of the wrappers parameters.
Okay, I'll take the views of all(Sujit, Subhash and you)

Thanks,
Seungwon Jeon
> 
> Thanks,
> Maya
> 
> > On 4/26/2013 10:36 AM, Seungwon Jeon wrote:
> >> Hi,
> >>
> >> On Thursday, April 25, 2013, Sujit Reddy Thumma wrote:
> >>> On 4/24/2013 9:36 PM, Seungwon Jeon wrote:
> >>>> Simplify operations with hiding mmio_base.
> >>>>
> >>>> Signed-off-by: Seungwon Jeon 
> >>>> ---
> >>>>drivers/scsi/ufs/ufshcd.c |  106
> >>>> +++--
> >>>>drivers/scsi/ufs/ufshcd.h |5 ++
> >>>>2 files changed, 49 insertions(+), 62 deletions(-)
> >>>>
> >>>> diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
> >>>> index 1680394..6728450 100644
> >>>> --- a/drivers/scsi/ufs/ufshcd.h
> >>>> +++ b/drivers/scsi/ufs/ufshcd.h
> >>>> @@ -190,4 +190,9 @@ int ufshcd_init(struct device *, struct ufs_hba **
> >>>> , void __iomem * ,
> >>>>  unsigned int);
> >>>>void ufshcd_remove(struct ufs_hba *);
> >>>>
> >>>> +#define ufshcd_writel(hba, reg, val)\
> >>> Let this be consistent with writel() arguments - "val" as second arg
> >>> and
> >>> "reg" as third?
> >> You got a point there.
> >> When considering an array of arguments in two functions and value part
> >> can be some long expression,
> >> I think it seems more coherent.
> >>ufshcd_readl(hba, reg);
> >>ufshcd_writel(hba, reg, val);
> >> How about keeping these?
> >
> > I somehow tend to agree with what Sujit suggested. Its good to be
> > consitent with writel() for better code readability.
> >
> >>
> >> Thanks,
> >> Seungwon Jeon
> >>
> >>>> +writel((val), (hba)->mmio_base + (reg))
> >>>> +#define ufshcd_readl(hba, reg)  \
> >>>> +readl((hba)->mmio_base + (reg))
> >>>> +
> >>>>#endif /* End of Header */
> >>>>
> >>> --
> >>> Regards,
> >>> Sujit
> >>> --
> >>> To unsubscribe from this list: send the line "unsubscribe linux-scsi"
> >>> in
> >>> the body of a message to majord...@vger.kernel.org
> >>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> >> --
> >> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> >> the body of a message to majord...@vger.kernel.org
> >> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> > the body of a message to majord...@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> >
> 
> 
> --
> Maya Erez
> QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
> of Code Aurora Forum, hosted by The Linux Foundation
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majord...@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: [PATCH 1/5] scsi: ufs: move the ufshcd_hba_stop to ufshcd.c

2013-05-02 Thread Seungwon Jeon
On Thursday, May 02, 2013, Santosh Y wrote:
> On Wed, Apr 24, 2013 at 9:36 PM, Seungwon Jeon  wrote:
> > Move the ufshcd_hba_stop from header file.
> >
> > Signed-off-by: Seungwon Jeon 
> > ---
> >  drivers/scsi/ufs/ufshcd.c |9 +
> >  drivers/scsi/ufs/ufshcd.h |9 -
> >  2 files changed, 9 insertions(+), 9 deletions(-)
> >
> > diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> > index 60fd40c..41b9639 100644
> > --- a/drivers/scsi/ufs/ufshcd.c
> > +++ b/drivers/scsi/ufs/ufshcd.c
> > @@ -285,6 +285,15 @@ static inline void ufshcd_hba_start(struct ufs_hba 
> > *hba)
> >  }
> >
> >  /**
> > + * ufshcd_hba_stop - Send controller to reset state
> > + * @hba: per adapter instance
> > + */
> > +static inline void ufshcd_hba_stop(struct ufs_hba *hba)
> > +{
> > +   writel(CONTROLLER_DISABLE, (hba->mmio_base + 
> > REG_CONTROLLER_ENABLE));
> > +}
> > +
> > +/**
> >   * ufshcd_is_hba_active - Get controller state
> >   * @hba: per adapter instance
> >   *
> > diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
> > index 6b99a42..1680394 100644
> > --- a/drivers/scsi/ufs/ufshcd.h
> > +++ b/drivers/scsi/ufs/ufshcd.h
> > @@ -190,13 +190,4 @@ int ufshcd_init(struct device *, struct ufs_hba ** , 
> > void __iomem * ,
> > unsigned int);
> >  void ufshcd_remove(struct ufs_hba *);
> >
> > -/**
> > - * ufshcd_hba_stop - Send controller to reset state
> > - * @hba: per adapter instance
> > - */
> > -static inline void ufshcd_hba_stop(struct ufs_hba *hba)
> > -{
> > -   writel(CONTROLLER_DISABLE, (hba->mmio_base + 
> > REG_CONTROLLER_ENABLE));
> > -}
> > -
> >  #endif /* End of Header */
> > --
> > 1.7.0.4
> >
> >
> 
> The patch doesn't apply due to the character set.
> 
> "fatal: cannot convert from ks_c_5601-1987 to UTF-8"
Oh, I didn't see the problem.
I'll check more for resend.

Thanks,
Seungwon Jeon
> 
> 
> --
> ~Santosh
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majord...@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: [PATCH 4/5] scsi: ufs: rework link start-up process

2013-05-02 Thread Seungwon Jeon
On Thursday, May 02, 2013, Santosh Y wrote:
> On Thu, May 2, 2013 at 10:45 AM, Seungwon Jeon  wrote:
> > On Tuesday, April 30, 2013, Sujit Reddy Thumma wrote:
> >> On 4/30/2013 12:03 PM, Seungwon Jeon wrote:
> >> > On Monday, April 29, 2013, Sujit Reddy Thumma wrote:
> >> >> On 4/29/2013 3:54 PM, Seungwon Jeon wrote:
> >> >>> On Monday, April 29, 2013, Sujit Reddy Thumma wrote:
> >> >>>> On 4/26/2013 10:44 AM, Seungwon Jeon wrote:
> >> >>>>> On Thursday, April 25, 2013 , Sujit Reddy Thumma wrote:
> >> >>>>>> On 4/24/2013 9:36 PM, Seungwon Jeon wrote:
> >> >>>>>>> Link start-up requires long time with multiphase handshakes
> >> >>>>>>> between UFS host and device. This affects driver's probe time.
> >> >>>>>>> This patch let link start-up run asynchronously.
> >> >>>>>>> And completion time of uic command is defined to avoid a
> >> >>>>>>> permanent wait.
> >> >>>>>>
> >> >>>>>> I have similar patch posted few days back "scsi: ufs: Generalize UFS
> >> >>>>>> Interconnect Layer (UIC) command support" which does a bit more 
> >> >>>>>> (mutex,
> >> >>>>>> error handling) than what is done here. Can that be used/improved?
> >> >>>>> I completed to check your patch to compare it now.
> >> >>>>> Though it's just my thought, the patch I sent is more intuitive on 
> >> >>>>> the whole.
> >> >>>>> Considering other dme operations which I have introduced, it looks 
> >> >>>>> like matched.
> >> >>>>
> >> >>>> There are lot of code duplications you might want to minimize 
> >> >>>> building a
> >> >>>> DME command.
> >> >>>>
> >> >>>>> Of course, you may disagree.
> >> >>>>> But I think the part of mutex is needed. It's a good point.
> >> >>>>> In case of error handling, I didn't catch nothing special.
> >> >>>>> Rather, handling link lost case is not proper.
> >> >>>>> When ufs host meets link lost status, it should start with dme_reset 
> >> >>>>> not retried
> dme_linkstartup.
> >> >>>>
> >> >>>> In section 7.2.1 (Host Controller Initialization) of JESD223A UFS HCI
> >> >>>> v1.1  specification I find this -
> >> >>>>
> >> >>>> 6. Sent DME_LINKSTARTUP command to start the link startup procedure
> >> >>>> 9. Check value of HCS.DP and make sure that there is a device attached
> >> >>>> to the Link. If presence of a device is detected, go to step 10;
> >> >>>> otherwise, resend the DME_LINKSTARTUP command after IS.ULLS has been 
> >> >>>> set
> >> >>>> to 1 (Go to step 6). IS.ULLS equal 1 indicates that the UFS Device is
> >> >>>> ready for a link startup.
> >> >>>>
> >> >>>> Going by the spec. just retrying with DME_LINKSTARTUP is correct.
> >> >>> Yes, as you quoted above, HCI standard mentions that.
> >> >>> Also, the following is mentioned.
> >> >>> UIC Link Lost Status (ULLS) corresponds to the UniPro DME_LINKLOST.ind
> >> >>> I just referred unipro specification.
> >> >>> When DME_LINKLOST.ind is generated, this affects the Link is put in 
> >> >>> the LinkLost state.
> >> >>> Unipro spec says that DME User must apply a DME_RESET to redo the boot 
> >> >>> sequence.
> >> >>> If there is misunderstood meaning and I have something to miss, we can 
> >> >>> discuss more.
> >> >>> Please let me know.
> >> >>
> >> >> Yes, it looks like the two specs. are conflicting each other. I guess we
> >> >> need to take this to Jedec for clarification. Meanwhile, to be on safe
> >> >> side can we add a retry mechanism that does ufshcd_hba_enable() before
> >> >> sending DME_LINKSTARTUP again? This way we can be sure that the
> >> >> DME_RESET and DME_ENABLE is taken care by the host reset itself.
> >> > Yes, If the latter case is applied, 'ufshcd

RE: [PATCH 4/5] scsi: ufs: rework link start-up process

2013-05-02 Thread Seungwon Jeon
On Thursday, May 02, 2013, Subhash Jadavani wrote:
> Few minor comments other than what Sujit/Santosh have already commented.
I'll take your comments for next send.

Thanks,
Seungwon Jeon
> 
> On 4/24/2013 9:36 PM, Seungwon Jeon wrote:
> > Link start-up requires long time with multiphase handshakes
> > between UFS host and device. This affects driver's probe time.
> > This patch let link start-up run asynchronously.
> > And completion time of uic command is defined to avoid a
> > permanent wait.
> >
> > Signed-off-by: Seungwon Jeon 
> > ---
> >   drivers/scsi/ufs/ufshcd.c |  114 
> > +---
> >   drivers/scsi/ufs/ufshcd.h |6 ++-
> >   2 files changed, 89 insertions(+), 31 deletions(-)
> >
> > diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> > index efe2256..76ff332 100644
> > --- a/drivers/scsi/ufs/ufshcd.c
> > +++ b/drivers/scsi/ufs/ufshcd.c
> > @@ -38,6 +38,7 @@
> >   #define UFSHCD_ENABLE_INTRS   (UTP_TRANSFER_REQ_COMPL |\
> >  UTP_TASK_REQ_COMPL |\
> >  UFSHCD_ERROR_MASK)
> > +#define UIC_CMD_TIMEOUT100
> 
> What is the timeout unit here (us/ms/sec)? Please add the same in the
> comment.
> 
> >
> >   enum {
> > UFSHCD_MAX_CHANNEL  = 0,
> > @@ -357,13 +358,15 @@ static inline void ufshcd_hba_capabilities(struct 
> > ufs_hba *hba)
> >   }
> >
> >   /**
> > - * ufshcd_send_uic_command - Send UIC commands to unipro layers
> > + * ufshcd_dispatch_uic_cmd - Dispatch UIC commands to unipro layers
> >* @hba: per adapter instance
> >* @uic_command: UIC command
> >*/
> >   static inline void
> > -ufshcd_send_uic_command(struct ufs_hba *hba, struct uic_command *uic_cmnd)
> > +ufshcd_dispatch_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmnd)
> >   {
> > +   init_completion(&uic_cmnd->done);
> > +
> > /* Write Args */
> > ufshcd_writel(hba, REG_UIC_COMMAND_ARG_1, uic_cmnd->argument1);
> > ufshcd_writel(hba, REG_UIC_COMMAND_ARG_2, uic_cmnd->argument2);
> > @@ -375,6 +378,45 @@ ufshcd_send_uic_command(struct ufs_hba *hba, struct 
> > uic_command *uic_cmnd)
> >   }
> >
> >   /**
> > + * ufshcd_wait_for_uic_cmd - Wait complectioin of UIC command
> > + * @hba: per adapter instance
> > + * @uic_command: UIC command
> > + *
> > + * Returns 0 only if success.
> > + */
> > +static int ufshcd_wait_for_uic_cmd(struct ufs_hba *hba)
> > +{
> > +   struct uic_command *uic_cmd = &hba->active_uic_cmd;
> > +   int ret;
> > +
> > +   if (wait_for_completion_timeout(&uic_cmd->done,
> > +   msecs_to_jiffies(UIC_CMD_TIMEOUT)))
> > +   ret = ufshcd_get_uic_cmd_result(hba);
> > +   else
> > +   ret = -ETIMEDOUT;
> > +
> > +   return ret;
> > +}
> > +
> > +/**
> > + * ufshcd_ready_uic_cmd - Check if controller is ready
> > + *to accept UIC commands
> > + * @hba: per adapter instance
> > + * Return true on success, else false
> > + */
> > +static inline bool ufshcd_ready_uic_cmd(struct ufs_hba *hba)
> 
> I guess this might sound more readable:
> s/ufshcd_ready_uic_cmd/ufshcd_ready_for_uic_cmd
> > +{
> > +   if (ufshcd_readl(hba, REG_CONTROLLER_STATUS) & UIC_COMMAND_READY) {
> > +   return true;
> > +   } else {
> > +   dev_err(hba->dev,
> > +   "Controller not ready"
> > +   " to accept UIC commands\n");
> Please have the full string on the same line even if it exceeeds 80
> characters limit per line.
> > +   return false;
> > +   }
> > +}
> > +
> > +/**
> >* ufshcd_map_sg - Map scatter-gather list to prdt
> >* @lrbp - pointer to local reference block
> >*
> > @@ -735,15 +777,10 @@ static int ufshcd_dme_link_startup(struct ufs_hba 
> > *hba)
> >   {
> > struct uic_command *uic_cmd;
> > unsigned long flags;
> > +   int ret;
> >
> > -   /* check if controller is ready to accept UIC commands */
> > -   if (((ufshcd_readl(hba, REG_CONTROLLER_STATUS)) &
> > -   UIC_COMMAND_READY) == 0x0) {
> > -   dev_err(hba->dev,
> > -   "Controller not ready"
> > -   " to accept UIC commands\n");
> > +   if (!ufshcd_ready_uic_cmd(hba))
> 

RE: [PATCH 5/5] scsi: ufs: add dme operations

2013-05-02 Thread Seungwon Jeon
+#define DL_PEERTC1RXINITCREVAL 0x2067
> >> +
> >> +/*
> >> + * Network Layer Attributes
> >> + */
> >> +#define N_DEVICEID 0x3000
> >> +#define N_DEVICEID_VALID   0x3001
> >> +#define N_TC0TXMAXSDUSIZE  0x3020
> >> +#define N_TC1TXMAXSDUSIZE  0x3021
> >> +
> >> +/*
> >> + * Transport Layer Attributes
> >> + */
> >> +#define T_NUMCPORTS0x4000
> >> +#define T_NUMTESTFEATURES  0x4001
> >> +#define T_CONNECTIONSTATE  0x4020
> >> +#define T_PEERDEVICEID 0x4021
> >> +#define T_PEERCPORTID  0x4022
> >> +#define T_TRAFFICCLASS 0x4023
> >> +#define T_PROTOCOLID   0x4024
> >> +#define T_CPORTFLAGS   0x4025
> >> +#define T_TXTOKENVALUE 0x4026
> >> +#define T_RXTOKENVALUE 0x4027
> >> +#define T_LOCALBUFFERSPACE 0x4028
> >> +#define T_PEERBUFFERSPACE  0x4029
> >> +#define T_CREDITSTOSEND0x402A
> >> +#define T_CPORTMODE0x402B
> >> +#define T_TC0TXMAXSDUSIZE  0x4060
> >> +#define T_TC1TXMAXSDUSIZE  0x4061
> >> +
> >> +#endif /* _UFS_ATTRS_H_ */
> >
> >
> > These are Unipro. So change the name of the file to unipro.h
> >
>  I meant Unipro attributes, So change the name accordingly.
Ok, unipro.h seems proper.

Thanks,
Seungwon Jeon
> 
> >> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> >> index 76ff332..55575ea 100644
> >> --- a/drivers/scsi/ufs/ufshcd.c
> >> +++ b/drivers/scsi/ufs/ufshcd.c
> >> @@ -37,6 +37,7 @@
> >>
> >>  #define UFSHCD_ENABLE_INTRS(UTP_TRANSFER_REQ_COMPL |\
> >>  UTP_TASK_REQ_COMPL |\
> >> +UFSHCD_HIBERNATE_MASK |\
> >>  UFSHCD_ERROR_MASK)
> >>  #define UIC_CMD_TIMEOUT100
> >>
> >> @@ -188,6 +189,31 @@ static inline int ufshcd_get_uic_cmd_result(struct 
> >> ufs_hba *hba)
> >>  }
> >>
> >
> >
> > --
> > ~Santosh
> 
> 
> 
> --
> ~Santosh
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majord...@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: [PATCH 5/5] scsi: ufs: add dme operations

2013-05-02 Thread Seungwon Jeon
On Thursday, May 02, 2013, Subhash Jadavani wrote:
> On 4/24/2013 9:36 PM, Seungwon Jeon wrote:
> > Add uic command operations including DME_XXX series.
> >
> > Signed-off-by: Seungwon Jeon 
> > ---
> >   drivers/scsi/ufs/ufs-attrs.h |  129 
> >   drivers/scsi/ufs/ufshcd.c|  220 
> > +-
> >   drivers/scsi/ufs/ufshcd.h|   55 +++
> >   drivers/scsi/ufs/ufshci.h|   19 
> >   4 files changed, 422 insertions(+), 1 deletions(-)
> >   create mode 100644 drivers/scsi/ufs/ufs-attrs.h
> >
> > diff --git a/drivers/scsi/ufs/ufs-attrs.h b/drivers/scsi/ufs/ufs-attrs.h
> > new file mode 100644
> > index 000..562bb49
> > --- /dev/null
> > +++ b/drivers/scsi/ufs/ufs-attrs.h
> > @@ -0,0 +1,129 @@
> > +/*
> > + * drivers/scsi/ufs/ufs-attrs.h
> > + *
> > + * Copyright (C) 2013 Samsung Electronics Co., Ltd.
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License as published by
> > + * the Free Software Foundation; either version 2 of the License, or
> > + * (at your option) any later version.
> > + */
> > +
> > +#ifndef _UFS_ATTRS_H_
> > +#define _UFS_ATTRS_H_
> 
> I don't see a need to add this file as part of this patch as there are
> no users of the same in this patch. So its better to remove from here
> and add it as separate patch when their real use arises.
Even though actual usage is not introduced here, dme_get{set} functions are 
introduced.
These attribute's ids will be used as argument of dme_get{set}.
So, I think definitions would be better to be in this patch.

> 
> > +
> > +/*
> > + * PHY Adpater attributes
> > + */
> > +#define PA_ACTIVETXDATALANES   0x1560
> > +#define PA_ACTIVERXDATALANES   0x1580
> > +#define PA_TXTRAILINGCLOCKS0x1564
> > +#define PA_PHY_TYPE0x1500
> > +#define PA_AVAILTXDATALANES0x1520
> > +#define PA_AVAILRXDATALANES0x1540
> > +#define PA_MINRXTRAILINGCLOCKS 0x1543
> > +#define PA_TXPWRSTATUS 0x1567
> > +#define PA_RXPWRSTATUS 0x1582
> > +#define PA_TXFORCECLOCK0x1562
> > +#define PA_TXPWRMODE   0x1563
> > +#define PA_LEGACYDPHYESCDL 0x1570
> > +#define PA_MAXTXSPEEDFAST  0x1521
> > +#define PA_MAXTXSPEEDSLOW  0x1522
> > +#define PA_MAXRXSPEEDFAST  0x1541
> > +#define PA_MAXRXSPEEDSLOW  0x1542
> > +#define PA_TXLINKSTARTUPHS 0x1544
> > +#define PA_TXSPEEDFAST 0x1565
> > +#define PA_TXSPEEDSLOW 0x1566
> > +#define PA_REMOTEVERINFO   0x15A0
> > +#define PA_TXGEAR  0x1568
> > +#define PA_TXTERMINATION   0x1569
> > +#define PA_HSSERIES0x156A
> > +#define PA_PWRMODE 0x1571
> > +#define PA_RXGEAR  0x1583
> > +#define PA_RXTERMINATION   0x1584
> > +#define PA_MAXRXPWMGEAR0x1586
> > +#define PA_MAXRXHSGEAR 0x1587
> > +#define PA_RXHSUNTERMCAP   0x15A5
> > +#define PA_RXLSTERMCAP 0x15A6
> > +#define PA_PACPREQTIMEOUT  0x1590
> > +#define PA_PACPREQEOBTIMEOUT   0x1591
> > +#define PA_LOCALVERINFO0x15A9
> > +#define PA_TACTIVATE   0x15A8
> > +#define PA_PACPFRAMECOUNT  0x15C0
> > +#define PA_PACPERRORCOUNT  0x15C1
> > +#define PA_PHYTESTCONTROL  0x15C2
> > +#define PA_PWRMODEUSERDATA00x15B0
> > +#define PA_PWRMODEUSERDATA10x15B1
> > +#define PA_PWRMODEUSERDATA20x15B2
> > +#define PA_PWRMODEUSERDATA30x15B3
> > +#define PA_PWRMODEUSERDATA40x15B4
> > +#define PA_PWRMODEUSERDATA50x15B5
> > +#define PA_PWRMODEUSERDATA60x15B6
> > +#define PA_PWRMODEUSERDATA70x15B7
> > +#define PA_PWRMODEUSERDATA80x15B8
> > +#define PA_PWRMODEUSERDATA90x15B9
> > +#define PA_PWRMODEUSERDATA10   0x15BA
> > +#define PA_PWRMODEUSERDATA11   0x15BB
> > +#define PA_CONNECTEDTXDATALANE 0x1561
> > +#define PA_CONNECTEDRXDATALANE 0x1581
> > +#define PA_LOGICALLANEMAP  0x15A1
> > +#define PA_SLEEPNOCONFIGTIME   0x15A2
> > +#define PA_STALLNOCONFIGTIME   0x15A3
> > +#define PA_SAVECONFIGTIME  0x15A4
> > +
> > +/*
> > + * Data Link Layer Attributes
> > + */
> > +#define DL_TC0TXFCTHRESHOLD0x2040
> > +#define DL_FC0PROTTIMEOUTVAL   0x2041
> > +#define DL_TC0REPLAYTIMEOUTVAL 0x2042
> > +#define DL_AFC0RE

[PATCH v2 1/7] scsi: ufs: move the ufshcd_hba_stop to ufshcd.c

2013-05-04 Thread Seungwon Jeon
Move the ufshcd_hba_stop from header file.

Signed-off-by: Seungwon Jeon 
Reviewed-by: Subhash Jadavani 
Tested-by: Maya Erez 
---
 drivers/scsi/ufs/ufshcd.c |9 +
 drivers/scsi/ufs/ufshcd.h |9 -
 2 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index f244812..d932239 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -280,6 +280,15 @@ static inline void ufshcd_hba_start(struct ufs_hba *hba)
 }
 
 /**
+ * ufshcd_hba_stop - Send controller to reset state
+ * @hba: per adapter instance
+ */
+static inline void ufshcd_hba_stop(struct ufs_hba *hba)
+{
+   writel(CONTROLLER_DISABLE, (hba->mmio_base + REG_CONTROLLER_ENABLE));
+}
+
+/**
  * ufshcd_is_hba_active - Get controller state
  * @hba: per adapter instance
  *
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 336980b..3a1052d 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -208,13 +208,4 @@ int ufshcd_init(struct device *, struct ufs_hba ** , void 
__iomem * ,
unsigned int);
 void ufshcd_remove(struct ufs_hba *);
 
-/**
- * ufshcd_hba_stop - Send controller to reset state
- * @hba: per adapter instance
- */
-static inline void ufshcd_hba_stop(struct ufs_hba *hba)
-{
-   writel(CONTROLLER_DISABLE, (hba->mmio_base + REG_CONTROLLER_ENABLE));
-}
-
 #endif /* End of Header */
-- 
1.7.0.4


--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 2/7] scsi: ufs: wrap the i/o access operations

2013-05-04 Thread Seungwon Jeon
Simplify operations with hiding mmio_base.

Signed-off-by: Seungwon Jeon 
Tested-by: Maya Erez 
---
 drivers/scsi/ufs/ufshcd.c |  107 +++--
 drivers/scsi/ufs/ufshcd.h |5 ++
 2 files changed, 50 insertions(+), 62 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index d932239..af7b81b 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -71,7 +71,7 @@ enum {
  */
 static inline u32 ufshcd_get_ufs_version(struct ufs_hba *hba)
 {
-   return readl(hba->mmio_base + REG_UFS_VERSION);
+   return ufshcd_readl(hba, REG_UFS_VERSION);
 }
 
 /**
@@ -130,8 +130,7 @@ static inline int ufshcd_get_tm_free_slot(struct ufs_hba 
*hba)
  */
 static inline void ufshcd_utrl_clear(struct ufs_hba *hba, u32 pos)
 {
-   writel(~(1 << pos),
-   (hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_CLEAR));
+   ufshcd_writel(hba, ~(1 << pos), REG_UTP_TRANSFER_REQ_LIST_CLEAR);
 }
 
 /**
@@ -165,7 +164,7 @@ static inline int ufshcd_get_lists_status(u32 reg)
  */
 static inline int ufshcd_get_uic_cmd_result(struct ufs_hba *hba)
 {
-   return readl(hba->mmio_base + REG_UIC_COMMAND_ARG_2) &
+   return ufshcd_readl(hba, REG_UIC_COMMAND_ARG_2) &
   MASK_UIC_COMMAND_RESULT;
 }
 
@@ -238,18 +237,15 @@ ufshcd_config_int_aggr(struct ufs_hba *hba, int option)
 {
switch (option) {
case INT_AGGR_RESET:
-   writel((INT_AGGR_ENABLE |
-   INT_AGGR_COUNTER_AND_TIMER_RESET),
-   (hba->mmio_base +
-REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL));
+   ufshcd_writel(hba, INT_AGGR_ENABLE |
+ INT_AGGR_COUNTER_AND_TIMER_RESET,
+ REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
break;
case INT_AGGR_CONFIG:
-   writel((INT_AGGR_ENABLE |
-   INT_AGGR_PARAM_WRITE |
-   INT_AGGR_COUNTER_THRESHOLD_VALUE |
-   INT_AGGR_TIMEOUT_VALUE),
-   (hba->mmio_base +
-REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL));
+   ufshcd_writel(hba, INT_AGGR_ENABLE | INT_AGGR_PARAM_WRITE |
+ INT_AGGR_COUNTER_THRESHOLD_VALUE |
+ INT_AGGR_TIMEOUT_VALUE,
+ REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
break;
}
 }
@@ -262,12 +258,10 @@ ufshcd_config_int_aggr(struct ufs_hba *hba, int option)
  */
 static void ufshcd_enable_run_stop_reg(struct ufs_hba *hba)
 {
-   writel(UTP_TASK_REQ_LIST_RUN_STOP_BIT,
-  (hba->mmio_base +
-   REG_UTP_TASK_REQ_LIST_RUN_STOP));
-   writel(UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT,
-  (hba->mmio_base +
-   REG_UTP_TRANSFER_REQ_LIST_RUN_STOP));
+   ufshcd_writel(hba, UTP_TASK_REQ_LIST_RUN_STOP_BIT,
+ REG_UTP_TASK_REQ_LIST_RUN_STOP);
+   ufshcd_writel(hba, UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT,
+ REG_UTP_TRANSFER_REQ_LIST_RUN_STOP);
 }
 
 /**
@@ -276,7 +270,7 @@ static void ufshcd_enable_run_stop_reg(struct ufs_hba *hba)
  */
 static inline void ufshcd_hba_start(struct ufs_hba *hba)
 {
-   writel(CONTROLLER_ENABLE , (hba->mmio_base + REG_CONTROLLER_ENABLE));
+   ufshcd_writel(hba, CONTROLLER_ENABLE, REG_CONTROLLER_ENABLE);
 }
 
 /**
@@ -285,7 +279,7 @@ static inline void ufshcd_hba_start(struct ufs_hba *hba)
  */
 static inline void ufshcd_hba_stop(struct ufs_hba *hba)
 {
-   writel(CONTROLLER_DISABLE, (hba->mmio_base + REG_CONTROLLER_ENABLE));
+   ufshcd_writel(hba, CONTROLLER_DISABLE, REG_CONTROLLER_ENABLE);
 }
 
 /**
@@ -296,7 +290,7 @@ static inline void ufshcd_hba_stop(struct ufs_hba *hba)
  */
 static inline int ufshcd_is_hba_active(struct ufs_hba *hba)
 {
-   return (readl(hba->mmio_base + REG_CONTROLLER_ENABLE) & 0x1) ? 0 : 1;
+   return (ufshcd_readl(hba, REG_CONTROLLER_ENABLE) & 0x1) ? 0 : 1;
 }
 
 /**
@@ -308,8 +302,7 @@ static inline
 void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag)
 {
__set_bit(task_tag, &hba->outstanding_reqs);
-   writel((1 << task_tag),
-  (hba->mmio_base + REG_UTP_TRANSFER_REQ_DOOR_BELL));
+   ufshcd_writel(hba, 1 << task_tag, REG_UTP_TRANSFER_REQ_DOOR_BELL);
 }
 
 /**
@@ -390,8 +383,7 @@ void ufshcd_copy_query_response(struct ufs_hba *hba, struct 
ufshcd_lrb *lrbp)
  */
 static inline void ufshcd_hba_capabilities(struct ufs_hba *hba)
 {
-   hba->capabilities =
-   readl(hba->mmio_base + REG_CONTROLLER_CAPABILITIES);
+   hba->capabilities = ufshcd_readl(hba, REG_CONTROLLER_CAPABILITIES);
 
/* nutrs and nutmrs are 0 based values */
hba->nutrs = (hba->capabilities & MASK_TRANSFER_REQUESTS_SLOTS) + 1;
@@ -408,16 +400,

[PATCH v2 3/7] scsi: ufs: amend interrupt configuration

2013-05-04 Thread Seungwon Jeon
It makes interrupt setting more flexible especially
for disabling. And wrong bit mask is fixed for ver 1.0.
[17:16] is added for mask.

Signed-off-by: Seungwon Jeon 
Tested-by: Maya Erez 
---
 drivers/scsi/ufs/ufshcd.c |   84 +++-
 drivers/scsi/ufs/ufshcd.h |4 +-
 drivers/scsi/ufs/ufshci.h |5 ++-
 3 files changed, 64 insertions(+), 29 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index af7b81b..bc956e8 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -35,6 +35,10 @@
 
 #include "ufshcd.h"
 
+#define UFSHCD_ENABLE_INTRS(UTP_TRANSFER_REQ_COMPL |\
+UTP_TASK_REQ_COMPL |\
+UFSHCD_ERROR_MASK)
+
 enum {
UFSHCD_MAX_CHANNEL  = 0,
UFSHCD_MAX_ID   = 1,
@@ -64,6 +68,20 @@ enum {
 };
 
 /**
+ * ufshcd_get_intr_mask - Get the interrupt bit mask
+ * @hba - Pointer to adapter instance
+ *
+ * Returns interrupt bit mask per version
+ */
+static inline u32 ufshcd_get_intr_mask(struct ufs_hba *hba)
+{
+   if (hba->ufs_version == UFSHCI_VERSION_10)
+   return INTERRUPT_MASK_ALL_VER_10;
+   else
+   return INTERRUPT_MASK_ALL_VER_11;
+}
+
+/**
  * ufshcd_get_ufs_version - Get the UFS version supported by the HBA
  * @hba - Pointer to adapter instance
  *
@@ -450,25 +468,45 @@ static int ufshcd_map_sg(struct ufshcd_lrb *lrbp)
 }
 
 /**
- * ufshcd_int_config - enable/disable interrupts
+ * ufshcd_enable_intr - enable interrupts
  * @hba: per adapter instance
- * @option: interrupt option
+ * @intrs: interrupt bits
  */
-static void ufshcd_int_config(struct ufs_hba *hba, u32 option)
+static void ufshcd_enable_intr(struct ufs_hba *hba, u32 intrs)
 {
-   switch (option) {
-   case UFSHCD_INT_ENABLE:
-   ufshcd_writel(hba, hba->int_enable_mask, REG_INTERRUPT_ENABLE);
-   break;
-   case UFSHCD_INT_DISABLE:
-   if (hba->ufs_version == UFSHCI_VERSION_10)
-   ufshcd_writel(hba, INTERRUPT_DISABLE_MASK_10,
- REG_INTERRUPT_ENABLE);
-   else
-   ufshcd_writel(hba, INTERRUPT_DISABLE_MASK_11,
- REG_INTERRUPT_ENABLE);
-   break;
+   u32 set = ufshcd_readl(hba, REG_INTERRUPT_ENABLE);
+
+   if (hba->ufs_version == UFSHCI_VERSION_10) {
+   u32 rw;
+   rw = set & INTERRUPT_MASK_RW_VER_10;
+   set = rw | ((set ^ intrs) & intrs);
+   } else {
+   set |= intrs;
+   }
+
+   ufshcd_writel(hba, set, REG_INTERRUPT_ENABLE);
+}
+
+/**
+ * ufshcd_disable_intr - disable interrupts
+ * @hba: per adapter instance
+ * @intrs: interrupt bits
+ */
+static void ufshcd_disable_intr(struct ufs_hba *hba, u32 intrs)
+{
+   u32 set = ufshcd_readl(hba, REG_INTERRUPT_ENABLE);
+
+   if (hba->ufs_version == UFSHCI_VERSION_10) {
+   u32 rw;
+   rw = (set & INTERRUPT_MASK_RW_VER_10) &
+   ~(intrs & INTERRUPT_MASK_RW_VER_10);
+   set = rw | ((set & intrs) & ~INTERRUPT_MASK_RW_VER_10);
+
+   } else {
+   set &= ~intrs;
}
+
+   ufshcd_writel(hba, set, REG_INTERRUPT_ENABLE);
 }
 
 /**
@@ -955,8 +993,7 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba)
uic_cmd->argument3 = 0;
 
/* enable UIC related interrupts */
-   hba->int_enable_mask |= UIC_COMMAND_COMPL;
-   ufshcd_int_config(hba, UFSHCD_INT_ENABLE);
+   ufshcd_enable_intr(hba, UIC_COMMAND_COMPL);
 
/* sending UIC commands to controller */
ufshcd_send_uic_command(hba, uic_cmd);
@@ -1003,13 +1040,7 @@ static int ufshcd_make_hba_operational(struct ufs_hba 
*hba)
}
 
/* Enable required interrupts */
-   hba->int_enable_mask |= (UTP_TRANSFER_REQ_COMPL |
-UIC_ERROR |
-UTP_TASK_REQ_COMPL |
-DEVICE_FATAL_ERROR |
-CONTROLLER_FATAL_ERROR |
-SYSTEM_BUS_FATAL_ERROR);
-   ufshcd_int_config(hba, UFSHCD_INT_ENABLE);
+   ufshcd_enable_intr(hba, UFSHCD_ENABLE_INTRS);
 
/* Configure interrupt aggregation */
ufshcd_config_int_aggr(hba, INT_AGGR_CONFIG);
@@ -1837,7 +1868,7 @@ static void ufshcd_hba_free(struct ufs_hba *hba)
 void ufshcd_remove(struct ufs_hba *hba)
 {
/* disable interrupts */
-   ufshcd_int_config(hba, UFSHCD_INT_DISABLE);
+   ufshcd_disable_intr(hba, hba->intr_mask);
 
ufshcd_hba_stop(hba);
ufshcd_hba_free(hba);
@@ -1895,6 +1926,9 @@ int ufshcd_init(struct device *dev, struct ufs_hba 
**hba_handle,
/* Get UFS version supported by the controller */
hba->ufs_version = ufshcd_get_ufs_vers

[PATCH v2 4/7] scsi: ufs: fix interrupt status clears

2013-05-04 Thread Seungwon Jeon
There is no need to check the version to clear
the interrupt status. And the order is changed
prior to actual handling.

Signed-off-by: Seungwon Jeon 
---
 drivers/scsi/ufs/ufshcd.c |5 +
 1 files changed, 1 insertions(+), 4 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index bc956e8..442195c 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -1591,11 +1591,8 @@ static irqreturn_t ufshcd_intr(int irq, void *__hba)
intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
 
if (intr_status) {
+   ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
ufshcd_sl_intr(hba, intr_status);
-
-   /* If UFSHCI 1.0 then clear interrupt status register */
-   if (hba->ufs_version == UFSHCI_VERSION_10)
-   ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
retval = IRQ_HANDLED;
}
spin_unlock(hba->host->host_lock);
-- 
1.7.0.4


--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 7/7] scsi: ufs: add dme control primitives

2013-05-04 Thread Seungwon Jeon
Implements to support the following operations.
Currently, this patch doesn't introduce DME_ENABLE and DME_RESET
because host controller's HCE enable contains these roles.

DME_POWERON{OFF}, DME_HIBERNATE_ENTER{EXIT}, DME_ENDPOINTRESET.

Signed-off-by: Seungwon Jeon 
---
 drivers/scsi/ufs/ufshcd.c |  133 ++---
 drivers/scsi/ufs/ufshcd.h |   26 +
 drivers/scsi/ufs/ufshci.h |   15 +
 3 files changed, 166 insertions(+), 8 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 956041c..54cd61a 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -39,6 +39,7 @@
 
 #define UFSHCD_ENABLE_INTRS(UTP_TRANSFER_REQ_COMPL |\
 UTP_TASK_REQ_COMPL |\
+UFSHCD_HIBERNATE_MASK |\
 UFSHCD_ERROR_MASK)
 /* UIC command timeout, unit: ms */
 #define UIC_CMD_TIMEOUT500
@@ -203,6 +204,18 @@ static inline u32 ufshcd_get_dme_attr_val(struct ufs_hba 
*hba)
 }
 
 /**
+ * ufshcd_get_upmcrs - Get the power mode change request status
+ * @hba: Pointer to adapter instance
+ *
+ * This function gets the UPMCRS field of HCS register
+ * Returns value of UPMCRS field
+ */
+static inline u8 ufshcd_get_upmcrs(struct ufs_hba *hba)
+{
+   return (ufshcd_readl(hba, REG_CONTROLLER_STATUS) >> 8) & 0x7;
+}
+
+/**
  * ufshcd_free_hba_memory - Free allocated memory for LRB, request
  * and task lists
  * @hba: Pointer to adapter instance
@@ -1161,6 +1174,104 @@ int ufshcd_dme_xxx_get(struct ufs_hba *hba, u32 
attr_sel,
 EXPORT_SYMBOL_GPL(ufshcd_dme_xxx_get);
 
 /**
+ * ufshcd_dme_power_xxx - UIC command for DME_POWERON, DME_POWEROFF
+ * @hba: per adapter instance
+ * @on: indicate wherter power_on or power_off
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+int ufshcd_dme_power_xxx(struct ufs_hba *hba, u8 on)
+{
+   struct uic_command uic_cmd = {0};
+   static const char *const action[] = {
+   "dme-power-off",
+   "dme-power-on"
+   };
+   const char *power = action[!!on];
+   int ret;
+
+   uic_cmd.command = on ?
+   UIC_CMD_DME_POWERON : UIC_CMD_DME_POWEROFF;
+
+   ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
+   if (ret)
+   dev_err(hba->dev, "%s: error code %d\n", power, ret);
+
+   return ret;
+}
+EXPORT_SYMBOL_GPL(ufshcd_dme_power_xxx);
+
+/**
+ * ufshcd_dme_hibern8_xxx - UIC command for DME_HIBERNATE_ENTER,
+ * DME_HIBERNATE_EXIT
+ * @hba: per adapter instance
+ * @enter: indicate wherter hibernation enter or exit
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+int ufshcd_dme_hibern8_xxx(struct ufs_hba *hba, u8 enter)
+{
+   struct uic_command uic_cmd = {0};
+   static const char *const action[] = {
+   "dme-hibernate-exit",
+   "dme-hibernate-enter"
+   };
+   const char *hibern8 = action[!!enter];
+   u8 status;
+   int ret;
+
+   uic_cmd.command = enter ?
+   UIC_CMD_DME_HIBER_ENTER : UIC_CMD_DME_HIBER_EXIT;
+
+   mutex_lock(&hba->uic_cmd_mutex);
+   ret = __ufshcd_send_uic_cmd(hba, &uic_cmd);
+   if (ret) {
+   dev_err(hba->dev, "%s: error code %d\n", hibern8, ret);
+   goto out;
+   }
+
+   init_completion(&hba->hibern8_done);
+
+   if (wait_for_completion_timeout(&hba->hibern8_done,
+   msecs_to_jiffies(UIC_CMD_TIMEOUT))) {
+   status = ufshcd_get_upmcrs(hba);
+   if (status != PWR_LOCAL) {
+   dev_err(hba->dev, "%s: failed, host upmcrs:%x\n",
+   hibern8, status);
+   ret = status;
+   }
+   } else {
+   dev_err(hba->dev, "%s: timeout\n", hibern8);
+   ret = -ETIMEDOUT;
+   }
+out:
+   mutex_unlock(&hba->uic_cmd_mutex);
+   return ret;
+}
+EXPORT_SYMBOL_GPL(ufshcd_dme_hibern8_xxx);
+
+/**
+ * ufshcd_dme_endpt_reset - UIC command for DME_ENDPOINTRESET
+ * @hba: per adapter instance
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+int ufshcd_dme_endpt_reset(struct ufs_hba *hba)
+{
+   struct uic_command uic_cmd = {0};
+   int ret;
+
+   uic_cmd.command = UIC_CMD_DME_END_PT_RST;
+
+   ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
+   if (ret)
+   dev_err(hba->dev, "endpoint reset: error code %d\n", ret);
+
+   return ret;
+}
+EXPORT_SYMBOL_GPL(ufshcd_dme_endpt_reset);
+
+/**
  * ufshcd_make_hba_operational - Make UFS controller operational
  * @hba: per adapter instance
  *
@@ -1617,14 +1728,20 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct 
ufshcd_lrb *lrbp)
 /**
  * uf

[PATCH v2 5/7] scsi: ufs: rework link start-up process

2013-05-04 Thread Seungwon Jeon
Link start-up requires long time with multiphase handshakes
between UFS host and device. This affects driver's probe time.
This patch let link start-up run asynchronously. Link start-up
will be executed at the end of prove separately.
Along with this change, the following is worked.

Defined completion time of uic command to avoid a permanent wait.
Added mutex to guarantee of uic command at a time.
Adapted some sequence of controller initialization after link statup
according to HCI standard.

Signed-off-by: Seungwon Jeon 
Signed-off-by: Sujit Reddy Thumma 
---
 drivers/scsi/ufs/ufshcd.c |  287 ++---
 drivers/scsi/ufs/ufshcd.h |   10 +-
 2 files changed, 200 insertions(+), 97 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 442195c..9c94d42 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -33,11 +33,15 @@
  * this program.
  */
 
+#include 
+
 #include "ufshcd.h"
 
 #define UFSHCD_ENABLE_INTRS(UTP_TRANSFER_REQ_COMPL |\
 UTP_TASK_REQ_COMPL |\
 UFSHCD_ERROR_MASK)
+/* UIC command timeout, unit: ms */
+#define UIC_CMD_TIMEOUT500
 
 enum {
UFSHCD_MAX_CHANNEL  = 0,
@@ -410,24 +414,115 @@ static inline void ufshcd_hba_capabilities(struct 
ufs_hba *hba)
 }
 
 /**
- * ufshcd_send_uic_command - Send UIC commands to unipro layers
+ * ufshcd_ready_for_uic_cmd - Check if controller is ready
+ *to accept UIC commands
  * @hba: per adapter instance
- * @uic_command: UIC command
+ * Return true on success, else false
+ */
+static inline bool ufshcd_ready_for_uic_cmd(struct ufs_hba *hba)
+{
+   if (ufshcd_readl(hba, REG_CONTROLLER_STATUS) & UIC_COMMAND_READY)
+   return true;
+   else
+   return false;
+}
+
+/**
+ * ufshcd_dispatch_uic_cmd - Dispatch UIC commands to unipro layers
+ * @hba: per adapter instance
+ * @uic_cmd: UIC command
+ *
+ * Mutex must be held.
  */
 static inline void
-ufshcd_send_uic_command(struct ufs_hba *hba, struct uic_command *uic_cmnd)
+ufshcd_dispatch_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
 {
+   hba->active_uic_cmd = uic_cmd;
+
/* Write Args */
-   ufshcd_writel(hba, uic_cmnd->argument1, REG_UIC_COMMAND_ARG_1);
-   ufshcd_writel(hba, uic_cmnd->argument2, REG_UIC_COMMAND_ARG_2);
-   ufshcd_writel(hba, uic_cmnd->argument3, REG_UIC_COMMAND_ARG_3);
+   ufshcd_writel(hba, uic_cmd->argument1, REG_UIC_COMMAND_ARG_1);
+   ufshcd_writel(hba, uic_cmd->argument2, REG_UIC_COMMAND_ARG_2);
+   ufshcd_writel(hba, uic_cmd->argument3, REG_UIC_COMMAND_ARG_3);
 
/* Write UIC Cmd */
-   ufshcd_writel(hba, uic_cmnd->command & COMMAND_OPCODE_MASK,
+   ufshcd_writel(hba, uic_cmd->command & COMMAND_OPCODE_MASK,
  REG_UIC_COMMAND);
 }
 
 /**
+ * ufshcd_wait_for_uic_cmd - Wait complectioin of UIC command
+ * @hba: per adapter instance
+ * @uic_command: UIC command
+ *
+ * Must be called with mutex held.
+ * Returns 0 only if success.
+ */
+static int
+ufshcd_wait_for_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
+{
+   int ret;
+
+   if (wait_for_completion_timeout(&uic_cmd->done,
+   msecs_to_jiffies(UIC_CMD_TIMEOUT)))
+   ret = uic_cmd->argument2 & MASK_UIC_COMMAND_RESULT;
+   else
+   ret = -ETIMEDOUT;
+
+   return ret;
+}
+
+/**
+ * __ufshcd_send_uic_cmd - Send UIC commands and retrieve the result
+ * @hba: per adapter instance
+ * @uic_cmd: UIC command
+ *
+ * Identical to ufshcd_send_uic_cmd() expect mutex. Must be called
+ * with mutex held.
+ * Returns 0 only if success.
+ */
+static int
+__ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
+{
+   int ret;
+   unsigned long flags;
+
+   if (!ufshcd_ready_for_uic_cmd(hba)) {
+   dev_err(hba->dev,
+   "Controller not ready to accept UIC commands\n");
+   return -EIO;
+   }
+
+   init_completion(&uic_cmd->done);
+
+   spin_lock_irqsave(hba->host->host_lock, flags);
+   ufshcd_dispatch_uic_cmd(hba, uic_cmd);
+   spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+   ret = ufshcd_wait_for_uic_cmd(hba, uic_cmd);
+
+   return ret;
+}
+
+/**
+ * ufshcd_send_uic_cmd - Send UIC commands and retrieve the result
+ * @hba: per adapter instance
+ * @uic_cmd: UIC command
+ *
+ * Returns 0 only if success.
+ */
+static int
+ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
+{
+   int ret;
+
+   mutex_lock(&hba->uic_cmd_mutex);
+   ret = __ufshcd_send_uic_cmd(hba, uic_cmd);
+   mutex_unlock(&hba->uic_cmd_mutex);
+
+   return ret;
+}
+
+/**
  * ufshcd_map_sg - Map scatter-gather list to prdt
  * @

[PATCH v2 6/7] scsi: ufs: add dme configuration primitives

2013-05-04 Thread Seungwon Jeon
Implements to support Get and Set operation of the DME.
And along with these operations, IDs of Attribute are added.
It is used to configure the behavior of the UNIPRO.

Signed-off-by: Seungwon Jeon 
---
 drivers/scsi/ufs/ufshcd.c |   84 +
 drivers/scsi/ufs/ufshcd.h |   29 ++
 drivers/scsi/ufs/ufshci.h |4 ++
 drivers/scsi/ufs/unipro.h |  129 +
 4 files changed, 246 insertions(+), 0 deletions(-)
 create mode 100644 drivers/scsi/ufs/unipro.h

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 9c94d42..956041c 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -191,6 +191,18 @@ static inline int ufshcd_get_uic_cmd_result(struct ufs_hba 
*hba)
 }
 
 /**
+ * ufshcd_get_dme_attr_val - Get the value of attribute returned by UIC command
+ * @hba: Pointer to adapter instance
+ *
+ * This function gets UIC command argument3
+ * Returns 0 on success, non zero value on error
+ */
+static inline u32 ufshcd_get_dme_attr_val(struct ufs_hba *hba)
+{
+   return ufshcd_readl(hba, REG_UIC_COMMAND_ARG_3);
+}
+
+/**
  * ufshcd_free_hba_memory - Free allocated memory for LRB, request
  * and task lists
  * @hba: Pointer to adapter instance
@@ -1079,6 +1091,76 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba)
 }
 
 /**
+ * ufshcd_dme_xxx_set - UIC command for DME_SET, DME_PEER_SET
+ * @hba: per adapter instance
+ * @attr_sel: uic command argument1
+ * @attr_set: attribute set type as uic command argument2
+ * @mib_val: setting value as uic command argument3
+ * @peer: indicate wherter peer or non-peer
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+int ufshcd_dme_xxx_set(struct ufs_hba *hba, u32 attr_sel,
+  u8 attr_set, u32 mib_val, u8 peer)
+{
+   struct uic_command uic_cmd = {0};
+   static const char *const action[] = {
+   "dme-set",
+   "dme-peer-set"
+   };
+   const char *set = action[!!peer];
+   int ret;
+
+   uic_cmd.command = peer ?
+   UIC_CMD_DME_PEER_SET : UIC_CMD_DME_SET;
+   uic_cmd.argument1 = attr_sel;
+   uic_cmd.argument2 = UIC_ARG_ATTR_SET(attr_set);
+   uic_cmd.argument3 = mib_val;
+
+   ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
+
+   dev_dbg(hba->dev, "%s: error code %d\n", set, ret);
+
+   return ret;
+}
+EXPORT_SYMBOL_GPL(ufshcd_dme_xxx_set);
+
+/**
+ * ufshcd_dme_xxx_get - UIC command for DME_GET, DME_PEER_GET
+ * @hba: per adapter instance
+ * @attr_sel: uic command argument1
+ * @mib_val: the value of the attribute as returned by the UIC command
+ * @peer: indicate wherter peer or non-peer
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+int ufshcd_dme_xxx_get(struct ufs_hba *hba, u32 attr_sel,
+  u32 *mib_val, u8 peer)
+{
+   struct uic_command uic_cmd = {0};
+   static const char *const action[] = {
+   "dme-get",
+   "dme-peer-get"
+   };
+   const char *get = action[!!peer];
+   int ret;
+
+   uic_cmd.command = peer ?
+   UIC_CMD_DME_PEER_GET : UIC_CMD_DME_GET;
+   uic_cmd.argument1 = attr_sel;
+
+   ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
+
+   if (mib_val)
+   *mib_val = uic_cmd.argument3;
+
+   dev_dbg(hba->dev, "%s: error code %d\n", get, ret);
+
+   return ret;
+}
+EXPORT_SYMBOL_GPL(ufshcd_dme_xxx_get);
+
+/**
  * ufshcd_make_hba_operational - Make UFS controller operational
  * @hba: per adapter instance
  *
@@ -1540,6 +1622,8 @@ static void ufshcd_uic_cmd_compl(struct ufs_hba *hba)
 {
hba->active_uic_cmd->argument2 |=
ufshcd_get_uic_cmd_result(hba);
+   hba->active_uic_cmd->argument3 =
+   ufshcd_get_dme_attr_val(hba);
complete(&hba->active_uic_cmd->done);
 }
 
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 6095b3b..b47de70 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -217,4 +217,33 @@ int ufshcd_init(struct device *, struct ufs_hba ** , void 
__iomem * ,
unsigned int);
 void ufshcd_remove(struct ufs_hba *);
 
+extern int ufshcd_dme_xxx_set(struct ufs_hba *hba, u32 attr_sel,
+ u8 attr_set, u32 mib_val, u8 peer);
+extern int ufshcd_dme_xxx_get(struct ufs_hba *hba, u32 attr_sel,
+ u32 *mib_val, u8 peer);
+
+static inline int ufshcd_dme_set(struct ufs_hba *hba, u32 attr_sel,
+u8 attr_set, u32 mib_val)
+{
+   return ufshcd_dme_xxx_set(hba, attr_sel, attr_set, mib_val, 0);
+}
+
+static inline int ufshcd_dme_peer_set(struct ufs_hba *hba, u32 attr_sel,
+ u8 attr_set, u32 mib_val)
+{
+   return ufshcd_dme_xxx_set(

RE: [PATCH v2 1/7] scsi: ufs: move the ufshcd_hba_stop to ufshcd.c

2013-05-05 Thread Seungwon Jeon
On Sunday, May 05, 2013 8:23, Merze wrote:
> Hi,
> 
> ufshcd_pci_shutdown (in ufshcd_pci.c) is using ufshcd_hba_stop so it
> cannot be moved to ufshcd.c.
> Sorry for missing it last time I tested, I returned ufshcd_hba_stop to
> ufshcd.h by mistake when I resolved conflicts of the next patch so I
> didn't hit the compilation errors.

Oh, I also missed this. Thank you for informing.
I'll keep ufshcd_hba_stop function in place and
just touch for the patch of "scsi: ufs: wrap the i/o access operations".

Thanks,
Seungwon Jeon
> 
> Thanks,
> Maya
> > Move the ufshcd_hba_stop from header file.
> >
> > Signed-off-by: Seungwon Jeon 
> > Reviewed-by: Subhash Jadavani 
> > Tested-by: Maya Erez 
> > ---
> >  drivers/scsi/ufs/ufshcd.c |9 +
> >  drivers/scsi/ufs/ufshcd.h |9 -
> >  2 files changed, 9 insertions(+), 9 deletions(-)
> >
> > diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> > index f244812..d932239 100644
> > --- a/drivers/scsi/ufs/ufshcd.c
> > +++ b/drivers/scsi/ufs/ufshcd.c
> > @@ -280,6 +280,15 @@ static inline void ufshcd_hba_start(struct ufs_hba
> > *hba)
> >  }
> >
> >  /**
> > + * ufshcd_hba_stop - Send controller to reset state
> > + * @hba: per adapter instance
> > + */
> > +static inline void ufshcd_hba_stop(struct ufs_hba *hba)
> > +{
> > +   writel(CONTROLLER_DISABLE, (hba->mmio_base + REG_CONTROLLER_ENABLE));
> > +}
> > +
> > +/**
> >   * ufshcd_is_hba_active - Get controller state
> >   * @hba: per adapter instance
> >   *
> > diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
> > index 336980b..3a1052d 100644
> > --- a/drivers/scsi/ufs/ufshcd.h
> > +++ b/drivers/scsi/ufs/ufshcd.h
> > @@ -208,13 +208,4 @@ int ufshcd_init(struct device *, struct ufs_hba ** ,
> > void __iomem * ,
> > unsigned int);
> >  void ufshcd_remove(struct ufs_hba *);
> >
> > -/**
> > - * ufshcd_hba_stop - Send controller to reset state
> > - * @hba: per adapter instance
> > - */
> > -static inline void ufshcd_hba_stop(struct ufs_hba *hba)
> > -{
> > -   writel(CONTROLLER_DISABLE, (hba->mmio_base + REG_CONTROLLER_ENABLE));
> > -}
> > -
> >  #endif /* End of Header */
> > --
> > 1.7.0.4
> >
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> > the body of a message to majord...@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> >
> 
> 
> --
> Maya Erez
> QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
> of Code Aurora Forum, hosted by The Linux Foundation
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majord...@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: [PATCH v2 7/7] scsi: ufs: add dme control primitives

2013-05-05 Thread Seungwon Jeon
On Sunday, May 05, 2013, Sujit Reddy Thumma wrote:
> On 5/4/2013 2:15 PM, Seungwon Jeon wrote:
> > Implements to support the following operations.
> > Currently, this patch doesn't introduce DME_ENABLE and DME_RESET
> > because host controller's HCE enable contains these roles.
> >
> > DME_POWERON{OFF}, DME_HIBERNATE_ENTER{EXIT}, DME_ENDPOINTRESET.
> >
> > Signed-off-by: Seungwon Jeon 
> > ---
> >   drivers/scsi/ufs/ufshcd.c |  133 
> > ++---
> >   drivers/scsi/ufs/ufshcd.h |   26 +
> >   drivers/scsi/ufs/ufshci.h |   15 +
> >   3 files changed, 166 insertions(+), 8 deletions(-)
> >
> > diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> > index 956041c..54cd61a 100644
> > --- a/drivers/scsi/ufs/ufshcd.c
> > +++ b/drivers/scsi/ufs/ufshcd.c
> > @@ -39,6 +39,7 @@
> >
> >   #define UFSHCD_ENABLE_INTRS   (UTP_TRANSFER_REQ_COMPL |\
> >  UTP_TASK_REQ_COMPL |\
> > +UFSHCD_HIBERNATE_MASK |\
> >  UFSHCD_ERROR_MASK)
> >   /* UIC command timeout, unit: ms */
> >   #define UIC_CMD_TIMEOUT   500
> > @@ -203,6 +204,18 @@ static inline u32 ufshcd_get_dme_attr_val(struct 
> > ufs_hba *hba)
> >   }
> >
> >   /**
> > + * ufshcd_get_upmcrs - Get the power mode change request status
> > + * @hba: Pointer to adapter instance
> > + *
> > + * This function gets the UPMCRS field of HCS register
> > + * Returns value of UPMCRS field
> > + */
> > +static inline u8 ufshcd_get_upmcrs(struct ufs_hba *hba)
> > +{
> > +   return (ufshcd_readl(hba, REG_CONTROLLER_STATUS) >> 8) & 0x7;
> > +}
> > +
> > +/**
> >* ufshcd_free_hba_memory - Free allocated memory for LRB, request
> >*and task lists
> >* @hba: Pointer to adapter instance
> > @@ -1161,6 +1174,104 @@ int ufshcd_dme_xxx_get(struct ufs_hba *hba, u32 
> > attr_sel,
> >   EXPORT_SYMBOL_GPL(ufshcd_dme_xxx_get);
> >
> >   /**
> > + * ufshcd_dme_power_xxx - UIC command for DME_POWERON, DME_POWEROFF
> > + * @hba: per adapter instance
> > + * @on: indicate wherter power_on or power_off
> > + *
> > + * Returns 0 on success, non-zero value on failure
> > + */
> > +int ufshcd_dme_power_xxx(struct ufs_hba *hba, u8 on)
> Instead of "xxx" can we have meaningful name like "switch" or "toggle"?
It is just intended to express the standard's primitives name fully keeping 
intact.
For actual usage, this function is wrapped like the followings. 

static inline int ufshcd_dme_power_on(struct ufs_hba *hba)
{
return ufshcd_dme_power_xxx(hba, 1);
}

static inline int ufshcd_dme_power_off(struct ufs_hba *hba)
{
return ufshcd_dme_power_xxx(hba, 0);
}

> 
> > +{
> > +   struct uic_command uic_cmd = {0};
> > +   static const char *const action[] = {
> > +   "dme-power-off",
> > +   "dme-power-on"
> > +   };
> > +   const char *power = action[!!on];
> > +   int ret;
> > +
> > +   uic_cmd.command = on ?
> > +   UIC_CMD_DME_POWERON : UIC_CMD_DME_POWEROFF;
> > +
> > +   ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
> > +   if (ret)
> > +   dev_err(hba->dev, "%s: error code %d\n", power, ret);
> > +
> > +   return ret;
> > +}
> > +EXPORT_SYMBOL_GPL(ufshcd_dme_power_xxx);
> > +
> > +/**
> > + * ufshcd_dme_hibern8_xxx - UIC command for DME_HIBERNATE_ENTER,
> > + * DME_HIBERNATE_EXIT
> > + * @hba: per adapter instance
> > + * @enter: indicate wherter hibernation enter or exit
> > + *
> > + * Returns 0 on success, non-zero value on failure
> > + */
> > +int ufshcd_dme_hibern8_xxx(struct ufs_hba *hba, u8 enter)
> > +{
> > +   struct uic_command uic_cmd = {0};
> > +   static const char *const action[] = {
> > +   "dme-hibernate-exit",
> > +   "dme-hibernate-enter"
> > +   };
> > +   const char *hibern8 = action[!!enter];
> > +   u8 status;
> > +   int ret;
> > +
> > +   uic_cmd.command = enter ?
> > +   UIC_CMD_DME_HIBER_ENTER : UIC_CMD_DME_HIBER_EXIT;
> > +
> > +   mutex_lock(&hba->uic_cmd_mutex);
> > +   ret = __ufshcd_send_uic_cmd(hba, &uic_cmd);
> > +   if (ret) {
> > +   dev_err(hba->dev, "%s: error code %d\n", hibern8, ret);
> > +   got

[PATCH v3 1/6] scsi: ufs: wrap the i/o access operations

2013-05-05 Thread Seungwon Jeon
Simplify operations with hiding mmio_base.

Signed-off-by: Seungwon Jeon 
Tested-by: Maya Erez 
---
 drivers/scsi/ufs/ufshcd.c |  105 +++--
 drivers/scsi/ufs/ufshcd.h |7 +++-
 2 files changed, 50 insertions(+), 62 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index f244812..cf7c8e4 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -71,7 +71,7 @@ enum {
  */
 static inline u32 ufshcd_get_ufs_version(struct ufs_hba *hba)
 {
-   return readl(hba->mmio_base + REG_UFS_VERSION);
+   return ufshcd_readl(hba, REG_UFS_VERSION);
 }
 
 /**
@@ -130,8 +130,7 @@ static inline int ufshcd_get_tm_free_slot(struct ufs_hba 
*hba)
  */
 static inline void ufshcd_utrl_clear(struct ufs_hba *hba, u32 pos)
 {
-   writel(~(1 << pos),
-   (hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_CLEAR));
+   ufshcd_writel(hba, ~(1 << pos), REG_UTP_TRANSFER_REQ_LIST_CLEAR);
 }
 
 /**
@@ -165,7 +164,7 @@ static inline int ufshcd_get_lists_status(u32 reg)
  */
 static inline int ufshcd_get_uic_cmd_result(struct ufs_hba *hba)
 {
-   return readl(hba->mmio_base + REG_UIC_COMMAND_ARG_2) &
+   return ufshcd_readl(hba, REG_UIC_COMMAND_ARG_2) &
   MASK_UIC_COMMAND_RESULT;
 }
 
@@ -238,18 +237,15 @@ ufshcd_config_int_aggr(struct ufs_hba *hba, int option)
 {
switch (option) {
case INT_AGGR_RESET:
-   writel((INT_AGGR_ENABLE |
-   INT_AGGR_COUNTER_AND_TIMER_RESET),
-   (hba->mmio_base +
-REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL));
+   ufshcd_writel(hba, INT_AGGR_ENABLE |
+ INT_AGGR_COUNTER_AND_TIMER_RESET,
+ REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
break;
case INT_AGGR_CONFIG:
-   writel((INT_AGGR_ENABLE |
-   INT_AGGR_PARAM_WRITE |
-   INT_AGGR_COUNTER_THRESHOLD_VALUE |
-   INT_AGGR_TIMEOUT_VALUE),
-   (hba->mmio_base +
-REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL));
+   ufshcd_writel(hba, INT_AGGR_ENABLE | INT_AGGR_PARAM_WRITE |
+ INT_AGGR_COUNTER_THRESHOLD_VALUE |
+ INT_AGGR_TIMEOUT_VALUE,
+ REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
break;
}
 }
@@ -262,12 +258,10 @@ ufshcd_config_int_aggr(struct ufs_hba *hba, int option)
  */
 static void ufshcd_enable_run_stop_reg(struct ufs_hba *hba)
 {
-   writel(UTP_TASK_REQ_LIST_RUN_STOP_BIT,
-  (hba->mmio_base +
-   REG_UTP_TASK_REQ_LIST_RUN_STOP));
-   writel(UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT,
-  (hba->mmio_base +
-   REG_UTP_TRANSFER_REQ_LIST_RUN_STOP));
+   ufshcd_writel(hba, UTP_TASK_REQ_LIST_RUN_STOP_BIT,
+ REG_UTP_TASK_REQ_LIST_RUN_STOP);
+   ufshcd_writel(hba, UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT,
+ REG_UTP_TRANSFER_REQ_LIST_RUN_STOP);
 }
 
 /**
@@ -276,7 +270,7 @@ static void ufshcd_enable_run_stop_reg(struct ufs_hba *hba)
  */
 static inline void ufshcd_hba_start(struct ufs_hba *hba)
 {
-   writel(CONTROLLER_ENABLE , (hba->mmio_base + REG_CONTROLLER_ENABLE));
+   ufshcd_writel(hba, CONTROLLER_ENABLE, REG_CONTROLLER_ENABLE);
 }
 
 /**
@@ -287,7 +281,7 @@ static inline void ufshcd_hba_start(struct ufs_hba *hba)
  */
 static inline int ufshcd_is_hba_active(struct ufs_hba *hba)
 {
-   return (readl(hba->mmio_base + REG_CONTROLLER_ENABLE) & 0x1) ? 0 : 1;
+   return (ufshcd_readl(hba, REG_CONTROLLER_ENABLE) & 0x1) ? 0 : 1;
 }
 
 /**
@@ -299,8 +293,7 @@ static inline
 void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag)
 {
__set_bit(task_tag, &hba->outstanding_reqs);
-   writel((1 << task_tag),
-  (hba->mmio_base + REG_UTP_TRANSFER_REQ_DOOR_BELL));
+   ufshcd_writel(hba, 1 << task_tag, REG_UTP_TRANSFER_REQ_DOOR_BELL);
 }
 
 /**
@@ -381,8 +374,7 @@ void ufshcd_copy_query_response(struct ufs_hba *hba, struct 
ufshcd_lrb *lrbp)
  */
 static inline void ufshcd_hba_capabilities(struct ufs_hba *hba)
 {
-   hba->capabilities =
-   readl(hba->mmio_base + REG_CONTROLLER_CAPABILITIES);
+   hba->capabilities = ufshcd_readl(hba, REG_CONTROLLER_CAPABILITIES);
 
/* nutrs and nutmrs are 0 based values */
hba->nutrs = (hba->capabilities & MASK_TRANSFER_REQUESTS_SLOTS) + 1;
@@ -399,16 +391,13 @@ static inline void
 ufshcd_send_uic_command(struct ufs_hba *hba, struct uic_command *uic_cmnd)
 {
/* Write Args */
-   writel(uic_cmnd->argument1,
- (hba->mmio_base + REG_UIC_COMMAND_ARG_1));
-   writel(uic_cmnd->argument2,
- (hba->mmio_base + REG_UI

[PATCH v3 2/6] scsi: ufs: amend interrupt configuration

2013-05-05 Thread Seungwon Jeon
It makes interrupt setting more flexible especially
for disabling. And wrong bit mask is fixed for ver 1.0.
[17:16] is added for mask.

Signed-off-by: Seungwon Jeon 
Tested-by: Maya Erez 
---
 drivers/scsi/ufs/ufshcd.c |   84 +++-
 drivers/scsi/ufs/ufshcd.h |4 +-
 drivers/scsi/ufs/ufshci.h |5 ++-
 3 files changed, 64 insertions(+), 29 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index cf7c8e4..feaf221 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -35,6 +35,10 @@
 
 #include "ufshcd.h"
 
+#define UFSHCD_ENABLE_INTRS(UTP_TRANSFER_REQ_COMPL |\
+UTP_TASK_REQ_COMPL |\
+UFSHCD_ERROR_MASK)
+
 enum {
UFSHCD_MAX_CHANNEL  = 0,
UFSHCD_MAX_ID   = 1,
@@ -64,6 +68,20 @@ enum {
 };
 
 /**
+ * ufshcd_get_intr_mask - Get the interrupt bit mask
+ * @hba - Pointer to adapter instance
+ *
+ * Returns interrupt bit mask per version
+ */
+static inline u32 ufshcd_get_intr_mask(struct ufs_hba *hba)
+{
+   if (hba->ufs_version == UFSHCI_VERSION_10)
+   return INTERRUPT_MASK_ALL_VER_10;
+   else
+   return INTERRUPT_MASK_ALL_VER_11;
+}
+
+/**
  * ufshcd_get_ufs_version - Get the UFS version supported by the HBA
  * @hba - Pointer to adapter instance
  *
@@ -441,25 +459,45 @@ static int ufshcd_map_sg(struct ufshcd_lrb *lrbp)
 }
 
 /**
- * ufshcd_int_config - enable/disable interrupts
+ * ufshcd_enable_intr - enable interrupts
  * @hba: per adapter instance
- * @option: interrupt option
+ * @intrs: interrupt bits
  */
-static void ufshcd_int_config(struct ufs_hba *hba, u32 option)
+static void ufshcd_enable_intr(struct ufs_hba *hba, u32 intrs)
 {
-   switch (option) {
-   case UFSHCD_INT_ENABLE:
-   ufshcd_writel(hba, hba->int_enable_mask, REG_INTERRUPT_ENABLE);
-   break;
-   case UFSHCD_INT_DISABLE:
-   if (hba->ufs_version == UFSHCI_VERSION_10)
-   ufshcd_writel(hba, INTERRUPT_DISABLE_MASK_10,
- REG_INTERRUPT_ENABLE);
-   else
-   ufshcd_writel(hba, INTERRUPT_DISABLE_MASK_11,
- REG_INTERRUPT_ENABLE);
-   break;
+   u32 set = ufshcd_readl(hba, REG_INTERRUPT_ENABLE);
+
+   if (hba->ufs_version == UFSHCI_VERSION_10) {
+   u32 rw;
+   rw = set & INTERRUPT_MASK_RW_VER_10;
+   set = rw | ((set ^ intrs) & intrs);
+   } else {
+   set |= intrs;
+   }
+
+   ufshcd_writel(hba, set, REG_INTERRUPT_ENABLE);
+}
+
+/**
+ * ufshcd_disable_intr - disable interrupts
+ * @hba: per adapter instance
+ * @intrs: interrupt bits
+ */
+static void ufshcd_disable_intr(struct ufs_hba *hba, u32 intrs)
+{
+   u32 set = ufshcd_readl(hba, REG_INTERRUPT_ENABLE);
+
+   if (hba->ufs_version == UFSHCI_VERSION_10) {
+   u32 rw;
+   rw = (set & INTERRUPT_MASK_RW_VER_10) &
+   ~(intrs & INTERRUPT_MASK_RW_VER_10);
+   set = rw | ((set & intrs) & ~INTERRUPT_MASK_RW_VER_10);
+
+   } else {
+   set &= ~intrs;
}
+
+   ufshcd_writel(hba, set, REG_INTERRUPT_ENABLE);
 }
 
 /**
@@ -946,8 +984,7 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba)
uic_cmd->argument3 = 0;
 
/* enable UIC related interrupts */
-   hba->int_enable_mask |= UIC_COMMAND_COMPL;
-   ufshcd_int_config(hba, UFSHCD_INT_ENABLE);
+   ufshcd_enable_intr(hba, UIC_COMMAND_COMPL);
 
/* sending UIC commands to controller */
ufshcd_send_uic_command(hba, uic_cmd);
@@ -994,13 +1031,7 @@ static int ufshcd_make_hba_operational(struct ufs_hba 
*hba)
}
 
/* Enable required interrupts */
-   hba->int_enable_mask |= (UTP_TRANSFER_REQ_COMPL |
-UIC_ERROR |
-UTP_TASK_REQ_COMPL |
-DEVICE_FATAL_ERROR |
-CONTROLLER_FATAL_ERROR |
-SYSTEM_BUS_FATAL_ERROR);
-   ufshcd_int_config(hba, UFSHCD_INT_ENABLE);
+   ufshcd_enable_intr(hba, UFSHCD_ENABLE_INTRS);
 
/* Configure interrupt aggregation */
ufshcd_config_int_aggr(hba, INT_AGGR_CONFIG);
@@ -1828,7 +1859,7 @@ static void ufshcd_hba_free(struct ufs_hba *hba)
 void ufshcd_remove(struct ufs_hba *hba)
 {
/* disable interrupts */
-   ufshcd_int_config(hba, UFSHCD_INT_DISABLE);
+   ufshcd_disable_intr(hba, hba->intr_mask);
 
ufshcd_hba_stop(hba);
ufshcd_hba_free(hba);
@@ -1886,6 +1917,9 @@ int ufshcd_init(struct device *dev, struct ufs_hba 
**hba_handle,
/* Get UFS version supported by the controller */
hba->ufs_version = ufshcd_get_ufs_vers

[PATCH v3 3/6] scsi: ufs: fix interrupt status clears

2013-05-05 Thread Seungwon Jeon
There is no need to check the version to clear
the interrupt status. And the order is changed
prior to actual handling.

Signed-off-by: Seungwon Jeon 
---
 drivers/scsi/ufs/ufshcd.c |5 +
 1 files changed, 1 insertions(+), 4 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index feaf221..e04c74e 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -1582,11 +1582,8 @@ static irqreturn_t ufshcd_intr(int irq, void *__hba)
intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
 
if (intr_status) {
+   ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
ufshcd_sl_intr(hba, intr_status);
-
-   /* If UFSHCI 1.0 then clear interrupt status register */
-   if (hba->ufs_version == UFSHCI_VERSION_10)
-   ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
retval = IRQ_HANDLED;
}
spin_unlock(hba->host->host_lock);
-- 
1.7.0.4


--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v3 5/6] scsi: ufs: add dme configuration primitives

2013-05-05 Thread Seungwon Jeon
Implements to support Get and Set operation of the DME.
And along with these operations, IDs of Attribute are added.
It is used to configure the behavior of the UNIPRO.

Signed-off-by: Seungwon Jeon 
---
 drivers/scsi/ufs/ufshcd.c |   84 +
 drivers/scsi/ufs/ufshcd.h |   30 ++
 drivers/scsi/ufs/ufshci.h |4 ++
 drivers/scsi/ufs/unipro.h |  130 +
 4 files changed, 248 insertions(+), 0 deletions(-)
 create mode 100644 drivers/scsi/ufs/unipro.h

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 118f104..aa06210 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -191,6 +191,18 @@ static inline int ufshcd_get_uic_cmd_result(struct ufs_hba 
*hba)
 }
 
 /**
+ * ufshcd_get_dme_attr_val - Get the value of attribute returned by UIC command
+ * @hba: Pointer to adapter instance
+ *
+ * This function gets UIC command argument3
+ * Returns 0 on success, non zero value on error
+ */
+static inline u32 ufshcd_get_dme_attr_val(struct ufs_hba *hba)
+{
+   return ufshcd_readl(hba, REG_UIC_COMMAND_ARG_3);
+}
+
+/**
  * ufshcd_free_hba_memory - Free allocated memory for LRB, request
  * and task lists
  * @hba: Pointer to adapter instance
@@ -1070,6 +1082,76 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba)
 }
 
 /**
+ * ufshcd_dme_xxx_set - UIC command for DME_SET, DME_PEER_SET
+ * @hba: per adapter instance
+ * @attr_sel: uic command argument1
+ * @attr_set: attribute set type as uic command argument2
+ * @mib_val: setting value as uic command argument3
+ * @peer: indicate wherter peer or non-peer
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+int ufshcd_dme_xxx_set(struct ufs_hba *hba, u32 attr_sel,
+  u8 attr_set, u32 mib_val, u8 peer)
+{
+   struct uic_command uic_cmd = {0};
+   static const char *const action[] = {
+   "dme-set",
+   "dme-peer-set"
+   };
+   const char *set = action[!!peer];
+   int ret;
+
+   uic_cmd.command = peer ?
+   UIC_CMD_DME_PEER_SET : UIC_CMD_DME_SET;
+   uic_cmd.argument1 = attr_sel;
+   uic_cmd.argument2 = UIC_ARG_ATTR_SET(attr_set);
+   uic_cmd.argument3 = mib_val;
+
+   ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
+
+   dev_dbg(hba->dev, "%s: error code %d\n", set, ret);
+
+   return ret;
+}
+EXPORT_SYMBOL_GPL(ufshcd_dme_xxx_set);
+
+/**
+ * ufshcd_dme_xxx_get - UIC command for DME_GET, DME_PEER_GET
+ * @hba: per adapter instance
+ * @attr_sel: uic command argument1
+ * @mib_val: the value of the attribute as returned by the UIC command
+ * @peer: indicate wherter peer or non-peer
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+int ufshcd_dme_xxx_get(struct ufs_hba *hba, u32 attr_sel,
+  u32 *mib_val, u8 peer)
+{
+   struct uic_command uic_cmd = {0};
+   static const char *const action[] = {
+   "dme-get",
+   "dme-peer-get"
+   };
+   const char *get = action[!!peer];
+   int ret;
+
+   uic_cmd.command = peer ?
+   UIC_CMD_DME_PEER_GET : UIC_CMD_DME_GET;
+   uic_cmd.argument1 = attr_sel;
+
+   ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
+
+   if (mib_val)
+   *mib_val = uic_cmd.argument3;
+
+   dev_dbg(hba->dev, "%s: error code %d\n", get, ret);
+
+   return ret;
+}
+EXPORT_SYMBOL_GPL(ufshcd_dme_xxx_get);
+
+/**
  * ufshcd_make_hba_operational - Make UFS controller operational
  * @hba: per adapter instance
  *
@@ -1531,6 +1613,8 @@ static void ufshcd_uic_cmd_compl(struct ufs_hba *hba)
 {
hba->active_uic_cmd->argument2 |=
ufshcd_get_uic_cmd_result(hba);
+   hba->active_uic_cmd->argument3 =
+   ufshcd_get_dme_attr_val(hba);
complete(&hba->active_uic_cmd->done);
 }
 
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 974bd07..93965b9 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -217,6 +217,11 @@ int ufshcd_init(struct device *, struct ufs_hba ** , void 
__iomem * ,
unsigned int);
 void ufshcd_remove(struct ufs_hba *);
 
+extern int ufshcd_dme_xxx_set(struct ufs_hba *hba, u32 attr_sel,
+ u8 attr_set, u32 mib_val, u8 peer);
+extern int ufshcd_dme_xxx_get(struct ufs_hba *hba, u32 attr_sel,
+ u32 *mib_val, u8 peer);
+
 /**
  * ufshcd_hba_stop - Send controller to reset state
  * @hba: per adapter instance
@@ -226,4 +231,29 @@ static inline void ufshcd_hba_stop(struct ufs_hba *hba)
ufshcd_writel(hba, CONTROLLER_DISABLE,  REG_CONTROLLER_ENABLE);
 }
 
+/* UIC command interfaces for DME primitives */
+static inline int ufshcd_dme_set(struct ufs_hba *hba, u32 attr_sel,
+u8 attr_set, u32 

[PATCH v3 4/6] scsi: ufs: rework link start-up process

2013-05-05 Thread Seungwon Jeon
Link start-up requires long time with multiphase handshakes
between UFS host and device. This affects driver's probe time.
This patch let link start-up run asynchronously. Link start-up
will be executed at the end of prove separately.
Along with this change, the following is worked.

Defined completion time of uic command to avoid a permanent wait.
Added mutex to guarantee of uic command at a time.
Adapted some sequence of controller initialization after link statup
according to HCI standard.

Signed-off-by: Seungwon Jeon 
Signed-off-by: Sujit Reddy Thumma 
---
 drivers/scsi/ufs/ufshcd.c |  287 ++---
 drivers/scsi/ufs/ufshcd.h |   10 +-
 2 files changed, 200 insertions(+), 97 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index e04c74e..118f104 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -33,11 +33,15 @@
  * this program.
  */
 
+#include 
+
 #include "ufshcd.h"
 
 #define UFSHCD_ENABLE_INTRS(UTP_TRANSFER_REQ_COMPL |\
 UTP_TASK_REQ_COMPL |\
 UFSHCD_ERROR_MASK)
+/* UIC command timeout, unit: ms */
+#define UIC_CMD_TIMEOUT500
 
 enum {
UFSHCD_MAX_CHANNEL  = 0,
@@ -401,24 +405,115 @@ static inline void ufshcd_hba_capabilities(struct 
ufs_hba *hba)
 }
 
 /**
- * ufshcd_send_uic_command - Send UIC commands to unipro layers
+ * ufshcd_ready_for_uic_cmd - Check if controller is ready
+ *to accept UIC commands
  * @hba: per adapter instance
- * @uic_command: UIC command
+ * Return true on success, else false
+ */
+static inline bool ufshcd_ready_for_uic_cmd(struct ufs_hba *hba)
+{
+   if (ufshcd_readl(hba, REG_CONTROLLER_STATUS) & UIC_COMMAND_READY)
+   return true;
+   else
+   return false;
+}
+
+/**
+ * ufshcd_dispatch_uic_cmd - Dispatch UIC commands to unipro layers
+ * @hba: per adapter instance
+ * @uic_cmd: UIC command
+ *
+ * Mutex must be held.
  */
 static inline void
-ufshcd_send_uic_command(struct ufs_hba *hba, struct uic_command *uic_cmnd)
+ufshcd_dispatch_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
 {
+   hba->active_uic_cmd = uic_cmd;
+
/* Write Args */
-   ufshcd_writel(hba, uic_cmnd->argument1, REG_UIC_COMMAND_ARG_1);
-   ufshcd_writel(hba, uic_cmnd->argument2, REG_UIC_COMMAND_ARG_2);
-   ufshcd_writel(hba, uic_cmnd->argument3, REG_UIC_COMMAND_ARG_3);
+   ufshcd_writel(hba, uic_cmd->argument1, REG_UIC_COMMAND_ARG_1);
+   ufshcd_writel(hba, uic_cmd->argument2, REG_UIC_COMMAND_ARG_2);
+   ufshcd_writel(hba, uic_cmd->argument3, REG_UIC_COMMAND_ARG_3);
 
/* Write UIC Cmd */
-   ufshcd_writel(hba, uic_cmnd->command & COMMAND_OPCODE_MASK,
+   ufshcd_writel(hba, uic_cmd->command & COMMAND_OPCODE_MASK,
  REG_UIC_COMMAND);
 }
 
 /**
+ * ufshcd_wait_for_uic_cmd - Wait complectioin of UIC command
+ * @hba: per adapter instance
+ * @uic_command: UIC command
+ *
+ * Must be called with mutex held.
+ * Returns 0 only if success.
+ */
+static int
+ufshcd_wait_for_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
+{
+   int ret;
+
+   if (wait_for_completion_timeout(&uic_cmd->done,
+   msecs_to_jiffies(UIC_CMD_TIMEOUT)))
+   ret = uic_cmd->argument2 & MASK_UIC_COMMAND_RESULT;
+   else
+   ret = -ETIMEDOUT;
+
+   return ret;
+}
+
+/**
+ * __ufshcd_send_uic_cmd - Send UIC commands and retrieve the result
+ * @hba: per adapter instance
+ * @uic_cmd: UIC command
+ *
+ * Identical to ufshcd_send_uic_cmd() expect mutex. Must be called
+ * with mutex held.
+ * Returns 0 only if success.
+ */
+static int
+__ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
+{
+   int ret;
+   unsigned long flags;
+
+   if (!ufshcd_ready_for_uic_cmd(hba)) {
+   dev_err(hba->dev,
+   "Controller not ready to accept UIC commands\n");
+   return -EIO;
+   }
+
+   init_completion(&uic_cmd->done);
+
+   spin_lock_irqsave(hba->host->host_lock, flags);
+   ufshcd_dispatch_uic_cmd(hba, uic_cmd);
+   spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+   ret = ufshcd_wait_for_uic_cmd(hba, uic_cmd);
+
+   return ret;
+}
+
+/**
+ * ufshcd_send_uic_cmd - Send UIC commands and retrieve the result
+ * @hba: per adapter instance
+ * @uic_cmd: UIC command
+ *
+ * Returns 0 only if success.
+ */
+static int
+ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
+{
+   int ret;
+
+   mutex_lock(&hba->uic_cmd_mutex);
+   ret = __ufshcd_send_uic_cmd(hba, uic_cmd);
+   mutex_unlock(&hba->uic_cmd_mutex);
+
+   return ret;
+}
+
+/**
  * ufshcd_map_sg - Map scatter-gather list to prdt
  * @

[PATCH v3 6/6] scsi: ufs: add dme control primitives

2013-05-05 Thread Seungwon Jeon
Implements to support the following operations.
Currently, this patch doesn't introduce DME_ENABLE and DME_RESET
because host controller's HCE enable contains these roles.

DME_POWERON{OFF}, DME_HIBERNATE_ENTER{EXIT}, DME_ENDPOINTRESET.

Signed-off-by: Seungwon Jeon 
---
 drivers/scsi/ufs/ufshcd.c |  132 ++---
 drivers/scsi/ufs/ufshcd.h |   26 +
 drivers/scsi/ufs/ufshci.h |   15 +
 3 files changed, 165 insertions(+), 8 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index aa06210..3607ffb 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -39,6 +39,7 @@
 
 #define UFSHCD_ENABLE_INTRS(UTP_TRANSFER_REQ_COMPL |\
 UTP_TASK_REQ_COMPL |\
+UFSHCD_HIBERNATE_MASK |\
 UFSHCD_ERROR_MASK)
 /* UIC command timeout, unit: ms */
 #define UIC_CMD_TIMEOUT500
@@ -203,6 +204,18 @@ static inline u32 ufshcd_get_dme_attr_val(struct ufs_hba 
*hba)
 }
 
 /**
+ * ufshcd_get_upmcrs - Get the power mode change request status
+ * @hba: Pointer to adapter instance
+ *
+ * This function gets the UPMCRS field of HCS register
+ * Returns value of UPMCRS field
+ */
+static inline u8 ufshcd_get_upmcrs(struct ufs_hba *hba)
+{
+   return (ufshcd_readl(hba, REG_CONTROLLER_STATUS) >> 8) & 0x7;
+}
+
+/**
  * ufshcd_free_hba_memory - Free allocated memory for LRB, request
  * and task lists
  * @hba: Pointer to adapter instance
@@ -1152,6 +1165,103 @@ int ufshcd_dme_xxx_get(struct ufs_hba *hba, u32 
attr_sel,
 EXPORT_SYMBOL_GPL(ufshcd_dme_xxx_get);
 
 /**
+ * ufshcd_dme_power_xxx - UIC command for DME_POWERON, DME_POWEROFF
+ * @hba: per adapter instance
+ * @on: indicate wherter power_on or power_off
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+int ufshcd_dme_power_xxx(struct ufs_hba *hba, u8 on)
+{
+   struct uic_command uic_cmd = {0};
+   static const char *const action[] = {
+   "dme-power-off",
+   "dme-power-on"
+   };
+   const char *power = action[!!on];
+   int ret;
+
+   uic_cmd.command = on ?
+   UIC_CMD_DME_POWERON : UIC_CMD_DME_POWEROFF;
+
+   ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
+   if (ret)
+   dev_err(hba->dev, "%s: error code %d\n", power, ret);
+
+   return ret;
+}
+EXPORT_SYMBOL_GPL(ufshcd_dme_power_xxx);
+
+/**
+ * ufshcd_dme_hibern8_xxx - UIC command for DME_HIBERNATE_ENTER,
+ * DME_HIBERNATE_EXIT
+ * @hba: per adapter instance
+ * @enter: indicate wherter hibernation enter or exit
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+int ufshcd_dme_hibern8_xxx(struct ufs_hba *hba, u8 enter)
+{
+   struct uic_command uic_cmd = {0};
+   static const char *const action[] = {
+   "dme-hibernate-exit",
+   "dme-hibernate-enter"
+   };
+   const char *hibern8 = action[!!enter];
+   u8 status;
+   int ret;
+
+   uic_cmd.command = enter ?
+   UIC_CMD_DME_HIBER_ENTER : UIC_CMD_DME_HIBER_EXIT;
+
+   mutex_lock(&hba->uic_cmd_mutex);
+   init_completion(&hba->hibern8_done);
+   ret = __ufshcd_send_uic_cmd(hba, &uic_cmd);
+   if (ret) {
+   dev_err(hba->dev, "%s: error code %d\n", hibern8, ret);
+   goto out;
+   }
+
+   if (wait_for_completion_timeout(&hba->hibern8_done,
+   msecs_to_jiffies(UIC_CMD_TIMEOUT))) {
+   status = ufshcd_get_upmcrs(hba);
+   if (status != PWR_LOCAL) {
+   dev_err(hba->dev, "%s: failed, host upmcrs:%x\n",
+   hibern8, status);
+   ret = status;
+   }
+   } else {
+   dev_err(hba->dev, "%s: timeout\n", hibern8);
+   ret = -ETIMEDOUT;
+   }
+out:
+   mutex_unlock(&hba->uic_cmd_mutex);
+   return ret;
+}
+EXPORT_SYMBOL_GPL(ufshcd_dme_hibern8_xxx);
+
+/**
+ * ufshcd_dme_endpt_reset - UIC command for DME_ENDPOINTRESET
+ * @hba: per adapter instance
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+int ufshcd_dme_endpt_reset(struct ufs_hba *hba)
+{
+   struct uic_command uic_cmd = {0};
+   int ret;
+
+   uic_cmd.command = UIC_CMD_DME_END_PT_RST;
+
+   ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
+   if (ret)
+   dev_err(hba->dev, "endpoint reset: error code %d\n", ret);
+
+   return ret;
+}
+EXPORT_SYMBOL_GPL(ufshcd_dme_endpt_reset);
+
+/**
  * ufshcd_make_hba_operational - Make UFS controller operational
  * @hba: per adapter instance
  *
@@ -1608,14 +1718,20 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct 
ufshcd_lrb *lrbp)
 /**
  * uf

RE: [PATCH v3 4/6] scsi: ufs: rework link start-up process

2013-05-06 Thread Seungwon Jeon
On Monday, May 06, 2013, Sujit Reddy Thumma wrote:
> On 5/6/2013 11:07 AM, Seungwon Jeon wrote:
> > Link start-up requires long time with multiphase handshakes
> > between UFS host and device. This affects driver's probe time.
> > This patch let link start-up run asynchronously. Link start-up
> > will be executed at the end of prove separately.
> > Along with this change, the following is worked.
> >
> > Defined completion time of uic command to avoid a permanent wait.
> We have seen a kernel crash when the timeout happens in our internal
> testing. This is basically because the the UIC_CMD_TIMEOUT of 500msec is
> less for our platform. We see UIC_COMMAND_COMPL interrupt after this
> timeout and since uic_cmd is freed we see a kernel crash.
> 
> [6.026094] ufshcd :01:00.0: link startup: error code -110
> [6.030886] ufshcd :01:00.0: link startup failed -110
> ...
> 
> [6.487288] BUG: spinlock bad magic on CPU#0, swapper/0/0
> [6.491683] Unable to handle kernel paging request at virtual address
> 612b
> ...
> [7.625270] [] (spin_dump+0x4c/0x88) from []
> (do_raw_spin_lock+0x20/0x154)
> [7.633877] [] (do_raw_spin_lock+0x20/0x154) from
> [] (_raw_spin_lock_irqsave+0x28/0x30)
> [7.643583] [] (_raw_spin_lock_irqsave+0x28/0x30) from
> [] (complete+0x1c/0x58)
> [7.652525] [] (complete+0x1c/0x58) from []
> (ufshcd_intr+0x1a8/0x498)
> [7.660705] [] (ufshcd_intr+0x1a8/0x498) from []
> (handle_irq_event_percpu+0xb0/0x290)
> [7.670227] [] (handle_irq_event_percpu+0xb0/0x290) from
> [] (handle_irq_event+0x3c/0x5c)
> [7.680054] [] (handle_irq_event+0x3c/0x5c) from
> [] (handle_fasteoi_irq+0xdc/0x148)
> [7.689424] [] (handle_fasteoi_irq+0xdc/0x148) from
> [] (generic_handle_irq+0x30/0x44)
> [7.698977] [] (generic_handle_irq+0x30/0x44) from
> [] (handle_IRQ+0x7c/0xc0)
> [7.707736] [] (handle_IRQ+0x7c/0xc0) from []
> (gic_handle_irq+0x94/0x110)
> [7.716252] [] (gic_handle_irq+0x94/0x110) from
> [] (__irq_svc+0x40/0x70)
> 
> 
> Following would fix this. Please check. Also, we need to increase the
> timeout to say 5 secs to avoid such races.
Thank you for test.
I have seen the completion of link startup within current timeout ever.
It should be fixed for that case.
By the way, I feel 5 seconds looks like a little too long.
Currently, is your platform situation with UFS in normal stage?
The UNIPRO spec. mentions the 100 ms as timeout internally for link startup.
Anyway, do you mean that you want to change timeout value to 5 seconds?
I think it has a strong dependency with your platform.
1 sec seems proper though the worst case is considered.

Thanks,
Seungwon Jeon

> 
> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> index ecbae40..ae22a8e 100644
> --- a/drivers/scsi/ufs/ufshcd.c
> +++ b/drivers/scsi/ufs/ufshcd.c
> @@ -485,6 +485,7 @@ static int
>  ufshcd_wait_for_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
>  {
>   int ret;
> + unsigned long flags;
> 
>   if (wait_for_completion_timeout(&uic_cmd->done,
>   msecs_to_jiffies(UIC_CMD_TIMEOUT)))
> @@ -492,6 +493,10 @@ ufshcd_wait_for_uic_cmd(struct ufs_hba *hba, struct
> uic_command *uic_cmd)
>   else
>   ret = -ETIMEDOUT;
> 
> + spin_lock_irqsave(hba->host->host_lock, flags);
> + hba->active_uic_cmd = NULL;
> + spin_unlock_irqrestore(hba->host->host_lock, flags);
> +
>   return ret;
>  }
> 
> @@ -1842,7 +1847,7 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba,
> struct ufshcd_lrb *lrbp)
>   */
>  static void ufshcd_uic_cmd_compl(struct ufs_hba *hba, u32 intr_status)
>  {
> - if (intr_status & UIC_COMMAND_COMPL) {
> + if (hba->active_uic_cmd && (intr_status & UIC_COMMAND_COMPL)) {
>   hba->active_uic_cmd->argument2 |=
>   ufshcd_get_uic_cmd_result(hba);
>   hba->active_uic_cmd->argument3 =
> 
> 
> > Added mutex to guarantee of uic command at a time.
> > Adapted some sequence of controller initialization after link statup
> > according to HCI standard.
> >
> > Signed-off-by: Seungwon Jeon 
> > Signed-off-by: Sujit Reddy Thumma 
> > ---
> >   drivers/scsi/ufs/ufshcd.c |  287 
> > ++---
> >   drivers/scsi/ufs/ufshcd.h |   10 +-
> >   2 files changed, 200 insertions(+), 97 deletions(-)
> >
> > diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> > index e04c74e..118f104 100644
> > --- a/drivers/scsi/ufs/ufshcd.c
> > +++ b/drivers/scsi/ufs/ufshcd.c
> > @@ -33,11 +33

RE: [PATCH v3 6/6] scsi: ufs: add dme control primitives

2013-05-06 Thread Seungwon Jeon
On Tuesday, May 07, 2013, Santosh Y wrote:
> >  /**
> > + * ufshcd_dme_power_xxx - UIC command for DME_POWERON, DME_POWEROFF
> > + * @hba: per adapter instance
> > + * @on: indicate wherter power_on or power_off
> > + *
> > + * Returns 0 on success, non-zero value on failure
> > + */
> > +int ufshcd_dme_power_xxx(struct ufs_hba *hba, u8 on)
> > +{
> > +   struct uic_command uic_cmd = {0};
> > +   static const char *const action[] = {
> > +   "dme-power-off",
> > +   "dme-power-on"
> > +   };
> > +   const char *power = action[!!on];
> > +   int ret;
> > +
> > +   uic_cmd.command = on ?
> > +   UIC_CMD_DME_POWERON : UIC_CMD_DME_POWEROFF;
> > +
> > +   ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
> > +   if (ret)
> > +   dev_err(hba->dev, "%s: error code %d\n", power, ret);
> > +
> > +   return ret;
> > +}
> > +EXPORT_SYMBOL_GPL(ufshcd_dme_power_xxx);
> > +
> > +/**
> > + * ufshcd_dme_hibern8_xxx - UIC command for DME_HIBERNATE_ENTER,
> > + * DME_HIBERNATE_EXIT
> > + * @hba: per adapter instance
> > + * @enter: indicate wherter hibernation enter or exit
> > + *
> > + * Returns 0 on success, non-zero value on failure
> > + */
> > +int ufshcd_dme_hibern8_xxx(struct ufs_hba *hba, u8 enter)
> > +{
> > +   struct uic_command uic_cmd = {0};
> > +   static const char *const action[] = {
> > +   "dme-hibernate-exit",
> > +   "dme-hibernate-enter"
> > +   };
> > +   const char *hibern8 = action[!!enter];
> > +   u8 status;
> > +   int ret;
> > +
> > +   uic_cmd.command = enter ?
> > +   UIC_CMD_DME_HIBER_ENTER : UIC_CMD_DME_HIBER_EXIT;
> > +
> > +   mutex_lock(&hba->uic_cmd_mutex);
> > +   init_completion(&hba->hibern8_done);
> > +   ret = __ufshcd_send_uic_cmd(hba, &uic_cmd);
> > +   if (ret) {
> > +   dev_err(hba->dev, "%s: error code %d\n", hibern8, ret);
> > +   goto out;
> > +   }
> > +
> > +   if (wait_for_completion_timeout(&hba->hibern8_done,
> > +   msecs_to_jiffies(UIC_CMD_TIMEOUT))) 
> > {
> > +   status = ufshcd_get_upmcrs(hba);
> > +   if (status != PWR_LOCAL) {
> > +   dev_err(hba->dev, "%s: failed, host upmcrs:%x\n",
> > +   hibern8, status);
> > +   ret = status;
> > +   }
> > +   } else {
> > +       dev_err(hba->dev, "%s: timeout\n", hibern8);
> > +   ret = -ETIMEDOUT;
> > +   }
> > +out:
> > +   mutex_unlock(&hba->uic_cmd_mutex);
> > +   return ret;
> > +}
> > +EXPORT_SYMBOL_GPL(ufshcd_dme_hibern8_xxx);
> > +
> 
> 
> power/hibernate functions can also be renamed as
> ufshcd_dme_power/hibernate_config(struct ufs_hba *hba, bool
> enable/enter) or similar instead of xxx.
Ok, I'll change the names including dme_get/set.
If you have further views, please let me know.

Thanks,
Seungwon Jeon

> 
> 
> --
> ~Santosh
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majord...@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: [PATCH v3 1/6] scsi: ufs: wrap the i/o access operations

2013-05-06 Thread Seungwon Jeon
On Tuesday, May 07, 2013, Santosh Y wrote:
> On Mon, May 6, 2013 at 11:07 AM, Seungwon Jeon  wrote:
> > Simplify operations with hiding mmio_base.
> >
> > Signed-off-by: Seungwon Jeon 
> > Tested-by: Maya Erez 
> > ---
> >  drivers/scsi/ufs/ufshcd.c |  105 
> > +++--
> >  drivers/scsi/ufs/ufshcd.h |7 +++-
> >  2 files changed, 50 insertions(+), 62 deletions(-)
> >
> > diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> > index f244812..cf7c8e4 100644
> > --- a/drivers/scsi/ufs/ufshcd.c
> > +++ b/drivers/scsi/ufs/ufshcd.c
> > @@ -71,7 +71,7 @@ enum {
> >   */
> >  static inline u32 ufshcd_get_ufs_version(struct ufs_hba *hba)
> >  {
> > -   return readl(hba->mmio_base + REG_UFS_VERSION);
> > +   return ufshcd_readl(hba, REG_UFS_VERSION);
> >  }
> >
> >  /**
> > @@ -130,8 +130,7 @@ static inline int ufshcd_get_tm_free_slot(struct 
> > ufs_hba *hba)
> >   */
> >  static inline void ufshcd_utrl_clear(struct ufs_hba *hba, u32 pos)
> >  {
> > -   writel(~(1 << pos),
> > -   (hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_CLEAR));
> > +   ufshcd_writel(hba, ~(1 << pos), REG_UTP_TRANSFER_REQ_LIST_CLEAR);
> >  }
> >
> >  /**
> > @@ -165,7 +164,7 @@ static inline int ufshcd_get_lists_status(u32 reg)
> >   */
> >  static inline int ufshcd_get_uic_cmd_result(struct ufs_hba *hba)
> >  {
> > -   return readl(hba->mmio_base + REG_UIC_COMMAND_ARG_2) &
> > +   return ufshcd_readl(hba, REG_UIC_COMMAND_ARG_2) &
> >MASK_UIC_COMMAND_RESULT;
> >  }
> >
> > @@ -238,18 +237,15 @@ ufshcd_config_int_aggr(struct ufs_hba *hba, int 
> > option)
> >  {
> > switch (option) {
> > case INT_AGGR_RESET:
> > -   writel((INT_AGGR_ENABLE |
> > -   INT_AGGR_COUNTER_AND_TIMER_RESET),
> > -   (hba->mmio_base +
> > -REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL));
> > +   ufshcd_writel(hba, INT_AGGR_ENABLE |
> > + INT_AGGR_COUNTER_AND_TIMER_RESET,
> > + REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
> > break;
> > case INT_AGGR_CONFIG:
> > -   writel((INT_AGGR_ENABLE |
> > -   INT_AGGR_PARAM_WRITE |
> > -   INT_AGGR_COUNTER_THRESHOLD_VALUE |
> > -   INT_AGGR_TIMEOUT_VALUE),
> > -   (hba->mmio_base +
> > -REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL));
> > +   ufshcd_writel(hba, INT_AGGR_ENABLE | INT_AGGR_PARAM_WRITE |
> > + INT_AGGR_COUNTER_THRESHOLD_VALUE |
> > + INT_AGGR_TIMEOUT_VALUE,
> > + REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
> > break;
> > }
> >  }
> > @@ -262,12 +258,10 @@ ufshcd_config_int_aggr(struct ufs_hba *hba, int 
> > option)
> >   */
> >  static void ufshcd_enable_run_stop_reg(struct ufs_hba *hba)
> >  {
> > -   writel(UTP_TASK_REQ_LIST_RUN_STOP_BIT,
> > -  (hba->mmio_base +
> > -   REG_UTP_TASK_REQ_LIST_RUN_STOP));
> > -   writel(UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT,
> > -  (hba->mmio_base +
> > -   REG_UTP_TRANSFER_REQ_LIST_RUN_STOP));
> > +   ufshcd_writel(hba, UTP_TASK_REQ_LIST_RUN_STOP_BIT,
> > + REG_UTP_TASK_REQ_LIST_RUN_STOP);
> > +   ufshcd_writel(hba, UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT,
> > + REG_UTP_TRANSFER_REQ_LIST_RUN_STOP);
> >  }
> >
> >  /**
> > @@ -276,7 +270,7 @@ static void ufshcd_enable_run_stop_reg(struct ufs_hba 
> > *hba)
> >   */
> >  static inline void ufshcd_hba_start(struct ufs_hba *hba)
> >  {
> > -   writel(CONTROLLER_ENABLE , (hba->mmio_base + 
> > REG_CONTROLLER_ENABLE));
> > +   ufshcd_writel(hba, CONTROLLER_ENABLE, REG_CONTROLLER_ENABLE);
> >  }
> >
> >  /**
> > @@ -287,7 +281,7 @@ static inline void ufshcd_hba_start(struct ufs_hba *hba)
> >   */
> >  static inline int ufshcd_is_hba_active(struct ufs_hba *hba)
> >  {
> > -   return (readl(hba->mmio_base + REG_CONTROLLER_ENABLE) & 0x1) ? 0 : 
> > 1;
> > +   return (ufshcd_readl(hba, REG_CONTROLLER_ENABLE) & 0x1) ? 0 : 1;
> >  }
> >
> >  

RE: [PATCH V3 1/1] scsi: ufs: Add support for sending NOP OUT UPIU

2013-05-07 Thread Seungwon Jeon
ufshcd_lrb *lrbp)
> +{
> + lrbp->cmd = NULL;
> + lrbp->sense_bufflen = 0;
> + lrbp->sense_buffer = NULL;
> + lrbp->task_tag = INTERNAL_CMD_TAG;
> + lrbp->lun = 0; /* NOP OUT is not specific to any LUN */
> + lrbp->command_type = UTP_CMD_TYPE_DEV_MANAGE;
> + lrbp->intr_cmd = true; /* No interrupt aggregation */
> +
> + return ufshcd_compose_upiu(hba, lrbp);
> +}
> +
> +static int ufshcd_wait_for_nop_cmd(struct ufs_hba *hba, struct ufshcd_lrb 
> *lrbp)
> +{
> + int err = 0;
> + unsigned long timeout;
> + unsigned long flags;
> +
> + timeout = wait_for_completion_timeout(
> + lrbp->completion, msecs_to_jiffies(NOP_OUT_TIMEOUT));
> +
> + if (timeout) {
> + spin_lock_irqsave(hba->host->host_lock, flags);
> + err = ufshcd_get_tr_ocs(lrbp);
> + spin_unlock_irqrestore(hba->host->host_lock, flags);
> + } else {
> + err = -ETIMEDOUT;
> + }
> +
> + return err;
> +}
> +
> +/**
> + * ufshcd_validate_dev_connection() - Check device connection status
> + * @hba: per-adapter instance
> + *
> + * Send NOP OUT UPIU and wait for NOP IN response to check whether the
> + * device Transport Protocol (UTP) layer is ready after a reset.
> + * If the UTP layer at the device side is not initialized, it may
> + * not respond with NOP IN UPIU within timeout of %NOP_OUT_TIMEOUT
> + * and we retry sending NOP OUT for %NOP_OUT_RETRIES iterations.
> + */
> +static int ufshcd_validate_dev_connection(struct ufs_hba *hba)
> +{
> + int err;
> + struct ufshcd_lrb *lrbp;
> + unsigned long flags;
> + struct completion wait;
> + int retries = NOP_OUT_RETRIES;
> +
> +retry:
> + init_completion(&wait);
> +
> + spin_lock_irqsave(hba->host->host_lock, flags);
> + lrbp = &hba->lrb[INTERNAL_CMD_TAG];
> + err = ufshcd_compose_nop_out_upiu(hba, lrbp);
> + if (unlikely(err)) {
> + spin_unlock_irqrestore(hba->host->host_lock, flags);
> + goto out;
> + }
> +
> + lrbp->completion = &wait;
> + ufshcd_send_command(hba, INTERNAL_CMD_TAG);
> + spin_unlock_irqrestore(hba->host->host_lock, flags);
> +
> + err = ufshcd_wait_for_nop_cmd(hba, lrbp);
> +
> + if (err == -ETIMEDOUT) {
> + u32 reg;
> +
> + /* clear outstanding transaction before retry */
> + spin_lock_irqsave(hba->host->host_lock, flags);
> + ufshcd_utrl_clear(hba, INTERNAL_CMD_TAG);
> + __clear_bit(INTERNAL_CMD_TAG, &hba->outstanding_reqs);
> + spin_unlock_irqrestore(hba->host->host_lock, flags);
> +
> + /* poll for max. 1 sec to clear door bell register by h/w */
> + if (readl_poll_timeout(
> + hba->mmio_base + REG_UTP_TRANSFER_REQ_DOOR_BELL,
> + reg, !(reg & (1 << INTERNAL_CMD_TAG)),
> + 1000, 1000))
> + retries = 0;
Also, readl_poll_timeout function is not present in Linux kernel.
Could you check your kernel?
You should implement this part in other way.
Additionally, is there no need to clear 'lrbp->completion'?
It will have invalid value after current function is out.

Thanks,
Seungwon Jeon

> + }
> +
> + if (err && retries--) {
> + dev_dbg(hba->dev, "%s: error %d retrying\n", __func__, err);
> + goto retry;
> + }
> +
> +out:
> + if (err)
> + dev_err(hba->dev, "%s: NOP OUT failed %d\n", __func__, err);
> + return err;
> +}
> +
>  /**
>   * ufshcd_make_hba_operational - Make UFS controller operational
>   * @hba: per adapter instance
> @@ -1734,6 +1856,16 @@ static void ufshcd_uic_cmd_compl(struct ufs_hba *hba, 
> u32 intr_status)
>   complete(&hba->hibern8_done);
>  }
> 
> +/*
> + * ufshcd_is_nop_out_upiu() - check if the command is NOP OUT UPIU
> + * @lrbp: pointer to logical reference block
> + */
> +static inline bool ufshcd_is_nop_out_upiu(struct ufshcd_lrb *lrbp)
> +{
> + return (be32_to_cpu(lrbp->ucd_req_ptr->header.dword_0) >> 24) ==
> + UPIU_TRANSACTION_NOP_OUT;
> +}
> +
>  /**
>   * ufshcd_transfer_req_compl - handle SCSI and query command completion
>   * @hba: per adapter instance
> @@ -1745,6 +1877,7 @@ static void ufshcd_transfer_req_compl(struct ufs_hba 
> *hba)
>   u32 tr_doorbell;
>   int result;
>   int index;
&

[PATCH v4 1/6] scsi: ufs: wrap the i/o access operations

2013-05-08 Thread Seungwon Jeon
Simplify operations with hiding mmio_base.

Signed-off-by: Seungwon Jeon 
Tested-by: Maya Erez 
---
 drivers/scsi/ufs/ufshcd.c |  105 +++--
 drivers/scsi/ufs/ufshcd.h |7 +++-
 2 files changed, 50 insertions(+), 62 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index f244812..cf7c8e4 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -71,7 +71,7 @@ enum {
  */
 static inline u32 ufshcd_get_ufs_version(struct ufs_hba *hba)
 {
-   return readl(hba->mmio_base + REG_UFS_VERSION);
+   return ufshcd_readl(hba, REG_UFS_VERSION);
 }
 
 /**
@@ -130,8 +130,7 @@ static inline int ufshcd_get_tm_free_slot(struct ufs_hba 
*hba)
  */
 static inline void ufshcd_utrl_clear(struct ufs_hba *hba, u32 pos)
 {
-   writel(~(1 << pos),
-   (hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_CLEAR));
+   ufshcd_writel(hba, ~(1 << pos), REG_UTP_TRANSFER_REQ_LIST_CLEAR);
 }
 
 /**
@@ -165,7 +164,7 @@ static inline int ufshcd_get_lists_status(u32 reg)
  */
 static inline int ufshcd_get_uic_cmd_result(struct ufs_hba *hba)
 {
-   return readl(hba->mmio_base + REG_UIC_COMMAND_ARG_2) &
+   return ufshcd_readl(hba, REG_UIC_COMMAND_ARG_2) &
   MASK_UIC_COMMAND_RESULT;
 }
 
@@ -238,18 +237,15 @@ ufshcd_config_int_aggr(struct ufs_hba *hba, int option)
 {
switch (option) {
case INT_AGGR_RESET:
-   writel((INT_AGGR_ENABLE |
-   INT_AGGR_COUNTER_AND_TIMER_RESET),
-   (hba->mmio_base +
-REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL));
+   ufshcd_writel(hba, INT_AGGR_ENABLE |
+ INT_AGGR_COUNTER_AND_TIMER_RESET,
+ REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
break;
case INT_AGGR_CONFIG:
-   writel((INT_AGGR_ENABLE |
-   INT_AGGR_PARAM_WRITE |
-   INT_AGGR_COUNTER_THRESHOLD_VALUE |
-   INT_AGGR_TIMEOUT_VALUE),
-   (hba->mmio_base +
-REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL));
+   ufshcd_writel(hba, INT_AGGR_ENABLE | INT_AGGR_PARAM_WRITE |
+ INT_AGGR_COUNTER_THRESHOLD_VALUE |
+ INT_AGGR_TIMEOUT_VALUE,
+ REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
break;
}
 }
@@ -262,12 +258,10 @@ ufshcd_config_int_aggr(struct ufs_hba *hba, int option)
  */
 static void ufshcd_enable_run_stop_reg(struct ufs_hba *hba)
 {
-   writel(UTP_TASK_REQ_LIST_RUN_STOP_BIT,
-  (hba->mmio_base +
-   REG_UTP_TASK_REQ_LIST_RUN_STOP));
-   writel(UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT,
-  (hba->mmio_base +
-   REG_UTP_TRANSFER_REQ_LIST_RUN_STOP));
+   ufshcd_writel(hba, UTP_TASK_REQ_LIST_RUN_STOP_BIT,
+ REG_UTP_TASK_REQ_LIST_RUN_STOP);
+   ufshcd_writel(hba, UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT,
+ REG_UTP_TRANSFER_REQ_LIST_RUN_STOP);
 }
 
 /**
@@ -276,7 +270,7 @@ static void ufshcd_enable_run_stop_reg(struct ufs_hba *hba)
  */
 static inline void ufshcd_hba_start(struct ufs_hba *hba)
 {
-   writel(CONTROLLER_ENABLE , (hba->mmio_base + REG_CONTROLLER_ENABLE));
+   ufshcd_writel(hba, CONTROLLER_ENABLE, REG_CONTROLLER_ENABLE);
 }
 
 /**
@@ -287,7 +281,7 @@ static inline void ufshcd_hba_start(struct ufs_hba *hba)
  */
 static inline int ufshcd_is_hba_active(struct ufs_hba *hba)
 {
-   return (readl(hba->mmio_base + REG_CONTROLLER_ENABLE) & 0x1) ? 0 : 1;
+   return (ufshcd_readl(hba, REG_CONTROLLER_ENABLE) & 0x1) ? 0 : 1;
 }
 
 /**
@@ -299,8 +293,7 @@ static inline
 void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag)
 {
__set_bit(task_tag, &hba->outstanding_reqs);
-   writel((1 << task_tag),
-  (hba->mmio_base + REG_UTP_TRANSFER_REQ_DOOR_BELL));
+   ufshcd_writel(hba, 1 << task_tag, REG_UTP_TRANSFER_REQ_DOOR_BELL);
 }
 
 /**
@@ -381,8 +374,7 @@ void ufshcd_copy_query_response(struct ufs_hba *hba, struct 
ufshcd_lrb *lrbp)
  */
 static inline void ufshcd_hba_capabilities(struct ufs_hba *hba)
 {
-   hba->capabilities =
-   readl(hba->mmio_base + REG_CONTROLLER_CAPABILITIES);
+   hba->capabilities = ufshcd_readl(hba, REG_CONTROLLER_CAPABILITIES);
 
/* nutrs and nutmrs are 0 based values */
hba->nutrs = (hba->capabilities & MASK_TRANSFER_REQUESTS_SLOTS) + 1;
@@ -399,16 +391,13 @@ static inline void
 ufshcd_send_uic_command(struct ufs_hba *hba, struct uic_command *uic_cmnd)
 {
/* Write Args */
-   writel(uic_cmnd->argument1,
- (hba->mmio_base + REG_UIC_COMMAND_ARG_1));
-   writel(uic_cmnd->argument2,
- (hba->mmio_base + REG_UI

[PATCH v4 2/6] scsi: ufs: amend interrupt configuration

2013-05-08 Thread Seungwon Jeon
It makes interrupt setting more flexible especially
for disabling. And wrong bit mask is fixed for ver 1.0.
[17:16] is added for mask.

Signed-off-by: Seungwon Jeon 
Tested-by: Maya Erez 
---
 drivers/scsi/ufs/ufshcd.c |   84 +++-
 drivers/scsi/ufs/ufshcd.h |4 +-
 drivers/scsi/ufs/ufshci.h |5 ++-
 3 files changed, 64 insertions(+), 29 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index cf7c8e4..feaf221 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -35,6 +35,10 @@
 
 #include "ufshcd.h"
 
+#define UFSHCD_ENABLE_INTRS(UTP_TRANSFER_REQ_COMPL |\
+UTP_TASK_REQ_COMPL |\
+UFSHCD_ERROR_MASK)
+
 enum {
UFSHCD_MAX_CHANNEL  = 0,
UFSHCD_MAX_ID   = 1,
@@ -64,6 +68,20 @@ enum {
 };
 
 /**
+ * ufshcd_get_intr_mask - Get the interrupt bit mask
+ * @hba - Pointer to adapter instance
+ *
+ * Returns interrupt bit mask per version
+ */
+static inline u32 ufshcd_get_intr_mask(struct ufs_hba *hba)
+{
+   if (hba->ufs_version == UFSHCI_VERSION_10)
+   return INTERRUPT_MASK_ALL_VER_10;
+   else
+   return INTERRUPT_MASK_ALL_VER_11;
+}
+
+/**
  * ufshcd_get_ufs_version - Get the UFS version supported by the HBA
  * @hba - Pointer to adapter instance
  *
@@ -441,25 +459,45 @@ static int ufshcd_map_sg(struct ufshcd_lrb *lrbp)
 }
 
 /**
- * ufshcd_int_config - enable/disable interrupts
+ * ufshcd_enable_intr - enable interrupts
  * @hba: per adapter instance
- * @option: interrupt option
+ * @intrs: interrupt bits
  */
-static void ufshcd_int_config(struct ufs_hba *hba, u32 option)
+static void ufshcd_enable_intr(struct ufs_hba *hba, u32 intrs)
 {
-   switch (option) {
-   case UFSHCD_INT_ENABLE:
-   ufshcd_writel(hba, hba->int_enable_mask, REG_INTERRUPT_ENABLE);
-   break;
-   case UFSHCD_INT_DISABLE:
-   if (hba->ufs_version == UFSHCI_VERSION_10)
-   ufshcd_writel(hba, INTERRUPT_DISABLE_MASK_10,
- REG_INTERRUPT_ENABLE);
-   else
-   ufshcd_writel(hba, INTERRUPT_DISABLE_MASK_11,
- REG_INTERRUPT_ENABLE);
-   break;
+   u32 set = ufshcd_readl(hba, REG_INTERRUPT_ENABLE);
+
+   if (hba->ufs_version == UFSHCI_VERSION_10) {
+   u32 rw;
+   rw = set & INTERRUPT_MASK_RW_VER_10;
+   set = rw | ((set ^ intrs) & intrs);
+   } else {
+   set |= intrs;
+   }
+
+   ufshcd_writel(hba, set, REG_INTERRUPT_ENABLE);
+}
+
+/**
+ * ufshcd_disable_intr - disable interrupts
+ * @hba: per adapter instance
+ * @intrs: interrupt bits
+ */
+static void ufshcd_disable_intr(struct ufs_hba *hba, u32 intrs)
+{
+   u32 set = ufshcd_readl(hba, REG_INTERRUPT_ENABLE);
+
+   if (hba->ufs_version == UFSHCI_VERSION_10) {
+   u32 rw;
+   rw = (set & INTERRUPT_MASK_RW_VER_10) &
+   ~(intrs & INTERRUPT_MASK_RW_VER_10);
+   set = rw | ((set & intrs) & ~INTERRUPT_MASK_RW_VER_10);
+
+   } else {
+   set &= ~intrs;
}
+
+   ufshcd_writel(hba, set, REG_INTERRUPT_ENABLE);
 }
 
 /**
@@ -946,8 +984,7 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba)
uic_cmd->argument3 = 0;
 
/* enable UIC related interrupts */
-   hba->int_enable_mask |= UIC_COMMAND_COMPL;
-   ufshcd_int_config(hba, UFSHCD_INT_ENABLE);
+   ufshcd_enable_intr(hba, UIC_COMMAND_COMPL);
 
/* sending UIC commands to controller */
ufshcd_send_uic_command(hba, uic_cmd);
@@ -994,13 +1031,7 @@ static int ufshcd_make_hba_operational(struct ufs_hba 
*hba)
}
 
/* Enable required interrupts */
-   hba->int_enable_mask |= (UTP_TRANSFER_REQ_COMPL |
-UIC_ERROR |
-UTP_TASK_REQ_COMPL |
-DEVICE_FATAL_ERROR |
-CONTROLLER_FATAL_ERROR |
-SYSTEM_BUS_FATAL_ERROR);
-   ufshcd_int_config(hba, UFSHCD_INT_ENABLE);
+   ufshcd_enable_intr(hba, UFSHCD_ENABLE_INTRS);
 
/* Configure interrupt aggregation */
ufshcd_config_int_aggr(hba, INT_AGGR_CONFIG);
@@ -1828,7 +1859,7 @@ static void ufshcd_hba_free(struct ufs_hba *hba)
 void ufshcd_remove(struct ufs_hba *hba)
 {
/* disable interrupts */
-   ufshcd_int_config(hba, UFSHCD_INT_DISABLE);
+   ufshcd_disable_intr(hba, hba->intr_mask);
 
ufshcd_hba_stop(hba);
ufshcd_hba_free(hba);
@@ -1886,6 +1917,9 @@ int ufshcd_init(struct device *dev, struct ufs_hba 
**hba_handle,
/* Get UFS version supported by the controller */
hba->ufs_version = ufshcd_get_ufs_vers

[PATCH v4 3/6] scsi: ufs: fix interrupt status clears

2013-05-08 Thread Seungwon Jeon
There is no need to check the version to clear
the interrupt status. And the order is changed
prior to actual handling.

Signed-off-by: Seungwon Jeon 
Tested-by: Maya Erez 
---
 drivers/scsi/ufs/ufshcd.c |5 +
 1 files changed, 1 insertions(+), 4 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index feaf221..e04c74e 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -1582,11 +1582,8 @@ static irqreturn_t ufshcd_intr(int irq, void *__hba)
intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
 
if (intr_status) {
+   ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
ufshcd_sl_intr(hba, intr_status);
-
-   /* If UFSHCI 1.0 then clear interrupt status register */
-   if (hba->ufs_version == UFSHCI_VERSION_10)
-   ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
retval = IRQ_HANDLED;
}
spin_unlock(hba->host->host_lock);
-- 
1.7.0.4


--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v4 4/6] scsi: ufs: rework link start-up process

2013-05-08 Thread Seungwon Jeon
Link start-up requires long time with multiphase handshakes
between UFS host and device. This affects driver's probe time.
This patch let link start-up run asynchronously. Link start-up
will be executed at the end of prove separately.
Along with this change, the following is worked.

Defined completion time of uic command to avoid a permanent wait.
Added mutex to guarantee of uic command at a time.
Adapted some sequence of controller initialization after link statup
according to HCI standard.

Signed-off-by: Seungwon Jeon 
Signed-off-by: Sujit Reddy Thumma 
Tested-by: Maya Erez 
---
Change in v4:
- Addressed late interrupt case (Sujit).
- Move print message in link startup (Maya).

 drivers/scsi/ufs/ufshcd.c |  295 ++--
 drivers/scsi/ufs/ufshcd.h |   10 +-
 2 files changed, 208 insertions(+), 97 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index e04c74e..8363b92 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -33,11 +33,15 @@
  * this program.
  */
 
+#include 
+
 #include "ufshcd.h"
 
 #define UFSHCD_ENABLE_INTRS(UTP_TRANSFER_REQ_COMPL |\
 UTP_TASK_REQ_COMPL |\
 UFSHCD_ERROR_MASK)
+/* UIC command timeout, unit: ms */
+#define UIC_CMD_TIMEOUT500
 
 enum {
UFSHCD_MAX_CHANNEL  = 0,
@@ -401,24 +405,122 @@ static inline void ufshcd_hba_capabilities(struct 
ufs_hba *hba)
 }
 
 /**
- * ufshcd_send_uic_command - Send UIC commands to unipro layers
+ * ufshcd_ready_for_uic_cmd - Check if controller is ready
+ *to accept UIC commands
  * @hba: per adapter instance
- * @uic_command: UIC command
+ * Return true on success, else false
+ */
+static inline bool ufshcd_ready_for_uic_cmd(struct ufs_hba *hba)
+{
+   if (ufshcd_readl(hba, REG_CONTROLLER_STATUS) & UIC_COMMAND_READY)
+   return true;
+   else
+   return false;
+}
+
+/**
+ * ufshcd_dispatch_uic_cmd - Dispatch UIC commands to unipro layers
+ * @hba: per adapter instance
+ * @uic_cmd: UIC command
+ *
+ * Mutex must be held.
  */
 static inline void
-ufshcd_send_uic_command(struct ufs_hba *hba, struct uic_command *uic_cmnd)
+ufshcd_dispatch_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
 {
+   WARN_ON(hba->active_uic_cmd);
+
+   hba->active_uic_cmd = uic_cmd;
+
/* Write Args */
-   ufshcd_writel(hba, uic_cmnd->argument1, REG_UIC_COMMAND_ARG_1);
-   ufshcd_writel(hba, uic_cmnd->argument2, REG_UIC_COMMAND_ARG_2);
-   ufshcd_writel(hba, uic_cmnd->argument3, REG_UIC_COMMAND_ARG_3);
+   ufshcd_writel(hba, uic_cmd->argument1, REG_UIC_COMMAND_ARG_1);
+   ufshcd_writel(hba, uic_cmd->argument2, REG_UIC_COMMAND_ARG_2);
+   ufshcd_writel(hba, uic_cmd->argument3, REG_UIC_COMMAND_ARG_3);
 
/* Write UIC Cmd */
-   ufshcd_writel(hba, uic_cmnd->command & COMMAND_OPCODE_MASK,
+   ufshcd_writel(hba, uic_cmd->command & COMMAND_OPCODE_MASK,
  REG_UIC_COMMAND);
 }
 
 /**
+ * ufshcd_wait_for_uic_cmd - Wait complectioin of UIC command
+ * @hba: per adapter instance
+ * @uic_command: UIC command
+ *
+ * Must be called with mutex held.
+ * Returns 0 only if success.
+ */
+static int
+ufshcd_wait_for_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
+{
+   int ret;
+   unsigned long flags;
+
+   if (wait_for_completion_timeout(&uic_cmd->done,
+   msecs_to_jiffies(UIC_CMD_TIMEOUT)))
+   ret = uic_cmd->argument2 & MASK_UIC_COMMAND_RESULT;
+   else
+   ret = -ETIMEDOUT;
+
+   spin_lock_irqsave(hba->host->host_lock, flags);
+   hba->active_uic_cmd = NULL;
+   spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+   return ret;
+}
+
+/**
+ * __ufshcd_send_uic_cmd - Send UIC commands and retrieve the result
+ * @hba: per adapter instance
+ * @uic_cmd: UIC command
+ *
+ * Identical to ufshcd_send_uic_cmd() expect mutex. Must be called
+ * with mutex held.
+ * Returns 0 only if success.
+ */
+static int
+__ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
+{
+   int ret;
+   unsigned long flags;
+
+   if (!ufshcd_ready_for_uic_cmd(hba)) {
+   dev_err(hba->dev,
+   "Controller not ready to accept UIC commands\n");
+   return -EIO;
+   }
+
+   init_completion(&uic_cmd->done);
+
+   spin_lock_irqsave(hba->host->host_lock, flags);
+   ufshcd_dispatch_uic_cmd(hba, uic_cmd);
+   spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+   ret = ufshcd_wait_for_uic_cmd(hba, uic_cmd);
+
+   return ret;
+}
+
+/**
+ * ufshcd_send_uic_cmd - Send UIC commands and retrieve the result
+ * @hba: per adapter instance
+ * @uic_cmd: UIC command
+ *
+ * Returns 0 only 

  1   2   >