xref: /openbsd/sys/dev/pci/if_bwfm_pci.c (revision 156d2677)
1*156d2677Spatrick /*	$OpenBSD: if_bwfm_pci.c,v 1.46 2021/02/26 00:14:28 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 *);
203*156d2677Spatrick void		 bwfm_pci_hostready(struct bwfm_pci_softc *);
204e5ec1e72Spatrick int		 bwfm_pci_load_microcode(struct bwfm_pci_softc *, const u_char *,
2056aad491fSpatrick 		    size_t, const u_char *, size_t);
206e5ec1e72Spatrick void		 bwfm_pci_select_core(struct bwfm_pci_softc *, int );
207e5ec1e72Spatrick 
208e5ec1e72Spatrick struct bwfm_pci_dmamem *
209e5ec1e72Spatrick 		 bwfm_pci_dmamem_alloc(struct bwfm_pci_softc *, bus_size_t,
210e5ec1e72Spatrick 		    bus_size_t);
211e5ec1e72Spatrick void		 bwfm_pci_dmamem_free(struct bwfm_pci_softc *, struct bwfm_pci_dmamem *);
21202ee7d07Spatrick int		 bwfm_pci_pktid_avail(struct bwfm_pci_softc *,
21302ee7d07Spatrick 		    struct bwfm_pci_pkts *);
214e5ec1e72Spatrick int		 bwfm_pci_pktid_new(struct bwfm_pci_softc *,
215e5ec1e72Spatrick 		    struct bwfm_pci_pkts *, struct mbuf *,
216e5ec1e72Spatrick 		    uint32_t *, paddr_t *);
217e5ec1e72Spatrick struct mbuf *	 bwfm_pci_pktid_free(struct bwfm_pci_softc *,
218e5ec1e72Spatrick 		    struct bwfm_pci_pkts *, uint32_t);
219e5ec1e72Spatrick void		 bwfm_pci_fill_rx_ioctl_ring(struct bwfm_pci_softc *,
220e5ec1e72Spatrick 		    struct if_rxring *, uint32_t);
221e5ec1e72Spatrick void		 bwfm_pci_fill_rx_buf_ring(struct bwfm_pci_softc *);
222e5ec1e72Spatrick void		 bwfm_pci_fill_rx_rings(struct bwfm_pci_softc *);
223e5ec1e72Spatrick int		 bwfm_pci_setup_ring(struct bwfm_pci_softc *, struct bwfm_pci_msgring *,
224e5ec1e72Spatrick 		    int, size_t, uint32_t, uint32_t, int, uint32_t, uint32_t *);
225518be5f3Spatrick int		 bwfm_pci_setup_flowring(struct bwfm_pci_softc *, struct bwfm_pci_msgring *,
226518be5f3Spatrick 		    int, size_t);
227e5ec1e72Spatrick 
228e5ec1e72Spatrick void		 bwfm_pci_ring_bell(struct bwfm_pci_softc *,
229e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
230e5ec1e72Spatrick void		 bwfm_pci_ring_update_rptr(struct bwfm_pci_softc *,
231e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
232e5ec1e72Spatrick void		 bwfm_pci_ring_update_wptr(struct bwfm_pci_softc *,
233e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
234e5ec1e72Spatrick void		 bwfm_pci_ring_write_rptr(struct bwfm_pci_softc *,
235e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
236e5ec1e72Spatrick void		 bwfm_pci_ring_write_wptr(struct bwfm_pci_softc *,
237e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
238e5ec1e72Spatrick void *		 bwfm_pci_ring_write_reserve(struct bwfm_pci_softc *,
239e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
240e5ec1e72Spatrick void *		 bwfm_pci_ring_write_reserve_multi(struct bwfm_pci_softc *,
241e5ec1e72Spatrick 		    struct bwfm_pci_msgring *, int, int *);
242e5ec1e72Spatrick void *		 bwfm_pci_ring_read_avail(struct bwfm_pci_softc *,
243e5ec1e72Spatrick 		    struct bwfm_pci_msgring *, int *);
244e5ec1e72Spatrick void		 bwfm_pci_ring_read_commit(struct bwfm_pci_softc *,
245e5ec1e72Spatrick 		    struct bwfm_pci_msgring *, int);
246e5ec1e72Spatrick void		 bwfm_pci_ring_write_commit(struct bwfm_pci_softc *,
247e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
248e5ec1e72Spatrick void		 bwfm_pci_ring_write_cancel(struct bwfm_pci_softc *,
249e5ec1e72Spatrick 		    struct bwfm_pci_msgring *, int);
250e5ec1e72Spatrick 
251e5ec1e72Spatrick void		 bwfm_pci_ring_rx(struct bwfm_pci_softc *,
2526f241297Spatrick 		    struct bwfm_pci_msgring *, struct mbuf_list *);
2536f241297Spatrick void		 bwfm_pci_msg_rx(struct bwfm_pci_softc *, void *,
2546f241297Spatrick 		    struct mbuf_list *);
255e5ec1e72Spatrick 
256e5ec1e72Spatrick uint32_t	 bwfm_pci_buscore_read(struct bwfm_softc *, uint32_t);
257e5ec1e72Spatrick void		 bwfm_pci_buscore_write(struct bwfm_softc *, uint32_t,
258e5ec1e72Spatrick 		    uint32_t);
259e5ec1e72Spatrick int		 bwfm_pci_buscore_prepare(struct bwfm_softc *);
260e5ec1e72Spatrick int		 bwfm_pci_buscore_reset(struct bwfm_softc *);
261e5ec1e72Spatrick void		 bwfm_pci_buscore_activate(struct bwfm_softc *, uint32_t);
262e5ec1e72Spatrick 
263f67437f3Spatrick int		 bwfm_pci_flowring_lookup(struct bwfm_pci_softc *,
264f67437f3Spatrick 		     struct mbuf *);
265f67437f3Spatrick void		 bwfm_pci_flowring_create(struct bwfm_pci_softc *,
266518be5f3Spatrick 		     struct mbuf *);
267518be5f3Spatrick void		 bwfm_pci_flowring_create_cb(struct bwfm_softc *, void *);
268a2c6ff8bSpatrick void		 bwfm_pci_flowring_delete(struct bwfm_pci_softc *, int);
269518be5f3Spatrick 
270972218f3Spatrick int		 bwfm_pci_preinit(struct bwfm_softc *);
271a2c6ff8bSpatrick void		 bwfm_pci_stop(struct bwfm_softc *);
27202ee7d07Spatrick int		 bwfm_pci_txcheck(struct bwfm_softc *);
273e5ec1e72Spatrick int		 bwfm_pci_txdata(struct bwfm_softc *, struct mbuf *);
274bbd71b0bSpatrick 
275bbd71b0bSpatrick #ifdef BWFM_DEBUG
276cadf5fcfSpatrick void		 bwfm_pci_debug_console(struct bwfm_pci_softc *);
277bbd71b0bSpatrick #endif
278e5ec1e72Spatrick 
279e5ec1e72Spatrick int		 bwfm_pci_msgbuf_query_dcmd(struct bwfm_softc *, int,
280e5ec1e72Spatrick 		    int, char *, size_t *);
281e5ec1e72Spatrick int		 bwfm_pci_msgbuf_set_dcmd(struct bwfm_softc *, int,
282e5ec1e72Spatrick 		    int, char *, size_t);
2832eeba925Spatrick void		 bwfm_pci_msgbuf_rxioctl(struct bwfm_pci_softc *,
2842eeba925Spatrick 		    struct msgbuf_ioctl_resp_hdr *);
285e5ec1e72Spatrick 
286e5ec1e72Spatrick struct bwfm_buscore_ops bwfm_pci_buscore_ops = {
287e5ec1e72Spatrick 	.bc_read = bwfm_pci_buscore_read,
288e5ec1e72Spatrick 	.bc_write = bwfm_pci_buscore_write,
289e5ec1e72Spatrick 	.bc_prepare = bwfm_pci_buscore_prepare,
290e5ec1e72Spatrick 	.bc_reset = bwfm_pci_buscore_reset,
291e5ec1e72Spatrick 	.bc_setup = NULL,
292e5ec1e72Spatrick 	.bc_activate = bwfm_pci_buscore_activate,
293e5ec1e72Spatrick };
294e5ec1e72Spatrick 
295e5ec1e72Spatrick struct bwfm_bus_ops bwfm_pci_bus_ops = {
296972218f3Spatrick 	.bs_preinit = bwfm_pci_preinit,
297a2c6ff8bSpatrick 	.bs_stop = bwfm_pci_stop,
29802ee7d07Spatrick 	.bs_txcheck = bwfm_pci_txcheck,
299e5ec1e72Spatrick 	.bs_txdata = bwfm_pci_txdata,
300e5ec1e72Spatrick 	.bs_txctl = NULL,
301e5ec1e72Spatrick };
302e5ec1e72Spatrick 
303e5ec1e72Spatrick struct bwfm_proto_ops bwfm_pci_msgbuf_ops = {
304e5ec1e72Spatrick 	.proto_query_dcmd = bwfm_pci_msgbuf_query_dcmd,
305e5ec1e72Spatrick 	.proto_set_dcmd = bwfm_pci_msgbuf_set_dcmd,
30614c74651Spatrick 	.proto_rx = NULL,
307029d6dd5Spatrick 	.proto_rxctl = NULL,
308e5ec1e72Spatrick };
309e5ec1e72Spatrick 
310e5ec1e72Spatrick struct cfattach bwfm_pci_ca = {
311e5ec1e72Spatrick 	sizeof(struct bwfm_pci_softc),
312e5ec1e72Spatrick 	bwfm_pci_match,
313e5ec1e72Spatrick 	bwfm_pci_attach,
314e5ec1e72Spatrick 	bwfm_pci_detach,
315e5ec1e72Spatrick };
316e5ec1e72Spatrick 
317e5ec1e72Spatrick static const struct pci_matchid bwfm_pci_devices[] = {
31882f0e660Sjcs 	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4350 },
31941d93ac2Spatrick 	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4356 },
32041d93ac2Spatrick 	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM43602 },
321821fc986Spatrick 	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4371 },
322e5ec1e72Spatrick };
323e5ec1e72Spatrick 
324e5ec1e72Spatrick int
325e5ec1e72Spatrick bwfm_pci_match(struct device *parent, void *match, void *aux)
326e5ec1e72Spatrick {
327e5ec1e72Spatrick 	return (pci_matchbyid(aux, bwfm_pci_devices,
328e5ec1e72Spatrick 	    nitems(bwfm_pci_devices)));
329e5ec1e72Spatrick }
330e5ec1e72Spatrick 
331e5ec1e72Spatrick void
332e5ec1e72Spatrick bwfm_pci_attach(struct device *parent, struct device *self, void *aux)
333e5ec1e72Spatrick {
334e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (struct bwfm_pci_softc *)self;
335e5ec1e72Spatrick 	struct pci_attach_args *pa = (struct pci_attach_args *)aux;
336e5ec1e72Spatrick 	const char *intrstr;
337e5ec1e72Spatrick 	pci_intr_handle_t ih;
338e5ec1e72Spatrick 
339e5ec1e72Spatrick 	if (pci_mapreg_map(pa, PCI_MAPREG_START + 0x08,
340e5ec1e72Spatrick 	    PCI_MAPREG_MEM_TYPE_64BIT, 0, &sc->sc_tcm_iot, &sc->sc_tcm_ioh,
341e5ec1e72Spatrick 	    NULL, &sc->sc_tcm_ios, 0)) {
342e5ec1e72Spatrick 		printf(": can't map bar1\n");
343a08e9144Spatrick 		return;
344a08e9144Spatrick 	}
345a08e9144Spatrick 
346a08e9144Spatrick 	if (pci_mapreg_map(pa, PCI_MAPREG_START + 0x00,
347a08e9144Spatrick 	    PCI_MAPREG_MEM_TYPE_64BIT, 0, &sc->sc_reg_iot, &sc->sc_reg_ioh,
348a08e9144Spatrick 	    NULL, &sc->sc_reg_ios, 0)) {
349a08e9144Spatrick 		printf(": can't map bar0\n");
350a08e9144Spatrick 		goto bar1;
351e5ec1e72Spatrick 	}
352e5ec1e72Spatrick 
353e5ec1e72Spatrick 	sc->sc_pc = pa->pa_pc;
354e5ec1e72Spatrick 	sc->sc_tag = pa->pa_tag;
355e5ec1e72Spatrick 	sc->sc_id = pa->pa_id;
356e5ec1e72Spatrick 	sc->sc_dmat = pa->pa_dmat;
357e5ec1e72Spatrick 
358e5ec1e72Spatrick 	/* Map and establish the interrupt. */
359e5ec1e72Spatrick 	if (pci_intr_map_msi(pa, &ih) != 0 && pci_intr_map(pa, &ih) != 0) {
360e5ec1e72Spatrick 		printf(": couldn't map interrupt\n");
361a08e9144Spatrick 		goto bar0;
362e5ec1e72Spatrick 	}
363e5ec1e72Spatrick 	intrstr = pci_intr_string(pa->pa_pc, ih);
364e5ec1e72Spatrick 
365e5ec1e72Spatrick 	sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_NET | IPL_MPSAFE,
366e5ec1e72Spatrick 	    bwfm_pci_intr, sc, DEVNAME(sc));
367e5ec1e72Spatrick 	if (sc->sc_ih == NULL) {
368e5ec1e72Spatrick 		printf(": couldn't establish interrupt");
369e5ec1e72Spatrick 		if (intrstr != NULL)
370e5ec1e72Spatrick 			printf(" at %s", intrstr);
371e5ec1e72Spatrick 		printf("\n");
372e5ec1e72Spatrick 		goto bar1;
373e5ec1e72Spatrick 	}
374e5ec1e72Spatrick 	printf(": %s\n", intrstr);
375e5ec1e72Spatrick 
376972218f3Spatrick 	sc->sc_sc.sc_bus_ops = &bwfm_pci_bus_ops;
377972218f3Spatrick 	sc->sc_sc.sc_proto_ops = &bwfm_pci_msgbuf_ops;
378972218f3Spatrick 	bwfm_attach(&sc->sc_sc);
379972218f3Spatrick 	config_mountroot(self, bwfm_attachhook);
380e5ec1e72Spatrick 	return;
381e5ec1e72Spatrick 
382e5ec1e72Spatrick bar0:
383e5ec1e72Spatrick 	bus_space_unmap(sc->sc_reg_iot, sc->sc_reg_ioh, sc->sc_reg_ios);
384a08e9144Spatrick bar1:
385a08e9144Spatrick 	bus_space_unmap(sc->sc_tcm_iot, sc->sc_tcm_ioh, sc->sc_tcm_ios);
386e5ec1e72Spatrick }
387e5ec1e72Spatrick 
388972218f3Spatrick int
389972218f3Spatrick bwfm_pci_preinit(struct bwfm_softc *bwfm)
390e5ec1e72Spatrick {
391972218f3Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
392e5ec1e72Spatrick 	struct bwfm_pci_ringinfo ringinfo;
3939ead8393Spatrick 	const char *chip = NULL;
39494e4747cSpatrick 	u_char *ucode, *nvram;
39594e4747cSpatrick 	size_t size, nvsize, nvlen;
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:
4219ead8393Spatrick 		if (bwfm->sc_chip.ch_chiprev > 7)
4229ead8393Spatrick 			chip = "4350";
4239ead8393Spatrick 		else
4249ead8393Spatrick 			chip = "4350c2";
42518b3a1dcSpatrick 		break;
42641d93ac2Spatrick 	case BRCM_CC_4356_CHIP_ID:
4279ead8393Spatrick 		chip = "4356";
42841d93ac2Spatrick 		break;
429e5ec1e72Spatrick 	case BRCM_CC_43602_CHIP_ID:
4309ead8393Spatrick 		chip = "43602";
431e5ec1e72Spatrick 		break;
432821fc986Spatrick 	case BRCM_CC_4371_CHIP_ID:
4339ead8393Spatrick 		chip = "4371";
434821fc986Spatrick 		break;
435c38a9bc9Spatrick 	case BRCM_CC_4378_CHIP_ID:
436c38a9bc9Spatrick 		chip = "4378";
437c38a9bc9Spatrick 		break;
438e5ec1e72Spatrick 	default:
43918b3a1dcSpatrick 		printf("%s: unknown firmware for chip %s\n",
44018b3a1dcSpatrick 		    DEVNAME(sc), bwfm->sc_chip.ch_name);
441972218f3Spatrick 		return 1;
442e5ec1e72Spatrick 	}
443e5ec1e72Spatrick 
44494e4747cSpatrick 	if (bwfm_loadfirmware(bwfm, chip, "-pcie", &ucode, &size,
44594e4747cSpatrick 	    &nvram, &nvsize, &nvlen) != 0)
446972218f3Spatrick 		return 1;
4476aad491fSpatrick 
448e5ec1e72Spatrick 	/* Retrieve RAM size from firmware. */
449e5ec1e72Spatrick 	if (size >= BWFM_RAMSIZE + 8) {
450e5ec1e72Spatrick 		uint32_t *ramsize = (uint32_t *)&ucode[BWFM_RAMSIZE];
451e5ec1e72Spatrick 		if (letoh32(ramsize[0]) == BWFM_RAMSIZE_MAGIC)
452e5ec1e72Spatrick 			bwfm->sc_chip.ch_ramsize = letoh32(ramsize[1]);
453e5ec1e72Spatrick 	}
454e5ec1e72Spatrick 
4556aad491fSpatrick 	if (bwfm_pci_load_microcode(sc, ucode, size, nvram, nvlen) != 0) {
456e5ec1e72Spatrick 		printf("%s: could not load microcode\n",
457e5ec1e72Spatrick 		    DEVNAME(sc));
458e5ec1e72Spatrick 		free(ucode, M_DEVBUF, size);
459b4e85b06Spatrick 		free(nvram, M_DEVBUF, nvsize);
460972218f3Spatrick 		return 1;
461e5ec1e72Spatrick 	}
462e5ec1e72Spatrick 	free(ucode, M_DEVBUF, size);
463b4e85b06Spatrick 	free(nvram, M_DEVBUF, nvsize);
464e5ec1e72Spatrick 
465e5ec1e72Spatrick 	sc->sc_shared_flags = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
466e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_INFO);
467e5ec1e72Spatrick 	sc->sc_shared_version = sc->sc_shared_flags;
468e5ec1e72Spatrick 	if (sc->sc_shared_version > BWFM_SHARED_INFO_MAX_VERSION ||
469e5ec1e72Spatrick 	    sc->sc_shared_version < BWFM_SHARED_INFO_MIN_VERSION) {
470e5ec1e72Spatrick 		printf("%s: PCIe version %d unsupported\n",
471e5ec1e72Spatrick 		    DEVNAME(sc), sc->sc_shared_version);
472972218f3Spatrick 		return 1;
473e5ec1e72Spatrick 	}
474e5ec1e72Spatrick 
475e5ec1e72Spatrick 	if (sc->sc_shared_flags & BWFM_SHARED_INFO_DMA_INDEX) {
476e5ec1e72Spatrick 		if (sc->sc_shared_flags & BWFM_SHARED_INFO_DMA_2B_IDX)
477e5ec1e72Spatrick 			sc->sc_dma_idx_sz = sizeof(uint16_t);
478e5ec1e72Spatrick 		else
479e5ec1e72Spatrick 			sc->sc_dma_idx_sz = sizeof(uint32_t);
480e5ec1e72Spatrick 	}
481e5ec1e72Spatrick 
482e5ec1e72Spatrick 	/* Maximum RX data buffers in the ring. */
483e5ec1e72Spatrick 	sc->sc_max_rxbufpost = bus_space_read_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
484e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_MAX_RXBUFPOST);
485e5ec1e72Spatrick 	if (sc->sc_max_rxbufpost == 0)
486e5ec1e72Spatrick 		sc->sc_max_rxbufpost = BWFM_SHARED_MAX_RXBUFPOST_DEFAULT;
487e5ec1e72Spatrick 
488e5ec1e72Spatrick 	/* Alternative offset of data in a packet */
489e5ec1e72Spatrick 	sc->sc_rx_dataoffset = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
490e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_RX_DATAOFFSET);
491e5ec1e72Spatrick 
492e5ec1e72Spatrick 	/* For Power Management */
493e5ec1e72Spatrick 	sc->sc_htod_mb_data_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
494e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_HTOD_MB_DATA_ADDR);
495e5ec1e72Spatrick 	sc->sc_dtoh_mb_data_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
496e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DTOH_MB_DATA_ADDR);
497e5ec1e72Spatrick 
498e5ec1e72Spatrick 	/* Ring information */
499e5ec1e72Spatrick 	sc->sc_ring_info_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
500e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_RING_INFO_ADDR);
501e5ec1e72Spatrick 
502e5ec1e72Spatrick 	/* Firmware's "dmesg" */
503e5ec1e72Spatrick 	sc->sc_console_base_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
504e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_CONSOLE_ADDR);
505e5ec1e72Spatrick 	sc->sc_console_buf_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
506e5ec1e72Spatrick 	    sc->sc_console_base_addr + BWFM_CONSOLE_BUFADDR);
507e5ec1e72Spatrick 	sc->sc_console_buf_size = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
508e5ec1e72Spatrick 	    sc->sc_console_base_addr + BWFM_CONSOLE_BUFSIZE);
509e5ec1e72Spatrick 
510e5ec1e72Spatrick 	/* Read ring information. */
511e5ec1e72Spatrick 	bus_space_read_region_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
512e5ec1e72Spatrick 	    sc->sc_ring_info_addr, (void *)&ringinfo, sizeof(ringinfo));
513e5ec1e72Spatrick 
514e5ec1e72Spatrick 	if (sc->sc_shared_version >= 6) {
515e5ec1e72Spatrick 		sc->sc_max_submissionrings = le16toh(ringinfo.max_submissionrings);
516e5ec1e72Spatrick 		sc->sc_max_flowrings = le16toh(ringinfo.max_flowrings);
517e5ec1e72Spatrick 		sc->sc_max_completionrings = le16toh(ringinfo.max_completionrings);
518e5ec1e72Spatrick 	} else {
519e5ec1e72Spatrick 		sc->sc_max_submissionrings = le16toh(ringinfo.max_flowrings);
520e5ec1e72Spatrick 		sc->sc_max_flowrings = sc->sc_max_submissionrings -
521e5ec1e72Spatrick 		    BWFM_NUM_TX_MSGRINGS;
522e5ec1e72Spatrick 		sc->sc_max_completionrings = BWFM_NUM_RX_MSGRINGS;
523e5ec1e72Spatrick 	}
524e5ec1e72Spatrick 
525e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
526e5ec1e72Spatrick 		d2h_w_idx_ptr = letoh32(ringinfo.d2h_w_idx_ptr);
527e5ec1e72Spatrick 		d2h_r_idx_ptr = letoh32(ringinfo.d2h_r_idx_ptr);
528e5ec1e72Spatrick 		h2d_w_idx_ptr = letoh32(ringinfo.h2d_w_idx_ptr);
529e5ec1e72Spatrick 		h2d_r_idx_ptr = letoh32(ringinfo.h2d_r_idx_ptr);
530e5ec1e72Spatrick 		idx_offset = sizeof(uint32_t);
531e5ec1e72Spatrick 	} else {
532e5ec1e72Spatrick 		uint64_t address;
533e5ec1e72Spatrick 
534e5ec1e72Spatrick 		/* Each TX/RX Ring has a Read and Write Ptr */
535e5ec1e72Spatrick 		sc->sc_dma_idx_bufsz = (sc->sc_max_submissionrings +
536e5ec1e72Spatrick 		    sc->sc_max_completionrings) * sc->sc_dma_idx_sz * 2;
537e5ec1e72Spatrick 		sc->sc_dma_idx_buf = bwfm_pci_dmamem_alloc(sc,
538e5ec1e72Spatrick 		    sc->sc_dma_idx_bufsz, 8);
539e5ec1e72Spatrick 		if (sc->sc_dma_idx_buf == NULL) {
540e5ec1e72Spatrick 			/* XXX: Fallback to TCM? */
541e5ec1e72Spatrick 			printf("%s: cannot allocate idx buf\n",
542e5ec1e72Spatrick 			    DEVNAME(sc));
543972218f3Spatrick 			return 1;
544e5ec1e72Spatrick 		}
545e5ec1e72Spatrick 
546e5ec1e72Spatrick 		idx_offset = sc->sc_dma_idx_sz;
547e5ec1e72Spatrick 		h2d_w_idx_ptr = 0;
548e5ec1e72Spatrick 		address = BWFM_PCI_DMA_DVA(sc->sc_dma_idx_buf);
549e5ec1e72Spatrick 		ringinfo.h2d_w_idx_hostaddr_low =
550e5ec1e72Spatrick 		    htole32(address & 0xffffffff);
551e5ec1e72Spatrick 		ringinfo.h2d_w_idx_hostaddr_high =
552e5ec1e72Spatrick 		    htole32(address >> 32);
553e5ec1e72Spatrick 
554e5ec1e72Spatrick 		h2d_r_idx_ptr = h2d_w_idx_ptr +
555e5ec1e72Spatrick 		    sc->sc_max_submissionrings * idx_offset;
556e5ec1e72Spatrick 		address += sc->sc_max_submissionrings * idx_offset;
557e5ec1e72Spatrick 		ringinfo.h2d_r_idx_hostaddr_low =
558e5ec1e72Spatrick 		    htole32(address & 0xffffffff);
559e5ec1e72Spatrick 		ringinfo.h2d_r_idx_hostaddr_high =
560e5ec1e72Spatrick 		    htole32(address >> 32);
561e5ec1e72Spatrick 
562e5ec1e72Spatrick 		d2h_w_idx_ptr = h2d_r_idx_ptr +
563e5ec1e72Spatrick 		    sc->sc_max_submissionrings * idx_offset;
564e5ec1e72Spatrick 		address += sc->sc_max_submissionrings * idx_offset;
565e5ec1e72Spatrick 		ringinfo.d2h_w_idx_hostaddr_low =
566e5ec1e72Spatrick 		    htole32(address & 0xffffffff);
567e5ec1e72Spatrick 		ringinfo.d2h_w_idx_hostaddr_high =
568e5ec1e72Spatrick 		    htole32(address >> 32);
569e5ec1e72Spatrick 
570e5ec1e72Spatrick 		d2h_r_idx_ptr = d2h_w_idx_ptr +
571e5ec1e72Spatrick 		    sc->sc_max_completionrings * idx_offset;
572e5ec1e72Spatrick 		address += sc->sc_max_completionrings * idx_offset;
573e5ec1e72Spatrick 		ringinfo.d2h_r_idx_hostaddr_low =
574e5ec1e72Spatrick 		    htole32(address & 0xffffffff);
575e5ec1e72Spatrick 		ringinfo.d2h_r_idx_hostaddr_high =
576e5ec1e72Spatrick 		    htole32(address >> 32);
577e5ec1e72Spatrick 
578e5ec1e72Spatrick 		bus_space_write_region_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
579e5ec1e72Spatrick 		    sc->sc_ring_info_addr, (void *)&ringinfo, sizeof(ringinfo));
580e5ec1e72Spatrick 	}
581e5ec1e72Spatrick 
582e5ec1e72Spatrick 	uint32_t ring_mem_ptr = letoh32(ringinfo.ringmem);
583e5ec1e72Spatrick 	/* TX ctrl ring: Send ctrl buffers, send IOCTLs */
584e5ec1e72Spatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_ctrl_submit, 64, 40,
585e5ec1e72Spatrick 	    h2d_w_idx_ptr, h2d_r_idx_ptr, 0, idx_offset,
586e5ec1e72Spatrick 	    &ring_mem_ptr))
587e5ec1e72Spatrick 		goto cleanup;
588e5ec1e72Spatrick 	/* TX rxpost ring: Send clean data mbufs for RX */
589e5ec1e72Spatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_rxpost_submit, 512, 32,
590e5ec1e72Spatrick 	    h2d_w_idx_ptr, h2d_r_idx_ptr, 1, idx_offset,
591e5ec1e72Spatrick 	    &ring_mem_ptr))
592e5ec1e72Spatrick 		goto cleanup;
593e5ec1e72Spatrick 	/* RX completion rings: recv our filled buffers back */
594e5ec1e72Spatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_ctrl_complete, 64, 24,
595e5ec1e72Spatrick 	    d2h_w_idx_ptr, d2h_r_idx_ptr, 0, idx_offset,
596e5ec1e72Spatrick 	    &ring_mem_ptr))
597e5ec1e72Spatrick 		goto cleanup;
598095b0c44Spatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_tx_complete, 1024,
599095b0c44Spatrick 	    sc->sc_shared_version >= 7 ? 24 : 16,
600e5ec1e72Spatrick 	    d2h_w_idx_ptr, d2h_r_idx_ptr, 1, idx_offset,
601e5ec1e72Spatrick 	    &ring_mem_ptr))
602e5ec1e72Spatrick 		goto cleanup;
603095b0c44Spatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_rx_complete, 512,
604095b0c44Spatrick 	    sc->sc_shared_version >= 7 ? 40 : 32,
605e5ec1e72Spatrick 	    d2h_w_idx_ptr, d2h_r_idx_ptr, 2, idx_offset,
606e5ec1e72Spatrick 	    &ring_mem_ptr))
607e5ec1e72Spatrick 		goto cleanup;
608e5ec1e72Spatrick 
609e5ec1e72Spatrick 	/* Dynamic TX rings for actual data */
610e5ec1e72Spatrick 	sc->sc_flowrings = malloc(sc->sc_max_flowrings *
611e5ec1e72Spatrick 	    sizeof(struct bwfm_pci_msgring), M_DEVBUF, M_WAITOK | M_ZERO);
612518be5f3Spatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
613518be5f3Spatrick 		struct bwfm_pci_msgring *ring = &sc->sc_flowrings[i];
614518be5f3Spatrick 		ring->w_idx_addr = h2d_w_idx_ptr + (i + 2) * idx_offset;
615518be5f3Spatrick 		ring->r_idx_addr = h2d_r_idx_ptr + (i + 2) * idx_offset;
616518be5f3Spatrick 	}
617e5ec1e72Spatrick 
618e5ec1e72Spatrick 	/* Scratch and ring update buffers for firmware */
619e5ec1e72Spatrick 	if ((sc->sc_scratch_buf = bwfm_pci_dmamem_alloc(sc,
620e5ec1e72Spatrick 	    BWFM_DMA_D2H_SCRATCH_BUF_LEN, 8)) == NULL)
621e5ec1e72Spatrick 		goto cleanup;
622e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
623e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_SCRATCH_ADDR_LOW,
624e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(sc->sc_scratch_buf) & 0xffffffff);
625e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
626e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_SCRATCH_ADDR_HIGH,
627e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(sc->sc_scratch_buf) >> 32);
628e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
629e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_SCRATCH_LEN,
630e5ec1e72Spatrick 	    BWFM_DMA_D2H_SCRATCH_BUF_LEN);
631e5ec1e72Spatrick 
632e5ec1e72Spatrick 	if ((sc->sc_ringupd_buf = bwfm_pci_dmamem_alloc(sc,
633e5ec1e72Spatrick 	    BWFM_DMA_D2H_RINGUPD_BUF_LEN, 8)) == NULL)
634e5ec1e72Spatrick 		goto cleanup;
635e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
636e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_RINGUPD_ADDR_LOW,
637e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(sc->sc_ringupd_buf) & 0xffffffff);
638e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
639e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_RINGUPD_ADDR_HIGH,
640e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(sc->sc_ringupd_buf) >> 32);
641e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
642e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_RINGUPD_LEN,
643e5ec1e72Spatrick 	    BWFM_DMA_D2H_RINGUPD_BUF_LEN);
644e5ec1e72Spatrick 
645e5ec1e72Spatrick 	bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2);
646e5ec1e72Spatrick 	bwfm_pci_intr_enable(sc);
647*156d2677Spatrick 	bwfm_pci_hostready(sc);
648e5ec1e72Spatrick 
649e5ec1e72Spatrick 	/* Maps RX mbufs to a packet id and back. */
650e5ec1e72Spatrick 	sc->sc_rx_pkts.npkt = BWFM_NUM_RX_PKTIDS;
651e5ec1e72Spatrick 	sc->sc_rx_pkts.pkts = malloc(BWFM_NUM_RX_PKTIDS *
652e5ec1e72Spatrick 	    sizeof(struct bwfm_pci_buf), M_DEVBUF, M_WAITOK | M_ZERO);
653e5ec1e72Spatrick 	for (i = 0; i < BWFM_NUM_RX_PKTIDS; i++)
654e5ec1e72Spatrick 		bus_dmamap_create(sc->sc_dmat, MSGBUF_MAX_PKT_SIZE,
655e5ec1e72Spatrick 		    BWFM_NUM_RX_DESCS, MSGBUF_MAX_PKT_SIZE, 0, BUS_DMA_WAITOK,
656e5ec1e72Spatrick 		    &sc->sc_rx_pkts.pkts[i].bb_map);
657e5ec1e72Spatrick 
658e5ec1e72Spatrick 	/* Maps TX mbufs to a packet id and back. */
659f416501bSpatrick 	sc->sc_tx_pkts.npkt = BWFM_NUM_TX_PKTIDS;
660e5ec1e72Spatrick 	sc->sc_tx_pkts.pkts = malloc(BWFM_NUM_TX_PKTIDS
661e5ec1e72Spatrick 	    * sizeof(struct bwfm_pci_buf), M_DEVBUF, M_WAITOK | M_ZERO);
662e5ec1e72Spatrick 	for (i = 0; i < BWFM_NUM_TX_PKTIDS; i++)
663e5ec1e72Spatrick 		bus_dmamap_create(sc->sc_dmat, MSGBUF_MAX_PKT_SIZE,
664e5ec1e72Spatrick 		    BWFM_NUM_TX_DESCS, MSGBUF_MAX_PKT_SIZE, 0, BUS_DMA_WAITOK,
665e5ec1e72Spatrick 		    &sc->sc_tx_pkts.pkts[i].bb_map);
666e5ec1e72Spatrick 
6672eeba925Spatrick 	/* Maps IOCTL mbufs to a packet id and back. */
6682eeba925Spatrick 	sc->sc_ioctl_pkts.npkt = BWFM_NUM_IOCTL_PKTIDS;
6692eeba925Spatrick 	sc->sc_ioctl_pkts.pkts = malloc(BWFM_NUM_IOCTL_PKTIDS
6702eeba925Spatrick 	    * sizeof(struct bwfm_pci_buf), M_DEVBUF, M_WAITOK | M_ZERO);
6712eeba925Spatrick 	for (i = 0; i < BWFM_NUM_IOCTL_PKTIDS; i++)
6722eeba925Spatrick 		bus_dmamap_create(sc->sc_dmat, MSGBUF_MAX_PKT_SIZE,
6732eeba925Spatrick 		    BWFM_NUM_IOCTL_DESCS, MSGBUF_MAX_PKT_SIZE, 0, BUS_DMA_WAITOK,
6742eeba925Spatrick 		    &sc->sc_ioctl_pkts.pkts[i].bb_map);
6752eeba925Spatrick 
67618722113Spatrick 	/*
67718722113Spatrick 	 * For whatever reason, could also be a bug somewhere in this
67818722113Spatrick 	 * driver, the firmware needs a bunch of RX buffers otherwise
67918722113Spatrick 	 * it won't send any RX complete messages.  64 buffers don't
68018722113Spatrick 	 * suffice, but 128 buffers are enough.
68118722113Spatrick 	 */
68218722113Spatrick 	if_rxr_init(&sc->sc_rxbuf_ring, 128, sc->sc_max_rxbufpost);
683e5ec1e72Spatrick 	if_rxr_init(&sc->sc_ioctl_ring, 8, 8);
684e5ec1e72Spatrick 	if_rxr_init(&sc->sc_event_ring, 8, 8);
685e5ec1e72Spatrick 	bwfm_pci_fill_rx_rings(sc);
686e5ec1e72Spatrick 
6872eeba925Spatrick 	TAILQ_INIT(&sc->sc_ioctlq);
6882eeba925Spatrick 
689cadf5fcfSpatrick #ifdef BWFM_DEBUG
690cadf5fcfSpatrick 	sc->sc_console_readidx = 0;
691cadf5fcfSpatrick 	bwfm_pci_debug_console(sc);
692cadf5fcfSpatrick #endif
693cadf5fcfSpatrick 
694972218f3Spatrick 	sc->sc_initialized = 1;
695972218f3Spatrick 	return 0;
696e5ec1e72Spatrick 
697e5ec1e72Spatrick cleanup:
698e5ec1e72Spatrick 	if (sc->sc_ringupd_buf)
699e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_ringupd_buf);
700e5ec1e72Spatrick 	if (sc->sc_scratch_buf)
701e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_scratch_buf);
702e5ec1e72Spatrick 	if (sc->sc_rx_complete.ring)
703e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_rx_complete.ring);
704e5ec1e72Spatrick 	if (sc->sc_tx_complete.ring)
705e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_tx_complete.ring);
706e5ec1e72Spatrick 	if (sc->sc_ctrl_complete.ring)
707e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_ctrl_complete.ring);
708e5ec1e72Spatrick 	if (sc->sc_rxpost_submit.ring)
709e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_rxpost_submit.ring);
710e5ec1e72Spatrick 	if (sc->sc_ctrl_submit.ring)
711e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_ctrl_submit.ring);
712e5ec1e72Spatrick 	if (sc->sc_dma_idx_buf)
713e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_dma_idx_buf);
714972218f3Spatrick 	return 1;
715e5ec1e72Spatrick }
716e5ec1e72Spatrick 
717e5ec1e72Spatrick int
7186aad491fSpatrick bwfm_pci_load_microcode(struct bwfm_pci_softc *sc, const u_char *ucode, size_t size,
7196aad491fSpatrick     const u_char *nvram, size_t nvlen)
720e5ec1e72Spatrick {
721e5ec1e72Spatrick 	struct bwfm_softc *bwfm = (void *)sc;
722e5ec1e72Spatrick 	struct bwfm_core *core;
7236aad491fSpatrick 	uint32_t shared, written;
724e5ec1e72Spatrick 	int i;
725e5ec1e72Spatrick 
726e5ec1e72Spatrick 	if (bwfm->sc_chip.ch_chip == BRCM_CC_43602_CHIP_ID) {
727e5ec1e72Spatrick 		bwfm_pci_select_core(sc, BWFM_AGENT_CORE_ARM_CR4);
728e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
729e5ec1e72Spatrick 		    BWFM_PCI_ARMCR4REG_BANKIDX, 5);
730e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
731e5ec1e72Spatrick 		    BWFM_PCI_ARMCR4REG_BANKPDA, 0);
732e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
733e5ec1e72Spatrick 		    BWFM_PCI_ARMCR4REG_BANKIDX, 7);
734e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
735e5ec1e72Spatrick 		    BWFM_PCI_ARMCR4REG_BANKPDA, 0);
736e5ec1e72Spatrick 	}
737e5ec1e72Spatrick 
738e5ec1e72Spatrick 	for (i = 0; i < size; i++)
739e5ec1e72Spatrick 		bus_space_write_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
740e5ec1e72Spatrick 		    bwfm->sc_chip.ch_rambase + i, ucode[i]);
741e5ec1e72Spatrick 
742e5ec1e72Spatrick 	/* Firmware replaces this with a pointer once up. */
743e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
744e5ec1e72Spatrick 	    bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize - 4, 0);
745e5ec1e72Spatrick 
7466aad491fSpatrick 	if (nvram) {
7476aad491fSpatrick 		for (i = 0; i < nvlen; i++)
7486aad491fSpatrick 			bus_space_write_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
7496aad491fSpatrick 			    bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize
7506aad491fSpatrick 			    - nvlen  + i, nvram[i]);
7516aad491fSpatrick 	}
7526aad491fSpatrick 
7536aad491fSpatrick 	written = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
7546aad491fSpatrick 	    bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize - 4);
755e5ec1e72Spatrick 
756e5ec1e72Spatrick 	/* Load reset vector from firmware and kickstart core. */
757b0cd4990Spatrick 	if (bwfm->sc_chip.ch_chip == BRCM_CC_43602_CHIP_ID) {
758e5ec1e72Spatrick 		core = bwfm_chip_get_core(bwfm, BWFM_AGENT_INTERNAL_MEM);
759e5ec1e72Spatrick 		bwfm->sc_chip.ch_core_reset(bwfm, core, 0, 0, 0);
760b0cd4990Spatrick 	}
761e5ec1e72Spatrick 	bwfm_chip_set_active(bwfm, *(uint32_t *)ucode);
762e5ec1e72Spatrick 
7633c53ddefSpatrick 	for (i = 0; i < 100; i++) {
764e5ec1e72Spatrick 		delay(50 * 1000);
765e5ec1e72Spatrick 		shared = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
766e5ec1e72Spatrick 		    bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize - 4);
7676aad491fSpatrick 		if (shared != written)
768e5ec1e72Spatrick 			break;
769e5ec1e72Spatrick 	}
77019871452Spatrick 	if (shared == written) {
771e5ec1e72Spatrick 		printf("%s: firmware did not come up\n", DEVNAME(sc));
772e5ec1e72Spatrick 		return 1;
773e5ec1e72Spatrick 	}
77419871452Spatrick 	if (shared < bwfm->sc_chip.ch_rambase ||
77519871452Spatrick 	    shared >= bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize) {
77619871452Spatrick 		printf("%s: invalid shared RAM address 0x%08x\n", DEVNAME(sc),
77719871452Spatrick 		    shared);
77819871452Spatrick 		return 1;
77919871452Spatrick 	}
780e5ec1e72Spatrick 
781e5ec1e72Spatrick 	sc->sc_shared_address = shared;
782e5ec1e72Spatrick 	return 0;
783e5ec1e72Spatrick }
784e5ec1e72Spatrick 
785e5ec1e72Spatrick int
786e5ec1e72Spatrick bwfm_pci_detach(struct device *self, int flags)
787e5ec1e72Spatrick {
788e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (struct bwfm_pci_softc *)self;
789e5ec1e72Spatrick 
790e5ec1e72Spatrick 	bwfm_detach(&sc->sc_sc, flags);
791e5ec1e72Spatrick 
792e5ec1e72Spatrick 	/* FIXME: free RX buffers */
793e5ec1e72Spatrick 	/* FIXME: free TX buffers */
794e5ec1e72Spatrick 	/* FIXME: free more memory */
795e5ec1e72Spatrick 
796e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_ringupd_buf);
797e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_scratch_buf);
798e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_rx_complete.ring);
799e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_tx_complete.ring);
800e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_ctrl_complete.ring);
801e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_rxpost_submit.ring);
802e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_ctrl_submit.ring);
803e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_dma_idx_buf);
804e5ec1e72Spatrick 	return 0;
805e5ec1e72Spatrick }
806e5ec1e72Spatrick 
807e5ec1e72Spatrick /* DMA code */
808e5ec1e72Spatrick struct bwfm_pci_dmamem *
809e5ec1e72Spatrick bwfm_pci_dmamem_alloc(struct bwfm_pci_softc *sc, bus_size_t size, bus_size_t align)
810e5ec1e72Spatrick {
811e5ec1e72Spatrick 	struct bwfm_pci_dmamem *bdm;
812e5ec1e72Spatrick 	int nsegs;
813e5ec1e72Spatrick 
814e5ec1e72Spatrick 	bdm = malloc(sizeof(*bdm), M_DEVBUF, M_WAITOK | M_ZERO);
815e5ec1e72Spatrick 	bdm->bdm_size = size;
816e5ec1e72Spatrick 
817e5ec1e72Spatrick 	if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
818e5ec1e72Spatrick 	    BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &bdm->bdm_map) != 0)
819e5ec1e72Spatrick 		goto bdmfree;
820e5ec1e72Spatrick 
821e5ec1e72Spatrick 	if (bus_dmamem_alloc(sc->sc_dmat, size, align, 0, &bdm->bdm_seg, 1,
822e5ec1e72Spatrick 	    &nsegs, BUS_DMA_WAITOK) != 0)
823e5ec1e72Spatrick 		goto destroy;
824e5ec1e72Spatrick 
825e5ec1e72Spatrick 	if (bus_dmamem_map(sc->sc_dmat, &bdm->bdm_seg, nsegs, size,
826e5ec1e72Spatrick 	    &bdm->bdm_kva, BUS_DMA_WAITOK | BUS_DMA_COHERENT) != 0)
827e5ec1e72Spatrick 		goto free;
828e5ec1e72Spatrick 
829e5ec1e72Spatrick 	if (bus_dmamap_load(sc->sc_dmat, bdm->bdm_map, bdm->bdm_kva, size,
830e5ec1e72Spatrick 	    NULL, BUS_DMA_WAITOK) != 0)
831e5ec1e72Spatrick 		goto unmap;
832e5ec1e72Spatrick 
833e5ec1e72Spatrick 	bzero(bdm->bdm_kva, size);
834e5ec1e72Spatrick 
835e5ec1e72Spatrick 	return (bdm);
836e5ec1e72Spatrick 
837e5ec1e72Spatrick unmap:
838e5ec1e72Spatrick 	bus_dmamem_unmap(sc->sc_dmat, bdm->bdm_kva, size);
839e5ec1e72Spatrick free:
840e5ec1e72Spatrick 	bus_dmamem_free(sc->sc_dmat, &bdm->bdm_seg, 1);
841e5ec1e72Spatrick destroy:
842e5ec1e72Spatrick 	bus_dmamap_destroy(sc->sc_dmat, bdm->bdm_map);
843e5ec1e72Spatrick bdmfree:
84465046b40Spatrick 	free(bdm, M_DEVBUF, sizeof(*bdm));
845e5ec1e72Spatrick 
846e5ec1e72Spatrick 	return (NULL);
847e5ec1e72Spatrick }
848e5ec1e72Spatrick 
849e5ec1e72Spatrick void
850e5ec1e72Spatrick bwfm_pci_dmamem_free(struct bwfm_pci_softc *sc, struct bwfm_pci_dmamem *bdm)
851e5ec1e72Spatrick {
852e5ec1e72Spatrick 	bus_dmamem_unmap(sc->sc_dmat, bdm->bdm_kva, bdm->bdm_size);
853e5ec1e72Spatrick 	bus_dmamem_free(sc->sc_dmat, &bdm->bdm_seg, 1);
854e5ec1e72Spatrick 	bus_dmamap_destroy(sc->sc_dmat, bdm->bdm_map);
85565046b40Spatrick 	free(bdm, M_DEVBUF, sizeof(*bdm));
856e5ec1e72Spatrick }
857e5ec1e72Spatrick 
858e5ec1e72Spatrick /*
859e5ec1e72Spatrick  * We need a simple mapping from a packet ID to mbufs, because when
860e5ec1e72Spatrick  * a transfer completed, we only know the ID so we have to look up
861e5ec1e72Spatrick  * the memory for the ID.  This simply looks for an empty slot.
862e5ec1e72Spatrick  */
863e5ec1e72Spatrick int
86402ee7d07Spatrick bwfm_pci_pktid_avail(struct bwfm_pci_softc *sc, struct bwfm_pci_pkts *pkts)
86502ee7d07Spatrick {
86602ee7d07Spatrick 	int i, idx;
86702ee7d07Spatrick 
86802ee7d07Spatrick 	idx = pkts->last + 1;
86902ee7d07Spatrick 	for (i = 0; i < pkts->npkt; i++) {
87002ee7d07Spatrick 		if (idx == pkts->npkt)
87102ee7d07Spatrick 			idx = 0;
87202ee7d07Spatrick 		if (pkts->pkts[idx].bb_m == NULL)
87302ee7d07Spatrick 			return 0;
87402ee7d07Spatrick 		idx++;
87502ee7d07Spatrick 	}
87602ee7d07Spatrick 	return ENOBUFS;
87702ee7d07Spatrick }
87802ee7d07Spatrick 
87902ee7d07Spatrick int
880e5ec1e72Spatrick bwfm_pci_pktid_new(struct bwfm_pci_softc *sc, struct bwfm_pci_pkts *pkts,
881e5ec1e72Spatrick     struct mbuf *m, uint32_t *pktid, paddr_t *paddr)
882e5ec1e72Spatrick {
883e5ec1e72Spatrick 	int i, idx;
884e5ec1e72Spatrick 
885e5ec1e72Spatrick 	idx = pkts->last + 1;
886e5ec1e72Spatrick 	for (i = 0; i < pkts->npkt; i++) {
887e5ec1e72Spatrick 		if (idx == pkts->npkt)
888e5ec1e72Spatrick 			idx = 0;
889e5ec1e72Spatrick 		if (pkts->pkts[idx].bb_m == NULL) {
890e5ec1e72Spatrick 			if (bus_dmamap_load_mbuf(sc->sc_dmat,
891e5ec1e72Spatrick 			    pkts->pkts[idx].bb_map, m, BUS_DMA_NOWAIT) != 0) {
892518be5f3Spatrick 				if (m_defrag(m, M_DONTWAIT))
893518be5f3Spatrick 					return EFBIG;
894518be5f3Spatrick 				if (bus_dmamap_load_mbuf(sc->sc_dmat,
895518be5f3Spatrick 				    pkts->pkts[idx].bb_map, m, BUS_DMA_NOWAIT) != 0)
896518be5f3Spatrick 					return EFBIG;
897e5ec1e72Spatrick 			}
898dcb67343Spatrick 			bus_dmamap_sync(sc->sc_dmat, pkts->pkts[idx].bb_map,
899dcb67343Spatrick 			    0, pkts->pkts[idx].bb_map->dm_mapsize,
900dcb67343Spatrick 			    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
901e5ec1e72Spatrick 			pkts->last = idx;
902e5ec1e72Spatrick 			pkts->pkts[idx].bb_m = m;
903e5ec1e72Spatrick 			*pktid = idx;
904e5ec1e72Spatrick 			*paddr = pkts->pkts[idx].bb_map->dm_segs[0].ds_addr;
905e5ec1e72Spatrick 			return 0;
906e5ec1e72Spatrick 		}
907e5ec1e72Spatrick 		idx++;
908e5ec1e72Spatrick 	}
909518be5f3Spatrick 	return ENOBUFS;
910e5ec1e72Spatrick }
911e5ec1e72Spatrick 
912e5ec1e72Spatrick struct mbuf *
913e5ec1e72Spatrick bwfm_pci_pktid_free(struct bwfm_pci_softc *sc, struct bwfm_pci_pkts *pkts,
914e5ec1e72Spatrick     uint32_t pktid)
915e5ec1e72Spatrick {
916e5ec1e72Spatrick 	struct mbuf *m;
917e5ec1e72Spatrick 
918e5ec1e72Spatrick 	if (pktid >= pkts->npkt || pkts->pkts[pktid].bb_m == NULL)
919e5ec1e72Spatrick 		return NULL;
920dcb67343Spatrick 	bus_dmamap_sync(sc->sc_dmat, pkts->pkts[pktid].bb_map, 0,
921dcb67343Spatrick 	    pkts->pkts[pktid].bb_map->dm_mapsize,
922dcb67343Spatrick 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
923e5ec1e72Spatrick 	bus_dmamap_unload(sc->sc_dmat, pkts->pkts[pktid].bb_map);
924e5ec1e72Spatrick 	m = pkts->pkts[pktid].bb_m;
925e5ec1e72Spatrick 	pkts->pkts[pktid].bb_m = NULL;
926e5ec1e72Spatrick 	return m;
927e5ec1e72Spatrick }
928e5ec1e72Spatrick 
929e5ec1e72Spatrick void
930e5ec1e72Spatrick bwfm_pci_fill_rx_rings(struct bwfm_pci_softc *sc)
931e5ec1e72Spatrick {
93218722113Spatrick 	bwfm_pci_fill_rx_buf_ring(sc);
933e5ec1e72Spatrick 	bwfm_pci_fill_rx_ioctl_ring(sc, &sc->sc_ioctl_ring,
934e5ec1e72Spatrick 	    MSGBUF_TYPE_IOCTLRESP_BUF_POST);
935e5ec1e72Spatrick 	bwfm_pci_fill_rx_ioctl_ring(sc, &sc->sc_event_ring,
936e5ec1e72Spatrick 	    MSGBUF_TYPE_EVENT_BUF_POST);
937e5ec1e72Spatrick }
938e5ec1e72Spatrick 
939e5ec1e72Spatrick void
940e5ec1e72Spatrick bwfm_pci_fill_rx_ioctl_ring(struct bwfm_pci_softc *sc, struct if_rxring *rxring,
941e5ec1e72Spatrick     uint32_t msgtype)
942e5ec1e72Spatrick {
943e5ec1e72Spatrick 	struct msgbuf_rx_ioctl_resp_or_event *req;
944e5ec1e72Spatrick 	struct mbuf *m;
945e5ec1e72Spatrick 	uint32_t pktid;
946e5ec1e72Spatrick 	paddr_t paddr;
947e5ec1e72Spatrick 	int s, slots;
948e5ec1e72Spatrick 
949e5ec1e72Spatrick 	s = splnet();
950e5ec1e72Spatrick 	for (slots = if_rxr_get(rxring, 8); slots > 0; slots--) {
95102ee7d07Spatrick 		if (bwfm_pci_pktid_avail(sc, &sc->sc_rx_pkts))
95202ee7d07Spatrick 			break;
953e5ec1e72Spatrick 		req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit);
954e5ec1e72Spatrick 		if (req == NULL)
955e5ec1e72Spatrick 			break;
956471f2571Sjan 		m = MCLGETL(NULL, M_DONTWAIT, MSGBUF_MAX_PKT_SIZE);
957e5ec1e72Spatrick 		if (m == NULL) {
958e5ec1e72Spatrick 			bwfm_pci_ring_write_cancel(sc, &sc->sc_ctrl_submit, 1);
959e5ec1e72Spatrick 			break;
960e5ec1e72Spatrick 		}
961e5ec1e72Spatrick 		m->m_len = m->m_pkthdr.len = MSGBUF_MAX_PKT_SIZE;
962e5ec1e72Spatrick 		if (bwfm_pci_pktid_new(sc, &sc->sc_rx_pkts, m, &pktid, &paddr)) {
963e5ec1e72Spatrick 			bwfm_pci_ring_write_cancel(sc, &sc->sc_ctrl_submit, 1);
964e5ec1e72Spatrick 			m_freem(m);
965e5ec1e72Spatrick 			break;
966e5ec1e72Spatrick 		}
967e5ec1e72Spatrick 		memset(req, 0, sizeof(*req));
968e5ec1e72Spatrick 		req->msg.msgtype = msgtype;
969e5ec1e72Spatrick 		req->msg.request_id = htole32(pktid);
970e5ec1e72Spatrick 		req->host_buf_len = htole16(MSGBUF_MAX_PKT_SIZE);
971e4dae658Spatrick 		req->host_buf_addr.high_addr = htole32((uint64_t)paddr >> 32);
972e5ec1e72Spatrick 		req->host_buf_addr.low_addr = htole32(paddr & 0xffffffff);
973e5ec1e72Spatrick 		bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit);
974e5ec1e72Spatrick 	}
975e5ec1e72Spatrick 	if_rxr_put(rxring, slots);
976e5ec1e72Spatrick 	splx(s);
977e5ec1e72Spatrick }
978e5ec1e72Spatrick 
979e5ec1e72Spatrick void
980e5ec1e72Spatrick bwfm_pci_fill_rx_buf_ring(struct bwfm_pci_softc *sc)
981e5ec1e72Spatrick {
982e5ec1e72Spatrick 	struct msgbuf_rx_bufpost *req;
983e5ec1e72Spatrick 	struct mbuf *m;
984e5ec1e72Spatrick 	uint32_t pktid;
985e5ec1e72Spatrick 	paddr_t paddr;
986e5ec1e72Spatrick 	int s, slots;
987e5ec1e72Spatrick 
988e5ec1e72Spatrick 	s = splnet();
989e5ec1e72Spatrick 	for (slots = if_rxr_get(&sc->sc_rxbuf_ring, sc->sc_max_rxbufpost);
990e5ec1e72Spatrick 	    slots > 0; slots--) {
99102ee7d07Spatrick 		if (bwfm_pci_pktid_avail(sc, &sc->sc_rx_pkts))
99202ee7d07Spatrick 			break;
993e5ec1e72Spatrick 		req = bwfm_pci_ring_write_reserve(sc, &sc->sc_rxpost_submit);
994e5ec1e72Spatrick 		if (req == NULL)
995e5ec1e72Spatrick 			break;
996471f2571Sjan 		m = MCLGETL(NULL, M_DONTWAIT, MSGBUF_MAX_PKT_SIZE);
997e5ec1e72Spatrick 		if (m == NULL) {
998e5ec1e72Spatrick 			bwfm_pci_ring_write_cancel(sc, &sc->sc_rxpost_submit, 1);
999e5ec1e72Spatrick 			break;
1000e5ec1e72Spatrick 		}
1001e5ec1e72Spatrick 		m->m_len = m->m_pkthdr.len = MSGBUF_MAX_PKT_SIZE;
1002e5ec1e72Spatrick 		if (bwfm_pci_pktid_new(sc, &sc->sc_rx_pkts, m, &pktid, &paddr)) {
1003e5ec1e72Spatrick 			bwfm_pci_ring_write_cancel(sc, &sc->sc_rxpost_submit, 1);
1004e5ec1e72Spatrick 			m_freem(m);
1005e5ec1e72Spatrick 			break;
1006e5ec1e72Spatrick 		}
1007e5ec1e72Spatrick 		memset(req, 0, sizeof(*req));
1008e5ec1e72Spatrick 		req->msg.msgtype = MSGBUF_TYPE_RXBUF_POST;
1009e5ec1e72Spatrick 		req->msg.request_id = htole32(pktid);
1010e5ec1e72Spatrick 		req->data_buf_len = htole16(MSGBUF_MAX_PKT_SIZE);
1011e4dae658Spatrick 		req->data_buf_addr.high_addr = htole32((uint64_t)paddr >> 32);
1012e5ec1e72Spatrick 		req->data_buf_addr.low_addr = htole32(paddr & 0xffffffff);
1013e5ec1e72Spatrick 		bwfm_pci_ring_write_commit(sc, &sc->sc_rxpost_submit);
1014e5ec1e72Spatrick 	}
1015e5ec1e72Spatrick 	if_rxr_put(&sc->sc_rxbuf_ring, slots);
1016e5ec1e72Spatrick 	splx(s);
1017e5ec1e72Spatrick }
1018e5ec1e72Spatrick 
1019e5ec1e72Spatrick int
1020e5ec1e72Spatrick bwfm_pci_setup_ring(struct bwfm_pci_softc *sc, struct bwfm_pci_msgring *ring,
1021e5ec1e72Spatrick     int nitem, size_t itemsz, uint32_t w_idx, uint32_t r_idx,
1022e5ec1e72Spatrick     int idx, uint32_t idx_off, uint32_t *ring_mem)
1023e5ec1e72Spatrick {
1024e5ec1e72Spatrick 	ring->w_idx_addr = w_idx + idx * idx_off;
1025e5ec1e72Spatrick 	ring->r_idx_addr = r_idx + idx * idx_off;
1026e5ec1e72Spatrick 	ring->nitem = nitem;
1027e5ec1e72Spatrick 	ring->itemsz = itemsz;
1028e5ec1e72Spatrick 	bwfm_pci_ring_write_rptr(sc, ring);
1029e5ec1e72Spatrick 	bwfm_pci_ring_write_wptr(sc, ring);
1030e5ec1e72Spatrick 
1031e5ec1e72Spatrick 	ring->ring = bwfm_pci_dmamem_alloc(sc, nitem * itemsz, 8);
1032e5ec1e72Spatrick 	if (ring->ring == NULL)
1033e5ec1e72Spatrick 		return ENOMEM;
1034e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1035e5ec1e72Spatrick 	    *ring_mem + BWFM_RING_MEM_BASE_ADDR_LOW,
1036e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(ring->ring) & 0xffffffff);
1037e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1038e5ec1e72Spatrick 	    *ring_mem + BWFM_RING_MEM_BASE_ADDR_HIGH,
1039e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(ring->ring) >> 32);
1040e5ec1e72Spatrick 	bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1041e5ec1e72Spatrick 	    *ring_mem + BWFM_RING_MAX_ITEM, nitem);
1042e5ec1e72Spatrick 	bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1043e5ec1e72Spatrick 	    *ring_mem + BWFM_RING_LEN_ITEMS, itemsz);
1044e5ec1e72Spatrick 	*ring_mem = *ring_mem + BWFM_RING_MEM_SZ;
1045e5ec1e72Spatrick 	return 0;
1046e5ec1e72Spatrick }
1047e5ec1e72Spatrick 
1048518be5f3Spatrick int
1049518be5f3Spatrick bwfm_pci_setup_flowring(struct bwfm_pci_softc *sc, struct bwfm_pci_msgring *ring,
1050518be5f3Spatrick     int nitem, size_t itemsz)
1051518be5f3Spatrick {
1052518be5f3Spatrick 	ring->w_ptr = 0;
1053518be5f3Spatrick 	ring->r_ptr = 0;
1054518be5f3Spatrick 	ring->nitem = nitem;
1055518be5f3Spatrick 	ring->itemsz = itemsz;
1056518be5f3Spatrick 	bwfm_pci_ring_write_rptr(sc, ring);
1057518be5f3Spatrick 	bwfm_pci_ring_write_wptr(sc, ring);
1058518be5f3Spatrick 
1059518be5f3Spatrick 	ring->ring = bwfm_pci_dmamem_alloc(sc, nitem * itemsz, 8);
1060518be5f3Spatrick 	if (ring->ring == NULL)
1061518be5f3Spatrick 		return ENOMEM;
1062518be5f3Spatrick 	return 0;
1063518be5f3Spatrick }
1064518be5f3Spatrick 
1065e5ec1e72Spatrick /* Ring helpers */
1066e5ec1e72Spatrick void
1067e5ec1e72Spatrick bwfm_pci_ring_bell(struct bwfm_pci_softc *sc,
1068e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1069e5ec1e72Spatrick {
1070e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1071*156d2677Spatrick 	    BWFM_PCI_PCIE2REG_H2D_MAILBOX_0, 1);
1072e5ec1e72Spatrick }
1073e5ec1e72Spatrick 
1074e5ec1e72Spatrick void
1075e5ec1e72Spatrick bwfm_pci_ring_update_rptr(struct bwfm_pci_softc *sc,
1076e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1077e5ec1e72Spatrick {
1078e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
1079e5ec1e72Spatrick 		ring->r_ptr = bus_space_read_2(sc->sc_tcm_iot,
1080e5ec1e72Spatrick 		    sc->sc_tcm_ioh, ring->r_idx_addr);
1081e5ec1e72Spatrick 	} else {
1082dcb67343Spatrick 		bus_dmamap_sync(sc->sc_dmat,
1083dcb67343Spatrick 		    BWFM_PCI_DMA_MAP(sc->sc_dma_idx_buf), ring->r_idx_addr,
1084dcb67343Spatrick 		    sizeof(uint16_t), BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1085e5ec1e72Spatrick 		ring->r_ptr = *(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf)
1086e5ec1e72Spatrick 		    + ring->r_idx_addr);
1087e5ec1e72Spatrick 	}
1088e5ec1e72Spatrick }
1089e5ec1e72Spatrick 
1090e5ec1e72Spatrick void
1091e5ec1e72Spatrick bwfm_pci_ring_update_wptr(struct bwfm_pci_softc *sc,
1092e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1093e5ec1e72Spatrick {
1094e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
1095e5ec1e72Spatrick 		ring->w_ptr = bus_space_read_2(sc->sc_tcm_iot,
1096e5ec1e72Spatrick 		    sc->sc_tcm_ioh, ring->w_idx_addr);
1097e5ec1e72Spatrick 	} else {
1098dcb67343Spatrick 		bus_dmamap_sync(sc->sc_dmat,
1099dcb67343Spatrick 		    BWFM_PCI_DMA_MAP(sc->sc_dma_idx_buf), ring->w_idx_addr,
1100dcb67343Spatrick 		    sizeof(uint16_t), BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1101e5ec1e72Spatrick 		ring->w_ptr = *(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf)
1102e5ec1e72Spatrick 		    + ring->w_idx_addr);
1103e5ec1e72Spatrick 	}
1104e5ec1e72Spatrick }
1105e5ec1e72Spatrick 
1106e5ec1e72Spatrick void
1107e5ec1e72Spatrick bwfm_pci_ring_write_rptr(struct bwfm_pci_softc *sc,
1108e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1109e5ec1e72Spatrick {
1110e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
1111e5ec1e72Spatrick 		bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1112e5ec1e72Spatrick 		    ring->r_idx_addr, ring->r_ptr);
1113e5ec1e72Spatrick 	} else {
1114e5ec1e72Spatrick 		*(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf)
1115e5ec1e72Spatrick 		    + ring->r_idx_addr) = ring->r_ptr;
1116dcb67343Spatrick 		bus_dmamap_sync(sc->sc_dmat,
1117dcb67343Spatrick 		    BWFM_PCI_DMA_MAP(sc->sc_dma_idx_buf), ring->r_idx_addr,
1118dcb67343Spatrick 		    sizeof(uint16_t), BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1119e5ec1e72Spatrick 	}
1120e5ec1e72Spatrick }
1121e5ec1e72Spatrick 
1122e5ec1e72Spatrick void
1123e5ec1e72Spatrick bwfm_pci_ring_write_wptr(struct bwfm_pci_softc *sc,
1124e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1125e5ec1e72Spatrick {
1126e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
1127e5ec1e72Spatrick 		bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1128e5ec1e72Spatrick 		    ring->w_idx_addr, ring->w_ptr);
1129e5ec1e72Spatrick 	} else {
1130e5ec1e72Spatrick 		*(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf)
1131e5ec1e72Spatrick 		    + ring->w_idx_addr) = ring->w_ptr;
1132dcb67343Spatrick 		bus_dmamap_sync(sc->sc_dmat,
1133dcb67343Spatrick 		    BWFM_PCI_DMA_MAP(sc->sc_dma_idx_buf), ring->w_idx_addr,
1134dcb67343Spatrick 		    sizeof(uint16_t), BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1135e5ec1e72Spatrick 	}
1136e5ec1e72Spatrick }
1137e5ec1e72Spatrick 
1138e5ec1e72Spatrick /*
1139e5ec1e72Spatrick  * Retrieve a free descriptor to put new stuff in, but don't commit
1140e5ec1e72Spatrick  * to it yet so we can rollback later if any error occurs.
1141e5ec1e72Spatrick  */
1142e5ec1e72Spatrick void *
1143e5ec1e72Spatrick bwfm_pci_ring_write_reserve(struct bwfm_pci_softc *sc,
1144e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1145e5ec1e72Spatrick {
1146e5ec1e72Spatrick 	int available;
1147e5ec1e72Spatrick 	char *ret;
1148e5ec1e72Spatrick 
1149e5ec1e72Spatrick 	bwfm_pci_ring_update_rptr(sc, ring);
1150e5ec1e72Spatrick 
1151e5ec1e72Spatrick 	if (ring->r_ptr > ring->w_ptr)
1152e5ec1e72Spatrick 		available = ring->r_ptr - ring->w_ptr;
1153e5ec1e72Spatrick 	else
1154e5ec1e72Spatrick 		available = ring->r_ptr + (ring->nitem - ring->w_ptr);
1155e5ec1e72Spatrick 
115630f5ada0Spatrick 	if (available <= 1)
1157e5ec1e72Spatrick 		return NULL;
1158e5ec1e72Spatrick 
1159e5ec1e72Spatrick 	ret = BWFM_PCI_DMA_KVA(ring->ring) + (ring->w_ptr * ring->itemsz);
1160e5ec1e72Spatrick 	ring->w_ptr += 1;
1161e5ec1e72Spatrick 	if (ring->w_ptr == ring->nitem)
1162e5ec1e72Spatrick 		ring->w_ptr = 0;
1163e5ec1e72Spatrick 	return ret;
1164e5ec1e72Spatrick }
1165e5ec1e72Spatrick 
1166e5ec1e72Spatrick void *
1167e5ec1e72Spatrick bwfm_pci_ring_write_reserve_multi(struct bwfm_pci_softc *sc,
1168e5ec1e72Spatrick     struct bwfm_pci_msgring *ring, int count, int *avail)
1169e5ec1e72Spatrick {
1170e5ec1e72Spatrick 	int available;
1171e5ec1e72Spatrick 	char *ret;
1172e5ec1e72Spatrick 
1173e5ec1e72Spatrick 	bwfm_pci_ring_update_rptr(sc, ring);
1174e5ec1e72Spatrick 
1175e5ec1e72Spatrick 	if (ring->r_ptr > ring->w_ptr)
1176e5ec1e72Spatrick 		available = ring->r_ptr - ring->w_ptr;
1177e5ec1e72Spatrick 	else
1178e5ec1e72Spatrick 		available = ring->r_ptr + (ring->nitem - ring->w_ptr);
1179e5ec1e72Spatrick 
118030f5ada0Spatrick 	if (available <= 1)
1181e5ec1e72Spatrick 		return NULL;
1182e5ec1e72Spatrick 
1183e5ec1e72Spatrick 	ret = BWFM_PCI_DMA_KVA(ring->ring) + (ring->w_ptr * ring->itemsz);
1184e5ec1e72Spatrick 	*avail = min(count, available - 1);
1185e5ec1e72Spatrick 	if (*avail + ring->w_ptr > ring->nitem)
1186e5ec1e72Spatrick 		*avail = ring->nitem - ring->w_ptr;
1187e5ec1e72Spatrick 	ring->w_ptr += *avail;
1188e5ec1e72Spatrick 	if (ring->w_ptr == ring->nitem)
1189e5ec1e72Spatrick 		ring->w_ptr = 0;
1190e5ec1e72Spatrick 	return ret;
1191e5ec1e72Spatrick }
1192e5ec1e72Spatrick 
1193e5ec1e72Spatrick /*
1194e5ec1e72Spatrick  * Read number of descriptors available (submitted by the firmware)
1195e5ec1e72Spatrick  * and retrieve pointer to first descriptor.
1196e5ec1e72Spatrick  */
1197e5ec1e72Spatrick void *
1198e5ec1e72Spatrick bwfm_pci_ring_read_avail(struct bwfm_pci_softc *sc,
1199e5ec1e72Spatrick     struct bwfm_pci_msgring *ring, int *avail)
1200e5ec1e72Spatrick {
1201e5ec1e72Spatrick 	bwfm_pci_ring_update_wptr(sc, ring);
1202e5ec1e72Spatrick 
1203e5ec1e72Spatrick 	if (ring->w_ptr >= ring->r_ptr)
1204e5ec1e72Spatrick 		*avail = ring->w_ptr - ring->r_ptr;
1205e5ec1e72Spatrick 	else
1206e5ec1e72Spatrick 		*avail = ring->nitem - ring->r_ptr;
1207e5ec1e72Spatrick 
1208e5ec1e72Spatrick 	if (*avail == 0)
1209e5ec1e72Spatrick 		return NULL;
1210e5ec1e72Spatrick 
1211dcb67343Spatrick 	bus_dmamap_sync(sc->sc_dmat, BWFM_PCI_DMA_MAP(ring->ring),
1212dcb67343Spatrick 	    ring->r_ptr * ring->itemsz, *avail * ring->itemsz,
1213dcb67343Spatrick 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1214e5ec1e72Spatrick 	return BWFM_PCI_DMA_KVA(ring->ring) + (ring->r_ptr * ring->itemsz);
1215e5ec1e72Spatrick }
1216e5ec1e72Spatrick 
1217e5ec1e72Spatrick /*
1218e5ec1e72Spatrick  * Let firmware know we read N descriptors.
1219e5ec1e72Spatrick  */
1220e5ec1e72Spatrick void
1221e5ec1e72Spatrick bwfm_pci_ring_read_commit(struct bwfm_pci_softc *sc,
1222e5ec1e72Spatrick     struct bwfm_pci_msgring *ring, int nitem)
1223e5ec1e72Spatrick {
1224e5ec1e72Spatrick 	ring->r_ptr += nitem;
1225e5ec1e72Spatrick 	if (ring->r_ptr == ring->nitem)
1226e5ec1e72Spatrick 		ring->r_ptr = 0;
1227e5ec1e72Spatrick 	bwfm_pci_ring_write_rptr(sc, ring);
1228e5ec1e72Spatrick }
1229e5ec1e72Spatrick 
1230e5ec1e72Spatrick /*
1231e5ec1e72Spatrick  * Let firmware know that we submitted some descriptors.
1232e5ec1e72Spatrick  */
1233e5ec1e72Spatrick void
1234e5ec1e72Spatrick bwfm_pci_ring_write_commit(struct bwfm_pci_softc *sc,
1235e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1236e5ec1e72Spatrick {
1237dcb67343Spatrick 	bus_dmamap_sync(sc->sc_dmat, BWFM_PCI_DMA_MAP(ring->ring),
1238dcb67343Spatrick 	    0, BWFM_PCI_DMA_LEN(ring->ring), BUS_DMASYNC_PREREAD |
1239dcb67343Spatrick 	    BUS_DMASYNC_PREWRITE);
1240e5ec1e72Spatrick 	bwfm_pci_ring_write_wptr(sc, ring);
1241e5ec1e72Spatrick 	bwfm_pci_ring_bell(sc, ring);
1242e5ec1e72Spatrick }
1243e5ec1e72Spatrick 
1244e5ec1e72Spatrick /*
1245e5ec1e72Spatrick  * Rollback N descriptors in case we don't actually want
1246e5ec1e72Spatrick  * to commit to it.
1247e5ec1e72Spatrick  */
1248e5ec1e72Spatrick void
1249e5ec1e72Spatrick bwfm_pci_ring_write_cancel(struct bwfm_pci_softc *sc,
1250e5ec1e72Spatrick     struct bwfm_pci_msgring *ring, int nitem)
1251e5ec1e72Spatrick {
1252e5ec1e72Spatrick 	if (ring->w_ptr == 0)
1253e5ec1e72Spatrick 		ring->w_ptr = ring->nitem - nitem;
1254e5ec1e72Spatrick 	else
1255e5ec1e72Spatrick 		ring->w_ptr -= nitem;
1256e5ec1e72Spatrick }
1257e5ec1e72Spatrick 
1258e5ec1e72Spatrick /*
1259e5ec1e72Spatrick  * Foreach written descriptor on the ring, pass the descriptor to
1260e5ec1e72Spatrick  * a message handler and let the firmware know we handled it.
1261e5ec1e72Spatrick  */
1262e5ec1e72Spatrick void
12636f241297Spatrick bwfm_pci_ring_rx(struct bwfm_pci_softc *sc, struct bwfm_pci_msgring *ring,
12646f241297Spatrick     struct mbuf_list *ml)
1265e5ec1e72Spatrick {
1266e5ec1e72Spatrick 	void *buf;
1267e5ec1e72Spatrick 	int avail, processed;
1268e5ec1e72Spatrick 
1269e5ec1e72Spatrick again:
1270e5ec1e72Spatrick 	buf = bwfm_pci_ring_read_avail(sc, ring, &avail);
1271e5ec1e72Spatrick 	if (buf == NULL)
1272e5ec1e72Spatrick 		return;
1273e5ec1e72Spatrick 
1274e5ec1e72Spatrick 	processed = 0;
1275e5ec1e72Spatrick 	while (avail) {
12766f241297Spatrick 		bwfm_pci_msg_rx(sc, buf + sc->sc_rx_dataoffset, ml);
1277e5ec1e72Spatrick 		buf += ring->itemsz;
1278e5ec1e72Spatrick 		processed++;
1279e5ec1e72Spatrick 		if (processed == 48) {
1280e5ec1e72Spatrick 			bwfm_pci_ring_read_commit(sc, ring, processed);
1281e5ec1e72Spatrick 			processed = 0;
1282e5ec1e72Spatrick 		}
1283e5ec1e72Spatrick 		avail--;
1284e5ec1e72Spatrick 	}
1285e5ec1e72Spatrick 	if (processed)
1286e5ec1e72Spatrick 		bwfm_pci_ring_read_commit(sc, ring, processed);
1287e5ec1e72Spatrick 	if (ring->r_ptr == 0)
1288e5ec1e72Spatrick 		goto again;
1289e5ec1e72Spatrick }
1290e5ec1e72Spatrick 
1291e5ec1e72Spatrick void
12926f241297Spatrick bwfm_pci_msg_rx(struct bwfm_pci_softc *sc, void *buf, struct mbuf_list *ml)
1293e5ec1e72Spatrick {
1294518be5f3Spatrick 	struct ifnet *ifp = &sc->sc_sc.sc_ic.ic_if;
1295e5ec1e72Spatrick 	struct msgbuf_ioctl_resp_hdr *resp;
1296518be5f3Spatrick 	struct msgbuf_tx_status *tx;
129718722113Spatrick 	struct msgbuf_rx_complete *rx;
1298e5ec1e72Spatrick 	struct msgbuf_rx_event *event;
1299e5ec1e72Spatrick 	struct msgbuf_common_hdr *msg;
1300518be5f3Spatrick 	struct msgbuf_flowring_create_resp *fcr;
1301a2c6ff8bSpatrick 	struct msgbuf_flowring_delete_resp *fdr;
1302518be5f3Spatrick 	struct bwfm_pci_msgring *ring;
1303e5ec1e72Spatrick 	struct mbuf *m;
1304518be5f3Spatrick 	int flowid;
1305e5ec1e72Spatrick 
1306e5ec1e72Spatrick 	msg = (struct msgbuf_common_hdr *)buf;
1307e5ec1e72Spatrick 	switch (msg->msgtype)
1308e5ec1e72Spatrick 	{
1309518be5f3Spatrick 	case MSGBUF_TYPE_FLOW_RING_CREATE_CMPLT:
1310518be5f3Spatrick 		fcr = (struct msgbuf_flowring_create_resp *)buf;
1311518be5f3Spatrick 		flowid = letoh16(fcr->compl_hdr.flow_ring_id);
1312518be5f3Spatrick 		if (flowid < 2)
1313518be5f3Spatrick 			break;
1314518be5f3Spatrick 		flowid -= 2;
1315518be5f3Spatrick 		if (flowid >= sc->sc_max_flowrings)
1316518be5f3Spatrick 			break;
1317518be5f3Spatrick 		ring = &sc->sc_flowrings[flowid];
1318518be5f3Spatrick 		if (ring->status != RING_OPENING)
1319518be5f3Spatrick 			break;
1320518be5f3Spatrick 		if (fcr->compl_hdr.status) {
1321518be5f3Spatrick 			printf("%s: failed to open flowring %d\n",
1322518be5f3Spatrick 			    DEVNAME(sc), flowid);
1323518be5f3Spatrick 			ring->status = RING_CLOSED;
132402ee7d07Spatrick 			if (ring->m) {
132502ee7d07Spatrick 				m_freem(ring->m);
132602ee7d07Spatrick 				ring->m = NULL;
132702ee7d07Spatrick 			}
1328518be5f3Spatrick 			ifq_restart(&ifp->if_snd);
1329518be5f3Spatrick 			break;
1330518be5f3Spatrick 		}
1331518be5f3Spatrick 		ring->status = RING_OPEN;
133202ee7d07Spatrick 		if (ring->m != NULL) {
133302ee7d07Spatrick 			m = ring->m;
133402ee7d07Spatrick 			ring->m = NULL;
133502ee7d07Spatrick 			if (bwfm_pci_txdata(&sc->sc_sc, m))
133602ee7d07Spatrick 				m_freem(ring->m);
133702ee7d07Spatrick 		}
1338518be5f3Spatrick 		ifq_restart(&ifp->if_snd);
1339518be5f3Spatrick 		break;
1340a2c6ff8bSpatrick 	case MSGBUF_TYPE_FLOW_RING_DELETE_CMPLT:
1341a2c6ff8bSpatrick 		fdr = (struct msgbuf_flowring_delete_resp *)buf;
1342a2c6ff8bSpatrick 		flowid = letoh16(fdr->compl_hdr.flow_ring_id);
1343a2c6ff8bSpatrick 		if (flowid < 2)
1344a2c6ff8bSpatrick 			break;
1345a2c6ff8bSpatrick 		flowid -= 2;
1346a2c6ff8bSpatrick 		if (flowid >= sc->sc_max_flowrings)
1347a2c6ff8bSpatrick 			break;
1348a2c6ff8bSpatrick 		ring = &sc->sc_flowrings[flowid];
1349a2c6ff8bSpatrick 		if (ring->status != RING_CLOSING)
1350a2c6ff8bSpatrick 			break;
1351a2c6ff8bSpatrick 		if (fdr->compl_hdr.status) {
1352a2c6ff8bSpatrick 			printf("%s: failed to delete flowring %d\n",
1353a2c6ff8bSpatrick 			    DEVNAME(sc), flowid);
1354a2c6ff8bSpatrick 			break;
1355a2c6ff8bSpatrick 		}
1356a2c6ff8bSpatrick 		bwfm_pci_dmamem_free(sc, ring->ring);
1357a2c6ff8bSpatrick 		ring->status = RING_CLOSED;
1358a2c6ff8bSpatrick 		break;
1359e5ec1e72Spatrick 	case MSGBUF_TYPE_IOCTLPTR_REQ_ACK:
13602eeba925Spatrick 		m = bwfm_pci_pktid_free(sc, &sc->sc_ioctl_pkts,
13612eeba925Spatrick 		    letoh32(msg->request_id));
13622eeba925Spatrick 		if (m == NULL)
13632eeba925Spatrick 			break;
13642eeba925Spatrick 		m_freem(m);
1365e5ec1e72Spatrick 		break;
1366e5ec1e72Spatrick 	case MSGBUF_TYPE_IOCTL_CMPLT:
1367e5ec1e72Spatrick 		resp = (struct msgbuf_ioctl_resp_hdr *)buf;
13682eeba925Spatrick 		bwfm_pci_msgbuf_rxioctl(sc, resp);
1369e5ec1e72Spatrick 		if_rxr_put(&sc->sc_ioctl_ring, 1);
1370e5ec1e72Spatrick 		bwfm_pci_fill_rx_rings(sc);
1371e5ec1e72Spatrick 		break;
1372e5ec1e72Spatrick 	case MSGBUF_TYPE_WL_EVENT:
1373e5ec1e72Spatrick 		event = (struct msgbuf_rx_event *)buf;
1374e5ec1e72Spatrick 		m = bwfm_pci_pktid_free(sc, &sc->sc_rx_pkts,
1375e5ec1e72Spatrick 		    letoh32(event->msg.request_id));
1376e5ec1e72Spatrick 		if (m == NULL)
1377e5ec1e72Spatrick 			break;
1378e5ec1e72Spatrick 		m_adj(m, sc->sc_rx_dataoffset);
1379f37fc236Spatrick 		m->m_len = m->m_pkthdr.len = letoh16(event->event_data_len);
13806f241297Spatrick 		bwfm_rx(&sc->sc_sc, m, ml);
1381e5ec1e72Spatrick 		if_rxr_put(&sc->sc_event_ring, 1);
1382e5ec1e72Spatrick 		bwfm_pci_fill_rx_rings(sc);
1383e5ec1e72Spatrick 		break;
1384518be5f3Spatrick 	case MSGBUF_TYPE_TX_STATUS:
1385518be5f3Spatrick 		tx = (struct msgbuf_tx_status *)buf;
1386518be5f3Spatrick 		m = bwfm_pci_pktid_free(sc, &sc->sc_tx_pkts,
1387f9ee104fSpatrick 		    letoh32(tx->msg.request_id) - 1);
1388518be5f3Spatrick 		if (m == NULL)
1389518be5f3Spatrick 			break;
1390518be5f3Spatrick 		m_freem(m);
1391c6f1636dSpatrick 		if (sc->sc_tx_pkts_full) {
1392c6f1636dSpatrick 			sc->sc_tx_pkts_full = 0;
1393c6f1636dSpatrick 			ifq_restart(&ifp->if_snd);
1394c6f1636dSpatrick 		}
1395518be5f3Spatrick 		break;
139618722113Spatrick 	case MSGBUF_TYPE_RX_CMPLT:
139718722113Spatrick 		rx = (struct msgbuf_rx_complete *)buf;
139818722113Spatrick 		m = bwfm_pci_pktid_free(sc, &sc->sc_rx_pkts,
139918722113Spatrick 		    letoh32(rx->msg.request_id));
140018722113Spatrick 		if (m == NULL)
140118722113Spatrick 			break;
140218722113Spatrick 		if (letoh16(rx->data_offset))
140318722113Spatrick 			m_adj(m, letoh16(rx->data_offset));
140418722113Spatrick 		else if (sc->sc_rx_dataoffset)
140518722113Spatrick 			m_adj(m, sc->sc_rx_dataoffset);
1406f37fc236Spatrick 		m->m_len = m->m_pkthdr.len = letoh16(rx->data_len);
14076f241297Spatrick 		bwfm_rx(&sc->sc_sc, m, ml);
140818722113Spatrick 		if_rxr_put(&sc->sc_rxbuf_ring, 1);
140918722113Spatrick 		bwfm_pci_fill_rx_rings(sc);
141018722113Spatrick 		break;
1411e5ec1e72Spatrick 	default:
1412e5ec1e72Spatrick 		printf("%s: msgtype 0x%08x\n", __func__, msg->msgtype);
1413e5ec1e72Spatrick 		break;
1414e5ec1e72Spatrick 	}
1415e5ec1e72Spatrick }
1416e5ec1e72Spatrick 
1417e5ec1e72Spatrick /* Bus core helpers */
1418e5ec1e72Spatrick void
1419e5ec1e72Spatrick bwfm_pci_select_core(struct bwfm_pci_softc *sc, int id)
1420e5ec1e72Spatrick {
1421e5ec1e72Spatrick 	struct bwfm_softc *bwfm = (void *)sc;
1422e5ec1e72Spatrick 	struct bwfm_core *core;
1423e5ec1e72Spatrick 
1424e5ec1e72Spatrick 	core = bwfm_chip_get_core(bwfm, id);
1425e5ec1e72Spatrick 	if (core == NULL) {
1426e5ec1e72Spatrick 		printf("%s: could not find core to select", DEVNAME(sc));
1427e5ec1e72Spatrick 		return;
1428e5ec1e72Spatrick 	}
1429e5ec1e72Spatrick 
1430e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag,
1431e5ec1e72Spatrick 	    BWFM_PCI_BAR0_WINDOW, core->co_base);
1432e5ec1e72Spatrick 	if (pci_conf_read(sc->sc_pc, sc->sc_tag,
1433e5ec1e72Spatrick 	    BWFM_PCI_BAR0_WINDOW) != core->co_base)
1434e5ec1e72Spatrick 		pci_conf_write(sc->sc_pc, sc->sc_tag,
1435e5ec1e72Spatrick 		    BWFM_PCI_BAR0_WINDOW, core->co_base);
1436e5ec1e72Spatrick }
1437e5ec1e72Spatrick 
1438e5ec1e72Spatrick uint32_t
1439e5ec1e72Spatrick bwfm_pci_buscore_read(struct bwfm_softc *bwfm, uint32_t reg)
1440e5ec1e72Spatrick {
1441e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1442e5ec1e72Spatrick 	uint32_t page, offset;
1443e5ec1e72Spatrick 
1444e5ec1e72Spatrick 	page = reg & ~(BWFM_PCI_BAR0_REG_SIZE - 1);
1445e5ec1e72Spatrick 	offset = reg & (BWFM_PCI_BAR0_REG_SIZE - 1);
1446e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_BAR0_WINDOW, page);
1447e5ec1e72Spatrick 	return bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh, offset);
1448e5ec1e72Spatrick }
1449e5ec1e72Spatrick 
1450e5ec1e72Spatrick void
1451e5ec1e72Spatrick bwfm_pci_buscore_write(struct bwfm_softc *bwfm, uint32_t reg, uint32_t val)
1452e5ec1e72Spatrick {
1453e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1454e5ec1e72Spatrick 	uint32_t page, offset;
1455e5ec1e72Spatrick 
1456e5ec1e72Spatrick 	page = reg & ~(BWFM_PCI_BAR0_REG_SIZE - 1);
1457e5ec1e72Spatrick 	offset = reg & (BWFM_PCI_BAR0_REG_SIZE - 1);
1458e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_BAR0_WINDOW, page);
1459e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, offset, val);
1460e5ec1e72Spatrick }
1461e5ec1e72Spatrick 
1462e5ec1e72Spatrick int
1463e5ec1e72Spatrick bwfm_pci_buscore_prepare(struct bwfm_softc *bwfm)
1464e5ec1e72Spatrick {
1465e5ec1e72Spatrick 	return 0;
1466e5ec1e72Spatrick }
1467e5ec1e72Spatrick 
1468e5ec1e72Spatrick int
1469e5ec1e72Spatrick bwfm_pci_buscore_reset(struct bwfm_softc *bwfm)
1470e5ec1e72Spatrick {
1471e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1472e5ec1e72Spatrick 	struct bwfm_core *core;
1473e5ec1e72Spatrick 	uint32_t reg;
1474e5ec1e72Spatrick 	int i;
1475e5ec1e72Spatrick 
1476e5ec1e72Spatrick 	bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2);
1477e5ec1e72Spatrick 	reg = pci_conf_read(sc->sc_pc, sc->sc_tag,
1478e5ec1e72Spatrick 	    BWFM_PCI_CFGREG_LINK_STATUS_CTRL);
1479e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_CFGREG_LINK_STATUS_CTRL,
1480e5ec1e72Spatrick 	    reg & ~BWFM_PCI_CFGREG_LINK_STATUS_CTRL_ASPM_ENAB);
1481e5ec1e72Spatrick 
1482e5ec1e72Spatrick 	bwfm_pci_select_core(sc, BWFM_AGENT_CORE_CHIPCOMMON);
1483e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1484e5ec1e72Spatrick 	    BWFM_CHIP_REG_WATCHDOG, 4);
1485e5ec1e72Spatrick 	delay(100 * 1000);
1486e5ec1e72Spatrick 
1487e5ec1e72Spatrick 	bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2);
1488e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag,
1489e5ec1e72Spatrick 	    BWFM_PCI_CFGREG_LINK_STATUS_CTRL, reg);
1490e5ec1e72Spatrick 
1491e5ec1e72Spatrick 	core = bwfm_chip_get_core(bwfm, BWFM_AGENT_CORE_PCIE2);
1492e5ec1e72Spatrick 	if (core->co_rev <= 13) {
1493e5ec1e72Spatrick 		uint16_t cfg_offset[] = {
1494e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_STATUS_CMD,
1495e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_PM_CSR,
1496e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_MSI_CAP,
1497e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_MSI_ADDR_L,
1498e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_MSI_ADDR_H,
1499e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_MSI_DATA,
1500e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_LINK_STATUS_CTRL2,
1501e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_RBAR_CTRL,
1502e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_PML1_SUB_CTRL1,
1503e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_REG_BAR2_CONFIG,
1504e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_REG_BAR3_CONFIG,
1505e5ec1e72Spatrick 		};
1506e5ec1e72Spatrick 
1507e5ec1e72Spatrick 		for (i = 0; i < nitems(cfg_offset); i++) {
1508e5ec1e72Spatrick 			bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1509e5ec1e72Spatrick 			    BWFM_PCI_PCIE2REG_CONFIGADDR, cfg_offset[i]);
1510e5ec1e72Spatrick 			reg = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1511e5ec1e72Spatrick 			    BWFM_PCI_PCIE2REG_CONFIGDATA);
1512e5ec1e72Spatrick 			DPRINTFN(3, ("%s: config offset 0x%04x, value 0x%04x\n",
1513e5ec1e72Spatrick 			    DEVNAME(sc), cfg_offset[i], reg));
1514e5ec1e72Spatrick 			bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1515e5ec1e72Spatrick 			    BWFM_PCI_PCIE2REG_CONFIGDATA, reg);
1516e5ec1e72Spatrick 		}
1517e5ec1e72Spatrick 	}
1518e5ec1e72Spatrick 
1519e5ec1e72Spatrick 	reg = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1520e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXINT);
1521e5ec1e72Spatrick 	if (reg != 0xffffffff)
1522e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1523e5ec1e72Spatrick 		    BWFM_PCI_PCIE2REG_MAILBOXINT, reg);
1524e5ec1e72Spatrick 
1525e5ec1e72Spatrick 	return 0;
1526e5ec1e72Spatrick }
1527e5ec1e72Spatrick 
1528e5ec1e72Spatrick void
1529e5ec1e72Spatrick bwfm_pci_buscore_activate(struct bwfm_softc *bwfm, uint32_t rstvec)
1530e5ec1e72Spatrick {
1531e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1532e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 0, rstvec);
1533e5ec1e72Spatrick }
1534e5ec1e72Spatrick 
1535f67437f3Spatrick static int bwfm_pci_prio2fifo[8] = {
15369e2c067eSpatrick 	0, /* best effort */
15379e2c067eSpatrick 	1, /* IPTOS_PREC_IMMEDIATE */
15389e2c067eSpatrick 	1, /* IPTOS_PREC_PRIORITY */
15399e2c067eSpatrick 	0, /* IPTOS_PREC_FLASH */
1540f67437f3Spatrick 	2, /* IPTOS_PREC_FLASHOVERRIDE */
1541f67437f3Spatrick 	2, /* IPTOS_PREC_CRITIC_ECP */
1542f67437f3Spatrick 	3, /* IPTOS_PREC_INTERNETCONTROL */
1543f67437f3Spatrick 	3, /* IPTOS_PREC_NETCONTROL */
1544f67437f3Spatrick };
1545f67437f3Spatrick 
1546f67437f3Spatrick int
1547f67437f3Spatrick bwfm_pci_flowring_lookup(struct bwfm_pci_softc *sc, struct mbuf *m)
1548518be5f3Spatrick {
1549f67437f3Spatrick 	struct ieee80211com *ic = &sc->sc_sc.sc_ic;
1550e6abcda3Smlarkin #ifndef IEEE80211_STA_ONLY
1551f67437f3Spatrick 	uint8_t *da = mtod(m, uint8_t *);
1552e6abcda3Smlarkin #endif
1553f67437f3Spatrick 	int flowid, prio, fifo;
1554f67437f3Spatrick 	int i, found;
1555f67437f3Spatrick 
1556f67437f3Spatrick 	prio = ieee80211_classify(ic, m);
1557f67437f3Spatrick 	fifo = bwfm_pci_prio2fifo[prio];
1558f67437f3Spatrick 
1559f67437f3Spatrick 	switch (ic->ic_opmode)
1560f67437f3Spatrick 	{
1561f67437f3Spatrick 	case IEEE80211_M_STA:
1562f67437f3Spatrick 		flowid = fifo;
1563f67437f3Spatrick 		break;
1564f67437f3Spatrick #ifndef IEEE80211_STA_ONLY
1565f67437f3Spatrick 	case IEEE80211_M_HOSTAP:
15662b7bea7eSpatrick 		if (ETHER_IS_MULTICAST(da))
15672b7bea7eSpatrick 			da = etherbroadcastaddr;
1568f67437f3Spatrick 		flowid = da[5] * 2 + fifo;
1569f67437f3Spatrick 		break;
1570f67437f3Spatrick #endif
1571f67437f3Spatrick 	default:
1572f67437f3Spatrick 		printf("%s: state not supported\n", DEVNAME(sc));
1573f67437f3Spatrick 		return ENOBUFS;
1574f67437f3Spatrick 	}
1575f67437f3Spatrick 
1576f67437f3Spatrick 	found = 0;
1577f67437f3Spatrick 	flowid = flowid % sc->sc_max_flowrings;
1578f67437f3Spatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
1579f67437f3Spatrick 		if (ic->ic_opmode == IEEE80211_M_STA &&
1580f67437f3Spatrick 		    sc->sc_flowrings[flowid].status >= RING_OPEN &&
1581f67437f3Spatrick 		    sc->sc_flowrings[flowid].fifo == fifo) {
1582f67437f3Spatrick 			found = 1;
1583f67437f3Spatrick 			break;
1584f67437f3Spatrick 		}
1585f67437f3Spatrick #ifndef IEEE80211_STA_ONLY
1586f67437f3Spatrick 		if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
1587f67437f3Spatrick 		    sc->sc_flowrings[flowid].status >= RING_OPEN &&
1588f67437f3Spatrick 		    sc->sc_flowrings[flowid].fifo == fifo &&
1589a2c6ff8bSpatrick 		    !memcmp(sc->sc_flowrings[flowid].mac, da, ETHER_ADDR_LEN)) {
1590f67437f3Spatrick 			found = 1;
1591f67437f3Spatrick 			break;
1592f67437f3Spatrick 		}
1593f67437f3Spatrick #endif
1594f67437f3Spatrick 		flowid = (flowid + 1) % sc->sc_max_flowrings;
1595f67437f3Spatrick 	}
1596f67437f3Spatrick 
1597f67437f3Spatrick 	if (found)
1598f67437f3Spatrick 		return flowid;
1599f67437f3Spatrick 
1600f67437f3Spatrick 	return -1;
1601f67437f3Spatrick }
1602f67437f3Spatrick 
1603f67437f3Spatrick void
1604f67437f3Spatrick bwfm_pci_flowring_create(struct bwfm_pci_softc *sc, struct mbuf *m)
1605f67437f3Spatrick {
1606f67437f3Spatrick 	struct ieee80211com *ic = &sc->sc_sc.sc_ic;
1607518be5f3Spatrick 	struct bwfm_cmd_flowring_create cmd;
1608e6abcda3Smlarkin #ifndef IEEE80211_STA_ONLY
1609f67437f3Spatrick 	uint8_t *da = mtod(m, uint8_t *);
1610e6abcda3Smlarkin #endif
161102ee7d07Spatrick 	struct bwfm_pci_msgring *ring;
1612f67437f3Spatrick 	int flowid, prio, fifo;
1613f67437f3Spatrick 	int i, found;
1614f67437f3Spatrick 
1615f67437f3Spatrick 	prio = ieee80211_classify(ic, m);
1616f67437f3Spatrick 	fifo = bwfm_pci_prio2fifo[prio];
1617f67437f3Spatrick 
1618f67437f3Spatrick 	switch (ic->ic_opmode)
1619f67437f3Spatrick 	{
1620f67437f3Spatrick 	case IEEE80211_M_STA:
1621f67437f3Spatrick 		flowid = fifo;
1622f67437f3Spatrick 		break;
1623f67437f3Spatrick #ifndef IEEE80211_STA_ONLY
1624f67437f3Spatrick 	case IEEE80211_M_HOSTAP:
16252b7bea7eSpatrick 		if (ETHER_IS_MULTICAST(da))
16262b7bea7eSpatrick 			da = etherbroadcastaddr;
1627f67437f3Spatrick 		flowid = da[5] * 2 + fifo;
1628f67437f3Spatrick 		break;
1629f67437f3Spatrick #endif
1630f67437f3Spatrick 	default:
1631f67437f3Spatrick 		printf("%s: state not supported\n", DEVNAME(sc));
1632f67437f3Spatrick 		return;
1633f67437f3Spatrick 	}
1634f67437f3Spatrick 
1635f67437f3Spatrick 	found = 0;
1636f67437f3Spatrick 	flowid = flowid % sc->sc_max_flowrings;
1637f67437f3Spatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
163802ee7d07Spatrick 		ring = &sc->sc_flowrings[flowid];
163902ee7d07Spatrick 		if (ring->status == RING_CLOSED) {
164002ee7d07Spatrick 			ring->status = RING_OPENING;
1641f67437f3Spatrick 			found = 1;
1642f67437f3Spatrick 			break;
1643f67437f3Spatrick 		}
1644f67437f3Spatrick 		flowid = (flowid + 1) % sc->sc_max_flowrings;
1645f67437f3Spatrick 	}
1646f67437f3Spatrick 
164702ee7d07Spatrick 	/*
164802ee7d07Spatrick 	 * We cannot recover from that so far.  Only a stop/init
164902ee7d07Spatrick 	 * cycle can revive this if it ever happens at all.
165002ee7d07Spatrick 	 */
1651f67437f3Spatrick 	if (!found) {
1652f67437f3Spatrick 		printf("%s: no flowring available\n", DEVNAME(sc));
1653f67437f3Spatrick 		return;
1654f67437f3Spatrick 	}
1655f67437f3Spatrick 
165602ee7d07Spatrick 	cmd.m = m;
1657f67437f3Spatrick 	cmd.prio = prio;
1658518be5f3Spatrick 	cmd.flowid = flowid;
1659518be5f3Spatrick 	bwfm_do_async(&sc->sc_sc, bwfm_pci_flowring_create_cb, &cmd, sizeof(cmd));
1660518be5f3Spatrick }
1661518be5f3Spatrick 
1662518be5f3Spatrick void
1663518be5f3Spatrick bwfm_pci_flowring_create_cb(struct bwfm_softc *bwfm, void *arg)
1664518be5f3Spatrick {
1665518be5f3Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1666e6abcda3Smlarkin #ifndef IEEE80211_STA_ONLY
16672b7bea7eSpatrick 	struct ieee80211com *ic = &sc->sc_sc.sc_ic;
1668e6abcda3Smlarkin #endif
1669518be5f3Spatrick 	struct bwfm_cmd_flowring_create *cmd = arg;
1670518be5f3Spatrick 	struct msgbuf_tx_flowring_create_req *req;
1671518be5f3Spatrick 	struct bwfm_pci_msgring *ring;
167202ee7d07Spatrick 	uint8_t *da, *sa;
1673e272db29Spatrick 	int s;
1674518be5f3Spatrick 
167502ee7d07Spatrick 	da = mtod(cmd->m, char *) + 0 * ETHER_ADDR_LEN;
167602ee7d07Spatrick 	sa = mtod(cmd->m, char *) + 1 * ETHER_ADDR_LEN;
1677518be5f3Spatrick 
167802ee7d07Spatrick 	ring = &sc->sc_flowrings[cmd->flowid];
167902ee7d07Spatrick 	if (ring->status != RING_OPENING) {
168002ee7d07Spatrick 		printf("%s: flowring not opening\n", DEVNAME(sc));
1681518be5f3Spatrick 		return;
1682f67437f3Spatrick 	}
1683f67437f3Spatrick 
1684f67437f3Spatrick 	if (bwfm_pci_setup_flowring(sc, ring, 512, 48)) {
1685f67437f3Spatrick 		printf("%s: cannot setup flowring\n", DEVNAME(sc));
1686f67437f3Spatrick 		return;
1687f67437f3Spatrick 	}
1688518be5f3Spatrick 
1689e272db29Spatrick 	s = splnet();
1690518be5f3Spatrick 	req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit);
1691f67437f3Spatrick 	if (req == NULL) {
1692f67437f3Spatrick 		printf("%s: cannot reserve for flowring\n", DEVNAME(sc));
1693e272db29Spatrick 		splx(s);
1694518be5f3Spatrick 		return;
1695f67437f3Spatrick 	}
1696518be5f3Spatrick 
1697518be5f3Spatrick 	ring->status = RING_OPENING;
169802ee7d07Spatrick 	ring->fifo = bwfm_pci_prio2fifo[cmd->prio];
169902ee7d07Spatrick 	ring->m = cmd->m;
170002ee7d07Spatrick 	memcpy(ring->mac, da, ETHER_ADDR_LEN);
17012b7bea7eSpatrick #ifndef IEEE80211_STA_ONLY
170202ee7d07Spatrick 	if (ic->ic_opmode == IEEE80211_M_HOSTAP && ETHER_IS_MULTICAST(da))
17032b7bea7eSpatrick 		memcpy(ring->mac, etherbroadcastaddr, ETHER_ADDR_LEN);
17042b7bea7eSpatrick #endif
1705f67437f3Spatrick 
1706518be5f3Spatrick 	req->msg.msgtype = MSGBUF_TYPE_FLOW_RING_CREATE;
1707518be5f3Spatrick 	req->msg.ifidx = 0;
1708518be5f3Spatrick 	req->msg.request_id = 0;
170902ee7d07Spatrick 	req->tid = bwfm_pci_prio2fifo[cmd->prio];
171002ee7d07Spatrick 	req->flow_ring_id = letoh16(cmd->flowid + 2);
171102ee7d07Spatrick 	memcpy(req->da, da, ETHER_ADDR_LEN);
171202ee7d07Spatrick 	memcpy(req->sa, sa, ETHER_ADDR_LEN);
1713518be5f3Spatrick 	req->flow_ring_addr.high_addr =
1714518be5f3Spatrick 	    letoh32(BWFM_PCI_DMA_DVA(ring->ring) >> 32);
1715518be5f3Spatrick 	req->flow_ring_addr.low_addr =
1716518be5f3Spatrick 	    letoh32(BWFM_PCI_DMA_DVA(ring->ring) & 0xffffffff);
1717518be5f3Spatrick 	req->max_items = letoh16(512);
1718518be5f3Spatrick 	req->len_item = letoh16(48);
1719518be5f3Spatrick 
1720518be5f3Spatrick 	bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit);
1721e272db29Spatrick 	splx(s);
1722518be5f3Spatrick }
1723518be5f3Spatrick 
1724a2c6ff8bSpatrick void
1725a2c6ff8bSpatrick bwfm_pci_flowring_delete(struct bwfm_pci_softc *sc, int flowid)
1726a2c6ff8bSpatrick {
1727a2c6ff8bSpatrick 	struct msgbuf_tx_flowring_delete_req *req;
1728a2c6ff8bSpatrick 	struct bwfm_pci_msgring *ring;
1729e272db29Spatrick 	int s;
1730a2c6ff8bSpatrick 
1731a2c6ff8bSpatrick 	ring = &sc->sc_flowrings[flowid];
1732a2c6ff8bSpatrick 	if (ring->status != RING_OPEN) {
1733a2c6ff8bSpatrick 		printf("%s: flowring not open\n", DEVNAME(sc));
1734a2c6ff8bSpatrick 		return;
1735a2c6ff8bSpatrick 	}
1736a2c6ff8bSpatrick 
1737e272db29Spatrick 	s = splnet();
1738a2c6ff8bSpatrick 	req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit);
1739a2c6ff8bSpatrick 	if (req == NULL) {
1740a2c6ff8bSpatrick 		printf("%s: cannot reserve for flowring\n", DEVNAME(sc));
1741e272db29Spatrick 		splx(s);
1742a2c6ff8bSpatrick 		return;
1743a2c6ff8bSpatrick 	}
1744a2c6ff8bSpatrick 
1745a2c6ff8bSpatrick 	ring->status = RING_CLOSING;
1746a2c6ff8bSpatrick 
1747a2c6ff8bSpatrick 	req->msg.msgtype = MSGBUF_TYPE_FLOW_RING_DELETE;
1748a2c6ff8bSpatrick 	req->msg.ifidx = 0;
1749a2c6ff8bSpatrick 	req->msg.request_id = 0;
1750a2c6ff8bSpatrick 	req->flow_ring_id = letoh16(flowid + 2);
1751a2c6ff8bSpatrick 	req->reason = 0;
1752a2c6ff8bSpatrick 
1753a2c6ff8bSpatrick 	bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit);
1754e272db29Spatrick 	splx(s);
1755a2c6ff8bSpatrick }
1756a2c6ff8bSpatrick 
1757a2c6ff8bSpatrick void
1758a2c6ff8bSpatrick bwfm_pci_stop(struct bwfm_softc *bwfm)
1759a2c6ff8bSpatrick {
1760a2c6ff8bSpatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1761a2c6ff8bSpatrick 	struct bwfm_pci_msgring *ring;
1762a2c6ff8bSpatrick 	int i;
1763a2c6ff8bSpatrick 
1764a2c6ff8bSpatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
1765a2c6ff8bSpatrick 		ring = &sc->sc_flowrings[i];
1766a2c6ff8bSpatrick 		if (ring->status == RING_OPEN)
1767a2c6ff8bSpatrick 			bwfm_pci_flowring_delete(sc, i);
1768a2c6ff8bSpatrick 	}
1769a2c6ff8bSpatrick }
1770a2c6ff8bSpatrick 
1771e5ec1e72Spatrick int
177202ee7d07Spatrick bwfm_pci_txcheck(struct bwfm_softc *bwfm)
177302ee7d07Spatrick {
177402ee7d07Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
177502ee7d07Spatrick 	struct bwfm_pci_msgring *ring;
177602ee7d07Spatrick 	int i;
177702ee7d07Spatrick 
177802ee7d07Spatrick 	/* If we are transitioning, we cannot send. */
177902ee7d07Spatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
178002ee7d07Spatrick 		ring = &sc->sc_flowrings[i];
178102ee7d07Spatrick 		if (ring->status == RING_OPENING)
178202ee7d07Spatrick 			return ENOBUFS;
178302ee7d07Spatrick 	}
178402ee7d07Spatrick 
178502ee7d07Spatrick 	if (bwfm_pci_pktid_avail(sc, &sc->sc_tx_pkts)) {
178602ee7d07Spatrick 		sc->sc_tx_pkts_full = 1;
178702ee7d07Spatrick 		return ENOBUFS;
178802ee7d07Spatrick 	}
178902ee7d07Spatrick 
179002ee7d07Spatrick 	return 0;
179102ee7d07Spatrick }
179202ee7d07Spatrick 
179302ee7d07Spatrick int
1794e5ec1e72Spatrick bwfm_pci_txdata(struct bwfm_softc *bwfm, struct mbuf *m)
1795e5ec1e72Spatrick {
1796e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1797518be5f3Spatrick 	struct bwfm_pci_msgring *ring;
1798518be5f3Spatrick 	struct msgbuf_tx_msghdr *tx;
1799518be5f3Spatrick 	uint32_t pktid;
1800518be5f3Spatrick 	paddr_t paddr;
1801518be5f3Spatrick 	int flowid, ret;
1802518be5f3Spatrick 
1803f67437f3Spatrick 	flowid = bwfm_pci_flowring_lookup(sc, m);
1804f67437f3Spatrick 	if (flowid < 0) {
180502ee7d07Spatrick 		/*
180602ee7d07Spatrick 		 * We cannot send the packet right now as there is
180702ee7d07Spatrick 		 * no flowring yet.  The flowring will be created
180802ee7d07Spatrick 		 * asynchronously.  While the ring is transitioning
180902ee7d07Spatrick 		 * the TX check will tell the upper layers that we
181002ee7d07Spatrick 		 * cannot send packets right now.  When the flowring
181102ee7d07Spatrick 		 * is created the queue will be restarted and this
181202ee7d07Spatrick 		 * mbuf will be transmitted.
181302ee7d07Spatrick 		 */
1814f67437f3Spatrick 		bwfm_pci_flowring_create(sc, m);
181502ee7d07Spatrick 		return 0;
1816f67437f3Spatrick 	}
1817518be5f3Spatrick 
1818518be5f3Spatrick 	ring = &sc->sc_flowrings[flowid];
1819518be5f3Spatrick 	if (ring->status == RING_OPENING ||
1820f67437f3Spatrick 	    ring->status == RING_CLOSING) {
1821f67437f3Spatrick 		printf("%s: tried to use a flow that was "
1822f67437f3Spatrick 		    "transitioning in status %d\n",
1823f67437f3Spatrick 		    DEVNAME(sc), ring->status);
1824518be5f3Spatrick 		return ENOBUFS;
1825518be5f3Spatrick 	}
1826518be5f3Spatrick 
1827518be5f3Spatrick 	tx = bwfm_pci_ring_write_reserve(sc, ring);
1828518be5f3Spatrick 	if (tx == NULL)
1829518be5f3Spatrick 		return ENOBUFS;
1830518be5f3Spatrick 
1831518be5f3Spatrick 	memset(tx, 0, sizeof(*tx));
1832518be5f3Spatrick 	tx->msg.msgtype = MSGBUF_TYPE_TX_POST;
1833518be5f3Spatrick 	tx->msg.ifidx = 0;
1834518be5f3Spatrick 	tx->flags = BWFM_MSGBUF_PKT_FLAGS_FRAME_802_3;
1835518be5f3Spatrick 	tx->flags |= ieee80211_classify(&sc->sc_sc.sc_ic, m) <<
1836518be5f3Spatrick 	    BWFM_MSGBUF_PKT_FLAGS_PRIO_SHIFT;
1837518be5f3Spatrick 	tx->seg_cnt = 1;
1838518be5f3Spatrick 	memcpy(tx->txhdr, mtod(m, char *), ETHER_HDR_LEN);
1839518be5f3Spatrick 
1840518be5f3Spatrick 	ret = bwfm_pci_pktid_new(sc, &sc->sc_tx_pkts, m, &pktid, &paddr);
1841518be5f3Spatrick 	if (ret) {
184202ee7d07Spatrick 		if (ret == ENOBUFS) {
184302ee7d07Spatrick 			printf("%s: no pktid available for TX\n",
184402ee7d07Spatrick 			    DEVNAME(sc));
1845c6f1636dSpatrick 			sc->sc_tx_pkts_full = 1;
184602ee7d07Spatrick 		}
1847518be5f3Spatrick 		bwfm_pci_ring_write_cancel(sc, ring, 1);
1848518be5f3Spatrick 		return ret;
1849518be5f3Spatrick 	}
1850518be5f3Spatrick 	paddr += ETHER_HDR_LEN;
1851518be5f3Spatrick 
1852f9ee104fSpatrick 	tx->msg.request_id = htole32(pktid + 1);
18534ff787bcSpatrick 	tx->data_len = htole16(m->m_len - ETHER_HDR_LEN);
1854e4dae658Spatrick 	tx->data_buf_addr.high_addr = htole32((uint64_t)paddr >> 32);
1855518be5f3Spatrick 	tx->data_buf_addr.low_addr = htole32(paddr & 0xffffffff);
1856518be5f3Spatrick 
1857518be5f3Spatrick 	bwfm_pci_ring_write_commit(sc, ring);
1858518be5f3Spatrick 	return 0;
1859e5ec1e72Spatrick }
1860e5ec1e72Spatrick 
1861bbd71b0bSpatrick #ifdef BWFM_DEBUG
1862cadf5fcfSpatrick void
1863cadf5fcfSpatrick bwfm_pci_debug_console(struct bwfm_pci_softc *sc)
1864cadf5fcfSpatrick {
1865cadf5fcfSpatrick 	uint32_t newidx = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1866cadf5fcfSpatrick 	    sc->sc_console_base_addr + BWFM_CONSOLE_WRITEIDX);
1867cadf5fcfSpatrick 
1868cadf5fcfSpatrick 	if (newidx != sc->sc_console_readidx)
1869bbd71b0bSpatrick 		DPRINTFN(3, ("BWFM CONSOLE: "));
1870cadf5fcfSpatrick 	while (newidx != sc->sc_console_readidx) {
1871cadf5fcfSpatrick 		uint8_t ch = bus_space_read_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1872cadf5fcfSpatrick 		    sc->sc_console_buf_addr + sc->sc_console_readidx);
1873cadf5fcfSpatrick 		sc->sc_console_readidx++;
1874cadf5fcfSpatrick 		if (sc->sc_console_readidx == sc->sc_console_buf_size)
1875cadf5fcfSpatrick 			sc->sc_console_readidx = 0;
1876cadf5fcfSpatrick 		if (ch == '\r')
1877cadf5fcfSpatrick 			continue;
1878bbd71b0bSpatrick 		DPRINTFN(3, ("%c", ch));
1879cadf5fcfSpatrick 	}
1880cadf5fcfSpatrick }
1881bbd71b0bSpatrick #endif
1882cadf5fcfSpatrick 
1883e5ec1e72Spatrick int
1884e5ec1e72Spatrick bwfm_pci_intr(void *v)
1885e5ec1e72Spatrick {
1886e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)v;
18876f241297Spatrick 	struct ifnet *ifp = &sc->sc_sc.sc_ic.ic_if;
18886f241297Spatrick 	struct mbuf_list ml = MBUF_LIST_INITIALIZER();
1889e5ec1e72Spatrick 	uint32_t status;
1890e5ec1e72Spatrick 
1891e5ec1e72Spatrick 	if ((status = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1892e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXINT)) == 0)
1893e5ec1e72Spatrick 		return 0;
1894e5ec1e72Spatrick 
1895e5ec1e72Spatrick 	bwfm_pci_intr_disable(sc);
1896e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1897e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXINT, status);
1898e5ec1e72Spatrick 
1899e5ec1e72Spatrick 	if (status & (BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_0 |
1900e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_1))
1901e5ec1e72Spatrick 		printf("%s: handle MB data\n", __func__);
1902e5ec1e72Spatrick 
1903e5ec1e72Spatrick 	if (status & BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_D2H_DB) {
19046f241297Spatrick 		bwfm_pci_ring_rx(sc, &sc->sc_rx_complete, &ml);
19056f241297Spatrick 		bwfm_pci_ring_rx(sc, &sc->sc_tx_complete, &ml);
19066f241297Spatrick 		bwfm_pci_ring_rx(sc, &sc->sc_ctrl_complete, &ml);
1907447a2df6Sdlg 
1908447a2df6Sdlg 		if (ifiq_input(&ifp->if_rcv, &ml))
1909447a2df6Sdlg 			if_rxr_livelocked(&sc->sc_rxbuf_ring);
1910e5ec1e72Spatrick 	}
1911e5ec1e72Spatrick 
1912cadf5fcfSpatrick #ifdef BWFM_DEBUG
1913cadf5fcfSpatrick 	bwfm_pci_debug_console(sc);
1914e5ec1e72Spatrick #endif
1915e5ec1e72Spatrick 
1916e5ec1e72Spatrick 	bwfm_pci_intr_enable(sc);
1917e5ec1e72Spatrick 	return 1;
1918e5ec1e72Spatrick }
1919e5ec1e72Spatrick 
1920e5ec1e72Spatrick void
1921e5ec1e72Spatrick bwfm_pci_intr_enable(struct bwfm_pci_softc *sc)
1922e5ec1e72Spatrick {
1923e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1924e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXMASK,
1925e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_0 |
1926e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_1 |
1927e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_D2H_DB);
1928e5ec1e72Spatrick }
1929e5ec1e72Spatrick 
1930e5ec1e72Spatrick void
1931e5ec1e72Spatrick bwfm_pci_intr_disable(struct bwfm_pci_softc *sc)
1932e5ec1e72Spatrick {
1933e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1934e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXMASK, 0);
1935e5ec1e72Spatrick }
1936e5ec1e72Spatrick 
1937*156d2677Spatrick void
1938*156d2677Spatrick bwfm_pci_hostready(struct bwfm_pci_softc *sc)
1939*156d2677Spatrick {
1940*156d2677Spatrick 	if ((sc->sc_shared_flags & BWFM_SHARED_INFO_HOSTRDY_DB1) == 0)
1941*156d2677Spatrick 		return;
1942*156d2677Spatrick 
1943*156d2677Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1944*156d2677Spatrick 	    BWFM_PCI_PCIE2REG_H2D_MAILBOX_1, 1);
1945*156d2677Spatrick }
1946*156d2677Spatrick 
1947e5ec1e72Spatrick /* Msgbuf protocol implementation */
1948e5ec1e72Spatrick int
1949e5ec1e72Spatrick bwfm_pci_msgbuf_query_dcmd(struct bwfm_softc *bwfm, int ifidx,
1950e5ec1e72Spatrick     int cmd, char *buf, size_t *len)
1951e5ec1e72Spatrick {
1952e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1953e5ec1e72Spatrick 	struct msgbuf_ioctl_req_hdr *req;
19542eeba925Spatrick 	struct bwfm_pci_ioctl *ctl;
1955e5ec1e72Spatrick 	struct mbuf *m;
19562eeba925Spatrick 	uint32_t pktid;
19572eeba925Spatrick 	paddr_t paddr;
1958e5ec1e72Spatrick 	size_t buflen;
1959e272db29Spatrick 	int s;
1960e5ec1e72Spatrick 
19612eeba925Spatrick 	buflen = min(*len, BWFM_DMA_H2D_IOCTL_BUF_LEN);
1962471f2571Sjan 	m = MCLGETL(NULL, M_DONTWAIT, buflen);
19632eeba925Spatrick 	if (m == NULL)
19642eeba925Spatrick 		return 1;
19652eeba925Spatrick 	m->m_len = m->m_pkthdr.len = buflen;
19662eeba925Spatrick 
19672eeba925Spatrick 	if (buf)
19682eeba925Spatrick 		memcpy(mtod(m, char *), buf, buflen);
19692eeba925Spatrick 	else
19702eeba925Spatrick 		memset(mtod(m, char *), 0, buflen);
19712eeba925Spatrick 
1972e272db29Spatrick 	s = splnet();
1973e5ec1e72Spatrick 	req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit);
1974e5ec1e72Spatrick 	if (req == NULL) {
1975e272db29Spatrick 		splx(s);
19762eeba925Spatrick 		m_freem(m);
1977e5ec1e72Spatrick 		return 1;
1978e5ec1e72Spatrick 	}
19792eeba925Spatrick 
19802eeba925Spatrick 	if (bwfm_pci_pktid_new(sc, &sc->sc_ioctl_pkts, m, &pktid, &paddr)) {
19812eeba925Spatrick 		bwfm_pci_ring_write_cancel(sc, &sc->sc_ctrl_submit, 1);
1982e272db29Spatrick 		splx(s);
19832eeba925Spatrick 		m_freem(m);
19842eeba925Spatrick 		return 1;
19852eeba925Spatrick 	}
19862eeba925Spatrick 
19872eeba925Spatrick 	ctl = malloc(sizeof(*ctl), M_TEMP, M_WAITOK|M_ZERO);
19882eeba925Spatrick 	ctl->transid = sc->sc_ioctl_transid++;
19892eeba925Spatrick 	TAILQ_INSERT_TAIL(&sc->sc_ioctlq, ctl, next);
19902eeba925Spatrick 
1991e5ec1e72Spatrick 	req->msg.msgtype = MSGBUF_TYPE_IOCTLPTR_REQ;
1992e5ec1e72Spatrick 	req->msg.ifidx = 0;
1993e5ec1e72Spatrick 	req->msg.flags = 0;
19942eeba925Spatrick 	req->msg.request_id = htole32(pktid);
1995e5ec1e72Spatrick 	req->cmd = htole32(cmd);
1996e5ec1e72Spatrick 	req->output_buf_len = htole16(*len);
19972eeba925Spatrick 	req->trans_id = htole16(ctl->transid);
1998e5ec1e72Spatrick 
19992eeba925Spatrick 	req->input_buf_len = htole16(m->m_len);
20002eeba925Spatrick 	req->req_buf_addr.high_addr = htole32((uint64_t)paddr >> 32);
20012eeba925Spatrick 	req->req_buf_addr.low_addr = htole32(paddr & 0xffffffff);
2002dcb67343Spatrick 
2003e5ec1e72Spatrick 	bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit);
2004e272db29Spatrick 	splx(s);
2005e5ec1e72Spatrick 
20068544fed6Smpi 	tsleep_nsec(ctl, PWAIT, "bwfm", SEC_TO_NSEC(1));
20072eeba925Spatrick 	TAILQ_REMOVE(&sc->sc_ioctlq, ctl, next);
20082eeba925Spatrick 
20092eeba925Spatrick 	if (ctl->m == NULL) {
20102eeba925Spatrick 		free(ctl, M_TEMP, sizeof(*ctl));
2011e5ec1e72Spatrick 		return 1;
2012e5ec1e72Spatrick 	}
2013e5ec1e72Spatrick 
20142eeba925Spatrick 	*len = min(ctl->retlen, m->m_len);
20152eeba925Spatrick 	*len = min(*len, buflen);
2016e5ec1e72Spatrick 	if (buf)
20175c7fed39Sdlg 		m_copydata(ctl->m, 0, *len, buf);
20182eeba925Spatrick 	m_freem(ctl->m);
2019e5ec1e72Spatrick 
20202eeba925Spatrick 	if (ctl->status < 0) {
20212eeba925Spatrick 		free(ctl, M_TEMP, sizeof(*ctl));
20222eeba925Spatrick 		return 1;
20232eeba925Spatrick 	}
20242eeba925Spatrick 
20252eeba925Spatrick 	free(ctl, M_TEMP, sizeof(*ctl));
2026e5ec1e72Spatrick 	return 0;
2027e5ec1e72Spatrick }
2028e5ec1e72Spatrick 
2029e5ec1e72Spatrick int
2030e5ec1e72Spatrick bwfm_pci_msgbuf_set_dcmd(struct bwfm_softc *bwfm, int ifidx,
2031e5ec1e72Spatrick     int cmd, char *buf, size_t len)
2032e5ec1e72Spatrick {
2033e5ec1e72Spatrick 	return bwfm_pci_msgbuf_query_dcmd(bwfm, ifidx, cmd, buf, &len);
2034e5ec1e72Spatrick }
20352eeba925Spatrick 
20362eeba925Spatrick void
20372eeba925Spatrick bwfm_pci_msgbuf_rxioctl(struct bwfm_pci_softc *sc,
20382eeba925Spatrick     struct msgbuf_ioctl_resp_hdr *resp)
20392eeba925Spatrick {
20402eeba925Spatrick 	struct bwfm_pci_ioctl *ctl, *tmp;
20412eeba925Spatrick 	struct mbuf *m;
20422eeba925Spatrick 
20432eeba925Spatrick 	m = bwfm_pci_pktid_free(sc, &sc->sc_rx_pkts,
20442eeba925Spatrick 	    letoh32(resp->msg.request_id));
20452eeba925Spatrick 
20462eeba925Spatrick 	TAILQ_FOREACH_SAFE(ctl, &sc->sc_ioctlq, next, tmp) {
20472eeba925Spatrick 		if (ctl->transid != letoh16(resp->trans_id))
20482eeba925Spatrick 			continue;
20492eeba925Spatrick 		ctl->m = m;
20502eeba925Spatrick 		ctl->retlen = letoh16(resp->resp_len);
20512eeba925Spatrick 		ctl->status = letoh16(resp->compl_hdr.status);
20522eeba925Spatrick 		wakeup(ctl);
20532eeba925Spatrick 		return;
20542eeba925Spatrick 	}
20552eeba925Spatrick 
2056cb2afc74Spatrick 	m_freem(m);
20572eeba925Spatrick }
2058