/* visorbus_main.c
*
* Copyright � 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.
*/
#include <linux/uuid.h>
#include "visorbus.h"
#include "visorchipset.h"
#include "version.h"
#include "timskmod.h"
#include "periodic_work.h"
#include "vbuschannel.h"
#include "guestlinuxdebug.h"
#include "vbusdeviceinfo.h"
/* module parameters */
int visorbus_debug;
int visorbus_forcematch;
int visorbus_forcenomatch;
#define MAXDEVICETEST 4
int visorbus_devicetest;
int visorbus_debugref;
int visorbus_serialloopbacktest;
#define SERIALLOOPBACKCHANADDR (100 * 1024 * 1024)
/** This is the private data that we store for each bus device instance.
*/
struct visorbus_devdata {
int devno; /* this is the chipset busNo */
struct list_head list_all;
struct device *dev;
struct kobject kobj;
struct visorchannel *chan; /* channel area for bus itself */
bool vbus_valid;
struct spar_vbus_headerinfo vbus_hdr_info;
};
/* These forward declarations are required since our drivers are out-of-tree.
* The structures referenced are kernel-private and are not in the headers, but
* it is impossible to make a functioning bus driver without them.
*/
struct subsys_private {
struct kset subsys;
struct kset *devices_kset;
struct kset *drivers_kset;
struct klist klist_devices;
struct klist klist_drivers;
struct blocking_notifier_head bus_notifier;
unsigned int drivers_autoprobe:1;
struct bus_type *bus;
struct list_head class_interfaces;
struct kset glue_dirs;
struct mutex class_mutex; /* ignore */
struct class *class;
};
struct bus_type_private {
struct kset subsys;
struct kset *drivers_kset;
struct kset *devices_kset;
struct klist klist_devices;
struct klist klist_drivers;
struct blocking_notifier_head bus_notifier;
unsigned int drivers_autoprobe:1;
struct bus_type *bus;
};
#define CURRENT_FILE_PC VISOR_BUS_PC_visorbus_main_c
#define POLLJIFFIES_TESTWORK 100
#define POLLJIFFIES_NORMALCHANNEL 10
static int visorbus_uevent(struct device *xdev, struct kobj_uevent_env *env);
static int visorbus_match(struct device *xdev, struct device_driver *xdrv);
static void fix_vbus_dev_info(struct visor_device *visordev);
/** This describes the TYPE of bus.
* (Don't confuse this with an INSTANCE of the bus.)
*/
static struct bus_type visorbus_type = {
.name = "visorbus",
.match = visorbus_match,
.uevent = visorbus_uevent,
};
static struct delayed_work periodic_work;
/* YES, we need 2 workqueues.
* The reason is, workitems on the test queue may need to cancel
* workitems on the other queue. You will be in for trouble if you try to
* do this with workitems queued on the same workqueue.
*/
static struct workqueue_struct *periodic_test_workqueue;
static struct workqueue_struct *periodic_dev_workqueue;
static long long bus_count; /** number of bus instances */
static long long total_devices_created;
/** ever-increasing */
static void chipset_bus_create(u32 bus_no);
static void chipset_bus_destroy(u32 bus_no);
static void chipset_device_create(u32 bus_no, u32 dev_no);
static void chipset_device_destroy(u32 bus_no, u32 dev_no);
static void chipset_device_pause(u32 bus_no, u32 dev_no);
static void chipset_device_resume(u32 bus_no, u32 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,
};
/** 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_driverinfo;
/* filled in with info about this driver, wrt it servicing client busses */
static struct ultra_vbus_deviceinfo clientbus_driverinfo;
/** list of visorbus_devdata structs, linked via .list_all */
static LIST_HEAD(list_all_bus_instances);
/** list of visor_device structs, linked via .list_all */
static LIST_HEAD(list_all_device_instances);
static int
visorbus_uevent(struct device *xdev, struct kobj_uevent_env *env)
{
if (add_uevent_var(env, "VERSION=%s", VERSION))
return -ENOMEM;
return 0;
}
/* This is called automatically upon adding a visor_device (device_add), or
* adding a visor_driver (visorbus_register_visor_driver), and returns 1 iff the
* provided driver can control the specified device.
*/
static int
visorbus_match(struct device *xdev, struct device_driver *xdrv)
{
uuid_le channel_type;
int rc = 0;
int i;
struct visor_device *dev;
struct visor_driver *drv;
dev = to_visor_device(xdev);
drv = to_visor_driver(xdrv);
channel_type = visorchannel_get_uuid(dev->visorchannel);
if (visorbus_forcematch) {
rc = 1;
goto away;
}
if (visorbus_forcenomatch)
goto away;
if (!drv->channel_types)
goto away;
for (i = 0;
(uuid_le_cmp(drv->channel_types[i].guid, NULL_UUID_LE) != 0) ||
(drv->channel_types[i].name);
i++)
if (uuid_le_cmp(drv->channel_types[i].guid,
channel_type) == 0) {
rc = i + 1;
goto away;
}
away:
return rc;
}
/** This is called when device_unregister() is called for the bus device
* instance, after all other tasks involved with destroying the device
* are complete.
*/
static void
visorbus_release_busdevice(struct device *xdev)
{
struct visorbus_devdata *devdata = dev_get_drvdata(xdev);
dev_set_drvdata(xdev, NULL);
kfree(devdata);
kfree(xdev);
}
/** This is called when device_unregister() is called for each child
* device instance.
*/
static void
visorbus_release_device(struct device *xdev)
{
struct visor_device *dev = to_visor_device(xdev);
if (dev->periodic_work) {
visor_periodic_work_destroy(dev->periodic_work);
dev->periodic_work = NULL;
}
if (dev->visorchannel) {
visorchannel_destroy(dev->visorchannel);
dev->visorchannel = NULL;
}
kfree(dev);
}
/* Implement publishing of device node attributes under:
*
* /sys/bus/visorbus<x>/dev<y>/devmajorminor
*
*/
#define to_devmajorminor_attr(_attr) \
container_of(_attr, struct devmajorminor_attribute, attr)
#define to_visor_device_from_kobjdevmajorminor(obj) \
container_of(obj, struct visor_device, kobjdevmajorminor)
struct devmajorminor_attribute {
struct attribute attr;
int slot;
ssize_t (*show)(struct visor_device *, int slot, char *buf);
ssize_t (*store)(struct visor_device *, int slot, const char *buf,
size_t count);
};
static ssize_t DEVMAJORMINOR_ATTR(struct visor_device *dev, int slot, char *buf)
{
int maxdevnodes = ARRAY_SIZE(dev->devnodes) / sizeof(dev->devnodes[0]);
if (slot < 0 || slot >= maxdevnodes)
return 0;
return snprintf(buf, PAGE_SIZE, "%d:%d\n",
dev->devnodes[slot].major, dev->devnodes[slot].minor);
}
static ssize_t
devmajorminor_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)
{
struct devmajorminor_attribute *devmajorminor_attr =
to_devmajorminor_attr(attr);
struct visor_device *dev = to_visor_device_from_kobjdevmajorminor(kobj);
ssize_t ret = 0;
if (devmajorminor_attr->show)
ret = devmajorminor_attr->show(dev,
devmajorminor_attr->slot, buf);
return ret;
}
static ssize_t
devmajorminor_attr_store(struct kobject *kobj,
struct attribute *attr, const char *buf, size_t count)
{
struct devmajorminor_attribute *devmajorminor_attr =
to_devmajorminor_attr(attr);
struct visor_device *dev = to_visor_device_from_kobjdevmajorminor(kobj);
ssize_t ret = 0;
if (devmajorminor_attr->store)
ret = devmajorminor_attr->store(dev,
devmajorminor_attr->slot,
buf, count);
return ret;
}
static int register_devmajorminor_attributes(struct visor_device *dev);
int
devmajorminor_create_file(struct visor_device *dev, const char *name,
int major, int minor)
{
int maxdevnodes = ARRAY_SIZE(dev->devnodes) / sizeof(dev->devnodes[0]);
struct devmajorminor_attribute *myattr = NULL;
int x = -1, rc = 0, slot = -1;
register_devmajorminor_attributes(dev);
for (slot = 0; slot < maxdevnodes; slot++)
if (!dev->devnodes[slot].attr)
break;
if (slot == maxdevnodes) {
rc = -ENOMEM;
goto away;
}
myattr = kmalloc(sizeof(*myattr), GFP_KERNEL);
if (!myattr) {
rc = -ENOMEM;
goto away;
}
memset(myattr, 0, sizeof(struct devmajorminor_attribute));
myattr->show = DEVMAJORMINOR_ATTR;
myattr->store = NULL;
myattr->slot = slot;
myattr->attr.name = name;
myattr->attr.mode = S_IRUGO;
dev->devnodes[slot].attr = myattr;
dev->devnodes[slot].major = major;
dev->devnodes[slot].minor = minor;
x = sysfs_create_file(&dev->kobjdevmajorminor, &myattr->attr);
if (x < 0) {
rc = x;
goto away;
}
kobject_uevent(&dev->device.kobj, KOBJ_ONLINE);
away:
if (rc < 0) {
kfree(myattr);
myattr = NULL;
dev->devnodes[slot].attr = NULL;
}
return rc;
}
void
devmajorminor_remove_file(struct visor_device *dev, int slot)
{
int maxdevnodes = ARRAY_SIZE(dev->devnodes) / sizeof(dev->devnodes[0]);
struct devmajorminor_attribute *myattr = NULL;
if (slot < 0 || slot >= maxdevnodes)
return;
myattr = (struct devmajorminor_attribute *)(dev->devnodes[slot].attr);
if (myattr)
return;
sysfs_remove_file(&dev->kobjdevmajorminor, &myattr->attr);
kobject_uevent(&dev->device.kobj, KOBJ_OFFLINE);
dev->devnodes[slot].attr = NULL;
kfree(myattr);
}
void
devmajorminor_remove_all_files(struct visor_device *dev)
{
int i = 0;
int maxdevnodes = ARRAY_SIZE(dev->devnodes) / sizeof(dev->devnodes[0]);
for (i = 0; i < maxdevnodes; i++)
devmajorminor_remove_file(dev, i);
}
static const struct sysfs_ops devmajorminor_sysfs_ops = {
.show = devmajorminor_attr_show,
.store = devmajorminor_attr_store,
};
static struct kobj_type devmajorminor_kobj_type = {
.sysfs_ops = &devmajorminor_sysfs_ops
};
static int
register_devmajorminor_attributes(struct visor_device *dev)
{
int rc = 0, x = 0;
if (dev->kobjdevmajorminor.parent)
goto away; /* already registered */
x = kobject_init_and_add(&dev->kobjdevmajorminor,
&devmajorminor_kobj_type, &dev->device.kobj,
"devmajorminor");
if (x < 0) {
rc = x;
goto away;
}
kobject_uevent(&dev->kobjdevmajorminor, KOBJ_ADD);
away:
return rc;
}
void
unregister_devmajorminor_attributes(struct visor_device *dev)
{
if (!dev->kobjdevmajorminor.parent)
return; /* already unregistered */
devmajorminor_remove_all_files(dev);
kobject_del(&dev->kobjdevmajorminor);
kobject_put(&dev->kobjdevmajorminor);
dev->kobjdevmajorminor.parent = NULL;
}
/* Implement publishing of channel attributes under:
*
* /sys/bus/visorbus<x>/dev<y>/channel
*
*/
#define to_channel_attr(_attr) \
container_of(_attr, struct channel_attribute, attr)
#define to_visor_device_from_kobjchannel(obj) \
container_of(obj, struct visor_device, kobjchannel)
struct channel_attribute {
struct attribute attr;
ssize_t (*show)(struct visor_device*, char *buf);
ssize_t (*store)(struct visor_device*, const char *buf, size_t count);
};
/* begin implementation of specific channel attributes to appear under
* /sys/bus/visorbus<x>/dev<y>/channel
*/
static ssize_t devicechannel_attr_physaddr(struct visor_device *dev, char *buf)
{
if (!dev->visorchannel)
return 0;
return snprintf(buf, PAGE_SIZE, "0x%Lx\n",
visorchannel_get_physaddr(dev->visorchannel));
}
static ssize_t devicechannel_attr_nbytes(struct visor_device *dev, char *buf)
{
if (!dev->visorchannel)
return 0;
return snprintf(buf, PAGE_SIZE, "0x%lx\n",
visorchannel_get_nbytes(dev->visorchannel));
}
static ssize_t devicechannel_attr_clientpartition(struct visor_device *dev,
char *buf) {
if (!dev->visorchannel)
return 0;
return snprintf(buf, PAGE_SIZE, "0x%Lx\n",
visorchannel_get_clientpartition(dev->visorchannel));
}
static ssize_t devicechannel_attr_typeguid(struct visor_device *dev, char *buf)
{
char s[99];
if (!dev->visorchannel)
return 0;
return snprintf(buf, PAGE_SIZE, "%s\n",
visorchannel_id(dev->visorchannel, s));
}
static ssize_t devicechannel_attr_zoneguid(struct visor_device *dev, char *buf)
{
char s[99];
if (!dev->visorchannel)
return 0;
return snprintf(buf, PAGE_SIZE, "%s\n",
visorchannel_zoneid(dev->visorchannel, s));
}
static ssize_t devicechannel_attr_typename(struct visor_device *dev, char *buf)
{
int i = 0;
struct bus_type *xbus = dev->device.bus;
struct device_driver *xdrv = dev->device.driver;
struct visor_driver *drv = NULL;
if (!dev->visorchannel || !xbus || !xdrv)
return 0;
i = xbus->match(&dev->device, xdrv);
if (!i)
return 0;
drv = to_visor_driver(xdrv);
return snprintf(buf, PAGE_SIZE, "%s\n", drv->channel_types[i - 1].name);
}
static ssize_t devicechannel_attr_dump(struct visor_device *dev, char *buf)
{
int count = 0;
/* TODO: replace this with debugfs code
struct seq_file *m = NULL;
if (dev->visorchannel == NULL)
return 0;
m = visor_seq_file_new_buffer(buf, PAGE_SIZE - 1);
if (m == NULL)
return 0;
visorchannel_debug(dev->visorchannel, 1, m, 0);
count = m->count;
visor_seq_file_done_buffer(m);
m = NULL;
*/
return count;
}
static struct channel_attribute all_channel_attrs[] = {
__ATTR(physaddr, S_IRUGO,
devicechannel_attr_physaddr, NULL),
__ATTR(nbytes, S_IRUGO,
devicechannel_attr_nbytes, NULL),
__ATTR(clientpartition, S_IRUGO,
devicechannel_attr_clientpartition, NULL),
__ATTR(typeguid, S_IRUGO,
devicechannel_attr_typeguid, NULL),
__ATTR(zoneguid, S_IRUGO,
devicechannel_attr_zoneguid, NULL),
__ATTR(typename, S_IRUGO,
devicechannel_attr_typename, NULL),
__ATTR(dump, S_IRUGO,
devicechannel_attr_dump, NULL),
};
/* end implementation of specific channel attributes */
static ssize_t channel_attr_show(struct kobject *kobj, struct attribute *attr,
char *buf)
{
struct channel_attribute *channel_attr = to_channel_attr(attr);
struct visor_device *dev = to_visor_device_from_kobjchannel(kobj);
ssize_t ret = 0;
if (channel_attr->show)
ret = channel_attr->show(dev, buf);
return ret;
}
static ssize_t channel_attr_store(struct kobject *kobj, struct attribute *attr,
const char *buf, size_t count)
{
struct channel_attribute *channel_attr = to_channel_attr(attr);
struct visor_device *dev = to_visor_device_from_kobjchannel(kobj);
ssize_t ret = 0;
if (channel_attr->store)
ret = channel_attr->store(dev, buf, count);
return ret;
}
static int channel_create_file(struct visor_device *dev,
struct channel_attribute *attr)
{
return sysfs_create_file(&dev->kobjchannel, &attr->attr);
}
static void channel_remove_file(struct visor_device *dev,
struct channel_attribute *attr)
{
sysfs_remove_file(&dev->kobjchannel, &attr->attr);
}
static const struct sysfs_ops channel_sysfs_ops = {
.show = channel_attr_show,
.store = channel_attr_store,
};
static struct kobj_type channel_kobj_type = {
.sysfs_ops = &channel_sysfs_ops
};
int register_channel_attributes(struct visor_device *dev)
{
int rc = 0, i = 0, x = 0;
if (dev->kobjchannel.parent)
goto away; /* already registered */
x = kobject_init_and_add(&dev->kobjchannel, &channel_kobj_type,
&dev->device.kobj, "channel");
if (x < 0) {
rc = x;
goto away;
}
kobject_uevent(&dev->kobjchannel, KOBJ_ADD);
for (i = 0;
i < sizeof(all_channel_attrs) / sizeof(struct channel_attribute);
i++)
x = channel_create_file(dev, &all_channel_attrs[i]);
if (x < 0) {
while (--i >= 0)
channel_remove_file(dev, &all_channel_attrs[i]);
kobject_del(&dev->kobjchannel);
kobject_put(&dev->kobjchannel);
rc = x;
goto away;
}
away:
return rc;
}
void unregister_channel_attributes(struct visor_device *dev)
{
int i = 0;
if (!dev->kobjchannel.parent)
return; /* already unregistered */
for (i = 0;
i < sizeof(all_channel_attrs) / sizeof(struct channel_attribute);
i++)
channel_remove_file(dev, &all_channel_attrs[i]);
kobject_del(&dev->kobjchannel);
kobject_put(&dev->kobjchannel);
dev->kobjchannel.parent = NULL;
}
/* This is actually something they forgot to put in the kernel.
* struct bus_type in the kernel SHOULD have a "busses" member, which
* should be treated similarly to the "devices" and "drivers" members.
* There SHOULD be:
* - a "businst_attribute" analogous to the existing "bus_attribute"
* - a "businst_create_file" and "businst_remove_file" analogous to the
* existing "bus_create_file" and "bus_remove_file".
* That's what I created businst.c and businst.h to do.
*
* We want to add the "busses" sub-tree in sysfs, where we will house the
* names and properties of each bus instance:
*
* /sys/bus/<bustypename>/
* version
* devices
* <devname1> --> /sys/devices/<businstancename><devname1>
* <devname2> --> /sys/devices/<businstancename><devname2>
* drivers
* <driverinstancename1>
* <driverinstance1property1>
* <driverinstance1property2>
* ...
* <driverinstancename2>
* <driverinstance2property1>
* <driverinstance2property2>
* ...
* >> busses
* >> <businstancename1>
* >> <businstance1property1>
* >> <businstance1property2>
* >> ...
* >> <businstancename2>
* >> <businstance2property1>
* >> <businstance2property2>
* >> ...
*
* I considered adding bus instance properties under
* /sys/devices/<businstancename>. But I thought there may be existing
* notions that ONLY device sub-trees should live under
* /sys/devices/<businstancename>. So I stayed out of there.
*
*/
struct businst_attribute {
struct attribute attr;
ssize_t (*show)(struct visorbus_devdata*, char *buf);
ssize_t (*store)(struct visorbus_devdata*, const char *buf,
size_t count);
};
#define to_businst_attr(_attr) \
container_of(_attr, struct businst_attribute, attr)
#define to_visorbus_devdata(obj) \
container_of(obj, struct visorbus_devdata, kobj)
static ssize_t
businst_attr_show(struct kobject *kobj, struct attribute *attr,
char *buf)
{
struct businst_attribute *businst_attr = to_businst_attr(attr);
struct visorbus_devdata *bus = to_visorbus_devdata(kobj);
ssize_t ret = 0;
if (businst_attr->show)
ret = businst_attr->show(bus, buf);
return ret;
}
static ssize_t
businst_attr_store(struct kobject *kobj, struct attribute *attr,
const char *buf, size_t count)
{
struct businst_attribute *businst_attr = to_businst_attr(attr);
struct visorbus_devdata *bus = to_visorbus_devdata(kobj);
ssize_t ret = 0;
if (businst_attr->store)
ret = businst_attr->store(bus, buf, count);
return ret;
}
static int
businst_create_file(struct visorbus_devdata *bus,
struct businst_attribute *attr)
{
return sysfs_create_file(&bus->kobj, &attr->attr);
}
static void
businst_remove_file(struct visorbus_devdata *bus,
struct businst_attribute *attr)
{
sysfs_remove_file(&bus->kobj, &attr->attr);
}
static const struct sysfs_ops businst_sysfs_ops = {
.show = businst_attr_show,
.store = businst_attr_store,
};
static struct kobj_type businst_kobj_type = {
.sysfs_ops = &businst_sysfs_ops
};
static struct kset businstances = { /* should actually be a member of
* bus_type */
};
/* BUS type attributes
*
* define & implement display of bus attributes under
* /sys/bus/visorbus.
*
*/
static ssize_t
BUSTYPE_ATTR_version(struct bus_type *bus, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", VERSION);
}
static struct bus_attribute bustype_attr_version =
__ATTR(version, S_IRUGO, BUSTYPE_ATTR_version, NULL);
static int
register_bustype_attributes(void)
{
int rc = 0;
rc = bus_create_file(&visorbus_type, &bustype_attr_version);
if (rc < 0)
goto away;
/* Here we make up for the fact that bus_type does not yet have a
* member to keep track of multiple bus instances for a given bus
* type. This is useful for stashing properties for each bus
* instance.
*/
kobject_set_name(&businstances.kobj, "busses");
businstances.kobj.ktype = &businst_kobj_type;
businstances.kobj.parent = &visorbus_type.p->subsys.kobj;
rc = kset_register(&businstances);
if (rc < 0)
goto away;
rc = 0;
away:
return rc;
}
static void
unregister_bustype_attributes(void)
{
bus_remove_file(&visorbus_type, &bustype_attr_version);
kset_unregister(&businstances);
}
/* BUS instance attributes
*
* define & implement display of bus attributes under
* /sys/bus/visorbus/busses/visorbus<n>.
*
* This is a bit hoaky because the kernel does not yet have the infrastructure
* to separate bus INSTANCE attributes from bus TYPE attributes...
* so we roll our own. See businst.c / businst.h.
*
*/
static ssize_t businst_attr_partition_handle(struct visorbus_devdata *businst,
char *buf) {
struct visorchipset_bus_info bus_info;
int len = 0;
if (businst && visorchipset_get_bus_info(businst->devno, &bus_info))
len = snprintf(buf, PAGE_SIZE,
"0x%Lx\n",
(unsigned long long)bus_info.partition_handle);
return len;
}
static ssize_t businst_attr_partition_guid(struct visorbus_devdata *businst,
char *buf) {
struct visorchipset_bus_info bus_info;
int len = 0;
if (businst && visorchipset_get_bus_info(businst->devno, &bus_info))
len = snprintf(buf, PAGE_SIZE, "{%pUb}\n",
&bus_info.partition_uuid);
return len;
}
static ssize_t businst_attr_partition_name(struct visorbus_devdata *businst,
char *buf) {
struct visorchipset_bus_info bus_info;
int len = 0;
if (businst &&
visorchipset_get_bus_info(businst->devno, &bus_info) &&
bus_info.name)
len = snprintf(buf, PAGE_SIZE, "%s\n", bus_info.name);
return len;
}
static ssize_t businst_attr_channel_addr(struct visorbus_devdata *businst,
char *buf) {
struct visorchipset_bus_info bus_info;
int len = 0;
if (businst && visorchipset_get_bus_info(businst->devno, &bus_info))
len = snprintf(buf, PAGE_SIZE, "0x%Lx\n", (unsigned long long)
bus_info.chan_info.channel_addr);
return len;
}
static ssize_t businst_attr_nchannel_bytes(struct visorbus_devdata *businst,
char *buf) {
struct visorchipset_bus_info bus_info;
int len = 0;
if (businst && visorchipset_get_bus_info(businst->devno, &bus_info))
len = snprintf(buf, PAGE_SIZE, "0x%Lx\n", (unsigned long long)
bus_info.chan_info.n_channel_bytes);
return len;
}
static ssize_t businst_attr_channel_id(struct visorbus_devdata *businst,
char *buf) {
int len = 0;
if (businst && businst->chan) {
visorchannel_id(businst->chan, buf);
len = strlen(buf);
buf[len++] = '\n';
}
return len;
}
static ssize_t businst_attr_client_bus_info(struct visorbus_devdata *businst,
char *buf) {
struct visorchipset_bus_info bus_info;
int i, x, remain = PAGE_SIZE;
unsigned long off;
char *p = buf;
u8 *partition_name;
struct ultra_vbus_deviceinfo dev_info;
partition_name = "";
if (businst && businst->chan) {
if (visorchipset_get_bus_info(businst->devno, &bus_info) &&
bus_info.name)
partition_name = bus_info.name;
x = snprintf(p, remain,
"Client device / client driver info for %s partition (vbus #%d):\n",
partition_name, businst->devno);
p += x;
remain -= x;
x = visorchannel_read(businst->chan,
offsetof(struct
spar_vbus_channel_protocol,
chp_info),
&dev_info, sizeof(dev_info));
if (x >= 0) {
x = vbuschannel_devinfo_to_string(&dev_info, p,
remain, -1);
p += x;
remain -= x;
}
x = visorchannel_read(businst->chan,
offsetof(struct
spar_vbus_channel_protocol,
bus_info),
&dev_info, sizeof(dev_info));
if (x >= 0) {
x = vbuschannel_devinfo_to_string(&dev_info, p,
remain, -1);
p += x;
remain -= x;
}
off = offsetof(struct spar_vbus_channel_protocol, dev_info);
i = 0;
while (off + sizeof(dev_info) <=
visorchannel_get_nbytes(businst->chan)) {
x = visorchannel_read(businst->chan,
off, &dev_info, sizeof(dev_info));
if (x >= 0) {
x = vbuschannel_devinfo_to_string
(&dev_info, p, remain, i);
p += x;
remain -= x;
}
off += sizeof(dev_info);
i++;
}
}
return PAGE_SIZE - remain;
}
static struct businst_attribute ba_partition_handle =
__ATTR(partition_handle, S_IRUGO, businst_attr_partition_handle, NULL);
static struct businst_attribute ba_partition_guid =
__ATTR(partition_guid, S_IRUGO, businst_attr_partition_guid, NULL);
static struct businst_attribute ba_partition_name =
__ATTR(partition_name, S_IRUGO, businst_attr_partition_name, NULL);
static struct businst_attribute ba_channel_addr =
__ATTR(channel_addr, S_IRUGO, businst_attr_channel_addr, NULL);
static struct businst_attribute ba_nchannel_bytes =
__ATTR(nchannel_bytes, S_IRUGO, businst_attr_nchannel_bytes, NULL);
static struct businst_attribute ba_channel_id =
__ATTR(channel_id, S_IRUGO, businst_attr_channel_id, NULL);
static struct businst_attribute ba_client_bus_info =
__ATTR(client_bus_info, S_IRUGO, businst_attr_client_bus_info, NULL);
static int
register_businst_attributes(struct visorbus_devdata *businst)
{
int rc = 0;
businst->kobj.kset = &businstances; /* identify parent sysfs dir */
rc = kobject_init_and_add(&businst->kobj, &businst_kobj_type,
NULL, "visorbus%d", businst->devno);
if (rc < 0)
goto away;
rc = businst_create_file(businst, &ba_partition_handle);
if (rc < 0)
goto away;
rc = businst_create_file(businst, &ba_partition_guid);
if (rc < 0)
goto away;
rc = businst_create_file(businst, &ba_partition_name);
if (rc < 0)
goto away;
rc = businst_create_file(businst, &ba_channel_addr);
if (rc < 0)
goto away;
rc = businst_create_file(businst, &ba_nchannel_bytes);
if (rc < 0)
goto away;
rc = businst_create_file(businst, &ba_channel_id);
if (rc < 0)
goto away;
rc = businst_create_file(businst, &ba_client_bus_info);
if (rc < 0)
goto away;
kobject_uevent(&businst->kobj, KOBJ_ADD);
rc = 0;
away:
return rc;
}
static void
unregister_businst_attributes(struct visorbus_devdata *businst)
{
businst_remove_file(businst, &ba_partition_handle);
businst_remove_file(businst, &ba_partition_guid);
businst_remove_file(businst, &ba_partition_name);
businst_remove_file(businst, &ba_channel_addr);
businst_remove_file(businst, &ba_nchannel_bytes);
businst_remove_file(businst, &ba_channel_id);
businst_remove_file(businst, &ba_client_bus_info);
kobject_put(&businst->kobj);
}
/* DRIVER attributes
*
* define & implement display of driver attributes under
* /sys/bus/visorbus/drivers/<drivername>.
*
*/
static ssize_t
DRIVER_ATTR_version(struct device_driver *xdrv, char *buf)
{
struct visor_driver *drv = to_visor_driver(xdrv);
return snprintf(buf, PAGE_SIZE, "%s\n", drv->version);
}
static int
register_driver_attributes(struct visor_driver *drv)
{
int rc;
struct driver_attribute version =
__ATTR(version, S_IRUGO, DRIVER_ATTR_version, NULL);
drv->version_attr = version;
rc = driver_create_file(&drv->driver, &drv->version_attr);
return rc;
}
static void
unregister_driver_attributes(struct visor_driver *drv)
{
driver_remove_file(&drv->driver, &drv->version_attr);
}
/* DEVICE attributes
*
* define & implement display of device attributes under
* /sys/bus/visorbus/devices/<devicename>.
*
*/
#define DEVATTR(nam, func) { \
.attr = { .name = __stringify(nam), \
.mode = 0444, \
.owner = THIS_MODULE }, \
.show = func, \
}
static struct device_attribute visor_device_attrs[] = {
/* DEVATTR(channel_nbytes, DEVICE_ATTR_channel_nbytes), */
__ATTR_NULL
};
static void
dev_periodic_work(void *xdev)
{
struct visor_device *dev = (struct visor_device *)xdev;
struct visor_driver *drv = to_visor_driver(dev->device.driver);
down(&dev->visordriver_callback_lock);
if (drv->channel_interrupt)
drv->channel_interrupt(dev);
up(&dev->visordriver_callback_lock);
if (!visor_periodic_work_nextperiod(dev->periodic_work))
put_device(&dev->device);
}
static void
dev_start_periodic_work(struct visor_device *dev)
{
if (dev->being_removed)
return;
/* now up by at least 2 */
get_device(&dev->device);
if (!visor_periodic_work_start(dev->periodic_work))
put_device(&dev->device);
}
static void
dev_stop_periodic_work(struct visor_device *dev)
{
if (visor_periodic_work_stop(dev->periodic_work))
put_device(&dev->device);
}
/** This is called automatically upon adding a visor_device (device_add), or
* adding a visor_driver (visorbus_register_visor_driver), but only after
* visorbus_match has returned 1 to indicate a successful match between
* driver and device.
*/
static int
visordriver_probe_device(struct device *xdev)
{
int rc;
struct visor_driver *drv;
struct visor_device *dev;
drv = to_visor_driver(xdev->driver);
dev = to_visor_device(xdev);
down(&dev->visordriver_callback_lock);
dev->being_removed = FALSE;
/*
* ensure that the dev->being_removed flag is cleared before
* we start the probe
*/
wmb();
get_device(&dev->device);
if (!drv->probe) {
up(&dev->visordriver_callback_lock);
rc = -1;
goto away;
}
rc = drv->probe(dev);
if (rc < 0)
goto away;
fix_vbus_dev_info(dev);
up(&dev->visordriver_callback_lock);
rc = 0;
away:
if (rc != 0)
put_device(&dev->device);
/* We could get here more than once if the child driver module is
* unloaded and re-loaded while devices are present. That's why we
* need a flag to be sure that we only respond to the device_create
* once. We cannot respond to the device_create prior to here,
* because until we call drv->probe() above, the channel has not been
* initialized.
*/
if (!dev->responded_to_device_create) {
dev->responded_to_device_create = TRUE;
if (chipset_responders.device_create)
(*chipset_responders.device_create)(dev->chipset_bus_no,
dev->chipset_dev_no,
rc);
}
return rc;
}
/** This is called when device_unregister() is called for each child device
* instance, to notify the appropriate visorbus_driver that the device is
* going away, and to decrease the reference count of the device.
*/
static int
visordriver_remove_device(struct device *xdev)
{
int rc = 0;
struct visor_device *dev;
struct visor_driver *drv;
dev = to_visor_device(xdev);
drv = to_visor_driver(xdev->driver);
down(&dev->visordriver_callback_lock);
dev->being_removed = TRUE;
/*
* ensure that the dev->being_removed flag is set before we start the
* actual removal
*/
wmb();
if (drv) {
if (drv->remove)
drv->remove(dev);
}
up(&dev->visordriver_callback_lock);
dev_stop_periodic_work(dev);
devmajorminor_remove_all_files(dev);
put_device(&dev->device);
return rc;
}
/** A particular type of visor driver calls this function to register
* the driver. The caller MUST fill in the following fields within the
* #drv structure:
* name, version, owner, channel_types, probe, remove
*
* Here's how the whole Linux bus / driver / device model works.
*
* At system start-up, the visorbus kernel module is loaded, which registers
* visorbus_type as a bus type, using bus_register().
*
* All kernel modules that support particular device types on a
* visorbus bus are loaded. Each of these kernel modules calls
* visorbus_register_visor_driver() in their init functions, passing a
* visor_driver struct. visorbus_register_visor_driver() in turn calls
* register_driver(&visor_driver.driver). This .driver member is
* initialized with generic methods (like probe), whose sole responsibility
* is to act as a broker for the real methods, which are within the
* visor_driver struct. (This is the way the subclass behavior is
* implemented, since visor_driver is essentially a subclass of the
* generic driver.) Whenever a driver_register() happens, core bus code in
* the kernel does (see device_attach() in drivers/base/dd.c):
*
* for each dev associated with the bus (the bus that driver is on) that
* does not yet have a driver
* if bus.match(dev,newdriver) == yes_matched ** .match specified
* ** during bus_register().
* newdriver.probe(dev) ** for visor drivers, this will call
* ** the generic driver.probe implemented in visorbus.c,
* ** which in turn calls the probe specified within the
* ** struct visor_driver (which was specified by the
* ** actual device driver as part of
* ** visorbus_register_visor_driver()).
*
* The above dance also happens when a new device appears.
* So the question is, how are devices created within the system?
* Basically, just call device_add(dev). See pci_bus_add_devices().
* pci_scan_device() shows an example of how to build a device struct. It
* returns the newly-created struct to pci_scan_single_device(), who adds it
* to the list of devices at PCIBUS.devices. That list of devices is what
* is traversed by pci_bus_add_devices().
*
*/
int visorbus_register_visor_driver(struct visor_driver *drv)
{
int rc = 0;
drv->driver.name = drv->name;
drv->driver.bus = &visorbus_type;
drv->driver.probe = visordriver_probe_device;
drv->driver.remove = visordriver_remove_device;
drv->driver.owner = drv->owner;
/* driver_register does this:
* bus_add_driver(drv)
* ->if (drv.bus) ** (bus_type) **
* driver_attach(drv)
* for each dev with bus type of drv.bus
* if (!dev.drv) ** no driver assigned yet **
* if (bus.match(dev,drv)) [visorbus_match]
* dev.drv = drv
* if (!drv.probe(dev)) [visordriver_probe_device]
* dev.drv = NULL
*/
rc = driver_register(&drv->driver);
if (rc < 0)
return rc;
rc = register_driver_attributes(drv);
return rc;
}
EXPORT_SYMBOL_GPL(visorbus_register_visor_driver);
/** A particular type of visor driver calls this function to unregister
* the driver, i.e., within its module_exit function.
*/
void
visorbus_unregister_visor_driver(struct visor_driver *drv)
{
unregister_driver_attributes(drv);
driver_unregister(&drv->driver);
}
EXPORT_SYMBOL_GPL(visorbus_unregister_visor_driver);
int
visorbus_read_channel(struct visor_device *dev, unsigned long offset,
void *dest, unsigned long nbytes)
{
return visorchannel_read(dev->visorchannel, offset, dest, nbytes);
}
EXPORT_SYMBOL_GPL(visorbus_read_channel);
int
visorbus_write_channel(struct visor_device *dev, unsigned long offset,
void *src, unsigned long nbytes)
{
return visorchannel_write(dev->visorchannel, offset, src, nbytes);
}
EXPORT_SYMBOL_GPL(visorbus_write_channel);
int
visorbus_clear_channel(struct visor_device *dev, unsigned long offset, u8 ch,
unsigned long nbytes)
{
return visorchannel_clear(dev->visorchannel, offset, ch, nbytes);
}
EXPORT_SYMBOL_GPL(visorbus_clear_channel);
int
visorbus_registerdevnode(struct visor_device *dev,
const char *name, int major, int minor)
{
return devmajorminor_create_file(dev, name, major, minor);
}
EXPORT_SYMBOL_GPL(visorbus_registerdevnode);
/** We don't really have a real interrupt, so for now we just call the
* interrupt function periodically...
*/
void
visorbus_enable_channel_interrupts(struct visor_device *dev)
{
dev_start_periodic_work(dev);
}
EXPORT_SYMBOL_GPL(visorbus_enable_channel_interrupts);
void
visorbus_disable_channel_interrupts(struct visor_device *dev)
{
dev_stop_periodic_work(dev);
}
EXPORT_SYMBOL_GPL(visorbus_disable_channel_interrupts);
/** This is how everything starts from the device end.
* This function is called when a channel first appears via a ControlVM
* message. In response, this function allocates a visor_device to
* correspond to the new channel, and attempts to connect it the appropriate
* driver. If the appropriate driver is found, the visor_driver.probe()
* function for that driver will be called, and will be passed the new
* visor_device that we just created.
*
* It's ok if the appropriate driver is not yet loaded, because in that case
* the new device struct will just stick around in the bus' list of devices.
* When the appropriate driver calls visorbus_register_visor_driver(), the
* visor_driver.probe() for the new driver will be called with the new
* device.
*/
static int
create_visor_device(struct visorbus_devdata *devdata,
unsigned long chipset_bus_no, unsigned long chipset_dev_no,
struct visorchipset_channel_info chan_info,
u64 partition_handle)
{
int rc = -1;
struct visorchannel *visorchannel = NULL;
struct visor_device *dev = NULL;
bool gotten = FALSE, registered1 = FALSE, registered2 = FALSE;
POSTCODE_LINUX_4(DEVICE_CREATE_ENTRY_PC, chipset_dev_no, chipset_bus_no,
POSTCODE_SEVERITY_INFO);
/* prepare chan_hdr (abstraction to read/write channel memory) */
visorchannel = visorchannel_create(chan_info.channel_addr,
(unsigned long)
chan_info.n_channel_bytes,
chan_info.channel_type_uuid);
if (!visorchannel) {
POSTCODE_LINUX_3(DEVICE_CREATE_FAILURE_PC, chipset_dev_no,
DIAG_SEVERITY_ERR);
goto away;
}
dev = kmalloc(sizeof(*dev), GFP_KERNEL);
if (!dev) {
POSTCODE_LINUX_3(DEVICE_CREATE_FAILURE_PC, chipset_dev_no,
DIAG_SEVERITY_ERR);
goto away;
}
memset(dev, 0, sizeof(struct visor_device));
dev->visorchannel = visorchannel;
dev->channel_type_guid = chan_info.channel_type_uuid;
dev->channel_bytes = chan_info.n_channel_bytes;
dev->chipset_bus_no = chipset_bus_no;
dev->chipset_dev_no = chipset_dev_no;
dev->device.parent = devdata->dev;
sema_init(&dev->visordriver_callback_lock, 1); /* unlocked */
dev->device.bus = &visorbus_type;
device_initialize(&dev->device);
dev->device.release = visorbus_release_device;
/* keep a reference just for us (now 2) */
get_device(&dev->device);
gotten = TRUE;
dev->periodic_work =
visor_periodic_work_create(POLLJIFFIES_NORMALCHANNEL,
periodic_dev_workqueue,
dev_periodic_work,
dev, dev_name(&dev->device));
if (!dev->periodic_work) {
POSTCODE_LINUX_3(DEVICE_CREATE_FAILURE_PC, chipset_dev_no,
DIAG_SEVERITY_ERR);
goto away;
}
/* bus_id must be a unique name with respect to this bus TYPE
* (NOT bus instance). That's why we need to include the bus
* number within the name.
*/
dev_set_name(&dev->device, "vbus%lu:dev%lu",
chipset_bus_no, chipset_dev_no);
/* device_add does this:
* bus_add_device(dev)
* ->device_attach(dev)
* ->for each driver drv registered on the bus that dev is on
* if (dev.drv) ** device already has a driver **
* ** not sure we could ever get here... **
* else
* if (bus.match(dev,drv)) [visorbus_match]
* dev.drv = drv
* if (!drv.probe(dev)) [visordriver_probe_device]
* dev.drv = NULL
*
* Note that device_add does NOT fail if no driver failed to
* claim the device. The device will be linked onto
* bus_type.klist_devices regardless (use bus_for_each_dev).
*/
rc = device_add(&dev->device);
if (rc < 0) {
POSTCODE_LINUX_3(DEVICE_ADD_PC, chipset_bus_no,
DIAG_SEVERITY_ERR);
goto away;
}
/* note: device_register is simply device_initialize + device_add */
rc = register_channel_attributes(dev);
if (rc < 0) {
POSTCODE_LINUX_3(DEVICE_REGISTER_FAILURE_PC, chipset_dev_no,
DIAG_SEVERITY_ERR);
goto away;
}
registered1 = TRUE;
rc = register_devmajorminor_attributes(dev);
if (rc < 0) {
POSTCODE_LINUX_3(DEVICE_REGISTER_FAILURE_PC, chipset_dev_no,
DIAG_SEVERITY_ERR);
goto away;
}
registered2 = TRUE;
rc = 0;
away:
if (rc < 0) {
if (registered2)
unregister_devmajorminor_attributes(dev);
if (registered1)
unregister_channel_attributes(dev);
if (gotten)
put_device(&dev->device);
if (visorchannel)
visorchannel_destroy(visorchannel);
kfree(dev);
} else {
total_devices_created++;
list_add_tail(&dev->list_all, &list_all_device_instances);
}
return rc;
}
static void
remove_visor_device(struct visor_device *dev)
{
list_del(&dev->list_all);
unregister_devmajorminor_attributes(dev);
unregister_channel_attributes(dev);
put_device(&dev->device);
device_unregister(&dev->device);
}
static struct visor_device *
find_visor_device_by_channel(HOSTADDRESS channel_physaddr)
{
struct list_head *listentry, *listtmp;
list_for_each_safe(listentry, listtmp, &list_all_device_instances) {
struct visor_device *dev = list_entry(listentry,
struct visor_device,
list_all);
if (visorchannel_get_physaddr(dev->visorchannel) ==
channel_physaddr)
return dev;
}
return NULL;
}
static int
init_vbus_channel(struct visorchannel *chan)
{
int rc = -1;
unsigned long allocated_bytes = visorchannel_get_nbytes(chan);
struct spar_vbus_channel_protocol *x =
kmalloc(sizeof(struct spar_vbus_channel_protocol),
GFP_KERNEL);
POSTCODE_LINUX_3(VBUS_CHANNEL_ENTRY_PC, rc, POSTCODE_SEVERITY_INFO);
if (x) {
POSTCODE_LINUX_2(MALLOC_FAILURE_PC, POSTCODE_SEVERITY_ERR);
goto away;
}
if (visorchannel_clear(chan, 0, 0, allocated_bytes) < 0) {
POSTCODE_LINUX_2(VBUS_CHANNEL_FAILURE_PC,
POSTCODE_SEVERITY_ERR);
goto away;
}
if (visorchannel_read
(chan, 0, x, sizeof(struct spar_vbus_channel_protocol)) < 0) {
POSTCODE_LINUX_2(VBUS_CHANNEL_FAILURE_PC,
POSTCODE_SEVERITY_ERR);
goto away;
}
if (!SPAR_VBUS_CHANNEL_OK_SERVER(allocated_bytes)) {
POSTCODE_LINUX_2(VBUS_CHANNEL_FAILURE_PC,
POSTCODE_SEVERITY_ERR);
goto away;
}
if (visorchannel_write
(chan, 0, x, sizeof(struct spar_vbus_channel_protocol)) < 0) {
POSTCODE_LINUX_3(VBUS_CHANNEL_FAILURE_PC, chan,
POSTCODE_SEVERITY_ERR);
goto away;
}
POSTCODE_LINUX_3(VBUS_CHANNEL_EXIT_PC, chan, POSTCODE_SEVERITY_INFO);
rc = 0;
away:
kfree(x);
x = NULL;
return rc;
}
static int
get_vbus_header_info(struct visorchannel *chan,
struct spar_vbus_headerinfo *hdr_info)
{
int rc = -1;
if (!SPAR_VBUS_CHANNEL_OK_CLIENT(visorchannel_get_header(chan)))
goto away;
if (visorchannel_read(chan, sizeof(struct channel_header), hdr_info,
sizeof(*hdr_info)) < 0) {
goto away;
}
if (hdr_info->struct_bytes < sizeof(struct spar_vbus_headerinfo))
goto away;
if (hdr_info->device_info_struct_bytes <
sizeof(struct ultra_vbus_deviceinfo)) {
goto away;
}
rc = 0;
away:
return rc;
}
/* Write the contents of <info> to the struct
* spar_vbus_channel_protocol.chp_info. */
static int
write_vbus_chp_info(struct visorchannel *chan,
struct spar_vbus_headerinfo *hdr_info,
struct ultra_vbus_deviceinfo *info)
{
int off = sizeof(struct channel_header) + hdr_info->chp_info_offset;
if (hdr_info->chp_info_offset == 0)
return -1;
if (visorchannel_write(chan, off, info, sizeof(*info)) < 0)
return -1;
return 0;
}
/* Write the contents of <info> to the struct
* spar_vbus_channel_protocol.bus_info. */
static int
write_vbus_bus_info(struct visorchannel *chan,
struct spar_vbus_headerinfo *hdr_info,
struct ultra_vbus_deviceinfo *info)
{
int off = sizeof(struct channel_header) + hdr_info->bus_info_offset;
if (hdr_info->bus_info_offset == 0)
return -1;
if (visorchannel_write(chan, off, info, sizeof(*info)) < 0)
return -1;
return 0;
}
/* Write the contents of <info> to the
* struct spar_vbus_channel_protocol.dev_info[<devix>].
*/
static int
write_vbus_dev_info(struct visorchannel *chan,
struct spar_vbus_headerinfo *hdr_info,
struct ultra_vbus_deviceinfo *info, int devix)
{
int off =
(sizeof(struct channel_header) + hdr_info->dev_info_offset) +
(hdr_info->device_info_struct_bytes * devix);
if (hdr_info->dev_info_offset == 0)
return -1;
if (visorchannel_write(chan, off, info, sizeof(*info)) < 0)
return -1;
return 0;
}
/* For a child device just created on a client bus, fill in
* information about the driver that is controlling this device into
* the the appropriate slot within the vbus channel of the bus
* instance.
*/
static void
fix_vbus_dev_info(struct visor_device *visordev)
{
int i;
struct visorchipset_bus_info bus_info;
struct visorbus_devdata *devdata = NULL;
struct visor_driver *visordrv;
int bus_no = visordev->chipset_bus_no;
int dev_no = visordev->chipset_dev_no;
struct ultra_vbus_deviceinfo dev_info;
const char *chan_type_name = NULL;
if (!visordev->device.driver)
return;
visordrv = to_visor_driver(visordev->device.driver);
if (!visorchipset_get_bus_info(bus_no, &bus_info))
return;
devdata = (struct visorbus_devdata *)(bus_info.bus_driver_context);
if (!devdata)
return;
if (!devdata->vbus_valid)
return;
/* Within the list of device types (by GUID) that the driver
* says it supports, find out which one of those types matches
* the type of this device, so that we can include the device
* type name
*/
for (i = 0; visordrv->channel_types[i].name; i++) {
if (STRUCTSEQUAL(visordrv->channel_types[i].guid,
visordev->channel_type_guid)) {
chan_type_name = visordrv->channel_types[i].name;
break;
}
}
bus_device_info_init(&dev_info, chan_type_name,
visordrv->name, visordrv->version,
visordrv->vertag);
write_vbus_dev_info(devdata->chan,
&devdata->vbus_hdr_info, &dev_info, dev_no);
/* Re-write bus+chipset info, because it is possible that this
* was previously written by our evil counterpart, virtpci.
*/
write_vbus_chp_info(devdata->chan, &devdata->vbus_hdr_info,
&chipset_driverinfo);
write_vbus_bus_info(devdata->chan, &devdata->vbus_hdr_info,
&clientbus_driverinfo);
}
/** Create a device instance for the visor bus itself.
*/
static struct visorbus_devdata *
create_bus_instance(int id)
{
struct visorbus_devdata *rc = NULL;
struct visorbus_devdata *devdata = NULL;
struct device *dev;
struct visorchipset_bus_info bus_info;
POSTCODE_LINUX_2(BUS_CREATE_ENTRY_PC, POSTCODE_SEVERITY_INFO);
dev = kmalloc(sizeof(*dev), GFP_KERNEL);
if (!dev) {
POSTCODE_LINUX_2(MALLOC_FAILURE_PC, POSTCODE_SEVERITY_ERR);
rc = NULL;
goto away;
}
memset(dev, 0, sizeof(struct device));
dev_set_name(dev, "visorbus%d", id);
dev->release = visorbus_release_busdevice;
if (device_register(dev) < 0) {
POSTCODE_LINUX_3(DEVICE_CREATE_FAILURE_PC, id,
POSTCODE_SEVERITY_ERR);
rc = NULL;
goto away;
}
devdata = kmalloc(sizeof(*devdata), GFP_KERNEL);
if (!devdata) {
POSTCODE_LINUX_2(MALLOC_FAILURE_PC, POSTCODE_SEVERITY_ERR);
rc = NULL;
goto away;
}
memset(devdata, 0, sizeof(struct visorbus_devdata));
devdata->devno = id;
devdata->dev = dev;
if ((visorchipset_get_bus_info(id, &bus_info)) &&
(bus_info.chan_info.channel_addr > 0) &&
(bus_info.chan_info.n_channel_bytes > 0)) {
HOSTADDRESS channel_addr = bus_info.chan_info.channel_addr;
unsigned long n_channel_bytes =
(unsigned long)
bus_info.chan_info.n_channel_bytes;
uuid_le channel_type_guid =
bus_info.chan_info.channel_type_uuid;
devdata->chan = visorchannel_create(channel_addr,
n_channel_bytes,
channel_type_guid);
if (!devdata->chan) {
POSTCODE_LINUX_3(DEVICE_CREATE_FAILURE_PC, channel_addr,
POSTCODE_SEVERITY_ERR);
} else {
if (bus_info.flags.server) {
init_vbus_channel(devdata->chan);
} else {
if (get_vbus_header_info(devdata->chan,
&devdata->
vbus_hdr_info) >= 0) {
devdata->vbus_valid = TRUE;
write_vbus_chp_info(devdata->chan,
&devdata->
vbus_hdr_info,
&chipset_driverinfo
);
write_vbus_bus_info(devdata->chan,
&devdata->
vbus_hdr_info,
&clientbus_driverinfo);
}
}
}
}
register_businst_attributes(devdata);
bus_count++;
list_add_tail(&devdata->list_all, &list_all_bus_instances);
if (id == 0)
devdata = devdata; /* for testing ONLY */
dev_set_drvdata(dev, devdata);
rc = devdata;
away:
return rc;
}
/** Remove a device instance for the visor bus itself.
*/
static void
remove_bus_instance(struct visorbus_devdata *devdata)
{
/* Note that this will result in the release method for
* devdata->dev being called, which will call
* visorbus_release_busdevice(). This has something to do with
* the put_device() done in device_unregister(), but I have never
* successfully been able to trace thru the code to see where/how
* release() gets called. But I know it does.
*/
unregister_businst_attributes(devdata);
bus_count--;
if (devdata->chan) {
visorchannel_destroy(devdata->chan);
devdata->chan = NULL;
}
list_del(&devdata->list_all);
device_unregister(devdata->dev);
}
/** Create and register the one-and-only one instance of
* the visor bus type (visorbus_type).
*/
static int
create_bus_type(void)
{
int rc = 0;
visorbus_type.dev_attrs = visor_device_attrs;
rc = bus_register(&visorbus_type);
if (rc < 0)
return rc;
rc = register_bustype_attributes();
return rc;
}
/** Remove the one-and-only one instance of the visor bus type (visorbus_type).
*/
static void
remove_bus_type(void)
{
unregister_bustype_attributes();
bus_unregister(&visorbus_type);
}
/** Remove all child visor bus device instances.
*/
static void
remove_all_visor_devices(void)
{
struct list_head *listentry, *listtmp;
list_for_each_safe(listentry, listtmp, &list_all_device_instances) {
struct visor_device *dev = list_entry(listentry,
struct visor_device,
list_all);
remove_visor_device(dev);
}
}
static bool entered_testing_mode = FALSE;
static struct visorchipset_channel_info test_channel_infos[MAXDEVICETEST];
static unsigned long test_bus_nos[MAXDEVICETEST];
static unsigned long test_dev_nos[MAXDEVICETEST];
static void
chipset_bus_create(u32 bus_no)
{
struct visorchipset_bus_info bus_info;
struct visorbus_devdata *devdata;
int rc = -1;
POSTCODE_LINUX_3(BUS_CREATE_ENTRY_PC, bus_no, POSTCODE_SEVERITY_INFO);
if (!visorchipset_get_bus_info(bus_no, &bus_info))
goto away;
devdata = create_bus_instance(bus_no);
if (!devdata)
goto away;
if (!visorchipset_set_bus_context(bus_no, devdata))
goto away;
POSTCODE_LINUX_3(BUS_CREATE_EXIT_PC, bus_no, POSTCODE_SEVERITY_INFO);
rc = 0;
away:
if (rc < 0) {
POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, bus_no,
POSTCODE_SEVERITY_ERR);
return;
}
POSTCODE_LINUX_3(CHIPSET_INIT_SUCCESS_PC, bus_no,
POSTCODE_SEVERITY_INFO);
if (chipset_responders.bus_create)
(*chipset_responders.bus_create) (bus_no, rc);
}
static void
chipset_bus_destroy(u32 bus_no)
{
struct visorchipset_bus_info bus_info;
struct visorbus_devdata *devdata;
int rc = -1;
if (!visorchipset_get_bus_info(bus_no, &bus_info))
goto away;
devdata = (struct visorbus_devdata *)(bus_info.bus_driver_context);
if (!devdata)
goto away;
remove_bus_instance(devdata);
if (!visorchipset_set_bus_context(bus_no, NULL))
goto away;
rc = 0;
away:
if (rc < 0)
return;
if (chipset_responders.bus_destroy)
(*chipset_responders.bus_destroy)(bus_no, rc);
}
static void
chipset_device_create(u32 bus_no, u32 dev_no)
{
struct visorchipset_device_info dev_info;
struct visorchipset_bus_info bus_info;
struct visorbus_devdata *devdata = NULL;
int rc = -1;
POSTCODE_LINUX_4(DEVICE_CREATE_ENTRY_PC, dev_no, bus_no,
POSTCODE_SEVERITY_INFO);
if (entered_testing_mode)
return;
if (!visorchipset_get_device_info(bus_no, dev_no, &dev_info))
goto away;
if (!visorchipset_get_bus_info(bus_no, &bus_info))
goto away;
if (visorbus_devicetest)
if (total_devices_created < MAXDEVICETEST) {
test_channel_infos[total_devices_created] =
dev_info.chan_info;
test_bus_nos[total_devices_created] = bus_no;
test_dev_nos[total_devices_created] = dev_no;
}
POSTCODE_LINUX_4(DEVICE_CREATE_EXIT_PC, dev_no, bus_no,
POSTCODE_SEVERITY_INFO);
rc = 0;
away:
if (rc < 0) {
POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, dev_no, bus_no,
POSTCODE_SEVERITY_ERR);
return;
}
devdata = (struct visorbus_devdata *)(bus_info.bus_driver_context);
rc = create_visor_device(devdata, bus_no, dev_no,
dev_info.chan_info, bus_info.partition_handle);
POSTCODE_LINUX_4(DEVICE_CREATE_SUCCESS_PC, dev_no, bus_no,
POSTCODE_SEVERITY_INFO);
if (rc < 0)
if (chipset_responders.device_create)
(*chipset_responders.device_create)(bus_no, dev_no, rc);
}
static void
chipset_device_destroy(u32 bus_no, u32 dev_no)
{
struct visorchipset_device_info dev_info;
struct visor_device *dev;
int rc = -1;
if (entered_testing_mode)
return;
if (!visorchipset_get_device_info(bus_no, dev_no, &dev_info))
goto away;
dev = find_visor_device_by_channel(dev_info.chan_info.channel_addr);
if (!dev)
goto away;
rc = 0;
away:
if (rc < 0)
return;
if (chipset_responders.device_destroy)
(*chipset_responders.device_destroy) (bus_no, dev_no, rc);
remove_visor_device(dev);
}
/* This is the callback function specified for a function driver, to
* be called when a pending "pause device" operation has been
* completed.
*/
static void
pause_state_change_complete(struct visor_device *dev, int status)
{
if (!dev->pausing)
return;
dev->pausing = FALSE;
if (!chipset_responders.device_pause) /* this can never happen! */
return;
/* Notify the chipset driver that the pause is complete, which
* will presumably want to send some sort of response to the
* initiator. */
(*chipset_responders.device_pause) (dev->chipset_bus_no,
dev->chipset_dev_no, status);
}
/* This is the callback function specified for a function driver, to
* be called when a pending "resume device" operation has been
* completed.
*/
static void
resume_state_change_complete(struct visor_device *dev, int status)
{
if (!dev->resuming)
return;
dev->resuming = FALSE;
if (!chipset_responders.device_resume) /* this can never happen! */
return;
/* Notify the chipset driver that the resume is complete,
* which will presumably want to send some sort of response to
* the initiator. */
(*chipset_responders.device_resume) (dev->chipset_bus_no,
dev->chipset_dev_no, status);
}
/* Tell the subordinate function driver for a specific device to pause
* or resume that device. Result is returned asynchronously via a
* callback function.
*/
static void
initiate_chipset_device_pause_resume(u32 bus_no, u32 dev_no, bool is_pause)
{
struct visorchipset_device_info dev_info;
struct visor_device *dev = NULL;
int rc = -1, x;
struct visor_driver *drv = NULL;
void (*notify_func)(u32 bus_no, u32 dev_no, int response) = NULL;
if (is_pause)
notify_func = chipset_responders.device_pause;
else
notify_func = chipset_responders.device_resume;
if (!notify_func)
goto away;
if (!visorchipset_get_device_info(bus_no, dev_no, &dev_info))
goto away;
dev = find_visor_device_by_channel(dev_info.chan_info.channel_addr);
if (!dev)
goto away;
drv = to_visor_driver(dev->device.driver);
if (!drv)
goto away;
if (dev->pausing || dev->resuming)
goto away;
/* Note that even though both drv->pause() and drv->resume
* specify a callback function, it is NOT necessary for us to
* increment our local module usage count. Reason is, there
* is already a linkage dependency between child function
* drivers and visorbus, so it is already IMPOSSIBLE to unload
* visorbus while child function drivers are still running.
*/
if (is_pause) {
if (!drv->pause)
goto away;
dev->pausing = TRUE;
x = drv->pause(dev, pause_state_change_complete);
} else {
/* This should be done at BUS resume time, but an
* existing problem prevents us from ever getting a bus
* resume... This hack would fail to work should we
* ever have a bus that contains NO devices, since we
* would never even get here in that case. */
fix_vbus_dev_info(dev);
if (!drv->resume)
goto away;
dev->resuming = TRUE;
x = drv->resume(dev, resume_state_change_complete);
}
if (x < 0) {
if (is_pause)
dev->pausing = FALSE;
else
dev->resuming = FALSE;
goto away;
}
rc = 0;
away:
if (rc < 0) {
if (notify_func)
(*notify_func)(bus_no, dev_no, rc);
}
}
static void
chipset_device_pause(u32 bus_no, u32 dev_no)
{
initiate_chipset_device_pause_resume(bus_no, dev_no, TRUE);
}
static void
chipset_device_resume(u32 bus_no, u32 dev_no)
{
initiate_chipset_device_pause_resume(bus_no, dev_no, FALSE);
}
struct channel_size_info {
uuid_le guid;
unsigned long min_size;
unsigned long max_size;
};
static int __init
visorbus_init(void)
{
int rc = 0;
POSTCODE_LINUX_3(DRIVER_ENTRY_PC, rc, POSTCODE_SEVERITY_INFO);
bus_device_info_init(&clientbus_driverinfo,
"clientbus", MYDRVNAME,
VERSION, NULL);
/* process module options */
if (visorbus_devicetest > MAXDEVICETEST)
visorbus_devicetest = MAXDEVICETEST;
rc = create_bus_type();
if (rc < 0) {
POSTCODE_LINUX_2(BUS_CREATE_ENTRY_PC, DIAG_SEVERITY_ERR);
goto away;
}
periodic_dev_workqueue = create_singlethread_workqueue("visorbus_dev");
if (!periodic_dev_workqueue) {
POSTCODE_LINUX_2(CREATE_WORKQUEUE_PC, DIAG_SEVERITY_ERR);
rc = -ENOMEM;
goto away;
}
/* This enables us to receive notifications when devices appear for
* which this service partition is to be a server for.
*/
visorchipset_register_busdev_server(&chipset_notifiers,
&chipset_responders,
&chipset_driverinfo);
rc = 0;
away:
if (rc)
POSTCODE_LINUX_3(CHIPSET_INIT_FAILURE_PC, rc,
POSTCODE_SEVERITY_ERR);
return rc;
}
static void
visorbus_exit(void)
{
struct list_head *listentry, *listtmp;
visorchipset_register_busdev_server(NULL, NULL, NULL);
remove_all_visor_devices();
flush_workqueue(periodic_dev_workqueue); /* better not be any work! */
destroy_workqueue(periodic_dev_workqueue);
periodic_dev_workqueue = NULL;
if (periodic_test_workqueue) {
cancel_delayed_work(&periodic_work);
flush_workqueue(periodic_test_workqueue);
destroy_workqueue(periodic_test_workqueue);
periodic_test_workqueue = NULL;
}
list_for_each_safe(listentry, listtmp, &list_all_bus_instances) {
struct visorbus_devdata *devdata = list_entry(listentry,
struct
visorbus_devdata,
list_all);
remove_bus_instance(devdata);
}
remove_bus_type();
}
module_param_named(debug, visorbus_debug, int, S_IRUGO);
MODULE_PARM_DESC(visorbus_debug, "1 to debug");
int visorbus_debug = 0;
module_param_named(forcematch, visorbus_forcematch, int, S_IRUGO);
MODULE_PARM_DESC(visorbus_forcematch,
"1 to force a successful dev <--> drv match");
int visorbus_forcematch = 0;
module_param_named(forcenomatch, visorbus_forcenomatch, int, S_IRUGO);
MODULE_PARM_DESC(visorbus_forcenomatch,
"1 to force an UNsuccessful dev <--> drv match");
int visorbus_forcenomatch = 0;
module_param_named(devicetest, visorbus_devicetest, int, S_IRUGO);
MODULE_PARM_DESC(visorbus_devicetest,
"non-0 to just test device creation and destruction");
int visorbus_devicetest = 0;
module_param_named(debugref, visorbus_debugref, int, S_IRUGO);
MODULE_PARM_DESC(visorbus_debugref, "1 to debug reference counting");
int visorbus_debugref = 0;
module_param_named(serialloopbacktest, visorbus_serialloopbacktest,
int, S_IRUGO);
MODULE_PARM_DESC(visorbus_serialloopbacktest,
"non-0 to just create 2 serial devices on the same channel");
int visorbus_serialloopbacktest = 0;
module_init(visorbus_init);
module_exit(visorbus_exit);
MODULE_AUTHOR("Unisys");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Supervisor bus driver for service partition: ver " VERSION);
MODULE_VERSION(VERSION);