phyp_llan.c revision 256778
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: head/sys/powerpc/pseries/phyp_llan.c 256778 2013-10-20 01:31:09Z 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
63256778Snwhitehornstruct llan_xfer {
64256778Snwhitehorn	struct mbuf *rx_mbuf;
65256778Snwhitehorn	bus_dmamap_t rx_dmamap;
66256778Snwhitehorn	uint64_t rx_bufdesc;
67256778Snwhitehorn};
68256778Snwhitehorn
69256778Snwhitehornstruct llan_receive_queue_entry { /* PAPR page 539 */
70256778Snwhitehorn	uint8_t control;
71256778Snwhitehorn	uint8_t reserved;
72256778Snwhitehorn	uint16_t offset;
73256778Snwhitehorn	uint32_t length;
74256778Snwhitehorn	uint64_t handle;
75256778Snwhitehorn} __packed;
76256778Snwhitehorn
77256778Snwhitehornstruct llan_softc {
78256778Snwhitehorn	device_t	dev;
79256778Snwhitehorn	struct mtx	io_lock;
80256778Snwhitehorn
81256778Snwhitehorn	cell_t		unit;
82256778Snwhitehorn	uint8_t		mac_address[8];
83256778Snwhitehorn
84256778Snwhitehorn	int		irqid;
85256778Snwhitehorn	struct resource	*irq;
86256778Snwhitehorn	void		*irq_cookie;
87256778Snwhitehorn
88256778Snwhitehorn	bus_dma_tag_t	rx_dma_tag;
89256778Snwhitehorn	bus_dma_tag_t	rxbuf_dma_tag;
90256778Snwhitehorn	bus_dma_tag_t	tx_dma_tag;
91256778Snwhitehorn
92256778Snwhitehorn	bus_dmamap_t	tx_dma_map;
93256778Snwhitehorn
94256778Snwhitehorn	struct llan_receive_queue_entry *rx_buf;
95256778Snwhitehorn	int		rx_dma_slot;
96256778Snwhitehorn	int		rx_valid_val;
97256778Snwhitehorn	bus_dmamap_t	rx_buf_map;
98256778Snwhitehorn	bus_addr_t	rx_buf_phys;
99256778Snwhitehorn	bus_size_t	rx_buf_len;
100256778Snwhitehorn	bus_addr_t	input_buf_phys;
101256778Snwhitehorn	bus_addr_t	filter_buf_phys;
102256778Snwhitehorn	struct llan_xfer rx_xfer[LLAN_MAX_RX_PACKETS];
103256778Snwhitehorn
104256778Snwhitehorn	struct ifnet	*ifp;
105256778Snwhitehorn};
106256778Snwhitehorn
107256778Snwhitehornstatic int	llan_probe(device_t);
108256778Snwhitehornstatic int	llan_attach(device_t);
109256778Snwhitehornstatic void	llan_intr(void *xsc);
110256778Snwhitehornstatic void	llan_init(void *xsc);
111256778Snwhitehornstatic void	llan_start(struct ifnet *ifp);
112256778Snwhitehornstatic int	llan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
113256778Snwhitehornstatic void	llan_rx_load_cb(void *xsc, bus_dma_segment_t *segs, int nsegs,
114256778Snwhitehorn		    int err);
115256778Snwhitehornstatic int	llan_add_rxbuf(struct llan_softc *sc, struct llan_xfer *rx);
116256778Snwhitehorn
117256778Snwhitehornstatic devclass_t       llan_devclass;
118256778Snwhitehornstatic device_method_t  llan_methods[] = {
119256778Snwhitehorn        DEVMETHOD(device_probe,         llan_probe),
120256778Snwhitehorn        DEVMETHOD(device_attach,        llan_attach),
121256778Snwhitehorn
122256778Snwhitehorn        DEVMETHOD_END
123256778Snwhitehorn};
124256778Snwhitehornstatic driver_t llan_driver = {
125256778Snwhitehorn        "llan",
126256778Snwhitehorn        llan_methods,
127256778Snwhitehorn        sizeof(struct llan_softc)
128256778Snwhitehorn};
129256778SnwhitehornDRIVER_MODULE(llan, vdevice, llan_driver, llan_devclass, 0, 0);
130256778Snwhitehorn
131256778Snwhitehornstatic int
132256778Snwhitehornllan_probe(device_t dev)
133256778Snwhitehorn{
134256778Snwhitehorn	if (!ofw_bus_is_compatible(dev,"IBM,l-lan"))
135256778Snwhitehorn		return (ENXIO);
136256778Snwhitehorn
137256778Snwhitehorn	device_set_desc(dev, "POWER Hypervisor Virtual Ethernet");
138256778Snwhitehorn	return (0);
139256778Snwhitehorn}
140256778Snwhitehorn
141256778Snwhitehornstatic int
142256778Snwhitehornllan_attach(device_t dev)
143256778Snwhitehorn{
144256778Snwhitehorn	struct llan_softc *sc;
145256778Snwhitehorn	phandle_t node;
146256778Snwhitehorn	int error, i;
147256778Snwhitehorn
148256778Snwhitehorn	sc = device_get_softc(dev);
149256778Snwhitehorn	sc->dev = dev;
150256778Snwhitehorn
151256778Snwhitehorn	/* Get firmware properties */
152256778Snwhitehorn	node = ofw_bus_get_node(dev);
153256778Snwhitehorn	OF_getprop(node, "local-mac-address", sc->mac_address,
154256778Snwhitehorn	    sizeof(sc->mac_address));
155256778Snwhitehorn	OF_getprop(node, "reg", &sc->unit, sizeof(sc->unit));
156256778Snwhitehorn
157256778Snwhitehorn	mtx_init(&sc->io_lock, "llan", NULL, MTX_DEF);
158256778Snwhitehorn
159256778Snwhitehorn        /* Setup interrupt */
160256778Snwhitehorn	sc->irqid = 0;
161256778Snwhitehorn	sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqid,
162256778Snwhitehorn	    RF_ACTIVE);
163256778Snwhitehorn
164256778Snwhitehorn	if (!sc->irq) {
165256778Snwhitehorn		device_printf(dev, "Could not allocate IRQ\n");
166256778Snwhitehorn		mtx_destroy(&sc->io_lock);
167256778Snwhitehorn		return (ENXIO);
168256778Snwhitehorn	}
169256778Snwhitehorn
170256778Snwhitehorn	bus_setup_intr(dev, sc->irq, INTR_TYPE_MISC | INTR_MPSAFE |
171256778Snwhitehorn	    INTR_ENTROPY, NULL, llan_intr, sc, &sc->irq_cookie);
172256778Snwhitehorn
173256778Snwhitehorn	/* Setup DMA */
174256778Snwhitehorn	error = bus_dma_tag_create(bus_get_dma_tag(dev), 16, 0,
175256778Snwhitehorn            BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
176256778Snwhitehorn	    LLAN_RX_BUF_LEN, 1, BUS_SPACE_MAXSIZE_32BIT,
177256778Snwhitehorn	    0, NULL, NULL, &sc->rx_dma_tag);
178256778Snwhitehorn	error = bus_dma_tag_create(bus_get_dma_tag(dev), 4, 0,
179256778Snwhitehorn            BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
180256778Snwhitehorn	    BUS_SPACE_MAXSIZE, 1, BUS_SPACE_MAXSIZE_32BIT,
181256778Snwhitehorn	    0, NULL, NULL, &sc->rxbuf_dma_tag);
182256778Snwhitehorn	error = bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0,
183256778Snwhitehorn            BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
184256778Snwhitehorn	    BUS_SPACE_MAXSIZE, 6, BUS_SPACE_MAXSIZE_32BIT, 0,
185256778Snwhitehorn	    busdma_lock_mutex, &sc->io_lock, &sc->tx_dma_tag);
186256778Snwhitehorn
187256778Snwhitehorn	error = bus_dmamem_alloc(sc->rx_dma_tag, (void **)&sc->rx_buf,
188256778Snwhitehorn	    BUS_DMA_WAITOK | BUS_DMA_ZERO, &sc->rx_buf_map);
189256778Snwhitehorn	error = bus_dmamap_load(sc->rx_dma_tag, sc->rx_buf_map, sc->rx_buf,
190256778Snwhitehorn	    LLAN_RX_BUF_LEN, llan_rx_load_cb, sc, 0);
191256778Snwhitehorn
192256778Snwhitehorn	/* TX DMA maps */
193256778Snwhitehorn	bus_dmamap_create(sc->tx_dma_tag, 0, &sc->tx_dma_map);
194256778Snwhitehorn
195256778Snwhitehorn	/* RX DMA */
196256778Snwhitehorn	for (i = 0; i < LLAN_MAX_RX_PACKETS; i++) {
197256778Snwhitehorn		error = bus_dmamap_create(sc->rxbuf_dma_tag, 0,
198256778Snwhitehorn		    &sc->rx_xfer[i].rx_dmamap);
199256778Snwhitehorn		sc->rx_xfer[i].rx_mbuf = NULL;
200256778Snwhitehorn	}
201256778Snwhitehorn
202256778Snwhitehorn	/* Attach to network stack */
203256778Snwhitehorn	sc->ifp = if_alloc(IFT_ETHER);
204256778Snwhitehorn	sc->ifp->if_softc = sc;
205256778Snwhitehorn
206256778Snwhitehorn	if_initname(sc->ifp, device_get_name(dev), device_get_unit(dev));
207256778Snwhitehorn	sc->ifp->if_mtu = ETHERMTU; /* XXX max-frame-size from OF? */
208256778Snwhitehorn	sc->ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
209256778Snwhitehorn	sc->ifp->if_hwassist = 0; /* XXX: ibm,illan-options */
210256778Snwhitehorn	sc->ifp->if_capabilities = 0;
211256778Snwhitehorn	sc->ifp->if_capenable = 0;
212256778Snwhitehorn	sc->ifp->if_start = llan_start;
213256778Snwhitehorn	sc->ifp->if_ioctl = llan_ioctl;
214256778Snwhitehorn	sc->ifp->if_init = llan_init;
215256778Snwhitehorn
216256778Snwhitehorn	IFQ_SET_MAXLEN(&sc->ifp->if_snd, LLAN_MAX_TX_PACKETS);
217256778Snwhitehorn	sc->ifp->if_snd.ifq_drv_maxlen = LLAN_MAX_TX_PACKETS;
218256778Snwhitehorn	IFQ_SET_READY(&sc->ifp->if_snd);
219256778Snwhitehorn
220256778Snwhitehorn	ether_ifattach(sc->ifp, &sc->mac_address[2]);
221256778Snwhitehorn
222256778Snwhitehorn	return (0);
223256778Snwhitehorn}
224256778Snwhitehorn
225256778Snwhitehornstatic void
226256778Snwhitehornllan_rx_load_cb(void *xsc, bus_dma_segment_t *segs, int nsegs, int err)
227256778Snwhitehorn{
228256778Snwhitehorn	struct llan_softc *sc = xsc;
229256778Snwhitehorn
230256778Snwhitehorn	sc->rx_buf_phys = segs[0].ds_addr;
231256778Snwhitehorn	sc->rx_buf_len = segs[0].ds_len - 2*PAGE_SIZE;
232256778Snwhitehorn	sc->input_buf_phys = segs[0].ds_addr + segs[0].ds_len - PAGE_SIZE;
233256778Snwhitehorn	sc->filter_buf_phys = segs[0].ds_addr + segs[0].ds_len - 2*PAGE_SIZE;
234256778Snwhitehorn}
235256778Snwhitehorn
236256778Snwhitehornstatic void
237256778Snwhitehornllan_init(void *xsc)
238256778Snwhitehorn{
239256778Snwhitehorn	struct llan_softc *sc = xsc;
240256778Snwhitehorn	uint64_t rx_buf_desc;
241256778Snwhitehorn	uint64_t macaddr;
242256778Snwhitehorn	int err, i;
243256778Snwhitehorn
244256778Snwhitehorn	mtx_lock(&sc->io_lock);
245256778Snwhitehorn
246256778Snwhitehorn	phyp_hcall(H_FREE_LOGICAL_LAN, sc->unit);
247256778Snwhitehorn
248256778Snwhitehorn	/* Create buffers (page 539) */
249256778Snwhitehorn	sc->rx_dma_slot = 0;
250256778Snwhitehorn	sc->rx_valid_val = 1;
251256778Snwhitehorn
252256778Snwhitehorn	rx_buf_desc = (1UL << 63); /* valid */
253256778Snwhitehorn	rx_buf_desc |= (sc->rx_buf_len << 32);
254256778Snwhitehorn	rx_buf_desc |= sc->rx_buf_phys;
255256778Snwhitehorn	memcpy(&macaddr, sc->mac_address, 8);
256256778Snwhitehorn	err = phyp_hcall(H_REGISTER_LOGICAL_LAN, sc->unit, sc->input_buf_phys,
257256778Snwhitehorn	    rx_buf_desc, sc->filter_buf_phys, macaddr);
258256778Snwhitehorn
259256778Snwhitehorn	for (i = 0; i < LLAN_MAX_RX_PACKETS; i++)
260256778Snwhitehorn		llan_add_rxbuf(sc, &sc->rx_xfer[i]);
261256778Snwhitehorn
262256778Snwhitehorn	phyp_hcall(H_VIO_SIGNAL, sc->unit, 1); /* Enable interrupts */
263256778Snwhitehorn
264256778Snwhitehorn	/* Tell stack we're up */
265256778Snwhitehorn	sc->ifp->if_drv_flags |= IFF_DRV_RUNNING;
266256778Snwhitehorn	sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
267256778Snwhitehorn
268256778Snwhitehorn	mtx_unlock(&sc->io_lock);
269256778Snwhitehorn}
270256778Snwhitehorn
271256778Snwhitehornstatic int
272256778Snwhitehornllan_add_rxbuf(struct llan_softc *sc, struct llan_xfer *rx)
273256778Snwhitehorn{
274256778Snwhitehorn	struct mbuf *m;
275256778Snwhitehorn	bus_dma_segment_t segs[1];
276256778Snwhitehorn	int error, nsegs;
277256778Snwhitehorn
278256778Snwhitehorn	mtx_assert(&sc->io_lock, MA_OWNED);
279256778Snwhitehorn
280256778Snwhitehorn	m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
281256778Snwhitehorn	if (m == NULL)
282256778Snwhitehorn		return (ENOBUFS);
283256778Snwhitehorn
284256778Snwhitehorn	m->m_len = m->m_pkthdr.len = m->m_ext.ext_size;
285256778Snwhitehorn	if (rx->rx_mbuf != NULL) {
286256778Snwhitehorn		bus_dmamap_sync(sc->rxbuf_dma_tag, rx->rx_dmamap,
287256778Snwhitehorn		    BUS_DMASYNC_POSTREAD);
288256778Snwhitehorn		bus_dmamap_unload(sc->rxbuf_dma_tag, rx->rx_dmamap);
289256778Snwhitehorn	}
290256778Snwhitehorn
291256778Snwhitehorn	/* Save pointer to buffer structure */
292256778Snwhitehorn	m_copyback(m, 0, 8, (void *)&rx);
293256778Snwhitehorn
294256778Snwhitehorn	error = bus_dmamap_load_mbuf_sg(sc->rxbuf_dma_tag, rx->rx_dmamap, m,
295256778Snwhitehorn	    segs, &nsegs, BUS_DMA_NOWAIT);
296256778Snwhitehorn	if (error != 0) {
297256778Snwhitehorn		device_printf(sc->dev,
298256778Snwhitehorn		    "cannot load RX DMA map %p, error = %d\n", rx, error);
299256778Snwhitehorn		m_freem(m);
300256778Snwhitehorn		return (error);
301256778Snwhitehorn	}
302256778Snwhitehorn
303256778Snwhitehorn	/* If nsegs is wrong then the stack is corrupt. */
304256778Snwhitehorn	KASSERT(nsegs == 1,
305256778Snwhitehorn	    ("%s: too many DMA segments (%d)", __func__, nsegs));
306256778Snwhitehorn	rx->rx_mbuf = m;
307256778Snwhitehorn
308256778Snwhitehorn	bus_dmamap_sync(sc->rxbuf_dma_tag, rx->rx_dmamap, BUS_DMASYNC_PREREAD);
309256778Snwhitehorn
310256778Snwhitehorn	rx->rx_bufdesc = (1UL << 63); /* valid */
311256778Snwhitehorn	rx->rx_bufdesc |= (((uint64_t)segs[0].ds_len) << 32);
312256778Snwhitehorn	rx->rx_bufdesc |= segs[0].ds_addr;
313256778Snwhitehorn	error = phyp_hcall(H_ADD_LOGICAL_LAN_BUFFER, sc->unit, rx->rx_bufdesc);
314256778Snwhitehorn	if (error != 0) {
315256778Snwhitehorn		m_freem(m);
316256778Snwhitehorn		rx->rx_mbuf = NULL;
317256778Snwhitehorn		return (ENOBUFS);
318256778Snwhitehorn	}
319256778Snwhitehorn
320256778Snwhitehorn        return (0);
321256778Snwhitehorn}
322256778Snwhitehorn
323256778Snwhitehornstatic void
324256778Snwhitehornllan_intr(void *xsc)
325256778Snwhitehorn{
326256778Snwhitehorn	struct llan_softc *sc = xsc;
327256778Snwhitehorn	struct llan_xfer *rx;
328256778Snwhitehorn	struct mbuf *m;
329256778Snwhitehorn
330256778Snwhitehorn	mtx_lock(&sc->io_lock);
331256778Snwhitehorn	phyp_hcall(H_VIO_SIGNAL, sc->unit, 0);
332256778Snwhitehorn
333256778Snwhitehorn	while ((sc->rx_buf[sc->rx_dma_slot].control >> 7) == sc->rx_valid_val) {
334256778Snwhitehorn		rx = (struct llan_xfer *)sc->rx_buf[sc->rx_dma_slot].handle;
335256778Snwhitehorn		m = rx->rx_mbuf;
336256778Snwhitehorn		m_adj(m, sc->rx_buf[sc->rx_dma_slot].offset - 8);
337256778Snwhitehorn		m->m_len = sc->rx_buf[sc->rx_dma_slot].length;
338256778Snwhitehorn
339256778Snwhitehorn		/* llan_add_rxbuf does DMA sync and unload as well as requeue */
340256778Snwhitehorn		if (llan_add_rxbuf(sc, rx) != 0) {
341256778Snwhitehorn			sc->ifp->if_ierrors++;
342256778Snwhitehorn			phyp_hcall(H_ADD_LOGICAL_LAN_BUFFER, sc->unit,
343256778Snwhitehorn			    rx->rx_bufdesc);
344256778Snwhitehorn			continue;
345256778Snwhitehorn		}
346256778Snwhitehorn
347256778Snwhitehorn		sc->ifp->if_ipackets++;
348256778Snwhitehorn		m_adj(m, sc->rx_buf[sc->rx_dma_slot].offset);
349256778Snwhitehorn		m->m_len = sc->rx_buf[sc->rx_dma_slot].length;
350256778Snwhitehorn		m->m_pkthdr.rcvif = sc->ifp;
351256778Snwhitehorn		m->m_pkthdr.len = m->m_len;
352256778Snwhitehorn		sc->rx_dma_slot++;
353256778Snwhitehorn
354256778Snwhitehorn		if (sc->rx_dma_slot >= sc->rx_buf_len/sizeof(sc->rx_buf[0])) {
355256778Snwhitehorn			sc->rx_dma_slot = 0;
356256778Snwhitehorn			sc->rx_valid_val = !sc->rx_valid_val;
357256778Snwhitehorn		}
358256778Snwhitehorn
359256778Snwhitehorn		mtx_unlock(&sc->io_lock);
360256778Snwhitehorn		(*sc->ifp->if_input)(sc->ifp, m);
361256778Snwhitehorn		mtx_lock(&sc->io_lock);
362256778Snwhitehorn	}
363256778Snwhitehorn
364256778Snwhitehorn	phyp_hcall(H_VIO_SIGNAL, sc->unit, 1);
365256778Snwhitehorn	mtx_unlock(&sc->io_lock);
366256778Snwhitehorn}
367256778Snwhitehorn
368256778Snwhitehornstatic void
369256778Snwhitehornllan_send_packet(void *xsc, bus_dma_segment_t *segs, int nsegs,
370256778Snwhitehorn    bus_size_t mapsize, int error)
371256778Snwhitehorn{
372256778Snwhitehorn	struct llan_softc *sc = xsc;
373256778Snwhitehorn	uint64_t bufdescs[6];
374256778Snwhitehorn	int i;
375256778Snwhitehorn
376256778Snwhitehorn	bzero(bufdescs, sizeof(bufdescs));
377256778Snwhitehorn
378256778Snwhitehorn	for (i = 0; i < nsegs; i++) {
379256778Snwhitehorn		bufdescs[i] = (1UL << 63); /* valid */
380256778Snwhitehorn		bufdescs[i] |= (((uint64_t)segs[i].ds_len) << 32);
381256778Snwhitehorn		bufdescs[i] |= segs[i].ds_addr;
382256778Snwhitehorn	}
383256778Snwhitehorn
384256778Snwhitehorn	error = phyp_hcall(H_SEND_LOGICAL_LAN, sc->unit, bufdescs[0],
385256778Snwhitehorn	    bufdescs[1], bufdescs[2], bufdescs[3], bufdescs[4], bufdescs[5], 0);
386256778Snwhitehorn#if 0
387256778Snwhitehorn	if (error)
388256778Snwhitehorn		sc->ifp->if_drv_flags |= IFF_DRV_OACTIVE;
389256778Snwhitehorn
390256778Snwhitehorn	/* XXX: handle H_BUSY? */
391256778Snwhitehorn	/* H_SEND_LOGICAL_LAN returning 0 implies completion of the send op */
392256778Snwhitehorn#endif
393256778Snwhitehorn}
394256778Snwhitehorn
395256778Snwhitehornstatic void
396256778Snwhitehornllan_start_locked(struct ifnet *ifp)
397256778Snwhitehorn{
398256778Snwhitehorn	struct llan_softc *sc = ifp->if_softc;
399256778Snwhitehorn	bus_addr_t first;
400256778Snwhitehorn	int nsegs;
401256778Snwhitehorn	struct mbuf *mb_head, *m;
402256778Snwhitehorn
403256778Snwhitehorn	mtx_assert(&sc->io_lock, MA_OWNED);
404256778Snwhitehorn	first = 0;
405256778Snwhitehorn
406256778Snwhitehorn	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
407256778Snwhitehorn	    IFF_DRV_RUNNING)
408256778Snwhitehorn		return;
409256778Snwhitehorn
410256778Snwhitehorn	while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
411256778Snwhitehorn		IFQ_DRV_DEQUEUE(&ifp->if_snd, mb_head);
412256778Snwhitehorn
413256778Snwhitehorn		if (mb_head == NULL)
414256778Snwhitehorn			break;
415256778Snwhitehorn
416256778Snwhitehorn		BPF_MTAP(ifp, mb_head);
417256778Snwhitehorn
418256778Snwhitehorn		for (m = mb_head, nsegs = 0; m != NULL; m = m->m_next)
419256778Snwhitehorn			nsegs++;
420256778Snwhitehorn		if (nsegs > 6) {
421256778Snwhitehorn			m = m_collapse(mb_head, M_NOWAIT, 6);
422256778Snwhitehorn			if (m == NULL) {
423256778Snwhitehorn				m_freem(mb_head);
424256778Snwhitehorn				continue;
425256778Snwhitehorn			}
426256778Snwhitehorn		}
427256778Snwhitehorn
428256778Snwhitehorn		bus_dmamap_load_mbuf(sc->tx_dma_tag, sc->tx_dma_map, //xfer->dmamap,
429256778Snwhitehorn			mb_head, llan_send_packet, sc, 0);
430256778Snwhitehorn		bus_dmamap_unload(sc->tx_dma_tag, sc->tx_dma_map); // XXX
431256778Snwhitehorn		m_freem(mb_head);
432256778Snwhitehorn	}
433256778Snwhitehorn}
434256778Snwhitehorn
435256778Snwhitehornstatic void
436256778Snwhitehornllan_start(struct ifnet *ifp)
437256778Snwhitehorn{
438256778Snwhitehorn	struct llan_softc *sc = ifp->if_softc;
439256778Snwhitehorn
440256778Snwhitehorn	mtx_lock(&sc->io_lock);
441256778Snwhitehorn	llan_start_locked(ifp);
442256778Snwhitehorn	mtx_unlock(&sc->io_lock);
443256778Snwhitehorn}
444256778Snwhitehorn
445256778Snwhitehornstatic int
446256778Snwhitehornllan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
447256778Snwhitehorn{
448256778Snwhitehorn	int err;
449256778Snwhitehorn
450256778Snwhitehorn	err = ether_ioctl(ifp, cmd, data);
451256778Snwhitehorn
452256778Snwhitehorn	return (err);
453256778Snwhitehorn}
454256778Snwhitehorn
455