1256778Snwhitehorn/*-
2256778Snwhitehorn * Copyright 2013 Nathan Whitehorn
3256778Snwhitehorn * All rights reserved.
4256778Snwhitehorn *
5256778Snwhitehorn * Redistribution and use in source and binary forms, with or without
6256778Snwhitehorn * modification, are permitted provided that the following conditions
7256778Snwhitehorn * are met:
8256778Snwhitehorn * 1. Redistributions of source code must retain the above copyright
9256778Snwhitehorn *    notice, this list of conditions and the following disclaimer.
10256778Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright
11256778Snwhitehorn *    notice, this list of conditions and the following disclaimer in the
12256778Snwhitehorn *    documentation and/or other materials provided with the distribution.
13256778Snwhitehorn *
14256778Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15256778Snwhitehorn * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16256778Snwhitehorn * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17256778Snwhitehorn * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18256778Snwhitehorn * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19256778Snwhitehorn * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20256778Snwhitehorn * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21256778Snwhitehorn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22256778Snwhitehorn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23256778Snwhitehorn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24256778Snwhitehorn * SUCH DAMAGE.
25256778Snwhitehorn */
26256778Snwhitehorn
27256778Snwhitehorn#include <sys/cdefs.h>
28256778Snwhitehorn__FBSDID("$FreeBSD: releng/10.2/sys/powerpc/pseries/phyp_llan.c 257292 2013-10-28 23:47:52Z nwhitehorn $");
29256778Snwhitehorn
30256778Snwhitehorn#include <sys/param.h>
31256778Snwhitehorn#include <sys/systm.h>
32256778Snwhitehorn#include <sys/sockio.h>
33256778Snwhitehorn#include <sys/endian.h>
34256778Snwhitehorn#include <sys/mbuf.h>
35256778Snwhitehorn#include <sys/module.h>
36256778Snwhitehorn#include <sys/malloc.h>
37256778Snwhitehorn#include <sys/kernel.h>
38256778Snwhitehorn#include <sys/socket.h>
39256778Snwhitehorn
40256778Snwhitehorn#include <net/bpf.h>
41256778Snwhitehorn#include <net/if.h>
42256778Snwhitehorn#include <net/if_arp.h>
43256778Snwhitehorn#include <net/ethernet.h>
44256778Snwhitehorn#include <net/if_dl.h>
45256778Snwhitehorn#include <net/if_media.h>
46256778Snwhitehorn#include <net/if_types.h>
47256778Snwhitehorn#include <net/if_vlan_var.h>
48256778Snwhitehorn
49256778Snwhitehorn#include <dev/ofw/openfirm.h>
50256778Snwhitehorn#include <dev/ofw/ofw_bus.h>
51256778Snwhitehorn#include <dev/ofw/ofw_bus_subr.h>
52256778Snwhitehorn#include <machine/bus.h>
53256778Snwhitehorn#include <machine/resource.h>
54256778Snwhitehorn#include <sys/bus.h>
55256778Snwhitehorn#include <sys/rman.h>
56256778Snwhitehorn
57256778Snwhitehorn#include <powerpc/pseries/phyp-hvcall.h>
58256778Snwhitehorn
59256778Snwhitehorn#define LLAN_MAX_RX_PACKETS	100
60256778Snwhitehorn#define LLAN_MAX_TX_PACKETS	100
61256778Snwhitehorn#define LLAN_RX_BUF_LEN		8*PAGE_SIZE
62256778Snwhitehorn
63257292Snwhitehorn#define LLAN_BUFDESC_VALID	(1ULL << 63)
64257292Snwhitehorn#define LLAN_ADD_MULTICAST	0x1
65257292Snwhitehorn#define LLAN_DEL_MULTICAST	0x2
66257292Snwhitehorn#define LLAN_CLEAR_MULTICAST	0x3
67257292Snwhitehorn
68256778Snwhitehornstruct llan_xfer {
69256778Snwhitehorn	struct mbuf *rx_mbuf;
70256778Snwhitehorn	bus_dmamap_t rx_dmamap;
71256778Snwhitehorn	uint64_t rx_bufdesc;
72256778Snwhitehorn};
73256778Snwhitehorn
74256778Snwhitehornstruct llan_receive_queue_entry { /* PAPR page 539 */
75256778Snwhitehorn	uint8_t control;
76256778Snwhitehorn	uint8_t reserved;
77256778Snwhitehorn	uint16_t offset;
78256778Snwhitehorn	uint32_t length;
79256778Snwhitehorn	uint64_t handle;
80256778Snwhitehorn} __packed;
81256778Snwhitehorn
82256778Snwhitehornstruct llan_softc {
83256778Snwhitehorn	device_t	dev;
84256778Snwhitehorn	struct mtx	io_lock;
85256778Snwhitehorn
86256778Snwhitehorn	cell_t		unit;
87256778Snwhitehorn	uint8_t		mac_address[8];
88256778Snwhitehorn
89256778Snwhitehorn	int		irqid;
90256778Snwhitehorn	struct resource	*irq;
91256778Snwhitehorn	void		*irq_cookie;
92256778Snwhitehorn
93256778Snwhitehorn	bus_dma_tag_t	rx_dma_tag;
94256778Snwhitehorn	bus_dma_tag_t	rxbuf_dma_tag;
95256778Snwhitehorn	bus_dma_tag_t	tx_dma_tag;
96256778Snwhitehorn
97256778Snwhitehorn	bus_dmamap_t	tx_dma_map;
98256778Snwhitehorn
99256778Snwhitehorn	struct llan_receive_queue_entry *rx_buf;
100256778Snwhitehorn	int		rx_dma_slot;
101256778Snwhitehorn	int		rx_valid_val;
102256778Snwhitehorn	bus_dmamap_t	rx_buf_map;
103256778Snwhitehorn	bus_addr_t	rx_buf_phys;
104256778Snwhitehorn	bus_size_t	rx_buf_len;
105256778Snwhitehorn	bus_addr_t	input_buf_phys;
106256778Snwhitehorn	bus_addr_t	filter_buf_phys;
107256778Snwhitehorn	struct llan_xfer rx_xfer[LLAN_MAX_RX_PACKETS];
108256778Snwhitehorn
109256778Snwhitehorn	struct ifnet	*ifp;
110256778Snwhitehorn};
111256778Snwhitehorn
112256778Snwhitehornstatic int	llan_probe(device_t);
113256778Snwhitehornstatic int	llan_attach(device_t);
114256778Snwhitehornstatic void	llan_intr(void *xsc);
115256778Snwhitehornstatic void	llan_init(void *xsc);
116256778Snwhitehornstatic void	llan_start(struct ifnet *ifp);
117256778Snwhitehornstatic int	llan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
118256778Snwhitehornstatic void	llan_rx_load_cb(void *xsc, bus_dma_segment_t *segs, int nsegs,
119256778Snwhitehorn		    int err);
120256778Snwhitehornstatic int	llan_add_rxbuf(struct llan_softc *sc, struct llan_xfer *rx);
121257292Snwhitehornstatic int	llan_set_multicast(struct llan_softc *sc);
122256778Snwhitehorn
123256778Snwhitehornstatic devclass_t       llan_devclass;
124256778Snwhitehornstatic device_method_t  llan_methods[] = {
125256778Snwhitehorn        DEVMETHOD(device_probe,         llan_probe),
126256778Snwhitehorn        DEVMETHOD(device_attach,        llan_attach),
127256778Snwhitehorn
128256778Snwhitehorn        DEVMETHOD_END
129256778Snwhitehorn};
130256778Snwhitehornstatic driver_t llan_driver = {
131256778Snwhitehorn        "llan",
132256778Snwhitehorn        llan_methods,
133256778Snwhitehorn        sizeof(struct llan_softc)
134256778Snwhitehorn};
135256778SnwhitehornDRIVER_MODULE(llan, vdevice, llan_driver, llan_devclass, 0, 0);
136256778Snwhitehorn
137256778Snwhitehornstatic int
138256778Snwhitehornllan_probe(device_t dev)
139256778Snwhitehorn{
140256778Snwhitehorn	if (!ofw_bus_is_compatible(dev,"IBM,l-lan"))
141256778Snwhitehorn		return (ENXIO);
142256778Snwhitehorn
143256778Snwhitehorn	device_set_desc(dev, "POWER Hypervisor Virtual Ethernet");
144256778Snwhitehorn	return (0);
145256778Snwhitehorn}
146256778Snwhitehorn
147256778Snwhitehornstatic int
148256778Snwhitehornllan_attach(device_t dev)
149256778Snwhitehorn{
150256778Snwhitehorn	struct llan_softc *sc;
151256778Snwhitehorn	phandle_t node;
152256778Snwhitehorn	int error, i;
153256778Snwhitehorn
154256778Snwhitehorn	sc = device_get_softc(dev);
155256778Snwhitehorn	sc->dev = dev;
156256778Snwhitehorn
157256778Snwhitehorn	/* Get firmware properties */
158256778Snwhitehorn	node = ofw_bus_get_node(dev);
159256778Snwhitehorn	OF_getprop(node, "local-mac-address", sc->mac_address,
160256778Snwhitehorn	    sizeof(sc->mac_address));
161256778Snwhitehorn	OF_getprop(node, "reg", &sc->unit, sizeof(sc->unit));
162256778Snwhitehorn
163256778Snwhitehorn	mtx_init(&sc->io_lock, "llan", NULL, MTX_DEF);
164256778Snwhitehorn
165256778Snwhitehorn        /* Setup interrupt */
166256778Snwhitehorn	sc->irqid = 0;
167256778Snwhitehorn	sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqid,
168256778Snwhitehorn	    RF_ACTIVE);
169256778Snwhitehorn
170256778Snwhitehorn	if (!sc->irq) {
171256778Snwhitehorn		device_printf(dev, "Could not allocate IRQ\n");
172256778Snwhitehorn		mtx_destroy(&sc->io_lock);
173256778Snwhitehorn		return (ENXIO);
174256778Snwhitehorn	}
175256778Snwhitehorn
176256778Snwhitehorn	bus_setup_intr(dev, sc->irq, INTR_TYPE_MISC | INTR_MPSAFE |
177256778Snwhitehorn	    INTR_ENTROPY, NULL, llan_intr, sc, &sc->irq_cookie);
178256778Snwhitehorn
179256778Snwhitehorn	/* Setup DMA */
180256778Snwhitehorn	error = bus_dma_tag_create(bus_get_dma_tag(dev), 16, 0,
181256778Snwhitehorn            BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
182256778Snwhitehorn	    LLAN_RX_BUF_LEN, 1, BUS_SPACE_MAXSIZE_32BIT,
183256778Snwhitehorn	    0, NULL, NULL, &sc->rx_dma_tag);
184256778Snwhitehorn	error = bus_dma_tag_create(bus_get_dma_tag(dev), 4, 0,
185256778Snwhitehorn            BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
186256778Snwhitehorn	    BUS_SPACE_MAXSIZE, 1, BUS_SPACE_MAXSIZE_32BIT,
187256778Snwhitehorn	    0, NULL, NULL, &sc->rxbuf_dma_tag);
188256778Snwhitehorn	error = bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0,
189256778Snwhitehorn            BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
190256778Snwhitehorn	    BUS_SPACE_MAXSIZE, 6, BUS_SPACE_MAXSIZE_32BIT, 0,
191256778Snwhitehorn	    busdma_lock_mutex, &sc->io_lock, &sc->tx_dma_tag);
192256778Snwhitehorn
193256778Snwhitehorn	error = bus_dmamem_alloc(sc->rx_dma_tag, (void **)&sc->rx_buf,
194256778Snwhitehorn	    BUS_DMA_WAITOK | BUS_DMA_ZERO, &sc->rx_buf_map);
195256778Snwhitehorn	error = bus_dmamap_load(sc->rx_dma_tag, sc->rx_buf_map, sc->rx_buf,
196256778Snwhitehorn	    LLAN_RX_BUF_LEN, llan_rx_load_cb, sc, 0);
197256778Snwhitehorn
198256778Snwhitehorn	/* TX DMA maps */
199256778Snwhitehorn	bus_dmamap_create(sc->tx_dma_tag, 0, &sc->tx_dma_map);
200256778Snwhitehorn
201256778Snwhitehorn	/* RX DMA */
202256778Snwhitehorn	for (i = 0; i < LLAN_MAX_RX_PACKETS; i++) {
203256778Snwhitehorn		error = bus_dmamap_create(sc->rxbuf_dma_tag, 0,
204256778Snwhitehorn		    &sc->rx_xfer[i].rx_dmamap);
205256778Snwhitehorn		sc->rx_xfer[i].rx_mbuf = NULL;
206256778Snwhitehorn	}
207256778Snwhitehorn
208256778Snwhitehorn	/* Attach to network stack */
209256778Snwhitehorn	sc->ifp = if_alloc(IFT_ETHER);
210256778Snwhitehorn	sc->ifp->if_softc = sc;
211256778Snwhitehorn
212256778Snwhitehorn	if_initname(sc->ifp, device_get_name(dev), device_get_unit(dev));
213256778Snwhitehorn	sc->ifp->if_mtu = ETHERMTU; /* XXX max-frame-size from OF? */
214256778Snwhitehorn	sc->ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
215256778Snwhitehorn	sc->ifp->if_hwassist = 0; /* XXX: ibm,illan-options */
216256778Snwhitehorn	sc->ifp->if_capabilities = 0;
217256778Snwhitehorn	sc->ifp->if_capenable = 0;
218256778Snwhitehorn	sc->ifp->if_start = llan_start;
219256778Snwhitehorn	sc->ifp->if_ioctl = llan_ioctl;
220256778Snwhitehorn	sc->ifp->if_init = llan_init;
221256778Snwhitehorn
222256778Snwhitehorn	IFQ_SET_MAXLEN(&sc->ifp->if_snd, LLAN_MAX_TX_PACKETS);
223256778Snwhitehorn	sc->ifp->if_snd.ifq_drv_maxlen = LLAN_MAX_TX_PACKETS;
224256778Snwhitehorn	IFQ_SET_READY(&sc->ifp->if_snd);
225256778Snwhitehorn
226256778Snwhitehorn	ether_ifattach(sc->ifp, &sc->mac_address[2]);
227256778Snwhitehorn
228256778Snwhitehorn	return (0);
229256778Snwhitehorn}
230256778Snwhitehorn
231256778Snwhitehornstatic void
232256778Snwhitehornllan_rx_load_cb(void *xsc, bus_dma_segment_t *segs, int nsegs, int err)
233256778Snwhitehorn{
234256778Snwhitehorn	struct llan_softc *sc = xsc;
235256778Snwhitehorn
236256778Snwhitehorn	sc->rx_buf_phys = segs[0].ds_addr;
237256778Snwhitehorn	sc->rx_buf_len = segs[0].ds_len - 2*PAGE_SIZE;
238256778Snwhitehorn	sc->input_buf_phys = segs[0].ds_addr + segs[0].ds_len - PAGE_SIZE;
239256778Snwhitehorn	sc->filter_buf_phys = segs[0].ds_addr + segs[0].ds_len - 2*PAGE_SIZE;
240256778Snwhitehorn}
241256778Snwhitehorn
242256778Snwhitehornstatic void
243256778Snwhitehornllan_init(void *xsc)
244256778Snwhitehorn{
245256778Snwhitehorn	struct llan_softc *sc = xsc;
246256778Snwhitehorn	uint64_t rx_buf_desc;
247256778Snwhitehorn	uint64_t macaddr;
248256778Snwhitehorn	int err, i;
249256778Snwhitehorn
250256778Snwhitehorn	mtx_lock(&sc->io_lock);
251256778Snwhitehorn
252256778Snwhitehorn	phyp_hcall(H_FREE_LOGICAL_LAN, sc->unit);
253256778Snwhitehorn
254256778Snwhitehorn	/* Create buffers (page 539) */
255256778Snwhitehorn	sc->rx_dma_slot = 0;
256256778Snwhitehorn	sc->rx_valid_val = 1;
257256778Snwhitehorn
258257292Snwhitehorn	rx_buf_desc = LLAN_BUFDESC_VALID;
259256778Snwhitehorn	rx_buf_desc |= (sc->rx_buf_len << 32);
260256778Snwhitehorn	rx_buf_desc |= sc->rx_buf_phys;
261256778Snwhitehorn	memcpy(&macaddr, sc->mac_address, 8);
262256778Snwhitehorn	err = phyp_hcall(H_REGISTER_LOGICAL_LAN, sc->unit, sc->input_buf_phys,
263256778Snwhitehorn	    rx_buf_desc, sc->filter_buf_phys, macaddr);
264256778Snwhitehorn
265256778Snwhitehorn	for (i = 0; i < LLAN_MAX_RX_PACKETS; i++)
266256778Snwhitehorn		llan_add_rxbuf(sc, &sc->rx_xfer[i]);
267256778Snwhitehorn
268256778Snwhitehorn	phyp_hcall(H_VIO_SIGNAL, sc->unit, 1); /* Enable interrupts */
269256778Snwhitehorn
270256778Snwhitehorn	/* Tell stack we're up */
271256778Snwhitehorn	sc->ifp->if_drv_flags |= IFF_DRV_RUNNING;
272256778Snwhitehorn	sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
273256778Snwhitehorn
274256778Snwhitehorn	mtx_unlock(&sc->io_lock);
275256778Snwhitehorn}
276256778Snwhitehorn
277256778Snwhitehornstatic int
278256778Snwhitehornllan_add_rxbuf(struct llan_softc *sc, struct llan_xfer *rx)
279256778Snwhitehorn{
280256778Snwhitehorn	struct mbuf *m;
281256778Snwhitehorn	bus_dma_segment_t segs[1];
282256778Snwhitehorn	int error, nsegs;
283256778Snwhitehorn
284256778Snwhitehorn	mtx_assert(&sc->io_lock, MA_OWNED);
285256778Snwhitehorn
286256778Snwhitehorn	m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
287256778Snwhitehorn	if (m == NULL)
288256778Snwhitehorn		return (ENOBUFS);
289256778Snwhitehorn
290256778Snwhitehorn	m->m_len = m->m_pkthdr.len = m->m_ext.ext_size;
291256778Snwhitehorn	if (rx->rx_mbuf != NULL) {
292256778Snwhitehorn		bus_dmamap_sync(sc->rxbuf_dma_tag, rx->rx_dmamap,
293256778Snwhitehorn		    BUS_DMASYNC_POSTREAD);
294256778Snwhitehorn		bus_dmamap_unload(sc->rxbuf_dma_tag, rx->rx_dmamap);
295256778Snwhitehorn	}
296256778Snwhitehorn
297256778Snwhitehorn	/* Save pointer to buffer structure */
298256778Snwhitehorn	m_copyback(m, 0, 8, (void *)&rx);
299256778Snwhitehorn
300256778Snwhitehorn	error = bus_dmamap_load_mbuf_sg(sc->rxbuf_dma_tag, rx->rx_dmamap, m,
301256778Snwhitehorn	    segs, &nsegs, BUS_DMA_NOWAIT);
302256778Snwhitehorn	if (error != 0) {
303256778Snwhitehorn		device_printf(sc->dev,
304256778Snwhitehorn		    "cannot load RX DMA map %p, error = %d\n", rx, error);
305256778Snwhitehorn		m_freem(m);
306256778Snwhitehorn		return (error);
307256778Snwhitehorn	}
308256778Snwhitehorn
309256778Snwhitehorn	/* If nsegs is wrong then the stack is corrupt. */
310256778Snwhitehorn	KASSERT(nsegs == 1,
311256778Snwhitehorn	    ("%s: too many DMA segments (%d)", __func__, nsegs));
312256778Snwhitehorn	rx->rx_mbuf = m;
313256778Snwhitehorn
314256778Snwhitehorn	bus_dmamap_sync(sc->rxbuf_dma_tag, rx->rx_dmamap, BUS_DMASYNC_PREREAD);
315256778Snwhitehorn
316257292Snwhitehorn	rx->rx_bufdesc = LLAN_BUFDESC_VALID;
317256778Snwhitehorn	rx->rx_bufdesc |= (((uint64_t)segs[0].ds_len) << 32);
318256778Snwhitehorn	rx->rx_bufdesc |= segs[0].ds_addr;
319256778Snwhitehorn	error = phyp_hcall(H_ADD_LOGICAL_LAN_BUFFER, sc->unit, rx->rx_bufdesc);
320256778Snwhitehorn	if (error != 0) {
321256778Snwhitehorn		m_freem(m);
322256778Snwhitehorn		rx->rx_mbuf = NULL;
323256778Snwhitehorn		return (ENOBUFS);
324256778Snwhitehorn	}
325256778Snwhitehorn
326256778Snwhitehorn        return (0);
327256778Snwhitehorn}
328256778Snwhitehorn
329256778Snwhitehornstatic void
330256778Snwhitehornllan_intr(void *xsc)
331256778Snwhitehorn{
332256778Snwhitehorn	struct llan_softc *sc = xsc;
333256778Snwhitehorn	struct llan_xfer *rx;
334256778Snwhitehorn	struct mbuf *m;
335256778Snwhitehorn
336256778Snwhitehorn	mtx_lock(&sc->io_lock);
337256778Snwhitehorn	phyp_hcall(H_VIO_SIGNAL, sc->unit, 0);
338256778Snwhitehorn
339256778Snwhitehorn	while ((sc->rx_buf[sc->rx_dma_slot].control >> 7) == sc->rx_valid_val) {
340256778Snwhitehorn		rx = (struct llan_xfer *)sc->rx_buf[sc->rx_dma_slot].handle;
341256778Snwhitehorn		m = rx->rx_mbuf;
342256778Snwhitehorn		m_adj(m, sc->rx_buf[sc->rx_dma_slot].offset - 8);
343256778Snwhitehorn		m->m_len = sc->rx_buf[sc->rx_dma_slot].length;
344256778Snwhitehorn
345256778Snwhitehorn		/* llan_add_rxbuf does DMA sync and unload as well as requeue */
346256778Snwhitehorn		if (llan_add_rxbuf(sc, rx) != 0) {
347256778Snwhitehorn			sc->ifp->if_ierrors++;
348256778Snwhitehorn			phyp_hcall(H_ADD_LOGICAL_LAN_BUFFER, sc->unit,
349256778Snwhitehorn			    rx->rx_bufdesc);
350256778Snwhitehorn			continue;
351256778Snwhitehorn		}
352256778Snwhitehorn
353256778Snwhitehorn		sc->ifp->if_ipackets++;
354256778Snwhitehorn		m_adj(m, sc->rx_buf[sc->rx_dma_slot].offset);
355256778Snwhitehorn		m->m_len = sc->rx_buf[sc->rx_dma_slot].length;
356256778Snwhitehorn		m->m_pkthdr.rcvif = sc->ifp;
357256778Snwhitehorn		m->m_pkthdr.len = m->m_len;
358256778Snwhitehorn		sc->rx_dma_slot++;
359256778Snwhitehorn
360256778Snwhitehorn		if (sc->rx_dma_slot >= sc->rx_buf_len/sizeof(sc->rx_buf[0])) {
361256778Snwhitehorn			sc->rx_dma_slot = 0;
362256778Snwhitehorn			sc->rx_valid_val = !sc->rx_valid_val;
363256778Snwhitehorn		}
364256778Snwhitehorn
365256778Snwhitehorn		mtx_unlock(&sc->io_lock);
366256778Snwhitehorn		(*sc->ifp->if_input)(sc->ifp, m);
367256778Snwhitehorn		mtx_lock(&sc->io_lock);
368256778Snwhitehorn	}
369256778Snwhitehorn
370256778Snwhitehorn	phyp_hcall(H_VIO_SIGNAL, sc->unit, 1);
371256778Snwhitehorn	mtx_unlock(&sc->io_lock);
372256778Snwhitehorn}
373256778Snwhitehorn
374256778Snwhitehornstatic void
375256778Snwhitehornllan_send_packet(void *xsc, bus_dma_segment_t *segs, int nsegs,
376256778Snwhitehorn    bus_size_t mapsize, int error)
377256778Snwhitehorn{
378256778Snwhitehorn	struct llan_softc *sc = xsc;
379256778Snwhitehorn	uint64_t bufdescs[6];
380256778Snwhitehorn	int i;
381256778Snwhitehorn
382256778Snwhitehorn	bzero(bufdescs, sizeof(bufdescs));
383256778Snwhitehorn
384256778Snwhitehorn	for (i = 0; i < nsegs; i++) {
385257292Snwhitehorn		bufdescs[i] = LLAN_BUFDESC_VALID;
386256778Snwhitehorn		bufdescs[i] |= (((uint64_t)segs[i].ds_len) << 32);
387256778Snwhitehorn		bufdescs[i] |= segs[i].ds_addr;
388256778Snwhitehorn	}
389256778Snwhitehorn
390257292Snwhitehorn	phyp_hcall(H_SEND_LOGICAL_LAN, sc->unit, bufdescs[0],
391256778Snwhitehorn	    bufdescs[1], bufdescs[2], bufdescs[3], bufdescs[4], bufdescs[5], 0);
392257292Snwhitehorn	/*
393257292Snwhitehorn	 * The hypercall returning implies completion -- or that the call will
394257292Snwhitehorn	 * not complete. In principle, we should try a few times if we get back
395257292Snwhitehorn	 * H_BUSY based on the continuation token in R4. For now, just drop
396257292Snwhitehorn	 * the packet in such cases.
397257292Snwhitehorn	 */
398256778Snwhitehorn}
399256778Snwhitehorn
400256778Snwhitehornstatic void
401256778Snwhitehornllan_start_locked(struct ifnet *ifp)
402256778Snwhitehorn{
403256778Snwhitehorn	struct llan_softc *sc = ifp->if_softc;
404256778Snwhitehorn	bus_addr_t first;
405256778Snwhitehorn	int nsegs;
406256778Snwhitehorn	struct mbuf *mb_head, *m;
407256778Snwhitehorn
408256778Snwhitehorn	mtx_assert(&sc->io_lock, MA_OWNED);
409256778Snwhitehorn	first = 0;
410256778Snwhitehorn
411256778Snwhitehorn	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
412256778Snwhitehorn	    IFF_DRV_RUNNING)
413256778Snwhitehorn		return;
414256778Snwhitehorn
415256778Snwhitehorn	while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
416256778Snwhitehorn		IFQ_DRV_DEQUEUE(&ifp->if_snd, mb_head);
417256778Snwhitehorn
418256778Snwhitehorn		if (mb_head == NULL)
419256778Snwhitehorn			break;
420256778Snwhitehorn
421256778Snwhitehorn		BPF_MTAP(ifp, mb_head);
422256778Snwhitehorn
423256778Snwhitehorn		for (m = mb_head, nsegs = 0; m != NULL; m = m->m_next)
424256778Snwhitehorn			nsegs++;
425256778Snwhitehorn		if (nsegs > 6) {
426256778Snwhitehorn			m = m_collapse(mb_head, M_NOWAIT, 6);
427256778Snwhitehorn			if (m == NULL) {
428256778Snwhitehorn				m_freem(mb_head);
429256778Snwhitehorn				continue;
430256778Snwhitehorn			}
431256778Snwhitehorn		}
432256778Snwhitehorn
433257292Snwhitehorn		bus_dmamap_load_mbuf(sc->tx_dma_tag, sc->tx_dma_map,
434256778Snwhitehorn			mb_head, llan_send_packet, sc, 0);
435257292Snwhitehorn		bus_dmamap_unload(sc->tx_dma_tag, sc->tx_dma_map);
436256778Snwhitehorn		m_freem(mb_head);
437256778Snwhitehorn	}
438256778Snwhitehorn}
439256778Snwhitehorn
440256778Snwhitehornstatic void
441256778Snwhitehornllan_start(struct ifnet *ifp)
442256778Snwhitehorn{
443256778Snwhitehorn	struct llan_softc *sc = ifp->if_softc;
444256778Snwhitehorn
445256778Snwhitehorn	mtx_lock(&sc->io_lock);
446256778Snwhitehorn	llan_start_locked(ifp);
447256778Snwhitehorn	mtx_unlock(&sc->io_lock);
448256778Snwhitehorn}
449256778Snwhitehorn
450256778Snwhitehornstatic int
451257292Snwhitehornllan_set_multicast(struct llan_softc *sc)
452257292Snwhitehorn{
453257292Snwhitehorn	struct ifnet *ifp = sc->ifp;
454257292Snwhitehorn	struct ifmultiaddr *inm;
455257292Snwhitehorn	uint64_t macaddr;
456257292Snwhitehorn
457257292Snwhitehorn	mtx_assert(&sc->io_lock, MA_OWNED);
458257292Snwhitehorn
459257292Snwhitehorn	phyp_hcall(H_MULTICAST_CTRL, sc->unit, LLAN_CLEAR_MULTICAST, 0);
460257292Snwhitehorn
461257292Snwhitehorn	if_maddr_rlock(ifp);
462257292Snwhitehorn	TAILQ_FOREACH(inm, &ifp->if_multiaddrs, ifma_link) {
463257292Snwhitehorn		if (inm->ifma_addr->sa_family != AF_LINK)
464257292Snwhitehorn			continue;
465257292Snwhitehorn
466257292Snwhitehorn		memcpy((uint8_t *)&macaddr + 2,
467257292Snwhitehorn		    LLADDR((struct sockaddr_dl *)inm->ifma_addr), 6);
468257292Snwhitehorn		phyp_hcall(H_MULTICAST_CTRL, sc->unit, LLAN_ADD_MULTICAST,
469257292Snwhitehorn		    macaddr);
470257292Snwhitehorn	}
471257292Snwhitehorn	if_maddr_runlock(ifp);
472257292Snwhitehorn
473257292Snwhitehorn	return (0);
474257292Snwhitehorn}
475257292Snwhitehorn
476257292Snwhitehornstatic int
477256778Snwhitehornllan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
478256778Snwhitehorn{
479257292Snwhitehorn	int err = 0;
480257292Snwhitehorn	struct llan_softc *sc = ifp->if_softc;
481256778Snwhitehorn
482257292Snwhitehorn	switch (cmd) {
483257292Snwhitehorn	case SIOCADDMULTI:
484257292Snwhitehorn	case SIOCDELMULTI:
485257292Snwhitehorn		mtx_lock(&sc->io_lock);
486257292Snwhitehorn		if ((sc->ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
487257292Snwhitehorn			llan_set_multicast(sc);
488257292Snwhitehorn		mtx_unlock(&sc->io_lock);
489257292Snwhitehorn		break;
490257292Snwhitehorn	case SIOCSIFFLAGS:
491257292Snwhitehorn	default:
492257292Snwhitehorn		err = ether_ioctl(ifp, cmd, data);
493257292Snwhitehorn		break;
494257292Snwhitehorn	}
495256778Snwhitehorn
496256778Snwhitehorn	return (err);
497256778Snwhitehorn}
498256778Snwhitehorn
499