11a1527cfSWu Hao // SPDX-License-Identifier: GPL-2.0 21a1527cfSWu Hao /* 31a1527cfSWu Hao * Driver for FPGA Accelerated Function Unit (AFU) 41a1527cfSWu Hao * 51a1527cfSWu Hao * Copyright (C) 2017-2018 Intel Corporation, Inc. 61a1527cfSWu Hao * 71a1527cfSWu Hao * Authors: 81a1527cfSWu Hao * Wu Hao <hao.wu@intel.com> 91a1527cfSWu Hao * Xiao Guangrong <guangrong.xiao@linux.intel.com> 101a1527cfSWu Hao * Joseph Grecco <joe.grecco@intel.com> 111a1527cfSWu Hao * Enno Luebbers <enno.luebbers@intel.com> 121a1527cfSWu Hao * Tim Whisonant <tim.whisonant@intel.com> 131a1527cfSWu Hao * Ananda Ravuri <ananda.ravuri@intel.com> 141a1527cfSWu Hao * Henry Mitchel <henry.mitchel@intel.com> 151a1527cfSWu Hao */ 161a1527cfSWu Hao 171a1527cfSWu Hao #include <linux/kernel.h> 181a1527cfSWu Hao #include <linux/module.h> 19857a2622SXiao Guangrong #include <linux/uaccess.h> 20e4664c0eSWu Hao #include <linux/fpga-dfl.h> 211a1527cfSWu Hao 22857a2622SXiao Guangrong #include "dfl-afu.h" 231a1527cfSWu Hao 2447c1b19cSWu Hao /** 2547c1b19cSWu Hao * port_enable - enable a port 2647c1b19cSWu Hao * @pdev: port platform device. 2747c1b19cSWu Hao * 2847c1b19cSWu Hao * Enable Port by clear the port soft reset bit, which is set by default. 29857a2622SXiao Guangrong * The AFU is unable to respond to any MMIO access while in reset. 30857a2622SXiao Guangrong * port_enable function should only be used after port_disable function. 3147c1b19cSWu Hao */ 3247c1b19cSWu Hao static void port_enable(struct platform_device *pdev) 3347c1b19cSWu Hao { 3447c1b19cSWu Hao struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); 3547c1b19cSWu Hao void __iomem *base; 3647c1b19cSWu Hao u64 v; 3747c1b19cSWu Hao 3847c1b19cSWu Hao WARN_ON(!pdata->disable_count); 3947c1b19cSWu Hao 4047c1b19cSWu Hao if (--pdata->disable_count != 0) 4147c1b19cSWu Hao return; 4247c1b19cSWu Hao 4347c1b19cSWu Hao base = dfl_get_feature_ioaddr_by_id(&pdev->dev, PORT_FEATURE_ID_HEADER); 4447c1b19cSWu Hao 4547c1b19cSWu Hao /* Clear port soft reset */ 4647c1b19cSWu Hao v = readq(base + PORT_HDR_CTRL); 4747c1b19cSWu Hao v &= ~PORT_CTRL_SFTRST; 4847c1b19cSWu Hao writeq(v, base + PORT_HDR_CTRL); 4947c1b19cSWu Hao } 5047c1b19cSWu Hao 5147c1b19cSWu Hao #define RST_POLL_INVL 10 /* us */ 5247c1b19cSWu Hao #define RST_POLL_TIMEOUT 1000 /* us */ 5347c1b19cSWu Hao 5447c1b19cSWu Hao /** 5547c1b19cSWu Hao * port_disable - disable a port 5647c1b19cSWu Hao * @pdev: port platform device. 5747c1b19cSWu Hao * 5847c1b19cSWu Hao * Disable Port by setting the port soft reset bit, it puts the port into 5947c1b19cSWu Hao * reset. 6047c1b19cSWu Hao */ 6147c1b19cSWu Hao static int port_disable(struct platform_device *pdev) 6247c1b19cSWu Hao { 6347c1b19cSWu Hao struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); 6447c1b19cSWu Hao void __iomem *base; 6547c1b19cSWu Hao u64 v; 6647c1b19cSWu Hao 6747c1b19cSWu Hao if (pdata->disable_count++ != 0) 6847c1b19cSWu Hao return 0; 6947c1b19cSWu Hao 7047c1b19cSWu Hao base = dfl_get_feature_ioaddr_by_id(&pdev->dev, PORT_FEATURE_ID_HEADER); 7147c1b19cSWu Hao 7247c1b19cSWu Hao /* Set port soft reset */ 7347c1b19cSWu Hao v = readq(base + PORT_HDR_CTRL); 7447c1b19cSWu Hao v |= PORT_CTRL_SFTRST; 7547c1b19cSWu Hao writeq(v, base + PORT_HDR_CTRL); 7647c1b19cSWu Hao 7747c1b19cSWu Hao /* 7847c1b19cSWu Hao * HW sets ack bit to 1 when all outstanding requests have been drained 7947c1b19cSWu Hao * on this port and minimum soft reset pulse width has elapsed. 8047c1b19cSWu Hao * Driver polls port_soft_reset_ack to determine if reset done by HW. 8147c1b19cSWu Hao */ 8247c1b19cSWu Hao if (readq_poll_timeout(base + PORT_HDR_CTRL, v, v & PORT_CTRL_SFTRST, 8347c1b19cSWu Hao RST_POLL_INVL, RST_POLL_TIMEOUT)) { 8447c1b19cSWu Hao dev_err(&pdev->dev, "timeout, fail to reset device\n"); 8547c1b19cSWu Hao return -ETIMEDOUT; 8647c1b19cSWu Hao } 8747c1b19cSWu Hao 8847c1b19cSWu Hao return 0; 8947c1b19cSWu Hao } 9047c1b19cSWu Hao 91e4664c0eSWu Hao /* 92e4664c0eSWu Hao * This function resets the FPGA Port and its accelerator (AFU) by function 93e4664c0eSWu Hao * __port_disable and __port_enable (set port soft reset bit and then clear 94e4664c0eSWu Hao * it). Userspace can do Port reset at any time, e.g. during DMA or Partial 95e4664c0eSWu Hao * Reconfiguration. But it should never cause any system level issue, only 96e4664c0eSWu Hao * functional failure (e.g. DMA or PR operation failure) and be recoverable 97e4664c0eSWu Hao * from the failure. 98e4664c0eSWu Hao * 99e4664c0eSWu Hao * Note: the accelerator (AFU) is not accessible when its port is in reset 100e4664c0eSWu Hao * (disabled). Any attempts on MMIO access to AFU while in reset, will 101e4664c0eSWu Hao * result errors reported via port error reporting sub feature (if present). 102e4664c0eSWu Hao */ 103e4664c0eSWu Hao static int __port_reset(struct platform_device *pdev) 104e4664c0eSWu Hao { 105e4664c0eSWu Hao int ret; 106e4664c0eSWu Hao 107e4664c0eSWu Hao ret = port_disable(pdev); 108e4664c0eSWu Hao if (!ret) 109e4664c0eSWu Hao port_enable(pdev); 110e4664c0eSWu Hao 111e4664c0eSWu Hao return ret; 112e4664c0eSWu Hao } 113e4664c0eSWu Hao 114e4664c0eSWu Hao static int port_reset(struct platform_device *pdev) 115e4664c0eSWu Hao { 116e4664c0eSWu Hao struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); 117e4664c0eSWu Hao int ret; 118e4664c0eSWu Hao 119e4664c0eSWu Hao mutex_lock(&pdata->lock); 120e4664c0eSWu Hao ret = __port_reset(pdev); 121e4664c0eSWu Hao mutex_unlock(&pdata->lock); 122e4664c0eSWu Hao 123e4664c0eSWu Hao return ret; 124e4664c0eSWu Hao } 125e4664c0eSWu Hao 12647c1b19cSWu Hao static int port_get_id(struct platform_device *pdev) 12747c1b19cSWu Hao { 12847c1b19cSWu Hao void __iomem *base; 12947c1b19cSWu Hao 13047c1b19cSWu Hao base = dfl_get_feature_ioaddr_by_id(&pdev->dev, PORT_FEATURE_ID_HEADER); 13147c1b19cSWu Hao 13247c1b19cSWu Hao return FIELD_GET(PORT_CAP_PORT_NUM, readq(base + PORT_HDR_CAP)); 13347c1b19cSWu Hao } 13447c1b19cSWu Hao 135e4664c0eSWu Hao static ssize_t 136e4664c0eSWu Hao id_show(struct device *dev, struct device_attribute *attr, char *buf) 137e4664c0eSWu Hao { 138e4664c0eSWu Hao int id = port_get_id(to_platform_device(dev)); 139e4664c0eSWu Hao 140e4664c0eSWu Hao return scnprintf(buf, PAGE_SIZE, "%d\n", id); 141e4664c0eSWu Hao } 142e4664c0eSWu Hao static DEVICE_ATTR_RO(id); 143e4664c0eSWu Hao 144d2ad5ac1SWu Hao static ssize_t 145d2ad5ac1SWu Hao ltr_show(struct device *dev, struct device_attribute *attr, char *buf) 146d2ad5ac1SWu Hao { 147d2ad5ac1SWu Hao struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); 148d2ad5ac1SWu Hao void __iomem *base; 149d2ad5ac1SWu Hao u64 v; 150d2ad5ac1SWu Hao 151d2ad5ac1SWu Hao base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); 152d2ad5ac1SWu Hao 153d2ad5ac1SWu Hao mutex_lock(&pdata->lock); 154d2ad5ac1SWu Hao v = readq(base + PORT_HDR_CTRL); 155d2ad5ac1SWu Hao mutex_unlock(&pdata->lock); 156d2ad5ac1SWu Hao 157d2ad5ac1SWu Hao return sprintf(buf, "%x\n", (u8)FIELD_GET(PORT_CTRL_LATENCY, v)); 158d2ad5ac1SWu Hao } 159d2ad5ac1SWu Hao 160d2ad5ac1SWu Hao static ssize_t 161d2ad5ac1SWu Hao ltr_store(struct device *dev, struct device_attribute *attr, 162d2ad5ac1SWu Hao const char *buf, size_t count) 163d2ad5ac1SWu Hao { 164d2ad5ac1SWu Hao struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); 165d2ad5ac1SWu Hao void __iomem *base; 166d2ad5ac1SWu Hao bool ltr; 167d2ad5ac1SWu Hao u64 v; 168d2ad5ac1SWu Hao 169d2ad5ac1SWu Hao if (kstrtobool(buf, <r)) 170d2ad5ac1SWu Hao return -EINVAL; 171d2ad5ac1SWu Hao 172d2ad5ac1SWu Hao base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); 173d2ad5ac1SWu Hao 174d2ad5ac1SWu Hao mutex_lock(&pdata->lock); 175d2ad5ac1SWu Hao v = readq(base + PORT_HDR_CTRL); 176d2ad5ac1SWu Hao v &= ~PORT_CTRL_LATENCY; 177d2ad5ac1SWu Hao v |= FIELD_PREP(PORT_CTRL_LATENCY, ltr ? 1 : 0); 178d2ad5ac1SWu Hao writeq(v, base + PORT_HDR_CTRL); 179d2ad5ac1SWu Hao mutex_unlock(&pdata->lock); 180d2ad5ac1SWu Hao 181d2ad5ac1SWu Hao return count; 182d2ad5ac1SWu Hao } 183d2ad5ac1SWu Hao static DEVICE_ATTR_RW(ltr); 184d2ad5ac1SWu Hao 185d2ad5ac1SWu Hao static ssize_t 186d2ad5ac1SWu Hao ap1_event_show(struct device *dev, struct device_attribute *attr, char *buf) 187d2ad5ac1SWu Hao { 188d2ad5ac1SWu Hao struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); 189d2ad5ac1SWu Hao void __iomem *base; 190d2ad5ac1SWu Hao u64 v; 191d2ad5ac1SWu Hao 192d2ad5ac1SWu Hao base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); 193d2ad5ac1SWu Hao 194d2ad5ac1SWu Hao mutex_lock(&pdata->lock); 195d2ad5ac1SWu Hao v = readq(base + PORT_HDR_STS); 196d2ad5ac1SWu Hao mutex_unlock(&pdata->lock); 197d2ad5ac1SWu Hao 198d2ad5ac1SWu Hao return sprintf(buf, "%x\n", (u8)FIELD_GET(PORT_STS_AP1_EVT, v)); 199d2ad5ac1SWu Hao } 200d2ad5ac1SWu Hao 201d2ad5ac1SWu Hao static ssize_t 202d2ad5ac1SWu Hao ap1_event_store(struct device *dev, struct device_attribute *attr, 203d2ad5ac1SWu Hao const char *buf, size_t count) 204d2ad5ac1SWu Hao { 205d2ad5ac1SWu Hao struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); 206d2ad5ac1SWu Hao void __iomem *base; 207d2ad5ac1SWu Hao bool clear; 208d2ad5ac1SWu Hao 209d2ad5ac1SWu Hao if (kstrtobool(buf, &clear) || !clear) 210d2ad5ac1SWu Hao return -EINVAL; 211d2ad5ac1SWu Hao 212d2ad5ac1SWu Hao base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); 213d2ad5ac1SWu Hao 214d2ad5ac1SWu Hao mutex_lock(&pdata->lock); 215d2ad5ac1SWu Hao writeq(PORT_STS_AP1_EVT, base + PORT_HDR_STS); 216d2ad5ac1SWu Hao mutex_unlock(&pdata->lock); 217d2ad5ac1SWu Hao 218d2ad5ac1SWu Hao return count; 219d2ad5ac1SWu Hao } 220d2ad5ac1SWu Hao static DEVICE_ATTR_RW(ap1_event); 221d2ad5ac1SWu Hao 222d2ad5ac1SWu Hao static ssize_t 223d2ad5ac1SWu Hao ap2_event_show(struct device *dev, struct device_attribute *attr, 224d2ad5ac1SWu Hao char *buf) 225d2ad5ac1SWu Hao { 226d2ad5ac1SWu Hao struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); 227d2ad5ac1SWu Hao void __iomem *base; 228d2ad5ac1SWu Hao u64 v; 229d2ad5ac1SWu Hao 230d2ad5ac1SWu Hao base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); 231d2ad5ac1SWu Hao 232d2ad5ac1SWu Hao mutex_lock(&pdata->lock); 233d2ad5ac1SWu Hao v = readq(base + PORT_HDR_STS); 234d2ad5ac1SWu Hao mutex_unlock(&pdata->lock); 235d2ad5ac1SWu Hao 236d2ad5ac1SWu Hao return sprintf(buf, "%x\n", (u8)FIELD_GET(PORT_STS_AP2_EVT, v)); 237d2ad5ac1SWu Hao } 238d2ad5ac1SWu Hao 239d2ad5ac1SWu Hao static ssize_t 240d2ad5ac1SWu Hao ap2_event_store(struct device *dev, struct device_attribute *attr, 241d2ad5ac1SWu Hao const char *buf, size_t count) 242d2ad5ac1SWu Hao { 243d2ad5ac1SWu Hao struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); 244d2ad5ac1SWu Hao void __iomem *base; 245d2ad5ac1SWu Hao bool clear; 246d2ad5ac1SWu Hao 247d2ad5ac1SWu Hao if (kstrtobool(buf, &clear) || !clear) 248d2ad5ac1SWu Hao return -EINVAL; 249d2ad5ac1SWu Hao 250d2ad5ac1SWu Hao base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); 251d2ad5ac1SWu Hao 252d2ad5ac1SWu Hao mutex_lock(&pdata->lock); 253d2ad5ac1SWu Hao writeq(PORT_STS_AP2_EVT, base + PORT_HDR_STS); 254d2ad5ac1SWu Hao mutex_unlock(&pdata->lock); 255d2ad5ac1SWu Hao 256d2ad5ac1SWu Hao return count; 257d2ad5ac1SWu Hao } 258d2ad5ac1SWu Hao static DEVICE_ATTR_RW(ap2_event); 259d2ad5ac1SWu Hao 260d2ad5ac1SWu Hao static ssize_t 261d2ad5ac1SWu Hao power_state_show(struct device *dev, struct device_attribute *attr, char *buf) 262d2ad5ac1SWu Hao { 263d2ad5ac1SWu Hao struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); 264d2ad5ac1SWu Hao void __iomem *base; 265d2ad5ac1SWu Hao u64 v; 266d2ad5ac1SWu Hao 267d2ad5ac1SWu Hao base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); 268d2ad5ac1SWu Hao 269d2ad5ac1SWu Hao mutex_lock(&pdata->lock); 270d2ad5ac1SWu Hao v = readq(base + PORT_HDR_STS); 271d2ad5ac1SWu Hao mutex_unlock(&pdata->lock); 272d2ad5ac1SWu Hao 273d2ad5ac1SWu Hao return sprintf(buf, "0x%x\n", (u8)FIELD_GET(PORT_STS_PWR_STATE, v)); 274d2ad5ac1SWu Hao } 275d2ad5ac1SWu Hao static DEVICE_ATTR_RO(power_state); 276d2ad5ac1SWu Hao 277*f09991adSWu Hao static ssize_t 278*f09991adSWu Hao userclk_freqcmd_store(struct device *dev, struct device_attribute *attr, 279*f09991adSWu Hao const char *buf, size_t count) 280*f09991adSWu Hao { 281*f09991adSWu Hao struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); 282*f09991adSWu Hao u64 userclk_freq_cmd; 283*f09991adSWu Hao void __iomem *base; 284*f09991adSWu Hao 285*f09991adSWu Hao if (kstrtou64(buf, 0, &userclk_freq_cmd)) 286*f09991adSWu Hao return -EINVAL; 287*f09991adSWu Hao 288*f09991adSWu Hao base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); 289*f09991adSWu Hao 290*f09991adSWu Hao mutex_lock(&pdata->lock); 291*f09991adSWu Hao writeq(userclk_freq_cmd, base + PORT_HDR_USRCLK_CMD0); 292*f09991adSWu Hao mutex_unlock(&pdata->lock); 293*f09991adSWu Hao 294*f09991adSWu Hao return count; 295*f09991adSWu Hao } 296*f09991adSWu Hao static DEVICE_ATTR_WO(userclk_freqcmd); 297*f09991adSWu Hao 298*f09991adSWu Hao static ssize_t 299*f09991adSWu Hao userclk_freqcntrcmd_store(struct device *dev, struct device_attribute *attr, 300*f09991adSWu Hao const char *buf, size_t count) 301*f09991adSWu Hao { 302*f09991adSWu Hao struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); 303*f09991adSWu Hao u64 userclk_freqcntr_cmd; 304*f09991adSWu Hao void __iomem *base; 305*f09991adSWu Hao 306*f09991adSWu Hao if (kstrtou64(buf, 0, &userclk_freqcntr_cmd)) 307*f09991adSWu Hao return -EINVAL; 308*f09991adSWu Hao 309*f09991adSWu Hao base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); 310*f09991adSWu Hao 311*f09991adSWu Hao mutex_lock(&pdata->lock); 312*f09991adSWu Hao writeq(userclk_freqcntr_cmd, base + PORT_HDR_USRCLK_CMD1); 313*f09991adSWu Hao mutex_unlock(&pdata->lock); 314*f09991adSWu Hao 315*f09991adSWu Hao return count; 316*f09991adSWu Hao } 317*f09991adSWu Hao static DEVICE_ATTR_WO(userclk_freqcntrcmd); 318*f09991adSWu Hao 319*f09991adSWu Hao static ssize_t 320*f09991adSWu Hao userclk_freqsts_show(struct device *dev, struct device_attribute *attr, 321*f09991adSWu Hao char *buf) 322*f09991adSWu Hao { 323*f09991adSWu Hao struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); 324*f09991adSWu Hao u64 userclk_freqsts; 325*f09991adSWu Hao void __iomem *base; 326*f09991adSWu Hao 327*f09991adSWu Hao base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); 328*f09991adSWu Hao 329*f09991adSWu Hao mutex_lock(&pdata->lock); 330*f09991adSWu Hao userclk_freqsts = readq(base + PORT_HDR_USRCLK_STS0); 331*f09991adSWu Hao mutex_unlock(&pdata->lock); 332*f09991adSWu Hao 333*f09991adSWu Hao return sprintf(buf, "0x%llx\n", (unsigned long long)userclk_freqsts); 334*f09991adSWu Hao } 335*f09991adSWu Hao static DEVICE_ATTR_RO(userclk_freqsts); 336*f09991adSWu Hao 337*f09991adSWu Hao static ssize_t 338*f09991adSWu Hao userclk_freqcntrsts_show(struct device *dev, struct device_attribute *attr, 339*f09991adSWu Hao char *buf) 340*f09991adSWu Hao { 341*f09991adSWu Hao struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); 342*f09991adSWu Hao u64 userclk_freqcntrsts; 343*f09991adSWu Hao void __iomem *base; 344*f09991adSWu Hao 345*f09991adSWu Hao base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); 346*f09991adSWu Hao 347*f09991adSWu Hao mutex_lock(&pdata->lock); 348*f09991adSWu Hao userclk_freqcntrsts = readq(base + PORT_HDR_USRCLK_STS1); 349*f09991adSWu Hao mutex_unlock(&pdata->lock); 350*f09991adSWu Hao 351*f09991adSWu Hao return sprintf(buf, "0x%llx\n", 352*f09991adSWu Hao (unsigned long long)userclk_freqcntrsts); 353*f09991adSWu Hao } 354*f09991adSWu Hao static DEVICE_ATTR_RO(userclk_freqcntrsts); 355*f09991adSWu Hao 356dcfecd4dSGreg Kroah-Hartman static struct attribute *port_hdr_attrs[] = { 357e4664c0eSWu Hao &dev_attr_id.attr, 358d2ad5ac1SWu Hao &dev_attr_ltr.attr, 359d2ad5ac1SWu Hao &dev_attr_ap1_event.attr, 360d2ad5ac1SWu Hao &dev_attr_ap2_event.attr, 361d2ad5ac1SWu Hao &dev_attr_power_state.attr, 362*f09991adSWu Hao &dev_attr_userclk_freqcmd.attr, 363*f09991adSWu Hao &dev_attr_userclk_freqcntrcmd.attr, 364*f09991adSWu Hao &dev_attr_userclk_freqsts.attr, 365*f09991adSWu Hao &dev_attr_userclk_freqcntrsts.attr, 366e4664c0eSWu Hao NULL, 367e4664c0eSWu Hao }; 368a80a4b82SWu Hao 369*f09991adSWu Hao static umode_t port_hdr_attrs_visible(struct kobject *kobj, 370*f09991adSWu Hao struct attribute *attr, int n) 371*f09991adSWu Hao { 372*f09991adSWu Hao struct device *dev = kobj_to_dev(kobj); 373*f09991adSWu Hao umode_t mode = attr->mode; 374*f09991adSWu Hao void __iomem *base; 375*f09991adSWu Hao 376*f09991adSWu Hao base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); 377*f09991adSWu Hao 378*f09991adSWu Hao if (dfl_feature_revision(base) > 0) { 379*f09991adSWu Hao /* 380*f09991adSWu Hao * userclk sysfs interfaces are only visible in case port 381*f09991adSWu Hao * revision is 0, as hardware with revision >0 doesn't 382*f09991adSWu Hao * support this. 383*f09991adSWu Hao */ 384*f09991adSWu Hao if (attr == &dev_attr_userclk_freqcmd.attr || 385*f09991adSWu Hao attr == &dev_attr_userclk_freqcntrcmd.attr || 386*f09991adSWu Hao attr == &dev_attr_userclk_freqsts.attr || 387*f09991adSWu Hao attr == &dev_attr_userclk_freqcntrsts.attr) 388*f09991adSWu Hao mode = 0; 389*f09991adSWu Hao } 390*f09991adSWu Hao 391*f09991adSWu Hao return mode; 392*f09991adSWu Hao } 393*f09991adSWu Hao 394a80a4b82SWu Hao static const struct attribute_group port_hdr_group = { 395a80a4b82SWu Hao .attrs = port_hdr_attrs, 396*f09991adSWu Hao .is_visible = port_hdr_attrs_visible, 397a80a4b82SWu Hao }; 398e4664c0eSWu Hao 3991a1527cfSWu Hao static int port_hdr_init(struct platform_device *pdev, 4001a1527cfSWu Hao struct dfl_feature *feature) 4011a1527cfSWu Hao { 402e4664c0eSWu Hao port_reset(pdev); 403e4664c0eSWu Hao 404a80a4b82SWu Hao return 0; 405e4664c0eSWu Hao } 406e4664c0eSWu Hao 407e4664c0eSWu Hao static long 408e4664c0eSWu Hao port_hdr_ioctl(struct platform_device *pdev, struct dfl_feature *feature, 409e4664c0eSWu Hao unsigned int cmd, unsigned long arg) 410e4664c0eSWu Hao { 411e4664c0eSWu Hao long ret; 412e4664c0eSWu Hao 413e4664c0eSWu Hao switch (cmd) { 414e4664c0eSWu Hao case DFL_FPGA_PORT_RESET: 415e4664c0eSWu Hao if (!arg) 416e4664c0eSWu Hao ret = port_reset(pdev); 417e4664c0eSWu Hao else 418e4664c0eSWu Hao ret = -EINVAL; 419e4664c0eSWu Hao break; 420e4664c0eSWu Hao default: 421e4664c0eSWu Hao dev_dbg(&pdev->dev, "%x cmd not handled", cmd); 422e4664c0eSWu Hao ret = -ENODEV; 423e4664c0eSWu Hao } 424e4664c0eSWu Hao 425e4664c0eSWu Hao return ret; 4261a1527cfSWu Hao } 4271a1527cfSWu Hao 42815bbb300SWu Hao static const struct dfl_feature_id port_hdr_id_table[] = { 42915bbb300SWu Hao {.id = PORT_FEATURE_ID_HEADER,}, 43015bbb300SWu Hao {0,} 43115bbb300SWu Hao }; 43215bbb300SWu Hao 4331a1527cfSWu Hao static const struct dfl_feature_ops port_hdr_ops = { 4341a1527cfSWu Hao .init = port_hdr_init, 435e4664c0eSWu Hao .ioctl = port_hdr_ioctl, 4361a1527cfSWu Hao }; 4371a1527cfSWu Hao 438857a2622SXiao Guangrong static ssize_t 439857a2622SXiao Guangrong afu_id_show(struct device *dev, struct device_attribute *attr, char *buf) 440857a2622SXiao Guangrong { 441857a2622SXiao Guangrong struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); 442857a2622SXiao Guangrong void __iomem *base; 443857a2622SXiao Guangrong u64 guidl, guidh; 444857a2622SXiao Guangrong 445857a2622SXiao Guangrong base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_AFU); 446857a2622SXiao Guangrong 447857a2622SXiao Guangrong mutex_lock(&pdata->lock); 448857a2622SXiao Guangrong if (pdata->disable_count) { 449857a2622SXiao Guangrong mutex_unlock(&pdata->lock); 450857a2622SXiao Guangrong return -EBUSY; 451857a2622SXiao Guangrong } 452857a2622SXiao Guangrong 453857a2622SXiao Guangrong guidl = readq(base + GUID_L); 454857a2622SXiao Guangrong guidh = readq(base + GUID_H); 455857a2622SXiao Guangrong mutex_unlock(&pdata->lock); 456857a2622SXiao Guangrong 457857a2622SXiao Guangrong return scnprintf(buf, PAGE_SIZE, "%016llx%016llx\n", guidh, guidl); 458857a2622SXiao Guangrong } 459857a2622SXiao Guangrong static DEVICE_ATTR_RO(afu_id); 460857a2622SXiao Guangrong 461dcfecd4dSGreg Kroah-Hartman static struct attribute *port_afu_attrs[] = { 462857a2622SXiao Guangrong &dev_attr_afu_id.attr, 463857a2622SXiao Guangrong NULL 464857a2622SXiao Guangrong }; 465a80a4b82SWu Hao 466a80a4b82SWu Hao static umode_t port_afu_attrs_visible(struct kobject *kobj, 467a80a4b82SWu Hao struct attribute *attr, int n) 468a80a4b82SWu Hao { 469a80a4b82SWu Hao struct device *dev = kobj_to_dev(kobj); 470a80a4b82SWu Hao 471a80a4b82SWu Hao /* 472a80a4b82SWu Hao * sysfs entries are visible only if related private feature is 473a80a4b82SWu Hao * enumerated. 474a80a4b82SWu Hao */ 475a80a4b82SWu Hao if (!dfl_get_feature_by_id(dev, PORT_FEATURE_ID_AFU)) 476a80a4b82SWu Hao return 0; 477a80a4b82SWu Hao 478a80a4b82SWu Hao return attr->mode; 479a80a4b82SWu Hao } 480a80a4b82SWu Hao 481a80a4b82SWu Hao static const struct attribute_group port_afu_group = { 482a80a4b82SWu Hao .attrs = port_afu_attrs, 483a80a4b82SWu Hao .is_visible = port_afu_attrs_visible, 484a80a4b82SWu Hao }; 485857a2622SXiao Guangrong 486857a2622SXiao Guangrong static int port_afu_init(struct platform_device *pdev, 487857a2622SXiao Guangrong struct dfl_feature *feature) 488857a2622SXiao Guangrong { 489857a2622SXiao Guangrong struct resource *res = &pdev->resource[feature->resource_index]; 490857a2622SXiao Guangrong 491a80a4b82SWu Hao return afu_mmio_region_add(dev_get_platdata(&pdev->dev), 492a80a4b82SWu Hao DFL_PORT_REGION_INDEX_AFU, 493a80a4b82SWu Hao resource_size(res), res->start, 494a80a4b82SWu Hao DFL_PORT_REGION_MMAP | DFL_PORT_REGION_READ | 495a80a4b82SWu Hao DFL_PORT_REGION_WRITE); 496857a2622SXiao Guangrong } 497857a2622SXiao Guangrong 49815bbb300SWu Hao static const struct dfl_feature_id port_afu_id_table[] = { 49915bbb300SWu Hao {.id = PORT_FEATURE_ID_AFU,}, 50015bbb300SWu Hao {0,} 50115bbb300SWu Hao }; 50215bbb300SWu Hao 503857a2622SXiao Guangrong static const struct dfl_feature_ops port_afu_ops = { 504857a2622SXiao Guangrong .init = port_afu_init, 505857a2622SXiao Guangrong }; 506857a2622SXiao Guangrong 5071a1527cfSWu Hao static struct dfl_feature_driver port_feature_drvs[] = { 5081a1527cfSWu Hao { 50915bbb300SWu Hao .id_table = port_hdr_id_table, 5101a1527cfSWu Hao .ops = &port_hdr_ops, 5111a1527cfSWu Hao }, 5121a1527cfSWu Hao { 51315bbb300SWu Hao .id_table = port_afu_id_table, 514857a2622SXiao Guangrong .ops = &port_afu_ops, 515857a2622SXiao Guangrong }, 516857a2622SXiao Guangrong { 5171a1527cfSWu Hao .ops = NULL, 5181a1527cfSWu Hao } 5191a1527cfSWu Hao }; 5201a1527cfSWu Hao 5211a1527cfSWu Hao static int afu_open(struct inode *inode, struct file *filp) 5221a1527cfSWu Hao { 5231a1527cfSWu Hao struct platform_device *fdev = dfl_fpga_inode_to_feature_dev(inode); 5241a1527cfSWu Hao struct dfl_feature_platform_data *pdata; 5251a1527cfSWu Hao int ret; 5261a1527cfSWu Hao 5271a1527cfSWu Hao pdata = dev_get_platdata(&fdev->dev); 5281a1527cfSWu Hao if (WARN_ON(!pdata)) 5291a1527cfSWu Hao return -ENODEV; 5301a1527cfSWu Hao 5311a1527cfSWu Hao ret = dfl_feature_dev_use_begin(pdata); 5321a1527cfSWu Hao if (ret) 5331a1527cfSWu Hao return ret; 5341a1527cfSWu Hao 5351a1527cfSWu Hao dev_dbg(&fdev->dev, "Device File Open\n"); 5361a1527cfSWu Hao filp->private_data = fdev; 5371a1527cfSWu Hao 5381a1527cfSWu Hao return 0; 5391a1527cfSWu Hao } 5401a1527cfSWu Hao 5411a1527cfSWu Hao static int afu_release(struct inode *inode, struct file *filp) 5421a1527cfSWu Hao { 5431a1527cfSWu Hao struct platform_device *pdev = filp->private_data; 5441a1527cfSWu Hao struct dfl_feature_platform_data *pdata; 5451a1527cfSWu Hao 5461a1527cfSWu Hao dev_dbg(&pdev->dev, "Device File Release\n"); 5471a1527cfSWu Hao 5481a1527cfSWu Hao pdata = dev_get_platdata(&pdev->dev); 5491a1527cfSWu Hao 550fa8dda1eSWu Hao mutex_lock(&pdata->lock); 551fa8dda1eSWu Hao __port_reset(pdev); 552fa8dda1eSWu Hao afu_dma_region_destroy(pdata); 553fa8dda1eSWu Hao mutex_unlock(&pdata->lock); 554fa8dda1eSWu Hao 5551a1527cfSWu Hao dfl_feature_dev_use_end(pdata); 5561a1527cfSWu Hao 5571a1527cfSWu Hao return 0; 5581a1527cfSWu Hao } 5591a1527cfSWu Hao 5606fd893c4SWu Hao static long afu_ioctl_check_extension(struct dfl_feature_platform_data *pdata, 5616fd893c4SWu Hao unsigned long arg) 5626fd893c4SWu Hao { 5636fd893c4SWu Hao /* No extension support for now */ 5646fd893c4SWu Hao return 0; 5656fd893c4SWu Hao } 5666fd893c4SWu Hao 567857a2622SXiao Guangrong static long 568857a2622SXiao Guangrong afu_ioctl_get_info(struct dfl_feature_platform_data *pdata, void __user *arg) 569857a2622SXiao Guangrong { 570857a2622SXiao Guangrong struct dfl_fpga_port_info info; 571857a2622SXiao Guangrong struct dfl_afu *afu; 572857a2622SXiao Guangrong unsigned long minsz; 573857a2622SXiao Guangrong 574857a2622SXiao Guangrong minsz = offsetofend(struct dfl_fpga_port_info, num_umsgs); 575857a2622SXiao Guangrong 576857a2622SXiao Guangrong if (copy_from_user(&info, arg, minsz)) 577857a2622SXiao Guangrong return -EFAULT; 578857a2622SXiao Guangrong 579857a2622SXiao Guangrong if (info.argsz < minsz) 580857a2622SXiao Guangrong return -EINVAL; 581857a2622SXiao Guangrong 582857a2622SXiao Guangrong mutex_lock(&pdata->lock); 583857a2622SXiao Guangrong afu = dfl_fpga_pdata_get_private(pdata); 584857a2622SXiao Guangrong info.flags = 0; 585857a2622SXiao Guangrong info.num_regions = afu->num_regions; 586857a2622SXiao Guangrong info.num_umsgs = afu->num_umsgs; 587857a2622SXiao Guangrong mutex_unlock(&pdata->lock); 588857a2622SXiao Guangrong 589857a2622SXiao Guangrong if (copy_to_user(arg, &info, sizeof(info))) 590857a2622SXiao Guangrong return -EFAULT; 591857a2622SXiao Guangrong 592857a2622SXiao Guangrong return 0; 593857a2622SXiao Guangrong } 594857a2622SXiao Guangrong 595857a2622SXiao Guangrong static long afu_ioctl_get_region_info(struct dfl_feature_platform_data *pdata, 596857a2622SXiao Guangrong void __user *arg) 597857a2622SXiao Guangrong { 598857a2622SXiao Guangrong struct dfl_fpga_port_region_info rinfo; 599857a2622SXiao Guangrong struct dfl_afu_mmio_region region; 600857a2622SXiao Guangrong unsigned long minsz; 601857a2622SXiao Guangrong long ret; 602857a2622SXiao Guangrong 603857a2622SXiao Guangrong minsz = offsetofend(struct dfl_fpga_port_region_info, offset); 604857a2622SXiao Guangrong 605857a2622SXiao Guangrong if (copy_from_user(&rinfo, arg, minsz)) 606857a2622SXiao Guangrong return -EFAULT; 607857a2622SXiao Guangrong 608857a2622SXiao Guangrong if (rinfo.argsz < minsz || rinfo.padding) 609857a2622SXiao Guangrong return -EINVAL; 610857a2622SXiao Guangrong 611857a2622SXiao Guangrong ret = afu_mmio_region_get_by_index(pdata, rinfo.index, ®ion); 612857a2622SXiao Guangrong if (ret) 613857a2622SXiao Guangrong return ret; 614857a2622SXiao Guangrong 615857a2622SXiao Guangrong rinfo.flags = region.flags; 616857a2622SXiao Guangrong rinfo.size = region.size; 617857a2622SXiao Guangrong rinfo.offset = region.offset; 618857a2622SXiao Guangrong 619857a2622SXiao Guangrong if (copy_to_user(arg, &rinfo, sizeof(rinfo))) 620857a2622SXiao Guangrong return -EFAULT; 621857a2622SXiao Guangrong 622857a2622SXiao Guangrong return 0; 623857a2622SXiao Guangrong } 624857a2622SXiao Guangrong 625fa8dda1eSWu Hao static long 626fa8dda1eSWu Hao afu_ioctl_dma_map(struct dfl_feature_platform_data *pdata, void __user *arg) 627fa8dda1eSWu Hao { 628fa8dda1eSWu Hao struct dfl_fpga_port_dma_map map; 629fa8dda1eSWu Hao unsigned long minsz; 630fa8dda1eSWu Hao long ret; 631fa8dda1eSWu Hao 632fa8dda1eSWu Hao minsz = offsetofend(struct dfl_fpga_port_dma_map, iova); 633fa8dda1eSWu Hao 634fa8dda1eSWu Hao if (copy_from_user(&map, arg, minsz)) 635fa8dda1eSWu Hao return -EFAULT; 636fa8dda1eSWu Hao 637fa8dda1eSWu Hao if (map.argsz < minsz || map.flags) 638fa8dda1eSWu Hao return -EINVAL; 639fa8dda1eSWu Hao 640fa8dda1eSWu Hao ret = afu_dma_map_region(pdata, map.user_addr, map.length, &map.iova); 641fa8dda1eSWu Hao if (ret) 642fa8dda1eSWu Hao return ret; 643fa8dda1eSWu Hao 644fa8dda1eSWu Hao if (copy_to_user(arg, &map, sizeof(map))) { 645fa8dda1eSWu Hao afu_dma_unmap_region(pdata, map.iova); 646fa8dda1eSWu Hao return -EFAULT; 647fa8dda1eSWu Hao } 648fa8dda1eSWu Hao 649fa8dda1eSWu Hao dev_dbg(&pdata->dev->dev, "dma map: ua=%llx, len=%llx, iova=%llx\n", 650fa8dda1eSWu Hao (unsigned long long)map.user_addr, 651fa8dda1eSWu Hao (unsigned long long)map.length, 652fa8dda1eSWu Hao (unsigned long long)map.iova); 653fa8dda1eSWu Hao 654fa8dda1eSWu Hao return 0; 655fa8dda1eSWu Hao } 656fa8dda1eSWu Hao 657fa8dda1eSWu Hao static long 658fa8dda1eSWu Hao afu_ioctl_dma_unmap(struct dfl_feature_platform_data *pdata, void __user *arg) 659fa8dda1eSWu Hao { 660fa8dda1eSWu Hao struct dfl_fpga_port_dma_unmap unmap; 661fa8dda1eSWu Hao unsigned long minsz; 662fa8dda1eSWu Hao 663fa8dda1eSWu Hao minsz = offsetofend(struct dfl_fpga_port_dma_unmap, iova); 664fa8dda1eSWu Hao 665fa8dda1eSWu Hao if (copy_from_user(&unmap, arg, minsz)) 666fa8dda1eSWu Hao return -EFAULT; 667fa8dda1eSWu Hao 668fa8dda1eSWu Hao if (unmap.argsz < minsz || unmap.flags) 669fa8dda1eSWu Hao return -EINVAL; 670fa8dda1eSWu Hao 671fa8dda1eSWu Hao return afu_dma_unmap_region(pdata, unmap.iova); 672fa8dda1eSWu Hao } 673fa8dda1eSWu Hao 6741a1527cfSWu Hao static long afu_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 6751a1527cfSWu Hao { 6761a1527cfSWu Hao struct platform_device *pdev = filp->private_data; 6771a1527cfSWu Hao struct dfl_feature_platform_data *pdata; 6781a1527cfSWu Hao struct dfl_feature *f; 6791a1527cfSWu Hao long ret; 6801a1527cfSWu Hao 6811a1527cfSWu Hao dev_dbg(&pdev->dev, "%s cmd 0x%x\n", __func__, cmd); 6821a1527cfSWu Hao 6831a1527cfSWu Hao pdata = dev_get_platdata(&pdev->dev); 6841a1527cfSWu Hao 6851a1527cfSWu Hao switch (cmd) { 6866fd893c4SWu Hao case DFL_FPGA_GET_API_VERSION: 6876fd893c4SWu Hao return DFL_FPGA_API_VERSION; 6886fd893c4SWu Hao case DFL_FPGA_CHECK_EXTENSION: 6896fd893c4SWu Hao return afu_ioctl_check_extension(pdata, arg); 690857a2622SXiao Guangrong case DFL_FPGA_PORT_GET_INFO: 691857a2622SXiao Guangrong return afu_ioctl_get_info(pdata, (void __user *)arg); 692857a2622SXiao Guangrong case DFL_FPGA_PORT_GET_REGION_INFO: 693857a2622SXiao Guangrong return afu_ioctl_get_region_info(pdata, (void __user *)arg); 694fa8dda1eSWu Hao case DFL_FPGA_PORT_DMA_MAP: 695fa8dda1eSWu Hao return afu_ioctl_dma_map(pdata, (void __user *)arg); 696fa8dda1eSWu Hao case DFL_FPGA_PORT_DMA_UNMAP: 697fa8dda1eSWu Hao return afu_ioctl_dma_unmap(pdata, (void __user *)arg); 6981a1527cfSWu Hao default: 6991a1527cfSWu Hao /* 7001a1527cfSWu Hao * Let sub-feature's ioctl function to handle the cmd 7011a1527cfSWu Hao * Sub-feature's ioctl returns -ENODEV when cmd is not 7021a1527cfSWu Hao * handled in this sub feature, and returns 0 and other 7031a1527cfSWu Hao * error code if cmd is handled. 7041a1527cfSWu Hao */ 7051a1527cfSWu Hao dfl_fpga_dev_for_each_feature(pdata, f) 7061a1527cfSWu Hao if (f->ops && f->ops->ioctl) { 7071a1527cfSWu Hao ret = f->ops->ioctl(pdev, f, cmd, arg); 7081a1527cfSWu Hao if (ret != -ENODEV) 7091a1527cfSWu Hao return ret; 7101a1527cfSWu Hao } 7111a1527cfSWu Hao } 7121a1527cfSWu Hao 7131a1527cfSWu Hao return -EINVAL; 7141a1527cfSWu Hao } 7151a1527cfSWu Hao 716857a2622SXiao Guangrong static int afu_mmap(struct file *filp, struct vm_area_struct *vma) 717857a2622SXiao Guangrong { 718857a2622SXiao Guangrong struct platform_device *pdev = filp->private_data; 719857a2622SXiao Guangrong struct dfl_feature_platform_data *pdata; 720857a2622SXiao Guangrong u64 size = vma->vm_end - vma->vm_start; 721857a2622SXiao Guangrong struct dfl_afu_mmio_region region; 722857a2622SXiao Guangrong u64 offset; 723857a2622SXiao Guangrong int ret; 724857a2622SXiao Guangrong 725857a2622SXiao Guangrong if (!(vma->vm_flags & VM_SHARED)) 726857a2622SXiao Guangrong return -EINVAL; 727857a2622SXiao Guangrong 728857a2622SXiao Guangrong pdata = dev_get_platdata(&pdev->dev); 729857a2622SXiao Guangrong 730857a2622SXiao Guangrong offset = vma->vm_pgoff << PAGE_SHIFT; 731857a2622SXiao Guangrong ret = afu_mmio_region_get_by_offset(pdata, offset, size, ®ion); 732857a2622SXiao Guangrong if (ret) 733857a2622SXiao Guangrong return ret; 734857a2622SXiao Guangrong 735857a2622SXiao Guangrong if (!(region.flags & DFL_PORT_REGION_MMAP)) 736857a2622SXiao Guangrong return -EINVAL; 737857a2622SXiao Guangrong 738857a2622SXiao Guangrong if ((vma->vm_flags & VM_READ) && !(region.flags & DFL_PORT_REGION_READ)) 739857a2622SXiao Guangrong return -EPERM; 740857a2622SXiao Guangrong 741857a2622SXiao Guangrong if ((vma->vm_flags & VM_WRITE) && 742857a2622SXiao Guangrong !(region.flags & DFL_PORT_REGION_WRITE)) 743857a2622SXiao Guangrong return -EPERM; 744857a2622SXiao Guangrong 745857a2622SXiao Guangrong vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 746857a2622SXiao Guangrong 747857a2622SXiao Guangrong return remap_pfn_range(vma, vma->vm_start, 748857a2622SXiao Guangrong (region.phys + (offset - region.offset)) >> PAGE_SHIFT, 749857a2622SXiao Guangrong size, vma->vm_page_prot); 750857a2622SXiao Guangrong } 751857a2622SXiao Guangrong 7521a1527cfSWu Hao static const struct file_operations afu_fops = { 7531a1527cfSWu Hao .owner = THIS_MODULE, 7541a1527cfSWu Hao .open = afu_open, 7551a1527cfSWu Hao .release = afu_release, 7561a1527cfSWu Hao .unlocked_ioctl = afu_ioctl, 757857a2622SXiao Guangrong .mmap = afu_mmap, 7581a1527cfSWu Hao }; 7591a1527cfSWu Hao 760857a2622SXiao Guangrong static int afu_dev_init(struct platform_device *pdev) 761857a2622SXiao Guangrong { 762857a2622SXiao Guangrong struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); 763857a2622SXiao Guangrong struct dfl_afu *afu; 764857a2622SXiao Guangrong 765857a2622SXiao Guangrong afu = devm_kzalloc(&pdev->dev, sizeof(*afu), GFP_KERNEL); 766857a2622SXiao Guangrong if (!afu) 767857a2622SXiao Guangrong return -ENOMEM; 768857a2622SXiao Guangrong 769857a2622SXiao Guangrong afu->pdata = pdata; 770857a2622SXiao Guangrong 771857a2622SXiao Guangrong mutex_lock(&pdata->lock); 772857a2622SXiao Guangrong dfl_fpga_pdata_set_private(pdata, afu); 773857a2622SXiao Guangrong afu_mmio_region_init(pdata); 774fa8dda1eSWu Hao afu_dma_region_init(pdata); 775857a2622SXiao Guangrong mutex_unlock(&pdata->lock); 776857a2622SXiao Guangrong 777857a2622SXiao Guangrong return 0; 778857a2622SXiao Guangrong } 779857a2622SXiao Guangrong 780857a2622SXiao Guangrong static int afu_dev_destroy(struct platform_device *pdev) 781857a2622SXiao Guangrong { 782857a2622SXiao Guangrong struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); 783857a2622SXiao Guangrong struct dfl_afu *afu; 784857a2622SXiao Guangrong 785857a2622SXiao Guangrong mutex_lock(&pdata->lock); 786857a2622SXiao Guangrong afu = dfl_fpga_pdata_get_private(pdata); 787857a2622SXiao Guangrong afu_mmio_region_destroy(pdata); 788fa8dda1eSWu Hao afu_dma_region_destroy(pdata); 789857a2622SXiao Guangrong dfl_fpga_pdata_set_private(pdata, NULL); 790857a2622SXiao Guangrong mutex_unlock(&pdata->lock); 791857a2622SXiao Guangrong 792857a2622SXiao Guangrong return 0; 793857a2622SXiao Guangrong } 794857a2622SXiao Guangrong 79547c1b19cSWu Hao static int port_enable_set(struct platform_device *pdev, bool enable) 79647c1b19cSWu Hao { 79747c1b19cSWu Hao struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); 79847c1b19cSWu Hao int ret = 0; 79947c1b19cSWu Hao 80047c1b19cSWu Hao mutex_lock(&pdata->lock); 80147c1b19cSWu Hao if (enable) 80247c1b19cSWu Hao port_enable(pdev); 80347c1b19cSWu Hao else 80447c1b19cSWu Hao ret = port_disable(pdev); 80547c1b19cSWu Hao mutex_unlock(&pdata->lock); 80647c1b19cSWu Hao 80747c1b19cSWu Hao return ret; 80847c1b19cSWu Hao } 80947c1b19cSWu Hao 81047c1b19cSWu Hao static struct dfl_fpga_port_ops afu_port_ops = { 81147c1b19cSWu Hao .name = DFL_FPGA_FEATURE_DEV_PORT, 81247c1b19cSWu Hao .owner = THIS_MODULE, 81347c1b19cSWu Hao .get_id = port_get_id, 81447c1b19cSWu Hao .enable_set = port_enable_set, 81547c1b19cSWu Hao }; 81647c1b19cSWu Hao 8171a1527cfSWu Hao static int afu_probe(struct platform_device *pdev) 8181a1527cfSWu Hao { 8191a1527cfSWu Hao int ret; 8201a1527cfSWu Hao 8211a1527cfSWu Hao dev_dbg(&pdev->dev, "%s\n", __func__); 8221a1527cfSWu Hao 823857a2622SXiao Guangrong ret = afu_dev_init(pdev); 824857a2622SXiao Guangrong if (ret) 825857a2622SXiao Guangrong goto exit; 826857a2622SXiao Guangrong 8271a1527cfSWu Hao ret = dfl_fpga_dev_feature_init(pdev, port_feature_drvs); 8281a1527cfSWu Hao if (ret) 829857a2622SXiao Guangrong goto dev_destroy; 8301a1527cfSWu Hao 8311a1527cfSWu Hao ret = dfl_fpga_dev_ops_register(pdev, &afu_fops, THIS_MODULE); 832857a2622SXiao Guangrong if (ret) { 8331a1527cfSWu Hao dfl_fpga_dev_feature_uinit(pdev); 834857a2622SXiao Guangrong goto dev_destroy; 835857a2622SXiao Guangrong } 8361a1527cfSWu Hao 837857a2622SXiao Guangrong return 0; 838857a2622SXiao Guangrong 839857a2622SXiao Guangrong dev_destroy: 840857a2622SXiao Guangrong afu_dev_destroy(pdev); 841857a2622SXiao Guangrong exit: 8421a1527cfSWu Hao return ret; 8431a1527cfSWu Hao } 8441a1527cfSWu Hao 8451a1527cfSWu Hao static int afu_remove(struct platform_device *pdev) 8461a1527cfSWu Hao { 8471a1527cfSWu Hao dev_dbg(&pdev->dev, "%s\n", __func__); 8481a1527cfSWu Hao 8491a1527cfSWu Hao dfl_fpga_dev_ops_unregister(pdev); 8501a1527cfSWu Hao dfl_fpga_dev_feature_uinit(pdev); 851857a2622SXiao Guangrong afu_dev_destroy(pdev); 8521a1527cfSWu Hao 8531a1527cfSWu Hao return 0; 8541a1527cfSWu Hao } 8551a1527cfSWu Hao 856a80a4b82SWu Hao static const struct attribute_group *afu_dev_groups[] = { 857a80a4b82SWu Hao &port_hdr_group, 858a80a4b82SWu Hao &port_afu_group, 859a80a4b82SWu Hao NULL 860a80a4b82SWu Hao }; 861a80a4b82SWu Hao 8621a1527cfSWu Hao static struct platform_driver afu_driver = { 8631a1527cfSWu Hao .driver = { 8641a1527cfSWu Hao .name = DFL_FPGA_FEATURE_DEV_PORT, 865a80a4b82SWu Hao .dev_groups = afu_dev_groups, 8661a1527cfSWu Hao }, 8671a1527cfSWu Hao .probe = afu_probe, 8681a1527cfSWu Hao .remove = afu_remove, 8691a1527cfSWu Hao }; 8701a1527cfSWu Hao 87147c1b19cSWu Hao static int __init afu_init(void) 87247c1b19cSWu Hao { 87347c1b19cSWu Hao int ret; 87447c1b19cSWu Hao 87547c1b19cSWu Hao dfl_fpga_port_ops_add(&afu_port_ops); 87647c1b19cSWu Hao 87747c1b19cSWu Hao ret = platform_driver_register(&afu_driver); 87847c1b19cSWu Hao if (ret) 87947c1b19cSWu Hao dfl_fpga_port_ops_del(&afu_port_ops); 88047c1b19cSWu Hao 88147c1b19cSWu Hao return ret; 88247c1b19cSWu Hao } 88347c1b19cSWu Hao 88447c1b19cSWu Hao static void __exit afu_exit(void) 88547c1b19cSWu Hao { 88647c1b19cSWu Hao platform_driver_unregister(&afu_driver); 88747c1b19cSWu Hao 88847c1b19cSWu Hao dfl_fpga_port_ops_del(&afu_port_ops); 88947c1b19cSWu Hao } 89047c1b19cSWu Hao 89147c1b19cSWu Hao module_init(afu_init); 89247c1b19cSWu Hao module_exit(afu_exit); 8931a1527cfSWu Hao 8941a1527cfSWu Hao MODULE_DESCRIPTION("FPGA Accelerated Function Unit driver"); 8951a1527cfSWu Hao MODULE_AUTHOR("Intel Corporation"); 8961a1527cfSWu Hao MODULE_LICENSE("GPL v2"); 8971a1527cfSWu Hao MODULE_ALIAS("platform:dfl-port"); 898