Path: blob/main/sys/arm/broadcom/bcm2835/bcm2838_pci.c
39566 views
/*-1* SPDX-License-Identifier: ISC2*3* Copyright (c) 2020 Dr Robert Harvey Crowston <[email protected]>4*5* Permission to use, copy, modify, and distribute this software for any6* purpose with or without fee is hereby granted, provided that the above7* copyright notice and this permission notice appear in all copies.8*9* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES10* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF11* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR12* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES13* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN14* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF15* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.16*17*18*/1920/*21* BCM2838-compatible PCI-express controller.22*23* Broadcom likes to give the same chip lots of different names. The name of24* this driver is taken from the Raspberry Pi 4 Broadcom 2838 chip.25*/2627#include <sys/param.h>28#include <sys/systm.h>29#include <sys/endian.h>30#include <sys/kernel.h>31#include <sys/module.h>32#include <sys/bus.h>33#include <sys/proc.h>34#include <sys/rman.h>35#include <sys/intr.h>36#include <sys/mutex.h>3738#include <dev/ofw/openfirm.h>39#include <dev/ofw/ofw_bus.h>40#include <dev/ofw/ofw_bus_subr.h>4142#include <dev/pci/pci_host_generic.h>43#include <dev/pci/pci_host_generic_fdt.h>44#include <dev/pci/pcivar.h>45#include <dev/pci/pcireg.h>46#include <dev/pci/pcib_private.h>4748#include <machine/bus.h>49#include <machine/intr.h>5051#include "pcib_if.h"52#include "msi_if.h"5354#define PCI_ID_VAL3 0x43c55#define CLASS_SHIFT 0x1056#define SUBCLASS_SHIFT 0x85758#define REG_CONTROLLER_HW_REV 0x406c59#define REG_BRIDGE_CTRL 0x921060#define BRIDGE_DISABLE_FLAG 0x161#define BRIDGE_RESET_FLAG 0x262#define REG_PCIE_HARD_DEBUG 0x420463#define REG_DMA_CONFIG 0x400864#define REG_DMA_WINDOW_LOW 0x403465#define REG_DMA_WINDOW_HIGH 0x403866#define REG_DMA_WINDOW_1 0x403c67#define REG_BRIDGE_GISB_WINDOW 0x402c68#define REG_BRIDGE_STATE 0x406869#define REG_BRIDGE_LINK_STATE 0x00bc70#define REG_BUS_WINDOW_LOW 0x400c71#define REG_BUS_WINDOW_HIGH 0x401072#define REG_CPU_WINDOW_LOW 0x407073#define REG_CPU_WINDOW_START_HIGH 0x408074#define REG_CPU_WINDOW_END_HIGH 0x40847576#define REG_MSI_ADDR_LOW 0x404477#define REG_MSI_ADDR_HIGH 0x404878#define REG_MSI_CONFIG 0x404c79#define REG_MSI_CLR 0x450880#define REG_MSI_MASK_CLR 0x451481#define REG_MSI_RAISED 0x450082#define REG_MSI_EOI 0x406083#define NUM_MSI 328485#define REG_EP_CONFIG_CHOICE 0x900086#define REG_EP_CONFIG_DATA 0x80008788#define L1SS_ENABLE 0x0020000089#define CLKREQ_ENABLE 0x29091/*92* The system memory controller can address up to 16 GiB of physical memory93* (although at time of writing the largest memory size available for purchase94* is 8 GiB). However, the system DMA controller is capable of accessing only a95* limited portion of the address space. Worse, the PCI-e controller has further96* constraints for DMA, and those limitations are not wholly clear to the97* author. NetBSD and Linux allow DMA on the lower 3 GiB of the physical memory,98* but experimentation shows DMA performed above 960 MiB results in data99* corruption with this driver. The limit of 960 MiB is taken from OpenBSD, but100* apparently that value was chosen for satisfying a constraint of an unrelated101* peripheral.102*103* Whatever the true maximum address, 960 MiB works.104*/105#define DMA_HIGH_LIMIT 0x3c000000106#define MAX_MEMORY_LOG2 0x21107#define REG_VALUE_DMA_WINDOW_LOW (MAX_MEMORY_LOG2 - 0xf)108#define REG_VALUE_DMA_WINDOW_HIGH 0x0109#define DMA_WINDOW_ENABLE 0x3000110#define REG_VALUE_DMA_WINDOW_CONFIG \111(((MAX_MEMORY_LOG2 - 0xf) << 0x1b) | DMA_WINDOW_ENABLE)112113#define REG_VALUE_MSI_CONFIG 0xffe06540114115struct bcm_pcib_irqsrc {116struct intr_irqsrc isrc;117u_int irq;118bool allocated;119};120121struct bcm_pcib_softc {122struct generic_pcie_fdt_softc base;123device_t dev;124bus_dma_tag_t dmat;125struct mtx config_mtx;126struct mtx msi_mtx;127struct resource *msi_irq_res;128void *msi_intr_cookie;129struct bcm_pcib_irqsrc *msi_isrcs;130pci_addr_t msi_addr;131};132133static struct ofw_compat_data compat_data[] = {134{"brcm,bcm2711-pcie", 1},135{"brcm,bcm7211-pcie", 1},136{"brcm,bcm7445-pcie", 1},137{NULL, 0}138};139140static int141bcm_pcib_probe(device_t dev)142{143144if (!ofw_bus_status_okay(dev))145return (ENXIO);146147if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)148return (ENXIO);149150device_set_desc(dev,151"BCM2838-compatible PCI-express controller");152return (BUS_PROBE_DEFAULT);153}154155static bus_dma_tag_t156bcm_pcib_get_dma_tag(device_t dev, device_t child)157{158struct bcm_pcib_softc *sc;159160sc = device_get_softc(dev);161return (sc->dmat);162}163164static void165bcm_pcib_set_reg(struct bcm_pcib_softc *sc, uint32_t reg, uint32_t val)166{167168bus_write_4(sc->base.base.res, reg, htole32(val));169}170171static uint32_t172bcm_pcib_read_reg(struct bcm_pcib_softc *sc, uint32_t reg)173{174175return (le32toh(bus_read_4(sc->base.base.res, reg)));176}177178static void179bcm_pcib_reset_controller(struct bcm_pcib_softc *sc)180{181uint32_t val;182183val = bcm_pcib_read_reg(sc, REG_BRIDGE_CTRL);184val = val | BRIDGE_RESET_FLAG | BRIDGE_DISABLE_FLAG;185bcm_pcib_set_reg(sc, REG_BRIDGE_CTRL, val);186187DELAY(100);188189val = bcm_pcib_read_reg(sc, REG_BRIDGE_CTRL);190val = val & ~BRIDGE_RESET_FLAG;191bcm_pcib_set_reg(sc, REG_BRIDGE_CTRL, val);192193DELAY(100);194195bcm_pcib_set_reg(sc, REG_PCIE_HARD_DEBUG, 0);196197DELAY(100);198}199200static void201bcm_pcib_enable_controller(struct bcm_pcib_softc *sc)202{203uint32_t val;204205val = bcm_pcib_read_reg(sc, REG_BRIDGE_CTRL);206val = val & ~BRIDGE_DISABLE_FLAG;207bcm_pcib_set_reg(sc, REG_BRIDGE_CTRL, val);208209DELAY(100);210}211212static int213bcm_pcib_check_ranges(device_t dev)214{215struct bcm_pcib_softc *sc;216struct pcie_range *ranges;217int error = 0, i;218219sc = device_get_softc(dev);220ranges = &sc->base.base.ranges[0];221222/* The first range needs to be non-zero. */223if (ranges[0].size == 0) {224device_printf(dev, "error: first outbound memory range "225"(pci addr: 0x%jx, cpu addr: 0x%jx) has zero size.\n",226ranges[0].pci_base, ranges[0].phys_base);227error = ENXIO;228}229230/*231* The controller can actually handle three distinct ranges, but we232* only implement support for one.233*/234for (i = 1; (bootverbose || error) && i < MAX_RANGES_TUPLES; ++i) {235if (ranges[i].size > 0)236device_printf(dev,237"note: outbound memory range %d (pci addr: 0x%jx, "238"cpu addr: 0x%jx, size: 0x%jx) will be ignored.\n",239i, ranges[i].pci_base, ranges[i].phys_base,240ranges[i].size);241}242243return (error);244}245246static const char *247bcm_pcib_link_state_string(uint32_t mode)248{249250switch(mode & PCIEM_LINK_STA_SPEED) {251case 0:252return ("not up");253case 1:254return ("2.5 GT/s");255case 2:256return ("5.0 GT/s");257case 4:258return ("8.0 GT/s");259default:260return ("unknown");261}262}263264static bus_addr_t265bcm_get_offset_and_prepare_config(struct bcm_pcib_softc *sc, u_int bus,266u_int slot, u_int func, u_int reg)267{268/*269* Config for an end point is only available through a narrow window for270* one end point at a time. We first tell the controller which end point271* we want, then access it through the window.272*/273uint32_t func_index;274275if (bus == 0 && slot == 0 && func == 0)276/*277* Special case for root device; its config is always available278* through the zero-offset.279*/280return (reg);281282/* Tell the controller to show us the config in question. */283func_index = PCIE_ADDR_OFFSET(bus, slot, func, 0);284bcm_pcib_set_reg(sc, REG_EP_CONFIG_CHOICE, func_index);285286return (REG_EP_CONFIG_DATA + reg);287}288289static bool290bcm_pcib_is_valid_quad(struct bcm_pcib_softc *sc, u_int bus, u_int slot,291u_int func, u_int reg)292{293294if ((bus < sc->base.base.bus_start) || (bus > sc->base.base.bus_end))295return (false);296if ((slot > PCI_SLOTMAX) || (func > PCI_FUNCMAX) || (reg > PCIE_REGMAX))297return (false);298299if (bus == 0 && slot == 0 && func == 0)300return (true);301if (bus == 0)302/*303* Probing other slots and funcs on bus 0 will lock up the304* memory controller.305*/306return (false);307308return (true);309}310311static uint32_t312bcm_pcib_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg,313int bytes)314{315struct bcm_pcib_softc *sc;316bus_addr_t offset;317uint32_t data;318319sc = device_get_softc(dev);320if (!bcm_pcib_is_valid_quad(sc, bus, slot, func, reg))321return (~0U);322323mtx_lock(&sc->config_mtx);324offset = bcm_get_offset_and_prepare_config(sc, bus, slot, func, reg);325326switch (bytes) {327case 1:328data = bus_read_1(sc->base.base.res, offset);329break;330case 2:331data = le16toh(bus_read_2(sc->base.base.res, offset));332break;333case 4:334data = le32toh(bus_read_4(sc->base.base.res, offset));335break;336default:337data = ~0U;338break;339}340341mtx_unlock(&sc->config_mtx);342return (data);343}344345static void346bcm_pcib_write_config(device_t dev, u_int bus, u_int slot,347u_int func, u_int reg, uint32_t val, int bytes)348{349struct bcm_pcib_softc *sc;350uint32_t offset;351352sc = device_get_softc(dev);353if (!bcm_pcib_is_valid_quad(sc, bus, slot, func, reg))354return;355356mtx_lock(&sc->config_mtx);357offset = bcm_get_offset_and_prepare_config(sc, bus, slot, func, reg);358359switch (bytes) {360case 1:361bus_write_1(sc->base.base.res, offset, val);362break;363case 2:364bus_write_2(sc->base.base.res, offset, htole16(val));365break;366case 4:367bus_write_4(sc->base.base.res, offset, htole32(val));368break;369default:370break;371}372373mtx_unlock(&sc->config_mtx);374}375376static void377bcm_pcib_msi_intr_process(struct bcm_pcib_softc *sc, uint32_t interrupt_bitmap,378struct trapframe *tf)379{380struct bcm_pcib_irqsrc *irqsrc;381uint32_t bit, irq;382383while ((bit = ffs(interrupt_bitmap))) {384irq = bit - 1;385386/* Acknowledge interrupt. */387bcm_pcib_set_reg(sc, REG_MSI_CLR, 1 << irq);388389/* Send EOI. */390bcm_pcib_set_reg(sc, REG_MSI_EOI, 1);391392/* Despatch to handler. */393irqsrc = &sc->msi_isrcs[irq];394if (intr_isrc_dispatch(&irqsrc->isrc, tf))395device_printf(sc->dev,396"note: unexpected interrupt (%d) triggered.\n",397irq);398399/* Done with this interrupt. */400interrupt_bitmap = interrupt_bitmap & ~(1 << irq);401}402}403404static int405bcm_pcib_msi_intr(void *arg)406{407struct bcm_pcib_softc *sc;408struct trapframe *tf;409uint32_t interrupt_bitmap;410411sc = (struct bcm_pcib_softc *) arg;412tf = curthread->td_intr_frame;413414while ((interrupt_bitmap = bcm_pcib_read_reg(sc, REG_MSI_RAISED)))415bcm_pcib_msi_intr_process(sc, interrupt_bitmap, tf);416417return (FILTER_HANDLED);418}419420static int421bcm_pcib_alloc_msi(device_t dev, device_t child, int count, int maxcount,422device_t *pic, struct intr_irqsrc **srcs)423{424struct bcm_pcib_softc *sc;425int first_int, i;426427sc = device_get_softc(dev);428mtx_lock(&sc->msi_mtx);429430/* Find a continguous region of free message-signalled interrupts. */431for (first_int = 0; first_int + count < NUM_MSI; ) {432for (i = first_int; i < first_int + count; ++i) {433if (sc->msi_isrcs[i].allocated)434goto next;435}436goto found;437next:438first_int = i + 1;439}440441/* No appropriate region available. */442mtx_unlock(&sc->msi_mtx);443device_printf(dev, "warning: failed to allocate %d MSI messages.\n",444count);445return (ENXIO);446447found:448/* Mark the messages as in use. */449for (i = 0; i < count; ++i) {450sc->msi_isrcs[i + first_int].allocated = true;451srcs[i] = &(sc->msi_isrcs[i + first_int].isrc);452}453454mtx_unlock(&sc->msi_mtx);455*pic = device_get_parent(dev);456457return (0);458}459460static int461bcm_pcib_map_msi(device_t dev, device_t child, struct intr_irqsrc *isrc,462uint64_t *addr, uint32_t *data)463{464struct bcm_pcib_softc *sc;465struct bcm_pcib_irqsrc *msi_msg;466467sc = device_get_softc(dev);468msi_msg = (struct bcm_pcib_irqsrc *) isrc;469470*addr = sc->msi_addr;471*data = (REG_VALUE_MSI_CONFIG & 0xffff) | msi_msg->irq;472return (0);473}474475static int476bcm_pcib_release_msi(device_t dev, device_t child, int count,477struct intr_irqsrc **isrc)478{479struct bcm_pcib_softc *sc;480struct bcm_pcib_irqsrc *msi_isrc;481int i;482483sc = device_get_softc(dev);484mtx_lock(&sc->msi_mtx);485486for (i = 0; i < count; i++) {487msi_isrc = (struct bcm_pcib_irqsrc *) isrc[i];488msi_isrc->allocated = false;489}490491mtx_unlock(&sc->msi_mtx);492return (0);493}494495static int496bcm_pcib_msi_attach(device_t dev)497{498struct bcm_pcib_softc *sc;499phandle_t node, xref;500char const *bcm_name;501int error, i, rid;502503sc = device_get_softc(dev);504sc->msi_addr = 0xffffffffc;505506/* Clear any pending interrupts. */507bcm_pcib_set_reg(sc, REG_MSI_CLR, 0xffffffff);508509rid = 1;510sc->msi_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,511RF_ACTIVE);512if (sc->msi_irq_res == NULL) {513device_printf(dev, "could not allocate MSI irq resource.\n");514return (ENXIO);515}516517sc->msi_isrcs = malloc(sizeof(*sc->msi_isrcs) * NUM_MSI, M_DEVBUF,518M_WAITOK | M_ZERO);519520error = bus_setup_intr(dev, sc->msi_irq_res, INTR_TYPE_BIO |521INTR_MPSAFE, bcm_pcib_msi_intr, NULL, sc, &sc->msi_intr_cookie);522if (error != 0) {523device_printf(dev, "error: failed to setup MSI handler.\n");524return (error);525}526527bcm_name = device_get_nameunit(dev);528for (i = 0; i < NUM_MSI; i++) {529sc->msi_isrcs[i].irq = i;530error = intr_isrc_register(&sc->msi_isrcs[i].isrc, dev, 0,531"%s,%u", bcm_name, i);532if (error != 0) {533device_printf(dev,534"error: failed to register interrupt %d.\n", i);535return (error);536}537}538539node = ofw_bus_get_node(dev);540xref = OF_xref_from_node(node);541OF_device_register_xref(xref, dev);542543error = intr_msi_register(dev, xref);544if (error != 0)545return (error);546547mtx_init(&sc->msi_mtx, "bcm_pcib: msi_mtx", NULL, MTX_DEF);548549bcm_pcib_set_reg(sc, REG_MSI_MASK_CLR, 0xffffffff);550bcm_pcib_set_reg(sc, REG_MSI_ADDR_LOW, (sc->msi_addr & 0xffffffff) | 1);551bcm_pcib_set_reg(sc, REG_MSI_ADDR_HIGH, (sc->msi_addr >> 32));552bcm_pcib_set_reg(sc, REG_MSI_CONFIG, REG_VALUE_MSI_CONFIG);553554return (0);555}556557static void558bcm_pcib_relocate_bridge_window(device_t dev)559{560/*561* In principle an out-of-bounds bridge window could be automatically562* adjusted at resource-activation time to lie within the bus address563* space by pcib_grow_window(), but that is not possible because the564* out-of-bounds resource allocation fails at allocation time. Instead,565* we will just fix up the window on the controller here, before it is566* re-discovered by pcib_probe_windows().567*/568569struct bcm_pcib_softc *sc;570pci_addr_t base, size, new_base, new_limit;571uint16_t val;572573sc = device_get_softc(dev);574575val = bcm_pcib_read_config(dev, 0, 0, 0, PCIR_MEMBASE_1, 2);576base = PCI_PPBMEMBASE(0, val);577578val = bcm_pcib_read_config(dev, 0, 0, 0, PCIR_MEMLIMIT_1, 2);579size = PCI_PPBMEMLIMIT(0, val) - base;580581new_base = sc->base.base.ranges[0].pci_base;582val = (uint16_t) (new_base >> 16);583bcm_pcib_write_config(dev, 0, 0, 0, PCIR_MEMBASE_1, val, 2);584585new_limit = new_base + size;586val = (uint16_t) (new_limit >> 16);587bcm_pcib_write_config(dev, 0, 0, 0, PCIR_MEMLIMIT_1, val, 2);588}589590static uint32_t591encode_cpu_window_low(pci_addr_t phys_base, bus_size_t size)592{593594return (((phys_base >> 0x10) & 0xfff0) |595((phys_base + size - 1) & 0xfff00000));596}597598static uint32_t599encode_cpu_window_start_high(pci_addr_t phys_base)600{601602return ((phys_base >> 0x20) & 0xff);603}604605static uint32_t606encode_cpu_window_end_high(pci_addr_t phys_base, bus_size_t size)607{608609return (((phys_base + size - 1) >> 0x20) & 0xff);610}611612static int613bcm_pcib_attach(device_t dev)614{615struct bcm_pcib_softc *sc;616pci_addr_t phys_base, pci_base;617bus_size_t size;618uint32_t hardware_rev, bridge_state, link_state, tmp;619int error, tries;620621sc = device_get_softc(dev);622sc->dev = dev;623624/*625* This tag will be used in preference to the one created in626* pci_host_generic.c.627*/628error = bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */6291, 0, /* alignment, bounds */630DMA_HIGH_LIMIT, /* lowaddr */631BUS_SPACE_MAXADDR, /* highaddr */632NULL, NULL, /* filter, filterarg */633DMA_HIGH_LIMIT, /* maxsize */634BUS_SPACE_UNRESTRICTED, /* nsegments */635DMA_HIGH_LIMIT, /* maxsegsize */6360, /* flags */637NULL, NULL, /* lockfunc, lockarg */638&sc->dmat);639if (error != 0)640return (error);641642error = pci_host_generic_setup_fdt(dev);643if (error != 0)644return (error);645646error = bcm_pcib_check_ranges(dev);647if (error != 0)648return (error);649650mtx_init(&sc->config_mtx, "bcm_pcib: config_mtx", NULL, MTX_DEF);651652bcm_pcib_reset_controller(sc);653654hardware_rev = bcm_pcib_read_reg(sc, REG_CONTROLLER_HW_REV) & 0xffff;655device_printf(dev, "hardware identifies as revision 0x%x.\n",656hardware_rev);657658/*659* Set PCI->CPU memory window. This encodes the inbound window showing660* the system memory to the controller.661*/662bcm_pcib_set_reg(sc, REG_DMA_WINDOW_LOW, REG_VALUE_DMA_WINDOW_LOW);663bcm_pcib_set_reg(sc, REG_DMA_WINDOW_HIGH, REG_VALUE_DMA_WINDOW_HIGH);664bcm_pcib_set_reg(sc, REG_DMA_CONFIG, REG_VALUE_DMA_WINDOW_CONFIG);665666bcm_pcib_set_reg(sc, REG_BRIDGE_GISB_WINDOW, 0);667bcm_pcib_set_reg(sc, REG_DMA_WINDOW_1, 0);668669bcm_pcib_enable_controller(sc);670671/* Wait for controller to start. */672for(tries = 0; ; ++tries) {673bridge_state = bcm_pcib_read_reg(sc, REG_BRIDGE_STATE);674675if ((bridge_state & 0x30) == 0x30)676/* Controller ready. */677break;678679if (tries > 100) {680device_printf(dev,681"error: controller failed to start.\n");682return (ENXIO);683}684685DELAY(1000);686}687688link_state = bcm_pcib_read_reg(sc, REG_BRIDGE_LINK_STATE) >> 0x10;689if (!link_state) {690device_printf(dev, "error: controller started but link is not "691"up.\n");692return (ENXIO);693}694if (bootverbose)695device_printf(dev, "note: reported link speed is %s.\n",696bcm_pcib_link_state_string(link_state));697698/*699* Set the CPU->PCI memory window. The map in this direction is not 1:1.700* Addresses seen by the CPU need to be adjusted to make sense to the701* controller as they pass through the window.702*/703pci_base = sc->base.base.ranges[0].pci_base;704phys_base = sc->base.base.ranges[0].phys_base;705size = sc->base.base.ranges[0].size;706707bcm_pcib_set_reg(sc, REG_BUS_WINDOW_LOW, pci_base & 0xffffffff);708bcm_pcib_set_reg(sc, REG_BUS_WINDOW_HIGH, pci_base >> 32);709710bcm_pcib_set_reg(sc, REG_CPU_WINDOW_LOW,711encode_cpu_window_low(phys_base, size));712bcm_pcib_set_reg(sc, REG_CPU_WINDOW_START_HIGH,713encode_cpu_window_start_high(phys_base));714bcm_pcib_set_reg(sc, REG_CPU_WINDOW_END_HIGH,715encode_cpu_window_end_high(phys_base, size));716717/*718* The controller starts up declaring itself an endpoint; readvertise it719* as a bridge.720*/721bcm_pcib_set_reg(sc, PCI_ID_VAL3,722PCIC_BRIDGE << CLASS_SHIFT | PCIS_BRIDGE_PCI << SUBCLASS_SHIFT);723724tmp = bcm_pcib_read_reg(sc, REG_PCIE_HARD_DEBUG);725tmp |= CLKREQ_ENABLE;726727if (ofw_bus_has_prop(dev, "brcm,enable-l1ss")) {728if (bootverbose)729device_printf(dev, "note: enabling L1SS due to OF "730"property brcm,enable-l1ss\n");731732tmp |= L1SS_ENABLE;733}734735bcm_pcib_set_reg(sc, REG_PCIE_HARD_DEBUG, tmp);736DELAY(100);737738bcm_pcib_relocate_bridge_window(dev);739740/* Configure interrupts. */741error = bcm_pcib_msi_attach(dev);742if (error != 0)743return (error);744745/* Done. */746device_add_child(dev, "pci", DEVICE_UNIT_ANY);747bus_attach_children(dev);748return (0);749}750751/*752* Device method table.753*/754static device_method_t bcm_pcib_methods[] = {755/* Bus interface. */756DEVMETHOD(bus_get_dma_tag, bcm_pcib_get_dma_tag),757758/* Device interface. */759DEVMETHOD(device_probe, bcm_pcib_probe),760DEVMETHOD(device_attach, bcm_pcib_attach),761762/* PCIB interface. */763DEVMETHOD(pcib_read_config, bcm_pcib_read_config),764DEVMETHOD(pcib_write_config, bcm_pcib_write_config),765766/* MSI interface. */767DEVMETHOD(msi_alloc_msi, bcm_pcib_alloc_msi),768DEVMETHOD(msi_release_msi, bcm_pcib_release_msi),769DEVMETHOD(msi_map_msi, bcm_pcib_map_msi),770771DEVMETHOD_END772};773774DEFINE_CLASS_1(pcib, bcm_pcib_driver, bcm_pcib_methods,775sizeof(struct bcm_pcib_softc), generic_pcie_fdt_driver);776777DRIVER_MODULE(bcm_pcib, simplebus, bcm_pcib_driver, 0, 0);778779780781