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>
|
2009-04-28 Chris Johns <chrisj@rtems.org>
|
||||||
|
|
||||||
* start/start.S: Update for boot_card command line change.
|
* 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.
|
* 'promisc' whether to set promiscuous flag.
|
||||||
* 'enaddr' pointer to six bytes with MAC address. Read
|
* 'enaddr' pointer to six bytes with MAC address. Read
|
||||||
* from the device if NULL.
|
* from the device if NULL.
|
||||||
|
* NOTE: multicast filter is cleared by this routine.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
BSP_tsec_init_hw(struct tsec_private *mp, int promisc, unsigned char *enaddr);
|
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.
|
* Dump statistics to FILE 'f'. If NULL, stdout is used.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -50,6 +50,7 @@
|
|||||||
#include <libcpu/byteorder.h>
|
#include <libcpu/byteorder.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <bsp.h>
|
#include <bsp.h>
|
||||||
|
|
||||||
@@ -113,6 +114,9 @@ phy_irq_pending(struct tsec_private *mp);
|
|||||||
static uint32_t
|
static uint32_t
|
||||||
phy_ack_irq(struct tsec_private *mp);
|
phy_ack_irq(struct tsec_private *mp);
|
||||||
|
|
||||||
|
static void
|
||||||
|
tsec_update_mcast(struct ifnet *ifp);
|
||||||
|
|
||||||
#if defined(PARANOIA) || defined(DEBUG)
|
#if defined(PARANOIA) || defined(DEBUG)
|
||||||
void tsec_dump_tring(struct tsec_private *mp);
|
void tsec_dump_tring(struct tsec_private *mp);
|
||||||
void tsec_dump_rring(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 ) {
|
for ( i=0; i<8*4; i+=4 ) {
|
||||||
fec_wr( b, TSEC_IADDR0 + i, 0 );
|
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);
|
BSP_tsec_reset_stats(mp);
|
||||||
|
|
||||||
fec_wr( b, TSEC_ATTR, (TSEC_ATTR_RDSEN | TSEC_ATTR_RBDSEN) );
|
fec_wr( b, TSEC_ATTR, (TSEC_ATTR_RDSEN | TSEC_ATTR_RBDSEN) );
|
||||||
@@ -1396,6 +1401,54 @@ rtems_interrupt_level l;
|
|||||||
rtems_interrupt_enable( 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
|
void
|
||||||
BSP_tsec_dump_stats(struct tsec_private *mp, FILE *f)
|
BSP_tsec_dump_stats(struct tsec_private *mp, FILE *f)
|
||||||
{
|
{
|
||||||
@@ -2310,6 +2363,8 @@ tsec_init(void *arg)
|
|||||||
struct tsec_softc *sc = arg;
|
struct tsec_softc *sc = arg;
|
||||||
struct ifnet *ifp = &sc->arpcom.ac_if;
|
struct ifnet *ifp = &sc->arpcom.ac_if;
|
||||||
BSP_tsec_init_hw(&sc->pvt, ifp->if_flags & IFF_PROMISC, sc->arpcom.ac_enaddr);
|
BSP_tsec_init_hw(&sc->pvt, ifp->if_flags & IFF_PROMISC, sc->arpcom.ac_enaddr);
|
||||||
|
|
||||||
|
tsec_update_mcast(ifp);
|
||||||
ifp->if_flags |= IFF_RUNNING;
|
ifp->if_flags |= IFF_RUNNING;
|
||||||
sc->arpcom.ac_if.if_timer = 0;
|
sc->arpcom.ac_if.if_timer = 0;
|
||||||
}
|
}
|
||||||
@@ -2348,6 +2403,31 @@ struct tsec_softc *sc = ifp->if_softc;
|
|||||||
tsec_start(ifp);
|
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 */
|
/* bsdnet driver ioctl entry */
|
||||||
static int
|
static int
|
||||||
tsec_ioctl(struct ifnet *ifp, ioctl_command_t cmd, caddr_t data)
|
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);
|
error = BSP_tsec_media_ioctl(&sc->pvt, cmd, &ifr->ifr_media);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*
|
case SIOCADDMULTI:
|
||||||
* TODO
|
case SIOCDELMULTI:
|
||||||
*
|
error = (cmd == SIOCADDMULTI)
|
||||||
* case SIOCADDMULTI:
|
? ether_addmulti(ifr, &sc->arpcom)
|
||||||
* case SIOCDELMULTI:
|
: ether_delmulti(ifr, &sc->arpcom);
|
||||||
*
|
|
||||||
* break;
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
if (error == ENETRESET) {
|
||||||
|
if (ifp->if_flags & IFF_RUNNING) {
|
||||||
|
tsec_update_mcast(ifp);
|
||||||
|
}
|
||||||
|
error = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case SIO_RTEMS_SHOW_STATS:
|
case SIO_RTEMS_SHOW_STATS:
|
||||||
BSP_tsec_dump_stats( &sc->pvt, stdout );
|
BSP_tsec_dump_stats( &sc->pvt, stdout );
|
||||||
@@ -2570,7 +2654,7 @@ struct ifnet *ifp;
|
|||||||
ifp->if_timer = 0;
|
ifp->if_timer = 0;
|
||||||
|
|
||||||
sc->bsd.oif_flags = /* ... */
|
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;
|
* if unset, this set to 10Mbps by ether_ifattach; seems to be unused by bsdnet stack;
|
||||||
|
|||||||
Reference in New Issue
Block a user