433 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * linux/drivers/mmc/core/sdio_cis.c4 *5 * Author: Nicolas Pitre6 * Created: June 11, 20077 * Copyright: MontaVista Software Inc.8 *9 * Copyright 2007 Pierre Ossman10 */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 25static 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 in39 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(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(string, 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 83static 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 105static const unsigned char speed_val[16] =106 { 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 };107static const unsigned int speed_unit[8] =108 { 10000, 100000, 1000000, 10000000, 0, 0, 0, 0 };109 110 111typedef int (tpl_parse_t)(struct mmc_card *, struct sdio_func *,112 const unsigned char *, unsigned);113 114struct cis_tpl {115 unsigned char code;116 unsigned char min_size;117 tpl_parse_t *parse;118};119 120static 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 else138 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 155static 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 172static 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 spec184 * 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 else204 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 depending213 * on the TPLFID_FUNCTION value of the previous CISTPL_FUNCID as on SDIO214 * TPLFID_FUNCTION is always hardcoded to 0x0C.215 */216static 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 222static 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, "CISTPL_FUNCE",229 cis_tpl_funce_list,230 ARRAY_SIZE(cis_tpl_funce_list),231 buf[0], buf, size);232}233 234/* Known TPL_CODEs table for CIS tuples */235static 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 243static 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) as251 * well as a function's CIS * since SDIO_CCCR_CIS and SDIO_FBR_CIS252 * 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 else260 fn = 0;261 262 ret = mmc_io_rw_direct(card, 0, 0,263 SDIO_FBR_BASE(fn) + SDIO_FBR_CIS + i, 0, &x);264 if (ret)265 return ret;266 ptr |= x << (i * 8);267 }268 269 if (func)270 prev = &func->tuples;271 else272 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, 0, 0, ptr++, 0, &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, 0, 0, ptr++, 0, &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(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, 0, 0,308 ptr + i, 0, &this->data[i]);309 if (ret)310 break;311 }312 if (ret) {313 kfree(this);314 break;315 }316 317 /* Try to parse the CIS tuple */318 ret = cis_tpl_parse(card, func, "CIS",319 cis_tpl_list, ARRAY_SIZE(cis_tpl_list),320 tpl_code, this->data, 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 for340 * vendors, so don't warn about them341 */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 else348 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 was359 * successfully parsed by the SDIO core or if it is360 * not going to be queued for a driver.361 */362 kfree(this);363 }364 365 ptr += tpl_link;366 } while (!ret);367 368 /*369 * Link in all unknown tuples found in the common CIS so that370 * drivers don't have to go digging in two places.371 */372 if (func)373 *prev = card->tuples;374 375 return ret;376}377 378int sdio_read_common_cis(struct mmc_card *card)379{380 return sdio_read_cis(card, NULL);381}382 383void 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(victim);393 }394 395 card->tuples = NULL;396}397 398int sdio_read_func_cis(struct sdio_func *func)399{400 int ret;401 402 ret = sdio_read_cis(func->card, func);403 if (ret)404 return ret;405 406 /*407 * Vendor/device id is optional for function CIS, so408 * 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 418void 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(victim);428 }429 430 func->tuples = NULL;431}432 433