Exemplo n.º 1
0
/*
 * pm_pc3_exit: 
 * Calling function needs to grab idle_state mutex.
 *
 * Execute pc3 exit for a node.
 * mic_ctx: The driver context of the node.
 */
int pm_pc3_exit(mic_ctx_t *mic_ctx)
{
	int err;
	int wait_cnt;

	WARN_ON(!mutex_is_locked(&mic_data.dd_pm.pm_idle_mutex));
	mic_send_pm_intr(mic_ctx);
	for (wait_cnt = 0; wait_cnt < PC3_EXIT_WAIT_COUNT; wait_cnt++) {
		if (check_card_state(mic_ctx, PM_IDLE_STATE_PC0))
			break;
		msleep(1);
	}


	if(wait_cnt >= PC3_EXIT_WAIT_COUNT) {
		PM_DEBUG("Syncronization with card failed."
			" Node is lost\n");
		err = -EFAULT;
		goto exit;
	}

	set_host_state(mic_ctx, PM_IDLE_STATE_PC0);
	mic_ctx->micpm_ctx.idle_state = PM_IDLE_STATE_PC0;
	PM_DEBUG("Node %d exited PC3\n", mic_get_scifnode_id(mic_ctx));

	return 0;
exit:
	return err;
}
Exemplo n.º 2
0
JNIEXPORT void JNICALL
Java_com_sun_netstorage_samqfs_mgmt_fs_Host_setClientState(JNIEnv *env,
	jclass cls /*ARGSUSED*/, jobject ctx, jstring fsName,
	jobjectArray host_strs, jint state) {

	jboolean isCopy;
	char *cstr = GET_STR(fsName, isCopy);

	PTRACE(1, "jni:Host_setAdvancedNetCfg() entry");
	if (-1 == set_host_state(CTX, cstr,
	    jarray2lst(env, host_strs, "java/lang/String", String2charr),
	    state)) {
		REL_STR(fsName, cstr, isCopy);
		ThrowEx(env);
		return;
	}

	REL_STR(fsName, cstr, isCopy);

	PTRACE(1, "jni:Host_setAdvancedNetCfg() done");
}
Exemplo n.º 3
0
/* do_idlestate_exit:
 *
 * Initiate idle state exits for nodes specified
 * by the bitmask.
 *
 * mic_ctx: The device context.
 * get_ref: Set to true if the entity that wants to wake
 * a node up also wantes to get a reference to the node.
 *
 * Returs 0 on success. Appropriate error on failure.
 *
 */
int do_idlestate_exit(mic_ctx_t *mic_ctx, bool get_ref) {
	int err = 0;
	uint32_t node_id = 0;
	mic_ctx_t *node_ctx;
	uint8_t *nodemask_buf;

	if(!mic_ctx)
		return -EINVAL;

	might_sleep();
	/* If the idle_state_mutex is already obtained by another thread
	 * try to wakeup the thread which MAY be waiting for REMOVE_NODE
	 * responses. This way, we give priority to idle state exits than
	 * idle state entries.
	 */
	if (!mutex_trylock(&mic_data.dd_pm.pm_idle_mutex)) {
		atomic_inc(&mic_data.dd_pm.wakeup_in_progress);
		wake_up(&ms_info.mi_disconn_wq);
		mutex_lock(&mic_data.dd_pm.pm_idle_mutex);
		atomic_dec(&mic_data.dd_pm.wakeup_in_progress);
	}

	nodemask_buf = (uint8_t *)kzalloc(mic_ctx->micpm_ctx.nodemask.len, GFP_KERNEL);
	if(!nodemask_buf) {
		PM_DEBUG("Error allocating nodemask buffer\n");
		mutex_unlock(&mic_data.dd_pm.pm_idle_mutex);
		err = ENOMEM;
		goto abort_node_wake;
	}

	if ((err = micscif_get_activeset(mic_get_scifnode_id(mic_ctx), nodemask_buf))) {
		PM_DEBUG("Node connect failed during Activation set calculation for node\n");
		mutex_unlock(&mic_data.dd_pm.pm_idle_mutex);
		err = -EINVAL;
		goto free_buf;
	}

	print_nodemaskbuf(nodemask_buf);

	for(node_id = 0; node_id <= ms_info.mi_maxid;  node_id++) {
		if (node_id == SCIF_HOST_NODE)
			continue;

		if (!get_nodemask_bit(nodemask_buf, node_id))
			continue;

		node_ctx = get_per_dev_ctx(node_id - 1);
		if (!node_ctx) {
			mutex_unlock(&mic_data.dd_pm.pm_idle_mutex);
			goto free_buf;
		}

		switch (node_ctx->micpm_ctx.idle_state) {
		case PM_IDLE_STATE_PC3:
		case PM_IDLE_STATE_PC3_READY:
			if ((err = pm_pc3_exit(node_ctx))) {
				PM_DEBUG("Wakeup of Node %d failed."
					"Node to be disconnected",node_id);
				set_nodemask_bit(nodemask_buf, node_id, 0);
				node_ctx->micpm_ctx.idle_state = PM_IDLE_STATE_LOST;
				/* Since node is lost, ref_cnt increment(decement) through the
				* pm_get(put)_reference interface is prevented by idle_state.
				* We still need to ensure the ref_cnt iself is reset
				* back to 0 so that pm_get(put)_reference will work after the
				* lost node interface recovers the node. */
				atomic_set(&node_ctx->micpm_ctx.pm_ref_cnt, 0);
			} else {
				if ((mic_ctx == node_ctx) && get_ref)
					if (atomic_cmpxchg(&mic_ctx->micpm_ctx.pm_ref_cnt, PM_NODE_IDLE, 1) !=
							PM_NODE_IDLE)
						atomic_inc(&mic_ctx->micpm_ctx.pm_ref_cnt);
			}
			break;
		case PM_IDLE_STATE_PC6:
			if ((err = pm_pc6_exit(node_ctx))) {
				PM_DEBUG("Wakeup of Node %d failed."
					"Node to be disconnected",node_id);
				set_nodemask_bit(nodemask_buf, node_id, 0);
				node_ctx->micpm_ctx.idle_state = PM_IDLE_STATE_LOST;
				/* Since node is lost, ref_cnt increment(decement) through the
				* pm_get(put)_reference interface is prevented by idle_state.
				* We still need to ensure the ref_cnt iself is reset
				* back to 0 so that pm_get(put)_reference will work after the
				* lost node interface recovers the node. */
				atomic_set(&node_ctx->micpm_ctx.pm_ref_cnt, 0);
			} else {
				if ((mic_ctx == node_ctx) && get_ref)
					if (atomic_cmpxchg(&mic_ctx->micpm_ctx.pm_ref_cnt, PM_NODE_IDLE, 1) !=
							PM_NODE_IDLE)
						atomic_inc(&mic_ctx->micpm_ctx.pm_ref_cnt);
			}
			break;
		case PM_IDLE_STATE_PC0:
			PM_DEBUG("Node %d is in state %d "
					"and already out of package state.\n",node_id,
					node_ctx->micpm_ctx.idle_state);
			if ((mic_ctx == node_ctx) && get_ref)
					if (atomic_cmpxchg(&mic_ctx->micpm_ctx.pm_ref_cnt, PM_NODE_IDLE, 1) !=
							PM_NODE_IDLE)
						atomic_inc(&mic_ctx->micpm_ctx.pm_ref_cnt);
			break;
		default:
			PM_DEBUG("Invalid idle state of node %d."
					" State = %d \n", node_id,
					node_ctx->micpm_ctx.idle_state);
			mutex_unlock(&mic_data.dd_pm.pm_idle_mutex);
			err = -ENODEV;
			goto free_buf;
		}
	}

	/* Idle state exit of nodes are complete.
	 * Set the register state now for those nodes
	 * that are successfully up.
	 */
	for(node_id = 0; node_id <= ms_info.mi_maxid;  node_id++) {
		if (node_id == SCIF_HOST_NODE)
			continue;

		if (!get_nodemask_bit(nodemask_buf, node_id))
			continue;

		node_ctx = get_per_dev_ctx(node_id - 1);
		if (!node_ctx) {
			PM_DEBUG("Failed to retrieve node context.");
			continue;
		}


		if (node_ctx->micpm_ctx.idle_state == PM_IDLE_STATE_PC0)
			set_host_state(node_ctx, PM_IDLE_STATE_PC0);
	}

	mutex_unlock(&mic_data.dd_pm.pm_idle_mutex);
free_buf:
	kfree(nodemask_buf);
abort_node_wake:
	return err;
}
Exemplo n.º 4
0
/*
 * do_idlestate_entry:
 *
 * Function to start the idle state entry transaction for a node. Puts a node
 * and all the nodes that are dependent on this node to idle state if
 * it is possible.
 *
 * mic_ctx: The device context of node that needs to be put in idle state
 * Returs 0 in success. Appropriate error code on failure
 */
int do_idlestate_entry(mic_ctx_t *mic_ctx)
{
	int err = 0;
	uint32_t node_id = 0;
	mic_ctx_t *node_ctx;
	uint8_t *nodemask_buf;

	if(!mic_ctx)
		return -EINVAL;

	mutex_lock(&mic_data.dd_pm.pm_idle_mutex);

	if ((err = setup_pm_dependency())) {
		PM_DEBUG("Failed to set up PM specific dependencies");
		goto unlock;
	}

	nodemask_buf = (uint8_t *)
		kzalloc(mic_ctx->micpm_ctx.nodemask.len, GFP_KERNEL);
	if(!nodemask_buf) {
		PM_DEBUG("Error allocating nodemask buffer\n");
		err = ENOMEM;
		goto dep_teardown;
	}

	err = micscif_get_deactiveset(mic_get_scifnode_id(mic_ctx),
		nodemask_buf, 1);
	if (err) {
		PM_DEBUG("Node disconnection failed "
			"during deactivation set calculation");
		goto free_buf;
	}

	print_nodemaskbuf(nodemask_buf);

	if ((err = micscif_disconnect_node(mic_get_scifnode_id(mic_ctx),
			nodemask_buf, DISCONN_TYPE_POWER_MGMT))) {
		PM_DEBUG("SCIF Node disconnect failed. err: %d", err);
		goto free_buf;
	}

	if ((err = pm_node_disconnect(nodemask_buf))) {
		PM_DEBUG("PM Node disconnect failed. err = %d\n", err);
		goto free_buf;
	}

	if ((err = micvcons_pm_disconnect_node(nodemask_buf,
		DISCONN_TYPE_POWER_MGMT))) {
		PM_DEBUG("VCONS Node disconnect failed. err = %d\n", err);
		goto free_buf;
	}

	for(node_id = 0; node_id <= ms_info.mi_maxid;  node_id++) {
		if (node_id == SCIF_HOST_NODE)
			continue;
		if (!get_nodemask_bit(nodemask_buf, node_id))
			continue;
		node_ctx = get_per_dev_ctx(node_id - 1);
		if (!node_ctx) {
			PM_DEBUG("Failed to retrieve node context.");
			err = -EINVAL;
			goto revert;
		}

		if (node_ctx->micpm_ctx.idle_state ==
			PM_IDLE_STATE_PC3_READY) {
			set_host_state(node_ctx, PM_IDLE_STATE_PC3);
			node_ctx->micpm_ctx.idle_state =
				PM_IDLE_STATE_PC3;
			PM_DEBUG("Node %d entered PC3\n",
				mic_get_scifnode_id(node_ctx));
		} else {
			PM_DEBUG("Invalid idle state \n");
			err = -EINVAL;
			goto revert;
		}
	}

revert:
	if (err)
		revert_idle_entry_trasaction(nodemask_buf);
free_buf:
	kfree(nodemask_buf);
dep_teardown:
	teardown_pm_dependency();
unlock:
	if (err && (mic_ctx->micpm_ctx.idle_state != PM_IDLE_STATE_PC0))
		pm_pc3_exit(mic_ctx);

	mutex_unlock(&mic_data.dd_pm.pm_idle_mutex);
	return err;
}
Exemplo n.º 5
0
int pm_pc3_to_pc6_entry(mic_ctx_t *mic_ctx)
{
	int err;
	sbox_pcu_ctrl_t ctrl_regval;
	gbox_pm_control pmctrl_reg;
	sbox_core_freq_t core_freq_reg;

	if ((get_card_state(mic_ctx)) != PM_IDLE_STATE_PC3) {
		PM_DEBUG("Card not ready to go to PC6. \n");
		err = -EAGAIN;
		goto exit;
	}

	if (atomic_cmpxchg(&mic_ctx->gate_interrupt, 0, 1) == 1) {
		PM_DEBUG("Cannot gate interrupt handler while it is in use\n");
		err = -EFAULT;
		goto exit;
	}

	program_prevent_C3Exit(mic_ctx, true);
	program_mclk_shutdown(mic_ctx, true);

	/* Wait for uos to become idle. */
	if (!hw_idle(mic_ctx)) {
		program_mclk_shutdown(mic_ctx, false);
		if (!hw_idle(mic_ctx)) {
			program_prevent_C3Exit(mic_ctx, false);
			PM_DEBUG("Card not ready to go to PC6. \n");
			err = -EAGAIN;
			goto intr_ungate;
		} else {
			program_mclk_shutdown(mic_ctx, true);
		}
	}

	pmctrl_reg.value = pm_reg_read(mic_ctx, GBOX_PM_CTRL);
	pmctrl_reg.bits.in_pckgc6 = 1;
	pm_reg_write(pmctrl_reg.value, mic_ctx, GBOX_PM_CTRL);

	core_freq_reg.value = pm_reg_read(mic_ctx, SBOX_COREFREQ);
	core_freq_reg.bits.booted = 0;
	pm_reg_write(core_freq_reg.value, mic_ctx, SBOX_COREFREQ);

	udelay(500);

	ctrl_regval.value = pm_reg_read(mic_ctx, SBOX_PCU_CONTROL);
	ctrl_regval.bits.grpB_pwrgood_mask = 1;
	pm_reg_write(ctrl_regval.value, mic_ctx, SBOX_PCU_CONTROL);

	err = set_vid_knc(mic_ctx, 0);
	if (err != 0) {
		PM_DEBUG("Aborting PC6 entry...Failed to set VID\n");
		restore_pc6_registers(mic_ctx, true);
		goto intr_ungate;
	}

	mic_ctx->micpm_ctx.idle_state = PM_IDLE_STATE_PC6;
	set_host_state(mic_ctx, PM_IDLE_STATE_PC6);

	dma_prep_suspend(mic_ctx->dma_handle);

	PM_PRINT("Node %d entered PC6\n",
		mic_get_scifnode_id(mic_ctx));

	return err;

intr_ungate:
	atomic_set(&mic_ctx->gate_interrupt, 0);
	tasklet_schedule(&mic_ctx->bi_dpc);
exit:
	return err;
}