qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] Re: [PATCH] e1000 VLAN offload emulation


From: Alex Williamson
Subject: [Qemu-devel] Re: [PATCH] e1000 VLAN offload emulation
Date: Fri, 21 Nov 2008 08:41:25 -0700

On Thu, 2008-11-20 at 17:11 -0600, Anthony Liguori wrote:
> The patch looks good but I don't like the idea of taking patches against 
> kvm-userspace.  It suggests that people have only tested in 
> kvm-userspace which means it's not guaranteed to work (or even compile) 
> in upstream QEMU.  Please rebase against QEMU and resubmit.

Hi Anthony,

Thanks for reviewing.  Here's a new one, created and tested against qemu
5765.  Thanks,

Alex


e1000: Add VLAN tagging/stripping/filtering offload emulation

Signed-off-by: Alex Williamson <address@hidden>
--

diff --git a/hw/e1000.c b/hw/e1000.c
index b351119..71781e6 100644
--- a/hw/e1000.c
+++ b/hw/e1000.c
@@ -88,9 +88,12 @@ typedef struct E1000State_st {
     int check_rxov;
     struct e1000_tx {
         unsigned char header[256];
+        unsigned char vlan_header[4];
+        unsigned char vlan[4];
         unsigned char data[0x10000];
         uint16_t size;
         unsigned char sum_needed;
+        unsigned char vlan_needed;
         uint8_t ipcss;
         uint8_t ipcso;
         uint16_t ipcse;
@@ -127,7 +130,8 @@ enum {
     defreg(TDBAL),     defreg(TDH),    defreg(TDLEN),  defreg(TDT),
     defreg(TORH),      defreg(TORL),   defreg(TOTH),   defreg(TOTL),
     defreg(TPR),       defreg(TPT),    defreg(TXDCTL), defreg(WUFC),
-    defreg(RA),                defreg(MTA),    defreg(CRCERRS),
+    defreg(RA),                defreg(MTA),    defreg(CRCERRS),defreg(VFTA),
+    defreg(VET),
 };
 
 enum { PHY_R = 1, PHY_W = 2, PHY_RW = PHY_R | PHY_W };
@@ -293,6 +297,31 @@ putsum(uint8_t *data, uint32_t n, uint32_t sloc, uint32_t 
css, uint32_t cse)
     }
 }
 
+static inline int
+vlan_enabled(E1000State *s)
+{
+    return ((s->mac_reg[CTRL] & E1000_CTRL_VME) != 0);
+}
+
+static inline int
+vlan_rx_filter_enabled(E1000State *s)
+{
+    return ((s->mac_reg[RCTL] & E1000_RCTL_VFE) != 0);
+}
+
+static inline int
+is_vlan_packet(E1000State *s, const uint8_t *buf)
+{
+    return (be16_to_cpup((uint16_t *)(buf + 12)) ==
+                le16_to_cpup((uint16_t *)(s->mac_reg + VET)));
+}
+
+static inline int
+is_vlan_txd(uint32_t txd_lower)
+{
+    return ((txd_lower & E1000_TXD_CMD_VLE) != 0);
+}
+
 static void
 xmit_seg(E1000State *s)
 {
@@ -335,7 +364,12 @@ xmit_seg(E1000State *s)
         putsum(tp->data, tp->size, tp->tucso, tp->tucss, tp->tucse);
     if (tp->sum_needed & E1000_TXD_POPTS_IXSM)
         putsum(tp->data, tp->size, tp->ipcso, tp->ipcss, tp->ipcse);
-    qemu_send_packet(s->vc, tp->data, tp->size);
+    if (tp->vlan_needed) {
+        memmove(tp->vlan, tp->data, 12);
+        memcpy(tp->data + 8, tp->vlan_header, 4);
+        qemu_send_packet(s->vc, tp->vlan, tp->size + 4);
+    } else
+        qemu_send_packet(s->vc, tp->data, tp->size);
     s->mac_reg[TPT]++;
     s->mac_reg[GPTC]++;
     n = s->mac_reg[TOTL];
@@ -382,6 +416,15 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
         // legacy descriptor
         tp->cptse = 0;
 
+    if (vlan_enabled(s) && is_vlan_txd(txd_lower) &&
+        (tp->cptse || txd_lower & E1000_TXD_CMD_EOP)) {
+        tp->vlan_needed = 1;
+        cpu_to_be16wu((uint16_t *)(tp->vlan_header),
+                      le16_to_cpup((uint16_t *)(s->mac_reg + VET)));
+        cpu_to_be16wu((uint16_t *)(tp->vlan_header + 2),
+                      le16_to_cpu(dp->upper.fields.special));
+    }
+        
     addr = le64_to_cpu(dp->buffer_addr);
     if (tp->tse && tp->cptse) {
         hdr = tp->hdr_len;
@@ -415,6 +458,7 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
         xmit_seg(s);
     tp->tso_frames = 0;
     tp->sum_needed = 0;
+    tp->vlan_needed = 0;
     tp->size = 0;
     tp->cptse = 0;
 }
@@ -481,6 +525,14 @@ receive_filter(E1000State *s, const uint8_t *buf, int size)
     static int mta_shift[] = {4, 3, 2, 0};
     uint32_t f, rctl = s->mac_reg[RCTL], ra[2], *rp;
 
+    if (is_vlan_packet(s, buf) && vlan_rx_filter_enabled(s)) {
+        uint16_t vid = be16_to_cpup((uint16_t *)(buf + 14));
+        uint32_t vfta = le32_to_cpup((uint32_t *)(s->mac_reg + VFTA) +
+                                     ((vid >> 5) & 0x7f));
+        if ((vfta & (1 << (vid & 0x1f))) == 0)
+            return 0;
+    }
+
     if (rctl & E1000_RCTL_UPE)                 // promiscuous
         return 1;
 
@@ -535,6 +587,8 @@ e1000_receive(void *opaque, const uint8_t *buf, int size)
     target_phys_addr_t base;
     unsigned int n, rdt;
     uint32_t rdh_start;
+    uint16_t vlan_special = 0;
+    uint8_t vlan_status = 0, vlan_offset = 0;
 
     if (!(s->mac_reg[RCTL] & E1000_RCTL_EN))
         return;
@@ -548,6 +602,14 @@ e1000_receive(void *opaque, const uint8_t *buf, int size)
     if (!receive_filter(s, buf, size))
         return;
 
+    if (vlan_enabled(s) && is_vlan_packet(s, buf)) {
+        vlan_special = cpu_to_le16(be16_to_cpup((uint16_t *)(buf + 14)));
+        memmove((void *)(buf + 4), buf, 12);
+        vlan_status = E1000_RXD_STAT_VP;
+        vlan_offset = 4;
+        size -= 4;
+    }
+
     rdh_start = s->mac_reg[RDH];
     size += 4; // for the header
     do {
@@ -558,10 +620,11 @@ e1000_receive(void *opaque, const uint8_t *buf, int size)
         base = ((uint64_t)s->mac_reg[RDBAH] << 32) + s->mac_reg[RDBAL] +
                sizeof(desc) * s->mac_reg[RDH];
         cpu_physical_memory_read(base, (void *)&desc, sizeof(desc));
-        desc.status |= E1000_RXD_STAT_DD;
+        desc.special = vlan_special;
+        desc.status |= (vlan_status | E1000_RXD_STAT_DD);
         if (desc.buffer_addr) {
             cpu_physical_memory_write(le64_to_cpu(desc.buffer_addr),
-                                      (void *)buf, size);
+                                      (void *)(buf + vlan_offset), size);
             desc.length = cpu_to_le16(size);
             desc.status |= E1000_RXD_STAT_EOP|E1000_RXD_STAT_IXSM;
         } else // as per intel docs; skip descriptors with null buf addr
@@ -691,7 +754,7 @@ static uint32_t (*macreg_readops[])(E1000State *, int) = {
     getreg(WUFC),      getreg(TDT),    getreg(CTRL),   getreg(LEDCTL),
     getreg(MANC),      getreg(MDIC),   getreg(SWSM),   getreg(STATUS),
     getreg(TORL),      getreg(TOTL),   getreg(IMS),    getreg(TCTL),
-    getreg(RDH),       getreg(RDT),
+    getreg(RDH),       getreg(RDT),    getreg(VET),
 
     [TOTH] = mac_read_clr8,    [TORH] = mac_read_clr8, [GPRC] = mac_read_clr4,
     [GPTC] = mac_read_clr4,    [TPR] = mac_read_clr4,  [TPT] = mac_read_clr4,
@@ -699,6 +762,7 @@ static uint32_t (*macreg_readops[])(E1000State *, int) = {
     [CRCERRS ... MPC] = &mac_readreg,
     [RA ... RA+31] = &mac_readreg,
     [MTA ... MTA+127] = &mac_readreg,
+    [VFTA ... VFTA+127] = &mac_readreg,
 };
 enum { NREADOPS = sizeof(macreg_readops) / sizeof(*macreg_readops) };
 
@@ -706,7 +770,7 @@ enum { NREADOPS = sizeof(macreg_readops) / 
sizeof(*macreg_readops) };
 static void (*macreg_writeops[])(E1000State *, int, uint32_t) = {
     putreg(PBA),       putreg(EERD),   putreg(SWSM),   putreg(WUFC),
     putreg(TDBAL),     putreg(TDBAH),  putreg(TXDCTL), putreg(RDBAH),
-    putreg(RDBAL),     putreg(LEDCTL),
+    putreg(RDBAL),     putreg(LEDCTL), putreg(CTRL),   putreg(VET),
     [TDLEN] = set_dlen,        [RDLEN] = set_dlen,     [TCTL] = set_tctl,
     [TDT] = set_tctl,  [MDIC] = set_mdic,      [ICS] = set_ics,
     [TDH] = set_16bit, [RDH] = set_16bit,      [RDT] = set_rdt,
@@ -714,6 +778,7 @@ static void (*macreg_writeops[])(E1000State *, int, 
uint32_t) = {
     [EECD] = set_eecd, [RCTL] = set_rx_control,
     [RA ... RA+31] = &mac_writereg,
     [MTA ... MTA+127] = &mac_writereg,
+    [VFTA ... VFTA+127] = &mac_writereg,
 };
 enum { NWRITEOPS = sizeof(macreg_writeops) / sizeof(*macreg_writeops) };
 
@@ -788,13 +853,14 @@ static const int mac_regtosave[] = {
     LEDCTL,    MANC,   MDIC,   MPC,    PBA,    RCTL,   RDBAH,  RDBAL,  RDH,
     RDLEN,     RDT,    STATUS, SWSM,   TCTL,   TDBAH,  TDBAL,  TDH,    TDLEN,
     TDT,       TORH,   TORL,   TOTH,   TOTL,   TPR,    TPT,    TXDCTL, WUFC,
+    VET,
 };
 enum { MAC_NSAVE = sizeof mac_regtosave/sizeof *mac_regtosave };
 
 static const struct {
     int size;
     int array0;
-} mac_regarraystosave[] = { {32, RA}, {128, MTA} };
+} mac_regarraystosave[] = { {32, RA}, {128, MTA}, {128, VFTA} };
 enum { MAC_NARRAYS = sizeof mac_regarraystosave/sizeof *mac_regarraystosave };
 
 static void






reply via email to

[Prev in Thread] Current Thread [Next in Thread]