forked from Imagelibrary/rtems
2009-06-05 Till Straumann <strauman@slac.stanford.edu>
* network/tsec.c, network/if_tsec_pub.h: implemented multicast support.
This commit is contained in:
@@ -1,3 +1,8 @@
|
||||
2009-06-05 Till Straumann <strauman@slac.stanford.edu>
|
||||
|
||||
* network/tsec.c, network/if_tsec_pub.h:
|
||||
implemented multicast support.
|
||||
|
||||
2009-04-28 Chris Johns <chrisj@rtems.org>
|
||||
|
||||
* start/start.S: Update for boot_card command line change.
|
||||
|
||||
@@ -173,10 +173,44 @@ BSP_tsec_reset_stats(struct tsec_private *mp);
|
||||
* 'promisc' whether to set promiscuous flag.
|
||||
* 'enaddr' pointer to six bytes with MAC address. Read
|
||||
* from the device if NULL.
|
||||
* NOTE: multicast filter is cleared by this routine.
|
||||
*/
|
||||
void
|
||||
BSP_tsec_init_hw(struct tsec_private *mp, int promisc, unsigned char *enaddr);
|
||||
|
||||
/*
|
||||
* Clear multicast hash filter. No multicast frames are accepted
|
||||
* after executing this routine (unless the hardware was initialized
|
||||
* in 'promiscuous' mode).
|
||||
*/
|
||||
void
|
||||
BSP_tsec_mcast_filter_clear(struct tsec_private *mp);
|
||||
|
||||
/*
|
||||
* Program multicast filter to accept all multicast frames.
|
||||
*/
|
||||
void
|
||||
BSP_tsec_mcast_filter_accept_all(struct tsec_private *mp);
|
||||
|
||||
/*
|
||||
* Add a MAC address to the multicast filter.
|
||||
* Existing entries are not changed but note that
|
||||
* the filter is imperfect, i.e., multiple MAC addresses
|
||||
* may alias to a single filter entry. Hence software
|
||||
* filtering must still be performed.
|
||||
*
|
||||
* NOTE: Deletion of an address is not possible. This is
|
||||
* usually accomplished by a higher-level driver
|
||||
* maintaining a list/database of multicast addresses
|
||||
* and going through a sequence:
|
||||
*
|
||||
* BSP_tsec_mcast_filter_clear()
|
||||
* forall mcast addresses do
|
||||
* BSP_tsec_mcast_filter_accept_add()
|
||||
*/
|
||||
void
|
||||
BSP_tsec_mcast_filter_accept_add(struct tsec_private *mp, unsigned char *enaddr);
|
||||
|
||||
/*
|
||||
* Dump statistics to FILE 'f'. If NULL, stdout is used.
|
||||
*/
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
#include <libcpu/byteorder.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <bsp.h>
|
||||
|
||||
@@ -113,6 +114,9 @@ phy_irq_pending(struct tsec_private *mp);
|
||||
static uint32_t
|
||||
phy_ack_irq(struct tsec_private *mp);
|
||||
|
||||
static void
|
||||
tsec_update_mcast(struct ifnet *ifp);
|
||||
|
||||
#if defined(PARANOIA) || defined(DEBUG)
|
||||
void tsec_dump_tring(struct tsec_private *mp);
|
||||
void tsec_dump_rring(struct tsec_private *mp);
|
||||
@@ -1339,9 +1343,10 @@ rtems_interrupt_level l;
|
||||
|
||||
for ( i=0; i<8*4; i+=4 ) {
|
||||
fec_wr( b, TSEC_IADDR0 + i, 0 );
|
||||
fec_wr( b, TSEC_GADDR0 + i, 0 );
|
||||
}
|
||||
|
||||
BSP_tsec_mcast_filter_clear(mp);
|
||||
|
||||
BSP_tsec_reset_stats(mp);
|
||||
|
||||
fec_wr( b, TSEC_ATTR, (TSEC_ATTR_RDSEN | TSEC_ATTR_RBDSEN) );
|
||||
@@ -1396,6 +1401,54 @@ rtems_interrupt_level l;
|
||||
rtems_interrupt_enable( l );
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
hash_accept(struct tsec_private *mp, uint32_t tble, const uint8_t *enaddr)
|
||||
{
|
||||
uint8_t s;
|
||||
|
||||
s = ether_crc32_le(enaddr, ETHER_ADDR_LEN);
|
||||
|
||||
/* bit-reverse */
|
||||
s = ((s&0x0f) << 4) | ((s&0xf0) >> 4);
|
||||
s = ((s&0x33) << 2) | ((s&0xcc) >> 2);
|
||||
s = ((s&0x55) << 1) | ((s&0xaa) >> 1);
|
||||
|
||||
fec_wr( mp->base, tble + (s >> (5-2)), (1 << (31 - (s & 31))) );
|
||||
}
|
||||
|
||||
void
|
||||
BSP_tsec_mcast_filter_clear(struct tsec_private *mp)
|
||||
{
|
||||
int i;
|
||||
for ( i=0; i<8*4; i+=4 ) {
|
||||
fec_wr( mp->base, TSEC_GADDR0 + i, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BSP_tsec_mcast_filter_accept_all(struct tsec_private *mp)
|
||||
{
|
||||
int i;
|
||||
for ( i=0; i<8*4; i+=4 ) {
|
||||
fec_wr( mp->base, TSEC_GADDR0 + i, 0xffffffff );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BSP_tsec_mcast_filter_accept_add(struct tsec_private *mp, uint8_t *enaddr)
|
||||
{
|
||||
static const uint8_t bcst={0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
if ( ! (enaddr[0] & 0x01) ) {
|
||||
/* not a multicast address; ignore */
|
||||
return;
|
||||
}
|
||||
if ( 0 == memcmp( enaddr, bcst, sizeof(bcst) ) ) {
|
||||
/* broadcast; ignore */
|
||||
return;
|
||||
}
|
||||
hash_accept(mp, TSEC_GADDR0, enaddr);
|
||||
}
|
||||
|
||||
void
|
||||
BSP_tsec_dump_stats(struct tsec_private *mp, FILE *f)
|
||||
{
|
||||
@@ -2310,6 +2363,8 @@ tsec_init(void *arg)
|
||||
struct tsec_softc *sc = arg;
|
||||
struct ifnet *ifp = &sc->arpcom.ac_if;
|
||||
BSP_tsec_init_hw(&sc->pvt, ifp->if_flags & IFF_PROMISC, sc->arpcom.ac_enaddr);
|
||||
|
||||
tsec_update_mcast(ifp);
|
||||
ifp->if_flags |= IFF_RUNNING;
|
||||
sc->arpcom.ac_if.if_timer = 0;
|
||||
}
|
||||
@@ -2348,6 +2403,31 @@ struct tsec_softc *sc = ifp->if_softc;
|
||||
tsec_start(ifp);
|
||||
}
|
||||
|
||||
static void
|
||||
tsec_update_mcast(struct ifnet *ifp)
|
||||
{
|
||||
struct tsec_softc *sc = ifp->if_softc;
|
||||
struct ether_multi *enm;
|
||||
struct ether_multistep step;
|
||||
|
||||
if ( IFF_ALLMULTI & ifp->if_flags ) {
|
||||
BSP_tsec_mcast_filter_accept_all( &sc->pvt );
|
||||
} else {
|
||||
BSP_tsec_mcast_filter_clear( &sc->pvt );
|
||||
|
||||
ETHER_FIRST_MULTI(step, (struct arpcom *)ifp, enm);
|
||||
|
||||
while ( enm ) {
|
||||
if ( memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN) )
|
||||
assert( !"Should never get here; IFF_ALLMULTI should be set!" );
|
||||
|
||||
BSP_tsec_mcast_filter_accept_add(&sc->pvt, enm->enm_addrlo);
|
||||
|
||||
ETHER_NEXT_MULTI(step, enm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* bsdnet driver ioctl entry */
|
||||
static int
|
||||
tsec_ioctl(struct ifnet *ifp, ioctl_command_t cmd, caddr_t data)
|
||||
@@ -2395,15 +2475,19 @@ int f;
|
||||
error = BSP_tsec_media_ioctl(&sc->pvt, cmd, &ifr->ifr_media);
|
||||
break;
|
||||
|
||||
/*
|
||||
* TODO
|
||||
*
|
||||
* case SIOCADDMULTI:
|
||||
* case SIOCDELMULTI:
|
||||
*
|
||||
* break;
|
||||
*/
|
||||
case SIOCADDMULTI:
|
||||
case SIOCDELMULTI:
|
||||
error = (cmd == SIOCADDMULTI)
|
||||
? ether_addmulti(ifr, &sc->arpcom)
|
||||
: ether_delmulti(ifr, &sc->arpcom);
|
||||
|
||||
if (error == ENETRESET) {
|
||||
if (ifp->if_flags & IFF_RUNNING) {
|
||||
tsec_update_mcast(ifp);
|
||||
}
|
||||
error = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case SIO_RTEMS_SHOW_STATS:
|
||||
BSP_tsec_dump_stats( &sc->pvt, stdout );
|
||||
@@ -2570,7 +2654,7 @@ struct ifnet *ifp;
|
||||
ifp->if_timer = 0;
|
||||
|
||||
sc->bsd.oif_flags = /* ... */
|
||||
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
|
||||
ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX;
|
||||
|
||||
/*
|
||||
* if unset, this set to 10Mbps by ether_ifattach; seems to be unused by bsdnet stack;
|
||||
|
||||
Reference in New Issue
Block a user