Loading drivers/scsi/ufs/ufs-qcom.c +313 −0 Original line number Diff line number Diff line Loading @@ -413,6 +413,44 @@ static void ufs_qcom_select_unipro_mode(struct ufs_qcom_host *host) mb(); } /** * ufs_qcom_host_reset - reset host controller and PHY */ static int ufs_qcom_host_reset(struct ufs_hba *hba) { int ret = 0; struct ufs_qcom_host *host = ufshcd_get_variant(hba); if (!host->core_reset) { dev_warn(hba->dev, "%s: reset control not set\n", __func__); goto out; } ret = reset_control_assert(host->core_reset); if (ret) { dev_err(hba->dev, "%s: core_reset assert failed, err = %d\n", __func__, ret); goto out; } /* * The hardware requirement for delay between assert/deassert * is at least 3-4 sleep clock (32.7KHz) cycles, which comes to * ~125us (4/32768). To be on the safe side add 200us delay. */ usleep_range(200, 210); ret = reset_control_deassert(host->core_reset); if (ret) dev_err(hba->dev, "%s: core_reset deassert failed, err = %d\n", __func__, ret); usleep_range(1000, 1100); out: return ret; } static int ufs_qcom_power_up_sequence(struct ufs_hba *hba) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); Loading @@ -421,6 +459,12 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba) bool is_rate_B = (UFS_QCOM_LIMIT_HS_RATE == PA_HS_MODE_B) ? true : false; /* Reset UFS Host Controller and PHY */ ret = ufs_qcom_host_reset(hba); if (ret) dev_warn(hba->dev, "%s: host reset returned %d\n", __func__, ret); #ifdef CONFIG_SCSI_UFSHCD_QTI /* Use Rate-A for Gear4 on non-simulation platforms */ if (hba->phy_init_g4) { Loading Loading @@ -1718,6 +1762,257 @@ static void ufs_qcom_save_host_ptr(struct ufs_hba *hba) dev_err(hba->dev, "invalid host index %d\n", id); } /** * ufs_qcom_query_ioctl - perform user read queries * @hba: per-adapter instance * @lun: used for lun specific queries * @buffer: user space buffer for reading and submitting query data and params * @return: 0 for success negative error code otherwise * * Expected/Submitted buffer structure is struct ufs_ioctl_query_data. * It will read the opcode, idn and buf_length parameters, and, put the * response in the buffer field while updating the used size in buf_length. */ static int ufs_qcom_query_ioctl(struct ufs_hba *hba, u8 lun, void __user *buffer) { struct ufs_ioctl_query_data *ioctl_data; int err = 0; int length = 0; void *data_ptr; bool flag; u32 att; u8 index; u8 *desc = NULL; ioctl_data = kzalloc(sizeof(*ioctl_data), GFP_KERNEL); if (!ioctl_data) { err = -ENOMEM; goto out; } /* extract params from user buffer */ err = copy_from_user(ioctl_data, buffer, sizeof(struct ufs_ioctl_query_data)); if (err) { dev_err(hba->dev, "%s: Failed copying buffer from user, err %d\n", __func__, err); goto out_release_mem; } /* verify legal parameters & send query */ switch (ioctl_data->opcode) { case UPIU_QUERY_OPCODE_READ_DESC: switch (ioctl_data->idn) { case QUERY_DESC_IDN_DEVICE: case QUERY_DESC_IDN_CONFIGURATION: case QUERY_DESC_IDN_INTERCONNECT: case QUERY_DESC_IDN_GEOMETRY: case QUERY_DESC_IDN_POWER: index = 0; break; case QUERY_DESC_IDN_UNIT: if (!ufs_is_valid_unit_desc_lun(lun)) { dev_err(hba->dev, "%s: No unit descriptor for lun 0x%x\n", __func__, lun); err = -EINVAL; goto out_release_mem; } index = lun; break; default: goto out_einval; } length = min_t(int, QUERY_DESC_MAX_SIZE, ioctl_data->buf_size); desc = kzalloc(length, GFP_KERNEL); if (!desc) { dev_err(hba->dev, "%s: Failed allocating %d bytes\n", __func__, length); err = -ENOMEM; goto out_release_mem; } err = ufshcd_query_descriptor_retry(hba, ioctl_data->opcode, ioctl_data->idn, index, 0, desc, &length); break; case UPIU_QUERY_OPCODE_READ_ATTR: switch (ioctl_data->idn) { case QUERY_ATTR_IDN_BOOT_LU_EN: case QUERY_ATTR_IDN_POWER_MODE: case QUERY_ATTR_IDN_ACTIVE_ICC_LVL: case QUERY_ATTR_IDN_OOO_DATA_EN: case QUERY_ATTR_IDN_BKOPS_STATUS: case QUERY_ATTR_IDN_PURGE_STATUS: case QUERY_ATTR_IDN_MAX_DATA_IN: case QUERY_ATTR_IDN_MAX_DATA_OUT: case QUERY_ATTR_IDN_REF_CLK_FREQ: case QUERY_ATTR_IDN_CONF_DESC_LOCK: case QUERY_ATTR_IDN_MAX_NUM_OF_RTT: case QUERY_ATTR_IDN_EE_CONTROL: case QUERY_ATTR_IDN_EE_STATUS: case QUERY_ATTR_IDN_SECONDS_PASSED: index = 0; break; case QUERY_ATTR_IDN_DYN_CAP_NEEDED: case QUERY_ATTR_IDN_CORR_PRG_BLK_NUM: index = lun; break; default: goto out_einval; } err = ufshcd_query_attr(hba, ioctl_data->opcode, ioctl_data->idn, index, 0, &att); break; case UPIU_QUERY_OPCODE_WRITE_ATTR: err = copy_from_user(&att, buffer + sizeof(struct ufs_ioctl_query_data), sizeof(u32)); if (err) { dev_err(hba->dev, "%s: Failed copying buffer from user, err %d\n", __func__, err); goto out_release_mem; } switch (ioctl_data->idn) { case QUERY_ATTR_IDN_BOOT_LU_EN: index = 0; if (!att) { dev_err(hba->dev, "%s: Illegal ufs query ioctl data, opcode 0x%x, idn 0x%x, att 0x%x\n", __func__, ioctl_data->opcode, (unsigned int)ioctl_data->idn, att); err = -EINVAL; goto out_release_mem; } break; default: goto out_einval; } err = ufshcd_query_attr(hba, ioctl_data->opcode, ioctl_data->idn, index, 0, &att); break; case UPIU_QUERY_OPCODE_READ_FLAG: switch (ioctl_data->idn) { case QUERY_FLAG_IDN_FDEVICEINIT: case QUERY_FLAG_IDN_PERMANENT_WPE: case QUERY_FLAG_IDN_PWR_ON_WPE: case QUERY_FLAG_IDN_BKOPS_EN: case QUERY_FLAG_IDN_PURGE_ENABLE: case QUERY_FLAG_IDN_FPHYRESOURCEREMOVAL: case QUERY_FLAG_IDN_BUSY_RTC: break; default: goto out_einval; } err = ufshcd_query_flag(hba, ioctl_data->opcode, ioctl_data->idn, &flag); break; default: goto out_einval; } if (err) { dev_err(hba->dev, "%s: Query for idn %d failed\n", __func__, ioctl_data->idn); goto out_release_mem; } /* * copy response data * As we might end up reading less data than what is specified in * "ioctl_data->buf_size". So we are updating "ioctl_data-> * buf_size" to what exactly we have read. */ switch (ioctl_data->opcode) { case UPIU_QUERY_OPCODE_READ_DESC: ioctl_data->buf_size = min_t(int, ioctl_data->buf_size, length); data_ptr = desc; break; case UPIU_QUERY_OPCODE_READ_ATTR: ioctl_data->buf_size = sizeof(u32); data_ptr = &att; break; case UPIU_QUERY_OPCODE_READ_FLAG: ioctl_data->buf_size = 1; data_ptr = &flag; break; case UPIU_QUERY_OPCODE_WRITE_ATTR: goto out_release_mem; default: goto out_einval; } /* copy to user */ err = copy_to_user(buffer, ioctl_data, sizeof(struct ufs_ioctl_query_data)); if (err) dev_err(hba->dev, "%s: Failed copying back to user.\n", __func__); err = copy_to_user(buffer + sizeof(struct ufs_ioctl_query_data), data_ptr, ioctl_data->buf_size); if (err) dev_err(hba->dev, "%s: err %d copying back to user.\n", __func__, err); goto out_release_mem; out_einval: dev_err(hba->dev, "%s: illegal ufs query ioctl data, opcode 0x%x, idn 0x%x\n", __func__, ioctl_data->opcode, (unsigned int)ioctl_data->idn); err = -EINVAL; out_release_mem: kfree(ioctl_data); kfree(desc); out: return err; } /** * ufs_qcom_ioctl - ufs ioctl callback registered in scsi_host * @dev: scsi device required for per LUN queries * @cmd: command opcode * @buffer: user space buffer for transferring data * * Supported commands: * UFS_IOCTL_QUERY */ static int ufs_qcom_ioctl(struct scsi_device *dev, unsigned int cmd, void __user *buffer) { struct ufs_hba *hba = shost_priv(dev->host); int err = 0; BUG_ON(!hba); if (!buffer) { dev_err(hba->dev, "%s: User buffer is NULL!\n", __func__); return -EINVAL; } switch (cmd) { case UFS_IOCTL_QUERY: pm_runtime_get_sync(hba->dev); err = ufs_qcom_query_ioctl(hba, ufshcd_scsi_to_upiu_lun(dev->lun), buffer); pm_runtime_put_sync(hba->dev); break; default: err = -ENOIOCTLCMD; dev_dbg(hba->dev, "%s: Unsupported ioctl cmd %d\n", __func__, cmd); break; } return err; } /** * ufs_qcom_init - bind phy with controller * @hba: host controller instance Loading Loading @@ -1750,6 +2045,15 @@ static int ufs_qcom_init(struct ufs_hba *hba) host->hba = hba; ufshcd_set_variant(hba, host); /* Setup the reset control of HCI */ host->core_reset = devm_reset_control_get(hba->dev, "rst"); if (IS_ERR(host->core_reset)) { err = PTR_ERR(host->core_reset); dev_warn(dev, "Failed to get reset control %d\n", err); host->core_reset = NULL; err = 0; } /* Fire up the reset controller. Failure here is non-fatal. */ host->rcdev.of_node = dev->of_node; host->rcdev.ops = &ufs_qcom_reset_ops; Loading Loading @@ -1884,6 +2188,15 @@ static int ufs_qcom_init(struct ufs_hba *hba) err = 0; } /* Provide SCSI host ioctl API */ hba->host->hostt->ioctl = (int (*)(struct scsi_device *, unsigned int, void __user *))ufs_qcom_ioctl; #ifdef CONFIG_COMPAT hba->host->hostt->compat_ioctl = (int (*)(struct scsi_device *, unsigned int, void __user *))ufs_qcom_ioctl; #endif ufs_qcom_save_host_ptr(hba); goto out; Loading drivers/scsi/ufs/ufs-qcom.h +55 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ #define UFS_QCOM_H_ #include <linux/reset-controller.h> #include <linux/reset.h> #include <linux/phy/phy.h> #include "ufshcd.h" #ifdef CONFIG_SCSI_UFSHCD_QTI Loading Loading @@ -312,6 +313,8 @@ struct ufs_qcom_host { u32 dbg_print_en; struct ufs_qcom_testbus testbus; /* Reset control of HCI */ struct reset_control *core_reset; struct reset_controller_dev rcdev; struct gpio_desc *device_reset; Loading Loading @@ -392,4 +395,56 @@ static inline int ufshcd_dme_rmw(struct ufs_hba *hba, u32 mask, return err; } /* * IOCTL opcode for ufs queries has the following opcode after * SCSI_IOCTL_GET_PCI */ #define UFS_IOCTL_QUERY 0x5388 /** * struct ufs_ioctl_query_data - used to transfer data to and from user via * ioctl * @opcode: type of data to query (descriptor/attribute/flag) * @idn: id of the data structure * @buf_size: number of allocated bytes/data size on return * @buffer: data location * * Received: buffer and buf_size (available space for transferred data) * Submitted: opcode, idn, length, buf_size */ struct ufs_ioctl_query_data { /* * User should select one of the opcode defined in "enum query_opcode". * Please check include/uapi/scsi/ufs/ufs.h for the definition of it. * Note that only UPIU_QUERY_OPCODE_READ_DESC, * UPIU_QUERY_OPCODE_READ_ATTR & UPIU_QUERY_OPCODE_READ_FLAG are * supported as of now. All other query_opcode would be considered * invalid. * As of now only read query operations are supported. */ __u32 opcode; /* * User should select one of the idn from "enum flag_idn" or "enum * attr_idn" or "enum desc_idn" based on whether opcode above is * attribute, flag or descriptor. * Please check include/uapi/scsi/ufs/ufs.h for the definition of it. */ __u8 idn; /* * User should specify the size of the buffer (buffer[0] below) where * it wants to read the query data (attribute/flag/descriptor). * As we might end up reading less data then what is specified in * buf_size. So we are updating buf_size to what exactly we have read. */ __u16 buf_size; /* * placeholder for the start of the data buffer where kernel will copy * the query data (attribute/flag/descriptor) read from the UFS device * Note: * For Read/Write Attribute you will have to allocate 4 bytes * For Read/Write Flag you will have to allocate 1 byte */ __u8 buffer[0]; }; #endif /* UFS_QCOM_H_ */ Loading
drivers/scsi/ufs/ufs-qcom.c +313 −0 Original line number Diff line number Diff line Loading @@ -413,6 +413,44 @@ static void ufs_qcom_select_unipro_mode(struct ufs_qcom_host *host) mb(); } /** * ufs_qcom_host_reset - reset host controller and PHY */ static int ufs_qcom_host_reset(struct ufs_hba *hba) { int ret = 0; struct ufs_qcom_host *host = ufshcd_get_variant(hba); if (!host->core_reset) { dev_warn(hba->dev, "%s: reset control not set\n", __func__); goto out; } ret = reset_control_assert(host->core_reset); if (ret) { dev_err(hba->dev, "%s: core_reset assert failed, err = %d\n", __func__, ret); goto out; } /* * The hardware requirement for delay between assert/deassert * is at least 3-4 sleep clock (32.7KHz) cycles, which comes to * ~125us (4/32768). To be on the safe side add 200us delay. */ usleep_range(200, 210); ret = reset_control_deassert(host->core_reset); if (ret) dev_err(hba->dev, "%s: core_reset deassert failed, err = %d\n", __func__, ret); usleep_range(1000, 1100); out: return ret; } static int ufs_qcom_power_up_sequence(struct ufs_hba *hba) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); Loading @@ -421,6 +459,12 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba) bool is_rate_B = (UFS_QCOM_LIMIT_HS_RATE == PA_HS_MODE_B) ? true : false; /* Reset UFS Host Controller and PHY */ ret = ufs_qcom_host_reset(hba); if (ret) dev_warn(hba->dev, "%s: host reset returned %d\n", __func__, ret); #ifdef CONFIG_SCSI_UFSHCD_QTI /* Use Rate-A for Gear4 on non-simulation platforms */ if (hba->phy_init_g4) { Loading Loading @@ -1718,6 +1762,257 @@ static void ufs_qcom_save_host_ptr(struct ufs_hba *hba) dev_err(hba->dev, "invalid host index %d\n", id); } /** * ufs_qcom_query_ioctl - perform user read queries * @hba: per-adapter instance * @lun: used for lun specific queries * @buffer: user space buffer for reading and submitting query data and params * @return: 0 for success negative error code otherwise * * Expected/Submitted buffer structure is struct ufs_ioctl_query_data. * It will read the opcode, idn and buf_length parameters, and, put the * response in the buffer field while updating the used size in buf_length. */ static int ufs_qcom_query_ioctl(struct ufs_hba *hba, u8 lun, void __user *buffer) { struct ufs_ioctl_query_data *ioctl_data; int err = 0; int length = 0; void *data_ptr; bool flag; u32 att; u8 index; u8 *desc = NULL; ioctl_data = kzalloc(sizeof(*ioctl_data), GFP_KERNEL); if (!ioctl_data) { err = -ENOMEM; goto out; } /* extract params from user buffer */ err = copy_from_user(ioctl_data, buffer, sizeof(struct ufs_ioctl_query_data)); if (err) { dev_err(hba->dev, "%s: Failed copying buffer from user, err %d\n", __func__, err); goto out_release_mem; } /* verify legal parameters & send query */ switch (ioctl_data->opcode) { case UPIU_QUERY_OPCODE_READ_DESC: switch (ioctl_data->idn) { case QUERY_DESC_IDN_DEVICE: case QUERY_DESC_IDN_CONFIGURATION: case QUERY_DESC_IDN_INTERCONNECT: case QUERY_DESC_IDN_GEOMETRY: case QUERY_DESC_IDN_POWER: index = 0; break; case QUERY_DESC_IDN_UNIT: if (!ufs_is_valid_unit_desc_lun(lun)) { dev_err(hba->dev, "%s: No unit descriptor for lun 0x%x\n", __func__, lun); err = -EINVAL; goto out_release_mem; } index = lun; break; default: goto out_einval; } length = min_t(int, QUERY_DESC_MAX_SIZE, ioctl_data->buf_size); desc = kzalloc(length, GFP_KERNEL); if (!desc) { dev_err(hba->dev, "%s: Failed allocating %d bytes\n", __func__, length); err = -ENOMEM; goto out_release_mem; } err = ufshcd_query_descriptor_retry(hba, ioctl_data->opcode, ioctl_data->idn, index, 0, desc, &length); break; case UPIU_QUERY_OPCODE_READ_ATTR: switch (ioctl_data->idn) { case QUERY_ATTR_IDN_BOOT_LU_EN: case QUERY_ATTR_IDN_POWER_MODE: case QUERY_ATTR_IDN_ACTIVE_ICC_LVL: case QUERY_ATTR_IDN_OOO_DATA_EN: case QUERY_ATTR_IDN_BKOPS_STATUS: case QUERY_ATTR_IDN_PURGE_STATUS: case QUERY_ATTR_IDN_MAX_DATA_IN: case QUERY_ATTR_IDN_MAX_DATA_OUT: case QUERY_ATTR_IDN_REF_CLK_FREQ: case QUERY_ATTR_IDN_CONF_DESC_LOCK: case QUERY_ATTR_IDN_MAX_NUM_OF_RTT: case QUERY_ATTR_IDN_EE_CONTROL: case QUERY_ATTR_IDN_EE_STATUS: case QUERY_ATTR_IDN_SECONDS_PASSED: index = 0; break; case QUERY_ATTR_IDN_DYN_CAP_NEEDED: case QUERY_ATTR_IDN_CORR_PRG_BLK_NUM: index = lun; break; default: goto out_einval; } err = ufshcd_query_attr(hba, ioctl_data->opcode, ioctl_data->idn, index, 0, &att); break; case UPIU_QUERY_OPCODE_WRITE_ATTR: err = copy_from_user(&att, buffer + sizeof(struct ufs_ioctl_query_data), sizeof(u32)); if (err) { dev_err(hba->dev, "%s: Failed copying buffer from user, err %d\n", __func__, err); goto out_release_mem; } switch (ioctl_data->idn) { case QUERY_ATTR_IDN_BOOT_LU_EN: index = 0; if (!att) { dev_err(hba->dev, "%s: Illegal ufs query ioctl data, opcode 0x%x, idn 0x%x, att 0x%x\n", __func__, ioctl_data->opcode, (unsigned int)ioctl_data->idn, att); err = -EINVAL; goto out_release_mem; } break; default: goto out_einval; } err = ufshcd_query_attr(hba, ioctl_data->opcode, ioctl_data->idn, index, 0, &att); break; case UPIU_QUERY_OPCODE_READ_FLAG: switch (ioctl_data->idn) { case QUERY_FLAG_IDN_FDEVICEINIT: case QUERY_FLAG_IDN_PERMANENT_WPE: case QUERY_FLAG_IDN_PWR_ON_WPE: case QUERY_FLAG_IDN_BKOPS_EN: case QUERY_FLAG_IDN_PURGE_ENABLE: case QUERY_FLAG_IDN_FPHYRESOURCEREMOVAL: case QUERY_FLAG_IDN_BUSY_RTC: break; default: goto out_einval; } err = ufshcd_query_flag(hba, ioctl_data->opcode, ioctl_data->idn, &flag); break; default: goto out_einval; } if (err) { dev_err(hba->dev, "%s: Query for idn %d failed\n", __func__, ioctl_data->idn); goto out_release_mem; } /* * copy response data * As we might end up reading less data than what is specified in * "ioctl_data->buf_size". So we are updating "ioctl_data-> * buf_size" to what exactly we have read. */ switch (ioctl_data->opcode) { case UPIU_QUERY_OPCODE_READ_DESC: ioctl_data->buf_size = min_t(int, ioctl_data->buf_size, length); data_ptr = desc; break; case UPIU_QUERY_OPCODE_READ_ATTR: ioctl_data->buf_size = sizeof(u32); data_ptr = &att; break; case UPIU_QUERY_OPCODE_READ_FLAG: ioctl_data->buf_size = 1; data_ptr = &flag; break; case UPIU_QUERY_OPCODE_WRITE_ATTR: goto out_release_mem; default: goto out_einval; } /* copy to user */ err = copy_to_user(buffer, ioctl_data, sizeof(struct ufs_ioctl_query_data)); if (err) dev_err(hba->dev, "%s: Failed copying back to user.\n", __func__); err = copy_to_user(buffer + sizeof(struct ufs_ioctl_query_data), data_ptr, ioctl_data->buf_size); if (err) dev_err(hba->dev, "%s: err %d copying back to user.\n", __func__, err); goto out_release_mem; out_einval: dev_err(hba->dev, "%s: illegal ufs query ioctl data, opcode 0x%x, idn 0x%x\n", __func__, ioctl_data->opcode, (unsigned int)ioctl_data->idn); err = -EINVAL; out_release_mem: kfree(ioctl_data); kfree(desc); out: return err; } /** * ufs_qcom_ioctl - ufs ioctl callback registered in scsi_host * @dev: scsi device required for per LUN queries * @cmd: command opcode * @buffer: user space buffer for transferring data * * Supported commands: * UFS_IOCTL_QUERY */ static int ufs_qcom_ioctl(struct scsi_device *dev, unsigned int cmd, void __user *buffer) { struct ufs_hba *hba = shost_priv(dev->host); int err = 0; BUG_ON(!hba); if (!buffer) { dev_err(hba->dev, "%s: User buffer is NULL!\n", __func__); return -EINVAL; } switch (cmd) { case UFS_IOCTL_QUERY: pm_runtime_get_sync(hba->dev); err = ufs_qcom_query_ioctl(hba, ufshcd_scsi_to_upiu_lun(dev->lun), buffer); pm_runtime_put_sync(hba->dev); break; default: err = -ENOIOCTLCMD; dev_dbg(hba->dev, "%s: Unsupported ioctl cmd %d\n", __func__, cmd); break; } return err; } /** * ufs_qcom_init - bind phy with controller * @hba: host controller instance Loading Loading @@ -1750,6 +2045,15 @@ static int ufs_qcom_init(struct ufs_hba *hba) host->hba = hba; ufshcd_set_variant(hba, host); /* Setup the reset control of HCI */ host->core_reset = devm_reset_control_get(hba->dev, "rst"); if (IS_ERR(host->core_reset)) { err = PTR_ERR(host->core_reset); dev_warn(dev, "Failed to get reset control %d\n", err); host->core_reset = NULL; err = 0; } /* Fire up the reset controller. Failure here is non-fatal. */ host->rcdev.of_node = dev->of_node; host->rcdev.ops = &ufs_qcom_reset_ops; Loading Loading @@ -1884,6 +2188,15 @@ static int ufs_qcom_init(struct ufs_hba *hba) err = 0; } /* Provide SCSI host ioctl API */ hba->host->hostt->ioctl = (int (*)(struct scsi_device *, unsigned int, void __user *))ufs_qcom_ioctl; #ifdef CONFIG_COMPAT hba->host->hostt->compat_ioctl = (int (*)(struct scsi_device *, unsigned int, void __user *))ufs_qcom_ioctl; #endif ufs_qcom_save_host_ptr(hba); goto out; Loading
drivers/scsi/ufs/ufs-qcom.h +55 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ #define UFS_QCOM_H_ #include <linux/reset-controller.h> #include <linux/reset.h> #include <linux/phy/phy.h> #include "ufshcd.h" #ifdef CONFIG_SCSI_UFSHCD_QTI Loading Loading @@ -312,6 +313,8 @@ struct ufs_qcom_host { u32 dbg_print_en; struct ufs_qcom_testbus testbus; /* Reset control of HCI */ struct reset_control *core_reset; struct reset_controller_dev rcdev; struct gpio_desc *device_reset; Loading Loading @@ -392,4 +395,56 @@ static inline int ufshcd_dme_rmw(struct ufs_hba *hba, u32 mask, return err; } /* * IOCTL opcode for ufs queries has the following opcode after * SCSI_IOCTL_GET_PCI */ #define UFS_IOCTL_QUERY 0x5388 /** * struct ufs_ioctl_query_data - used to transfer data to and from user via * ioctl * @opcode: type of data to query (descriptor/attribute/flag) * @idn: id of the data structure * @buf_size: number of allocated bytes/data size on return * @buffer: data location * * Received: buffer and buf_size (available space for transferred data) * Submitted: opcode, idn, length, buf_size */ struct ufs_ioctl_query_data { /* * User should select one of the opcode defined in "enum query_opcode". * Please check include/uapi/scsi/ufs/ufs.h for the definition of it. * Note that only UPIU_QUERY_OPCODE_READ_DESC, * UPIU_QUERY_OPCODE_READ_ATTR & UPIU_QUERY_OPCODE_READ_FLAG are * supported as of now. All other query_opcode would be considered * invalid. * As of now only read query operations are supported. */ __u32 opcode; /* * User should select one of the idn from "enum flag_idn" or "enum * attr_idn" or "enum desc_idn" based on whether opcode above is * attribute, flag or descriptor. * Please check include/uapi/scsi/ufs/ufs.h for the definition of it. */ __u8 idn; /* * User should specify the size of the buffer (buffer[0] below) where * it wants to read the query data (attribute/flag/descriptor). * As we might end up reading less data then what is specified in * buf_size. So we are updating buf_size to what exactly we have read. */ __u16 buf_size; /* * placeholder for the start of the data buffer where kernel will copy * the query data (attribute/flag/descriptor) read from the UFS device * Note: * For Read/Write Attribute you will have to allocate 4 bytes * For Read/Write Flag you will have to allocate 1 byte */ __u8 buffer[0]; }; #endif /* UFS_QCOM_H_ */