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

mxms.c (4759B)


      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 * Authors: Ben Skeggs
     23 */
     24#include "mxms.h"
     25
     26#define ROM16(x) get_unaligned_le16(&(x))
     27#define ROM32(x) get_unaligned_le32(&(x))
     28
     29static u8 *
     30mxms_data(struct nvkm_mxm *mxm)
     31{
     32	return mxm->mxms;
     33
     34}
     35
     36u16
     37mxms_version(struct nvkm_mxm *mxm)
     38{
     39	u8 *mxms = mxms_data(mxm);
     40	u16 version = (mxms[4] << 8) | mxms[5];
     41	switch (version ) {
     42	case 0x0200:
     43	case 0x0201:
     44	case 0x0300:
     45		return version;
     46	default:
     47		break;
     48	}
     49
     50	nvkm_debug(&mxm->subdev, "unknown version %d.%d\n", mxms[4], mxms[5]);
     51	return 0x0000;
     52}
     53
     54u16
     55mxms_headerlen(struct nvkm_mxm *mxm)
     56{
     57	return 8;
     58}
     59
     60u16
     61mxms_structlen(struct nvkm_mxm *mxm)
     62{
     63	return *(u16 *)&mxms_data(mxm)[6];
     64}
     65
     66bool
     67mxms_checksum(struct nvkm_mxm *mxm)
     68{
     69	u16 size = mxms_headerlen(mxm) + mxms_structlen(mxm);
     70	u8 *mxms = mxms_data(mxm), sum = 0;
     71	while (size--)
     72		sum += *mxms++;
     73	if (sum) {
     74		nvkm_debug(&mxm->subdev, "checksum invalid\n");
     75		return false;
     76	}
     77	return true;
     78}
     79
     80bool
     81mxms_valid(struct nvkm_mxm *mxm)
     82{
     83	u8 *mxms = mxms_data(mxm);
     84	if (*(u32 *)mxms != 0x5f4d584d) {
     85		nvkm_debug(&mxm->subdev, "signature invalid\n");
     86		return false;
     87	}
     88
     89	if (!mxms_version(mxm) || !mxms_checksum(mxm))
     90		return false;
     91
     92	return true;
     93}
     94
     95bool
     96mxms_foreach(struct nvkm_mxm *mxm, u8 types,
     97	     bool (*exec)(struct nvkm_mxm *, u8 *, void *), void *info)
     98{
     99	struct nvkm_subdev *subdev = &mxm->subdev;
    100	u8 *mxms = mxms_data(mxm);
    101	u8 *desc = mxms + mxms_headerlen(mxm);
    102	u8 *fini = desc + mxms_structlen(mxm) - 1;
    103	while (desc < fini) {
    104		u8 type = desc[0] & 0x0f;
    105		u8 headerlen = 0;
    106		u8 recordlen = 0;
    107		u8 entries = 0;
    108
    109		switch (type) {
    110		case 0: /* Output Device Structure */
    111			if (mxms_version(mxm) >= 0x0300)
    112				headerlen = 8;
    113			else
    114				headerlen = 6;
    115			break;
    116		case 1: /* System Cooling Capability Structure */
    117		case 2: /* Thermal Structure */
    118		case 3: /* Input Power Structure */
    119			headerlen = 4;
    120			break;
    121		case 4: /* GPIO Device Structure */
    122			headerlen = 4;
    123			recordlen = 2;
    124			entries   = (ROM32(desc[0]) & 0x01f00000) >> 20;
    125			break;
    126		case 5: /* Vendor Specific Structure */
    127			headerlen = 8;
    128			break;
    129		case 6: /* Backlight Control Structure */
    130			if (mxms_version(mxm) >= 0x0300) {
    131				headerlen = 4;
    132				recordlen = 8;
    133				entries   = (desc[1] & 0xf0) >> 4;
    134			} else {
    135				headerlen = 8;
    136			}
    137			break;
    138		case 7: /* Fan Control Structure */
    139			headerlen = 8;
    140			recordlen = 4;
    141			entries   = desc[1] & 0x07;
    142			break;
    143		default:
    144			nvkm_debug(subdev, "unknown descriptor type %d\n", type);
    145			return false;
    146		}
    147
    148		if (mxm->subdev.debug >= NV_DBG_DEBUG && (exec == NULL)) {
    149			static const char * mxms_desc[] = {
    150				"ODS", "SCCS", "TS", "IPS",
    151				"GSD", "VSS", "BCS", "FCS",
    152			};
    153			u8 *dump = desc;
    154			char data[32], *ptr;
    155			int i, j;
    156
    157			for (j = headerlen - 1, ptr = data; j >= 0; j--)
    158				ptr += sprintf(ptr, "%02x", dump[j]);
    159			dump += headerlen;
    160
    161			nvkm_debug(subdev, "%4s: %s\n", mxms_desc[type], data);
    162			for (i = 0; i < entries; i++, dump += recordlen) {
    163				for (j = recordlen - 1, ptr = data; j >= 0; j--)
    164					ptr += sprintf(ptr, "%02x", dump[j]);
    165				nvkm_debug(subdev, "      %s\n", data);
    166			}
    167		}
    168
    169		if (types & (1 << type)) {
    170			if (!exec(mxm, desc, info))
    171				return false;
    172		}
    173
    174		desc += headerlen + (entries * recordlen);
    175	}
    176
    177	return true;
    178}
    179
    180void
    181mxms_output_device(struct nvkm_mxm *mxm, u8 *pdata, struct mxms_odev *desc)
    182{
    183	u64 data = ROM32(pdata[0]);
    184	if (mxms_version(mxm) >= 0x0300)
    185		data |= (u64)ROM16(pdata[4]) << 32;
    186
    187	desc->outp_type = (data & 0x00000000000000f0ULL) >> 4;
    188	desc->ddc_port  = (data & 0x0000000000000f00ULL) >> 8;
    189	desc->conn_type = (data & 0x000000000001f000ULL) >> 12;
    190	desc->dig_conn  = (data & 0x0000000000780000ULL) >> 19;
    191}