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

common.c (3886B)


      1// SPDX-License-Identifier: GPL-2.0
      2#include <linux/pci.h>
      3#include <linux/interrupt.h>
      4#include <linux/timer.h>
      5#include <linux/kernel.h>
      6
      7/*
      8 * These functions are used early on before PCI scanning is done
      9 * and all of the pci_dev and pci_bus structures have been created.
     10 */
     11static struct pci_dev *fake_pci_dev(struct pci_channel *hose,
     12	int top_bus, int busnr, int devfn)
     13{
     14	static struct pci_dev dev;
     15	static struct pci_bus bus;
     16
     17	dev.bus = &bus;
     18	dev.sysdata = hose;
     19	dev.devfn = devfn;
     20	bus.number = busnr;
     21	bus.sysdata = hose;
     22	bus.ops = hose->pci_ops;
     23
     24	if(busnr != top_bus)
     25		/* Fake a parent bus structure. */
     26		bus.parent = &bus;
     27	else
     28		bus.parent = NULL;
     29
     30	return &dev;
     31}
     32
     33#define EARLY_PCI_OP(rw, size, type)					\
     34int __init early_##rw##_config_##size(struct pci_channel *hose,		\
     35	int top_bus, int bus, int devfn, int offset, type value)	\
     36{									\
     37	return pci_##rw##_config_##size(				\
     38		fake_pci_dev(hose, top_bus, bus, devfn),		\
     39		offset, value);						\
     40}
     41
     42EARLY_PCI_OP(read, byte, u8 *)
     43EARLY_PCI_OP(read, word, u16 *)
     44EARLY_PCI_OP(read, dword, u32 *)
     45EARLY_PCI_OP(write, byte, u8)
     46EARLY_PCI_OP(write, word, u16)
     47EARLY_PCI_OP(write, dword, u32)
     48
     49int __init pci_is_66mhz_capable(struct pci_channel *hose,
     50				int top_bus, int current_bus)
     51{
     52	u32 pci_devfn;
     53	unsigned short vid;
     54	int cap66 = -1;
     55	u16 stat;
     56
     57	pr_info("PCI: Checking 66MHz capabilities...\n");
     58
     59	for (pci_devfn = 0; pci_devfn < 0xff; pci_devfn++) {
     60		if (PCI_FUNC(pci_devfn))
     61			continue;
     62		if (early_read_config_word(hose, top_bus, current_bus,
     63					   pci_devfn, PCI_VENDOR_ID, &vid) !=
     64		    PCIBIOS_SUCCESSFUL)
     65			continue;
     66		if (vid == 0xffff)
     67			continue;
     68
     69		/* check 66MHz capability */
     70		if (cap66 < 0)
     71			cap66 = 1;
     72		if (cap66) {
     73			early_read_config_word(hose, top_bus, current_bus,
     74					       pci_devfn, PCI_STATUS, &stat);
     75			if (!(stat & PCI_STATUS_66MHZ)) {
     76				printk(KERN_DEBUG
     77				       "PCI: %02x:%02x not 66MHz capable.\n",
     78				       current_bus, pci_devfn);
     79				cap66 = 0;
     80				break;
     81			}
     82		}
     83	}
     84
     85	return cap66 > 0;
     86}
     87
     88static void pcibios_enable_err(struct timer_list *t)
     89{
     90	struct pci_channel *hose = from_timer(hose, t, err_timer);
     91
     92	del_timer(&hose->err_timer);
     93	printk(KERN_DEBUG "PCI: re-enabling error IRQ.\n");
     94	enable_irq(hose->err_irq);
     95}
     96
     97static void pcibios_enable_serr(struct timer_list *t)
     98{
     99	struct pci_channel *hose = from_timer(hose, t, serr_timer);
    100
    101	del_timer(&hose->serr_timer);
    102	printk(KERN_DEBUG "PCI: re-enabling system error IRQ.\n");
    103	enable_irq(hose->serr_irq);
    104}
    105
    106void pcibios_enable_timers(struct pci_channel *hose)
    107{
    108	if (hose->err_irq) {
    109		timer_setup(&hose->err_timer, pcibios_enable_err, 0);
    110	}
    111
    112	if (hose->serr_irq) {
    113		timer_setup(&hose->serr_timer, pcibios_enable_serr, 0);
    114	}
    115}
    116
    117/*
    118 * A simple handler for the regular PCI status errors, called from IRQ
    119 * context.
    120 */
    121unsigned int pcibios_handle_status_errors(unsigned long addr,
    122					  unsigned int status,
    123					  struct pci_channel *hose)
    124{
    125	unsigned int cmd = 0;
    126
    127	if (status & PCI_STATUS_REC_MASTER_ABORT) {
    128		printk(KERN_DEBUG "PCI: master abort, pc=0x%08lx\n", addr);
    129		cmd |= PCI_STATUS_REC_MASTER_ABORT;
    130	}
    131
    132	if (status & PCI_STATUS_REC_TARGET_ABORT) {
    133		printk(KERN_DEBUG "PCI: target abort: ");
    134		pcibios_report_status(PCI_STATUS_REC_TARGET_ABORT |
    135				      PCI_STATUS_SIG_TARGET_ABORT |
    136				      PCI_STATUS_REC_MASTER_ABORT, 1);
    137		pr_cont("\n");
    138
    139		cmd |= PCI_STATUS_REC_TARGET_ABORT;
    140	}
    141
    142	if (status & (PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY)) {
    143		printk(KERN_DEBUG "PCI: parity error detected: ");
    144		pcibios_report_status(PCI_STATUS_PARITY |
    145				      PCI_STATUS_DETECTED_PARITY, 1);
    146		pr_cont("\n");
    147
    148		cmd |= PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY;
    149
    150		/* Now back off of the IRQ for awhile */
    151		if (hose->err_irq) {
    152			disable_irq_nosync(hose->err_irq);
    153			hose->err_timer.expires = jiffies + HZ;
    154			add_timer(&hose->err_timer);
    155		}
    156	}
    157
    158	return cmd;
    159}