From 9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00 Mon Sep 17 00:00:00 2001 From: Yunhong Jiang Date: Tue, 4 Aug 2015 12:17:53 -0700 Subject: Add the rt linux 4.1.3-rt3 as base Import the rt linux 4.1.3-rt3 as OPNFV kvm base. It's from git://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-rt-devel.git linux-4.1.y-rt and the base is: commit 0917f823c59692d751951bf5ea699a2d1e2f26a2 Author: Sebastian Andrzej Siewior Date: Sat Jul 25 12:13:34 2015 +0200 Prepare v4.1.3-rt3 Signed-off-by: Sebastian Andrzej Siewior We lose all the git history this way and it's not good. We should apply another opnfv project repo in future. Change-Id: I87543d81c9df70d99c5001fbdf646b202c19f423 Signed-off-by: Yunhong Jiang --- kernel/drivers/staging/unisys/visorchannel/Kconfig | 10 + .../drivers/staging/unisys/visorchannel/Makefile | 12 + .../drivers/staging/unisys/visorchannel/globals.h | 27 + .../staging/unisys/visorchannel/visorchannel.h | 76 +++ .../unisys/visorchannel/visorchannel_funcs.c | 665 +++++++++++++++++++++ .../unisys/visorchannel/visorchannel_main.c | 50 ++ 6 files changed, 840 insertions(+) create mode 100644 kernel/drivers/staging/unisys/visorchannel/Kconfig create mode 100644 kernel/drivers/staging/unisys/visorchannel/Makefile create mode 100644 kernel/drivers/staging/unisys/visorchannel/globals.h create mode 100644 kernel/drivers/staging/unisys/visorchannel/visorchannel.h create mode 100644 kernel/drivers/staging/unisys/visorchannel/visorchannel_funcs.c create mode 100644 kernel/drivers/staging/unisys/visorchannel/visorchannel_main.c (limited to 'kernel/drivers/staging/unisys/visorchannel') diff --git a/kernel/drivers/staging/unisys/visorchannel/Kconfig b/kernel/drivers/staging/unisys/visorchannel/Kconfig new file mode 100644 index 000000000..8d31bebf0 --- /dev/null +++ b/kernel/drivers/staging/unisys/visorchannel/Kconfig @@ -0,0 +1,10 @@ +# +# Unisys visorchannel configuration +# + +config UNISYS_VISORCHANNEL + tristate "Unisys visorchannel driver" + select UNISYS_VISORUTIL + ---help--- + If you say Y here, you will enable the Unisys visorchannel driver. + diff --git a/kernel/drivers/staging/unisys/visorchannel/Makefile b/kernel/drivers/staging/unisys/visorchannel/Makefile new file mode 100644 index 000000000..e079c96b1 --- /dev/null +++ b/kernel/drivers/staging/unisys/visorchannel/Makefile @@ -0,0 +1,12 @@ +# +# Makefile for Unisys visorchannel +# + +obj-$(CONFIG_UNISYS_VISORCHANNEL) += visorchannel.o + +visorchannel-y := visorchannel_main.o visorchannel_funcs.o + +ccflags-y += -Idrivers/staging/unisys/include +ccflags-y += -Idrivers/staging/unisys/common-spar/include +ccflags-y += -Idrivers/staging/unisys/common-spar/include/channels +ccflags-y += -Idrivers/staging/unisys/visorutil diff --git a/kernel/drivers/staging/unisys/visorchannel/globals.h b/kernel/drivers/staging/unisys/visorchannel/globals.h new file mode 100644 index 000000000..0ed8e1d80 --- /dev/null +++ b/kernel/drivers/staging/unisys/visorchannel/globals.h @@ -0,0 +1,27 @@ +/* globals.h + * + * Copyright (C) 2010 - 2013 UNISYS CORPORATION + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + */ + +#ifndef __VISORCHANNEL_GLOBALS_H__ +#define __VISORCHANNEL_GLOBALS_H__ + +#include "timskmod.h" +#include "memregion.h" +#include "version.h" + +#define MYDRVNAME "visorchannel" + +#endif diff --git a/kernel/drivers/staging/unisys/visorchannel/visorchannel.h b/kernel/drivers/staging/unisys/visorchannel/visorchannel.h new file mode 100644 index 000000000..63f1b9760 --- /dev/null +++ b/kernel/drivers/staging/unisys/visorchannel/visorchannel.h @@ -0,0 +1,76 @@ +/* visorchannel.h + * + * Copyright (C) 2010 - 2013 UNISYS CORPORATION + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + */ + +#ifndef __VISORCHANNEL_H__ +#define __VISORCHANNEL_H__ + +#include + +#include "memregion.h" +#include "channel.h" +#ifndef HOSTADDRESS +#define HOSTADDRESS u64 +#endif +#ifndef BOOL +#define BOOL int +#endif + +/* Note that for visorchannel_create() and visorchannel_create_overlapped(), + * and arguments may be 0 if we are a channel CLIENT. + * In this case, the values can simply be read from the channel header. + */ +struct visorchannel *visorchannel_create(HOSTADDRESS physaddr, + ulong channel_bytes, uuid_le guid); +struct visorchannel *visorchannel_create_overlapped(ulong channel_bytes, + struct visorchannel *parent, + ulong off, uuid_le guid); +struct visorchannel *visorchannel_create_with_lock(HOSTADDRESS physaddr, + ulong channel_bytes, + uuid_le guid); +struct visorchannel *visorchannel_create_overlapped_with_lock( + ulong channel_bytes, + struct visorchannel *parent, + ulong off, uuid_le guid); +void visorchannel_destroy(struct visorchannel *channel); +int visorchannel_read(struct visorchannel *channel, ulong offset, + void *local, ulong nbytes); +int visorchannel_write(struct visorchannel *channel, ulong offset, + void *local, ulong nbytes); +int visorchannel_clear(struct visorchannel *channel, ulong offset, + u8 ch, ulong nbytes); +BOOL visorchannel_signalremove(struct visorchannel *channel, u32 queue, + void *msg); +BOOL visorchannel_signalinsert(struct visorchannel *channel, u32 queue, + void *msg); +int visorchannel_signalqueue_slots_avail(struct visorchannel *channel, + u32 queue); +int visorchannel_signalqueue_max_slots(struct visorchannel *channel, u32 queue); +HOSTADDRESS visorchannel_get_physaddr(struct visorchannel *channel); +ulong visorchannel_get_nbytes(struct visorchannel *channel); +char *visorchannel_id(struct visorchannel *channel, char *s); +char *visorchannel_zoneid(struct visorchannel *channel, char *s); +u64 visorchannel_get_clientpartition(struct visorchannel *channel); +uuid_le visorchannel_get_uuid(struct visorchannel *channel); +struct memregion *visorchannel_get_memregion(struct visorchannel *channel); +char *visorchannel_uuid_id(uuid_le *guid, char *s); +void visorchannel_debug(struct visorchannel *channel, int num_queues, + struct seq_file *seq, u32 off); +void visorchannel_dump_section(struct visorchannel *chan, char *s, + int off, int len, struct seq_file *seq); +void __iomem *visorchannel_get_header(struct visorchannel *channel); + +#endif diff --git a/kernel/drivers/staging/unisys/visorchannel/visorchannel_funcs.c b/kernel/drivers/staging/unisys/visorchannel/visorchannel_funcs.c new file mode 100644 index 000000000..7a9a7242f --- /dev/null +++ b/kernel/drivers/staging/unisys/visorchannel/visorchannel_funcs.c @@ -0,0 +1,665 @@ +/* visorchannel_funcs.c + * + * Copyright (C) 2010 - 2013 UNISYS CORPORATION + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + */ + +/* + * This provides Supervisor channel communication primitives, which are + * independent of the mechanism used to access the channel data. All channel + * data is accessed using the memregion abstraction. (memregion has both + * a CM2 implementation and a direct memory implementation.) + */ + +#include "globals.h" +#include "visorchannel.h" +#include + +#define MYDRVNAME "visorchannel" + +struct visorchannel { + struct memregion *memregion; /* from visor_memregion_create() */ + struct channel_header chan_hdr; + uuid_le guid; + ulong size; + BOOL needs_lock; /* channel creator knows if more than one + * thread will be inserting or removing */ + spinlock_t insert_lock; /* protect head writes in chan_hdr */ + spinlock_t remove_lock; /* protect tail writes in chan_hdr */ + + struct { + struct signal_queue_header req_queue; + struct signal_queue_header rsp_queue; + struct signal_queue_header event_queue; + struct signal_queue_header ack_queue; + } safe_uis_queue; +}; + +/* Creates the struct visorchannel abstraction for a data area in memory, + * but does NOT modify this data area. + */ +static struct visorchannel * +visorchannel_create_guts(HOSTADDRESS physaddr, ulong channel_bytes, + struct visorchannel *parent, ulong off, uuid_le guid, + BOOL needs_lock) +{ + struct visorchannel *p = NULL; + void *rc = NULL; + + p = kmalloc(sizeof(*p), GFP_KERNEL|__GFP_NORETRY); + if (!p) { + rc = NULL; + goto cleanup; + } + p->memregion = NULL; + p->needs_lock = needs_lock; + spin_lock_init(&p->insert_lock); + spin_lock_init(&p->remove_lock); + + /* prepare chan_hdr (abstraction to read/write channel memory) */ + if (!parent) + p->memregion = + visor_memregion_create(physaddr, + sizeof(struct channel_header)); + else + p->memregion = + visor_memregion_create_overlapped(parent->memregion, + off, sizeof(struct channel_header)); + if (!p->memregion) { + rc = NULL; + goto cleanup; + } + if (visor_memregion_read(p->memregion, 0, &p->chan_hdr, + sizeof(struct channel_header)) < 0) { + rc = NULL; + goto cleanup; + } + if (channel_bytes == 0) + /* we had better be a CLIENT of this channel */ + channel_bytes = (ulong)p->chan_hdr.size; + if (uuid_le_cmp(guid, NULL_UUID_LE) == 0) + /* we had better be a CLIENT of this channel */ + guid = p->chan_hdr.chtype; + if (visor_memregion_resize(p->memregion, channel_bytes) < 0) { + rc = NULL; + goto cleanup; + } + p->size = channel_bytes; + p->guid = guid; + + rc = p; +cleanup: + + if (!rc) { + if (!p) { + visorchannel_destroy(p); + p = NULL; + } + } + return rc; +} + +struct visorchannel * +visorchannel_create(HOSTADDRESS physaddr, ulong channel_bytes, uuid_le guid) +{ + return visorchannel_create_guts(physaddr, channel_bytes, NULL, 0, guid, + FALSE); +} +EXPORT_SYMBOL_GPL(visorchannel_create); + +struct visorchannel * +visorchannel_create_with_lock(HOSTADDRESS physaddr, ulong channel_bytes, + uuid_le guid) +{ + return visorchannel_create_guts(physaddr, channel_bytes, NULL, 0, guid, + TRUE); +} +EXPORT_SYMBOL_GPL(visorchannel_create_with_lock); + +struct visorchannel * +visorchannel_create_overlapped(ulong channel_bytes, + struct visorchannel *parent, ulong off, + uuid_le guid) +{ + return visorchannel_create_guts(0, channel_bytes, parent, off, guid, + FALSE); +} +EXPORT_SYMBOL_GPL(visorchannel_create_overlapped); + +struct visorchannel * +visorchannel_create_overlapped_with_lock(ulong channel_bytes, + struct visorchannel *parent, ulong off, + uuid_le guid) +{ + return visorchannel_create_guts(0, channel_bytes, parent, off, guid, + TRUE); +} +EXPORT_SYMBOL_GPL(visorchannel_create_overlapped_with_lock); + +void +visorchannel_destroy(struct visorchannel *channel) +{ + if (!channel) + return; + if (channel->memregion) { + visor_memregion_destroy(channel->memregion); + channel->memregion = NULL; + } + kfree(channel); +} +EXPORT_SYMBOL_GPL(visorchannel_destroy); + +HOSTADDRESS +visorchannel_get_physaddr(struct visorchannel *channel) +{ + return visor_memregion_get_physaddr(channel->memregion); +} +EXPORT_SYMBOL_GPL(visorchannel_get_physaddr); + +ulong +visorchannel_get_nbytes(struct visorchannel *channel) +{ + return channel->size; +} +EXPORT_SYMBOL_GPL(visorchannel_get_nbytes); + +char * +visorchannel_uuid_id(uuid_le *guid, char *s) +{ + sprintf(s, "%pUL", guid); + return s; +} +EXPORT_SYMBOL_GPL(visorchannel_uuid_id); + +char * +visorchannel_id(struct visorchannel *channel, char *s) +{ + return visorchannel_uuid_id(&channel->guid, s); +} +EXPORT_SYMBOL_GPL(visorchannel_id); + +char * +visorchannel_zoneid(struct visorchannel *channel, char *s) +{ + return visorchannel_uuid_id(&channel->chan_hdr.zone_uuid, s); +} +EXPORT_SYMBOL_GPL(visorchannel_zoneid); + +HOSTADDRESS +visorchannel_get_clientpartition(struct visorchannel *channel) +{ + return channel->chan_hdr.partition_handle; +} +EXPORT_SYMBOL_GPL(visorchannel_get_clientpartition); + +uuid_le +visorchannel_get_uuid(struct visorchannel *channel) +{ + return channel->guid; +} +EXPORT_SYMBOL_GPL(visorchannel_get_uuid); + +struct memregion * +visorchannel_get_memregion(struct visorchannel *channel) +{ + return channel->memregion; +} +EXPORT_SYMBOL_GPL(visorchannel_get_memregion); + +int +visorchannel_read(struct visorchannel *channel, ulong offset, + void *local, ulong nbytes) +{ + int rc = visor_memregion_read(channel->memregion, offset, + local, nbytes); + if ((rc >= 0) && (offset == 0) && + (nbytes >= sizeof(struct channel_header))) { + memcpy(&channel->chan_hdr, local, + sizeof(struct channel_header)); + } + return rc; +} +EXPORT_SYMBOL_GPL(visorchannel_read); + +int +visorchannel_write(struct visorchannel *channel, ulong offset, + void *local, ulong nbytes) +{ + if (offset == 0 && nbytes >= sizeof(struct channel_header)) + memcpy(&channel->chan_hdr, local, + sizeof(struct channel_header)); + return visor_memregion_write(channel->memregion, offset, local, nbytes); +} +EXPORT_SYMBOL_GPL(visorchannel_write); + +int +visorchannel_clear(struct visorchannel *channel, ulong offset, u8 ch, + ulong nbytes) +{ + int rc = -1; + int bufsize = 65536; + int written = 0; + u8 *buf = vmalloc(bufsize); + + if (!buf) + goto cleanup; + + memset(buf, ch, bufsize); + while (nbytes > 0) { + ulong thisbytes = bufsize; + int x = -1; + + if (nbytes < thisbytes) + thisbytes = nbytes; + x = visor_memregion_write(channel->memregion, offset + written, + buf, thisbytes); + if (x < 0) { + rc = x; + goto cleanup; + } + written += thisbytes; + nbytes -= thisbytes; + } + rc = 0; + +cleanup: + if (buf) { + vfree(buf); + buf = NULL; + } + return rc; +} +EXPORT_SYMBOL_GPL(visorchannel_clear); + +void __iomem * +visorchannel_get_header(struct visorchannel *channel) +{ + return (void __iomem *)&channel->chan_hdr; +} +EXPORT_SYMBOL_GPL(visorchannel_get_header); + +/** Return offset of a specific SIGNAL_QUEUE_HEADER from the beginning of a + * channel header + */ +#define SIG_QUEUE_OFFSET(chan_hdr, q) \ + ((chan_hdr)->ch_space_offset + \ + ((q) * sizeof(struct signal_queue_header))) + +/** Return offset of a specific queue entry (data) from the beginning of a + * channel header + */ +#define SIG_DATA_OFFSET(chan_hdr, q, sig_hdr, slot) \ + (SIG_QUEUE_OFFSET(chan_hdr, q) + (sig_hdr)->sig_base_offset + \ + ((slot) * (sig_hdr)->signal_size)) + +/** Write the contents of a specific field within a SIGNAL_QUEUE_HEADER back + * into host memory + */ +#define SIG_WRITE_FIELD(channel, queue, sig_hdr, FIELD) \ + (visor_memregion_write(channel->memregion, \ + SIG_QUEUE_OFFSET(&channel->chan_hdr, queue)+ \ + offsetof(struct signal_queue_header, FIELD),\ + &((sig_hdr)->FIELD), \ + sizeof((sig_hdr)->FIELD)) >= 0) + +static BOOL +sig_read_header(struct visorchannel *channel, u32 queue, + struct signal_queue_header *sig_hdr) +{ + BOOL rc = FALSE; + + if (channel->chan_hdr.ch_space_offset < sizeof(struct channel_header)) + goto cleanup; + + /* Read the appropriate SIGNAL_QUEUE_HEADER into local memory. */ + + if (visor_memregion_read(channel->memregion, + SIG_QUEUE_OFFSET(&channel->chan_hdr, queue), + sig_hdr, + sizeof(struct signal_queue_header)) < 0) { + goto cleanup; + } + rc = TRUE; +cleanup: + return rc; +} + +static BOOL +sig_do_data(struct visorchannel *channel, u32 queue, + struct signal_queue_header *sig_hdr, u32 slot, void *data, + BOOL is_write) +{ + BOOL rc = FALSE; + int signal_data_offset = SIG_DATA_OFFSET(&channel->chan_hdr, queue, + sig_hdr, slot); + if (is_write) { + if (visor_memregion_write(channel->memregion, + signal_data_offset, + data, sig_hdr->signal_size) < 0) { + goto cleanup; + } + } else { + if (visor_memregion_read(channel->memregion, signal_data_offset, + data, sig_hdr->signal_size) < 0) { + goto cleanup; + } + } + rc = TRUE; +cleanup: + return rc; +} + +static inline BOOL +sig_read_data(struct visorchannel *channel, u32 queue, + struct signal_queue_header *sig_hdr, u32 slot, void *data) +{ + return sig_do_data(channel, queue, sig_hdr, slot, data, FALSE); +} + +static inline BOOL +sig_write_data(struct visorchannel *channel, u32 queue, + struct signal_queue_header *sig_hdr, u32 slot, void *data) +{ + return sig_do_data(channel, queue, sig_hdr, slot, data, TRUE); +} + +static inline unsigned char +safe_sig_queue_validate(struct signal_queue_header *psafe_sqh, + struct signal_queue_header *punsafe_sqh, + u32 *phead, u32 *ptail) +{ + if ((*phead >= psafe_sqh->max_slots) || + (*ptail >= psafe_sqh->max_slots)) { + /* Choose 0 or max, maybe based on current tail value */ + *phead = 0; + *ptail = 0; + + /* Sync with client as necessary */ + punsafe_sqh->head = *phead; + punsafe_sqh->tail = *ptail; + + return 0; + } + return 1; +} /* end safe_sig_queue_validate */ + +static BOOL +signalremove_inner(struct visorchannel *channel, u32 queue, void *msg) +{ + struct signal_queue_header sig_hdr; + + if (!sig_read_header(channel, queue, &sig_hdr)) + return FALSE; + if (sig_hdr.head == sig_hdr.tail) + return FALSE; /* no signals to remove */ + + sig_hdr.tail = (sig_hdr.tail + 1) % sig_hdr.max_slots; + if (!sig_read_data(channel, queue, &sig_hdr, sig_hdr.tail, msg)) { + return FALSE; + } + sig_hdr.num_received++; + + /* For each data field in SIGNAL_QUEUE_HEADER that was modified, + * update host memory. + */ + mb(); /* required for channel synch */ + if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, tail)) + return FALSE; + if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, num_received)) + return FALSE; + return TRUE; +} + +BOOL +visorchannel_signalremove(struct visorchannel *channel, u32 queue, void *msg) +{ + BOOL rc; + + if (channel->needs_lock) { + spin_lock(&channel->remove_lock); + rc = signalremove_inner(channel, queue, msg); + spin_unlock(&channel->remove_lock); + } else { + rc = signalremove_inner(channel, queue, msg); + } + + return rc; +} +EXPORT_SYMBOL_GPL(visorchannel_signalremove); + +static BOOL +signalinsert_inner(struct visorchannel *channel, u32 queue, void *msg) +{ + struct signal_queue_header sig_hdr; + + if (!sig_read_header(channel, queue, &sig_hdr)) + return FALSE; + + sig_hdr.head = ((sig_hdr.head + 1) % sig_hdr.max_slots); + if (sig_hdr.head == sig_hdr.tail) { + sig_hdr.num_overflows++; + visor_memregion_write(channel->memregion, + SIG_QUEUE_OFFSET(&channel->chan_hdr, + queue) + + offsetof(struct signal_queue_header, + num_overflows), + &(sig_hdr.num_overflows), + sizeof(sig_hdr.num_overflows)); + return FALSE; + } + + if (!sig_write_data(channel, queue, &sig_hdr, sig_hdr.head, msg)) + return FALSE; + + sig_hdr.num_sent++; + + /* For each data field in SIGNAL_QUEUE_HEADER that was modified, + * update host memory. + */ + mb(); /* required for channel synch */ + if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, head)) + return FALSE; + if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, num_sent)) { + return FALSE; + } + + return TRUE; +} + +BOOL +visorchannel_signalinsert(struct visorchannel *channel, u32 queue, void *msg) +{ + BOOL rc; + + if (channel->needs_lock) { + spin_lock(&channel->insert_lock); + rc = signalinsert_inner(channel, queue, msg); + spin_unlock(&channel->insert_lock); + } else { + rc = signalinsert_inner(channel, queue, msg); + } + + return rc; +} +EXPORT_SYMBOL_GPL(visorchannel_signalinsert); + +int +visorchannel_signalqueue_slots_avail(struct visorchannel *channel, u32 queue) +{ + struct signal_queue_header sig_hdr; + u32 slots_avail, slots_used; + u32 head, tail; + + if (!sig_read_header(channel, queue, &sig_hdr)) + return 0; + head = sig_hdr.head; + tail = sig_hdr.tail; + if (head < tail) + head = head + sig_hdr.max_slots; + slots_used = (head - tail); + slots_avail = sig_hdr.max_signals - slots_used; + return (int)slots_avail; +} +EXPORT_SYMBOL_GPL(visorchannel_signalqueue_slots_avail); + +int +visorchannel_signalqueue_max_slots(struct visorchannel *channel, u32 queue) +{ + struct signal_queue_header sig_hdr; + + if (!sig_read_header(channel, queue, &sig_hdr)) + return 0; + return (int)sig_hdr.max_signals; +} +EXPORT_SYMBOL_GPL(visorchannel_signalqueue_max_slots); + +static void +sigqueue_debug(struct signal_queue_header *q, int which, struct seq_file *seq) +{ + seq_printf(seq, "Signal Queue #%d\n", which); + seq_printf(seq, " VersionId = %lu\n", (ulong)q->version); + seq_printf(seq, " Type = %lu\n", (ulong)q->chtype); + seq_printf(seq, " oSignalBase = %llu\n", + (long long)q->sig_base_offset); + seq_printf(seq, " SignalSize = %lu\n", (ulong)q->signal_size); + seq_printf(seq, " MaxSignalSlots = %lu\n", + (ulong)q->max_slots); + seq_printf(seq, " MaxSignals = %lu\n", (ulong)q->max_signals); + seq_printf(seq, " FeatureFlags = %-16.16Lx\n", + (long long)q->features); + seq_printf(seq, " NumSignalsSent = %llu\n", + (long long)q->num_sent); + seq_printf(seq, " NumSignalsReceived = %llu\n", + (long long)q->num_received); + seq_printf(seq, " NumOverflows = %llu\n", + (long long)q->num_overflows); + seq_printf(seq, " Head = %lu\n", (ulong)q->head); + seq_printf(seq, " Tail = %lu\n", (ulong)q->tail); +} + +void +visorchannel_debug(struct visorchannel *channel, int num_queues, + struct seq_file *seq, u32 off) +{ + HOSTADDRESS addr = 0; + ulong nbytes = 0, nbytes_region = 0; + struct memregion *memregion = NULL; + struct channel_header hdr; + struct channel_header *phdr = &hdr; + int i = 0; + int errcode = 0; + + if (!channel) + return; + memregion = channel->memregion; + if (!memregion) + return; + + addr = visor_memregion_get_physaddr(memregion); + nbytes_region = visor_memregion_get_nbytes(memregion); + errcode = visorchannel_read(channel, off, + phdr, sizeof(struct channel_header)); + if (errcode < 0) { + seq_printf(seq, + "Read of channel header failed with errcode=%d)\n", + errcode); + if (off == 0) { + phdr = &channel->chan_hdr; + seq_puts(seq, "(following data may be stale)\n"); + } else { + return; + } + } + nbytes = (ulong)(phdr->size); + seq_printf(seq, "--- Begin channel @0x%-16.16Lx for 0x%lx bytes (region=0x%lx bytes) ---\n", + addr + off, nbytes, nbytes_region); + seq_printf(seq, "Type = %pUL\n", &phdr->chtype); + seq_printf(seq, "ZoneGuid = %pUL\n", &phdr->zone_uuid); + seq_printf(seq, "Signature = 0x%-16.16Lx\n", + (long long)phdr->signature); + seq_printf(seq, "LegacyState = %lu\n", (ulong)phdr->legacy_state); + seq_printf(seq, "SrvState = %lu\n", (ulong)phdr->srv_state); + seq_printf(seq, "CliStateBoot = %lu\n", (ulong)phdr->cli_state_boot); + seq_printf(seq, "CliStateOS = %lu\n", (ulong)phdr->cli_state_os); + seq_printf(seq, "HeaderSize = %lu\n", (ulong)phdr->header_size); + seq_printf(seq, "Size = %llu\n", (long long)phdr->size); + seq_printf(seq, "Features = 0x%-16.16llx\n", + (long long)phdr->features); + seq_printf(seq, "PartitionHandle = 0x%-16.16llx\n", + (long long)phdr->partition_handle); + seq_printf(seq, "Handle = 0x%-16.16llx\n", + (long long)phdr->handle); + seq_printf(seq, "VersionId = %lu\n", (ulong)phdr->version_id); + seq_printf(seq, "oChannelSpace = %llu\n", + (long long)phdr->ch_space_offset); + if ((phdr->ch_space_offset == 0) || (errcode < 0)) + ; + else + for (i = 0; i < num_queues; i++) { + struct signal_queue_header q; + + errcode = visorchannel_read(channel, + off + + phdr->ch_space_offset + + (i * sizeof(q)), + &q, sizeof(q)); + if (errcode < 0) { + seq_printf(seq, + "failed to read signal queue #%d from channel @0x%-16.16Lx errcode=%d\n", + i, addr, errcode); + continue; + } + sigqueue_debug(&q, i, seq); + } + seq_printf(seq, "--- End channel @0x%-16.16Lx for 0x%lx bytes ---\n", + addr + off, nbytes); +} +EXPORT_SYMBOL_GPL(visorchannel_debug); + +void +visorchannel_dump_section(struct visorchannel *chan, char *s, + int off, int len, struct seq_file *seq) +{ + char *buf, *tbuf, *fmtbuf; + int fmtbufsize = 0; + int i; + int errcode = 0; + + fmtbufsize = 100 * COVQ(len, 16); + buf = kmalloc(len, GFP_KERNEL|__GFP_NORETRY); + if (!buf) + return; + fmtbuf = kmalloc(fmtbufsize, GFP_KERNEL|__GFP_NORETRY); + if (!fmtbuf) + goto fmt_failed; + + errcode = visorchannel_read(chan, off, buf, len); + if (errcode < 0) + goto read_failed; + seq_printf(seq, "channel %s:\n", s); + tbuf = buf; + while (len > 0) { + i = (len < 16) ? len : 16; + hex_dump_to_buffer(tbuf, i, 16, 1, fmtbuf, fmtbufsize, TRUE); + seq_printf(seq, "%s\n", fmtbuf); + tbuf += 16; + len -= 16; + } + +read_failed: + kfree(fmtbuf); +fmt_failed: + kfree(buf); +} +EXPORT_SYMBOL_GPL(visorchannel_dump_section); diff --git a/kernel/drivers/staging/unisys/visorchannel/visorchannel_main.c b/kernel/drivers/staging/unisys/visorchannel/visorchannel_main.c new file mode 100644 index 000000000..787d4774b --- /dev/null +++ b/kernel/drivers/staging/unisys/visorchannel/visorchannel_main.c @@ -0,0 +1,50 @@ +/* visorchannel_main.c + * + * Copyright (C) 2010 - 2013 UNISYS CORPORATION + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + */ + +/* + * This is a module "wrapper" around visorchannel_funcs. + */ + +#include "globals.h" +#include "channel.h" +#include "visorchannel.h" +#include + +#define MYDRVNAME "visorchannel" + +static int __init +visorchannel_init(void) +{ + if (!unisys_spar_platform) + return -ENODEV; + + return 0; +} + +static void +visorchannel_exit(void) +{ +} + +module_init(visorchannel_init); +module_exit(visorchannel_exit); + +MODULE_AUTHOR("Unisys"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Supervisor channel driver for service partition: ver " + VERSION); +MODULE_VERSION(VERSION); -- cgit 1.2.3-korg