~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/powerpc/sysdev/indirect_pci.c

Version: ~ [ linux-5.8-rc4 ] ~ [ linux-5.7.7 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.50 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.131 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.187 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.229 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.229 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.85 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp