xref: /netbsd-src/sys/dev/usb/ehcivar.h (revision ccd9df534e375a4366c5b55f23782053c7a98d82)
1 /*	$NetBSD: ehcivar.h,v 1.52 2024/01/20 00:51:29 jmcneill Exp $ */
2 
3 /*
4  * Copyright (c) 2001 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Lennart Augustsson (lennart@augustsson.net).
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #ifndef _EHCIVAR_H_
33 #define _EHCIVAR_H_
34 
35 #include <sys/pool.h>
36 
37 typedef struct ehci_soft_qtd {
38 	ehci_qtd_t qtd;
39 	struct ehci_soft_qtd *nextqtd;	/* mirrors nextqtd in TD */
40 	ehci_physaddr_t physaddr;	/* qTD's physical address */
41 	usb_dma_t dma;			/* qTD's DMA infos */
42 	int offs;			/* qTD's offset in usb_dma_t */
43 	struct usbd_xfer *xfer;		/* xfer back pointer */
44 	uint16_t len;
45 } ehci_soft_qtd_t;
46 #define EHCI_SQTD_ALIGN	MAX(EHCI_QTD_ALIGN, CACHE_LINE_SIZE)
47 #define EHCI_SQTD_SIZE (roundup(sizeof(struct ehci_soft_qtd), EHCI_SQTD_ALIGN))
48 #define EHCI_SQTD_CHUNK (EHCI_PAGE_SIZE / EHCI_SQTD_SIZE)
49 
50 typedef struct ehci_soft_qh {
51 	ehci_qh_t qh;
52 	struct ehci_soft_qh *next;
53 	struct ehci_soft_qtd *sqtd;
54 	ehci_physaddr_t physaddr;
55 	usb_dma_t dma;			/* QH's DMA infos */
56 	int offs;			/* QH's offset in usb_dma_t */
57 	int islot;
58 } ehci_soft_qh_t;
59 #define EHCI_SQH_SIZE (roundup(sizeof(struct ehci_soft_qh), EHCI_QH_ALIGN))
60 #define EHCI_SQH_CHUNK (EHCI_PAGE_SIZE / EHCI_SQH_SIZE)
61 
62 typedef struct ehci_soft_itd {
63 	union {
64 		ehci_itd_t itd;
65 		ehci_sitd_t sitd;
66 	};
67 	union {
68 		struct {
69 			/* soft_itds links in a periodic frame */
70 			struct ehci_soft_itd *next;
71 			struct ehci_soft_itd *prev;
72 		} frame_list;
73 		/* circular list of free itds */
74 		LIST_ENTRY(ehci_soft_itd) free_list;
75 	};
76 	struct ehci_soft_itd *xfer_next; /* Next soft_itd in xfer */
77 	ehci_physaddr_t physaddr;
78 	usb_dma_t dma;
79 	int offs;
80 	int slot;
81 	struct timeval t; /* store free time */
82 } ehci_soft_itd_t;
83 #define EHCI_ITD_SIZE (roundup(sizeof(struct ehci_soft_itd), EHCI_ITD_ALIGN))
84 #define EHCI_ITD_CHUNK (EHCI_PAGE_SIZE / EHCI_ITD_SIZE)
85 
86 #define ehci_soft_sitd_t ehci_soft_itd_t
87 #define ehci_soft_sitd ehci_soft_itd
88 #define sc_softsitds sc_softitds
89 #define EHCI_SITD_SIZE (roundup(sizeof(struct ehci_soft_sitd), EHCI_SITD_ALIGN))
90 #define EHCI_SITD_CHUNK (EHCI_PAGE_SIZE / EHCI_SITD_SIZE)
91 
92 struct ehci_xfer {
93 	struct usbd_xfer ex_xfer;
94 	TAILQ_ENTRY(ehci_xfer) ex_next; /* list of active xfers */
95 	enum {
96 		EX_NONE,
97 		EX_CTRL,
98 		EX_BULK,
99 		EX_INTR,
100 		EX_ISOC,
101 		EX_FS_ISOC
102 	} ex_type;
103 	/* ctrl/bulk/intr */
104 	struct {
105 		ehci_soft_qtd_t **ex_sqtds;
106 		size_t ex_nsqtd;
107 	};
108 	union {
109 		/* ctrl */
110 		struct {
111 			ehci_soft_qtd_t *ex_setup;
112 			ehci_soft_qtd_t *ex_data;
113 			ehci_soft_qtd_t *ex_status;
114 		};
115 		/* bulk/intr */
116 		struct {
117 			ehci_soft_qtd_t *ex_sqtdstart;
118 			ehci_soft_qtd_t *ex_sqtdend;
119 		};
120 		/* isoc */
121 		struct {
122 			ehci_soft_itd_t *ex_itdstart;
123 			ehci_soft_itd_t *ex_itdend;
124 		};
125 		/* split (aka fs) isoc */
126 		struct {
127 			ehci_soft_sitd_t *ex_sitdstart;
128 			ehci_soft_sitd_t *ex_sitdend;
129 		};
130 	};
131 	bool ex_isdone;	/* used only when DIAGNOSTIC is defined */
132 };
133 
134 #define EHCI_BUS2SC(bus)	((bus)->ub_hcpriv)
135 #define EHCI_PIPE2SC(pipe)	EHCI_BUS2SC((pipe)->up_dev->ud_bus)
136 #define EHCI_XFER2SC(xfer)	EHCI_BUS2SC((xfer)->ux_bus)
137 #define EHCI_EPIPE2SC(epipe)	EHCI_BUS2SC((epipe)->pipe.up_dev->ud_bus)
138 
139 #define EHCI_XFER2EXFER(xfer)	((struct ehci_xfer *)(xfer))
140 
141 #define EHCI_XFER2EPIPE(xfer)	((struct ehci_pipe *)((xfer)->ux_pipe))
142 #define EHCI_PIPE2EPIPE(pipe)	((struct ehci_pipe *)(pipe))
143 
144 /* Information about an entry in the interrupt list. */
145 struct ehci_soft_islot {
146 	ehci_soft_qh_t *sqh;	/* Queue Head. */
147 };
148 
149 #define EHCI_FRAMELIST_MAXCOUNT	1024
150 #define EHCI_IPOLLRATES		8 /* Poll rates (1ms, 2, 4, 8 .. 128) */
151 #define EHCI_INTRQHS		((1 << EHCI_IPOLLRATES) - 1)
152 #define EHCI_MAX_POLLRATE	(1 << (EHCI_IPOLLRATES - 1))
153 #define EHCI_IQHIDX(lev, pos) \
154 	((((pos) & ((1 << (lev)) - 1)) | (1 << (lev))) - 1)
155 #define EHCI_ILEV_IVAL(lev)	(1 << (lev))
156 
157 
158 #define EHCI_HASH_SIZE 128
159 #define EHCI_COMPANION_MAX 8
160 
161 #define EHCI_FREE_LIST_INTERVAL 100
162 
163 typedef struct ehci_softc {
164 	device_t sc_dev;
165 	kmutex_t sc_rhlock;
166 	kmutex_t sc_lock;
167 	kmutex_t sc_intr_lock;
168 	kcondvar_t sc_doorbell;
169 	void *sc_doorbell_si;
170 	struct lwp *sc_doorbelllwp;
171 	void *sc_pcd_si;
172 	struct usbd_bus sc_bus;
173 	bus_space_tag_t iot;
174 	bus_space_handle_t ioh;
175 	bus_size_t sc_size;
176 	bus_dma_tag_t sc_dmatag;	/* for control data structures */
177 	u_int sc_offs;			/* offset to operational regs */
178 	int sc_flags;			/* misc flags */
179 #define EHCIF_DROPPED_INTR_WORKAROUND	0x01
180 #define EHCIF_ETTF			0x02 /* Emb. Transaction Translater func. */
181 #define EHCIF_32BIT_ACCESS		0x04 /* 32-bit MMIO access req'd */
182 
183 	uint32_t sc_cmd;		/* shadow of cmd reg during suspend */
184 
185 	u_int sc_ncomp;
186 	u_int sc_npcomp;
187 	device_t sc_comps[EHCI_COMPANION_MAX];
188 
189 	/* This chunk to handle early RB_ASKNAME hand over. */
190 	callout_t sc_compcallout;
191 	kmutex_t sc_complock;
192 	kcondvar_t sc_compcv;
193 	enum {
194 		CO_EARLY,
195 		CO_SCHED,
196 		CO_DONE,
197 	} sc_comp_state;
198 
199 	usb_dma_t sc_fldma;
200 	ehci_link_t *sc_flist;
201 	u_int sc_flsize;
202 	u_int sc_rand;			/* XXX need proper intr scheduling */
203 
204 	struct ehci_soft_islot sc_islots[EHCI_INTRQHS];
205 
206 	/*
207 	 * an array matching sc_flist, but with software pointers,
208 	 * not hardware address pointers
209 	 */
210 	struct ehci_soft_itd **sc_softitds;
211 
212 	TAILQ_HEAD(, ehci_xfer) sc_intrhead;
213 
214 	ehci_soft_qh_t *sc_freeqhs;
215 	ehci_soft_qtd_t *sc_freeqtds;
216 	LIST_HEAD(sc_freeitds, ehci_soft_itd) sc_freeitds;
217 	LIST_HEAD(sc_freesitds, ehci_soft_sitd) sc_freesitds;
218 
219 	int sc_noport;
220 	uint8_t sc_hasppc;		/* has Port Power Control */
221 	uint8_t sc_istthreshold;	/* ISOC Scheduling Threshold (uframes) */
222 	struct usbd_xfer *sc_intrxfer;
223 	char sc_isreset[EHCI_MAX_PORTS];
224 
225 	uint32_t sc_eintrs;
226 	ehci_soft_qh_t *sc_async_head;
227 
228 	pool_cache_t sc_xferpool;	/* free xfer pool */
229 
230 	struct callout sc_tmo_intrlist;
231 
232 	device_t sc_child; /* /dev/usb# device */
233 	char sc_dying;
234 
235 	void (*sc_vendor_init)(struct ehci_softc *);
236 	int (*sc_vendor_port_status)(struct ehci_softc *, uint32_t, int);
237 } ehci_softc_t;
238 
239 static inline uint8_t
240 ehci_read_1(struct ehci_softc *sc, u_int offset)
241 {
242 	if (ISSET(sc->sc_flags, EHCIF_32BIT_ACCESS)) {
243 		uint32_t val;
244 
245 		val = bus_space_read_4(sc->iot, sc->ioh, offset & ~3);
246 		return (val >> ((offset & 3) * NBBY)) & 0xff;
247 	} else {
248 		return bus_space_read_1(sc->iot, sc->ioh, offset);
249 	}
250 }
251 
252 static inline uint16_t
253 ehci_read_2(struct ehci_softc *sc, u_int offset)
254 {
255 	if (ISSET(sc->sc_flags, EHCIF_32BIT_ACCESS)) {
256 		uint32_t val;
257 
258 		val = bus_space_read_4(sc->iot, sc->ioh, offset & ~3);
259 		return (val >> ((offset & 3) * NBBY)) & 0xffff;
260 	} else {
261 		return bus_space_read_2(sc->iot, sc->ioh, offset);
262 	}
263 }
264 
265 static inline void
266 ehci_write_1(struct ehci_softc *sc, u_int offset, uint8_t data)
267 {
268 	if (ISSET(sc->sc_flags, EHCIF_32BIT_ACCESS)) {
269 		const uint32_t mask = 0xffU << ((offset & 3) * NBBY);
270 		uint32_t val;
271 
272 		val = bus_space_read_4(sc->iot, sc->ioh, offset & ~3);
273 		val &= ~mask;
274 		val |= __SHIFTIN(data, mask);
275 		bus_space_write_4(sc->iot, sc->ioh, offset & ~3, val);
276 	} else {
277 		bus_space_write_1(sc->iot, sc->ioh, offset, data);
278 	}
279 }
280 
281 static inline void
282 ehci_write_2(struct ehci_softc *sc, u_int offset, uint16_t data)
283 {
284 	if (ISSET(sc->sc_flags, EHCIF_32BIT_ACCESS)) {
285 		const uint32_t mask = 0xffffU << ((offset & 3) * NBBY);
286 		uint32_t val;
287 
288 		val = bus_space_read_4(sc->iot, sc->ioh, offset & ~3);
289 		val &= ~mask;
290 		val |= __SHIFTIN(data, mask);
291 		bus_space_write_4(sc->iot, sc->ioh, offset & ~3, val);
292 	} else {
293 		bus_space_write_2(sc->iot, sc->ioh, offset, data);
294 	}
295 }
296 
297 #define EREAD1(sc, a) ehci_read_1((sc), (a))
298 #define EREAD2(sc, a) ehci_read_2((sc), (a))
299 #define EREAD4(sc, a) bus_space_read_4((sc)->iot, (sc)->ioh, (a))
300 #define EWRITE1(sc, a, x) ehci_write_1((sc), (a), (x))
301 #define EWRITE2(sc, a, x) ehci_write_2((sc), (a), (x))
302 #define EWRITE4(sc, a, x) bus_space_write_4((sc)->iot, (sc)->ioh, (a), (x))
303 #define EOREAD1(sc, a) ehci_read_1((sc), (sc)->sc_offs+(a))
304 #define EOREAD2(sc, a) ehci_read_2((sc), (sc)->sc_offs+(a))
305 #define EOREAD4(sc, a) bus_space_read_4((sc)->iot, (sc)->ioh, (sc)->sc_offs+(a))
306 #define EOWRITE1(sc, a, x) ehci_write_1((sc), (sc)->sc_offs+(a), (x))
307 #define EOWRITE2(sc, a, x) ehci_write_2((sc), (sc)->sc_offs+(a), (x))
308 #define EOWRITE4(sc, a, x) bus_space_write_4((sc)->iot, (sc)->ioh, (sc)->sc_offs+(a), (x))
309 
310 int		ehci_init(ehci_softc_t *);
311 int		ehci_intr(void *);
312 int		ehci_detach(ehci_softc_t *, int);
313 int		ehci_activate(device_t, enum devact);
314 void		ehci_childdet(device_t, device_t);
315 bool		ehci_suspend(device_t, const pmf_qual_t *);
316 bool		ehci_resume(device_t, const pmf_qual_t *);
317 bool		ehci_shutdown(device_t, int);
318 
319 #endif /* _EHCIVAR_H_ */
320