| .. | .. |
|---|
| 63 | 63 | #define ETB_FFSR_BIT 1 |
|---|
| 64 | 64 | #define ETB_FRAME_SIZE_WORDS 4 |
|---|
| 65 | 65 | |
|---|
| 66 | +DEFINE_CORESIGHT_DEVLIST(etb_devs, "etb"); |
|---|
| 67 | + |
|---|
| 66 | 68 | /** |
|---|
| 67 | 69 | * struct etb_drvdata - specifics associated to an ETB component |
|---|
| 68 | 70 | * @base: memory mapped base address for this component. |
|---|
| 69 | | - * @dev: the device entity associated to this component. |
|---|
| 70 | 71 | * @atclk: optional clock for the core parts of the ETB. |
|---|
| 71 | 72 | * @csdev: component vitals needed by the framework. |
|---|
| 72 | 73 | * @miscdev: specifics to handle "/dev/xyz.etb" entry. |
|---|
| 73 | 74 | * @spinlock: only one at a time pls. |
|---|
| 74 | 75 | * @reading: synchronise user space access to etb buffer. |
|---|
| 76 | + * @pid: Process ID of the process being monitored by the session |
|---|
| 77 | + * that is using this component. |
|---|
| 75 | 78 | * @buf: area of memory where ETB buffer content gets sent. |
|---|
| 76 | 79 | * @mode: this ETB is being used. |
|---|
| 77 | 80 | * @buffer_depth: size of @buf. |
|---|
| .. | .. |
|---|
| 79 | 82 | */ |
|---|
| 80 | 83 | struct etb_drvdata { |
|---|
| 81 | 84 | void __iomem *base; |
|---|
| 82 | | - struct device *dev; |
|---|
| 83 | 85 | struct clk *atclk; |
|---|
| 84 | 86 | struct coresight_device *csdev; |
|---|
| 85 | 87 | struct miscdevice miscdev; |
|---|
| 86 | 88 | spinlock_t spinlock; |
|---|
| 87 | 89 | local_t reading; |
|---|
| 90 | + pid_t pid; |
|---|
| 88 | 91 | u8 *buf; |
|---|
| 89 | 92 | u32 mode; |
|---|
| 90 | 93 | u32 buffer_depth; |
|---|
| .. | .. |
|---|
| 94 | 97 | static int etb_set_buffer(struct coresight_device *csdev, |
|---|
| 95 | 98 | struct perf_output_handle *handle); |
|---|
| 96 | 99 | |
|---|
| 97 | | -static unsigned int etb_get_buffer_depth(struct etb_drvdata *drvdata) |
|---|
| 100 | +static inline unsigned int etb_get_buffer_depth(struct etb_drvdata *drvdata) |
|---|
| 98 | 101 | { |
|---|
| 99 | | - u32 depth = 0; |
|---|
| 100 | | - |
|---|
| 101 | | - pm_runtime_get_sync(drvdata->dev); |
|---|
| 102 | | - |
|---|
| 103 | | - /* RO registers don't need locking */ |
|---|
| 104 | | - depth = readl_relaxed(drvdata->base + ETB_RAM_DEPTH_REG); |
|---|
| 105 | | - |
|---|
| 106 | | - pm_runtime_put(drvdata->dev); |
|---|
| 107 | | - return depth; |
|---|
| 102 | + return readl_relaxed(drvdata->base + ETB_RAM_DEPTH_REG); |
|---|
| 108 | 103 | } |
|---|
| 109 | 104 | |
|---|
| 110 | 105 | static void __etb_enable_hw(struct etb_drvdata *drvdata) |
|---|
| .. | .. |
|---|
| 137 | 132 | |
|---|
| 138 | 133 | static int etb_enable_hw(struct etb_drvdata *drvdata) |
|---|
| 139 | 134 | { |
|---|
| 140 | | - int rc = coresight_claim_device(drvdata->base); |
|---|
| 135 | + int rc = coresight_claim_device(drvdata->csdev); |
|---|
| 141 | 136 | |
|---|
| 142 | 137 | if (rc) |
|---|
| 143 | 138 | return rc; |
|---|
| .. | .. |
|---|
| 177 | 172 | static int etb_enable_perf(struct coresight_device *csdev, void *data) |
|---|
| 178 | 173 | { |
|---|
| 179 | 174 | int ret = 0; |
|---|
| 175 | + pid_t pid; |
|---|
| 180 | 176 | unsigned long flags; |
|---|
| 181 | 177 | struct etb_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); |
|---|
| 178 | + struct perf_output_handle *handle = data; |
|---|
| 179 | + struct cs_buffers *buf = etm_perf_sink_config(handle); |
|---|
| 182 | 180 | |
|---|
| 183 | 181 | spin_lock_irqsave(&drvdata->spinlock, flags); |
|---|
| 184 | 182 | |
|---|
| 185 | | - /* No need to continue if the component is already in use. */ |
|---|
| 186 | | - if (drvdata->mode != CS_MODE_DISABLED) { |
|---|
| 183 | + /* No need to continue if the component is already in used by sysFS. */ |
|---|
| 184 | + if (drvdata->mode == CS_MODE_SYSFS) { |
|---|
| 187 | 185 | ret = -EBUSY; |
|---|
| 186 | + goto out; |
|---|
| 187 | + } |
|---|
| 188 | + |
|---|
| 189 | + /* Get a handle on the pid of the process to monitor */ |
|---|
| 190 | + pid = buf->pid; |
|---|
| 191 | + |
|---|
| 192 | + if (drvdata->pid != -1 && drvdata->pid != pid) { |
|---|
| 193 | + ret = -EBUSY; |
|---|
| 194 | + goto out; |
|---|
| 195 | + } |
|---|
| 196 | + |
|---|
| 197 | + /* |
|---|
| 198 | + * No HW configuration is needed if the sink is already in |
|---|
| 199 | + * use for this session. |
|---|
| 200 | + */ |
|---|
| 201 | + if (drvdata->pid == pid) { |
|---|
| 202 | + atomic_inc(csdev->refcnt); |
|---|
| 188 | 203 | goto out; |
|---|
| 189 | 204 | } |
|---|
| 190 | 205 | |
|---|
| .. | .. |
|---|
| 193 | 208 | * the perf buffer. So we can perform the step before we turn the |
|---|
| 194 | 209 | * ETB on and leave without cleaning up. |
|---|
| 195 | 210 | */ |
|---|
| 196 | | - ret = etb_set_buffer(csdev, (struct perf_output_handle *)data); |
|---|
| 211 | + ret = etb_set_buffer(csdev, handle); |
|---|
| 197 | 212 | if (ret) |
|---|
| 198 | 213 | goto out; |
|---|
| 199 | 214 | |
|---|
| 200 | 215 | ret = etb_enable_hw(drvdata); |
|---|
| 201 | 216 | if (!ret) { |
|---|
| 217 | + /* Associate with monitored process. */ |
|---|
| 218 | + drvdata->pid = pid; |
|---|
| 202 | 219 | drvdata->mode = CS_MODE_PERF; |
|---|
| 203 | 220 | atomic_inc(csdev->refcnt); |
|---|
| 204 | 221 | } |
|---|
| .. | .. |
|---|
| 211 | 228 | static int etb_enable(struct coresight_device *csdev, u32 mode, void *data) |
|---|
| 212 | 229 | { |
|---|
| 213 | 230 | int ret; |
|---|
| 214 | | - struct etb_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); |
|---|
| 215 | 231 | |
|---|
| 216 | 232 | switch (mode) { |
|---|
| 217 | 233 | case CS_MODE_SYSFS: |
|---|
| .. | .. |
|---|
| 228 | 244 | if (ret) |
|---|
| 229 | 245 | return ret; |
|---|
| 230 | 246 | |
|---|
| 231 | | - dev_dbg(drvdata->dev, "ETB enabled\n"); |
|---|
| 247 | + dev_dbg(&csdev->dev, "ETB enabled\n"); |
|---|
| 232 | 248 | return 0; |
|---|
| 233 | 249 | } |
|---|
| 234 | 250 | |
|---|
| 235 | 251 | static void __etb_disable_hw(struct etb_drvdata *drvdata) |
|---|
| 236 | 252 | { |
|---|
| 237 | 253 | u32 ffcr; |
|---|
| 254 | + struct device *dev = &drvdata->csdev->dev; |
|---|
| 255 | + struct csdev_access *csa = &drvdata->csdev->access; |
|---|
| 238 | 256 | |
|---|
| 239 | 257 | CS_UNLOCK(drvdata->base); |
|---|
| 240 | 258 | |
|---|
| .. | .. |
|---|
| 246 | 264 | ffcr |= ETB_FFCR_FON_MAN; |
|---|
| 247 | 265 | writel_relaxed(ffcr, drvdata->base + ETB_FFCR); |
|---|
| 248 | 266 | |
|---|
| 249 | | - if (coresight_timeout(drvdata->base, ETB_FFCR, ETB_FFCR_BIT, 0)) { |
|---|
| 250 | | - dev_err(drvdata->dev, |
|---|
| 267 | + if (coresight_timeout(csa, ETB_FFCR, ETB_FFCR_BIT, 0)) { |
|---|
| 268 | + dev_err(dev, |
|---|
| 251 | 269 | "timeout while waiting for completion of Manual Flush\n"); |
|---|
| 252 | 270 | } |
|---|
| 253 | 271 | |
|---|
| 254 | 272 | /* disable trace capture */ |
|---|
| 255 | 273 | writel_relaxed(0x0, drvdata->base + ETB_CTL_REG); |
|---|
| 256 | 274 | |
|---|
| 257 | | - if (coresight_timeout(drvdata->base, ETB_FFSR, ETB_FFSR_BIT, 1)) { |
|---|
| 258 | | - dev_err(drvdata->dev, |
|---|
| 275 | + if (coresight_timeout(csa, ETB_FFSR, ETB_FFSR_BIT, 1)) { |
|---|
| 276 | + dev_err(dev, |
|---|
| 259 | 277 | "timeout while waiting for Formatter to Stop\n"); |
|---|
| 260 | 278 | } |
|---|
| 261 | 279 | |
|---|
| .. | .. |
|---|
| 270 | 288 | u32 read_data, depth; |
|---|
| 271 | 289 | u32 read_ptr, write_ptr; |
|---|
| 272 | 290 | u32 frame_off, frame_endoff; |
|---|
| 291 | + struct device *dev = &drvdata->csdev->dev; |
|---|
| 273 | 292 | |
|---|
| 274 | 293 | CS_UNLOCK(drvdata->base); |
|---|
| 275 | 294 | |
|---|
| .. | .. |
|---|
| 279 | 298 | frame_off = write_ptr % ETB_FRAME_SIZE_WORDS; |
|---|
| 280 | 299 | frame_endoff = ETB_FRAME_SIZE_WORDS - frame_off; |
|---|
| 281 | 300 | if (frame_off) { |
|---|
| 282 | | - dev_err(drvdata->dev, |
|---|
| 301 | + dev_err(dev, |
|---|
| 283 | 302 | "write_ptr: %lu not aligned to formatter frame size\n", |
|---|
| 284 | 303 | (unsigned long)write_ptr); |
|---|
| 285 | | - dev_err(drvdata->dev, "frameoff: %lu, frame_endoff: %lu\n", |
|---|
| 304 | + dev_err(dev, "frameoff: %lu, frame_endoff: %lu\n", |
|---|
| 286 | 305 | (unsigned long)frame_off, (unsigned long)frame_endoff); |
|---|
| 287 | 306 | write_ptr += frame_endoff; |
|---|
| 288 | 307 | } |
|---|
| .. | .. |
|---|
| 326 | 345 | { |
|---|
| 327 | 346 | __etb_disable_hw(drvdata); |
|---|
| 328 | 347 | etb_dump_hw(drvdata); |
|---|
| 329 | | - coresight_disclaim_device(drvdata->base); |
|---|
| 348 | + coresight_disclaim_device(drvdata->csdev); |
|---|
| 330 | 349 | } |
|---|
| 331 | 350 | |
|---|
| 332 | 351 | static int etb_disable(struct coresight_device *csdev) |
|---|
| .. | .. |
|---|
| 344 | 363 | /* Complain if we (somehow) got out of sync */ |
|---|
| 345 | 364 | WARN_ON_ONCE(drvdata->mode == CS_MODE_DISABLED); |
|---|
| 346 | 365 | etb_disable_hw(drvdata); |
|---|
| 366 | + /* Dissociate from monitored process. */ |
|---|
| 367 | + drvdata->pid = -1; |
|---|
| 347 | 368 | drvdata->mode = CS_MODE_DISABLED; |
|---|
| 348 | 369 | spin_unlock_irqrestore(&drvdata->spinlock, flags); |
|---|
| 349 | 370 | |
|---|
| 350 | | - dev_dbg(drvdata->dev, "ETB disabled\n"); |
|---|
| 371 | + dev_dbg(&csdev->dev, "ETB disabled\n"); |
|---|
| 351 | 372 | return 0; |
|---|
| 352 | 373 | } |
|---|
| 353 | 374 | |
|---|
| .. | .. |
|---|
| 355 | 376 | struct perf_event *event, void **pages, |
|---|
| 356 | 377 | int nr_pages, bool overwrite) |
|---|
| 357 | 378 | { |
|---|
| 358 | | - int node, cpu = event->cpu; |
|---|
| 379 | + int node; |
|---|
| 359 | 380 | struct cs_buffers *buf; |
|---|
| 360 | 381 | |
|---|
| 361 | | - node = (cpu == -1) ? NUMA_NO_NODE : cpu_to_node(cpu); |
|---|
| 382 | + node = (event->cpu == -1) ? NUMA_NO_NODE : cpu_to_node(event->cpu); |
|---|
| 362 | 383 | |
|---|
| 363 | 384 | buf = kzalloc_node(sizeof(struct cs_buffers), GFP_KERNEL, node); |
|---|
| 364 | 385 | if (!buf) |
|---|
| 365 | 386 | return NULL; |
|---|
| 366 | 387 | |
|---|
| 388 | + buf->pid = task_pid_nr(event->owner); |
|---|
| 367 | 389 | buf->snapshot = overwrite; |
|---|
| 368 | 390 | buf->nr_pages = nr_pages; |
|---|
| 369 | 391 | buf->data_pages = pages; |
|---|
| .. | .. |
|---|
| 412 | 434 | const u32 *barrier; |
|---|
| 413 | 435 | u32 read_ptr, write_ptr, capacity; |
|---|
| 414 | 436 | u32 status, read_data; |
|---|
| 415 | | - unsigned long offset, to_read, flags; |
|---|
| 437 | + unsigned long offset, to_read = 0, flags; |
|---|
| 416 | 438 | struct cs_buffers *buf = sink_config; |
|---|
| 417 | 439 | struct etb_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); |
|---|
| 418 | 440 | |
|---|
| .. | .. |
|---|
| 422 | 444 | capacity = drvdata->buffer_depth * ETB_FRAME_SIZE_WORDS; |
|---|
| 423 | 445 | |
|---|
| 424 | 446 | spin_lock_irqsave(&drvdata->spinlock, flags); |
|---|
| 447 | + |
|---|
| 448 | + /* Don't do anything if another tracer is using this sink */ |
|---|
| 449 | + if (atomic_read(csdev->refcnt) != 1) |
|---|
| 450 | + goto out; |
|---|
| 451 | + |
|---|
| 425 | 452 | __etb_disable_hw(drvdata); |
|---|
| 426 | 453 | CS_UNLOCK(drvdata->base); |
|---|
| 427 | 454 | |
|---|
| .. | .. |
|---|
| 435 | 462 | * chance to fix things. |
|---|
| 436 | 463 | */ |
|---|
| 437 | 464 | if (write_ptr % ETB_FRAME_SIZE_WORDS) { |
|---|
| 438 | | - dev_err(drvdata->dev, |
|---|
| 465 | + dev_err(&csdev->dev, |
|---|
| 439 | 466 | "write_ptr: %lu not aligned to formatter frame size\n", |
|---|
| 440 | 467 | (unsigned long)write_ptr); |
|---|
| 441 | 468 | |
|---|
| .. | .. |
|---|
| 501 | 528 | |
|---|
| 502 | 529 | cur = buf->cur; |
|---|
| 503 | 530 | offset = buf->offset; |
|---|
| 504 | | - barrier = barrier_pkt; |
|---|
| 531 | + barrier = coresight_barrier_pkt; |
|---|
| 505 | 532 | |
|---|
| 506 | 533 | for (i = 0; i < to_read; i += 4) { |
|---|
| 507 | 534 | buf_ptr = buf->data_pages[cur] + offset; |
|---|
| .. | .. |
|---|
| 529 | 556 | writel_relaxed(0x0, drvdata->base + ETB_RAM_WRITE_POINTER); |
|---|
| 530 | 557 | |
|---|
| 531 | 558 | /* |
|---|
| 532 | | - * In snapshot mode we have to update the handle->head to point |
|---|
| 533 | | - * to the new location. |
|---|
| 559 | + * In snapshot mode we simply increment the head by the number of byte |
|---|
| 560 | + * that were written. User space function cs_etm_find_snapshot() will |
|---|
| 561 | + * figure out how many bytes to get from the AUX buffer based on the |
|---|
| 562 | + * position of the head. |
|---|
| 534 | 563 | */ |
|---|
| 535 | | - if (buf->snapshot) { |
|---|
| 536 | | - handle->head = (cur * PAGE_SIZE) + offset; |
|---|
| 537 | | - to_read = buf->nr_pages << PAGE_SHIFT; |
|---|
| 538 | | - } |
|---|
| 564 | + if (buf->snapshot) |
|---|
| 565 | + handle->head += to_read; |
|---|
| 566 | + |
|---|
| 539 | 567 | __etb_enable_hw(drvdata); |
|---|
| 540 | 568 | CS_LOCK(drvdata->base); |
|---|
| 569 | +out: |
|---|
| 541 | 570 | spin_unlock_irqrestore(&drvdata->spinlock, flags); |
|---|
| 542 | 571 | |
|---|
| 543 | 572 | return to_read; |
|---|
| .. | .. |
|---|
| 567 | 596 | } |
|---|
| 568 | 597 | spin_unlock_irqrestore(&drvdata->spinlock, flags); |
|---|
| 569 | 598 | |
|---|
| 570 | | - dev_dbg(drvdata->dev, "ETB dumped\n"); |
|---|
| 599 | + dev_dbg(&drvdata->csdev->dev, "ETB dumped\n"); |
|---|
| 571 | 600 | } |
|---|
| 572 | 601 | |
|---|
| 573 | 602 | static int etb_open(struct inode *inode, struct file *file) |
|---|
| .. | .. |
|---|
| 578 | 607 | if (local_cmpxchg(&drvdata->reading, 0, 1)) |
|---|
| 579 | 608 | return -EBUSY; |
|---|
| 580 | 609 | |
|---|
| 581 | | - dev_dbg(drvdata->dev, "%s: successfully opened\n", __func__); |
|---|
| 610 | + dev_dbg(&drvdata->csdev->dev, "%s: successfully opened\n", __func__); |
|---|
| 582 | 611 | return 0; |
|---|
| 583 | 612 | } |
|---|
| 584 | 613 | |
|---|
| .. | .. |
|---|
| 588 | 617 | u32 depth; |
|---|
| 589 | 618 | struct etb_drvdata *drvdata = container_of(file->private_data, |
|---|
| 590 | 619 | struct etb_drvdata, miscdev); |
|---|
| 620 | + struct device *dev = &drvdata->csdev->dev; |
|---|
| 591 | 621 | |
|---|
| 592 | 622 | etb_dump(drvdata); |
|---|
| 593 | 623 | |
|---|
| .. | .. |
|---|
| 596 | 626 | len = depth * 4 - *ppos; |
|---|
| 597 | 627 | |
|---|
| 598 | 628 | if (copy_to_user(data, drvdata->buf + *ppos, len)) { |
|---|
| 599 | | - dev_dbg(drvdata->dev, "%s: copy_to_user failed\n", __func__); |
|---|
| 629 | + dev_dbg(dev, |
|---|
| 630 | + "%s: copy_to_user failed\n", __func__); |
|---|
| 600 | 631 | return -EFAULT; |
|---|
| 601 | 632 | } |
|---|
| 602 | 633 | |
|---|
| 603 | 634 | *ppos += len; |
|---|
| 604 | 635 | |
|---|
| 605 | | - dev_dbg(drvdata->dev, "%s: %zu bytes copied, %d bytes left\n", |
|---|
| 636 | + dev_dbg(dev, "%s: %zu bytes copied, %d bytes left\n", |
|---|
| 606 | 637 | __func__, len, (int)(depth * 4 - *ppos)); |
|---|
| 607 | 638 | return len; |
|---|
| 608 | 639 | } |
|---|
| .. | .. |
|---|
| 613 | 644 | struct etb_drvdata, miscdev); |
|---|
| 614 | 645 | local_set(&drvdata->reading, 0); |
|---|
| 615 | 646 | |
|---|
| 616 | | - dev_dbg(drvdata->dev, "%s: released\n", __func__); |
|---|
| 647 | + dev_dbg(&drvdata->csdev->dev, "%s: released\n", __func__); |
|---|
| 617 | 648 | return 0; |
|---|
| 618 | 649 | } |
|---|
| 619 | 650 | |
|---|
| .. | .. |
|---|
| 689 | 720 | .name = "mgmt", |
|---|
| 690 | 721 | }; |
|---|
| 691 | 722 | |
|---|
| 692 | | -const struct attribute_group *coresight_etb_groups[] = { |
|---|
| 723 | +static const struct attribute_group *coresight_etb_groups[] = { |
|---|
| 693 | 724 | &coresight_etb_group, |
|---|
| 694 | 725 | &coresight_etb_mgmt_group, |
|---|
| 695 | 726 | NULL, |
|---|
| .. | .. |
|---|
| 704 | 735 | struct etb_drvdata *drvdata; |
|---|
| 705 | 736 | struct resource *res = &adev->res; |
|---|
| 706 | 737 | struct coresight_desc desc = { 0 }; |
|---|
| 707 | | - struct device_node *np = adev->dev.of_node; |
|---|
| 708 | 738 | |
|---|
| 709 | | - if (np) { |
|---|
| 710 | | - pdata = of_get_coresight_platform_data(dev, np); |
|---|
| 711 | | - if (IS_ERR(pdata)) |
|---|
| 712 | | - return PTR_ERR(pdata); |
|---|
| 713 | | - adev->dev.platform_data = pdata; |
|---|
| 714 | | - } |
|---|
| 739 | + desc.name = coresight_alloc_device_name(&etb_devs, dev); |
|---|
| 740 | + if (!desc.name) |
|---|
| 741 | + return -ENOMEM; |
|---|
| 715 | 742 | |
|---|
| 716 | 743 | drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); |
|---|
| 717 | 744 | if (!drvdata) |
|---|
| 718 | 745 | return -ENOMEM; |
|---|
| 719 | 746 | |
|---|
| 720 | | - drvdata->dev = &adev->dev; |
|---|
| 721 | 747 | drvdata->atclk = devm_clk_get(&adev->dev, "atclk"); /* optional */ |
|---|
| 722 | 748 | if (!IS_ERR(drvdata->atclk)) { |
|---|
| 723 | 749 | ret = clk_prepare_enable(drvdata->atclk); |
|---|
| .. | .. |
|---|
| 732 | 758 | return PTR_ERR(base); |
|---|
| 733 | 759 | |
|---|
| 734 | 760 | drvdata->base = base; |
|---|
| 761 | + desc.access = CSDEV_ACCESS_IOMEM(base); |
|---|
| 735 | 762 | |
|---|
| 736 | 763 | spin_lock_init(&drvdata->spinlock); |
|---|
| 737 | 764 | |
|---|
| 738 | 765 | drvdata->buffer_depth = etb_get_buffer_depth(drvdata); |
|---|
| 739 | | - pm_runtime_put(&adev->dev); |
|---|
| 740 | 766 | |
|---|
| 741 | 767 | if (drvdata->buffer_depth & 0x80000000) |
|---|
| 742 | 768 | return -EINVAL; |
|---|
| .. | .. |
|---|
| 745 | 771 | drvdata->buffer_depth, 4, GFP_KERNEL); |
|---|
| 746 | 772 | if (!drvdata->buf) |
|---|
| 747 | 773 | return -ENOMEM; |
|---|
| 774 | + |
|---|
| 775 | + /* This device is not associated with a session */ |
|---|
| 776 | + drvdata->pid = -1; |
|---|
| 777 | + |
|---|
| 778 | + pdata = coresight_get_platform_data(dev); |
|---|
| 779 | + if (IS_ERR(pdata)) |
|---|
| 780 | + return PTR_ERR(pdata); |
|---|
| 781 | + adev->dev.platform_data = pdata; |
|---|
| 748 | 782 | |
|---|
| 749 | 783 | desc.type = CORESIGHT_DEV_TYPE_SINK; |
|---|
| 750 | 784 | desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER; |
|---|
| .. | .. |
|---|
| 756 | 790 | if (IS_ERR(drvdata->csdev)) |
|---|
| 757 | 791 | return PTR_ERR(drvdata->csdev); |
|---|
| 758 | 792 | |
|---|
| 759 | | - drvdata->miscdev.name = pdata->name; |
|---|
| 793 | + drvdata->miscdev.name = desc.name; |
|---|
| 760 | 794 | drvdata->miscdev.minor = MISC_DYNAMIC_MINOR; |
|---|
| 761 | 795 | drvdata->miscdev.fops = &etb_fops; |
|---|
| 762 | 796 | ret = misc_register(&drvdata->miscdev); |
|---|
| 763 | 797 | if (ret) |
|---|
| 764 | 798 | goto err_misc_register; |
|---|
| 765 | 799 | |
|---|
| 800 | + pm_runtime_put(&adev->dev); |
|---|
| 766 | 801 | return 0; |
|---|
| 767 | 802 | |
|---|
| 768 | 803 | err_misc_register: |
|---|
| 769 | 804 | coresight_unregister(drvdata->csdev); |
|---|
| 770 | 805 | return ret; |
|---|
| 806 | +} |
|---|
| 807 | + |
|---|
| 808 | +static void etb_remove(struct amba_device *adev) |
|---|
| 809 | +{ |
|---|
| 810 | + struct etb_drvdata *drvdata = dev_get_drvdata(&adev->dev); |
|---|
| 811 | + |
|---|
| 812 | + /* |
|---|
| 813 | + * Since misc_open() holds a refcount on the f_ops, which is |
|---|
| 814 | + * etb fops in this case, device is there until last file |
|---|
| 815 | + * handler to this device is closed. |
|---|
| 816 | + */ |
|---|
| 817 | + misc_deregister(&drvdata->miscdev); |
|---|
| 818 | + coresight_unregister(drvdata->csdev); |
|---|
| 771 | 819 | } |
|---|
| 772 | 820 | |
|---|
| 773 | 821 | #ifdef CONFIG_PM |
|---|
| .. | .. |
|---|
| 804 | 852 | { 0, 0}, |
|---|
| 805 | 853 | }; |
|---|
| 806 | 854 | |
|---|
| 855 | +MODULE_DEVICE_TABLE(amba, etb_ids); |
|---|
| 856 | + |
|---|
| 807 | 857 | static struct amba_driver etb_driver = { |
|---|
| 808 | 858 | .drv = { |
|---|
| 809 | 859 | .name = "coresight-etb10", |
|---|
| .. | .. |
|---|
| 813 | 863 | |
|---|
| 814 | 864 | }, |
|---|
| 815 | 865 | .probe = etb_probe, |
|---|
| 866 | + .remove = etb_remove, |
|---|
| 816 | 867 | .id_table = etb_ids, |
|---|
| 817 | 868 | }; |
|---|
| 818 | | -builtin_amba_driver(etb_driver); |
|---|
| 869 | + |
|---|
| 870 | +module_amba_driver(etb_driver); |
|---|
| 871 | + |
|---|
| 872 | +MODULE_AUTHOR("Pratik Patel <pratikp@codeaurora.org>"); |
|---|
| 873 | +MODULE_AUTHOR("Mathieu Poirier <mathieu.poirier@linaro.org>"); |
|---|
| 874 | +MODULE_DESCRIPTION("Arm CoreSight Embedded Trace Buffer driver"); |
|---|
| 875 | +MODULE_LICENSE("GPL v2"); |
|---|