1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * SD card common framework. This module provides most of the common 28 * functionality so that SecureDigital host adapters and client devices 29 * (such as the sdcard driver) can share common code. 30 * 31 * NB that this file contains a fair bit of non-DDI compliant code. 32 * But writing a nexus driver would be impossible to do with only DDI 33 * compliant interfaces. 34 */ 35 36 #include <sys/types.h> 37 #include <sys/kmem.h> 38 #include <sys/sysmacros.h> 39 #include <sys/ddi.h> 40 #include <sys/sunddi.h> 41 #include <sys/sunndi.h> 42 #include <sys/sdcard/sda_impl.h> 43 44 /* 45 * Types and Structures. 46 */ 47 48 typedef struct sda_cmd_impl { 49 struct sda_cmd c_public; 50 51 /* 52 * Implementation private stuff. 53 */ 54 sda_slot_t *c_slot; 55 kmutex_t c_lock; 56 kcondvar_t c_cv; 57 list_node_t c_list; 58 sda_err_t c_errno; 59 60 sda_index_t c_acmd; /* saved acmd */ 61 sda_rtype_t c_artype; /* saved rtype */ 62 uint32_t c_aarg; /* saved argument */ 63 64 void (*c_done)(struct sda_cmd *); 65 void *c_private; 66 } sda_cmd_impl_t; 67 68 #define c_index c_public.sc_index 69 #define c_argument c_public.sc_argument 70 #define c_rtype c_public.sc_rtype 71 #define c_response c_public.sc_response 72 #define c_blksz c_public.sc_blksz 73 #define c_nblks c_public.sc_nblks 74 #define c_resid c_public.sc_resid 75 #define c_flags c_public.sc_flags 76 #define c_ndmac c_public.sc_ndmac 77 #define c_dmacs c_public.sc_dmacs 78 #define c_kvaddr c_public.sc_kvaddr 79 80 /* 81 * Local Prototypes. 82 */ 83 84 static void sda_cmd_wait(sda_cmd_t *); 85 static int sda_cmd_ctor(void *, void *, int); 86 static void sda_cmd_dtor(void *, void *); 87 88 /* 89 * Static Variables. 90 */ 91 92 static kmem_cache_t *sda_cmd_cache; 93 94 /* 95 * Macros. 96 */ 97 98 #define CIP(cmdp) ((sda_cmd_impl_t *)(void *)cmdp) 99 100 /* 101 * Implementation. 102 */ 103 104 void 105 sda_cmd_init(void) 106 { 107 sda_cmd_cache = kmem_cache_create("sda_cmd_cache", 108 sizeof (struct sda_cmd_impl), 0, sda_cmd_ctor, sda_cmd_dtor, 109 NULL, NULL, NULL, 0); 110 } 111 112 void 113 sda_cmd_fini(void) 114 { 115 kmem_cache_destroy(sda_cmd_cache); 116 } 117 118 void 119 sda_cmd_list_init(list_t *list) 120 { 121 list_create(list, sizeof (struct sda_cmd_impl), 122 offsetof(struct sda_cmd_impl, c_list)); 123 } 124 125 void 126 sda_cmd_list_fini(list_t *list) 127 { 128 list_destroy(list); 129 } 130 131 /*ARGSUSED1*/ 132 int 133 sda_cmd_ctor(void *cbuf, void *arg, int kmflags) 134 { 135 sda_cmd_impl_t *c = cbuf; 136 137 mutex_init(&c->c_lock, NULL, MUTEX_DRIVER, NULL); 138 cv_init(&c->c_cv, NULL, CV_DRIVER, NULL); 139 return (0); 140 } 141 142 /*ARGSUSED1*/ 143 void 144 sda_cmd_dtor(void *cbuf, void *arg) 145 { 146 sda_cmd_impl_t *c = cbuf; 147 148 cv_destroy(&c->c_cv); 149 mutex_destroy(&c->c_lock); 150 } 151 152 void * 153 sda_cmd_data(sda_cmd_t *cmdp) 154 { 155 return (CIP(cmdp)->c_private); 156 } 157 158 sda_err_t 159 sda_cmd_errno(sda_cmd_t *cmdp) 160 { 161 return (CIP(cmdp)->c_errno); 162 } 163 164 void 165 sda_cmd_notify(sda_cmd_t *cmdp, uint16_t flags, sda_err_t errno) 166 { 167 sda_cmd_impl_t *c = CIP(cmdp); 168 169 /* 170 * Now we need to make sure that we wake anyone waiting on this 171 * command to complete, if it is complete. 172 */ 173 mutex_enter(&c->c_lock); 174 c->c_flags &= ~(flags); 175 /* 176 * Don't overwrite an earlier error. 177 */ 178 if (c->c_errno == SDA_EOK) { 179 c->c_errno = errno; 180 } 181 if ((c->c_flags & (SDA_CMDF_BUSY | SDA_CMDF_DAT)) == 0) { 182 183 if (c->c_done != NULL) { 184 mutex_exit(&c->c_lock); 185 c->c_done(cmdp); 186 } else { 187 cv_broadcast(&c->c_cv); 188 mutex_exit(&c->c_lock); 189 } 190 } else { 191 mutex_exit(&c->c_lock); 192 } 193 } 194 195 void 196 sda_cmd_wait(sda_cmd_t *cmdp) 197 { 198 sda_cmd_impl_t *c = CIP(cmdp); 199 200 mutex_enter(&c->c_lock); 201 while ((c->c_flags & (SDA_CMDF_BUSY | SDA_CMDF_DAT)) != 0) 202 cv_wait(&c->c_cv, &c->c_lock); 203 mutex_exit(&c->c_lock); 204 } 205 206 void 207 sda_cmd_submit(sda_slot_t *slot, sda_cmd_t *cmdp, void (*done)(sda_cmd_t *)) 208 { 209 sda_cmd_impl_t *c = CIP(cmdp); 210 sda_err_t errno = 0; 211 212 mutex_enter(&c->c_lock); 213 c->c_done = done; 214 c->c_flags |= SDA_CMDF_BUSY; 215 mutex_exit(&c->c_lock); 216 217 sda_slot_enter(slot); 218 219 /* checks for cases where the slot can't accept the command */ 220 if (slot->s_failed) { 221 errno = SDA_EFAULT; 222 } 223 if (!slot->s_inserted) { 224 errno = SDA_ENODEV; 225 } 226 if (errno != SDA_EOK) { 227 sda_slot_exit(slot); 228 /* fail it synchronously */ 229 sda_cmd_notify(cmdp, SDA_CMDF_DAT | SDA_CMDF_BUSY, errno); 230 return; 231 } 232 233 list_insert_tail(&slot->s_cmdlist, c); 234 sda_slot_exit(slot); 235 236 sda_slot_wakeup(slot); 237 } 238 239 void 240 sda_cmd_resubmit_acmd(sda_slot_t *slot, sda_cmd_t *cmdp) 241 { 242 sda_cmd_impl_t *c = CIP(cmdp); 243 244 ASSERT(sda_slot_owned(slot)); 245 246 c->c_index = c->c_acmd; 247 c->c_argument = c->c_aarg; 248 c->c_rtype = c->c_artype; 249 c->c_acmd = 0; 250 251 list_insert_head(&slot->s_cmdlist, c); 252 } 253 254 sda_cmd_t * 255 sda_cmd_alloc(sda_slot_t *slot, sda_index_t index, uint32_t argument, 256 sda_rtype_t rtype, void *data, int kmflag) 257 { 258 sda_cmd_impl_t *c; 259 260 c = kmem_cache_alloc(sda_cmd_cache, kmflag); 261 if (c == NULL) { 262 return (NULL); 263 } 264 c->c_index = index; 265 c->c_rtype = rtype; 266 c->c_argument = argument; 267 c->c_resid = 0; 268 c->c_nblks = 0; 269 c->c_blksz = 0; 270 271 c->c_kvaddr = 0; 272 c->c_ndmac = 0; 273 c->c_dmacs = NULL; 274 c->c_flags = 0; 275 276 c->c_slot = slot; 277 c->c_errno = SDA_EOK; 278 c->c_done = NULL; 279 c->c_private = data; 280 c->c_acmd = 0; 281 282 return (&(c->c_public)); 283 } 284 285 sda_cmd_t * 286 sda_cmd_alloc_acmd(sda_slot_t *slot, sda_index_t index, uint32_t argument, 287 sda_rtype_t rtype, void *data, int kmflag) 288 { 289 sda_cmd_impl_t *c; 290 291 c = kmem_cache_alloc(sda_cmd_cache, kmflag); 292 if (c == NULL) { 293 return (NULL); 294 } 295 c->c_index = CMD_APP_CMD; 296 c->c_argument = index == ACMD_SD_SEND_OCR ? 0 : slot->s_rca << 16; 297 c->c_rtype = R1; 298 c->c_acmd = index; 299 c->c_artype = rtype; 300 c->c_aarg = argument; 301 c->c_resid = 0; 302 c->c_nblks = 0; 303 c->c_blksz = 0; 304 305 c->c_kvaddr = 0; 306 c->c_ndmac = 0; 307 c->c_dmacs = NULL; 308 c->c_flags = 0; 309 310 c->c_slot = slot; 311 c->c_errno = SDA_EOK; 312 c->c_done = NULL; 313 c->c_private = data; 314 315 return (&(c->c_public)); 316 } 317 318 void 319 sda_cmd_free(sda_cmd_t *cmdp) 320 { 321 kmem_cache_free(sda_cmd_cache, cmdp); 322 } 323 324 sda_err_t 325 sda_cmd_exec(sda_slot_t *slot, sda_cmd_t *cmdp, uint32_t *resp) 326 { 327 int errno; 328 329 if ((cmdp->sc_rtype & Rb) || (cmdp->sc_nblks != 0)) { 330 cmdp->sc_flags |= SDA_CMDF_DAT; 331 } 332 sda_cmd_submit(slot, cmdp, NULL); 333 334 sda_cmd_wait(cmdp); 335 336 if (resp != NULL) { 337 switch (cmdp->sc_rtype) { 338 case R0: 339 break; 340 case R2: 341 resp[0] = cmdp->sc_response[0]; 342 resp[1] = cmdp->sc_response[1]; 343 resp[2] = cmdp->sc_response[2]; 344 resp[3] = cmdp->sc_response[3]; 345 break; 346 default: 347 resp[0] = cmdp->sc_response[0]; 348 break; 349 } 350 } 351 352 errno = CIP(cmdp)->c_errno; 353 354 return (errno); 355 } 356