Commit 8f2e8d1f800d242feb99da920675186fa66f8942

Authored by aliguori
1 parent 7e5f90fa

e1000 VLAN offload emulation (Alex Williamson)

We're currently ignoring the e1000 VLAN tagging, stripping and filtering
features in the e1000 emulation.  This patch adds backing for the
relevant registers and provides a software implementation of the
acceleration, such that a guest can make use of VLANs.

This is mostly (only?) useful for a guest on a bridge (not user mode
networking).  The only caveat beyond that is that you need to make sure
the host NIC isn't doing it's own tagging, stripping, or filtering.
This generally means the host NIC on the bridge should not be part of a
VLAN.

Signed-off-by: Alex Williamson <alex.williamson@hp.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>



git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5766 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 1 changed file with 73 additions and 7 deletions
hw/e1000.c
@@ -88,9 +88,12 @@ typedef struct E1000State_st { @@ -88,9 +88,12 @@ typedef struct E1000State_st {
88 int check_rxov; 88 int check_rxov;
89 struct e1000_tx { 89 struct e1000_tx {
90 unsigned char header[256]; 90 unsigned char header[256];
  91 + unsigned char vlan_header[4];
  92 + unsigned char vlan[4];
91 unsigned char data[0x10000]; 93 unsigned char data[0x10000];
92 uint16_t size; 94 uint16_t size;
93 unsigned char sum_needed; 95 unsigned char sum_needed;
  96 + unsigned char vlan_needed;
94 uint8_t ipcss; 97 uint8_t ipcss;
95 uint8_t ipcso; 98 uint8_t ipcso;
96 uint16_t ipcse; 99 uint16_t ipcse;
@@ -127,7 +130,8 @@ enum { @@ -127,7 +130,8 @@ enum {
127 defreg(TDBAL), defreg(TDH), defreg(TDLEN), defreg(TDT), 130 defreg(TDBAL), defreg(TDH), defreg(TDLEN), defreg(TDT),
128 defreg(TORH), defreg(TORL), defreg(TOTH), defreg(TOTL), 131 defreg(TORH), defreg(TORL), defreg(TOTH), defreg(TOTL),
129 defreg(TPR), defreg(TPT), defreg(TXDCTL), defreg(WUFC), 132 defreg(TPR), defreg(TPT), defreg(TXDCTL), defreg(WUFC),
130 - defreg(RA), defreg(MTA), defreg(CRCERRS), 133 + defreg(RA), defreg(MTA), defreg(CRCERRS),defreg(VFTA),
  134 + defreg(VET),
131 }; 135 };
132 136
133 enum { PHY_R = 1, PHY_W = 2, PHY_RW = PHY_R | PHY_W }; 137 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) @@ -293,6 +297,31 @@ putsum(uint8_t *data, uint32_t n, uint32_t sloc, uint32_t css, uint32_t cse)
293 } 297 }
294 } 298 }
295 299
  300 +static inline int
  301 +vlan_enabled(E1000State *s)
  302 +{
  303 + return ((s->mac_reg[CTRL] & E1000_CTRL_VME) != 0);
  304 +}
  305 +
  306 +static inline int
  307 +vlan_rx_filter_enabled(E1000State *s)
  308 +{
  309 + return ((s->mac_reg[RCTL] & E1000_RCTL_VFE) != 0);
  310 +}
  311 +
  312 +static inline int
  313 +is_vlan_packet(E1000State *s, const uint8_t *buf)
  314 +{
  315 + return (be16_to_cpup((uint16_t *)(buf + 12)) ==
  316 + le16_to_cpup((uint16_t *)(s->mac_reg + VET)));
  317 +}
  318 +
  319 +static inline int
  320 +is_vlan_txd(uint32_t txd_lower)
  321 +{
  322 + return ((txd_lower & E1000_TXD_CMD_VLE) != 0);
  323 +}
  324 +
296 static void 325 static void
297 xmit_seg(E1000State *s) 326 xmit_seg(E1000State *s)
298 { 327 {
@@ -335,7 +364,12 @@ xmit_seg(E1000State *s) @@ -335,7 +364,12 @@ xmit_seg(E1000State *s)
335 putsum(tp->data, tp->size, tp->tucso, tp->tucss, tp->tucse); 364 putsum(tp->data, tp->size, tp->tucso, tp->tucss, tp->tucse);
336 if (tp->sum_needed & E1000_TXD_POPTS_IXSM) 365 if (tp->sum_needed & E1000_TXD_POPTS_IXSM)
337 putsum(tp->data, tp->size, tp->ipcso, tp->ipcss, tp->ipcse); 366 putsum(tp->data, tp->size, tp->ipcso, tp->ipcss, tp->ipcse);
338 - qemu_send_packet(s->vc, tp->data, tp->size); 367 + if (tp->vlan_needed) {
  368 + memmove(tp->vlan, tp->data, 12);
  369 + memcpy(tp->data + 8, tp->vlan_header, 4);
  370 + qemu_send_packet(s->vc, tp->vlan, tp->size + 4);
  371 + } else
  372 + qemu_send_packet(s->vc, tp->data, tp->size);
339 s->mac_reg[TPT]++; 373 s->mac_reg[TPT]++;
340 s->mac_reg[GPTC]++; 374 s->mac_reg[GPTC]++;
341 n = s->mac_reg[TOTL]; 375 n = s->mac_reg[TOTL];
@@ -382,6 +416,15 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) @@ -382,6 +416,15 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
382 // legacy descriptor 416 // legacy descriptor
383 tp->cptse = 0; 417 tp->cptse = 0;
384 418
  419 + if (vlan_enabled(s) && is_vlan_txd(txd_lower) &&
  420 + (tp->cptse || txd_lower & E1000_TXD_CMD_EOP)) {
  421 + tp->vlan_needed = 1;
  422 + cpu_to_be16wu((uint16_t *)(tp->vlan_header),
  423 + le16_to_cpup((uint16_t *)(s->mac_reg + VET)));
  424 + cpu_to_be16wu((uint16_t *)(tp->vlan_header + 2),
  425 + le16_to_cpu(dp->upper.fields.special));
  426 + }
  427 +
385 addr = le64_to_cpu(dp->buffer_addr); 428 addr = le64_to_cpu(dp->buffer_addr);
386 if (tp->tse && tp->cptse) { 429 if (tp->tse && tp->cptse) {
387 hdr = tp->hdr_len; 430 hdr = tp->hdr_len;
@@ -415,6 +458,7 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) @@ -415,6 +458,7 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
415 xmit_seg(s); 458 xmit_seg(s);
416 tp->tso_frames = 0; 459 tp->tso_frames = 0;
417 tp->sum_needed = 0; 460 tp->sum_needed = 0;
  461 + tp->vlan_needed = 0;
418 tp->size = 0; 462 tp->size = 0;
419 tp->cptse = 0; 463 tp->cptse = 0;
420 } 464 }
@@ -481,6 +525,14 @@ receive_filter(E1000State *s, const uint8_t *buf, int size) @@ -481,6 +525,14 @@ receive_filter(E1000State *s, const uint8_t *buf, int size)
481 static int mta_shift[] = {4, 3, 2, 0}; 525 static int mta_shift[] = {4, 3, 2, 0};
482 uint32_t f, rctl = s->mac_reg[RCTL], ra[2], *rp; 526 uint32_t f, rctl = s->mac_reg[RCTL], ra[2], *rp;
483 527
  528 + if (is_vlan_packet(s, buf) && vlan_rx_filter_enabled(s)) {
  529 + uint16_t vid = be16_to_cpup((uint16_t *)(buf + 14));
  530 + uint32_t vfta = le32_to_cpup((uint32_t *)(s->mac_reg + VFTA) +
  531 + ((vid >> 5) & 0x7f));
  532 + if ((vfta & (1 << (vid & 0x1f))) == 0)
  533 + return 0;
  534 + }
  535 +
484 if (rctl & E1000_RCTL_UPE) // promiscuous 536 if (rctl & E1000_RCTL_UPE) // promiscuous
485 return 1; 537 return 1;
486 538
@@ -535,6 +587,8 @@ e1000_receive(void *opaque, const uint8_t *buf, int size) @@ -535,6 +587,8 @@ e1000_receive(void *opaque, const uint8_t *buf, int size)
535 target_phys_addr_t base; 587 target_phys_addr_t base;
536 unsigned int n, rdt; 588 unsigned int n, rdt;
537 uint32_t rdh_start; 589 uint32_t rdh_start;
  590 + uint16_t vlan_special = 0;
  591 + uint8_t vlan_status = 0, vlan_offset = 0;
538 592
539 if (!(s->mac_reg[RCTL] & E1000_RCTL_EN)) 593 if (!(s->mac_reg[RCTL] & E1000_RCTL_EN))
540 return; 594 return;
@@ -548,6 +602,14 @@ e1000_receive(void *opaque, const uint8_t *buf, int size) @@ -548,6 +602,14 @@ e1000_receive(void *opaque, const uint8_t *buf, int size)
548 if (!receive_filter(s, buf, size)) 602 if (!receive_filter(s, buf, size))
549 return; 603 return;
550 604
  605 + if (vlan_enabled(s) && is_vlan_packet(s, buf)) {
  606 + vlan_special = cpu_to_le16(be16_to_cpup((uint16_t *)(buf + 14)));
  607 + memmove((void *)(buf + 4), buf, 12);
  608 + vlan_status = E1000_RXD_STAT_VP;
  609 + vlan_offset = 4;
  610 + size -= 4;
  611 + }
  612 +
551 rdh_start = s->mac_reg[RDH]; 613 rdh_start = s->mac_reg[RDH];
552 size += 4; // for the header 614 size += 4; // for the header
553 do { 615 do {
@@ -558,10 +620,11 @@ e1000_receive(void *opaque, const uint8_t *buf, int size) @@ -558,10 +620,11 @@ e1000_receive(void *opaque, const uint8_t *buf, int size)
558 base = ((uint64_t)s->mac_reg[RDBAH] << 32) + s->mac_reg[RDBAL] + 620 base = ((uint64_t)s->mac_reg[RDBAH] << 32) + s->mac_reg[RDBAL] +
559 sizeof(desc) * s->mac_reg[RDH]; 621 sizeof(desc) * s->mac_reg[RDH];
560 cpu_physical_memory_read(base, (void *)&desc, sizeof(desc)); 622 cpu_physical_memory_read(base, (void *)&desc, sizeof(desc));
561 - desc.status |= E1000_RXD_STAT_DD; 623 + desc.special = vlan_special;
  624 + desc.status |= (vlan_status | E1000_RXD_STAT_DD);
562 if (desc.buffer_addr) { 625 if (desc.buffer_addr) {
563 cpu_physical_memory_write(le64_to_cpu(desc.buffer_addr), 626 cpu_physical_memory_write(le64_to_cpu(desc.buffer_addr),
564 - (void *)buf, size); 627 + (void *)(buf + vlan_offset), size);
565 desc.length = cpu_to_le16(size); 628 desc.length = cpu_to_le16(size);
566 desc.status |= E1000_RXD_STAT_EOP|E1000_RXD_STAT_IXSM; 629 desc.status |= E1000_RXD_STAT_EOP|E1000_RXD_STAT_IXSM;
567 } else // as per intel docs; skip descriptors with null buf addr 630 } else // as per intel docs; skip descriptors with null buf addr
@@ -691,7 +754,7 @@ static uint32_t (*macreg_readops[])(E1000State *, int) = { @@ -691,7 +754,7 @@ static uint32_t (*macreg_readops[])(E1000State *, int) = {
691 getreg(WUFC), getreg(TDT), getreg(CTRL), getreg(LEDCTL), 754 getreg(WUFC), getreg(TDT), getreg(CTRL), getreg(LEDCTL),
692 getreg(MANC), getreg(MDIC), getreg(SWSM), getreg(STATUS), 755 getreg(MANC), getreg(MDIC), getreg(SWSM), getreg(STATUS),
693 getreg(TORL), getreg(TOTL), getreg(IMS), getreg(TCTL), 756 getreg(TORL), getreg(TOTL), getreg(IMS), getreg(TCTL),
694 - getreg(RDH), getreg(RDT), 757 + getreg(RDH), getreg(RDT), getreg(VET),
695 758
696 [TOTH] = mac_read_clr8, [TORH] = mac_read_clr8, [GPRC] = mac_read_clr4, 759 [TOTH] = mac_read_clr8, [TORH] = mac_read_clr8, [GPRC] = mac_read_clr4,
697 [GPTC] = mac_read_clr4, [TPR] = mac_read_clr4, [TPT] = mac_read_clr4, 760 [GPTC] = mac_read_clr4, [TPR] = mac_read_clr4, [TPT] = mac_read_clr4,
@@ -699,6 +762,7 @@ static uint32_t (*macreg_readops[])(E1000State *, int) = { @@ -699,6 +762,7 @@ static uint32_t (*macreg_readops[])(E1000State *, int) = {
699 [CRCERRS ... MPC] = &mac_readreg, 762 [CRCERRS ... MPC] = &mac_readreg,
700 [RA ... RA+31] = &mac_readreg, 763 [RA ... RA+31] = &mac_readreg,
701 [MTA ... MTA+127] = &mac_readreg, 764 [MTA ... MTA+127] = &mac_readreg,
  765 + [VFTA ... VFTA+127] = &mac_readreg,
702 }; 766 };
703 enum { NREADOPS = sizeof(macreg_readops) / sizeof(*macreg_readops) }; 767 enum { NREADOPS = sizeof(macreg_readops) / sizeof(*macreg_readops) };
704 768
@@ -706,7 +770,7 @@ enum { NREADOPS = sizeof(macreg_readops) / sizeof(*macreg_readops) }; @@ -706,7 +770,7 @@ enum { NREADOPS = sizeof(macreg_readops) / sizeof(*macreg_readops) };
706 static void (*macreg_writeops[])(E1000State *, int, uint32_t) = { 770 static void (*macreg_writeops[])(E1000State *, int, uint32_t) = {
707 putreg(PBA), putreg(EERD), putreg(SWSM), putreg(WUFC), 771 putreg(PBA), putreg(EERD), putreg(SWSM), putreg(WUFC),
708 putreg(TDBAL), putreg(TDBAH), putreg(TXDCTL), putreg(RDBAH), 772 putreg(TDBAL), putreg(TDBAH), putreg(TXDCTL), putreg(RDBAH),
709 - putreg(RDBAL), putreg(LEDCTL), 773 + putreg(RDBAL), putreg(LEDCTL), putreg(CTRL), putreg(VET),
710 [TDLEN] = set_dlen, [RDLEN] = set_dlen, [TCTL] = set_tctl, 774 [TDLEN] = set_dlen, [RDLEN] = set_dlen, [TCTL] = set_tctl,
711 [TDT] = set_tctl, [MDIC] = set_mdic, [ICS] = set_ics, 775 [TDT] = set_tctl, [MDIC] = set_mdic, [ICS] = set_ics,
712 [TDH] = set_16bit, [RDH] = set_16bit, [RDT] = set_rdt, 776 [TDH] = set_16bit, [RDH] = set_16bit, [RDT] = set_rdt,
@@ -714,6 +778,7 @@ static void (*macreg_writeops[])(E1000State *, int, uint32_t) = { @@ -714,6 +778,7 @@ static void (*macreg_writeops[])(E1000State *, int, uint32_t) = {
714 [EECD] = set_eecd, [RCTL] = set_rx_control, 778 [EECD] = set_eecd, [RCTL] = set_rx_control,
715 [RA ... RA+31] = &mac_writereg, 779 [RA ... RA+31] = &mac_writereg,
716 [MTA ... MTA+127] = &mac_writereg, 780 [MTA ... MTA+127] = &mac_writereg,
  781 + [VFTA ... VFTA+127] = &mac_writereg,
717 }; 782 };
718 enum { NWRITEOPS = sizeof(macreg_writeops) / sizeof(*macreg_writeops) }; 783 enum { NWRITEOPS = sizeof(macreg_writeops) / sizeof(*macreg_writeops) };
719 784
@@ -788,13 +853,14 @@ static const int mac_regtosave[] = { @@ -788,13 +853,14 @@ static const int mac_regtosave[] = {
788 LEDCTL, MANC, MDIC, MPC, PBA, RCTL, RDBAH, RDBAL, RDH, 853 LEDCTL, MANC, MDIC, MPC, PBA, RCTL, RDBAH, RDBAL, RDH,
789 RDLEN, RDT, STATUS, SWSM, TCTL, TDBAH, TDBAL, TDH, TDLEN, 854 RDLEN, RDT, STATUS, SWSM, TCTL, TDBAH, TDBAL, TDH, TDLEN,
790 TDT, TORH, TORL, TOTH, TOTL, TPR, TPT, TXDCTL, WUFC, 855 TDT, TORH, TORL, TOTH, TOTL, TPR, TPT, TXDCTL, WUFC,
  856 + VET,
791 }; 857 };
792 enum { MAC_NSAVE = sizeof mac_regtosave/sizeof *mac_regtosave }; 858 enum { MAC_NSAVE = sizeof mac_regtosave/sizeof *mac_regtosave };
793 859
794 static const struct { 860 static const struct {
795 int size; 861 int size;
796 int array0; 862 int array0;
797 -} mac_regarraystosave[] = { {32, RA}, {128, MTA} }; 863 +} mac_regarraystosave[] = { {32, RA}, {128, MTA}, {128, VFTA} };
798 enum { MAC_NARRAYS = sizeof mac_regarraystosave/sizeof *mac_regarraystosave }; 864 enum { MAC_NARRAYS = sizeof mac_regarraystosave/sizeof *mac_regarraystosave };
799 865
800 static void 866 static void