xref: /openbsd/sys/dev/pci/if_bwfm_pci.c (revision cb2afc74)
1*cb2afc74Spatrick /*	$OpenBSD: if_bwfm_pci.c,v 1.29 2019/02/07 07:39:56 patrick Exp $	*/
2e5ec1e72Spatrick /*
3e5ec1e72Spatrick  * Copyright (c) 2010-2016 Broadcom Corporation
4e5ec1e72Spatrick  * Copyright (c) 2017 Patrick Wildt <patrick@blueri.se>
5e5ec1e72Spatrick  *
6e5ec1e72Spatrick  * Permission to use, copy, modify, and/or distribute this software for any
7e5ec1e72Spatrick  * purpose with or without fee is hereby granted, provided that the above
8e5ec1e72Spatrick  * copyright notice and this permission notice appear in all copies.
9e5ec1e72Spatrick  *
10e5ec1e72Spatrick  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11e5ec1e72Spatrick  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12e5ec1e72Spatrick  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13e5ec1e72Spatrick  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14e5ec1e72Spatrick  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15e5ec1e72Spatrick  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16e5ec1e72Spatrick  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17e5ec1e72Spatrick  */
18e5ec1e72Spatrick 
19e5ec1e72Spatrick #include "bpfilter.h"
20e5ec1e72Spatrick 
21e5ec1e72Spatrick #include <sys/param.h>
22e5ec1e72Spatrick #include <sys/systm.h>
23e5ec1e72Spatrick #include <sys/buf.h>
24e5ec1e72Spatrick #include <sys/kernel.h>
25e5ec1e72Spatrick #include <sys/malloc.h>
26e5ec1e72Spatrick #include <sys/device.h>
27e5ec1e72Spatrick #include <sys/queue.h>
28e5ec1e72Spatrick #include <sys/socket.h>
29e5ec1e72Spatrick 
30e5ec1e72Spatrick #if NBPFILTER > 0
31e5ec1e72Spatrick #include <net/bpf.h>
32e5ec1e72Spatrick #endif
33e5ec1e72Spatrick #include <net/if.h>
34e5ec1e72Spatrick #include <net/if_dl.h>
35e5ec1e72Spatrick #include <net/if_media.h>
36e5ec1e72Spatrick 
37e5ec1e72Spatrick #include <netinet/in.h>
38e5ec1e72Spatrick #include <netinet/if_ether.h>
39e5ec1e72Spatrick 
40e5ec1e72Spatrick #include <net80211/ieee80211_var.h>
41e5ec1e72Spatrick 
42e5ec1e72Spatrick #include <machine/bus.h>
43e5ec1e72Spatrick 
44e5ec1e72Spatrick #include <dev/pci/pcireg.h>
45e5ec1e72Spatrick #include <dev/pci/pcivar.h>
46e5ec1e72Spatrick #include <dev/pci/pcidevs.h>
47e5ec1e72Spatrick 
48e5ec1e72Spatrick #include <dev/ic/bwfmvar.h>
49e5ec1e72Spatrick #include <dev/ic/bwfmreg.h>
50e5ec1e72Spatrick #include <dev/pci/if_bwfm_pci.h>
51e5ec1e72Spatrick 
52e5ec1e72Spatrick #define BWFM_DMA_D2H_SCRATCH_BUF_LEN		8
53e5ec1e72Spatrick #define BWFM_DMA_D2H_RINGUPD_BUF_LEN		1024
54e5ec1e72Spatrick #define BWFM_DMA_H2D_IOCTL_BUF_LEN		ETHER_MAX_LEN
55e5ec1e72Spatrick 
56e5ec1e72Spatrick #define BWFM_NUM_TX_MSGRINGS			2
57e5ec1e72Spatrick #define BWFM_NUM_RX_MSGRINGS			3
58e5ec1e72Spatrick 
592eeba925Spatrick #define BWFM_NUM_IOCTL_PKTIDS			8
60e5ec1e72Spatrick #define BWFM_NUM_TX_PKTIDS			2048
61e5ec1e72Spatrick #define BWFM_NUM_RX_PKTIDS			1024
62e5ec1e72Spatrick 
632eeba925Spatrick #define BWFM_NUM_IOCTL_DESCS			1
64e5ec1e72Spatrick #define BWFM_NUM_TX_DESCS			1
65e5ec1e72Spatrick #define BWFM_NUM_RX_DESCS			1
66e5ec1e72Spatrick 
67e5ec1e72Spatrick #ifdef BWFM_DEBUG
68e5ec1e72Spatrick #define DPRINTF(x)	do { if (bwfm_debug > 0) printf x; } while (0)
69e5ec1e72Spatrick #define DPRINTFN(n, x)	do { if (bwfm_debug >= (n)) printf x; } while (0)
70e5ec1e72Spatrick static int bwfm_debug = 2;
71e5ec1e72Spatrick #else
72e5ec1e72Spatrick #define DPRINTF(x)	do { ; } while (0)
73e5ec1e72Spatrick #define DPRINTFN(n, x)	do { ; } while (0)
74e5ec1e72Spatrick #endif
75e5ec1e72Spatrick 
76e5ec1e72Spatrick #define DEVNAME(sc)	((sc)->sc_sc.sc_dev.dv_xname)
77e5ec1e72Spatrick 
78518be5f3Spatrick enum ring_status {
79518be5f3Spatrick 	RING_CLOSED,
80518be5f3Spatrick 	RING_CLOSING,
81518be5f3Spatrick 	RING_OPEN,
82518be5f3Spatrick 	RING_OPENING,
83518be5f3Spatrick };
84518be5f3Spatrick 
85e5ec1e72Spatrick struct bwfm_pci_msgring {
86e5ec1e72Spatrick 	uint32_t		 w_idx_addr;
87e5ec1e72Spatrick 	uint32_t		 r_idx_addr;
88e5ec1e72Spatrick 	uint32_t		 w_ptr;
89e5ec1e72Spatrick 	uint32_t		 r_ptr;
90e5ec1e72Spatrick 	int			 nitem;
91e5ec1e72Spatrick 	int			 itemsz;
92518be5f3Spatrick 	enum ring_status	 status;
93e5ec1e72Spatrick 	struct bwfm_pci_dmamem	*ring;
9402ee7d07Spatrick 	struct mbuf		*m;
95f67437f3Spatrick 
96f67437f3Spatrick 	int			 fifo;
97f67437f3Spatrick 	uint8_t			 mac[ETHER_ADDR_LEN];
98e5ec1e72Spatrick };
99e5ec1e72Spatrick 
1002eeba925Spatrick struct bwfm_pci_ioctl {
1012eeba925Spatrick 	uint16_t		 transid;
1022eeba925Spatrick 	uint16_t		 retlen;
1032eeba925Spatrick 	int16_t			 status;
1042eeba925Spatrick 	struct mbuf		*m;
1052eeba925Spatrick 	TAILQ_ENTRY(bwfm_pci_ioctl) next;
1062eeba925Spatrick };
1072eeba925Spatrick 
108e5ec1e72Spatrick struct bwfm_pci_buf {
109e5ec1e72Spatrick 	bus_dmamap_t	 bb_map;
110e5ec1e72Spatrick 	struct mbuf	*bb_m;
111e5ec1e72Spatrick };
112e5ec1e72Spatrick 
113e5ec1e72Spatrick struct bwfm_pci_pkts {
114e5ec1e72Spatrick 	struct bwfm_pci_buf	*pkts;
115e5ec1e72Spatrick 	uint32_t		 npkt;
116e5ec1e72Spatrick 	int			 last;
117e5ec1e72Spatrick };
118e5ec1e72Spatrick 
119e5ec1e72Spatrick struct bwfm_pci_softc {
120e5ec1e72Spatrick 	struct bwfm_softc	 sc_sc;
121e5ec1e72Spatrick 	pci_chipset_tag_t	 sc_pc;
122e5ec1e72Spatrick 	pcitag_t		 sc_tag;
123e5ec1e72Spatrick 	pcireg_t		 sc_id;
124e5ec1e72Spatrick 	void 			*sc_ih;
125e5ec1e72Spatrick 
126972218f3Spatrick 	int			 sc_initialized;
127972218f3Spatrick 
128e5ec1e72Spatrick 	bus_space_tag_t		 sc_reg_iot;
129e5ec1e72Spatrick 	bus_space_handle_t	 sc_reg_ioh;
130e5ec1e72Spatrick 	bus_size_t		 sc_reg_ios;
131e5ec1e72Spatrick 
132e5ec1e72Spatrick 	bus_space_tag_t		 sc_tcm_iot;
133e5ec1e72Spatrick 	bus_space_handle_t	 sc_tcm_ioh;
134e5ec1e72Spatrick 	bus_size_t		 sc_tcm_ios;
135e5ec1e72Spatrick 
136e5ec1e72Spatrick 	bus_dma_tag_t		 sc_dmat;
137e5ec1e72Spatrick 
138e5ec1e72Spatrick 	uint32_t		 sc_shared_address;
139e5ec1e72Spatrick 	uint32_t		 sc_shared_flags;
140e5ec1e72Spatrick 	uint8_t			 sc_shared_version;
141e5ec1e72Spatrick 
142e5ec1e72Spatrick 	uint8_t			 sc_dma_idx_sz;
143e5ec1e72Spatrick 	struct bwfm_pci_dmamem	*sc_dma_idx_buf;
144e5ec1e72Spatrick 	size_t			 sc_dma_idx_bufsz;
145e5ec1e72Spatrick 
146e5ec1e72Spatrick 	uint16_t		 sc_max_rxbufpost;
147e5ec1e72Spatrick 	uint32_t		 sc_rx_dataoffset;
148e5ec1e72Spatrick 	uint32_t		 sc_htod_mb_data_addr;
149e5ec1e72Spatrick 	uint32_t		 sc_dtoh_mb_data_addr;
150e5ec1e72Spatrick 	uint32_t		 sc_ring_info_addr;
151e5ec1e72Spatrick 
152e5ec1e72Spatrick 	uint32_t		 sc_console_base_addr;
153e5ec1e72Spatrick 	uint32_t		 sc_console_buf_addr;
154e5ec1e72Spatrick 	uint32_t		 sc_console_buf_size;
155cadf5fcfSpatrick 	uint32_t		 sc_console_readidx;
156e5ec1e72Spatrick 
157e5ec1e72Spatrick 	uint16_t		 sc_max_flowrings;
158e5ec1e72Spatrick 	uint16_t		 sc_max_submissionrings;
159e5ec1e72Spatrick 	uint16_t		 sc_max_completionrings;
160e5ec1e72Spatrick 
161e5ec1e72Spatrick 	struct bwfm_pci_msgring	 sc_ctrl_submit;
162e5ec1e72Spatrick 	struct bwfm_pci_msgring	 sc_rxpost_submit;
163e5ec1e72Spatrick 	struct bwfm_pci_msgring	 sc_ctrl_complete;
164e5ec1e72Spatrick 	struct bwfm_pci_msgring	 sc_tx_complete;
165e5ec1e72Spatrick 	struct bwfm_pci_msgring	 sc_rx_complete;
166e5ec1e72Spatrick 	struct bwfm_pci_msgring	*sc_flowrings;
167e5ec1e72Spatrick 
168e5ec1e72Spatrick 	struct bwfm_pci_dmamem	*sc_scratch_buf;
169e5ec1e72Spatrick 	struct bwfm_pci_dmamem	*sc_ringupd_buf;
170e5ec1e72Spatrick 
1712eeba925Spatrick 	TAILQ_HEAD(, bwfm_pci_ioctl) sc_ioctlq;
1722eeba925Spatrick 	uint16_t		 sc_ioctl_transid;
173e5ec1e72Spatrick 
174e5ec1e72Spatrick 	struct if_rxring	 sc_ioctl_ring;
175e5ec1e72Spatrick 	struct if_rxring	 sc_event_ring;
176e5ec1e72Spatrick 	struct if_rxring	 sc_rxbuf_ring;
177e5ec1e72Spatrick 
1782eeba925Spatrick 	struct bwfm_pci_pkts	 sc_ioctl_pkts;
179e5ec1e72Spatrick 	struct bwfm_pci_pkts	 sc_rx_pkts;
180c6f1636dSpatrick 	struct bwfm_pci_pkts	 sc_tx_pkts;
181c6f1636dSpatrick 	int			 sc_tx_pkts_full;
182e5ec1e72Spatrick };
183e5ec1e72Spatrick 
184e5ec1e72Spatrick struct bwfm_pci_dmamem {
185e5ec1e72Spatrick 	bus_dmamap_t		bdm_map;
186e5ec1e72Spatrick 	bus_dma_segment_t	bdm_seg;
187e5ec1e72Spatrick 	size_t			bdm_size;
188e5ec1e72Spatrick 	caddr_t			bdm_kva;
189e5ec1e72Spatrick };
190e5ec1e72Spatrick 
191e5ec1e72Spatrick #define BWFM_PCI_DMA_MAP(_bdm)	((_bdm)->bdm_map)
192e5ec1e72Spatrick #define BWFM_PCI_DMA_LEN(_bdm)	((_bdm)->bdm_size)
193e4dae658Spatrick #define BWFM_PCI_DMA_DVA(_bdm)	((uint64_t)(_bdm)->bdm_map->dm_segs[0].ds_addr)
194e5ec1e72Spatrick #define BWFM_PCI_DMA_KVA(_bdm)	((void *)(_bdm)->bdm_kva)
195e5ec1e72Spatrick 
196e5ec1e72Spatrick int		 bwfm_pci_match(struct device *, void *, void *);
197e5ec1e72Spatrick void		 bwfm_pci_attach(struct device *, struct device *, void *);
198e5ec1e72Spatrick int		 bwfm_pci_detach(struct device *, int);
199e5ec1e72Spatrick 
200e5ec1e72Spatrick int		 bwfm_pci_intr(void *);
201e5ec1e72Spatrick void		 bwfm_pci_intr_enable(struct bwfm_pci_softc *);
202e5ec1e72Spatrick void		 bwfm_pci_intr_disable(struct bwfm_pci_softc *);
203e5ec1e72Spatrick int		 bwfm_pci_load_microcode(struct bwfm_pci_softc *, const u_char *,
2046aad491fSpatrick 		    size_t, const u_char *, size_t);
205e5ec1e72Spatrick void		 bwfm_pci_select_core(struct bwfm_pci_softc *, int );
206e5ec1e72Spatrick 
207e5ec1e72Spatrick struct bwfm_pci_dmamem *
208e5ec1e72Spatrick 		 bwfm_pci_dmamem_alloc(struct bwfm_pci_softc *, bus_size_t,
209e5ec1e72Spatrick 		    bus_size_t);
210e5ec1e72Spatrick void		 bwfm_pci_dmamem_free(struct bwfm_pci_softc *, struct bwfm_pci_dmamem *);
21102ee7d07Spatrick int		 bwfm_pci_pktid_avail(struct bwfm_pci_softc *,
21202ee7d07Spatrick 		    struct bwfm_pci_pkts *);
213e5ec1e72Spatrick int		 bwfm_pci_pktid_new(struct bwfm_pci_softc *,
214e5ec1e72Spatrick 		    struct bwfm_pci_pkts *, struct mbuf *,
215e5ec1e72Spatrick 		    uint32_t *, paddr_t *);
216e5ec1e72Spatrick struct mbuf *	 bwfm_pci_pktid_free(struct bwfm_pci_softc *,
217e5ec1e72Spatrick 		    struct bwfm_pci_pkts *, uint32_t);
218e5ec1e72Spatrick void		 bwfm_pci_fill_rx_ioctl_ring(struct bwfm_pci_softc *,
219e5ec1e72Spatrick 		    struct if_rxring *, uint32_t);
220e5ec1e72Spatrick void		 bwfm_pci_fill_rx_buf_ring(struct bwfm_pci_softc *);
221e5ec1e72Spatrick void		 bwfm_pci_fill_rx_rings(struct bwfm_pci_softc *);
222e5ec1e72Spatrick int		 bwfm_pci_setup_ring(struct bwfm_pci_softc *, struct bwfm_pci_msgring *,
223e5ec1e72Spatrick 		    int, size_t, uint32_t, uint32_t, int, uint32_t, uint32_t *);
224518be5f3Spatrick int		 bwfm_pci_setup_flowring(struct bwfm_pci_softc *, struct bwfm_pci_msgring *,
225518be5f3Spatrick 		    int, size_t);
226e5ec1e72Spatrick 
227e5ec1e72Spatrick void		 bwfm_pci_ring_bell(struct bwfm_pci_softc *,
228e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
229e5ec1e72Spatrick void		 bwfm_pci_ring_update_rptr(struct bwfm_pci_softc *,
230e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
231e5ec1e72Spatrick void		 bwfm_pci_ring_update_wptr(struct bwfm_pci_softc *,
232e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
233e5ec1e72Spatrick void		 bwfm_pci_ring_write_rptr(struct bwfm_pci_softc *,
234e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
235e5ec1e72Spatrick void		 bwfm_pci_ring_write_wptr(struct bwfm_pci_softc *,
236e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
237e5ec1e72Spatrick void *		 bwfm_pci_ring_write_reserve(struct bwfm_pci_softc *,
238e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
239e5ec1e72Spatrick void *		 bwfm_pci_ring_write_reserve_multi(struct bwfm_pci_softc *,
240e5ec1e72Spatrick 		    struct bwfm_pci_msgring *, int, int *);
241e5ec1e72Spatrick void *		 bwfm_pci_ring_read_avail(struct bwfm_pci_softc *,
242e5ec1e72Spatrick 		    struct bwfm_pci_msgring *, int *);
243e5ec1e72Spatrick void		 bwfm_pci_ring_read_commit(struct bwfm_pci_softc *,
244e5ec1e72Spatrick 		    struct bwfm_pci_msgring *, int);
245e5ec1e72Spatrick void		 bwfm_pci_ring_write_commit(struct bwfm_pci_softc *,
246e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
247e5ec1e72Spatrick void		 bwfm_pci_ring_write_cancel(struct bwfm_pci_softc *,
248e5ec1e72Spatrick 		    struct bwfm_pci_msgring *, int);
249e5ec1e72Spatrick 
250e5ec1e72Spatrick void		 bwfm_pci_ring_rx(struct bwfm_pci_softc *,
251e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
252e5ec1e72Spatrick void		 bwfm_pci_msg_rx(struct bwfm_pci_softc *, void *);
253e5ec1e72Spatrick 
254e5ec1e72Spatrick uint32_t	 bwfm_pci_buscore_read(struct bwfm_softc *, uint32_t);
255e5ec1e72Spatrick void		 bwfm_pci_buscore_write(struct bwfm_softc *, uint32_t,
256e5ec1e72Spatrick 		    uint32_t);
257e5ec1e72Spatrick int		 bwfm_pci_buscore_prepare(struct bwfm_softc *);
258e5ec1e72Spatrick int		 bwfm_pci_buscore_reset(struct bwfm_softc *);
259e5ec1e72Spatrick void		 bwfm_pci_buscore_activate(struct bwfm_softc *, uint32_t);
260e5ec1e72Spatrick 
261f67437f3Spatrick int		 bwfm_pci_flowring_lookup(struct bwfm_pci_softc *,
262f67437f3Spatrick 		     struct mbuf *);
263f67437f3Spatrick void		 bwfm_pci_flowring_create(struct bwfm_pci_softc *,
264518be5f3Spatrick 		     struct mbuf *);
265518be5f3Spatrick void		 bwfm_pci_flowring_create_cb(struct bwfm_softc *, void *);
266a2c6ff8bSpatrick void		 bwfm_pci_flowring_delete(struct bwfm_pci_softc *, int);
267518be5f3Spatrick 
268972218f3Spatrick int		 bwfm_pci_preinit(struct bwfm_softc *);
269a2c6ff8bSpatrick void		 bwfm_pci_stop(struct bwfm_softc *);
27002ee7d07Spatrick int		 bwfm_pci_txcheck(struct bwfm_softc *);
271e5ec1e72Spatrick int		 bwfm_pci_txdata(struct bwfm_softc *, struct mbuf *);
272bbd71b0bSpatrick 
273bbd71b0bSpatrick #ifdef BWFM_DEBUG
274cadf5fcfSpatrick void		 bwfm_pci_debug_console(struct bwfm_pci_softc *);
275bbd71b0bSpatrick #endif
276e5ec1e72Spatrick 
277e5ec1e72Spatrick int		 bwfm_pci_msgbuf_query_dcmd(struct bwfm_softc *, int,
278e5ec1e72Spatrick 		    int, char *, size_t *);
279e5ec1e72Spatrick int		 bwfm_pci_msgbuf_set_dcmd(struct bwfm_softc *, int,
280e5ec1e72Spatrick 		    int, char *, size_t);
2812eeba925Spatrick void		 bwfm_pci_msgbuf_rxioctl(struct bwfm_pci_softc *,
2822eeba925Spatrick 		    struct msgbuf_ioctl_resp_hdr *);
283e5ec1e72Spatrick 
284e5ec1e72Spatrick struct bwfm_buscore_ops bwfm_pci_buscore_ops = {
285e5ec1e72Spatrick 	.bc_read = bwfm_pci_buscore_read,
286e5ec1e72Spatrick 	.bc_write = bwfm_pci_buscore_write,
287e5ec1e72Spatrick 	.bc_prepare = bwfm_pci_buscore_prepare,
288e5ec1e72Spatrick 	.bc_reset = bwfm_pci_buscore_reset,
289e5ec1e72Spatrick 	.bc_setup = NULL,
290e5ec1e72Spatrick 	.bc_activate = bwfm_pci_buscore_activate,
291e5ec1e72Spatrick };
292e5ec1e72Spatrick 
293e5ec1e72Spatrick struct bwfm_bus_ops bwfm_pci_bus_ops = {
294972218f3Spatrick 	.bs_preinit = bwfm_pci_preinit,
295a2c6ff8bSpatrick 	.bs_stop = bwfm_pci_stop,
29602ee7d07Spatrick 	.bs_txcheck = bwfm_pci_txcheck,
297e5ec1e72Spatrick 	.bs_txdata = bwfm_pci_txdata,
298e5ec1e72Spatrick 	.bs_txctl = NULL,
299e5ec1e72Spatrick };
300e5ec1e72Spatrick 
301e5ec1e72Spatrick struct bwfm_proto_ops bwfm_pci_msgbuf_ops = {
302e5ec1e72Spatrick 	.proto_query_dcmd = bwfm_pci_msgbuf_query_dcmd,
303e5ec1e72Spatrick 	.proto_set_dcmd = bwfm_pci_msgbuf_set_dcmd,
30414c74651Spatrick 	.proto_rx = NULL,
305029d6dd5Spatrick 	.proto_rxctl = NULL,
306e5ec1e72Spatrick };
307e5ec1e72Spatrick 
308e5ec1e72Spatrick struct cfattach bwfm_pci_ca = {
309e5ec1e72Spatrick 	sizeof(struct bwfm_pci_softc),
310e5ec1e72Spatrick 	bwfm_pci_match,
311e5ec1e72Spatrick 	bwfm_pci_attach,
312e5ec1e72Spatrick 	bwfm_pci_detach,
313e5ec1e72Spatrick };
314e5ec1e72Spatrick 
315e5ec1e72Spatrick static const struct pci_matchid bwfm_pci_devices[] = {
31682f0e660Sjcs 	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4350 },
31741d93ac2Spatrick 	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4356 },
31841d93ac2Spatrick 	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM43602 },
319821fc986Spatrick 	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4371 },
320e5ec1e72Spatrick };
321e5ec1e72Spatrick 
322e5ec1e72Spatrick int
323e5ec1e72Spatrick bwfm_pci_match(struct device *parent, void *match, void *aux)
324e5ec1e72Spatrick {
325e5ec1e72Spatrick 	return (pci_matchbyid(aux, bwfm_pci_devices,
326e5ec1e72Spatrick 	    nitems(bwfm_pci_devices)));
327e5ec1e72Spatrick }
328e5ec1e72Spatrick 
329e5ec1e72Spatrick void
330e5ec1e72Spatrick bwfm_pci_attach(struct device *parent, struct device *self, void *aux)
331e5ec1e72Spatrick {
332e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (struct bwfm_pci_softc *)self;
333e5ec1e72Spatrick 	struct pci_attach_args *pa = (struct pci_attach_args *)aux;
334e5ec1e72Spatrick 	const char *intrstr;
335e5ec1e72Spatrick 	pci_intr_handle_t ih;
336e5ec1e72Spatrick 
337e5ec1e72Spatrick 	if (pci_mapreg_map(pa, PCI_MAPREG_START + 0x08,
338e5ec1e72Spatrick 	    PCI_MAPREG_MEM_TYPE_64BIT, 0, &sc->sc_tcm_iot, &sc->sc_tcm_ioh,
339e5ec1e72Spatrick 	    NULL, &sc->sc_tcm_ios, 0)) {
340e5ec1e72Spatrick 		printf(": can't map bar1\n");
341a08e9144Spatrick 		return;
342a08e9144Spatrick 	}
343a08e9144Spatrick 
344a08e9144Spatrick 	if (pci_mapreg_map(pa, PCI_MAPREG_START + 0x00,
345a08e9144Spatrick 	    PCI_MAPREG_MEM_TYPE_64BIT, 0, &sc->sc_reg_iot, &sc->sc_reg_ioh,
346a08e9144Spatrick 	    NULL, &sc->sc_reg_ios, 0)) {
347a08e9144Spatrick 		printf(": can't map bar0\n");
348a08e9144Spatrick 		goto bar1;
349e5ec1e72Spatrick 	}
350e5ec1e72Spatrick 
351e5ec1e72Spatrick 	sc->sc_pc = pa->pa_pc;
352e5ec1e72Spatrick 	sc->sc_tag = pa->pa_tag;
353e5ec1e72Spatrick 	sc->sc_id = pa->pa_id;
354e5ec1e72Spatrick 	sc->sc_dmat = pa->pa_dmat;
355e5ec1e72Spatrick 
356e5ec1e72Spatrick 	/* Map and establish the interrupt. */
357e5ec1e72Spatrick 	if (pci_intr_map_msi(pa, &ih) != 0 && pci_intr_map(pa, &ih) != 0) {
358e5ec1e72Spatrick 		printf(": couldn't map interrupt\n");
359a08e9144Spatrick 		goto bar0;
360e5ec1e72Spatrick 	}
361e5ec1e72Spatrick 	intrstr = pci_intr_string(pa->pa_pc, ih);
362e5ec1e72Spatrick 
363e5ec1e72Spatrick 	sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_NET | IPL_MPSAFE,
364e5ec1e72Spatrick 	    bwfm_pci_intr, sc, DEVNAME(sc));
365e5ec1e72Spatrick 	if (sc->sc_ih == NULL) {
366e5ec1e72Spatrick 		printf(": couldn't establish interrupt");
367e5ec1e72Spatrick 		if (intrstr != NULL)
368e5ec1e72Spatrick 			printf(" at %s", intrstr);
369e5ec1e72Spatrick 		printf("\n");
370e5ec1e72Spatrick 		goto bar1;
371e5ec1e72Spatrick 	}
372e5ec1e72Spatrick 	printf(": %s\n", intrstr);
373e5ec1e72Spatrick 
374972218f3Spatrick 	sc->sc_sc.sc_bus_ops = &bwfm_pci_bus_ops;
375972218f3Spatrick 	sc->sc_sc.sc_proto_ops = &bwfm_pci_msgbuf_ops;
376972218f3Spatrick 	bwfm_attach(&sc->sc_sc);
377972218f3Spatrick 	config_mountroot(self, bwfm_attachhook);
378e5ec1e72Spatrick 	return;
379e5ec1e72Spatrick 
380e5ec1e72Spatrick bar0:
381e5ec1e72Spatrick 	bus_space_unmap(sc->sc_reg_iot, sc->sc_reg_ioh, sc->sc_reg_ios);
382a08e9144Spatrick bar1:
383a08e9144Spatrick 	bus_space_unmap(sc->sc_tcm_iot, sc->sc_tcm_ioh, sc->sc_tcm_ios);
384e5ec1e72Spatrick }
385e5ec1e72Spatrick 
386972218f3Spatrick int
387972218f3Spatrick bwfm_pci_preinit(struct bwfm_softc *bwfm)
388e5ec1e72Spatrick {
389972218f3Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
390e5ec1e72Spatrick 	struct bwfm_pci_ringinfo ringinfo;
3916aad491fSpatrick 	const char *name, *nvname;
3926aad491fSpatrick 	u_char *ucode, *nvram = NULL;
3936aad491fSpatrick 	size_t size, nvlen = 0;
394e5ec1e72Spatrick 	uint32_t d2h_w_idx_ptr, d2h_r_idx_ptr;
395e5ec1e72Spatrick 	uint32_t h2d_w_idx_ptr, h2d_r_idx_ptr;
396e5ec1e72Spatrick 	uint32_t idx_offset, reg;
397e5ec1e72Spatrick 	int i;
398e5ec1e72Spatrick 
399972218f3Spatrick 	if (sc->sc_initialized)
400972218f3Spatrick 		return 0;
401972218f3Spatrick 
402e5ec1e72Spatrick 	sc->sc_sc.sc_buscore_ops = &bwfm_pci_buscore_ops;
403e5ec1e72Spatrick 	if (bwfm_chip_attach(&sc->sc_sc) != 0) {
404e5ec1e72Spatrick 		printf("%s: cannot attach chip\n", DEVNAME(sc));
405972218f3Spatrick 		return 1;
406e5ec1e72Spatrick 	}
407e5ec1e72Spatrick 
408e5ec1e72Spatrick 	bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2);
409e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
410e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_CONFIGADDR, 0x4e0);
411e5ec1e72Spatrick 	reg = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
412e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_CONFIGDATA);
413e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
414e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_CONFIGDATA, reg);
415e5ec1e72Spatrick 
416e5ec1e72Spatrick 	switch (bwfm->sc_chip.ch_chip)
417e5ec1e72Spatrick 	{
41818b3a1dcSpatrick 	case BRCM_CC_4350_CHIP_ID:
4196aad491fSpatrick 		if (bwfm->sc_chip.ch_chiprev > 7) {
42018b3a1dcSpatrick 			name = "brcmfmac4350-pcie.bin";
4216aad491fSpatrick 			nvname = "brcmfmac4350-pcie.nvram";
4226aad491fSpatrick 		} else {
42318b3a1dcSpatrick 			name = "brcmfmac4350c2-pcie.bin";
4246aad491fSpatrick 			nvname = "brcmfmac4350c2-pcie.nvram";
4256aad491fSpatrick 		}
42618b3a1dcSpatrick 		break;
42741d93ac2Spatrick 	case BRCM_CC_4356_CHIP_ID:
42841d93ac2Spatrick 		name = "brcmfmac4356-pcie.bin";
42941d93ac2Spatrick 		nvname = "brcmfmac4356-pcie.nvram";
43041d93ac2Spatrick 		break;
431e5ec1e72Spatrick 	case BRCM_CC_43602_CHIP_ID:
432e5ec1e72Spatrick 		name = "brcmfmac43602-pcie.bin";
4336aad491fSpatrick 		nvname = "brcmfmac43602-pcie.nvram";
434e5ec1e72Spatrick 		break;
435821fc986Spatrick 	case BRCM_CC_4371_CHIP_ID:
436821fc986Spatrick 		name = "brcmfmac4371-pcie.bin";
437821fc986Spatrick 		nvname = "brcmfmac4371-pcie.nvram";
438821fc986Spatrick 		break;
439e5ec1e72Spatrick 	default:
44018b3a1dcSpatrick 		printf("%s: unknown firmware for chip %s\n",
44118b3a1dcSpatrick 		    DEVNAME(sc), bwfm->sc_chip.ch_name);
442972218f3Spatrick 		return 1;
443e5ec1e72Spatrick 	}
444e5ec1e72Spatrick 
445e5ec1e72Spatrick 	if (loadfirmware(name, &ucode, &size) != 0) {
446e5ec1e72Spatrick 		printf("%s: failed loadfirmware of file %s\n",
447e5ec1e72Spatrick 		    DEVNAME(sc), name);
448972218f3Spatrick 		return 1;
449e5ec1e72Spatrick 	}
450e5ec1e72Spatrick 
4516aad491fSpatrick 	/* NVRAM is optional. */
4526aad491fSpatrick 	loadfirmware(nvname, &nvram, &nvlen);
4536aad491fSpatrick 
454e5ec1e72Spatrick 	/* Retrieve RAM size from firmware. */
455e5ec1e72Spatrick 	if (size >= BWFM_RAMSIZE + 8) {
456e5ec1e72Spatrick 		uint32_t *ramsize = (uint32_t *)&ucode[BWFM_RAMSIZE];
457e5ec1e72Spatrick 		if (letoh32(ramsize[0]) == BWFM_RAMSIZE_MAGIC)
458e5ec1e72Spatrick 			bwfm->sc_chip.ch_ramsize = letoh32(ramsize[1]);
459e5ec1e72Spatrick 	}
460e5ec1e72Spatrick 
4616aad491fSpatrick 	if (bwfm_pci_load_microcode(sc, ucode, size, nvram, nvlen) != 0) {
462e5ec1e72Spatrick 		printf("%s: could not load microcode\n",
463e5ec1e72Spatrick 		    DEVNAME(sc));
464e5ec1e72Spatrick 		free(ucode, M_DEVBUF, size);
4656aad491fSpatrick 		free(nvram, M_DEVBUF, nvlen);
466972218f3Spatrick 		return 1;
467e5ec1e72Spatrick 	}
468e5ec1e72Spatrick 	free(ucode, M_DEVBUF, size);
4696aad491fSpatrick 	free(nvram, M_DEVBUF, nvlen);
470e5ec1e72Spatrick 
471e5ec1e72Spatrick 	sc->sc_shared_flags = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
472e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_INFO);
473e5ec1e72Spatrick 	sc->sc_shared_version = sc->sc_shared_flags;
474e5ec1e72Spatrick 	if (sc->sc_shared_version > BWFM_SHARED_INFO_MAX_VERSION ||
475e5ec1e72Spatrick 	    sc->sc_shared_version < BWFM_SHARED_INFO_MIN_VERSION) {
476e5ec1e72Spatrick 		printf("%s: PCIe version %d unsupported\n",
477e5ec1e72Spatrick 		    DEVNAME(sc), sc->sc_shared_version);
478972218f3Spatrick 		return 1;
479e5ec1e72Spatrick 	}
480e5ec1e72Spatrick 
481e5ec1e72Spatrick 	if (sc->sc_shared_flags & BWFM_SHARED_INFO_DMA_INDEX) {
482e5ec1e72Spatrick 		if (sc->sc_shared_flags & BWFM_SHARED_INFO_DMA_2B_IDX)
483e5ec1e72Spatrick 			sc->sc_dma_idx_sz = sizeof(uint16_t);
484e5ec1e72Spatrick 		else
485e5ec1e72Spatrick 			sc->sc_dma_idx_sz = sizeof(uint32_t);
486e5ec1e72Spatrick 	}
487e5ec1e72Spatrick 
488e5ec1e72Spatrick 	/* Maximum RX data buffers in the ring. */
489e5ec1e72Spatrick 	sc->sc_max_rxbufpost = bus_space_read_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
490e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_MAX_RXBUFPOST);
491e5ec1e72Spatrick 	if (sc->sc_max_rxbufpost == 0)
492e5ec1e72Spatrick 		sc->sc_max_rxbufpost = BWFM_SHARED_MAX_RXBUFPOST_DEFAULT;
493e5ec1e72Spatrick 
494e5ec1e72Spatrick 	/* Alternative offset of data in a packet */
495e5ec1e72Spatrick 	sc->sc_rx_dataoffset = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
496e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_RX_DATAOFFSET);
497e5ec1e72Spatrick 
498e5ec1e72Spatrick 	/* For Power Management */
499e5ec1e72Spatrick 	sc->sc_htod_mb_data_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
500e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_HTOD_MB_DATA_ADDR);
501e5ec1e72Spatrick 	sc->sc_dtoh_mb_data_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
502e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DTOH_MB_DATA_ADDR);
503e5ec1e72Spatrick 
504e5ec1e72Spatrick 	/* Ring information */
505e5ec1e72Spatrick 	sc->sc_ring_info_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
506e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_RING_INFO_ADDR);
507e5ec1e72Spatrick 
508e5ec1e72Spatrick 	/* Firmware's "dmesg" */
509e5ec1e72Spatrick 	sc->sc_console_base_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
510e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_CONSOLE_ADDR);
511e5ec1e72Spatrick 	sc->sc_console_buf_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
512e5ec1e72Spatrick 	    sc->sc_console_base_addr + BWFM_CONSOLE_BUFADDR);
513e5ec1e72Spatrick 	sc->sc_console_buf_size = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
514e5ec1e72Spatrick 	    sc->sc_console_base_addr + BWFM_CONSOLE_BUFSIZE);
515e5ec1e72Spatrick 
516e5ec1e72Spatrick 	/* Read ring information. */
517e5ec1e72Spatrick 	bus_space_read_region_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
518e5ec1e72Spatrick 	    sc->sc_ring_info_addr, (void *)&ringinfo, sizeof(ringinfo));
519e5ec1e72Spatrick 
520e5ec1e72Spatrick 	if (sc->sc_shared_version >= 6) {
521e5ec1e72Spatrick 		sc->sc_max_submissionrings = le16toh(ringinfo.max_submissionrings);
522e5ec1e72Spatrick 		sc->sc_max_flowrings = le16toh(ringinfo.max_flowrings);
523e5ec1e72Spatrick 		sc->sc_max_completionrings = le16toh(ringinfo.max_completionrings);
524e5ec1e72Spatrick 	} else {
525e5ec1e72Spatrick 		sc->sc_max_submissionrings = le16toh(ringinfo.max_flowrings);
526e5ec1e72Spatrick 		sc->sc_max_flowrings = sc->sc_max_submissionrings -
527e5ec1e72Spatrick 		    BWFM_NUM_TX_MSGRINGS;
528e5ec1e72Spatrick 		sc->sc_max_completionrings = BWFM_NUM_RX_MSGRINGS;
529e5ec1e72Spatrick 	}
530e5ec1e72Spatrick 
531e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
532e5ec1e72Spatrick 		d2h_w_idx_ptr = letoh32(ringinfo.d2h_w_idx_ptr);
533e5ec1e72Spatrick 		d2h_r_idx_ptr = letoh32(ringinfo.d2h_r_idx_ptr);
534e5ec1e72Spatrick 		h2d_w_idx_ptr = letoh32(ringinfo.h2d_w_idx_ptr);
535e5ec1e72Spatrick 		h2d_r_idx_ptr = letoh32(ringinfo.h2d_r_idx_ptr);
536e5ec1e72Spatrick 		idx_offset = sizeof(uint32_t);
537e5ec1e72Spatrick 	} else {
538e5ec1e72Spatrick 		uint64_t address;
539e5ec1e72Spatrick 
540e5ec1e72Spatrick 		/* Each TX/RX Ring has a Read and Write Ptr */
541e5ec1e72Spatrick 		sc->sc_dma_idx_bufsz = (sc->sc_max_submissionrings +
542e5ec1e72Spatrick 		    sc->sc_max_completionrings) * sc->sc_dma_idx_sz * 2;
543e5ec1e72Spatrick 		sc->sc_dma_idx_buf = bwfm_pci_dmamem_alloc(sc,
544e5ec1e72Spatrick 		    sc->sc_dma_idx_bufsz, 8);
545e5ec1e72Spatrick 		if (sc->sc_dma_idx_buf == NULL) {
546e5ec1e72Spatrick 			/* XXX: Fallback to TCM? */
547e5ec1e72Spatrick 			printf("%s: cannot allocate idx buf\n",
548e5ec1e72Spatrick 			    DEVNAME(sc));
549972218f3Spatrick 			return 1;
550e5ec1e72Spatrick 		}
551e5ec1e72Spatrick 
552e5ec1e72Spatrick 		idx_offset = sc->sc_dma_idx_sz;
553e5ec1e72Spatrick 		h2d_w_idx_ptr = 0;
554e5ec1e72Spatrick 		address = BWFM_PCI_DMA_DVA(sc->sc_dma_idx_buf);
555e5ec1e72Spatrick 		ringinfo.h2d_w_idx_hostaddr_low =
556e5ec1e72Spatrick 		    htole32(address & 0xffffffff);
557e5ec1e72Spatrick 		ringinfo.h2d_w_idx_hostaddr_high =
558e5ec1e72Spatrick 		    htole32(address >> 32);
559e5ec1e72Spatrick 
560e5ec1e72Spatrick 		h2d_r_idx_ptr = h2d_w_idx_ptr +
561e5ec1e72Spatrick 		    sc->sc_max_submissionrings * idx_offset;
562e5ec1e72Spatrick 		address += sc->sc_max_submissionrings * idx_offset;
563e5ec1e72Spatrick 		ringinfo.h2d_r_idx_hostaddr_low =
564e5ec1e72Spatrick 		    htole32(address & 0xffffffff);
565e5ec1e72Spatrick 		ringinfo.h2d_r_idx_hostaddr_high =
566e5ec1e72Spatrick 		    htole32(address >> 32);
567e5ec1e72Spatrick 
568e5ec1e72Spatrick 		d2h_w_idx_ptr = h2d_r_idx_ptr +
569e5ec1e72Spatrick 		    sc->sc_max_submissionrings * idx_offset;
570e5ec1e72Spatrick 		address += sc->sc_max_submissionrings * idx_offset;
571e5ec1e72Spatrick 		ringinfo.d2h_w_idx_hostaddr_low =
572e5ec1e72Spatrick 		    htole32(address & 0xffffffff);
573e5ec1e72Spatrick 		ringinfo.d2h_w_idx_hostaddr_high =
574e5ec1e72Spatrick 		    htole32(address >> 32);
575e5ec1e72Spatrick 
576e5ec1e72Spatrick 		d2h_r_idx_ptr = d2h_w_idx_ptr +
577e5ec1e72Spatrick 		    sc->sc_max_completionrings * idx_offset;
578e5ec1e72Spatrick 		address += sc->sc_max_completionrings * idx_offset;
579e5ec1e72Spatrick 		ringinfo.d2h_r_idx_hostaddr_low =
580e5ec1e72Spatrick 		    htole32(address & 0xffffffff);
581e5ec1e72Spatrick 		ringinfo.d2h_r_idx_hostaddr_high =
582e5ec1e72Spatrick 		    htole32(address >> 32);
583e5ec1e72Spatrick 
584e5ec1e72Spatrick 		bus_space_write_region_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
585e5ec1e72Spatrick 		    sc->sc_ring_info_addr, (void *)&ringinfo, sizeof(ringinfo));
586e5ec1e72Spatrick 	}
587e5ec1e72Spatrick 
588e5ec1e72Spatrick 	uint32_t ring_mem_ptr = letoh32(ringinfo.ringmem);
589e5ec1e72Spatrick 	/* TX ctrl ring: Send ctrl buffers, send IOCTLs */
590e5ec1e72Spatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_ctrl_submit, 64, 40,
591e5ec1e72Spatrick 	    h2d_w_idx_ptr, h2d_r_idx_ptr, 0, idx_offset,
592e5ec1e72Spatrick 	    &ring_mem_ptr))
593e5ec1e72Spatrick 		goto cleanup;
594e5ec1e72Spatrick 	/* TX rxpost ring: Send clean data mbufs for RX */
595e5ec1e72Spatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_rxpost_submit, 512, 32,
596e5ec1e72Spatrick 	    h2d_w_idx_ptr, h2d_r_idx_ptr, 1, idx_offset,
597e5ec1e72Spatrick 	    &ring_mem_ptr))
598e5ec1e72Spatrick 		goto cleanup;
599e5ec1e72Spatrick 	/* RX completion rings: recv our filled buffers back */
600e5ec1e72Spatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_ctrl_complete, 64, 24,
601e5ec1e72Spatrick 	    d2h_w_idx_ptr, d2h_r_idx_ptr, 0, idx_offset,
602e5ec1e72Spatrick 	    &ring_mem_ptr))
603e5ec1e72Spatrick 		goto cleanup;
604e5ec1e72Spatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_tx_complete, 1024, 16,
605e5ec1e72Spatrick 	    d2h_w_idx_ptr, d2h_r_idx_ptr, 1, idx_offset,
606e5ec1e72Spatrick 	    &ring_mem_ptr))
607e5ec1e72Spatrick 		goto cleanup;
608e5ec1e72Spatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_rx_complete, 512, 32,
609e5ec1e72Spatrick 	    d2h_w_idx_ptr, d2h_r_idx_ptr, 2, idx_offset,
610e5ec1e72Spatrick 	    &ring_mem_ptr))
611e5ec1e72Spatrick 		goto cleanup;
612e5ec1e72Spatrick 
613e5ec1e72Spatrick 	/* Dynamic TX rings for actual data */
614e5ec1e72Spatrick 	sc->sc_flowrings = malloc(sc->sc_max_flowrings *
615e5ec1e72Spatrick 	    sizeof(struct bwfm_pci_msgring), M_DEVBUF, M_WAITOK | M_ZERO);
616518be5f3Spatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
617518be5f3Spatrick 		struct bwfm_pci_msgring *ring = &sc->sc_flowrings[i];
618518be5f3Spatrick 		ring->w_idx_addr = h2d_w_idx_ptr + (i + 2) * idx_offset;
619518be5f3Spatrick 		ring->r_idx_addr = h2d_r_idx_ptr + (i + 2) * idx_offset;
620518be5f3Spatrick 	}
621e5ec1e72Spatrick 
622e5ec1e72Spatrick 	/* Scratch and ring update buffers for firmware */
623e5ec1e72Spatrick 	if ((sc->sc_scratch_buf = bwfm_pci_dmamem_alloc(sc,
624e5ec1e72Spatrick 	    BWFM_DMA_D2H_SCRATCH_BUF_LEN, 8)) == NULL)
625e5ec1e72Spatrick 		goto cleanup;
626e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
627e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_SCRATCH_ADDR_LOW,
628e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(sc->sc_scratch_buf) & 0xffffffff);
629e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
630e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_SCRATCH_ADDR_HIGH,
631e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(sc->sc_scratch_buf) >> 32);
632e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
633e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_SCRATCH_LEN,
634e5ec1e72Spatrick 	    BWFM_DMA_D2H_SCRATCH_BUF_LEN);
635e5ec1e72Spatrick 
636e5ec1e72Spatrick 	if ((sc->sc_ringupd_buf = bwfm_pci_dmamem_alloc(sc,
637e5ec1e72Spatrick 	    BWFM_DMA_D2H_RINGUPD_BUF_LEN, 8)) == NULL)
638e5ec1e72Spatrick 		goto cleanup;
639e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
640e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_RINGUPD_ADDR_LOW,
641e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(sc->sc_ringupd_buf) & 0xffffffff);
642e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
643e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_RINGUPD_ADDR_HIGH,
644e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(sc->sc_ringupd_buf) >> 32);
645e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
646e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_RINGUPD_LEN,
647e5ec1e72Spatrick 	    BWFM_DMA_D2H_RINGUPD_BUF_LEN);
648e5ec1e72Spatrick 
649e5ec1e72Spatrick 	bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2);
650e5ec1e72Spatrick 	bwfm_pci_intr_enable(sc);
651e5ec1e72Spatrick 
652e5ec1e72Spatrick 	/* Maps RX mbufs to a packet id and back. */
653e5ec1e72Spatrick 	sc->sc_rx_pkts.npkt = BWFM_NUM_RX_PKTIDS;
654e5ec1e72Spatrick 	sc->sc_rx_pkts.pkts = malloc(BWFM_NUM_RX_PKTIDS *
655e5ec1e72Spatrick 	    sizeof(struct bwfm_pci_buf), M_DEVBUF, M_WAITOK | M_ZERO);
656e5ec1e72Spatrick 	for (i = 0; i < BWFM_NUM_RX_PKTIDS; i++)
657e5ec1e72Spatrick 		bus_dmamap_create(sc->sc_dmat, MSGBUF_MAX_PKT_SIZE,
658e5ec1e72Spatrick 		    BWFM_NUM_RX_DESCS, MSGBUF_MAX_PKT_SIZE, 0, BUS_DMA_WAITOK,
659e5ec1e72Spatrick 		    &sc->sc_rx_pkts.pkts[i].bb_map);
660e5ec1e72Spatrick 
661e5ec1e72Spatrick 	/* Maps TX mbufs to a packet id and back. */
662f416501bSpatrick 	sc->sc_tx_pkts.npkt = BWFM_NUM_TX_PKTIDS;
663e5ec1e72Spatrick 	sc->sc_tx_pkts.pkts = malloc(BWFM_NUM_TX_PKTIDS
664e5ec1e72Spatrick 	    * sizeof(struct bwfm_pci_buf), M_DEVBUF, M_WAITOK | M_ZERO);
665e5ec1e72Spatrick 	for (i = 0; i < BWFM_NUM_TX_PKTIDS; i++)
666e5ec1e72Spatrick 		bus_dmamap_create(sc->sc_dmat, MSGBUF_MAX_PKT_SIZE,
667e5ec1e72Spatrick 		    BWFM_NUM_TX_DESCS, MSGBUF_MAX_PKT_SIZE, 0, BUS_DMA_WAITOK,
668e5ec1e72Spatrick 		    &sc->sc_tx_pkts.pkts[i].bb_map);
669e5ec1e72Spatrick 
6702eeba925Spatrick 	/* Maps IOCTL mbufs to a packet id and back. */
6712eeba925Spatrick 	sc->sc_ioctl_pkts.npkt = BWFM_NUM_IOCTL_PKTIDS;
6722eeba925Spatrick 	sc->sc_ioctl_pkts.pkts = malloc(BWFM_NUM_IOCTL_PKTIDS
6732eeba925Spatrick 	    * sizeof(struct bwfm_pci_buf), M_DEVBUF, M_WAITOK | M_ZERO);
6742eeba925Spatrick 	for (i = 0; i < BWFM_NUM_IOCTL_PKTIDS; i++)
6752eeba925Spatrick 		bus_dmamap_create(sc->sc_dmat, MSGBUF_MAX_PKT_SIZE,
6762eeba925Spatrick 		    BWFM_NUM_IOCTL_DESCS, MSGBUF_MAX_PKT_SIZE, 0, BUS_DMA_WAITOK,
6772eeba925Spatrick 		    &sc->sc_ioctl_pkts.pkts[i].bb_map);
6782eeba925Spatrick 
67918722113Spatrick 	/*
68018722113Spatrick 	 * For whatever reason, could also be a bug somewhere in this
68118722113Spatrick 	 * driver, the firmware needs a bunch of RX buffers otherwise
68218722113Spatrick 	 * it won't send any RX complete messages.  64 buffers don't
68318722113Spatrick 	 * suffice, but 128 buffers are enough.
68418722113Spatrick 	 */
68518722113Spatrick 	if_rxr_init(&sc->sc_rxbuf_ring, 128, sc->sc_max_rxbufpost);
686e5ec1e72Spatrick 	if_rxr_init(&sc->sc_ioctl_ring, 8, 8);
687e5ec1e72Spatrick 	if_rxr_init(&sc->sc_event_ring, 8, 8);
688e5ec1e72Spatrick 	bwfm_pci_fill_rx_rings(sc);
689e5ec1e72Spatrick 
6902eeba925Spatrick 	TAILQ_INIT(&sc->sc_ioctlq);
6912eeba925Spatrick 
692cadf5fcfSpatrick #ifdef BWFM_DEBUG
693cadf5fcfSpatrick 	sc->sc_console_readidx = 0;
694cadf5fcfSpatrick 	bwfm_pci_debug_console(sc);
695cadf5fcfSpatrick #endif
696cadf5fcfSpatrick 
697972218f3Spatrick 	sc->sc_initialized = 1;
698972218f3Spatrick 	return 0;
699e5ec1e72Spatrick 
700e5ec1e72Spatrick cleanup:
701e5ec1e72Spatrick 	if (sc->sc_ringupd_buf)
702e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_ringupd_buf);
703e5ec1e72Spatrick 	if (sc->sc_scratch_buf)
704e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_scratch_buf);
705e5ec1e72Spatrick 	if (sc->sc_rx_complete.ring)
706e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_rx_complete.ring);
707e5ec1e72Spatrick 	if (sc->sc_tx_complete.ring)
708e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_tx_complete.ring);
709e5ec1e72Spatrick 	if (sc->sc_ctrl_complete.ring)
710e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_ctrl_complete.ring);
711e5ec1e72Spatrick 	if (sc->sc_rxpost_submit.ring)
712e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_rxpost_submit.ring);
713e5ec1e72Spatrick 	if (sc->sc_ctrl_submit.ring)
714e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_ctrl_submit.ring);
715e5ec1e72Spatrick 	if (sc->sc_dma_idx_buf)
716e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_dma_idx_buf);
717972218f3Spatrick 	return 1;
718e5ec1e72Spatrick }
719e5ec1e72Spatrick 
720e5ec1e72Spatrick int
7216aad491fSpatrick bwfm_pci_load_microcode(struct bwfm_pci_softc *sc, const u_char *ucode, size_t size,
7226aad491fSpatrick     const u_char *nvram, size_t nvlen)
723e5ec1e72Spatrick {
724e5ec1e72Spatrick 	struct bwfm_softc *bwfm = (void *)sc;
725e5ec1e72Spatrick 	struct bwfm_core *core;
7266aad491fSpatrick 	uint32_t shared, written;
727e5ec1e72Spatrick 	int i;
728e5ec1e72Spatrick 
729e5ec1e72Spatrick 	if (bwfm->sc_chip.ch_chip == BRCM_CC_43602_CHIP_ID) {
730e5ec1e72Spatrick 		bwfm_pci_select_core(sc, BWFM_AGENT_CORE_ARM_CR4);
731e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
732e5ec1e72Spatrick 		    BWFM_PCI_ARMCR4REG_BANKIDX, 5);
733e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
734e5ec1e72Spatrick 		    BWFM_PCI_ARMCR4REG_BANKPDA, 0);
735e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
736e5ec1e72Spatrick 		    BWFM_PCI_ARMCR4REG_BANKIDX, 7);
737e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
738e5ec1e72Spatrick 		    BWFM_PCI_ARMCR4REG_BANKPDA, 0);
739e5ec1e72Spatrick 	}
740e5ec1e72Spatrick 
741e5ec1e72Spatrick 	for (i = 0; i < size; i++)
742e5ec1e72Spatrick 		bus_space_write_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
743e5ec1e72Spatrick 		    bwfm->sc_chip.ch_rambase + i, ucode[i]);
744e5ec1e72Spatrick 
745e5ec1e72Spatrick 	/* Firmware replaces this with a pointer once up. */
746e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
747e5ec1e72Spatrick 	    bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize - 4, 0);
748e5ec1e72Spatrick 
7496aad491fSpatrick 	if (nvram) {
7506aad491fSpatrick 		for (i = 0; i < nvlen; i++)
7516aad491fSpatrick 			bus_space_write_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
7526aad491fSpatrick 			    bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize
7536aad491fSpatrick 			    - nvlen  + i, nvram[i]);
7546aad491fSpatrick 	}
7556aad491fSpatrick 
7566aad491fSpatrick 	written = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
7576aad491fSpatrick 	    bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize - 4);
758e5ec1e72Spatrick 
759e5ec1e72Spatrick 	/* Load reset vector from firmware and kickstart core. */
760b0cd4990Spatrick 	if (bwfm->sc_chip.ch_chip == BRCM_CC_43602_CHIP_ID) {
761e5ec1e72Spatrick 		core = bwfm_chip_get_core(bwfm, BWFM_AGENT_INTERNAL_MEM);
762e5ec1e72Spatrick 		bwfm->sc_chip.ch_core_reset(bwfm, core, 0, 0, 0);
763b0cd4990Spatrick 	}
764e5ec1e72Spatrick 	bwfm_chip_set_active(bwfm, *(uint32_t *)ucode);
765e5ec1e72Spatrick 
766e5ec1e72Spatrick 	for (i = 0; i < 40; i++) {
767e5ec1e72Spatrick 		delay(50 * 1000);
768e5ec1e72Spatrick 		shared = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
769e5ec1e72Spatrick 		    bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize - 4);
7706aad491fSpatrick 		if (shared != written)
771e5ec1e72Spatrick 			break;
772e5ec1e72Spatrick 	}
773e5ec1e72Spatrick 	if (!shared) {
774e5ec1e72Spatrick 		printf("%s: firmware did not come up\n", DEVNAME(sc));
775e5ec1e72Spatrick 		return 1;
776e5ec1e72Spatrick 	}
777e5ec1e72Spatrick 
778e5ec1e72Spatrick 	sc->sc_shared_address = shared;
779e5ec1e72Spatrick 	return 0;
780e5ec1e72Spatrick }
781e5ec1e72Spatrick 
782e5ec1e72Spatrick int
783e5ec1e72Spatrick bwfm_pci_detach(struct device *self, int flags)
784e5ec1e72Spatrick {
785e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (struct bwfm_pci_softc *)self;
786e5ec1e72Spatrick 
787e5ec1e72Spatrick 	bwfm_detach(&sc->sc_sc, flags);
788e5ec1e72Spatrick 
789e5ec1e72Spatrick 	/* FIXME: free RX buffers */
790e5ec1e72Spatrick 	/* FIXME: free TX buffers */
791e5ec1e72Spatrick 	/* FIXME: free more memory */
792e5ec1e72Spatrick 
793e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_ringupd_buf);
794e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_scratch_buf);
795e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_rx_complete.ring);
796e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_tx_complete.ring);
797e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_ctrl_complete.ring);
798e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_rxpost_submit.ring);
799e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_ctrl_submit.ring);
800e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_dma_idx_buf);
801e5ec1e72Spatrick 	return 0;
802e5ec1e72Spatrick }
803e5ec1e72Spatrick 
804e5ec1e72Spatrick /* DMA code */
805e5ec1e72Spatrick struct bwfm_pci_dmamem *
806e5ec1e72Spatrick bwfm_pci_dmamem_alloc(struct bwfm_pci_softc *sc, bus_size_t size, bus_size_t align)
807e5ec1e72Spatrick {
808e5ec1e72Spatrick 	struct bwfm_pci_dmamem *bdm;
809e5ec1e72Spatrick 	int nsegs;
810e5ec1e72Spatrick 
811e5ec1e72Spatrick 	bdm = malloc(sizeof(*bdm), M_DEVBUF, M_WAITOK | M_ZERO);
812e5ec1e72Spatrick 	bdm->bdm_size = size;
813e5ec1e72Spatrick 
814e5ec1e72Spatrick 	if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
815e5ec1e72Spatrick 	    BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &bdm->bdm_map) != 0)
816e5ec1e72Spatrick 		goto bdmfree;
817e5ec1e72Spatrick 
818e5ec1e72Spatrick 	if (bus_dmamem_alloc(sc->sc_dmat, size, align, 0, &bdm->bdm_seg, 1,
819e5ec1e72Spatrick 	    &nsegs, BUS_DMA_WAITOK) != 0)
820e5ec1e72Spatrick 		goto destroy;
821e5ec1e72Spatrick 
822e5ec1e72Spatrick 	if (bus_dmamem_map(sc->sc_dmat, &bdm->bdm_seg, nsegs, size,
823e5ec1e72Spatrick 	    &bdm->bdm_kva, BUS_DMA_WAITOK | BUS_DMA_COHERENT) != 0)
824e5ec1e72Spatrick 		goto free;
825e5ec1e72Spatrick 
826e5ec1e72Spatrick 	if (bus_dmamap_load(sc->sc_dmat, bdm->bdm_map, bdm->bdm_kva, size,
827e5ec1e72Spatrick 	    NULL, BUS_DMA_WAITOK) != 0)
828e5ec1e72Spatrick 		goto unmap;
829e5ec1e72Spatrick 
830e5ec1e72Spatrick 	bzero(bdm->bdm_kva, size);
831e5ec1e72Spatrick 
832e5ec1e72Spatrick 	return (bdm);
833e5ec1e72Spatrick 
834e5ec1e72Spatrick unmap:
835e5ec1e72Spatrick 	bus_dmamem_unmap(sc->sc_dmat, bdm->bdm_kva, size);
836e5ec1e72Spatrick free:
837e5ec1e72Spatrick 	bus_dmamem_free(sc->sc_dmat, &bdm->bdm_seg, 1);
838e5ec1e72Spatrick destroy:
839e5ec1e72Spatrick 	bus_dmamap_destroy(sc->sc_dmat, bdm->bdm_map);
840e5ec1e72Spatrick bdmfree:
84165046b40Spatrick 	free(bdm, M_DEVBUF, sizeof(*bdm));
842e5ec1e72Spatrick 
843e5ec1e72Spatrick 	return (NULL);
844e5ec1e72Spatrick }
845e5ec1e72Spatrick 
846e5ec1e72Spatrick void
847e5ec1e72Spatrick bwfm_pci_dmamem_free(struct bwfm_pci_softc *sc, struct bwfm_pci_dmamem *bdm)
848e5ec1e72Spatrick {
849e5ec1e72Spatrick 	bus_dmamem_unmap(sc->sc_dmat, bdm->bdm_kva, bdm->bdm_size);
850e5ec1e72Spatrick 	bus_dmamem_free(sc->sc_dmat, &bdm->bdm_seg, 1);
851e5ec1e72Spatrick 	bus_dmamap_destroy(sc->sc_dmat, bdm->bdm_map);
85265046b40Spatrick 	free(bdm, M_DEVBUF, sizeof(*bdm));
853e5ec1e72Spatrick }
854e5ec1e72Spatrick 
855e5ec1e72Spatrick /*
856e5ec1e72Spatrick  * We need a simple mapping from a packet ID to mbufs, because when
857e5ec1e72Spatrick  * a transfer completed, we only know the ID so we have to look up
858e5ec1e72Spatrick  * the memory for the ID.  This simply looks for an empty slot.
859e5ec1e72Spatrick  */
860e5ec1e72Spatrick int
86102ee7d07Spatrick bwfm_pci_pktid_avail(struct bwfm_pci_softc *sc, struct bwfm_pci_pkts *pkts)
86202ee7d07Spatrick {
86302ee7d07Spatrick 	int i, idx;
86402ee7d07Spatrick 
86502ee7d07Spatrick 	idx = pkts->last + 1;
86602ee7d07Spatrick 	for (i = 0; i < pkts->npkt; i++) {
86702ee7d07Spatrick 		if (idx == pkts->npkt)
86802ee7d07Spatrick 			idx = 0;
86902ee7d07Spatrick 		if (pkts->pkts[idx].bb_m == NULL)
87002ee7d07Spatrick 			return 0;
87102ee7d07Spatrick 		idx++;
87202ee7d07Spatrick 	}
87302ee7d07Spatrick 	return ENOBUFS;
87402ee7d07Spatrick }
87502ee7d07Spatrick 
87602ee7d07Spatrick int
877e5ec1e72Spatrick bwfm_pci_pktid_new(struct bwfm_pci_softc *sc, struct bwfm_pci_pkts *pkts,
878e5ec1e72Spatrick     struct mbuf *m, uint32_t *pktid, paddr_t *paddr)
879e5ec1e72Spatrick {
880e5ec1e72Spatrick 	int i, idx;
881e5ec1e72Spatrick 
882e5ec1e72Spatrick 	idx = pkts->last + 1;
883e5ec1e72Spatrick 	for (i = 0; i < pkts->npkt; i++) {
884e5ec1e72Spatrick 		if (idx == pkts->npkt)
885e5ec1e72Spatrick 			idx = 0;
886e5ec1e72Spatrick 		if (pkts->pkts[idx].bb_m == NULL) {
887e5ec1e72Spatrick 			if (bus_dmamap_load_mbuf(sc->sc_dmat,
888e5ec1e72Spatrick 			    pkts->pkts[idx].bb_map, m, BUS_DMA_NOWAIT) != 0) {
889518be5f3Spatrick 				if (m_defrag(m, M_DONTWAIT))
890518be5f3Spatrick 					return EFBIG;
891518be5f3Spatrick 				if (bus_dmamap_load_mbuf(sc->sc_dmat,
892518be5f3Spatrick 				    pkts->pkts[idx].bb_map, m, BUS_DMA_NOWAIT) != 0)
893518be5f3Spatrick 					return EFBIG;
894e5ec1e72Spatrick 			}
895dcb67343Spatrick 			bus_dmamap_sync(sc->sc_dmat, pkts->pkts[idx].bb_map,
896dcb67343Spatrick 			    0, pkts->pkts[idx].bb_map->dm_mapsize,
897dcb67343Spatrick 			    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
898e5ec1e72Spatrick 			pkts->last = idx;
899e5ec1e72Spatrick 			pkts->pkts[idx].bb_m = m;
900e5ec1e72Spatrick 			*pktid = idx;
901e5ec1e72Spatrick 			*paddr = pkts->pkts[idx].bb_map->dm_segs[0].ds_addr;
902e5ec1e72Spatrick 			return 0;
903e5ec1e72Spatrick 		}
904e5ec1e72Spatrick 		idx++;
905e5ec1e72Spatrick 	}
906518be5f3Spatrick 	return ENOBUFS;
907e5ec1e72Spatrick }
908e5ec1e72Spatrick 
909e5ec1e72Spatrick struct mbuf *
910e5ec1e72Spatrick bwfm_pci_pktid_free(struct bwfm_pci_softc *sc, struct bwfm_pci_pkts *pkts,
911e5ec1e72Spatrick     uint32_t pktid)
912e5ec1e72Spatrick {
913e5ec1e72Spatrick 	struct mbuf *m;
914e5ec1e72Spatrick 
915e5ec1e72Spatrick 	if (pktid >= pkts->npkt || pkts->pkts[pktid].bb_m == NULL)
916e5ec1e72Spatrick 		return NULL;
917dcb67343Spatrick 	bus_dmamap_sync(sc->sc_dmat, pkts->pkts[pktid].bb_map, 0,
918dcb67343Spatrick 	    pkts->pkts[pktid].bb_map->dm_mapsize,
919dcb67343Spatrick 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
920e5ec1e72Spatrick 	bus_dmamap_unload(sc->sc_dmat, pkts->pkts[pktid].bb_map);
921e5ec1e72Spatrick 	m = pkts->pkts[pktid].bb_m;
922e5ec1e72Spatrick 	pkts->pkts[pktid].bb_m = NULL;
923e5ec1e72Spatrick 	return m;
924e5ec1e72Spatrick }
925e5ec1e72Spatrick 
926e5ec1e72Spatrick void
927e5ec1e72Spatrick bwfm_pci_fill_rx_rings(struct bwfm_pci_softc *sc)
928e5ec1e72Spatrick {
92918722113Spatrick 	bwfm_pci_fill_rx_buf_ring(sc);
930e5ec1e72Spatrick 	bwfm_pci_fill_rx_ioctl_ring(sc, &sc->sc_ioctl_ring,
931e5ec1e72Spatrick 	    MSGBUF_TYPE_IOCTLRESP_BUF_POST);
932e5ec1e72Spatrick 	bwfm_pci_fill_rx_ioctl_ring(sc, &sc->sc_event_ring,
933e5ec1e72Spatrick 	    MSGBUF_TYPE_EVENT_BUF_POST);
934e5ec1e72Spatrick }
935e5ec1e72Spatrick 
936e5ec1e72Spatrick void
937e5ec1e72Spatrick bwfm_pci_fill_rx_ioctl_ring(struct bwfm_pci_softc *sc, struct if_rxring *rxring,
938e5ec1e72Spatrick     uint32_t msgtype)
939e5ec1e72Spatrick {
940e5ec1e72Spatrick 	struct msgbuf_rx_ioctl_resp_or_event *req;
941e5ec1e72Spatrick 	struct mbuf *m;
942e5ec1e72Spatrick 	uint32_t pktid;
943e5ec1e72Spatrick 	paddr_t paddr;
944e5ec1e72Spatrick 	int s, slots;
945e5ec1e72Spatrick 
946e5ec1e72Spatrick 	s = splnet();
947e5ec1e72Spatrick 	for (slots = if_rxr_get(rxring, 8); slots > 0; slots--) {
94802ee7d07Spatrick 		if (bwfm_pci_pktid_avail(sc, &sc->sc_rx_pkts))
94902ee7d07Spatrick 			break;
950e5ec1e72Spatrick 		req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit);
951e5ec1e72Spatrick 		if (req == NULL)
952e5ec1e72Spatrick 			break;
953e5ec1e72Spatrick 		m = MCLGETI(NULL, M_DONTWAIT, NULL, MSGBUF_MAX_PKT_SIZE);
954e5ec1e72Spatrick 		if (m == NULL) {
955e5ec1e72Spatrick 			bwfm_pci_ring_write_cancel(sc, &sc->sc_ctrl_submit, 1);
956e5ec1e72Spatrick 			break;
957e5ec1e72Spatrick 		}
958e5ec1e72Spatrick 		m->m_len = m->m_pkthdr.len = MSGBUF_MAX_PKT_SIZE;
959e5ec1e72Spatrick 		if (bwfm_pci_pktid_new(sc, &sc->sc_rx_pkts, m, &pktid, &paddr)) {
960e5ec1e72Spatrick 			bwfm_pci_ring_write_cancel(sc, &sc->sc_ctrl_submit, 1);
961e5ec1e72Spatrick 			m_freem(m);
962e5ec1e72Spatrick 			break;
963e5ec1e72Spatrick 		}
964e5ec1e72Spatrick 		memset(req, 0, sizeof(*req));
965e5ec1e72Spatrick 		req->msg.msgtype = msgtype;
966e5ec1e72Spatrick 		req->msg.request_id = htole32(pktid);
967e5ec1e72Spatrick 		req->host_buf_len = htole16(MSGBUF_MAX_PKT_SIZE);
968e4dae658Spatrick 		req->host_buf_addr.high_addr = htole32((uint64_t)paddr >> 32);
969e5ec1e72Spatrick 		req->host_buf_addr.low_addr = htole32(paddr & 0xffffffff);
970e5ec1e72Spatrick 		bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit);
971e5ec1e72Spatrick 	}
972e5ec1e72Spatrick 	if_rxr_put(rxring, slots);
973e5ec1e72Spatrick 	splx(s);
974e5ec1e72Spatrick }
975e5ec1e72Spatrick 
976e5ec1e72Spatrick void
977e5ec1e72Spatrick bwfm_pci_fill_rx_buf_ring(struct bwfm_pci_softc *sc)
978e5ec1e72Spatrick {
979e5ec1e72Spatrick 	struct msgbuf_rx_bufpost *req;
980e5ec1e72Spatrick 	struct mbuf *m;
981e5ec1e72Spatrick 	uint32_t pktid;
982e5ec1e72Spatrick 	paddr_t paddr;
983e5ec1e72Spatrick 	int s, slots;
984e5ec1e72Spatrick 
985e5ec1e72Spatrick 	s = splnet();
986e5ec1e72Spatrick 	for (slots = if_rxr_get(&sc->sc_rxbuf_ring, sc->sc_max_rxbufpost);
987e5ec1e72Spatrick 	    slots > 0; slots--) {
98802ee7d07Spatrick 		if (bwfm_pci_pktid_avail(sc, &sc->sc_rx_pkts))
98902ee7d07Spatrick 			break;
990e5ec1e72Spatrick 		req = bwfm_pci_ring_write_reserve(sc, &sc->sc_rxpost_submit);
991e5ec1e72Spatrick 		if (req == NULL)
992e5ec1e72Spatrick 			break;
993e5ec1e72Spatrick 		m = MCLGETI(NULL, M_DONTWAIT, NULL, MSGBUF_MAX_PKT_SIZE);
994e5ec1e72Spatrick 		if (m == NULL) {
995e5ec1e72Spatrick 			bwfm_pci_ring_write_cancel(sc, &sc->sc_rxpost_submit, 1);
996e5ec1e72Spatrick 			break;
997e5ec1e72Spatrick 		}
998e5ec1e72Spatrick 		m->m_len = m->m_pkthdr.len = MSGBUF_MAX_PKT_SIZE;
999e5ec1e72Spatrick 		if (bwfm_pci_pktid_new(sc, &sc->sc_rx_pkts, m, &pktid, &paddr)) {
1000e5ec1e72Spatrick 			bwfm_pci_ring_write_cancel(sc, &sc->sc_rxpost_submit, 1);
1001e5ec1e72Spatrick 			m_freem(m);
1002e5ec1e72Spatrick 			break;
1003e5ec1e72Spatrick 		}
1004e5ec1e72Spatrick 		memset(req, 0, sizeof(*req));
1005e5ec1e72Spatrick 		req->msg.msgtype = MSGBUF_TYPE_RXBUF_POST;
1006e5ec1e72Spatrick 		req->msg.request_id = htole32(pktid);
1007e5ec1e72Spatrick 		req->data_buf_len = htole16(MSGBUF_MAX_PKT_SIZE);
1008e4dae658Spatrick 		req->data_buf_addr.high_addr = htole32((uint64_t)paddr >> 32);
1009e5ec1e72Spatrick 		req->data_buf_addr.low_addr = htole32(paddr & 0xffffffff);
1010e5ec1e72Spatrick 		bwfm_pci_ring_write_commit(sc, &sc->sc_rxpost_submit);
1011e5ec1e72Spatrick 	}
1012e5ec1e72Spatrick 	if_rxr_put(&sc->sc_rxbuf_ring, slots);
1013e5ec1e72Spatrick 	splx(s);
1014e5ec1e72Spatrick }
1015e5ec1e72Spatrick 
1016e5ec1e72Spatrick int
1017e5ec1e72Spatrick bwfm_pci_setup_ring(struct bwfm_pci_softc *sc, struct bwfm_pci_msgring *ring,
1018e5ec1e72Spatrick     int nitem, size_t itemsz, uint32_t w_idx, uint32_t r_idx,
1019e5ec1e72Spatrick     int idx, uint32_t idx_off, uint32_t *ring_mem)
1020e5ec1e72Spatrick {
1021e5ec1e72Spatrick 	ring->w_idx_addr = w_idx + idx * idx_off;
1022e5ec1e72Spatrick 	ring->r_idx_addr = r_idx + idx * idx_off;
1023e5ec1e72Spatrick 	ring->nitem = nitem;
1024e5ec1e72Spatrick 	ring->itemsz = itemsz;
1025e5ec1e72Spatrick 	bwfm_pci_ring_write_rptr(sc, ring);
1026e5ec1e72Spatrick 	bwfm_pci_ring_write_wptr(sc, ring);
1027e5ec1e72Spatrick 
1028e5ec1e72Spatrick 	ring->ring = bwfm_pci_dmamem_alloc(sc, nitem * itemsz, 8);
1029e5ec1e72Spatrick 	if (ring->ring == NULL)
1030e5ec1e72Spatrick 		return ENOMEM;
1031e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1032e5ec1e72Spatrick 	    *ring_mem + BWFM_RING_MEM_BASE_ADDR_LOW,
1033e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(ring->ring) & 0xffffffff);
1034e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1035e5ec1e72Spatrick 	    *ring_mem + BWFM_RING_MEM_BASE_ADDR_HIGH,
1036e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(ring->ring) >> 32);
1037e5ec1e72Spatrick 	bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1038e5ec1e72Spatrick 	    *ring_mem + BWFM_RING_MAX_ITEM, nitem);
1039e5ec1e72Spatrick 	bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1040e5ec1e72Spatrick 	    *ring_mem + BWFM_RING_LEN_ITEMS, itemsz);
1041e5ec1e72Spatrick 	*ring_mem = *ring_mem + BWFM_RING_MEM_SZ;
1042e5ec1e72Spatrick 	return 0;
1043e5ec1e72Spatrick }
1044e5ec1e72Spatrick 
1045518be5f3Spatrick int
1046518be5f3Spatrick bwfm_pci_setup_flowring(struct bwfm_pci_softc *sc, struct bwfm_pci_msgring *ring,
1047518be5f3Spatrick     int nitem, size_t itemsz)
1048518be5f3Spatrick {
1049518be5f3Spatrick 	ring->w_ptr = 0;
1050518be5f3Spatrick 	ring->r_ptr = 0;
1051518be5f3Spatrick 	ring->nitem = nitem;
1052518be5f3Spatrick 	ring->itemsz = itemsz;
1053518be5f3Spatrick 	bwfm_pci_ring_write_rptr(sc, ring);
1054518be5f3Spatrick 	bwfm_pci_ring_write_wptr(sc, ring);
1055518be5f3Spatrick 
1056518be5f3Spatrick 	ring->ring = bwfm_pci_dmamem_alloc(sc, nitem * itemsz, 8);
1057518be5f3Spatrick 	if (ring->ring == NULL)
1058518be5f3Spatrick 		return ENOMEM;
1059518be5f3Spatrick 	return 0;
1060518be5f3Spatrick }
1061518be5f3Spatrick 
1062e5ec1e72Spatrick /* Ring helpers */
1063e5ec1e72Spatrick void
1064e5ec1e72Spatrick bwfm_pci_ring_bell(struct bwfm_pci_softc *sc,
1065e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1066e5ec1e72Spatrick {
1067e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1068e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_H2D_MAILBOX, 1);
1069e5ec1e72Spatrick }
1070e5ec1e72Spatrick 
1071e5ec1e72Spatrick void
1072e5ec1e72Spatrick bwfm_pci_ring_update_rptr(struct bwfm_pci_softc *sc,
1073e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1074e5ec1e72Spatrick {
1075e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
1076e5ec1e72Spatrick 		ring->r_ptr = bus_space_read_2(sc->sc_tcm_iot,
1077e5ec1e72Spatrick 		    sc->sc_tcm_ioh, ring->r_idx_addr);
1078e5ec1e72Spatrick 	} else {
1079dcb67343Spatrick 		bus_dmamap_sync(sc->sc_dmat,
1080dcb67343Spatrick 		    BWFM_PCI_DMA_MAP(sc->sc_dma_idx_buf), ring->r_idx_addr,
1081dcb67343Spatrick 		    sizeof(uint16_t), BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1082e5ec1e72Spatrick 		ring->r_ptr = *(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf)
1083e5ec1e72Spatrick 		    + ring->r_idx_addr);
1084e5ec1e72Spatrick 	}
1085e5ec1e72Spatrick }
1086e5ec1e72Spatrick 
1087e5ec1e72Spatrick void
1088e5ec1e72Spatrick bwfm_pci_ring_update_wptr(struct bwfm_pci_softc *sc,
1089e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1090e5ec1e72Spatrick {
1091e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
1092e5ec1e72Spatrick 		ring->w_ptr = bus_space_read_2(sc->sc_tcm_iot,
1093e5ec1e72Spatrick 		    sc->sc_tcm_ioh, ring->w_idx_addr);
1094e5ec1e72Spatrick 	} else {
1095dcb67343Spatrick 		bus_dmamap_sync(sc->sc_dmat,
1096dcb67343Spatrick 		    BWFM_PCI_DMA_MAP(sc->sc_dma_idx_buf), ring->w_idx_addr,
1097dcb67343Spatrick 		    sizeof(uint16_t), BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1098e5ec1e72Spatrick 		ring->w_ptr = *(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf)
1099e5ec1e72Spatrick 		    + ring->w_idx_addr);
1100e5ec1e72Spatrick 	}
1101e5ec1e72Spatrick }
1102e5ec1e72Spatrick 
1103e5ec1e72Spatrick void
1104e5ec1e72Spatrick bwfm_pci_ring_write_rptr(struct bwfm_pci_softc *sc,
1105e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1106e5ec1e72Spatrick {
1107e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
1108e5ec1e72Spatrick 		bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1109e5ec1e72Spatrick 		    ring->r_idx_addr, ring->r_ptr);
1110e5ec1e72Spatrick 	} else {
1111e5ec1e72Spatrick 		*(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf)
1112e5ec1e72Spatrick 		    + ring->r_idx_addr) = ring->r_ptr;
1113dcb67343Spatrick 		bus_dmamap_sync(sc->sc_dmat,
1114dcb67343Spatrick 		    BWFM_PCI_DMA_MAP(sc->sc_dma_idx_buf), ring->r_idx_addr,
1115dcb67343Spatrick 		    sizeof(uint16_t), BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1116e5ec1e72Spatrick 	}
1117e5ec1e72Spatrick }
1118e5ec1e72Spatrick 
1119e5ec1e72Spatrick void
1120e5ec1e72Spatrick bwfm_pci_ring_write_wptr(struct bwfm_pci_softc *sc,
1121e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1122e5ec1e72Spatrick {
1123e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
1124e5ec1e72Spatrick 		bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1125e5ec1e72Spatrick 		    ring->w_idx_addr, ring->w_ptr);
1126e5ec1e72Spatrick 	} else {
1127e5ec1e72Spatrick 		*(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf)
1128e5ec1e72Spatrick 		    + ring->w_idx_addr) = ring->w_ptr;
1129dcb67343Spatrick 		bus_dmamap_sync(sc->sc_dmat,
1130dcb67343Spatrick 		    BWFM_PCI_DMA_MAP(sc->sc_dma_idx_buf), ring->w_idx_addr,
1131dcb67343Spatrick 		    sizeof(uint16_t), BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1132e5ec1e72Spatrick 	}
1133e5ec1e72Spatrick }
1134e5ec1e72Spatrick 
1135e5ec1e72Spatrick /*
1136e5ec1e72Spatrick  * Retrieve a free descriptor to put new stuff in, but don't commit
1137e5ec1e72Spatrick  * to it yet so we can rollback later if any error occurs.
1138e5ec1e72Spatrick  */
1139e5ec1e72Spatrick void *
1140e5ec1e72Spatrick bwfm_pci_ring_write_reserve(struct bwfm_pci_softc *sc,
1141e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1142e5ec1e72Spatrick {
1143e5ec1e72Spatrick 	int available;
1144e5ec1e72Spatrick 	char *ret;
1145e5ec1e72Spatrick 
1146e5ec1e72Spatrick 	bwfm_pci_ring_update_rptr(sc, ring);
1147e5ec1e72Spatrick 
1148e5ec1e72Spatrick 	if (ring->r_ptr > ring->w_ptr)
1149e5ec1e72Spatrick 		available = ring->r_ptr - ring->w_ptr;
1150e5ec1e72Spatrick 	else
1151e5ec1e72Spatrick 		available = ring->r_ptr + (ring->nitem - ring->w_ptr);
1152e5ec1e72Spatrick 
1153e5ec1e72Spatrick 	if (available < 1)
1154e5ec1e72Spatrick 		return NULL;
1155e5ec1e72Spatrick 
1156e5ec1e72Spatrick 	ret = BWFM_PCI_DMA_KVA(ring->ring) + (ring->w_ptr * ring->itemsz);
1157e5ec1e72Spatrick 	ring->w_ptr += 1;
1158e5ec1e72Spatrick 	if (ring->w_ptr == ring->nitem)
1159e5ec1e72Spatrick 		ring->w_ptr = 0;
1160e5ec1e72Spatrick 	return ret;
1161e5ec1e72Spatrick }
1162e5ec1e72Spatrick 
1163e5ec1e72Spatrick void *
1164e5ec1e72Spatrick bwfm_pci_ring_write_reserve_multi(struct bwfm_pci_softc *sc,
1165e5ec1e72Spatrick     struct bwfm_pci_msgring *ring, int count, int *avail)
1166e5ec1e72Spatrick {
1167e5ec1e72Spatrick 	int available;
1168e5ec1e72Spatrick 	char *ret;
1169e5ec1e72Spatrick 
1170e5ec1e72Spatrick 	bwfm_pci_ring_update_rptr(sc, ring);
1171e5ec1e72Spatrick 
1172e5ec1e72Spatrick 	if (ring->r_ptr > ring->w_ptr)
1173e5ec1e72Spatrick 		available = ring->r_ptr - ring->w_ptr;
1174e5ec1e72Spatrick 	else
1175e5ec1e72Spatrick 		available = ring->r_ptr + (ring->nitem - ring->w_ptr);
1176e5ec1e72Spatrick 
1177e5ec1e72Spatrick 	if (available < 1)
1178e5ec1e72Spatrick 		return NULL;
1179e5ec1e72Spatrick 
1180e5ec1e72Spatrick 	ret = BWFM_PCI_DMA_KVA(ring->ring) + (ring->w_ptr * ring->itemsz);
1181e5ec1e72Spatrick 	*avail = min(count, available - 1);
1182e5ec1e72Spatrick 	if (*avail + ring->w_ptr > ring->nitem)
1183e5ec1e72Spatrick 		*avail = ring->nitem - ring->w_ptr;
1184e5ec1e72Spatrick 	ring->w_ptr += *avail;
1185e5ec1e72Spatrick 	if (ring->w_ptr == ring->nitem)
1186e5ec1e72Spatrick 		ring->w_ptr = 0;
1187e5ec1e72Spatrick 	return ret;
1188e5ec1e72Spatrick }
1189e5ec1e72Spatrick 
1190e5ec1e72Spatrick /*
1191e5ec1e72Spatrick  * Read number of descriptors available (submitted by the firmware)
1192e5ec1e72Spatrick  * and retrieve pointer to first descriptor.
1193e5ec1e72Spatrick  */
1194e5ec1e72Spatrick void *
1195e5ec1e72Spatrick bwfm_pci_ring_read_avail(struct bwfm_pci_softc *sc,
1196e5ec1e72Spatrick     struct bwfm_pci_msgring *ring, int *avail)
1197e5ec1e72Spatrick {
1198e5ec1e72Spatrick 	bwfm_pci_ring_update_wptr(sc, ring);
1199e5ec1e72Spatrick 
1200e5ec1e72Spatrick 	if (ring->w_ptr >= ring->r_ptr)
1201e5ec1e72Spatrick 		*avail = ring->w_ptr - ring->r_ptr;
1202e5ec1e72Spatrick 	else
1203e5ec1e72Spatrick 		*avail = ring->nitem - ring->r_ptr;
1204e5ec1e72Spatrick 
1205e5ec1e72Spatrick 	if (*avail == 0)
1206e5ec1e72Spatrick 		return NULL;
1207e5ec1e72Spatrick 
1208dcb67343Spatrick 	bus_dmamap_sync(sc->sc_dmat, BWFM_PCI_DMA_MAP(ring->ring),
1209dcb67343Spatrick 	    ring->r_ptr * ring->itemsz, *avail * ring->itemsz,
1210dcb67343Spatrick 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1211e5ec1e72Spatrick 	return BWFM_PCI_DMA_KVA(ring->ring) + (ring->r_ptr * ring->itemsz);
1212e5ec1e72Spatrick }
1213e5ec1e72Spatrick 
1214e5ec1e72Spatrick /*
1215e5ec1e72Spatrick  * Let firmware know we read N descriptors.
1216e5ec1e72Spatrick  */
1217e5ec1e72Spatrick void
1218e5ec1e72Spatrick bwfm_pci_ring_read_commit(struct bwfm_pci_softc *sc,
1219e5ec1e72Spatrick     struct bwfm_pci_msgring *ring, int nitem)
1220e5ec1e72Spatrick {
1221e5ec1e72Spatrick 	ring->r_ptr += nitem;
1222e5ec1e72Spatrick 	if (ring->r_ptr == ring->nitem)
1223e5ec1e72Spatrick 		ring->r_ptr = 0;
1224e5ec1e72Spatrick 	bwfm_pci_ring_write_rptr(sc, ring);
1225e5ec1e72Spatrick }
1226e5ec1e72Spatrick 
1227e5ec1e72Spatrick /*
1228e5ec1e72Spatrick  * Let firmware know that we submitted some descriptors.
1229e5ec1e72Spatrick  */
1230e5ec1e72Spatrick void
1231e5ec1e72Spatrick bwfm_pci_ring_write_commit(struct bwfm_pci_softc *sc,
1232e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1233e5ec1e72Spatrick {
1234dcb67343Spatrick 	bus_dmamap_sync(sc->sc_dmat, BWFM_PCI_DMA_MAP(ring->ring),
1235dcb67343Spatrick 	    0, BWFM_PCI_DMA_LEN(ring->ring), BUS_DMASYNC_PREREAD |
1236dcb67343Spatrick 	    BUS_DMASYNC_PREWRITE);
1237e5ec1e72Spatrick 	bwfm_pci_ring_write_wptr(sc, ring);
1238e5ec1e72Spatrick 	bwfm_pci_ring_bell(sc, ring);
1239e5ec1e72Spatrick }
1240e5ec1e72Spatrick 
1241e5ec1e72Spatrick /*
1242e5ec1e72Spatrick  * Rollback N descriptors in case we don't actually want
1243e5ec1e72Spatrick  * to commit to it.
1244e5ec1e72Spatrick  */
1245e5ec1e72Spatrick void
1246e5ec1e72Spatrick bwfm_pci_ring_write_cancel(struct bwfm_pci_softc *sc,
1247e5ec1e72Spatrick     struct bwfm_pci_msgring *ring, int nitem)
1248e5ec1e72Spatrick {
1249e5ec1e72Spatrick 	if (ring->w_ptr == 0)
1250e5ec1e72Spatrick 		ring->w_ptr = ring->nitem - nitem;
1251e5ec1e72Spatrick 	else
1252e5ec1e72Spatrick 		ring->w_ptr -= nitem;
1253e5ec1e72Spatrick }
1254e5ec1e72Spatrick 
1255e5ec1e72Spatrick /*
1256e5ec1e72Spatrick  * Foreach written descriptor on the ring, pass the descriptor to
1257e5ec1e72Spatrick  * a message handler and let the firmware know we handled it.
1258e5ec1e72Spatrick  */
1259e5ec1e72Spatrick void
1260e5ec1e72Spatrick bwfm_pci_ring_rx(struct bwfm_pci_softc *sc, struct bwfm_pci_msgring *ring)
1261e5ec1e72Spatrick {
1262e5ec1e72Spatrick 	void *buf;
1263e5ec1e72Spatrick 	int avail, processed;
1264e5ec1e72Spatrick 
1265e5ec1e72Spatrick again:
1266e5ec1e72Spatrick 	buf = bwfm_pci_ring_read_avail(sc, ring, &avail);
1267e5ec1e72Spatrick 	if (buf == NULL)
1268e5ec1e72Spatrick 		return;
1269e5ec1e72Spatrick 
1270e5ec1e72Spatrick 	processed = 0;
1271e5ec1e72Spatrick 	while (avail) {
1272e5ec1e72Spatrick 		bwfm_pci_msg_rx(sc, buf + sc->sc_rx_dataoffset);
1273e5ec1e72Spatrick 		buf += ring->itemsz;
1274e5ec1e72Spatrick 		processed++;
1275e5ec1e72Spatrick 		if (processed == 48) {
1276e5ec1e72Spatrick 			bwfm_pci_ring_read_commit(sc, ring, processed);
1277e5ec1e72Spatrick 			processed = 0;
1278e5ec1e72Spatrick 		}
1279e5ec1e72Spatrick 		avail--;
1280e5ec1e72Spatrick 	}
1281e5ec1e72Spatrick 	if (processed)
1282e5ec1e72Spatrick 		bwfm_pci_ring_read_commit(sc, ring, processed);
1283e5ec1e72Spatrick 	if (ring->r_ptr == 0)
1284e5ec1e72Spatrick 		goto again;
1285e5ec1e72Spatrick }
1286e5ec1e72Spatrick 
1287e5ec1e72Spatrick void
1288e5ec1e72Spatrick bwfm_pci_msg_rx(struct bwfm_pci_softc *sc, void *buf)
1289e5ec1e72Spatrick {
1290518be5f3Spatrick 	struct ifnet *ifp = &sc->sc_sc.sc_ic.ic_if;
1291e5ec1e72Spatrick 	struct msgbuf_ioctl_resp_hdr *resp;
1292518be5f3Spatrick 	struct msgbuf_tx_status *tx;
129318722113Spatrick 	struct msgbuf_rx_complete *rx;
1294e5ec1e72Spatrick 	struct msgbuf_rx_event *event;
1295e5ec1e72Spatrick 	struct msgbuf_common_hdr *msg;
1296518be5f3Spatrick 	struct msgbuf_flowring_create_resp *fcr;
1297a2c6ff8bSpatrick 	struct msgbuf_flowring_delete_resp *fdr;
1298518be5f3Spatrick 	struct bwfm_pci_msgring *ring;
1299e5ec1e72Spatrick 	struct mbuf *m;
1300518be5f3Spatrick 	int flowid;
1301e5ec1e72Spatrick 
1302e5ec1e72Spatrick 	msg = (struct msgbuf_common_hdr *)buf;
1303e5ec1e72Spatrick 	switch (msg->msgtype)
1304e5ec1e72Spatrick 	{
1305518be5f3Spatrick 	case MSGBUF_TYPE_FLOW_RING_CREATE_CMPLT:
1306518be5f3Spatrick 		fcr = (struct msgbuf_flowring_create_resp *)buf;
1307518be5f3Spatrick 		flowid = letoh16(fcr->compl_hdr.flow_ring_id);
1308518be5f3Spatrick 		if (flowid < 2)
1309518be5f3Spatrick 			break;
1310518be5f3Spatrick 		flowid -= 2;
1311518be5f3Spatrick 		if (flowid >= sc->sc_max_flowrings)
1312518be5f3Spatrick 			break;
1313518be5f3Spatrick 		ring = &sc->sc_flowrings[flowid];
1314518be5f3Spatrick 		if (ring->status != RING_OPENING)
1315518be5f3Spatrick 			break;
1316518be5f3Spatrick 		if (fcr->compl_hdr.status) {
1317518be5f3Spatrick 			printf("%s: failed to open flowring %d\n",
1318518be5f3Spatrick 			    DEVNAME(sc), flowid);
1319518be5f3Spatrick 			ring->status = RING_CLOSED;
132002ee7d07Spatrick 			if (ring->m) {
132102ee7d07Spatrick 				m_freem(ring->m);
132202ee7d07Spatrick 				ring->m = NULL;
132302ee7d07Spatrick 			}
1324518be5f3Spatrick 			ifq_restart(&ifp->if_snd);
1325518be5f3Spatrick 			break;
1326518be5f3Spatrick 		}
1327518be5f3Spatrick 		ring->status = RING_OPEN;
132802ee7d07Spatrick 		if (ring->m != NULL) {
132902ee7d07Spatrick 			m = ring->m;
133002ee7d07Spatrick 			ring->m = NULL;
133102ee7d07Spatrick 			if (bwfm_pci_txdata(&sc->sc_sc, m))
133202ee7d07Spatrick 				m_freem(ring->m);
133302ee7d07Spatrick 		}
1334518be5f3Spatrick 		ifq_restart(&ifp->if_snd);
1335518be5f3Spatrick 		break;
1336a2c6ff8bSpatrick 	case MSGBUF_TYPE_FLOW_RING_DELETE_CMPLT:
1337a2c6ff8bSpatrick 		fdr = (struct msgbuf_flowring_delete_resp *)buf;
1338a2c6ff8bSpatrick 		flowid = letoh16(fdr->compl_hdr.flow_ring_id);
1339a2c6ff8bSpatrick 		if (flowid < 2)
1340a2c6ff8bSpatrick 			break;
1341a2c6ff8bSpatrick 		flowid -= 2;
1342a2c6ff8bSpatrick 		if (flowid >= sc->sc_max_flowrings)
1343a2c6ff8bSpatrick 			break;
1344a2c6ff8bSpatrick 		ring = &sc->sc_flowrings[flowid];
1345a2c6ff8bSpatrick 		if (ring->status != RING_CLOSING)
1346a2c6ff8bSpatrick 			break;
1347a2c6ff8bSpatrick 		if (fdr->compl_hdr.status) {
1348a2c6ff8bSpatrick 			printf("%s: failed to delete flowring %d\n",
1349a2c6ff8bSpatrick 			    DEVNAME(sc), flowid);
1350a2c6ff8bSpatrick 			break;
1351a2c6ff8bSpatrick 		}
1352a2c6ff8bSpatrick 		bwfm_pci_dmamem_free(sc, ring->ring);
1353a2c6ff8bSpatrick 		ring->status = RING_CLOSED;
1354a2c6ff8bSpatrick 		break;
1355e5ec1e72Spatrick 	case MSGBUF_TYPE_IOCTLPTR_REQ_ACK:
13562eeba925Spatrick 		m = bwfm_pci_pktid_free(sc, &sc->sc_ioctl_pkts,
13572eeba925Spatrick 		    letoh32(msg->request_id));
13582eeba925Spatrick 		if (m == NULL)
13592eeba925Spatrick 			break;
13602eeba925Spatrick 		m_freem(m);
1361e5ec1e72Spatrick 		break;
1362e5ec1e72Spatrick 	case MSGBUF_TYPE_IOCTL_CMPLT:
1363e5ec1e72Spatrick 		resp = (struct msgbuf_ioctl_resp_hdr *)buf;
13642eeba925Spatrick 		bwfm_pci_msgbuf_rxioctl(sc, resp);
1365e5ec1e72Spatrick 		if_rxr_put(&sc->sc_ioctl_ring, 1);
1366e5ec1e72Spatrick 		bwfm_pci_fill_rx_rings(sc);
1367e5ec1e72Spatrick 		break;
1368e5ec1e72Spatrick 	case MSGBUF_TYPE_WL_EVENT:
1369e5ec1e72Spatrick 		event = (struct msgbuf_rx_event *)buf;
1370e5ec1e72Spatrick 		m = bwfm_pci_pktid_free(sc, &sc->sc_rx_pkts,
1371e5ec1e72Spatrick 		    letoh32(event->msg.request_id));
1372e5ec1e72Spatrick 		if (m == NULL)
1373e5ec1e72Spatrick 			break;
1374e5ec1e72Spatrick 		m_adj(m, sc->sc_rx_dataoffset);
1375f37fc236Spatrick 		m->m_len = m->m_pkthdr.len = letoh16(event->event_data_len);
1376f37fc236Spatrick 		bwfm_rx(&sc->sc_sc, m);
1377e5ec1e72Spatrick 		if_rxr_put(&sc->sc_event_ring, 1);
1378e5ec1e72Spatrick 		bwfm_pci_fill_rx_rings(sc);
1379e5ec1e72Spatrick 		break;
1380518be5f3Spatrick 	case MSGBUF_TYPE_TX_STATUS:
1381518be5f3Spatrick 		tx = (struct msgbuf_tx_status *)buf;
1382518be5f3Spatrick 		m = bwfm_pci_pktid_free(sc, &sc->sc_tx_pkts,
1383518be5f3Spatrick 		    letoh32(tx->msg.request_id));
1384518be5f3Spatrick 		if (m == NULL)
1385518be5f3Spatrick 			break;
1386518be5f3Spatrick 		m_freem(m);
1387c6f1636dSpatrick 		if (sc->sc_tx_pkts_full) {
1388c6f1636dSpatrick 			sc->sc_tx_pkts_full = 0;
1389c6f1636dSpatrick 			ifq_restart(&ifp->if_snd);
1390c6f1636dSpatrick 		}
1391518be5f3Spatrick 		break;
139218722113Spatrick 	case MSGBUF_TYPE_RX_CMPLT:
139318722113Spatrick 		rx = (struct msgbuf_rx_complete *)buf;
139418722113Spatrick 		m = bwfm_pci_pktid_free(sc, &sc->sc_rx_pkts,
139518722113Spatrick 		    letoh32(rx->msg.request_id));
139618722113Spatrick 		if (m == NULL)
139718722113Spatrick 			break;
139818722113Spatrick 		if (letoh16(rx->data_offset))
139918722113Spatrick 			m_adj(m, letoh16(rx->data_offset));
140018722113Spatrick 		else if (sc->sc_rx_dataoffset)
140118722113Spatrick 			m_adj(m, sc->sc_rx_dataoffset);
1402f37fc236Spatrick 		m->m_len = m->m_pkthdr.len = letoh16(rx->data_len);
1403f37fc236Spatrick 		bwfm_rx(&sc->sc_sc, m);
140418722113Spatrick 		if_rxr_put(&sc->sc_rxbuf_ring, 1);
140518722113Spatrick 		bwfm_pci_fill_rx_rings(sc);
140618722113Spatrick 		break;
1407e5ec1e72Spatrick 	default:
1408e5ec1e72Spatrick 		printf("%s: msgtype 0x%08x\n", __func__, msg->msgtype);
1409e5ec1e72Spatrick 		break;
1410e5ec1e72Spatrick 	}
1411e5ec1e72Spatrick }
1412e5ec1e72Spatrick 
1413e5ec1e72Spatrick /* Bus core helpers */
1414e5ec1e72Spatrick void
1415e5ec1e72Spatrick bwfm_pci_select_core(struct bwfm_pci_softc *sc, int id)
1416e5ec1e72Spatrick {
1417e5ec1e72Spatrick 	struct bwfm_softc *bwfm = (void *)sc;
1418e5ec1e72Spatrick 	struct bwfm_core *core;
1419e5ec1e72Spatrick 
1420e5ec1e72Spatrick 	core = bwfm_chip_get_core(bwfm, id);
1421e5ec1e72Spatrick 	if (core == NULL) {
1422e5ec1e72Spatrick 		printf("%s: could not find core to select", DEVNAME(sc));
1423e5ec1e72Spatrick 		return;
1424e5ec1e72Spatrick 	}
1425e5ec1e72Spatrick 
1426e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag,
1427e5ec1e72Spatrick 	    BWFM_PCI_BAR0_WINDOW, core->co_base);
1428e5ec1e72Spatrick 	if (pci_conf_read(sc->sc_pc, sc->sc_tag,
1429e5ec1e72Spatrick 	    BWFM_PCI_BAR0_WINDOW) != core->co_base)
1430e5ec1e72Spatrick 		pci_conf_write(sc->sc_pc, sc->sc_tag,
1431e5ec1e72Spatrick 		    BWFM_PCI_BAR0_WINDOW, core->co_base);
1432e5ec1e72Spatrick }
1433e5ec1e72Spatrick 
1434e5ec1e72Spatrick uint32_t
1435e5ec1e72Spatrick bwfm_pci_buscore_read(struct bwfm_softc *bwfm, uint32_t reg)
1436e5ec1e72Spatrick {
1437e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1438e5ec1e72Spatrick 	uint32_t page, offset;
1439e5ec1e72Spatrick 
1440e5ec1e72Spatrick 	page = reg & ~(BWFM_PCI_BAR0_REG_SIZE - 1);
1441e5ec1e72Spatrick 	offset = reg & (BWFM_PCI_BAR0_REG_SIZE - 1);
1442e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_BAR0_WINDOW, page);
1443e5ec1e72Spatrick 	return bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh, offset);
1444e5ec1e72Spatrick }
1445e5ec1e72Spatrick 
1446e5ec1e72Spatrick void
1447e5ec1e72Spatrick bwfm_pci_buscore_write(struct bwfm_softc *bwfm, uint32_t reg, uint32_t val)
1448e5ec1e72Spatrick {
1449e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1450e5ec1e72Spatrick 	uint32_t page, offset;
1451e5ec1e72Spatrick 
1452e5ec1e72Spatrick 	page = reg & ~(BWFM_PCI_BAR0_REG_SIZE - 1);
1453e5ec1e72Spatrick 	offset = reg & (BWFM_PCI_BAR0_REG_SIZE - 1);
1454e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_BAR0_WINDOW, page);
1455e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, offset, val);
1456e5ec1e72Spatrick }
1457e5ec1e72Spatrick 
1458e5ec1e72Spatrick int
1459e5ec1e72Spatrick bwfm_pci_buscore_prepare(struct bwfm_softc *bwfm)
1460e5ec1e72Spatrick {
1461e5ec1e72Spatrick 	return 0;
1462e5ec1e72Spatrick }
1463e5ec1e72Spatrick 
1464e5ec1e72Spatrick int
1465e5ec1e72Spatrick bwfm_pci_buscore_reset(struct bwfm_softc *bwfm)
1466e5ec1e72Spatrick {
1467e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1468e5ec1e72Spatrick 	struct bwfm_core *core;
1469e5ec1e72Spatrick 	uint32_t reg;
1470e5ec1e72Spatrick 	int i;
1471e5ec1e72Spatrick 
1472e5ec1e72Spatrick 	bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2);
1473e5ec1e72Spatrick 	reg = pci_conf_read(sc->sc_pc, sc->sc_tag,
1474e5ec1e72Spatrick 	    BWFM_PCI_CFGREG_LINK_STATUS_CTRL);
1475e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_CFGREG_LINK_STATUS_CTRL,
1476e5ec1e72Spatrick 	    reg & ~BWFM_PCI_CFGREG_LINK_STATUS_CTRL_ASPM_ENAB);
1477e5ec1e72Spatrick 
1478e5ec1e72Spatrick 	bwfm_pci_select_core(sc, BWFM_AGENT_CORE_CHIPCOMMON);
1479e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1480e5ec1e72Spatrick 	    BWFM_CHIP_REG_WATCHDOG, 4);
1481e5ec1e72Spatrick 	delay(100 * 1000);
1482e5ec1e72Spatrick 
1483e5ec1e72Spatrick 	bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2);
1484e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag,
1485e5ec1e72Spatrick 	    BWFM_PCI_CFGREG_LINK_STATUS_CTRL, reg);
1486e5ec1e72Spatrick 
1487e5ec1e72Spatrick 	core = bwfm_chip_get_core(bwfm, BWFM_AGENT_CORE_PCIE2);
1488e5ec1e72Spatrick 	if (core->co_rev <= 13) {
1489e5ec1e72Spatrick 		uint16_t cfg_offset[] = {
1490e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_STATUS_CMD,
1491e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_PM_CSR,
1492e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_MSI_CAP,
1493e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_MSI_ADDR_L,
1494e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_MSI_ADDR_H,
1495e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_MSI_DATA,
1496e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_LINK_STATUS_CTRL2,
1497e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_RBAR_CTRL,
1498e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_PML1_SUB_CTRL1,
1499e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_REG_BAR2_CONFIG,
1500e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_REG_BAR3_CONFIG,
1501e5ec1e72Spatrick 		};
1502e5ec1e72Spatrick 
1503e5ec1e72Spatrick 		for (i = 0; i < nitems(cfg_offset); i++) {
1504e5ec1e72Spatrick 			bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1505e5ec1e72Spatrick 			    BWFM_PCI_PCIE2REG_CONFIGADDR, cfg_offset[i]);
1506e5ec1e72Spatrick 			reg = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1507e5ec1e72Spatrick 			    BWFM_PCI_PCIE2REG_CONFIGDATA);
1508e5ec1e72Spatrick 			DPRINTFN(3, ("%s: config offset 0x%04x, value 0x%04x\n",
1509e5ec1e72Spatrick 			    DEVNAME(sc), cfg_offset[i], reg));
1510e5ec1e72Spatrick 			bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1511e5ec1e72Spatrick 			    BWFM_PCI_PCIE2REG_CONFIGDATA, reg);
1512e5ec1e72Spatrick 		}
1513e5ec1e72Spatrick 	}
1514e5ec1e72Spatrick 
1515e5ec1e72Spatrick 	reg = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1516e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXINT);
1517e5ec1e72Spatrick 	if (reg != 0xffffffff)
1518e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1519e5ec1e72Spatrick 		    BWFM_PCI_PCIE2REG_MAILBOXINT, reg);
1520e5ec1e72Spatrick 
1521e5ec1e72Spatrick 	return 0;
1522e5ec1e72Spatrick }
1523e5ec1e72Spatrick 
1524e5ec1e72Spatrick void
1525e5ec1e72Spatrick bwfm_pci_buscore_activate(struct bwfm_softc *bwfm, uint32_t rstvec)
1526e5ec1e72Spatrick {
1527e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1528e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 0, rstvec);
1529e5ec1e72Spatrick }
1530e5ec1e72Spatrick 
1531f67437f3Spatrick static int bwfm_pci_prio2fifo[8] = {
1532f67437f3Spatrick 	1, /* best effort */
1533f67437f3Spatrick 	0, /* IPTOS_PREC_IMMEDIATE */
1534f67437f3Spatrick 	0, /* IPTOS_PREC_PRIORITY */
1535f67437f3Spatrick 	1, /* IPTOS_PREC_FLASH */
1536f67437f3Spatrick 	2, /* IPTOS_PREC_FLASHOVERRIDE */
1537f67437f3Spatrick 	2, /* IPTOS_PREC_CRITIC_ECP */
1538f67437f3Spatrick 	3, /* IPTOS_PREC_INTERNETCONTROL */
1539f67437f3Spatrick 	3, /* IPTOS_PREC_NETCONTROL */
1540f67437f3Spatrick };
1541f67437f3Spatrick 
1542f67437f3Spatrick int
1543f67437f3Spatrick bwfm_pci_flowring_lookup(struct bwfm_pci_softc *sc, struct mbuf *m)
1544518be5f3Spatrick {
1545f67437f3Spatrick 	struct ieee80211com *ic = &sc->sc_sc.sc_ic;
1546e6abcda3Smlarkin #ifndef IEEE80211_STA_ONLY
1547f67437f3Spatrick 	uint8_t *da = mtod(m, uint8_t *);
1548e6abcda3Smlarkin #endif
1549f67437f3Spatrick 	int flowid, prio, fifo;
1550f67437f3Spatrick 	int i, found;
1551f67437f3Spatrick 
1552f67437f3Spatrick 	prio = ieee80211_classify(ic, m);
1553f67437f3Spatrick 	fifo = bwfm_pci_prio2fifo[prio];
1554f67437f3Spatrick 
1555f67437f3Spatrick 	switch (ic->ic_opmode)
1556f67437f3Spatrick 	{
1557f67437f3Spatrick 	case IEEE80211_M_STA:
1558f67437f3Spatrick 		flowid = fifo;
1559f67437f3Spatrick 		break;
1560f67437f3Spatrick #ifndef IEEE80211_STA_ONLY
1561f67437f3Spatrick 	case IEEE80211_M_HOSTAP:
15622b7bea7eSpatrick 		if (ETHER_IS_MULTICAST(da))
15632b7bea7eSpatrick 			da = etherbroadcastaddr;
1564f67437f3Spatrick 		flowid = da[5] * 2 + fifo;
1565f67437f3Spatrick 		break;
1566f67437f3Spatrick #endif
1567f67437f3Spatrick 	default:
1568f67437f3Spatrick 		printf("%s: state not supported\n", DEVNAME(sc));
1569f67437f3Spatrick 		return ENOBUFS;
1570f67437f3Spatrick 	}
1571f67437f3Spatrick 
1572f67437f3Spatrick 	found = 0;
1573f67437f3Spatrick 	flowid = flowid % sc->sc_max_flowrings;
1574f67437f3Spatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
1575f67437f3Spatrick 		if (ic->ic_opmode == IEEE80211_M_STA &&
1576f67437f3Spatrick 		    sc->sc_flowrings[flowid].status >= RING_OPEN &&
1577f67437f3Spatrick 		    sc->sc_flowrings[flowid].fifo == fifo) {
1578f67437f3Spatrick 			found = 1;
1579f67437f3Spatrick 			break;
1580f67437f3Spatrick 		}
1581f67437f3Spatrick #ifndef IEEE80211_STA_ONLY
1582f67437f3Spatrick 		if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
1583f67437f3Spatrick 		    sc->sc_flowrings[flowid].status >= RING_OPEN &&
1584f67437f3Spatrick 		    sc->sc_flowrings[flowid].fifo == fifo &&
1585a2c6ff8bSpatrick 		    !memcmp(sc->sc_flowrings[flowid].mac, da, ETHER_ADDR_LEN)) {
1586f67437f3Spatrick 			found = 1;
1587f67437f3Spatrick 			break;
1588f67437f3Spatrick 		}
1589f67437f3Spatrick #endif
1590f67437f3Spatrick 		flowid = (flowid + 1) % sc->sc_max_flowrings;
1591f67437f3Spatrick 	}
1592f67437f3Spatrick 
1593f67437f3Spatrick 	if (found)
1594f67437f3Spatrick 		return flowid;
1595f67437f3Spatrick 
1596f67437f3Spatrick 	return -1;
1597f67437f3Spatrick }
1598f67437f3Spatrick 
1599f67437f3Spatrick void
1600f67437f3Spatrick bwfm_pci_flowring_create(struct bwfm_pci_softc *sc, struct mbuf *m)
1601f67437f3Spatrick {
1602f67437f3Spatrick 	struct ieee80211com *ic = &sc->sc_sc.sc_ic;
1603518be5f3Spatrick 	struct bwfm_cmd_flowring_create cmd;
1604e6abcda3Smlarkin #ifndef IEEE80211_STA_ONLY
1605f67437f3Spatrick 	uint8_t *da = mtod(m, uint8_t *);
1606e6abcda3Smlarkin #endif
160702ee7d07Spatrick 	struct bwfm_pci_msgring *ring;
1608f67437f3Spatrick 	int flowid, prio, fifo;
1609f67437f3Spatrick 	int i, found;
1610f67437f3Spatrick 
1611f67437f3Spatrick 	prio = ieee80211_classify(ic, m);
1612f67437f3Spatrick 	fifo = bwfm_pci_prio2fifo[prio];
1613f67437f3Spatrick 
1614f67437f3Spatrick 	switch (ic->ic_opmode)
1615f67437f3Spatrick 	{
1616f67437f3Spatrick 	case IEEE80211_M_STA:
1617f67437f3Spatrick 		flowid = fifo;
1618f67437f3Spatrick 		break;
1619f67437f3Spatrick #ifndef IEEE80211_STA_ONLY
1620f67437f3Spatrick 	case IEEE80211_M_HOSTAP:
16212b7bea7eSpatrick 		if (ETHER_IS_MULTICAST(da))
16222b7bea7eSpatrick 			da = etherbroadcastaddr;
1623f67437f3Spatrick 		flowid = da[5] * 2 + fifo;
1624f67437f3Spatrick 		break;
1625f67437f3Spatrick #endif
1626f67437f3Spatrick 	default:
1627f67437f3Spatrick 		printf("%s: state not supported\n", DEVNAME(sc));
1628f67437f3Spatrick 		return;
1629f67437f3Spatrick 	}
1630f67437f3Spatrick 
1631f67437f3Spatrick 	found = 0;
1632f67437f3Spatrick 	flowid = flowid % sc->sc_max_flowrings;
1633f67437f3Spatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
163402ee7d07Spatrick 		ring = &sc->sc_flowrings[flowid];
163502ee7d07Spatrick 		if (ring->status == RING_CLOSED) {
163602ee7d07Spatrick 			ring->status = RING_OPENING;
1637f67437f3Spatrick 			found = 1;
1638f67437f3Spatrick 			break;
1639f67437f3Spatrick 		}
1640f67437f3Spatrick 		flowid = (flowid + 1) % sc->sc_max_flowrings;
1641f67437f3Spatrick 	}
1642f67437f3Spatrick 
164302ee7d07Spatrick 	/*
164402ee7d07Spatrick 	 * We cannot recover from that so far.  Only a stop/init
164502ee7d07Spatrick 	 * cycle can revive this if it ever happens at all.
164602ee7d07Spatrick 	 */
1647f67437f3Spatrick 	if (!found) {
1648f67437f3Spatrick 		printf("%s: no flowring available\n", DEVNAME(sc));
1649f67437f3Spatrick 		return;
1650f67437f3Spatrick 	}
1651f67437f3Spatrick 
165202ee7d07Spatrick 	cmd.m = m;
1653f67437f3Spatrick 	cmd.prio = prio;
1654518be5f3Spatrick 	cmd.flowid = flowid;
1655518be5f3Spatrick 	bwfm_do_async(&sc->sc_sc, bwfm_pci_flowring_create_cb, &cmd, sizeof(cmd));
1656518be5f3Spatrick }
1657518be5f3Spatrick 
1658518be5f3Spatrick void
1659518be5f3Spatrick bwfm_pci_flowring_create_cb(struct bwfm_softc *bwfm, void *arg)
1660518be5f3Spatrick {
1661518be5f3Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1662e6abcda3Smlarkin #ifndef IEEE80211_STA_ONLY
16632b7bea7eSpatrick 	struct ieee80211com *ic = &sc->sc_sc.sc_ic;
1664e6abcda3Smlarkin #endif
1665518be5f3Spatrick 	struct bwfm_cmd_flowring_create *cmd = arg;
1666518be5f3Spatrick 	struct msgbuf_tx_flowring_create_req *req;
1667518be5f3Spatrick 	struct bwfm_pci_msgring *ring;
166802ee7d07Spatrick 	uint8_t *da, *sa;
1669518be5f3Spatrick 
167002ee7d07Spatrick 	da = mtod(cmd->m, char *) + 0 * ETHER_ADDR_LEN;
167102ee7d07Spatrick 	sa = mtod(cmd->m, char *) + 1 * ETHER_ADDR_LEN;
1672518be5f3Spatrick 
167302ee7d07Spatrick 	ring = &sc->sc_flowrings[cmd->flowid];
167402ee7d07Spatrick 	if (ring->status != RING_OPENING) {
167502ee7d07Spatrick 		printf("%s: flowring not opening\n", DEVNAME(sc));
1676518be5f3Spatrick 		return;
1677f67437f3Spatrick 	}
1678f67437f3Spatrick 
1679f67437f3Spatrick 	if (bwfm_pci_setup_flowring(sc, ring, 512, 48)) {
1680f67437f3Spatrick 		printf("%s: cannot setup flowring\n", DEVNAME(sc));
1681f67437f3Spatrick 		return;
1682f67437f3Spatrick 	}
1683518be5f3Spatrick 
1684518be5f3Spatrick 	req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit);
1685f67437f3Spatrick 	if (req == NULL) {
1686f67437f3Spatrick 		printf("%s: cannot reserve for flowring\n", DEVNAME(sc));
1687518be5f3Spatrick 		return;
1688f67437f3Spatrick 	}
1689518be5f3Spatrick 
1690518be5f3Spatrick 	ring->status = RING_OPENING;
169102ee7d07Spatrick 	ring->fifo = bwfm_pci_prio2fifo[cmd->prio];
169202ee7d07Spatrick 	ring->m = cmd->m;
169302ee7d07Spatrick 	memcpy(ring->mac, da, ETHER_ADDR_LEN);
16942b7bea7eSpatrick #ifndef IEEE80211_STA_ONLY
169502ee7d07Spatrick 	if (ic->ic_opmode == IEEE80211_M_HOSTAP && ETHER_IS_MULTICAST(da))
16962b7bea7eSpatrick 		memcpy(ring->mac, etherbroadcastaddr, ETHER_ADDR_LEN);
16972b7bea7eSpatrick #endif
1698f67437f3Spatrick 
1699518be5f3Spatrick 	req->msg.msgtype = MSGBUF_TYPE_FLOW_RING_CREATE;
1700518be5f3Spatrick 	req->msg.ifidx = 0;
1701518be5f3Spatrick 	req->msg.request_id = 0;
170202ee7d07Spatrick 	req->tid = bwfm_pci_prio2fifo[cmd->prio];
170302ee7d07Spatrick 	req->flow_ring_id = letoh16(cmd->flowid + 2);
170402ee7d07Spatrick 	memcpy(req->da, da, ETHER_ADDR_LEN);
170502ee7d07Spatrick 	memcpy(req->sa, sa, ETHER_ADDR_LEN);
1706518be5f3Spatrick 	req->flow_ring_addr.high_addr =
1707518be5f3Spatrick 	    letoh32(BWFM_PCI_DMA_DVA(ring->ring) >> 32);
1708518be5f3Spatrick 	req->flow_ring_addr.low_addr =
1709518be5f3Spatrick 	    letoh32(BWFM_PCI_DMA_DVA(ring->ring) & 0xffffffff);
1710518be5f3Spatrick 	req->max_items = letoh16(512);
1711518be5f3Spatrick 	req->len_item = letoh16(48);
1712518be5f3Spatrick 
1713518be5f3Spatrick 	bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit);
1714518be5f3Spatrick }
1715518be5f3Spatrick 
1716a2c6ff8bSpatrick void
1717a2c6ff8bSpatrick bwfm_pci_flowring_delete(struct bwfm_pci_softc *sc, int flowid)
1718a2c6ff8bSpatrick {
1719a2c6ff8bSpatrick 	struct msgbuf_tx_flowring_delete_req *req;
1720a2c6ff8bSpatrick 	struct bwfm_pci_msgring *ring;
1721a2c6ff8bSpatrick 
1722a2c6ff8bSpatrick 	ring = &sc->sc_flowrings[flowid];
1723a2c6ff8bSpatrick 	if (ring->status != RING_OPEN) {
1724a2c6ff8bSpatrick 		printf("%s: flowring not open\n", DEVNAME(sc));
1725a2c6ff8bSpatrick 		return;
1726a2c6ff8bSpatrick 	}
1727a2c6ff8bSpatrick 
1728a2c6ff8bSpatrick 	req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit);
1729a2c6ff8bSpatrick 	if (req == NULL) {
1730a2c6ff8bSpatrick 		printf("%s: cannot reserve for flowring\n", DEVNAME(sc));
1731a2c6ff8bSpatrick 		return;
1732a2c6ff8bSpatrick 	}
1733a2c6ff8bSpatrick 
1734a2c6ff8bSpatrick 	ring->status = RING_CLOSING;
1735a2c6ff8bSpatrick 
1736a2c6ff8bSpatrick 	req->msg.msgtype = MSGBUF_TYPE_FLOW_RING_DELETE;
1737a2c6ff8bSpatrick 	req->msg.ifidx = 0;
1738a2c6ff8bSpatrick 	req->msg.request_id = 0;
1739a2c6ff8bSpatrick 	req->flow_ring_id = letoh16(flowid + 2);
1740a2c6ff8bSpatrick 	req->reason = 0;
1741a2c6ff8bSpatrick 
1742a2c6ff8bSpatrick 	bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit);
1743a2c6ff8bSpatrick }
1744a2c6ff8bSpatrick 
1745a2c6ff8bSpatrick void
1746a2c6ff8bSpatrick bwfm_pci_stop(struct bwfm_softc *bwfm)
1747a2c6ff8bSpatrick {
1748a2c6ff8bSpatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1749a2c6ff8bSpatrick 	struct bwfm_pci_msgring *ring;
1750a2c6ff8bSpatrick 	int i;
1751a2c6ff8bSpatrick 
1752a2c6ff8bSpatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
1753a2c6ff8bSpatrick 		ring = &sc->sc_flowrings[i];
1754a2c6ff8bSpatrick 		if (ring->status == RING_OPEN)
1755a2c6ff8bSpatrick 			bwfm_pci_flowring_delete(sc, i);
1756a2c6ff8bSpatrick 	}
1757a2c6ff8bSpatrick }
1758a2c6ff8bSpatrick 
1759e5ec1e72Spatrick int
176002ee7d07Spatrick bwfm_pci_txcheck(struct bwfm_softc *bwfm)
176102ee7d07Spatrick {
176202ee7d07Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
176302ee7d07Spatrick 	struct bwfm_pci_msgring *ring;
176402ee7d07Spatrick 	int i;
176502ee7d07Spatrick 
176602ee7d07Spatrick 	/* If we are transitioning, we cannot send. */
176702ee7d07Spatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
176802ee7d07Spatrick 		ring = &sc->sc_flowrings[i];
176902ee7d07Spatrick 		if (ring->status == RING_OPENING)
177002ee7d07Spatrick 			return ENOBUFS;
177102ee7d07Spatrick 	}
177202ee7d07Spatrick 
177302ee7d07Spatrick 	if (bwfm_pci_pktid_avail(sc, &sc->sc_tx_pkts)) {
177402ee7d07Spatrick 		sc->sc_tx_pkts_full = 1;
177502ee7d07Spatrick 		return ENOBUFS;
177602ee7d07Spatrick 	}
177702ee7d07Spatrick 
177802ee7d07Spatrick 	return 0;
177902ee7d07Spatrick }
178002ee7d07Spatrick 
178102ee7d07Spatrick int
1782e5ec1e72Spatrick bwfm_pci_txdata(struct bwfm_softc *bwfm, struct mbuf *m)
1783e5ec1e72Spatrick {
1784e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1785518be5f3Spatrick 	struct bwfm_pci_msgring *ring;
1786518be5f3Spatrick 	struct msgbuf_tx_msghdr *tx;
1787518be5f3Spatrick 	uint32_t pktid;
1788518be5f3Spatrick 	paddr_t paddr;
1789518be5f3Spatrick 	int flowid, ret;
1790518be5f3Spatrick 
1791f67437f3Spatrick 	flowid = bwfm_pci_flowring_lookup(sc, m);
1792f67437f3Spatrick 	if (flowid < 0) {
179302ee7d07Spatrick 		/*
179402ee7d07Spatrick 		 * We cannot send the packet right now as there is
179502ee7d07Spatrick 		 * no flowring yet.  The flowring will be created
179602ee7d07Spatrick 		 * asynchronously.  While the ring is transitioning
179702ee7d07Spatrick 		 * the TX check will tell the upper layers that we
179802ee7d07Spatrick 		 * cannot send packets right now.  When the flowring
179902ee7d07Spatrick 		 * is created the queue will be restarted and this
180002ee7d07Spatrick 		 * mbuf will be transmitted.
180102ee7d07Spatrick 		 */
1802f67437f3Spatrick 		bwfm_pci_flowring_create(sc, m);
180302ee7d07Spatrick 		return 0;
1804f67437f3Spatrick 	}
1805518be5f3Spatrick 
1806518be5f3Spatrick 	ring = &sc->sc_flowrings[flowid];
1807518be5f3Spatrick 	if (ring->status == RING_OPENING ||
1808f67437f3Spatrick 	    ring->status == RING_CLOSING) {
1809f67437f3Spatrick 		printf("%s: tried to use a flow that was "
1810f67437f3Spatrick 		    "transitioning in status %d\n",
1811f67437f3Spatrick 		    DEVNAME(sc), ring->status);
1812518be5f3Spatrick 		return ENOBUFS;
1813518be5f3Spatrick 	}
1814518be5f3Spatrick 
1815518be5f3Spatrick 	tx = bwfm_pci_ring_write_reserve(sc, ring);
1816518be5f3Spatrick 	if (tx == NULL)
1817518be5f3Spatrick 		return ENOBUFS;
1818518be5f3Spatrick 
1819518be5f3Spatrick 	memset(tx, 0, sizeof(*tx));
1820518be5f3Spatrick 	tx->msg.msgtype = MSGBUF_TYPE_TX_POST;
1821518be5f3Spatrick 	tx->msg.ifidx = 0;
1822518be5f3Spatrick 	tx->flags = BWFM_MSGBUF_PKT_FLAGS_FRAME_802_3;
1823518be5f3Spatrick 	tx->flags |= ieee80211_classify(&sc->sc_sc.sc_ic, m) <<
1824518be5f3Spatrick 	    BWFM_MSGBUF_PKT_FLAGS_PRIO_SHIFT;
1825518be5f3Spatrick 	tx->seg_cnt = 1;
1826518be5f3Spatrick 	memcpy(tx->txhdr, mtod(m, char *), ETHER_HDR_LEN);
1827518be5f3Spatrick 
1828518be5f3Spatrick 	ret = bwfm_pci_pktid_new(sc, &sc->sc_tx_pkts, m, &pktid, &paddr);
1829518be5f3Spatrick 	if (ret) {
183002ee7d07Spatrick 		if (ret == ENOBUFS) {
183102ee7d07Spatrick 			printf("%s: no pktid available for TX\n",
183202ee7d07Spatrick 			    DEVNAME(sc));
1833c6f1636dSpatrick 			sc->sc_tx_pkts_full = 1;
183402ee7d07Spatrick 		}
1835518be5f3Spatrick 		bwfm_pci_ring_write_cancel(sc, ring, 1);
1836518be5f3Spatrick 		return ret;
1837518be5f3Spatrick 	}
1838518be5f3Spatrick 	paddr += ETHER_HDR_LEN;
1839518be5f3Spatrick 
1840518be5f3Spatrick 	tx->msg.request_id = htole32(pktid);
18414ff787bcSpatrick 	tx->data_len = htole16(m->m_len - ETHER_HDR_LEN);
1842e4dae658Spatrick 	tx->data_buf_addr.high_addr = htole32((uint64_t)paddr >> 32);
1843518be5f3Spatrick 	tx->data_buf_addr.low_addr = htole32(paddr & 0xffffffff);
1844518be5f3Spatrick 
1845518be5f3Spatrick 	bwfm_pci_ring_write_commit(sc, ring);
1846518be5f3Spatrick 	return 0;
1847e5ec1e72Spatrick }
1848e5ec1e72Spatrick 
1849bbd71b0bSpatrick #ifdef BWFM_DEBUG
1850cadf5fcfSpatrick void
1851cadf5fcfSpatrick bwfm_pci_debug_console(struct bwfm_pci_softc *sc)
1852cadf5fcfSpatrick {
1853cadf5fcfSpatrick 	uint32_t newidx = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1854cadf5fcfSpatrick 	    sc->sc_console_base_addr + BWFM_CONSOLE_WRITEIDX);
1855cadf5fcfSpatrick 
1856cadf5fcfSpatrick 	if (newidx != sc->sc_console_readidx)
1857bbd71b0bSpatrick 		DPRINTFN(3, ("BWFM CONSOLE: "));
1858cadf5fcfSpatrick 	while (newidx != sc->sc_console_readidx) {
1859cadf5fcfSpatrick 		uint8_t ch = bus_space_read_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1860cadf5fcfSpatrick 		    sc->sc_console_buf_addr + sc->sc_console_readidx);
1861cadf5fcfSpatrick 		sc->sc_console_readidx++;
1862cadf5fcfSpatrick 		if (sc->sc_console_readidx == sc->sc_console_buf_size)
1863cadf5fcfSpatrick 			sc->sc_console_readidx = 0;
1864cadf5fcfSpatrick 		if (ch == '\r')
1865cadf5fcfSpatrick 			continue;
1866bbd71b0bSpatrick 		DPRINTFN(3, ("%c", ch));
1867cadf5fcfSpatrick 	}
1868cadf5fcfSpatrick }
1869bbd71b0bSpatrick #endif
1870cadf5fcfSpatrick 
1871e5ec1e72Spatrick int
1872e5ec1e72Spatrick bwfm_pci_intr(void *v)
1873e5ec1e72Spatrick {
1874e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)v;
1875e5ec1e72Spatrick 	uint32_t status;
1876e5ec1e72Spatrick 
1877e5ec1e72Spatrick 	if ((status = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1878e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXINT)) == 0)
1879e5ec1e72Spatrick 		return 0;
1880e5ec1e72Spatrick 
1881e5ec1e72Spatrick 	bwfm_pci_intr_disable(sc);
1882e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1883e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXINT, status);
1884e5ec1e72Spatrick 
1885e5ec1e72Spatrick 	if (status & (BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_0 |
1886e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_1))
1887e5ec1e72Spatrick 		printf("%s: handle MB data\n", __func__);
1888e5ec1e72Spatrick 
1889e5ec1e72Spatrick 	if (status & BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_D2H_DB) {
1890518be5f3Spatrick 		bwfm_pci_ring_rx(sc, &sc->sc_rx_complete);
18912b7bea7eSpatrick 		bwfm_pci_ring_rx(sc, &sc->sc_tx_complete);
18922b7bea7eSpatrick 		bwfm_pci_ring_rx(sc, &sc->sc_ctrl_complete);
1893e5ec1e72Spatrick 	}
1894e5ec1e72Spatrick 
1895cadf5fcfSpatrick #ifdef BWFM_DEBUG
1896cadf5fcfSpatrick 	bwfm_pci_debug_console(sc);
1897e5ec1e72Spatrick #endif
1898e5ec1e72Spatrick 
1899e5ec1e72Spatrick 	bwfm_pci_intr_enable(sc);
1900e5ec1e72Spatrick 	return 1;
1901e5ec1e72Spatrick }
1902e5ec1e72Spatrick 
1903e5ec1e72Spatrick void
1904e5ec1e72Spatrick bwfm_pci_intr_enable(struct bwfm_pci_softc *sc)
1905e5ec1e72Spatrick {
1906e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1907e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXMASK,
1908e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_0 |
1909e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_1 |
1910e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_D2H_DB);
1911e5ec1e72Spatrick }
1912e5ec1e72Spatrick 
1913e5ec1e72Spatrick void
1914e5ec1e72Spatrick bwfm_pci_intr_disable(struct bwfm_pci_softc *sc)
1915e5ec1e72Spatrick {
1916e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1917e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXMASK, 0);
1918e5ec1e72Spatrick }
1919e5ec1e72Spatrick 
1920e5ec1e72Spatrick /* Msgbuf protocol implementation */
1921e5ec1e72Spatrick int
1922e5ec1e72Spatrick bwfm_pci_msgbuf_query_dcmd(struct bwfm_softc *bwfm, int ifidx,
1923e5ec1e72Spatrick     int cmd, char *buf, size_t *len)
1924e5ec1e72Spatrick {
1925e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1926e5ec1e72Spatrick 	struct msgbuf_ioctl_req_hdr *req;
19272eeba925Spatrick 	struct bwfm_pci_ioctl *ctl;
1928e5ec1e72Spatrick 	struct mbuf *m;
19292eeba925Spatrick 	uint32_t pktid;
19302eeba925Spatrick 	paddr_t paddr;
1931e5ec1e72Spatrick 	size_t buflen;
1932e5ec1e72Spatrick 
19332eeba925Spatrick 	buflen = min(*len, BWFM_DMA_H2D_IOCTL_BUF_LEN);
19342eeba925Spatrick 	m = MCLGETI(NULL, M_DONTWAIT, NULL, buflen);
19352eeba925Spatrick 	if (m == NULL)
19362eeba925Spatrick 		return 1;
19372eeba925Spatrick 	m->m_len = m->m_pkthdr.len = buflen;
19382eeba925Spatrick 
19392eeba925Spatrick 	if (buf)
19402eeba925Spatrick 		memcpy(mtod(m, char *), buf, buflen);
19412eeba925Spatrick 	else
19422eeba925Spatrick 		memset(mtod(m, char *), 0, buflen);
19432eeba925Spatrick 
1944e5ec1e72Spatrick 	req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit);
1945e5ec1e72Spatrick 	if (req == NULL) {
19462eeba925Spatrick 		m_freem(m);
1947e5ec1e72Spatrick 		return 1;
1948e5ec1e72Spatrick 	}
19492eeba925Spatrick 
19502eeba925Spatrick 	if (bwfm_pci_pktid_new(sc, &sc->sc_ioctl_pkts, m, &pktid, &paddr)) {
19512eeba925Spatrick 		bwfm_pci_ring_write_cancel(sc, &sc->sc_ctrl_submit, 1);
19522eeba925Spatrick 		m_freem(m);
19532eeba925Spatrick 		return 1;
19542eeba925Spatrick 	}
19552eeba925Spatrick 
19562eeba925Spatrick 	ctl = malloc(sizeof(*ctl), M_TEMP, M_WAITOK|M_ZERO);
19572eeba925Spatrick 	ctl->transid = sc->sc_ioctl_transid++;
19582eeba925Spatrick 	TAILQ_INSERT_TAIL(&sc->sc_ioctlq, ctl, next);
19592eeba925Spatrick 
1960e5ec1e72Spatrick 	req->msg.msgtype = MSGBUF_TYPE_IOCTLPTR_REQ;
1961e5ec1e72Spatrick 	req->msg.ifidx = 0;
1962e5ec1e72Spatrick 	req->msg.flags = 0;
19632eeba925Spatrick 	req->msg.request_id = htole32(pktid);
1964e5ec1e72Spatrick 	req->cmd = htole32(cmd);
1965e5ec1e72Spatrick 	req->output_buf_len = htole16(*len);
19662eeba925Spatrick 	req->trans_id = htole16(ctl->transid);
1967e5ec1e72Spatrick 
19682eeba925Spatrick 	req->input_buf_len = htole16(m->m_len);
19692eeba925Spatrick 	req->req_buf_addr.high_addr = htole32((uint64_t)paddr >> 32);
19702eeba925Spatrick 	req->req_buf_addr.low_addr = htole32(paddr & 0xffffffff);
1971dcb67343Spatrick 
1972e5ec1e72Spatrick 	bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit);
1973e5ec1e72Spatrick 
19742eeba925Spatrick 	tsleep(ctl, PWAIT, "bwfm", hz);
19752eeba925Spatrick 	TAILQ_REMOVE(&sc->sc_ioctlq, ctl, next);
19762eeba925Spatrick 
19772eeba925Spatrick 	if (ctl->m == NULL) {
19782eeba925Spatrick 		free(ctl, M_TEMP, sizeof(*ctl));
1979e5ec1e72Spatrick 		return 1;
1980e5ec1e72Spatrick 	}
1981e5ec1e72Spatrick 
19822eeba925Spatrick 	*len = min(ctl->retlen, m->m_len);
19832eeba925Spatrick 	*len = min(*len, buflen);
1984e5ec1e72Spatrick 	if (buf)
19852eeba925Spatrick 		m_copydata(ctl->m, 0, *len, (caddr_t)buf);
19862eeba925Spatrick 	m_freem(ctl->m);
1987e5ec1e72Spatrick 
19882eeba925Spatrick 	if (ctl->status < 0) {
19892eeba925Spatrick 		free(ctl, M_TEMP, sizeof(*ctl));
19902eeba925Spatrick 		return 1;
19912eeba925Spatrick 	}
19922eeba925Spatrick 
19932eeba925Spatrick 	free(ctl, M_TEMP, sizeof(*ctl));
1994e5ec1e72Spatrick 	return 0;
1995e5ec1e72Spatrick }
1996e5ec1e72Spatrick 
1997e5ec1e72Spatrick int
1998e5ec1e72Spatrick bwfm_pci_msgbuf_set_dcmd(struct bwfm_softc *bwfm, int ifidx,
1999e5ec1e72Spatrick     int cmd, char *buf, size_t len)
2000e5ec1e72Spatrick {
2001e5ec1e72Spatrick 	return bwfm_pci_msgbuf_query_dcmd(bwfm, ifidx, cmd, buf, &len);
2002e5ec1e72Spatrick }
20032eeba925Spatrick 
20042eeba925Spatrick void
20052eeba925Spatrick bwfm_pci_msgbuf_rxioctl(struct bwfm_pci_softc *sc,
20062eeba925Spatrick     struct msgbuf_ioctl_resp_hdr *resp)
20072eeba925Spatrick {
20082eeba925Spatrick 	struct bwfm_pci_ioctl *ctl, *tmp;
20092eeba925Spatrick 	struct mbuf *m;
20102eeba925Spatrick 
20112eeba925Spatrick 	m = bwfm_pci_pktid_free(sc, &sc->sc_rx_pkts,
20122eeba925Spatrick 	    letoh32(resp->msg.request_id));
20132eeba925Spatrick 
20142eeba925Spatrick 	TAILQ_FOREACH_SAFE(ctl, &sc->sc_ioctlq, next, tmp) {
20152eeba925Spatrick 		if (ctl->transid != letoh16(resp->trans_id))
20162eeba925Spatrick 			continue;
20172eeba925Spatrick 		ctl->m = m;
20182eeba925Spatrick 		ctl->retlen = letoh16(resp->resp_len);
20192eeba925Spatrick 		ctl->status = letoh16(resp->compl_hdr.status);
20202eeba925Spatrick 		wakeup(ctl);
20212eeba925Spatrick 		return;
20222eeba925Spatrick 	}
20232eeba925Spatrick 
2024*cb2afc74Spatrick 	m_freem(m);
20252eeba925Spatrick }
2026