xref: /openbsd/sys/dev/pci/if_bwfm_pci.c (revision 41d93ac2)
1*41d93ac2Spatrick /*	$OpenBSD: if_bwfm_pci.c,v 1.23 2018/06/07 11:24:19 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 
116972218f3Spatrick 	int			 sc_initialized;
117972218f3Spatrick 
118e5ec1e72Spatrick 	bus_space_tag_t		 sc_reg_iot;
119e5ec1e72Spatrick 	bus_space_handle_t	 sc_reg_ioh;
120e5ec1e72Spatrick 	bus_size_t		 sc_reg_ios;
121e5ec1e72Spatrick 
122e5ec1e72Spatrick 	bus_space_tag_t		 sc_tcm_iot;
123e5ec1e72Spatrick 	bus_space_handle_t	 sc_tcm_ioh;
124e5ec1e72Spatrick 	bus_size_t		 sc_tcm_ios;
125e5ec1e72Spatrick 
126e5ec1e72Spatrick 	bus_dma_tag_t		 sc_dmat;
127e5ec1e72Spatrick 
128e5ec1e72Spatrick 	uint32_t		 sc_shared_address;
129e5ec1e72Spatrick 	uint32_t		 sc_shared_flags;
130e5ec1e72Spatrick 	uint8_t			 sc_shared_version;
131e5ec1e72Spatrick 
132e5ec1e72Spatrick 	uint8_t			 sc_dma_idx_sz;
133e5ec1e72Spatrick 	struct bwfm_pci_dmamem	*sc_dma_idx_buf;
134e5ec1e72Spatrick 	size_t			 sc_dma_idx_bufsz;
135e5ec1e72Spatrick 
136e5ec1e72Spatrick 	uint16_t		 sc_max_rxbufpost;
137e5ec1e72Spatrick 	uint32_t		 sc_rx_dataoffset;
138e5ec1e72Spatrick 	uint32_t		 sc_htod_mb_data_addr;
139e5ec1e72Spatrick 	uint32_t		 sc_dtoh_mb_data_addr;
140e5ec1e72Spatrick 	uint32_t		 sc_ring_info_addr;
141e5ec1e72Spatrick 
142e5ec1e72Spatrick 	uint32_t		 sc_console_base_addr;
143e5ec1e72Spatrick 	uint32_t		 sc_console_buf_addr;
144e5ec1e72Spatrick 	uint32_t		 sc_console_buf_size;
145cadf5fcfSpatrick 	uint32_t		 sc_console_readidx;
146e5ec1e72Spatrick 
147e5ec1e72Spatrick 	uint16_t		 sc_max_flowrings;
148e5ec1e72Spatrick 	uint16_t		 sc_max_submissionrings;
149e5ec1e72Spatrick 	uint16_t		 sc_max_completionrings;
150e5ec1e72Spatrick 
151e5ec1e72Spatrick 	struct bwfm_pci_msgring	 sc_ctrl_submit;
152e5ec1e72Spatrick 	struct bwfm_pci_msgring	 sc_rxpost_submit;
153e5ec1e72Spatrick 	struct bwfm_pci_msgring	 sc_ctrl_complete;
154e5ec1e72Spatrick 	struct bwfm_pci_msgring	 sc_tx_complete;
155e5ec1e72Spatrick 	struct bwfm_pci_msgring	 sc_rx_complete;
156e5ec1e72Spatrick 	struct bwfm_pci_msgring	*sc_flowrings;
157e5ec1e72Spatrick 
158e5ec1e72Spatrick 	struct bwfm_pci_dmamem	*sc_scratch_buf;
159e5ec1e72Spatrick 	struct bwfm_pci_dmamem	*sc_ringupd_buf;
160e5ec1e72Spatrick 
161e5ec1e72Spatrick 	struct bwfm_pci_dmamem	*sc_ioctl_buf;
162e5ec1e72Spatrick 	int			 sc_ioctl_reqid;
163e5ec1e72Spatrick 	uint32_t		 sc_ioctl_resp_pktid;
164e5ec1e72Spatrick 	uint32_t		 sc_ioctl_resp_ret_len;
165e5ec1e72Spatrick 	uint32_t		 sc_ioctl_resp_status;
166e5ec1e72Spatrick 	int			 sc_ioctl_poll;
167e5ec1e72Spatrick 
168e5ec1e72Spatrick 	struct if_rxring	 sc_ioctl_ring;
169e5ec1e72Spatrick 	struct if_rxring	 sc_event_ring;
170e5ec1e72Spatrick 	struct if_rxring	 sc_rxbuf_ring;
171e5ec1e72Spatrick 
172e5ec1e72Spatrick 	struct bwfm_pci_pkts	 sc_rx_pkts;
173c6f1636dSpatrick 	struct bwfm_pci_pkts	 sc_tx_pkts;
174c6f1636dSpatrick 	int			 sc_tx_pkts_full;
175e5ec1e72Spatrick };
176e5ec1e72Spatrick 
177e5ec1e72Spatrick struct bwfm_pci_dmamem {
178e5ec1e72Spatrick 	bus_dmamap_t		bdm_map;
179e5ec1e72Spatrick 	bus_dma_segment_t	bdm_seg;
180e5ec1e72Spatrick 	size_t			bdm_size;
181e5ec1e72Spatrick 	caddr_t			bdm_kva;
182e5ec1e72Spatrick };
183e5ec1e72Spatrick 
184e5ec1e72Spatrick #define BWFM_PCI_DMA_MAP(_bdm)	((_bdm)->bdm_map)
185e5ec1e72Spatrick #define BWFM_PCI_DMA_LEN(_bdm)	((_bdm)->bdm_size)
186e5ec1e72Spatrick #define BWFM_PCI_DMA_DVA(_bdm)	((_bdm)->bdm_map->dm_segs[0].ds_addr)
187e5ec1e72Spatrick #define BWFM_PCI_DMA_KVA(_bdm)	((void *)(_bdm)->bdm_kva)
188e5ec1e72Spatrick 
189e5ec1e72Spatrick int		 bwfm_pci_match(struct device *, void *, void *);
190e5ec1e72Spatrick void		 bwfm_pci_attach(struct device *, struct device *, void *);
191e5ec1e72Spatrick int		 bwfm_pci_detach(struct device *, int);
192e5ec1e72Spatrick 
193e5ec1e72Spatrick int		 bwfm_pci_intr(void *);
194e5ec1e72Spatrick void		 bwfm_pci_intr_enable(struct bwfm_pci_softc *);
195e5ec1e72Spatrick void		 bwfm_pci_intr_disable(struct bwfm_pci_softc *);
196e5ec1e72Spatrick int		 bwfm_pci_load_microcode(struct bwfm_pci_softc *, const u_char *,
1976aad491fSpatrick 		    size_t, const u_char *, size_t);
198e5ec1e72Spatrick void		 bwfm_pci_select_core(struct bwfm_pci_softc *, int );
199e5ec1e72Spatrick 
200e5ec1e72Spatrick struct bwfm_pci_dmamem *
201e5ec1e72Spatrick 		 bwfm_pci_dmamem_alloc(struct bwfm_pci_softc *, bus_size_t,
202e5ec1e72Spatrick 		    bus_size_t);
203e5ec1e72Spatrick void		 bwfm_pci_dmamem_free(struct bwfm_pci_softc *, struct bwfm_pci_dmamem *);
20402ee7d07Spatrick int		 bwfm_pci_pktid_avail(struct bwfm_pci_softc *,
20502ee7d07Spatrick 		    struct bwfm_pci_pkts *);
206e5ec1e72Spatrick int		 bwfm_pci_pktid_new(struct bwfm_pci_softc *,
207e5ec1e72Spatrick 		    struct bwfm_pci_pkts *, struct mbuf *,
208e5ec1e72Spatrick 		    uint32_t *, paddr_t *);
209e5ec1e72Spatrick struct mbuf *	 bwfm_pci_pktid_free(struct bwfm_pci_softc *,
210e5ec1e72Spatrick 		    struct bwfm_pci_pkts *, uint32_t);
211e5ec1e72Spatrick void		 bwfm_pci_fill_rx_ioctl_ring(struct bwfm_pci_softc *,
212e5ec1e72Spatrick 		    struct if_rxring *, uint32_t);
213e5ec1e72Spatrick void		 bwfm_pci_fill_rx_buf_ring(struct bwfm_pci_softc *);
214e5ec1e72Spatrick void		 bwfm_pci_fill_rx_rings(struct bwfm_pci_softc *);
215e5ec1e72Spatrick int		 bwfm_pci_setup_ring(struct bwfm_pci_softc *, struct bwfm_pci_msgring *,
216e5ec1e72Spatrick 		    int, size_t, uint32_t, uint32_t, int, uint32_t, uint32_t *);
217518be5f3Spatrick int		 bwfm_pci_setup_flowring(struct bwfm_pci_softc *, struct bwfm_pci_msgring *,
218518be5f3Spatrick 		    int, size_t);
219e5ec1e72Spatrick 
220e5ec1e72Spatrick void		 bwfm_pci_ring_bell(struct bwfm_pci_softc *,
221e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
222e5ec1e72Spatrick void		 bwfm_pci_ring_update_rptr(struct bwfm_pci_softc *,
223e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
224e5ec1e72Spatrick void		 bwfm_pci_ring_update_wptr(struct bwfm_pci_softc *,
225e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
226e5ec1e72Spatrick void		 bwfm_pci_ring_write_rptr(struct bwfm_pci_softc *,
227e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
228e5ec1e72Spatrick void		 bwfm_pci_ring_write_wptr(struct bwfm_pci_softc *,
229e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
230e5ec1e72Spatrick void *		 bwfm_pci_ring_write_reserve(struct bwfm_pci_softc *,
231e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
232e5ec1e72Spatrick void *		 bwfm_pci_ring_write_reserve_multi(struct bwfm_pci_softc *,
233e5ec1e72Spatrick 		    struct bwfm_pci_msgring *, int, int *);
234e5ec1e72Spatrick void *		 bwfm_pci_ring_read_avail(struct bwfm_pci_softc *,
235e5ec1e72Spatrick 		    struct bwfm_pci_msgring *, int *);
236e5ec1e72Spatrick void		 bwfm_pci_ring_read_commit(struct bwfm_pci_softc *,
237e5ec1e72Spatrick 		    struct bwfm_pci_msgring *, int);
238e5ec1e72Spatrick void		 bwfm_pci_ring_write_commit(struct bwfm_pci_softc *,
239e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
240e5ec1e72Spatrick void		 bwfm_pci_ring_write_cancel(struct bwfm_pci_softc *,
241e5ec1e72Spatrick 		    struct bwfm_pci_msgring *, int);
242e5ec1e72Spatrick 
243e5ec1e72Spatrick void		 bwfm_pci_ring_rx(struct bwfm_pci_softc *,
244e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
245e5ec1e72Spatrick void		 bwfm_pci_msg_rx(struct bwfm_pci_softc *, void *);
246e5ec1e72Spatrick 
247e5ec1e72Spatrick uint32_t	 bwfm_pci_buscore_read(struct bwfm_softc *, uint32_t);
248e5ec1e72Spatrick void		 bwfm_pci_buscore_write(struct bwfm_softc *, uint32_t,
249e5ec1e72Spatrick 		    uint32_t);
250e5ec1e72Spatrick int		 bwfm_pci_buscore_prepare(struct bwfm_softc *);
251e5ec1e72Spatrick int		 bwfm_pci_buscore_reset(struct bwfm_softc *);
252e5ec1e72Spatrick void		 bwfm_pci_buscore_activate(struct bwfm_softc *, uint32_t);
253e5ec1e72Spatrick 
254f67437f3Spatrick int		 bwfm_pci_flowring_lookup(struct bwfm_pci_softc *,
255f67437f3Spatrick 		     struct mbuf *);
256f67437f3Spatrick void		 bwfm_pci_flowring_create(struct bwfm_pci_softc *,
257518be5f3Spatrick 		     struct mbuf *);
258518be5f3Spatrick void		 bwfm_pci_flowring_create_cb(struct bwfm_softc *, void *);
259a2c6ff8bSpatrick void		 bwfm_pci_flowring_delete(struct bwfm_pci_softc *, int);
260518be5f3Spatrick 
261972218f3Spatrick int		 bwfm_pci_preinit(struct bwfm_softc *);
262a2c6ff8bSpatrick void		 bwfm_pci_stop(struct bwfm_softc *);
26302ee7d07Spatrick int		 bwfm_pci_txcheck(struct bwfm_softc *);
264e5ec1e72Spatrick int		 bwfm_pci_txdata(struct bwfm_softc *, struct mbuf *);
265bbd71b0bSpatrick 
266bbd71b0bSpatrick #ifdef BWFM_DEBUG
267cadf5fcfSpatrick void		 bwfm_pci_debug_console(struct bwfm_pci_softc *);
268bbd71b0bSpatrick #endif
269e5ec1e72Spatrick 
270e5ec1e72Spatrick int		 bwfm_pci_msgbuf_query_dcmd(struct bwfm_softc *, int,
271e5ec1e72Spatrick 		    int, char *, size_t *);
272e5ec1e72Spatrick int		 bwfm_pci_msgbuf_set_dcmd(struct bwfm_softc *, int,
273e5ec1e72Spatrick 		    int, char *, size_t);
274e5ec1e72Spatrick 
275e5ec1e72Spatrick struct bwfm_buscore_ops bwfm_pci_buscore_ops = {
276e5ec1e72Spatrick 	.bc_read = bwfm_pci_buscore_read,
277e5ec1e72Spatrick 	.bc_write = bwfm_pci_buscore_write,
278e5ec1e72Spatrick 	.bc_prepare = bwfm_pci_buscore_prepare,
279e5ec1e72Spatrick 	.bc_reset = bwfm_pci_buscore_reset,
280e5ec1e72Spatrick 	.bc_setup = NULL,
281e5ec1e72Spatrick 	.bc_activate = bwfm_pci_buscore_activate,
282e5ec1e72Spatrick };
283e5ec1e72Spatrick 
284e5ec1e72Spatrick struct bwfm_bus_ops bwfm_pci_bus_ops = {
285972218f3Spatrick 	.bs_preinit = bwfm_pci_preinit,
286a2c6ff8bSpatrick 	.bs_stop = bwfm_pci_stop,
28702ee7d07Spatrick 	.bs_txcheck = bwfm_pci_txcheck,
288e5ec1e72Spatrick 	.bs_txdata = bwfm_pci_txdata,
289e5ec1e72Spatrick 	.bs_txctl = NULL,
290e5ec1e72Spatrick };
291e5ec1e72Spatrick 
292e5ec1e72Spatrick struct bwfm_proto_ops bwfm_pci_msgbuf_ops = {
293e5ec1e72Spatrick 	.proto_query_dcmd = bwfm_pci_msgbuf_query_dcmd,
294e5ec1e72Spatrick 	.proto_set_dcmd = bwfm_pci_msgbuf_set_dcmd,
29514c74651Spatrick 	.proto_rx = NULL,
296029d6dd5Spatrick 	.proto_rxctl = NULL,
297e5ec1e72Spatrick };
298e5ec1e72Spatrick 
299e5ec1e72Spatrick struct cfattach bwfm_pci_ca = {
300e5ec1e72Spatrick 	sizeof(struct bwfm_pci_softc),
301e5ec1e72Spatrick 	bwfm_pci_match,
302e5ec1e72Spatrick 	bwfm_pci_attach,
303e5ec1e72Spatrick 	bwfm_pci_detach,
304e5ec1e72Spatrick };
305e5ec1e72Spatrick 
306e5ec1e72Spatrick static const struct pci_matchid bwfm_pci_devices[] = {
30782f0e660Sjcs 	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4350 },
308*41d93ac2Spatrick 	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4356 },
309*41d93ac2Spatrick 	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM43602 },
310e5ec1e72Spatrick };
311e5ec1e72Spatrick 
312e5ec1e72Spatrick int
313e5ec1e72Spatrick bwfm_pci_match(struct device *parent, void *match, void *aux)
314e5ec1e72Spatrick {
315e5ec1e72Spatrick 	return (pci_matchbyid(aux, bwfm_pci_devices,
316e5ec1e72Spatrick 	    nitems(bwfm_pci_devices)));
317e5ec1e72Spatrick }
318e5ec1e72Spatrick 
319e5ec1e72Spatrick void
320e5ec1e72Spatrick bwfm_pci_attach(struct device *parent, struct device *self, void *aux)
321e5ec1e72Spatrick {
322e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (struct bwfm_pci_softc *)self;
323e5ec1e72Spatrick 	struct pci_attach_args *pa = (struct pci_attach_args *)aux;
324e5ec1e72Spatrick 	const char *intrstr;
325e5ec1e72Spatrick 	pci_intr_handle_t ih;
326e5ec1e72Spatrick 
327e5ec1e72Spatrick 	if (pci_mapreg_map(pa, PCI_MAPREG_START + 0x08,
328e5ec1e72Spatrick 	    PCI_MAPREG_MEM_TYPE_64BIT, 0, &sc->sc_tcm_iot, &sc->sc_tcm_ioh,
329e5ec1e72Spatrick 	    NULL, &sc->sc_tcm_ios, 0)) {
330e5ec1e72Spatrick 		printf(": can't map bar1\n");
331a08e9144Spatrick 		return;
332a08e9144Spatrick 	}
333a08e9144Spatrick 
334a08e9144Spatrick 	if (pci_mapreg_map(pa, PCI_MAPREG_START + 0x00,
335a08e9144Spatrick 	    PCI_MAPREG_MEM_TYPE_64BIT, 0, &sc->sc_reg_iot, &sc->sc_reg_ioh,
336a08e9144Spatrick 	    NULL, &sc->sc_reg_ios, 0)) {
337a08e9144Spatrick 		printf(": can't map bar0\n");
338a08e9144Spatrick 		goto bar1;
339e5ec1e72Spatrick 	}
340e5ec1e72Spatrick 
341e5ec1e72Spatrick 	sc->sc_pc = pa->pa_pc;
342e5ec1e72Spatrick 	sc->sc_tag = pa->pa_tag;
343e5ec1e72Spatrick 	sc->sc_id = pa->pa_id;
344e5ec1e72Spatrick 	sc->sc_dmat = pa->pa_dmat;
345e5ec1e72Spatrick 
346e5ec1e72Spatrick 	/* Map and establish the interrupt. */
347e5ec1e72Spatrick 	if (pci_intr_map_msi(pa, &ih) != 0 && pci_intr_map(pa, &ih) != 0) {
348e5ec1e72Spatrick 		printf(": couldn't map interrupt\n");
349a08e9144Spatrick 		goto bar0;
350e5ec1e72Spatrick 	}
351e5ec1e72Spatrick 	intrstr = pci_intr_string(pa->pa_pc, ih);
352e5ec1e72Spatrick 
353e5ec1e72Spatrick 	sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_NET | IPL_MPSAFE,
354e5ec1e72Spatrick 	    bwfm_pci_intr, sc, DEVNAME(sc));
355e5ec1e72Spatrick 	if (sc->sc_ih == NULL) {
356e5ec1e72Spatrick 		printf(": couldn't establish interrupt");
357e5ec1e72Spatrick 		if (intrstr != NULL)
358e5ec1e72Spatrick 			printf(" at %s", intrstr);
359e5ec1e72Spatrick 		printf("\n");
360e5ec1e72Spatrick 		goto bar1;
361e5ec1e72Spatrick 	}
362e5ec1e72Spatrick 	printf(": %s\n", intrstr);
363e5ec1e72Spatrick 
364972218f3Spatrick 	sc->sc_sc.sc_bus_ops = &bwfm_pci_bus_ops;
365972218f3Spatrick 	sc->sc_sc.sc_proto_ops = &bwfm_pci_msgbuf_ops;
366972218f3Spatrick 	bwfm_attach(&sc->sc_sc);
367972218f3Spatrick 	config_mountroot(self, bwfm_attachhook);
368e5ec1e72Spatrick 	return;
369e5ec1e72Spatrick 
370e5ec1e72Spatrick bar0:
371e5ec1e72Spatrick 	bus_space_unmap(sc->sc_reg_iot, sc->sc_reg_ioh, sc->sc_reg_ios);
372a08e9144Spatrick bar1:
373a08e9144Spatrick 	bus_space_unmap(sc->sc_tcm_iot, sc->sc_tcm_ioh, sc->sc_tcm_ios);
374e5ec1e72Spatrick }
375e5ec1e72Spatrick 
376972218f3Spatrick int
377972218f3Spatrick bwfm_pci_preinit(struct bwfm_softc *bwfm)
378e5ec1e72Spatrick {
379972218f3Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
380e5ec1e72Spatrick 	struct bwfm_pci_ringinfo ringinfo;
3816aad491fSpatrick 	const char *name, *nvname;
3826aad491fSpatrick 	u_char *ucode, *nvram = NULL;
3836aad491fSpatrick 	size_t size, nvlen = 0;
384e5ec1e72Spatrick 	uint32_t d2h_w_idx_ptr, d2h_r_idx_ptr;
385e5ec1e72Spatrick 	uint32_t h2d_w_idx_ptr, h2d_r_idx_ptr;
386e5ec1e72Spatrick 	uint32_t idx_offset, reg;
387e5ec1e72Spatrick 	int i;
388e5ec1e72Spatrick 
389972218f3Spatrick 	if (sc->sc_initialized)
390972218f3Spatrick 		return 0;
391972218f3Spatrick 
392e5ec1e72Spatrick 	sc->sc_sc.sc_buscore_ops = &bwfm_pci_buscore_ops;
393e5ec1e72Spatrick 	if (bwfm_chip_attach(&sc->sc_sc) != 0) {
394e5ec1e72Spatrick 		printf("%s: cannot attach chip\n", DEVNAME(sc));
395972218f3Spatrick 		return 1;
396e5ec1e72Spatrick 	}
397e5ec1e72Spatrick 
398e5ec1e72Spatrick 	bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2);
399e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
400e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_CONFIGADDR, 0x4e0);
401e5ec1e72Spatrick 	reg = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
402e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_CONFIGDATA);
403e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
404e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_CONFIGDATA, reg);
405e5ec1e72Spatrick 
406e5ec1e72Spatrick 	switch (bwfm->sc_chip.ch_chip)
407e5ec1e72Spatrick 	{
40818b3a1dcSpatrick 	case BRCM_CC_4350_CHIP_ID:
4096aad491fSpatrick 		if (bwfm->sc_chip.ch_chiprev > 7) {
41018b3a1dcSpatrick 			name = "brcmfmac4350-pcie.bin";
4116aad491fSpatrick 			nvname = "brcmfmac4350-pcie.nvram";
4126aad491fSpatrick 		} else {
41318b3a1dcSpatrick 			name = "brcmfmac4350c2-pcie.bin";
4146aad491fSpatrick 			nvname = "brcmfmac4350c2-pcie.nvram";
4156aad491fSpatrick 		}
41618b3a1dcSpatrick 		break;
417*41d93ac2Spatrick 	case BRCM_CC_4356_CHIP_ID:
418*41d93ac2Spatrick 		name = "brcmfmac4356-pcie.bin";
419*41d93ac2Spatrick 		nvname = "brcmfmac4356-pcie.nvram";
420*41d93ac2Spatrick 		break;
421e5ec1e72Spatrick 	case BRCM_CC_43602_CHIP_ID:
422e5ec1e72Spatrick 		name = "brcmfmac43602-pcie.bin";
4236aad491fSpatrick 		nvname = "brcmfmac43602-pcie.nvram";
424e5ec1e72Spatrick 		break;
425e5ec1e72Spatrick 	default:
42618b3a1dcSpatrick 		printf("%s: unknown firmware for chip %s\n",
42718b3a1dcSpatrick 		    DEVNAME(sc), bwfm->sc_chip.ch_name);
428972218f3Spatrick 		return 1;
429e5ec1e72Spatrick 	}
430e5ec1e72Spatrick 
431e5ec1e72Spatrick 	if (loadfirmware(name, &ucode, &size) != 0) {
432e5ec1e72Spatrick 		printf("%s: failed loadfirmware of file %s\n",
433e5ec1e72Spatrick 		    DEVNAME(sc), name);
434972218f3Spatrick 		return 1;
435e5ec1e72Spatrick 	}
436e5ec1e72Spatrick 
4376aad491fSpatrick 	/* NVRAM is optional. */
4386aad491fSpatrick 	loadfirmware(nvname, &nvram, &nvlen);
4396aad491fSpatrick 
440e5ec1e72Spatrick 	/* Retrieve RAM size from firmware. */
441e5ec1e72Spatrick 	if (size >= BWFM_RAMSIZE + 8) {
442e5ec1e72Spatrick 		uint32_t *ramsize = (uint32_t *)&ucode[BWFM_RAMSIZE];
443e5ec1e72Spatrick 		if (letoh32(ramsize[0]) == BWFM_RAMSIZE_MAGIC)
444e5ec1e72Spatrick 			bwfm->sc_chip.ch_ramsize = letoh32(ramsize[1]);
445e5ec1e72Spatrick 	}
446e5ec1e72Spatrick 
4476aad491fSpatrick 	if (bwfm_pci_load_microcode(sc, ucode, size, nvram, nvlen) != 0) {
448e5ec1e72Spatrick 		printf("%s: could not load microcode\n",
449e5ec1e72Spatrick 		    DEVNAME(sc));
450e5ec1e72Spatrick 		free(ucode, M_DEVBUF, size);
4516aad491fSpatrick 		free(nvram, M_DEVBUF, nvlen);
452972218f3Spatrick 		return 1;
453e5ec1e72Spatrick 	}
454e5ec1e72Spatrick 	free(ucode, M_DEVBUF, size);
4556aad491fSpatrick 	free(nvram, M_DEVBUF, nvlen);
456e5ec1e72Spatrick 
457e5ec1e72Spatrick 	sc->sc_shared_flags = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
458e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_INFO);
459e5ec1e72Spatrick 	sc->sc_shared_version = sc->sc_shared_flags;
460e5ec1e72Spatrick 	if (sc->sc_shared_version > BWFM_SHARED_INFO_MAX_VERSION ||
461e5ec1e72Spatrick 	    sc->sc_shared_version < BWFM_SHARED_INFO_MIN_VERSION) {
462e5ec1e72Spatrick 		printf("%s: PCIe version %d unsupported\n",
463e5ec1e72Spatrick 		    DEVNAME(sc), sc->sc_shared_version);
464972218f3Spatrick 		return 1;
465e5ec1e72Spatrick 	}
466e5ec1e72Spatrick 
467e5ec1e72Spatrick 	if (sc->sc_shared_flags & BWFM_SHARED_INFO_DMA_INDEX) {
468e5ec1e72Spatrick 		if (sc->sc_shared_flags & BWFM_SHARED_INFO_DMA_2B_IDX)
469e5ec1e72Spatrick 			sc->sc_dma_idx_sz = sizeof(uint16_t);
470e5ec1e72Spatrick 		else
471e5ec1e72Spatrick 			sc->sc_dma_idx_sz = sizeof(uint32_t);
472e5ec1e72Spatrick 	}
473e5ec1e72Spatrick 
474e5ec1e72Spatrick 	/* Maximum RX data buffers in the ring. */
475e5ec1e72Spatrick 	sc->sc_max_rxbufpost = bus_space_read_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
476e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_MAX_RXBUFPOST);
477e5ec1e72Spatrick 	if (sc->sc_max_rxbufpost == 0)
478e5ec1e72Spatrick 		sc->sc_max_rxbufpost = BWFM_SHARED_MAX_RXBUFPOST_DEFAULT;
479e5ec1e72Spatrick 
480e5ec1e72Spatrick 	/* Alternative offset of data in a packet */
481e5ec1e72Spatrick 	sc->sc_rx_dataoffset = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
482e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_RX_DATAOFFSET);
483e5ec1e72Spatrick 
484e5ec1e72Spatrick 	/* For Power Management */
485e5ec1e72Spatrick 	sc->sc_htod_mb_data_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
486e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_HTOD_MB_DATA_ADDR);
487e5ec1e72Spatrick 	sc->sc_dtoh_mb_data_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
488e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DTOH_MB_DATA_ADDR);
489e5ec1e72Spatrick 
490e5ec1e72Spatrick 	/* Ring information */
491e5ec1e72Spatrick 	sc->sc_ring_info_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
492e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_RING_INFO_ADDR);
493e5ec1e72Spatrick 
494e5ec1e72Spatrick 	/* Firmware's "dmesg" */
495e5ec1e72Spatrick 	sc->sc_console_base_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
496e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_CONSOLE_ADDR);
497e5ec1e72Spatrick 	sc->sc_console_buf_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
498e5ec1e72Spatrick 	    sc->sc_console_base_addr + BWFM_CONSOLE_BUFADDR);
499e5ec1e72Spatrick 	sc->sc_console_buf_size = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
500e5ec1e72Spatrick 	    sc->sc_console_base_addr + BWFM_CONSOLE_BUFSIZE);
501e5ec1e72Spatrick 
502e5ec1e72Spatrick 	/* Read ring information. */
503e5ec1e72Spatrick 	bus_space_read_region_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
504e5ec1e72Spatrick 	    sc->sc_ring_info_addr, (void *)&ringinfo, sizeof(ringinfo));
505e5ec1e72Spatrick 
506e5ec1e72Spatrick 	if (sc->sc_shared_version >= 6) {
507e5ec1e72Spatrick 		sc->sc_max_submissionrings = le16toh(ringinfo.max_submissionrings);
508e5ec1e72Spatrick 		sc->sc_max_flowrings = le16toh(ringinfo.max_flowrings);
509e5ec1e72Spatrick 		sc->sc_max_completionrings = le16toh(ringinfo.max_completionrings);
510e5ec1e72Spatrick 	} else {
511e5ec1e72Spatrick 		sc->sc_max_submissionrings = le16toh(ringinfo.max_flowrings);
512e5ec1e72Spatrick 		sc->sc_max_flowrings = sc->sc_max_submissionrings -
513e5ec1e72Spatrick 		    BWFM_NUM_TX_MSGRINGS;
514e5ec1e72Spatrick 		sc->sc_max_completionrings = BWFM_NUM_RX_MSGRINGS;
515e5ec1e72Spatrick 	}
516e5ec1e72Spatrick 
517e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
518e5ec1e72Spatrick 		d2h_w_idx_ptr = letoh32(ringinfo.d2h_w_idx_ptr);
519e5ec1e72Spatrick 		d2h_r_idx_ptr = letoh32(ringinfo.d2h_r_idx_ptr);
520e5ec1e72Spatrick 		h2d_w_idx_ptr = letoh32(ringinfo.h2d_w_idx_ptr);
521e5ec1e72Spatrick 		h2d_r_idx_ptr = letoh32(ringinfo.h2d_r_idx_ptr);
522e5ec1e72Spatrick 		idx_offset = sizeof(uint32_t);
523e5ec1e72Spatrick 	} else {
524e5ec1e72Spatrick 		uint64_t address;
525e5ec1e72Spatrick 
526e5ec1e72Spatrick 		/* Each TX/RX Ring has a Read and Write Ptr */
527e5ec1e72Spatrick 		sc->sc_dma_idx_bufsz = (sc->sc_max_submissionrings +
528e5ec1e72Spatrick 		    sc->sc_max_completionrings) * sc->sc_dma_idx_sz * 2;
529e5ec1e72Spatrick 		sc->sc_dma_idx_buf = bwfm_pci_dmamem_alloc(sc,
530e5ec1e72Spatrick 		    sc->sc_dma_idx_bufsz, 8);
531e5ec1e72Spatrick 		if (sc->sc_dma_idx_buf == NULL) {
532e5ec1e72Spatrick 			/* XXX: Fallback to TCM? */
533e5ec1e72Spatrick 			printf("%s: cannot allocate idx buf\n",
534e5ec1e72Spatrick 			    DEVNAME(sc));
535972218f3Spatrick 			return 1;
536e5ec1e72Spatrick 		}
537e5ec1e72Spatrick 
538e5ec1e72Spatrick 		idx_offset = sc->sc_dma_idx_sz;
539e5ec1e72Spatrick 		h2d_w_idx_ptr = 0;
540e5ec1e72Spatrick 		address = BWFM_PCI_DMA_DVA(sc->sc_dma_idx_buf);
541e5ec1e72Spatrick 		ringinfo.h2d_w_idx_hostaddr_low =
542e5ec1e72Spatrick 		    htole32(address & 0xffffffff);
543e5ec1e72Spatrick 		ringinfo.h2d_w_idx_hostaddr_high =
544e5ec1e72Spatrick 		    htole32(address >> 32);
545e5ec1e72Spatrick 
546e5ec1e72Spatrick 		h2d_r_idx_ptr = h2d_w_idx_ptr +
547e5ec1e72Spatrick 		    sc->sc_max_submissionrings * idx_offset;
548e5ec1e72Spatrick 		address += sc->sc_max_submissionrings * idx_offset;
549e5ec1e72Spatrick 		ringinfo.h2d_r_idx_hostaddr_low =
550e5ec1e72Spatrick 		    htole32(address & 0xffffffff);
551e5ec1e72Spatrick 		ringinfo.h2d_r_idx_hostaddr_high =
552e5ec1e72Spatrick 		    htole32(address >> 32);
553e5ec1e72Spatrick 
554e5ec1e72Spatrick 		d2h_w_idx_ptr = h2d_r_idx_ptr +
555e5ec1e72Spatrick 		    sc->sc_max_submissionrings * idx_offset;
556e5ec1e72Spatrick 		address += sc->sc_max_submissionrings * idx_offset;
557e5ec1e72Spatrick 		ringinfo.d2h_w_idx_hostaddr_low =
558e5ec1e72Spatrick 		    htole32(address & 0xffffffff);
559e5ec1e72Spatrick 		ringinfo.d2h_w_idx_hostaddr_high =
560e5ec1e72Spatrick 		    htole32(address >> 32);
561e5ec1e72Spatrick 
562e5ec1e72Spatrick 		d2h_r_idx_ptr = d2h_w_idx_ptr +
563e5ec1e72Spatrick 		    sc->sc_max_completionrings * idx_offset;
564e5ec1e72Spatrick 		address += sc->sc_max_completionrings * idx_offset;
565e5ec1e72Spatrick 		ringinfo.d2h_r_idx_hostaddr_low =
566e5ec1e72Spatrick 		    htole32(address & 0xffffffff);
567e5ec1e72Spatrick 		ringinfo.d2h_r_idx_hostaddr_high =
568e5ec1e72Spatrick 		    htole32(address >> 32);
569e5ec1e72Spatrick 
570e5ec1e72Spatrick 		bus_space_write_region_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
571e5ec1e72Spatrick 		    sc->sc_ring_info_addr, (void *)&ringinfo, sizeof(ringinfo));
572e5ec1e72Spatrick 	}
573e5ec1e72Spatrick 
574e5ec1e72Spatrick 	uint32_t ring_mem_ptr = letoh32(ringinfo.ringmem);
575e5ec1e72Spatrick 	/* TX ctrl ring: Send ctrl buffers, send IOCTLs */
576e5ec1e72Spatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_ctrl_submit, 64, 40,
577e5ec1e72Spatrick 	    h2d_w_idx_ptr, h2d_r_idx_ptr, 0, idx_offset,
578e5ec1e72Spatrick 	    &ring_mem_ptr))
579e5ec1e72Spatrick 		goto cleanup;
580e5ec1e72Spatrick 	/* TX rxpost ring: Send clean data mbufs for RX */
581e5ec1e72Spatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_rxpost_submit, 512, 32,
582e5ec1e72Spatrick 	    h2d_w_idx_ptr, h2d_r_idx_ptr, 1, idx_offset,
583e5ec1e72Spatrick 	    &ring_mem_ptr))
584e5ec1e72Spatrick 		goto cleanup;
585e5ec1e72Spatrick 	/* RX completion rings: recv our filled buffers back */
586e5ec1e72Spatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_ctrl_complete, 64, 24,
587e5ec1e72Spatrick 	    d2h_w_idx_ptr, d2h_r_idx_ptr, 0, idx_offset,
588e5ec1e72Spatrick 	    &ring_mem_ptr))
589e5ec1e72Spatrick 		goto cleanup;
590e5ec1e72Spatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_tx_complete, 1024, 16,
591e5ec1e72Spatrick 	    d2h_w_idx_ptr, d2h_r_idx_ptr, 1, idx_offset,
592e5ec1e72Spatrick 	    &ring_mem_ptr))
593e5ec1e72Spatrick 		goto cleanup;
594e5ec1e72Spatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_rx_complete, 512, 32,
595e5ec1e72Spatrick 	    d2h_w_idx_ptr, d2h_r_idx_ptr, 2, idx_offset,
596e5ec1e72Spatrick 	    &ring_mem_ptr))
597e5ec1e72Spatrick 		goto cleanup;
598e5ec1e72Spatrick 
599e5ec1e72Spatrick 	/* Dynamic TX rings for actual data */
600e5ec1e72Spatrick 	sc->sc_flowrings = malloc(sc->sc_max_flowrings *
601e5ec1e72Spatrick 	    sizeof(struct bwfm_pci_msgring), M_DEVBUF, M_WAITOK | M_ZERO);
602518be5f3Spatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
603518be5f3Spatrick 		struct bwfm_pci_msgring *ring = &sc->sc_flowrings[i];
604518be5f3Spatrick 		ring->w_idx_addr = h2d_w_idx_ptr + (i + 2) * idx_offset;
605518be5f3Spatrick 		ring->r_idx_addr = h2d_r_idx_ptr + (i + 2) * idx_offset;
606518be5f3Spatrick 	}
607e5ec1e72Spatrick 
608e5ec1e72Spatrick 	/* Scratch and ring update buffers for firmware */
609e5ec1e72Spatrick 	if ((sc->sc_scratch_buf = bwfm_pci_dmamem_alloc(sc,
610e5ec1e72Spatrick 	    BWFM_DMA_D2H_SCRATCH_BUF_LEN, 8)) == NULL)
611e5ec1e72Spatrick 		goto cleanup;
612e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
613e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_SCRATCH_ADDR_LOW,
614e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(sc->sc_scratch_buf) & 0xffffffff);
615e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
616e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_SCRATCH_ADDR_HIGH,
617e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(sc->sc_scratch_buf) >> 32);
618e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
619e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_SCRATCH_LEN,
620e5ec1e72Spatrick 	    BWFM_DMA_D2H_SCRATCH_BUF_LEN);
621e5ec1e72Spatrick 
622e5ec1e72Spatrick 	if ((sc->sc_ringupd_buf = bwfm_pci_dmamem_alloc(sc,
623e5ec1e72Spatrick 	    BWFM_DMA_D2H_RINGUPD_BUF_LEN, 8)) == NULL)
624e5ec1e72Spatrick 		goto cleanup;
625e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
626e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_RINGUPD_ADDR_LOW,
627e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(sc->sc_ringupd_buf) & 0xffffffff);
628e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
629e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_RINGUPD_ADDR_HIGH,
630e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(sc->sc_ringupd_buf) >> 32);
631e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
632e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_RINGUPD_LEN,
633e5ec1e72Spatrick 	    BWFM_DMA_D2H_RINGUPD_BUF_LEN);
634e5ec1e72Spatrick 
635e5ec1e72Spatrick 	if ((sc->sc_ioctl_buf = bwfm_pci_dmamem_alloc(sc,
636e5ec1e72Spatrick 	    BWFM_DMA_H2D_IOCTL_BUF_LEN, 8)) == NULL)
637e5ec1e72Spatrick 		goto cleanup;
638e5ec1e72Spatrick 
639e5ec1e72Spatrick 	bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2);
640e5ec1e72Spatrick 	bwfm_pci_intr_enable(sc);
641e5ec1e72Spatrick 
642e5ec1e72Spatrick 	/* Maps RX mbufs to a packet id and back. */
643e5ec1e72Spatrick 	sc->sc_rx_pkts.npkt = BWFM_NUM_RX_PKTIDS;
644e5ec1e72Spatrick 	sc->sc_rx_pkts.pkts = malloc(BWFM_NUM_RX_PKTIDS *
645e5ec1e72Spatrick 	    sizeof(struct bwfm_pci_buf), M_DEVBUF, M_WAITOK | M_ZERO);
646e5ec1e72Spatrick 	for (i = 0; i < BWFM_NUM_RX_PKTIDS; i++)
647e5ec1e72Spatrick 		bus_dmamap_create(sc->sc_dmat, MSGBUF_MAX_PKT_SIZE,
648e5ec1e72Spatrick 		    BWFM_NUM_RX_DESCS, MSGBUF_MAX_PKT_SIZE, 0, BUS_DMA_WAITOK,
649e5ec1e72Spatrick 		    &sc->sc_rx_pkts.pkts[i].bb_map);
650e5ec1e72Spatrick 
651e5ec1e72Spatrick 	/* Maps TX mbufs to a packet id and back. */
652f416501bSpatrick 	sc->sc_tx_pkts.npkt = BWFM_NUM_TX_PKTIDS;
653e5ec1e72Spatrick 	sc->sc_tx_pkts.pkts = malloc(BWFM_NUM_TX_PKTIDS
654e5ec1e72Spatrick 	    * sizeof(struct bwfm_pci_buf), M_DEVBUF, M_WAITOK | M_ZERO);
655e5ec1e72Spatrick 	for (i = 0; i < BWFM_NUM_TX_PKTIDS; i++)
656e5ec1e72Spatrick 		bus_dmamap_create(sc->sc_dmat, MSGBUF_MAX_PKT_SIZE,
657e5ec1e72Spatrick 		    BWFM_NUM_TX_DESCS, MSGBUF_MAX_PKT_SIZE, 0, BUS_DMA_WAITOK,
658e5ec1e72Spatrick 		    &sc->sc_tx_pkts.pkts[i].bb_map);
659e5ec1e72Spatrick 
66018722113Spatrick 	/*
66118722113Spatrick 	 * For whatever reason, could also be a bug somewhere in this
66218722113Spatrick 	 * driver, the firmware needs a bunch of RX buffers otherwise
66318722113Spatrick 	 * it won't send any RX complete messages.  64 buffers don't
66418722113Spatrick 	 * suffice, but 128 buffers are enough.
66518722113Spatrick 	 */
66618722113Spatrick 	if_rxr_init(&sc->sc_rxbuf_ring, 128, sc->sc_max_rxbufpost);
667e5ec1e72Spatrick 	if_rxr_init(&sc->sc_ioctl_ring, 8, 8);
668e5ec1e72Spatrick 	if_rxr_init(&sc->sc_event_ring, 8, 8);
669e5ec1e72Spatrick 	bwfm_pci_fill_rx_rings(sc);
670e5ec1e72Spatrick 
671cadf5fcfSpatrick #ifdef BWFM_DEBUG
672cadf5fcfSpatrick 	sc->sc_console_readidx = 0;
673cadf5fcfSpatrick 	bwfm_pci_debug_console(sc);
674cadf5fcfSpatrick #endif
675cadf5fcfSpatrick 
676972218f3Spatrick 	sc->sc_initialized = 1;
677972218f3Spatrick 	return 0;
678e5ec1e72Spatrick 
679e5ec1e72Spatrick cleanup:
680e5ec1e72Spatrick 	if (sc->sc_ioctl_buf)
681e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_ioctl_buf);
682e5ec1e72Spatrick 	if (sc->sc_ringupd_buf)
683e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_ringupd_buf);
684e5ec1e72Spatrick 	if (sc->sc_scratch_buf)
685e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_scratch_buf);
686e5ec1e72Spatrick 	if (sc->sc_rx_complete.ring)
687e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_rx_complete.ring);
688e5ec1e72Spatrick 	if (sc->sc_tx_complete.ring)
689e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_tx_complete.ring);
690e5ec1e72Spatrick 	if (sc->sc_ctrl_complete.ring)
691e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_ctrl_complete.ring);
692e5ec1e72Spatrick 	if (sc->sc_rxpost_submit.ring)
693e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_rxpost_submit.ring);
694e5ec1e72Spatrick 	if (sc->sc_ctrl_submit.ring)
695e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_ctrl_submit.ring);
696e5ec1e72Spatrick 	if (sc->sc_dma_idx_buf)
697e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_dma_idx_buf);
698972218f3Spatrick 	return 1;
699e5ec1e72Spatrick }
700e5ec1e72Spatrick 
701e5ec1e72Spatrick int
7026aad491fSpatrick bwfm_pci_load_microcode(struct bwfm_pci_softc *sc, const u_char *ucode, size_t size,
7036aad491fSpatrick     const u_char *nvram, size_t nvlen)
704e5ec1e72Spatrick {
705e5ec1e72Spatrick 	struct bwfm_softc *bwfm = (void *)sc;
706e5ec1e72Spatrick 	struct bwfm_core *core;
7076aad491fSpatrick 	uint32_t shared, written;
708e5ec1e72Spatrick 	int i;
709e5ec1e72Spatrick 
710e5ec1e72Spatrick 	if (bwfm->sc_chip.ch_chip == BRCM_CC_43602_CHIP_ID) {
711e5ec1e72Spatrick 		bwfm_pci_select_core(sc, BWFM_AGENT_CORE_ARM_CR4);
712e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
713e5ec1e72Spatrick 		    BWFM_PCI_ARMCR4REG_BANKIDX, 5);
714e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
715e5ec1e72Spatrick 		    BWFM_PCI_ARMCR4REG_BANKPDA, 0);
716e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
717e5ec1e72Spatrick 		    BWFM_PCI_ARMCR4REG_BANKIDX, 7);
718e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
719e5ec1e72Spatrick 		    BWFM_PCI_ARMCR4REG_BANKPDA, 0);
720e5ec1e72Spatrick 	}
721e5ec1e72Spatrick 
722e5ec1e72Spatrick 	for (i = 0; i < size; i++)
723e5ec1e72Spatrick 		bus_space_write_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
724e5ec1e72Spatrick 		    bwfm->sc_chip.ch_rambase + i, ucode[i]);
725e5ec1e72Spatrick 
726e5ec1e72Spatrick 	/* Firmware replaces this with a pointer once up. */
727e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
728e5ec1e72Spatrick 	    bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize - 4, 0);
729e5ec1e72Spatrick 
7306aad491fSpatrick 	if (nvram) {
7316aad491fSpatrick 		for (i = 0; i < nvlen; i++)
7326aad491fSpatrick 			bus_space_write_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
7336aad491fSpatrick 			    bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize
7346aad491fSpatrick 			    - nvlen  + i, nvram[i]);
7356aad491fSpatrick 	}
7366aad491fSpatrick 
7376aad491fSpatrick 	written = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
7386aad491fSpatrick 	    bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize - 4);
739e5ec1e72Spatrick 
740e5ec1e72Spatrick 	/* Load reset vector from firmware and kickstart core. */
741b0cd4990Spatrick 	if (bwfm->sc_chip.ch_chip == BRCM_CC_43602_CHIP_ID) {
742e5ec1e72Spatrick 		core = bwfm_chip_get_core(bwfm, BWFM_AGENT_INTERNAL_MEM);
743e5ec1e72Spatrick 		bwfm->sc_chip.ch_core_reset(bwfm, core, 0, 0, 0);
744b0cd4990Spatrick 	}
745e5ec1e72Spatrick 	bwfm_chip_set_active(bwfm, *(uint32_t *)ucode);
746e5ec1e72Spatrick 
747e5ec1e72Spatrick 	for (i = 0; i < 40; i++) {
748e5ec1e72Spatrick 		delay(50 * 1000);
749e5ec1e72Spatrick 		shared = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
750e5ec1e72Spatrick 		    bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize - 4);
7516aad491fSpatrick 		if (shared != written)
752e5ec1e72Spatrick 			break;
753e5ec1e72Spatrick 	}
754e5ec1e72Spatrick 	if (!shared) {
755e5ec1e72Spatrick 		printf("%s: firmware did not come up\n", DEVNAME(sc));
756e5ec1e72Spatrick 		return 1;
757e5ec1e72Spatrick 	}
758e5ec1e72Spatrick 
759e5ec1e72Spatrick 	sc->sc_shared_address = shared;
760e5ec1e72Spatrick 	return 0;
761e5ec1e72Spatrick }
762e5ec1e72Spatrick 
763e5ec1e72Spatrick int
764e5ec1e72Spatrick bwfm_pci_detach(struct device *self, int flags)
765e5ec1e72Spatrick {
766e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (struct bwfm_pci_softc *)self;
767e5ec1e72Spatrick 
768e5ec1e72Spatrick 	bwfm_detach(&sc->sc_sc, flags);
769e5ec1e72Spatrick 
770e5ec1e72Spatrick 	/* FIXME: free RX buffers */
771e5ec1e72Spatrick 	/* FIXME: free TX buffers */
772e5ec1e72Spatrick 	/* FIXME: free more memory */
773e5ec1e72Spatrick 
774e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_ioctl_buf);
775e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_ringupd_buf);
776e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_scratch_buf);
777e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_rx_complete.ring);
778e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_tx_complete.ring);
779e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_ctrl_complete.ring);
780e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_rxpost_submit.ring);
781e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_ctrl_submit.ring);
782e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_dma_idx_buf);
783e5ec1e72Spatrick 	return 0;
784e5ec1e72Spatrick }
785e5ec1e72Spatrick 
786e5ec1e72Spatrick /* DMA code */
787e5ec1e72Spatrick struct bwfm_pci_dmamem *
788e5ec1e72Spatrick bwfm_pci_dmamem_alloc(struct bwfm_pci_softc *sc, bus_size_t size, bus_size_t align)
789e5ec1e72Spatrick {
790e5ec1e72Spatrick 	struct bwfm_pci_dmamem *bdm;
791e5ec1e72Spatrick 	int nsegs;
792e5ec1e72Spatrick 
793e5ec1e72Spatrick 	bdm = malloc(sizeof(*bdm), M_DEVBUF, M_WAITOK | M_ZERO);
794e5ec1e72Spatrick 	bdm->bdm_size = size;
795e5ec1e72Spatrick 
796e5ec1e72Spatrick 	if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
797e5ec1e72Spatrick 	    BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &bdm->bdm_map) != 0)
798e5ec1e72Spatrick 		goto bdmfree;
799e5ec1e72Spatrick 
800e5ec1e72Spatrick 	if (bus_dmamem_alloc(sc->sc_dmat, size, align, 0, &bdm->bdm_seg, 1,
801e5ec1e72Spatrick 	    &nsegs, BUS_DMA_WAITOK) != 0)
802e5ec1e72Spatrick 		goto destroy;
803e5ec1e72Spatrick 
804e5ec1e72Spatrick 	if (bus_dmamem_map(sc->sc_dmat, &bdm->bdm_seg, nsegs, size,
805e5ec1e72Spatrick 	    &bdm->bdm_kva, BUS_DMA_WAITOK | BUS_DMA_COHERENT) != 0)
806e5ec1e72Spatrick 		goto free;
807e5ec1e72Spatrick 
808e5ec1e72Spatrick 	if (bus_dmamap_load(sc->sc_dmat, bdm->bdm_map, bdm->bdm_kva, size,
809e5ec1e72Spatrick 	    NULL, BUS_DMA_WAITOK) != 0)
810e5ec1e72Spatrick 		goto unmap;
811e5ec1e72Spatrick 
812e5ec1e72Spatrick 	bzero(bdm->bdm_kva, size);
813e5ec1e72Spatrick 
814e5ec1e72Spatrick 	return (bdm);
815e5ec1e72Spatrick 
816e5ec1e72Spatrick unmap:
817e5ec1e72Spatrick 	bus_dmamem_unmap(sc->sc_dmat, bdm->bdm_kva, size);
818e5ec1e72Spatrick free:
819e5ec1e72Spatrick 	bus_dmamem_free(sc->sc_dmat, &bdm->bdm_seg, 1);
820e5ec1e72Spatrick destroy:
821e5ec1e72Spatrick 	bus_dmamap_destroy(sc->sc_dmat, bdm->bdm_map);
822e5ec1e72Spatrick bdmfree:
82365046b40Spatrick 	free(bdm, M_DEVBUF, sizeof(*bdm));
824e5ec1e72Spatrick 
825e5ec1e72Spatrick 	return (NULL);
826e5ec1e72Spatrick }
827e5ec1e72Spatrick 
828e5ec1e72Spatrick void
829e5ec1e72Spatrick bwfm_pci_dmamem_free(struct bwfm_pci_softc *sc, struct bwfm_pci_dmamem *bdm)
830e5ec1e72Spatrick {
831e5ec1e72Spatrick 	bus_dmamem_unmap(sc->sc_dmat, bdm->bdm_kva, bdm->bdm_size);
832e5ec1e72Spatrick 	bus_dmamem_free(sc->sc_dmat, &bdm->bdm_seg, 1);
833e5ec1e72Spatrick 	bus_dmamap_destroy(sc->sc_dmat, bdm->bdm_map);
83465046b40Spatrick 	free(bdm, M_DEVBUF, sizeof(*bdm));
835e5ec1e72Spatrick }
836e5ec1e72Spatrick 
837e5ec1e72Spatrick /*
838e5ec1e72Spatrick  * We need a simple mapping from a packet ID to mbufs, because when
839e5ec1e72Spatrick  * a transfer completed, we only know the ID so we have to look up
840e5ec1e72Spatrick  * the memory for the ID.  This simply looks for an empty slot.
841e5ec1e72Spatrick  */
842e5ec1e72Spatrick int
84302ee7d07Spatrick bwfm_pci_pktid_avail(struct bwfm_pci_softc *sc, struct bwfm_pci_pkts *pkts)
84402ee7d07Spatrick {
84502ee7d07Spatrick 	int i, idx;
84602ee7d07Spatrick 
84702ee7d07Spatrick 	idx = pkts->last + 1;
84802ee7d07Spatrick 	for (i = 0; i < pkts->npkt; i++) {
84902ee7d07Spatrick 		if (idx == pkts->npkt)
85002ee7d07Spatrick 			idx = 0;
85102ee7d07Spatrick 		if (pkts->pkts[idx].bb_m == NULL)
85202ee7d07Spatrick 			return 0;
85302ee7d07Spatrick 		idx++;
85402ee7d07Spatrick 	}
85502ee7d07Spatrick 	return ENOBUFS;
85602ee7d07Spatrick }
85702ee7d07Spatrick 
85802ee7d07Spatrick int
859e5ec1e72Spatrick bwfm_pci_pktid_new(struct bwfm_pci_softc *sc, struct bwfm_pci_pkts *pkts,
860e5ec1e72Spatrick     struct mbuf *m, uint32_t *pktid, paddr_t *paddr)
861e5ec1e72Spatrick {
862e5ec1e72Spatrick 	int i, idx;
863e5ec1e72Spatrick 
864e5ec1e72Spatrick 	idx = pkts->last + 1;
865e5ec1e72Spatrick 	for (i = 0; i < pkts->npkt; i++) {
866e5ec1e72Spatrick 		if (idx == pkts->npkt)
867e5ec1e72Spatrick 			idx = 0;
868e5ec1e72Spatrick 		if (pkts->pkts[idx].bb_m == NULL) {
869e5ec1e72Spatrick 			if (bus_dmamap_load_mbuf(sc->sc_dmat,
870e5ec1e72Spatrick 			    pkts->pkts[idx].bb_map, m, BUS_DMA_NOWAIT) != 0) {
871518be5f3Spatrick 				if (m_defrag(m, M_DONTWAIT))
872518be5f3Spatrick 					return EFBIG;
873518be5f3Spatrick 				if (bus_dmamap_load_mbuf(sc->sc_dmat,
874518be5f3Spatrick 				    pkts->pkts[idx].bb_map, m, BUS_DMA_NOWAIT) != 0)
875518be5f3Spatrick 					return EFBIG;
876e5ec1e72Spatrick 			}
877e5ec1e72Spatrick 			pkts->last = idx;
878e5ec1e72Spatrick 			pkts->pkts[idx].bb_m = m;
879e5ec1e72Spatrick 			*pktid = idx;
880e5ec1e72Spatrick 			*paddr = pkts->pkts[idx].bb_map->dm_segs[0].ds_addr;
881e5ec1e72Spatrick 			return 0;
882e5ec1e72Spatrick 		}
883e5ec1e72Spatrick 		idx++;
884e5ec1e72Spatrick 	}
885518be5f3Spatrick 	return ENOBUFS;
886e5ec1e72Spatrick }
887e5ec1e72Spatrick 
888e5ec1e72Spatrick struct mbuf *
889e5ec1e72Spatrick bwfm_pci_pktid_free(struct bwfm_pci_softc *sc, struct bwfm_pci_pkts *pkts,
890e5ec1e72Spatrick     uint32_t pktid)
891e5ec1e72Spatrick {
892e5ec1e72Spatrick 	struct mbuf *m;
893e5ec1e72Spatrick 
894e5ec1e72Spatrick 	if (pktid >= pkts->npkt || pkts->pkts[pktid].bb_m == NULL)
895e5ec1e72Spatrick 		return NULL;
896e5ec1e72Spatrick 	bus_dmamap_unload(sc->sc_dmat, pkts->pkts[pktid].bb_map);
897e5ec1e72Spatrick 	m = pkts->pkts[pktid].bb_m;
898e5ec1e72Spatrick 	pkts->pkts[pktid].bb_m = NULL;
899e5ec1e72Spatrick 	return m;
900e5ec1e72Spatrick }
901e5ec1e72Spatrick 
902e5ec1e72Spatrick void
903e5ec1e72Spatrick bwfm_pci_fill_rx_rings(struct bwfm_pci_softc *sc)
904e5ec1e72Spatrick {
90518722113Spatrick 	bwfm_pci_fill_rx_buf_ring(sc);
906e5ec1e72Spatrick 	bwfm_pci_fill_rx_ioctl_ring(sc, &sc->sc_ioctl_ring,
907e5ec1e72Spatrick 	    MSGBUF_TYPE_IOCTLRESP_BUF_POST);
908e5ec1e72Spatrick 	bwfm_pci_fill_rx_ioctl_ring(sc, &sc->sc_event_ring,
909e5ec1e72Spatrick 	    MSGBUF_TYPE_EVENT_BUF_POST);
910e5ec1e72Spatrick }
911e5ec1e72Spatrick 
912e5ec1e72Spatrick void
913e5ec1e72Spatrick bwfm_pci_fill_rx_ioctl_ring(struct bwfm_pci_softc *sc, struct if_rxring *rxring,
914e5ec1e72Spatrick     uint32_t msgtype)
915e5ec1e72Spatrick {
916e5ec1e72Spatrick 	struct msgbuf_rx_ioctl_resp_or_event *req;
917e5ec1e72Spatrick 	struct mbuf *m;
918e5ec1e72Spatrick 	uint32_t pktid;
919e5ec1e72Spatrick 	paddr_t paddr;
920e5ec1e72Spatrick 	int s, slots;
921e5ec1e72Spatrick 
922e5ec1e72Spatrick 	s = splnet();
923e5ec1e72Spatrick 	for (slots = if_rxr_get(rxring, 8); slots > 0; slots--) {
92402ee7d07Spatrick 		if (bwfm_pci_pktid_avail(sc, &sc->sc_rx_pkts))
92502ee7d07Spatrick 			break;
926e5ec1e72Spatrick 		req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit);
927e5ec1e72Spatrick 		if (req == NULL)
928e5ec1e72Spatrick 			break;
929e5ec1e72Spatrick 		m = MCLGETI(NULL, M_DONTWAIT, NULL, MSGBUF_MAX_PKT_SIZE);
930e5ec1e72Spatrick 		if (m == NULL) {
931e5ec1e72Spatrick 			bwfm_pci_ring_write_cancel(sc, &sc->sc_ctrl_submit, 1);
932e5ec1e72Spatrick 			break;
933e5ec1e72Spatrick 		}
934e5ec1e72Spatrick 		m->m_len = m->m_pkthdr.len = MSGBUF_MAX_PKT_SIZE;
935e5ec1e72Spatrick 		if (bwfm_pci_pktid_new(sc, &sc->sc_rx_pkts, m, &pktid, &paddr)) {
936e5ec1e72Spatrick 			bwfm_pci_ring_write_cancel(sc, &sc->sc_ctrl_submit, 1);
937e5ec1e72Spatrick 			m_freem(m);
938e5ec1e72Spatrick 			break;
939e5ec1e72Spatrick 		}
940e5ec1e72Spatrick 		memset(req, 0, sizeof(*req));
941e5ec1e72Spatrick 		req->msg.msgtype = msgtype;
942e5ec1e72Spatrick 		req->msg.request_id = htole32(pktid);
943e5ec1e72Spatrick 		req->host_buf_len = htole16(MSGBUF_MAX_PKT_SIZE);
944e5ec1e72Spatrick 		req->host_buf_addr.high_addr = htole32(paddr >> 32);
945e5ec1e72Spatrick 		req->host_buf_addr.low_addr = htole32(paddr & 0xffffffff);
946e5ec1e72Spatrick 		bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit);
947e5ec1e72Spatrick 	}
948e5ec1e72Spatrick 	if_rxr_put(rxring, slots);
949e5ec1e72Spatrick 	splx(s);
950e5ec1e72Spatrick }
951e5ec1e72Spatrick 
952e5ec1e72Spatrick void
953e5ec1e72Spatrick bwfm_pci_fill_rx_buf_ring(struct bwfm_pci_softc *sc)
954e5ec1e72Spatrick {
955e5ec1e72Spatrick 	struct msgbuf_rx_bufpost *req;
956e5ec1e72Spatrick 	struct mbuf *m;
957e5ec1e72Spatrick 	uint32_t pktid;
958e5ec1e72Spatrick 	paddr_t paddr;
959e5ec1e72Spatrick 	int s, slots;
960e5ec1e72Spatrick 
961e5ec1e72Spatrick 	s = splnet();
962e5ec1e72Spatrick 	for (slots = if_rxr_get(&sc->sc_rxbuf_ring, sc->sc_max_rxbufpost);
963e5ec1e72Spatrick 	    slots > 0; slots--) {
96402ee7d07Spatrick 		if (bwfm_pci_pktid_avail(sc, &sc->sc_rx_pkts))
96502ee7d07Spatrick 			break;
966e5ec1e72Spatrick 		req = bwfm_pci_ring_write_reserve(sc, &sc->sc_rxpost_submit);
967e5ec1e72Spatrick 		if (req == NULL)
968e5ec1e72Spatrick 			break;
969e5ec1e72Spatrick 		m = MCLGETI(NULL, M_DONTWAIT, NULL, MSGBUF_MAX_PKT_SIZE);
970e5ec1e72Spatrick 		if (m == NULL) {
971e5ec1e72Spatrick 			bwfm_pci_ring_write_cancel(sc, &sc->sc_rxpost_submit, 1);
972e5ec1e72Spatrick 			break;
973e5ec1e72Spatrick 		}
974e5ec1e72Spatrick 		m->m_len = m->m_pkthdr.len = MSGBUF_MAX_PKT_SIZE;
975e5ec1e72Spatrick 		if (bwfm_pci_pktid_new(sc, &sc->sc_rx_pkts, m, &pktid, &paddr)) {
976e5ec1e72Spatrick 			bwfm_pci_ring_write_cancel(sc, &sc->sc_rxpost_submit, 1);
977e5ec1e72Spatrick 			m_freem(m);
978e5ec1e72Spatrick 			break;
979e5ec1e72Spatrick 		}
980e5ec1e72Spatrick 		memset(req, 0, sizeof(*req));
981e5ec1e72Spatrick 		req->msg.msgtype = MSGBUF_TYPE_RXBUF_POST;
982e5ec1e72Spatrick 		req->msg.request_id = htole32(pktid);
983e5ec1e72Spatrick 		req->data_buf_len = htole16(MSGBUF_MAX_PKT_SIZE);
984e5ec1e72Spatrick 		req->data_buf_addr.high_addr = htole32(paddr >> 32);
985e5ec1e72Spatrick 		req->data_buf_addr.low_addr = htole32(paddr & 0xffffffff);
986e5ec1e72Spatrick 		bwfm_pci_ring_write_commit(sc, &sc->sc_rxpost_submit);
987e5ec1e72Spatrick 	}
988e5ec1e72Spatrick 	if_rxr_put(&sc->sc_rxbuf_ring, slots);
989e5ec1e72Spatrick 	splx(s);
990e5ec1e72Spatrick }
991e5ec1e72Spatrick 
992e5ec1e72Spatrick int
993e5ec1e72Spatrick bwfm_pci_setup_ring(struct bwfm_pci_softc *sc, struct bwfm_pci_msgring *ring,
994e5ec1e72Spatrick     int nitem, size_t itemsz, uint32_t w_idx, uint32_t r_idx,
995e5ec1e72Spatrick     int idx, uint32_t idx_off, uint32_t *ring_mem)
996e5ec1e72Spatrick {
997e5ec1e72Spatrick 	ring->w_idx_addr = w_idx + idx * idx_off;
998e5ec1e72Spatrick 	ring->r_idx_addr = r_idx + idx * idx_off;
999e5ec1e72Spatrick 	ring->nitem = nitem;
1000e5ec1e72Spatrick 	ring->itemsz = itemsz;
1001e5ec1e72Spatrick 	bwfm_pci_ring_write_rptr(sc, ring);
1002e5ec1e72Spatrick 	bwfm_pci_ring_write_wptr(sc, ring);
1003e5ec1e72Spatrick 
1004e5ec1e72Spatrick 	ring->ring = bwfm_pci_dmamem_alloc(sc, nitem * itemsz, 8);
1005e5ec1e72Spatrick 	if (ring->ring == NULL)
1006e5ec1e72Spatrick 		return ENOMEM;
1007e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1008e5ec1e72Spatrick 	    *ring_mem + BWFM_RING_MEM_BASE_ADDR_LOW,
1009e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(ring->ring) & 0xffffffff);
1010e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1011e5ec1e72Spatrick 	    *ring_mem + BWFM_RING_MEM_BASE_ADDR_HIGH,
1012e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(ring->ring) >> 32);
1013e5ec1e72Spatrick 	bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1014e5ec1e72Spatrick 	    *ring_mem + BWFM_RING_MAX_ITEM, nitem);
1015e5ec1e72Spatrick 	bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1016e5ec1e72Spatrick 	    *ring_mem + BWFM_RING_LEN_ITEMS, itemsz);
1017e5ec1e72Spatrick 	*ring_mem = *ring_mem + BWFM_RING_MEM_SZ;
1018e5ec1e72Spatrick 	return 0;
1019e5ec1e72Spatrick }
1020e5ec1e72Spatrick 
1021518be5f3Spatrick int
1022518be5f3Spatrick bwfm_pci_setup_flowring(struct bwfm_pci_softc *sc, struct bwfm_pci_msgring *ring,
1023518be5f3Spatrick     int nitem, size_t itemsz)
1024518be5f3Spatrick {
1025518be5f3Spatrick 	ring->w_ptr = 0;
1026518be5f3Spatrick 	ring->r_ptr = 0;
1027518be5f3Spatrick 	ring->nitem = nitem;
1028518be5f3Spatrick 	ring->itemsz = itemsz;
1029518be5f3Spatrick 	bwfm_pci_ring_write_rptr(sc, ring);
1030518be5f3Spatrick 	bwfm_pci_ring_write_wptr(sc, ring);
1031518be5f3Spatrick 
1032518be5f3Spatrick 	ring->ring = bwfm_pci_dmamem_alloc(sc, nitem * itemsz, 8);
1033518be5f3Spatrick 	if (ring->ring == NULL)
1034518be5f3Spatrick 		return ENOMEM;
1035518be5f3Spatrick 	return 0;
1036518be5f3Spatrick }
1037518be5f3Spatrick 
1038e5ec1e72Spatrick /* Ring helpers */
1039e5ec1e72Spatrick void
1040e5ec1e72Spatrick bwfm_pci_ring_bell(struct bwfm_pci_softc *sc,
1041e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1042e5ec1e72Spatrick {
1043e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1044e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_H2D_MAILBOX, 1);
1045e5ec1e72Spatrick }
1046e5ec1e72Spatrick 
1047e5ec1e72Spatrick void
1048e5ec1e72Spatrick bwfm_pci_ring_update_rptr(struct bwfm_pci_softc *sc,
1049e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1050e5ec1e72Spatrick {
1051e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
1052e5ec1e72Spatrick 		ring->r_ptr = bus_space_read_2(sc->sc_tcm_iot,
1053e5ec1e72Spatrick 		    sc->sc_tcm_ioh, ring->r_idx_addr);
1054e5ec1e72Spatrick 	} else {
1055e5ec1e72Spatrick 		ring->r_ptr = *(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf)
1056e5ec1e72Spatrick 		    + ring->r_idx_addr);
1057e5ec1e72Spatrick 	}
1058e5ec1e72Spatrick }
1059e5ec1e72Spatrick 
1060e5ec1e72Spatrick void
1061e5ec1e72Spatrick bwfm_pci_ring_update_wptr(struct bwfm_pci_softc *sc,
1062e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1063e5ec1e72Spatrick {
1064e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
1065e5ec1e72Spatrick 		ring->w_ptr = bus_space_read_2(sc->sc_tcm_iot,
1066e5ec1e72Spatrick 		    sc->sc_tcm_ioh, ring->w_idx_addr);
1067e5ec1e72Spatrick 	} else {
1068e5ec1e72Spatrick 		ring->w_ptr = *(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf)
1069e5ec1e72Spatrick 		    + ring->w_idx_addr);
1070e5ec1e72Spatrick 	}
1071e5ec1e72Spatrick }
1072e5ec1e72Spatrick 
1073e5ec1e72Spatrick void
1074e5ec1e72Spatrick bwfm_pci_ring_write_rptr(struct bwfm_pci_softc *sc,
1075e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1076e5ec1e72Spatrick {
1077e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
1078e5ec1e72Spatrick 		bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1079e5ec1e72Spatrick 		    ring->r_idx_addr, ring->r_ptr);
1080e5ec1e72Spatrick 	} else {
1081e5ec1e72Spatrick 		*(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf)
1082e5ec1e72Spatrick 		    + ring->r_idx_addr) = ring->r_ptr;
1083e5ec1e72Spatrick 	}
1084e5ec1e72Spatrick }
1085e5ec1e72Spatrick 
1086e5ec1e72Spatrick void
1087e5ec1e72Spatrick bwfm_pci_ring_write_wptr(struct bwfm_pci_softc *sc,
1088e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1089e5ec1e72Spatrick {
1090e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
1091e5ec1e72Spatrick 		bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1092e5ec1e72Spatrick 		    ring->w_idx_addr, ring->w_ptr);
1093e5ec1e72Spatrick 	} else {
1094e5ec1e72Spatrick 		*(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf)
1095e5ec1e72Spatrick 		    + ring->w_idx_addr) = ring->w_ptr;
1096e5ec1e72Spatrick 	}
1097e5ec1e72Spatrick }
1098e5ec1e72Spatrick 
1099e5ec1e72Spatrick /*
1100e5ec1e72Spatrick  * Retrieve a free descriptor to put new stuff in, but don't commit
1101e5ec1e72Spatrick  * to it yet so we can rollback later if any error occurs.
1102e5ec1e72Spatrick  */
1103e5ec1e72Spatrick void *
1104e5ec1e72Spatrick bwfm_pci_ring_write_reserve(struct bwfm_pci_softc *sc,
1105e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1106e5ec1e72Spatrick {
1107e5ec1e72Spatrick 	int available;
1108e5ec1e72Spatrick 	char *ret;
1109e5ec1e72Spatrick 
1110e5ec1e72Spatrick 	bwfm_pci_ring_update_rptr(sc, ring);
1111e5ec1e72Spatrick 
1112e5ec1e72Spatrick 	if (ring->r_ptr > ring->w_ptr)
1113e5ec1e72Spatrick 		available = ring->r_ptr - ring->w_ptr;
1114e5ec1e72Spatrick 	else
1115e5ec1e72Spatrick 		available = ring->r_ptr + (ring->nitem - ring->w_ptr);
1116e5ec1e72Spatrick 
1117e5ec1e72Spatrick 	if (available < 1)
1118e5ec1e72Spatrick 		return NULL;
1119e5ec1e72Spatrick 
1120e5ec1e72Spatrick 	ret = BWFM_PCI_DMA_KVA(ring->ring) + (ring->w_ptr * ring->itemsz);
1121e5ec1e72Spatrick 	ring->w_ptr += 1;
1122e5ec1e72Spatrick 	if (ring->w_ptr == ring->nitem)
1123e5ec1e72Spatrick 		ring->w_ptr = 0;
1124e5ec1e72Spatrick 	return ret;
1125e5ec1e72Spatrick }
1126e5ec1e72Spatrick 
1127e5ec1e72Spatrick void *
1128e5ec1e72Spatrick bwfm_pci_ring_write_reserve_multi(struct bwfm_pci_softc *sc,
1129e5ec1e72Spatrick     struct bwfm_pci_msgring *ring, int count, int *avail)
1130e5ec1e72Spatrick {
1131e5ec1e72Spatrick 	int available;
1132e5ec1e72Spatrick 	char *ret;
1133e5ec1e72Spatrick 
1134e5ec1e72Spatrick 	bwfm_pci_ring_update_rptr(sc, ring);
1135e5ec1e72Spatrick 
1136e5ec1e72Spatrick 	if (ring->r_ptr > ring->w_ptr)
1137e5ec1e72Spatrick 		available = ring->r_ptr - ring->w_ptr;
1138e5ec1e72Spatrick 	else
1139e5ec1e72Spatrick 		available = ring->r_ptr + (ring->nitem - ring->w_ptr);
1140e5ec1e72Spatrick 
1141e5ec1e72Spatrick 	if (available < 1)
1142e5ec1e72Spatrick 		return NULL;
1143e5ec1e72Spatrick 
1144e5ec1e72Spatrick 	ret = BWFM_PCI_DMA_KVA(ring->ring) + (ring->w_ptr * ring->itemsz);
1145e5ec1e72Spatrick 	*avail = min(count, available - 1);
1146e5ec1e72Spatrick 	if (*avail + ring->w_ptr > ring->nitem)
1147e5ec1e72Spatrick 		*avail = ring->nitem - ring->w_ptr;
1148e5ec1e72Spatrick 	ring->w_ptr += *avail;
1149e5ec1e72Spatrick 	if (ring->w_ptr == ring->nitem)
1150e5ec1e72Spatrick 		ring->w_ptr = 0;
1151e5ec1e72Spatrick 	return ret;
1152e5ec1e72Spatrick }
1153e5ec1e72Spatrick 
1154e5ec1e72Spatrick /*
1155e5ec1e72Spatrick  * Read number of descriptors available (submitted by the firmware)
1156e5ec1e72Spatrick  * and retrieve pointer to first descriptor.
1157e5ec1e72Spatrick  */
1158e5ec1e72Spatrick void *
1159e5ec1e72Spatrick bwfm_pci_ring_read_avail(struct bwfm_pci_softc *sc,
1160e5ec1e72Spatrick     struct bwfm_pci_msgring *ring, int *avail)
1161e5ec1e72Spatrick {
1162e5ec1e72Spatrick 	bwfm_pci_ring_update_wptr(sc, ring);
1163e5ec1e72Spatrick 
1164e5ec1e72Spatrick 	if (ring->w_ptr >= ring->r_ptr)
1165e5ec1e72Spatrick 		*avail = ring->w_ptr - ring->r_ptr;
1166e5ec1e72Spatrick 	else
1167e5ec1e72Spatrick 		*avail = ring->nitem - ring->r_ptr;
1168e5ec1e72Spatrick 
1169e5ec1e72Spatrick 	if (*avail == 0)
1170e5ec1e72Spatrick 		return NULL;
1171e5ec1e72Spatrick 
1172e5ec1e72Spatrick 	return BWFM_PCI_DMA_KVA(ring->ring) + (ring->r_ptr * ring->itemsz);
1173e5ec1e72Spatrick }
1174e5ec1e72Spatrick 
1175e5ec1e72Spatrick /*
1176e5ec1e72Spatrick  * Let firmware know we read N descriptors.
1177e5ec1e72Spatrick  */
1178e5ec1e72Spatrick void
1179e5ec1e72Spatrick bwfm_pci_ring_read_commit(struct bwfm_pci_softc *sc,
1180e5ec1e72Spatrick     struct bwfm_pci_msgring *ring, int nitem)
1181e5ec1e72Spatrick {
1182e5ec1e72Spatrick 	ring->r_ptr += nitem;
1183e5ec1e72Spatrick 	if (ring->r_ptr == ring->nitem)
1184e5ec1e72Spatrick 		ring->r_ptr = 0;
1185e5ec1e72Spatrick 	bwfm_pci_ring_write_rptr(sc, ring);
1186e5ec1e72Spatrick }
1187e5ec1e72Spatrick 
1188e5ec1e72Spatrick /*
1189e5ec1e72Spatrick  * Let firmware know that we submitted some descriptors.
1190e5ec1e72Spatrick  */
1191e5ec1e72Spatrick void
1192e5ec1e72Spatrick bwfm_pci_ring_write_commit(struct bwfm_pci_softc *sc,
1193e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1194e5ec1e72Spatrick {
1195e5ec1e72Spatrick 	bwfm_pci_ring_write_wptr(sc, ring);
1196e5ec1e72Spatrick 	bwfm_pci_ring_bell(sc, ring);
1197e5ec1e72Spatrick }
1198e5ec1e72Spatrick 
1199e5ec1e72Spatrick /*
1200e5ec1e72Spatrick  * Rollback N descriptors in case we don't actually want
1201e5ec1e72Spatrick  * to commit to it.
1202e5ec1e72Spatrick  */
1203e5ec1e72Spatrick void
1204e5ec1e72Spatrick bwfm_pci_ring_write_cancel(struct bwfm_pci_softc *sc,
1205e5ec1e72Spatrick     struct bwfm_pci_msgring *ring, int nitem)
1206e5ec1e72Spatrick {
1207e5ec1e72Spatrick 	if (ring->w_ptr == 0)
1208e5ec1e72Spatrick 		ring->w_ptr = ring->nitem - nitem;
1209e5ec1e72Spatrick 	else
1210e5ec1e72Spatrick 		ring->w_ptr -= nitem;
1211e5ec1e72Spatrick }
1212e5ec1e72Spatrick 
1213e5ec1e72Spatrick /*
1214e5ec1e72Spatrick  * Foreach written descriptor on the ring, pass the descriptor to
1215e5ec1e72Spatrick  * a message handler and let the firmware know we handled it.
1216e5ec1e72Spatrick  */
1217e5ec1e72Spatrick void
1218e5ec1e72Spatrick bwfm_pci_ring_rx(struct bwfm_pci_softc *sc, struct bwfm_pci_msgring *ring)
1219e5ec1e72Spatrick {
1220e5ec1e72Spatrick 	void *buf;
1221e5ec1e72Spatrick 	int avail, processed;
1222e5ec1e72Spatrick 
1223e5ec1e72Spatrick again:
1224e5ec1e72Spatrick 	buf = bwfm_pci_ring_read_avail(sc, ring, &avail);
1225e5ec1e72Spatrick 	if (buf == NULL)
1226e5ec1e72Spatrick 		return;
1227e5ec1e72Spatrick 
1228e5ec1e72Spatrick 	processed = 0;
1229e5ec1e72Spatrick 	while (avail) {
1230e5ec1e72Spatrick 		bwfm_pci_msg_rx(sc, buf + sc->sc_rx_dataoffset);
1231e5ec1e72Spatrick 		buf += ring->itemsz;
1232e5ec1e72Spatrick 		processed++;
1233e5ec1e72Spatrick 		if (processed == 48) {
1234e5ec1e72Spatrick 			bwfm_pci_ring_read_commit(sc, ring, processed);
1235e5ec1e72Spatrick 			processed = 0;
1236e5ec1e72Spatrick 		}
1237e5ec1e72Spatrick 		avail--;
1238e5ec1e72Spatrick 	}
1239e5ec1e72Spatrick 	if (processed)
1240e5ec1e72Spatrick 		bwfm_pci_ring_read_commit(sc, ring, processed);
1241e5ec1e72Spatrick 	if (ring->r_ptr == 0)
1242e5ec1e72Spatrick 		goto again;
1243e5ec1e72Spatrick }
1244e5ec1e72Spatrick 
1245e5ec1e72Spatrick void
1246e5ec1e72Spatrick bwfm_pci_msg_rx(struct bwfm_pci_softc *sc, void *buf)
1247e5ec1e72Spatrick {
1248518be5f3Spatrick 	struct ifnet *ifp = &sc->sc_sc.sc_ic.ic_if;
1249e5ec1e72Spatrick 	struct msgbuf_ioctl_resp_hdr *resp;
1250518be5f3Spatrick 	struct msgbuf_tx_status *tx;
125118722113Spatrick 	struct msgbuf_rx_complete *rx;
1252e5ec1e72Spatrick 	struct msgbuf_rx_event *event;
1253e5ec1e72Spatrick 	struct msgbuf_common_hdr *msg;
1254518be5f3Spatrick 	struct msgbuf_flowring_create_resp *fcr;
1255a2c6ff8bSpatrick 	struct msgbuf_flowring_delete_resp *fdr;
1256518be5f3Spatrick 	struct bwfm_pci_msgring *ring;
1257e5ec1e72Spatrick 	struct mbuf *m;
1258518be5f3Spatrick 	int flowid;
1259e5ec1e72Spatrick 
1260e5ec1e72Spatrick 	msg = (struct msgbuf_common_hdr *)buf;
1261e5ec1e72Spatrick 	switch (msg->msgtype)
1262e5ec1e72Spatrick 	{
1263518be5f3Spatrick 	case MSGBUF_TYPE_FLOW_RING_CREATE_CMPLT:
1264518be5f3Spatrick 		fcr = (struct msgbuf_flowring_create_resp *)buf;
1265518be5f3Spatrick 		flowid = letoh16(fcr->compl_hdr.flow_ring_id);
1266518be5f3Spatrick 		if (flowid < 2)
1267518be5f3Spatrick 			break;
1268518be5f3Spatrick 		flowid -= 2;
1269518be5f3Spatrick 		if (flowid >= sc->sc_max_flowrings)
1270518be5f3Spatrick 			break;
1271518be5f3Spatrick 		ring = &sc->sc_flowrings[flowid];
1272518be5f3Spatrick 		if (ring->status != RING_OPENING)
1273518be5f3Spatrick 			break;
1274518be5f3Spatrick 		if (fcr->compl_hdr.status) {
1275518be5f3Spatrick 			printf("%s: failed to open flowring %d\n",
1276518be5f3Spatrick 			    DEVNAME(sc), flowid);
1277518be5f3Spatrick 			ring->status = RING_CLOSED;
127802ee7d07Spatrick 			if (ring->m) {
127902ee7d07Spatrick 				m_freem(ring->m);
128002ee7d07Spatrick 				ring->m = NULL;
128102ee7d07Spatrick 			}
1282518be5f3Spatrick 			ifq_restart(&ifp->if_snd);
1283518be5f3Spatrick 			break;
1284518be5f3Spatrick 		}
1285518be5f3Spatrick 		ring->status = RING_OPEN;
128602ee7d07Spatrick 		if (ring->m != NULL) {
128702ee7d07Spatrick 			m = ring->m;
128802ee7d07Spatrick 			ring->m = NULL;
128902ee7d07Spatrick 			if (bwfm_pci_txdata(&sc->sc_sc, m))
129002ee7d07Spatrick 				m_freem(ring->m);
129102ee7d07Spatrick 		}
1292518be5f3Spatrick 		ifq_restart(&ifp->if_snd);
1293518be5f3Spatrick 		break;
1294a2c6ff8bSpatrick 	case MSGBUF_TYPE_FLOW_RING_DELETE_CMPLT:
1295a2c6ff8bSpatrick 		fdr = (struct msgbuf_flowring_delete_resp *)buf;
1296a2c6ff8bSpatrick 		flowid = letoh16(fdr->compl_hdr.flow_ring_id);
1297a2c6ff8bSpatrick 		if (flowid < 2)
1298a2c6ff8bSpatrick 			break;
1299a2c6ff8bSpatrick 		flowid -= 2;
1300a2c6ff8bSpatrick 		if (flowid >= sc->sc_max_flowrings)
1301a2c6ff8bSpatrick 			break;
1302a2c6ff8bSpatrick 		ring = &sc->sc_flowrings[flowid];
1303a2c6ff8bSpatrick 		if (ring->status != RING_CLOSING)
1304a2c6ff8bSpatrick 			break;
1305a2c6ff8bSpatrick 		if (fdr->compl_hdr.status) {
1306a2c6ff8bSpatrick 			printf("%s: failed to delete flowring %d\n",
1307a2c6ff8bSpatrick 			    DEVNAME(sc), flowid);
1308a2c6ff8bSpatrick 			break;
1309a2c6ff8bSpatrick 		}
1310a2c6ff8bSpatrick 		bwfm_pci_dmamem_free(sc, ring->ring);
1311a2c6ff8bSpatrick 		ring->status = RING_CLOSED;
1312a2c6ff8bSpatrick 		break;
1313e5ec1e72Spatrick 	case MSGBUF_TYPE_IOCTLPTR_REQ_ACK:
1314e5ec1e72Spatrick 		break;
1315e5ec1e72Spatrick 	case MSGBUF_TYPE_IOCTL_CMPLT:
1316e5ec1e72Spatrick 		resp = (struct msgbuf_ioctl_resp_hdr *)buf;
1317e5ec1e72Spatrick 		sc->sc_ioctl_resp_pktid = letoh32(resp->msg.request_id);
1318e5ec1e72Spatrick 		sc->sc_ioctl_resp_ret_len = letoh16(resp->resp_len);
1319e5ec1e72Spatrick 		sc->sc_ioctl_resp_status = letoh16(resp->compl_hdr.status);
1320e5ec1e72Spatrick 		if_rxr_put(&sc->sc_ioctl_ring, 1);
1321e5ec1e72Spatrick 		bwfm_pci_fill_rx_rings(sc);
1322e5ec1e72Spatrick 		wakeup(&sc->sc_ioctl_buf);
1323e5ec1e72Spatrick 		break;
1324e5ec1e72Spatrick 	case MSGBUF_TYPE_WL_EVENT:
1325e5ec1e72Spatrick 		event = (struct msgbuf_rx_event *)buf;
1326e5ec1e72Spatrick 		m = bwfm_pci_pktid_free(sc, &sc->sc_rx_pkts,
1327e5ec1e72Spatrick 		    letoh32(event->msg.request_id));
1328e5ec1e72Spatrick 		if (m == NULL)
1329e5ec1e72Spatrick 			break;
1330e5ec1e72Spatrick 		m_adj(m, sc->sc_rx_dataoffset);
1331f37fc236Spatrick 		m->m_len = m->m_pkthdr.len = letoh16(event->event_data_len);
1332f37fc236Spatrick 		bwfm_rx(&sc->sc_sc, m);
1333e5ec1e72Spatrick 		if_rxr_put(&sc->sc_event_ring, 1);
1334e5ec1e72Spatrick 		bwfm_pci_fill_rx_rings(sc);
1335e5ec1e72Spatrick 		break;
1336518be5f3Spatrick 	case MSGBUF_TYPE_TX_STATUS:
1337518be5f3Spatrick 		tx = (struct msgbuf_tx_status *)buf;
1338518be5f3Spatrick 		m = bwfm_pci_pktid_free(sc, &sc->sc_tx_pkts,
1339518be5f3Spatrick 		    letoh32(tx->msg.request_id));
1340518be5f3Spatrick 		if (m == NULL)
1341518be5f3Spatrick 			break;
1342518be5f3Spatrick 		m_freem(m);
1343c6f1636dSpatrick 		if (sc->sc_tx_pkts_full) {
1344c6f1636dSpatrick 			sc->sc_tx_pkts_full = 0;
1345c6f1636dSpatrick 			ifq_restart(&ifp->if_snd);
1346c6f1636dSpatrick 		}
1347518be5f3Spatrick 		break;
134818722113Spatrick 	case MSGBUF_TYPE_RX_CMPLT:
134918722113Spatrick 		rx = (struct msgbuf_rx_complete *)buf;
135018722113Spatrick 		m = bwfm_pci_pktid_free(sc, &sc->sc_rx_pkts,
135118722113Spatrick 		    letoh32(rx->msg.request_id));
135218722113Spatrick 		if (m == NULL)
135318722113Spatrick 			break;
135418722113Spatrick 		if (letoh16(rx->data_offset))
135518722113Spatrick 			m_adj(m, letoh16(rx->data_offset));
135618722113Spatrick 		else if (sc->sc_rx_dataoffset)
135718722113Spatrick 			m_adj(m, sc->sc_rx_dataoffset);
1358f37fc236Spatrick 		m->m_len = m->m_pkthdr.len = letoh16(rx->data_len);
1359f37fc236Spatrick 		bwfm_rx(&sc->sc_sc, m);
136018722113Spatrick 		if_rxr_put(&sc->sc_rxbuf_ring, 1);
136118722113Spatrick 		bwfm_pci_fill_rx_rings(sc);
136218722113Spatrick 		break;
1363e5ec1e72Spatrick 	default:
1364e5ec1e72Spatrick 		printf("%s: msgtype 0x%08x\n", __func__, msg->msgtype);
1365e5ec1e72Spatrick 		break;
1366e5ec1e72Spatrick 	}
1367e5ec1e72Spatrick }
1368e5ec1e72Spatrick 
1369e5ec1e72Spatrick /* Bus core helpers */
1370e5ec1e72Spatrick void
1371e5ec1e72Spatrick bwfm_pci_select_core(struct bwfm_pci_softc *sc, int id)
1372e5ec1e72Spatrick {
1373e5ec1e72Spatrick 	struct bwfm_softc *bwfm = (void *)sc;
1374e5ec1e72Spatrick 	struct bwfm_core *core;
1375e5ec1e72Spatrick 
1376e5ec1e72Spatrick 	core = bwfm_chip_get_core(bwfm, id);
1377e5ec1e72Spatrick 	if (core == NULL) {
1378e5ec1e72Spatrick 		printf("%s: could not find core to select", DEVNAME(sc));
1379e5ec1e72Spatrick 		return;
1380e5ec1e72Spatrick 	}
1381e5ec1e72Spatrick 
1382e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag,
1383e5ec1e72Spatrick 	    BWFM_PCI_BAR0_WINDOW, core->co_base);
1384e5ec1e72Spatrick 	if (pci_conf_read(sc->sc_pc, sc->sc_tag,
1385e5ec1e72Spatrick 	    BWFM_PCI_BAR0_WINDOW) != core->co_base)
1386e5ec1e72Spatrick 		pci_conf_write(sc->sc_pc, sc->sc_tag,
1387e5ec1e72Spatrick 		    BWFM_PCI_BAR0_WINDOW, core->co_base);
1388e5ec1e72Spatrick }
1389e5ec1e72Spatrick 
1390e5ec1e72Spatrick uint32_t
1391e5ec1e72Spatrick bwfm_pci_buscore_read(struct bwfm_softc *bwfm, uint32_t reg)
1392e5ec1e72Spatrick {
1393e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1394e5ec1e72Spatrick 	uint32_t page, offset;
1395e5ec1e72Spatrick 
1396e5ec1e72Spatrick 	page = reg & ~(BWFM_PCI_BAR0_REG_SIZE - 1);
1397e5ec1e72Spatrick 	offset = reg & (BWFM_PCI_BAR0_REG_SIZE - 1);
1398e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_BAR0_WINDOW, page);
1399e5ec1e72Spatrick 	return bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh, offset);
1400e5ec1e72Spatrick }
1401e5ec1e72Spatrick 
1402e5ec1e72Spatrick void
1403e5ec1e72Spatrick bwfm_pci_buscore_write(struct bwfm_softc *bwfm, uint32_t reg, uint32_t val)
1404e5ec1e72Spatrick {
1405e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1406e5ec1e72Spatrick 	uint32_t page, offset;
1407e5ec1e72Spatrick 
1408e5ec1e72Spatrick 	page = reg & ~(BWFM_PCI_BAR0_REG_SIZE - 1);
1409e5ec1e72Spatrick 	offset = reg & (BWFM_PCI_BAR0_REG_SIZE - 1);
1410e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_BAR0_WINDOW, page);
1411e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, offset, val);
1412e5ec1e72Spatrick }
1413e5ec1e72Spatrick 
1414e5ec1e72Spatrick int
1415e5ec1e72Spatrick bwfm_pci_buscore_prepare(struct bwfm_softc *bwfm)
1416e5ec1e72Spatrick {
1417e5ec1e72Spatrick 	return 0;
1418e5ec1e72Spatrick }
1419e5ec1e72Spatrick 
1420e5ec1e72Spatrick int
1421e5ec1e72Spatrick bwfm_pci_buscore_reset(struct bwfm_softc *bwfm)
1422e5ec1e72Spatrick {
1423e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1424e5ec1e72Spatrick 	struct bwfm_core *core;
1425e5ec1e72Spatrick 	uint32_t reg;
1426e5ec1e72Spatrick 	int i;
1427e5ec1e72Spatrick 
1428e5ec1e72Spatrick 	bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2);
1429e5ec1e72Spatrick 	reg = pci_conf_read(sc->sc_pc, sc->sc_tag,
1430e5ec1e72Spatrick 	    BWFM_PCI_CFGREG_LINK_STATUS_CTRL);
1431e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_CFGREG_LINK_STATUS_CTRL,
1432e5ec1e72Spatrick 	    reg & ~BWFM_PCI_CFGREG_LINK_STATUS_CTRL_ASPM_ENAB);
1433e5ec1e72Spatrick 
1434e5ec1e72Spatrick 	bwfm_pci_select_core(sc, BWFM_AGENT_CORE_CHIPCOMMON);
1435e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1436e5ec1e72Spatrick 	    BWFM_CHIP_REG_WATCHDOG, 4);
1437e5ec1e72Spatrick 	delay(100 * 1000);
1438e5ec1e72Spatrick 
1439e5ec1e72Spatrick 	bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2);
1440e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag,
1441e5ec1e72Spatrick 	    BWFM_PCI_CFGREG_LINK_STATUS_CTRL, reg);
1442e5ec1e72Spatrick 
1443e5ec1e72Spatrick 	core = bwfm_chip_get_core(bwfm, BWFM_AGENT_CORE_PCIE2);
1444e5ec1e72Spatrick 	if (core->co_rev <= 13) {
1445e5ec1e72Spatrick 		uint16_t cfg_offset[] = {
1446e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_STATUS_CMD,
1447e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_PM_CSR,
1448e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_MSI_CAP,
1449e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_MSI_ADDR_L,
1450e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_MSI_ADDR_H,
1451e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_MSI_DATA,
1452e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_LINK_STATUS_CTRL2,
1453e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_RBAR_CTRL,
1454e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_PML1_SUB_CTRL1,
1455e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_REG_BAR2_CONFIG,
1456e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_REG_BAR3_CONFIG,
1457e5ec1e72Spatrick 		};
1458e5ec1e72Spatrick 
1459e5ec1e72Spatrick 		for (i = 0; i < nitems(cfg_offset); i++) {
1460e5ec1e72Spatrick 			bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1461e5ec1e72Spatrick 			    BWFM_PCI_PCIE2REG_CONFIGADDR, cfg_offset[i]);
1462e5ec1e72Spatrick 			reg = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1463e5ec1e72Spatrick 			    BWFM_PCI_PCIE2REG_CONFIGDATA);
1464e5ec1e72Spatrick 			DPRINTFN(3, ("%s: config offset 0x%04x, value 0x%04x\n",
1465e5ec1e72Spatrick 			    DEVNAME(sc), cfg_offset[i], reg));
1466e5ec1e72Spatrick 			bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1467e5ec1e72Spatrick 			    BWFM_PCI_PCIE2REG_CONFIGDATA, reg);
1468e5ec1e72Spatrick 		}
1469e5ec1e72Spatrick 	}
1470e5ec1e72Spatrick 
1471e5ec1e72Spatrick 	reg = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1472e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXINT);
1473e5ec1e72Spatrick 	if (reg != 0xffffffff)
1474e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1475e5ec1e72Spatrick 		    BWFM_PCI_PCIE2REG_MAILBOXINT, reg);
1476e5ec1e72Spatrick 
1477e5ec1e72Spatrick 	return 0;
1478e5ec1e72Spatrick }
1479e5ec1e72Spatrick 
1480e5ec1e72Spatrick void
1481e5ec1e72Spatrick bwfm_pci_buscore_activate(struct bwfm_softc *bwfm, uint32_t rstvec)
1482e5ec1e72Spatrick {
1483e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1484e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 0, rstvec);
1485e5ec1e72Spatrick }
1486e5ec1e72Spatrick 
1487f67437f3Spatrick static int bwfm_pci_prio2fifo[8] = {
1488f67437f3Spatrick 	1, /* best effort */
1489f67437f3Spatrick 	0, /* IPTOS_PREC_IMMEDIATE */
1490f67437f3Spatrick 	0, /* IPTOS_PREC_PRIORITY */
1491f67437f3Spatrick 	1, /* IPTOS_PREC_FLASH */
1492f67437f3Spatrick 	2, /* IPTOS_PREC_FLASHOVERRIDE */
1493f67437f3Spatrick 	2, /* IPTOS_PREC_CRITIC_ECP */
1494f67437f3Spatrick 	3, /* IPTOS_PREC_INTERNETCONTROL */
1495f67437f3Spatrick 	3, /* IPTOS_PREC_NETCONTROL */
1496f67437f3Spatrick };
1497f67437f3Spatrick 
1498f67437f3Spatrick int
1499f67437f3Spatrick bwfm_pci_flowring_lookup(struct bwfm_pci_softc *sc, struct mbuf *m)
1500518be5f3Spatrick {
1501f67437f3Spatrick 	struct ieee80211com *ic = &sc->sc_sc.sc_ic;
1502f67437f3Spatrick 	uint8_t *da = mtod(m, uint8_t *);
1503f67437f3Spatrick 	int flowid, prio, fifo;
1504f67437f3Spatrick 	int i, found;
1505f67437f3Spatrick 
1506f67437f3Spatrick 	prio = ieee80211_classify(ic, m);
1507f67437f3Spatrick 	fifo = bwfm_pci_prio2fifo[prio];
1508f67437f3Spatrick 
1509f67437f3Spatrick 	switch (ic->ic_opmode)
1510f67437f3Spatrick 	{
1511f67437f3Spatrick 	case IEEE80211_M_STA:
1512f67437f3Spatrick 		flowid = fifo;
1513f67437f3Spatrick 		break;
1514f67437f3Spatrick #ifndef IEEE80211_STA_ONLY
1515f67437f3Spatrick 	case IEEE80211_M_HOSTAP:
15162b7bea7eSpatrick 		if (ETHER_IS_MULTICAST(da))
15172b7bea7eSpatrick 			da = etherbroadcastaddr;
1518f67437f3Spatrick 		flowid = da[5] * 2 + fifo;
1519f67437f3Spatrick 		break;
1520f67437f3Spatrick #endif
1521f67437f3Spatrick 	default:
1522f67437f3Spatrick 		printf("%s: state not supported\n", DEVNAME(sc));
1523f67437f3Spatrick 		return ENOBUFS;
1524f67437f3Spatrick 	}
1525f67437f3Spatrick 
1526f67437f3Spatrick 	found = 0;
1527f67437f3Spatrick 	flowid = flowid % sc->sc_max_flowrings;
1528f67437f3Spatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
1529f67437f3Spatrick 		if (ic->ic_opmode == IEEE80211_M_STA &&
1530f67437f3Spatrick 		    sc->sc_flowrings[flowid].status >= RING_OPEN &&
1531f67437f3Spatrick 		    sc->sc_flowrings[flowid].fifo == fifo) {
1532f67437f3Spatrick 			found = 1;
1533f67437f3Spatrick 			break;
1534f67437f3Spatrick 		}
1535f67437f3Spatrick #ifndef IEEE80211_STA_ONLY
1536f67437f3Spatrick 		if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
1537f67437f3Spatrick 		    sc->sc_flowrings[flowid].status >= RING_OPEN &&
1538f67437f3Spatrick 		    sc->sc_flowrings[flowid].fifo == fifo &&
1539a2c6ff8bSpatrick 		    !memcmp(sc->sc_flowrings[flowid].mac, da, ETHER_ADDR_LEN)) {
1540f67437f3Spatrick 			found = 1;
1541f67437f3Spatrick 			break;
1542f67437f3Spatrick 		}
1543f67437f3Spatrick #endif
1544f67437f3Spatrick 		flowid = (flowid + 1) % sc->sc_max_flowrings;
1545f67437f3Spatrick 	}
1546f67437f3Spatrick 
1547f67437f3Spatrick 	if (found)
1548f67437f3Spatrick 		return flowid;
1549f67437f3Spatrick 
1550f67437f3Spatrick 	return -1;
1551f67437f3Spatrick }
1552f67437f3Spatrick 
1553f67437f3Spatrick void
1554f67437f3Spatrick bwfm_pci_flowring_create(struct bwfm_pci_softc *sc, struct mbuf *m)
1555f67437f3Spatrick {
1556f67437f3Spatrick 	struct ieee80211com *ic = &sc->sc_sc.sc_ic;
1557518be5f3Spatrick 	struct bwfm_cmd_flowring_create cmd;
1558f67437f3Spatrick 	uint8_t *da = mtod(m, uint8_t *);
155902ee7d07Spatrick 	struct bwfm_pci_msgring *ring;
1560f67437f3Spatrick 	int flowid, prio, fifo;
1561f67437f3Spatrick 	int i, found;
1562f67437f3Spatrick 
1563f67437f3Spatrick 	prio = ieee80211_classify(ic, m);
1564f67437f3Spatrick 	fifo = bwfm_pci_prio2fifo[prio];
1565f67437f3Spatrick 
1566f67437f3Spatrick 	switch (ic->ic_opmode)
1567f67437f3Spatrick 	{
1568f67437f3Spatrick 	case IEEE80211_M_STA:
1569f67437f3Spatrick 		flowid = fifo;
1570f67437f3Spatrick 		break;
1571f67437f3Spatrick #ifndef IEEE80211_STA_ONLY
1572f67437f3Spatrick 	case IEEE80211_M_HOSTAP:
15732b7bea7eSpatrick 		if (ETHER_IS_MULTICAST(da))
15742b7bea7eSpatrick 			da = etherbroadcastaddr;
1575f67437f3Spatrick 		flowid = da[5] * 2 + fifo;
1576f67437f3Spatrick 		break;
1577f67437f3Spatrick #endif
1578f67437f3Spatrick 	default:
1579f67437f3Spatrick 		printf("%s: state not supported\n", DEVNAME(sc));
1580f67437f3Spatrick 		return;
1581f67437f3Spatrick 	}
1582f67437f3Spatrick 
1583f67437f3Spatrick 	found = 0;
1584f67437f3Spatrick 	flowid = flowid % sc->sc_max_flowrings;
1585f67437f3Spatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
158602ee7d07Spatrick 		ring = &sc->sc_flowrings[flowid];
158702ee7d07Spatrick 		if (ring->status == RING_CLOSED) {
158802ee7d07Spatrick 			ring->status = RING_OPENING;
1589f67437f3Spatrick 			found = 1;
1590f67437f3Spatrick 			break;
1591f67437f3Spatrick 		}
1592f67437f3Spatrick 		flowid = (flowid + 1) % sc->sc_max_flowrings;
1593f67437f3Spatrick 	}
1594f67437f3Spatrick 
159502ee7d07Spatrick 	/*
159602ee7d07Spatrick 	 * We cannot recover from that so far.  Only a stop/init
159702ee7d07Spatrick 	 * cycle can revive this if it ever happens at all.
159802ee7d07Spatrick 	 */
1599f67437f3Spatrick 	if (!found) {
1600f67437f3Spatrick 		printf("%s: no flowring available\n", DEVNAME(sc));
1601f67437f3Spatrick 		return;
1602f67437f3Spatrick 	}
1603f67437f3Spatrick 
160402ee7d07Spatrick 	cmd.m = m;
1605f67437f3Spatrick 	cmd.prio = prio;
1606518be5f3Spatrick 	cmd.flowid = flowid;
1607518be5f3Spatrick 	bwfm_do_async(&sc->sc_sc, bwfm_pci_flowring_create_cb, &cmd, sizeof(cmd));
1608518be5f3Spatrick }
1609518be5f3Spatrick 
1610518be5f3Spatrick void
1611518be5f3Spatrick bwfm_pci_flowring_create_cb(struct bwfm_softc *bwfm, void *arg)
1612518be5f3Spatrick {
1613518be5f3Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
16142b7bea7eSpatrick 	struct ieee80211com *ic = &sc->sc_sc.sc_ic;
1615518be5f3Spatrick 	struct bwfm_cmd_flowring_create *cmd = arg;
1616518be5f3Spatrick 	struct msgbuf_tx_flowring_create_req *req;
1617518be5f3Spatrick 	struct bwfm_pci_msgring *ring;
161802ee7d07Spatrick 	uint8_t *da, *sa;
1619518be5f3Spatrick 
162002ee7d07Spatrick 	da = mtod(cmd->m, char *) + 0 * ETHER_ADDR_LEN;
162102ee7d07Spatrick 	sa = mtod(cmd->m, char *) + 1 * ETHER_ADDR_LEN;
1622518be5f3Spatrick 
162302ee7d07Spatrick 	ring = &sc->sc_flowrings[cmd->flowid];
162402ee7d07Spatrick 	if (ring->status != RING_OPENING) {
162502ee7d07Spatrick 		printf("%s: flowring not opening\n", DEVNAME(sc));
1626518be5f3Spatrick 		return;
1627f67437f3Spatrick 	}
1628f67437f3Spatrick 
1629f67437f3Spatrick 	if (bwfm_pci_setup_flowring(sc, ring, 512, 48)) {
1630f67437f3Spatrick 		printf("%s: cannot setup flowring\n", DEVNAME(sc));
1631f67437f3Spatrick 		return;
1632f67437f3Spatrick 	}
1633518be5f3Spatrick 
1634518be5f3Spatrick 	req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit);
1635f67437f3Spatrick 	if (req == NULL) {
1636f67437f3Spatrick 		printf("%s: cannot reserve for flowring\n", DEVNAME(sc));
1637518be5f3Spatrick 		return;
1638f67437f3Spatrick 	}
1639518be5f3Spatrick 
1640518be5f3Spatrick 	ring->status = RING_OPENING;
164102ee7d07Spatrick 	ring->fifo = bwfm_pci_prio2fifo[cmd->prio];
164202ee7d07Spatrick 	ring->m = cmd->m;
164302ee7d07Spatrick 	memcpy(ring->mac, da, ETHER_ADDR_LEN);
16442b7bea7eSpatrick #ifndef IEEE80211_STA_ONLY
164502ee7d07Spatrick 	if (ic->ic_opmode == IEEE80211_M_HOSTAP && ETHER_IS_MULTICAST(da))
16462b7bea7eSpatrick 		memcpy(ring->mac, etherbroadcastaddr, ETHER_ADDR_LEN);
16472b7bea7eSpatrick #endif
1648f67437f3Spatrick 
1649518be5f3Spatrick 	req->msg.msgtype = MSGBUF_TYPE_FLOW_RING_CREATE;
1650518be5f3Spatrick 	req->msg.ifidx = 0;
1651518be5f3Spatrick 	req->msg.request_id = 0;
165202ee7d07Spatrick 	req->tid = bwfm_pci_prio2fifo[cmd->prio];
165302ee7d07Spatrick 	req->flow_ring_id = letoh16(cmd->flowid + 2);
165402ee7d07Spatrick 	memcpy(req->da, da, ETHER_ADDR_LEN);
165502ee7d07Spatrick 	memcpy(req->sa, sa, ETHER_ADDR_LEN);
1656518be5f3Spatrick 	req->flow_ring_addr.high_addr =
1657518be5f3Spatrick 	    letoh32(BWFM_PCI_DMA_DVA(ring->ring) >> 32);
1658518be5f3Spatrick 	req->flow_ring_addr.low_addr =
1659518be5f3Spatrick 	    letoh32(BWFM_PCI_DMA_DVA(ring->ring) & 0xffffffff);
1660518be5f3Spatrick 	req->max_items = letoh16(512);
1661518be5f3Spatrick 	req->len_item = letoh16(48);
1662518be5f3Spatrick 
1663518be5f3Spatrick 	bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit);
1664518be5f3Spatrick }
1665518be5f3Spatrick 
1666a2c6ff8bSpatrick void
1667a2c6ff8bSpatrick bwfm_pci_flowring_delete(struct bwfm_pci_softc *sc, int flowid)
1668a2c6ff8bSpatrick {
1669a2c6ff8bSpatrick 	struct msgbuf_tx_flowring_delete_req *req;
1670a2c6ff8bSpatrick 	struct bwfm_pci_msgring *ring;
1671a2c6ff8bSpatrick 
1672a2c6ff8bSpatrick 	ring = &sc->sc_flowrings[flowid];
1673a2c6ff8bSpatrick 	if (ring->status != RING_OPEN) {
1674a2c6ff8bSpatrick 		printf("%s: flowring not open\n", DEVNAME(sc));
1675a2c6ff8bSpatrick 		return;
1676a2c6ff8bSpatrick 	}
1677a2c6ff8bSpatrick 
1678a2c6ff8bSpatrick 	req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit);
1679a2c6ff8bSpatrick 	if (req == NULL) {
1680a2c6ff8bSpatrick 		printf("%s: cannot reserve for flowring\n", DEVNAME(sc));
1681a2c6ff8bSpatrick 		return;
1682a2c6ff8bSpatrick 	}
1683a2c6ff8bSpatrick 
1684a2c6ff8bSpatrick 	ring->status = RING_CLOSING;
1685a2c6ff8bSpatrick 
1686a2c6ff8bSpatrick 	req->msg.msgtype = MSGBUF_TYPE_FLOW_RING_DELETE;
1687a2c6ff8bSpatrick 	req->msg.ifidx = 0;
1688a2c6ff8bSpatrick 	req->msg.request_id = 0;
1689a2c6ff8bSpatrick 	req->flow_ring_id = letoh16(flowid + 2);
1690a2c6ff8bSpatrick 	req->reason = 0;
1691a2c6ff8bSpatrick 
1692a2c6ff8bSpatrick 	bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit);
1693a2c6ff8bSpatrick }
1694a2c6ff8bSpatrick 
1695a2c6ff8bSpatrick void
1696a2c6ff8bSpatrick bwfm_pci_stop(struct bwfm_softc *bwfm)
1697a2c6ff8bSpatrick {
1698a2c6ff8bSpatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1699a2c6ff8bSpatrick 	struct bwfm_pci_msgring *ring;
1700a2c6ff8bSpatrick 	int i;
1701a2c6ff8bSpatrick 
1702a2c6ff8bSpatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
1703a2c6ff8bSpatrick 		ring = &sc->sc_flowrings[i];
1704a2c6ff8bSpatrick 		if (ring->status == RING_OPEN)
1705a2c6ff8bSpatrick 			bwfm_pci_flowring_delete(sc, i);
1706a2c6ff8bSpatrick 	}
1707a2c6ff8bSpatrick }
1708a2c6ff8bSpatrick 
1709e5ec1e72Spatrick int
171002ee7d07Spatrick bwfm_pci_txcheck(struct bwfm_softc *bwfm)
171102ee7d07Spatrick {
171202ee7d07Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
171302ee7d07Spatrick 	struct bwfm_pci_msgring *ring;
171402ee7d07Spatrick 	int i;
171502ee7d07Spatrick 
171602ee7d07Spatrick 	/* If we are transitioning, we cannot send. */
171702ee7d07Spatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
171802ee7d07Spatrick 		ring = &sc->sc_flowrings[i];
171902ee7d07Spatrick 		if (ring->status == RING_OPENING)
172002ee7d07Spatrick 			return ENOBUFS;
172102ee7d07Spatrick 	}
172202ee7d07Spatrick 
172302ee7d07Spatrick 	if (bwfm_pci_pktid_avail(sc, &sc->sc_tx_pkts)) {
172402ee7d07Spatrick 		sc->sc_tx_pkts_full = 1;
172502ee7d07Spatrick 		return ENOBUFS;
172602ee7d07Spatrick 	}
172702ee7d07Spatrick 
172802ee7d07Spatrick 	return 0;
172902ee7d07Spatrick }
173002ee7d07Spatrick 
173102ee7d07Spatrick int
1732e5ec1e72Spatrick bwfm_pci_txdata(struct bwfm_softc *bwfm, struct mbuf *m)
1733e5ec1e72Spatrick {
1734e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1735518be5f3Spatrick 	struct bwfm_pci_msgring *ring;
1736518be5f3Spatrick 	struct msgbuf_tx_msghdr *tx;
1737518be5f3Spatrick 	uint32_t pktid;
1738518be5f3Spatrick 	paddr_t paddr;
1739518be5f3Spatrick 	int flowid, ret;
1740518be5f3Spatrick 
1741f67437f3Spatrick 	flowid = bwfm_pci_flowring_lookup(sc, m);
1742f67437f3Spatrick 	if (flowid < 0) {
174302ee7d07Spatrick 		/*
174402ee7d07Spatrick 		 * We cannot send the packet right now as there is
174502ee7d07Spatrick 		 * no flowring yet.  The flowring will be created
174602ee7d07Spatrick 		 * asynchronously.  While the ring is transitioning
174702ee7d07Spatrick 		 * the TX check will tell the upper layers that we
174802ee7d07Spatrick 		 * cannot send packets right now.  When the flowring
174902ee7d07Spatrick 		 * is created the queue will be restarted and this
175002ee7d07Spatrick 		 * mbuf will be transmitted.
175102ee7d07Spatrick 		 */
1752f67437f3Spatrick 		bwfm_pci_flowring_create(sc, m);
175302ee7d07Spatrick 		return 0;
1754f67437f3Spatrick 	}
1755518be5f3Spatrick 
1756518be5f3Spatrick 	ring = &sc->sc_flowrings[flowid];
1757518be5f3Spatrick 	if (ring->status == RING_OPENING ||
1758f67437f3Spatrick 	    ring->status == RING_CLOSING) {
1759f67437f3Spatrick 		printf("%s: tried to use a flow that was "
1760f67437f3Spatrick 		    "transitioning in status %d\n",
1761f67437f3Spatrick 		    DEVNAME(sc), ring->status);
1762518be5f3Spatrick 		return ENOBUFS;
1763518be5f3Spatrick 	}
1764518be5f3Spatrick 
1765518be5f3Spatrick 	tx = bwfm_pci_ring_write_reserve(sc, ring);
1766518be5f3Spatrick 	if (tx == NULL)
1767518be5f3Spatrick 		return ENOBUFS;
1768518be5f3Spatrick 
1769518be5f3Spatrick 	memset(tx, 0, sizeof(*tx));
1770518be5f3Spatrick 	tx->msg.msgtype = MSGBUF_TYPE_TX_POST;
1771518be5f3Spatrick 	tx->msg.ifidx = 0;
1772518be5f3Spatrick 	tx->flags = BWFM_MSGBUF_PKT_FLAGS_FRAME_802_3;
1773518be5f3Spatrick 	tx->flags |= ieee80211_classify(&sc->sc_sc.sc_ic, m) <<
1774518be5f3Spatrick 	    BWFM_MSGBUF_PKT_FLAGS_PRIO_SHIFT;
1775518be5f3Spatrick 	tx->seg_cnt = 1;
1776518be5f3Spatrick 	memcpy(tx->txhdr, mtod(m, char *), ETHER_HDR_LEN);
1777518be5f3Spatrick 
1778518be5f3Spatrick 	ret = bwfm_pci_pktid_new(sc, &sc->sc_tx_pkts, m, &pktid, &paddr);
1779518be5f3Spatrick 	if (ret) {
178002ee7d07Spatrick 		if (ret == ENOBUFS) {
178102ee7d07Spatrick 			printf("%s: no pktid available for TX\n",
178202ee7d07Spatrick 			    DEVNAME(sc));
1783c6f1636dSpatrick 			sc->sc_tx_pkts_full = 1;
178402ee7d07Spatrick 		}
1785518be5f3Spatrick 		bwfm_pci_ring_write_cancel(sc, ring, 1);
1786518be5f3Spatrick 		return ret;
1787518be5f3Spatrick 	}
1788518be5f3Spatrick 	paddr += ETHER_HDR_LEN;
1789518be5f3Spatrick 
1790518be5f3Spatrick 	tx->msg.request_id = htole32(pktid);
17914ff787bcSpatrick 	tx->data_len = htole16(m->m_len - ETHER_HDR_LEN);
1792518be5f3Spatrick 	tx->data_buf_addr.high_addr = htole32(paddr >> 32);
1793518be5f3Spatrick 	tx->data_buf_addr.low_addr = htole32(paddr & 0xffffffff);
1794518be5f3Spatrick 
1795518be5f3Spatrick 	bwfm_pci_ring_write_commit(sc, ring);
1796518be5f3Spatrick 	return 0;
1797e5ec1e72Spatrick }
1798e5ec1e72Spatrick 
1799bbd71b0bSpatrick #ifdef BWFM_DEBUG
1800cadf5fcfSpatrick void
1801cadf5fcfSpatrick bwfm_pci_debug_console(struct bwfm_pci_softc *sc)
1802cadf5fcfSpatrick {
1803cadf5fcfSpatrick 	uint32_t newidx = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1804cadf5fcfSpatrick 	    sc->sc_console_base_addr + BWFM_CONSOLE_WRITEIDX);
1805cadf5fcfSpatrick 
1806cadf5fcfSpatrick 	if (newidx != sc->sc_console_readidx)
1807bbd71b0bSpatrick 		DPRINTFN(3, ("BWFM CONSOLE: "));
1808cadf5fcfSpatrick 	while (newidx != sc->sc_console_readidx) {
1809cadf5fcfSpatrick 		uint8_t ch = bus_space_read_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1810cadf5fcfSpatrick 		    sc->sc_console_buf_addr + sc->sc_console_readidx);
1811cadf5fcfSpatrick 		sc->sc_console_readidx++;
1812cadf5fcfSpatrick 		if (sc->sc_console_readidx == sc->sc_console_buf_size)
1813cadf5fcfSpatrick 			sc->sc_console_readidx = 0;
1814cadf5fcfSpatrick 		if (ch == '\r')
1815cadf5fcfSpatrick 			continue;
1816bbd71b0bSpatrick 		DPRINTFN(3, ("%c", ch));
1817cadf5fcfSpatrick 	}
1818cadf5fcfSpatrick }
1819bbd71b0bSpatrick #endif
1820cadf5fcfSpatrick 
1821e5ec1e72Spatrick int
1822e5ec1e72Spatrick bwfm_pci_intr(void *v)
1823e5ec1e72Spatrick {
1824e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)v;
1825e5ec1e72Spatrick 	uint32_t status;
1826e5ec1e72Spatrick 
1827e5ec1e72Spatrick 	if ((status = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1828e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXINT)) == 0)
1829e5ec1e72Spatrick 		return 0;
1830e5ec1e72Spatrick 
1831e5ec1e72Spatrick 	bwfm_pci_intr_disable(sc);
1832e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1833e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXINT, status);
1834e5ec1e72Spatrick 
1835e5ec1e72Spatrick 	if (status & (BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_0 |
1836e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_1))
1837e5ec1e72Spatrick 		printf("%s: handle MB data\n", __func__);
1838e5ec1e72Spatrick 
1839e5ec1e72Spatrick 	if (status & BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_D2H_DB) {
1840518be5f3Spatrick 		bwfm_pci_ring_rx(sc, &sc->sc_rx_complete);
18412b7bea7eSpatrick 		bwfm_pci_ring_rx(sc, &sc->sc_tx_complete);
18422b7bea7eSpatrick 		bwfm_pci_ring_rx(sc, &sc->sc_ctrl_complete);
1843e5ec1e72Spatrick 	}
1844e5ec1e72Spatrick 
1845cadf5fcfSpatrick #ifdef BWFM_DEBUG
1846cadf5fcfSpatrick 	bwfm_pci_debug_console(sc);
1847e5ec1e72Spatrick #endif
1848e5ec1e72Spatrick 
1849e5ec1e72Spatrick 	bwfm_pci_intr_enable(sc);
1850e5ec1e72Spatrick 	return 1;
1851e5ec1e72Spatrick }
1852e5ec1e72Spatrick 
1853e5ec1e72Spatrick void
1854e5ec1e72Spatrick bwfm_pci_intr_enable(struct bwfm_pci_softc *sc)
1855e5ec1e72Spatrick {
1856e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1857e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXMASK,
1858e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_0 |
1859e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_1 |
1860e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_D2H_DB);
1861e5ec1e72Spatrick }
1862e5ec1e72Spatrick 
1863e5ec1e72Spatrick void
1864e5ec1e72Spatrick bwfm_pci_intr_disable(struct bwfm_pci_softc *sc)
1865e5ec1e72Spatrick {
1866e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1867e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXMASK, 0);
1868e5ec1e72Spatrick }
1869e5ec1e72Spatrick 
1870e5ec1e72Spatrick /* Msgbuf protocol implementation */
1871e5ec1e72Spatrick int
1872e5ec1e72Spatrick bwfm_pci_msgbuf_query_dcmd(struct bwfm_softc *bwfm, int ifidx,
1873e5ec1e72Spatrick     int cmd, char *buf, size_t *len)
1874e5ec1e72Spatrick {
1875e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1876e5ec1e72Spatrick 	struct msgbuf_ioctl_req_hdr *req;
1877e5ec1e72Spatrick 	struct mbuf *m;
1878e5ec1e72Spatrick 	size_t buflen;
1879e5ec1e72Spatrick 	int s;
1880e5ec1e72Spatrick 
1881e5ec1e72Spatrick 	s = splnet();
1882e5ec1e72Spatrick 	sc->sc_ioctl_resp_pktid = -1;
1883e5ec1e72Spatrick 	req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit);
1884e5ec1e72Spatrick 	if (req == NULL) {
1885e5ec1e72Spatrick 		printf("%s: cannot reserve for write\n", DEVNAME(sc));
1886e5ec1e72Spatrick 		splx(s);
1887e5ec1e72Spatrick 		return 1;
1888e5ec1e72Spatrick 	}
1889e5ec1e72Spatrick 	req->msg.msgtype = MSGBUF_TYPE_IOCTLPTR_REQ;
1890e5ec1e72Spatrick 	req->msg.ifidx = 0;
1891e5ec1e72Spatrick 	req->msg.flags = 0;
1892e5ec1e72Spatrick 	req->msg.request_id = htole32(MSGBUF_IOCTL_REQ_PKTID);
1893e5ec1e72Spatrick 	req->cmd = htole32(cmd);
1894e5ec1e72Spatrick 	req->output_buf_len = htole16(*len);
1895e5ec1e72Spatrick 	req->trans_id = htole16(sc->sc_ioctl_reqid++);
1896e5ec1e72Spatrick 
1897e5ec1e72Spatrick 	buflen = min(*len, BWFM_DMA_H2D_IOCTL_BUF_LEN);
1898e5ec1e72Spatrick 	req->input_buf_len = htole16(buflen);
1899e5ec1e72Spatrick 	req->req_buf_addr.high_addr =
1900e5ec1e72Spatrick 	    htole32((uint64_t)BWFM_PCI_DMA_DVA(sc->sc_ioctl_buf) >> 32);
1901e5ec1e72Spatrick 	req->req_buf_addr.low_addr =
1902e5ec1e72Spatrick 	    htole32((uint64_t)BWFM_PCI_DMA_DVA(sc->sc_ioctl_buf) & 0xffffffff);
1903e5ec1e72Spatrick 	if (buf)
1904e5ec1e72Spatrick 		memcpy(BWFM_PCI_DMA_KVA(sc->sc_ioctl_buf), buf, buflen);
1905e5ec1e72Spatrick 	else
1906e5ec1e72Spatrick 		memset(BWFM_PCI_DMA_KVA(sc->sc_ioctl_buf), 0, buflen);
1907e5ec1e72Spatrick 
1908e5ec1e72Spatrick 	bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit);
1909e5ec1e72Spatrick 	splx(s);
1910e5ec1e72Spatrick 
1911e5ec1e72Spatrick 	if (sc->sc_ioctl_poll) {
1912e5ec1e72Spatrick 		int i;
1913e5ec1e72Spatrick 		for (i = 0; i < 100; i++) {
1914e5ec1e72Spatrick 			if (sc->sc_ioctl_resp_pktid != -1)
1915e5ec1e72Spatrick 				break;
1916e5ec1e72Spatrick 			delay(10 * 1000);
1917e5ec1e72Spatrick 		}
1918e5ec1e72Spatrick 		if (i == 100) {
1919e5ec1e72Spatrick 			printf("%s: timeout waiting for ioctl response\n",
1920e5ec1e72Spatrick 			    DEVNAME(sc));
1921e5ec1e72Spatrick 			return 1;
1922e5ec1e72Spatrick 		}
1923e5ec1e72Spatrick 	} else if (tsleep(&sc->sc_ioctl_buf, PCATCH, "bwfm", hz)) {
1924e5ec1e72Spatrick 		printf("%s: timeout waiting for ioctl response\n",
1925e5ec1e72Spatrick 		    DEVNAME(sc));
1926e5ec1e72Spatrick 		return 1;
1927e5ec1e72Spatrick 	}
1928e5ec1e72Spatrick 
1929e5ec1e72Spatrick 	m = bwfm_pci_pktid_free(sc, &sc->sc_rx_pkts, sc->sc_ioctl_resp_pktid);
1930e5ec1e72Spatrick 	if (m == NULL)
1931e5ec1e72Spatrick 		return 1;
1932e5ec1e72Spatrick 
1933e5ec1e72Spatrick 	*len = min(buflen, sc->sc_ioctl_resp_ret_len);
1934e5ec1e72Spatrick 	if (buf)
1935e5ec1e72Spatrick 		memcpy(buf, mtod(m, char *), *len);
1936e5ec1e72Spatrick 	m_freem(m);
1937e5ec1e72Spatrick 	splx(s);
1938e5ec1e72Spatrick 
1939e5ec1e72Spatrick 	return 0;
1940e5ec1e72Spatrick }
1941e5ec1e72Spatrick 
1942e5ec1e72Spatrick int
1943e5ec1e72Spatrick bwfm_pci_msgbuf_set_dcmd(struct bwfm_softc *bwfm, int ifidx,
1944e5ec1e72Spatrick     int cmd, char *buf, size_t len)
1945e5ec1e72Spatrick {
1946e5ec1e72Spatrick 	return bwfm_pci_msgbuf_query_dcmd(bwfm, ifidx, cmd, buf, &len);
1947e5ec1e72Spatrick }
1948