* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <linux/config.h>
-#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/errno.h>
#include <linux/tty_flip.h>
#include <linux/sysrq.h>
-#include <asm/iSeries/vio.h>
+#include <asm/iseries/vio.h>
-#include <asm/iSeries/HvLpEvent.h>
-#include <asm/iSeries/HvCallEvent.h>
-#include <asm/iSeries/HvLpConfig.h>
-#include <asm/iSeries/HvCall.h>
+#include <asm/iseries/hv_lp_event.h>
+#include <asm/iseries/hv_call_event.h>
+#include <asm/iseries/hv_lp_config.h>
+#include <asm/iseries/hv_call.h>
#ifdef CONFIG_VT
#error You must turn off CONFIG_VT to use CONFIG_VIOCONS
#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;
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
static struct tty_driver *viotty_driver;
-void hvlog(char *fmt, ...)
+static void hvlog(char *fmt, ...)
{
int i;
unsigned long flags;
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;
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.
*
* 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
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;
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;
}
/* 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;
}
*/
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);
}
/*
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
* 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);
}
/*
/*
* 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);
* 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);
}
/*
hvlogOutput(&ch, 1);
if (viopath_isactive(pi->lp))
- internal_write(pi, &ch, 1, NULL);
+ internal_write(pi, &ch, 1);
}
/*
struct port_info *pi;
int reject = 0;
- if (event->xFlags.xFunction == HvLpEvent_Function_Ack) {
+ if (hvlpevent_is_ack(event)) {
if (port >= VTTY_PORTS)
return;
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;
}
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");
struct viocharlpevent *cevent = (struct viocharlpevent *)event;
struct port_info *pi;
int index;
+ int num_pushed;
u8 port = cevent->virtual_device;
if (port >= VTTY_PORTS) {
* 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) {
* 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);
}
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);
}
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;
viotty_driver = NULL;
}
- viocons_init_cfu_buffer();
-
unregister_console(&viocons_early);
register_console(&viocons);