Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/vr/if_vr.c
Show First 20 Lines • Show All 426 Lines • ▼ Show 20 Lines | vr_cam_data(struct vr_softc *sc, int type, int idx, uint8_t *mac) | ||||
if (i == VR_TIMEOUT) | if (i == VR_TIMEOUT) | ||||
device_printf(sc->vr_dev, "%s: setting CAM filter timeout!\n", | device_printf(sc->vr_dev, "%s: setting CAM filter timeout!\n", | ||||
__func__); | __func__); | ||||
CSR_WRITE_1(sc, VR_CAMCTL, 0); | CSR_WRITE_1(sc, VR_CAMCTL, 0); | ||||
return (i == VR_TIMEOUT ? ETIMEDOUT : 0); | return (i == VR_TIMEOUT ? ETIMEDOUT : 0); | ||||
} | } | ||||
struct vr_hash_maddr_cam_ctx { | |||||
struct vr_softc *sc; | |||||
uint32_t mask; | |||||
int error; | |||||
}; | |||||
static u_int | |||||
vr_hash_maddr_cam(void *arg, struct sockaddr_dl *sdl, u_int mcnt) | |||||
{ | |||||
struct vr_hash_maddr_cam_ctx *ctx = arg; | |||||
if (ctx->error != 0) | |||||
return (0); | |||||
ctx->error = vr_cam_data(ctx->sc, VR_MCAST_CAM, mcnt, LLADDR(sdl)); | |||||
if (ctx->error != 0) { | |||||
ctx->mask = 0; | |||||
return (0); | |||||
} | |||||
ctx->mask |= 1 << mcnt; | |||||
return (1); | |||||
} | |||||
static u_int | |||||
vr_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) | |||||
{ | |||||
uint32_t *hashes = arg; | |||||
int h; | |||||
h = ether_crc32_be(LLADDR(sdl), ETHER_ADDR_LEN) >> 26; | |||||
if (h < 32) | |||||
hashes[0] |= (1 << h); | |||||
else | |||||
hashes[1] |= (1 << (h - 32)); | |||||
return (1); | |||||
} | |||||
/* | /* | ||||
* Program the 64-bit multicast hash filter. | * Program the 64-bit multicast hash filter. | ||||
*/ | */ | ||||
static void | static void | ||||
vr_set_filter(struct vr_softc *sc) | vr_set_filter(struct vr_softc *sc) | ||||
{ | { | ||||
struct ifnet *ifp; | struct ifnet *ifp; | ||||
int h; | |||||
uint32_t hashes[2] = { 0, 0 }; | uint32_t hashes[2] = { 0, 0 }; | ||||
struct ifmultiaddr *ifma; | |||||
uint8_t rxfilt; | uint8_t rxfilt; | ||||
int error, mcnt; | int error, mcnt; | ||||
uint32_t cam_mask; | |||||
VR_LOCK_ASSERT(sc); | VR_LOCK_ASSERT(sc); | ||||
ifp = sc->vr_ifp; | ifp = sc->vr_ifp; | ||||
rxfilt = CSR_READ_1(sc, VR_RXCFG); | rxfilt = CSR_READ_1(sc, VR_RXCFG); | ||||
rxfilt &= ~(VR_RXCFG_RX_PROMISC | VR_RXCFG_RX_BROAD | | rxfilt &= ~(VR_RXCFG_RX_PROMISC | VR_RXCFG_RX_BROAD | | ||||
VR_RXCFG_RX_MULTI); | VR_RXCFG_RX_MULTI); | ||||
if (ifp->if_flags & IFF_BROADCAST) | if (ifp->if_flags & IFF_BROADCAST) | ||||
rxfilt |= VR_RXCFG_RX_BROAD; | rxfilt |= VR_RXCFG_RX_BROAD; | ||||
if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { | if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { | ||||
rxfilt |= VR_RXCFG_RX_MULTI; | rxfilt |= VR_RXCFG_RX_MULTI; | ||||
if (ifp->if_flags & IFF_PROMISC) | if (ifp->if_flags & IFF_PROMISC) | ||||
rxfilt |= VR_RXCFG_RX_PROMISC; | rxfilt |= VR_RXCFG_RX_PROMISC; | ||||
CSR_WRITE_1(sc, VR_RXCFG, rxfilt); | CSR_WRITE_1(sc, VR_RXCFG, rxfilt); | ||||
CSR_WRITE_4(sc, VR_MAR0, 0xFFFFFFFF); | CSR_WRITE_4(sc, VR_MAR0, 0xFFFFFFFF); | ||||
CSR_WRITE_4(sc, VR_MAR1, 0xFFFFFFFF); | CSR_WRITE_4(sc, VR_MAR1, 0xFFFFFFFF); | ||||
return; | return; | ||||
} | } | ||||
/* Now program new ones. */ | /* Now program new ones. */ | ||||
error = 0; | error = 0; | ||||
mcnt = 0; | |||||
if_maddr_rlock(ifp); | |||||
if ((sc->vr_quirks & VR_Q_CAM) != 0) { | if ((sc->vr_quirks & VR_Q_CAM) != 0) { | ||||
struct vr_hash_maddr_cam_ctx ctx; | |||||
/* | /* | ||||
* For hardwares that have CAM capability, use | * For hardwares that have CAM capability, use | ||||
* 32 entries multicast perfect filter. | * 32 entries multicast perfect filter. | ||||
*/ | */ | ||||
cam_mask = 0; | ctx.sc = sc; | ||||
CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { | ctx.mask = 0; | ||||
if (ifma->ifma_addr->sa_family != AF_LINK) | ctx.error = 0; | ||||
continue; | mcnt = if_foreach_llmaddr(ifp, vr_hash_maddr_cam, &ctx); | ||||
error = vr_cam_data(sc, VR_MCAST_CAM, mcnt, | vr_cam_mask(sc, VR_MCAST_CAM, ctx.mask); | ||||
LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); | |||||
if (error != 0) { | |||||
cam_mask = 0; | |||||
break; | |||||
} | } | ||||
cam_mask |= 1 << mcnt; | |||||
mcnt++; | |||||
} | |||||
vr_cam_mask(sc, VR_MCAST_CAM, cam_mask); | |||||
} | |||||
if ((sc->vr_quirks & VR_Q_CAM) == 0 || error != 0) { | if ((sc->vr_quirks & VR_Q_CAM) == 0 || error != 0) { | ||||
/* | /* | ||||
* If there are too many multicast addresses or | * If there are too many multicast addresses or | ||||
* setting multicast CAM filter failed, use hash | * setting multicast CAM filter failed, use hash | ||||
* table based filtering. | * table based filtering. | ||||
*/ | */ | ||||
mcnt = 0; | mcnt = if_foreach_llmaddr(ifp, vr_hash_maddr, hashes); | ||||
CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { | |||||
if (ifma->ifma_addr->sa_family != AF_LINK) | |||||
continue; | |||||
h = ether_crc32_be(LLADDR((struct sockaddr_dl *) | |||||
ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; | |||||
if (h < 32) | |||||
hashes[0] |= (1 << h); | |||||
else | |||||
hashes[1] |= (1 << (h - 32)); | |||||
mcnt++; | |||||
} | } | ||||
} | |||||
if_maddr_runlock(ifp); | |||||
if (mcnt > 0) | if (mcnt > 0) | ||||
rxfilt |= VR_RXCFG_RX_MULTI; | rxfilt |= VR_RXCFG_RX_MULTI; | ||||
CSR_WRITE_4(sc, VR_MAR0, hashes[0]); | CSR_WRITE_4(sc, VR_MAR0, hashes[0]); | ||||
CSR_WRITE_4(sc, VR_MAR1, hashes[1]); | CSR_WRITE_4(sc, VR_MAR1, hashes[1]); | ||||
CSR_WRITE_1(sc, VR_RXCFG, rxfilt); | CSR_WRITE_1(sc, VR_RXCFG, rxfilt); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 2,137 Lines • Show Last 20 Lines |