[bug report] drm/imagination: Implement MIPS firmware processor and MMU support

Dan Carpenter dan.carpenter at linaro.org
Wed Dec 6 13:01:48 UTC 2023


Hello Sarah Walker,

The patch 927f3e0253c1: "drm/imagination: Implement MIPS firmware
processor and MMU support" from Nov 22, 2023 (linux-next), leads to
the following Smatch static checker warning:

	drivers/gpu/drm/imagination/pvr_vm_mips.c:204 pvr_vm_mips_map()
	warn: 'pfn' can be negative (type promoted to high)

drivers/gpu/drm/imagination/pvr_vm_mips.c
    144 int
    145 pvr_vm_mips_map(struct pvr_device *pvr_dev, struct pvr_fw_object *fw_obj)
    146 {
    147         struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev;
    148         struct pvr_fw_mips_data *mips_data = fw_dev->processor_data.mips_data;
    149         struct pvr_gem_object *pvr_obj = fw_obj->gem;
    150         const u64 start = fw_obj->fw_mm_node.start;
    151         const u64 size = fw_obj->fw_mm_node.size;
    152         u64 end;
    153         u32 cache_policy;
    154         u32 pte_flags;
    155         u32 start_pfn;
    156         u32 end_pfn;
    157         s32 pfn;

pfn is s32 but start_pfn is u32.

    158         int err;
    159 
    160         if (check_add_overflow(start, size - 1, &end))
    161                 return -EINVAL;
    162 
    163         if (start < ROGUE_FW_HEAP_BASE ||
    164             start >= ROGUE_FW_HEAP_BASE + fw_dev->fw_heap_info.raw_size ||
    165             end < ROGUE_FW_HEAP_BASE ||
    166             end >= ROGUE_FW_HEAP_BASE + fw_dev->fw_heap_info.raw_size ||
    167             (start & ROGUE_MIPSFW_PAGE_MASK_4K) ||
    168             ((end + 1) & ROGUE_MIPSFW_PAGE_MASK_4K))
    169                 return -EINVAL;
    170 
    171         start_pfn = (start & fw_dev->fw_heap_info.offset_mask) >> ROGUE_MIPSFW_LOG2_PAGE_SIZE_4K;

Can start_pfn be zero?

    172         end_pfn = (end & fw_dev->fw_heap_info.offset_mask) >> ROGUE_MIPSFW_LOG2_PAGE_SIZE_4K;
    173 
    174         if (pvr_obj->flags & PVR_BO_FW_FLAGS_DEVICE_UNCACHED)
    175                 cache_policy = ROGUE_MIPSFW_UNCACHED_CACHE_POLICY;
    176         else
    177                 cache_policy = mips_data->cache_policy;
    178 
    179         pte_flags = get_mips_pte_flags(true, true, cache_policy);
    180 
    181         for (pfn = start_pfn; pfn <= end_pfn; pfn++) {
    182                 dma_addr_t dma_addr;
    183                 u32 pte;
    184 
    185                 err = pvr_fw_object_get_dma_addr(fw_obj,
    186                                                  (pfn - start_pfn) <<
    187                                                  ROGUE_MIPSFW_LOG2_PAGE_SIZE_4K,
    188                                                  &dma_addr);
    189                 if (err)
    190                         goto err_unmap_pages;
    191 
    192                 pte = ((dma_addr >> ROGUE_MIPSFW_LOG2_PAGE_SIZE_4K)
    193                        << ROGUE_MIPSFW_ENTRYLO_PFN_SHIFT) & mips_data->pfn_mask;
    194                 pte |= pte_flags;
    195 
    196                 WRITE_ONCE(mips_data->pt[pfn], pte);
    197         }
    198 
    199         pvr_mmu_flush_request_all(pvr_dev);
    200 
    201         return 0;
    202 
    203 err_unmap_pages:
--> 204         for (; pfn >= start_pfn; pfn--)
                       ^^^^^^^^^^^^^^^^
If start_pfn can be zero then this is an endless loop.  I've seen this
code in other places as well.  This loop is slightly off as well.  It
should decrement pfn on the first iteration.

There are hack arounds for using unsigned iterators:

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

Personally I would be tempted to make things signed...  Here are some
links to various rants I have wrote:
https://staticthinking.wordpress.com/2022/06/01/unsigned-int-i-is-stupid/
https://staticthinking.wordpress.com/2023/07/25/wsign-compare-is-garbage/
You didn't ask for rants...  No one ever asks for rants...

    205                 WRITE_ONCE(mips_data->pt[pfn], 0);
    206 
    207         pvr_mmu_flush_request_all(pvr_dev);
    208         WARN_ON(pvr_mmu_flush_exec(pvr_dev, true));
    209 
    210         return err;
    211 }

regards,
dan carpenter


More information about the dri-devel mailing list