18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * RapidIO driver support 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2005 MontaVista Software, Inc. 68c2ecf20Sopenharmony_ci * Matt Porter <mporter@kernel.crashing.org> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/init.h> 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/rio.h> 128c2ecf20Sopenharmony_ci#include <linux/rio_ids.h> 138c2ecf20Sopenharmony_ci#include <linux/rio_drv.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include "rio.h" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci/** 188c2ecf20Sopenharmony_ci * rio_match_device - Tell if a RIO device has a matching RIO device id structure 198c2ecf20Sopenharmony_ci * @id: the RIO device id structure to match against 208c2ecf20Sopenharmony_ci * @rdev: the RIO device structure to match against 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * Used from driver probe and bus matching to check whether a RIO device 238c2ecf20Sopenharmony_ci * matches a device id structure provided by a RIO driver. Returns the 248c2ecf20Sopenharmony_ci * matching &struct rio_device_id or %NULL if there is no match. 258c2ecf20Sopenharmony_ci */ 268c2ecf20Sopenharmony_cistatic const struct rio_device_id *rio_match_device(const struct rio_device_id 278c2ecf20Sopenharmony_ci *id, 288c2ecf20Sopenharmony_ci const struct rio_dev *rdev) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci while (id->vid || id->asm_vid) { 318c2ecf20Sopenharmony_ci if (((id->vid == RIO_ANY_ID) || (id->vid == rdev->vid)) && 328c2ecf20Sopenharmony_ci ((id->did == RIO_ANY_ID) || (id->did == rdev->did)) && 338c2ecf20Sopenharmony_ci ((id->asm_vid == RIO_ANY_ID) 348c2ecf20Sopenharmony_ci || (id->asm_vid == rdev->asm_vid)) 358c2ecf20Sopenharmony_ci && ((id->asm_did == RIO_ANY_ID) 368c2ecf20Sopenharmony_ci || (id->asm_did == rdev->asm_did))) 378c2ecf20Sopenharmony_ci return id; 388c2ecf20Sopenharmony_ci id++; 398c2ecf20Sopenharmony_ci } 408c2ecf20Sopenharmony_ci return NULL; 418c2ecf20Sopenharmony_ci} 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci/** 448c2ecf20Sopenharmony_ci * rio_dev_get - Increments the reference count of the RIO device structure 458c2ecf20Sopenharmony_ci * 468c2ecf20Sopenharmony_ci * @rdev: RIO device being referenced 478c2ecf20Sopenharmony_ci * 488c2ecf20Sopenharmony_ci * Each live reference to a device should be refcounted. 498c2ecf20Sopenharmony_ci * 508c2ecf20Sopenharmony_ci * Drivers for RIO devices should normally record such references in 518c2ecf20Sopenharmony_ci * their probe() methods, when they bind to a device, and release 528c2ecf20Sopenharmony_ci * them by calling rio_dev_put(), in their disconnect() methods. 538c2ecf20Sopenharmony_ci */ 548c2ecf20Sopenharmony_cistruct rio_dev *rio_dev_get(struct rio_dev *rdev) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci if (rdev) 578c2ecf20Sopenharmony_ci get_device(&rdev->dev); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci return rdev; 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci/** 638c2ecf20Sopenharmony_ci * rio_dev_put - Release a use of the RIO device structure 648c2ecf20Sopenharmony_ci * 658c2ecf20Sopenharmony_ci * @rdev: RIO device being disconnected 668c2ecf20Sopenharmony_ci * 678c2ecf20Sopenharmony_ci * Must be called when a user of a device is finished with it. 688c2ecf20Sopenharmony_ci * When the last user of the device calls this function, the 698c2ecf20Sopenharmony_ci * memory of the device is freed. 708c2ecf20Sopenharmony_ci */ 718c2ecf20Sopenharmony_civoid rio_dev_put(struct rio_dev *rdev) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci if (rdev) 748c2ecf20Sopenharmony_ci put_device(&rdev->dev); 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci/** 788c2ecf20Sopenharmony_ci * rio_device_probe - Tell if a RIO device structure has a matching RIO device id structure 798c2ecf20Sopenharmony_ci * @dev: the RIO device structure to match against 808c2ecf20Sopenharmony_ci * 818c2ecf20Sopenharmony_ci * return 0 and set rio_dev->driver when drv claims rio_dev, else error 828c2ecf20Sopenharmony_ci */ 838c2ecf20Sopenharmony_cistatic int rio_device_probe(struct device *dev) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci struct rio_driver *rdrv = to_rio_driver(dev->driver); 868c2ecf20Sopenharmony_ci struct rio_dev *rdev = to_rio_dev(dev); 878c2ecf20Sopenharmony_ci int error = -ENODEV; 888c2ecf20Sopenharmony_ci const struct rio_device_id *id; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci if (!rdev->driver && rdrv->probe) { 918c2ecf20Sopenharmony_ci if (!rdrv->id_table) 928c2ecf20Sopenharmony_ci return error; 938c2ecf20Sopenharmony_ci id = rio_match_device(rdrv->id_table, rdev); 948c2ecf20Sopenharmony_ci rio_dev_get(rdev); 958c2ecf20Sopenharmony_ci if (id) 968c2ecf20Sopenharmony_ci error = rdrv->probe(rdev, id); 978c2ecf20Sopenharmony_ci if (error >= 0) { 988c2ecf20Sopenharmony_ci rdev->driver = rdrv; 998c2ecf20Sopenharmony_ci error = 0; 1008c2ecf20Sopenharmony_ci } else 1018c2ecf20Sopenharmony_ci rio_dev_put(rdev); 1028c2ecf20Sopenharmony_ci } 1038c2ecf20Sopenharmony_ci return error; 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci/** 1078c2ecf20Sopenharmony_ci * rio_device_remove - Remove a RIO device from the system 1088c2ecf20Sopenharmony_ci * 1098c2ecf20Sopenharmony_ci * @dev: the RIO device structure to match against 1108c2ecf20Sopenharmony_ci * 1118c2ecf20Sopenharmony_ci * Remove a RIO device from the system. If it has an associated 1128c2ecf20Sopenharmony_ci * driver, then run the driver remove() method. Then update 1138c2ecf20Sopenharmony_ci * the reference count. 1148c2ecf20Sopenharmony_ci */ 1158c2ecf20Sopenharmony_cistatic int rio_device_remove(struct device *dev) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci struct rio_dev *rdev = to_rio_dev(dev); 1188c2ecf20Sopenharmony_ci struct rio_driver *rdrv = rdev->driver; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci if (rdrv) { 1218c2ecf20Sopenharmony_ci if (rdrv->remove) 1228c2ecf20Sopenharmony_ci rdrv->remove(rdev); 1238c2ecf20Sopenharmony_ci rdev->driver = NULL; 1248c2ecf20Sopenharmony_ci } 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci rio_dev_put(rdev); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci return 0; 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic void rio_device_shutdown(struct device *dev) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci struct rio_dev *rdev = to_rio_dev(dev); 1348c2ecf20Sopenharmony_ci struct rio_driver *rdrv = rdev->driver; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci dev_dbg(dev, "RIO: %s\n", __func__); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci if (rdrv && rdrv->shutdown) 1398c2ecf20Sopenharmony_ci rdrv->shutdown(rdev); 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci/** 1438c2ecf20Sopenharmony_ci * rio_register_driver - register a new RIO driver 1448c2ecf20Sopenharmony_ci * @rdrv: the RIO driver structure to register 1458c2ecf20Sopenharmony_ci * 1468c2ecf20Sopenharmony_ci * Adds a &struct rio_driver to the list of registered drivers. 1478c2ecf20Sopenharmony_ci * Returns a negative value on error, otherwise 0. If no error 1488c2ecf20Sopenharmony_ci * occurred, the driver remains registered even if no device 1498c2ecf20Sopenharmony_ci * was claimed during registration. 1508c2ecf20Sopenharmony_ci */ 1518c2ecf20Sopenharmony_ciint rio_register_driver(struct rio_driver *rdrv) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci /* initialize common driver fields */ 1548c2ecf20Sopenharmony_ci rdrv->driver.name = rdrv->name; 1558c2ecf20Sopenharmony_ci rdrv->driver.bus = &rio_bus_type; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci /* register with core */ 1588c2ecf20Sopenharmony_ci return driver_register(&rdrv->driver); 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci/** 1628c2ecf20Sopenharmony_ci * rio_unregister_driver - unregister a RIO driver 1638c2ecf20Sopenharmony_ci * @rdrv: the RIO driver structure to unregister 1648c2ecf20Sopenharmony_ci * 1658c2ecf20Sopenharmony_ci * Deletes the &struct rio_driver from the list of registered RIO 1668c2ecf20Sopenharmony_ci * drivers, gives it a chance to clean up by calling its remove() 1678c2ecf20Sopenharmony_ci * function for each device it was responsible for, and marks those 1688c2ecf20Sopenharmony_ci * devices as driverless. 1698c2ecf20Sopenharmony_ci */ 1708c2ecf20Sopenharmony_civoid rio_unregister_driver(struct rio_driver *rdrv) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci driver_unregister(&rdrv->driver); 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_civoid rio_attach_device(struct rio_dev *rdev) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci rdev->dev.bus = &rio_bus_type; 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rio_attach_device); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci/** 1828c2ecf20Sopenharmony_ci * rio_match_bus - Tell if a RIO device structure has a matching RIO driver device id structure 1838c2ecf20Sopenharmony_ci * @dev: the standard device structure to match against 1848c2ecf20Sopenharmony_ci * @drv: the standard driver structure containing the ids to match against 1858c2ecf20Sopenharmony_ci * 1868c2ecf20Sopenharmony_ci * Used by a driver to check whether a RIO device present in the 1878c2ecf20Sopenharmony_ci * system is in its list of supported devices. Returns 1 if 1888c2ecf20Sopenharmony_ci * there is a matching &struct rio_device_id or 0 if there is 1898c2ecf20Sopenharmony_ci * no match. 1908c2ecf20Sopenharmony_ci */ 1918c2ecf20Sopenharmony_cistatic int rio_match_bus(struct device *dev, struct device_driver *drv) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci struct rio_dev *rdev = to_rio_dev(dev); 1948c2ecf20Sopenharmony_ci struct rio_driver *rdrv = to_rio_driver(drv); 1958c2ecf20Sopenharmony_ci const struct rio_device_id *id = rdrv->id_table; 1968c2ecf20Sopenharmony_ci const struct rio_device_id *found_id; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci if (!id) 1998c2ecf20Sopenharmony_ci goto out; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci found_id = rio_match_device(id, rdev); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci if (found_id) 2048c2ecf20Sopenharmony_ci return 1; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci out:return 0; 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistatic int rio_uevent(struct device *dev, struct kobj_uevent_env *env) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci struct rio_dev *rdev; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci if (!dev) 2148c2ecf20Sopenharmony_ci return -ENODEV; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci rdev = to_rio_dev(dev); 2178c2ecf20Sopenharmony_ci if (!rdev) 2188c2ecf20Sopenharmony_ci return -ENODEV; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci if (add_uevent_var(env, "MODALIAS=rapidio:v%04Xd%04Xav%04Xad%04X", 2218c2ecf20Sopenharmony_ci rdev->vid, rdev->did, rdev->asm_vid, rdev->asm_did)) 2228c2ecf20Sopenharmony_ci return -ENOMEM; 2238c2ecf20Sopenharmony_ci return 0; 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistruct class rio_mport_class = { 2278c2ecf20Sopenharmony_ci .name = "rapidio_port", 2288c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 2298c2ecf20Sopenharmony_ci .dev_groups = rio_mport_groups, 2308c2ecf20Sopenharmony_ci}; 2318c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rio_mport_class); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_cistruct bus_type rio_bus_type = { 2348c2ecf20Sopenharmony_ci .name = "rapidio", 2358c2ecf20Sopenharmony_ci .match = rio_match_bus, 2368c2ecf20Sopenharmony_ci .dev_groups = rio_dev_groups, 2378c2ecf20Sopenharmony_ci .bus_groups = rio_bus_groups, 2388c2ecf20Sopenharmony_ci .probe = rio_device_probe, 2398c2ecf20Sopenharmony_ci .remove = rio_device_remove, 2408c2ecf20Sopenharmony_ci .shutdown = rio_device_shutdown, 2418c2ecf20Sopenharmony_ci .uevent = rio_uevent, 2428c2ecf20Sopenharmony_ci}; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci/** 2458c2ecf20Sopenharmony_ci * rio_bus_init - Register the RapidIO bus with the device model 2468c2ecf20Sopenharmony_ci * 2478c2ecf20Sopenharmony_ci * Registers the RIO mport device class and RIO bus type with the Linux 2488c2ecf20Sopenharmony_ci * device model. 2498c2ecf20Sopenharmony_ci */ 2508c2ecf20Sopenharmony_cistatic int __init rio_bus_init(void) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci int ret; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci ret = class_register(&rio_mport_class); 2558c2ecf20Sopenharmony_ci if (!ret) { 2568c2ecf20Sopenharmony_ci ret = bus_register(&rio_bus_type); 2578c2ecf20Sopenharmony_ci if (ret) 2588c2ecf20Sopenharmony_ci class_unregister(&rio_mport_class); 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci return ret; 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_cipostcore_initcall(rio_bus_init); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rio_register_driver); 2668c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rio_unregister_driver); 2678c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rio_bus_type); 2688c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rio_dev_get); 2698c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rio_dev_put); 270