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