xref: /kernel/linux/linux-5.10/drivers/dma/idxd/sysfs.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/* Copyright(c) 2019 Intel Corporation. All rights rsvd. */
38c2ecf20Sopenharmony_ci#include <linux/init.h>
48c2ecf20Sopenharmony_ci#include <linux/kernel.h>
58c2ecf20Sopenharmony_ci#include <linux/module.h>
68c2ecf20Sopenharmony_ci#include <linux/pci.h>
78c2ecf20Sopenharmony_ci#include <linux/device.h>
88c2ecf20Sopenharmony_ci#include <linux/io-64-nonatomic-lo-hi.h>
98c2ecf20Sopenharmony_ci#include <uapi/linux/idxd.h>
108c2ecf20Sopenharmony_ci#include "registers.h"
118c2ecf20Sopenharmony_ci#include "idxd.h"
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_cistatic char *idxd_wq_type_names[] = {
148c2ecf20Sopenharmony_ci	[IDXD_WQT_NONE]		= "none",
158c2ecf20Sopenharmony_ci	[IDXD_WQT_KERNEL]	= "kernel",
168c2ecf20Sopenharmony_ci	[IDXD_WQT_USER]		= "user",
178c2ecf20Sopenharmony_ci};
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_cistatic void idxd_conf_device_release(struct device *dev)
208c2ecf20Sopenharmony_ci{
218c2ecf20Sopenharmony_ci	dev_dbg(dev, "%s for %s\n", __func__, dev_name(dev));
228c2ecf20Sopenharmony_ci}
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_cistatic struct device_type idxd_group_device_type = {
258c2ecf20Sopenharmony_ci	.name = "group",
268c2ecf20Sopenharmony_ci	.release = idxd_conf_device_release,
278c2ecf20Sopenharmony_ci};
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistatic struct device_type idxd_wq_device_type = {
308c2ecf20Sopenharmony_ci	.name = "wq",
318c2ecf20Sopenharmony_ci	.release = idxd_conf_device_release,
328c2ecf20Sopenharmony_ci};
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic struct device_type idxd_engine_device_type = {
358c2ecf20Sopenharmony_ci	.name = "engine",
368c2ecf20Sopenharmony_ci	.release = idxd_conf_device_release,
378c2ecf20Sopenharmony_ci};
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistatic struct device_type dsa_device_type = {
408c2ecf20Sopenharmony_ci	.name = "dsa",
418c2ecf20Sopenharmony_ci	.release = idxd_conf_device_release,
428c2ecf20Sopenharmony_ci};
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cistatic inline bool is_dsa_dev(struct device *dev)
458c2ecf20Sopenharmony_ci{
468c2ecf20Sopenharmony_ci	return dev ? dev->type == &dsa_device_type : false;
478c2ecf20Sopenharmony_ci}
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistatic inline bool is_idxd_dev(struct device *dev)
508c2ecf20Sopenharmony_ci{
518c2ecf20Sopenharmony_ci	return is_dsa_dev(dev);
528c2ecf20Sopenharmony_ci}
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cistatic inline bool is_idxd_wq_dev(struct device *dev)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	return dev ? dev->type == &idxd_wq_device_type : false;
578c2ecf20Sopenharmony_ci}
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistatic inline bool is_idxd_wq_dmaengine(struct idxd_wq *wq)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	if (wq->type == IDXD_WQT_KERNEL &&
628c2ecf20Sopenharmony_ci	    strcmp(wq->name, "dmaengine") == 0)
638c2ecf20Sopenharmony_ci		return true;
648c2ecf20Sopenharmony_ci	return false;
658c2ecf20Sopenharmony_ci}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistatic inline bool is_idxd_wq_cdev(struct idxd_wq *wq)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	return wq->type == IDXD_WQT_USER;
708c2ecf20Sopenharmony_ci}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cistatic int idxd_config_bus_match(struct device *dev,
738c2ecf20Sopenharmony_ci				 struct device_driver *drv)
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	int matched = 0;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	if (is_idxd_dev(dev)) {
788c2ecf20Sopenharmony_ci		struct idxd_device *idxd = confdev_to_idxd(dev);
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci		if (idxd->state != IDXD_DEV_CONF_READY)
818c2ecf20Sopenharmony_ci			return 0;
828c2ecf20Sopenharmony_ci		matched = 1;
838c2ecf20Sopenharmony_ci	} else if (is_idxd_wq_dev(dev)) {
848c2ecf20Sopenharmony_ci		struct idxd_wq *wq = confdev_to_wq(dev);
858c2ecf20Sopenharmony_ci		struct idxd_device *idxd = wq->idxd;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci		if (idxd->state < IDXD_DEV_CONF_READY)
888c2ecf20Sopenharmony_ci			return 0;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci		if (wq->state != IDXD_WQ_DISABLED) {
918c2ecf20Sopenharmony_ci			dev_dbg(dev, "%s not disabled\n", dev_name(dev));
928c2ecf20Sopenharmony_ci			return 0;
938c2ecf20Sopenharmony_ci		}
948c2ecf20Sopenharmony_ci		matched = 1;
958c2ecf20Sopenharmony_ci	}
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	if (matched)
988c2ecf20Sopenharmony_ci		dev_dbg(dev, "%s matched\n", dev_name(dev));
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	return matched;
1018c2ecf20Sopenharmony_ci}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_cistatic int idxd_config_bus_probe(struct device *dev)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci	int rc;
1068c2ecf20Sopenharmony_ci	unsigned long flags;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	dev_dbg(dev, "%s called\n", __func__);
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	if (is_idxd_dev(dev)) {
1118c2ecf20Sopenharmony_ci		struct idxd_device *idxd = confdev_to_idxd(dev);
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci		if (idxd->state != IDXD_DEV_CONF_READY) {
1148c2ecf20Sopenharmony_ci			dev_warn(dev, "Device not ready for config\n");
1158c2ecf20Sopenharmony_ci			return -EBUSY;
1168c2ecf20Sopenharmony_ci		}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci		if (!try_module_get(THIS_MODULE))
1198c2ecf20Sopenharmony_ci			return -ENXIO;
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci		/* Perform IDXD configuration and enabling */
1228c2ecf20Sopenharmony_ci		spin_lock_irqsave(&idxd->dev_lock, flags);
1238c2ecf20Sopenharmony_ci		rc = idxd_device_config(idxd);
1248c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&idxd->dev_lock, flags);
1258c2ecf20Sopenharmony_ci		if (rc < 0) {
1268c2ecf20Sopenharmony_ci			module_put(THIS_MODULE);
1278c2ecf20Sopenharmony_ci			dev_warn(dev, "Device config failed: %d\n", rc);
1288c2ecf20Sopenharmony_ci			return rc;
1298c2ecf20Sopenharmony_ci		}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci		/* start device */
1328c2ecf20Sopenharmony_ci		rc = idxd_device_enable(idxd);
1338c2ecf20Sopenharmony_ci		if (rc < 0) {
1348c2ecf20Sopenharmony_ci			module_put(THIS_MODULE);
1358c2ecf20Sopenharmony_ci			dev_warn(dev, "Device enable failed: %d\n", rc);
1368c2ecf20Sopenharmony_ci			return rc;
1378c2ecf20Sopenharmony_ci		}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci		dev_info(dev, "Device %s enabled\n", dev_name(dev));
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci		rc = idxd_register_dma_device(idxd);
1428c2ecf20Sopenharmony_ci		if (rc < 0) {
1438c2ecf20Sopenharmony_ci			module_put(THIS_MODULE);
1448c2ecf20Sopenharmony_ci			dev_dbg(dev, "Failed to register dmaengine device\n");
1458c2ecf20Sopenharmony_ci			return rc;
1468c2ecf20Sopenharmony_ci		}
1478c2ecf20Sopenharmony_ci		return 0;
1488c2ecf20Sopenharmony_ci	} else if (is_idxd_wq_dev(dev)) {
1498c2ecf20Sopenharmony_ci		struct idxd_wq *wq = confdev_to_wq(dev);
1508c2ecf20Sopenharmony_ci		struct idxd_device *idxd = wq->idxd;
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci		mutex_lock(&wq->wq_lock);
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci		if (idxd->state != IDXD_DEV_ENABLED) {
1558c2ecf20Sopenharmony_ci			mutex_unlock(&wq->wq_lock);
1568c2ecf20Sopenharmony_ci			dev_warn(dev, "Enabling while device not enabled.\n");
1578c2ecf20Sopenharmony_ci			return -EPERM;
1588c2ecf20Sopenharmony_ci		}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci		if (wq->state != IDXD_WQ_DISABLED) {
1618c2ecf20Sopenharmony_ci			mutex_unlock(&wq->wq_lock);
1628c2ecf20Sopenharmony_ci			dev_warn(dev, "WQ %d already enabled.\n", wq->id);
1638c2ecf20Sopenharmony_ci			return -EBUSY;
1648c2ecf20Sopenharmony_ci		}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci		if (!wq->group) {
1678c2ecf20Sopenharmony_ci			mutex_unlock(&wq->wq_lock);
1688c2ecf20Sopenharmony_ci			dev_warn(dev, "WQ not attached to group.\n");
1698c2ecf20Sopenharmony_ci			return -EINVAL;
1708c2ecf20Sopenharmony_ci		}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci		if (strlen(wq->name) == 0) {
1738c2ecf20Sopenharmony_ci			mutex_unlock(&wq->wq_lock);
1748c2ecf20Sopenharmony_ci			dev_warn(dev, "WQ name not set.\n");
1758c2ecf20Sopenharmony_ci			return -EINVAL;
1768c2ecf20Sopenharmony_ci		}
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci		rc = idxd_wq_alloc_resources(wq);
1798c2ecf20Sopenharmony_ci		if (rc < 0) {
1808c2ecf20Sopenharmony_ci			mutex_unlock(&wq->wq_lock);
1818c2ecf20Sopenharmony_ci			dev_warn(dev, "WQ resource alloc failed\n");
1828c2ecf20Sopenharmony_ci			return rc;
1838c2ecf20Sopenharmony_ci		}
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci		spin_lock_irqsave(&idxd->dev_lock, flags);
1868c2ecf20Sopenharmony_ci		rc = idxd_device_config(idxd);
1878c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&idxd->dev_lock, flags);
1888c2ecf20Sopenharmony_ci		if (rc < 0) {
1898c2ecf20Sopenharmony_ci			mutex_unlock(&wq->wq_lock);
1908c2ecf20Sopenharmony_ci			dev_warn(dev, "Writing WQ %d config failed: %d\n",
1918c2ecf20Sopenharmony_ci				 wq->id, rc);
1928c2ecf20Sopenharmony_ci			return rc;
1938c2ecf20Sopenharmony_ci		}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci		rc = idxd_wq_enable(wq);
1968c2ecf20Sopenharmony_ci		if (rc < 0) {
1978c2ecf20Sopenharmony_ci			mutex_unlock(&wq->wq_lock);
1988c2ecf20Sopenharmony_ci			dev_warn(dev, "WQ %d enabling failed: %d\n",
1998c2ecf20Sopenharmony_ci				 wq->id, rc);
2008c2ecf20Sopenharmony_ci			return rc;
2018c2ecf20Sopenharmony_ci		}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci		rc = idxd_wq_map_portal(wq);
2048c2ecf20Sopenharmony_ci		if (rc < 0) {
2058c2ecf20Sopenharmony_ci			dev_warn(dev, "wq portal mapping failed: %d\n", rc);
2068c2ecf20Sopenharmony_ci			rc = idxd_wq_disable(wq);
2078c2ecf20Sopenharmony_ci			if (rc < 0)
2088c2ecf20Sopenharmony_ci				dev_warn(dev, "IDXD wq disable failed\n");
2098c2ecf20Sopenharmony_ci			mutex_unlock(&wq->wq_lock);
2108c2ecf20Sopenharmony_ci			return rc;
2118c2ecf20Sopenharmony_ci		}
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci		wq->client_count = 0;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci		dev_info(dev, "wq %s enabled\n", dev_name(&wq->conf_dev));
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci		if (is_idxd_wq_dmaengine(wq)) {
2188c2ecf20Sopenharmony_ci			rc = idxd_register_dma_channel(wq);
2198c2ecf20Sopenharmony_ci			if (rc < 0) {
2208c2ecf20Sopenharmony_ci				dev_dbg(dev, "DMA channel register failed\n");
2218c2ecf20Sopenharmony_ci				mutex_unlock(&wq->wq_lock);
2228c2ecf20Sopenharmony_ci				return rc;
2238c2ecf20Sopenharmony_ci			}
2248c2ecf20Sopenharmony_ci		} else if (is_idxd_wq_cdev(wq)) {
2258c2ecf20Sopenharmony_ci			rc = idxd_wq_add_cdev(wq);
2268c2ecf20Sopenharmony_ci			if (rc < 0) {
2278c2ecf20Sopenharmony_ci				dev_dbg(dev, "Cdev creation failed\n");
2288c2ecf20Sopenharmony_ci				mutex_unlock(&wq->wq_lock);
2298c2ecf20Sopenharmony_ci				return rc;
2308c2ecf20Sopenharmony_ci			}
2318c2ecf20Sopenharmony_ci		}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci		mutex_unlock(&wq->wq_lock);
2348c2ecf20Sopenharmony_ci		return 0;
2358c2ecf20Sopenharmony_ci	}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	return -ENODEV;
2388c2ecf20Sopenharmony_ci}
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_cistatic void disable_wq(struct idxd_wq *wq)
2418c2ecf20Sopenharmony_ci{
2428c2ecf20Sopenharmony_ci	struct idxd_device *idxd = wq->idxd;
2438c2ecf20Sopenharmony_ci	struct device *dev = &idxd->pdev->dev;
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	mutex_lock(&wq->wq_lock);
2468c2ecf20Sopenharmony_ci	dev_dbg(dev, "%s removing WQ %s\n", __func__, dev_name(&wq->conf_dev));
2478c2ecf20Sopenharmony_ci	if (wq->state == IDXD_WQ_DISABLED) {
2488c2ecf20Sopenharmony_ci		mutex_unlock(&wq->wq_lock);
2498c2ecf20Sopenharmony_ci		return;
2508c2ecf20Sopenharmony_ci	}
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	if (is_idxd_wq_dmaengine(wq))
2538c2ecf20Sopenharmony_ci		idxd_unregister_dma_channel(wq);
2548c2ecf20Sopenharmony_ci	else if (is_idxd_wq_cdev(wq))
2558c2ecf20Sopenharmony_ci		idxd_wq_del_cdev(wq);
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	if (idxd_wq_refcount(wq))
2588c2ecf20Sopenharmony_ci		dev_warn(dev, "Clients has claim on wq %d: %d\n",
2598c2ecf20Sopenharmony_ci			 wq->id, idxd_wq_refcount(wq));
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	idxd_wq_unmap_portal(wq);
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	idxd_wq_drain(wq);
2648c2ecf20Sopenharmony_ci	idxd_wq_reset(wq);
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	idxd_wq_free_resources(wq);
2678c2ecf20Sopenharmony_ci	wq->client_count = 0;
2688c2ecf20Sopenharmony_ci	mutex_unlock(&wq->wq_lock);
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	dev_info(dev, "wq %s disabled\n", dev_name(&wq->conf_dev));
2718c2ecf20Sopenharmony_ci}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_cistatic int idxd_config_bus_remove(struct device *dev)
2748c2ecf20Sopenharmony_ci{
2758c2ecf20Sopenharmony_ci	int rc;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	dev_dbg(dev, "%s called for %s\n", __func__, dev_name(dev));
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	/* disable workqueue here */
2808c2ecf20Sopenharmony_ci	if (is_idxd_wq_dev(dev)) {
2818c2ecf20Sopenharmony_ci		struct idxd_wq *wq = confdev_to_wq(dev);
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci		disable_wq(wq);
2848c2ecf20Sopenharmony_ci	} else if (is_idxd_dev(dev)) {
2858c2ecf20Sopenharmony_ci		struct idxd_device *idxd = confdev_to_idxd(dev);
2868c2ecf20Sopenharmony_ci		int i;
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci		dev_dbg(dev, "%s removing dev %s\n", __func__,
2898c2ecf20Sopenharmony_ci			dev_name(&idxd->conf_dev));
2908c2ecf20Sopenharmony_ci		for (i = 0; i < idxd->max_wqs; i++) {
2918c2ecf20Sopenharmony_ci			struct idxd_wq *wq = &idxd->wqs[i];
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci			if (wq->state == IDXD_WQ_DISABLED)
2948c2ecf20Sopenharmony_ci				continue;
2958c2ecf20Sopenharmony_ci			dev_warn(dev, "Active wq %d on disable %s.\n", i,
2968c2ecf20Sopenharmony_ci				 dev_name(&idxd->conf_dev));
2978c2ecf20Sopenharmony_ci			device_release_driver(&wq->conf_dev);
2988c2ecf20Sopenharmony_ci		}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci		idxd_unregister_dma_device(idxd);
3018c2ecf20Sopenharmony_ci		rc = idxd_device_disable(idxd);
3028c2ecf20Sopenharmony_ci		for (i = 0; i < idxd->max_wqs; i++) {
3038c2ecf20Sopenharmony_ci			struct idxd_wq *wq = &idxd->wqs[i];
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci			mutex_lock(&wq->wq_lock);
3068c2ecf20Sopenharmony_ci			idxd_wq_disable_cleanup(wq);
3078c2ecf20Sopenharmony_ci			mutex_unlock(&wq->wq_lock);
3088c2ecf20Sopenharmony_ci		}
3098c2ecf20Sopenharmony_ci		module_put(THIS_MODULE);
3108c2ecf20Sopenharmony_ci		if (rc < 0)
3118c2ecf20Sopenharmony_ci			dev_warn(dev, "Device disable failed\n");
3128c2ecf20Sopenharmony_ci		else
3138c2ecf20Sopenharmony_ci			dev_info(dev, "Device %s disabled\n", dev_name(dev));
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	return 0;
3188c2ecf20Sopenharmony_ci}
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_cistatic void idxd_config_bus_shutdown(struct device *dev)
3218c2ecf20Sopenharmony_ci{
3228c2ecf20Sopenharmony_ci	dev_dbg(dev, "%s called\n", __func__);
3238c2ecf20Sopenharmony_ci}
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_cistruct bus_type dsa_bus_type = {
3268c2ecf20Sopenharmony_ci	.name = "dsa",
3278c2ecf20Sopenharmony_ci	.match = idxd_config_bus_match,
3288c2ecf20Sopenharmony_ci	.probe = idxd_config_bus_probe,
3298c2ecf20Sopenharmony_ci	.remove = idxd_config_bus_remove,
3308c2ecf20Sopenharmony_ci	.shutdown = idxd_config_bus_shutdown,
3318c2ecf20Sopenharmony_ci};
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_cistatic struct bus_type *idxd_bus_types[] = {
3348c2ecf20Sopenharmony_ci	&dsa_bus_type
3358c2ecf20Sopenharmony_ci};
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_cistatic struct idxd_device_driver dsa_drv = {
3388c2ecf20Sopenharmony_ci	.drv = {
3398c2ecf20Sopenharmony_ci		.name = "dsa",
3408c2ecf20Sopenharmony_ci		.bus = &dsa_bus_type,
3418c2ecf20Sopenharmony_ci		.owner = THIS_MODULE,
3428c2ecf20Sopenharmony_ci		.mod_name = KBUILD_MODNAME,
3438c2ecf20Sopenharmony_ci	},
3448c2ecf20Sopenharmony_ci};
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_cistatic struct idxd_device_driver *idxd_drvs[] = {
3478c2ecf20Sopenharmony_ci	&dsa_drv
3488c2ecf20Sopenharmony_ci};
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_cistruct bus_type *idxd_get_bus_type(struct idxd_device *idxd)
3518c2ecf20Sopenharmony_ci{
3528c2ecf20Sopenharmony_ci	return idxd_bus_types[idxd->type];
3538c2ecf20Sopenharmony_ci}
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_cistatic struct device_type *idxd_get_device_type(struct idxd_device *idxd)
3568c2ecf20Sopenharmony_ci{
3578c2ecf20Sopenharmony_ci	if (idxd->type == IDXD_TYPE_DSA)
3588c2ecf20Sopenharmony_ci		return &dsa_device_type;
3598c2ecf20Sopenharmony_ci	else
3608c2ecf20Sopenharmony_ci		return NULL;
3618c2ecf20Sopenharmony_ci}
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci/* IDXD generic driver setup */
3648c2ecf20Sopenharmony_ciint idxd_register_driver(void)
3658c2ecf20Sopenharmony_ci{
3668c2ecf20Sopenharmony_ci	int i, rc;
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	for (i = 0; i < IDXD_TYPE_MAX; i++) {
3698c2ecf20Sopenharmony_ci		rc = driver_register(&idxd_drvs[i]->drv);
3708c2ecf20Sopenharmony_ci		if (rc < 0)
3718c2ecf20Sopenharmony_ci			goto drv_fail;
3728c2ecf20Sopenharmony_ci	}
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	return 0;
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_cidrv_fail:
3778c2ecf20Sopenharmony_ci	while (--i >= 0)
3788c2ecf20Sopenharmony_ci		driver_unregister(&idxd_drvs[i]->drv);
3798c2ecf20Sopenharmony_ci	return rc;
3808c2ecf20Sopenharmony_ci}
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_civoid idxd_unregister_driver(void)
3838c2ecf20Sopenharmony_ci{
3848c2ecf20Sopenharmony_ci	int i;
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	for (i = 0; i < IDXD_TYPE_MAX; i++)
3878c2ecf20Sopenharmony_ci		driver_unregister(&idxd_drvs[i]->drv);
3888c2ecf20Sopenharmony_ci}
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci/* IDXD engine attributes */
3918c2ecf20Sopenharmony_cistatic ssize_t engine_group_id_show(struct device *dev,
3928c2ecf20Sopenharmony_ci				    struct device_attribute *attr, char *buf)
3938c2ecf20Sopenharmony_ci{
3948c2ecf20Sopenharmony_ci	struct idxd_engine *engine =
3958c2ecf20Sopenharmony_ci		container_of(dev, struct idxd_engine, conf_dev);
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	if (engine->group)
3988c2ecf20Sopenharmony_ci		return sprintf(buf, "%d\n", engine->group->id);
3998c2ecf20Sopenharmony_ci	else
4008c2ecf20Sopenharmony_ci		return sprintf(buf, "%d\n", -1);
4018c2ecf20Sopenharmony_ci}
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_cistatic ssize_t engine_group_id_store(struct device *dev,
4048c2ecf20Sopenharmony_ci				     struct device_attribute *attr,
4058c2ecf20Sopenharmony_ci				     const char *buf, size_t count)
4068c2ecf20Sopenharmony_ci{
4078c2ecf20Sopenharmony_ci	struct idxd_engine *engine =
4088c2ecf20Sopenharmony_ci		container_of(dev, struct idxd_engine, conf_dev);
4098c2ecf20Sopenharmony_ci	struct idxd_device *idxd = engine->idxd;
4108c2ecf20Sopenharmony_ci	long id;
4118c2ecf20Sopenharmony_ci	int rc;
4128c2ecf20Sopenharmony_ci	struct idxd_group *prevg;
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	rc = kstrtol(buf, 10, &id);
4158c2ecf20Sopenharmony_ci	if (rc < 0)
4168c2ecf20Sopenharmony_ci		return -EINVAL;
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	if (!test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags))
4198c2ecf20Sopenharmony_ci		return -EPERM;
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	if (id > idxd->max_groups - 1 || id < -1)
4228c2ecf20Sopenharmony_ci		return -EINVAL;
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	if (id == -1) {
4258c2ecf20Sopenharmony_ci		if (engine->group) {
4268c2ecf20Sopenharmony_ci			engine->group->num_engines--;
4278c2ecf20Sopenharmony_ci			engine->group = NULL;
4288c2ecf20Sopenharmony_ci		}
4298c2ecf20Sopenharmony_ci		return count;
4308c2ecf20Sopenharmony_ci	}
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	prevg = engine->group;
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	if (prevg)
4358c2ecf20Sopenharmony_ci		prevg->num_engines--;
4368c2ecf20Sopenharmony_ci	engine->group = &idxd->groups[id];
4378c2ecf20Sopenharmony_ci	engine->group->num_engines++;
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	return count;
4408c2ecf20Sopenharmony_ci}
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_cistatic struct device_attribute dev_attr_engine_group =
4438c2ecf20Sopenharmony_ci		__ATTR(group_id, 0644, engine_group_id_show,
4448c2ecf20Sopenharmony_ci		       engine_group_id_store);
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_cistatic struct attribute *idxd_engine_attributes[] = {
4478c2ecf20Sopenharmony_ci	&dev_attr_engine_group.attr,
4488c2ecf20Sopenharmony_ci	NULL,
4498c2ecf20Sopenharmony_ci};
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_cistatic const struct attribute_group idxd_engine_attribute_group = {
4528c2ecf20Sopenharmony_ci	.attrs = idxd_engine_attributes,
4538c2ecf20Sopenharmony_ci};
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_cistatic const struct attribute_group *idxd_engine_attribute_groups[] = {
4568c2ecf20Sopenharmony_ci	&idxd_engine_attribute_group,
4578c2ecf20Sopenharmony_ci	NULL,
4588c2ecf20Sopenharmony_ci};
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci/* Group attributes */
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_cistatic void idxd_set_free_tokens(struct idxd_device *idxd)
4638c2ecf20Sopenharmony_ci{
4648c2ecf20Sopenharmony_ci	int i, tokens;
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	for (i = 0, tokens = 0; i < idxd->max_groups; i++) {
4678c2ecf20Sopenharmony_ci		struct idxd_group *g = &idxd->groups[i];
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci		tokens += g->tokens_reserved;
4708c2ecf20Sopenharmony_ci	}
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	idxd->nr_tokens = idxd->max_tokens - tokens;
4738c2ecf20Sopenharmony_ci}
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_cistatic ssize_t group_tokens_reserved_show(struct device *dev,
4768c2ecf20Sopenharmony_ci					  struct device_attribute *attr,
4778c2ecf20Sopenharmony_ci					  char *buf)
4788c2ecf20Sopenharmony_ci{
4798c2ecf20Sopenharmony_ci	struct idxd_group *group =
4808c2ecf20Sopenharmony_ci		container_of(dev, struct idxd_group, conf_dev);
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	return sprintf(buf, "%u\n", group->tokens_reserved);
4838c2ecf20Sopenharmony_ci}
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_cistatic ssize_t group_tokens_reserved_store(struct device *dev,
4868c2ecf20Sopenharmony_ci					   struct device_attribute *attr,
4878c2ecf20Sopenharmony_ci					   const char *buf, size_t count)
4888c2ecf20Sopenharmony_ci{
4898c2ecf20Sopenharmony_ci	struct idxd_group *group =
4908c2ecf20Sopenharmony_ci		container_of(dev, struct idxd_group, conf_dev);
4918c2ecf20Sopenharmony_ci	struct idxd_device *idxd = group->idxd;
4928c2ecf20Sopenharmony_ci	unsigned long val;
4938c2ecf20Sopenharmony_ci	int rc;
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	rc = kstrtoul(buf, 10, &val);
4968c2ecf20Sopenharmony_ci	if (rc < 0)
4978c2ecf20Sopenharmony_ci		return -EINVAL;
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	if (!test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags))
5008c2ecf20Sopenharmony_ci		return -EPERM;
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	if (idxd->state == IDXD_DEV_ENABLED)
5038c2ecf20Sopenharmony_ci		return -EPERM;
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	if (val > idxd->max_tokens)
5068c2ecf20Sopenharmony_ci		return -EINVAL;
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	if (val > idxd->nr_tokens + group->tokens_reserved)
5098c2ecf20Sopenharmony_ci		return -EINVAL;
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	group->tokens_reserved = val;
5128c2ecf20Sopenharmony_ci	idxd_set_free_tokens(idxd);
5138c2ecf20Sopenharmony_ci	return count;
5148c2ecf20Sopenharmony_ci}
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_cistatic struct device_attribute dev_attr_group_tokens_reserved =
5178c2ecf20Sopenharmony_ci		__ATTR(tokens_reserved, 0644, group_tokens_reserved_show,
5188c2ecf20Sopenharmony_ci		       group_tokens_reserved_store);
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_cistatic ssize_t group_tokens_allowed_show(struct device *dev,
5218c2ecf20Sopenharmony_ci					 struct device_attribute *attr,
5228c2ecf20Sopenharmony_ci					 char *buf)
5238c2ecf20Sopenharmony_ci{
5248c2ecf20Sopenharmony_ci	struct idxd_group *group =
5258c2ecf20Sopenharmony_ci		container_of(dev, struct idxd_group, conf_dev);
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	return sprintf(buf, "%u\n", group->tokens_allowed);
5288c2ecf20Sopenharmony_ci}
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_cistatic ssize_t group_tokens_allowed_store(struct device *dev,
5318c2ecf20Sopenharmony_ci					  struct device_attribute *attr,
5328c2ecf20Sopenharmony_ci					  const char *buf, size_t count)
5338c2ecf20Sopenharmony_ci{
5348c2ecf20Sopenharmony_ci	struct idxd_group *group =
5358c2ecf20Sopenharmony_ci		container_of(dev, struct idxd_group, conf_dev);
5368c2ecf20Sopenharmony_ci	struct idxd_device *idxd = group->idxd;
5378c2ecf20Sopenharmony_ci	unsigned long val;
5388c2ecf20Sopenharmony_ci	int rc;
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	rc = kstrtoul(buf, 10, &val);
5418c2ecf20Sopenharmony_ci	if (rc < 0)
5428c2ecf20Sopenharmony_ci		return -EINVAL;
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci	if (!test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags))
5458c2ecf20Sopenharmony_ci		return -EPERM;
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	if (idxd->state == IDXD_DEV_ENABLED)
5488c2ecf20Sopenharmony_ci		return -EPERM;
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	if (val < 4 * group->num_engines ||
5518c2ecf20Sopenharmony_ci	    val > group->tokens_reserved + idxd->nr_tokens)
5528c2ecf20Sopenharmony_ci		return -EINVAL;
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	group->tokens_allowed = val;
5558c2ecf20Sopenharmony_ci	return count;
5568c2ecf20Sopenharmony_ci}
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_cistatic struct device_attribute dev_attr_group_tokens_allowed =
5598c2ecf20Sopenharmony_ci		__ATTR(tokens_allowed, 0644, group_tokens_allowed_show,
5608c2ecf20Sopenharmony_ci		       group_tokens_allowed_store);
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_cistatic ssize_t group_use_token_limit_show(struct device *dev,
5638c2ecf20Sopenharmony_ci					  struct device_attribute *attr,
5648c2ecf20Sopenharmony_ci					  char *buf)
5658c2ecf20Sopenharmony_ci{
5668c2ecf20Sopenharmony_ci	struct idxd_group *group =
5678c2ecf20Sopenharmony_ci		container_of(dev, struct idxd_group, conf_dev);
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	return sprintf(buf, "%u\n", group->use_token_limit);
5708c2ecf20Sopenharmony_ci}
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_cistatic ssize_t group_use_token_limit_store(struct device *dev,
5738c2ecf20Sopenharmony_ci					   struct device_attribute *attr,
5748c2ecf20Sopenharmony_ci					   const char *buf, size_t count)
5758c2ecf20Sopenharmony_ci{
5768c2ecf20Sopenharmony_ci	struct idxd_group *group =
5778c2ecf20Sopenharmony_ci		container_of(dev, struct idxd_group, conf_dev);
5788c2ecf20Sopenharmony_ci	struct idxd_device *idxd = group->idxd;
5798c2ecf20Sopenharmony_ci	unsigned long val;
5808c2ecf20Sopenharmony_ci	int rc;
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	rc = kstrtoul(buf, 10, &val);
5838c2ecf20Sopenharmony_ci	if (rc < 0)
5848c2ecf20Sopenharmony_ci		return -EINVAL;
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	if (!test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags))
5878c2ecf20Sopenharmony_ci		return -EPERM;
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci	if (idxd->state == IDXD_DEV_ENABLED)
5908c2ecf20Sopenharmony_ci		return -EPERM;
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	if (idxd->token_limit == 0)
5938c2ecf20Sopenharmony_ci		return -EPERM;
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	group->use_token_limit = !!val;
5968c2ecf20Sopenharmony_ci	return count;
5978c2ecf20Sopenharmony_ci}
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_cistatic struct device_attribute dev_attr_group_use_token_limit =
6008c2ecf20Sopenharmony_ci		__ATTR(use_token_limit, 0644, group_use_token_limit_show,
6018c2ecf20Sopenharmony_ci		       group_use_token_limit_store);
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_cistatic ssize_t group_engines_show(struct device *dev,
6048c2ecf20Sopenharmony_ci				  struct device_attribute *attr, char *buf)
6058c2ecf20Sopenharmony_ci{
6068c2ecf20Sopenharmony_ci	struct idxd_group *group =
6078c2ecf20Sopenharmony_ci		container_of(dev, struct idxd_group, conf_dev);
6088c2ecf20Sopenharmony_ci	int i, rc = 0;
6098c2ecf20Sopenharmony_ci	char *tmp = buf;
6108c2ecf20Sopenharmony_ci	struct idxd_device *idxd = group->idxd;
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	for (i = 0; i < idxd->max_engines; i++) {
6138c2ecf20Sopenharmony_ci		struct idxd_engine *engine = &idxd->engines[i];
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci		if (!engine->group)
6168c2ecf20Sopenharmony_ci			continue;
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci		if (engine->group->id == group->id)
6198c2ecf20Sopenharmony_ci			rc += sprintf(tmp + rc, "engine%d.%d ",
6208c2ecf20Sopenharmony_ci					idxd->id, engine->id);
6218c2ecf20Sopenharmony_ci	}
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci	rc--;
6248c2ecf20Sopenharmony_ci	rc += sprintf(tmp + rc, "\n");
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	return rc;
6278c2ecf20Sopenharmony_ci}
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_cistatic struct device_attribute dev_attr_group_engines =
6308c2ecf20Sopenharmony_ci		__ATTR(engines, 0444, group_engines_show, NULL);
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_cistatic ssize_t group_work_queues_show(struct device *dev,
6338c2ecf20Sopenharmony_ci				      struct device_attribute *attr, char *buf)
6348c2ecf20Sopenharmony_ci{
6358c2ecf20Sopenharmony_ci	struct idxd_group *group =
6368c2ecf20Sopenharmony_ci		container_of(dev, struct idxd_group, conf_dev);
6378c2ecf20Sopenharmony_ci	int i, rc = 0;
6388c2ecf20Sopenharmony_ci	char *tmp = buf;
6398c2ecf20Sopenharmony_ci	struct idxd_device *idxd = group->idxd;
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci	for (i = 0; i < idxd->max_wqs; i++) {
6428c2ecf20Sopenharmony_ci		struct idxd_wq *wq = &idxd->wqs[i];
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci		if (!wq->group)
6458c2ecf20Sopenharmony_ci			continue;
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci		if (wq->group->id == group->id)
6488c2ecf20Sopenharmony_ci			rc += sprintf(tmp + rc, "wq%d.%d ",
6498c2ecf20Sopenharmony_ci					idxd->id, wq->id);
6508c2ecf20Sopenharmony_ci	}
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci	rc--;
6538c2ecf20Sopenharmony_ci	rc += sprintf(tmp + rc, "\n");
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci	return rc;
6568c2ecf20Sopenharmony_ci}
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_cistatic struct device_attribute dev_attr_group_work_queues =
6598c2ecf20Sopenharmony_ci		__ATTR(work_queues, 0444, group_work_queues_show, NULL);
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_cistatic ssize_t group_traffic_class_a_show(struct device *dev,
6628c2ecf20Sopenharmony_ci					  struct device_attribute *attr,
6638c2ecf20Sopenharmony_ci					  char *buf)
6648c2ecf20Sopenharmony_ci{
6658c2ecf20Sopenharmony_ci	struct idxd_group *group =
6668c2ecf20Sopenharmony_ci		container_of(dev, struct idxd_group, conf_dev);
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", group->tc_a);
6698c2ecf20Sopenharmony_ci}
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_cistatic ssize_t group_traffic_class_a_store(struct device *dev,
6728c2ecf20Sopenharmony_ci					   struct device_attribute *attr,
6738c2ecf20Sopenharmony_ci					   const char *buf, size_t count)
6748c2ecf20Sopenharmony_ci{
6758c2ecf20Sopenharmony_ci	struct idxd_group *group =
6768c2ecf20Sopenharmony_ci		container_of(dev, struct idxd_group, conf_dev);
6778c2ecf20Sopenharmony_ci	struct idxd_device *idxd = group->idxd;
6788c2ecf20Sopenharmony_ci	long val;
6798c2ecf20Sopenharmony_ci	int rc;
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci	rc = kstrtol(buf, 10, &val);
6828c2ecf20Sopenharmony_ci	if (rc < 0)
6838c2ecf20Sopenharmony_ci		return -EINVAL;
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci	if (!test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags))
6868c2ecf20Sopenharmony_ci		return -EPERM;
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	if (idxd->state == IDXD_DEV_ENABLED)
6898c2ecf20Sopenharmony_ci		return -EPERM;
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	if (val < 0 || val > 7)
6928c2ecf20Sopenharmony_ci		return -EINVAL;
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci	group->tc_a = val;
6958c2ecf20Sopenharmony_ci	return count;
6968c2ecf20Sopenharmony_ci}
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_cistatic struct device_attribute dev_attr_group_traffic_class_a =
6998c2ecf20Sopenharmony_ci		__ATTR(traffic_class_a, 0644, group_traffic_class_a_show,
7008c2ecf20Sopenharmony_ci		       group_traffic_class_a_store);
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_cistatic ssize_t group_traffic_class_b_show(struct device *dev,
7038c2ecf20Sopenharmony_ci					  struct device_attribute *attr,
7048c2ecf20Sopenharmony_ci					  char *buf)
7058c2ecf20Sopenharmony_ci{
7068c2ecf20Sopenharmony_ci	struct idxd_group *group =
7078c2ecf20Sopenharmony_ci		container_of(dev, struct idxd_group, conf_dev);
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", group->tc_b);
7108c2ecf20Sopenharmony_ci}
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_cistatic ssize_t group_traffic_class_b_store(struct device *dev,
7138c2ecf20Sopenharmony_ci					   struct device_attribute *attr,
7148c2ecf20Sopenharmony_ci					   const char *buf, size_t count)
7158c2ecf20Sopenharmony_ci{
7168c2ecf20Sopenharmony_ci	struct idxd_group *group =
7178c2ecf20Sopenharmony_ci		container_of(dev, struct idxd_group, conf_dev);
7188c2ecf20Sopenharmony_ci	struct idxd_device *idxd = group->idxd;
7198c2ecf20Sopenharmony_ci	long val;
7208c2ecf20Sopenharmony_ci	int rc;
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci	rc = kstrtol(buf, 10, &val);
7238c2ecf20Sopenharmony_ci	if (rc < 0)
7248c2ecf20Sopenharmony_ci		return -EINVAL;
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci	if (!test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags))
7278c2ecf20Sopenharmony_ci		return -EPERM;
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_ci	if (idxd->state == IDXD_DEV_ENABLED)
7308c2ecf20Sopenharmony_ci		return -EPERM;
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci	if (val < 0 || val > 7)
7338c2ecf20Sopenharmony_ci		return -EINVAL;
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci	group->tc_b = val;
7368c2ecf20Sopenharmony_ci	return count;
7378c2ecf20Sopenharmony_ci}
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_cistatic struct device_attribute dev_attr_group_traffic_class_b =
7408c2ecf20Sopenharmony_ci		__ATTR(traffic_class_b, 0644, group_traffic_class_b_show,
7418c2ecf20Sopenharmony_ci		       group_traffic_class_b_store);
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_cistatic struct attribute *idxd_group_attributes[] = {
7448c2ecf20Sopenharmony_ci	&dev_attr_group_work_queues.attr,
7458c2ecf20Sopenharmony_ci	&dev_attr_group_engines.attr,
7468c2ecf20Sopenharmony_ci	&dev_attr_group_use_token_limit.attr,
7478c2ecf20Sopenharmony_ci	&dev_attr_group_tokens_allowed.attr,
7488c2ecf20Sopenharmony_ci	&dev_attr_group_tokens_reserved.attr,
7498c2ecf20Sopenharmony_ci	&dev_attr_group_traffic_class_a.attr,
7508c2ecf20Sopenharmony_ci	&dev_attr_group_traffic_class_b.attr,
7518c2ecf20Sopenharmony_ci	NULL,
7528c2ecf20Sopenharmony_ci};
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_cistatic const struct attribute_group idxd_group_attribute_group = {
7558c2ecf20Sopenharmony_ci	.attrs = idxd_group_attributes,
7568c2ecf20Sopenharmony_ci};
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_cistatic const struct attribute_group *idxd_group_attribute_groups[] = {
7598c2ecf20Sopenharmony_ci	&idxd_group_attribute_group,
7608c2ecf20Sopenharmony_ci	NULL,
7618c2ecf20Sopenharmony_ci};
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci/* IDXD work queue attribs */
7648c2ecf20Sopenharmony_cistatic ssize_t wq_clients_show(struct device *dev,
7658c2ecf20Sopenharmony_ci			       struct device_attribute *attr, char *buf)
7668c2ecf20Sopenharmony_ci{
7678c2ecf20Sopenharmony_ci	struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev);
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", wq->client_count);
7708c2ecf20Sopenharmony_ci}
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_cistatic struct device_attribute dev_attr_wq_clients =
7738c2ecf20Sopenharmony_ci		__ATTR(clients, 0444, wq_clients_show, NULL);
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_cistatic ssize_t wq_state_show(struct device *dev,
7768c2ecf20Sopenharmony_ci			     struct device_attribute *attr, char *buf)
7778c2ecf20Sopenharmony_ci{
7788c2ecf20Sopenharmony_ci	struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev);
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci	switch (wq->state) {
7818c2ecf20Sopenharmony_ci	case IDXD_WQ_DISABLED:
7828c2ecf20Sopenharmony_ci		return sprintf(buf, "disabled\n");
7838c2ecf20Sopenharmony_ci	case IDXD_WQ_ENABLED:
7848c2ecf20Sopenharmony_ci		return sprintf(buf, "enabled\n");
7858c2ecf20Sopenharmony_ci	}
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci	return sprintf(buf, "unknown\n");
7888c2ecf20Sopenharmony_ci}
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_cistatic struct device_attribute dev_attr_wq_state =
7918c2ecf20Sopenharmony_ci		__ATTR(state, 0444, wq_state_show, NULL);
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_cistatic ssize_t wq_group_id_show(struct device *dev,
7948c2ecf20Sopenharmony_ci				struct device_attribute *attr, char *buf)
7958c2ecf20Sopenharmony_ci{
7968c2ecf20Sopenharmony_ci	struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev);
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci	if (wq->group)
7998c2ecf20Sopenharmony_ci		return sprintf(buf, "%u\n", wq->group->id);
8008c2ecf20Sopenharmony_ci	else
8018c2ecf20Sopenharmony_ci		return sprintf(buf, "-1\n");
8028c2ecf20Sopenharmony_ci}
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_cistatic ssize_t wq_group_id_store(struct device *dev,
8058c2ecf20Sopenharmony_ci				 struct device_attribute *attr,
8068c2ecf20Sopenharmony_ci				 const char *buf, size_t count)
8078c2ecf20Sopenharmony_ci{
8088c2ecf20Sopenharmony_ci	struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev);
8098c2ecf20Sopenharmony_ci	struct idxd_device *idxd = wq->idxd;
8108c2ecf20Sopenharmony_ci	long id;
8118c2ecf20Sopenharmony_ci	int rc;
8128c2ecf20Sopenharmony_ci	struct idxd_group *prevg, *group;
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	rc = kstrtol(buf, 10, &id);
8158c2ecf20Sopenharmony_ci	if (rc < 0)
8168c2ecf20Sopenharmony_ci		return -EINVAL;
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci	if (!test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags))
8198c2ecf20Sopenharmony_ci		return -EPERM;
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci	if (wq->state != IDXD_WQ_DISABLED)
8228c2ecf20Sopenharmony_ci		return -EPERM;
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci	if (id > idxd->max_groups - 1 || id < -1)
8258c2ecf20Sopenharmony_ci		return -EINVAL;
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci	if (id == -1) {
8288c2ecf20Sopenharmony_ci		if (wq->group) {
8298c2ecf20Sopenharmony_ci			wq->group->num_wqs--;
8308c2ecf20Sopenharmony_ci			wq->group = NULL;
8318c2ecf20Sopenharmony_ci		}
8328c2ecf20Sopenharmony_ci		return count;
8338c2ecf20Sopenharmony_ci	}
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci	group = &idxd->groups[id];
8368c2ecf20Sopenharmony_ci	prevg = wq->group;
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_ci	if (prevg)
8398c2ecf20Sopenharmony_ci		prevg->num_wqs--;
8408c2ecf20Sopenharmony_ci	wq->group = group;
8418c2ecf20Sopenharmony_ci	group->num_wqs++;
8428c2ecf20Sopenharmony_ci	return count;
8438c2ecf20Sopenharmony_ci}
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_cistatic struct device_attribute dev_attr_wq_group_id =
8468c2ecf20Sopenharmony_ci		__ATTR(group_id, 0644, wq_group_id_show, wq_group_id_store);
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_cistatic ssize_t wq_mode_show(struct device *dev, struct device_attribute *attr,
8498c2ecf20Sopenharmony_ci			    char *buf)
8508c2ecf20Sopenharmony_ci{
8518c2ecf20Sopenharmony_ci	struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev);
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_ci	return sprintf(buf, "%s\n",
8548c2ecf20Sopenharmony_ci			wq_dedicated(wq) ? "dedicated" : "shared");
8558c2ecf20Sopenharmony_ci}
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_cistatic ssize_t wq_mode_store(struct device *dev,
8588c2ecf20Sopenharmony_ci			     struct device_attribute *attr, const char *buf,
8598c2ecf20Sopenharmony_ci			     size_t count)
8608c2ecf20Sopenharmony_ci{
8618c2ecf20Sopenharmony_ci	struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev);
8628c2ecf20Sopenharmony_ci	struct idxd_device *idxd = wq->idxd;
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci	if (!test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags))
8658c2ecf20Sopenharmony_ci		return -EPERM;
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci	if (wq->state != IDXD_WQ_DISABLED)
8688c2ecf20Sopenharmony_ci		return -EPERM;
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci	if (sysfs_streq(buf, "dedicated")) {
8718c2ecf20Sopenharmony_ci		set_bit(WQ_FLAG_DEDICATED, &wq->flags);
8728c2ecf20Sopenharmony_ci		wq->threshold = 0;
8738c2ecf20Sopenharmony_ci	} else {
8748c2ecf20Sopenharmony_ci		return -EINVAL;
8758c2ecf20Sopenharmony_ci	}
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci	return count;
8788c2ecf20Sopenharmony_ci}
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_cistatic struct device_attribute dev_attr_wq_mode =
8818c2ecf20Sopenharmony_ci		__ATTR(mode, 0644, wq_mode_show, wq_mode_store);
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_cistatic ssize_t wq_size_show(struct device *dev, struct device_attribute *attr,
8848c2ecf20Sopenharmony_ci			    char *buf)
8858c2ecf20Sopenharmony_ci{
8868c2ecf20Sopenharmony_ci	struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev);
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci	return sprintf(buf, "%u\n", wq->size);
8898c2ecf20Sopenharmony_ci}
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_cistatic int total_claimed_wq_size(struct idxd_device *idxd)
8928c2ecf20Sopenharmony_ci{
8938c2ecf20Sopenharmony_ci	int i;
8948c2ecf20Sopenharmony_ci	int wq_size = 0;
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci	for (i = 0; i < idxd->max_wqs; i++) {
8978c2ecf20Sopenharmony_ci		struct idxd_wq *wq = &idxd->wqs[i];
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci		wq_size += wq->size;
9008c2ecf20Sopenharmony_ci	}
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci	return wq_size;
9038c2ecf20Sopenharmony_ci}
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_cistatic ssize_t wq_size_store(struct device *dev,
9068c2ecf20Sopenharmony_ci			     struct device_attribute *attr, const char *buf,
9078c2ecf20Sopenharmony_ci			     size_t count)
9088c2ecf20Sopenharmony_ci{
9098c2ecf20Sopenharmony_ci	struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev);
9108c2ecf20Sopenharmony_ci	unsigned long size;
9118c2ecf20Sopenharmony_ci	struct idxd_device *idxd = wq->idxd;
9128c2ecf20Sopenharmony_ci	int rc;
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci	rc = kstrtoul(buf, 10, &size);
9158c2ecf20Sopenharmony_ci	if (rc < 0)
9168c2ecf20Sopenharmony_ci		return -EINVAL;
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci	if (!test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags))
9198c2ecf20Sopenharmony_ci		return -EPERM;
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci	if (idxd->state == IDXD_DEV_ENABLED)
9228c2ecf20Sopenharmony_ci		return -EPERM;
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	if (size + total_claimed_wq_size(idxd) - wq->size > idxd->max_wq_size)
9258c2ecf20Sopenharmony_ci		return -EINVAL;
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_ci	wq->size = size;
9288c2ecf20Sopenharmony_ci	return count;
9298c2ecf20Sopenharmony_ci}
9308c2ecf20Sopenharmony_ci
9318c2ecf20Sopenharmony_cistatic struct device_attribute dev_attr_wq_size =
9328c2ecf20Sopenharmony_ci		__ATTR(size, 0644, wq_size_show, wq_size_store);
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_cistatic ssize_t wq_priority_show(struct device *dev,
9358c2ecf20Sopenharmony_ci				struct device_attribute *attr, char *buf)
9368c2ecf20Sopenharmony_ci{
9378c2ecf20Sopenharmony_ci	struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev);
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_ci	return sprintf(buf, "%u\n", wq->priority);
9408c2ecf20Sopenharmony_ci}
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_cistatic ssize_t wq_priority_store(struct device *dev,
9438c2ecf20Sopenharmony_ci				 struct device_attribute *attr,
9448c2ecf20Sopenharmony_ci				 const char *buf, size_t count)
9458c2ecf20Sopenharmony_ci{
9468c2ecf20Sopenharmony_ci	struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev);
9478c2ecf20Sopenharmony_ci	unsigned long prio;
9488c2ecf20Sopenharmony_ci	struct idxd_device *idxd = wq->idxd;
9498c2ecf20Sopenharmony_ci	int rc;
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci	rc = kstrtoul(buf, 10, &prio);
9528c2ecf20Sopenharmony_ci	if (rc < 0)
9538c2ecf20Sopenharmony_ci		return -EINVAL;
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_ci	if (!test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags))
9568c2ecf20Sopenharmony_ci		return -EPERM;
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci	if (wq->state != IDXD_WQ_DISABLED)
9598c2ecf20Sopenharmony_ci		return -EPERM;
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci	if (prio > IDXD_MAX_PRIORITY)
9628c2ecf20Sopenharmony_ci		return -EINVAL;
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci	wq->priority = prio;
9658c2ecf20Sopenharmony_ci	return count;
9668c2ecf20Sopenharmony_ci}
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_cistatic struct device_attribute dev_attr_wq_priority =
9698c2ecf20Sopenharmony_ci		__ATTR(priority, 0644, wq_priority_show, wq_priority_store);
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_cistatic ssize_t wq_type_show(struct device *dev,
9728c2ecf20Sopenharmony_ci			    struct device_attribute *attr, char *buf)
9738c2ecf20Sopenharmony_ci{
9748c2ecf20Sopenharmony_ci	struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev);
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci	switch (wq->type) {
9778c2ecf20Sopenharmony_ci	case IDXD_WQT_KERNEL:
9788c2ecf20Sopenharmony_ci		return sprintf(buf, "%s\n",
9798c2ecf20Sopenharmony_ci			       idxd_wq_type_names[IDXD_WQT_KERNEL]);
9808c2ecf20Sopenharmony_ci	case IDXD_WQT_USER:
9818c2ecf20Sopenharmony_ci		return sprintf(buf, "%s\n",
9828c2ecf20Sopenharmony_ci			       idxd_wq_type_names[IDXD_WQT_USER]);
9838c2ecf20Sopenharmony_ci	case IDXD_WQT_NONE:
9848c2ecf20Sopenharmony_ci	default:
9858c2ecf20Sopenharmony_ci		return sprintf(buf, "%s\n",
9868c2ecf20Sopenharmony_ci			       idxd_wq_type_names[IDXD_WQT_NONE]);
9878c2ecf20Sopenharmony_ci	}
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_ci	return -EINVAL;
9908c2ecf20Sopenharmony_ci}
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_cistatic ssize_t wq_type_store(struct device *dev,
9938c2ecf20Sopenharmony_ci			     struct device_attribute *attr, const char *buf,
9948c2ecf20Sopenharmony_ci			     size_t count)
9958c2ecf20Sopenharmony_ci{
9968c2ecf20Sopenharmony_ci	struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev);
9978c2ecf20Sopenharmony_ci	enum idxd_wq_type old_type;
9988c2ecf20Sopenharmony_ci
9998c2ecf20Sopenharmony_ci	if (wq->state != IDXD_WQ_DISABLED)
10008c2ecf20Sopenharmony_ci		return -EPERM;
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_ci	old_type = wq->type;
10038c2ecf20Sopenharmony_ci	if (sysfs_streq(buf, idxd_wq_type_names[IDXD_WQT_NONE]))
10048c2ecf20Sopenharmony_ci		wq->type = IDXD_WQT_NONE;
10058c2ecf20Sopenharmony_ci	else if (sysfs_streq(buf, idxd_wq_type_names[IDXD_WQT_KERNEL]))
10068c2ecf20Sopenharmony_ci		wq->type = IDXD_WQT_KERNEL;
10078c2ecf20Sopenharmony_ci	else if (sysfs_streq(buf, idxd_wq_type_names[IDXD_WQT_USER]))
10088c2ecf20Sopenharmony_ci		wq->type = IDXD_WQT_USER;
10098c2ecf20Sopenharmony_ci	else
10108c2ecf20Sopenharmony_ci		return -EINVAL;
10118c2ecf20Sopenharmony_ci
10128c2ecf20Sopenharmony_ci	/* If we are changing queue type, clear the name */
10138c2ecf20Sopenharmony_ci	if (wq->type != old_type)
10148c2ecf20Sopenharmony_ci		memset(wq->name, 0, WQ_NAME_SIZE + 1);
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci	return count;
10178c2ecf20Sopenharmony_ci}
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_cistatic struct device_attribute dev_attr_wq_type =
10208c2ecf20Sopenharmony_ci		__ATTR(type, 0644, wq_type_show, wq_type_store);
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_cistatic ssize_t wq_name_show(struct device *dev,
10238c2ecf20Sopenharmony_ci			    struct device_attribute *attr, char *buf)
10248c2ecf20Sopenharmony_ci{
10258c2ecf20Sopenharmony_ci	struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev);
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci	return sprintf(buf, "%s\n", wq->name);
10288c2ecf20Sopenharmony_ci}
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_cistatic ssize_t wq_name_store(struct device *dev,
10318c2ecf20Sopenharmony_ci			     struct device_attribute *attr, const char *buf,
10328c2ecf20Sopenharmony_ci			     size_t count)
10338c2ecf20Sopenharmony_ci{
10348c2ecf20Sopenharmony_ci	struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev);
10358c2ecf20Sopenharmony_ci
10368c2ecf20Sopenharmony_ci	if (wq->state != IDXD_WQ_DISABLED)
10378c2ecf20Sopenharmony_ci		return -EPERM;
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_ci	if (strlen(buf) > WQ_NAME_SIZE || strlen(buf) == 0)
10408c2ecf20Sopenharmony_ci		return -EINVAL;
10418c2ecf20Sopenharmony_ci
10428c2ecf20Sopenharmony_ci	memset(wq->name, 0, WQ_NAME_SIZE + 1);
10438c2ecf20Sopenharmony_ci	strncpy(wq->name, buf, WQ_NAME_SIZE);
10448c2ecf20Sopenharmony_ci	strreplace(wq->name, '\n', '\0');
10458c2ecf20Sopenharmony_ci	return count;
10468c2ecf20Sopenharmony_ci}
10478c2ecf20Sopenharmony_ci
10488c2ecf20Sopenharmony_cistatic struct device_attribute dev_attr_wq_name =
10498c2ecf20Sopenharmony_ci		__ATTR(name, 0644, wq_name_show, wq_name_store);
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_cistatic ssize_t wq_cdev_minor_show(struct device *dev,
10528c2ecf20Sopenharmony_ci				  struct device_attribute *attr, char *buf)
10538c2ecf20Sopenharmony_ci{
10548c2ecf20Sopenharmony_ci	struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev);
10558c2ecf20Sopenharmony_ci	int minor = -1;
10568c2ecf20Sopenharmony_ci
10578c2ecf20Sopenharmony_ci	mutex_lock(&wq->wq_lock);
10588c2ecf20Sopenharmony_ci	if (wq->idxd_cdev)
10598c2ecf20Sopenharmony_ci		minor = wq->idxd_cdev->minor;
10608c2ecf20Sopenharmony_ci	mutex_unlock(&wq->wq_lock);
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_ci	if (minor == -1)
10638c2ecf20Sopenharmony_ci		return -ENXIO;
10648c2ecf20Sopenharmony_ci	return sysfs_emit(buf, "%d\n", minor);
10658c2ecf20Sopenharmony_ci}
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_cistatic struct device_attribute dev_attr_wq_cdev_minor =
10688c2ecf20Sopenharmony_ci		__ATTR(cdev_minor, 0444, wq_cdev_minor_show, NULL);
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_cistatic int __get_sysfs_u64(const char *buf, u64 *val)
10718c2ecf20Sopenharmony_ci{
10728c2ecf20Sopenharmony_ci	int rc;
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_ci	rc = kstrtou64(buf, 0, val);
10758c2ecf20Sopenharmony_ci	if (rc < 0)
10768c2ecf20Sopenharmony_ci		return -EINVAL;
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_ci	if (*val == 0)
10798c2ecf20Sopenharmony_ci		return -EINVAL;
10808c2ecf20Sopenharmony_ci
10818c2ecf20Sopenharmony_ci	*val = roundup_pow_of_two(*val);
10828c2ecf20Sopenharmony_ci	return 0;
10838c2ecf20Sopenharmony_ci}
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_cistatic ssize_t wq_max_transfer_size_show(struct device *dev, struct device_attribute *attr,
10868c2ecf20Sopenharmony_ci					 char *buf)
10878c2ecf20Sopenharmony_ci{
10888c2ecf20Sopenharmony_ci	struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev);
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ci	return sprintf(buf, "%llu\n", wq->max_xfer_bytes);
10918c2ecf20Sopenharmony_ci}
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_cistatic ssize_t wq_max_transfer_size_store(struct device *dev, struct device_attribute *attr,
10948c2ecf20Sopenharmony_ci					  const char *buf, size_t count)
10958c2ecf20Sopenharmony_ci{
10968c2ecf20Sopenharmony_ci	struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev);
10978c2ecf20Sopenharmony_ci	struct idxd_device *idxd = wq->idxd;
10988c2ecf20Sopenharmony_ci	u64 xfer_size;
10998c2ecf20Sopenharmony_ci	int rc;
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_ci	if (!test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags))
11028c2ecf20Sopenharmony_ci		return -EPERM;
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_ci	if (wq->state != IDXD_WQ_DISABLED)
11058c2ecf20Sopenharmony_ci		return -EPERM;
11068c2ecf20Sopenharmony_ci
11078c2ecf20Sopenharmony_ci	rc = __get_sysfs_u64(buf, &xfer_size);
11088c2ecf20Sopenharmony_ci	if (rc < 0)
11098c2ecf20Sopenharmony_ci		return rc;
11108c2ecf20Sopenharmony_ci
11118c2ecf20Sopenharmony_ci	if (xfer_size > idxd->max_xfer_bytes)
11128c2ecf20Sopenharmony_ci		return -EINVAL;
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ci	wq->max_xfer_bytes = xfer_size;
11158c2ecf20Sopenharmony_ci
11168c2ecf20Sopenharmony_ci	return count;
11178c2ecf20Sopenharmony_ci}
11188c2ecf20Sopenharmony_ci
11198c2ecf20Sopenharmony_cistatic struct device_attribute dev_attr_wq_max_transfer_size =
11208c2ecf20Sopenharmony_ci		__ATTR(max_transfer_size, 0644,
11218c2ecf20Sopenharmony_ci		       wq_max_transfer_size_show, wq_max_transfer_size_store);
11228c2ecf20Sopenharmony_ci
11238c2ecf20Sopenharmony_cistatic ssize_t wq_max_batch_size_show(struct device *dev, struct device_attribute *attr, char *buf)
11248c2ecf20Sopenharmony_ci{
11258c2ecf20Sopenharmony_ci	struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev);
11268c2ecf20Sopenharmony_ci
11278c2ecf20Sopenharmony_ci	return sprintf(buf, "%u\n", wq->max_batch_size);
11288c2ecf20Sopenharmony_ci}
11298c2ecf20Sopenharmony_ci
11308c2ecf20Sopenharmony_cistatic ssize_t wq_max_batch_size_store(struct device *dev, struct device_attribute *attr,
11318c2ecf20Sopenharmony_ci				       const char *buf, size_t count)
11328c2ecf20Sopenharmony_ci{
11338c2ecf20Sopenharmony_ci	struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev);
11348c2ecf20Sopenharmony_ci	struct idxd_device *idxd = wq->idxd;
11358c2ecf20Sopenharmony_ci	u64 batch_size;
11368c2ecf20Sopenharmony_ci	int rc;
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_ci	if (!test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags))
11398c2ecf20Sopenharmony_ci		return -EPERM;
11408c2ecf20Sopenharmony_ci
11418c2ecf20Sopenharmony_ci	if (wq->state != IDXD_WQ_DISABLED)
11428c2ecf20Sopenharmony_ci		return -EPERM;
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_ci	rc = __get_sysfs_u64(buf, &batch_size);
11458c2ecf20Sopenharmony_ci	if (rc < 0)
11468c2ecf20Sopenharmony_ci		return rc;
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_ci	if (batch_size > idxd->max_batch_size)
11498c2ecf20Sopenharmony_ci		return -EINVAL;
11508c2ecf20Sopenharmony_ci
11518c2ecf20Sopenharmony_ci	wq->max_batch_size = (u32)batch_size;
11528c2ecf20Sopenharmony_ci
11538c2ecf20Sopenharmony_ci	return count;
11548c2ecf20Sopenharmony_ci}
11558c2ecf20Sopenharmony_ci
11568c2ecf20Sopenharmony_cistatic struct device_attribute dev_attr_wq_max_batch_size =
11578c2ecf20Sopenharmony_ci		__ATTR(max_batch_size, 0644, wq_max_batch_size_show, wq_max_batch_size_store);
11588c2ecf20Sopenharmony_ci
11598c2ecf20Sopenharmony_cistatic struct attribute *idxd_wq_attributes[] = {
11608c2ecf20Sopenharmony_ci	&dev_attr_wq_clients.attr,
11618c2ecf20Sopenharmony_ci	&dev_attr_wq_state.attr,
11628c2ecf20Sopenharmony_ci	&dev_attr_wq_group_id.attr,
11638c2ecf20Sopenharmony_ci	&dev_attr_wq_mode.attr,
11648c2ecf20Sopenharmony_ci	&dev_attr_wq_size.attr,
11658c2ecf20Sopenharmony_ci	&dev_attr_wq_priority.attr,
11668c2ecf20Sopenharmony_ci	&dev_attr_wq_type.attr,
11678c2ecf20Sopenharmony_ci	&dev_attr_wq_name.attr,
11688c2ecf20Sopenharmony_ci	&dev_attr_wq_cdev_minor.attr,
11698c2ecf20Sopenharmony_ci	&dev_attr_wq_max_transfer_size.attr,
11708c2ecf20Sopenharmony_ci	&dev_attr_wq_max_batch_size.attr,
11718c2ecf20Sopenharmony_ci	NULL,
11728c2ecf20Sopenharmony_ci};
11738c2ecf20Sopenharmony_ci
11748c2ecf20Sopenharmony_cistatic const struct attribute_group idxd_wq_attribute_group = {
11758c2ecf20Sopenharmony_ci	.attrs = idxd_wq_attributes,
11768c2ecf20Sopenharmony_ci};
11778c2ecf20Sopenharmony_ci
11788c2ecf20Sopenharmony_cistatic const struct attribute_group *idxd_wq_attribute_groups[] = {
11798c2ecf20Sopenharmony_ci	&idxd_wq_attribute_group,
11808c2ecf20Sopenharmony_ci	NULL,
11818c2ecf20Sopenharmony_ci};
11828c2ecf20Sopenharmony_ci
11838c2ecf20Sopenharmony_ci/* IDXD device attribs */
11848c2ecf20Sopenharmony_cistatic ssize_t version_show(struct device *dev, struct device_attribute *attr,
11858c2ecf20Sopenharmony_ci			    char *buf)
11868c2ecf20Sopenharmony_ci{
11878c2ecf20Sopenharmony_ci	struct idxd_device *idxd =
11888c2ecf20Sopenharmony_ci		container_of(dev, struct idxd_device, conf_dev);
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_ci	return sprintf(buf, "%#x\n", idxd->hw.version);
11918c2ecf20Sopenharmony_ci}
11928c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(version);
11938c2ecf20Sopenharmony_ci
11948c2ecf20Sopenharmony_cistatic ssize_t max_work_queues_size_show(struct device *dev,
11958c2ecf20Sopenharmony_ci					 struct device_attribute *attr,
11968c2ecf20Sopenharmony_ci					 char *buf)
11978c2ecf20Sopenharmony_ci{
11988c2ecf20Sopenharmony_ci	struct idxd_device *idxd =
11998c2ecf20Sopenharmony_ci		container_of(dev, struct idxd_device, conf_dev);
12008c2ecf20Sopenharmony_ci
12018c2ecf20Sopenharmony_ci	return sprintf(buf, "%u\n", idxd->max_wq_size);
12028c2ecf20Sopenharmony_ci}
12038c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(max_work_queues_size);
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_cistatic ssize_t max_groups_show(struct device *dev,
12068c2ecf20Sopenharmony_ci			       struct device_attribute *attr, char *buf)
12078c2ecf20Sopenharmony_ci{
12088c2ecf20Sopenharmony_ci	struct idxd_device *idxd =
12098c2ecf20Sopenharmony_ci		container_of(dev, struct idxd_device, conf_dev);
12108c2ecf20Sopenharmony_ci
12118c2ecf20Sopenharmony_ci	return sprintf(buf, "%u\n", idxd->max_groups);
12128c2ecf20Sopenharmony_ci}
12138c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(max_groups);
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_cistatic ssize_t max_work_queues_show(struct device *dev,
12168c2ecf20Sopenharmony_ci				    struct device_attribute *attr, char *buf)
12178c2ecf20Sopenharmony_ci{
12188c2ecf20Sopenharmony_ci	struct idxd_device *idxd =
12198c2ecf20Sopenharmony_ci		container_of(dev, struct idxd_device, conf_dev);
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_ci	return sprintf(buf, "%u\n", idxd->max_wqs);
12228c2ecf20Sopenharmony_ci}
12238c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(max_work_queues);
12248c2ecf20Sopenharmony_ci
12258c2ecf20Sopenharmony_cistatic ssize_t max_engines_show(struct device *dev,
12268c2ecf20Sopenharmony_ci				struct device_attribute *attr, char *buf)
12278c2ecf20Sopenharmony_ci{
12288c2ecf20Sopenharmony_ci	struct idxd_device *idxd =
12298c2ecf20Sopenharmony_ci		container_of(dev, struct idxd_device, conf_dev);
12308c2ecf20Sopenharmony_ci
12318c2ecf20Sopenharmony_ci	return sprintf(buf, "%u\n", idxd->max_engines);
12328c2ecf20Sopenharmony_ci}
12338c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(max_engines);
12348c2ecf20Sopenharmony_ci
12358c2ecf20Sopenharmony_cistatic ssize_t numa_node_show(struct device *dev,
12368c2ecf20Sopenharmony_ci			      struct device_attribute *attr, char *buf)
12378c2ecf20Sopenharmony_ci{
12388c2ecf20Sopenharmony_ci	struct idxd_device *idxd =
12398c2ecf20Sopenharmony_ci		container_of(dev, struct idxd_device, conf_dev);
12408c2ecf20Sopenharmony_ci
12418c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", dev_to_node(&idxd->pdev->dev));
12428c2ecf20Sopenharmony_ci}
12438c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(numa_node);
12448c2ecf20Sopenharmony_ci
12458c2ecf20Sopenharmony_cistatic ssize_t max_batch_size_show(struct device *dev,
12468c2ecf20Sopenharmony_ci				   struct device_attribute *attr, char *buf)
12478c2ecf20Sopenharmony_ci{
12488c2ecf20Sopenharmony_ci	struct idxd_device *idxd =
12498c2ecf20Sopenharmony_ci		container_of(dev, struct idxd_device, conf_dev);
12508c2ecf20Sopenharmony_ci
12518c2ecf20Sopenharmony_ci	return sprintf(buf, "%u\n", idxd->max_batch_size);
12528c2ecf20Sopenharmony_ci}
12538c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(max_batch_size);
12548c2ecf20Sopenharmony_ci
12558c2ecf20Sopenharmony_cistatic ssize_t max_transfer_size_show(struct device *dev,
12568c2ecf20Sopenharmony_ci				      struct device_attribute *attr,
12578c2ecf20Sopenharmony_ci				      char *buf)
12588c2ecf20Sopenharmony_ci{
12598c2ecf20Sopenharmony_ci	struct idxd_device *idxd =
12608c2ecf20Sopenharmony_ci		container_of(dev, struct idxd_device, conf_dev);
12618c2ecf20Sopenharmony_ci
12628c2ecf20Sopenharmony_ci	return sprintf(buf, "%llu\n", idxd->max_xfer_bytes);
12638c2ecf20Sopenharmony_ci}
12648c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(max_transfer_size);
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_cistatic ssize_t op_cap_show(struct device *dev,
12678c2ecf20Sopenharmony_ci			   struct device_attribute *attr, char *buf)
12688c2ecf20Sopenharmony_ci{
12698c2ecf20Sopenharmony_ci	struct idxd_device *idxd =
12708c2ecf20Sopenharmony_ci		container_of(dev, struct idxd_device, conf_dev);
12718c2ecf20Sopenharmony_ci	int i, rc = 0;
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++)
12748c2ecf20Sopenharmony_ci		rc += sysfs_emit_at(buf, rc, "%#llx ", idxd->hw.opcap.bits[i]);
12758c2ecf20Sopenharmony_ci
12768c2ecf20Sopenharmony_ci	rc--;
12778c2ecf20Sopenharmony_ci	rc += sysfs_emit_at(buf, rc, "\n");
12788c2ecf20Sopenharmony_ci	return rc;
12798c2ecf20Sopenharmony_ci}
12808c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(op_cap);
12818c2ecf20Sopenharmony_ci
12828c2ecf20Sopenharmony_cistatic ssize_t gen_cap_show(struct device *dev,
12838c2ecf20Sopenharmony_ci			    struct device_attribute *attr, char *buf)
12848c2ecf20Sopenharmony_ci{
12858c2ecf20Sopenharmony_ci	struct idxd_device *idxd =
12868c2ecf20Sopenharmony_ci		container_of(dev, struct idxd_device, conf_dev);
12878c2ecf20Sopenharmony_ci
12888c2ecf20Sopenharmony_ci	return sprintf(buf, "%#llx\n", idxd->hw.gen_cap.bits);
12898c2ecf20Sopenharmony_ci}
12908c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(gen_cap);
12918c2ecf20Sopenharmony_ci
12928c2ecf20Sopenharmony_cistatic ssize_t configurable_show(struct device *dev,
12938c2ecf20Sopenharmony_ci				 struct device_attribute *attr, char *buf)
12948c2ecf20Sopenharmony_ci{
12958c2ecf20Sopenharmony_ci	struct idxd_device *idxd =
12968c2ecf20Sopenharmony_ci		container_of(dev, struct idxd_device, conf_dev);
12978c2ecf20Sopenharmony_ci
12988c2ecf20Sopenharmony_ci	return sprintf(buf, "%u\n",
12998c2ecf20Sopenharmony_ci			test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags));
13008c2ecf20Sopenharmony_ci}
13018c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(configurable);
13028c2ecf20Sopenharmony_ci
13038c2ecf20Sopenharmony_cistatic ssize_t clients_show(struct device *dev,
13048c2ecf20Sopenharmony_ci			    struct device_attribute *attr, char *buf)
13058c2ecf20Sopenharmony_ci{
13068c2ecf20Sopenharmony_ci	struct idxd_device *idxd =
13078c2ecf20Sopenharmony_ci		container_of(dev, struct idxd_device, conf_dev);
13088c2ecf20Sopenharmony_ci	unsigned long flags;
13098c2ecf20Sopenharmony_ci	int count = 0, i;
13108c2ecf20Sopenharmony_ci
13118c2ecf20Sopenharmony_ci	spin_lock_irqsave(&idxd->dev_lock, flags);
13128c2ecf20Sopenharmony_ci	for (i = 0; i < idxd->max_wqs; i++) {
13138c2ecf20Sopenharmony_ci		struct idxd_wq *wq = &idxd->wqs[i];
13148c2ecf20Sopenharmony_ci
13158c2ecf20Sopenharmony_ci		count += wq->client_count;
13168c2ecf20Sopenharmony_ci	}
13178c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&idxd->dev_lock, flags);
13188c2ecf20Sopenharmony_ci
13198c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", count);
13208c2ecf20Sopenharmony_ci}
13218c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(clients);
13228c2ecf20Sopenharmony_ci
13238c2ecf20Sopenharmony_cistatic ssize_t state_show(struct device *dev,
13248c2ecf20Sopenharmony_ci			  struct device_attribute *attr, char *buf)
13258c2ecf20Sopenharmony_ci{
13268c2ecf20Sopenharmony_ci	struct idxd_device *idxd =
13278c2ecf20Sopenharmony_ci		container_of(dev, struct idxd_device, conf_dev);
13288c2ecf20Sopenharmony_ci
13298c2ecf20Sopenharmony_ci	switch (idxd->state) {
13308c2ecf20Sopenharmony_ci	case IDXD_DEV_DISABLED:
13318c2ecf20Sopenharmony_ci	case IDXD_DEV_CONF_READY:
13328c2ecf20Sopenharmony_ci		return sprintf(buf, "disabled\n");
13338c2ecf20Sopenharmony_ci	case IDXD_DEV_ENABLED:
13348c2ecf20Sopenharmony_ci		return sprintf(buf, "enabled\n");
13358c2ecf20Sopenharmony_ci	case IDXD_DEV_HALTED:
13368c2ecf20Sopenharmony_ci		return sprintf(buf, "halted\n");
13378c2ecf20Sopenharmony_ci	}
13388c2ecf20Sopenharmony_ci
13398c2ecf20Sopenharmony_ci	return sprintf(buf, "unknown\n");
13408c2ecf20Sopenharmony_ci}
13418c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(state);
13428c2ecf20Sopenharmony_ci
13438c2ecf20Sopenharmony_cistatic ssize_t errors_show(struct device *dev,
13448c2ecf20Sopenharmony_ci			   struct device_attribute *attr, char *buf)
13458c2ecf20Sopenharmony_ci{
13468c2ecf20Sopenharmony_ci	struct idxd_device *idxd =
13478c2ecf20Sopenharmony_ci		container_of(dev, struct idxd_device, conf_dev);
13488c2ecf20Sopenharmony_ci	int i, out = 0;
13498c2ecf20Sopenharmony_ci	unsigned long flags;
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_ci	spin_lock_irqsave(&idxd->dev_lock, flags);
13528c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++)
13538c2ecf20Sopenharmony_ci		out += sprintf(buf + out, "%#018llx ", idxd->sw_err.bits[i]);
13548c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&idxd->dev_lock, flags);
13558c2ecf20Sopenharmony_ci	out--;
13568c2ecf20Sopenharmony_ci	out += sprintf(buf + out, "\n");
13578c2ecf20Sopenharmony_ci	return out;
13588c2ecf20Sopenharmony_ci}
13598c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(errors);
13608c2ecf20Sopenharmony_ci
13618c2ecf20Sopenharmony_cistatic ssize_t max_tokens_show(struct device *dev,
13628c2ecf20Sopenharmony_ci			       struct device_attribute *attr, char *buf)
13638c2ecf20Sopenharmony_ci{
13648c2ecf20Sopenharmony_ci	struct idxd_device *idxd =
13658c2ecf20Sopenharmony_ci		container_of(dev, struct idxd_device, conf_dev);
13668c2ecf20Sopenharmony_ci
13678c2ecf20Sopenharmony_ci	return sprintf(buf, "%u\n", idxd->max_tokens);
13688c2ecf20Sopenharmony_ci}
13698c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(max_tokens);
13708c2ecf20Sopenharmony_ci
13718c2ecf20Sopenharmony_cistatic ssize_t token_limit_show(struct device *dev,
13728c2ecf20Sopenharmony_ci				struct device_attribute *attr, char *buf)
13738c2ecf20Sopenharmony_ci{
13748c2ecf20Sopenharmony_ci	struct idxd_device *idxd =
13758c2ecf20Sopenharmony_ci		container_of(dev, struct idxd_device, conf_dev);
13768c2ecf20Sopenharmony_ci
13778c2ecf20Sopenharmony_ci	return sprintf(buf, "%u\n", idxd->token_limit);
13788c2ecf20Sopenharmony_ci}
13798c2ecf20Sopenharmony_ci
13808c2ecf20Sopenharmony_cistatic ssize_t token_limit_store(struct device *dev,
13818c2ecf20Sopenharmony_ci				 struct device_attribute *attr,
13828c2ecf20Sopenharmony_ci				 const char *buf, size_t count)
13838c2ecf20Sopenharmony_ci{
13848c2ecf20Sopenharmony_ci	struct idxd_device *idxd =
13858c2ecf20Sopenharmony_ci		container_of(dev, struct idxd_device, conf_dev);
13868c2ecf20Sopenharmony_ci	unsigned long val;
13878c2ecf20Sopenharmony_ci	int rc;
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_ci	rc = kstrtoul(buf, 10, &val);
13908c2ecf20Sopenharmony_ci	if (rc < 0)
13918c2ecf20Sopenharmony_ci		return -EINVAL;
13928c2ecf20Sopenharmony_ci
13938c2ecf20Sopenharmony_ci	if (idxd->state == IDXD_DEV_ENABLED)
13948c2ecf20Sopenharmony_ci		return -EPERM;
13958c2ecf20Sopenharmony_ci
13968c2ecf20Sopenharmony_ci	if (!test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags))
13978c2ecf20Sopenharmony_ci		return -EPERM;
13988c2ecf20Sopenharmony_ci
13998c2ecf20Sopenharmony_ci	if (!idxd->hw.group_cap.token_limit)
14008c2ecf20Sopenharmony_ci		return -EPERM;
14018c2ecf20Sopenharmony_ci
14028c2ecf20Sopenharmony_ci	if (val > idxd->hw.group_cap.total_tokens)
14038c2ecf20Sopenharmony_ci		return -EINVAL;
14048c2ecf20Sopenharmony_ci
14058c2ecf20Sopenharmony_ci	idxd->token_limit = val;
14068c2ecf20Sopenharmony_ci	return count;
14078c2ecf20Sopenharmony_ci}
14088c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(token_limit);
14098c2ecf20Sopenharmony_ci
14108c2ecf20Sopenharmony_cistatic ssize_t cdev_major_show(struct device *dev,
14118c2ecf20Sopenharmony_ci			       struct device_attribute *attr, char *buf)
14128c2ecf20Sopenharmony_ci{
14138c2ecf20Sopenharmony_ci	struct idxd_device *idxd =
14148c2ecf20Sopenharmony_ci		container_of(dev, struct idxd_device, conf_dev);
14158c2ecf20Sopenharmony_ci
14168c2ecf20Sopenharmony_ci	return sprintf(buf, "%u\n", idxd->major);
14178c2ecf20Sopenharmony_ci}
14188c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(cdev_major);
14198c2ecf20Sopenharmony_ci
14208c2ecf20Sopenharmony_cistatic ssize_t cmd_status_show(struct device *dev,
14218c2ecf20Sopenharmony_ci			       struct device_attribute *attr, char *buf)
14228c2ecf20Sopenharmony_ci{
14238c2ecf20Sopenharmony_ci	struct idxd_device *idxd = container_of(dev, struct idxd_device, conf_dev);
14248c2ecf20Sopenharmony_ci
14258c2ecf20Sopenharmony_ci	return sprintf(buf, "%#x\n", idxd->cmd_status);
14268c2ecf20Sopenharmony_ci}
14278c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(cmd_status);
14288c2ecf20Sopenharmony_ci
14298c2ecf20Sopenharmony_cistatic struct attribute *idxd_device_attributes[] = {
14308c2ecf20Sopenharmony_ci	&dev_attr_version.attr,
14318c2ecf20Sopenharmony_ci	&dev_attr_max_groups.attr,
14328c2ecf20Sopenharmony_ci	&dev_attr_max_work_queues.attr,
14338c2ecf20Sopenharmony_ci	&dev_attr_max_work_queues_size.attr,
14348c2ecf20Sopenharmony_ci	&dev_attr_max_engines.attr,
14358c2ecf20Sopenharmony_ci	&dev_attr_numa_node.attr,
14368c2ecf20Sopenharmony_ci	&dev_attr_max_batch_size.attr,
14378c2ecf20Sopenharmony_ci	&dev_attr_max_transfer_size.attr,
14388c2ecf20Sopenharmony_ci	&dev_attr_op_cap.attr,
14398c2ecf20Sopenharmony_ci	&dev_attr_gen_cap.attr,
14408c2ecf20Sopenharmony_ci	&dev_attr_configurable.attr,
14418c2ecf20Sopenharmony_ci	&dev_attr_clients.attr,
14428c2ecf20Sopenharmony_ci	&dev_attr_state.attr,
14438c2ecf20Sopenharmony_ci	&dev_attr_errors.attr,
14448c2ecf20Sopenharmony_ci	&dev_attr_max_tokens.attr,
14458c2ecf20Sopenharmony_ci	&dev_attr_token_limit.attr,
14468c2ecf20Sopenharmony_ci	&dev_attr_cdev_major.attr,
14478c2ecf20Sopenharmony_ci	&dev_attr_cmd_status.attr,
14488c2ecf20Sopenharmony_ci	NULL,
14498c2ecf20Sopenharmony_ci};
14508c2ecf20Sopenharmony_ci
14518c2ecf20Sopenharmony_cistatic const struct attribute_group idxd_device_attribute_group = {
14528c2ecf20Sopenharmony_ci	.attrs = idxd_device_attributes,
14538c2ecf20Sopenharmony_ci};
14548c2ecf20Sopenharmony_ci
14558c2ecf20Sopenharmony_cistatic const struct attribute_group *idxd_attribute_groups[] = {
14568c2ecf20Sopenharmony_ci	&idxd_device_attribute_group,
14578c2ecf20Sopenharmony_ci	NULL,
14588c2ecf20Sopenharmony_ci};
14598c2ecf20Sopenharmony_ci
14608c2ecf20Sopenharmony_cistatic int idxd_setup_engine_sysfs(struct idxd_device *idxd)
14618c2ecf20Sopenharmony_ci{
14628c2ecf20Sopenharmony_ci	struct device *dev = &idxd->pdev->dev;
14638c2ecf20Sopenharmony_ci	int i, rc;
14648c2ecf20Sopenharmony_ci
14658c2ecf20Sopenharmony_ci	for (i = 0; i < idxd->max_engines; i++) {
14668c2ecf20Sopenharmony_ci		struct idxd_engine *engine = &idxd->engines[i];
14678c2ecf20Sopenharmony_ci
14688c2ecf20Sopenharmony_ci		engine->conf_dev.parent = &idxd->conf_dev;
14698c2ecf20Sopenharmony_ci		dev_set_name(&engine->conf_dev, "engine%d.%d",
14708c2ecf20Sopenharmony_ci			     idxd->id, engine->id);
14718c2ecf20Sopenharmony_ci		engine->conf_dev.bus = idxd_get_bus_type(idxd);
14728c2ecf20Sopenharmony_ci		engine->conf_dev.groups = idxd_engine_attribute_groups;
14738c2ecf20Sopenharmony_ci		engine->conf_dev.type = &idxd_engine_device_type;
14748c2ecf20Sopenharmony_ci		dev_dbg(dev, "Engine device register: %s\n",
14758c2ecf20Sopenharmony_ci			dev_name(&engine->conf_dev));
14768c2ecf20Sopenharmony_ci		rc = device_register(&engine->conf_dev);
14778c2ecf20Sopenharmony_ci		if (rc < 0) {
14788c2ecf20Sopenharmony_ci			put_device(&engine->conf_dev);
14798c2ecf20Sopenharmony_ci			goto cleanup;
14808c2ecf20Sopenharmony_ci		}
14818c2ecf20Sopenharmony_ci	}
14828c2ecf20Sopenharmony_ci
14838c2ecf20Sopenharmony_ci	return 0;
14848c2ecf20Sopenharmony_ci
14858c2ecf20Sopenharmony_cicleanup:
14868c2ecf20Sopenharmony_ci	while (i--) {
14878c2ecf20Sopenharmony_ci		struct idxd_engine *engine = &idxd->engines[i];
14888c2ecf20Sopenharmony_ci
14898c2ecf20Sopenharmony_ci		device_unregister(&engine->conf_dev);
14908c2ecf20Sopenharmony_ci	}
14918c2ecf20Sopenharmony_ci	return rc;
14928c2ecf20Sopenharmony_ci}
14938c2ecf20Sopenharmony_ci
14948c2ecf20Sopenharmony_cistatic int idxd_setup_group_sysfs(struct idxd_device *idxd)
14958c2ecf20Sopenharmony_ci{
14968c2ecf20Sopenharmony_ci	struct device *dev = &idxd->pdev->dev;
14978c2ecf20Sopenharmony_ci	int i, rc;
14988c2ecf20Sopenharmony_ci
14998c2ecf20Sopenharmony_ci	for (i = 0; i < idxd->max_groups; i++) {
15008c2ecf20Sopenharmony_ci		struct idxd_group *group = &idxd->groups[i];
15018c2ecf20Sopenharmony_ci
15028c2ecf20Sopenharmony_ci		group->conf_dev.parent = &idxd->conf_dev;
15038c2ecf20Sopenharmony_ci		dev_set_name(&group->conf_dev, "group%d.%d",
15048c2ecf20Sopenharmony_ci			     idxd->id, group->id);
15058c2ecf20Sopenharmony_ci		group->conf_dev.bus = idxd_get_bus_type(idxd);
15068c2ecf20Sopenharmony_ci		group->conf_dev.groups = idxd_group_attribute_groups;
15078c2ecf20Sopenharmony_ci		group->conf_dev.type = &idxd_group_device_type;
15088c2ecf20Sopenharmony_ci		dev_dbg(dev, "Group device register: %s\n",
15098c2ecf20Sopenharmony_ci			dev_name(&group->conf_dev));
15108c2ecf20Sopenharmony_ci		rc = device_register(&group->conf_dev);
15118c2ecf20Sopenharmony_ci		if (rc < 0) {
15128c2ecf20Sopenharmony_ci			put_device(&group->conf_dev);
15138c2ecf20Sopenharmony_ci			goto cleanup;
15148c2ecf20Sopenharmony_ci		}
15158c2ecf20Sopenharmony_ci	}
15168c2ecf20Sopenharmony_ci
15178c2ecf20Sopenharmony_ci	return 0;
15188c2ecf20Sopenharmony_ci
15198c2ecf20Sopenharmony_cicleanup:
15208c2ecf20Sopenharmony_ci	while (i--) {
15218c2ecf20Sopenharmony_ci		struct idxd_group *group = &idxd->groups[i];
15228c2ecf20Sopenharmony_ci
15238c2ecf20Sopenharmony_ci		device_unregister(&group->conf_dev);
15248c2ecf20Sopenharmony_ci	}
15258c2ecf20Sopenharmony_ci	return rc;
15268c2ecf20Sopenharmony_ci}
15278c2ecf20Sopenharmony_ci
15288c2ecf20Sopenharmony_cistatic int idxd_setup_wq_sysfs(struct idxd_device *idxd)
15298c2ecf20Sopenharmony_ci{
15308c2ecf20Sopenharmony_ci	struct device *dev = &idxd->pdev->dev;
15318c2ecf20Sopenharmony_ci	int i, rc;
15328c2ecf20Sopenharmony_ci
15338c2ecf20Sopenharmony_ci	for (i = 0; i < idxd->max_wqs; i++) {
15348c2ecf20Sopenharmony_ci		struct idxd_wq *wq = &idxd->wqs[i];
15358c2ecf20Sopenharmony_ci
15368c2ecf20Sopenharmony_ci		wq->conf_dev.parent = &idxd->conf_dev;
15378c2ecf20Sopenharmony_ci		dev_set_name(&wq->conf_dev, "wq%d.%d", idxd->id, wq->id);
15388c2ecf20Sopenharmony_ci		wq->conf_dev.bus = idxd_get_bus_type(idxd);
15398c2ecf20Sopenharmony_ci		wq->conf_dev.groups = idxd_wq_attribute_groups;
15408c2ecf20Sopenharmony_ci		wq->conf_dev.type = &idxd_wq_device_type;
15418c2ecf20Sopenharmony_ci		dev_dbg(dev, "WQ device register: %s\n",
15428c2ecf20Sopenharmony_ci			dev_name(&wq->conf_dev));
15438c2ecf20Sopenharmony_ci		rc = device_register(&wq->conf_dev);
15448c2ecf20Sopenharmony_ci		if (rc < 0) {
15458c2ecf20Sopenharmony_ci			put_device(&wq->conf_dev);
15468c2ecf20Sopenharmony_ci			goto cleanup;
15478c2ecf20Sopenharmony_ci		}
15488c2ecf20Sopenharmony_ci	}
15498c2ecf20Sopenharmony_ci
15508c2ecf20Sopenharmony_ci	return 0;
15518c2ecf20Sopenharmony_ci
15528c2ecf20Sopenharmony_cicleanup:
15538c2ecf20Sopenharmony_ci	while (i--) {
15548c2ecf20Sopenharmony_ci		struct idxd_wq *wq = &idxd->wqs[i];
15558c2ecf20Sopenharmony_ci
15568c2ecf20Sopenharmony_ci		device_unregister(&wq->conf_dev);
15578c2ecf20Sopenharmony_ci	}
15588c2ecf20Sopenharmony_ci	return rc;
15598c2ecf20Sopenharmony_ci}
15608c2ecf20Sopenharmony_ci
15618c2ecf20Sopenharmony_cistatic int idxd_setup_device_sysfs(struct idxd_device *idxd)
15628c2ecf20Sopenharmony_ci{
15638c2ecf20Sopenharmony_ci	struct device *dev = &idxd->pdev->dev;
15648c2ecf20Sopenharmony_ci	int rc;
15658c2ecf20Sopenharmony_ci	char devname[IDXD_NAME_SIZE];
15668c2ecf20Sopenharmony_ci
15678c2ecf20Sopenharmony_ci	sprintf(devname, "%s%d", idxd_get_dev_name(idxd), idxd->id);
15688c2ecf20Sopenharmony_ci	idxd->conf_dev.parent = dev;
15698c2ecf20Sopenharmony_ci	dev_set_name(&idxd->conf_dev, "%s", devname);
15708c2ecf20Sopenharmony_ci	idxd->conf_dev.bus = idxd_get_bus_type(idxd);
15718c2ecf20Sopenharmony_ci	idxd->conf_dev.groups = idxd_attribute_groups;
15728c2ecf20Sopenharmony_ci	idxd->conf_dev.type = idxd_get_device_type(idxd);
15738c2ecf20Sopenharmony_ci
15748c2ecf20Sopenharmony_ci	dev_dbg(dev, "IDXD device register: %s\n", dev_name(&idxd->conf_dev));
15758c2ecf20Sopenharmony_ci	rc = device_register(&idxd->conf_dev);
15768c2ecf20Sopenharmony_ci	if (rc < 0) {
15778c2ecf20Sopenharmony_ci		put_device(&idxd->conf_dev);
15788c2ecf20Sopenharmony_ci		return rc;
15798c2ecf20Sopenharmony_ci	}
15808c2ecf20Sopenharmony_ci
15818c2ecf20Sopenharmony_ci	return 0;
15828c2ecf20Sopenharmony_ci}
15838c2ecf20Sopenharmony_ci
15848c2ecf20Sopenharmony_ciint idxd_setup_sysfs(struct idxd_device *idxd)
15858c2ecf20Sopenharmony_ci{
15868c2ecf20Sopenharmony_ci	struct device *dev = &idxd->pdev->dev;
15878c2ecf20Sopenharmony_ci	int rc;
15888c2ecf20Sopenharmony_ci
15898c2ecf20Sopenharmony_ci	rc = idxd_setup_device_sysfs(idxd);
15908c2ecf20Sopenharmony_ci	if (rc < 0) {
15918c2ecf20Sopenharmony_ci		dev_dbg(dev, "Device sysfs registering failed: %d\n", rc);
15928c2ecf20Sopenharmony_ci		return rc;
15938c2ecf20Sopenharmony_ci	}
15948c2ecf20Sopenharmony_ci
15958c2ecf20Sopenharmony_ci	rc = idxd_setup_wq_sysfs(idxd);
15968c2ecf20Sopenharmony_ci	if (rc < 0) {
15978c2ecf20Sopenharmony_ci		/* unregister conf dev */
15988c2ecf20Sopenharmony_ci		dev_dbg(dev, "Work Queue sysfs registering failed: %d\n", rc);
15998c2ecf20Sopenharmony_ci		return rc;
16008c2ecf20Sopenharmony_ci	}
16018c2ecf20Sopenharmony_ci
16028c2ecf20Sopenharmony_ci	rc = idxd_setup_group_sysfs(idxd);
16038c2ecf20Sopenharmony_ci	if (rc < 0) {
16048c2ecf20Sopenharmony_ci		/* unregister conf dev */
16058c2ecf20Sopenharmony_ci		dev_dbg(dev, "Group sysfs registering failed: %d\n", rc);
16068c2ecf20Sopenharmony_ci		return rc;
16078c2ecf20Sopenharmony_ci	}
16088c2ecf20Sopenharmony_ci
16098c2ecf20Sopenharmony_ci	rc = idxd_setup_engine_sysfs(idxd);
16108c2ecf20Sopenharmony_ci	if (rc < 0) {
16118c2ecf20Sopenharmony_ci		/* unregister conf dev */
16128c2ecf20Sopenharmony_ci		dev_dbg(dev, "Engine sysfs registering failed: %d\n", rc);
16138c2ecf20Sopenharmony_ci		return rc;
16148c2ecf20Sopenharmony_ci	}
16158c2ecf20Sopenharmony_ci
16168c2ecf20Sopenharmony_ci	return 0;
16178c2ecf20Sopenharmony_ci}
16188c2ecf20Sopenharmony_ci
16198c2ecf20Sopenharmony_civoid idxd_cleanup_sysfs(struct idxd_device *idxd)
16208c2ecf20Sopenharmony_ci{
16218c2ecf20Sopenharmony_ci	int i;
16228c2ecf20Sopenharmony_ci
16238c2ecf20Sopenharmony_ci	for (i = 0; i < idxd->max_wqs; i++) {
16248c2ecf20Sopenharmony_ci		struct idxd_wq *wq = &idxd->wqs[i];
16258c2ecf20Sopenharmony_ci
16268c2ecf20Sopenharmony_ci		device_unregister(&wq->conf_dev);
16278c2ecf20Sopenharmony_ci	}
16288c2ecf20Sopenharmony_ci
16298c2ecf20Sopenharmony_ci	for (i = 0; i < idxd->max_engines; i++) {
16308c2ecf20Sopenharmony_ci		struct idxd_engine *engine = &idxd->engines[i];
16318c2ecf20Sopenharmony_ci
16328c2ecf20Sopenharmony_ci		device_unregister(&engine->conf_dev);
16338c2ecf20Sopenharmony_ci	}
16348c2ecf20Sopenharmony_ci
16358c2ecf20Sopenharmony_ci	for (i = 0; i < idxd->max_groups; i++) {
16368c2ecf20Sopenharmony_ci		struct idxd_group *group = &idxd->groups[i];
16378c2ecf20Sopenharmony_ci
16388c2ecf20Sopenharmony_ci		device_unregister(&group->conf_dev);
16398c2ecf20Sopenharmony_ci	}
16408c2ecf20Sopenharmony_ci
16418c2ecf20Sopenharmony_ci	device_unregister(&idxd->conf_dev);
16428c2ecf20Sopenharmony_ci}
16438c2ecf20Sopenharmony_ci
16448c2ecf20Sopenharmony_ciint idxd_register_bus_type(void)
16458c2ecf20Sopenharmony_ci{
16468c2ecf20Sopenharmony_ci	int i, rc;
16478c2ecf20Sopenharmony_ci
16488c2ecf20Sopenharmony_ci	for (i = 0; i < IDXD_TYPE_MAX; i++) {
16498c2ecf20Sopenharmony_ci		rc = bus_register(idxd_bus_types[i]);
16508c2ecf20Sopenharmony_ci		if (rc < 0)
16518c2ecf20Sopenharmony_ci			goto bus_err;
16528c2ecf20Sopenharmony_ci	}
16538c2ecf20Sopenharmony_ci
16548c2ecf20Sopenharmony_ci	return 0;
16558c2ecf20Sopenharmony_ci
16568c2ecf20Sopenharmony_cibus_err:
16578c2ecf20Sopenharmony_ci	while (--i >= 0)
16588c2ecf20Sopenharmony_ci		bus_unregister(idxd_bus_types[i]);
16598c2ecf20Sopenharmony_ci	return rc;
16608c2ecf20Sopenharmony_ci}
16618c2ecf20Sopenharmony_ci
16628c2ecf20Sopenharmony_civoid idxd_unregister_bus_type(void)
16638c2ecf20Sopenharmony_ci{
16648c2ecf20Sopenharmony_ci	int i;
16658c2ecf20Sopenharmony_ci
16668c2ecf20Sopenharmony_ci	for (i = 0; i < IDXD_TYPE_MAX; i++)
16678c2ecf20Sopenharmony_ci		bus_unregister(idxd_bus_types[i]);
16688c2ecf20Sopenharmony_ci}
1669