|
@@ -443,6 +443,22 @@ static void ftgmac100_do_tx(FTGMAC100State *s, uint32_t tx_ring,
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
+ /* Check for VLAN */
|
|
|
+ if (bd.des0 & FTGMAC100_TXDES0_FTS &&
|
|
|
+ bd.des1 & FTGMAC100_TXDES1_INS_VLANTAG &&
|
|
|
+ be16_to_cpu(PKT_GET_ETH_HDR(ptr)->h_proto) != ETH_P_VLAN) {
|
|
|
+ if (frame_size + len + 4 > sizeof(s->frame)) {
|
|
|
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: frame too big : %d bytes\n",
|
|
|
+ __func__, len);
|
|
|
+ s->isr |= FTGMAC100_INT_XPKT_LOST;
|
|
|
+ len = sizeof(s->frame) - frame_size - 4;
|
|
|
+ }
|
|
|
+ memmove(ptr + 16, ptr + 12, len - 12);
|
|
|
+ stw_be_p(ptr + 12, ETH_P_VLAN);
|
|
|
+ stw_be_p(ptr + 14, bd.des1);
|
|
|
+ len += 4;
|
|
|
+ }
|
|
|
+
|
|
|
ptr += len;
|
|
|
frame_size += len;
|
|
|
if (bd.des0 & FTGMAC100_TXDES0_LTS) {
|
|
@@ -864,7 +880,20 @@ static ssize_t ftgmac100_receive(NetClientState *nc, const uint8_t *buf,
|
|
|
buf_len += size - 4;
|
|
|
}
|
|
|
buf_addr = bd.des3;
|
|
|
- dma_memory_write(&address_space_memory, buf_addr, buf, buf_len);
|
|
|
+ if (first && proto == ETH_P_VLAN && buf_len >= 18) {
|
|
|
+ bd.des1 = lduw_be_p(buf + 14) | FTGMAC100_RXDES1_VLANTAG_AVAIL;
|
|
|
+
|
|
|
+ if (s->maccr & FTGMAC100_MACCR_RM_VLAN) {
|
|
|
+ dma_memory_write(&address_space_memory, buf_addr, buf, 12);
|
|
|
+ dma_memory_write(&address_space_memory, buf_addr + 12, buf + 16,
|
|
|
+ buf_len - 16);
|
|
|
+ } else {
|
|
|
+ dma_memory_write(&address_space_memory, buf_addr, buf, buf_len);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ bd.des1 = 0;
|
|
|
+ dma_memory_write(&address_space_memory, buf_addr, buf, buf_len);
|
|
|
+ }
|
|
|
buf += buf_len;
|
|
|
if (size < 4) {
|
|
|
dma_memory_write(&address_space_memory, buf_addr + buf_len,
|