ehcivar.h revision 1.50
1/*	$NetBSD: ehcivar.h,v 1.50 2022/03/13 11:29:10 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
37typedef 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
50typedef 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
62typedef 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
92struct 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. */
145struct 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
163typedef struct ehci_softc {
164	device_t sc_dev;
165	kmutex_t sc_lock;
166	kmutex_t sc_intr_lock;
167	kcondvar_t sc_doorbell;
168	void *sc_doorbell_si;
169	struct lwp *sc_doorbelllwp;
170	void *sc_pcd_si;
171	struct usbd_bus sc_bus;
172	bus_space_tag_t iot;
173	bus_space_handle_t ioh;
174	bus_size_t sc_size;
175	bus_dma_tag_t sc_dmatag;	/* for control data structures */
176	u_int sc_offs;			/* offset to operational regs */
177	int sc_flags;			/* misc flags */
178#define EHCIF_DROPPED_INTR_WORKAROUND	0x01
179#define EHCIF_ETTF			0x02 /* Emb. Transaction Translater func. */
180
181	uint32_t sc_cmd;		/* shadow of cmd reg during suspend */
182
183	u_int sc_ncomp;
184	u_int sc_npcomp;
185	device_t sc_comps[EHCI_COMPANION_MAX];
186
187	/* This chunk to handle early RB_ASKNAME hand over. */
188	callout_t sc_compcallout;
189	kmutex_t sc_complock;
190	kcondvar_t sc_compcv;
191	enum {
192		CO_EARLY,
193		CO_SCHED,
194		CO_DONE,
195	} sc_comp_state;
196
197	usb_dma_t sc_fldma;
198	ehci_link_t *sc_flist;
199	u_int sc_flsize;
200	u_int sc_rand;			/* XXX need proper intr scheduling */
201
202	struct ehci_soft_islot sc_islots[EHCI_INTRQHS];
203
204	/*
205	 * an array matching sc_flist, but with software pointers,
206	 * not hardware address pointers
207	 */
208	struct ehci_soft_itd **sc_softitds;
209
210	TAILQ_HEAD(, ehci_xfer) sc_intrhead;
211
212	ehci_soft_qh_t *sc_freeqhs;
213	ehci_soft_qtd_t *sc_freeqtds;
214	LIST_HEAD(sc_freeitds, ehci_soft_itd) sc_freeitds;
215	LIST_HEAD(sc_freesitds, ehci_soft_sitd) sc_freesitds;
216
217	int sc_noport;
218	uint8_t sc_hasppc;		/* has Port Power Control */
219	uint8_t sc_istthreshold;	/* ISOC Scheduling Threshold (uframes) */
220	struct usbd_xfer *sc_intrxfer;
221	char sc_isreset[EHCI_MAX_PORTS];
222
223	uint32_t sc_eintrs;
224	ehci_soft_qh_t *sc_async_head;
225
226	pool_cache_t sc_xferpool;	/* free xfer pool */
227
228	struct callout sc_tmo_intrlist;
229
230	device_t sc_child; /* /dev/usb# device */
231	char sc_dying;
232
233	void (*sc_vendor_init)(struct ehci_softc *);
234	int (*sc_vendor_port_status)(struct ehci_softc *, uint32_t, int);
235} ehci_softc_t;
236
237#define EREAD1(sc, a) bus_space_read_1((sc)->iot, (sc)->ioh, (a))
238#define EREAD2(sc, a) bus_space_read_2((sc)->iot, (sc)->ioh, (a))
239#define EREAD4(sc, a) bus_space_read_4((sc)->iot, (sc)->ioh, (a))
240#define EWRITE1(sc, a, x) bus_space_write_1((sc)->iot, (sc)->ioh, (a), (x))
241#define EWRITE2(sc, a, x) bus_space_write_2((sc)->iot, (sc)->ioh, (a), (x))
242#define EWRITE4(sc, a, x) bus_space_write_4((sc)->iot, (sc)->ioh, (a), (x))
243#define EOREAD1(sc, a) bus_space_read_1((sc)->iot, (sc)->ioh, (sc)->sc_offs+(a))
244#define EOREAD2(sc, a) bus_space_read_2((sc)->iot, (sc)->ioh, (sc)->sc_offs+(a))
245#define EOREAD4(sc, a) bus_space_read_4((sc)->iot, (sc)->ioh, (sc)->sc_offs+(a))
246#define EOWRITE1(sc, a, x) bus_space_write_1((sc)->iot, (sc)->ioh, (sc)->sc_offs+(a), (x))
247#define EOWRITE2(sc, a, x) bus_space_write_2((sc)->iot, (sc)->ioh, (sc)->sc_offs+(a), (x))
248#define EOWRITE4(sc, a, x) bus_space_write_4((sc)->iot, (sc)->ioh, (sc)->sc_offs+(a), (x))
249
250int		ehci_init(ehci_softc_t *);
251int		ehci_intr(void *);
252int		ehci_detach(ehci_softc_t *, int);
253int		ehci_activate(device_t, enum devact);
254void		ehci_childdet(device_t, device_t);
255bool		ehci_suspend(device_t, const pmf_qual_t *);
256bool		ehci_resume(device_t, const pmf_qual_t *);
257bool		ehci_shutdown(device_t, int);
258
259#endif /* _EHCIVAR_H_ */
260