drivers/gpu/drm/imagination/pvr_fw.c

Source file repositories/reference/linux-study-clean/drivers/gpu/drm/imagination/pvr_fw.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/imagination/pvr_fw.c
Extension
.c
Size
44023 bytes
Lines
1516
Domain
Driver Families
Bucket
drivers/gpu
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

switch (layout_entries[entry].type) {
		case FW_CODE:
			fw_mem->code_alloc_size += layout_entries[entry].alloc_size;
			break;
		case FW_DATA:
			fw_mem->data_alloc_size += layout_entries[entry].alloc_size;
			break;
		case FW_COREMEM_CODE:
			fw_mem->core_code_alloc_size +=
				layout_entries[entry].alloc_size;
			break;
		case FW_COREMEM_DATA:
			fw_mem->core_data_alloc_size +=
				layout_entries[entry].alloc_size;
			break;
		case NONE:
			break;
		}
	}
}

int
pvr_fw_find_mmu_segment(struct pvr_device *pvr_dev, u32 addr, u32 size, void *fw_code_ptr,
			void *fw_data_ptr, void *fw_core_code_ptr, void *fw_core_data_ptr,
			void **host_addr_out)
{
	const struct pvr_fw_layout_entry *layout_entries = pvr_dev->fw_dev.layout_entries;
	u32 num_layout_entries = pvr_dev->fw_dev.header->layout_entry_num;
	u32 end_addr = addr + size;

	/* Ensure requested range is not zero, and size is not causing addr to overflow. */
	if (end_addr <= addr)
		return -EINVAL;

	for (int entry = 0; entry < num_layout_entries; entry++) {
		u32 entry_start_addr = layout_entries[entry].base_addr;
		u32 entry_end_addr = entry_start_addr + layout_entries[entry].alloc_size;

		if (addr >= entry_start_addr && addr < entry_end_addr &&
		    end_addr > entry_start_addr && end_addr <= entry_end_addr) {
			switch (layout_entries[entry].type) {
			case FW_CODE:
				*host_addr_out = fw_code_ptr;
				break;

			case FW_DATA:
				*host_addr_out = fw_data_ptr;
				break;

			case FW_COREMEM_CODE:
				*host_addr_out = fw_core_code_ptr;
				break;

			case FW_COREMEM_DATA:
				*host_addr_out = fw_core_data_ptr;
				break;

			default:
				return -EINVAL;
			}
			/* Direct Mem write to mapped memory */
			addr -= layout_entries[entry].base_addr;
			addr += layout_entries[entry].alloc_offset;

			/*
			 * Add offset to pointer to FW allocation only if that
			 * allocation is available
			 */
			*(u8 **)host_addr_out += addr;
			return 0;
		}
	}

	return -EINVAL;
}

static int
pvr_fw_create_fwif_connection_ctl(struct pvr_device *pvr_dev)
{
	struct drm_device *drm_dev = from_pvr_device(pvr_dev);
	struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev;

	fw_dev->fwif_connection_ctl =
		pvr_fw_object_create_and_map_offset(pvr_dev,
						    fw_dev->fw_heap_info.config_offset +
						    PVR_ROGUE_FWIF_CONNECTION_CTL_OFFSET,
						    sizeof(*fw_dev->fwif_connection_ctl),
						    PVR_BO_FW_FLAGS_DEVICE_UNCACHED,
						    NULL, NULL,
						    &fw_dev->mem.fwif_connection_ctl_obj);

Annotation

Implementation Notes