cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

power_budget.c (3460B)


      1/*
      2 * Copyright 2016 Karol Herbst
      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 * Authors: Karol Herbst
     23 */
     24#include <subdev/bios.h>
     25#include <subdev/bios/bit.h>
     26#include <subdev/bios/power_budget.h>
     27
     28static u32
     29nvbios_power_budget_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt,
     30			  u8 *len)
     31{
     32	struct bit_entry bit_P;
     33	u32 power_budget;
     34
     35	if (bit_entry(bios, 'P', &bit_P) || bit_P.version != 2 ||
     36	    bit_P.length < 0x30)
     37		return 0;
     38
     39	power_budget = nvbios_rd32(bios, bit_P.offset + 0x2c);
     40	if (!power_budget)
     41		return 0;
     42
     43	*ver = nvbios_rd08(bios, power_budget);
     44	switch (*ver) {
     45	case 0x20:
     46	case 0x30:
     47		*hdr = nvbios_rd08(bios, power_budget + 0x1);
     48		*len = nvbios_rd08(bios, power_budget + 0x2);
     49		*cnt = nvbios_rd08(bios, power_budget + 0x3);
     50		return power_budget;
     51	default:
     52		break;
     53	}
     54
     55	return 0;
     56}
     57
     58int
     59nvbios_power_budget_header(struct nvkm_bios *bios,
     60                           struct nvbios_power_budget *budget)
     61{
     62	struct nvkm_subdev *subdev = &bios->subdev;
     63	u8 ver, hdr, cnt, len, cap_entry;
     64	u32 header;
     65
     66	if (!bios || !budget)
     67		return -EINVAL;
     68
     69	header = nvbios_power_budget_table(bios, &ver, &hdr, &cnt, &len);
     70	if (!header || !cnt)
     71		return -ENODEV;
     72
     73	switch (ver) {
     74	case 0x20:
     75		cap_entry = nvbios_rd08(bios, header + 0x9);
     76		break;
     77	case 0x30:
     78		cap_entry = nvbios_rd08(bios, header + 0xa);
     79		break;
     80	default:
     81		cap_entry = 0xff;
     82	}
     83
     84	if (cap_entry >= cnt && cap_entry != 0xff) {
     85		nvkm_warn(subdev,
     86		          "invalid cap_entry in power budget table found\n");
     87		budget->cap_entry = 0xff;
     88		return -EINVAL;
     89	}
     90
     91	budget->offset = header;
     92	budget->ver = ver;
     93	budget->hlen = hdr;
     94	budget->elen = len;
     95	budget->ecount = cnt;
     96
     97	budget->cap_entry = cap_entry;
     98
     99	return 0;
    100}
    101
    102int
    103nvbios_power_budget_entry(struct nvkm_bios *bios,
    104                          struct nvbios_power_budget *budget,
    105                          u8 idx, struct nvbios_power_budget_entry *entry)
    106{
    107	u32 entry_offset;
    108
    109	if (!bios || !budget || !budget->offset || idx >= budget->ecount
    110		|| !entry)
    111		return -EINVAL;
    112
    113	entry_offset = budget->offset + budget->hlen + idx * budget->elen;
    114
    115	if (budget->ver >= 0x20) {
    116		entry->min_w = nvbios_rd32(bios, entry_offset + 0x2);
    117		entry->avg_w = nvbios_rd32(bios, entry_offset + 0x6);
    118		entry->max_w = nvbios_rd32(bios, entry_offset + 0xa);
    119	} else {
    120		entry->min_w = 0;
    121		entry->max_w = nvbios_rd32(bios, entry_offset + 0x2);
    122		entry->avg_w = entry->max_w;
    123	}
    124
    125	return 0;
    126}