Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/vte/if_vte.c
Show First 20 Lines • Show All 1,949 Lines • ▼ Show 20 Lines | vte_init_rx_ring(struct vte_softc *sc) | ||||
bus_dmamap_sync(sc->vte_cdata.vte_rx_ring_tag, | bus_dmamap_sync(sc->vte_cdata.vte_rx_ring_tag, | ||||
sc->vte_cdata.vte_rx_ring_map, BUS_DMASYNC_PREREAD | | sc->vte_cdata.vte_rx_ring_map, BUS_DMASYNC_PREREAD | | ||||
BUS_DMASYNC_PREWRITE); | BUS_DMASYNC_PREWRITE); | ||||
return (0); | return (0); | ||||
} | } | ||||
struct vte_maddr_ctx { | |||||
uint16_t rxfilt_perf[VTE_RXFILT_PERFECT_CNT][3]; | |||||
uint16_t mchash[4]; | |||||
u_int nperf; | |||||
}; | |||||
static u_int | |||||
vte_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) | |||||
{ | |||||
struct vte_maddr_ctx *ctx = arg; | |||||
uint8_t *eaddr; | |||||
uint32_t crc; | |||||
/* | |||||
* Program the first 3 multicast groups into the perfect filter. | |||||
* For all others, use the hash table. | |||||
*/ | |||||
if (ctx->nperf < VTE_RXFILT_PERFECT_CNT) { | |||||
eaddr = LLADDR(sdl); | |||||
ctx->rxfilt_perf[ctx->nperf][0] = eaddr[1] << 8 | eaddr[0]; | |||||
ctx->rxfilt_perf[ctx->nperf][1] = eaddr[3] << 8 | eaddr[2]; | |||||
ctx->rxfilt_perf[ctx->nperf][2] = eaddr[5] << 8 | eaddr[4]; | |||||
ctx->nperf++; | |||||
return (1); | |||||
} | |||||
crc = ether_crc32_be(LLADDR(sdl), ETHER_ADDR_LEN); | |||||
ctx->mchash[crc >> 30] |= 1 << ((crc >> 26) & 0x0F); | |||||
return (1); | |||||
} | |||||
static void | static void | ||||
vte_rxfilter(struct vte_softc *sc) | vte_rxfilter(struct vte_softc *sc) | ||||
{ | { | ||||
struct ifnet *ifp; | struct ifnet *ifp; | ||||
struct ifmultiaddr *ifma; | struct vte_maddr_ctx ctx; | ||||
uint8_t *eaddr; | uint16_t mcr; | ||||
uint32_t crc; | int i; | ||||
uint16_t rxfilt_perf[VTE_RXFILT_PERFECT_CNT][3]; | |||||
uint16_t mchash[4], mcr; | |||||
int i, nperf; | |||||
VTE_LOCK_ASSERT(sc); | VTE_LOCK_ASSERT(sc); | ||||
ifp = sc->vte_ifp; | ifp = sc->vte_ifp; | ||||
bzero(mchash, sizeof(mchash)); | bzero(ctx.mchash, sizeof(ctx.mchash)); | ||||
for (i = 0; i < VTE_RXFILT_PERFECT_CNT; i++) { | for (i = 0; i < VTE_RXFILT_PERFECT_CNT; i++) { | ||||
rxfilt_perf[i][0] = 0xFFFF; | ctx.rxfilt_perf[i][0] = 0xFFFF; | ||||
rxfilt_perf[i][1] = 0xFFFF; | ctx.rxfilt_perf[i][1] = 0xFFFF; | ||||
rxfilt_perf[i][2] = 0xFFFF; | ctx.rxfilt_perf[i][2] = 0xFFFF; | ||||
} | } | ||||
ctx.nperf = 0; | |||||
mcr = CSR_READ_2(sc, VTE_MCR0); | mcr = CSR_READ_2(sc, VTE_MCR0); | ||||
mcr &= ~(MCR0_PROMISC | MCR0_MULTICAST); | mcr &= ~(MCR0_PROMISC | MCR0_MULTICAST); | ||||
mcr |= MCR0_BROADCAST_DIS; | mcr |= MCR0_BROADCAST_DIS; | ||||
if ((ifp->if_flags & IFF_BROADCAST) != 0) | if ((ifp->if_flags & IFF_BROADCAST) != 0) | ||||
mcr &= ~MCR0_BROADCAST_DIS; | mcr &= ~MCR0_BROADCAST_DIS; | ||||
if ((ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI)) != 0) { | if ((ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI)) != 0) { | ||||
if ((ifp->if_flags & IFF_PROMISC) != 0) | if ((ifp->if_flags & IFF_PROMISC) != 0) | ||||
mcr |= MCR0_PROMISC; | mcr |= MCR0_PROMISC; | ||||
if ((ifp->if_flags & IFF_ALLMULTI) != 0) | if ((ifp->if_flags & IFF_ALLMULTI) != 0) | ||||
mcr |= MCR0_MULTICAST; | mcr |= MCR0_MULTICAST; | ||||
mchash[0] = 0xFFFF; | ctx.mchash[0] = 0xFFFF; | ||||
mchash[1] = 0xFFFF; | ctx.mchash[1] = 0xFFFF; | ||||
mchash[2] = 0xFFFF; | ctx.mchash[2] = 0xFFFF; | ||||
mchash[3] = 0xFFFF; | ctx.mchash[3] = 0xFFFF; | ||||
goto chipit; | goto chipit; | ||||
} | } | ||||
nperf = 0; | if_foreach_llmaddr(ifp, vte_hash_maddr, &ctx); | ||||
if_maddr_rlock(ifp); | if (ctx.mchash[0] != 0 || ctx.mchash[1] != 0 || | ||||
CK_STAILQ_FOREACH(ifma, &sc->vte_ifp->if_multiaddrs, ifma_link) { | ctx.mchash[2] != 0 || ctx.mchash[3] != 0) | ||||
if (ifma->ifma_addr->sa_family != AF_LINK) | |||||
continue; | |||||
/* | |||||
* Program the first 3 multicast groups into | |||||
* the perfect filter. For all others, use the | |||||
* hash table. | |||||
*/ | |||||
if (nperf < VTE_RXFILT_PERFECT_CNT) { | |||||
eaddr = LLADDR((struct sockaddr_dl *)ifma->ifma_addr); | |||||
rxfilt_perf[nperf][0] = eaddr[1] << 8 | eaddr[0]; | |||||
rxfilt_perf[nperf][1] = eaddr[3] << 8 | eaddr[2]; | |||||
rxfilt_perf[nperf][2] = eaddr[5] << 8 | eaddr[4]; | |||||
nperf++; | |||||
continue; | |||||
} | |||||
crc = ether_crc32_be(LLADDR((struct sockaddr_dl *) | |||||
ifma->ifma_addr), ETHER_ADDR_LEN); | |||||
mchash[crc >> 30] |= 1 << ((crc >> 26) & 0x0F); | |||||
} | |||||
if_maddr_runlock(ifp); | |||||
if (mchash[0] != 0 || mchash[1] != 0 || mchash[2] != 0 || | |||||
mchash[3] != 0) | |||||
mcr |= MCR0_MULTICAST; | mcr |= MCR0_MULTICAST; | ||||
chipit: | chipit: | ||||
/* Program multicast hash table. */ | /* Program multicast hash table. */ | ||||
CSR_WRITE_2(sc, VTE_MAR0, mchash[0]); | CSR_WRITE_2(sc, VTE_MAR0, ctx.mchash[0]); | ||||
CSR_WRITE_2(sc, VTE_MAR1, mchash[1]); | CSR_WRITE_2(sc, VTE_MAR1, ctx.mchash[1]); | ||||
CSR_WRITE_2(sc, VTE_MAR2, mchash[2]); | CSR_WRITE_2(sc, VTE_MAR2, ctx.mchash[2]); | ||||
CSR_WRITE_2(sc, VTE_MAR3, mchash[3]); | CSR_WRITE_2(sc, VTE_MAR3, ctx.mchash[3]); | ||||
/* Program perfect filter table. */ | /* Program perfect filter table. */ | ||||
for (i = 0; i < VTE_RXFILT_PERFECT_CNT; i++) { | for (i = 0; i < VTE_RXFILT_PERFECT_CNT; i++) { | ||||
CSR_WRITE_2(sc, VTE_RXFILTER_PEEFECT_BASE + 8 * i + 0, | CSR_WRITE_2(sc, VTE_RXFILTER_PEEFECT_BASE + 8 * i + 0, | ||||
rxfilt_perf[i][0]); | ctx.rxfilt_perf[i][0]); | ||||
CSR_WRITE_2(sc, VTE_RXFILTER_PEEFECT_BASE + 8 * i + 2, | CSR_WRITE_2(sc, VTE_RXFILTER_PEEFECT_BASE + 8 * i + 2, | ||||
rxfilt_perf[i][1]); | ctx.rxfilt_perf[i][1]); | ||||
CSR_WRITE_2(sc, VTE_RXFILTER_PEEFECT_BASE + 8 * i + 4, | CSR_WRITE_2(sc, VTE_RXFILTER_PEEFECT_BASE + 8 * i + 4, | ||||
rxfilt_perf[i][2]); | ctx.rxfilt_perf[i][2]); | ||||
} | } | ||||
CSR_WRITE_2(sc, VTE_MCR0, mcr); | CSR_WRITE_2(sc, VTE_MCR0, mcr); | ||||
CSR_READ_2(sc, VTE_MCR0); | CSR_READ_2(sc, VTE_MCR0); | ||||
} | } | ||||
static int | static int | ||||
sysctl_int_range(SYSCTL_HANDLER_ARGS, int low, int high) | sysctl_int_range(SYSCTL_HANDLER_ARGS, int low, int high) | ||||
{ | { | ||||
Show All 22 Lines |