dw-xdata-pcie.c (9923B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (c) 2020 Synopsys, Inc. and/or its affiliates. 4 * Synopsys DesignWare xData driver 5 * 6 * Author: Gustavo Pimentel <gustavo.pimentel@synopsys.com> 7 */ 8 9#include <linux/miscdevice.h> 10#include <linux/bitfield.h> 11#include <linux/pci-epf.h> 12#include <linux/kernel.h> 13#include <linux/module.h> 14#include <linux/device.h> 15#include <linux/bitops.h> 16#include <linux/mutex.h> 17#include <linux/delay.h> 18#include <linux/pci.h> 19 20#define DW_XDATA_DRIVER_NAME "dw-xdata-pcie" 21 22#define DW_XDATA_EP_MEM_OFFSET 0x8000000 23 24static DEFINE_IDA(xdata_ida); 25 26#define STATUS_DONE BIT(0) 27 28#define CONTROL_DOORBELL BIT(0) 29#define CONTROL_IS_WRITE BIT(1) 30#define CONTROL_LENGTH(a) FIELD_PREP(GENMASK(13, 2), a) 31#define CONTROL_PATTERN_INC BIT(16) 32#define CONTROL_NO_ADDR_INC BIT(18) 33 34#define XPERF_CONTROL_ENABLE BIT(5) 35 36#define BURST_REPEAT BIT(31) 37#define BURST_VALUE 0x1001 38 39#define PATTERN_VALUE 0x0 40 41struct dw_xdata_regs { 42 u32 addr_lsb; /* 0x000 */ 43 u32 addr_msb; /* 0x004 */ 44 u32 burst_cnt; /* 0x008 */ 45 u32 control; /* 0x00c */ 46 u32 pattern; /* 0x010 */ 47 u32 status; /* 0x014 */ 48 u32 RAM_addr; /* 0x018 */ 49 u32 RAM_port; /* 0x01c */ 50 u32 _reserved0[14]; /* 0x020..0x054 */ 51 u32 perf_control; /* 0x058 */ 52 u32 _reserved1[41]; /* 0x05c..0x0fc */ 53 u32 wr_cnt_lsb; /* 0x100 */ 54 u32 wr_cnt_msb; /* 0x104 */ 55 u32 rd_cnt_lsb; /* 0x108 */ 56 u32 rd_cnt_msb; /* 0x10c */ 57} __packed; 58 59struct dw_xdata_region { 60 phys_addr_t paddr; /* physical address */ 61 void __iomem *vaddr; /* virtual address */ 62}; 63 64struct dw_xdata { 65 struct dw_xdata_region rg_region; /* registers */ 66 size_t max_wr_len; /* max wr xfer len */ 67 size_t max_rd_len; /* max rd xfer len */ 68 struct mutex mutex; 69 struct pci_dev *pdev; 70 struct miscdevice misc_dev; 71}; 72 73static inline struct dw_xdata_regs __iomem *__dw_regs(struct dw_xdata *dw) 74{ 75 return dw->rg_region.vaddr; 76} 77 78static void dw_xdata_stop(struct dw_xdata *dw) 79{ 80 u32 burst; 81 82 mutex_lock(&dw->mutex); 83 84 burst = readl(&(__dw_regs(dw)->burst_cnt)); 85 86 if (burst & BURST_REPEAT) { 87 burst &= ~(u32)BURST_REPEAT; 88 writel(burst, &(__dw_regs(dw)->burst_cnt)); 89 } 90 91 mutex_unlock(&dw->mutex); 92} 93 94static void dw_xdata_start(struct dw_xdata *dw, bool write) 95{ 96 struct device *dev = &dw->pdev->dev; 97 u32 control, status; 98 99 /* Stop first if xfer in progress */ 100 dw_xdata_stop(dw); 101 102 mutex_lock(&dw->mutex); 103 104 /* Clear status register */ 105 writel(0x0, &(__dw_regs(dw)->status)); 106 107 /* Burst count register set for continuous until stopped */ 108 writel(BURST_REPEAT | BURST_VALUE, &(__dw_regs(dw)->burst_cnt)); 109 110 /* Pattern register */ 111 writel(PATTERN_VALUE, &(__dw_regs(dw)->pattern)); 112 113 /* Control register */ 114 control = CONTROL_DOORBELL | CONTROL_PATTERN_INC | CONTROL_NO_ADDR_INC; 115 if (write) { 116 control |= CONTROL_IS_WRITE; 117 control |= CONTROL_LENGTH(dw->max_wr_len); 118 } else { 119 control |= CONTROL_LENGTH(dw->max_rd_len); 120 } 121 writel(control, &(__dw_regs(dw)->control)); 122 123 /* 124 * The xData HW block needs about 100 ms to initiate the traffic 125 * generation according this HW block datasheet. 126 */ 127 usleep_range(100, 150); 128 129 status = readl(&(__dw_regs(dw)->status)); 130 131 mutex_unlock(&dw->mutex); 132 133 if (!(status & STATUS_DONE)) 134 dev_dbg(dev, "xData: started %s direction\n", 135 write ? "write" : "read"); 136} 137 138static void dw_xdata_perf_meas(struct dw_xdata *dw, u64 *data, bool write) 139{ 140 if (write) { 141 *data = readl(&(__dw_regs(dw)->wr_cnt_msb)); 142 *data <<= 32; 143 *data |= readl(&(__dw_regs(dw)->wr_cnt_lsb)); 144 } else { 145 *data = readl(&(__dw_regs(dw)->rd_cnt_msb)); 146 *data <<= 32; 147 *data |= readl(&(__dw_regs(dw)->rd_cnt_lsb)); 148 } 149} 150 151static u64 dw_xdata_perf_diff(u64 *m1, u64 *m2, u64 time) 152{ 153 u64 rate = (*m1 - *m2); 154 155 rate *= (1000 * 1000 * 1000); 156 rate >>= 20; 157 rate = DIV_ROUND_CLOSEST_ULL(rate, time); 158 159 return rate; 160} 161 162static void dw_xdata_perf(struct dw_xdata *dw, u64 *rate, bool write) 163{ 164 struct device *dev = &dw->pdev->dev; 165 u64 data[2], time[2], diff; 166 167 mutex_lock(&dw->mutex); 168 169 /* First acquisition of current count frames */ 170 writel(0x0, &(__dw_regs(dw)->perf_control)); 171 dw_xdata_perf_meas(dw, &data[0], write); 172 time[0] = jiffies; 173 writel((u32)XPERF_CONTROL_ENABLE, &(__dw_regs(dw)->perf_control)); 174 175 /* 176 * Wait 100ms between the 1st count frame acquisition and the 2nd 177 * count frame acquisition, in order to calculate the speed later 178 */ 179 mdelay(100); 180 181 /* Second acquisition of current count frames */ 182 writel(0x0, &(__dw_regs(dw)->perf_control)); 183 dw_xdata_perf_meas(dw, &data[1], write); 184 time[1] = jiffies; 185 writel((u32)XPERF_CONTROL_ENABLE, &(__dw_regs(dw)->perf_control)); 186 187 /* 188 * Speed calculation 189 * 190 * rate = (2nd count frames - 1st count frames) / (time elapsed) 191 */ 192 diff = jiffies_to_nsecs(time[1] - time[0]); 193 *rate = dw_xdata_perf_diff(&data[1], &data[0], diff); 194 195 mutex_unlock(&dw->mutex); 196 197 dev_dbg(dev, "xData: time=%llu us, %s=%llu MB/s\n", 198 diff, write ? "write" : "read", *rate); 199} 200 201static struct dw_xdata *misc_dev_to_dw(struct miscdevice *misc_dev) 202{ 203 return container_of(misc_dev, struct dw_xdata, misc_dev); 204} 205 206static ssize_t write_show(struct device *dev, struct device_attribute *attr, 207 char *buf) 208{ 209 struct miscdevice *misc_dev = dev_get_drvdata(dev); 210 struct dw_xdata *dw = misc_dev_to_dw(misc_dev); 211 u64 rate; 212 213 dw_xdata_perf(dw, &rate, true); 214 215 return sysfs_emit(buf, "%llu\n", rate); 216} 217 218static ssize_t write_store(struct device *dev, struct device_attribute *attr, 219 const char *buf, size_t size) 220{ 221 struct miscdevice *misc_dev = dev_get_drvdata(dev); 222 struct dw_xdata *dw = misc_dev_to_dw(misc_dev); 223 bool enabled; 224 int ret; 225 226 ret = kstrtobool(buf, &enabled); 227 if (ret < 0) 228 return ret; 229 230 if (enabled) { 231 dev_dbg(dev, "xData: requested write transfer\n"); 232 dw_xdata_start(dw, true); 233 } else { 234 dev_dbg(dev, "xData: requested stop transfer\n"); 235 dw_xdata_stop(dw); 236 } 237 238 return size; 239} 240 241static DEVICE_ATTR_RW(write); 242 243static ssize_t read_show(struct device *dev, struct device_attribute *attr, 244 char *buf) 245{ 246 struct miscdevice *misc_dev = dev_get_drvdata(dev); 247 struct dw_xdata *dw = misc_dev_to_dw(misc_dev); 248 u64 rate; 249 250 dw_xdata_perf(dw, &rate, false); 251 252 return sysfs_emit(buf, "%llu\n", rate); 253} 254 255static ssize_t read_store(struct device *dev, struct device_attribute *attr, 256 const char *buf, size_t size) 257{ 258 struct miscdevice *misc_dev = dev_get_drvdata(dev); 259 struct dw_xdata *dw = misc_dev_to_dw(misc_dev); 260 bool enabled; 261 int ret; 262 263 ret = kstrtobool(buf, &enabled); 264 if (ret < 0) 265 return ret; 266 267 if (enabled) { 268 dev_dbg(dev, "xData: requested read transfer\n"); 269 dw_xdata_start(dw, false); 270 } else { 271 dev_dbg(dev, "xData: requested stop transfer\n"); 272 dw_xdata_stop(dw); 273 } 274 275 return size; 276} 277 278static DEVICE_ATTR_RW(read); 279 280static struct attribute *xdata_attrs[] = { 281 &dev_attr_write.attr, 282 &dev_attr_read.attr, 283 NULL, 284}; 285 286ATTRIBUTE_GROUPS(xdata); 287 288static int dw_xdata_pcie_probe(struct pci_dev *pdev, 289 const struct pci_device_id *pid) 290{ 291 struct device *dev = &pdev->dev; 292 struct dw_xdata *dw; 293 char name[24]; 294 u64 addr; 295 int err; 296 int id; 297 298 /* Enable PCI device */ 299 err = pcim_enable_device(pdev); 300 if (err) { 301 dev_err(dev, "enabling device failed\n"); 302 return err; 303 } 304 305 /* Mapping PCI BAR regions */ 306 err = pcim_iomap_regions(pdev, BIT(BAR_0), pci_name(pdev)); 307 if (err) { 308 dev_err(dev, "xData BAR I/O remapping failed\n"); 309 return err; 310 } 311 312 pci_set_master(pdev); 313 314 /* Allocate memory */ 315 dw = devm_kzalloc(dev, sizeof(*dw), GFP_KERNEL); 316 if (!dw) 317 return -ENOMEM; 318 319 /* Data structure initialization */ 320 mutex_init(&dw->mutex); 321 322 dw->rg_region.vaddr = pcim_iomap_table(pdev)[BAR_0]; 323 if (!dw->rg_region.vaddr) 324 return -ENOMEM; 325 326 dw->rg_region.paddr = pdev->resource[BAR_0].start; 327 328 dw->max_wr_len = pcie_get_mps(pdev); 329 dw->max_wr_len >>= 2; 330 331 dw->max_rd_len = pcie_get_readrq(pdev); 332 dw->max_rd_len >>= 2; 333 334 dw->pdev = pdev; 335 336 id = ida_simple_get(&xdata_ida, 0, 0, GFP_KERNEL); 337 if (id < 0) { 338 dev_err(dev, "xData: unable to get id\n"); 339 return id; 340 } 341 342 snprintf(name, sizeof(name), DW_XDATA_DRIVER_NAME ".%d", id); 343 dw->misc_dev.name = kstrdup(name, GFP_KERNEL); 344 if (!dw->misc_dev.name) { 345 err = -ENOMEM; 346 goto err_ida_remove; 347 } 348 349 dw->misc_dev.minor = MISC_DYNAMIC_MINOR; 350 dw->misc_dev.parent = dev; 351 dw->misc_dev.groups = xdata_groups; 352 353 writel(0x0, &(__dw_regs(dw)->RAM_addr)); 354 writel(0x0, &(__dw_regs(dw)->RAM_port)); 355 356 addr = dw->rg_region.paddr + DW_XDATA_EP_MEM_OFFSET; 357 writel(lower_32_bits(addr), &(__dw_regs(dw)->addr_lsb)); 358 writel(upper_32_bits(addr), &(__dw_regs(dw)->addr_msb)); 359 dev_dbg(dev, "xData: target address = 0x%.16llx\n", addr); 360 361 dev_dbg(dev, "xData: wr_len = %zu, rd_len = %zu\n", 362 dw->max_wr_len * 4, dw->max_rd_len * 4); 363 364 /* Saving data structure reference */ 365 pci_set_drvdata(pdev, dw); 366 367 /* Register misc device */ 368 err = misc_register(&dw->misc_dev); 369 if (err) { 370 dev_err(dev, "xData: failed to register device\n"); 371 goto err_kfree_name; 372 } 373 374 return 0; 375 376err_kfree_name: 377 kfree(dw->misc_dev.name); 378 379err_ida_remove: 380 ida_simple_remove(&xdata_ida, id); 381 382 return err; 383} 384 385static void dw_xdata_pcie_remove(struct pci_dev *pdev) 386{ 387 struct dw_xdata *dw = pci_get_drvdata(pdev); 388 int id; 389 390 if (sscanf(dw->misc_dev.name, DW_XDATA_DRIVER_NAME ".%d", &id) != 1) 391 return; 392 393 if (id < 0) 394 return; 395 396 dw_xdata_stop(dw); 397 misc_deregister(&dw->misc_dev); 398 kfree(dw->misc_dev.name); 399 ida_simple_remove(&xdata_ida, id); 400} 401 402static const struct pci_device_id dw_xdata_pcie_id_table[] = { 403 { PCI_DEVICE_DATA(SYNOPSYS, EDDA, NULL) }, 404 { } 405}; 406MODULE_DEVICE_TABLE(pci, dw_xdata_pcie_id_table); 407 408static struct pci_driver dw_xdata_pcie_driver = { 409 .name = DW_XDATA_DRIVER_NAME, 410 .id_table = dw_xdata_pcie_id_table, 411 .probe = dw_xdata_pcie_probe, 412 .remove = dw_xdata_pcie_remove, 413}; 414 415module_pci_driver(dw_xdata_pcie_driver); 416 417MODULE_LICENSE("GPL v2"); 418MODULE_DESCRIPTION("Synopsys DesignWare xData PCIe driver"); 419MODULE_AUTHOR("Gustavo Pimentel <gustavo.pimentel@synopsys.com>"); 420