Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

sdio: split up common and function CIS parsing

Add a more clean separation between global, common CIS information
and the function specific one as we need the common information in
places where no specific function is specified.

Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

+205 -26
+3
drivers/mmc/core/bus.c
··· 19 19 20 20 #include "sysfs.h" 21 21 #include "core.h" 22 + #include "sdio_cis.h" 22 23 #include "bus.h" 23 24 24 25 #define dev_to_mmc_card(d) container_of(d, struct mmc_card, dev) ··· 181 180 static void mmc_release_card(struct device *dev) 182 181 { 183 182 struct mmc_card *card = dev_to_mmc_card(dev); 183 + 184 + sdio_free_common_cis(card); 184 185 185 186 kfree(card); 186 187 }
+8 -1
drivers/mmc/core/sdio.c
··· 66 66 if (ret) 67 67 goto fail; 68 68 69 - ret = sdio_read_cis(func); 69 + ret = sdio_read_func_cis(func); 70 70 if (ret) 71 71 goto fail; 72 72 ··· 283 283 * Read the common registers. 284 284 */ 285 285 err = sdio_read_cccr(card); 286 + if (err) 287 + goto remove; 288 + 289 + /* 290 + * Read the common CIS tuples. 291 + */ 292 + err = sdio_read_common_cis(card); 286 293 if (err) 287 294 goto remove; 288 295
+1 -1
drivers/mmc/core/sdio_bus.c
··· 95 95 { 96 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 100 kfree(func); 101 101 }
+176 -22
drivers/mmc/core/sdio_cis.c
··· 16 16 #include <linux/kernel.h> 17 17 18 18 #include <linux/mmc/host.h> 19 + #include <linux/mmc/card.h> 19 20 #include <linux/mmc/sdio.h> 20 21 #include <linux/mmc/sdio_func.h> 21 22 22 23 #include "sdio_cis.h" 23 24 #include "sdio_ops.h" 24 25 25 - static int cistpl_manfid(struct sdio_func *func, 26 - const unsigned char *buf, 27 - unsigned size) 26 + static int cistpl_manfid(struct mmc_card *card, struct sdio_func *func, 27 + const unsigned char *buf, unsigned size) 28 28 { 29 + unsigned int vendor, device; 30 + 29 31 /* TPLMID_MANF */ 30 - func->vendor = buf[0] | (buf[1] << 8); 32 + vendor = buf[0] | (buf[1] << 8); 31 33 32 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 + } 34 44 35 45 return 0; 36 46 } 37 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); 83 + 84 + return 0; 85 + } 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 115 struct cis_tpl { 39 116 unsigned char code; 40 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 121 static const struct cis_tpl cis_tpl_list[] = { 45 122 { 0x15, 3, /* cistpl_vers_1 */ }, 46 123 { 0x20, 4, cistpl_manfid }, 47 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 130 int ret; 54 131 struct sdio_func_tuple *this, **prev; 55 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 139 for (i = 0; i < 3; i++) { 58 - unsigned char x; 59 - ret = mmc_io_rw_direct(func->card, 0, 0, 60 - func->num * 0x100 + SDIO_FBR_CIS + i, 0, &x); 140 + unsigned char x, fn; 141 + 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 149 if (ret) 62 150 return ret; 63 151 ptr |= x << (i * 8); 64 152 } 65 153 66 - /* find the list tail */ 67 - for (prev = &func->tuples; *prev; prev = &(*prev)->next); 154 + if (func) 155 + prev = &func->tuples; 156 + else 157 + prev = &card->tuples; 158 + 159 + BUG_ON(*prev); 68 160 69 161 do { 70 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 165 if (ret) 74 166 break; 75 167 ··· 169 77 if (tpl_code == 0xff) 170 78 break; 171 79 172 - ret = mmc_io_rw_direct(func->card, 0, 0, ptr++, 0, &tpl_link); 80 + ret = mmc_io_rw_direct(card, 0, 0, ptr++, 0, &tpl_link); 173 81 if (ret) 174 82 break; 175 83 ··· 178 86 return -ENOMEM; 179 87 180 88 for (i = 0; i < tpl_link; i++) { 181 - ret = mmc_io_rw_direct(func->card, 0, 0, 89 + ret = mmc_io_rw_direct(card, 0, 0, 182 90 ptr + i, 0, &this->data[i]); 183 91 if (ret) 184 92 break; ··· 200 108 prev = &this->next; 201 109 printk(KERN_DEBUG 202 110 "%s: queuing CIS tuple 0x%02x length %u\n", 203 - sdio_func_id(func), tpl_code, tpl_link); 111 + mmc_hostname(card->host), tpl_code, tpl_link); 204 112 } else { 205 113 const struct cis_tpl *tpl = cis_tpl_list + i; 206 114 if (tpl_link < tpl->min_size) { 207 115 printk(KERN_ERR 208 116 "%s: bad CIS tuple 0x%02x (length = %u, expected >= %u)\n", 209 - sdio_func_id(func), tpl_code, tpl_link, tpl->min_size); 117 + mmc_hostname(card->host), 118 + tpl_code, tpl_link, tpl->min_size); 210 119 ret = -EINVAL; 211 - } else if (tpl->parse) 212 - ret = tpl->parse(func, this->data, tpl_link); 120 + } else if (tpl->parse) { 121 + ret = tpl->parse(card, func, 122 + this->data, tpl_link); 123 + } 213 124 kfree(this); 214 125 } 215 126 216 127 ptr += tpl_link; 217 128 } while (!ret); 218 129 130 + /* 131 + * Link in all unknown tuples found in the common CIS so that 132 + * drivers don't have to go digging in two places. 133 + */ 134 + if (func) 135 + *prev = card->tuples; 136 + 219 137 return ret; 220 138 } 221 139 222 - void sdio_free_cis(struct sdio_func *func) 140 + int sdio_read_common_cis(struct mmc_card *card) 141 + { 142 + return sdio_read_cis(card, NULL); 143 + } 144 + 145 + void sdio_free_common_cis(struct mmc_card *card) 223 146 { 224 147 struct sdio_func_tuple *tuple, *victim; 225 148 226 - tuple = func->tuples; 149 + tuple = card->tuples; 227 150 228 151 while (tuple) { 229 152 victim = tuple; ··· 246 139 kfree(victim); 247 140 } 248 141 142 + card->tuples = NULL; 143 + } 144 + 145 + int sdio_read_func_cis(struct sdio_func *func) 146 + { 147 + int ret; 148 + 149 + ret = sdio_read_cis(func->card, func); 150 + if (ret) 151 + return ret; 152 + 153 + /* 154 + * Since we've linked to tuples in the card structure, 155 + * we must make sure we have a reference to it. 156 + */ 157 + get_device(&func->card->dev); 158 + 159 + /* 160 + * Vendor/device id is optional for function CIS, so 161 + * copy it from the card structure as needed. 162 + */ 163 + if (func->vendor == 0) { 164 + func->vendor = func->card->cis.vendor; 165 + func->device = func->card->cis.device; 166 + } 167 + 168 + return 0; 169 + } 170 + 171 + void sdio_free_func_cis(struct sdio_func *func) 172 + { 173 + struct sdio_func_tuple *tuple, *victim; 174 + 175 + tuple = func->tuples; 176 + 177 + while (tuple && tuple != func->card->tuples) { 178 + victim = tuple; 179 + tuple = tuple->next; 180 + kfree(victim); 181 + } 182 + 249 183 func->tuples = NULL; 184 + 185 + /* 186 + * We have now removed the link to the tuples in the 187 + * card structure, so remove the reference. 188 + */ 189 + put_device(&func->card->dev); 250 190 } 251 191
+5 -2
drivers/mmc/core/sdio_cis.h
··· 14 14 #ifndef _MMC_SDIO_CIS_H 15 15 #define _MMC_SDIO_CIS_H 16 16 17 - int sdio_read_cis(struct sdio_func *func); 18 - void sdio_free_cis(struct sdio_func *func); 17 + int sdio_read_common_cis(struct mmc_card *card); 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 23 #endif
+10
include/linux/mmc/card.h
··· 65 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 75 struct mmc_host; 69 76 struct sdio_func; 77 + struct sdio_func_tuple; 70 78 71 79 #define SDIO_MAX_FUNCS 7 72 80 ··· 106 98 107 99 unsigned int sdio_funcs; /* number of SDIO functions */ 108 100 struct sdio_cccr cccr; /* common card info */ 101 + struct sdio_cis cis; /* common tuple info */ 109 102 struct sdio_func *sdio_func[SDIO_MAX_FUNCS]; /* SDIO functions (devices) */ 103 + struct sdio_func_tuple *tuples; /* unknown common tuples */ 110 104 }; 111 105 112 106 #define mmc_card_mmc(c) ((c)->type == MMC_TYPE_MMC)
+2
include/linux/mmc/sdio_func.h
··· 36 36 unsigned short vendor; /* vendor id */ 37 37 unsigned short device; /* device id */ 38 38 39 + unsigned short blksize; /* maximum block size */ 40 + 39 41 unsigned int state; /* function state */ 40 42 #define SDIO_STATE_PRESENT (1<<0) /* present in sysfs */ 41 43