diff options
| author | Mikel Rychliski <mikel@mikelr.com> | 2020-03-18 22:16:23 -0400 | 
|---|---|---|
| committer | Bjorn Helgaas <bhelgaas@google.com> | 2020-03-30 09:52:23 -0500 | 
| commit | 72e0ef0e5f067fd991f702f0b2635d911d0cf208 (patch) | |
| tree | fdc18c72009c35c9331adc5abaf20c322aaa909f /drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c | |
| parent | bb6d3fb354c5ee8d6bde2d576eb7220ea09862b9 (diff) | |
PCI: Use ioremap(), not phys_to_virt() for platform ROM
On some EFI systems, the video BIOS is provided by the EFI firmware.  The
boot stub code stores the physical address of the ROM image in pdev->rom.
Currently we attempt to access this pointer using phys_to_virt(), which
doesn't work with CONFIG_HIGHMEM.
On these systems, attempting to load the radeon module on a x86_32 kernel
can result in the following:
  BUG: unable to handle page fault for address: 3e8ed03c
  #PF: supervisor read access in kernel mode
  #PF: error_code(0x0000) - not-present page
  *pde = 00000000
  Oops: 0000 [#1] PREEMPT SMP
  CPU: 0 PID: 317 Comm: systemd-udevd Not tainted 5.6.0-rc3-next-20200228 #2
  Hardware name: Apple Computer, Inc. MacPro1,1/Mac-F4208DC8, BIOS     MP11.88Z.005C.B08.0707021221 07/02/07
  EIP: radeon_get_bios+0x5ed/0xe50 [radeon]
  Code: 00 00 84 c0 0f 85 12 fd ff ff c7 87 64 01 00 00 00 00 00 00 8b 47 08 8b 55 b0 e8 1e 83 e1 d6 85 c0 74 1a 8b 55 c0 85 d2 74 13 <80> 38 55 75 0e 80 78 01 aa 0f 84 a4 03 00 00 8d 74 26 00 68 dc 06
  EAX: 3e8ed03c EBX: 00000000 ECX: 3e8ed03c EDX: 00010000
  ESI: 00040000 EDI: eec04000 EBP: eef3fc60 ESP: eef3fbe0
  DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068 EFLAGS: 00010206
  CR0: 80050033 CR2: 3e8ed03c CR3: 2ec77000 CR4: 000006d0
  Call Trace:
   r520_init+0x26/0x240 [radeon]
   radeon_device_init+0x533/0xa50 [radeon]
   radeon_driver_load_kms+0x80/0x220 [radeon]
   drm_dev_register+0xa7/0x180 [drm]
   radeon_pci_probe+0x10f/0x1a0 [radeon]
   pci_device_probe+0xd4/0x140
Fix the issue by updating all drivers which can access a platform provided
ROM. Instead of calling the helper function pci_platform_rom() which uses
phys_to_virt(), call ioremap() directly on the pdev->rom.
radeon_read_platform_bios() previously directly accessed an __iomem
pointer. Avoid this by calling memcpy_fromio() instead of kmemdup().
pci_platform_rom() now has no remaining callers, so remove it.
Link: https://lore.kernel.org/r/20200319021623.5426-1-mikel@mikelr.com
Signed-off-by: Mikel Rychliski <mikel@mikelr.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Acked-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c')
| -rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c | 31 | 
1 files changed, 18 insertions, 13 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c index 50dff69a0f6e..b1172d93c99c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c @@ -192,30 +192,35 @@ static bool amdgpu_read_bios_from_rom(struct amdgpu_device *adev)  static bool amdgpu_read_platform_bios(struct amdgpu_device *adev)  { -	uint8_t __iomem *bios; -	size_t size; +	phys_addr_t rom = adev->pdev->rom; +	size_t romlen = adev->pdev->romlen; +	void __iomem *bios;  	adev->bios = NULL; -	bios = pci_platform_rom(adev->pdev, &size); -	if (!bios) { +	if (!rom || romlen == 0)  		return false; -	} -	adev->bios = kzalloc(size, GFP_KERNEL); -	if (adev->bios == NULL) +	adev->bios = kzalloc(romlen, GFP_KERNEL); +	if (!adev->bios)  		return false; -	memcpy_fromio(adev->bios, bios, size); +	bios = ioremap(rom, romlen); +	if (!bios) +		goto free_bios; -	if (!check_atom_bios(adev->bios, size)) { -		kfree(adev->bios); -		return false; -	} +	memcpy_fromio(adev->bios, bios, romlen); +	iounmap(bios); -	adev->bios_size = size; +	if (!check_atom_bios(adev->bios, romlen)) +		goto free_bios; + +	adev->bios_size = romlen;  	return true; +free_bios: +	kfree(adev->bios); +	return false;  }  #ifdef CONFIG_ACPI  | 
