⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i2o_core.c

📁 内核linux2.4.20,可跟rtlinux3.2打补丁 组成实时linux系统,编译内核
💻 C
📖 第 1 页 / 共 5 页
字号:
 *	Clear and (re)initialize IOP's outbound queue. Returns 0 on *	success or a negative errno code on a failure. */ int i2o_init_outbound_q(struct i2o_controller *c){	u8 *status;	u32 m;	u32 *msg;	u32 time;	dprintk(KERN_INFO "%s: Initializing Outbound Queue...\n", c->name);	m=i2o_wait_message(c, "OutboundInit");	if(m==0xFFFFFFFF)		return -ETIMEDOUT;	msg=(u32 *)(c->mem_offset+m);	status = kmalloc(4,GFP_KERNEL);	if (status==NULL) {		printk(KERN_ERR "%s: Outbound Queue initialization failed - no free memory.\n",			c->name);		return -ENOMEM;	}	memset(status, 0, 4);	msg[0]= EIGHT_WORD_MSG_SIZE| TRL_OFFSET_6;	msg[1]= I2O_CMD_OUTBOUND_INIT<<24 | HOST_TID<<12 | ADAPTER_TID;	msg[2]= core_context;	msg[3]= 0x0106;				/* Transaction context */	msg[4]= 4096;				/* Host page frame size */	/* Frame size is in words. Pick 128, its what everyone elses uses and		other sizes break some adapters. */	msg[5]= MSG_FRAME_SIZE<<16|0x80;	/* Outbound msg frame size and Initcode */	msg[6]= 0xD0000004;			/* Simple SG LE, EOB */	msg[7]= virt_to_bus(status);	i2o_post_message(c,m);		barrier();	time=jiffies;	while(status[0] < I2O_CMD_REJECTED)	{		if((jiffies-time)>=30*HZ)		{			if(status[0]==0x00)				printk(KERN_ERR "%s: Ignored queue initialize request.\n",					c->name);			else  				printk(KERN_ERR "%s: Outbound queue initialize timeout.\n",					c->name);			kfree(status);			return -ETIMEDOUT;		}  		schedule();		barrier();	}  	if(status[0] != I2O_CMD_COMPLETED)	{		printk(KERN_ERR "%s: IOP outbound initialise failed.\n", c->name);		kfree(status);		return -ETIMEDOUT;	}	return 0;}/** *	i2o_post_outbound_messages	-	fill message queue *	@c: controller * *	Allocate a message frame and load the messages into the IOP. The *	function returns zero on success or a negative errno code on *	failure. */int i2o_post_outbound_messages(struct i2o_controller *c){	int i;	u32 m;	/* Alloc space for IOP's outbound queue message frames */	c->page_frame = kmalloc(MSG_POOL_SIZE, GFP_KERNEL);	if(c->page_frame==NULL) {		printk(KERN_ERR "%s: Outbound Q initialize failed; out of memory.\n",			c->name);		return -ENOMEM;	}	c->page_frame_map = pci_map_single(c->pdev, c->page_frame, MSG_POOL_SIZE, PCI_DMA_FROMDEVICE);	if(c->page_frame_map == 0)	{		kfree(c->page_frame);		printk(KERN_ERR "%s: Unable to map outbound queue.\n", c->name);		return -ENOMEM;	}	m = c->page_frame_map;	/* Post frames */	for(i=0; i< NMBR_MSG_FRAMES; i++) {		I2O_REPLY_WRITE32(c,m);		mb();		m += MSG_FRAME_SIZE;	}	return 0;}/* * Get the IOP's Logical Configuration Table */int i2o_lct_get(struct i2o_controller *c){	u32 msg[8];	int ret, size = c->status_block->expected_lct_size;	do {		if (c->lct == NULL) {			c->lct = kmalloc(size, GFP_KERNEL);			if(c->lct == NULL) {				printk(KERN_CRIT "%s: Lct Get failed. Out of memory.\n",					c->name);				return -ENOMEM;			}		}		memset(c->lct, 0, size);		msg[0] = EIGHT_WORD_MSG_SIZE|SGL_OFFSET_6;		msg[1] = I2O_CMD_LCT_NOTIFY<<24 | HOST_TID<<12 | ADAPTER_TID;		/* msg[2] filled in i2o_post_wait */		msg[3] = 0;		msg[4] = 0xFFFFFFFF;	/* All devices */		msg[5] = 0x00000000;	/* Report now */		msg[6] = 0xD0000000|size;		msg[7] = virt_to_bus(c->lct);		ret=i2o_post_wait_mem(c, msg, sizeof(msg), 120, c->lct, NULL);				if(ret == -ETIMEDOUT)		{			c->lct = NULL;			return ret;		}				if(ret<0)		{			printk(KERN_ERR "%s: LCT Get failed (status=%#x.\n", 				c->name, -ret);				return ret;		}		if (c->lct->table_size << 2 > size) {			size = c->lct->table_size << 2;			kfree(c->lct);			c->lct = NULL;		}	} while (c->lct == NULL);        if ((ret=i2o_parse_lct(c)) < 0)                return ret;	return 0;}/* * Like above, but used for async notification.  The main * difference is that we keep track of the CurrentChangeIndiicator * so that we only get updates when it actually changes. * */int i2o_lct_notify(struct i2o_controller *c){	u32 msg[8];	msg[0] = EIGHT_WORD_MSG_SIZE|SGL_OFFSET_6;	msg[1] = I2O_CMD_LCT_NOTIFY<<24 | HOST_TID<<12 | ADAPTER_TID;	msg[2] = core_context;	msg[3] = 0xDEADBEEF;		msg[4] = 0xFFFFFFFF;	/* All devices */	msg[5] = c->dlct->change_ind+1;	/* Next change */	msg[6] = 0xD0000000|8192;	msg[7] = virt_to_bus(c->dlct);	return i2o_post_this(c, msg, sizeof(msg));}		/* *	Bring a controller online into OPERATIONAL state.  */ int i2o_online_controller(struct i2o_controller *iop){	u32 v;		if (i2o_systab_send(iop) < 0)		return -1;	/* In READY state */	dprintk(KERN_INFO "%s: Attempting to enable...\n", iop->name);	if (i2o_enable_controller(iop) < 0)		return -1;	/* In OPERATIONAL state  */	dprintk(KERN_INFO "%s: Attempting to get/parse lct...\n", iop->name);	if (i2o_lct_get(iop) < 0)		return -1;	/* Check battery status */	 	iop->battery = 0;	if(i2o_query_scalar(iop, ADAPTER_TID, 0x0000, 4, &v, 4)>=0)	{		if(v&16)			iop->battery = 1;	}	return 0;}/* * Build system table * * The system table contains information about all the IOPs in the * system (duh) and is used by the Executives on the IOPs to establish * peer2peer connections.  We're not supporting peer2peer at the moment, * but this will be needed down the road for things like lan2lan forwarding. */static int i2o_build_sys_table(void){	struct i2o_controller *iop = NULL;	struct i2o_controller *niop = NULL;	int count = 0;	sys_tbl_len = sizeof(struct i2o_sys_tbl) +	// Header + IOPs				(i2o_num_controllers) *					sizeof(struct i2o_sys_tbl_entry);	if(sys_tbl)		kfree(sys_tbl);	sys_tbl = kmalloc(sys_tbl_len, GFP_KERNEL);	if(!sys_tbl) {		printk(KERN_CRIT "SysTab Set failed. Out of memory.\n");		return -ENOMEM;	}	memset((void*)sys_tbl, 0, sys_tbl_len);	sys_tbl->num_entries = i2o_num_controllers;	sys_tbl->version = I2OVERSION; /* TODO: Version 2.0 */	sys_tbl->change_ind = sys_tbl_ind++;	for(iop = i2o_controller_chain; iop; iop = niop)	{		niop = iop->next;		/* 		 * Get updated IOP state so we have the latest information		 *		 * We should delete the controller at this point if it		 * doesn't respond since  if it's not on the system table 		 * it is techninically not part of the I2O subsy遲em...		 */		if(i2o_status_get(iop)) {			printk(KERN_ERR "%s: Deleting b/c could not get status while"				"attempting to build system table\n", iop->name);			i2o_delete_controller(iop);					sys_tbl->num_entries--;			continue; // try the next one		}		sys_tbl->iops[count].org_id = iop->status_block->org_id;		sys_tbl->iops[count].iop_id = iop->unit + 2;		sys_tbl->iops[count].seg_num = 0;		sys_tbl->iops[count].i2o_version = 				iop->status_block->i2o_version;		sys_tbl->iops[count].iop_state = 				iop->status_block->iop_state;		sys_tbl->iops[count].msg_type = 				iop->status_block->msg_type;		sys_tbl->iops[count].frame_size = 				iop->status_block->inbound_frame_size;		sys_tbl->iops[count].last_changed = sys_tbl_ind - 1; // ??		sys_tbl->iops[count].iop_capabilities = 				iop->status_block->iop_capabilities;		sys_tbl->iops[count].inbound_low = 				(u32)virt_to_bus(iop->post_port);		sys_tbl->iops[count].inbound_high = 0;	// TODO: 64-bit support		count++;	}#ifdef DRIVERDEBUG{	u32 *table;	table = (u32*)sys_tbl;	for(count = 0; count < (sys_tbl_len >>2); count++)		printk(KERN_INFO "sys_tbl[%d] = %0#10x\n", count, table[count]);}#endif	return 0;}/* *	Run time support routines */ /* *	Generic "post and forget" helpers. This is less efficient - we do *	a memcpy for example that isnt strictly needed, but for most uses *	this is simply not worth optimising */int i2o_post_this(struct i2o_controller *c, u32 *data, int len){	u32 m;	u32 *msg;	unsigned long t=jiffies;	do	{		mb();		m = I2O_POST_READ32(c);	}	while(m==0xFFFFFFFF && (jiffies-t)<HZ);		if(m==0xFFFFFFFF)	{		printk(KERN_ERR "%s: Timeout waiting for message frame!\n",		       c->name);		return -ETIMEDOUT;	}	msg = (u32 *)(c->mem_offset + m); 	memcpy_toio(msg, data, len);	i2o_post_message(c,m);	return 0;}/** * 	i2o_post_wait_mem	-	I2O query/reply with DMA buffers *	@c: controller *	@msg: message to send *	@len: length of message *	@timeout: time in seconds to wait *	@mem1: attached memory buffer 1 *	@mem2: attached memory buffer 2 * * 	This core API allows an OSM to post a message and then be told whether *	or not the system received a successful reply.  * *	If the message times out then the value '-ETIMEDOUT' is returned. This *	is a special case. In this situation the message may (should) complete *	at an indefinite time in the future. When it completes it will use the *	memory buffers attached to the request. If -ETIMEDOUT is returned then *	the memory buffers must not be freed. Instead the event completion will *	free them for you. In all other cases the buffers are your problem. * *	Pass NULL for unneeded buffers. */ int i2o_post_wait_mem(struct i2o_controller *c, u32 *msg, int len, int timeout, void *mem1, void *mem2){	DECLARE_WAIT_QUEUE_HEAD(wq_i2o_post);	DECLARE_WAITQUEUE(wait, current);	int complete = 0;	int status;	unsigned long flags = 0;	struct i2o_post_wait_data *wait_data =		kmalloc(sizeof(struct i2o_post_wait_data), GFP_KERNEL);	if(!wait_data)		return -ENOMEM;	/*	 *	Create a new notification object	 */	wait_data->status = &status;	wait_data->complete = &complete;	wait_data->mem[0] = mem1;	wait_data->mem[1] = mem2;	/* 	 *	Queue the event with its unique id	 */	spin_lock_irqsave(&post_wait_lock, flags);	wait_data->next = post_wait_queue;	post_wait_queue = wait_data;	wait_data->id = (++post_wait_id) & 0x7fff;	wait_data->wq = &wq_i2o_post;	spin_unlock_irqrestore(&post_wait_lock, flags);	/*	 *	Fill in the message id	 */	 	msg[2] = 0x80000000|(u32)core_context|((u32)wait_data->id<<16);		/*	 *	Post the message to the controller. At some point later it 	 *	will return. If we time out before it returns then	 *	complete will be zero.  From the point post_this returns	 *	the wait_data may have been deleted.	 */	add_wait_queue(&wq_i2o_post, &wait);	set_current_state(TASK_INTERRUPTIBLE);	if ((status = i2o_post_this(c, msg, len))==0) {		schedule_timeout(HZ * timeout);	}  	else	{		remove_wait_queue(&wq_i2o_post, &wait);		return -EIO;	}	remove_wait_queue(&wq_i2o_post, &wait);	if(signal_pending(current))		status = -EINTR;			spin_lock_irqsave(&post_wait_lock, flags);	barrier();	/* Be sure we see complete as it is locked */	if(!complete)	{		/* 		 *	Mark the entry dead. We cannot remove it. This is important.		 *	When it does terminate (which it must do if the controller hasnt		 *	died..) then it will otherwise scribble on stuff.		 *	!complete lets us safely check if the entry is still		 *	allocated and thus we can write into it		 */		wait_data->wq = NULL;		status = -ETIMEDOUT;	}	else	{		/* Debugging check - remove me soon */		if(status == -ETIMEDOUT)		{			printk("TIMEDOUT BUG!\n");			status = -EIO;		}	}	/* And the wait_data is not leaked either! */	 	spin_unlock_irqrestore(&post_wait_lock, flags);	return status;}/** * 	i2o_post_wait		-	I2O query/reply *	@c: controller *	@msg: message to send *	@len: length of message *	@timeout: time in seconds to wait * * 	This core API allows an OSM to post a message and then be told whether *	or not the system received a successful reply.  */ int i2o_post_wait(struct i2o_controller *c, u32 *msg, int len, int timeout){	return i2o_post_wait_mem(c, msg, len, timeout, NULL, NULL);}/* * i2o_post_wait is completed and we want to wake up the  * sleeping proccess. Called by core's reply handler. */static void i2o_post_wait_complete(u32 context, int status){	struct i2o_post_wait_data **p1, *q;	unsigned long flags;		/* 	 * We need to search through the post_wait 	 * queue to see if the given message is still	 * outstanding.  If not, it means that the IOP 	 * took longer to respond to the message than we 	 * had allowed and timer has already expired.  	 * Not much we can do about that except log	 * it for debug purposes, increase timeout, and recompile	 *	 * Lock needed to keep anyone from moving queue pointers 	 * around while we're looking through them.	 */	spin_lock_irqsave(&post_wait_lock, flags);	for(p1 = &post_wait_queue; *p1!=NULL; p1 = &((*p1)->next)) 	{		q = (*p1);		if(q->id == ((context >> 16) & 0x7fff)) {			/*			 *	Delete it 			 */			 			*p1 = q->next;						/*			 *	Live or dead ?			 */			 			if(q->wq)			{				/* Live entry - wakeup and set status */				*q->status = status;				*q->complete = 1;				wake_up(q->wq);			}			else			{				/*				 *	Free resources. Caller is dead				 */				if(q->mem[0])					kfree(q->mem[0]);				if(q->mem[1])					kfree(q->mem[1]);				printk(KERN_WARNING "i2o_post_wait event completed after timeout.\n");			}			kfree(q);			spin_unlock(&post_wait_lock);			return;		}	}	spin_unlock(&post_wait_lock);	printk(KERN_DEBUG "i2o_post_wait: Bogus reply!\n");}/*	Issue UTIL_PARAMS_GET or UTIL_PARAMS_SET * *	This function can be used for all UtilParamsGet/Set operations. *	The OperationList is given in oplist-buffer,  *	and results are returned in reslist-buffer. *	Note that the minimum sized reslist is 8 bytes and contains *	ResultCount, ErrorInfoS

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -