1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * linux/drivers/mmc/core/sdio_cis.c |
4 | * |
5 | * Author: Nicolas Pitre |
6 | * Created: June 11, 2007 |
7 | * Copyright: MontaVista Software Inc. |
8 | * |
9 | * Copyright 2007 Pierre Ossman |
10 | */ |
11 | |
12 | #include <linux/kernel.h> |
13 | #include <linux/slab.h> |
14 | |
15 | #include <linux/mmc/host.h> |
16 | #include <linux/mmc/card.h> |
17 | #include <linux/mmc/sdio.h> |
18 | #include <linux/mmc/sdio_func.h> |
19 | |
20 | #include "sdio_cis.h" |
21 | #include "sdio_ops.h" |
22 | |
23 | #define SDIO_READ_CIS_TIMEOUT_MS (10 * 1000) /* 10s */ |
24 | |
25 | static int cistpl_vers_1(struct mmc_card *card, struct sdio_func *func, |
26 | const unsigned char *buf, unsigned size) |
27 | { |
28 | u8 major_rev, minor_rev; |
29 | unsigned i, nr_strings; |
30 | char **buffer, *string; |
31 | |
32 | if (size < 2) |
33 | return 0; |
34 | |
35 | major_rev = buf[0]; |
36 | minor_rev = buf[1]; |
37 | |
38 | /* Find all null-terminated (including zero length) strings in |
39 | the TPLLV1_INFO field. Trailing garbage is ignored. */ |
40 | buf += 2; |
41 | size -= 2; |
42 | |
43 | nr_strings = 0; |
44 | for (i = 0; i < size; i++) { |
45 | if (buf[i] == 0xff) |
46 | break; |
47 | if (buf[i] == 0) |
48 | nr_strings++; |
49 | } |
50 | if (nr_strings == 0) |
51 | return 0; |
52 | |
53 | size = i; |
54 | |
55 | buffer = kzalloc(size: sizeof(char*) * nr_strings + size, GFP_KERNEL); |
56 | if (!buffer) |
57 | return -ENOMEM; |
58 | |
59 | string = (char*)(buffer + nr_strings); |
60 | |
61 | for (i = 0; i < nr_strings; i++) { |
62 | buffer[i] = string; |
63 | strcpy(p: string, q: buf); |
64 | string += strlen(string) + 1; |
65 | buf += strlen(buf) + 1; |
66 | } |
67 | |
68 | if (func) { |
69 | func->major_rev = major_rev; |
70 | func->minor_rev = minor_rev; |
71 | func->num_info = nr_strings; |
72 | func->info = (const char**)buffer; |
73 | } else { |
74 | card->major_rev = major_rev; |
75 | card->minor_rev = minor_rev; |
76 | card->num_info = nr_strings; |
77 | card->info = (const char**)buffer; |
78 | } |
79 | |
80 | return 0; |
81 | } |
82 | |
83 | static int cistpl_manfid(struct mmc_card *card, struct sdio_func *func, |
84 | const unsigned char *buf, unsigned size) |
85 | { |
86 | unsigned int vendor, device; |
87 | |
88 | /* TPLMID_MANF */ |
89 | vendor = buf[0] | (buf[1] << 8); |
90 | |
91 | /* TPLMID_CARD */ |
92 | device = buf[2] | (buf[3] << 8); |
93 | |
94 | if (func) { |
95 | func->vendor = vendor; |
96 | func->device = device; |
97 | } else { |
98 | card->cis.vendor = vendor; |
99 | card->cis.device = device; |
100 | } |
101 | |
102 | return 0; |
103 | } |
104 | |
105 | static const unsigned char speed_val[16] = |
106 | { 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 }; |
107 | static const unsigned int speed_unit[8] = |
108 | { 10000, 100000, 1000000, 10000000, 0, 0, 0, 0 }; |
109 | |
110 | |
111 | typedef int (tpl_parse_t)(struct mmc_card *, struct sdio_func *, |
112 | const unsigned char *, unsigned); |
113 | |
114 | struct cis_tpl { |
115 | unsigned char code; |
116 | unsigned char min_size; |
117 | tpl_parse_t *parse; |
118 | }; |
119 | |
120 | static int cis_tpl_parse(struct mmc_card *card, struct sdio_func *func, |
121 | const char *tpl_descr, |
122 | const struct cis_tpl *tpl, int tpl_count, |
123 | unsigned char code, |
124 | const unsigned char *buf, unsigned size) |
125 | { |
126 | int i, ret; |
127 | |
128 | /* look for a matching code in the table */ |
129 | for (i = 0; i < tpl_count; i++, tpl++) { |
130 | if (tpl->code == code) |
131 | break; |
132 | } |
133 | if (i < tpl_count) { |
134 | if (size >= tpl->min_size) { |
135 | if (tpl->parse) |
136 | ret = tpl->parse(card, func, buf, size); |
137 | else |
138 | ret = -EILSEQ; /* known tuple, not parsed */ |
139 | } else { |
140 | /* invalid tuple */ |
141 | ret = -EINVAL; |
142 | } |
143 | if (ret && ret != -EILSEQ && ret != -ENOENT) { |
144 | pr_err("%s: bad %s tuple 0x%02x (%u bytes)\n" , |
145 | mmc_hostname(card->host), tpl_descr, code, size); |
146 | } |
147 | } else { |
148 | /* unknown tuple */ |
149 | ret = -ENOENT; |
150 | } |
151 | |
152 | return ret; |
153 | } |
154 | |
155 | static int cistpl_funce_common(struct mmc_card *card, struct sdio_func *func, |
156 | const unsigned char *buf, unsigned size) |
157 | { |
158 | /* Only valid for the common CIS (function 0) */ |
159 | if (func) |
160 | return -EINVAL; |
161 | |
162 | /* TPLFE_FN0_BLK_SIZE */ |
163 | card->cis.blksize = buf[1] | (buf[2] << 8); |
164 | |
165 | /* TPLFE_MAX_TRAN_SPEED */ |
166 | card->cis.max_dtr = speed_val[(buf[3] >> 3) & 15] * |
167 | speed_unit[buf[3] & 7]; |
168 | |
169 | return 0; |
170 | } |
171 | |
172 | static int cistpl_funce_func(struct mmc_card *card, struct sdio_func *func, |
173 | const unsigned char *buf, unsigned size) |
174 | { |
175 | unsigned vsn; |
176 | unsigned min_size; |
177 | |
178 | /* Only valid for the individual function's CIS (1-7) */ |
179 | if (!func) |
180 | return -EINVAL; |
181 | |
182 | /* |
183 | * This tuple has a different length depending on the SDIO spec |
184 | * version. |
185 | */ |
186 | vsn = func->card->cccr.sdio_vsn; |
187 | min_size = (vsn == SDIO_SDIO_REV_1_00) ? 28 : 42; |
188 | |
189 | if (size == 28 && vsn == SDIO_SDIO_REV_1_10) { |
190 | pr_warn("%s: card has broken SDIO 1.1 CIS, forcing SDIO 1.0\n" , |
191 | mmc_hostname(card->host)); |
192 | vsn = SDIO_SDIO_REV_1_00; |
193 | } else if (size < min_size) { |
194 | return -EINVAL; |
195 | } |
196 | |
197 | /* TPLFE_MAX_BLK_SIZE */ |
198 | func->max_blksize = buf[12] | (buf[13] << 8); |
199 | |
200 | /* TPLFE_ENABLE_TIMEOUT_VAL, present in ver 1.1 and above */ |
201 | if (vsn > SDIO_SDIO_REV_1_00) |
202 | func->enable_timeout = (buf[28] | (buf[29] << 8)) * 10; |
203 | else |
204 | func->enable_timeout = jiffies_to_msecs(HZ); |
205 | |
206 | return 0; |
207 | } |
208 | |
209 | /* |
210 | * Known TPLFE_TYPEs table for CISTPL_FUNCE tuples. |
211 | * |
212 | * Note that, unlike PCMCIA, CISTPL_FUNCE tuples are not parsed depending |
213 | * on the TPLFID_FUNCTION value of the previous CISTPL_FUNCID as on SDIO |
214 | * TPLFID_FUNCTION is always hardcoded to 0x0C. |
215 | */ |
216 | static const struct cis_tpl cis_tpl_funce_list[] = { |
217 | { 0x00, 4, cistpl_funce_common }, |
218 | { 0x01, 0, cistpl_funce_func }, |
219 | { 0x04, 1+1+6, /* CISTPL_FUNCE_LAN_NODE_ID */ }, |
220 | }; |
221 | |
222 | static int cistpl_funce(struct mmc_card *card, struct sdio_func *func, |
223 | const unsigned char *buf, unsigned size) |
224 | { |
225 | if (size < 1) |
226 | return -EINVAL; |
227 | |
228 | return cis_tpl_parse(card, func, tpl_descr: "CISTPL_FUNCE" , |
229 | tpl: cis_tpl_funce_list, |
230 | ARRAY_SIZE(cis_tpl_funce_list), |
231 | code: buf[0], buf, size); |
232 | } |
233 | |
234 | /* Known TPL_CODEs table for CIS tuples */ |
235 | static const struct cis_tpl cis_tpl_list[] = { |
236 | { 0x15, 3, cistpl_vers_1 }, |
237 | { 0x20, 4, cistpl_manfid }, |
238 | { 0x21, 2, /* cistpl_funcid */ }, |
239 | { 0x22, 0, cistpl_funce }, |
240 | { 0x91, 2, /* cistpl_sdio_std */ }, |
241 | }; |
242 | |
243 | static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func) |
244 | { |
245 | int ret; |
246 | struct sdio_func_tuple *this, **prev; |
247 | unsigned i, ptr = 0; |
248 | |
249 | /* |
250 | * Note that this works for the common CIS (function number 0) as |
251 | * well as a function's CIS * since SDIO_CCCR_CIS and SDIO_FBR_CIS |
252 | * have the same offset. |
253 | */ |
254 | for (i = 0; i < 3; i++) { |
255 | unsigned char x, fn; |
256 | |
257 | if (func) |
258 | fn = func->num; |
259 | else |
260 | fn = 0; |
261 | |
262 | ret = mmc_io_rw_direct(card, write: 0, fn: 0, |
263 | SDIO_FBR_BASE(fn) + SDIO_FBR_CIS + i, in: 0, out: &x); |
264 | if (ret) |
265 | return ret; |
266 | ptr |= x << (i * 8); |
267 | } |
268 | |
269 | if (func) |
270 | prev = &func->tuples; |
271 | else |
272 | prev = &card->tuples; |
273 | |
274 | if (*prev) |
275 | return -EINVAL; |
276 | |
277 | do { |
278 | unsigned char tpl_code, tpl_link; |
279 | unsigned long timeout = jiffies + |
280 | msecs_to_jiffies(SDIO_READ_CIS_TIMEOUT_MS); |
281 | |
282 | ret = mmc_io_rw_direct(card, write: 0, fn: 0, addr: ptr++, in: 0, out: &tpl_code); |
283 | if (ret) |
284 | break; |
285 | |
286 | /* 0xff means we're done */ |
287 | if (tpl_code == 0xff) |
288 | break; |
289 | |
290 | /* null entries have no link field or data */ |
291 | if (tpl_code == 0x00) |
292 | continue; |
293 | |
294 | ret = mmc_io_rw_direct(card, write: 0, fn: 0, addr: ptr++, in: 0, out: &tpl_link); |
295 | if (ret) |
296 | break; |
297 | |
298 | /* a size of 0xff also means we're done */ |
299 | if (tpl_link == 0xff) |
300 | break; |
301 | |
302 | this = kmalloc(size: sizeof(*this) + tpl_link, GFP_KERNEL); |
303 | if (!this) |
304 | return -ENOMEM; |
305 | |
306 | for (i = 0; i < tpl_link; i++) { |
307 | ret = mmc_io_rw_direct(card, write: 0, fn: 0, |
308 | addr: ptr + i, in: 0, out: &this->data[i]); |
309 | if (ret) |
310 | break; |
311 | } |
312 | if (ret) { |
313 | kfree(objp: this); |
314 | break; |
315 | } |
316 | |
317 | /* Try to parse the CIS tuple */ |
318 | ret = cis_tpl_parse(card, func, tpl_descr: "CIS" , |
319 | tpl: cis_tpl_list, ARRAY_SIZE(cis_tpl_list), |
320 | code: tpl_code, buf: this->data, size: tpl_link); |
321 | if (ret == -EILSEQ || ret == -ENOENT) { |
322 | /* |
323 | * The tuple is unknown or known but not parsed. |
324 | * Queue the tuple for the function driver. |
325 | */ |
326 | this->next = NULL; |
327 | this->code = tpl_code; |
328 | this->size = tpl_link; |
329 | *prev = this; |
330 | prev = &this->next; |
331 | |
332 | if (ret == -ENOENT) { |
333 | |
334 | if (time_after(jiffies, timeout)) |
335 | break; |
336 | |
337 | #define FMT(type) "%s: queuing " type " CIS tuple 0x%02x [%*ph] (%u bytes)\n" |
338 | /* |
339 | * Tuples in this range are reserved for |
340 | * vendors, so don't warn about them |
341 | */ |
342 | if (tpl_code >= 0x80 && tpl_code <= 0x8f) |
343 | pr_debug_ratelimited(FMT("vendor" ), |
344 | mmc_hostname(card->host), |
345 | tpl_code, tpl_link, this->data, |
346 | tpl_link); |
347 | else |
348 | pr_warn_ratelimited(FMT("unknown" ), |
349 | mmc_hostname(card->host), |
350 | tpl_code, tpl_link, this->data, |
351 | tpl_link); |
352 | } |
353 | |
354 | /* keep on analyzing tuples */ |
355 | ret = 0; |
356 | } else { |
357 | /* |
358 | * We don't need the tuple anymore if it was |
359 | * successfully parsed by the SDIO core or if it is |
360 | * not going to be queued for a driver. |
361 | */ |
362 | kfree(objp: this); |
363 | } |
364 | |
365 | ptr += tpl_link; |
366 | } while (!ret); |
367 | |
368 | /* |
369 | * Link in all unknown tuples found in the common CIS so that |
370 | * drivers don't have to go digging in two places. |
371 | */ |
372 | if (func) |
373 | *prev = card->tuples; |
374 | |
375 | return ret; |
376 | } |
377 | |
378 | int sdio_read_common_cis(struct mmc_card *card) |
379 | { |
380 | return sdio_read_cis(card, NULL); |
381 | } |
382 | |
383 | void sdio_free_common_cis(struct mmc_card *card) |
384 | { |
385 | struct sdio_func_tuple *tuple, *victim; |
386 | |
387 | tuple = card->tuples; |
388 | |
389 | while (tuple) { |
390 | victim = tuple; |
391 | tuple = tuple->next; |
392 | kfree(objp: victim); |
393 | } |
394 | |
395 | card->tuples = NULL; |
396 | } |
397 | |
398 | int sdio_read_func_cis(struct sdio_func *func) |
399 | { |
400 | int ret; |
401 | |
402 | ret = sdio_read_cis(card: func->card, func); |
403 | if (ret) |
404 | return ret; |
405 | |
406 | /* |
407 | * Vendor/device id is optional for function CIS, so |
408 | * copy it from the card structure as needed. |
409 | */ |
410 | if (func->vendor == 0) { |
411 | func->vendor = func->card->cis.vendor; |
412 | func->device = func->card->cis.device; |
413 | } |
414 | |
415 | return 0; |
416 | } |
417 | |
418 | void sdio_free_func_cis(struct sdio_func *func) |
419 | { |
420 | struct sdio_func_tuple *tuple, *victim; |
421 | |
422 | tuple = func->tuples; |
423 | |
424 | while (tuple && tuple != func->card->tuples) { |
425 | victim = tuple; |
426 | tuple = tuple->next; |
427 | kfree(objp: victim); |
428 | } |
429 | |
430 | func->tuples = NULL; |
431 | } |
432 | |
433 | |