Home | History | Annotate | Line # | Download | only in usb
      1 /*	$NetBSD: ehcivar.h,v 1.55 2026/05/02 07:23:00 tsutsui 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 (at) 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 
     47 typedef struct ehci_soft_qh {
     48 	ehci_qh_t *qh;
     49 	struct ehci_soft_qh *next;
     50 	struct ehci_soft_qtd *sqtd;
     51 	ehci_physaddr_t physaddr;
     52 	usb_dma_t dma;			/* QH's DMA infos */
     53 	int offs;			/* QH's offset in usb_dma_t */
     54 	int islot;
     55 } ehci_soft_qh_t;
     56 
     57 typedef struct ehci_soft_itd {
     58 	union {
     59 		ehci_itd_t *itd;
     60 		ehci_sitd_t *sitd;
     61 	};
     62 	union {
     63 		struct {
     64 			/* soft_itds links in a periodic frame */
     65 			struct ehci_soft_itd *next;
     66 			struct ehci_soft_itd *prev;
     67 		} frame_list;
     68 		/* circular list of free itds */
     69 		LIST_ENTRY(ehci_soft_itd) free_list;
     70 	};
     71 	struct ehci_soft_itd *xfer_next; /* Next soft_itd in xfer */
     72 	ehci_physaddr_t physaddr;
     73 	usb_dma_t dma;
     74 	int offs;
     75 	int slot;
     76 	struct timeval t; /* store free time */
     77 } ehci_soft_itd_t;
     78 
     79 #define ehci_soft_sitd_t ehci_soft_itd_t
     80 #define ehci_soft_sitd ehci_soft_itd
     81 #define sc_softsitds sc_softitds
     82 
     83 struct ehci_xfer {
     84 	struct usbd_xfer ex_xfer;
     85 	TAILQ_ENTRY(ehci_xfer) ex_next; /* list of active xfers */
     86 	enum {
     87 		EX_NONE,
     88 		EX_CTRL,
     89 		EX_BULK,
     90 		EX_INTR,
     91 		EX_ISOC,
     92 		EX_FS_ISOC
     93 	} ex_type;
     94 	/* ctrl/bulk/intr */
     95 	struct {
     96 		ehci_soft_qtd_t **ex_sqtds;
     97 		size_t ex_nsqtd;
     98 	};
     99 	union {
    100 		/* ctrl */
    101 		struct {
    102 			ehci_soft_qtd_t *ex_setup;
    103 			ehci_soft_qtd_t *ex_data;
    104 			ehci_soft_qtd_t *ex_status;
    105 		};
    106 		/* bulk/intr */
    107 		struct {
    108 			ehci_soft_qtd_t *ex_sqtdstart;
    109 			ehci_soft_qtd_t *ex_sqtdend;
    110 		};
    111 		/* isoc */
    112 		struct {
    113 			ehci_soft_itd_t *ex_itdstart;
    114 			ehci_soft_itd_t *ex_itdend;
    115 		};
    116 		/* split (aka fs) isoc */
    117 		struct {
    118 			ehci_soft_sitd_t *ex_sitdstart;
    119 			ehci_soft_sitd_t *ex_sitdend;
    120 		};
    121 	};
    122 	bool ex_isdone;	/* used only when DIAGNOSTIC is defined */
    123 };
    124 
    125 #define EHCI_BUS2SC(bus)	((bus)->ub_hcpriv)
    126 #define EHCI_PIPE2SC(pipe)	EHCI_BUS2SC((pipe)->up_dev->ud_bus)
    127 #define EHCI_XFER2SC(xfer)	EHCI_BUS2SC((xfer)->ux_bus)
    128 #define EHCI_EPIPE2SC(epipe)	EHCI_BUS2SC((epipe)->pipe.up_dev->ud_bus)
    129 
    130 #define EHCI_XFER2EXFER(xfer)	((struct ehci_xfer *)(xfer))
    131 
    132 #define EHCI_XFER2EPIPE(xfer)	((struct ehci_pipe *)((xfer)->ux_pipe))
    133 #define EHCI_PIPE2EPIPE(pipe)	((struct ehci_pipe *)(pipe))
    134 
    135 /* Information about an entry in the interrupt list. */
    136 struct ehci_soft_islot {
    137 	ehci_soft_qh_t *sqh;	/* Queue Head. */
    138 };
    139 
    140 #define EHCI_FRAMELIST_MAXCOUNT	1024
    141 #define EHCI_IPOLLRATES		8 /* Poll rates (1ms, 2, 4, 8 .. 128) */
    142 #define EHCI_INTRQHS		((1 << EHCI_IPOLLRATES) - 1)
    143 #define EHCI_MAX_POLLRATE	(1 << (EHCI_IPOLLRATES - 1))
    144 #define EHCI_IQHIDX(lev, pos) \
    145 	((((pos) & ((1 << (lev)) - 1)) | (1 << (lev))) - 1)
    146 #define EHCI_ILEV_IVAL(lev)	(1 << (lev))
    147 
    148 
    149 #define EHCI_HASH_SIZE 128
    150 #define EHCI_COMPANION_MAX 8
    151 
    152 #define EHCI_FREE_LIST_INTERVAL 100
    153 
    154 typedef struct ehci_softc {
    155 	device_t sc_dev;
    156 	kmutex_t sc_rhlock;
    157 	kmutex_t sc_lock;
    158 	kmutex_t sc_intr_lock;
    159 	kcondvar_t sc_doorbell;
    160 	void *sc_doorbell_si;
    161 	struct lwp *sc_doorbelllwp;
    162 	void *sc_pcd_si;
    163 	struct usbd_bus sc_bus;
    164 	bus_space_tag_t iot;
    165 	bus_space_handle_t ioh;
    166 	bus_size_t sc_size;
    167 	bus_dma_tag_t sc_dmatag;	/* for control data structures */
    168 	u_int sc_offs;			/* offset to operational regs */
    169 	int sc_flags;			/* misc flags */
    170 #define EHCIF_DROPPED_INTR_WORKAROUND	0x01
    171 #define EHCIF_ETTF			0x02 /* Emb. Transaction Translater func. */
    172 #define EHCIF_32BIT_ACCESS		0x04 /* 32-bit MMIO access req'd */
    173 #define EHCIF_SB600_ASYNCLIST_RELOAD	0x08 /* SB600 quirk (PR/57359) */
    174 
    175 	uint32_t sc_cmd;		/* shadow of cmd reg during suspend */
    176 
    177 	u_int sc_ncomp;
    178 	u_int sc_npcomp;
    179 	device_t sc_comps[EHCI_COMPANION_MAX];
    180 
    181 	/* This chunk to handle early RB_ASKNAME hand over. */
    182 	callout_t sc_compcallout;
    183 	kmutex_t sc_complock;
    184 	kcondvar_t sc_compcv;
    185 	enum {
    186 		CO_EARLY,
    187 		CO_SCHED,
    188 		CO_DONE,
    189 	} sc_comp_state;
    190 
    191 	usb_dma_t sc_fldma;
    192 	ehci_link_t *sc_flist;
    193 	u_int sc_flsize;
    194 	u_int sc_rand;			/* XXX need proper intr scheduling */
    195 
    196 	struct ehci_soft_islot sc_islots[EHCI_INTRQHS];
    197 
    198 	/*
    199 	 * an array matching sc_flist, but with software pointers,
    200 	 * not hardware address pointers
    201 	 */
    202 	struct ehci_soft_itd **sc_softitds;
    203 
    204 	TAILQ_HEAD(, ehci_xfer) sc_intrhead;
    205 
    206 	ehci_soft_qh_t *sc_freeqhs;
    207 	ehci_soft_qtd_t *sc_freeqtds;
    208 	LIST_HEAD(sc_freeitds, ehci_soft_itd) sc_freeitds;
    209 	LIST_HEAD(sc_freesitds, ehci_soft_sitd) sc_freesitds;
    210 
    211 	int sc_noport;
    212 	uint8_t sc_hasppc;		/* has Port Power Control */
    213 	uint8_t sc_istthreshold;	/* ISOC Scheduling Threshold (uframes) */
    214 	struct usbd_xfer *sc_intrxfer;
    215 	char sc_isreset[EHCI_MAX_PORTS];
    216 
    217 	uint32_t sc_eintrs;
    218 	ehci_soft_qh_t *sc_async_head;
    219 
    220 	pool_cache_t sc_xferpool;	/* free xfer pool */
    221 
    222 	struct callout sc_tmo_intrlist;
    223 
    224 	device_t sc_child; /* /dev/usb# device */
    225 	char sc_dying;
    226 
    227 	void (*sc_vendor_init)(struct ehci_softc *);
    228 	int (*sc_vendor_port_status)(struct ehci_softc *, uint32_t, int);
    229 } ehci_softc_t;
    230 
    231 static inline uint8_t
    232 ehci_read_1(struct ehci_softc *sc, u_int offset)
    233 {
    234 	if (ISSET(sc->sc_flags, EHCIF_32BIT_ACCESS)) {
    235 		uint32_t val;
    236 
    237 		val = bus_space_read_4(sc->iot, sc->ioh, offset & ~3);
    238 		return (val >> ((offset & 3) * NBBY)) & 0xff;
    239 	} else {
    240 		return bus_space_read_1(sc->iot, sc->ioh, offset);
    241 	}
    242 }
    243 
    244 static inline uint16_t
    245 ehci_read_2(struct ehci_softc *sc, u_int offset)
    246 {
    247 	if (ISSET(sc->sc_flags, EHCIF_32BIT_ACCESS)) {
    248 		uint32_t val;
    249 
    250 		val = bus_space_read_4(sc->iot, sc->ioh, offset & ~3);
    251 		return (val >> ((offset & 3) * NBBY)) & 0xffff;
    252 	} else {
    253 		return bus_space_read_2(sc->iot, sc->ioh, offset);
    254 	}
    255 }
    256 
    257 static inline void
    258 ehci_write_1(struct ehci_softc *sc, u_int offset, uint8_t data)
    259 {
    260 	if (ISSET(sc->sc_flags, EHCIF_32BIT_ACCESS)) {
    261 		const uint32_t mask = 0xffU << ((offset & 3) * NBBY);
    262 		uint32_t val;
    263 
    264 		val = bus_space_read_4(sc->iot, sc->ioh, offset & ~3);
    265 		val &= ~mask;
    266 		val |= __SHIFTIN(data, mask);
    267 		bus_space_write_4(sc->iot, sc->ioh, offset & ~3, val);
    268 	} else {
    269 		bus_space_write_1(sc->iot, sc->ioh, offset, data);
    270 	}
    271 }
    272 
    273 static inline void
    274 ehci_write_2(struct ehci_softc *sc, u_int offset, uint16_t data)
    275 {
    276 	if (ISSET(sc->sc_flags, EHCIF_32BIT_ACCESS)) {
    277 		const uint32_t mask = 0xffffU << ((offset & 3) * NBBY);
    278 		uint32_t val;
    279 
    280 		val = bus_space_read_4(sc->iot, sc->ioh, offset & ~3);
    281 		val &= ~mask;
    282 		val |= __SHIFTIN(data, mask);
    283 		bus_space_write_4(sc->iot, sc->ioh, offset & ~3, val);
    284 	} else {
    285 		bus_space_write_2(sc->iot, sc->ioh, offset, data);
    286 	}
    287 }
    288 
    289 #define EREAD1(sc, a) ehci_read_1((sc), (a))
    290 #define EREAD2(sc, a) ehci_read_2((sc), (a))
    291 #define EREAD4(sc, a) bus_space_read_4((sc)->iot, (sc)->ioh, (a))
    292 #define EWRITE1(sc, a, x) ehci_write_1((sc), (a), (x))
    293 #define EWRITE2(sc, a, x) ehci_write_2((sc), (a), (x))
    294 #define EWRITE4(sc, a, x) bus_space_write_4((sc)->iot, (sc)->ioh, (a), (x))
    295 #define EOREAD1(sc, a) ehci_read_1((sc), (sc)->sc_offs+(a))
    296 #define EOREAD2(sc, a) ehci_read_2((sc), (sc)->sc_offs+(a))
    297 #define EOREAD4(sc, a) bus_space_read_4((sc)->iot, (sc)->ioh, (sc)->sc_offs+(a))
    298 #define EOWRITE1(sc, a, x) ehci_write_1((sc), (sc)->sc_offs+(a), (x))
    299 #define EOWRITE2(sc, a, x) ehci_write_2((sc), (sc)->sc_offs+(a), (x))
    300 #define EOWRITE4(sc, a, x) bus_space_write_4((sc)->iot, (sc)->ioh, (sc)->sc_offs+(a), (x))
    301 
    302 int		ehci_init(ehci_softc_t *);
    303 int		ehci_intr(void *);
    304 int		ehci_detach(ehci_softc_t *, int);
    305 int		ehci_activate(device_t, enum devact);
    306 void		ehci_childdet(device_t, device_t);
    307 bool		ehci_suspend(device_t, const pmf_qual_t *);
    308 bool		ehci_resume(device_t, const pmf_qual_t *);
    309 bool		ehci_shutdown(device_t, int);
    310 
    311 #endif /* _EHCIVAR_H_ */
    312