xref: /freebsd/sys/powerpc/pseries/phyp_llan.c (revision af4c3211f863bb46767707029f9459b18f7419e9)
1757e5b29SNathan Whitehorn /*-
2757e5b29SNathan Whitehorn  * Copyright 2013 Nathan Whitehorn
3757e5b29SNathan Whitehorn  * All rights reserved.
4757e5b29SNathan Whitehorn  *
5757e5b29SNathan Whitehorn  * Redistribution and use in source and binary forms, with or without
6757e5b29SNathan Whitehorn  * modification, are permitted provided that the following conditions
7757e5b29SNathan Whitehorn  * are met:
8757e5b29SNathan Whitehorn  * 1. Redistributions of source code must retain the above copyright
9757e5b29SNathan Whitehorn  *    notice, this list of conditions and the following disclaimer.
10757e5b29SNathan Whitehorn  * 2. Redistributions in binary form must reproduce the above copyright
11757e5b29SNathan Whitehorn  *    notice, this list of conditions and the following disclaimer in the
12757e5b29SNathan Whitehorn  *    documentation and/or other materials provided with the distribution.
13757e5b29SNathan Whitehorn  *
14757e5b29SNathan Whitehorn  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15757e5b29SNathan Whitehorn  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16757e5b29SNathan Whitehorn  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17757e5b29SNathan Whitehorn  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18757e5b29SNathan Whitehorn  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19757e5b29SNathan Whitehorn  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20757e5b29SNathan Whitehorn  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21757e5b29SNathan Whitehorn  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22757e5b29SNathan Whitehorn  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23757e5b29SNathan Whitehorn  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24757e5b29SNathan Whitehorn  * SUCH DAMAGE.
25757e5b29SNathan Whitehorn  */
26757e5b29SNathan Whitehorn 
27757e5b29SNathan Whitehorn #include <sys/cdefs.h>
28757e5b29SNathan Whitehorn __FBSDID("$FreeBSD$");
29757e5b29SNathan Whitehorn 
30757e5b29SNathan Whitehorn #include <sys/param.h>
31757e5b29SNathan Whitehorn #include <sys/systm.h>
32757e5b29SNathan Whitehorn #include <sys/sockio.h>
33757e5b29SNathan Whitehorn #include <sys/endian.h>
34757e5b29SNathan Whitehorn #include <sys/mbuf.h>
35757e5b29SNathan Whitehorn #include <sys/module.h>
36757e5b29SNathan Whitehorn #include <sys/malloc.h>
37757e5b29SNathan Whitehorn #include <sys/kernel.h>
38757e5b29SNathan Whitehorn #include <sys/socket.h>
39757e5b29SNathan Whitehorn 
40757e5b29SNathan Whitehorn #include <net/bpf.h>
41757e5b29SNathan Whitehorn #include <net/if.h>
42757e5b29SNathan Whitehorn #include <net/if_arp.h>
43757e5b29SNathan Whitehorn #include <net/ethernet.h>
44757e5b29SNathan Whitehorn #include <net/if_dl.h>
45757e5b29SNathan Whitehorn #include <net/if_media.h>
46757e5b29SNathan Whitehorn #include <net/if_types.h>
47757e5b29SNathan Whitehorn #include <net/if_vlan_var.h>
48757e5b29SNathan Whitehorn 
49757e5b29SNathan Whitehorn #include <dev/ofw/openfirm.h>
50757e5b29SNathan Whitehorn #include <dev/ofw/ofw_bus.h>
51757e5b29SNathan Whitehorn #include <dev/ofw/ofw_bus_subr.h>
52757e5b29SNathan Whitehorn #include <machine/bus.h>
53757e5b29SNathan Whitehorn #include <machine/resource.h>
54757e5b29SNathan Whitehorn #include <sys/bus.h>
55757e5b29SNathan Whitehorn #include <sys/rman.h>
56757e5b29SNathan Whitehorn 
57757e5b29SNathan Whitehorn #include <powerpc/pseries/phyp-hvcall.h>
58757e5b29SNathan Whitehorn 
59757e5b29SNathan Whitehorn #define LLAN_MAX_RX_PACKETS	100
60757e5b29SNathan Whitehorn #define LLAN_MAX_TX_PACKETS	100
61757e5b29SNathan Whitehorn #define LLAN_RX_BUF_LEN		8*PAGE_SIZE
62757e5b29SNathan Whitehorn 
63757e5b29SNathan Whitehorn struct llan_xfer {
64757e5b29SNathan Whitehorn 	struct mbuf *rx_mbuf;
65757e5b29SNathan Whitehorn 	bus_dmamap_t rx_dmamap;
66757e5b29SNathan Whitehorn 	uint64_t rx_bufdesc;
67757e5b29SNathan Whitehorn };
68757e5b29SNathan Whitehorn 
69757e5b29SNathan Whitehorn struct llan_receive_queue_entry { /* PAPR page 539 */
70757e5b29SNathan Whitehorn 	uint8_t control;
71757e5b29SNathan Whitehorn 	uint8_t reserved;
72757e5b29SNathan Whitehorn 	uint16_t offset;
73757e5b29SNathan Whitehorn 	uint32_t length;
74757e5b29SNathan Whitehorn 	uint64_t handle;
75757e5b29SNathan Whitehorn } __packed;
76757e5b29SNathan Whitehorn 
77757e5b29SNathan Whitehorn struct llan_softc {
78757e5b29SNathan Whitehorn 	device_t	dev;
79757e5b29SNathan Whitehorn 	struct mtx	io_lock;
80757e5b29SNathan Whitehorn 
81757e5b29SNathan Whitehorn 	cell_t		unit;
82757e5b29SNathan Whitehorn 	uint8_t		mac_address[8];
83757e5b29SNathan Whitehorn 
84757e5b29SNathan Whitehorn 	int		irqid;
85757e5b29SNathan Whitehorn 	struct resource	*irq;
86757e5b29SNathan Whitehorn 	void		*irq_cookie;
87757e5b29SNathan Whitehorn 
88757e5b29SNathan Whitehorn 	bus_dma_tag_t	rx_dma_tag;
89757e5b29SNathan Whitehorn 	bus_dma_tag_t	rxbuf_dma_tag;
90757e5b29SNathan Whitehorn 	bus_dma_tag_t	tx_dma_tag;
91757e5b29SNathan Whitehorn 
92757e5b29SNathan Whitehorn 	bus_dmamap_t	tx_dma_map;
93757e5b29SNathan Whitehorn 
94757e5b29SNathan Whitehorn 	struct llan_receive_queue_entry *rx_buf;
95757e5b29SNathan Whitehorn 	int		rx_dma_slot;
96757e5b29SNathan Whitehorn 	int		rx_valid_val;
97757e5b29SNathan Whitehorn 	bus_dmamap_t	rx_buf_map;
98757e5b29SNathan Whitehorn 	bus_addr_t	rx_buf_phys;
99757e5b29SNathan Whitehorn 	bus_size_t	rx_buf_len;
100757e5b29SNathan Whitehorn 	bus_addr_t	input_buf_phys;
101757e5b29SNathan Whitehorn 	bus_addr_t	filter_buf_phys;
102757e5b29SNathan Whitehorn 	struct llan_xfer rx_xfer[LLAN_MAX_RX_PACKETS];
103757e5b29SNathan Whitehorn 
104757e5b29SNathan Whitehorn 	struct ifnet	*ifp;
105757e5b29SNathan Whitehorn };
106757e5b29SNathan Whitehorn 
107757e5b29SNathan Whitehorn static int	llan_probe(device_t);
108757e5b29SNathan Whitehorn static int	llan_attach(device_t);
109757e5b29SNathan Whitehorn static void	llan_intr(void *xsc);
110757e5b29SNathan Whitehorn static void	llan_init(void *xsc);
111757e5b29SNathan Whitehorn static void	llan_start(struct ifnet *ifp);
112757e5b29SNathan Whitehorn static int	llan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
113757e5b29SNathan Whitehorn static void	llan_rx_load_cb(void *xsc, bus_dma_segment_t *segs, int nsegs,
114757e5b29SNathan Whitehorn 		    int err);
115757e5b29SNathan Whitehorn static int	llan_add_rxbuf(struct llan_softc *sc, struct llan_xfer *rx);
116757e5b29SNathan Whitehorn 
117757e5b29SNathan Whitehorn static devclass_t       llan_devclass;
118757e5b29SNathan Whitehorn static device_method_t  llan_methods[] = {
119757e5b29SNathan Whitehorn         DEVMETHOD(device_probe,         llan_probe),
120757e5b29SNathan Whitehorn         DEVMETHOD(device_attach,        llan_attach),
121757e5b29SNathan Whitehorn 
122757e5b29SNathan Whitehorn         DEVMETHOD_END
123757e5b29SNathan Whitehorn };
124757e5b29SNathan Whitehorn static driver_t llan_driver = {
125757e5b29SNathan Whitehorn         "llan",
126757e5b29SNathan Whitehorn         llan_methods,
127757e5b29SNathan Whitehorn         sizeof(struct llan_softc)
128757e5b29SNathan Whitehorn };
129757e5b29SNathan Whitehorn DRIVER_MODULE(llan, vdevice, llan_driver, llan_devclass, 0, 0);
130757e5b29SNathan Whitehorn 
131757e5b29SNathan Whitehorn static int
132757e5b29SNathan Whitehorn llan_probe(device_t dev)
133757e5b29SNathan Whitehorn {
134757e5b29SNathan Whitehorn 	if (!ofw_bus_is_compatible(dev,"IBM,l-lan"))
135757e5b29SNathan Whitehorn 		return (ENXIO);
136757e5b29SNathan Whitehorn 
137757e5b29SNathan Whitehorn 	device_set_desc(dev, "POWER Hypervisor Virtual Ethernet");
138757e5b29SNathan Whitehorn 	return (0);
139757e5b29SNathan Whitehorn }
140757e5b29SNathan Whitehorn 
141757e5b29SNathan Whitehorn static int
142757e5b29SNathan Whitehorn llan_attach(device_t dev)
143757e5b29SNathan Whitehorn {
144757e5b29SNathan Whitehorn 	struct llan_softc *sc;
145757e5b29SNathan Whitehorn 	phandle_t node;
146757e5b29SNathan Whitehorn 	int error, i;
147757e5b29SNathan Whitehorn 
148757e5b29SNathan Whitehorn 	sc = device_get_softc(dev);
149757e5b29SNathan Whitehorn 	sc->dev = dev;
150757e5b29SNathan Whitehorn 
151757e5b29SNathan Whitehorn 	/* Get firmware properties */
152757e5b29SNathan Whitehorn 	node = ofw_bus_get_node(dev);
153757e5b29SNathan Whitehorn 	OF_getprop(node, "local-mac-address", sc->mac_address,
154757e5b29SNathan Whitehorn 	    sizeof(sc->mac_address));
155757e5b29SNathan Whitehorn 	OF_getprop(node, "reg", &sc->unit, sizeof(sc->unit));
156757e5b29SNathan Whitehorn 
157757e5b29SNathan Whitehorn 	mtx_init(&sc->io_lock, "llan", NULL, MTX_DEF);
158757e5b29SNathan Whitehorn 
159757e5b29SNathan Whitehorn         /* Setup interrupt */
160757e5b29SNathan Whitehorn 	sc->irqid = 0;
161757e5b29SNathan Whitehorn 	sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqid,
162757e5b29SNathan Whitehorn 	    RF_ACTIVE);
163757e5b29SNathan Whitehorn 
164757e5b29SNathan Whitehorn 	if (!sc->irq) {
165757e5b29SNathan Whitehorn 		device_printf(dev, "Could not allocate IRQ\n");
166757e5b29SNathan Whitehorn 		mtx_destroy(&sc->io_lock);
167757e5b29SNathan Whitehorn 		return (ENXIO);
168757e5b29SNathan Whitehorn 	}
169757e5b29SNathan Whitehorn 
170757e5b29SNathan Whitehorn 	bus_setup_intr(dev, sc->irq, INTR_TYPE_MISC | INTR_MPSAFE |
171757e5b29SNathan Whitehorn 	    INTR_ENTROPY, NULL, llan_intr, sc, &sc->irq_cookie);
172757e5b29SNathan Whitehorn 
173757e5b29SNathan Whitehorn 	/* Setup DMA */
174757e5b29SNathan Whitehorn 	error = bus_dma_tag_create(bus_get_dma_tag(dev), 16, 0,
175757e5b29SNathan Whitehorn             BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
176757e5b29SNathan Whitehorn 	    LLAN_RX_BUF_LEN, 1, BUS_SPACE_MAXSIZE_32BIT,
177757e5b29SNathan Whitehorn 	    0, NULL, NULL, &sc->rx_dma_tag);
178757e5b29SNathan Whitehorn 	error = bus_dma_tag_create(bus_get_dma_tag(dev), 4, 0,
179757e5b29SNathan Whitehorn             BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
180757e5b29SNathan Whitehorn 	    BUS_SPACE_MAXSIZE, 1, BUS_SPACE_MAXSIZE_32BIT,
181757e5b29SNathan Whitehorn 	    0, NULL, NULL, &sc->rxbuf_dma_tag);
182757e5b29SNathan Whitehorn 	error = bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0,
183757e5b29SNathan Whitehorn             BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
184757e5b29SNathan Whitehorn 	    BUS_SPACE_MAXSIZE, 6, BUS_SPACE_MAXSIZE_32BIT, 0,
185757e5b29SNathan Whitehorn 	    busdma_lock_mutex, &sc->io_lock, &sc->tx_dma_tag);
186757e5b29SNathan Whitehorn 
187757e5b29SNathan Whitehorn 	error = bus_dmamem_alloc(sc->rx_dma_tag, (void **)&sc->rx_buf,
188757e5b29SNathan Whitehorn 	    BUS_DMA_WAITOK | BUS_DMA_ZERO, &sc->rx_buf_map);
189757e5b29SNathan Whitehorn 	error = bus_dmamap_load(sc->rx_dma_tag, sc->rx_buf_map, sc->rx_buf,
190757e5b29SNathan Whitehorn 	    LLAN_RX_BUF_LEN, llan_rx_load_cb, sc, 0);
191757e5b29SNathan Whitehorn 
192757e5b29SNathan Whitehorn 	/* TX DMA maps */
193757e5b29SNathan Whitehorn 	bus_dmamap_create(sc->tx_dma_tag, 0, &sc->tx_dma_map);
194757e5b29SNathan Whitehorn 
195757e5b29SNathan Whitehorn 	/* RX DMA */
196757e5b29SNathan Whitehorn 	for (i = 0; i < LLAN_MAX_RX_PACKETS; i++) {
197757e5b29SNathan Whitehorn 		error = bus_dmamap_create(sc->rxbuf_dma_tag, 0,
198757e5b29SNathan Whitehorn 		    &sc->rx_xfer[i].rx_dmamap);
199757e5b29SNathan Whitehorn 		sc->rx_xfer[i].rx_mbuf = NULL;
200757e5b29SNathan Whitehorn 	}
201757e5b29SNathan Whitehorn 
202757e5b29SNathan Whitehorn 	/* Attach to network stack */
203757e5b29SNathan Whitehorn 	sc->ifp = if_alloc(IFT_ETHER);
204757e5b29SNathan Whitehorn 	sc->ifp->if_softc = sc;
205757e5b29SNathan Whitehorn 
206757e5b29SNathan Whitehorn 	if_initname(sc->ifp, device_get_name(dev), device_get_unit(dev));
207757e5b29SNathan Whitehorn 	sc->ifp->if_mtu = ETHERMTU; /* XXX max-frame-size from OF? */
208757e5b29SNathan Whitehorn 	sc->ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
209757e5b29SNathan Whitehorn 	sc->ifp->if_hwassist = 0; /* XXX: ibm,illan-options */
210757e5b29SNathan Whitehorn 	sc->ifp->if_capabilities = 0;
211757e5b29SNathan Whitehorn 	sc->ifp->if_capenable = 0;
212757e5b29SNathan Whitehorn 	sc->ifp->if_start = llan_start;
213757e5b29SNathan Whitehorn 	sc->ifp->if_ioctl = llan_ioctl;
214757e5b29SNathan Whitehorn 	sc->ifp->if_init = llan_init;
215757e5b29SNathan Whitehorn 
216757e5b29SNathan Whitehorn 	IFQ_SET_MAXLEN(&sc->ifp->if_snd, LLAN_MAX_TX_PACKETS);
217757e5b29SNathan Whitehorn 	sc->ifp->if_snd.ifq_drv_maxlen = LLAN_MAX_TX_PACKETS;
218757e5b29SNathan Whitehorn 	IFQ_SET_READY(&sc->ifp->if_snd);
219757e5b29SNathan Whitehorn 
220757e5b29SNathan Whitehorn 	ether_ifattach(sc->ifp, &sc->mac_address[2]);
221757e5b29SNathan Whitehorn 
222757e5b29SNathan Whitehorn 	return (0);
223757e5b29SNathan Whitehorn }
224757e5b29SNathan Whitehorn 
225757e5b29SNathan Whitehorn static void
226757e5b29SNathan Whitehorn llan_rx_load_cb(void *xsc, bus_dma_segment_t *segs, int nsegs, int err)
227757e5b29SNathan Whitehorn {
228757e5b29SNathan Whitehorn 	struct llan_softc *sc = xsc;
229757e5b29SNathan Whitehorn 
230757e5b29SNathan Whitehorn 	sc->rx_buf_phys = segs[0].ds_addr;
231757e5b29SNathan Whitehorn 	sc->rx_buf_len = segs[0].ds_len - 2*PAGE_SIZE;
232757e5b29SNathan Whitehorn 	sc->input_buf_phys = segs[0].ds_addr + segs[0].ds_len - PAGE_SIZE;
233757e5b29SNathan Whitehorn 	sc->filter_buf_phys = segs[0].ds_addr + segs[0].ds_len - 2*PAGE_SIZE;
234757e5b29SNathan Whitehorn }
235757e5b29SNathan Whitehorn 
236757e5b29SNathan Whitehorn static void
237757e5b29SNathan Whitehorn llan_init(void *xsc)
238757e5b29SNathan Whitehorn {
239757e5b29SNathan Whitehorn 	struct llan_softc *sc = xsc;
240757e5b29SNathan Whitehorn 	uint64_t rx_buf_desc;
241757e5b29SNathan Whitehorn 	uint64_t macaddr;
242757e5b29SNathan Whitehorn 	int err, i;
243757e5b29SNathan Whitehorn 
244757e5b29SNathan Whitehorn 	mtx_lock(&sc->io_lock);
245757e5b29SNathan Whitehorn 
246757e5b29SNathan Whitehorn 	phyp_hcall(H_FREE_LOGICAL_LAN, sc->unit);
247757e5b29SNathan Whitehorn 
248757e5b29SNathan Whitehorn 	/* Create buffers (page 539) */
249757e5b29SNathan Whitehorn 	sc->rx_dma_slot = 0;
250757e5b29SNathan Whitehorn 	sc->rx_valid_val = 1;
251757e5b29SNathan Whitehorn 
252757e5b29SNathan Whitehorn 	rx_buf_desc = (1UL << 63); /* valid */
253757e5b29SNathan Whitehorn 	rx_buf_desc |= (sc->rx_buf_len << 32);
254757e5b29SNathan Whitehorn 	rx_buf_desc |= sc->rx_buf_phys;
255757e5b29SNathan Whitehorn 	memcpy(&macaddr, sc->mac_address, 8);
256757e5b29SNathan Whitehorn 	err = phyp_hcall(H_REGISTER_LOGICAL_LAN, sc->unit, sc->input_buf_phys,
257757e5b29SNathan Whitehorn 	    rx_buf_desc, sc->filter_buf_phys, macaddr);
258757e5b29SNathan Whitehorn 
259757e5b29SNathan Whitehorn 	for (i = 0; i < LLAN_MAX_RX_PACKETS; i++)
260757e5b29SNathan Whitehorn 		llan_add_rxbuf(sc, &sc->rx_xfer[i]);
261757e5b29SNathan Whitehorn 
262757e5b29SNathan Whitehorn 	phyp_hcall(H_VIO_SIGNAL, sc->unit, 1); /* Enable interrupts */
263757e5b29SNathan Whitehorn 
264757e5b29SNathan Whitehorn 	/* Tell stack we're up */
265757e5b29SNathan Whitehorn 	sc->ifp->if_drv_flags |= IFF_DRV_RUNNING;
266757e5b29SNathan Whitehorn 	sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
267757e5b29SNathan Whitehorn 
268757e5b29SNathan Whitehorn 	mtx_unlock(&sc->io_lock);
269757e5b29SNathan Whitehorn }
270757e5b29SNathan Whitehorn 
271757e5b29SNathan Whitehorn static int
272757e5b29SNathan Whitehorn llan_add_rxbuf(struct llan_softc *sc, struct llan_xfer *rx)
273757e5b29SNathan Whitehorn {
274757e5b29SNathan Whitehorn 	struct mbuf *m;
275757e5b29SNathan Whitehorn 	bus_dma_segment_t segs[1];
276757e5b29SNathan Whitehorn 	int error, nsegs;
277757e5b29SNathan Whitehorn 
278757e5b29SNathan Whitehorn 	mtx_assert(&sc->io_lock, MA_OWNED);
279757e5b29SNathan Whitehorn 
280757e5b29SNathan Whitehorn 	m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
281757e5b29SNathan Whitehorn 	if (m == NULL)
282757e5b29SNathan Whitehorn 		return (ENOBUFS);
283757e5b29SNathan Whitehorn 
284757e5b29SNathan Whitehorn 	m->m_len = m->m_pkthdr.len = m->m_ext.ext_size;
285757e5b29SNathan Whitehorn 	if (rx->rx_mbuf != NULL) {
286757e5b29SNathan Whitehorn 		bus_dmamap_sync(sc->rxbuf_dma_tag, rx->rx_dmamap,
287757e5b29SNathan Whitehorn 		    BUS_DMASYNC_POSTREAD);
288757e5b29SNathan Whitehorn 		bus_dmamap_unload(sc->rxbuf_dma_tag, rx->rx_dmamap);
289757e5b29SNathan Whitehorn 	}
290757e5b29SNathan Whitehorn 
291757e5b29SNathan Whitehorn 	/* Save pointer to buffer structure */
292757e5b29SNathan Whitehorn 	m_copyback(m, 0, 8, (void *)&rx);
293757e5b29SNathan Whitehorn 
294757e5b29SNathan Whitehorn 	error = bus_dmamap_load_mbuf_sg(sc->rxbuf_dma_tag, rx->rx_dmamap, m,
295757e5b29SNathan Whitehorn 	    segs, &nsegs, BUS_DMA_NOWAIT);
296757e5b29SNathan Whitehorn 	if (error != 0) {
297757e5b29SNathan Whitehorn 		device_printf(sc->dev,
298757e5b29SNathan Whitehorn 		    "cannot load RX DMA map %p, error = %d\n", rx, error);
299757e5b29SNathan Whitehorn 		m_freem(m);
300757e5b29SNathan Whitehorn 		return (error);
301757e5b29SNathan Whitehorn 	}
302757e5b29SNathan Whitehorn 
303757e5b29SNathan Whitehorn 	/* If nsegs is wrong then the stack is corrupt. */
304757e5b29SNathan Whitehorn 	KASSERT(nsegs == 1,
305757e5b29SNathan Whitehorn 	    ("%s: too many DMA segments (%d)", __func__, nsegs));
306757e5b29SNathan Whitehorn 	rx->rx_mbuf = m;
307757e5b29SNathan Whitehorn 
308757e5b29SNathan Whitehorn 	bus_dmamap_sync(sc->rxbuf_dma_tag, rx->rx_dmamap, BUS_DMASYNC_PREREAD);
309757e5b29SNathan Whitehorn 
310757e5b29SNathan Whitehorn 	rx->rx_bufdesc = (1UL << 63); /* valid */
311757e5b29SNathan Whitehorn 	rx->rx_bufdesc |= (((uint64_t)segs[0].ds_len) << 32);
312757e5b29SNathan Whitehorn 	rx->rx_bufdesc |= segs[0].ds_addr;
313757e5b29SNathan Whitehorn 	error = phyp_hcall(H_ADD_LOGICAL_LAN_BUFFER, sc->unit, rx->rx_bufdesc);
314757e5b29SNathan Whitehorn 	if (error != 0) {
315757e5b29SNathan Whitehorn 		m_freem(m);
316757e5b29SNathan Whitehorn 		rx->rx_mbuf = NULL;
317757e5b29SNathan Whitehorn 		return (ENOBUFS);
318757e5b29SNathan Whitehorn 	}
319757e5b29SNathan Whitehorn 
320757e5b29SNathan Whitehorn         return (0);
321757e5b29SNathan Whitehorn }
322757e5b29SNathan Whitehorn 
323757e5b29SNathan Whitehorn static void
324757e5b29SNathan Whitehorn llan_intr(void *xsc)
325757e5b29SNathan Whitehorn {
326757e5b29SNathan Whitehorn 	struct llan_softc *sc = xsc;
327757e5b29SNathan Whitehorn 	struct llan_xfer *rx;
328757e5b29SNathan Whitehorn 	struct mbuf *m;
329757e5b29SNathan Whitehorn 
330757e5b29SNathan Whitehorn 	mtx_lock(&sc->io_lock);
331757e5b29SNathan Whitehorn 	phyp_hcall(H_VIO_SIGNAL, sc->unit, 0);
332757e5b29SNathan Whitehorn 
333757e5b29SNathan Whitehorn 	while ((sc->rx_buf[sc->rx_dma_slot].control >> 7) == sc->rx_valid_val) {
334757e5b29SNathan Whitehorn 		rx = (struct llan_xfer *)sc->rx_buf[sc->rx_dma_slot].handle;
335757e5b29SNathan Whitehorn 		m = rx->rx_mbuf;
336757e5b29SNathan Whitehorn 		m_adj(m, sc->rx_buf[sc->rx_dma_slot].offset - 8);
337757e5b29SNathan Whitehorn 		m->m_len = sc->rx_buf[sc->rx_dma_slot].length;
338757e5b29SNathan Whitehorn 
339757e5b29SNathan Whitehorn 		/* llan_add_rxbuf does DMA sync and unload as well as requeue */
340757e5b29SNathan Whitehorn 		if (llan_add_rxbuf(sc, rx) != 0) {
341757e5b29SNathan Whitehorn 			sc->ifp->if_ierrors++;
342757e5b29SNathan Whitehorn 			phyp_hcall(H_ADD_LOGICAL_LAN_BUFFER, sc->unit,
343757e5b29SNathan Whitehorn 			    rx->rx_bufdesc);
344757e5b29SNathan Whitehorn 			continue;
345757e5b29SNathan Whitehorn 		}
346757e5b29SNathan Whitehorn 
347757e5b29SNathan Whitehorn 		sc->ifp->if_ipackets++;
348757e5b29SNathan Whitehorn 		m_adj(m, sc->rx_buf[sc->rx_dma_slot].offset);
349757e5b29SNathan Whitehorn 		m->m_len = sc->rx_buf[sc->rx_dma_slot].length;
350757e5b29SNathan Whitehorn 		m->m_pkthdr.rcvif = sc->ifp;
351757e5b29SNathan Whitehorn 		m->m_pkthdr.len = m->m_len;
352757e5b29SNathan Whitehorn 		sc->rx_dma_slot++;
353757e5b29SNathan Whitehorn 
354757e5b29SNathan Whitehorn 		if (sc->rx_dma_slot >= sc->rx_buf_len/sizeof(sc->rx_buf[0])) {
355757e5b29SNathan Whitehorn 			sc->rx_dma_slot = 0;
356757e5b29SNathan Whitehorn 			sc->rx_valid_val = !sc->rx_valid_val;
357757e5b29SNathan Whitehorn 		}
358757e5b29SNathan Whitehorn 
359757e5b29SNathan Whitehorn 		mtx_unlock(&sc->io_lock);
360757e5b29SNathan Whitehorn 		(*sc->ifp->if_input)(sc->ifp, m);
361757e5b29SNathan Whitehorn 		mtx_lock(&sc->io_lock);
362757e5b29SNathan Whitehorn 	}
363757e5b29SNathan Whitehorn 
364757e5b29SNathan Whitehorn 	phyp_hcall(H_VIO_SIGNAL, sc->unit, 1);
365757e5b29SNathan Whitehorn 	mtx_unlock(&sc->io_lock);
366757e5b29SNathan Whitehorn }
367757e5b29SNathan Whitehorn 
368757e5b29SNathan Whitehorn static void
369757e5b29SNathan Whitehorn llan_send_packet(void *xsc, bus_dma_segment_t *segs, int nsegs,
370757e5b29SNathan Whitehorn     bus_size_t mapsize, int error)
371757e5b29SNathan Whitehorn {
372757e5b29SNathan Whitehorn 	struct llan_softc *sc = xsc;
373757e5b29SNathan Whitehorn 	uint64_t bufdescs[6];
374757e5b29SNathan Whitehorn 	int i;
375757e5b29SNathan Whitehorn 
376757e5b29SNathan Whitehorn 	bzero(bufdescs, sizeof(bufdescs));
377757e5b29SNathan Whitehorn 
378757e5b29SNathan Whitehorn 	for (i = 0; i < nsegs; i++) {
379757e5b29SNathan Whitehorn 		bufdescs[i] = (1UL << 63); /* valid */
380757e5b29SNathan Whitehorn 		bufdescs[i] |= (((uint64_t)segs[i].ds_len) << 32);
381757e5b29SNathan Whitehorn 		bufdescs[i] |= segs[i].ds_addr;
382757e5b29SNathan Whitehorn 	}
383757e5b29SNathan Whitehorn 
384*af4c3211SNathan Whitehorn 	phyp_hcall(H_SEND_LOGICAL_LAN, sc->unit, bufdescs[0],
385757e5b29SNathan Whitehorn 	    bufdescs[1], bufdescs[2], bufdescs[3], bufdescs[4], bufdescs[5], 0);
386*af4c3211SNathan Whitehorn 	/*
387*af4c3211SNathan Whitehorn 	 * The hypercall returning implies completion -- or that the call will
388*af4c3211SNathan Whitehorn 	 * not complete. In principle, we should try a few times if we get back
389*af4c3211SNathan Whitehorn 	 * H_BUSY based on the continuation token in R4. For now, just drop
390*af4c3211SNathan Whitehorn 	 * the packet in such cases.
391*af4c3211SNathan Whitehorn 	 */
392757e5b29SNathan Whitehorn }
393757e5b29SNathan Whitehorn 
394757e5b29SNathan Whitehorn static void
395757e5b29SNathan Whitehorn llan_start_locked(struct ifnet *ifp)
396757e5b29SNathan Whitehorn {
397757e5b29SNathan Whitehorn 	struct llan_softc *sc = ifp->if_softc;
398757e5b29SNathan Whitehorn 	bus_addr_t first;
399757e5b29SNathan Whitehorn 	int nsegs;
400757e5b29SNathan Whitehorn 	struct mbuf *mb_head, *m;
401757e5b29SNathan Whitehorn 
402757e5b29SNathan Whitehorn 	mtx_assert(&sc->io_lock, MA_OWNED);
403757e5b29SNathan Whitehorn 	first = 0;
404757e5b29SNathan Whitehorn 
405757e5b29SNathan Whitehorn 	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
406757e5b29SNathan Whitehorn 	    IFF_DRV_RUNNING)
407757e5b29SNathan Whitehorn 		return;
408757e5b29SNathan Whitehorn 
409757e5b29SNathan Whitehorn 	while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
410757e5b29SNathan Whitehorn 		IFQ_DRV_DEQUEUE(&ifp->if_snd, mb_head);
411757e5b29SNathan Whitehorn 
412757e5b29SNathan Whitehorn 		if (mb_head == NULL)
413757e5b29SNathan Whitehorn 			break;
414757e5b29SNathan Whitehorn 
415757e5b29SNathan Whitehorn 		BPF_MTAP(ifp, mb_head);
416757e5b29SNathan Whitehorn 
417757e5b29SNathan Whitehorn 		for (m = mb_head, nsegs = 0; m != NULL; m = m->m_next)
418757e5b29SNathan Whitehorn 			nsegs++;
419757e5b29SNathan Whitehorn 		if (nsegs > 6) {
420757e5b29SNathan Whitehorn 			m = m_collapse(mb_head, M_NOWAIT, 6);
421757e5b29SNathan Whitehorn 			if (m == NULL) {
422757e5b29SNathan Whitehorn 				m_freem(mb_head);
423757e5b29SNathan Whitehorn 				continue;
424757e5b29SNathan Whitehorn 			}
425757e5b29SNathan Whitehorn 		}
426757e5b29SNathan Whitehorn 
427*af4c3211SNathan Whitehorn 		bus_dmamap_load_mbuf(sc->tx_dma_tag, sc->tx_dma_map,
428757e5b29SNathan Whitehorn 			mb_head, llan_send_packet, sc, 0);
429*af4c3211SNathan Whitehorn 		bus_dmamap_unload(sc->tx_dma_tag, sc->tx_dma_map);
430757e5b29SNathan Whitehorn 		m_freem(mb_head);
431757e5b29SNathan Whitehorn 	}
432757e5b29SNathan Whitehorn }
433757e5b29SNathan Whitehorn 
434757e5b29SNathan Whitehorn static void
435757e5b29SNathan Whitehorn llan_start(struct ifnet *ifp)
436757e5b29SNathan Whitehorn {
437757e5b29SNathan Whitehorn 	struct llan_softc *sc = ifp->if_softc;
438757e5b29SNathan Whitehorn 
439757e5b29SNathan Whitehorn 	mtx_lock(&sc->io_lock);
440757e5b29SNathan Whitehorn 	llan_start_locked(ifp);
441757e5b29SNathan Whitehorn 	mtx_unlock(&sc->io_lock);
442757e5b29SNathan Whitehorn }
443757e5b29SNathan Whitehorn 
444757e5b29SNathan Whitehorn static int
445757e5b29SNathan Whitehorn llan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
446757e5b29SNathan Whitehorn {
447757e5b29SNathan Whitehorn 	int err;
448757e5b29SNathan Whitehorn 
449757e5b29SNathan Whitehorn 	err = ether_ioctl(ifp, cmd, data);
450757e5b29SNathan Whitehorn 
451757e5b29SNathan Whitehorn 	return (err);
452757e5b29SNathan Whitehorn }
453757e5b29SNathan Whitehorn 
454