xref: /openbsd/sys/dev/pci/if_bwfm_pci.c (revision 9ead8393)
1*9ead8393Spatrick /*	$OpenBSD: if_bwfm_pci.c,v 1.36 2020/03/07 09:56:46 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 
592eeba925Spatrick #define BWFM_NUM_IOCTL_PKTIDS			8
60e5ec1e72Spatrick #define BWFM_NUM_TX_PKTIDS			2048
61e5ec1e72Spatrick #define BWFM_NUM_RX_PKTIDS			1024
62e5ec1e72Spatrick 
632eeba925Spatrick #define BWFM_NUM_IOCTL_DESCS			1
64e5ec1e72Spatrick #define BWFM_NUM_TX_DESCS			1
65e5ec1e72Spatrick #define BWFM_NUM_RX_DESCS			1
66e5ec1e72Spatrick 
67e5ec1e72Spatrick #ifdef BWFM_DEBUG
68e5ec1e72Spatrick #define DPRINTF(x)	do { if (bwfm_debug > 0) printf x; } while (0)
69e5ec1e72Spatrick #define DPRINTFN(n, x)	do { if (bwfm_debug >= (n)) printf x; } while (0)
70e5ec1e72Spatrick static int bwfm_debug = 2;
71e5ec1e72Spatrick #else
72e5ec1e72Spatrick #define DPRINTF(x)	do { ; } while (0)
73e5ec1e72Spatrick #define DPRINTFN(n, x)	do { ; } while (0)
74e5ec1e72Spatrick #endif
75e5ec1e72Spatrick 
76e5ec1e72Spatrick #define DEVNAME(sc)	((sc)->sc_sc.sc_dev.dv_xname)
77e5ec1e72Spatrick 
78518be5f3Spatrick enum ring_status {
79518be5f3Spatrick 	RING_CLOSED,
80518be5f3Spatrick 	RING_CLOSING,
81518be5f3Spatrick 	RING_OPEN,
82518be5f3Spatrick 	RING_OPENING,
83518be5f3Spatrick };
84518be5f3Spatrick 
85e5ec1e72Spatrick struct bwfm_pci_msgring {
86e5ec1e72Spatrick 	uint32_t		 w_idx_addr;
87e5ec1e72Spatrick 	uint32_t		 r_idx_addr;
88e5ec1e72Spatrick 	uint32_t		 w_ptr;
89e5ec1e72Spatrick 	uint32_t		 r_ptr;
90e5ec1e72Spatrick 	int			 nitem;
91e5ec1e72Spatrick 	int			 itemsz;
92518be5f3Spatrick 	enum ring_status	 status;
93e5ec1e72Spatrick 	struct bwfm_pci_dmamem	*ring;
9402ee7d07Spatrick 	struct mbuf		*m;
95f67437f3Spatrick 
96f67437f3Spatrick 	int			 fifo;
97f67437f3Spatrick 	uint8_t			 mac[ETHER_ADDR_LEN];
98e5ec1e72Spatrick };
99e5ec1e72Spatrick 
1002eeba925Spatrick struct bwfm_pci_ioctl {
1012eeba925Spatrick 	uint16_t		 transid;
1022eeba925Spatrick 	uint16_t		 retlen;
1032eeba925Spatrick 	int16_t			 status;
1042eeba925Spatrick 	struct mbuf		*m;
1052eeba925Spatrick 	TAILQ_ENTRY(bwfm_pci_ioctl) next;
1062eeba925Spatrick };
1072eeba925Spatrick 
108e5ec1e72Spatrick struct bwfm_pci_buf {
109e5ec1e72Spatrick 	bus_dmamap_t	 bb_map;
110e5ec1e72Spatrick 	struct mbuf	*bb_m;
111e5ec1e72Spatrick };
112e5ec1e72Spatrick 
113e5ec1e72Spatrick struct bwfm_pci_pkts {
114e5ec1e72Spatrick 	struct bwfm_pci_buf	*pkts;
115e5ec1e72Spatrick 	uint32_t		 npkt;
116e5ec1e72Spatrick 	int			 last;
117e5ec1e72Spatrick };
118e5ec1e72Spatrick 
119e5ec1e72Spatrick struct bwfm_pci_softc {
120e5ec1e72Spatrick 	struct bwfm_softc	 sc_sc;
121e5ec1e72Spatrick 	pci_chipset_tag_t	 sc_pc;
122e5ec1e72Spatrick 	pcitag_t		 sc_tag;
123e5ec1e72Spatrick 	pcireg_t		 sc_id;
124e5ec1e72Spatrick 	void 			*sc_ih;
125e5ec1e72Spatrick 
126972218f3Spatrick 	int			 sc_initialized;
127972218f3Spatrick 
128e5ec1e72Spatrick 	bus_space_tag_t		 sc_reg_iot;
129e5ec1e72Spatrick 	bus_space_handle_t	 sc_reg_ioh;
130e5ec1e72Spatrick 	bus_size_t		 sc_reg_ios;
131e5ec1e72Spatrick 
132e5ec1e72Spatrick 	bus_space_tag_t		 sc_tcm_iot;
133e5ec1e72Spatrick 	bus_space_handle_t	 sc_tcm_ioh;
134e5ec1e72Spatrick 	bus_size_t		 sc_tcm_ios;
135e5ec1e72Spatrick 
136e5ec1e72Spatrick 	bus_dma_tag_t		 sc_dmat;
137e5ec1e72Spatrick 
138e5ec1e72Spatrick 	uint32_t		 sc_shared_address;
139e5ec1e72Spatrick 	uint32_t		 sc_shared_flags;
140e5ec1e72Spatrick 	uint8_t			 sc_shared_version;
141e5ec1e72Spatrick 
142e5ec1e72Spatrick 	uint8_t			 sc_dma_idx_sz;
143e5ec1e72Spatrick 	struct bwfm_pci_dmamem	*sc_dma_idx_buf;
144e5ec1e72Spatrick 	size_t			 sc_dma_idx_bufsz;
145e5ec1e72Spatrick 
146e5ec1e72Spatrick 	uint16_t		 sc_max_rxbufpost;
147e5ec1e72Spatrick 	uint32_t		 sc_rx_dataoffset;
148e5ec1e72Spatrick 	uint32_t		 sc_htod_mb_data_addr;
149e5ec1e72Spatrick 	uint32_t		 sc_dtoh_mb_data_addr;
150e5ec1e72Spatrick 	uint32_t		 sc_ring_info_addr;
151e5ec1e72Spatrick 
152e5ec1e72Spatrick 	uint32_t		 sc_console_base_addr;
153e5ec1e72Spatrick 	uint32_t		 sc_console_buf_addr;
154e5ec1e72Spatrick 	uint32_t		 sc_console_buf_size;
155cadf5fcfSpatrick 	uint32_t		 sc_console_readidx;
156e5ec1e72Spatrick 
157e5ec1e72Spatrick 	uint16_t		 sc_max_flowrings;
158e5ec1e72Spatrick 	uint16_t		 sc_max_submissionrings;
159e5ec1e72Spatrick 	uint16_t		 sc_max_completionrings;
160e5ec1e72Spatrick 
161e5ec1e72Spatrick 	struct bwfm_pci_msgring	 sc_ctrl_submit;
162e5ec1e72Spatrick 	struct bwfm_pci_msgring	 sc_rxpost_submit;
163e5ec1e72Spatrick 	struct bwfm_pci_msgring	 sc_ctrl_complete;
164e5ec1e72Spatrick 	struct bwfm_pci_msgring	 sc_tx_complete;
165e5ec1e72Spatrick 	struct bwfm_pci_msgring	 sc_rx_complete;
166e5ec1e72Spatrick 	struct bwfm_pci_msgring	*sc_flowrings;
167e5ec1e72Spatrick 
168e5ec1e72Spatrick 	struct bwfm_pci_dmamem	*sc_scratch_buf;
169e5ec1e72Spatrick 	struct bwfm_pci_dmamem	*sc_ringupd_buf;
170e5ec1e72Spatrick 
1712eeba925Spatrick 	TAILQ_HEAD(, bwfm_pci_ioctl) sc_ioctlq;
1722eeba925Spatrick 	uint16_t		 sc_ioctl_transid;
173e5ec1e72Spatrick 
174e5ec1e72Spatrick 	struct if_rxring	 sc_ioctl_ring;
175e5ec1e72Spatrick 	struct if_rxring	 sc_event_ring;
176e5ec1e72Spatrick 	struct if_rxring	 sc_rxbuf_ring;
177e5ec1e72Spatrick 
1782eeba925Spatrick 	struct bwfm_pci_pkts	 sc_ioctl_pkts;
179e5ec1e72Spatrick 	struct bwfm_pci_pkts	 sc_rx_pkts;
180c6f1636dSpatrick 	struct bwfm_pci_pkts	 sc_tx_pkts;
181c6f1636dSpatrick 	int			 sc_tx_pkts_full;
182e5ec1e72Spatrick };
183e5ec1e72Spatrick 
184e5ec1e72Spatrick struct bwfm_pci_dmamem {
185e5ec1e72Spatrick 	bus_dmamap_t		bdm_map;
186e5ec1e72Spatrick 	bus_dma_segment_t	bdm_seg;
187e5ec1e72Spatrick 	size_t			bdm_size;
188e5ec1e72Spatrick 	caddr_t			bdm_kva;
189e5ec1e72Spatrick };
190e5ec1e72Spatrick 
191e5ec1e72Spatrick #define BWFM_PCI_DMA_MAP(_bdm)	((_bdm)->bdm_map)
192e5ec1e72Spatrick #define BWFM_PCI_DMA_LEN(_bdm)	((_bdm)->bdm_size)
193e4dae658Spatrick #define BWFM_PCI_DMA_DVA(_bdm)	((uint64_t)(_bdm)->bdm_map->dm_segs[0].ds_addr)
194e5ec1e72Spatrick #define BWFM_PCI_DMA_KVA(_bdm)	((void *)(_bdm)->bdm_kva)
195e5ec1e72Spatrick 
196e5ec1e72Spatrick int		 bwfm_pci_match(struct device *, void *, void *);
197e5ec1e72Spatrick void		 bwfm_pci_attach(struct device *, struct device *, void *);
198e5ec1e72Spatrick int		 bwfm_pci_detach(struct device *, int);
199e5ec1e72Spatrick 
200e5ec1e72Spatrick int		 bwfm_pci_intr(void *);
201e5ec1e72Spatrick void		 bwfm_pci_intr_enable(struct bwfm_pci_softc *);
202e5ec1e72Spatrick void		 bwfm_pci_intr_disable(struct bwfm_pci_softc *);
203e5ec1e72Spatrick int		 bwfm_pci_load_microcode(struct bwfm_pci_softc *, const u_char *,
2046aad491fSpatrick 		    size_t, const u_char *, size_t);
205e5ec1e72Spatrick void		 bwfm_pci_select_core(struct bwfm_pci_softc *, int );
206e5ec1e72Spatrick 
207e5ec1e72Spatrick struct bwfm_pci_dmamem *
208e5ec1e72Spatrick 		 bwfm_pci_dmamem_alloc(struct bwfm_pci_softc *, bus_size_t,
209e5ec1e72Spatrick 		    bus_size_t);
210e5ec1e72Spatrick void		 bwfm_pci_dmamem_free(struct bwfm_pci_softc *, struct bwfm_pci_dmamem *);
21102ee7d07Spatrick int		 bwfm_pci_pktid_avail(struct bwfm_pci_softc *,
21202ee7d07Spatrick 		    struct bwfm_pci_pkts *);
213e5ec1e72Spatrick int		 bwfm_pci_pktid_new(struct bwfm_pci_softc *,
214e5ec1e72Spatrick 		    struct bwfm_pci_pkts *, struct mbuf *,
215e5ec1e72Spatrick 		    uint32_t *, paddr_t *);
216e5ec1e72Spatrick struct mbuf *	 bwfm_pci_pktid_free(struct bwfm_pci_softc *,
217e5ec1e72Spatrick 		    struct bwfm_pci_pkts *, uint32_t);
218e5ec1e72Spatrick void		 bwfm_pci_fill_rx_ioctl_ring(struct bwfm_pci_softc *,
219e5ec1e72Spatrick 		    struct if_rxring *, uint32_t);
220e5ec1e72Spatrick void		 bwfm_pci_fill_rx_buf_ring(struct bwfm_pci_softc *);
221e5ec1e72Spatrick void		 bwfm_pci_fill_rx_rings(struct bwfm_pci_softc *);
222e5ec1e72Spatrick int		 bwfm_pci_setup_ring(struct bwfm_pci_softc *, struct bwfm_pci_msgring *,
223e5ec1e72Spatrick 		    int, size_t, uint32_t, uint32_t, int, uint32_t, uint32_t *);
224518be5f3Spatrick int		 bwfm_pci_setup_flowring(struct bwfm_pci_softc *, struct bwfm_pci_msgring *,
225518be5f3Spatrick 		    int, size_t);
226e5ec1e72Spatrick 
227e5ec1e72Spatrick void		 bwfm_pci_ring_bell(struct bwfm_pci_softc *,
228e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
229e5ec1e72Spatrick void		 bwfm_pci_ring_update_rptr(struct bwfm_pci_softc *,
230e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
231e5ec1e72Spatrick void		 bwfm_pci_ring_update_wptr(struct bwfm_pci_softc *,
232e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
233e5ec1e72Spatrick void		 bwfm_pci_ring_write_rptr(struct bwfm_pci_softc *,
234e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
235e5ec1e72Spatrick void		 bwfm_pci_ring_write_wptr(struct bwfm_pci_softc *,
236e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
237e5ec1e72Spatrick void *		 bwfm_pci_ring_write_reserve(struct bwfm_pci_softc *,
238e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
239e5ec1e72Spatrick void *		 bwfm_pci_ring_write_reserve_multi(struct bwfm_pci_softc *,
240e5ec1e72Spatrick 		    struct bwfm_pci_msgring *, int, int *);
241e5ec1e72Spatrick void *		 bwfm_pci_ring_read_avail(struct bwfm_pci_softc *,
242e5ec1e72Spatrick 		    struct bwfm_pci_msgring *, int *);
243e5ec1e72Spatrick void		 bwfm_pci_ring_read_commit(struct bwfm_pci_softc *,
244e5ec1e72Spatrick 		    struct bwfm_pci_msgring *, int);
245e5ec1e72Spatrick void		 bwfm_pci_ring_write_commit(struct bwfm_pci_softc *,
246e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
247e5ec1e72Spatrick void		 bwfm_pci_ring_write_cancel(struct bwfm_pci_softc *,
248e5ec1e72Spatrick 		    struct bwfm_pci_msgring *, int);
249e5ec1e72Spatrick 
250e5ec1e72Spatrick void		 bwfm_pci_ring_rx(struct bwfm_pci_softc *,
2516f241297Spatrick 		    struct bwfm_pci_msgring *, struct mbuf_list *);
2526f241297Spatrick void		 bwfm_pci_msg_rx(struct bwfm_pci_softc *, void *,
2536f241297Spatrick 		    struct mbuf_list *);
254e5ec1e72Spatrick 
255e5ec1e72Spatrick uint32_t	 bwfm_pci_buscore_read(struct bwfm_softc *, uint32_t);
256e5ec1e72Spatrick void		 bwfm_pci_buscore_write(struct bwfm_softc *, uint32_t,
257e5ec1e72Spatrick 		    uint32_t);
258e5ec1e72Spatrick int		 bwfm_pci_buscore_prepare(struct bwfm_softc *);
259e5ec1e72Spatrick int		 bwfm_pci_buscore_reset(struct bwfm_softc *);
260e5ec1e72Spatrick void		 bwfm_pci_buscore_activate(struct bwfm_softc *, uint32_t);
261e5ec1e72Spatrick 
262f67437f3Spatrick int		 bwfm_pci_flowring_lookup(struct bwfm_pci_softc *,
263f67437f3Spatrick 		     struct mbuf *);
264f67437f3Spatrick void		 bwfm_pci_flowring_create(struct bwfm_pci_softc *,
265518be5f3Spatrick 		     struct mbuf *);
266518be5f3Spatrick void		 bwfm_pci_flowring_create_cb(struct bwfm_softc *, void *);
267a2c6ff8bSpatrick void		 bwfm_pci_flowring_delete(struct bwfm_pci_softc *, int);
268518be5f3Spatrick 
269972218f3Spatrick int		 bwfm_pci_preinit(struct bwfm_softc *);
270a2c6ff8bSpatrick void		 bwfm_pci_stop(struct bwfm_softc *);
27102ee7d07Spatrick int		 bwfm_pci_txcheck(struct bwfm_softc *);
272e5ec1e72Spatrick int		 bwfm_pci_txdata(struct bwfm_softc *, struct mbuf *);
273bbd71b0bSpatrick 
274bbd71b0bSpatrick #ifdef BWFM_DEBUG
275cadf5fcfSpatrick void		 bwfm_pci_debug_console(struct bwfm_pci_softc *);
276bbd71b0bSpatrick #endif
277e5ec1e72Spatrick 
278e5ec1e72Spatrick int		 bwfm_pci_msgbuf_query_dcmd(struct bwfm_softc *, int,
279e5ec1e72Spatrick 		    int, char *, size_t *);
280e5ec1e72Spatrick int		 bwfm_pci_msgbuf_set_dcmd(struct bwfm_softc *, int,
281e5ec1e72Spatrick 		    int, char *, size_t);
2822eeba925Spatrick void		 bwfm_pci_msgbuf_rxioctl(struct bwfm_pci_softc *,
2832eeba925Spatrick 		    struct msgbuf_ioctl_resp_hdr *);
284e5ec1e72Spatrick 
285e5ec1e72Spatrick struct bwfm_buscore_ops bwfm_pci_buscore_ops = {
286e5ec1e72Spatrick 	.bc_read = bwfm_pci_buscore_read,
287e5ec1e72Spatrick 	.bc_write = bwfm_pci_buscore_write,
288e5ec1e72Spatrick 	.bc_prepare = bwfm_pci_buscore_prepare,
289e5ec1e72Spatrick 	.bc_reset = bwfm_pci_buscore_reset,
290e5ec1e72Spatrick 	.bc_setup = NULL,
291e5ec1e72Spatrick 	.bc_activate = bwfm_pci_buscore_activate,
292e5ec1e72Spatrick };
293e5ec1e72Spatrick 
294e5ec1e72Spatrick struct bwfm_bus_ops bwfm_pci_bus_ops = {
295972218f3Spatrick 	.bs_preinit = bwfm_pci_preinit,
296a2c6ff8bSpatrick 	.bs_stop = bwfm_pci_stop,
29702ee7d07Spatrick 	.bs_txcheck = bwfm_pci_txcheck,
298e5ec1e72Spatrick 	.bs_txdata = bwfm_pci_txdata,
299e5ec1e72Spatrick 	.bs_txctl = NULL,
300e5ec1e72Spatrick };
301e5ec1e72Spatrick 
302e5ec1e72Spatrick struct bwfm_proto_ops bwfm_pci_msgbuf_ops = {
303e5ec1e72Spatrick 	.proto_query_dcmd = bwfm_pci_msgbuf_query_dcmd,
304e5ec1e72Spatrick 	.proto_set_dcmd = bwfm_pci_msgbuf_set_dcmd,
30514c74651Spatrick 	.proto_rx = NULL,
306029d6dd5Spatrick 	.proto_rxctl = NULL,
307e5ec1e72Spatrick };
308e5ec1e72Spatrick 
309e5ec1e72Spatrick struct cfattach bwfm_pci_ca = {
310e5ec1e72Spatrick 	sizeof(struct bwfm_pci_softc),
311e5ec1e72Spatrick 	bwfm_pci_match,
312e5ec1e72Spatrick 	bwfm_pci_attach,
313e5ec1e72Spatrick 	bwfm_pci_detach,
314e5ec1e72Spatrick };
315e5ec1e72Spatrick 
316e5ec1e72Spatrick static const struct pci_matchid bwfm_pci_devices[] = {
31782f0e660Sjcs 	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4350 },
31841d93ac2Spatrick 	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4356 },
31941d93ac2Spatrick 	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM43602 },
320821fc986Spatrick 	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4371 },
321e5ec1e72Spatrick };
322e5ec1e72Spatrick 
323e5ec1e72Spatrick int
324e5ec1e72Spatrick bwfm_pci_match(struct device *parent, void *match, void *aux)
325e5ec1e72Spatrick {
326e5ec1e72Spatrick 	return (pci_matchbyid(aux, bwfm_pci_devices,
327e5ec1e72Spatrick 	    nitems(bwfm_pci_devices)));
328e5ec1e72Spatrick }
329e5ec1e72Spatrick 
330e5ec1e72Spatrick void
331e5ec1e72Spatrick bwfm_pci_attach(struct device *parent, struct device *self, void *aux)
332e5ec1e72Spatrick {
333e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (struct bwfm_pci_softc *)self;
334e5ec1e72Spatrick 	struct pci_attach_args *pa = (struct pci_attach_args *)aux;
335e5ec1e72Spatrick 	const char *intrstr;
336e5ec1e72Spatrick 	pci_intr_handle_t ih;
337e5ec1e72Spatrick 
338e5ec1e72Spatrick 	if (pci_mapreg_map(pa, PCI_MAPREG_START + 0x08,
339e5ec1e72Spatrick 	    PCI_MAPREG_MEM_TYPE_64BIT, 0, &sc->sc_tcm_iot, &sc->sc_tcm_ioh,
340e5ec1e72Spatrick 	    NULL, &sc->sc_tcm_ios, 0)) {
341e5ec1e72Spatrick 		printf(": can't map bar1\n");
342a08e9144Spatrick 		return;
343a08e9144Spatrick 	}
344a08e9144Spatrick 
345a08e9144Spatrick 	if (pci_mapreg_map(pa, PCI_MAPREG_START + 0x00,
346a08e9144Spatrick 	    PCI_MAPREG_MEM_TYPE_64BIT, 0, &sc->sc_reg_iot, &sc->sc_reg_ioh,
347a08e9144Spatrick 	    NULL, &sc->sc_reg_ios, 0)) {
348a08e9144Spatrick 		printf(": can't map bar0\n");
349a08e9144Spatrick 		goto bar1;
350e5ec1e72Spatrick 	}
351e5ec1e72Spatrick 
352e5ec1e72Spatrick 	sc->sc_pc = pa->pa_pc;
353e5ec1e72Spatrick 	sc->sc_tag = pa->pa_tag;
354e5ec1e72Spatrick 	sc->sc_id = pa->pa_id;
355e5ec1e72Spatrick 	sc->sc_dmat = pa->pa_dmat;
356e5ec1e72Spatrick 
357e5ec1e72Spatrick 	/* Map and establish the interrupt. */
358e5ec1e72Spatrick 	if (pci_intr_map_msi(pa, &ih) != 0 && pci_intr_map(pa, &ih) != 0) {
359e5ec1e72Spatrick 		printf(": couldn't map interrupt\n");
360a08e9144Spatrick 		goto bar0;
361e5ec1e72Spatrick 	}
362e5ec1e72Spatrick 	intrstr = pci_intr_string(pa->pa_pc, ih);
363e5ec1e72Spatrick 
364e5ec1e72Spatrick 	sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_NET | IPL_MPSAFE,
365e5ec1e72Spatrick 	    bwfm_pci_intr, sc, DEVNAME(sc));
366e5ec1e72Spatrick 	if (sc->sc_ih == NULL) {
367e5ec1e72Spatrick 		printf(": couldn't establish interrupt");
368e5ec1e72Spatrick 		if (intrstr != NULL)
369e5ec1e72Spatrick 			printf(" at %s", intrstr);
370e5ec1e72Spatrick 		printf("\n");
371e5ec1e72Spatrick 		goto bar1;
372e5ec1e72Spatrick 	}
373e5ec1e72Spatrick 	printf(": %s\n", intrstr);
374e5ec1e72Spatrick 
375972218f3Spatrick 	sc->sc_sc.sc_bus_ops = &bwfm_pci_bus_ops;
376972218f3Spatrick 	sc->sc_sc.sc_proto_ops = &bwfm_pci_msgbuf_ops;
377972218f3Spatrick 	bwfm_attach(&sc->sc_sc);
378972218f3Spatrick 	config_mountroot(self, bwfm_attachhook);
379e5ec1e72Spatrick 	return;
380e5ec1e72Spatrick 
381e5ec1e72Spatrick bar0:
382e5ec1e72Spatrick 	bus_space_unmap(sc->sc_reg_iot, sc->sc_reg_ioh, sc->sc_reg_ios);
383a08e9144Spatrick bar1:
384a08e9144Spatrick 	bus_space_unmap(sc->sc_tcm_iot, sc->sc_tcm_ioh, sc->sc_tcm_ios);
385e5ec1e72Spatrick }
386e5ec1e72Spatrick 
387972218f3Spatrick int
388972218f3Spatrick bwfm_pci_preinit(struct bwfm_softc *bwfm)
389e5ec1e72Spatrick {
390972218f3Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
391e5ec1e72Spatrick 	struct bwfm_pci_ringinfo ringinfo;
392*9ead8393Spatrick 	const char *chip = NULL;
393*9ead8393Spatrick 	char name[128];
3946aad491fSpatrick 	u_char *ucode, *nvram = NULL;
395b4e85b06Spatrick 	size_t size, nvsize, nvlen = 0;
396e5ec1e72Spatrick 	uint32_t d2h_w_idx_ptr, d2h_r_idx_ptr;
397e5ec1e72Spatrick 	uint32_t h2d_w_idx_ptr, h2d_r_idx_ptr;
398e5ec1e72Spatrick 	uint32_t idx_offset, reg;
399e5ec1e72Spatrick 	int i;
400e5ec1e72Spatrick 
401972218f3Spatrick 	if (sc->sc_initialized)
402972218f3Spatrick 		return 0;
403972218f3Spatrick 
404e5ec1e72Spatrick 	sc->sc_sc.sc_buscore_ops = &bwfm_pci_buscore_ops;
405e5ec1e72Spatrick 	if (bwfm_chip_attach(&sc->sc_sc) != 0) {
406e5ec1e72Spatrick 		printf("%s: cannot attach chip\n", DEVNAME(sc));
407972218f3Spatrick 		return 1;
408e5ec1e72Spatrick 	}
409e5ec1e72Spatrick 
410e5ec1e72Spatrick 	bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2);
411e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
412e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_CONFIGADDR, 0x4e0);
413e5ec1e72Spatrick 	reg = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
414e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_CONFIGDATA);
415e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
416e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_CONFIGDATA, reg);
417e5ec1e72Spatrick 
418e5ec1e72Spatrick 	switch (bwfm->sc_chip.ch_chip)
419e5ec1e72Spatrick 	{
42018b3a1dcSpatrick 	case BRCM_CC_4350_CHIP_ID:
421*9ead8393Spatrick 		if (bwfm->sc_chip.ch_chiprev > 7)
422*9ead8393Spatrick 			chip = "4350";
423*9ead8393Spatrick 		else
424*9ead8393Spatrick 			chip = "4350c2";
42518b3a1dcSpatrick 		break;
42641d93ac2Spatrick 	case BRCM_CC_4356_CHIP_ID:
427*9ead8393Spatrick 		chip = "4356";
42841d93ac2Spatrick 		break;
429e5ec1e72Spatrick 	case BRCM_CC_43602_CHIP_ID:
430*9ead8393Spatrick 		chip = "43602";
431e5ec1e72Spatrick 		break;
432821fc986Spatrick 	case BRCM_CC_4371_CHIP_ID:
433*9ead8393Spatrick 		chip = "4371";
434821fc986Spatrick 		break;
435e5ec1e72Spatrick 	default:
43618b3a1dcSpatrick 		printf("%s: unknown firmware for chip %s\n",
43718b3a1dcSpatrick 		    DEVNAME(sc), bwfm->sc_chip.ch_name);
438972218f3Spatrick 		return 1;
439e5ec1e72Spatrick 	}
440e5ec1e72Spatrick 
441*9ead8393Spatrick 	snprintf(name, sizeof(name), "brcmfmac%s-pcie.bin", chip);
442e5ec1e72Spatrick 	if (loadfirmware(name, &ucode, &size) != 0) {
443e5ec1e72Spatrick 		printf("%s: failed loadfirmware of file %s\n",
444e5ec1e72Spatrick 		    DEVNAME(sc), name);
445972218f3Spatrick 		return 1;
446e5ec1e72Spatrick 	}
447e5ec1e72Spatrick 
448b4e85b06Spatrick 	/* .txt needs to be processed first */
449*9ead8393Spatrick 	snprintf(name, sizeof(name), "brcmfmac%s-pcie.txt", chip);
450*9ead8393Spatrick 	if (loadfirmware(name, &nvram, &nvsize) == 0) {
451b4e85b06Spatrick 		if (bwfm_nvram_convert(nvram, nvsize, &nvlen) != 0) {
452b4e85b06Spatrick 			printf("%s: failed to process file %s\n",
453*9ead8393Spatrick 			    DEVNAME(sc), name);
454b4e85b06Spatrick 			free(ucode, M_DEVBUF, size);
455b4e85b06Spatrick 			free(nvram, M_DEVBUF, nvsize);
456b4e85b06Spatrick 			return 1;
457b4e85b06Spatrick 		}
458*9ead8393Spatrick 	}
459*9ead8393Spatrick 
460b4e85b06Spatrick 	/* .nvram is the pre-processed version */
461*9ead8393Spatrick 	if (nvlen == 0) {
462*9ead8393Spatrick 		snprintf(name, sizeof(name), "brcmfmac%s-pcie.nvram", chip);
463*9ead8393Spatrick 		if (loadfirmware(name, &nvram, &nvsize) == 0)
464b4e85b06Spatrick 			nvlen = nvsize;
465b4e85b06Spatrick 	}
4666aad491fSpatrick 
467e5ec1e72Spatrick 	/* Retrieve RAM size from firmware. */
468e5ec1e72Spatrick 	if (size >= BWFM_RAMSIZE + 8) {
469e5ec1e72Spatrick 		uint32_t *ramsize = (uint32_t *)&ucode[BWFM_RAMSIZE];
470e5ec1e72Spatrick 		if (letoh32(ramsize[0]) == BWFM_RAMSIZE_MAGIC)
471e5ec1e72Spatrick 			bwfm->sc_chip.ch_ramsize = letoh32(ramsize[1]);
472e5ec1e72Spatrick 	}
473e5ec1e72Spatrick 
4746aad491fSpatrick 	if (bwfm_pci_load_microcode(sc, ucode, size, nvram, nvlen) != 0) {
475e5ec1e72Spatrick 		printf("%s: could not load microcode\n",
476e5ec1e72Spatrick 		    DEVNAME(sc));
477e5ec1e72Spatrick 		free(ucode, M_DEVBUF, size);
478b4e85b06Spatrick 		free(nvram, M_DEVBUF, nvsize);
479972218f3Spatrick 		return 1;
480e5ec1e72Spatrick 	}
481e5ec1e72Spatrick 	free(ucode, M_DEVBUF, size);
482b4e85b06Spatrick 	free(nvram, M_DEVBUF, nvsize);
483e5ec1e72Spatrick 
484e5ec1e72Spatrick 	sc->sc_shared_flags = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
485e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_INFO);
486e5ec1e72Spatrick 	sc->sc_shared_version = sc->sc_shared_flags;
487e5ec1e72Spatrick 	if (sc->sc_shared_version > BWFM_SHARED_INFO_MAX_VERSION ||
488e5ec1e72Spatrick 	    sc->sc_shared_version < BWFM_SHARED_INFO_MIN_VERSION) {
489e5ec1e72Spatrick 		printf("%s: PCIe version %d unsupported\n",
490e5ec1e72Spatrick 		    DEVNAME(sc), sc->sc_shared_version);
491972218f3Spatrick 		return 1;
492e5ec1e72Spatrick 	}
493e5ec1e72Spatrick 
494e5ec1e72Spatrick 	if (sc->sc_shared_flags & BWFM_SHARED_INFO_DMA_INDEX) {
495e5ec1e72Spatrick 		if (sc->sc_shared_flags & BWFM_SHARED_INFO_DMA_2B_IDX)
496e5ec1e72Spatrick 			sc->sc_dma_idx_sz = sizeof(uint16_t);
497e5ec1e72Spatrick 		else
498e5ec1e72Spatrick 			sc->sc_dma_idx_sz = sizeof(uint32_t);
499e5ec1e72Spatrick 	}
500e5ec1e72Spatrick 
501e5ec1e72Spatrick 	/* Maximum RX data buffers in the ring. */
502e5ec1e72Spatrick 	sc->sc_max_rxbufpost = bus_space_read_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
503e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_MAX_RXBUFPOST);
504e5ec1e72Spatrick 	if (sc->sc_max_rxbufpost == 0)
505e5ec1e72Spatrick 		sc->sc_max_rxbufpost = BWFM_SHARED_MAX_RXBUFPOST_DEFAULT;
506e5ec1e72Spatrick 
507e5ec1e72Spatrick 	/* Alternative offset of data in a packet */
508e5ec1e72Spatrick 	sc->sc_rx_dataoffset = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
509e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_RX_DATAOFFSET);
510e5ec1e72Spatrick 
511e5ec1e72Spatrick 	/* For Power Management */
512e5ec1e72Spatrick 	sc->sc_htod_mb_data_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
513e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_HTOD_MB_DATA_ADDR);
514e5ec1e72Spatrick 	sc->sc_dtoh_mb_data_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
515e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DTOH_MB_DATA_ADDR);
516e5ec1e72Spatrick 
517e5ec1e72Spatrick 	/* Ring information */
518e5ec1e72Spatrick 	sc->sc_ring_info_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
519e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_RING_INFO_ADDR);
520e5ec1e72Spatrick 
521e5ec1e72Spatrick 	/* Firmware's "dmesg" */
522e5ec1e72Spatrick 	sc->sc_console_base_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
523e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_CONSOLE_ADDR);
524e5ec1e72Spatrick 	sc->sc_console_buf_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
525e5ec1e72Spatrick 	    sc->sc_console_base_addr + BWFM_CONSOLE_BUFADDR);
526e5ec1e72Spatrick 	sc->sc_console_buf_size = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
527e5ec1e72Spatrick 	    sc->sc_console_base_addr + BWFM_CONSOLE_BUFSIZE);
528e5ec1e72Spatrick 
529e5ec1e72Spatrick 	/* Read ring information. */
530e5ec1e72Spatrick 	bus_space_read_region_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
531e5ec1e72Spatrick 	    sc->sc_ring_info_addr, (void *)&ringinfo, sizeof(ringinfo));
532e5ec1e72Spatrick 
533e5ec1e72Spatrick 	if (sc->sc_shared_version >= 6) {
534e5ec1e72Spatrick 		sc->sc_max_submissionrings = le16toh(ringinfo.max_submissionrings);
535e5ec1e72Spatrick 		sc->sc_max_flowrings = le16toh(ringinfo.max_flowrings);
536e5ec1e72Spatrick 		sc->sc_max_completionrings = le16toh(ringinfo.max_completionrings);
537e5ec1e72Spatrick 	} else {
538e5ec1e72Spatrick 		sc->sc_max_submissionrings = le16toh(ringinfo.max_flowrings);
539e5ec1e72Spatrick 		sc->sc_max_flowrings = sc->sc_max_submissionrings -
540e5ec1e72Spatrick 		    BWFM_NUM_TX_MSGRINGS;
541e5ec1e72Spatrick 		sc->sc_max_completionrings = BWFM_NUM_RX_MSGRINGS;
542e5ec1e72Spatrick 	}
543e5ec1e72Spatrick 
544e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
545e5ec1e72Spatrick 		d2h_w_idx_ptr = letoh32(ringinfo.d2h_w_idx_ptr);
546e5ec1e72Spatrick 		d2h_r_idx_ptr = letoh32(ringinfo.d2h_r_idx_ptr);
547e5ec1e72Spatrick 		h2d_w_idx_ptr = letoh32(ringinfo.h2d_w_idx_ptr);
548e5ec1e72Spatrick 		h2d_r_idx_ptr = letoh32(ringinfo.h2d_r_idx_ptr);
549e5ec1e72Spatrick 		idx_offset = sizeof(uint32_t);
550e5ec1e72Spatrick 	} else {
551e5ec1e72Spatrick 		uint64_t address;
552e5ec1e72Spatrick 
553e5ec1e72Spatrick 		/* Each TX/RX Ring has a Read and Write Ptr */
554e5ec1e72Spatrick 		sc->sc_dma_idx_bufsz = (sc->sc_max_submissionrings +
555e5ec1e72Spatrick 		    sc->sc_max_completionrings) * sc->sc_dma_idx_sz * 2;
556e5ec1e72Spatrick 		sc->sc_dma_idx_buf = bwfm_pci_dmamem_alloc(sc,
557e5ec1e72Spatrick 		    sc->sc_dma_idx_bufsz, 8);
558e5ec1e72Spatrick 		if (sc->sc_dma_idx_buf == NULL) {
559e5ec1e72Spatrick 			/* XXX: Fallback to TCM? */
560e5ec1e72Spatrick 			printf("%s: cannot allocate idx buf\n",
561e5ec1e72Spatrick 			    DEVNAME(sc));
562972218f3Spatrick 			return 1;
563e5ec1e72Spatrick 		}
564e5ec1e72Spatrick 
565e5ec1e72Spatrick 		idx_offset = sc->sc_dma_idx_sz;
566e5ec1e72Spatrick 		h2d_w_idx_ptr = 0;
567e5ec1e72Spatrick 		address = BWFM_PCI_DMA_DVA(sc->sc_dma_idx_buf);
568e5ec1e72Spatrick 		ringinfo.h2d_w_idx_hostaddr_low =
569e5ec1e72Spatrick 		    htole32(address & 0xffffffff);
570e5ec1e72Spatrick 		ringinfo.h2d_w_idx_hostaddr_high =
571e5ec1e72Spatrick 		    htole32(address >> 32);
572e5ec1e72Spatrick 
573e5ec1e72Spatrick 		h2d_r_idx_ptr = h2d_w_idx_ptr +
574e5ec1e72Spatrick 		    sc->sc_max_submissionrings * idx_offset;
575e5ec1e72Spatrick 		address += sc->sc_max_submissionrings * idx_offset;
576e5ec1e72Spatrick 		ringinfo.h2d_r_idx_hostaddr_low =
577e5ec1e72Spatrick 		    htole32(address & 0xffffffff);
578e5ec1e72Spatrick 		ringinfo.h2d_r_idx_hostaddr_high =
579e5ec1e72Spatrick 		    htole32(address >> 32);
580e5ec1e72Spatrick 
581e5ec1e72Spatrick 		d2h_w_idx_ptr = h2d_r_idx_ptr +
582e5ec1e72Spatrick 		    sc->sc_max_submissionrings * idx_offset;
583e5ec1e72Spatrick 		address += sc->sc_max_submissionrings * idx_offset;
584e5ec1e72Spatrick 		ringinfo.d2h_w_idx_hostaddr_low =
585e5ec1e72Spatrick 		    htole32(address & 0xffffffff);
586e5ec1e72Spatrick 		ringinfo.d2h_w_idx_hostaddr_high =
587e5ec1e72Spatrick 		    htole32(address >> 32);
588e5ec1e72Spatrick 
589e5ec1e72Spatrick 		d2h_r_idx_ptr = d2h_w_idx_ptr +
590e5ec1e72Spatrick 		    sc->sc_max_completionrings * idx_offset;
591e5ec1e72Spatrick 		address += sc->sc_max_completionrings * idx_offset;
592e5ec1e72Spatrick 		ringinfo.d2h_r_idx_hostaddr_low =
593e5ec1e72Spatrick 		    htole32(address & 0xffffffff);
594e5ec1e72Spatrick 		ringinfo.d2h_r_idx_hostaddr_high =
595e5ec1e72Spatrick 		    htole32(address >> 32);
596e5ec1e72Spatrick 
597e5ec1e72Spatrick 		bus_space_write_region_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
598e5ec1e72Spatrick 		    sc->sc_ring_info_addr, (void *)&ringinfo, sizeof(ringinfo));
599e5ec1e72Spatrick 	}
600e5ec1e72Spatrick 
601e5ec1e72Spatrick 	uint32_t ring_mem_ptr = letoh32(ringinfo.ringmem);
602e5ec1e72Spatrick 	/* TX ctrl ring: Send ctrl buffers, send IOCTLs */
603e5ec1e72Spatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_ctrl_submit, 64, 40,
604e5ec1e72Spatrick 	    h2d_w_idx_ptr, h2d_r_idx_ptr, 0, idx_offset,
605e5ec1e72Spatrick 	    &ring_mem_ptr))
606e5ec1e72Spatrick 		goto cleanup;
607e5ec1e72Spatrick 	/* TX rxpost ring: Send clean data mbufs for RX */
608e5ec1e72Spatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_rxpost_submit, 512, 32,
609e5ec1e72Spatrick 	    h2d_w_idx_ptr, h2d_r_idx_ptr, 1, idx_offset,
610e5ec1e72Spatrick 	    &ring_mem_ptr))
611e5ec1e72Spatrick 		goto cleanup;
612e5ec1e72Spatrick 	/* RX completion rings: recv our filled buffers back */
613e5ec1e72Spatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_ctrl_complete, 64, 24,
614e5ec1e72Spatrick 	    d2h_w_idx_ptr, d2h_r_idx_ptr, 0, idx_offset,
615e5ec1e72Spatrick 	    &ring_mem_ptr))
616e5ec1e72Spatrick 		goto cleanup;
617e5ec1e72Spatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_tx_complete, 1024, 16,
618e5ec1e72Spatrick 	    d2h_w_idx_ptr, d2h_r_idx_ptr, 1, idx_offset,
619e5ec1e72Spatrick 	    &ring_mem_ptr))
620e5ec1e72Spatrick 		goto cleanup;
621e5ec1e72Spatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_rx_complete, 512, 32,
622e5ec1e72Spatrick 	    d2h_w_idx_ptr, d2h_r_idx_ptr, 2, idx_offset,
623e5ec1e72Spatrick 	    &ring_mem_ptr))
624e5ec1e72Spatrick 		goto cleanup;
625e5ec1e72Spatrick 
626e5ec1e72Spatrick 	/* Dynamic TX rings for actual data */
627e5ec1e72Spatrick 	sc->sc_flowrings = malloc(sc->sc_max_flowrings *
628e5ec1e72Spatrick 	    sizeof(struct bwfm_pci_msgring), M_DEVBUF, M_WAITOK | M_ZERO);
629518be5f3Spatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
630518be5f3Spatrick 		struct bwfm_pci_msgring *ring = &sc->sc_flowrings[i];
631518be5f3Spatrick 		ring->w_idx_addr = h2d_w_idx_ptr + (i + 2) * idx_offset;
632518be5f3Spatrick 		ring->r_idx_addr = h2d_r_idx_ptr + (i + 2) * idx_offset;
633518be5f3Spatrick 	}
634e5ec1e72Spatrick 
635e5ec1e72Spatrick 	/* Scratch and ring update buffers for firmware */
636e5ec1e72Spatrick 	if ((sc->sc_scratch_buf = bwfm_pci_dmamem_alloc(sc,
637e5ec1e72Spatrick 	    BWFM_DMA_D2H_SCRATCH_BUF_LEN, 8)) == NULL)
638e5ec1e72Spatrick 		goto cleanup;
639e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
640e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_SCRATCH_ADDR_LOW,
641e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(sc->sc_scratch_buf) & 0xffffffff);
642e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
643e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_SCRATCH_ADDR_HIGH,
644e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(sc->sc_scratch_buf) >> 32);
645e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
646e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_SCRATCH_LEN,
647e5ec1e72Spatrick 	    BWFM_DMA_D2H_SCRATCH_BUF_LEN);
648e5ec1e72Spatrick 
649e5ec1e72Spatrick 	if ((sc->sc_ringupd_buf = bwfm_pci_dmamem_alloc(sc,
650e5ec1e72Spatrick 	    BWFM_DMA_D2H_RINGUPD_BUF_LEN, 8)) == NULL)
651e5ec1e72Spatrick 		goto cleanup;
652e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
653e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_RINGUPD_ADDR_LOW,
654e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(sc->sc_ringupd_buf) & 0xffffffff);
655e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
656e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_RINGUPD_ADDR_HIGH,
657e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(sc->sc_ringupd_buf) >> 32);
658e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
659e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_RINGUPD_LEN,
660e5ec1e72Spatrick 	    BWFM_DMA_D2H_RINGUPD_BUF_LEN);
661e5ec1e72Spatrick 
662e5ec1e72Spatrick 	bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2);
663e5ec1e72Spatrick 	bwfm_pci_intr_enable(sc);
664e5ec1e72Spatrick 
665e5ec1e72Spatrick 	/* Maps RX mbufs to a packet id and back. */
666e5ec1e72Spatrick 	sc->sc_rx_pkts.npkt = BWFM_NUM_RX_PKTIDS;
667e5ec1e72Spatrick 	sc->sc_rx_pkts.pkts = malloc(BWFM_NUM_RX_PKTIDS *
668e5ec1e72Spatrick 	    sizeof(struct bwfm_pci_buf), M_DEVBUF, M_WAITOK | M_ZERO);
669e5ec1e72Spatrick 	for (i = 0; i < BWFM_NUM_RX_PKTIDS; i++)
670e5ec1e72Spatrick 		bus_dmamap_create(sc->sc_dmat, MSGBUF_MAX_PKT_SIZE,
671e5ec1e72Spatrick 		    BWFM_NUM_RX_DESCS, MSGBUF_MAX_PKT_SIZE, 0, BUS_DMA_WAITOK,
672e5ec1e72Spatrick 		    &sc->sc_rx_pkts.pkts[i].bb_map);
673e5ec1e72Spatrick 
674e5ec1e72Spatrick 	/* Maps TX mbufs to a packet id and back. */
675f416501bSpatrick 	sc->sc_tx_pkts.npkt = BWFM_NUM_TX_PKTIDS;
676e5ec1e72Spatrick 	sc->sc_tx_pkts.pkts = malloc(BWFM_NUM_TX_PKTIDS
677e5ec1e72Spatrick 	    * sizeof(struct bwfm_pci_buf), M_DEVBUF, M_WAITOK | M_ZERO);
678e5ec1e72Spatrick 	for (i = 0; i < BWFM_NUM_TX_PKTIDS; i++)
679e5ec1e72Spatrick 		bus_dmamap_create(sc->sc_dmat, MSGBUF_MAX_PKT_SIZE,
680e5ec1e72Spatrick 		    BWFM_NUM_TX_DESCS, MSGBUF_MAX_PKT_SIZE, 0, BUS_DMA_WAITOK,
681e5ec1e72Spatrick 		    &sc->sc_tx_pkts.pkts[i].bb_map);
682e5ec1e72Spatrick 
6832eeba925Spatrick 	/* Maps IOCTL mbufs to a packet id and back. */
6842eeba925Spatrick 	sc->sc_ioctl_pkts.npkt = BWFM_NUM_IOCTL_PKTIDS;
6852eeba925Spatrick 	sc->sc_ioctl_pkts.pkts = malloc(BWFM_NUM_IOCTL_PKTIDS
6862eeba925Spatrick 	    * sizeof(struct bwfm_pci_buf), M_DEVBUF, M_WAITOK | M_ZERO);
6872eeba925Spatrick 	for (i = 0; i < BWFM_NUM_IOCTL_PKTIDS; i++)
6882eeba925Spatrick 		bus_dmamap_create(sc->sc_dmat, MSGBUF_MAX_PKT_SIZE,
6892eeba925Spatrick 		    BWFM_NUM_IOCTL_DESCS, MSGBUF_MAX_PKT_SIZE, 0, BUS_DMA_WAITOK,
6902eeba925Spatrick 		    &sc->sc_ioctl_pkts.pkts[i].bb_map);
6912eeba925Spatrick 
69218722113Spatrick 	/*
69318722113Spatrick 	 * For whatever reason, could also be a bug somewhere in this
69418722113Spatrick 	 * driver, the firmware needs a bunch of RX buffers otherwise
69518722113Spatrick 	 * it won't send any RX complete messages.  64 buffers don't
69618722113Spatrick 	 * suffice, but 128 buffers are enough.
69718722113Spatrick 	 */
69818722113Spatrick 	if_rxr_init(&sc->sc_rxbuf_ring, 128, sc->sc_max_rxbufpost);
699e5ec1e72Spatrick 	if_rxr_init(&sc->sc_ioctl_ring, 8, 8);
700e5ec1e72Spatrick 	if_rxr_init(&sc->sc_event_ring, 8, 8);
701e5ec1e72Spatrick 	bwfm_pci_fill_rx_rings(sc);
702e5ec1e72Spatrick 
7032eeba925Spatrick 	TAILQ_INIT(&sc->sc_ioctlq);
7042eeba925Spatrick 
705cadf5fcfSpatrick #ifdef BWFM_DEBUG
706cadf5fcfSpatrick 	sc->sc_console_readidx = 0;
707cadf5fcfSpatrick 	bwfm_pci_debug_console(sc);
708cadf5fcfSpatrick #endif
709cadf5fcfSpatrick 
710972218f3Spatrick 	sc->sc_initialized = 1;
711972218f3Spatrick 	return 0;
712e5ec1e72Spatrick 
713e5ec1e72Spatrick cleanup:
714e5ec1e72Spatrick 	if (sc->sc_ringupd_buf)
715e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_ringupd_buf);
716e5ec1e72Spatrick 	if (sc->sc_scratch_buf)
717e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_scratch_buf);
718e5ec1e72Spatrick 	if (sc->sc_rx_complete.ring)
719e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_rx_complete.ring);
720e5ec1e72Spatrick 	if (sc->sc_tx_complete.ring)
721e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_tx_complete.ring);
722e5ec1e72Spatrick 	if (sc->sc_ctrl_complete.ring)
723e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_ctrl_complete.ring);
724e5ec1e72Spatrick 	if (sc->sc_rxpost_submit.ring)
725e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_rxpost_submit.ring);
726e5ec1e72Spatrick 	if (sc->sc_ctrl_submit.ring)
727e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_ctrl_submit.ring);
728e5ec1e72Spatrick 	if (sc->sc_dma_idx_buf)
729e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_dma_idx_buf);
730972218f3Spatrick 	return 1;
731e5ec1e72Spatrick }
732e5ec1e72Spatrick 
733e5ec1e72Spatrick int
7346aad491fSpatrick bwfm_pci_load_microcode(struct bwfm_pci_softc *sc, const u_char *ucode, size_t size,
7356aad491fSpatrick     const u_char *nvram, size_t nvlen)
736e5ec1e72Spatrick {
737e5ec1e72Spatrick 	struct bwfm_softc *bwfm = (void *)sc;
738e5ec1e72Spatrick 	struct bwfm_core *core;
7396aad491fSpatrick 	uint32_t shared, written;
740e5ec1e72Spatrick 	int i;
741e5ec1e72Spatrick 
742e5ec1e72Spatrick 	if (bwfm->sc_chip.ch_chip == BRCM_CC_43602_CHIP_ID) {
743e5ec1e72Spatrick 		bwfm_pci_select_core(sc, BWFM_AGENT_CORE_ARM_CR4);
744e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
745e5ec1e72Spatrick 		    BWFM_PCI_ARMCR4REG_BANKIDX, 5);
746e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
747e5ec1e72Spatrick 		    BWFM_PCI_ARMCR4REG_BANKPDA, 0);
748e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
749e5ec1e72Spatrick 		    BWFM_PCI_ARMCR4REG_BANKIDX, 7);
750e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
751e5ec1e72Spatrick 		    BWFM_PCI_ARMCR4REG_BANKPDA, 0);
752e5ec1e72Spatrick 	}
753e5ec1e72Spatrick 
754e5ec1e72Spatrick 	for (i = 0; i < size; i++)
755e5ec1e72Spatrick 		bus_space_write_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
756e5ec1e72Spatrick 		    bwfm->sc_chip.ch_rambase + i, ucode[i]);
757e5ec1e72Spatrick 
758e5ec1e72Spatrick 	/* Firmware replaces this with a pointer once up. */
759e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
760e5ec1e72Spatrick 	    bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize - 4, 0);
761e5ec1e72Spatrick 
7626aad491fSpatrick 	if (nvram) {
7636aad491fSpatrick 		for (i = 0; i < nvlen; i++)
7646aad491fSpatrick 			bus_space_write_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
7656aad491fSpatrick 			    bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize
7666aad491fSpatrick 			    - nvlen  + i, nvram[i]);
7676aad491fSpatrick 	}
7686aad491fSpatrick 
7696aad491fSpatrick 	written = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
7706aad491fSpatrick 	    bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize - 4);
771e5ec1e72Spatrick 
772e5ec1e72Spatrick 	/* Load reset vector from firmware and kickstart core. */
773b0cd4990Spatrick 	if (bwfm->sc_chip.ch_chip == BRCM_CC_43602_CHIP_ID) {
774e5ec1e72Spatrick 		core = bwfm_chip_get_core(bwfm, BWFM_AGENT_INTERNAL_MEM);
775e5ec1e72Spatrick 		bwfm->sc_chip.ch_core_reset(bwfm, core, 0, 0, 0);
776b0cd4990Spatrick 	}
777e5ec1e72Spatrick 	bwfm_chip_set_active(bwfm, *(uint32_t *)ucode);
778e5ec1e72Spatrick 
779e5ec1e72Spatrick 	for (i = 0; i < 40; i++) {
780e5ec1e72Spatrick 		delay(50 * 1000);
781e5ec1e72Spatrick 		shared = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
782e5ec1e72Spatrick 		    bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize - 4);
7836aad491fSpatrick 		if (shared != written)
784e5ec1e72Spatrick 			break;
785e5ec1e72Spatrick 	}
786e5ec1e72Spatrick 	if (!shared) {
787e5ec1e72Spatrick 		printf("%s: firmware did not come up\n", DEVNAME(sc));
788e5ec1e72Spatrick 		return 1;
789e5ec1e72Spatrick 	}
790e5ec1e72Spatrick 
791e5ec1e72Spatrick 	sc->sc_shared_address = shared;
792e5ec1e72Spatrick 	return 0;
793e5ec1e72Spatrick }
794e5ec1e72Spatrick 
795e5ec1e72Spatrick int
796e5ec1e72Spatrick bwfm_pci_detach(struct device *self, int flags)
797e5ec1e72Spatrick {
798e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (struct bwfm_pci_softc *)self;
799e5ec1e72Spatrick 
800e5ec1e72Spatrick 	bwfm_detach(&sc->sc_sc, flags);
801e5ec1e72Spatrick 
802e5ec1e72Spatrick 	/* FIXME: free RX buffers */
803e5ec1e72Spatrick 	/* FIXME: free TX buffers */
804e5ec1e72Spatrick 	/* FIXME: free more memory */
805e5ec1e72Spatrick 
806e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_ringupd_buf);
807e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_scratch_buf);
808e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_rx_complete.ring);
809e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_tx_complete.ring);
810e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_ctrl_complete.ring);
811e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_rxpost_submit.ring);
812e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_ctrl_submit.ring);
813e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_dma_idx_buf);
814e5ec1e72Spatrick 	return 0;
815e5ec1e72Spatrick }
816e5ec1e72Spatrick 
817e5ec1e72Spatrick /* DMA code */
818e5ec1e72Spatrick struct bwfm_pci_dmamem *
819e5ec1e72Spatrick bwfm_pci_dmamem_alloc(struct bwfm_pci_softc *sc, bus_size_t size, bus_size_t align)
820e5ec1e72Spatrick {
821e5ec1e72Spatrick 	struct bwfm_pci_dmamem *bdm;
822e5ec1e72Spatrick 	int nsegs;
823e5ec1e72Spatrick 
824e5ec1e72Spatrick 	bdm = malloc(sizeof(*bdm), M_DEVBUF, M_WAITOK | M_ZERO);
825e5ec1e72Spatrick 	bdm->bdm_size = size;
826e5ec1e72Spatrick 
827e5ec1e72Spatrick 	if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
828e5ec1e72Spatrick 	    BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &bdm->bdm_map) != 0)
829e5ec1e72Spatrick 		goto bdmfree;
830e5ec1e72Spatrick 
831e5ec1e72Spatrick 	if (bus_dmamem_alloc(sc->sc_dmat, size, align, 0, &bdm->bdm_seg, 1,
832e5ec1e72Spatrick 	    &nsegs, BUS_DMA_WAITOK) != 0)
833e5ec1e72Spatrick 		goto destroy;
834e5ec1e72Spatrick 
835e5ec1e72Spatrick 	if (bus_dmamem_map(sc->sc_dmat, &bdm->bdm_seg, nsegs, size,
836e5ec1e72Spatrick 	    &bdm->bdm_kva, BUS_DMA_WAITOK | BUS_DMA_COHERENT) != 0)
837e5ec1e72Spatrick 		goto free;
838e5ec1e72Spatrick 
839e5ec1e72Spatrick 	if (bus_dmamap_load(sc->sc_dmat, bdm->bdm_map, bdm->bdm_kva, size,
840e5ec1e72Spatrick 	    NULL, BUS_DMA_WAITOK) != 0)
841e5ec1e72Spatrick 		goto unmap;
842e5ec1e72Spatrick 
843e5ec1e72Spatrick 	bzero(bdm->bdm_kva, size);
844e5ec1e72Spatrick 
845e5ec1e72Spatrick 	return (bdm);
846e5ec1e72Spatrick 
847e5ec1e72Spatrick unmap:
848e5ec1e72Spatrick 	bus_dmamem_unmap(sc->sc_dmat, bdm->bdm_kva, size);
849e5ec1e72Spatrick free:
850e5ec1e72Spatrick 	bus_dmamem_free(sc->sc_dmat, &bdm->bdm_seg, 1);
851e5ec1e72Spatrick destroy:
852e5ec1e72Spatrick 	bus_dmamap_destroy(sc->sc_dmat, bdm->bdm_map);
853e5ec1e72Spatrick bdmfree:
85465046b40Spatrick 	free(bdm, M_DEVBUF, sizeof(*bdm));
855e5ec1e72Spatrick 
856e5ec1e72Spatrick 	return (NULL);
857e5ec1e72Spatrick }
858e5ec1e72Spatrick 
859e5ec1e72Spatrick void
860e5ec1e72Spatrick bwfm_pci_dmamem_free(struct bwfm_pci_softc *sc, struct bwfm_pci_dmamem *bdm)
861e5ec1e72Spatrick {
862e5ec1e72Spatrick 	bus_dmamem_unmap(sc->sc_dmat, bdm->bdm_kva, bdm->bdm_size);
863e5ec1e72Spatrick 	bus_dmamem_free(sc->sc_dmat, &bdm->bdm_seg, 1);
864e5ec1e72Spatrick 	bus_dmamap_destroy(sc->sc_dmat, bdm->bdm_map);
86565046b40Spatrick 	free(bdm, M_DEVBUF, sizeof(*bdm));
866e5ec1e72Spatrick }
867e5ec1e72Spatrick 
868e5ec1e72Spatrick /*
869e5ec1e72Spatrick  * We need a simple mapping from a packet ID to mbufs, because when
870e5ec1e72Spatrick  * a transfer completed, we only know the ID so we have to look up
871e5ec1e72Spatrick  * the memory for the ID.  This simply looks for an empty slot.
872e5ec1e72Spatrick  */
873e5ec1e72Spatrick int
87402ee7d07Spatrick bwfm_pci_pktid_avail(struct bwfm_pci_softc *sc, struct bwfm_pci_pkts *pkts)
87502ee7d07Spatrick {
87602ee7d07Spatrick 	int i, idx;
87702ee7d07Spatrick 
87802ee7d07Spatrick 	idx = pkts->last + 1;
87902ee7d07Spatrick 	for (i = 0; i < pkts->npkt; i++) {
88002ee7d07Spatrick 		if (idx == pkts->npkt)
88102ee7d07Spatrick 			idx = 0;
88202ee7d07Spatrick 		if (pkts->pkts[idx].bb_m == NULL)
88302ee7d07Spatrick 			return 0;
88402ee7d07Spatrick 		idx++;
88502ee7d07Spatrick 	}
88602ee7d07Spatrick 	return ENOBUFS;
88702ee7d07Spatrick }
88802ee7d07Spatrick 
88902ee7d07Spatrick int
890e5ec1e72Spatrick bwfm_pci_pktid_new(struct bwfm_pci_softc *sc, struct bwfm_pci_pkts *pkts,
891e5ec1e72Spatrick     struct mbuf *m, uint32_t *pktid, paddr_t *paddr)
892e5ec1e72Spatrick {
893e5ec1e72Spatrick 	int i, idx;
894e5ec1e72Spatrick 
895e5ec1e72Spatrick 	idx = pkts->last + 1;
896e5ec1e72Spatrick 	for (i = 0; i < pkts->npkt; i++) {
897e5ec1e72Spatrick 		if (idx == pkts->npkt)
898e5ec1e72Spatrick 			idx = 0;
899e5ec1e72Spatrick 		if (pkts->pkts[idx].bb_m == NULL) {
900e5ec1e72Spatrick 			if (bus_dmamap_load_mbuf(sc->sc_dmat,
901e5ec1e72Spatrick 			    pkts->pkts[idx].bb_map, m, BUS_DMA_NOWAIT) != 0) {
902518be5f3Spatrick 				if (m_defrag(m, M_DONTWAIT))
903518be5f3Spatrick 					return EFBIG;
904518be5f3Spatrick 				if (bus_dmamap_load_mbuf(sc->sc_dmat,
905518be5f3Spatrick 				    pkts->pkts[idx].bb_map, m, BUS_DMA_NOWAIT) != 0)
906518be5f3Spatrick 					return EFBIG;
907e5ec1e72Spatrick 			}
908dcb67343Spatrick 			bus_dmamap_sync(sc->sc_dmat, pkts->pkts[idx].bb_map,
909dcb67343Spatrick 			    0, pkts->pkts[idx].bb_map->dm_mapsize,
910dcb67343Spatrick 			    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
911e5ec1e72Spatrick 			pkts->last = idx;
912e5ec1e72Spatrick 			pkts->pkts[idx].bb_m = m;
913e5ec1e72Spatrick 			*pktid = idx;
914e5ec1e72Spatrick 			*paddr = pkts->pkts[idx].bb_map->dm_segs[0].ds_addr;
915e5ec1e72Spatrick 			return 0;
916e5ec1e72Spatrick 		}
917e5ec1e72Spatrick 		idx++;
918e5ec1e72Spatrick 	}
919518be5f3Spatrick 	return ENOBUFS;
920e5ec1e72Spatrick }
921e5ec1e72Spatrick 
922e5ec1e72Spatrick struct mbuf *
923e5ec1e72Spatrick bwfm_pci_pktid_free(struct bwfm_pci_softc *sc, struct bwfm_pci_pkts *pkts,
924e5ec1e72Spatrick     uint32_t pktid)
925e5ec1e72Spatrick {
926e5ec1e72Spatrick 	struct mbuf *m;
927e5ec1e72Spatrick 
928e5ec1e72Spatrick 	if (pktid >= pkts->npkt || pkts->pkts[pktid].bb_m == NULL)
929e5ec1e72Spatrick 		return NULL;
930dcb67343Spatrick 	bus_dmamap_sync(sc->sc_dmat, pkts->pkts[pktid].bb_map, 0,
931dcb67343Spatrick 	    pkts->pkts[pktid].bb_map->dm_mapsize,
932dcb67343Spatrick 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
933e5ec1e72Spatrick 	bus_dmamap_unload(sc->sc_dmat, pkts->pkts[pktid].bb_map);
934e5ec1e72Spatrick 	m = pkts->pkts[pktid].bb_m;
935e5ec1e72Spatrick 	pkts->pkts[pktid].bb_m = NULL;
936e5ec1e72Spatrick 	return m;
937e5ec1e72Spatrick }
938e5ec1e72Spatrick 
939e5ec1e72Spatrick void
940e5ec1e72Spatrick bwfm_pci_fill_rx_rings(struct bwfm_pci_softc *sc)
941e5ec1e72Spatrick {
94218722113Spatrick 	bwfm_pci_fill_rx_buf_ring(sc);
943e5ec1e72Spatrick 	bwfm_pci_fill_rx_ioctl_ring(sc, &sc->sc_ioctl_ring,
944e5ec1e72Spatrick 	    MSGBUF_TYPE_IOCTLRESP_BUF_POST);
945e5ec1e72Spatrick 	bwfm_pci_fill_rx_ioctl_ring(sc, &sc->sc_event_ring,
946e5ec1e72Spatrick 	    MSGBUF_TYPE_EVENT_BUF_POST);
947e5ec1e72Spatrick }
948e5ec1e72Spatrick 
949e5ec1e72Spatrick void
950e5ec1e72Spatrick bwfm_pci_fill_rx_ioctl_ring(struct bwfm_pci_softc *sc, struct if_rxring *rxring,
951e5ec1e72Spatrick     uint32_t msgtype)
952e5ec1e72Spatrick {
953e5ec1e72Spatrick 	struct msgbuf_rx_ioctl_resp_or_event *req;
954e5ec1e72Spatrick 	struct mbuf *m;
955e5ec1e72Spatrick 	uint32_t pktid;
956e5ec1e72Spatrick 	paddr_t paddr;
957e5ec1e72Spatrick 	int s, slots;
958e5ec1e72Spatrick 
959e5ec1e72Spatrick 	s = splnet();
960e5ec1e72Spatrick 	for (slots = if_rxr_get(rxring, 8); slots > 0; slots--) {
96102ee7d07Spatrick 		if (bwfm_pci_pktid_avail(sc, &sc->sc_rx_pkts))
96202ee7d07Spatrick 			break;
963e5ec1e72Spatrick 		req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit);
964e5ec1e72Spatrick 		if (req == NULL)
965e5ec1e72Spatrick 			break;
966e5ec1e72Spatrick 		m = MCLGETI(NULL, M_DONTWAIT, NULL, MSGBUF_MAX_PKT_SIZE);
967e5ec1e72Spatrick 		if (m == NULL) {
968e5ec1e72Spatrick 			bwfm_pci_ring_write_cancel(sc, &sc->sc_ctrl_submit, 1);
969e5ec1e72Spatrick 			break;
970e5ec1e72Spatrick 		}
971e5ec1e72Spatrick 		m->m_len = m->m_pkthdr.len = MSGBUF_MAX_PKT_SIZE;
972e5ec1e72Spatrick 		if (bwfm_pci_pktid_new(sc, &sc->sc_rx_pkts, m, &pktid, &paddr)) {
973e5ec1e72Spatrick 			bwfm_pci_ring_write_cancel(sc, &sc->sc_ctrl_submit, 1);
974e5ec1e72Spatrick 			m_freem(m);
975e5ec1e72Spatrick 			break;
976e5ec1e72Spatrick 		}
977e5ec1e72Spatrick 		memset(req, 0, sizeof(*req));
978e5ec1e72Spatrick 		req->msg.msgtype = msgtype;
979e5ec1e72Spatrick 		req->msg.request_id = htole32(pktid);
980e5ec1e72Spatrick 		req->host_buf_len = htole16(MSGBUF_MAX_PKT_SIZE);
981e4dae658Spatrick 		req->host_buf_addr.high_addr = htole32((uint64_t)paddr >> 32);
982e5ec1e72Spatrick 		req->host_buf_addr.low_addr = htole32(paddr & 0xffffffff);
983e5ec1e72Spatrick 		bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit);
984e5ec1e72Spatrick 	}
985e5ec1e72Spatrick 	if_rxr_put(rxring, slots);
986e5ec1e72Spatrick 	splx(s);
987e5ec1e72Spatrick }
988e5ec1e72Spatrick 
989e5ec1e72Spatrick void
990e5ec1e72Spatrick bwfm_pci_fill_rx_buf_ring(struct bwfm_pci_softc *sc)
991e5ec1e72Spatrick {
992e5ec1e72Spatrick 	struct msgbuf_rx_bufpost *req;
993e5ec1e72Spatrick 	struct mbuf *m;
994e5ec1e72Spatrick 	uint32_t pktid;
995e5ec1e72Spatrick 	paddr_t paddr;
996e5ec1e72Spatrick 	int s, slots;
997e5ec1e72Spatrick 
998e5ec1e72Spatrick 	s = splnet();
999e5ec1e72Spatrick 	for (slots = if_rxr_get(&sc->sc_rxbuf_ring, sc->sc_max_rxbufpost);
1000e5ec1e72Spatrick 	    slots > 0; slots--) {
100102ee7d07Spatrick 		if (bwfm_pci_pktid_avail(sc, &sc->sc_rx_pkts))
100202ee7d07Spatrick 			break;
1003e5ec1e72Spatrick 		req = bwfm_pci_ring_write_reserve(sc, &sc->sc_rxpost_submit);
1004e5ec1e72Spatrick 		if (req == NULL)
1005e5ec1e72Spatrick 			break;
1006e5ec1e72Spatrick 		m = MCLGETI(NULL, M_DONTWAIT, NULL, MSGBUF_MAX_PKT_SIZE);
1007e5ec1e72Spatrick 		if (m == NULL) {
1008e5ec1e72Spatrick 			bwfm_pci_ring_write_cancel(sc, &sc->sc_rxpost_submit, 1);
1009e5ec1e72Spatrick 			break;
1010e5ec1e72Spatrick 		}
1011e5ec1e72Spatrick 		m->m_len = m->m_pkthdr.len = MSGBUF_MAX_PKT_SIZE;
1012e5ec1e72Spatrick 		if (bwfm_pci_pktid_new(sc, &sc->sc_rx_pkts, m, &pktid, &paddr)) {
1013e5ec1e72Spatrick 			bwfm_pci_ring_write_cancel(sc, &sc->sc_rxpost_submit, 1);
1014e5ec1e72Spatrick 			m_freem(m);
1015e5ec1e72Spatrick 			break;
1016e5ec1e72Spatrick 		}
1017e5ec1e72Spatrick 		memset(req, 0, sizeof(*req));
1018e5ec1e72Spatrick 		req->msg.msgtype = MSGBUF_TYPE_RXBUF_POST;
1019e5ec1e72Spatrick 		req->msg.request_id = htole32(pktid);
1020e5ec1e72Spatrick 		req->data_buf_len = htole16(MSGBUF_MAX_PKT_SIZE);
1021e4dae658Spatrick 		req->data_buf_addr.high_addr = htole32((uint64_t)paddr >> 32);
1022e5ec1e72Spatrick 		req->data_buf_addr.low_addr = htole32(paddr & 0xffffffff);
1023e5ec1e72Spatrick 		bwfm_pci_ring_write_commit(sc, &sc->sc_rxpost_submit);
1024e5ec1e72Spatrick 	}
1025e5ec1e72Spatrick 	if_rxr_put(&sc->sc_rxbuf_ring, slots);
1026e5ec1e72Spatrick 	splx(s);
1027e5ec1e72Spatrick }
1028e5ec1e72Spatrick 
1029e5ec1e72Spatrick int
1030e5ec1e72Spatrick bwfm_pci_setup_ring(struct bwfm_pci_softc *sc, struct bwfm_pci_msgring *ring,
1031e5ec1e72Spatrick     int nitem, size_t itemsz, uint32_t w_idx, uint32_t r_idx,
1032e5ec1e72Spatrick     int idx, uint32_t idx_off, uint32_t *ring_mem)
1033e5ec1e72Spatrick {
1034e5ec1e72Spatrick 	ring->w_idx_addr = w_idx + idx * idx_off;
1035e5ec1e72Spatrick 	ring->r_idx_addr = r_idx + idx * idx_off;
1036e5ec1e72Spatrick 	ring->nitem = nitem;
1037e5ec1e72Spatrick 	ring->itemsz = itemsz;
1038e5ec1e72Spatrick 	bwfm_pci_ring_write_rptr(sc, ring);
1039e5ec1e72Spatrick 	bwfm_pci_ring_write_wptr(sc, ring);
1040e5ec1e72Spatrick 
1041e5ec1e72Spatrick 	ring->ring = bwfm_pci_dmamem_alloc(sc, nitem * itemsz, 8);
1042e5ec1e72Spatrick 	if (ring->ring == NULL)
1043e5ec1e72Spatrick 		return ENOMEM;
1044e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1045e5ec1e72Spatrick 	    *ring_mem + BWFM_RING_MEM_BASE_ADDR_LOW,
1046e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(ring->ring) & 0xffffffff);
1047e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1048e5ec1e72Spatrick 	    *ring_mem + BWFM_RING_MEM_BASE_ADDR_HIGH,
1049e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(ring->ring) >> 32);
1050e5ec1e72Spatrick 	bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1051e5ec1e72Spatrick 	    *ring_mem + BWFM_RING_MAX_ITEM, nitem);
1052e5ec1e72Spatrick 	bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1053e5ec1e72Spatrick 	    *ring_mem + BWFM_RING_LEN_ITEMS, itemsz);
1054e5ec1e72Spatrick 	*ring_mem = *ring_mem + BWFM_RING_MEM_SZ;
1055e5ec1e72Spatrick 	return 0;
1056e5ec1e72Spatrick }
1057e5ec1e72Spatrick 
1058518be5f3Spatrick int
1059518be5f3Spatrick bwfm_pci_setup_flowring(struct bwfm_pci_softc *sc, struct bwfm_pci_msgring *ring,
1060518be5f3Spatrick     int nitem, size_t itemsz)
1061518be5f3Spatrick {
1062518be5f3Spatrick 	ring->w_ptr = 0;
1063518be5f3Spatrick 	ring->r_ptr = 0;
1064518be5f3Spatrick 	ring->nitem = nitem;
1065518be5f3Spatrick 	ring->itemsz = itemsz;
1066518be5f3Spatrick 	bwfm_pci_ring_write_rptr(sc, ring);
1067518be5f3Spatrick 	bwfm_pci_ring_write_wptr(sc, ring);
1068518be5f3Spatrick 
1069518be5f3Spatrick 	ring->ring = bwfm_pci_dmamem_alloc(sc, nitem * itemsz, 8);
1070518be5f3Spatrick 	if (ring->ring == NULL)
1071518be5f3Spatrick 		return ENOMEM;
1072518be5f3Spatrick 	return 0;
1073518be5f3Spatrick }
1074518be5f3Spatrick 
1075e5ec1e72Spatrick /* Ring helpers */
1076e5ec1e72Spatrick void
1077e5ec1e72Spatrick bwfm_pci_ring_bell(struct bwfm_pci_softc *sc,
1078e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1079e5ec1e72Spatrick {
1080e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1081e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_H2D_MAILBOX, 1);
1082e5ec1e72Spatrick }
1083e5ec1e72Spatrick 
1084e5ec1e72Spatrick void
1085e5ec1e72Spatrick bwfm_pci_ring_update_rptr(struct bwfm_pci_softc *sc,
1086e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1087e5ec1e72Spatrick {
1088e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
1089e5ec1e72Spatrick 		ring->r_ptr = bus_space_read_2(sc->sc_tcm_iot,
1090e5ec1e72Spatrick 		    sc->sc_tcm_ioh, ring->r_idx_addr);
1091e5ec1e72Spatrick 	} else {
1092dcb67343Spatrick 		bus_dmamap_sync(sc->sc_dmat,
1093dcb67343Spatrick 		    BWFM_PCI_DMA_MAP(sc->sc_dma_idx_buf), ring->r_idx_addr,
1094dcb67343Spatrick 		    sizeof(uint16_t), BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1095e5ec1e72Spatrick 		ring->r_ptr = *(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf)
1096e5ec1e72Spatrick 		    + ring->r_idx_addr);
1097e5ec1e72Spatrick 	}
1098e5ec1e72Spatrick }
1099e5ec1e72Spatrick 
1100e5ec1e72Spatrick void
1101e5ec1e72Spatrick bwfm_pci_ring_update_wptr(struct bwfm_pci_softc *sc,
1102e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1103e5ec1e72Spatrick {
1104e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
1105e5ec1e72Spatrick 		ring->w_ptr = bus_space_read_2(sc->sc_tcm_iot,
1106e5ec1e72Spatrick 		    sc->sc_tcm_ioh, ring->w_idx_addr);
1107e5ec1e72Spatrick 	} else {
1108dcb67343Spatrick 		bus_dmamap_sync(sc->sc_dmat,
1109dcb67343Spatrick 		    BWFM_PCI_DMA_MAP(sc->sc_dma_idx_buf), ring->w_idx_addr,
1110dcb67343Spatrick 		    sizeof(uint16_t), BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1111e5ec1e72Spatrick 		ring->w_ptr = *(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf)
1112e5ec1e72Spatrick 		    + ring->w_idx_addr);
1113e5ec1e72Spatrick 	}
1114e5ec1e72Spatrick }
1115e5ec1e72Spatrick 
1116e5ec1e72Spatrick void
1117e5ec1e72Spatrick bwfm_pci_ring_write_rptr(struct bwfm_pci_softc *sc,
1118e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1119e5ec1e72Spatrick {
1120e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
1121e5ec1e72Spatrick 		bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1122e5ec1e72Spatrick 		    ring->r_idx_addr, ring->r_ptr);
1123e5ec1e72Spatrick 	} else {
1124e5ec1e72Spatrick 		*(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf)
1125e5ec1e72Spatrick 		    + ring->r_idx_addr) = ring->r_ptr;
1126dcb67343Spatrick 		bus_dmamap_sync(sc->sc_dmat,
1127dcb67343Spatrick 		    BWFM_PCI_DMA_MAP(sc->sc_dma_idx_buf), ring->r_idx_addr,
1128dcb67343Spatrick 		    sizeof(uint16_t), BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1129e5ec1e72Spatrick 	}
1130e5ec1e72Spatrick }
1131e5ec1e72Spatrick 
1132e5ec1e72Spatrick void
1133e5ec1e72Spatrick bwfm_pci_ring_write_wptr(struct bwfm_pci_softc *sc,
1134e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1135e5ec1e72Spatrick {
1136e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
1137e5ec1e72Spatrick 		bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1138e5ec1e72Spatrick 		    ring->w_idx_addr, ring->w_ptr);
1139e5ec1e72Spatrick 	} else {
1140e5ec1e72Spatrick 		*(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf)
1141e5ec1e72Spatrick 		    + ring->w_idx_addr) = ring->w_ptr;
1142dcb67343Spatrick 		bus_dmamap_sync(sc->sc_dmat,
1143dcb67343Spatrick 		    BWFM_PCI_DMA_MAP(sc->sc_dma_idx_buf), ring->w_idx_addr,
1144dcb67343Spatrick 		    sizeof(uint16_t), BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1145e5ec1e72Spatrick 	}
1146e5ec1e72Spatrick }
1147e5ec1e72Spatrick 
1148e5ec1e72Spatrick /*
1149e5ec1e72Spatrick  * Retrieve a free descriptor to put new stuff in, but don't commit
1150e5ec1e72Spatrick  * to it yet so we can rollback later if any error occurs.
1151e5ec1e72Spatrick  */
1152e5ec1e72Spatrick void *
1153e5ec1e72Spatrick bwfm_pci_ring_write_reserve(struct bwfm_pci_softc *sc,
1154e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1155e5ec1e72Spatrick {
1156e5ec1e72Spatrick 	int available;
1157e5ec1e72Spatrick 	char *ret;
1158e5ec1e72Spatrick 
1159e5ec1e72Spatrick 	bwfm_pci_ring_update_rptr(sc, ring);
1160e5ec1e72Spatrick 
1161e5ec1e72Spatrick 	if (ring->r_ptr > ring->w_ptr)
1162e5ec1e72Spatrick 		available = ring->r_ptr - ring->w_ptr;
1163e5ec1e72Spatrick 	else
1164e5ec1e72Spatrick 		available = ring->r_ptr + (ring->nitem - ring->w_ptr);
1165e5ec1e72Spatrick 
116630f5ada0Spatrick 	if (available <= 1)
1167e5ec1e72Spatrick 		return NULL;
1168e5ec1e72Spatrick 
1169e5ec1e72Spatrick 	ret = BWFM_PCI_DMA_KVA(ring->ring) + (ring->w_ptr * ring->itemsz);
1170e5ec1e72Spatrick 	ring->w_ptr += 1;
1171e5ec1e72Spatrick 	if (ring->w_ptr == ring->nitem)
1172e5ec1e72Spatrick 		ring->w_ptr = 0;
1173e5ec1e72Spatrick 	return ret;
1174e5ec1e72Spatrick }
1175e5ec1e72Spatrick 
1176e5ec1e72Spatrick void *
1177e5ec1e72Spatrick bwfm_pci_ring_write_reserve_multi(struct bwfm_pci_softc *sc,
1178e5ec1e72Spatrick     struct bwfm_pci_msgring *ring, int count, int *avail)
1179e5ec1e72Spatrick {
1180e5ec1e72Spatrick 	int available;
1181e5ec1e72Spatrick 	char *ret;
1182e5ec1e72Spatrick 
1183e5ec1e72Spatrick 	bwfm_pci_ring_update_rptr(sc, ring);
1184e5ec1e72Spatrick 
1185e5ec1e72Spatrick 	if (ring->r_ptr > ring->w_ptr)
1186e5ec1e72Spatrick 		available = ring->r_ptr - ring->w_ptr;
1187e5ec1e72Spatrick 	else
1188e5ec1e72Spatrick 		available = ring->r_ptr + (ring->nitem - ring->w_ptr);
1189e5ec1e72Spatrick 
119030f5ada0Spatrick 	if (available <= 1)
1191e5ec1e72Spatrick 		return NULL;
1192e5ec1e72Spatrick 
1193e5ec1e72Spatrick 	ret = BWFM_PCI_DMA_KVA(ring->ring) + (ring->w_ptr * ring->itemsz);
1194e5ec1e72Spatrick 	*avail = min(count, available - 1);
1195e5ec1e72Spatrick 	if (*avail + ring->w_ptr > ring->nitem)
1196e5ec1e72Spatrick 		*avail = ring->nitem - ring->w_ptr;
1197e5ec1e72Spatrick 	ring->w_ptr += *avail;
1198e5ec1e72Spatrick 	if (ring->w_ptr == ring->nitem)
1199e5ec1e72Spatrick 		ring->w_ptr = 0;
1200e5ec1e72Spatrick 	return ret;
1201e5ec1e72Spatrick }
1202e5ec1e72Spatrick 
1203e5ec1e72Spatrick /*
1204e5ec1e72Spatrick  * Read number of descriptors available (submitted by the firmware)
1205e5ec1e72Spatrick  * and retrieve pointer to first descriptor.
1206e5ec1e72Spatrick  */
1207e5ec1e72Spatrick void *
1208e5ec1e72Spatrick bwfm_pci_ring_read_avail(struct bwfm_pci_softc *sc,
1209e5ec1e72Spatrick     struct bwfm_pci_msgring *ring, int *avail)
1210e5ec1e72Spatrick {
1211e5ec1e72Spatrick 	bwfm_pci_ring_update_wptr(sc, ring);
1212e5ec1e72Spatrick 
1213e5ec1e72Spatrick 	if (ring->w_ptr >= ring->r_ptr)
1214e5ec1e72Spatrick 		*avail = ring->w_ptr - ring->r_ptr;
1215e5ec1e72Spatrick 	else
1216e5ec1e72Spatrick 		*avail = ring->nitem - ring->r_ptr;
1217e5ec1e72Spatrick 
1218e5ec1e72Spatrick 	if (*avail == 0)
1219e5ec1e72Spatrick 		return NULL;
1220e5ec1e72Spatrick 
1221dcb67343Spatrick 	bus_dmamap_sync(sc->sc_dmat, BWFM_PCI_DMA_MAP(ring->ring),
1222dcb67343Spatrick 	    ring->r_ptr * ring->itemsz, *avail * ring->itemsz,
1223dcb67343Spatrick 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1224e5ec1e72Spatrick 	return BWFM_PCI_DMA_KVA(ring->ring) + (ring->r_ptr * ring->itemsz);
1225e5ec1e72Spatrick }
1226e5ec1e72Spatrick 
1227e5ec1e72Spatrick /*
1228e5ec1e72Spatrick  * Let firmware know we read N descriptors.
1229e5ec1e72Spatrick  */
1230e5ec1e72Spatrick void
1231e5ec1e72Spatrick bwfm_pci_ring_read_commit(struct bwfm_pci_softc *sc,
1232e5ec1e72Spatrick     struct bwfm_pci_msgring *ring, int nitem)
1233e5ec1e72Spatrick {
1234e5ec1e72Spatrick 	ring->r_ptr += nitem;
1235e5ec1e72Spatrick 	if (ring->r_ptr == ring->nitem)
1236e5ec1e72Spatrick 		ring->r_ptr = 0;
1237e5ec1e72Spatrick 	bwfm_pci_ring_write_rptr(sc, ring);
1238e5ec1e72Spatrick }
1239e5ec1e72Spatrick 
1240e5ec1e72Spatrick /*
1241e5ec1e72Spatrick  * Let firmware know that we submitted some descriptors.
1242e5ec1e72Spatrick  */
1243e5ec1e72Spatrick void
1244e5ec1e72Spatrick bwfm_pci_ring_write_commit(struct bwfm_pci_softc *sc,
1245e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1246e5ec1e72Spatrick {
1247dcb67343Spatrick 	bus_dmamap_sync(sc->sc_dmat, BWFM_PCI_DMA_MAP(ring->ring),
1248dcb67343Spatrick 	    0, BWFM_PCI_DMA_LEN(ring->ring), BUS_DMASYNC_PREREAD |
1249dcb67343Spatrick 	    BUS_DMASYNC_PREWRITE);
1250e5ec1e72Spatrick 	bwfm_pci_ring_write_wptr(sc, ring);
1251e5ec1e72Spatrick 	bwfm_pci_ring_bell(sc, ring);
1252e5ec1e72Spatrick }
1253e5ec1e72Spatrick 
1254e5ec1e72Spatrick /*
1255e5ec1e72Spatrick  * Rollback N descriptors in case we don't actually want
1256e5ec1e72Spatrick  * to commit to it.
1257e5ec1e72Spatrick  */
1258e5ec1e72Spatrick void
1259e5ec1e72Spatrick bwfm_pci_ring_write_cancel(struct bwfm_pci_softc *sc,
1260e5ec1e72Spatrick     struct bwfm_pci_msgring *ring, int nitem)
1261e5ec1e72Spatrick {
1262e5ec1e72Spatrick 	if (ring->w_ptr == 0)
1263e5ec1e72Spatrick 		ring->w_ptr = ring->nitem - nitem;
1264e5ec1e72Spatrick 	else
1265e5ec1e72Spatrick 		ring->w_ptr -= nitem;
1266e5ec1e72Spatrick }
1267e5ec1e72Spatrick 
1268e5ec1e72Spatrick /*
1269e5ec1e72Spatrick  * Foreach written descriptor on the ring, pass the descriptor to
1270e5ec1e72Spatrick  * a message handler and let the firmware know we handled it.
1271e5ec1e72Spatrick  */
1272e5ec1e72Spatrick void
12736f241297Spatrick bwfm_pci_ring_rx(struct bwfm_pci_softc *sc, struct bwfm_pci_msgring *ring,
12746f241297Spatrick     struct mbuf_list *ml)
1275e5ec1e72Spatrick {
1276e5ec1e72Spatrick 	void *buf;
1277e5ec1e72Spatrick 	int avail, processed;
1278e5ec1e72Spatrick 
1279e5ec1e72Spatrick again:
1280e5ec1e72Spatrick 	buf = bwfm_pci_ring_read_avail(sc, ring, &avail);
1281e5ec1e72Spatrick 	if (buf == NULL)
1282e5ec1e72Spatrick 		return;
1283e5ec1e72Spatrick 
1284e5ec1e72Spatrick 	processed = 0;
1285e5ec1e72Spatrick 	while (avail) {
12866f241297Spatrick 		bwfm_pci_msg_rx(sc, buf + sc->sc_rx_dataoffset, ml);
1287e5ec1e72Spatrick 		buf += ring->itemsz;
1288e5ec1e72Spatrick 		processed++;
1289e5ec1e72Spatrick 		if (processed == 48) {
1290e5ec1e72Spatrick 			bwfm_pci_ring_read_commit(sc, ring, processed);
1291e5ec1e72Spatrick 			processed = 0;
1292e5ec1e72Spatrick 		}
1293e5ec1e72Spatrick 		avail--;
1294e5ec1e72Spatrick 	}
1295e5ec1e72Spatrick 	if (processed)
1296e5ec1e72Spatrick 		bwfm_pci_ring_read_commit(sc, ring, processed);
1297e5ec1e72Spatrick 	if (ring->r_ptr == 0)
1298e5ec1e72Spatrick 		goto again;
1299e5ec1e72Spatrick }
1300e5ec1e72Spatrick 
1301e5ec1e72Spatrick void
13026f241297Spatrick bwfm_pci_msg_rx(struct bwfm_pci_softc *sc, void *buf, struct mbuf_list *ml)
1303e5ec1e72Spatrick {
1304518be5f3Spatrick 	struct ifnet *ifp = &sc->sc_sc.sc_ic.ic_if;
1305e5ec1e72Spatrick 	struct msgbuf_ioctl_resp_hdr *resp;
1306518be5f3Spatrick 	struct msgbuf_tx_status *tx;
130718722113Spatrick 	struct msgbuf_rx_complete *rx;
1308e5ec1e72Spatrick 	struct msgbuf_rx_event *event;
1309e5ec1e72Spatrick 	struct msgbuf_common_hdr *msg;
1310518be5f3Spatrick 	struct msgbuf_flowring_create_resp *fcr;
1311a2c6ff8bSpatrick 	struct msgbuf_flowring_delete_resp *fdr;
1312518be5f3Spatrick 	struct bwfm_pci_msgring *ring;
1313e5ec1e72Spatrick 	struct mbuf *m;
1314518be5f3Spatrick 	int flowid;
1315e5ec1e72Spatrick 
1316e5ec1e72Spatrick 	msg = (struct msgbuf_common_hdr *)buf;
1317e5ec1e72Spatrick 	switch (msg->msgtype)
1318e5ec1e72Spatrick 	{
1319518be5f3Spatrick 	case MSGBUF_TYPE_FLOW_RING_CREATE_CMPLT:
1320518be5f3Spatrick 		fcr = (struct msgbuf_flowring_create_resp *)buf;
1321518be5f3Spatrick 		flowid = letoh16(fcr->compl_hdr.flow_ring_id);
1322518be5f3Spatrick 		if (flowid < 2)
1323518be5f3Spatrick 			break;
1324518be5f3Spatrick 		flowid -= 2;
1325518be5f3Spatrick 		if (flowid >= sc->sc_max_flowrings)
1326518be5f3Spatrick 			break;
1327518be5f3Spatrick 		ring = &sc->sc_flowrings[flowid];
1328518be5f3Spatrick 		if (ring->status != RING_OPENING)
1329518be5f3Spatrick 			break;
1330518be5f3Spatrick 		if (fcr->compl_hdr.status) {
1331518be5f3Spatrick 			printf("%s: failed to open flowring %d\n",
1332518be5f3Spatrick 			    DEVNAME(sc), flowid);
1333518be5f3Spatrick 			ring->status = RING_CLOSED;
133402ee7d07Spatrick 			if (ring->m) {
133502ee7d07Spatrick 				m_freem(ring->m);
133602ee7d07Spatrick 				ring->m = NULL;
133702ee7d07Spatrick 			}
1338518be5f3Spatrick 			ifq_restart(&ifp->if_snd);
1339518be5f3Spatrick 			break;
1340518be5f3Spatrick 		}
1341518be5f3Spatrick 		ring->status = RING_OPEN;
134202ee7d07Spatrick 		if (ring->m != NULL) {
134302ee7d07Spatrick 			m = ring->m;
134402ee7d07Spatrick 			ring->m = NULL;
134502ee7d07Spatrick 			if (bwfm_pci_txdata(&sc->sc_sc, m))
134602ee7d07Spatrick 				m_freem(ring->m);
134702ee7d07Spatrick 		}
1348518be5f3Spatrick 		ifq_restart(&ifp->if_snd);
1349518be5f3Spatrick 		break;
1350a2c6ff8bSpatrick 	case MSGBUF_TYPE_FLOW_RING_DELETE_CMPLT:
1351a2c6ff8bSpatrick 		fdr = (struct msgbuf_flowring_delete_resp *)buf;
1352a2c6ff8bSpatrick 		flowid = letoh16(fdr->compl_hdr.flow_ring_id);
1353a2c6ff8bSpatrick 		if (flowid < 2)
1354a2c6ff8bSpatrick 			break;
1355a2c6ff8bSpatrick 		flowid -= 2;
1356a2c6ff8bSpatrick 		if (flowid >= sc->sc_max_flowrings)
1357a2c6ff8bSpatrick 			break;
1358a2c6ff8bSpatrick 		ring = &sc->sc_flowrings[flowid];
1359a2c6ff8bSpatrick 		if (ring->status != RING_CLOSING)
1360a2c6ff8bSpatrick 			break;
1361a2c6ff8bSpatrick 		if (fdr->compl_hdr.status) {
1362a2c6ff8bSpatrick 			printf("%s: failed to delete flowring %d\n",
1363a2c6ff8bSpatrick 			    DEVNAME(sc), flowid);
1364a2c6ff8bSpatrick 			break;
1365a2c6ff8bSpatrick 		}
1366a2c6ff8bSpatrick 		bwfm_pci_dmamem_free(sc, ring->ring);
1367a2c6ff8bSpatrick 		ring->status = RING_CLOSED;
1368a2c6ff8bSpatrick 		break;
1369e5ec1e72Spatrick 	case MSGBUF_TYPE_IOCTLPTR_REQ_ACK:
13702eeba925Spatrick 		m = bwfm_pci_pktid_free(sc, &sc->sc_ioctl_pkts,
13712eeba925Spatrick 		    letoh32(msg->request_id));
13722eeba925Spatrick 		if (m == NULL)
13732eeba925Spatrick 			break;
13742eeba925Spatrick 		m_freem(m);
1375e5ec1e72Spatrick 		break;
1376e5ec1e72Spatrick 	case MSGBUF_TYPE_IOCTL_CMPLT:
1377e5ec1e72Spatrick 		resp = (struct msgbuf_ioctl_resp_hdr *)buf;
13782eeba925Spatrick 		bwfm_pci_msgbuf_rxioctl(sc, resp);
1379e5ec1e72Spatrick 		if_rxr_put(&sc->sc_ioctl_ring, 1);
1380e5ec1e72Spatrick 		bwfm_pci_fill_rx_rings(sc);
1381e5ec1e72Spatrick 		break;
1382e5ec1e72Spatrick 	case MSGBUF_TYPE_WL_EVENT:
1383e5ec1e72Spatrick 		event = (struct msgbuf_rx_event *)buf;
1384e5ec1e72Spatrick 		m = bwfm_pci_pktid_free(sc, &sc->sc_rx_pkts,
1385e5ec1e72Spatrick 		    letoh32(event->msg.request_id));
1386e5ec1e72Spatrick 		if (m == NULL)
1387e5ec1e72Spatrick 			break;
1388e5ec1e72Spatrick 		m_adj(m, sc->sc_rx_dataoffset);
1389f37fc236Spatrick 		m->m_len = m->m_pkthdr.len = letoh16(event->event_data_len);
13906f241297Spatrick 		bwfm_rx(&sc->sc_sc, m, ml);
1391e5ec1e72Spatrick 		if_rxr_put(&sc->sc_event_ring, 1);
1392e5ec1e72Spatrick 		bwfm_pci_fill_rx_rings(sc);
1393e5ec1e72Spatrick 		break;
1394518be5f3Spatrick 	case MSGBUF_TYPE_TX_STATUS:
1395518be5f3Spatrick 		tx = (struct msgbuf_tx_status *)buf;
1396518be5f3Spatrick 		m = bwfm_pci_pktid_free(sc, &sc->sc_tx_pkts,
1397f9ee104fSpatrick 		    letoh32(tx->msg.request_id) - 1);
1398518be5f3Spatrick 		if (m == NULL)
1399518be5f3Spatrick 			break;
1400518be5f3Spatrick 		m_freem(m);
1401c6f1636dSpatrick 		if (sc->sc_tx_pkts_full) {
1402c6f1636dSpatrick 			sc->sc_tx_pkts_full = 0;
1403c6f1636dSpatrick 			ifq_restart(&ifp->if_snd);
1404c6f1636dSpatrick 		}
1405518be5f3Spatrick 		break;
140618722113Spatrick 	case MSGBUF_TYPE_RX_CMPLT:
140718722113Spatrick 		rx = (struct msgbuf_rx_complete *)buf;
140818722113Spatrick 		m = bwfm_pci_pktid_free(sc, &sc->sc_rx_pkts,
140918722113Spatrick 		    letoh32(rx->msg.request_id));
141018722113Spatrick 		if (m == NULL)
141118722113Spatrick 			break;
141218722113Spatrick 		if (letoh16(rx->data_offset))
141318722113Spatrick 			m_adj(m, letoh16(rx->data_offset));
141418722113Spatrick 		else if (sc->sc_rx_dataoffset)
141518722113Spatrick 			m_adj(m, sc->sc_rx_dataoffset);
1416f37fc236Spatrick 		m->m_len = m->m_pkthdr.len = letoh16(rx->data_len);
14176f241297Spatrick 		bwfm_rx(&sc->sc_sc, m, ml);
141818722113Spatrick 		if_rxr_put(&sc->sc_rxbuf_ring, 1);
141918722113Spatrick 		bwfm_pci_fill_rx_rings(sc);
142018722113Spatrick 		break;
1421e5ec1e72Spatrick 	default:
1422e5ec1e72Spatrick 		printf("%s: msgtype 0x%08x\n", __func__, msg->msgtype);
1423e5ec1e72Spatrick 		break;
1424e5ec1e72Spatrick 	}
1425e5ec1e72Spatrick }
1426e5ec1e72Spatrick 
1427e5ec1e72Spatrick /* Bus core helpers */
1428e5ec1e72Spatrick void
1429e5ec1e72Spatrick bwfm_pci_select_core(struct bwfm_pci_softc *sc, int id)
1430e5ec1e72Spatrick {
1431e5ec1e72Spatrick 	struct bwfm_softc *bwfm = (void *)sc;
1432e5ec1e72Spatrick 	struct bwfm_core *core;
1433e5ec1e72Spatrick 
1434e5ec1e72Spatrick 	core = bwfm_chip_get_core(bwfm, id);
1435e5ec1e72Spatrick 	if (core == NULL) {
1436e5ec1e72Spatrick 		printf("%s: could not find core to select", DEVNAME(sc));
1437e5ec1e72Spatrick 		return;
1438e5ec1e72Spatrick 	}
1439e5ec1e72Spatrick 
1440e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag,
1441e5ec1e72Spatrick 	    BWFM_PCI_BAR0_WINDOW, core->co_base);
1442e5ec1e72Spatrick 	if (pci_conf_read(sc->sc_pc, sc->sc_tag,
1443e5ec1e72Spatrick 	    BWFM_PCI_BAR0_WINDOW) != core->co_base)
1444e5ec1e72Spatrick 		pci_conf_write(sc->sc_pc, sc->sc_tag,
1445e5ec1e72Spatrick 		    BWFM_PCI_BAR0_WINDOW, core->co_base);
1446e5ec1e72Spatrick }
1447e5ec1e72Spatrick 
1448e5ec1e72Spatrick uint32_t
1449e5ec1e72Spatrick bwfm_pci_buscore_read(struct bwfm_softc *bwfm, uint32_t reg)
1450e5ec1e72Spatrick {
1451e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1452e5ec1e72Spatrick 	uint32_t page, offset;
1453e5ec1e72Spatrick 
1454e5ec1e72Spatrick 	page = reg & ~(BWFM_PCI_BAR0_REG_SIZE - 1);
1455e5ec1e72Spatrick 	offset = reg & (BWFM_PCI_BAR0_REG_SIZE - 1);
1456e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_BAR0_WINDOW, page);
1457e5ec1e72Spatrick 	return bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh, offset);
1458e5ec1e72Spatrick }
1459e5ec1e72Spatrick 
1460e5ec1e72Spatrick void
1461e5ec1e72Spatrick bwfm_pci_buscore_write(struct bwfm_softc *bwfm, uint32_t reg, uint32_t val)
1462e5ec1e72Spatrick {
1463e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1464e5ec1e72Spatrick 	uint32_t page, offset;
1465e5ec1e72Spatrick 
1466e5ec1e72Spatrick 	page = reg & ~(BWFM_PCI_BAR0_REG_SIZE - 1);
1467e5ec1e72Spatrick 	offset = reg & (BWFM_PCI_BAR0_REG_SIZE - 1);
1468e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_BAR0_WINDOW, page);
1469e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, offset, val);
1470e5ec1e72Spatrick }
1471e5ec1e72Spatrick 
1472e5ec1e72Spatrick int
1473e5ec1e72Spatrick bwfm_pci_buscore_prepare(struct bwfm_softc *bwfm)
1474e5ec1e72Spatrick {
1475e5ec1e72Spatrick 	return 0;
1476e5ec1e72Spatrick }
1477e5ec1e72Spatrick 
1478e5ec1e72Spatrick int
1479e5ec1e72Spatrick bwfm_pci_buscore_reset(struct bwfm_softc *bwfm)
1480e5ec1e72Spatrick {
1481e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1482e5ec1e72Spatrick 	struct bwfm_core *core;
1483e5ec1e72Spatrick 	uint32_t reg;
1484e5ec1e72Spatrick 	int i;
1485e5ec1e72Spatrick 
1486e5ec1e72Spatrick 	bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2);
1487e5ec1e72Spatrick 	reg = pci_conf_read(sc->sc_pc, sc->sc_tag,
1488e5ec1e72Spatrick 	    BWFM_PCI_CFGREG_LINK_STATUS_CTRL);
1489e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_CFGREG_LINK_STATUS_CTRL,
1490e5ec1e72Spatrick 	    reg & ~BWFM_PCI_CFGREG_LINK_STATUS_CTRL_ASPM_ENAB);
1491e5ec1e72Spatrick 
1492e5ec1e72Spatrick 	bwfm_pci_select_core(sc, BWFM_AGENT_CORE_CHIPCOMMON);
1493e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1494e5ec1e72Spatrick 	    BWFM_CHIP_REG_WATCHDOG, 4);
1495e5ec1e72Spatrick 	delay(100 * 1000);
1496e5ec1e72Spatrick 
1497e5ec1e72Spatrick 	bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2);
1498e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag,
1499e5ec1e72Spatrick 	    BWFM_PCI_CFGREG_LINK_STATUS_CTRL, reg);
1500e5ec1e72Spatrick 
1501e5ec1e72Spatrick 	core = bwfm_chip_get_core(bwfm, BWFM_AGENT_CORE_PCIE2);
1502e5ec1e72Spatrick 	if (core->co_rev <= 13) {
1503e5ec1e72Spatrick 		uint16_t cfg_offset[] = {
1504e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_STATUS_CMD,
1505e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_PM_CSR,
1506e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_MSI_CAP,
1507e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_MSI_ADDR_L,
1508e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_MSI_ADDR_H,
1509e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_MSI_DATA,
1510e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_LINK_STATUS_CTRL2,
1511e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_RBAR_CTRL,
1512e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_PML1_SUB_CTRL1,
1513e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_REG_BAR2_CONFIG,
1514e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_REG_BAR3_CONFIG,
1515e5ec1e72Spatrick 		};
1516e5ec1e72Spatrick 
1517e5ec1e72Spatrick 		for (i = 0; i < nitems(cfg_offset); i++) {
1518e5ec1e72Spatrick 			bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1519e5ec1e72Spatrick 			    BWFM_PCI_PCIE2REG_CONFIGADDR, cfg_offset[i]);
1520e5ec1e72Spatrick 			reg = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1521e5ec1e72Spatrick 			    BWFM_PCI_PCIE2REG_CONFIGDATA);
1522e5ec1e72Spatrick 			DPRINTFN(3, ("%s: config offset 0x%04x, value 0x%04x\n",
1523e5ec1e72Spatrick 			    DEVNAME(sc), cfg_offset[i], reg));
1524e5ec1e72Spatrick 			bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1525e5ec1e72Spatrick 			    BWFM_PCI_PCIE2REG_CONFIGDATA, reg);
1526e5ec1e72Spatrick 		}
1527e5ec1e72Spatrick 	}
1528e5ec1e72Spatrick 
1529e5ec1e72Spatrick 	reg = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1530e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXINT);
1531e5ec1e72Spatrick 	if (reg != 0xffffffff)
1532e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1533e5ec1e72Spatrick 		    BWFM_PCI_PCIE2REG_MAILBOXINT, reg);
1534e5ec1e72Spatrick 
1535e5ec1e72Spatrick 	return 0;
1536e5ec1e72Spatrick }
1537e5ec1e72Spatrick 
1538e5ec1e72Spatrick void
1539e5ec1e72Spatrick bwfm_pci_buscore_activate(struct bwfm_softc *bwfm, uint32_t rstvec)
1540e5ec1e72Spatrick {
1541e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1542e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 0, rstvec);
1543e5ec1e72Spatrick }
1544e5ec1e72Spatrick 
1545f67437f3Spatrick static int bwfm_pci_prio2fifo[8] = {
1546f67437f3Spatrick 	1, /* best effort */
1547f67437f3Spatrick 	0, /* IPTOS_PREC_IMMEDIATE */
1548f67437f3Spatrick 	0, /* IPTOS_PREC_PRIORITY */
1549f67437f3Spatrick 	1, /* IPTOS_PREC_FLASH */
1550f67437f3Spatrick 	2, /* IPTOS_PREC_FLASHOVERRIDE */
1551f67437f3Spatrick 	2, /* IPTOS_PREC_CRITIC_ECP */
1552f67437f3Spatrick 	3, /* IPTOS_PREC_INTERNETCONTROL */
1553f67437f3Spatrick 	3, /* IPTOS_PREC_NETCONTROL */
1554f67437f3Spatrick };
1555f67437f3Spatrick 
1556f67437f3Spatrick int
1557f67437f3Spatrick bwfm_pci_flowring_lookup(struct bwfm_pci_softc *sc, struct mbuf *m)
1558518be5f3Spatrick {
1559f67437f3Spatrick 	struct ieee80211com *ic = &sc->sc_sc.sc_ic;
1560e6abcda3Smlarkin #ifndef IEEE80211_STA_ONLY
1561f67437f3Spatrick 	uint8_t *da = mtod(m, uint8_t *);
1562e6abcda3Smlarkin #endif
1563f67437f3Spatrick 	int flowid, prio, fifo;
1564f67437f3Spatrick 	int i, found;
1565f67437f3Spatrick 
1566f67437f3Spatrick 	prio = ieee80211_classify(ic, m);
1567f67437f3Spatrick 	fifo = bwfm_pci_prio2fifo[prio];
1568f67437f3Spatrick 
1569f67437f3Spatrick 	switch (ic->ic_opmode)
1570f67437f3Spatrick 	{
1571f67437f3Spatrick 	case IEEE80211_M_STA:
1572f67437f3Spatrick 		flowid = fifo;
1573f67437f3Spatrick 		break;
1574f67437f3Spatrick #ifndef IEEE80211_STA_ONLY
1575f67437f3Spatrick 	case IEEE80211_M_HOSTAP:
15762b7bea7eSpatrick 		if (ETHER_IS_MULTICAST(da))
15772b7bea7eSpatrick 			da = etherbroadcastaddr;
1578f67437f3Spatrick 		flowid = da[5] * 2 + fifo;
1579f67437f3Spatrick 		break;
1580f67437f3Spatrick #endif
1581f67437f3Spatrick 	default:
1582f67437f3Spatrick 		printf("%s: state not supported\n", DEVNAME(sc));
1583f67437f3Spatrick 		return ENOBUFS;
1584f67437f3Spatrick 	}
1585f67437f3Spatrick 
1586f67437f3Spatrick 	found = 0;
1587f67437f3Spatrick 	flowid = flowid % sc->sc_max_flowrings;
1588f67437f3Spatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
1589f67437f3Spatrick 		if (ic->ic_opmode == IEEE80211_M_STA &&
1590f67437f3Spatrick 		    sc->sc_flowrings[flowid].status >= RING_OPEN &&
1591f67437f3Spatrick 		    sc->sc_flowrings[flowid].fifo == fifo) {
1592f67437f3Spatrick 			found = 1;
1593f67437f3Spatrick 			break;
1594f67437f3Spatrick 		}
1595f67437f3Spatrick #ifndef IEEE80211_STA_ONLY
1596f67437f3Spatrick 		if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
1597f67437f3Spatrick 		    sc->sc_flowrings[flowid].status >= RING_OPEN &&
1598f67437f3Spatrick 		    sc->sc_flowrings[flowid].fifo == fifo &&
1599a2c6ff8bSpatrick 		    !memcmp(sc->sc_flowrings[flowid].mac, da, ETHER_ADDR_LEN)) {
1600f67437f3Spatrick 			found = 1;
1601f67437f3Spatrick 			break;
1602f67437f3Spatrick 		}
1603f67437f3Spatrick #endif
1604f67437f3Spatrick 		flowid = (flowid + 1) % sc->sc_max_flowrings;
1605f67437f3Spatrick 	}
1606f67437f3Spatrick 
1607f67437f3Spatrick 	if (found)
1608f67437f3Spatrick 		return flowid;
1609f67437f3Spatrick 
1610f67437f3Spatrick 	return -1;
1611f67437f3Spatrick }
1612f67437f3Spatrick 
1613f67437f3Spatrick void
1614f67437f3Spatrick bwfm_pci_flowring_create(struct bwfm_pci_softc *sc, struct mbuf *m)
1615f67437f3Spatrick {
1616f67437f3Spatrick 	struct ieee80211com *ic = &sc->sc_sc.sc_ic;
1617518be5f3Spatrick 	struct bwfm_cmd_flowring_create cmd;
1618e6abcda3Smlarkin #ifndef IEEE80211_STA_ONLY
1619f67437f3Spatrick 	uint8_t *da = mtod(m, uint8_t *);
1620e6abcda3Smlarkin #endif
162102ee7d07Spatrick 	struct bwfm_pci_msgring *ring;
1622f67437f3Spatrick 	int flowid, prio, fifo;
1623f67437f3Spatrick 	int i, found;
1624f67437f3Spatrick 
1625f67437f3Spatrick 	prio = ieee80211_classify(ic, m);
1626f67437f3Spatrick 	fifo = bwfm_pci_prio2fifo[prio];
1627f67437f3Spatrick 
1628f67437f3Spatrick 	switch (ic->ic_opmode)
1629f67437f3Spatrick 	{
1630f67437f3Spatrick 	case IEEE80211_M_STA:
1631f67437f3Spatrick 		flowid = fifo;
1632f67437f3Spatrick 		break;
1633f67437f3Spatrick #ifndef IEEE80211_STA_ONLY
1634f67437f3Spatrick 	case IEEE80211_M_HOSTAP:
16352b7bea7eSpatrick 		if (ETHER_IS_MULTICAST(da))
16362b7bea7eSpatrick 			da = etherbroadcastaddr;
1637f67437f3Spatrick 		flowid = da[5] * 2 + fifo;
1638f67437f3Spatrick 		break;
1639f67437f3Spatrick #endif
1640f67437f3Spatrick 	default:
1641f67437f3Spatrick 		printf("%s: state not supported\n", DEVNAME(sc));
1642f67437f3Spatrick 		return;
1643f67437f3Spatrick 	}
1644f67437f3Spatrick 
1645f67437f3Spatrick 	found = 0;
1646f67437f3Spatrick 	flowid = flowid % sc->sc_max_flowrings;
1647f67437f3Spatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
164802ee7d07Spatrick 		ring = &sc->sc_flowrings[flowid];
164902ee7d07Spatrick 		if (ring->status == RING_CLOSED) {
165002ee7d07Spatrick 			ring->status = RING_OPENING;
1651f67437f3Spatrick 			found = 1;
1652f67437f3Spatrick 			break;
1653f67437f3Spatrick 		}
1654f67437f3Spatrick 		flowid = (flowid + 1) % sc->sc_max_flowrings;
1655f67437f3Spatrick 	}
1656f67437f3Spatrick 
165702ee7d07Spatrick 	/*
165802ee7d07Spatrick 	 * We cannot recover from that so far.  Only a stop/init
165902ee7d07Spatrick 	 * cycle can revive this if it ever happens at all.
166002ee7d07Spatrick 	 */
1661f67437f3Spatrick 	if (!found) {
1662f67437f3Spatrick 		printf("%s: no flowring available\n", DEVNAME(sc));
1663f67437f3Spatrick 		return;
1664f67437f3Spatrick 	}
1665f67437f3Spatrick 
166602ee7d07Spatrick 	cmd.m = m;
1667f67437f3Spatrick 	cmd.prio = prio;
1668518be5f3Spatrick 	cmd.flowid = flowid;
1669518be5f3Spatrick 	bwfm_do_async(&sc->sc_sc, bwfm_pci_flowring_create_cb, &cmd, sizeof(cmd));
1670518be5f3Spatrick }
1671518be5f3Spatrick 
1672518be5f3Spatrick void
1673518be5f3Spatrick bwfm_pci_flowring_create_cb(struct bwfm_softc *bwfm, void *arg)
1674518be5f3Spatrick {
1675518be5f3Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1676e6abcda3Smlarkin #ifndef IEEE80211_STA_ONLY
16772b7bea7eSpatrick 	struct ieee80211com *ic = &sc->sc_sc.sc_ic;
1678e6abcda3Smlarkin #endif
1679518be5f3Spatrick 	struct bwfm_cmd_flowring_create *cmd = arg;
1680518be5f3Spatrick 	struct msgbuf_tx_flowring_create_req *req;
1681518be5f3Spatrick 	struct bwfm_pci_msgring *ring;
168202ee7d07Spatrick 	uint8_t *da, *sa;
1683e272db29Spatrick 	int s;
1684518be5f3Spatrick 
168502ee7d07Spatrick 	da = mtod(cmd->m, char *) + 0 * ETHER_ADDR_LEN;
168602ee7d07Spatrick 	sa = mtod(cmd->m, char *) + 1 * ETHER_ADDR_LEN;
1687518be5f3Spatrick 
168802ee7d07Spatrick 	ring = &sc->sc_flowrings[cmd->flowid];
168902ee7d07Spatrick 	if (ring->status != RING_OPENING) {
169002ee7d07Spatrick 		printf("%s: flowring not opening\n", DEVNAME(sc));
1691518be5f3Spatrick 		return;
1692f67437f3Spatrick 	}
1693f67437f3Spatrick 
1694f67437f3Spatrick 	if (bwfm_pci_setup_flowring(sc, ring, 512, 48)) {
1695f67437f3Spatrick 		printf("%s: cannot setup flowring\n", DEVNAME(sc));
1696f67437f3Spatrick 		return;
1697f67437f3Spatrick 	}
1698518be5f3Spatrick 
1699e272db29Spatrick 	s = splnet();
1700518be5f3Spatrick 	req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit);
1701f67437f3Spatrick 	if (req == NULL) {
1702f67437f3Spatrick 		printf("%s: cannot reserve for flowring\n", DEVNAME(sc));
1703e272db29Spatrick 		splx(s);
1704518be5f3Spatrick 		return;
1705f67437f3Spatrick 	}
1706518be5f3Spatrick 
1707518be5f3Spatrick 	ring->status = RING_OPENING;
170802ee7d07Spatrick 	ring->fifo = bwfm_pci_prio2fifo[cmd->prio];
170902ee7d07Spatrick 	ring->m = cmd->m;
171002ee7d07Spatrick 	memcpy(ring->mac, da, ETHER_ADDR_LEN);
17112b7bea7eSpatrick #ifndef IEEE80211_STA_ONLY
171202ee7d07Spatrick 	if (ic->ic_opmode == IEEE80211_M_HOSTAP && ETHER_IS_MULTICAST(da))
17132b7bea7eSpatrick 		memcpy(ring->mac, etherbroadcastaddr, ETHER_ADDR_LEN);
17142b7bea7eSpatrick #endif
1715f67437f3Spatrick 
1716518be5f3Spatrick 	req->msg.msgtype = MSGBUF_TYPE_FLOW_RING_CREATE;
1717518be5f3Spatrick 	req->msg.ifidx = 0;
1718518be5f3Spatrick 	req->msg.request_id = 0;
171902ee7d07Spatrick 	req->tid = bwfm_pci_prio2fifo[cmd->prio];
172002ee7d07Spatrick 	req->flow_ring_id = letoh16(cmd->flowid + 2);
172102ee7d07Spatrick 	memcpy(req->da, da, ETHER_ADDR_LEN);
172202ee7d07Spatrick 	memcpy(req->sa, sa, ETHER_ADDR_LEN);
1723518be5f3Spatrick 	req->flow_ring_addr.high_addr =
1724518be5f3Spatrick 	    letoh32(BWFM_PCI_DMA_DVA(ring->ring) >> 32);
1725518be5f3Spatrick 	req->flow_ring_addr.low_addr =
1726518be5f3Spatrick 	    letoh32(BWFM_PCI_DMA_DVA(ring->ring) & 0xffffffff);
1727518be5f3Spatrick 	req->max_items = letoh16(512);
1728518be5f3Spatrick 	req->len_item = letoh16(48);
1729518be5f3Spatrick 
1730518be5f3Spatrick 	bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit);
1731e272db29Spatrick 	splx(s);
1732518be5f3Spatrick }
1733518be5f3Spatrick 
1734a2c6ff8bSpatrick void
1735a2c6ff8bSpatrick bwfm_pci_flowring_delete(struct bwfm_pci_softc *sc, int flowid)
1736a2c6ff8bSpatrick {
1737a2c6ff8bSpatrick 	struct msgbuf_tx_flowring_delete_req *req;
1738a2c6ff8bSpatrick 	struct bwfm_pci_msgring *ring;
1739e272db29Spatrick 	int s;
1740a2c6ff8bSpatrick 
1741a2c6ff8bSpatrick 	ring = &sc->sc_flowrings[flowid];
1742a2c6ff8bSpatrick 	if (ring->status != RING_OPEN) {
1743a2c6ff8bSpatrick 		printf("%s: flowring not open\n", DEVNAME(sc));
1744a2c6ff8bSpatrick 		return;
1745a2c6ff8bSpatrick 	}
1746a2c6ff8bSpatrick 
1747e272db29Spatrick 	s = splnet();
1748a2c6ff8bSpatrick 	req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit);
1749a2c6ff8bSpatrick 	if (req == NULL) {
1750a2c6ff8bSpatrick 		printf("%s: cannot reserve for flowring\n", DEVNAME(sc));
1751e272db29Spatrick 		splx(s);
1752a2c6ff8bSpatrick 		return;
1753a2c6ff8bSpatrick 	}
1754a2c6ff8bSpatrick 
1755a2c6ff8bSpatrick 	ring->status = RING_CLOSING;
1756a2c6ff8bSpatrick 
1757a2c6ff8bSpatrick 	req->msg.msgtype = MSGBUF_TYPE_FLOW_RING_DELETE;
1758a2c6ff8bSpatrick 	req->msg.ifidx = 0;
1759a2c6ff8bSpatrick 	req->msg.request_id = 0;
1760a2c6ff8bSpatrick 	req->flow_ring_id = letoh16(flowid + 2);
1761a2c6ff8bSpatrick 	req->reason = 0;
1762a2c6ff8bSpatrick 
1763a2c6ff8bSpatrick 	bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit);
1764e272db29Spatrick 	splx(s);
1765a2c6ff8bSpatrick }
1766a2c6ff8bSpatrick 
1767a2c6ff8bSpatrick void
1768a2c6ff8bSpatrick bwfm_pci_stop(struct bwfm_softc *bwfm)
1769a2c6ff8bSpatrick {
1770a2c6ff8bSpatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1771a2c6ff8bSpatrick 	struct bwfm_pci_msgring *ring;
1772a2c6ff8bSpatrick 	int i;
1773a2c6ff8bSpatrick 
1774a2c6ff8bSpatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
1775a2c6ff8bSpatrick 		ring = &sc->sc_flowrings[i];
1776a2c6ff8bSpatrick 		if (ring->status == RING_OPEN)
1777a2c6ff8bSpatrick 			bwfm_pci_flowring_delete(sc, i);
1778a2c6ff8bSpatrick 	}
1779a2c6ff8bSpatrick }
1780a2c6ff8bSpatrick 
1781e5ec1e72Spatrick int
178202ee7d07Spatrick bwfm_pci_txcheck(struct bwfm_softc *bwfm)
178302ee7d07Spatrick {
178402ee7d07Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
178502ee7d07Spatrick 	struct bwfm_pci_msgring *ring;
178602ee7d07Spatrick 	int i;
178702ee7d07Spatrick 
178802ee7d07Spatrick 	/* If we are transitioning, we cannot send. */
178902ee7d07Spatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
179002ee7d07Spatrick 		ring = &sc->sc_flowrings[i];
179102ee7d07Spatrick 		if (ring->status == RING_OPENING)
179202ee7d07Spatrick 			return ENOBUFS;
179302ee7d07Spatrick 	}
179402ee7d07Spatrick 
179502ee7d07Spatrick 	if (bwfm_pci_pktid_avail(sc, &sc->sc_tx_pkts)) {
179602ee7d07Spatrick 		sc->sc_tx_pkts_full = 1;
179702ee7d07Spatrick 		return ENOBUFS;
179802ee7d07Spatrick 	}
179902ee7d07Spatrick 
180002ee7d07Spatrick 	return 0;
180102ee7d07Spatrick }
180202ee7d07Spatrick 
180302ee7d07Spatrick int
1804e5ec1e72Spatrick bwfm_pci_txdata(struct bwfm_softc *bwfm, struct mbuf *m)
1805e5ec1e72Spatrick {
1806e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1807518be5f3Spatrick 	struct bwfm_pci_msgring *ring;
1808518be5f3Spatrick 	struct msgbuf_tx_msghdr *tx;
1809518be5f3Spatrick 	uint32_t pktid;
1810518be5f3Spatrick 	paddr_t paddr;
1811518be5f3Spatrick 	int flowid, ret;
1812518be5f3Spatrick 
1813f67437f3Spatrick 	flowid = bwfm_pci_flowring_lookup(sc, m);
1814f67437f3Spatrick 	if (flowid < 0) {
181502ee7d07Spatrick 		/*
181602ee7d07Spatrick 		 * We cannot send the packet right now as there is
181702ee7d07Spatrick 		 * no flowring yet.  The flowring will be created
181802ee7d07Spatrick 		 * asynchronously.  While the ring is transitioning
181902ee7d07Spatrick 		 * the TX check will tell the upper layers that we
182002ee7d07Spatrick 		 * cannot send packets right now.  When the flowring
182102ee7d07Spatrick 		 * is created the queue will be restarted and this
182202ee7d07Spatrick 		 * mbuf will be transmitted.
182302ee7d07Spatrick 		 */
1824f67437f3Spatrick 		bwfm_pci_flowring_create(sc, m);
182502ee7d07Spatrick 		return 0;
1826f67437f3Spatrick 	}
1827518be5f3Spatrick 
1828518be5f3Spatrick 	ring = &sc->sc_flowrings[flowid];
1829518be5f3Spatrick 	if (ring->status == RING_OPENING ||
1830f67437f3Spatrick 	    ring->status == RING_CLOSING) {
1831f67437f3Spatrick 		printf("%s: tried to use a flow that was "
1832f67437f3Spatrick 		    "transitioning in status %d\n",
1833f67437f3Spatrick 		    DEVNAME(sc), ring->status);
1834518be5f3Spatrick 		return ENOBUFS;
1835518be5f3Spatrick 	}
1836518be5f3Spatrick 
1837518be5f3Spatrick 	tx = bwfm_pci_ring_write_reserve(sc, ring);
1838518be5f3Spatrick 	if (tx == NULL)
1839518be5f3Spatrick 		return ENOBUFS;
1840518be5f3Spatrick 
1841518be5f3Spatrick 	memset(tx, 0, sizeof(*tx));
1842518be5f3Spatrick 	tx->msg.msgtype = MSGBUF_TYPE_TX_POST;
1843518be5f3Spatrick 	tx->msg.ifidx = 0;
1844518be5f3Spatrick 	tx->flags = BWFM_MSGBUF_PKT_FLAGS_FRAME_802_3;
1845518be5f3Spatrick 	tx->flags |= ieee80211_classify(&sc->sc_sc.sc_ic, m) <<
1846518be5f3Spatrick 	    BWFM_MSGBUF_PKT_FLAGS_PRIO_SHIFT;
1847518be5f3Spatrick 	tx->seg_cnt = 1;
1848518be5f3Spatrick 	memcpy(tx->txhdr, mtod(m, char *), ETHER_HDR_LEN);
1849518be5f3Spatrick 
1850518be5f3Spatrick 	ret = bwfm_pci_pktid_new(sc, &sc->sc_tx_pkts, m, &pktid, &paddr);
1851518be5f3Spatrick 	if (ret) {
185202ee7d07Spatrick 		if (ret == ENOBUFS) {
185302ee7d07Spatrick 			printf("%s: no pktid available for TX\n",
185402ee7d07Spatrick 			    DEVNAME(sc));
1855c6f1636dSpatrick 			sc->sc_tx_pkts_full = 1;
185602ee7d07Spatrick 		}
1857518be5f3Spatrick 		bwfm_pci_ring_write_cancel(sc, ring, 1);
1858518be5f3Spatrick 		return ret;
1859518be5f3Spatrick 	}
1860518be5f3Spatrick 	paddr += ETHER_HDR_LEN;
1861518be5f3Spatrick 
1862f9ee104fSpatrick 	tx->msg.request_id = htole32(pktid + 1);
18634ff787bcSpatrick 	tx->data_len = htole16(m->m_len - ETHER_HDR_LEN);
1864e4dae658Spatrick 	tx->data_buf_addr.high_addr = htole32((uint64_t)paddr >> 32);
1865518be5f3Spatrick 	tx->data_buf_addr.low_addr = htole32(paddr & 0xffffffff);
1866518be5f3Spatrick 
1867518be5f3Spatrick 	bwfm_pci_ring_write_commit(sc, ring);
1868518be5f3Spatrick 	return 0;
1869e5ec1e72Spatrick }
1870e5ec1e72Spatrick 
1871bbd71b0bSpatrick #ifdef BWFM_DEBUG
1872cadf5fcfSpatrick void
1873cadf5fcfSpatrick bwfm_pci_debug_console(struct bwfm_pci_softc *sc)
1874cadf5fcfSpatrick {
1875cadf5fcfSpatrick 	uint32_t newidx = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1876cadf5fcfSpatrick 	    sc->sc_console_base_addr + BWFM_CONSOLE_WRITEIDX);
1877cadf5fcfSpatrick 
1878cadf5fcfSpatrick 	if (newidx != sc->sc_console_readidx)
1879bbd71b0bSpatrick 		DPRINTFN(3, ("BWFM CONSOLE: "));
1880cadf5fcfSpatrick 	while (newidx != sc->sc_console_readidx) {
1881cadf5fcfSpatrick 		uint8_t ch = bus_space_read_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1882cadf5fcfSpatrick 		    sc->sc_console_buf_addr + sc->sc_console_readidx);
1883cadf5fcfSpatrick 		sc->sc_console_readidx++;
1884cadf5fcfSpatrick 		if (sc->sc_console_readidx == sc->sc_console_buf_size)
1885cadf5fcfSpatrick 			sc->sc_console_readidx = 0;
1886cadf5fcfSpatrick 		if (ch == '\r')
1887cadf5fcfSpatrick 			continue;
1888bbd71b0bSpatrick 		DPRINTFN(3, ("%c", ch));
1889cadf5fcfSpatrick 	}
1890cadf5fcfSpatrick }
1891bbd71b0bSpatrick #endif
1892cadf5fcfSpatrick 
1893e5ec1e72Spatrick int
1894e5ec1e72Spatrick bwfm_pci_intr(void *v)
1895e5ec1e72Spatrick {
1896e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)v;
18976f241297Spatrick 	struct ifnet *ifp = &sc->sc_sc.sc_ic.ic_if;
18986f241297Spatrick 	struct mbuf_list ml = MBUF_LIST_INITIALIZER();
1899e5ec1e72Spatrick 	uint32_t status;
1900e5ec1e72Spatrick 
1901e5ec1e72Spatrick 	if ((status = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1902e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXINT)) == 0)
1903e5ec1e72Spatrick 		return 0;
1904e5ec1e72Spatrick 
1905e5ec1e72Spatrick 	bwfm_pci_intr_disable(sc);
1906e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1907e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXINT, status);
1908e5ec1e72Spatrick 
1909e5ec1e72Spatrick 	if (status & (BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_0 |
1910e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_1))
1911e5ec1e72Spatrick 		printf("%s: handle MB data\n", __func__);
1912e5ec1e72Spatrick 
1913e5ec1e72Spatrick 	if (status & BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_D2H_DB) {
19146f241297Spatrick 		bwfm_pci_ring_rx(sc, &sc->sc_rx_complete, &ml);
19156f241297Spatrick 		bwfm_pci_ring_rx(sc, &sc->sc_tx_complete, &ml);
19166f241297Spatrick 		bwfm_pci_ring_rx(sc, &sc->sc_ctrl_complete, &ml);
19176f241297Spatrick 		if_input(ifp, &ml);
1918e5ec1e72Spatrick 	}
1919e5ec1e72Spatrick 
1920cadf5fcfSpatrick #ifdef BWFM_DEBUG
1921cadf5fcfSpatrick 	bwfm_pci_debug_console(sc);
1922e5ec1e72Spatrick #endif
1923e5ec1e72Spatrick 
1924e5ec1e72Spatrick 	bwfm_pci_intr_enable(sc);
1925e5ec1e72Spatrick 	return 1;
1926e5ec1e72Spatrick }
1927e5ec1e72Spatrick 
1928e5ec1e72Spatrick void
1929e5ec1e72Spatrick bwfm_pci_intr_enable(struct bwfm_pci_softc *sc)
1930e5ec1e72Spatrick {
1931e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1932e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXMASK,
1933e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_0 |
1934e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_1 |
1935e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_D2H_DB);
1936e5ec1e72Spatrick }
1937e5ec1e72Spatrick 
1938e5ec1e72Spatrick void
1939e5ec1e72Spatrick bwfm_pci_intr_disable(struct bwfm_pci_softc *sc)
1940e5ec1e72Spatrick {
1941e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1942e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXMASK, 0);
1943e5ec1e72Spatrick }
1944e5ec1e72Spatrick 
1945e5ec1e72Spatrick /* Msgbuf protocol implementation */
1946e5ec1e72Spatrick int
1947e5ec1e72Spatrick bwfm_pci_msgbuf_query_dcmd(struct bwfm_softc *bwfm, int ifidx,
1948e5ec1e72Spatrick     int cmd, char *buf, size_t *len)
1949e5ec1e72Spatrick {
1950e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1951e5ec1e72Spatrick 	struct msgbuf_ioctl_req_hdr *req;
19522eeba925Spatrick 	struct bwfm_pci_ioctl *ctl;
1953e5ec1e72Spatrick 	struct mbuf *m;
19542eeba925Spatrick 	uint32_t pktid;
19552eeba925Spatrick 	paddr_t paddr;
1956e5ec1e72Spatrick 	size_t buflen;
1957e272db29Spatrick 	int s;
1958e5ec1e72Spatrick 
19592eeba925Spatrick 	buflen = min(*len, BWFM_DMA_H2D_IOCTL_BUF_LEN);
19602eeba925Spatrick 	m = MCLGETI(NULL, M_DONTWAIT, NULL, buflen);
19612eeba925Spatrick 	if (m == NULL)
19622eeba925Spatrick 		return 1;
19632eeba925Spatrick 	m->m_len = m->m_pkthdr.len = buflen;
19642eeba925Spatrick 
19652eeba925Spatrick 	if (buf)
19662eeba925Spatrick 		memcpy(mtod(m, char *), buf, buflen);
19672eeba925Spatrick 	else
19682eeba925Spatrick 		memset(mtod(m, char *), 0, buflen);
19692eeba925Spatrick 
1970e272db29Spatrick 	s = splnet();
1971e5ec1e72Spatrick 	req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit);
1972e5ec1e72Spatrick 	if (req == NULL) {
1973e272db29Spatrick 		splx(s);
19742eeba925Spatrick 		m_freem(m);
1975e5ec1e72Spatrick 		return 1;
1976e5ec1e72Spatrick 	}
19772eeba925Spatrick 
19782eeba925Spatrick 	if (bwfm_pci_pktid_new(sc, &sc->sc_ioctl_pkts, m, &pktid, &paddr)) {
19792eeba925Spatrick 		bwfm_pci_ring_write_cancel(sc, &sc->sc_ctrl_submit, 1);
1980e272db29Spatrick 		splx(s);
19812eeba925Spatrick 		m_freem(m);
19822eeba925Spatrick 		return 1;
19832eeba925Spatrick 	}
19842eeba925Spatrick 
19852eeba925Spatrick 	ctl = malloc(sizeof(*ctl), M_TEMP, M_WAITOK|M_ZERO);
19862eeba925Spatrick 	ctl->transid = sc->sc_ioctl_transid++;
19872eeba925Spatrick 	TAILQ_INSERT_TAIL(&sc->sc_ioctlq, ctl, next);
19882eeba925Spatrick 
1989e5ec1e72Spatrick 	req->msg.msgtype = MSGBUF_TYPE_IOCTLPTR_REQ;
1990e5ec1e72Spatrick 	req->msg.ifidx = 0;
1991e5ec1e72Spatrick 	req->msg.flags = 0;
19922eeba925Spatrick 	req->msg.request_id = htole32(pktid);
1993e5ec1e72Spatrick 	req->cmd = htole32(cmd);
1994e5ec1e72Spatrick 	req->output_buf_len = htole16(*len);
19952eeba925Spatrick 	req->trans_id = htole16(ctl->transid);
1996e5ec1e72Spatrick 
19972eeba925Spatrick 	req->input_buf_len = htole16(m->m_len);
19982eeba925Spatrick 	req->req_buf_addr.high_addr = htole32((uint64_t)paddr >> 32);
19992eeba925Spatrick 	req->req_buf_addr.low_addr = htole32(paddr & 0xffffffff);
2000dcb67343Spatrick 
2001e5ec1e72Spatrick 	bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit);
2002e272db29Spatrick 	splx(s);
2003e5ec1e72Spatrick 
20048544fed6Smpi 	tsleep_nsec(ctl, PWAIT, "bwfm", SEC_TO_NSEC(1));
20052eeba925Spatrick 	TAILQ_REMOVE(&sc->sc_ioctlq, ctl, next);
20062eeba925Spatrick 
20072eeba925Spatrick 	if (ctl->m == NULL) {
20082eeba925Spatrick 		free(ctl, M_TEMP, sizeof(*ctl));
2009e5ec1e72Spatrick 		return 1;
2010e5ec1e72Spatrick 	}
2011e5ec1e72Spatrick 
20122eeba925Spatrick 	*len = min(ctl->retlen, m->m_len);
20132eeba925Spatrick 	*len = min(*len, buflen);
2014e5ec1e72Spatrick 	if (buf)
20152eeba925Spatrick 		m_copydata(ctl->m, 0, *len, (caddr_t)buf);
20162eeba925Spatrick 	m_freem(ctl->m);
2017e5ec1e72Spatrick 
20182eeba925Spatrick 	if (ctl->status < 0) {
20192eeba925Spatrick 		free(ctl, M_TEMP, sizeof(*ctl));
20202eeba925Spatrick 		return 1;
20212eeba925Spatrick 	}
20222eeba925Spatrick 
20232eeba925Spatrick 	free(ctl, M_TEMP, sizeof(*ctl));
2024e5ec1e72Spatrick 	return 0;
2025e5ec1e72Spatrick }
2026e5ec1e72Spatrick 
2027e5ec1e72Spatrick int
2028e5ec1e72Spatrick bwfm_pci_msgbuf_set_dcmd(struct bwfm_softc *bwfm, int ifidx,
2029e5ec1e72Spatrick     int cmd, char *buf, size_t len)
2030e5ec1e72Spatrick {
2031e5ec1e72Spatrick 	return bwfm_pci_msgbuf_query_dcmd(bwfm, ifidx, cmd, buf, &len);
2032e5ec1e72Spatrick }
20332eeba925Spatrick 
20342eeba925Spatrick void
20352eeba925Spatrick bwfm_pci_msgbuf_rxioctl(struct bwfm_pci_softc *sc,
20362eeba925Spatrick     struct msgbuf_ioctl_resp_hdr *resp)
20372eeba925Spatrick {
20382eeba925Spatrick 	struct bwfm_pci_ioctl *ctl, *tmp;
20392eeba925Spatrick 	struct mbuf *m;
20402eeba925Spatrick 
20412eeba925Spatrick 	m = bwfm_pci_pktid_free(sc, &sc->sc_rx_pkts,
20422eeba925Spatrick 	    letoh32(resp->msg.request_id));
20432eeba925Spatrick 
20442eeba925Spatrick 	TAILQ_FOREACH_SAFE(ctl, &sc->sc_ioctlq, next, tmp) {
20452eeba925Spatrick 		if (ctl->transid != letoh16(resp->trans_id))
20462eeba925Spatrick 			continue;
20472eeba925Spatrick 		ctl->m = m;
20482eeba925Spatrick 		ctl->retlen = letoh16(resp->resp_len);
20492eeba925Spatrick 		ctl->status = letoh16(resp->compl_hdr.status);
20502eeba925Spatrick 		wakeup(ctl);
20512eeba925Spatrick 		return;
20522eeba925Spatrick 	}
20532eeba925Spatrick 
2054cb2afc74Spatrick 	m_freem(m);
20552eeba925Spatrick }
2056