Expose timestamp information supported by the GPU with a new device query. Mali uses an external timer as GPU system time. On ARM, this is wired to the generic arch timer so we wire cntfrq_el0 as device frequency. This new uAPI will be used in Mesa to implement timestamp queries and VK_KHR_calibrated_timestamps. Since this extends the uAPI and because userland needs a way to advertise those features conditionally, this also bumps the driver minor version. v2: - Rewrote to use GPU timestamp register - Added timestamp_offset to drm_panthor_timestamp_info - Add missing include for arch_timer_get_cntfrq - Rework commit message v3: - Add panthor_gpu_read_64bit_counter - Change panthor_gpu_read_timestamp to use panthor_gpu_read_64bit_counter v4: - Fix multiple typos in uAPI documentation - Mention behavior when the timestamp frequency is unknown - Use u64 instead of unsigned long long for panthor_gpu_read_timestamp - Apply r-b from Mihail
Unified · Split
| @@ -3,6 +3,10 @@ · 2 unmodified lines | |||
| 3 | /* Copyright 2019 Linaro, Ltd., Rob Herring <robh@kernel.org> */ | 3 | /* Copyright 2019 Linaro, Ltd., Rob Herring <robh@kernel.org> */ |
| 4 | /* Copyright 2019 Collabora ltd. */ | 4 | /* Copyright 2019 Collabora ltd. */ |
| 5 | 5 | ||
| 6 | #ifdef CONFIG_ARM_ARCH_TIMER | ||
| 7 | #include <asm/arch_timer.h> | ||
| 8 | #endif | ||
| 9 | |||
| 6 | #include <linux/list.h> | 10 | #include <linux/list.h> |
| 7 | #include <linux/module.h> | 11 | #include <linux/module.h> |
| 8 | #include <linux/of_platform.h> | 12 | #include <linux/of_platform.h> |
| @@ -164,6 +168,7 @@ panthor_get_uobj_array(const struct drm_panthor_obj_array *in, u32 min_stride, · 155 unmodified lines | |||
| 164 | _Generic(_obj_name, \ | 168 | _Generic(_obj_name, \ |
| 165 | PANTHOR_UOBJ_DECL(struct drm_panthor_gpu_info, tiler_present), \ | 169 | PANTHOR_UOBJ_DECL(struct drm_panthor_gpu_info, tiler_present), \ |
| 166 | PANTHOR_UOBJ_DECL(struct drm_panthor_csif_info, pad), \ | 170 | PANTHOR_UOBJ_DECL(struct drm_panthor_csif_info, pad), \ |
| 171 | PANTHOR_UOBJ_DECL(struct drm_panthor_timestamp_info, current_timestamp), \ | ||
| 167 | PANTHOR_UOBJ_DECL(struct drm_panthor_sync_op, timeline_value), \ | 172 | PANTHOR_UOBJ_DECL(struct drm_panthor_sync_op, timeline_value), \ |
| 168 | PANTHOR_UOBJ_DECL(struct drm_panthor_queue_submit, syncs), \ | 173 | PANTHOR_UOBJ_DECL(struct drm_panthor_queue_submit, syncs), \ |
| 169 | PANTHOR_UOBJ_DECL(struct drm_panthor_queue_create, ringbuf_size), \ | 174 | PANTHOR_UOBJ_DECL(struct drm_panthor_queue_create, ringbuf_size), \ |
| @@ -750,10 +755,33 @@ static void panthor_submit_ctx_cleanup(struct panthor_submit_ctx *ctx, · 580 unmodified lines | |||
| 750 | kvfree(ctx->jobs); | 755 | kvfree(ctx->jobs); |
| 751 | } | 756 | } |
| 752 | 757 | ||
| 758 | static int panthor_query_timestamp_info(struct panthor_device *ptdev, | ||
| 759 | struct drm_panthor_timestamp_info *arg) | ||
| 760 | { | ||
| 761 | int ret; | ||
| 762 | |||
| 763 | ret = pm_runtime_resume_and_get(ptdev->base.dev); | ||
| 764 | if (ret) | ||
| 765 | return ret; | ||
| 766 | |||
| 767 | #ifdef CONFIG_ARM_ARCH_TIMER | ||
| 768 | arg->timestamp_frequency = arch_timer_get_cntfrq(); | ||
| 769 | #else | ||
| 770 | arg->timestamp_frequency = 0; | ||
| 771 | #endif | ||
| 772 | arg->current_timestamp = panthor_gpu_read_timestamp(ptdev); | ||
| 773 | arg->timestamp_offset = panthor_gpu_read_timestamp_offset(ptdev); | ||
| 774 | |||
| 775 | pm_runtime_put(ptdev->base.dev); | ||
| 776 | return 0; | ||
| 777 | } | ||
| 778 | |||
| 753 | static int panthor_ioctl_dev_query(struct drm_device *ddev, void *data, struct drm_file *file) | 779 | static int panthor_ioctl_dev_query(struct drm_device *ddev, void *data, struct drm_file *file) |
| 754 | { | 780 | { |
| 755 | struct panthor_device *ptdev = container_of(ddev, struct panthor_device, base); | 781 | struct panthor_device *ptdev = container_of(ddev, struct panthor_device, base); |
| 756 | struct drm_panthor_dev_query *args = data; | 782 | struct drm_panthor_dev_query *args = data; |
| 783 | struct drm_panthor_timestamp_info timestamp_info; | ||
| 784 | int ret; | ||
| 757 | 785 | ||
| 758 | if (!args->pointer) { | 786 | if (!args->pointer) { |
| 759 | switch (args->type) { | 787 | switch (args->type) { |
| @@ -765,6 +793,10 @@ static int panthor_ioctl_dev_query(struct drm_device *ddev, void *data, struct d · 5 unmodified lines | |||
| 765 | args->size = sizeof(ptdev->csif_info); | 793 | args->size = sizeof(ptdev->csif_info); |
| 766 | return 0; | 794 | return 0; |
| 767 | 795 | ||
| 796 | case DRM_PANTHOR_DEV_QUERY_TIMESTAMP_INFO: | ||
| 797 | args->size = sizeof(timestamp_info); | ||
| 798 | return 0; | ||
| 799 | |||
| 768 | default: | 800 | default: |
| 769 | return -EINVAL; | 801 | return -EINVAL; |
| 770 | } | 802 | } |
| @@ -777,6 +809,14 @@ static int panthor_ioctl_dev_query(struct drm_device *ddev, void *data, struct d · 6 unmodified lines | |||
| 777 | case DRM_PANTHOR_DEV_QUERY_CSIF_INFO: | 809 | case DRM_PANTHOR_DEV_QUERY_CSIF_INFO: |
| 778 | return PANTHOR_UOBJ_SET(args->pointer, args->size, ptdev->csif_info); | 810 | return PANTHOR_UOBJ_SET(args->pointer, args->size, ptdev->csif_info); |
| 779 | 811 | ||
| 812 | case DRM_PANTHOR_DEV_QUERY_TIMESTAMP_INFO: | ||
| 813 | ret = panthor_query_timestamp_info(ptdev, ×tamp_info); | ||
| 814 | |||
| 815 | if (ret) | ||
| 816 | return ret; | ||
| 817 | |||
| 818 | return PANTHOR_UOBJ_SET(args->pointer, args->size, timestamp_info); | ||
| 819 | |||
| 780 | default: | 820 | default: |
| 781 | return -EINVAL; | 821 | return -EINVAL; |
| 782 | } | 822 | } |
| @@ -1372,6 +1412,7 @@ static void panthor_debugfs_init(struct drm_minor *minor) · 589 unmodified lines | |||
| 1372 | /* | 1412 | /* |
| 1373 | * PanCSF driver version: | 1413 | * PanCSF driver version: |
| 1374 | * - 1.0 - initial interface | 1414 | * - 1.0 - initial interface |
| 1415 | * - 1.1 - adds DEV_QUERY_TIMESTAMP_INFO query | ||
| 1375 | */ | 1416 | */ |
| 1376 | static const struct drm_driver panthor_drm_driver = { | 1417 | static const struct drm_driver panthor_drm_driver = { |
| 1377 | .driver_features = DRIVER_RENDER | DRIVER_GEM | DRIVER_SYNCOBJ | | 1418 | .driver_features = DRIVER_RENDER | DRIVER_GEM | DRIVER_SYNCOBJ | |
| @@ -1385,7 +1426,7 @@ static const struct drm_driver panthor_drm_driver = { · 7 unmodified lines | |||
| 1385 | .desc = "Panthor DRM driver", | 1426 | .desc = "Panthor DRM driver", |
| 1386 | .date = "20230801", | 1427 | .date = "20230801", |
| 1387 | .major = 1, | 1428 | .major = 1, |
| 1388 | .minor = 0, | 1429 | .minor = 1, |
| 1389 | 1430 | ||
| 1390 | .gem_create_object = panthor_gem_create_object, | 1431 | .gem_create_object = panthor_gem_create_object, |
| 1391 | .gem_prime_import_sg_table = drm_gem_shmem_prime_import_sg_table, | 1432 | .gem_prime_import_sg_table = drm_gem_shmem_prime_import_sg_table, |
| @@ -480,3 +480,50 @@ void panthor_gpu_resume(struct panthor_device *ptdev) · 479 unmodified lines | |||
| 480 | panthor_gpu_irq_resume(&ptdev->gpu->irq, GPU_INTERRUPTS_MASK); | 480 | panthor_gpu_irq_resume(&ptdev->gpu->irq, GPU_INTERRUPTS_MASK); |
| 481 | panthor_gpu_l2_power_on(ptdev); | 481 | panthor_gpu_l2_power_on(ptdev); |
| 482 | } | 482 | } |
| 483 | |||
| 484 | /** | ||
| 485 | * panthor_gpu_read_64bit_counter() - Read a 64-bit counter at a given offset. | ||
| 486 | * @ptdev: Device. | ||
| 487 | * @reg: The offset of the register to read. | ||
| 488 | * | ||
| 489 | * Return: The counter value. | ||
| 490 | */ | ||
| 491 | static u64 | ||
| 492 | panthor_gpu_read_64bit_counter(struct panthor_device *ptdev, u32 reg) | ||
| 493 | { | ||
| 494 | u32 hi, lo; | ||
| 495 | |||
| 496 | do { | ||
| 497 | hi = gpu_read(ptdev, reg + 0x4); | ||
| 498 | lo = gpu_read(ptdev, reg); | ||
| 499 | } while (hi != gpu_read(ptdev, reg + 0x4)); | ||
| 500 | |||
| 501 | return ((u64)hi << 32) | lo; | ||
| 502 | } | ||
| 503 | |||
| 504 | /** | ||
| 505 | * panthor_gpu_read_timestamp() - Read the timestamp register. | ||
| 506 | * @ptdev: Device. | ||
| 507 | * | ||
| 508 | * Return: The GPU timestamp value. | ||
| 509 | */ | ||
| 510 | u64 panthor_gpu_read_timestamp(struct panthor_device *ptdev) | ||
| 511 | { | ||
| 512 | return panthor_gpu_read_64bit_counter(ptdev, GPU_TIMESTAMP_LO); | ||
| 513 | } | ||
| 514 | |||
| 515 | /** | ||
| 516 | * panthor_gpu_read_timestamp_offset() - Read the timestamp offset register. | ||
| 517 | * @ptdev: Device. | ||
| 518 | * | ||
| 519 | * Return: The GPU timestamp offset value. | ||
| 520 | */ | ||
| 521 | u64 panthor_gpu_read_timestamp_offset(struct panthor_device *ptdev) | ||
| 522 | { | ||
| 523 | u32 hi, lo; | ||
| 524 | |||
| 525 | hi = gpu_read(ptdev, GPU_TIMESTAMP_OFFSET_HI); | ||
| 526 | lo = gpu_read(ptdev, GPU_TIMESTAMP_OFFSET_LO); | ||
| 527 | |||
| 528 | return ((u64)hi << 32) | lo; | ||
| 529 | } | ||
| @@ -5,6 +5,8 @@ · 4 unmodified lines | |||
| 5 | #ifndef __PANTHOR_GPU_H__ | 5 | #ifndef __PANTHOR_GPU_H__ |
| 6 | #define __PANTHOR_GPU_H__ | 6 | #define __PANTHOR_GPU_H__ |
| 7 | 7 | ||
| 8 | #include <linux/types.h> | ||
| 9 | |||
| 8 | struct panthor_device; | 10 | struct panthor_device; |
| 9 | 11 | ||
| 10 | int panthor_gpu_init(struct panthor_device *ptdev); | 12 | int panthor_gpu_init(struct panthor_device *ptdev); |
| @@ -48,5 +50,7 @@ int panthor_gpu_l2_power_on(struct panthor_device *ptdev); · 37 unmodified lines | |||
| 48 | int panthor_gpu_flush_caches(struct panthor_device *ptdev, | 50 | int panthor_gpu_flush_caches(struct panthor_device *ptdev, |
| 49 | u32 l2, u32 lsc, u32 other); | 51 | u32 l2, u32 lsc, u32 other); |
| 50 | int panthor_gpu_soft_reset(struct panthor_device *ptdev); | 52 | int panthor_gpu_soft_reset(struct panthor_device *ptdev); |
| 53 | u64 panthor_gpu_read_timestamp(struct panthor_device *ptdev); | ||
| 54 | u64 panthor_gpu_read_timestamp_offset(struct panthor_device *ptdev); | ||
| 51 | 55 | ||
| 52 | #endif | 56 | #endif |
| @@ -260,6 +260,9 @@ enum drm_panthor_dev_query_type { · 259 unmodified lines | |||
| 260 | 260 | ||
| 261 | /** @DRM_PANTHOR_DEV_QUERY_CSIF_INFO: Query command-stream interface information. */ | 261 | /** @DRM_PANTHOR_DEV_QUERY_CSIF_INFO: Query command-stream interface information. */ |
| 262 | DRM_PANTHOR_DEV_QUERY_CSIF_INFO, | 262 | DRM_PANTHOR_DEV_QUERY_CSIF_INFO, |
| 263 | |||
| 264 | /** @DRM_PANTHOR_DEV_QUERY_TIMESTAMP_INFO: Query timestamp information. */ | ||
| 265 | DRM_PANTHOR_DEV_QUERY_TIMESTAMP_INFO, | ||
| 263 | }; | 266 | }; |
| 264 | 267 | ||
| 265 | /** | 268 | /** |
| @@ -377,6 +380,25 @@ struct drm_panthor_csif_info { · 111 unmodified lines | |||
| 377 | __u32 pad; | 380 | __u32 pad; |
| 378 | }; | 381 | }; |
| 379 | 382 | ||
| 383 | /** | ||
| 384 | * struct drm_panthor_timestamp_info - Timestamp information | ||
| 385 | * | ||
| 386 | * Structure grouping all queryable information relating to the GPU timestamp. | ||
| 387 | */ | ||
| 388 | struct drm_panthor_timestamp_info { | ||
| 389 | /** | ||
| 390 | * @timestamp_frequency: The frequency of the timestamp timer or 0 if | ||
| 391 | * unknown. | ||
| 392 | */ | ||
| 393 | __u64 timestamp_frequency; | ||
| 394 | |||
| 395 | /** @current_timestamp: The current timestamp. */ | ||
| 396 | __u64 current_timestamp; | ||
| 397 | |||
| 398 | /** @timestamp_offset: The offset of the timestamp timer. */ | ||
| 399 | __u64 timestamp_offset; | ||
| 400 | }; | ||
| 401 | |||
| 380 | /** | 402 | /** |
| 381 | * struct drm_panthor_dev_query - Arguments passed to DRM_PANTHOR_IOCTL_DEV_QUERY | 403 | * struct drm_panthor_dev_query - Arguments passed to DRM_PANTHOR_IOCTL_DEV_QUERY |
| 382 | */ | 404 | */ |