summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/dev/pci/if_em.c41
1 files changed, 40 insertions, 1 deletions
diff --git a/sys/dev/pci/if_em.c b/sys/dev/pci/if_em.c
index 541f87f46f2..7d68e157a4a 100644
--- a/sys/dev/pci/if_em.c
+++ b/sys/dev/pci/if_em.c
@@ -31,7 +31,7 @@ POSSIBILITY OF SUCH DAMAGE.
***************************************************************************/
-/* $OpenBSD: if_em.c,v 1.192 2008/10/15 19:12:18 blambert Exp $ */
+/* $OpenBSD: if_em.c,v 1.193 2008/10/19 19:53:09 brad Exp $ */
/* $FreeBSD: if_em.c,v 1.46 2004/09/29 18:28:28 mlaier Exp $ */
#include <dev/pci/if_em.h>
@@ -178,6 +178,7 @@ void em_print_hw_stats(struct em_softc *);
#endif
void em_update_link_status(struct em_softc *);
int em_get_buf(struct em_softc *, int);
+void em_enable_hw_vlans(struct em_softc *);
int em_encap(struct em_softc *, struct mbuf *);
void em_smartspeed(struct em_softc *);
int em_82547_fifo_workaround(struct em_softc *, int);
@@ -739,6 +740,10 @@ em_init(void *arg)
}
em_update_link_status(sc);
+ E1000_WRITE_REG(&sc->hw, VET, ETHERTYPE_VLAN);
+ if (ifp->if_capabilities & IFCAP_VLAN_HWTAGGING)
+ em_enable_hw_vlans(sc);
+
/* Prepare transmit descriptors and buffers */
if (em_setup_transmit_structures(sc)) {
printf("%s: Could not setup transmit structures\n",
@@ -1103,6 +1108,16 @@ em_encap(struct em_softc *sc, struct mbuf *m_head)
else
sc->num_tx_desc_avail -= map->dm_nsegs;
+ /* Find out if we are in VLAN mode */
+ if (m_head->m_flags & M_VLANTAG) {
+ /* Set the VLAN id */
+ current_tx_desc->upper.fields.special =
+ htole16(m_head->m_pkthdr.ether_vtag);
+
+ /* Tell hardware to add tag */
+ current_tx_desc->lower.data |= htole32(E1000_TXD_CMD_VLE);
+ }
+
tx_buffer->m_head = m_head;
tx_buffer_mapped->map = tx_buffer->map;
tx_buffer->map = map;
@@ -1718,6 +1733,10 @@ em_setup_interface(struct em_softc *sc)
ifp->if_capabilities = IFCAP_VLAN_MTU;
+#if NVLAN > 0
+ ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING;
+#endif
+
#ifdef EM_CSUM_OFFLOAD
if (sc->hw.mac_type >= em_82543)
ifp->if_capabilities |= IFCAP_CSUM_TCPv4|IFCAP_CSUM_UDPv4;
@@ -2699,6 +2718,12 @@ em_rxeof(struct em_softc *sc, int count)
ifp->if_ipackets++;
em_receive_checksum(sc, current_desc,
sc->fmp);
+ if (current_desc->status & E1000_RXD_STAT_VP) {
+ sc->fmp->m_pkthdr.ether_vtag =
+ (current_desc->special &
+ E1000_RXD_SPC_VLAN_MASK);
+ sc->fmp->m_flags |= M_VLANTAG;
+ }
m = sc->fmp;
sc->fmp = NULL;
sc->lmp = NULL;
@@ -2793,6 +2818,20 @@ em_receive_checksum(struct em_softc *sc, struct em_rx_desc *rx_desc,
}
}
+/*
+ * This turns on the hardware offload of the VLAN
+ * tag insertion and strip
+ */
+void
+em_enable_hw_vlans(struct em_softc *sc)
+{
+ uint32_t ctrl;
+
+ ctrl = E1000_READ_REG(&sc->hw, CTRL);
+ ctrl |= E1000_CTRL_VME;
+ E1000_WRITE_REG(&sc->hw, CTRL, ctrl);
+}
+
void
em_enable_intr(struct em_softc *sc)
{