aboutsummaryrefslogtreecommitdiff
path: root/hw/net/e1000x_common.c
diff options
context:
space:
mode:
authorAkihiko Odaki <akihiko.odaki@daynix.com>2023-05-23 11:43:06 +0900
committerJason Wang <jasowang@redhat.com>2023-05-23 15:20:15 +0800
commite9e5b930691e5995210ca82aa6b9516733c20577 (patch)
tree4e7836ed9482fcc6dcf4db329270bd54faa7acdf /hw/net/e1000x_common.c
parent0b11783014a0876344b14872d05ad55b21838e12 (diff)
e1000x: Share more Rx filtering logic
This saves some code and enables tracepoint for e1000's VLAN filtering. Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> Reviewed-by: Sriram Yagnaraman <sriram.yagnaraman@est.tech> Signed-off-by: Jason Wang <jasowang@redhat.com>
Diffstat (limited to 'hw/net/e1000x_common.c')
-rw-r--r--hw/net/e1000x_common.c44
1 files changed, 38 insertions, 6 deletions
diff --git a/hw/net/e1000x_common.c b/hw/net/e1000x_common.c
index 7694673bcc..6cc23138a8 100644
--- a/hw/net/e1000x_common.c
+++ b/hw/net/e1000x_common.c
@@ -58,32 +58,64 @@ bool e1000x_is_vlan_packet(const void *buf, uint16_t vet)
return res;
}
-bool e1000x_rx_group_filter(uint32_t *mac, const uint8_t *buf)
+bool e1000x_rx_vlan_filter(uint32_t *mac, const struct vlan_header *vhdr)
+{
+ if (e1000x_vlan_rx_filter_enabled(mac)) {
+ uint16_t vid = lduw_be_p(&vhdr->h_tci);
+ uint32_t vfta =
+ ldl_le_p((uint32_t *)(mac + VFTA) +
+ ((vid >> E1000_VFTA_ENTRY_SHIFT) & E1000_VFTA_ENTRY_MASK));
+ if ((vfta & (1 << (vid & E1000_VFTA_ENTRY_BIT_SHIFT_MASK))) == 0) {
+ trace_e1000x_rx_flt_vlan_mismatch(vid);
+ return false;
+ }
+
+ trace_e1000x_rx_flt_vlan_match(vid);
+ }
+
+ return true;
+}
+
+bool e1000x_rx_group_filter(uint32_t *mac, const struct eth_header *ehdr)
{
static const int mta_shift[] = { 4, 3, 2, 0 };
uint32_t f, ra[2], *rp, rctl = mac[RCTL];
+ if (is_broadcast_ether_addr(ehdr->h_dest)) {
+ if (rctl & E1000_RCTL_BAM) {
+ return true;
+ }
+ } else if (is_multicast_ether_addr(ehdr->h_dest)) {
+ if (rctl & E1000_RCTL_MPE) {
+ return true;
+ }
+ } else {
+ if (rctl & E1000_RCTL_UPE) {
+ return true;
+ }
+ }
+
for (rp = mac + RA; rp < mac + RA + 32; rp += 2) {
if (!(rp[1] & E1000_RAH_AV)) {
continue;
}
ra[0] = cpu_to_le32(rp[0]);
ra[1] = cpu_to_le32(rp[1]);
- if (!memcmp(buf, (uint8_t *)ra, ETH_ALEN)) {
+ if (!memcmp(ehdr->h_dest, (uint8_t *)ra, ETH_ALEN)) {
trace_e1000x_rx_flt_ucast_match((int)(rp - mac - RA) / 2,
- MAC_ARG(buf));
+ MAC_ARG(ehdr->h_dest));
return true;
}
}
- trace_e1000x_rx_flt_ucast_mismatch(MAC_ARG(buf));
+ trace_e1000x_rx_flt_ucast_mismatch(MAC_ARG(ehdr->h_dest));
f = mta_shift[(rctl >> E1000_RCTL_MO_SHIFT) & 3];
- f = (((buf[5] << 8) | buf[4]) >> f) & 0xfff;
+ f = (((ehdr->h_dest[5] << 8) | ehdr->h_dest[4]) >> f) & 0xfff;
if (mac[MTA + (f >> 5)] & (1 << (f & 0x1f))) {
return true;
}
- trace_e1000x_rx_flt_inexact_mismatch(MAC_ARG(buf),
+ trace_e1000x_rx_flt_inexact_mismatch(MAC_ARG(ehdr->h_dest),
(rctl >> E1000_RCTL_MO_SHIFT) & 3,
f >> 5,
mac[MTA + (f >> 5)]);