staticint vlan_add_hw_rx_fltr(struct net_device *dev, struct mac_device_info *hw,
__be16 proto, u16 vid)
{ int index = -1;
u32 val = 0; int i, ret;
if (vid > 4095) return -EINVAL;
/* Single Rx VLAN Filter */ if (hw->num_vlan == 1) { /* For single VLAN filter, VID 0 means VLAN promiscuous */ if (vid == 0) {
netdev_warn(dev, "Adding VLAN ID 0 is not supported\n"); return -EPERM;
}
if (hw->vlan_filter[0] & VLAN_TAG_VID) {
netdev_err(dev, "Only single VLAN ID supported\n"); return -EPERM;
}
for (i = 0; i < hw->num_vlan; i++) { if (hw->vlan_filter[i] == val) return 0; elseif (!(hw->vlan_filter[i] & VLAN_TAG_DATA_VEN))
index = i;
}
if (index == -1) {
netdev_err(dev, "MAC_VLAN_Tag_Filter full (size: %0u)\n",
hw->num_vlan); return -EPERM;
}
ret = vlan_write_filter(dev, hw, index, val);
if (!ret)
hw->vlan_filter[index] = val;
return ret;
}
staticint vlan_del_hw_rx_fltr(struct net_device *dev, struct mac_device_info *hw,
__be16 proto, u16 vid)
{ int i, ret = 0;
/* Single Rx VLAN Filter */ if (hw->num_vlan == 1) { if ((hw->vlan_filter[0] & VLAN_TAG_VID) == vid) {
hw->vlan_filter[0] = 0;
vlan_write_single(dev, 0);
} return 0;
}
/* Extended Rx VLAN Filter Enable */ for (i = 0; i < hw->num_vlan; i++) { if ((hw->vlan_filter[i] & VLAN_TAG_DATA_VID) == vid) {
ret = vlan_write_filter(dev, hw, i, 0);
if (!ret)
hw->vlan_filter[i] = 0; else return ret;
}
}
/* Single Rx VLAN Filter */ if (hw->num_vlan == 1) {
vlan_write_single(dev, hw->vlan_filter[0]); return;
}
/* Extended Rx VLAN Filter Enable */ for (i = 0; i < hw->num_vlan; i++) { if (hw->vlan_filter[i] & VLAN_TAG_DATA_VEN) {
val = hw->vlan_filter[i];
vlan_write_filter(dev, hw, i, val);
}
}
hash = readl(ioaddr + VLAN_HASH_TABLE); if (hash & VLAN_VLHT) {
value = readl(ioaddr + VLAN_TAG);
value |= VLAN_VTHM;
writel(value, ioaddr + VLAN_TAG);
}
}
value = readl(ioaddr + VLAN_INCL);
value |= VLAN_VLTI;
value |= VLAN_CSVL; /* Only use SVLAN */
value &= ~VLAN_VLC;
value |= (type << VLAN_VLC_SHIFT) & VLAN_VLC;
writel(value, ioaddr + VLAN_INCL);
}
staticvoid vlan_rx_hw(struct mac_device_info *hw, struct dma_desc *rx_desc, struct sk_buff *skb)
{ if (hw->desc->get_rx_vlan_valid(rx_desc)) {
u16 vid = hw->desc->get_rx_vlan_tci(rx_desc);
if (hw->hw_vlan_en) /* Always strip VLAN on Receive */
value |= VLAN_TAG_STRIP_ALL; else /* Do not strip VLAN on Receive */
value |= VLAN_TAG_STRIP_NONE;
/* Enable outer VLAN Tag in Rx DMA descriptor */
value |= VLAN_TAG_CTRL_EVLRXS;
writel(value, ioaddr + VLAN_TAG);
}
if (hash) {
u32 value = readl(ioaddr + XGMAC_PACKET_FILTER);
value |= XGMAC_FILTER_VTFE;
writel(value, ioaddr + XGMAC_PACKET_FILTER);
value = readl(ioaddr + VLAN_TAG);
value |= VLAN_VTHM | VLAN_ETV; if (is_double) {
value |= VLAN_EDVLP;
value |= VLAN_ESVL;
value |= VLAN_DOVLTC;
} else {
value &= ~VLAN_EDVLP;
value &= ~VLAN_ESVL;
value &= ~VLAN_DOVLTC;
}
value &= ~VLAN_VID;
writel(value, ioaddr + VLAN_TAG);
} elseif (perfect_match) {
u32 value = readl(ioaddr + XGMAC_PACKET_FILTER);
value |= XGMAC_FILTER_VTFE;
writel(value, ioaddr + XGMAC_PACKET_FILTER);
value = readl(ioaddr + VLAN_TAG);
value &= ~VLAN_VTHM;
value |= VLAN_ETV; if (is_double) {
value |= VLAN_EDVLP;
value |= VLAN_ESVL;
value |= VLAN_DOVLTC;
} else {
value &= ~VLAN_EDVLP;
value &= ~VLAN_ESVL;
value &= ~VLAN_DOVLTC;
}
value &= ~VLAN_VID;
writel(value | perfect_match, ioaddr + VLAN_TAG);
} else {
u32 value = readl(ioaddr + XGMAC_PACKET_FILTER);
value &= ~XGMAC_FILTER_VTFE;
writel(value, ioaddr + XGMAC_PACKET_FILTER);
value = readl(ioaddr + VLAN_TAG);
value &= ~(VLAN_VTHM | VLAN_ETV);
value &= ~(VLAN_EDVLP | VLAN_ESVL);
value &= ~VLAN_DOVLTC;
value &= ~VLAN_VID;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.