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

cs5536_isa.c (8121B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * the ISA Virtual Support Module of AMD CS5536
      4 *
      5 * Copyright (C) 2007 Lemote, Inc.
      6 * Author : jlliu, liujl@lemote.com
      7 *
      8 * Copyright (C) 2009 Lemote, Inc.
      9 * Author: Wu Zhangjin, wuzhangjin@gmail.com
     10 */
     11
     12#include <linux/pci.h>
     13#include <cs5536/cs5536.h>
     14#include <cs5536/cs5536_pci.h>
     15
     16/* common variables for PCI_ISA_READ/WRITE_BAR */
     17static const u32 divil_msr_reg[6] = {
     18	DIVIL_MSR_REG(DIVIL_LBAR_SMB), DIVIL_MSR_REG(DIVIL_LBAR_GPIO),
     19	DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), DIVIL_MSR_REG(DIVIL_LBAR_IRQ),
     20	DIVIL_MSR_REG(DIVIL_LBAR_PMS), DIVIL_MSR_REG(DIVIL_LBAR_ACPI),
     21};
     22
     23static const u32 soft_bar_flag[6] = {
     24	SOFT_BAR_SMB_FLAG, SOFT_BAR_GPIO_FLAG, SOFT_BAR_MFGPT_FLAG,
     25	SOFT_BAR_IRQ_FLAG, SOFT_BAR_PMS_FLAG, SOFT_BAR_ACPI_FLAG,
     26};
     27
     28static const u32 sb_msr_reg[6] = {
     29	SB_MSR_REG(SB_R0), SB_MSR_REG(SB_R1), SB_MSR_REG(SB_R2),
     30	SB_MSR_REG(SB_R3), SB_MSR_REG(SB_R4), SB_MSR_REG(SB_R5),
     31};
     32
     33static const u32 bar_space_range[6] = {
     34	CS5536_SMB_RANGE, CS5536_GPIO_RANGE, CS5536_MFGPT_RANGE,
     35	CS5536_IRQ_RANGE, CS5536_PMS_RANGE, CS5536_ACPI_RANGE,
     36};
     37
     38static const int bar_space_len[6] = {
     39	CS5536_SMB_LENGTH, CS5536_GPIO_LENGTH, CS5536_MFGPT_LENGTH,
     40	CS5536_IRQ_LENGTH, CS5536_PMS_LENGTH, CS5536_ACPI_LENGTH,
     41};
     42
     43/*
     44 * enable the divil module bar space.
     45 *
     46 * For all the DIVIL module LBAR, you should control the DIVIL LBAR reg
     47 * and the RCONFx(0~5) reg to use the modules.
     48 */
     49static void divil_lbar_enable(void)
     50{
     51	u32 hi, lo;
     52	int offset;
     53
     54	/*
     55	 * The DIVIL IRQ is not used yet. and make the RCONF0 reserved.
     56	 */
     57
     58	for (offset = DIVIL_LBAR_SMB; offset <= DIVIL_LBAR_PMS; offset++) {
     59		_rdmsr(DIVIL_MSR_REG(offset), &hi, &lo);
     60		hi |= 0x01;
     61		_wrmsr(DIVIL_MSR_REG(offset), hi, lo);
     62	}
     63}
     64
     65/*
     66 * disable the divil module bar space.
     67 */
     68static void divil_lbar_disable(void)
     69{
     70	u32 hi, lo;
     71	int offset;
     72
     73	for (offset = DIVIL_LBAR_SMB; offset <= DIVIL_LBAR_PMS; offset++) {
     74		_rdmsr(DIVIL_MSR_REG(offset), &hi, &lo);
     75		hi &= ~0x01;
     76		_wrmsr(DIVIL_MSR_REG(offset), hi, lo);
     77	}
     78}
     79
     80/*
     81 * BAR write: write value to the n BAR
     82 */
     83
     84void pci_isa_write_bar(int n, u32 value)
     85{
     86	u32 hi = 0, lo = value;
     87
     88	if (value == PCI_BAR_RANGE_MASK) {
     89		_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
     90		lo |= soft_bar_flag[n];
     91		_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
     92	} else if (value & 0x01) {
     93		/* NATIVE reg */
     94		hi = 0x0000f001;
     95		lo &= bar_space_range[n];
     96		_wrmsr(divil_msr_reg[n], hi, lo);
     97
     98		/* RCONFx is 4bytes in units for I/O space */
     99		hi = ((value & 0x000ffffc) << 12) |
    100		    ((bar_space_len[n] - 4) << 12) | 0x01;
    101		lo = ((value & 0x000ffffc) << 12) | 0x01;
    102		_wrmsr(sb_msr_reg[n], hi, lo);
    103	}
    104}
    105
    106/*
    107 * BAR read: read the n BAR
    108 */
    109
    110u32 pci_isa_read_bar(int n)
    111{
    112	u32 conf_data = 0;
    113	u32 hi, lo;
    114
    115	_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
    116	if (lo & soft_bar_flag[n]) {
    117		conf_data = bar_space_range[n] | PCI_BASE_ADDRESS_SPACE_IO;
    118		lo &= ~soft_bar_flag[n];
    119		_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
    120	} else {
    121		_rdmsr(divil_msr_reg[n], &hi, &lo);
    122		conf_data = lo & bar_space_range[n];
    123		conf_data |= 0x01;
    124		conf_data &= ~0x02;
    125	}
    126	return conf_data;
    127}
    128
    129/*
    130 * isa_write: ISA write transfer
    131 *
    132 * We assume that this is not a bus master transfer.
    133 */
    134void pci_isa_write_reg(int reg, u32 value)
    135{
    136	u32 hi = 0, lo = value;
    137	u32 temp;
    138
    139	switch (reg) {
    140	case PCI_COMMAND:
    141		if (value & PCI_COMMAND_IO)
    142			divil_lbar_enable();
    143		else
    144			divil_lbar_disable();
    145		break;
    146	case PCI_STATUS:
    147		_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
    148		temp = lo & 0x0000ffff;
    149		if ((value & PCI_STATUS_SIG_TARGET_ABORT) &&
    150		    (lo & SB_TAS_ERR_EN))
    151			temp |= SB_TAS_ERR_FLAG;
    152
    153		if ((value & PCI_STATUS_REC_TARGET_ABORT) &&
    154		    (lo & SB_TAR_ERR_EN))
    155			temp |= SB_TAR_ERR_FLAG;
    156
    157		if ((value & PCI_STATUS_REC_MASTER_ABORT)
    158		    && (lo & SB_MAR_ERR_EN))
    159			temp |= SB_MAR_ERR_FLAG;
    160
    161		if ((value & PCI_STATUS_DETECTED_PARITY)
    162		    && (lo & SB_PARE_ERR_EN))
    163			temp |= SB_PARE_ERR_FLAG;
    164
    165		lo = temp;
    166		_wrmsr(SB_MSR_REG(SB_ERROR), hi, lo);
    167		break;
    168	case PCI_CACHE_LINE_SIZE:
    169		value &= 0x0000ff00;
    170		_rdmsr(SB_MSR_REG(SB_CTRL), &hi, &lo);
    171		hi &= 0xffffff00;
    172		hi |= (value >> 8);
    173		_wrmsr(SB_MSR_REG(SB_CTRL), hi, lo);
    174		break;
    175	case PCI_BAR0_REG:
    176		pci_isa_write_bar(0, value);
    177		break;
    178	case PCI_BAR1_REG:
    179		pci_isa_write_bar(1, value);
    180		break;
    181	case PCI_BAR2_REG:
    182		pci_isa_write_bar(2, value);
    183		break;
    184	case PCI_BAR3_REG:
    185		pci_isa_write_bar(3, value);
    186		break;
    187	case PCI_BAR4_REG:
    188		pci_isa_write_bar(4, value);
    189		break;
    190	case PCI_BAR5_REG:
    191		pci_isa_write_bar(5, value);
    192		break;
    193	case PCI_UART1_INT_REG:
    194		_rdmsr(DIVIL_MSR_REG(PIC_YSEL_HIGH), &hi, &lo);
    195		/* disable uart1 interrupt in PIC */
    196		lo &= ~(0xf << 24);
    197		if (value)	/* enable uart1 interrupt in PIC */
    198			lo |= (CS5536_UART1_INTR << 24);
    199		_wrmsr(DIVIL_MSR_REG(PIC_YSEL_HIGH), hi, lo);
    200		break;
    201	case PCI_UART2_INT_REG:
    202		_rdmsr(DIVIL_MSR_REG(PIC_YSEL_HIGH), &hi, &lo);
    203		/* disable uart2 interrupt in PIC */
    204		lo &= ~(0xf << 28);
    205		if (value)	/* enable uart2 interrupt in PIC */
    206			lo |= (CS5536_UART2_INTR << 28);
    207		_wrmsr(DIVIL_MSR_REG(PIC_YSEL_HIGH), hi, lo);
    208		break;
    209	case PCI_ISA_FIXUP_REG:
    210		if (value) {
    211			/* enable the TARGET ABORT/MASTER ABORT etc. */
    212			_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
    213			lo |= 0x00000063;
    214			_wrmsr(SB_MSR_REG(SB_ERROR), hi, lo);
    215		}
    216
    217	default:
    218		/* ALL OTHER PCI CONFIG SPACE HEADER IS NOT IMPLEMENTED. */
    219		break;
    220	}
    221}
    222
    223/*
    224 * isa_read: ISA read transfers
    225 *
    226 * We assume that this is not a bus master transfer.
    227 */
    228u32 pci_isa_read_reg(int reg)
    229{
    230	u32 conf_data = 0;
    231	u32 hi, lo;
    232
    233	switch (reg) {
    234	case PCI_VENDOR_ID:
    235		conf_data =
    236		    CFG_PCI_VENDOR_ID(CS5536_ISA_DEVICE_ID, CS5536_VENDOR_ID);
    237		break;
    238	case PCI_COMMAND:
    239		/* we just check the first LBAR for the IO enable bit, */
    240		/* maybe we should changed later. */
    241		_rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_SMB), &hi, &lo);
    242		if (hi & 0x01)
    243			conf_data |= PCI_COMMAND_IO;
    244		break;
    245	case PCI_STATUS:
    246		conf_data |= PCI_STATUS_66MHZ;
    247		conf_data |= PCI_STATUS_DEVSEL_MEDIUM;
    248		conf_data |= PCI_STATUS_FAST_BACK;
    249
    250		_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
    251		if (lo & SB_TAS_ERR_FLAG)
    252			conf_data |= PCI_STATUS_SIG_TARGET_ABORT;
    253		if (lo & SB_TAR_ERR_FLAG)
    254			conf_data |= PCI_STATUS_REC_TARGET_ABORT;
    255		if (lo & SB_MAR_ERR_FLAG)
    256			conf_data |= PCI_STATUS_REC_MASTER_ABORT;
    257		if (lo & SB_PARE_ERR_FLAG)
    258			conf_data |= PCI_STATUS_DETECTED_PARITY;
    259		break;
    260	case PCI_CLASS_REVISION:
    261		_rdmsr(GLCP_MSR_REG(GLCP_CHIP_REV_ID), &hi, &lo);
    262		conf_data = lo & 0x000000ff;
    263		conf_data |= (CS5536_ISA_CLASS_CODE << 8);
    264		break;
    265	case PCI_CACHE_LINE_SIZE:
    266		_rdmsr(SB_MSR_REG(SB_CTRL), &hi, &lo);
    267		hi &= 0x000000f8;
    268		conf_data = CFG_PCI_CACHE_LINE_SIZE(PCI_BRIDGE_HEADER_TYPE, hi);
    269		break;
    270		/*
    271		 * we only use the LBAR of DIVIL, no RCONF used.
    272		 * all of them are IO space.
    273		 */
    274	case PCI_BAR0_REG:
    275		return pci_isa_read_bar(0);
    276		break;
    277	case PCI_BAR1_REG:
    278		return pci_isa_read_bar(1);
    279		break;
    280	case PCI_BAR2_REG:
    281		return pci_isa_read_bar(2);
    282		break;
    283	case PCI_BAR3_REG:
    284		break;
    285	case PCI_BAR4_REG:
    286		return pci_isa_read_bar(4);
    287		break;
    288	case PCI_BAR5_REG:
    289		return pci_isa_read_bar(5);
    290		break;
    291	case PCI_CARDBUS_CIS:
    292		conf_data = PCI_CARDBUS_CIS_POINTER;
    293		break;
    294	case PCI_SUBSYSTEM_VENDOR_ID:
    295		conf_data =
    296		    CFG_PCI_VENDOR_ID(CS5536_ISA_SUB_ID, CS5536_SUB_VENDOR_ID);
    297		break;
    298	case PCI_ROM_ADDRESS:
    299		conf_data = PCI_EXPANSION_ROM_BAR;
    300		break;
    301	case PCI_CAPABILITY_LIST:
    302		conf_data = PCI_CAPLIST_POINTER;
    303		break;
    304	case PCI_INTERRUPT_LINE:
    305		/* no interrupt used here */
    306		conf_data = CFG_PCI_INTERRUPT_LINE(0x00, 0x00);
    307		break;
    308	default:
    309		break;
    310	}
    311
    312	return conf_data;
    313}
    314
    315/*
    316 * The mfgpt timer interrupt is running early, so we must keep the south bridge
    317 * mmio always enabled. Otherwise we may race with the PCI configuration which
    318 * may temporarily disable it. When that happens and the timer interrupt fires,
    319 * we are not able to clear it and the system will hang.
    320 */
    321static void cs5536_isa_mmio_always_on(struct pci_dev *dev)
    322{
    323	dev->mmio_always_on = 1;
    324}
    325DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA,
    326	PCI_CLASS_BRIDGE_ISA, 8, cs5536_isa_mmio_always_on);