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

dice-extension.c (4776B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * dice-extension.c - a part of driver for DICE based devices
      4 *
      5 * Copyright (c) 2018 Takashi Sakamoto
      6 */
      7
      8#include "dice.h"
      9
     10/* For TCD2210/2220, TCAT defines extension of application protocol. */
     11
     12#define DICE_EXT_APP_SPACE		0xffffe0200000uLL
     13
     14#define DICE_EXT_APP_CAPS_OFFSET	0x00
     15#define DICE_EXT_APP_CAPS_SIZE		0x04
     16#define DICE_EXT_APP_CMD_OFFSET		0x08
     17#define DICE_EXT_APP_CMD_SIZE		0x0c
     18#define DICE_EXT_APP_MIXER_OFFSET	0x10
     19#define DICE_EXT_APP_MIXER_SIZE		0x14
     20#define DICE_EXT_APP_PEAK_OFFSET	0x18
     21#define DICE_EXT_APP_PEAK_SIZE		0x1c
     22#define DICE_EXT_APP_ROUTER_OFFSET	0x20
     23#define DICE_EXT_APP_ROUTER_SIZE	0x24
     24#define DICE_EXT_APP_STREAM_OFFSET	0x28
     25#define DICE_EXT_APP_STREAM_SIZE	0x2c
     26#define DICE_EXT_APP_CURRENT_OFFSET	0x30
     27#define DICE_EXT_APP_CURRENT_SIZE	0x34
     28#define DICE_EXT_APP_STANDALONE_OFFSET	0x38
     29#define DICE_EXT_APP_STANDALONE_SIZE	0x3c
     30#define DICE_EXT_APP_APPLICATION_OFFSET	0x40
     31#define DICE_EXT_APP_APPLICATION_SIZE	0x44
     32
     33#define EXT_APP_STREAM_TX_NUMBER	0x0000
     34#define EXT_APP_STREAM_RX_NUMBER	0x0004
     35#define EXT_APP_STREAM_ENTRIES		0x0008
     36#define EXT_APP_STREAM_ENTRY_SIZE	0x010c
     37#define  EXT_APP_NUMBER_AUDIO		0x0000
     38#define  EXT_APP_NUMBER_MIDI		0x0004
     39#define  EXT_APP_NAMES			0x0008
     40#define   EXT_APP_NAMES_SIZE		256
     41#define  EXT_APP_AC3			0x0108
     42
     43#define EXT_APP_CONFIG_LOW_ROUTER	0x0000
     44#define EXT_APP_CONFIG_LOW_STREAM	0x1000
     45#define EXT_APP_CONFIG_MIDDLE_ROUTER	0x2000
     46#define EXT_APP_CONFIG_MIDDLE_STREAM	0x3000
     47#define EXT_APP_CONFIG_HIGH_ROUTER	0x4000
     48#define EXT_APP_CONFIG_HIGH_STREAM	0x5000
     49
     50static inline int read_transaction(struct snd_dice *dice, u64 section_addr,
     51				   u32 offset, void *buf, size_t len)
     52{
     53	return snd_fw_transaction(dice->unit,
     54				  len == 4 ? TCODE_READ_QUADLET_REQUEST :
     55					     TCODE_READ_BLOCK_REQUEST,
     56				  section_addr + offset, buf, len, 0);
     57}
     58
     59static int read_stream_entries(struct snd_dice *dice, u64 section_addr,
     60			       u32 base_offset, unsigned int stream_count,
     61			       unsigned int mode,
     62			       unsigned int pcm_channels[MAX_STREAMS][3],
     63			       unsigned int midi_ports[MAX_STREAMS])
     64{
     65	u32 entry_offset;
     66	__be32 reg[2];
     67	int err;
     68	int i;
     69
     70	for (i = 0; i < stream_count; ++i) {
     71		entry_offset = base_offset + i * EXT_APP_STREAM_ENTRY_SIZE;
     72		err = read_transaction(dice, section_addr,
     73				    entry_offset + EXT_APP_NUMBER_AUDIO,
     74				    reg, sizeof(reg));
     75		if (err < 0)
     76			return err;
     77		pcm_channels[i][mode] = be32_to_cpu(reg[0]);
     78		midi_ports[i] = max(midi_ports[i], be32_to_cpu(reg[1]));
     79	}
     80
     81	return 0;
     82}
     83
     84static int detect_stream_formats(struct snd_dice *dice, u64 section_addr)
     85{
     86	u32 base_offset;
     87	__be32 reg[2];
     88	unsigned int stream_count;
     89	int mode;
     90	int err = 0;
     91
     92	for (mode = 0; mode < SND_DICE_RATE_MODE_COUNT; ++mode) {
     93		unsigned int cap;
     94
     95		/*
     96		 * Some models report stream formats at highest mode, however
     97		 * they don't support the mode. Check clock capabilities.
     98		 */
     99		if (mode == 2) {
    100			cap = CLOCK_CAP_RATE_176400 | CLOCK_CAP_RATE_192000;
    101		} else if (mode == 1) {
    102			cap = CLOCK_CAP_RATE_88200 | CLOCK_CAP_RATE_96000;
    103		} else {
    104			cap = CLOCK_CAP_RATE_32000 | CLOCK_CAP_RATE_44100 |
    105			      CLOCK_CAP_RATE_48000;
    106		}
    107		if (!(cap & dice->clock_caps))
    108			continue;
    109
    110		base_offset = 0x2000 * mode + 0x1000;
    111
    112		err = read_transaction(dice, section_addr,
    113				       base_offset + EXT_APP_STREAM_TX_NUMBER,
    114				       &reg, sizeof(reg));
    115		if (err < 0)
    116			break;
    117
    118		base_offset += EXT_APP_STREAM_ENTRIES;
    119		stream_count = be32_to_cpu(reg[0]);
    120		err = read_stream_entries(dice, section_addr, base_offset,
    121					  stream_count, mode,
    122					  dice->tx_pcm_chs,
    123					  dice->tx_midi_ports);
    124		if (err < 0)
    125			break;
    126
    127		base_offset += stream_count * EXT_APP_STREAM_ENTRY_SIZE;
    128		stream_count = be32_to_cpu(reg[1]);
    129		err = read_stream_entries(dice, section_addr, base_offset,
    130					  stream_count,
    131					  mode, dice->rx_pcm_chs,
    132					  dice->rx_midi_ports);
    133		if (err < 0)
    134			break;
    135	}
    136
    137	return err;
    138}
    139
    140int snd_dice_detect_extension_formats(struct snd_dice *dice)
    141{
    142	__be32 *pointers;
    143	unsigned int i;
    144	u64 section_addr;
    145	int err;
    146
    147	pointers = kmalloc_array(9, sizeof(__be32) * 2, GFP_KERNEL);
    148	if (pointers == NULL)
    149		return -ENOMEM;
    150
    151	err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST,
    152				 DICE_EXT_APP_SPACE, pointers,
    153				 9 * sizeof(__be32) * 2, 0);
    154	if (err < 0)
    155		goto end;
    156
    157	/* Check two of them for offset have the same value or not. */
    158	for (i = 0; i < 9; ++i) {
    159		int j;
    160
    161		for (j = i + 1; j < 9; ++j) {
    162			if (pointers[i * 2] == pointers[j * 2]) {
    163				// Fallback to limited functionality.
    164				err = -ENXIO;
    165				goto end;
    166			}
    167		}
    168	}
    169
    170	section_addr = DICE_EXT_APP_SPACE + be32_to_cpu(pointers[12]) * 4;
    171	err = detect_stream_formats(dice, section_addr);
    172end:
    173	kfree(pointers);
    174	return err;
    175}