Message ID | 20180530061711.23673-3-clg@kaod.org |
---|---|
State | New |
Headers | show |
Series | net: ftgmac100 enhancements | expand |
On 30 May 2018 at 07:17, Cédric Le Goater <clg@kaod.org> wrote: > The ftgmac100 NIC supports VLAN tag insertion and the MAC engine also > has a control to remove VLAN tags from received packets. > > The VLAN control bits and VLAN tag information are contained in the > second word of the transmit and receive descriptors. The Insert VLAN > bit and the VLAN Tag available bit are only valid in the first segment > of the packet. > > Signed-off-by: Cédric Le Goater <clg@kaod.org> > Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> > + /* 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) { This is kind of bogus because there's no guarantee that h_proto here is sufficiently aligned to do a halfword load. However this is a problem common to all the PKT_GET_* macros so we should probably attack it separately to this series. Getting the ethernet h_proto field seems common enough that something like static inline uint16_t eth_get_proto(uint8_t *pkt) { return lduw_be_p(&PKT_GET_ETH_HDR(pkt)->h_proto); } would be handy in eth.h. Anyway, I've applied this series to target-arm.next. thanks -- PMM
On 06/07/2018 02:41 PM, Peter Maydell wrote: > On 30 May 2018 at 07:17, Cédric Le Goater <clg@kaod.org> wrote: >> The ftgmac100 NIC supports VLAN tag insertion and the MAC engine also >> has a control to remove VLAN tags from received packets. >> >> The VLAN control bits and VLAN tag information are contained in the >> second word of the transmit and receive descriptors. The Insert VLAN >> bit and the VLAN Tag available bit are only valid in the first segment >> of the packet. >> >> Signed-off-by: Cédric Le Goater <clg@kaod.org> >> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> > >> + /* 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) { > > This is kind of bogus because there's no guarantee that h_proto here > is sufficiently aligned to do a halfword load. However this is > a problem common to all the PKT_GET_* macros so we should probably > attack it separately to this series. > > Getting the ethernet h_proto field seems common enough that > something like > > static inline uint16_t eth_get_proto(uint8_t *pkt) > { > return lduw_be_p(&PKT_GET_ETH_HDR(pkt)->h_proto); > } > > would be handy in eth.h. yes. There are a few candidates : hw/net/virtio-net.c: int vid = lduw_be_p(ptr + 14) & 0xfff; hw/net/e1000e_core.c: uint16_t vid = lduw_be_p(buf + 14); hw/net/rtl8139.c: lduw_be_p(&buf[ETH_ALEN * 2]) == ETH_P_VLAN) { hw/net/e1000x_common.c: uint16_t eth_proto = lduw_be_p(buf + 12); hw/net/e1000.c: uint16_t vid = lduw_be_p(buf + 14); hw/net/e1000.c: vlan_special = cpu_to_le16(lduw_be_p(filter_buf + 14)); Thanks, C. > Anyway, I've applied this series to target-arm.next. > > thanks > -- PMM >
diff --git a/hw/net/ftgmac100.c b/hw/net/ftgmac100.c index 425ac36cff87..abf80655f28f 100644 --- a/hw/net/ftgmac100.c +++ b/hw/net/ftgmac100.c @@ -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,