Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

misc: Add Synopsys DesignWare xData IP driver

Add Synopsys DesignWare xData IP driver. This driver enables/disables
the PCI traffic generator module pertain to the Synopsys DesignWare
prototype.

Signed-off-by: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
Link: https://lore.kernel.org/r/daa1efe23850e77d6807dc3f371728fc0b7548b8.1617016509.git.gustavo.pimentel@synopsys.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Gustavo Pimentel and committed by
Greg Kroah-Hartman
e8a30eef b2192cfe

+431
+10
drivers/misc/Kconfig
··· 402 402 config SRAM_EXEC 403 403 bool 404 404 405 + config DW_XDATA_PCIE 406 + depends on PCI 407 + tristate "Synopsys DesignWare xData PCIe driver" 408 + help 409 + This driver allows controlling Synopsys DesignWare PCIe traffic 410 + generator IP also known as xData, present in Synopsys DesignWare 411 + PCIe Endpoint prototype. 412 + 413 + If unsure, say N. 414 + 405 415 config PCI_ENDPOINT_TEST 406 416 depends on PCI 407 417 select CRC32
+1
drivers/misc/Makefile
··· 47 47 obj-$(CONFIG_GENWQE) += genwqe/ 48 48 obj-$(CONFIG_ECHO) += echo/ 49 49 obj-$(CONFIG_CXL_BASE) += cxl/ 50 + obj-$(CONFIG_DW_XDATA_PCIE) += dw-xdata-pcie.o 50 51 obj-$(CONFIG_PCI_ENDPOINT_TEST) += pci_endpoint_test.o 51 52 obj-$(CONFIG_OCXL) += ocxl/ 52 53 obj-$(CONFIG_BCM_VK) += bcm-vk/
+420
drivers/misc/dw-xdata-pcie.c
··· 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 + 24 + static 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 + 41 + struct 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 + 59 + struct dw_xdata_region { 60 + phys_addr_t paddr; /* physical address */ 61 + void __iomem *vaddr; /* virtual address */ 62 + }; 63 + 64 + struct 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 + 73 + static inline struct dw_xdata_regs __iomem *__dw_regs(struct dw_xdata *dw) 74 + { 75 + return dw->rg_region.vaddr; 76 + } 77 + 78 + static 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 + 94 + static 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 + 138 + static 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 + 151 + static 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 + 162 + static 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 + 201 + static 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 + 206 + static 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 + 218 + static 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 + 241 + static DEVICE_ATTR_RW(write); 242 + 243 + static 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 + 255 + static 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 + 278 + static DEVICE_ATTR_RW(read); 279 + 280 + static struct attribute *xdata_attrs[] = { 281 + &dev_attr_write.attr, 282 + &dev_attr_read.attr, 283 + NULL, 284 + }; 285 + 286 + ATTRIBUTE_GROUPS(xdata); 287 + 288 + static 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 + 376 + err_kfree_name: 377 + kfree(dw->misc_dev.name); 378 + 379 + err_ida_remove: 380 + ida_simple_remove(&xdata_ida, id); 381 + 382 + return err; 383 + } 384 + 385 + static 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 + 402 + static const struct pci_device_id dw_xdata_pcie_id_table[] = { 403 + { PCI_DEVICE_DATA(SYNOPSYS, EDDA, NULL) }, 404 + { } 405 + }; 406 + MODULE_DEVICE_TABLE(pci, dw_xdata_pcie_id_table); 407 + 408 + static 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 + 415 + module_pci_driver(dw_xdata_pcie_driver); 416 + 417 + MODULE_LICENSE("GPL v2"); 418 + MODULE_DESCRIPTION("Synopsys DesignWare xData PCIe driver"); 419 + MODULE_AUTHOR("Gustavo Pimentel <gustavo.pimentel@synopsys.com>"); 420 +