18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * MDEV driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. 68c2ecf20Sopenharmony_ci * Author: Neo Jia <cjia@nvidia.com> 78c2ecf20Sopenharmony_ci * Kirti Wankhede <kwankhede@nvidia.com> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/device.h> 118c2ecf20Sopenharmony_ci#include <linux/iommu.h> 128c2ecf20Sopenharmony_ci#include <linux/mdev.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include "mdev_private.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_cistatic int mdev_attach_iommu(struct mdev_device *mdev) 178c2ecf20Sopenharmony_ci{ 188c2ecf20Sopenharmony_ci int ret; 198c2ecf20Sopenharmony_ci struct iommu_group *group; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci group = iommu_group_alloc(); 228c2ecf20Sopenharmony_ci if (IS_ERR(group)) 238c2ecf20Sopenharmony_ci return PTR_ERR(group); 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci ret = iommu_group_add_device(group, &mdev->dev); 268c2ecf20Sopenharmony_ci if (!ret) 278c2ecf20Sopenharmony_ci dev_info(&mdev->dev, "MDEV: group_id = %d\n", 288c2ecf20Sopenharmony_ci iommu_group_id(group)); 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci iommu_group_put(group); 318c2ecf20Sopenharmony_ci return ret; 328c2ecf20Sopenharmony_ci} 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic void mdev_detach_iommu(struct mdev_device *mdev) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci iommu_group_remove_device(&mdev->dev); 378c2ecf20Sopenharmony_ci dev_info(&mdev->dev, "MDEV: detaching iommu\n"); 388c2ecf20Sopenharmony_ci} 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic int mdev_probe(struct device *dev) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci struct mdev_driver *drv = to_mdev_driver(dev->driver); 438c2ecf20Sopenharmony_ci struct mdev_device *mdev = to_mdev_device(dev); 448c2ecf20Sopenharmony_ci int ret; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci ret = mdev_attach_iommu(mdev); 478c2ecf20Sopenharmony_ci if (ret) 488c2ecf20Sopenharmony_ci return ret; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci if (drv && drv->probe) { 518c2ecf20Sopenharmony_ci ret = drv->probe(dev); 528c2ecf20Sopenharmony_ci if (ret) 538c2ecf20Sopenharmony_ci mdev_detach_iommu(mdev); 548c2ecf20Sopenharmony_ci } 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci return ret; 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic int mdev_remove(struct device *dev) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci struct mdev_driver *drv = to_mdev_driver(dev->driver); 628c2ecf20Sopenharmony_ci struct mdev_device *mdev = to_mdev_device(dev); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci if (drv && drv->remove) 658c2ecf20Sopenharmony_ci drv->remove(dev); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci mdev_detach_iommu(mdev); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci return 0; 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistruct bus_type mdev_bus_type = { 738c2ecf20Sopenharmony_ci .name = "mdev", 748c2ecf20Sopenharmony_ci .probe = mdev_probe, 758c2ecf20Sopenharmony_ci .remove = mdev_remove, 768c2ecf20Sopenharmony_ci}; 778c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mdev_bus_type); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci/** 808c2ecf20Sopenharmony_ci * mdev_register_driver - register a new MDEV driver 818c2ecf20Sopenharmony_ci * @drv: the driver to register 828c2ecf20Sopenharmony_ci * @owner: module owner of driver to be registered 838c2ecf20Sopenharmony_ci * 848c2ecf20Sopenharmony_ci * Returns a negative value on error, otherwise 0. 858c2ecf20Sopenharmony_ci **/ 868c2ecf20Sopenharmony_ciint mdev_register_driver(struct mdev_driver *drv, struct module *owner) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci /* initialize common driver fields */ 898c2ecf20Sopenharmony_ci drv->driver.name = drv->name; 908c2ecf20Sopenharmony_ci drv->driver.bus = &mdev_bus_type; 918c2ecf20Sopenharmony_ci drv->driver.owner = owner; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci /* register with core */ 948c2ecf20Sopenharmony_ci return driver_register(&drv->driver); 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mdev_register_driver); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci/* 998c2ecf20Sopenharmony_ci * mdev_unregister_driver - unregister MDEV driver 1008c2ecf20Sopenharmony_ci * @drv: the driver to unregister 1018c2ecf20Sopenharmony_ci */ 1028c2ecf20Sopenharmony_civoid mdev_unregister_driver(struct mdev_driver *drv) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci driver_unregister(&drv->driver); 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mdev_unregister_driver); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ciint mdev_bus_register(void) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci return bus_register(&mdev_bus_type); 1118c2ecf20Sopenharmony_ci} 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_civoid mdev_bus_unregister(void) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci bus_unregister(&mdev_bus_type); 1168c2ecf20Sopenharmony_ci} 117