root/drivers/pci/controller/pci-thunder-ecam.c

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

DEFINITIONS

This source file includes following definitions.
  1. set_val
  2. handle_ea_bar
  3. thunder_ecam_p2_config_read
  4. thunder_ecam_config_read
  5. thunder_ecam_config_write
  6. thunder_ecam_probe

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Copyright (C) 2015, 2016 Cavium, Inc.
   4  */
   5 
   6 #include <linux/kernel.h>
   7 #include <linux/init.h>
   8 #include <linux/ioport.h>
   9 #include <linux/of_pci.h>
  10 #include <linux/of.h>
  11 #include <linux/pci-ecam.h>
  12 #include <linux/platform_device.h>
  13 
  14 #if defined(CONFIG_PCI_HOST_THUNDER_ECAM) || (defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS))
  15 
  16 static void set_val(u32 v, int where, int size, u32 *val)
  17 {
  18         int shift = (where & 3) * 8;
  19 
  20         pr_debug("set_val %04x: %08x\n", (unsigned)(where & ~3), v);
  21         v >>= shift;
  22         if (size == 1)
  23                 v &= 0xff;
  24         else if (size == 2)
  25                 v &= 0xffff;
  26         *val = v;
  27 }
  28 
  29 static int handle_ea_bar(u32 e0, int bar, struct pci_bus *bus,
  30                          unsigned int devfn, int where, int size, u32 *val)
  31 {
  32         void __iomem *addr;
  33         u32 v;
  34 
  35         /* Entries are 16-byte aligned; bits[2,3] select word in entry */
  36         int where_a = where & 0xc;
  37 
  38         if (where_a == 0) {
  39                 set_val(e0, where, size, val);
  40                 return PCIBIOS_SUCCESSFUL;
  41         }
  42         if (where_a == 0x4) {
  43                 addr = bus->ops->map_bus(bus, devfn, bar); /* BAR 0 */
  44                 if (!addr) {
  45                         *val = ~0;
  46                         return PCIBIOS_DEVICE_NOT_FOUND;
  47                 }
  48                 v = readl(addr);
  49                 v &= ~0xf;
  50                 v |= 2; /* EA entry-1. Base-L */
  51                 set_val(v, where, size, val);
  52                 return PCIBIOS_SUCCESSFUL;
  53         }
  54         if (where_a == 0x8) {
  55                 u32 barl_orig;
  56                 u32 barl_rb;
  57 
  58                 addr = bus->ops->map_bus(bus, devfn, bar); /* BAR 0 */
  59                 if (!addr) {
  60                         *val = ~0;
  61                         return PCIBIOS_DEVICE_NOT_FOUND;
  62                 }
  63                 barl_orig = readl(addr + 0);
  64                 writel(0xffffffff, addr + 0);
  65                 barl_rb = readl(addr + 0);
  66                 writel(barl_orig, addr + 0);
  67                 /* zeros in unsettable bits */
  68                 v = ~barl_rb & ~3;
  69                 v |= 0xc; /* EA entry-2. Offset-L */
  70                 set_val(v, where, size, val);
  71                 return PCIBIOS_SUCCESSFUL;
  72         }
  73         if (where_a == 0xc) {
  74                 addr = bus->ops->map_bus(bus, devfn, bar + 4); /* BAR 1 */
  75                 if (!addr) {
  76                         *val = ~0;
  77                         return PCIBIOS_DEVICE_NOT_FOUND;
  78                 }
  79                 v = readl(addr); /* EA entry-3. Base-H */
  80                 set_val(v, where, size, val);
  81                 return PCIBIOS_SUCCESSFUL;
  82         }
  83         return PCIBIOS_DEVICE_NOT_FOUND;
  84 }
  85 
  86 static int thunder_ecam_p2_config_read(struct pci_bus *bus, unsigned int devfn,
  87                                        int where, int size, u32 *val)
  88 {
  89         struct pci_config_window *cfg = bus->sysdata;
  90         int where_a = where & ~3;
  91         void __iomem *addr;
  92         u32 node_bits;
  93         u32 v;
  94 
  95         /* EA Base[63:32] may be missing some bits ... */
  96         switch (where_a) {
  97         case 0xa8:
  98         case 0xbc:
  99         case 0xd0:
 100         case 0xe4:
 101                 break;
 102         default:
 103                 return pci_generic_config_read(bus, devfn, where, size, val);
 104         }
 105 
 106         addr = bus->ops->map_bus(bus, devfn, where_a);
 107         if (!addr) {
 108                 *val = ~0;
 109                 return PCIBIOS_DEVICE_NOT_FOUND;
 110         }
 111 
 112         v = readl(addr);
 113 
 114         /*
 115          * Bit 44 of the 64-bit Base must match the same bit in
 116          * the config space access window.  Since we are working with
 117          * the high-order 32 bits, shift everything down by 32 bits.
 118          */
 119         node_bits = (cfg->res.start >> 32) & (1 << 12);
 120 
 121         v |= node_bits;
 122         set_val(v, where, size, val);
 123 
 124         return PCIBIOS_SUCCESSFUL;
 125 }
 126 
 127 static int thunder_ecam_config_read(struct pci_bus *bus, unsigned int devfn,
 128                                     int where, int size, u32 *val)
 129 {
 130         u32 v;
 131         u32 vendor_device;
 132         u32 class_rev;
 133         void __iomem *addr;
 134         int cfg_type;
 135         int where_a = where & ~3;
 136 
 137         addr = bus->ops->map_bus(bus, devfn, 0xc);
 138         if (!addr) {
 139                 *val = ~0;
 140                 return PCIBIOS_DEVICE_NOT_FOUND;
 141         }
 142 
 143         v = readl(addr);
 144 
 145         /* Check for non type-00 header */
 146         cfg_type = (v >> 16) & 0x7f;
 147 
 148         addr = bus->ops->map_bus(bus, devfn, 8);
 149         if (!addr) {
 150                 *val = ~0;
 151                 return PCIBIOS_DEVICE_NOT_FOUND;
 152         }
 153 
 154         class_rev = readl(addr);
 155         if (class_rev == 0xffffffff)
 156                 goto no_emulation;
 157 
 158         if ((class_rev & 0xff) >= 8) {
 159                 /* Pass-2 handling */
 160                 if (cfg_type)
 161                         goto no_emulation;
 162                 return thunder_ecam_p2_config_read(bus, devfn, where,
 163                                                    size, val);
 164         }
 165 
 166         /*
 167          * All BARs have fixed addresses specified by the EA
 168          * capability; they must return zero on read.
 169          */
 170         if (cfg_type == 0 &&
 171             ((where >= 0x10 && where < 0x2c) ||
 172              (where >= 0x1a4 && where < 0x1bc))) {
 173                 /* BAR or SR-IOV BAR */
 174                 *val = 0;
 175                 return PCIBIOS_SUCCESSFUL;
 176         }
 177 
 178         addr = bus->ops->map_bus(bus, devfn, 0);
 179         if (!addr) {
 180                 *val = ~0;
 181                 return PCIBIOS_DEVICE_NOT_FOUND;
 182         }
 183 
 184         vendor_device = readl(addr);
 185         if (vendor_device == 0xffffffff)
 186                 goto no_emulation;
 187 
 188         pr_debug("%04x:%04x - Fix pass#: %08x, where: %03x, devfn: %03x\n",
 189                  vendor_device & 0xffff, vendor_device >> 16, class_rev,
 190                  (unsigned) where, devfn);
 191 
 192         /* Check for non type-00 header */
 193         if (cfg_type == 0) {
 194                 bool has_msix;
 195                 bool is_nic = (vendor_device == 0xa01e177d);
 196                 bool is_tns = (vendor_device == 0xa01f177d);
 197 
 198                 addr = bus->ops->map_bus(bus, devfn, 0x70);
 199                 if (!addr) {
 200                         *val = ~0;
 201                         return PCIBIOS_DEVICE_NOT_FOUND;
 202                 }
 203                 /* E_CAP */
 204                 v = readl(addr);
 205                 has_msix = (v & 0xff00) != 0;
 206 
 207                 if (!has_msix && where_a == 0x70) {
 208                         v |= 0xbc00; /* next capability is EA at 0xbc */
 209                         set_val(v, where, size, val);
 210                         return PCIBIOS_SUCCESSFUL;
 211                 }
 212                 if (where_a == 0xb0) {
 213                         addr = bus->ops->map_bus(bus, devfn, where_a);
 214                         if (!addr) {
 215                                 *val = ~0;
 216                                 return PCIBIOS_DEVICE_NOT_FOUND;
 217                         }
 218                         v = readl(addr);
 219                         if (v & 0xff00)
 220                                 pr_err("Bad MSIX cap header: %08x\n", v);
 221                         v |= 0xbc00; /* next capability is EA at 0xbc */
 222                         set_val(v, where, size, val);
 223                         return PCIBIOS_SUCCESSFUL;
 224                 }
 225                 if (where_a == 0xbc) {
 226                         if (is_nic)
 227                                 v = 0x40014; /* EA last in chain, 4 entries */
 228                         else if (is_tns)
 229                                 v = 0x30014; /* EA last in chain, 3 entries */
 230                         else if (has_msix)
 231                                 v = 0x20014; /* EA last in chain, 2 entries */
 232                         else
 233                                 v = 0x10014; /* EA last in chain, 1 entry */
 234                         set_val(v, where, size, val);
 235                         return PCIBIOS_SUCCESSFUL;
 236                 }
 237                 if (where_a >= 0xc0 && where_a < 0xd0)
 238                         /* EA entry-0. PP=0, BAR0 Size:3 */
 239                         return handle_ea_bar(0x80ff0003,
 240                                              0x10, bus, devfn, where,
 241                                              size, val);
 242                 if (where_a >= 0xd0 && where_a < 0xe0 && has_msix)
 243                          /* EA entry-1. PP=0, BAR4 Size:3 */
 244                         return handle_ea_bar(0x80ff0043,
 245                                              0x20, bus, devfn, where,
 246                                              size, val);
 247                 if (where_a >= 0xe0 && where_a < 0xf0 && is_tns)
 248                         /* EA entry-2. PP=0, BAR2, Size:3 */
 249                         return handle_ea_bar(0x80ff0023,
 250                                              0x18, bus, devfn, where,
 251                                              size, val);
 252                 if (where_a >= 0xe0 && where_a < 0xf0 && is_nic)
 253                         /* EA entry-2. PP=4, VF_BAR0 (9), Size:3 */
 254                         return handle_ea_bar(0x80ff0493,
 255                                              0x1a4, bus, devfn, where,
 256                                              size, val);
 257                 if (where_a >= 0xf0 && where_a < 0x100 && is_nic)
 258                         /* EA entry-3. PP=4, VF_BAR4 (d), Size:3 */
 259                         return handle_ea_bar(0x80ff04d3,
 260                                              0x1b4, bus, devfn, where,
 261                                              size, val);
 262         } else if (cfg_type == 1) {
 263                 bool is_rsl_bridge = devfn == 0x08;
 264                 bool is_rad_bridge = devfn == 0xa0;
 265                 bool is_zip_bridge = devfn == 0xa8;
 266                 bool is_dfa_bridge = devfn == 0xb0;
 267                 bool is_nic_bridge = devfn == 0x10;
 268 
 269                 if (where_a == 0x70) {
 270                         addr = bus->ops->map_bus(bus, devfn, where_a);
 271                         if (!addr) {
 272                                 *val = ~0;
 273                                 return PCIBIOS_DEVICE_NOT_FOUND;
 274                         }
 275                         v = readl(addr);
 276                         if (v & 0xff00)
 277                                 pr_err("Bad PCIe cap header: %08x\n", v);
 278                         v |= 0xbc00; /* next capability is EA at 0xbc */
 279                         set_val(v, where, size, val);
 280                         return PCIBIOS_SUCCESSFUL;
 281                 }
 282                 if (where_a == 0xbc) {
 283                         if (is_nic_bridge)
 284                                 v = 0x10014; /* EA last in chain, 1 entry */
 285                         else
 286                                 v = 0x00014; /* EA last in chain, no entries */
 287                         set_val(v, where, size, val);
 288                         return PCIBIOS_SUCCESSFUL;
 289                 }
 290                 if (where_a == 0xc0) {
 291                         if (is_rsl_bridge || is_nic_bridge)
 292                                 v = 0x0101; /* subordinate:secondary = 1:1 */
 293                         else if (is_rad_bridge)
 294                                 v = 0x0202; /* subordinate:secondary = 2:2 */
 295                         else if (is_zip_bridge)
 296                                 v = 0x0303; /* subordinate:secondary = 3:3 */
 297                         else if (is_dfa_bridge)
 298                                 v = 0x0404; /* subordinate:secondary = 4:4 */
 299                         set_val(v, where, size, val);
 300                         return PCIBIOS_SUCCESSFUL;
 301                 }
 302                 if (where_a == 0xc4 && is_nic_bridge) {
 303                         /* Enabled, not-Write, SP=ff, PP=05, BEI=6, ES=4 */
 304                         v = 0x80ff0564;
 305                         set_val(v, where, size, val);
 306                         return PCIBIOS_SUCCESSFUL;
 307                 }
 308                 if (where_a == 0xc8 && is_nic_bridge) {
 309                         v = 0x00000002; /* Base-L 64-bit */
 310                         set_val(v, where, size, val);
 311                         return PCIBIOS_SUCCESSFUL;
 312                 }
 313                 if (where_a == 0xcc && is_nic_bridge) {
 314                         v = 0xfffffffe; /* MaxOffset-L 64-bit */
 315                         set_val(v, where, size, val);
 316                         return PCIBIOS_SUCCESSFUL;
 317                 }
 318                 if (where_a == 0xd0 && is_nic_bridge) {
 319                         v = 0x00008430; /* NIC Base-H */
 320                         set_val(v, where, size, val);
 321                         return PCIBIOS_SUCCESSFUL;
 322                 }
 323                 if (where_a == 0xd4 && is_nic_bridge) {
 324                         v = 0x0000000f; /* MaxOffset-H */
 325                         set_val(v, where, size, val);
 326                         return PCIBIOS_SUCCESSFUL;
 327                 }
 328         }
 329 no_emulation:
 330         return pci_generic_config_read(bus, devfn, where, size, val);
 331 }
 332 
 333 static int thunder_ecam_config_write(struct pci_bus *bus, unsigned int devfn,
 334                                      int where, int size, u32 val)
 335 {
 336         /*
 337          * All BARs have fixed addresses; ignore BAR writes so they
 338          * don't get corrupted.
 339          */
 340         if ((where >= 0x10 && where < 0x2c) ||
 341             (where >= 0x1a4 && where < 0x1bc))
 342                 /* BAR or SR-IOV BAR */
 343                 return PCIBIOS_SUCCESSFUL;
 344 
 345         return pci_generic_config_write(bus, devfn, where, size, val);
 346 }
 347 
 348 struct pci_ecam_ops pci_thunder_ecam_ops = {
 349         .bus_shift      = 20,
 350         .pci_ops        = {
 351                 .map_bus        = pci_ecam_map_bus,
 352                 .read           = thunder_ecam_config_read,
 353                 .write          = thunder_ecam_config_write,
 354         }
 355 };
 356 
 357 #ifdef CONFIG_PCI_HOST_THUNDER_ECAM
 358 
 359 static const struct of_device_id thunder_ecam_of_match[] = {
 360         { .compatible = "cavium,pci-host-thunder-ecam" },
 361         { },
 362 };
 363 
 364 static int thunder_ecam_probe(struct platform_device *pdev)
 365 {
 366         return pci_host_common_probe(pdev, &pci_thunder_ecam_ops);
 367 }
 368 
 369 static struct platform_driver thunder_ecam_driver = {
 370         .driver = {
 371                 .name = KBUILD_MODNAME,
 372                 .of_match_table = thunder_ecam_of_match,
 373                 .suppress_bind_attrs = true,
 374         },
 375         .probe = thunder_ecam_probe,
 376 };
 377 builtin_platform_driver(thunder_ecam_driver);
 378 
 379 #endif
 380 #endif

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