scsi: ufs: set the device reference clock setting
A message that is not in the archive (sent off-list or not yet received): [email protected]
PATCH v12 1/2 scsi: ufs: set the device reference clock setting
From: Subhash Jadavani <[email protected]>
UFS host supplies the reference clock to UFS device and UFS device specification allows host to provide one of the 4 frequencies (19.2 MHz, 26 MHz, 38.4 MHz, 52 MHz) for reference clock. Host should set the device reference clock frequency setting in the device based on what frequency it is supplying to UFS device.
--- drivers/scsi/ufs/ufs.h | 14 +++++++ drivers/scsi/ufs/ufshcd-pltfrm.c | 2 + drivers/scsi/ufs/ufshcd.c | 90 ++++++++++++++++++++++++++++++++++++++++ drivers/scsi/ufs/ufshcd.h | 2 + 4 files changed, 108 insertions(+)
drivers/scsi/ufs/ufs.h +14 -0
@@ -378,6 +378,20 @@ enum query_opcode { UPIU_QUERY_OPCODE_TOGGLE_FLAG = 0x8, }; +/* bRefClkFreq attribute values */ +enum ufs_ref_clk_freq { +REF_CLK_FREQ_19_2_MHZ =0 , +REF_CLK_FREQ_26_MHZ =1 , +REF_CLK_FREQ_38_4_MHZ =2 , +REF_CLK_FREQ_52_MHZ =3 , +REF_CLK_FREQ_INVAL =-1 , +}; + +struct ufs_ref_clk { +u32 freq_hz; +enum ufs_ref_clk_freq val; +}; +/* Query response result code */ enum {QUERY_RESULT_SUCCESS =0x00 ,
drivers/scsi/ufs/ufshcd-pltfrm.c +2 -0
@@ -343,6 +343,8 @@ int ufshcd_pltfrm_init(struct platform_device *pdev,pm_runtime_set_active (&pdev->dev);pm_runtime_enable (&pdev->dev); +ufshcd_parse_dev_ref_clk_freq (hba); +ufshcd_init_lanes_per_dir (hba); err =ufshcd_init (hba, mmio_base, irq);
drivers/scsi/ufs/ufshcd.c +90 -0
108 lines not on this page · raw message
drivers/scsi/ufs/ufshcd.h +2 -0
@@ -548,6 +548,7 @@ struct ufs_hba {void *priv;unsigned int irq;bool is_irq_enabled; +enum ufs_ref_clk_freq dev_ref_clk_freq;/* Interrupt aggregation support is broken */ #define UFSHCD_QUIRK_BROKEN_INTR_AGGR 0x1
@@ -746,6 +747,7 @@ static inline void ufshcd_rmwl(struct ufs_hba *hba, u32 mask, u32 val, u32 reg)int ufshcd_wait_for_register (struct ufs_hba *hba,u32 reg,u32 mask,u32 val,unsigned long interval_us,unsigned long timeout_ms,bool can_sleep); +void ufshcd_parse_dev_ref_clk_freq (struct ufs_hba *hba);static inline void check_upiu_size (void ) {
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
PATCH v12 2/2 scsi: ufs: Add configfs support for UFS provisioning
In reply to a message not in the archiveThis patch adds configfs support to provision UFS device at runtime. This feature can be primarily useful in factory or assembly line as some devices may be required to be configured multiple times during initial system development phase. Configuration Descriptors can be written multiple times until bConfigDescrLock attribute is zero.
Configuration descriptor buffer consists of Device and Unit descriptor configurable parameters which are parsed from vendor specific provisioning file and then passed via configfs node at runtime to provision ufs device.CONFIG_CONFIGFS_FS and CONFIG_UFS_PROVISION needs to be enabled for using this feature.
Usage:
1) To read current configuration descriptor with index X (where index X can be 0/1/2/3) :
cat /config/XXXX.ufshc/ufs_config_desc_X
2) To write configuration descriptor with index X :
echo <config_desc_buf> > /config/XXXX.ufshc/ufs_config_desc_X
--- Documentation/ABI/testing/configfs-driver-ufs | 12 ++ drivers/scsi/ufs/Kconfig | 10 ++ drivers/scsi/ufs/Makefile | 1 + drivers/scsi/ufs/ufs-configfs.c | 232 ++++++++++++++++++++++++++ drivers/scsi/ufs/ufshcd.c | 3 +- drivers/scsi/ufs/ufshcd.h | 17 ++ 6 files changed, 274 insertions(+), 1 deletion(-) create mode 100644 Documentation/ABI/testing/configfs-driver-ufs create mode 100644 drivers/scsi/ufs/ufs-configfs.c
Documentation/ABI/testing/configfs-driver-ufs new file +12 -0
@@ -0,0 +1,12 @@ +What: /config/*/ufs_config_desc_X +Date: Jun 2018 +KernelVersion: 4.19 +Description: + This file shows bytes of the current ufs configuration descriptor + with index X (where X = 0/1/2/3) set in device. This can be used to + provision ufs device if bConfigDescrLock is 0. + For more details, refer 14.1.6.3 Configuration Descriptor and + table 14-12 - Unit Descriptor configurable parameters from specs for + description and format of each configuration descriptor parameter. + Parameters of Configuration descriptor buffer for respective index + needs to be passed as bytes in space separated format.
drivers/scsi/ufs/Kconfig +10 -0
@@ -100,3 +100,13 @@ config SCSI_UFS_QCOM Select this if you have UFS controller on QCOM chipset. If unsure, say N. + +config UFS_PROVISION + tristate "Runtime UFS Provisioning support" + depends on SCSI_UFSHCD && CONFIGFS_FS + help + This enables runtime UFS provisioning support. This can be used + primarily during assembly line as some devices may be required to + be configured multiple times during initial development phase. + + If unsure, say N.
drivers/scsi/ufs/Makefile +1 -0
@@ -5,5 +5,6 @@ obj-$(CONFIG_SCSI_UFS_DWC_TC_PLATFORM) += tc-dwc-g210-pltfrm.o ufshcd-dwc.o tc-d obj-$(CONFIG_SCSI_UFS_QCOM) += ufs-qcom.o obj-$(CONFIG_SCSI_UFSHCD) += ufshcd-core.o ufshcd-core-objs := ufshcd.o ufs-sysfs.o +obj-$(CONFIG_UFS_PROVISION) += ufs-configfs.o obj-$(CONFIG_SCSI_UFSHCD_PCI) += ufshcd-pci.o obj-$(CONFIG_SCSI_UFSHCD_PLATFORM) += ufshcd-pltfrm.o
drivers/scsi/ufs/ufs-configfs.c new file +232 -0
232 lines not on this page · raw message
drivers/scsi/ufs/ufshcd.c +2 -1
@@ -7711,6 +7711,7 @@ int ufshcd_shutdown(struct ufs_hba *hba)void ufshcd_remove (struct ufs_hba *hba) {ufs_sysfs_remove_nodes (hba->dev); +ufshcd_configfs_exit (hba);scsi_remove_host (hba->host);/* disable interrupts */ ufshcd_disable_intr (hba, hba->intr_mask);
@@ -7965,7 +7966,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)async_schedule (ufshcd_async_scan, hba);ufs_sysfs_add_nodes (hba->dev); - +ufshcd_configfs_init (hba,dev_name (hba->dev));return 0 ; out_remove_scsi_host:
drivers/scsi/ufs/ufshcd.h +17 -0
@@ -37,6 +37,7 @@#ifndef _UFSHCD_H#define _UFSHCD_H +#include <linux/configfs.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h>
@@ -515,6 +516,9 @@ struct ufs_hba {struct Scsi_Host *host;struct device *dev; +#ifdef CONFIG_UFS_PROVISION +struct configfs_subsystem subsys; +#endif /* * This field is to keep a reference to "scsi_device" corresponding to * "UFS device" W-LU.
@@ -868,6 +872,19 @@ int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index,int ufshcd_hold (struct ufs_hba *hba,bool async);void ufshcd_release (struct ufs_hba *hba); +/* Expose UFS configfs API's */ +#ifndef CONFIG_UFS_PROVISION +static inline void ufshcd_configfs_init (struct ufs_hba *hba,const char *name) +{ +} +static inline void ufshcd_configfs_exit (struct ufs_hba *hba) +{ +} +#else +void ufshcd_configfs_init (struct ufs_hba *hba,const char *name); +void ufshcd_configfs_exit (struct ufs_hba *hba); +#endif +int ufshcd_map_desc_id_to_length (struct ufs_hba *hba,enum desc_idn desc_id,int *desc_length);
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
Re: [PATCH V12 2/2] scsi: ufs: Add configfs support for UFS provisioning
Quoted 24 lines · Sayali Lokhande
This patch adds configfs support to provision UFS device at runtime. This feature can be primarily useful in factory or assembly line as some devices may be required to be configured multiple times during initial system development phase. Configuration Descriptors can be written multiple times until bConfigDescrLock attribute is zero.
Configuration descriptor buffer consists of Device and Unit descriptor configurable parameters which are parsed from vendor specific provisioning file and then passed via configfs node at runtime to provision ufs device.
CONFIG_CONFIGFS_FSandCONFIG_UFS_PROVISIONneeds to be enabled for using this feature.Usage:
1) To read current configuration descriptor with index X (where index X can be 0/1/2/3) :
cat /config/XXXX.ufshc/ufs_config_desc_X2) To write configuration descriptor with index X :
echo <config_desc_buf> > /config/XXXX.ufshc/ufs_config_desc_XSigned-off-by Sayali Lokhande <[email protected]>---
<SNIP>
Quoted 1 line
+static struct
configfs_attributeufshcd_attr_provision_0= {
Actually, wasn't the original suggestion to use a binary attribute? i.e. configfs_bin_attribute
Re: [PATCH V12 2/2] scsi: ufs: Add configfs support for UFS provisioning
Quoted 23 lines · Adrian Hunter
Quoted 22 lines · Sayali Lokhande
This patch adds configfs support to provision UFS device at runtime. This feature can be primarily useful in factory or assembly line as some devices may be required to be configured multiple times during initial system development phase. Configuration Descriptors can be written multiple times until bConfigDescrLock attribute is zero.
Configuration descriptor buffer consists of Device and Unit descriptor configurable parameters which are parsed from vendor specific provisioning file and then passed via configfs node at runtime to provision ufs device.
CONFIG_CONFIGFS_FSandCONFIG_UFS_PROVISIONneeds to be enabled for using this feature.Usage:
1) To read current configuration descriptor with index X(where index X can be 0/1/2/3) : cat /config/XXXX.ufshc/ufs_config_desc_X2) To write configuration descriptor with index X :
echo <config_desc_buf> > /config/XXXX.ufshc/ufs_config_desc_X
Quoted 7 lines
Quoted 2 lines
Signed-off-by Sayali Lokhande <[email protected]>---
<SNIP>
Quoted 1 line
+static struct
configfs_attributeufshcd_attr_provision_0= {Actually, wasn't the original suggestion to use a binary attribute? i.e.
configfs_bin_attribute
Yes. we did discuss about having binary attribute in between , but then it was thought if anyone who wants to use this interface from a shell script, it will be much easier to write multiple ASCII attributes than a single binary attribute. It seemed more readable for users and easier/comfortable to compare any value to default spec value(if required).
Re: [PATCH V12 2/2] scsi: ufs: Add configfs support for UFS provisioning
In reply to Sayali LokhandeQuoted 14 lines · Sayali Lokhande
This patch adds configfs support to provision UFS device at runtime. This feature can be primarily useful in factory or assembly line as some devices may be required to be configured multiple times during initial system development phase. Configuration Descriptors can be written multiple times until bConfigDescrLock attribute is zero.
Configuration descriptor buffer consists of Device and Unit descriptor configurable parameters which are parsed from vendor specific provisioning file and then passed via configfs node at runtime to provision ufs device.
CONFIG_CONFIGFS_FSandCONFIG_UFS_PROVISIONneeds to be enabled for using this feature.
Quoted 4 lines
Usage:
1) To read current configuration descriptor with index X (where index X can be 0/1/2/3) :
cat /config/XXXX.ufshc/ufs_config_desc_X
Device name could be nearly anything, not necessarily in the form XXXX.ufshc, so maybe make this :
cat /config/<device name>/ufs_config_desc_X
Quoted 3 lines
2) To write configuration descriptor with index X :
echo <config_desc_buf> > /config/XXXX.ufshc/ufs_config_desc_X
Ditto
Quoted 19 lines
Signed-off-by Sayali Lokhande <[email protected]>--- Documentation/ABI/testing/configfs-driver-ufs | 12 ++ drivers/scsi/ufs/Kconfig | 10 ++ drivers/scsi/ufs/Makefile | 1 + drivers/scsi/ufs/ufs-configfs.c | 232 ++++++++++++++++++++++++++ drivers/scsi/ufs/ufshcd.c | 3 +- drivers/scsi/ufs/ufshcd.h | 17 ++ 6 files changed, 274 insertions(+), 1 deletion(-) create mode 100644 Documentation/ABI/testing/configfs-driver-ufs create mode 100644 drivers/scsi/ufs/ufs-configfs.cDocumentation/ABI/testing/configfs-driver-ufs new file +0
-0
Documentation/ABI/testing/configfs-driver-ufs line 3
Quoted 3 lines
Documentation/ABI/testing/configfs-driver-ufs new file +3
-0@@ -0,0 +1,12 @@ +What: /config/*/ufs_config_desc_X +Date: Jun 2018 +KernelVersion: 4.19
4.20 now
Quoted 14 lines
Documentation/ABI/testing/configfs-driver-ufs new file +9
-0+Description: + This file shows bytes of the current ufs configuration descriptor + with index X (where X = 0/1/2/3) set in device. This can be used to + provision ufs device if bConfigDescrLock is 0. + For more details, refer 14.1.6.3 Configuration Descriptor and + table 14-12 - Unit Descriptor configurable parameters from specs for + description and format of each configuration descriptor parameter. + Parameters of Configuration descriptor buffer for respective index + needs to be passed as bytes in space separated format.drivers/scsi/ufs/Kconfig +0
-0
drivers/scsi/ufs/Kconfig config SCSI_UFS_QCOM · line 104
Quoted 5 lines
drivers/scsi/ufs/Kconfig +2
-0@@ -100,3 +100,13 @@ config SCSI_UFS_QCOM Select this if you have UFS controller on QCOM chipset. If unsure, say N. + +config UFS_PROVISION
Better if this is config SCSI_UFS_PROVISION to avoid mixups with UFS filesystem
drivers/scsi/ufs/Kconfig config SCSI_UFS_QCOM · line 105
Quoted 1 line
drivers/scsi/ufs/Kconfig +1
-0+ tristate "Runtime UFS Provisioning support"
tristate won't work with what you have. It will have to be bool
Quoted 60 lines
drivers/scsi/ufs/Kconfig +7
-0+ depends on SCSI_UFSHCD && CONFIGFS_FS + help + This enables runtime UFS provisioning support. This can be used + primarily during assembly line as some devices may be required to + be configured multiple times during initial development phase. + + If unsure, say N.drivers/scsi/ufs/Makefile +1
-0@@ -5,5 +5,6 @@ obj-$(CONFIG_SCSI_UFS_DWC_TC_PLATFORM) += tc-dwc-g210-pltfrm.o ufshcd-dwc.o tc-d obj-$(CONFIG_SCSI_UFS_QCOM) += ufs-qcom.o obj-$(CONFIG_SCSI_UFSHCD) += ufshcd-core.o ufshcd-core-objs := ufshcd.o ufs-sysfs.o +obj-$(CONFIG_UFS_PROVISION) += ufs-configfs.o obj-$(CONFIG_SCSI_UFSHCD_PCI) += ufshcd-pci.o obj-$(CONFIG_SCSI_UFSHCD_PLATFORM) += ufshcd-pltfrm.odrivers/scsi/ufs/ufs-configfs.c new file +36
-0@@ -0,0 +1,232 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2018, Linux Foundation. + +#include <linux/configfs.h> +#include <linux/err.h> +#include <linux/string.h> + +#include "ufs.h" +#include "ufshcd.h" + +static inline struct ufs_hba *config_item_to_hba (struct config_item *item) +{ +struct config_group *group =to_config_group (item); +struct configfs_subsystem *subsys =to_configfs_subsystem (group); + struct ufs_hba *hba = container_of(subsys, struct ufs_hba, subsys); + +return hba; +} + +static ssize_t ufs_config_desc_show (struct config_item *item,char *buf, +u8 index) +{ +struct ufs_hba *hba =config_item_to_hba (item); +u8 *desc_buf =NULL ; +int desc_buf_len = hba->desc_size.conf_desc; +int i, ret, curr_len =0 ; + + desc_buf =kzalloc (desc_buf_len,GFP_KERNEL ); +if (!desc_buf) +return -ENOMEM ; + + ret =ufshcd_query_descriptor_retry (hba,UPIU_QUERY_OPCODE_READ_DESC , +QUERY_DESC_IDN_CONFIGURATION , index,0 , + desc_buf, &desc_buf_len); +if (ret) + goto out;
drivers/scsi/ufs/ufs-configfs.c line 46
Quoted 10 lines
drivers/scsi/ufs/ufs-configfs.c new file +10
-0+ +for (i =0 ; i < desc_buf_len; i++) + curr_len +=snprintf ((buf + curr_len), (PAGE_SIZE - curr_len), +"0x%x " , desc_buf[i]); + +out: +kfree (desc_buf); +if (ret) +return ret; +return curr_len;
Could be:
return ret ?: curr_len;
Quoted 11 lines
drivers/scsi/ufs/ufs-configfs.c new file +11
-0+} + +ssize_t ufshcd_desc_configfs_store (struct config_item *item, +const char *buf,size_t count,u8 index) +{ +char *strbuf; +char *strbuf_copy; +struct ufs_hba *hba =config_item_to_hba (item); +u8 *desc_buf =NULL ; +int desc_buf_len = hba->desc_size.conf_desc; +char *token;
drivers/scsi/ufs/ufs-configfs.c line 67
Quoted 10 lines
drivers/scsi/ufs/ufs-configfs.c new file +10
-0+int i, ret; +u8 value; +u32 config_desc_lock =0 ; + + desc_buf =kzalloc (desc_buf_len,GFP_KERNEL ); +if (!desc_buf) +return -ENOMEM ; + +/* reserve one byte for null termination */ + strbuf =kmalloc (count +1 ,GFP_KERNEL );
buf is null-terminated so just use kstrdup()
Quoted 7 lines
drivers/scsi/ufs/ufs-configfs.c new file +7
-0+if (!strbuf) { + ret = -ENOMEM ; + goto out; + } + + strbuf_copy = strbuf; +strlcpy (strbuf, buf, count +1 );
drivers/scsi/ufs/ufs-configfs.c line 84
Quoted 10 lines
drivers/scsi/ufs/ufs-configfs.c new file +10
-0+ +/* Just return if bConfigDescrLock is already set */ + ret =ufshcd_query_attr (hba,UPIU_QUERY_OPCODE_READ_ATTR , +QUERY_ATTR_IDN_CONF_DESC_LOCK ,0 ,0 , &config_desc_lock); +if (ret) + goto out; + +if (config_desc_lock) { +dev_err (hba->dev,"%s: bConfigDescrLock already set to %u, cannot re-provision device!\n" , + __func__, config_desc_lock);
Indenting is not ideal. Consider some of the suggestions of:scripts/checkpatch.pl --strict
drivers/scsi/ufs/ufs-configfs.c line 91
Quoted 7 lines
drivers/scsi/ufs/ufs-configfs.c new file +7
-0+ ret = -EINVAL ; + goto out; + } + +for (i =0 ; i < desc_buf_len; i++) { + token =strsep (&strbuf_copy," " ); +if (!token && i)
What is 'i' doing here?
If the user does not supply enough bytes, the remainder will be overwritten by 0 which doesn't seem ideal. It would be better to read desc_buf first.
drivers/scsi/ufs/ufs-configfs.c line 96
Quoted 5 lines
drivers/scsi/ufs/ufs-configfs.c new file +5
-0+break ; + + ret =kstrtou8 (token,0 , &value); +if (ret) { + dev_err(hba->dev, "%s: kstrtou8 failed %d %s\n",
User may not understand 'kstrtou8'. 'Invalid value %s writing UFS configuration descriptor %u' would be better.
Quoted 11 lines
drivers/scsi/ufs/ufs-configfs.c new file +11
-0+ __func__, ret, token); + ret = -EINVAL ; + goto out; + } + desc_buf[i] = value; + } + +/* Write configuration descriptor to provision ufs */ + ret =ufshcd_query_descriptor_retry (hba,UPIU_QUERY_OPCODE_WRITE_DESC , +QUERY_DESC_IDN_CONFIGURATION , index,0 , + desc_buf, &desc_buf_len);
drivers/scsi/ufs/ufs-configfs.c line 117
Quoted 10 lines
drivers/scsi/ufs/ufs-configfs.c new file +10
-0+if (!ret) +dev_info (hba->dev,"%s: UFS Configuration Descriptor %u written\n" , + __func__, index); + +out: +kfree (strbuf); +kfree (desc_buf); +if (ret) +return ret; +return count;
Could be:
return ret ?: count;
Quoted 179 lines
drivers/scsi/ufs/ufs-configfs.c new file +115
-0+} + +static ssize_t ufs_config_desc_0_show (struct config_item *item,char *buf) +{ +return ufs_config_desc_show (item, buf,0 ); +} + +static ssize_t ufs_config_desc_0_store (struct config_item *item, +const char *buf,size_t count) +{ +return ufshcd_desc_configfs_store (item, buf, count,0 ); +} + +static ssize_t ufs_config_desc_1_show (struct config_item *item,char *buf) +{ +return ufs_config_desc_show (item, buf,1 ); +} + +static ssize_t ufs_config_desc_1_store (struct config_item *item, +const char *buf,size_t count) +{ +return ufshcd_desc_configfs_store (item, buf, count,1 ); +} + +static ssize_t ufs_config_desc_2_show (struct config_item *item,char *buf) +{ +return ufs_config_desc_show (item, buf,2 ); +} + +static ssize_t ufs_config_desc_2_store (struct config_item *item, +const char *buf,size_t count) +{ +return ufshcd_desc_configfs_store (item, buf, count,2 ); +} + +static ssize_t ufs_config_desc_3_show (struct config_item *item,char *buf) +{ +return ufs_config_desc_show (item, buf,3 ); +} + +static ssize_t ufs_config_desc_3_store (struct config_item *item, +const char *buf,size_t count) +{ +return ufshcd_desc_configfs_store (item, buf, count,3 ); +} + +static struct configfs_attribute ufshcd_attr_provision_0 = { + .ca_name ="ufs_config_desc_0" , + .ca_mode =0644 , + .ca_owner =THIS_MODULE , + .show = ufs_config_desc_0_show, + .store = ufs_config_desc_0_store, +}; + +static struct configfs_attribute ufshcd_attr_provision_1 = { + .ca_name ="ufs_config_desc_1" , + .ca_mode =0644 , + .ca_owner =THIS_MODULE , + .show = ufs_config_desc_1_show, + .store = ufs_config_desc_1_store, +}; + +static struct configfs_attribute ufshcd_attr_provision_2 = { + .ca_name ="ufs_config_desc_2" , + .ca_mode =0644 , + .ca_owner =THIS_MODULE , + .show = ufs_config_desc_2_show, + .store = ufs_config_desc_2_store, +}; + +static struct configfs_attribute ufshcd_attr_provision_3 = { + .ca_name ="ufs_config_desc_3" , + .ca_mode =0644 , + .ca_owner =THIS_MODULE , + .show = ufs_config_desc_3_show, + .store = ufs_config_desc_3_store, +}; + +static struct configfs_attribute *ufshcd_attrs[] = { + &ufshcd_attr_provision_0, + &ufshcd_attr_provision_1, + &ufshcd_attr_provision_2, + &ufshcd_attr_provision_3, +NULL , +}; + +static struct config_item_type ufscfg_type = { + .ct_attrs = ufshcd_attrs, + .ct_owner =THIS_MODULE , +}; + +void ufshcd_configfs_init (struct ufs_hba *hba,const char *name) +{ +int ret; +struct config_item *cg_item; +struct configfs_subsystem *subsys; + + cg_item = &hba->subsys.su_group.cg_item; +sprintf (cg_item->ci_namebuf,"%s" , name); + cg_item->ci_type = &ufscfg_type; + + subsys = &hba->subsys; +config_group_init (&subsys->su_group); +mutex_init (&subsys->su_mutex); + ret =configfs_register_subsystem (subsys); +if (ret) +pr_err ("Error %d while registering subsystem %s\n" , + ret, + subsys->su_group.cg_item.ci_namebuf); +} + +void ufshcd_configfs_exit (struct ufs_hba *hba) +{ +configfs_unregister_subsystem (&hba->subsys); +}drivers/scsi/ufs/ufshcd.c +2
-1@@ -7711,6 +7711,7 @@ int ufshcd_shutdown(struct ufs_hba *hba)void ufshcd_remove (struct ufs_hba *hba) {ufs_sysfs_remove_nodes (hba->dev); +ufshcd_configfs_exit (hba);scsi_remove_host (hba->host);/* disable interrupts */ ufshcd_disable_intr (hba, hba->intr_mask);@@ -7965,7 +7966,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)async_schedule (ufshcd_async_scan, hba);ufs_sysfs_add_nodes (hba->dev); - +ufshcd_configfs_init (hba,dev_name (hba->dev));return 0 ; out_remove_scsi_host:drivers/scsi/ufs/ufshcd.h +17
-0@@ -37,6 +37,7 @@#ifndef _UFSHCD_H#define _UFSHCD_H +#include <linux/configfs.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> @@ -515,6 +516,9 @@ struct ufs_hba {struct Scsi_Host *host;struct device *dev; +#ifdef CONFIG_UFS_PROVISION +struct configfs_subsystem subsys; +#endif /* * This field is to keep a reference to "scsi_device" corresponding to * "UFS device" W-LU. @@ -868,6 +872,19 @@ int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index,int ufshcd_hold (struct ufs_hba *hba,bool async);void ufshcd_release (struct ufs_hba *hba); +/* Expose UFS configfs API's */ +#ifndef CONFIG_UFS_PROVISION +static inline void ufshcd_configfs_init (struct ufs_hba *hba,const char *name) +{ +} +static inline void ufshcd_configfs_exit (struct ufs_hba *hba) +{ +} +#else +void ufshcd_configfs_init (struct ufs_hba *hba,const char *name); +void ufshcd_configfs_exit (struct ufs_hba *hba); +#endif +int ufshcd_map_desc_id_to_length (struct ufs_hba *hba,enum desc_idn desc_id,int *desc_length);
Re: [PATCH V12 2/2] scsi: ufs: Add configfs support for UFS provisioning
Quoted 15 lines · Adrian Hunter
Quoted 14 lines · Sayali Lokhande
This patch adds configfs support to provision UFS device at runtime. This feature can be primarily useful in factory or assembly line as some devices may be required to be configured multiple times during initial system development phase. Configuration Descriptors can be written multiple times until bConfigDescrLock attribute is zero.
Configuration descriptor buffer consists of Device and Unit descriptor configurable parameters which are parsed from vendor specific provisioning file and then passed via configfs node at runtime to provision ufs device.
CONFIG_CONFIGFS_FSandCONFIG_UFS_PROVISIONneeds to be enabled for using this feature.
Quoted 8 lines
Quoted 4 lines
Usage:
1) To read current configuration descriptor with index X(where index X can be 0/1/2/3) : cat /config/XXXX.ufshc/ufs_config_desc_XDevice name could be nearly anything, not necessarily in the form XXXX.ufshc, so maybe make this :
cat /config/<device name>/ufs_config_desc_X
Done.
Quoted 3 lines
Quoted 2 lines
2) To write configuration descriptor with index X :
echo <config_desc_buf> > /config/XXXX.ufshc/ufs_config_desc_XDitto
Done.
Quoted 12 lines
Quoted 12 lines
Signed-off-by Sayali Lokhande <[email protected]>--- Documentation/ABI/testing/configfs-driver-ufs | 12 ++ drivers/scsi/ufs/Kconfig | 10 ++ drivers/scsi/ufs/Makefile | 1 + drivers/scsi/ufs/ufs-configfs.c | 232 ++++++++++++++++++++++++++ drivers/scsi/ufs/ufshcd.c | 3 +- drivers/scsi/ufs/ufshcd.h | 17 ++ 6 files changed, 274 insertions(+), 1 deletion(-)create mode 100644
Documentation/ABI/testing/configfs-driver-ufscreate mode 100644drivers/scsi/ufs/ufs-configfs.c
Quoted 10 lines
Documentation/ABI/testing/configfs-driver-ufs line 3
Quoted 9 lines
Documentation/ABI/testing/configfs-driver-ufs new file +3
-0@@ -0,0 +1,12 @@ +What: /config/*/ufs_config_desc_X +Date: Jun 2018 +KernelVersion: 4.194.20 now
Done.
Quoted 15 lines
Quoted 15 lines
Documentation/ABI/testing/configfs-driver-ufs new file +9
-0+Description: + This file shows bytes of the current ufs configuration descriptor + with index X (where X = 0/1/2/3) set in device. This can be used to + provision ufs device if bConfigDescrLock is 0. + For more details, refer 14.1.6.3 Configuration Descriptor and + table 14-12 - Unit Descriptor configurable parameters from specs for + description and format of each configuration descriptor parameter. + Parameters of Configuration descriptor buffer for respective index + needs to be passed as bytes in space separated format.drivers/scsi/ufs/Kconfig +0
-0@@ -100,3 +100,13 @@ config SCSI_UFS_QCOM
Quoted 5 lines
drivers/scsi/ufs/Kconfig config SCSI_UFS_QCOM · line 104
Quoted 4 lines
drivers/scsi/ufs/Kconfig +2
-0Select this if you have UFS controller on QCOM chipset. If unsure, say N. + +config UFS_PROVISIONBetter if this is config
SCSI_UFS_PROVISIONto avoid mixups with UFS filesystem
Done.
Quoted 2 lines
drivers/scsi/ufs/Kconfig config SCSI_UFS_QCOM · line 105
Quoted 1 line
drivers/scsi/ufs/Kconfig +1
-0+ tristate "Runtime UFS Provisioning support"tristate won't work with what you have. It will have to be bool
Done.
Quoted 72 lines
Quoted 60 lines
drivers/scsi/ufs/Kconfig +7
-0+ depends on SCSI_UFSHCD && CONFIGFS_FS + help + This enables runtime UFS provisioning support. This can be used + primarily during assembly line as some devices may be required to + be configured multiple times during initial development phase. + + If unsure, say N.drivers/scsi/ufs/Makefile +1
-0@@ -5,5 +5,6 @@ obj-$(CONFIG_SCSI_UFS_DWC_TC_PLATFORM) += tc-dwc-g210-pltfrm.o ufshcd-dwc.o tc-d obj-$(CONFIG_SCSI_UFS_QCOM) += ufs-qcom.o obj-$(CONFIG_SCSI_UFSHCD) += ufshcd-core.o ufshcd-core-objs := ufshcd.o ufs-sysfs.o +obj-$(CONFIG_UFS_PROVISION) += ufs-configfs.o obj-$(CONFIG_SCSI_UFSHCD_PCI) += ufshcd-pci.o obj-$(CONFIG_SCSI_UFSHCD_PLATFORM) += ufshcd-pltfrm.odrivers/scsi/ufs/ufs-configfs.c new file +36
-0@@ -0,0 +1,232 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2018, Linux Foundation. + +#include <linux/configfs.h> +#include <linux/err.h> +#include <linux/string.h> + +#include "ufs.h" +#include "ufshcd.h" + +static inline struct ufs_hba *config_item_to_hba (struct config_item *item) +{ +struct config_group *group =to_config_group (item); +struct configfs_subsystem *subsys =to_configfs_subsystem (group); + struct ufs_hba *hba = container_of(subsys, struct ufs_hba, subsys); + +return hba; +} + +static ssize_t ufs_config_desc_show (struct config_item *item,char *buf, +u8 index) +{ +struct ufs_hba *hba =config_item_to_hba (item); +u8 *desc_buf =NULL ; +int desc_buf_len = hba->desc_size.conf_desc; +int i, ret, curr_len =0 ; + + desc_buf =kzalloc (desc_buf_len,GFP_KERNEL ); +if (!desc_buf) +return -ENOMEM ; + + ret =ufshcd_query_descriptor_retry (hba,UPIU_QUERY_OPCODE_READ_DESC , +QUERY_DESC_IDN_CONFIGURATION , index,0 , + desc_buf, &desc_buf_len); +if (ret) + goto out;drivers/scsi/ufs/ufs-configfs.c line 46
Quoted 10 lines
drivers/scsi/ufs/ufs-configfs.c new file +10
-0+ +for (i =0 ; i < desc_buf_len; i++) + curr_len +=snprintf ((buf + curr_len), (PAGE_SIZE - curr_len), +"0x%x " , desc_buf[i]); + +out: +kfree (desc_buf); +if (ret) +return ret; +return curr_len;Could be:
Quoted 1 line
return ret ?: curr_len;
Done.
Quoted 14 lines
Quoted 14 lines
drivers/scsi/ufs/ufs-configfs.c new file +14
-0+} + +ssize_t ufshcd_desc_configfs_store (struct config_item *item, +const char *buf,size_t count,u8 index) +{ +char *strbuf; +char *strbuf_copy; +struct ufs_hba *hba =config_item_to_hba (item); +u8 *desc_buf =NULL ; +int desc_buf_len = hba->desc_size.conf_desc; +char *token; +int i, ret; +u8 value; +u32 config_desc_lock =0 ;
Quoted 8 lines
drivers/scsi/ufs/ufs-configfs.c line 67
Quoted 7 lines
drivers/scsi/ufs/ufs-configfs.c new file +7
-0+ + desc_buf =kzalloc (desc_buf_len,GFP_KERNEL ); +if (!desc_buf) +return -ENOMEM ; + +/* reserve one byte for null termination */ + strbuf =kmalloc (count +1 ,GFP_KERNEL );buf is null-terminated so just use
kstrdup()
Done.
Quoted 20 lines
Quoted 7 lines
drivers/scsi/ufs/ufs-configfs.c new file +7
-0+if (!strbuf) { + ret = -ENOMEM ; + goto out; + } + + strbuf_copy = strbuf; +strlcpy (strbuf, buf, count +1 );drivers/scsi/ufs/ufs-configfs.c line 84
Quoted 10 lines
drivers/scsi/ufs/ufs-configfs.c new file +10
-0+ +/* Just return if bConfigDescrLock is already set */ + ret =ufshcd_query_attr (hba,UPIU_QUERY_OPCODE_READ_ATTR , +QUERY_ATTR_IDN_CONF_DESC_LOCK ,0 ,0 , &config_desc_lock); +if (ret) + goto out; + +if (config_desc_lock) { +dev_err (hba->dev,"%s: bConfigDescrLock already set to %u, cannot re-provision device!\n" , + __func__, config_desc_lock);Indenting is not ideal. Consider some of the suggestions of:
scripts/checkpatch.pl--strict
Quoted 8 lines
drivers/scsi/ufs/ufs-configfs.c line 91
Quoted 7 lines
drivers/scsi/ufs/ufs-configfs.c new file +7
-0+ ret = -EINVAL ; + goto out; + } + +for (i =0 ; i < desc_buf_len; i++) { + token =strsep (&strbuf_copy," " ); +if (!token && i)What is 'i' doing here?
Its not needed now. Will remove. (earlier I had some debug prints which used i).
Quoted 2 lines
If the user does not supply enough bytes, the remainder will be overwritten by 0 which doesn't seem ideal. It would be better to read
desc_buffirst.
Ok. Will first read the current config desc and then update with user passed parameters. In this way, if user supplied bytes are less than desc length, we will retain the remaining old configuration.
Quoted 7 lines
drivers/scsi/ufs/ufs-configfs.c line 96
Quoted 5 lines
drivers/scsi/ufs/ufs-configfs.c new file +5
-0+break ; + + ret =kstrtou8 (token,0 , &value); +if (ret) { + dev_err(hba->dev, "%s: kstrtou8 failed %d %s\n",User may not understand 'kstrtou8'. 'Invalid value %s writing UFS configuration descriptor %u' would be better.
Done.
Quoted 23 lines
Quoted 11 lines
drivers/scsi/ufs/ufs-configfs.c new file +11
-0+ __func__, ret, token); + ret = -EINVAL ; + goto out; + } + desc_buf[i] = value; + } + +/* Write configuration descriptor to provision ufs */ + ret =ufshcd_query_descriptor_retry (hba,UPIU_QUERY_OPCODE_WRITE_DESC , +QUERY_DESC_IDN_CONFIGURATION , index,0 , + desc_buf, &desc_buf_len);drivers/scsi/ufs/ufs-configfs.c line 117
Quoted 10 lines
drivers/scsi/ufs/ufs-configfs.c new file +10
-0+if (!ret) +dev_info (hba->dev,"%s: UFS Configuration Descriptor %u written\n" , + __func__, index); + +out: +kfree (strbuf); +kfree (desc_buf); +if (ret) +return ret; +return count;Could be:
Quoted 1 line
return ret ?: count;
Done.
Quoted 179 lines
Quoted 179 lines
drivers/scsi/ufs/ufs-configfs.c new file +115
-0+} + +static ssize_t ufs_config_desc_0_show (struct config_item *item,char *buf) +{ +return ufs_config_desc_show (item, buf,0 ); +} + +static ssize_t ufs_config_desc_0_store (struct config_item *item, +const char *buf,size_t count) +{ +return ufshcd_desc_configfs_store (item, buf, count,0 ); +} + +static ssize_t ufs_config_desc_1_show (struct config_item *item,char *buf) +{ +return ufs_config_desc_show (item, buf,1 ); +} + +static ssize_t ufs_config_desc_1_store (struct config_item *item, +const char *buf,size_t count) +{ +return ufshcd_desc_configfs_store (item, buf, count,1 ); +} + +static ssize_t ufs_config_desc_2_show (struct config_item *item,char *buf) +{ +return ufs_config_desc_show (item, buf,2 ); +} + +static ssize_t ufs_config_desc_2_store (struct config_item *item, +const char *buf,size_t count) +{ +return ufshcd_desc_configfs_store (item, buf, count,2 ); +} + +static ssize_t ufs_config_desc_3_show (struct config_item *item,char *buf) +{ +return ufs_config_desc_show (item, buf,3 ); +} + +static ssize_t ufs_config_desc_3_store (struct config_item *item, +const char *buf,size_t count) +{ +return ufshcd_desc_configfs_store (item, buf, count,3 ); +} + +static struct configfs_attribute ufshcd_attr_provision_0 = { + .ca_name ="ufs_config_desc_0" , + .ca_mode =0644 , + .ca_owner =THIS_MODULE , + .show = ufs_config_desc_0_show, + .store = ufs_config_desc_0_store, +}; + +static struct configfs_attribute ufshcd_attr_provision_1 = { + .ca_name ="ufs_config_desc_1" , + .ca_mode =0644 , + .ca_owner =THIS_MODULE , + .show = ufs_config_desc_1_show, + .store = ufs_config_desc_1_store, +}; + +static struct configfs_attribute ufshcd_attr_provision_2 = { + .ca_name ="ufs_config_desc_2" , + .ca_mode =0644 , + .ca_owner =THIS_MODULE , + .show = ufs_config_desc_2_show, + .store = ufs_config_desc_2_store, +}; + +static struct configfs_attribute ufshcd_attr_provision_3 = { + .ca_name ="ufs_config_desc_3" , + .ca_mode =0644 , + .ca_owner =THIS_MODULE , + .show = ufs_config_desc_3_show, + .store = ufs_config_desc_3_store, +}; + +static struct configfs_attribute *ufshcd_attrs[] = { + &ufshcd_attr_provision_0, + &ufshcd_attr_provision_1, + &ufshcd_attr_provision_2, + &ufshcd_attr_provision_3, +NULL , +}; + +static struct config_item_type ufscfg_type = { + .ct_attrs = ufshcd_attrs, + .ct_owner =THIS_MODULE , +}; + +void ufshcd_configfs_init (struct ufs_hba *hba,const char *name) +{ +int ret; +struct config_item *cg_item; +struct configfs_subsystem *subsys; + + cg_item = &hba->subsys.su_group.cg_item; +sprintf (cg_item->ci_namebuf,"%s" , name); + cg_item->ci_type = &ufscfg_type; + + subsys = &hba->subsys; +config_group_init (&subsys->su_group); +mutex_init (&subsys->su_mutex); + ret =configfs_register_subsystem (subsys); +if (ret) +pr_err ("Error %d while registering subsystem %s\n" , + ret, + subsys->su_group.cg_item.ci_namebuf); +} + +void ufshcd_configfs_exit (struct ufs_hba *hba) +{ +configfs_unregister_subsystem (&hba->subsys); +}drivers/scsi/ufs/ufshcd.c +2
-1@@ -7711,6 +7711,7 @@ int ufshcd_shutdown(struct ufs_hba *hba)void ufshcd_remove (struct ufs_hba *hba) {ufs_sysfs_remove_nodes (hba->dev); +ufshcd_configfs_exit (hba);scsi_remove_host (hba->host);/* disable interrupts */ ufshcd_disable_intr (hba, hba->intr_mask);@@ -7965,7 +7966,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)async_schedule (ufshcd_async_scan, hba);ufs_sysfs_add_nodes (hba->dev); - +ufshcd_configfs_init (hba,dev_name (hba->dev));return 0 ; out_remove_scsi_host:drivers/scsi/ufs/ufshcd.h +17
-0@@ -37,6 +37,7 @@#ifndef _UFSHCD_H#define _UFSHCD_H +#include <linux/configfs.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> @@ -515,6 +516,9 @@ struct ufs_hba {struct Scsi_Host *host;struct device *dev; +#ifdef CONFIG_UFS_PROVISION +struct configfs_subsystem subsys; +#endif /* * This field is to keep a reference to "scsi_device" corresponding to * "UFS device" W-LU. @@ -868,6 +872,19 @@ int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index,int ufshcd_hold (struct ufs_hba *hba,bool async);void ufshcd_release (struct ufs_hba *hba); +/* Expose UFS configfs API's */ +#ifndef CONFIG_UFS_PROVISION +static inline void ufshcd_configfs_init (struct ufs_hba *hba,const char *name) +{ +} +static inline void ufshcd_configfs_exit (struct ufs_hba *hba) +{ +} +#else +void ufshcd_configfs_init (struct ufs_hba *hba,const char *name); +void ufshcd_configfs_exit (struct ufs_hba *hba); +#endif +int ufshcd_map_desc_id_to_length (struct ufs_hba *hba,enum desc_idn desc_id,int *desc_length);