📄 s390io.c
字号:
debug_text_event(cio_debug_trace_id, 2, dbf_txt); } return( ret );}/* * Disable IRQ by modifying the subchannel */static int disable_subchannel( unsigned int irq){ int cc; /* condition code */ int ret = 0; /* function return value */ int retry = 5; char dbf_txt[15]; SANITY_CHECK(irq); if ( ioinfo[irq]->ui.flags.busy ) { /* * the disable function must not be called while there are * requests pending for completion ! */ ret = -EBUSY; } else { if (cio_debug_initialized) { sprintf(dbf_txt, "dissch%x", irq); debug_text_event(cio_debug_trace_id, 2, dbf_txt); } /* * 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: /* ok */ retry = 0; ret = 0; break; case 1: /* status pending */ 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() call */ retry--; break; case 2: /* busy; this should not happen! */ printk( KERN_CRIT"disable_subchannel(%04X) " "- unexpected busy condition for " "device %04X received !\n", irq, ioinfo[irq]->devstat.devno); if (cio_debug_initialized) debug_sprintf_event(cio_debug_msg_id, 0, "disable_subchannel(%04X) - unexpected busy condition for device %04X received !\n", irq, ioinfo[irq]->devstat.devno); retry = 0; ret = -EBUSY; break; case 3: /* not oper */ /* * should hardly occur ?! */ ioinfo[irq]->ui.flags.oper = 0; ioinfo[irq]->ui.flags.d_disable = 1; retry = 0; ret = 0; /* if the device has gone we */ /* ... don't need to disable */ /* ... it anymore ! */ break; } /* endswitch */ } while ( retry ); } /* endif */ } /* endif */ if (cio_debug_initialized) { sprintf(dbf_txt, "ret:%d",ret); debug_text_event(cio_debug_trace_id, 2, dbf_txt); } return( ret);}void s390_init_IRQ( void ){ unsigned long flags; /* PSW flags */ long cr6 __attribute__ ((aligned (8))); asm volatile ("STCK %0" : "=m" (irq_IPL_TOD)); p_init_schib = alloc_bootmem_low( sizeof(schib_t)); p_init_irb = alloc_bootmem_low( sizeof(irb_t)); /* * 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; __ctl_load( cr6, 6, 6); s390_process_subchannels(); if (cio_count_irqs) { int i; for (i=0; i<NR_CPUS; i++) s390_irq_count[i]=0; } /* * enable default I/O-interrupt sublass 3 */ cr6 = 0x10000000; __ctl_load( cr6, 6, 6); s390_device_recognition_all(); init_IRQ_complete = 1; __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; int ret = 0; char buffer[80]; char dbf_txt[15]; SANITY_CHECK(irq); /* * The flag usage is mutal exclusive ... */ if ( (flag & DOIO_EARLY_NOTIFICATION) && (flag & DOIO_REPORT_ALL ) ) { return( -EINVAL ); } /* endif */ if (cio_debug_initialized) { sprintf(dbf_txt, "stIO%x", irq); debug_text_event(cio_debug_trace_id, 4, dbf_txt); } /* * setup ORB */ ioinfo[irq]->orb.intparm = (__u32)(long)&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 ? TRUE : FALSE); 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 */#ifdef CONFIG_ARCH_S390X /* * for 64 bit we always support 64 bit IDAWs with 4k page size only */ ioinfo[irq]->orb.c64 = 1; ioinfo[irq]->orb.i2k = 0;#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 ) { ret = enable_cpu_sync_isc( irq); if ( ret ) { return( ret); } } /* endif */ if ( flag & DOIO_DONT_CALL_INTHDLR ) { ioinfo[irq]->ui.flags.repnone = 1; } /* endif */ /* * Issue "Start subchannel" and process condition code */ ccode = ssch( irq, &(ioinfo[irq]->orb) ); if (cio_debug_initialized) { sprintf(dbf_txt, "ccode:%d", ccode); debug_text_event(cio_debug_trace_id, 4, dbf_txt); } 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.dev_id)->ii.irb, '\0', sizeof( irb_t) ); } /* endif */ memset( &ioinfo[irq]->devstat.ii.irb, '\0', sizeof( irb_t) ); /* * 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_EARLY_NOTIFICATION ) { 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 ) { psw_t io_new_psw; int ccode; uint64_t time_start; uint64_t time_curr; int ready = 0; int io_sub = -1; struct _lowcore *lc = NULL; int do_retry = 1; /* * 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; asm volatile ("STCK %0" : "=m" (time_start)); time_start = time_start >> 32; do { if ( flag & DOIO_TIMEOUT ) { tpi_info_t tpi_info={0,}; do { if ( tpi(&tpi_info) == 1 ) { io_sub = tpi_info.irq; break; } else { udelay(100); /* usecs */ asm volatile ("STCK %0" : "=m" (time_curr)); if ( ((time_curr >> 32) - time_start ) >= 3 ) do_retry = 0; } /* endif */ } while ( do_retry ); } else { __load_psw( io_sync_wait );io_wakeup: io_sub = (__u32)*(__u16 *)__LC_SUBCHANNEL_NR; } /* endif */ if ( do_retry ) ready = s390_process_IRQ( io_sub ); /* * surrender when retry count's exceeded ... */ } while ( !( ( io_sub == irq ) && ( ready == 1 )) && do_retry ); *(__u32 *)__LC_SYNC_IO_WORD = 0; if ( !do_retry ) ret = -ETIMEDOUT; } /* endif */ break; case 1 : /* status pending */ ioinfo[irq]->devstat.flag = DEVSTAT_START_FUNCTION | DEVSTAT_STATUS_PENDING; /* * initialize the device driver specific devstat irb area */ memset( &((devstat_t *) ioinfo[irq]->irq_desc.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 ) { if ( flag & DOIO_VALID_LPM ) { ioinfo[irq]->opm &= ~(ioinfo[irq]->devstat.ii.irb.esw.esw1.lpum); } else { ioinfo[irq]->opm = 0; } /* endif */ if ( ioinfo[irq]->opm == 0 ) { ret = -ENODEV; ioinfo[irq]->ui.flags.oper = 0; } else { ret = -EIO; } /* endif */ ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;#ifdef CONFIG_DEBUG_IO { 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,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -