aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYaniv Gardi <ygardi@codeaurora.org>2016-03-10 10:37:10 -0500
committerMartin K. Petersen <martin.petersen@oracle.com>2016-03-14 21:04:45 -0400
commitc58ab7aab71e2c783087115f0ce1623c2fdcf0b2 (patch)
treefac4f86f285d9b49e0be67b6075407fb3eb6437d
parentb573d484e4ff33b60b1ef95ca30f199e749ff7c9 (diff)
scsi: ufs: separate device and host quirks
Currently we use the host quirks mechanism in order to handle both device and host controller quirks. In order to support various of UFS devices we should separate handling the device quirks from the host controller's. Reviewed-by: Gilad Broner <gbroner@codeaurora.org> Reviewed-by: Hannes Reinecke <hare@suse.de> Signed-off-by: Raviv Shvili <rshvili@codeaurora.org> Signed-off-by: Yaniv Gardi <ygardi@codeaurora.org> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
-rw-r--r--drivers/scsi/ufs/ufs.h31
-rw-r--r--drivers/scsi/ufs/ufs_quirks.h139
-rw-r--r--drivers/scsi/ufs/ufshcd.c71
-rw-r--r--drivers/scsi/ufs/ufshcd.h3
4 files changed, 244 insertions, 0 deletions
diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index aacb23521ef0..8ec63566d71d 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -196,6 +196,37 @@ enum unit_desc_param {
196 UNIT_DESC_PARAM_LARGE_UNIT_SIZE_M1 = 0x22, 196 UNIT_DESC_PARAM_LARGE_UNIT_SIZE_M1 = 0x22,
197}; 197};
198 198
199/* Device descriptor parameters offsets in bytes*/
200enum device_desc_param {
201 DEVICE_DESC_PARAM_LEN = 0x0,
202 DEVICE_DESC_PARAM_TYPE = 0x1,
203 DEVICE_DESC_PARAM_DEVICE_TYPE = 0x2,
204 DEVICE_DESC_PARAM_DEVICE_CLASS = 0x3,
205 DEVICE_DESC_PARAM_DEVICE_SUB_CLASS = 0x4,
206 DEVICE_DESC_PARAM_PRTCL = 0x5,
207 DEVICE_DESC_PARAM_NUM_LU = 0x6,
208 DEVICE_DESC_PARAM_NUM_WLU = 0x7,
209 DEVICE_DESC_PARAM_BOOT_ENBL = 0x8,
210 DEVICE_DESC_PARAM_DESC_ACCSS_ENBL = 0x9,
211 DEVICE_DESC_PARAM_INIT_PWR_MODE = 0xA,
212 DEVICE_DESC_PARAM_HIGH_PR_LUN = 0xB,
213 DEVICE_DESC_PARAM_SEC_RMV_TYPE = 0xC,
214 DEVICE_DESC_PARAM_SEC_LU = 0xD,
215 DEVICE_DESC_PARAM_BKOP_TERM_LT = 0xE,
216 DEVICE_DESC_PARAM_ACTVE_ICC_LVL = 0xF,
217 DEVICE_DESC_PARAM_SPEC_VER = 0x10,
218 DEVICE_DESC_PARAM_MANF_DATE = 0x12,
219 DEVICE_DESC_PARAM_MANF_NAME = 0x14,
220 DEVICE_DESC_PARAM_PRDCT_NAME = 0x15,
221 DEVICE_DESC_PARAM_SN = 0x16,
222 DEVICE_DESC_PARAM_OEM_ID = 0x17,
223 DEVICE_DESC_PARAM_MANF_ID = 0x18,
224 DEVICE_DESC_PARAM_UD_OFFSET = 0x1A,
225 DEVICE_DESC_PARAM_UD_LEN = 0x1B,
226 DEVICE_DESC_PARAM_RTT_CAP = 0x1C,
227 DEVICE_DESC_PARAM_FRQ_RTC = 0x1D,
228};
229
199/* 230/*
200 * Logical Unit Write Protect 231 * Logical Unit Write Protect
201 * 00h: LU not write protected 232 * 00h: LU not write protected
diff --git a/drivers/scsi/ufs/ufs_quirks.h b/drivers/scsi/ufs/ufs_quirks.h
new file mode 100644
index 000000000000..62ebd89fd787
--- /dev/null
+++ b/drivers/scsi/ufs/ufs_quirks.h
@@ -0,0 +1,139 @@
1/*
2 * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 */
14
15#ifndef _UFS_QUIRKS_H_
16#define _UFS_QUIRKS_H_
17
18/* return true if s1 is a prefix of s2 */
19#define STR_PRFX_EQUAL(s1, s2) !strncmp(s1, s2, strlen(s1))
20
21#define UFS_ANY_VENDOR -1
22#define UFS_ANY_MODEL "ANY_MODEL"
23
24#define MAX_MODEL_LEN 16
25
26#define UFS_VENDOR_TOSHIBA 0x198
27#define UFS_VENDOR_SAMSUNG 0x1CE
28
29/**
30 * ufs_device_info - ufs device details
31 * @wmanufacturerid: card details
32 * @model: card model
33 */
34struct ufs_device_info {
35 u16 wmanufacturerid;
36 char model[MAX_MODEL_LEN + 1];
37};
38
39/**
40 * ufs_dev_fix - ufs device quirk info
41 * @card: ufs card details
42 * @quirk: device quirk
43 */
44struct ufs_dev_fix {
45 struct ufs_device_info card;
46 unsigned int quirk;
47};
48
49#define END_FIX { { 0 }, 0 }
50
51/* add specific device quirk */
52#define UFS_FIX(_vendor, _model, _quirk) \
53 { \
54 .card.wmanufacturerid = (_vendor),\
55 .card.model = (_model), \
56 .quirk = (_quirk), \
57 }
58
59/*
60 * If UFS device is having issue in processing LCC (Line Control
61 * Command) coming from UFS host controller then enable this quirk.
62 * When this quirk is enabled, host controller driver should disable
63 * the LCC transmission on UFS host controller (by clearing
64 * TX_LCC_ENABLE attribute of host to 0).
65 */
66#define UFS_DEVICE_QUIRK_BROKEN_LCC (1 << 0)
67
68/*
69 * Some UFS devices don't need VCCQ rail for device operations. Enabling this
70 * quirk for such devices will make sure that VCCQ rail is not voted.
71 */
72#define UFS_DEVICE_NO_VCCQ (1 << 1)
73
74/*
75 * Some vendor's UFS device sends back to back NACs for the DL data frames
76 * causing the host controller to raise the DFES error status. Sometimes
77 * such UFS devices send back to back NAC without waiting for new
78 * retransmitted DL frame from the host and in such cases it might be possible
79 * the Host UniPro goes into bad state without raising the DFES error
80 * interrupt. If this happens then all the pending commands would timeout
81 * only after respective SW command (which is generally too large).
82 *
83 * We can workaround such device behaviour like this:
84 * - As soon as SW sees the DL NAC error, it should schedule the error handler
85 * - Error handler would sleep for 50ms to see if there are any fatal errors
86 * raised by UFS controller.
87 * - If there are fatal errors then SW does normal error recovery.
88 * - If there are no fatal errors then SW sends the NOP command to device
89 * to check if link is alive.
90 * - If NOP command times out, SW does normal error recovery
91 * - If NOP command succeed, skip the error handling.
92 *
93 * If DL NAC error is seen multiple times with some vendor's UFS devices then
94 * enable this quirk to initiate quick error recovery and also silence related
95 * error logs to reduce spamming of kernel logs.
96 */
97#define UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS (1 << 2)
98
99/*
100 * Some UFS devices may not work properly after resume if the link was kept
101 * in off state during suspend. Enabling this quirk will not allow the
102 * link to be kept in off state during suspend.
103 */
104#define UFS_DEVICE_QUIRK_NO_LINK_OFF (1 << 3)
105
106/*
107 * Few Toshiba UFS device models advertise RX_MIN_ACTIVATETIME_CAPABILITY as
108 * 600us which may not be enough for reliable hibern8 exit hardware sequence
109 * from UFS device.
110 * To workaround this issue, host should set its PA_TACTIVATE time to 1ms even
111 * if device advertises RX_MIN_ACTIVATETIME_CAPABILITY less than 1ms.
112 */
113#define UFS_DEVICE_QUIRK_PA_TACTIVATE (1 << 4)
114
115/*
116 * Some UFS memory devices may have really low read/write throughput in
117 * FAST AUTO mode, enable this quirk to make sure that FAST AUTO mode is
118 * never enabled for such devices.
119 */
120#define UFS_DEVICE_NO_FASTAUTO (1 << 5)
121
122struct ufs_hba;
123void ufs_advertise_fixup_device(struct ufs_hba *hba);
124
125static struct ufs_dev_fix ufs_fixups[] = {
126 /* UFS cards deviations table */
127 UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, UFS_DEVICE_NO_VCCQ),
128 UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL,
129 UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS),
130 UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL,
131 UFS_DEVICE_NO_FASTAUTO),
132 UFS_FIX(UFS_VENDOR_TOSHIBA, "THGLF2G9C8KBADG",
133 UFS_DEVICE_QUIRK_PA_TACTIVATE),
134 UFS_FIX(UFS_VENDOR_TOSHIBA, "THGLF2G9D8KBADG",
135 UFS_DEVICE_QUIRK_PA_TACTIVATE),
136
137 END_FIX
138};
139#endif /* UFS_QUIRKS_H_ */
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index e2ed41587f56..f8b458fb258a 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -42,6 +42,7 @@
42#include <linux/nls.h> 42#include <linux/nls.h>
43#include <linux/of.h> 43#include <linux/of.h>
44#include "ufshcd.h" 44#include "ufshcd.h"
45#include "ufs_quirks.h"
45#include "unipro.h" 46#include "unipro.h"
46 47
47#define UFSHCD_ENABLE_INTRS (UTP_TRANSFER_REQ_COMPL |\ 48#define UFSHCD_ENABLE_INTRS (UTP_TRANSFER_REQ_COMPL |\
@@ -4564,6 +4565,75 @@ out:
4564 return ret; 4565 return ret;
4565} 4566}
4566 4567
4568static int ufs_get_device_info(struct ufs_hba *hba,
4569 struct ufs_device_info *card_data)
4570{
4571 int err;
4572 u8 model_index;
4573 u8 str_desc_buf[QUERY_DESC_STRING_MAX_SIZE + 1] = {0};
4574 u8 desc_buf[QUERY_DESC_DEVICE_MAX_SIZE];
4575
4576 err = ufshcd_read_device_desc(hba, desc_buf,
4577 QUERY_DESC_DEVICE_MAX_SIZE);
4578 if (err) {
4579 dev_err(hba->dev, "%s: Failed reading Device Desc. err = %d\n",
4580 __func__, err);
4581 goto out;
4582 }
4583
4584 /*
4585 * getting vendor (manufacturerID) and Bank Index in big endian
4586 * format
4587 */
4588 card_data->wmanufacturerid = desc_buf[DEVICE_DESC_PARAM_MANF_ID] << 8 |
4589 desc_buf[DEVICE_DESC_PARAM_MANF_ID + 1];
4590
4591 model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME];
4592
4593 err = ufshcd_read_string_desc(hba, model_index, str_desc_buf,
4594 QUERY_DESC_STRING_MAX_SIZE, ASCII_STD);
4595 if (err) {
4596 dev_err(hba->dev, "%s: Failed reading Product Name. err = %d\n",
4597 __func__, err);
4598 goto out;
4599 }
4600
4601 str_desc_buf[QUERY_DESC_STRING_MAX_SIZE] = '\0';
4602 strlcpy(card_data->model, (str_desc_buf + QUERY_DESC_HDR_SIZE),
4603 min_t(u8, str_desc_buf[QUERY_DESC_LENGTH_OFFSET],
4604 MAX_MODEL_LEN));
4605
4606 /* Null terminate the model string */
4607 card_data->model[MAX_MODEL_LEN] = '\0';
4608
4609out:
4610 return err;
4611}
4612
4613void ufs_advertise_fixup_device(struct ufs_hba *hba)
4614{
4615 int err;
4616 struct ufs_dev_fix *f;
4617 struct ufs_device_info card_data;
4618
4619 card_data.wmanufacturerid = 0;
4620
4621 err = ufs_get_device_info(hba, &card_data);
4622 if (err) {
4623 dev_err(hba->dev, "%s: Failed getting device info. err = %d\n",
4624 __func__, err);
4625 return;
4626 }
4627
4628 for (f = ufs_fixups; f->quirk; f++) {
4629 if (((f->card.wmanufacturerid == card_data.wmanufacturerid) ||
4630 (f->card.wmanufacturerid == UFS_ANY_VENDOR)) &&
4631 (STR_PRFX_EQUAL(f->card.model, card_data.model) ||
4632 !strcmp(f->card.model, UFS_ANY_MODEL)))
4633 hba->dev_quirks |= f->quirk;
4634 }
4635}
4636
4567/** 4637/**
4568 * ufshcd_probe_hba - probe hba to detect device and initialize 4638 * ufshcd_probe_hba - probe hba to detect device and initialize
4569 * @hba: per-adapter instance 4639 * @hba: per-adapter instance
@@ -4591,6 +4661,7 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
4591 if (ret) 4661 if (ret)
4592 goto out; 4662 goto out;
4593 4663
4664 ufs_advertise_fixup_device(hba);
4594 /* UFS device is also active now */ 4665 /* UFS device is also active now */
4595 ufshcd_set_ufs_dev_active(hba); 4666 ufshcd_set_ufs_dev_active(hba);
4596 ufshcd_force_reset_auto_bkops(hba); 4667 ufshcd_force_reset_auto_bkops(hba);
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 54e13ccb5754..77e79c00ef8c 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -470,6 +470,9 @@ struct ufs_hba {
470 470
471 unsigned int quirks; /* Deviations from standard UFSHCI spec. */ 471 unsigned int quirks; /* Deviations from standard UFSHCI spec. */
472 472
473 /* Device deviations from standard UFS device spec. */
474 unsigned int dev_quirks;
475
473 wait_queue_head_t tm_wq; 476 wait_queue_head_t tm_wq;
474 wait_queue_head_t tm_tag_wq; 477 wait_queue_head_t tm_tag_wq;
475 unsigned long tm_condition; 478 unsigned long tm_condition;