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