162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * RapidIO driver support 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2005 MontaVista Software, Inc. 662306a36Sopenharmony_ci * Matt Porter <mporter@kernel.crashing.org> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/init.h> 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <linux/rio.h> 1262306a36Sopenharmony_ci#include <linux/rio_ids.h> 1362306a36Sopenharmony_ci#include <linux/rio_drv.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include "rio.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci/** 1862306a36Sopenharmony_ci * rio_match_device - Tell if a RIO device has a matching RIO device id structure 1962306a36Sopenharmony_ci * @id: the RIO device id structure to match against 2062306a36Sopenharmony_ci * @rdev: the RIO device structure to match against 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci * Used from driver probe and bus matching to check whether a RIO device 2362306a36Sopenharmony_ci * matches a device id structure provided by a RIO driver. Returns the 2462306a36Sopenharmony_ci * matching &struct rio_device_id or %NULL if there is no match. 2562306a36Sopenharmony_ci */ 2662306a36Sopenharmony_cistatic const struct rio_device_id *rio_match_device(const struct rio_device_id 2762306a36Sopenharmony_ci *id, 2862306a36Sopenharmony_ci const struct rio_dev *rdev) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci while (id->vid || id->asm_vid) { 3162306a36Sopenharmony_ci if (((id->vid == RIO_ANY_ID) || (id->vid == rdev->vid)) && 3262306a36Sopenharmony_ci ((id->did == RIO_ANY_ID) || (id->did == rdev->did)) && 3362306a36Sopenharmony_ci ((id->asm_vid == RIO_ANY_ID) 3462306a36Sopenharmony_ci || (id->asm_vid == rdev->asm_vid)) 3562306a36Sopenharmony_ci && ((id->asm_did == RIO_ANY_ID) 3662306a36Sopenharmony_ci || (id->asm_did == rdev->asm_did))) 3762306a36Sopenharmony_ci return id; 3862306a36Sopenharmony_ci id++; 3962306a36Sopenharmony_ci } 4062306a36Sopenharmony_ci return NULL; 4162306a36Sopenharmony_ci} 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci/** 4462306a36Sopenharmony_ci * rio_dev_get - Increments the reference count of the RIO device structure 4562306a36Sopenharmony_ci * 4662306a36Sopenharmony_ci * @rdev: RIO device being referenced 4762306a36Sopenharmony_ci * 4862306a36Sopenharmony_ci * Each live reference to a device should be refcounted. 4962306a36Sopenharmony_ci * 5062306a36Sopenharmony_ci * Drivers for RIO devices should normally record such references in 5162306a36Sopenharmony_ci * their probe() methods, when they bind to a device, and release 5262306a36Sopenharmony_ci * them by calling rio_dev_put(), in their disconnect() methods. 5362306a36Sopenharmony_ci */ 5462306a36Sopenharmony_cistruct rio_dev *rio_dev_get(struct rio_dev *rdev) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci if (rdev) 5762306a36Sopenharmony_ci get_device(&rdev->dev); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci return rdev; 6062306a36Sopenharmony_ci} 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci/** 6362306a36Sopenharmony_ci * rio_dev_put - Release a use of the RIO device structure 6462306a36Sopenharmony_ci * 6562306a36Sopenharmony_ci * @rdev: RIO device being disconnected 6662306a36Sopenharmony_ci * 6762306a36Sopenharmony_ci * Must be called when a user of a device is finished with it. 6862306a36Sopenharmony_ci * When the last user of the device calls this function, the 6962306a36Sopenharmony_ci * memory of the device is freed. 7062306a36Sopenharmony_ci */ 7162306a36Sopenharmony_civoid rio_dev_put(struct rio_dev *rdev) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci if (rdev) 7462306a36Sopenharmony_ci put_device(&rdev->dev); 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci/** 7862306a36Sopenharmony_ci * rio_device_probe - Tell if a RIO device structure has a matching RIO device id structure 7962306a36Sopenharmony_ci * @dev: the RIO device structure to match against 8062306a36Sopenharmony_ci * 8162306a36Sopenharmony_ci * return 0 and set rio_dev->driver when drv claims rio_dev, else error 8262306a36Sopenharmony_ci */ 8362306a36Sopenharmony_cistatic int rio_device_probe(struct device *dev) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci struct rio_driver *rdrv = to_rio_driver(dev->driver); 8662306a36Sopenharmony_ci struct rio_dev *rdev = to_rio_dev(dev); 8762306a36Sopenharmony_ci int error = -ENODEV; 8862306a36Sopenharmony_ci const struct rio_device_id *id; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci if (!rdev->driver && rdrv->probe) { 9162306a36Sopenharmony_ci if (!rdrv->id_table) 9262306a36Sopenharmony_ci return error; 9362306a36Sopenharmony_ci id = rio_match_device(rdrv->id_table, rdev); 9462306a36Sopenharmony_ci rio_dev_get(rdev); 9562306a36Sopenharmony_ci if (id) 9662306a36Sopenharmony_ci error = rdrv->probe(rdev, id); 9762306a36Sopenharmony_ci if (error >= 0) { 9862306a36Sopenharmony_ci rdev->driver = rdrv; 9962306a36Sopenharmony_ci error = 0; 10062306a36Sopenharmony_ci } else 10162306a36Sopenharmony_ci rio_dev_put(rdev); 10262306a36Sopenharmony_ci } 10362306a36Sopenharmony_ci return error; 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci/** 10762306a36Sopenharmony_ci * rio_device_remove - Remove a RIO device from the system 10862306a36Sopenharmony_ci * 10962306a36Sopenharmony_ci * @dev: the RIO device structure to match against 11062306a36Sopenharmony_ci * 11162306a36Sopenharmony_ci * Remove a RIO device from the system. If it has an associated 11262306a36Sopenharmony_ci * driver, then run the driver remove() method. Then update 11362306a36Sopenharmony_ci * the reference count. 11462306a36Sopenharmony_ci */ 11562306a36Sopenharmony_cistatic void rio_device_remove(struct device *dev) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci struct rio_dev *rdev = to_rio_dev(dev); 11862306a36Sopenharmony_ci struct rio_driver *rdrv = rdev->driver; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci if (rdrv) { 12162306a36Sopenharmony_ci if (rdrv->remove) 12262306a36Sopenharmony_ci rdrv->remove(rdev); 12362306a36Sopenharmony_ci rdev->driver = NULL; 12462306a36Sopenharmony_ci } 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci rio_dev_put(rdev); 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic void rio_device_shutdown(struct device *dev) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci struct rio_dev *rdev = to_rio_dev(dev); 13262306a36Sopenharmony_ci struct rio_driver *rdrv = rdev->driver; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci dev_dbg(dev, "RIO: %s\n", __func__); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci if (rdrv && rdrv->shutdown) 13762306a36Sopenharmony_ci rdrv->shutdown(rdev); 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci/** 14162306a36Sopenharmony_ci * rio_register_driver - register a new RIO driver 14262306a36Sopenharmony_ci * @rdrv: the RIO driver structure to register 14362306a36Sopenharmony_ci * 14462306a36Sopenharmony_ci * Adds a &struct rio_driver to the list of registered drivers. 14562306a36Sopenharmony_ci * Returns a negative value on error, otherwise 0. If no error 14662306a36Sopenharmony_ci * occurred, the driver remains registered even if no device 14762306a36Sopenharmony_ci * was claimed during registration. 14862306a36Sopenharmony_ci */ 14962306a36Sopenharmony_ciint rio_register_driver(struct rio_driver *rdrv) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci /* initialize common driver fields */ 15262306a36Sopenharmony_ci rdrv->driver.name = rdrv->name; 15362306a36Sopenharmony_ci rdrv->driver.bus = &rio_bus_type; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci /* register with core */ 15662306a36Sopenharmony_ci return driver_register(&rdrv->driver); 15762306a36Sopenharmony_ci} 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci/** 16062306a36Sopenharmony_ci * rio_unregister_driver - unregister a RIO driver 16162306a36Sopenharmony_ci * @rdrv: the RIO driver structure to unregister 16262306a36Sopenharmony_ci * 16362306a36Sopenharmony_ci * Deletes the &struct rio_driver from the list of registered RIO 16462306a36Sopenharmony_ci * drivers, gives it a chance to clean up by calling its remove() 16562306a36Sopenharmony_ci * function for each device it was responsible for, and marks those 16662306a36Sopenharmony_ci * devices as driverless. 16762306a36Sopenharmony_ci */ 16862306a36Sopenharmony_civoid rio_unregister_driver(struct rio_driver *rdrv) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci driver_unregister(&rdrv->driver); 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_civoid rio_attach_device(struct rio_dev *rdev) 17462306a36Sopenharmony_ci{ 17562306a36Sopenharmony_ci rdev->dev.bus = &rio_bus_type; 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rio_attach_device); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci/** 18062306a36Sopenharmony_ci * rio_match_bus - Tell if a RIO device structure has a matching RIO driver device id structure 18162306a36Sopenharmony_ci * @dev: the standard device structure to match against 18262306a36Sopenharmony_ci * @drv: the standard driver structure containing the ids to match against 18362306a36Sopenharmony_ci * 18462306a36Sopenharmony_ci * Used by a driver to check whether a RIO device present in the 18562306a36Sopenharmony_ci * system is in its list of supported devices. Returns 1 if 18662306a36Sopenharmony_ci * there is a matching &struct rio_device_id or 0 if there is 18762306a36Sopenharmony_ci * no match. 18862306a36Sopenharmony_ci */ 18962306a36Sopenharmony_cistatic int rio_match_bus(struct device *dev, struct device_driver *drv) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci struct rio_dev *rdev = to_rio_dev(dev); 19262306a36Sopenharmony_ci struct rio_driver *rdrv = to_rio_driver(drv); 19362306a36Sopenharmony_ci const struct rio_device_id *id = rdrv->id_table; 19462306a36Sopenharmony_ci const struct rio_device_id *found_id; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci if (!id) 19762306a36Sopenharmony_ci goto out; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci found_id = rio_match_device(id, rdev); 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci if (found_id) 20262306a36Sopenharmony_ci return 1; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci out:return 0; 20562306a36Sopenharmony_ci} 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_cistatic int rio_uevent(const struct device *dev, struct kobj_uevent_env *env) 20862306a36Sopenharmony_ci{ 20962306a36Sopenharmony_ci const struct rio_dev *rdev; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci if (!dev) 21262306a36Sopenharmony_ci return -ENODEV; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci rdev = to_rio_dev(dev); 21562306a36Sopenharmony_ci if (!rdev) 21662306a36Sopenharmony_ci return -ENODEV; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci if (add_uevent_var(env, "MODALIAS=rapidio:v%04Xd%04Xav%04Xad%04X", 21962306a36Sopenharmony_ci rdev->vid, rdev->did, rdev->asm_vid, rdev->asm_did)) 22062306a36Sopenharmony_ci return -ENOMEM; 22162306a36Sopenharmony_ci return 0; 22262306a36Sopenharmony_ci} 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_cistruct class rio_mport_class = { 22562306a36Sopenharmony_ci .name = "rapidio_port", 22662306a36Sopenharmony_ci .dev_groups = rio_mport_groups, 22762306a36Sopenharmony_ci}; 22862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rio_mport_class); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_cistruct bus_type rio_bus_type = { 23162306a36Sopenharmony_ci .name = "rapidio", 23262306a36Sopenharmony_ci .match = rio_match_bus, 23362306a36Sopenharmony_ci .dev_groups = rio_dev_groups, 23462306a36Sopenharmony_ci .bus_groups = rio_bus_groups, 23562306a36Sopenharmony_ci .probe = rio_device_probe, 23662306a36Sopenharmony_ci .remove = rio_device_remove, 23762306a36Sopenharmony_ci .shutdown = rio_device_shutdown, 23862306a36Sopenharmony_ci .uevent = rio_uevent, 23962306a36Sopenharmony_ci}; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci/** 24262306a36Sopenharmony_ci * rio_bus_init - Register the RapidIO bus with the device model 24362306a36Sopenharmony_ci * 24462306a36Sopenharmony_ci * Registers the RIO mport device class and RIO bus type with the Linux 24562306a36Sopenharmony_ci * device model. 24662306a36Sopenharmony_ci */ 24762306a36Sopenharmony_cistatic int __init rio_bus_init(void) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci int ret; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci ret = class_register(&rio_mport_class); 25262306a36Sopenharmony_ci if (!ret) { 25362306a36Sopenharmony_ci ret = bus_register(&rio_bus_type); 25462306a36Sopenharmony_ci if (ret) 25562306a36Sopenharmony_ci class_unregister(&rio_mport_class); 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci return ret; 25862306a36Sopenharmony_ci} 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_cipostcore_initcall(rio_bus_init); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rio_register_driver); 26362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rio_unregister_driver); 26462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rio_bus_type); 26562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rio_dev_get); 26662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rio_dev_put); 267