Path: blob/main/sys/arm64/broadcom/genet/if_genet.c
39507 views
/*-1* Copyright (c) 2020 Michael J Karels2* Copyright (c) 2016, 2020 Jared McNeill <[email protected]>3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9* 2. Redistributions in binary form must reproduce the above copyright10* notice, this list of conditions and the following disclaimer in the11* documentation and/or other materials provided with the distribution.12*13* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR14* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES15* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.16* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,17* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,18* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;19* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED20* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,21* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY22* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF23* SUCH DAMAGE.24*/2526/*27* RPi4 (BCM 2711) Gigabit Ethernet ("GENET") controller28*29* This driver is derived in large part from bcmgenet.c from NetBSD by30* Jared McNeill. Parts of the structure and other common code in31* this driver have been copied from if_awg.c for the Allwinner EMAC,32* also by Jared McNeill.33*/3435#include "opt_device_polling.h"3637#include <sys/param.h>38#include <sys/systm.h>39#include <sys/bus.h>40#include <sys/rman.h>41#include <sys/kernel.h>42#include <sys/endian.h>43#include <sys/mbuf.h>44#include <sys/socket.h>45#include <sys/sockio.h>46#include <sys/sysctl.h>47#include <sys/module.h>48#include <sys/taskqueue.h>49#include <sys/gpio.h>5051#include <net/bpf.h>52#include <net/if.h>53#include <net/ethernet.h>54#include <net/if_dl.h>55#include <net/if_media.h>56#include <net/if_types.h>57#include <net/if_var.h>5859#include <machine/bus.h>6061#include <dev/ofw/ofw_bus.h>62#include <dev/ofw/ofw_bus_subr.h>6364#define __BIT(_x) (1 << (_x))65#include "if_genetreg.h"6667#include <dev/mii/mii.h>68#include <dev/mii/miivar.h>69#include <dev/mii/mii_fdt.h>7071#include <netinet/in.h>72#include <netinet/ip.h>73#include <netinet/ip6.h>7475#include "syscon_if.h"76#include "miibus_if.h"77#include "gpio_if.h"7879#define RD4(sc, reg) bus_read_4((sc)->res[_RES_MAC], (reg))80#define WR4(sc, reg, val) bus_write_4((sc)->res[_RES_MAC], (reg), (val))8182#define GEN_LOCK(sc) mtx_lock(&(sc)->mtx)83#define GEN_UNLOCK(sc) mtx_unlock(&(sc)->mtx)84#define GEN_ASSERT_LOCKED(sc) mtx_assert(&(sc)->mtx, MA_OWNED)85#define GEN_ASSERT_UNLOCKED(sc) mtx_assert(&(sc)->mtx, MA_NOTOWNED)8687#define TX_DESC_COUNT GENET_DMA_DESC_COUNT88#define RX_DESC_COUNT GENET_DMA_DESC_COUNT8990#define TX_NEXT(n, count) (((n) + 1) & ((count) - 1))91#define RX_NEXT(n, count) (((n) + 1) & ((count) - 1))9293#define TX_MAX_SEGS 209495static SYSCTL_NODE(_hw, OID_AUTO, genet, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,96"genet driver parameters");9798/* Maximum number of mbufs to pass per call to if_input */99static int gen_rx_batch = 16 /* RX_BATCH_DEFAULT */;100SYSCTL_INT(_hw_genet, OID_AUTO, rx_batch, CTLFLAG_RDTUN,101&gen_rx_batch, 0, "max mbufs per call to if_input");102103TUNABLE_INT("hw.gen.rx_batch", &gen_rx_batch); /* old name/interface */104105/*106* Transmitting packets with only an Ethernet header in the first mbuf107* fails. Examples include reflected ICMPv6 packets, e.g. echo replies;108* forwarded IPv6/TCP packets; and forwarded IPv4/TCP packets that use NAT109* with IPFW. Pulling up the sizes of ether_header + ip6_hdr + icmp6_hdr110* seems to work for both ICMPv6 and TCP over IPv6, as well as the IPv4/TCP111* case.112*/113static int gen_tx_hdr_min = 56; /* ether_header + ip6_hdr + icmp6_hdr */114SYSCTL_INT(_hw_genet, OID_AUTO, tx_hdr_min, CTLFLAG_RW,115&gen_tx_hdr_min, 0, "header to add to packets with ether header only");116117static struct ofw_compat_data compat_data[] = {118{ "brcm,genet-v1", 1 },119{ "brcm,genet-v2", 2 },120{ "brcm,genet-v3", 3 },121{ "brcm,genet-v4", 4 },122{ "brcm,genet-v5", 5 },123{ "brcm,bcm2711-genet-v5", 5 },124{ NULL, 0 }125};126127enum {128_RES_MAC, /* what to call this? */129_RES_IRQ1,130_RES_IRQ2,131_RES_NITEMS132};133134static struct resource_spec gen_spec[] = {135{ SYS_RES_MEMORY, 0, RF_ACTIVE },136{ SYS_RES_IRQ, 0, RF_ACTIVE },137{ SYS_RES_IRQ, 1, RF_ACTIVE },138{ -1, 0 }139};140141/* structure per ring entry */142struct gen_ring_ent {143bus_dmamap_t map;144struct mbuf *mbuf;145};146147struct tx_queue {148int hwindex; /* hardware index */149int nentries;150u_int queued; /* or avail? */151u_int cur;152u_int next;153u_int prod_idx;154u_int cons_idx;155struct gen_ring_ent *entries;156};157158struct rx_queue {159int hwindex; /* hardware index */160int nentries;161u_int cur;162u_int prod_idx;163u_int cons_idx;164struct gen_ring_ent *entries;165};166167struct gen_softc {168struct resource *res[_RES_NITEMS];169struct mtx mtx;170if_t ifp;171device_t dev;172device_t miibus;173mii_contype_t phy_mode;174175struct callout stat_ch;176struct task link_task;177void *ih;178void *ih2;179int type;180int if_flags;181int link;182bus_dma_tag_t tx_buf_tag;183/*184* The genet chip has multiple queues for transmit and receive.185* This driver uses only one (queue 16, the default), but is cast186* with multiple rings. The additional rings are used for different187* priorities.188*/189#define DEF_TXQUEUE 0190#define NTXQUEUE 1191struct tx_queue tx_queue[NTXQUEUE];192struct gen_ring_ent tx_ring_ent[TX_DESC_COUNT]; /* ring entries */193194bus_dma_tag_t rx_buf_tag;195#define DEF_RXQUEUE 0196#define NRXQUEUE 1197struct rx_queue rx_queue[NRXQUEUE];198struct gen_ring_ent rx_ring_ent[RX_DESC_COUNT]; /* ring entries */199};200201static void gen_init(void *softc);202static void gen_start(if_t ifp);203static void gen_stop(struct gen_softc *sc);204static void gen_destroy(struct gen_softc *sc);205static int gen_encap(struct gen_softc *sc, struct mbuf **mp);206static int gen_parse_tx(struct mbuf *m, int csum_flags);207static int gen_ioctl(if_t ifp, u_long cmd, caddr_t data);208static int gen_get_phy_mode(device_t dev);209static bool gen_get_eaddr(device_t dev, struct ether_addr *eaddr);210static void gen_set_enaddr(struct gen_softc *sc);211static void gen_setup_rxfilter(struct gen_softc *sc);212static void gen_reset(struct gen_softc *sc);213static void gen_enable(struct gen_softc *sc);214static void gen_dma_disable(struct gen_softc *sc);215static int gen_bus_dma_init(struct gen_softc *sc);216static void gen_bus_dma_teardown(struct gen_softc *sc);217static void gen_enable_intr(struct gen_softc *sc);218static void gen_init_txrings(struct gen_softc *sc);219static void gen_init_rxrings(struct gen_softc *sc);220static void gen_intr(void *softc);221static int gen_rxintr(struct gen_softc *sc, struct rx_queue *q);222static void gen_txintr(struct gen_softc *sc, struct tx_queue *q);223static void gen_intr2(void *softc);224static int gen_newbuf_rx(struct gen_softc *sc, struct rx_queue *q, int index);225static int gen_mapbuf_rx(struct gen_softc *sc, struct rx_queue *q, int index,226struct mbuf *m);227static void gen_link_task(void *arg, int pending);228static void gen_media_status(if_t ifp, struct ifmediareq *ifmr);229static int gen_media_change(if_t ifp);230static void gen_tick(void *softc);231232static int233gen_probe(device_t dev)234{235if (!ofw_bus_status_okay(dev))236return (ENXIO);237238if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)239return (ENXIO);240241device_set_desc(dev, "RPi4 Gigabit Ethernet");242return (BUS_PROBE_DEFAULT);243}244245static int246gen_attach(device_t dev)247{248struct ether_addr eaddr;249struct gen_softc *sc;250int major, minor, error, mii_flags;251bool eaddr_found;252253sc = device_get_softc(dev);254sc->dev = dev;255sc->type = ofw_bus_search_compatible(dev, compat_data)->ocd_data;256257if (bus_alloc_resources(dev, gen_spec, sc->res) != 0) {258device_printf(dev, "cannot allocate resources for device\n");259error = ENXIO;260goto fail;261}262263major = (RD4(sc, GENET_SYS_REV_CTRL) & REV_MAJOR) >> REV_MAJOR_SHIFT;264if (major != REV_MAJOR_V5) {265device_printf(dev, "version %d is not supported\n", major);266error = ENXIO;267goto fail;268}269minor = (RD4(sc, GENET_SYS_REV_CTRL) & REV_MINOR) >> REV_MINOR_SHIFT;270device_printf(dev, "GENET version 5.%d phy 0x%04x\n", minor,271RD4(sc, GENET_SYS_REV_CTRL) & REV_PHY);272273mtx_init(&sc->mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, MTX_DEF);274callout_init_mtx(&sc->stat_ch, &sc->mtx, 0);275TASK_INIT(&sc->link_task, 0, gen_link_task, sc);276277error = gen_get_phy_mode(dev);278if (error != 0)279goto fail;280281bzero(&eaddr, sizeof(eaddr));282eaddr_found = gen_get_eaddr(dev, &eaddr);283284/* reset core */285gen_reset(sc);286287gen_dma_disable(sc);288289/* Setup DMA */290error = gen_bus_dma_init(sc);291if (error != 0) {292device_printf(dev, "cannot setup bus dma\n");293goto fail;294}295296/* Setup ethernet interface */297sc->ifp = if_alloc(IFT_ETHER);298if_setsoftc(sc->ifp, sc);299if_initname(sc->ifp, device_get_name(dev), device_get_unit(dev));300if_setflags(sc->ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);301if_setstartfn(sc->ifp, gen_start);302if_setioctlfn(sc->ifp, gen_ioctl);303if_setinitfn(sc->ifp, gen_init);304if_setsendqlen(sc->ifp, TX_DESC_COUNT - 1);305if_setsendqready(sc->ifp);306#define GEN_CSUM_FEATURES (CSUM_UDP | CSUM_TCP)307if_sethwassist(sc->ifp, GEN_CSUM_FEATURES);308if_setcapabilities(sc->ifp, IFCAP_VLAN_MTU | IFCAP_HWCSUM |309IFCAP_HWCSUM_IPV6);310if_setcapenable(sc->ifp, if_getcapabilities(sc->ifp));311312/* Install interrupt handlers */313error = bus_setup_intr(dev, sc->res[_RES_IRQ1],314INTR_TYPE_NET | INTR_MPSAFE, NULL, gen_intr, sc, &sc->ih);315if (error != 0) {316device_printf(dev, "cannot setup interrupt handler1\n");317goto fail;318}319320error = bus_setup_intr(dev, sc->res[_RES_IRQ2],321INTR_TYPE_NET | INTR_MPSAFE, NULL, gen_intr2, sc, &sc->ih2);322if (error != 0) {323device_printf(dev, "cannot setup interrupt handler2\n");324goto fail;325}326327/* Attach MII driver */328mii_flags = 0;329switch (sc->phy_mode)330{331case MII_CONTYPE_RGMII_ID:332mii_flags |= MIIF_RX_DELAY | MIIF_TX_DELAY;333break;334case MII_CONTYPE_RGMII_RXID:335mii_flags |= MIIF_RX_DELAY;336break;337case MII_CONTYPE_RGMII_TXID:338mii_flags |= MIIF_TX_DELAY;339break;340default:341break;342}343error = mii_attach(dev, &sc->miibus, sc->ifp, gen_media_change,344gen_media_status, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY,345mii_flags);346if (error != 0) {347device_printf(dev, "cannot attach PHY\n");348goto fail;349}350351/* If address was not found, create one based on the hostid and name. */352if (!eaddr_found)353ether_gen_addr(sc->ifp, &eaddr);354/* Attach ethernet interface */355ether_ifattach(sc->ifp, eaddr.octet);356357fail:358if (error)359gen_destroy(sc);360return (error);361}362363/* Free resources after failed attach. This is not a complete detach. */364static void365gen_destroy(struct gen_softc *sc)366{367368device_delete_children(sc->dev);369bus_teardown_intr(sc->dev, sc->res[_RES_IRQ1], sc->ih);370bus_teardown_intr(sc->dev, sc->res[_RES_IRQ2], sc->ih2);371gen_bus_dma_teardown(sc);372callout_drain(&sc->stat_ch);373if (mtx_initialized(&sc->mtx))374mtx_destroy(&sc->mtx);375bus_release_resources(sc->dev, gen_spec, sc->res);376if (sc->ifp != NULL) {377if_free(sc->ifp);378sc->ifp = NULL;379}380}381382static int383gen_detach(device_t dev)384{385struct gen_softc *sc;386int error;387388sc = device_get_softc(dev);389390GEN_LOCK(sc);391gen_stop(sc);392GEN_UNLOCK(sc);393callout_drain(&sc->stat_ch);394ether_ifdetach(sc->ifp);395396/* Detach the miibus */397error = bus_generic_detach(dev);398if (error != 0)399return (error);400401/* clean up dma */402gen_bus_dma_teardown(sc);403404/* Release bus resources. */405bus_teardown_intr(sc->dev, sc->res[_RES_IRQ1], sc->ih);406bus_teardown_intr(sc->dev, sc->res[_RES_IRQ2], sc->ih2);407bus_release_resources(sc->dev, gen_spec, sc->res);408409if (sc->ifp != NULL)410if_free(sc->ifp);411mtx_destroy(&sc->mtx);412return (0);413}414415static int416gen_get_phy_mode(device_t dev)417{418struct gen_softc *sc;419phandle_t node;420mii_contype_t type;421int error = 0;422423sc = device_get_softc(dev);424node = ofw_bus_get_node(dev);425type = mii_fdt_get_contype(node);426427switch (type) {428case MII_CONTYPE_RGMII:429case MII_CONTYPE_RGMII_ID:430case MII_CONTYPE_RGMII_RXID:431case MII_CONTYPE_RGMII_TXID:432sc->phy_mode = type;433break;434default:435device_printf(dev, "unknown phy-mode '%s'\n",436mii_fdt_contype_to_name(type));437error = ENXIO;438break;439}440441return (error);442}443444static bool445gen_get_eaddr(device_t dev, struct ether_addr *eaddr)446{447struct gen_softc *sc;448uint32_t maclo, machi, val;449phandle_t node;450451sc = device_get_softc(dev);452453node = ofw_bus_get_node(dev);454if (OF_getprop(node, "mac-address", eaddr->octet,455ETHER_ADDR_LEN) != -1 ||456OF_getprop(node, "local-mac-address", eaddr->octet,457ETHER_ADDR_LEN) != -1 ||458OF_getprop(node, "address", eaddr->octet, ETHER_ADDR_LEN) != -1)459return (true);460461device_printf(dev, "No Ethernet address found in fdt!\n");462maclo = machi = 0;463464val = RD4(sc, GENET_SYS_RBUF_FLUSH_CTRL);465if ((val & GENET_SYS_RBUF_FLUSH_RESET) == 0) {466maclo = htobe32(RD4(sc, GENET_UMAC_MAC0));467machi = htobe16(RD4(sc, GENET_UMAC_MAC1) & 0xffff);468}469470if (maclo == 0 && machi == 0) {471if (bootverbose)472device_printf(dev,473"No Ethernet address found in controller\n");474return (false);475} else {476eaddr->octet[0] = maclo & 0xff;477eaddr->octet[1] = (maclo >> 8) & 0xff;478eaddr->octet[2] = (maclo >> 16) & 0xff;479eaddr->octet[3] = (maclo >> 24) & 0xff;480eaddr->octet[4] = machi & 0xff;481eaddr->octet[5] = (machi >> 8) & 0xff;482return (true);483}484}485486static void487gen_reset(struct gen_softc *sc)488{489uint32_t val;490491val = RD4(sc, GENET_SYS_RBUF_FLUSH_CTRL);492val |= GENET_SYS_RBUF_FLUSH_RESET;493WR4(sc, GENET_SYS_RBUF_FLUSH_CTRL, val);494DELAY(10);495496val &= ~GENET_SYS_RBUF_FLUSH_RESET;497WR4(sc, GENET_SYS_RBUF_FLUSH_CTRL, val);498DELAY(10);499500WR4(sc, GENET_SYS_RBUF_FLUSH_CTRL, 0);501DELAY(10);502503WR4(sc, GENET_UMAC_CMD, 0);504WR4(sc, GENET_UMAC_CMD,505GENET_UMAC_CMD_LCL_LOOP_EN | GENET_UMAC_CMD_SW_RESET);506DELAY(10);507WR4(sc, GENET_UMAC_CMD, 0);508509WR4(sc, GENET_UMAC_MIB_CTRL, GENET_UMAC_MIB_RESET_RUNT |510GENET_UMAC_MIB_RESET_RX | GENET_UMAC_MIB_RESET_TX);511WR4(sc, GENET_UMAC_MIB_CTRL, 0);512}513514static void515gen_enable(struct gen_softc *sc)516{517u_int val;518519WR4(sc, GENET_UMAC_MAX_FRAME_LEN, 1536);520521val = RD4(sc, GENET_RBUF_CTRL);522val |= GENET_RBUF_ALIGN_2B;523WR4(sc, GENET_RBUF_CTRL, val);524525WR4(sc, GENET_RBUF_TBUF_SIZE_CTRL, 1);526527/* Enable transmitter and receiver */528val = RD4(sc, GENET_UMAC_CMD);529val |= GENET_UMAC_CMD_TXEN;530val |= GENET_UMAC_CMD_RXEN;531WR4(sc, GENET_UMAC_CMD, val);532533/* Enable interrupts */534gen_enable_intr(sc);535WR4(sc, GENET_INTRL2_CPU_CLEAR_MASK,536GENET_IRQ_TXDMA_DONE | GENET_IRQ_RXDMA_DONE);537}538539static void540gen_disable_intr(struct gen_softc *sc)541{542/* Disable interrupts */543WR4(sc, GENET_INTRL2_CPU_SET_MASK, 0xffffffff);544WR4(sc, GENET_INTRL2_CPU_CLEAR_MASK, 0xffffffff);545}546547static void548gen_disable(struct gen_softc *sc)549{550uint32_t val;551552/* Stop receiver */553val = RD4(sc, GENET_UMAC_CMD);554val &= ~GENET_UMAC_CMD_RXEN;555WR4(sc, GENET_UMAC_CMD, val);556557/* Stop transmitter */558val = RD4(sc, GENET_UMAC_CMD);559val &= ~GENET_UMAC_CMD_TXEN;560WR4(sc, GENET_UMAC_CMD, val);561562/* Disable Interrupt */563gen_disable_intr(sc);564}565566static void567gen_enable_offload(struct gen_softc *sc)568{569uint32_t check_ctrl, buf_ctrl;570571check_ctrl = RD4(sc, GENET_RBUF_CHECK_CTRL);572buf_ctrl = RD4(sc, GENET_RBUF_CTRL);573if ((if_getcapenable(sc->ifp) & IFCAP_RXCSUM) != 0) {574check_ctrl |= GENET_RBUF_CHECK_CTRL_EN;575buf_ctrl |= GENET_RBUF_64B_EN;576} else {577check_ctrl &= ~GENET_RBUF_CHECK_CTRL_EN;578buf_ctrl &= ~GENET_RBUF_64B_EN;579}580WR4(sc, GENET_RBUF_CHECK_CTRL, check_ctrl);581WR4(sc, GENET_RBUF_CTRL, buf_ctrl);582583buf_ctrl = RD4(sc, GENET_TBUF_CTRL);584if ((if_getcapenable(sc->ifp) & (IFCAP_TXCSUM | IFCAP_TXCSUM_IPV6)) !=5850)586buf_ctrl |= GENET_RBUF_64B_EN;587else588buf_ctrl &= ~GENET_RBUF_64B_EN;589WR4(sc, GENET_TBUF_CTRL, buf_ctrl);590}591592static void593gen_dma_disable(struct gen_softc *sc)594{595int val;596597val = RD4(sc, GENET_TX_DMA_CTRL);598val &= ~GENET_TX_DMA_CTRL_EN;599val &= ~GENET_TX_DMA_CTRL_RBUF_EN(GENET_DMA_DEFAULT_QUEUE);600WR4(sc, GENET_TX_DMA_CTRL, val);601602val = RD4(sc, GENET_RX_DMA_CTRL);603val &= ~GENET_RX_DMA_CTRL_EN;604val &= ~GENET_RX_DMA_CTRL_RBUF_EN(GENET_DMA_DEFAULT_QUEUE);605WR4(sc, GENET_RX_DMA_CTRL, val);606}607608static int609gen_bus_dma_init(struct gen_softc *sc)610{611device_t dev = sc->dev;612int i, error;613614error = bus_dma_tag_create(615bus_get_dma_tag(dev), /* Parent tag */6164, 0, /* alignment, boundary */617BUS_SPACE_MAXADDR_40BIT, /* lowaddr */618BUS_SPACE_MAXADDR, /* highaddr */619NULL, NULL, /* filter, filterarg */620MCLBYTES, TX_MAX_SEGS, /* maxsize, nsegs */621MCLBYTES, /* maxsegsize */6220, /* flags */623NULL, NULL, /* lockfunc, lockarg */624&sc->tx_buf_tag);625if (error != 0) {626device_printf(dev, "cannot create TX buffer tag\n");627return (error);628}629630for (i = 0; i < TX_DESC_COUNT; i++) {631error = bus_dmamap_create(sc->tx_buf_tag, 0,632&sc->tx_ring_ent[i].map);633if (error != 0) {634device_printf(dev, "cannot create TX buffer map\n");635return (error);636}637}638639error = bus_dma_tag_create(640bus_get_dma_tag(dev), /* Parent tag */6414, 0, /* alignment, boundary */642BUS_SPACE_MAXADDR_40BIT, /* lowaddr */643BUS_SPACE_MAXADDR, /* highaddr */644NULL, NULL, /* filter, filterarg */645MCLBYTES, 1, /* maxsize, nsegs */646MCLBYTES, /* maxsegsize */6470, /* flags */648NULL, NULL, /* lockfunc, lockarg */649&sc->rx_buf_tag);650if (error != 0) {651device_printf(dev, "cannot create RX buffer tag\n");652return (error);653}654655for (i = 0; i < RX_DESC_COUNT; i++) {656error = bus_dmamap_create(sc->rx_buf_tag, 0,657&sc->rx_ring_ent[i].map);658if (error != 0) {659device_printf(dev, "cannot create RX buffer map\n");660return (error);661}662}663return (0);664}665666static void667gen_bus_dma_teardown(struct gen_softc *sc)668{669int i, error;670671if (sc->tx_buf_tag != NULL) {672for (i = 0; i < TX_DESC_COUNT; i++) {673error = bus_dmamap_destroy(sc->tx_buf_tag,674sc->tx_ring_ent[i].map);675sc->tx_ring_ent[i].map = NULL;676if (error)677device_printf(sc->dev,678"%s: bus_dmamap_destroy failed: %d\n",679__func__, error);680}681error = bus_dma_tag_destroy(sc->tx_buf_tag);682sc->tx_buf_tag = NULL;683if (error)684device_printf(sc->dev,685"%s: bus_dma_tag_destroy failed: %d\n", __func__,686error);687}688689if (sc->rx_buf_tag != NULL) {690for (i = 0; i < RX_DESC_COUNT; i++) {691error = bus_dmamap_destroy(sc->rx_buf_tag,692sc->rx_ring_ent[i].map);693sc->rx_ring_ent[i].map = NULL;694if (error)695device_printf(sc->dev,696"%s: bus_dmamap_destroy failed: %d\n",697__func__, error);698}699error = bus_dma_tag_destroy(sc->rx_buf_tag);700sc->rx_buf_tag = NULL;701if (error)702device_printf(sc->dev,703"%s: bus_dma_tag_destroy failed: %d\n", __func__,704error);705}706}707708static void709gen_enable_intr(struct gen_softc *sc)710{711712WR4(sc, GENET_INTRL2_CPU_CLEAR_MASK,713GENET_IRQ_TXDMA_DONE | GENET_IRQ_RXDMA_DONE);714}715716/*717* "queue" is the software queue index (0-4); "qid" is the hardware index718* (0-16). "base" is the starting index in the ring array.719*/720static void721gen_init_txring(struct gen_softc *sc, int queue, int qid, int base,722int nentries)723{724struct tx_queue *q;725uint32_t val;726727q = &sc->tx_queue[queue];728q->entries = &sc->tx_ring_ent[base];729q->hwindex = qid;730q->nentries = nentries;731732/* TX ring */733734q->queued = 0;735q->cons_idx = q->prod_idx = 0;736737WR4(sc, GENET_TX_SCB_BURST_SIZE, 0x08);738739WR4(sc, GENET_TX_DMA_READ_PTR_LO(qid), 0);740WR4(sc, GENET_TX_DMA_READ_PTR_HI(qid), 0);741WR4(sc, GENET_TX_DMA_CONS_INDEX(qid), 0);742WR4(sc, GENET_TX_DMA_PROD_INDEX(qid), 0);743WR4(sc, GENET_TX_DMA_RING_BUF_SIZE(qid),744(nentries << GENET_TX_DMA_RING_BUF_SIZE_DESC_SHIFT) |745(MCLBYTES & GENET_TX_DMA_RING_BUF_SIZE_BUF_LEN_MASK));746WR4(sc, GENET_TX_DMA_START_ADDR_LO(qid), 0);747WR4(sc, GENET_TX_DMA_START_ADDR_HI(qid), 0);748WR4(sc, GENET_TX_DMA_END_ADDR_LO(qid),749TX_DESC_COUNT * GENET_DMA_DESC_SIZE / 4 - 1);750WR4(sc, GENET_TX_DMA_END_ADDR_HI(qid), 0);751WR4(sc, GENET_TX_DMA_MBUF_DONE_THRES(qid), 1);752WR4(sc, GENET_TX_DMA_FLOW_PERIOD(qid), 0);753WR4(sc, GENET_TX_DMA_WRITE_PTR_LO(qid), 0);754WR4(sc, GENET_TX_DMA_WRITE_PTR_HI(qid), 0);755756WR4(sc, GENET_TX_DMA_RING_CFG, __BIT(qid)); /* enable */757758/* Enable transmit DMA */759val = RD4(sc, GENET_TX_DMA_CTRL);760val |= GENET_TX_DMA_CTRL_EN;761val |= GENET_TX_DMA_CTRL_RBUF_EN(qid);762WR4(sc, GENET_TX_DMA_CTRL, val);763}764765/*766* "queue" is the software queue index (0-4); "qid" is the hardware index767* (0-16). "base" is the starting index in the ring array.768*/769static void770gen_init_rxring(struct gen_softc *sc, int queue, int qid, int base,771int nentries)772{773struct rx_queue *q;774uint32_t val;775int i;776777q = &sc->rx_queue[queue];778q->entries = &sc->rx_ring_ent[base];779q->hwindex = qid;780q->nentries = nentries;781q->cons_idx = q->prod_idx = 0;782783WR4(sc, GENET_RX_SCB_BURST_SIZE, 0x08);784785WR4(sc, GENET_RX_DMA_WRITE_PTR_LO(qid), 0);786WR4(sc, GENET_RX_DMA_WRITE_PTR_HI(qid), 0);787WR4(sc, GENET_RX_DMA_PROD_INDEX(qid), 0);788WR4(sc, GENET_RX_DMA_CONS_INDEX(qid), 0);789WR4(sc, GENET_RX_DMA_RING_BUF_SIZE(qid),790(nentries << GENET_RX_DMA_RING_BUF_SIZE_DESC_SHIFT) |791(MCLBYTES & GENET_RX_DMA_RING_BUF_SIZE_BUF_LEN_MASK));792WR4(sc, GENET_RX_DMA_START_ADDR_LO(qid), 0);793WR4(sc, GENET_RX_DMA_START_ADDR_HI(qid), 0);794WR4(sc, GENET_RX_DMA_END_ADDR_LO(qid),795RX_DESC_COUNT * GENET_DMA_DESC_SIZE / 4 - 1);796WR4(sc, GENET_RX_DMA_END_ADDR_HI(qid), 0);797WR4(sc, GENET_RX_DMA_XON_XOFF_THRES(qid),798(5 << GENET_RX_DMA_XON_XOFF_THRES_LO_SHIFT) | (RX_DESC_COUNT >> 4));799WR4(sc, GENET_RX_DMA_READ_PTR_LO(qid), 0);800WR4(sc, GENET_RX_DMA_READ_PTR_HI(qid), 0);801802WR4(sc, GENET_RX_DMA_RING_CFG, __BIT(qid)); /* enable */803804/* fill ring */805for (i = 0; i < RX_DESC_COUNT; i++)806gen_newbuf_rx(sc, &sc->rx_queue[DEF_RXQUEUE], i);807808/* Enable receive DMA */809val = RD4(sc, GENET_RX_DMA_CTRL);810val |= GENET_RX_DMA_CTRL_EN;811val |= GENET_RX_DMA_CTRL_RBUF_EN(qid);812WR4(sc, GENET_RX_DMA_CTRL, val);813}814815static void816gen_init_txrings(struct gen_softc *sc)817{818int base = 0;819#ifdef PRI_RINGS820int i;821822/* init priority rings */823for (i = 0; i < PRI_RINGS; i++) {824gen_init_txring(sc, i, i, base, TX_DESC_PRICOUNT);825sc->tx_queue[i].queue = i;826base += TX_DESC_PRICOUNT;827dma_ring_conf |= 1 << i;828dma_control |= DMA_RENABLE(i);829}830#endif831832/* init GENET_DMA_DEFAULT_QUEUE (16) */833gen_init_txring(sc, DEF_TXQUEUE, GENET_DMA_DEFAULT_QUEUE, base,834TX_DESC_COUNT);835sc->tx_queue[DEF_TXQUEUE].hwindex = GENET_DMA_DEFAULT_QUEUE;836}837838static void839gen_init_rxrings(struct gen_softc *sc)840{841int base = 0;842#ifdef PRI_RINGS843int i;844845/* init priority rings */846for (i = 0; i < PRI_RINGS; i++) {847gen_init_rxring(sc, i, i, base, TX_DESC_PRICOUNT);848sc->rx_queue[i].queue = i;849base += TX_DESC_PRICOUNT;850dma_ring_conf |= 1 << i;851dma_control |= DMA_RENABLE(i);852}853#endif854855/* init GENET_DMA_DEFAULT_QUEUE (16) */856gen_init_rxring(sc, DEF_RXQUEUE, GENET_DMA_DEFAULT_QUEUE, base,857RX_DESC_COUNT);858sc->rx_queue[DEF_RXQUEUE].hwindex = GENET_DMA_DEFAULT_QUEUE;859860}861862static void863gen_stop(struct gen_softc *sc)864{865int i;866struct gen_ring_ent *ent;867868GEN_ASSERT_LOCKED(sc);869870callout_stop(&sc->stat_ch);871if_setdrvflagbits(sc->ifp, 0, IFF_DRV_RUNNING);872gen_reset(sc);873gen_disable(sc);874gen_dma_disable(sc);875876/* Clear the tx/rx ring buffer */877for (i = 0; i < TX_DESC_COUNT; i++) {878ent = &sc->tx_ring_ent[i];879if (ent->mbuf != NULL) {880bus_dmamap_sync(sc->tx_buf_tag, ent->map,881BUS_DMASYNC_POSTWRITE);882bus_dmamap_unload(sc->tx_buf_tag, ent->map);883m_freem(ent->mbuf);884ent->mbuf = NULL;885}886}887888for (i = 0; i < RX_DESC_COUNT; i++) {889ent = &sc->rx_ring_ent[i];890if (ent->mbuf != NULL) {891bus_dmamap_sync(sc->rx_buf_tag, ent->map,892BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);893bus_dmamap_unload(sc->rx_buf_tag, ent->map);894m_freem(ent->mbuf);895ent->mbuf = NULL;896}897}898}899900static void901gen_init_locked(struct gen_softc *sc)902{903struct mii_data *mii;904if_t ifp;905906mii = device_get_softc(sc->miibus);907ifp = sc->ifp;908909GEN_ASSERT_LOCKED(sc);910911if (if_getdrvflags(ifp) & IFF_DRV_RUNNING)912return;913914switch (sc->phy_mode)915{916case MII_CONTYPE_RGMII:917case MII_CONTYPE_RGMII_ID:918case MII_CONTYPE_RGMII_RXID:919case MII_CONTYPE_RGMII_TXID:920WR4(sc, GENET_SYS_PORT_CTRL, GENET_SYS_PORT_MODE_EXT_GPHY);921break;922default:923WR4(sc, GENET_SYS_PORT_CTRL, 0);924}925926gen_set_enaddr(sc);927928/* Setup RX filter */929gen_setup_rxfilter(sc);930931gen_init_txrings(sc);932gen_init_rxrings(sc);933gen_enable(sc);934gen_enable_offload(sc);935936if_setdrvflagbits(ifp, IFF_DRV_RUNNING, IFF_DRV_OACTIVE);937938mii_mediachg(mii);939callout_reset(&sc->stat_ch, hz, gen_tick, sc);940}941942static void943gen_init(void *softc)944{945struct gen_softc *sc;946947sc = softc;948GEN_LOCK(sc);949gen_init_locked(sc);950GEN_UNLOCK(sc);951}952953static uint8_t ether_broadcastaddr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };954955static void956gen_setup_rxfilter_mdf(struct gen_softc *sc, u_int n, const uint8_t *ea)957{958uint32_t addr0 = (ea[0] << 8) | ea[1];959uint32_t addr1 = (ea[2] << 24) | (ea[3] << 16) | (ea[4] << 8) | ea[5];960961WR4(sc, GENET_UMAC_MDF_ADDR0(n), addr0);962WR4(sc, GENET_UMAC_MDF_ADDR1(n), addr1);963}964965static u_int966gen_setup_multi(void *arg, struct sockaddr_dl *sdl, u_int count)967{968struct gen_softc *sc = arg;969970/* "count + 2" to account for unicast and broadcast */971gen_setup_rxfilter_mdf(sc, count + 2, LLADDR(sdl));972return (1); /* increment to count */973}974975static void976gen_setup_rxfilter(struct gen_softc *sc)977{978if_t ifp = sc->ifp;979uint32_t cmd, mdf_ctrl;980u_int n;981982GEN_ASSERT_LOCKED(sc);983984cmd = RD4(sc, GENET_UMAC_CMD);985986/*987* Count the required number of hardware filters. We need one988* for each multicast address, plus one for our own address and989* the broadcast address.990*/991n = if_llmaddr_count(ifp) + 2;992993if (n > GENET_MAX_MDF_FILTER)994if_setflagbits(ifp, IFF_ALLMULTI, 0);995else996if_setflagbits(ifp, 0, IFF_ALLMULTI);997998if ((if_getflags(ifp) & (IFF_PROMISC|IFF_ALLMULTI)) != 0) {999cmd |= GENET_UMAC_CMD_PROMISC;1000mdf_ctrl = 0;1001} else {1002cmd &= ~GENET_UMAC_CMD_PROMISC;1003gen_setup_rxfilter_mdf(sc, 0, ether_broadcastaddr);1004gen_setup_rxfilter_mdf(sc, 1, if_getlladdr(ifp));1005(void) if_foreach_llmaddr(ifp, gen_setup_multi, sc);1006mdf_ctrl = (__BIT(GENET_MAX_MDF_FILTER) - 1) &~1007(__BIT(GENET_MAX_MDF_FILTER - n) - 1);1008}10091010WR4(sc, GENET_UMAC_CMD, cmd);1011WR4(sc, GENET_UMAC_MDF_CTRL, mdf_ctrl);1012}10131014static void1015gen_set_enaddr(struct gen_softc *sc)1016{1017uint8_t *enaddr;1018uint32_t val;1019if_t ifp;10201021GEN_ASSERT_LOCKED(sc);10221023ifp = sc->ifp;10241025/* Write our unicast address */1026enaddr = if_getlladdr(ifp);1027/* Write hardware address */1028val = enaddr[3] | (enaddr[2] << 8) | (enaddr[1] << 16) |1029(enaddr[0] << 24);1030WR4(sc, GENET_UMAC_MAC0, val);1031val = enaddr[5] | (enaddr[4] << 8);1032WR4(sc, GENET_UMAC_MAC1, val);1033}10341035static void1036gen_start_locked(struct gen_softc *sc)1037{1038struct mbuf *m;1039if_t ifp;1040int err;10411042GEN_ASSERT_LOCKED(sc);10431044if (!sc->link)1045return;10461047ifp = sc->ifp;10481049if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING|IFF_DRV_OACTIVE)) !=1050IFF_DRV_RUNNING)1051return;10521053while (true) {1054m = if_dequeue(ifp);1055if (m == NULL)1056break;10571058err = gen_encap(sc, &m);1059if (err != 0) {1060if (err == ENOBUFS)1061if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0);1062else if (m == NULL)1063if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);1064if (m != NULL)1065if_sendq_prepend(ifp, m);1066break;1067}1068bpf_mtap_if(ifp, m);1069}1070}10711072static void1073gen_start(if_t ifp)1074{1075struct gen_softc *sc;10761077sc = if_getsoftc(ifp);10781079GEN_LOCK(sc);1080gen_start_locked(sc);1081GEN_UNLOCK(sc);1082}10831084/* Test for any delayed checksum */1085#define CSUM_DELAY_ANY (CSUM_TCP | CSUM_UDP | CSUM_IP6_TCP | CSUM_IP6_UDP)10861087static int1088gen_encap(struct gen_softc *sc, struct mbuf **mp)1089{1090bus_dmamap_t map;1091bus_dma_segment_t segs[TX_MAX_SEGS];1092int error, nsegs, cur, first, i, index, offset;1093uint32_t csuminfo, length_status, csum_flags = 0, csumdata;1094struct mbuf *m;1095struct statusblock *sb = NULL;1096struct tx_queue *q;1097struct gen_ring_ent *ent;10981099GEN_ASSERT_LOCKED(sc);11001101q = &sc->tx_queue[DEF_TXQUEUE];1102if (q->queued == q->nentries) {1103/* tx_queue is full */1104return (ENOBUFS);1105}11061107m = *mp;11081109/*1110* Don't attempt to send packets with only an Ethernet header in1111* first mbuf; see comment above with gen_tx_hdr_min.1112*/1113if (m->m_len == sizeof(struct ether_header)) {1114m = m_pullup(m, MIN(m->m_pkthdr.len, gen_tx_hdr_min));1115if (m == NULL) {1116if (if_getflags(sc->ifp) & IFF_DEBUG)1117device_printf(sc->dev,1118"header pullup fail\n");1119*mp = NULL;1120return (ENOMEM);1121}1122}11231124if ((if_getcapenable(sc->ifp) & (IFCAP_TXCSUM | IFCAP_TXCSUM_IPV6)) !=11250) {1126csum_flags = m->m_pkthdr.csum_flags;1127csumdata = m->m_pkthdr.csum_data;1128M_PREPEND(m, sizeof(struct statusblock), M_NOWAIT);1129if (m == NULL) {1130if (if_getflags(sc->ifp) & IFF_DEBUG)1131device_printf(sc->dev, "prepend fail\n");1132*mp = NULL;1133return (ENOMEM);1134}1135offset = gen_parse_tx(m, csum_flags);1136sb = mtod(m, struct statusblock *);1137if ((csum_flags & CSUM_DELAY_ANY) != 0) {1138csuminfo = (offset << TXCSUM_OFF_SHIFT) |1139(offset + csumdata);1140csuminfo |= TXCSUM_LEN_VALID;1141if (csum_flags & (CSUM_UDP | CSUM_IP6_UDP))1142csuminfo |= TXCSUM_UDP;1143sb->txcsuminfo = csuminfo;1144} else1145sb->txcsuminfo = 0;1146}11471148*mp = m;11491150cur = first = q->cur;1151ent = &q->entries[cur];1152map = ent->map;1153error = bus_dmamap_load_mbuf_sg(sc->tx_buf_tag, map, m, segs,1154&nsegs, BUS_DMA_NOWAIT);1155if (error == EFBIG) {1156m = m_collapse(m, M_NOWAIT, TX_MAX_SEGS);1157if (m == NULL) {1158device_printf(sc->dev,1159"gen_encap: m_collapse failed\n");1160m_freem(*mp);1161*mp = NULL;1162return (ENOMEM);1163}1164*mp = m;1165error = bus_dmamap_load_mbuf_sg(sc->tx_buf_tag, map, m,1166segs, &nsegs, BUS_DMA_NOWAIT);1167if (error != 0) {1168m_freem(*mp);1169*mp = NULL;1170}1171}1172if (error != 0) {1173device_printf(sc->dev,1174"gen_encap: bus_dmamap_load_mbuf_sg failed\n");1175return (error);1176}1177if (nsegs == 0) {1178m_freem(*mp);1179*mp = NULL;1180return (EIO);1181}11821183/* Remove statusblock after mapping, before possible requeue or bpf. */1184if (sb != NULL) {1185m->m_data += sizeof(struct statusblock);1186m->m_len -= sizeof(struct statusblock);1187m->m_pkthdr.len -= sizeof(struct statusblock);1188}1189if (q->queued + nsegs > q->nentries) {1190bus_dmamap_unload(sc->tx_buf_tag, map);1191return (ENOBUFS);1192}11931194bus_dmamap_sync(sc->tx_buf_tag, map, BUS_DMASYNC_PREWRITE);11951196index = q->prod_idx & (q->nentries - 1);1197for (i = 0; i < nsegs; i++) {1198ent = &q->entries[cur];1199length_status = GENET_TX_DESC_STATUS_QTAG_MASK;1200if (i == 0) {1201length_status |= GENET_TX_DESC_STATUS_SOP |1202GENET_TX_DESC_STATUS_CRC;1203if ((csum_flags & CSUM_DELAY_ANY) != 0)1204length_status |= GENET_TX_DESC_STATUS_CKSUM;1205}1206if (i == nsegs - 1)1207length_status |= GENET_TX_DESC_STATUS_EOP;12081209length_status |= segs[i].ds_len <<1210GENET_TX_DESC_STATUS_BUFLEN_SHIFT;12111212WR4(sc, GENET_TX_DESC_ADDRESS_LO(index),1213(uint32_t)segs[i].ds_addr);1214WR4(sc, GENET_TX_DESC_ADDRESS_HI(index),1215(uint32_t)(segs[i].ds_addr >> 32));1216WR4(sc, GENET_TX_DESC_STATUS(index), length_status);12171218++q->queued;1219cur = TX_NEXT(cur, q->nentries);1220index = TX_NEXT(index, q->nentries);1221}12221223q->prod_idx += nsegs;1224q->prod_idx &= GENET_TX_DMA_PROD_CONS_MASK;1225/* We probably don't need to write the producer index on every iter */1226if (nsegs != 0)1227WR4(sc, GENET_TX_DMA_PROD_INDEX(q->hwindex), q->prod_idx);1228q->cur = cur;12291230/* Store mbuf in the last segment */1231q->entries[first].mbuf = m;12321233return (0);1234}12351236/*1237* Parse a packet to find the offset of the transport header for checksum1238* offload. Ensure that the link and network headers are contiguous with1239* the status block, or transmission fails.1240*/1241static int1242gen_parse_tx(struct mbuf *m, int csum_flags)1243{1244int offset, off_in_m;1245bool copy = false, shift = false;1246u_char *p, *copy_p = NULL;1247struct mbuf *m0 = m;1248uint16_t ether_type;12491250if (m->m_len == sizeof(struct statusblock)) {1251/* M_PREPEND placed statusblock at end; move to beginning */1252m->m_data = m->m_pktdat;1253copy_p = mtodo(m, sizeof(struct statusblock));1254m = m->m_next;1255off_in_m = 0;1256p = mtod(m, u_char *);1257copy = true;1258} else {1259/*1260* If statusblock is not at beginning of mbuf (likely),1261* then remember to move mbuf contents down before copying1262* after them.1263*/1264if ((m->m_flags & M_EXT) == 0 && m->m_data != m->m_pktdat)1265shift = true;1266p = mtodo(m, sizeof(struct statusblock));1267off_in_m = sizeof(struct statusblock);1268}12691270/*1271* If headers need to be copied contiguous to statusblock, do so.1272* If copying to the internal mbuf data area, and the status block1273* is not at the beginning of that area, shift the status block (which1274* is empty) and following data.1275*/1276#define COPY(size) { \1277int hsize = size; \1278if (copy) { \1279if (shift) { \1280u_char *p0; \1281shift = false; \1282p0 = mtodo(m0, sizeof(struct statusblock)); \1283m0->m_data = m0->m_pktdat; \1284bcopy(p0, mtodo(m0, sizeof(struct statusblock)),\1285m0->m_len - sizeof(struct statusblock)); \1286copy_p = mtodo(m0, m0->m_len); \1287} \1288bcopy(p, copy_p, hsize); \1289m0->m_len += hsize; \1290m->m_len -= hsize; \1291m->m_data += hsize; \1292} \1293copy_p += hsize; \1294}12951296KASSERT((sizeof(struct statusblock) + sizeof(struct ether_vlan_header) +1297sizeof(struct ip6_hdr) <= MLEN), ("%s: mbuf too small", __func__));12981299if (((struct ether_header *)p)->ether_type == htons(ETHERTYPE_VLAN)) {1300offset = sizeof(struct ether_vlan_header);1301ether_type = ntohs(((struct ether_vlan_header *)p)->evl_proto);1302COPY(sizeof(struct ether_vlan_header));1303if (m->m_len == off_in_m + sizeof(struct ether_vlan_header)) {1304m = m->m_next;1305off_in_m = 0;1306p = mtod(m, u_char *);1307copy = true;1308} else {1309off_in_m += sizeof(struct ether_vlan_header);1310p += sizeof(struct ether_vlan_header);1311}1312} else {1313offset = sizeof(struct ether_header);1314ether_type = ntohs(((struct ether_header *)p)->ether_type);1315COPY(sizeof(struct ether_header));1316if (m->m_len == off_in_m + sizeof(struct ether_header)) {1317m = m->m_next;1318off_in_m = 0;1319p = mtod(m, u_char *);1320copy = true;1321} else {1322off_in_m += sizeof(struct ether_header);1323p += sizeof(struct ether_header);1324}1325}1326if (ether_type == ETHERTYPE_IP) {1327COPY(((struct ip *)p)->ip_hl << 2);1328offset += ((struct ip *)p)->ip_hl << 2;1329} else if (ether_type == ETHERTYPE_IPV6) {1330COPY(sizeof(struct ip6_hdr));1331offset += sizeof(struct ip6_hdr);1332} else {1333/*1334* Unknown whether most other cases require moving a header;1335* ARP works without. However, Wake On LAN packets sent1336* by wake(8) via BPF need something like this.1337*/1338COPY(MIN(gen_tx_hdr_min, m->m_len));1339offset += MIN(gen_tx_hdr_min, m->m_len);1340}1341return (offset);1342#undef COPY1343}13441345static void1346gen_intr(void *arg)1347{1348struct gen_softc *sc = arg;1349uint32_t val;13501351GEN_LOCK(sc);13521353val = RD4(sc, GENET_INTRL2_CPU_STAT);1354val &= ~RD4(sc, GENET_INTRL2_CPU_STAT_MASK);1355WR4(sc, GENET_INTRL2_CPU_CLEAR, val);13561357if (val & GENET_IRQ_RXDMA_DONE)1358gen_rxintr(sc, &sc->rx_queue[DEF_RXQUEUE]);13591360if (val & GENET_IRQ_TXDMA_DONE) {1361gen_txintr(sc, &sc->tx_queue[DEF_TXQUEUE]);1362if (!if_sendq_empty(sc->ifp))1363gen_start_locked(sc);1364}13651366GEN_UNLOCK(sc);1367}13681369static int1370gen_rxintr(struct gen_softc *sc, struct rx_queue *q)1371{1372if_t ifp;1373struct mbuf *m, *mh, *mt;1374struct statusblock *sb = NULL;1375int error, index, len, cnt, npkt, n;1376uint32_t status, prod_idx, total;13771378ifp = sc->ifp;1379mh = mt = NULL;1380cnt = 0;1381npkt = 0;13821383prod_idx = RD4(sc, GENET_RX_DMA_PROD_INDEX(q->hwindex)) &1384GENET_RX_DMA_PROD_CONS_MASK;1385total = (prod_idx - q->cons_idx) & GENET_RX_DMA_PROD_CONS_MASK;13861387index = q->cons_idx & (RX_DESC_COUNT - 1);1388for (n = 0; n < total; n++) {1389bus_dmamap_sync(sc->rx_buf_tag, q->entries[index].map,1390BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);1391bus_dmamap_unload(sc->rx_buf_tag, q->entries[index].map);13921393m = q->entries[index].mbuf;13941395if ((if_getcapenable(ifp) & IFCAP_RXCSUM) != 0) {1396sb = mtod(m, struct statusblock *);1397status = sb->status_buflen;1398} else1399status = RD4(sc, GENET_RX_DESC_STATUS(index));14001401len = (status & GENET_RX_DESC_STATUS_BUFLEN_MASK) >>1402GENET_RX_DESC_STATUS_BUFLEN_SHIFT;14031404/* check for errors */1405if ((status &1406(GENET_RX_DESC_STATUS_SOP | GENET_RX_DESC_STATUS_EOP |1407GENET_RX_DESC_STATUS_RX_ERROR)) !=1408(GENET_RX_DESC_STATUS_SOP | GENET_RX_DESC_STATUS_EOP)) {1409if (if_getflags(ifp) & IFF_DEBUG)1410device_printf(sc->dev,1411"error/frag %x csum %x\n", status,1412sb->rxcsum);1413if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);1414continue;1415}14161417error = gen_newbuf_rx(sc, q, index);1418if (error != 0) {1419if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);1420if (if_getflags(ifp) & IFF_DEBUG)1421device_printf(sc->dev, "gen_newbuf_rx %d\n",1422error);1423/* reuse previous mbuf */1424(void) gen_mapbuf_rx(sc, q, index, m);1425continue;1426}14271428if (sb != NULL) {1429if (status & GENET_RX_DESC_STATUS_CKSUM_OK) {1430/* L4 checksum checked; not sure about L3. */1431m->m_pkthdr.csum_flags = CSUM_DATA_VALID |1432CSUM_PSEUDO_HDR;1433m->m_pkthdr.csum_data = 0xffff;1434}1435m->m_data += sizeof(struct statusblock);1436m->m_len -= sizeof(struct statusblock);1437len -= sizeof(struct statusblock);1438}1439if (len > ETHER_ALIGN) {1440m_adj(m, ETHER_ALIGN);1441len -= ETHER_ALIGN;1442}14431444m->m_pkthdr.rcvif = ifp;1445m->m_pkthdr.len = len;1446m->m_len = len;1447if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);14481449m->m_nextpkt = NULL;1450if (mh == NULL)1451mh = m;1452else1453mt->m_nextpkt = m;1454mt = m;1455++cnt;1456++npkt;14571458index = RX_NEXT(index, q->nentries);14591460q->cons_idx = (q->cons_idx + 1) & GENET_RX_DMA_PROD_CONS_MASK;1461WR4(sc, GENET_RX_DMA_CONS_INDEX(q->hwindex), q->cons_idx);14621463if (cnt == gen_rx_batch) {1464GEN_UNLOCK(sc);1465if_input(ifp, mh);1466GEN_LOCK(sc);1467mh = mt = NULL;1468cnt = 0;1469}1470}14711472if (mh != NULL) {1473GEN_UNLOCK(sc);1474if_input(ifp, mh);1475GEN_LOCK(sc);1476}14771478return (npkt);1479}14801481static void1482gen_txintr(struct gen_softc *sc, struct tx_queue *q)1483{1484uint32_t cons_idx, total;1485struct gen_ring_ent *ent;1486if_t ifp;1487int i, prog;14881489GEN_ASSERT_LOCKED(sc);14901491ifp = sc->ifp;14921493cons_idx = RD4(sc, GENET_TX_DMA_CONS_INDEX(q->hwindex)) &1494GENET_TX_DMA_PROD_CONS_MASK;1495total = (cons_idx - q->cons_idx) & GENET_TX_DMA_PROD_CONS_MASK;14961497prog = 0;1498for (i = q->next; q->queued > 0 && total > 0;1499i = TX_NEXT(i, q->nentries), total--) {1500/* XXX check for errors */15011502ent = &q->entries[i];1503if (ent->mbuf != NULL) {1504bus_dmamap_sync(sc->tx_buf_tag, ent->map,1505BUS_DMASYNC_POSTWRITE);1506bus_dmamap_unload(sc->tx_buf_tag, ent->map);1507m_freem(ent->mbuf);1508ent->mbuf = NULL;1509if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);1510}15111512prog++;1513--q->queued;1514}15151516if (prog > 0) {1517q->next = i;1518if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE);1519}15201521q->cons_idx = cons_idx;1522}15231524static void1525gen_intr2(void *arg)1526{1527struct gen_softc *sc = arg;15281529device_printf(sc->dev, "gen_intr2\n");1530}15311532static int1533gen_newbuf_rx(struct gen_softc *sc, struct rx_queue *q, int index)1534{1535struct mbuf *m;15361537m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);1538if (m == NULL)1539return (ENOBUFS);15401541m->m_pkthdr.len = m->m_len = m->m_ext.ext_size;1542m_adj(m, ETHER_ALIGN);15431544return (gen_mapbuf_rx(sc, q, index, m));1545}15461547static int1548gen_mapbuf_rx(struct gen_softc *sc, struct rx_queue *q, int index,1549struct mbuf *m)1550{1551bus_dma_segment_t seg;1552bus_dmamap_t map;1553int nsegs;15541555map = q->entries[index].map;1556if (bus_dmamap_load_mbuf_sg(sc->rx_buf_tag, map, m, &seg, &nsegs,1557BUS_DMA_NOWAIT) != 0) {1558m_freem(m);1559return (ENOBUFS);1560}15611562bus_dmamap_sync(sc->rx_buf_tag, map, BUS_DMASYNC_PREREAD);15631564q->entries[index].mbuf = m;1565WR4(sc, GENET_RX_DESC_ADDRESS_LO(index), (uint32_t)seg.ds_addr);1566WR4(sc, GENET_RX_DESC_ADDRESS_HI(index), (uint32_t)(seg.ds_addr >> 32));15671568return (0);1569}15701571static int1572gen_ioctl(if_t ifp, u_long cmd, caddr_t data)1573{1574struct gen_softc *sc;1575struct mii_data *mii;1576struct ifreq *ifr;1577int flags, enable, error;15781579sc = if_getsoftc(ifp);1580mii = device_get_softc(sc->miibus);1581ifr = (struct ifreq *)data;1582error = 0;15831584switch (cmd) {1585case SIOCSIFFLAGS:1586GEN_LOCK(sc);1587if (if_getflags(ifp) & IFF_UP) {1588if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {1589flags = if_getflags(ifp) ^ sc->if_flags;1590if ((flags & (IFF_PROMISC|IFF_ALLMULTI)) != 0)1591gen_setup_rxfilter(sc);1592} else1593gen_init_locked(sc);1594} else {1595if (if_getdrvflags(ifp) & IFF_DRV_RUNNING)1596gen_stop(sc);1597}1598sc->if_flags = if_getflags(ifp);1599GEN_UNLOCK(sc);1600break;16011602case SIOCADDMULTI:1603case SIOCDELMULTI:1604if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {1605GEN_LOCK(sc);1606gen_setup_rxfilter(sc);1607GEN_UNLOCK(sc);1608}1609break;16101611case SIOCSIFMEDIA:1612case SIOCGIFMEDIA:1613error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd);1614break;16151616case SIOCSIFCAP:1617enable = if_getcapenable(ifp);1618flags = ifr->ifr_reqcap ^ enable;1619if (flags & IFCAP_RXCSUM)1620enable ^= IFCAP_RXCSUM;1621if (flags & IFCAP_RXCSUM_IPV6)1622enable ^= IFCAP_RXCSUM_IPV6;1623if (flags & IFCAP_TXCSUM)1624enable ^= IFCAP_TXCSUM;1625if (flags & IFCAP_TXCSUM_IPV6)1626enable ^= IFCAP_TXCSUM_IPV6;1627if (enable & (IFCAP_TXCSUM | IFCAP_TXCSUM_IPV6))1628if_sethwassist(ifp, GEN_CSUM_FEATURES);1629else1630if_sethwassist(ifp, 0);1631if_setcapenable(ifp, enable);1632if (if_getdrvflags(ifp) & IFF_DRV_RUNNING)1633gen_enable_offload(sc);1634break;16351636default:1637error = ether_ioctl(ifp, cmd, data);1638break;1639}1640return (error);1641}16421643static void1644gen_tick(void *softc)1645{1646struct gen_softc *sc;1647struct mii_data *mii;1648if_t ifp;1649int link;16501651sc = softc;1652ifp = sc->ifp;1653mii = device_get_softc(sc->miibus);16541655GEN_ASSERT_LOCKED(sc);16561657if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0)1658return;16591660link = sc->link;1661mii_tick(mii);1662if (sc->link && !link)1663gen_start_locked(sc);16641665callout_reset(&sc->stat_ch, hz, gen_tick, sc);1666}16671668#define MII_BUSY_RETRY 100016691670static int1671gen_miibus_readreg(device_t dev, int phy, int reg)1672{1673struct gen_softc *sc;1674int retry, val;16751676sc = device_get_softc(dev);1677val = 0;16781679WR4(sc, GENET_MDIO_CMD, GENET_MDIO_READ |1680(phy << GENET_MDIO_ADDR_SHIFT) | (reg << GENET_MDIO_REG_SHIFT));1681val = RD4(sc, GENET_MDIO_CMD);1682WR4(sc, GENET_MDIO_CMD, val | GENET_MDIO_START_BUSY);1683for (retry = MII_BUSY_RETRY; retry > 0; retry--) {1684if (((val = RD4(sc, GENET_MDIO_CMD)) &1685GENET_MDIO_START_BUSY) == 0) {1686if (val & GENET_MDIO_READ_FAILED)1687return (0); /* -1? */1688val &= GENET_MDIO_VAL_MASK;1689break;1690}1691DELAY(10);1692}16931694if (retry == 0)1695device_printf(dev, "phy read timeout, phy=%d reg=%d\n",1696phy, reg);16971698return (val);1699}17001701static int1702gen_miibus_writereg(device_t dev, int phy, int reg, int val)1703{1704struct gen_softc *sc;1705int retry;17061707sc = device_get_softc(dev);17081709WR4(sc, GENET_MDIO_CMD, GENET_MDIO_WRITE |1710(phy << GENET_MDIO_ADDR_SHIFT) | (reg << GENET_MDIO_REG_SHIFT) |1711(val & GENET_MDIO_VAL_MASK));1712val = RD4(sc, GENET_MDIO_CMD);1713WR4(sc, GENET_MDIO_CMD, val | GENET_MDIO_START_BUSY);1714for (retry = MII_BUSY_RETRY; retry > 0; retry--) {1715val = RD4(sc, GENET_MDIO_CMD);1716if ((val & GENET_MDIO_START_BUSY) == 0)1717break;1718DELAY(10);1719}1720if (retry == 0)1721device_printf(dev, "phy write timeout, phy=%d reg=%d\n",1722phy, reg);17231724return (0);1725}17261727static void1728gen_update_link_locked(struct gen_softc *sc)1729{1730struct mii_data *mii;1731uint32_t val;1732u_int speed;17331734GEN_ASSERT_LOCKED(sc);17351736if ((if_getdrvflags(sc->ifp) & IFF_DRV_RUNNING) == 0)1737return;1738mii = device_get_softc(sc->miibus);17391740if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==1741(IFM_ACTIVE | IFM_AVALID)) {1742switch (IFM_SUBTYPE(mii->mii_media_active)) {1743case IFM_1000_T:1744case IFM_1000_SX:1745speed = GENET_UMAC_CMD_SPEED_1000;1746sc->link = 1;1747break;1748case IFM_100_TX:1749speed = GENET_UMAC_CMD_SPEED_100;1750sc->link = 1;1751break;1752case IFM_10_T:1753speed = GENET_UMAC_CMD_SPEED_10;1754sc->link = 1;1755break;1756default:1757sc->link = 0;1758break;1759}1760} else1761sc->link = 0;17621763if (sc->link == 0)1764return;17651766val = RD4(sc, GENET_EXT_RGMII_OOB_CTRL);1767val &= ~GENET_EXT_RGMII_OOB_OOB_DISABLE;1768val |= GENET_EXT_RGMII_OOB_RGMII_LINK;1769val |= GENET_EXT_RGMII_OOB_RGMII_MODE_EN;1770if (sc->phy_mode == MII_CONTYPE_RGMII)1771val |= GENET_EXT_RGMII_OOB_ID_MODE_DISABLE;1772else1773val &= ~GENET_EXT_RGMII_OOB_ID_MODE_DISABLE;1774WR4(sc, GENET_EXT_RGMII_OOB_CTRL, val);17751776val = RD4(sc, GENET_UMAC_CMD);1777val &= ~GENET_UMAC_CMD_SPEED;1778val |= speed;1779WR4(sc, GENET_UMAC_CMD, val);1780}17811782static void1783gen_link_task(void *arg, int pending)1784{1785struct gen_softc *sc;17861787sc = arg;17881789GEN_LOCK(sc);1790gen_update_link_locked(sc);1791GEN_UNLOCK(sc);1792}17931794static void1795gen_miibus_statchg(device_t dev)1796{1797struct gen_softc *sc;17981799sc = device_get_softc(dev);18001801taskqueue_enqueue(taskqueue_swi, &sc->link_task);1802}18031804static void1805gen_media_status(if_t ifp, struct ifmediareq *ifmr)1806{1807struct gen_softc *sc;1808struct mii_data *mii;18091810sc = if_getsoftc(ifp);1811mii = device_get_softc(sc->miibus);18121813GEN_LOCK(sc);1814mii_pollstat(mii);1815ifmr->ifm_active = mii->mii_media_active;1816ifmr->ifm_status = mii->mii_media_status;1817GEN_UNLOCK(sc);1818}18191820static int1821gen_media_change(if_t ifp)1822{1823struct gen_softc *sc;1824struct mii_data *mii;1825int error;18261827sc = if_getsoftc(ifp);1828mii = device_get_softc(sc->miibus);18291830GEN_LOCK(sc);1831error = mii_mediachg(mii);1832GEN_UNLOCK(sc);18331834return (error);1835}18361837static device_method_t gen_methods[] = {1838/* Device interface */1839DEVMETHOD(device_probe, gen_probe),1840DEVMETHOD(device_attach, gen_attach),1841DEVMETHOD(device_detach, gen_detach),18421843/* MII interface */1844DEVMETHOD(miibus_readreg, gen_miibus_readreg),1845DEVMETHOD(miibus_writereg, gen_miibus_writereg),1846DEVMETHOD(miibus_statchg, gen_miibus_statchg),18471848DEVMETHOD_END1849};18501851static driver_t gen_driver = {1852"genet",1853gen_methods,1854sizeof(struct gen_softc),1855};18561857DRIVER_MODULE(genet, simplebus, gen_driver, 0, 0);1858DRIVER_MODULE(miibus, genet, miibus_driver, 0, 0);1859MODULE_DEPEND(genet, ether, 1, 1, 1);1860MODULE_DEPEND(genet, miibus, 1, 1, 1);186118621863