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

📄 s390io.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
					 * *** must not occur !              ***					 * ***                               ***					 * *** indicates our internal        ***					 * *** interrupt accounting is out   ***					 * ***  of sync ===> panic()         ***					 */					printk( KERN_CRIT"disable_subchannel(%04X) "					        "- unexpected busy condition for "							  "device %04X received !\n",					        irq,					        ioinfo[irq]->devstat.devno);					ret = -ENODEV; // never reached					break;				case 3 :					/*					 * should hardly occur ?!					 */					ioinfo[irq]->ui.flags.oper      = 0;					ioinfo[irq]->ui.flags.d_disable = 1;					ret = 0; /* if the device has gone we */					         /* ... don't need to disable */					         /* ... it anymore !    */					break;				default :					ret = -ENODEV;  // never reached ...					break;				} /* endswitch */			} while ( (cc == 1) && retry );		} /* endif */	} /* endif */	return( ret);}int s390_setup_irq( unsigned int irq, struct irqaction * new){	unsigned long      flags;	int                rc = 0;	if ( ioinfo[irq] == INVALID_STORAGE_AREA )	{		return( -ENODEV);   }	/*	 * The following block of code has to be executed atomically	 */	s390irq_spin_lock_irqsave( irq, flags);	if ( ioinfo[irq]->irq_desc.action == NULL )	{		ioinfo[irq]->irq_desc.action           = new;		ioinfo[irq]->irq_desc.status           = 0;		ioinfo[irq]->irq_desc.handler->enable  = &enable_subchannel;		ioinfo[irq]->irq_desc.handler->disable = &disable_subchannel;		ioinfo[irq]->irq_desc.handler->handle  = &handle_IRQ_event;		ioinfo[irq]->ui.flags.ready            = 1;		ioinfo[irq]->irq_desc.handler->enable(irq);	}	else	{		/*		 *  interrupt already owned, and shared interrupts		 *   aren't supported on S/390.		 */		rc = -EBUSY;	} /* endif */	s390irq_spin_unlock_irqrestore(irq,flags);	return( rc);}void s390_init_IRQ( void ){	unsigned long flags;     /* PSW flags */	long          cr6 __attribute__ ((aligned (8)));	// Hopefully bh_count's will get set when we copy the prefix lowcore	// structure to other CPI's ( DJB )	softirq_active(smp_processor_id()) = 0;	softirq_mask(smp_processor_id()) = 0;	local_bh_count(smp_processor_id()) = 0;	local_irq_count(smp_processor_id()) = 0;	syscall_count(smp_processor_id()) = 0;	asm volatile ("STCK %0" : "=m" (irq_IPL_TOD));	/*	 * As we don't know about the calling environment	 *  we assure running disabled. Before leaving the	 *  function we resestablish the old environment.	 *	 * Note : as we don't need a system wide lock, therefore	 *        we shouldn't use cli(), but __cli() as this	 *        affects the current CPU only.	 */	__save_flags(flags);	__cli();	/*	 * disable all interrupts	 */	cr6 = 0;	asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory");	s390_process_subchannels();	/*	 * enable default I/O-interrupt sublass 3	 */	cr6 = 0x10000000;	asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory");	s390_device_recognition();	init_IRQ_complete = 1;	s390_init_machine_check();	__restore_flags(flags);	return;}/* * dummy handler, used during init_IRQ() processing for compatibility only */void  init_IRQ_handler( int irq, void *dev_id, struct pt_regs *regs){   /* this is a dummy handler only ... */}int s390_start_IO( int            irq,      /* IRQ */                   ccw1_t        *cpa,      /* logical channel prog addr */                   unsigned long  user_intparm,  /* interruption parameter */                   __u8           lpm,      /* logical path mask */                   unsigned long  flag)     /* flags */{	int            ccode;	unsigned long  psw_flags;	int            sync_isc_locked = 0;	int            ret             = 0;	/*	 * The flag usage is mutal exclusive ...	 */	if (    (flag & DOIO_RETURN_CHAN_END)	     && (flag & DOIO_REPORT_ALL     ) )	{		return( -EINVAL );	} /* endif */	memset( &(ioinfo[irq]->orb), '\0', sizeof( orb_t) );	/*	 * setup ORB	 */  	ioinfo[irq]->orb.intparm = (__u32)&ioinfo[irq]->u_intparm;	ioinfo[irq]->orb.fmt     = 1;	ioinfo[irq]->orb.pfch = !(flag & DOIO_DENY_PREFETCH);	ioinfo[irq]->orb.spnd =  (flag & DOIO_ALLOW_SUSPEND);	ioinfo[irq]->orb.ssic =  (    (flag & DOIO_ALLOW_SUSPEND )	                           && (flag & DOIO_SUPPRESS_INTER) );	if ( flag & DOIO_VALID_LPM )	{		ioinfo[irq]->orb.lpm = lpm;	}	else	{		ioinfo[irq]->orb.lpm = ioinfo[irq]->opm;	} /* endif */	ioinfo[irq]->orb.cpa = (__u32)virt_to_phys( cpa);	/*	 * If sync processing was requested we lock the sync ISC, modify the	 *  device to present interrupts for this ISC only and switch the	 *  CPU to handle this ISC + the console ISC exclusively.	 */	if ( flag & DOIO_WAIT_FOR_INTERRUPT )	{		//		// check whether we run recursively (sense processing)		//		if ( !ioinfo[irq]->ui.flags.syncio )		{			spin_lock_irqsave( &sync_isc, psw_flags); 				ret = enable_cpu_sync_isc( irq);			if ( ret )			{				spin_unlock_irqrestore( &sync_isc, psw_flags);				return( ret);			}			else			{				sync_isc_locked              = 1; // local				ioinfo[irq]->ui.flags.syncio = 1; // global			} /* endif */  	 			} /* endif */	} /* endif */	/*	 * Issue "Start subchannel" and process condition code	 */	ccode = ssch( irq, &(ioinfo[irq]->orb) );	switch ( ccode ) {	case 0:		if ( !ioinfo[irq]->ui.flags.w4sense )		{			/*			 * init the device driver specific devstat irb area			 *			 * Note : don磘 clear saved irb info in case of sense !			 */			memset( &((devstat_t *)ioinfo[irq]->irq_desc.action->dev_id)->ii.irb,				'\0', sizeof( irb_t) );		} /* endif */		/*		 * initialize device status information		 */		ioinfo[irq]->ui.flags.busy   = 1;		ioinfo[irq]->ui.flags.doio   = 1;		ioinfo[irq]->u_intparm       = user_intparm;		ioinfo[irq]->devstat.cstat   = 0;		ioinfo[irq]->devstat.dstat   = 0;		ioinfo[irq]->devstat.lpum    = 0;		ioinfo[irq]->devstat.flag    = DEVSTAT_START_FUNCTION;		ioinfo[irq]->devstat.scnt    = 0;		ioinfo[irq]->ui.flags.fast   = 0;		ioinfo[irq]->ui.flags.repall = 0;		/*		 * Check for either early (FAST) notification requests		 *  or if we are to return all interrupt info.		 * Default is to call IRQ handler at secondary status only		 */		if ( flag & DOIO_RETURN_CHAN_END )		{			ioinfo[irq]->ui.flags.fast = 1;		}		else if ( flag & DOIO_REPORT_ALL )		{			ioinfo[irq]->ui.flags.repall = 1;		} /* endif */		ioinfo[irq]->ulpm = ioinfo[irq]->orb.lpm;		/*		 * If synchronous I/O processing is requested, we have		 *  to wait for the corresponding interrupt to occur by		 *  polling the interrupt condition. However, as multiple		 *  interrupts may be outstanding, we must not just wait		 *  for the first interrupt, but must poll until ours		 *  pops up.		 */		if ( flag & DOIO_WAIT_FOR_INTERRUPT )		{	//		__u32            io_parm;			psw_t            io_new_psw;			int              ccode;			int              ready  = 0;			int              io_sub = -1;			struct _lowcore *lc     = NULL;			int              count  = 30000;			/*			 * We shouldn't perform a TPI loop, waiting for an			 *  interrupt to occur, but should load a WAIT PSW			 *  instead. Otherwise we may keep the channel subsystem			 *  busy, not able to present the interrupt. When our			 *  sync. interrupt arrived we reset the I/O old PSW to			 *  its original value.			 */			memcpy( &io_new_psw, &lc->io_new_psw, sizeof(psw_t));			ccode = iac();			switch (ccode) {			case 0:  		// primary-space				io_sync_wait.mask =   _IO_PSW_MASK				                    | _PSW_PRIM_SPACE_MODE				                    | _PSW_IO_WAIT;				break;			case 1:			// secondary-space				io_sync_wait.mask =   _IO_PSW_MASK				                    | _PSW_SEC_SPACE_MODE				                    | _PSW_IO_WAIT;				break;			case 2:			// access-register				io_sync_wait.mask =   _IO_PSW_MASK				                    | _PSW_ACC_REG_MODE				                    | _PSW_IO_WAIT;				break;			case 3:			// home-space					io_sync_wait.mask =   _IO_PSW_MASK				                    | _PSW_HOME_SPACE_MODE				                    | _PSW_IO_WAIT;				break;			default:				panic( "start_IO() : unexpected "				       "address-space-control %d\n",				       ccode);				break;			} /* endswitch */			io_sync_wait.addr = FIX_PSW(&&io_wakeup);			/*			 * Martin didn't like modifying the new PSW, now we take			 *  a fast exit in do_IRQ() instead			 */			*(__u32 *)__LC_SYNC_IO_WORD  = 1;			do			{				if ( flag & DOIO_TIMEOUT )				{					tpi_info_t tpi_info;					do					{						if ( tpi(&tpi_info) == 1 )						{							io_sub = tpi_info.irq;							break;						}						else						{							count--;							tod_wait(100); /* usecs */						} /* endif */									} while ( count );				}				else				{					asm volatile ("lpsw %0" : : "m" (io_sync_wait));io_wakeup:					io_sub  = (__u32)*(__u16 *)__LC_SUBCHANNEL_NR;				} /* endif */ 				if ( count )					ready = s390_process_IRQ( io_sub );				/*				 * surrender when retry count's exceeded ...				 */			} while ( !(     ( io_sub == irq )			              && ( ready  == 1   ))			            && count                );			*(__u32 *)__LC_SYNC_IO_WORD = 0;			if ( !count )				ret = -ETIMEDOUT;		} /* endif */		break;	case 1 :            /* status pending */		ioinfo[irq]->devstat.flag |= DEVSTAT_STATUS_PENDING;		/*		 * initialize the device driver specific devstat irb area		 */		memset( &((devstat_t *) ioinfo[irq]->irq_desc.action->dev_id)->ii.irb,		        '\0', sizeof( irb_t) );		/*		 * Let the common interrupt handler process the pending status.		 *  However, we must avoid calling the user action handler, as		 *  it won't be prepared to handle a pending status during		 *  do_IO() processing inline. This also implies that process_IRQ		 *  must terminate synchronously - especially if device sensing		 *  is required.		 */		ioinfo[irq]->ui.flags.s_pend   = 1;		ioinfo[irq]->ui.flags.busy     = 1;		ioinfo[irq]->ui.flags.doio     = 1;		s390_process_IRQ( irq );		ioinfo[irq]->ui.flags.s_pend   = 0;		ioinfo[irq]->ui.flags.busy     = 0;		ioinfo[irq]->ui.flags.doio     = 0;		ioinfo[irq]->ui.flags.repall   = 0;		ioinfo[irq]->ui.flags.w4final  = 0;		ioinfo[irq]->devstat.flag     |= DEVSTAT_FINAL_STATUS;		/*		 * In multipath mode a condition code 3 implies the last path		 *  has gone, except we have previously restricted the I/O to		 *  a particular path. A condition code 1 (0 won't occur)		 *  results in return code EIO as well as 3 with another path		 *  than the one used (i.e. path available mask is non-zero).		 */		if ( ioinfo[irq]->devstat.ii.irb.scsw.cc == 3 )		{			ret                         = -ENODEV;			ioinfo[irq]->devstat.flag  |= DEVSTAT_NOT_OPER;			ioinfo[irq]->ui.flags.oper  = 0;#if CONFIG_DEBUG_IO			{			char buffer[80];			stsch(irq, &(ioinfo[irq]->schib) );			sprintf( buffer, "s390_start_IO(%04X) - irb for "			         "device %04X, after status pending\n",			         irq,			         ioinfo[irq]->devstat.devno );			s390_displayhex( buffer,			                 &(ioinfo[irq]->devstat.ii.irb) ,			                 sizeof(irb_t));			sprintf( buffer, "s390_start_IO(%04X) - schib for "			         "device %04X, after status pending\n",			         irq,			         ioinfo[irq]->devstat.devno );			s390_displayhex( buffer,			                 &(ioinfo[irq]->schib) ,			                 sizeof(schib_t));			if (ioinfo[irq]->devstat.flag & DEVSTAT_FLAG_SENSE_AVAIL)			{				sprintf( buffer, "s390_start_IO(%04X) - sense "				         "data for "				         "device %04X, after status pending\n",				         irq,				         ioinfo[irq]->devstat.devno );				s390_displayhex( buffer,		((devstat_t *)(ioinfo[irq]->irq_desc.action->dev_id))->ii.sense.data,		((devstat_t *)(ioinfo[irq]->irq_desc.action->dev_id))->rescnt);			}			}#endif		}		else		{			ret                         = -EIO;			ioinfo[irq]->devstat.flag  &= ~DEVSTAT_NOT_OPER;			ioinfo[irq]->ui.flags.oper  = 1;		} /* endif */		break;	case 2 :            /* busy */		ret = -EBUSY;		break;	default:            /* device not operational */		ret                           = -ENODEV;		ioinfo[irq]->ui.flags.oper    = 0;		ioinfo[irq]->devstat.flag    |= DEVSTAT_NOT_OPER;		memcpy( ioinfo[irq]->irq_desc.action->dev_id,			&(ioinfo[irq]->devstat),			sizeof( devstat_t) );#if CONFIG_DEBUG_IO		{			char buffer[80];   			stsch(irq, &(ioinfo[irq]->schib) );			sprintf( buffer, "s390_start_IO(%04X) - schib for "			         "device %04X, after 'not oper' status\n",			         irq,			         ioinfo[irq]->devstat.devno );			s390_displayhex( buffer,			                 &(ioinfo[irq]->schib),			                 sizeof(schib_t));      	}#endif		break;	} /* endswitch */	if (    ( flag & DOIO_WAIT_FOR_INTERRUPT )   	

⌨️ 快捷键说明

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