You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1426 lines
41 KiB
1426 lines
41 KiB
/* $Id: if_gt.c,v 1.1.1.1 2006/09/14 01:59:08 root Exp $ */
|
|
|
|
/*
|
|
* Copyright (c) 2001 Allegro Networks (www.allegronetworks.com)
|
|
* Copyright (c) 2002 Opsycon AB.
|
|
*
|
|
* 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 by Allegro Networks Inc.
|
|
* This product includes software developed by Opsycon AB.
|
|
* 4. The name of the author may not be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
|
|
*
|
|
*/
|
|
|
|
#include "bpfilter.h"
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/mbuf.h>
|
|
#include <sys/malloc.h>
|
|
#include <sys/kernel.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/syslog.h>
|
|
|
|
#include <net/if.h>
|
|
#include <net/if_dl.h>
|
|
#include <net/if_media.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
|
|
|
|
#ifdef IPX
|
|
#include <netipx/ipx.h>
|
|
#include <netipx/ipx_if.h>
|
|
#endif
|
|
|
|
#ifdef NS
|
|
#include <netns/ns.h>
|
|
#include <netns/ns_if.h>
|
|
#endif
|
|
|
|
#if 0
|
|
#if NBPFILTER > 0
|
|
#include <net/bpf.h>
|
|
#include <net/bpfdesc.h>
|
|
#endif
|
|
#endif
|
|
|
|
#include <sys/ioctl.h>
|
|
#include <sys/errno.h>
|
|
#include <sys/device.h>
|
|
#include <autoconf.h>
|
|
|
|
#include <netinet/if_ether.h>
|
|
#include <vm/vm.h>
|
|
|
|
#include <machine/cpu.h>
|
|
#include <machine/bus.h>
|
|
#include <machine/intr.h>
|
|
|
|
#include <dev/mii/miivar.h>
|
|
|
|
#include <dev/pci/pcivar.h>
|
|
#include <dev/pci/pcireg.h>
|
|
#include <dev/pci/pcidevs.h>
|
|
|
|
#include <dev/ic/if_gt.h>
|
|
|
|
extern int _pciverbose;
|
|
|
|
/* Prototypes */
|
|
static int gt_match (struct device *, void *, void *);
|
|
void gt_attach (struct device *, struct device *, void *);
|
|
static void abort (struct gt_softc *, u_int32_t);
|
|
static void reset_tx (struct gt_softc *);
|
|
static void reset_rx (struct gt_softc *);
|
|
static int gt_ioctl (struct ifnet *, u_long, caddr_t);
|
|
static void gt_init (void *);
|
|
static void gt_start (struct ifnet *);
|
|
static void gt_stop (struct gt_softc *, int);
|
|
static void gt_watchdog (struct ifnet *);
|
|
static int gt_add_rfabuf (struct gt_softc *, struct mbuf **);
|
|
static int gt_intr (void *);
|
|
static int gt_rx (struct gt_softc *, u_int32_t);
|
|
static void read_mib_counters (struct gt_softc *);
|
|
int gt_miibus_readreg(void *, int, int);
|
|
int gt_miibus_writereg(void *, int, int, int);
|
|
|
|
void tgt_netstats (int);
|
|
|
|
int initAddressTable (int, int, int, int);
|
|
int addAddressTableEntry (int, uint, uint, uint, uint);
|
|
|
|
/* Compensate for lack of a generic ether_ioctl() */
|
|
static int gt_ether_ioctl (struct ifnet *, u_int32_t, caddr_t);
|
|
#define ether_ioctl gt_ether_ioctl
|
|
|
|
struct cfattach gt_ca = {
|
|
sizeof(struct gt_softc), gt_match, gt_attach
|
|
};
|
|
|
|
struct cfdriver gt_cd = {
|
|
NULL, "gt", DV_IFNET
|
|
};
|
|
|
|
/* Define ethernet MAC address */
|
|
extern char hwethadr[];
|
|
|
|
#define RFA_ALIGNMENT_FUDGE 2
|
|
|
|
/*
|
|
* Check for Galileo gt642[46]0
|
|
*/
|
|
static int
|
|
gt_match(parent, match, aux)
|
|
struct device *parent;
|
|
void *match, *aux;
|
|
{
|
|
return(1); /* I suppose soooo... */
|
|
}
|
|
|
|
/* Attach the interface */
|
|
void
|
|
gt_attach (parent, self, aux)
|
|
struct device *parent, *self;
|
|
void *aux;
|
|
{
|
|
struct gt_softc *sc = (struct gt_softc *)self;
|
|
struct confargs *cf = aux;
|
|
struct ifnet *ifp;
|
|
u_int32_t macH, macL;
|
|
int i, isrmii;
|
|
|
|
ifp = &sc->arpcom.ac_if;
|
|
bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
|
|
bcopy(hwethadr, sc->arpcom.ac_enaddr, sizeof(sc->arpcom.ac_enaddr));
|
|
sc->arpcom.ac_enaddr[5] += sc->sc_dev.dv_unit;
|
|
printf(": address %s\n", ether_sprintf(sc->arpcom.ac_enaddr));
|
|
|
|
sc->port_offset = sc->sc_dev.dv_unit * ETH_IO_SIZE;
|
|
sc->phy_addr = cf->ca_baseaddr;
|
|
|
|
ifp->if_softc = sc;
|
|
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
|
|
ifp->if_ioctl = gt_ioctl;
|
|
ifp->if_start = gt_start;
|
|
ifp->if_watchdog = gt_watchdog;
|
|
|
|
/*
|
|
* Allocate Tx and Rx descriptor rings
|
|
*/
|
|
sc->tx_ring = (TX_DESC *)(malloc(sizeof(TX_DESC) * TX_RING_SIZE,
|
|
M_DEVBUF, M_NOWAIT));
|
|
sc->rx_ring = (RX_DESC *)(malloc(sizeof(RX_DESC) * RX_RING_SIZE,
|
|
M_DEVBUF, M_NOWAIT));
|
|
|
|
sc->tx_m = (struct mbuf **)(malloc(sizeof(struct mbuf *) * TX_RING_SIZE,
|
|
M_DEVBUF, M_NOWAIT));
|
|
sc->rx_m = (struct mbuf **)(malloc(sizeof(struct mbuf *) * RX_RING_SIZE,
|
|
M_DEVBUF, M_NOWAIT));
|
|
bzero(sc->tx_m, sizeof(struct m_buf *) * TX_RING_SIZE);
|
|
bzero(sc->rx_m, sizeof(struct m_buf *) * RX_RING_SIZE);
|
|
|
|
/*
|
|
* Allocate Tx data buffers
|
|
*/
|
|
sc->tx_bp = malloc(TX_BUF_SZ*TX_RING_SIZE, M_DEVBUF, M_NOWAIT);
|
|
|
|
/*
|
|
* Initialize hash table
|
|
*/
|
|
sc->hash_mode = 0;
|
|
initAddressTable(sc->sc_dev.dv_unit,0,1,0);
|
|
macH = (sc->arpcom.ac_enaddr[0] << 8) | (sc->arpcom.ac_enaddr[1]);
|
|
macL = (sc->arpcom.ac_enaddr[5] << 0) | (sc->arpcom.ac_enaddr[4] << 8) |
|
|
(sc->arpcom.ac_enaddr[3] << 16)| (sc->arpcom.ac_enaddr[2] << 24);
|
|
|
|
addAddressTableEntry(sc->sc_dev.dv_unit,macH,macL,1,0);
|
|
|
|
/*
|
|
* Reset port
|
|
*/
|
|
gt_stop(sc,0);
|
|
gt_miibus_writereg(sc, sc->phy_addr, 0, 0x8000);
|
|
i = 100;
|
|
while (i && gt_miibus_readreg(sc, sc->phy_addr, 0) & 0x8000) {
|
|
delay(100);
|
|
i--;
|
|
}
|
|
|
|
/*
|
|
* Initialize Tx and Rx descriptors
|
|
*/
|
|
reset_tx(sc);
|
|
reset_rx(sc);
|
|
|
|
GTETH_WRITE(sc, ETH0_INTERRUPT_MASK_REG, 0x0);
|
|
|
|
/*
|
|
* Setup eth0 Port Config Extend Reg, clear the MIB registers.
|
|
* When done set MIB counters clear mode to 'no effect' so each
|
|
* read doesn't zero the register.
|
|
*/
|
|
isrmii = gt_miibus_readreg(sc, sc->phy_addr, 2) << 16;
|
|
isrmii |= gt_miibus_readreg(sc, sc->phy_addr, 3) & 0xfff0;
|
|
switch(isrmii) {
|
|
case 0x20005c20:
|
|
case 0x1378e0: /* Intel LTX972A */
|
|
isrmii = 0;
|
|
break;
|
|
default:
|
|
isrmii = pcxrRMIIen;
|
|
break;
|
|
}
|
|
|
|
GTETH_WRITE(sc, ETH0_PORT_CONFIG_EXT_REG,
|
|
isrmii | pcxrFCTL | pcxrFCTLen | pcxrFLP);
|
|
read_mib_counters(sc);
|
|
GTETH_WRITE(sc, ETH0_PORT_CONFIG_EXT_REG,
|
|
isrmii | pcxrFCTL | pcxrFCTLen | pcxrFLP |
|
|
pcxrPRIOrxOverride | pcxrMIBclrMode);
|
|
|
|
/*
|
|
* Big endian DMA, burst size 8 64bit words, frame boundary interrupts
|
|
*/
|
|
#if BYTE_ORDER == LITTLE_ENDIAN
|
|
GTETH_WRITE(sc, ETH0_SDMA_CONFIG_REG,
|
|
sdcrBLMR | sdcrBLMT |
|
|
(0xf<<sdcrRCBit) | sdcrRIFB | (3<<sdcrBSZBit));
|
|
#else
|
|
GTETH_WRITE(sc, ETH0_SDMA_CONFIG_REG,
|
|
(0xf<<sdcrRCBit) | sdcrRIFB | (3<<sdcrBSZBit));
|
|
#endif
|
|
|
|
/*
|
|
* Start eth0 Rx DMA
|
|
*/
|
|
GTETH_WRITE(sc, ETH0_SDMA_COMMAND_REG, sdcmrERD);
|
|
|
|
/*
|
|
* Enable eth0 with 1/2K hash size
|
|
*/
|
|
GTETH_WRITE(sc, ETH0_PORT_CONFIG_REG, pcrEN | pcrHS);
|
|
|
|
/*
|
|
* Attach the interface
|
|
*/
|
|
if_attach(ifp);
|
|
|
|
/*
|
|
* Let the system queue as many packets as we have available
|
|
* Tx descriptors
|
|
*/
|
|
ifp->if_snd.ifq_maxlen = TX_RING_SIZE - 1;
|
|
ether_ifattach(ifp);
|
|
}
|
|
|
|
/*
|
|
* Start packet transmission on the interface.
|
|
*/
|
|
static void
|
|
gt_start(ifp)
|
|
struct ifnet *ifp;
|
|
{
|
|
struct gt_softc *sc = ifp->if_softc;
|
|
u_int16_t total_len;
|
|
char *p;
|
|
|
|
/*
|
|
* Process all mbufs ready for transmit or until all available
|
|
* transmit buffers are full.
|
|
*/
|
|
CACHESYNC(&sc->tx_ring[sc->tx_next_in], sizeof(TX_DESC), SYNC_R);
|
|
if(sc->tx_ring[sc->tx_next_in].cmdstat & txOwn) {
|
|
return; /* No buffers */
|
|
}
|
|
|
|
while (ifp->if_snd.ifq_head != NULL) {
|
|
struct mbuf *m, *mb_head;
|
|
u_int32_t nextTx;
|
|
|
|
/*
|
|
* Grab a packet to transmit.
|
|
*/
|
|
IF_DEQUEUE(&ifp->if_snd, mb_head);
|
|
|
|
/*
|
|
* Go through each of the mbufs in the chain and copy the data
|
|
* collecting fragments to the transmit descriptors data buffer.
|
|
*/
|
|
nextTx = sc->tx_next_in;
|
|
total_len = 0;
|
|
p = (char *)PA_TO_VA(sc->tx_ring[nextTx].buff_ptr);
|
|
for (m = mb_head; m != NULL; m = m->m_next) {
|
|
bcopy((char *)(mtod(m, vm_offset_t)), p, m->m_len);
|
|
total_len += m->m_len;
|
|
p += m->m_len;
|
|
}
|
|
|
|
sc->tx_ring[nextTx].byte_cnt_res = total_len << 16;
|
|
CACHESYNC((void *)(p - total_len), total_len, SYNC_W);
|
|
|
|
sc->tx_next_in = (nextTx + 1) % TX_RING_SIZE;
|
|
/*
|
|
* Free the mbuf chain
|
|
*/
|
|
m_freem(mb_head);
|
|
|
|
sc->tx_ring[nextTx].cmdstat =
|
|
txOwn | txFirst | txLast | txPad | txEI | txGenCRC;
|
|
CACHESYNC(&sc->tx_ring[nextTx], sizeof(TX_DESC), SYNC_W);
|
|
|
|
/*
|
|
* Send the packet out the low priority queue
|
|
*/
|
|
if(!(GTETH_READ(sc, ETH0_PORT_STATUS_REG) & psrTxInProg)) {
|
|
GTETH_WRITE(sc, ETH0_SDMA_COMMAND_REG, sdcmrERD | sdcmrTXDL);
|
|
}
|
|
|
|
#if 0
|
|
/*
|
|
* Set a 5 second timer just in case we don't hear
|
|
* from the card again.
|
|
*/
|
|
ifp->if_timer = 300;
|
|
#endif
|
|
} /* end while */
|
|
|
|
sc->tx_queued++;
|
|
}
|
|
|
|
/*
|
|
* Stop the interface
|
|
*/
|
|
void
|
|
gt_stop(struct gt_softc *sc, int drain)
|
|
{
|
|
|
|
/*
|
|
* Disable port
|
|
*/
|
|
abort(sc, sdcmrAR | sdcmrAT);
|
|
GTETH_WRITE(sc, ETH0_PORT_CONFIG_REG, 0);
|
|
}
|
|
|
|
static void
|
|
abort(struct gt_softc *sc, u_int32_t abort_bits)
|
|
{
|
|
/* Return if neither Rx or Tx abort bits are set */
|
|
if (!(abort_bits & (sdcmrAR | sdcmrAT)))
|
|
return;
|
|
|
|
/* Make sure only the Rx and Tx abort bits are set */
|
|
abort_bits &= (sdcmrAR | sdcmrAT);
|
|
|
|
/* Abort any Rx and Tx DMA immediately */
|
|
GTETH_WRITE(sc, ETH0_SDMA_COMMAND_REG, abort_bits);
|
|
}
|
|
|
|
/*
|
|
* Watchdog timeout handler. This routine is called when
|
|
* transmission has started on the interface and no
|
|
* interrupt was received before the timeout.
|
|
*/
|
|
void
|
|
gt_watchdog(ifp)
|
|
struct ifnet *ifp;
|
|
{
|
|
struct gt_softc *sc = ifp->if_softc;
|
|
|
|
log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
|
|
ifp->if_oerrors++;
|
|
//gt_init(sc);
|
|
}
|
|
|
|
static void
|
|
reset_tx(struct gt_softc *sc)
|
|
{
|
|
int i;
|
|
|
|
abort(sc, sdcmrAT);
|
|
|
|
for (i=0; i < TX_RING_SIZE; i++) {
|
|
sc->tx_ring[i].cmdstat = 0; /* CPU owns */
|
|
sc->tx_ring[i].byte_cnt_res = 0;
|
|
sc->tx_ring[i].buff_ptr = (u_int32_t)VA_TO_PA(sc->tx_bp+i*TX_BUF_SZ);
|
|
sc->tx_ring[i].next = (u_int32_t)VA_TO_PA(sc->tx_ring + (i+1));
|
|
}
|
|
|
|
/* Wrap the ring. */
|
|
sc->tx_ring[i-1].next = VA_TO_PA(sc->tx_ring);
|
|
CACHESYNC(sc->tx_ring, TX_RING_SIZE * sizeof(TX_DESC), SYNC_W);
|
|
|
|
/* setup only the lowest priority TxCDP reg */
|
|
GTETH_WRITE(sc, ETH0_CURRENT_TX_DESC_PTR0, VA_TO_PA(sc->tx_ring));
|
|
GTETH_WRITE(sc, ETH0_CURRENT_TX_DESC_PTR1, 0);
|
|
|
|
/* Initialize Tx indeces and packet counter */
|
|
sc->tx_next_in = 0;
|
|
sc->tx_next_out = 0;
|
|
sc->tx_count = 0;
|
|
}
|
|
|
|
static void
|
|
reset_rx(struct gt_softc *sc)
|
|
{
|
|
struct mbuf *m;
|
|
int i;
|
|
|
|
abort(sc, sdcmrAR);
|
|
|
|
/* Scan and release allocated mbufs */
|
|
for (i=0; i<RX_RING_SIZE; i++) {
|
|
if(sc->rx_m[i] != NULL) {
|
|
m_free(sc->rx_m[i]);
|
|
}
|
|
}
|
|
|
|
for (i=0; i < RX_RING_SIZE; i++) {
|
|
RX_DESC *rx_desc;
|
|
m = NULL;
|
|
if(gt_add_rfabuf(sc, &m) < 0) {
|
|
printf("%s: malloc failed\n", sc->sc_dev.dv_xname);
|
|
break;
|
|
}
|
|
sc->rx_m[i] = m;
|
|
rx_desc = &sc->rx_ring[i];
|
|
rx_desc->next = VA_TO_PA((sc->rx_ring + (i+1)));
|
|
rx_desc->buff_ptr = VA_TO_PA(m->m_data);
|
|
rx_desc->byte_sz_cnt = RX_BUF_SZ << 16;
|
|
|
|
/*
|
|
* Give ownership to device, set first and last,
|
|
* enable interrupt
|
|
*/
|
|
sc->rx_ring[i].cmdstat = (rxFirst | rxLast | rxOwn | rxEI);
|
|
}
|
|
|
|
/* Wrap the ring */
|
|
sc->rx_ring[i-1].next = VA_TO_PA(sc->rx_ring);
|
|
CACHESYNC(sc->rx_ring, RX_RING_SIZE * sizeof(RX_DESC), SYNC_W);
|
|
|
|
/* Setup only the lowest priority RxFDP and RxCDP regs */
|
|
for (i=0; i<4; i++) {
|
|
if (i == 0) {
|
|
GTETH_WRITE(sc, ETH0_FIRST_RX_DESC_PTR0, VA_TO_PA(sc->rx_ring));
|
|
GTETH_WRITE(sc, ETH0_CURRENT_RX_DESC_PTR0, VA_TO_PA(sc->rx_ring));
|
|
} else {
|
|
GTETH_WRITE(sc, ETH0_FIRST_RX_DESC_PTR0 + i*4, 0);
|
|
GTETH_WRITE(sc, ETH0_CURRENT_RX_DESC_PTR0 + i*4, 0);
|
|
}
|
|
}
|
|
|
|
/* Initialize Rx index */
|
|
sc->rx_next_out = 0;
|
|
}
|
|
|
|
int
|
|
gt_ioctl(ifp, command, data)
|
|
struct ifnet *ifp;
|
|
u_long command;
|
|
caddr_t data;
|
|
{
|
|
struct gt_softc *sc = ifp->if_softc;
|
|
int s, error = 0;
|
|
|
|
s = splimp();
|
|
|
|
switch (command) {
|
|
case SIOCPOLL:
|
|
gt_intr(sc);
|
|
break;
|
|
|
|
case SIOCSIFADDR:
|
|
error = ether_ioctl(ifp, command, data);
|
|
break;
|
|
|
|
case SIOCSIFFLAGS:
|
|
printf("case SIOCSIFFLAGS, marking interface up/down...\n");
|
|
|
|
//sc->all_mcasts = (ifp->if_flags & IFF_ALLMULTI) ? 1 : 0;
|
|
|
|
/*
|
|
* If interface is marked up and not running, then start it.
|
|
* If it is marked down and running, stop it.
|
|
* XXX If it's up then re-initialize it. This is so flags
|
|
* such as IFF_PROMISC are handled.
|
|
*/
|
|
if (ifp->if_flags & IFF_UP) {
|
|
gt_init(sc);
|
|
} else {
|
|
if (ifp->if_flags & IFF_RUNNING)
|
|
gt_stop(sc, 1);
|
|
}
|
|
break;
|
|
|
|
#if USE_GT_MULTICAST
|
|
case SIOCADDMULTI:
|
|
case SIOCDELMULTI:
|
|
//sc->all_mcasts = (ifp->if_flags & IFF_ALLMULTI) ? 1 : 0;
|
|
error = (command == SIOCADDMULTI) ?
|
|
ether_addmulti(ifr, &sc->arpcom) :
|
|
ether_delmulti(ifr, &sc->arpcom);
|
|
|
|
if (error == ENETRESET) {
|
|
/*
|
|
* Multicast list has changed; set the hardware
|
|
* filter accordingly.
|
|
*/
|
|
/*if (!sc->all_mcasts)
|
|
fxp_mc_setup(sc);*/
|
|
/*
|
|
* fxp_mc_setup() can turn on all_mcasts if we run
|
|
* out of space, so check it again rather than else {}.
|
|
*/
|
|
/*if (sc->all_mcasts)*/
|
|
if (0)
|
|
gt_init(sc);
|
|
error = 0;
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
case SIOCSIFMEDIA:
|
|
case SIOCGIFMEDIA:
|
|
/*error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, command);*/
|
|
break;
|
|
|
|
default:
|
|
error = EINVAL;
|
|
}
|
|
(void) splx(s);
|
|
return (error);
|
|
}
|
|
|
|
void
|
|
gt_init(xsc)
|
|
void *xsc;
|
|
{
|
|
struct gt_softc *sc = xsc;
|
|
struct ifnet *ifp = &sc->arpcom.ac_if;
|
|
|
|
/*s = splimp();*/
|
|
/*
|
|
* Cancel any pending I/O
|
|
*/
|
|
ifp->if_flags |= IFF_RUNNING;
|
|
|
|
/* Stop and disable port, or reset to stable state */
|
|
/*gt_stop(sc,0);*/
|
|
}
|
|
|
|
static int
|
|
gt_ether_ioctl(ifp, cmd, data)
|
|
struct ifnet *ifp;
|
|
u_int32_t cmd;
|
|
caddr_t data;
|
|
{
|
|
struct ifaddr *ifa = (struct ifaddr *) data;
|
|
struct gt_softc *sc = ifp->if_softc;
|
|
|
|
switch (cmd) {
|
|
#ifdef PMON
|
|
case SIOCPOLL:
|
|
gt_intr(sc);
|
|
break;
|
|
#endif
|
|
case SIOCSIFADDR:
|
|
ifp->if_flags |= IFF_UP;
|
|
|
|
switch (ifa->ifa_addr->sa_family) {
|
|
#ifdef INET
|
|
case AF_INET:
|
|
gt_init(sc);
|
|
arp_ifinit(&sc->arpcom, ifa);
|
|
break;
|
|
#endif
|
|
#ifdef NS
|
|
case AF_NS:
|
|
{
|
|
struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
|
|
|
|
if (ns_nullhost(*ina))
|
|
ina->x_host = *(union ns_host *)
|
|
LLADDR(ifp->if_sadl);
|
|
else
|
|
bcopy(ina->x_host.c_host, LLADDR(ifp->if_sadl),
|
|
ifp->if_addrlen);
|
|
/* Set new address. */
|
|
gt_init(sc);
|
|
break;
|
|
}
|
|
#endif
|
|
default:
|
|
gt_init(sc);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return (EINVAL);
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
gt_intr(arg)
|
|
void *arg;
|
|
{
|
|
struct gt_softc *sc = arg;
|
|
struct ifnet *ifp = &sc->arpcom.ac_if;
|
|
uint icr, psr;
|
|
|
|
/*
|
|
* Read Interrupt Cause Register and ACK interrupts
|
|
*/
|
|
icr = GTETH_READ(sc, ETH0_INTERRUPT_CAUSE_REG);
|
|
GTETH_WRITE(sc, ETH0_INTERRUPT_CAUSE_REG, 0);
|
|
|
|
/*
|
|
* Process incoming packets if Rx descriptor returned to CPU ownership
|
|
*/
|
|
gt_rx(sc, icr);
|
|
|
|
/*
|
|
* Transmit more packets if queue isn't empty
|
|
*/
|
|
if (ifp->if_snd.ifq_head != NULL)
|
|
gt_start(ifp);
|
|
|
|
/*
|
|
* Check for Tx errors
|
|
*/
|
|
if (icr & icrTxErrorLow)
|
|
printf("%s: Tx resource error (low priority)\n", sc->sc_dev.dv_xname);
|
|
if (icr & icrTxUdr)
|
|
printf("%s: Tx underrun error\n", sc->sc_dev.dv_xname);
|
|
|
|
/*
|
|
* Check for Rx errors
|
|
*/
|
|
if (icr & icrRxError) {
|
|
//printf("%s: Rx resource error. Resetting Rx\n", sc->sc_dev.dv_xname);
|
|
reset_rx(sc);
|
|
/* Restart receive engine */
|
|
GTETH_WRITE(sc, ETH0_SDMA_COMMAND_REG, sdcmrERD);
|
|
}
|
|
if (icr & icrRxOVR)
|
|
printf("%s: Rx overrun\n", sc->sc_dev.dv_xname);
|
|
|
|
/*
|
|
* Check port status errors
|
|
*/
|
|
psr = GTETH_READ(sc, ETH0_PORT_STATUS_REG);
|
|
if (psr & psrPause)
|
|
printf("%s: Pause!\n", sc->sc_dev.dv_xname);
|
|
|
|
return(0);
|
|
}
|
|
|
|
static int
|
|
gt_rx(struct gt_softc *sc, u_int32_t status)
|
|
{
|
|
struct ifnet *ifp = &sc->arpcom.ac_if;
|
|
struct mbuf *m;
|
|
int nextRx, cdp;
|
|
RX_DESC *rd;
|
|
u_int32_t cmdstat;
|
|
u_int16_t total_len;
|
|
|
|
/*
|
|
* Determine index to current descriptor
|
|
*/
|
|
cdp = (GTETH_READ(sc, ETH0_CURRENT_RX_DESC_PTR0)
|
|
- (u_int32_t)sc->rx_ring) / sizeof(RX_DESC);
|
|
|
|
/*
|
|
* Process to current descriptor
|
|
*/
|
|
for (nextRx = sc->rx_next_out; nextRx != cdp;
|
|
nextRx = (nextRx + 1) % RX_RING_SIZE) {
|
|
|
|
rd = &sc->rx_ring[nextRx];
|
|
CACHESYNC(rd, sizeof(RX_DESC), SYNC_R);
|
|
cmdstat = (u_int32_t)rd->cmdstat;
|
|
|
|
/*
|
|
* Bail if gt owns descriptor. This is the workaround for
|
|
* not relying on the icr register.
|
|
*/
|
|
if (cmdstat & (u_int32_t)rxOwn) {
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Must be first and last (ie only) buffer of packet
|
|
*/
|
|
if (!(cmdstat & (u_int32_t)rxFirst) || !(cmdstat & (u_int32_t)rxLast)) {
|
|
printf("%s: descriptor not first and last!\n", sc->sc_dev.dv_xname);
|
|
goto next;
|
|
}
|
|
|
|
/*
|
|
* Drop this packet if there were any errors
|
|
*/
|
|
if ((cmdstat & (u_int32_t)rxErrorSummary) || (status & icrRxError)) {
|
|
#ifdef DEBUG_GT
|
|
printf("%s: dropped packet %p:%p\n",
|
|
sc->sc_dev.dv_xname, cmdstat, status);
|
|
#endif
|
|
goto next;
|
|
}
|
|
|
|
if((total_len = (rd->byte_sz_cnt & 0xffff)) > MCLBYTES) {
|
|
printf("%s: bad packet length %d\n", sc->sc_dev.dv_xname, total_len);
|
|
goto next;
|
|
}
|
|
|
|
/*
|
|
* This is where the packets start to get processed to send
|
|
* to upper layers of the protocol stack.
|
|
*/
|
|
m = sc->rx_m[nextRx];
|
|
|
|
/*
|
|
* Add a new buffer to the receive descriptor. The old
|
|
* buffer is recycled if it fails to get a new buffer
|
|
* and true is returned by gt_add_rfabuf.
|
|
*/
|
|
if (!gt_add_rfabuf(sc, &sc->rx_m[nextRx])) {
|
|
struct ether_header *eh;
|
|
|
|
rd->buff_ptr = VA_TO_PA(sc->rx_m[nextRx]->m_data);
|
|
|
|
total_len = rd->byte_sz_cnt & 0xffff;
|
|
if (total_len < sizeof(struct ether_header)) {
|
|
printf("%s: buffer too small, freeing mbuf\n", sc->sc_dev.dv_xname);
|
|
m_freem(m);
|
|
goto next;
|
|
}
|
|
m->m_pkthdr.rcvif = ifp;
|
|
m->m_pkthdr.len = m->m_len = total_len - sizeof(struct ether_header);
|
|
|
|
/*
|
|
* Realign data in mbuf. Discovery require receive buffer
|
|
* to be 64 bit aligned so we can't do this before receive.
|
|
*/
|
|
bcopy(m->m_data, m->m_data + RFA_ALIGNMENT_FUDGE, total_len);
|
|
m->m_data += RFA_ALIGNMENT_FUDGE;
|
|
|
|
/*
|
|
* Send packet to upper layer
|
|
*/
|
|
eh = mtod(m, struct ether_header *);
|
|
m->m_data += sizeof(struct ether_header);
|
|
ether_input(ifp, eh, m);
|
|
}
|
|
else {
|
|
printf("%s: gt recycling rxbuf!\n", sc->sc_dev.dv_xname);
|
|
}
|
|
|
|
next:
|
|
/*
|
|
* Release ownership to device, set first and last, enable interrupt
|
|
*/
|
|
rd->cmdstat = (u_int32_t)(rxFirst | rxLast | rxOwn | rxEI);
|
|
CACHESYNC(rd, sizeof(RX_DESC), SYNC_W);
|
|
}
|
|
sc->rx_next_out = nextRx;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Get a receive buffer and return it's data address.
|
|
* Return 0 if recycled. The buffer is prepares such that
|
|
* the pointer to "m" is stored in front of the data.
|
|
*/
|
|
int
|
|
gt_add_rfabuf(sc, oldm)
|
|
struct gt_softc *sc;
|
|
struct mbuf **oldm;
|
|
{
|
|
struct mbuf *m, *pm;
|
|
|
|
if(oldm != NULL) {
|
|
pm = *oldm;
|
|
}
|
|
else {
|
|
pm = NULL;
|
|
}
|
|
|
|
MGETHDR(m, M_DONTWAIT, MT_DATA);
|
|
if (m != NULL) {
|
|
MCLGET(m, M_DONTWAIT);
|
|
if ((m->m_flags & M_EXT) == 0) {
|
|
m_freem(m);
|
|
if (pm == NULL) {
|
|
printf("gt_add_rfabuf: error 1\n");
|
|
return -1;
|
|
}
|
|
/* Recycle */
|
|
m = pm;
|
|
m->m_data = m->m_ext.ext_buf;
|
|
}
|
|
}
|
|
else { /* Recycle */
|
|
if (pm == NULL) {
|
|
printf("gt_add_rfabuf: error 2\n");
|
|
return 1;
|
|
}
|
|
m = pm;
|
|
m->m_data = m->m_ext.ext_buf;
|
|
}
|
|
|
|
/*
|
|
* Move the data pointer up so that the incoming data packet
|
|
* will be 64-bit aligned as requiered by the Discovery.
|
|
* The ether header is not a multiple of 4 bytes but the upper layer
|
|
* assumes data to be aligned so we will have to adjust this later.
|
|
*/
|
|
m->m_data = (void *)ALIGN(m->m_data);
|
|
CACHESYNC((void *)m->m_data, RX_BUF_SZ, SYNC_R);
|
|
|
|
*oldm = m;
|
|
|
|
return (m == pm);
|
|
}
|
|
|
|
void
|
|
read_mib_counters (sc)
|
|
struct gt_softc *sc;
|
|
{
|
|
u_int32_t *mib_reg = (u_int32_t *)&sc->mib;
|
|
int i;
|
|
|
|
for (i=0; i<sizeof(mib_counters_t)/sizeof(u_int32_t); i++) {
|
|
mib_reg[i] = GTETH_READ(sc, ETH0_MIB_COUNTER_BASE + i*sizeof(u_int32_t));
|
|
}
|
|
}
|
|
|
|
int
|
|
gt_miibus_readreg(arg, phy, reg)
|
|
void *arg;
|
|
int phy;
|
|
int reg;
|
|
{
|
|
struct gt_softc *sc = (struct gt_softc *)arg;
|
|
unsigned int data = 0;
|
|
u_int32_t phyreg;
|
|
|
|
phyreg = GT_READ(ETH_PHY_ADDR_REG);
|
|
|
|
if ((sc->sc_dev.dv_unit == 0 && (phyreg & 0x1f) != phy) ||
|
|
(sc->sc_dev.dv_unit == 1 && (phyreg & 0x3e0) != (phy << 5)) ||
|
|
(sc->sc_dev.dv_unit == 2 && (phyreg & 0x7c00) != (phy << 10)) ||
|
|
(sc->sc_dev.dv_unit > 2)) {
|
|
return (0xffff);
|
|
}
|
|
|
|
phyreg = ((reg << SMIR_REGADBIT) & SMIR_REGADMASK) |
|
|
((phy << SMIR_PHYADBIT) & SMIR_PHYADMASK) |
|
|
SMIR_READOP;
|
|
GT_WRITE(ETH_SMI_REG, phyreg);
|
|
do {
|
|
phyreg = GT_READ(ETH_SMI_REG);
|
|
} while (phyreg & SMIR_BUSY);
|
|
|
|
data = GT_READ(ETH_SMI_REG);
|
|
|
|
return (data & 0xffff);
|
|
}
|
|
|
|
int
|
|
gt_miibus_writereg(arg, phy, reg, data)
|
|
void *arg;
|
|
int phy;
|
|
int reg;
|
|
int data;
|
|
{
|
|
struct gt_softc *sc = (struct gt_softc *)arg;
|
|
u_int32_t phyreg;
|
|
|
|
phyreg = GT_READ(ETH_PHY_ADDR_REG);
|
|
|
|
if ((sc->sc_dev.dv_unit == 0 && (phyreg & 0x1f) != phy) ||
|
|
(sc->sc_dev.dv_unit == 1 && (phyreg & 0x3e0) != (phy << 5)) ||
|
|
(sc->sc_dev.dv_unit == 2 && (phyreg & 0x7c00) != (phy << 10)) ||
|
|
(sc->sc_dev.dv_unit > 2)) {
|
|
return (0xffff);
|
|
}
|
|
|
|
phyreg = ((reg << SMIR_REGADBIT) & SMIR_REGADMASK) |
|
|
((phy << SMIR_PHYADBIT) & SMIR_PHYADMASK) |
|
|
(data & SMIR_DATAMASK);
|
|
GT_WRITE(ETH_SMI_REG, phyreg);
|
|
do {
|
|
phyreg = GT_READ(ETH_SMI_REG);
|
|
} while (phyreg & SMIR_BUSY);
|
|
|
|
return (0);
|
|
}
|
|
|
|
#define NUM_ETH_PORTS 3
|
|
|
|
unsigned int addressTableHashMode[NUM_ETH_PORTS];
|
|
unsigned int addressTableHashSize[NUM_ETH_PORTS];
|
|
unsigned int addressTableBase[NUM_ETH_PORTS];
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* boolean_t initAddressTable(int port,int hashMode,int hashSize,int hashDefaultMode)
|
|
*
|
|
* This function will initialize the address table
|
|
* and will enableFiltering.
|
|
* Inputs
|
|
* hashMode - hash mode 0 or hash mode 1.
|
|
* hashSize - the size of the hash table (0=8K ,1=1/2K)
|
|
* hashDefaultMode - 0 = discard addresses not found in the address table ,
|
|
* 1 = pass addresses not found in the address table.
|
|
* port - ETHERNET port number.
|
|
* Outputs
|
|
* address table is allocated and initialized.
|
|
* TRUE if success.
|
|
* FALSE if fail to make the assignment.
|
|
*/
|
|
int initAddressTable(int port,int hashMode,int hashSize,int hashDefaultMode)
|
|
{
|
|
u_int32_t portControlReg;
|
|
unsigned int hashLengh[NUM_ETH_PORTS];
|
|
|
|
hashLengh[0] = EIGHT_K;
|
|
hashLengh[1] = HALF_K;
|
|
addressTableHashMode[port] = hashMode;
|
|
addressTableHashSize[port] = hashSize;
|
|
|
|
/* allocate memory for the address table */
|
|
addressTableBase[port] = (unsigned int)malloc(hashLengh[hashSize]*MAC_ENTRY_SIZE,
|
|
M_DEVBUF, M_NOWAIT);
|
|
/*
|
|
* Set-up ptr to hash table
|
|
*/
|
|
GT_WRITE(ETH0_HASH_TABLE_PTR_REG+port*ETHERNET_PORTS_DIFFERENCE_OFFSETS,addressTableBase[port]);
|
|
|
|
/* fill all the address table with 0's */
|
|
memset((void*)addressTableBase[port],0,hashLengh[hashSize]*MAC_ENTRY_SIZE);
|
|
|
|
/* set hash size hash mode and HDM in the PCR */
|
|
portControlReg = 0x00000081;
|
|
portControlReg = portControlReg & ~(1 << HASH_DEFUALT_MODE);
|
|
portControlReg = portControlReg & ~(1 << HASH_MODE);
|
|
portControlReg = portControlReg & ~(1 << HASH_SIZE);
|
|
|
|
portControlReg = portControlReg |
|
|
(hashDefaultMode<<HASH_DEFUALT_MODE) |
|
|
(hashMode << HASH_MODE) |
|
|
(hashSize << HASH_SIZE);
|
|
|
|
GT_WRITE(ETH0_PORT_CONFIG_REG+port*ETHERNET_PORTS_DIFFERENCE_OFFSETS, portControlReg);
|
|
|
|
/* enableFiltering */
|
|
enableFiltering(port);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* This function will add an entry to the address table and
|
|
* depends on the hash mode and hash size that was initialized.
|
|
* Inputs
|
|
* port - ETHERNET port number.
|
|
* macH - the 2 most significant bytes of the MAC address.
|
|
* macL - the 4 least significant bytes of the MAC address.
|
|
* skip - if 1 , skip this address.
|
|
* rd - the RD field in the address table.
|
|
* Outputs
|
|
* address table entry is added.
|
|
* TRUE if success.
|
|
* FALSE if fail to make the assignment.
|
|
*/
|
|
int
|
|
addAddressTableEntry(port, macH, macL, rd, skip)
|
|
int port;
|
|
unsigned int macH;
|
|
unsigned int macL;
|
|
unsigned int rd;
|
|
unsigned int skip;
|
|
{
|
|
unsigned int addressHighValue;
|
|
unsigned int addressLowValue;
|
|
void* entryNumber;
|
|
int hashBase = addressTableBase[port];
|
|
int i;
|
|
unsigned int addressLowRead;
|
|
unsigned int addressHighRead;
|
|
|
|
entryNumber = (void*)(hashBase +
|
|
MAC_ENTRY_SIZE*hashTableFunction(macH,macL,(int)addressTableHashSize[port],
|
|
(int)addressTableHashMode[port]));
|
|
addressLowValue = VALID | (skip<<SKIP_BIT) | (rd<<2) | (((macH>>8)&0xf)<<3) | (((macH>>12)&0xf)<<7) |
|
|
(((macH>>0)&0xf)<<11) | (((macH>>4)&0xf)<<15) |
|
|
(((macL>>24)&0xf)<<19) | (((macL>>28)&0xf)<<23) | (((macL>>16)&0xf)<<27) |
|
|
((((macL>>20)&0x1)<<31));
|
|
|
|
addressHighValue = ((macL>>21)&0x7) | (((macL>>8)&0xf)<<3) | (((macL>>12)&0xf)<<7) |
|
|
(((macL>>0)&0xf)<<11) | (((macL>>4)&0xf)<<15);
|
|
|
|
/* find a free place */
|
|
for(i = 0 ; i < HOP_NUMBER ; i++)
|
|
{
|
|
addressLowRead = *(unsigned int*)(entryNumber+i*MAC_ENTRY_SIZE+4);
|
|
if((!(addressLowRead & VALID))/* || (addressLowRead & SKIP)*/)
|
|
{
|
|
entryNumber = entryNumber+i*MAC_ENTRY_SIZE;
|
|
break;
|
|
}
|
|
else /* if the address is the same locate it at the same position */
|
|
{
|
|
addressHighRead = *(unsigned int*)(entryNumber+i*MAC_ENTRY_SIZE);
|
|
if(((addressLowRead>>3)&0x1fffffff)==((addressLowValue>>3)&0x1fffffff)
|
|
&& ((addressHighRead/*&0x7ffff*/)==(addressHighValue/*&0x7ffff*/)))
|
|
{
|
|
printf("addressHighRead = 0x%x addressHighValue = 0x%x\n",addressHighRead,addressHighValue);
|
|
entryNumber = entryNumber+i*MAC_ENTRY_SIZE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if(i == HOP_NUMBER)
|
|
{
|
|
printf("The address table section is full\n");
|
|
return 1;
|
|
}
|
|
|
|
/* write the address to the address table */
|
|
*(unsigned int*)(entryNumber) = addressHighValue;
|
|
*(unsigned int*)(entryNumber+4) = addressLowValue;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* int hashTableFunction(unsigned int macH,unsigned int macL,int HashSize,int hash_mode)
|
|
*
|
|
* This function will calculate the hash function of the address.
|
|
* depends on the hash mode and hash size.
|
|
* Inputs
|
|
* macH - the 2 most significant bytes of the MAC address.
|
|
* macL - the 4 least significant bytes of the MAC address.
|
|
* hashMode - hash mode 0 or hash mode 1.
|
|
* hashSize - the size of the hash table (0=8K ,1=1/2K).
|
|
* Outputs
|
|
* return the caculated entry.
|
|
* TRUE if success.
|
|
* FALSE if fail to make the assignment.
|
|
*/
|
|
int hashTableFunction(unsigned int macH,unsigned int macL,int HashSize,int hash_mode)
|
|
{
|
|
unsigned int hashResult;
|
|
unsigned int ethernetAddH;
|
|
unsigned int ethernetAddL;
|
|
unsigned int ethernetAdd0;
|
|
unsigned int ethernetAdd1;
|
|
unsigned int ethernetAdd2;
|
|
unsigned int ethernetAdd3;
|
|
unsigned int ethernetAddHSwapped = 0;
|
|
unsigned int ethernetAddLSwapped = 0;
|
|
|
|
ethernetAddH = NIBBLE_SWAPPING_16_BIT(macH);
|
|
ethernetAddL = NIBBLE_SWAPPING_32_BIT(macL);
|
|
|
|
ethernetAddHSwapped = GT_NIBBLE(ethernetAddH&0xf)+((GT_NIBBLE((ethernetAddH>>4)&0xf))<<4)+
|
|
((GT_NIBBLE((ethernetAddH>>8)&0xf))<<8)+((GT_NIBBLE((ethernetAddH>>12)&0xf))<<12);
|
|
|
|
|
|
ethernetAddLSwapped = GT_NIBBLE(ethernetAddL&0xf)+((GT_NIBBLE((ethernetAddL>>4)&0xf))<<4)+
|
|
((GT_NIBBLE((ethernetAddL>>8)&0xf))<<8)+((GT_NIBBLE((ethernetAddL>>12)&0xf))<<12)+
|
|
((GT_NIBBLE((ethernetAddL>>16)&0xf))<<16)+((GT_NIBBLE((ethernetAddL>>20)&0xf))<<20)+
|
|
((GT_NIBBLE((ethernetAddL>>24)&0xf))<<24)+((GT_NIBBLE((ethernetAddL>>28)&0xf))<<28);
|
|
|
|
|
|
|
|
ethernetAddH = ethernetAddHSwapped;
|
|
ethernetAddL = ethernetAddLSwapped;
|
|
|
|
if(hash_mode == 0)
|
|
{
|
|
ethernetAdd0 = (ethernetAddL>>2) & 0x3f;
|
|
ethernetAdd1 = (ethernetAddL & 0x3) | ((ethernetAddL>>8) & 0x7f)<<2;
|
|
ethernetAdd2 = (ethernetAddL>>15) & 0x1ff;
|
|
ethernetAdd3 = ((ethernetAddL>>24) & 0xff) | ((ethernetAddH & 0x1)<<8);
|
|
|
|
}
|
|
else
|
|
{
|
|
ethernetAdd0 = FLIP_6_BITS((ethernetAddL) & 0x3f);
|
|
ethernetAdd1 = FLIP_9_BITS(((ethernetAddL>>6) & 0x1ff));
|
|
ethernetAdd2 = FLIP_9_BITS((ethernetAddL>>15) & 0x1ff);
|
|
ethernetAdd3 = FLIP_9_BITS((((ethernetAddL>>24) & 0xff) | ((ethernetAddH & 0x1)<<8)));
|
|
|
|
}
|
|
|
|
hashResult = (ethernetAdd0<<9) | (ethernetAdd1^ethernetAdd2^ethernetAdd3);
|
|
|
|
if(HashSize == _8K_TABLE)
|
|
{
|
|
hashResult = hashResult & 0xffff;
|
|
|
|
}
|
|
else
|
|
{
|
|
hashResult = hashResult & 0x7ff;
|
|
}
|
|
|
|
return hashResult;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* boolean_t enableFiltering(int port)
|
|
*
|
|
* This function will set the Promiscuous mode to normal mode.
|
|
* in ordet to enable Filtering.
|
|
* Inputs
|
|
* port - ETHERNET port number.
|
|
* Outputs
|
|
* address filtering will be enabled.
|
|
* TRUE if success.
|
|
* FALSE if fail to make the assignment.
|
|
*/
|
|
boolean_t enableFiltering(int port)
|
|
{
|
|
u_int32_t portControlReg;
|
|
|
|
portControlReg = GT_READ(ETH0_PORT_CONFIG_REG+port*ETHERNET_PORTS_DIFFERENCE_OFFSETS);
|
|
|
|
portControlReg = portControlReg & ~(1<<PROMISCUOUS_MODE);
|
|
|
|
GT_WRITE(ETH0_PORT_CONFIG_REG+port*ETHERNET_PORTS_DIFFERENCE_OFFSETS, portControlReg);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* bool disableFiltering(int port)
|
|
*
|
|
* This function will set the Promiscuous mode to Promiscuous mode.
|
|
* in order to disable Filtering.
|
|
* Inputs
|
|
* port - ETHERNET port number.
|
|
* Outputs
|
|
* address filtering will be enabled.
|
|
* TRUE if success.
|
|
* FALSE if fail to make the assignment.
|
|
*/
|
|
boolean_t disableFiltering(int port)
|
|
{
|
|
u_int32_t portControlReg;
|
|
|
|
portControlReg = GT_READ(ETH0_PORT_CONFIG_REG+port*ETHERNET_PORTS_DIFFERENCE_OFFSETS);
|
|
|
|
portControlReg = portControlReg | (1<<PROMISCUOUS_MODE);
|
|
|
|
GT_WRITE(ETH0_PORT_CONFIG_REG+port*ETHERNET_PORTS_DIFFERENCE_OFFSETS, portControlReg);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* boolean_t scanAddressTable(int port)
|
|
*
|
|
* This function will scan and print all the address table valid entries.
|
|
* Inputs
|
|
* port - ETHERNET port number.
|
|
* TRUE if success.
|
|
* FALSE if fail to make the assignment.
|
|
*/
|
|
boolean_t scanAddressTable(int port)
|
|
{
|
|
unsigned int entry=0;
|
|
char dummyBuffer[100];
|
|
|
|
while(findFirstAddressTableEntry(port,&entry,dummyBuffer) != FALSE);
|
|
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* boolean_t findFirstAddressTableEntry(int port,unsigned int* startEntry)
|
|
*
|
|
* This function will scan and print the first address table valid entry.
|
|
* Inputs
|
|
* port - ETHERNET port number.
|
|
* TRUE if success.
|
|
* FALSE if fail to make the assignment.
|
|
*/
|
|
boolean_t findFirstAddressTableEntry(int port,unsigned int* startEntry,char* resultBuffer)
|
|
{
|
|
unsigned int currentEntry;
|
|
unsigned int hashLengh[NUM_ETH_PORTS];
|
|
unsigned int addressLowRead;
|
|
unsigned int addressHighRead;
|
|
unsigned int addressLowValue;
|
|
unsigned int addressHighValue;
|
|
unsigned int endTable;
|
|
int hashSize;
|
|
unsigned int firstEntry;
|
|
|
|
hashLengh[0] = EIGHT_K;
|
|
hashLengh[1] = HALF_K;
|
|
|
|
hashSize = addressTableHashSize[port];
|
|
endTable = (addressTableBase[port]+hashLengh[hashSize]*MAC_ENTRY_SIZE);
|
|
firstEntry = *startEntry;
|
|
|
|
currentEntry = addressTableBase[port]+((firstEntry)*MAC_ENTRY_SIZE);
|
|
while(currentEntry < endTable)
|
|
{
|
|
addressLowRead = *(unsigned int*)(currentEntry+4);
|
|
if(addressLowRead & VALID)
|
|
{
|
|
addressHighRead = *(unsigned int*)(currentEntry);
|
|
addressLowValue = (((addressHighRead>>11)&0xf)<<0) | (((addressHighRead>>15)&0xf)<<4) |
|
|
(((addressHighRead>>3)&0xf)<<8) | (((addressHighRead>>7)&0xf)<<12) |
|
|
(((addressLowRead>>27)&0xf)<<16) | (((addressHighRead>>0)&0x7)<<21) |
|
|
(((addressLowRead>>31)&0x1)<<20) | (((addressLowRead>>19)&0xf)<<24) |
|
|
(((addressLowRead>>23)&0xf)<<28);
|
|
addressHighValue = (((addressLowRead>>11)&0xf)<<0) | (((addressLowRead>>15)&0xf)<<4) |
|
|
(((addressLowRead>>3)&0xf)<<8) | (((addressLowRead>>7)&0xf)<<12);
|
|
printf("valid address %04x%08x was found in entry # 0x%x SKIP=%d RD=%d\n",
|
|
addressHighValue,addressLowValue,firstEntry,
|
|
(addressLowRead>>1)&0x1,(addressLowRead>>2)&0x1);
|
|
|
|
sprintf(resultBuffer,"%x!!!%02x!!!%02x!!!%02x!!!%02x!!!%02x!!!%02x!!!%x!!!%x!!!%x",firstEntry*8,(addressHighValue>>8)&0xff,
|
|
(addressHighValue>>0)&0xff,(addressLowValue>>24)&0xff,(addressLowValue>>16)&0xff,
|
|
(addressLowValue>>8)&0xff,(addressLowValue>>0)&0xff,
|
|
((addressLowRead>>2)&0x1),((addressLowRead>>1)&0x1),VALID);
|
|
|
|
firstEntry++;
|
|
*startEntry = firstEntry;
|
|
return TRUE;
|
|
}
|
|
currentEntry += MAC_ENTRY_SIZE;
|
|
firstEntry ++;
|
|
|
|
}
|
|
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* boolean_t addressTableDefragment(int port,int hashMode,int hashSize)
|
|
*
|
|
* This function will save all adresses in memory reinitialize the address table
|
|
* and add all the addresses to the new table.
|
|
* Inputs
|
|
* hashMode - hash mode 0 or hash mode 1.
|
|
* hashSize - the size of the hash table.
|
|
* port - ETHERNET port number.
|
|
* Outputs
|
|
* address table is reinitialized with the old addresses all skip addresses
|
|
* will be deleted.
|
|
* TRUE if success.
|
|
* FALSE if fail to make the assignment.
|
|
*/
|
|
boolean_t addressTableDefragment(int port,int hashMode,int hashSize,int hashDefaultMode)
|
|
{
|
|
ADDRESS_TABLE_STORE addresses[MAX_NUMBER_OF_ADDRESSES_TO_STORE];
|
|
u_int32_t numberOfAddresses = 0;
|
|
u_int32_t entry;
|
|
u_int32_t endTable;
|
|
u_int32_t addressLowRead;
|
|
u_int32_t addressHighRead;
|
|
u_int32_t addressLowValue;
|
|
u_int32_t addressHighValue;
|
|
u_int32_t hashLengh[NUM_ETH_PORTS];
|
|
u_int32_t portControlReg;
|
|
int i;
|
|
|
|
hashLengh[0] = EIGHT_K;
|
|
hashLengh[1] = HALF_K;
|
|
|
|
/* keep all addresses in memory */
|
|
endTable = (addressTableBase[port]+hashLengh[addressTableHashSize[port]]*MAC_ENTRY_SIZE);
|
|
for(entry = addressTableBase[port] ; entry < endTable ; entry+=MAC_ENTRY_SIZE)
|
|
{
|
|
addressLowRead = *(unsigned int*)(entry+4);
|
|
if(addressLowRead & VALID)
|
|
{
|
|
addressHighRead = *(unsigned int*)(entry);
|
|
addressLowValue = (((addressHighRead>>11)&0xf)<<0) | (((addressHighRead>>15)&0xf)<<4) |
|
|
(((addressHighRead>>3)&0xf)<<8) | (((addressHighRead>>7)&0xf)<<12) |
|
|
(((addressLowRead>>27)&0xf)<<16) | (((addressHighRead>>0)&0x7)<<21) |
|
|
(((addressLowRead>>31)&0x1)<<20) | (((addressLowRead>>19)&0xf)<<24) |
|
|
(((addressLowRead>>23)&0xf)<<28);
|
|
addressHighValue = (((addressLowRead>>11)&0xf)<<0) | (((addressLowRead>>15)&0xf)<<4) |
|
|
(((addressLowRead>>3)&0xf)<<8) | (((addressLowRead>>7)&0xf)<<12);
|
|
addresses[numberOfAddresses].macH = addressHighValue;
|
|
addresses[numberOfAddresses].macL = addressLowValue;
|
|
addresses[numberOfAddresses].rd = (addressLowRead>>2)&0x1;
|
|
addresses[numberOfAddresses].skip = (addressLowRead>>1)&0x1;
|
|
addresses[numberOfAddresses].valid = (addressLowRead)&0x1;
|
|
numberOfAddresses++;
|
|
if(numberOfAddresses > MAX_NUMBER_OF_ADDRESSES_TO_STORE)
|
|
{
|
|
printf("can't store so many addresses\n");
|
|
return 1;
|
|
} /* if(numberOfAddresses > MAX_NUMBER_OF_ADDRESSES_TO_STORE) */
|
|
|
|
} /* if(addressLowRead & VALID) */
|
|
} /* for(entry = addressTableBase[port] ; entry < endTable ; entry+=MAC_ENTRY_SIZE) */
|
|
|
|
/* clear the table */
|
|
addressTableClear(port);
|
|
|
|
/* if the table size is the same use the same table else allocate new one */
|
|
/* if the new table is smaller - do not allocate a new one */
|
|
if((hashSize == addressTableHashSize[port]) || (addressTableHashSize[port] == _8K_TABLE))
|
|
{
|
|
portControlReg = GT_READ(ETH0_PORT_CONFIG_REG+port*ETHERNET_PORTS_DIFFERENCE_OFFSETS);
|
|
|
|
portControlReg = portControlReg & ~(1 << HASH_DEFUALT_MODE);
|
|
portControlReg = portControlReg & ~(1 << HASH_MODE);
|
|
portControlReg = portControlReg & ~(1 << HASH_SIZE);
|
|
|
|
portControlReg = portControlReg |
|
|
(hashDefaultMode<<HASH_DEFUALT_MODE) |
|
|
(hashMode << HASH_MODE) |
|
|
(hashSize << HASH_SIZE);
|
|
|
|
GT_WRITE(ETH0_PORT_CONFIG_REG+port*ETHERNET_PORTS_DIFFERENCE_OFFSETS, portControlReg);
|
|
}
|
|
else
|
|
{
|
|
initAddressTable(port,hashMode,hashSize,hashDefaultMode);
|
|
}
|
|
|
|
/* add all the addresses to the table */
|
|
for(i = 0 ; i < numberOfAddresses ; i++)
|
|
{
|
|
if((addresses[i].skip == 0) & (addresses[i].valid == 1))
|
|
{
|
|
/* add only the valid and unskipped addresses */
|
|
addAddressTableEntry(port,addresses[i].macH,addresses[i].macL,addresses[i].rd,addresses[i].skip);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* boolean_t addressTableClear(int port)
|
|
*
|
|
* This function will clear the address table
|
|
* Inputs
|
|
* port - ETHERNET port number.
|
|
* Outputs
|
|
* address table is clear.
|
|
* TRUE if success.
|
|
* FALSE if fail to make the assignment.
|
|
*/
|
|
boolean_t addressTableClear(int port)
|
|
{
|
|
unsigned int hashLengh[NUM_ETH_PORTS];
|
|
|
|
hashLengh[0] = EIGHT_K;
|
|
hashLengh[1] = HALF_K;
|
|
|
|
memset((void*)addressTableBase[port],0,hashLengh[addressTableHashSize[port]]*MAC_ENTRY_SIZE);
|
|
|
|
return TRUE;
|
|
}
|
|
|