xref: /netbsd/sys/dev/usb/ehcivar.h (revision 08ccf0ed)
1 /*	$NetBSD: ehcivar.h,v 1.51 2022/03/13 11:29:21 riastradh 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 
182 	uint32_t sc_cmd;		/* shadow of cmd reg during suspend */
183 
184 	u_int sc_ncomp;
185 	u_int sc_npcomp;
186 	device_t sc_comps[EHCI_COMPANION_MAX];
187 
188 	/* This chunk to handle early RB_ASKNAME hand over. */
189 	callout_t sc_compcallout;
190 	kmutex_t sc_complock;
191 	kcondvar_t sc_compcv;
192 	enum {
193 		CO_EARLY,
194 		CO_SCHED,
195 		CO_DONE,
196 	} sc_comp_state;
197 
198 	usb_dma_t sc_fldma;
199 	ehci_link_t *sc_flist;
200 	u_int sc_flsize;
201 	u_int sc_rand;			/* XXX need proper intr scheduling */
202 
203 	struct ehci_soft_islot sc_islots[EHCI_INTRQHS];
204 
205 	/*
206 	 * an array matching sc_flist, but with software pointers,
207 	 * not hardware address pointers
208 	 */
209 	struct ehci_soft_itd **sc_softitds;
210 
211 	TAILQ_HEAD(, ehci_xfer) sc_intrhead;
212 
213 	ehci_soft_qh_t *sc_freeqhs;
214 	ehci_soft_qtd_t *sc_freeqtds;
215 	LIST_HEAD(sc_freeitds, ehci_soft_itd) sc_freeitds;
216 	LIST_HEAD(sc_freesitds, ehci_soft_sitd) sc_freesitds;
217 
218 	int sc_noport;
219 	uint8_t sc_hasppc;		/* has Port Power Control */
220 	uint8_t sc_istthreshold;	/* ISOC Scheduling Threshold (uframes) */
221 	struct usbd_xfer *sc_intrxfer;
222 	char sc_isreset[EHCI_MAX_PORTS];
223 
224 	uint32_t sc_eintrs;
225 	ehci_soft_qh_t *sc_async_head;
226 
227 	pool_cache_t sc_xferpool;	/* free xfer pool */
228 
229 	struct callout sc_tmo_intrlist;
230 
231 	device_t sc_child; /* /dev/usb# device */
232 	char sc_dying;
233 
234 	void (*sc_vendor_init)(struct ehci_softc *);
235 	int (*sc_vendor_port_status)(struct ehci_softc *, uint32_t, int);
236 } ehci_softc_t;
237 
238 #define EREAD1(sc, a) bus_space_read_1((sc)->iot, (sc)->ioh, (a))
239 #define EREAD2(sc, a) bus_space_read_2((sc)->iot, (sc)->ioh, (a))
240 #define EREAD4(sc, a) bus_space_read_4((sc)->iot, (sc)->ioh, (a))
241 #define EWRITE1(sc, a, x) bus_space_write_1((sc)->iot, (sc)->ioh, (a), (x))
242 #define EWRITE2(sc, a, x) bus_space_write_2((sc)->iot, (sc)->ioh, (a), (x))
243 #define EWRITE4(sc, a, x) bus_space_write_4((sc)->iot, (sc)->ioh, (a), (x))
244 #define EOREAD1(sc, a) bus_space_read_1((sc)->iot, (sc)->ioh, (sc)->sc_offs+(a))
245 #define EOREAD2(sc, a) bus_space_read_2((sc)->iot, (sc)->ioh, (sc)->sc_offs+(a))
246 #define EOREAD4(sc, a) bus_space_read_4((sc)->iot, (sc)->ioh, (sc)->sc_offs+(a))
247 #define EOWRITE1(sc, a, x) bus_space_write_1((sc)->iot, (sc)->ioh, (sc)->sc_offs+(a), (x))
248 #define EOWRITE2(sc, a, x) bus_space_write_2((sc)->iot, (sc)->ioh, (sc)->sc_offs+(a), (x))
249 #define EOWRITE4(sc, a, x) bus_space_write_4((sc)->iot, (sc)->ioh, (sc)->sc_offs+(a), (x))
250 
251 int		ehci_init(ehci_softc_t *);
252 int		ehci_intr(void *);
253 int		ehci_detach(ehci_softc_t *, int);
254 int		ehci_activate(device_t, enum devact);
255 void		ehci_childdet(device_t, device_t);
256 bool		ehci_suspend(device_t, const pmf_qual_t *);
257 bool		ehci_resume(device_t, const pmf_qual_t *);
258 bool		ehci_shutdown(device_t, int);
259 
260 #endif /* _EHCIVAR_H_ */
261