int sda_slot_power_on(sda_slot_t *slot) { int rv; uint32_t ocr; sda_slot_enter(slot); /* * Get the voltage supplied by the host. Note that we expect * hosts will include a range of 2.7-3.7 in their supported * voltage ranges. The spec does not allow for hosts that * cannot supply a voltage in this range, yet. */ if ((rv = sda_getprop(slot, SDA_PROP_OCR, &ocr)) != 0) { sda_slot_err(slot, "Failed to get host OCR (%d)", rv); goto done; } if ((ocr & OCR_HI_MASK) == 0) { sda_slot_err(slot, "Host does not support standard voltages."); rv = ENOTSUP; goto done; } /* * We prefer 3.3V, 3.0V, and failing that, just use the * maximum that the host supports. 3.3V is preferable, * because it is the typical common voltage that just about * everything supports. Otherwise we just pick the highest * supported voltage. This facilitates initial power up. */ if (ocr & OCR_32_33V) { slot->s_cur_ocr = OCR_32_33V; } else if (ocr & OCR_29_30V) { slot->s_cur_ocr = OCR_29_30V; } else { slot->s_cur_ocr = (1U << (ddi_fls(ocr) - 1)); } /* * Turn on the power. */ if ((rv = sda_setprop(slot, SDA_PROP_OCR, slot->s_cur_ocr)) != 0) { sda_slot_err(slot, "Failed to set OCR %x (%d)", slot->s_cur_ocr, rv); goto done; } sda_slot_exit(slot); /* * Wait 250 msec (per spec) for power ramp to complete. */ delay(drv_usectohz(250000)); return (0); done: sda_slot_exit(slot); return (rv); }
void sda_slot_handle_detect(sda_slot_t *slot) { uint32_t inserted; sda_slot_enter(slot); slot->s_stamp = ddi_get_time(); slot->s_intransit = 1; slot->s_flags = 0; slot->s_rca = 0; slot->s_ready = B_FALSE; sda_getprop(slot, SDA_PROP_INSERTED, &inserted); slot->s_inserted = (inserted != 0); if (slot->s_inserted && !slot->s_failed) { /* * We need to initialize the card, so we only support * hipri commands for now. */ slot->s_init = B_TRUE; sda_slot_exit(slot); /* * Card insertion occurred. We have to run this on * another task, to avoid deadlock as the task may * need to dispatch commands. */ (void) ddi_taskq_dispatch(slot->s_hp_tq, sda_slot_insert, slot, DDI_SLEEP); } else { /* * Nuke in-flight commands. */ sda_slot_abort(slot, SDA_ENODEV); /* * Restart the slot (incl. power cycle). This gets the * slot to a known good state. */ sda_slot_reset(slot); slot->s_intransit = 0; sda_slot_exit(slot); bd_state_change(slot->s_bdh); } sda_slot_wakeup(slot); }
void sda_slot_attach(sda_slot_t *slot) { sda_host_t *h = slot->s_hostp; char name[16]; uint32_t cap; /* * We have two taskqs. The first taskq is used for * card initialization. * * The second is used for the main processing loop. * * The reason for a separate taskq is that initialization * needs to acquire locks which may be held by the slot * thread, or by device driver context... use of the separate * taskq breaks the deadlock. Additionally, the * initialization task may need to sleep quite a while during * card initialization. */ sda_slot_enter(slot); (void) snprintf(name, sizeof (name), "slot_%d_hp_tq", slot->s_slot_num); slot->s_hp_tq = ddi_taskq_create(h->h_dip, name, 1, TASKQ_DEFAULTPRI, 0); if (slot->s_hp_tq == NULL) { /* Generally, this failure should never occur */ sda_slot_err(slot, "Unable to create hotplug slot taskq"); sda_slot_exit(slot); return; } /* create the main processing thread */ (void) snprintf(name, sizeof (name), "slot_%d_main_tq", slot->s_slot_num); slot->s_main_tq = ddi_taskq_create(h->h_dip, name, 1, TASKQ_DEFAULTPRI, 0); if (slot->s_main_tq == NULL) { /* Generally, this failure should never occur */ sda_slot_err(slot, "Unable to create main slot taskq"); sda_slot_exit(slot); return; } (void) ddi_taskq_dispatch(slot->s_main_tq, sda_slot_thread, slot, DDI_SLEEP); /* * Determine slot capabilities. */ slot->s_caps = 0; if ((sda_getprop(slot, SDA_PROP_CAP_NOPIO, &cap) == 0) && (cap != 0)) { slot->s_caps |= SLOT_CAP_NOPIO; } if ((sda_getprop(slot, SDA_PROP_CAP_4BITS, &cap) == 0) && (cap != 0)) { slot->s_caps |= SLOT_CAP_4BITS; } if ((sda_getprop(slot, SDA_PROP_CAP_HISPEED, &cap) == 0) && (cap != 0)) { slot->s_caps |= SLOT_CAP_HISPEED; } /* make sure that the host is started up */ if (slot->s_ops.so_reset(slot->s_prv) != 0) { sda_slot_fault(slot, SDA_FAULT_RESET); } sda_slot_exit(slot); }