The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/arm64/cavium/thunder_pcie_pem.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2015 The FreeBSD Foundation
    3  *
    4  * This software was developed by Semihalf under
    5  * the sponsorship of the FreeBSD Foundation.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 /* PCIe external MAC root complex driver (PEM) for Cavium Thunder SOC */
   30 
   31 #include <sys/cdefs.h>
   32 __FBSDID("$FreeBSD$");
   33 
   34 #include "opt_platform.h"
   35 
   36 #include <sys/param.h>
   37 #include <sys/systm.h>
   38 #include <sys/bus.h>
   39 #include <sys/kernel.h>
   40 #include <sys/malloc.h>
   41 #include <sys/module.h>
   42 #include <sys/rman.h>
   43 #include <sys/endian.h>
   44 
   45 #ifdef FDT
   46 #include <dev/ofw/openfirm.h>
   47 #include <dev/ofw/ofw_bus.h>
   48 #include <dev/ofw/ofw_bus_subr.h>
   49 #include <dev/ofw/ofw_pci.h>
   50 #endif
   51 
   52 #include <dev/pci/pcivar.h>
   53 #include <dev/pci/pcireg.h>
   54 #include <dev/pci/pci_host_generic.h>
   55 #include <dev/pci/pcib_private.h>
   56 
   57 #include <machine/bus.h>
   58 #include <machine/resource.h>
   59 #include <machine/smp.h>
   60 #include <machine/intr.h>
   61 
   62 #include <arm64/cavium/thunder_pcie_common.h>
   63 #include <arm64/cavium/thunder_pcie_pem.h>
   64 #include "pcib_if.h"
   65 
   66 #define THUNDER_PEM_DEVICE_ID           0xa020
   67 #define THUNDER_PEM_VENDOR_ID           0x177d
   68 
   69 /* ThunderX specific defines */
   70 #define THUNDER_PEMn_REG_BASE(unit)     (0x87e0c0000000UL | ((unit) << 24))
   71 #define PCIERC_CFG002                   0x08
   72 #define PCIERC_CFG006                   0x18
   73 #define PCIERC_CFG032                   0x80
   74 #define PCIERC_CFG006_SEC_BUS(reg)      (((reg) >> 8) & 0xFF)
   75 #define PEM_CFG_RD_REG_ALIGN(reg)       ((reg) & ~0x3)
   76 #define PEM_CFG_RD_REG_DATA(val)        (((val) >> 32) & 0xFFFFFFFF)
   77 #define PEM_CFG_RD                      0x30
   78 #define PEM_CFG_LINK_MASK               0x3
   79 #define PEM_CFG_LINK_RDY                0x3
   80 #define PEM_CFG_SLIX_TO_REG(slix)       ((slix) << 4)
   81 #define SBNUM_OFFSET                    0x8
   82 #define SBNUM_MASK                      0xFF
   83 #define PEM_ON_REG                      0x420
   84 #define PEM_CTL_STATUS                  0x0
   85 #define PEM_LINK_ENABLE                 (1 << 4)
   86 #define PEM_LINK_DLLA                   (1 << 29)
   87 #define PEM_LINK_LT                     (1 << 27)
   88 #define PEM_BUS_SHIFT                   (24)
   89 #define PEM_SLOT_SHIFT                  (19)
   90 #define PEM_FUNC_SHIFT                  (16)
   91 #define SLIX_S2M_REGX_ACC               0x874001000000UL
   92 #define SLIX_S2M_REGX_ACC_SIZE          0x1000
   93 #define SLIX_S2M_REGX_ACC_SPACING       0x001000000000UL
   94 #define SLI_BASE                        0x880000000000UL
   95 #define SLI_WINDOW_SPACING              0x004000000000UL
   96 #define SLI_PCI_OFFSET                  0x001000000000UL
   97 #define SLI_NODE_SHIFT                  (44)
   98 #define SLI_NODE_MASK                   (3)
   99 #define SLI_GROUP_SHIFT                 (40)
  100 #define SLI_ID_SHIFT                    (24)
  101 #define SLI_ID_MASK                     (7)
  102 #define SLI_PEMS_PER_GROUP              (3)
  103 #define SLI_GROUPS_PER_NODE             (2)
  104 #define SLI_PEMS_PER_NODE               (SLI_PEMS_PER_GROUP * SLI_GROUPS_PER_NODE)
  105 #define SLI_ACC_REG_CNT                 (256)
  106 
  107 /*
  108  * Each PEM device creates its own bus with
  109  * own address translation, so we can adjust bus addresses
  110  * as we want. To support 32-bit cards let's assume
  111  * PCI window assignment looks as following:
  112  *
  113  * 0x00000000 - 0x000FFFFF      IO
  114  * 0x00100000 - 0xFFFFFFFF      Memory
  115  */
  116 #define PCI_IO_BASE             0x00000000UL
  117 #define PCI_IO_SIZE             0x00100000UL
  118 #define PCI_MEMORY_BASE         PCI_IO_SIZE
  119 #define PCI_MEMORY_SIZE         0xFFF00000UL
  120 
  121 #define RID_PEM_SPACE           1
  122 
  123 static int thunder_pem_activate_resource(device_t, device_t, int, int,
  124     struct resource *);
  125 static int thunder_pem_adjust_resource(device_t, device_t, int,
  126     struct resource *, rman_res_t, rman_res_t);
  127 static struct resource * thunder_pem_alloc_resource(device_t, device_t, int,
  128     int *, rman_res_t, rman_res_t, rman_res_t, u_int);
  129 static int thunder_pem_alloc_msi(device_t, device_t, int, int, int *);
  130 static int thunder_pem_release_msi(device_t, device_t, int, int *);
  131 static int thunder_pem_alloc_msix(device_t, device_t, int *);
  132 static int thunder_pem_release_msix(device_t, device_t, int);
  133 static int thunder_pem_map_msi(device_t, device_t, int, uint64_t *, uint32_t *);
  134 static int thunder_pem_get_id(device_t, device_t, enum pci_id_type,
  135     uintptr_t *);
  136 static int thunder_pem_attach(device_t);
  137 static int thunder_pem_deactivate_resource(device_t, device_t, int, int,
  138     struct resource *);
  139 static bus_dma_tag_t thunder_pem_get_dma_tag(device_t, device_t);
  140 static int thunder_pem_detach(device_t);
  141 static uint64_t thunder_pem_config_reg_read(struct thunder_pem_softc *, int);
  142 static int thunder_pem_link_init(struct thunder_pem_softc *);
  143 static int thunder_pem_maxslots(device_t);
  144 static int thunder_pem_probe(device_t);
  145 static uint32_t thunder_pem_read_config(device_t, u_int, u_int, u_int, u_int,
  146     int);
  147 static int thunder_pem_read_ivar(device_t, device_t, int, uintptr_t *);
  148 static void thunder_pem_release_all(device_t);
  149 static int thunder_pem_release_resource(device_t, device_t, int, int,
  150     struct resource *);
  151 static struct rman * thunder_pem_rman(struct thunder_pem_softc *, int);
  152 static void thunder_pem_slix_s2m_regx_acc_modify(struct thunder_pem_softc *,
  153     int, int);
  154 static void thunder_pem_write_config(device_t, u_int, u_int, u_int, u_int,
  155     uint32_t, int);
  156 static int thunder_pem_write_ivar(device_t, device_t, int, uintptr_t);
  157 
  158 /* Global handlers for SLI interface */
  159 static bus_space_handle_t sli0_s2m_regx_base = 0;
  160 static bus_space_handle_t sli1_s2m_regx_base = 0;
  161 
  162 static device_method_t thunder_pem_methods[] = {
  163         /* Device interface */
  164         DEVMETHOD(device_probe,                 thunder_pem_probe),
  165         DEVMETHOD(device_attach,                thunder_pem_attach),
  166         DEVMETHOD(device_detach,                thunder_pem_detach),
  167 
  168         /* Bus interface */
  169         DEVMETHOD(bus_read_ivar,                thunder_pem_read_ivar),
  170         DEVMETHOD(bus_write_ivar,               thunder_pem_write_ivar),
  171         DEVMETHOD(bus_alloc_resource,           thunder_pem_alloc_resource),
  172         DEVMETHOD(bus_release_resource,         thunder_pem_release_resource),
  173         DEVMETHOD(bus_adjust_resource,          thunder_pem_adjust_resource),
  174         DEVMETHOD(bus_activate_resource,        thunder_pem_activate_resource),
  175         DEVMETHOD(bus_deactivate_resource,      thunder_pem_deactivate_resource),
  176         DEVMETHOD(bus_setup_intr,               bus_generic_setup_intr),
  177         DEVMETHOD(bus_teardown_intr,            bus_generic_teardown_intr),
  178 
  179         DEVMETHOD(bus_get_dma_tag,              thunder_pem_get_dma_tag),
  180 
  181         /* pcib interface */
  182         DEVMETHOD(pcib_maxslots,                thunder_pem_maxslots),
  183         DEVMETHOD(pcib_read_config,             thunder_pem_read_config),
  184         DEVMETHOD(pcib_write_config,            thunder_pem_write_config),
  185         DEVMETHOD(pcib_alloc_msix,              thunder_pem_alloc_msix),
  186         DEVMETHOD(pcib_release_msix,            thunder_pem_release_msix),
  187         DEVMETHOD(pcib_alloc_msi,               thunder_pem_alloc_msi),
  188         DEVMETHOD(pcib_release_msi,             thunder_pem_release_msi),
  189         DEVMETHOD(pcib_map_msi,                 thunder_pem_map_msi),
  190         DEVMETHOD(pcib_get_id,                  thunder_pem_get_id),
  191 
  192         DEVMETHOD_END
  193 };
  194 
  195 DEFINE_CLASS_0(pcib, thunder_pem_driver, thunder_pem_methods,
  196     sizeof(struct thunder_pem_softc));
  197 
  198 extern struct bus_space memmap_bus;
  199 
  200 DRIVER_MODULE(thunder_pem, pci, thunder_pem_driver, 0, 0);
  201 MODULE_DEPEND(thunder_pem, pci, 1, 1, 1);
  202 
  203 static int
  204 thunder_pem_maxslots(device_t dev)
  205 {
  206 
  207 #if 0
  208         /* max slots per bus acc. to standard */
  209         return (PCI_SLOTMAX);
  210 #else
  211         /*
  212          * ARM64TODO Workaround - otherwise an em(4) interface appears to be
  213          * present on every PCI function on the bus to which it is connected
  214          */
  215         return (0);
  216 #endif
  217 }
  218 
  219 static int
  220 thunder_pem_read_ivar(device_t dev, device_t child, int index,
  221     uintptr_t *result)
  222 {
  223         struct thunder_pem_softc *sc;
  224         int secondary_bus = 0;
  225 
  226         sc = device_get_softc(dev);
  227 
  228         if (index == PCIB_IVAR_BUS) {
  229                 secondary_bus = thunder_pem_config_reg_read(sc, PCIERC_CFG006);
  230                 *result = PCIERC_CFG006_SEC_BUS(secondary_bus);
  231                 return (0);
  232         }
  233         if (index == PCIB_IVAR_DOMAIN) {
  234                 *result = sc->id;
  235                 return (0);
  236         }
  237 
  238         return (ENOENT);
  239 }
  240 
  241 static int
  242 thunder_pem_write_ivar(device_t dev, device_t child, int index,
  243     uintptr_t value)
  244 {
  245 
  246         return (ENOENT);
  247 }
  248 
  249 static int
  250 thunder_pem_activate_resource(device_t dev, device_t child, int type, int rid,
  251     struct resource *r)
  252 {
  253         int err;
  254         bus_addr_t paddr;
  255         bus_size_t psize;
  256         bus_space_handle_t vaddr;
  257         struct thunder_pem_softc *sc;
  258 
  259         if ((err = rman_activate_resource(r)) != 0)
  260                 return (err);
  261 
  262         sc = device_get_softc(dev);
  263 
  264         /*
  265          * If this is a memory resource, map it into the kernel.
  266          */
  267         if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) {
  268                 paddr = (bus_addr_t)rman_get_start(r);
  269                 psize = (bus_size_t)rman_get_size(r);
  270 
  271                 paddr = range_addr_pci_to_phys(sc->ranges, paddr);
  272 
  273                 err = bus_space_map(&memmap_bus, paddr, psize, 0, &vaddr);
  274                 if (err != 0) {
  275                         rman_deactivate_resource(r);
  276                         return (err);
  277                 }
  278                 rman_set_bustag(r, &memmap_bus);
  279                 rman_set_virtual(r, (void *)vaddr);
  280                 rman_set_bushandle(r, vaddr);
  281         }
  282         return (0);
  283 }
  284 
  285 /*
  286  * This function is an exact copy of nexus_deactivate_resource()
  287  * Keep it up-to-date with all changes in nexus. To be removed
  288  * once bus-mapping interface is developed.
  289  */
  290 static int
  291 thunder_pem_deactivate_resource(device_t bus, device_t child, int type, int rid,
  292     struct resource *r)
  293 {
  294         bus_size_t psize;
  295         bus_space_handle_t vaddr;
  296 
  297         psize = (bus_size_t)rman_get_size(r);
  298         vaddr = rman_get_bushandle(r);
  299 
  300         if (vaddr != 0) {
  301                 bus_space_unmap(&memmap_bus, vaddr, psize);
  302                 rman_set_virtual(r, NULL);
  303                 rman_set_bushandle(r, 0);
  304         }
  305 
  306         return (rman_deactivate_resource(r));
  307 }
  308 
  309 static int
  310 thunder_pem_adjust_resource(device_t dev, device_t child, int type,
  311     struct resource *res, rman_res_t start, rman_res_t end)
  312 {
  313         struct thunder_pem_softc *sc;
  314         struct rman *rm;
  315 
  316         sc = device_get_softc(dev);
  317 #if defined(NEW_PCIB) && defined(PCI_RES_BUS)
  318         if (type == PCI_RES_BUS)
  319                 return (pci_domain_adjust_bus(sc->id, child, res, start, end));
  320 #endif
  321 
  322         rm = thunder_pem_rman(sc, type);
  323         if (rm == NULL)
  324                 return (bus_generic_adjust_resource(dev, child, type, res,
  325                     start, end));
  326         if (!rman_is_region_manager(res, rm))
  327                 /*
  328                  * This means a child device has a memory or I/O
  329                  * resource not from you which shouldn't happen.
  330                  */
  331                 return (EINVAL);
  332         return (rman_adjust_resource(res, start, end));
  333 }
  334 
  335 static bus_dma_tag_t
  336 thunder_pem_get_dma_tag(device_t dev, device_t child)
  337 {
  338         struct thunder_pem_softc *sc;
  339 
  340         sc = device_get_softc(dev);
  341         return (sc->dmat);
  342 }
  343 
  344 static int
  345 thunder_pem_alloc_msi(device_t pci, device_t child, int count, int maxcount,
  346     int *irqs)
  347 {
  348         device_t bus;
  349 
  350         bus = device_get_parent(pci);
  351         return (PCIB_ALLOC_MSI(device_get_parent(bus), child, count, maxcount,
  352             irqs));
  353 }
  354 
  355 static int
  356 thunder_pem_release_msi(device_t pci, device_t child, int count, int *irqs)
  357 {
  358         device_t bus;
  359 
  360         bus = device_get_parent(pci);
  361         return (PCIB_RELEASE_MSI(device_get_parent(bus), child, count, irqs));
  362 }
  363 
  364 static int
  365 thunder_pem_alloc_msix(device_t pci, device_t child, int *irq)
  366 {
  367         device_t bus;
  368 
  369         bus = device_get_parent(pci);
  370         return (PCIB_ALLOC_MSIX(device_get_parent(bus), child, irq));
  371 }
  372 
  373 static int
  374 thunder_pem_release_msix(device_t pci, device_t child, int irq)
  375 {
  376         device_t bus;
  377 
  378         bus = device_get_parent(pci);
  379         return (PCIB_RELEASE_MSIX(device_get_parent(bus), child, irq));
  380 }
  381 
  382 static int
  383 thunder_pem_map_msi(device_t pci, device_t child, int irq, uint64_t *addr,
  384     uint32_t *data)
  385 {
  386         device_t bus;
  387 
  388         bus = device_get_parent(pci);
  389         return (PCIB_MAP_MSI(device_get_parent(bus), child, irq, addr, data));
  390 }
  391 
  392 static int
  393 thunder_pem_get_id(device_t pci, device_t child, enum pci_id_type type,
  394     uintptr_t *id)
  395 {
  396         int bsf;
  397         int pem;
  398 
  399         if (type != PCI_ID_MSI)
  400                 return (pcib_get_id(pci, child, type, id));
  401 
  402         bsf = pci_get_rid(child);
  403 
  404         /* PEM (PCIe MAC/root complex) number is equal to domain */
  405         pem = pci_get_domain(child);
  406 
  407         /*
  408          * Set appropriate device ID (passed by the HW along with
  409          * the transaction to memory) for different root complex
  410          * numbers using hard-coded domain portion for each group.
  411          */
  412         if (pem < 3)
  413                 *id = (0x1 << PCI_RID_DOMAIN_SHIFT) | bsf;
  414         else if (pem < 6)
  415                 *id = (0x3 << PCI_RID_DOMAIN_SHIFT) | bsf;
  416         else if (pem < 9)
  417                 *id = (0x9 << PCI_RID_DOMAIN_SHIFT) | bsf;
  418         else if (pem < 12)
  419                 *id = (0xB << PCI_RID_DOMAIN_SHIFT) | bsf;
  420         else
  421                 return (ENXIO);
  422 
  423         return (0);
  424 }
  425 
  426 static int
  427 thunder_pem_identify(device_t dev)
  428 {
  429         struct thunder_pem_softc *sc;
  430         rman_res_t start;
  431 
  432         sc = device_get_softc(dev);
  433         start = rman_get_start(sc->reg);
  434 
  435         /* Calculate PEM designations from its address */
  436         sc->node = (start >> SLI_NODE_SHIFT) & SLI_NODE_MASK;
  437         sc->id = ((start >> SLI_ID_SHIFT) & SLI_ID_MASK) +
  438             (SLI_PEMS_PER_NODE * sc->node);
  439         sc->sli = sc->id % SLI_PEMS_PER_GROUP;
  440         sc->sli_group = (sc->id / SLI_PEMS_PER_GROUP) % SLI_GROUPS_PER_NODE;
  441         sc->sli_window_base = SLI_BASE |
  442             (((uint64_t)sc->node) << SLI_NODE_SHIFT) |
  443             ((uint64_t)sc->sli_group << SLI_GROUP_SHIFT);
  444         sc->sli_window_base += SLI_WINDOW_SPACING * sc->sli;
  445 
  446         return (0);
  447 }
  448 
  449 static void
  450 thunder_pem_slix_s2m_regx_acc_modify(struct thunder_pem_softc *sc,
  451     int sli_group, int slix)
  452 {
  453         uint64_t regval;
  454         bus_space_handle_t handle = 0;
  455 
  456         KASSERT(slix >= 0 && slix <= SLI_ACC_REG_CNT, ("Invalid SLI index"));
  457 
  458         if (sli_group == 0)
  459                 handle = sli0_s2m_regx_base;
  460         else if (sli_group == 1)
  461                 handle = sli1_s2m_regx_base;
  462         else
  463                 device_printf(sc->dev, "SLI group is not correct\n");
  464 
  465         if (handle) {
  466                 /* Clear lower 32-bits of the SLIx register */
  467                 regval = bus_space_read_8(sc->reg_bst, handle,
  468                     PEM_CFG_SLIX_TO_REG(slix));
  469                 regval &= ~(0xFFFFFFFFUL);
  470                 bus_space_write_8(sc->reg_bst, handle,
  471                     PEM_CFG_SLIX_TO_REG(slix), regval);
  472         }
  473 }
  474 
  475 static int
  476 thunder_pem_link_init(struct thunder_pem_softc *sc)
  477 {
  478         uint64_t regval;
  479 
  480         /* check whether PEM is safe to access. */
  481         regval = bus_space_read_8(sc->reg_bst, sc->reg_bsh, PEM_ON_REG);
  482         if ((regval & PEM_CFG_LINK_MASK) != PEM_CFG_LINK_RDY) {
  483                 device_printf(sc->dev, "PEM%d is not ON\n", sc->id);
  484                 return (ENXIO);
  485         }
  486 
  487         regval = bus_space_read_8(sc->reg_bst, sc->reg_bsh, PEM_CTL_STATUS);
  488         regval |= PEM_LINK_ENABLE;
  489         bus_space_write_8(sc->reg_bst, sc->reg_bsh, PEM_CTL_STATUS, regval);
  490 
  491         /* Wait 1ms as per Cavium specification */
  492         DELAY(1000);
  493 
  494         regval = thunder_pem_config_reg_read(sc, PCIERC_CFG032);
  495 
  496         if (((regval & PEM_LINK_DLLA) == 0) || ((regval & PEM_LINK_LT) != 0)) {
  497                 device_printf(sc->dev, "PCIe RC: Port %d Link Timeout\n",
  498                     sc->id);
  499                 return (ENXIO);
  500         }
  501 
  502         return (0);
  503 }
  504 
  505 static int
  506 thunder_pem_init(struct thunder_pem_softc *sc)
  507 {
  508         int i, retval = 0;
  509 
  510         retval = thunder_pem_link_init(sc);
  511         if (retval) {
  512                 device_printf(sc->dev, "%s failed\n", __func__);
  513                 return retval;
  514         }
  515 
  516         /* To support 32-bit PCIe devices, set S2M_REGx_ACC[BA]=0x0 */
  517         for (i = 0; i < SLI_ACC_REG_CNT; i++) {
  518                 thunder_pem_slix_s2m_regx_acc_modify(sc, sc->sli_group, i);
  519         }
  520 
  521         return (retval);
  522 }
  523 
  524 static uint64_t
  525 thunder_pem_config_reg_read(struct thunder_pem_softc *sc, int reg)
  526 {
  527         uint64_t data;
  528 
  529         /* Write to ADDR register */
  530         bus_space_write_8(sc->reg_bst, sc->reg_bsh, PEM_CFG_RD,
  531             PEM_CFG_RD_REG_ALIGN(reg));
  532         bus_space_barrier(sc->reg_bst, sc->reg_bsh, PEM_CFG_RD, 8,
  533             BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
  534         /* Read from DATA register */
  535         data = PEM_CFG_RD_REG_DATA(bus_space_read_8(sc->reg_bst, sc->reg_bsh,
  536             PEM_CFG_RD));
  537 
  538         return (data);
  539 }
  540 
  541 static uint32_t
  542 thunder_pem_read_config(device_t dev, u_int bus, u_int slot,
  543     u_int func, u_int reg, int bytes)
  544 {
  545         uint64_t offset;
  546         uint32_t data;
  547         struct thunder_pem_softc *sc;
  548         bus_space_tag_t t;
  549         bus_space_handle_t h;
  550 
  551         if ((bus > PCI_BUSMAX) || (slot > PCI_SLOTMAX) ||
  552             (func > PCI_FUNCMAX) || (reg > PCIE_REGMAX))
  553                 return (~0U);
  554 
  555         sc = device_get_softc(dev);
  556 
  557         /* Calculate offset */
  558         offset = (bus << PEM_BUS_SHIFT) | (slot << PEM_SLOT_SHIFT) |
  559             (func << PEM_FUNC_SHIFT);
  560         t = sc->reg_bst;
  561         h = sc->pem_sli_base;
  562 
  563         bus_space_map(sc->reg_bst, sc->sli_window_base + offset,
  564             PCIE_REGMAX, 0, &h);
  565 
  566         switch (bytes) {
  567         case 1:
  568                 data = bus_space_read_1(t, h, reg);
  569                 break;
  570         case 2:
  571                 data = le16toh(bus_space_read_2(t, h, reg));
  572                 break;
  573         case 4:
  574                 data = le32toh(bus_space_read_4(t, h, reg));
  575                 break;
  576         default:
  577                 data = ~0U;
  578                 break;
  579         }
  580 
  581         bus_space_unmap(sc->reg_bst, h, PCIE_REGMAX);
  582 
  583         return (data);
  584 }
  585 
  586 static void
  587 thunder_pem_write_config(device_t dev, u_int bus, u_int slot,
  588     u_int func, u_int reg, uint32_t val, int bytes)
  589 {
  590         uint64_t offset;
  591         struct thunder_pem_softc *sc;
  592         bus_space_tag_t t;
  593         bus_space_handle_t h;
  594 
  595         if ((bus > PCI_BUSMAX) || (slot > PCI_SLOTMAX) ||
  596             (func > PCI_FUNCMAX) || (reg > PCIE_REGMAX))
  597                 return;
  598 
  599         sc = device_get_softc(dev);
  600 
  601         /* Calculate offset */
  602         offset = (bus << PEM_BUS_SHIFT) | (slot << PEM_SLOT_SHIFT) |
  603             (func << PEM_FUNC_SHIFT);
  604         t = sc->reg_bst;
  605         h = sc->pem_sli_base;
  606 
  607         bus_space_map(sc->reg_bst, sc->sli_window_base + offset,
  608             PCIE_REGMAX, 0, &h);
  609 
  610         switch (bytes) {
  611         case 1:
  612                 bus_space_write_1(t, h, reg, val);
  613                 break;
  614         case 2:
  615                 bus_space_write_2(t, h, reg, htole16(val));
  616                 break;
  617         case 4:
  618                 bus_space_write_4(t, h, reg, htole32(val));
  619                 break;
  620         default:
  621                 break;
  622         }
  623 
  624         bus_space_unmap(sc->reg_bst, h, PCIE_REGMAX);
  625 }
  626 
  627 static struct resource *
  628 thunder_pem_alloc_resource(device_t dev, device_t child, int type, int *rid,
  629     rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
  630 {
  631         struct thunder_pem_softc *sc = device_get_softc(dev);
  632         struct rman *rm = NULL;
  633         struct resource *res;
  634         device_t parent_dev;
  635 
  636 #if defined(NEW_PCIB) && defined(PCI_RES_BUS)
  637         if (type == PCI_RES_BUS)
  638                 return (pci_domain_alloc_bus(sc->id, child, rid, start,  end,
  639                     count, flags));
  640 #endif
  641         rm = thunder_pem_rman(sc, type);
  642         if (rm == NULL) {
  643                 /* Find parent device. On ThunderX we know an exact path. */
  644                 parent_dev = device_get_parent(device_get_parent(dev));
  645                 return (BUS_ALLOC_RESOURCE(parent_dev, dev, type, rid, start,
  646                     end, count, flags));
  647         }
  648 
  649         if (!RMAN_IS_DEFAULT_RANGE(start, end)) {
  650                 /*
  651                  * We might get PHYS addresses here inherited from EFI.
  652                  * Convert to PCI if necessary.
  653                  */
  654                 if (range_addr_is_phys(sc->ranges, start, count)) {
  655                         start = range_addr_phys_to_pci(sc->ranges, start);
  656                         end = start + count - 1;
  657                 }
  658         }
  659 
  660         if (bootverbose) {
  661                 device_printf(dev,
  662                     "thunder_pem_alloc_resource: start=%#lx, end=%#lx, count=%#lx\n",
  663                     start, end, count);
  664         }
  665 
  666         res = rman_reserve_resource(rm, start, end, count, flags, child);
  667         if (res == NULL)
  668                 goto fail;
  669 
  670         rman_set_rid(res, *rid);
  671 
  672         if (flags & RF_ACTIVE)
  673                 if (bus_activate_resource(child, type, *rid, res)) {
  674                         rman_release_resource(res);
  675                         goto fail;
  676                 }
  677 
  678         return (res);
  679 
  680 fail:
  681         if (bootverbose) {
  682                 device_printf(dev, "%s FAIL: type=%d, rid=%d, "
  683                     "start=%016lx, end=%016lx, count=%016lx, flags=%x\n",
  684                     __func__, type, *rid, start, end, count, flags);
  685         }
  686 
  687         return (NULL);
  688 }
  689 
  690 static int
  691 thunder_pem_release_resource(device_t dev, device_t child, int type, int rid,
  692     struct resource *res)
  693 {
  694         device_t parent_dev;
  695 #if defined(NEW_PCIB) && defined(PCI_RES_BUS)
  696         struct thunder_pem_softc *sc = device_get_softc(dev);
  697 
  698         if (type == PCI_RES_BUS)
  699                 return (pci_domain_release_bus(sc->id, child, rid, res));
  700 #endif
  701         /* Find parent device. On ThunderX we know an exact path. */
  702         parent_dev = device_get_parent(device_get_parent(dev));
  703 
  704         if ((type != SYS_RES_MEMORY) && (type != SYS_RES_IOPORT))
  705                 return (BUS_RELEASE_RESOURCE(parent_dev, child,
  706                     type, rid, res));
  707 
  708         return (rman_release_resource(res));
  709 }
  710 
  711 static struct rman *
  712 thunder_pem_rman(struct thunder_pem_softc *sc, int type)
  713 {
  714 
  715         switch (type) {
  716         case SYS_RES_IOPORT:
  717                 return (&sc->io_rman);
  718         case SYS_RES_MEMORY:
  719                 return (&sc->mem_rman);
  720         default:
  721                 break;
  722         }
  723 
  724         return (NULL);
  725 }
  726 
  727 static int
  728 thunder_pem_probe(device_t dev)
  729 {
  730         uint16_t pci_vendor_id;
  731         uint16_t pci_device_id;
  732 
  733         pci_vendor_id = pci_get_vendor(dev);
  734         pci_device_id = pci_get_device(dev);
  735 
  736         if ((pci_vendor_id == THUNDER_PEM_VENDOR_ID) &&
  737             (pci_device_id == THUNDER_PEM_DEVICE_ID)) {
  738                 device_set_desc_copy(dev, THUNDER_PEM_DESC);
  739                 return (0);
  740         }
  741 
  742         return (ENXIO);
  743 }
  744 
  745 static int
  746 thunder_pem_attach(device_t dev)
  747 {
  748         devclass_t pci_class;
  749         device_t parent;
  750         struct thunder_pem_softc *sc;
  751         int error;
  752         int rid;
  753         int tuple;
  754         uint64_t base, size;
  755         struct rman *rman;
  756 
  757         sc = device_get_softc(dev);
  758         sc->dev = dev;
  759 
  760         /* Allocate memory for resource */
  761         pci_class = devclass_find("pci");
  762         parent = device_get_parent(dev);
  763         if (device_get_devclass(parent) == pci_class)
  764                 rid = PCIR_BAR(0);
  765         else
  766                 rid = RID_PEM_SPACE;
  767 
  768         sc->reg = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
  769             &rid, RF_ACTIVE);
  770         if (sc->reg == NULL) {
  771                 device_printf(dev, "Failed to allocate resource\n");
  772                 return (ENXIO);
  773         }
  774         sc->reg_bst = rman_get_bustag(sc->reg);
  775         sc->reg_bsh = rman_get_bushandle(sc->reg);
  776 
  777         /* Create the parent DMA tag to pass down the coherent flag */
  778         error = bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */
  779             1, 0,                       /* alignment, bounds */
  780             BUS_SPACE_MAXADDR,          /* lowaddr */
  781             BUS_SPACE_MAXADDR,          /* highaddr */
  782             NULL, NULL,                 /* filter, filterarg */
  783             BUS_SPACE_MAXSIZE,          /* maxsize */
  784             BUS_SPACE_UNRESTRICTED,     /* nsegments */
  785             BUS_SPACE_MAXSIZE,          /* maxsegsize */
  786             BUS_DMA_COHERENT,           /* flags */
  787             NULL, NULL,                 /* lockfunc, lockarg */
  788             &sc->dmat);
  789         if (error != 0)
  790                 return (error);
  791 
  792         /* Map SLI, do it only once */
  793         if (!sli0_s2m_regx_base) {
  794                 bus_space_map(sc->reg_bst, SLIX_S2M_REGX_ACC,
  795                     SLIX_S2M_REGX_ACC_SIZE, 0, &sli0_s2m_regx_base);
  796         }
  797         if (!sli1_s2m_regx_base) {
  798                 bus_space_map(sc->reg_bst, SLIX_S2M_REGX_ACC +
  799                     SLIX_S2M_REGX_ACC_SPACING, SLIX_S2M_REGX_ACC_SIZE, 0,
  800                     &sli1_s2m_regx_base);
  801         }
  802 
  803         if ((sli0_s2m_regx_base == 0) || (sli1_s2m_regx_base == 0)) {
  804                 device_printf(dev,
  805                     "bus_space_map failed to map slix_s2m_regx_base\n");
  806                 goto fail;
  807         }
  808 
  809         /* Identify PEM */
  810         if (thunder_pem_identify(dev) != 0)
  811                 goto fail;
  812 
  813         /* Initialize rman and allocate regions */
  814         sc->mem_rman.rm_type = RMAN_ARRAY;
  815         sc->mem_rman.rm_descr = "PEM PCIe Memory";
  816         error = rman_init(&sc->mem_rman);
  817         if (error != 0) {
  818                 device_printf(dev, "memory rman_init() failed. error = %d\n",
  819                     error);
  820                 goto fail;
  821         }
  822         sc->io_rman.rm_type = RMAN_ARRAY;
  823         sc->io_rman.rm_descr = "PEM PCIe IO";
  824         error = rman_init(&sc->io_rman);
  825         if (error != 0) {
  826                 device_printf(dev, "IO rman_init() failed. error = %d\n",
  827                     error);
  828                 goto fail_mem;
  829         }
  830 
  831         /*
  832          * We ignore the values that may have been provided in FDT
  833          * and configure ranges according to the below formula
  834          * for all types of devices. This is because some DTBs provided
  835          * by EFI do not have proper ranges property or don't have them
  836          * at all.
  837          */
  838         /* Fill memory window */
  839         sc->ranges[0].pci_base = PCI_MEMORY_BASE;
  840         sc->ranges[0].size = PCI_MEMORY_SIZE;
  841         sc->ranges[0].phys_base = sc->sli_window_base + SLI_PCI_OFFSET +
  842             sc->ranges[0].pci_base;
  843         sc->ranges[0].flags = SYS_RES_MEMORY;
  844 
  845         /* Fill IO window */
  846         sc->ranges[1].pci_base = PCI_IO_BASE;
  847         sc->ranges[1].size = PCI_IO_SIZE;
  848         sc->ranges[1].phys_base = sc->sli_window_base + SLI_PCI_OFFSET +
  849             sc->ranges[1].pci_base;
  850         sc->ranges[1].flags = SYS_RES_IOPORT;
  851 
  852         for (tuple = 0; tuple < MAX_RANGES_TUPLES; tuple++) {
  853                 base = sc->ranges[tuple].pci_base;
  854                 size = sc->ranges[tuple].size;
  855                 if (size == 0)
  856                         continue; /* empty range element */
  857 
  858                 rman = thunder_pem_rman(sc, sc->ranges[tuple].flags);
  859                 if (rman != NULL)
  860                         error = rman_manage_region(rman, base,
  861                             base + size - 1);
  862                 else
  863                         error = EINVAL;
  864                 if (error) {
  865                         device_printf(dev,
  866                             "rman_manage_region() failed. error = %d\n", error);
  867                         rman_fini(&sc->mem_rman);
  868                         return (error);
  869                 }
  870                 if (bootverbose) {
  871                         device_printf(dev,
  872                             "\tPCI addr: 0x%jx, CPU addr: 0x%jx, Size: 0x%jx, Flags:0x%jx\n",
  873                             sc->ranges[tuple].pci_base,
  874                             sc->ranges[tuple].phys_base,
  875                             sc->ranges[tuple].size,
  876                             sc->ranges[tuple].flags);
  877                 }
  878         }
  879 
  880         if (thunder_pem_init(sc)) {
  881                 device_printf(dev, "Failure during PEM init\n");
  882                 goto fail_io;
  883         }
  884 
  885         device_add_child(dev, "pci", -1);
  886 
  887         return (bus_generic_attach(dev));
  888 
  889 fail_io:
  890         rman_fini(&sc->io_rman);
  891 fail_mem:
  892         rman_fini(&sc->mem_rman);
  893 fail:
  894         bus_free_resource(dev, SYS_RES_MEMORY, sc->reg);
  895         return (ENXIO);
  896 }
  897 
  898 static void
  899 thunder_pem_release_all(device_t dev)
  900 {
  901         struct thunder_pem_softc *sc;
  902 
  903         sc = device_get_softc(dev);
  904 
  905         rman_fini(&sc->io_rman);
  906         rman_fini(&sc->mem_rman);
  907 
  908         if (sc->reg != NULL)
  909                 bus_free_resource(dev, SYS_RES_MEMORY, sc->reg);
  910 }
  911 
  912 static int
  913 thunder_pem_detach(device_t dev)
  914 {
  915 
  916         thunder_pem_release_all(dev);
  917 
  918         return (0);
  919 }

Cache object: 73b1affca4f4ce2efd2d9d681cfe41b9


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.