📄 s390io.c
字号:
} /* * we ignore the clear_io() request if ending_status was received but * a SENSE operation is waiting for completion. */ else if ( ioinfo[irq]->ui.flags.w4sense ) { ret = 0; } else { if (cio_debug_initialized) { sprintf(dbf_txt, "clearIO%x", irq); debug_text_event(cio_debug_trace_id, 2, dbf_txt); } /* * 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 ) { ret = enable_cpu_sync_isc( irq); if ( ret ) { return( ret); } /* endif */ } /* endif */ /* * Issue "Clear subchannel" and process condition code */ ccode = csch( irq ); if (cio_debug_initialized) { sprintf(dbf_txt, "ccode:%d",ccode); debug_text_event(cio_debug_trace_id, 2, dbf_txt); } switch ( ccode ) { case 0: ioinfo[irq]->ui.flags.haltio = 1; if ( !ioinfo[irq]->ui.flags.doio ) { ioinfo[irq]->ui.flags.busy = 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_CLEAR_FUNCTION; ioinfo[irq]->devstat.scnt = 0; } else { ioinfo[irq]->devstat.flag |= DEVSTAT_CLEAR_FUNCTION; } /* endif */ /* * 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 ) { int io_sub; __u32 io_parm; psw_t io_new_psw; int ccode; int ready = 0; struct _lowcore *lc = NULL; /* * 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( "clear_IO() : unexpected " "address-space-control %d\n", ccode); break; } /* endswitch */ io_sync_wait.addr = FIX_PSW(&&cio_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 { __load_psw( io_sync_wait );cio_wakeup: io_parm = *(__u32 *)__LC_IO_INT_PARM; io_sub = (__u32)*(__u16 *)__LC_SUBCHANNEL_NR; ready = s390_process_IRQ( io_sub ); } while ( !((io_sub == irq) && (ready == 1)) ); *(__u32 *)__LC_SYNC_IO_WORD = 0; } /* endif */ ret = 0; break; case 1 : /* no status pending for csh */ BUG(); break; case 2 : /* no busy for csh*/ BUG(); break; default: /* device not operational */ ret = -ENODEV; break; } /* endswitch */ if ( flag & DOIO_WAIT_FOR_INTERRUPT ) { disable_cpu_sync_isc( irq ); } /* endif */ } /* endif */ return( ret );}/* * do_IRQ() handles all normal I/O device IRQ's (the special * SMP cross-CPU interrupts have their own specific * handlers). * */asmlinkage void do_IRQ( struct pt_regs regs ){ /* * Get interrupt info from lowcore */ volatile tpi_info_t *tpi_info = (tpi_info_t*)(__LC_SUBCHANNEL_ID); int cpu = smp_processor_id(); /* * take fast exit if CPU is in sync. I/O state * * Note: we have to turn off the WAIT bit and re-disable * interrupts prior to return as this was the initial * entry condition to synchronous I/O. */ if ( *(__u32 *)__LC_SYNC_IO_WORD ) { regs.psw.mask &= ~(_PSW_WAIT_MASK_BIT | _PSW_IO_MASK_BIT); return; } /* endif */#ifdef CONFIG_FAST_IRQ do {#endif /* CONFIG_FAST_IRQ */ /* * Non I/O-subchannel thin interrupts are processed differently */ if ( tpi_info->adapter_IO == 1 && tpi_info->int_type == IO_INTERRUPT_TYPE ) { irq_enter(cpu, -1); do_adapter_IO( tpi_info->intparm ); irq_exit(cpu, -1); } else { unsigned int irq = tpi_info->irq; /* * fix me !!! * * instead of boxing the device, we need to schedule device * recognition, the interrupt stays pending. We need to * dynamically allocate an ioinfo structure, etc.. */ if ( ioinfo[irq] == INVALID_STORAGE_AREA ) { return; /* this keeps the device boxed ... */ } irq_enter(cpu, irq); s390irq_spin_lock( irq ); s390_process_IRQ( irq ); s390irq_spin_unlock( irq ); irq_exit(cpu, irq); }#ifdef CONFIG_FAST_IRQ /* * Are more interrupts pending? * If so, the tpi instruction will update the lowcore * to hold the info for the next interrupt. */ } while ( tpi( NULL ) != 0 );#endif /* CONFIG_FAST_IRQ */ return;}/* * s390_process_IRQ() handles status pending situations and interrupts * * Called by : do_IRQ() - for "real" interrupts * s390_start_IO, halt_IO() * - status pending cond. after SSCH, or HSCH * disable_subchannel() - status pending conditions (after MSCH) * * Returns: 0 - no ending status received, no further action taken * 1 - interrupt handler was called with ending status */int s390_process_IRQ( unsigned int irq ){ int ccode; /* cond code from tsch() operation */ int irb_cc; /* cond code from irb */ int sdevstat; /* struct devstat size to copy */ unsigned int fctl; /* function control */ unsigned int stctl; /* status control */ unsigned int actl; /* activity control */ int issense = 0; int ending_status = 0; int allow4handler = 1; int chnchk = 0; devstat_t *dp; devstat_t *udp; char dbf_txt[15]; char buffer[80]; if (cio_count_irqs) { int cpu = smp_processor_id(); s390_irq_count[cpu]++; } if (cio_debug_initialized) { sprintf(dbf_txt, "procIRQ%x", irq); debug_text_event(cio_debug_trace_id, 3, dbf_txt); } if ( ioinfo[irq] == INVALID_STORAGE_AREA ) { /* we can't properly process the interrupt ... */ tsch( irq, p_init_irb ); return( 1 ); } /* endif */ dp = &ioinfo[irq]->devstat; udp = ioinfo[irq]->irq_desc.dev_id; /* * It might be possible that a device was not-oper. at the time * of free_irq() processing. This means the handler is no longer * available when the device possibly becomes ready again. In * this case we perform delayed disable_subchannel() processing. */ if ( !ioinfo[irq]->ui.flags.ready ) { if ( !ioinfo[irq]->ui.flags.d_disable ) {#ifdef CONFIG_DEBUG_IO printk( KERN_CRIT"s390_process_IRQ(%04X) " "- no interrupt handler registered " "for device %04X !\n", irq, ioinfo[irq]->devstat.devno);#endif /* CONFIG_DEBUG_IO */ if (cio_debug_initialized) debug_sprintf_event(cio_debug_msg_id, 0, "s390_process_IRQ(%04X) - no interrupt handler registered for device %04X !\n", irq, ioinfo[irq]->devstat.devno); } /* endif */ } /* endif */ /* * retrieve the i/o interrupt information (irb), * update the device specific status information * and possibly call the interrupt handler. * * Note 1: At this time we don't process the resulting * condition code (ccode) from tsch(), although * we probably should. * * Note 2: Here we will have to check for channel * check conditions and call a channel check * handler. * * Note 3: If a start function was issued, the interruption * parameter relates to it. If a halt function was * issued for an idle device, the intparm must not * be taken from lowcore, but from the devstat area. */ ccode = tsch( irq, &(dp->ii.irb) ); if (cio_debug_initialized) { sprintf(dbf_txt, "ccode:%d", ccode); debug_text_event(cio_debug_trace_id, 3, dbf_txt); } // // We must only accumulate the status if the device is busy already // if ( ioinfo[irq]->ui.flags.busy ) { dp->dstat |= dp->ii.irb.scsw.dstat; dp->cstat |= dp->ii.irb.scsw.cstat; dp->intparm = ioinfo[irq]->u_intparm; } else { dp->dstat = dp->ii.irb.scsw.dstat; dp->cstat = dp->ii.irb.scsw.cstat; dp->flag = 0; // reset status flags dp->intparm = 0; } /* endif */ dp->lpum = dp->ii.irb.esw.esw1.lpum; /* * reset device-busy bit if no longer set in irb */ if ( (dp->dstat & DEV_STAT_BUSY ) && ((dp->ii.irb.scsw.dstat & DEV_STAT_BUSY) == 0)) { dp->dstat &= ~DEV_STAT_BUSY; } /* endif */ /* * Save residual count and CCW information in case primary and * secondary status are presented with different interrupts. */ if ( dp->ii.irb.scsw.stctl & ( SCSW_STCTL_PRIM_STATUS | SCSW_STCTL_INTER_STATUS ) ) { /* * If the subchannel status shows status pending * and we received a check condition, the count * information is not meaningful. */ if ( !( (dp->ii.irb.scsw.stctl & SCSW_STCTL_STATUS_PEND) && ( dp->ii.irb.scsw.cstat & ( SCHN_STAT_CHN_DATA_CHK | SCHN_STAT_CHN_CTRL_CHK | SCHN_STAT_INTF_CTRL_CHK | SCHN_STAT_PROG_CHECK | SCHN_STAT_PROT_CHECK | SCHN_STAT_CHAIN_CHECK )))) { dp->rescnt = dp->ii.irb.scsw.count; } else { dp->rescnt = SENSE_MAX_COUNT; } dp->cpa = dp->ii.irb.scsw.cpa;#ifdef CONFIG_DEBUG_IO if ( irq != cons_dev ) printk( KERN_DEBUG "s390_process_IRQ( %04X ) : " "residual count from irb after tsch() %d\n", irq, dp->rescnt );#endif if (cio_debug_initialized) debug_sprintf_event(cio_debug_msg_id, 6, "s390_process_IRQ( %04X ) : residual count from irq after tsch() %d\n", irq, dp->rescnt); } /* endif */ irb_cc = dp->ii.irb.scsw.cc; // // check for any kind of channel or interface control check but don't // issue the message for the console device // if ( (dp->ii.irb.scsw.cstat & ( SCHN_STAT_CHN_DATA_CHK | SCHN_STAT_CHN_CTRL_CHK | SCHN_STAT_INTF_CTRL_CHK ))) { if (irq != cons_dev) printk( KERN_WARNING "Channel-Check or Interface-Control-Check " "received\n" " ... device %04X on subchannel %04X, dev_stat " ": %02X sch_stat : %02X\n", ioinfo[irq]->devstat.devno, irq, dp->dstat, dp->cstat); if (cio_debug_initialized) { debug_sprintf_event(cio_debug_msg_id, 0, "Channel-Check or Interface-Control-Check received\n"); debug_sprintf_event(cio_debug_msg_id, 0, "... device %04X on subchannel %04X, dev_stat: %02X sch_stat: %02X\n", ioinfo[irq]->devstat.devno, irq, dp->dstat, dp->cstat); } chnchk = 1; } /* endif */ if( dp->ii.irb.scsw.ectl==0) { issense=0; } else if ( (dp->ii.irb.scsw.stctl == SCSW_STCTL_STATUS_PEND) && (dp->ii.irb.scsw.eswf == 0 )) { issense = 0; } else if ( (dp->ii.irb.scsw.stctl == (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_INTER_STATUS)) && ((dp->ii.irb.scsw.actl & SCSW_ACTL_SUSPENDED) == 0) ) { issense = 0; } else { issense = dp->ii.irb.esw.esw0.erw.cons; } /* endif */ if ( issense ) { dp->scnt = dp->ii.irb.esw.esw0.erw.scnt; dp->flag |= DEVSTAT_FLAG_SENSE_AVAIL; sdevstat = sizeof( devstat_t);#ifdef CONFIG_DEBUG_IO if ( irq != cons_dev ) printk( KERN_DEBUG "s390_process_IRQ( %04X ) : " "concurrent sense bytes avail %d\n", irq, dp->scnt );#endif if (cio_debug_initialized) debug_sprintf_event(cio_debug_msg_id, 4, "s390_process_IRQ( %04X ): concurrent sense bytes avail %d\n", irq, dp->scnt); } else { /* don't copy the sense data area ! */ sdevstat = sizeof( devstat_t) - SENSE_MAX_COUNT; } /* endif */ switch ( irb_cc ) { case 1: /* status pending */ dp->flag |= DEVSTAT_STATUS_PENDING; case 0: /* normal i/o interruption */ fctl = dp->ii.irb.scsw.fctl; stctl = dp->ii.irb.scsw.stctl; actl = dp->ii.irb.scsw.actl; if ( chnchk ) { sprintf( buffer, "s390_process_IRQ(%04X) - irb for " "device %04X after channel check\n", irq, dp->devno ); s390_displayhex( buffer, &(dp->ii.irb) , sizeof(irb_t)); if (cio_debug_initialized) { sp
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -