// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2017-2018 Samsung Electronics Co., Ltd. */ #ifndef _UFSTW_H_ #define _UFSTW_H_ #include #include #include #include #include #include "../../../block/blk.h" #define UFSTW_VER 0x0101 #define UFSTW_DD_VER 0x0103 #define UFSTW_FLUSH_CHECK_PERIOD_MS 1000 #define UFSTW_FLUSH_WORKER_TH_MIN 3 #define UFSTW_FLUSH_WORKER_TH_MAX 8 #define UFSTW_LIFETIME_SECT 2097152 /* 1GB */ #define UFSTW_MAX_LIFETIME_VALUE 0x0B /* TW 1.0.1[31], TW 1.1.0[7] */ #define MASK_UFSTW_LIFETIME_NOT_GUARANTEE 0x80000080 /* * UFSTW DEBUG */ #define TW_DEBUG(ufsf, msg, args...) \ do { if (ufsf->tw_debug) \ printk(KERN_ERR "%s:%d " msg "\n", \ __func__, __LINE__, ##args); \ } while (0) enum { FLUSH_IDLE = 0, FLUSH_RUN, FLUSH_COMPLETE, FLUSH_FAIL, FLUSH_NUM_OF_STATE, }; enum UFSTW_STATE { TW_NOT_SUPPORTED = -1, TW_NEED_INIT = 0, TW_PRESENT = 1, TW_FAILED = -2, TW_RESET = -3, }; enum { TW_MODE_DISABLED, TW_MODE_MANUAL, TW_MODE_FS, TW_MODE_NUM }; enum { TW_EE_MODE_DISABLE, TW_EE_MODE_AUTO, TW_EE_MODE_NUM }; enum { TW_FLAG_ENABLE_NONE = 0, TW_FLAG_ENABLE_CLEAR = 1, TW_FLAG_ENABLE_SET = 2, }; struct ufstw_dev_info { bool tw_device; /* from Device Descriptor */ u16 tw_ver; u8 tw_buf_no_reduct; u8 tw_buf_type; /* from Geometry Descriptor */ u8 tw_number_lu; }; struct ufstw_lu { struct ufsf_feature *ufsf; int lun; /* Flags */ bool tw_flush_enable; bool tw_flush_during_hibern_enter; struct mutex flush_lock; /* lifetiem estimated */ unsigned int tw_lifetime_est; spinlock_t lifetime_lock; u32 stat_write_sec; struct work_struct tw_lifetime_work; /* Attributes */ unsigned int tw_flush_status; unsigned int tw_available_buffer_size; unsigned int tw_current_tw_buffer_size; /* mode manual/fs */ atomic_t tw_mode; bool tw_enable; atomic_t active_cnt; struct mutex mode_lock; /* Worker */ struct delayed_work tw_flush_work; struct delayed_work tw_flush_h8_work; unsigned long next_q; unsigned int flush_th_max; unsigned int flush_th_min; /* for sysfs */ struct kobject kobj; struct mutex sysfs_lock; struct ufstw_sysfs_entry *sysfs_entries; }; struct ufstw_sysfs_entry { struct attribute attr; ssize_t (*show)(struct ufstw_lu *tw, char *buf); ssize_t (*store)(struct ufstw_lu *tw, const char *buf, size_t count); }; struct ufshcd_lrb; void ufstw_get_dev_info(struct ufstw_dev_info *tw_dev_info, u8 *desc_buf); void ufstw_get_geo_info(struct ufstw_dev_info *tw_dev_info, u8 *geo_buf); int ufstw_get_lu_info(struct ufsf_feature *ufsf, unsigned int lun, u8 *lu_buf); void ufstw_init(struct ufsf_feature *ufsf); void ufstw_prep_fn(struct ufsf_feature *ufsf, struct ufshcd_lrb *lrbp); void ufstw_init_work_fn(struct work_struct *work); void ufstw_ee_handler(struct ufsf_feature *ufsf); void ufstw_error_handler(struct ufsf_feature *ufsf); void ufstw_reset_work_fn(struct work_struct *work); void ufstw_suspend(struct ufsf_feature *ufsf); void ufstw_resume(struct ufsf_feature *ufsf); void ufstw_release(struct kref *kref); bool ufstw_need_flush(struct ufsf_feature *ufsf); #endif /* End of Header */