]>
Commit | Line | Data |
---|---|---|
5fd54ace | 1 | // SPDX-License-Identifier: GPL-2.0+ |
1da177e4 LT |
2 | /* |
3 | * Copyright (c) 2001 by David Brownell | |
53bd6a60 | 4 | * |
1da177e4 LT |
5 | * This program is free software; you can redistribute it and/or modify it |
6 | * under the terms of the GNU General Public License as published by the | |
7 | * Free Software Foundation; either version 2 of the License, or (at your | |
8 | * option) any later version. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, but | |
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
12 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
13 | * for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License | |
16 | * along with this program; if not, write to the Free Software Foundation, | |
17 | * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
18 | */ | |
19 | ||
20 | /* this file is part of ehci-hcd.c */ | |
21 | ||
22 | /*-------------------------------------------------------------------------*/ | |
23 | ||
24 | /* | |
25 | * There's basically three types of memory: | |
26 | * - data used only by the HCD ... kmalloc is fine | |
27 | * - async and periodic schedules, shared by HC and HCD ... these | |
28 | * need to use dma_pool or dma_alloc_coherent | |
53bd6a60 | 29 | * - driver buffers, read/written by HC ... single shot DMA mapped |
1da177e4 | 30 | * |
6dbd682b | 31 | * There's also "register" data (e.g. PCI or SOC), which is memory mapped. |
1da177e4 LT |
32 | * No memory seen by this driver is pageable. |
33 | */ | |
34 | ||
35 | /*-------------------------------------------------------------------------*/ | |
36 | ||
37 | /* Allocate the key transfer structures from the previously allocated pool */ | |
38 | ||
6dbd682b SR |
39 | static inline void ehci_qtd_init(struct ehci_hcd *ehci, struct ehci_qtd *qtd, |
40 | dma_addr_t dma) | |
1da177e4 LT |
41 | { |
42 | memset (qtd, 0, sizeof *qtd); | |
43 | qtd->qtd_dma = dma; | |
230f7ede | 44 | qtd->hw_token = cpu_to_hc32(ehci, QTD_STS_HALT); |
6dbd682b SR |
45 | qtd->hw_next = EHCI_LIST_END(ehci); |
46 | qtd->hw_alt_next = EHCI_LIST_END(ehci); | |
1da177e4 LT |
47 | INIT_LIST_HEAD (&qtd->qtd_list); |
48 | } | |
49 | ||
55016f10 | 50 | static struct ehci_qtd *ehci_qtd_alloc (struct ehci_hcd *ehci, gfp_t flags) |
1da177e4 LT |
51 | { |
52 | struct ehci_qtd *qtd; | |
53 | dma_addr_t dma; | |
54 | ||
55 | qtd = dma_pool_alloc (ehci->qtd_pool, flags, &dma); | |
56 | if (qtd != NULL) { | |
6dbd682b | 57 | ehci_qtd_init(ehci, qtd, dma); |
1da177e4 LT |
58 | } |
59 | return qtd; | |
60 | } | |
61 | ||
62 | static inline void ehci_qtd_free (struct ehci_hcd *ehci, struct ehci_qtd *qtd) | |
63 | { | |
64 | dma_pool_free (ehci->qtd_pool, qtd, qtd->qtd_dma); | |
65 | } | |
66 | ||
67 | ||
c83e1a9f | 68 | static void qh_destroy(struct ehci_hcd *ehci, struct ehci_qh *qh) |
1da177e4 | 69 | { |
1da177e4 LT |
70 | /* clean qtds first, and know this is not linked */ |
71 | if (!list_empty (&qh->qtd_list) || qh->qh_next.ptr) { | |
72 | ehci_dbg (ehci, "unused qh not empty!\n"); | |
73 | BUG (); | |
74 | } | |
75 | if (qh->dummy) | |
76 | ehci_qtd_free (ehci, qh->dummy); | |
3807e26d AD |
77 | dma_pool_free(ehci->qh_pool, qh->hw, qh->qh_dma); |
78 | kfree(qh); | |
1da177e4 LT |
79 | } |
80 | ||
55016f10 | 81 | static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags) |
1da177e4 LT |
82 | { |
83 | struct ehci_qh *qh; | |
84 | dma_addr_t dma; | |
85 | ||
3807e26d | 86 | qh = kzalloc(sizeof *qh, GFP_ATOMIC); |
1da177e4 | 87 | if (!qh) |
3807e26d AD |
88 | goto done; |
89 | qh->hw = (struct ehci_qh_hw *) | |
90 | dma_pool_alloc(ehci->qh_pool, flags, &dma); | |
91 | if (!qh->hw) | |
92 | goto fail; | |
93 | memset(qh->hw, 0, sizeof *qh->hw); | |
1da177e4 LT |
94 | qh->qh_dma = dma; |
95 | // INIT_LIST_HEAD (&qh->qh_list); | |
96 | INIT_LIST_HEAD (&qh->qtd_list); | |
9118f9eb | 97 | INIT_LIST_HEAD(&qh->unlink_node); |
1da177e4 LT |
98 | |
99 | /* dummy td enables safe urb queuing */ | |
100 | qh->dummy = ehci_qtd_alloc (ehci, flags); | |
101 | if (qh->dummy == NULL) { | |
102 | ehci_dbg (ehci, "no dummy td\n"); | |
3807e26d | 103 | goto fail1; |
1da177e4 | 104 | } |
3807e26d | 105 | done: |
1da177e4 | 106 | return qh; |
3807e26d AD |
107 | fail1: |
108 | dma_pool_free(ehci->qh_pool, qh->hw, qh->qh_dma); | |
109 | fail: | |
110 | kfree(qh); | |
111 | return NULL; | |
1da177e4 LT |
112 | } |
113 | ||
1da177e4 LT |
114 | /*-------------------------------------------------------------------------*/ |
115 | ||
53bd6a60 | 116 | /* The queue heads and transfer descriptors are managed from pools tied |
1da177e4 LT |
117 | * to each of the "per device" structures. |
118 | * This is the initialisation and cleanup code. | |
119 | */ | |
120 | ||
121 | static void ehci_mem_cleanup (struct ehci_hcd *ehci) | |
122 | { | |
123 | if (ehci->async) | |
c83e1a9f | 124 | qh_destroy(ehci, ehci->async); |
1da177e4 LT |
125 | ehci->async = NULL; |
126 | ||
3d091a6f | 127 | if (ehci->dummy) |
c83e1a9f | 128 | qh_destroy(ehci, ehci->dummy); |
3d091a6f AX |
129 | ehci->dummy = NULL; |
130 | ||
1da177e4 | 131 | /* DMA consistent memory and pools */ |
a7a19d7a | 132 | dma_pool_destroy(ehci->qtd_pool); |
1da177e4 | 133 | ehci->qtd_pool = NULL; |
a7a19d7a ME |
134 | dma_pool_destroy(ehci->qh_pool); |
135 | ehci->qh_pool = NULL; | |
136 | dma_pool_destroy(ehci->itd_pool); | |
1da177e4 | 137 | ehci->itd_pool = NULL; |
a7a19d7a | 138 | dma_pool_destroy(ehci->sitd_pool); |
1da177e4 LT |
139 | ehci->sitd_pool = NULL; |
140 | ||
141 | if (ehci->periodic) | |
8b373ffc | 142 | dma_free_coherent(ehci_to_hcd(ehci)->self.sysdev, |
1da177e4 LT |
143 | ehci->periodic_size * sizeof (u32), |
144 | ehci->periodic, ehci->periodic_dma); | |
145 | ehci->periodic = NULL; | |
146 | ||
147 | /* shadow periodic table */ | |
1bc3c9e1 | 148 | kfree(ehci->pshadow); |
1da177e4 LT |
149 | ehci->pshadow = NULL; |
150 | } | |
151 | ||
152 | /* remember to add cleanup code (above) if you add anything here */ | |
55016f10 | 153 | static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags) |
1da177e4 LT |
154 | { |
155 | int i; | |
156 | ||
157 | /* QTDs for control/bulk/intr transfers */ | |
53bd6a60 | 158 | ehci->qtd_pool = dma_pool_create ("ehci_qtd", |
8b373ffc | 159 | ehci_to_hcd(ehci)->self.sysdev, |
1da177e4 LT |
160 | sizeof (struct ehci_qtd), |
161 | 32 /* byte alignment (for hw parts) */, | |
162 | 4096 /* can't cross 4K */); | |
163 | if (!ehci->qtd_pool) { | |
164 | goto fail; | |
165 | } | |
166 | ||
167 | /* QHs for control/bulk/intr transfers */ | |
53bd6a60 | 168 | ehci->qh_pool = dma_pool_create ("ehci_qh", |
8b373ffc | 169 | ehci_to_hcd(ehci)->self.sysdev, |
3807e26d | 170 | sizeof(struct ehci_qh_hw), |
1da177e4 LT |
171 | 32 /* byte alignment (for hw parts) */, |
172 | 4096 /* can't cross 4K */); | |
173 | if (!ehci->qh_pool) { | |
174 | goto fail; | |
175 | } | |
176 | ehci->async = ehci_qh_alloc (ehci, flags); | |
177 | if (!ehci->async) { | |
178 | goto fail; | |
179 | } | |
180 | ||
181 | /* ITD for high speed ISO transfers */ | |
53bd6a60 | 182 | ehci->itd_pool = dma_pool_create ("ehci_itd", |
8b373ffc | 183 | ehci_to_hcd(ehci)->self.sysdev, |
1da177e4 LT |
184 | sizeof (struct ehci_itd), |
185 | 32 /* byte alignment (for hw parts) */, | |
186 | 4096 /* can't cross 4K */); | |
187 | if (!ehci->itd_pool) { | |
188 | goto fail; | |
189 | } | |
190 | ||
191 | /* SITD for full/low speed split ISO transfers */ | |
53bd6a60 | 192 | ehci->sitd_pool = dma_pool_create ("ehci_sitd", |
8b373ffc | 193 | ehci_to_hcd(ehci)->self.sysdev, |
1da177e4 LT |
194 | sizeof (struct ehci_sitd), |
195 | 32 /* byte alignment (for hw parts) */, | |
196 | 4096 /* can't cross 4K */); | |
197 | if (!ehci->sitd_pool) { | |
198 | goto fail; | |
199 | } | |
200 | ||
201 | /* Hardware periodic table */ | |
202 | ehci->periodic = (__le32 *) | |
8b373ffc | 203 | dma_alloc_coherent(ehci_to_hcd(ehci)->self.sysdev, |
1da177e4 | 204 | ehci->periodic_size * sizeof(__le32), |
47c6ae7c | 205 | &ehci->periodic_dma, flags); |
1da177e4 LT |
206 | if (ehci->periodic == NULL) { |
207 | goto fail; | |
208 | } | |
3d091a6f AX |
209 | |
210 | if (ehci->use_dummy_qh) { | |
211 | struct ehci_qh_hw *hw; | |
212 | ehci->dummy = ehci_qh_alloc(ehci, flags); | |
213 | if (!ehci->dummy) | |
214 | goto fail; | |
215 | ||
216 | hw = ehci->dummy->hw; | |
217 | hw->hw_next = EHCI_LIST_END(ehci); | |
218 | hw->hw_qtd_next = EHCI_LIST_END(ehci); | |
219 | hw->hw_alt_next = EHCI_LIST_END(ehci); | |
3d091a6f AX |
220 | ehci->dummy->hw = hw; |
221 | ||
222 | for (i = 0; i < ehci->periodic_size; i++) | |
4a71f242 AS |
223 | ehci->periodic[i] = cpu_to_hc32(ehci, |
224 | ehci->dummy->qh_dma); | |
3d091a6f AX |
225 | } else { |
226 | for (i = 0; i < ehci->periodic_size; i++) | |
227 | ehci->periodic[i] = EHCI_LIST_END(ehci); | |
228 | } | |
1da177e4 LT |
229 | |
230 | /* software shadow of hardware table */ | |
80b6ca48 ES |
231 | ehci->pshadow = kcalloc(ehci->periodic_size, sizeof(void *), flags); |
232 | if (ehci->pshadow != NULL) | |
233 | return 0; | |
1da177e4 LT |
234 | |
235 | fail: | |
236 | ehci_dbg (ehci, "couldn't init memory\n"); | |
237 | ehci_mem_cleanup (ehci); | |
238 | return -ENOMEM; | |
239 | } |