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 /** 2595844372SWu Hao * __afu_port_enable - enable a port by clear reset 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. 3095844372SWu Hao * __afu_port_enable function should only be used after __afu_port_disable 3195844372SWu Hao * function. 3295844372SWu Hao * 3395844372SWu Hao * The caller needs to hold lock for protection. 3447c1b19cSWu Hao */ 3595844372SWu Hao void __afu_port_enable(struct platform_device *pdev) 3647c1b19cSWu Hao { 3747c1b19cSWu Hao struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); 3847c1b19cSWu Hao void __iomem *base; 3947c1b19cSWu Hao u64 v; 4047c1b19cSWu Hao 4147c1b19cSWu Hao WARN_ON(!pdata->disable_count); 4247c1b19cSWu Hao 4347c1b19cSWu Hao if (--pdata->disable_count != 0) 4447c1b19cSWu Hao return; 4547c1b19cSWu Hao 4647c1b19cSWu Hao base = dfl_get_feature_ioaddr_by_id(&pdev->dev, PORT_FEATURE_ID_HEADER); 4747c1b19cSWu Hao 4847c1b19cSWu Hao /* Clear port soft reset */ 4947c1b19cSWu Hao v = readq(base + PORT_HDR_CTRL); 5047c1b19cSWu Hao v &= ~PORT_CTRL_SFTRST; 5147c1b19cSWu Hao writeq(v, base + PORT_HDR_CTRL); 5247c1b19cSWu Hao } 5347c1b19cSWu Hao 5447c1b19cSWu Hao #define RST_POLL_INVL 10 /* us */ 5547c1b19cSWu Hao #define RST_POLL_TIMEOUT 1000 /* us */ 5647c1b19cSWu Hao 5747c1b19cSWu Hao /** 5895844372SWu Hao * __afu_port_disable - disable a port by hold reset 5947c1b19cSWu Hao * @pdev: port platform device. 6047c1b19cSWu Hao * 6195844372SWu Hao * Disable Port by setting the port soft reset bit, it puts the port into reset. 6295844372SWu Hao * 6395844372SWu Hao * The caller needs to hold lock for protection. 6447c1b19cSWu Hao */ 6595844372SWu Hao int __afu_port_disable(struct platform_device *pdev) 6647c1b19cSWu Hao { 6747c1b19cSWu Hao struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); 6847c1b19cSWu Hao void __iomem *base; 6947c1b19cSWu Hao u64 v; 7047c1b19cSWu Hao 7147c1b19cSWu Hao if (pdata->disable_count++ != 0) 7247c1b19cSWu Hao return 0; 7347c1b19cSWu Hao 7447c1b19cSWu Hao base = dfl_get_feature_ioaddr_by_id(&pdev->dev, PORT_FEATURE_ID_HEADER); 7547c1b19cSWu Hao 7647c1b19cSWu Hao /* Set port soft reset */ 7747c1b19cSWu Hao v = readq(base + PORT_HDR_CTRL); 7847c1b19cSWu Hao v |= PORT_CTRL_SFTRST; 7947c1b19cSWu Hao writeq(v, base + PORT_HDR_CTRL); 8047c1b19cSWu Hao 8147c1b19cSWu Hao /* 8247c1b19cSWu Hao * HW sets ack bit to 1 when all outstanding requests have been drained 8347c1b19cSWu Hao * on this port and minimum soft reset pulse width has elapsed. 8447c1b19cSWu Hao * Driver polls port_soft_reset_ack to determine if reset done by HW. 8547c1b19cSWu Hao */ 8647c1b19cSWu Hao if (readq_poll_timeout(base + PORT_HDR_CTRL, v, v & PORT_CTRL_SFTRST, 8747c1b19cSWu Hao RST_POLL_INVL, RST_POLL_TIMEOUT)) { 8847c1b19cSWu Hao dev_err(&pdev->dev, "timeout, fail to reset device\n"); 8947c1b19cSWu Hao return -ETIMEDOUT; 9047c1b19cSWu Hao } 9147c1b19cSWu Hao 9247c1b19cSWu Hao return 0; 9347c1b19cSWu Hao } 9447c1b19cSWu Hao 95e4664c0eSWu Hao /* 96e4664c0eSWu Hao * This function resets the FPGA Port and its accelerator (AFU) by function 97e4664c0eSWu Hao * __port_disable and __port_enable (set port soft reset bit and then clear 98e4664c0eSWu Hao * it). Userspace can do Port reset at any time, e.g. during DMA or Partial 99e4664c0eSWu Hao * Reconfiguration. But it should never cause any system level issue, only 100e4664c0eSWu Hao * functional failure (e.g. DMA or PR operation failure) and be recoverable 101e4664c0eSWu Hao * from the failure. 102e4664c0eSWu Hao * 103e4664c0eSWu Hao * Note: the accelerator (AFU) is not accessible when its port is in reset 104e4664c0eSWu Hao * (disabled). Any attempts on MMIO access to AFU while in reset, will 105e4664c0eSWu Hao * result errors reported via port error reporting sub feature (if present). 106e4664c0eSWu Hao */ 107e4664c0eSWu Hao static int __port_reset(struct platform_device *pdev) 108e4664c0eSWu Hao { 109e4664c0eSWu Hao int ret; 110e4664c0eSWu Hao 11195844372SWu Hao ret = __afu_port_disable(pdev); 112e4664c0eSWu Hao if (!ret) 11395844372SWu Hao __afu_port_enable(pdev); 114e4664c0eSWu Hao 115e4664c0eSWu Hao return ret; 116e4664c0eSWu Hao } 117e4664c0eSWu Hao 118e4664c0eSWu Hao static int port_reset(struct platform_device *pdev) 119e4664c0eSWu Hao { 120e4664c0eSWu Hao struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); 121e4664c0eSWu Hao int ret; 122e4664c0eSWu Hao 123e4664c0eSWu Hao mutex_lock(&pdata->lock); 124e4664c0eSWu Hao ret = __port_reset(pdev); 125e4664c0eSWu Hao mutex_unlock(&pdata->lock); 126e4664c0eSWu Hao 127e4664c0eSWu Hao return ret; 128e4664c0eSWu Hao } 129e4664c0eSWu Hao 13047c1b19cSWu Hao static int port_get_id(struct platform_device *pdev) 13147c1b19cSWu Hao { 13247c1b19cSWu Hao void __iomem *base; 13347c1b19cSWu Hao 13447c1b19cSWu Hao base = dfl_get_feature_ioaddr_by_id(&pdev->dev, PORT_FEATURE_ID_HEADER); 13547c1b19cSWu Hao 13647c1b19cSWu Hao return FIELD_GET(PORT_CAP_PORT_NUM, readq(base + PORT_HDR_CAP)); 13747c1b19cSWu Hao } 13847c1b19cSWu Hao 139e4664c0eSWu Hao static ssize_t 140e4664c0eSWu Hao id_show(struct device *dev, struct device_attribute *attr, char *buf) 141e4664c0eSWu Hao { 142e4664c0eSWu Hao int id = port_get_id(to_platform_device(dev)); 143e4664c0eSWu Hao 144e4664c0eSWu Hao return scnprintf(buf, PAGE_SIZE, "%d\n", id); 145e4664c0eSWu Hao } 146e4664c0eSWu Hao static DEVICE_ATTR_RO(id); 147e4664c0eSWu Hao 148d2ad5ac1SWu Hao static ssize_t 149d2ad5ac1SWu Hao ltr_show(struct device *dev, struct device_attribute *attr, char *buf) 150d2ad5ac1SWu Hao { 151d2ad5ac1SWu Hao struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); 152d2ad5ac1SWu Hao void __iomem *base; 153d2ad5ac1SWu Hao u64 v; 154d2ad5ac1SWu Hao 155d2ad5ac1SWu Hao base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); 156d2ad5ac1SWu Hao 157d2ad5ac1SWu Hao mutex_lock(&pdata->lock); 158d2ad5ac1SWu Hao v = readq(base + PORT_HDR_CTRL); 159d2ad5ac1SWu Hao mutex_unlock(&pdata->lock); 160d2ad5ac1SWu Hao 161d2ad5ac1SWu Hao return sprintf(buf, "%x\n", (u8)FIELD_GET(PORT_CTRL_LATENCY, v)); 162d2ad5ac1SWu Hao } 163d2ad5ac1SWu Hao 164d2ad5ac1SWu Hao static ssize_t 165d2ad5ac1SWu Hao ltr_store(struct device *dev, struct device_attribute *attr, 166d2ad5ac1SWu Hao const char *buf, size_t count) 167d2ad5ac1SWu Hao { 168d2ad5ac1SWu Hao struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); 169d2ad5ac1SWu Hao void __iomem *base; 170d2ad5ac1SWu Hao bool ltr; 171d2ad5ac1SWu Hao u64 v; 172d2ad5ac1SWu Hao 173d2ad5ac1SWu Hao if (kstrtobool(buf, <r)) 174d2ad5ac1SWu Hao return -EINVAL; 175d2ad5ac1SWu Hao 176d2ad5ac1SWu Hao base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); 177d2ad5ac1SWu Hao 178d2ad5ac1SWu Hao mutex_lock(&pdata->lock); 179d2ad5ac1SWu Hao v = readq(base + PORT_HDR_CTRL); 180d2ad5ac1SWu Hao v &= ~PORT_CTRL_LATENCY; 181d2ad5ac1SWu Hao v |= FIELD_PREP(PORT_CTRL_LATENCY, ltr ? 1 : 0); 182d2ad5ac1SWu Hao writeq(v, base + PORT_HDR_CTRL); 183d2ad5ac1SWu Hao mutex_unlock(&pdata->lock); 184d2ad5ac1SWu Hao 185d2ad5ac1SWu Hao return count; 186d2ad5ac1SWu Hao } 187d2ad5ac1SWu Hao static DEVICE_ATTR_RW(ltr); 188d2ad5ac1SWu Hao 189d2ad5ac1SWu Hao static ssize_t 190d2ad5ac1SWu Hao ap1_event_show(struct device *dev, struct device_attribute *attr, char *buf) 191d2ad5ac1SWu Hao { 192d2ad5ac1SWu Hao struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); 193d2ad5ac1SWu Hao void __iomem *base; 194d2ad5ac1SWu Hao u64 v; 195d2ad5ac1SWu Hao 196d2ad5ac1SWu Hao base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); 197d2ad5ac1SWu Hao 198d2ad5ac1SWu Hao mutex_lock(&pdata->lock); 199d2ad5ac1SWu Hao v = readq(base + PORT_HDR_STS); 200d2ad5ac1SWu Hao mutex_unlock(&pdata->lock); 201d2ad5ac1SWu Hao 202d2ad5ac1SWu Hao return sprintf(buf, "%x\n", (u8)FIELD_GET(PORT_STS_AP1_EVT, v)); 203d2ad5ac1SWu Hao } 204d2ad5ac1SWu Hao 205d2ad5ac1SWu Hao static ssize_t 206d2ad5ac1SWu Hao ap1_event_store(struct device *dev, struct device_attribute *attr, 207d2ad5ac1SWu Hao const char *buf, size_t count) 208d2ad5ac1SWu Hao { 209d2ad5ac1SWu Hao struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); 210d2ad5ac1SWu Hao void __iomem *base; 211d2ad5ac1SWu Hao bool clear; 212d2ad5ac1SWu Hao 213d2ad5ac1SWu Hao if (kstrtobool(buf, &clear) || !clear) 214d2ad5ac1SWu Hao return -EINVAL; 215d2ad5ac1SWu Hao 216d2ad5ac1SWu Hao base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); 217d2ad5ac1SWu Hao 218d2ad5ac1SWu Hao mutex_lock(&pdata->lock); 219d2ad5ac1SWu Hao writeq(PORT_STS_AP1_EVT, base + PORT_HDR_STS); 220d2ad5ac1SWu Hao mutex_unlock(&pdata->lock); 221d2ad5ac1SWu Hao 222d2ad5ac1SWu Hao return count; 223d2ad5ac1SWu Hao } 224d2ad5ac1SWu Hao static DEVICE_ATTR_RW(ap1_event); 225d2ad5ac1SWu Hao 226d2ad5ac1SWu Hao static ssize_t 227d2ad5ac1SWu Hao ap2_event_show(struct device *dev, struct device_attribute *attr, 228d2ad5ac1SWu Hao char *buf) 229d2ad5ac1SWu Hao { 230d2ad5ac1SWu Hao struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); 231d2ad5ac1SWu Hao void __iomem *base; 232d2ad5ac1SWu Hao u64 v; 233d2ad5ac1SWu Hao 234d2ad5ac1SWu Hao base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); 235d2ad5ac1SWu Hao 236d2ad5ac1SWu Hao mutex_lock(&pdata->lock); 237d2ad5ac1SWu Hao v = readq(base + PORT_HDR_STS); 238d2ad5ac1SWu Hao mutex_unlock(&pdata->lock); 239d2ad5ac1SWu Hao 240d2ad5ac1SWu Hao return sprintf(buf, "%x\n", (u8)FIELD_GET(PORT_STS_AP2_EVT, v)); 241d2ad5ac1SWu Hao } 242d2ad5ac1SWu Hao 243d2ad5ac1SWu Hao static ssize_t 244d2ad5ac1SWu Hao ap2_event_store(struct device *dev, struct device_attribute *attr, 245d2ad5ac1SWu Hao const char *buf, size_t count) 246d2ad5ac1SWu Hao { 247d2ad5ac1SWu Hao struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); 248d2ad5ac1SWu Hao void __iomem *base; 249d2ad5ac1SWu Hao bool clear; 250d2ad5ac1SWu Hao 251d2ad5ac1SWu Hao if (kstrtobool(buf, &clear) || !clear) 252d2ad5ac1SWu Hao return -EINVAL; 253d2ad5ac1SWu Hao 254d2ad5ac1SWu Hao base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); 255d2ad5ac1SWu Hao 256d2ad5ac1SWu Hao mutex_lock(&pdata->lock); 257d2ad5ac1SWu Hao writeq(PORT_STS_AP2_EVT, base + PORT_HDR_STS); 258d2ad5ac1SWu Hao mutex_unlock(&pdata->lock); 259d2ad5ac1SWu Hao 260d2ad5ac1SWu Hao return count; 261d2ad5ac1SWu Hao } 262d2ad5ac1SWu Hao static DEVICE_ATTR_RW(ap2_event); 263d2ad5ac1SWu Hao 264d2ad5ac1SWu Hao static ssize_t 265d2ad5ac1SWu Hao power_state_show(struct device *dev, struct device_attribute *attr, char *buf) 266d2ad5ac1SWu Hao { 267d2ad5ac1SWu Hao struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); 268d2ad5ac1SWu Hao void __iomem *base; 269d2ad5ac1SWu Hao u64 v; 270d2ad5ac1SWu Hao 271d2ad5ac1SWu Hao base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); 272d2ad5ac1SWu Hao 273d2ad5ac1SWu Hao mutex_lock(&pdata->lock); 274d2ad5ac1SWu Hao v = readq(base + PORT_HDR_STS); 275d2ad5ac1SWu Hao mutex_unlock(&pdata->lock); 276d2ad5ac1SWu Hao 277d2ad5ac1SWu Hao return sprintf(buf, "0x%x\n", (u8)FIELD_GET(PORT_STS_PWR_STATE, v)); 278d2ad5ac1SWu Hao } 279d2ad5ac1SWu Hao static DEVICE_ATTR_RO(power_state); 280d2ad5ac1SWu Hao 281f09991adSWu Hao static ssize_t 282f09991adSWu Hao userclk_freqcmd_store(struct device *dev, struct device_attribute *attr, 283f09991adSWu Hao const char *buf, size_t count) 284f09991adSWu Hao { 285f09991adSWu Hao struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); 286f09991adSWu Hao u64 userclk_freq_cmd; 287f09991adSWu Hao void __iomem *base; 288f09991adSWu Hao 289f09991adSWu Hao if (kstrtou64(buf, 0, &userclk_freq_cmd)) 290f09991adSWu Hao return -EINVAL; 291f09991adSWu Hao 292f09991adSWu Hao base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); 293f09991adSWu Hao 294f09991adSWu Hao mutex_lock(&pdata->lock); 295f09991adSWu Hao writeq(userclk_freq_cmd, base + PORT_HDR_USRCLK_CMD0); 296f09991adSWu Hao mutex_unlock(&pdata->lock); 297f09991adSWu Hao 298f09991adSWu Hao return count; 299f09991adSWu Hao } 300f09991adSWu Hao static DEVICE_ATTR_WO(userclk_freqcmd); 301f09991adSWu Hao 302f09991adSWu Hao static ssize_t 303f09991adSWu Hao userclk_freqcntrcmd_store(struct device *dev, struct device_attribute *attr, 304f09991adSWu Hao const char *buf, size_t count) 305f09991adSWu Hao { 306f09991adSWu Hao struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); 307f09991adSWu Hao u64 userclk_freqcntr_cmd; 308f09991adSWu Hao void __iomem *base; 309f09991adSWu Hao 310f09991adSWu Hao if (kstrtou64(buf, 0, &userclk_freqcntr_cmd)) 311f09991adSWu Hao return -EINVAL; 312f09991adSWu Hao 313f09991adSWu Hao base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); 314f09991adSWu Hao 315f09991adSWu Hao mutex_lock(&pdata->lock); 316f09991adSWu Hao writeq(userclk_freqcntr_cmd, base + PORT_HDR_USRCLK_CMD1); 317f09991adSWu Hao mutex_unlock(&pdata->lock); 318f09991adSWu Hao 319f09991adSWu Hao return count; 320f09991adSWu Hao } 321f09991adSWu Hao static DEVICE_ATTR_WO(userclk_freqcntrcmd); 322f09991adSWu Hao 323f09991adSWu Hao static ssize_t 324f09991adSWu Hao userclk_freqsts_show(struct device *dev, struct device_attribute *attr, 325f09991adSWu Hao char *buf) 326f09991adSWu Hao { 327f09991adSWu Hao struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); 328f09991adSWu Hao u64 userclk_freqsts; 329f09991adSWu Hao void __iomem *base; 330f09991adSWu Hao 331f09991adSWu Hao base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); 332f09991adSWu Hao 333f09991adSWu Hao mutex_lock(&pdata->lock); 334f09991adSWu Hao userclk_freqsts = readq(base + PORT_HDR_USRCLK_STS0); 335f09991adSWu Hao mutex_unlock(&pdata->lock); 336f09991adSWu Hao 337f09991adSWu Hao return sprintf(buf, "0x%llx\n", (unsigned long long)userclk_freqsts); 338f09991adSWu Hao } 339f09991adSWu Hao static DEVICE_ATTR_RO(userclk_freqsts); 340f09991adSWu Hao 341f09991adSWu Hao static ssize_t 342f09991adSWu Hao userclk_freqcntrsts_show(struct device *dev, struct device_attribute *attr, 343f09991adSWu Hao char *buf) 344f09991adSWu Hao { 345f09991adSWu Hao struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); 346f09991adSWu Hao u64 userclk_freqcntrsts; 347f09991adSWu Hao void __iomem *base; 348f09991adSWu Hao 349f09991adSWu Hao base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); 350f09991adSWu Hao 351f09991adSWu Hao mutex_lock(&pdata->lock); 352f09991adSWu Hao userclk_freqcntrsts = readq(base + PORT_HDR_USRCLK_STS1); 353f09991adSWu Hao mutex_unlock(&pdata->lock); 354f09991adSWu Hao 355f09991adSWu Hao return sprintf(buf, "0x%llx\n", 356f09991adSWu Hao (unsigned long long)userclk_freqcntrsts); 357f09991adSWu Hao } 358f09991adSWu Hao static DEVICE_ATTR_RO(userclk_freqcntrsts); 359f09991adSWu Hao 360dcfecd4dSGreg Kroah-Hartman static struct attribute *port_hdr_attrs[] = { 361e4664c0eSWu Hao &dev_attr_id.attr, 362d2ad5ac1SWu Hao &dev_attr_ltr.attr, 363d2ad5ac1SWu Hao &dev_attr_ap1_event.attr, 364d2ad5ac1SWu Hao &dev_attr_ap2_event.attr, 365d2ad5ac1SWu Hao &dev_attr_power_state.attr, 366f09991adSWu Hao &dev_attr_userclk_freqcmd.attr, 367f09991adSWu Hao &dev_attr_userclk_freqcntrcmd.attr, 368f09991adSWu Hao &dev_attr_userclk_freqsts.attr, 369f09991adSWu Hao &dev_attr_userclk_freqcntrsts.attr, 370e4664c0eSWu Hao NULL, 371e4664c0eSWu Hao }; 372a80a4b82SWu Hao 373f09991adSWu Hao static umode_t port_hdr_attrs_visible(struct kobject *kobj, 374f09991adSWu Hao struct attribute *attr, int n) 375f09991adSWu Hao { 376f09991adSWu Hao struct device *dev = kobj_to_dev(kobj); 377f09991adSWu Hao umode_t mode = attr->mode; 378f09991adSWu Hao void __iomem *base; 379f09991adSWu Hao 380f09991adSWu Hao base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); 381f09991adSWu Hao 382f09991adSWu Hao if (dfl_feature_revision(base) > 0) { 383f09991adSWu Hao /* 384f09991adSWu Hao * userclk sysfs interfaces are only visible in case port 385f09991adSWu Hao * revision is 0, as hardware with revision >0 doesn't 386f09991adSWu Hao * support this. 387f09991adSWu Hao */ 388f09991adSWu Hao if (attr == &dev_attr_userclk_freqcmd.attr || 389f09991adSWu Hao attr == &dev_attr_userclk_freqcntrcmd.attr || 390f09991adSWu Hao attr == &dev_attr_userclk_freqsts.attr || 391f09991adSWu Hao attr == &dev_attr_userclk_freqcntrsts.attr) 392f09991adSWu Hao mode = 0; 393f09991adSWu Hao } 394f09991adSWu Hao 395f09991adSWu Hao return mode; 396f09991adSWu Hao } 397f09991adSWu Hao 398a80a4b82SWu Hao static const struct attribute_group port_hdr_group = { 399a80a4b82SWu Hao .attrs = port_hdr_attrs, 400f09991adSWu Hao .is_visible = port_hdr_attrs_visible, 401a80a4b82SWu Hao }; 402e4664c0eSWu Hao 4031a1527cfSWu Hao static int port_hdr_init(struct platform_device *pdev, 4041a1527cfSWu Hao struct dfl_feature *feature) 4051a1527cfSWu Hao { 406e4664c0eSWu Hao port_reset(pdev); 407e4664c0eSWu Hao 408a80a4b82SWu Hao return 0; 409e4664c0eSWu Hao } 410e4664c0eSWu Hao 411e4664c0eSWu Hao static long 412e4664c0eSWu Hao port_hdr_ioctl(struct platform_device *pdev, struct dfl_feature *feature, 413e4664c0eSWu Hao unsigned int cmd, unsigned long arg) 414e4664c0eSWu Hao { 415e4664c0eSWu Hao long ret; 416e4664c0eSWu Hao 417e4664c0eSWu Hao switch (cmd) { 418e4664c0eSWu Hao case DFL_FPGA_PORT_RESET: 419e4664c0eSWu Hao if (!arg) 420e4664c0eSWu Hao ret = port_reset(pdev); 421e4664c0eSWu Hao else 422e4664c0eSWu Hao ret = -EINVAL; 423e4664c0eSWu Hao break; 424e4664c0eSWu Hao default: 425e4664c0eSWu Hao dev_dbg(&pdev->dev, "%x cmd not handled", cmd); 426e4664c0eSWu Hao ret = -ENODEV; 427e4664c0eSWu Hao } 428e4664c0eSWu Hao 429e4664c0eSWu Hao return ret; 4301a1527cfSWu Hao } 4311a1527cfSWu Hao 43215bbb300SWu Hao static const struct dfl_feature_id port_hdr_id_table[] = { 43315bbb300SWu Hao {.id = PORT_FEATURE_ID_HEADER,}, 43415bbb300SWu Hao {0,} 43515bbb300SWu Hao }; 43615bbb300SWu Hao 4371a1527cfSWu Hao static const struct dfl_feature_ops port_hdr_ops = { 4381a1527cfSWu Hao .init = port_hdr_init, 439e4664c0eSWu Hao .ioctl = port_hdr_ioctl, 4401a1527cfSWu Hao }; 4411a1527cfSWu Hao 442857a2622SXiao Guangrong static ssize_t 443857a2622SXiao Guangrong afu_id_show(struct device *dev, struct device_attribute *attr, char *buf) 444857a2622SXiao Guangrong { 445857a2622SXiao Guangrong struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); 446857a2622SXiao Guangrong void __iomem *base; 447857a2622SXiao Guangrong u64 guidl, guidh; 448857a2622SXiao Guangrong 449857a2622SXiao Guangrong base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_AFU); 450857a2622SXiao Guangrong 451857a2622SXiao Guangrong mutex_lock(&pdata->lock); 452857a2622SXiao Guangrong if (pdata->disable_count) { 453857a2622SXiao Guangrong mutex_unlock(&pdata->lock); 454857a2622SXiao Guangrong return -EBUSY; 455857a2622SXiao Guangrong } 456857a2622SXiao Guangrong 457857a2622SXiao Guangrong guidl = readq(base + GUID_L); 458857a2622SXiao Guangrong guidh = readq(base + GUID_H); 459857a2622SXiao Guangrong mutex_unlock(&pdata->lock); 460857a2622SXiao Guangrong 461857a2622SXiao Guangrong return scnprintf(buf, PAGE_SIZE, "%016llx%016llx\n", guidh, guidl); 462857a2622SXiao Guangrong } 463857a2622SXiao Guangrong static DEVICE_ATTR_RO(afu_id); 464857a2622SXiao Guangrong 465dcfecd4dSGreg Kroah-Hartman static struct attribute *port_afu_attrs[] = { 466857a2622SXiao Guangrong &dev_attr_afu_id.attr, 467857a2622SXiao Guangrong NULL 468857a2622SXiao Guangrong }; 469a80a4b82SWu Hao 470a80a4b82SWu Hao static umode_t port_afu_attrs_visible(struct kobject *kobj, 471a80a4b82SWu Hao struct attribute *attr, int n) 472a80a4b82SWu Hao { 473a80a4b82SWu Hao struct device *dev = kobj_to_dev(kobj); 474a80a4b82SWu Hao 475a80a4b82SWu Hao /* 476a80a4b82SWu Hao * sysfs entries are visible only if related private feature is 477a80a4b82SWu Hao * enumerated. 478a80a4b82SWu Hao */ 479a80a4b82SWu Hao if (!dfl_get_feature_by_id(dev, PORT_FEATURE_ID_AFU)) 480a80a4b82SWu Hao return 0; 481a80a4b82SWu Hao 482a80a4b82SWu Hao return attr->mode; 483a80a4b82SWu Hao } 484a80a4b82SWu Hao 485a80a4b82SWu Hao static const struct attribute_group port_afu_group = { 486a80a4b82SWu Hao .attrs = port_afu_attrs, 487a80a4b82SWu Hao .is_visible = port_afu_attrs_visible, 488a80a4b82SWu Hao }; 489857a2622SXiao Guangrong 490857a2622SXiao Guangrong static int port_afu_init(struct platform_device *pdev, 491857a2622SXiao Guangrong struct dfl_feature *feature) 492857a2622SXiao Guangrong { 493857a2622SXiao Guangrong struct resource *res = &pdev->resource[feature->resource_index]; 494857a2622SXiao Guangrong 495a80a4b82SWu Hao return afu_mmio_region_add(dev_get_platdata(&pdev->dev), 496a80a4b82SWu Hao DFL_PORT_REGION_INDEX_AFU, 497a80a4b82SWu Hao resource_size(res), res->start, 498a80a4b82SWu Hao DFL_PORT_REGION_MMAP | DFL_PORT_REGION_READ | 499a80a4b82SWu Hao DFL_PORT_REGION_WRITE); 500857a2622SXiao Guangrong } 501857a2622SXiao Guangrong 50215bbb300SWu Hao static const struct dfl_feature_id port_afu_id_table[] = { 50315bbb300SWu Hao {.id = PORT_FEATURE_ID_AFU,}, 50415bbb300SWu Hao {0,} 50515bbb300SWu Hao }; 50615bbb300SWu Hao 507857a2622SXiao Guangrong static const struct dfl_feature_ops port_afu_ops = { 508857a2622SXiao Guangrong .init = port_afu_init, 509857a2622SXiao Guangrong }; 510857a2622SXiao Guangrong 511bd127b81SWu Hao static int port_stp_init(struct platform_device *pdev, 512bd127b81SWu Hao struct dfl_feature *feature) 513bd127b81SWu Hao { 514bd127b81SWu Hao struct resource *res = &pdev->resource[feature->resource_index]; 515bd127b81SWu Hao 516bd127b81SWu Hao return afu_mmio_region_add(dev_get_platdata(&pdev->dev), 517bd127b81SWu Hao DFL_PORT_REGION_INDEX_STP, 518bd127b81SWu Hao resource_size(res), res->start, 519bd127b81SWu Hao DFL_PORT_REGION_MMAP | DFL_PORT_REGION_READ | 520bd127b81SWu Hao DFL_PORT_REGION_WRITE); 521bd127b81SWu Hao } 522bd127b81SWu Hao 523bd127b81SWu Hao static const struct dfl_feature_id port_stp_id_table[] = { 524bd127b81SWu Hao {.id = PORT_FEATURE_ID_STP,}, 525bd127b81SWu Hao {0,} 526bd127b81SWu Hao }; 527bd127b81SWu Hao 528bd127b81SWu Hao static const struct dfl_feature_ops port_stp_ops = { 529bd127b81SWu Hao .init = port_stp_init, 530bd127b81SWu Hao }; 531bd127b81SWu Hao 5321a1527cfSWu Hao static struct dfl_feature_driver port_feature_drvs[] = { 5331a1527cfSWu Hao { 53415bbb300SWu Hao .id_table = port_hdr_id_table, 5351a1527cfSWu Hao .ops = &port_hdr_ops, 5361a1527cfSWu Hao }, 5371a1527cfSWu Hao { 53815bbb300SWu Hao .id_table = port_afu_id_table, 539857a2622SXiao Guangrong .ops = &port_afu_ops, 540857a2622SXiao Guangrong }, 541857a2622SXiao Guangrong { 54244d24753SWu Hao .id_table = port_err_id_table, 54344d24753SWu Hao .ops = &port_err_ops, 54444d24753SWu Hao }, 54544d24753SWu Hao { 546bd127b81SWu Hao .id_table = port_stp_id_table, 547bd127b81SWu Hao .ops = &port_stp_ops, 548bd127b81SWu Hao }, 549bd127b81SWu Hao { 5501a1527cfSWu Hao .ops = NULL, 5511a1527cfSWu Hao } 5521a1527cfSWu Hao }; 5531a1527cfSWu Hao 5541a1527cfSWu Hao static int afu_open(struct inode *inode, struct file *filp) 5551a1527cfSWu Hao { 5561a1527cfSWu Hao struct platform_device *fdev = dfl_fpga_inode_to_feature_dev(inode); 5571a1527cfSWu Hao struct dfl_feature_platform_data *pdata; 5581a1527cfSWu Hao int ret; 5591a1527cfSWu Hao 5601a1527cfSWu Hao pdata = dev_get_platdata(&fdev->dev); 5611a1527cfSWu Hao if (WARN_ON(!pdata)) 5621a1527cfSWu Hao return -ENODEV; 5631a1527cfSWu Hao 564b6862193SXu Yilun mutex_lock(&pdata->lock); 565b6862193SXu Yilun ret = dfl_feature_dev_use_begin(pdata, filp->f_flags & O_EXCL); 566b6862193SXu Yilun if (!ret) { 567b6862193SXu Yilun dev_dbg(&fdev->dev, "Device File Opened %d Times\n", 568b6862193SXu Yilun dfl_feature_dev_use_count(pdata)); 5691a1527cfSWu Hao filp->private_data = fdev; 570b6862193SXu Yilun } 571b6862193SXu Yilun mutex_unlock(&pdata->lock); 5721a1527cfSWu Hao 573b6862193SXu Yilun return ret; 5741a1527cfSWu Hao } 5751a1527cfSWu Hao 5761a1527cfSWu Hao static int afu_release(struct inode *inode, struct file *filp) 5771a1527cfSWu Hao { 5781a1527cfSWu Hao struct platform_device *pdev = filp->private_data; 5791a1527cfSWu Hao struct dfl_feature_platform_data *pdata; 5801a1527cfSWu Hao 5811a1527cfSWu Hao dev_dbg(&pdev->dev, "Device File Release\n"); 5821a1527cfSWu Hao 5831a1527cfSWu Hao pdata = dev_get_platdata(&pdev->dev); 5841a1527cfSWu Hao 585fa8dda1eSWu Hao mutex_lock(&pdata->lock); 586b6862193SXu Yilun dfl_feature_dev_use_end(pdata); 587b6862193SXu Yilun 588b6862193SXu Yilun if (!dfl_feature_dev_use_count(pdata)) { 589fa8dda1eSWu Hao __port_reset(pdev); 590fa8dda1eSWu Hao afu_dma_region_destroy(pdata); 591b6862193SXu Yilun } 592fa8dda1eSWu Hao mutex_unlock(&pdata->lock); 593fa8dda1eSWu Hao 5941a1527cfSWu Hao return 0; 5951a1527cfSWu Hao } 5961a1527cfSWu Hao 5976fd893c4SWu Hao static long afu_ioctl_check_extension(struct dfl_feature_platform_data *pdata, 5986fd893c4SWu Hao unsigned long arg) 5996fd893c4SWu Hao { 6006fd893c4SWu Hao /* No extension support for now */ 6016fd893c4SWu Hao return 0; 6026fd893c4SWu Hao } 6036fd893c4SWu Hao 604857a2622SXiao Guangrong static long 605857a2622SXiao Guangrong afu_ioctl_get_info(struct dfl_feature_platform_data *pdata, void __user *arg) 606857a2622SXiao Guangrong { 607857a2622SXiao Guangrong struct dfl_fpga_port_info info; 608857a2622SXiao Guangrong struct dfl_afu *afu; 609857a2622SXiao Guangrong unsigned long minsz; 610857a2622SXiao Guangrong 611857a2622SXiao Guangrong minsz = offsetofend(struct dfl_fpga_port_info, num_umsgs); 612857a2622SXiao Guangrong 613857a2622SXiao Guangrong if (copy_from_user(&info, arg, minsz)) 614857a2622SXiao Guangrong return -EFAULT; 615857a2622SXiao Guangrong 616857a2622SXiao Guangrong if (info.argsz < minsz) 617857a2622SXiao Guangrong return -EINVAL; 618857a2622SXiao Guangrong 619857a2622SXiao Guangrong mutex_lock(&pdata->lock); 620857a2622SXiao Guangrong afu = dfl_fpga_pdata_get_private(pdata); 621857a2622SXiao Guangrong info.flags = 0; 622857a2622SXiao Guangrong info.num_regions = afu->num_regions; 623857a2622SXiao Guangrong info.num_umsgs = afu->num_umsgs; 624857a2622SXiao Guangrong mutex_unlock(&pdata->lock); 625857a2622SXiao Guangrong 626857a2622SXiao Guangrong if (copy_to_user(arg, &info, sizeof(info))) 627857a2622SXiao Guangrong return -EFAULT; 628857a2622SXiao Guangrong 629857a2622SXiao Guangrong return 0; 630857a2622SXiao Guangrong } 631857a2622SXiao Guangrong 632857a2622SXiao Guangrong static long afu_ioctl_get_region_info(struct dfl_feature_platform_data *pdata, 633857a2622SXiao Guangrong void __user *arg) 634857a2622SXiao Guangrong { 635857a2622SXiao Guangrong struct dfl_fpga_port_region_info rinfo; 636857a2622SXiao Guangrong struct dfl_afu_mmio_region region; 637857a2622SXiao Guangrong unsigned long minsz; 638857a2622SXiao Guangrong long ret; 639857a2622SXiao Guangrong 640857a2622SXiao Guangrong minsz = offsetofend(struct dfl_fpga_port_region_info, offset); 641857a2622SXiao Guangrong 642857a2622SXiao Guangrong if (copy_from_user(&rinfo, arg, minsz)) 643857a2622SXiao Guangrong return -EFAULT; 644857a2622SXiao Guangrong 645857a2622SXiao Guangrong if (rinfo.argsz < minsz || rinfo.padding) 646857a2622SXiao Guangrong return -EINVAL; 647857a2622SXiao Guangrong 648857a2622SXiao Guangrong ret = afu_mmio_region_get_by_index(pdata, rinfo.index, ®ion); 649857a2622SXiao Guangrong if (ret) 650857a2622SXiao Guangrong return ret; 651857a2622SXiao Guangrong 652857a2622SXiao Guangrong rinfo.flags = region.flags; 653857a2622SXiao Guangrong rinfo.size = region.size; 654857a2622SXiao Guangrong rinfo.offset = region.offset; 655857a2622SXiao Guangrong 656857a2622SXiao Guangrong if (copy_to_user(arg, &rinfo, sizeof(rinfo))) 657857a2622SXiao Guangrong return -EFAULT; 658857a2622SXiao Guangrong 659857a2622SXiao Guangrong return 0; 660857a2622SXiao Guangrong } 661857a2622SXiao Guangrong 662fa8dda1eSWu Hao static long 663fa8dda1eSWu Hao afu_ioctl_dma_map(struct dfl_feature_platform_data *pdata, void __user *arg) 664fa8dda1eSWu Hao { 665fa8dda1eSWu Hao struct dfl_fpga_port_dma_map map; 666fa8dda1eSWu Hao unsigned long minsz; 667fa8dda1eSWu Hao long ret; 668fa8dda1eSWu Hao 669fa8dda1eSWu Hao minsz = offsetofend(struct dfl_fpga_port_dma_map, iova); 670fa8dda1eSWu Hao 671fa8dda1eSWu Hao if (copy_from_user(&map, arg, minsz)) 672fa8dda1eSWu Hao return -EFAULT; 673fa8dda1eSWu Hao 674fa8dda1eSWu Hao if (map.argsz < minsz || map.flags) 675fa8dda1eSWu Hao return -EINVAL; 676fa8dda1eSWu Hao 677fa8dda1eSWu Hao ret = afu_dma_map_region(pdata, map.user_addr, map.length, &map.iova); 678fa8dda1eSWu Hao if (ret) 679fa8dda1eSWu Hao return ret; 680fa8dda1eSWu Hao 681fa8dda1eSWu Hao if (copy_to_user(arg, &map, sizeof(map))) { 682fa8dda1eSWu Hao afu_dma_unmap_region(pdata, map.iova); 683fa8dda1eSWu Hao return -EFAULT; 684fa8dda1eSWu Hao } 685fa8dda1eSWu Hao 686fa8dda1eSWu Hao dev_dbg(&pdata->dev->dev, "dma map: ua=%llx, len=%llx, iova=%llx\n", 687fa8dda1eSWu Hao (unsigned long long)map.user_addr, 688fa8dda1eSWu Hao (unsigned long long)map.length, 689fa8dda1eSWu Hao (unsigned long long)map.iova); 690fa8dda1eSWu Hao 691fa8dda1eSWu Hao return 0; 692fa8dda1eSWu Hao } 693fa8dda1eSWu Hao 694fa8dda1eSWu Hao static long 695fa8dda1eSWu Hao afu_ioctl_dma_unmap(struct dfl_feature_platform_data *pdata, void __user *arg) 696fa8dda1eSWu Hao { 697fa8dda1eSWu Hao struct dfl_fpga_port_dma_unmap unmap; 698fa8dda1eSWu Hao unsigned long minsz; 699fa8dda1eSWu Hao 700fa8dda1eSWu Hao minsz = offsetofend(struct dfl_fpga_port_dma_unmap, iova); 701fa8dda1eSWu Hao 702fa8dda1eSWu Hao if (copy_from_user(&unmap, arg, minsz)) 703fa8dda1eSWu Hao return -EFAULT; 704fa8dda1eSWu Hao 705fa8dda1eSWu Hao if (unmap.argsz < minsz || unmap.flags) 706fa8dda1eSWu Hao return -EINVAL; 707fa8dda1eSWu Hao 708fa8dda1eSWu Hao return afu_dma_unmap_region(pdata, unmap.iova); 709fa8dda1eSWu Hao } 710fa8dda1eSWu Hao 7111a1527cfSWu Hao static long afu_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 7121a1527cfSWu Hao { 7131a1527cfSWu Hao struct platform_device *pdev = filp->private_data; 7141a1527cfSWu Hao struct dfl_feature_platform_data *pdata; 7151a1527cfSWu Hao struct dfl_feature *f; 7161a1527cfSWu Hao long ret; 7171a1527cfSWu Hao 7181a1527cfSWu Hao dev_dbg(&pdev->dev, "%s cmd 0x%x\n", __func__, cmd); 7191a1527cfSWu Hao 7201a1527cfSWu Hao pdata = dev_get_platdata(&pdev->dev); 7211a1527cfSWu Hao 7221a1527cfSWu Hao switch (cmd) { 7236fd893c4SWu Hao case DFL_FPGA_GET_API_VERSION: 7246fd893c4SWu Hao return DFL_FPGA_API_VERSION; 7256fd893c4SWu Hao case DFL_FPGA_CHECK_EXTENSION: 7266fd893c4SWu Hao return afu_ioctl_check_extension(pdata, arg); 727857a2622SXiao Guangrong case DFL_FPGA_PORT_GET_INFO: 728857a2622SXiao Guangrong return afu_ioctl_get_info(pdata, (void __user *)arg); 729857a2622SXiao Guangrong case DFL_FPGA_PORT_GET_REGION_INFO: 730857a2622SXiao Guangrong return afu_ioctl_get_region_info(pdata, (void __user *)arg); 731fa8dda1eSWu Hao case DFL_FPGA_PORT_DMA_MAP: 732fa8dda1eSWu Hao return afu_ioctl_dma_map(pdata, (void __user *)arg); 733fa8dda1eSWu Hao case DFL_FPGA_PORT_DMA_UNMAP: 734fa8dda1eSWu Hao return afu_ioctl_dma_unmap(pdata, (void __user *)arg); 7351a1527cfSWu Hao default: 7361a1527cfSWu Hao /* 7371a1527cfSWu Hao * Let sub-feature's ioctl function to handle the cmd 7381a1527cfSWu Hao * Sub-feature's ioctl returns -ENODEV when cmd is not 7391a1527cfSWu Hao * handled in this sub feature, and returns 0 and other 7401a1527cfSWu Hao * error code if cmd is handled. 7411a1527cfSWu Hao */ 7421a1527cfSWu Hao dfl_fpga_dev_for_each_feature(pdata, f) 7431a1527cfSWu Hao if (f->ops && f->ops->ioctl) { 7441a1527cfSWu Hao ret = f->ops->ioctl(pdev, f, cmd, arg); 7451a1527cfSWu Hao if (ret != -ENODEV) 7461a1527cfSWu Hao return ret; 7471a1527cfSWu Hao } 7481a1527cfSWu Hao } 7491a1527cfSWu Hao 7501a1527cfSWu Hao return -EINVAL; 7511a1527cfSWu Hao } 7521a1527cfSWu Hao 753*a2b9d4eaSDominic Chen static const struct vm_operations_struct afu_vma_ops = { 754*a2b9d4eaSDominic Chen #ifdef CONFIG_HAVE_IOREMAP_PROT 755*a2b9d4eaSDominic Chen .access = generic_access_phys, 756*a2b9d4eaSDominic Chen #endif 757*a2b9d4eaSDominic Chen }; 758*a2b9d4eaSDominic Chen 759857a2622SXiao Guangrong static int afu_mmap(struct file *filp, struct vm_area_struct *vma) 760857a2622SXiao Guangrong { 761857a2622SXiao Guangrong struct platform_device *pdev = filp->private_data; 762857a2622SXiao Guangrong struct dfl_feature_platform_data *pdata; 763857a2622SXiao Guangrong u64 size = vma->vm_end - vma->vm_start; 764857a2622SXiao Guangrong struct dfl_afu_mmio_region region; 765857a2622SXiao Guangrong u64 offset; 766857a2622SXiao Guangrong int ret; 767857a2622SXiao Guangrong 768857a2622SXiao Guangrong if (!(vma->vm_flags & VM_SHARED)) 769857a2622SXiao Guangrong return -EINVAL; 770857a2622SXiao Guangrong 771857a2622SXiao Guangrong pdata = dev_get_platdata(&pdev->dev); 772857a2622SXiao Guangrong 773857a2622SXiao Guangrong offset = vma->vm_pgoff << PAGE_SHIFT; 774857a2622SXiao Guangrong ret = afu_mmio_region_get_by_offset(pdata, offset, size, ®ion); 775857a2622SXiao Guangrong if (ret) 776857a2622SXiao Guangrong return ret; 777857a2622SXiao Guangrong 778857a2622SXiao Guangrong if (!(region.flags & DFL_PORT_REGION_MMAP)) 779857a2622SXiao Guangrong return -EINVAL; 780857a2622SXiao Guangrong 781857a2622SXiao Guangrong if ((vma->vm_flags & VM_READ) && !(region.flags & DFL_PORT_REGION_READ)) 782857a2622SXiao Guangrong return -EPERM; 783857a2622SXiao Guangrong 784857a2622SXiao Guangrong if ((vma->vm_flags & VM_WRITE) && 785857a2622SXiao Guangrong !(region.flags & DFL_PORT_REGION_WRITE)) 786857a2622SXiao Guangrong return -EPERM; 787857a2622SXiao Guangrong 788*a2b9d4eaSDominic Chen /* Support debug access to the mapping */ 789*a2b9d4eaSDominic Chen vma->vm_ops = &afu_vma_ops; 790*a2b9d4eaSDominic Chen 791857a2622SXiao Guangrong vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 792857a2622SXiao Guangrong 793857a2622SXiao Guangrong return remap_pfn_range(vma, vma->vm_start, 794857a2622SXiao Guangrong (region.phys + (offset - region.offset)) >> PAGE_SHIFT, 795857a2622SXiao Guangrong size, vma->vm_page_prot); 796857a2622SXiao Guangrong } 797857a2622SXiao Guangrong 7981a1527cfSWu Hao static const struct file_operations afu_fops = { 7991a1527cfSWu Hao .owner = THIS_MODULE, 8001a1527cfSWu Hao .open = afu_open, 8011a1527cfSWu Hao .release = afu_release, 8021a1527cfSWu Hao .unlocked_ioctl = afu_ioctl, 803857a2622SXiao Guangrong .mmap = afu_mmap, 8041a1527cfSWu Hao }; 8051a1527cfSWu Hao 806857a2622SXiao Guangrong static int afu_dev_init(struct platform_device *pdev) 807857a2622SXiao Guangrong { 808857a2622SXiao Guangrong struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); 809857a2622SXiao Guangrong struct dfl_afu *afu; 810857a2622SXiao Guangrong 811857a2622SXiao Guangrong afu = devm_kzalloc(&pdev->dev, sizeof(*afu), GFP_KERNEL); 812857a2622SXiao Guangrong if (!afu) 813857a2622SXiao Guangrong return -ENOMEM; 814857a2622SXiao Guangrong 815857a2622SXiao Guangrong afu->pdata = pdata; 816857a2622SXiao Guangrong 817857a2622SXiao Guangrong mutex_lock(&pdata->lock); 818857a2622SXiao Guangrong dfl_fpga_pdata_set_private(pdata, afu); 819857a2622SXiao Guangrong afu_mmio_region_init(pdata); 820fa8dda1eSWu Hao afu_dma_region_init(pdata); 821857a2622SXiao Guangrong mutex_unlock(&pdata->lock); 822857a2622SXiao Guangrong 823857a2622SXiao Guangrong return 0; 824857a2622SXiao Guangrong } 825857a2622SXiao Guangrong 826857a2622SXiao Guangrong static int afu_dev_destroy(struct platform_device *pdev) 827857a2622SXiao Guangrong { 828857a2622SXiao Guangrong struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); 829857a2622SXiao Guangrong 830857a2622SXiao Guangrong mutex_lock(&pdata->lock); 831857a2622SXiao Guangrong afu_mmio_region_destroy(pdata); 832fa8dda1eSWu Hao afu_dma_region_destroy(pdata); 833857a2622SXiao Guangrong dfl_fpga_pdata_set_private(pdata, NULL); 834857a2622SXiao Guangrong mutex_unlock(&pdata->lock); 835857a2622SXiao Guangrong 836857a2622SXiao Guangrong return 0; 837857a2622SXiao Guangrong } 838857a2622SXiao Guangrong 83947c1b19cSWu Hao static int port_enable_set(struct platform_device *pdev, bool enable) 84047c1b19cSWu Hao { 84147c1b19cSWu Hao struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); 84247c1b19cSWu Hao int ret = 0; 84347c1b19cSWu Hao 84447c1b19cSWu Hao mutex_lock(&pdata->lock); 84547c1b19cSWu Hao if (enable) 84695844372SWu Hao __afu_port_enable(pdev); 84747c1b19cSWu Hao else 84895844372SWu Hao ret = __afu_port_disable(pdev); 84947c1b19cSWu Hao mutex_unlock(&pdata->lock); 85047c1b19cSWu Hao 85147c1b19cSWu Hao return ret; 85247c1b19cSWu Hao } 85347c1b19cSWu Hao 85447c1b19cSWu Hao static struct dfl_fpga_port_ops afu_port_ops = { 85547c1b19cSWu Hao .name = DFL_FPGA_FEATURE_DEV_PORT, 85647c1b19cSWu Hao .owner = THIS_MODULE, 85747c1b19cSWu Hao .get_id = port_get_id, 85847c1b19cSWu Hao .enable_set = port_enable_set, 85947c1b19cSWu Hao }; 86047c1b19cSWu Hao 8611a1527cfSWu Hao static int afu_probe(struct platform_device *pdev) 8621a1527cfSWu Hao { 8631a1527cfSWu Hao int ret; 8641a1527cfSWu Hao 8651a1527cfSWu Hao dev_dbg(&pdev->dev, "%s\n", __func__); 8661a1527cfSWu Hao 867857a2622SXiao Guangrong ret = afu_dev_init(pdev); 868857a2622SXiao Guangrong if (ret) 869857a2622SXiao Guangrong goto exit; 870857a2622SXiao Guangrong 8711a1527cfSWu Hao ret = dfl_fpga_dev_feature_init(pdev, port_feature_drvs); 8721a1527cfSWu Hao if (ret) 873857a2622SXiao Guangrong goto dev_destroy; 8741a1527cfSWu Hao 8751a1527cfSWu Hao ret = dfl_fpga_dev_ops_register(pdev, &afu_fops, THIS_MODULE); 876857a2622SXiao Guangrong if (ret) { 8771a1527cfSWu Hao dfl_fpga_dev_feature_uinit(pdev); 878857a2622SXiao Guangrong goto dev_destroy; 879857a2622SXiao Guangrong } 8801a1527cfSWu Hao 881857a2622SXiao Guangrong return 0; 882857a2622SXiao Guangrong 883857a2622SXiao Guangrong dev_destroy: 884857a2622SXiao Guangrong afu_dev_destroy(pdev); 885857a2622SXiao Guangrong exit: 8861a1527cfSWu Hao return ret; 8871a1527cfSWu Hao } 8881a1527cfSWu Hao 8891a1527cfSWu Hao static int afu_remove(struct platform_device *pdev) 8901a1527cfSWu Hao { 8911a1527cfSWu Hao dev_dbg(&pdev->dev, "%s\n", __func__); 8921a1527cfSWu Hao 8931a1527cfSWu Hao dfl_fpga_dev_ops_unregister(pdev); 8941a1527cfSWu Hao dfl_fpga_dev_feature_uinit(pdev); 895857a2622SXiao Guangrong afu_dev_destroy(pdev); 8961a1527cfSWu Hao 8971a1527cfSWu Hao return 0; 8981a1527cfSWu Hao } 8991a1527cfSWu Hao 900a80a4b82SWu Hao static const struct attribute_group *afu_dev_groups[] = { 901a80a4b82SWu Hao &port_hdr_group, 902a80a4b82SWu Hao &port_afu_group, 90344d24753SWu Hao &port_err_group, 904a80a4b82SWu Hao NULL 905a80a4b82SWu Hao }; 906a80a4b82SWu Hao 9071a1527cfSWu Hao static struct platform_driver afu_driver = { 9081a1527cfSWu Hao .driver = { 9091a1527cfSWu Hao .name = DFL_FPGA_FEATURE_DEV_PORT, 910a80a4b82SWu Hao .dev_groups = afu_dev_groups, 9111a1527cfSWu Hao }, 9121a1527cfSWu Hao .probe = afu_probe, 9131a1527cfSWu Hao .remove = afu_remove, 9141a1527cfSWu Hao }; 9151a1527cfSWu Hao 91647c1b19cSWu Hao static int __init afu_init(void) 91747c1b19cSWu Hao { 91847c1b19cSWu Hao int ret; 91947c1b19cSWu Hao 92047c1b19cSWu Hao dfl_fpga_port_ops_add(&afu_port_ops); 92147c1b19cSWu Hao 92247c1b19cSWu Hao ret = platform_driver_register(&afu_driver); 92347c1b19cSWu Hao if (ret) 92447c1b19cSWu Hao dfl_fpga_port_ops_del(&afu_port_ops); 92547c1b19cSWu Hao 92647c1b19cSWu Hao return ret; 92747c1b19cSWu Hao } 92847c1b19cSWu Hao 92947c1b19cSWu Hao static void __exit afu_exit(void) 93047c1b19cSWu Hao { 93147c1b19cSWu Hao platform_driver_unregister(&afu_driver); 93247c1b19cSWu Hao 93347c1b19cSWu Hao dfl_fpga_port_ops_del(&afu_port_ops); 93447c1b19cSWu Hao } 93547c1b19cSWu Hao 93647c1b19cSWu Hao module_init(afu_init); 93747c1b19cSWu Hao module_exit(afu_exit); 9381a1527cfSWu Hao 9391a1527cfSWu Hao MODULE_DESCRIPTION("FPGA Accelerated Function Unit driver"); 9401a1527cfSWu Hao MODULE_AUTHOR("Intel Corporation"); 9411a1527cfSWu Hao MODULE_LICENSE("GPL v2"); 9421a1527cfSWu Hao MODULE_ALIAS("platform:dfl-port"); 943