diff options
author | Seungwon Jeon <tgih.jun@samsung.com> | 2013-08-31 12:10:21 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2013-09-06 19:01:41 -0400 |
commit | 12b4fdb4f6bccb5459a2f75fbe0eab253bfceab4 (patch) | |
tree | b83139cc18787adc3d8ea552ba41563ac9d4c3e0 /drivers/scsi | |
parent | 7d568652d3abc81a6d684d4760571a3ccb6f68d9 (diff) |
[SCSI] ufs: add dme configuration primitives
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 <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>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/ufs/ufshcd.c | 88 | ||||
-rw-r--r-- | drivers/scsi/ufs/ufshcd.h | 51 | ||||
-rw-r--r-- | 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 46b0754b4b76..a4ce6c462614 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c | |||
@@ -235,6 +235,18 @@ static inline int ufshcd_get_uic_cmd_result(struct ufs_hba *hba) | |||
235 | } | 235 | } |
236 | 236 | ||
237 | /** | 237 | /** |
238 | * ufshcd_get_dme_attr_val - Get the value of attribute returned by UIC command | ||
239 | * @hba: Pointer to adapter instance | ||
240 | * | ||
241 | * This function gets UIC command argument3 | ||
242 | * Returns 0 on success, non zero value on error | ||
243 | */ | ||
244 | static inline u32 ufshcd_get_dme_attr_val(struct ufs_hba *hba) | ||
245 | { | ||
246 | return ufshcd_readl(hba, REG_UIC_COMMAND_ARG_3); | ||
247 | } | ||
248 | |||
249 | /** | ||
238 | * ufshcd_get_req_rsp - returns the TR response transaction type | 250 | * ufshcd_get_req_rsp - returns the TR response transaction type |
239 | * @ucd_rsp_ptr: pointer to response UPIU | 251 | * @ucd_rsp_ptr: pointer to response UPIU |
240 | */ | 252 | */ |
@@ -1374,6 +1386,80 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba) | |||
1374 | } | 1386 | } |
1375 | 1387 | ||
1376 | /** | 1388 | /** |
1389 | * ufshcd_dme_set_attr - UIC command for DME_SET, DME_PEER_SET | ||
1390 | * @hba: per adapter instance | ||
1391 | * @attr_sel: uic command argument1 | ||
1392 | * @attr_set: attribute set type as uic command argument2 | ||
1393 | * @mib_val: setting value as uic command argument3 | ||
1394 | * @peer: indicate whether peer or local | ||
1395 | * | ||
1396 | * Returns 0 on success, non-zero value on failure | ||
1397 | */ | ||
1398 | int ufshcd_dme_set_attr(struct ufs_hba *hba, u32 attr_sel, | ||
1399 | u8 attr_set, u32 mib_val, u8 peer) | ||
1400 | { | ||
1401 | struct uic_command uic_cmd = {0}; | ||
1402 | static const char *const action[] = { | ||
1403 | "dme-set", | ||
1404 | "dme-peer-set" | ||
1405 | }; | ||
1406 | const char *set = action[!!peer]; | ||
1407 | int ret; | ||
1408 | |||
1409 | uic_cmd.command = peer ? | ||
1410 | UIC_CMD_DME_PEER_SET : UIC_CMD_DME_SET; | ||
1411 | uic_cmd.argument1 = attr_sel; | ||
1412 | uic_cmd.argument2 = UIC_ARG_ATTR_TYPE(attr_set); | ||
1413 | uic_cmd.argument3 = mib_val; | ||
1414 | |||
1415 | ret = ufshcd_send_uic_cmd(hba, &uic_cmd); | ||
1416 | if (ret) | ||
1417 | dev_err(hba->dev, "%s: attr-id 0x%x val 0x%x error code %d\n", | ||
1418 | set, UIC_GET_ATTR_ID(attr_sel), mib_val, ret); | ||
1419 | |||
1420 | return ret; | ||
1421 | } | ||
1422 | EXPORT_SYMBOL_GPL(ufshcd_dme_set_attr); | ||
1423 | |||
1424 | /** | ||
1425 | * ufshcd_dme_get_attr - UIC command for DME_GET, DME_PEER_GET | ||
1426 | * @hba: per adapter instance | ||
1427 | * @attr_sel: uic command argument1 | ||
1428 | * @mib_val: the value of the attribute as returned by the UIC command | ||
1429 | * @peer: indicate whether peer or local | ||
1430 | * | ||
1431 | * Returns 0 on success, non-zero value on failure | ||
1432 | */ | ||
1433 | int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel, | ||
1434 | u32 *mib_val, u8 peer) | ||
1435 | { | ||
1436 | struct uic_command uic_cmd = {0}; | ||
1437 | static const char *const action[] = { | ||
1438 | "dme-get", | ||
1439 | "dme-peer-get" | ||
1440 | }; | ||
1441 | const char *get = action[!!peer]; | ||
1442 | int ret; | ||
1443 | |||
1444 | uic_cmd.command = peer ? | ||
1445 | UIC_CMD_DME_PEER_GET : UIC_CMD_DME_GET; | ||
1446 | uic_cmd.argument1 = attr_sel; | ||
1447 | |||
1448 | ret = ufshcd_send_uic_cmd(hba, &uic_cmd); | ||
1449 | if (ret) { | ||
1450 | dev_err(hba->dev, "%s: attr-id 0x%x error code %d\n", | ||
1451 | get, UIC_GET_ATTR_ID(attr_sel), ret); | ||
1452 | goto out; | ||
1453 | } | ||
1454 | |||
1455 | if (mib_val) | ||
1456 | *mib_val = uic_cmd.argument3; | ||
1457 | out: | ||
1458 | return ret; | ||
1459 | } | ||
1460 | EXPORT_SYMBOL_GPL(ufshcd_dme_get_attr); | ||
1461 | |||
1462 | /** | ||
1377 | * ufshcd_complete_dev_init() - checks device readiness | 1463 | * ufshcd_complete_dev_init() - checks device readiness |
1378 | * hba: per-adapter instance | 1464 | * hba: per-adapter instance |
1379 | * | 1465 | * |
@@ -1908,6 +1994,8 @@ static void ufshcd_uic_cmd_compl(struct ufs_hba *hba) | |||
1908 | if (hba->active_uic_cmd) { | 1994 | if (hba->active_uic_cmd) { |
1909 | hba->active_uic_cmd->argument2 |= | 1995 | hba->active_uic_cmd->argument2 |= |
1910 | ufshcd_get_uic_cmd_result(hba); | 1996 | ufshcd_get_uic_cmd_result(hba); |
1997 | hba->active_uic_cmd->argument3 = | ||
1998 | ufshcd_get_dme_attr_val(hba); | ||
1911 | complete(&hba->active_uic_cmd->done); | 1999 | complete(&hba->active_uic_cmd->done); |
1912 | } | 2000 | } |
1913 | } | 2001 | } |
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 59c9c4848be1..648ab16d379c 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h | |||
@@ -263,4 +263,55 @@ static inline void check_upiu_size(void) | |||
263 | extern int ufshcd_runtime_suspend(struct ufs_hba *hba); | 263 | extern int ufshcd_runtime_suspend(struct ufs_hba *hba); |
264 | extern int ufshcd_runtime_resume(struct ufs_hba *hba); | 264 | extern int ufshcd_runtime_resume(struct ufs_hba *hba); |
265 | extern int ufshcd_runtime_idle(struct ufs_hba *hba); | 265 | extern int ufshcd_runtime_idle(struct ufs_hba *hba); |
266 | extern int ufshcd_dme_set_attr(struct ufs_hba *hba, u32 attr_sel, | ||
267 | u8 attr_set, u32 mib_val, u8 peer); | ||
268 | extern int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel, | ||
269 | u32 *mib_val, u8 peer); | ||
270 | |||
271 | /* UIC command interfaces for DME primitives */ | ||
272 | #define DME_LOCAL 0 | ||
273 | #define DME_PEER 1 | ||
274 | #define ATTR_SET_NOR 0 /* NORMAL */ | ||
275 | #define ATTR_SET_ST 1 /* STATIC */ | ||
276 | |||
277 | static inline int ufshcd_dme_set(struct ufs_hba *hba, u32 attr_sel, | ||
278 | u32 mib_val) | ||
279 | { | ||
280 | return ufshcd_dme_set_attr(hba, attr_sel, ATTR_SET_NOR, | ||
281 | mib_val, DME_LOCAL); | ||
282 | } | ||
283 | |||
284 | static inline int ufshcd_dme_st_set(struct ufs_hba *hba, u32 attr_sel, | ||
285 | u32 mib_val) | ||
286 | { | ||
287 | return ufshcd_dme_set_attr(hba, attr_sel, ATTR_SET_ST, | ||
288 | mib_val, DME_LOCAL); | ||
289 | } | ||
290 | |||
291 | static inline int ufshcd_dme_peer_set(struct ufs_hba *hba, u32 attr_sel, | ||
292 | u32 mib_val) | ||
293 | { | ||
294 | return ufshcd_dme_set_attr(hba, attr_sel, ATTR_SET_NOR, | ||
295 | mib_val, DME_PEER); | ||
296 | } | ||
297 | |||
298 | static inline int ufshcd_dme_peer_st_set(struct ufs_hba *hba, u32 attr_sel, | ||
299 | u32 mib_val) | ||
300 | { | ||
301 | return ufshcd_dme_set_attr(hba, attr_sel, ATTR_SET_ST, | ||
302 | mib_val, DME_PEER); | ||
303 | } | ||
304 | |||
305 | static inline int ufshcd_dme_get(struct ufs_hba *hba, | ||
306 | u32 attr_sel, u32 *mib_val) | ||
307 | { | ||
308 | return ufshcd_dme_get_attr(hba, attr_sel, mib_val, DME_LOCAL); | ||
309 | } | ||
310 | |||
311 | static inline int ufshcd_dme_peer_get(struct ufs_hba *hba, | ||
312 | u32 attr_sel, u32 *mib_val) | ||
313 | { | ||
314 | return ufshcd_dme_get_attr(hba, attr_sel, mib_val, DME_PEER); | ||
315 | } | ||
316 | |||
266 | #endif /* End of Header */ | 317 | #endif /* End of Header */ |
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h index 739ae3aade0e..1e1fe2668181 100644 --- a/drivers/scsi/ufs/ufshci.h +++ b/drivers/scsi/ufs/ufshci.h | |||
@@ -191,6 +191,12 @@ enum { | |||
191 | #define CONFIG_RESULT_CODE_MASK 0xFF | 191 | #define CONFIG_RESULT_CODE_MASK 0xFF |
192 | #define GENERIC_ERROR_CODE_MASK 0xFF | 192 | #define GENERIC_ERROR_CODE_MASK 0xFF |
193 | 193 | ||
194 | #define UIC_ARG_MIB_SEL(attr, sel) ((((attr) & 0xFFFF) << 16) |\ | ||
195 | ((sel) & 0xFFFF)) | ||
196 | #define UIC_ARG_MIB(attr) UIC_ARG_MIB_SEL(attr, 0) | ||
197 | #define UIC_ARG_ATTR_TYPE(t) (((t) & 0xFF) << 16) | ||
198 | #define UIC_GET_ATTR_ID(v) (((v) >> 16) & 0xFFFF) | ||
199 | |||
194 | /* UIC Commands */ | 200 | /* UIC Commands */ |
195 | enum { | 201 | enum { |
196 | UIC_CMD_DME_GET = 0x01, | 202 | UIC_CMD_DME_GET = 0x01, |