[PATCH] staging: unisys: add visorclientbus driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Benjamin Romer <benjamin.romer@xxxxxxxxxx>

This patch adds the visorclientbus driver to the Unisys s-Par driver set. This
driver is responsible for helping manage virtual devices like keyboards, mice,
serial ports, displays, and any customized drivers for special-purpose guests.

Signed-off-by: Benjamin Romer <benjamin.romer@xxxxxxxxxx>
Signed-off-by: Ken Cox <jkc@xxxxxxxxxx>
---
 drivers/staging/unisys/Kconfig                     |   1 +
 drivers/staging/unisys/Makefile                    |   1 +
 drivers/staging/unisys/visorclientbus/Kconfig      |   9 +
 drivers/staging/unisys/visorclientbus/Makefile     |  13 +
 .../unisys/visorclientbus/visorclientbus_main.c    | 378 +++++++++++++++++++++
 5 files changed, 402 insertions(+)
 create mode 100644 drivers/staging/unisys/visorclientbus/Kconfig
 create mode 100644 drivers/staging/unisys/visorclientbus/Makefile
 create mode 100644 drivers/staging/unisys/visorclientbus/visorclientbus_main.c

diff --git a/drivers/staging/unisys/Kconfig b/drivers/staging/unisys/Kconfig
index ac080c9..d63b035 100644
--- a/drivers/staging/unisys/Kconfig
+++ b/drivers/staging/unisys/Kconfig
@@ -16,5 +16,6 @@ source "drivers/staging/unisys/channels/Kconfig"
 source "drivers/staging/unisys/uislib/Kconfig"
 source "drivers/staging/unisys/virtpci/Kconfig"
 source "drivers/staging/unisys/virthba/Kconfig"
+source "drivers/staging/unisys/visorclientbus/Kconfig"
 
 endif # UNISYSSPAR
diff --git a/drivers/staging/unisys/Makefile b/drivers/staging/unisys/Makefile
index b988d69..794177b 100644
--- a/drivers/staging/unisys/Makefile
+++ b/drivers/staging/unisys/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_UNISYS_CHANNELSTUB)	+= channels/
 obj-$(CONFIG_UNISYS_UISLIB)		+= uislib/
 obj-$(CONFIG_UNISYS_VIRTPCI)		+= virtpci/
 obj-$(CONFIG_UNISYS_VIRTHBA)		+= virthba/
+obj-$(CONFIG_UNISYS_VISORCLIENTBUS)	+= visorclientbus/
diff --git a/drivers/staging/unisys/visorclientbus/Kconfig b/drivers/staging/unisys/visorclientbus/Kconfig
new file mode 100644
index 0000000..62bdbb9
--- /dev/null
+++ b/drivers/staging/unisys/visorclientbus/Kconfig
@@ -0,0 +1,9 @@
+#
+# Unisys visorclientbus configuration
+#
+
+config UNISYS_VISORCLIENTBUS
+	tristate "Unisys visorclientbus driver"
+	depends on UNISYSSPAR && UNISYS_VISORCHIPSET && UNISYS_UISLIB
+	---help---
+	If you say Y here, you will enable the Unisys visorclientbus driver.
diff --git a/drivers/staging/unisys/visorclientbus/Makefile b/drivers/staging/unisys/visorclientbus/Makefile
new file mode 100644
index 0000000..bfacc0d
--- /dev/null
+++ b/drivers/staging/unisys/visorclientbus/Makefile
@@ -0,0 +1,13 @@
+#
+# Makefile for Unisys visorclientbus
+#
+
+obj-$(CONFIG_UNISYS_VISORCLIENTBUS)	+= visorclientbus.o
+
+visorclientbus-y := visorclientbus_main.o
+
+ccflags-y += -Idrivers/staging/unisys/include
+ccflags-y += -Idrivers/staging/unisys/uislib
+ccflags-y += -Idrivers/staging/unisys/visorchipset
+ccflags-y += -Idrivers/staging/unisys/common-spar/include
+ccflags-y += -Idrivers/staging/unisys/common-spar/include/channels
diff --git a/drivers/staging/unisys/visorclientbus/visorclientbus_main.c b/drivers/staging/unisys/visorclientbus/visorclientbus_main.c
new file mode 100644
index 0000000..0c560a1
--- /dev/null
+++ b/drivers/staging/unisys/visorclientbus/visorclientbus_main.c
@@ -0,0 +1,378 @@
+/* visorclientbus_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 module processes bus+device messages received for devices which we are
+ *  to act as a client for.  Currently the only device for which we can act
+ *  as a client is VNIC.
+ */
+
+#include "timskmod.h"
+#include "visorchipset.h"
+#include "uisutils.h"
+#include "iochannel.h"
+#include "version.h"
+#include "guestlinuxdebug.h"
+#include <linux/mm.h>
+
+#define CURRENT_FILE_PC VISOR_CLIENT_BUS_PC_visorclientbus_main_c
+#define MYDRVNAME "visorclientbus"
+
+static int dump_vhba_bus = -1;
+
+static void chipset_bus_create(ulong bus_no);
+static void chipset_bus_destroy(ulong bus_no);
+
+static void chipset_device_create(ulong bus_no, ulong dev_no);
+static void chipset_device_destroy(ulong bus_no, ulong dev_no);
+static void chipset_device_pause(ulong bus_no, ulong dev_no);
+static void chipset_device_resume(ulong bus_no, ulong dev_no);
+
+/* These functions are implemented herein, and are called by the chipset
+ * driver to notify us about specific events.
+ */
+static struct visorchipset_busdev_notifiers chipset_notifiers = {
+	.bus_create = chipset_bus_create,
+	.bus_destroy = chipset_bus_destroy,
+	.device_create = chipset_device_create,
+	.device_destroy = chipset_device_destroy,
+	.device_pause = chipset_device_pause,
+	.device_resume = chipset_device_resume,
+	.get_channel_info = NULL,
+};
+
+/* These functions are implemented in the chipset driver, and we call them
+ * herein when we want to acknowledge a specific event.
+ */
+static struct visorchipset_busdev_responders chipset_responders;
+
+/* filled in with info about parent chipset driver when we register with it */
+static struct ultra_vbus_deviceinfo chipset_driver_info;
+
+static void __iomem *
+get_virt(u64 phys_addr, u32 bytes, enum visorchipset_addresstype addr_type)
+{
+	struct resource *tmp, **p;
+	struct resource *root = NULL;
+	void __iomem  *pcpy = NULL;
+
+	if (addr_type == ADDRTYPE_LOCALTEST) {
+		if (phys_addr > virt_to_phys(high_memory - 1)) {
+			ERRDRV("%s - bad localTest address for channel (0x%-16.16Lx for %lu bytes)",
+			       __func__,
+			       (unsigned long long)phys_addr, (ulong)bytes);
+			return NULL;
+		}
+		return (void __iomem *)__va(phys_addr);
+	} else if (addr_type == ADDRTYPE_LOCALPHYSICAL) {
+		/* walk through the "iomem_resource" tables, check the requested
+		 * channel addresses is in RESERVED or UNDEFINED/AVAILABLE or
+		 * greater than HIGH_MEMORY.  If channel addresses is TRUE with
+		 * the above mentioned scenario, then use ioremap_cache to get a
+		 * valid pointer otherwise return NULL. */
+		root = &iomem_resource;	/* Root node, Global var */
+		p = &root->child;
+		for (;;) {
+			tmp = *p;
+			if (!tmp || tmp->start > (phys_addr + bytes - 1)) {
+				/* Memory region is undefined */
+				break;
+			}
+			p = &tmp->sibling;
+			if (tmp->end < phys_addr) /* start */
+				continue;
+
+			if (phys_addr <= virt_to_phys(high_memory - 1)) {
+				/* Memory is reserved and within HIGH_MEMORY */
+				ERRDRV("%s - localPhysical address overlaps memory our OS is currently using! (0x%-16.16Lx for %lu bytes)",
+				       __func__,
+				       (unsigned long long)phys_addr,
+				       (ulong)bytes);
+				return NULL;
+			}
+			break;	/* greater then HIGH_MEMORY */
+		}
+		/* come out, if Memory is undefined or greater then
+		 * HIGM_MEMORY
+		 */
+		if (phys_addr > (u64)ULONG_MAX) {
+			ERRDRV("%s - localPhysical address is too large to be be mapped (0x%-16.16Lx for %lu bytes)",
+			       __func__,
+			       (unsigned long long)phys_addr, (ulong)bytes);
+			return NULL;
+		}
+		pcpy = ioremap_cache((ulong)phys_addr, (ulong)bytes);
+		if (pcpy == NULL) {
+			ERRDRV("%s - ioremap_cache(0x%lx, %lu) failed",
+			       __func__, (ulong)phys_addr, (ulong)bytes);
+			return NULL;
+		}
+		return pcpy;
+	}
+	return NULL;
+}
+
+static void __iomem *chipset_preamble(ulong bus_no, ulong dev_no,
+				      struct visorchipset_device_info *devinfo)
+{
+	if (!visorchipset_get_device_info(bus_no, dev_no, devinfo)) {
+		ERRDRV("%s - visorchipset_get_device_info returned false",
+		       __func__);
+		return NULL;
+	}
+	if ((uuid_le_cmp(devinfo->chan_info.channel_type_uuid,
+			 spar_vnic_channel_protocol_uuid) != 0) &&
+	    (uuid_le_cmp(devinfo->chan_info.channel_type_uuid,
+			 spar_vhba_channel_protocol_uuid) != 0)) {
+		ERRDRV("%s - I only know how to handle VNIC or VHBA client channels",
+		       __func__);
+		return NULL;
+	}
+	return get_virt(devinfo->chan_info.channel_addr,
+			devinfo->chan_info.n_channel_bytes,
+			devinfo->chan_info.addr_type);
+}
+
+static void
+chipset_bus_create(ulong bus_no)
+{
+	int rc = 0;
+	u64 channeladdr = 0;
+	ulong nchannelbytes = 0;
+	struct visorchipset_bus_info businfo;
+	struct controlvm_message msg;
+
+	POSTCODE_LINUX_3(BUS_CREATE_ENTRY_PC, bus_no, POSTCODE_SEVERITY_INFO);
+	if ((visorchipset_get_bus_info(bus_no, &businfo)) &&
+	    (businfo.chan_info.channel_addr > 0) &&
+	    (businfo.chan_info.n_channel_bytes > 0)) {
+		channeladdr = businfo.chan_info.channel_addr;
+		nchannelbytes = (ulong)businfo.chan_info.n_channel_bytes;
+	}
+	/* Save off message with IOVM bus info in case of crash */
+	if ((uuid_le_cmp(businfo.chan_info.channel_inst_uuid,
+			 spar_siovm_uuid) == 0)) {
+		msg.hdr.id = CONTROLVM_BUS_CREATE;
+		msg.hdr.flags.response_expected = 0;
+		msg.hdr.flags.server = 0;
+		msg.cmd.create_bus.bus_no = bus_no;
+		msg.cmd.create_bus.dev_count = businfo.dev_no;
+		msg.cmd.create_bus.channel_addr = channeladdr;
+		msg.cmd.create_bus.channel_bytes = nchannelbytes;
+		dump_vhba_bus = bus_no;
+		visorchipset_save_message(&msg, CRASH_BUS);
+	}
+
+	if (!uislib_client_inject_add_bus(bus_no,
+					  spar_vbus_channel_protocol_uuid,
+					  channeladdr, nchannelbytes)) {
+		rc = -1;
+	}
+
+	if (chipset_responders.bus_create)
+		(*chipset_responders.bus_create) (bus_no, rc);
+}
+
+static void
+chipset_bus_destroy(ulong bus_no)
+{
+	int rc = 0;
+
+	if (!uislib_client_inject_del_bus(bus_no))
+		rc = -1;
+
+	if (chipset_responders.bus_destroy)
+		(*chipset_responders.bus_destroy) (bus_no, rc);
+}
+
+static void
+chipset_device_create(ulong bus_no, ulong dev_no)
+{
+	void __iomem *paddr = NULL;
+	int rc = 0;
+	struct visorchipset_device_info dev_info;
+	struct controlvm_message msg;
+
+	paddr = chipset_preamble(bus_no, dev_no, &dev_info);
+	POSTCODE_LINUX_4(DEVICE_CREATE_ENTRY_PC, dev_no, bus_no,
+			 POSTCODE_SEVERITY_INFO);
+
+	if (!paddr) {
+		rc = -1;
+		goto cleanup;
+	}
+	if (uuid_le_cmp(dev_info.chan_info.channel_type_uuid,
+			spar_vnic_channel_protocol_uuid) == 0) {
+		if (!uislib_client_inject_add_vnic
+		    (bus_no, dev_no,
+		     dev_info.chan_info.channel_addr,
+		     dev_info.chan_info.n_channel_bytes,
+		     dev_info.chan_info.addr_type == ADDRTYPE_LOCALTEST,
+		     dev_info.dev_inst_uuid, &dev_info.chan_info.intr)) {
+			rc = -2;
+			goto cleanup;
+		}
+		goto cleanup;
+	} else if (uuid_le_cmp(dev_info.chan_info.channel_type_uuid,
+			       spar_vhba_channel_protocol_uuid) == 0) {
+		/* Save off message with hba info in case of crash */
+		if (bus_no == dump_vhba_bus) {
+			msg.hdr.id = CONTROLVM_DEVICE_CREATE;
+			msg.hdr.flags.response_expected = 0;
+			msg.hdr.flags.server = 0;
+			msg.cmd.create_device.bus_no = bus_no;
+			msg.cmd.create_device.dev_no = dev_no;
+			msg.cmd.create_device.dev_inst_uuid =
+				dev_info.dev_inst_uuid;
+			msg.cmd.create_device.intr = dev_info.chan_info.intr;
+			msg.cmd.create_device.channel_addr =
+			    dev_info.chan_info.channel_addr;
+			msg.cmd.create_device.channel_bytes =
+			    dev_info.chan_info.n_channel_bytes;
+			msg.cmd.create_device.data_type_uuid =
+					spar_vhba_channel_protocol_uuid;
+			visorchipset_save_message(&msg, CRASH_DEV);
+		}
+
+		if (!uislib_client_inject_add_vhba
+		    (bus_no, dev_no,
+		     dev_info.chan_info.channel_addr,
+		     dev_info.chan_info.n_channel_bytes,
+		     dev_info.chan_info.addr_type == ADDRTYPE_LOCALTEST,
+		     dev_info.dev_inst_uuid, &dev_info.chan_info.intr)) {
+			rc = -3;
+			goto cleanup;
+		}
+		goto cleanup;
+	}
+
+	rc = -4;		/* unsupported GUID */
+cleanup:
+	if (chipset_responders.device_create)
+		(*chipset_responders.device_create) (bus_no, dev_no, rc);
+}
+
+static void
+chipset_device_destroy(ulong bus_no, ulong dev_no)
+{
+	void __iomem *paddr = NULL;
+	int rc = 0;
+	struct visorchipset_device_info dev_info;
+
+	paddr = chipset_preamble(bus_no, dev_no, &dev_info);
+	if (!paddr) {
+		rc = -1;
+		goto cleanup;
+	}
+	if (uuid_le_cmp(dev_info.chan_info.channel_type_uuid,
+			spar_vnic_channel_protocol_uuid) == 0) {
+		uislib_client_inject_del_vnic(bus_no, dev_no);
+		goto cleanup;
+	} else if (uuid_le_cmp(dev_info.chan_info.channel_type_uuid,
+			       spar_vhba_channel_protocol_uuid) == 0) {
+		uislib_client_inject_del_vhba(bus_no, dev_no);
+		goto cleanup;
+	}
+	rc = -1;		/* no match on GUID */
+cleanup:
+	if (chipset_responders.device_destroy)
+		(*chipset_responders.device_destroy) (bus_no, dev_no, rc);
+}
+
+static void
+chipset_device_pause(ulong bus_no, ulong dev_no)
+{
+	void __iomem *paddr = NULL;
+	int rc = 0;
+	struct visorchipset_device_info dev_info;
+
+	paddr = chipset_preamble(bus_no, dev_no, &dev_info);
+	if (!paddr) {
+		rc = -1;
+		goto cleanup;
+	}
+	if (uuid_le_cmp(dev_info.chan_info.channel_type_uuid,
+			spar_vnic_channel_protocol_uuid) == 0) {
+		rc = uislib_client_inject_pause_vnic(bus_no, dev_no);
+		goto cleanup;
+	} else if (uuid_le_cmp(dev_info.chan_info.channel_type_uuid,
+			       spar_vhba_channel_protocol_uuid) == 0) {
+		rc = uislib_client_inject_pause_vhba(bus_no, dev_no);
+		goto cleanup;
+	}
+	rc = -1;		/* no match on GUID */
+cleanup:
+	if ((rc != CONTROLVM_RESP_SUCCESS) && chipset_responders.device_pause)
+		(*chipset_responders.device_pause)(bus_no, dev_no, rc);
+}
+
+static void
+chipset_device_resume(ulong bus_no, ulong dev_no)
+{
+	void __iomem *paddr = NULL;
+	int rc = 0;
+	struct visorchipset_device_info dev_info;
+
+	paddr = chipset_preamble(bus_no, dev_no, &dev_info);
+	if (!paddr) {
+		rc = -1;
+		goto cleanup;
+	}
+	if (uuid_le_cmp(dev_info.chan_info.channel_type_uuid,
+			spar_vnic_channel_protocol_uuid) == 0) {
+		rc = uislib_client_inject_resume_vnic(bus_no, dev_no);
+		goto cleanup;
+	} else if (uuid_le_cmp(dev_info.chan_info.channel_type_uuid,
+			       spar_vhba_channel_protocol_uuid) == 0) {
+		rc = uislib_client_inject_resume_vhba(bus_no, dev_no);
+		goto cleanup;
+	}
+	rc = -1;		/* no match on GUID */
+cleanup:
+	if (chipset_responders.device_resume)
+		(*chipset_responders.device_resume) (bus_no, dev_no, rc);
+}
+
+static int __init
+visorclientbus_init(void)
+{
+	POSTCODE_LINUX_2(CHIPSET_INIT_ENTRY_PC, POSTCODE_SEVERITY_INFO);
+	/* This enables us to receive notifications when devices appear for
+	 * which this service partition is to be a client for.
+	 */
+	visorchipset_register_busdev_client(&chipset_notifiers,
+					    &chipset_responders,
+					    &chipset_driver_info);
+
+	POSTCODE_LINUX_2(CHIPSET_INIT_EXIT_PC, POSTCODE_SEVERITY_INFO);
+
+	return 0;
+}
+
+static void
+visorclientbus_exit(void)
+{
+	visorchipset_register_busdev_client(NULL, NULL, NULL);
+}
+
+module_init(visorclientbus_init);
+module_exit(visorclientbus_exit);
+
+MODULE_AUTHOR("Unisys");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("client device bus driver for service partition");
+MODULE_VERSION(VERSION);
-- 
1.9.3

_______________________________________________
devel mailing list
devel@xxxxxxxxxxxxxxxxxxxxxx
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel




[Index of Archives]     [Linux Driver Backports]     [DMA Engine]     [Linux GPIO]     [Linux SPI]     [Video for Linux]     [Linux USB Devel]     [Linux Coverity]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux