18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright � 2010 - 2015 UNISYS CORPORATION
48c2ecf20Sopenharmony_ci * All rights reserved.
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <linux/ctype.h>
88c2ecf20Sopenharmony_ci#include <linux/debugfs.h>
98c2ecf20Sopenharmony_ci#include <linux/module.h>
108c2ecf20Sopenharmony_ci#include <linux/slab.h>
118c2ecf20Sopenharmony_ci#include <linux/visorbus.h>
128c2ecf20Sopenharmony_ci#include <linux/uuid.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include "visorbus_private.h"
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_cistatic const guid_t visor_vbus_channel_guid = VISOR_VBUS_CHANNEL_GUID;
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci/* Display string that is guaranteed to be no longer the 99 characters */
198c2ecf20Sopenharmony_ci#define LINESIZE 99
208c2ecf20Sopenharmony_ci#define POLLJIFFIES_NORMALCHANNEL 10
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci/* stores whether bus_registration was successful */
238c2ecf20Sopenharmony_cistatic bool initialized;
248c2ecf20Sopenharmony_cistatic struct dentry *visorbus_debugfs_dir;
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci/*
278c2ecf20Sopenharmony_ci * DEVICE type attributes
288c2ecf20Sopenharmony_ci *
298c2ecf20Sopenharmony_ci * The modalias file will contain the guid of the device.
308c2ecf20Sopenharmony_ci */
318c2ecf20Sopenharmony_cistatic ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
328c2ecf20Sopenharmony_ci			     char *buf)
338c2ecf20Sopenharmony_ci{
348c2ecf20Sopenharmony_ci	struct visor_device *vdev;
358c2ecf20Sopenharmony_ci	const guid_t *guid;
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	vdev = to_visor_device(dev);
388c2ecf20Sopenharmony_ci	guid = visorchannel_get_guid(vdev->visorchannel);
398c2ecf20Sopenharmony_ci	return sprintf(buf, "visorbus:%pUl\n", guid);
408c2ecf20Sopenharmony_ci}
418c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(modalias);
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_cistatic struct attribute *visorbus_dev_attrs[] = {
448c2ecf20Sopenharmony_ci	&dev_attr_modalias.attr,
458c2ecf20Sopenharmony_ci	NULL,
468c2ecf20Sopenharmony_ci};
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ciATTRIBUTE_GROUPS(visorbus_dev);
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci/* filled in with info about parent chipset driver when we register with it */
518c2ecf20Sopenharmony_cistatic struct visor_vbus_deviceinfo chipset_driverinfo;
528c2ecf20Sopenharmony_ci/* filled in with info about this driver, wrt it servicing client busses */
538c2ecf20Sopenharmony_cistatic struct visor_vbus_deviceinfo clientbus_driverinfo;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci/* list of visor_device structs, linked via .list_all */
568c2ecf20Sopenharmony_cistatic LIST_HEAD(list_all_bus_instances);
578c2ecf20Sopenharmony_ci/* list of visor_device structs, linked via .list_all */
588c2ecf20Sopenharmony_cistatic LIST_HEAD(list_all_device_instances);
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci/*
618c2ecf20Sopenharmony_ci * Generic function useful for validating any type of channel when it is
628c2ecf20Sopenharmony_ci * received by the client that will be accessing the channel.
638c2ecf20Sopenharmony_ci * Note that <logCtx> is only needed for callers in the EFI environment, and
648c2ecf20Sopenharmony_ci * is used to pass the EFI_DIAG_CAPTURE_PROTOCOL needed to log messages.
658c2ecf20Sopenharmony_ci */
668c2ecf20Sopenharmony_ciint visor_check_channel(struct channel_header *ch, struct device *dev,
678c2ecf20Sopenharmony_ci			const guid_t *expected_guid, char *chname,
688c2ecf20Sopenharmony_ci			u64 expected_min_bytes, u32 expected_version,
698c2ecf20Sopenharmony_ci			u64 expected_signature)
708c2ecf20Sopenharmony_ci{
718c2ecf20Sopenharmony_ci	if (!guid_is_null(expected_guid)) {
728c2ecf20Sopenharmony_ci		/* caller wants us to verify type GUID */
738c2ecf20Sopenharmony_ci		if (!guid_equal(&ch->chtype, expected_guid)) {
748c2ecf20Sopenharmony_ci			dev_err(dev, "Channel mismatch on channel=%s(%pUL) field=type expected=%pUL actual=%pUL\n",
758c2ecf20Sopenharmony_ci				chname, expected_guid, expected_guid,
768c2ecf20Sopenharmony_ci				&ch->chtype);
778c2ecf20Sopenharmony_ci			return 0;
788c2ecf20Sopenharmony_ci		}
798c2ecf20Sopenharmony_ci	}
808c2ecf20Sopenharmony_ci	/* verify channel size */
818c2ecf20Sopenharmony_ci	if (expected_min_bytes > 0) {
828c2ecf20Sopenharmony_ci		if (ch->size < expected_min_bytes) {
838c2ecf20Sopenharmony_ci			dev_err(dev, "Channel mismatch on channel=%s(%pUL) field=size expected=0x%-8.8Lx actual=0x%-8.8Lx\n",
848c2ecf20Sopenharmony_ci				chname, expected_guid,
858c2ecf20Sopenharmony_ci				(unsigned long long)expected_min_bytes,
868c2ecf20Sopenharmony_ci				ch->size);
878c2ecf20Sopenharmony_ci			return 0;
888c2ecf20Sopenharmony_ci		}
898c2ecf20Sopenharmony_ci	}
908c2ecf20Sopenharmony_ci	/* verify channel version */
918c2ecf20Sopenharmony_ci	if (expected_version > 0) {
928c2ecf20Sopenharmony_ci		if (ch->version_id != expected_version) {
938c2ecf20Sopenharmony_ci			dev_err(dev, "Channel mismatch on channel=%s(%pUL) field=version expected=0x%-8.8lx actual=0x%-8.8x\n",
948c2ecf20Sopenharmony_ci				chname, expected_guid,
958c2ecf20Sopenharmony_ci				(unsigned long)expected_version,
968c2ecf20Sopenharmony_ci				ch->version_id);
978c2ecf20Sopenharmony_ci			return 0;
988c2ecf20Sopenharmony_ci		}
998c2ecf20Sopenharmony_ci	}
1008c2ecf20Sopenharmony_ci	/* verify channel signature */
1018c2ecf20Sopenharmony_ci	if (expected_signature > 0) {
1028c2ecf20Sopenharmony_ci		if (ch->signature != expected_signature) {
1038c2ecf20Sopenharmony_ci			dev_err(dev, "Channel mismatch on channel=%s(%pUL) field=signature expected=0x%-8.8Lx actual=0x%-8.8Lx\n",
1048c2ecf20Sopenharmony_ci				chname, expected_guid,	expected_signature,
1058c2ecf20Sopenharmony_ci				ch->signature);
1068c2ecf20Sopenharmony_ci			return 0;
1078c2ecf20Sopenharmony_ci		}
1088c2ecf20Sopenharmony_ci	}
1098c2ecf20Sopenharmony_ci	return 1;
1108c2ecf20Sopenharmony_ci}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_cistatic int visorbus_uevent(struct device *xdev, struct kobj_uevent_env *env)
1138c2ecf20Sopenharmony_ci{
1148c2ecf20Sopenharmony_ci	struct visor_device *dev;
1158c2ecf20Sopenharmony_ci	const guid_t *guid;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	dev = to_visor_device(xdev);
1188c2ecf20Sopenharmony_ci	guid = visorchannel_get_guid(dev->visorchannel);
1198c2ecf20Sopenharmony_ci	return add_uevent_var(env, "MODALIAS=visorbus:%pUl", guid);
1208c2ecf20Sopenharmony_ci}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci/*
1238c2ecf20Sopenharmony_ci * visorbus_match() - called automatically upon adding a visor_device
1248c2ecf20Sopenharmony_ci *                    (device_add), or adding a visor_driver
1258c2ecf20Sopenharmony_ci *                    (visorbus_register_visor_driver)
1268c2ecf20Sopenharmony_ci * @xdev: struct device for the device being matched
1278c2ecf20Sopenharmony_ci * @xdrv: struct device_driver for driver to match device against
1288c2ecf20Sopenharmony_ci *
1298c2ecf20Sopenharmony_ci * Return: 1 iff the provided driver can control the specified device
1308c2ecf20Sopenharmony_ci */
1318c2ecf20Sopenharmony_cistatic int visorbus_match(struct device *xdev, struct device_driver *xdrv)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	const guid_t *channel_type;
1348c2ecf20Sopenharmony_ci	int i;
1358c2ecf20Sopenharmony_ci	struct visor_device *dev;
1368c2ecf20Sopenharmony_ci	struct visor_driver *drv;
1378c2ecf20Sopenharmony_ci	struct visorchannel *chan;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	dev = to_visor_device(xdev);
1408c2ecf20Sopenharmony_ci	channel_type = visorchannel_get_guid(dev->visorchannel);
1418c2ecf20Sopenharmony_ci	drv = to_visor_driver(xdrv);
1428c2ecf20Sopenharmony_ci	chan = dev->visorchannel;
1438c2ecf20Sopenharmony_ci	if (!drv->channel_types)
1448c2ecf20Sopenharmony_ci		return 0;
1458c2ecf20Sopenharmony_ci	for (i = 0; !guid_is_null(&drv->channel_types[i].guid); i++)
1468c2ecf20Sopenharmony_ci		if (guid_equal(&drv->channel_types[i].guid, channel_type) &&
1478c2ecf20Sopenharmony_ci		    visor_check_channel(visorchannel_get_header(chan),
1488c2ecf20Sopenharmony_ci					xdev,
1498c2ecf20Sopenharmony_ci					&drv->channel_types[i].guid,
1508c2ecf20Sopenharmony_ci					(char *)drv->channel_types[i].name,
1518c2ecf20Sopenharmony_ci					drv->channel_types[i].min_bytes,
1528c2ecf20Sopenharmony_ci					drv->channel_types[i].version,
1538c2ecf20Sopenharmony_ci					VISOR_CHANNEL_SIGNATURE))
1548c2ecf20Sopenharmony_ci			return i + 1;
1558c2ecf20Sopenharmony_ci	return 0;
1568c2ecf20Sopenharmony_ci}
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci/*
1598c2ecf20Sopenharmony_ci * This describes the TYPE of bus.
1608c2ecf20Sopenharmony_ci * (Don't confuse this with an INSTANCE of the bus.)
1618c2ecf20Sopenharmony_ci */
1628c2ecf20Sopenharmony_cistatic struct bus_type visorbus_type = {
1638c2ecf20Sopenharmony_ci	.name = "visorbus",
1648c2ecf20Sopenharmony_ci	.match = visorbus_match,
1658c2ecf20Sopenharmony_ci	.uevent = visorbus_uevent,
1668c2ecf20Sopenharmony_ci	.dev_groups = visorbus_dev_groups,
1678c2ecf20Sopenharmony_ci};
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_cistruct visor_busdev {
1708c2ecf20Sopenharmony_ci	u32 bus_no;
1718c2ecf20Sopenharmony_ci	u32 dev_no;
1728c2ecf20Sopenharmony_ci};
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_cistatic int match_visorbus_dev_by_id(struct device *dev, const void *data)
1758c2ecf20Sopenharmony_ci{
1768c2ecf20Sopenharmony_ci	struct visor_device *vdev = to_visor_device(dev);
1778c2ecf20Sopenharmony_ci	const struct visor_busdev *id = data;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	if (vdev->chipset_bus_no == id->bus_no &&
1808c2ecf20Sopenharmony_ci	    vdev->chipset_dev_no == id->dev_no)
1818c2ecf20Sopenharmony_ci		return 1;
1828c2ecf20Sopenharmony_ci	return 0;
1838c2ecf20Sopenharmony_ci}
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_cistruct visor_device *visorbus_get_device_by_id(u32 bus_no, u32 dev_no,
1868c2ecf20Sopenharmony_ci					       struct visor_device *from)
1878c2ecf20Sopenharmony_ci{
1888c2ecf20Sopenharmony_ci	struct device *dev;
1898c2ecf20Sopenharmony_ci	struct device *dev_start = NULL;
1908c2ecf20Sopenharmony_ci	struct visor_busdev id = {
1918c2ecf20Sopenharmony_ci		.bus_no = bus_no,
1928c2ecf20Sopenharmony_ci		.dev_no = dev_no
1938c2ecf20Sopenharmony_ci	};
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	if (from)
1968c2ecf20Sopenharmony_ci		dev_start = &from->device;
1978c2ecf20Sopenharmony_ci	dev = bus_find_device(&visorbus_type, dev_start, (void *)&id,
1988c2ecf20Sopenharmony_ci			      match_visorbus_dev_by_id);
1998c2ecf20Sopenharmony_ci	if (!dev)
2008c2ecf20Sopenharmony_ci		return NULL;
2018c2ecf20Sopenharmony_ci	return to_visor_device(dev);
2028c2ecf20Sopenharmony_ci}
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci/*
2058c2ecf20Sopenharmony_ci * visorbus_release_busdevice() - called when device_unregister() is called for
2068c2ecf20Sopenharmony_ci *                                the bus device instance, after all other tasks
2078c2ecf20Sopenharmony_ci *                                involved with destroying the dev are complete
2088c2ecf20Sopenharmony_ci * @xdev: struct device for the bus being released
2098c2ecf20Sopenharmony_ci */
2108c2ecf20Sopenharmony_cistatic void visorbus_release_busdevice(struct device *xdev)
2118c2ecf20Sopenharmony_ci{
2128c2ecf20Sopenharmony_ci	struct visor_device *dev = dev_get_drvdata(xdev);
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	debugfs_remove(dev->debugfs_bus_info);
2158c2ecf20Sopenharmony_ci	debugfs_remove_recursive(dev->debugfs_dir);
2168c2ecf20Sopenharmony_ci	visorchannel_destroy(dev->visorchannel);
2178c2ecf20Sopenharmony_ci	kfree(dev);
2188c2ecf20Sopenharmony_ci}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci/*
2218c2ecf20Sopenharmony_ci * visorbus_release_device() - called when device_unregister() is called for
2228c2ecf20Sopenharmony_ci *                             each child device instance
2238c2ecf20Sopenharmony_ci * @xdev: struct device for the visor device being released
2248c2ecf20Sopenharmony_ci */
2258c2ecf20Sopenharmony_cistatic void visorbus_release_device(struct device *xdev)
2268c2ecf20Sopenharmony_ci{
2278c2ecf20Sopenharmony_ci	struct visor_device *dev = to_visor_device(xdev);
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	visorchannel_destroy(dev->visorchannel);
2308c2ecf20Sopenharmony_ci	kfree(dev);
2318c2ecf20Sopenharmony_ci}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci/*
2348c2ecf20Sopenharmony_ci * BUS specific channel attributes to appear under
2358c2ecf20Sopenharmony_ci * /sys/bus/visorbus<x>/dev<y>/channel
2368c2ecf20Sopenharmony_ci */
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_cistatic ssize_t physaddr_show(struct device *dev, struct device_attribute *attr,
2398c2ecf20Sopenharmony_ci			     char *buf)
2408c2ecf20Sopenharmony_ci{
2418c2ecf20Sopenharmony_ci	struct visor_device *vdev = to_visor_device(dev);
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	return sprintf(buf, "0x%llx\n",
2448c2ecf20Sopenharmony_ci		       visorchannel_get_physaddr(vdev->visorchannel));
2458c2ecf20Sopenharmony_ci}
2468c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(physaddr);
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_cistatic ssize_t nbytes_show(struct device *dev, struct device_attribute *attr,
2498c2ecf20Sopenharmony_ci			   char *buf)
2508c2ecf20Sopenharmony_ci{
2518c2ecf20Sopenharmony_ci	struct visor_device *vdev = to_visor_device(dev);
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	return sprintf(buf, "0x%lx\n",
2548c2ecf20Sopenharmony_ci		       visorchannel_get_nbytes(vdev->visorchannel));
2558c2ecf20Sopenharmony_ci}
2568c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(nbytes);
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_cistatic ssize_t clientpartition_show(struct device *dev,
2598c2ecf20Sopenharmony_ci				    struct device_attribute *attr, char *buf)
2608c2ecf20Sopenharmony_ci{
2618c2ecf20Sopenharmony_ci	struct visor_device *vdev = to_visor_device(dev);
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	return sprintf(buf, "0x%llx\n",
2648c2ecf20Sopenharmony_ci		       visorchannel_get_clientpartition(vdev->visorchannel));
2658c2ecf20Sopenharmony_ci}
2668c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(clientpartition);
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_cistatic ssize_t typeguid_show(struct device *dev, struct device_attribute *attr,
2698c2ecf20Sopenharmony_ci			     char *buf)
2708c2ecf20Sopenharmony_ci{
2718c2ecf20Sopenharmony_ci	struct visor_device *vdev = to_visor_device(dev);
2728c2ecf20Sopenharmony_ci	char typeid[LINESIZE];
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	return sprintf(buf, "%s\n",
2758c2ecf20Sopenharmony_ci		       visorchannel_id(vdev->visorchannel, typeid));
2768c2ecf20Sopenharmony_ci}
2778c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(typeguid);
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_cistatic ssize_t zoneguid_show(struct device *dev, struct device_attribute *attr,
2808c2ecf20Sopenharmony_ci			     char *buf)
2818c2ecf20Sopenharmony_ci{
2828c2ecf20Sopenharmony_ci	struct visor_device *vdev = to_visor_device(dev);
2838c2ecf20Sopenharmony_ci	char zoneid[LINESIZE];
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	return sprintf(buf, "%s\n",
2868c2ecf20Sopenharmony_ci		       visorchannel_zoneid(vdev->visorchannel, zoneid));
2878c2ecf20Sopenharmony_ci}
2888c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(zoneguid);
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_cistatic ssize_t typename_show(struct device *dev, struct device_attribute *attr,
2918c2ecf20Sopenharmony_ci			     char *buf)
2928c2ecf20Sopenharmony_ci{
2938c2ecf20Sopenharmony_ci	int i = 0;
2948c2ecf20Sopenharmony_ci	struct bus_type *xbus = dev->bus;
2958c2ecf20Sopenharmony_ci	struct device_driver *xdrv = dev->driver;
2968c2ecf20Sopenharmony_ci	struct visor_driver *drv = NULL;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	if (!xdrv)
2998c2ecf20Sopenharmony_ci		return 0;
3008c2ecf20Sopenharmony_ci	i = xbus->match(dev, xdrv);
3018c2ecf20Sopenharmony_ci	if (!i)
3028c2ecf20Sopenharmony_ci		return 0;
3038c2ecf20Sopenharmony_ci	drv = to_visor_driver(xdrv);
3048c2ecf20Sopenharmony_ci	return sprintf(buf, "%s\n", drv->channel_types[i - 1].name);
3058c2ecf20Sopenharmony_ci}
3068c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(typename);
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_cistatic struct attribute *channel_attrs[] = {
3098c2ecf20Sopenharmony_ci	&dev_attr_physaddr.attr,
3108c2ecf20Sopenharmony_ci	&dev_attr_nbytes.attr,
3118c2ecf20Sopenharmony_ci	&dev_attr_clientpartition.attr,
3128c2ecf20Sopenharmony_ci	&dev_attr_typeguid.attr,
3138c2ecf20Sopenharmony_ci	&dev_attr_zoneguid.attr,
3148c2ecf20Sopenharmony_ci	&dev_attr_typename.attr,
3158c2ecf20Sopenharmony_ci	NULL
3168c2ecf20Sopenharmony_ci};
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ciATTRIBUTE_GROUPS(channel);
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci/*
3218c2ecf20Sopenharmony_ci *  BUS instance attributes
3228c2ecf20Sopenharmony_ci *
3238c2ecf20Sopenharmony_ci *  define & implement display of bus attributes under
3248c2ecf20Sopenharmony_ci *  /sys/bus/visorbus/devices/visorbus<n>.
3258c2ecf20Sopenharmony_ci */
3268c2ecf20Sopenharmony_cistatic ssize_t partition_handle_show(struct device *dev,
3278c2ecf20Sopenharmony_ci				     struct device_attribute *attr, char *buf)
3288c2ecf20Sopenharmony_ci{
3298c2ecf20Sopenharmony_ci	struct visor_device *vdev = to_visor_device(dev);
3308c2ecf20Sopenharmony_ci	u64 handle = visorchannel_get_clientpartition(vdev->visorchannel);
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	return sprintf(buf, "0x%llx\n", handle);
3338c2ecf20Sopenharmony_ci}
3348c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(partition_handle);
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_cistatic ssize_t partition_guid_show(struct device *dev,
3378c2ecf20Sopenharmony_ci				   struct device_attribute *attr, char *buf)
3388c2ecf20Sopenharmony_ci{
3398c2ecf20Sopenharmony_ci	struct visor_device *vdev = to_visor_device(dev);
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	return sprintf(buf, "{%pUb}\n", &vdev->partition_guid);
3428c2ecf20Sopenharmony_ci}
3438c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(partition_guid);
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_cistatic ssize_t partition_name_show(struct device *dev,
3468c2ecf20Sopenharmony_ci				   struct device_attribute *attr, char *buf)
3478c2ecf20Sopenharmony_ci{
3488c2ecf20Sopenharmony_ci	struct visor_device *vdev = to_visor_device(dev);
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	return sprintf(buf, "%s\n", vdev->name);
3518c2ecf20Sopenharmony_ci}
3528c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(partition_name);
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_cistatic ssize_t channel_addr_show(struct device *dev,
3558c2ecf20Sopenharmony_ci				 struct device_attribute *attr, char *buf)
3568c2ecf20Sopenharmony_ci{
3578c2ecf20Sopenharmony_ci	struct visor_device *vdev = to_visor_device(dev);
3588c2ecf20Sopenharmony_ci	u64 addr = visorchannel_get_physaddr(vdev->visorchannel);
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	return sprintf(buf, "0x%llx\n", addr);
3618c2ecf20Sopenharmony_ci}
3628c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(channel_addr);
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_cistatic ssize_t channel_bytes_show(struct device *dev,
3658c2ecf20Sopenharmony_ci				  struct device_attribute *attr, char *buf)
3668c2ecf20Sopenharmony_ci{
3678c2ecf20Sopenharmony_ci	struct visor_device *vdev = to_visor_device(dev);
3688c2ecf20Sopenharmony_ci	u64 nbytes = visorchannel_get_nbytes(vdev->visorchannel);
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	return sprintf(buf, "0x%llx\n", nbytes);
3718c2ecf20Sopenharmony_ci}
3728c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(channel_bytes);
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_cistatic ssize_t channel_id_show(struct device *dev,
3758c2ecf20Sopenharmony_ci			       struct device_attribute *attr, char *buf)
3768c2ecf20Sopenharmony_ci{
3778c2ecf20Sopenharmony_ci	struct visor_device *vdev = to_visor_device(dev);
3788c2ecf20Sopenharmony_ci	int len = 0;
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	visorchannel_id(vdev->visorchannel, buf);
3818c2ecf20Sopenharmony_ci	len = strlen(buf);
3828c2ecf20Sopenharmony_ci	buf[len++] = '\n';
3838c2ecf20Sopenharmony_ci	return len;
3848c2ecf20Sopenharmony_ci}
3858c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(channel_id);
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_cistatic struct attribute *visorbus_attrs[] = {
3888c2ecf20Sopenharmony_ci	&dev_attr_partition_handle.attr,
3898c2ecf20Sopenharmony_ci	&dev_attr_partition_guid.attr,
3908c2ecf20Sopenharmony_ci	&dev_attr_partition_name.attr,
3918c2ecf20Sopenharmony_ci	&dev_attr_channel_addr.attr,
3928c2ecf20Sopenharmony_ci	&dev_attr_channel_bytes.attr,
3938c2ecf20Sopenharmony_ci	&dev_attr_channel_id.attr,
3948c2ecf20Sopenharmony_ci	NULL
3958c2ecf20Sopenharmony_ci};
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ciATTRIBUTE_GROUPS(visorbus);
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci/*
4008c2ecf20Sopenharmony_ci *  BUS debugfs entries
4018c2ecf20Sopenharmony_ci *
4028c2ecf20Sopenharmony_ci *  define & implement display of debugfs attributes under
4038c2ecf20Sopenharmony_ci *  /sys/kernel/debug/visorbus/visorbus<n>.
4048c2ecf20Sopenharmony_ci */
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci/*
4078c2ecf20Sopenharmony_ci * vbuschannel_print_devinfo() - format a struct visor_vbus_deviceinfo
4088c2ecf20Sopenharmony_ci *                               and write it to a seq_file
4098c2ecf20Sopenharmony_ci * @devinfo: the struct visor_vbus_deviceinfo to format
4108c2ecf20Sopenharmony_ci * @seq: seq_file to write to
4118c2ecf20Sopenharmony_ci * @devix: the device index to be included in the output data, or -1 if no
4128c2ecf20Sopenharmony_ci *         device index is to be included
4138c2ecf20Sopenharmony_ci *
4148c2ecf20Sopenharmony_ci * Reads @devInfo, and writes it in human-readable notation to @seq.
4158c2ecf20Sopenharmony_ci */
4168c2ecf20Sopenharmony_cistatic void vbuschannel_print_devinfo(struct visor_vbus_deviceinfo *devinfo,
4178c2ecf20Sopenharmony_ci				      struct seq_file *seq, int devix)
4188c2ecf20Sopenharmony_ci{
4198c2ecf20Sopenharmony_ci	/* uninitialized vbus device entry */
4208c2ecf20Sopenharmony_ci	if (!isprint(devinfo->devtype[0]))
4218c2ecf20Sopenharmony_ci		return;
4228c2ecf20Sopenharmony_ci	if (devix >= 0)
4238c2ecf20Sopenharmony_ci		seq_printf(seq, "[%d]", devix);
4248c2ecf20Sopenharmony_ci	else
4258c2ecf20Sopenharmony_ci		/* vbus device entry is for bus or chipset */
4268c2ecf20Sopenharmony_ci		seq_puts(seq, "   ");
4278c2ecf20Sopenharmony_ci	/*
4288c2ecf20Sopenharmony_ci	 * Note: because the s-Par back-end is free to scribble in this area,
4298c2ecf20Sopenharmony_ci	 * we never assume '\0'-termination.
4308c2ecf20Sopenharmony_ci	 */
4318c2ecf20Sopenharmony_ci	seq_printf(seq, "%-*.*s ", (int)sizeof(devinfo->devtype),
4328c2ecf20Sopenharmony_ci		   (int)sizeof(devinfo->devtype), devinfo->devtype);
4338c2ecf20Sopenharmony_ci	seq_printf(seq, "%-*.*s ", (int)sizeof(devinfo->drvname),
4348c2ecf20Sopenharmony_ci		   (int)sizeof(devinfo->drvname), devinfo->drvname);
4358c2ecf20Sopenharmony_ci	seq_printf(seq, "%.*s\n", (int)sizeof(devinfo->infostrs),
4368c2ecf20Sopenharmony_ci		   devinfo->infostrs);
4378c2ecf20Sopenharmony_ci}
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_cistatic int bus_info_debugfs_show(struct seq_file *seq, void *v)
4408c2ecf20Sopenharmony_ci{
4418c2ecf20Sopenharmony_ci	int i = 0;
4428c2ecf20Sopenharmony_ci	unsigned long off;
4438c2ecf20Sopenharmony_ci	struct visor_vbus_deviceinfo dev_info;
4448c2ecf20Sopenharmony_ci	struct visor_device *vdev = seq->private;
4458c2ecf20Sopenharmony_ci	struct visorchannel *channel = vdev->visorchannel;
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	if (!channel)
4488c2ecf20Sopenharmony_ci		return 0;
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	seq_printf(seq,
4518c2ecf20Sopenharmony_ci		   "Client device/driver info for %s partition (vbus #%u):\n",
4528c2ecf20Sopenharmony_ci		   ((vdev->name) ? (char *)(vdev->name) : ""),
4538c2ecf20Sopenharmony_ci		   vdev->chipset_bus_no);
4548c2ecf20Sopenharmony_ci	if (visorchannel_read(channel,
4558c2ecf20Sopenharmony_ci			      offsetof(struct visor_vbus_channel, chp_info),
4568c2ecf20Sopenharmony_ci			      &dev_info, sizeof(dev_info)) >= 0)
4578c2ecf20Sopenharmony_ci		vbuschannel_print_devinfo(&dev_info, seq, -1);
4588c2ecf20Sopenharmony_ci	if (visorchannel_read(channel,
4598c2ecf20Sopenharmony_ci			      offsetof(struct visor_vbus_channel, bus_info),
4608c2ecf20Sopenharmony_ci			      &dev_info, sizeof(dev_info)) >= 0)
4618c2ecf20Sopenharmony_ci		vbuschannel_print_devinfo(&dev_info, seq, -1);
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	off = offsetof(struct visor_vbus_channel, dev_info);
4648c2ecf20Sopenharmony_ci	while (off + sizeof(dev_info) <= visorchannel_get_nbytes(channel)) {
4658c2ecf20Sopenharmony_ci		if (visorchannel_read(channel, off, &dev_info,
4668c2ecf20Sopenharmony_ci				      sizeof(dev_info)) >= 0)
4678c2ecf20Sopenharmony_ci			vbuschannel_print_devinfo(&dev_info, seq, i);
4688c2ecf20Sopenharmony_ci		off += sizeof(dev_info);
4698c2ecf20Sopenharmony_ci		i++;
4708c2ecf20Sopenharmony_ci	}
4718c2ecf20Sopenharmony_ci	return 0;
4728c2ecf20Sopenharmony_ci}
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_cistatic int bus_info_debugfs_open(struct inode *inode, struct file *file)
4758c2ecf20Sopenharmony_ci{
4768c2ecf20Sopenharmony_ci	return single_open(file, bus_info_debugfs_show, inode->i_private);
4778c2ecf20Sopenharmony_ci}
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_cistatic const struct file_operations bus_info_debugfs_fops = {
4808c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
4818c2ecf20Sopenharmony_ci	.open = bus_info_debugfs_open,
4828c2ecf20Sopenharmony_ci	.read = seq_read,
4838c2ecf20Sopenharmony_ci	.llseek = seq_lseek,
4848c2ecf20Sopenharmony_ci	.release = single_release,
4858c2ecf20Sopenharmony_ci};
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_cistatic void dev_periodic_work(struct timer_list *t)
4888c2ecf20Sopenharmony_ci{
4898c2ecf20Sopenharmony_ci	struct visor_device *dev = from_timer(dev, t, timer);
4908c2ecf20Sopenharmony_ci	struct visor_driver *drv = to_visor_driver(dev->device.driver);
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	drv->channel_interrupt(dev);
4938c2ecf20Sopenharmony_ci	mod_timer(&dev->timer, jiffies + POLLJIFFIES_NORMALCHANNEL);
4948c2ecf20Sopenharmony_ci}
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_cistatic int dev_start_periodic_work(struct visor_device *dev)
4978c2ecf20Sopenharmony_ci{
4988c2ecf20Sopenharmony_ci	if (dev->being_removed || dev->timer_active)
4998c2ecf20Sopenharmony_ci		return -EINVAL;
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	/* now up by at least 2 */
5028c2ecf20Sopenharmony_ci	get_device(&dev->device);
5038c2ecf20Sopenharmony_ci	dev->timer.expires = jiffies + POLLJIFFIES_NORMALCHANNEL;
5048c2ecf20Sopenharmony_ci	add_timer(&dev->timer);
5058c2ecf20Sopenharmony_ci	dev->timer_active = true;
5068c2ecf20Sopenharmony_ci	return 0;
5078c2ecf20Sopenharmony_ci}
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_cistatic void dev_stop_periodic_work(struct visor_device *dev)
5108c2ecf20Sopenharmony_ci{
5118c2ecf20Sopenharmony_ci	if (!dev->timer_active)
5128c2ecf20Sopenharmony_ci		return;
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	del_timer_sync(&dev->timer);
5158c2ecf20Sopenharmony_ci	dev->timer_active = false;
5168c2ecf20Sopenharmony_ci	put_device(&dev->device);
5178c2ecf20Sopenharmony_ci}
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci/*
5208c2ecf20Sopenharmony_ci * visordriver_remove_device() - handle visor device going away
5218c2ecf20Sopenharmony_ci * @xdev: struct device for the visor device being removed
5228c2ecf20Sopenharmony_ci *
5238c2ecf20Sopenharmony_ci * This is called when device_unregister() is called for each child device
5248c2ecf20Sopenharmony_ci * instance, to notify the appropriate visorbus function driver that the device
5258c2ecf20Sopenharmony_ci * is going away, and to decrease the reference count of the device.
5268c2ecf20Sopenharmony_ci *
5278c2ecf20Sopenharmony_ci * Return: 0 iff successful
5288c2ecf20Sopenharmony_ci */
5298c2ecf20Sopenharmony_cistatic int visordriver_remove_device(struct device *xdev)
5308c2ecf20Sopenharmony_ci{
5318c2ecf20Sopenharmony_ci	struct visor_device *dev = to_visor_device(xdev);
5328c2ecf20Sopenharmony_ci	struct visor_driver *drv = to_visor_driver(xdev->driver);
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	mutex_lock(&dev->visordriver_callback_lock);
5358c2ecf20Sopenharmony_ci	dev->being_removed = true;
5368c2ecf20Sopenharmony_ci	drv->remove(dev);
5378c2ecf20Sopenharmony_ci	mutex_unlock(&dev->visordriver_callback_lock);
5388c2ecf20Sopenharmony_ci	dev_stop_periodic_work(dev);
5398c2ecf20Sopenharmony_ci	put_device(&dev->device);
5408c2ecf20Sopenharmony_ci	return 0;
5418c2ecf20Sopenharmony_ci}
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci/*
5448c2ecf20Sopenharmony_ci * visorbus_unregister_visor_driver() - unregisters the provided driver
5458c2ecf20Sopenharmony_ci * @drv: the driver to unregister
5468c2ecf20Sopenharmony_ci *
5478c2ecf20Sopenharmony_ci * A visor function driver calls this function to unregister the driver,
5488c2ecf20Sopenharmony_ci * i.e., within its module_exit function.
5498c2ecf20Sopenharmony_ci */
5508c2ecf20Sopenharmony_civoid visorbus_unregister_visor_driver(struct visor_driver *drv)
5518c2ecf20Sopenharmony_ci{
5528c2ecf20Sopenharmony_ci	driver_unregister(&drv->driver);
5538c2ecf20Sopenharmony_ci}
5548c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(visorbus_unregister_visor_driver);
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci/*
5578c2ecf20Sopenharmony_ci * visorbus_read_channel() - reads from the designated channel into
5588c2ecf20Sopenharmony_ci *                           the provided buffer
5598c2ecf20Sopenharmony_ci * @dev:    the device whose channel is read from
5608c2ecf20Sopenharmony_ci * @offset: the offset into the channel at which reading starts
5618c2ecf20Sopenharmony_ci * @dest:   the destination buffer that is written into from the channel
5628c2ecf20Sopenharmony_ci * @nbytes: the number of bytes to read from the channel
5638c2ecf20Sopenharmony_ci *
5648c2ecf20Sopenharmony_ci * If receiving a message, use the visorchannel_signalremove() function instead.
5658c2ecf20Sopenharmony_ci *
5668c2ecf20Sopenharmony_ci * Return: integer indicating success (zero) or failure (non-zero)
5678c2ecf20Sopenharmony_ci */
5688c2ecf20Sopenharmony_ciint visorbus_read_channel(struct visor_device *dev, unsigned long offset,
5698c2ecf20Sopenharmony_ci			  void *dest, unsigned long nbytes)
5708c2ecf20Sopenharmony_ci{
5718c2ecf20Sopenharmony_ci	return visorchannel_read(dev->visorchannel, offset, dest, nbytes);
5728c2ecf20Sopenharmony_ci}
5738c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(visorbus_read_channel);
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci/*
5768c2ecf20Sopenharmony_ci * visorbus_write_channel() - writes the provided buffer into the designated
5778c2ecf20Sopenharmony_ci *                            channel
5788c2ecf20Sopenharmony_ci * @dev:    the device whose channel is written to
5798c2ecf20Sopenharmony_ci * @offset: the offset into the channel at which writing starts
5808c2ecf20Sopenharmony_ci * @src:    the source buffer that is written into the channel
5818c2ecf20Sopenharmony_ci * @nbytes: the number of bytes to write into the channel
5828c2ecf20Sopenharmony_ci *
5838c2ecf20Sopenharmony_ci * If sending a message, use the visorchannel_signalinsert() function instead.
5848c2ecf20Sopenharmony_ci *
5858c2ecf20Sopenharmony_ci * Return: integer indicating success (zero) or failure (non-zero)
5868c2ecf20Sopenharmony_ci */
5878c2ecf20Sopenharmony_ciint visorbus_write_channel(struct visor_device *dev, unsigned long offset,
5888c2ecf20Sopenharmony_ci			   void *src, unsigned long nbytes)
5898c2ecf20Sopenharmony_ci{
5908c2ecf20Sopenharmony_ci	return visorchannel_write(dev->visorchannel, offset, src, nbytes);
5918c2ecf20Sopenharmony_ci}
5928c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(visorbus_write_channel);
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci/*
5958c2ecf20Sopenharmony_ci * visorbus_enable_channel_interrupts() - enables interrupts on the
5968c2ecf20Sopenharmony_ci *                                        designated device
5978c2ecf20Sopenharmony_ci * @dev: the device on which to enable interrupts
5988c2ecf20Sopenharmony_ci *
5998c2ecf20Sopenharmony_ci * Currently we don't yet have a real interrupt, so for now we just call the
6008c2ecf20Sopenharmony_ci * interrupt function periodically via a timer.
6018c2ecf20Sopenharmony_ci */
6028c2ecf20Sopenharmony_ciint visorbus_enable_channel_interrupts(struct visor_device *dev)
6038c2ecf20Sopenharmony_ci{
6048c2ecf20Sopenharmony_ci	struct visor_driver *drv = to_visor_driver(dev->device.driver);
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	if (!drv->channel_interrupt) {
6078c2ecf20Sopenharmony_ci		dev_err(&dev->device, "%s no interrupt function!\n", __func__);
6088c2ecf20Sopenharmony_ci		return -ENOENT;
6098c2ecf20Sopenharmony_ci	}
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	return dev_start_periodic_work(dev);
6128c2ecf20Sopenharmony_ci}
6138c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(visorbus_enable_channel_interrupts);
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci/*
6168c2ecf20Sopenharmony_ci * visorbus_disable_channel_interrupts() - disables interrupts on the
6178c2ecf20Sopenharmony_ci *                                         designated device
6188c2ecf20Sopenharmony_ci * @dev: the device on which to disable interrupts
6198c2ecf20Sopenharmony_ci */
6208c2ecf20Sopenharmony_civoid visorbus_disable_channel_interrupts(struct visor_device *dev)
6218c2ecf20Sopenharmony_ci{
6228c2ecf20Sopenharmony_ci	dev_stop_periodic_work(dev);
6238c2ecf20Sopenharmony_ci}
6248c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(visorbus_disable_channel_interrupts);
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci/*
6278c2ecf20Sopenharmony_ci * create_visor_device() - create visor device as a result of receiving the
6288c2ecf20Sopenharmony_ci *                         controlvm device_create message for a new device
6298c2ecf20Sopenharmony_ci * @dev: a freshly-zeroed struct visor_device, containing only filled-in values
6308c2ecf20Sopenharmony_ci *       for chipset_bus_no and chipset_dev_no, that will be initialized
6318c2ecf20Sopenharmony_ci *
6328c2ecf20Sopenharmony_ci * This is how everything starts from the device end.
6338c2ecf20Sopenharmony_ci * This function is called when a channel first appears via a ControlVM
6348c2ecf20Sopenharmony_ci * message.  In response, this function allocates a visor_device to correspond
6358c2ecf20Sopenharmony_ci * to the new channel, and attempts to connect it the appropriate * driver. If
6368c2ecf20Sopenharmony_ci * the appropriate driver is found, the visor_driver.probe() function for that
6378c2ecf20Sopenharmony_ci * driver will be called, and will be passed the new * visor_device that we
6388c2ecf20Sopenharmony_ci * just created.
6398c2ecf20Sopenharmony_ci *
6408c2ecf20Sopenharmony_ci * It's ok if the appropriate driver is not yet loaded, because in that case
6418c2ecf20Sopenharmony_ci * the new device struct will just stick around in the bus' list of devices.
6428c2ecf20Sopenharmony_ci * When the appropriate driver calls visorbus_register_visor_driver(), the
6438c2ecf20Sopenharmony_ci * visor_driver.probe() for the new driver will be called with the new device.
6448c2ecf20Sopenharmony_ci *
6458c2ecf20Sopenharmony_ci * Return: 0 if successful, otherwise the negative value returned by
6468c2ecf20Sopenharmony_ci *         device_add() indicating the reason for failure
6478c2ecf20Sopenharmony_ci */
6488c2ecf20Sopenharmony_ciint create_visor_device(struct visor_device *dev)
6498c2ecf20Sopenharmony_ci{
6508c2ecf20Sopenharmony_ci	int err;
6518c2ecf20Sopenharmony_ci	u32 chipset_bus_no = dev->chipset_bus_no;
6528c2ecf20Sopenharmony_ci	u32 chipset_dev_no = dev->chipset_dev_no;
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci	mutex_init(&dev->visordriver_callback_lock);
6558c2ecf20Sopenharmony_ci	dev->device.bus = &visorbus_type;
6568c2ecf20Sopenharmony_ci	dev->device.groups = channel_groups;
6578c2ecf20Sopenharmony_ci	device_initialize(&dev->device);
6588c2ecf20Sopenharmony_ci	dev->device.release = visorbus_release_device;
6598c2ecf20Sopenharmony_ci	/* keep a reference just for us (now 2) */
6608c2ecf20Sopenharmony_ci	get_device(&dev->device);
6618c2ecf20Sopenharmony_ci	timer_setup(&dev->timer, dev_periodic_work, 0);
6628c2ecf20Sopenharmony_ci	/*
6638c2ecf20Sopenharmony_ci	 * bus_id must be a unique name with respect to this bus TYPE (NOT bus
6648c2ecf20Sopenharmony_ci	 * instance).  That's why we need to include the bus number within the
6658c2ecf20Sopenharmony_ci	 * name.
6668c2ecf20Sopenharmony_ci	 */
6678c2ecf20Sopenharmony_ci	err = dev_set_name(&dev->device, "vbus%u:dev%u",
6688c2ecf20Sopenharmony_ci			   chipset_bus_no, chipset_dev_no);
6698c2ecf20Sopenharmony_ci	if (err)
6708c2ecf20Sopenharmony_ci		goto err_put;
6718c2ecf20Sopenharmony_ci	/*
6728c2ecf20Sopenharmony_ci	 * device_add does this:
6738c2ecf20Sopenharmony_ci	 *    bus_add_device(dev)
6748c2ecf20Sopenharmony_ci	 *    ->device_attach(dev)
6758c2ecf20Sopenharmony_ci	 *      ->for each driver drv registered on the bus that dev is on
6768c2ecf20Sopenharmony_ci	 *          if (dev.drv)  **  device already has a driver **
6778c2ecf20Sopenharmony_ci	 *            ** not sure we could ever get here... **
6788c2ecf20Sopenharmony_ci	 *          else
6798c2ecf20Sopenharmony_ci	 *            if (bus.match(dev,drv)) [visorbus_match]
6808c2ecf20Sopenharmony_ci	 *              dev.drv = drv
6818c2ecf20Sopenharmony_ci	 *              if (!drv.probe(dev))  [visordriver_probe_device]
6828c2ecf20Sopenharmony_ci	 *                dev.drv = NULL
6838c2ecf20Sopenharmony_ci	 *
6848c2ecf20Sopenharmony_ci	 * Note that device_add does NOT fail if no driver failed to claim the
6858c2ecf20Sopenharmony_ci	 * device.  The device will be linked onto bus_type.klist_devices
6868c2ecf20Sopenharmony_ci	 * regardless (use bus_for_each_dev).
6878c2ecf20Sopenharmony_ci	 */
6888c2ecf20Sopenharmony_ci	err = device_add(&dev->device);
6898c2ecf20Sopenharmony_ci	if (err < 0)
6908c2ecf20Sopenharmony_ci		goto err_put;
6918c2ecf20Sopenharmony_ci	list_add_tail(&dev->list_all, &list_all_device_instances);
6928c2ecf20Sopenharmony_ci	dev->state.created = 1;
6938c2ecf20Sopenharmony_ci	visorbus_response(dev, err, CONTROLVM_DEVICE_CREATE);
6948c2ecf20Sopenharmony_ci	/* success: reference kept via unmatched get_device() */
6958c2ecf20Sopenharmony_ci	return 0;
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_cierr_put:
6988c2ecf20Sopenharmony_ci	put_device(&dev->device);
6998c2ecf20Sopenharmony_ci	dev_err(&dev->device, "Creating visor device failed. %d\n", err);
7008c2ecf20Sopenharmony_ci	return err;
7018c2ecf20Sopenharmony_ci}
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_civoid remove_visor_device(struct visor_device *dev)
7048c2ecf20Sopenharmony_ci{
7058c2ecf20Sopenharmony_ci	list_del(&dev->list_all);
7068c2ecf20Sopenharmony_ci	put_device(&dev->device);
7078c2ecf20Sopenharmony_ci	if (dev->pending_msg_hdr)
7088c2ecf20Sopenharmony_ci		visorbus_response(dev, 0, CONTROLVM_DEVICE_DESTROY);
7098c2ecf20Sopenharmony_ci	device_unregister(&dev->device);
7108c2ecf20Sopenharmony_ci}
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_cistatic int get_vbus_header_info(struct visorchannel *chan,
7138c2ecf20Sopenharmony_ci				struct device *dev,
7148c2ecf20Sopenharmony_ci				struct visor_vbus_headerinfo *hdr_info)
7158c2ecf20Sopenharmony_ci{
7168c2ecf20Sopenharmony_ci	int err;
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	if (!visor_check_channel(visorchannel_get_header(chan),
7198c2ecf20Sopenharmony_ci				 dev,
7208c2ecf20Sopenharmony_ci				 &visor_vbus_channel_guid,
7218c2ecf20Sopenharmony_ci				 "vbus",
7228c2ecf20Sopenharmony_ci				 sizeof(struct visor_vbus_channel),
7238c2ecf20Sopenharmony_ci				 VISOR_VBUS_CHANNEL_VERSIONID,
7248c2ecf20Sopenharmony_ci				 VISOR_CHANNEL_SIGNATURE))
7258c2ecf20Sopenharmony_ci		return -EINVAL;
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci	err = visorchannel_read(chan, sizeof(struct channel_header), hdr_info,
7288c2ecf20Sopenharmony_ci				sizeof(*hdr_info));
7298c2ecf20Sopenharmony_ci	if (err < 0)
7308c2ecf20Sopenharmony_ci		return err;
7318c2ecf20Sopenharmony_ci	if (hdr_info->struct_bytes < sizeof(struct visor_vbus_headerinfo))
7328c2ecf20Sopenharmony_ci		return -EINVAL;
7338c2ecf20Sopenharmony_ci	if (hdr_info->device_info_struct_bytes <
7348c2ecf20Sopenharmony_ci	    sizeof(struct visor_vbus_deviceinfo))
7358c2ecf20Sopenharmony_ci		return -EINVAL;
7368c2ecf20Sopenharmony_ci	return 0;
7378c2ecf20Sopenharmony_ci}
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci/*
7408c2ecf20Sopenharmony_ci * write_vbus_chp_info() - write the contents of <info> to the struct
7418c2ecf20Sopenharmony_ci *                         visor_vbus_channel.chp_info
7428c2ecf20Sopenharmony_ci * @chan:     indentifies the s-Par channel that will be updated
7438c2ecf20Sopenharmony_ci * @hdr_info: used to find appropriate channel offset to write data
7448c2ecf20Sopenharmony_ci * @info:     contains the information to write
7458c2ecf20Sopenharmony_ci *
7468c2ecf20Sopenharmony_ci * Writes chipset info into the channel memory to be used for diagnostic
7478c2ecf20Sopenharmony_ci * purposes.
7488c2ecf20Sopenharmony_ci *
7498c2ecf20Sopenharmony_ci * Returns no value since this is debug information and not needed for
7508c2ecf20Sopenharmony_ci * device functionality.
7518c2ecf20Sopenharmony_ci */
7528c2ecf20Sopenharmony_cistatic void write_vbus_chp_info(struct visorchannel *chan,
7538c2ecf20Sopenharmony_ci				struct visor_vbus_headerinfo *hdr_info,
7548c2ecf20Sopenharmony_ci				struct visor_vbus_deviceinfo *info)
7558c2ecf20Sopenharmony_ci{
7568c2ecf20Sopenharmony_ci	int off;
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	if (hdr_info->chp_info_offset == 0)
7598c2ecf20Sopenharmony_ci		return;
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	off = sizeof(struct channel_header) + hdr_info->chp_info_offset;
7628c2ecf20Sopenharmony_ci	visorchannel_write(chan, off, info, sizeof(*info));
7638c2ecf20Sopenharmony_ci}
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci/*
7668c2ecf20Sopenharmony_ci * write_vbus_bus_info() - write the contents of <info> to the struct
7678c2ecf20Sopenharmony_ci *                         visor_vbus_channel.bus_info
7688c2ecf20Sopenharmony_ci * @chan:     indentifies the s-Par channel that will be updated
7698c2ecf20Sopenharmony_ci * @hdr_info: used to find appropriate channel offset to write data
7708c2ecf20Sopenharmony_ci * @info:     contains the information to write
7718c2ecf20Sopenharmony_ci *
7728c2ecf20Sopenharmony_ci * Writes bus info into the channel memory to be used for diagnostic
7738c2ecf20Sopenharmony_ci * purposes.
7748c2ecf20Sopenharmony_ci *
7758c2ecf20Sopenharmony_ci * Returns no value since this is debug information and not needed for
7768c2ecf20Sopenharmony_ci * device functionality.
7778c2ecf20Sopenharmony_ci */
7788c2ecf20Sopenharmony_cistatic void write_vbus_bus_info(struct visorchannel *chan,
7798c2ecf20Sopenharmony_ci				struct visor_vbus_headerinfo *hdr_info,
7808c2ecf20Sopenharmony_ci				struct visor_vbus_deviceinfo *info)
7818c2ecf20Sopenharmony_ci{
7828c2ecf20Sopenharmony_ci	int off;
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci	if (hdr_info->bus_info_offset == 0)
7858c2ecf20Sopenharmony_ci		return;
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci	off = sizeof(struct channel_header) + hdr_info->bus_info_offset;
7888c2ecf20Sopenharmony_ci	visorchannel_write(chan, off, info, sizeof(*info));
7898c2ecf20Sopenharmony_ci}
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci/*
7928c2ecf20Sopenharmony_ci * write_vbus_dev_info() - write the contents of <info> to the struct
7938c2ecf20Sopenharmony_ci *                         visor_vbus_channel.dev_info[<devix>]
7948c2ecf20Sopenharmony_ci * @chan:     indentifies the s-Par channel that will be updated
7958c2ecf20Sopenharmony_ci * @hdr_info: used to find appropriate channel offset to write data
7968c2ecf20Sopenharmony_ci * @info:     contains the information to write
7978c2ecf20Sopenharmony_ci * @devix:    the relative device number (0..n-1) of the device on the bus
7988c2ecf20Sopenharmony_ci *
7998c2ecf20Sopenharmony_ci * Writes device info into the channel memory to be used for diagnostic
8008c2ecf20Sopenharmony_ci * purposes.
8018c2ecf20Sopenharmony_ci *
8028c2ecf20Sopenharmony_ci * Returns no value since this is debug information and not needed for
8038c2ecf20Sopenharmony_ci * device functionality.
8048c2ecf20Sopenharmony_ci */
8058c2ecf20Sopenharmony_cistatic void write_vbus_dev_info(struct visorchannel *chan,
8068c2ecf20Sopenharmony_ci				struct visor_vbus_headerinfo *hdr_info,
8078c2ecf20Sopenharmony_ci				struct visor_vbus_deviceinfo *info,
8088c2ecf20Sopenharmony_ci				unsigned int devix)
8098c2ecf20Sopenharmony_ci{
8108c2ecf20Sopenharmony_ci	int off;
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci	if (hdr_info->dev_info_offset == 0)
8138c2ecf20Sopenharmony_ci		return;
8148c2ecf20Sopenharmony_ci	off = (sizeof(struct channel_header) + hdr_info->dev_info_offset) +
8158c2ecf20Sopenharmony_ci	      (hdr_info->device_info_struct_bytes * devix);
8168c2ecf20Sopenharmony_ci	visorchannel_write(chan, off, info, sizeof(*info));
8178c2ecf20Sopenharmony_ci}
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_cistatic void bus_device_info_init(
8208c2ecf20Sopenharmony_ci		struct visor_vbus_deviceinfo *bus_device_info_ptr,
8218c2ecf20Sopenharmony_ci		const char *dev_type, const char *drv_name)
8228c2ecf20Sopenharmony_ci{
8238c2ecf20Sopenharmony_ci	memset(bus_device_info_ptr, 0, sizeof(struct visor_vbus_deviceinfo));
8248c2ecf20Sopenharmony_ci	snprintf(bus_device_info_ptr->devtype,
8258c2ecf20Sopenharmony_ci		 sizeof(bus_device_info_ptr->devtype),
8268c2ecf20Sopenharmony_ci		 "%s", (dev_type) ? dev_type : "unknownType");
8278c2ecf20Sopenharmony_ci	snprintf(bus_device_info_ptr->drvname,
8288c2ecf20Sopenharmony_ci		 sizeof(bus_device_info_ptr->drvname),
8298c2ecf20Sopenharmony_ci		 "%s", (drv_name) ? drv_name : "unknownDriver");
8308c2ecf20Sopenharmony_ci	snprintf(bus_device_info_ptr->infostrs,
8318c2ecf20Sopenharmony_ci		 sizeof(bus_device_info_ptr->infostrs), "kernel ver. %s",
8328c2ecf20Sopenharmony_ci		 utsname()->release);
8338c2ecf20Sopenharmony_ci}
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci/*
8368c2ecf20Sopenharmony_ci * publish_vbus_dev_info() - for a child device just created on a client bus,
8378c2ecf20Sopenharmony_ci *			     fill in information about the driver that is
8388c2ecf20Sopenharmony_ci *			     controlling this device into the appropriate slot
8398c2ecf20Sopenharmony_ci *			     within the vbus channel of the bus instance
8408c2ecf20Sopenharmony_ci * @visordev: struct visor_device for the desired device
8418c2ecf20Sopenharmony_ci */
8428c2ecf20Sopenharmony_cistatic void publish_vbus_dev_info(struct visor_device *visordev)
8438c2ecf20Sopenharmony_ci{
8448c2ecf20Sopenharmony_ci	int i;
8458c2ecf20Sopenharmony_ci	struct visor_device *bdev;
8468c2ecf20Sopenharmony_ci	struct visor_driver *visordrv;
8478c2ecf20Sopenharmony_ci	u32 bus_no = visordev->chipset_bus_no;
8488c2ecf20Sopenharmony_ci	u32 dev_no = visordev->chipset_dev_no;
8498c2ecf20Sopenharmony_ci	struct visor_vbus_deviceinfo dev_info;
8508c2ecf20Sopenharmony_ci	const char *chan_type_name = NULL;
8518c2ecf20Sopenharmony_ci	struct visor_vbus_headerinfo *hdr_info;
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_ci	if (!visordev->device.driver)
8548c2ecf20Sopenharmony_ci		return;
8558c2ecf20Sopenharmony_ci	bdev = visorbus_get_device_by_id(bus_no, BUS_ROOT_DEVICE, NULL);
8568c2ecf20Sopenharmony_ci	if (!bdev)
8578c2ecf20Sopenharmony_ci		return;
8588c2ecf20Sopenharmony_ci	hdr_info = (struct visor_vbus_headerinfo *)bdev->vbus_hdr_info;
8598c2ecf20Sopenharmony_ci	if (!hdr_info)
8608c2ecf20Sopenharmony_ci		return;
8618c2ecf20Sopenharmony_ci	visordrv = to_visor_driver(visordev->device.driver);
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci	/*
8648c2ecf20Sopenharmony_ci	 * Within the list of device types (by GUID) that the driver
8658c2ecf20Sopenharmony_ci	 * says it supports, find out which one of those types matches
8668c2ecf20Sopenharmony_ci	 * the type of this device, so that we can include the device
8678c2ecf20Sopenharmony_ci	 * type name
8688c2ecf20Sopenharmony_ci	 */
8698c2ecf20Sopenharmony_ci	for (i = 0; visordrv->channel_types[i].name; i++) {
8708c2ecf20Sopenharmony_ci		if (guid_equal(&visordrv->channel_types[i].guid,
8718c2ecf20Sopenharmony_ci			       &visordev->channel_type_guid)) {
8728c2ecf20Sopenharmony_ci			chan_type_name = visordrv->channel_types[i].name;
8738c2ecf20Sopenharmony_ci			break;
8748c2ecf20Sopenharmony_ci		}
8758c2ecf20Sopenharmony_ci	}
8768c2ecf20Sopenharmony_ci	bus_device_info_init(&dev_info, chan_type_name, visordrv->name);
8778c2ecf20Sopenharmony_ci	write_vbus_dev_info(bdev->visorchannel, hdr_info, &dev_info, dev_no);
8788c2ecf20Sopenharmony_ci	write_vbus_chp_info(bdev->visorchannel, hdr_info, &chipset_driverinfo);
8798c2ecf20Sopenharmony_ci	write_vbus_bus_info(bdev->visorchannel, hdr_info,
8808c2ecf20Sopenharmony_ci			    &clientbus_driverinfo);
8818c2ecf20Sopenharmony_ci}
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_ci/*
8848c2ecf20Sopenharmony_ci * visordriver_probe_device() - handle new visor device coming online
8858c2ecf20Sopenharmony_ci * @xdev: struct device for the visor device being probed
8868c2ecf20Sopenharmony_ci *
8878c2ecf20Sopenharmony_ci * This is called automatically upon adding a visor_device (device_add), or
8888c2ecf20Sopenharmony_ci * adding a visor_driver (visorbus_register_visor_driver), but only after
8898c2ecf20Sopenharmony_ci * visorbus_match() has returned 1 to indicate a successful match between
8908c2ecf20Sopenharmony_ci * driver and device.
8918c2ecf20Sopenharmony_ci *
8928c2ecf20Sopenharmony_ci * If successful, a reference to the device will be held onto via get_device().
8938c2ecf20Sopenharmony_ci *
8948c2ecf20Sopenharmony_ci * Return: 0 if successful, meaning the function driver's probe() function
8958c2ecf20Sopenharmony_ci *         was successful with this device, otherwise a negative errno
8968c2ecf20Sopenharmony_ci *         value indicating failure reason
8978c2ecf20Sopenharmony_ci */
8988c2ecf20Sopenharmony_cistatic int visordriver_probe_device(struct device *xdev)
8998c2ecf20Sopenharmony_ci{
9008c2ecf20Sopenharmony_ci	int err;
9018c2ecf20Sopenharmony_ci	struct visor_driver *drv = to_visor_driver(xdev->driver);
9028c2ecf20Sopenharmony_ci	struct visor_device *dev = to_visor_device(xdev);
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci	mutex_lock(&dev->visordriver_callback_lock);
9058c2ecf20Sopenharmony_ci	dev->being_removed = false;
9068c2ecf20Sopenharmony_ci	err = drv->probe(dev);
9078c2ecf20Sopenharmony_ci	if (err) {
9088c2ecf20Sopenharmony_ci		mutex_unlock(&dev->visordriver_callback_lock);
9098c2ecf20Sopenharmony_ci		return err;
9108c2ecf20Sopenharmony_ci	}
9118c2ecf20Sopenharmony_ci	/* success: reference kept via unmatched get_device() */
9128c2ecf20Sopenharmony_ci	get_device(&dev->device);
9138c2ecf20Sopenharmony_ci	publish_vbus_dev_info(dev);
9148c2ecf20Sopenharmony_ci	mutex_unlock(&dev->visordriver_callback_lock);
9158c2ecf20Sopenharmony_ci	return 0;
9168c2ecf20Sopenharmony_ci}
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci/*
9198c2ecf20Sopenharmony_ci * visorbus_register_visor_driver() - registers the provided visor driver for
9208c2ecf20Sopenharmony_ci *				      handling one or more visor device
9218c2ecf20Sopenharmony_ci *                                    types (channel_types)
9228c2ecf20Sopenharmony_ci * @drv: the driver to register
9238c2ecf20Sopenharmony_ci *
9248c2ecf20Sopenharmony_ci * A visor function driver calls this function to register the driver. The
9258c2ecf20Sopenharmony_ci * caller MUST fill in the following fields within the #drv structure:
9268c2ecf20Sopenharmony_ci *     name, version, owner, channel_types, probe, remove
9278c2ecf20Sopenharmony_ci *
9288c2ecf20Sopenharmony_ci * Here's how the whole Linux bus / driver / device model works.
9298c2ecf20Sopenharmony_ci *
9308c2ecf20Sopenharmony_ci * At system start-up, the visorbus kernel module is loaded, which registers
9318c2ecf20Sopenharmony_ci * visorbus_type as a bus type, using bus_register().
9328c2ecf20Sopenharmony_ci *
9338c2ecf20Sopenharmony_ci * All kernel modules that support particular device types on a
9348c2ecf20Sopenharmony_ci * visorbus bus are loaded.  Each of these kernel modules calls
9358c2ecf20Sopenharmony_ci * visorbus_register_visor_driver() in their init functions, passing a
9368c2ecf20Sopenharmony_ci * visor_driver struct.  visorbus_register_visor_driver() in turn calls
9378c2ecf20Sopenharmony_ci * register_driver(&visor_driver.driver).  This .driver member is
9388c2ecf20Sopenharmony_ci * initialized with generic methods (like probe), whose sole responsibility
9398c2ecf20Sopenharmony_ci * is to act as a broker for the real methods, which are within the
9408c2ecf20Sopenharmony_ci * visor_driver struct.  (This is the way the subclass behavior is
9418c2ecf20Sopenharmony_ci * implemented, since visor_driver is essentially a subclass of the
9428c2ecf20Sopenharmony_ci * generic driver.)  Whenever a driver_register() happens, core bus code in
9438c2ecf20Sopenharmony_ci * the kernel does (see device_attach() in drivers/base/dd.c):
9448c2ecf20Sopenharmony_ci *
9458c2ecf20Sopenharmony_ci *     for each dev associated with the bus (the bus that driver is on) that
9468c2ecf20Sopenharmony_ci *     does not yet have a driver
9478c2ecf20Sopenharmony_ci *         if bus.match(dev,newdriver) == yes_matched  ** .match specified
9488c2ecf20Sopenharmony_ci *                                                ** during bus_register().
9498c2ecf20Sopenharmony_ci *             newdriver.probe(dev)  ** for visor drivers, this will call
9508c2ecf20Sopenharmony_ci *                   ** the generic driver.probe implemented in visorbus.c,
9518c2ecf20Sopenharmony_ci *                   ** which in turn calls the probe specified within the
9528c2ecf20Sopenharmony_ci *                   ** struct visor_driver (which was specified by the
9538c2ecf20Sopenharmony_ci *                   ** actual device driver as part of
9548c2ecf20Sopenharmony_ci *                   ** visorbus_register_visor_driver()).
9558c2ecf20Sopenharmony_ci *
9568c2ecf20Sopenharmony_ci * The above dance also happens when a new device appears.
9578c2ecf20Sopenharmony_ci * So the question is, how are devices created within the system?
9588c2ecf20Sopenharmony_ci * Basically, just call device_add(dev).  See pci_bus_add_devices().
9598c2ecf20Sopenharmony_ci * pci_scan_device() shows an example of how to build a device struct.  It
9608c2ecf20Sopenharmony_ci * returns the newly-created struct to pci_scan_single_device(), who adds it
9618c2ecf20Sopenharmony_ci * to the list of devices at PCIBUS.devices.  That list of devices is what
9628c2ecf20Sopenharmony_ci * is traversed by pci_bus_add_devices().
9638c2ecf20Sopenharmony_ci *
9648c2ecf20Sopenharmony_ci * Return: integer indicating success (zero) or failure (non-zero)
9658c2ecf20Sopenharmony_ci */
9668c2ecf20Sopenharmony_ciint visorbus_register_visor_driver(struct visor_driver *drv)
9678c2ecf20Sopenharmony_ci{
9688c2ecf20Sopenharmony_ci	/* can't register on a nonexistent bus */
9698c2ecf20Sopenharmony_ci	if (!initialized)
9708c2ecf20Sopenharmony_ci		return -ENODEV;
9718c2ecf20Sopenharmony_ci	if (!drv->probe)
9728c2ecf20Sopenharmony_ci		return -EINVAL;
9738c2ecf20Sopenharmony_ci	if (!drv->remove)
9748c2ecf20Sopenharmony_ci		return -EINVAL;
9758c2ecf20Sopenharmony_ci	if (!drv->pause)
9768c2ecf20Sopenharmony_ci		return -EINVAL;
9778c2ecf20Sopenharmony_ci	if (!drv->resume)
9788c2ecf20Sopenharmony_ci		return -EINVAL;
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_ci	drv->driver.name = drv->name;
9818c2ecf20Sopenharmony_ci	drv->driver.bus = &visorbus_type;
9828c2ecf20Sopenharmony_ci	drv->driver.probe = visordriver_probe_device;
9838c2ecf20Sopenharmony_ci	drv->driver.remove = visordriver_remove_device;
9848c2ecf20Sopenharmony_ci	drv->driver.owner = drv->owner;
9858c2ecf20Sopenharmony_ci	/*
9868c2ecf20Sopenharmony_ci	 * driver_register does this:
9878c2ecf20Sopenharmony_ci	 *   bus_add_driver(drv)
9888c2ecf20Sopenharmony_ci	 *   ->if (drv.bus)  ** (bus_type) **
9898c2ecf20Sopenharmony_ci	 *       driver_attach(drv)
9908c2ecf20Sopenharmony_ci	 *         for each dev with bus type of drv.bus
9918c2ecf20Sopenharmony_ci	 *           if (!dev.drv)  ** no driver assigned yet **
9928c2ecf20Sopenharmony_ci	 *             if (bus.match(dev,drv))  [visorbus_match]
9938c2ecf20Sopenharmony_ci	 *               dev.drv = drv
9948c2ecf20Sopenharmony_ci	 *               if (!drv.probe(dev))   [visordriver_probe_device]
9958c2ecf20Sopenharmony_ci	 *                 dev.drv = NULL
9968c2ecf20Sopenharmony_ci	 */
9978c2ecf20Sopenharmony_ci	return driver_register(&drv->driver);
9988c2ecf20Sopenharmony_ci}
9998c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(visorbus_register_visor_driver);
10008c2ecf20Sopenharmony_ci
10018c2ecf20Sopenharmony_ci/*
10028c2ecf20Sopenharmony_ci * visorbus_create_instance() - create a device instance for the visorbus itself
10038c2ecf20Sopenharmony_ci * @dev: struct visor_device indicating the bus instance
10048c2ecf20Sopenharmony_ci *
10058c2ecf20Sopenharmony_ci * Return: 0 for success, otherwise negative errno value indicating reason for
10068c2ecf20Sopenharmony_ci *         failure
10078c2ecf20Sopenharmony_ci */
10088c2ecf20Sopenharmony_ciint visorbus_create_instance(struct visor_device *dev)
10098c2ecf20Sopenharmony_ci{
10108c2ecf20Sopenharmony_ci	int id = dev->chipset_bus_no;
10118c2ecf20Sopenharmony_ci	int err;
10128c2ecf20Sopenharmony_ci	struct visor_vbus_headerinfo *hdr_info;
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci	hdr_info = kzalloc(sizeof(*hdr_info), GFP_KERNEL);
10158c2ecf20Sopenharmony_ci	if (!hdr_info)
10168c2ecf20Sopenharmony_ci		return -ENOMEM;
10178c2ecf20Sopenharmony_ci	dev_set_name(&dev->device, "visorbus%d", id);
10188c2ecf20Sopenharmony_ci	dev->device.bus = &visorbus_type;
10198c2ecf20Sopenharmony_ci	dev->device.groups = visorbus_groups;
10208c2ecf20Sopenharmony_ci	dev->device.release = visorbus_release_busdevice;
10218c2ecf20Sopenharmony_ci	dev->debugfs_dir = debugfs_create_dir(dev_name(&dev->device),
10228c2ecf20Sopenharmony_ci					      visorbus_debugfs_dir);
10238c2ecf20Sopenharmony_ci	dev->debugfs_bus_info = debugfs_create_file("client_bus_info", 0440,
10248c2ecf20Sopenharmony_ci						    dev->debugfs_dir, dev,
10258c2ecf20Sopenharmony_ci						    &bus_info_debugfs_fops);
10268c2ecf20Sopenharmony_ci	dev_set_drvdata(&dev->device, dev);
10278c2ecf20Sopenharmony_ci	err = get_vbus_header_info(dev->visorchannel, &dev->device, hdr_info);
10288c2ecf20Sopenharmony_ci	if (err < 0)
10298c2ecf20Sopenharmony_ci		goto err_debugfs_dir;
10308c2ecf20Sopenharmony_ci	err = device_register(&dev->device);
10318c2ecf20Sopenharmony_ci	if (err < 0)
10328c2ecf20Sopenharmony_ci		goto err_debugfs_dir;
10338c2ecf20Sopenharmony_ci	list_add_tail(&dev->list_all, &list_all_bus_instances);
10348c2ecf20Sopenharmony_ci	dev->state.created = 1;
10358c2ecf20Sopenharmony_ci	dev->vbus_hdr_info = (void *)hdr_info;
10368c2ecf20Sopenharmony_ci	write_vbus_chp_info(dev->visorchannel, hdr_info, &chipset_driverinfo);
10378c2ecf20Sopenharmony_ci	write_vbus_bus_info(dev->visorchannel, hdr_info, &clientbus_driverinfo);
10388c2ecf20Sopenharmony_ci	visorbus_response(dev, err, CONTROLVM_BUS_CREATE);
10398c2ecf20Sopenharmony_ci	return 0;
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_cierr_debugfs_dir:
10428c2ecf20Sopenharmony_ci	debugfs_remove_recursive(dev->debugfs_dir);
10438c2ecf20Sopenharmony_ci	kfree(hdr_info);
10448c2ecf20Sopenharmony_ci	dev_err(&dev->device, "%s failed: %d\n", __func__, err);
10458c2ecf20Sopenharmony_ci	return err;
10468c2ecf20Sopenharmony_ci}
10478c2ecf20Sopenharmony_ci
10488c2ecf20Sopenharmony_ci/*
10498c2ecf20Sopenharmony_ci * visorbus_remove_instance() - remove a device instance for the visorbus itself
10508c2ecf20Sopenharmony_ci * @dev: struct visor_device indentifying the bus to remove
10518c2ecf20Sopenharmony_ci */
10528c2ecf20Sopenharmony_civoid visorbus_remove_instance(struct visor_device *dev)
10538c2ecf20Sopenharmony_ci{
10548c2ecf20Sopenharmony_ci	/*
10558c2ecf20Sopenharmony_ci	 * Note that this will result in the release method for
10568c2ecf20Sopenharmony_ci	 * dev->dev being called, which will call
10578c2ecf20Sopenharmony_ci	 * visorbus_release_busdevice().  This has something to do with
10588c2ecf20Sopenharmony_ci	 * the put_device() done in device_unregister(), but I have never
10598c2ecf20Sopenharmony_ci	 * successfully been able to trace thru the code to see where/how
10608c2ecf20Sopenharmony_ci	 * release() gets called.  But I know it does.
10618c2ecf20Sopenharmony_ci	 */
10628c2ecf20Sopenharmony_ci	kfree(dev->vbus_hdr_info);
10638c2ecf20Sopenharmony_ci	list_del(&dev->list_all);
10648c2ecf20Sopenharmony_ci	if (dev->pending_msg_hdr)
10658c2ecf20Sopenharmony_ci		visorbus_response(dev, 0, CONTROLVM_BUS_DESTROY);
10668c2ecf20Sopenharmony_ci	device_unregister(&dev->device);
10678c2ecf20Sopenharmony_ci}
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_ci/*
10708c2ecf20Sopenharmony_ci * remove_all_visor_devices() - remove all child visorbus device instances
10718c2ecf20Sopenharmony_ci */
10728c2ecf20Sopenharmony_cistatic void remove_all_visor_devices(void)
10738c2ecf20Sopenharmony_ci{
10748c2ecf20Sopenharmony_ci	struct list_head *listentry, *listtmp;
10758c2ecf20Sopenharmony_ci
10768c2ecf20Sopenharmony_ci	list_for_each_safe(listentry, listtmp, &list_all_device_instances) {
10778c2ecf20Sopenharmony_ci		struct visor_device *dev;
10788c2ecf20Sopenharmony_ci
10798c2ecf20Sopenharmony_ci		dev = list_entry(listentry, struct visor_device, list_all);
10808c2ecf20Sopenharmony_ci		remove_visor_device(dev);
10818c2ecf20Sopenharmony_ci	}
10828c2ecf20Sopenharmony_ci}
10838c2ecf20Sopenharmony_ci
10848c2ecf20Sopenharmony_ci/*
10858c2ecf20Sopenharmony_ci * pause_state_change_complete() - the callback function to be called by a
10868c2ecf20Sopenharmony_ci *                                 visorbus function driver when a
10878c2ecf20Sopenharmony_ci *                                 pending "pause device" operation has
10888c2ecf20Sopenharmony_ci *                                 completed
10898c2ecf20Sopenharmony_ci * @dev: struct visor_device identifying the paused device
10908c2ecf20Sopenharmony_ci * @status: 0 iff the pause state change completed successfully, otherwise
10918c2ecf20Sopenharmony_ci *          a negative errno value indicating the reason for failure
10928c2ecf20Sopenharmony_ci */
10938c2ecf20Sopenharmony_cistatic void pause_state_change_complete(struct visor_device *dev, int status)
10948c2ecf20Sopenharmony_ci{
10958c2ecf20Sopenharmony_ci	if (!dev->pausing)
10968c2ecf20Sopenharmony_ci		return;
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_ci	dev->pausing = false;
10998c2ecf20Sopenharmony_ci	visorbus_device_changestate_response(dev, status,
11008c2ecf20Sopenharmony_ci					     segment_state_standby);
11018c2ecf20Sopenharmony_ci}
11028c2ecf20Sopenharmony_ci
11038c2ecf20Sopenharmony_ci/*
11048c2ecf20Sopenharmony_ci * resume_state_change_complete() - the callback function to be called by a
11058c2ecf20Sopenharmony_ci *                                  visorbus function driver when a
11068c2ecf20Sopenharmony_ci *                                  pending "resume device" operation has
11078c2ecf20Sopenharmony_ci *                                  completed
11088c2ecf20Sopenharmony_ci * @dev: struct visor_device identifying the resumed device
11098c2ecf20Sopenharmony_ci * @status: 0 iff the resume state change completed successfully, otherwise
11108c2ecf20Sopenharmony_ci *          a negative errno value indicating the reason for failure
11118c2ecf20Sopenharmony_ci */
11128c2ecf20Sopenharmony_cistatic void resume_state_change_complete(struct visor_device *dev, int status)
11138c2ecf20Sopenharmony_ci{
11148c2ecf20Sopenharmony_ci	if (!dev->resuming)
11158c2ecf20Sopenharmony_ci		return;
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_ci	dev->resuming = false;
11188c2ecf20Sopenharmony_ci	/*
11198c2ecf20Sopenharmony_ci	 * Notify the chipset driver that the resume is complete,
11208c2ecf20Sopenharmony_ci	 * which will presumably want to send some sort of response to
11218c2ecf20Sopenharmony_ci	 * the initiator.
11228c2ecf20Sopenharmony_ci	 */
11238c2ecf20Sopenharmony_ci	visorbus_device_changestate_response(dev, status,
11248c2ecf20Sopenharmony_ci					     segment_state_running);
11258c2ecf20Sopenharmony_ci}
11268c2ecf20Sopenharmony_ci
11278c2ecf20Sopenharmony_ci/*
11288c2ecf20Sopenharmony_ci * visorchipset_initiate_device_pause_resume() - start a pause or resume
11298c2ecf20Sopenharmony_ci *                                               operation for a visor device
11308c2ecf20Sopenharmony_ci * @dev: struct visor_device identifying the device being paused or resumed
11318c2ecf20Sopenharmony_ci * @is_pause: true to indicate pause operation, false to indicate resume
11328c2ecf20Sopenharmony_ci *
11338c2ecf20Sopenharmony_ci * Tell the subordinate function driver for a specific device to pause
11348c2ecf20Sopenharmony_ci * or resume that device.  Success/failure result is returned asynchronously
11358c2ecf20Sopenharmony_ci * via a callback function; see pause_state_change_complete() and
11368c2ecf20Sopenharmony_ci * resume_state_change_complete().
11378c2ecf20Sopenharmony_ci */
11388c2ecf20Sopenharmony_cistatic int visorchipset_initiate_device_pause_resume(struct visor_device *dev,
11398c2ecf20Sopenharmony_ci						     bool is_pause)
11408c2ecf20Sopenharmony_ci{
11418c2ecf20Sopenharmony_ci	int err;
11428c2ecf20Sopenharmony_ci	struct visor_driver *drv;
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_ci	/* If no driver associated with the device nothing to pause/resume */
11458c2ecf20Sopenharmony_ci	if (!dev->device.driver)
11468c2ecf20Sopenharmony_ci		return 0;
11478c2ecf20Sopenharmony_ci	if (dev->pausing || dev->resuming)
11488c2ecf20Sopenharmony_ci		return -EBUSY;
11498c2ecf20Sopenharmony_ci
11508c2ecf20Sopenharmony_ci	drv = to_visor_driver(dev->device.driver);
11518c2ecf20Sopenharmony_ci	if (is_pause) {
11528c2ecf20Sopenharmony_ci		dev->pausing = true;
11538c2ecf20Sopenharmony_ci		err = drv->pause(dev, pause_state_change_complete);
11548c2ecf20Sopenharmony_ci	} else {
11558c2ecf20Sopenharmony_ci		/*
11568c2ecf20Sopenharmony_ci		 * The vbus_dev_info structure in the channel was been cleared,
11578c2ecf20Sopenharmony_ci		 * make sure it is valid.
11588c2ecf20Sopenharmony_ci		 */
11598c2ecf20Sopenharmony_ci		publish_vbus_dev_info(dev);
11608c2ecf20Sopenharmony_ci		dev->resuming = true;
11618c2ecf20Sopenharmony_ci		err = drv->resume(dev, resume_state_change_complete);
11628c2ecf20Sopenharmony_ci	}
11638c2ecf20Sopenharmony_ci	return err;
11648c2ecf20Sopenharmony_ci}
11658c2ecf20Sopenharmony_ci
11668c2ecf20Sopenharmony_ci/*
11678c2ecf20Sopenharmony_ci * visorchipset_device_pause() - start a pause operation for a visor device
11688c2ecf20Sopenharmony_ci * @dev_info: struct visor_device identifying the device being paused
11698c2ecf20Sopenharmony_ci *
11708c2ecf20Sopenharmony_ci * Tell the subordinate function driver for a specific device to pause
11718c2ecf20Sopenharmony_ci * that device.  Success/failure result is returned asynchronously
11728c2ecf20Sopenharmony_ci * via a callback function; see pause_state_change_complete().
11738c2ecf20Sopenharmony_ci */
11748c2ecf20Sopenharmony_ciint visorchipset_device_pause(struct visor_device *dev_info)
11758c2ecf20Sopenharmony_ci{
11768c2ecf20Sopenharmony_ci	int err;
11778c2ecf20Sopenharmony_ci
11788c2ecf20Sopenharmony_ci	err = visorchipset_initiate_device_pause_resume(dev_info, true);
11798c2ecf20Sopenharmony_ci	if (err < 0) {
11808c2ecf20Sopenharmony_ci		dev_info->pausing = false;
11818c2ecf20Sopenharmony_ci		return err;
11828c2ecf20Sopenharmony_ci	}
11838c2ecf20Sopenharmony_ci	return 0;
11848c2ecf20Sopenharmony_ci}
11858c2ecf20Sopenharmony_ci
11868c2ecf20Sopenharmony_ci/*
11878c2ecf20Sopenharmony_ci * visorchipset_device_resume() - start a resume operation for a visor device
11888c2ecf20Sopenharmony_ci * @dev_info: struct visor_device identifying the device being resumed
11898c2ecf20Sopenharmony_ci *
11908c2ecf20Sopenharmony_ci * Tell the subordinate function driver for a specific device to resume
11918c2ecf20Sopenharmony_ci * that device.  Success/failure result is returned asynchronously
11928c2ecf20Sopenharmony_ci * via a callback function; see resume_state_change_complete().
11938c2ecf20Sopenharmony_ci */
11948c2ecf20Sopenharmony_ciint visorchipset_device_resume(struct visor_device *dev_info)
11958c2ecf20Sopenharmony_ci{
11968c2ecf20Sopenharmony_ci	int err;
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_ci	err = visorchipset_initiate_device_pause_resume(dev_info, false);
11998c2ecf20Sopenharmony_ci	if (err < 0) {
12008c2ecf20Sopenharmony_ci		dev_info->resuming = false;
12018c2ecf20Sopenharmony_ci		return err;
12028c2ecf20Sopenharmony_ci	}
12038c2ecf20Sopenharmony_ci	return 0;
12048c2ecf20Sopenharmony_ci}
12058c2ecf20Sopenharmony_ci
12068c2ecf20Sopenharmony_ciint visorbus_init(void)
12078c2ecf20Sopenharmony_ci{
12088c2ecf20Sopenharmony_ci	int err;
12098c2ecf20Sopenharmony_ci
12108c2ecf20Sopenharmony_ci	visorbus_debugfs_dir = debugfs_create_dir("visorbus", NULL);
12118c2ecf20Sopenharmony_ci	bus_device_info_init(&clientbus_driverinfo, "clientbus", "visorbus");
12128c2ecf20Sopenharmony_ci	err = bus_register(&visorbus_type);
12138c2ecf20Sopenharmony_ci	if (err < 0)
12148c2ecf20Sopenharmony_ci		return err;
12158c2ecf20Sopenharmony_ci	initialized = true;
12168c2ecf20Sopenharmony_ci	bus_device_info_init(&chipset_driverinfo, "chipset", "visorchipset");
12178c2ecf20Sopenharmony_ci	return 0;
12188c2ecf20Sopenharmony_ci}
12198c2ecf20Sopenharmony_ci
12208c2ecf20Sopenharmony_civoid visorbus_exit(void)
12218c2ecf20Sopenharmony_ci{
12228c2ecf20Sopenharmony_ci	struct list_head *listentry, *listtmp;
12238c2ecf20Sopenharmony_ci
12248c2ecf20Sopenharmony_ci	remove_all_visor_devices();
12258c2ecf20Sopenharmony_ci	list_for_each_safe(listentry, listtmp, &list_all_bus_instances) {
12268c2ecf20Sopenharmony_ci		struct visor_device *dev;
12278c2ecf20Sopenharmony_ci
12288c2ecf20Sopenharmony_ci		dev = list_entry(listentry, struct visor_device, list_all);
12298c2ecf20Sopenharmony_ci		visorbus_remove_instance(dev);
12308c2ecf20Sopenharmony_ci	}
12318c2ecf20Sopenharmony_ci	bus_unregister(&visorbus_type);
12328c2ecf20Sopenharmony_ci	initialized = false;
12338c2ecf20Sopenharmony_ci	debugfs_remove_recursive(visorbus_debugfs_dir);
12348c2ecf20Sopenharmony_ci}
1235