aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/core/sdio_cis.c65
1 files changed, 49 insertions, 16 deletions
diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c
index 6636354b48ce..e1035c895808 100644
--- a/drivers/mmc/core/sdio_cis.c
+++ b/drivers/mmc/core/sdio_cis.c
@@ -98,6 +98,22 @@ static const unsigned char speed_val[16] =
98static const unsigned int speed_unit[8] = 98static const unsigned int speed_unit[8] =
99 { 10000, 100000, 1000000, 10000000, 0, 0, 0, 0 }; 99 { 10000, 100000, 1000000, 10000000, 0, 0, 0, 0 };
100 100
101/* FUNCE tuples with these types get passed to SDIO drivers */
102static const unsigned char funce_type_whitelist[] = {
103 4 /* CISTPL_FUNCE_LAN_NODE_ID used in Broadcom cards */
104};
105
106static int cistpl_funce_whitelisted(unsigned char type)
107{
108 int i;
109
110 for (i = 0; i < ARRAY_SIZE(funce_type_whitelist); i++) {
111 if (funce_type_whitelist[i] == type)
112 return 1;
113 }
114 return 0;
115}
116
101static int cistpl_funce_common(struct mmc_card *card, 117static int cistpl_funce_common(struct mmc_card *card,
102 const unsigned char *buf, unsigned size) 118 const unsigned char *buf, unsigned size)
103{ 119{
@@ -120,6 +136,10 @@ static int cistpl_funce_func(struct sdio_func *func,
120 unsigned vsn; 136 unsigned vsn;
121 unsigned min_size; 137 unsigned min_size;
122 138
139 /* let SDIO drivers take care of whitelisted FUNCE tuples */
140 if (cistpl_funce_whitelisted(buf[0]))
141 return -EILSEQ;
142
123 vsn = func->card->cccr.sdio_vsn; 143 vsn = func->card->cccr.sdio_vsn;
124 min_size = (vsn == SDIO_SDIO_REV_1_00) ? 28 : 42; 144 min_size = (vsn == SDIO_SDIO_REV_1_00) ? 28 : 42;
125 145
@@ -154,13 +174,12 @@ static int cistpl_funce(struct mmc_card *card, struct sdio_func *func,
154 else 174 else
155 ret = cistpl_funce_common(card, buf, size); 175 ret = cistpl_funce_common(card, buf, size);
156 176
157 if (ret) { 177 if (ret && ret != -EILSEQ) {
158 printk(KERN_ERR "%s: bad CISTPL_FUNCE size %u " 178 printk(KERN_ERR "%s: bad CISTPL_FUNCE size %u "
159 "type %u\n", mmc_hostname(card->host), size, buf[0]); 179 "type %u\n", mmc_hostname(card->host), size, buf[0]);
160 return ret;
161 } 180 }
162 181
163 return 0; 182 return ret;
164} 183}
165 184
166typedef int (tpl_parse_t)(struct mmc_card *, struct sdio_func *, 185typedef int (tpl_parse_t)(struct mmc_card *, struct sdio_func *,
@@ -253,21 +272,12 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func)
253 for (i = 0; i < ARRAY_SIZE(cis_tpl_list); i++) 272 for (i = 0; i < ARRAY_SIZE(cis_tpl_list); i++)
254 if (cis_tpl_list[i].code == tpl_code) 273 if (cis_tpl_list[i].code == tpl_code)
255 break; 274 break;
256 if (i >= ARRAY_SIZE(cis_tpl_list)) { 275 if (i < ARRAY_SIZE(cis_tpl_list)) {
257 /* this tuple is unknown to the core */
258 this->next = NULL;
259 this->code = tpl_code;
260 this->size = tpl_link;
261 *prev = this;
262 prev = &this->next;
263 printk(KERN_DEBUG
264 "%s: queuing CIS tuple 0x%02x length %u\n",
265 mmc_hostname(card->host), tpl_code, tpl_link);
266 } else {
267 const struct cis_tpl *tpl = cis_tpl_list + i; 276 const struct cis_tpl *tpl = cis_tpl_list + i;
268 if (tpl_link < tpl->min_size) { 277 if (tpl_link < tpl->min_size) {
269 printk(KERN_ERR 278 printk(KERN_ERR
270 "%s: bad CIS tuple 0x%02x (length = %u, expected >= %u)\n", 279 "%s: bad CIS tuple 0x%02x"
280 " (length = %u, expected >= %u)\n",
271 mmc_hostname(card->host), 281 mmc_hostname(card->host),
272 tpl_code, tpl_link, tpl->min_size); 282 tpl_code, tpl_link, tpl->min_size);
273 ret = -EINVAL; 283 ret = -EINVAL;
@@ -275,7 +285,30 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func)
275 ret = tpl->parse(card, func, 285 ret = tpl->parse(card, func,
276 this->data, tpl_link); 286 this->data, tpl_link);
277 } 287 }
278 kfree(this); 288 /*
289 * We don't need the tuple anymore if it was
290 * successfully parsed by the SDIO core or if it is
291 * not going to be parsed by SDIO drivers.
292 */
293 if (!ret || ret != -EILSEQ)
294 kfree(this);
295 } else {
296 /* unknown tuple */
297 ret = -EILSEQ;
298 }
299
300 if (ret == -EILSEQ) {
301 /* this tuple is unknown to the core or whitelisted */
302 this->next = NULL;
303 this->code = tpl_code;
304 this->size = tpl_link;
305 *prev = this;
306 prev = &this->next;
307 printk(KERN_DEBUG
308 "%s: queuing CIS tuple 0x%02x length %u\n",
309 mmc_hostname(card->host), tpl_code, tpl_link);
310 /* keep on analyzing tuples */
311 ret = 0;
279 } 312 }
280 313
281 ptr += tpl_link; 314 ptr += tpl_link;