Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/ufshci/ufshci_private.h
| Show First 20 Lines • Show All 62 Lines • ▼ Show 20 Lines | struct ufshci_request { | ||||
| struct memdesc payload; | struct memdesc payload; | ||||
| enum ufshci_data_direction data_direction; | enum ufshci_data_direction data_direction; | ||||
| ufshci_cb_fn_t cb_fn; | ufshci_cb_fn_t cb_fn; | ||||
| void *cb_arg; | void *cb_arg; | ||||
| bool is_admin; | bool is_admin; | ||||
| int32_t retries; | int32_t retries; | ||||
| bool payload_valid; | bool payload_valid; | ||||
| bool timeout; | |||||
| bool spare[2]; /* Future use */ | bool spare[2]; /* Future use */ | ||||
| STAILQ_ENTRY(ufshci_request) stailq; | STAILQ_ENTRY(ufshci_request) stailq; | ||||
| }; | }; | ||||
| enum ufshci_slot_state { | enum ufshci_slot_state { | ||||
| UFSHCI_SLOT_STATE_FREE = 0x0, | UFSHCI_SLOT_STATE_FREE = 0x0, | ||||
| UFSHCI_SLOT_STATE_RESERVED = 0x1, | UFSHCI_SLOT_STATE_RESERVED = 0x1, | ||||
| UFSHCI_SLOT_STATE_SCHEDULED = 0x2, | UFSHCI_SLOT_STATE_SCHEDULED = 0x2, | ||||
| UFSHCI_SLOT_STATE_TIMEOUT = 0x3, | UFSHCI_SLOT_STATE_TIMEOUT = 0x3, | ||||
| UFSHCI_SLOT_STATE_NEED_ERROR_HANDLING = 0x4, | UFSHCI_SLOT_STATE_NEED_ERROR_HANDLING = 0x4, | ||||
| }; | }; | ||||
| struct ufshci_tracker { | struct ufshci_tracker { | ||||
| TAILQ_ENTRY(ufshci_tracker) tailq; | |||||
| struct ufshci_request *req; | struct ufshci_request *req; | ||||
| struct ufshci_req_queue *req_queue; | struct ufshci_req_queue *req_queue; | ||||
| struct ufshci_hw_queue *hwq; | struct ufshci_hw_queue *hwq; | ||||
| uint8_t slot_num; | uint8_t slot_num; | ||||
| enum ufshci_slot_state slot_state; | enum ufshci_slot_state slot_state; | ||||
| size_t response_size; | size_t response_size; | ||||
| sbintime_t deadline; | sbintime_t deadline; | ||||
| Show All 23 Lines | int (*construct)(struct ufshci_controller *ctrlr, | ||||
| struct ufshci_req_queue *req_queue, uint32_t num_entries, | struct ufshci_req_queue *req_queue, uint32_t num_entries, | ||||
| bool is_task_mgmt); | bool is_task_mgmt); | ||||
| void (*destroy)(struct ufshci_controller *ctrlr, | void (*destroy)(struct ufshci_controller *ctrlr, | ||||
| struct ufshci_req_queue *req_queue); | struct ufshci_req_queue *req_queue); | ||||
| struct ufshci_hw_queue *(*get_hw_queue)( | struct ufshci_hw_queue *(*get_hw_queue)( | ||||
| struct ufshci_req_queue *req_queue); | struct ufshci_req_queue *req_queue); | ||||
| int (*enable)(struct ufshci_controller *ctrlr, | int (*enable)(struct ufshci_controller *ctrlr, | ||||
| struct ufshci_req_queue *req_queue); | struct ufshci_req_queue *req_queue); | ||||
| void (*disable)(struct ufshci_controller *ctrlr, | |||||
| struct ufshci_req_queue *req_queue); | |||||
| int (*reserve_slot)(struct ufshci_req_queue *req_queue, | int (*reserve_slot)(struct ufshci_req_queue *req_queue, | ||||
| struct ufshci_tracker **tr); | struct ufshci_tracker **tr); | ||||
| int (*reserve_admin_slot)(struct ufshci_req_queue *req_queue, | int (*reserve_admin_slot)(struct ufshci_req_queue *req_queue, | ||||
| struct ufshci_tracker **tr); | struct ufshci_tracker **tr); | ||||
| void (*ring_doorbell)(struct ufshci_controller *ctrlr, | void (*ring_doorbell)(struct ufshci_controller *ctrlr, | ||||
| struct ufshci_tracker *tr); | struct ufshci_tracker *tr); | ||||
| bool (*is_doorbell_cleared)(struct ufshci_controller *ctrlr, | bool (*is_doorbell_cleared)(struct ufshci_controller *ctrlr, | ||||
| uint8_t slot); | uint8_t slot); | ||||
| void (*clear_cpl_ntf)(struct ufshci_controller *ctrlr, | void (*clear_cpl_ntf)(struct ufshci_controller *ctrlr, | ||||
| struct ufshci_tracker *tr); | struct ufshci_tracker *tr); | ||||
| bool (*process_cpl)(struct ufshci_req_queue *req_queue); | bool (*process_cpl)(struct ufshci_req_queue *req_queue); | ||||
| int (*get_inflight_io)(struct ufshci_controller *ctrlr); | int (*get_inflight_io)(struct ufshci_controller *ctrlr); | ||||
| }; | }; | ||||
| #define UFSHCI_SDB_Q 0 /* Queue number for a single doorbell queue */ | #define UFSHCI_SDB_Q 0 /* Queue number for a single doorbell queue */ | ||||
| enum ufshci_recovery { | |||||
| RECOVERY_NONE = 0, /* Normal operations */ | |||||
| RECOVERY_WAITING, /* waiting for the reset to complete */ | |||||
| }; | |||||
| /* | /* | ||||
| * Generic queue container used by both SDB (fixed 32-slot bitmap) and MCQ | * Generic queue container used by both SDB (fixed 32-slot bitmap) and MCQ | ||||
| * (ring buffer) modes. Fields are shared; some such as sq_head, sq_tail and | * (ring buffer) modes. Fields are shared; some such as sq_head, sq_tail and | ||||
| * cq_head are not used in SDB but used in MCQ. | * cq_head are not used in SDB but used in MCQ. | ||||
| */ | */ | ||||
| struct ufshci_hw_queue { | struct ufshci_hw_queue { | ||||
| struct ufshci_controller *ctrlr; | |||||
| struct ufshci_req_queue *req_queue; | |||||
| uint32_t id; | uint32_t id; | ||||
| int domain; | int domain; | ||||
| int cpu; | int cpu; | ||||
| struct callout timer; /* recovery lock */ | |||||
| bool timer_armed; /* recovery lock */ | |||||
| enum ufshci_recovery recovery_state; /* recovery lock */ | |||||
| union { | union { | ||||
| struct ufshci_utp_xfer_req_desc *utrd; | struct ufshci_utp_xfer_req_desc *utrd; | ||||
| struct ufshci_utp_task_mgmt_req_desc *utmrd; | struct ufshci_utp_task_mgmt_req_desc *utmrd; | ||||
| }; | }; | ||||
| bus_dma_tag_t dma_tag_queue; | bus_dma_tag_t dma_tag_queue; | ||||
| bus_dmamap_t queuemem_map; | bus_dmamap_t queuemem_map; | ||||
| bus_addr_t req_queue_addr; | bus_addr_t req_queue_addr; | ||||
| bus_addr_t *ucd_bus_addr; | bus_addr_t *ucd_bus_addr; | ||||
| uint32_t num_entries; | uint32_t num_entries; | ||||
| uint32_t num_trackers; | uint32_t num_trackers; | ||||
| TAILQ_HEAD(, ufshci_tracker) free_tr; | |||||
| TAILQ_HEAD(, ufshci_tracker) outstanding_tr; | |||||
| /* | /* | ||||
| * A Request List using the single doorbell method uses a dedicated | * A Request List using the single doorbell method uses a dedicated | ||||
| * ufshci_tracker, one per slot. | * ufshci_tracker, one per slot. | ||||
| */ | */ | ||||
| struct ufshci_tracker **act_tr; | struct ufshci_tracker **act_tr; | ||||
| uint32_t sq_head; /* MCQ mode */ | uint32_t sq_head; /* MCQ mode */ | ||||
| uint32_t sq_tail; /* MCQ mode */ | uint32_t sq_tail; /* MCQ mode */ | ||||
| uint32_t cq_head; /* MCQ mode */ | uint32_t cq_head; /* MCQ mode */ | ||||
| uint32_t phase; | uint32_t phase; | ||||
| int64_t num_cmds; | int64_t num_cmds; | ||||
| int64_t num_intr_handler_calls; | int64_t num_intr_handler_calls; | ||||
| int64_t num_retries; | int64_t num_retries; | ||||
| int64_t num_failures; | int64_t num_failures; | ||||
| /* | |||||
| * Each lock may be acquired independently. | |||||
| * When both are required, acquire them in this order to avoid | |||||
| * deadlocks. (recovery_lock -> qlock) | |||||
| */ | |||||
| struct mtx_padalign qlock; | struct mtx_padalign qlock; | ||||
| struct mtx_padalign recovery_lock; | |||||
| }; | }; | ||||
| struct ufshci_req_queue { | struct ufshci_req_queue { | ||||
| struct ufshci_controller *ctrlr; | struct ufshci_controller *ctrlr; | ||||
| int domain; | int domain; | ||||
| /* | /* | ||||
| * queue_mode: active transfer scheme | * queue_mode: active transfer scheme | ||||
| ▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | |||||
| #define UFSHCI_QUIRK_IGNORE_UIC_POWER_MODE \ | #define UFSHCI_QUIRK_IGNORE_UIC_POWER_MODE \ | ||||
| 1 /* QEMU does not support UIC POWER MODE */ | 1 /* QEMU does not support UIC POWER MODE */ | ||||
| #define UFSHCI_QUIRK_LONG_PEER_PA_TACTIVATE \ | #define UFSHCI_QUIRK_LONG_PEER_PA_TACTIVATE \ | ||||
| 2 /* Need an additional 200 ms of PA_TActivate */ | 2 /* Need an additional 200 ms of PA_TActivate */ | ||||
| #define UFSHCI_QUIRK_WAIT_AFTER_POWER_MODE_CHANGE \ | #define UFSHCI_QUIRK_WAIT_AFTER_POWER_MODE_CHANGE \ | ||||
| 4 /* Need to wait 1250us after power mode change */ | 4 /* Need to wait 1250us after power mode change */ | ||||
| #define UFSHCI_QUIRK_CHANGE_LANE_AND_GEAR_SEPARATELY \ | #define UFSHCI_QUIRK_CHANGE_LANE_AND_GEAR_SEPARATELY \ | ||||
| 8 /* Need to change the number of lanes before changing HS-GEAR. */ | 8 /* Need to change the number of lanes before changing HS-GEAR. */ | ||||
| #define UFSHCI_QUIRK_NOT_SUPPORT_ABORT_TASK \ | |||||
| 16 /* QEMU does not support Task Management Request */ | |||||
| uint32_t ref_clk; | uint32_t ref_clk; | ||||
| struct cam_sim *ufshci_sim; | struct cam_sim *ufshci_sim; | ||||
| struct cam_path *ufshci_path; | struct cam_path *ufshci_path; | ||||
| struct mtx sc_mtx; | struct mtx sc_mtx; | ||||
| uint32_t sc_unit; | uint32_t sc_unit; | ||||
| uint8_t sc_name[16]; | uint8_t sc_name[16]; | ||||
| struct ufshci_device ufs_dev; | struct ufshci_device ufs_dev; | ||||
| bus_space_tag_t bus_tag; | bus_space_tag_t bus_tag; | ||||
| bus_space_handle_t bus_handle; | bus_space_handle_t bus_handle; | ||||
| int resource_id; | int resource_id; | ||||
| struct resource *resource; | struct resource *resource; | ||||
| /* Currently, there is no UFSHCI that supports MSI, MSI-X. */ | /* Currently, there is no UFSHCI that supports MSI, MSI-X. */ | ||||
| int msi_count; | int msi_count; | ||||
| /* Fields for tracking progress during controller initialization. */ | /* Fields for tracking progress during controller initialization. */ | ||||
| struct intr_config_hook config_hook; | struct intr_config_hook config_hook; | ||||
| struct task reset_task; | |||||
| struct taskqueue *taskqueue; | |||||
| /* For shared legacy interrupt. */ | /* For shared legacy interrupt. */ | ||||
| int rid; | int rid; | ||||
| struct resource *res; | struct resource *res; | ||||
| void *tag; | void *tag; | ||||
| uint32_t major_version; | uint32_t major_version; | ||||
| uint32_t minor_version; | uint32_t minor_version; | ||||
| uint32_t enable_aborts; | |||||
| uint32_t num_io_queues; | uint32_t num_io_queues; | ||||
| uint32_t max_hw_pend_io; | uint32_t max_hw_pend_io; | ||||
| /* Maximum logical unit number */ | /* Maximum logical unit number */ | ||||
| uint32_t max_lun_count; | uint32_t max_lun_count; | ||||
| /* Maximum i/o size in bytes */ | /* Maximum i/o size in bytes */ | ||||
| uint32_t max_xfer_size; | uint32_t max_xfer_size; | ||||
| ▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | |||||
| /* SIM */ | /* SIM */ | ||||
| int ufshci_sim_attach(struct ufshci_controller *ctrlr); | int ufshci_sim_attach(struct ufshci_controller *ctrlr); | ||||
| void ufshci_sim_detach(struct ufshci_controller *ctrlr); | void ufshci_sim_detach(struct ufshci_controller *ctrlr); | ||||
| /* Controller */ | /* Controller */ | ||||
| int ufshci_ctrlr_construct(struct ufshci_controller *ctrlr, device_t dev); | int ufshci_ctrlr_construct(struct ufshci_controller *ctrlr, device_t dev); | ||||
| void ufshci_ctrlr_destruct(struct ufshci_controller *ctrlr, device_t dev); | void ufshci_ctrlr_destruct(struct ufshci_controller *ctrlr, device_t dev); | ||||
| int ufshci_ctrlr_reset(struct ufshci_controller *ctrlr); | void ufshci_ctrlr_reset(struct ufshci_controller *ctrlr); | ||||
| /* ctrlr defined as void * to allow use with config_intrhook. */ | /* ctrlr defined as void * to allow use with config_intrhook. */ | ||||
| void ufshci_ctrlr_start_config_hook(void *arg); | void ufshci_ctrlr_start_config_hook(void *arg); | ||||
| void ufshci_ctrlr_poll(struct ufshci_controller *ctrlr); | void ufshci_ctrlr_poll(struct ufshci_controller *ctrlr); | ||||
| int ufshci_ctrlr_submit_task_mgmt_request(struct ufshci_controller *ctrlr, | int ufshci_ctrlr_submit_task_mgmt_request(struct ufshci_controller *ctrlr, | ||||
| struct ufshci_request *req); | struct ufshci_request *req); | ||||
| int ufshci_ctrlr_submit_admin_request(struct ufshci_controller *ctrlr, | int ufshci_ctrlr_submit_admin_request(struct ufshci_controller *ctrlr, | ||||
| struct ufshci_request *req); | struct ufshci_request *req); | ||||
| Show All 26 Lines | void ufshci_ctrlr_cmd_send_scsi_command(struct ufshci_controller *ctrlr, | ||||
| uint32_t data_len, uint8_t lun, bool is_write); | uint32_t data_len, uint8_t lun, bool is_write); | ||||
| /* Request Queue */ | /* Request Queue */ | ||||
| bool ufshci_req_queue_process_completions(struct ufshci_req_queue *req_queue); | bool ufshci_req_queue_process_completions(struct ufshci_req_queue *req_queue); | ||||
| int ufshci_utmr_req_queue_construct(struct ufshci_controller *ctrlr); | int ufshci_utmr_req_queue_construct(struct ufshci_controller *ctrlr); | ||||
| int ufshci_utr_req_queue_construct(struct ufshci_controller *ctrlr); | int ufshci_utr_req_queue_construct(struct ufshci_controller *ctrlr); | ||||
| void ufshci_utmr_req_queue_destroy(struct ufshci_controller *ctrlr); | void ufshci_utmr_req_queue_destroy(struct ufshci_controller *ctrlr); | ||||
| void ufshci_utr_req_queue_destroy(struct ufshci_controller *ctrlr); | void ufshci_utr_req_queue_destroy(struct ufshci_controller *ctrlr); | ||||
| void ufshci_utmr_req_queue_disable(struct ufshci_controller *ctrlr); | |||||
| int ufshci_utmr_req_queue_enable(struct ufshci_controller *ctrlr); | int ufshci_utmr_req_queue_enable(struct ufshci_controller *ctrlr); | ||||
| void ufshci_utr_req_queue_disable(struct ufshci_controller *ctrlr); | |||||
| int ufshci_utr_req_queue_enable(struct ufshci_controller *ctrlr); | int ufshci_utr_req_queue_enable(struct ufshci_controller *ctrlr); | ||||
| void ufshci_req_queue_fail(struct ufshci_controller *ctrlr, | void ufshci_req_queue_fail(struct ufshci_controller *ctrlr, | ||||
| struct ufshci_hw_queue *hwq); | struct ufshci_hw_queue *hwq); | ||||
| int ufshci_req_queue_submit_request(struct ufshci_req_queue *req_queue, | int ufshci_req_queue_submit_request(struct ufshci_req_queue *req_queue, | ||||
| struct ufshci_request *req, bool is_admin); | struct ufshci_request *req, bool is_admin); | ||||
| void ufshci_req_queue_complete_tracker(struct ufshci_tracker *tr); | void ufshci_req_queue_complete_tracker(struct ufshci_tracker *tr); | ||||
| /* Request Single Doorbell Queue */ | /* Request Single Doorbell Queue */ | ||||
| int ufshci_req_sdb_construct(struct ufshci_controller *ctrlr, | int ufshci_req_sdb_construct(struct ufshci_controller *ctrlr, | ||||
| struct ufshci_req_queue *req_queue, uint32_t num_entries, | struct ufshci_req_queue *req_queue, uint32_t num_entries, | ||||
| bool is_task_mgmt); | bool is_task_mgmt); | ||||
| void ufshci_req_sdb_destroy(struct ufshci_controller *ctrlr, | void ufshci_req_sdb_destroy(struct ufshci_controller *ctrlr, | ||||
| struct ufshci_req_queue *req_queue); | struct ufshci_req_queue *req_queue); | ||||
| struct ufshci_hw_queue *ufshci_req_sdb_get_hw_queue( | struct ufshci_hw_queue *ufshci_req_sdb_get_hw_queue( | ||||
| struct ufshci_req_queue *req_queue); | struct ufshci_req_queue *req_queue); | ||||
| void ufshci_req_sdb_disable(struct ufshci_controller *ctrlr, | |||||
| struct ufshci_req_queue *req_queue); | |||||
| int ufshci_req_sdb_enable(struct ufshci_controller *ctrlr, | int ufshci_req_sdb_enable(struct ufshci_controller *ctrlr, | ||||
| struct ufshci_req_queue *req_queue); | struct ufshci_req_queue *req_queue); | ||||
| int ufshci_req_sdb_reserve_slot(struct ufshci_req_queue *req_queue, | int ufshci_req_sdb_reserve_slot(struct ufshci_req_queue *req_queue, | ||||
| struct ufshci_tracker **tr); | struct ufshci_tracker **tr); | ||||
| void ufshci_req_sdb_utmr_ring_doorbell(struct ufshci_controller *ctrlr, | void ufshci_req_sdb_utmr_ring_doorbell(struct ufshci_controller *ctrlr, | ||||
| struct ufshci_tracker *tr); | struct ufshci_tracker *tr); | ||||
| void ufshci_req_sdb_utr_ring_doorbell(struct ufshci_controller *ctrlr, | void ufshci_req_sdb_utr_ring_doorbell(struct ufshci_controller *ctrlr, | ||||
| struct ufshci_tracker *tr); | struct ufshci_tracker *tr); | ||||
| ▲ Show 20 Lines • Show All 69 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| static __inline struct ufshci_request * | static __inline struct ufshci_request * | ||||
| _ufshci_allocate_request(const int how, ufshci_cb_fn_t cb_fn, void *cb_arg) | _ufshci_allocate_request(const int how, ufshci_cb_fn_t cb_fn, void *cb_arg) | ||||
| { | { | ||||
| struct ufshci_request *req; | struct ufshci_request *req; | ||||
| KASSERT(how == M_WAITOK || how == M_NOWAIT, | KASSERT(how == M_WAITOK || how == M_NOWAIT, | ||||
| ("nvme_allocate_request: invalid how %d", how)); | ("ufshci_allocate_request: invalid how %d", how)); | ||||
| req = malloc(sizeof(*req), M_UFSHCI, how | M_ZERO); | req = malloc(sizeof(*req), M_UFSHCI, how | M_ZERO); | ||||
| if (req != NULL) { | if (req != NULL) { | ||||
| req->cb_fn = cb_fn; | req->cb_fn = cb_fn; | ||||
| req->cb_arg = cb_arg; | req->cb_arg = cb_arg; | ||||
| req->timeout = true; | |||||
| } | } | ||||
| return (req); | return (req); | ||||
| } | } | ||||
| static __inline struct ufshci_request * | static __inline struct ufshci_request * | ||||
| ufshci_allocate_request_vaddr(void *payload, uint32_t payload_size, | ufshci_allocate_request_vaddr(void *payload, uint32_t payload_size, | ||||
| const int how, ufshci_cb_fn_t cb_fn, void *cb_arg) | const int how, ufshci_cb_fn_t cb_fn, void *cb_arg) | ||||
| { | { | ||||
| Show All 31 Lines | |||||