18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci/* Copyright(c) 2019 Intel Corporation. All rights rsvd. */ 38c2ecf20Sopenharmony_ci#ifndef _IDXD_H_ 48c2ecf20Sopenharmony_ci#define _IDXD_H_ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/sbitmap.h> 78c2ecf20Sopenharmony_ci#include <linux/dmaengine.h> 88c2ecf20Sopenharmony_ci#include <linux/percpu-rwsem.h> 98c2ecf20Sopenharmony_ci#include <linux/wait.h> 108c2ecf20Sopenharmony_ci#include <linux/cdev.h> 118c2ecf20Sopenharmony_ci#include "registers.h" 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#define IDXD_DRIVER_VERSION "1.00" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ciextern struct kmem_cache *idxd_desc_pool; 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_cistruct idxd_device; 188c2ecf20Sopenharmony_cistruct idxd_wq; 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define IDXD_REG_TIMEOUT 50 218c2ecf20Sopenharmony_ci#define IDXD_DRAIN_TIMEOUT 5000 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cienum idxd_type { 248c2ecf20Sopenharmony_ci IDXD_TYPE_UNKNOWN = -1, 258c2ecf20Sopenharmony_ci IDXD_TYPE_DSA = 0, 268c2ecf20Sopenharmony_ci IDXD_TYPE_MAX 278c2ecf20Sopenharmony_ci}; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define IDXD_NAME_SIZE 128 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistruct idxd_device_driver { 328c2ecf20Sopenharmony_ci struct device_driver drv; 338c2ecf20Sopenharmony_ci}; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistruct idxd_irq_entry { 368c2ecf20Sopenharmony_ci struct idxd_device *idxd; 378c2ecf20Sopenharmony_ci int id; 388c2ecf20Sopenharmony_ci struct llist_head pending_llist; 398c2ecf20Sopenharmony_ci struct list_head work_list; 408c2ecf20Sopenharmony_ci}; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistruct idxd_group { 438c2ecf20Sopenharmony_ci struct device conf_dev; 448c2ecf20Sopenharmony_ci struct idxd_device *idxd; 458c2ecf20Sopenharmony_ci struct grpcfg grpcfg; 468c2ecf20Sopenharmony_ci int id; 478c2ecf20Sopenharmony_ci int num_engines; 488c2ecf20Sopenharmony_ci int num_wqs; 498c2ecf20Sopenharmony_ci bool use_token_limit; 508c2ecf20Sopenharmony_ci u8 tokens_allowed; 518c2ecf20Sopenharmony_ci u8 tokens_reserved; 528c2ecf20Sopenharmony_ci int tc_a; 538c2ecf20Sopenharmony_ci int tc_b; 548c2ecf20Sopenharmony_ci}; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#define IDXD_MAX_PRIORITY 0xf 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cienum idxd_wq_state { 598c2ecf20Sopenharmony_ci IDXD_WQ_DISABLED = 0, 608c2ecf20Sopenharmony_ci IDXD_WQ_ENABLED, 618c2ecf20Sopenharmony_ci}; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cienum idxd_wq_flag { 648c2ecf20Sopenharmony_ci WQ_FLAG_DEDICATED = 0, 658c2ecf20Sopenharmony_ci}; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cienum idxd_wq_type { 688c2ecf20Sopenharmony_ci IDXD_WQT_NONE = 0, 698c2ecf20Sopenharmony_ci IDXD_WQT_KERNEL, 708c2ecf20Sopenharmony_ci IDXD_WQT_USER, 718c2ecf20Sopenharmony_ci}; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistruct idxd_cdev { 748c2ecf20Sopenharmony_ci struct idxd_wq *wq; 758c2ecf20Sopenharmony_ci struct cdev cdev; 768c2ecf20Sopenharmony_ci struct device dev; 778c2ecf20Sopenharmony_ci int minor; 788c2ecf20Sopenharmony_ci}; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci#define IDXD_ALLOCATED_BATCH_SIZE 128U 818c2ecf20Sopenharmony_ci#define WQ_NAME_SIZE 1024 828c2ecf20Sopenharmony_ci#define WQ_TYPE_SIZE 10 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cienum idxd_op_type { 858c2ecf20Sopenharmony_ci IDXD_OP_BLOCK = 0, 868c2ecf20Sopenharmony_ci IDXD_OP_NONBLOCK = 1, 878c2ecf20Sopenharmony_ci}; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cienum idxd_complete_type { 908c2ecf20Sopenharmony_ci IDXD_COMPLETE_NORMAL = 0, 918c2ecf20Sopenharmony_ci IDXD_COMPLETE_ABORT, 928c2ecf20Sopenharmony_ci}; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistruct idxd_dma_chan { 958c2ecf20Sopenharmony_ci struct dma_chan chan; 968c2ecf20Sopenharmony_ci struct idxd_wq *wq; 978c2ecf20Sopenharmony_ci}; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistruct idxd_wq { 1008c2ecf20Sopenharmony_ci void __iomem *dportal; 1018c2ecf20Sopenharmony_ci struct device conf_dev; 1028c2ecf20Sopenharmony_ci struct idxd_cdev *idxd_cdev; 1038c2ecf20Sopenharmony_ci struct wait_queue_head err_queue; 1048c2ecf20Sopenharmony_ci struct idxd_device *idxd; 1058c2ecf20Sopenharmony_ci int id; 1068c2ecf20Sopenharmony_ci enum idxd_wq_type type; 1078c2ecf20Sopenharmony_ci struct idxd_group *group; 1088c2ecf20Sopenharmony_ci int client_count; 1098c2ecf20Sopenharmony_ci struct mutex wq_lock; /* mutex for workqueue */ 1108c2ecf20Sopenharmony_ci u32 size; 1118c2ecf20Sopenharmony_ci u32 threshold; 1128c2ecf20Sopenharmony_ci u32 priority; 1138c2ecf20Sopenharmony_ci enum idxd_wq_state state; 1148c2ecf20Sopenharmony_ci unsigned long flags; 1158c2ecf20Sopenharmony_ci union wqcfg *wqcfg; 1168c2ecf20Sopenharmony_ci u32 vec_ptr; /* interrupt steering */ 1178c2ecf20Sopenharmony_ci struct dsa_hw_desc **hw_descs; 1188c2ecf20Sopenharmony_ci int num_descs; 1198c2ecf20Sopenharmony_ci struct dsa_completion_record *compls; 1208c2ecf20Sopenharmony_ci dma_addr_t compls_addr; 1218c2ecf20Sopenharmony_ci int compls_size; 1228c2ecf20Sopenharmony_ci struct idxd_desc **descs; 1238c2ecf20Sopenharmony_ci struct sbitmap_queue sbq; 1248c2ecf20Sopenharmony_ci struct idxd_dma_chan *idxd_chan; 1258c2ecf20Sopenharmony_ci char name[WQ_NAME_SIZE + 1]; 1268c2ecf20Sopenharmony_ci u64 max_xfer_bytes; 1278c2ecf20Sopenharmony_ci u32 max_batch_size; 1288c2ecf20Sopenharmony_ci}; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistruct idxd_engine { 1318c2ecf20Sopenharmony_ci struct device conf_dev; 1328c2ecf20Sopenharmony_ci int id; 1338c2ecf20Sopenharmony_ci struct idxd_group *group; 1348c2ecf20Sopenharmony_ci struct idxd_device *idxd; 1358c2ecf20Sopenharmony_ci}; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci/* shadow registers */ 1388c2ecf20Sopenharmony_cistruct idxd_hw { 1398c2ecf20Sopenharmony_ci u32 version; 1408c2ecf20Sopenharmony_ci union gen_cap_reg gen_cap; 1418c2ecf20Sopenharmony_ci union wq_cap_reg wq_cap; 1428c2ecf20Sopenharmony_ci union group_cap_reg group_cap; 1438c2ecf20Sopenharmony_ci union engine_cap_reg engine_cap; 1448c2ecf20Sopenharmony_ci struct opcap opcap; 1458c2ecf20Sopenharmony_ci}; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cienum idxd_device_state { 1488c2ecf20Sopenharmony_ci IDXD_DEV_HALTED = -1, 1498c2ecf20Sopenharmony_ci IDXD_DEV_DISABLED = 0, 1508c2ecf20Sopenharmony_ci IDXD_DEV_CONF_READY, 1518c2ecf20Sopenharmony_ci IDXD_DEV_ENABLED, 1528c2ecf20Sopenharmony_ci}; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_cienum idxd_device_flag { 1558c2ecf20Sopenharmony_ci IDXD_FLAG_CONFIGURABLE = 0, 1568c2ecf20Sopenharmony_ci IDXD_FLAG_CMD_RUNNING, 1578c2ecf20Sopenharmony_ci}; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_cistruct idxd_dma_dev { 1608c2ecf20Sopenharmony_ci struct idxd_device *idxd; 1618c2ecf20Sopenharmony_ci struct dma_device dma; 1628c2ecf20Sopenharmony_ci}; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistruct idxd_device { 1658c2ecf20Sopenharmony_ci enum idxd_type type; 1668c2ecf20Sopenharmony_ci struct device conf_dev; 1678c2ecf20Sopenharmony_ci struct list_head list; 1688c2ecf20Sopenharmony_ci struct idxd_hw hw; 1698c2ecf20Sopenharmony_ci enum idxd_device_state state; 1708c2ecf20Sopenharmony_ci unsigned long flags; 1718c2ecf20Sopenharmony_ci int id; 1728c2ecf20Sopenharmony_ci int major; 1738c2ecf20Sopenharmony_ci u8 cmd_status; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci struct pci_dev *pdev; 1768c2ecf20Sopenharmony_ci void __iomem *reg_base; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci spinlock_t dev_lock; /* spinlock for device */ 1798c2ecf20Sopenharmony_ci struct completion *cmd_done; 1808c2ecf20Sopenharmony_ci struct idxd_group *groups; 1818c2ecf20Sopenharmony_ci struct idxd_wq *wqs; 1828c2ecf20Sopenharmony_ci struct idxd_engine *engines; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci int num_groups; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci u32 msix_perm_offset; 1878c2ecf20Sopenharmony_ci u32 wqcfg_offset; 1888c2ecf20Sopenharmony_ci u32 grpcfg_offset; 1898c2ecf20Sopenharmony_ci u32 perfmon_offset; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci u64 max_xfer_bytes; 1928c2ecf20Sopenharmony_ci u32 max_batch_size; 1938c2ecf20Sopenharmony_ci int max_groups; 1948c2ecf20Sopenharmony_ci int max_engines; 1958c2ecf20Sopenharmony_ci int max_tokens; 1968c2ecf20Sopenharmony_ci int max_wqs; 1978c2ecf20Sopenharmony_ci int max_wq_size; 1988c2ecf20Sopenharmony_ci int token_limit; 1998c2ecf20Sopenharmony_ci int nr_tokens; /* non-reserved tokens */ 2008c2ecf20Sopenharmony_ci unsigned int wqcfg_size; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci union sw_err_reg sw_err; 2038c2ecf20Sopenharmony_ci wait_queue_head_t cmd_waitq; 2048c2ecf20Sopenharmony_ci struct msix_entry *msix_entries; 2058c2ecf20Sopenharmony_ci int num_wq_irqs; 2068c2ecf20Sopenharmony_ci struct idxd_irq_entry *irq_entries; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci struct idxd_dma_dev *idxd_dma; 2098c2ecf20Sopenharmony_ci struct workqueue_struct *wq; 2108c2ecf20Sopenharmony_ci struct work_struct work; 2118c2ecf20Sopenharmony_ci}; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci/* IDXD software descriptor */ 2148c2ecf20Sopenharmony_cistruct idxd_desc { 2158c2ecf20Sopenharmony_ci struct dsa_hw_desc *hw; 2168c2ecf20Sopenharmony_ci dma_addr_t desc_dma; 2178c2ecf20Sopenharmony_ci struct dsa_completion_record *completion; 2188c2ecf20Sopenharmony_ci dma_addr_t compl_dma; 2198c2ecf20Sopenharmony_ci struct dma_async_tx_descriptor txd; 2208c2ecf20Sopenharmony_ci struct llist_node llnode; 2218c2ecf20Sopenharmony_ci struct list_head list; 2228c2ecf20Sopenharmony_ci int id; 2238c2ecf20Sopenharmony_ci int cpu; 2248c2ecf20Sopenharmony_ci struct idxd_wq *wq; 2258c2ecf20Sopenharmony_ci}; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci#define confdev_to_idxd(dev) container_of(dev, struct idxd_device, conf_dev) 2288c2ecf20Sopenharmony_ci#define confdev_to_wq(dev) container_of(dev, struct idxd_wq, conf_dev) 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ciextern struct bus_type dsa_bus_type; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cistatic inline bool wq_dedicated(struct idxd_wq *wq) 2338c2ecf20Sopenharmony_ci{ 2348c2ecf20Sopenharmony_ci return test_bit(WQ_FLAG_DEDICATED, &wq->flags); 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cienum idxd_portal_prot { 2388c2ecf20Sopenharmony_ci IDXD_PORTAL_UNLIMITED = 0, 2398c2ecf20Sopenharmony_ci IDXD_PORTAL_LIMITED, 2408c2ecf20Sopenharmony_ci}; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistatic inline int idxd_get_wq_portal_offset(enum idxd_portal_prot prot) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci return prot * 0x1000; 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistatic inline int idxd_get_wq_portal_full_offset(int wq_id, 2488c2ecf20Sopenharmony_ci enum idxd_portal_prot prot) 2498c2ecf20Sopenharmony_ci{ 2508c2ecf20Sopenharmony_ci return ((wq_id * 4) << PAGE_SHIFT) + idxd_get_wq_portal_offset(prot); 2518c2ecf20Sopenharmony_ci} 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_cistatic inline void idxd_set_type(struct idxd_device *idxd) 2548c2ecf20Sopenharmony_ci{ 2558c2ecf20Sopenharmony_ci struct pci_dev *pdev = idxd->pdev; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci if (pdev->device == PCI_DEVICE_ID_INTEL_DSA_SPR0) 2588c2ecf20Sopenharmony_ci idxd->type = IDXD_TYPE_DSA; 2598c2ecf20Sopenharmony_ci else 2608c2ecf20Sopenharmony_ci idxd->type = IDXD_TYPE_UNKNOWN; 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_cistatic inline void idxd_wq_get(struct idxd_wq *wq) 2648c2ecf20Sopenharmony_ci{ 2658c2ecf20Sopenharmony_ci wq->client_count++; 2668c2ecf20Sopenharmony_ci} 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_cistatic inline void idxd_wq_put(struct idxd_wq *wq) 2698c2ecf20Sopenharmony_ci{ 2708c2ecf20Sopenharmony_ci wq->client_count--; 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_cistatic inline int idxd_wq_refcount(struct idxd_wq *wq) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci return wq->client_count; 2768c2ecf20Sopenharmony_ci}; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ciconst char *idxd_get_dev_name(struct idxd_device *idxd); 2798c2ecf20Sopenharmony_ciint idxd_register_bus_type(void); 2808c2ecf20Sopenharmony_civoid idxd_unregister_bus_type(void); 2818c2ecf20Sopenharmony_ciint idxd_setup_sysfs(struct idxd_device *idxd); 2828c2ecf20Sopenharmony_civoid idxd_cleanup_sysfs(struct idxd_device *idxd); 2838c2ecf20Sopenharmony_ciint idxd_register_driver(void); 2848c2ecf20Sopenharmony_civoid idxd_unregister_driver(void); 2858c2ecf20Sopenharmony_cistruct bus_type *idxd_get_bus_type(struct idxd_device *idxd); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci/* device interrupt control */ 2888c2ecf20Sopenharmony_ciirqreturn_t idxd_irq_handler(int vec, void *data); 2898c2ecf20Sopenharmony_ciirqreturn_t idxd_misc_thread(int vec, void *data); 2908c2ecf20Sopenharmony_ciirqreturn_t idxd_wq_thread(int irq, void *data); 2918c2ecf20Sopenharmony_civoid idxd_mask_error_interrupts(struct idxd_device *idxd); 2928c2ecf20Sopenharmony_civoid idxd_unmask_error_interrupts(struct idxd_device *idxd); 2938c2ecf20Sopenharmony_civoid idxd_mask_msix_vectors(struct idxd_device *idxd); 2948c2ecf20Sopenharmony_civoid idxd_mask_msix_vector(struct idxd_device *idxd, int vec_id); 2958c2ecf20Sopenharmony_civoid idxd_unmask_msix_vector(struct idxd_device *idxd, int vec_id); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci/* device control */ 2988c2ecf20Sopenharmony_ciint idxd_device_init_reset(struct idxd_device *idxd); 2998c2ecf20Sopenharmony_ciint idxd_device_enable(struct idxd_device *idxd); 3008c2ecf20Sopenharmony_ciint idxd_device_disable(struct idxd_device *idxd); 3018c2ecf20Sopenharmony_civoid idxd_device_reset(struct idxd_device *idxd); 3028c2ecf20Sopenharmony_civoid idxd_device_cleanup(struct idxd_device *idxd); 3038c2ecf20Sopenharmony_ciint idxd_device_config(struct idxd_device *idxd); 3048c2ecf20Sopenharmony_civoid idxd_device_wqs_clear_state(struct idxd_device *idxd); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci/* work queue control */ 3078c2ecf20Sopenharmony_ciint idxd_wq_alloc_resources(struct idxd_wq *wq); 3088c2ecf20Sopenharmony_civoid idxd_wq_free_resources(struct idxd_wq *wq); 3098c2ecf20Sopenharmony_ciint idxd_wq_enable(struct idxd_wq *wq); 3108c2ecf20Sopenharmony_ciint idxd_wq_disable(struct idxd_wq *wq); 3118c2ecf20Sopenharmony_civoid idxd_wq_drain(struct idxd_wq *wq); 3128c2ecf20Sopenharmony_civoid idxd_wq_reset(struct idxd_wq *wq); 3138c2ecf20Sopenharmony_ciint idxd_wq_map_portal(struct idxd_wq *wq); 3148c2ecf20Sopenharmony_civoid idxd_wq_unmap_portal(struct idxd_wq *wq); 3158c2ecf20Sopenharmony_civoid idxd_wq_disable_cleanup(struct idxd_wq *wq); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci/* submission */ 3188c2ecf20Sopenharmony_ciint idxd_submit_desc(struct idxd_wq *wq, struct idxd_desc *desc); 3198c2ecf20Sopenharmony_cistruct idxd_desc *idxd_alloc_desc(struct idxd_wq *wq, enum idxd_op_type optype); 3208c2ecf20Sopenharmony_civoid idxd_free_desc(struct idxd_wq *wq, struct idxd_desc *desc); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci/* dmaengine */ 3238c2ecf20Sopenharmony_ciint idxd_register_dma_device(struct idxd_device *idxd); 3248c2ecf20Sopenharmony_civoid idxd_unregister_dma_device(struct idxd_device *idxd); 3258c2ecf20Sopenharmony_ciint idxd_register_dma_channel(struct idxd_wq *wq); 3268c2ecf20Sopenharmony_civoid idxd_unregister_dma_channel(struct idxd_wq *wq); 3278c2ecf20Sopenharmony_civoid idxd_parse_completion_status(u8 status, enum dmaengine_tx_result *res); 3288c2ecf20Sopenharmony_civoid idxd_dma_complete_txd(struct idxd_desc *desc, 3298c2ecf20Sopenharmony_ci enum idxd_complete_type comp_type); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci/* cdev */ 3328c2ecf20Sopenharmony_ciint idxd_cdev_register(void); 3338c2ecf20Sopenharmony_civoid idxd_cdev_remove(void); 3348c2ecf20Sopenharmony_ciint idxd_cdev_get_major(struct idxd_device *idxd); 3358c2ecf20Sopenharmony_ciint idxd_wq_add_cdev(struct idxd_wq *wq); 3368c2ecf20Sopenharmony_civoid idxd_wq_del_cdev(struct idxd_wq *wq); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci#endif 339