drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowrom.c

Source file repositories/reference/linux-study-clean/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowrom.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowrom.c
Extension
.c
Size
4492 bytes
Lines
157
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

struct priv {
	struct nvkm_device *device;
	u32 pci_rom_offset;
};

static u32
nvbios_prom_read(void *data, u32 offset, u32 length, struct nvkm_bios *bios)
{
	struct priv *priv = data;
	struct nvkm_device *device = priv->device;
	u32 i;

	/* Make sure we don't try to read past the end of data[] */
	if (offset + length > bios->size)
		return 0;

	/* Make sure the read falls within the 1MB PROM window */
	if (offset + priv->pci_rom_offset + length > 0x00100000)
		return 0;

	for (i = offset; i < offset + length; i += 4)
		*(u32 *)&bios->data[i] = nvkm_rd32(device, 0x300000 + priv->pci_rom_offset + i);
	return length;
}

static void
nvbios_prom_fini(void *data)
{
	struct priv *priv = data;
	struct nvkm_device *device = priv->device;

	nvkm_pci_rom_shadow(device->pci, true);

	kfree(data);
}

static void *
nvbios_prom_init(struct nvkm_bios *bios, const char *name)
{
	struct nvkm_device *device = bios->subdev.device;
	struct priv *priv;
	u32 fixed0;

	/* There is no PROM on NV4x iGPUs */
	if (device->card_type == NV_40 && device->chipset >= 0x4c)
		return ERR_PTR(-ENODEV);

	priv = kzalloc_obj(*priv);
	if (!priv)
		return ERR_PTR(-ENOMEM);

	/* Disable the PCI ROM shadow so that we can read PROM. */
	nvkm_pci_rom_shadow(device->pci, false);

	/*
	 * Check for an IFR header. If present, parse it to find the actual PCI ROM header.
	 *
	 * The IFR header is documented in Documentation/gpu/nova/core/vbios.rst
	 */
	fixed0 = nvkm_rd32(device, 0x300000);
	if (fixed0 == NV_PBUS_IFR_FMT_FIXED0_SIGNATURE_VALUE) {
		u32 fixed1 = nvkm_rd32(device, 0x300004);
		u8 version = (fixed1 >> 8) & 0xff;
		u32 fixed2, data_size, offset, signature;

		switch (version) {
		case 1:
		case 2:
			data_size = (fixed1 >> 16) & 0x7fff;
			priv->pci_rom_offset = nvkm_rd32(device, 0x300000 + data_size + 4);
			break;
		case 3:
			fixed2 = nvkm_rd32(device, 0x300008);
			data_size = fixed2 & 0x000fffff;

			/* ROM directory offset */
			offset = nvkm_rd32(device, 0x300000 + data_size) + 4096;

			signature = nvkm_rd32(device, 0x300000 + offset);
			if (signature != NV_ROM_DIRECTORY_IDENTIFIER) {
				nvkm_error(&bios->subdev, "could not find IFR ROM directory\n");
				goto fail;
			}

			priv->pci_rom_offset = nvkm_rd32(device, 0x300000 + offset + 8);

			break;
		default:
			nvkm_error(&bios->subdev, "unsupported IFR header version %u\n",
				   version);

Annotation

Implementation Notes