Index: sys/external/bsd/drm2/dist/drm/radeon/radeon_bios.c =================================================================== RCS file: /cvsroot/src/sys/external/bsd/drm2/dist/drm/radeon/radeon_bios.c,v retrieving revision 1.4 diff -p -u -r1.4 radeon_bios.c --- sys/external/bsd/drm2/dist/drm/radeon/radeon_bios.c 24 Jun 2015 18:23:23 -0000 1.4 +++ sys/external/bsd/drm2/dist/drm/radeon/radeon_bios.c 16 Jun 2016 14:39:41 -0000 @@ -34,6 +34,14 @@ #include #include #include + +#if defined(__NetBSD__) && defined(_KERNEL_OPT) +# include "acpica.h" +# if NACPICA > 0 +# define CONFIG_ACPI +# endif +#endif + /* * BIOS. */ @@ -186,13 +194,106 @@ static bool radeon_read_platform_bios(st #endif } -/* XXX radeon acpi */ #ifdef CONFIG_ACPI /* ATRM is used to get the BIOS on the discrete cards in * dual-gpu systems. */ /* retrieve the ROM in 4k blocks */ #define ATRM_BIOS_PAGE 4096 + +#ifdef __NetBSD__ + +#include +#define _COMPONENT ACPI_RESOURCE_COMPONENT +ACPI_MODULE_NAME ("radeon_bios") + +static ACPI_STATUS +radeon_atrm_call(ACPI_HANDLE atrm_handle, uint8_t *bios, size_t offset, + size_t len) +{ + ACPI_OBJECT args[] = { + { .Integer = { .Type = ACPI_TYPE_INTEGER, .Value = offset } }, + { .Integer = { .Type = ACPI_TYPE_INTEGER, .Value = len } }, + }; + ACPI_OBJECT_LIST arglist = { + .Count = __arraycount(args), + .Pointer = args, + }; + ACPI_BUFFER buffer = { .Length = ACPI_ALLOCATE_BUFFER }; + ACPI_OBJECT *obj; + size_t n; + ACPI_STATUS status; + + status = AcpiEvaluateObject(atrm_handle, NULL, &arglist, &buffer); + if (ACPI_FAILURE(status)) + return status; + + obj = (ACPI_OBJECT *)buffer.Pointer; + KASSERT(obj != NULL); + n = MIN(obj->Buffer.Length, len); /* paranoia */ + (void)memcpy(bios + offset, obj->Buffer.Pointer, n); + + /* Success! */ + status = AE_OK; + ACPI_FREE(buffer.Pointer); + return AE_OK; +} + +static bool +radeon_atrm_get_bios(struct radeon_device *rdev) +{ + const size_t size = 256*1024U; + const struct pci_attach_args *const pa = &rdev->pdev->pd_pa; + struct acpi_devnode *node; + ACPI_HANDLE handle, atrm_handle; + size_t i; + ACPI_STATUS status; + + if (ISSET(rdev->flags, RADEON_IS_IGP)) + goto fail0; + + /* XXX Try all VGA-class devices? */ + node = acpi_pcidev_find(0 /* segment */, pa->pa_bus, pa->pa_device, + pa->pa_function); + if (node == NULL) { + DRM_ERROR("Failed to find PCI ACPI node\n"); + goto fail0; + } + handle = node->ad_handle; + KASSERT(handle != NULL); + status = AcpiGetHandle(handle, "ATRM", &atrm_handle); + if (ACPI_FAILURE(status)) { + DRM_ERROR("Failed to get ACPI ATRM handle: %s\n", + AcpiFormatException(status)); + goto fail1; + } + rdev->bios = kzalloc(size, GFP_KERNEL); /* z paranoia */ + for (i = 0; i < size; i += 4096) { + status = radeon_atrm_call(atrm_handle, rdev->bios, i, 4096); + if (ACPI_FAILURE(status)) + break; + } + + if (i == 0) { + DRM_ERROR("Failed to call ACPI ATRM: %s\n", + AcpiFormatException(status)); + goto fail1; + } + if (rdev->bios[0] != 0x55 || rdev->bios[1] != 0xaa) { + DRM_ERROR("Invalid BIOS from ATRM\n"); + goto fail1; + } + + /* Success! */ + return true; + +fail1: kfree(rdev->bios); + rdev->bios = NULL; +fail0: return false; +} + +#else + /** * radeon_atrm_call - fetch a chunk of the vbios * @@ -299,7 +400,8 @@ static bool radeon_atrm_get_bios(struct } return true; } -#else +#endif /* __NetBSD__ */ +#else /* CONFIG_ACPI */ static inline bool radeon_atrm_get_bios(struct radeon_device *rdev) { return false; @@ -656,6 +758,67 @@ static bool radeon_read_disabled_bios(st } #ifdef CONFIG_ACPI + +#ifdef __NetBSD__ + +static bool +radeon_acpi_vfct_bios(struct radeon_device *rdev) +{ + const size_t minsize = MIN(sizeof(UEFI_ACPI_VFCT), + sizeof(VFCT_IMAGE_HEADER)); + const struct pci_attach_args *const pa = &rdev->pdev->pd_pa; + UEFI_ACPI_VFCT *vfct; + const VFCT_IMAGE_HEADER *vhdr; + const GOP_VBIOS_CONTENT *vbios; + size_t size, offset; + ACPI_STATUS status; + + status = AcpiGetTable("VFCT", 1, (ACPI_TABLE_HEADER **)&vfct); + if (ACPI_FAILURE(status)) { + DRM_ERROR("Unable to get ACPI VFCT table: %s\n", + AcpiFormatException(status)); + return false; + } + size = vfct->SHeader.TableLength; + if (size < minsize) { + DRM_ERROR("ACPI VFCT table too short for header: %zu < %zu\n", + size, minsize); + return false; + } + offset = vfct->VBIOSImageOffset; + if (offset > size - sizeof(VFCT_IMAGE_HEADER)) { + DRM_ERROR("ACPI VFCT VBIOS offset too large: %zu > %zu\n", + offset, size); + return false; + } + + vbios = (const GOP_VBIOS_CONTENT *)((const char *)vfct + offset); + vhdr = &vbios->VbiosHeader; + DRM_INFO("ACPI VFCT contains a BIOS for" + " %02"PRIx32":%02"PRIx32".%"PRId32" %04"PRIx16":%04"PRIx16 + ", size %"PRIu32"\n", + vhdr->PCIBus, vhdr->PCIDevice, vhdr->PCIFunction, + vhdr->VendorID, vhdr->DeviceID, vhdr->ImageLength); + if (vhdr->PCIBus != pa->pa_bus || + vhdr->PCIDevice != pa->pa_device || + vhdr->PCIFunction != pa->pa_function || + vhdr->VendorID != PCI_VENDOR(pa->pa_id) || + vhdr->DeviceID != PCI_PRODUCT(pa->pa_id)) { + DRM_INFO("ACPI VFCT table is not for this device\n"); + return false; + } + + rdev->bios = kmemdup(&vbios->VbiosContent, vhdr->ImageLength, + GFP_KERNEL); + if (rdev->bios == NULL) + return false; + + /* Success! */ + return true; +} + +#else /* !__NetBSD__ */ + static bool radeon_acpi_vfct_bios(struct radeon_device *rdev) { bool ret = false; @@ -704,7 +867,10 @@ static bool radeon_acpi_vfct_bios(struct out_unmap: return ret; } -#else + +#endif /* __NetBSD__ */ + +#else /* CONFIG_ACPI */ static inline bool radeon_acpi_vfct_bios(struct radeon_device *rdev) { return false;