119370Spst// SPDX-License-Identifier: GPL-2.0 2130803Smarcel/* 398944Sobrien * CDX bus driver. 419370Spst * 519370Spst * Copyright (C) 2022-2023, Advanced Micro Devices, Inc. 619370Spst */ 798944Sobrien 819370Spst/* 998944Sobrien * Architecture Overview 1098944Sobrien * ===================== 1198944Sobrien * CDX is a Hardware Architecture designed for AMD FPGA devices. It 1298944Sobrien * consists of sophisticated mechanism for interaction between FPGA, 1319370Spst * Firmware and the APUs (Application CPUs). 1498944Sobrien * 1598944Sobrien * Firmware resides on RPU (Realtime CPUs) which interacts with 1698944Sobrien * the FPGA program manager and the APUs. The RPU provides memory-mapped 1798944Sobrien * interface (RPU if) which is used to communicate with APUs. 1819370Spst * 1998944Sobrien * The diagram below shows an overview of the CDX architecture: 2098944Sobrien * 2198944Sobrien * +--------------------------------------+ 2298944Sobrien * | Application CPUs (APU) | 2319370Spst * | | 2419370Spst * | CDX device drivers| 2519370Spst * | Linux OS | | 2619370Spst * | CDX bus | 2719370Spst * | | | 2819370Spst * | CDX controller | 2919370Spst * | | | 3019370Spst * +-----------------------------|--------+ 3119370Spst * | (discover, config, 3298944Sobrien * | reset, rescan) 33130803Smarcel * | 3419370Spst * +------------------------| RPU if |----+ 3519370Spst * | | | 3619370Spst * | V | 3719370Spst * | Realtime CPUs (RPU) | 3819370Spst * | | 3919370Spst * +--------------------------------------+ 4019370Spst * | 4119370Spst * +---------------------|----------------+ 4298944Sobrien * | FPGA | | 4319370Spst * | +-----------------------+ | 4419370Spst * | | | | | 4519370Spst * | +-------+ +-------+ +-------+ | 4619370Spst * | | dev 1 | | dev 2 | | dev 3 | | 4719370Spst * | +-------+ +-------+ +-------+ | 4819370Spst * +--------------------------------------+ 4919370Spst * 5019370Spst * The RPU firmware extracts the device information from the loaded FPGA 5119370Spst * image and implements a mechanism that allows the APU drivers to 5246283Sdfr * enumerate such devices (device personality and resource details) via 5346283Sdfr * a dedicated communication channel. RPU mediates operations such as 5446283Sdfr * discover, reset and rescan of the FPGA devices for the APU. This is 5598944Sobrien * done using memory mapped interface provided by the RPU to APU. 5698944Sobrien */ 5798944Sobrien 5898944Sobrien#include <linux/init.h> 5946283Sdfr#include <linux/irqdomain.h> 6046283Sdfr#include <linux/kernel.h> 6198944Sobrien#include <linux/of.h> 6298944Sobrien#include <linux/of_device.h> 6398944Sobrien#include <linux/of_platform.h> 6498944Sobrien#include <linux/platform_device.h> 6598944Sobrien#include <linux/slab.h> 6698944Sobrien#include <linux/mm.h> 6746283Sdfr#include <linux/idr.h> 6898944Sobrien#include <linux/cdx/cdx_bus.h> 6998944Sobrien#include <linux/iommu.h> 7046283Sdfr#include <linux/dma-map-ops.h> 7146283Sdfr#include <linux/debugfs.h> 7246283Sdfr#include "cdx.h" 7398944Sobrien 7446283Sdfr/* Default DMA mask for devices on a CDX bus */ 7598944Sobrien#define CDX_DEFAULT_DMA_MASK (~0ULL) 7698944Sobrien#define MAX_CDX_CONTROLLERS 16 7798944Sobrien 7898944Sobrien/* IDA for CDX controllers registered with the CDX bus */ 7998944Sobrienstatic DEFINE_IDA(cdx_controller_ida); 8098944Sobrien/* Lock to protect controller ops */ 8198944Sobrienstatic DEFINE_MUTEX(cdx_controller_lock); 8298944Sobrien/* Debugfs dir for cdx bus */ 8398944Sobrienstatic struct dentry *cdx_debugfs_dir; 8498944Sobrien 8598944Sobrienstatic char *compat_node_name = "xlnx,versal-net-cdx"; 8698944Sobrien 8746283Sdfrstatic void cdx_destroy_res_attr(struct cdx_device *cdx_dev, int num); 8846283Sdfr 8998944Sobrien/** 9098944Sobrien * cdx_dev_reset - Reset a CDX device 9198944Sobrien * @dev: CDX device 9298944Sobrien * 9398944Sobrien * Return: -errno on failure, 0 on success. 9498944Sobrien */ 9546283Sdfrint cdx_dev_reset(struct device *dev) 9619370Spst{ 9719370Spst struct cdx_device *cdx_dev = to_cdx_device(dev); 9819370Spst struct cdx_controller *cdx = cdx_dev->cdx; 9919370Spst struct cdx_device_config dev_config = {0}; 10019370Spst struct cdx_driver *cdx_drv; 10119370Spst int ret; 10219370Spst 103130803Smarcel cdx_drv = to_cdx_driver(dev->driver); 10419370Spst /* Notify driver that device is being reset */ 10519370Spst if (cdx_drv && cdx_drv->reset_prepare) 10698944Sobrien cdx_drv->reset_prepare(cdx_dev); 10719370Spst 10819370Spst dev_config.type = CDX_DEV_RESET_CONF; 10919370Spst ret = cdx->ops->dev_configure(cdx, cdx_dev->bus_num, 11019370Spst cdx_dev->dev_num, &dev_config); 11119370Spst if (ret) 11219370Spst dev_err(dev, "cdx device reset failed\n"); 11319370Spst 11419370Spst /* Notify driver that device reset is complete */ 11519370Spst if (cdx_drv && cdx_drv->reset_done) 11619370Spst cdx_drv->reset_done(cdx_dev); 11719370Spst 11819370Spst return ret; 11919370Spst} 12019370SpstEXPORT_SYMBOL_GPL(cdx_dev_reset); 12119370Spst 12219370Spst/** 12319370Spst * reset_cdx_device - Reset a CDX device 12419370Spst * @dev: CDX device 12519370Spst * @data: This is always passed as NULL, and is not used in this API, 12619370Spst * but is required here as the device_for_each_child() API expects 12719370Spst * the passed function to have this as an argument. 12819370Spst * 12919370Spst * Return: -errno on failure, 0 on success. 13019370Spst */ 13119370Spststatic int reset_cdx_device(struct device *dev, void *data) 13219370Spst{ 13319370Spst return cdx_dev_reset(dev); 13419370Spst} 13519370Spst 13619370Spst/** 13719370Spst * cdx_unregister_device - Unregister a CDX device 13819370Spst * @dev: CDX device 13919370Spst * @data: This is always passed as NULL, and is not used in this API, 14019370Spst * but is required here as the bus_for_each_dev() API expects 14119370Spst * the passed function (cdx_unregister_device) to have this 14219370Spst * as an argument. 14319370Spst * 14419370Spst * Return: 0 on success. 14519370Spst */ 14619370Spststatic int cdx_unregister_device(struct device *dev, 14719370Spst void *data) 14819370Spst{ 14998944Sobrien struct cdx_device *cdx_dev = to_cdx_device(dev); 15019370Spst struct cdx_controller *cdx = cdx_dev->cdx; 15119370Spst 15246283Sdfr if (cdx_dev->is_bus) { 15319370Spst device_for_each_child(dev, NULL, cdx_unregister_device); 15419370Spst if (cdx_dev->enabled && cdx->ops->bus_disable) 15519370Spst cdx->ops->bus_disable(cdx, cdx_dev->bus_num); 15619370Spst } else { 15719370Spst cdx_destroy_res_attr(cdx_dev, MAX_CDX_DEV_RESOURCES); 15819370Spst debugfs_remove_recursive(cdx_dev->debugfs_dir); 15919370Spst kfree(cdx_dev->driver_override); 16019370Spst cdx_dev->driver_override = NULL; 16119370Spst } 16219370Spst 16319370Spst /* 16498944Sobrien * Do not free cdx_dev here as it would be freed in 16598944Sobrien * cdx_device_release() called from within put_device(). 16619370Spst */ 167130803Smarcel device_del(&cdx_dev->dev); 16819370Spst put_device(&cdx_dev->dev); 16919370Spst 17019370Spst return 0; 17198944Sobrien} 17219370Spst 17319370Spststatic void cdx_unregister_devices(struct bus_type *bus) 17446283Sdfr{ 17519370Spst /* Reset all the devices attached to cdx bus */ 17619370Spst bus_for_each_dev(bus, NULL, NULL, cdx_unregister_device); 17798944Sobrien} 17819370Spst 17919370Spst/** 18019370Spst * cdx_match_one_device - Tell if a CDX device structure has a matching 18198944Sobrien * CDX device id structure 18219370Spst * @id: single CDX device id structure to match 18319370Spst * @dev: the CDX device structure to match against 18419370Spst * 18598944Sobrien * Return: matching cdx_device_id structure or NULL if there is no match. 18619370Spst */ 18798944Sobrienstatic inline const struct cdx_device_id * 18819370Spstcdx_match_one_device(const struct cdx_device_id *id, 18919370Spst const struct cdx_device *dev) 19019370Spst{ 19119370Spst /* Use vendor ID and device ID for matching */ 19219370Spst if ((id->vendor == CDX_ANY_ID || id->vendor == dev->vendor) && 19398944Sobrien (id->device == CDX_ANY_ID || id->device == dev->device) && 19419370Spst (id->subvendor == CDX_ANY_ID || id->subvendor == dev->subsystem_vendor) && 19519370Spst (id->subdevice == CDX_ANY_ID || id->subdevice == dev->subsystem_device) && 19619370Spst !((id->class ^ dev->class) & id->class_mask)) 19719370Spst return id; 19819370Spst return NULL; 19919370Spst} 20019370Spst 20198944Sobrien/** 20219370Spst * cdx_match_id - See if a CDX device matches a given cdx_id table 20319370Spst * @ids: array of CDX device ID structures to search in 20419370Spst * @dev: the CDX device structure to match against. 20519370Spst * 20619370Spst * Used by a driver to check whether a CDX device is in its list of 20719370Spst * supported devices. Returns the matching cdx_device_id structure or 20819370Spst * NULL if there is no match. 20919370Spst * 21019370Spst * Return: matching cdx_device_id structure or NULL if there is no match. 21119370Spst */ 21219370Spststatic inline const struct cdx_device_id * 21319370Spstcdx_match_id(const struct cdx_device_id *ids, struct cdx_device *dev) 21419370Spst{ 21519370Spst if (ids) { 21619370Spst while (ids->vendor || ids->device) { 21719370Spst if (cdx_match_one_device(ids, dev)) 21819370Spst return ids; 21919370Spst ids++; 22019370Spst } 22119370Spst } 22219370Spst return NULL; 22319370Spst} 22419370Spst 22519370Spstint cdx_set_master(struct cdx_device *cdx_dev) 22619370Spst{ 22719370Spst struct cdx_controller *cdx = cdx_dev->cdx; 22846283Sdfr struct cdx_device_config dev_config; 22919370Spst int ret = -EOPNOTSUPP; 23019370Spst 23119370Spst dev_config.type = CDX_DEV_BUS_MASTER_CONF; 23298944Sobrien dev_config.bus_master_enable = true; 23319370Spst if (cdx->ops->dev_configure) 23419370Spst ret = cdx->ops->dev_configure(cdx, cdx_dev->bus_num, 23519370Spst cdx_dev->dev_num, &dev_config); 23619370Spst 23719370Spst return ret; 23819370Spst} 23919370SpstEXPORT_SYMBOL_GPL(cdx_set_master); 24019370Spst 24198944Sobrienint cdx_clear_master(struct cdx_device *cdx_dev) 24219370Spst{ 24319370Spst struct cdx_controller *cdx = cdx_dev->cdx; 24419370Spst struct cdx_device_config dev_config; 24519370Spst int ret = -EOPNOTSUPP; 24619370Spst 24719370Spst dev_config.type = CDX_DEV_BUS_MASTER_CONF; 24819370Spst dev_config.bus_master_enable = false; 24919370Spst if (cdx->ops->dev_configure) 25019370Spst ret = cdx->ops->dev_configure(cdx, cdx_dev->bus_num, 25198944Sobrien cdx_dev->dev_num, &dev_config); 25219370Spst 253130803Smarcel return ret; 25498944Sobrien} 25519370SpstEXPORT_SYMBOL_GPL(cdx_clear_master); 25619370Spst 25719370Spst/** 25819370Spst * cdx_bus_match - device to driver matching callback 25919370Spst * @dev: the cdx device to match against 26019370Spst * @drv: the device driver to search for matching cdx device 26119370Spst * structures 26219370Spst * 26319370Spst * Return: true on success, false otherwise. 26419370Spst */ 26519370Spststatic int cdx_bus_match(struct device *dev, struct device_driver *drv) 26619370Spst{ 26719370Spst struct cdx_device *cdx_dev = to_cdx_device(dev); 26819370Spst struct cdx_driver *cdx_drv = to_cdx_driver(drv); 26919370Spst const struct cdx_device_id *found_id = NULL; 27019370Spst const struct cdx_device_id *ids; 27119370Spst 27219370Spst if (cdx_dev->is_bus) 27319370Spst return false; 27419370Spst 27519370Spst ids = cdx_drv->match_id_table; 27619370Spst 27719370Spst /* When driver_override is set, only bind to the matching driver */ 27819370Spst if (cdx_dev->driver_override && strcmp(cdx_dev->driver_override, drv->name)) 27919370Spst return false; 28019370Spst 28119370Spst found_id = cdx_match_id(ids, cdx_dev); 28219370Spst if (!found_id) 28319370Spst return false; 28419370Spst 28519370Spst do { 28619370Spst /* 28719370Spst * In case override_only was set, enforce driver_override 28819370Spst * matching. 28919370Spst */ 29019370Spst if (!found_id->override_only) 29119370Spst return true; 29219370Spst if (cdx_dev->driver_override) 29319370Spst return true; 29419370Spst 29519370Spst ids = found_id + 1; 29619370Spst found_id = cdx_match_id(ids, cdx_dev); 29719370Spst } while (found_id); 29819370Spst 29919370Spst return false; 30019370Spst} 30119370Spst 30219370Spststatic int cdx_probe(struct device *dev) 30319370Spst{ 30419370Spst struct cdx_driver *cdx_drv = to_cdx_driver(dev->driver); 30519370Spst struct cdx_device *cdx_dev = to_cdx_device(dev); 30619370Spst struct cdx_controller *cdx = cdx_dev->cdx; 30719370Spst int error; 30819370Spst 30919370Spst /* 31098944Sobrien * Setup MSI device data so that generic MSI alloc/free can 31119370Spst * be used by the device driver. 31219370Spst */ 31398944Sobrien if (cdx->msi_domain) { 31419370Spst error = msi_setup_device_data(&cdx_dev->dev); 31519370Spst if (error) 31619370Spst return error; 31719370Spst } 31819370Spst 31919370Spst error = cdx_drv->probe(cdx_dev); 32019370Spst if (error) { 32119370Spst dev_err_probe(dev, error, "%s failed\n", __func__); 32219370Spst return error; 32319370Spst } 32419370Spst 32519370Spst return 0; 32619370Spst} 32719370Spst 32819370Spststatic void cdx_remove(struct device *dev) 32919370Spst{ 33098944Sobrien struct cdx_driver *cdx_drv = to_cdx_driver(dev->driver); 33119370Spst struct cdx_device *cdx_dev = to_cdx_device(dev); 33219370Spst 33319370Spst if (cdx_drv && cdx_drv->remove) 33419370Spst cdx_drv->remove(cdx_dev); 33519370Spst} 33619370Spst 33719370Spststatic void cdx_shutdown(struct device *dev) 33819370Spst{ 33919370Spst struct cdx_driver *cdx_drv = to_cdx_driver(dev->driver); 34019370Spst struct cdx_device *cdx_dev = to_cdx_device(dev); 34119370Spst 34219370Spst if (cdx_drv && cdx_drv->shutdown) 34319370Spst cdx_drv->shutdown(cdx_dev); 34419370Spst} 34519370Spst 34619370Spststatic int cdx_dma_configure(struct device *dev) 34719370Spst{ 34819370Spst struct cdx_driver *cdx_drv = to_cdx_driver(dev->driver); 34919370Spst struct cdx_device *cdx_dev = to_cdx_device(dev); 35019370Spst struct cdx_controller *cdx = cdx_dev->cdx; 35119370Spst u32 input_id = cdx_dev->req_id; 35219370Spst int ret; 35319370Spst 35419370Spst ret = of_dma_configure_id(dev, cdx->dev->of_node, 0, &input_id); 35519370Spst if (ret && ret != -EPROBE_DEFER) { 35619370Spst dev_err(dev, "of_dma_configure_id() failed\n"); 35719370Spst return ret; 35819370Spst } 35919370Spst 36019370Spst if (!ret && !cdx_drv->driver_managed_dma) { 36119370Spst ret = iommu_device_use_default_domain(dev); 36219370Spst if (ret) 36319370Spst arch_teardown_dma_ops(dev); 36419370Spst } 36519370Spst 36619370Spst return 0; 36719370Spst} 36819370Spst 36919370Spststatic void cdx_dma_cleanup(struct device *dev) 37019370Spst{ 37119370Spst struct cdx_driver *cdx_drv = to_cdx_driver(dev->driver); 37219370Spst 37319370Spst if (!cdx_drv->driver_managed_dma) 37419370Spst iommu_device_unuse_default_domain(dev); 37519370Spst} 37619370Spst 37719370Spst/* show configuration fields */ 37819370Spst#define cdx_config_attr(field, format_string) \ 37919370Spststatic ssize_t \ 38019370Spstfield##_show(struct device *dev, struct device_attribute *attr, char *buf) \ 38119370Spst{ \ 38219370Spst struct cdx_device *cdx_dev = to_cdx_device(dev); \ 38319370Spst return sysfs_emit(buf, format_string, cdx_dev->field); \ 38419370Spst} \ 38519370Spststatic DEVICE_ATTR_RO(field) 38619370Spst 38719370Spstcdx_config_attr(vendor, "0x%04x\n"); 38819370Spstcdx_config_attr(device, "0x%04x\n"); 38919370Spstcdx_config_attr(subsystem_vendor, "0x%04x\n"); 39019370Spstcdx_config_attr(subsystem_device, "0x%04x\n"); 39119370Spstcdx_config_attr(revision, "0x%02x\n"); 39298944Sobriencdx_config_attr(class, "0x%06x\n"); 39398944Sobrien 39498944Sobrienstatic ssize_t remove_store(struct device *dev, 39519370Spst struct device_attribute *attr, 39619370Spst const char *buf, size_t count) 39719370Spst{ 39819370Spst bool val; 39919370Spst 40019370Spst if (kstrtobool(buf, &val) < 0) 40119370Spst return -EINVAL; 40219370Spst 40398944Sobrien if (!val) 40419370Spst return -EINVAL; 40519370Spst 40619370Spst if (device_remove_file_self(dev, attr)) { 40798944Sobrien int ret; 40898944Sobrien 40998944Sobrien ret = cdx_unregister_device(dev, NULL); 41098944Sobrien if (ret) 41198944Sobrien return ret; 41298944Sobrien } 41398944Sobrien 41498944Sobrien return count; 41598944Sobrien} 41698944Sobrienstatic DEVICE_ATTR_WO(remove); 41798944Sobrien 41898944Sobrienstatic ssize_t reset_store(struct device *dev, struct device_attribute *attr, 41998944Sobrien const char *buf, size_t count) 42098944Sobrien{ 42198944Sobrien struct cdx_device *cdx_dev = to_cdx_device(dev); 42298944Sobrien bool val; 42398944Sobrien int ret; 42498944Sobrien 42598944Sobrien if (kstrtobool(buf, &val) < 0) 42698944Sobrien return -EINVAL; 42798944Sobrien 42898944Sobrien if (!val) 42998944Sobrien return -EINVAL; 43019370Spst 43119370Spst if (cdx_dev->is_bus) 43298944Sobrien /* Reset all the devices attached to cdx bus */ 43319370Spst ret = device_for_each_child(dev, NULL, reset_cdx_device); 43419370Spst else 43598944Sobrien ret = cdx_dev_reset(dev); 43698944Sobrien 43798944Sobrien return ret < 0 ? ret : count; 43898944Sobrien} 43998944Sobrienstatic DEVICE_ATTR_WO(reset); 44098944Sobrien 44198944Sobrienstatic ssize_t modalias_show(struct device *dev, struct device_attribute *attr, 44298944Sobrien char *buf) 44398944Sobrien{ 44498944Sobrien struct cdx_device *cdx_dev = to_cdx_device(dev); 44519370Spst 44698944Sobrien return sprintf(buf, "cdx:v%04Xd%04Xsv%04Xsd%04Xc%06X\n", cdx_dev->vendor, 44719370Spst cdx_dev->device, cdx_dev->subsystem_vendor, cdx_dev->subsystem_device, 44898944Sobrien cdx_dev->class); 44998944Sobrien} 45019370Spststatic DEVICE_ATTR_RO(modalias); 45119370Spst 45246283Sdfrstatic ssize_t driver_override_store(struct device *dev, 45346283Sdfr struct device_attribute *attr, 45498944Sobrien const char *buf, size_t count) 45598944Sobrien{ 45619370Spst struct cdx_device *cdx_dev = to_cdx_device(dev); 45798944Sobrien int ret; 45898944Sobrien 45919370Spst if (WARN_ON(dev->bus != &cdx_bus_type)) 46019370Spst return -EINVAL; 46119370Spst 46219370Spst ret = driver_set_override(dev, &cdx_dev->driver_override, buf, count); 46319370Spst if (ret) 46498944Sobrien return ret; 465130803Smarcel 46619370Spst return count; 46719370Spst} 46819370Spst 46919370Spststatic ssize_t driver_override_show(struct device *dev, 47046283Sdfr struct device_attribute *attr, char *buf) 47119370Spst{ 47298944Sobrien struct cdx_device *cdx_dev = to_cdx_device(dev); 47319370Spst 47498944Sobrien return sysfs_emit(buf, "%s\n", cdx_dev->driver_override); 475130803Smarcel} 476130803Smarcelstatic DEVICE_ATTR_RW(driver_override); 477130803Smarcel 478130803Smarcelstatic ssize_t enable_store(struct device *dev, struct device_attribute *attr, 479130803Smarcel const char *buf, size_t count) 48098944Sobrien{ 48198944Sobrien struct cdx_device *cdx_dev = to_cdx_device(dev); 48298944Sobrien struct cdx_controller *cdx = cdx_dev->cdx; 48398944Sobrien bool enable; 48419370Spst int ret; 48519370Spst 48619370Spst if (kstrtobool(buf, &enable) < 0) 48798944Sobrien return -EINVAL; 488130803Smarcel 48919370Spst if (enable == cdx_dev->enabled) 49098944Sobrien return count; 49119370Spst 492130803Smarcel if (enable && cdx->ops->bus_enable) 493130803Smarcel ret = cdx->ops->bus_enable(cdx, cdx_dev->bus_num); 49419370Spst else if (!enable && cdx->ops->bus_disable) 49519370Spst ret = cdx->ops->bus_disable(cdx, cdx_dev->bus_num); 49619370Spst else 49719370Spst ret = -EOPNOTSUPP; 49819370Spst 49998944Sobrien if (!ret) 50019370Spst cdx_dev->enabled = enable; 50119370Spst 50219370Spst return ret < 0 ? ret : count; 50319370Spst} 50498944Sobrien 50519370Spststatic ssize_t enable_show(struct device *dev, struct device_attribute *attr, char *buf) 50619370Spst{ 50719370Spst struct cdx_device *cdx_dev = to_cdx_device(dev); 50819370Spst 50998944Sobrien return sysfs_emit(buf, "%u\n", cdx_dev->enabled); 51019370Spst} 51119370Spststatic DEVICE_ATTR_RW(enable); 51219370Spst 51319370Spststatic umode_t cdx_dev_attrs_are_visible(struct kobject *kobj, struct attribute *a, int n) 51498944Sobrien{ 51519370Spst struct device *dev = kobj_to_dev(kobj); 51619370Spst struct cdx_device *cdx_dev; 51719370Spst 51819370Spst cdx_dev = to_cdx_device(dev); 51998944Sobrien if (!cdx_dev->is_bus) 52019370Spst return a->mode; 52119370Spst 52219370Spst return 0; 52319370Spst} 52498944Sobrien 52519370Spststatic umode_t cdx_bus_attrs_are_visible(struct kobject *kobj, struct attribute *a, int n) 52619370Spst{ 52719370Spst struct device *dev = kobj_to_dev(kobj); 52819370Spst struct cdx_device *cdx_dev; 52998944Sobrien 53019370Spst cdx_dev = to_cdx_device(dev); 53119370Spst if (cdx_dev->is_bus) 53219370Spst return a->mode; 53319370Spst 53498944Sobrien return 0; 53519370Spst} 53619370Spst 53719370Spststatic struct attribute *cdx_dev_attrs[] = { 53819370Spst &dev_attr_remove.attr, 53998944Sobrien &dev_attr_reset.attr, 54019370Spst &dev_attr_vendor.attr, 54119370Spst &dev_attr_device.attr, 54219370Spst &dev_attr_subsystem_vendor.attr, 54319370Spst &dev_attr_subsystem_device.attr, 54498944Sobrien &dev_attr_class.attr, 54519370Spst &dev_attr_revision.attr, 54619370Spst &dev_attr_modalias.attr, 54719370Spst &dev_attr_driver_override.attr, 54819370Spst NULL, 54919370Spst}; 55098944Sobrien 55119370Spststatic const struct attribute_group cdx_dev_group = { 55219370Spst .attrs = cdx_dev_attrs, 55319370Spst .is_visible = cdx_dev_attrs_are_visible, 55419370Spst}; 55519370Spst 55698944Sobrienstatic struct attribute *cdx_bus_dev_attrs[] = { 55719370Spst &dev_attr_enable.attr, 55819370Spst &dev_attr_reset.attr, 55998944Sobrien NULL, 56098944Sobrien}; 56119370Spst 56219370Spststatic const struct attribute_group cdx_bus_dev_group = { 56319370Spst .attrs = cdx_bus_dev_attrs, 56419370Spst .is_visible = cdx_bus_attrs_are_visible, 565130803Smarcel}; 56619370Spst 567130803Smarcelstatic const struct attribute_group *cdx_dev_groups[] = { 568130803Smarcel &cdx_dev_group, 569130803Smarcel &cdx_bus_dev_group, 570130803Smarcel NULL, 571130803Smarcel}; 572130803Smarcel 573130803Smarcelstatic int cdx_debug_resource_show(struct seq_file *s, void *data) 574130803Smarcel{ 575130803Smarcel struct cdx_device *cdx_dev = s->private; 576130803Smarcel int i; 577130803Smarcel 578130803Smarcel for (i = 0; i < MAX_CDX_DEV_RESOURCES; i++) { 579130803Smarcel struct resource *res = &cdx_dev->res[i]; 580130803Smarcel 581130803Smarcel seq_printf(s, "%pr\n", res); 582130803Smarcel } 583130803Smarcel 584130803Smarcel return 0; 585130803Smarcel} 586130803SmarcelDEFINE_SHOW_ATTRIBUTE(cdx_debug_resource); 587130803Smarcel 58819370Spststatic void cdx_device_debugfs_init(struct cdx_device *cdx_dev) 58919370Spst{ 59019370Spst cdx_dev->debugfs_dir = debugfs_create_dir(dev_name(&cdx_dev->dev), cdx_debugfs_dir); 59198944Sobrien if (IS_ERR(cdx_dev->debugfs_dir)) 59298944Sobrien return; 59319370Spst 59419370Spst debugfs_create_file("resource", 0444, cdx_dev->debugfs_dir, cdx_dev, 59519370Spst &cdx_debug_resource_fops); 59646283Sdfr} 59746283Sdfr 59898944Sobrienstatic ssize_t rescan_store(const struct bus_type *bus, 59919370Spst const char *buf, size_t count) 60019370Spst{ 60198944Sobrien struct cdx_controller *cdx; 60219370Spst struct platform_device *pd; 60398944Sobrien struct device_node *np; 60419370Spst bool val; 60519370Spst 60646283Sdfr if (kstrtobool(buf, &val) < 0) 60798944Sobrien return -EINVAL; 60819370Spst 60919370Spst if (!val) 61098944Sobrien return -EINVAL; 61119370Spst 61298944Sobrien mutex_lock(&cdx_controller_lock); 61319370Spst 61419370Spst /* Unregister all the devices on the bus */ 61598944Sobrien cdx_unregister_devices(&cdx_bus_type); 61698944Sobrien 61719370Spst /* Rescan all the devices */ 61819370Spst for_each_compatible_node(np, NULL, compat_node_name) { 61998944Sobrien pd = of_find_device_by_node(np); 62019370Spst if (!pd) { 62198944Sobrien of_node_put(np); 62219370Spst count = -EINVAL; 62319370Spst goto unlock; 62498944Sobrien } 62598944Sobrien 62619370Spst cdx = platform_get_drvdata(pd); 62719370Spst if (cdx && cdx->controller_registered && cdx->ops->scan) 62898944Sobrien cdx->ops->scan(cdx); 62919370Spst 63098944Sobrien put_device(&pd->dev); 63119370Spst } 63246283Sdfr 63319370Spstunlock: 63498944Sobrien mutex_unlock(&cdx_controller_lock); 63598944Sobrien 63698944Sobrien return count; 63719370Spst} 63846283Sdfrstatic BUS_ATTR_WO(rescan); 63998944Sobrien 64098944Sobrienstatic struct attribute *cdx_bus_attrs[] = { 64198944Sobrien &bus_attr_rescan.attr, 64298944Sobrien NULL, 64398944Sobrien}; 64419370SpstATTRIBUTE_GROUPS(cdx_bus); 64598944Sobrien 64698944Sobrienstruct bus_type cdx_bus_type = { 64719370Spst .name = "cdx", 64819370Spst .match = cdx_bus_match, 64919370Spst .probe = cdx_probe, 65019370Spst .remove = cdx_remove, 65146283Sdfr .shutdown = cdx_shutdown, 65298944Sobrien .dma_configure = cdx_dma_configure, 65319370Spst .dma_cleanup = cdx_dma_cleanup, 65419370Spst .bus_groups = cdx_bus_groups, 65598944Sobrien .dev_groups = cdx_dev_groups, 65698944Sobrien}; 65719370SpstEXPORT_SYMBOL_GPL(cdx_bus_type); 65819370Spst 65919370Spstint __cdx_driver_register(struct cdx_driver *cdx_driver, 66098944Sobrien struct module *owner) 66198944Sobrien{ 66298944Sobrien int error; 663130803Smarcel 664130803Smarcel cdx_driver->driver.owner = owner; 66519370Spst cdx_driver->driver.bus = &cdx_bus_type; 66698944Sobrien 66798944Sobrien error = driver_register(&cdx_driver->driver); 66898944Sobrien if (error) { 66998944Sobrien pr_err("driver_register() failed for %s: %d\n", 67019370Spst cdx_driver->driver.name, error); 67198944Sobrien return error; 67298944Sobrien } 67398944Sobrien 67498944Sobrien return 0; 67598944Sobrien} 67698944SobrienEXPORT_SYMBOL_GPL(__cdx_driver_register); 67798944Sobrien 67898944Sobrienvoid cdx_driver_unregister(struct cdx_driver *cdx_driver) 67919370Spst{ 68098944Sobrien driver_unregister(&cdx_driver->driver); 68198944Sobrien} 68298944SobrienEXPORT_SYMBOL_GPL(cdx_driver_unregister); 68398944Sobrien 68498944Sobrienstatic void cdx_device_release(struct device *dev) 68598944Sobrien{ 68619370Spst struct cdx_device *cdx_dev = to_cdx_device(dev); 68719370Spst 68819370Spst kfree(cdx_dev); 68998944Sobrien} 69098944Sobrien 69198944Sobrienstatic const struct vm_operations_struct cdx_phys_vm_ops = { 69298944Sobrien#ifdef CONFIG_HAVE_IOREMAP_PROT 69398944Sobrien .access = generic_access_phys, 69498944Sobrien#endif 69598944Sobrien}; 69698944Sobrien 69798944Sobrien/** 69819370Spst * cdx_mmap_resource - map a CDX resource into user memory space 69919370Spst * @fp: File pointer. Not used in this function, but required where 70098944Sobrien * this API is registered as a callback. 70198944Sobrien * @kobj: kobject for mapping 70219370Spst * @attr: struct bin_attribute for the file being mapped 70398944Sobrien * @vma: struct vm_area_struct passed into the mmap 70419370Spst * 70519370Spst * Use the regular CDX mapping routines to map a CDX resource into userspace. 70619370Spst * 70719370Spst * Return: true on success, false otherwise. 70819370Spst */ 70919370Spststatic int cdx_mmap_resource(struct file *fp, struct kobject *kobj, 71098944Sobrien struct bin_attribute *attr, 71119370Spst struct vm_area_struct *vma) 71219370Spst{ 71319370Spst struct cdx_device *cdx_dev = to_cdx_device(kobj_to_dev(kobj)); 71446283Sdfr int num = (unsigned long)attr->private; 71519370Spst struct resource *res; 71619370Spst unsigned long size; 71798944Sobrien 71819370Spst res = &cdx_dev->res[num]; 71946283Sdfr if (iomem_is_exclusive(res->start)) 72046283Sdfr return -EINVAL; 72198944Sobrien 72219370Spst /* Make sure the caller is mapping a valid resource for this device */ 72319370Spst size = ((cdx_resource_len(cdx_dev, num) - 1) >> PAGE_SHIFT) + 1; 72498944Sobrien if (vma->vm_pgoff + vma_pages(vma) > size) 72598944Sobrien return -EINVAL; 72698944Sobrien 72719370Spst /* 72819370Spst * Map memory region and vm->vm_pgoff is expected to be an 72998944Sobrien * offset within that region. 73098944Sobrien */ 73198944Sobrien vma->vm_page_prot = pgprot_device(vma->vm_page_prot); 73298944Sobrien vma->vm_pgoff += (cdx_resource_start(cdx_dev, num) >> PAGE_SHIFT); 73319370Spst vma->vm_ops = &cdx_phys_vm_ops; 73419370Spst return io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, 73598944Sobrien vma->vm_end - vma->vm_start, 73619370Spst vma->vm_page_prot); 73798944Sobrien} 73898944Sobrien 73919370Spststatic void cdx_destroy_res_attr(struct cdx_device *cdx_dev, int num) 74019370Spst{ 74119370Spst int i; 74219370Spst 74398944Sobrien /* removing the bin attributes */ 74419370Spst for (i = 0; i < num; i++) { 74519370Spst struct bin_attribute *res_attr; 74619370Spst 74798944Sobrien res_attr = cdx_dev->res_attr[i]; 74898944Sobrien if (res_attr) { 74919370Spst sysfs_remove_bin_file(&cdx_dev->dev.kobj, res_attr); 75019370Spst kfree(res_attr); 75119370Spst } 75246283Sdfr } 75319370Spst} 75498944Sobrien 75519370Spst#define CDX_RES_ATTR_NAME_LEN 10 75646283Sdfrstatic int cdx_create_res_attr(struct cdx_device *cdx_dev, int num) 75746283Sdfr{ 75898944Sobrien struct bin_attribute *res_attr; 75919370Spst char *res_attr_name; 76098944Sobrien int ret; 76119370Spst 76298944Sobrien res_attr = kzalloc(sizeof(*res_attr) + CDX_RES_ATTR_NAME_LEN, GFP_ATOMIC); 76319370Spst if (!res_attr) 76498944Sobrien return -ENOMEM; 76519370Spst 76619370Spst res_attr_name = (char *)(res_attr + 1); 767130803Smarcel 76898944Sobrien sysfs_bin_attr_init(res_attr); 76919370Spst 77019370Spst cdx_dev->res_attr[num] = res_attr; 77119370Spst sprintf(res_attr_name, "resource%d", num); 77298944Sobrien 77319370Spst res_attr->mmap = cdx_mmap_resource; 77446283Sdfr res_attr->attr.name = res_attr_name; 77519370Spst res_attr->attr.mode = 0600; 77619370Spst res_attr->size = cdx_resource_len(cdx_dev, num); 77798944Sobrien res_attr->private = (void *)(unsigned long)num; 77819370Spst ret = sysfs_create_bin_file(&cdx_dev->dev.kobj, res_attr); 77998944Sobrien if (ret) 78098944Sobrien kfree(res_attr); 78119370Spst 78298944Sobrien return ret; 78319370Spst} 78498944Sobrien 78519370Spstint cdx_device_add(struct cdx_dev_params *dev_params) 78698944Sobrien{ 78719370Spst struct cdx_controller *cdx = dev_params->cdx; 78819370Spst struct cdx_device *cdx_dev; 789130803Smarcel int ret, i; 790130803Smarcel 79198944Sobrien cdx_dev = kzalloc(sizeof(*cdx_dev), GFP_KERNEL); 79219370Spst if (!cdx_dev) 79319370Spst return -ENOMEM; 79419370Spst 79598944Sobrien /* Populate resource */ 79619370Spst memcpy(cdx_dev->res, dev_params->res, sizeof(struct resource) * 79719370Spst dev_params->res_count); 79819370Spst cdx_dev->res_count = dev_params->res_count; 79946283Sdfr 80019370Spst /* Populate CDX dev params */ 80119370Spst cdx_dev->req_id = dev_params->req_id; 80219370Spst cdx_dev->msi_dev_id = dev_params->msi_dev_id; 80398944Sobrien cdx_dev->vendor = dev_params->vendor; 80419370Spst cdx_dev->device = dev_params->device; 80546283Sdfr cdx_dev->subsystem_vendor = dev_params->subsys_vendor; 80698944Sobrien cdx_dev->subsystem_device = dev_params->subsys_device; 80719370Spst cdx_dev->class = dev_params->class; 80819370Spst cdx_dev->revision = dev_params->revision; 80998944Sobrien cdx_dev->bus_num = dev_params->bus_num; 81098944Sobrien cdx_dev->dev_num = dev_params->dev_num; 81198944Sobrien cdx_dev->cdx = dev_params->cdx; 81219370Spst cdx_dev->dma_mask = CDX_DEFAULT_DMA_MASK; 81398944Sobrien 81419370Spst /* Initialize generic device */ 81519370Spst device_initialize(&cdx_dev->dev); 81698944Sobrien cdx_dev->dev.parent = dev_params->parent; 81719370Spst cdx_dev->dev.bus = &cdx_bus_type; 81898944Sobrien cdx_dev->dev.dma_mask = &cdx_dev->dma_mask; 81919370Spst cdx_dev->dev.release = cdx_device_release; 82019370Spst cdx_dev->msi_write_pending = false; 82198944Sobrien mutex_init(&cdx_dev->irqchip_lock); 82219370Spst 82319370Spst /* Set Name */ 82419370Spst dev_set_name(&cdx_dev->dev, "cdx-%02x:%02x", 82519370Spst ((cdx->id << CDX_CONTROLLER_ID_SHIFT) | (cdx_dev->bus_num & CDX_BUS_NUM_MASK)), 82619370Spst cdx_dev->dev_num); 82719370Spst 82819370Spst if (cdx->msi_domain) { 82919370Spst cdx_dev->num_msi = dev_params->num_msi; 83046283Sdfr dev_set_msi_domain(&cdx_dev->dev, cdx->msi_domain); 83198944Sobrien } 83219370Spst 83398944Sobrien ret = device_add(&cdx_dev->dev); 83419370Spst if (ret) { 83598944Sobrien dev_err(&cdx_dev->dev, 83619370Spst "cdx device add failed: %d", ret); 83719370Spst goto fail; 83898944Sobrien } 839130803Smarcel 840130803Smarcel /* Create resource<N> attributes */ 84119370Spst for (i = 0; i < MAX_CDX_DEV_RESOURCES; i++) { 84298944Sobrien if (cdx_resource_flags(cdx_dev, i) & IORESOURCE_MEM) { 84398944Sobrien /* skip empty resources */ 84498944Sobrien if (!cdx_resource_len(cdx_dev, i)) 84519370Spst continue; 84698944Sobrien 84719370Spst ret = cdx_create_res_attr(cdx_dev, i); 84898944Sobrien if (ret != 0) { 84919370Spst dev_err(&cdx_dev->dev, 85019370Spst "cdx device resource<%d> file creation failed: %d", i, ret); 85198944Sobrien goto resource_create_fail; 852130803Smarcel } 85398944Sobrien } 85498944Sobrien } 85519370Spst 85698944Sobrien cdx_device_debugfs_init(cdx_dev); 85719370Spst 85846283Sdfr return 0; 85919370Spstresource_create_fail: 86019370Spst cdx_destroy_res_attr(cdx_dev, i); 86119370Spst device_del(&cdx_dev->dev); 86219370Spstfail: 86319370Spst /* 86419370Spst * Do not free cdx_dev here as it would be freed in 86519370Spst * cdx_device_release() called from put_device(). 86698944Sobrien */ 86719370Spst put_device(&cdx_dev->dev); 86819370Spst 86919370Spst return ret; 87019370Spst} 87119370SpstEXPORT_SYMBOL_NS_GPL(cdx_device_add, CDX_BUS_CONTROLLER); 87219370Spst 87319370Spststruct device *cdx_bus_add(struct cdx_controller *cdx, u8 bus_num) 87419370Spst{ 87519370Spst struct cdx_device *cdx_dev; 87619370Spst int ret; 87719370Spst 87819370Spst cdx_dev = kzalloc(sizeof(*cdx_dev), GFP_KERNEL); 87919370Spst if (!cdx_dev) 88019370Spst return NULL; 88119370Spst 88219370Spst device_initialize(&cdx_dev->dev); 88319370Spst cdx_dev->cdx = cdx; 88419370Spst 88519370Spst cdx_dev->dev.parent = cdx->dev; 88619370Spst cdx_dev->dev.bus = &cdx_bus_type; 88719370Spst cdx_dev->dev.release = cdx_device_release; 88819370Spst cdx_dev->is_bus = true; 88919370Spst cdx_dev->bus_num = bus_num; 89019370Spst 89119370Spst dev_set_name(&cdx_dev->dev, "cdx-%02x", 89298944Sobrien ((cdx->id << CDX_CONTROLLER_ID_SHIFT) | (bus_num & CDX_BUS_NUM_MASK))); 89319370Spst 89419370Spst ret = device_add(&cdx_dev->dev); 89598944Sobrien if (ret) { 89619370Spst dev_err(&cdx_dev->dev, "cdx bus device add failed: %d\n", ret); 89746283Sdfr goto device_add_fail; 89898944Sobrien } 89998944Sobrien 90019370Spst if (cdx->ops->bus_enable) { 90198944Sobrien ret = cdx->ops->bus_enable(cdx, bus_num); 90219370Spst if (ret && ret != -EALREADY) { 90398944Sobrien dev_err(cdx->dev, "cdx bus enable failed: %d\n", ret); 90498944Sobrien goto bus_enable_fail; 90519370Spst } 90619370Spst } 90719370Spst 90898944Sobrien cdx_dev->enabled = true; 90998944Sobrien return &cdx_dev->dev; 91019370Spst 91119370Spstbus_enable_fail: 91219370Spst device_del(&cdx_dev->dev); 91346283Sdfrdevice_add_fail: 91419370Spst put_device(&cdx_dev->dev); 91519370Spst 91619370Spst return NULL; 91746283Sdfr} 91846283SdfrEXPORT_SYMBOL_NS_GPL(cdx_bus_add, CDX_BUS_CONTROLLER); 91946283Sdfr 92098944Sobrienint cdx_register_controller(struct cdx_controller *cdx) 92119370Spst{ 92219370Spst int ret; 92319370Spst 92498944Sobrien ret = ida_alloc_range(&cdx_controller_ida, 0, MAX_CDX_CONTROLLERS - 1, GFP_KERNEL); 92519370Spst if (ret < 0) { 92619370Spst dev_err(cdx->dev, 92798944Sobrien "No free index available. Maximum controllers already registered\n"); 92819370Spst cdx->id = (u8)MAX_CDX_CONTROLLERS; 92998944Sobrien return ret; 93098944Sobrien } 93198944Sobrien 93298944Sobrien mutex_lock(&cdx_controller_lock); 93319370Spst cdx->id = ret; 93419370Spst 93598944Sobrien /* Scan all the devices */ 936130803Smarcel if (cdx->ops->scan) 93719370Spst cdx->ops->scan(cdx); 93898944Sobrien cdx->controller_registered = true; 93919370Spst mutex_unlock(&cdx_controller_lock); 94098944Sobrien 94119370Spst return 0; 94298944Sobrien} 94319370SpstEXPORT_SYMBOL_NS_GPL(cdx_register_controller, CDX_BUS_CONTROLLER); 94419370Spst 94519370Spstvoid cdx_unregister_controller(struct cdx_controller *cdx) 94698944Sobrien{ 94798944Sobrien if (cdx->id >= MAX_CDX_CONTROLLERS) 948130803Smarcel return; 94998944Sobrien 95098944Sobrien mutex_lock(&cdx_controller_lock); 95119370Spst 95219370Spst cdx->controller_registered = false; 95319370Spst device_for_each_child(cdx->dev, NULL, cdx_unregister_device); 95498944Sobrien ida_free(&cdx_controller_ida, cdx->id); 95519370Spst 95698944Sobrien mutex_unlock(&cdx_controller_lock); 95719370Spst} 958130803SmarcelEXPORT_SYMBOL_NS_GPL(cdx_unregister_controller, CDX_BUS_CONTROLLER); 95919370Spst 96098944Sobrienstatic int __init cdx_bus_init(void) 96198944Sobrien{ 96298944Sobrien int ret; 96319370Spst 96498944Sobrien ret = bus_register(&cdx_bus_type); 96598944Sobrien if (!ret) 96619370Spst cdx_debugfs_dir = debugfs_create_dir(cdx_bus_type.name, NULL); 96719370Spst 96898944Sobrien return ret; 96998944Sobrien} 97019370Spstpostcore_initcall(cdx_bus_init); 97146283Sdfr