Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/gpu/drm/imagination/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 6 kB image not shown  

Quelle  pvr_vm_mips.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only OR MIT
/* Copyright (c) 2023 Imagination Technologies Ltd. */

#include "pvr_device.h"
#include "pvr_fw_mips.h"
#include "pvr_gem.h"
#include "pvr_mmu.h"
#include "pvr_rogue_mips.h"
#include "pvr_vm.h"
#include "pvr_vm_mips.h"

#include <drm/drm_managed.h>
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/vmalloc.h>

/**
 * pvr_vm_mips_init() - Initialise MIPS FW pagetable
 * @pvr_dev: Target PowerVR device.
 *
 * Returns:
 *  * 0 on success,
 *  * -%EINVAL,
 *  * Any error returned by pvr_gem_object_create(), or
 *  * And error returned by pvr_gem_object_vmap().
 */

int
pvr_vm_mips_init(struct pvr_device *pvr_dev)
{
 u32 pt_size = 1 << ROGUE_MIPSFW_LOG2_PAGETABLE_SIZE_4K(pvr_dev);
 struct device *dev = from_pvr_device(pvr_dev)->dev;
 struct pvr_fw_mips_data *mips_data;
 u32 phys_bus_width;
 int page_nr;
 int err;

 /* Page table size must be at most ROGUE_MIPSFW_MAX_NUM_PAGETABLE_PAGES * 4k pages. */
 if (pt_size > ROGUE_MIPSFW_MAX_NUM_PAGETABLE_PAGES * SZ_4K)
  return -EINVAL;

 if (PVR_FEATURE_VALUE(pvr_dev, phys_bus_width, &phys_bus_width))
  return -EINVAL;

 mips_data = drmm_kzalloc(from_pvr_device(pvr_dev), sizeof(*mips_data), GFP_KERNEL);
 if (!mips_data)
  return -ENOMEM;

 for (page_nr = 0; page_nr < PVR_MIPS_PT_PAGE_COUNT; page_nr++) {
  mips_data->pt_pages[page_nr] = alloc_page(GFP_KERNEL | __GFP_ZERO);
  if (!mips_data->pt_pages[page_nr]) {
   err = -ENOMEM;
   goto err_free_pages;
  }

  mips_data->pt_dma_addr[page_nr] = dma_map_page(dev, mips_data->pt_pages[page_nr], 0,
              PAGE_SIZE, DMA_TO_DEVICE);
  if (dma_mapping_error(dev, mips_data->pt_dma_addr[page_nr])) {
   err = -ENOMEM;
   __free_page(mips_data->pt_pages[page_nr]);
   goto err_free_pages;
  }
 }

 mips_data->pt = vmap(mips_data->pt_pages, pt_size >> PAGE_SHIFT, VM_MAP,
        pgprot_writecombine(PAGE_KERNEL));
 if (!mips_data->pt) {
  err = -ENOMEM;
  goto err_free_pages;
 }

 mips_data->pfn_mask = (phys_bus_width > 32) ? ROGUE_MIPSFW_ENTRYLO_PFN_MASK_ABOVE_32BIT :
            ROGUE_MIPSFW_ENTRYLO_PFN_MASK;

 mips_data->cache_policy = (phys_bus_width > 32) ? ROGUE_MIPSFW_CACHED_POLICY_ABOVE_32BIT :
         ROGUE_MIPSFW_CACHED_POLICY;

 pvr_dev->fw_dev.processor_data.mips_data = mips_data;

 return 0;

err_free_pages:
 while (--page_nr >= 0) {
  dma_unmap_page(from_pvr_device(pvr_dev)->dev,
          mips_data->pt_dma_addr[page_nr], PAGE_SIZE, DMA_TO_DEVICE);

  __free_page(mips_data->pt_pages[page_nr]);
 }

 return err;
}

/**
 * pvr_vm_mips_fini() - Release MIPS FW pagetable
 * @pvr_dev: Target PowerVR device.
 */

void
pvr_vm_mips_fini(struct pvr_device *pvr_dev)
{
 struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev;
 struct pvr_fw_mips_data *mips_data = fw_dev->processor_data.mips_data;

 vunmap(mips_data->pt);
 for (int page_nr = PVR_MIPS_PT_PAGE_COUNT - 1; page_nr >= 0; page_nr--) {
  dma_unmap_page(from_pvr_device(pvr_dev)->dev,
          mips_data->pt_dma_addr[page_nr], PAGE_SIZE, DMA_TO_DEVICE);

  __free_page(mips_data->pt_pages[page_nr]);
 }

 fw_dev->processor_data.mips_data = NULL;
}

static u32
get_mips_pte_flags(bool read, bool write, u32 cache_policy)
{
 u32 flags = 0;

 if (read && write) /* Read/write. */
  flags |= ROGUE_MIPSFW_ENTRYLO_DIRTY_EN;
 else if (write)    /* Write only. */
  flags |= ROGUE_MIPSFW_ENTRYLO_READ_INHIBIT_EN;
 else
  WARN_ON(!read);

 flags |= cache_policy << ROGUE_MIPSFW_ENTRYLO_CACHE_POLICY_SHIFT;

 flags |= ROGUE_MIPSFW_ENTRYLO_VALID_EN | ROGUE_MIPSFW_ENTRYLO_GLOBAL_EN;

 return flags;
}

/**
 * pvr_vm_mips_map() - Map a FW object into MIPS address space
 * @pvr_dev: Target PowerVR device.
 * @fw_obj: FW object to map.
 *
 * Returns:
 *  * 0 on success,
 *  * -%EINVAL if object does not reside within FW address space, or
 *  * Any error returned by pvr_fw_object_get_dma_addr().
 */

int
pvr_vm_mips_map(struct pvr_device *pvr_dev, struct pvr_fw_object *fw_obj)
{
 struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev;
 struct pvr_fw_mips_data *mips_data = fw_dev->processor_data.mips_data;
 struct pvr_gem_object *pvr_obj = fw_obj->gem;
 const u64 start = fw_obj->fw_mm_node.start;
 const u64 size = fw_obj->fw_mm_node.size;
 u64 end;
 u32 cache_policy;
 u32 pte_flags;
 s32 start_pfn;
 s32 end_pfn;
 s32 pfn;
 int err;

 if (check_add_overflow(start, size - 1, &end))
  return -EINVAL;

 if (start < ROGUE_FW_HEAP_BASE ||
     start >= ROGUE_FW_HEAP_BASE + fw_dev->fw_heap_info.raw_size ||
     end < ROGUE_FW_HEAP_BASE ||
     end >= ROGUE_FW_HEAP_BASE + fw_dev->fw_heap_info.raw_size ||
     (start & ROGUE_MIPSFW_PAGE_MASK_4K) ||
     ((end + 1) & ROGUE_MIPSFW_PAGE_MASK_4K))
  return -EINVAL;

 start_pfn = (start & fw_dev->fw_heap_info.offset_mask) >> ROGUE_MIPSFW_LOG2_PAGE_SIZE_4K;
 end_pfn = (end & fw_dev->fw_heap_info.offset_mask) >> ROGUE_MIPSFW_LOG2_PAGE_SIZE_4K;

 if (pvr_obj->flags & PVR_BO_FW_FLAGS_DEVICE_UNCACHED)
  cache_policy = ROGUE_MIPSFW_UNCACHED_CACHE_POLICY;
 else
  cache_policy = mips_data->cache_policy;

 pte_flags = get_mips_pte_flags(truetrue, cache_policy);

 for (pfn = start_pfn; pfn <= end_pfn; pfn++) {
  dma_addr_t dma_addr;
  u32 pte;

  err = pvr_fw_object_get_dma_addr(fw_obj,
       (pfn - start_pfn) <<
       ROGUE_MIPSFW_LOG2_PAGE_SIZE_4K,
       &dma_addr);
  if (err)
   goto err_unmap_pages;

  pte = ((dma_addr >> ROGUE_MIPSFW_LOG2_PAGE_SIZE_4K)
         << ROGUE_MIPSFW_ENTRYLO_PFN_SHIFT) & mips_data->pfn_mask;
  pte |= pte_flags;

  WRITE_ONCE(mips_data->pt[pfn], pte);
 }

 pvr_mmu_flush_request_all(pvr_dev);

 return 0;

err_unmap_pages:
 while (--pfn >= start_pfn)
  WRITE_ONCE(mips_data->pt[pfn], 0);

 pvr_mmu_flush_request_all(pvr_dev);
 WARN_ON(pvr_mmu_flush_exec(pvr_dev, true));

 return err;
}

/**
 * pvr_vm_mips_unmap() - Unmap a FW object into MIPS address space
 * @pvr_dev: Target PowerVR device.
 * @fw_obj: FW object to unmap.
 */

void
pvr_vm_mips_unmap(struct pvr_device *pvr_dev, struct pvr_fw_object *fw_obj)
{
 struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev;
 struct pvr_fw_mips_data *mips_data = fw_dev->processor_data.mips_data;
 const u64 start = fw_obj->fw_mm_node.start;
 const u64 size = fw_obj->fw_mm_node.size;
 const u64 end = start + size;

 const u32 start_pfn = (start & fw_dev->fw_heap_info.offset_mask) >>
         ROGUE_MIPSFW_LOG2_PAGE_SIZE_4K;
 const u32 end_pfn = (end & fw_dev->fw_heap_info.offset_mask) >>
       ROGUE_MIPSFW_LOG2_PAGE_SIZE_4K;

 for (u32 pfn = start_pfn; pfn < end_pfn; pfn++)
  WRITE_ONCE(mips_data->pt[pfn], 0);

 pvr_mmu_flush_request_all(pvr_dev);
 WARN_ON(pvr_mmu_flush_exec(pvr_dev, true));
}

Messung V0.5
C=95 H=80 G=87

¤ Dauer der Verarbeitung: 0.4 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.