diff options
| -rw-r--r-- | drivers/mmc/core/bus.c | 3 | ||||
| -rw-r--r-- | drivers/mmc/core/sdio.c | 9 | ||||
| -rw-r--r-- | drivers/mmc/core/sdio_bus.c | 2 | ||||
| -rw-r--r-- | drivers/mmc/core/sdio_cis.c | 198 | ||||
| -rw-r--r-- | drivers/mmc/core/sdio_cis.h | 7 | ||||
| -rw-r--r-- | include/linux/mmc/card.h | 10 | ||||
| -rw-r--r-- | include/linux/mmc/sdio_func.h | 2 |
7 files changed, 205 insertions, 26 deletions
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 87a6070522f..9be11ec05d8 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | 19 | ||
| 20 | #include "sysfs.h" | 20 | #include "sysfs.h" |
| 21 | #include "core.h" | 21 | #include "core.h" |
| 22 | #include "sdio_cis.h" | ||
| 22 | #include "bus.h" | 23 | #include "bus.h" |
| 23 | 24 | ||
| 24 | #define dev_to_mmc_card(d) container_of(d, struct mmc_card, dev) | 25 | #define dev_to_mmc_card(d) container_of(d, struct mmc_card, dev) |
| @@ -181,6 +182,8 @@ static void mmc_release_card(struct device *dev) | |||
| 181 | { | 182 | { |
| 182 | struct mmc_card *card = dev_to_mmc_card(dev); | 183 | struct mmc_card *card = dev_to_mmc_card(dev); |
| 183 | 184 | ||
| 185 | sdio_free_common_cis(card); | ||
| 186 | |||
| 184 | kfree(card); | 187 | kfree(card); |
| 185 | } | 188 | } |
| 186 | 189 | ||
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index c5baf76146b..1fb36a34046 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c | |||
| @@ -66,7 +66,7 @@ static int sdio_init_func(struct mmc_card *card, unsigned int fn) | |||
| 66 | if (ret) | 66 | if (ret) |
| 67 | goto fail; | 67 | goto fail; |
| 68 | 68 | ||
| 69 | ret = sdio_read_cis(func); | 69 | ret = sdio_read_func_cis(func); |
| 70 | if (ret) | 70 | if (ret) |
| 71 | goto fail; | 71 | goto fail; |
| 72 | 72 | ||
| @@ -287,6 +287,13 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr) | |||
| 287 | goto remove; | 287 | goto remove; |
| 288 | 288 | ||
| 289 | /* | 289 | /* |
| 290 | * Read the common CIS tuples. | ||
| 291 | */ | ||
| 292 | err = sdio_read_common_cis(card); | ||
| 293 | if (err) | ||
| 294 | goto remove; | ||
| 295 | |||
| 296 | /* | ||
| 290 | * Initialize (but don't add) all present functions. | 297 | * Initialize (but don't add) all present functions. |
| 291 | */ | 298 | */ |
| 292 | for (i = 0;i < funcs;i++) { | 299 | for (i = 0;i < funcs;i++) { |
diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 78e0381f55a..461fe4837a9 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c | |||
| @@ -95,7 +95,7 @@ static void sdio_release_func(struct device *dev) | |||
| 95 | { | 95 | { |
| 96 | struct sdio_func *func = dev_to_sdio_func(dev); | 96 | struct sdio_func *func = dev_to_sdio_func(dev); |
| 97 | 97 | ||
| 98 | sdio_free_cis(func); | 98 | sdio_free_func_cis(func); |
| 99 | 99 | ||
| 100 | kfree(func); | 100 | kfree(func); |
| 101 | } | 101 | } |
diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c index b6c7342572c..ec806a1229b 100644 --- a/drivers/mmc/core/sdio_cis.c +++ b/drivers/mmc/core/sdio_cis.c | |||
| @@ -16,60 +16,152 @@ | |||
| 16 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
| 17 | 17 | ||
| 18 | #include <linux/mmc/host.h> | 18 | #include <linux/mmc/host.h> |
| 19 | #include <linux/mmc/card.h> | ||
| 19 | #include <linux/mmc/sdio.h> | 20 | #include <linux/mmc/sdio.h> |
| 20 | #include <linux/mmc/sdio_func.h> | 21 | #include <linux/mmc/sdio_func.h> |
| 21 | 22 | ||
| 22 | #include "sdio_cis.h" | 23 | #include "sdio_cis.h" |
| 23 | #include "sdio_ops.h" | 24 | #include "sdio_ops.h" |
| 24 | 25 | ||
| 25 | static int cistpl_manfid(struct sdio_func *func, | 26 | static int cistpl_manfid(struct mmc_card *card, struct sdio_func *func, |
| 26 | const unsigned char *buf, | 27 | const unsigned char *buf, unsigned size) |
| 27 | unsigned size) | ||
| 28 | { | 28 | { |
| 29 | unsigned int vendor, device; | ||
| 30 | |||
| 29 | /* TPLMID_MANF */ | 31 | /* TPLMID_MANF */ |
| 30 | func->vendor = buf[0] | (buf[1] << 8); | 32 | vendor = buf[0] | (buf[1] << 8); |
| 31 | 33 | ||
| 32 | /* TPLMID_CARD */ | 34 | /* TPLMID_CARD */ |
| 33 | func->device = buf[2] | (buf[3] << 8); | 35 | device = buf[2] | (buf[3] << 8); |
| 36 | |||
| 37 | if (func) { | ||
| 38 | func->vendor = vendor; | ||
| 39 | func->device = device; | ||
| 40 | } else { | ||
| 41 | card->cis.vendor = vendor; | ||
| 42 | card->cis.device = device; | ||
| 43 | } | ||
| 44 | |||
| 45 | return 0; | ||
| 46 | } | ||
| 47 | |||
| 48 | static const unsigned char speed_val[16] = | ||
| 49 | { 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 }; | ||
| 50 | static const unsigned int speed_unit[8] = | ||
| 51 | { 10000, 100000, 1000000, 10000000, 0, 0, 0, 0 }; | ||
| 52 | |||
| 53 | static int cistpl_funce_common(struct mmc_card *card, | ||
| 54 | const unsigned char *buf, unsigned size) | ||
| 55 | { | ||
| 56 | if (size < 0x04 || buf[0] != 0) | ||
| 57 | return -EINVAL; | ||
| 58 | |||
| 59 | /* TPLFE_FN0_BLK_SIZE */ | ||
| 60 | card->cis.blksize = buf[1] | (buf[2] << 8); | ||
| 61 | |||
| 62 | /* TPLFE_MAX_TRAN_SPEED */ | ||
| 63 | card->cis.max_dtr = speed_val[(buf[3] >> 3) & 15] * | ||
| 64 | speed_unit[buf[3] & 7]; | ||
| 65 | |||
| 66 | return 0; | ||
| 67 | } | ||
| 68 | |||
| 69 | static int cistpl_funce_func(struct sdio_func *func, | ||
| 70 | const unsigned char *buf, unsigned size) | ||
| 71 | { | ||
| 72 | unsigned vsn; | ||
| 73 | unsigned min_size; | ||
| 74 | |||
| 75 | vsn = func->card->cccr.sdio_vsn; | ||
| 76 | min_size = (vsn == SDIO_SDIO_REV_1_00) ? 28 : 42; | ||
| 77 | |||
| 78 | if (size < min_size || buf[0] != 1) | ||
| 79 | return -EINVAL; | ||
| 80 | |||
| 81 | /* TPLFE_MAX_BLK_SIZE */ | ||
| 82 | func->blksize = buf[12] | (buf[13] << 8); | ||
| 34 | 83 | ||
| 35 | return 0; | 84 | return 0; |
| 36 | } | 85 | } |
| 37 | 86 | ||
| 87 | static int cistpl_funce(struct mmc_card *card, struct sdio_func *func, | ||
| 88 | const unsigned char *buf, unsigned size) | ||
| 89 | { | ||
| 90 | int ret; | ||
| 91 | |||
| 92 | /* | ||
| 93 | * There should be two versions of the CISTPL_FUNCE tuple, | ||
| 94 | * one for the common CIS (function 0) and a version used by | ||
| 95 | * the individual function's CIS (1-7). Yet, the later has a | ||
| 96 | * different length depending on the SDIO spec version. | ||
| 97 | */ | ||
| 98 | if (func) | ||
| 99 | ret = cistpl_funce_func(func, buf, size); | ||
| 100 | else | ||
| 101 | ret = cistpl_funce_common(card, buf, size); | ||
| 102 | |||
| 103 | if (ret) { | ||
| 104 | printk(KERN_ERR "%s: bad CISTPL_FUNCE size %u " | ||
| 105 | "type %u\n", mmc_hostname(card->host), size, buf[0]); | ||
| 106 | return ret; | ||
| 107 | } | ||
| 108 | |||
| 109 | return 0; | ||
| 110 | } | ||
| 111 | |||
| 112 | typedef int (tpl_parse_t)(struct mmc_card *, struct sdio_func *, | ||
| 113 | const unsigned char *, unsigned); | ||
| 114 | |||
| 38 | struct cis_tpl { | 115 | struct cis_tpl { |
| 39 | unsigned char code; | 116 | unsigned char code; |
| 40 | unsigned char min_size; | 117 | unsigned char min_size; |
| 41 | int (*parse)(struct sdio_func *, const unsigned char *buf, unsigned size); | 118 | tpl_parse_t *parse; |
| 42 | }; | 119 | }; |
| 43 | 120 | ||
| 44 | static const struct cis_tpl cis_tpl_list[] = { | 121 | static const struct cis_tpl cis_tpl_list[] = { |
| 45 | { 0x15, 3, /* cistpl_vers_1 */ }, | 122 | { 0x15, 3, /* cistpl_vers_1 */ }, |
| 46 | { 0x20, 4, cistpl_manfid }, | 123 | { 0x20, 4, cistpl_manfid }, |
| 47 | { 0x21, 2, /* cistpl_funcid */ }, | 124 | { 0x21, 2, /* cistpl_funcid */ }, |
| 48 | { 0x22, 0, /* cistpl_funce */ }, | 125 | { 0x22, 0, cistpl_funce }, |
| 49 | }; | 126 | }; |
| 50 | 127 | ||
| 51 | int sdio_read_cis(struct sdio_func *func) | 128 | static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func) |
| 52 | { | 129 | { |
| 53 | int ret; | 130 | int ret; |
| 54 | struct sdio_func_tuple *this, **prev; | 131 | struct sdio_func_tuple *this, **prev; |
| 55 | unsigned i, ptr = 0; | 132 | unsigned i, ptr = 0; |
| 56 | 133 | ||
| 134 | /* | ||
| 135 | * Note that this works for the common CIS (function number 0) as | ||
| 136 | * well as a function's CIS * since SDIO_CCCR_CIS and SDIO_FBR_CIS | ||
| 137 | * have the same offset. | ||
| 138 | */ | ||
| 57 | for (i = 0; i < 3; i++) { | 139 | for (i = 0; i < 3; i++) { |
| 58 | unsigned char x; | 140 | unsigned char x, fn; |
| 59 | ret = mmc_io_rw_direct(func->card, 0, 0, | 141 | |
| 60 | func->num * 0x100 + SDIO_FBR_CIS + i, 0, &x); | 142 | if (func) |
| 143 | fn = func->num; | ||
| 144 | else | ||
| 145 | fn = 0; | ||
| 146 | |||
| 147 | ret = mmc_io_rw_direct(card, 0, 0, | ||
| 148 | fn * 0x100 + SDIO_FBR_CIS + i, 0, &x); | ||
| 61 | if (ret) | 149 | if (ret) |
| 62 | return ret; | 150 | return ret; |
| 63 | ptr |= x << (i * 8); | 151 | ptr |= x << (i * 8); |
| 64 | } | 152 | } |
| 65 | 153 | ||
| 66 | /* find the list tail */ | 154 | if (func) |
| 67 | for (prev = &func->tuples; *prev; prev = &(*prev)->next); | 155 | prev = &func->tuples; |
| 156 | else | ||
| 157 | prev = &card->tuples; | ||
| 158 | |||
| 159 | BUG_ON(*prev); | ||
| 68 | 160 | ||
| 69 | do { | 161 | do { |
| 70 | unsigned char tpl_code, tpl_link; | 162 | unsigned char tpl_code, tpl_link; |
| 71 | 163 | ||
| 72 | ret = mmc_io_rw_direct(func->card, 0, 0, ptr++, 0, &tpl_code); | 164 | ret = mmc_io_rw_direct(card, 0, 0, ptr++, 0, &tpl_code); |
| 73 | if (ret) | 165 | if (ret) |
| 74 | break; | 166 | break; |
| 75 | 167 | ||
| @@ -77,7 +169,7 @@ int sdio_read_cis(struct sdio_func *func) | |||
| 77 | if (tpl_code == 0xff) | 169 | if (tpl_code == 0xff) |
| 78 | break; | 170 | break; |
| 79 | 171 | ||
| 80 | ret = mmc_io_rw_direct(func->card, 0, 0, ptr++, 0, &tpl_link); | 172 | ret = mmc_io_rw_direct(card, 0, 0, ptr++, 0, &tpl_link); |
| 81 | if (ret) | 173 | if (ret) |
| 82 | break; | 174 | break; |
| 83 | 175 | ||
| @@ -86,7 +178,7 @@ int sdio_read_cis(struct sdio_func *func) | |||
| 86 | return -ENOMEM; | 178 | return -ENOMEM; |
| 87 | 179 | ||
| 88 | for (i = 0; i < tpl_link; i++) { | 180 | for (i = 0; i < tpl_link; i++) { |
| 89 | ret = mmc_io_rw_direct(func->card, 0, 0, | 181 | ret = mmc_io_rw_direct(card, 0, 0, |
| 90 | ptr + i, 0, &this->data[i]); | 182 | ptr + i, 0, &this->data[i]); |
| 91 | if (ret) | 183 | if (ret) |
| 92 | break; | 184 | break; |
| @@ -108,30 +200,45 @@ int sdio_read_cis(struct sdio_func *func) | |||
| 108 | prev = &this->next; | 200 | prev = &this->next; |
| 109 | printk(KERN_DEBUG | 201 | printk(KERN_DEBUG |
| 110 | "%s: queuing CIS tuple 0x%02x length %u\n", | 202 | "%s: queuing CIS tuple 0x%02x length %u\n", |
| 111 | sdio_func_id(func), tpl_code, tpl_link); | 203 | mmc_hostname(card->host), tpl_code, tpl_link); |
| 112 | } else { | 204 | } else { |
| 113 | const struct cis_tpl *tpl = cis_tpl_list + i; | 205 | const struct cis_tpl *tpl = cis_tpl_list + i; |
| 114 | if (tpl_link < tpl->min_size) { | 206 | if (tpl_link < tpl->min_size) { |
| 115 | printk(KERN_ERR | 207 | printk(KERN_ERR |
| 116 | "%s: bad CIS tuple 0x%02x (length = %u, expected >= %u)\n", | 208 | "%s: bad CIS tuple 0x%02x (length = %u, expected >= %u)\n", |
| 117 | sdio_func_id(func), tpl_code, tpl_link, tpl->min_size); | 209 | mmc_hostname(card->host), |
| 210 | tpl_code, tpl_link, tpl->min_size); | ||
| 118 | ret = -EINVAL; | 211 | ret = -EINVAL; |
| 119 | } else if (tpl->parse) | 212 | } else if (tpl->parse) { |
| 120 | ret = tpl->parse(func, this->data, tpl_link); | 213 | ret = tpl->parse(card, func, |
| 214 | this->data, tpl_link); | ||
| 215 | } | ||
| 121 | kfree(this); | 216 | kfree(this); |
| 122 | } | 217 | } |
| 123 | 218 | ||
| 124 | ptr += tpl_link; | 219 | ptr += tpl_link; |
| 125 | } while (!ret); | 220 | } while (!ret); |
| 126 | 221 | ||
| 222 | /* | ||
| 223 | * Link in all unknown tuples found in the common CIS so that | ||
| 224 | * drivers don't have to go digging in two places. | ||
| 225 | */ | ||
| 226 | if (func) | ||
| 227 | *prev = card->tuples; | ||
| 228 | |||
| 127 | return ret; | 229 | return ret; |
| 128 | } | 230 | } |
| 129 | 231 | ||
| 130 | void sdio_free_cis(struct sdio_func *func) | 232 | int sdio_read_common_cis(struct mmc_card *card) |
| 233 | { | ||
| 234 | return sdio_read_cis(card, NULL); | ||
| 235 | } | ||
| 236 | |||
| 237 | void sdio_free_common_cis(struct mmc_card *card) | ||
| 131 | { | 238 | { |
| 132 | struct sdio_func_tuple *tuple, *victim; | 239 | struct sdio_func_tuple *tuple, *victim; |
| 133 | 240 | ||
| 134 | tuple = func->tuples; | 241 | tuple = card->tuples; |
| 135 | 242 | ||
| 136 | while (tuple) { | 243 | while (tuple) { |
| 137 | victim = tuple; | 244 | victim = tuple; |
| @@ -139,6 +246,53 @@ void sdio_free_cis(struct sdio_func *func) | |||
| 139 | kfree(victim); | 246 | kfree(victim); |
| 140 | } | 247 | } |
| 141 | 248 | ||
| 249 | card->tuples = NULL; | ||
| 250 | } | ||
| 251 | |||
| 252 | int sdio_read_func_cis(struct sdio_func *func) | ||
| 253 | { | ||
| 254 | int ret; | ||
| 255 | |||
| 256 | ret = sdio_read_cis(func->card, func); | ||
| 257 | if (ret) | ||
| 258 | return ret; | ||
| 259 | |||
| 260 | /* | ||
| 261 | * Since we've linked to tuples in the card structure, | ||
| 262 | * we must make sure we have a reference to it. | ||
| 263 | */ | ||
| 264 | get_device(&func->card->dev); | ||
| 265 | |||
| 266 | /* | ||
| 267 | * Vendor/device id is optional for function CIS, so | ||
| 268 | * copy it from the card structure as needed. | ||
| 269 | */ | ||
| 270 | if (func->vendor == 0) { | ||
| 271 | func->vendor = func->card->cis.vendor; | ||
| 272 | func->device = func->card->cis.device; | ||
| 273 | } | ||
| 274 | |||
| 275 | return 0; | ||
| 276 | } | ||
| 277 | |||
| 278 | void sdio_free_func_cis(struct sdio_func *func) | ||
| 279 | { | ||
| 280 | struct sdio_func_tuple *tuple, *victim; | ||
| 281 | |||
| 282 | tuple = func->tuples; | ||
| 283 | |||
| 284 | while (tuple && tuple != func->card->tuples) { | ||
| 285 | victim = tuple; | ||
| 286 | tuple = tuple->next; | ||
| 287 | kfree(victim); | ||
| 288 | } | ||
| 289 | |||
| 142 | func->tuples = NULL; | 290 | func->tuples = NULL; |
| 291 | |||
| 292 | /* | ||
| 293 | * We have now removed the link to the tuples in the | ||
| 294 | * card structure, so remove the reference. | ||
| 295 | */ | ||
| 296 | put_device(&func->card->dev); | ||
| 143 | } | 297 | } |
| 144 | 298 | ||
diff --git a/drivers/mmc/core/sdio_cis.h b/drivers/mmc/core/sdio_cis.h index 863d3d51637..4d903c2e425 100644 --- a/drivers/mmc/core/sdio_cis.h +++ b/drivers/mmc/core/sdio_cis.h | |||
| @@ -14,7 +14,10 @@ | |||
| 14 | #ifndef _MMC_SDIO_CIS_H | 14 | #ifndef _MMC_SDIO_CIS_H |
| 15 | #define _MMC_SDIO_CIS_H | 15 | #define _MMC_SDIO_CIS_H |
| 16 | 16 | ||
| 17 | int sdio_read_cis(struct sdio_func *func); | 17 | int sdio_read_common_cis(struct mmc_card *card); |
| 18 | void sdio_free_cis(struct sdio_func *func); | 18 | void sdio_free_common_cis(struct mmc_card *card); |
| 19 | |||
| 20 | int sdio_read_func_cis(struct sdio_func *func); | ||
| 21 | void sdio_free_func_cis(struct sdio_func *func); | ||
| 19 | 22 | ||
| 20 | #endif | 23 | #endif |
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 520d9d29b3b..a444431e28b 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h | |||
| @@ -65,8 +65,16 @@ struct sdio_cccr { | |||
| 65 | high_speed:1; | 65 | high_speed:1; |
| 66 | }; | 66 | }; |
| 67 | 67 | ||
| 68 | struct sdio_cis { | ||
| 69 | unsigned short vendor; | ||
| 70 | unsigned short device; | ||
| 71 | unsigned short blksize; | ||
| 72 | unsigned int max_dtr; | ||
| 73 | }; | ||
| 74 | |||
| 68 | struct mmc_host; | 75 | struct mmc_host; |
| 69 | struct sdio_func; | 76 | struct sdio_func; |
| 77 | struct sdio_func_tuple; | ||
| 70 | 78 | ||
| 71 | #define SDIO_MAX_FUNCS 7 | 79 | #define SDIO_MAX_FUNCS 7 |
| 72 | 80 | ||
| @@ -98,7 +106,9 @@ struct mmc_card { | |||
| 98 | 106 | ||
| 99 | unsigned int sdio_funcs; /* number of SDIO functions */ | 107 | unsigned int sdio_funcs; /* number of SDIO functions */ |
| 100 | struct sdio_cccr cccr; /* common card info */ | 108 | struct sdio_cccr cccr; /* common card info */ |
| 109 | struct sdio_cis cis; /* common tuple info */ | ||
| 101 | struct sdio_func *sdio_func[SDIO_MAX_FUNCS]; /* SDIO functions (devices) */ | 110 | struct sdio_func *sdio_func[SDIO_MAX_FUNCS]; /* SDIO functions (devices) */ |
| 111 | struct sdio_func_tuple *tuples; /* unknown common tuples */ | ||
| 102 | }; | 112 | }; |
| 103 | 113 | ||
| 104 | #define mmc_card_mmc(c) ((c)->type == MMC_TYPE_MMC) | 114 | #define mmc_card_mmc(c) ((c)->type == MMC_TYPE_MMC) |
diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h index 269067663c8..2f2b3c85441 100644 --- a/include/linux/mmc/sdio_func.h +++ b/include/linux/mmc/sdio_func.h | |||
| @@ -36,6 +36,8 @@ struct sdio_func { | |||
| 36 | unsigned short vendor; /* vendor id */ | 36 | unsigned short vendor; /* vendor id */ |
| 37 | unsigned short device; /* device id */ | 37 | unsigned short device; /* device id */ |
| 38 | 38 | ||
| 39 | unsigned short blksize; /* maximum block size */ | ||
| 40 | |||
| 39 | unsigned int state; /* function state */ | 41 | unsigned int state; /* function state */ |
| 40 | #define SDIO_STATE_PRESENT (1<<0) /* present in sysfs */ | 42 | #define SDIO_STATE_PRESENT (1<<0) /* present in sysfs */ |
| 41 | 43 | ||
