Commit 53b3d9c3fdda94d14392dd221c67e24700b1fed6

Authored by Seungwon Jeon
Committed by James Bottomley
1 parent 12b4fdb4f6

[SCSI] ufs: add operation for the uic power mode change

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 <tgih.jun@samsung.com>
Reviewed-by: Subhash Jadavani <subhashj@codeaurora.org>
Tested-by: Yaniv Gardi <ygardi@codeaurora.org>
Signed-off-by: Santosh Y <santoshsy@gmail.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>

Showing 4 changed files with 225 additions and 4 deletions Side-by-side Diff

drivers/scsi/ufs/ufshcd.c
... ... @@ -36,9 +36,11 @@
36 36 #include <linux/async.h>
37 37  
38 38 #include "ufshcd.h"
  39 +#include "unipro.h"
39 40  
40 41 #define UFSHCD_ENABLE_INTRS (UTP_TRANSFER_REQ_COMPL |\
41 42 UTP_TASK_REQ_COMPL |\
  43 + UIC_POWER_MODE |\
42 44 UFSHCD_ERROR_MASK)
43 45 /* UIC command timeout, unit: ms */
44 46 #define UIC_CMD_TIMEOUT 500
... ... @@ -470,6 +472,18 @@
470 472 }
471 473  
472 474 /**
  475 + * ufshcd_get_upmcrs - Get the power mode change request status
  476 + * @hba: Pointer to adapter instance
  477 + *
  478 + * This function gets the UPMCRS field of HCS register
  479 + * Returns value of UPMCRS field
  480 + */
  481 +static inline u8 ufshcd_get_upmcrs(struct ufs_hba *hba)
  482 +{
  483 + return (ufshcd_readl(hba, REG_CONTROLLER_STATUS) >> 8) & 0x7;
  484 +}
  485 +
  486 +/**
473 487 * ufshcd_dispatch_uic_cmd - Dispatch UIC commands to unipro layers
474 488 * @hba: per adapter instance
475 489 * @uic_cmd: UIC command
... ... @@ -1460,6 +1474,64 @@
1460 1474 EXPORT_SYMBOL_GPL(ufshcd_dme_get_attr);
1461 1475  
1462 1476 /**
  1477 + * ufshcd_uic_change_pwr_mode - Perform the UIC power mode chage
  1478 + * using DME_SET primitives.
  1479 + * @hba: per adapter instance
  1480 + * @mode: powr mode value
  1481 + *
  1482 + * Returns 0 on success, non-zero value on failure
  1483 + */
  1484 +int ufshcd_uic_change_pwr_mode(struct ufs_hba *hba, u8 mode)
  1485 +{
  1486 + struct uic_command uic_cmd = {0};
  1487 + struct completion pwr_done;
  1488 + unsigned long flags;
  1489 + u8 status;
  1490 + int ret;
  1491 +
  1492 + uic_cmd.command = UIC_CMD_DME_SET;
  1493 + uic_cmd.argument1 = UIC_ARG_MIB(PA_PWRMODE);
  1494 + uic_cmd.argument3 = mode;
  1495 + init_completion(&pwr_done);
  1496 +
  1497 + mutex_lock(&hba->uic_cmd_mutex);
  1498 +
  1499 + spin_lock_irqsave(hba->host->host_lock, flags);
  1500 + hba->pwr_done = &pwr_done;
  1501 + spin_unlock_irqrestore(hba->host->host_lock, flags);
  1502 + ret = __ufshcd_send_uic_cmd(hba, &uic_cmd);
  1503 + if (ret) {
  1504 + dev_err(hba->dev,
  1505 + "pwr mode change with mode 0x%x uic error %d\n",
  1506 + mode, ret);
  1507 + goto out;
  1508 + }
  1509 +
  1510 + if (!wait_for_completion_timeout(hba->pwr_done,
  1511 + msecs_to_jiffies(UIC_CMD_TIMEOUT))) {
  1512 + dev_err(hba->dev,
  1513 + "pwr mode change with mode 0x%x completion timeout\n",
  1514 + mode);
  1515 + ret = -ETIMEDOUT;
  1516 + goto out;
  1517 + }
  1518 +
  1519 + status = ufshcd_get_upmcrs(hba);
  1520 + if (status != PWR_LOCAL) {
  1521 + dev_err(hba->dev,
  1522 + "pwr mode change failed, host umpcrs:0x%x\n",
  1523 + status);
  1524 + ret = (status != PWR_OK) ? status : -1;
  1525 + }
  1526 +out:
  1527 + spin_lock_irqsave(hba->host->host_lock, flags);
  1528 + hba->pwr_done = NULL;
  1529 + spin_unlock_irqrestore(hba->host->host_lock, flags);
  1530 + mutex_unlock(&hba->uic_cmd_mutex);
  1531 + return ret;
  1532 +}
  1533 +
  1534 +/**
1463 1535 * ufshcd_complete_dev_init() - checks device readiness
1464 1536 * hba: per-adapter instance
1465 1537 *
1466 1538  
1467 1539  
1468 1540  
... ... @@ -1988,16 +2060,20 @@
1988 2060 /**
1989 2061 * ufshcd_uic_cmd_compl - handle completion of uic command
1990 2062 * @hba: per adapter instance
  2063 + * @intr_status: interrupt status generated by the controller
1991 2064 */
1992   -static void ufshcd_uic_cmd_compl(struct ufs_hba *hba)
  2065 +static void ufshcd_uic_cmd_compl(struct ufs_hba *hba, u32 intr_status)
1993 2066 {
1994   - if (hba->active_uic_cmd) {
  2067 + if ((intr_status & UIC_COMMAND_COMPL) && hba->active_uic_cmd) {
1995 2068 hba->active_uic_cmd->argument2 |=
1996 2069 ufshcd_get_uic_cmd_result(hba);
1997 2070 hba->active_uic_cmd->argument3 =
1998 2071 ufshcd_get_dme_attr_val(hba);
1999 2072 complete(&hba->active_uic_cmd->done);
2000 2073 }
  2074 +
  2075 + if ((intr_status & UIC_POWER_MODE) && hba->pwr_done)
  2076 + complete(hba->pwr_done);
2001 2077 }
2002 2078  
2003 2079 /**
... ... @@ -2343,8 +2419,8 @@
2343 2419 if (hba->errors)
2344 2420 ufshcd_err_handler(hba);
2345 2421  
2346   - if (intr_status & UIC_COMMAND_COMPL)
2347   - ufshcd_uic_cmd_compl(hba);
  2422 + if (intr_status & UFSHCD_UIC_MASK)
  2423 + ufshcd_uic_cmd_compl(hba, intr_status);
2348 2424  
2349 2425 if (intr_status & UTP_TASK_REQ_COMPL)
2350 2426 ufshcd_tmc_handler(hba);
drivers/scsi/ufs/ufshcd.h
... ... @@ -175,6 +175,7 @@
175 175 * @active_uic_cmd: handle of active UIC command
176 176 * @uic_cmd_mutex: mutex for uic command
177 177 * @ufshcd_tm_wait_queue: wait queue for task management
  178 + * @pwr_done: completion for power mode change
178 179 * @tm_condition: condition variable for task management
179 180 * @ufshcd_state: UFSHCD states
180 181 * @intr_mask: Interrupt Mask Bits
... ... @@ -218,6 +219,8 @@
218 219  
219 220 wait_queue_head_t ufshcd_tm_wait_queue;
220 221 unsigned long tm_condition;
  222 +
  223 + struct completion *pwr_done;
221 224  
222 225 u32 ufshcd_state;
223 226 u32 intr_mask;
drivers/scsi/ufs/ufshci.h
... ... @@ -124,6 +124,9 @@
124 124 #define CONTROLLER_FATAL_ERROR UFS_BIT(16)
125 125 #define SYSTEM_BUS_FATAL_ERROR UFS_BIT(17)
126 126  
  127 +#define UFSHCD_UIC_MASK (UIC_COMMAND_COMPL |\
  128 + UIC_POWER_MODE)
  129 +
127 130 #define UFSHCD_ERROR_MASK (UIC_ERROR |\
128 131 DEVICE_FATAL_ERROR |\
129 132 CONTROLLER_FATAL_ERROR |\
... ... @@ -141,6 +144,15 @@
141 144 #define HOST_ERROR_INDICATOR UFS_BIT(4)
142 145 #define DEVICE_ERROR_INDICATOR UFS_BIT(5)
143 146 #define UIC_POWER_MODE_CHANGE_REQ_STATUS_MASK UFS_MASK(0x7, 8)
  147 +
  148 +enum {
  149 + PWR_OK = 0x0,
  150 + PWR_LOCAL = 0x01,
  151 + PWR_REMOTE = 0x02,
  152 + PWR_BUSY = 0x03,
  153 + PWR_ERROR_CAP = 0x04,
  154 + PWR_FATAL_ERROR = 0x05,
  155 +};
144 156  
145 157 /* HCE - Host Controller Enable 34h */
146 158 #define CONTROLLER_ENABLE UFS_BIT(0)
drivers/scsi/ufs/unipro.h
  1 +/*
  2 + * drivers/scsi/ufs/unipro.h
  3 + *
  4 + * Copyright (C) 2013 Samsung Electronics Co., Ltd.
  5 + *
  6 + * This program is free software; you can redistribute it and/or modify
  7 + * it under the terms of the GNU General Public License as published by
  8 + * the Free Software Foundation; either version 2 of the License, or
  9 + * (at your option) any later version.
  10 + */
  11 +
  12 +#ifndef _UNIPRO_H_
  13 +#define _UNIPRO_H_
  14 +
  15 +/*
  16 + * PHY Adpater attributes
  17 + */
  18 +#define PA_ACTIVETXDATALANES 0x1560
  19 +#define PA_ACTIVERXDATALANES 0x1580
  20 +#define PA_TXTRAILINGCLOCKS 0x1564
  21 +#define PA_PHY_TYPE 0x1500
  22 +#define PA_AVAILTXDATALANES 0x1520
  23 +#define PA_AVAILRXDATALANES 0x1540
  24 +#define PA_MINRXTRAILINGCLOCKS 0x1543
  25 +#define PA_TXPWRSTATUS 0x1567
  26 +#define PA_RXPWRSTATUS 0x1582
  27 +#define PA_TXFORCECLOCK 0x1562
  28 +#define PA_TXPWRMODE 0x1563
  29 +#define PA_LEGACYDPHYESCDL 0x1570
  30 +#define PA_MAXTXSPEEDFAST 0x1521
  31 +#define PA_MAXTXSPEEDSLOW 0x1522
  32 +#define PA_MAXRXSPEEDFAST 0x1541
  33 +#define PA_MAXRXSPEEDSLOW 0x1542
  34 +#define PA_TXLINKSTARTUPHS 0x1544
  35 +#define PA_TXSPEEDFAST 0x1565
  36 +#define PA_TXSPEEDSLOW 0x1566
  37 +#define PA_REMOTEVERINFO 0x15A0
  38 +#define PA_TXGEAR 0x1568
  39 +#define PA_TXTERMINATION 0x1569
  40 +#define PA_HSSERIES 0x156A
  41 +#define PA_PWRMODE 0x1571
  42 +#define PA_RXGEAR 0x1583
  43 +#define PA_RXTERMINATION 0x1584
  44 +#define PA_MAXRXPWMGEAR 0x1586
  45 +#define PA_MAXRXHSGEAR 0x1587
  46 +#define PA_RXHSUNTERMCAP 0x15A5
  47 +#define PA_RXLSTERMCAP 0x15A6
  48 +#define PA_PACPREQTIMEOUT 0x1590
  49 +#define PA_PACPREQEOBTIMEOUT 0x1591
  50 +#define PA_HIBERN8TIME 0x15A7
  51 +#define PA_LOCALVERINFO 0x15A9
  52 +#define PA_TACTIVATE 0x15A8
  53 +#define PA_PACPFRAMECOUNT 0x15C0
  54 +#define PA_PACPERRORCOUNT 0x15C1
  55 +#define PA_PHYTESTCONTROL 0x15C2
  56 +#define PA_PWRMODEUSERDATA0 0x15B0
  57 +#define PA_PWRMODEUSERDATA1 0x15B1
  58 +#define PA_PWRMODEUSERDATA2 0x15B2
  59 +#define PA_PWRMODEUSERDATA3 0x15B3
  60 +#define PA_PWRMODEUSERDATA4 0x15B4
  61 +#define PA_PWRMODEUSERDATA5 0x15B5
  62 +#define PA_PWRMODEUSERDATA6 0x15B6
  63 +#define PA_PWRMODEUSERDATA7 0x15B7
  64 +#define PA_PWRMODEUSERDATA8 0x15B8
  65 +#define PA_PWRMODEUSERDATA9 0x15B9
  66 +#define PA_PWRMODEUSERDATA10 0x15BA
  67 +#define PA_PWRMODEUSERDATA11 0x15BB
  68 +#define PA_CONNECTEDTXDATALANES 0x1561
  69 +#define PA_CONNECTEDRXDATALANES 0x1581
  70 +#define PA_LOGICALLANEMAP 0x15A1
  71 +#define PA_SLEEPNOCONFIGTIME 0x15A2
  72 +#define PA_STALLNOCONFIGTIME 0x15A3
  73 +#define PA_SAVECONFIGTIME 0x15A4
  74 +
  75 +/*
  76 + * Data Link Layer Attributes
  77 + */
  78 +#define DL_TC0TXFCTHRESHOLD 0x2040
  79 +#define DL_FC0PROTTIMEOUTVAL 0x2041
  80 +#define DL_TC0REPLAYTIMEOUTVAL 0x2042
  81 +#define DL_AFC0REQTIMEOUTVAL 0x2043
  82 +#define DL_AFC0CREDITTHRESHOLD 0x2044
  83 +#define DL_TC0OUTACKTHRESHOLD 0x2045
  84 +#define DL_TC1TXFCTHRESHOLD 0x2060
  85 +#define DL_FC1PROTTIMEOUTVAL 0x2061
  86 +#define DL_TC1REPLAYTIMEOUTVAL 0x2062
  87 +#define DL_AFC1REQTIMEOUTVAL 0x2063
  88 +#define DL_AFC1CREDITTHRESHOLD 0x2064
  89 +#define DL_TC1OUTACKTHRESHOLD 0x2065
  90 +#define DL_TXPREEMPTIONCAP 0x2000
  91 +#define DL_TC0TXMAXSDUSIZE 0x2001
  92 +#define DL_TC0RXINITCREDITVAL 0x2002
  93 +#define DL_TC0TXBUFFERSIZE 0x2005
  94 +#define DL_PEERTC0PRESENT 0x2046
  95 +#define DL_PEERTC0RXINITCREVAL 0x2047
  96 +#define DL_TC1TXMAXSDUSIZE 0x2003
  97 +#define DL_TC1RXINITCREDITVAL 0x2004
  98 +#define DL_TC1TXBUFFERSIZE 0x2006
  99 +#define DL_PEERTC1PRESENT 0x2066
  100 +#define DL_PEERTC1RXINITCREVAL 0x2067
  101 +
  102 +/*
  103 + * Network Layer Attributes
  104 + */
  105 +#define N_DEVICEID 0x3000
  106 +#define N_DEVICEID_VALID 0x3001
  107 +#define N_TC0TXMAXSDUSIZE 0x3020
  108 +#define N_TC1TXMAXSDUSIZE 0x3021
  109 +
  110 +/*
  111 + * Transport Layer Attributes
  112 + */
  113 +#define T_NUMCPORTS 0x4000
  114 +#define T_NUMTESTFEATURES 0x4001
  115 +#define T_CONNECTIONSTATE 0x4020
  116 +#define T_PEERDEVICEID 0x4021
  117 +#define T_PEERCPORTID 0x4022
  118 +#define T_TRAFFICCLASS 0x4023
  119 +#define T_PROTOCOLID 0x4024
  120 +#define T_CPORTFLAGS 0x4025
  121 +#define T_TXTOKENVALUE 0x4026
  122 +#define T_RXTOKENVALUE 0x4027
  123 +#define T_LOCALBUFFERSPACE 0x4028
  124 +#define T_PEERBUFFERSPACE 0x4029
  125 +#define T_CREDITSTOSEND 0x402A
  126 +#define T_CPORTMODE 0x402B
  127 +#define T_TC0TXMAXSDUSIZE 0x4060
  128 +#define T_TC1TXMAXSDUSIZE 0x4061
  129 +
  130 +#endif /* _UNIPRO_H_ */