root/arch/powerpc/sysdev/indirect_pci.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. __indirect_read_config
  2. indirect_read_config
  3. indirect_write_config
  4. setup_indirect_pci

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Support for indirect PCI bridges.
   4  *
   5  * Copyright (C) 1998 Gabriel Paubert.
   6  */
   7 
   8 #include <linux/kernel.h>
   9 #include <linux/pci.h>
  10 #include <linux/delay.h>
  11 #include <linux/string.h>
  12 #include <linux/init.h>
  13 
  14 #include <asm/io.h>
  15 #include <asm/prom.h>
  16 #include <asm/pci-bridge.h>
  17 #include <asm/machdep.h>
  18 
  19 int __indirect_read_config(struct pci_controller *hose,
  20                            unsigned char bus_number, unsigned int devfn,
  21                            int offset, int len, u32 *val)
  22 {
  23         volatile void __iomem *cfg_data;
  24         u8 cfg_type = 0;
  25         u32 bus_no, reg;
  26 
  27         if (hose->indirect_type & PPC_INDIRECT_TYPE_NO_PCIE_LINK) {
  28                 if (bus_number != hose->first_busno)
  29                         return PCIBIOS_DEVICE_NOT_FOUND;
  30                 if (devfn != 0)
  31                         return PCIBIOS_DEVICE_NOT_FOUND;
  32         }
  33 
  34         if (ppc_md.pci_exclude_device)
  35                 if (ppc_md.pci_exclude_device(hose, bus_number, devfn))
  36                         return PCIBIOS_DEVICE_NOT_FOUND;
  37 
  38         if (hose->indirect_type & PPC_INDIRECT_TYPE_SET_CFG_TYPE)
  39                 if (bus_number != hose->first_busno)
  40                         cfg_type = 1;
  41 
  42         bus_no = (bus_number == hose->first_busno) ?
  43                         hose->self_busno : bus_number;
  44 
  45         if (hose->indirect_type & PPC_INDIRECT_TYPE_EXT_REG)
  46                 reg = ((offset & 0xf00) << 16) | (offset & 0xfc);
  47         else
  48                 reg = offset & 0xfc;
  49 
  50         if (hose->indirect_type & PPC_INDIRECT_TYPE_BIG_ENDIAN)
  51                 out_be32(hose->cfg_addr, (0x80000000 | (bus_no << 16) |
  52                          (devfn << 8) | reg | cfg_type));
  53         else
  54                 out_le32(hose->cfg_addr, (0x80000000 | (bus_no << 16) |
  55                          (devfn << 8) | reg | cfg_type));
  56 
  57         /*
  58          * Note: the caller has already checked that offset is
  59          * suitably aligned and that len is 1, 2 or 4.
  60          */
  61         cfg_data = hose->cfg_data + (offset & 3);
  62         switch (len) {
  63         case 1:
  64                 *val = in_8(cfg_data);
  65                 break;
  66         case 2:
  67                 *val = in_le16(cfg_data);
  68                 break;
  69         default:
  70                 *val = in_le32(cfg_data);
  71                 break;
  72         }
  73         return PCIBIOS_SUCCESSFUL;
  74 }
  75 
  76 int indirect_read_config(struct pci_bus *bus, unsigned int devfn,
  77                          int offset, int len, u32 *val)
  78 {
  79         struct pci_controller *hose = pci_bus_to_host(bus);
  80 
  81         return __indirect_read_config(hose, bus->number, devfn, offset, len,
  82                                       val);
  83 }
  84 
  85 int indirect_write_config(struct pci_bus *bus, unsigned int devfn,
  86                           int offset, int len, u32 val)
  87 {
  88         struct pci_controller *hose = pci_bus_to_host(bus);
  89         volatile void __iomem *cfg_data;
  90         u8 cfg_type = 0;
  91         u32 bus_no, reg;
  92 
  93         if (hose->indirect_type & PPC_INDIRECT_TYPE_NO_PCIE_LINK) {
  94                 if (bus->number != hose->first_busno)
  95                         return PCIBIOS_DEVICE_NOT_FOUND;
  96                 if (devfn != 0)
  97                         return PCIBIOS_DEVICE_NOT_FOUND;
  98         }
  99 
 100         if (ppc_md.pci_exclude_device)
 101                 if (ppc_md.pci_exclude_device(hose, bus->number, devfn))
 102                         return PCIBIOS_DEVICE_NOT_FOUND;
 103 
 104         if (hose->indirect_type & PPC_INDIRECT_TYPE_SET_CFG_TYPE)
 105                 if (bus->number != hose->first_busno)
 106                         cfg_type = 1;
 107 
 108         bus_no = (bus->number == hose->first_busno) ?
 109                         hose->self_busno : bus->number;
 110 
 111         if (hose->indirect_type & PPC_INDIRECT_TYPE_EXT_REG)
 112                 reg = ((offset & 0xf00) << 16) | (offset & 0xfc);
 113         else
 114                 reg = offset & 0xfc;
 115 
 116         if (hose->indirect_type & PPC_INDIRECT_TYPE_BIG_ENDIAN)
 117                 out_be32(hose->cfg_addr, (0x80000000 | (bus_no << 16) |
 118                          (devfn << 8) | reg | cfg_type));
 119         else
 120                 out_le32(hose->cfg_addr, (0x80000000 | (bus_no << 16) |
 121                          (devfn << 8) | reg | cfg_type));
 122 
 123         /* suppress setting of PCI_PRIMARY_BUS */
 124         if (hose->indirect_type & PPC_INDIRECT_TYPE_SURPRESS_PRIMARY_BUS)
 125                 if ((offset == PCI_PRIMARY_BUS) &&
 126                         (bus->number == hose->first_busno))
 127                 val &= 0xffffff00;
 128 
 129         /* Workaround for PCI_28 Errata in 440EPx/GRx */
 130         if ((hose->indirect_type & PPC_INDIRECT_TYPE_BROKEN_MRM) &&
 131                         offset == PCI_CACHE_LINE_SIZE) {
 132                 val = 0;
 133         }
 134 
 135         /*
 136          * Note: the caller has already checked that offset is
 137          * suitably aligned and that len is 1, 2 or 4.
 138          */
 139         cfg_data = hose->cfg_data + (offset & 3);
 140         switch (len) {
 141         case 1:
 142                 out_8(cfg_data, val);
 143                 break;
 144         case 2:
 145                 out_le16(cfg_data, val);
 146                 break;
 147         default:
 148                 out_le32(cfg_data, val);
 149                 break;
 150         }
 151         return PCIBIOS_SUCCESSFUL;
 152 }
 153 
 154 static struct pci_ops indirect_pci_ops =
 155 {
 156         .read = indirect_read_config,
 157         .write = indirect_write_config,
 158 };
 159 
 160 void setup_indirect_pci(struct pci_controller *hose, resource_size_t cfg_addr,
 161                         resource_size_t cfg_data, u32 flags)
 162 {
 163         resource_size_t base = cfg_addr & PAGE_MASK;
 164         void __iomem *mbase;
 165 
 166         mbase = ioremap(base, PAGE_SIZE);
 167         hose->cfg_addr = mbase + (cfg_addr & ~PAGE_MASK);
 168         if ((cfg_data & PAGE_MASK) != base)
 169                 mbase = ioremap(cfg_data & PAGE_MASK, PAGE_SIZE);
 170         hose->cfg_data = mbase + (cfg_data & ~PAGE_MASK);
 171         hose->ops = &indirect_pci_ops;
 172         hose->indirect_type = flags;
 173 }

/* [<][>][^][v][top][bottom][index][help] */