LCOV - code coverage report
Current view: top level - drivers/gpu/drm/amd/amdgpu - amdgpu_ih.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 108 0.0 %
Date: 2022-12-09 01:23:36 Functions: 0 7 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright 2014 Advanced Micro Devices, Inc.
       3             :  *
       4             :  * Permission is hereby granted, free of charge, to any person obtaining a
       5             :  * copy of this software and associated documentation files (the "Software"),
       6             :  * to deal in the Software without restriction, including without limitation
       7             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
       8             :  * and/or sell copies of the Software, and to permit persons to whom the
       9             :  * Software is furnished to do so, subject to the following conditions:
      10             :  *
      11             :  * The above copyright notice and this permission notice shall be included in
      12             :  * all copies or substantial portions of the Software.
      13             :  *
      14             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      15             :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      16             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
      17             :  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
      18             :  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
      19             :  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
      20             :  * OTHER DEALINGS IN THE SOFTWARE.
      21             :  *
      22             :  */
      23             : 
      24             : #include <linux/dma-mapping.h>
      25             : 
      26             : #include "amdgpu.h"
      27             : #include "amdgpu_ih.h"
      28             : 
      29             : /**
      30             :  * amdgpu_ih_ring_init - initialize the IH state
      31             :  *
      32             :  * @adev: amdgpu_device pointer
      33             :  * @ih: ih ring to initialize
      34             :  * @ring_size: ring size to allocate
      35             :  * @use_bus_addr: true when we can use dma_alloc_coherent
      36             :  *
      37             :  * Initializes the IH state and allocates a buffer
      38             :  * for the IH ring buffer.
      39             :  * Returns 0 for success, errors for failure.
      40             :  */
      41           0 : int amdgpu_ih_ring_init(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih,
      42             :                         unsigned ring_size, bool use_bus_addr)
      43             : {
      44             :         u32 rb_bufsz;
      45             :         int r;
      46             : 
      47             :         /* Align ring size */
      48           0 :         rb_bufsz = order_base_2(ring_size / 4);
      49           0 :         ring_size = (1 << rb_bufsz) * 4;
      50           0 :         ih->ring_size = ring_size;
      51           0 :         ih->ptr_mask = ih->ring_size - 1;
      52           0 :         ih->rptr = 0;
      53           0 :         ih->use_bus_addr = use_bus_addr;
      54             : 
      55           0 :         if (use_bus_addr) {
      56             :                 dma_addr_t dma_addr;
      57             : 
      58           0 :                 if (ih->ring)
      59           0 :                         return 0;
      60             : 
      61             :                 /* add 8 bytes for the rptr/wptr shadows and
      62             :                  * add them to the end of the ring allocation.
      63             :                  */
      64           0 :                 ih->ring = dma_alloc_coherent(adev->dev, ih->ring_size + 8,
      65             :                                               &dma_addr, GFP_KERNEL);
      66           0 :                 if (ih->ring == NULL)
      67             :                         return -ENOMEM;
      68             : 
      69           0 :                 ih->gpu_addr = dma_addr;
      70           0 :                 ih->wptr_addr = dma_addr + ih->ring_size;
      71           0 :                 ih->wptr_cpu = &ih->ring[ih->ring_size / 4];
      72           0 :                 ih->rptr_addr = dma_addr + ih->ring_size + 4;
      73           0 :                 ih->rptr_cpu = &ih->ring[(ih->ring_size / 4) + 1];
      74             :         } else {
      75             :                 unsigned wptr_offs, rptr_offs;
      76             : 
      77           0 :                 r = amdgpu_device_wb_get(adev, &wptr_offs);
      78           0 :                 if (r)
      79           0 :                         return r;
      80             : 
      81           0 :                 r = amdgpu_device_wb_get(adev, &rptr_offs);
      82           0 :                 if (r) {
      83           0 :                         amdgpu_device_wb_free(adev, wptr_offs);
      84           0 :                         return r;
      85             :                 }
      86             : 
      87           0 :                 r = amdgpu_bo_create_kernel(adev, ih->ring_size, PAGE_SIZE,
      88             :                                             AMDGPU_GEM_DOMAIN_GTT,
      89           0 :                                             &ih->ring_obj, &ih->gpu_addr,
      90           0 :                                             (void **)&ih->ring);
      91           0 :                 if (r) {
      92           0 :                         amdgpu_device_wb_free(adev, rptr_offs);
      93           0 :                         amdgpu_device_wb_free(adev, wptr_offs);
      94           0 :                         return r;
      95             :                 }
      96             : 
      97           0 :                 ih->wptr_addr = adev->wb.gpu_addr + wptr_offs * 4;
      98           0 :                 ih->wptr_cpu = &adev->wb.wb[wptr_offs];
      99           0 :                 ih->rptr_addr = adev->wb.gpu_addr + rptr_offs * 4;
     100           0 :                 ih->rptr_cpu = &adev->wb.wb[rptr_offs];
     101             :         }
     102             : 
     103           0 :         init_waitqueue_head(&ih->wait_process);
     104           0 :         return 0;
     105             : }
     106             : 
     107             : /**
     108             :  * amdgpu_ih_ring_fini - tear down the IH state
     109             :  *
     110             :  * @adev: amdgpu_device pointer
     111             :  * @ih: ih ring to tear down
     112             :  *
     113             :  * Tears down the IH state and frees buffer
     114             :  * used for the IH ring buffer.
     115             :  */
     116           0 : void amdgpu_ih_ring_fini(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih)
     117             : {
     118             : 
     119           0 :         if (!ih->ring)
     120             :                 return;
     121             : 
     122           0 :         if (ih->use_bus_addr) {
     123             : 
     124             :                 /* add 8 bytes for the rptr/wptr shadows and
     125             :                  * add them to the end of the ring allocation.
     126             :                  */
     127           0 :                 dma_free_coherent(adev->dev, ih->ring_size + 8,
     128             :                                   (void *)ih->ring, ih->gpu_addr);
     129           0 :                 ih->ring = NULL;
     130             :         } else {
     131           0 :                 amdgpu_bo_free_kernel(&ih->ring_obj, &ih->gpu_addr,
     132           0 :                                       (void **)&ih->ring);
     133           0 :                 amdgpu_device_wb_free(adev, (ih->wptr_addr - ih->gpu_addr) / 4);
     134           0 :                 amdgpu_device_wb_free(adev, (ih->rptr_addr - ih->gpu_addr) / 4);
     135             :         }
     136             : }
     137             : 
     138             : /**
     139             :  * amdgpu_ih_ring_write - write IV to the ring buffer
     140             :  *
     141             :  * @ih: ih ring to write to
     142             :  * @iv: the iv to write
     143             :  * @num_dw: size of the iv in dw
     144             :  *
     145             :  * Writes an IV to the ring buffer using the CPU and increment the wptr.
     146             :  * Used for testing and delegating IVs to a software ring.
     147             :  */
     148           0 : void amdgpu_ih_ring_write(struct amdgpu_ih_ring *ih, const uint32_t *iv,
     149             :                           unsigned int num_dw)
     150             : {
     151           0 :         uint32_t wptr = le32_to_cpu(*ih->wptr_cpu) >> 2;
     152             :         unsigned int i;
     153             : 
     154           0 :         for (i = 0; i < num_dw; ++i)
     155           0 :                 ih->ring[wptr++] = cpu_to_le32(iv[i]);
     156             : 
     157           0 :         wptr <<= 2;
     158           0 :         wptr &= ih->ptr_mask;
     159             : 
     160             :         /* Only commit the new wptr if we don't overflow */
     161           0 :         if (wptr != READ_ONCE(ih->rptr)) {
     162           0 :                 wmb();
     163           0 :                 WRITE_ONCE(*ih->wptr_cpu, cpu_to_le32(wptr));
     164             :         }
     165           0 : }
     166             : 
     167             : /**
     168             :  * amdgpu_ih_wait_on_checkpoint_process_ts - wait to process IVs up to checkpoint
     169             :  *
     170             :  * @adev: amdgpu_device pointer
     171             :  * @ih: ih ring to process
     172             :  *
     173             :  * Used to ensure ring has processed IVs up to the checkpoint write pointer.
     174             :  */
     175           0 : int amdgpu_ih_wait_on_checkpoint_process_ts(struct amdgpu_device *adev,
     176             :                                         struct amdgpu_ih_ring *ih)
     177             : {
     178             :         uint32_t checkpoint_wptr;
     179             :         uint64_t checkpoint_ts;
     180           0 :         long timeout = HZ;
     181             : 
     182           0 :         if (!ih->enabled || adev->shutdown)
     183             :                 return -ENODEV;
     184             : 
     185           0 :         checkpoint_wptr = amdgpu_ih_get_wptr(adev, ih);
     186             :         /* Order wptr with ring data. */
     187           0 :         rmb();
     188           0 :         checkpoint_ts = amdgpu_ih_decode_iv_ts(adev, ih, checkpoint_wptr, -1);
     189             : 
     190           0 :         return wait_event_interruptible_timeout(ih->wait_process,
     191             :                     amdgpu_ih_ts_after(checkpoint_ts, ih->processed_timestamp) ||
     192             :                     ih->rptr == amdgpu_ih_get_wptr(adev, ih), timeout);
     193             : }
     194             : 
     195             : /**
     196             :  * amdgpu_ih_process - interrupt handler
     197             :  *
     198             :  * @adev: amdgpu_device pointer
     199             :  * @ih: ih ring to process
     200             :  *
     201             :  * Interrupt hander (VI), walk the IH ring.
     202             :  * Returns irq process return code.
     203             :  */
     204           0 : int amdgpu_ih_process(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih)
     205             : {
     206             :         unsigned int count;
     207             :         u32 wptr;
     208             : 
     209           0 :         if (!ih->enabled || adev->shutdown)
     210             :                 return IRQ_NONE;
     211             : 
     212           0 :         wptr = amdgpu_ih_get_wptr(adev, ih);
     213             : 
     214             : restart_ih:
     215           0 :         count  = AMDGPU_IH_MAX_NUM_IVS;
     216           0 :         DRM_DEBUG("%s: rptr %d, wptr %d\n", __func__, ih->rptr, wptr);
     217             : 
     218             :         /* Order reading of wptr vs. reading of IH ring data */
     219           0 :         rmb();
     220             : 
     221           0 :         while (ih->rptr != wptr && --count) {
     222           0 :                 amdgpu_irq_dispatch(adev, ih);
     223           0 :                 ih->rptr &= ih->ptr_mask;
     224             :         }
     225             : 
     226           0 :         amdgpu_ih_set_rptr(adev, ih);
     227           0 :         wake_up_all(&ih->wait_process);
     228             : 
     229             :         /* make sure wptr hasn't changed while processing */
     230           0 :         wptr = amdgpu_ih_get_wptr(adev, ih);
     231           0 :         if (wptr != ih->rptr)
     232             :                 goto restart_ih;
     233             : 
     234             :         return IRQ_HANDLED;
     235             : }
     236             : 
     237             : /**
     238             :  * amdgpu_ih_decode_iv_helper - decode an interrupt vector
     239             :  *
     240             :  * @adev: amdgpu_device pointer
     241             :  * @ih: ih ring to process
     242             :  * @entry: IV entry
     243             :  *
     244             :  * Decodes the interrupt vector at the current rptr
     245             :  * position and also advance the position for Vega10
     246             :  * and later GPUs.
     247             :  */
     248           0 : void amdgpu_ih_decode_iv_helper(struct amdgpu_device *adev,
     249             :                                 struct amdgpu_ih_ring *ih,
     250             :                                 struct amdgpu_iv_entry *entry)
     251             : {
     252             :         /* wptr/rptr are in bytes! */
     253           0 :         u32 ring_index = ih->rptr >> 2;
     254             :         uint32_t dw[8];
     255             : 
     256           0 :         dw[0] = le32_to_cpu(ih->ring[ring_index + 0]);
     257           0 :         dw[1] = le32_to_cpu(ih->ring[ring_index + 1]);
     258           0 :         dw[2] = le32_to_cpu(ih->ring[ring_index + 2]);
     259           0 :         dw[3] = le32_to_cpu(ih->ring[ring_index + 3]);
     260           0 :         dw[4] = le32_to_cpu(ih->ring[ring_index + 4]);
     261           0 :         dw[5] = le32_to_cpu(ih->ring[ring_index + 5]);
     262           0 :         dw[6] = le32_to_cpu(ih->ring[ring_index + 6]);
     263           0 :         dw[7] = le32_to_cpu(ih->ring[ring_index + 7]);
     264             : 
     265           0 :         entry->client_id = dw[0] & 0xff;
     266           0 :         entry->src_id = (dw[0] >> 8) & 0xff;
     267           0 :         entry->ring_id = (dw[0] >> 16) & 0xff;
     268           0 :         entry->vmid = (dw[0] >> 24) & 0xf;
     269           0 :         entry->vmid_src = (dw[0] >> 31);
     270           0 :         entry->timestamp = dw[1] | ((u64)(dw[2] & 0xffff) << 32);
     271           0 :         entry->timestamp_src = dw[2] >> 31;
     272           0 :         entry->pasid = dw[3] & 0xffff;
     273           0 :         entry->pasid_src = dw[3] >> 31;
     274           0 :         entry->src_data[0] = dw[4];
     275           0 :         entry->src_data[1] = dw[5];
     276           0 :         entry->src_data[2] = dw[6];
     277           0 :         entry->src_data[3] = dw[7];
     278             : 
     279             :         /* wptr/rptr are in bytes! */
     280           0 :         ih->rptr += 32;
     281           0 : }
     282             : 
     283           0 : uint64_t amdgpu_ih_decode_iv_ts_helper(struct amdgpu_ih_ring *ih, u32 rptr,
     284             :                                        signed int offset)
     285             : {
     286           0 :         uint32_t iv_size = 32;
     287             :         uint32_t ring_index;
     288             :         uint32_t dw1, dw2;
     289             : 
     290           0 :         rptr += iv_size * offset;
     291           0 :         ring_index = (rptr & ih->ptr_mask) >> 2;
     292             : 
     293           0 :         dw1 = le32_to_cpu(ih->ring[ring_index + 1]);
     294           0 :         dw2 = le32_to_cpu(ih->ring[ring_index + 2]);
     295           0 :         return dw1 | ((u64)(dw2 & 0xffff) << 32);
     296             : }

Generated by: LCOV version 1.14