X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fchar%2Fviocons.c;h=8de6b95aeb844cd03468d86f8643d2f65ed18acf;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=dcfcef4be16059876378faeec5b998dd0ff78840;hpb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;p=linux-2.6.git diff --git a/drivers/char/viocons.c b/drivers/char/viocons.c index dcfcef4be..8de6b95ae 100644 --- a/drivers/char/viocons.c +++ b/drivers/char/viocons.c @@ -25,8 +25,6 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include -#include #include #include #include @@ -44,12 +42,12 @@ #include #include -#include - -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #ifdef CONFIG_VT #error You must turn off CONFIG_VT to use CONFIG_VIOCONS @@ -61,51 +59,10 @@ #define VIOCONS_KERN_WARN KERN_WARNING "viocons: " #define VIOCONS_KERN_INFO KERN_INFO "viocons: " -static spinlock_t consolelock = SPIN_LOCK_UNLOCKED; -static spinlock_t consoleloglock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(consolelock); +static DEFINE_SPINLOCK(consoleloglock); -#ifdef CONFIG_MAGIC_SYSRQ static int vio_sysrq_pressed; -extern int sysrq_enabled; -#endif - -/* - * The structure of the events that flow between us and OS/400. You can't - * mess with this unless the OS/400 side changes too - */ -struct viocharlpevent { - struct HvLpEvent event; - u32 reserved; - u16 version; - u16 subtype_result_code; - u8 virtual_device; - u8 len; - u8 data[VIOCHAR_MAX_DATA]; -}; - -/* - * This is a place where we handle the distribution of memory - * for copy_from_user() calls. The buffer_available array is to - * help us determine which buffer to use. - */ -#define VIOCHAR_NUM_CFU_BUFFERS 7 -static struct viocharlpevent viocons_cfu_buffer[VIOCHAR_NUM_CFU_BUFFERS]; -static atomic_t viocons_cfu_buffer_available[VIOCHAR_NUM_CFU_BUFFERS]; - -#define VIOCHAR_WINDOW 10 -#define VIOCHAR_HIGHWATERMARK 3 - -enum viocharsubtype { - viocharopen = 0x0001, - viocharclose = 0x0002, - viochardata = 0x0003, - viocharack = 0x0004, - viocharconfig = 0x0005 -}; - -enum viochar_rc { - viochar_rc_ebusy = 1 -}; #define VIOCHAR_NUM_BUF 16 @@ -141,7 +98,7 @@ static void initDataEvent(struct viocharlpevent *viochar, HvLpIndex lp); static struct tty_driver *viotty_driver; -void hvlog(char *fmt, ...) +static void hvlog(char *fmt, ...) { int i; unsigned long flags; @@ -157,7 +114,7 @@ void hvlog(char *fmt, ...) spin_unlock_irqrestore(&consoleloglock, flags); } -void hvlogOutput(const char *buf, int count) +static void hvlogOutput(const char *buf, int count) { unsigned long flags; int begin; @@ -206,50 +163,6 @@ static inline int viotty_paranoia_check(struct port_info *pi, return 0; } -/* - * This function should ONLY be called once from viocons_init2 - */ -static void viocons_init_cfu_buffer(void) -{ - int i; - - for (i = 1; i < VIOCHAR_NUM_CFU_BUFFERS; i++) - atomic_set(&viocons_cfu_buffer_available[i], 1); -} - -static struct viocharlpevent *viocons_get_cfu_buffer(void) -{ - int i; - - /* - * Grab the first available buffer. It doesn't matter if we - * are interrupted during this array traversal as long as we - * get an available space. - */ - for (i = 0; i < VIOCHAR_NUM_CFU_BUFFERS; i++) - if (atomic_dec_if_positive(&viocons_cfu_buffer_available[i]) - == 0 ) - return &viocons_cfu_buffer[i]; - hvlog("\n\rviocons: viocons_get_cfu_buffer : no free buffers found"); - return NULL; -} - -static void viocons_free_cfu_buffer(struct viocharlpevent *buffer) -{ - int i; - - i = buffer - &viocons_cfu_buffer[0]; - if (i >= (sizeof(viocons_cfu_buffer) / sizeof(viocons_cfu_buffer[0]))) { - hvlog("\n\rviocons: viocons_free_cfu_buffer : buffer pointer not found in list."); - return; - } - if (atomic_read(&viocons_cfu_buffer_available[i]) != 0) { - hvlog("\n\rviocons: WARNING : returning unallocated cfu buffer."); - return; - } - atomic_set(&viocons_cfu_buffer_available[i], 1); -} - /* * Add data to our pending-send buffers. * @@ -438,15 +351,14 @@ static void send_buffers(struct port_info *pi) * NOTE: Don't use printk in here because it gets nastily recursive. hvlog * can be used to log to the hypervisor buffer */ -static int internal_write(struct port_info *pi, const char *buf, - size_t len, struct viocharlpevent *viochar) +static int internal_write(struct port_info *pi, const char *buf, size_t len) { HvLpEvent_Rc hvrc; size_t bleft; size_t curlen; const char *curbuf; unsigned long flags; - int copy_needed = (viochar == NULL); + struct viocharlpevent *viochar; /* * Write to the hvlog of inbound data are now done prior to @@ -462,25 +374,13 @@ static int internal_write(struct port_info *pi, const char *buf, spin_lock_irqsave(&consolelock, flags); - /* - * If the internal_write() was passed a pointer to a - * viocharlpevent then we don't need to allocate a new one - * (this is the case where we are internal_writing user space - * data). If we aren't writing user space data then we need - * to get an event from viopath. - */ - if (copy_needed) { - /* This one is fetched from the viopath data structure */ - viochar = (struct viocharlpevent *) - vio_get_event_buffer(viomajorsubtype_chario); - /* Make sure we got a buffer */ - if (viochar == NULL) { - spin_unlock_irqrestore(&consolelock, flags); - hvlog("\n\rviocons: Can't get viochar buffer in internal_write()."); - return -EAGAIN; - } - initDataEvent(viochar, pi->lp); + viochar = vio_get_event_buffer(viomajorsubtype_chario); + if (viochar == NULL) { + spin_unlock_irqrestore(&consolelock, flags); + hvlog("\n\rviocons: Can't get vio buffer in internal_write()."); + return -EAGAIN; } + initDataEvent(viochar, pi->lp); curbuf = buf; bleft = len; @@ -493,25 +393,16 @@ static int internal_write(struct port_info *pi, const char *buf, curlen = bleft; viochar->event.xCorrelationToken = pi->seq++; - - if (copy_needed) { - memcpy(viochar->data, curbuf, curlen); - viochar->len = curlen; - } - + memcpy(viochar->data, curbuf, curlen); + viochar->len = curlen; viochar->event.xSizeMinus1 = offsetof(struct viocharlpevent, data) + curlen; hvrc = HvCallEvent_signalLpEvent(&viochar->event); if (hvrc) { - spin_unlock_irqrestore(&consolelock, flags); - if (copy_needed) - vio_free_event_buffer(viomajorsubtype_chario, viochar); - hvlog("viocons: error sending event! %d\n", (int)hvrc); - return len - bleft; + goto out; } - curbuf += curlen; bleft -= curlen; } @@ -519,14 +410,9 @@ static int internal_write(struct port_info *pi, const char *buf, /* If we didn't send it all, buffer as much of it as we can. */ if (bleft > 0) bleft -= buffer_add(pi, curbuf, bleft); - /* - * Since we grabbed it from the viopath data structure, return - * it to the data structure. - */ - if (copy_needed) - vio_free_event_buffer(viomajorsubtype_chario, viochar); +out: + vio_free_event_buffer(viomajorsubtype_chario, viochar); spin_unlock_irqrestore(&consolelock, flags); - return len - bleft; } @@ -557,19 +443,19 @@ static struct port_info *get_port_data(struct tty_struct *tty) */ static void initDataEvent(struct viocharlpevent *viochar, HvLpIndex lp) { + struct HvLpEvent *hev = &viochar->event; + memset(viochar, 0, sizeof(struct viocharlpevent)); - viochar->event.xFlags.xValid = 1; - viochar->event.xFlags.xFunction = HvLpEvent_Function_Int; - viochar->event.xFlags.xAckInd = HvLpEvent_AckInd_NoAck; - viochar->event.xFlags.xAckType = HvLpEvent_AckType_DeferredAck; - viochar->event.xType = HvLpEvent_Type_VirtualIo; - viochar->event.xSubtype = viomajorsubtype_chario | viochardata; - viochar->event.xSourceLp = HvLpConfig_getLpIndex(); - viochar->event.xTargetLp = lp; - viochar->event.xSizeMinus1 = sizeof(struct viocharlpevent); - viochar->event.xSourceInstanceId = viopath_sourceinst(lp); - viochar->event.xTargetInstanceId = viopath_targetinst(lp); + hev->flags = HV_LP_EVENT_VALID | HV_LP_EVENT_DEFERRED_ACK | + HV_LP_EVENT_INT; + hev->xType = HvLpEvent_Type_VirtualIo; + hev->xSubtype = viomajorsubtype_chario | viochardata; + hev->xSourceLp = HvLpConfig_getLpIndex(); + hev->xTargetLp = lp; + hev->xSizeMinus1 = sizeof(struct viocharlpevent); + hev->xSourceInstanceId = viopath_sourceinst(lp); + hev->xTargetInstanceId = viopath_targetinst(lp); } /* @@ -603,18 +489,8 @@ static void viocons_write(struct console *co, const char *s, unsigned count) hvlogOutput(s, count); - if (!viopath_isactive(pi->lp)) { - /* - * This is a VERY noisy trace message in the case where the - * path manager is not active or in the case where this - * function is called prior to viocons initialization. It is - * being commented out for the sake of a clear trace buffer. - */ -#if 0 - hvlog("\n\rviocons_write: path not active to lp %d", pi->lp); -#endif + if (!viopath_isactive(pi->lp)) return; - } /* * Any newline character found will cause a @@ -627,17 +503,16 @@ static void viocons_write(struct console *co, const char *s, unsigned count) * Newline found. Print everything up to and * including the newline */ - internal_write(pi, &s[begin], index - begin + 1, - NULL); + internal_write(pi, &s[begin], index - begin + 1); begin = index + 1; /* Emit a carriage return as well */ - internal_write(pi, &cr, 1, NULL); + internal_write(pi, &cr, 1); } } /* If any characters left to write, write them now */ if ((index - begin) > 0) - internal_write(pi, &s[begin], index - begin, NULL); + internal_write(pi, &s[begin], index - begin); } /* @@ -721,11 +596,9 @@ static void viotty_close(struct tty_struct *tty, struct file *filp) /* * TTY Write method */ -static int viotty_write(struct tty_struct *tty, int from_user, - const unsigned char *buf, int count) +static int viotty_write(struct tty_struct *tty, const unsigned char *buf, + int count) { - int ret; - int total = 0; struct port_info *pi; pi = get_port_data(tty); @@ -746,53 +619,10 @@ static int viotty_write(struct tty_struct *tty, int from_user, * viotty_write call and, since the viopath isn't active to this * partition, return count. */ - if (!viopath_isactive(pi->lp)) { - /* Noisy trace. Commented unless needed. */ -#if 0 - hvlog("\n\rviotty_write: viopath NOT active for lp %d.",pi->lp); -#endif + if (!viopath_isactive(pi->lp)) return count; - } - /* - * If the viotty_write is invoked from user space we want to do the - * copy_from_user() into an event buffer from the cfu buffer before - * internal_write() is called because internal_write may need to buffer - * data which will need to grab a spin_lock and we shouldn't - * copy_from_user() while holding a spin_lock. Should internal_write() - * not need to buffer data then it'll just use the event we created here - * rather than checking one out from vio_get_event_buffer(). - */ - if (from_user) { - struct viocharlpevent *viochar; - int curlen; - const char *curbuf = buf; - - viochar = viocons_get_cfu_buffer(); - if (viochar == NULL) - return -EAGAIN; - initDataEvent(viochar, pi->lp); - while (count > 0) { - if (count > VIOCHAR_MAX_DATA) - curlen = VIOCHAR_MAX_DATA; - else - curlen = count; - viochar->len = curlen; - ret = copy_from_user(viochar->data, curbuf, curlen); - if (ret) - break; - ret = internal_write(pi, viochar->data, - viochar->len, viochar); - total += ret; - if (ret != curlen) - break; - count -= curlen; - curbuf += curlen; - } - viocons_free_cfu_buffer(viochar); - } else - total = internal_write(pi, buf, count, NULL); - return total; + return internal_write(pi, buf, count); } /* @@ -811,7 +641,7 @@ static void viotty_put_char(struct tty_struct *tty, unsigned char ch) hvlogOutput(&ch, 1); if (viopath_isactive(pi->lp)) - internal_write(pi, &ch, 1, NULL); + internal_write(pi, &ch, 1); } /* @@ -889,7 +719,7 @@ static void vioHandleOpenEvent(struct HvLpEvent *event) struct port_info *pi; int reject = 0; - if (event->xFlags.xFunction == HvLpEvent_Function_Ack) { + if (hvlpevent_is_ack(event)) { if (port >= VTTY_PORTS) return; @@ -920,12 +750,12 @@ static void vioHandleOpenEvent(struct HvLpEvent *event) atomic_set(aptr, 1); } else printk(VIOCONS_KERN_WARN - "wierd...got open ack without atomic\n"); + "weird...got open ack without atomic\n"); return; } /* This had better require an ack, otherwise complain */ - if (event->xFlags.xAckInd != HvLpEvent_AckInd_DoAck) { + if (!hvlpevent_need_ack(event)) { printk(VIOCONS_KERN_WARN "viocharopen without ack bit!\n"); return; } @@ -993,7 +823,7 @@ static void vioHandleCloseEvent(struct HvLpEvent *event) struct viocharlpevent *cevent = (struct viocharlpevent *)event; u8 port = cevent->virtual_device; - if (event->xFlags.xFunction == HvLpEvent_Function_Int) { + if (hvlpevent_is_int(event)) { if (port >= VTTY_PORTS) { printk(VIOCONS_KERN_WARN "close message from invalid virtual device.\n"); @@ -1041,6 +871,7 @@ static void vioHandleData(struct HvLpEvent *event) struct viocharlpevent *cevent = (struct viocharlpevent *)event; struct port_info *pi; int index; + int num_pushed; u8 port = cevent->virtual_device; if (port >= VTTY_PORTS) { @@ -1101,9 +932,12 @@ static void vioHandleData(struct HvLpEvent *event) * functionality will only work if built into the kernel and * then only if sysrq is enabled through the proc filesystem. */ + num_pushed = 0; for (index = 0; index < cevent->len; index++) { -#ifdef CONFIG_MAGIC_SYSRQ - if (sysrq_enabled) { + /* + * Will be optimized away if !CONFIG_MAGIC_SYSRQ: + */ + if (sysrq_on()) { /* 0x0f is the ascii character for ^O */ if (cevent->data[index] == '\x0f') { vio_sysrq_pressed = 1; @@ -1113,7 +947,7 @@ static void vioHandleData(struct HvLpEvent *event) */ continue; } else if (vio_sysrq_pressed) { - handle_sysrq(cevent->data[index], NULL, tty); + handle_sysrq(cevent->data[index], tty); vio_sysrq_pressed = 0; /* * continue because we don't want to add @@ -1122,7 +956,6 @@ static void vioHandleData(struct HvLpEvent *event) continue; } } -#endif /* * The sysrq sequence isn't included in this check if * sysrq is enabled and compiled into the kernel because @@ -1130,16 +963,14 @@ static void vioHandleData(struct HvLpEvent *event) * Don't attempt to copy more data into the buffer than we * have room for because it would fail without indication. */ - if ((tty->flip.count + 1) > TTY_FLIPBUF_SIZE) { + if(tty_insert_flip_char(tty, cevent->data[index], TTY_NORMAL) == 0) { printk(VIOCONS_KERN_WARN "input buffer overflow!\n"); break; } - tty_insert_flip_char(tty, cevent->data[index], TTY_NORMAL); + num_pushed++; } - /* if cevent->len == 0 then no data was added to the buffer and flip.count == 0 */ - if (tty->flip.count) - /* The next call resets flip.count when the data is flushed. */ + if (num_pushed) tty_flip_buffer_push(tty); } @@ -1193,8 +1024,7 @@ static void vioHandleCharEvent(struct HvLpEvent *event) vioHandleConfig(event); break; default: - if ((event->xFlags.xFunction == HvLpEvent_Function_Int) && - (event->xFlags.xAckInd == HvLpEvent_AckInd_DoAck)) { + if (hvlpevent_is_int(event) && hvlpevent_need_ack(event)) { event->xRc = HvLpEvent_Rc_InvalidSubtype; HvCallEvent_ackLpEvent(event); } @@ -1216,7 +1046,7 @@ static int send_open(HvLpIndex remoteLp, void *sem) 0, 0, 0, 0); } -static struct tty_operations serial_ops = { +static const struct tty_operations serial_ops = { .open = viotty_open, .close = viotty_close, .write = viotty_write, @@ -1231,6 +1061,9 @@ static int __init viocons_init2(void) atomic_t wait_flag; int rc; + if (!firmware_has_feature(FW_FEATURE_ISERIES)) + return -ENODEV; + /* +2 for fudge */ rc = viopath_open(HvLpConfig_getPrimaryLpIndex(), viomajorsubtype_chario, VIOCHAR_WINDOW + 2); @@ -1290,7 +1123,6 @@ static int __init viocons_init2(void) viotty_driver = alloc_tty_driver(VTTY_PORTS); viotty_driver->owner = THIS_MODULE; viotty_driver->driver_name = "vioconsole"; - viotty_driver->devfs_name = "vcs/"; viotty_driver->name = "tty"; viotty_driver->name_base = 1; viotty_driver->major = TTY_MAJOR; @@ -1307,8 +1139,6 @@ static int __init viocons_init2(void) viotty_driver = NULL; } - viocons_init_cfu_buffer(); - unregister_console(&viocons_early); register_console(&viocons); @@ -1319,12 +1149,16 @@ static int __init viocons_init(void) { int i; + if (!firmware_has_feature(FW_FEATURE_ISERIES)) + return -ENODEV; + printk(VIOCONS_KERN_INFO "registering console\n"); for (i = 0; i < VTTY_PORTS; i++) { port_info[i].lp = HvLpIndexInvalid; port_info[i].magic = VIOTTY_MAGIC; } HvCall_setLogBufferFormatAndCodepage(HvCall_LogBuffer_ASCII, 437); + add_preferred_console("viocons", 0, NULL); register_console(&viocons_early); return 0; }