| .. | .. |
|---|
| 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. |
|---|
| .. | .. |
|---|
| 375 | 407 | /* Disable fast clear on GC700. */ |
|---|
| 376 | 408 | if (gpu->identity.model == chipModel_GC700) |
|---|
| 377 | 409 | gpu->identity.features &= ~chipFeatures_FAST_CLEAR; |
|---|
| 410 | + |
|---|
| 411 | + /* These models/revisions don't have the 2D pipe bit */ |
|---|
| 412 | + if ((gpu->identity.model == chipModel_GC500 && |
|---|
| 413 | + gpu->identity.revision <= 2) || |
|---|
| 414 | + gpu->identity.model == chipModel_GC300) |
|---|
| 415 | + gpu->identity.features |= chipFeatures_PIPE_2D; |
|---|
| 378 | 416 | |
|---|
| 379 | 417 | if ((gpu->identity.model == chipModel_GC500 && |
|---|
| 380 | 418 | gpu->identity.revision < 2) || |
|---|
| .. | .. |
|---|
| 409 | 447 | gpu_read(gpu, VIVS_HI_CHIP_MINOR_FEATURE_5); |
|---|
| 410 | 448 | } |
|---|
| 411 | 449 | |
|---|
| 412 | | - /* GC600 idle register reports zero bits where modules aren't present */ |
|---|
| 413 | | - if (gpu->identity.model == chipModel_GC600) { |
|---|
| 450 | + /* GC600/300 idle register reports zero bits where modules aren't present */ |
|---|
| 451 | + if (gpu->identity.model == chipModel_GC600 || |
|---|
| 452 | + gpu->identity.model == chipModel_GC300) |
|---|
| 414 | 453 | gpu->idle_mask = VIVS_HI_IDLE_STATE_TX | |
|---|
| 415 | 454 | VIVS_HI_IDLE_STATE_RA | |
|---|
| 416 | 455 | VIVS_HI_IDLE_STATE_SE | |
|---|
| .. | .. |
|---|
| 419 | 458 | VIVS_HI_IDLE_STATE_PE | |
|---|
| 420 | 459 | VIVS_HI_IDLE_STATE_DE | |
|---|
| 421 | 460 | VIVS_HI_IDLE_STATE_FE; |
|---|
| 422 | | - } else { |
|---|
| 423 | | - gpu->idle_mask = ~VIVS_HI_IDLE_STATE_AXI_LP; |
|---|
| 424 | | - } |
|---|
| 425 | 461 | |
|---|
| 426 | 462 | etnaviv_hw_specs(gpu); |
|---|
| 427 | 463 | } |
|---|
| .. | .. |
|---|
| 493 | 529 | /* read idle register. */ |
|---|
| 494 | 530 | idle = gpu_read(gpu, VIVS_HI_IDLE_STATE); |
|---|
| 495 | 531 | |
|---|
| 496 | | - /* try reseting again if FE it not idle */ |
|---|
| 532 | + /* try resetting again if FE is not idle */ |
|---|
| 497 | 533 | if ((idle & VIVS_HI_IDLE_STATE_FE) == 0) { |
|---|
| 498 | 534 | dev_dbg(gpu->dev, "FE is not idle\n"); |
|---|
| 499 | 535 | continue; |
|---|
| .. | .. |
|---|
| 531 | 567 | |
|---|
| 532 | 568 | /* We rely on the GPU running, so program the clock */ |
|---|
| 533 | 569 | etnaviv_gpu_update_clock(gpu); |
|---|
| 570 | + |
|---|
| 571 | + gpu->fe_running = false; |
|---|
| 572 | + gpu->exec_state = -1; |
|---|
| 573 | + if (gpu->mmu_context) |
|---|
| 574 | + etnaviv_iommu_context_put(gpu->mmu_context); |
|---|
| 575 | + gpu->mmu_context = NULL; |
|---|
| 534 | 576 | |
|---|
| 535 | 577 | return 0; |
|---|
| 536 | 578 | } |
|---|
| .. | .. |
|---|
| 594 | 636 | VIVS_MMUv2_SEC_COMMAND_CONTROL_ENABLE | |
|---|
| 595 | 637 | VIVS_MMUv2_SEC_COMMAND_CONTROL_PREFETCH(prefetch)); |
|---|
| 596 | 638 | } |
|---|
| 639 | + |
|---|
| 640 | + gpu->fe_running = true; |
|---|
| 641 | +} |
|---|
| 642 | + |
|---|
| 643 | +static void etnaviv_gpu_start_fe_idleloop(struct etnaviv_gpu *gpu, |
|---|
| 644 | + struct etnaviv_iommu_context *context) |
|---|
| 645 | +{ |
|---|
| 646 | + u16 prefetch; |
|---|
| 647 | + u32 address; |
|---|
| 648 | + |
|---|
| 649 | + /* setup the MMU */ |
|---|
| 650 | + etnaviv_iommu_restore(gpu, context); |
|---|
| 651 | + |
|---|
| 652 | + /* Start command processor */ |
|---|
| 653 | + prefetch = etnaviv_buffer_init(gpu); |
|---|
| 654 | + address = etnaviv_cmdbuf_get_va(&gpu->buffer, |
|---|
| 655 | + &gpu->mmu_context->cmdbuf_mapping); |
|---|
| 656 | + |
|---|
| 657 | + etnaviv_gpu_start_fe(gpu, address, prefetch); |
|---|
| 597 | 658 | } |
|---|
| 598 | 659 | |
|---|
| 599 | 660 | static void etnaviv_gpu_setup_pulse_eater(struct etnaviv_gpu *gpu) |
|---|
| .. | .. |
|---|
| 629 | 690 | |
|---|
| 630 | 691 | static void etnaviv_gpu_hw_init(struct etnaviv_gpu *gpu) |
|---|
| 631 | 692 | { |
|---|
| 632 | | - u16 prefetch; |
|---|
| 633 | | - |
|---|
| 634 | 693 | if ((etnaviv_is_model_rev(gpu, GC320, 0x5007) || |
|---|
| 635 | 694 | etnaviv_is_model_rev(gpu, GC320, 0x5220)) && |
|---|
| 636 | 695 | gpu_read(gpu, VIVS_HI_CHIP_TIME) != 0x2062400) { |
|---|
| .. | .. |
|---|
| 676 | 735 | /* setup the pulse eater */ |
|---|
| 677 | 736 | etnaviv_gpu_setup_pulse_eater(gpu); |
|---|
| 678 | 737 | |
|---|
| 679 | | - /* setup the MMU */ |
|---|
| 680 | | - etnaviv_iommu_restore(gpu); |
|---|
| 681 | | - |
|---|
| 682 | | - /* Start command processor */ |
|---|
| 683 | | - prefetch = etnaviv_buffer_init(gpu); |
|---|
| 684 | | - |
|---|
| 685 | 738 | gpu_write(gpu, VIVS_HI_INTR_ENBL, ~0U); |
|---|
| 686 | | - etnaviv_gpu_start_fe(gpu, etnaviv_cmdbuf_get_va(&gpu->buffer), |
|---|
| 687 | | - prefetch); |
|---|
| 688 | 739 | } |
|---|
| 689 | 740 | |
|---|
| 690 | 741 | int etnaviv_gpu_init(struct etnaviv_gpu *gpu) |
|---|
| 691 | 742 | { |
|---|
| 743 | + struct etnaviv_drm_private *priv = gpu->drm->dev_private; |
|---|
| 692 | 744 | int ret, i; |
|---|
| 693 | 745 | |
|---|
| 694 | 746 | ret = pm_runtime_get_sync(gpu->dev); |
|---|
| .. | .. |
|---|
| 714 | 766 | } |
|---|
| 715 | 767 | |
|---|
| 716 | 768 | /* |
|---|
| 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 | 769 | * On cores with security features supported, we claim control over the |
|---|
| 740 | 770 | * security states. |
|---|
| 741 | 771 | */ |
|---|
| .. | .. |
|---|
| 749 | 779 | goto fail; |
|---|
| 750 | 780 | } |
|---|
| 751 | 781 | |
|---|
| 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); |
|---|
| 782 | + ret = etnaviv_iommu_global_init(gpu); |
|---|
| 783 | + if (ret) |
|---|
| 756 | 784 | goto fail; |
|---|
| 785 | + |
|---|
| 786 | + /* |
|---|
| 787 | + * Set the GPU linear window to be at the end of the DMA window, where |
|---|
| 788 | + * the CMA area is likely to reside. This ensures that we are able to |
|---|
| 789 | + * map the command buffers while having the linear window overlap as |
|---|
| 790 | + * much RAM as possible, so we can optimize mappings for other buffers. |
|---|
| 791 | + * |
|---|
| 792 | + * For 3D cores only do this if MC2.0 is present, as with MC1.0 it leads |
|---|
| 793 | + * to different views of the memory on the individual engines. |
|---|
| 794 | + */ |
|---|
| 795 | + if (!(gpu->identity.features & chipFeatures_PIPE_3D) || |
|---|
| 796 | + (gpu->identity.minor_features0 & chipMinorFeatures0_MC20)) { |
|---|
| 797 | + u32 dma_mask = (u32)dma_get_required_mask(gpu->dev); |
|---|
| 798 | + if (dma_mask < PHYS_OFFSET + SZ_2G) |
|---|
| 799 | + priv->mmu_global->memory_base = PHYS_OFFSET; |
|---|
| 800 | + else |
|---|
| 801 | + priv->mmu_global->memory_base = dma_mask - SZ_2G + 1; |
|---|
| 802 | + } else if (PHYS_OFFSET >= SZ_2G) { |
|---|
| 803 | + dev_info(gpu->dev, "Need to move linear window on MC1.0, disabling TS\n"); |
|---|
| 804 | + priv->mmu_global->memory_base = PHYS_OFFSET; |
|---|
| 805 | + gpu->identity.features &= ~chipFeatures_FAST_CLEAR; |
|---|
| 757 | 806 | } |
|---|
| 758 | 807 | |
|---|
| 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 | | - } |
|---|
| 808 | + /* |
|---|
| 809 | + * If the GPU is part of a system with DMA addressing limitations, |
|---|
| 810 | + * request pages for our SHM backend buffers from the DMA32 zone to |
|---|
| 811 | + * hopefully avoid performance killing SWIOTLB bounce buffering. |
|---|
| 812 | + */ |
|---|
| 813 | + if (dma_addressing_limited(gpu->dev)) |
|---|
| 814 | + priv->shm_gfp_mask |= GFP_DMA32; |
|---|
| 765 | 815 | |
|---|
| 766 | 816 | /* Create buffer: */ |
|---|
| 767 | | - ret = etnaviv_cmdbuf_init(gpu->cmdbuf_suballoc, &gpu->buffer, |
|---|
| 817 | + ret = etnaviv_cmdbuf_init(priv->cmdbuf_suballoc, &gpu->buffer, |
|---|
| 768 | 818 | PAGE_SIZE); |
|---|
| 769 | 819 | if (ret) { |
|---|
| 770 | 820 | 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; |
|---|
| 821 | + goto fail; |
|---|
| 780 | 822 | } |
|---|
| 781 | 823 | |
|---|
| 782 | 824 | /* Setup event management */ |
|---|
| .. | .. |
|---|
| 789 | 831 | /* Now program the hardware */ |
|---|
| 790 | 832 | mutex_lock(&gpu->lock); |
|---|
| 791 | 833 | etnaviv_gpu_hw_init(gpu); |
|---|
| 792 | | - gpu->exec_state = -1; |
|---|
| 793 | 834 | mutex_unlock(&gpu->lock); |
|---|
| 794 | 835 | |
|---|
| 795 | 836 | pm_runtime_mark_last_busy(gpu->dev); |
|---|
| 796 | 837 | pm_runtime_put_autosuspend(gpu->dev); |
|---|
| 797 | 838 | |
|---|
| 839 | + gpu->initialized = true; |
|---|
| 840 | + |
|---|
| 798 | 841 | return 0; |
|---|
| 799 | 842 | |
|---|
| 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 | 843 | fail: |
|---|
| 810 | 844 | pm_runtime_mark_last_busy(gpu->dev); |
|---|
| 811 | 845 | pm_put: |
|---|
| .. | .. |
|---|
| 857 | 891 | idle = gpu_read(gpu, VIVS_HI_IDLE_STATE); |
|---|
| 858 | 892 | |
|---|
| 859 | 893 | verify_dma(gpu, &debug); |
|---|
| 894 | + |
|---|
| 895 | + seq_puts(m, "\tidentity\n"); |
|---|
| 896 | + seq_printf(m, "\t model: 0x%x\n", gpu->identity.model); |
|---|
| 897 | + seq_printf(m, "\t revision: 0x%x\n", gpu->identity.revision); |
|---|
| 898 | + seq_printf(m, "\t product_id: 0x%x\n", gpu->identity.product_id); |
|---|
| 899 | + seq_printf(m, "\t customer_id: 0x%x\n", gpu->identity.customer_id); |
|---|
| 900 | + seq_printf(m, "\t eco_id: 0x%x\n", gpu->identity.eco_id); |
|---|
| 860 | 901 | |
|---|
| 861 | 902 | seq_puts(m, "\tfeatures\n"); |
|---|
| 862 | 903 | seq_printf(m, "\t major_features: 0x%08x\n", |
|---|
| .. | .. |
|---|
| 937 | 978 | seq_puts(m, "\t FP is not idle\n"); |
|---|
| 938 | 979 | if ((idle & VIVS_HI_IDLE_STATE_TS) == 0) |
|---|
| 939 | 980 | seq_puts(m, "\t TS is not idle\n"); |
|---|
| 981 | + if ((idle & VIVS_HI_IDLE_STATE_BL) == 0) |
|---|
| 982 | + seq_puts(m, "\t BL is not idle\n"); |
|---|
| 983 | + if ((idle & VIVS_HI_IDLE_STATE_ASYNCFE) == 0) |
|---|
| 984 | + seq_puts(m, "\t ASYNCFE is not idle\n"); |
|---|
| 985 | + if ((idle & VIVS_HI_IDLE_STATE_MC) == 0) |
|---|
| 986 | + seq_puts(m, "\t MC is not idle\n"); |
|---|
| 987 | + if ((idle & VIVS_HI_IDLE_STATE_PPA) == 0) |
|---|
| 988 | + seq_puts(m, "\t PPA is not idle\n"); |
|---|
| 989 | + if ((idle & VIVS_HI_IDLE_STATE_WD) == 0) |
|---|
| 990 | + seq_puts(m, "\t WD is not idle\n"); |
|---|
| 991 | + if ((idle & VIVS_HI_IDLE_STATE_NN) == 0) |
|---|
| 992 | + seq_puts(m, "\t NN is not idle\n"); |
|---|
| 993 | + if ((idle & VIVS_HI_IDLE_STATE_TP) == 0) |
|---|
| 994 | + seq_puts(m, "\t TP is not idle\n"); |
|---|
| 940 | 995 | if (idle & VIVS_HI_IDLE_STATE_AXI_LP) |
|---|
| 941 | 996 | seq_puts(m, "\t AXI low power mode\n"); |
|---|
| 942 | 997 | |
|---|
| .. | .. |
|---|
| 981 | 1036 | |
|---|
| 982 | 1037 | void etnaviv_gpu_recover_hang(struct etnaviv_gpu *gpu) |
|---|
| 983 | 1038 | { |
|---|
| 984 | | - unsigned long flags; |
|---|
| 985 | 1039 | unsigned int i = 0; |
|---|
| 986 | 1040 | |
|---|
| 987 | 1041 | dev_err(gpu->dev, "recover hung GPU!\n"); |
|---|
| .. | .. |
|---|
| 994 | 1048 | etnaviv_hw_reset(gpu); |
|---|
| 995 | 1049 | |
|---|
| 996 | 1050 | /* complete all events, the GPU won't do it after the reset */ |
|---|
| 997 | | - spin_lock_irqsave(&gpu->event_spinlock, flags); |
|---|
| 1051 | + spin_lock(&gpu->event_spinlock); |
|---|
| 998 | 1052 | for_each_set_bit_from(i, gpu->event_bitmap, ETNA_NR_EVENTS) |
|---|
| 999 | 1053 | complete(&gpu->event_free); |
|---|
| 1000 | 1054 | bitmap_zero(gpu->event_bitmap, ETNA_NR_EVENTS); |
|---|
| 1001 | | - spin_unlock_irqrestore(&gpu->event_spinlock, flags); |
|---|
| 1002 | | - gpu->completed_fence = gpu->active_fence; |
|---|
| 1055 | + spin_unlock(&gpu->event_spinlock); |
|---|
| 1003 | 1056 | |
|---|
| 1004 | 1057 | etnaviv_gpu_hw_init(gpu); |
|---|
| 1005 | | - gpu->lastctx = NULL; |
|---|
| 1006 | | - gpu->exec_state = -1; |
|---|
| 1007 | 1058 | |
|---|
| 1008 | 1059 | mutex_unlock(&gpu->lock); |
|---|
| 1009 | 1060 | pm_runtime_mark_last_busy(gpu->dev); |
|---|
| .. | .. |
|---|
| 1038 | 1089 | { |
|---|
| 1039 | 1090 | struct etnaviv_fence *f = to_etnaviv_fence(fence); |
|---|
| 1040 | 1091 | |
|---|
| 1041 | | - return fence_completed(f->gpu, f->base.seqno); |
|---|
| 1092 | + return (s32)(f->gpu->completed_fence - f->base.seqno) >= 0; |
|---|
| 1042 | 1093 | } |
|---|
| 1043 | 1094 | |
|---|
| 1044 | 1095 | static void etnaviv_fence_release(struct dma_fence *fence) |
|---|
| .. | .. |
|---|
| 1077 | 1128 | return &f->base; |
|---|
| 1078 | 1129 | } |
|---|
| 1079 | 1130 | |
|---|
| 1131 | +/* returns true if fence a comes after fence b */ |
|---|
| 1132 | +static inline bool fence_after(u32 a, u32 b) |
|---|
| 1133 | +{ |
|---|
| 1134 | + return (s32)(a - b) > 0; |
|---|
| 1135 | +} |
|---|
| 1136 | + |
|---|
| 1080 | 1137 | /* |
|---|
| 1081 | 1138 | * event management: |
|---|
| 1082 | 1139 | */ |
|---|
| .. | .. |
|---|
| 1084 | 1141 | static int event_alloc(struct etnaviv_gpu *gpu, unsigned nr_events, |
|---|
| 1085 | 1142 | unsigned int *events) |
|---|
| 1086 | 1143 | { |
|---|
| 1087 | | - unsigned long flags, timeout = msecs_to_jiffies(10 * 10000); |
|---|
| 1144 | + unsigned long timeout = msecs_to_jiffies(10 * 10000); |
|---|
| 1088 | 1145 | unsigned i, acquired = 0; |
|---|
| 1089 | 1146 | |
|---|
| 1090 | 1147 | for (i = 0; i < nr_events; i++) { |
|---|
| .. | .. |
|---|
| 1101 | 1158 | timeout = ret; |
|---|
| 1102 | 1159 | } |
|---|
| 1103 | 1160 | |
|---|
| 1104 | | - spin_lock_irqsave(&gpu->event_spinlock, flags); |
|---|
| 1161 | + spin_lock(&gpu->event_spinlock); |
|---|
| 1105 | 1162 | |
|---|
| 1106 | 1163 | for (i = 0; i < nr_events; i++) { |
|---|
| 1107 | 1164 | int event = find_first_zero_bit(gpu->event_bitmap, ETNA_NR_EVENTS); |
|---|
| .. | .. |
|---|
| 1111 | 1168 | set_bit(event, gpu->event_bitmap); |
|---|
| 1112 | 1169 | } |
|---|
| 1113 | 1170 | |
|---|
| 1114 | | - spin_unlock_irqrestore(&gpu->event_spinlock, flags); |
|---|
| 1171 | + spin_unlock(&gpu->event_spinlock); |
|---|
| 1115 | 1172 | |
|---|
| 1116 | 1173 | return 0; |
|---|
| 1117 | 1174 | |
|---|
| .. | .. |
|---|
| 1124 | 1181 | |
|---|
| 1125 | 1182 | static void event_free(struct etnaviv_gpu *gpu, unsigned int event) |
|---|
| 1126 | 1183 | { |
|---|
| 1127 | | - unsigned long flags; |
|---|
| 1128 | | - |
|---|
| 1129 | | - spin_lock_irqsave(&gpu->event_spinlock, flags); |
|---|
| 1130 | | - |
|---|
| 1131 | 1184 | if (!test_bit(event, gpu->event_bitmap)) { |
|---|
| 1132 | 1185 | dev_warn(gpu->dev, "event %u is already marked as free", |
|---|
| 1133 | 1186 | event); |
|---|
| 1134 | | - spin_unlock_irqrestore(&gpu->event_spinlock, flags); |
|---|
| 1135 | 1187 | } else { |
|---|
| 1136 | 1188 | clear_bit(event, gpu->event_bitmap); |
|---|
| 1137 | | - spin_unlock_irqrestore(&gpu->event_spinlock, flags); |
|---|
| 1138 | | - |
|---|
| 1139 | 1189 | complete(&gpu->event_free); |
|---|
| 1140 | 1190 | } |
|---|
| 1141 | 1191 | } |
|---|
| .. | .. |
|---|
| 1144 | 1194 | * Cmdstream submission/retirement: |
|---|
| 1145 | 1195 | */ |
|---|
| 1146 | 1196 | int etnaviv_gpu_wait_fence_interruptible(struct etnaviv_gpu *gpu, |
|---|
| 1147 | | - u32 id, struct timespec *timeout) |
|---|
| 1197 | + u32 id, struct drm_etnaviv_timespec *timeout) |
|---|
| 1148 | 1198 | { |
|---|
| 1149 | 1199 | struct dma_fence *fence; |
|---|
| 1150 | 1200 | int ret; |
|---|
| .. | .. |
|---|
| 1191 | 1241 | * that lock in this function while waiting. |
|---|
| 1192 | 1242 | */ |
|---|
| 1193 | 1243 | int etnaviv_gpu_wait_obj_inactive(struct etnaviv_gpu *gpu, |
|---|
| 1194 | | - struct etnaviv_gem_object *etnaviv_obj, struct timespec *timeout) |
|---|
| 1244 | + struct etnaviv_gem_object *etnaviv_obj, |
|---|
| 1245 | + struct drm_etnaviv_timespec *timeout) |
|---|
| 1195 | 1246 | { |
|---|
| 1196 | 1247 | unsigned long remaining; |
|---|
| 1197 | 1248 | long ret; |
|---|
| .. | .. |
|---|
| 1315 | 1366 | goto out_unlock; |
|---|
| 1316 | 1367 | } |
|---|
| 1317 | 1368 | |
|---|
| 1318 | | - gpu->active_fence = gpu_fence->seqno; |
|---|
| 1369 | + if (!gpu->fe_running) |
|---|
| 1370 | + etnaviv_gpu_start_fe_idleloop(gpu, submit->mmu_context); |
|---|
| 1371 | + |
|---|
| 1372 | + if (submit->prev_mmu_context) |
|---|
| 1373 | + etnaviv_iommu_context_put(submit->prev_mmu_context); |
|---|
| 1374 | + submit->prev_mmu_context = etnaviv_iommu_context_get(gpu->mmu_context); |
|---|
| 1319 | 1375 | |
|---|
| 1320 | 1376 | if (submit->nr_pmrs) { |
|---|
| 1321 | 1377 | gpu->event[event[1]].sync_point = &sync_point_perfmon_sample_pre; |
|---|
| .. | .. |
|---|
| 1326 | 1382 | |
|---|
| 1327 | 1383 | gpu->event[event[0]].fence = gpu_fence; |
|---|
| 1328 | 1384 | submit->cmdbuf.user_size = submit->cmdbuf.size - 8; |
|---|
| 1329 | | - etnaviv_buffer_queue(gpu, submit->exec_state, event[0], |
|---|
| 1330 | | - &submit->cmdbuf); |
|---|
| 1385 | + etnaviv_buffer_queue(gpu, submit->exec_state, submit->mmu_context, |
|---|
| 1386 | + event[0], &submit->cmdbuf); |
|---|
| 1331 | 1387 | |
|---|
| 1332 | 1388 | if (submit->nr_pmrs) { |
|---|
| 1333 | 1389 | gpu->event[event[2]].sync_point = &sync_point_perfmon_sample_post; |
|---|
| .. | .. |
|---|
| 1456 | 1512 | { |
|---|
| 1457 | 1513 | int ret; |
|---|
| 1458 | 1514 | |
|---|
| 1459 | | - if (gpu->clk_reg) { |
|---|
| 1460 | | - ret = clk_prepare_enable(gpu->clk_reg); |
|---|
| 1461 | | - if (ret) |
|---|
| 1462 | | - return ret; |
|---|
| 1463 | | - } |
|---|
| 1515 | + ret = clk_prepare_enable(gpu->clk_reg); |
|---|
| 1516 | + if (ret) |
|---|
| 1517 | + return ret; |
|---|
| 1464 | 1518 | |
|---|
| 1465 | | - if (gpu->clk_bus) { |
|---|
| 1466 | | - ret = clk_prepare_enable(gpu->clk_bus); |
|---|
| 1467 | | - if (ret) |
|---|
| 1468 | | - goto disable_clk_reg; |
|---|
| 1469 | | - } |
|---|
| 1519 | + ret = clk_prepare_enable(gpu->clk_bus); |
|---|
| 1520 | + if (ret) |
|---|
| 1521 | + goto disable_clk_reg; |
|---|
| 1470 | 1522 | |
|---|
| 1471 | | - if (gpu->clk_core) { |
|---|
| 1472 | | - ret = clk_prepare_enable(gpu->clk_core); |
|---|
| 1473 | | - if (ret) |
|---|
| 1474 | | - goto disable_clk_bus; |
|---|
| 1475 | | - } |
|---|
| 1523 | + ret = clk_prepare_enable(gpu->clk_core); |
|---|
| 1524 | + if (ret) |
|---|
| 1525 | + goto disable_clk_bus; |
|---|
| 1476 | 1526 | |
|---|
| 1477 | | - if (gpu->clk_shader) { |
|---|
| 1478 | | - ret = clk_prepare_enable(gpu->clk_shader); |
|---|
| 1479 | | - if (ret) |
|---|
| 1480 | | - goto disable_clk_core; |
|---|
| 1481 | | - } |
|---|
| 1527 | + ret = clk_prepare_enable(gpu->clk_shader); |
|---|
| 1528 | + if (ret) |
|---|
| 1529 | + goto disable_clk_core; |
|---|
| 1482 | 1530 | |
|---|
| 1483 | 1531 | return 0; |
|---|
| 1484 | 1532 | |
|---|
| 1485 | 1533 | disable_clk_core: |
|---|
| 1486 | | - if (gpu->clk_core) |
|---|
| 1487 | | - clk_disable_unprepare(gpu->clk_core); |
|---|
| 1534 | + clk_disable_unprepare(gpu->clk_core); |
|---|
| 1488 | 1535 | disable_clk_bus: |
|---|
| 1489 | | - if (gpu->clk_bus) |
|---|
| 1490 | | - clk_disable_unprepare(gpu->clk_bus); |
|---|
| 1536 | + clk_disable_unprepare(gpu->clk_bus); |
|---|
| 1491 | 1537 | disable_clk_reg: |
|---|
| 1492 | | - if (gpu->clk_reg) |
|---|
| 1493 | | - clk_disable_unprepare(gpu->clk_reg); |
|---|
| 1538 | + clk_disable_unprepare(gpu->clk_reg); |
|---|
| 1494 | 1539 | |
|---|
| 1495 | 1540 | return ret; |
|---|
| 1496 | 1541 | } |
|---|
| 1497 | 1542 | |
|---|
| 1498 | 1543 | static int etnaviv_gpu_clk_disable(struct etnaviv_gpu *gpu) |
|---|
| 1499 | 1544 | { |
|---|
| 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); |
|---|
| 1545 | + clk_disable_unprepare(gpu->clk_shader); |
|---|
| 1546 | + clk_disable_unprepare(gpu->clk_core); |
|---|
| 1547 | + clk_disable_unprepare(gpu->clk_bus); |
|---|
| 1548 | + clk_disable_unprepare(gpu->clk_reg); |
|---|
| 1508 | 1549 | |
|---|
| 1509 | 1550 | return 0; |
|---|
| 1510 | 1551 | } |
|---|
| .. | .. |
|---|
| 1532 | 1573 | |
|---|
| 1533 | 1574 | static int etnaviv_gpu_hw_suspend(struct etnaviv_gpu *gpu) |
|---|
| 1534 | 1575 | { |
|---|
| 1535 | | - if (gpu->buffer.suballoc) { |
|---|
| 1576 | + if (gpu->initialized && gpu->fe_running) { |
|---|
| 1536 | 1577 | /* Replace the last WAIT with END */ |
|---|
| 1537 | 1578 | mutex_lock(&gpu->lock); |
|---|
| 1538 | 1579 | etnaviv_buffer_end(gpu); |
|---|
| .. | .. |
|---|
| 1544 | 1585 | * we fail, just warn and continue. |
|---|
| 1545 | 1586 | */ |
|---|
| 1546 | 1587 | etnaviv_gpu_wait_idle(gpu, 100); |
|---|
| 1588 | + |
|---|
| 1589 | + gpu->fe_running = false; |
|---|
| 1547 | 1590 | } |
|---|
| 1591 | + |
|---|
| 1592 | + gpu->exec_state = -1; |
|---|
| 1548 | 1593 | |
|---|
| 1549 | 1594 | return etnaviv_gpu_clk_disable(gpu); |
|---|
| 1550 | 1595 | } |
|---|
| .. | .. |
|---|
| 1560 | 1605 | |
|---|
| 1561 | 1606 | etnaviv_gpu_update_clock(gpu); |
|---|
| 1562 | 1607 | etnaviv_gpu_hw_init(gpu); |
|---|
| 1563 | | - |
|---|
| 1564 | | - gpu->lastctx = NULL; |
|---|
| 1565 | | - gpu->exec_state = -1; |
|---|
| 1566 | 1608 | |
|---|
| 1567 | 1609 | mutex_unlock(&gpu->lock); |
|---|
| 1568 | 1610 | |
|---|
| .. | .. |
|---|
| 1692 | 1734 | etnaviv_gpu_hw_suspend(gpu); |
|---|
| 1693 | 1735 | #endif |
|---|
| 1694 | 1736 | |
|---|
| 1695 | | - if (gpu->buffer.suballoc) |
|---|
| 1737 | + if (gpu->mmu_context) |
|---|
| 1738 | + etnaviv_iommu_context_put(gpu->mmu_context); |
|---|
| 1739 | + |
|---|
| 1740 | + if (gpu->initialized) { |
|---|
| 1696 | 1741 | 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; |
|---|
| 1742 | + etnaviv_iommu_global_fini(gpu); |
|---|
| 1743 | + gpu->initialized = false; |
|---|
| 1706 | 1744 | } |
|---|
| 1707 | 1745 | |
|---|
| 1708 | 1746 | gpu->drm = NULL; |
|---|
| .. | .. |
|---|
| 1730 | 1768 | { |
|---|
| 1731 | 1769 | struct device *dev = &pdev->dev; |
|---|
| 1732 | 1770 | struct etnaviv_gpu *gpu; |
|---|
| 1733 | | - struct resource *res; |
|---|
| 1734 | 1771 | int err; |
|---|
| 1735 | 1772 | |
|---|
| 1736 | 1773 | gpu = devm_kzalloc(dev, sizeof(*gpu), GFP_KERNEL); |
|---|
| .. | .. |
|---|
| 1742 | 1779 | mutex_init(&gpu->fence_lock); |
|---|
| 1743 | 1780 | |
|---|
| 1744 | 1781 | /* Map registers: */ |
|---|
| 1745 | | - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
|---|
| 1746 | | - gpu->mmio = devm_ioremap_resource(&pdev->dev, res); |
|---|
| 1782 | + gpu->mmio = devm_platform_ioremap_resource(pdev, 0); |
|---|
| 1747 | 1783 | if (IS_ERR(gpu->mmio)) |
|---|
| 1748 | 1784 | return PTR_ERR(gpu->mmio); |
|---|
| 1749 | 1785 | |
|---|
| .. | .. |
|---|
| 1762 | 1798 | } |
|---|
| 1763 | 1799 | |
|---|
| 1764 | 1800 | /* Get Clocks: */ |
|---|
| 1765 | | - gpu->clk_reg = devm_clk_get(&pdev->dev, "reg"); |
|---|
| 1801 | + gpu->clk_reg = devm_clk_get_optional(&pdev->dev, "reg"); |
|---|
| 1766 | 1802 | DBG("clk_reg: %p", gpu->clk_reg); |
|---|
| 1767 | 1803 | if (IS_ERR(gpu->clk_reg)) |
|---|
| 1768 | | - gpu->clk_reg = NULL; |
|---|
| 1804 | + return PTR_ERR(gpu->clk_reg); |
|---|
| 1769 | 1805 | |
|---|
| 1770 | | - gpu->clk_bus = devm_clk_get(&pdev->dev, "bus"); |
|---|
| 1806 | + gpu->clk_bus = devm_clk_get_optional(&pdev->dev, "bus"); |
|---|
| 1771 | 1807 | DBG("clk_bus: %p", gpu->clk_bus); |
|---|
| 1772 | 1808 | if (IS_ERR(gpu->clk_bus)) |
|---|
| 1773 | | - gpu->clk_bus = NULL; |
|---|
| 1809 | + return PTR_ERR(gpu->clk_bus); |
|---|
| 1774 | 1810 | |
|---|
| 1775 | 1811 | gpu->clk_core = devm_clk_get(&pdev->dev, "core"); |
|---|
| 1776 | 1812 | DBG("clk_core: %p", gpu->clk_core); |
|---|
| 1777 | 1813 | if (IS_ERR(gpu->clk_core)) |
|---|
| 1778 | | - gpu->clk_core = NULL; |
|---|
| 1814 | + return PTR_ERR(gpu->clk_core); |
|---|
| 1779 | 1815 | gpu->base_rate_core = clk_get_rate(gpu->clk_core); |
|---|
| 1780 | 1816 | |
|---|
| 1781 | | - gpu->clk_shader = devm_clk_get(&pdev->dev, "shader"); |
|---|
| 1817 | + gpu->clk_shader = devm_clk_get_optional(&pdev->dev, "shader"); |
|---|
| 1782 | 1818 | DBG("clk_shader: %p", gpu->clk_shader); |
|---|
| 1783 | 1819 | if (IS_ERR(gpu->clk_shader)) |
|---|
| 1784 | | - gpu->clk_shader = NULL; |
|---|
| 1820 | + return PTR_ERR(gpu->clk_shader); |
|---|
| 1785 | 1821 | gpu->base_rate_shader = clk_get_rate(gpu->clk_shader); |
|---|
| 1786 | 1822 | |
|---|
| 1787 | 1823 | /* TODO: figure out max mapped size */ |
|---|
| .. | .. |
|---|
| 1818 | 1854 | struct etnaviv_gpu *gpu = dev_get_drvdata(dev); |
|---|
| 1819 | 1855 | u32 idle, mask; |
|---|
| 1820 | 1856 | |
|---|
| 1821 | | - /* If we have outstanding fences, we're not idle */ |
|---|
| 1822 | | - if (gpu->completed_fence != gpu->active_fence) |
|---|
| 1857 | + /* If there are any jobs in the HW queue, we're not idle */ |
|---|
| 1858 | + if (atomic_read(&gpu->sched.hw_rq_count)) |
|---|
| 1823 | 1859 | return -EBUSY; |
|---|
| 1824 | 1860 | |
|---|
| 1825 | | - /* Check whether the hardware (except FE) is idle */ |
|---|
| 1826 | | - mask = gpu->idle_mask & ~VIVS_HI_IDLE_STATE_FE; |
|---|
| 1861 | + /* Check whether the hardware (except FE and MC) is idle */ |
|---|
| 1862 | + mask = gpu->idle_mask & ~(VIVS_HI_IDLE_STATE_FE | |
|---|
| 1863 | + VIVS_HI_IDLE_STATE_MC); |
|---|
| 1827 | 1864 | idle = gpu_read(gpu, VIVS_HI_IDLE_STATE) & mask; |
|---|
| 1828 | | - if (idle != mask) |
|---|
| 1865 | + if (idle != mask) { |
|---|
| 1866 | + dev_warn_ratelimited(dev, "GPU not yet idle, mask: 0x%08x\n", |
|---|
| 1867 | + idle); |
|---|
| 1829 | 1868 | return -EBUSY; |
|---|
| 1869 | + } |
|---|
| 1830 | 1870 | |
|---|
| 1831 | 1871 | return etnaviv_gpu_hw_suspend(gpu); |
|---|
| 1832 | 1872 | } |
|---|
| .. | .. |
|---|
| 1841 | 1881 | return ret; |
|---|
| 1842 | 1882 | |
|---|
| 1843 | 1883 | /* Re-initialise the basic hardware state */ |
|---|
| 1844 | | - if (gpu->drm && gpu->buffer.suballoc) { |
|---|
| 1884 | + if (gpu->drm && gpu->initialized) { |
|---|
| 1845 | 1885 | ret = etnaviv_gpu_hw_resume(gpu); |
|---|
| 1846 | 1886 | if (ret) { |
|---|
| 1847 | 1887 | etnaviv_gpu_clk_disable(gpu); |
|---|