Beispiel #1
0
static int
thunder_pem_link_init(struct thunder_pem_softc *sc)
{
	uint64_t regval;

	/* check whether PEM is safe to access. */
	regval = bus_space_read_8(sc->reg_bst, sc->reg_bsh, PEM_ON_REG);
	if ((regval & PEM_CFG_LINK_MASK) != PEM_CFG_LINK_RDY) {
		device_printf(sc->dev, "PEM%d is not ON\n", sc->id);
		return (ENXIO);
	}

	regval = bus_space_read_8(sc->reg_bst, sc->reg_bsh, PEM_CTL_STATUS);
	regval |= PEM_LINK_ENABLE;
	bus_space_write_8(sc->reg_bst, sc->reg_bsh, PEM_CTL_STATUS, regval);

	/* Wait 1ms as per Cavium specification */
	DELAY(1000);

	regval = thunder_pem_config_reg_read(sc, PCIERC_CFG032);

	if (((regval & PEM_LINK_DLLA) == 0) || ((regval & PEM_LINK_LT) != 0)) {
		device_printf(sc->dev, "PCIe RC: Port %d Link Timeout\n",
		    sc->id);
		return (ENXIO);
	}

	return (0);
}
Beispiel #2
0
static uint32 __inline _get_cur_offset()
{
  uint32 offset, offset_h, offset_l;

  bus_space_write_8( cur_io_type, cur_io_base, cur_index_off, 14 );
  bus_space_read_8( cur_io_type, cur_io_base, cur_data_off, offset_h );
  offset_h <<= 8;
  bus_space_write_8( cur_io_type, cur_io_base, cur_index_off, 15 );
  bus_space_read_8( cur_io_type, cur_io_base, cur_data_off, offset_l );
  offset = offset_h|offset_l;

  return offset;
}
Beispiel #3
0
/*ARGSUSED*/
static void
pbridgeattach(struct device *parent, struct device *self, void *args)
{
	struct superhyway_attach_args *sa = args;
	struct pbridge_attach_args pa;
	bus_space_handle_t bh;
	u_int64_t vcr;
	int i;

	pa._pa_base = SUPERHYWAY_PPORT_TO_BUSADDR(sa->sa_pport);

	bus_space_map(sa->sa_bust, pa._pa_base, SUPERHYWAY_REG_SZ, 0, &bh);
	vcr = bus_space_read_8(sa->sa_bust, bh, SUPERHYWAY_REG_VCR);
	bus_space_unmap(sa->sa_bust, bh, SUPERHYWAY_REG_SZ);

	printf(": Peripheral Bridge, Version 0x%x\n",
	    (int)SUPERHYWAY_VCR_MOD_VERS(vcr));

	/*
	 * Attach configured children
	 */
	for (i = 0; pbridge_devices[i].pd_name != NULL; i++) {
		pa.pa_name = pbridge_devices[i].pd_name;
		pa.pa_offset = pbridge_devices[i].pd_offset + pa._pa_base;
		pa.pa_bust = sa->sa_bust;
		pa.pa_dmat = sa->sa_dmat;
		pa.pa_ipl = -1;
		pa.pa_intevt = -1;

		(void) config_found(self, &pa, pbridgeprint);
	}
}
Beispiel #4
0
static uint8_t
cfi_read_qry(struct cfi * const cfi, bus_size_t off)
{
	const bus_space_tag_t bst = cfi->cfi_bst;
	bus_space_handle_t bsh = cfi->cfi_bsh;
	uint8_t data;

	off <<= cfi->cfi_portwidth;

	switch (cfi->cfi_portwidth) {
	case 0:
		data = bus_space_read_1(bst, bsh, off);
		break;
	case 1:
		data = bus_space_read_2(bst, bsh, off);
		break;
	case 2:
		data = bus_space_read_4(bst, bsh, off);
		break;
	case 3:
		data = bus_space_read_8(bst, bsh, off);
		break;
	default:
		data = ~0;
		break;
	}
	return data;
}
Beispiel #5
0
static void
thunder_pem_slix_s2m_regx_acc_modify(struct thunder_pem_softc *sc,
    int sli_group, int slix)
{
	uint64_t regval;
	bus_space_handle_t handle = 0;

	KASSERT(slix >= 0 && slix <= SLI_ACC_REG_CNT, ("Invalid SLI index"));

	if (sli_group == 0)
		handle = sli0_s2m_regx_base;
	else if (sli_group == 1)
		handle = sli1_s2m_regx_base;
	else
		device_printf(sc->dev, "SLI group is not correct\n");

	if (handle) {
		/* Clear lower 32-bits of the SLIx register */
		regval = bus_space_read_8(sc->reg_bst, handle,
		    PEM_CFG_SLIX_TO_REG(slix));
		regval &= ~(0xFFFFFFFFUL);
		bus_space_write_8(sc->reg_bst, handle,
		    PEM_CFG_SLIX_TO_REG(slix), regval);
	}
}
Beispiel #6
0
/*ARGSUSED*/
static int
pbridgematch(struct device *parent, struct cfdata *cf, void *args)
{
	struct superhyway_attach_args *sa = args;
#ifndef SH5_SIM
	bus_space_handle_t bh;
	u_int64_t vcr;
#endif
	if (strcmp(sa->sa_name, pbridge_cd.cd_name))
		return (0);
#ifndef SH5_SIM
	sa->sa_pport = 0;

	bus_space_map(sa->sa_bust,
	    SUPERHYWAY_PPORT_TO_BUSADDR(cf->cf_loc[SUPERHYWAYCF_PPORT]),
	    SUPERHYWAY_REG_SZ, 0, &bh);
	vcr = bus_space_read_8(sa->sa_bust, bh, SUPERHYWAY_REG_VCR);
	bus_space_unmap(sa->sa_bust, bh, SUPERHYWAY_REG_SZ);

	if (SUPERHYWAY_VCR_MOD_ID(vcr) != PBRIDGE_MODULE_ID)
		return (0);
#endif
	sa->sa_pport = cf->cf_loc[SUPERHYWAYCF_PPORT];

	return (1);
}
Beispiel #7
0
void
mec_reset(struct mec_softc *sc)
{
	bus_space_tag_t st = sc->sc_st;
	bus_space_handle_t sh = sc->sc_sh;
	uint64_t address, control;
	int i;

	/* Reset chip. */
	bus_space_write_8(st, sh, MEC_MAC_CONTROL, MEC_MAC_CORE_RESET);
	delay(1000);
	bus_space_write_8(st, sh, MEC_MAC_CONTROL, 0);
	delay(1000);

	/* Set Ethernet address. */
	address = 0;
	for (i = 0; i < ETHER_ADDR_LEN; i++) {
		address = address << 8;
		address += sc->sc_ac.ac_enaddr[i];
	}
	bus_space_write_8(st, sh, MEC_STATION, address);

	/* Default to 100/half and let auto-negotiation work its magic. */
	control = MEC_MAC_SPEED_SELECT | MEC_MAC_FILTER_MATCHMULTI |
	    MEC_MAC_IPG_DEFAULT;

	bus_space_write_8(st, sh, MEC_MAC_CONTROL, control);
	bus_space_write_8(st, sh, MEC_DMA_CONTROL, 0);

	DPRINTF(MEC_DEBUG_RESET, ("mec: control now %llx\n",
	    bus_space_read_8(st, sh, MEC_MAC_CONTROL)));
}
Beispiel #8
0
static unsigned int
counter_get_timecount(struct timecounter *tc)
{
	struct ct_softc *sc;

	sc = tc->tc_priv;
	return (bus_space_read_8(sc->sc_tag, sc->sc_handle, sc->sc_offset));
}
Beispiel #9
0
uint64_t
cn30xxfpa_query(int poolno)
{
	struct cn30xxfpa_softc *sc = &cn30xxfpa_softc;

	return bus_space_read_8(sc->sc_regt, sc->sc_regh,
	    FPA_QUE0_AVAILABLE_OFFSET + sizeof(uint64_t) * poolno);
}
Beispiel #10
0
uint64_t
cn30xxfpa_int_summary(void)
{
	struct cn30xxfpa_softc *sc = &cn30xxfpa_softc;
	uint64_t summary;

	summary = bus_space_read_8(sc->sc_regt, sc->sc_regh, FPA_INT_SUM_OFFSET);
	bus_space_write_8(sc->sc_regt, sc->sc_regh, FPA_INT_SUM_OFFSET, summary);
	return summary;
}
Beispiel #11
0
void
macebusattach(struct device *parent, struct device *self, void *aux)
{
	u_int32_t creg;
	uint i;

	/*
	 * Map and setup CRIME control registers.
	 */
	if (bus_space_map(&crimebus_tag, 0x00000000, 0x400, 0, &crime_h)) {
		printf(": can't map CRIME control registers\n");
		return;
	}

	creg = bus_space_read_8(&crimebus_tag, crime_h, CRIME_REVISION);
	printf(": crime rev %d.%d\n", (creg & 0xf0) >> 4, creg & 0xf);

	bus_space_write_8(&crimebus_tag, crime_h, CRIME_CPU_ERROR_STAT, 0);
	bus_space_write_8(&crimebus_tag, crime_h, CRIME_MEM_ERROR_STAT, 0);

	bus_space_write_8(&crimebus_tag, crime_h, CRIME_INT_MASK, 0);
	bus_space_write_8(&crimebus_tag, crime_h, CRIME_INT_SOFT, 0);
	bus_space_write_8(&crimebus_tag, crime_h, CRIME_INT_HARD, 0);
	bus_space_write_8(&crimebus_tag, crime_h, CRIME_INT_STAT, 0);

	/*
	 * Map and setup MACE ISA control registers.
	 */
	if (bus_space_map(&macebus_tag, MACE_ISA_OFFS, 0x400, 0, &mace_h)) {
		printf("%s: can't map MACE control registers\n",
		    self->dv_xname);
		return;
	}

	bus_space_write_8(&macebus_tag, mace_h, MACE_ISA_INT_MASK, 0);
	bus_space_write_8(&macebus_tag, mace_h, MACE_ISA_INT_STAT, 0);

	/*
	 * On O2 systems all interrupts are handled by the macebus interrupt
	 * handler. Register all except clock.
	 */
	set_intr(INTPRI_MACEIO, CR_INT_0, macebus_iointr);
	register_splx_handler(macebus_splx);

	/* Set up a handler called when clock interrupts go off. */
	set_intr(INTPRI_MACEAUX, CR_INT_5, macebus_aux);

	/*
	 * Attach subdevices.
	 */
	for (i = 0; i < nitems(macebus_children); i++)
		config_found_sm(self, macebus_children + i,
		    macebusprint, macebussubmatch);
}
Beispiel #12
0
void
octohci_attach(struct device *parent, struct device *self, void *aux)
{
	struct octohci_softc *sc = (struct octohci_softc *)self;
	struct octuctl_attach_args *aa = aux;
	char *devname;
	uint64_t port_ctl;
	int rc;
	int s;

	sc->sc_ohci.iot = aa->aa_bust;
	sc->sc_ohci.sc_bus.pipe_size = sizeof(struct usbd_pipe);
	sc->sc_ohci.sc_bus.dmatag = aa->aa_dmat;

	rc = bus_space_map(sc->sc_ohci.iot, UCTL_OHCI_BASE, UCTL_OHCI_SIZE,
	    0, &sc->sc_ohci.ioh);
	KASSERT(rc == 0);

	port_ctl = bus_space_read_8(aa->aa_octuctl_bust, aa->aa_ioh,
	    UCTL_OHCI_CTL);
	port_ctl &= ~UCTL_OHCI_CTL_L2C_ADDR_MSB_MASK;
	port_ctl |= (1 << UCTL_OHCI_CTL_L2C_DESC_EMOD_SHIFT);
	port_ctl |= (1 << UCTL_OHCI_CTL_L2C_BUFF_EMOD_SHIFT);
	bus_space_write_8(aa->aa_octuctl_bust, aa->aa_ioh, UCTL_OHCI_CTL,
	    port_ctl);

	s = splusb();

	sc->sc_ohci.sc_id_vendor = 0;
	strlcpy(sc->sc_ohci.sc_vendor, "Octeon", sizeof(sc->sc_ohci.sc_vendor));

	sc->sc_ih = octeon_intr_establish(CIU_INT_USB, IPL_USB, ohci_intr,
	    (void *)&sc->sc_ohci, devname);
	KASSERT(sc->sc_ih != NULL);

	if ((ohci_checkrev(&sc->sc_ohci) != USBD_NORMAL_COMPLETION) ||
	    (ohci_handover(&sc->sc_ohci) != USBD_NORMAL_COMPLETION))
		goto failed;

	/* ignore interrupts for now */
	sc->sc_ohci.sc_bus.dying = 1;
	config_defer(self, octohci_attach_deferred);

	splx(s);
	return;

failed:
	octeon_intr_disestablish(sc->sc_ih);
	bus_space_unmap(sc->sc_ohci.iot, sc->sc_ohci.ioh, UCTL_OHCI_SIZE);
	splx(s);
	return;
}
Beispiel #13
0
void
mec_setfilter(struct mec_softc *sc)
{
	struct arpcom *ec = &sc->sc_ac;
	struct ifnet *ifp = &sc->sc_ac.ac_if;
	struct ether_multi *enm;
	struct ether_multistep step;
	bus_space_tag_t st = sc->sc_st;
	bus_space_handle_t sh = sc->sc_sh;
	uint64_t mchash;
	uint32_t control, hash;
	int mcnt;

	control = bus_space_read_8(st, sh, MEC_MAC_CONTROL);
	control &= ~MEC_MAC_FILTER_MASK;

	if (ifp->if_flags & IFF_PROMISC) {
		control |= MEC_MAC_FILTER_PROMISC;
		bus_space_write_8(st, sh, MEC_MULTICAST, 0xffffffffffffffffULL);
		bus_space_write_8(st, sh, MEC_MAC_CONTROL, control);
		return;
	}

	mcnt = 0;
	mchash = 0;
	ETHER_FIRST_MULTI(step, ec, enm);
	while (enm != NULL) {
		if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
			/* Set allmulti for a range of multicast addresses. */
			control |= MEC_MAC_FILTER_ALLMULTI;
			bus_space_write_8(st, sh, MEC_MULTICAST,
			    0xffffffffffffffffULL);
			bus_space_write_8(st, sh, MEC_MAC_CONTROL, control);
			return;
		}

#define mec_calchash(addr)	(ether_crc32_be((addr), ETHER_ADDR_LEN) >> 26)

		hash = mec_calchash(enm->enm_addrlo);
		mchash |= 1 << hash;
		mcnt++;
		ETHER_NEXT_MULTI(step, enm);
	}

	ifp->if_flags &= ~IFF_ALLMULTI;

	if (mcnt > 0)
		control |= MEC_MAC_FILTER_MATCHMULTI;

	bus_space_write_8(st, sh, MEC_MULTICAST, mchash);
	bus_space_write_8(st, sh, MEC_MAC_CONTROL, control);
}
Beispiel #14
0
void
octrng_rnd(void *arg)
{
	struct octrng_softc *sc = arg;
	uint64_t value;

	value = bus_space_read_8(sc->sc_iot, sc->sc_ioh, OCTRNG_ENTROPY_REG);

	DPRINTF(("%#llX ", value));	/* WARNING: very verbose */

	add_true_randomness(value);
	timeout_add_msec(&sc->sc_to, 10);
}
Beispiel #15
0
static uint64_t
thunder_pem_config_reg_read(struct thunder_pem_softc *sc, int reg)
{
	uint64_t data;

	/* Write to ADDR register */
	bus_space_write_8(sc->reg_bst, sc->reg_bsh, PEM_CFG_RD,
	    PEM_CFG_RD_REG_ALIGN(reg));
	bus_space_barrier(sc->reg_bst, sc->reg_bsh, PEM_CFG_RD, 8,
	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
	/* Read from DATA register */
	data = PEM_CFG_RD_REG_DATA(bus_space_read_8(sc->reg_bst, sc->reg_bsh,
	    PEM_CFG_RD));

	return (data);
}
Beispiel #16
0
static void
le_lebuffer_copyfromdesc(struct lance_softc *sc, void *tov, int off, int len)
{
	struct le_lebuffer_softc *lesc = (struct le_lebuffer_softc *)sc;
	caddr_t to = tov;

	for (; len >= 8; len -= 8, off += 8, to += 8)
		be64enc(to,
		    bus_space_read_8(lesc->sc_buft, lesc->sc_bufh, off));
	for (; len >= 4; len -= 4, off += 4, to += 4)
		be32enc(to,
		    bus_space_read_4(lesc->sc_buft, lesc->sc_bufh, off));
	for (; len >= 2; len -= 2, off += 2, to += 2)
		be16enc(to,
		    bus_space_read_2(lesc->sc_buft, lesc->sc_bufh, off));
	if (len == 1)
		*to =
		    bus_space_read_1(lesc->sc_buft, lesc->sc_bufh, off);
}
Beispiel #17
0
void
mec_statchg(struct device *self)
{
	struct mec_softc *sc = (void *)self;
	bus_space_tag_t st = sc->sc_st;
	bus_space_handle_t sh = sc->sc_sh;
	uint32_t control;

	control = bus_space_read_8(st, sh, MEC_MAC_CONTROL);
	control &= ~(MEC_MAC_IPGT | MEC_MAC_IPGR1 | MEC_MAC_IPGR2 |
	    MEC_MAC_FULL_DUPLEX | MEC_MAC_SPEED_SELECT);

	/* Must also set IPG here for duplex stuff... */
	if ((sc->sc_mii.mii_media_active & IFM_FDX) != 0) {
		control |= MEC_MAC_FULL_DUPLEX;
	} else {
		/* Set IPG. */
		control |= MEC_MAC_IPG_DEFAULT;
	}

	bus_space_write_8(st, sh, MEC_MAC_CONTROL, control);
}
Beispiel #18
0
/*
 * Macebus auxilary functions run each clock interrupt.
 */
uint32_t
macebus_aux(uint32_t hwpend, struct trapframe *cf)
{
	u_int64_t mask;

	mask = bus_space_read_8(&macebus_tag, mace_h, MACE_ISA_MISC_REG);
	mask |= MACE_ISA_MISC_RLED_OFF | MACE_ISA_MISC_GLED_OFF;

	/* GREEN - Idle */
	/* AMBER - System mode */
	/* RED   - User mode */
	if (cf->sr & SR_KSU_USER) {
		mask &= ~MACE_ISA_MISC_RLED_OFF;
	} else if (curproc == NULL ||
	    curproc == curcpu()->ci_schedstate.spc_idleproc) {
		mask &= ~MACE_ISA_MISC_GLED_OFF;
	} else {
		mask &= ~(MACE_ISA_MISC_RLED_OFF | MACE_ISA_MISC_GLED_OFF);
	}
	bus_space_write_8(&macebus_tag, mace_h, MACE_ISA_MISC_REG, mask);

	return 0;	/* Real clock int handler will claim the interrupt. */
}
Beispiel #19
0
/*
 * Interrupt dispatcher.
 */
uint32_t
obio_iointr(uint32_t hwpend, struct trap_frame *frame)
{
	struct cpu_info *ci = curcpu();
	int cpuid = cpu_number();
	uint64_t imr, isr, mask;
	int ipl;
	int bit;
	struct intrhand *ih;
	int rc;
	uint64_t sum0 = CIU_IP2_SUM0(cpuid);
	uint64_t en0 = CIU_IP2_EN0(cpuid);

	isr = bus_space_read_8(&obio_tag, obio_h, sum0);
	imr = bus_space_read_8(&obio_tag, obio_h, en0);
	bit = 63;

	isr &= imr;
	if (isr == 0)
		return 0;	/* not for us */

	/*
	 * Mask all pending interrupts.
	 */
	bus_space_write_8(&obio_tag, obio_h, en0, imr & ~isr);

	/*
	 * If interrupts are spl-masked, mask them and wait for splx()
	 * to reenable them when necessary.
	 */
	if ((mask = isr & obio_imask[cpuid][frame->ipl]) != 0) {
		isr &= ~mask;
		imr &= ~mask;
	}

	/*
	 * Now process allowed interrupts.
	 */
	if (isr != 0) {
		int lvl, bitno;
		uint64_t tmpisr;

		__asm__ (".set noreorder\n");
		ipl = ci->ci_ipl;
		__asm__ ("sync\n\t.set reorder\n");

		/* Service higher level interrupts first */
		for (lvl = NIPLS - 1; lvl != IPL_NONE; lvl--) {
			tmpisr = isr & (obio_imask[cpuid][lvl] ^ obio_imask[cpuid][lvl - 1]);
			if (tmpisr == 0)
				continue;
			for (bitno = bit, mask = 1UL << bitno; mask != 0;
			    bitno--, mask >>= 1) {
				if ((tmpisr & mask) == 0)
					continue;

				rc = 0;
				for (ih = (struct intrhand *)obio_intrhand[bitno];
					ih != NULL;
				    ih = ih->ih_next) {
#ifdef MULTIPROCESSOR
					u_int32_t sr;
#endif
					splraise(ih->ih_level);
#ifdef MULTIPROCESSOR
					if (ih->ih_level < IPL_IPI) {
						sr = getsr();
						ENABLEIPI();
						if (ipl < IPL_SCHED)
							__mp_lock(&kernel_lock);
					}
#endif
					if ((*ih->ih_fun)(ih->ih_arg) != 0) {
						rc = 1;
						atomic_add_uint64(&ih->ih_count.ec_count, 1);
					}
#ifdef MULTIPROCESSOR
					if (ih->ih_level < IPL_IPI) {
						if (ipl < IPL_SCHED)
							__mp_unlock(&kernel_lock);
						setsr(sr);
					}
#endif
					__asm__ (".set noreorder\n");
					ci->ci_ipl = ipl;
					__asm__ ("sync\n\t.set reorder\n");
				}
				if (rc == 0)
					printf("spurious crime interrupt %d\n", bitno);

				isr ^= mask;
				if ((tmpisr ^= mask) == 0)
					break;
			}
		}

		/*
		 * Reenable interrupts which have been serviced.
		 */
		bus_space_write_8(&obio_tag, obio_h, en0, imr);
	}
u_int64_t
bs_through_bs_r_8(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset)
{
	return bus_space_read_8(t->bs_base, bsh, offset);
}
Beispiel #21
0
uint64_t
nep_read(struct nep_softc *sc, uint32_t reg)
{
	return bus_space_read_8(sc->sc_memt, sc->sc_memh, reg);
}
Beispiel #22
0
int
mec_intr(void *arg)
{
	struct mec_softc *sc = arg;
	bus_space_tag_t st = sc->sc_st;
	bus_space_handle_t sh = sc->sc_sh;
	struct ifnet *ifp = &sc->sc_ac.ac_if;
	uint32_t statreg, statack, dmac;
	int handled, sent;

	DPRINTF(MEC_DEBUG_INTR, ("mec_intr: called\n"));

	handled = sent = 0;

	for (;;) {
		statreg = bus_space_read_8(st, sh, MEC_INT_STATUS);

		DPRINTF(MEC_DEBUG_INTR,
		    ("mec_intr: INT_STAT = 0x%x\n", statreg));

		statack = statreg & MEC_INT_STATUS_MASK;
		if (statack == 0)
			break;
		bus_space_write_8(st, sh, MEC_INT_STATUS, statack);

		handled = 1;

		if (statack &
		    (MEC_INT_RX_THRESHOLD |
		     MEC_INT_RX_FIFO_UNDERFLOW)) {
			mec_rxintr(sc, statreg);
		}

		dmac = bus_space_read_8(st, sh, MEC_DMA_CONTROL);
		DPRINTF(MEC_DEBUG_INTR,
		    ("mec_intr: DMA_CONT = 0x%x\n", dmac));

		if (statack &
		    (MEC_INT_TX_EMPTY |
		     MEC_INT_TX_PACKET_SENT |
		     MEC_INT_TX_ABORT)) {
			mec_txintr(sc, statreg);
			sent = 1;
		}

		if (statack &
		    (MEC_INT_TX_LINK_FAIL |
		     MEC_INT_TX_MEM_ERROR |
		     MEC_INT_TX_ABORT |
		     MEC_INT_RX_DMA_UNDERFLOW)) {
			printf("%s: mec_intr: interrupt status = 0x%x\n",
			    sc->sc_dev.dv_xname, statreg);
		}
	}

	if (sent) {
		/* Try to get more packets going. */
		mec_start(ifp);
	}

	return handled;
}
Beispiel #23
0
void
mec_attach(struct device *parent, struct device *self, void *aux)
{
	struct mec_softc *sc = (void *)self;
	struct confargs *ca = aux;
	struct ifnet *ifp = &sc->sc_ac.ac_if;
	uint32_t command;
	struct mii_softc *child;
	bus_dma_segment_t seg;
	int i, err, rseg;

	sc->sc_st = ca->ca_iot;
	if (bus_space_map(sc->sc_st, ca->ca_baseaddr, MEC_NREGS, 0,
	    &sc->sc_sh) != 0) {
		printf(": can't map i/o space\n");
		return;
	}

	/* Set up DMA structures. */
	sc->sc_dmat = ca->ca_dmat;

	/*
	 * Allocate the control data structures, and create and load the
	 * DMA map for it.
	 */
	if ((err = bus_dmamem_alloc(sc->sc_dmat,
	    sizeof(struct mec_control_data), MEC_CONTROL_DATA_ALIGN, 0,
	    &seg, 1, &rseg, BUS_DMA_NOWAIT)) != 0) {
		printf(": unable to allocate control data, error = %d\n", err);
		goto fail_0;
	}

	/*
	 * XXX needs re-think...
	 * control data structures contain whole RX data buffer, so
	 * BUS_DMA_COHERENT (which disables cache) may cause some performance
	 * issue on copying data from the RX buffer to mbuf on normal memory,
	 * though we have to make sure all bus_dmamap_sync(9) ops are called
	 * properly in that case.
	 */
	if ((err = bus_dmamem_map(sc->sc_dmat, &seg, rseg,
	    sizeof(struct mec_control_data),
	    (caddr_t *)&sc->sc_control_data, /*BUS_DMA_COHERENT*/ 0)) != 0) {
		printf(": unable to map control data, error = %d\n", err);
		goto fail_1;
	}
	memset(sc->sc_control_data, 0, sizeof(struct mec_control_data));

	if ((err = bus_dmamap_create(sc->sc_dmat,
	    sizeof(struct mec_control_data), 1,
	    sizeof(struct mec_control_data), 0, 0, &sc->sc_cddmamap)) != 0) {
		printf(": unable to create control data DMA map, error = %d\n",
		    err);
		goto fail_2;
	}
	if ((err = bus_dmamap_load(sc->sc_dmat, sc->sc_cddmamap,
	    sc->sc_control_data, sizeof(struct mec_control_data), NULL,
	    BUS_DMA_NOWAIT)) != 0) {
		printf(": unable to load control data DMA map, error = %d\n",
		    err);
		goto fail_3;
	}

	/* Create TX buffer DMA maps. */
	for (i = 0; i < MEC_NTXDESC; i++) {
		if ((err = bus_dmamap_create(sc->sc_dmat,
		    MCLBYTES, 1, MCLBYTES, 0, 0,
		    &sc->sc_txsoft[i].txs_dmamap)) != 0) {
			printf(": unable to create tx DMA map %d, error = %d\n",
			    i, err);
			goto fail_4;
		}
	}

	timeout_set(&sc->sc_tick_ch, mec_tick, sc);

	/* Use the Ethernet address from the ARCBIOS. */
	enaddr_aton(bios_enaddr, sc->sc_ac.ac_enaddr);

	/* Reset device. */
	mec_reset(sc);

	command = bus_space_read_8(sc->sc_st, sc->sc_sh, MEC_MAC_CONTROL);

	printf(": MAC-110 rev %d, address %s\n",
	    (command & MEC_MAC_REVISION) >> MEC_MAC_REVISION_SHIFT,
	    ether_sprintf(sc->sc_ac.ac_enaddr));

	/* Done, now attach everything. */

	sc->sc_mii.mii_ifp = ifp;
	sc->sc_mii.mii_readreg = mec_mii_readreg;
	sc->sc_mii.mii_writereg = mec_mii_writereg;
	sc->sc_mii.mii_statchg = mec_statchg;

	/* Set up PHY properties. */
	ifmedia_init(&sc->sc_mii.mii_media, 0, mec_mediachange,
	    mec_mediastatus);
	mii_attach(&sc->sc_dev, &sc->sc_mii, 0xffffffff, MII_PHY_ANY,
	    MII_OFFSET_ANY, 0);

	child = LIST_FIRST(&sc->sc_mii.mii_phys);
	if (child == NULL) {
		/* No PHY attached. */
		ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER | IFM_MANUAL,
		    0, NULL);
		ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER | IFM_MANUAL);
	} else {
		ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER | IFM_AUTO);
		sc->sc_phyaddr = child->mii_phy;
	}

	bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
	ifp->if_softc = sc;
	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
	ifp->if_ioctl = mec_ioctl;
	ifp->if_start = mec_start;
	ifp->if_watchdog = mec_watchdog;
	IFQ_SET_READY(&ifp->if_snd);

	if_attach(ifp);
	IFQ_SET_MAXLEN(&ifp->if_snd, MEC_NTXDESC - 1);
	ether_ifattach(ifp);

	/* Establish interrupt handler. */
	macebus_intr_establish(NULL, ca->ca_intr, IST_EDGE, IPL_NET,
	    mec_intr, sc, sc->sc_dev.dv_xname);

	/* Set hook to stop interface on shutdown. */
	sc->sc_sdhook = shutdownhook_establish(mec_shutdown, sc);

	return;

	/*
	 * Free any resources we've allocated during the failed attach
	 * attempt. Do this in reverse order and fall though.
	 */
 fail_4:
	for (i = 0; i < MEC_NTXDESC; i++) {
		if (sc->sc_txsoft[i].txs_dmamap != NULL)
			bus_dmamap_destroy(sc->sc_dmat,
			    sc->sc_txsoft[i].txs_dmamap);
	}
	bus_dmamap_unload(sc->sc_dmat, sc->sc_cddmamap);
 fail_3:
	bus_dmamap_destroy(sc->sc_dmat, sc->sc_cddmamap);
 fail_2:
	bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_control_data,
	    sizeof(struct mec_control_data));
 fail_1:
	bus_dmamem_free(sc->sc_dmat, &seg, rseg);
 fail_0:
	return;
}
Beispiel #24
0
void
mec_rxintr(struct mec_softc *sc, uint32_t stat)
{
	bus_space_tag_t st = sc->sc_st;
	bus_space_handle_t sh = sc->sc_sh;
	struct ifnet *ifp = &sc->sc_ac.ac_if;
	struct mbuf *m;
	struct mec_rxdesc *rxd;
	uint64_t rxstat;
	u_int len;
	int i, last;

	DPRINTF(MEC_DEBUG_RXINTR, ("mec_rxintr: called\n"));

	bus_space_write_8(st, sh, MEC_RX_ALIAS, 0);

	last = (stat & MEC_INT_RX_MCL_FIFO_ALIAS) >> 8;
	/* XXX does alias count mod 32 even if 16 descs are set up? */
	last &= MEC_NRXDESC_MASK;

	if (stat & MEC_INT_RX_FIFO_UNDERFLOW)
		last = (last - 1) & MEC_NRXDESC_MASK;

	DPRINTF(MEC_DEBUG_RXINTR, ("mec_rxintr: rxptr %d last %d\n",
	    sc->sc_rxptr, last));
	for (i = sc->sc_rxptr; i != last; i = MEC_NEXTRX(i)) {

		MEC_RXSTATSYNC(sc, i, BUS_DMASYNC_POSTREAD);
		rxd = &sc->sc_rxdesc[i];
		rxstat = rxd->rxd_stat;

		DPRINTF(MEC_DEBUG_RXINTR,
		    ("mec_rxintr: rxstat = 0x%llx, rxptr = %d\n",
		    rxstat, i));
		DPRINTF(MEC_DEBUG_RXINTR, ("mec_rxintr: rxfifo = 0x%x\n",
		    (u_int)bus_space_read_8(st, sh, MEC_RX_FIFO)));

		if ((rxstat & MEC_RXSTAT_RECEIVED) == 0) {
			/* Status not received but FIFO counted? Drop it! */
			goto dropit;
		}

		len = rxstat & MEC_RXSTAT_LEN;

		if (len < ETHER_MIN_LEN ||
		    len > ETHER_MAX_LEN) {
			/* Invalid length packet; drop it. */
			DPRINTF(MEC_DEBUG_RXINTR,
			    ("mec_rxintr: wrong packet\n"));
 dropit:
			ifp->if_ierrors++;
			rxd->rxd_stat = 0;
			MEC_RXSTATSYNC(sc, i, BUS_DMASYNC_PREREAD);
			bus_space_write_8(st, sh, MEC_MCL_RX_FIFO,
			    MEC_CDRXADDR(sc, i));
			continue;
		}

		if (rxstat &
		    (MEC_RXSTAT_BADPACKET |
		     MEC_RXSTAT_LONGEVENT |
		     MEC_RXSTAT_INVALID   |
		     MEC_RXSTAT_CRCERROR  |
		     MEC_RXSTAT_VIOLATION)) {
			printf("%s: mec_rxintr: status = 0x%llx\n",
			    sc->sc_dev.dv_xname, rxstat);
			goto dropit;
		}

		/*
		 * Now allocate an mbuf (and possibly a cluster) to hold
		 * the received packet.
		 */
		MGETHDR(m, M_DONTWAIT, MT_DATA);
		if (m == NULL) {
			printf("%s: unable to allocate RX mbuf\n",
			    sc->sc_dev.dv_xname);
			goto dropit;
		}
		if (len > (MHLEN - ETHER_ALIGN)) {
			MCLGET(m, M_DONTWAIT);
			if ((m->m_flags & M_EXT) == 0) {
				printf("%s: unable to allocate RX cluster\n",
				    sc->sc_dev.dv_xname);
				m_freem(m);
				m = NULL;
				goto dropit;
			}
		}

		/*
		 * Note MEC chip seems to insert 2 byte padding at the start of
		 * RX buffer, but we copy whole buffer to avoid unaligned copy.
		 */
		MEC_RXBUFSYNC(sc, i, len + ETHER_ALIGN, BUS_DMASYNC_POSTREAD);
		memcpy(mtod(m, caddr_t), rxd->rxd_buf,
		    ETHER_ALIGN + len - ETHER_CRC_LEN);
		MEC_RXBUFSYNC(sc, i, ETHER_MAX_LEN, BUS_DMASYNC_PREREAD);
		m->m_data += ETHER_ALIGN;

		/* Put RX buffer into FIFO again. */
		rxd->rxd_stat = 0;
		MEC_RXSTATSYNC(sc, i, BUS_DMASYNC_PREREAD);
		bus_space_write_8(st, sh, MEC_MCL_RX_FIFO, MEC_CDRXADDR(sc, i));

		m->m_pkthdr.rcvif = ifp;
		m->m_pkthdr.len = m->m_len = len - ETHER_CRC_LEN;

		ifp->if_ipackets++;

#if NBPFILTER > 0
		/*
		 * Pass this up to any BPF listeners, but only
		 * pass it up the stack if it is for us.
		 */
		if (ifp->if_bpf)
			bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
#endif

		/* Pass it on. */
		ether_input_mbuf(ifp, m);
	}

	/* Update RX pointer. */
	sc->sc_rxptr = i;

	bus_space_write_8(st, sh, MEC_RX_ALIAS,
	    (MEC_NRXDESC << MEC_DMA_RX_INT_THRESH_SHIFT) |
	    MEC_DMA_RX_INT_ENABLE);
}