Path: blob/main/sys/arm64/cavium/thunder_pcie_pem.c
39478 views
/*-1* Copyright (c) 2015 The FreeBSD Foundation2*3* This software was developed by Semihalf under4* the sponsorship of the FreeBSD Foundation.5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted provided that the following conditions8* are met:9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer.11* 2. Redistributions in binary form must reproduce the above copyright12* notice, this list of conditions and the following disclaimer in the13* documentation and/or other materials provided with the distribution.14*15* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND16* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE17* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE18* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE19* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL20* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS21* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)22* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT23* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY24* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF25* SUCH DAMAGE.26*/2728/* PCIe external MAC root complex driver (PEM) for Cavium Thunder SOC */2930#include <sys/cdefs.h>31#include "opt_platform.h"3233#include <sys/param.h>34#include <sys/systm.h>35#include <sys/bus.h>36#include <sys/kernel.h>37#include <sys/malloc.h>38#include <sys/module.h>39#include <sys/rman.h>40#include <sys/endian.h>4142#include <vm/vm.h>4344#ifdef FDT45#include <dev/ofw/openfirm.h>46#include <dev/ofw/ofw_bus.h>47#include <dev/ofw/ofw_bus_subr.h>48#include <dev/ofw/ofw_pci.h>49#endif5051#include <dev/pci/pcivar.h>52#include <dev/pci/pcireg.h>53#include <dev/pci/pci_host_generic.h>54#include <dev/pci/pcib_private.h>5556#include <machine/bus.h>57#include <machine/resource.h>58#include <machine/smp.h>59#include <machine/intr.h>6061#include <arm64/cavium/thunder_pcie_common.h>62#include <arm64/cavium/thunder_pcie_pem.h>63#include "pcib_if.h"6465#define THUNDER_PEM_DEVICE_ID 0xa02066#define THUNDER_PEM_VENDOR_ID 0x177d6768/* ThunderX specific defines */69#define THUNDER_PEMn_REG_BASE(unit) (0x87e0c0000000UL | ((unit) << 24))70#define PCIERC_CFG002 0x0871#define PCIERC_CFG006 0x1872#define PCIERC_CFG032 0x8073#define PCIERC_CFG006_SEC_BUS(reg) (((reg) >> 8) & 0xFF)74#define PEM_CFG_RD_REG_ALIGN(reg) ((reg) & ~0x3)75#define PEM_CFG_RD_REG_DATA(val) (((val) >> 32) & 0xFFFFFFFF)76#define PEM_CFG_RD 0x3077#define PEM_CFG_LINK_MASK 0x378#define PEM_CFG_LINK_RDY 0x379#define PEM_CFG_SLIX_TO_REG(slix) ((slix) << 4)80#define SBNUM_OFFSET 0x881#define SBNUM_MASK 0xFF82#define PEM_ON_REG 0x42083#define PEM_CTL_STATUS 0x084#define PEM_LINK_ENABLE (1 << 4)85#define PEM_LINK_DLLA (1 << 29)86#define PEM_LINK_LT (1 << 27)87#define PEM_BUS_SHIFT (24)88#define PEM_SLOT_SHIFT (19)89#define PEM_FUNC_SHIFT (16)90#define SLIX_S2M_REGX_ACC 0x874001000000UL91#define SLIX_S2M_REGX_ACC_SIZE 0x100092#define SLIX_S2M_REGX_ACC_SPACING 0x001000000000UL93#define SLI_BASE 0x880000000000UL94#define SLI_WINDOW_SPACING 0x004000000000UL95#define SLI_PCI_OFFSET 0x001000000000UL96#define SLI_NODE_SHIFT (44)97#define SLI_NODE_MASK (3)98#define SLI_GROUP_SHIFT (40)99#define SLI_ID_SHIFT (24)100#define SLI_ID_MASK (7)101#define SLI_PEMS_PER_GROUP (3)102#define SLI_GROUPS_PER_NODE (2)103#define SLI_PEMS_PER_NODE (SLI_PEMS_PER_GROUP * SLI_GROUPS_PER_NODE)104#define SLI_ACC_REG_CNT (256)105106/*107* Each PEM device creates its own bus with108* own address translation, so we can adjust bus addresses109* as we want. To support 32-bit cards let's assume110* PCI window assignment looks as following:111*112* 0x00000000 - 0x000FFFFF IO113* 0x00100000 - 0xFFFFFFFF Memory114*/115#define PCI_IO_BASE 0x00000000UL116#define PCI_IO_SIZE 0x00100000UL117#define PCI_MEMORY_BASE PCI_IO_SIZE118#define PCI_MEMORY_SIZE 0xFFF00000UL119120#define RID_PEM_SPACE 1121122static int thunder_pem_activate_resource(device_t, device_t, struct resource *);123static int thunder_pem_adjust_resource(device_t, device_t,124struct resource *, rman_res_t, rman_res_t);125static struct resource * thunder_pem_alloc_resource(device_t, device_t, int,126int *, rman_res_t, rman_res_t, rman_res_t, u_int);127static int thunder_pem_alloc_msi(device_t, device_t, int, int, int *);128static int thunder_pem_release_msi(device_t, device_t, int, int *);129static int thunder_pem_alloc_msix(device_t, device_t, int *);130static int thunder_pem_release_msix(device_t, device_t, int);131static int thunder_pem_map_msi(device_t, device_t, int, uint64_t *, uint32_t *);132static int thunder_pem_get_id(device_t, device_t, enum pci_id_type,133uintptr_t *);134static int thunder_pem_attach(device_t);135static int thunder_pem_deactivate_resource(device_t, device_t,136struct resource *);137static int thunder_pem_map_resource(device_t, device_t, struct resource *,138struct resource_map_request *, struct resource_map *);139static int thunder_pem_unmap_resource(device_t, device_t, struct resource *,140struct resource_map *);141static bus_dma_tag_t thunder_pem_get_dma_tag(device_t, device_t);142static int thunder_pem_detach(device_t);143static uint64_t thunder_pem_config_reg_read(struct thunder_pem_softc *, int);144static int thunder_pem_link_init(struct thunder_pem_softc *);145static int thunder_pem_maxslots(device_t);146static int thunder_pem_probe(device_t);147static uint32_t thunder_pem_read_config(device_t, u_int, u_int, u_int, u_int,148int);149static int thunder_pem_read_ivar(device_t, device_t, int, uintptr_t *);150static void thunder_pem_release_all(device_t);151static int thunder_pem_release_resource(device_t, device_t, struct resource *);152static struct rman * thunder_pem_get_rman(device_t, int, u_int);153static void thunder_pem_slix_s2m_regx_acc_modify(struct thunder_pem_softc *,154int, int);155static void thunder_pem_write_config(device_t, u_int, u_int, u_int, u_int,156uint32_t, int);157static int thunder_pem_write_ivar(device_t, device_t, int, uintptr_t);158159/* Global handlers for SLI interface */160static bus_space_handle_t sli0_s2m_regx_base = 0;161static bus_space_handle_t sli1_s2m_regx_base = 0;162163static device_method_t thunder_pem_methods[] = {164/* Device interface */165DEVMETHOD(device_probe, thunder_pem_probe),166DEVMETHOD(device_attach, thunder_pem_attach),167DEVMETHOD(device_detach, thunder_pem_detach),168169/* Bus interface */170DEVMETHOD(bus_read_ivar, thunder_pem_read_ivar),171DEVMETHOD(bus_write_ivar, thunder_pem_write_ivar),172DEVMETHOD(bus_get_rman, thunder_pem_get_rman),173DEVMETHOD(bus_alloc_resource, thunder_pem_alloc_resource),174DEVMETHOD(bus_release_resource, thunder_pem_release_resource),175DEVMETHOD(bus_adjust_resource, thunder_pem_adjust_resource),176DEVMETHOD(bus_activate_resource, thunder_pem_activate_resource),177DEVMETHOD(bus_deactivate_resource, thunder_pem_deactivate_resource),178DEVMETHOD(bus_map_resource, thunder_pem_map_resource),179DEVMETHOD(bus_unmap_resource, thunder_pem_unmap_resource),180DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),181DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),182183DEVMETHOD(bus_get_dma_tag, thunder_pem_get_dma_tag),184185/* pcib interface */186DEVMETHOD(pcib_maxslots, thunder_pem_maxslots),187DEVMETHOD(pcib_read_config, thunder_pem_read_config),188DEVMETHOD(pcib_write_config, thunder_pem_write_config),189DEVMETHOD(pcib_alloc_msix, thunder_pem_alloc_msix),190DEVMETHOD(pcib_release_msix, thunder_pem_release_msix),191DEVMETHOD(pcib_alloc_msi, thunder_pem_alloc_msi),192DEVMETHOD(pcib_release_msi, thunder_pem_release_msi),193DEVMETHOD(pcib_map_msi, thunder_pem_map_msi),194DEVMETHOD(pcib_get_id, thunder_pem_get_id),195196DEVMETHOD_END197};198199DEFINE_CLASS_0(pcib, thunder_pem_driver, thunder_pem_methods,200sizeof(struct thunder_pem_softc));201202extern struct bus_space memmap_bus;203204DRIVER_MODULE(thunder_pem, pci, thunder_pem_driver, 0, 0);205MODULE_DEPEND(thunder_pem, pci, 1, 1, 1);206207static int208thunder_pem_maxslots(device_t dev)209{210211#if 0212/* max slots per bus acc. to standard */213return (PCI_SLOTMAX);214#else215/*216* ARM64TODO Workaround - otherwise an em(4) interface appears to be217* present on every PCI function on the bus to which it is connected218*/219return (0);220#endif221}222223static int224thunder_pem_read_ivar(device_t dev, device_t child, int index,225uintptr_t *result)226{227struct thunder_pem_softc *sc;228int secondary_bus = 0;229230sc = device_get_softc(dev);231232if (index == PCIB_IVAR_BUS) {233secondary_bus = thunder_pem_config_reg_read(sc, PCIERC_CFG006);234*result = PCIERC_CFG006_SEC_BUS(secondary_bus);235return (0);236}237if (index == PCIB_IVAR_DOMAIN) {238*result = sc->id;239return (0);240}241242return (ENOENT);243}244245static int246thunder_pem_write_ivar(device_t dev, device_t child, int index,247uintptr_t value)248{249250return (ENOENT);251}252253static int254thunder_pem_activate_resource(device_t dev, device_t child, struct resource *r)255{256struct thunder_pem_softc *sc;257258sc = device_get_softc(dev);259switch (rman_get_type(r)) {260case PCI_RES_BUS:261return (pci_domain_activate_bus(sc->id, child, r));262case SYS_RES_MEMORY:263case SYS_RES_IOPORT:264return (bus_generic_rman_activate_resource(dev, child, r));265default:266return (bus_generic_activate_resource(dev, child, r));267}268}269270static int271thunder_pem_deactivate_resource(device_t dev, device_t child,272struct resource *r)273{274struct thunder_pem_softc *sc;275276sc = device_get_softc(dev);277switch (rman_get_type(r)) {278case PCI_RES_BUS:279return (pci_domain_deactivate_bus(sc->id, child, r));280case SYS_RES_MEMORY:281case SYS_RES_IOPORT:282return (bus_generic_rman_deactivate_resource(dev, child, r));283default:284return (bus_generic_deactivate_resource(dev, child, r));285}286}287288static int289thunder_pem_map_resource(device_t dev, device_t child, struct resource *r,290struct resource_map_request *argsp, struct resource_map *map)291{292struct resource_map_request args;293struct thunder_pem_softc *sc;294rman_res_t length, start;295int error;296297/* Resources must be active to be mapped. */298if (!(rman_get_flags(r) & RF_ACTIVE))299return (ENXIO);300301switch (rman_get_type(r)) {302case SYS_RES_MEMORY:303case SYS_RES_IOPORT:304break;305default:306return (EINVAL);307}308309resource_init_map_request(&args);310error = resource_validate_map_request(r, argsp, &args, &start, &length);311if (error)312return (error);313314sc = device_get_softc(dev);315start = range_addr_pci_to_phys(sc->ranges, start);316error = bus_space_map(&memmap_bus, start, length, 0, &map->r_bushandle);317if (error)318return (error);319map->r_bustag = &memmap_bus;320map->r_vaddr = (void *)map->r_bushandle;321map->r_size = length;322return (0);323}324325static int326thunder_pem_unmap_resource(device_t dev, device_t child, struct resource *r,327struct resource_map *map)328{329330switch (rman_get_type(r)) {331case SYS_RES_MEMORY:332case SYS_RES_IOPORT:333bus_space_unmap(map->r_bustag, map->r_bushandle, map->r_size);334return (0);335default:336return (EINVAL);337}338}339340static int341thunder_pem_adjust_resource(device_t dev, device_t child, struct resource *res,342rman_res_t start, rman_res_t end)343{344struct thunder_pem_softc *sc;345346sc = device_get_softc(dev);347switch (rman_get_type(res)) {348case PCI_RES_BUS:349return (pci_domain_adjust_bus(sc->id, child, res, start, end));350case SYS_RES_MEMORY:351case SYS_RES_IOPORT:352return (bus_generic_rman_adjust_resource(dev, child, res, start,353end));354default:355return (bus_generic_adjust_resource(dev, child, res, start,356end));357}358}359360static bus_dma_tag_t361thunder_pem_get_dma_tag(device_t dev, device_t child)362{363struct thunder_pem_softc *sc;364365sc = device_get_softc(dev);366return (sc->dmat);367}368369static int370thunder_pem_alloc_msi(device_t pci, device_t child, int count, int maxcount,371int *irqs)372{373device_t bus;374375bus = device_get_parent(pci);376return (PCIB_ALLOC_MSI(device_get_parent(bus), child, count, maxcount,377irqs));378}379380static int381thunder_pem_release_msi(device_t pci, device_t child, int count, int *irqs)382{383device_t bus;384385bus = device_get_parent(pci);386return (PCIB_RELEASE_MSI(device_get_parent(bus), child, count, irqs));387}388389static int390thunder_pem_alloc_msix(device_t pci, device_t child, int *irq)391{392device_t bus;393394bus = device_get_parent(pci);395return (PCIB_ALLOC_MSIX(device_get_parent(bus), child, irq));396}397398static int399thunder_pem_release_msix(device_t pci, device_t child, int irq)400{401device_t bus;402403bus = device_get_parent(pci);404return (PCIB_RELEASE_MSIX(device_get_parent(bus), child, irq));405}406407static int408thunder_pem_map_msi(device_t pci, device_t child, int irq, uint64_t *addr,409uint32_t *data)410{411device_t bus;412413bus = device_get_parent(pci);414return (PCIB_MAP_MSI(device_get_parent(bus), child, irq, addr, data));415}416417static int418thunder_pem_get_id(device_t pci, device_t child, enum pci_id_type type,419uintptr_t *id)420{421int bsf;422int pem;423424if (type != PCI_ID_MSI)425return (pcib_get_id(pci, child, type, id));426427bsf = pci_get_rid(child);428429/* PEM (PCIe MAC/root complex) number is equal to domain */430pem = pci_get_domain(child);431432/*433* Set appropriate device ID (passed by the HW along with434* the transaction to memory) for different root complex435* numbers using hard-coded domain portion for each group.436*/437if (pem < 3)438*id = (0x1 << PCI_RID_DOMAIN_SHIFT) | bsf;439else if (pem < 6)440*id = (0x3 << PCI_RID_DOMAIN_SHIFT) | bsf;441else if (pem < 9)442*id = (0x9 << PCI_RID_DOMAIN_SHIFT) | bsf;443else if (pem < 12)444*id = (0xB << PCI_RID_DOMAIN_SHIFT) | bsf;445else446return (ENXIO);447448return (0);449}450451static int452thunder_pem_identify(device_t dev)453{454struct thunder_pem_softc *sc;455rman_res_t start;456457sc = device_get_softc(dev);458start = rman_get_start(sc->reg);459460/* Calculate PEM designations from its address */461sc->node = (start >> SLI_NODE_SHIFT) & SLI_NODE_MASK;462sc->id = ((start >> SLI_ID_SHIFT) & SLI_ID_MASK) +463(SLI_PEMS_PER_NODE * sc->node);464sc->sli = sc->id % SLI_PEMS_PER_GROUP;465sc->sli_group = (sc->id / SLI_PEMS_PER_GROUP) % SLI_GROUPS_PER_NODE;466sc->sli_window_base = SLI_BASE |467(((uint64_t)sc->node) << SLI_NODE_SHIFT) |468((uint64_t)sc->sli_group << SLI_GROUP_SHIFT);469sc->sli_window_base += SLI_WINDOW_SPACING * sc->sli;470471return (0);472}473474static void475thunder_pem_slix_s2m_regx_acc_modify(struct thunder_pem_softc *sc,476int sli_group, int slix)477{478uint64_t regval;479bus_space_handle_t handle = 0;480481KASSERT(slix >= 0 && slix <= SLI_ACC_REG_CNT, ("Invalid SLI index"));482483if (sli_group == 0)484handle = sli0_s2m_regx_base;485else if (sli_group == 1)486handle = sli1_s2m_regx_base;487else488device_printf(sc->dev, "SLI group is not correct\n");489490if (handle) {491/* Clear lower 32-bits of the SLIx register */492regval = bus_space_read_8(sc->reg_bst, handle,493PEM_CFG_SLIX_TO_REG(slix));494regval &= ~(0xFFFFFFFFUL);495bus_space_write_8(sc->reg_bst, handle,496PEM_CFG_SLIX_TO_REG(slix), regval);497}498}499500static int501thunder_pem_link_init(struct thunder_pem_softc *sc)502{503uint64_t regval;504505/* check whether PEM is safe to access. */506regval = bus_space_read_8(sc->reg_bst, sc->reg_bsh, PEM_ON_REG);507if ((regval & PEM_CFG_LINK_MASK) != PEM_CFG_LINK_RDY) {508device_printf(sc->dev, "PEM%d is not ON\n", sc->id);509return (ENXIO);510}511512regval = bus_space_read_8(sc->reg_bst, sc->reg_bsh, PEM_CTL_STATUS);513regval |= PEM_LINK_ENABLE;514bus_space_write_8(sc->reg_bst, sc->reg_bsh, PEM_CTL_STATUS, regval);515516/* Wait 1ms as per Cavium specification */517DELAY(1000);518519regval = thunder_pem_config_reg_read(sc, PCIERC_CFG032);520521if (((regval & PEM_LINK_DLLA) == 0) || ((regval & PEM_LINK_LT) != 0)) {522device_printf(sc->dev, "PCIe RC: Port %d Link Timeout\n",523sc->id);524return (ENXIO);525}526527return (0);528}529530static int531thunder_pem_init(struct thunder_pem_softc *sc)532{533int i, retval = 0;534535retval = thunder_pem_link_init(sc);536if (retval) {537device_printf(sc->dev, "%s failed\n", __func__);538return retval;539}540541/* To support 32-bit PCIe devices, set S2M_REGx_ACC[BA]=0x0 */542for (i = 0; i < SLI_ACC_REG_CNT; i++) {543thunder_pem_slix_s2m_regx_acc_modify(sc, sc->sli_group, i);544}545546return (retval);547}548549static uint64_t550thunder_pem_config_reg_read(struct thunder_pem_softc *sc, int reg)551{552uint64_t data;553554/* Write to ADDR register */555bus_space_write_8(sc->reg_bst, sc->reg_bsh, PEM_CFG_RD,556PEM_CFG_RD_REG_ALIGN(reg));557bus_space_barrier(sc->reg_bst, sc->reg_bsh, PEM_CFG_RD, 8,558BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);559/* Read from DATA register */560data = PEM_CFG_RD_REG_DATA(bus_space_read_8(sc->reg_bst, sc->reg_bsh,561PEM_CFG_RD));562563return (data);564}565566static uint32_t567thunder_pem_read_config(device_t dev, u_int bus, u_int slot,568u_int func, u_int reg, int bytes)569{570uint64_t offset;571uint32_t data;572struct thunder_pem_softc *sc;573bus_space_tag_t t;574bus_space_handle_t h;575576if ((bus > PCI_BUSMAX) || (slot > PCI_SLOTMAX) ||577(func > PCI_FUNCMAX) || (reg > PCIE_REGMAX))578return (~0U);579580sc = device_get_softc(dev);581582/* Calculate offset */583offset = (bus << PEM_BUS_SHIFT) | (slot << PEM_SLOT_SHIFT) |584(func << PEM_FUNC_SHIFT);585t = sc->reg_bst;586h = sc->pem_sli_base;587588bus_space_map(sc->reg_bst, sc->sli_window_base + offset,589PCIE_REGMAX, 0, &h);590591switch (bytes) {592case 1:593data = bus_space_read_1(t, h, reg);594break;595case 2:596data = le16toh(bus_space_read_2(t, h, reg));597break;598case 4:599data = le32toh(bus_space_read_4(t, h, reg));600break;601default:602data = ~0U;603break;604}605606bus_space_unmap(sc->reg_bst, h, PCIE_REGMAX);607608return (data);609}610611static void612thunder_pem_write_config(device_t dev, u_int bus, u_int slot,613u_int func, u_int reg, uint32_t val, int bytes)614{615uint64_t offset;616struct thunder_pem_softc *sc;617bus_space_tag_t t;618bus_space_handle_t h;619620if ((bus > PCI_BUSMAX) || (slot > PCI_SLOTMAX) ||621(func > PCI_FUNCMAX) || (reg > PCIE_REGMAX))622return;623624sc = device_get_softc(dev);625626/* Calculate offset */627offset = (bus << PEM_BUS_SHIFT) | (slot << PEM_SLOT_SHIFT) |628(func << PEM_FUNC_SHIFT);629t = sc->reg_bst;630h = sc->pem_sli_base;631632bus_space_map(sc->reg_bst, sc->sli_window_base + offset,633PCIE_REGMAX, 0, &h);634635switch (bytes) {636case 1:637bus_space_write_1(t, h, reg, val);638break;639case 2:640bus_space_write_2(t, h, reg, htole16(val));641break;642case 4:643bus_space_write_4(t, h, reg, htole32(val));644break;645default:646break;647}648649bus_space_unmap(sc->reg_bst, h, PCIE_REGMAX);650}651652static struct resource *653thunder_pem_alloc_resource(device_t dev, device_t child, int type, int *rid,654rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)655{656struct thunder_pem_softc *sc = device_get_softc(dev);657struct resource *res;658device_t parent_dev;659660switch (type) {661case PCI_RES_BUS:662return (pci_domain_alloc_bus(sc->id, child, rid, start, end,663count, flags));664case SYS_RES_IOPORT:665case SYS_RES_MEMORY:666break;667default:668/* Find parent device. On ThunderX we know an exact path. */669parent_dev = device_get_parent(device_get_parent(dev));670return (BUS_ALLOC_RESOURCE(parent_dev, dev, type, rid, start,671end, count, flags));672}673674if (!RMAN_IS_DEFAULT_RANGE(start, end)) {675/*676* We might get PHYS addresses here inherited from EFI.677* Convert to PCI if necessary.678*/679if (range_addr_is_phys(sc->ranges, start, count)) {680start = range_addr_phys_to_pci(sc->ranges, start);681end = start + count - 1;682}683}684685if (bootverbose) {686device_printf(dev,687"thunder_pem_alloc_resource: start=%#lx, end=%#lx, count=%#lx\n",688start, end, count);689}690691res = bus_generic_rman_alloc_resource(dev, child, type, rid, start,692end, count, flags);693if (res == NULL && bootverbose) {694device_printf(dev, "%s FAIL: type=%d, rid=%d, "695"start=%016lx, end=%016lx, count=%016lx, flags=%x\n",696__func__, type, *rid, start, end, count, flags);697}698699return (res);700}701702static int703thunder_pem_release_resource(device_t dev, device_t child, struct resource *res)704{705device_t parent_dev;706struct thunder_pem_softc *sc = device_get_softc(dev);707708switch (rman_get_type(res)) {709case PCI_RES_BUS:710return (pci_domain_release_bus(sc->id, child, res));711case SYS_RES_MEMORY:712case SYS_RES_IOPORT:713return (bus_generic_rman_release_resource(dev, child, res));714default:715/* Find parent device. On ThunderX we know an exact path. */716parent_dev = device_get_parent(device_get_parent(dev));717return (BUS_RELEASE_RESOURCE(parent_dev, child, res));718}719}720721static struct rman *722thunder_pem_get_rman(device_t bus, int type, u_int flags)723{724struct thunder_pem_softc *sc;725726sc = device_get_softc(bus);727switch (type) {728case SYS_RES_IOPORT:729return (&sc->io_rman);730case SYS_RES_MEMORY:731return (&sc->mem_rman);732default:733break;734}735736return (NULL);737}738739static int740thunder_pem_probe(device_t dev)741{742uint16_t pci_vendor_id;743uint16_t pci_device_id;744745pci_vendor_id = pci_get_vendor(dev);746pci_device_id = pci_get_device(dev);747748if ((pci_vendor_id == THUNDER_PEM_VENDOR_ID) &&749(pci_device_id == THUNDER_PEM_DEVICE_ID)) {750device_set_desc(dev, THUNDER_PEM_DESC);751return (0);752}753754return (ENXIO);755}756757static int758thunder_pem_attach(device_t dev)759{760struct resource_map_request req;761struct resource_map map;762devclass_t pci_class;763device_t parent;764struct thunder_pem_softc *sc;765int error;766int rid;767int tuple;768uint64_t base, size;769struct rman *rman;770771sc = device_get_softc(dev);772sc->dev = dev;773774/* Allocate memory for resource */775pci_class = devclass_find("pci");776parent = device_get_parent(dev);777if (device_get_devclass(parent) == pci_class)778rid = PCIR_BAR(0);779else780rid = RID_PEM_SPACE;781782sc->reg = bus_alloc_resource_any(dev, SYS_RES_MEMORY,783&rid, RF_ACTIVE | RF_UNMAPPED);784if (sc->reg == NULL) {785device_printf(dev, "Failed to allocate resource\n");786return (ENXIO);787}788resource_init_map_request(&req);789req.memattr = VM_MEMATTR_DEVICE_NP;790error = bus_map_resource(dev, SYS_RES_MEMORY, sc->reg, &req, &map);791if (error != 0) {792device_printf(dev, "could not map memory.\n");793return (error);794}795rman_set_mapping(sc->reg, &map);796797sc->reg_bst = rman_get_bustag(sc->reg);798sc->reg_bsh = rman_get_bushandle(sc->reg);799800/* Create the parent DMA tag to pass down the coherent flag */801error = bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */8021, 0, /* alignment, bounds */803BUS_SPACE_MAXADDR, /* lowaddr */804BUS_SPACE_MAXADDR, /* highaddr */805NULL, NULL, /* filter, filterarg */806BUS_SPACE_MAXSIZE, /* maxsize */807BUS_SPACE_UNRESTRICTED, /* nsegments */808BUS_SPACE_MAXSIZE, /* maxsegsize */809BUS_DMA_COHERENT, /* flags */810NULL, NULL, /* lockfunc, lockarg */811&sc->dmat);812if (error != 0)813return (error);814815/* Map SLI, do it only once */816if (!sli0_s2m_regx_base) {817bus_space_map(sc->reg_bst, SLIX_S2M_REGX_ACC,818SLIX_S2M_REGX_ACC_SIZE, 0, &sli0_s2m_regx_base);819}820if (!sli1_s2m_regx_base) {821bus_space_map(sc->reg_bst, SLIX_S2M_REGX_ACC +822SLIX_S2M_REGX_ACC_SPACING, SLIX_S2M_REGX_ACC_SIZE, 0,823&sli1_s2m_regx_base);824}825826if ((sli0_s2m_regx_base == 0) || (sli1_s2m_regx_base == 0)) {827device_printf(dev,828"bus_space_map failed to map slix_s2m_regx_base\n");829goto fail;830}831832/* Identify PEM */833if (thunder_pem_identify(dev) != 0)834goto fail;835836/* Initialize rman and allocate regions */837sc->mem_rman.rm_type = RMAN_ARRAY;838sc->mem_rman.rm_descr = "PEM PCIe Memory";839error = rman_init(&sc->mem_rman);840if (error != 0) {841device_printf(dev, "memory rman_init() failed. error = %d\n",842error);843goto fail;844}845sc->io_rman.rm_type = RMAN_ARRAY;846sc->io_rman.rm_descr = "PEM PCIe IO";847error = rman_init(&sc->io_rman);848if (error != 0) {849device_printf(dev, "IO rman_init() failed. error = %d\n",850error);851goto fail_mem;852}853854/*855* We ignore the values that may have been provided in FDT856* and configure ranges according to the below formula857* for all types of devices. This is because some DTBs provided858* by EFI do not have proper ranges property or don't have them859* at all.860*/861/* Fill memory window */862sc->ranges[0].pci_base = PCI_MEMORY_BASE;863sc->ranges[0].size = PCI_MEMORY_SIZE;864sc->ranges[0].phys_base = sc->sli_window_base + SLI_PCI_OFFSET +865sc->ranges[0].pci_base;866sc->ranges[0].flags = SYS_RES_MEMORY;867868/* Fill IO window */869sc->ranges[1].pci_base = PCI_IO_BASE;870sc->ranges[1].size = PCI_IO_SIZE;871sc->ranges[1].phys_base = sc->sli_window_base + SLI_PCI_OFFSET +872sc->ranges[1].pci_base;873sc->ranges[1].flags = SYS_RES_IOPORT;874875for (tuple = 0; tuple < MAX_RANGES_TUPLES; tuple++) {876base = sc->ranges[tuple].pci_base;877size = sc->ranges[tuple].size;878if (size == 0)879continue; /* empty range element */880881rman = thunder_pem_get_rman(dev, sc->ranges[tuple].flags, 0);882if (rman != NULL)883error = rman_manage_region(rman, base,884base + size - 1);885else886error = EINVAL;887if (error) {888device_printf(dev,889"rman_manage_region() failed. error = %d\n", error);890rman_fini(&sc->mem_rman);891return (error);892}893if (bootverbose) {894device_printf(dev,895"\tPCI addr: 0x%jx, CPU addr: 0x%jx, Size: 0x%jx, Flags:0x%jx\n",896sc->ranges[tuple].pci_base,897sc->ranges[tuple].phys_base,898sc->ranges[tuple].size,899sc->ranges[tuple].flags);900}901}902903if (thunder_pem_init(sc)) {904device_printf(dev, "Failure during PEM init\n");905goto fail_io;906}907908device_add_child(dev, "pci", DEVICE_UNIT_ANY);909bus_attach_children(dev);910return (0);911912fail_io:913rman_fini(&sc->io_rman);914fail_mem:915rman_fini(&sc->mem_rman);916fail:917bus_free_resource(dev, SYS_RES_MEMORY, sc->reg);918return (ENXIO);919}920921static void922thunder_pem_release_all(device_t dev)923{924struct thunder_pem_softc *sc;925926sc = device_get_softc(dev);927928rman_fini(&sc->io_rman);929rman_fini(&sc->mem_rman);930931if (sc->reg != NULL)932bus_free_resource(dev, SYS_RES_MEMORY, sc->reg);933}934935static int936thunder_pem_detach(device_t dev)937{938939thunder_pem_release_all(dev);940941return (0);942}943944945