xref: /freebsd/sys/dev/ufshci/ufshci_private.h (revision 9d0d55e398bfea1ebc2ef18e8d83edcf7e55f1b2)
1*1349a733SJaeyoon Choi /*-
2*1349a733SJaeyoon Choi  * Copyright (c) 2025, Samsung Electronics Co., Ltd.
3*1349a733SJaeyoon Choi  * Written by Jaeyoon Choi
4*1349a733SJaeyoon Choi  *
5*1349a733SJaeyoon Choi  * SPDX-License-Identifier: BSD-2-Clause
6*1349a733SJaeyoon Choi  */
7*1349a733SJaeyoon Choi 
8*1349a733SJaeyoon Choi #ifndef __UFSHCI_PRIVATE_H__
9*1349a733SJaeyoon Choi #define __UFSHCI_PRIVATE_H__
10*1349a733SJaeyoon Choi 
11*1349a733SJaeyoon Choi #ifdef _KERNEL
12*1349a733SJaeyoon Choi #include <sys/types.h>
13*1349a733SJaeyoon Choi #else /* !_KERNEL */
14*1349a733SJaeyoon Choi #include <stdbool.h>
15*1349a733SJaeyoon Choi #include <stdint.h>
16*1349a733SJaeyoon Choi #endif /* _KERNEL */
17*1349a733SJaeyoon Choi 
18*1349a733SJaeyoon Choi #include <sys/param.h>
19*1349a733SJaeyoon Choi #include <sys/systm.h>
20*1349a733SJaeyoon Choi #include <sys/bio.h>
21*1349a733SJaeyoon Choi #include <sys/bus.h>
22*1349a733SJaeyoon Choi #include <sys/counter.h>
23*1349a733SJaeyoon Choi #include <sys/kernel.h>
24*1349a733SJaeyoon Choi #include <sys/lock.h>
25*1349a733SJaeyoon Choi #include <sys/malloc.h>
26*1349a733SJaeyoon Choi #include <sys/memdesc.h>
27*1349a733SJaeyoon Choi #include <sys/module.h>
28*1349a733SJaeyoon Choi #include <sys/mutex.h>
29*1349a733SJaeyoon Choi #include <sys/rman.h>
30*1349a733SJaeyoon Choi #include <sys/taskqueue.h>
31*1349a733SJaeyoon Choi 
32*1349a733SJaeyoon Choi #include <machine/bus.h>
33*1349a733SJaeyoon Choi 
34*1349a733SJaeyoon Choi #include "ufshci.h"
35*1349a733SJaeyoon Choi 
36*1349a733SJaeyoon Choi MALLOC_DECLARE(M_UFSHCI);
37*1349a733SJaeyoon Choi 
38*1349a733SJaeyoon Choi #define UFSHCI_DEVICE_INIT_TIMEOUT_MS (2000) /* in milliseconds */
39*1349a733SJaeyoon Choi #define UFSHCI_UIC_CMD_TIMEOUT_MS     (500)  /* in milliseconds */
40*1349a733SJaeyoon Choi #define UFSHCI_DEFAULT_TIMEOUT_PERIOD (10)   /* in seconds */
41*1349a733SJaeyoon Choi #define UFSHCI_MIN_TIMEOUT_PERIOD     (5)    /* in seconds */
42*1349a733SJaeyoon Choi #define UFSHCI_MAX_TIMEOUT_PERIOD     (120)  /* in seconds */
43*1349a733SJaeyoon Choi 
44*1349a733SJaeyoon Choi #define UFSHCI_DEFAULT_RETRY_COUNT    (4)
45*1349a733SJaeyoon Choi 
46*1349a733SJaeyoon Choi #define UFSHCI_UTR_ENTRIES	      (32)
47*1349a733SJaeyoon Choi #define UFSHCI_UTRM_ENTRIES	      (8)
48*1349a733SJaeyoon Choi 
49*1349a733SJaeyoon Choi struct ufshci_controller;
50*1349a733SJaeyoon Choi 
51*1349a733SJaeyoon Choi struct ufshci_completion_poll_status {
52*1349a733SJaeyoon Choi 	struct ufshci_completion cpl;
53*1349a733SJaeyoon Choi 	int done;
54*1349a733SJaeyoon Choi 	bool error;
55*1349a733SJaeyoon Choi };
56*1349a733SJaeyoon Choi 
57*1349a733SJaeyoon Choi struct ufshci_request {
58*1349a733SJaeyoon Choi 	struct ufshci_upiu request_upiu;
59*1349a733SJaeyoon Choi 	size_t request_size;
60*1349a733SJaeyoon Choi 	size_t response_size;
61*1349a733SJaeyoon Choi 
62*1349a733SJaeyoon Choi 	struct memdesc payload;
63*1349a733SJaeyoon Choi 	enum ufshci_data_direction data_direction;
64*1349a733SJaeyoon Choi 	ufshci_cb_fn_t cb_fn;
65*1349a733SJaeyoon Choi 	void *cb_arg;
66*1349a733SJaeyoon Choi 	bool is_admin;
67*1349a733SJaeyoon Choi 	int32_t retries;
68*1349a733SJaeyoon Choi 	bool payload_valid;
69*1349a733SJaeyoon Choi 	bool timeout;
70*1349a733SJaeyoon Choi 	bool spare[2]; /* Future use */
71*1349a733SJaeyoon Choi 	STAILQ_ENTRY(ufshci_request) stailq;
72*1349a733SJaeyoon Choi };
73*1349a733SJaeyoon Choi 
74*1349a733SJaeyoon Choi enum ufshci_slot_state {
75*1349a733SJaeyoon Choi 	UFSHCI_SLOT_STATE_FREE = 0x0,
76*1349a733SJaeyoon Choi 	UFSHCI_SLOT_STATE_RESERVED = 0x1,
77*1349a733SJaeyoon Choi 	UFSHCI_SLOT_STATE_SCHEDULED = 0x2,
78*1349a733SJaeyoon Choi 	UFSHCI_SLOT_STATE_TIMEOUT = 0x3,
79*1349a733SJaeyoon Choi 	UFSHCI_SLOT_STATE_NEED_ERROR_HANDLING = 0x4,
80*1349a733SJaeyoon Choi };
81*1349a733SJaeyoon Choi 
82*1349a733SJaeyoon Choi struct ufshci_tracker {
83*1349a733SJaeyoon Choi 	struct ufshci_request *req;
84*1349a733SJaeyoon Choi 	struct ufshci_req_queue *req_queue;
85*1349a733SJaeyoon Choi 	struct ufshci_hw_queue *hwq;
86*1349a733SJaeyoon Choi 	uint8_t slot_num;
87*1349a733SJaeyoon Choi 	enum ufshci_slot_state slot_state;
88*1349a733SJaeyoon Choi 	size_t response_size;
89*1349a733SJaeyoon Choi 	sbintime_t deadline;
90*1349a733SJaeyoon Choi 
91*1349a733SJaeyoon Choi 	bus_dmamap_t payload_dma_map;
92*1349a733SJaeyoon Choi 	uint64_t payload_addr;
93*1349a733SJaeyoon Choi 
94*1349a733SJaeyoon Choi 	struct ufshci_utp_cmd_desc *ucd;
95*1349a733SJaeyoon Choi 	bus_addr_t ucd_bus_addr;
96*1349a733SJaeyoon Choi 
97*1349a733SJaeyoon Choi 	uint16_t prdt_off;
98*1349a733SJaeyoon Choi 	uint16_t prdt_entry_cnt;
99*1349a733SJaeyoon Choi };
100*1349a733SJaeyoon Choi 
101*1349a733SJaeyoon Choi enum ufshci_queue_mode {
102*1349a733SJaeyoon Choi 	UFSHCI_Q_MODE_SDB = 0x00, /* Single Doorbell Mode*/
103*1349a733SJaeyoon Choi 	UFSHCI_Q_MODE_MCQ = 0x01, /* Multi-Circular Queue Mode*/
104*1349a733SJaeyoon Choi };
105*1349a733SJaeyoon Choi 
106*1349a733SJaeyoon Choi /*
107*1349a733SJaeyoon Choi  * UFS uses slot-based Single Doorbell (SDB) mode for request submission by
108*1349a733SJaeyoon Choi  * default and additionally supports Multi-Circular Queue (MCQ) in UFS 4.0. To
109*1349a733SJaeyoon Choi  * minimize duplicated code between SDB and MCQ, mode dependent operations are
110*1349a733SJaeyoon Choi  * extracted into ufshci_qops.
111*1349a733SJaeyoon Choi  */
112*1349a733SJaeyoon Choi struct ufshci_qops {
113*1349a733SJaeyoon Choi 	int (*construct)(struct ufshci_controller *ctrlr,
114*1349a733SJaeyoon Choi 	    struct ufshci_req_queue *req_queue, uint32_t num_entries,
115*1349a733SJaeyoon Choi 	    bool is_task_mgmt);
116*1349a733SJaeyoon Choi 	void (*destroy)(struct ufshci_controller *ctrlr,
117*1349a733SJaeyoon Choi 	    struct ufshci_req_queue *req_queue);
118*1349a733SJaeyoon Choi 	struct ufshci_hw_queue *(*get_hw_queue)(
119*1349a733SJaeyoon Choi 	    struct ufshci_req_queue *req_queue);
120*1349a733SJaeyoon Choi 	int (*enable)(struct ufshci_controller *ctrlr,
121*1349a733SJaeyoon Choi 	    struct ufshci_req_queue *req_queue);
122*1349a733SJaeyoon Choi 	int (*reserve_slot)(struct ufshci_req_queue *req_queue,
123*1349a733SJaeyoon Choi 	    struct ufshci_tracker **tr);
124*1349a733SJaeyoon Choi 	int (*reserve_admin_slot)(struct ufshci_req_queue *req_queue,
125*1349a733SJaeyoon Choi 	    struct ufshci_tracker **tr);
126*1349a733SJaeyoon Choi 	void (*ring_doorbell)(struct ufshci_controller *ctrlr,
127*1349a733SJaeyoon Choi 	    struct ufshci_tracker *tr);
128*1349a733SJaeyoon Choi 	void (*clear_cpl_ntf)(struct ufshci_controller *ctrlr,
129*1349a733SJaeyoon Choi 	    struct ufshci_tracker *tr);
130*1349a733SJaeyoon Choi 	bool (*process_cpl)(struct ufshci_req_queue *req_queue);
131*1349a733SJaeyoon Choi 	int (*get_inflight_io)(struct ufshci_controller *ctrlr);
132*1349a733SJaeyoon Choi };
133*1349a733SJaeyoon Choi 
134*1349a733SJaeyoon Choi #define UFSHCI_SDB_Q 0 /* Queue number for a single doorbell queue */
135*1349a733SJaeyoon Choi 
136*1349a733SJaeyoon Choi /*
137*1349a733SJaeyoon Choi  * Generic queue container used by both SDB (fixed 32-slot bitmap) and MCQ
138*1349a733SJaeyoon Choi  * (ring buffer) modes. Fields are shared; some such as sq_head, sq_tail and
139*1349a733SJaeyoon Choi  * cq_head are not used in SDB but used in MCQ.
140*1349a733SJaeyoon Choi  */
141*1349a733SJaeyoon Choi struct ufshci_hw_queue {
142*1349a733SJaeyoon Choi 	uint32_t id;
143*1349a733SJaeyoon Choi 	int domain;
144*1349a733SJaeyoon Choi 	int cpu;
145*1349a733SJaeyoon Choi 
146*1349a733SJaeyoon Choi 	struct ufshci_utp_xfer_req_desc *utrd;
147*1349a733SJaeyoon Choi 
148*1349a733SJaeyoon Choi 	bus_dma_tag_t dma_tag_queue;
149*1349a733SJaeyoon Choi 	bus_dmamap_t queuemem_map;
150*1349a733SJaeyoon Choi 	bus_addr_t req_queue_addr;
151*1349a733SJaeyoon Choi 
152*1349a733SJaeyoon Choi 	uint32_t num_entries;
153*1349a733SJaeyoon Choi 	uint32_t num_trackers;
154*1349a733SJaeyoon Choi 
155*1349a733SJaeyoon Choi 	/*
156*1349a733SJaeyoon Choi 	 * A Request List using the single doorbell method uses a dedicated
157*1349a733SJaeyoon Choi 	 * ufshci_tracker, one per slot.
158*1349a733SJaeyoon Choi 	 */
159*1349a733SJaeyoon Choi 	struct ufshci_tracker **act_tr;
160*1349a733SJaeyoon Choi 
161*1349a733SJaeyoon Choi 	uint32_t sq_head; /* MCQ mode */
162*1349a733SJaeyoon Choi 	uint32_t sq_tail; /* MCQ mode */
163*1349a733SJaeyoon Choi 	uint32_t cq_head; /* MCQ mode */
164*1349a733SJaeyoon Choi 
165*1349a733SJaeyoon Choi 	uint32_t phase;
166*1349a733SJaeyoon Choi 	int64_t num_cmds;
167*1349a733SJaeyoon Choi 	int64_t num_intr_handler_calls;
168*1349a733SJaeyoon Choi 	int64_t num_retries;
169*1349a733SJaeyoon Choi 	int64_t num_failures;
170*1349a733SJaeyoon Choi 
171*1349a733SJaeyoon Choi 	struct mtx_padalign qlock;
172*1349a733SJaeyoon Choi };
173*1349a733SJaeyoon Choi 
174*1349a733SJaeyoon Choi struct ufshci_req_queue {
175*1349a733SJaeyoon Choi 	struct ufshci_controller *ctrlr;
176*1349a733SJaeyoon Choi 	int domain;
177*1349a733SJaeyoon Choi 
178*1349a733SJaeyoon Choi 	/*
179*1349a733SJaeyoon Choi 	 *  queue_mode: active transfer scheme
180*1349a733SJaeyoon Choi 	 *  UFSHCI_Q_MODE_SDB – legacy single‑doorbell list
181*1349a733SJaeyoon Choi 	 *  UFSHCI_Q_MODE_MCQ – modern multi‑circular queue (UFSHCI 4.0+)
182*1349a733SJaeyoon Choi 	 */
183*1349a733SJaeyoon Choi 	enum ufshci_queue_mode queue_mode;
184*1349a733SJaeyoon Choi 
185*1349a733SJaeyoon Choi 	uint8_t num_q;
186*1349a733SJaeyoon Choi 	struct ufshci_hw_queue *hwq;
187*1349a733SJaeyoon Choi 
188*1349a733SJaeyoon Choi 	struct ufshci_qops qops;
189*1349a733SJaeyoon Choi 
190*1349a733SJaeyoon Choi 	bool is_task_mgmt;
191*1349a733SJaeyoon Choi 	uint32_t num_entries;
192*1349a733SJaeyoon Choi 	uint32_t num_trackers;
193*1349a733SJaeyoon Choi 
194*1349a733SJaeyoon Choi 	/* Shared DMA resource */
195*1349a733SJaeyoon Choi 	struct ufshci_utp_cmd_desc *ucd;
196*1349a733SJaeyoon Choi 
197*1349a733SJaeyoon Choi 	bus_dma_tag_t dma_tag_ucd;
198*1349a733SJaeyoon Choi 	bus_dma_tag_t dma_tag_payload;
199*1349a733SJaeyoon Choi 
200*1349a733SJaeyoon Choi 	bus_dmamap_t ucdmem_map;
201*1349a733SJaeyoon Choi 
202*1349a733SJaeyoon Choi 	bus_addr_t ucd_addr;
203*1349a733SJaeyoon Choi };
204*1349a733SJaeyoon Choi 
205*1349a733SJaeyoon Choi struct ufshci_device {
206*1349a733SJaeyoon Choi 	uint32_t max_lun_count;
207*1349a733SJaeyoon Choi 
208*1349a733SJaeyoon Choi 	struct ufshci_device_descriptor dev_desc;
209*1349a733SJaeyoon Choi 	struct ufshci_geometry_descriptor geo_desc;
210*1349a733SJaeyoon Choi 
211*1349a733SJaeyoon Choi 	uint32_t unipro_version;
212*1349a733SJaeyoon Choi };
213*1349a733SJaeyoon Choi 
214*1349a733SJaeyoon Choi /*
215*1349a733SJaeyoon Choi  * One of these per allocated device.
216*1349a733SJaeyoon Choi  */
217*1349a733SJaeyoon Choi struct ufshci_controller {
218*1349a733SJaeyoon Choi 	device_t dev;
219*1349a733SJaeyoon Choi 
220*1349a733SJaeyoon Choi 	uint32_t quirks;
221*1349a733SJaeyoon Choi #define UFSHCI_QUIRK_IGNORE_UIC_POWER_MODE \
222*1349a733SJaeyoon Choi 	1 /* QEMU does not support UIC POWER MODE */
223*1349a733SJaeyoon Choi #define UFSHCI_QUIRK_LONG_PEER_PA_TACTIVATE \
224*1349a733SJaeyoon Choi 	2 /* Need an additional 200 ms of PA_TActivate */
225*1349a733SJaeyoon Choi #define UFSHCI_QUIRK_WAIT_AFTER_POWER_MODE_CHANGE \
226*1349a733SJaeyoon Choi 	4 /* Need to wait 1250us after power mode change */
227*1349a733SJaeyoon Choi 
228*1349a733SJaeyoon Choi 	uint32_t ref_clk;
229*1349a733SJaeyoon Choi 
230*1349a733SJaeyoon Choi 	struct cam_sim *ufshci_sim;
231*1349a733SJaeyoon Choi 	struct cam_path *ufshci_path;
232*1349a733SJaeyoon Choi 
233*1349a733SJaeyoon Choi 	struct mtx sc_mtx;
234*1349a733SJaeyoon Choi 	uint32_t sc_unit;
235*1349a733SJaeyoon Choi 	uint8_t sc_name[16];
236*1349a733SJaeyoon Choi 
237*1349a733SJaeyoon Choi 	struct ufshci_device ufs_dev;
238*1349a733SJaeyoon Choi 
239*1349a733SJaeyoon Choi 	bus_space_tag_t bus_tag;
240*1349a733SJaeyoon Choi 	bus_space_handle_t bus_handle;
241*1349a733SJaeyoon Choi 	int resource_id;
242*1349a733SJaeyoon Choi 	struct resource *resource;
243*1349a733SJaeyoon Choi 
244*1349a733SJaeyoon Choi 	/* Currently, there is no UFSHCI that supports MSI, MSI-X.  */
245*1349a733SJaeyoon Choi 	int msi_count;
246*1349a733SJaeyoon Choi 
247*1349a733SJaeyoon Choi 	/* Fields for tracking progress during controller initialization. */
248*1349a733SJaeyoon Choi 	struct intr_config_hook config_hook;
249*1349a733SJaeyoon Choi 
250*1349a733SJaeyoon Choi 	/* For shared legacy interrupt. */
251*1349a733SJaeyoon Choi 	int rid;
252*1349a733SJaeyoon Choi 	struct resource *res;
253*1349a733SJaeyoon Choi 	void *tag;
254*1349a733SJaeyoon Choi 
255*1349a733SJaeyoon Choi 	uint32_t major_version;
256*1349a733SJaeyoon Choi 	uint32_t minor_version;
257*1349a733SJaeyoon Choi 
258*1349a733SJaeyoon Choi 	uint32_t num_io_queues;
259*1349a733SJaeyoon Choi 	uint32_t max_hw_pend_io;
260*1349a733SJaeyoon Choi 
261*1349a733SJaeyoon Choi 	/* Maximum logical unit number */
262*1349a733SJaeyoon Choi 	uint32_t max_lun_count;
263*1349a733SJaeyoon Choi 
264*1349a733SJaeyoon Choi 	/* Maximum i/o size in bytes */
265*1349a733SJaeyoon Choi 	uint32_t max_xfer_size;
266*1349a733SJaeyoon Choi 
267*1349a733SJaeyoon Choi 	/* Controller capacity */
268*1349a733SJaeyoon Choi 	uint32_t cap;
269*1349a733SJaeyoon Choi 
270*1349a733SJaeyoon Choi 	/* Page size and log2(page_size) - 12 that we're currently using */
271*1349a733SJaeyoon Choi 	uint32_t page_size;
272*1349a733SJaeyoon Choi 
273*1349a733SJaeyoon Choi 	/* Timeout value on device initialization */
274*1349a733SJaeyoon Choi 	uint32_t device_init_timeout_in_ms;
275*1349a733SJaeyoon Choi 
276*1349a733SJaeyoon Choi 	/* Timeout value on UIC command */
277*1349a733SJaeyoon Choi 	uint32_t uic_cmd_timeout_in_ms;
278*1349a733SJaeyoon Choi 
279*1349a733SJaeyoon Choi 	/* UTMR/UTR queue timeout period in seconds */
280*1349a733SJaeyoon Choi 	uint32_t timeout_period;
281*1349a733SJaeyoon Choi 
282*1349a733SJaeyoon Choi 	/* UTMR/UTR queue retry count */
283*1349a733SJaeyoon Choi 	uint32_t retry_count;
284*1349a733SJaeyoon Choi 
285*1349a733SJaeyoon Choi 	/* UFS Host Controller Interface Registers */
286*1349a733SJaeyoon Choi 	struct ufshci_registers *regs;
287*1349a733SJaeyoon Choi 
288*1349a733SJaeyoon Choi 	/* UFS Transport Protocol Layer (UTP) */
289*1349a733SJaeyoon Choi 	struct ufshci_req_queue task_mgmt_req_queue;
290*1349a733SJaeyoon Choi 	struct ufshci_req_queue transfer_req_queue;
291*1349a733SJaeyoon Choi 	bool is_single_db_supported; /* 0 = supported */
292*1349a733SJaeyoon Choi 	bool is_mcq_supported;	     /* 1 = supported */
293*1349a733SJaeyoon Choi 
294*1349a733SJaeyoon Choi 	/* UFS Interconnect Layer (UIC) */
295*1349a733SJaeyoon Choi 	struct mtx uic_cmd_lock;
296*1349a733SJaeyoon Choi 	uint32_t unipro_version;
297*1349a733SJaeyoon Choi 	uint8_t hs_gear;
298*1349a733SJaeyoon Choi 	uint32_t tx_lanes;
299*1349a733SJaeyoon Choi 	uint32_t rx_lanes;
300*1349a733SJaeyoon Choi 	uint32_t max_rx_hs_gear;
301*1349a733SJaeyoon Choi 	uint32_t max_tx_lanes;
302*1349a733SJaeyoon Choi 	uint32_t max_rx_lanes;
303*1349a733SJaeyoon Choi 
304*1349a733SJaeyoon Choi 	bool is_failed;
305*1349a733SJaeyoon Choi };
306*1349a733SJaeyoon Choi 
307*1349a733SJaeyoon Choi #define ufshci_mmio_offsetof(reg) offsetof(struct ufshci_registers, reg)
308*1349a733SJaeyoon Choi 
309*1349a733SJaeyoon Choi #define ufshci_mmio_read_4(sc, reg)                       \
310*1349a733SJaeyoon Choi 	bus_space_read_4((sc)->bus_tag, (sc)->bus_handle, \
311*1349a733SJaeyoon Choi 	    ufshci_mmio_offsetof(reg))
312*1349a733SJaeyoon Choi 
313*1349a733SJaeyoon Choi #define ufshci_mmio_write_4(sc, reg, val)                  \
314*1349a733SJaeyoon Choi 	bus_space_write_4((sc)->bus_tag, (sc)->bus_handle, \
315*1349a733SJaeyoon Choi 	    ufshci_mmio_offsetof(reg), val)
316*1349a733SJaeyoon Choi 
317*1349a733SJaeyoon Choi #define ufshci_printf(ctrlr, fmt, args...) \
318*1349a733SJaeyoon Choi 	device_printf(ctrlr->dev, fmt, ##args)
319*1349a733SJaeyoon Choi 
320*1349a733SJaeyoon Choi /* UFSHCI */
321*1349a733SJaeyoon Choi void ufshci_completion_poll_cb(void *arg, const struct ufshci_completion *cpl,
322*1349a733SJaeyoon Choi     bool error);
323*1349a733SJaeyoon Choi 
324*1349a733SJaeyoon Choi /* SIM */
325*1349a733SJaeyoon Choi int ufshci_sim_attach(struct ufshci_controller *ctrlr);
326*1349a733SJaeyoon Choi void ufshci_sim_detach(struct ufshci_controller *ctrlr);
327*1349a733SJaeyoon Choi 
328*1349a733SJaeyoon Choi /* Controller */
329*1349a733SJaeyoon Choi int ufshci_ctrlr_construct(struct ufshci_controller *ctrlr, device_t dev);
330*1349a733SJaeyoon Choi void ufshci_ctrlr_destruct(struct ufshci_controller *ctrlr, device_t dev);
331*1349a733SJaeyoon Choi int ufshci_ctrlr_reset(struct ufshci_controller *ctrlr);
332*1349a733SJaeyoon Choi /* ctrlr defined as void * to allow use with config_intrhook. */
333*1349a733SJaeyoon Choi void ufshci_ctrlr_start_config_hook(void *arg);
334*1349a733SJaeyoon Choi void ufshci_ctrlr_poll(struct ufshci_controller *ctrlr);
335*1349a733SJaeyoon Choi 
336*1349a733SJaeyoon Choi int ufshci_ctrlr_submit_admin_request(struct ufshci_controller *ctrlr,
337*1349a733SJaeyoon Choi     struct ufshci_request *req);
338*1349a733SJaeyoon Choi int ufshci_ctrlr_submit_io_request(struct ufshci_controller *ctrlr,
339*1349a733SJaeyoon Choi     struct ufshci_request *req);
340*1349a733SJaeyoon Choi int ufshci_ctrlr_send_nop(struct ufshci_controller *ctrlr);
341*1349a733SJaeyoon Choi 
342*1349a733SJaeyoon Choi void ufshci_reg_dump(struct ufshci_controller *ctrlr);
343*1349a733SJaeyoon Choi 
344*1349a733SJaeyoon Choi /* Device */
345*1349a733SJaeyoon Choi int ufshci_dev_init(struct ufshci_controller *ctrlr);
346*1349a733SJaeyoon Choi int ufshci_dev_reset(struct ufshci_controller *ctrlr);
347*1349a733SJaeyoon Choi int ufshci_dev_init_reference_clock(struct ufshci_controller *ctrlr);
348*1349a733SJaeyoon Choi int ufshci_dev_init_unipro(struct ufshci_controller *ctrlr);
349*1349a733SJaeyoon Choi int ufshci_dev_init_uic_power_mode(struct ufshci_controller *ctrlr);
350*1349a733SJaeyoon Choi int ufshci_dev_init_ufs_power_mode(struct ufshci_controller *ctrlr);
351*1349a733SJaeyoon Choi int ufshci_dev_get_descriptor(struct ufshci_controller *ctrlr);
352*1349a733SJaeyoon Choi 
353*1349a733SJaeyoon Choi /* Controller Command */
354*1349a733SJaeyoon Choi void ufshci_ctrlr_cmd_send_nop(struct ufshci_controller *ctrlr,
355*1349a733SJaeyoon Choi     ufshci_cb_fn_t cb_fn, void *cb_arg);
356*1349a733SJaeyoon Choi void ufshci_ctrlr_cmd_send_query_request(struct ufshci_controller *ctrlr,
357*1349a733SJaeyoon Choi     ufshci_cb_fn_t cb_fn, void *cb_arg, struct ufshci_query_param param);
358*1349a733SJaeyoon Choi void ufshci_ctrlr_cmd_send_scsi_command(struct ufshci_controller *ctrlr,
359*1349a733SJaeyoon Choi     ufshci_cb_fn_t cb_fn, void *cb_arg, uint8_t *cmd_ptr, uint8_t cmd_len,
360*1349a733SJaeyoon Choi     uint32_t data_len, uint8_t lun, bool is_write);
361*1349a733SJaeyoon Choi 
362*1349a733SJaeyoon Choi /* Request Queue */
363*1349a733SJaeyoon Choi bool ufshci_req_queue_process_completions(struct ufshci_req_queue *req_queue);
364*1349a733SJaeyoon Choi int ufshci_utm_req_queue_construct(struct ufshci_controller *ctrlr);
365*1349a733SJaeyoon Choi int ufshci_ut_req_queue_construct(struct ufshci_controller *ctrlr);
366*1349a733SJaeyoon Choi void ufshci_utm_req_queue_destroy(struct ufshci_controller *ctrlr);
367*1349a733SJaeyoon Choi void ufshci_ut_req_queue_destroy(struct ufshci_controller *ctrlr);
368*1349a733SJaeyoon Choi int ufshci_utm_req_queue_enable(struct ufshci_controller *ctrlr);
369*1349a733SJaeyoon Choi int ufshci_ut_req_queue_enable(struct ufshci_controller *ctrlr);
370*1349a733SJaeyoon Choi void ufshci_req_queue_fail(struct ufshci_controller *ctrlr,
371*1349a733SJaeyoon Choi     struct ufshci_hw_queue *hwq);
372*1349a733SJaeyoon Choi int ufshci_req_queue_submit_request(struct ufshci_req_queue *req_queue,
373*1349a733SJaeyoon Choi     struct ufshci_request *req, bool is_admin);
374*1349a733SJaeyoon Choi void ufshci_req_queue_complete_tracker(struct ufshci_tracker *tr);
375*1349a733SJaeyoon Choi 
376*1349a733SJaeyoon Choi /* Request Single Doorbell Queue */
377*1349a733SJaeyoon Choi int ufshci_req_sdb_construct(struct ufshci_controller *ctrlr,
378*1349a733SJaeyoon Choi     struct ufshci_req_queue *req_queue, uint32_t num_entries,
379*1349a733SJaeyoon Choi     bool is_task_mgmt);
380*1349a733SJaeyoon Choi void ufshci_req_sdb_destroy(struct ufshci_controller *ctrlr,
381*1349a733SJaeyoon Choi     struct ufshci_req_queue *req_queue);
382*1349a733SJaeyoon Choi struct ufshci_hw_queue *ufshci_req_sdb_get_hw_queue(
383*1349a733SJaeyoon Choi     struct ufshci_req_queue *req_queue);
384*1349a733SJaeyoon Choi int ufshci_req_sdb_enable(struct ufshci_controller *ctrlr,
385*1349a733SJaeyoon Choi     struct ufshci_req_queue *req_queue);
386*1349a733SJaeyoon Choi int ufshci_req_sdb_reserve_slot(struct ufshci_req_queue *req_queue,
387*1349a733SJaeyoon Choi     struct ufshci_tracker **tr);
388*1349a733SJaeyoon Choi void ufshci_req_sdb_ring_doorbell(struct ufshci_controller *ctrlr,
389*1349a733SJaeyoon Choi     struct ufshci_tracker *tr);
390*1349a733SJaeyoon Choi void ufshci_req_sdb_clear_cpl_ntf(struct ufshci_controller *ctrlr,
391*1349a733SJaeyoon Choi     struct ufshci_tracker *tr);
392*1349a733SJaeyoon Choi bool ufshci_req_sdb_process_cpl(struct ufshci_req_queue *req_queue);
393*1349a733SJaeyoon Choi int ufshci_req_sdb_get_inflight_io(struct ufshci_controller *ctrlr);
394*1349a733SJaeyoon Choi 
395*1349a733SJaeyoon Choi /* UIC Command */
396*1349a733SJaeyoon Choi int ufshci_uic_power_mode_ready(struct ufshci_controller *ctrlr);
397*1349a733SJaeyoon Choi int ufshci_uic_cmd_ready(struct ufshci_controller *ctrlr);
398*1349a733SJaeyoon Choi int ufshci_uic_send_dme_link_startup(struct ufshci_controller *ctrlr);
399*1349a733SJaeyoon Choi int ufshci_uic_send_dme_get(struct ufshci_controller *ctrlr, uint16_t attribute,
400*1349a733SJaeyoon Choi     uint32_t *return_value);
401*1349a733SJaeyoon Choi int ufshci_uic_send_dme_set(struct ufshci_controller *ctrlr, uint16_t attribute,
402*1349a733SJaeyoon Choi     uint32_t value);
403*1349a733SJaeyoon Choi int ufshci_uic_send_dme_peer_get(struct ufshci_controller *ctrlr,
404*1349a733SJaeyoon Choi     uint16_t attribute, uint32_t *return_value);
405*1349a733SJaeyoon Choi int ufshci_uic_send_dme_peer_set(struct ufshci_controller *ctrlr,
406*1349a733SJaeyoon Choi     uint16_t attribute, uint32_t value);
407*1349a733SJaeyoon Choi int ufshci_uic_send_dme_endpoint_reset(struct ufshci_controller *ctrlr);
408*1349a733SJaeyoon Choi 
409*1349a733SJaeyoon Choi /* SYSCTL */
410*1349a733SJaeyoon Choi void ufshci_sysctl_initialize_ctrlr(struct ufshci_controller *ctrlr);
411*1349a733SJaeyoon Choi 
412*1349a733SJaeyoon Choi int ufshci_attach(device_t dev);
413*1349a733SJaeyoon Choi int ufshci_detach(device_t dev);
414*1349a733SJaeyoon Choi 
415*1349a733SJaeyoon Choi /*
416*1349a733SJaeyoon Choi  * Wait for a command to complete using the ufshci_completion_poll_cb. Used in
417*1349a733SJaeyoon Choi  * limited contexts where the caller knows it's OK to block briefly while the
418*1349a733SJaeyoon Choi  * command runs. The ISR will run the callback which will set status->done to
419*1349a733SJaeyoon Choi  * true, usually within microseconds. If not, then after one second timeout
420*1349a733SJaeyoon Choi  * handler should reset the controller and abort all outstanding requests
421*1349a733SJaeyoon Choi  * including this polled one. If still not after ten seconds, then something is
422*1349a733SJaeyoon Choi  * wrong with the driver, and panic is the only way to recover.
423*1349a733SJaeyoon Choi  *
424*1349a733SJaeyoon Choi  * Most commands using this interface aren't actual I/O to the drive's media so
425*1349a733SJaeyoon Choi  * complete within a few microseconds. Adaptively spin for one tick to catch the
426*1349a733SJaeyoon Choi  * vast majority of these without waiting for a tick plus scheduling delays.
427*1349a733SJaeyoon Choi  * Since these are on startup, this drastically reduces startup time.
428*1349a733SJaeyoon Choi  */
429*1349a733SJaeyoon Choi static __inline void
ufshci_completion_poll(struct ufshci_completion_poll_status * status)430*1349a733SJaeyoon Choi ufshci_completion_poll(struct ufshci_completion_poll_status *status)
431*1349a733SJaeyoon Choi {
432*1349a733SJaeyoon Choi 	int timeout = ticks + 10 * hz;
433*1349a733SJaeyoon Choi 	sbintime_t delta_t = SBT_1US;
434*1349a733SJaeyoon Choi 
435*1349a733SJaeyoon Choi 	while (!atomic_load_acq_int(&status->done)) {
436*1349a733SJaeyoon Choi 		if (timeout - ticks < 0)
437*1349a733SJaeyoon Choi 			panic(
438*1349a733SJaeyoon Choi 			    "UFSHCI polled command failed to complete within 10s.");
439*1349a733SJaeyoon Choi 		pause_sbt("ufshci_cpl", delta_t, 0, C_PREL(1));
440*1349a733SJaeyoon Choi 		delta_t = min(SBT_1MS, delta_t * 3 / 2);
441*1349a733SJaeyoon Choi 	}
442*1349a733SJaeyoon Choi }
443*1349a733SJaeyoon Choi 
444*1349a733SJaeyoon Choi static __inline void
ufshci_single_map(void * arg,bus_dma_segment_t * seg,int nseg,int error)445*1349a733SJaeyoon Choi ufshci_single_map(void *arg, bus_dma_segment_t *seg, int nseg, int error)
446*1349a733SJaeyoon Choi {
447*1349a733SJaeyoon Choi 	uint64_t *bus_addr = (uint64_t *)arg;
448*1349a733SJaeyoon Choi 
449*1349a733SJaeyoon Choi 	KASSERT(nseg == 1, ("number of segments (%d) is not 1", nseg));
450*1349a733SJaeyoon Choi 	if (error != 0)
451*1349a733SJaeyoon Choi 		printf("ufshci_single_map err %d\n", error);
452*1349a733SJaeyoon Choi 	*bus_addr = seg[0].ds_addr;
453*1349a733SJaeyoon Choi }
454*1349a733SJaeyoon Choi 
455*1349a733SJaeyoon Choi static __inline struct ufshci_request *
_ufshci_allocate_request(const int how,ufshci_cb_fn_t cb_fn,void * cb_arg)456*1349a733SJaeyoon Choi _ufshci_allocate_request(const int how, ufshci_cb_fn_t cb_fn, void *cb_arg)
457*1349a733SJaeyoon Choi {
458*1349a733SJaeyoon Choi 	struct ufshci_request *req;
459*1349a733SJaeyoon Choi 
460*1349a733SJaeyoon Choi 	KASSERT(how == M_WAITOK || how == M_NOWAIT,
461*1349a733SJaeyoon Choi 	    ("nvme_allocate_request: invalid how %d", how));
462*1349a733SJaeyoon Choi 
463*1349a733SJaeyoon Choi 	req = malloc(sizeof(*req), M_UFSHCI, how | M_ZERO);
464*1349a733SJaeyoon Choi 	if (req != NULL) {
465*1349a733SJaeyoon Choi 		req->cb_fn = cb_fn;
466*1349a733SJaeyoon Choi 		req->cb_arg = cb_arg;
467*1349a733SJaeyoon Choi 		req->timeout = true;
468*1349a733SJaeyoon Choi 	}
469*1349a733SJaeyoon Choi 	return (req);
470*1349a733SJaeyoon Choi }
471*1349a733SJaeyoon Choi 
472*1349a733SJaeyoon Choi static __inline struct ufshci_request *
ufshci_allocate_request_vaddr(void * payload,uint32_t payload_size,const int how,ufshci_cb_fn_t cb_fn,void * cb_arg)473*1349a733SJaeyoon Choi ufshci_allocate_request_vaddr(void *payload, uint32_t payload_size,
474*1349a733SJaeyoon Choi     const int how, ufshci_cb_fn_t cb_fn, void *cb_arg)
475*1349a733SJaeyoon Choi {
476*1349a733SJaeyoon Choi 	struct ufshci_request *req;
477*1349a733SJaeyoon Choi 
478*1349a733SJaeyoon Choi 	req = _ufshci_allocate_request(how, cb_fn, cb_arg);
479*1349a733SJaeyoon Choi 	if (req != NULL) {
480*1349a733SJaeyoon Choi 		if (payload_size) {
481*1349a733SJaeyoon Choi 			req->payload = memdesc_vaddr(payload, payload_size);
482*1349a733SJaeyoon Choi 			req->payload_valid = true;
483*1349a733SJaeyoon Choi 		}
484*1349a733SJaeyoon Choi 	}
485*1349a733SJaeyoon Choi 	return (req);
486*1349a733SJaeyoon Choi }
487*1349a733SJaeyoon Choi 
488*1349a733SJaeyoon Choi static __inline struct ufshci_request *
ufshci_allocate_request_bio(struct bio * bio,const int how,ufshci_cb_fn_t cb_fn,void * cb_arg)489*1349a733SJaeyoon Choi ufshci_allocate_request_bio(struct bio *bio, const int how,
490*1349a733SJaeyoon Choi     ufshci_cb_fn_t cb_fn, void *cb_arg)
491*1349a733SJaeyoon Choi {
492*1349a733SJaeyoon Choi 	struct ufshci_request *req;
493*1349a733SJaeyoon Choi 
494*1349a733SJaeyoon Choi 	req = _ufshci_allocate_request(how, cb_fn, cb_arg);
495*1349a733SJaeyoon Choi 	if (req != NULL) {
496*1349a733SJaeyoon Choi 		req->payload = memdesc_bio(bio);
497*1349a733SJaeyoon Choi 		req->payload_valid = true;
498*1349a733SJaeyoon Choi 	}
499*1349a733SJaeyoon Choi 	return (req);
500*1349a733SJaeyoon Choi }
501*1349a733SJaeyoon Choi 
502*1349a733SJaeyoon Choi #define ufshci_free_request(req) free(req, M_UFSHCI)
503*1349a733SJaeyoon Choi 
504*1349a733SJaeyoon Choi void ufshci_ctrlr_shared_handler(void *arg);
505*1349a733SJaeyoon Choi 
506*1349a733SJaeyoon Choi #endif /* __UFSHCI_PRIVATE_H__ */
507