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