18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Driver Header File for FPGA Device Feature List (DFL) Support 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2017-2018 Intel Corporation, Inc. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Authors: 88c2ecf20Sopenharmony_ci * Kang Luwei <luwei.kang@intel.com> 98c2ecf20Sopenharmony_ci * Zhang Yi <yi.z.zhang@intel.com> 108c2ecf20Sopenharmony_ci * Wu Hao <hao.wu@intel.com> 118c2ecf20Sopenharmony_ci * Xiao Guangrong <guangrong.xiao@linux.intel.com> 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#ifndef __FPGA_DFL_H 158c2ecf20Sopenharmony_ci#define __FPGA_DFL_H 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <linux/bitfield.h> 188c2ecf20Sopenharmony_ci#include <linux/cdev.h> 198c2ecf20Sopenharmony_ci#include <linux/delay.h> 208c2ecf20Sopenharmony_ci#include <linux/eventfd.h> 218c2ecf20Sopenharmony_ci#include <linux/fs.h> 228c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 238c2ecf20Sopenharmony_ci#include <linux/iopoll.h> 248c2ecf20Sopenharmony_ci#include <linux/io-64-nonatomic-lo-hi.h> 258c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 268c2ecf20Sopenharmony_ci#include <linux/slab.h> 278c2ecf20Sopenharmony_ci#include <linux/uuid.h> 288c2ecf20Sopenharmony_ci#include <linux/fpga/fpga-region.h> 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci/* maximum supported number of ports */ 318c2ecf20Sopenharmony_ci#define MAX_DFL_FPGA_PORT_NUM 4 328c2ecf20Sopenharmony_ci/* plus one for fme device */ 338c2ecf20Sopenharmony_ci#define MAX_DFL_FEATURE_DEV_NUM (MAX_DFL_FPGA_PORT_NUM + 1) 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/* Reserved 0xfe for Header Group Register and 0xff for AFU */ 368c2ecf20Sopenharmony_ci#define FEATURE_ID_FIU_HEADER 0xfe 378c2ecf20Sopenharmony_ci#define FEATURE_ID_AFU 0xff 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define FME_FEATURE_ID_HEADER FEATURE_ID_FIU_HEADER 408c2ecf20Sopenharmony_ci#define FME_FEATURE_ID_THERMAL_MGMT 0x1 418c2ecf20Sopenharmony_ci#define FME_FEATURE_ID_POWER_MGMT 0x2 428c2ecf20Sopenharmony_ci#define FME_FEATURE_ID_GLOBAL_IPERF 0x3 438c2ecf20Sopenharmony_ci#define FME_FEATURE_ID_GLOBAL_ERR 0x4 448c2ecf20Sopenharmony_ci#define FME_FEATURE_ID_PR_MGMT 0x5 458c2ecf20Sopenharmony_ci#define FME_FEATURE_ID_HSSI 0x6 468c2ecf20Sopenharmony_ci#define FME_FEATURE_ID_GLOBAL_DPERF 0x7 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#define PORT_FEATURE_ID_HEADER FEATURE_ID_FIU_HEADER 498c2ecf20Sopenharmony_ci#define PORT_FEATURE_ID_AFU FEATURE_ID_AFU 508c2ecf20Sopenharmony_ci#define PORT_FEATURE_ID_ERROR 0x10 518c2ecf20Sopenharmony_ci#define PORT_FEATURE_ID_UMSG 0x11 528c2ecf20Sopenharmony_ci#define PORT_FEATURE_ID_UINT 0x12 538c2ecf20Sopenharmony_ci#define PORT_FEATURE_ID_STP 0x13 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci/* 568c2ecf20Sopenharmony_ci * Device Feature Header Register Set 578c2ecf20Sopenharmony_ci * 588c2ecf20Sopenharmony_ci * For FIUs, they all have DFH + GUID + NEXT_AFU as common header registers. 598c2ecf20Sopenharmony_ci * For AFUs, they have DFH + GUID as common header registers. 608c2ecf20Sopenharmony_ci * For private features, they only have DFH register as common header. 618c2ecf20Sopenharmony_ci */ 628c2ecf20Sopenharmony_ci#define DFH 0x0 638c2ecf20Sopenharmony_ci#define GUID_L 0x8 648c2ecf20Sopenharmony_ci#define GUID_H 0x10 658c2ecf20Sopenharmony_ci#define NEXT_AFU 0x18 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci#define DFH_SIZE 0x8 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci/* Device Feature Header Register Bitfield */ 708c2ecf20Sopenharmony_ci#define DFH_ID GENMASK_ULL(11, 0) /* Feature ID */ 718c2ecf20Sopenharmony_ci#define DFH_ID_FIU_FME 0 728c2ecf20Sopenharmony_ci#define DFH_ID_FIU_PORT 1 738c2ecf20Sopenharmony_ci#define DFH_REVISION GENMASK_ULL(15, 12) /* Feature revision */ 748c2ecf20Sopenharmony_ci#define DFH_NEXT_HDR_OFST GENMASK_ULL(39, 16) /* Offset to next DFH */ 758c2ecf20Sopenharmony_ci#define DFH_EOL BIT_ULL(40) /* End of list */ 768c2ecf20Sopenharmony_ci#define DFH_TYPE GENMASK_ULL(63, 60) /* Feature type */ 778c2ecf20Sopenharmony_ci#define DFH_TYPE_AFU 1 788c2ecf20Sopenharmony_ci#define DFH_TYPE_PRIVATE 3 798c2ecf20Sopenharmony_ci#define DFH_TYPE_FIU 4 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci/* Next AFU Register Bitfield */ 828c2ecf20Sopenharmony_ci#define NEXT_AFU_NEXT_DFH_OFST GENMASK_ULL(23, 0) /* Offset to next AFU */ 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci/* FME Header Register Set */ 858c2ecf20Sopenharmony_ci#define FME_HDR_DFH DFH 868c2ecf20Sopenharmony_ci#define FME_HDR_GUID_L GUID_L 878c2ecf20Sopenharmony_ci#define FME_HDR_GUID_H GUID_H 888c2ecf20Sopenharmony_ci#define FME_HDR_NEXT_AFU NEXT_AFU 898c2ecf20Sopenharmony_ci#define FME_HDR_CAP 0x30 908c2ecf20Sopenharmony_ci#define FME_HDR_PORT_OFST(n) (0x38 + ((n) * 0x8)) 918c2ecf20Sopenharmony_ci#define FME_HDR_BITSTREAM_ID 0x60 928c2ecf20Sopenharmony_ci#define FME_HDR_BITSTREAM_MD 0x68 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci/* FME Fab Capability Register Bitfield */ 958c2ecf20Sopenharmony_ci#define FME_CAP_FABRIC_VERID GENMASK_ULL(7, 0) /* Fabric version ID */ 968c2ecf20Sopenharmony_ci#define FME_CAP_SOCKET_ID BIT_ULL(8) /* Socket ID */ 978c2ecf20Sopenharmony_ci#define FME_CAP_PCIE0_LINK_AVL BIT_ULL(12) /* PCIE0 Link */ 988c2ecf20Sopenharmony_ci#define FME_CAP_PCIE1_LINK_AVL BIT_ULL(13) /* PCIE1 Link */ 998c2ecf20Sopenharmony_ci#define FME_CAP_COHR_LINK_AVL BIT_ULL(14) /* Coherent Link */ 1008c2ecf20Sopenharmony_ci#define FME_CAP_IOMMU_AVL BIT_ULL(16) /* IOMMU available */ 1018c2ecf20Sopenharmony_ci#define FME_CAP_NUM_PORTS GENMASK_ULL(19, 17) /* Number of ports */ 1028c2ecf20Sopenharmony_ci#define FME_CAP_ADDR_WIDTH GENMASK_ULL(29, 24) /* Address bus width */ 1038c2ecf20Sopenharmony_ci#define FME_CAP_CACHE_SIZE GENMASK_ULL(43, 32) /* cache size in KB */ 1048c2ecf20Sopenharmony_ci#define FME_CAP_CACHE_ASSOC GENMASK_ULL(47, 44) /* Associativity */ 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci/* FME Port Offset Register Bitfield */ 1078c2ecf20Sopenharmony_ci/* Offset to port device feature header */ 1088c2ecf20Sopenharmony_ci#define FME_PORT_OFST_DFH_OFST GENMASK_ULL(23, 0) 1098c2ecf20Sopenharmony_ci/* PCI Bar ID for this port */ 1108c2ecf20Sopenharmony_ci#define FME_PORT_OFST_BAR_ID GENMASK_ULL(34, 32) 1118c2ecf20Sopenharmony_ci/* AFU MMIO access permission. 1 - VF, 0 - PF. */ 1128c2ecf20Sopenharmony_ci#define FME_PORT_OFST_ACC_CTRL BIT_ULL(55) 1138c2ecf20Sopenharmony_ci#define FME_PORT_OFST_ACC_PF 0 1148c2ecf20Sopenharmony_ci#define FME_PORT_OFST_ACC_VF 1 1158c2ecf20Sopenharmony_ci#define FME_PORT_OFST_IMP BIT_ULL(60) 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci/* FME Error Capability Register */ 1188c2ecf20Sopenharmony_ci#define FME_ERROR_CAP 0x70 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci/* FME Error Capability Register Bitfield */ 1218c2ecf20Sopenharmony_ci#define FME_ERROR_CAP_SUPP_INT BIT_ULL(0) /* Interrupt Support */ 1228c2ecf20Sopenharmony_ci#define FME_ERROR_CAP_INT_VECT GENMASK_ULL(12, 1) /* Interrupt vector */ 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci/* PORT Header Register Set */ 1258c2ecf20Sopenharmony_ci#define PORT_HDR_DFH DFH 1268c2ecf20Sopenharmony_ci#define PORT_HDR_GUID_L GUID_L 1278c2ecf20Sopenharmony_ci#define PORT_HDR_GUID_H GUID_H 1288c2ecf20Sopenharmony_ci#define PORT_HDR_NEXT_AFU NEXT_AFU 1298c2ecf20Sopenharmony_ci#define PORT_HDR_CAP 0x30 1308c2ecf20Sopenharmony_ci#define PORT_HDR_CTRL 0x38 1318c2ecf20Sopenharmony_ci#define PORT_HDR_STS 0x40 1328c2ecf20Sopenharmony_ci#define PORT_HDR_USRCLK_CMD0 0x50 1338c2ecf20Sopenharmony_ci#define PORT_HDR_USRCLK_CMD1 0x58 1348c2ecf20Sopenharmony_ci#define PORT_HDR_USRCLK_STS0 0x60 1358c2ecf20Sopenharmony_ci#define PORT_HDR_USRCLK_STS1 0x68 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci/* Port Capability Register Bitfield */ 1388c2ecf20Sopenharmony_ci#define PORT_CAP_PORT_NUM GENMASK_ULL(1, 0) /* ID of this port */ 1398c2ecf20Sopenharmony_ci#define PORT_CAP_MMIO_SIZE GENMASK_ULL(23, 8) /* MMIO size in KB */ 1408c2ecf20Sopenharmony_ci#define PORT_CAP_SUPP_INT_NUM GENMASK_ULL(35, 32) /* Interrupts num */ 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci/* Port Control Register Bitfield */ 1438c2ecf20Sopenharmony_ci#define PORT_CTRL_SFTRST BIT_ULL(0) /* Port soft reset */ 1448c2ecf20Sopenharmony_ci/* Latency tolerance reporting. '1' >= 40us, '0' < 40us.*/ 1458c2ecf20Sopenharmony_ci#define PORT_CTRL_LATENCY BIT_ULL(2) 1468c2ecf20Sopenharmony_ci#define PORT_CTRL_SFTRST_ACK BIT_ULL(4) /* HW ack for reset */ 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci/* Port Status Register Bitfield */ 1498c2ecf20Sopenharmony_ci#define PORT_STS_AP2_EVT BIT_ULL(13) /* AP2 event detected */ 1508c2ecf20Sopenharmony_ci#define PORT_STS_AP1_EVT BIT_ULL(12) /* AP1 event detected */ 1518c2ecf20Sopenharmony_ci#define PORT_STS_PWR_STATE GENMASK_ULL(11, 8) /* AFU power states */ 1528c2ecf20Sopenharmony_ci#define PORT_STS_PWR_STATE_NORM 0 1538c2ecf20Sopenharmony_ci#define PORT_STS_PWR_STATE_AP1 1 /* 50% throttling */ 1548c2ecf20Sopenharmony_ci#define PORT_STS_PWR_STATE_AP2 2 /* 90% throttling */ 1558c2ecf20Sopenharmony_ci#define PORT_STS_PWR_STATE_AP6 6 /* 100% throttling */ 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci/* Port Error Capability Register */ 1588c2ecf20Sopenharmony_ci#define PORT_ERROR_CAP 0x38 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci/* Port Error Capability Register Bitfield */ 1618c2ecf20Sopenharmony_ci#define PORT_ERROR_CAP_SUPP_INT BIT_ULL(0) /* Interrupt Support */ 1628c2ecf20Sopenharmony_ci#define PORT_ERROR_CAP_INT_VECT GENMASK_ULL(12, 1) /* Interrupt vector */ 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci/* Port Uint Capability Register */ 1658c2ecf20Sopenharmony_ci#define PORT_UINT_CAP 0x8 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci/* Port Uint Capability Register Bitfield */ 1688c2ecf20Sopenharmony_ci#define PORT_UINT_CAP_INT_NUM GENMASK_ULL(11, 0) /* Interrupts num */ 1698c2ecf20Sopenharmony_ci#define PORT_UINT_CAP_FST_VECT GENMASK_ULL(23, 12) /* First Vector */ 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci/** 1728c2ecf20Sopenharmony_ci * struct dfl_fpga_port_ops - port ops 1738c2ecf20Sopenharmony_ci * 1748c2ecf20Sopenharmony_ci * @name: name of this port ops, to match with port platform device. 1758c2ecf20Sopenharmony_ci * @owner: pointer to the module which owns this port ops. 1768c2ecf20Sopenharmony_ci * @node: node to link port ops to global list. 1778c2ecf20Sopenharmony_ci * @get_id: get port id from hardware. 1788c2ecf20Sopenharmony_ci * @enable_set: enable/disable the port. 1798c2ecf20Sopenharmony_ci */ 1808c2ecf20Sopenharmony_cistruct dfl_fpga_port_ops { 1818c2ecf20Sopenharmony_ci const char *name; 1828c2ecf20Sopenharmony_ci struct module *owner; 1838c2ecf20Sopenharmony_ci struct list_head node; 1848c2ecf20Sopenharmony_ci int (*get_id)(struct platform_device *pdev); 1858c2ecf20Sopenharmony_ci int (*enable_set)(struct platform_device *pdev, bool enable); 1868c2ecf20Sopenharmony_ci}; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_civoid dfl_fpga_port_ops_add(struct dfl_fpga_port_ops *ops); 1898c2ecf20Sopenharmony_civoid dfl_fpga_port_ops_del(struct dfl_fpga_port_ops *ops); 1908c2ecf20Sopenharmony_cistruct dfl_fpga_port_ops *dfl_fpga_port_ops_get(struct platform_device *pdev); 1918c2ecf20Sopenharmony_civoid dfl_fpga_port_ops_put(struct dfl_fpga_port_ops *ops); 1928c2ecf20Sopenharmony_ciint dfl_fpga_check_port_id(struct platform_device *pdev, void *pport_id); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci/** 1958c2ecf20Sopenharmony_ci * struct dfl_feature_id - dfl private feature id 1968c2ecf20Sopenharmony_ci * 1978c2ecf20Sopenharmony_ci * @id: unique dfl private feature id. 1988c2ecf20Sopenharmony_ci */ 1998c2ecf20Sopenharmony_cistruct dfl_feature_id { 2008c2ecf20Sopenharmony_ci u16 id; 2018c2ecf20Sopenharmony_ci}; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci/** 2048c2ecf20Sopenharmony_ci * struct dfl_feature_driver - dfl private feature driver 2058c2ecf20Sopenharmony_ci * 2068c2ecf20Sopenharmony_ci * @id_table: id_table for dfl private features supported by this driver. 2078c2ecf20Sopenharmony_ci * @ops: ops of this dfl private feature driver. 2088c2ecf20Sopenharmony_ci */ 2098c2ecf20Sopenharmony_cistruct dfl_feature_driver { 2108c2ecf20Sopenharmony_ci const struct dfl_feature_id *id_table; 2118c2ecf20Sopenharmony_ci const struct dfl_feature_ops *ops; 2128c2ecf20Sopenharmony_ci}; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci/** 2158c2ecf20Sopenharmony_ci * struct dfl_feature_irq_ctx - dfl private feature interrupt context 2168c2ecf20Sopenharmony_ci * 2178c2ecf20Sopenharmony_ci * @irq: Linux IRQ number of this interrupt. 2188c2ecf20Sopenharmony_ci * @trigger: eventfd context to signal when interrupt happens. 2198c2ecf20Sopenharmony_ci * @name: irq name needed when requesting irq. 2208c2ecf20Sopenharmony_ci */ 2218c2ecf20Sopenharmony_cistruct dfl_feature_irq_ctx { 2228c2ecf20Sopenharmony_ci int irq; 2238c2ecf20Sopenharmony_ci struct eventfd_ctx *trigger; 2248c2ecf20Sopenharmony_ci char *name; 2258c2ecf20Sopenharmony_ci}; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci/** 2288c2ecf20Sopenharmony_ci * struct dfl_feature - sub feature of the feature devices 2298c2ecf20Sopenharmony_ci * 2308c2ecf20Sopenharmony_ci * @dev: ptr to pdev of the feature device which has the sub feature. 2318c2ecf20Sopenharmony_ci * @id: sub feature id. 2328c2ecf20Sopenharmony_ci * @resource_index: each sub feature has one mmio resource for its registers. 2338c2ecf20Sopenharmony_ci * this index is used to find its mmio resource from the 2348c2ecf20Sopenharmony_ci * feature dev (platform device)'s reources. 2358c2ecf20Sopenharmony_ci * @ioaddr: mapped mmio resource address. 2368c2ecf20Sopenharmony_ci * @irq_ctx: interrupt context list. 2378c2ecf20Sopenharmony_ci * @nr_irqs: number of interrupt contexts. 2388c2ecf20Sopenharmony_ci * @ops: ops of this sub feature. 2398c2ecf20Sopenharmony_ci * @ddev: ptr to the dfl device of this sub feature. 2408c2ecf20Sopenharmony_ci * @priv: priv data of this feature. 2418c2ecf20Sopenharmony_ci */ 2428c2ecf20Sopenharmony_cistruct dfl_feature { 2438c2ecf20Sopenharmony_ci struct platform_device *dev; 2448c2ecf20Sopenharmony_ci u16 id; 2458c2ecf20Sopenharmony_ci int resource_index; 2468c2ecf20Sopenharmony_ci void __iomem *ioaddr; 2478c2ecf20Sopenharmony_ci struct dfl_feature_irq_ctx *irq_ctx; 2488c2ecf20Sopenharmony_ci unsigned int nr_irqs; 2498c2ecf20Sopenharmony_ci const struct dfl_feature_ops *ops; 2508c2ecf20Sopenharmony_ci struct dfl_device *ddev; 2518c2ecf20Sopenharmony_ci void *priv; 2528c2ecf20Sopenharmony_ci}; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci#define FEATURE_DEV_ID_UNUSED (-1) 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci/** 2578c2ecf20Sopenharmony_ci * struct dfl_feature_platform_data - platform data for feature devices 2588c2ecf20Sopenharmony_ci * 2598c2ecf20Sopenharmony_ci * @node: node to link feature devs to container device's port_dev_list. 2608c2ecf20Sopenharmony_ci * @lock: mutex to protect platform data. 2618c2ecf20Sopenharmony_ci * @cdev: cdev of feature dev. 2628c2ecf20Sopenharmony_ci * @dev: ptr to platform device linked with this platform data. 2638c2ecf20Sopenharmony_ci * @dfl_cdev: ptr to container device. 2648c2ecf20Sopenharmony_ci * @id: id used for this feature device. 2658c2ecf20Sopenharmony_ci * @disable_count: count for port disable. 2668c2ecf20Sopenharmony_ci * @excl_open: set on feature device exclusive open. 2678c2ecf20Sopenharmony_ci * @open_count: count for feature device open. 2688c2ecf20Sopenharmony_ci * @num: number for sub features. 2698c2ecf20Sopenharmony_ci * @private: ptr to feature dev private data. 2708c2ecf20Sopenharmony_ci * @features: sub features of this feature dev. 2718c2ecf20Sopenharmony_ci */ 2728c2ecf20Sopenharmony_cistruct dfl_feature_platform_data { 2738c2ecf20Sopenharmony_ci struct list_head node; 2748c2ecf20Sopenharmony_ci struct mutex lock; 2758c2ecf20Sopenharmony_ci struct cdev cdev; 2768c2ecf20Sopenharmony_ci struct platform_device *dev; 2778c2ecf20Sopenharmony_ci struct dfl_fpga_cdev *dfl_cdev; 2788c2ecf20Sopenharmony_ci int id; 2798c2ecf20Sopenharmony_ci unsigned int disable_count; 2808c2ecf20Sopenharmony_ci bool excl_open; 2818c2ecf20Sopenharmony_ci int open_count; 2828c2ecf20Sopenharmony_ci void *private; 2838c2ecf20Sopenharmony_ci int num; 2848c2ecf20Sopenharmony_ci struct dfl_feature features[]; 2858c2ecf20Sopenharmony_ci}; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_cistatic inline 2888c2ecf20Sopenharmony_ciint dfl_feature_dev_use_begin(struct dfl_feature_platform_data *pdata, 2898c2ecf20Sopenharmony_ci bool excl) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci if (pdata->excl_open) 2928c2ecf20Sopenharmony_ci return -EBUSY; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci if (excl) { 2958c2ecf20Sopenharmony_ci if (pdata->open_count) 2968c2ecf20Sopenharmony_ci return -EBUSY; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci pdata->excl_open = true; 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci pdata->open_count++; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci return 0; 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_cistatic inline 3068c2ecf20Sopenharmony_civoid dfl_feature_dev_use_end(struct dfl_feature_platform_data *pdata) 3078c2ecf20Sopenharmony_ci{ 3088c2ecf20Sopenharmony_ci pdata->excl_open = false; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci if (WARN_ON(pdata->open_count <= 0)) 3118c2ecf20Sopenharmony_ci return; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci pdata->open_count--; 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_cistatic inline 3178c2ecf20Sopenharmony_ciint dfl_feature_dev_use_count(struct dfl_feature_platform_data *pdata) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci return pdata->open_count; 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_cistatic inline 3238c2ecf20Sopenharmony_civoid dfl_fpga_pdata_set_private(struct dfl_feature_platform_data *pdata, 3248c2ecf20Sopenharmony_ci void *private) 3258c2ecf20Sopenharmony_ci{ 3268c2ecf20Sopenharmony_ci pdata->private = private; 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_cistatic inline 3308c2ecf20Sopenharmony_civoid *dfl_fpga_pdata_get_private(struct dfl_feature_platform_data *pdata) 3318c2ecf20Sopenharmony_ci{ 3328c2ecf20Sopenharmony_ci return pdata->private; 3338c2ecf20Sopenharmony_ci} 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_cistruct dfl_feature_ops { 3368c2ecf20Sopenharmony_ci int (*init)(struct platform_device *pdev, struct dfl_feature *feature); 3378c2ecf20Sopenharmony_ci void (*uinit)(struct platform_device *pdev, 3388c2ecf20Sopenharmony_ci struct dfl_feature *feature); 3398c2ecf20Sopenharmony_ci long (*ioctl)(struct platform_device *pdev, struct dfl_feature *feature, 3408c2ecf20Sopenharmony_ci unsigned int cmd, unsigned long arg); 3418c2ecf20Sopenharmony_ci}; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci#define DFL_FPGA_FEATURE_DEV_FME "dfl-fme" 3448c2ecf20Sopenharmony_ci#define DFL_FPGA_FEATURE_DEV_PORT "dfl-port" 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_civoid dfl_fpga_dev_feature_uinit(struct platform_device *pdev); 3478c2ecf20Sopenharmony_ciint dfl_fpga_dev_feature_init(struct platform_device *pdev, 3488c2ecf20Sopenharmony_ci struct dfl_feature_driver *feature_drvs); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ciint dfl_fpga_dev_ops_register(struct platform_device *pdev, 3518c2ecf20Sopenharmony_ci const struct file_operations *fops, 3528c2ecf20Sopenharmony_ci struct module *owner); 3538c2ecf20Sopenharmony_civoid dfl_fpga_dev_ops_unregister(struct platform_device *pdev); 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_cistatic inline 3568c2ecf20Sopenharmony_cistruct platform_device *dfl_fpga_inode_to_feature_dev(struct inode *inode) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci struct dfl_feature_platform_data *pdata; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci pdata = container_of(inode->i_cdev, struct dfl_feature_platform_data, 3618c2ecf20Sopenharmony_ci cdev); 3628c2ecf20Sopenharmony_ci return pdata->dev; 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci#define dfl_fpga_dev_for_each_feature(pdata, feature) \ 3668c2ecf20Sopenharmony_ci for ((feature) = (pdata)->features; \ 3678c2ecf20Sopenharmony_ci (feature) < (pdata)->features + (pdata)->num; (feature)++) 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_cistatic inline 3708c2ecf20Sopenharmony_cistruct dfl_feature *dfl_get_feature_by_id(struct device *dev, u16 id) 3718c2ecf20Sopenharmony_ci{ 3728c2ecf20Sopenharmony_ci struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); 3738c2ecf20Sopenharmony_ci struct dfl_feature *feature; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci dfl_fpga_dev_for_each_feature(pdata, feature) 3768c2ecf20Sopenharmony_ci if (feature->id == id) 3778c2ecf20Sopenharmony_ci return feature; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci return NULL; 3808c2ecf20Sopenharmony_ci} 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_cistatic inline 3838c2ecf20Sopenharmony_civoid __iomem *dfl_get_feature_ioaddr_by_id(struct device *dev, u16 id) 3848c2ecf20Sopenharmony_ci{ 3858c2ecf20Sopenharmony_ci struct dfl_feature *feature = dfl_get_feature_by_id(dev, id); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci if (feature && feature->ioaddr) 3888c2ecf20Sopenharmony_ci return feature->ioaddr; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci WARN_ON(1); 3918c2ecf20Sopenharmony_ci return NULL; 3928c2ecf20Sopenharmony_ci} 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_cistatic inline bool is_dfl_feature_present(struct device *dev, u16 id) 3958c2ecf20Sopenharmony_ci{ 3968c2ecf20Sopenharmony_ci return !!dfl_get_feature_ioaddr_by_id(dev, id); 3978c2ecf20Sopenharmony_ci} 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_cistatic inline 4008c2ecf20Sopenharmony_cistruct device *dfl_fpga_pdata_to_parent(struct dfl_feature_platform_data *pdata) 4018c2ecf20Sopenharmony_ci{ 4028c2ecf20Sopenharmony_ci return pdata->dev->dev.parent->parent; 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_cistatic inline bool dfl_feature_is_fme(void __iomem *base) 4068c2ecf20Sopenharmony_ci{ 4078c2ecf20Sopenharmony_ci u64 v = readq(base + DFH); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci return (FIELD_GET(DFH_TYPE, v) == DFH_TYPE_FIU) && 4108c2ecf20Sopenharmony_ci (FIELD_GET(DFH_ID, v) == DFH_ID_FIU_FME); 4118c2ecf20Sopenharmony_ci} 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_cistatic inline bool dfl_feature_is_port(void __iomem *base) 4148c2ecf20Sopenharmony_ci{ 4158c2ecf20Sopenharmony_ci u64 v = readq(base + DFH); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci return (FIELD_GET(DFH_TYPE, v) == DFH_TYPE_FIU) && 4188c2ecf20Sopenharmony_ci (FIELD_GET(DFH_ID, v) == DFH_ID_FIU_PORT); 4198c2ecf20Sopenharmony_ci} 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cistatic inline u8 dfl_feature_revision(void __iomem *base) 4228c2ecf20Sopenharmony_ci{ 4238c2ecf20Sopenharmony_ci return (u8)FIELD_GET(DFH_REVISION, readq(base + DFH)); 4248c2ecf20Sopenharmony_ci} 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci/** 4278c2ecf20Sopenharmony_ci * struct dfl_fpga_enum_info - DFL FPGA enumeration information 4288c2ecf20Sopenharmony_ci * 4298c2ecf20Sopenharmony_ci * @dev: parent device. 4308c2ecf20Sopenharmony_ci * @dfls: list of device feature lists. 4318c2ecf20Sopenharmony_ci * @nr_irqs: number of irqs for all feature devices. 4328c2ecf20Sopenharmony_ci * @irq_table: Linux IRQ numbers for all irqs, indexed by hw irq numbers. 4338c2ecf20Sopenharmony_ci */ 4348c2ecf20Sopenharmony_cistruct dfl_fpga_enum_info { 4358c2ecf20Sopenharmony_ci struct device *dev; 4368c2ecf20Sopenharmony_ci struct list_head dfls; 4378c2ecf20Sopenharmony_ci unsigned int nr_irqs; 4388c2ecf20Sopenharmony_ci int *irq_table; 4398c2ecf20Sopenharmony_ci}; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci/** 4428c2ecf20Sopenharmony_ci * struct dfl_fpga_enum_dfl - DFL FPGA enumeration device feature list info 4438c2ecf20Sopenharmony_ci * 4448c2ecf20Sopenharmony_ci * @start: base address of this device feature list. 4458c2ecf20Sopenharmony_ci * @len: size of this device feature list. 4468c2ecf20Sopenharmony_ci * @node: node in list of device feature lists. 4478c2ecf20Sopenharmony_ci */ 4488c2ecf20Sopenharmony_cistruct dfl_fpga_enum_dfl { 4498c2ecf20Sopenharmony_ci resource_size_t start; 4508c2ecf20Sopenharmony_ci resource_size_t len; 4518c2ecf20Sopenharmony_ci struct list_head node; 4528c2ecf20Sopenharmony_ci}; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_cistruct dfl_fpga_enum_info *dfl_fpga_enum_info_alloc(struct device *dev); 4558c2ecf20Sopenharmony_ciint dfl_fpga_enum_info_add_dfl(struct dfl_fpga_enum_info *info, 4568c2ecf20Sopenharmony_ci resource_size_t start, resource_size_t len); 4578c2ecf20Sopenharmony_ciint dfl_fpga_enum_info_add_irq(struct dfl_fpga_enum_info *info, 4588c2ecf20Sopenharmony_ci unsigned int nr_irqs, int *irq_table); 4598c2ecf20Sopenharmony_civoid dfl_fpga_enum_info_free(struct dfl_fpga_enum_info *info); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci/** 4628c2ecf20Sopenharmony_ci * struct dfl_fpga_cdev - container device of DFL based FPGA 4638c2ecf20Sopenharmony_ci * 4648c2ecf20Sopenharmony_ci * @parent: parent device of this container device. 4658c2ecf20Sopenharmony_ci * @region: base fpga region. 4668c2ecf20Sopenharmony_ci * @fme_dev: FME feature device under this container device. 4678c2ecf20Sopenharmony_ci * @lock: mutex lock to protect the port device list. 4688c2ecf20Sopenharmony_ci * @port_dev_list: list of all port feature devices under this container device. 4698c2ecf20Sopenharmony_ci * @released_port_num: released port number under this container device. 4708c2ecf20Sopenharmony_ci */ 4718c2ecf20Sopenharmony_cistruct dfl_fpga_cdev { 4728c2ecf20Sopenharmony_ci struct device *parent; 4738c2ecf20Sopenharmony_ci struct fpga_region *region; 4748c2ecf20Sopenharmony_ci struct device *fme_dev; 4758c2ecf20Sopenharmony_ci struct mutex lock; 4768c2ecf20Sopenharmony_ci struct list_head port_dev_list; 4778c2ecf20Sopenharmony_ci int released_port_num; 4788c2ecf20Sopenharmony_ci}; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_cistruct dfl_fpga_cdev * 4818c2ecf20Sopenharmony_cidfl_fpga_feature_devs_enumerate(struct dfl_fpga_enum_info *info); 4828c2ecf20Sopenharmony_civoid dfl_fpga_feature_devs_remove(struct dfl_fpga_cdev *cdev); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci/* 4858c2ecf20Sopenharmony_ci * need to drop the device reference with put_device() after use port platform 4868c2ecf20Sopenharmony_ci * device returned by __dfl_fpga_cdev_find_port and dfl_fpga_cdev_find_port 4878c2ecf20Sopenharmony_ci * functions. 4888c2ecf20Sopenharmony_ci */ 4898c2ecf20Sopenharmony_cistruct platform_device * 4908c2ecf20Sopenharmony_ci__dfl_fpga_cdev_find_port(struct dfl_fpga_cdev *cdev, void *data, 4918c2ecf20Sopenharmony_ci int (*match)(struct platform_device *, void *)); 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_cistatic inline struct platform_device * 4948c2ecf20Sopenharmony_cidfl_fpga_cdev_find_port(struct dfl_fpga_cdev *cdev, void *data, 4958c2ecf20Sopenharmony_ci int (*match)(struct platform_device *, void *)) 4968c2ecf20Sopenharmony_ci{ 4978c2ecf20Sopenharmony_ci struct platform_device *pdev; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci mutex_lock(&cdev->lock); 5008c2ecf20Sopenharmony_ci pdev = __dfl_fpga_cdev_find_port(cdev, data, match); 5018c2ecf20Sopenharmony_ci mutex_unlock(&cdev->lock); 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci return pdev; 5048c2ecf20Sopenharmony_ci} 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ciint dfl_fpga_cdev_release_port(struct dfl_fpga_cdev *cdev, int port_id); 5078c2ecf20Sopenharmony_ciint dfl_fpga_cdev_assign_port(struct dfl_fpga_cdev *cdev, int port_id); 5088c2ecf20Sopenharmony_civoid dfl_fpga_cdev_config_ports_pf(struct dfl_fpga_cdev *cdev); 5098c2ecf20Sopenharmony_ciint dfl_fpga_cdev_config_ports_vf(struct dfl_fpga_cdev *cdev, int num_vf); 5108c2ecf20Sopenharmony_ciint dfl_fpga_set_irq_triggers(struct dfl_feature *feature, unsigned int start, 5118c2ecf20Sopenharmony_ci unsigned int count, int32_t *fds); 5128c2ecf20Sopenharmony_cilong dfl_feature_ioctl_get_num_irqs(struct platform_device *pdev, 5138c2ecf20Sopenharmony_ci struct dfl_feature *feature, 5148c2ecf20Sopenharmony_ci unsigned long arg); 5158c2ecf20Sopenharmony_cilong dfl_feature_ioctl_set_irq(struct platform_device *pdev, 5168c2ecf20Sopenharmony_ci struct dfl_feature *feature, 5178c2ecf20Sopenharmony_ci unsigned long arg); 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci/** 5208c2ecf20Sopenharmony_ci * enum dfl_id_type - define the DFL FIU types 5218c2ecf20Sopenharmony_ci */ 5228c2ecf20Sopenharmony_cienum dfl_id_type { 5238c2ecf20Sopenharmony_ci FME_ID, 5248c2ecf20Sopenharmony_ci PORT_ID, 5258c2ecf20Sopenharmony_ci DFL_ID_MAX, 5268c2ecf20Sopenharmony_ci}; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci/** 5298c2ecf20Sopenharmony_ci * struct dfl_device_id - dfl device identifier 5308c2ecf20Sopenharmony_ci * @type: contains 4 bits DFL FIU type of the device. See enum dfl_id_type. 5318c2ecf20Sopenharmony_ci * @feature_id: contains 12 bits feature identifier local to its DFL FIU type. 5328c2ecf20Sopenharmony_ci * @driver_data: driver specific data. 5338c2ecf20Sopenharmony_ci */ 5348c2ecf20Sopenharmony_cistruct dfl_device_id { 5358c2ecf20Sopenharmony_ci u8 type; 5368c2ecf20Sopenharmony_ci u16 feature_id; 5378c2ecf20Sopenharmony_ci unsigned long driver_data; 5388c2ecf20Sopenharmony_ci}; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci/** 5418c2ecf20Sopenharmony_ci * struct dfl_device - represent an dfl device on dfl bus 5428c2ecf20Sopenharmony_ci * 5438c2ecf20Sopenharmony_ci * @dev: generic device interface. 5448c2ecf20Sopenharmony_ci * @id: id of the dfl device. 5458c2ecf20Sopenharmony_ci * @type: type of DFL FIU of the device. See enum dfl_id_type. 5468c2ecf20Sopenharmony_ci * @feature_id: 16 bits feature identifier local to its DFL FIU type. 5478c2ecf20Sopenharmony_ci * @mmio_res: mmio resource of this dfl device. 5488c2ecf20Sopenharmony_ci * @irqs: list of Linux IRQ numbers of this dfl device. 5498c2ecf20Sopenharmony_ci * @num_irqs: number of IRQs supported by this dfl device. 5508c2ecf20Sopenharmony_ci * @cdev: pointer to DFL FPGA container device this dfl device belongs to. 5518c2ecf20Sopenharmony_ci * @id_entry: matched id entry in dfl driver's id table. 5528c2ecf20Sopenharmony_ci */ 5538c2ecf20Sopenharmony_cistruct dfl_device { 5548c2ecf20Sopenharmony_ci struct device dev; 5558c2ecf20Sopenharmony_ci int id; 5568c2ecf20Sopenharmony_ci u8 type; 5578c2ecf20Sopenharmony_ci u16 feature_id; 5588c2ecf20Sopenharmony_ci struct resource mmio_res; 5598c2ecf20Sopenharmony_ci int *irqs; 5608c2ecf20Sopenharmony_ci unsigned int num_irqs; 5618c2ecf20Sopenharmony_ci struct dfl_fpga_cdev *cdev; 5628c2ecf20Sopenharmony_ci const struct dfl_device_id *id_entry; 5638c2ecf20Sopenharmony_ci}; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci/** 5668c2ecf20Sopenharmony_ci * struct dfl_driver - represent an dfl device driver 5678c2ecf20Sopenharmony_ci * 5688c2ecf20Sopenharmony_ci * @drv: driver model structure. 5698c2ecf20Sopenharmony_ci * @id_table: pointer to table of device IDs the driver is interested in. 5708c2ecf20Sopenharmony_ci * { } member terminated. 5718c2ecf20Sopenharmony_ci * @probe: mandatory callback for device binding. 5728c2ecf20Sopenharmony_ci * @remove: callback for device unbinding. 5738c2ecf20Sopenharmony_ci */ 5748c2ecf20Sopenharmony_cistruct dfl_driver { 5758c2ecf20Sopenharmony_ci struct device_driver drv; 5768c2ecf20Sopenharmony_ci const struct dfl_device_id *id_table; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci int (*probe)(struct dfl_device *dfl_dev); 5798c2ecf20Sopenharmony_ci void (*remove)(struct dfl_device *dfl_dev); 5808c2ecf20Sopenharmony_ci}; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci#define to_dfl_dev(d) container_of(d, struct dfl_device, dev) 5838c2ecf20Sopenharmony_ci#define to_dfl_drv(d) container_of(d, struct dfl_driver, drv) 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci/* 5868c2ecf20Sopenharmony_ci * use a macro to avoid include chaining to get THIS_MODULE. 5878c2ecf20Sopenharmony_ci */ 5888c2ecf20Sopenharmony_ci#define dfl_driver_register(drv) \ 5898c2ecf20Sopenharmony_ci __dfl_driver_register(drv, THIS_MODULE) 5908c2ecf20Sopenharmony_ciint __dfl_driver_register(struct dfl_driver *dfl_drv, struct module *owner); 5918c2ecf20Sopenharmony_civoid dfl_driver_unregister(struct dfl_driver *dfl_drv); 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci/* 5948c2ecf20Sopenharmony_ci * module_dfl_driver() - Helper macro for drivers that don't do 5958c2ecf20Sopenharmony_ci * anything special in module init/exit. This eliminates a lot of 5968c2ecf20Sopenharmony_ci * boilerplate. Each module may only use this macro once, and 5978c2ecf20Sopenharmony_ci * calling it replaces module_init() and module_exit(). 5988c2ecf20Sopenharmony_ci */ 5998c2ecf20Sopenharmony_ci#define module_dfl_driver(__dfl_driver) \ 6008c2ecf20Sopenharmony_ci module_driver(__dfl_driver, dfl_driver_register, \ 6018c2ecf20Sopenharmony_ci dfl_driver_unregister) 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci#endif /* __FPGA_DFL_H */ 604