diff options
Diffstat (limited to 'drivers/mmc/core/sdio_cis.c')
| -rw-r--r-- | drivers/mmc/core/sdio_cis.c | 68 |
1 files changed, 44 insertions, 24 deletions
diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c index 8e94e555b788..afaa6cab1adc 100644 --- a/drivers/mmc/core/sdio_cis.c +++ b/drivers/mmc/core/sdio_cis.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * linux/drivers/mmc/core/sdio_cis.c * @@ -6,11 +7,6 @@ * Copyright: MontaVista Software Inc. * * Copyright 2007 Pierre Ossman - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. */ #include <linux/kernel.h> @@ -24,12 +20,21 @@ #include "sdio_cis.h" #include "sdio_ops.h" +#define SDIO_READ_CIS_TIMEOUT_MS (10 * 1000) /* 10s */ + static int cistpl_vers_1(struct mmc_card *card, struct sdio_func *func, const unsigned char *buf, unsigned size) { + u8 major_rev, minor_rev; unsigned i, nr_strings; char **buffer, *string; + if (size < 2) + return 0; + + major_rev = buf[0]; + minor_rev = buf[1]; + /* Find all null-terminated (including zero length) strings in the TPLLV1_INFO field. Trailing garbage is ignored. */ buf += 2; @@ -61,9 +66,13 @@ static int cistpl_vers_1(struct mmc_card *card, struct sdio_func *func, } if (func) { + func->major_rev = major_rev; + func->minor_rev = minor_rev; func->num_info = nr_strings; func->info = (const char**)buffer; } else { + card->major_rev = major_rev; + card->minor_rev = minor_rev; card->num_info = nr_strings; card->info = (const char**)buffer; } @@ -177,8 +186,13 @@ static int cistpl_funce_func(struct mmc_card *card, struct sdio_func *func, vsn = func->card->cccr.sdio_vsn; min_size = (vsn == SDIO_SDIO_REV_1_00) ? 28 : 42; - if (size < min_size) + if (size == 28 && vsn == SDIO_SDIO_REV_1_10) { + pr_warn("%s: card has broken SDIO 1.1 CIS, forcing SDIO 1.0\n", + mmc_hostname(card->host)); + vsn = SDIO_SDIO_REV_1_00; + } else if (size < min_size) { return -EINVAL; + } /* TPLFE_MAX_BLK_SIZE */ func->max_blksize = buf[12] | (buf[13] << 8); @@ -223,6 +237,7 @@ static const struct cis_tpl cis_tpl_list[] = { { 0x20, 4, cistpl_manfid }, { 0x21, 2, /* cistpl_funcid */ }, { 0x22, 0, cistpl_funce }, + { 0x91, 2, /* cistpl_sdio_std */ }, }; static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func) @@ -256,10 +271,13 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func) else prev = &card->tuples; - BUG_ON(*prev); + if (*prev) + return -EINVAL; do { unsigned char tpl_code, tpl_link; + unsigned long timeout = jiffies + + msecs_to_jiffies(SDIO_READ_CIS_TIMEOUT_MS); ret = mmc_io_rw_direct(card, 0, 0, ptr++, 0, &tpl_code); if (ret) @@ -312,11 +330,25 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func) prev = &this->next; if (ret == -ENOENT) { - /* warn about unknown tuples */ - pr_warn_ratelimited("%s: queuing unknown" - " CIS tuple 0x%02x (%u bytes)\n", - mmc_hostname(card->host), - tpl_code, tpl_link); + + if (time_after(jiffies, timeout)) + break; + +#define FMT(type) "%s: queuing " type " CIS tuple 0x%02x [%*ph] (%u bytes)\n" + /* + * Tuples in this range are reserved for + * vendors, so don't warn about them + */ + if (tpl_code >= 0x80 && tpl_code <= 0x8f) + pr_debug_ratelimited(FMT("vendor"), + mmc_hostname(card->host), + tpl_code, tpl_link, this->data, + tpl_link); + else + pr_warn_ratelimited(FMT("unknown"), + mmc_hostname(card->host), + tpl_code, tpl_link, this->data, + tpl_link); } /* keep on analyzing tuples */ @@ -372,12 +404,6 @@ int sdio_read_func_cis(struct sdio_func *func) return ret; /* - * Since we've linked to tuples in the card structure, - * we must make sure we have a reference to it. - */ - get_device(&func->card->dev); - - /* * Vendor/device id is optional for function CIS, so * copy it from the card structure as needed. */ @@ -402,11 +428,5 @@ void sdio_free_func_cis(struct sdio_func *func) } func->tuples = NULL; - - /* - * We have now removed the link to the tuples in the - * card structure, so remove the reference. - */ - put_device(&func->card->dev); } |
