1/* $NetBSD: nouveau_nvkm_subdev_bios_shadowacpi.c,v 1.4 2024/04/16 14:34:02 riastradh Exp $ */ 2 3/* 4 * Copyright 2012 Red Hat Inc. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 * OTHER DEALINGS IN THE SOFTWARE. 23 * 24 */ 25#include <sys/cdefs.h> 26__KERNEL_RCSID(0, "$NetBSD: nouveau_nvkm_subdev_bios_shadowacpi.c,v 1.4 2024/04/16 14:34:02 riastradh Exp $"); 27 28#include "priv.h" 29 30#if defined(CONFIG_ACPI) && defined(CONFIG_X86) 31int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len); 32#ifdef __NetBSD__ 33bool nouveau_acpi_rom_supported(struct acpi_devnode *); 34#else 35bool nouveau_acpi_rom_supported(struct device *); 36#endif 37#else 38static inline bool 39#ifdef __NetBSD__ 40nouveau_acpi_rom_supported(struct acpi_devnode *dev) 41#else 42nouveau_acpi_rom_supported(struct device *dev) 43#endif 44{ 45 return false; 46} 47 48static inline int 49nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len) 50{ 51 return -EINVAL; 52} 53#endif 54 55/* This version of the shadow function disobeys the ACPI spec and tries 56 * to fetch in units of more than 4KiB at a time. This is a LOT faster 57 * on some systems, such as Lenovo W530. 58 */ 59static u32 60acpi_read_fast(void *data, u32 offset, u32 length, struct nvkm_bios *bios) 61{ 62 u32 limit = (offset + length + 0xfff) & ~0xfff; 63 u32 start = offset & ~0x00000fff; 64 u32 fetch = limit - start; 65 66 if (nvbios_extend(bios, limit) >= 0) { 67 int ret = nouveau_acpi_get_bios_chunk(bios->data, start, fetch); 68 if (ret == fetch) 69 return fetch; 70 } 71 72 return 0; 73} 74 75/* Other systems, such as the one in fdo#55948, will report a success 76 * but only return 4KiB of data. The common bios fetching logic will 77 * detect an invalid image, and fall back to this version of the read 78 * function. 79 */ 80static u32 81acpi_read_slow(void *data, u32 offset, u32 length, struct nvkm_bios *bios) 82{ 83 u32 limit = (offset + length + 0xfff) & ~0xfff; 84 u32 start = offset & ~0xfff; 85 u32 fetch = 0; 86 87 if (nvbios_extend(bios, limit) >= 0) { 88 while (start + fetch < limit) { 89 int ret = nouveau_acpi_get_bios_chunk(bios->data, 90 start + fetch, 91 0x1000); 92 if (ret != 0x1000) 93 break; 94 fetch += 0x1000; 95 } 96 } 97 98 return fetch; 99} 100 101static void * 102acpi_init(struct nvkm_bios *bios, const char *name) 103{ 104 if (!nouveau_acpi_rom_supported(bios->subdev.device->acpidev)) 105 return ERR_PTR(-ENODEV); 106 return NULL; 107} 108 109const struct nvbios_source 110nvbios_acpi_fast = { 111 .name = "ACPI", 112 .init = acpi_init, 113 .read = acpi_read_fast, 114 .rw = false, 115 .require_checksum = true, 116}; 117 118const struct nvbios_source 119nvbios_acpi_slow = { 120 .name = "ACPI", 121 .init = acpi_init, 122 .read = acpi_read_slow, 123 .rw = false, 124}; 125