xref: /openbsd/sys/dev/pci/if_bwfm_pci.c (revision 2b7bea7e)
1*2b7bea7eSpatrick /*	$OpenBSD: if_bwfm_pci.c,v 1.11 2018/01/08 17:57:48 patrick Exp $	*/
2e5ec1e72Spatrick /*
3e5ec1e72Spatrick  * Copyright (c) 2010-2016 Broadcom Corporation
4e5ec1e72Spatrick  * Copyright (c) 2017 Patrick Wildt <patrick@blueri.se>
5e5ec1e72Spatrick  *
6e5ec1e72Spatrick  * Permission to use, copy, modify, and/or distribute this software for any
7e5ec1e72Spatrick  * purpose with or without fee is hereby granted, provided that the above
8e5ec1e72Spatrick  * copyright notice and this permission notice appear in all copies.
9e5ec1e72Spatrick  *
10e5ec1e72Spatrick  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11e5ec1e72Spatrick  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12e5ec1e72Spatrick  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13e5ec1e72Spatrick  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14e5ec1e72Spatrick  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15e5ec1e72Spatrick  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16e5ec1e72Spatrick  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17e5ec1e72Spatrick  */
18e5ec1e72Spatrick 
19e5ec1e72Spatrick #include "bpfilter.h"
20e5ec1e72Spatrick 
21e5ec1e72Spatrick #include <sys/param.h>
22e5ec1e72Spatrick #include <sys/systm.h>
23e5ec1e72Spatrick #include <sys/buf.h>
24e5ec1e72Spatrick #include <sys/kernel.h>
25e5ec1e72Spatrick #include <sys/malloc.h>
26e5ec1e72Spatrick #include <sys/device.h>
27e5ec1e72Spatrick #include <sys/queue.h>
28e5ec1e72Spatrick #include <sys/socket.h>
29e5ec1e72Spatrick 
30e5ec1e72Spatrick #if NBPFILTER > 0
31e5ec1e72Spatrick #include <net/bpf.h>
32e5ec1e72Spatrick #endif
33e5ec1e72Spatrick #include <net/if.h>
34e5ec1e72Spatrick #include <net/if_dl.h>
35e5ec1e72Spatrick #include <net/if_media.h>
36e5ec1e72Spatrick 
37e5ec1e72Spatrick #include <netinet/in.h>
38e5ec1e72Spatrick #include <netinet/if_ether.h>
39e5ec1e72Spatrick 
40e5ec1e72Spatrick #include <net80211/ieee80211_var.h>
41e5ec1e72Spatrick 
42e5ec1e72Spatrick #include <machine/bus.h>
43e5ec1e72Spatrick 
44e5ec1e72Spatrick #include <dev/pci/pcireg.h>
45e5ec1e72Spatrick #include <dev/pci/pcivar.h>
46e5ec1e72Spatrick #include <dev/pci/pcidevs.h>
47e5ec1e72Spatrick 
48e5ec1e72Spatrick #include <dev/ic/bwfmvar.h>
49e5ec1e72Spatrick #include <dev/ic/bwfmreg.h>
50e5ec1e72Spatrick #include <dev/pci/if_bwfm_pci.h>
51e5ec1e72Spatrick 
52e5ec1e72Spatrick #define BWFM_DMA_D2H_SCRATCH_BUF_LEN		8
53e5ec1e72Spatrick #define BWFM_DMA_D2H_RINGUPD_BUF_LEN		1024
54e5ec1e72Spatrick #define BWFM_DMA_H2D_IOCTL_BUF_LEN		ETHER_MAX_LEN
55e5ec1e72Spatrick 
56e5ec1e72Spatrick #define BWFM_NUM_TX_MSGRINGS			2
57e5ec1e72Spatrick #define BWFM_NUM_RX_MSGRINGS			3
58e5ec1e72Spatrick 
59e5ec1e72Spatrick #define BWFM_NUM_TX_PKTIDS			2048
60e5ec1e72Spatrick #define BWFM_NUM_RX_PKTIDS			1024
61e5ec1e72Spatrick 
62e5ec1e72Spatrick #define BWFM_NUM_TX_DESCS			1
63e5ec1e72Spatrick #define BWFM_NUM_RX_DESCS			1
64e5ec1e72Spatrick 
65e5ec1e72Spatrick #ifdef BWFM_DEBUG
66e5ec1e72Spatrick #define DPRINTF(x)	do { if (bwfm_debug > 0) printf x; } while (0)
67e5ec1e72Spatrick #define DPRINTFN(n, x)	do { if (bwfm_debug >= (n)) printf x; } while (0)
68e5ec1e72Spatrick static int bwfm_debug = 2;
69e5ec1e72Spatrick #else
70e5ec1e72Spatrick #define DPRINTF(x)	do { ; } while (0)
71e5ec1e72Spatrick #define DPRINTFN(n, x)	do { ; } while (0)
72e5ec1e72Spatrick #endif
73e5ec1e72Spatrick 
74e5ec1e72Spatrick #define DEVNAME(sc)	((sc)->sc_sc.sc_dev.dv_xname)
75e5ec1e72Spatrick 
76518be5f3Spatrick enum ring_status {
77518be5f3Spatrick 	RING_CLOSED,
78518be5f3Spatrick 	RING_CLOSING,
79518be5f3Spatrick 	RING_OPEN,
80518be5f3Spatrick 	RING_OPENING,
81518be5f3Spatrick };
82518be5f3Spatrick 
83e5ec1e72Spatrick struct bwfm_pci_msgring {
84e5ec1e72Spatrick 	uint32_t		 w_idx_addr;
85e5ec1e72Spatrick 	uint32_t		 r_idx_addr;
86e5ec1e72Spatrick 	uint32_t		 w_ptr;
87e5ec1e72Spatrick 	uint32_t		 r_ptr;
88e5ec1e72Spatrick 	int			 nitem;
89e5ec1e72Spatrick 	int			 itemsz;
90518be5f3Spatrick 	enum ring_status	 status;
91e5ec1e72Spatrick 	struct bwfm_pci_dmamem	*ring;
92f67437f3Spatrick 
93f67437f3Spatrick 	int			 fifo;
94f67437f3Spatrick 	uint8_t			 mac[ETHER_ADDR_LEN];
95e5ec1e72Spatrick };
96e5ec1e72Spatrick 
97e5ec1e72Spatrick struct bwfm_pci_buf {
98e5ec1e72Spatrick 	bus_dmamap_t	 bb_map;
99e5ec1e72Spatrick 	struct mbuf	*bb_m;
100e5ec1e72Spatrick };
101e5ec1e72Spatrick 
102e5ec1e72Spatrick struct bwfm_pci_pkts {
103e5ec1e72Spatrick 	struct bwfm_pci_buf	*pkts;
104e5ec1e72Spatrick 	uint32_t		 npkt;
105e5ec1e72Spatrick 	int			 last;
106e5ec1e72Spatrick };
107e5ec1e72Spatrick 
108e5ec1e72Spatrick struct bwfm_pci_softc {
109e5ec1e72Spatrick 	struct bwfm_softc	 sc_sc;
110e5ec1e72Spatrick 	pci_chipset_tag_t	 sc_pc;
111e5ec1e72Spatrick 	pcitag_t		 sc_tag;
112e5ec1e72Spatrick 	pcireg_t		 sc_id;
113e5ec1e72Spatrick 	void 			*sc_ih;
114e5ec1e72Spatrick 
115e5ec1e72Spatrick 	bus_space_tag_t		 sc_reg_iot;
116e5ec1e72Spatrick 	bus_space_handle_t	 sc_reg_ioh;
117e5ec1e72Spatrick 	bus_size_t		 sc_reg_ios;
118e5ec1e72Spatrick 
119e5ec1e72Spatrick 	bus_space_tag_t		 sc_tcm_iot;
120e5ec1e72Spatrick 	bus_space_handle_t	 sc_tcm_ioh;
121e5ec1e72Spatrick 	bus_size_t		 sc_tcm_ios;
122e5ec1e72Spatrick 
123e5ec1e72Spatrick 	bus_dma_tag_t		 sc_dmat;
124e5ec1e72Spatrick 
125e5ec1e72Spatrick 	uint32_t		 sc_shared_address;
126e5ec1e72Spatrick 	uint32_t		 sc_shared_flags;
127e5ec1e72Spatrick 	uint8_t			 sc_shared_version;
128e5ec1e72Spatrick 
129e5ec1e72Spatrick 	uint8_t			 sc_dma_idx_sz;
130e5ec1e72Spatrick 	struct bwfm_pci_dmamem	*sc_dma_idx_buf;
131e5ec1e72Spatrick 	size_t			 sc_dma_idx_bufsz;
132e5ec1e72Spatrick 
133e5ec1e72Spatrick 	uint16_t		 sc_max_rxbufpost;
134e5ec1e72Spatrick 	uint32_t		 sc_rx_dataoffset;
135e5ec1e72Spatrick 	uint32_t		 sc_htod_mb_data_addr;
136e5ec1e72Spatrick 	uint32_t		 sc_dtoh_mb_data_addr;
137e5ec1e72Spatrick 	uint32_t		 sc_ring_info_addr;
138e5ec1e72Spatrick 
139e5ec1e72Spatrick 	uint32_t		 sc_console_base_addr;
140e5ec1e72Spatrick 	uint32_t		 sc_console_buf_addr;
141e5ec1e72Spatrick 	uint32_t		 sc_console_buf_size;
142cadf5fcfSpatrick 	uint32_t		 sc_console_readidx;
143e5ec1e72Spatrick 
144e5ec1e72Spatrick 	uint16_t		 sc_max_flowrings;
145e5ec1e72Spatrick 	uint16_t		 sc_max_submissionrings;
146e5ec1e72Spatrick 	uint16_t		 sc_max_completionrings;
147e5ec1e72Spatrick 
148e5ec1e72Spatrick 	struct bwfm_pci_msgring	 sc_ctrl_submit;
149e5ec1e72Spatrick 	struct bwfm_pci_msgring	 sc_rxpost_submit;
150e5ec1e72Spatrick 	struct bwfm_pci_msgring	 sc_ctrl_complete;
151e5ec1e72Spatrick 	struct bwfm_pci_msgring	 sc_tx_complete;
152e5ec1e72Spatrick 	struct bwfm_pci_msgring	 sc_rx_complete;
153e5ec1e72Spatrick 	struct bwfm_pci_msgring	*sc_flowrings;
154e5ec1e72Spatrick 
155e5ec1e72Spatrick 	struct bwfm_pci_dmamem	*sc_scratch_buf;
156e5ec1e72Spatrick 	struct bwfm_pci_dmamem	*sc_ringupd_buf;
157e5ec1e72Spatrick 
158e5ec1e72Spatrick 	struct bwfm_pci_dmamem	*sc_ioctl_buf;
159e5ec1e72Spatrick 	int			 sc_ioctl_reqid;
160e5ec1e72Spatrick 	uint32_t		 sc_ioctl_resp_pktid;
161e5ec1e72Spatrick 	uint32_t		 sc_ioctl_resp_ret_len;
162e5ec1e72Spatrick 	uint32_t		 sc_ioctl_resp_status;
163e5ec1e72Spatrick 	int			 sc_ioctl_poll;
164e5ec1e72Spatrick 
165e5ec1e72Spatrick 	struct if_rxring	 sc_ioctl_ring;
166e5ec1e72Spatrick 	struct if_rxring	 sc_event_ring;
167e5ec1e72Spatrick 	struct if_rxring	 sc_rxbuf_ring;
168e5ec1e72Spatrick 
169e5ec1e72Spatrick 	struct bwfm_pci_pkts	 sc_tx_pkts;
170e5ec1e72Spatrick 	struct bwfm_pci_pkts	 sc_rx_pkts;
171e5ec1e72Spatrick };
172e5ec1e72Spatrick 
173e5ec1e72Spatrick struct bwfm_pci_dmamem {
174e5ec1e72Spatrick 	bus_dmamap_t		bdm_map;
175e5ec1e72Spatrick 	bus_dma_segment_t	bdm_seg;
176e5ec1e72Spatrick 	size_t			bdm_size;
177e5ec1e72Spatrick 	caddr_t			bdm_kva;
178e5ec1e72Spatrick };
179e5ec1e72Spatrick 
180e5ec1e72Spatrick #define BWFM_PCI_DMA_MAP(_bdm)	((_bdm)->bdm_map)
181e5ec1e72Spatrick #define BWFM_PCI_DMA_LEN(_bdm)	((_bdm)->bdm_size)
182e5ec1e72Spatrick #define BWFM_PCI_DMA_DVA(_bdm)	((_bdm)->bdm_map->dm_segs[0].ds_addr)
183e5ec1e72Spatrick #define BWFM_PCI_DMA_KVA(_bdm)	((void *)(_bdm)->bdm_kva)
184e5ec1e72Spatrick 
185e5ec1e72Spatrick int		 bwfm_pci_match(struct device *, void *, void *);
186e5ec1e72Spatrick void		 bwfm_pci_attachhook(struct device *);
187e5ec1e72Spatrick void		 bwfm_pci_attach(struct device *, struct device *, void *);
188e5ec1e72Spatrick int		 bwfm_pci_detach(struct device *, int);
189e5ec1e72Spatrick 
190e5ec1e72Spatrick int		 bwfm_pci_intr(void *);
191e5ec1e72Spatrick void		 bwfm_pci_intr_enable(struct bwfm_pci_softc *);
192e5ec1e72Spatrick void		 bwfm_pci_intr_disable(struct bwfm_pci_softc *);
193e5ec1e72Spatrick int		 bwfm_pci_load_microcode(struct bwfm_pci_softc *, const u_char *,
194e5ec1e72Spatrick 		    size_t);
195e5ec1e72Spatrick void		 bwfm_pci_select_core(struct bwfm_pci_softc *, int );
196e5ec1e72Spatrick 
197e5ec1e72Spatrick struct bwfm_pci_dmamem *
198e5ec1e72Spatrick 		 bwfm_pci_dmamem_alloc(struct bwfm_pci_softc *, bus_size_t,
199e5ec1e72Spatrick 		    bus_size_t);
200e5ec1e72Spatrick void		 bwfm_pci_dmamem_free(struct bwfm_pci_softc *, struct bwfm_pci_dmamem *);
201e5ec1e72Spatrick int		 bwfm_pci_pktid_new(struct bwfm_pci_softc *,
202e5ec1e72Spatrick 		    struct bwfm_pci_pkts *, struct mbuf *,
203e5ec1e72Spatrick 		    uint32_t *, paddr_t *);
204e5ec1e72Spatrick struct mbuf *	 bwfm_pci_pktid_free(struct bwfm_pci_softc *,
205e5ec1e72Spatrick 		    struct bwfm_pci_pkts *, uint32_t);
206e5ec1e72Spatrick void		 bwfm_pci_fill_rx_ioctl_ring(struct bwfm_pci_softc *,
207e5ec1e72Spatrick 		    struct if_rxring *, uint32_t);
208e5ec1e72Spatrick void		 bwfm_pci_fill_rx_buf_ring(struct bwfm_pci_softc *);
209e5ec1e72Spatrick void		 bwfm_pci_fill_rx_rings(struct bwfm_pci_softc *);
210e5ec1e72Spatrick int		 bwfm_pci_setup_ring(struct bwfm_pci_softc *, struct bwfm_pci_msgring *,
211e5ec1e72Spatrick 		    int, size_t, uint32_t, uint32_t, int, uint32_t, uint32_t *);
212518be5f3Spatrick int		 bwfm_pci_setup_flowring(struct bwfm_pci_softc *, struct bwfm_pci_msgring *,
213518be5f3Spatrick 		    int, size_t);
214e5ec1e72Spatrick 
215e5ec1e72Spatrick void		 bwfm_pci_ring_bell(struct bwfm_pci_softc *,
216e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
217e5ec1e72Spatrick void		 bwfm_pci_ring_update_rptr(struct bwfm_pci_softc *,
218e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
219e5ec1e72Spatrick void		 bwfm_pci_ring_update_wptr(struct bwfm_pci_softc *,
220e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
221e5ec1e72Spatrick void		 bwfm_pci_ring_write_rptr(struct bwfm_pci_softc *,
222e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
223e5ec1e72Spatrick void		 bwfm_pci_ring_write_wptr(struct bwfm_pci_softc *,
224e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
225e5ec1e72Spatrick void *		 bwfm_pci_ring_write_reserve(struct bwfm_pci_softc *,
226e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
227e5ec1e72Spatrick void *		 bwfm_pci_ring_write_reserve_multi(struct bwfm_pci_softc *,
228e5ec1e72Spatrick 		    struct bwfm_pci_msgring *, int, int *);
229e5ec1e72Spatrick void *		 bwfm_pci_ring_read_avail(struct bwfm_pci_softc *,
230e5ec1e72Spatrick 		    struct bwfm_pci_msgring *, int *);
231e5ec1e72Spatrick void		 bwfm_pci_ring_read_commit(struct bwfm_pci_softc *,
232e5ec1e72Spatrick 		    struct bwfm_pci_msgring *, int);
233e5ec1e72Spatrick void		 bwfm_pci_ring_write_commit(struct bwfm_pci_softc *,
234e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
235e5ec1e72Spatrick void		 bwfm_pci_ring_write_cancel(struct bwfm_pci_softc *,
236e5ec1e72Spatrick 		    struct bwfm_pci_msgring *, int);
237e5ec1e72Spatrick 
238e5ec1e72Spatrick void		 bwfm_pci_ring_rx(struct bwfm_pci_softc *,
239e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
240e5ec1e72Spatrick void		 bwfm_pci_msg_rx(struct bwfm_pci_softc *, void *);
241e5ec1e72Spatrick 
242e5ec1e72Spatrick uint32_t	 bwfm_pci_buscore_read(struct bwfm_softc *, uint32_t);
243e5ec1e72Spatrick void		 bwfm_pci_buscore_write(struct bwfm_softc *, uint32_t,
244e5ec1e72Spatrick 		    uint32_t);
245e5ec1e72Spatrick int		 bwfm_pci_buscore_prepare(struct bwfm_softc *);
246e5ec1e72Spatrick int		 bwfm_pci_buscore_reset(struct bwfm_softc *);
247e5ec1e72Spatrick void		 bwfm_pci_buscore_activate(struct bwfm_softc *, uint32_t);
248e5ec1e72Spatrick 
249f67437f3Spatrick int		 bwfm_pci_flowring_lookup(struct bwfm_pci_softc *,
250f67437f3Spatrick 		     struct mbuf *);
251f67437f3Spatrick void		 bwfm_pci_flowring_create(struct bwfm_pci_softc *,
252518be5f3Spatrick 		     struct mbuf *);
253518be5f3Spatrick void		 bwfm_pci_flowring_create_cb(struct bwfm_softc *, void *);
254a2c6ff8bSpatrick void		 bwfm_pci_flowring_delete(struct bwfm_pci_softc *, int);
255518be5f3Spatrick 
256a2c6ff8bSpatrick void		 bwfm_pci_stop(struct bwfm_softc *);
257e5ec1e72Spatrick int		 bwfm_pci_txdata(struct bwfm_softc *, struct mbuf *);
258bbd71b0bSpatrick 
259bbd71b0bSpatrick #ifdef BWFM_DEBUG
260cadf5fcfSpatrick void		 bwfm_pci_debug_console(struct bwfm_pci_softc *);
261bbd71b0bSpatrick #endif
262e5ec1e72Spatrick 
263e5ec1e72Spatrick int		 bwfm_pci_msgbuf_query_dcmd(struct bwfm_softc *, int,
264e5ec1e72Spatrick 		    int, char *, size_t *);
265e5ec1e72Spatrick int		 bwfm_pci_msgbuf_set_dcmd(struct bwfm_softc *, int,
266e5ec1e72Spatrick 		    int, char *, size_t);
267e5ec1e72Spatrick 
268e5ec1e72Spatrick struct bwfm_buscore_ops bwfm_pci_buscore_ops = {
269e5ec1e72Spatrick 	.bc_read = bwfm_pci_buscore_read,
270e5ec1e72Spatrick 	.bc_write = bwfm_pci_buscore_write,
271e5ec1e72Spatrick 	.bc_prepare = bwfm_pci_buscore_prepare,
272e5ec1e72Spatrick 	.bc_reset = bwfm_pci_buscore_reset,
273e5ec1e72Spatrick 	.bc_setup = NULL,
274e5ec1e72Spatrick 	.bc_activate = bwfm_pci_buscore_activate,
275e5ec1e72Spatrick };
276e5ec1e72Spatrick 
277e5ec1e72Spatrick struct bwfm_bus_ops bwfm_pci_bus_ops = {
278e5ec1e72Spatrick 	.bs_init = NULL,
279a2c6ff8bSpatrick 	.bs_stop = bwfm_pci_stop,
280e5ec1e72Spatrick 	.bs_txdata = bwfm_pci_txdata,
281e5ec1e72Spatrick 	.bs_txctl = NULL,
282e5ec1e72Spatrick 	.bs_rxctl = NULL,
283e5ec1e72Spatrick };
284e5ec1e72Spatrick 
285e5ec1e72Spatrick struct bwfm_proto_ops bwfm_pci_msgbuf_ops = {
286e5ec1e72Spatrick 	.proto_query_dcmd = bwfm_pci_msgbuf_query_dcmd,
287e5ec1e72Spatrick 	.proto_set_dcmd = bwfm_pci_msgbuf_set_dcmd,
288e5ec1e72Spatrick };
289e5ec1e72Spatrick 
290e5ec1e72Spatrick struct cfattach bwfm_pci_ca = {
291e5ec1e72Spatrick 	sizeof(struct bwfm_pci_softc),
292e5ec1e72Spatrick 	bwfm_pci_match,
293e5ec1e72Spatrick 	bwfm_pci_attach,
294e5ec1e72Spatrick 	bwfm_pci_detach,
295e5ec1e72Spatrick };
296e5ec1e72Spatrick 
297e5ec1e72Spatrick static const struct pci_matchid bwfm_pci_devices[] = {
298e5ec1e72Spatrick 	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM43602 },
299e5ec1e72Spatrick };
300e5ec1e72Spatrick 
301e5ec1e72Spatrick int
302e5ec1e72Spatrick bwfm_pci_match(struct device *parent, void *match, void *aux)
303e5ec1e72Spatrick {
304e5ec1e72Spatrick 	return (pci_matchbyid(aux, bwfm_pci_devices,
305e5ec1e72Spatrick 	    nitems(bwfm_pci_devices)));
306e5ec1e72Spatrick }
307e5ec1e72Spatrick 
308e5ec1e72Spatrick void
309e5ec1e72Spatrick bwfm_pci_attach(struct device *parent, struct device *self, void *aux)
310e5ec1e72Spatrick {
311e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (struct bwfm_pci_softc *)self;
312e5ec1e72Spatrick 	struct pci_attach_args *pa = (struct pci_attach_args *)aux;
313e5ec1e72Spatrick 	const char *intrstr;
314e5ec1e72Spatrick 	pci_intr_handle_t ih;
315e5ec1e72Spatrick 
316e5ec1e72Spatrick 	if (pci_mapreg_map(pa, PCI_MAPREG_START + 0x00,
317e5ec1e72Spatrick 	    PCI_MAPREG_MEM_TYPE_64BIT, 0, &sc->sc_reg_iot, &sc->sc_reg_ioh,
318e5ec1e72Spatrick 	    NULL, &sc->sc_reg_ios, 0)) {
319e5ec1e72Spatrick 		printf(": can't map bar0\n");
320e5ec1e72Spatrick 		return;
321e5ec1e72Spatrick 	}
322e5ec1e72Spatrick 
323e5ec1e72Spatrick 	if (pci_mapreg_map(pa, PCI_MAPREG_START + 0x08,
324e5ec1e72Spatrick 	    PCI_MAPREG_MEM_TYPE_64BIT, 0, &sc->sc_tcm_iot, &sc->sc_tcm_ioh,
325e5ec1e72Spatrick 	    NULL, &sc->sc_tcm_ios, 0)) {
326e5ec1e72Spatrick 		printf(": can't map bar1\n");
327e5ec1e72Spatrick 		goto bar0;
328e5ec1e72Spatrick 	}
329e5ec1e72Spatrick 
330e5ec1e72Spatrick 	sc->sc_pc = pa->pa_pc;
331e5ec1e72Spatrick 	sc->sc_tag = pa->pa_tag;
332e5ec1e72Spatrick 	sc->sc_id = pa->pa_id;
333e5ec1e72Spatrick 	sc->sc_dmat = pa->pa_dmat;
334e5ec1e72Spatrick 
335e5ec1e72Spatrick 	/* Map and establish the interrupt. */
336e5ec1e72Spatrick 	if (pci_intr_map_msi(pa, &ih) != 0 && pci_intr_map(pa, &ih) != 0) {
337e5ec1e72Spatrick 		printf(": couldn't map interrupt\n");
338e5ec1e72Spatrick 		goto bar1;
339e5ec1e72Spatrick 	}
340e5ec1e72Spatrick 	intrstr = pci_intr_string(pa->pa_pc, ih);
341e5ec1e72Spatrick 
342e5ec1e72Spatrick 	sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_NET | IPL_MPSAFE,
343e5ec1e72Spatrick 	    bwfm_pci_intr, sc, DEVNAME(sc));
344e5ec1e72Spatrick 	if (sc->sc_ih == NULL) {
345e5ec1e72Spatrick 		printf(": couldn't establish interrupt");
346e5ec1e72Spatrick 		if (intrstr != NULL)
347e5ec1e72Spatrick 			printf(" at %s", intrstr);
348e5ec1e72Spatrick 		printf("\n");
349e5ec1e72Spatrick 		goto bar1;
350e5ec1e72Spatrick 	}
351e5ec1e72Spatrick 	printf(": %s\n", intrstr);
352e5ec1e72Spatrick 
353e5ec1e72Spatrick 	config_mountroot(self, bwfm_pci_attachhook);
354e5ec1e72Spatrick 	return;
355e5ec1e72Spatrick 
356e5ec1e72Spatrick bar1:
357e5ec1e72Spatrick 	bus_space_unmap(sc->sc_tcm_iot, sc->sc_tcm_ioh, sc->sc_tcm_ios);
358e5ec1e72Spatrick bar0:
359e5ec1e72Spatrick 	bus_space_unmap(sc->sc_reg_iot, sc->sc_reg_ioh, sc->sc_reg_ios);
360e5ec1e72Spatrick }
361e5ec1e72Spatrick 
362e5ec1e72Spatrick void
363e5ec1e72Spatrick bwfm_pci_attachhook(struct device *self)
364e5ec1e72Spatrick {
365e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (struct bwfm_pci_softc *)self;
366e5ec1e72Spatrick 	struct bwfm_softc *bwfm = (void *)sc;
367e5ec1e72Spatrick 	struct bwfm_pci_ringinfo ringinfo;
368e5ec1e72Spatrick 	const char *name = NULL;
369e5ec1e72Spatrick 	u_char *ucode; size_t size;
370e5ec1e72Spatrick 	uint32_t d2h_w_idx_ptr, d2h_r_idx_ptr;
371e5ec1e72Spatrick 	uint32_t h2d_w_idx_ptr, h2d_r_idx_ptr;
372e5ec1e72Spatrick 	uint32_t idx_offset, reg;
373e5ec1e72Spatrick 	int i;
374e5ec1e72Spatrick 
375e5ec1e72Spatrick 	sc->sc_sc.sc_buscore_ops = &bwfm_pci_buscore_ops;
376e5ec1e72Spatrick 	if (bwfm_chip_attach(&sc->sc_sc) != 0) {
377e5ec1e72Spatrick 		printf("%s: cannot attach chip\n", DEVNAME(sc));
378e5ec1e72Spatrick 		return;
379e5ec1e72Spatrick 	}
380e5ec1e72Spatrick 
381e5ec1e72Spatrick 	bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2);
382e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
383e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_CONFIGADDR, 0x4e0);
384e5ec1e72Spatrick 	reg = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
385e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_CONFIGDATA);
386e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
387e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_CONFIGDATA, reg);
388e5ec1e72Spatrick 
389e5ec1e72Spatrick 	switch (bwfm->sc_chip.ch_chip)
390e5ec1e72Spatrick 	{
391e5ec1e72Spatrick 	case BRCM_CC_43602_CHIP_ID:
392e5ec1e72Spatrick 		name = "brcmfmac43602-pcie.bin";
393e5ec1e72Spatrick 		break;
394e5ec1e72Spatrick 	default:
395e5ec1e72Spatrick 		break;
396e5ec1e72Spatrick 	}
397e5ec1e72Spatrick 
398e5ec1e72Spatrick 	if (name == NULL) {
399e5ec1e72Spatrick 		printf("%s: unknown firmware\n", DEVNAME(sc));
400e5ec1e72Spatrick 		return;
401e5ec1e72Spatrick 	}
402e5ec1e72Spatrick 
403e5ec1e72Spatrick 	if (loadfirmware(name, &ucode, &size) != 0) {
404e5ec1e72Spatrick 		printf("%s: failed loadfirmware of file %s\n",
405e5ec1e72Spatrick 		    DEVNAME(sc), name);
406e5ec1e72Spatrick 		return;
407e5ec1e72Spatrick 	}
408e5ec1e72Spatrick 
409e5ec1e72Spatrick 	/* Retrieve RAM size from firmware. */
410e5ec1e72Spatrick 	if (size >= BWFM_RAMSIZE + 8) {
411e5ec1e72Spatrick 		uint32_t *ramsize = (uint32_t *)&ucode[BWFM_RAMSIZE];
412e5ec1e72Spatrick 		if (letoh32(ramsize[0]) == BWFM_RAMSIZE_MAGIC)
413e5ec1e72Spatrick 			bwfm->sc_chip.ch_ramsize = letoh32(ramsize[1]);
414e5ec1e72Spatrick 	}
415e5ec1e72Spatrick 
416e5ec1e72Spatrick 	if (bwfm_pci_load_microcode(sc, ucode, size) != 0) {
417e5ec1e72Spatrick 		printf("%s: could not load microcode\n",
418e5ec1e72Spatrick 		    DEVNAME(sc));
419e5ec1e72Spatrick 		free(ucode, M_DEVBUF, size);
420e5ec1e72Spatrick 		return;
421e5ec1e72Spatrick 	}
422e5ec1e72Spatrick 	free(ucode, M_DEVBUF, size);
423e5ec1e72Spatrick 
424e5ec1e72Spatrick 	sc->sc_shared_flags = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
425e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_INFO);
426e5ec1e72Spatrick 	sc->sc_shared_version = sc->sc_shared_flags;
427e5ec1e72Spatrick 	if (sc->sc_shared_version > BWFM_SHARED_INFO_MAX_VERSION ||
428e5ec1e72Spatrick 	    sc->sc_shared_version < BWFM_SHARED_INFO_MIN_VERSION) {
429e5ec1e72Spatrick 		printf("%s: PCIe version %d unsupported\n",
430e5ec1e72Spatrick 		    DEVNAME(sc), sc->sc_shared_version);
431e5ec1e72Spatrick 		return;
432e5ec1e72Spatrick 	}
433e5ec1e72Spatrick 
434e5ec1e72Spatrick 	if (sc->sc_shared_flags & BWFM_SHARED_INFO_DMA_INDEX) {
435e5ec1e72Spatrick 		if (sc->sc_shared_flags & BWFM_SHARED_INFO_DMA_2B_IDX)
436e5ec1e72Spatrick 			sc->sc_dma_idx_sz = sizeof(uint16_t);
437e5ec1e72Spatrick 		else
438e5ec1e72Spatrick 			sc->sc_dma_idx_sz = sizeof(uint32_t);
439e5ec1e72Spatrick 	}
440e5ec1e72Spatrick 
441e5ec1e72Spatrick 	/* Maximum RX data buffers in the ring. */
442e5ec1e72Spatrick 	sc->sc_max_rxbufpost = bus_space_read_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
443e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_MAX_RXBUFPOST);
444e5ec1e72Spatrick 	if (sc->sc_max_rxbufpost == 0)
445e5ec1e72Spatrick 		sc->sc_max_rxbufpost = BWFM_SHARED_MAX_RXBUFPOST_DEFAULT;
446e5ec1e72Spatrick 
447e5ec1e72Spatrick 	/* Alternative offset of data in a packet */
448e5ec1e72Spatrick 	sc->sc_rx_dataoffset = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
449e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_RX_DATAOFFSET);
450e5ec1e72Spatrick 
451e5ec1e72Spatrick 	/* For Power Management */
452e5ec1e72Spatrick 	sc->sc_htod_mb_data_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
453e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_HTOD_MB_DATA_ADDR);
454e5ec1e72Spatrick 	sc->sc_dtoh_mb_data_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
455e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DTOH_MB_DATA_ADDR);
456e5ec1e72Spatrick 
457e5ec1e72Spatrick 	/* Ring information */
458e5ec1e72Spatrick 	sc->sc_ring_info_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
459e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_RING_INFO_ADDR);
460e5ec1e72Spatrick 
461e5ec1e72Spatrick 	/* Firmware's "dmesg" */
462e5ec1e72Spatrick 	sc->sc_console_base_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
463e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_CONSOLE_ADDR);
464e5ec1e72Spatrick 	sc->sc_console_buf_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
465e5ec1e72Spatrick 	    sc->sc_console_base_addr + BWFM_CONSOLE_BUFADDR);
466e5ec1e72Spatrick 	sc->sc_console_buf_size = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
467e5ec1e72Spatrick 	    sc->sc_console_base_addr + BWFM_CONSOLE_BUFSIZE);
468e5ec1e72Spatrick 
469e5ec1e72Spatrick 	/* Read ring information. */
470e5ec1e72Spatrick 	bus_space_read_region_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
471e5ec1e72Spatrick 	    sc->sc_ring_info_addr, (void *)&ringinfo, sizeof(ringinfo));
472e5ec1e72Spatrick 
473e5ec1e72Spatrick 	if (sc->sc_shared_version >= 6) {
474e5ec1e72Spatrick 		sc->sc_max_submissionrings = le16toh(ringinfo.max_submissionrings);
475e5ec1e72Spatrick 		sc->sc_max_flowrings = le16toh(ringinfo.max_flowrings);
476e5ec1e72Spatrick 		sc->sc_max_completionrings = le16toh(ringinfo.max_completionrings);
477e5ec1e72Spatrick 	} else {
478e5ec1e72Spatrick 		sc->sc_max_submissionrings = le16toh(ringinfo.max_flowrings);
479e5ec1e72Spatrick 		sc->sc_max_flowrings = sc->sc_max_submissionrings -
480e5ec1e72Spatrick 		    BWFM_NUM_TX_MSGRINGS;
481e5ec1e72Spatrick 		sc->sc_max_completionrings = BWFM_NUM_RX_MSGRINGS;
482e5ec1e72Spatrick 	}
483e5ec1e72Spatrick 
484e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
485e5ec1e72Spatrick 		d2h_w_idx_ptr = letoh32(ringinfo.d2h_w_idx_ptr);
486e5ec1e72Spatrick 		d2h_r_idx_ptr = letoh32(ringinfo.d2h_r_idx_ptr);
487e5ec1e72Spatrick 		h2d_w_idx_ptr = letoh32(ringinfo.h2d_w_idx_ptr);
488e5ec1e72Spatrick 		h2d_r_idx_ptr = letoh32(ringinfo.h2d_r_idx_ptr);
489e5ec1e72Spatrick 		idx_offset = sizeof(uint32_t);
490e5ec1e72Spatrick 	} else {
491e5ec1e72Spatrick 		uint64_t address;
492e5ec1e72Spatrick 
493e5ec1e72Spatrick 		/* Each TX/RX Ring has a Read and Write Ptr */
494e5ec1e72Spatrick 		sc->sc_dma_idx_bufsz = (sc->sc_max_submissionrings +
495e5ec1e72Spatrick 		    sc->sc_max_completionrings) * sc->sc_dma_idx_sz * 2;
496e5ec1e72Spatrick 		sc->sc_dma_idx_buf = bwfm_pci_dmamem_alloc(sc,
497e5ec1e72Spatrick 		    sc->sc_dma_idx_bufsz, 8);
498e5ec1e72Spatrick 		if (sc->sc_dma_idx_buf == NULL) {
499e5ec1e72Spatrick 			/* XXX: Fallback to TCM? */
500e5ec1e72Spatrick 			printf("%s: cannot allocate idx buf\n",
501e5ec1e72Spatrick 			    DEVNAME(sc));
502e5ec1e72Spatrick 			return;
503e5ec1e72Spatrick 		}
504e5ec1e72Spatrick 
505e5ec1e72Spatrick 		idx_offset = sc->sc_dma_idx_sz;
506e5ec1e72Spatrick 		h2d_w_idx_ptr = 0;
507e5ec1e72Spatrick 		address = BWFM_PCI_DMA_DVA(sc->sc_dma_idx_buf);
508e5ec1e72Spatrick 		ringinfo.h2d_w_idx_hostaddr_low =
509e5ec1e72Spatrick 		    htole32(address & 0xffffffff);
510e5ec1e72Spatrick 		ringinfo.h2d_w_idx_hostaddr_high =
511e5ec1e72Spatrick 		    htole32(address >> 32);
512e5ec1e72Spatrick 
513e5ec1e72Spatrick 		h2d_r_idx_ptr = h2d_w_idx_ptr +
514e5ec1e72Spatrick 		    sc->sc_max_submissionrings * idx_offset;
515e5ec1e72Spatrick 		address += sc->sc_max_submissionrings * idx_offset;
516e5ec1e72Spatrick 		ringinfo.h2d_r_idx_hostaddr_low =
517e5ec1e72Spatrick 		    htole32(address & 0xffffffff);
518e5ec1e72Spatrick 		ringinfo.h2d_r_idx_hostaddr_high =
519e5ec1e72Spatrick 		    htole32(address >> 32);
520e5ec1e72Spatrick 
521e5ec1e72Spatrick 		d2h_w_idx_ptr = h2d_r_idx_ptr +
522e5ec1e72Spatrick 		    sc->sc_max_submissionrings * idx_offset;
523e5ec1e72Spatrick 		address += sc->sc_max_submissionrings * idx_offset;
524e5ec1e72Spatrick 		ringinfo.d2h_w_idx_hostaddr_low =
525e5ec1e72Spatrick 		    htole32(address & 0xffffffff);
526e5ec1e72Spatrick 		ringinfo.d2h_w_idx_hostaddr_high =
527e5ec1e72Spatrick 		    htole32(address >> 32);
528e5ec1e72Spatrick 
529e5ec1e72Spatrick 		d2h_r_idx_ptr = d2h_w_idx_ptr +
530e5ec1e72Spatrick 		    sc->sc_max_completionrings * idx_offset;
531e5ec1e72Spatrick 		address += sc->sc_max_completionrings * idx_offset;
532e5ec1e72Spatrick 		ringinfo.d2h_r_idx_hostaddr_low =
533e5ec1e72Spatrick 		    htole32(address & 0xffffffff);
534e5ec1e72Spatrick 		ringinfo.d2h_r_idx_hostaddr_high =
535e5ec1e72Spatrick 		    htole32(address >> 32);
536e5ec1e72Spatrick 
537e5ec1e72Spatrick 		bus_space_write_region_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
538e5ec1e72Spatrick 		    sc->sc_ring_info_addr, (void *)&ringinfo, sizeof(ringinfo));
539e5ec1e72Spatrick 	}
540e5ec1e72Spatrick 
541e5ec1e72Spatrick 	uint32_t ring_mem_ptr = letoh32(ringinfo.ringmem);
542e5ec1e72Spatrick 	/* TX ctrl ring: Send ctrl buffers, send IOCTLs */
543e5ec1e72Spatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_ctrl_submit, 64, 40,
544e5ec1e72Spatrick 	    h2d_w_idx_ptr, h2d_r_idx_ptr, 0, idx_offset,
545e5ec1e72Spatrick 	    &ring_mem_ptr))
546e5ec1e72Spatrick 		goto cleanup;
547e5ec1e72Spatrick 	/* TX rxpost ring: Send clean data mbufs for RX */
548e5ec1e72Spatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_rxpost_submit, 512, 32,
549e5ec1e72Spatrick 	    h2d_w_idx_ptr, h2d_r_idx_ptr, 1, idx_offset,
550e5ec1e72Spatrick 	    &ring_mem_ptr))
551e5ec1e72Spatrick 		goto cleanup;
552e5ec1e72Spatrick 	/* RX completion rings: recv our filled buffers back */
553e5ec1e72Spatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_ctrl_complete, 64, 24,
554e5ec1e72Spatrick 	    d2h_w_idx_ptr, d2h_r_idx_ptr, 0, idx_offset,
555e5ec1e72Spatrick 	    &ring_mem_ptr))
556e5ec1e72Spatrick 		goto cleanup;
557e5ec1e72Spatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_tx_complete, 1024, 16,
558e5ec1e72Spatrick 	    d2h_w_idx_ptr, d2h_r_idx_ptr, 1, idx_offset,
559e5ec1e72Spatrick 	    &ring_mem_ptr))
560e5ec1e72Spatrick 		goto cleanup;
561e5ec1e72Spatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_rx_complete, 512, 32,
562e5ec1e72Spatrick 	    d2h_w_idx_ptr, d2h_r_idx_ptr, 2, idx_offset,
563e5ec1e72Spatrick 	    &ring_mem_ptr))
564e5ec1e72Spatrick 		goto cleanup;
565e5ec1e72Spatrick 
566e5ec1e72Spatrick 	/* Dynamic TX rings for actual data */
567e5ec1e72Spatrick 	sc->sc_flowrings = malloc(sc->sc_max_flowrings *
568e5ec1e72Spatrick 	    sizeof(struct bwfm_pci_msgring), M_DEVBUF, M_WAITOK | M_ZERO);
569518be5f3Spatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
570518be5f3Spatrick 		struct bwfm_pci_msgring *ring = &sc->sc_flowrings[i];
571518be5f3Spatrick 		ring->w_idx_addr = h2d_w_idx_ptr + (i + 2) * idx_offset;
572518be5f3Spatrick 		ring->r_idx_addr = h2d_r_idx_ptr + (i + 2) * idx_offset;
573518be5f3Spatrick 	}
574e5ec1e72Spatrick 
575e5ec1e72Spatrick 	/* Scratch and ring update buffers for firmware */
576e5ec1e72Spatrick 	if ((sc->sc_scratch_buf = bwfm_pci_dmamem_alloc(sc,
577e5ec1e72Spatrick 	    BWFM_DMA_D2H_SCRATCH_BUF_LEN, 8)) == NULL)
578e5ec1e72Spatrick 		goto cleanup;
579e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
580e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_SCRATCH_ADDR_LOW,
581e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(sc->sc_scratch_buf) & 0xffffffff);
582e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
583e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_SCRATCH_ADDR_HIGH,
584e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(sc->sc_scratch_buf) >> 32);
585e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
586e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_SCRATCH_LEN,
587e5ec1e72Spatrick 	    BWFM_DMA_D2H_SCRATCH_BUF_LEN);
588e5ec1e72Spatrick 
589e5ec1e72Spatrick 	if ((sc->sc_ringupd_buf = bwfm_pci_dmamem_alloc(sc,
590e5ec1e72Spatrick 	    BWFM_DMA_D2H_RINGUPD_BUF_LEN, 8)) == NULL)
591e5ec1e72Spatrick 		goto cleanup;
592e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
593e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_RINGUPD_ADDR_LOW,
594e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(sc->sc_ringupd_buf) & 0xffffffff);
595e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
596e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_RINGUPD_ADDR_HIGH,
597e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(sc->sc_ringupd_buf) >> 32);
598e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
599e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_RINGUPD_LEN,
600e5ec1e72Spatrick 	    BWFM_DMA_D2H_RINGUPD_BUF_LEN);
601e5ec1e72Spatrick 
602e5ec1e72Spatrick 	if ((sc->sc_ioctl_buf = bwfm_pci_dmamem_alloc(sc,
603e5ec1e72Spatrick 	    BWFM_DMA_H2D_IOCTL_BUF_LEN, 8)) == NULL)
604e5ec1e72Spatrick 		goto cleanup;
605e5ec1e72Spatrick 
606e5ec1e72Spatrick 	bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2);
607e5ec1e72Spatrick 	bwfm_pci_intr_enable(sc);
608e5ec1e72Spatrick 
609e5ec1e72Spatrick 	/* Maps RX mbufs to a packet id and back. */
610e5ec1e72Spatrick 	sc->sc_rx_pkts.npkt = BWFM_NUM_RX_PKTIDS;
611e5ec1e72Spatrick 	sc->sc_rx_pkts.pkts = malloc(BWFM_NUM_RX_PKTIDS *
612e5ec1e72Spatrick 	    sizeof(struct bwfm_pci_buf), M_DEVBUF, M_WAITOK | M_ZERO);
613e5ec1e72Spatrick 	for (i = 0; i < BWFM_NUM_RX_PKTIDS; i++)
614e5ec1e72Spatrick 		bus_dmamap_create(sc->sc_dmat, MSGBUF_MAX_PKT_SIZE,
615e5ec1e72Spatrick 		    BWFM_NUM_RX_DESCS, MSGBUF_MAX_PKT_SIZE, 0, BUS_DMA_WAITOK,
616e5ec1e72Spatrick 		    &sc->sc_rx_pkts.pkts[i].bb_map);
617e5ec1e72Spatrick 	sc->sc_tx_pkts.npkt = BWFM_NUM_TX_PKTIDS;
618e5ec1e72Spatrick 
619e5ec1e72Spatrick 	/* Maps TX mbufs to a packet id and back. */
620e5ec1e72Spatrick 	sc->sc_tx_pkts.pkts = malloc(BWFM_NUM_TX_PKTIDS
621e5ec1e72Spatrick 	    * sizeof(struct bwfm_pci_buf), M_DEVBUF, M_WAITOK | M_ZERO);
622e5ec1e72Spatrick 	for (i = 0; i < BWFM_NUM_TX_PKTIDS; i++)
623e5ec1e72Spatrick 		bus_dmamap_create(sc->sc_dmat, MSGBUF_MAX_PKT_SIZE,
624e5ec1e72Spatrick 		    BWFM_NUM_TX_DESCS, MSGBUF_MAX_PKT_SIZE, 0, BUS_DMA_WAITOK,
625e5ec1e72Spatrick 		    &sc->sc_tx_pkts.pkts[i].bb_map);
626e5ec1e72Spatrick 
62718722113Spatrick 	/*
62818722113Spatrick 	 * For whatever reason, could also be a bug somewhere in this
62918722113Spatrick 	 * driver, the firmware needs a bunch of RX buffers otherwise
63018722113Spatrick 	 * it won't send any RX complete messages.  64 buffers don't
63118722113Spatrick 	 * suffice, but 128 buffers are enough.
63218722113Spatrick 	 */
63318722113Spatrick 	if_rxr_init(&sc->sc_rxbuf_ring, 128, sc->sc_max_rxbufpost);
634e5ec1e72Spatrick 	if_rxr_init(&sc->sc_ioctl_ring, 8, 8);
635e5ec1e72Spatrick 	if_rxr_init(&sc->sc_event_ring, 8, 8);
636e5ec1e72Spatrick 	bwfm_pci_fill_rx_rings(sc);
637e5ec1e72Spatrick 
638cadf5fcfSpatrick #ifdef BWFM_DEBUG
639cadf5fcfSpatrick 	sc->sc_console_readidx = 0;
640cadf5fcfSpatrick 	bwfm_pci_debug_console(sc);
641cadf5fcfSpatrick #endif
642cadf5fcfSpatrick 
643e5ec1e72Spatrick 	sc->sc_ioctl_poll = 1;
644e5ec1e72Spatrick 	sc->sc_sc.sc_bus_ops = &bwfm_pci_bus_ops;
645e5ec1e72Spatrick 	sc->sc_sc.sc_proto_ops = &bwfm_pci_msgbuf_ops;
646e5ec1e72Spatrick 	bwfm_attach(&sc->sc_sc);
647e5ec1e72Spatrick 	sc->sc_ioctl_poll = 0;
648e5ec1e72Spatrick 	return;
649e5ec1e72Spatrick 
650e5ec1e72Spatrick cleanup:
651e5ec1e72Spatrick 	if (sc->sc_ioctl_buf)
652e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_ioctl_buf);
653e5ec1e72Spatrick 	if (sc->sc_ringupd_buf)
654e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_ringupd_buf);
655e5ec1e72Spatrick 	if (sc->sc_scratch_buf)
656e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_scratch_buf);
657e5ec1e72Spatrick 	if (sc->sc_rx_complete.ring)
658e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_rx_complete.ring);
659e5ec1e72Spatrick 	if (sc->sc_tx_complete.ring)
660e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_tx_complete.ring);
661e5ec1e72Spatrick 	if (sc->sc_ctrl_complete.ring)
662e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_ctrl_complete.ring);
663e5ec1e72Spatrick 	if (sc->sc_rxpost_submit.ring)
664e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_rxpost_submit.ring);
665e5ec1e72Spatrick 	if (sc->sc_ctrl_submit.ring)
666e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_ctrl_submit.ring);
667e5ec1e72Spatrick 	if (sc->sc_dma_idx_buf)
668e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_dma_idx_buf);
669e5ec1e72Spatrick }
670e5ec1e72Spatrick 
671e5ec1e72Spatrick int
672e5ec1e72Spatrick bwfm_pci_load_microcode(struct bwfm_pci_softc *sc, const u_char *ucode, size_t size)
673e5ec1e72Spatrick {
674e5ec1e72Spatrick 	struct bwfm_softc *bwfm = (void *)sc;
675e5ec1e72Spatrick 	struct bwfm_core *core;
676e5ec1e72Spatrick 	uint32_t shared;
677e5ec1e72Spatrick 	int i;
678e5ec1e72Spatrick 
679e5ec1e72Spatrick 	if (bwfm->sc_chip.ch_chip == BRCM_CC_43602_CHIP_ID) {
680e5ec1e72Spatrick 		bwfm_pci_select_core(sc, BWFM_AGENT_CORE_ARM_CR4);
681e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
682e5ec1e72Spatrick 		    BWFM_PCI_ARMCR4REG_BANKIDX, 5);
683e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
684e5ec1e72Spatrick 		    BWFM_PCI_ARMCR4REG_BANKPDA, 0);
685e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
686e5ec1e72Spatrick 		    BWFM_PCI_ARMCR4REG_BANKIDX, 7);
687e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
688e5ec1e72Spatrick 		    BWFM_PCI_ARMCR4REG_BANKPDA, 0);
689e5ec1e72Spatrick 	}
690e5ec1e72Spatrick 
691e5ec1e72Spatrick 	for (i = 0; i < size; i++)
692e5ec1e72Spatrick 		bus_space_write_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
693e5ec1e72Spatrick 		    bwfm->sc_chip.ch_rambase + i, ucode[i]);
694e5ec1e72Spatrick 
695e5ec1e72Spatrick 	/* Firmware replaces this with a pointer once up. */
696e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
697e5ec1e72Spatrick 	    bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize - 4, 0);
698e5ec1e72Spatrick 
699e5ec1e72Spatrick 	/* TODO: restore NVRAM */
700e5ec1e72Spatrick 
701e5ec1e72Spatrick 	/* Load reset vector from firmware and kickstart core. */
702e5ec1e72Spatrick 	core = bwfm_chip_get_core(bwfm, BWFM_AGENT_INTERNAL_MEM);
703e5ec1e72Spatrick 	bwfm->sc_chip.ch_core_reset(bwfm, core, 0, 0, 0);
704e5ec1e72Spatrick 	bwfm_chip_set_active(bwfm, *(uint32_t *)ucode);
705e5ec1e72Spatrick 
706e5ec1e72Spatrick 	for (i = 0; i < 40; i++) {
707e5ec1e72Spatrick 		delay(50 * 1000);
708e5ec1e72Spatrick 		shared = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
709e5ec1e72Spatrick 		    bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize - 4);
710e5ec1e72Spatrick 		if (shared)
711e5ec1e72Spatrick 			break;
712e5ec1e72Spatrick 	}
713e5ec1e72Spatrick 	if (!shared) {
714e5ec1e72Spatrick 		printf("%s: firmware did not come up\n", DEVNAME(sc));
715e5ec1e72Spatrick 		return 1;
716e5ec1e72Spatrick 	}
717e5ec1e72Spatrick 
718e5ec1e72Spatrick 	sc->sc_shared_address = shared;
719e5ec1e72Spatrick 	return 0;
720e5ec1e72Spatrick }
721e5ec1e72Spatrick 
722e5ec1e72Spatrick int
723e5ec1e72Spatrick bwfm_pci_detach(struct device *self, int flags)
724e5ec1e72Spatrick {
725e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (struct bwfm_pci_softc *)self;
726e5ec1e72Spatrick 
727e5ec1e72Spatrick 	bwfm_detach(&sc->sc_sc, flags);
728e5ec1e72Spatrick 
729e5ec1e72Spatrick 	/* FIXME: free RX buffers */
730e5ec1e72Spatrick 	/* FIXME: free TX buffers */
731e5ec1e72Spatrick 	/* FIXME: free more memory */
732e5ec1e72Spatrick 
733e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_ioctl_buf);
734e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_ringupd_buf);
735e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_scratch_buf);
736e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_rx_complete.ring);
737e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_tx_complete.ring);
738e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_ctrl_complete.ring);
739e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_rxpost_submit.ring);
740e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_ctrl_submit.ring);
741e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_dma_idx_buf);
742e5ec1e72Spatrick 	return 0;
743e5ec1e72Spatrick }
744e5ec1e72Spatrick 
745e5ec1e72Spatrick /* DMA code */
746e5ec1e72Spatrick struct bwfm_pci_dmamem *
747e5ec1e72Spatrick bwfm_pci_dmamem_alloc(struct bwfm_pci_softc *sc, bus_size_t size, bus_size_t align)
748e5ec1e72Spatrick {
749e5ec1e72Spatrick 	struct bwfm_pci_dmamem *bdm;
750e5ec1e72Spatrick 	int nsegs;
751e5ec1e72Spatrick 
752e5ec1e72Spatrick 	bdm = malloc(sizeof(*bdm), M_DEVBUF, M_WAITOK | M_ZERO);
753e5ec1e72Spatrick 	bdm->bdm_size = size;
754e5ec1e72Spatrick 
755e5ec1e72Spatrick 	if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
756e5ec1e72Spatrick 	    BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &bdm->bdm_map) != 0)
757e5ec1e72Spatrick 		goto bdmfree;
758e5ec1e72Spatrick 
759e5ec1e72Spatrick 	if (bus_dmamem_alloc(sc->sc_dmat, size, align, 0, &bdm->bdm_seg, 1,
760e5ec1e72Spatrick 	    &nsegs, BUS_DMA_WAITOK) != 0)
761e5ec1e72Spatrick 		goto destroy;
762e5ec1e72Spatrick 
763e5ec1e72Spatrick 	if (bus_dmamem_map(sc->sc_dmat, &bdm->bdm_seg, nsegs, size,
764e5ec1e72Spatrick 	    &bdm->bdm_kva, BUS_DMA_WAITOK | BUS_DMA_COHERENT) != 0)
765e5ec1e72Spatrick 		goto free;
766e5ec1e72Spatrick 
767e5ec1e72Spatrick 	if (bus_dmamap_load(sc->sc_dmat, bdm->bdm_map, bdm->bdm_kva, size,
768e5ec1e72Spatrick 	    NULL, BUS_DMA_WAITOK) != 0)
769e5ec1e72Spatrick 		goto unmap;
770e5ec1e72Spatrick 
771e5ec1e72Spatrick 	bzero(bdm->bdm_kva, size);
772e5ec1e72Spatrick 
773e5ec1e72Spatrick 	return (bdm);
774e5ec1e72Spatrick 
775e5ec1e72Spatrick unmap:
776e5ec1e72Spatrick 	bus_dmamem_unmap(sc->sc_dmat, bdm->bdm_kva, size);
777e5ec1e72Spatrick free:
778e5ec1e72Spatrick 	bus_dmamem_free(sc->sc_dmat, &bdm->bdm_seg, 1);
779e5ec1e72Spatrick destroy:
780e5ec1e72Spatrick 	bus_dmamap_destroy(sc->sc_dmat, bdm->bdm_map);
781e5ec1e72Spatrick bdmfree:
78265046b40Spatrick 	free(bdm, M_DEVBUF, sizeof(*bdm));
783e5ec1e72Spatrick 
784e5ec1e72Spatrick 	return (NULL);
785e5ec1e72Spatrick }
786e5ec1e72Spatrick 
787e5ec1e72Spatrick void
788e5ec1e72Spatrick bwfm_pci_dmamem_free(struct bwfm_pci_softc *sc, struct bwfm_pci_dmamem *bdm)
789e5ec1e72Spatrick {
790e5ec1e72Spatrick 	bus_dmamem_unmap(sc->sc_dmat, bdm->bdm_kva, bdm->bdm_size);
791e5ec1e72Spatrick 	bus_dmamem_free(sc->sc_dmat, &bdm->bdm_seg, 1);
792e5ec1e72Spatrick 	bus_dmamap_destroy(sc->sc_dmat, bdm->bdm_map);
79365046b40Spatrick 	free(bdm, M_DEVBUF, sizeof(*bdm));
794e5ec1e72Spatrick }
795e5ec1e72Spatrick 
796e5ec1e72Spatrick /*
797e5ec1e72Spatrick  * We need a simple mapping from a packet ID to mbufs, because when
798e5ec1e72Spatrick  * a transfer completed, we only know the ID so we have to look up
799e5ec1e72Spatrick  * the memory for the ID.  This simply looks for an empty slot.
800e5ec1e72Spatrick  */
801e5ec1e72Spatrick int
802e5ec1e72Spatrick bwfm_pci_pktid_new(struct bwfm_pci_softc *sc, struct bwfm_pci_pkts *pkts,
803e5ec1e72Spatrick     struct mbuf *m, uint32_t *pktid, paddr_t *paddr)
804e5ec1e72Spatrick {
805e5ec1e72Spatrick 	int i, idx;
806e5ec1e72Spatrick 
807e5ec1e72Spatrick 	idx = pkts->last + 1;
808e5ec1e72Spatrick 	for (i = 0; i < pkts->npkt; i++) {
809e5ec1e72Spatrick 		if (idx == pkts->npkt)
810e5ec1e72Spatrick 			idx = 0;
811e5ec1e72Spatrick 		if (pkts->pkts[idx].bb_m == NULL) {
812e5ec1e72Spatrick 			if (bus_dmamap_load_mbuf(sc->sc_dmat,
813e5ec1e72Spatrick 			    pkts->pkts[idx].bb_map, m, BUS_DMA_NOWAIT) != 0) {
814518be5f3Spatrick 				if (m_defrag(m, M_DONTWAIT))
815518be5f3Spatrick 					return EFBIG;
816518be5f3Spatrick 				if (bus_dmamap_load_mbuf(sc->sc_dmat,
817518be5f3Spatrick 				    pkts->pkts[idx].bb_map, m, BUS_DMA_NOWAIT) != 0)
818518be5f3Spatrick 					return EFBIG;
819e5ec1e72Spatrick 			}
820e5ec1e72Spatrick 			pkts->last = idx;
821e5ec1e72Spatrick 			pkts->pkts[idx].bb_m = m;
822e5ec1e72Spatrick 			*pktid = idx;
823e5ec1e72Spatrick 			*paddr = pkts->pkts[idx].bb_map->dm_segs[0].ds_addr;
824e5ec1e72Spatrick 			return 0;
825e5ec1e72Spatrick 		}
826e5ec1e72Spatrick 		idx++;
827e5ec1e72Spatrick 	}
828518be5f3Spatrick 	return ENOBUFS;
829e5ec1e72Spatrick }
830e5ec1e72Spatrick 
831e5ec1e72Spatrick struct mbuf *
832e5ec1e72Spatrick bwfm_pci_pktid_free(struct bwfm_pci_softc *sc, struct bwfm_pci_pkts *pkts,
833e5ec1e72Spatrick     uint32_t pktid)
834e5ec1e72Spatrick {
835e5ec1e72Spatrick 	struct mbuf *m;
836e5ec1e72Spatrick 
837e5ec1e72Spatrick 	if (pktid >= pkts->npkt || pkts->pkts[pktid].bb_m == NULL)
838e5ec1e72Spatrick 		return NULL;
839e5ec1e72Spatrick 	bus_dmamap_unload(sc->sc_dmat, pkts->pkts[pktid].bb_map);
840e5ec1e72Spatrick 	m = pkts->pkts[pktid].bb_m;
841e5ec1e72Spatrick 	pkts->pkts[pktid].bb_m = NULL;
842e5ec1e72Spatrick 	return m;
843e5ec1e72Spatrick }
844e5ec1e72Spatrick 
845e5ec1e72Spatrick void
846e5ec1e72Spatrick bwfm_pci_fill_rx_rings(struct bwfm_pci_softc *sc)
847e5ec1e72Spatrick {
84818722113Spatrick 	bwfm_pci_fill_rx_buf_ring(sc);
849e5ec1e72Spatrick 	bwfm_pci_fill_rx_ioctl_ring(sc, &sc->sc_ioctl_ring,
850e5ec1e72Spatrick 	    MSGBUF_TYPE_IOCTLRESP_BUF_POST);
851e5ec1e72Spatrick 	bwfm_pci_fill_rx_ioctl_ring(sc, &sc->sc_event_ring,
852e5ec1e72Spatrick 	    MSGBUF_TYPE_EVENT_BUF_POST);
853e5ec1e72Spatrick }
854e5ec1e72Spatrick 
855e5ec1e72Spatrick void
856e5ec1e72Spatrick bwfm_pci_fill_rx_ioctl_ring(struct bwfm_pci_softc *sc, struct if_rxring *rxring,
857e5ec1e72Spatrick     uint32_t msgtype)
858e5ec1e72Spatrick {
859e5ec1e72Spatrick 	struct msgbuf_rx_ioctl_resp_or_event *req;
860e5ec1e72Spatrick 	struct mbuf *m;
861e5ec1e72Spatrick 	uint32_t pktid;
862e5ec1e72Spatrick 	paddr_t paddr;
863e5ec1e72Spatrick 	int s, slots;
864e5ec1e72Spatrick 
865e5ec1e72Spatrick 	s = splnet();
866e5ec1e72Spatrick 	for (slots = if_rxr_get(rxring, 8); slots > 0; slots--) {
867e5ec1e72Spatrick 		req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit);
868e5ec1e72Spatrick 		if (req == NULL)
869e5ec1e72Spatrick 			break;
870e5ec1e72Spatrick 		m = MCLGETI(NULL, M_DONTWAIT, NULL, MSGBUF_MAX_PKT_SIZE);
871e5ec1e72Spatrick 		if (m == NULL) {
872e5ec1e72Spatrick 			bwfm_pci_ring_write_cancel(sc, &sc->sc_ctrl_submit, 1);
873e5ec1e72Spatrick 			break;
874e5ec1e72Spatrick 		}
875e5ec1e72Spatrick 		m->m_len = m->m_pkthdr.len = MSGBUF_MAX_PKT_SIZE;
876e5ec1e72Spatrick 		if (bwfm_pci_pktid_new(sc, &sc->sc_rx_pkts, m, &pktid, &paddr)) {
877e5ec1e72Spatrick 			bwfm_pci_ring_write_cancel(sc, &sc->sc_ctrl_submit, 1);
878e5ec1e72Spatrick 			m_freem(m);
879e5ec1e72Spatrick 			break;
880e5ec1e72Spatrick 		}
881e5ec1e72Spatrick 		memset(req, 0, sizeof(*req));
882e5ec1e72Spatrick 		req->msg.msgtype = msgtype;
883e5ec1e72Spatrick 		req->msg.request_id = htole32(pktid);
884e5ec1e72Spatrick 		req->host_buf_len = htole16(MSGBUF_MAX_PKT_SIZE);
885e5ec1e72Spatrick 		req->host_buf_addr.high_addr = htole32(paddr >> 32);
886e5ec1e72Spatrick 		req->host_buf_addr.low_addr = htole32(paddr & 0xffffffff);
887e5ec1e72Spatrick 		bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit);
888e5ec1e72Spatrick 	}
889e5ec1e72Spatrick 	if_rxr_put(rxring, slots);
890e5ec1e72Spatrick 	splx(s);
891e5ec1e72Spatrick }
892e5ec1e72Spatrick 
893e5ec1e72Spatrick void
894e5ec1e72Spatrick bwfm_pci_fill_rx_buf_ring(struct bwfm_pci_softc *sc)
895e5ec1e72Spatrick {
896e5ec1e72Spatrick 	struct msgbuf_rx_bufpost *req;
897e5ec1e72Spatrick 	struct mbuf *m;
898e5ec1e72Spatrick 	uint32_t pktid;
899e5ec1e72Spatrick 	paddr_t paddr;
900e5ec1e72Spatrick 	int s, slots;
901e5ec1e72Spatrick 
902e5ec1e72Spatrick 	s = splnet();
903e5ec1e72Spatrick 	for (slots = if_rxr_get(&sc->sc_rxbuf_ring, sc->sc_max_rxbufpost);
904e5ec1e72Spatrick 	    slots > 0; slots--) {
905e5ec1e72Spatrick 		req = bwfm_pci_ring_write_reserve(sc, &sc->sc_rxpost_submit);
906e5ec1e72Spatrick 		if (req == NULL)
907e5ec1e72Spatrick 			break;
908e5ec1e72Spatrick 		m = MCLGETI(NULL, M_DONTWAIT, NULL, MSGBUF_MAX_PKT_SIZE);
909e5ec1e72Spatrick 		if (m == NULL) {
910e5ec1e72Spatrick 			bwfm_pci_ring_write_cancel(sc, &sc->sc_rxpost_submit, 1);
911e5ec1e72Spatrick 			break;
912e5ec1e72Spatrick 		}
913e5ec1e72Spatrick 		m->m_len = m->m_pkthdr.len = MSGBUF_MAX_PKT_SIZE;
914e5ec1e72Spatrick 		if (bwfm_pci_pktid_new(sc, &sc->sc_rx_pkts, m, &pktid, &paddr)) {
915e5ec1e72Spatrick 			bwfm_pci_ring_write_cancel(sc, &sc->sc_rxpost_submit, 1);
916e5ec1e72Spatrick 			m_freem(m);
917e5ec1e72Spatrick 			break;
918e5ec1e72Spatrick 		}
919e5ec1e72Spatrick 		memset(req, 0, sizeof(*req));
920e5ec1e72Spatrick 		req->msg.msgtype = MSGBUF_TYPE_RXBUF_POST;
921e5ec1e72Spatrick 		req->msg.request_id = htole32(pktid);
922e5ec1e72Spatrick 		req->data_buf_len = htole16(MSGBUF_MAX_PKT_SIZE);
923e5ec1e72Spatrick 		req->data_buf_addr.high_addr = htole32(paddr >> 32);
924e5ec1e72Spatrick 		req->data_buf_addr.low_addr = htole32(paddr & 0xffffffff);
925e5ec1e72Spatrick 		bwfm_pci_ring_write_commit(sc, &sc->sc_rxpost_submit);
926e5ec1e72Spatrick 	}
927e5ec1e72Spatrick 	if_rxr_put(&sc->sc_rxbuf_ring, slots);
928e5ec1e72Spatrick 	splx(s);
929e5ec1e72Spatrick }
930e5ec1e72Spatrick 
931e5ec1e72Spatrick int
932e5ec1e72Spatrick bwfm_pci_setup_ring(struct bwfm_pci_softc *sc, struct bwfm_pci_msgring *ring,
933e5ec1e72Spatrick     int nitem, size_t itemsz, uint32_t w_idx, uint32_t r_idx,
934e5ec1e72Spatrick     int idx, uint32_t idx_off, uint32_t *ring_mem)
935e5ec1e72Spatrick {
936e5ec1e72Spatrick 	ring->w_idx_addr = w_idx + idx * idx_off;
937e5ec1e72Spatrick 	ring->r_idx_addr = r_idx + idx * idx_off;
938e5ec1e72Spatrick 	ring->nitem = nitem;
939e5ec1e72Spatrick 	ring->itemsz = itemsz;
940e5ec1e72Spatrick 	bwfm_pci_ring_write_rptr(sc, ring);
941e5ec1e72Spatrick 	bwfm_pci_ring_write_wptr(sc, ring);
942e5ec1e72Spatrick 
943e5ec1e72Spatrick 	ring->ring = bwfm_pci_dmamem_alloc(sc, nitem * itemsz, 8);
944e5ec1e72Spatrick 	if (ring->ring == NULL)
945e5ec1e72Spatrick 		return ENOMEM;
946e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
947e5ec1e72Spatrick 	    *ring_mem + BWFM_RING_MEM_BASE_ADDR_LOW,
948e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(ring->ring) & 0xffffffff);
949e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
950e5ec1e72Spatrick 	    *ring_mem + BWFM_RING_MEM_BASE_ADDR_HIGH,
951e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(ring->ring) >> 32);
952e5ec1e72Spatrick 	bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
953e5ec1e72Spatrick 	    *ring_mem + BWFM_RING_MAX_ITEM, nitem);
954e5ec1e72Spatrick 	bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
955e5ec1e72Spatrick 	    *ring_mem + BWFM_RING_LEN_ITEMS, itemsz);
956e5ec1e72Spatrick 	*ring_mem = *ring_mem + BWFM_RING_MEM_SZ;
957e5ec1e72Spatrick 	return 0;
958e5ec1e72Spatrick }
959e5ec1e72Spatrick 
960518be5f3Spatrick int
961518be5f3Spatrick bwfm_pci_setup_flowring(struct bwfm_pci_softc *sc, struct bwfm_pci_msgring *ring,
962518be5f3Spatrick     int nitem, size_t itemsz)
963518be5f3Spatrick {
964518be5f3Spatrick 	ring->w_ptr = 0;
965518be5f3Spatrick 	ring->r_ptr = 0;
966518be5f3Spatrick 	ring->nitem = nitem;
967518be5f3Spatrick 	ring->itemsz = itemsz;
968518be5f3Spatrick 	bwfm_pci_ring_write_rptr(sc, ring);
969518be5f3Spatrick 	bwfm_pci_ring_write_wptr(sc, ring);
970518be5f3Spatrick 
971518be5f3Spatrick 	ring->ring = bwfm_pci_dmamem_alloc(sc, nitem * itemsz, 8);
972518be5f3Spatrick 	if (ring->ring == NULL)
973518be5f3Spatrick 		return ENOMEM;
974518be5f3Spatrick 	return 0;
975518be5f3Spatrick }
976518be5f3Spatrick 
977e5ec1e72Spatrick /* Ring helpers */
978e5ec1e72Spatrick void
979e5ec1e72Spatrick bwfm_pci_ring_bell(struct bwfm_pci_softc *sc,
980e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
981e5ec1e72Spatrick {
982e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
983e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_H2D_MAILBOX, 1);
984e5ec1e72Spatrick }
985e5ec1e72Spatrick 
986e5ec1e72Spatrick void
987e5ec1e72Spatrick bwfm_pci_ring_update_rptr(struct bwfm_pci_softc *sc,
988e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
989e5ec1e72Spatrick {
990e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
991e5ec1e72Spatrick 		ring->r_ptr = bus_space_read_2(sc->sc_tcm_iot,
992e5ec1e72Spatrick 		    sc->sc_tcm_ioh, ring->r_idx_addr);
993e5ec1e72Spatrick 	} else {
994e5ec1e72Spatrick 		ring->r_ptr = *(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf)
995e5ec1e72Spatrick 		    + ring->r_idx_addr);
996e5ec1e72Spatrick 	}
997e5ec1e72Spatrick }
998e5ec1e72Spatrick 
999e5ec1e72Spatrick void
1000e5ec1e72Spatrick bwfm_pci_ring_update_wptr(struct bwfm_pci_softc *sc,
1001e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1002e5ec1e72Spatrick {
1003e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
1004e5ec1e72Spatrick 		ring->w_ptr = bus_space_read_2(sc->sc_tcm_iot,
1005e5ec1e72Spatrick 		    sc->sc_tcm_ioh, ring->w_idx_addr);
1006e5ec1e72Spatrick 	} else {
1007e5ec1e72Spatrick 		ring->w_ptr = *(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf)
1008e5ec1e72Spatrick 		    + ring->w_idx_addr);
1009e5ec1e72Spatrick 	}
1010e5ec1e72Spatrick }
1011e5ec1e72Spatrick 
1012e5ec1e72Spatrick void
1013e5ec1e72Spatrick bwfm_pci_ring_write_rptr(struct bwfm_pci_softc *sc,
1014e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1015e5ec1e72Spatrick {
1016e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
1017e5ec1e72Spatrick 		bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1018e5ec1e72Spatrick 		    ring->r_idx_addr, ring->r_ptr);
1019e5ec1e72Spatrick 	} else {
1020e5ec1e72Spatrick 		*(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf)
1021e5ec1e72Spatrick 		    + ring->r_idx_addr) = ring->r_ptr;
1022e5ec1e72Spatrick 	}
1023e5ec1e72Spatrick }
1024e5ec1e72Spatrick 
1025e5ec1e72Spatrick void
1026e5ec1e72Spatrick bwfm_pci_ring_write_wptr(struct bwfm_pci_softc *sc,
1027e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1028e5ec1e72Spatrick {
1029e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
1030e5ec1e72Spatrick 		bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1031e5ec1e72Spatrick 		    ring->w_idx_addr, ring->w_ptr);
1032e5ec1e72Spatrick 	} else {
1033e5ec1e72Spatrick 		*(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf)
1034e5ec1e72Spatrick 		    + ring->w_idx_addr) = ring->w_ptr;
1035e5ec1e72Spatrick 	}
1036e5ec1e72Spatrick }
1037e5ec1e72Spatrick 
1038e5ec1e72Spatrick /*
1039e5ec1e72Spatrick  * Retrieve a free descriptor to put new stuff in, but don't commit
1040e5ec1e72Spatrick  * to it yet so we can rollback later if any error occurs.
1041e5ec1e72Spatrick  */
1042e5ec1e72Spatrick void *
1043e5ec1e72Spatrick bwfm_pci_ring_write_reserve(struct bwfm_pci_softc *sc,
1044e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1045e5ec1e72Spatrick {
1046e5ec1e72Spatrick 	int available;
1047e5ec1e72Spatrick 	char *ret;
1048e5ec1e72Spatrick 
1049e5ec1e72Spatrick 	bwfm_pci_ring_update_rptr(sc, ring);
1050e5ec1e72Spatrick 
1051e5ec1e72Spatrick 	if (ring->r_ptr > ring->w_ptr)
1052e5ec1e72Spatrick 		available = ring->r_ptr - ring->w_ptr;
1053e5ec1e72Spatrick 	else
1054e5ec1e72Spatrick 		available = ring->r_ptr + (ring->nitem - ring->w_ptr);
1055e5ec1e72Spatrick 
1056e5ec1e72Spatrick 	if (available < 1)
1057e5ec1e72Spatrick 		return NULL;
1058e5ec1e72Spatrick 
1059e5ec1e72Spatrick 	ret = BWFM_PCI_DMA_KVA(ring->ring) + (ring->w_ptr * ring->itemsz);
1060e5ec1e72Spatrick 	ring->w_ptr += 1;
1061e5ec1e72Spatrick 	if (ring->w_ptr == ring->nitem)
1062e5ec1e72Spatrick 		ring->w_ptr = 0;
1063e5ec1e72Spatrick 	return ret;
1064e5ec1e72Spatrick }
1065e5ec1e72Spatrick 
1066e5ec1e72Spatrick void *
1067e5ec1e72Spatrick bwfm_pci_ring_write_reserve_multi(struct bwfm_pci_softc *sc,
1068e5ec1e72Spatrick     struct bwfm_pci_msgring *ring, int count, int *avail)
1069e5ec1e72Spatrick {
1070e5ec1e72Spatrick 	int available;
1071e5ec1e72Spatrick 	char *ret;
1072e5ec1e72Spatrick 
1073e5ec1e72Spatrick 	bwfm_pci_ring_update_rptr(sc, ring);
1074e5ec1e72Spatrick 
1075e5ec1e72Spatrick 	if (ring->r_ptr > ring->w_ptr)
1076e5ec1e72Spatrick 		available = ring->r_ptr - ring->w_ptr;
1077e5ec1e72Spatrick 	else
1078e5ec1e72Spatrick 		available = ring->r_ptr + (ring->nitem - ring->w_ptr);
1079e5ec1e72Spatrick 
1080e5ec1e72Spatrick 	if (available < 1)
1081e5ec1e72Spatrick 		return NULL;
1082e5ec1e72Spatrick 
1083e5ec1e72Spatrick 	ret = BWFM_PCI_DMA_KVA(ring->ring) + (ring->w_ptr * ring->itemsz);
1084e5ec1e72Spatrick 	*avail = min(count, available - 1);
1085e5ec1e72Spatrick 	if (*avail + ring->w_ptr > ring->nitem)
1086e5ec1e72Spatrick 		*avail = ring->nitem - ring->w_ptr;
1087e5ec1e72Spatrick 	ring->w_ptr += *avail;
1088e5ec1e72Spatrick 	if (ring->w_ptr == ring->nitem)
1089e5ec1e72Spatrick 		ring->w_ptr = 0;
1090e5ec1e72Spatrick 	return ret;
1091e5ec1e72Spatrick }
1092e5ec1e72Spatrick 
1093e5ec1e72Spatrick /*
1094e5ec1e72Spatrick  * Read number of descriptors available (submitted by the firmware)
1095e5ec1e72Spatrick  * and retrieve pointer to first descriptor.
1096e5ec1e72Spatrick  */
1097e5ec1e72Spatrick void *
1098e5ec1e72Spatrick bwfm_pci_ring_read_avail(struct bwfm_pci_softc *sc,
1099e5ec1e72Spatrick     struct bwfm_pci_msgring *ring, int *avail)
1100e5ec1e72Spatrick {
1101e5ec1e72Spatrick 	bwfm_pci_ring_update_wptr(sc, ring);
1102e5ec1e72Spatrick 
1103e5ec1e72Spatrick 	if (ring->w_ptr >= ring->r_ptr)
1104e5ec1e72Spatrick 		*avail = ring->w_ptr - ring->r_ptr;
1105e5ec1e72Spatrick 	else
1106e5ec1e72Spatrick 		*avail = ring->nitem - ring->r_ptr;
1107e5ec1e72Spatrick 
1108e5ec1e72Spatrick 	if (*avail == 0)
1109e5ec1e72Spatrick 		return NULL;
1110e5ec1e72Spatrick 
1111e5ec1e72Spatrick 	return BWFM_PCI_DMA_KVA(ring->ring) + (ring->r_ptr * ring->itemsz);
1112e5ec1e72Spatrick }
1113e5ec1e72Spatrick 
1114e5ec1e72Spatrick /*
1115e5ec1e72Spatrick  * Let firmware know we read N descriptors.
1116e5ec1e72Spatrick  */
1117e5ec1e72Spatrick void
1118e5ec1e72Spatrick bwfm_pci_ring_read_commit(struct bwfm_pci_softc *sc,
1119e5ec1e72Spatrick     struct bwfm_pci_msgring *ring, int nitem)
1120e5ec1e72Spatrick {
1121e5ec1e72Spatrick 	ring->r_ptr += nitem;
1122e5ec1e72Spatrick 	if (ring->r_ptr == ring->nitem)
1123e5ec1e72Spatrick 		ring->r_ptr = 0;
1124e5ec1e72Spatrick 	bwfm_pci_ring_write_rptr(sc, ring);
1125e5ec1e72Spatrick }
1126e5ec1e72Spatrick 
1127e5ec1e72Spatrick /*
1128e5ec1e72Spatrick  * Let firmware know that we submitted some descriptors.
1129e5ec1e72Spatrick  */
1130e5ec1e72Spatrick void
1131e5ec1e72Spatrick bwfm_pci_ring_write_commit(struct bwfm_pci_softc *sc,
1132e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1133e5ec1e72Spatrick {
1134e5ec1e72Spatrick 	bwfm_pci_ring_write_wptr(sc, ring);
1135e5ec1e72Spatrick 	bwfm_pci_ring_bell(sc, ring);
1136e5ec1e72Spatrick }
1137e5ec1e72Spatrick 
1138e5ec1e72Spatrick /*
1139e5ec1e72Spatrick  * Rollback N descriptors in case we don't actually want
1140e5ec1e72Spatrick  * to commit to it.
1141e5ec1e72Spatrick  */
1142e5ec1e72Spatrick void
1143e5ec1e72Spatrick bwfm_pci_ring_write_cancel(struct bwfm_pci_softc *sc,
1144e5ec1e72Spatrick     struct bwfm_pci_msgring *ring, int nitem)
1145e5ec1e72Spatrick {
1146e5ec1e72Spatrick 	if (ring->w_ptr == 0)
1147e5ec1e72Spatrick 		ring->w_ptr = ring->nitem - nitem;
1148e5ec1e72Spatrick 	else
1149e5ec1e72Spatrick 		ring->w_ptr -= nitem;
1150e5ec1e72Spatrick }
1151e5ec1e72Spatrick 
1152e5ec1e72Spatrick /*
1153e5ec1e72Spatrick  * Foreach written descriptor on the ring, pass the descriptor to
1154e5ec1e72Spatrick  * a message handler and let the firmware know we handled it.
1155e5ec1e72Spatrick  */
1156e5ec1e72Spatrick void
1157e5ec1e72Spatrick bwfm_pci_ring_rx(struct bwfm_pci_softc *sc, struct bwfm_pci_msgring *ring)
1158e5ec1e72Spatrick {
1159e5ec1e72Spatrick 	void *buf;
1160e5ec1e72Spatrick 	int avail, processed;
1161e5ec1e72Spatrick 
1162e5ec1e72Spatrick again:
1163e5ec1e72Spatrick 	buf = bwfm_pci_ring_read_avail(sc, ring, &avail);
1164e5ec1e72Spatrick 	if (buf == NULL)
1165e5ec1e72Spatrick 		return;
1166e5ec1e72Spatrick 
1167e5ec1e72Spatrick 	processed = 0;
1168e5ec1e72Spatrick 	while (avail) {
1169e5ec1e72Spatrick 		bwfm_pci_msg_rx(sc, buf + sc->sc_rx_dataoffset);
1170e5ec1e72Spatrick 		buf += ring->itemsz;
1171e5ec1e72Spatrick 		processed++;
1172e5ec1e72Spatrick 		if (processed == 48) {
1173e5ec1e72Spatrick 			bwfm_pci_ring_read_commit(sc, ring, processed);
1174e5ec1e72Spatrick 			processed = 0;
1175e5ec1e72Spatrick 		}
1176e5ec1e72Spatrick 		avail--;
1177e5ec1e72Spatrick 	}
1178e5ec1e72Spatrick 	if (processed)
1179e5ec1e72Spatrick 		bwfm_pci_ring_read_commit(sc, ring, processed);
1180e5ec1e72Spatrick 	if (ring->r_ptr == 0)
1181e5ec1e72Spatrick 		goto again;
1182e5ec1e72Spatrick }
1183e5ec1e72Spatrick 
1184e5ec1e72Spatrick void
1185e5ec1e72Spatrick bwfm_pci_msg_rx(struct bwfm_pci_softc *sc, void *buf)
1186e5ec1e72Spatrick {
1187518be5f3Spatrick 	struct ifnet *ifp = &sc->sc_sc.sc_ic.ic_if;
1188e5ec1e72Spatrick 	struct msgbuf_ioctl_resp_hdr *resp;
1189518be5f3Spatrick 	struct msgbuf_tx_status *tx;
119018722113Spatrick 	struct msgbuf_rx_complete *rx;
1191e5ec1e72Spatrick 	struct msgbuf_rx_event *event;
1192e5ec1e72Spatrick 	struct msgbuf_common_hdr *msg;
1193518be5f3Spatrick 	struct msgbuf_flowring_create_resp *fcr;
1194a2c6ff8bSpatrick 	struct msgbuf_flowring_delete_resp *fdr;
1195518be5f3Spatrick 	struct bwfm_pci_msgring *ring;
1196e5ec1e72Spatrick 	struct mbuf *m;
1197518be5f3Spatrick 	int flowid;
1198e5ec1e72Spatrick 
1199e5ec1e72Spatrick 	msg = (struct msgbuf_common_hdr *)buf;
1200e5ec1e72Spatrick 	switch (msg->msgtype)
1201e5ec1e72Spatrick 	{
1202518be5f3Spatrick 	case MSGBUF_TYPE_FLOW_RING_CREATE_CMPLT:
1203518be5f3Spatrick 		fcr = (struct msgbuf_flowring_create_resp *)buf;
1204518be5f3Spatrick 		flowid = letoh16(fcr->compl_hdr.flow_ring_id);
1205518be5f3Spatrick 		if (flowid < 2)
1206518be5f3Spatrick 			break;
1207518be5f3Spatrick 		flowid -= 2;
1208518be5f3Spatrick 		if (flowid >= sc->sc_max_flowrings)
1209518be5f3Spatrick 			break;
1210518be5f3Spatrick 		ring = &sc->sc_flowrings[flowid];
1211518be5f3Spatrick 		if (ring->status != RING_OPENING)
1212518be5f3Spatrick 			break;
1213518be5f3Spatrick 		if (fcr->compl_hdr.status) {
1214518be5f3Spatrick 			printf("%s: failed to open flowring %d\n",
1215518be5f3Spatrick 			    DEVNAME(sc), flowid);
1216518be5f3Spatrick 			ring->status = RING_CLOSED;
1217518be5f3Spatrick 			ifq_restart(&ifp->if_snd);
1218518be5f3Spatrick 			break;
1219518be5f3Spatrick 		}
1220518be5f3Spatrick 		ring->status = RING_OPEN;
1221518be5f3Spatrick 		ifq_restart(&ifp->if_snd);
1222518be5f3Spatrick 		break;
1223a2c6ff8bSpatrick 	case MSGBUF_TYPE_FLOW_RING_DELETE_CMPLT:
1224a2c6ff8bSpatrick 		fdr = (struct msgbuf_flowring_delete_resp *)buf;
1225a2c6ff8bSpatrick 		flowid = letoh16(fdr->compl_hdr.flow_ring_id);
1226a2c6ff8bSpatrick 		if (flowid < 2)
1227a2c6ff8bSpatrick 			break;
1228a2c6ff8bSpatrick 		flowid -= 2;
1229a2c6ff8bSpatrick 		if (flowid >= sc->sc_max_flowrings)
1230a2c6ff8bSpatrick 			break;
1231a2c6ff8bSpatrick 		ring = &sc->sc_flowrings[flowid];
1232a2c6ff8bSpatrick 		if (ring->status != RING_CLOSING)
1233a2c6ff8bSpatrick 			break;
1234a2c6ff8bSpatrick 		if (fdr->compl_hdr.status) {
1235a2c6ff8bSpatrick 			printf("%s: failed to delete flowring %d\n",
1236a2c6ff8bSpatrick 			    DEVNAME(sc), flowid);
1237a2c6ff8bSpatrick 			break;
1238a2c6ff8bSpatrick 		}
1239a2c6ff8bSpatrick 		bwfm_pci_dmamem_free(sc, ring->ring);
1240a2c6ff8bSpatrick 		ring->status = RING_CLOSED;
1241a2c6ff8bSpatrick 		break;
1242e5ec1e72Spatrick 	case MSGBUF_TYPE_IOCTLPTR_REQ_ACK:
1243e5ec1e72Spatrick 		break;
1244e5ec1e72Spatrick 	case MSGBUF_TYPE_IOCTL_CMPLT:
1245e5ec1e72Spatrick 		resp = (struct msgbuf_ioctl_resp_hdr *)buf;
1246e5ec1e72Spatrick 		sc->sc_ioctl_resp_pktid = letoh32(resp->msg.request_id);
1247e5ec1e72Spatrick 		sc->sc_ioctl_resp_ret_len = letoh16(resp->resp_len);
1248e5ec1e72Spatrick 		sc->sc_ioctl_resp_status = letoh16(resp->compl_hdr.status);
1249e5ec1e72Spatrick 		if_rxr_put(&sc->sc_ioctl_ring, 1);
1250e5ec1e72Spatrick 		bwfm_pci_fill_rx_rings(sc);
1251e5ec1e72Spatrick 		wakeup(&sc->sc_ioctl_buf);
1252e5ec1e72Spatrick 		break;
1253e5ec1e72Spatrick 	case MSGBUF_TYPE_WL_EVENT:
1254e5ec1e72Spatrick 		event = (struct msgbuf_rx_event *)buf;
1255e5ec1e72Spatrick 		m = bwfm_pci_pktid_free(sc, &sc->sc_rx_pkts,
1256e5ec1e72Spatrick 		    letoh32(event->msg.request_id));
1257e5ec1e72Spatrick 		if (m == NULL)
1258e5ec1e72Spatrick 			break;
1259e5ec1e72Spatrick 		m_adj(m, sc->sc_rx_dataoffset);
1260f37fc236Spatrick 		m->m_len = m->m_pkthdr.len = letoh16(event->event_data_len);
1261f37fc236Spatrick 		bwfm_rx(&sc->sc_sc, m);
1262e5ec1e72Spatrick 		if_rxr_put(&sc->sc_event_ring, 1);
1263e5ec1e72Spatrick 		bwfm_pci_fill_rx_rings(sc);
1264e5ec1e72Spatrick 		break;
1265518be5f3Spatrick 	case MSGBUF_TYPE_TX_STATUS:
1266518be5f3Spatrick 		tx = (struct msgbuf_tx_status *)buf;
1267518be5f3Spatrick 		m = bwfm_pci_pktid_free(sc, &sc->sc_tx_pkts,
1268518be5f3Spatrick 		    letoh32(tx->msg.request_id));
1269518be5f3Spatrick 		if (m == NULL)
1270518be5f3Spatrick 			break;
1271518be5f3Spatrick 		m_freem(m);
1272518be5f3Spatrick 		break;
127318722113Spatrick 	case MSGBUF_TYPE_RX_CMPLT:
127418722113Spatrick 		rx = (struct msgbuf_rx_complete *)buf;
127518722113Spatrick 		m = bwfm_pci_pktid_free(sc, &sc->sc_rx_pkts,
127618722113Spatrick 		    letoh32(rx->msg.request_id));
127718722113Spatrick 		if (m == NULL)
127818722113Spatrick 			break;
127918722113Spatrick 		if (letoh16(rx->data_offset))
128018722113Spatrick 			m_adj(m, letoh16(rx->data_offset));
128118722113Spatrick 		else if (sc->sc_rx_dataoffset)
128218722113Spatrick 			m_adj(m, sc->sc_rx_dataoffset);
1283f37fc236Spatrick 		m->m_len = m->m_pkthdr.len = letoh16(rx->data_len);
1284f37fc236Spatrick 		bwfm_rx(&sc->sc_sc, m);
128518722113Spatrick 		if_rxr_put(&sc->sc_rxbuf_ring, 1);
128618722113Spatrick 		bwfm_pci_fill_rx_rings(sc);
128718722113Spatrick 		break;
1288e5ec1e72Spatrick 	default:
1289e5ec1e72Spatrick 		printf("%s: msgtype 0x%08x\n", __func__, msg->msgtype);
1290e5ec1e72Spatrick 		break;
1291e5ec1e72Spatrick 	}
1292e5ec1e72Spatrick }
1293e5ec1e72Spatrick 
1294e5ec1e72Spatrick /* Bus core helpers */
1295e5ec1e72Spatrick void
1296e5ec1e72Spatrick bwfm_pci_select_core(struct bwfm_pci_softc *sc, int id)
1297e5ec1e72Spatrick {
1298e5ec1e72Spatrick 	struct bwfm_softc *bwfm = (void *)sc;
1299e5ec1e72Spatrick 	struct bwfm_core *core;
1300e5ec1e72Spatrick 
1301e5ec1e72Spatrick 	core = bwfm_chip_get_core(bwfm, id);
1302e5ec1e72Spatrick 	if (core == NULL) {
1303e5ec1e72Spatrick 		printf("%s: could not find core to select", DEVNAME(sc));
1304e5ec1e72Spatrick 		return;
1305e5ec1e72Spatrick 	}
1306e5ec1e72Spatrick 
1307e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag,
1308e5ec1e72Spatrick 	    BWFM_PCI_BAR0_WINDOW, core->co_base);
1309e5ec1e72Spatrick 	if (pci_conf_read(sc->sc_pc, sc->sc_tag,
1310e5ec1e72Spatrick 	    BWFM_PCI_BAR0_WINDOW) != core->co_base)
1311e5ec1e72Spatrick 		pci_conf_write(sc->sc_pc, sc->sc_tag,
1312e5ec1e72Spatrick 		    BWFM_PCI_BAR0_WINDOW, core->co_base);
1313e5ec1e72Spatrick }
1314e5ec1e72Spatrick 
1315e5ec1e72Spatrick uint32_t
1316e5ec1e72Spatrick bwfm_pci_buscore_read(struct bwfm_softc *bwfm, uint32_t reg)
1317e5ec1e72Spatrick {
1318e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1319e5ec1e72Spatrick 	uint32_t page, offset;
1320e5ec1e72Spatrick 
1321e5ec1e72Spatrick 	page = reg & ~(BWFM_PCI_BAR0_REG_SIZE - 1);
1322e5ec1e72Spatrick 	offset = reg & (BWFM_PCI_BAR0_REG_SIZE - 1);
1323e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_BAR0_WINDOW, page);
1324e5ec1e72Spatrick 	return bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh, offset);
1325e5ec1e72Spatrick }
1326e5ec1e72Spatrick 
1327e5ec1e72Spatrick void
1328e5ec1e72Spatrick bwfm_pci_buscore_write(struct bwfm_softc *bwfm, uint32_t reg, uint32_t val)
1329e5ec1e72Spatrick {
1330e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1331e5ec1e72Spatrick 	uint32_t page, offset;
1332e5ec1e72Spatrick 
1333e5ec1e72Spatrick 	page = reg & ~(BWFM_PCI_BAR0_REG_SIZE - 1);
1334e5ec1e72Spatrick 	offset = reg & (BWFM_PCI_BAR0_REG_SIZE - 1);
1335e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_BAR0_WINDOW, page);
1336e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, offset, val);
1337e5ec1e72Spatrick }
1338e5ec1e72Spatrick 
1339e5ec1e72Spatrick int
1340e5ec1e72Spatrick bwfm_pci_buscore_prepare(struct bwfm_softc *bwfm)
1341e5ec1e72Spatrick {
1342e5ec1e72Spatrick 	return 0;
1343e5ec1e72Spatrick }
1344e5ec1e72Spatrick 
1345e5ec1e72Spatrick int
1346e5ec1e72Spatrick bwfm_pci_buscore_reset(struct bwfm_softc *bwfm)
1347e5ec1e72Spatrick {
1348e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1349e5ec1e72Spatrick 	struct bwfm_core *core;
1350e5ec1e72Spatrick 	uint32_t reg;
1351e5ec1e72Spatrick 	int i;
1352e5ec1e72Spatrick 
1353e5ec1e72Spatrick 	bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2);
1354e5ec1e72Spatrick 	reg = pci_conf_read(sc->sc_pc, sc->sc_tag,
1355e5ec1e72Spatrick 	    BWFM_PCI_CFGREG_LINK_STATUS_CTRL);
1356e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_CFGREG_LINK_STATUS_CTRL,
1357e5ec1e72Spatrick 	    reg & ~BWFM_PCI_CFGREG_LINK_STATUS_CTRL_ASPM_ENAB);
1358e5ec1e72Spatrick 
1359e5ec1e72Spatrick 	bwfm_pci_select_core(sc, BWFM_AGENT_CORE_CHIPCOMMON);
1360e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1361e5ec1e72Spatrick 	    BWFM_CHIP_REG_WATCHDOG, 4);
1362e5ec1e72Spatrick 	delay(100 * 1000);
1363e5ec1e72Spatrick 
1364e5ec1e72Spatrick 	bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2);
1365e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag,
1366e5ec1e72Spatrick 	    BWFM_PCI_CFGREG_LINK_STATUS_CTRL, reg);
1367e5ec1e72Spatrick 
1368e5ec1e72Spatrick 	core = bwfm_chip_get_core(bwfm, BWFM_AGENT_CORE_PCIE2);
1369e5ec1e72Spatrick 	if (core->co_rev <= 13) {
1370e5ec1e72Spatrick 		uint16_t cfg_offset[] = {
1371e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_STATUS_CMD,
1372e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_PM_CSR,
1373e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_MSI_CAP,
1374e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_MSI_ADDR_L,
1375e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_MSI_ADDR_H,
1376e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_MSI_DATA,
1377e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_LINK_STATUS_CTRL2,
1378e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_RBAR_CTRL,
1379e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_PML1_SUB_CTRL1,
1380e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_REG_BAR2_CONFIG,
1381e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_REG_BAR3_CONFIG,
1382e5ec1e72Spatrick 		};
1383e5ec1e72Spatrick 
1384e5ec1e72Spatrick 		for (i = 0; i < nitems(cfg_offset); i++) {
1385e5ec1e72Spatrick 			bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1386e5ec1e72Spatrick 			    BWFM_PCI_PCIE2REG_CONFIGADDR, cfg_offset[i]);
1387e5ec1e72Spatrick 			reg = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1388e5ec1e72Spatrick 			    BWFM_PCI_PCIE2REG_CONFIGDATA);
1389e5ec1e72Spatrick 			DPRINTFN(3, ("%s: config offset 0x%04x, value 0x%04x\n",
1390e5ec1e72Spatrick 			    DEVNAME(sc), cfg_offset[i], reg));
1391e5ec1e72Spatrick 			bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1392e5ec1e72Spatrick 			    BWFM_PCI_PCIE2REG_CONFIGDATA, reg);
1393e5ec1e72Spatrick 		}
1394e5ec1e72Spatrick 	}
1395e5ec1e72Spatrick 
1396e5ec1e72Spatrick 	reg = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1397e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXINT);
1398e5ec1e72Spatrick 	if (reg != 0xffffffff)
1399e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1400e5ec1e72Spatrick 		    BWFM_PCI_PCIE2REG_MAILBOXINT, reg);
1401e5ec1e72Spatrick 
1402e5ec1e72Spatrick 	return 0;
1403e5ec1e72Spatrick }
1404e5ec1e72Spatrick 
1405e5ec1e72Spatrick void
1406e5ec1e72Spatrick bwfm_pci_buscore_activate(struct bwfm_softc *bwfm, uint32_t rstvec)
1407e5ec1e72Spatrick {
1408e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1409e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 0, rstvec);
1410e5ec1e72Spatrick }
1411e5ec1e72Spatrick 
1412f67437f3Spatrick static int bwfm_pci_prio2fifo[8] = {
1413f67437f3Spatrick 	1, /* best effort */
1414f67437f3Spatrick 	0, /* IPTOS_PREC_IMMEDIATE */
1415f67437f3Spatrick 	0, /* IPTOS_PREC_PRIORITY */
1416f67437f3Spatrick 	1, /* IPTOS_PREC_FLASH */
1417f67437f3Spatrick 	2, /* IPTOS_PREC_FLASHOVERRIDE */
1418f67437f3Spatrick 	2, /* IPTOS_PREC_CRITIC_ECP */
1419f67437f3Spatrick 	3, /* IPTOS_PREC_INTERNETCONTROL */
1420f67437f3Spatrick 	3, /* IPTOS_PREC_NETCONTROL */
1421f67437f3Spatrick };
1422f67437f3Spatrick 
1423f67437f3Spatrick int
1424f67437f3Spatrick bwfm_pci_flowring_lookup(struct bwfm_pci_softc *sc, struct mbuf *m)
1425518be5f3Spatrick {
1426f67437f3Spatrick 	struct ieee80211com *ic = &sc->sc_sc.sc_ic;
1427f67437f3Spatrick 	uint8_t *da = mtod(m, uint8_t *);
1428f67437f3Spatrick 	int flowid, prio, fifo;
1429f67437f3Spatrick 	int i, found;
1430f67437f3Spatrick 
1431f67437f3Spatrick 	prio = ieee80211_classify(ic, m);
1432f67437f3Spatrick 	fifo = bwfm_pci_prio2fifo[prio];
1433f67437f3Spatrick 
1434f67437f3Spatrick 	switch (ic->ic_opmode)
1435f67437f3Spatrick 	{
1436f67437f3Spatrick 	case IEEE80211_M_STA:
1437f67437f3Spatrick 		flowid = fifo;
1438f67437f3Spatrick 		break;
1439f67437f3Spatrick #ifndef IEEE80211_STA_ONLY
1440f67437f3Spatrick 	case IEEE80211_M_HOSTAP:
1441*2b7bea7eSpatrick 		if (ETHER_IS_MULTICAST(da))
1442*2b7bea7eSpatrick 			da = etherbroadcastaddr;
1443f67437f3Spatrick 		flowid = da[5] * 2 + fifo;
1444f67437f3Spatrick 		break;
1445f67437f3Spatrick #endif
1446f67437f3Spatrick 	default:
1447f67437f3Spatrick 		printf("%s: state not supported\n", DEVNAME(sc));
1448f67437f3Spatrick 		return ENOBUFS;
1449f67437f3Spatrick 	}
1450f67437f3Spatrick 
1451f67437f3Spatrick 	found = 0;
1452f67437f3Spatrick 	flowid = flowid % sc->sc_max_flowrings;
1453f67437f3Spatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
1454f67437f3Spatrick 		if (ic->ic_opmode == IEEE80211_M_STA &&
1455f67437f3Spatrick 		    sc->sc_flowrings[flowid].status >= RING_OPEN &&
1456f67437f3Spatrick 		    sc->sc_flowrings[flowid].fifo == fifo) {
1457f67437f3Spatrick 			found = 1;
1458f67437f3Spatrick 			break;
1459f67437f3Spatrick 		}
1460f67437f3Spatrick #ifndef IEEE80211_STA_ONLY
1461f67437f3Spatrick 		if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
1462f67437f3Spatrick 		    sc->sc_flowrings[flowid].status >= RING_OPEN &&
1463f67437f3Spatrick 		    sc->sc_flowrings[flowid].fifo == fifo &&
1464a2c6ff8bSpatrick 		    !memcmp(sc->sc_flowrings[flowid].mac, da, ETHER_ADDR_LEN)) {
1465f67437f3Spatrick 			found = 1;
1466f67437f3Spatrick 			break;
1467f67437f3Spatrick 		}
1468f67437f3Spatrick #endif
1469f67437f3Spatrick 		flowid = (flowid + 1) % sc->sc_max_flowrings;
1470f67437f3Spatrick 	}
1471f67437f3Spatrick 
1472f67437f3Spatrick 	if (found)
1473f67437f3Spatrick 		return flowid;
1474f67437f3Spatrick 
1475f67437f3Spatrick 	return -1;
1476f67437f3Spatrick }
1477f67437f3Spatrick 
1478f67437f3Spatrick void
1479f67437f3Spatrick bwfm_pci_flowring_create(struct bwfm_pci_softc *sc, struct mbuf *m)
1480f67437f3Spatrick {
1481f67437f3Spatrick 	struct ieee80211com *ic = &sc->sc_sc.sc_ic;
1482518be5f3Spatrick 	struct bwfm_cmd_flowring_create cmd;
1483f67437f3Spatrick 	uint8_t *da = mtod(m, uint8_t *);
1484f67437f3Spatrick 	int flowid, prio, fifo;
1485f67437f3Spatrick 	int i, found;
1486f67437f3Spatrick 
1487f67437f3Spatrick 	prio = ieee80211_classify(ic, m);
1488f67437f3Spatrick 	fifo = bwfm_pci_prio2fifo[prio];
1489f67437f3Spatrick 
1490f67437f3Spatrick 	switch (ic->ic_opmode)
1491f67437f3Spatrick 	{
1492f67437f3Spatrick 	case IEEE80211_M_STA:
1493f67437f3Spatrick 		flowid = fifo;
1494f67437f3Spatrick 		break;
1495f67437f3Spatrick #ifndef IEEE80211_STA_ONLY
1496f67437f3Spatrick 	case IEEE80211_M_HOSTAP:
1497*2b7bea7eSpatrick 		if (ETHER_IS_MULTICAST(da))
1498*2b7bea7eSpatrick 			da = etherbroadcastaddr;
1499f67437f3Spatrick 		flowid = da[5] * 2 + fifo;
1500f67437f3Spatrick 		break;
1501f67437f3Spatrick #endif
1502f67437f3Spatrick 	default:
1503f67437f3Spatrick 		printf("%s: state not supported\n", DEVNAME(sc));
1504f67437f3Spatrick 		return;
1505f67437f3Spatrick 	}
1506f67437f3Spatrick 
1507f67437f3Spatrick 	found = 0;
1508f67437f3Spatrick 	flowid = flowid % sc->sc_max_flowrings;
1509f67437f3Spatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
1510f67437f3Spatrick 		if (sc->sc_flowrings[flowid].status == RING_CLOSED) {
1511f67437f3Spatrick 			found = 1;
1512f67437f3Spatrick 			break;
1513f67437f3Spatrick 		}
1514f67437f3Spatrick 		flowid = (flowid + 1) % sc->sc_max_flowrings;
1515f67437f3Spatrick 	}
1516f67437f3Spatrick 
1517f67437f3Spatrick 	if (!found) {
1518f67437f3Spatrick 		printf("%s: no flowring available\n", DEVNAME(sc));
1519f67437f3Spatrick 		return;
1520f67437f3Spatrick 	}
1521f67437f3Spatrick 
1522f67437f3Spatrick 	cmd.prio = prio;
1523518be5f3Spatrick 	cmd.flowid = flowid;
1524518be5f3Spatrick 	memcpy(cmd.da, mtod(m, char *) + 0 * ETHER_ADDR_LEN, ETHER_ADDR_LEN);
1525518be5f3Spatrick 	memcpy(cmd.sa, mtod(m, char *) + 1 * ETHER_ADDR_LEN, ETHER_ADDR_LEN);
1526518be5f3Spatrick 	bwfm_do_async(&sc->sc_sc, bwfm_pci_flowring_create_cb, &cmd, sizeof(cmd));
1527518be5f3Spatrick }
1528518be5f3Spatrick 
1529518be5f3Spatrick void
1530518be5f3Spatrick bwfm_pci_flowring_create_cb(struct bwfm_softc *bwfm, void *arg)
1531518be5f3Spatrick {
1532518be5f3Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1533*2b7bea7eSpatrick 	struct ieee80211com *ic = &sc->sc_sc.sc_ic;
1534518be5f3Spatrick 	struct bwfm_cmd_flowring_create *cmd = arg;
1535518be5f3Spatrick 	struct msgbuf_tx_flowring_create_req *req;
1536518be5f3Spatrick 	struct bwfm_pci_msgring *ring;
1537f67437f3Spatrick 	int flowid, prio;
1538518be5f3Spatrick 
1539518be5f3Spatrick 	flowid = cmd->flowid;
1540f67437f3Spatrick 	prio = cmd->prio;
1541518be5f3Spatrick 
1542f67437f3Spatrick 	ring = &sc->sc_flowrings[flowid];
1543f67437f3Spatrick 	if (ring->status != RING_CLOSED) {
1544f67437f3Spatrick 		printf("%s: flowring not closed\n", DEVNAME(sc));
1545518be5f3Spatrick 		return;
1546f67437f3Spatrick 	}
1547f67437f3Spatrick 
1548f67437f3Spatrick 	if (bwfm_pci_setup_flowring(sc, ring, 512, 48)) {
1549f67437f3Spatrick 		printf("%s: cannot setup flowring\n", DEVNAME(sc));
1550f67437f3Spatrick 		return;
1551f67437f3Spatrick 	}
1552518be5f3Spatrick 
1553518be5f3Spatrick 	req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit);
1554f67437f3Spatrick 	if (req == NULL) {
1555f67437f3Spatrick 		printf("%s: cannot reserve for flowring\n", DEVNAME(sc));
1556518be5f3Spatrick 		return;
1557f67437f3Spatrick 	}
1558518be5f3Spatrick 
1559518be5f3Spatrick 	ring->status = RING_OPENING;
1560f67437f3Spatrick 	ring->fifo = bwfm_pci_prio2fifo[prio];
1561f67437f3Spatrick 	memcpy(ring->mac, cmd->da, ETHER_ADDR_LEN);
1562*2b7bea7eSpatrick #ifndef IEEE80211_STA_ONLY
1563*2b7bea7eSpatrick 	if (ic->ic_opmode == IEEE80211_M_HOSTAP && ETHER_IS_MULTICAST(cmd->da))
1564*2b7bea7eSpatrick 		memcpy(ring->mac, etherbroadcastaddr, ETHER_ADDR_LEN);
1565*2b7bea7eSpatrick #endif
1566f67437f3Spatrick 
1567518be5f3Spatrick 	req->msg.msgtype = MSGBUF_TYPE_FLOW_RING_CREATE;
1568518be5f3Spatrick 	req->msg.ifidx = 0;
1569518be5f3Spatrick 	req->msg.request_id = 0;
1570f67437f3Spatrick 	req->tid = bwfm_pci_prio2fifo[prio];
1571518be5f3Spatrick 	req->flow_ring_id = letoh16(flowid + 2);
1572518be5f3Spatrick 	memcpy(req->da, cmd->da, ETHER_ADDR_LEN);
1573518be5f3Spatrick 	memcpy(req->sa, cmd->sa, ETHER_ADDR_LEN);
1574518be5f3Spatrick 	req->flow_ring_addr.high_addr =
1575518be5f3Spatrick 	    letoh32(BWFM_PCI_DMA_DVA(ring->ring) >> 32);
1576518be5f3Spatrick 	req->flow_ring_addr.low_addr =
1577518be5f3Spatrick 	    letoh32(BWFM_PCI_DMA_DVA(ring->ring) & 0xffffffff);
1578518be5f3Spatrick 	req->max_items = letoh16(512);
1579518be5f3Spatrick 	req->len_item = letoh16(48);
1580518be5f3Spatrick 
1581518be5f3Spatrick 	bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit);
1582518be5f3Spatrick }
1583518be5f3Spatrick 
1584a2c6ff8bSpatrick void
1585a2c6ff8bSpatrick bwfm_pci_flowring_delete(struct bwfm_pci_softc *sc, int flowid)
1586a2c6ff8bSpatrick {
1587a2c6ff8bSpatrick 	struct msgbuf_tx_flowring_delete_req *req;
1588a2c6ff8bSpatrick 	struct bwfm_pci_msgring *ring;
1589a2c6ff8bSpatrick 
1590a2c6ff8bSpatrick 	ring = &sc->sc_flowrings[flowid];
1591a2c6ff8bSpatrick 	if (ring->status != RING_OPEN) {
1592a2c6ff8bSpatrick 		printf("%s: flowring not open\n", DEVNAME(sc));
1593a2c6ff8bSpatrick 		return;
1594a2c6ff8bSpatrick 	}
1595a2c6ff8bSpatrick 
1596a2c6ff8bSpatrick 	req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit);
1597a2c6ff8bSpatrick 	if (req == NULL) {
1598a2c6ff8bSpatrick 		printf("%s: cannot reserve for flowring\n", DEVNAME(sc));
1599a2c6ff8bSpatrick 		return;
1600a2c6ff8bSpatrick 	}
1601a2c6ff8bSpatrick 
1602a2c6ff8bSpatrick 	ring->status = RING_CLOSING;
1603a2c6ff8bSpatrick 
1604a2c6ff8bSpatrick 	req->msg.msgtype = MSGBUF_TYPE_FLOW_RING_DELETE;
1605a2c6ff8bSpatrick 	req->msg.ifidx = 0;
1606a2c6ff8bSpatrick 	req->msg.request_id = 0;
1607a2c6ff8bSpatrick 	req->flow_ring_id = letoh16(flowid + 2);
1608a2c6ff8bSpatrick 	req->reason = 0;
1609a2c6ff8bSpatrick 
1610a2c6ff8bSpatrick 	bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit);
1611a2c6ff8bSpatrick }
1612a2c6ff8bSpatrick 
1613a2c6ff8bSpatrick void
1614a2c6ff8bSpatrick bwfm_pci_stop(struct bwfm_softc *bwfm)
1615a2c6ff8bSpatrick {
1616a2c6ff8bSpatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1617a2c6ff8bSpatrick 	struct bwfm_pci_msgring *ring;
1618a2c6ff8bSpatrick 	int i;
1619a2c6ff8bSpatrick 
1620a2c6ff8bSpatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
1621a2c6ff8bSpatrick 		ring = &sc->sc_flowrings[i];
1622a2c6ff8bSpatrick 		if (ring->status == RING_OPEN)
1623a2c6ff8bSpatrick 			bwfm_pci_flowring_delete(sc, i);
1624a2c6ff8bSpatrick 	}
1625a2c6ff8bSpatrick }
1626a2c6ff8bSpatrick 
1627e5ec1e72Spatrick int
1628e5ec1e72Spatrick bwfm_pci_txdata(struct bwfm_softc *bwfm, struct mbuf *m)
1629e5ec1e72Spatrick {
1630e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1631518be5f3Spatrick 	struct bwfm_pci_msgring *ring;
1632518be5f3Spatrick 	struct msgbuf_tx_msghdr *tx;
1633518be5f3Spatrick 	uint32_t pktid;
1634518be5f3Spatrick 	paddr_t paddr;
1635518be5f3Spatrick 	int flowid, ret;
1636518be5f3Spatrick 
1637f67437f3Spatrick 	flowid = bwfm_pci_flowring_lookup(sc, m);
1638f67437f3Spatrick 	if (flowid < 0) {
1639f67437f3Spatrick 		bwfm_pci_flowring_create(sc, m);
1640f67437f3Spatrick 		return ENOBUFS;
1641f67437f3Spatrick 	}
1642518be5f3Spatrick 
1643518be5f3Spatrick 	ring = &sc->sc_flowrings[flowid];
1644518be5f3Spatrick 	if (ring->status == RING_OPENING ||
1645f67437f3Spatrick 	    ring->status == RING_CLOSING) {
1646f67437f3Spatrick 		printf("%s: tried to use a flow that was "
1647f67437f3Spatrick 		    "transitioning in status %d\n",
1648f67437f3Spatrick 		    DEVNAME(sc), ring->status);
1649518be5f3Spatrick 		return ENOBUFS;
1650518be5f3Spatrick 	}
1651518be5f3Spatrick 
1652518be5f3Spatrick 	tx = bwfm_pci_ring_write_reserve(sc, ring);
1653518be5f3Spatrick 	if (tx == NULL)
1654518be5f3Spatrick 		return ENOBUFS;
1655518be5f3Spatrick 
1656518be5f3Spatrick 	memset(tx, 0, sizeof(*tx));
1657518be5f3Spatrick 	tx->msg.msgtype = MSGBUF_TYPE_TX_POST;
1658518be5f3Spatrick 	tx->msg.ifidx = 0;
1659518be5f3Spatrick 	tx->flags = BWFM_MSGBUF_PKT_FLAGS_FRAME_802_3;
1660518be5f3Spatrick 	tx->flags |= ieee80211_classify(&sc->sc_sc.sc_ic, m) <<
1661518be5f3Spatrick 	    BWFM_MSGBUF_PKT_FLAGS_PRIO_SHIFT;
1662518be5f3Spatrick 	tx->seg_cnt = 1;
1663518be5f3Spatrick 	memcpy(tx->txhdr, mtod(m, char *), ETHER_HDR_LEN);
1664518be5f3Spatrick 
1665518be5f3Spatrick 	ret = bwfm_pci_pktid_new(sc, &sc->sc_tx_pkts, m, &pktid, &paddr);
1666518be5f3Spatrick 	if (ret) {
1667518be5f3Spatrick 		bwfm_pci_ring_write_cancel(sc, ring, 1);
1668518be5f3Spatrick 		return ret;
1669518be5f3Spatrick 	}
1670518be5f3Spatrick 	paddr += ETHER_HDR_LEN;
1671518be5f3Spatrick 
1672518be5f3Spatrick 	tx->msg.request_id = htole32(pktid);
16734ff787bcSpatrick 	tx->data_len = htole16(m->m_len - ETHER_HDR_LEN);
1674518be5f3Spatrick 	tx->data_buf_addr.high_addr = htole32(paddr >> 32);
1675518be5f3Spatrick 	tx->data_buf_addr.low_addr = htole32(paddr & 0xffffffff);
1676518be5f3Spatrick 
1677518be5f3Spatrick 	bwfm_pci_ring_write_commit(sc, ring);
1678518be5f3Spatrick 	return 0;
1679e5ec1e72Spatrick }
1680e5ec1e72Spatrick 
1681bbd71b0bSpatrick #ifdef BWFM_DEBUG
1682cadf5fcfSpatrick void
1683cadf5fcfSpatrick bwfm_pci_debug_console(struct bwfm_pci_softc *sc)
1684cadf5fcfSpatrick {
1685cadf5fcfSpatrick 	uint32_t newidx = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1686cadf5fcfSpatrick 	    sc->sc_console_base_addr + BWFM_CONSOLE_WRITEIDX);
1687cadf5fcfSpatrick 
1688cadf5fcfSpatrick 	if (newidx != sc->sc_console_readidx)
1689bbd71b0bSpatrick 		DPRINTFN(3, ("BWFM CONSOLE: "));
1690cadf5fcfSpatrick 	while (newidx != sc->sc_console_readidx) {
1691cadf5fcfSpatrick 		uint8_t ch = bus_space_read_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1692cadf5fcfSpatrick 		    sc->sc_console_buf_addr + sc->sc_console_readidx);
1693cadf5fcfSpatrick 		sc->sc_console_readidx++;
1694cadf5fcfSpatrick 		if (sc->sc_console_readidx == sc->sc_console_buf_size)
1695cadf5fcfSpatrick 			sc->sc_console_readidx = 0;
1696cadf5fcfSpatrick 		if (ch == '\r')
1697cadf5fcfSpatrick 			continue;
1698bbd71b0bSpatrick 		DPRINTFN(3, ("%c", ch));
1699cadf5fcfSpatrick 	}
1700cadf5fcfSpatrick }
1701bbd71b0bSpatrick #endif
1702cadf5fcfSpatrick 
1703e5ec1e72Spatrick int
1704e5ec1e72Spatrick bwfm_pci_intr(void *v)
1705e5ec1e72Spatrick {
1706e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)v;
1707e5ec1e72Spatrick 	uint32_t status;
1708e5ec1e72Spatrick 
1709e5ec1e72Spatrick 	if ((status = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1710e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXINT)) == 0)
1711e5ec1e72Spatrick 		return 0;
1712e5ec1e72Spatrick 
1713e5ec1e72Spatrick 	bwfm_pci_intr_disable(sc);
1714e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1715e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXINT, status);
1716e5ec1e72Spatrick 
1717e5ec1e72Spatrick 	if (status & (BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_0 |
1718e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_1))
1719e5ec1e72Spatrick 		printf("%s: handle MB data\n", __func__);
1720e5ec1e72Spatrick 
1721e5ec1e72Spatrick 	if (status & BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_D2H_DB) {
1722518be5f3Spatrick 		bwfm_pci_ring_rx(sc, &sc->sc_rx_complete);
1723*2b7bea7eSpatrick 		bwfm_pci_ring_rx(sc, &sc->sc_tx_complete);
1724*2b7bea7eSpatrick 		bwfm_pci_ring_rx(sc, &sc->sc_ctrl_complete);
1725e5ec1e72Spatrick 	}
1726e5ec1e72Spatrick 
1727cadf5fcfSpatrick #ifdef BWFM_DEBUG
1728cadf5fcfSpatrick 	bwfm_pci_debug_console(sc);
1729e5ec1e72Spatrick #endif
1730e5ec1e72Spatrick 
1731e5ec1e72Spatrick 	bwfm_pci_intr_enable(sc);
1732e5ec1e72Spatrick 	return 1;
1733e5ec1e72Spatrick }
1734e5ec1e72Spatrick 
1735e5ec1e72Spatrick void
1736e5ec1e72Spatrick bwfm_pci_intr_enable(struct bwfm_pci_softc *sc)
1737e5ec1e72Spatrick {
1738e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1739e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXMASK,
1740e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_0 |
1741e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_1 |
1742e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_D2H_DB);
1743e5ec1e72Spatrick }
1744e5ec1e72Spatrick 
1745e5ec1e72Spatrick void
1746e5ec1e72Spatrick bwfm_pci_intr_disable(struct bwfm_pci_softc *sc)
1747e5ec1e72Spatrick {
1748e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1749e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXMASK, 0);
1750e5ec1e72Spatrick }
1751e5ec1e72Spatrick 
1752e5ec1e72Spatrick /* Msgbuf protocol implementation */
1753e5ec1e72Spatrick int
1754e5ec1e72Spatrick bwfm_pci_msgbuf_query_dcmd(struct bwfm_softc *bwfm, int ifidx,
1755e5ec1e72Spatrick     int cmd, char *buf, size_t *len)
1756e5ec1e72Spatrick {
1757e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1758e5ec1e72Spatrick 	struct msgbuf_ioctl_req_hdr *req;
1759e5ec1e72Spatrick 	struct mbuf *m;
1760e5ec1e72Spatrick 	size_t buflen;
1761e5ec1e72Spatrick 	int s;
1762e5ec1e72Spatrick 
1763e5ec1e72Spatrick 	s = splnet();
1764e5ec1e72Spatrick 	sc->sc_ioctl_resp_pktid = -1;
1765e5ec1e72Spatrick 	req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit);
1766e5ec1e72Spatrick 	if (req == NULL) {
1767e5ec1e72Spatrick 		printf("%s: cannot reserve for write\n", DEVNAME(sc));
1768e5ec1e72Spatrick 		splx(s);
1769e5ec1e72Spatrick 		return 1;
1770e5ec1e72Spatrick 	}
1771e5ec1e72Spatrick 	req->msg.msgtype = MSGBUF_TYPE_IOCTLPTR_REQ;
1772e5ec1e72Spatrick 	req->msg.ifidx = 0;
1773e5ec1e72Spatrick 	req->msg.flags = 0;
1774e5ec1e72Spatrick 	req->msg.request_id = htole32(MSGBUF_IOCTL_REQ_PKTID);
1775e5ec1e72Spatrick 	req->cmd = htole32(cmd);
1776e5ec1e72Spatrick 	req->output_buf_len = htole16(*len);
1777e5ec1e72Spatrick 	req->trans_id = htole16(sc->sc_ioctl_reqid++);
1778e5ec1e72Spatrick 
1779e5ec1e72Spatrick 	buflen = min(*len, BWFM_DMA_H2D_IOCTL_BUF_LEN);
1780e5ec1e72Spatrick 	req->input_buf_len = htole16(buflen);
1781e5ec1e72Spatrick 	req->req_buf_addr.high_addr =
1782e5ec1e72Spatrick 	    htole32((uint64_t)BWFM_PCI_DMA_DVA(sc->sc_ioctl_buf) >> 32);
1783e5ec1e72Spatrick 	req->req_buf_addr.low_addr =
1784e5ec1e72Spatrick 	    htole32((uint64_t)BWFM_PCI_DMA_DVA(sc->sc_ioctl_buf) & 0xffffffff);
1785e5ec1e72Spatrick 	if (buf)
1786e5ec1e72Spatrick 		memcpy(BWFM_PCI_DMA_KVA(sc->sc_ioctl_buf), buf, buflen);
1787e5ec1e72Spatrick 	else
1788e5ec1e72Spatrick 		memset(BWFM_PCI_DMA_KVA(sc->sc_ioctl_buf), 0, buflen);
1789e5ec1e72Spatrick 
1790e5ec1e72Spatrick 	bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit);
1791e5ec1e72Spatrick 	splx(s);
1792e5ec1e72Spatrick 
1793e5ec1e72Spatrick 	if (sc->sc_ioctl_poll) {
1794e5ec1e72Spatrick 		int i;
1795e5ec1e72Spatrick 		for (i = 0; i < 100; i++) {
1796e5ec1e72Spatrick 			if (sc->sc_ioctl_resp_pktid != -1)
1797e5ec1e72Spatrick 				break;
1798e5ec1e72Spatrick 			delay(10 * 1000);
1799e5ec1e72Spatrick 		}
1800e5ec1e72Spatrick 		if (i == 100) {
1801e5ec1e72Spatrick 			printf("%s: timeout waiting for ioctl response\n",
1802e5ec1e72Spatrick 			    DEVNAME(sc));
1803e5ec1e72Spatrick 			return 1;
1804e5ec1e72Spatrick 		}
1805e5ec1e72Spatrick 	} else if (tsleep(&sc->sc_ioctl_buf, PCATCH, "bwfm", hz)) {
1806e5ec1e72Spatrick 		printf("%s: timeout waiting for ioctl response\n",
1807e5ec1e72Spatrick 		    DEVNAME(sc));
1808e5ec1e72Spatrick 		return 1;
1809e5ec1e72Spatrick 	}
1810e5ec1e72Spatrick 
1811e5ec1e72Spatrick 	m = bwfm_pci_pktid_free(sc, &sc->sc_rx_pkts, sc->sc_ioctl_resp_pktid);
1812e5ec1e72Spatrick 	if (m == NULL)
1813e5ec1e72Spatrick 		return 1;
1814e5ec1e72Spatrick 
1815e5ec1e72Spatrick 	*len = min(buflen, sc->sc_ioctl_resp_ret_len);
1816e5ec1e72Spatrick 	if (buf)
1817e5ec1e72Spatrick 		memcpy(buf, mtod(m, char *), *len);
1818e5ec1e72Spatrick 	m_freem(m);
1819e5ec1e72Spatrick 	splx(s);
1820e5ec1e72Spatrick 
1821e5ec1e72Spatrick 	return 0;
1822e5ec1e72Spatrick }
1823e5ec1e72Spatrick 
1824e5ec1e72Spatrick int
1825e5ec1e72Spatrick bwfm_pci_msgbuf_set_dcmd(struct bwfm_softc *bwfm, int ifidx,
1826e5ec1e72Spatrick     int cmd, char *buf, size_t len)
1827e5ec1e72Spatrick {
1828e5ec1e72Spatrick 	return bwfm_pci_msgbuf_query_dcmd(bwfm, ifidx, cmd, buf, &len);
1829e5ec1e72Spatrick }
1830