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

📄 s390io.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *  arch/s390/kernel/s390io.c *   S/390 common I/O routines * *  S390 version *    Copyright (C) 1999, 2000 IBM Deutschland Entwicklung GmbH, *                             IBM Corporation *    Author(s): Ingo Adlung (adlung@de.ibm.com) */#include <linux/config.h>#include <linux/errno.h>#include <linux/kernel_stat.h>#include <linux/signal.h>#include <linux/sched.h>#include <linux/interrupt.h>#include <linux/malloc.h>#include <linux/string.h>#include <linux/smp.h>#include <linux/tasks.h>#include <linux/smp_lock.h>#include <linux/init.h>#include <linux/bootmem.h>#include <asm/system.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/bitops.h>#include <asm/smp.h>#include <asm/pgtable.h>#include <asm/delay.h>#include <asm/processor.h>#include <asm/lowcore.h>#include <asm/s390io.h>#include <asm/s390dyn.h>#include <asm/s390mach.h>#ifndef TRUE#define TRUE  1#define FALSE 0#endif#undef CONFIG_DEBUG_IO#define REIPL_DEVID_MAGIC 0x87654321struct irqaction  init_IRQ_action;unsigned int      highest_subchannel;ioinfo_t         *ioinfo_head = NULL;ioinfo_t         *ioinfo_tail = NULL;ioinfo_t         *ioinfo[__MAX_SUBCHANNELS] = {	[0 ... (__MAX_SUBCHANNELS-1)] = INVALID_STORAGE_AREA};static spinlock_t        sync_isc;                 // synchronous irq processing lockstatic psw_t             io_sync_wait;             // wait PSW for sync IO, prot. by sync_iscstatic psw_t             io_new_psw;               // save I/O new PSW, prot. by sync_iscstatic int               cons_dev          = -1;   // identify console devicestatic int               init_IRQ_complete = 0;static schib_t           init_schib;static __u64             irq_IPL_TOD;/* * Dummy controller type for unused interrupts */int  do_none(unsigned int irq, int cpu, struct pt_regs * regs) { return 0;}int  enable_none(unsigned int irq) { return(-ENODEV); }int  disable_none(unsigned int irq) { return(-ENODEV); }struct hw_interrupt_type no_irq_type = {	"none",	do_none,	enable_none,	disable_none};static void init_IRQ_handler( int irq, void *dev_id, struct pt_regs *regs);static int  s390_setup_irq(unsigned int irq, struct irqaction * new);static void s390_process_subchannels( void);static void s390_device_recognition( void);static int  s390_validate_subchannel( int irq);static int  s390_SenseID( int irq, senseid_t *sid);static int  s390_SetPGID( int irq, __u8 lpm, pgid_t *pgid);static int  s390_SensePGID( int irq, __u8 lpm, pgid_t *pgid);static int  s390_process_IRQ( unsigned int irq );static int  s390_DevicePathVerification( int irq );extern int  do_none(unsigned int irq, int cpu, struct pt_regs * regs);extern int  enable_none(unsigned int irq);extern int  disable_none(unsigned int irq);extern void tod_wait(unsigned long usecs);asmlinkage void do_IRQ( struct pt_regs regs,                        unsigned int   irq,                        __u32          s390_intparm );void s390_displayhex(char *str,void *ptr,s32 cnt);void s390_displayhex(char *str,void *ptr,s32 cnt){	s32	cnt1,cnt2,maxcnt2;	u32	*currptr=(__u32 *)ptr;	printk("\n%s\n",str);	for(cnt1=0;cnt1<cnt;cnt1+=16)	{		printk("%08lX ",(unsigned long)currptr);		maxcnt2=cnt-cnt1;		if(maxcnt2>16)			maxcnt2=16;		for(cnt2=0;cnt2<maxcnt2;cnt2+=4)			printk("%08X ",*currptr++);		printk("\n");	}}int s390_request_irq( unsigned int   irq,                      void           (*handler)(int, void *, struct pt_regs *),                      unsigned long  irqflags,                      const char    *devname,                      void          *dev_id){	int               retval;	struct irqaction *action;	if (irq >= __MAX_SUBCHANNELS)		return -EINVAL;	if ( !handler || !dev_id )		return -EINVAL;	/*	 * during init_IRQ() processing we don't have memory	 *  management yet, thus need to use a statically	 *  allocated irqaction control block	 */	if ( init_IRQ_complete )	{		action = (struct irqaction *)		kmalloc(sizeof(struct irqaction), GFP_KERNEL);	}	else	{		action = &init_IRQ_action;	} /* endif */	if (!action)	{		return -ENOMEM;	} /* endif */	action->handler = handler;	action->flags   = irqflags;	action->mask    = 0;	action->name    = devname;	action->next    = NULL;	action->dev_id  = dev_id;	retval = s390_setup_irq( irq, action);	if ( !retval )	{		retval = s390_DevicePathVerification( irq );	}	else if ( retval && init_IRQ_complete )	{		kfree(action);	} /* endif */	return retval;}void s390_free_irq(unsigned int irq, void *dev_id){	unsigned int flags;	int          ret;	unsigned int count = 0;	if ( irq >= __MAX_SUBCHANNELS || ioinfo[irq] == INVALID_STORAGE_AREA )	{		return;	} /* endif */	s390irq_spin_lock_irqsave( irq, flags);#ifdef  CONFIG_KERNEL_DEBUG	if ( irq != cons_dev )	{		printk("Trying to free IRQ%d\n",irq);	} /* endif */#endif	/*	 * disable the device and reset all IRQ info if	 *  the IRQ is actually owned by the handler ...	 */	if ( ioinfo[irq]->irq_desc.action )	{		if (    (dev_id == ioinfo[irq]->irq_desc.action->dev_id  )		     || (dev_id == (devstat_t *)REIPL_DEVID_MAGIC) )		{			/* start deregister */			ioinfo[irq]->ui.flags.unready = 1;			do			{				ret = ioinfo[irq]->irq_desc.handler->disable(irq);				count++;				if ( ret == -EBUSY )				{					int iret;					/*					 * kill it !					 * ... we first try sync and eventually					 *  try terminating the current I/O by					 *  an async request, twice halt, then					 *  clear.					 */					if ( count < 3 )					{              							iret = halt_IO( irq,						                0xC8C1D3E3,						                DOIO_WAIT_FOR_INTERRUPT );   							if ( iret == -EBUSY )						{							halt_IO( irq, 0xC8C1D3E3, 0);							s390irq_spin_unlock_irqrestore( irq, flags);							tod_wait( 200000 ); /* 200 ms */							s390irq_spin_lock_irqsave( irq, flags);						} /* endif */					}					else					{						iret = clear_IO( irq,						                 0x40C3D3D9,						                 DOIO_WAIT_FOR_INTERRUPT );   							if ( iret == -EBUSY )						{							clear_IO( irq, 0xC8C1D3E3, 0);							s390irq_spin_unlock_irqrestore( irq, flags);							tod_wait( 1000000 ); /* 1000 ms */							s390irq_spin_lock_irqsave( irq, flags);						} /* endif */					} /* endif */					if ( count == 3 )               {						/* give it a very last try ... */						ioinfo[irq]->irq_desc.handler->disable(irq);						if ( ioinfo[irq]->ui.flags.busy )					   {							printk( KERN_CRIT"free_irq(%04X) "							       "- device %04X busy, retry "							       "count exceeded\n",						   	    irq,						      	 ioinfo[irq]->devstat.devno);                  } /* endif */												break; /* sigh, let's give up ... */					} /* endif */				} /* endif */					} while ( ret == -EBUSY );			if ( init_IRQ_complete )				kfree( ioinfo[irq]->irq_desc.action );			ioinfo[irq]->irq_desc.action  = NULL;			ioinfo[irq]->ui.flags.ready   = 0;			ioinfo[irq]->irq_desc.handler->enable  = &enable_none;			ioinfo[irq]->irq_desc.handler->disable = &disable_none;			ioinfo[irq]->ui.flags.unready = 0; /* deregister ended */			s390irq_spin_unlock_irqrestore( irq, flags);		}		else		{			s390irq_spin_unlock_irqrestore( irq, flags);			printk("free_irq() : error, dev_id does not match !");		} /* endif */	}	else	{		s390irq_spin_unlock_irqrestore( irq, flags);		printk("free_irq() : error, no action block ... !");	} /* endif */}/* * Generic enable/disable code */int disable_irq(unsigned int irq){	unsigned long flags;	int           ret;	if ( ioinfo[irq] == INVALID_STORAGE_AREA )		return( -ENODEV);	s390irq_spin_lock_irqsave(irq, flags);	/*	 * At this point we may actually have a pending interrupt being active	 * on another CPU. So don't touch the IRQ_INPROGRESS bit..	 */	ioinfo[irq]->irq_desc.status |= IRQ_DISABLED;	ret = ioinfo[irq]->irq_desc.handler->disable(irq);	s390irq_spin_unlock_irqrestore(irq, flags);	synchronize_irq();	return( ret);}int enable_irq(unsigned int irq){	unsigned long flags;	int           ret;	if ( ioinfo[irq] == INVALID_STORAGE_AREA )		return( -ENODEV);	s390irq_spin_lock_irqsave(irq, flags);	ioinfo[irq]->irq_desc.status = 0;	ret = ioinfo[irq]->irq_desc.handler->enable(irq);	s390irq_spin_unlock_irqrestore(irq, flags);	return(ret);}/* * Enable IRQ by modifying the subchannel */static int enable_subchannel( unsigned int irq){	int   ret;	int   ccode;	int   retry = 5;	if ( irq > highest_subchannel || irq < 0 )	{		return( -ENODEV );	} /* endif */	if ( ioinfo[irq] == INVALID_STORAGE_AREA )		return( -ENODEV);	/*	 * If a previous disable request is pending we reset it. However, this	 *  status implies that the device may (still) be not-operational.	 */	if (  ioinfo[irq]->ui.flags.d_disable )	{		ioinfo[irq]->ui.flags.d_disable = 0;		ret                             = 0;	}	else	{		ccode = stsch(irq, &(ioinfo[irq]->schib) );		if ( ccode )		{			ret = -ENODEV;		}		else		{			ioinfo[irq]->schib.pmcw.ena = 1;			do			{				ccode = msch( irq, &(ioinfo[irq]->schib) );				switch (ccode) {				case 0:					ret = 0;					break;				case 1:					/*					 * very bad, requires interrupt alike					 *  processing, where "rbh" is a dummy					 *  parameter for interface compatibility					 *  only. Bottom-half handling cannot be					 *  required as this must be an					 *  unsolicited interrupt (!busy).					 */					ioinfo[irq]->ui.flags.s_pend = 1;					s390_process_IRQ( irq );					ioinfo[irq]->ui.flags.s_pend = 0;					ret = -EIO;    /* might be overwritten */					               /* ... on re-driving    */					               /* ... the msch() */					retry--;					break;				case 3:					ioinfo[irq]->ui.flags.oper = 0;					ret = -ENODEV;					break;				default:					printk( KERN_CRIT"enable_subchannel(%04X) "					        " : ccode 2 on msch() for device "					        "%04X received !\n",					        irq,					        ioinfo[irq]->devstat.devno);					ret = -ENODEV; // never reached				}			} while ( (ccode == 1) && retry );		} /* endif */	}  /* endif */	return( ret );}/* * Disable IRQ by modifying the subchannel */static int disable_subchannel( unsigned int irq){	int  cc;          /* condition code */	int  ret;         /* function return value */	int  retry = 5;	if ( irq > highest_subchannel )	{		ret = -ENODEV;	}	if ( ioinfo[irq] == INVALID_STORAGE_AREA )	{		return( -ENODEV);   }	else if ( ioinfo[irq]->ui.flags.busy )	{		/*		 * the disable function must not be called while there are		 *  requests pending for completion !		 */		ret = -EBUSY;	}	else	{		/*		 * If device isn't operational we have to perform delayed		 *  disabling when the next interrupt occurs - unless the		 *  irq is re-requested prior to the interrupt to occur.		 */		cc = stsch(irq, &(ioinfo[irq]->schib) );		if ( cc == 3 )		{			ioinfo[irq]->ui.flags.oper      = 0;			ioinfo[irq]->ui.flags.d_disable = 1;			ret = 0;		}		else // cc == 0		{			ioinfo[irq]->schib.pmcw.ena = 0;			do			{				cc = msch( irq, &(ioinfo[irq]->schib) );				switch (cc) {				case 0 :					ret = 0;   /* done */					break;				case 1 :					/*					 * very bad, requires interrupt alike  					 *  processing, where "rbh" is a dummy					 *  parm for interface compatibility					 *  only. Bottom-half handling cannot					 *  be required as this must be an					 *  unsolicited interrupt (!busy).					 */					ioinfo[irq]->ui.flags.s_pend = 1;					s390_process_IRQ( irq );					ioinfo[irq]->ui.flags.s_pend = 0;					ret = -EBUSY;  /* might be overwritten  */					               /* ... on re-driving the */					               /* ... msch() call       */					retry--;					break;				case 2 :					/*

⌨️ 快捷键说明

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