| .. | .. |
|---|
| 3 | 3 | * Copyright (C) 2015-2018 Etnaviv Project |
|---|
| 4 | 4 | */ |
|---|
| 5 | 5 | |
|---|
| 6 | +#include <linux/clk.h> |
|---|
| 6 | 7 | #include <linux/component.h> |
|---|
| 8 | +#include <linux/delay.h> |
|---|
| 7 | 9 | #include <linux/dma-fence.h> |
|---|
| 8 | | -#include <linux/moduleparam.h> |
|---|
| 10 | +#include <linux/dma-mapping.h> |
|---|
| 11 | +#include <linux/module.h> |
|---|
| 9 | 12 | #include <linux/of_device.h> |
|---|
| 13 | +#include <linux/platform_device.h> |
|---|
| 14 | +#include <linux/pm_runtime.h> |
|---|
| 15 | +#include <linux/regulator/consumer.h> |
|---|
| 10 | 16 | #include <linux/thermal.h> |
|---|
| 11 | 17 | |
|---|
| 12 | 18 | #include "etnaviv_cmdbuf.h" |
|---|
| .. | .. |
|---|
| 36 | 42 | |
|---|
| 37 | 43 | int etnaviv_gpu_get_param(struct etnaviv_gpu *gpu, u32 param, u64 *value) |
|---|
| 38 | 44 | { |
|---|
| 45 | + struct etnaviv_drm_private *priv = gpu->drm->dev_private; |
|---|
| 46 | + |
|---|
| 39 | 47 | switch (param) { |
|---|
| 40 | 48 | case ETNAVIV_PARAM_GPU_MODEL: |
|---|
| 41 | 49 | *value = gpu->identity.model; |
|---|
| .. | .. |
|---|
| 139 | 147 | |
|---|
| 140 | 148 | case ETNAVIV_PARAM_GPU_NUM_VARYINGS: |
|---|
| 141 | 149 | *value = gpu->identity.varyings_count; |
|---|
| 150 | + break; |
|---|
| 151 | + |
|---|
| 152 | + case ETNAVIV_PARAM_SOFTPIN_START_ADDR: |
|---|
| 153 | + if (priv->mmu_global->version == ETNAVIV_IOMMU_V2) |
|---|
| 154 | + *value = ETNAVIV_SOFTPIN_START_ADDRESS; |
|---|
| 155 | + else |
|---|
| 156 | + *value = ~0ULL; |
|---|
| 142 | 157 | break; |
|---|
| 143 | 158 | |
|---|
| 144 | 159 | default: |
|---|
| .. | .. |
|---|
| 318 | 333 | gpu->identity.revision = etnaviv_field(chipIdentity, |
|---|
| 319 | 334 | VIVS_HI_CHIP_IDENTITY_REVISION); |
|---|
| 320 | 335 | } else { |
|---|
| 336 | + u32 chipDate = gpu_read(gpu, VIVS_HI_CHIP_DATE); |
|---|
| 321 | 337 | |
|---|
| 322 | 338 | gpu->identity.model = gpu_read(gpu, VIVS_HI_CHIP_MODEL); |
|---|
| 323 | 339 | gpu->identity.revision = gpu_read(gpu, VIVS_HI_CHIP_REV); |
|---|
| 340 | + gpu->identity.customer_id = gpu_read(gpu, VIVS_HI_CHIP_CUSTOMER_ID); |
|---|
| 341 | + |
|---|
| 342 | + /* |
|---|
| 343 | + * Reading these two registers on GC600 rev 0x19 result in a |
|---|
| 344 | + * unhandled fault: external abort on non-linefetch |
|---|
| 345 | + */ |
|---|
| 346 | + if (!etnaviv_is_model_rev(gpu, GC600, 0x19)) { |
|---|
| 347 | + gpu->identity.product_id = gpu_read(gpu, VIVS_HI_CHIP_PRODUCT_ID); |
|---|
| 348 | + gpu->identity.eco_id = gpu_read(gpu, VIVS_HI_CHIP_ECO_ID); |
|---|
| 349 | + } |
|---|
| 324 | 350 | |
|---|
| 325 | 351 | /* |
|---|
| 326 | 352 | * !!!! HACK ALERT !!!! |
|---|
| .. | .. |
|---|
| 335 | 361 | |
|---|
| 336 | 362 | /* Another special case */ |
|---|
| 337 | 363 | if (etnaviv_is_model_rev(gpu, GC300, 0x2201)) { |
|---|
| 338 | | - u32 chipDate = gpu_read(gpu, VIVS_HI_CHIP_DATE); |
|---|
| 339 | 364 | u32 chipTime = gpu_read(gpu, VIVS_HI_CHIP_TIME); |
|---|
| 340 | 365 | |
|---|
| 341 | 366 | if (chipDate == 0x20080814 && chipTime == 0x12051100) { |
|---|
| .. | .. |
|---|
| 358 | 383 | gpu->identity.model = chipModel_GC3000; |
|---|
| 359 | 384 | gpu->identity.revision &= 0xffff; |
|---|
| 360 | 385 | } |
|---|
| 386 | + |
|---|
| 387 | + if (etnaviv_is_model_rev(gpu, GC1000, 0x5037) && (chipDate == 0x20120617)) |
|---|
| 388 | + gpu->identity.eco_id = 1; |
|---|
| 389 | + |
|---|
| 390 | + if (etnaviv_is_model_rev(gpu, GC320, 0x5303) && (chipDate == 0x20140511)) |
|---|
| 391 | + gpu->identity.eco_id = 1; |
|---|
| 361 | 392 | } |
|---|
| 362 | 393 | |
|---|
| 363 | 394 | dev_info(gpu->dev, "model: GC%x, revision: %x\n", |
|---|
| 364 | 395 | gpu->identity.model, gpu->identity.revision); |
|---|
| 365 | 396 | |
|---|
| 397 | + gpu->idle_mask = ~VIVS_HI_IDLE_STATE_AXI_LP; |
|---|
| 366 | 398 | /* |
|---|
| 367 | 399 | * If there is a match in the HWDB, we aren't interested in the |
|---|
| 368 | 400 | * remaining register values, as they might be wrong. |
|---|
| .. | .. |
|---|
| 410 | 442 | } |
|---|
| 411 | 443 | |
|---|
| 412 | 444 | /* GC600 idle register reports zero bits where modules aren't present */ |
|---|
| 413 | | - if (gpu->identity.model == chipModel_GC600) { |
|---|
| 445 | + if (gpu->identity.model == chipModel_GC600) |
|---|
| 414 | 446 | gpu->idle_mask = VIVS_HI_IDLE_STATE_TX | |
|---|
| 415 | 447 | VIVS_HI_IDLE_STATE_RA | |
|---|
| 416 | 448 | VIVS_HI_IDLE_STATE_SE | |
|---|
| .. | .. |
|---|
| 419 | 451 | VIVS_HI_IDLE_STATE_PE | |
|---|
| 420 | 452 | VIVS_HI_IDLE_STATE_DE | |
|---|
| 421 | 453 | VIVS_HI_IDLE_STATE_FE; |
|---|
| 422 | | - } else { |
|---|
| 423 | | - gpu->idle_mask = ~VIVS_HI_IDLE_STATE_AXI_LP; |
|---|
| 424 | | - } |
|---|
| 425 | 454 | |
|---|
| 426 | 455 | etnaviv_hw_specs(gpu); |
|---|
| 427 | 456 | } |
|---|
| .. | .. |
|---|
| 493 | 522 | /* read idle register. */ |
|---|
| 494 | 523 | idle = gpu_read(gpu, VIVS_HI_IDLE_STATE); |
|---|
| 495 | 524 | |
|---|
| 496 | | - /* try reseting again if FE it not idle */ |
|---|
| 525 | + /* try resetting again if FE is not idle */ |
|---|
| 497 | 526 | if ((idle & VIVS_HI_IDLE_STATE_FE) == 0) { |
|---|
| 498 | 527 | dev_dbg(gpu->dev, "FE is not idle\n"); |
|---|
| 499 | 528 | continue; |
|---|
| .. | .. |
|---|
| 531 | 560 | |
|---|
| 532 | 561 | /* We rely on the GPU running, so program the clock */ |
|---|
| 533 | 562 | etnaviv_gpu_update_clock(gpu); |
|---|
| 563 | + |
|---|
| 564 | + gpu->fe_running = false; |
|---|
| 565 | + gpu->exec_state = -1; |
|---|
| 566 | + if (gpu->mmu_context) |
|---|
| 567 | + etnaviv_iommu_context_put(gpu->mmu_context); |
|---|
| 568 | + gpu->mmu_context = NULL; |
|---|
| 534 | 569 | |
|---|
| 535 | 570 | return 0; |
|---|
| 536 | 571 | } |
|---|
| .. | .. |
|---|
| 594 | 629 | VIVS_MMUv2_SEC_COMMAND_CONTROL_ENABLE | |
|---|
| 595 | 630 | VIVS_MMUv2_SEC_COMMAND_CONTROL_PREFETCH(prefetch)); |
|---|
| 596 | 631 | } |
|---|
| 632 | + |
|---|
| 633 | + gpu->fe_running = true; |
|---|
| 634 | +} |
|---|
| 635 | + |
|---|
| 636 | +static void etnaviv_gpu_start_fe_idleloop(struct etnaviv_gpu *gpu, |
|---|
| 637 | + struct etnaviv_iommu_context *context) |
|---|
| 638 | +{ |
|---|
| 639 | + u16 prefetch; |
|---|
| 640 | + u32 address; |
|---|
| 641 | + |
|---|
| 642 | + /* setup the MMU */ |
|---|
| 643 | + etnaviv_iommu_restore(gpu, context); |
|---|
| 644 | + |
|---|
| 645 | + /* Start command processor */ |
|---|
| 646 | + prefetch = etnaviv_buffer_init(gpu); |
|---|
| 647 | + address = etnaviv_cmdbuf_get_va(&gpu->buffer, |
|---|
| 648 | + &gpu->mmu_context->cmdbuf_mapping); |
|---|
| 649 | + |
|---|
| 650 | + etnaviv_gpu_start_fe(gpu, address, prefetch); |
|---|
| 597 | 651 | } |
|---|
| 598 | 652 | |
|---|
| 599 | 653 | static void etnaviv_gpu_setup_pulse_eater(struct etnaviv_gpu *gpu) |
|---|
| .. | .. |
|---|
| 629 | 683 | |
|---|
| 630 | 684 | static void etnaviv_gpu_hw_init(struct etnaviv_gpu *gpu) |
|---|
| 631 | 685 | { |
|---|
| 632 | | - u16 prefetch; |
|---|
| 633 | | - |
|---|
| 634 | 686 | if ((etnaviv_is_model_rev(gpu, GC320, 0x5007) || |
|---|
| 635 | 687 | etnaviv_is_model_rev(gpu, GC320, 0x5220)) && |
|---|
| 636 | 688 | gpu_read(gpu, VIVS_HI_CHIP_TIME) != 0x2062400) { |
|---|
| .. | .. |
|---|
| 676 | 728 | /* setup the pulse eater */ |
|---|
| 677 | 729 | etnaviv_gpu_setup_pulse_eater(gpu); |
|---|
| 678 | 730 | |
|---|
| 679 | | - /* setup the MMU */ |
|---|
| 680 | | - etnaviv_iommu_restore(gpu); |
|---|
| 681 | | - |
|---|
| 682 | | - /* Start command processor */ |
|---|
| 683 | | - prefetch = etnaviv_buffer_init(gpu); |
|---|
| 684 | | - |
|---|
| 685 | 731 | gpu_write(gpu, VIVS_HI_INTR_ENBL, ~0U); |
|---|
| 686 | | - etnaviv_gpu_start_fe(gpu, etnaviv_cmdbuf_get_va(&gpu->buffer), |
|---|
| 687 | | - prefetch); |
|---|
| 688 | 732 | } |
|---|
| 689 | 733 | |
|---|
| 690 | 734 | int etnaviv_gpu_init(struct etnaviv_gpu *gpu) |
|---|
| 691 | 735 | { |
|---|
| 736 | + struct etnaviv_drm_private *priv = gpu->drm->dev_private; |
|---|
| 692 | 737 | int ret, i; |
|---|
| 693 | 738 | |
|---|
| 694 | 739 | ret = pm_runtime_get_sync(gpu->dev); |
|---|
| .. | .. |
|---|
| 714 | 759 | } |
|---|
| 715 | 760 | |
|---|
| 716 | 761 | /* |
|---|
| 717 | | - * Set the GPU linear window to be at the end of the DMA window, where |
|---|
| 718 | | - * the CMA area is likely to reside. This ensures that we are able to |
|---|
| 719 | | - * map the command buffers while having the linear window overlap as |
|---|
| 720 | | - * much RAM as possible, so we can optimize mappings for other buffers. |
|---|
| 721 | | - * |
|---|
| 722 | | - * For 3D cores only do this if MC2.0 is present, as with MC1.0 it leads |
|---|
| 723 | | - * to different views of the memory on the individual engines. |
|---|
| 724 | | - */ |
|---|
| 725 | | - if (!(gpu->identity.features & chipFeatures_PIPE_3D) || |
|---|
| 726 | | - (gpu->identity.minor_features0 & chipMinorFeatures0_MC20)) { |
|---|
| 727 | | - u32 dma_mask = (u32)dma_get_required_mask(gpu->dev); |
|---|
| 728 | | - if (dma_mask < PHYS_OFFSET + SZ_2G) |
|---|
| 729 | | - gpu->memory_base = PHYS_OFFSET; |
|---|
| 730 | | - else |
|---|
| 731 | | - gpu->memory_base = dma_mask - SZ_2G + 1; |
|---|
| 732 | | - } else if (PHYS_OFFSET >= SZ_2G) { |
|---|
| 733 | | - dev_info(gpu->dev, "Need to move linear window on MC1.0, disabling TS\n"); |
|---|
| 734 | | - gpu->memory_base = PHYS_OFFSET; |
|---|
| 735 | | - gpu->identity.features &= ~chipFeatures_FAST_CLEAR; |
|---|
| 736 | | - } |
|---|
| 737 | | - |
|---|
| 738 | | - /* |
|---|
| 739 | 762 | * On cores with security features supported, we claim control over the |
|---|
| 740 | 763 | * security states. |
|---|
| 741 | 764 | */ |
|---|
| .. | .. |
|---|
| 749 | 772 | goto fail; |
|---|
| 750 | 773 | } |
|---|
| 751 | 774 | |
|---|
| 752 | | - gpu->mmu = etnaviv_iommu_new(gpu); |
|---|
| 753 | | - if (IS_ERR(gpu->mmu)) { |
|---|
| 754 | | - dev_err(gpu->dev, "Failed to instantiate GPU IOMMU\n"); |
|---|
| 755 | | - ret = PTR_ERR(gpu->mmu); |
|---|
| 775 | + ret = etnaviv_iommu_global_init(gpu); |
|---|
| 776 | + if (ret) |
|---|
| 756 | 777 | goto fail; |
|---|
| 778 | + |
|---|
| 779 | + /* |
|---|
| 780 | + * Set the GPU linear window to be at the end of the DMA window, where |
|---|
| 781 | + * the CMA area is likely to reside. This ensures that we are able to |
|---|
| 782 | + * map the command buffers while having the linear window overlap as |
|---|
| 783 | + * much RAM as possible, so we can optimize mappings for other buffers. |
|---|
| 784 | + * |
|---|
| 785 | + * For 3D cores only do this if MC2.0 is present, as with MC1.0 it leads |
|---|
| 786 | + * to different views of the memory on the individual engines. |
|---|
| 787 | + */ |
|---|
| 788 | + if (!(gpu->identity.features & chipFeatures_PIPE_3D) || |
|---|
| 789 | + (gpu->identity.minor_features0 & chipMinorFeatures0_MC20)) { |
|---|
| 790 | + u32 dma_mask = (u32)dma_get_required_mask(gpu->dev); |
|---|
| 791 | + if (dma_mask < PHYS_OFFSET + SZ_2G) |
|---|
| 792 | + priv->mmu_global->memory_base = PHYS_OFFSET; |
|---|
| 793 | + else |
|---|
| 794 | + priv->mmu_global->memory_base = dma_mask - SZ_2G + 1; |
|---|
| 795 | + } else if (PHYS_OFFSET >= SZ_2G) { |
|---|
| 796 | + dev_info(gpu->dev, "Need to move linear window on MC1.0, disabling TS\n"); |
|---|
| 797 | + priv->mmu_global->memory_base = PHYS_OFFSET; |
|---|
| 798 | + gpu->identity.features &= ~chipFeatures_FAST_CLEAR; |
|---|
| 757 | 799 | } |
|---|
| 758 | 800 | |
|---|
| 759 | | - gpu->cmdbuf_suballoc = etnaviv_cmdbuf_suballoc_new(gpu); |
|---|
| 760 | | - if (IS_ERR(gpu->cmdbuf_suballoc)) { |
|---|
| 761 | | - dev_err(gpu->dev, "Failed to create cmdbuf suballocator\n"); |
|---|
| 762 | | - ret = PTR_ERR(gpu->cmdbuf_suballoc); |
|---|
| 763 | | - goto destroy_iommu; |
|---|
| 764 | | - } |
|---|
| 801 | + /* |
|---|
| 802 | + * If the GPU is part of a system with DMA addressing limitations, |
|---|
| 803 | + * request pages for our SHM backend buffers from the DMA32 zone to |
|---|
| 804 | + * hopefully avoid performance killing SWIOTLB bounce buffering. |
|---|
| 805 | + */ |
|---|
| 806 | + if (dma_addressing_limited(gpu->dev)) |
|---|
| 807 | + priv->shm_gfp_mask |= GFP_DMA32; |
|---|
| 765 | 808 | |
|---|
| 766 | 809 | /* Create buffer: */ |
|---|
| 767 | | - ret = etnaviv_cmdbuf_init(gpu->cmdbuf_suballoc, &gpu->buffer, |
|---|
| 810 | + ret = etnaviv_cmdbuf_init(priv->cmdbuf_suballoc, &gpu->buffer, |
|---|
| 768 | 811 | PAGE_SIZE); |
|---|
| 769 | 812 | if (ret) { |
|---|
| 770 | 813 | dev_err(gpu->dev, "could not create command buffer\n"); |
|---|
| 771 | | - goto destroy_suballoc; |
|---|
| 772 | | - } |
|---|
| 773 | | - |
|---|
| 774 | | - if (gpu->mmu->version == ETNAVIV_IOMMU_V1 && |
|---|
| 775 | | - etnaviv_cmdbuf_get_va(&gpu->buffer) > 0x80000000) { |
|---|
| 776 | | - ret = -EINVAL; |
|---|
| 777 | | - dev_err(gpu->dev, |
|---|
| 778 | | - "command buffer outside valid memory window\n"); |
|---|
| 779 | | - goto free_buffer; |
|---|
| 814 | + goto fail; |
|---|
| 780 | 815 | } |
|---|
| 781 | 816 | |
|---|
| 782 | 817 | /* Setup event management */ |
|---|
| .. | .. |
|---|
| 789 | 824 | /* Now program the hardware */ |
|---|
| 790 | 825 | mutex_lock(&gpu->lock); |
|---|
| 791 | 826 | etnaviv_gpu_hw_init(gpu); |
|---|
| 792 | | - gpu->exec_state = -1; |
|---|
| 793 | 827 | mutex_unlock(&gpu->lock); |
|---|
| 794 | 828 | |
|---|
| 795 | 829 | pm_runtime_mark_last_busy(gpu->dev); |
|---|
| 796 | 830 | pm_runtime_put_autosuspend(gpu->dev); |
|---|
| 797 | 831 | |
|---|
| 832 | + gpu->initialized = true; |
|---|
| 833 | + |
|---|
| 798 | 834 | return 0; |
|---|
| 799 | 835 | |
|---|
| 800 | | -free_buffer: |
|---|
| 801 | | - etnaviv_cmdbuf_free(&gpu->buffer); |
|---|
| 802 | | - gpu->buffer.suballoc = NULL; |
|---|
| 803 | | -destroy_suballoc: |
|---|
| 804 | | - etnaviv_cmdbuf_suballoc_destroy(gpu->cmdbuf_suballoc); |
|---|
| 805 | | - gpu->cmdbuf_suballoc = NULL; |
|---|
| 806 | | -destroy_iommu: |
|---|
| 807 | | - etnaviv_iommu_destroy(gpu->mmu); |
|---|
| 808 | | - gpu->mmu = NULL; |
|---|
| 809 | 836 | fail: |
|---|
| 810 | 837 | pm_runtime_mark_last_busy(gpu->dev); |
|---|
| 811 | 838 | pm_put: |
|---|
| .. | .. |
|---|
| 857 | 884 | idle = gpu_read(gpu, VIVS_HI_IDLE_STATE); |
|---|
| 858 | 885 | |
|---|
| 859 | 886 | verify_dma(gpu, &debug); |
|---|
| 887 | + |
|---|
| 888 | + seq_puts(m, "\tidentity\n"); |
|---|
| 889 | + seq_printf(m, "\t model: 0x%x\n", gpu->identity.model); |
|---|
| 890 | + seq_printf(m, "\t revision: 0x%x\n", gpu->identity.revision); |
|---|
| 891 | + seq_printf(m, "\t product_id: 0x%x\n", gpu->identity.product_id); |
|---|
| 892 | + seq_printf(m, "\t customer_id: 0x%x\n", gpu->identity.customer_id); |
|---|
| 893 | + seq_printf(m, "\t eco_id: 0x%x\n", gpu->identity.eco_id); |
|---|
| 860 | 894 | |
|---|
| 861 | 895 | seq_puts(m, "\tfeatures\n"); |
|---|
| 862 | 896 | seq_printf(m, "\t major_features: 0x%08x\n", |
|---|
| .. | .. |
|---|
| 937 | 971 | seq_puts(m, "\t FP is not idle\n"); |
|---|
| 938 | 972 | if ((idle & VIVS_HI_IDLE_STATE_TS) == 0) |
|---|
| 939 | 973 | seq_puts(m, "\t TS is not idle\n"); |
|---|
| 974 | + if ((idle & VIVS_HI_IDLE_STATE_BL) == 0) |
|---|
| 975 | + seq_puts(m, "\t BL is not idle\n"); |
|---|
| 976 | + if ((idle & VIVS_HI_IDLE_STATE_ASYNCFE) == 0) |
|---|
| 977 | + seq_puts(m, "\t ASYNCFE is not idle\n"); |
|---|
| 978 | + if ((idle & VIVS_HI_IDLE_STATE_MC) == 0) |
|---|
| 979 | + seq_puts(m, "\t MC is not idle\n"); |
|---|
| 980 | + if ((idle & VIVS_HI_IDLE_STATE_PPA) == 0) |
|---|
| 981 | + seq_puts(m, "\t PPA is not idle\n"); |
|---|
| 982 | + if ((idle & VIVS_HI_IDLE_STATE_WD) == 0) |
|---|
| 983 | + seq_puts(m, "\t WD is not idle\n"); |
|---|
| 984 | + if ((idle & VIVS_HI_IDLE_STATE_NN) == 0) |
|---|
| 985 | + seq_puts(m, "\t NN is not idle\n"); |
|---|
| 986 | + if ((idle & VIVS_HI_IDLE_STATE_TP) == 0) |
|---|
| 987 | + seq_puts(m, "\t TP is not idle\n"); |
|---|
| 940 | 988 | if (idle & VIVS_HI_IDLE_STATE_AXI_LP) |
|---|
| 941 | 989 | seq_puts(m, "\t AXI low power mode\n"); |
|---|
| 942 | 990 | |
|---|
| .. | .. |
|---|
| 981 | 1029 | |
|---|
| 982 | 1030 | void etnaviv_gpu_recover_hang(struct etnaviv_gpu *gpu) |
|---|
| 983 | 1031 | { |
|---|
| 984 | | - unsigned long flags; |
|---|
| 985 | 1032 | unsigned int i = 0; |
|---|
| 986 | 1033 | |
|---|
| 987 | 1034 | dev_err(gpu->dev, "recover hung GPU!\n"); |
|---|
| .. | .. |
|---|
| 994 | 1041 | etnaviv_hw_reset(gpu); |
|---|
| 995 | 1042 | |
|---|
| 996 | 1043 | /* complete all events, the GPU won't do it after the reset */ |
|---|
| 997 | | - spin_lock_irqsave(&gpu->event_spinlock, flags); |
|---|
| 1044 | + spin_lock(&gpu->event_spinlock); |
|---|
| 998 | 1045 | for_each_set_bit_from(i, gpu->event_bitmap, ETNA_NR_EVENTS) |
|---|
| 999 | 1046 | complete(&gpu->event_free); |
|---|
| 1000 | 1047 | bitmap_zero(gpu->event_bitmap, ETNA_NR_EVENTS); |
|---|
| 1001 | | - spin_unlock_irqrestore(&gpu->event_spinlock, flags); |
|---|
| 1002 | | - gpu->completed_fence = gpu->active_fence; |
|---|
| 1048 | + spin_unlock(&gpu->event_spinlock); |
|---|
| 1003 | 1049 | |
|---|
| 1004 | 1050 | etnaviv_gpu_hw_init(gpu); |
|---|
| 1005 | | - gpu->lastctx = NULL; |
|---|
| 1006 | | - gpu->exec_state = -1; |
|---|
| 1007 | 1051 | |
|---|
| 1008 | 1052 | mutex_unlock(&gpu->lock); |
|---|
| 1009 | 1053 | pm_runtime_mark_last_busy(gpu->dev); |
|---|
| .. | .. |
|---|
| 1038 | 1082 | { |
|---|
| 1039 | 1083 | struct etnaviv_fence *f = to_etnaviv_fence(fence); |
|---|
| 1040 | 1084 | |
|---|
| 1041 | | - return fence_completed(f->gpu, f->base.seqno); |
|---|
| 1085 | + return (s32)(f->gpu->completed_fence - f->base.seqno) >= 0; |
|---|
| 1042 | 1086 | } |
|---|
| 1043 | 1087 | |
|---|
| 1044 | 1088 | static void etnaviv_fence_release(struct dma_fence *fence) |
|---|
| .. | .. |
|---|
| 1077 | 1121 | return &f->base; |
|---|
| 1078 | 1122 | } |
|---|
| 1079 | 1123 | |
|---|
| 1124 | +/* returns true if fence a comes after fence b */ |
|---|
| 1125 | +static inline bool fence_after(u32 a, u32 b) |
|---|
| 1126 | +{ |
|---|
| 1127 | + return (s32)(a - b) > 0; |
|---|
| 1128 | +} |
|---|
| 1129 | + |
|---|
| 1080 | 1130 | /* |
|---|
| 1081 | 1131 | * event management: |
|---|
| 1082 | 1132 | */ |
|---|
| .. | .. |
|---|
| 1084 | 1134 | static int event_alloc(struct etnaviv_gpu *gpu, unsigned nr_events, |
|---|
| 1085 | 1135 | unsigned int *events) |
|---|
| 1086 | 1136 | { |
|---|
| 1087 | | - unsigned long flags, timeout = msecs_to_jiffies(10 * 10000); |
|---|
| 1137 | + unsigned long timeout = msecs_to_jiffies(10 * 10000); |
|---|
| 1088 | 1138 | unsigned i, acquired = 0; |
|---|
| 1089 | 1139 | |
|---|
| 1090 | 1140 | for (i = 0; i < nr_events; i++) { |
|---|
| .. | .. |
|---|
| 1101 | 1151 | timeout = ret; |
|---|
| 1102 | 1152 | } |
|---|
| 1103 | 1153 | |
|---|
| 1104 | | - spin_lock_irqsave(&gpu->event_spinlock, flags); |
|---|
| 1154 | + spin_lock(&gpu->event_spinlock); |
|---|
| 1105 | 1155 | |
|---|
| 1106 | 1156 | for (i = 0; i < nr_events; i++) { |
|---|
| 1107 | 1157 | int event = find_first_zero_bit(gpu->event_bitmap, ETNA_NR_EVENTS); |
|---|
| .. | .. |
|---|
| 1111 | 1161 | set_bit(event, gpu->event_bitmap); |
|---|
| 1112 | 1162 | } |
|---|
| 1113 | 1163 | |
|---|
| 1114 | | - spin_unlock_irqrestore(&gpu->event_spinlock, flags); |
|---|
| 1164 | + spin_unlock(&gpu->event_spinlock); |
|---|
| 1115 | 1165 | |
|---|
| 1116 | 1166 | return 0; |
|---|
| 1117 | 1167 | |
|---|
| .. | .. |
|---|
| 1124 | 1174 | |
|---|
| 1125 | 1175 | static void event_free(struct etnaviv_gpu *gpu, unsigned int event) |
|---|
| 1126 | 1176 | { |
|---|
| 1127 | | - unsigned long flags; |
|---|
| 1128 | | - |
|---|
| 1129 | | - spin_lock_irqsave(&gpu->event_spinlock, flags); |
|---|
| 1130 | | - |
|---|
| 1131 | 1177 | if (!test_bit(event, gpu->event_bitmap)) { |
|---|
| 1132 | 1178 | dev_warn(gpu->dev, "event %u is already marked as free", |
|---|
| 1133 | 1179 | event); |
|---|
| 1134 | | - spin_unlock_irqrestore(&gpu->event_spinlock, flags); |
|---|
| 1135 | 1180 | } else { |
|---|
| 1136 | 1181 | clear_bit(event, gpu->event_bitmap); |
|---|
| 1137 | | - spin_unlock_irqrestore(&gpu->event_spinlock, flags); |
|---|
| 1138 | | - |
|---|
| 1139 | 1182 | complete(&gpu->event_free); |
|---|
| 1140 | 1183 | } |
|---|
| 1141 | 1184 | } |
|---|
| .. | .. |
|---|
| 1144 | 1187 | * Cmdstream submission/retirement: |
|---|
| 1145 | 1188 | */ |
|---|
| 1146 | 1189 | int etnaviv_gpu_wait_fence_interruptible(struct etnaviv_gpu *gpu, |
|---|
| 1147 | | - u32 id, struct timespec *timeout) |
|---|
| 1190 | + u32 id, struct drm_etnaviv_timespec *timeout) |
|---|
| 1148 | 1191 | { |
|---|
| 1149 | 1192 | struct dma_fence *fence; |
|---|
| 1150 | 1193 | int ret; |
|---|
| .. | .. |
|---|
| 1191 | 1234 | * that lock in this function while waiting. |
|---|
| 1192 | 1235 | */ |
|---|
| 1193 | 1236 | int etnaviv_gpu_wait_obj_inactive(struct etnaviv_gpu *gpu, |
|---|
| 1194 | | - struct etnaviv_gem_object *etnaviv_obj, struct timespec *timeout) |
|---|
| 1237 | + struct etnaviv_gem_object *etnaviv_obj, |
|---|
| 1238 | + struct drm_etnaviv_timespec *timeout) |
|---|
| 1195 | 1239 | { |
|---|
| 1196 | 1240 | unsigned long remaining; |
|---|
| 1197 | 1241 | long ret; |
|---|
| .. | .. |
|---|
| 1315 | 1359 | goto out_unlock; |
|---|
| 1316 | 1360 | } |
|---|
| 1317 | 1361 | |
|---|
| 1318 | | - gpu->active_fence = gpu_fence->seqno; |
|---|
| 1362 | + if (!gpu->fe_running) |
|---|
| 1363 | + etnaviv_gpu_start_fe_idleloop(gpu, submit->mmu_context); |
|---|
| 1364 | + |
|---|
| 1365 | + if (submit->prev_mmu_context) |
|---|
| 1366 | + etnaviv_iommu_context_put(submit->prev_mmu_context); |
|---|
| 1367 | + submit->prev_mmu_context = etnaviv_iommu_context_get(gpu->mmu_context); |
|---|
| 1319 | 1368 | |
|---|
| 1320 | 1369 | if (submit->nr_pmrs) { |
|---|
| 1321 | 1370 | gpu->event[event[1]].sync_point = &sync_point_perfmon_sample_pre; |
|---|
| .. | .. |
|---|
| 1326 | 1375 | |
|---|
| 1327 | 1376 | gpu->event[event[0]].fence = gpu_fence; |
|---|
| 1328 | 1377 | submit->cmdbuf.user_size = submit->cmdbuf.size - 8; |
|---|
| 1329 | | - etnaviv_buffer_queue(gpu, submit->exec_state, event[0], |
|---|
| 1330 | | - &submit->cmdbuf); |
|---|
| 1378 | + etnaviv_buffer_queue(gpu, submit->exec_state, submit->mmu_context, |
|---|
| 1379 | + event[0], &submit->cmdbuf); |
|---|
| 1331 | 1380 | |
|---|
| 1332 | 1381 | if (submit->nr_pmrs) { |
|---|
| 1333 | 1382 | gpu->event[event[2]].sync_point = &sync_point_perfmon_sample_post; |
|---|
| .. | .. |
|---|
| 1456 | 1505 | { |
|---|
| 1457 | 1506 | int ret; |
|---|
| 1458 | 1507 | |
|---|
| 1459 | | - if (gpu->clk_reg) { |
|---|
| 1460 | | - ret = clk_prepare_enable(gpu->clk_reg); |
|---|
| 1461 | | - if (ret) |
|---|
| 1462 | | - return ret; |
|---|
| 1463 | | - } |
|---|
| 1508 | + ret = clk_prepare_enable(gpu->clk_reg); |
|---|
| 1509 | + if (ret) |
|---|
| 1510 | + return ret; |
|---|
| 1464 | 1511 | |
|---|
| 1465 | | - if (gpu->clk_bus) { |
|---|
| 1466 | | - ret = clk_prepare_enable(gpu->clk_bus); |
|---|
| 1467 | | - if (ret) |
|---|
| 1468 | | - goto disable_clk_reg; |
|---|
| 1469 | | - } |
|---|
| 1512 | + ret = clk_prepare_enable(gpu->clk_bus); |
|---|
| 1513 | + if (ret) |
|---|
| 1514 | + goto disable_clk_reg; |
|---|
| 1470 | 1515 | |
|---|
| 1471 | | - if (gpu->clk_core) { |
|---|
| 1472 | | - ret = clk_prepare_enable(gpu->clk_core); |
|---|
| 1473 | | - if (ret) |
|---|
| 1474 | | - goto disable_clk_bus; |
|---|
| 1475 | | - } |
|---|
| 1516 | + ret = clk_prepare_enable(gpu->clk_core); |
|---|
| 1517 | + if (ret) |
|---|
| 1518 | + goto disable_clk_bus; |
|---|
| 1476 | 1519 | |
|---|
| 1477 | | - if (gpu->clk_shader) { |
|---|
| 1478 | | - ret = clk_prepare_enable(gpu->clk_shader); |
|---|
| 1479 | | - if (ret) |
|---|
| 1480 | | - goto disable_clk_core; |
|---|
| 1481 | | - } |
|---|
| 1520 | + ret = clk_prepare_enable(gpu->clk_shader); |
|---|
| 1521 | + if (ret) |
|---|
| 1522 | + goto disable_clk_core; |
|---|
| 1482 | 1523 | |
|---|
| 1483 | 1524 | return 0; |
|---|
| 1484 | 1525 | |
|---|
| 1485 | 1526 | disable_clk_core: |
|---|
| 1486 | | - if (gpu->clk_core) |
|---|
| 1487 | | - clk_disable_unprepare(gpu->clk_core); |
|---|
| 1527 | + clk_disable_unprepare(gpu->clk_core); |
|---|
| 1488 | 1528 | disable_clk_bus: |
|---|
| 1489 | | - if (gpu->clk_bus) |
|---|
| 1490 | | - clk_disable_unprepare(gpu->clk_bus); |
|---|
| 1529 | + clk_disable_unprepare(gpu->clk_bus); |
|---|
| 1491 | 1530 | disable_clk_reg: |
|---|
| 1492 | | - if (gpu->clk_reg) |
|---|
| 1493 | | - clk_disable_unprepare(gpu->clk_reg); |
|---|
| 1531 | + clk_disable_unprepare(gpu->clk_reg); |
|---|
| 1494 | 1532 | |
|---|
| 1495 | 1533 | return ret; |
|---|
| 1496 | 1534 | } |
|---|
| 1497 | 1535 | |
|---|
| 1498 | 1536 | static int etnaviv_gpu_clk_disable(struct etnaviv_gpu *gpu) |
|---|
| 1499 | 1537 | { |
|---|
| 1500 | | - if (gpu->clk_shader) |
|---|
| 1501 | | - clk_disable_unprepare(gpu->clk_shader); |
|---|
| 1502 | | - if (gpu->clk_core) |
|---|
| 1503 | | - clk_disable_unprepare(gpu->clk_core); |
|---|
| 1504 | | - if (gpu->clk_bus) |
|---|
| 1505 | | - clk_disable_unprepare(gpu->clk_bus); |
|---|
| 1506 | | - if (gpu->clk_reg) |
|---|
| 1507 | | - clk_disable_unprepare(gpu->clk_reg); |
|---|
| 1538 | + clk_disable_unprepare(gpu->clk_shader); |
|---|
| 1539 | + clk_disable_unprepare(gpu->clk_core); |
|---|
| 1540 | + clk_disable_unprepare(gpu->clk_bus); |
|---|
| 1541 | + clk_disable_unprepare(gpu->clk_reg); |
|---|
| 1508 | 1542 | |
|---|
| 1509 | 1543 | return 0; |
|---|
| 1510 | 1544 | } |
|---|
| .. | .. |
|---|
| 1532 | 1566 | |
|---|
| 1533 | 1567 | static int etnaviv_gpu_hw_suspend(struct etnaviv_gpu *gpu) |
|---|
| 1534 | 1568 | { |
|---|
| 1535 | | - if (gpu->buffer.suballoc) { |
|---|
| 1569 | + if (gpu->initialized && gpu->fe_running) { |
|---|
| 1536 | 1570 | /* Replace the last WAIT with END */ |
|---|
| 1537 | 1571 | mutex_lock(&gpu->lock); |
|---|
| 1538 | 1572 | etnaviv_buffer_end(gpu); |
|---|
| .. | .. |
|---|
| 1544 | 1578 | * we fail, just warn and continue. |
|---|
| 1545 | 1579 | */ |
|---|
| 1546 | 1580 | etnaviv_gpu_wait_idle(gpu, 100); |
|---|
| 1581 | + |
|---|
| 1582 | + gpu->fe_running = false; |
|---|
| 1547 | 1583 | } |
|---|
| 1584 | + |
|---|
| 1585 | + gpu->exec_state = -1; |
|---|
| 1548 | 1586 | |
|---|
| 1549 | 1587 | return etnaviv_gpu_clk_disable(gpu); |
|---|
| 1550 | 1588 | } |
|---|
| .. | .. |
|---|
| 1560 | 1598 | |
|---|
| 1561 | 1599 | etnaviv_gpu_update_clock(gpu); |
|---|
| 1562 | 1600 | etnaviv_gpu_hw_init(gpu); |
|---|
| 1563 | | - |
|---|
| 1564 | | - gpu->lastctx = NULL; |
|---|
| 1565 | | - gpu->exec_state = -1; |
|---|
| 1566 | 1601 | |
|---|
| 1567 | 1602 | mutex_unlock(&gpu->lock); |
|---|
| 1568 | 1603 | |
|---|
| .. | .. |
|---|
| 1692 | 1727 | etnaviv_gpu_hw_suspend(gpu); |
|---|
| 1693 | 1728 | #endif |
|---|
| 1694 | 1729 | |
|---|
| 1695 | | - if (gpu->buffer.suballoc) |
|---|
| 1730 | + if (gpu->mmu_context) |
|---|
| 1731 | + etnaviv_iommu_context_put(gpu->mmu_context); |
|---|
| 1732 | + |
|---|
| 1733 | + if (gpu->initialized) { |
|---|
| 1696 | 1734 | etnaviv_cmdbuf_free(&gpu->buffer); |
|---|
| 1697 | | - |
|---|
| 1698 | | - if (gpu->cmdbuf_suballoc) { |
|---|
| 1699 | | - etnaviv_cmdbuf_suballoc_destroy(gpu->cmdbuf_suballoc); |
|---|
| 1700 | | - gpu->cmdbuf_suballoc = NULL; |
|---|
| 1701 | | - } |
|---|
| 1702 | | - |
|---|
| 1703 | | - if (gpu->mmu) { |
|---|
| 1704 | | - etnaviv_iommu_destroy(gpu->mmu); |
|---|
| 1705 | | - gpu->mmu = NULL; |
|---|
| 1735 | + etnaviv_iommu_global_fini(gpu); |
|---|
| 1736 | + gpu->initialized = false; |
|---|
| 1706 | 1737 | } |
|---|
| 1707 | 1738 | |
|---|
| 1708 | 1739 | gpu->drm = NULL; |
|---|
| .. | .. |
|---|
| 1730 | 1761 | { |
|---|
| 1731 | 1762 | struct device *dev = &pdev->dev; |
|---|
| 1732 | 1763 | struct etnaviv_gpu *gpu; |
|---|
| 1733 | | - struct resource *res; |
|---|
| 1734 | 1764 | int err; |
|---|
| 1735 | 1765 | |
|---|
| 1736 | 1766 | gpu = devm_kzalloc(dev, sizeof(*gpu), GFP_KERNEL); |
|---|
| .. | .. |
|---|
| 1742 | 1772 | mutex_init(&gpu->fence_lock); |
|---|
| 1743 | 1773 | |
|---|
| 1744 | 1774 | /* Map registers: */ |
|---|
| 1745 | | - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
|---|
| 1746 | | - gpu->mmio = devm_ioremap_resource(&pdev->dev, res); |
|---|
| 1775 | + gpu->mmio = devm_platform_ioremap_resource(pdev, 0); |
|---|
| 1747 | 1776 | if (IS_ERR(gpu->mmio)) |
|---|
| 1748 | 1777 | return PTR_ERR(gpu->mmio); |
|---|
| 1749 | 1778 | |
|---|
| .. | .. |
|---|
| 1762 | 1791 | } |
|---|
| 1763 | 1792 | |
|---|
| 1764 | 1793 | /* Get Clocks: */ |
|---|
| 1765 | | - gpu->clk_reg = devm_clk_get(&pdev->dev, "reg"); |
|---|
| 1794 | + gpu->clk_reg = devm_clk_get_optional(&pdev->dev, "reg"); |
|---|
| 1766 | 1795 | DBG("clk_reg: %p", gpu->clk_reg); |
|---|
| 1767 | 1796 | if (IS_ERR(gpu->clk_reg)) |
|---|
| 1768 | | - gpu->clk_reg = NULL; |
|---|
| 1797 | + return PTR_ERR(gpu->clk_reg); |
|---|
| 1769 | 1798 | |
|---|
| 1770 | | - gpu->clk_bus = devm_clk_get(&pdev->dev, "bus"); |
|---|
| 1799 | + gpu->clk_bus = devm_clk_get_optional(&pdev->dev, "bus"); |
|---|
| 1771 | 1800 | DBG("clk_bus: %p", gpu->clk_bus); |
|---|
| 1772 | 1801 | if (IS_ERR(gpu->clk_bus)) |
|---|
| 1773 | | - gpu->clk_bus = NULL; |
|---|
| 1802 | + return PTR_ERR(gpu->clk_bus); |
|---|
| 1774 | 1803 | |
|---|
| 1775 | 1804 | gpu->clk_core = devm_clk_get(&pdev->dev, "core"); |
|---|
| 1776 | 1805 | DBG("clk_core: %p", gpu->clk_core); |
|---|
| 1777 | 1806 | if (IS_ERR(gpu->clk_core)) |
|---|
| 1778 | | - gpu->clk_core = NULL; |
|---|
| 1807 | + return PTR_ERR(gpu->clk_core); |
|---|
| 1779 | 1808 | gpu->base_rate_core = clk_get_rate(gpu->clk_core); |
|---|
| 1780 | 1809 | |
|---|
| 1781 | | - gpu->clk_shader = devm_clk_get(&pdev->dev, "shader"); |
|---|
| 1810 | + gpu->clk_shader = devm_clk_get_optional(&pdev->dev, "shader"); |
|---|
| 1782 | 1811 | DBG("clk_shader: %p", gpu->clk_shader); |
|---|
| 1783 | 1812 | if (IS_ERR(gpu->clk_shader)) |
|---|
| 1784 | | - gpu->clk_shader = NULL; |
|---|
| 1813 | + return PTR_ERR(gpu->clk_shader); |
|---|
| 1785 | 1814 | gpu->base_rate_shader = clk_get_rate(gpu->clk_shader); |
|---|
| 1786 | 1815 | |
|---|
| 1787 | 1816 | /* TODO: figure out max mapped size */ |
|---|
| .. | .. |
|---|
| 1818 | 1847 | struct etnaviv_gpu *gpu = dev_get_drvdata(dev); |
|---|
| 1819 | 1848 | u32 idle, mask; |
|---|
| 1820 | 1849 | |
|---|
| 1821 | | - /* If we have outstanding fences, we're not idle */ |
|---|
| 1822 | | - if (gpu->completed_fence != gpu->active_fence) |
|---|
| 1850 | + /* If there are any jobs in the HW queue, we're not idle */ |
|---|
| 1851 | + if (atomic_read(&gpu->sched.hw_rq_count)) |
|---|
| 1823 | 1852 | return -EBUSY; |
|---|
| 1824 | 1853 | |
|---|
| 1825 | | - /* Check whether the hardware (except FE) is idle */ |
|---|
| 1826 | | - mask = gpu->idle_mask & ~VIVS_HI_IDLE_STATE_FE; |
|---|
| 1854 | + /* Check whether the hardware (except FE and MC) is idle */ |
|---|
| 1855 | + mask = gpu->idle_mask & ~(VIVS_HI_IDLE_STATE_FE | |
|---|
| 1856 | + VIVS_HI_IDLE_STATE_MC); |
|---|
| 1827 | 1857 | idle = gpu_read(gpu, VIVS_HI_IDLE_STATE) & mask; |
|---|
| 1828 | | - if (idle != mask) |
|---|
| 1858 | + if (idle != mask) { |
|---|
| 1859 | + dev_warn_ratelimited(dev, "GPU not yet idle, mask: 0x%08x\n", |
|---|
| 1860 | + idle); |
|---|
| 1829 | 1861 | return -EBUSY; |
|---|
| 1862 | + } |
|---|
| 1830 | 1863 | |
|---|
| 1831 | 1864 | return etnaviv_gpu_hw_suspend(gpu); |
|---|
| 1832 | 1865 | } |
|---|
| .. | .. |
|---|
| 1841 | 1874 | return ret; |
|---|
| 1842 | 1875 | |
|---|
| 1843 | 1876 | /* Re-initialise the basic hardware state */ |
|---|
| 1844 | | - if (gpu->drm && gpu->buffer.suballoc) { |
|---|
| 1877 | + if (gpu->drm && gpu->initialized) { |
|---|
| 1845 | 1878 | ret = etnaviv_gpu_hw_resume(gpu); |
|---|
| 1846 | 1879 | if (ret) { |
|---|
| 1847 | 1880 | etnaviv_gpu_clk_disable(gpu); |
|---|