/* * Make sure the DMA-safe memory allocated for dev lies between * min_addr and max_addr. Can be used multiple times to restrict the * bounds further, but never to expand the bounds again. * * XXX Caller must guarantee nobody has used the tag yet, * i.e. allocated any DMA memory. */ int drm_limit_dma_space(struct drm_device *dev, resource_size_t min_addr, resource_size_t max_addr) { int ret; KASSERT(min_addr <= max_addr); /* * Limit it further if we have already limited it, and destroy * the old subregion DMA tag. */ if (dev->dmat_subregion_p) { min_addr = MAX(min_addr, dev->dmat_subregion_min); max_addr = MIN(max_addr, dev->dmat_subregion_max); bus_dmatag_destroy(dev->dmat); } /* * Create a DMA tag for a subregion from the bus's DMA tag. If * that fails, restore dev->dmat to the whole region so that we * need not worry about dev->dmat being uninitialized (not that * the caller should try to allocate DMA-safe memory on failure * anyway, but...paranoia). */ /* XXX errno NetBSD->Linux */ ret = -bus_dmatag_subregion(dev->bus_dmat, min_addr, max_addr, &dev->dmat, BUS_DMA_WAITOK); if (ret) { dev->dmat = dev->bus_dmat; dev->dmat_subregion_p = false; return ret; } /* * Remember that we have a subregion tag so that we know to * destroy it later, and record the bounds in case we need to * limit them again. */ dev->dmat_subregion_p = true; dev->dmat_subregion_min = min_addr; dev->dmat_subregion_max = max_addr; /* Success! */ return 0; }
static void rmixl_pcix_attach(device_t parent, device_t self, void *aux) { rmixl_pcix_softc_t *sc = device_private(self); struct obio_attach_args *obio = aux; struct rmixl_config *rcp = &rmixl_configuration; struct pcibus_attach_args pba; uint32_t bar; rmixl_pcix_found = 1; sc->sc_dev = self; sc->sc_29bit_dmat = obio->obio_29bit_dmat; sc->sc_32bit_dmat = obio->obio_32bit_dmat; sc->sc_64bit_dmat = obio->obio_64bit_dmat; sc->sc_tmsk = obio->obio_tmsk; aprint_normal(": RMI XLR PCI-X Interface\n"); mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_HIGH); rmixl_pcix_intcfg(sc); rmixl_pcix_errata(sc); /* * check XLR Control Register */ DPRINTF(("%s: XLR_CONTROL=%#x\n", __func__, RMIXL_PCIXREG_READ(RMIXL_PCIX_ECFG_XLR_CONTROL))); /* * HBAR[0] if a 32 bit BAR, or * HBAR[0,1] if a 64 bit BAR pair * must cover all RAM */ extern u_quad_t mem_cluster_maxaddr; uint64_t hbar_addr; uint64_t hbar_size; uint32_t hbar_size_lo, hbar_size_hi; uint32_t hbar_addr_lo, hbar_addr_hi; hbar_addr_lo = RMIXL_PCIXREG_READ(RMIXL_PCIX_ECFG_HOST_BAR0_ADDR); hbar_addr_hi = RMIXL_PCIXREG_READ(RMIXL_PCIX_ECFG_HOST_BAR1_ADDR); hbar_size_lo = RMIXL_PCIXREG_READ(RMIXL_PCIX_ECFG_HOST_BAR0_SIZE); hbar_size_hi = RMIXL_PCIXREG_READ(RMIXL_PCIX_ECFG_HOST_BAR1_SIZE); hbar_addr = (u_quad_t)(hbar_addr_lo & PCI_MAPREG_MEM_ADDR_MASK); hbar_size = hbar_size_lo; if ((hbar_size_lo & PCI_MAPREG_MEM_TYPE_64BIT) != 0) { hbar_addr |= (uint64_t)hbar_addr_hi << 32; hbar_size |= (uint64_t)hbar_size_hi << 32; } if ((hbar_addr != 0) || (hbar_size < mem_cluster_maxaddr)) { int error; aprint_error_dev(self, "HostBAR0 addr %#x, size %#x\n", hbar_addr_lo, hbar_size_lo); if ((hbar_size_lo & PCI_MAPREG_MEM_TYPE_64BIT) != 0) aprint_error_dev(self, "HostBAR1 addr %#x, size %#x\n", hbar_addr_hi, hbar_size_hi); aprint_error_dev(self, "WARNING: firmware PCI-X setup error: " "RAM %#"PRIx64"..%#"PRIx64" not accessible by Host BAR, " "enabling DMA bounce buffers\n", hbar_size, mem_cluster_maxaddr-1); /* * force use of bouce buffers for inaccessible RAM addrs */ if (hbar_size < ((uint64_t)1 << 32)) { error = bus_dmatag_subregion(sc->sc_32bit_dmat, 0, (bus_addr_t)hbar_size, &sc->sc_32bit_dmat, BUS_DMA_NOWAIT); if (error) panic("%s: failed to subregion 32-bit dma tag:" " error %d", __func__, error); sc->sc_64bit_dmat = NULL; } else { error = bus_dmatag_subregion(sc->sc_64bit_dmat, 0, (bus_addr_t)hbar_size, &sc->sc_64bit_dmat, BUS_DMA_NOWAIT); if (error) panic("%s: failed to subregion 64-bit dma tag:" " error %d", __func__, error); } } /* * check PCI-X interface byteswap setup * ensure 'Match Byte Lane' is disabled */ uint32_t mble; mble = RMIXL_PCIXREG_READ(RMIXL_PCIX_ECFG_XLR_MBLE); #ifdef PCI_DEBUG uint32_t mba, mbs; mba = RMIXL_PCIXREG_READ(RMIXL_PCIX_ECFG_MATCH_BIT_ADDR); mbs = RMIXL_PCIXREG_READ(RMIXL_PCIX_ECFG_MATCH_BIT_SIZE); DPRINTF(("%s: MBLE=%#x, MBA=%#x, MBS=%#x\n", __func__, mble, mba, mbs)); #endif if ((mble & __BIT(40)) != 0) RMIXL_PCIXREG_WRITE(RMIXL_PCIX_ECFG_XLR_MBLE, 0); /* * get PCI config space base addr from SBC PCIe CFG BAR * initialize it if necessary */ bar = RMIXL_IOREG_READ(RMIXL_IO_DEV_BRIDGE + RMIXLR_SBC_PCIX_CFG_BAR); DPRINTF(("%s: PCIX_CFG_BAR %#x\n", __func__, bar)); if ((bar & RMIXL_PCIX_CFG_BAR_ENB) == 0) { u_long n = RMIXL_PCIX_CFG_SIZE / (1024 * 1024); RMIXL_PCIX_BAR_INIT(CFG, bar, n, n); } rcp->rc_pci_cfg_pbase = (bus_addr_t)RMIXL_PCIX_CFG_BAR_TO_BA(bar); rcp->rc_pci_cfg_size = (bus_size_t)RMIXL_PCIX_CFG_SIZE; /* * get PCI MEM space base [addr, size] from SBC PCIe MEM BAR * initialize it if necessary */ bar = RMIXL_IOREG_READ(RMIXL_IO_DEV_BRIDGE + RMIXLR_SBC_PCIX_MEM_BAR); DPRINTF(("%s: PCIX_MEM_BAR %#x\n", __func__, bar)); if ((bar & RMIXL_PCIX_MEM_BAR_ENB) == 0) { u_long n = 256; /* 256 MB */ RMIXL_PCIX_BAR_INIT(MEM, bar, n, n); } rcp->rc_pci_mem_pbase = (bus_addr_t)RMIXL_PCIX_MEM_BAR_TO_BA(bar); rcp->rc_pci_mem_size = (bus_size_t)RMIXL_PCIX_MEM_BAR_TO_SIZE(bar); /* * get PCI IO space base [addr, size] from SBC PCIe IO BAR * initialize it if necessary */ bar = RMIXL_IOREG_READ(RMIXL_IO_DEV_BRIDGE + RMIXLR_SBC_PCIX_IO_BAR); DPRINTF(("%s: PCIX_IO_BAR %#x\n", __func__, bar)); if ((bar & RMIXL_PCIX_IO_BAR_ENB) == 0) { u_long n = 32; /* 32 MB */ RMIXL_PCIX_BAR_INIT(IO, bar, n, n); } rcp->rc_pci_io_pbase = (bus_addr_t)RMIXL_PCIX_IO_BAR_TO_BA(bar); rcp->rc_pci_io_size = (bus_size_t)RMIXL_PCIX_IO_BAR_TO_SIZE(bar); /* * initialize the PCI CFG bus space tag */ rmixl_pci_cfg_bus_mem_init(&rcp->rc_pci_cfg_memt, rcp); sc->sc_pci_cfg_memt = &rcp->rc_pci_cfg_memt; /* * initialize the PCI MEM and IO bus space tags */ rmixl_pci_bus_mem_init(&rcp->rc_pci_memt, rcp); rmixl_pci_bus_io_init(&rcp->rc_pci_iot, rcp); /* * initialize the extended configuration regs */ rmixl_pcix_init_errors(sc); /* * initialize the PCI chipset tag */ rmixl_pcix_init(sc); /* * attach the PCI bus */ memset(&pba, 0, sizeof(pba)); pba.pba_memt = &rcp->rc_pci_memt; pba.pba_iot = &rcp->rc_pci_iot; pba.pba_dmat = sc->sc_32bit_dmat; pba.pba_dmat64 = sc->sc_64bit_dmat; pba.pba_pc = &sc->sc_pci_chipset; pba.pba_bus = 0; pba.pba_bridgetag = NULL; pba.pba_intrswiz = 0; pba.pba_intrtag = 0; pba.pba_flags = PCI_FLAGS_IO_OKAY | PCI_FLAGS_MEM_OKAY | PCI_FLAGS_MRL_OKAY | PCI_FLAGS_MRM_OKAY | PCI_FLAGS_MWI_OKAY; (void) config_found_ia(self, "pcibus", &pba, pcibusprint); }
static void bce_attach(device_t parent, device_t self, void *aux) { struct bce_softc *sc = device_private(self); struct pci_attach_args *pa = aux; const struct bce_product *bp; pci_chipset_tag_t pc = pa->pa_pc; pci_intr_handle_t ih; const char *intrstr = NULL; uint32_t command; pcireg_t memtype, pmode; bus_addr_t memaddr; bus_size_t memsize; void *kva; bus_dma_segment_t seg; int error, i, pmreg, rseg; struct ifnet *ifp; char intrbuf[PCI_INTRSTR_LEN]; sc->bce_dev = self; bp = bce_lookup(pa); KASSERT(bp != NULL); sc->bce_pa = *pa; /* BCM440x can only address 30 bits (1GB) */ if (bus_dmatag_subregion(pa->pa_dmat, 0, (1 << 30), &(sc->bce_dmatag), BUS_DMA_NOWAIT) != 0) { aprint_error_dev(self, "WARNING: failed to restrict dma range," " falling back to parent bus dma range\n"); sc->bce_dmatag = pa->pa_dmat; } aprint_naive(": Ethernet controller\n"); aprint_normal(": %s\n", bp->bp_name); /* * Map control/status registers. */ command = pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); command |= PCI_COMMAND_MEM_ENABLE | PCI_COMMAND_MASTER_ENABLE; pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, command); command = pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); if (!(command & PCI_COMMAND_MEM_ENABLE)) { aprint_error_dev(self, "failed to enable memory mapping!\n"); return; } memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, BCE_PCI_BAR0); switch (memtype) { case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT: case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT: if (pci_mapreg_map(pa, BCE_PCI_BAR0, memtype, 0, &sc->bce_btag, &sc->bce_bhandle, &memaddr, &memsize) == 0) break; default: aprint_error_dev(self, "unable to find mem space\n"); return; } /* Get it out of power save mode if needed. */ if (pci_get_capability(pc, pa->pa_tag, PCI_CAP_PWRMGMT, &pmreg, NULL)) { pmode = pci_conf_read(pc, pa->pa_tag, pmreg + 4) & 0x3; if (pmode == 3) { /* * The card has lost all configuration data in * this state, so punt. */ aprint_error_dev(self, "unable to wake up from power state D3\n"); return; } if (pmode != 0) { aprint_normal_dev(self, "waking up from power state D%d\n", pmode); pci_conf_write(pc, pa->pa_tag, pmreg + 4, 0); } } if (pci_intr_map(pa, &ih)) { aprint_error_dev(self, "couldn't map interrupt\n"); return; } intrstr = pci_intr_string(pc, ih, intrbuf, sizeof(intrbuf)); sc->bce_intrhand = pci_intr_establish(pc, ih, IPL_NET, bce_intr, sc); if (sc->bce_intrhand == NULL) { aprint_error_dev(self, "couldn't establish interrupt\n"); if (intrstr != NULL) aprint_error(" at %s", intrstr); aprint_error("\n"); return; } aprint_normal_dev(self, "interrupting at %s\n", intrstr); /* reset the chip */ bce_reset(sc); /* * Allocate DMA-safe memory for ring descriptors. * The receive, and transmit rings can not share the same * 4k space, however both are allocated at once here. */ /* * XXX PAGE_SIZE is wasteful; we only need 1KB + 1KB, but * due to the limition above. ?? */ if ((error = bus_dmamem_alloc(sc->bce_dmatag, 2 * PAGE_SIZE, PAGE_SIZE, 2 * PAGE_SIZE, &seg, 1, &rseg, BUS_DMA_NOWAIT))) { aprint_error_dev(self, "unable to alloc space for ring descriptors, error = %d\n", error); return; } /* map ring space to kernel */ if ((error = bus_dmamem_map(sc->bce_dmatag, &seg, rseg, 2 * PAGE_SIZE, &kva, BUS_DMA_NOWAIT))) { aprint_error_dev(self, "unable to map DMA buffers, error = %d\n", error); bus_dmamem_free(sc->bce_dmatag, &seg, rseg); return; } /* create a dma map for the ring */ if ((error = bus_dmamap_create(sc->bce_dmatag, 2 * PAGE_SIZE, 1, 2 * PAGE_SIZE, 0, BUS_DMA_NOWAIT, &sc->bce_ring_map))) { aprint_error_dev(self, "unable to create ring DMA map, error = %d\n", error); bus_dmamem_unmap(sc->bce_dmatag, kva, 2 * PAGE_SIZE); bus_dmamem_free(sc->bce_dmatag, &seg, rseg); return; } /* connect the ring space to the dma map */ if (bus_dmamap_load(sc->bce_dmatag, sc->bce_ring_map, kva, 2 * PAGE_SIZE, NULL, BUS_DMA_NOWAIT)) { bus_dmamap_destroy(sc->bce_dmatag, sc->bce_ring_map); bus_dmamem_unmap(sc->bce_dmatag, kva, 2 * PAGE_SIZE); bus_dmamem_free(sc->bce_dmatag, &seg, rseg); return; } /* save the ring space in softc */ sc->bce_rx_ring = (struct bce_dma_slot *) kva; sc->bce_tx_ring = (struct bce_dma_slot *) ((char *)kva + PAGE_SIZE); /* Create the transmit buffer DMA maps. */ for (i = 0; i < BCE_NTXDESC; i++) { if ((error = bus_dmamap_create(sc->bce_dmatag, MCLBYTES, BCE_NTXFRAGS, MCLBYTES, 0, 0, &sc->bce_cdata.bce_tx_map[i])) != 0) { aprint_error_dev(self, "unable to create tx DMA map, error = %d\n", error); } sc->bce_cdata.bce_tx_chain[i] = NULL; } /* Create the receive buffer DMA maps. */ for (i = 0; i < BCE_NRXDESC; i++) { if ((error = bus_dmamap_create(sc->bce_dmatag, MCLBYTES, 1, MCLBYTES, 0, 0, &sc->bce_cdata.bce_rx_map[i])) != 0) { aprint_error_dev(self, "unable to create rx DMA map, error = %d\n", error); } sc->bce_cdata.bce_rx_chain[i] = NULL; } /* Set up ifnet structure */ ifp = &sc->ethercom.ec_if; strcpy(ifp->if_xname, device_xname(self)); ifp->if_softc = sc; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_ioctl = bce_ioctl; ifp->if_start = bce_start; ifp->if_watchdog = bce_watchdog; ifp->if_init = bce_init; ifp->if_stop = bce_stop; IFQ_SET_READY(&ifp->if_snd); /* Initialize our media structures and probe the MII. */ sc->bce_mii.mii_ifp = ifp; sc->bce_mii.mii_readreg = bce_mii_read; sc->bce_mii.mii_writereg = bce_mii_write; sc->bce_mii.mii_statchg = bce_statchg; sc->ethercom.ec_mii = &sc->bce_mii; ifmedia_init(&sc->bce_mii.mii_media, 0, ether_mediachange, ether_mediastatus); mii_attach(sc->bce_dev, &sc->bce_mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY, MIIF_FORCEANEG|MIIF_DOPAUSE); if (LIST_FIRST(&sc->bce_mii.mii_phys) == NULL) { ifmedia_add(&sc->bce_mii.mii_media, IFM_ETHER | IFM_NONE, 0, NULL); ifmedia_set(&sc->bce_mii.mii_media, IFM_ETHER | IFM_NONE); } else ifmedia_set(&sc->bce_mii.mii_media, IFM_ETHER | IFM_AUTO); /* get the phy */ sc->bce_phy = bus_space_read_1(sc->bce_btag, sc->bce_bhandle, BCE_MAGIC_PHY) & 0x1f; /* * Enable activity led. * XXX This should be in a phy driver, but not currently. */ bce_mii_write(sc->bce_dev, 1, 26, /* MAGIC */ bce_mii_read(sc->bce_dev, 1, 26) & 0x7fff); /* MAGIC */ /* enable traffic meter led mode */ bce_mii_write(sc->bce_dev, 1, 27, /* MAGIC */ bce_mii_read(sc->bce_dev, 1, 27) | (1 << 6)); /* MAGIC */ /* Attach the interface */ if_attach(ifp); sc->enaddr[0] = bus_space_read_1(sc->bce_btag, sc->bce_bhandle, BCE_MAGIC_ENET0); sc->enaddr[1] = bus_space_read_1(sc->bce_btag, sc->bce_bhandle, BCE_MAGIC_ENET1); sc->enaddr[2] = bus_space_read_1(sc->bce_btag, sc->bce_bhandle, BCE_MAGIC_ENET2); sc->enaddr[3] = bus_space_read_1(sc->bce_btag, sc->bce_bhandle, BCE_MAGIC_ENET3); sc->enaddr[4] = bus_space_read_1(sc->bce_btag, sc->bce_bhandle, BCE_MAGIC_ENET4); sc->enaddr[5] = bus_space_read_1(sc->bce_btag, sc->bce_bhandle, BCE_MAGIC_ENET5); aprint_normal_dev(self, "Ethernet address %s\n", ether_sprintf(sc->enaddr)); ether_ifattach(ifp, sc->enaddr); rnd_attach_source(&sc->rnd_source, device_xname(self), RND_TYPE_NET, 0); callout_init(&sc->bce_timeout, 0); if (pmf_device_register(self, NULL, bce_resume)) pmf_class_network_register(self, ifp); else aprint_error_dev(self, "couldn't establish power handler\n"); }