|
@@ -481,6 +481,37 @@ static int ftgmac100_write_bd(FTGMAC100Desc *bd, dma_addr_t addr)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int ftgmac100_insert_vlan(FTGMAC100State *s, int frame_size,
|
|
|
+ uint8_t vlan_tci)
|
|
|
+{
|
|
|
+ uint8_t *vlan_hdr = s->frame + (ETH_ALEN * 2);
|
|
|
+ uint8_t *payload = vlan_hdr + sizeof(struct vlan_header);
|
|
|
+
|
|
|
+ if (frame_size < sizeof(struct eth_header)) {
|
|
|
+ qemu_log_mask(LOG_GUEST_ERROR,
|
|
|
+ "%s: frame too small for VLAN insertion : %d bytes\n",
|
|
|
+ __func__, frame_size);
|
|
|
+ s->isr |= FTGMAC100_INT_XPKT_LOST;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (frame_size + sizeof(struct vlan_header) > sizeof(s->frame)) {
|
|
|
+ qemu_log_mask(LOG_GUEST_ERROR,
|
|
|
+ "%s: frame too big : %d bytes\n",
|
|
|
+ __func__, frame_size);
|
|
|
+ s->isr |= FTGMAC100_INT_XPKT_LOST;
|
|
|
+ frame_size -= sizeof(struct vlan_header);
|
|
|
+ }
|
|
|
+
|
|
|
+ memmove(payload, vlan_hdr, frame_size - (ETH_ALEN * 2));
|
|
|
+ stw_be_p(vlan_hdr, ETH_P_VLAN);
|
|
|
+ stw_be_p(vlan_hdr + 2, vlan_tci);
|
|
|
+ frame_size += sizeof(struct vlan_header);
|
|
|
+
|
|
|
+out:
|
|
|
+ return frame_size;
|
|
|
+}
|
|
|
+
|
|
|
static void ftgmac100_do_tx(FTGMAC100State *s, uint32_t tx_ring,
|
|
|
uint32_t tx_descriptor)
|
|
|
{
|
|
@@ -530,25 +561,17 @@ 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) {
|
|
|
+
|
|
|
+ /* Check for VLAN */
|
|
|
+ if (flags & FTGMAC100_TXDES1_INS_VLANTAG &&
|
|
|
+ be16_to_cpu(PKT_GET_ETH_HDR(s->frame)->h_proto) != ETH_P_VLAN) {
|
|
|
+ frame_size = ftgmac100_insert_vlan(s, frame_size,
|
|
|
+ FTGMAC100_TXDES1_VLANTAG_CI(flags));
|
|
|
+ }
|
|
|
+
|
|
|
if (flags & FTGMAC100_TXDES1_IP_CHKSUM) {
|
|
|
net_checksum_calculate(s->frame, frame_size);
|
|
|
}
|