Ejemplo n.º 1
0
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);
}
Ejemplo n.º 2
0
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);
}
Ejemplo n.º 3
0
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);
}