📄 s390io.c
字号:
}}void s390_displayhex2(char *str, void *ptr, s32 cnt, int level){ s32 cnt1, cnt2, maxcnt2; u32 *currptr = (__u32 *)ptr; char buffer[cnt*12]; debug_sprintf_event(cio_debug_msg_id, level, "%s\n", str); for (cnt1 = 0; cnt1<cnt; cnt1+=16) { sprintf(buffer, "%08lX ", (unsigned long)currptr); maxcnt2 = cnt - cnt1; if (maxcnt2 > 16) maxcnt2 = 16; for (cnt2 = 0; cnt2 < maxcnt2; cnt2 += 4) sprintf(buffer, "%08X ", *currptr++); } debug_sprintf_event(cio_debug_msg_id, level, "%s\n",buffer);}static int __init cio_setup( char *parm ){ if ( !strcmp( parm, "yes") ) { cio_show_msg = 1; } else if ( !strcmp( parm, "no") ) { cio_show_msg = 0; } else { printk( KERN_ERR "cio_setup : invalid cio_msg parameter '%s'", parm); } /* endif */ return 1;}__setup("cio_msg=", cio_setup);static int __init cio_notoper_setup(char *parm){ if (!strcmp(parm, "yes")) { cio_notoper_msg = 1; } else if (!strcmp(parm, "no")) { cio_notoper_msg = 0; } else { printk( KERN_ERR "cio_notoper_setup: invalid cio_notoper_msg parameter '%s'", parm); } return 1;} __setup("cio_notoper_msg=", cio_notoper_setup);#ifdef CONFIG_PROC_FSstatic int __init cio_proc_devinfo_setup(char *parm){ if (!strcmp(parm, "yes")) { cio_proc_devinfo = 1; } else if (!strcmp(parm, "no")) { cio_proc_devinfo = 0; } else { printk( KERN_ERR "cio_proc_devinfo_setup: invalid parameter '%s'\n",parm); } return 1;}__setup("cio_proc_devinfo=", cio_proc_devinfo_setup);#endif/* * register for adapter interrupts * * With HiperSockets the zSeries architecture provides for * means of adapter interrups, pseudo I/O interrupts that are * not tied to an I/O subchannel, but to an adapter. However, * it doesn't disclose the info how to enable/disable them, but * to recognize them only. Perhaps we should consider them * being shared interrupts, and thus build a linked list * of adapter handlers ... to be evaluated ... */int s390_register_adapter_interrupt( adapter_int_handler_t handler ){ int ret = 0; char dbf_txt[15]; if (cio_debug_initialized) debug_text_event(cio_debug_trace_id, 4, "rgaint"); spin_lock( &adapter_lock ); if ( handler == NULL ) ret = -EINVAL; else if ( adapter_handler ) ret = -EBUSY; else adapter_handler = handler; spin_unlock( &adapter_lock ); if (cio_debug_initialized) { sprintf(dbf_txt,"ret:%d",ret); debug_text_event(cio_debug_trace_id, 4, dbf_txt); } return( ret);}int s390_unregister_adapter_interrupt( adapter_int_handler_t handler ){ int ret = 0; char dbf_txt[15]; if (cio_debug_initialized) debug_text_event(cio_debug_trace_id, 4, "urgaint"); spin_lock( &adapter_lock ); if ( handler == NULL ) ret = -EINVAL; else if ( handler != adapter_handler ) ret = -EINVAL; else adapter_handler = NULL; spin_unlock( &adapter_lock ); if (cio_debug_initialized) { sprintf(dbf_txt,"ret:%d",ret); debug_text_event(cio_debug_trace_id, 4, dbf_txt); } return( ret);}static inline void do_adapter_IO( __u32 intparm ){ if (cio_debug_initialized) debug_text_event(cio_debug_trace_id, 4, "doaio"); spin_lock( &adapter_lock ); if ( adapter_handler ) (*adapter_handler)( intparm ); spin_unlock( &adapter_lock ); return; }/* * Note : internal use of irqflags SA_PROBE for NOT path grouping * */int s390_request_irq_special( int irq, io_handler_func_t io_handler, not_oper_handler_func_t not_oper_handler, unsigned long irqflags, const char *devname, void *dev_id){ int retval = 0; unsigned long flags; char dbf_txt[15]; int retry; if (irq >= __MAX_SUBCHANNELS) return -EINVAL; if ( !io_handler || !dev_id ) return -EINVAL; if ( ioinfo[irq] == INVALID_STORAGE_AREA ) return -ENODEV; if (cio_debug_initialized) { sprintf(dbf_txt, "reqsp%x", irq); debug_text_event(cio_debug_trace_id, 4, dbf_txt); } /* * The following block of code has to be executed atomically */ s390irq_spin_lock_irqsave( irq, flags); if ( !ioinfo[irq]->ui.flags.ready ) { retry = 5; ioinfo[irq]->irq_desc.handler = io_handler; ioinfo[irq]->irq_desc.name = devname; ioinfo[irq]->irq_desc.dev_id = dev_id; ioinfo[irq]->ui.flags.ready = 1; do { retval = enable_subchannel(irq); if (retval) { ioinfo[irq]->ui.flags.ready = 0; break; } stsch(irq,&ioinfo[irq]->schib); if (ioinfo[irq]->schib.pmcw.ena) retry = 0; else retry--; } while (retry); } else { /* * interrupt already owned, and shared interrupts * aren't supported on S/390. */ retval = -EBUSY; } /* endif */ s390irq_spin_unlock_irqrestore(irq,flags); if ( retval == 0 ) { if ( !(irqflags & SA_PROBE)) s390_DevicePathVerification( irq, 0 ); ioinfo[irq]->ui.flags.newreq = 1; ioinfo[irq]->nopfunc = not_oper_handler; } if (cio_debug_initialized) debug_int_event(cio_debug_trace_id, 4, retval); return retval;}int s390_request_irq( unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, const char *devname, void *dev_id){ int ret; ret = s390_request_irq_special( irq, (io_handler_func_t)handler, NULL, irqflags, devname, dev_id); if ( ret == 0 ) { ioinfo[irq]->ui.flags.newreq = 0; } /* endif */ return( ret);}void s390_free_irq(unsigned int irq, void *dev_id){ unsigned long flags; int ret; char dbf_txt[15]; if ( irq >= __MAX_SUBCHANNELS || ioinfo[irq] == INVALID_STORAGE_AREA ) return; if (cio_debug_initialized) { sprintf(dbf_txt, "free%x", irq); debug_text_event(cio_debug_trace_id, 2, dbf_txt); } s390irq_spin_lock_irqsave( irq, flags);#ifdef CONFIG_KERNEL_DEBUG if ( irq != cons_dev ) printk( KERN_DEBUG "Trying to free IRQ%d\n",irq);#endif if (cio_debug_initialized) debug_sprintf_event(cio_debug_msg_id, 2, "Trying to free IRQ %d\n", irq); /* * disable the device and reset all IRQ info if * the IRQ is actually owned by the handler ... */ if ( ioinfo[irq]->ui.flags.ready ) { if ( dev_id == ioinfo[irq]->irq_desc.dev_id ) { /* start deregister */ ioinfo[irq]->ui.flags.unready = 1; /* * Try to stop IO first... * ... it seems disable_subchannel is sometimes * successfully called with IO still pending. */ halt_IO( irq, 0xC8C1D3E3, DOIO_WAIT_FOR_INTERRUPT ); ret = disable_subchannel( irq); if ( ret == -EBUSY ) { /* * kill it ! * ... we first try sync and eventually * try terminating the current I/O by * an async request, twice halt, then * clear. */ ret = halt_IO( irq, 0xC8C1D3E3, DOIO_WAIT_FOR_INTERRUPT ); if ( ret == -EBUSY ) { halt_IO( irq, 0xC8C1D3E3, 0); s390irq_spin_unlock_irqrestore( irq, flags); udelay( 200000 ); /* 200 ms */ s390irq_spin_lock_irqsave( irq, flags); } /* endif */ ret = disable_subchannel(irq); if (ret == -EBUSY) { clear_IO( irq, 0x40C3D3D9,0 ); s390irq_spin_unlock_irqrestore( irq, flags); udelay( 1000000 ); /* 1000 ms */ s390irq_spin_lock_irqsave( irq, flags); /* give it a very last try ... */ disable_subchannel( 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); if (cio_debug_initialized) debug_sprintf_event(cio_debug_msg_id, 0, "free_irq(%04X) - device %04X busy, retry count exceeded\n", irq, ioinfo[irq]->devstat.devno); } /* endif */ } /* endif */ } /* endif */ ioinfo[irq]->ui.flags.ready = 0; ioinfo[irq]->ui.flags.unready = 0; /* deregister ended */ ioinfo[irq]->nopfunc = NULL; s390irq_spin_unlock_irqrestore( irq, flags); } else { s390irq_spin_unlock_irqrestore( irq, flags); printk( KERN_ERR "free_irq(%04X) : error, " "dev_id does not match !\n", irq); if (cio_debug_initialized) debug_sprintf_event(cio_debug_msg_id, 0, "free_irq(%04X) : error, dev_id does not match !\n", irq); } /* endif */ } else { s390irq_spin_unlock_irqrestore( irq, flags); printk( KERN_ERR "free_irq(%04X) : error, " "no action block ... !\n", irq); if (cio_debug_initialized) debug_sprintf_event(cio_debug_msg_id, 0, "free_irq(%04X) : error, no action block ... !\n", irq); } /* endif */}/* * Generic enable/disable code */int disable_irq(unsigned int irq){ unsigned long flags; int ret; char dbf_txt[15]; SANITY_CHECK(irq); if ( !ioinfo[irq]->ui.flags.ready ) return -ENODEV; if (cio_debug_initialized) { sprintf(dbf_txt, "disirq%x", irq); debug_text_event(cio_debug_trace_id, 4, dbf_txt); } s390irq_spin_lock_irqsave(irq, flags); ret = disable_subchannel(irq); s390irq_spin_unlock_irqrestore(irq, flags); synchronize_irq(); if (cio_debug_initialized) debug_int_event(cio_debug_trace_id, 4, ret); return( ret);}int enable_irq(unsigned int irq){ unsigned long flags; int ret; char dbf_txt[15]; SANITY_CHECK(irq); if ( !ioinfo[irq]->ui.flags.ready ) return -ENODEV; if (cio_debug_initialized) { sprintf(dbf_txt, "enirq%x", irq); debug_text_event(cio_debug_trace_id, 4, dbf_txt); } s390irq_spin_lock_irqsave(irq, flags); ret = enable_subchannel(irq); s390irq_spin_unlock_irqrestore(irq, flags); if (cio_debug_initialized) debug_int_event(cio_debug_trace_id, 4, ret); return(ret);}/* * Enable IRQ by modifying the subchannel */static int enable_subchannel( unsigned int irq){ int ret = 0; int ccode; int retry = 5; char dbf_txt[15]; SANITY_CHECK(irq); if (cio_debug_initialized) { sprintf(dbf_txt, "ensch%x", irq); debug_text_event(cio_debug_trace_id, 2, dbf_txt); } /* * 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; if ( irq == cons_dev ) { ioinfo[irq]->schib.pmcw.isc = 7; } else { ioinfo[irq]->schib.pmcw.isc = 3; } /* endif */ do { ccode = msch( irq, &(ioinfo[irq]->schib) ); switch (ccode) { case 0: /* ok */ ret = 0; retry = 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() */ retry--; break; case 2: /* busy */ udelay(100); /* allow for recovery */ ret = -EBUSY; retry--; break; case 3: /* not oper */ ioinfo[irq]->ui.flags.oper = 0; retry = 0; ret = -ENODEV; break; } } while ( retry ); } /* endif */ } /* endif */ if (cio_debug_initialized) { sprintf(dbf_txt,"ret:%d",ret);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -