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