/* * 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; }
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"); }
/* 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; }
/* * 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; }
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; }