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 88 int check_rxov;
89 89 struct e1000_tx {
90 90 unsigned char header[256];
  91 + unsigned char vlan_header[4];
  92 + unsigned char vlan[4];
91 93 unsigned char data[0x10000];
92 94 uint16_t size;
93 95 unsigned char sum_needed;
  96 + unsigned char vlan_needed;
94 97 uint8_t ipcss;
95 98 uint8_t ipcso;
96 99 uint16_t ipcse;
... ... @@ -127,7 +130,8 @@ enum {
127 130 defreg(TDBAL), defreg(TDH), defreg(TDLEN), defreg(TDT),
128 131 defreg(TORH), defreg(TORL), defreg(TOTH), defreg(TOTL),
129 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 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 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 325 static void
297 326 xmit_seg(E1000State *s)
298 327 {
... ... @@ -335,7 +364,12 @@ xmit_seg(E1000State *s)
335 364 putsum(tp->data, tp->size, tp->tucso, tp->tucss, tp->tucse);
336 365 if (tp->sum_needed & E1000_TXD_POPTS_IXSM)
337 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 373 s->mac_reg[TPT]++;
340 374 s->mac_reg[GPTC]++;
341 375 n = s->mac_reg[TOTL];
... ... @@ -382,6 +416,15 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
382 416 // legacy descriptor
383 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 428 addr = le64_to_cpu(dp->buffer_addr);
386 429 if (tp->tse && tp->cptse) {
387 430 hdr = tp->hdr_len;
... ... @@ -415,6 +458,7 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
415 458 xmit_seg(s);
416 459 tp->tso_frames = 0;
417 460 tp->sum_needed = 0;
  461 + tp->vlan_needed = 0;
418 462 tp->size = 0;
419 463 tp->cptse = 0;
420 464 }
... ... @@ -481,6 +525,14 @@ receive_filter(E1000State *s, const uint8_t *buf, int size)
481 525 static int mta_shift[] = {4, 3, 2, 0};
482 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 536 if (rctl & E1000_RCTL_UPE) // promiscuous
485 537 return 1;
486 538  
... ... @@ -535,6 +587,8 @@ e1000_receive(void *opaque, const uint8_t *buf, int size)
535 587 target_phys_addr_t base;
536 588 unsigned int n, rdt;
537 589 uint32_t rdh_start;
  590 + uint16_t vlan_special = 0;
  591 + uint8_t vlan_status = 0, vlan_offset = 0;
538 592  
539 593 if (!(s->mac_reg[RCTL] & E1000_RCTL_EN))
540 594 return;
... ... @@ -548,6 +602,14 @@ e1000_receive(void *opaque, const uint8_t *buf, int size)
548 602 if (!receive_filter(s, buf, size))
549 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 613 rdh_start = s->mac_reg[RDH];
552 614 size += 4; // for the header
553 615 do {
... ... @@ -558,10 +620,11 @@ e1000_receive(void *opaque, const uint8_t *buf, int size)
558 620 base = ((uint64_t)s->mac_reg[RDBAH] << 32) + s->mac_reg[RDBAL] +
559 621 sizeof(desc) * s->mac_reg[RDH];
560 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 625 if (desc.buffer_addr) {
563 626 cpu_physical_memory_write(le64_to_cpu(desc.buffer_addr),
564   - (void *)buf, size);
  627 + (void *)(buf + vlan_offset), size);
565 628 desc.length = cpu_to_le16(size);
566 629 desc.status |= E1000_RXD_STAT_EOP|E1000_RXD_STAT_IXSM;
567 630 } else // as per intel docs; skip descriptors with null buf addr
... ... @@ -691,7 +754,7 @@ static uint32_t (*macreg_readops[])(E1000State *, int) = {
691 754 getreg(WUFC), getreg(TDT), getreg(CTRL), getreg(LEDCTL),
692 755 getreg(MANC), getreg(MDIC), getreg(SWSM), getreg(STATUS),
693 756 getreg(TORL), getreg(TOTL), getreg(IMS), getreg(TCTL),
694   - getreg(RDH), getreg(RDT),
  757 + getreg(RDH), getreg(RDT), getreg(VET),
695 758  
696 759 [TOTH] = mac_read_clr8, [TORH] = mac_read_clr8, [GPRC] = mac_read_clr4,
697 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 762 [CRCERRS ... MPC] = &mac_readreg,
700 763 [RA ... RA+31] = &mac_readreg,
701 764 [MTA ... MTA+127] = &mac_readreg,
  765 + [VFTA ... VFTA+127] = &mac_readreg,
702 766 };
703 767 enum { NREADOPS = sizeof(macreg_readops) / sizeof(*macreg_readops) };
704 768  
... ... @@ -706,7 +770,7 @@ enum { NREADOPS = sizeof(macreg_readops) / sizeof(*macreg_readops) };
706 770 static void (*macreg_writeops[])(E1000State *, int, uint32_t) = {
707 771 putreg(PBA), putreg(EERD), putreg(SWSM), putreg(WUFC),
708 772 putreg(TDBAL), putreg(TDBAH), putreg(TXDCTL), putreg(RDBAH),
709   - putreg(RDBAL), putreg(LEDCTL),
  773 + putreg(RDBAL), putreg(LEDCTL), putreg(CTRL), putreg(VET),
710 774 [TDLEN] = set_dlen, [RDLEN] = set_dlen, [TCTL] = set_tctl,
711 775 [TDT] = set_tctl, [MDIC] = set_mdic, [ICS] = set_ics,
712 776 [TDH] = set_16bit, [RDH] = set_16bit, [RDT] = set_rdt,
... ... @@ -714,6 +778,7 @@ static void (*macreg_writeops[])(E1000State *, int, uint32_t) = {
714 778 [EECD] = set_eecd, [RCTL] = set_rx_control,
715 779 [RA ... RA+31] = &mac_writereg,
716 780 [MTA ... MTA+127] = &mac_writereg,
  781 + [VFTA ... VFTA+127] = &mac_writereg,
717 782 };
718 783 enum { NWRITEOPS = sizeof(macreg_writeops) / sizeof(*macreg_writeops) };
719 784  
... ... @@ -788,13 +853,14 @@ static const int mac_regtosave[] = {
788 853 LEDCTL, MANC, MDIC, MPC, PBA, RCTL, RDBAH, RDBAL, RDH,
789 854 RDLEN, RDT, STATUS, SWSM, TCTL, TDBAH, TDBAL, TDH, TDLEN,
790 855 TDT, TORH, TORL, TOTH, TOTL, TPR, TPT, TXDCTL, WUFC,
  856 + VET,
791 857 };
792 858 enum { MAC_NSAVE = sizeof mac_regtosave/sizeof *mac_regtosave };
793 859  
794 860 static const struct {
795 861 int size;
796 862 int array0;
797   -} mac_regarraystosave[] = { {32, RA}, {128, MTA} };
  863 +} mac_regarraystosave[] = { {32, RA}, {128, MTA}, {128, VFTA} };
798 864 enum { MAC_NARRAYS = sizeof mac_regarraystosave/sizeof *mac_regarraystosave };
799 865  
800 866 static void
... ...