> Date: Thu, 27 Sep 2012 09:54:35 +1000 > From: Darren Tucker <dtuc...@zip.com.au> > > Hi all. > > This diff adds hardware 802.1q VLAN tagging support to vr(4) (just > tag/untag, it doesn't do anything with the VLAN CAM filters). > > As far as I know, the capability is only in the VT6105M Rhine III chip > which is used, amongst other places, in the pcengines ALIX machines. > > If anyone has a vr(4) (any revision), especially if you use VLANs, > I'd be interested to hear if this works for you. > > I'm not a kernel guy, so it's quite possible I made some basic mistake > in there somewhere, but it works for me on an ALIX: > > vr0 at pci0 dev 9 function 0 "VIA VT6105M RhineIII" rev 0x96: irq 10, address > 00:0d:b9:7e:21:5c > ukphy0 at vr0 phy 1: Generic IEEE 802.3u media interface, rev. 3: OUI > 0x004063, model 0x0034 > > $ ifconfig vr0 hwfeatures | grep hwfeatures > > hwfeatures=8037<CSUM_IPv4,CSUM_TCPv4,CSUM_UDPv4,VLAN_MTU,VLAN_HWTAGGING,WOL> > > As an aside, I found what I believe is a latent bug in the existing > driver. When it's done with the TX descriptor, it sets the "owner" > bit to tell the chip that it's good to go: > > #define VR_TXSTAT_OWN 0x80000000 > #define VR_TXOWN(x) x->vr_ptr->vr_status > > VR_TXOWN(cur_tx) = htole32(VR_TXSTAT_OWN); > > which expands to: > > cur_tx->vr_ptr->vr_status = htole32(0x80000000); > > which zeroes the 31 least significant bits in the first word of the > TX descriptor. Sadly, this includes the VLAN ID, which caused me some > head-scratching trying to figure out why my tagged frames were all in > VLAN 0. > > On the plus side, nothing else currently uses those bits, so right > now it doesn't matter. My questions is: why hide that behind a macro? > or at least, if you're going to, why not go the whole hog and put the > entire thing in there? > > #define VR_TXOWN(x) ((x)->vr_ptr->vr_status |= htole32(VR_TXSTAT_OWN))
Yes. I consider using macros in the LHS of an assignment bad style. But I'd just drop the macro entirely. I think having the code show explicitly that vr_status is getting changed is better, and would probably have prevented the latent bug you mention above. Diff looks good to me, but I don't have the hardware to test this. ok kettenis@ > Index: sys/dev/pci/if_vr.c > =================================================================== > RCS file: /cvs/src/sys/dev/pci/if_vr.c,v > retrieving revision 1.114 > diff -u -p -r1.114 if_vr.c > --- sys/dev/pci/if_vr.c 30 Jan 2012 09:11:30 -0000 1.114 > +++ sys/dev/pci/if_vr.c 26 Sep 2012 23:13:45 -0000 > @@ -62,6 +62,7 @@ > */ > > #include "bpfilter.h" > +#include "vlan.h" > > #include <sys/param.h> > #include <sys/systm.h> > @@ -83,6 +84,11 @@ > #include <net/if_dl.h> > #include <net/if_media.h> > > +#if NVLAN > 0 > +#include <net/if_types.h> > +#include <net/if_vlan_var.h> > +#endif > + > #if NBPFILTER > 0 > #include <net/bpf.h> > #endif > @@ -633,6 +639,12 @@ vr_attach(struct device *parent, struct > if (sc->vr_quirks & VR_Q_CSUM) > ifp->if_capabilities |= IFCAP_CSUM_IPv4|IFCAP_CSUM_TCPv4| > IFCAP_CSUM_UDPv4; > + > +#if NVLAN > 0 > + /* if the hardware can do VLAN tagging, say so. */ > + if (sc->vr_quirks & VR_Q_HWTAG) > + ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING; > +#endif > #ifndef SMALL_KERNEL > if (sc->vr_revid >= REV_ID_VT3065_A) { > ifp->if_capabilities |= IFCAP_WOL; > @@ -880,6 +892,23 @@ vr_rxeof(struct vr_softc *sc) > cur_rx->vr_map->dm_mapsize, BUS_DMASYNC_POSTREAD); > bus_dmamap_unload(sc->sc_dmat, cur_rx->vr_map); > > +#if NVLAN > 0 > + /* > + * If there's a tagged packet, the 802.1q header will be at the > + * 4-byte boundary following the CRC. There will be 2 bytes > + * TPID (0x8100) and 2 bytes TCI (including VLAN ID). > + * This isn't in the data sheet. > + */ > + if (rxctl & VR_RXCTL_TAG) { > + u_int16_t vtag; > + int offset = ((total_len + 3) & ~3) + 2; > + > + bcopy(m->m_data + offset, &vtag, sizeof(vtag)); > + m->m_pkthdr.ether_vtag = ntohs(vtag); > + m->m_flags |= M_VLANTAG; > + } > +#endif > + > /* > * The VIA Rhine chip includes the CRC with every > * received frame, and there's no way to turn this > @@ -1002,7 +1031,7 @@ vr_txeof(struct vr_softc *sc) > sc->vr_flags |= VR_F_RESTART; > break; > } > - VR_TXOWN(cur_tx) = htole32(VR_TXSTAT_OWN); > + VR_TXOWN(cur_tx) |= htole32(VR_TXSTAT_OWN); > CSR_WRITE_4(sc, VR_TXADDR, cur_tx->vr_paddr); > break; > } > @@ -1170,6 +1199,16 @@ vr_encap(struct vr_softc *sc, struct vr_ > struct mbuf *m_new = NULL; > u_int32_t vr_flags = 0, vr_status = 0; > > +#if NVLAN > 0 > + /* Tell chip to insert VLAN tag if needed. */ > + if (m_head->m_flags & M_VLANTAG) { > + u_int32_t vtag = m_head->m_pkthdr.ether_vtag; > + vtag = (vtag << VR_TXSTAT_PQSHIFT) & VR_TXSTAT_PQMASK; > + vr_status |= vtag; > + vr_flags |= VR_TXCTL_INSERTTAG; > + } > +#endif > + > if (sc->vr_quirks & VR_Q_CSUM) { > if (m_head->m_pkthdr.csum_flags & M_IPV4_CSUM_OUT) > vr_flags |= VR_TXCTL_IPCSUM; > @@ -1274,7 +1313,7 @@ vr_start(struct ifnet *ifp) > break; > } > > - VR_TXOWN(cur_tx) = htole32(VR_TXSTAT_OWN); > + VR_TXOWN(cur_tx) |= htole32(VR_TXSTAT_OWN); > > #if NBPFILTER > 0 > /* > @@ -1394,6 +1433,11 @@ vr_init(void *xsc) > * Program promiscuous mode and multicast filters. > */ > vr_iff(sc); > + > +#if NVLAN > 0 > + if (ifp->if_capabilities & IFCAP_VLAN_HWTAGGING) > + VR_SETBIT(sc, VR_TXCFG, VR_TXCFG_TXTAGEN); > +#endif > > /* > * Load the address of the RX list. > Index: sys/dev/pci/if_vrreg.h > =================================================================== > RCS file: /cvs/src/sys/dev/pci/if_vrreg.h,v > retrieving revision 1.30 > diff -u -p -r1.30 if_vrreg.h > --- sys/dev/pci/if_vrreg.h 5 Jan 2012 19:08:25 -0000 1.30 > +++ sys/dev/pci/if_vrreg.h 26 Sep 2012 23:13:45 -0000 > @@ -83,6 +83,9 @@ > #define VR_MPA_CNT 0x7C > #define VR_CRC_CNT 0x7E > #define VR_STICKHW 0x83 > +#define VR_CAMMASK 0x88 /* 4 bytes */ > +#define VR_CAMCTRL 0x92 > +#define VR_CAMADDR 0x93 > > /* Misc Registers */ > #define VR_MISC_CR1 0x81 > @@ -342,6 +345,14 @@ > #define VR_BCR1_VLANFILT_ENB 0x80 /* 6105M */ > > /* > + * CAM Control registers (VT6105M) > + */ > +#define VR_CAMCTRL_WREN 0x01 > +#define VR_CAMCTRL_VCAMSEL 0x02 > +#define VR_CAMCTRL_WRITE 0x04 > +#define VR_CAMCTRL_READ 0x08 > + > +/* > * Rhine TX/RX list structure. > */ > > @@ -404,6 +415,7 @@ struct vr_desc { > #define VR_TXSTAT_ERRSUM 0x00008000 > #define VR_TXSTAT_PQMASK 0x7FFF0000 > #define VR_TXSTAT_OWN 0x80000000 > +#define VR_TXSTAT_PQSHIFT 16 > > #define VR_TXCTL_BUFLEN 0x000007FF > #define VR_TXCTL_BUFLEN_EXT 0x00007800 > > -- > Darren Tucker (dtucker at zip.com.au) > GPG key 8FF4FA69 / D9A3 86E9 7EEE AF4B B2D4 37C9 C982 80C7 8FF4 FA69 > Good judgement comes with experience. Unfortunately, the experience > usually comes from bad judgement.