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

ops-sni.c (3717B)


      1/*
      2 * This file is subject to the terms and conditions of the GNU General Public
      3 * License.  See the file "COPYING" in the main directory of this archive
      4 * for more details.
      5 *
      6 * SNI specific PCI support for RM200/RM300.
      7 *
      8 * Copyright (C) 1997 - 2000, 2003 Ralf Baechle <ralf@linux-mips.org>
      9 */
     10#include <linux/kernel.h>
     11#include <linux/pci.h>
     12#include <linux/types.h>
     13#include <asm/sni.h>
     14
     15/*
     16 * It seems that on the RM200 only lower 3 bits of the 5 bit PCI device
     17 * address are decoded.	 We therefore manually have to reject attempts at
     18 * reading outside this range.	Being on the paranoid side we only do this
     19 * test for bus 0 and hope forwarding and decoding work properly for any
     20 * subordinated busses.
     21 *
     22 * ASIC PCI only supports type 1 config cycles.
     23 */
     24static int set_config_address(unsigned int busno, unsigned int devfn, int reg)
     25{
     26	if ((devfn > 255) || (reg > 255))
     27		return PCIBIOS_BAD_REGISTER_NUMBER;
     28
     29	if (busno == 0 && devfn >= PCI_DEVFN(8, 0))
     30		return PCIBIOS_DEVICE_NOT_FOUND;
     31
     32	*(volatile u32 *)PCIMT_CONFIG_ADDRESS =
     33		 ((busno    & 0xff) << 16) |
     34		 ((devfn    & 0xff) <<	8) |
     35		  (reg	    & 0xfc);
     36
     37	return PCIBIOS_SUCCESSFUL;
     38}
     39
     40static int pcimt_read(struct pci_bus *bus, unsigned int devfn, int reg,
     41		      int size, u32 * val)
     42{
     43	int res;
     44
     45	if ((res = set_config_address(bus->number, devfn, reg)))
     46		return res;
     47
     48	switch (size) {
     49	case 1:
     50		*val = inb(PCIMT_CONFIG_DATA + (reg & 3));
     51		break;
     52	case 2:
     53		*val = inw(PCIMT_CONFIG_DATA + (reg & 2));
     54		break;
     55	case 4:
     56		*val = inl(PCIMT_CONFIG_DATA);
     57		break;
     58	}
     59
     60	return 0;
     61}
     62
     63static int pcimt_write(struct pci_bus *bus, unsigned int devfn, int reg,
     64		       int size, u32 val)
     65{
     66	int res;
     67
     68	if ((res = set_config_address(bus->number, devfn, reg)))
     69		return res;
     70
     71	switch (size) {
     72	case 1:
     73		outb(val, PCIMT_CONFIG_DATA + (reg & 3));
     74		break;
     75	case 2:
     76		outw(val, PCIMT_CONFIG_DATA + (reg & 2));
     77		break;
     78	case 4:
     79		outl(val, PCIMT_CONFIG_DATA);
     80		break;
     81	}
     82
     83	return 0;
     84}
     85
     86struct pci_ops sni_pcimt_ops = {
     87	.read = pcimt_read,
     88	.write = pcimt_write,
     89};
     90
     91static int pcit_set_config_address(unsigned int busno, unsigned int devfn, int reg)
     92{
     93	if ((devfn > 255) || (reg > 255) || (busno > 255))
     94		return PCIBIOS_BAD_REGISTER_NUMBER;
     95
     96	outl((1 << 31) | ((busno & 0xff) << 16) | ((devfn & 0xff) << 8) | (reg & 0xfc), 0xcf8);
     97	return PCIBIOS_SUCCESSFUL;
     98}
     99
    100static int pcit_read(struct pci_bus *bus, unsigned int devfn, int reg,
    101		      int size, u32 * val)
    102{
    103	int res;
    104
    105	/*
    106	 * on bus 0 we need to check, whether there is a device answering
    107	 * for the devfn by doing a config write and checking the result. If
    108	 * we don't do it, we will get a data bus error
    109	 */
    110	if (bus->number == 0) {
    111		pcit_set_config_address(0, 0, 0x68);
    112		outl(inl(0xcfc) | 0xc0000000, 0xcfc);
    113		if ((res = pcit_set_config_address(0, devfn, 0)))
    114			return res;
    115		outl(0xffffffff, 0xcfc);
    116		pcit_set_config_address(0, 0, 0x68);
    117		if (inl(0xcfc) & 0x100000)
    118			return PCIBIOS_DEVICE_NOT_FOUND;
    119	}
    120	if ((res = pcit_set_config_address(bus->number, devfn, reg)))
    121		return res;
    122
    123	switch (size) {
    124	case 1:
    125		*val = inb(PCIMT_CONFIG_DATA + (reg & 3));
    126		break;
    127	case 2:
    128		*val = inw(PCIMT_CONFIG_DATA + (reg & 2));
    129		break;
    130	case 4:
    131		*val = inl(PCIMT_CONFIG_DATA);
    132		break;
    133	}
    134	return 0;
    135}
    136
    137static int pcit_write(struct pci_bus *bus, unsigned int devfn, int reg,
    138		       int size, u32 val)
    139{
    140	int res;
    141
    142	if ((res = pcit_set_config_address(bus->number, devfn, reg)))
    143		return res;
    144
    145	switch (size) {
    146	case 1:
    147		outb(val, PCIMT_CONFIG_DATA + (reg & 3));
    148		break;
    149	case 2:
    150		outw(val, PCIMT_CONFIG_DATA + (reg & 2));
    151		break;
    152	case 4:
    153		outl(val, PCIMT_CONFIG_DATA);
    154		break;
    155	}
    156
    157	return 0;
    158}
    159
    160
    161struct pci_ops sni_pcit_ops = {
    162	.read = pcit_read,
    163	.write = pcit_write,
    164};