linux/arch/sh/drivers/pci/common.c
<<
>>
Prefs
   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        printk(KERN_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                printk("\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                printk("\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}
 160