Exemplo n.º 1
0
/*
 * setup_pm_dependency:
 *
 * Function sets up the dependency matrix by populating
 * the matrix with node depency information.
 *
 * Returns 0 on success. Appropriate error on failure.
 */
int setup_pm_dependency(void){
	int err = 0;
	uint16_t i;
	uint16_t j;
	mic_ctx_t *mic_ctx;

	for (i = 0; i < mic_data.dd_numdevs; i++) {
		mic_ctx = get_per_dev_ctx(i);
		if (!mic_ctx) {
			PM_DEBUG("Failed to retrieve driver context\n");
			return -EFAULT;
		}
		if (mic_ctx->micpm_ctx.idle_state ==
			PM_IDLE_STATE_PC3_READY) {
			for (j = 0; j < mic_data.dd_numdevs; j++) {
				if (micscif_get_nodedep(mic_get_scifnode_id(mic_ctx),j+1) ==
						DEP_STATE_DEPENDENT) {
					micscif_set_nodedep(mic_get_scifnode_id(mic_ctx),j+1,
							DEP_STATE_DISCONNECT_READY);
				}
			}
		}
	}
	return err;
}
Exemplo n.º 2
0
static int
micvcons_write(struct tty_struct * tty, const unsigned char *buf, int count)
{
	micvcons_port_t *port = (micvcons_port_t *)tty->driver_data;
	mic_ctx_t *mic_ctx = get_per_dev_ctx(tty->index);
	int bytes=0, status;
	struct vcons_buf *vcons_host_header;
	u8 card_alive = 1;

	spin_lock_bh(&port->dp_lock);
	vcons_host_header = (struct vcons_buf *)port->dp_vcons->dc_hdr_virt;
	if (vcons_host_header->mic_magic == MIC_VCONS_SLEEPING) {
		status = micvcons_resume(mic_ctx);
		if (status != 0) {
			/* If card can not wakeup, it is dead. */
			card_alive = 0;
			goto exit;
		}
	}
	if (vcons_host_header->mic_magic != MIC_VCONS_READY)
		goto exit;
	bytes = micvcons_port_write(port, buf, count);
	if (bytes) {
		mic_send_hvc_intr(mic_ctx);
		extra_timeout = 0;
	}
exit:
	spin_unlock_bh(&port->dp_lock);
	if (!card_alive)
		micvcons_del_timer_entry(port);
	return bytes;
}
Exemplo n.º 3
0
static int
micvcons_open(struct tty_struct * tty, struct file * filp)
{
	micvcons_port_t *port = &mic_data.dd_ports[tty->index];
	int ret = 0;
	mic_ctx_t *mic_ctx = get_per_dev_ctx(tty->index);

	tty->driver_data = port;

	mutex_lock(&port->dp_mutex);
	spin_lock_bh(&port->dp_lock);

	if ((filp->f_flags & O_ACCMODE) != O_RDONLY) {
		if (port->dp_writer) {
			ret = -EBUSY;
			goto exit_locked;
		}
		port->dp_writer = filp;
		port->dp_bytes = 0;
	}

	if ((filp->f_flags & O_ACCMODE) != O_WRONLY) {
		if (port->dp_reader) {
			ret = -EBUSY;
			goto exit_locked;
		}
		port->dp_reader = filp;
		port->dp_canread = 1;
	}

#if LINUX_VERSION_CODE < KERNEL_VERSION(3,9,0)
	tty->low_latency = 0;
#else
	tty->port->low_latency = 0;
#endif

	if (!port->dp_tty)
		port->dp_tty = tty;
	if (!port->dp_vcons)
		port->dp_vcons = &mic_ctx->bi_vcons;
	if (tty->count == 1) {
		ret = micvcons_start(mic_ctx);
		if (ret != 0)
			goto exit_locked;
		spin_lock(&timer_list_lock);
		list_add_tail_rcu(&port->list_member, &timer_list_head);
		if (list_is_singular(&timer_list_head)) {
			restart_timer_flag = MICVCONS_TIMER_RESTART;
			mod_timer(&vcons_timer, jiffies + 
				msecs_to_jiffies(MICVCONS_SHORT_TIMEOUT));
		}
		spin_unlock(&timer_list_lock);
	}

exit_locked:
	spin_unlock_bh(&port->dp_lock);
	mutex_unlock(&port->dp_mutex);
	return ret;
}
Exemplo n.º 4
0
void acptboot_getconn(struct work_struct *work)
{
	mic_ctx_t *node_ctx;
	struct scif_portID data;
	scif_epd_t conn_epd;
	struct timespec tod;
	int proto;
	int version;
	int err;

	if ((err = scif_accept(acptboot_data->listen_epd, &data, &conn_epd,
						SCIF_ACCEPT_SYNC))) {
		pr_debug("ACPTBOOT: scif_accept_failed %d\n", err);
		return;

		//goto requeue_accept;
	}

	if (!data.node) {
		printk(KERN_ERR "ACPTBOOT: connect received from invalid dev %d\n", 
								-EINVAL);
		goto close_epd;
	}

	if ((err = scif_recv(conn_epd, &version, sizeof(version), SCIF_RECV_BLOCK)) != sizeof(version)) {
		printk(KERN_ERR "ACPTBOOT: failed to recieve version number err %d\n", err);
		goto close_epd;
	}

	if ((err = scif_recv(conn_epd, &proto, sizeof(proto), SCIF_RECV_BLOCK)) != sizeof(proto)) {
		printk(KERN_ERR "ACPTBOOT: failed to recieve proto id %d\n", err);
		goto close_epd;
	}

	switch (proto) {
	case ACPT_BOOTED:
		node_ctx = get_per_dev_ctx(data.node - 1);
		mic_setstate(node_ctx, MIC_ONLINE);
		node_ctx->boot_count++;

		proto = ACPT_BOOT_ACK;
		scif_send(conn_epd, &proto, sizeof(proto), SCIF_SEND_BLOCK);
		break;

	case ACPT_REQUEST_TIME:
		getnstimeofday(&tod);
		proto = ACPT_TIME_DATA;
		scif_send(conn_epd, &proto, sizeof(proto), SCIF_SEND_BLOCK);
		scif_send(conn_epd, &tod, sizeof(tod), SCIF_SEND_BLOCK);
		break;
	}

close_epd:
	if ((err = scif_close(conn_epd)))
		printk(KERN_ERR "ACPTBOOT: scif_close failed %d\n", err);

//requeue_accept:
	queue_work(acptboot_data->acptbootwq, &acptboot_data->acptbootwork);
}
Exemplo n.º 5
0
/*
 * revert_idle_entry_trasaction:
 *
 * @node_disc_bitmask: Bitmask of nodes which were involved in the
 *  transaction
 *
 *  Function Reverts idle state changes made to nodes when an idle
 *  state trasaction fails.
 */
int revert_idle_entry_trasaction(uint8_t *node_disc_bitmask) {
	int err = 0;
	mic_ctx_t *node_ctx;
	uint32_t node_id = 0;

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

		if (!get_nodemask_bit(node_disc_bitmask, 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 exit;
		}

		if (node_ctx->micpm_ctx.idle_state == PM_IDLE_STATE_PC3) {
			err = pm_pc3_exit(node_ctx);
			if (err) {
				PM_DEBUG("Wakeup of Node %d failed. Node is lost"
					" and is to be disconnected",node_id);
				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);
			}
		}
	}
exit:
	return err;
}
Exemplo n.º 6
0
/* pm_node_disconnect
 *
 * Called during idlestate entry.
 *
 * Function checks the pm_ref_cnt and returns ACK
 * or NACK depending on the pm_ref_cnt value.
 */
int pm_node_disconnect(uint8_t *nodemask) {

	uint32_t node_id;
	mic_ctx_t *mic_ctx;
	int ret = 0;
	int err = 0;

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

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

		mic_ctx = get_per_dev_ctx(node_id - 1);
		if (!mic_ctx) {
			set_nodemask_bit(nodemask, node_id, 0);
			return -EAGAIN;
		}

		if (mic_ctx->state != MIC_ONLINE) {
			set_nodemask_bit(nodemask, node_id, 0);
			return -EAGAIN;
		}

		ret = atomic_cmpxchg(&mic_ctx->micpm_ctx.pm_ref_cnt, 
			0, PM_NODE_IDLE);
		if (((ret != 0) && (ret != PM_NODE_IDLE))
			|| atomic_read(&mic_data.dd_pm.wakeup_in_progress)) {
			set_nodemask_bit(nodemask, node_id, 0);
			return -EAGAIN;
		}
	}

	return err;
}
Exemplo n.º 7
0
static PM_MMIO_REGVALUE_GET(svidctrl, SBOX_SVID_CONTROL);
static PM_MMIO_REGVALUE_GET(pcuctrl, SBOX_PCU_CONTROL);
static PM_MMIO_REGVALUE_GET(hoststate,SBOX_HOST_PMSTATE);
static PM_MMIO_REGVALUE_GET(cardstate, SBOX_UOS_PMSTATE);
static PM_MMIO_REGVALUE_GET(wtimer, SBOX_C3WAKEUP_TIMER);
static PM_MMIO_REGVALUE_GET(gpmctrl, GBOX_PM_CTRL);
static PM_MMIO_REGVALUE_GET(core_volt, SBOX_COREVOLT);
static PM_MMIO_REGVALUE_GET(uos_pcuctrl, SBOX_UOS_PCUCONTROL);

static int depgraph_j2i_show(struct seq_file *s, void *pos)
{
	uint64_t bid = (uint64_t)s->private;
	mic_ctx_t *mic_ctx;
	int i, j;

	mic_ctx = get_per_dev_ctx(bid);
	if (!mic_ctx) {
		return -EINVAL;
	}

	seq_printf(s,"=================================================================\n");
	seq_printf(s,"%-10s |%-25s\n", "Scif Node" , "dependent nodes");
	seq_printf(s,"=================================================================\n");

	for ( i = 0; i <= ms_info.mi_maxid; i++) {
		seq_printf(s, "%-10d |", i);
		for (j = 0; j <= ms_info.mi_maxid; j++) {
			switch(ms_info.mi_depmtrx[j][i]) {
				case DEP_STATE_DEPENDENT:
				{
					/* (A) - active dependency on node i */
Exemplo n.º 8
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.º 9
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.º 10
0
/*
 DESCRIPTION:: Gets the opcode from the input buffer and call appropriate method
 PARAMETERS::
   [in]mic_ctx_t *mic_ctx - pointer to the mic private context
   [in]void *in_buffer - input buffer containing opcode + ioctl arguments,
 RETURN_VALUE:: 0 if successful, non-zero if failure
*/
int
adapter_do_ioctl(struct file *f, uint32_t cmd, uint64_t arg)
{
	int status = 0;
	mic_ctx_t *mic_ctx = NULL;

	void __user *argp = (void __user *)arg;
	switch (cmd) {

	case IOCTL_FLASHCMD:
	{
		struct ctrlioctl_flashcmd args = {0};

		if (copy_from_user(&args, argp, sizeof(struct ctrlioctl_flashcmd))) {
			return -EFAULT;
		}

		if (args.brdnum >= (uint32_t)mic_data.dd_numdevs) {
			printk(KERN_ERR "IOCTL error: given board num is invalid\n");
			return -EINVAL;
		}

		mic_ctx = get_per_dev_ctx(args.brdnum);
		if (!mic_ctx) {
			printk(KERN_ERR "IOCTL error: null mic context\n");
			return -ENODEV;
		}

		/* Make sure we are running in flash mode */
		if (mic_ctx->mode != MODE_FLASH || mic_ctx->state != MIC_ONLINE) {
			printk(KERN_ERR "%s Card is not online in flash mode or online state\n", __func__);
			return -EPERM;
		}

		if (mic_ctx->bi_family != FAMILY_KNC) {
			printk(KERN_ERR "%s IOCTL_FLASHCMD not supported for non KNC family cards\n", __func__);
			return -EPERM;
		}

		status = do_send_flash_cmd(mic_ctx, &args);
		if (status) {
			printk(KERN_ERR "IOCTL error: failed to complete IOCTL for bdnum %d\n", args.brdnum);
			return status;
		}

		if (copy_to_user(argp, &args, sizeof(struct ctrlioctl_flashcmd))) {
			return -EFAULT;
		}

		break;
	}

	case IOCTL_CARDMEMCPY:
	{
		struct ctrlioctl_cardmemcpy args = {0};

		if (copy_from_user(&args, argp, sizeof(struct ctrlioctl_cardmemcpy))) {
			return -EFAULT;
		}

		if (args.brdnum >= (uint32_t)mic_data.dd_numdevs) {
			printk(KERN_ERR "IOCTL error: given board num is invalid\n");
			return -EINVAL;
		}
		mic_ctx = get_per_dev_ctx(args.brdnum);
		if (!mic_ctx) {
			printk(KERN_ERR "IOCTL error: null mic context\n");
			return -EFAULT;
		}

		if(mic_ctx->state != MIC_ONLINE || mic_ctx->mode != MODE_LINUX) {
			status = -EFAULT;
			printk("Error ! Card not in linux mode or online state!\n");
			return status;
		}

		status = get_card_mem(mic_ctx, &args);
		if (status) {
			printk(KERN_ERR "IOCTL error: failed to complete IOCTL for bdnum %d\n", args.brdnum);
			return status;
		}

		break;
	}
	default:
		return micmem_ioctl(f, cmd, arg);
	}
	return status;
}
Exemplo n.º 11
0
static int __init
mic_init(void)
{
	int ret, i;

	adapter_init();

	unaligned_cache = micscif_kmem_cache_create();
	if (!unaligned_cache) {
		ret = -ENOMEM;
		goto init_free_ports;
	}

	mic_lindata.dd_pcidriver.name = "mic";
	mic_lindata.dd_pcidriver.id_table = mic_pci_tbl;
	mic_lindata.dd_pcidriver.probe = mic_probe;
	mic_lindata.dd_pcidriver.remove = mic_remove;
	mic_lindata.dd_pcidriver.driver.pm = &pci_dev_pm_ops;
	mic_lindata.dd_pcidriver.shutdown = mic_shutdown;


	if ((ret = alloc_chrdev_region(&mic_lindata.dd_dev,
				       0, MAX_DLDR_MINORS, "mic") != 0)) {
		printk("Error allocating device nodes: %d\n", ret);
		goto init_free_ports;
	}

	cdev_init(&mic_lindata.dd_cdev, &mic_fops);
	mic_lindata.dd_cdev.owner = THIS_MODULE;
	mic_lindata.dd_cdev.ops = &mic_fops;

	if ((ret = cdev_add(&mic_lindata.dd_cdev,
			    mic_lindata.dd_dev, MAX_DLDR_MINORS) != 0)) {
		kobject_put(&mic_lindata.dd_cdev.kobj);
		goto init_free_region;
	}

	mic_lindata.dd_class = class_create(THIS_MODULE, "mic");
	if (IS_ERR(mic_lindata.dd_class)) {
		printk("MICDLDR: Error createing mic class\n");
		cdev_del(&mic_lindata.dd_cdev);
		ret = PTR_ERR(mic_lindata.dd_class);
		goto init_free_region;
	}

#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,31)
	mic_lindata.dd_class->devnode = mic_devnode;
#endif

	mic_lindata.dd_hostdev = device_create(mic_lindata.dd_class, NULL,
					    mic_lindata.dd_dev, NULL, "ctrl");
	mic_lindata.dd_scifdev = device_create(mic_lindata.dd_class, NULL,
					    mic_lindata.dd_dev + 1, NULL, "scif");
	ret = sysfs_create_group(&mic_lindata.dd_hostdev->kobj, &host_attr_group);
	ret = sysfs_create_group(&mic_lindata.dd_scifdev->kobj, &scif_attr_group);

#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,31)
	mic_lindata.dd_class->devnode = NULL;
#endif

	if (micveth_init(mic_lindata.dd_hostdev))
		printk(KERN_ERR "%s: micveth_init failed\n", __func__);

	ret = pci_register_driver(&mic_lindata.dd_pcidriver);
	if (ret) {
		micscif_destroy();
		printk("mic: failed to register pci driver %d\n", ret);
		goto clean_unregister;
	}

	if (!mic_data.dd_numdevs) {
		printk("mic: No MIC boards present.  SCIF available in loopback mode\n");
	} else {
		printk("mic: number of devices detected %d \n", mic_data.dd_numdevs);
	}

	for (i = 0; i < mic_data.dd_numdevs; i++) {
		mic_ctx_t *mic_ctx = get_per_dev_ctx(i);
		wait_event(mic_ctx->ioremapwq,
			mic_ctx->aper.va || mic_ctx->state == MIC_RESETFAIL);
		destroy_workqueue(mic_ctx->ioremapworkq);
	}

	micveth_init_legacy(mic_data.dd_numdevs, mic_lindata.dd_hostdev);

	ret = acptboot_init();

#ifdef USE_VCONSOLE
	micvcons_create(mic_data.dd_numdevs);
#endif

	/* Initialize Data structures for PM Disconnect */
	ret = micpm_disconn_init(mic_data.dd_numdevs + 1);
	if (ret)
		printk(KERN_ERR "%s: Failed to initialize PM disconnect"
			" data structures. PM may not work as expected."
			" ret = %d\n", __func__, ret);
	register_pm_notifier(&mic_pm_notifer);
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,34))
	ret = pm_qos_add_requirement(PM_QOS_CPU_DMA_LATENCY, "mic", mic_pm_qos_cpu_dma_lat);
	if (ret) {
		printk(KERN_ERR "%s %d mic_pm_qos_cpu_dma_lat %d ret %d\n", 
			__func__, __LINE__, mic_pm_qos_cpu_dma_lat, ret);
		ret = 0;
		/* Dont fail driver load due to PM QoS API. Fall through */
	}
#endif
	return 0;

clean_unregister:
	device_destroy(mic_lindata.dd_class, mic_lindata.dd_dev + 1);
	device_destroy(mic_lindata.dd_class, mic_lindata.dd_dev);
	class_destroy(mic_lindata.dd_class);
	cdev_del(&mic_lindata.dd_cdev);
	unregister_pm_notifier(&mic_pm_notifer);
init_free_region:
	unregister_chrdev_region(mic_lindata.dd_dev, MAX_DLDR_MINORS);
init_free_ports:
	micpm_uninit();
	return ret;
}