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