FreeBSD/mips port. The FreeBSD/mips port targets mips32, mips64,
mips32r2 and mips64r2 (and close relatives) processors. There
presently is support for ADMtek ADM5120, A mips 4Kc in a malta board,
the RB533 routerboard (based on IDT RC32434) and some preliminary
support for sibtye/broadcom designs. Other hardware support will be
forthcomcing.
This port boots multiuser under gxemul emulating the malta board and
also bootstraps on the hardware whose support is forthcoming...
Oleksandr Tymoshenko, Wojciech Koszek, Warner Losh, Olivier Houchard,
Randall Stewert and others that have contributed to the mips2 and/or
mips2-jnpr perforce branches. Juniper contirbuted a generic mips port
late in the life cycle of the misp2 branch. Warner Losh merged the
mips2 and Juniper code bases, and others list above have worked for
the past several months to get to multiuser.
In addition, the mips2 work owe a debt to the trail blazing efforts of
the original mips branch in perforce done by Juli Mallett.
2008-04-13 07:44:55 +00:00
|
|
|
/* $NetBSD: if_admsw.c,v 1.3 2007/04/22 19:26:25 dyoung Exp $ */
|
|
|
|
|
|
|
|
/*-
|
|
|
|
* Copyright (c) 2007 Ruslan Ermilov and Vsevolod Lobko.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or
|
|
|
|
* without modification, are permitted provided that the following
|
|
|
|
* conditions are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above
|
|
|
|
* copyright notice, this list of conditions and the following
|
|
|
|
* disclaimer in the documentation and/or other materials provided
|
|
|
|
* with the distribution.
|
|
|
|
* 3. The names of the authors may not be used to endorse or promote
|
|
|
|
* products derived from this software without specific prior
|
|
|
|
* written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY
|
|
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
|
|
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
|
|
|
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS
|
|
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
|
|
|
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
|
|
|
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
|
|
|
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
|
|
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
|
|
* OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
* Copyright (c) 2001 Wasabi Systems, Inc.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Written by Jason R. Thorpe for Wasabi Systems, Inc.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
|
|
* must display the following acknowledgement:
|
|
|
|
* This product includes software developed for the NetBSD Project by
|
|
|
|
* Wasabi Systems, Inc.
|
|
|
|
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
|
|
|
|
* or promote products derived from this software without specific prior
|
|
|
|
* written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
|
|
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Device driver for Alchemy Semiconductor Au1x00 Ethernet Media
|
|
|
|
* Access Controller.
|
|
|
|
*
|
|
|
|
* TODO:
|
|
|
|
*
|
|
|
|
* Better Rx buffer management; we want to get new Rx buffers
|
|
|
|
* to the chip more quickly than we currently do.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/cdefs.h>
|
|
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/bus.h>
|
|
|
|
#include <sys/kernel.h>
|
|
|
|
#include <sys/mbuf.h>
|
|
|
|
#include <sys/malloc.h>
|
|
|
|
#include <sys/module.h>
|
|
|
|
#include <sys/rman.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/sockio.h>
|
|
|
|
#include <sys/sysctl.h>
|
|
|
|
#include <machine/bus.h>
|
|
|
|
|
|
|
|
#include <net/ethernet.h>
|
|
|
|
#include <net/if.h>
|
|
|
|
#include <net/if_arp.h>
|
|
|
|
#include <net/if_dl.h>
|
|
|
|
#include <net/if_media.h>
|
|
|
|
#include <net/if_mib.h>
|
|
|
|
#include <net/if_types.h>
|
|
|
|
|
|
|
|
#ifdef INET
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <netinet/in_systm.h>
|
|
|
|
#include <netinet/in_var.h>
|
|
|
|
#include <netinet/ip.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <net/bpf.h>
|
|
|
|
#include <net/bpfdesc.h>
|
|
|
|
|
2008-09-10 03:49:08 +00:00
|
|
|
#include <mips/adm5120/adm5120reg.h>
|
|
|
|
#include <mips/adm5120/if_admswreg.h>
|
|
|
|
#include <mips/adm5120/if_admswvar.h>
|
FreeBSD/mips port. The FreeBSD/mips port targets mips32, mips64,
mips32r2 and mips64r2 (and close relatives) processors. There
presently is support for ADMtek ADM5120, A mips 4Kc in a malta board,
the RB533 routerboard (based on IDT RC32434) and some preliminary
support for sibtye/broadcom designs. Other hardware support will be
forthcomcing.
This port boots multiuser under gxemul emulating the malta board and
also bootstraps on the hardware whose support is forthcoming...
Oleksandr Tymoshenko, Wojciech Koszek, Warner Losh, Olivier Houchard,
Randall Stewert and others that have contributed to the mips2 and/or
mips2-jnpr perforce branches. Juniper contirbuted a generic mips port
late in the life cycle of the misp2 branch. Warner Losh merged the
mips2 and Juniper code bases, and others list above have worked for
the past several months to get to multiuser.
In addition, the mips2 work owe a debt to the trail blazing efforts of
the original mips branch in perforce done by Juli Mallett.
2008-04-13 07:44:55 +00:00
|
|
|
|
|
|
|
/* TODO: add locking */
|
|
|
|
#define ADMSW_LOCK(sc) do {} while(0);
|
|
|
|
#define ADMSW_UNLOCK(sc) do {} while(0);
|
|
|
|
|
|
|
|
static uint8_t vlan_matrix[SW_DEVS] = {
|
|
|
|
(1 << 6) | (1 << 0), /* CPU + port0 */
|
|
|
|
(1 << 6) | (1 << 1), /* CPU + port1 */
|
|
|
|
(1 << 6) | (1 << 2), /* CPU + port2 */
|
|
|
|
(1 << 6) | (1 << 3), /* CPU + port3 */
|
|
|
|
(1 << 6) | (1 << 4), /* CPU + port4 */
|
|
|
|
(1 << 6) | (1 << 5), /* CPU + port5 */
|
|
|
|
};
|
|
|
|
|
|
|
|
/* ifnet entry points */
|
|
|
|
static void admsw_start(struct ifnet *);
|
|
|
|
static void admsw_watchdog(struct ifnet *);
|
|
|
|
static int admsw_ioctl(struct ifnet *, u_long, caddr_t);
|
|
|
|
static void admsw_init(void *);
|
|
|
|
static void admsw_stop(struct ifnet *, int);
|
|
|
|
|
|
|
|
static void admsw_reset(struct admsw_softc *);
|
|
|
|
static void admsw_set_filter(struct admsw_softc *);
|
|
|
|
|
|
|
|
static void admsw_txintr(struct admsw_softc *, int);
|
|
|
|
static void admsw_rxintr(struct admsw_softc *, int);
|
|
|
|
static int admsw_add_rxbuf(struct admsw_softc *, int, int);
|
|
|
|
#define admsw_add_rxhbuf(sc, idx) admsw_add_rxbuf(sc, idx, 1)
|
|
|
|
#define admsw_add_rxlbuf(sc, idx) admsw_add_rxbuf(sc, idx, 0)
|
|
|
|
|
|
|
|
static int admsw_mediachange(struct ifnet *);
|
|
|
|
static void admsw_mediastatus(struct ifnet *, struct ifmediareq *);
|
|
|
|
|
|
|
|
static int admsw_intr(void *);
|
|
|
|
|
|
|
|
/* bus entry points */
|
|
|
|
static int admsw_probe(device_t dev);
|
|
|
|
static int admsw_attach(device_t dev);
|
|
|
|
static int admsw_detach(device_t dev);
|
2009-06-17 10:23:25 +00:00
|
|
|
static int admsw_shutdown(device_t dev);
|
FreeBSD/mips port. The FreeBSD/mips port targets mips32, mips64,
mips32r2 and mips64r2 (and close relatives) processors. There
presently is support for ADMtek ADM5120, A mips 4Kc in a malta board,
the RB533 routerboard (based on IDT RC32434) and some preliminary
support for sibtye/broadcom designs. Other hardware support will be
forthcomcing.
This port boots multiuser under gxemul emulating the malta board and
also bootstraps on the hardware whose support is forthcoming...
Oleksandr Tymoshenko, Wojciech Koszek, Warner Losh, Olivier Houchard,
Randall Stewert and others that have contributed to the mips2 and/or
mips2-jnpr perforce branches. Juniper contirbuted a generic mips port
late in the life cycle of the misp2 branch. Warner Losh merged the
mips2 and Juniper code bases, and others list above have worked for
the past several months to get to multiuser.
In addition, the mips2 work owe a debt to the trail blazing efforts of
the original mips branch in perforce done by Juli Mallett.
2008-04-13 07:44:55 +00:00
|
|
|
|
|
|
|
static void
|
|
|
|
admsw_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error)
|
|
|
|
{
|
|
|
|
uint32_t *addr;
|
|
|
|
|
|
|
|
if (error)
|
|
|
|
return;
|
|
|
|
|
|
|
|
KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg));
|
|
|
|
addr = arg;
|
|
|
|
*addr = segs->ds_addr;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
admsw_rxbuf_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error)
|
|
|
|
{
|
|
|
|
struct admsw_descsoft *ds;
|
|
|
|
|
|
|
|
if (error)
|
|
|
|
return;
|
|
|
|
|
|
|
|
KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg));
|
|
|
|
|
|
|
|
ds = arg;
|
|
|
|
ds->ds_nsegs = nseg;
|
|
|
|
ds->ds_addr[0] = segs[0].ds_addr;
|
|
|
|
ds->ds_len[0] = segs[0].ds_len;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
admsw_mbuf_map_addr(void *arg, bus_dma_segment_t *segs, int nseg,
|
|
|
|
bus_size_t mapsize, int error)
|
|
|
|
{
|
|
|
|
struct admsw_descsoft *ds;
|
|
|
|
|
|
|
|
if (error)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ds = arg;
|
|
|
|
|
|
|
|
if((nseg != 1) && (nseg != 2))
|
|
|
|
panic("%s: nseg == %d\n", __func__, nseg);
|
|
|
|
|
|
|
|
ds->ds_nsegs = nseg;
|
|
|
|
ds->ds_addr[0] = segs[0].ds_addr;
|
|
|
|
ds->ds_len[0] = segs[0].ds_len;
|
|
|
|
|
|
|
|
if(nseg > 1) {
|
|
|
|
ds->ds_addr[1] = segs[1].ds_addr;
|
|
|
|
ds->ds_len[1] = segs[1].ds_len;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
admsw_probe(device_t dev)
|
|
|
|
{
|
|
|
|
|
|
|
|
device_set_desc(dev, "ADM5120 Switch Engine");
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
#define REG_READ(o) bus_read_4((sc)->mem_res, (o))
|
|
|
|
#define REG_WRITE(o,v) bus_write_4((sc)->mem_res, (o),(v))
|
|
|
|
|
|
|
|
static void
|
|
|
|
admsw_init_bufs(struct admsw_softc *sc)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
struct admsw_desc *desc;
|
|
|
|
|
|
|
|
for (i = 0; i < ADMSW_NTXHDESC; i++) {
|
|
|
|
if (sc->sc_txhsoft[i].ds_mbuf != NULL) {
|
|
|
|
m_freem(sc->sc_txhsoft[i].ds_mbuf);
|
|
|
|
sc->sc_txhsoft[i].ds_mbuf = NULL;
|
|
|
|
}
|
|
|
|
desc = &sc->sc_txhdescs[i];
|
|
|
|
desc->data = 0;
|
|
|
|
desc->cntl = 0;
|
|
|
|
desc->len = MAC_BUFLEN;
|
|
|
|
desc->status = 0;
|
|
|
|
ADMSW_CDTXHSYNC(sc, i,
|
|
|
|
BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
|
|
|
|
}
|
|
|
|
sc->sc_txhdescs[ADMSW_NTXHDESC - 1].data |= ADM5120_DMA_RINGEND;
|
|
|
|
ADMSW_CDTXHSYNC(sc, ADMSW_NTXHDESC - 1,
|
|
|
|
BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
|
|
|
|
|
|
|
|
for (i = 0; i < ADMSW_NRXHDESC; i++) {
|
|
|
|
if (sc->sc_rxhsoft[i].ds_mbuf == NULL) {
|
|
|
|
if (admsw_add_rxhbuf(sc, i) != 0)
|
|
|
|
panic("admsw_init_bufs\n");
|
|
|
|
} else
|
|
|
|
ADMSW_INIT_RXHDESC(sc, i);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < ADMSW_NTXLDESC; i++) {
|
|
|
|
if (sc->sc_txlsoft[i].ds_mbuf != NULL) {
|
|
|
|
m_freem(sc->sc_txlsoft[i].ds_mbuf);
|
|
|
|
sc->sc_txlsoft[i].ds_mbuf = NULL;
|
|
|
|
}
|
|
|
|
desc = &sc->sc_txldescs[i];
|
|
|
|
desc->data = 0;
|
|
|
|
desc->cntl = 0;
|
|
|
|
desc->len = MAC_BUFLEN;
|
|
|
|
desc->status = 0;
|
|
|
|
ADMSW_CDTXLSYNC(sc, i,
|
|
|
|
BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
|
|
|
|
}
|
|
|
|
sc->sc_txldescs[ADMSW_NTXLDESC - 1].data |= ADM5120_DMA_RINGEND;
|
|
|
|
ADMSW_CDTXLSYNC(sc, ADMSW_NTXLDESC - 1,
|
|
|
|
BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
|
|
|
|
|
|
|
|
for (i = 0; i < ADMSW_NRXLDESC; i++) {
|
|
|
|
if (sc->sc_rxlsoft[i].ds_mbuf == NULL) {
|
|
|
|
if (admsw_add_rxlbuf(sc, i) != 0)
|
|
|
|
panic("admsw_init_bufs\n");
|
|
|
|
} else
|
|
|
|
ADMSW_INIT_RXLDESC(sc, i);
|
|
|
|
}
|
|
|
|
|
|
|
|
REG_WRITE(SEND_HBADDR_REG, ADMSW_CDTXHADDR(sc, 0));
|
|
|
|
REG_WRITE(SEND_LBADDR_REG, ADMSW_CDTXLADDR(sc, 0));
|
|
|
|
REG_WRITE(RECV_HBADDR_REG, ADMSW_CDRXHADDR(sc, 0));
|
|
|
|
REG_WRITE(RECV_LBADDR_REG, ADMSW_CDRXLADDR(sc, 0));
|
|
|
|
|
|
|
|
sc->sc_txfree = ADMSW_NTXLDESC;
|
|
|
|
sc->sc_txnext = 0;
|
|
|
|
sc->sc_txdirty = 0;
|
|
|
|
sc->sc_rxptr = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
admsw_setvlan(struct admsw_softc *sc, char matrix[6])
|
|
|
|
{
|
|
|
|
uint32_t i;
|
|
|
|
|
|
|
|
i = matrix[0] + (matrix[1] << 8) + (matrix[2] << 16) + (matrix[3] << 24);
|
|
|
|
REG_WRITE(VLAN_G1_REG, i);
|
|
|
|
i = matrix[4] + (matrix[5] << 8);
|
|
|
|
REG_WRITE(VLAN_G2_REG, i);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
admsw_reset(struct admsw_softc *sc)
|
|
|
|
{
|
|
|
|
uint32_t wdog1;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
REG_WRITE(PORT_CONF0_REG,
|
|
|
|
REG_READ(PORT_CONF0_REG) | PORT_CONF0_DP_MASK);
|
|
|
|
REG_WRITE(CPUP_CONF_REG,
|
|
|
|
REG_READ(CPUP_CONF_REG) | CPUP_CONF_DCPUP);
|
|
|
|
|
|
|
|
/* Wait for DMA to complete. Overkill. In 3ms, we can
|
|
|
|
* send at least two entire 1500-byte packets at 10 Mb/s.
|
|
|
|
*/
|
|
|
|
DELAY(3000);
|
|
|
|
|
|
|
|
/* The datasheet recommends that we move all PHYs to reset
|
|
|
|
* state prior to software reset.
|
|
|
|
*/
|
|
|
|
REG_WRITE(PHY_CNTL2_REG,
|
|
|
|
REG_READ(PHY_CNTL2_REG) & ~PHY_CNTL2_PHYR_MASK);
|
|
|
|
|
|
|
|
/* Reset the switch. */
|
|
|
|
REG_WRITE(ADMSW_SW_RES, 0x1);
|
|
|
|
|
|
|
|
DELAY(100 * 1000);
|
|
|
|
|
|
|
|
REG_WRITE(ADMSW_BOOT_DONE, ADMSW_BOOT_DONE_BO);
|
|
|
|
|
|
|
|
/* begin old code */
|
|
|
|
REG_WRITE(CPUP_CONF_REG,
|
|
|
|
CPUP_CONF_DCPUP | CPUP_CONF_CRCP | CPUP_CONF_DUNP_MASK |
|
|
|
|
CPUP_CONF_DMCP_MASK);
|
|
|
|
|
|
|
|
REG_WRITE(PORT_CONF0_REG, PORT_CONF0_EMCP_MASK | PORT_CONF0_EMBP_MASK);
|
|
|
|
|
|
|
|
REG_WRITE(PHY_CNTL2_REG,
|
|
|
|
REG_READ(PHY_CNTL2_REG) | PHY_CNTL2_ANE_MASK | PHY_CNTL2_PHYR_MASK |
|
|
|
|
PHY_CNTL2_AMDIX_MASK);
|
|
|
|
|
|
|
|
REG_WRITE(PHY_CNTL3_REG, REG_READ(PHY_CNTL3_REG) | PHY_CNTL3_RNT);
|
|
|
|
|
|
|
|
REG_WRITE(ADMSW_INT_MASK, INT_MASK);
|
|
|
|
REG_WRITE(ADMSW_INT_ST, INT_MASK);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* While in DDB, we stop servicing interrupts, RX ring
|
|
|
|
* fills up and when free block counter falls behind FC
|
|
|
|
* threshold, the switch starts to emit 802.3x PAUSE
|
|
|
|
* frames. This can upset peer switches.
|
|
|
|
*
|
|
|
|
* Stop this from happening by disabling FC and D2
|
|
|
|
* thresholds.
|
|
|
|
*/
|
|
|
|
REG_WRITE(FC_TH_REG,
|
|
|
|
REG_READ(FC_TH_REG) & ~(FC_TH_FCS_MASK | FC_TH_D2S_MASK));
|
|
|
|
|
|
|
|
admsw_setvlan(sc, vlan_matrix);
|
|
|
|
|
|
|
|
for (i = 0; i < SW_DEVS; i++) {
|
|
|
|
REG_WRITE(MAC_WT1_REG,
|
|
|
|
sc->sc_enaddr[2] |
|
|
|
|
(sc->sc_enaddr[3]<<8) |
|
|
|
|
(sc->sc_enaddr[4]<<16) |
|
|
|
|
((sc->sc_enaddr[5]+i)<<24));
|
|
|
|
REG_WRITE(MAC_WT0_REG, (i<<MAC_WT0_VLANID_SHIFT) |
|
|
|
|
(sc->sc_enaddr[0]<<16) | (sc->sc_enaddr[1]<<24) |
|
|
|
|
MAC_WT0_WRITE | MAC_WT0_VLANID_EN);
|
|
|
|
|
|
|
|
while (!(REG_READ(MAC_WT0_REG) & MAC_WT0_WRITE_DONE));
|
|
|
|
}
|
|
|
|
|
|
|
|
wdog1 = REG_READ(ADM5120_WDOG1);
|
|
|
|
REG_WRITE(ADM5120_WDOG1, wdog1 & ~ADM5120_WDOG1_WDE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
admsw_attach(device_t dev)
|
|
|
|
{
|
|
|
|
uint8_t enaddr[ETHER_ADDR_LEN];
|
|
|
|
struct admsw_softc *sc = (struct admsw_softc *) device_get_softc(dev);
|
|
|
|
struct ifnet *ifp;
|
|
|
|
int error, i, rid;
|
|
|
|
|
|
|
|
sc->sc_dev = dev;
|
|
|
|
device_printf(dev, "ADM5120 Switch Engine, %d ports\n", SW_DEVS);
|
|
|
|
sc->ndevs = 0;
|
|
|
|
|
|
|
|
/* XXXMIPS: fix it */
|
|
|
|
enaddr[0] = 0x00;
|
|
|
|
enaddr[1] = 0x0C;
|
|
|
|
enaddr[2] = 0x42;
|
|
|
|
enaddr[3] = 0x07;
|
|
|
|
enaddr[4] = 0xB2;
|
|
|
|
enaddr[5] = 0x4E;
|
|
|
|
|
|
|
|
memcpy(sc->sc_enaddr, enaddr, sizeof(sc->sc_enaddr));
|
|
|
|
|
|
|
|
device_printf(sc->sc_dev, "base Ethernet address %s\n",
|
|
|
|
ether_sprintf(enaddr));
|
|
|
|
|
|
|
|
rid = 0;
|
|
|
|
if ((sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
|
|
|
|
RF_ACTIVE)) == NULL) {
|
|
|
|
device_printf(dev, "unable to allocate memory resource\n");
|
|
|
|
return (ENXIO);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Hook up the interrupt handler. */
|
|
|
|
rid = 0;
|
|
|
|
if ((sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
|
|
|
|
RF_SHAREABLE | RF_ACTIVE)) == NULL) {
|
|
|
|
device_printf(dev, "unable to allocate IRQ resource\n");
|
|
|
|
return (ENXIO);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET,
|
|
|
|
admsw_intr, NULL, sc, &sc->sc_ih)) != 0) {
|
|
|
|
device_printf(dev,
|
|
|
|
"WARNING: unable to register interrupt handler\n");
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Allocate the control data structures, and create and load the
|
|
|
|
* DMA map for it.
|
|
|
|
*/
|
|
|
|
if ((error = bus_dma_tag_create(NULL, 4, 0,
|
|
|
|
BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR,
|
|
|
|
NULL, NULL, sizeof(struct admsw_control_data), 1,
|
|
|
|
sizeof(struct admsw_control_data), 0, NULL, NULL,
|
|
|
|
&sc->sc_control_dmat)) != 0) {
|
|
|
|
device_printf(sc->sc_dev,
|
|
|
|
"unable to create control data DMA map, error = %d\n",
|
|
|
|
error);
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((error = bus_dmamem_alloc(sc->sc_control_dmat,
|
|
|
|
(void **)&sc->sc_control_data, BUS_DMA_NOWAIT,
|
|
|
|
&sc->sc_cddmamap)) != 0) {
|
|
|
|
device_printf(sc->sc_dev,
|
|
|
|
"unable to allocate control data, error = %d\n", error);
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((error = bus_dmamap_load(sc->sc_control_dmat, sc->sc_cddmamap,
|
|
|
|
sc->sc_control_data, sizeof(struct admsw_control_data),
|
|
|
|
admsw_dma_map_addr, &sc->sc_cddma, 0)) != 0) {
|
|
|
|
device_printf(sc->sc_dev,
|
|
|
|
"unable to load control data DMA map, error = %d\n", error);
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create the transmit buffer DMA maps.
|
|
|
|
*/
|
|
|
|
if ((error = bus_dma_tag_create(NULL, 1, 0,
|
|
|
|
BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR,
|
|
|
|
NULL, NULL, MCLBYTES, 1, MCLBYTES, 0, NULL, NULL,
|
|
|
|
&sc->sc_bufs_dmat)) != 0) {
|
|
|
|
device_printf(sc->sc_dev,
|
|
|
|
"unable to create control data DMA map, error = %d\n",
|
|
|
|
error);
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < ADMSW_NTXHDESC; i++) {
|
|
|
|
if ((error = bus_dmamap_create(sc->sc_bufs_dmat, 0,
|
|
|
|
&sc->sc_txhsoft[i].ds_dmamap)) != 0) {
|
|
|
|
device_printf(sc->sc_dev,
|
|
|
|
"unable to create txh DMA map %d, error = %d\n",
|
|
|
|
i, error);
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
sc->sc_txhsoft[i].ds_mbuf = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < ADMSW_NTXLDESC; i++) {
|
|
|
|
if ((error = bus_dmamap_create(sc->sc_bufs_dmat, 0,
|
|
|
|
&sc->sc_txlsoft[i].ds_dmamap)) != 0) {
|
|
|
|
device_printf(sc->sc_dev,
|
|
|
|
"unable to create txl DMA map %d, error = %d\n",
|
|
|
|
i, error);
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
sc->sc_txlsoft[i].ds_mbuf = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create the receive buffer DMA maps.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < ADMSW_NRXHDESC; i++) {
|
|
|
|
if ((error = bus_dmamap_create(sc->sc_bufs_dmat, 0,
|
|
|
|
&sc->sc_rxhsoft[i].ds_dmamap)) != 0) {
|
|
|
|
device_printf(sc->sc_dev,
|
|
|
|
"unable to create rxh DMA map %d, error = %d\n",
|
|
|
|
i, error);
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
sc->sc_rxhsoft[i].ds_mbuf = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < ADMSW_NRXLDESC; i++) {
|
|
|
|
if ((error = bus_dmamap_create(sc->sc_bufs_dmat, 0,
|
|
|
|
&sc->sc_rxlsoft[i].ds_dmamap)) != 0) {
|
|
|
|
device_printf(sc->sc_dev,
|
|
|
|
"unable to create rxl DMA map %d, error = %d\n",
|
|
|
|
i, error);
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
sc->sc_rxlsoft[i].ds_mbuf = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
admsw_init_bufs(sc);
|
|
|
|
admsw_reset(sc);
|
|
|
|
|
|
|
|
for (i = 0; i < SW_DEVS; i++) {
|
|
|
|
ifmedia_init(&sc->sc_ifmedia[i], 0, admsw_mediachange,
|
|
|
|
admsw_mediastatus);
|
|
|
|
ifmedia_add(&sc->sc_ifmedia[i], IFM_ETHER|IFM_10_T, 0, NULL);
|
|
|
|
ifmedia_add(&sc->sc_ifmedia[i],
|
|
|
|
IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL);
|
|
|
|
ifmedia_add(&sc->sc_ifmedia[i], IFM_ETHER|IFM_100_TX, 0, NULL);
|
|
|
|
ifmedia_add(&sc->sc_ifmedia[i],
|
|
|
|
IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL);
|
|
|
|
ifmedia_add(&sc->sc_ifmedia[i], IFM_ETHER|IFM_AUTO, 0, NULL);
|
|
|
|
ifmedia_set(&sc->sc_ifmedia[i], IFM_ETHER|IFM_AUTO);
|
|
|
|
|
|
|
|
ifp = sc->sc_ifnet[i] = if_alloc(IFT_ETHER);;
|
|
|
|
|
|
|
|
/* Setup interface parameters */
|
|
|
|
ifp->if_softc = sc;
|
|
|
|
if_initname(ifp, device_get_name(dev), i);
|
|
|
|
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
|
|
|
|
ifp->if_ioctl = admsw_ioctl;
|
|
|
|
ifp->if_output = ether_output;
|
|
|
|
ifp->if_start = admsw_start;
|
|
|
|
ifp->if_watchdog = admsw_watchdog;
|
|
|
|
ifp->if_timer = 0;
|
|
|
|
ifp->if_init = admsw_init;
|
|
|
|
ifp->if_mtu = ETHERMTU;
|
|
|
|
ifp->if_baudrate = IF_Mbps(100);
|
|
|
|
IFQ_SET_MAXLEN(&ifp->if_snd, max(ADMSW_NTXLDESC, IFQ_MAXLEN));
|
|
|
|
ifp->if_snd.ifq_drv_maxlen = max(ADMSW_NTXLDESC, IFQ_MAXLEN);
|
|
|
|
IFQ_SET_READY(&ifp->if_snd);
|
|
|
|
ifp->if_capabilities |= IFCAP_VLAN_MTU;
|
|
|
|
|
|
|
|
/* Attach the interface. */
|
|
|
|
ether_ifattach(ifp, enaddr);
|
|
|
|
enaddr[5]++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX: admwdog_attach(sc); */
|
|
|
|
|
|
|
|
/* leave interrupts and cpu port disabled */
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
admsw_detach(device_t dev)
|
|
|
|
{
|
|
|
|
|
|
|
|
printf("TODO: DETACH\n");
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* admsw_shutdown:
|
|
|
|
*
|
|
|
|
* Make sure the interface is stopped at reboot time.
|
|
|
|
*/
|
2009-06-17 10:23:25 +00:00
|
|
|
static int
|
|
|
|
admsw_shutdown(device_t dev)
|
FreeBSD/mips port. The FreeBSD/mips port targets mips32, mips64,
mips32r2 and mips64r2 (and close relatives) processors. There
presently is support for ADMtek ADM5120, A mips 4Kc in a malta board,
the RB533 routerboard (based on IDT RC32434) and some preliminary
support for sibtye/broadcom designs. Other hardware support will be
forthcomcing.
This port boots multiuser under gxemul emulating the malta board and
also bootstraps on the hardware whose support is forthcoming...
Oleksandr Tymoshenko, Wojciech Koszek, Warner Losh, Olivier Houchard,
Randall Stewert and others that have contributed to the mips2 and/or
mips2-jnpr perforce branches. Juniper contirbuted a generic mips port
late in the life cycle of the misp2 branch. Warner Losh merged the
mips2 and Juniper code bases, and others list above have worked for
the past several months to get to multiuser.
In addition, the mips2 work owe a debt to the trail blazing efforts of
the original mips branch in perforce done by Juli Mallett.
2008-04-13 07:44:55 +00:00
|
|
|
{
|
2009-06-17 10:23:25 +00:00
|
|
|
struct admsw_softc *sc;
|
FreeBSD/mips port. The FreeBSD/mips port targets mips32, mips64,
mips32r2 and mips64r2 (and close relatives) processors. There
presently is support for ADMtek ADM5120, A mips 4Kc in a malta board,
the RB533 routerboard (based on IDT RC32434) and some preliminary
support for sibtye/broadcom designs. Other hardware support will be
forthcomcing.
This port boots multiuser under gxemul emulating the malta board and
also bootstraps on the hardware whose support is forthcoming...
Oleksandr Tymoshenko, Wojciech Koszek, Warner Losh, Olivier Houchard,
Randall Stewert and others that have contributed to the mips2 and/or
mips2-jnpr perforce branches. Juniper contirbuted a generic mips port
late in the life cycle of the misp2 branch. Warner Losh merged the
mips2 and Juniper code bases, and others list above have worked for
the past several months to get to multiuser.
In addition, the mips2 work owe a debt to the trail blazing efforts of
the original mips branch in perforce done by Juli Mallett.
2008-04-13 07:44:55 +00:00
|
|
|
int i;
|
|
|
|
|
2009-06-17 10:23:25 +00:00
|
|
|
sc = device_get_softc(dev);
|
FreeBSD/mips port. The FreeBSD/mips port targets mips32, mips64,
mips32r2 and mips64r2 (and close relatives) processors. There
presently is support for ADMtek ADM5120, A mips 4Kc in a malta board,
the RB533 routerboard (based on IDT RC32434) and some preliminary
support for sibtye/broadcom designs. Other hardware support will be
forthcomcing.
This port boots multiuser under gxemul emulating the malta board and
also bootstraps on the hardware whose support is forthcoming...
Oleksandr Tymoshenko, Wojciech Koszek, Warner Losh, Olivier Houchard,
Randall Stewert and others that have contributed to the mips2 and/or
mips2-jnpr perforce branches. Juniper contirbuted a generic mips port
late in the life cycle of the misp2 branch. Warner Losh merged the
mips2 and Juniper code bases, and others list above have worked for
the past several months to get to multiuser.
In addition, the mips2 work owe a debt to the trail blazing efforts of
the original mips branch in perforce done by Juli Mallett.
2008-04-13 07:44:55 +00:00
|
|
|
for (i = 0; i < SW_DEVS; i++)
|
|
|
|
admsw_stop(sc->sc_ifnet[i], 1);
|
2009-06-17 10:23:25 +00:00
|
|
|
|
|
|
|
return (0);
|
FreeBSD/mips port. The FreeBSD/mips port targets mips32, mips64,
mips32r2 and mips64r2 (and close relatives) processors. There
presently is support for ADMtek ADM5120, A mips 4Kc in a malta board,
the RB533 routerboard (based on IDT RC32434) and some preliminary
support for sibtye/broadcom designs. Other hardware support will be
forthcomcing.
This port boots multiuser under gxemul emulating the malta board and
also bootstraps on the hardware whose support is forthcoming...
Oleksandr Tymoshenko, Wojciech Koszek, Warner Losh, Olivier Houchard,
Randall Stewert and others that have contributed to the mips2 and/or
mips2-jnpr perforce branches. Juniper contirbuted a generic mips port
late in the life cycle of the misp2 branch. Warner Losh merged the
mips2 and Juniper code bases, and others list above have worked for
the past several months to get to multiuser.
In addition, the mips2 work owe a debt to the trail blazing efforts of
the original mips branch in perforce done by Juli Mallett.
2008-04-13 07:44:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* admsw_start: [ifnet interface function]
|
|
|
|
*
|
|
|
|
* Start packet transmission on the interface.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
admsw_start(struct ifnet *ifp)
|
|
|
|
{
|
|
|
|
struct admsw_softc *sc = ifp->if_softc;
|
|
|
|
struct mbuf *m0, *m;
|
|
|
|
struct admsw_descsoft *ds;
|
|
|
|
struct admsw_desc *desc;
|
|
|
|
bus_dmamap_t dmamap;
|
|
|
|
struct ether_header *eh;
|
|
|
|
int error, nexttx, len, i;
|
|
|
|
static int vlan = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Loop through the send queues, setting up transmit descriptors
|
|
|
|
* unitl we drain the queues, or use up all available transmit
|
|
|
|
* descriptors.
|
|
|
|
*/
|
|
|
|
for (;;) {
|
|
|
|
vlan++;
|
|
|
|
if (vlan == SW_DEVS)
|
|
|
|
vlan = 0;
|
|
|
|
i = vlan;
|
|
|
|
for (;;) {
|
|
|
|
ifp = sc->sc_ifnet[i];
|
|
|
|
if ((ifp->if_drv_flags & (IFF_DRV_RUNNING|IFF_DRV_OACTIVE))
|
|
|
|
== IFF_DRV_RUNNING) {
|
|
|
|
/* Grab a packet off the queue. */
|
|
|
|
IF_DEQUEUE(&ifp->if_snd, m0);
|
|
|
|
if (m0 != NULL)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
if (i == SW_DEVS)
|
|
|
|
i = 0;
|
|
|
|
if (i == vlan)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
vlan = i;
|
|
|
|
m = NULL;
|
|
|
|
|
|
|
|
/* Get a spare descriptor. */
|
|
|
|
if (sc->sc_txfree == 0) {
|
|
|
|
/* No more slots left; notify upper layer. */
|
|
|
|
ifp->if_drv_flags |= IFF_DRV_OACTIVE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
nexttx = sc->sc_txnext;
|
|
|
|
desc = &sc->sc_txldescs[nexttx];
|
|
|
|
ds = &sc->sc_txlsoft[nexttx];
|
|
|
|
dmamap = ds->ds_dmamap;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Load the DMA map. If this fails, the packet either
|
|
|
|
* didn't fit in the alloted number of segments, or we
|
|
|
|
* were short on resources. In this case, we'll copy
|
|
|
|
* and try again.
|
|
|
|
*/
|
|
|
|
if (m0->m_pkthdr.len < ETHER_MIN_LEN ||
|
|
|
|
bus_dmamap_load_mbuf(sc->sc_bufs_dmat, dmamap, m0,
|
|
|
|
admsw_mbuf_map_addr, ds, BUS_DMA_NOWAIT) != 0) {
|
|
|
|
MGETHDR(m, M_DONTWAIT, MT_DATA);
|
|
|
|
if (m == NULL) {
|
|
|
|
device_printf(sc->sc_dev,
|
|
|
|
"unable to allocate Tx mbuf\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (m0->m_pkthdr.len > MHLEN) {
|
|
|
|
MCLGET(m, M_DONTWAIT);
|
|
|
|
if ((m->m_flags & M_EXT) == 0) {
|
|
|
|
device_printf(sc->sc_dev,
|
|
|
|
"unable to allocate Tx cluster\n");
|
|
|
|
m_freem(m);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
m->m_pkthdr.csum_flags = m0->m_pkthdr.csum_flags;
|
|
|
|
m_copydata(m0, 0, m0->m_pkthdr.len, mtod(m, void *));
|
|
|
|
m->m_pkthdr.len = m->m_len = m0->m_pkthdr.len;
|
|
|
|
if (m->m_pkthdr.len < ETHER_MIN_LEN) {
|
|
|
|
if (M_TRAILINGSPACE(m) < ETHER_MIN_LEN - m->m_pkthdr.len)
|
|
|
|
panic("admsw_start: M_TRAILINGSPACE\n");
|
|
|
|
memset(mtod(m, uint8_t *) + m->m_pkthdr.len, 0,
|
|
|
|
ETHER_MIN_LEN - ETHER_CRC_LEN - m->m_pkthdr.len);
|
|
|
|
m->m_pkthdr.len = m->m_len = ETHER_MIN_LEN;
|
|
|
|
}
|
|
|
|
error = bus_dmamap_load_mbuf(sc->sc_bufs_dmat,
|
|
|
|
dmamap, m, admsw_mbuf_map_addr, ds, BUS_DMA_NOWAIT);
|
|
|
|
if (error) {
|
|
|
|
device_printf(sc->sc_dev,
|
|
|
|
"unable to load Tx buffer, error = %d\n",
|
|
|
|
error);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m != NULL) {
|
|
|
|
m_freem(m0);
|
|
|
|
m0 = m;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* WE ARE NOW COMMITTED TO TRANSMITTING THE PACKET.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Sync the DMA map. */
|
|
|
|
bus_dmamap_sync(sc->sc_bufs_dmat, dmamap, BUS_DMASYNC_PREWRITE);
|
|
|
|
|
|
|
|
if (ds->ds_nsegs != 1 && ds->ds_nsegs != 2)
|
|
|
|
panic("admsw_start: nsegs == %d\n", ds->ds_nsegs);
|
|
|
|
desc->data = ds->ds_addr[0];
|
|
|
|
desc->len = len = ds->ds_len[0];
|
|
|
|
if (ds->ds_nsegs > 1) {
|
|
|
|
len += ds->ds_len[1];
|
|
|
|
desc->cntl = ds->ds_addr[1] | ADM5120_DMA_BUF2ENABLE;
|
|
|
|
} else
|
|
|
|
desc->cntl = 0;
|
|
|
|
desc->status = (len << ADM5120_DMA_LENSHIFT) | (1 << vlan);
|
|
|
|
eh = mtod(m0, struct ether_header *);
|
|
|
|
if (ntohs(eh->ether_type) == ETHERTYPE_IP &&
|
|
|
|
m0->m_pkthdr.csum_flags & CSUM_IP)
|
|
|
|
desc->status |= ADM5120_DMA_CSUM;
|
|
|
|
if (nexttx == ADMSW_NTXLDESC - 1)
|
|
|
|
desc->data |= ADM5120_DMA_RINGEND;
|
|
|
|
desc->data |= ADM5120_DMA_OWN;
|
|
|
|
|
|
|
|
/* Sync the descriptor. */
|
|
|
|
ADMSW_CDTXLSYNC(sc, nexttx,
|
|
|
|
BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
|
|
|
|
|
|
|
|
REG_WRITE(SEND_TRIG_REG, 1);
|
|
|
|
/* printf("send slot %d\n",nexttx); */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Store a pointer to the packet so we can free it later.
|
|
|
|
*/
|
|
|
|
ds->ds_mbuf = m0;
|
|
|
|
|
|
|
|
/* Advance the Tx pointer. */
|
|
|
|
sc->sc_txfree--;
|
|
|
|
sc->sc_txnext = ADMSW_NEXTTXL(nexttx);
|
|
|
|
|
|
|
|
/* Pass the packet to any BPF listeners. */
|
|
|
|
BPF_MTAP(ifp, m0);
|
|
|
|
|
|
|
|
/* Set a watchdog timer in case the chip flakes out. */
|
|
|
|
sc->sc_ifnet[0]->if_timer = 5;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* admsw_watchdog: [ifnet interface function]
|
|
|
|
*
|
|
|
|
* Watchdog timer handler.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
admsw_watchdog(struct ifnet *ifp)
|
|
|
|
{
|
|
|
|
struct admsw_softc *sc = ifp->if_softc;
|
|
|
|
int vlan;
|
|
|
|
|
|
|
|
/* Check if an interrupt was lost. */
|
|
|
|
if (sc->sc_txfree == ADMSW_NTXLDESC) {
|
|
|
|
device_printf(sc->sc_dev, "watchdog false alarm\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (sc->sc_ifnet[0]->if_timer != 0)
|
|
|
|
device_printf(sc->sc_dev, "watchdog timer is %d!\n",
|
|
|
|
sc->sc_ifnet[0]->if_timer);
|
|
|
|
admsw_txintr(sc, 0);
|
|
|
|
if (sc->sc_txfree == ADMSW_NTXLDESC) {
|
|
|
|
device_printf(sc->sc_dev, "tx IRQ lost (queue empty)\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (sc->sc_ifnet[0]->if_timer != 0) {
|
|
|
|
device_printf(sc->sc_dev, "tx IRQ lost (timer recharged)\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
device_printf(sc->sc_dev, "device timeout, txfree = %d\n",
|
|
|
|
sc->sc_txfree);
|
|
|
|
for (vlan = 0; vlan < SW_DEVS; vlan++)
|
|
|
|
admsw_stop(sc->sc_ifnet[vlan], 0);
|
|
|
|
admsw_init(sc);
|
|
|
|
|
|
|
|
/* Try to get more packets going. */
|
|
|
|
admsw_start(ifp);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* admsw_ioctl: [ifnet interface function]
|
|
|
|
*
|
|
|
|
* Handle control requests from the operator.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
admsw_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
|
|
|
|
{
|
|
|
|
struct admsw_softc *sc = ifp->if_softc;
|
|
|
|
struct ifdrv *ifd;
|
|
|
|
int error, port;
|
|
|
|
|
|
|
|
ADMSW_LOCK(sc);
|
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
case SIOCSIFMEDIA:
|
|
|
|
case SIOCGIFMEDIA:
|
|
|
|
port = 0;
|
|
|
|
while(port < SW_DEVS)
|
|
|
|
if(ifp == sc->sc_ifnet[port])
|
|
|
|
break;
|
|
|
|
else
|
|
|
|
port++;
|
|
|
|
if (port >= SW_DEVS)
|
|
|
|
error = EOPNOTSUPP;
|
|
|
|
else
|
|
|
|
error = ifmedia_ioctl(ifp, (struct ifreq *)data,
|
|
|
|
&sc->sc_ifmedia[port], cmd);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SIOCGDRVSPEC:
|
|
|
|
case SIOCSDRVSPEC:
|
|
|
|
ifd = (struct ifdrv *) data;
|
|
|
|
if (ifd->ifd_cmd != 0 || ifd->ifd_len != sizeof(vlan_matrix)) {
|
|
|
|
error = EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (cmd == SIOCGDRVSPEC) {
|
|
|
|
error = copyout(vlan_matrix, ifd->ifd_data,
|
|
|
|
sizeof(vlan_matrix));
|
|
|
|
} else {
|
|
|
|
error = copyin(ifd->ifd_data, vlan_matrix,
|
|
|
|
sizeof(vlan_matrix));
|
|
|
|
admsw_setvlan(sc, vlan_matrix);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
error = ether_ioctl(ifp, cmd, data);
|
|
|
|
if (error == ENETRESET) {
|
|
|
|
/*
|
|
|
|
* Multicast list has changed; set the hardware filter
|
|
|
|
* accordingly.
|
|
|
|
*/
|
|
|
|
admsw_set_filter(sc);
|
|
|
|
error = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Try to get more packets going. */
|
|
|
|
admsw_start(ifp);
|
|
|
|
|
|
|
|
ADMSW_UNLOCK(sc);
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* admsw_intr:
|
|
|
|
*
|
|
|
|
* Interrupt service routine.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
admsw_intr(void *arg)
|
|
|
|
{
|
|
|
|
struct admsw_softc *sc = arg;
|
|
|
|
uint32_t pending;
|
|
|
|
|
|
|
|
pending = REG_READ(ADMSW_INT_ST);
|
|
|
|
REG_WRITE(ADMSW_INT_ST, pending);
|
|
|
|
|
|
|
|
if (sc->ndevs == 0)
|
|
|
|
return (FILTER_STRAY);
|
|
|
|
|
|
|
|
if ((pending & ADMSW_INTR_RHD) != 0)
|
|
|
|
admsw_rxintr(sc, 1);
|
|
|
|
|
|
|
|
if ((pending & ADMSW_INTR_RLD) != 0)
|
|
|
|
admsw_rxintr(sc, 0);
|
|
|
|
|
|
|
|
if ((pending & ADMSW_INTR_SHD) != 0)
|
|
|
|
admsw_txintr(sc, 1);
|
|
|
|
|
|
|
|
if ((pending & ADMSW_INTR_SLD) != 0)
|
|
|
|
admsw_txintr(sc, 0);
|
|
|
|
|
|
|
|
return (FILTER_HANDLED);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* admsw_txintr:
|
|
|
|
*
|
|
|
|
* Helper; handle transmit interrupts.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
admsw_txintr(struct admsw_softc *sc, int prio)
|
|
|
|
{
|
|
|
|
struct ifnet *ifp;
|
|
|
|
struct admsw_desc *desc;
|
|
|
|
struct admsw_descsoft *ds;
|
|
|
|
int i, vlan;
|
|
|
|
int gotone = 0;
|
|
|
|
|
|
|
|
/* printf("txintr: txdirty: %d, txfree: %d\n",sc->sc_txdirty, sc->sc_txfree); */
|
|
|
|
for (i = sc->sc_txdirty; sc->sc_txfree != ADMSW_NTXLDESC;
|
|
|
|
i = ADMSW_NEXTTXL(i)) {
|
|
|
|
|
|
|
|
ADMSW_CDTXLSYNC(sc, i,
|
|
|
|
BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
|
|
|
|
|
|
|
|
desc = &sc->sc_txldescs[i];
|
|
|
|
ds = &sc->sc_txlsoft[i];
|
|
|
|
if (desc->data & ADM5120_DMA_OWN) {
|
|
|
|
ADMSW_CDTXLSYNC(sc, i,
|
|
|
|
BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
bus_dmamap_sync(sc->sc_bufs_dmat, ds->ds_dmamap,
|
|
|
|
BUS_DMASYNC_POSTWRITE);
|
|
|
|
bus_dmamap_unload(sc->sc_bufs_dmat, ds->ds_dmamap);
|
|
|
|
m_freem(ds->ds_mbuf);
|
|
|
|
ds->ds_mbuf = NULL;
|
|
|
|
|
|
|
|
vlan = ffs(desc->status & 0x3f) - 1;
|
|
|
|
if (vlan < 0 || vlan >= SW_DEVS)
|
|
|
|
panic("admsw_txintr: bad vlan\n");
|
|
|
|
ifp = sc->sc_ifnet[vlan];
|
|
|
|
gotone = 1;
|
|
|
|
/* printf("clear tx slot %d\n",i); */
|
|
|
|
|
|
|
|
ifp->if_opackets++;
|
|
|
|
|
|
|
|
sc->sc_txfree++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gotone) {
|
|
|
|
sc->sc_txdirty = i;
|
|
|
|
for (vlan = 0; vlan < SW_DEVS; vlan++)
|
|
|
|
sc->sc_ifnet[vlan]->if_drv_flags &= ~IFF_DRV_OACTIVE;
|
|
|
|
|
|
|
|
ifp = sc->sc_ifnet[0];
|
|
|
|
|
|
|
|
/* Try to queue more packets. */
|
|
|
|
admsw_start(ifp);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If there are no more pending transmissions,
|
|
|
|
* cancel the watchdog timer.
|
|
|
|
*/
|
|
|
|
if (sc->sc_txfree == ADMSW_NTXLDESC)
|
|
|
|
ifp->if_timer = 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* printf("txintr end: txdirty: %d, txfree: %d\n",sc->sc_txdirty, sc->sc_txfree); */
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* admsw_rxintr:
|
|
|
|
*
|
|
|
|
* Helper; handle receive interrupts.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
admsw_rxintr(struct admsw_softc *sc, int high)
|
|
|
|
{
|
|
|
|
struct ifnet *ifp;
|
|
|
|
struct admsw_descsoft *ds;
|
|
|
|
struct mbuf *m;
|
|
|
|
uint32_t stat;
|
|
|
|
int i, len, port, vlan;
|
|
|
|
|
|
|
|
/* printf("rxintr\n"); */
|
|
|
|
|
|
|
|
if (high)
|
|
|
|
panic("admsw_rxintr: high priority packet\n");
|
|
|
|
|
|
|
|
#if 1
|
|
|
|
ADMSW_CDRXLSYNC(sc, sc->sc_rxptr,
|
|
|
|
BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
|
|
|
|
if ((sc->sc_rxldescs[sc->sc_rxptr].data & ADM5120_DMA_OWN) == 0)
|
|
|
|
ADMSW_CDRXLSYNC(sc, sc->sc_rxptr,
|
|
|
|
BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
|
|
|
|
else {
|
|
|
|
i = sc->sc_rxptr;
|
|
|
|
do {
|
|
|
|
ADMSW_CDRXLSYNC(sc, i,
|
|
|
|
BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
|
|
|
|
i = ADMSW_NEXTRXL(i);
|
|
|
|
/* the ring is empty, just return. */
|
|
|
|
if (i == sc->sc_rxptr)
|
|
|
|
return;
|
|
|
|
ADMSW_CDRXLSYNC(sc, i,
|
|
|
|
BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
|
|
|
|
} while (sc->sc_rxldescs[i].data & ADM5120_DMA_OWN);
|
|
|
|
|
|
|
|
ADMSW_CDRXLSYNC(sc, i,
|
|
|
|
BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
|
|
|
|
|
|
|
|
ADMSW_CDRXLSYNC(sc, sc->sc_rxptr,
|
|
|
|
BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
|
|
|
|
|
|
|
|
if ((sc->sc_rxldescs[sc->sc_rxptr].data & ADM5120_DMA_OWN) == 0)
|
|
|
|
ADMSW_CDRXLSYNC(sc, sc->sc_rxptr,
|
|
|
|
BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
|
|
|
|
else {
|
|
|
|
ADMSW_CDRXLSYNC(sc, sc->sc_rxptr,
|
|
|
|
BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
|
|
|
|
/* We've fallen behind the chip: catch it. */
|
|
|
|
#if 0
|
|
|
|
device_printf(sc->sc_dev,
|
|
|
|
"RX ring resync, base=%x, work=%x, %d -> %d\n",
|
|
|
|
REG_READ(RECV_LBADDR_REG),
|
|
|
|
REG_READ(RECV_LWADDR_REG), sc->sc_rxptr, i);
|
|
|
|
#endif
|
|
|
|
sc->sc_rxptr = i;
|
|
|
|
/* ADMSW_EVCNT_INCR(&sc->sc_ev_rxsync); */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
for (i = sc->sc_rxptr;; i = ADMSW_NEXTRXL(i)) {
|
|
|
|
ds = &sc->sc_rxlsoft[i];
|
|
|
|
|
|
|
|
ADMSW_CDRXLSYNC(sc, i,
|
|
|
|
BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
|
|
|
|
|
|
|
|
if (sc->sc_rxldescs[i].data & ADM5120_DMA_OWN) {
|
|
|
|
ADMSW_CDRXLSYNC(sc, i,
|
|
|
|
BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* printf("process slot %d\n",i); */
|
|
|
|
|
|
|
|
bus_dmamap_sync(sc->sc_bufs_dmat, ds->ds_dmamap,
|
|
|
|
BUS_DMASYNC_POSTREAD);
|
|
|
|
|
|
|
|
stat = sc->sc_rxldescs[i].status;
|
|
|
|
len = (stat & ADM5120_DMA_LEN) >> ADM5120_DMA_LENSHIFT;
|
|
|
|
len -= ETHER_CRC_LEN;
|
|
|
|
port = (stat & ADM5120_DMA_PORTID) >> ADM5120_DMA_PORTSHIFT;
|
|
|
|
|
|
|
|
for (vlan = 0; vlan < SW_DEVS; vlan++)
|
|
|
|
if ((1 << port) & vlan_matrix[vlan])
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (vlan == SW_DEVS)
|
|
|
|
vlan = 0;
|
|
|
|
|
|
|
|
ifp = sc->sc_ifnet[vlan];
|
|
|
|
|
|
|
|
m = ds->ds_mbuf;
|
|
|
|
if (admsw_add_rxlbuf(sc, i) != 0) {
|
|
|
|
ifp->if_ierrors++;
|
|
|
|
ADMSW_INIT_RXLDESC(sc, i);
|
|
|
|
bus_dmamap_sync(sc->sc_bufs_dmat, ds->ds_dmamap,
|
|
|
|
BUS_DMASYNC_PREREAD);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
m->m_pkthdr.rcvif = ifp;
|
|
|
|
m->m_pkthdr.len = m->m_len = len;
|
|
|
|
if ((stat & ADM5120_DMA_TYPE) == ADM5120_DMA_TYPE_IP) {
|
|
|
|
m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED;
|
|
|
|
if (!(stat & ADM5120_DMA_CSUMFAIL))
|
|
|
|
m->m_pkthdr.csum_flags |= CSUM_IP_VALID;
|
|
|
|
}
|
|
|
|
|
|
|
|
BPF_MTAP(ifp, m);
|
|
|
|
|
|
|
|
/* Pass it on. */
|
|
|
|
(*ifp->if_input)(ifp, m);
|
|
|
|
ifp->if_ipackets++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update the receive pointer. */
|
|
|
|
sc->sc_rxptr = i;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* admsw_init: [ifnet interface function]
|
|
|
|
*
|
2008-09-28 03:48:15 +00:00
|
|
|
* Initialize the interface.
|
FreeBSD/mips port. The FreeBSD/mips port targets mips32, mips64,
mips32r2 and mips64r2 (and close relatives) processors. There
presently is support for ADMtek ADM5120, A mips 4Kc in a malta board,
the RB533 routerboard (based on IDT RC32434) and some preliminary
support for sibtye/broadcom designs. Other hardware support will be
forthcomcing.
This port boots multiuser under gxemul emulating the malta board and
also bootstraps on the hardware whose support is forthcoming...
Oleksandr Tymoshenko, Wojciech Koszek, Warner Losh, Olivier Houchard,
Randall Stewert and others that have contributed to the mips2 and/or
mips2-jnpr perforce branches. Juniper contirbuted a generic mips port
late in the life cycle of the misp2 branch. Warner Losh merged the
mips2 and Juniper code bases, and others list above have worked for
the past several months to get to multiuser.
In addition, the mips2 work owe a debt to the trail blazing efforts of
the original mips branch in perforce done by Juli Mallett.
2008-04-13 07:44:55 +00:00
|
|
|
*/
|
|
|
|
static void
|
|
|
|
admsw_init(void *xsc)
|
|
|
|
{
|
|
|
|
struct admsw_softc *sc = xsc;
|
|
|
|
struct ifnet *ifp;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < SW_DEVS; i++) {
|
|
|
|
ifp = sc->sc_ifnet[i];
|
|
|
|
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
|
|
|
|
if (sc->ndevs == 0) {
|
|
|
|
admsw_init_bufs(sc);
|
|
|
|
admsw_reset(sc);
|
|
|
|
REG_WRITE(CPUP_CONF_REG,
|
|
|
|
CPUP_CONF_CRCP | CPUP_CONF_DUNP_MASK |
|
|
|
|
CPUP_CONF_DMCP_MASK);
|
|
|
|
/* clear all pending interrupts */
|
|
|
|
REG_WRITE(ADMSW_INT_ST, INT_MASK);
|
|
|
|
|
|
|
|
/* enable needed interrupts */
|
|
|
|
REG_WRITE(ADMSW_INT_MASK,
|
|
|
|
REG_READ(ADMSW_INT_MASK) &
|
|
|
|
~(ADMSW_INTR_SHD | ADMSW_INTR_SLD |
|
|
|
|
ADMSW_INTR_RHD | ADMSW_INTR_RLD |
|
|
|
|
ADMSW_INTR_HDF | ADMSW_INTR_LDF));
|
|
|
|
}
|
|
|
|
sc->ndevs++;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* mark iface as running */
|
|
|
|
ifp->if_drv_flags |= IFF_DRV_RUNNING;
|
|
|
|
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set the receive filter. */
|
|
|
|
admsw_set_filter(sc);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* admsw_stop: [ifnet interface function]
|
|
|
|
*
|
|
|
|
* Stop transmission on the interface.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
admsw_stop(struct ifnet *ifp, int disable)
|
|
|
|
{
|
|
|
|
struct admsw_softc *sc = ifp->if_softc;
|
|
|
|
|
|
|
|
if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (--sc->ndevs == 0) {
|
|
|
|
/* printf("debug: de-initializing hardware\n"); */
|
|
|
|
|
|
|
|
/* disable cpu port */
|
|
|
|
REG_WRITE(CPUP_CONF_REG,
|
|
|
|
CPUP_CONF_DCPUP | CPUP_CONF_CRCP |
|
|
|
|
CPUP_CONF_DUNP_MASK | CPUP_CONF_DMCP_MASK);
|
|
|
|
|
|
|
|
/* XXX We should disable, then clear? --dyoung */
|
|
|
|
/* clear all pending interrupts */
|
|
|
|
REG_WRITE(ADMSW_INT_ST, INT_MASK);
|
|
|
|
|
|
|
|
/* disable interrupts */
|
|
|
|
REG_WRITE(ADMSW_INT_MASK, INT_MASK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Mark the interface as down and cancel the watchdog timer. */
|
|
|
|
ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
|
|
|
|
ifp->if_timer = 0;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* admsw_set_filter:
|
|
|
|
*
|
|
|
|
* Set up the receive filter.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
admsw_set_filter(struct admsw_softc *sc)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
uint32_t allmc, anymc, conf, promisc;
|
|
|
|
struct ifnet *ifp;
|
|
|
|
struct ifmultiaddr *ifma;
|
|
|
|
|
|
|
|
/* Find which ports should be operated in promisc mode. */
|
|
|
|
allmc = anymc = promisc = 0;
|
|
|
|
for (i = 0; i < SW_DEVS; i++) {
|
|
|
|
ifp = sc->sc_ifnet[i];
|
|
|
|
if (ifp->if_flags & IFF_PROMISC)
|
|
|
|
promisc |= vlan_matrix[i];
|
|
|
|
|
|
|
|
ifp->if_flags &= ~IFF_ALLMULTI;
|
|
|
|
|
2009-06-26 11:45:06 +00:00
|
|
|
if_maddr_rlock(ifp);
|
FreeBSD/mips port. The FreeBSD/mips port targets mips32, mips64,
mips32r2 and mips64r2 (and close relatives) processors. There
presently is support for ADMtek ADM5120, A mips 4Kc in a malta board,
the RB533 routerboard (based on IDT RC32434) and some preliminary
support for sibtye/broadcom designs. Other hardware support will be
forthcomcing.
This port boots multiuser under gxemul emulating the malta board and
also bootstraps on the hardware whose support is forthcoming...
Oleksandr Tymoshenko, Wojciech Koszek, Warner Losh, Olivier Houchard,
Randall Stewert and others that have contributed to the mips2 and/or
mips2-jnpr perforce branches. Juniper contirbuted a generic mips port
late in the life cycle of the misp2 branch. Warner Losh merged the
mips2 and Juniper code bases, and others list above have worked for
the past several months to get to multiuser.
In addition, the mips2 work owe a debt to the trail blazing efforts of
the original mips branch in perforce done by Juli Mallett.
2008-04-13 07:44:55 +00:00
|
|
|
TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
|
|
|
|
{
|
|
|
|
if (ifma->ifma_addr->sa_family != AF_LINK)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
anymc |= vlan_matrix[i];
|
|
|
|
}
|
2009-06-26 11:45:06 +00:00
|
|
|
if_maddr_runlock(ifp);
|
FreeBSD/mips port. The FreeBSD/mips port targets mips32, mips64,
mips32r2 and mips64r2 (and close relatives) processors. There
presently is support for ADMtek ADM5120, A mips 4Kc in a malta board,
the RB533 routerboard (based on IDT RC32434) and some preliminary
support for sibtye/broadcom designs. Other hardware support will be
forthcomcing.
This port boots multiuser under gxemul emulating the malta board and
also bootstraps on the hardware whose support is forthcoming...
Oleksandr Tymoshenko, Wojciech Koszek, Warner Losh, Olivier Houchard,
Randall Stewert and others that have contributed to the mips2 and/or
mips2-jnpr perforce branches. Juniper contirbuted a generic mips port
late in the life cycle of the misp2 branch. Warner Losh merged the
mips2 and Juniper code bases, and others list above have worked for
the past several months to get to multiuser.
In addition, the mips2 work owe a debt to the trail blazing efforts of
the original mips branch in perforce done by Juli Mallett.
2008-04-13 07:44:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
conf = REG_READ(CPUP_CONF_REG);
|
|
|
|
/* 1 Disable forwarding of unknown & multicast packets to
|
|
|
|
* CPU on all ports.
|
|
|
|
* 2 Enable forwarding of unknown & multicast packets to
|
|
|
|
* CPU on ports where IFF_PROMISC or IFF_ALLMULTI is set.
|
|
|
|
*/
|
|
|
|
conf |= CPUP_CONF_DUNP_MASK | CPUP_CONF_DMCP_MASK;
|
|
|
|
/* Enable forwarding of unknown packets to CPU on selected ports. */
|
|
|
|
conf ^= ((promisc << CPUP_CONF_DUNP_SHIFT) & CPUP_CONF_DUNP_MASK);
|
|
|
|
conf ^= ((allmc << CPUP_CONF_DMCP_SHIFT) & CPUP_CONF_DMCP_MASK);
|
|
|
|
conf ^= ((anymc << CPUP_CONF_DMCP_SHIFT) & CPUP_CONF_DMCP_MASK);
|
|
|
|
REG_WRITE(CPUP_CONF_REG, conf);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* admsw_add_rxbuf:
|
|
|
|
*
|
|
|
|
* Add a receive buffer to the indicated descriptor.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
admsw_add_rxbuf(struct admsw_softc *sc, int idx, int high)
|
|
|
|
{
|
|
|
|
struct admsw_descsoft *ds;
|
|
|
|
struct mbuf *m;
|
|
|
|
int error;
|
|
|
|
|
|
|
|
if (high)
|
|
|
|
ds = &sc->sc_rxhsoft[idx];
|
|
|
|
else
|
|
|
|
ds = &sc->sc_rxlsoft[idx];
|
|
|
|
|
|
|
|
MGETHDR(m, M_DONTWAIT, MT_DATA);
|
|
|
|
if (m == NULL)
|
|
|
|
return (ENOBUFS);
|
|
|
|
|
|
|
|
MCLGET(m, M_DONTWAIT);
|
|
|
|
if ((m->m_flags & M_EXT) == 0) {
|
|
|
|
m_freem(m);
|
|
|
|
return (ENOBUFS);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ds->ds_mbuf != NULL)
|
|
|
|
bus_dmamap_unload(sc->sc_bufs_dmat, ds->ds_dmamap);
|
|
|
|
|
|
|
|
ds->ds_mbuf = m;
|
|
|
|
|
|
|
|
error = bus_dmamap_load(sc->sc_bufs_dmat, ds->ds_dmamap,
|
|
|
|
m->m_ext.ext_buf, m->m_ext.ext_size, admsw_rxbuf_map_addr,
|
|
|
|
ds, BUS_DMA_NOWAIT);
|
|
|
|
if (error) {
|
|
|
|
device_printf(sc->sc_dev,
|
|
|
|
"can't load rx DMA map %d, error = %d\n", idx, error);
|
|
|
|
panic("admsw_add_rxbuf"); /* XXX */
|
|
|
|
}
|
|
|
|
|
|
|
|
bus_dmamap_sync(sc->sc_bufs_dmat, ds->ds_dmamap, BUS_DMASYNC_PREREAD);
|
|
|
|
|
|
|
|
if (high)
|
|
|
|
ADMSW_INIT_RXHDESC(sc, idx);
|
|
|
|
else
|
|
|
|
ADMSW_INIT_RXLDESC(sc, idx);
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
admsw_mediachange(struct ifnet *ifp)
|
|
|
|
{
|
|
|
|
struct admsw_softc *sc = ifp->if_softc;
|
|
|
|
int port = 0;
|
|
|
|
struct ifmedia *ifm;
|
|
|
|
int old, new, val;
|
|
|
|
|
|
|
|
while(port < SW_DEVS) {
|
|
|
|
if(ifp == sc->sc_ifnet[port])
|
|
|
|
break;
|
|
|
|
else
|
|
|
|
port++;
|
|
|
|
}
|
|
|
|
|
|
|
|
ifm = &sc->sc_ifmedia[port];
|
|
|
|
|
|
|
|
if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) {
|
|
|
|
val = PHY_CNTL2_AUTONEG|PHY_CNTL2_100M|PHY_CNTL2_FDX;
|
|
|
|
} else if (IFM_SUBTYPE(ifm->ifm_media) == IFM_100_TX) {
|
|
|
|
if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX)
|
|
|
|
val = PHY_CNTL2_100M|PHY_CNTL2_FDX;
|
|
|
|
else
|
|
|
|
val = PHY_CNTL2_100M;
|
|
|
|
} else if (IFM_SUBTYPE(ifm->ifm_media) == IFM_10_T) {
|
|
|
|
if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX)
|
|
|
|
val = PHY_CNTL2_FDX;
|
|
|
|
else
|
|
|
|
val = 0;
|
|
|
|
} else
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
old = REG_READ(PHY_CNTL2_REG);
|
|
|
|
new = old & ~((PHY_CNTL2_AUTONEG|PHY_CNTL2_100M|PHY_CNTL2_FDX) << port);
|
|
|
|
new |= (val << port);
|
|
|
|
|
|
|
|
if (new != old)
|
|
|
|
REG_WRITE(PHY_CNTL2_REG, new);
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
admsw_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
|
|
|
|
{
|
|
|
|
struct admsw_softc *sc = ifp->if_softc;
|
|
|
|
int port = 0;
|
|
|
|
int status;
|
|
|
|
|
|
|
|
while(port < SW_DEVS) {
|
|
|
|
if(ifp == sc->sc_ifnet[port])
|
|
|
|
break;
|
|
|
|
else
|
|
|
|
port++;
|
|
|
|
}
|
|
|
|
|
|
|
|
ifmr->ifm_status = IFM_AVALID;
|
|
|
|
ifmr->ifm_active = IFM_ETHER;
|
|
|
|
|
|
|
|
status = REG_READ(PHY_ST_REG) >> port;
|
|
|
|
|
|
|
|
if ((status & PHY_ST_LINKUP) == 0) {
|
|
|
|
ifmr->ifm_active |= IFM_NONE;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ifmr->ifm_status |= IFM_ACTIVE;
|
|
|
|
ifmr->ifm_active |= (status & PHY_ST_100M) ? IFM_100_TX : IFM_10_T;
|
|
|
|
if (status & PHY_ST_FDX)
|
|
|
|
ifmr->ifm_active |= IFM_FDX;
|
|
|
|
}
|
|
|
|
|
|
|
|
static device_method_t admsw_methods[] = {
|
|
|
|
/* Device interface */
|
|
|
|
DEVMETHOD(device_probe, admsw_probe),
|
|
|
|
DEVMETHOD(device_attach, admsw_attach),
|
|
|
|
DEVMETHOD(device_detach, admsw_detach),
|
|
|
|
DEVMETHOD(device_shutdown, admsw_shutdown),
|
|
|
|
|
|
|
|
{ 0, 0 }
|
|
|
|
};
|
|
|
|
|
|
|
|
static devclass_t admsw_devclass;
|
|
|
|
|
|
|
|
static driver_t admsw_driver = {
|
|
|
|
"admsw",
|
|
|
|
admsw_methods,
|
|
|
|
sizeof(struct admsw_softc),
|
|
|
|
};
|
|
|
|
|
|
|
|
DRIVER_MODULE(admsw, obio, admsw_driver, admsw_devclass, 0, 0);
|
|
|
|
MODULE_DEPEND(admsw, ether, 1, 1, 1);
|