diff options
Diffstat (limited to 'drivers/scsi/ufs/ufshcd.h')
-rw-r--r-- | drivers/scsi/ufs/ufshcd.h | 368 |
1 files changed, 80 insertions, 288 deletions
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 94f545be183a..2b0f3441b813 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -12,44 +12,18 @@ #ifndef _UFSHCD_H #define _UFSHCD_H -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/io.h> -#include <linux/delay.h> -#include <linux/slab.h> -#include <linux/spinlock.h> -#include <linux/rwsem.h> -#include <linux/workqueue.h> -#include <linux/errno.h> -#include <linux/types.h> -#include <linux/wait.h> -#include <linux/bitops.h> -#include <linux/pm_runtime.h> -#include <linux/clk.h> -#include <linux/completion.h> -#include <linux/regulator/consumer.h> #include <linux/bitfield.h> -#include <linux/devfreq.h> #include <linux/blk-crypto-profile.h> +#include <linux/blk-mq.h> +#include <linux/devfreq.h> +#include <linux/pm_runtime.h> +#include <scsi/scsi_device.h> #include "unipro.h" - -#include <asm/irq.h> -#include <asm/byteorder.h> -#include <scsi/scsi.h> -#include <scsi/scsi_cmnd.h> -#include <scsi/scsi_host.h> -#include <scsi/scsi_tcq.h> -#include <scsi/scsi_dbg.h> -#include <scsi/scsi_eh.h> - #include "ufs.h" #include "ufs_quirks.h" #include "ufshci.h" #define UFSHCD "ufshcd" -#define UFSHCD_DRIVER_VERSION "0.2" struct ufs_hba; @@ -181,8 +155,6 @@ struct ufs_pm_lvl_states { * @ucd_rsp_dma_addr: UPIU response dma address for debug * @ucd_req_dma_addr: UPIU request dma address for debug * @cmd: pointer to SCSI command - * @sense_buffer: pointer to sense buffer address of the SCSI command - * @sense_bufflen: Length of the sense buffer * @scsi_status: SCSI status of the command * @command_type: SCSI, UFS, Query. * @task_tag: Task tag of the command @@ -206,8 +178,6 @@ struct ufshcd_lrb { dma_addr_t ucd_prdt_dma_addr; struct scsi_cmnd *cmd; - u8 *sense_buffer; - unsigned int sense_bufflen; int scsi_status; int command_type; @@ -241,6 +211,7 @@ struct ufs_query { * @type: device management command type - Query, NOP OUT * @lock: lock to allow one command at a time * @complete: internal commands completion + * @query: Device management query information */ struct ufs_dev_cmd { enum dev_cmd_type type; @@ -258,7 +229,7 @@ struct ufs_dev_cmd { * @min_freq: min frequency that can be used for clock scaling * @curr_freq: indicates the current frequency that it is set to * @keep_link_active: indicates that the clk should not be disabled if - link is active + * link is active * @enabled: variable to check against multiple enable/disable */ struct ufs_clk_info { @@ -313,11 +284,13 @@ struct ufs_pwr_mode_info { * to set some things * @hibern8_notify: called around hibern8 enter/exit * @apply_dev_quirks: called to apply device specific quirks + * @fixup_dev_quirks: called to modify device specific quirks * @suspend: called during host controller PM callback * @resume: called during host controller PM callback * @dbg_register_dump: used to dump controller debug information * @phy_initialization: used to initialize phys * @device_reset: called to issue a reset pulse on the UFS device + * @config_scaling_param: called to configure clock scaling parameters * @program_key: program or evict an inline encryption key * @event_notify: called to notify important events */ @@ -352,8 +325,8 @@ struct ufs_hba_variant_ops { int (*phy_initialization)(struct ufs_hba *); int (*device_reset)(struct ufs_hba *hba); void (*config_scaling_param)(struct ufs_hba *hba, - struct devfreq_dev_profile *profile, - void *data); + struct devfreq_dev_profile *profile, + struct devfreq_simple_ondemand_data *data); int (*program_key)(struct ufs_hba *hba, const union ufs_crypto_cfg_entry *cfg, int slot); void (*event_notify)(struct ufs_hba *hba, @@ -384,6 +357,7 @@ enum clk_gating_state { * @is_initialized: Indicates whether clock gating is initialized or not * @active_reqs: number of requests that are pending and should be waited for * completion before gating clocks. + * @clk_gating_workq: workqueue for clock gating work. */ struct ufs_clk_gating { struct delayed_work gate_work; @@ -420,9 +394,9 @@ struct ufs_saved_pwr_info { * @resume_work: worker to resume devfreq * @min_gear: lowest HS gear to scale down to * @is_enabled: tracks if scaling is currently enabled or not, controlled by - clkscale_enable sysfs node + * clkscale_enable sysfs node * @is_allowed: tracks if scaling is currently allowed or not, used to block - clock scaling which is not invoked from devfreq governor + * clock scaling which is not invoked from devfreq governor * @is_initialized: Indicates whether clock scaling is initialized or not * @is_busy_started: tracks if busy period has started or not * @is_suspended: tracks if devfreq is suspended or not @@ -449,7 +423,7 @@ struct ufs_clk_scaling { /** * struct ufs_event_hist - keeps history of errors * @pos: index to indicate cyclic buffer position - * @reg: cyclic buffer for registers value + * @val: cyclic buffer for registers value * @tstamp: cyclic buffer for time stamp * @cnt: error counter */ @@ -468,6 +442,7 @@ struct ufs_event_hist { * reset this after link-startup. * @last_hibern8_exit_tstamp: Set time after the hibern8 exit. * Clear after the first successful command completion. + * @event: array with event history. */ struct ufs_stats { u32 last_intr_status; @@ -737,6 +712,14 @@ struct ufs_hba_monitor { * @utmrdl_dma_addr: UTMRDL DMA address * @host: Scsi_Host instance of the driver * @dev: device handle + * @ufs_device_wlun: WLUN that controls the entire UFS device. + * @hwmon_device: device instance registered with the hwmon core. + * @curr_dev_pwr_mode: active UFS device power mode. + * @uic_link_state: active state of the link to the UFS device. + * @rpm_lvl: desired UFS power management level during runtime PM. + * @spm_lvl: desired UFS power management level during system PM. + * @pm_op_in_progress: whether or not a PM operation is in progress. + * @ahit: value of Auto-Hibernate Idle Timer register. * @lrb: local reference block * @outstanding_tasks: Bits representing outstanding task requests * @outstanding_lock: Protects @outstanding_reqs. @@ -747,17 +730,26 @@ struct ufs_hba_monitor { * @reserved_slot: Used to submit device commands. Protected by @dev_cmd.lock. * @ufs_version: UFS Version to which controller complies * @vops: pointer to variant specific operations + * @vps: pointer to variant specific parameters * @priv: pointer to variant specific private data * @irq: Irq number of the controller - * @active_uic_cmd: handle of active UIC command - * @uic_cmd_mutex: mutex for UIC command + * @is_irq_enabled: whether or not the UFS controller interrupt is enabled. + * @dev_ref_clk_freq: reference clock frequency + * @quirks: bitmask with information about deviations from the UFSHCI standard. + * @dev_quirks: bitmask with information about deviations from the UFS standard. * @tmf_tag_set: TMF tag set. * @tmf_queue: Used to allocate TMF tags. - * @pwr_done: completion for power mode change + * @tmf_rqs: array with pointers to TMF requests while these are in progress. + * @active_uic_cmd: handle of active UIC command + * @uic_cmd_mutex: mutex for UIC command + * @uic_async_done: completion used during UIC processing * @ufshcd_state: UFSHCD state * @eh_flags: Error handling flags * @intr_mask: Interrupt Mask Bits * @ee_ctrl_mask: Exception event control mask + * @ee_drv_mask: Exception event mask for driver + * @ee_usr_mask: Exception event mask for user (set via debugfs) + * @ee_ctrl_mutex: Used to serialize exception event information. * @is_powered: flag to check if HBA is powered * @shutting_down: flag to check if shutdown has been invoked * @host_sem: semaphore used to serialize concurrent contexts @@ -768,26 +760,52 @@ struct ufs_hba_monitor { * @uic_error: UFS interconnect layer error status * @saved_err: sticky error mask * @saved_uic_err: sticky UIC error mask + * @ufs_stats: various error counters * @force_reset: flag to force eh_work perform a full reset * @force_pmc: flag to force a power mode change * @silence_err_logs: flag to silence error logs * @dev_cmd: ufs device management command information * @last_dme_cmd_tstamp: time stamp of the last completed DME command + * @nop_out_timeout: NOP OUT timeout value + * @dev_info: information about the UFS device * @auto_bkops_enabled: to track whether bkops is enabled in device * @vreg_info: UFS device voltage regulator information * @clk_list_head: UFS host controller clocks list node head + * @req_abort_count: number of times ufshcd_abort() has been called + * @lanes_per_direction: number of lanes per data direction between the UFS + * controller and the UFS device. * @pwr_info: holds current power mode * @max_pwr_info: keeps the device max valid pwm - * @clk_scaling_lock: used to serialize device commands and clock scaling - * @desc_size: descriptor sizes reported by device + * @clk_gating: information related to clock gating + * @caps: bitmask with information about UFS controller capabilities + * @devfreq: frequency scaling information owned by the devfreq core + * @clk_scaling: frequency scaling information owned by the UFS driver + * @is_sys_suspended: whether or not the entire system has been suspended * @urgent_bkops_lvl: keeps track of urgent bkops level for device * @is_urgent_bkops_lvl_checked: keeps track if the urgent bkops level for * device is known or not. + * @clk_scaling_lock: used to serialize device commands and clock scaling + * @desc_size: descriptor sizes reported by device * @scsi_block_reqs_cnt: reference counting for scsi block requests + * @bsg_dev: struct device associated with the BSG queue + * @bsg_queue: BSG queue associated with the UFS controller + * @rpm_dev_flush_recheck_work: used to suspend from RPM (runtime power + * management) after the UFS device has finished a WriteBooster buffer + * flush or auto BKOP. + * @ufshpb_dev: information related to HPB (Host Performance Booster). + * @monitor: statistics about UFS commands * @crypto_capabilities: Content of crypto capabilities register (0x100) * @crypto_cap_array: Array of crypto capabilities * @crypto_cfg_register: Start of the crypto cfg array * @crypto_profile: the crypto profile of this hba (if applicable) + * @debugfs_root: UFS controller debugfs root directory + * @debugfs_ee_work: used to restore ee_ctrl_mask after a delay + * @debugfs_ee_rate_limit_ms: user configurable delay after which to restore + * ee_ctrl_mask + * @luns_avail: number of regular and well known LUNs supported by the UFS + * device + * @complete_put: whether or not to call ufshcd_rpm_put() from inside + * ufshcd_resume_complete() */ struct ufs_hba { void __iomem *mmio_base; @@ -804,11 +822,7 @@ struct ufs_hba { struct Scsi_Host *host; struct device *dev; - /* - * This field is to keep a reference to "scsi_device" corresponding to - * "UFS device" W-LU. - */ - struct scsi_device *sdev_ufs_device; + struct scsi_device *ufs_device_wlun; #ifdef CONFIG_SCSI_UFS_HWMON struct device *hwmon_device; @@ -859,9 +873,9 @@ struct ufs_hba { enum ufshcd_state ufshcd_state; u32 eh_flags; u32 intr_mask; - u16 ee_ctrl_mask; /* Exception event mask */ - u16 ee_drv_mask; /* Exception event mask for driver */ - u16 ee_usr_mask; /* Exception event mask for user (via debugfs) */ + u16 ee_ctrl_mask; + u16 ee_drv_mask; + u16 ee_usr_mask; struct mutex ee_ctrl_mutex; bool is_powered; bool shutting_down; @@ -983,7 +997,7 @@ static inline bool ufshcd_is_auto_hibern8_supported(struct ufs_hba *hba) static inline bool ufshcd_is_auto_hibern8_enabled(struct ufs_hba *hba) { - return FIELD_GET(UFSHCI_AHIBERN8_TIMER_MASK, hba->ahit) ? true : false; + return FIELD_GET(UFSHCI_AHIBERN8_TIMER_MASK, hba->ahit); } static inline bool ufshcd_is_wb_allowed(struct ufs_hba *hba) @@ -991,22 +1005,17 @@ static inline bool ufshcd_is_wb_allowed(struct ufs_hba *hba) return hba->caps & UFSHCD_CAP_WB_EN; } -static inline bool ufshcd_is_user_access_allowed(struct ufs_hba *hba) -{ - return !hba->shutting_down; -} - #define ufshcd_writel(hba, val, reg) \ writel((val), (hba)->mmio_base + (reg)) #define ufshcd_readl(hba, reg) \ readl((hba)->mmio_base + (reg)) /** - * ufshcd_rmwl - read modify write into a register - * @hba - per adapter instance - * @mask - mask to apply on read value - * @val - actual value to write - * @reg - register address + * ufshcd_rmwl - perform read/modify/write for a controller register + * @hba: per adapter instance + * @mask: mask to apply on read value + * @val: actual value to write + * @reg: register address */ static inline void ufshcd_rmwl(struct ufs_hba *hba, u32 mask, u32 val, u32 reg) { @@ -1028,9 +1037,6 @@ void ufshcd_remove(struct ufs_hba *); int ufshcd_uic_hibern8_enter(struct ufs_hba *hba); int ufshcd_uic_hibern8_exit(struct ufs_hba *hba); void ufshcd_delay_us(unsigned long us, unsigned long tolerance); -int ufshcd_wait_for_register(struct ufs_hba *hba, u32 reg, u32 mask, - u32 val, unsigned long interval_us, - unsigned long timeout_ms); void ufshcd_parse_dev_ref_clk_freq(struct ufs_hba *hba, struct clk *refclk); void ufshcd_update_evt_hist(struct ufs_hba *hba, u32 id, u32 val); void ufshcd_hba_stop(struct ufs_hba *hba); @@ -1044,8 +1050,8 @@ static inline void check_upiu_size(void) /** * ufshcd_set_variant - set variant specific data to the hba - * @hba - per adapter instance - * @variant - pointer to variant specific data + * @hba: per adapter instance + * @variant: pointer to variant specific data */ static inline void ufshcd_set_variant(struct ufs_hba *hba, void *variant) { @@ -1055,35 +1061,13 @@ static inline void ufshcd_set_variant(struct ufs_hba *hba, void *variant) /** * ufshcd_get_variant - get variant specific data from the hba - * @hba - per adapter instance + * @hba: per adapter instance */ static inline void *ufshcd_get_variant(struct ufs_hba *hba) { BUG_ON(!hba); return hba->priv; } -static inline bool ufshcd_keep_autobkops_enabled_except_suspend( - struct ufs_hba *hba) -{ - return hba->caps & UFSHCD_CAP_KEEP_AUTO_BKOPS_ENABLED_EXCEPT_SUSPEND; -} - -static inline u8 ufshcd_wb_get_query_index(struct ufs_hba *hba) -{ - if (hba->dev_info.wb_buffer_type == WB_BUF_MODE_LU_DEDICATED) - return hba->dev_info.wb_dedicated_lu; - return 0; -} - -#ifdef CONFIG_SCSI_UFS_HWMON -void ufs_hwmon_probe(struct ufs_hba *hba, u8 mask); -void ufs_hwmon_remove(struct ufs_hba *hba); -void ufs_hwmon_notify_event(struct ufs_hba *hba, u8 ee_mask); -#else -static inline void ufs_hwmon_probe(struct ufs_hba *hba, u8 mask) {} -static inline void ufs_hwmon_remove(struct ufs_hba *hba) {} -static inline void ufs_hwmon_notify_event(struct ufs_hba *hba, u8 ee_mask) {} -#endif #ifdef CONFIG_PM extern int ufshcd_runtime_suspend(struct device *dev); @@ -1185,7 +1169,8 @@ int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode, void ufshcd_auto_hibern8_enable(struct ufs_hba *hba); void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit); -void ufshcd_fixup_dev_quirks(struct ufs_hba *hba, struct ufs_dev_fix *fixups); +void ufshcd_fixup_dev_quirks(struct ufs_hba *hba, + const struct ufs_dev_quirk *fixups); #define SD_ASCII_STD true #define SD_RAW false int ufshcd_read_string_desc(struct ufs_hba *hba, u8 desc_index, @@ -1194,6 +1179,8 @@ int ufshcd_read_string_desc(struct ufs_hba *hba, u8 desc_index, int ufshcd_hold(struct ufs_hba *hba, bool async); void ufshcd_release(struct ufs_hba *hba); +void ufshcd_clkgate_delay_set(struct device *dev, unsigned long value); + void ufshcd_map_desc_id_to_length(struct ufs_hba *hba, enum desc_idn desc_id, int *desc_length); @@ -1214,13 +1201,6 @@ int __ufshcd_suspend_prepare(struct device *dev, bool rpm_ok_for_spm); void ufshcd_resume_complete(struct device *dev); /* Wrapper functions for safely calling variant operations */ -static inline const char *ufshcd_get_var_name(struct ufs_hba *hba) -{ - if (hba->vops) - return hba->vops->name; - return ""; -} - static inline int ufshcd_vops_init(struct ufs_hba *hba) { if (hba->vops && hba->vops->init) @@ -1229,61 +1209,6 @@ static inline int ufshcd_vops_init(struct ufs_hba *hba) return 0; } -static inline void ufshcd_vops_exit(struct ufs_hba *hba) -{ - if (hba->vops && hba->vops->exit) - return hba->vops->exit(hba); -} - -static inline u32 ufshcd_vops_get_ufs_hci_version(struct ufs_hba *hba) -{ - if (hba->vops && hba->vops->get_ufs_hci_version) - return hba->vops->get_ufs_hci_version(hba); - - return ufshcd_readl(hba, REG_UFS_VERSION); -} - -static inline int ufshcd_vops_clk_scale_notify(struct ufs_hba *hba, - bool up, enum ufs_notify_change_status status) -{ - if (hba->vops && hba->vops->clk_scale_notify) - return hba->vops->clk_scale_notify(hba, up, status); - return 0; -} - -static inline void ufshcd_vops_event_notify(struct ufs_hba *hba, - enum ufs_event_type evt, - void *data) -{ - if (hba->vops && hba->vops->event_notify) - hba->vops->event_notify(hba, evt, data); -} - -static inline int ufshcd_vops_setup_clocks(struct ufs_hba *hba, bool on, - enum ufs_notify_change_status status) -{ - if (hba->vops && hba->vops->setup_clocks) - return hba->vops->setup_clocks(hba, on, status); - return 0; -} - -static inline int ufshcd_vops_hce_enable_notify(struct ufs_hba *hba, - bool status) -{ - if (hba->vops && hba->vops->hce_enable_notify) - return hba->vops->hce_enable_notify(hba, status); - - return 0; -} -static inline int ufshcd_vops_link_startup_notify(struct ufs_hba *hba, - bool status) -{ - if (hba->vops && hba->vops->link_startup_notify) - return hba->vops->link_startup_notify(hba, status); - - return 0; -} - static inline int ufshcd_vops_phy_initialization(struct ufs_hba *hba) { if (hba->vops && hba->vops->phy_initialization) @@ -1292,102 +1217,8 @@ static inline int ufshcd_vops_phy_initialization(struct ufs_hba *hba) return 0; } -static inline int ufshcd_vops_pwr_change_notify(struct ufs_hba *hba, - enum ufs_notify_change_status status, - struct ufs_pa_layer_attr *dev_max_params, - struct ufs_pa_layer_attr *dev_req_params) -{ - if (hba->vops && hba->vops->pwr_change_notify) - return hba->vops->pwr_change_notify(hba, status, - dev_max_params, dev_req_params); - - return -ENOTSUPP; -} - -static inline void ufshcd_vops_setup_task_mgmt(struct ufs_hba *hba, - int tag, u8 tm_function) -{ - if (hba->vops && hba->vops->setup_task_mgmt) - return hba->vops->setup_task_mgmt(hba, tag, tm_function); -} - -static inline void ufshcd_vops_hibern8_notify(struct ufs_hba *hba, - enum uic_cmd_dme cmd, - enum ufs_notify_change_status status) -{ - if (hba->vops && hba->vops->hibern8_notify) - return hba->vops->hibern8_notify(hba, cmd, status); -} - -static inline int ufshcd_vops_apply_dev_quirks(struct ufs_hba *hba) -{ - if (hba->vops && hba->vops->apply_dev_quirks) - return hba->vops->apply_dev_quirks(hba); - return 0; -} - -static inline void ufshcd_vops_fixup_dev_quirks(struct ufs_hba *hba) -{ - if (hba->vops && hba->vops->fixup_dev_quirks) - hba->vops->fixup_dev_quirks(hba); -} - -static inline int ufshcd_vops_suspend(struct ufs_hba *hba, enum ufs_pm_op op, - enum ufs_notify_change_status status) -{ - if (hba->vops && hba->vops->suspend) - return hba->vops->suspend(hba, op, status); - - return 0; -} - -static inline int ufshcd_vops_resume(struct ufs_hba *hba, enum ufs_pm_op op) -{ - if (hba->vops && hba->vops->resume) - return hba->vops->resume(hba, op); - - return 0; -} - -static inline void ufshcd_vops_dbg_register_dump(struct ufs_hba *hba) -{ - if (hba->vops && hba->vops->dbg_register_dump) - hba->vops->dbg_register_dump(hba); -} - -static inline int ufshcd_vops_device_reset(struct ufs_hba *hba) -{ - if (hba->vops && hba->vops->device_reset) - return hba->vops->device_reset(hba); - - return -EOPNOTSUPP; -} - -static inline void ufshcd_vops_config_scaling_param(struct ufs_hba *hba, - struct devfreq_dev_profile - *profile, void *data) -{ - if (hba->vops && hba->vops->config_scaling_param) - hba->vops->config_scaling_param(hba, profile, data); -} - extern struct ufs_pm_lvl_states ufs_pm_lvl_states[]; -/* - * ufshcd_scsi_to_upiu_lun - maps scsi LUN to UPIU LUN - * @scsi_lun: scsi LUN id - * - * Returns UPIU LUN id - */ -static inline u8 ufshcd_scsi_to_upiu_lun(unsigned int scsi_lun) -{ - if (scsi_is_wlun(scsi_lun)) - return (scsi_lun & UFS_UPIU_MAX_UNIT_NUM_ID) - | UFS_UPIU_WLUN_ID; - else - return scsi_lun & UFS_UPIU_MAX_UNIT_NUM_ID; -} - int ufshcd_dump_regs(struct ufs_hba *hba, size_t offset, size_t len, const char *prefix); @@ -1396,43 +1227,4 @@ int ufshcd_write_ee_control(struct ufs_hba *hba); int ufshcd_update_ee_control(struct ufs_hba *hba, u16 *mask, u16 *other_mask, u16 set, u16 clr); -static inline int ufshcd_update_ee_drv_mask(struct ufs_hba *hba, - u16 set, u16 clr) -{ - return ufshcd_update_ee_control(hba, &hba->ee_drv_mask, - &hba->ee_usr_mask, set, clr); -} - -static inline int ufshcd_update_ee_usr_mask(struct ufs_hba *hba, - u16 set, u16 clr) -{ - return ufshcd_update_ee_control(hba, &hba->ee_usr_mask, - &hba->ee_drv_mask, set, clr); -} - -static inline int ufshcd_rpm_get_sync(struct ufs_hba *hba) -{ - return pm_runtime_get_sync(&hba->sdev_ufs_device->sdev_gendev); -} - -static inline int ufshcd_rpm_put_sync(struct ufs_hba *hba) -{ - return pm_runtime_put_sync(&hba->sdev_ufs_device->sdev_gendev); -} - -static inline void ufshcd_rpm_get_noresume(struct ufs_hba *hba) -{ - pm_runtime_get_noresume(&hba->sdev_ufs_device->sdev_gendev); -} - -static inline int ufshcd_rpm_resume(struct ufs_hba *hba) -{ - return pm_runtime_resume(&hba->sdev_ufs_device->sdev_gendev); -} - -static inline int ufshcd_rpm_put(struct ufs_hba *hba) -{ - return pm_runtime_put(&hba->sdev_ufs_device->sdev_gendev); -} - #endif /* End of Header */ |