It enabled promiscous mode or sets the multicast filter according to the configuration and parameters to ioctl(SIOCSIFFLAGS), ioctl(SIOCADDMULTI) and ioctl(SIOCDELMULTI). On SIOCADDMULTI/SIOCDELMULTI requests the greth ioctl calls the Ethernet helper functions ether_addmulti()/ether_delmulti() which tells the greth driver when its required to update the MAC multicast filtering.
The interface notifies support for multicast by setting IFF_MULTICAST. The GRETH has two registers which contains a bit-mask of allowed MAC addresses. The incomming MAC address is CRC:ed and the CRC is used as an index into the bit-mask to determine to allow or drop the frame. --- bsps/sparc/include/bsp/greth.h | 7 +++ bsps/sparc/shared/net/greth.c | 99 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 105 insertions(+), 1 deletion(-) diff --git a/bsps/sparc/include/bsp/greth.h b/bsps/sparc/include/bsp/greth.h index 9209d82..1c42c99 100644 --- a/bsps/sparc/include/bsp/greth.h +++ b/bsps/sparc/include/bsp/greth.h @@ -24,6 +24,9 @@ typedef struct _greth_regs { volatile uint32_t mdio_ctrl; /* MDIO control and status */ volatile uint32_t txdesc; /* Transmit descriptor pointer */ volatile uint32_t rxdesc; /* Receive descriptor pointer */ + volatile uint32_t edcl; /* EDCL IP register */ + volatile uint32_t ht_msb; /* Multicast MSB hash */ + volatile uint32_t ht_lsb; /* Multicast LSB hash */ } greth_regs; #define GRETH_TOTAL_BD 128 @@ -83,8 +86,12 @@ typedef struct _greth_regs { #define GRETH_CTRL_RST 0x00000040 /* Reset MAC */ #define GRETH_CTRL_SP 0x00000080 /* 100MBit speed mode */ #define GRETH_CTRL_GB 0x00000100 /* 1GBit speed mode */ +#define GRETH_CTRL_MCE 0x00000800 /* Multicast Enable */ #define GRETH_CTRL_DD 0x00001000 /* Disable EDCL Duplex Detection */ #define GRETH_CTRL_ED 0x00004000 /* EDCL Disable */ +#define GRETH_CTRL_MC 0x02000000 /* Multicast available */ +#define GRETH_CTRL_ME 0x04000000 /* MDIO interrupts enabled */ +#define GRETH_CTRL_GA 0x08000000 /* Gigabit MAC available */ /* Status Register */ #define GRETH_STATUS_RXERR 0x00000001 /* Receive Error */ diff --git a/bsps/sparc/shared/net/greth.c b/bsps/sparc/shared/net/greth.c index b2d2569..d282451 100644 --- a/bsps/sparc/shared/net/greth.c +++ b/bsps/sparc/shared/net/greth.c @@ -194,6 +194,7 @@ struct greth_softc int auto_neg; unsigned int advmodes; /* advertise ethernet speed modes. 0 = all modes. */ struct timespec auto_neg_time; + int mc_available; /* * Statistics @@ -341,6 +342,78 @@ static void print_init_info(struct greth_softc *sc) #endif } +/* + * Generates the hash words based on CRCs of the enabled MAC addresses that are + * allowed to be received. The allowed MAC addresses are maintained in a linked + * "multi-cast" list available in the arpcom structure. + * + * Returns the number of MAC addresses that were processed (in the list) + */ +static int +greth_mac_filter_calc(struct arpcom *ac, uint32_t *msb, uint32_t *lsb) +{ + struct ether_multistep step; + struct ether_multi *enm; + int cnt = 0; + uint32_t crc, htindex, ht[2] = {0, 0}; + + /* Go through the Ethernet Multicast addresses one by one and add their + * CRC contribution to the MAC filter. + */ + ETHER_FIRST_MULTI(step, ac, enm); + while (enm) { + crc = ether_crc32_be((uint8_t *)enm->enm_addrlo, 6); + htindex = crc & 0x3f; + ht[htindex >> 5] |= (1 << (htindex & 0x1F)); + cnt++; + ETHER_NEXT_MULTI(step, enm); + } + + if (cnt > 0) { + *msb = ht[1]; + *lsb = ht[0]; + } + + return cnt; +} + +/* + * Initialize the ethernet hardware + */ +static int greth_mac_filter_set(struct greth_softc *sc) +{ + struct ifnet *ifp = &sc->arpcom.ac_if; + uint32_t hash_msb, hash_lsb, ctrl; + SPIN_IRQFLAGS(flags); + + hash_msb = 0; + hash_lsb = 0; + ctrl = 0; + if (ifp->if_flags & IFF_PROMISC) { + /* No need to enable multi-cast when promiscous mode accepts all */ + ctrl |= GRETH_CTRL_PRO; + } else if(!sc->mc_available) { + return EINVAL; /* no hardware support for multicast filtering. */ + } else if (ifp->if_flags & IFF_ALLMULTI) { + /* We should accept all multicast addresses */ + ctrl |= GRETH_CTRL_MCE; + hash_msb = 0xFFFFFFFF; + hash_lsb = 0xFFFFFFFF; + } else if (greth_mac_filter_calc(&sc->arpcom, &hash_msb, &hash_lsb) > 0) { + /* Generate hash for MAC filtering out multicast addresses */ + ctrl |= GRETH_CTRL_MCE; + } else { + /* Multicast list is empty .. disable multicast */ + } + SPIN_LOCK_IRQ(&sc->devlock, flags); + sc->regs->ht_msb = hash_msb; + sc->regs->ht_lsb = hash_lsb; + sc->regs->ctrl = (sc->regs->ctrl & ~(GRETH_CTRL_PRO | GRETH_CTRL_MCE)) | + ctrl; + SPIN_UNLOCK_IRQ(&sc->devlock, flags); + + return 0; +} /* * Initialize the ethernet hardware @@ -1182,6 +1255,11 @@ greth_init (void *arg) } /* + * Setup promiscous/multi-cast MAC address filters if user enabled it + */ + greth_mac_filter_set(sc); + + /* * Tell the world that we're running. */ ifp->if_flags |= IFF_RUNNING; @@ -1240,6 +1318,7 @@ greth_ioctl (struct ifnet *ifp, ioctl_command_t command, caddr_t data) { struct greth_softc *sc = ifp->if_softc; int error = 0; + struct ifreq *ifr; switch (command) { @@ -1273,8 +1352,21 @@ greth_ioctl (struct ifnet *ifp, ioctl_command_t command, caddr_t data) break; /* - * FIXME: All sorts of multicast commands need to be added here! + * Multicast commands: Enabling/disabling filtering of MAC addresses */ + case SIOCADDMULTI: + case SIOCDELMULTI: + ifr = (struct ifreq *)data; + if (command == SIOCADDMULTI) { + error = ether_addmulti(ifr, &sc->arpcom); + } else { + error = ether_delmulti(ifr, &sc->arpcom); + } + if (error == ENETRESET) { + error = greth_mac_filter_set(sc); + } + break; + default: error = EINVAL; break; @@ -1336,6 +1428,8 @@ greth_interface_driver_attach ( ifp->if_start = greth_start; ifp->if_output = ether_output; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; + if (sc->mc_available) + ifp->if_flags |= IFF_MULTICAST; if (ifp->if_snd.ifq_maxlen == 0) ifp->if_snd.ifq_maxlen = ifqmaxlen; @@ -1540,6 +1634,9 @@ int greth_device_init(struct greth_softc *sc) if ( value ) sc->advmodes = value->i; + /* Check if multicast support is available */ + sc->mc_available = sc->regs->ctrl & GRETH_CTRL_MC; + return 0; } -- 2.7.4 _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel