Пример #1
0
/*
 * 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);
}
Пример #3
0
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");
}