xref: /illumos-gate/usr/src/uts/common/io/usb/hcd/xhci/xhci_context.c (revision 993e3faf6a142ae3efdd24388883264c2b56bede)
1*993e3fafSRobert Mustacchi /*
2*993e3fafSRobert Mustacchi  * This file and its contents are supplied under the terms of the
3*993e3fafSRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4*993e3fafSRobert Mustacchi  * You may only use this file in accordance with the terms of version
5*993e3fafSRobert Mustacchi  * 1.0 of the CDDL.
6*993e3fafSRobert Mustacchi  *
7*993e3fafSRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8*993e3fafSRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9*993e3fafSRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10*993e3fafSRobert Mustacchi  */
11*993e3fafSRobert Mustacchi 
12*993e3fafSRobert Mustacchi /*
13*993e3fafSRobert Mustacchi  * Copyright 2016 Joyent, Inc.
14*993e3fafSRobert Mustacchi  */
15*993e3fafSRobert Mustacchi 
16*993e3fafSRobert Mustacchi /*
17*993e3fafSRobert Mustacchi  * Device Context Base Address Array (DCBAA) Management and Scratchpad
18*993e3fafSRobert Mustacchi  * management. This is also used to manage the device slot contexts in shared
19*993e3fafSRobert Mustacchi  * memory.
20*993e3fafSRobert Mustacchi  *
21*993e3fafSRobert Mustacchi  * Please see the big theory statement in xhci.c for more information.
22*993e3fafSRobert Mustacchi  */
23*993e3fafSRobert Mustacchi 
24*993e3fafSRobert Mustacchi #include <sys/usb/hcd/xhci/xhci.h>
25*993e3fafSRobert Mustacchi #include <sys/byteorder.h>
26*993e3fafSRobert Mustacchi 
27*993e3fafSRobert Mustacchi static void
xhci_scratchpad_fini(xhci_t * xhcip)28*993e3fafSRobert Mustacchi xhci_scratchpad_fini(xhci_t *xhcip)
29*993e3fafSRobert Mustacchi {
30*993e3fafSRobert Mustacchi 	xhci_scratchpad_t *xsp = &xhcip->xhci_scratchpad;
31*993e3fafSRobert Mustacchi 
32*993e3fafSRobert Mustacchi 	if (xsp->xsp_scratch_dma != NULL) {
33*993e3fafSRobert Mustacchi 		int i, npages;
34*993e3fafSRobert Mustacchi 		npages = xhcip->xhci_caps.xcap_max_scratch;
35*993e3fafSRobert Mustacchi 		for (i = 0; i < npages; i++) {
36*993e3fafSRobert Mustacchi 			xhci_dma_free(&xsp->xsp_scratch_dma[i]);
37*993e3fafSRobert Mustacchi 		}
38*993e3fafSRobert Mustacchi 		kmem_free(xsp->xsp_scratch_dma,
39*993e3fafSRobert Mustacchi 		    sizeof (xhci_dma_buffer_t) * npages);
40*993e3fafSRobert Mustacchi 		xsp->xsp_scratch_dma = NULL;
41*993e3fafSRobert Mustacchi 	}
42*993e3fafSRobert Mustacchi 	xhci_dma_free(&xsp->xsp_addr_dma);
43*993e3fafSRobert Mustacchi 	xsp->xsp_addrs = NULL;
44*993e3fafSRobert Mustacchi }
45*993e3fafSRobert Mustacchi 
46*993e3fafSRobert Mustacchi void
xhci_context_fini(xhci_t * xhcip)47*993e3fafSRobert Mustacchi xhci_context_fini(xhci_t *xhcip)
48*993e3fafSRobert Mustacchi {
49*993e3fafSRobert Mustacchi 	xhci_scratchpad_fini(xhcip);
50*993e3fafSRobert Mustacchi 	xhci_dma_free(&xhcip->xhci_dcbaa.xdc_dma);
51*993e3fafSRobert Mustacchi 	xhcip->xhci_dcbaa.xdc_base_addrs = NULL;
52*993e3fafSRobert Mustacchi }
53*993e3fafSRobert Mustacchi 
54*993e3fafSRobert Mustacchi static int
xhci_scratchpad_alloc(xhci_t * xhcip)55*993e3fafSRobert Mustacchi xhci_scratchpad_alloc(xhci_t *xhcip)
56*993e3fafSRobert Mustacchi {
57*993e3fafSRobert Mustacchi 	int npages, i;
58*993e3fafSRobert Mustacchi 	xhci_scratchpad_t *xsp;
59*993e3fafSRobert Mustacchi 	ddi_device_acc_attr_t acc;
60*993e3fafSRobert Mustacchi 	ddi_dma_attr_t attr;
61*993e3fafSRobert Mustacchi 
62*993e3fafSRobert Mustacchi 	/*
63*993e3fafSRobert Mustacchi 	 * First allocate the scratchpad table, then the actual pages.
64*993e3fafSRobert Mustacchi 	 */
65*993e3fafSRobert Mustacchi 	ASSERT(xhcip->xhci_caps.xcap_max_scratch > 0);
66*993e3fafSRobert Mustacchi 	npages = xhcip->xhci_caps.xcap_max_scratch;
67*993e3fafSRobert Mustacchi 	xhci_dma_acc_attr(xhcip, &acc);
68*993e3fafSRobert Mustacchi 	xhci_dma_dma_attr(xhcip, &attr);
69*993e3fafSRobert Mustacchi 	xsp = &xhcip->xhci_scratchpad;
70*993e3fafSRobert Mustacchi 	if (xhci_dma_alloc(xhcip, &xsp->xsp_addr_dma, &attr, &acc,
71*993e3fafSRobert Mustacchi 	    B_TRUE, sizeof (uint64_t) * npages, B_FALSE) == B_FALSE) {
72*993e3fafSRobert Mustacchi 		xhci_log(xhcip, "!failed to allocate DMA memory for device "
73*993e3fafSRobert Mustacchi 		    "context");
74*993e3fafSRobert Mustacchi 		return (ENOMEM);
75*993e3fafSRobert Mustacchi 	}
76*993e3fafSRobert Mustacchi 
77*993e3fafSRobert Mustacchi 	xsp->xsp_addrs = (void *)xsp->xsp_addr_dma.xdb_va;
78*993e3fafSRobert Mustacchi 
79*993e3fafSRobert Mustacchi 	/*
80*993e3fafSRobert Mustacchi 	 * Note that the scratchpad memory itself can actually be relaxed, which
81*993e3fafSRobert Mustacchi 	 * is almost better, since we'll never actually access this memory
82*993e3fafSRobert Mustacchi 	 * ourselves, only use it to tear things down. As such, we also bump up
83*993e3fafSRobert Mustacchi 	 * the segment boundary restrictions, since we don't really have any for
84*993e3fafSRobert Mustacchi 	 * this memory.
85*993e3fafSRobert Mustacchi 	 */
86*993e3fafSRobert Mustacchi 	xhci_dma_scratchpad_attr(xhcip, &attr);
87*993e3fafSRobert Mustacchi 	xsp->xsp_scratch_dma = kmem_zalloc(sizeof (xhci_dma_buffer_t) * npages,
88*993e3fafSRobert Mustacchi 	    KM_SLEEP);
89*993e3fafSRobert Mustacchi 	for (i = 0; i < npages; i++) {
90*993e3fafSRobert Mustacchi 		if (xhci_dma_alloc(xhcip, &xsp->xsp_scratch_dma[i], &attr, &acc,
91*993e3fafSRobert Mustacchi 		    B_TRUE, xhcip->xhci_caps.xcap_pagesize, B_FALSE) ==
92*993e3fafSRobert Mustacchi 		    B_FALSE) {
93*993e3fafSRobert Mustacchi 			/*
94*993e3fafSRobert Mustacchi 			 * It is safe for us to call xhci_scratchpad_fini() in a
95*993e3fafSRobert Mustacchi 			 * partially constructed state. Because we've zeroed the
96*993e3fafSRobert Mustacchi 			 * structures in the above allocation, the DMA buffer
97*993e3fafSRobert Mustacchi 			 * teardown code can handle these zeroed or partially
98*993e3fafSRobert Mustacchi 			 * initialized structures correctly.
99*993e3fafSRobert Mustacchi 			 */
100*993e3fafSRobert Mustacchi 			xhci_scratchpad_fini(xhcip);
101*993e3fafSRobert Mustacchi 			xhci_log(xhcip, "!failed to allocate DMA memory for "
102*993e3fafSRobert Mustacchi 			    "device scratchpad");
103*993e3fafSRobert Mustacchi 			return (ENOMEM);
104*993e3fafSRobert Mustacchi 		}
105*993e3fafSRobert Mustacchi 	}
106*993e3fafSRobert Mustacchi 
107*993e3fafSRobert Mustacchi 	return (0);
108*993e3fafSRobert Mustacchi }
109*993e3fafSRobert Mustacchi 
110*993e3fafSRobert Mustacchi /*
111*993e3fafSRobert Mustacchi  * We always allocate the DCBAA based on its maximum possible size, simplifying
112*993e3fafSRobert Mustacchi  * the code and at worst wasting only a couple hundred bytes.
113*993e3fafSRobert Mustacchi  */
114*993e3fafSRobert Mustacchi static int
xhci_dcbaa_alloc(xhci_t * xhcip)115*993e3fafSRobert Mustacchi xhci_dcbaa_alloc(xhci_t *xhcip)
116*993e3fafSRobert Mustacchi {
117*993e3fafSRobert Mustacchi 	xhci_dcbaa_t *dcb;
118*993e3fafSRobert Mustacchi 	ddi_device_acc_attr_t acc;
119*993e3fafSRobert Mustacchi 	ddi_dma_attr_t attr;
120*993e3fafSRobert Mustacchi 
121*993e3fafSRobert Mustacchi 	dcb = &xhcip->xhci_dcbaa;
122*993e3fafSRobert Mustacchi 	xhci_dma_acc_attr(xhcip, &acc);
123*993e3fafSRobert Mustacchi 	xhci_dma_dma_attr(xhcip, &attr);
124*993e3fafSRobert Mustacchi 	if (xhci_dma_alloc(xhcip, &dcb->xdc_dma, &attr, &acc,
125*993e3fafSRobert Mustacchi 	    B_FALSE, sizeof (uint64_t) * XHCI_MAX_SLOTS, B_FALSE) == B_FALSE) {
126*993e3fafSRobert Mustacchi 		xhci_log(xhcip, "!failed to allocate DMA memory for device "
127*993e3fafSRobert Mustacchi 		    "context");
128*993e3fafSRobert Mustacchi 		return (ENOMEM);
129*993e3fafSRobert Mustacchi 	}
130*993e3fafSRobert Mustacchi 
131*993e3fafSRobert Mustacchi 	/*
132*993e3fafSRobert Mustacchi 	 * This lint gag is safe, because we always have at least a 64-byte
133*993e3fafSRobert Mustacchi 	 * alignment from the DMA attributes.
134*993e3fafSRobert Mustacchi 	 */
135*993e3fafSRobert Mustacchi 	/* LINTED: E_BAD_PTR_CAST_ALIGN */
136*993e3fafSRobert Mustacchi 	dcb->xdc_base_addrs = (uint64_t *)dcb->xdc_dma.xdb_va;
137*993e3fafSRobert Mustacchi 	return (0);
138*993e3fafSRobert Mustacchi }
139*993e3fafSRobert Mustacchi 
140*993e3fafSRobert Mustacchi /*
141*993e3fafSRobert Mustacchi  * We are called to initialize the DCBAA every time that we start the
142*993e3fafSRobert Mustacchi  * controller. This happens both the first time we bring it up and after we
143*993e3fafSRobert Mustacchi  * reset it from errors. Therefore to initialize the DCBAA we need to do the
144*993e3fafSRobert Mustacchi  * following:
145*993e3fafSRobert Mustacchi  *
146*993e3fafSRobert Mustacchi  *   o Allocate DMA memory (if it doesn't already exist)
147*993e3fafSRobert Mustacchi  *   o If scratchpad slots have been requested, allocate and program them if
148*993e3fafSRobert Mustacchi  *     necessary
149*993e3fafSRobert Mustacchi  *   o Program the DCBAAP register.
150*993e3fafSRobert Mustacchi  */
151*993e3fafSRobert Mustacchi int
xhci_context_init(xhci_t * xhcip)152*993e3fafSRobert Mustacchi xhci_context_init(xhci_t *xhcip)
153*993e3fafSRobert Mustacchi {
154*993e3fafSRobert Mustacchi 	int ret;
155*993e3fafSRobert Mustacchi 	xhci_dcbaa_t *dcb = &xhcip->xhci_dcbaa;
156*993e3fafSRobert Mustacchi 
157*993e3fafSRobert Mustacchi 	if (dcb->xdc_base_addrs == NULL) {
158*993e3fafSRobert Mustacchi 		if ((ret = xhci_dcbaa_alloc(xhcip)) != 0)
159*993e3fafSRobert Mustacchi 			return (ret);
160*993e3fafSRobert Mustacchi 	}
161*993e3fafSRobert Mustacchi 
162*993e3fafSRobert Mustacchi 	bzero(dcb->xdc_base_addrs, sizeof (uint64_t) * XHCI_MAX_SLOTS);
163*993e3fafSRobert Mustacchi 	if (xhcip->xhci_caps.xcap_max_scratch != 0) {
164*993e3fafSRobert Mustacchi 		int i, npages;
165*993e3fafSRobert Mustacchi 		xhci_scratchpad_t *xsp = &xhcip->xhci_scratchpad;
166*993e3fafSRobert Mustacchi 
167*993e3fafSRobert Mustacchi 		if (xsp->xsp_addrs == NULL &&
168*993e3fafSRobert Mustacchi 		    (ret = xhci_scratchpad_alloc(xhcip)) != 0) {
169*993e3fafSRobert Mustacchi 			xhci_context_fini(xhcip);
170*993e3fafSRobert Mustacchi 			return (ret);
171*993e3fafSRobert Mustacchi 		}
172*993e3fafSRobert Mustacchi 
173*993e3fafSRobert Mustacchi 		dcb->xdc_base_addrs[XHCI_DCBAA_SCRATCHPAD_INDEX] =
174*993e3fafSRobert Mustacchi 		    LE_64(xhci_dma_pa(&xsp->xsp_addr_dma));
175*993e3fafSRobert Mustacchi 
176*993e3fafSRobert Mustacchi 		npages = xhcip->xhci_caps.xcap_max_scratch;
177*993e3fafSRobert Mustacchi 		for (i = 0; i < npages; i++) {
178*993e3fafSRobert Mustacchi 			xsp->xsp_addrs[i] =
179*993e3fafSRobert Mustacchi 			    LE_64(xhci_dma_pa(&xsp->xsp_scratch_dma[i]));
180*993e3fafSRobert Mustacchi 		}
181*993e3fafSRobert Mustacchi 
182*993e3fafSRobert Mustacchi 		XHCI_DMA_SYNC(xsp->xsp_addr_dma, DDI_DMA_SYNC_FORDEV);
183*993e3fafSRobert Mustacchi 		if (xhci_check_dma_handle(xhcip, &xsp->xsp_addr_dma) !=
184*993e3fafSRobert Mustacchi 		    DDI_FM_OK) {
185*993e3fafSRobert Mustacchi 			ddi_fm_service_impact(xhcip->xhci_dip,
186*993e3fafSRobert Mustacchi 			    DDI_SERVICE_LOST);
187*993e3fafSRobert Mustacchi 			return (EIO);
188*993e3fafSRobert Mustacchi 		}
189*993e3fafSRobert Mustacchi 	}
190*993e3fafSRobert Mustacchi 
191*993e3fafSRobert Mustacchi 	XHCI_DMA_SYNC(dcb->xdc_dma, DDI_DMA_SYNC_FORDEV);
192*993e3fafSRobert Mustacchi 	if (xhci_check_dma_handle(xhcip, &dcb->xdc_dma) != DDI_FM_OK) {
193*993e3fafSRobert Mustacchi 		ddi_fm_service_impact(xhcip->xhci_dip, DDI_SERVICE_LOST);
194*993e3fafSRobert Mustacchi 		return (EIO);
195*993e3fafSRobert Mustacchi 	}
196*993e3fafSRobert Mustacchi 
197*993e3fafSRobert Mustacchi 	xhci_put64(xhcip, XHCI_R_OPER, XHCI_DCBAAP,
198*993e3fafSRobert Mustacchi 	    LE_64(xhci_dma_pa(&dcb->xdc_dma)));
199*993e3fafSRobert Mustacchi 	if (xhci_check_regs_acc(xhcip) != DDI_FM_OK) {
200*993e3fafSRobert Mustacchi 		ddi_fm_service_impact(xhcip->xhci_dip,
201*993e3fafSRobert Mustacchi 		    DDI_SERVICE_LOST);
202*993e3fafSRobert Mustacchi 		return (EIO);
203*993e3fafSRobert Mustacchi 	}
204*993e3fafSRobert Mustacchi 
205*993e3fafSRobert Mustacchi 	return (0);
206*993e3fafSRobert Mustacchi }
207*993e3fafSRobert Mustacchi 
208*993e3fafSRobert Mustacchi /*
209*993e3fafSRobert Mustacchi  * Initialize the default output context. It should already have been zeroed, so
210*993e3fafSRobert Mustacchi  * all we need to do is insert it into the right place in the device context
211*993e3fafSRobert Mustacchi  * array.
212*993e3fafSRobert Mustacchi  */
213*993e3fafSRobert Mustacchi boolean_t
xhci_context_slot_output_init(xhci_t * xhcip,xhci_device_t * xd)214*993e3fafSRobert Mustacchi xhci_context_slot_output_init(xhci_t *xhcip, xhci_device_t *xd)
215*993e3fafSRobert Mustacchi {
216*993e3fafSRobert Mustacchi 	xhci_dcbaa_t *dcb = &xhcip->xhci_dcbaa;
217*993e3fafSRobert Mustacchi 	VERIFY(xd->xd_slot > 0 &&
218*993e3fafSRobert Mustacchi 	    xd->xd_slot <= xhcip->xhci_caps.xcap_max_slots);
219*993e3fafSRobert Mustacchi 
220*993e3fafSRobert Mustacchi 	xhcip->xhci_dcbaa.xdc_base_addrs[xd->xd_slot] =
221*993e3fafSRobert Mustacchi 	    LE_64(xhci_dma_pa(&xd->xd_octx));
222*993e3fafSRobert Mustacchi 	XHCI_DMA_SYNC(dcb->xdc_dma, DDI_DMA_SYNC_FORDEV);
223*993e3fafSRobert Mustacchi 	if (xhci_check_dma_handle(xhcip, &dcb->xdc_dma) != DDI_FM_OK) {
224*993e3fafSRobert Mustacchi 		xhci_error(xhcip, "failed to initialize slot output context "
225*993e3fafSRobert Mustacchi 		    "for device on port %d, slot %d: fatal FM error "
226*993e3fafSRobert Mustacchi 		    "synchronizing DCBAA slot DMA memory", xd->xd_slot,
227*993e3fafSRobert Mustacchi 		    xd->xd_port);
228*993e3fafSRobert Mustacchi 		xhci_fm_runtime_reset(xhcip);
229*993e3fafSRobert Mustacchi 		return (B_FALSE);
230*993e3fafSRobert Mustacchi 	}
231*993e3fafSRobert Mustacchi 
232*993e3fafSRobert Mustacchi 	return (B_TRUE);
233*993e3fafSRobert Mustacchi }
234*993e3fafSRobert Mustacchi 
235*993e3fafSRobert Mustacchi void
xhci_context_slot_output_fini(xhci_t * xhcip,xhci_device_t * xd)236*993e3fafSRobert Mustacchi xhci_context_slot_output_fini(xhci_t *xhcip, xhci_device_t *xd)
237*993e3fafSRobert Mustacchi {
238*993e3fafSRobert Mustacchi 	xhci_dcbaa_t *dcb = &xhcip->xhci_dcbaa;
239*993e3fafSRobert Mustacchi 	VERIFY(xd->xd_slot > 0 &&
240*993e3fafSRobert Mustacchi 	    xd->xd_slot <= xhcip->xhci_caps.xcap_max_slots);
241*993e3fafSRobert Mustacchi 
242*993e3fafSRobert Mustacchi 	xhcip->xhci_dcbaa.xdc_base_addrs[xd->xd_slot] = 0ULL;
243*993e3fafSRobert Mustacchi 	XHCI_DMA_SYNC(dcb->xdc_dma, DDI_DMA_SYNC_FORDEV);
244*993e3fafSRobert Mustacchi 	if (xhci_check_dma_handle(xhcip, &dcb->xdc_dma) != DDI_FM_OK) {
245*993e3fafSRobert Mustacchi 		xhci_error(xhcip, "failed to finalize slot output context "
246*993e3fafSRobert Mustacchi 		    "for device on port %d, slot %d: fatal FM error "
247*993e3fafSRobert Mustacchi 		    "synchronizing DCBAA slot DMA memory", xd->xd_slot,
248*993e3fafSRobert Mustacchi 		    xd->xd_port);
249*993e3fafSRobert Mustacchi 		xhci_fm_runtime_reset(xhcip);
250*993e3fafSRobert Mustacchi 	}
251*993e3fafSRobert Mustacchi }
252