xref: /openbsd/sys/dev/pci/if_bwfm_pci.c (revision 029d6dd5)
1*029d6dd5Spatrick /*	$OpenBSD: if_bwfm_pci.c,v 1.19 2018/05/16 08:20:00 patrick Exp $	*/
2e5ec1e72Spatrick /*
3e5ec1e72Spatrick  * Copyright (c) 2010-2016 Broadcom Corporation
4e5ec1e72Spatrick  * Copyright (c) 2017 Patrick Wildt <patrick@blueri.se>
5e5ec1e72Spatrick  *
6e5ec1e72Spatrick  * Permission to use, copy, modify, and/or distribute this software for any
7e5ec1e72Spatrick  * purpose with or without fee is hereby granted, provided that the above
8e5ec1e72Spatrick  * copyright notice and this permission notice appear in all copies.
9e5ec1e72Spatrick  *
10e5ec1e72Spatrick  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11e5ec1e72Spatrick  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12e5ec1e72Spatrick  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13e5ec1e72Spatrick  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14e5ec1e72Spatrick  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15e5ec1e72Spatrick  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16e5ec1e72Spatrick  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17e5ec1e72Spatrick  */
18e5ec1e72Spatrick 
19e5ec1e72Spatrick #include "bpfilter.h"
20e5ec1e72Spatrick 
21e5ec1e72Spatrick #include <sys/param.h>
22e5ec1e72Spatrick #include <sys/systm.h>
23e5ec1e72Spatrick #include <sys/buf.h>
24e5ec1e72Spatrick #include <sys/kernel.h>
25e5ec1e72Spatrick #include <sys/malloc.h>
26e5ec1e72Spatrick #include <sys/device.h>
27e5ec1e72Spatrick #include <sys/queue.h>
28e5ec1e72Spatrick #include <sys/socket.h>
29e5ec1e72Spatrick 
30e5ec1e72Spatrick #if NBPFILTER > 0
31e5ec1e72Spatrick #include <net/bpf.h>
32e5ec1e72Spatrick #endif
33e5ec1e72Spatrick #include <net/if.h>
34e5ec1e72Spatrick #include <net/if_dl.h>
35e5ec1e72Spatrick #include <net/if_media.h>
36e5ec1e72Spatrick 
37e5ec1e72Spatrick #include <netinet/in.h>
38e5ec1e72Spatrick #include <netinet/if_ether.h>
39e5ec1e72Spatrick 
40e5ec1e72Spatrick #include <net80211/ieee80211_var.h>
41e5ec1e72Spatrick 
42e5ec1e72Spatrick #include <machine/bus.h>
43e5ec1e72Spatrick 
44e5ec1e72Spatrick #include <dev/pci/pcireg.h>
45e5ec1e72Spatrick #include <dev/pci/pcivar.h>
46e5ec1e72Spatrick #include <dev/pci/pcidevs.h>
47e5ec1e72Spatrick 
48e5ec1e72Spatrick #include <dev/ic/bwfmvar.h>
49e5ec1e72Spatrick #include <dev/ic/bwfmreg.h>
50e5ec1e72Spatrick #include <dev/pci/if_bwfm_pci.h>
51e5ec1e72Spatrick 
52e5ec1e72Spatrick #define BWFM_DMA_D2H_SCRATCH_BUF_LEN		8
53e5ec1e72Spatrick #define BWFM_DMA_D2H_RINGUPD_BUF_LEN		1024
54e5ec1e72Spatrick #define BWFM_DMA_H2D_IOCTL_BUF_LEN		ETHER_MAX_LEN
55e5ec1e72Spatrick 
56e5ec1e72Spatrick #define BWFM_NUM_TX_MSGRINGS			2
57e5ec1e72Spatrick #define BWFM_NUM_RX_MSGRINGS			3
58e5ec1e72Spatrick 
59e5ec1e72Spatrick #define BWFM_NUM_TX_PKTIDS			2048
60e5ec1e72Spatrick #define BWFM_NUM_RX_PKTIDS			1024
61e5ec1e72Spatrick 
62e5ec1e72Spatrick #define BWFM_NUM_TX_DESCS			1
63e5ec1e72Spatrick #define BWFM_NUM_RX_DESCS			1
64e5ec1e72Spatrick 
65e5ec1e72Spatrick #ifdef BWFM_DEBUG
66e5ec1e72Spatrick #define DPRINTF(x)	do { if (bwfm_debug > 0) printf x; } while (0)
67e5ec1e72Spatrick #define DPRINTFN(n, x)	do { if (bwfm_debug >= (n)) printf x; } while (0)
68e5ec1e72Spatrick static int bwfm_debug = 2;
69e5ec1e72Spatrick #else
70e5ec1e72Spatrick #define DPRINTF(x)	do { ; } while (0)
71e5ec1e72Spatrick #define DPRINTFN(n, x)	do { ; } while (0)
72e5ec1e72Spatrick #endif
73e5ec1e72Spatrick 
74e5ec1e72Spatrick #define DEVNAME(sc)	((sc)->sc_sc.sc_dev.dv_xname)
75e5ec1e72Spatrick 
76518be5f3Spatrick enum ring_status {
77518be5f3Spatrick 	RING_CLOSED,
78518be5f3Spatrick 	RING_CLOSING,
79518be5f3Spatrick 	RING_OPEN,
80518be5f3Spatrick 	RING_OPENING,
81518be5f3Spatrick };
82518be5f3Spatrick 
83e5ec1e72Spatrick struct bwfm_pci_msgring {
84e5ec1e72Spatrick 	uint32_t		 w_idx_addr;
85e5ec1e72Spatrick 	uint32_t		 r_idx_addr;
86e5ec1e72Spatrick 	uint32_t		 w_ptr;
87e5ec1e72Spatrick 	uint32_t		 r_ptr;
88e5ec1e72Spatrick 	int			 nitem;
89e5ec1e72Spatrick 	int			 itemsz;
90518be5f3Spatrick 	enum ring_status	 status;
91e5ec1e72Spatrick 	struct bwfm_pci_dmamem	*ring;
9202ee7d07Spatrick 	struct mbuf		*m;
93f67437f3Spatrick 
94f67437f3Spatrick 	int			 fifo;
95f67437f3Spatrick 	uint8_t			 mac[ETHER_ADDR_LEN];
96e5ec1e72Spatrick };
97e5ec1e72Spatrick 
98e5ec1e72Spatrick struct bwfm_pci_buf {
99e5ec1e72Spatrick 	bus_dmamap_t	 bb_map;
100e5ec1e72Spatrick 	struct mbuf	*bb_m;
101e5ec1e72Spatrick };
102e5ec1e72Spatrick 
103e5ec1e72Spatrick struct bwfm_pci_pkts {
104e5ec1e72Spatrick 	struct bwfm_pci_buf	*pkts;
105e5ec1e72Spatrick 	uint32_t		 npkt;
106e5ec1e72Spatrick 	int			 last;
107e5ec1e72Spatrick };
108e5ec1e72Spatrick 
109e5ec1e72Spatrick struct bwfm_pci_softc {
110e5ec1e72Spatrick 	struct bwfm_softc	 sc_sc;
111e5ec1e72Spatrick 	pci_chipset_tag_t	 sc_pc;
112e5ec1e72Spatrick 	pcitag_t		 sc_tag;
113e5ec1e72Spatrick 	pcireg_t		 sc_id;
114e5ec1e72Spatrick 	void 			*sc_ih;
115e5ec1e72Spatrick 
116e5ec1e72Spatrick 	bus_space_tag_t		 sc_reg_iot;
117e5ec1e72Spatrick 	bus_space_handle_t	 sc_reg_ioh;
118e5ec1e72Spatrick 	bus_size_t		 sc_reg_ios;
119e5ec1e72Spatrick 
120e5ec1e72Spatrick 	bus_space_tag_t		 sc_tcm_iot;
121e5ec1e72Spatrick 	bus_space_handle_t	 sc_tcm_ioh;
122e5ec1e72Spatrick 	bus_size_t		 sc_tcm_ios;
123e5ec1e72Spatrick 
124e5ec1e72Spatrick 	bus_dma_tag_t		 sc_dmat;
125e5ec1e72Spatrick 
126e5ec1e72Spatrick 	uint32_t		 sc_shared_address;
127e5ec1e72Spatrick 	uint32_t		 sc_shared_flags;
128e5ec1e72Spatrick 	uint8_t			 sc_shared_version;
129e5ec1e72Spatrick 
130e5ec1e72Spatrick 	uint8_t			 sc_dma_idx_sz;
131e5ec1e72Spatrick 	struct bwfm_pci_dmamem	*sc_dma_idx_buf;
132e5ec1e72Spatrick 	size_t			 sc_dma_idx_bufsz;
133e5ec1e72Spatrick 
134e5ec1e72Spatrick 	uint16_t		 sc_max_rxbufpost;
135e5ec1e72Spatrick 	uint32_t		 sc_rx_dataoffset;
136e5ec1e72Spatrick 	uint32_t		 sc_htod_mb_data_addr;
137e5ec1e72Spatrick 	uint32_t		 sc_dtoh_mb_data_addr;
138e5ec1e72Spatrick 	uint32_t		 sc_ring_info_addr;
139e5ec1e72Spatrick 
140e5ec1e72Spatrick 	uint32_t		 sc_console_base_addr;
141e5ec1e72Spatrick 	uint32_t		 sc_console_buf_addr;
142e5ec1e72Spatrick 	uint32_t		 sc_console_buf_size;
143cadf5fcfSpatrick 	uint32_t		 sc_console_readidx;
144e5ec1e72Spatrick 
145e5ec1e72Spatrick 	uint16_t		 sc_max_flowrings;
146e5ec1e72Spatrick 	uint16_t		 sc_max_submissionrings;
147e5ec1e72Spatrick 	uint16_t		 sc_max_completionrings;
148e5ec1e72Spatrick 
149e5ec1e72Spatrick 	struct bwfm_pci_msgring	 sc_ctrl_submit;
150e5ec1e72Spatrick 	struct bwfm_pci_msgring	 sc_rxpost_submit;
151e5ec1e72Spatrick 	struct bwfm_pci_msgring	 sc_ctrl_complete;
152e5ec1e72Spatrick 	struct bwfm_pci_msgring	 sc_tx_complete;
153e5ec1e72Spatrick 	struct bwfm_pci_msgring	 sc_rx_complete;
154e5ec1e72Spatrick 	struct bwfm_pci_msgring	*sc_flowrings;
155e5ec1e72Spatrick 
156e5ec1e72Spatrick 	struct bwfm_pci_dmamem	*sc_scratch_buf;
157e5ec1e72Spatrick 	struct bwfm_pci_dmamem	*sc_ringupd_buf;
158e5ec1e72Spatrick 
159e5ec1e72Spatrick 	struct bwfm_pci_dmamem	*sc_ioctl_buf;
160e5ec1e72Spatrick 	int			 sc_ioctl_reqid;
161e5ec1e72Spatrick 	uint32_t		 sc_ioctl_resp_pktid;
162e5ec1e72Spatrick 	uint32_t		 sc_ioctl_resp_ret_len;
163e5ec1e72Spatrick 	uint32_t		 sc_ioctl_resp_status;
164e5ec1e72Spatrick 	int			 sc_ioctl_poll;
165e5ec1e72Spatrick 
166e5ec1e72Spatrick 	struct if_rxring	 sc_ioctl_ring;
167e5ec1e72Spatrick 	struct if_rxring	 sc_event_ring;
168e5ec1e72Spatrick 	struct if_rxring	 sc_rxbuf_ring;
169e5ec1e72Spatrick 
170e5ec1e72Spatrick 	struct bwfm_pci_pkts	 sc_rx_pkts;
171c6f1636dSpatrick 	struct bwfm_pci_pkts	 sc_tx_pkts;
172c6f1636dSpatrick 	int			 sc_tx_pkts_full;
173e5ec1e72Spatrick };
174e5ec1e72Spatrick 
175e5ec1e72Spatrick struct bwfm_pci_dmamem {
176e5ec1e72Spatrick 	bus_dmamap_t		bdm_map;
177e5ec1e72Spatrick 	bus_dma_segment_t	bdm_seg;
178e5ec1e72Spatrick 	size_t			bdm_size;
179e5ec1e72Spatrick 	caddr_t			bdm_kva;
180e5ec1e72Spatrick };
181e5ec1e72Spatrick 
182e5ec1e72Spatrick #define BWFM_PCI_DMA_MAP(_bdm)	((_bdm)->bdm_map)
183e5ec1e72Spatrick #define BWFM_PCI_DMA_LEN(_bdm)	((_bdm)->bdm_size)
184e5ec1e72Spatrick #define BWFM_PCI_DMA_DVA(_bdm)	((_bdm)->bdm_map->dm_segs[0].ds_addr)
185e5ec1e72Spatrick #define BWFM_PCI_DMA_KVA(_bdm)	((void *)(_bdm)->bdm_kva)
186e5ec1e72Spatrick 
187e5ec1e72Spatrick int		 bwfm_pci_match(struct device *, void *, void *);
188e5ec1e72Spatrick void		 bwfm_pci_attachhook(struct device *);
189e5ec1e72Spatrick void		 bwfm_pci_attach(struct device *, struct device *, void *);
190e5ec1e72Spatrick int		 bwfm_pci_detach(struct device *, int);
191e5ec1e72Spatrick 
192e5ec1e72Spatrick int		 bwfm_pci_intr(void *);
193e5ec1e72Spatrick void		 bwfm_pci_intr_enable(struct bwfm_pci_softc *);
194e5ec1e72Spatrick void		 bwfm_pci_intr_disable(struct bwfm_pci_softc *);
195e5ec1e72Spatrick int		 bwfm_pci_load_microcode(struct bwfm_pci_softc *, const u_char *,
196e5ec1e72Spatrick 		    size_t);
197e5ec1e72Spatrick void		 bwfm_pci_select_core(struct bwfm_pci_softc *, int );
198e5ec1e72Spatrick 
199e5ec1e72Spatrick struct bwfm_pci_dmamem *
200e5ec1e72Spatrick 		 bwfm_pci_dmamem_alloc(struct bwfm_pci_softc *, bus_size_t,
201e5ec1e72Spatrick 		    bus_size_t);
202e5ec1e72Spatrick void		 bwfm_pci_dmamem_free(struct bwfm_pci_softc *, struct bwfm_pci_dmamem *);
20302ee7d07Spatrick int		 bwfm_pci_pktid_avail(struct bwfm_pci_softc *,
20402ee7d07Spatrick 		    struct bwfm_pci_pkts *);
205e5ec1e72Spatrick int		 bwfm_pci_pktid_new(struct bwfm_pci_softc *,
206e5ec1e72Spatrick 		    struct bwfm_pci_pkts *, struct mbuf *,
207e5ec1e72Spatrick 		    uint32_t *, paddr_t *);
208e5ec1e72Spatrick struct mbuf *	 bwfm_pci_pktid_free(struct bwfm_pci_softc *,
209e5ec1e72Spatrick 		    struct bwfm_pci_pkts *, uint32_t);
210e5ec1e72Spatrick void		 bwfm_pci_fill_rx_ioctl_ring(struct bwfm_pci_softc *,
211e5ec1e72Spatrick 		    struct if_rxring *, uint32_t);
212e5ec1e72Spatrick void		 bwfm_pci_fill_rx_buf_ring(struct bwfm_pci_softc *);
213e5ec1e72Spatrick void		 bwfm_pci_fill_rx_rings(struct bwfm_pci_softc *);
214e5ec1e72Spatrick int		 bwfm_pci_setup_ring(struct bwfm_pci_softc *, struct bwfm_pci_msgring *,
215e5ec1e72Spatrick 		    int, size_t, uint32_t, uint32_t, int, uint32_t, uint32_t *);
216518be5f3Spatrick int		 bwfm_pci_setup_flowring(struct bwfm_pci_softc *, struct bwfm_pci_msgring *,
217518be5f3Spatrick 		    int, size_t);
218e5ec1e72Spatrick 
219e5ec1e72Spatrick void		 bwfm_pci_ring_bell(struct bwfm_pci_softc *,
220e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
221e5ec1e72Spatrick void		 bwfm_pci_ring_update_rptr(struct bwfm_pci_softc *,
222e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
223e5ec1e72Spatrick void		 bwfm_pci_ring_update_wptr(struct bwfm_pci_softc *,
224e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
225e5ec1e72Spatrick void		 bwfm_pci_ring_write_rptr(struct bwfm_pci_softc *,
226e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
227e5ec1e72Spatrick void		 bwfm_pci_ring_write_wptr(struct bwfm_pci_softc *,
228e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
229e5ec1e72Spatrick void *		 bwfm_pci_ring_write_reserve(struct bwfm_pci_softc *,
230e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
231e5ec1e72Spatrick void *		 bwfm_pci_ring_write_reserve_multi(struct bwfm_pci_softc *,
232e5ec1e72Spatrick 		    struct bwfm_pci_msgring *, int, int *);
233e5ec1e72Spatrick void *		 bwfm_pci_ring_read_avail(struct bwfm_pci_softc *,
234e5ec1e72Spatrick 		    struct bwfm_pci_msgring *, int *);
235e5ec1e72Spatrick void		 bwfm_pci_ring_read_commit(struct bwfm_pci_softc *,
236e5ec1e72Spatrick 		    struct bwfm_pci_msgring *, int);
237e5ec1e72Spatrick void		 bwfm_pci_ring_write_commit(struct bwfm_pci_softc *,
238e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
239e5ec1e72Spatrick void		 bwfm_pci_ring_write_cancel(struct bwfm_pci_softc *,
240e5ec1e72Spatrick 		    struct bwfm_pci_msgring *, int);
241e5ec1e72Spatrick 
242e5ec1e72Spatrick void		 bwfm_pci_ring_rx(struct bwfm_pci_softc *,
243e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
244e5ec1e72Spatrick void		 bwfm_pci_msg_rx(struct bwfm_pci_softc *, void *);
245e5ec1e72Spatrick 
246e5ec1e72Spatrick uint32_t	 bwfm_pci_buscore_read(struct bwfm_softc *, uint32_t);
247e5ec1e72Spatrick void		 bwfm_pci_buscore_write(struct bwfm_softc *, uint32_t,
248e5ec1e72Spatrick 		    uint32_t);
249e5ec1e72Spatrick int		 bwfm_pci_buscore_prepare(struct bwfm_softc *);
250e5ec1e72Spatrick int		 bwfm_pci_buscore_reset(struct bwfm_softc *);
251e5ec1e72Spatrick void		 bwfm_pci_buscore_activate(struct bwfm_softc *, uint32_t);
252e5ec1e72Spatrick 
253f67437f3Spatrick int		 bwfm_pci_flowring_lookup(struct bwfm_pci_softc *,
254f67437f3Spatrick 		     struct mbuf *);
255f67437f3Spatrick void		 bwfm_pci_flowring_create(struct bwfm_pci_softc *,
256518be5f3Spatrick 		     struct mbuf *);
257518be5f3Spatrick void		 bwfm_pci_flowring_create_cb(struct bwfm_softc *, void *);
258a2c6ff8bSpatrick void		 bwfm_pci_flowring_delete(struct bwfm_pci_softc *, int);
259518be5f3Spatrick 
260a2c6ff8bSpatrick void		 bwfm_pci_stop(struct bwfm_softc *);
26102ee7d07Spatrick int		 bwfm_pci_txcheck(struct bwfm_softc *);
262e5ec1e72Spatrick int		 bwfm_pci_txdata(struct bwfm_softc *, struct mbuf *);
263bbd71b0bSpatrick 
264bbd71b0bSpatrick #ifdef BWFM_DEBUG
265cadf5fcfSpatrick void		 bwfm_pci_debug_console(struct bwfm_pci_softc *);
266bbd71b0bSpatrick #endif
267e5ec1e72Spatrick 
268e5ec1e72Spatrick int		 bwfm_pci_msgbuf_query_dcmd(struct bwfm_softc *, int,
269e5ec1e72Spatrick 		    int, char *, size_t *);
270e5ec1e72Spatrick int		 bwfm_pci_msgbuf_set_dcmd(struct bwfm_softc *, int,
271e5ec1e72Spatrick 		    int, char *, size_t);
272e5ec1e72Spatrick 
273e5ec1e72Spatrick struct bwfm_buscore_ops bwfm_pci_buscore_ops = {
274e5ec1e72Spatrick 	.bc_read = bwfm_pci_buscore_read,
275e5ec1e72Spatrick 	.bc_write = bwfm_pci_buscore_write,
276e5ec1e72Spatrick 	.bc_prepare = bwfm_pci_buscore_prepare,
277e5ec1e72Spatrick 	.bc_reset = bwfm_pci_buscore_reset,
278e5ec1e72Spatrick 	.bc_setup = NULL,
279e5ec1e72Spatrick 	.bc_activate = bwfm_pci_buscore_activate,
280e5ec1e72Spatrick };
281e5ec1e72Spatrick 
282e5ec1e72Spatrick struct bwfm_bus_ops bwfm_pci_bus_ops = {
283e5ec1e72Spatrick 	.bs_init = NULL,
284a2c6ff8bSpatrick 	.bs_stop = bwfm_pci_stop,
28502ee7d07Spatrick 	.bs_txcheck = bwfm_pci_txcheck,
286e5ec1e72Spatrick 	.bs_txdata = bwfm_pci_txdata,
287e5ec1e72Spatrick 	.bs_txctl = NULL,
288e5ec1e72Spatrick };
289e5ec1e72Spatrick 
290e5ec1e72Spatrick struct bwfm_proto_ops bwfm_pci_msgbuf_ops = {
291e5ec1e72Spatrick 	.proto_query_dcmd = bwfm_pci_msgbuf_query_dcmd,
292e5ec1e72Spatrick 	.proto_set_dcmd = bwfm_pci_msgbuf_set_dcmd,
29314c74651Spatrick 	.proto_rx = NULL,
294*029d6dd5Spatrick 	.proto_rxctl = NULL,
295e5ec1e72Spatrick };
296e5ec1e72Spatrick 
297e5ec1e72Spatrick struct cfattach bwfm_pci_ca = {
298e5ec1e72Spatrick 	sizeof(struct bwfm_pci_softc),
299e5ec1e72Spatrick 	bwfm_pci_match,
300e5ec1e72Spatrick 	bwfm_pci_attach,
301e5ec1e72Spatrick 	bwfm_pci_detach,
302e5ec1e72Spatrick };
303e5ec1e72Spatrick 
304e5ec1e72Spatrick static const struct pci_matchid bwfm_pci_devices[] = {
305e5ec1e72Spatrick 	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM43602 },
30682f0e660Sjcs 	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4350 },
307e5ec1e72Spatrick };
308e5ec1e72Spatrick 
309e5ec1e72Spatrick int
310e5ec1e72Spatrick bwfm_pci_match(struct device *parent, void *match, void *aux)
311e5ec1e72Spatrick {
312e5ec1e72Spatrick 	return (pci_matchbyid(aux, bwfm_pci_devices,
313e5ec1e72Spatrick 	    nitems(bwfm_pci_devices)));
314e5ec1e72Spatrick }
315e5ec1e72Spatrick 
316e5ec1e72Spatrick void
317e5ec1e72Spatrick bwfm_pci_attach(struct device *parent, struct device *self, void *aux)
318e5ec1e72Spatrick {
319e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (struct bwfm_pci_softc *)self;
320e5ec1e72Spatrick 	struct pci_attach_args *pa = (struct pci_attach_args *)aux;
321e5ec1e72Spatrick 	const char *intrstr;
322e5ec1e72Spatrick 	pci_intr_handle_t ih;
323e5ec1e72Spatrick 
324e5ec1e72Spatrick 	if (pci_mapreg_map(pa, PCI_MAPREG_START + 0x00,
325e5ec1e72Spatrick 	    PCI_MAPREG_MEM_TYPE_64BIT, 0, &sc->sc_reg_iot, &sc->sc_reg_ioh,
326e5ec1e72Spatrick 	    NULL, &sc->sc_reg_ios, 0)) {
327e5ec1e72Spatrick 		printf(": can't map bar0\n");
328e5ec1e72Spatrick 		return;
329e5ec1e72Spatrick 	}
330e5ec1e72Spatrick 
331e5ec1e72Spatrick 	if (pci_mapreg_map(pa, PCI_MAPREG_START + 0x08,
332e5ec1e72Spatrick 	    PCI_MAPREG_MEM_TYPE_64BIT, 0, &sc->sc_tcm_iot, &sc->sc_tcm_ioh,
333e5ec1e72Spatrick 	    NULL, &sc->sc_tcm_ios, 0)) {
334e5ec1e72Spatrick 		printf(": can't map bar1\n");
335e5ec1e72Spatrick 		goto bar0;
336e5ec1e72Spatrick 	}
337e5ec1e72Spatrick 
338e5ec1e72Spatrick 	sc->sc_pc = pa->pa_pc;
339e5ec1e72Spatrick 	sc->sc_tag = pa->pa_tag;
340e5ec1e72Spatrick 	sc->sc_id = pa->pa_id;
341e5ec1e72Spatrick 	sc->sc_dmat = pa->pa_dmat;
342e5ec1e72Spatrick 
343e5ec1e72Spatrick 	/* Map and establish the interrupt. */
344e5ec1e72Spatrick 	if (pci_intr_map_msi(pa, &ih) != 0 && pci_intr_map(pa, &ih) != 0) {
345e5ec1e72Spatrick 		printf(": couldn't map interrupt\n");
346e5ec1e72Spatrick 		goto bar1;
347e5ec1e72Spatrick 	}
348e5ec1e72Spatrick 	intrstr = pci_intr_string(pa->pa_pc, ih);
349e5ec1e72Spatrick 
350e5ec1e72Spatrick 	sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_NET | IPL_MPSAFE,
351e5ec1e72Spatrick 	    bwfm_pci_intr, sc, DEVNAME(sc));
352e5ec1e72Spatrick 	if (sc->sc_ih == NULL) {
353e5ec1e72Spatrick 		printf(": couldn't establish interrupt");
354e5ec1e72Spatrick 		if (intrstr != NULL)
355e5ec1e72Spatrick 			printf(" at %s", intrstr);
356e5ec1e72Spatrick 		printf("\n");
357e5ec1e72Spatrick 		goto bar1;
358e5ec1e72Spatrick 	}
359e5ec1e72Spatrick 	printf(": %s\n", intrstr);
360e5ec1e72Spatrick 
361e5ec1e72Spatrick 	config_mountroot(self, bwfm_pci_attachhook);
362e5ec1e72Spatrick 	return;
363e5ec1e72Spatrick 
364e5ec1e72Spatrick bar1:
365e5ec1e72Spatrick 	bus_space_unmap(sc->sc_tcm_iot, sc->sc_tcm_ioh, sc->sc_tcm_ios);
366e5ec1e72Spatrick bar0:
367e5ec1e72Spatrick 	bus_space_unmap(sc->sc_reg_iot, sc->sc_reg_ioh, sc->sc_reg_ios);
368e5ec1e72Spatrick }
369e5ec1e72Spatrick 
370e5ec1e72Spatrick void
371e5ec1e72Spatrick bwfm_pci_attachhook(struct device *self)
372e5ec1e72Spatrick {
373e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (struct bwfm_pci_softc *)self;
374e5ec1e72Spatrick 	struct bwfm_softc *bwfm = (void *)sc;
375e5ec1e72Spatrick 	struct bwfm_pci_ringinfo ringinfo;
376e5ec1e72Spatrick 	const char *name = NULL;
377e5ec1e72Spatrick 	u_char *ucode; size_t size;
378e5ec1e72Spatrick 	uint32_t d2h_w_idx_ptr, d2h_r_idx_ptr;
379e5ec1e72Spatrick 	uint32_t h2d_w_idx_ptr, h2d_r_idx_ptr;
380e5ec1e72Spatrick 	uint32_t idx_offset, reg;
381e5ec1e72Spatrick 	int i;
382e5ec1e72Spatrick 
383e5ec1e72Spatrick 	sc->sc_sc.sc_buscore_ops = &bwfm_pci_buscore_ops;
384e5ec1e72Spatrick 	if (bwfm_chip_attach(&sc->sc_sc) != 0) {
385e5ec1e72Spatrick 		printf("%s: cannot attach chip\n", DEVNAME(sc));
386e5ec1e72Spatrick 		return;
387e5ec1e72Spatrick 	}
388e5ec1e72Spatrick 
389e5ec1e72Spatrick 	bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2);
390e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
391e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_CONFIGADDR, 0x4e0);
392e5ec1e72Spatrick 	reg = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
393e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_CONFIGDATA);
394e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
395e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_CONFIGDATA, reg);
396e5ec1e72Spatrick 
397e5ec1e72Spatrick 	switch (bwfm->sc_chip.ch_chip)
398e5ec1e72Spatrick 	{
39918b3a1dcSpatrick 	case BRCM_CC_4350_CHIP_ID:
40018b3a1dcSpatrick 		if (bwfm->sc_chip.ch_chiprev > 7)
40118b3a1dcSpatrick 			name = "brcmfmac4350-pcie.bin";
40218b3a1dcSpatrick 		else
40318b3a1dcSpatrick 			name = "brcmfmac4350c2-pcie.bin";
40418b3a1dcSpatrick 		break;
405e5ec1e72Spatrick 	case BRCM_CC_43602_CHIP_ID:
406e5ec1e72Spatrick 		name = "brcmfmac43602-pcie.bin";
407e5ec1e72Spatrick 		break;
408e5ec1e72Spatrick 	default:
40918b3a1dcSpatrick 		printf("%s: unknown firmware for chip %s\n",
41018b3a1dcSpatrick 		    DEVNAME(sc), bwfm->sc_chip.ch_name);
411e5ec1e72Spatrick 		return;
412e5ec1e72Spatrick 	}
413e5ec1e72Spatrick 
414e5ec1e72Spatrick 	if (loadfirmware(name, &ucode, &size) != 0) {
415e5ec1e72Spatrick 		printf("%s: failed loadfirmware of file %s\n",
416e5ec1e72Spatrick 		    DEVNAME(sc), name);
417e5ec1e72Spatrick 		return;
418e5ec1e72Spatrick 	}
419e5ec1e72Spatrick 
420e5ec1e72Spatrick 	/* Retrieve RAM size from firmware. */
421e5ec1e72Spatrick 	if (size >= BWFM_RAMSIZE + 8) {
422e5ec1e72Spatrick 		uint32_t *ramsize = (uint32_t *)&ucode[BWFM_RAMSIZE];
423e5ec1e72Spatrick 		if (letoh32(ramsize[0]) == BWFM_RAMSIZE_MAGIC)
424e5ec1e72Spatrick 			bwfm->sc_chip.ch_ramsize = letoh32(ramsize[1]);
425e5ec1e72Spatrick 	}
426e5ec1e72Spatrick 
427e5ec1e72Spatrick 	if (bwfm_pci_load_microcode(sc, ucode, size) != 0) {
428e5ec1e72Spatrick 		printf("%s: could not load microcode\n",
429e5ec1e72Spatrick 		    DEVNAME(sc));
430e5ec1e72Spatrick 		free(ucode, M_DEVBUF, size);
431e5ec1e72Spatrick 		return;
432e5ec1e72Spatrick 	}
433e5ec1e72Spatrick 	free(ucode, M_DEVBUF, size);
434e5ec1e72Spatrick 
435e5ec1e72Spatrick 	sc->sc_shared_flags = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
436e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_INFO);
437e5ec1e72Spatrick 	sc->sc_shared_version = sc->sc_shared_flags;
438e5ec1e72Spatrick 	if (sc->sc_shared_version > BWFM_SHARED_INFO_MAX_VERSION ||
439e5ec1e72Spatrick 	    sc->sc_shared_version < BWFM_SHARED_INFO_MIN_VERSION) {
440e5ec1e72Spatrick 		printf("%s: PCIe version %d unsupported\n",
441e5ec1e72Spatrick 		    DEVNAME(sc), sc->sc_shared_version);
442e5ec1e72Spatrick 		return;
443e5ec1e72Spatrick 	}
444e5ec1e72Spatrick 
445e5ec1e72Spatrick 	if (sc->sc_shared_flags & BWFM_SHARED_INFO_DMA_INDEX) {
446e5ec1e72Spatrick 		if (sc->sc_shared_flags & BWFM_SHARED_INFO_DMA_2B_IDX)
447e5ec1e72Spatrick 			sc->sc_dma_idx_sz = sizeof(uint16_t);
448e5ec1e72Spatrick 		else
449e5ec1e72Spatrick 			sc->sc_dma_idx_sz = sizeof(uint32_t);
450e5ec1e72Spatrick 	}
451e5ec1e72Spatrick 
452e5ec1e72Spatrick 	/* Maximum RX data buffers in the ring. */
453e5ec1e72Spatrick 	sc->sc_max_rxbufpost = bus_space_read_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
454e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_MAX_RXBUFPOST);
455e5ec1e72Spatrick 	if (sc->sc_max_rxbufpost == 0)
456e5ec1e72Spatrick 		sc->sc_max_rxbufpost = BWFM_SHARED_MAX_RXBUFPOST_DEFAULT;
457e5ec1e72Spatrick 
458e5ec1e72Spatrick 	/* Alternative offset of data in a packet */
459e5ec1e72Spatrick 	sc->sc_rx_dataoffset = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
460e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_RX_DATAOFFSET);
461e5ec1e72Spatrick 
462e5ec1e72Spatrick 	/* For Power Management */
463e5ec1e72Spatrick 	sc->sc_htod_mb_data_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
464e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_HTOD_MB_DATA_ADDR);
465e5ec1e72Spatrick 	sc->sc_dtoh_mb_data_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
466e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DTOH_MB_DATA_ADDR);
467e5ec1e72Spatrick 
468e5ec1e72Spatrick 	/* Ring information */
469e5ec1e72Spatrick 	sc->sc_ring_info_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
470e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_RING_INFO_ADDR);
471e5ec1e72Spatrick 
472e5ec1e72Spatrick 	/* Firmware's "dmesg" */
473e5ec1e72Spatrick 	sc->sc_console_base_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
474e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_CONSOLE_ADDR);
475e5ec1e72Spatrick 	sc->sc_console_buf_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
476e5ec1e72Spatrick 	    sc->sc_console_base_addr + BWFM_CONSOLE_BUFADDR);
477e5ec1e72Spatrick 	sc->sc_console_buf_size = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
478e5ec1e72Spatrick 	    sc->sc_console_base_addr + BWFM_CONSOLE_BUFSIZE);
479e5ec1e72Spatrick 
480e5ec1e72Spatrick 	/* Read ring information. */
481e5ec1e72Spatrick 	bus_space_read_region_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
482e5ec1e72Spatrick 	    sc->sc_ring_info_addr, (void *)&ringinfo, sizeof(ringinfo));
483e5ec1e72Spatrick 
484e5ec1e72Spatrick 	if (sc->sc_shared_version >= 6) {
485e5ec1e72Spatrick 		sc->sc_max_submissionrings = le16toh(ringinfo.max_submissionrings);
486e5ec1e72Spatrick 		sc->sc_max_flowrings = le16toh(ringinfo.max_flowrings);
487e5ec1e72Spatrick 		sc->sc_max_completionrings = le16toh(ringinfo.max_completionrings);
488e5ec1e72Spatrick 	} else {
489e5ec1e72Spatrick 		sc->sc_max_submissionrings = le16toh(ringinfo.max_flowrings);
490e5ec1e72Spatrick 		sc->sc_max_flowrings = sc->sc_max_submissionrings -
491e5ec1e72Spatrick 		    BWFM_NUM_TX_MSGRINGS;
492e5ec1e72Spatrick 		sc->sc_max_completionrings = BWFM_NUM_RX_MSGRINGS;
493e5ec1e72Spatrick 	}
494e5ec1e72Spatrick 
495e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
496e5ec1e72Spatrick 		d2h_w_idx_ptr = letoh32(ringinfo.d2h_w_idx_ptr);
497e5ec1e72Spatrick 		d2h_r_idx_ptr = letoh32(ringinfo.d2h_r_idx_ptr);
498e5ec1e72Spatrick 		h2d_w_idx_ptr = letoh32(ringinfo.h2d_w_idx_ptr);
499e5ec1e72Spatrick 		h2d_r_idx_ptr = letoh32(ringinfo.h2d_r_idx_ptr);
500e5ec1e72Spatrick 		idx_offset = sizeof(uint32_t);
501e5ec1e72Spatrick 	} else {
502e5ec1e72Spatrick 		uint64_t address;
503e5ec1e72Spatrick 
504e5ec1e72Spatrick 		/* Each TX/RX Ring has a Read and Write Ptr */
505e5ec1e72Spatrick 		sc->sc_dma_idx_bufsz = (sc->sc_max_submissionrings +
506e5ec1e72Spatrick 		    sc->sc_max_completionrings) * sc->sc_dma_idx_sz * 2;
507e5ec1e72Spatrick 		sc->sc_dma_idx_buf = bwfm_pci_dmamem_alloc(sc,
508e5ec1e72Spatrick 		    sc->sc_dma_idx_bufsz, 8);
509e5ec1e72Spatrick 		if (sc->sc_dma_idx_buf == NULL) {
510e5ec1e72Spatrick 			/* XXX: Fallback to TCM? */
511e5ec1e72Spatrick 			printf("%s: cannot allocate idx buf\n",
512e5ec1e72Spatrick 			    DEVNAME(sc));
513e5ec1e72Spatrick 			return;
514e5ec1e72Spatrick 		}
515e5ec1e72Spatrick 
516e5ec1e72Spatrick 		idx_offset = sc->sc_dma_idx_sz;
517e5ec1e72Spatrick 		h2d_w_idx_ptr = 0;
518e5ec1e72Spatrick 		address = BWFM_PCI_DMA_DVA(sc->sc_dma_idx_buf);
519e5ec1e72Spatrick 		ringinfo.h2d_w_idx_hostaddr_low =
520e5ec1e72Spatrick 		    htole32(address & 0xffffffff);
521e5ec1e72Spatrick 		ringinfo.h2d_w_idx_hostaddr_high =
522e5ec1e72Spatrick 		    htole32(address >> 32);
523e5ec1e72Spatrick 
524e5ec1e72Spatrick 		h2d_r_idx_ptr = h2d_w_idx_ptr +
525e5ec1e72Spatrick 		    sc->sc_max_submissionrings * idx_offset;
526e5ec1e72Spatrick 		address += sc->sc_max_submissionrings * idx_offset;
527e5ec1e72Spatrick 		ringinfo.h2d_r_idx_hostaddr_low =
528e5ec1e72Spatrick 		    htole32(address & 0xffffffff);
529e5ec1e72Spatrick 		ringinfo.h2d_r_idx_hostaddr_high =
530e5ec1e72Spatrick 		    htole32(address >> 32);
531e5ec1e72Spatrick 
532e5ec1e72Spatrick 		d2h_w_idx_ptr = h2d_r_idx_ptr +
533e5ec1e72Spatrick 		    sc->sc_max_submissionrings * idx_offset;
534e5ec1e72Spatrick 		address += sc->sc_max_submissionrings * idx_offset;
535e5ec1e72Spatrick 		ringinfo.d2h_w_idx_hostaddr_low =
536e5ec1e72Spatrick 		    htole32(address & 0xffffffff);
537e5ec1e72Spatrick 		ringinfo.d2h_w_idx_hostaddr_high =
538e5ec1e72Spatrick 		    htole32(address >> 32);
539e5ec1e72Spatrick 
540e5ec1e72Spatrick 		d2h_r_idx_ptr = d2h_w_idx_ptr +
541e5ec1e72Spatrick 		    sc->sc_max_completionrings * idx_offset;
542e5ec1e72Spatrick 		address += sc->sc_max_completionrings * idx_offset;
543e5ec1e72Spatrick 		ringinfo.d2h_r_idx_hostaddr_low =
544e5ec1e72Spatrick 		    htole32(address & 0xffffffff);
545e5ec1e72Spatrick 		ringinfo.d2h_r_idx_hostaddr_high =
546e5ec1e72Spatrick 		    htole32(address >> 32);
547e5ec1e72Spatrick 
548e5ec1e72Spatrick 		bus_space_write_region_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
549e5ec1e72Spatrick 		    sc->sc_ring_info_addr, (void *)&ringinfo, sizeof(ringinfo));
550e5ec1e72Spatrick 	}
551e5ec1e72Spatrick 
552e5ec1e72Spatrick 	uint32_t ring_mem_ptr = letoh32(ringinfo.ringmem);
553e5ec1e72Spatrick 	/* TX ctrl ring: Send ctrl buffers, send IOCTLs */
554e5ec1e72Spatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_ctrl_submit, 64, 40,
555e5ec1e72Spatrick 	    h2d_w_idx_ptr, h2d_r_idx_ptr, 0, idx_offset,
556e5ec1e72Spatrick 	    &ring_mem_ptr))
557e5ec1e72Spatrick 		goto cleanup;
558e5ec1e72Spatrick 	/* TX rxpost ring: Send clean data mbufs for RX */
559e5ec1e72Spatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_rxpost_submit, 512, 32,
560e5ec1e72Spatrick 	    h2d_w_idx_ptr, h2d_r_idx_ptr, 1, idx_offset,
561e5ec1e72Spatrick 	    &ring_mem_ptr))
562e5ec1e72Spatrick 		goto cleanup;
563e5ec1e72Spatrick 	/* RX completion rings: recv our filled buffers back */
564e5ec1e72Spatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_ctrl_complete, 64, 24,
565e5ec1e72Spatrick 	    d2h_w_idx_ptr, d2h_r_idx_ptr, 0, idx_offset,
566e5ec1e72Spatrick 	    &ring_mem_ptr))
567e5ec1e72Spatrick 		goto cleanup;
568e5ec1e72Spatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_tx_complete, 1024, 16,
569e5ec1e72Spatrick 	    d2h_w_idx_ptr, d2h_r_idx_ptr, 1, idx_offset,
570e5ec1e72Spatrick 	    &ring_mem_ptr))
571e5ec1e72Spatrick 		goto cleanup;
572e5ec1e72Spatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_rx_complete, 512, 32,
573e5ec1e72Spatrick 	    d2h_w_idx_ptr, d2h_r_idx_ptr, 2, idx_offset,
574e5ec1e72Spatrick 	    &ring_mem_ptr))
575e5ec1e72Spatrick 		goto cleanup;
576e5ec1e72Spatrick 
577e5ec1e72Spatrick 	/* Dynamic TX rings for actual data */
578e5ec1e72Spatrick 	sc->sc_flowrings = malloc(sc->sc_max_flowrings *
579e5ec1e72Spatrick 	    sizeof(struct bwfm_pci_msgring), M_DEVBUF, M_WAITOK | M_ZERO);
580518be5f3Spatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
581518be5f3Spatrick 		struct bwfm_pci_msgring *ring = &sc->sc_flowrings[i];
582518be5f3Spatrick 		ring->w_idx_addr = h2d_w_idx_ptr + (i + 2) * idx_offset;
583518be5f3Spatrick 		ring->r_idx_addr = h2d_r_idx_ptr + (i + 2) * idx_offset;
584518be5f3Spatrick 	}
585e5ec1e72Spatrick 
586e5ec1e72Spatrick 	/* Scratch and ring update buffers for firmware */
587e5ec1e72Spatrick 	if ((sc->sc_scratch_buf = bwfm_pci_dmamem_alloc(sc,
588e5ec1e72Spatrick 	    BWFM_DMA_D2H_SCRATCH_BUF_LEN, 8)) == NULL)
589e5ec1e72Spatrick 		goto cleanup;
590e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
591e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_SCRATCH_ADDR_LOW,
592e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(sc->sc_scratch_buf) & 0xffffffff);
593e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
594e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_SCRATCH_ADDR_HIGH,
595e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(sc->sc_scratch_buf) >> 32);
596e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
597e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_SCRATCH_LEN,
598e5ec1e72Spatrick 	    BWFM_DMA_D2H_SCRATCH_BUF_LEN);
599e5ec1e72Spatrick 
600e5ec1e72Spatrick 	if ((sc->sc_ringupd_buf = bwfm_pci_dmamem_alloc(sc,
601e5ec1e72Spatrick 	    BWFM_DMA_D2H_RINGUPD_BUF_LEN, 8)) == NULL)
602e5ec1e72Spatrick 		goto cleanup;
603e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
604e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_RINGUPD_ADDR_LOW,
605e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(sc->sc_ringupd_buf) & 0xffffffff);
606e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
607e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_RINGUPD_ADDR_HIGH,
608e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(sc->sc_ringupd_buf) >> 32);
609e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
610e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_RINGUPD_LEN,
611e5ec1e72Spatrick 	    BWFM_DMA_D2H_RINGUPD_BUF_LEN);
612e5ec1e72Spatrick 
613e5ec1e72Spatrick 	if ((sc->sc_ioctl_buf = bwfm_pci_dmamem_alloc(sc,
614e5ec1e72Spatrick 	    BWFM_DMA_H2D_IOCTL_BUF_LEN, 8)) == NULL)
615e5ec1e72Spatrick 		goto cleanup;
616e5ec1e72Spatrick 
617e5ec1e72Spatrick 	bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2);
618e5ec1e72Spatrick 	bwfm_pci_intr_enable(sc);
619e5ec1e72Spatrick 
620e5ec1e72Spatrick 	/* Maps RX mbufs to a packet id and back. */
621e5ec1e72Spatrick 	sc->sc_rx_pkts.npkt = BWFM_NUM_RX_PKTIDS;
622e5ec1e72Spatrick 	sc->sc_rx_pkts.pkts = malloc(BWFM_NUM_RX_PKTIDS *
623e5ec1e72Spatrick 	    sizeof(struct bwfm_pci_buf), M_DEVBUF, M_WAITOK | M_ZERO);
624e5ec1e72Spatrick 	for (i = 0; i < BWFM_NUM_RX_PKTIDS; i++)
625e5ec1e72Spatrick 		bus_dmamap_create(sc->sc_dmat, MSGBUF_MAX_PKT_SIZE,
626e5ec1e72Spatrick 		    BWFM_NUM_RX_DESCS, MSGBUF_MAX_PKT_SIZE, 0, BUS_DMA_WAITOK,
627e5ec1e72Spatrick 		    &sc->sc_rx_pkts.pkts[i].bb_map);
628e5ec1e72Spatrick 
629e5ec1e72Spatrick 	/* Maps TX mbufs to a packet id and back. */
630f416501bSpatrick 	sc->sc_tx_pkts.npkt = BWFM_NUM_TX_PKTIDS;
631e5ec1e72Spatrick 	sc->sc_tx_pkts.pkts = malloc(BWFM_NUM_TX_PKTIDS
632e5ec1e72Spatrick 	    * sizeof(struct bwfm_pci_buf), M_DEVBUF, M_WAITOK | M_ZERO);
633e5ec1e72Spatrick 	for (i = 0; i < BWFM_NUM_TX_PKTIDS; i++)
634e5ec1e72Spatrick 		bus_dmamap_create(sc->sc_dmat, MSGBUF_MAX_PKT_SIZE,
635e5ec1e72Spatrick 		    BWFM_NUM_TX_DESCS, MSGBUF_MAX_PKT_SIZE, 0, BUS_DMA_WAITOK,
636e5ec1e72Spatrick 		    &sc->sc_tx_pkts.pkts[i].bb_map);
637e5ec1e72Spatrick 
63818722113Spatrick 	/*
63918722113Spatrick 	 * For whatever reason, could also be a bug somewhere in this
64018722113Spatrick 	 * driver, the firmware needs a bunch of RX buffers otherwise
64118722113Spatrick 	 * it won't send any RX complete messages.  64 buffers don't
64218722113Spatrick 	 * suffice, but 128 buffers are enough.
64318722113Spatrick 	 */
64418722113Spatrick 	if_rxr_init(&sc->sc_rxbuf_ring, 128, sc->sc_max_rxbufpost);
645e5ec1e72Spatrick 	if_rxr_init(&sc->sc_ioctl_ring, 8, 8);
646e5ec1e72Spatrick 	if_rxr_init(&sc->sc_event_ring, 8, 8);
647e5ec1e72Spatrick 	bwfm_pci_fill_rx_rings(sc);
648e5ec1e72Spatrick 
649cadf5fcfSpatrick #ifdef BWFM_DEBUG
650cadf5fcfSpatrick 	sc->sc_console_readidx = 0;
651cadf5fcfSpatrick 	bwfm_pci_debug_console(sc);
652cadf5fcfSpatrick #endif
653cadf5fcfSpatrick 
654e5ec1e72Spatrick 	sc->sc_ioctl_poll = 1;
655e5ec1e72Spatrick 	sc->sc_sc.sc_bus_ops = &bwfm_pci_bus_ops;
656e5ec1e72Spatrick 	sc->sc_sc.sc_proto_ops = &bwfm_pci_msgbuf_ops;
657e5ec1e72Spatrick 	bwfm_attach(&sc->sc_sc);
658e5ec1e72Spatrick 	sc->sc_ioctl_poll = 0;
659e5ec1e72Spatrick 	return;
660e5ec1e72Spatrick 
661e5ec1e72Spatrick cleanup:
662e5ec1e72Spatrick 	if (sc->sc_ioctl_buf)
663e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_ioctl_buf);
664e5ec1e72Spatrick 	if (sc->sc_ringupd_buf)
665e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_ringupd_buf);
666e5ec1e72Spatrick 	if (sc->sc_scratch_buf)
667e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_scratch_buf);
668e5ec1e72Spatrick 	if (sc->sc_rx_complete.ring)
669e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_rx_complete.ring);
670e5ec1e72Spatrick 	if (sc->sc_tx_complete.ring)
671e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_tx_complete.ring);
672e5ec1e72Spatrick 	if (sc->sc_ctrl_complete.ring)
673e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_ctrl_complete.ring);
674e5ec1e72Spatrick 	if (sc->sc_rxpost_submit.ring)
675e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_rxpost_submit.ring);
676e5ec1e72Spatrick 	if (sc->sc_ctrl_submit.ring)
677e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_ctrl_submit.ring);
678e5ec1e72Spatrick 	if (sc->sc_dma_idx_buf)
679e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_dma_idx_buf);
680e5ec1e72Spatrick }
681e5ec1e72Spatrick 
682e5ec1e72Spatrick int
683e5ec1e72Spatrick bwfm_pci_load_microcode(struct bwfm_pci_softc *sc, const u_char *ucode, size_t size)
684e5ec1e72Spatrick {
685e5ec1e72Spatrick 	struct bwfm_softc *bwfm = (void *)sc;
686e5ec1e72Spatrick 	struct bwfm_core *core;
687e5ec1e72Spatrick 	uint32_t shared;
688e5ec1e72Spatrick 	int i;
689e5ec1e72Spatrick 
690e5ec1e72Spatrick 	if (bwfm->sc_chip.ch_chip == BRCM_CC_43602_CHIP_ID) {
691e5ec1e72Spatrick 		bwfm_pci_select_core(sc, BWFM_AGENT_CORE_ARM_CR4);
692e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
693e5ec1e72Spatrick 		    BWFM_PCI_ARMCR4REG_BANKIDX, 5);
694e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
695e5ec1e72Spatrick 		    BWFM_PCI_ARMCR4REG_BANKPDA, 0);
696e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
697e5ec1e72Spatrick 		    BWFM_PCI_ARMCR4REG_BANKIDX, 7);
698e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
699e5ec1e72Spatrick 		    BWFM_PCI_ARMCR4REG_BANKPDA, 0);
700e5ec1e72Spatrick 	}
701e5ec1e72Spatrick 
702e5ec1e72Spatrick 	for (i = 0; i < size; i++)
703e5ec1e72Spatrick 		bus_space_write_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
704e5ec1e72Spatrick 		    bwfm->sc_chip.ch_rambase + i, ucode[i]);
705e5ec1e72Spatrick 
706e5ec1e72Spatrick 	/* Firmware replaces this with a pointer once up. */
707e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
708e5ec1e72Spatrick 	    bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize - 4, 0);
709e5ec1e72Spatrick 
710e5ec1e72Spatrick 	/* TODO: restore NVRAM */
711e5ec1e72Spatrick 
712e5ec1e72Spatrick 	/* Load reset vector from firmware and kickstart core. */
713b0cd4990Spatrick 	if (bwfm->sc_chip.ch_chip == BRCM_CC_43602_CHIP_ID) {
714e5ec1e72Spatrick 		core = bwfm_chip_get_core(bwfm, BWFM_AGENT_INTERNAL_MEM);
715e5ec1e72Spatrick 		bwfm->sc_chip.ch_core_reset(bwfm, core, 0, 0, 0);
716b0cd4990Spatrick 	}
717e5ec1e72Spatrick 	bwfm_chip_set_active(bwfm, *(uint32_t *)ucode);
718e5ec1e72Spatrick 
719e5ec1e72Spatrick 	for (i = 0; i < 40; i++) {
720e5ec1e72Spatrick 		delay(50 * 1000);
721e5ec1e72Spatrick 		shared = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
722e5ec1e72Spatrick 		    bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize - 4);
723e5ec1e72Spatrick 		if (shared)
724e5ec1e72Spatrick 			break;
725e5ec1e72Spatrick 	}
726e5ec1e72Spatrick 	if (!shared) {
727e5ec1e72Spatrick 		printf("%s: firmware did not come up\n", DEVNAME(sc));
728e5ec1e72Spatrick 		return 1;
729e5ec1e72Spatrick 	}
730e5ec1e72Spatrick 
731e5ec1e72Spatrick 	sc->sc_shared_address = shared;
732e5ec1e72Spatrick 	return 0;
733e5ec1e72Spatrick }
734e5ec1e72Spatrick 
735e5ec1e72Spatrick int
736e5ec1e72Spatrick bwfm_pci_detach(struct device *self, int flags)
737e5ec1e72Spatrick {
738e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (struct bwfm_pci_softc *)self;
739e5ec1e72Spatrick 
740e5ec1e72Spatrick 	bwfm_detach(&sc->sc_sc, flags);
741e5ec1e72Spatrick 
742e5ec1e72Spatrick 	/* FIXME: free RX buffers */
743e5ec1e72Spatrick 	/* FIXME: free TX buffers */
744e5ec1e72Spatrick 	/* FIXME: free more memory */
745e5ec1e72Spatrick 
746e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_ioctl_buf);
747e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_ringupd_buf);
748e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_scratch_buf);
749e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_rx_complete.ring);
750e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_tx_complete.ring);
751e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_ctrl_complete.ring);
752e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_rxpost_submit.ring);
753e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_ctrl_submit.ring);
754e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_dma_idx_buf);
755e5ec1e72Spatrick 	return 0;
756e5ec1e72Spatrick }
757e5ec1e72Spatrick 
758e5ec1e72Spatrick /* DMA code */
759e5ec1e72Spatrick struct bwfm_pci_dmamem *
760e5ec1e72Spatrick bwfm_pci_dmamem_alloc(struct bwfm_pci_softc *sc, bus_size_t size, bus_size_t align)
761e5ec1e72Spatrick {
762e5ec1e72Spatrick 	struct bwfm_pci_dmamem *bdm;
763e5ec1e72Spatrick 	int nsegs;
764e5ec1e72Spatrick 
765e5ec1e72Spatrick 	bdm = malloc(sizeof(*bdm), M_DEVBUF, M_WAITOK | M_ZERO);
766e5ec1e72Spatrick 	bdm->bdm_size = size;
767e5ec1e72Spatrick 
768e5ec1e72Spatrick 	if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
769e5ec1e72Spatrick 	    BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &bdm->bdm_map) != 0)
770e5ec1e72Spatrick 		goto bdmfree;
771e5ec1e72Spatrick 
772e5ec1e72Spatrick 	if (bus_dmamem_alloc(sc->sc_dmat, size, align, 0, &bdm->bdm_seg, 1,
773e5ec1e72Spatrick 	    &nsegs, BUS_DMA_WAITOK) != 0)
774e5ec1e72Spatrick 		goto destroy;
775e5ec1e72Spatrick 
776e5ec1e72Spatrick 	if (bus_dmamem_map(sc->sc_dmat, &bdm->bdm_seg, nsegs, size,
777e5ec1e72Spatrick 	    &bdm->bdm_kva, BUS_DMA_WAITOK | BUS_DMA_COHERENT) != 0)
778e5ec1e72Spatrick 		goto free;
779e5ec1e72Spatrick 
780e5ec1e72Spatrick 	if (bus_dmamap_load(sc->sc_dmat, bdm->bdm_map, bdm->bdm_kva, size,
781e5ec1e72Spatrick 	    NULL, BUS_DMA_WAITOK) != 0)
782e5ec1e72Spatrick 		goto unmap;
783e5ec1e72Spatrick 
784e5ec1e72Spatrick 	bzero(bdm->bdm_kva, size);
785e5ec1e72Spatrick 
786e5ec1e72Spatrick 	return (bdm);
787e5ec1e72Spatrick 
788e5ec1e72Spatrick unmap:
789e5ec1e72Spatrick 	bus_dmamem_unmap(sc->sc_dmat, bdm->bdm_kva, size);
790e5ec1e72Spatrick free:
791e5ec1e72Spatrick 	bus_dmamem_free(sc->sc_dmat, &bdm->bdm_seg, 1);
792e5ec1e72Spatrick destroy:
793e5ec1e72Spatrick 	bus_dmamap_destroy(sc->sc_dmat, bdm->bdm_map);
794e5ec1e72Spatrick bdmfree:
79565046b40Spatrick 	free(bdm, M_DEVBUF, sizeof(*bdm));
796e5ec1e72Spatrick 
797e5ec1e72Spatrick 	return (NULL);
798e5ec1e72Spatrick }
799e5ec1e72Spatrick 
800e5ec1e72Spatrick void
801e5ec1e72Spatrick bwfm_pci_dmamem_free(struct bwfm_pci_softc *sc, struct bwfm_pci_dmamem *bdm)
802e5ec1e72Spatrick {
803e5ec1e72Spatrick 	bus_dmamem_unmap(sc->sc_dmat, bdm->bdm_kva, bdm->bdm_size);
804e5ec1e72Spatrick 	bus_dmamem_free(sc->sc_dmat, &bdm->bdm_seg, 1);
805e5ec1e72Spatrick 	bus_dmamap_destroy(sc->sc_dmat, bdm->bdm_map);
80665046b40Spatrick 	free(bdm, M_DEVBUF, sizeof(*bdm));
807e5ec1e72Spatrick }
808e5ec1e72Spatrick 
809e5ec1e72Spatrick /*
810e5ec1e72Spatrick  * We need a simple mapping from a packet ID to mbufs, because when
811e5ec1e72Spatrick  * a transfer completed, we only know the ID so we have to look up
812e5ec1e72Spatrick  * the memory for the ID.  This simply looks for an empty slot.
813e5ec1e72Spatrick  */
814e5ec1e72Spatrick int
81502ee7d07Spatrick bwfm_pci_pktid_avail(struct bwfm_pci_softc *sc, struct bwfm_pci_pkts *pkts)
81602ee7d07Spatrick {
81702ee7d07Spatrick 	int i, idx;
81802ee7d07Spatrick 
81902ee7d07Spatrick 	idx = pkts->last + 1;
82002ee7d07Spatrick 	for (i = 0; i < pkts->npkt; i++) {
82102ee7d07Spatrick 		if (idx == pkts->npkt)
82202ee7d07Spatrick 			idx = 0;
82302ee7d07Spatrick 		if (pkts->pkts[idx].bb_m == NULL)
82402ee7d07Spatrick 			return 0;
82502ee7d07Spatrick 		idx++;
82602ee7d07Spatrick 	}
82702ee7d07Spatrick 	return ENOBUFS;
82802ee7d07Spatrick }
82902ee7d07Spatrick 
83002ee7d07Spatrick int
831e5ec1e72Spatrick bwfm_pci_pktid_new(struct bwfm_pci_softc *sc, struct bwfm_pci_pkts *pkts,
832e5ec1e72Spatrick     struct mbuf *m, uint32_t *pktid, paddr_t *paddr)
833e5ec1e72Spatrick {
834e5ec1e72Spatrick 	int i, idx;
835e5ec1e72Spatrick 
836e5ec1e72Spatrick 	idx = pkts->last + 1;
837e5ec1e72Spatrick 	for (i = 0; i < pkts->npkt; i++) {
838e5ec1e72Spatrick 		if (idx == pkts->npkt)
839e5ec1e72Spatrick 			idx = 0;
840e5ec1e72Spatrick 		if (pkts->pkts[idx].bb_m == NULL) {
841e5ec1e72Spatrick 			if (bus_dmamap_load_mbuf(sc->sc_dmat,
842e5ec1e72Spatrick 			    pkts->pkts[idx].bb_map, m, BUS_DMA_NOWAIT) != 0) {
843518be5f3Spatrick 				if (m_defrag(m, M_DONTWAIT))
844518be5f3Spatrick 					return EFBIG;
845518be5f3Spatrick 				if (bus_dmamap_load_mbuf(sc->sc_dmat,
846518be5f3Spatrick 				    pkts->pkts[idx].bb_map, m, BUS_DMA_NOWAIT) != 0)
847518be5f3Spatrick 					return EFBIG;
848e5ec1e72Spatrick 			}
849e5ec1e72Spatrick 			pkts->last = idx;
850e5ec1e72Spatrick 			pkts->pkts[idx].bb_m = m;
851e5ec1e72Spatrick 			*pktid = idx;
852e5ec1e72Spatrick 			*paddr = pkts->pkts[idx].bb_map->dm_segs[0].ds_addr;
853e5ec1e72Spatrick 			return 0;
854e5ec1e72Spatrick 		}
855e5ec1e72Spatrick 		idx++;
856e5ec1e72Spatrick 	}
857518be5f3Spatrick 	return ENOBUFS;
858e5ec1e72Spatrick }
859e5ec1e72Spatrick 
860e5ec1e72Spatrick struct mbuf *
861e5ec1e72Spatrick bwfm_pci_pktid_free(struct bwfm_pci_softc *sc, struct bwfm_pci_pkts *pkts,
862e5ec1e72Spatrick     uint32_t pktid)
863e5ec1e72Spatrick {
864e5ec1e72Spatrick 	struct mbuf *m;
865e5ec1e72Spatrick 
866e5ec1e72Spatrick 	if (pktid >= pkts->npkt || pkts->pkts[pktid].bb_m == NULL)
867e5ec1e72Spatrick 		return NULL;
868e5ec1e72Spatrick 	bus_dmamap_unload(sc->sc_dmat, pkts->pkts[pktid].bb_map);
869e5ec1e72Spatrick 	m = pkts->pkts[pktid].bb_m;
870e5ec1e72Spatrick 	pkts->pkts[pktid].bb_m = NULL;
871e5ec1e72Spatrick 	return m;
872e5ec1e72Spatrick }
873e5ec1e72Spatrick 
874e5ec1e72Spatrick void
875e5ec1e72Spatrick bwfm_pci_fill_rx_rings(struct bwfm_pci_softc *sc)
876e5ec1e72Spatrick {
87718722113Spatrick 	bwfm_pci_fill_rx_buf_ring(sc);
878e5ec1e72Spatrick 	bwfm_pci_fill_rx_ioctl_ring(sc, &sc->sc_ioctl_ring,
879e5ec1e72Spatrick 	    MSGBUF_TYPE_IOCTLRESP_BUF_POST);
880e5ec1e72Spatrick 	bwfm_pci_fill_rx_ioctl_ring(sc, &sc->sc_event_ring,
881e5ec1e72Spatrick 	    MSGBUF_TYPE_EVENT_BUF_POST);
882e5ec1e72Spatrick }
883e5ec1e72Spatrick 
884e5ec1e72Spatrick void
885e5ec1e72Spatrick bwfm_pci_fill_rx_ioctl_ring(struct bwfm_pci_softc *sc, struct if_rxring *rxring,
886e5ec1e72Spatrick     uint32_t msgtype)
887e5ec1e72Spatrick {
888e5ec1e72Spatrick 	struct msgbuf_rx_ioctl_resp_or_event *req;
889e5ec1e72Spatrick 	struct mbuf *m;
890e5ec1e72Spatrick 	uint32_t pktid;
891e5ec1e72Spatrick 	paddr_t paddr;
892e5ec1e72Spatrick 	int s, slots;
893e5ec1e72Spatrick 
894e5ec1e72Spatrick 	s = splnet();
895e5ec1e72Spatrick 	for (slots = if_rxr_get(rxring, 8); slots > 0; slots--) {
89602ee7d07Spatrick 		if (bwfm_pci_pktid_avail(sc, &sc->sc_rx_pkts))
89702ee7d07Spatrick 			break;
898e5ec1e72Spatrick 		req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit);
899e5ec1e72Spatrick 		if (req == NULL)
900e5ec1e72Spatrick 			break;
901e5ec1e72Spatrick 		m = MCLGETI(NULL, M_DONTWAIT, NULL, MSGBUF_MAX_PKT_SIZE);
902e5ec1e72Spatrick 		if (m == NULL) {
903e5ec1e72Spatrick 			bwfm_pci_ring_write_cancel(sc, &sc->sc_ctrl_submit, 1);
904e5ec1e72Spatrick 			break;
905e5ec1e72Spatrick 		}
906e5ec1e72Spatrick 		m->m_len = m->m_pkthdr.len = MSGBUF_MAX_PKT_SIZE;
907e5ec1e72Spatrick 		if (bwfm_pci_pktid_new(sc, &sc->sc_rx_pkts, m, &pktid, &paddr)) {
908e5ec1e72Spatrick 			bwfm_pci_ring_write_cancel(sc, &sc->sc_ctrl_submit, 1);
909e5ec1e72Spatrick 			m_freem(m);
910e5ec1e72Spatrick 			break;
911e5ec1e72Spatrick 		}
912e5ec1e72Spatrick 		memset(req, 0, sizeof(*req));
913e5ec1e72Spatrick 		req->msg.msgtype = msgtype;
914e5ec1e72Spatrick 		req->msg.request_id = htole32(pktid);
915e5ec1e72Spatrick 		req->host_buf_len = htole16(MSGBUF_MAX_PKT_SIZE);
916e5ec1e72Spatrick 		req->host_buf_addr.high_addr = htole32(paddr >> 32);
917e5ec1e72Spatrick 		req->host_buf_addr.low_addr = htole32(paddr & 0xffffffff);
918e5ec1e72Spatrick 		bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit);
919e5ec1e72Spatrick 	}
920e5ec1e72Spatrick 	if_rxr_put(rxring, slots);
921e5ec1e72Spatrick 	splx(s);
922e5ec1e72Spatrick }
923e5ec1e72Spatrick 
924e5ec1e72Spatrick void
925e5ec1e72Spatrick bwfm_pci_fill_rx_buf_ring(struct bwfm_pci_softc *sc)
926e5ec1e72Spatrick {
927e5ec1e72Spatrick 	struct msgbuf_rx_bufpost *req;
928e5ec1e72Spatrick 	struct mbuf *m;
929e5ec1e72Spatrick 	uint32_t pktid;
930e5ec1e72Spatrick 	paddr_t paddr;
931e5ec1e72Spatrick 	int s, slots;
932e5ec1e72Spatrick 
933e5ec1e72Spatrick 	s = splnet();
934e5ec1e72Spatrick 	for (slots = if_rxr_get(&sc->sc_rxbuf_ring, sc->sc_max_rxbufpost);
935e5ec1e72Spatrick 	    slots > 0; slots--) {
93602ee7d07Spatrick 		if (bwfm_pci_pktid_avail(sc, &sc->sc_rx_pkts))
93702ee7d07Spatrick 			break;
938e5ec1e72Spatrick 		req = bwfm_pci_ring_write_reserve(sc, &sc->sc_rxpost_submit);
939e5ec1e72Spatrick 		if (req == NULL)
940e5ec1e72Spatrick 			break;
941e5ec1e72Spatrick 		m = MCLGETI(NULL, M_DONTWAIT, NULL, MSGBUF_MAX_PKT_SIZE);
942e5ec1e72Spatrick 		if (m == NULL) {
943e5ec1e72Spatrick 			bwfm_pci_ring_write_cancel(sc, &sc->sc_rxpost_submit, 1);
944e5ec1e72Spatrick 			break;
945e5ec1e72Spatrick 		}
946e5ec1e72Spatrick 		m->m_len = m->m_pkthdr.len = MSGBUF_MAX_PKT_SIZE;
947e5ec1e72Spatrick 		if (bwfm_pci_pktid_new(sc, &sc->sc_rx_pkts, m, &pktid, &paddr)) {
948e5ec1e72Spatrick 			bwfm_pci_ring_write_cancel(sc, &sc->sc_rxpost_submit, 1);
949e5ec1e72Spatrick 			m_freem(m);
950e5ec1e72Spatrick 			break;
951e5ec1e72Spatrick 		}
952e5ec1e72Spatrick 		memset(req, 0, sizeof(*req));
953e5ec1e72Spatrick 		req->msg.msgtype = MSGBUF_TYPE_RXBUF_POST;
954e5ec1e72Spatrick 		req->msg.request_id = htole32(pktid);
955e5ec1e72Spatrick 		req->data_buf_len = htole16(MSGBUF_MAX_PKT_SIZE);
956e5ec1e72Spatrick 		req->data_buf_addr.high_addr = htole32(paddr >> 32);
957e5ec1e72Spatrick 		req->data_buf_addr.low_addr = htole32(paddr & 0xffffffff);
958e5ec1e72Spatrick 		bwfm_pci_ring_write_commit(sc, &sc->sc_rxpost_submit);
959e5ec1e72Spatrick 	}
960e5ec1e72Spatrick 	if_rxr_put(&sc->sc_rxbuf_ring, slots);
961e5ec1e72Spatrick 	splx(s);
962e5ec1e72Spatrick }
963e5ec1e72Spatrick 
964e5ec1e72Spatrick int
965e5ec1e72Spatrick bwfm_pci_setup_ring(struct bwfm_pci_softc *sc, struct bwfm_pci_msgring *ring,
966e5ec1e72Spatrick     int nitem, size_t itemsz, uint32_t w_idx, uint32_t r_idx,
967e5ec1e72Spatrick     int idx, uint32_t idx_off, uint32_t *ring_mem)
968e5ec1e72Spatrick {
969e5ec1e72Spatrick 	ring->w_idx_addr = w_idx + idx * idx_off;
970e5ec1e72Spatrick 	ring->r_idx_addr = r_idx + idx * idx_off;
971e5ec1e72Spatrick 	ring->nitem = nitem;
972e5ec1e72Spatrick 	ring->itemsz = itemsz;
973e5ec1e72Spatrick 	bwfm_pci_ring_write_rptr(sc, ring);
974e5ec1e72Spatrick 	bwfm_pci_ring_write_wptr(sc, ring);
975e5ec1e72Spatrick 
976e5ec1e72Spatrick 	ring->ring = bwfm_pci_dmamem_alloc(sc, nitem * itemsz, 8);
977e5ec1e72Spatrick 	if (ring->ring == NULL)
978e5ec1e72Spatrick 		return ENOMEM;
979e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
980e5ec1e72Spatrick 	    *ring_mem + BWFM_RING_MEM_BASE_ADDR_LOW,
981e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(ring->ring) & 0xffffffff);
982e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
983e5ec1e72Spatrick 	    *ring_mem + BWFM_RING_MEM_BASE_ADDR_HIGH,
984e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(ring->ring) >> 32);
985e5ec1e72Spatrick 	bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
986e5ec1e72Spatrick 	    *ring_mem + BWFM_RING_MAX_ITEM, nitem);
987e5ec1e72Spatrick 	bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
988e5ec1e72Spatrick 	    *ring_mem + BWFM_RING_LEN_ITEMS, itemsz);
989e5ec1e72Spatrick 	*ring_mem = *ring_mem + BWFM_RING_MEM_SZ;
990e5ec1e72Spatrick 	return 0;
991e5ec1e72Spatrick }
992e5ec1e72Spatrick 
993518be5f3Spatrick int
994518be5f3Spatrick bwfm_pci_setup_flowring(struct bwfm_pci_softc *sc, struct bwfm_pci_msgring *ring,
995518be5f3Spatrick     int nitem, size_t itemsz)
996518be5f3Spatrick {
997518be5f3Spatrick 	ring->w_ptr = 0;
998518be5f3Spatrick 	ring->r_ptr = 0;
999518be5f3Spatrick 	ring->nitem = nitem;
1000518be5f3Spatrick 	ring->itemsz = itemsz;
1001518be5f3Spatrick 	bwfm_pci_ring_write_rptr(sc, ring);
1002518be5f3Spatrick 	bwfm_pci_ring_write_wptr(sc, ring);
1003518be5f3Spatrick 
1004518be5f3Spatrick 	ring->ring = bwfm_pci_dmamem_alloc(sc, nitem * itemsz, 8);
1005518be5f3Spatrick 	if (ring->ring == NULL)
1006518be5f3Spatrick 		return ENOMEM;
1007518be5f3Spatrick 	return 0;
1008518be5f3Spatrick }
1009518be5f3Spatrick 
1010e5ec1e72Spatrick /* Ring helpers */
1011e5ec1e72Spatrick void
1012e5ec1e72Spatrick bwfm_pci_ring_bell(struct bwfm_pci_softc *sc,
1013e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1014e5ec1e72Spatrick {
1015e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1016e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_H2D_MAILBOX, 1);
1017e5ec1e72Spatrick }
1018e5ec1e72Spatrick 
1019e5ec1e72Spatrick void
1020e5ec1e72Spatrick bwfm_pci_ring_update_rptr(struct bwfm_pci_softc *sc,
1021e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1022e5ec1e72Spatrick {
1023e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
1024e5ec1e72Spatrick 		ring->r_ptr = bus_space_read_2(sc->sc_tcm_iot,
1025e5ec1e72Spatrick 		    sc->sc_tcm_ioh, ring->r_idx_addr);
1026e5ec1e72Spatrick 	} else {
1027e5ec1e72Spatrick 		ring->r_ptr = *(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf)
1028e5ec1e72Spatrick 		    + ring->r_idx_addr);
1029e5ec1e72Spatrick 	}
1030e5ec1e72Spatrick }
1031e5ec1e72Spatrick 
1032e5ec1e72Spatrick void
1033e5ec1e72Spatrick bwfm_pci_ring_update_wptr(struct bwfm_pci_softc *sc,
1034e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1035e5ec1e72Spatrick {
1036e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
1037e5ec1e72Spatrick 		ring->w_ptr = bus_space_read_2(sc->sc_tcm_iot,
1038e5ec1e72Spatrick 		    sc->sc_tcm_ioh, ring->w_idx_addr);
1039e5ec1e72Spatrick 	} else {
1040e5ec1e72Spatrick 		ring->w_ptr = *(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf)
1041e5ec1e72Spatrick 		    + ring->w_idx_addr);
1042e5ec1e72Spatrick 	}
1043e5ec1e72Spatrick }
1044e5ec1e72Spatrick 
1045e5ec1e72Spatrick void
1046e5ec1e72Spatrick bwfm_pci_ring_write_rptr(struct bwfm_pci_softc *sc,
1047e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1048e5ec1e72Spatrick {
1049e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
1050e5ec1e72Spatrick 		bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1051e5ec1e72Spatrick 		    ring->r_idx_addr, ring->r_ptr);
1052e5ec1e72Spatrick 	} else {
1053e5ec1e72Spatrick 		*(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf)
1054e5ec1e72Spatrick 		    + ring->r_idx_addr) = ring->r_ptr;
1055e5ec1e72Spatrick 	}
1056e5ec1e72Spatrick }
1057e5ec1e72Spatrick 
1058e5ec1e72Spatrick void
1059e5ec1e72Spatrick bwfm_pci_ring_write_wptr(struct bwfm_pci_softc *sc,
1060e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1061e5ec1e72Spatrick {
1062e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
1063e5ec1e72Spatrick 		bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1064e5ec1e72Spatrick 		    ring->w_idx_addr, ring->w_ptr);
1065e5ec1e72Spatrick 	} else {
1066e5ec1e72Spatrick 		*(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf)
1067e5ec1e72Spatrick 		    + ring->w_idx_addr) = ring->w_ptr;
1068e5ec1e72Spatrick 	}
1069e5ec1e72Spatrick }
1070e5ec1e72Spatrick 
1071e5ec1e72Spatrick /*
1072e5ec1e72Spatrick  * Retrieve a free descriptor to put new stuff in, but don't commit
1073e5ec1e72Spatrick  * to it yet so we can rollback later if any error occurs.
1074e5ec1e72Spatrick  */
1075e5ec1e72Spatrick void *
1076e5ec1e72Spatrick bwfm_pci_ring_write_reserve(struct bwfm_pci_softc *sc,
1077e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1078e5ec1e72Spatrick {
1079e5ec1e72Spatrick 	int available;
1080e5ec1e72Spatrick 	char *ret;
1081e5ec1e72Spatrick 
1082e5ec1e72Spatrick 	bwfm_pci_ring_update_rptr(sc, ring);
1083e5ec1e72Spatrick 
1084e5ec1e72Spatrick 	if (ring->r_ptr > ring->w_ptr)
1085e5ec1e72Spatrick 		available = ring->r_ptr - ring->w_ptr;
1086e5ec1e72Spatrick 	else
1087e5ec1e72Spatrick 		available = ring->r_ptr + (ring->nitem - ring->w_ptr);
1088e5ec1e72Spatrick 
1089e5ec1e72Spatrick 	if (available < 1)
1090e5ec1e72Spatrick 		return NULL;
1091e5ec1e72Spatrick 
1092e5ec1e72Spatrick 	ret = BWFM_PCI_DMA_KVA(ring->ring) + (ring->w_ptr * ring->itemsz);
1093e5ec1e72Spatrick 	ring->w_ptr += 1;
1094e5ec1e72Spatrick 	if (ring->w_ptr == ring->nitem)
1095e5ec1e72Spatrick 		ring->w_ptr = 0;
1096e5ec1e72Spatrick 	return ret;
1097e5ec1e72Spatrick }
1098e5ec1e72Spatrick 
1099e5ec1e72Spatrick void *
1100e5ec1e72Spatrick bwfm_pci_ring_write_reserve_multi(struct bwfm_pci_softc *sc,
1101e5ec1e72Spatrick     struct bwfm_pci_msgring *ring, int count, int *avail)
1102e5ec1e72Spatrick {
1103e5ec1e72Spatrick 	int available;
1104e5ec1e72Spatrick 	char *ret;
1105e5ec1e72Spatrick 
1106e5ec1e72Spatrick 	bwfm_pci_ring_update_rptr(sc, ring);
1107e5ec1e72Spatrick 
1108e5ec1e72Spatrick 	if (ring->r_ptr > ring->w_ptr)
1109e5ec1e72Spatrick 		available = ring->r_ptr - ring->w_ptr;
1110e5ec1e72Spatrick 	else
1111e5ec1e72Spatrick 		available = ring->r_ptr + (ring->nitem - ring->w_ptr);
1112e5ec1e72Spatrick 
1113e5ec1e72Spatrick 	if (available < 1)
1114e5ec1e72Spatrick 		return NULL;
1115e5ec1e72Spatrick 
1116e5ec1e72Spatrick 	ret = BWFM_PCI_DMA_KVA(ring->ring) + (ring->w_ptr * ring->itemsz);
1117e5ec1e72Spatrick 	*avail = min(count, available - 1);
1118e5ec1e72Spatrick 	if (*avail + ring->w_ptr > ring->nitem)
1119e5ec1e72Spatrick 		*avail = ring->nitem - ring->w_ptr;
1120e5ec1e72Spatrick 	ring->w_ptr += *avail;
1121e5ec1e72Spatrick 	if (ring->w_ptr == ring->nitem)
1122e5ec1e72Spatrick 		ring->w_ptr = 0;
1123e5ec1e72Spatrick 	return ret;
1124e5ec1e72Spatrick }
1125e5ec1e72Spatrick 
1126e5ec1e72Spatrick /*
1127e5ec1e72Spatrick  * Read number of descriptors available (submitted by the firmware)
1128e5ec1e72Spatrick  * and retrieve pointer to first descriptor.
1129e5ec1e72Spatrick  */
1130e5ec1e72Spatrick void *
1131e5ec1e72Spatrick bwfm_pci_ring_read_avail(struct bwfm_pci_softc *sc,
1132e5ec1e72Spatrick     struct bwfm_pci_msgring *ring, int *avail)
1133e5ec1e72Spatrick {
1134e5ec1e72Spatrick 	bwfm_pci_ring_update_wptr(sc, ring);
1135e5ec1e72Spatrick 
1136e5ec1e72Spatrick 	if (ring->w_ptr >= ring->r_ptr)
1137e5ec1e72Spatrick 		*avail = ring->w_ptr - ring->r_ptr;
1138e5ec1e72Spatrick 	else
1139e5ec1e72Spatrick 		*avail = ring->nitem - ring->r_ptr;
1140e5ec1e72Spatrick 
1141e5ec1e72Spatrick 	if (*avail == 0)
1142e5ec1e72Spatrick 		return NULL;
1143e5ec1e72Spatrick 
1144e5ec1e72Spatrick 	return BWFM_PCI_DMA_KVA(ring->ring) + (ring->r_ptr * ring->itemsz);
1145e5ec1e72Spatrick }
1146e5ec1e72Spatrick 
1147e5ec1e72Spatrick /*
1148e5ec1e72Spatrick  * Let firmware know we read N descriptors.
1149e5ec1e72Spatrick  */
1150e5ec1e72Spatrick void
1151e5ec1e72Spatrick bwfm_pci_ring_read_commit(struct bwfm_pci_softc *sc,
1152e5ec1e72Spatrick     struct bwfm_pci_msgring *ring, int nitem)
1153e5ec1e72Spatrick {
1154e5ec1e72Spatrick 	ring->r_ptr += nitem;
1155e5ec1e72Spatrick 	if (ring->r_ptr == ring->nitem)
1156e5ec1e72Spatrick 		ring->r_ptr = 0;
1157e5ec1e72Spatrick 	bwfm_pci_ring_write_rptr(sc, ring);
1158e5ec1e72Spatrick }
1159e5ec1e72Spatrick 
1160e5ec1e72Spatrick /*
1161e5ec1e72Spatrick  * Let firmware know that we submitted some descriptors.
1162e5ec1e72Spatrick  */
1163e5ec1e72Spatrick void
1164e5ec1e72Spatrick bwfm_pci_ring_write_commit(struct bwfm_pci_softc *sc,
1165e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1166e5ec1e72Spatrick {
1167e5ec1e72Spatrick 	bwfm_pci_ring_write_wptr(sc, ring);
1168e5ec1e72Spatrick 	bwfm_pci_ring_bell(sc, ring);
1169e5ec1e72Spatrick }
1170e5ec1e72Spatrick 
1171e5ec1e72Spatrick /*
1172e5ec1e72Spatrick  * Rollback N descriptors in case we don't actually want
1173e5ec1e72Spatrick  * to commit to it.
1174e5ec1e72Spatrick  */
1175e5ec1e72Spatrick void
1176e5ec1e72Spatrick bwfm_pci_ring_write_cancel(struct bwfm_pci_softc *sc,
1177e5ec1e72Spatrick     struct bwfm_pci_msgring *ring, int nitem)
1178e5ec1e72Spatrick {
1179e5ec1e72Spatrick 	if (ring->w_ptr == 0)
1180e5ec1e72Spatrick 		ring->w_ptr = ring->nitem - nitem;
1181e5ec1e72Spatrick 	else
1182e5ec1e72Spatrick 		ring->w_ptr -= nitem;
1183e5ec1e72Spatrick }
1184e5ec1e72Spatrick 
1185e5ec1e72Spatrick /*
1186e5ec1e72Spatrick  * Foreach written descriptor on the ring, pass the descriptor to
1187e5ec1e72Spatrick  * a message handler and let the firmware know we handled it.
1188e5ec1e72Spatrick  */
1189e5ec1e72Spatrick void
1190e5ec1e72Spatrick bwfm_pci_ring_rx(struct bwfm_pci_softc *sc, struct bwfm_pci_msgring *ring)
1191e5ec1e72Spatrick {
1192e5ec1e72Spatrick 	void *buf;
1193e5ec1e72Spatrick 	int avail, processed;
1194e5ec1e72Spatrick 
1195e5ec1e72Spatrick again:
1196e5ec1e72Spatrick 	buf = bwfm_pci_ring_read_avail(sc, ring, &avail);
1197e5ec1e72Spatrick 	if (buf == NULL)
1198e5ec1e72Spatrick 		return;
1199e5ec1e72Spatrick 
1200e5ec1e72Spatrick 	processed = 0;
1201e5ec1e72Spatrick 	while (avail) {
1202e5ec1e72Spatrick 		bwfm_pci_msg_rx(sc, buf + sc->sc_rx_dataoffset);
1203e5ec1e72Spatrick 		buf += ring->itemsz;
1204e5ec1e72Spatrick 		processed++;
1205e5ec1e72Spatrick 		if (processed == 48) {
1206e5ec1e72Spatrick 			bwfm_pci_ring_read_commit(sc, ring, processed);
1207e5ec1e72Spatrick 			processed = 0;
1208e5ec1e72Spatrick 		}
1209e5ec1e72Spatrick 		avail--;
1210e5ec1e72Spatrick 	}
1211e5ec1e72Spatrick 	if (processed)
1212e5ec1e72Spatrick 		bwfm_pci_ring_read_commit(sc, ring, processed);
1213e5ec1e72Spatrick 	if (ring->r_ptr == 0)
1214e5ec1e72Spatrick 		goto again;
1215e5ec1e72Spatrick }
1216e5ec1e72Spatrick 
1217e5ec1e72Spatrick void
1218e5ec1e72Spatrick bwfm_pci_msg_rx(struct bwfm_pci_softc *sc, void *buf)
1219e5ec1e72Spatrick {
1220518be5f3Spatrick 	struct ifnet *ifp = &sc->sc_sc.sc_ic.ic_if;
1221e5ec1e72Spatrick 	struct msgbuf_ioctl_resp_hdr *resp;
1222518be5f3Spatrick 	struct msgbuf_tx_status *tx;
122318722113Spatrick 	struct msgbuf_rx_complete *rx;
1224e5ec1e72Spatrick 	struct msgbuf_rx_event *event;
1225e5ec1e72Spatrick 	struct msgbuf_common_hdr *msg;
1226518be5f3Spatrick 	struct msgbuf_flowring_create_resp *fcr;
1227a2c6ff8bSpatrick 	struct msgbuf_flowring_delete_resp *fdr;
1228518be5f3Spatrick 	struct bwfm_pci_msgring *ring;
1229e5ec1e72Spatrick 	struct mbuf *m;
1230518be5f3Spatrick 	int flowid;
1231e5ec1e72Spatrick 
1232e5ec1e72Spatrick 	msg = (struct msgbuf_common_hdr *)buf;
1233e5ec1e72Spatrick 	switch (msg->msgtype)
1234e5ec1e72Spatrick 	{
1235518be5f3Spatrick 	case MSGBUF_TYPE_FLOW_RING_CREATE_CMPLT:
1236518be5f3Spatrick 		fcr = (struct msgbuf_flowring_create_resp *)buf;
1237518be5f3Spatrick 		flowid = letoh16(fcr->compl_hdr.flow_ring_id);
1238518be5f3Spatrick 		if (flowid < 2)
1239518be5f3Spatrick 			break;
1240518be5f3Spatrick 		flowid -= 2;
1241518be5f3Spatrick 		if (flowid >= sc->sc_max_flowrings)
1242518be5f3Spatrick 			break;
1243518be5f3Spatrick 		ring = &sc->sc_flowrings[flowid];
1244518be5f3Spatrick 		if (ring->status != RING_OPENING)
1245518be5f3Spatrick 			break;
1246518be5f3Spatrick 		if (fcr->compl_hdr.status) {
1247518be5f3Spatrick 			printf("%s: failed to open flowring %d\n",
1248518be5f3Spatrick 			    DEVNAME(sc), flowid);
1249518be5f3Spatrick 			ring->status = RING_CLOSED;
125002ee7d07Spatrick 			if (ring->m) {
125102ee7d07Spatrick 				m_freem(ring->m);
125202ee7d07Spatrick 				ring->m = NULL;
125302ee7d07Spatrick 			}
1254518be5f3Spatrick 			ifq_restart(&ifp->if_snd);
1255518be5f3Spatrick 			break;
1256518be5f3Spatrick 		}
1257518be5f3Spatrick 		ring->status = RING_OPEN;
125802ee7d07Spatrick 		if (ring->m != NULL) {
125902ee7d07Spatrick 			m = ring->m;
126002ee7d07Spatrick 			ring->m = NULL;
126102ee7d07Spatrick 			if (bwfm_pci_txdata(&sc->sc_sc, m))
126202ee7d07Spatrick 				m_freem(ring->m);
126302ee7d07Spatrick 		}
1264518be5f3Spatrick 		ifq_restart(&ifp->if_snd);
1265518be5f3Spatrick 		break;
1266a2c6ff8bSpatrick 	case MSGBUF_TYPE_FLOW_RING_DELETE_CMPLT:
1267a2c6ff8bSpatrick 		fdr = (struct msgbuf_flowring_delete_resp *)buf;
1268a2c6ff8bSpatrick 		flowid = letoh16(fdr->compl_hdr.flow_ring_id);
1269a2c6ff8bSpatrick 		if (flowid < 2)
1270a2c6ff8bSpatrick 			break;
1271a2c6ff8bSpatrick 		flowid -= 2;
1272a2c6ff8bSpatrick 		if (flowid >= sc->sc_max_flowrings)
1273a2c6ff8bSpatrick 			break;
1274a2c6ff8bSpatrick 		ring = &sc->sc_flowrings[flowid];
1275a2c6ff8bSpatrick 		if (ring->status != RING_CLOSING)
1276a2c6ff8bSpatrick 			break;
1277a2c6ff8bSpatrick 		if (fdr->compl_hdr.status) {
1278a2c6ff8bSpatrick 			printf("%s: failed to delete flowring %d\n",
1279a2c6ff8bSpatrick 			    DEVNAME(sc), flowid);
1280a2c6ff8bSpatrick 			break;
1281a2c6ff8bSpatrick 		}
1282a2c6ff8bSpatrick 		bwfm_pci_dmamem_free(sc, ring->ring);
1283a2c6ff8bSpatrick 		ring->status = RING_CLOSED;
1284a2c6ff8bSpatrick 		break;
1285e5ec1e72Spatrick 	case MSGBUF_TYPE_IOCTLPTR_REQ_ACK:
1286e5ec1e72Spatrick 		break;
1287e5ec1e72Spatrick 	case MSGBUF_TYPE_IOCTL_CMPLT:
1288e5ec1e72Spatrick 		resp = (struct msgbuf_ioctl_resp_hdr *)buf;
1289e5ec1e72Spatrick 		sc->sc_ioctl_resp_pktid = letoh32(resp->msg.request_id);
1290e5ec1e72Spatrick 		sc->sc_ioctl_resp_ret_len = letoh16(resp->resp_len);
1291e5ec1e72Spatrick 		sc->sc_ioctl_resp_status = letoh16(resp->compl_hdr.status);
1292e5ec1e72Spatrick 		if_rxr_put(&sc->sc_ioctl_ring, 1);
1293e5ec1e72Spatrick 		bwfm_pci_fill_rx_rings(sc);
1294e5ec1e72Spatrick 		wakeup(&sc->sc_ioctl_buf);
1295e5ec1e72Spatrick 		break;
1296e5ec1e72Spatrick 	case MSGBUF_TYPE_WL_EVENT:
1297e5ec1e72Spatrick 		event = (struct msgbuf_rx_event *)buf;
1298e5ec1e72Spatrick 		m = bwfm_pci_pktid_free(sc, &sc->sc_rx_pkts,
1299e5ec1e72Spatrick 		    letoh32(event->msg.request_id));
1300e5ec1e72Spatrick 		if (m == NULL)
1301e5ec1e72Spatrick 			break;
1302e5ec1e72Spatrick 		m_adj(m, sc->sc_rx_dataoffset);
1303f37fc236Spatrick 		m->m_len = m->m_pkthdr.len = letoh16(event->event_data_len);
1304f37fc236Spatrick 		bwfm_rx(&sc->sc_sc, m);
1305e5ec1e72Spatrick 		if_rxr_put(&sc->sc_event_ring, 1);
1306e5ec1e72Spatrick 		bwfm_pci_fill_rx_rings(sc);
1307e5ec1e72Spatrick 		break;
1308518be5f3Spatrick 	case MSGBUF_TYPE_TX_STATUS:
1309518be5f3Spatrick 		tx = (struct msgbuf_tx_status *)buf;
1310518be5f3Spatrick 		m = bwfm_pci_pktid_free(sc, &sc->sc_tx_pkts,
1311518be5f3Spatrick 		    letoh32(tx->msg.request_id));
1312518be5f3Spatrick 		if (m == NULL)
1313518be5f3Spatrick 			break;
1314518be5f3Spatrick 		m_freem(m);
1315c6f1636dSpatrick 		if (sc->sc_tx_pkts_full) {
1316c6f1636dSpatrick 			sc->sc_tx_pkts_full = 0;
1317c6f1636dSpatrick 			ifq_restart(&ifp->if_snd);
1318c6f1636dSpatrick 		}
1319518be5f3Spatrick 		break;
132018722113Spatrick 	case MSGBUF_TYPE_RX_CMPLT:
132118722113Spatrick 		rx = (struct msgbuf_rx_complete *)buf;
132218722113Spatrick 		m = bwfm_pci_pktid_free(sc, &sc->sc_rx_pkts,
132318722113Spatrick 		    letoh32(rx->msg.request_id));
132418722113Spatrick 		if (m == NULL)
132518722113Spatrick 			break;
132618722113Spatrick 		if (letoh16(rx->data_offset))
132718722113Spatrick 			m_adj(m, letoh16(rx->data_offset));
132818722113Spatrick 		else if (sc->sc_rx_dataoffset)
132918722113Spatrick 			m_adj(m, sc->sc_rx_dataoffset);
1330f37fc236Spatrick 		m->m_len = m->m_pkthdr.len = letoh16(rx->data_len);
1331f37fc236Spatrick 		bwfm_rx(&sc->sc_sc, m);
133218722113Spatrick 		if_rxr_put(&sc->sc_rxbuf_ring, 1);
133318722113Spatrick 		bwfm_pci_fill_rx_rings(sc);
133418722113Spatrick 		break;
1335e5ec1e72Spatrick 	default:
1336e5ec1e72Spatrick 		printf("%s: msgtype 0x%08x\n", __func__, msg->msgtype);
1337e5ec1e72Spatrick 		break;
1338e5ec1e72Spatrick 	}
1339e5ec1e72Spatrick }
1340e5ec1e72Spatrick 
1341e5ec1e72Spatrick /* Bus core helpers */
1342e5ec1e72Spatrick void
1343e5ec1e72Spatrick bwfm_pci_select_core(struct bwfm_pci_softc *sc, int id)
1344e5ec1e72Spatrick {
1345e5ec1e72Spatrick 	struct bwfm_softc *bwfm = (void *)sc;
1346e5ec1e72Spatrick 	struct bwfm_core *core;
1347e5ec1e72Spatrick 
1348e5ec1e72Spatrick 	core = bwfm_chip_get_core(bwfm, id);
1349e5ec1e72Spatrick 	if (core == NULL) {
1350e5ec1e72Spatrick 		printf("%s: could not find core to select", DEVNAME(sc));
1351e5ec1e72Spatrick 		return;
1352e5ec1e72Spatrick 	}
1353e5ec1e72Spatrick 
1354e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag,
1355e5ec1e72Spatrick 	    BWFM_PCI_BAR0_WINDOW, core->co_base);
1356e5ec1e72Spatrick 	if (pci_conf_read(sc->sc_pc, sc->sc_tag,
1357e5ec1e72Spatrick 	    BWFM_PCI_BAR0_WINDOW) != core->co_base)
1358e5ec1e72Spatrick 		pci_conf_write(sc->sc_pc, sc->sc_tag,
1359e5ec1e72Spatrick 		    BWFM_PCI_BAR0_WINDOW, core->co_base);
1360e5ec1e72Spatrick }
1361e5ec1e72Spatrick 
1362e5ec1e72Spatrick uint32_t
1363e5ec1e72Spatrick bwfm_pci_buscore_read(struct bwfm_softc *bwfm, uint32_t reg)
1364e5ec1e72Spatrick {
1365e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1366e5ec1e72Spatrick 	uint32_t page, offset;
1367e5ec1e72Spatrick 
1368e5ec1e72Spatrick 	page = reg & ~(BWFM_PCI_BAR0_REG_SIZE - 1);
1369e5ec1e72Spatrick 	offset = reg & (BWFM_PCI_BAR0_REG_SIZE - 1);
1370e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_BAR0_WINDOW, page);
1371e5ec1e72Spatrick 	return bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh, offset);
1372e5ec1e72Spatrick }
1373e5ec1e72Spatrick 
1374e5ec1e72Spatrick void
1375e5ec1e72Spatrick bwfm_pci_buscore_write(struct bwfm_softc *bwfm, uint32_t reg, uint32_t val)
1376e5ec1e72Spatrick {
1377e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1378e5ec1e72Spatrick 	uint32_t page, offset;
1379e5ec1e72Spatrick 
1380e5ec1e72Spatrick 	page = reg & ~(BWFM_PCI_BAR0_REG_SIZE - 1);
1381e5ec1e72Spatrick 	offset = reg & (BWFM_PCI_BAR0_REG_SIZE - 1);
1382e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_BAR0_WINDOW, page);
1383e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, offset, val);
1384e5ec1e72Spatrick }
1385e5ec1e72Spatrick 
1386e5ec1e72Spatrick int
1387e5ec1e72Spatrick bwfm_pci_buscore_prepare(struct bwfm_softc *bwfm)
1388e5ec1e72Spatrick {
1389e5ec1e72Spatrick 	return 0;
1390e5ec1e72Spatrick }
1391e5ec1e72Spatrick 
1392e5ec1e72Spatrick int
1393e5ec1e72Spatrick bwfm_pci_buscore_reset(struct bwfm_softc *bwfm)
1394e5ec1e72Spatrick {
1395e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1396e5ec1e72Spatrick 	struct bwfm_core *core;
1397e5ec1e72Spatrick 	uint32_t reg;
1398e5ec1e72Spatrick 	int i;
1399e5ec1e72Spatrick 
1400e5ec1e72Spatrick 	bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2);
1401e5ec1e72Spatrick 	reg = pci_conf_read(sc->sc_pc, sc->sc_tag,
1402e5ec1e72Spatrick 	    BWFM_PCI_CFGREG_LINK_STATUS_CTRL);
1403e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_CFGREG_LINK_STATUS_CTRL,
1404e5ec1e72Spatrick 	    reg & ~BWFM_PCI_CFGREG_LINK_STATUS_CTRL_ASPM_ENAB);
1405e5ec1e72Spatrick 
1406e5ec1e72Spatrick 	bwfm_pci_select_core(sc, BWFM_AGENT_CORE_CHIPCOMMON);
1407e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1408e5ec1e72Spatrick 	    BWFM_CHIP_REG_WATCHDOG, 4);
1409e5ec1e72Spatrick 	delay(100 * 1000);
1410e5ec1e72Spatrick 
1411e5ec1e72Spatrick 	bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2);
1412e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag,
1413e5ec1e72Spatrick 	    BWFM_PCI_CFGREG_LINK_STATUS_CTRL, reg);
1414e5ec1e72Spatrick 
1415e5ec1e72Spatrick 	core = bwfm_chip_get_core(bwfm, BWFM_AGENT_CORE_PCIE2);
1416e5ec1e72Spatrick 	if (core->co_rev <= 13) {
1417e5ec1e72Spatrick 		uint16_t cfg_offset[] = {
1418e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_STATUS_CMD,
1419e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_PM_CSR,
1420e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_MSI_CAP,
1421e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_MSI_ADDR_L,
1422e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_MSI_ADDR_H,
1423e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_MSI_DATA,
1424e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_LINK_STATUS_CTRL2,
1425e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_RBAR_CTRL,
1426e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_PML1_SUB_CTRL1,
1427e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_REG_BAR2_CONFIG,
1428e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_REG_BAR3_CONFIG,
1429e5ec1e72Spatrick 		};
1430e5ec1e72Spatrick 
1431e5ec1e72Spatrick 		for (i = 0; i < nitems(cfg_offset); i++) {
1432e5ec1e72Spatrick 			bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1433e5ec1e72Spatrick 			    BWFM_PCI_PCIE2REG_CONFIGADDR, cfg_offset[i]);
1434e5ec1e72Spatrick 			reg = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1435e5ec1e72Spatrick 			    BWFM_PCI_PCIE2REG_CONFIGDATA);
1436e5ec1e72Spatrick 			DPRINTFN(3, ("%s: config offset 0x%04x, value 0x%04x\n",
1437e5ec1e72Spatrick 			    DEVNAME(sc), cfg_offset[i], reg));
1438e5ec1e72Spatrick 			bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1439e5ec1e72Spatrick 			    BWFM_PCI_PCIE2REG_CONFIGDATA, reg);
1440e5ec1e72Spatrick 		}
1441e5ec1e72Spatrick 	}
1442e5ec1e72Spatrick 
1443e5ec1e72Spatrick 	reg = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1444e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXINT);
1445e5ec1e72Spatrick 	if (reg != 0xffffffff)
1446e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1447e5ec1e72Spatrick 		    BWFM_PCI_PCIE2REG_MAILBOXINT, reg);
1448e5ec1e72Spatrick 
1449e5ec1e72Spatrick 	return 0;
1450e5ec1e72Spatrick }
1451e5ec1e72Spatrick 
1452e5ec1e72Spatrick void
1453e5ec1e72Spatrick bwfm_pci_buscore_activate(struct bwfm_softc *bwfm, uint32_t rstvec)
1454e5ec1e72Spatrick {
1455e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1456e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 0, rstvec);
1457e5ec1e72Spatrick }
1458e5ec1e72Spatrick 
1459f67437f3Spatrick static int bwfm_pci_prio2fifo[8] = {
1460f67437f3Spatrick 	1, /* best effort */
1461f67437f3Spatrick 	0, /* IPTOS_PREC_IMMEDIATE */
1462f67437f3Spatrick 	0, /* IPTOS_PREC_PRIORITY */
1463f67437f3Spatrick 	1, /* IPTOS_PREC_FLASH */
1464f67437f3Spatrick 	2, /* IPTOS_PREC_FLASHOVERRIDE */
1465f67437f3Spatrick 	2, /* IPTOS_PREC_CRITIC_ECP */
1466f67437f3Spatrick 	3, /* IPTOS_PREC_INTERNETCONTROL */
1467f67437f3Spatrick 	3, /* IPTOS_PREC_NETCONTROL */
1468f67437f3Spatrick };
1469f67437f3Spatrick 
1470f67437f3Spatrick int
1471f67437f3Spatrick bwfm_pci_flowring_lookup(struct bwfm_pci_softc *sc, struct mbuf *m)
1472518be5f3Spatrick {
1473f67437f3Spatrick 	struct ieee80211com *ic = &sc->sc_sc.sc_ic;
1474f67437f3Spatrick 	uint8_t *da = mtod(m, uint8_t *);
1475f67437f3Spatrick 	int flowid, prio, fifo;
1476f67437f3Spatrick 	int i, found;
1477f67437f3Spatrick 
1478f67437f3Spatrick 	prio = ieee80211_classify(ic, m);
1479f67437f3Spatrick 	fifo = bwfm_pci_prio2fifo[prio];
1480f67437f3Spatrick 
1481f67437f3Spatrick 	switch (ic->ic_opmode)
1482f67437f3Spatrick 	{
1483f67437f3Spatrick 	case IEEE80211_M_STA:
1484f67437f3Spatrick 		flowid = fifo;
1485f67437f3Spatrick 		break;
1486f67437f3Spatrick #ifndef IEEE80211_STA_ONLY
1487f67437f3Spatrick 	case IEEE80211_M_HOSTAP:
14882b7bea7eSpatrick 		if (ETHER_IS_MULTICAST(da))
14892b7bea7eSpatrick 			da = etherbroadcastaddr;
1490f67437f3Spatrick 		flowid = da[5] * 2 + fifo;
1491f67437f3Spatrick 		break;
1492f67437f3Spatrick #endif
1493f67437f3Spatrick 	default:
1494f67437f3Spatrick 		printf("%s: state not supported\n", DEVNAME(sc));
1495f67437f3Spatrick 		return ENOBUFS;
1496f67437f3Spatrick 	}
1497f67437f3Spatrick 
1498f67437f3Spatrick 	found = 0;
1499f67437f3Spatrick 	flowid = flowid % sc->sc_max_flowrings;
1500f67437f3Spatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
1501f67437f3Spatrick 		if (ic->ic_opmode == IEEE80211_M_STA &&
1502f67437f3Spatrick 		    sc->sc_flowrings[flowid].status >= RING_OPEN &&
1503f67437f3Spatrick 		    sc->sc_flowrings[flowid].fifo == fifo) {
1504f67437f3Spatrick 			found = 1;
1505f67437f3Spatrick 			break;
1506f67437f3Spatrick 		}
1507f67437f3Spatrick #ifndef IEEE80211_STA_ONLY
1508f67437f3Spatrick 		if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
1509f67437f3Spatrick 		    sc->sc_flowrings[flowid].status >= RING_OPEN &&
1510f67437f3Spatrick 		    sc->sc_flowrings[flowid].fifo == fifo &&
1511a2c6ff8bSpatrick 		    !memcmp(sc->sc_flowrings[flowid].mac, da, ETHER_ADDR_LEN)) {
1512f67437f3Spatrick 			found = 1;
1513f67437f3Spatrick 			break;
1514f67437f3Spatrick 		}
1515f67437f3Spatrick #endif
1516f67437f3Spatrick 		flowid = (flowid + 1) % sc->sc_max_flowrings;
1517f67437f3Spatrick 	}
1518f67437f3Spatrick 
1519f67437f3Spatrick 	if (found)
1520f67437f3Spatrick 		return flowid;
1521f67437f3Spatrick 
1522f67437f3Spatrick 	return -1;
1523f67437f3Spatrick }
1524f67437f3Spatrick 
1525f67437f3Spatrick void
1526f67437f3Spatrick bwfm_pci_flowring_create(struct bwfm_pci_softc *sc, struct mbuf *m)
1527f67437f3Spatrick {
1528f67437f3Spatrick 	struct ieee80211com *ic = &sc->sc_sc.sc_ic;
1529518be5f3Spatrick 	struct bwfm_cmd_flowring_create cmd;
1530f67437f3Spatrick 	uint8_t *da = mtod(m, uint8_t *);
153102ee7d07Spatrick 	struct bwfm_pci_msgring *ring;
1532f67437f3Spatrick 	int flowid, prio, fifo;
1533f67437f3Spatrick 	int i, found;
1534f67437f3Spatrick 
1535f67437f3Spatrick 	prio = ieee80211_classify(ic, m);
1536f67437f3Spatrick 	fifo = bwfm_pci_prio2fifo[prio];
1537f67437f3Spatrick 
1538f67437f3Spatrick 	switch (ic->ic_opmode)
1539f67437f3Spatrick 	{
1540f67437f3Spatrick 	case IEEE80211_M_STA:
1541f67437f3Spatrick 		flowid = fifo;
1542f67437f3Spatrick 		break;
1543f67437f3Spatrick #ifndef IEEE80211_STA_ONLY
1544f67437f3Spatrick 	case IEEE80211_M_HOSTAP:
15452b7bea7eSpatrick 		if (ETHER_IS_MULTICAST(da))
15462b7bea7eSpatrick 			da = etherbroadcastaddr;
1547f67437f3Spatrick 		flowid = da[5] * 2 + fifo;
1548f67437f3Spatrick 		break;
1549f67437f3Spatrick #endif
1550f67437f3Spatrick 	default:
1551f67437f3Spatrick 		printf("%s: state not supported\n", DEVNAME(sc));
1552f67437f3Spatrick 		return;
1553f67437f3Spatrick 	}
1554f67437f3Spatrick 
1555f67437f3Spatrick 	found = 0;
1556f67437f3Spatrick 	flowid = flowid % sc->sc_max_flowrings;
1557f67437f3Spatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
155802ee7d07Spatrick 		ring = &sc->sc_flowrings[flowid];
155902ee7d07Spatrick 		if (ring->status == RING_CLOSED) {
156002ee7d07Spatrick 			ring->status = RING_OPENING;
1561f67437f3Spatrick 			found = 1;
1562f67437f3Spatrick 			break;
1563f67437f3Spatrick 		}
1564f67437f3Spatrick 		flowid = (flowid + 1) % sc->sc_max_flowrings;
1565f67437f3Spatrick 	}
1566f67437f3Spatrick 
156702ee7d07Spatrick 	/*
156802ee7d07Spatrick 	 * We cannot recover from that so far.  Only a stop/init
156902ee7d07Spatrick 	 * cycle can revive this if it ever happens at all.
157002ee7d07Spatrick 	 */
1571f67437f3Spatrick 	if (!found) {
1572f67437f3Spatrick 		printf("%s: no flowring available\n", DEVNAME(sc));
1573f67437f3Spatrick 		return;
1574f67437f3Spatrick 	}
1575f67437f3Spatrick 
157602ee7d07Spatrick 	cmd.m = m;
1577f67437f3Spatrick 	cmd.prio = prio;
1578518be5f3Spatrick 	cmd.flowid = flowid;
1579518be5f3Spatrick 	bwfm_do_async(&sc->sc_sc, bwfm_pci_flowring_create_cb, &cmd, sizeof(cmd));
1580518be5f3Spatrick }
1581518be5f3Spatrick 
1582518be5f3Spatrick void
1583518be5f3Spatrick bwfm_pci_flowring_create_cb(struct bwfm_softc *bwfm, void *arg)
1584518be5f3Spatrick {
1585518be5f3Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
15862b7bea7eSpatrick 	struct ieee80211com *ic = &sc->sc_sc.sc_ic;
1587518be5f3Spatrick 	struct bwfm_cmd_flowring_create *cmd = arg;
1588518be5f3Spatrick 	struct msgbuf_tx_flowring_create_req *req;
1589518be5f3Spatrick 	struct bwfm_pci_msgring *ring;
159002ee7d07Spatrick 	uint8_t *da, *sa;
1591518be5f3Spatrick 
159202ee7d07Spatrick 	da = mtod(cmd->m, char *) + 0 * ETHER_ADDR_LEN;
159302ee7d07Spatrick 	sa = mtod(cmd->m, char *) + 1 * ETHER_ADDR_LEN;
1594518be5f3Spatrick 
159502ee7d07Spatrick 	ring = &sc->sc_flowrings[cmd->flowid];
159602ee7d07Spatrick 	if (ring->status != RING_OPENING) {
159702ee7d07Spatrick 		printf("%s: flowring not opening\n", DEVNAME(sc));
1598518be5f3Spatrick 		return;
1599f67437f3Spatrick 	}
1600f67437f3Spatrick 
1601f67437f3Spatrick 	if (bwfm_pci_setup_flowring(sc, ring, 512, 48)) {
1602f67437f3Spatrick 		printf("%s: cannot setup flowring\n", DEVNAME(sc));
1603f67437f3Spatrick 		return;
1604f67437f3Spatrick 	}
1605518be5f3Spatrick 
1606518be5f3Spatrick 	req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit);
1607f67437f3Spatrick 	if (req == NULL) {
1608f67437f3Spatrick 		printf("%s: cannot reserve for flowring\n", DEVNAME(sc));
1609518be5f3Spatrick 		return;
1610f67437f3Spatrick 	}
1611518be5f3Spatrick 
1612518be5f3Spatrick 	ring->status = RING_OPENING;
161302ee7d07Spatrick 	ring->fifo = bwfm_pci_prio2fifo[cmd->prio];
161402ee7d07Spatrick 	ring->m = cmd->m;
161502ee7d07Spatrick 	memcpy(ring->mac, da, ETHER_ADDR_LEN);
16162b7bea7eSpatrick #ifndef IEEE80211_STA_ONLY
161702ee7d07Spatrick 	if (ic->ic_opmode == IEEE80211_M_HOSTAP && ETHER_IS_MULTICAST(da))
16182b7bea7eSpatrick 		memcpy(ring->mac, etherbroadcastaddr, ETHER_ADDR_LEN);
16192b7bea7eSpatrick #endif
1620f67437f3Spatrick 
1621518be5f3Spatrick 	req->msg.msgtype = MSGBUF_TYPE_FLOW_RING_CREATE;
1622518be5f3Spatrick 	req->msg.ifidx = 0;
1623518be5f3Spatrick 	req->msg.request_id = 0;
162402ee7d07Spatrick 	req->tid = bwfm_pci_prio2fifo[cmd->prio];
162502ee7d07Spatrick 	req->flow_ring_id = letoh16(cmd->flowid + 2);
162602ee7d07Spatrick 	memcpy(req->da, da, ETHER_ADDR_LEN);
162702ee7d07Spatrick 	memcpy(req->sa, sa, ETHER_ADDR_LEN);
1628518be5f3Spatrick 	req->flow_ring_addr.high_addr =
1629518be5f3Spatrick 	    letoh32(BWFM_PCI_DMA_DVA(ring->ring) >> 32);
1630518be5f3Spatrick 	req->flow_ring_addr.low_addr =
1631518be5f3Spatrick 	    letoh32(BWFM_PCI_DMA_DVA(ring->ring) & 0xffffffff);
1632518be5f3Spatrick 	req->max_items = letoh16(512);
1633518be5f3Spatrick 	req->len_item = letoh16(48);
1634518be5f3Spatrick 
1635518be5f3Spatrick 	bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit);
1636518be5f3Spatrick }
1637518be5f3Spatrick 
1638a2c6ff8bSpatrick void
1639a2c6ff8bSpatrick bwfm_pci_flowring_delete(struct bwfm_pci_softc *sc, int flowid)
1640a2c6ff8bSpatrick {
1641a2c6ff8bSpatrick 	struct msgbuf_tx_flowring_delete_req *req;
1642a2c6ff8bSpatrick 	struct bwfm_pci_msgring *ring;
1643a2c6ff8bSpatrick 
1644a2c6ff8bSpatrick 	ring = &sc->sc_flowrings[flowid];
1645a2c6ff8bSpatrick 	if (ring->status != RING_OPEN) {
1646a2c6ff8bSpatrick 		printf("%s: flowring not open\n", DEVNAME(sc));
1647a2c6ff8bSpatrick 		return;
1648a2c6ff8bSpatrick 	}
1649a2c6ff8bSpatrick 
1650a2c6ff8bSpatrick 	req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit);
1651a2c6ff8bSpatrick 	if (req == NULL) {
1652a2c6ff8bSpatrick 		printf("%s: cannot reserve for flowring\n", DEVNAME(sc));
1653a2c6ff8bSpatrick 		return;
1654a2c6ff8bSpatrick 	}
1655a2c6ff8bSpatrick 
1656a2c6ff8bSpatrick 	ring->status = RING_CLOSING;
1657a2c6ff8bSpatrick 
1658a2c6ff8bSpatrick 	req->msg.msgtype = MSGBUF_TYPE_FLOW_RING_DELETE;
1659a2c6ff8bSpatrick 	req->msg.ifidx = 0;
1660a2c6ff8bSpatrick 	req->msg.request_id = 0;
1661a2c6ff8bSpatrick 	req->flow_ring_id = letoh16(flowid + 2);
1662a2c6ff8bSpatrick 	req->reason = 0;
1663a2c6ff8bSpatrick 
1664a2c6ff8bSpatrick 	bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit);
1665a2c6ff8bSpatrick }
1666a2c6ff8bSpatrick 
1667a2c6ff8bSpatrick void
1668a2c6ff8bSpatrick bwfm_pci_stop(struct bwfm_softc *bwfm)
1669a2c6ff8bSpatrick {
1670a2c6ff8bSpatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1671a2c6ff8bSpatrick 	struct bwfm_pci_msgring *ring;
1672a2c6ff8bSpatrick 	int i;
1673a2c6ff8bSpatrick 
1674a2c6ff8bSpatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
1675a2c6ff8bSpatrick 		ring = &sc->sc_flowrings[i];
1676a2c6ff8bSpatrick 		if (ring->status == RING_OPEN)
1677a2c6ff8bSpatrick 			bwfm_pci_flowring_delete(sc, i);
1678a2c6ff8bSpatrick 	}
1679a2c6ff8bSpatrick }
1680a2c6ff8bSpatrick 
1681e5ec1e72Spatrick int
168202ee7d07Spatrick bwfm_pci_txcheck(struct bwfm_softc *bwfm)
168302ee7d07Spatrick {
168402ee7d07Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
168502ee7d07Spatrick 	struct bwfm_pci_msgring *ring;
168602ee7d07Spatrick 	int i;
168702ee7d07Spatrick 
168802ee7d07Spatrick 	/* If we are transitioning, we cannot send. */
168902ee7d07Spatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
169002ee7d07Spatrick 		ring = &sc->sc_flowrings[i];
169102ee7d07Spatrick 		if (ring->status == RING_OPENING)
169202ee7d07Spatrick 			return ENOBUFS;
169302ee7d07Spatrick 	}
169402ee7d07Spatrick 
169502ee7d07Spatrick 	if (bwfm_pci_pktid_avail(sc, &sc->sc_tx_pkts)) {
169602ee7d07Spatrick 		sc->sc_tx_pkts_full = 1;
169702ee7d07Spatrick 		return ENOBUFS;
169802ee7d07Spatrick 	}
169902ee7d07Spatrick 
170002ee7d07Spatrick 	return 0;
170102ee7d07Spatrick }
170202ee7d07Spatrick 
170302ee7d07Spatrick int
1704e5ec1e72Spatrick bwfm_pci_txdata(struct bwfm_softc *bwfm, struct mbuf *m)
1705e5ec1e72Spatrick {
1706e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1707518be5f3Spatrick 	struct bwfm_pci_msgring *ring;
1708518be5f3Spatrick 	struct msgbuf_tx_msghdr *tx;
1709518be5f3Spatrick 	uint32_t pktid;
1710518be5f3Spatrick 	paddr_t paddr;
1711518be5f3Spatrick 	int flowid, ret;
1712518be5f3Spatrick 
1713f67437f3Spatrick 	flowid = bwfm_pci_flowring_lookup(sc, m);
1714f67437f3Spatrick 	if (flowid < 0) {
171502ee7d07Spatrick 		/*
171602ee7d07Spatrick 		 * We cannot send the packet right now as there is
171702ee7d07Spatrick 		 * no flowring yet.  The flowring will be created
171802ee7d07Spatrick 		 * asynchronously.  While the ring is transitioning
171902ee7d07Spatrick 		 * the TX check will tell the upper layers that we
172002ee7d07Spatrick 		 * cannot send packets right now.  When the flowring
172102ee7d07Spatrick 		 * is created the queue will be restarted and this
172202ee7d07Spatrick 		 * mbuf will be transmitted.
172302ee7d07Spatrick 		 */
1724f67437f3Spatrick 		bwfm_pci_flowring_create(sc, m);
172502ee7d07Spatrick 		return 0;
1726f67437f3Spatrick 	}
1727518be5f3Spatrick 
1728518be5f3Spatrick 	ring = &sc->sc_flowrings[flowid];
1729518be5f3Spatrick 	if (ring->status == RING_OPENING ||
1730f67437f3Spatrick 	    ring->status == RING_CLOSING) {
1731f67437f3Spatrick 		printf("%s: tried to use a flow that was "
1732f67437f3Spatrick 		    "transitioning in status %d\n",
1733f67437f3Spatrick 		    DEVNAME(sc), ring->status);
1734518be5f3Spatrick 		return ENOBUFS;
1735518be5f3Spatrick 	}
1736518be5f3Spatrick 
1737518be5f3Spatrick 	tx = bwfm_pci_ring_write_reserve(sc, ring);
1738518be5f3Spatrick 	if (tx == NULL)
1739518be5f3Spatrick 		return ENOBUFS;
1740518be5f3Spatrick 
1741518be5f3Spatrick 	memset(tx, 0, sizeof(*tx));
1742518be5f3Spatrick 	tx->msg.msgtype = MSGBUF_TYPE_TX_POST;
1743518be5f3Spatrick 	tx->msg.ifidx = 0;
1744518be5f3Spatrick 	tx->flags = BWFM_MSGBUF_PKT_FLAGS_FRAME_802_3;
1745518be5f3Spatrick 	tx->flags |= ieee80211_classify(&sc->sc_sc.sc_ic, m) <<
1746518be5f3Spatrick 	    BWFM_MSGBUF_PKT_FLAGS_PRIO_SHIFT;
1747518be5f3Spatrick 	tx->seg_cnt = 1;
1748518be5f3Spatrick 	memcpy(tx->txhdr, mtod(m, char *), ETHER_HDR_LEN);
1749518be5f3Spatrick 
1750518be5f3Spatrick 	ret = bwfm_pci_pktid_new(sc, &sc->sc_tx_pkts, m, &pktid, &paddr);
1751518be5f3Spatrick 	if (ret) {
175202ee7d07Spatrick 		if (ret == ENOBUFS) {
175302ee7d07Spatrick 			printf("%s: no pktid available for TX\n",
175402ee7d07Spatrick 			    DEVNAME(sc));
1755c6f1636dSpatrick 			sc->sc_tx_pkts_full = 1;
175602ee7d07Spatrick 		}
1757518be5f3Spatrick 		bwfm_pci_ring_write_cancel(sc, ring, 1);
1758518be5f3Spatrick 		return ret;
1759518be5f3Spatrick 	}
1760518be5f3Spatrick 	paddr += ETHER_HDR_LEN;
1761518be5f3Spatrick 
1762518be5f3Spatrick 	tx->msg.request_id = htole32(pktid);
17634ff787bcSpatrick 	tx->data_len = htole16(m->m_len - ETHER_HDR_LEN);
1764518be5f3Spatrick 	tx->data_buf_addr.high_addr = htole32(paddr >> 32);
1765518be5f3Spatrick 	tx->data_buf_addr.low_addr = htole32(paddr & 0xffffffff);
1766518be5f3Spatrick 
1767518be5f3Spatrick 	bwfm_pci_ring_write_commit(sc, ring);
1768518be5f3Spatrick 	return 0;
1769e5ec1e72Spatrick }
1770e5ec1e72Spatrick 
1771bbd71b0bSpatrick #ifdef BWFM_DEBUG
1772cadf5fcfSpatrick void
1773cadf5fcfSpatrick bwfm_pci_debug_console(struct bwfm_pci_softc *sc)
1774cadf5fcfSpatrick {
1775cadf5fcfSpatrick 	uint32_t newidx = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1776cadf5fcfSpatrick 	    sc->sc_console_base_addr + BWFM_CONSOLE_WRITEIDX);
1777cadf5fcfSpatrick 
1778cadf5fcfSpatrick 	if (newidx != sc->sc_console_readidx)
1779bbd71b0bSpatrick 		DPRINTFN(3, ("BWFM CONSOLE: "));
1780cadf5fcfSpatrick 	while (newidx != sc->sc_console_readidx) {
1781cadf5fcfSpatrick 		uint8_t ch = bus_space_read_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1782cadf5fcfSpatrick 		    sc->sc_console_buf_addr + sc->sc_console_readidx);
1783cadf5fcfSpatrick 		sc->sc_console_readidx++;
1784cadf5fcfSpatrick 		if (sc->sc_console_readidx == sc->sc_console_buf_size)
1785cadf5fcfSpatrick 			sc->sc_console_readidx = 0;
1786cadf5fcfSpatrick 		if (ch == '\r')
1787cadf5fcfSpatrick 			continue;
1788bbd71b0bSpatrick 		DPRINTFN(3, ("%c", ch));
1789cadf5fcfSpatrick 	}
1790cadf5fcfSpatrick }
1791bbd71b0bSpatrick #endif
1792cadf5fcfSpatrick 
1793e5ec1e72Spatrick int
1794e5ec1e72Spatrick bwfm_pci_intr(void *v)
1795e5ec1e72Spatrick {
1796e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)v;
1797e5ec1e72Spatrick 	uint32_t status;
1798e5ec1e72Spatrick 
1799e5ec1e72Spatrick 	if ((status = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1800e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXINT)) == 0)
1801e5ec1e72Spatrick 		return 0;
1802e5ec1e72Spatrick 
1803e5ec1e72Spatrick 	bwfm_pci_intr_disable(sc);
1804e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1805e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXINT, status);
1806e5ec1e72Spatrick 
1807e5ec1e72Spatrick 	if (status & (BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_0 |
1808e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_1))
1809e5ec1e72Spatrick 		printf("%s: handle MB data\n", __func__);
1810e5ec1e72Spatrick 
1811e5ec1e72Spatrick 	if (status & BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_D2H_DB) {
1812518be5f3Spatrick 		bwfm_pci_ring_rx(sc, &sc->sc_rx_complete);
18132b7bea7eSpatrick 		bwfm_pci_ring_rx(sc, &sc->sc_tx_complete);
18142b7bea7eSpatrick 		bwfm_pci_ring_rx(sc, &sc->sc_ctrl_complete);
1815e5ec1e72Spatrick 	}
1816e5ec1e72Spatrick 
1817cadf5fcfSpatrick #ifdef BWFM_DEBUG
1818cadf5fcfSpatrick 	bwfm_pci_debug_console(sc);
1819e5ec1e72Spatrick #endif
1820e5ec1e72Spatrick 
1821e5ec1e72Spatrick 	bwfm_pci_intr_enable(sc);
1822e5ec1e72Spatrick 	return 1;
1823e5ec1e72Spatrick }
1824e5ec1e72Spatrick 
1825e5ec1e72Spatrick void
1826e5ec1e72Spatrick bwfm_pci_intr_enable(struct bwfm_pci_softc *sc)
1827e5ec1e72Spatrick {
1828e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1829e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXMASK,
1830e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_0 |
1831e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_1 |
1832e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_D2H_DB);
1833e5ec1e72Spatrick }
1834e5ec1e72Spatrick 
1835e5ec1e72Spatrick void
1836e5ec1e72Spatrick bwfm_pci_intr_disable(struct bwfm_pci_softc *sc)
1837e5ec1e72Spatrick {
1838e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1839e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXMASK, 0);
1840e5ec1e72Spatrick }
1841e5ec1e72Spatrick 
1842e5ec1e72Spatrick /* Msgbuf protocol implementation */
1843e5ec1e72Spatrick int
1844e5ec1e72Spatrick bwfm_pci_msgbuf_query_dcmd(struct bwfm_softc *bwfm, int ifidx,
1845e5ec1e72Spatrick     int cmd, char *buf, size_t *len)
1846e5ec1e72Spatrick {
1847e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1848e5ec1e72Spatrick 	struct msgbuf_ioctl_req_hdr *req;
1849e5ec1e72Spatrick 	struct mbuf *m;
1850e5ec1e72Spatrick 	size_t buflen;
1851e5ec1e72Spatrick 	int s;
1852e5ec1e72Spatrick 
1853e5ec1e72Spatrick 	s = splnet();
1854e5ec1e72Spatrick 	sc->sc_ioctl_resp_pktid = -1;
1855e5ec1e72Spatrick 	req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit);
1856e5ec1e72Spatrick 	if (req == NULL) {
1857e5ec1e72Spatrick 		printf("%s: cannot reserve for write\n", DEVNAME(sc));
1858e5ec1e72Spatrick 		splx(s);
1859e5ec1e72Spatrick 		return 1;
1860e5ec1e72Spatrick 	}
1861e5ec1e72Spatrick 	req->msg.msgtype = MSGBUF_TYPE_IOCTLPTR_REQ;
1862e5ec1e72Spatrick 	req->msg.ifidx = 0;
1863e5ec1e72Spatrick 	req->msg.flags = 0;
1864e5ec1e72Spatrick 	req->msg.request_id = htole32(MSGBUF_IOCTL_REQ_PKTID);
1865e5ec1e72Spatrick 	req->cmd = htole32(cmd);
1866e5ec1e72Spatrick 	req->output_buf_len = htole16(*len);
1867e5ec1e72Spatrick 	req->trans_id = htole16(sc->sc_ioctl_reqid++);
1868e5ec1e72Spatrick 
1869e5ec1e72Spatrick 	buflen = min(*len, BWFM_DMA_H2D_IOCTL_BUF_LEN);
1870e5ec1e72Spatrick 	req->input_buf_len = htole16(buflen);
1871e5ec1e72Spatrick 	req->req_buf_addr.high_addr =
1872e5ec1e72Spatrick 	    htole32((uint64_t)BWFM_PCI_DMA_DVA(sc->sc_ioctl_buf) >> 32);
1873e5ec1e72Spatrick 	req->req_buf_addr.low_addr =
1874e5ec1e72Spatrick 	    htole32((uint64_t)BWFM_PCI_DMA_DVA(sc->sc_ioctl_buf) & 0xffffffff);
1875e5ec1e72Spatrick 	if (buf)
1876e5ec1e72Spatrick 		memcpy(BWFM_PCI_DMA_KVA(sc->sc_ioctl_buf), buf, buflen);
1877e5ec1e72Spatrick 	else
1878e5ec1e72Spatrick 		memset(BWFM_PCI_DMA_KVA(sc->sc_ioctl_buf), 0, buflen);
1879e5ec1e72Spatrick 
1880e5ec1e72Spatrick 	bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit);
1881e5ec1e72Spatrick 	splx(s);
1882e5ec1e72Spatrick 
1883e5ec1e72Spatrick 	if (sc->sc_ioctl_poll) {
1884e5ec1e72Spatrick 		int i;
1885e5ec1e72Spatrick 		for (i = 0; i < 100; i++) {
1886e5ec1e72Spatrick 			if (sc->sc_ioctl_resp_pktid != -1)
1887e5ec1e72Spatrick 				break;
1888e5ec1e72Spatrick 			delay(10 * 1000);
1889e5ec1e72Spatrick 		}
1890e5ec1e72Spatrick 		if (i == 100) {
1891e5ec1e72Spatrick 			printf("%s: timeout waiting for ioctl response\n",
1892e5ec1e72Spatrick 			    DEVNAME(sc));
1893e5ec1e72Spatrick 			return 1;
1894e5ec1e72Spatrick 		}
1895e5ec1e72Spatrick 	} else if (tsleep(&sc->sc_ioctl_buf, PCATCH, "bwfm", hz)) {
1896e5ec1e72Spatrick 		printf("%s: timeout waiting for ioctl response\n",
1897e5ec1e72Spatrick 		    DEVNAME(sc));
1898e5ec1e72Spatrick 		return 1;
1899e5ec1e72Spatrick 	}
1900e5ec1e72Spatrick 
1901e5ec1e72Spatrick 	m = bwfm_pci_pktid_free(sc, &sc->sc_rx_pkts, sc->sc_ioctl_resp_pktid);
1902e5ec1e72Spatrick 	if (m == NULL)
1903e5ec1e72Spatrick 		return 1;
1904e5ec1e72Spatrick 
1905e5ec1e72Spatrick 	*len = min(buflen, sc->sc_ioctl_resp_ret_len);
1906e5ec1e72Spatrick 	if (buf)
1907e5ec1e72Spatrick 		memcpy(buf, mtod(m, char *), *len);
1908e5ec1e72Spatrick 	m_freem(m);
1909e5ec1e72Spatrick 	splx(s);
1910e5ec1e72Spatrick 
1911e5ec1e72Spatrick 	return 0;
1912e5ec1e72Spatrick }
1913e5ec1e72Spatrick 
1914e5ec1e72Spatrick int
1915e5ec1e72Spatrick bwfm_pci_msgbuf_set_dcmd(struct bwfm_softc *bwfm, int ifidx,
1916e5ec1e72Spatrick     int cmd, char *buf, size_t len)
1917e5ec1e72Spatrick {
1918e5ec1e72Spatrick 	return bwfm_pci_msgbuf_query_dcmd(bwfm, ifidx, cmd, buf, &len);
1919e5ec1e72Spatrick }
1920