xref: /openbsd/sys/dev/pci/if_bwfm_pci.c (revision 92fbeeb7)
1*92fbeeb7Spatrick /*	$OpenBSD: if_bwfm_pci.c,v 1.60 2021/12/27 12:03:59 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 
30ed6d4272Spatrick #if defined(__HAVE_FDT)
31ed6d4272Spatrick #include <machine/fdt.h>
32ed6d4272Spatrick #include <dev/ofw/openfirm.h>
33ed6d4272Spatrick #endif
34ed6d4272Spatrick 
35e5ec1e72Spatrick #if NBPFILTER > 0
36e5ec1e72Spatrick #include <net/bpf.h>
37e5ec1e72Spatrick #endif
38e5ec1e72Spatrick #include <net/if.h>
39e5ec1e72Spatrick #include <net/if_dl.h>
40e5ec1e72Spatrick #include <net/if_media.h>
41e5ec1e72Spatrick 
42e5ec1e72Spatrick #include <netinet/in.h>
43e5ec1e72Spatrick #include <netinet/if_ether.h>
44e5ec1e72Spatrick 
45e5ec1e72Spatrick #include <net80211/ieee80211_var.h>
46e5ec1e72Spatrick 
47e5ec1e72Spatrick #include <machine/bus.h>
48e5ec1e72Spatrick 
49e5ec1e72Spatrick #include <dev/pci/pcireg.h>
50e5ec1e72Spatrick #include <dev/pci/pcivar.h>
51e5ec1e72Spatrick #include <dev/pci/pcidevs.h>
52e5ec1e72Spatrick 
53e5ec1e72Spatrick #include <dev/ic/bwfmvar.h>
54e5ec1e72Spatrick #include <dev/ic/bwfmreg.h>
55e5ec1e72Spatrick #include <dev/pci/if_bwfm_pci.h>
56e5ec1e72Spatrick 
57e5ec1e72Spatrick #define BWFM_DMA_D2H_SCRATCH_BUF_LEN		8
58e5ec1e72Spatrick #define BWFM_DMA_D2H_RINGUPD_BUF_LEN		1024
59e5ec1e72Spatrick #define BWFM_DMA_H2D_IOCTL_BUF_LEN		ETHER_MAX_LEN
60e5ec1e72Spatrick 
61e5ec1e72Spatrick #define BWFM_NUM_TX_MSGRINGS			2
62e5ec1e72Spatrick #define BWFM_NUM_RX_MSGRINGS			3
63e5ec1e72Spatrick 
642eeba925Spatrick #define BWFM_NUM_IOCTL_PKTIDS			8
65e5ec1e72Spatrick #define BWFM_NUM_TX_PKTIDS			2048
66e5ec1e72Spatrick #define BWFM_NUM_RX_PKTIDS			1024
67e5ec1e72Spatrick 
682eeba925Spatrick #define BWFM_NUM_IOCTL_DESCS			1
69e5ec1e72Spatrick #define BWFM_NUM_TX_DESCS			1
70e5ec1e72Spatrick #define BWFM_NUM_RX_DESCS			1
71e5ec1e72Spatrick 
72e5ec1e72Spatrick #ifdef BWFM_DEBUG
73e5ec1e72Spatrick #define DPRINTF(x)	do { if (bwfm_debug > 0) printf x; } while (0)
74e5ec1e72Spatrick #define DPRINTFN(n, x)	do { if (bwfm_debug >= (n)) printf x; } while (0)
75e5ec1e72Spatrick static int bwfm_debug = 2;
76e5ec1e72Spatrick #else
77e5ec1e72Spatrick #define DPRINTF(x)	do { ; } while (0)
78e5ec1e72Spatrick #define DPRINTFN(n, x)	do { ; } while (0)
79e5ec1e72Spatrick #endif
80e5ec1e72Spatrick 
81e5ec1e72Spatrick #define DEVNAME(sc)	((sc)->sc_sc.sc_dev.dv_xname)
82e5ec1e72Spatrick 
83518be5f3Spatrick enum ring_status {
84518be5f3Spatrick 	RING_CLOSED,
85518be5f3Spatrick 	RING_CLOSING,
86518be5f3Spatrick 	RING_OPEN,
87518be5f3Spatrick 	RING_OPENING,
88518be5f3Spatrick };
89518be5f3Spatrick 
90e5ec1e72Spatrick struct bwfm_pci_msgring {
91e5ec1e72Spatrick 	uint32_t		 w_idx_addr;
92e5ec1e72Spatrick 	uint32_t		 r_idx_addr;
93e5ec1e72Spatrick 	uint32_t		 w_ptr;
94e5ec1e72Spatrick 	uint32_t		 r_ptr;
95e5ec1e72Spatrick 	int			 nitem;
96e5ec1e72Spatrick 	int			 itemsz;
97518be5f3Spatrick 	enum ring_status	 status;
98e5ec1e72Spatrick 	struct bwfm_pci_dmamem	*ring;
9902ee7d07Spatrick 	struct mbuf		*m;
100f67437f3Spatrick 
101f67437f3Spatrick 	int			 fifo;
102f67437f3Spatrick 	uint8_t			 mac[ETHER_ADDR_LEN];
103e5ec1e72Spatrick };
104e5ec1e72Spatrick 
1052eeba925Spatrick struct bwfm_pci_ioctl {
1062eeba925Spatrick 	uint16_t		 transid;
1072eeba925Spatrick 	uint16_t		 retlen;
1082eeba925Spatrick 	int16_t			 status;
1092eeba925Spatrick 	struct mbuf		*m;
1102eeba925Spatrick 	TAILQ_ENTRY(bwfm_pci_ioctl) next;
1112eeba925Spatrick };
1122eeba925Spatrick 
113e5ec1e72Spatrick struct bwfm_pci_buf {
114e5ec1e72Spatrick 	bus_dmamap_t	 bb_map;
115e5ec1e72Spatrick 	struct mbuf	*bb_m;
116e5ec1e72Spatrick };
117e5ec1e72Spatrick 
118e5ec1e72Spatrick struct bwfm_pci_pkts {
119e5ec1e72Spatrick 	struct bwfm_pci_buf	*pkts;
120e5ec1e72Spatrick 	uint32_t		 npkt;
121e5ec1e72Spatrick 	int			 last;
122e5ec1e72Spatrick };
123e5ec1e72Spatrick 
124e5ec1e72Spatrick struct bwfm_pci_softc {
125e5ec1e72Spatrick 	struct bwfm_softc	 sc_sc;
126e5ec1e72Spatrick 	pci_chipset_tag_t	 sc_pc;
127e5ec1e72Spatrick 	pcitag_t		 sc_tag;
128e5ec1e72Spatrick 	pcireg_t		 sc_id;
129e5ec1e72Spatrick 	void 			*sc_ih;
130e5ec1e72Spatrick 
131972218f3Spatrick 	int			 sc_initialized;
132972218f3Spatrick 
133e5ec1e72Spatrick 	bus_space_tag_t		 sc_reg_iot;
134e5ec1e72Spatrick 	bus_space_handle_t	 sc_reg_ioh;
135e5ec1e72Spatrick 	bus_size_t		 sc_reg_ios;
136e5ec1e72Spatrick 
137e5ec1e72Spatrick 	bus_space_tag_t		 sc_tcm_iot;
138e5ec1e72Spatrick 	bus_space_handle_t	 sc_tcm_ioh;
139e5ec1e72Spatrick 	bus_size_t		 sc_tcm_ios;
140e5ec1e72Spatrick 
141e5ec1e72Spatrick 	bus_dma_tag_t		 sc_dmat;
142e5ec1e72Spatrick 
143e5ec1e72Spatrick 	uint32_t		 sc_shared_address;
144e5ec1e72Spatrick 	uint32_t		 sc_shared_flags;
145e5ec1e72Spatrick 	uint8_t			 sc_shared_version;
146e5ec1e72Spatrick 
147e5ec1e72Spatrick 	uint8_t			 sc_dma_idx_sz;
148e5ec1e72Spatrick 	struct bwfm_pci_dmamem	*sc_dma_idx_buf;
149e5ec1e72Spatrick 	size_t			 sc_dma_idx_bufsz;
150e5ec1e72Spatrick 
151e5ec1e72Spatrick 	uint16_t		 sc_max_rxbufpost;
152e5ec1e72Spatrick 	uint32_t		 sc_rx_dataoffset;
153e5ec1e72Spatrick 	uint32_t		 sc_htod_mb_data_addr;
154e5ec1e72Spatrick 	uint32_t		 sc_dtoh_mb_data_addr;
155e5ec1e72Spatrick 	uint32_t		 sc_ring_info_addr;
156e5ec1e72Spatrick 
157e5ec1e72Spatrick 	uint32_t		 sc_console_base_addr;
158e5ec1e72Spatrick 	uint32_t		 sc_console_buf_addr;
159e5ec1e72Spatrick 	uint32_t		 sc_console_buf_size;
160cadf5fcfSpatrick 	uint32_t		 sc_console_readidx;
161e5ec1e72Spatrick 
162e5ec1e72Spatrick 	uint16_t		 sc_max_flowrings;
163e5ec1e72Spatrick 	uint16_t		 sc_max_submissionrings;
164e5ec1e72Spatrick 	uint16_t		 sc_max_completionrings;
165e5ec1e72Spatrick 
166e5ec1e72Spatrick 	struct bwfm_pci_msgring	 sc_ctrl_submit;
167e5ec1e72Spatrick 	struct bwfm_pci_msgring	 sc_rxpost_submit;
168e5ec1e72Spatrick 	struct bwfm_pci_msgring	 sc_ctrl_complete;
169e5ec1e72Spatrick 	struct bwfm_pci_msgring	 sc_tx_complete;
170e5ec1e72Spatrick 	struct bwfm_pci_msgring	 sc_rx_complete;
171e5ec1e72Spatrick 	struct bwfm_pci_msgring	*sc_flowrings;
172e5ec1e72Spatrick 
173e5ec1e72Spatrick 	struct bwfm_pci_dmamem	*sc_scratch_buf;
174e5ec1e72Spatrick 	struct bwfm_pci_dmamem	*sc_ringupd_buf;
175e5ec1e72Spatrick 
1762eeba925Spatrick 	TAILQ_HEAD(, bwfm_pci_ioctl) sc_ioctlq;
1772eeba925Spatrick 	uint16_t		 sc_ioctl_transid;
178e5ec1e72Spatrick 
179e5ec1e72Spatrick 	struct if_rxring	 sc_ioctl_ring;
180e5ec1e72Spatrick 	struct if_rxring	 sc_event_ring;
181e5ec1e72Spatrick 	struct if_rxring	 sc_rxbuf_ring;
182e5ec1e72Spatrick 
1832eeba925Spatrick 	struct bwfm_pci_pkts	 sc_ioctl_pkts;
184e5ec1e72Spatrick 	struct bwfm_pci_pkts	 sc_rx_pkts;
185c6f1636dSpatrick 	struct bwfm_pci_pkts	 sc_tx_pkts;
186c6f1636dSpatrick 	int			 sc_tx_pkts_full;
1871a93a9bdSpatrick 
1881a93a9bdSpatrick 	uint8_t			 sc_mbdata_done;
189e5ec1e72Spatrick };
190e5ec1e72Spatrick 
191e5ec1e72Spatrick struct bwfm_pci_dmamem {
192e5ec1e72Spatrick 	bus_dmamap_t		bdm_map;
193e5ec1e72Spatrick 	bus_dma_segment_t	bdm_seg;
194e5ec1e72Spatrick 	size_t			bdm_size;
195e5ec1e72Spatrick 	caddr_t			bdm_kva;
196e5ec1e72Spatrick };
197e5ec1e72Spatrick 
198e5ec1e72Spatrick #define BWFM_PCI_DMA_MAP(_bdm)	((_bdm)->bdm_map)
199e5ec1e72Spatrick #define BWFM_PCI_DMA_LEN(_bdm)	((_bdm)->bdm_size)
200e4dae658Spatrick #define BWFM_PCI_DMA_DVA(_bdm)	((uint64_t)(_bdm)->bdm_map->dm_segs[0].ds_addr)
201e5ec1e72Spatrick #define BWFM_PCI_DMA_KVA(_bdm)	((void *)(_bdm)->bdm_kva)
202e5ec1e72Spatrick 
203e5ec1e72Spatrick int		 bwfm_pci_match(struct device *, void *, void *);
204e5ec1e72Spatrick void		 bwfm_pci_attach(struct device *, struct device *, void *);
205e5ec1e72Spatrick int		 bwfm_pci_detach(struct device *, int);
2061a93a9bdSpatrick int		 bwfm_pci_activate(struct device *, int);
2071a93a9bdSpatrick void		 bwfm_pci_cleanup(struct bwfm_pci_softc *);
208e5ec1e72Spatrick 
209ed6d4272Spatrick #if defined(__HAVE_FDT)
210ed6d4272Spatrick int		 bwfm_pci_read_otp(struct bwfm_pci_softc *);
211ed6d4272Spatrick void		 bwfm_pci_process_otp_tuple(struct bwfm_pci_softc *, uint8_t,
212ed6d4272Spatrick 		    uint8_t, uint8_t *);
213ed6d4272Spatrick #endif
214ed6d4272Spatrick 
215e5ec1e72Spatrick int		 bwfm_pci_intr(void *);
216e5ec1e72Spatrick void		 bwfm_pci_intr_enable(struct bwfm_pci_softc *);
217e5ec1e72Spatrick void		 bwfm_pci_intr_disable(struct bwfm_pci_softc *);
218bb813cf8Spatrick uint32_t	 bwfm_pci_intr_status(struct bwfm_pci_softc *);
219bb813cf8Spatrick void		 bwfm_pci_intr_ack(struct bwfm_pci_softc *, uint32_t);
2201a93a9bdSpatrick uint32_t	 bwfm_pci_intmask(struct bwfm_pci_softc *);
221156d2677Spatrick void		 bwfm_pci_hostready(struct bwfm_pci_softc *);
222e5ec1e72Spatrick int		 bwfm_pci_load_microcode(struct bwfm_pci_softc *, const u_char *,
2236aad491fSpatrick 		    size_t, const u_char *, size_t);
224e5ec1e72Spatrick void		 bwfm_pci_select_core(struct bwfm_pci_softc *, int );
225e5ec1e72Spatrick 
226e5ec1e72Spatrick struct bwfm_pci_dmamem *
227e5ec1e72Spatrick 		 bwfm_pci_dmamem_alloc(struct bwfm_pci_softc *, bus_size_t,
228e5ec1e72Spatrick 		    bus_size_t);
229e5ec1e72Spatrick void		 bwfm_pci_dmamem_free(struct bwfm_pci_softc *, struct bwfm_pci_dmamem *);
23002ee7d07Spatrick int		 bwfm_pci_pktid_avail(struct bwfm_pci_softc *,
23102ee7d07Spatrick 		    struct bwfm_pci_pkts *);
232e5ec1e72Spatrick int		 bwfm_pci_pktid_new(struct bwfm_pci_softc *,
233e5ec1e72Spatrick 		    struct bwfm_pci_pkts *, struct mbuf *,
234e5ec1e72Spatrick 		    uint32_t *, paddr_t *);
235e5ec1e72Spatrick struct mbuf *	 bwfm_pci_pktid_free(struct bwfm_pci_softc *,
236e5ec1e72Spatrick 		    struct bwfm_pci_pkts *, uint32_t);
237e5ec1e72Spatrick void		 bwfm_pci_fill_rx_ioctl_ring(struct bwfm_pci_softc *,
238e5ec1e72Spatrick 		    struct if_rxring *, uint32_t);
239e5ec1e72Spatrick void		 bwfm_pci_fill_rx_buf_ring(struct bwfm_pci_softc *);
240e5ec1e72Spatrick void		 bwfm_pci_fill_rx_rings(struct bwfm_pci_softc *);
241e5ec1e72Spatrick int		 bwfm_pci_setup_ring(struct bwfm_pci_softc *, struct bwfm_pci_msgring *,
242e5ec1e72Spatrick 		    int, size_t, uint32_t, uint32_t, int, uint32_t, uint32_t *);
243518be5f3Spatrick int		 bwfm_pci_setup_flowring(struct bwfm_pci_softc *, struct bwfm_pci_msgring *,
244518be5f3Spatrick 		    int, size_t);
245e5ec1e72Spatrick 
246e5ec1e72Spatrick void		 bwfm_pci_ring_bell(struct bwfm_pci_softc *,
247e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
248e5ec1e72Spatrick void		 bwfm_pci_ring_update_rptr(struct bwfm_pci_softc *,
249e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
250e5ec1e72Spatrick void		 bwfm_pci_ring_update_wptr(struct bwfm_pci_softc *,
251e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
252e5ec1e72Spatrick void		 bwfm_pci_ring_write_rptr(struct bwfm_pci_softc *,
253e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
254e5ec1e72Spatrick void		 bwfm_pci_ring_write_wptr(struct bwfm_pci_softc *,
255e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
256e5ec1e72Spatrick void *		 bwfm_pci_ring_write_reserve(struct bwfm_pci_softc *,
257e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
258e5ec1e72Spatrick void *		 bwfm_pci_ring_write_reserve_multi(struct bwfm_pci_softc *,
259e5ec1e72Spatrick 		    struct bwfm_pci_msgring *, int, int *);
260e5ec1e72Spatrick void *		 bwfm_pci_ring_read_avail(struct bwfm_pci_softc *,
261e5ec1e72Spatrick 		    struct bwfm_pci_msgring *, int *);
262e5ec1e72Spatrick void		 bwfm_pci_ring_read_commit(struct bwfm_pci_softc *,
263e5ec1e72Spatrick 		    struct bwfm_pci_msgring *, int);
264e5ec1e72Spatrick void		 bwfm_pci_ring_write_commit(struct bwfm_pci_softc *,
265e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
266e5ec1e72Spatrick void		 bwfm_pci_ring_write_cancel(struct bwfm_pci_softc *,
267e5ec1e72Spatrick 		    struct bwfm_pci_msgring *, int);
268e5ec1e72Spatrick 
269e5ec1e72Spatrick void		 bwfm_pci_ring_rx(struct bwfm_pci_softc *,
2706f241297Spatrick 		    struct bwfm_pci_msgring *, struct mbuf_list *);
2716f241297Spatrick void		 bwfm_pci_msg_rx(struct bwfm_pci_softc *, void *,
2726f241297Spatrick 		    struct mbuf_list *);
273e5ec1e72Spatrick 
274e5ec1e72Spatrick uint32_t	 bwfm_pci_buscore_read(struct bwfm_softc *, uint32_t);
275e5ec1e72Spatrick void		 bwfm_pci_buscore_write(struct bwfm_softc *, uint32_t,
276e5ec1e72Spatrick 		    uint32_t);
277e5ec1e72Spatrick int		 bwfm_pci_buscore_prepare(struct bwfm_softc *);
278e5ec1e72Spatrick int		 bwfm_pci_buscore_reset(struct bwfm_softc *);
279e5ec1e72Spatrick void		 bwfm_pci_buscore_activate(struct bwfm_softc *, uint32_t);
280e5ec1e72Spatrick 
281f67437f3Spatrick int		 bwfm_pci_flowring_lookup(struct bwfm_pci_softc *,
282f67437f3Spatrick 		     struct mbuf *);
283f67437f3Spatrick void		 bwfm_pci_flowring_create(struct bwfm_pci_softc *,
284518be5f3Spatrick 		     struct mbuf *);
285518be5f3Spatrick void		 bwfm_pci_flowring_create_cb(struct bwfm_softc *, void *);
286a2c6ff8bSpatrick void		 bwfm_pci_flowring_delete(struct bwfm_pci_softc *, int);
287b5553ee6Spatrick void		 bwfm_pci_flowring_delete_cb(struct bwfm_softc *, void *);
288518be5f3Spatrick 
289972218f3Spatrick int		 bwfm_pci_preinit(struct bwfm_softc *);
290a2c6ff8bSpatrick void		 bwfm_pci_stop(struct bwfm_softc *);
29102ee7d07Spatrick int		 bwfm_pci_txcheck(struct bwfm_softc *);
292e5ec1e72Spatrick int		 bwfm_pci_txdata(struct bwfm_softc *, struct mbuf *);
293bbd71b0bSpatrick 
2941a93a9bdSpatrick int		 bwfm_pci_send_mb_data(struct bwfm_pci_softc *, uint32_t);
2951a93a9bdSpatrick void		 bwfm_pci_handle_mb_data(struct bwfm_pci_softc *);
2961a93a9bdSpatrick 
297bbd71b0bSpatrick #ifdef BWFM_DEBUG
298cadf5fcfSpatrick void		 bwfm_pci_debug_console(struct bwfm_pci_softc *);
299bbd71b0bSpatrick #endif
300e5ec1e72Spatrick 
301e5ec1e72Spatrick int		 bwfm_pci_msgbuf_query_dcmd(struct bwfm_softc *, int,
302e5ec1e72Spatrick 		    int, char *, size_t *);
303e5ec1e72Spatrick int		 bwfm_pci_msgbuf_set_dcmd(struct bwfm_softc *, int,
304e5ec1e72Spatrick 		    int, char *, size_t);
3052eeba925Spatrick void		 bwfm_pci_msgbuf_rxioctl(struct bwfm_pci_softc *,
3062eeba925Spatrick 		    struct msgbuf_ioctl_resp_hdr *);
307e5ec1e72Spatrick 
308e5ec1e72Spatrick struct bwfm_buscore_ops bwfm_pci_buscore_ops = {
309e5ec1e72Spatrick 	.bc_read = bwfm_pci_buscore_read,
310e5ec1e72Spatrick 	.bc_write = bwfm_pci_buscore_write,
311e5ec1e72Spatrick 	.bc_prepare = bwfm_pci_buscore_prepare,
312e5ec1e72Spatrick 	.bc_reset = bwfm_pci_buscore_reset,
313e5ec1e72Spatrick 	.bc_setup = NULL,
314e5ec1e72Spatrick 	.bc_activate = bwfm_pci_buscore_activate,
315e5ec1e72Spatrick };
316e5ec1e72Spatrick 
317e5ec1e72Spatrick struct bwfm_bus_ops bwfm_pci_bus_ops = {
318972218f3Spatrick 	.bs_preinit = bwfm_pci_preinit,
319a2c6ff8bSpatrick 	.bs_stop = bwfm_pci_stop,
32002ee7d07Spatrick 	.bs_txcheck = bwfm_pci_txcheck,
321e5ec1e72Spatrick 	.bs_txdata = bwfm_pci_txdata,
322e5ec1e72Spatrick 	.bs_txctl = NULL,
323e5ec1e72Spatrick };
324e5ec1e72Spatrick 
325e5ec1e72Spatrick struct bwfm_proto_ops bwfm_pci_msgbuf_ops = {
326e5ec1e72Spatrick 	.proto_query_dcmd = bwfm_pci_msgbuf_query_dcmd,
327e5ec1e72Spatrick 	.proto_set_dcmd = bwfm_pci_msgbuf_set_dcmd,
32814c74651Spatrick 	.proto_rx = NULL,
329029d6dd5Spatrick 	.proto_rxctl = NULL,
330e5ec1e72Spatrick };
331e5ec1e72Spatrick 
332e5ec1e72Spatrick struct cfattach bwfm_pci_ca = {
333e5ec1e72Spatrick 	sizeof(struct bwfm_pci_softc),
334e5ec1e72Spatrick 	bwfm_pci_match,
335e5ec1e72Spatrick 	bwfm_pci_attach,
336e5ec1e72Spatrick 	bwfm_pci_detach,
3371a93a9bdSpatrick 	bwfm_pci_activate,
338e5ec1e72Spatrick };
339e5ec1e72Spatrick 
340e5ec1e72Spatrick static const struct pci_matchid bwfm_pci_devices[] = {
34182f0e660Sjcs 	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4350 },
34241d93ac2Spatrick 	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4356 },
34341d93ac2Spatrick 	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM43602 },
344821fc986Spatrick 	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4371 },
3458e234c40Spatrick 	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4378 },
346e5ec1e72Spatrick };
347e5ec1e72Spatrick 
348e5ec1e72Spatrick int
349e5ec1e72Spatrick bwfm_pci_match(struct device *parent, void *match, void *aux)
350e5ec1e72Spatrick {
351e5ec1e72Spatrick 	return (pci_matchbyid(aux, bwfm_pci_devices,
352e5ec1e72Spatrick 	    nitems(bwfm_pci_devices)));
353e5ec1e72Spatrick }
354e5ec1e72Spatrick 
355e5ec1e72Spatrick void
356e5ec1e72Spatrick bwfm_pci_attach(struct device *parent, struct device *self, void *aux)
357e5ec1e72Spatrick {
358e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (struct bwfm_pci_softc *)self;
359e5ec1e72Spatrick 	struct pci_attach_args *pa = (struct pci_attach_args *)aux;
360e5ec1e72Spatrick 	const char *intrstr;
361e5ec1e72Spatrick 	pci_intr_handle_t ih;
362e5ec1e72Spatrick 
363e5ec1e72Spatrick 	if (pci_mapreg_map(pa, PCI_MAPREG_START + 0x08,
364e5ec1e72Spatrick 	    PCI_MAPREG_MEM_TYPE_64BIT, 0, &sc->sc_tcm_iot, &sc->sc_tcm_ioh,
365e5ec1e72Spatrick 	    NULL, &sc->sc_tcm_ios, 0)) {
366e5ec1e72Spatrick 		printf(": can't map bar1\n");
367a08e9144Spatrick 		return;
368a08e9144Spatrick 	}
369a08e9144Spatrick 
370a08e9144Spatrick 	if (pci_mapreg_map(pa, PCI_MAPREG_START + 0x00,
371a08e9144Spatrick 	    PCI_MAPREG_MEM_TYPE_64BIT, 0, &sc->sc_reg_iot, &sc->sc_reg_ioh,
372a08e9144Spatrick 	    NULL, &sc->sc_reg_ios, 0)) {
373a08e9144Spatrick 		printf(": can't map bar0\n");
374a08e9144Spatrick 		goto bar1;
375e5ec1e72Spatrick 	}
376e5ec1e72Spatrick 
377e5ec1e72Spatrick 	sc->sc_pc = pa->pa_pc;
378e5ec1e72Spatrick 	sc->sc_tag = pa->pa_tag;
379e5ec1e72Spatrick 	sc->sc_id = pa->pa_id;
380e5ec1e72Spatrick 	sc->sc_dmat = pa->pa_dmat;
381e5ec1e72Spatrick 
382e5ec1e72Spatrick 	/* Map and establish the interrupt. */
383e5ec1e72Spatrick 	if (pci_intr_map_msi(pa, &ih) != 0 && pci_intr_map(pa, &ih) != 0) {
384e5ec1e72Spatrick 		printf(": couldn't map interrupt\n");
385a08e9144Spatrick 		goto bar0;
386e5ec1e72Spatrick 	}
387e5ec1e72Spatrick 	intrstr = pci_intr_string(pa->pa_pc, ih);
388e5ec1e72Spatrick 
38914484acaSpatrick 	sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_NET,
390e5ec1e72Spatrick 	    bwfm_pci_intr, sc, DEVNAME(sc));
391e5ec1e72Spatrick 	if (sc->sc_ih == NULL) {
392e5ec1e72Spatrick 		printf(": couldn't establish interrupt");
393e5ec1e72Spatrick 		if (intrstr != NULL)
394e5ec1e72Spatrick 			printf(" at %s", intrstr);
395e5ec1e72Spatrick 		printf("\n");
396e5ec1e72Spatrick 		goto bar1;
397e5ec1e72Spatrick 	}
398e5ec1e72Spatrick 	printf(": %s\n", intrstr);
399e5ec1e72Spatrick 
400db31205aSkettenis #if defined(__HAVE_FDT)
401db31205aSkettenis 	sc->sc_sc.sc_node = PCITAG_NODE(pa->pa_tag);
402db31205aSkettenis #endif
403db31205aSkettenis 
404972218f3Spatrick 	sc->sc_sc.sc_bus_ops = &bwfm_pci_bus_ops;
405972218f3Spatrick 	sc->sc_sc.sc_proto_ops = &bwfm_pci_msgbuf_ops;
406972218f3Spatrick 	bwfm_attach(&sc->sc_sc);
407972218f3Spatrick 	config_mountroot(self, bwfm_attachhook);
408e5ec1e72Spatrick 	return;
409e5ec1e72Spatrick 
410e5ec1e72Spatrick bar0:
411e5ec1e72Spatrick 	bus_space_unmap(sc->sc_reg_iot, sc->sc_reg_ioh, sc->sc_reg_ios);
412a08e9144Spatrick bar1:
413a08e9144Spatrick 	bus_space_unmap(sc->sc_tcm_iot, sc->sc_tcm_ioh, sc->sc_tcm_ios);
414e5ec1e72Spatrick }
415e5ec1e72Spatrick 
416972218f3Spatrick int
417972218f3Spatrick bwfm_pci_preinit(struct bwfm_softc *bwfm)
418e5ec1e72Spatrick {
419972218f3Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
420e5ec1e72Spatrick 	struct bwfm_pci_ringinfo ringinfo;
4219ead8393Spatrick 	const char *chip = NULL;
42294e4747cSpatrick 	u_char *ucode, *nvram;
42394e4747cSpatrick 	size_t size, nvsize, nvlen;
424e5ec1e72Spatrick 	uint32_t d2h_w_idx_ptr, d2h_r_idx_ptr;
425e5ec1e72Spatrick 	uint32_t h2d_w_idx_ptr, h2d_r_idx_ptr;
426e5ec1e72Spatrick 	uint32_t idx_offset, reg;
427e5ec1e72Spatrick 	int i;
428e5ec1e72Spatrick 
429972218f3Spatrick 	if (sc->sc_initialized)
430972218f3Spatrick 		return 0;
431972218f3Spatrick 
432e5ec1e72Spatrick 	sc->sc_sc.sc_buscore_ops = &bwfm_pci_buscore_ops;
433e5ec1e72Spatrick 	if (bwfm_chip_attach(&sc->sc_sc) != 0) {
434e5ec1e72Spatrick 		printf("%s: cannot attach chip\n", DEVNAME(sc));
435972218f3Spatrick 		return 1;
436e5ec1e72Spatrick 	}
437e5ec1e72Spatrick 
438ed6d4272Spatrick #if defined(__HAVE_FDT)
439ed6d4272Spatrick 	if (bwfm_pci_read_otp(sc)) {
440ed6d4272Spatrick 		printf("%s: cannot read OTP\n", DEVNAME(sc));
441ed6d4272Spatrick 		return 1;
442ed6d4272Spatrick 	}
443ed6d4272Spatrick #endif
444ed6d4272Spatrick 
445e5ec1e72Spatrick 	bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2);
446e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
447e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_CONFIGADDR, 0x4e0);
448e5ec1e72Spatrick 	reg = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
449e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_CONFIGDATA);
450e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
451e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_CONFIGDATA, reg);
452e5ec1e72Spatrick 
453e5ec1e72Spatrick 	switch (bwfm->sc_chip.ch_chip)
454e5ec1e72Spatrick 	{
45518b3a1dcSpatrick 	case BRCM_CC_4350_CHIP_ID:
4569ead8393Spatrick 		if (bwfm->sc_chip.ch_chiprev > 7)
4579ead8393Spatrick 			chip = "4350";
4589ead8393Spatrick 		else
4599ead8393Spatrick 			chip = "4350c2";
46018b3a1dcSpatrick 		break;
46141d93ac2Spatrick 	case BRCM_CC_4356_CHIP_ID:
4629ead8393Spatrick 		chip = "4356";
46341d93ac2Spatrick 		break;
464e5ec1e72Spatrick 	case BRCM_CC_43602_CHIP_ID:
4659ead8393Spatrick 		chip = "43602";
466e5ec1e72Spatrick 		break;
467821fc986Spatrick 	case BRCM_CC_4371_CHIP_ID:
4689ead8393Spatrick 		chip = "4371";
469821fc986Spatrick 		break;
470c38a9bc9Spatrick 	case BRCM_CC_4378_CHIP_ID:
471c38a9bc9Spatrick 		chip = "4378";
472c38a9bc9Spatrick 		break;
473e5ec1e72Spatrick 	default:
47418b3a1dcSpatrick 		printf("%s: unknown firmware for chip %s\n",
47518b3a1dcSpatrick 		    DEVNAME(sc), bwfm->sc_chip.ch_name);
476972218f3Spatrick 		return 1;
477e5ec1e72Spatrick 	}
478e5ec1e72Spatrick 
47994e4747cSpatrick 	if (bwfm_loadfirmware(bwfm, chip, "-pcie", &ucode, &size,
48094e4747cSpatrick 	    &nvram, &nvsize, &nvlen) != 0)
481972218f3Spatrick 		return 1;
4826aad491fSpatrick 
483e5ec1e72Spatrick 	/* Retrieve RAM size from firmware. */
484e5ec1e72Spatrick 	if (size >= BWFM_RAMSIZE + 8) {
485e5ec1e72Spatrick 		uint32_t *ramsize = (uint32_t *)&ucode[BWFM_RAMSIZE];
486e5ec1e72Spatrick 		if (letoh32(ramsize[0]) == BWFM_RAMSIZE_MAGIC)
487e5ec1e72Spatrick 			bwfm->sc_chip.ch_ramsize = letoh32(ramsize[1]);
488e5ec1e72Spatrick 	}
489e5ec1e72Spatrick 
4906aad491fSpatrick 	if (bwfm_pci_load_microcode(sc, ucode, size, nvram, nvlen) != 0) {
491e5ec1e72Spatrick 		printf("%s: could not load microcode\n",
492e5ec1e72Spatrick 		    DEVNAME(sc));
493e5ec1e72Spatrick 		free(ucode, M_DEVBUF, size);
494b4e85b06Spatrick 		free(nvram, M_DEVBUF, nvsize);
495972218f3Spatrick 		return 1;
496e5ec1e72Spatrick 	}
497e5ec1e72Spatrick 	free(ucode, M_DEVBUF, size);
498b4e85b06Spatrick 	free(nvram, M_DEVBUF, nvsize);
499e5ec1e72Spatrick 
500e5ec1e72Spatrick 	sc->sc_shared_flags = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
501e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_INFO);
502e5ec1e72Spatrick 	sc->sc_shared_version = sc->sc_shared_flags;
503e5ec1e72Spatrick 	if (sc->sc_shared_version > BWFM_SHARED_INFO_MAX_VERSION ||
504e5ec1e72Spatrick 	    sc->sc_shared_version < BWFM_SHARED_INFO_MIN_VERSION) {
505e5ec1e72Spatrick 		printf("%s: PCIe version %d unsupported\n",
506e5ec1e72Spatrick 		    DEVNAME(sc), sc->sc_shared_version);
507972218f3Spatrick 		return 1;
508e5ec1e72Spatrick 	}
509e5ec1e72Spatrick 
510c794abf2Spatrick 	sc->sc_dma_idx_sz = 0;
511e5ec1e72Spatrick 	if (sc->sc_shared_flags & BWFM_SHARED_INFO_DMA_INDEX) {
512e5ec1e72Spatrick 		if (sc->sc_shared_flags & BWFM_SHARED_INFO_DMA_2B_IDX)
513e5ec1e72Spatrick 			sc->sc_dma_idx_sz = sizeof(uint16_t);
514e5ec1e72Spatrick 		else
515e5ec1e72Spatrick 			sc->sc_dma_idx_sz = sizeof(uint32_t);
516e5ec1e72Spatrick 	}
517e5ec1e72Spatrick 
518e5ec1e72Spatrick 	/* Maximum RX data buffers in the ring. */
519e5ec1e72Spatrick 	sc->sc_max_rxbufpost = bus_space_read_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
520e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_MAX_RXBUFPOST);
521e5ec1e72Spatrick 	if (sc->sc_max_rxbufpost == 0)
522e5ec1e72Spatrick 		sc->sc_max_rxbufpost = BWFM_SHARED_MAX_RXBUFPOST_DEFAULT;
523e5ec1e72Spatrick 
524e5ec1e72Spatrick 	/* Alternative offset of data in a packet */
525e5ec1e72Spatrick 	sc->sc_rx_dataoffset = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
526e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_RX_DATAOFFSET);
527e5ec1e72Spatrick 
528e5ec1e72Spatrick 	/* For Power Management */
529e5ec1e72Spatrick 	sc->sc_htod_mb_data_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
530e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_HTOD_MB_DATA_ADDR);
531e5ec1e72Spatrick 	sc->sc_dtoh_mb_data_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
532e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DTOH_MB_DATA_ADDR);
533e5ec1e72Spatrick 
534e5ec1e72Spatrick 	/* Ring information */
535e5ec1e72Spatrick 	sc->sc_ring_info_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
536e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_RING_INFO_ADDR);
537e5ec1e72Spatrick 
538e5ec1e72Spatrick 	/* Firmware's "dmesg" */
539e5ec1e72Spatrick 	sc->sc_console_base_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
540e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_CONSOLE_ADDR);
541e5ec1e72Spatrick 	sc->sc_console_buf_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
542e5ec1e72Spatrick 	    sc->sc_console_base_addr + BWFM_CONSOLE_BUFADDR);
543e5ec1e72Spatrick 	sc->sc_console_buf_size = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
544e5ec1e72Spatrick 	    sc->sc_console_base_addr + BWFM_CONSOLE_BUFSIZE);
545e5ec1e72Spatrick 
546e5ec1e72Spatrick 	/* Read ring information. */
547e5ec1e72Spatrick 	bus_space_read_region_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
548e5ec1e72Spatrick 	    sc->sc_ring_info_addr, (void *)&ringinfo, sizeof(ringinfo));
549e5ec1e72Spatrick 
550e5ec1e72Spatrick 	if (sc->sc_shared_version >= 6) {
551e5ec1e72Spatrick 		sc->sc_max_submissionrings = le16toh(ringinfo.max_submissionrings);
552e5ec1e72Spatrick 		sc->sc_max_flowrings = le16toh(ringinfo.max_flowrings);
553e5ec1e72Spatrick 		sc->sc_max_completionrings = le16toh(ringinfo.max_completionrings);
554e5ec1e72Spatrick 	} else {
555e5ec1e72Spatrick 		sc->sc_max_submissionrings = le16toh(ringinfo.max_flowrings);
556e5ec1e72Spatrick 		sc->sc_max_flowrings = sc->sc_max_submissionrings -
557e5ec1e72Spatrick 		    BWFM_NUM_TX_MSGRINGS;
558e5ec1e72Spatrick 		sc->sc_max_completionrings = BWFM_NUM_RX_MSGRINGS;
559e5ec1e72Spatrick 	}
560e5ec1e72Spatrick 
561e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
562e5ec1e72Spatrick 		d2h_w_idx_ptr = letoh32(ringinfo.d2h_w_idx_ptr);
563e5ec1e72Spatrick 		d2h_r_idx_ptr = letoh32(ringinfo.d2h_r_idx_ptr);
564e5ec1e72Spatrick 		h2d_w_idx_ptr = letoh32(ringinfo.h2d_w_idx_ptr);
565e5ec1e72Spatrick 		h2d_r_idx_ptr = letoh32(ringinfo.h2d_r_idx_ptr);
566e5ec1e72Spatrick 		idx_offset = sizeof(uint32_t);
567e5ec1e72Spatrick 	} else {
568e5ec1e72Spatrick 		uint64_t address;
569e5ec1e72Spatrick 
570e5ec1e72Spatrick 		/* Each TX/RX Ring has a Read and Write Ptr */
571e5ec1e72Spatrick 		sc->sc_dma_idx_bufsz = (sc->sc_max_submissionrings +
572e5ec1e72Spatrick 		    sc->sc_max_completionrings) * sc->sc_dma_idx_sz * 2;
573e5ec1e72Spatrick 		sc->sc_dma_idx_buf = bwfm_pci_dmamem_alloc(sc,
574e5ec1e72Spatrick 		    sc->sc_dma_idx_bufsz, 8);
575e5ec1e72Spatrick 		if (sc->sc_dma_idx_buf == NULL) {
576e5ec1e72Spatrick 			/* XXX: Fallback to TCM? */
577e5ec1e72Spatrick 			printf("%s: cannot allocate idx buf\n",
578e5ec1e72Spatrick 			    DEVNAME(sc));
579972218f3Spatrick 			return 1;
580e5ec1e72Spatrick 		}
581e5ec1e72Spatrick 
582e5ec1e72Spatrick 		idx_offset = sc->sc_dma_idx_sz;
583e5ec1e72Spatrick 		h2d_w_idx_ptr = 0;
584e5ec1e72Spatrick 		address = BWFM_PCI_DMA_DVA(sc->sc_dma_idx_buf);
585e5ec1e72Spatrick 		ringinfo.h2d_w_idx_hostaddr_low =
586e5ec1e72Spatrick 		    htole32(address & 0xffffffff);
587e5ec1e72Spatrick 		ringinfo.h2d_w_idx_hostaddr_high =
588e5ec1e72Spatrick 		    htole32(address >> 32);
589e5ec1e72Spatrick 
590e5ec1e72Spatrick 		h2d_r_idx_ptr = h2d_w_idx_ptr +
591e5ec1e72Spatrick 		    sc->sc_max_submissionrings * idx_offset;
592e5ec1e72Spatrick 		address += sc->sc_max_submissionrings * idx_offset;
593e5ec1e72Spatrick 		ringinfo.h2d_r_idx_hostaddr_low =
594e5ec1e72Spatrick 		    htole32(address & 0xffffffff);
595e5ec1e72Spatrick 		ringinfo.h2d_r_idx_hostaddr_high =
596e5ec1e72Spatrick 		    htole32(address >> 32);
597e5ec1e72Spatrick 
598e5ec1e72Spatrick 		d2h_w_idx_ptr = h2d_r_idx_ptr +
599e5ec1e72Spatrick 		    sc->sc_max_submissionrings * idx_offset;
600e5ec1e72Spatrick 		address += sc->sc_max_submissionrings * idx_offset;
601e5ec1e72Spatrick 		ringinfo.d2h_w_idx_hostaddr_low =
602e5ec1e72Spatrick 		    htole32(address & 0xffffffff);
603e5ec1e72Spatrick 		ringinfo.d2h_w_idx_hostaddr_high =
604e5ec1e72Spatrick 		    htole32(address >> 32);
605e5ec1e72Spatrick 
606e5ec1e72Spatrick 		d2h_r_idx_ptr = d2h_w_idx_ptr +
607e5ec1e72Spatrick 		    sc->sc_max_completionrings * idx_offset;
608e5ec1e72Spatrick 		address += sc->sc_max_completionrings * idx_offset;
609e5ec1e72Spatrick 		ringinfo.d2h_r_idx_hostaddr_low =
610e5ec1e72Spatrick 		    htole32(address & 0xffffffff);
611e5ec1e72Spatrick 		ringinfo.d2h_r_idx_hostaddr_high =
612e5ec1e72Spatrick 		    htole32(address >> 32);
613e5ec1e72Spatrick 
614e5ec1e72Spatrick 		bus_space_write_region_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
615e5ec1e72Spatrick 		    sc->sc_ring_info_addr, (void *)&ringinfo, sizeof(ringinfo));
616e5ec1e72Spatrick 	}
617e5ec1e72Spatrick 
618e5ec1e72Spatrick 	uint32_t ring_mem_ptr = letoh32(ringinfo.ringmem);
619e5ec1e72Spatrick 	/* TX ctrl ring: Send ctrl buffers, send IOCTLs */
620e5ec1e72Spatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_ctrl_submit, 64, 40,
621e5ec1e72Spatrick 	    h2d_w_idx_ptr, h2d_r_idx_ptr, 0, idx_offset,
622e5ec1e72Spatrick 	    &ring_mem_ptr))
623e5ec1e72Spatrick 		goto cleanup;
624e5ec1e72Spatrick 	/* TX rxpost ring: Send clean data mbufs for RX */
6251c0efb8bSpatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_rxpost_submit, 1024, 32,
626e5ec1e72Spatrick 	    h2d_w_idx_ptr, h2d_r_idx_ptr, 1, idx_offset,
627e5ec1e72Spatrick 	    &ring_mem_ptr))
628e5ec1e72Spatrick 		goto cleanup;
629e5ec1e72Spatrick 	/* RX completion rings: recv our filled buffers back */
630e5ec1e72Spatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_ctrl_complete, 64, 24,
631e5ec1e72Spatrick 	    d2h_w_idx_ptr, d2h_r_idx_ptr, 0, idx_offset,
632e5ec1e72Spatrick 	    &ring_mem_ptr))
633e5ec1e72Spatrick 		goto cleanup;
634095b0c44Spatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_tx_complete, 1024,
635095b0c44Spatrick 	    sc->sc_shared_version >= 7 ? 24 : 16,
636e5ec1e72Spatrick 	    d2h_w_idx_ptr, d2h_r_idx_ptr, 1, idx_offset,
637e5ec1e72Spatrick 	    &ring_mem_ptr))
638e5ec1e72Spatrick 		goto cleanup;
6391c0efb8bSpatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_rx_complete, 1024,
640095b0c44Spatrick 	    sc->sc_shared_version >= 7 ? 40 : 32,
641e5ec1e72Spatrick 	    d2h_w_idx_ptr, d2h_r_idx_ptr, 2, idx_offset,
642e5ec1e72Spatrick 	    &ring_mem_ptr))
643e5ec1e72Spatrick 		goto cleanup;
644e5ec1e72Spatrick 
645e5ec1e72Spatrick 	/* Dynamic TX rings for actual data */
646e5ec1e72Spatrick 	sc->sc_flowrings = malloc(sc->sc_max_flowrings *
647e5ec1e72Spatrick 	    sizeof(struct bwfm_pci_msgring), M_DEVBUF, M_WAITOK | M_ZERO);
648518be5f3Spatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
649518be5f3Spatrick 		struct bwfm_pci_msgring *ring = &sc->sc_flowrings[i];
650518be5f3Spatrick 		ring->w_idx_addr = h2d_w_idx_ptr + (i + 2) * idx_offset;
651518be5f3Spatrick 		ring->r_idx_addr = h2d_r_idx_ptr + (i + 2) * idx_offset;
652518be5f3Spatrick 	}
653e5ec1e72Spatrick 
654e5ec1e72Spatrick 	/* Scratch and ring update buffers for firmware */
655e5ec1e72Spatrick 	if ((sc->sc_scratch_buf = bwfm_pci_dmamem_alloc(sc,
656e5ec1e72Spatrick 	    BWFM_DMA_D2H_SCRATCH_BUF_LEN, 8)) == NULL)
657e5ec1e72Spatrick 		goto cleanup;
658e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
659e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_SCRATCH_ADDR_LOW,
660e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(sc->sc_scratch_buf) & 0xffffffff);
661e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
662e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_SCRATCH_ADDR_HIGH,
663e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(sc->sc_scratch_buf) >> 32);
664e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
665e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_SCRATCH_LEN,
666e5ec1e72Spatrick 	    BWFM_DMA_D2H_SCRATCH_BUF_LEN);
667e5ec1e72Spatrick 
668e5ec1e72Spatrick 	if ((sc->sc_ringupd_buf = bwfm_pci_dmamem_alloc(sc,
669e5ec1e72Spatrick 	    BWFM_DMA_D2H_RINGUPD_BUF_LEN, 8)) == NULL)
670e5ec1e72Spatrick 		goto cleanup;
671e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
672e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_RINGUPD_ADDR_LOW,
673e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(sc->sc_ringupd_buf) & 0xffffffff);
674e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
675e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_RINGUPD_ADDR_HIGH,
676e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(sc->sc_ringupd_buf) >> 32);
677e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
678e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_RINGUPD_LEN,
679e5ec1e72Spatrick 	    BWFM_DMA_D2H_RINGUPD_BUF_LEN);
680e5ec1e72Spatrick 
681e5ec1e72Spatrick 	bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2);
682e5ec1e72Spatrick 	bwfm_pci_intr_enable(sc);
683156d2677Spatrick 	bwfm_pci_hostready(sc);
684e5ec1e72Spatrick 
685e5ec1e72Spatrick 	/* Maps RX mbufs to a packet id and back. */
686e5ec1e72Spatrick 	sc->sc_rx_pkts.npkt = BWFM_NUM_RX_PKTIDS;
687e5ec1e72Spatrick 	sc->sc_rx_pkts.pkts = malloc(BWFM_NUM_RX_PKTIDS *
688e5ec1e72Spatrick 	    sizeof(struct bwfm_pci_buf), M_DEVBUF, M_WAITOK | M_ZERO);
689e5ec1e72Spatrick 	for (i = 0; i < BWFM_NUM_RX_PKTIDS; i++)
6901950c5c5Spatrick 		bus_dmamap_create(sc->sc_dmat, MSGBUF_MAX_CTL_PKT_SIZE,
6911950c5c5Spatrick 		    BWFM_NUM_RX_DESCS, MSGBUF_MAX_CTL_PKT_SIZE, 0, BUS_DMA_WAITOK,
692e5ec1e72Spatrick 		    &sc->sc_rx_pkts.pkts[i].bb_map);
693e5ec1e72Spatrick 
694e5ec1e72Spatrick 	/* Maps TX mbufs to a packet id and back. */
695f416501bSpatrick 	sc->sc_tx_pkts.npkt = BWFM_NUM_TX_PKTIDS;
696e5ec1e72Spatrick 	sc->sc_tx_pkts.pkts = malloc(BWFM_NUM_TX_PKTIDS
697e5ec1e72Spatrick 	    * sizeof(struct bwfm_pci_buf), M_DEVBUF, M_WAITOK | M_ZERO);
698e5ec1e72Spatrick 	for (i = 0; i < BWFM_NUM_TX_PKTIDS; i++)
699e5ec1e72Spatrick 		bus_dmamap_create(sc->sc_dmat, MSGBUF_MAX_PKT_SIZE,
700e5ec1e72Spatrick 		    BWFM_NUM_TX_DESCS, MSGBUF_MAX_PKT_SIZE, 0, BUS_DMA_WAITOK,
701e5ec1e72Spatrick 		    &sc->sc_tx_pkts.pkts[i].bb_map);
702c794abf2Spatrick 	sc->sc_tx_pkts_full = 0;
703e5ec1e72Spatrick 
7042eeba925Spatrick 	/* Maps IOCTL mbufs to a packet id and back. */
7052eeba925Spatrick 	sc->sc_ioctl_pkts.npkt = BWFM_NUM_IOCTL_PKTIDS;
7062eeba925Spatrick 	sc->sc_ioctl_pkts.pkts = malloc(BWFM_NUM_IOCTL_PKTIDS
7072eeba925Spatrick 	    * sizeof(struct bwfm_pci_buf), M_DEVBUF, M_WAITOK | M_ZERO);
7082eeba925Spatrick 	for (i = 0; i < BWFM_NUM_IOCTL_PKTIDS; i++)
7092eeba925Spatrick 		bus_dmamap_create(sc->sc_dmat, MSGBUF_MAX_PKT_SIZE,
7102eeba925Spatrick 		    BWFM_NUM_IOCTL_DESCS, MSGBUF_MAX_PKT_SIZE, 0, BUS_DMA_WAITOK,
7112eeba925Spatrick 		    &sc->sc_ioctl_pkts.pkts[i].bb_map);
7122eeba925Spatrick 
71318722113Spatrick 	/*
71418722113Spatrick 	 * For whatever reason, could also be a bug somewhere in this
71518722113Spatrick 	 * driver, the firmware needs a bunch of RX buffers otherwise
7164ef2dd0fSpatrick 	 * it won't send any RX complete messages.
71718722113Spatrick 	 */
7184ef2dd0fSpatrick 	if_rxr_init(&sc->sc_rxbuf_ring, min(256, sc->sc_max_rxbufpost),
7194ef2dd0fSpatrick 	    sc->sc_max_rxbufpost);
720e5ec1e72Spatrick 	if_rxr_init(&sc->sc_ioctl_ring, 8, 8);
721e5ec1e72Spatrick 	if_rxr_init(&sc->sc_event_ring, 8, 8);
722e5ec1e72Spatrick 	bwfm_pci_fill_rx_rings(sc);
723e5ec1e72Spatrick 
7242eeba925Spatrick 	TAILQ_INIT(&sc->sc_ioctlq);
7252eeba925Spatrick 
726cadf5fcfSpatrick #ifdef BWFM_DEBUG
727cadf5fcfSpatrick 	sc->sc_console_readidx = 0;
728cadf5fcfSpatrick 	bwfm_pci_debug_console(sc);
729cadf5fcfSpatrick #endif
730cadf5fcfSpatrick 
731972218f3Spatrick 	sc->sc_initialized = 1;
732972218f3Spatrick 	return 0;
733e5ec1e72Spatrick 
734e5ec1e72Spatrick cleanup:
735e5ec1e72Spatrick 	if (sc->sc_ringupd_buf)
736e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_ringupd_buf);
737e5ec1e72Spatrick 	if (sc->sc_scratch_buf)
738e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_scratch_buf);
739e5ec1e72Spatrick 	if (sc->sc_rx_complete.ring)
740e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_rx_complete.ring);
741e5ec1e72Spatrick 	if (sc->sc_tx_complete.ring)
742e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_tx_complete.ring);
743e5ec1e72Spatrick 	if (sc->sc_ctrl_complete.ring)
744e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_ctrl_complete.ring);
745e5ec1e72Spatrick 	if (sc->sc_rxpost_submit.ring)
746e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_rxpost_submit.ring);
747e5ec1e72Spatrick 	if (sc->sc_ctrl_submit.ring)
748e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_ctrl_submit.ring);
749e5ec1e72Spatrick 	if (sc->sc_dma_idx_buf)
750e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_dma_idx_buf);
751972218f3Spatrick 	return 1;
752e5ec1e72Spatrick }
753e5ec1e72Spatrick 
754e5ec1e72Spatrick int
7556aad491fSpatrick bwfm_pci_load_microcode(struct bwfm_pci_softc *sc, const u_char *ucode, size_t size,
7566aad491fSpatrick     const u_char *nvram, size_t nvlen)
757e5ec1e72Spatrick {
758e5ec1e72Spatrick 	struct bwfm_softc *bwfm = (void *)sc;
759e5ec1e72Spatrick 	struct bwfm_core *core;
7606aad491fSpatrick 	uint32_t shared, written;
761e5ec1e72Spatrick 	int i;
762e5ec1e72Spatrick 
763e5ec1e72Spatrick 	if (bwfm->sc_chip.ch_chip == BRCM_CC_43602_CHIP_ID) {
764e5ec1e72Spatrick 		bwfm_pci_select_core(sc, BWFM_AGENT_CORE_ARM_CR4);
765e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
766e5ec1e72Spatrick 		    BWFM_PCI_ARMCR4REG_BANKIDX, 5);
767e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
768e5ec1e72Spatrick 		    BWFM_PCI_ARMCR4REG_BANKPDA, 0);
769e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
770e5ec1e72Spatrick 		    BWFM_PCI_ARMCR4REG_BANKIDX, 7);
771e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
772e5ec1e72Spatrick 		    BWFM_PCI_ARMCR4REG_BANKPDA, 0);
773e5ec1e72Spatrick 	}
774e5ec1e72Spatrick 
775e5ec1e72Spatrick 	for (i = 0; i < size; i++)
776e5ec1e72Spatrick 		bus_space_write_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
777e5ec1e72Spatrick 		    bwfm->sc_chip.ch_rambase + i, ucode[i]);
778e5ec1e72Spatrick 
779e5ec1e72Spatrick 	/* Firmware replaces this with a pointer once up. */
780e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
781e5ec1e72Spatrick 	    bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize - 4, 0);
782e5ec1e72Spatrick 
7836aad491fSpatrick 	if (nvram) {
7846aad491fSpatrick 		for (i = 0; i < nvlen; i++)
7856aad491fSpatrick 			bus_space_write_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
7866aad491fSpatrick 			    bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize
7876aad491fSpatrick 			    - nvlen  + i, nvram[i]);
7886aad491fSpatrick 	}
7896aad491fSpatrick 
7906aad491fSpatrick 	written = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
7916aad491fSpatrick 	    bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize - 4);
792e5ec1e72Spatrick 
793e5ec1e72Spatrick 	/* Load reset vector from firmware and kickstart core. */
794b0cd4990Spatrick 	if (bwfm->sc_chip.ch_chip == BRCM_CC_43602_CHIP_ID) {
795e5ec1e72Spatrick 		core = bwfm_chip_get_core(bwfm, BWFM_AGENT_INTERNAL_MEM);
796e5ec1e72Spatrick 		bwfm->sc_chip.ch_core_reset(bwfm, core, 0, 0, 0);
797b0cd4990Spatrick 	}
798e5ec1e72Spatrick 	bwfm_chip_set_active(bwfm, *(uint32_t *)ucode);
799e5ec1e72Spatrick 
8003c53ddefSpatrick 	for (i = 0; i < 100; i++) {
801e5ec1e72Spatrick 		delay(50 * 1000);
802e5ec1e72Spatrick 		shared = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
803e5ec1e72Spatrick 		    bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize - 4);
8046aad491fSpatrick 		if (shared != written)
805e5ec1e72Spatrick 			break;
806e5ec1e72Spatrick 	}
80719871452Spatrick 	if (shared == written) {
808e5ec1e72Spatrick 		printf("%s: firmware did not come up\n", DEVNAME(sc));
809e5ec1e72Spatrick 		return 1;
810e5ec1e72Spatrick 	}
81119871452Spatrick 	if (shared < bwfm->sc_chip.ch_rambase ||
81219871452Spatrick 	    shared >= bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize) {
81319871452Spatrick 		printf("%s: invalid shared RAM address 0x%08x\n", DEVNAME(sc),
81419871452Spatrick 		    shared);
81519871452Spatrick 		return 1;
81619871452Spatrick 	}
817e5ec1e72Spatrick 
818e5ec1e72Spatrick 	sc->sc_shared_address = shared;
819e5ec1e72Spatrick 	return 0;
820e5ec1e72Spatrick }
821e5ec1e72Spatrick 
822e5ec1e72Spatrick int
823e5ec1e72Spatrick bwfm_pci_detach(struct device *self, int flags)
824e5ec1e72Spatrick {
825e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (struct bwfm_pci_softc *)self;
826e5ec1e72Spatrick 
827e5ec1e72Spatrick 	bwfm_detach(&sc->sc_sc, flags);
8281a93a9bdSpatrick 	bwfm_pci_cleanup(sc);
8291a93a9bdSpatrick 
8301a93a9bdSpatrick 	return 0;
8311a93a9bdSpatrick }
8321a93a9bdSpatrick 
8331a93a9bdSpatrick void
8341a93a9bdSpatrick bwfm_pci_cleanup(struct bwfm_pci_softc *sc)
8351a93a9bdSpatrick {
8361a93a9bdSpatrick 	int i;
837e5ec1e72Spatrick 
83864ae3612Spatrick 	for (i = 0; i < BWFM_NUM_RX_PKTIDS; i++) {
83964ae3612Spatrick 		bus_dmamap_destroy(sc->sc_dmat, sc->sc_rx_pkts.pkts[i].bb_map);
84064ae3612Spatrick 		if (sc->sc_rx_pkts.pkts[i].bb_m)
84164ae3612Spatrick 			m_freem(sc->sc_rx_pkts.pkts[i].bb_m);
84264ae3612Spatrick 	}
84364ae3612Spatrick 	free(sc->sc_rx_pkts.pkts, M_DEVBUF, BWFM_NUM_RX_PKTIDS *
84464ae3612Spatrick 	    sizeof(struct bwfm_pci_buf));
84564ae3612Spatrick 
84664ae3612Spatrick 	for (i = 0; i < BWFM_NUM_TX_PKTIDS; i++) {
84764ae3612Spatrick 		bus_dmamap_destroy(sc->sc_dmat, sc->sc_tx_pkts.pkts[i].bb_map);
84864ae3612Spatrick 		if (sc->sc_tx_pkts.pkts[i].bb_m)
84964ae3612Spatrick 			m_freem(sc->sc_tx_pkts.pkts[i].bb_m);
85064ae3612Spatrick 	}
85164ae3612Spatrick 	free(sc->sc_tx_pkts.pkts, M_DEVBUF, BWFM_NUM_TX_PKTIDS *
85264ae3612Spatrick 	    sizeof(struct bwfm_pci_buf));
85364ae3612Spatrick 
85464ae3612Spatrick 	for (i = 0; i < BWFM_NUM_IOCTL_PKTIDS; i++) {
85564ae3612Spatrick 		bus_dmamap_destroy(sc->sc_dmat, sc->sc_ioctl_pkts.pkts[i].bb_map);
85664ae3612Spatrick 		if (sc->sc_ioctl_pkts.pkts[i].bb_m)
85764ae3612Spatrick 			m_freem(sc->sc_ioctl_pkts.pkts[i].bb_m);
85864ae3612Spatrick 	}
85964ae3612Spatrick 	free(sc->sc_ioctl_pkts.pkts, M_DEVBUF, BWFM_NUM_IOCTL_PKTIDS *
86064ae3612Spatrick 	    sizeof(struct bwfm_pci_buf));
86164ae3612Spatrick 
86264ae3612Spatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
86364ae3612Spatrick 		if (sc->sc_flowrings[i].status >= RING_OPEN)
86464ae3612Spatrick 			bwfm_pci_dmamem_free(sc, sc->sc_flowrings[i].ring);
86564ae3612Spatrick 	}
86664ae3612Spatrick 	free(sc->sc_flowrings, M_DEVBUF, sc->sc_max_flowrings *
86764ae3612Spatrick 	    sizeof(struct bwfm_pci_msgring));
868e5ec1e72Spatrick 
869e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_ringupd_buf);
870e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_scratch_buf);
871e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_rx_complete.ring);
872e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_tx_complete.ring);
873e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_ctrl_complete.ring);
874e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_rxpost_submit.ring);
875e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_ctrl_submit.ring);
87664ae3612Spatrick 	if (sc->sc_dma_idx_buf) {
877e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_dma_idx_buf);
87864ae3612Spatrick 		sc->sc_dma_idx_buf = NULL;
87964ae3612Spatrick 	}
88064ae3612Spatrick 
88164ae3612Spatrick 	sc->sc_initialized = 0;
8821a93a9bdSpatrick }
8831a93a9bdSpatrick 
8841a93a9bdSpatrick int
8851a93a9bdSpatrick bwfm_pci_activate(struct device *self, int act)
8861a93a9bdSpatrick {
8871a93a9bdSpatrick 	struct bwfm_pci_softc *sc = (struct bwfm_pci_softc *)self;
8881a93a9bdSpatrick 	struct bwfm_softc *bwfm = (void *)sc;
8891a93a9bdSpatrick 	int error = 0;
8901a93a9bdSpatrick 
8911a93a9bdSpatrick 	switch (act) {
8921a93a9bdSpatrick 	case DVACT_QUIESCE:
8931a93a9bdSpatrick 		error = bwfm_activate(bwfm, act);
8941a93a9bdSpatrick 		if (error)
8951a93a9bdSpatrick 			return error;
8961a93a9bdSpatrick 		if (sc->sc_initialized) {
8971a93a9bdSpatrick 			sc->sc_mbdata_done = 0;
8981a93a9bdSpatrick 			error = bwfm_pci_send_mb_data(sc,
8991a93a9bdSpatrick 			    BWFM_PCI_H2D_HOST_D3_INFORM);
9001a93a9bdSpatrick 			if (error)
9011a93a9bdSpatrick 				return error;
9021a93a9bdSpatrick 			tsleep_nsec(&sc->sc_mbdata_done, PCATCH,
9031a93a9bdSpatrick 			    DEVNAME(sc), SEC_TO_NSEC(2));
9041a93a9bdSpatrick 			if (!sc->sc_mbdata_done)
9051a93a9bdSpatrick 				return ETIMEDOUT;
9061a93a9bdSpatrick 		}
9071a93a9bdSpatrick 		break;
9081a93a9bdSpatrick 	case DVACT_WAKEUP:
9091a93a9bdSpatrick 		if (sc->sc_initialized) {
9101a93a9bdSpatrick 			/* If device can't be resumed, re-init. */
9111a93a9bdSpatrick 			if (bwfm_pci_intmask(sc) == 0 ||
9121a93a9bdSpatrick 			    bwfm_pci_send_mb_data(sc,
9131a93a9bdSpatrick 			    BWFM_PCI_H2D_HOST_D0_INFORM) != 0) {
9141a93a9bdSpatrick 				bwfm_cleanup(bwfm);
9151a93a9bdSpatrick 				bwfm_pci_cleanup(sc);
9161a93a9bdSpatrick 			}
9171a93a9bdSpatrick 		}
9181a93a9bdSpatrick 		error = bwfm_activate(bwfm, act);
9191a93a9bdSpatrick 		if (error)
9201a93a9bdSpatrick 			return error;
9211a93a9bdSpatrick 		break;
9221a93a9bdSpatrick 	default:
9231a93a9bdSpatrick 		break;
9241a93a9bdSpatrick 	}
9251a93a9bdSpatrick 
926e5ec1e72Spatrick 	return 0;
927e5ec1e72Spatrick }
928e5ec1e72Spatrick 
929ed6d4272Spatrick #if defined(__HAVE_FDT)
930ed6d4272Spatrick int
931ed6d4272Spatrick bwfm_pci_read_otp(struct bwfm_pci_softc *sc)
932ed6d4272Spatrick {
933ed6d4272Spatrick 	struct bwfm_softc *bwfm = (void *)sc;
934ed6d4272Spatrick 	struct bwfm_core *core;
935ed6d4272Spatrick 	uint8_t otp[BWFM_OTP_SIZE];
936ed6d4272Spatrick 	int i;
937ed6d4272Spatrick 
938ed6d4272Spatrick 	if (bwfm->sc_chip.ch_chip != BRCM_CC_4378_CHIP_ID)
939ed6d4272Spatrick 		return 0;
940ed6d4272Spatrick 
941ed6d4272Spatrick 	core = bwfm_chip_get_core(bwfm, BWFM_AGENT_CORE_GCI);
942ed6d4272Spatrick 	if (core == NULL)
943ed6d4272Spatrick 		return 1;
944ed6d4272Spatrick 
945ed6d4272Spatrick 	for (i = 0; i < (sizeof(otp) / sizeof(uint32_t)); i++)
946ed6d4272Spatrick 		((uint32_t *)otp)[i] = bwfm_pci_buscore_read(bwfm,
947ed6d4272Spatrick 		    core->co_base + BWFM_OTP_4378_BASE + i * sizeof(uint32_t));
948ed6d4272Spatrick 
949ed6d4272Spatrick 	for (i = 0; i < BWFM_OTP_SIZE - 1; ) {
950ed6d4272Spatrick 		if (otp[i + 0] == 0) {
951ed6d4272Spatrick 			i++;
952ed6d4272Spatrick 			continue;
953ed6d4272Spatrick 		}
954ed6d4272Spatrick 		if (i + otp[i + 1] > BWFM_OTP_SIZE)
955ed6d4272Spatrick 			break;
956ed6d4272Spatrick 		bwfm_pci_process_otp_tuple(sc, otp[i + 0], otp[i + 1],
957ed6d4272Spatrick 		    &otp[i + 2]);
958ed6d4272Spatrick 		i += otp[i + 1];
959ed6d4272Spatrick 	}
960ed6d4272Spatrick 
961ed6d4272Spatrick 	return 0;
962ed6d4272Spatrick }
963ed6d4272Spatrick 
964ed6d4272Spatrick void
965ed6d4272Spatrick bwfm_pci_process_otp_tuple(struct bwfm_pci_softc *sc, uint8_t type, uint8_t size,
966ed6d4272Spatrick     uint8_t *data)
967ed6d4272Spatrick {
968ed6d4272Spatrick 	struct bwfm_softc *bwfm = (void *)sc;
969ed6d4272Spatrick 	char chiprev[8] = "", module[8] = "", modrev[8] = "", vendor[8] = "", chip[8] = "";
970ed6d4272Spatrick 	char product[16] = "unknown";
971*92fbeeb7Spatrick 	int len;
972ed6d4272Spatrick 
973ed6d4272Spatrick 	switch (type) {
974ed6d4272Spatrick 	case 0x15: /* system vendor OTP */
975ed6d4272Spatrick 		DPRINTF(("%s: system vendor OTP\n", DEVNAME(sc)));
976ed6d4272Spatrick 		if (size < sizeof(uint32_t))
977ed6d4272Spatrick 			return;
978ed6d4272Spatrick 		if (data[0] != 0x08 || data[1] != 0x00 ||
979ed6d4272Spatrick 		    data[2] != 0x00 || data[3] != 0x00)
980ed6d4272Spatrick 			return;
981ed6d4272Spatrick 		size -= sizeof(uint32_t);
982ed6d4272Spatrick 		data += sizeof(uint32_t);
983ed6d4272Spatrick 		while (size) {
984ed6d4272Spatrick 			/* reached end */
985ed6d4272Spatrick 			if (data[0] == 0xff)
986ed6d4272Spatrick 				break;
987ed6d4272Spatrick 			for (len = 0; len < size; len++)
988ed6d4272Spatrick 				if (data[len] == 0x00 || data[len] == ' ' ||
989ed6d4272Spatrick 				    data[len] == 0xff)
990ed6d4272Spatrick 					break;
991ed6d4272Spatrick 			if (len < 3 || len > 9) /* X=abcdef */
992ed6d4272Spatrick 				goto next;
993ed6d4272Spatrick 			if (data[1] != '=')
994ed6d4272Spatrick 				goto next;
995ed6d4272Spatrick 			/* NULL-terminate string */
996ed6d4272Spatrick 			if (data[len] == ' ')
997ed6d4272Spatrick 				data[len] = '\0';
998ed6d4272Spatrick 			switch (data[0]) {
999ed6d4272Spatrick 			case 's':
1000ed6d4272Spatrick 				strlcpy(chiprev, &data[2], sizeof(chiprev));
1001ed6d4272Spatrick 				break;
1002ed6d4272Spatrick 			case 'M':
1003ed6d4272Spatrick 				strlcpy(module, &data[2], sizeof(module));
1004ed6d4272Spatrick 				break;
1005ed6d4272Spatrick 			case 'm':
1006ed6d4272Spatrick 				strlcpy(modrev, &data[2], sizeof(modrev));
1007ed6d4272Spatrick 				break;
1008ed6d4272Spatrick 			case 'V':
1009ed6d4272Spatrick 				strlcpy(vendor, &data[2], sizeof(vendor));
1010ed6d4272Spatrick 				break;
1011ed6d4272Spatrick 			}
1012ed6d4272Spatrick next:
1013ed6d4272Spatrick 			/* skip content */
1014ed6d4272Spatrick 			data += len;
1015ed6d4272Spatrick 			size -= len;
1016ed6d4272Spatrick 			/* skip spacer tag */
1017ed6d4272Spatrick 			if (size) {
1018ed6d4272Spatrick 				data++;
1019ed6d4272Spatrick 				size--;
1020ed6d4272Spatrick 			}
1021ed6d4272Spatrick 		}
1022ed6d4272Spatrick 		snprintf(chip, sizeof(chip),
1023ed6d4272Spatrick 		    bwfm->sc_chip.ch_chip > 40000 ? "%05d" : "%04x",
1024ed6d4272Spatrick 		    bwfm->sc_chip.ch_chip);
1025*92fbeeb7Spatrick 		if (sc->sc_sc.sc_node)
1026*92fbeeb7Spatrick 			OF_getprop(sc->sc_sc.sc_node, "apple,module-instance",
1027*92fbeeb7Spatrick 			    product, sizeof(product));
1028ed6d4272Spatrick 		printf("%s: firmware C-%s%s%s/P-%s_M-%s_V-%s__m-%s\n",
1029ed6d4272Spatrick 		    DEVNAME(sc), chip,
1030ed6d4272Spatrick 		    *chiprev ? "__s-" : "", *chiprev ? chiprev : "",
1031ed6d4272Spatrick 		    product, module, vendor, modrev);
1032ed6d4272Spatrick 		break;
1033ed6d4272Spatrick 	case 0x80: /* Broadcom CIS */
1034ed6d4272Spatrick 		DPRINTF(("%s: Broadcom CIS\n", DEVNAME(sc)));
1035ed6d4272Spatrick 		break;
1036ed6d4272Spatrick 	default:
1037ed6d4272Spatrick 		DPRINTF(("%s: unknown OTP tuple\n", DEVNAME(sc)));
1038ed6d4272Spatrick 		break;
1039ed6d4272Spatrick 	}
1040ed6d4272Spatrick }
1041ed6d4272Spatrick #endif
1042ed6d4272Spatrick 
1043e5ec1e72Spatrick /* DMA code */
1044e5ec1e72Spatrick struct bwfm_pci_dmamem *
1045e5ec1e72Spatrick bwfm_pci_dmamem_alloc(struct bwfm_pci_softc *sc, bus_size_t size, bus_size_t align)
1046e5ec1e72Spatrick {
1047e5ec1e72Spatrick 	struct bwfm_pci_dmamem *bdm;
1048e5ec1e72Spatrick 	int nsegs;
1049e5ec1e72Spatrick 
1050e5ec1e72Spatrick 	bdm = malloc(sizeof(*bdm), M_DEVBUF, M_WAITOK | M_ZERO);
1051e5ec1e72Spatrick 	bdm->bdm_size = size;
1052e5ec1e72Spatrick 
1053e5ec1e72Spatrick 	if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
1054e5ec1e72Spatrick 	    BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &bdm->bdm_map) != 0)
1055e5ec1e72Spatrick 		goto bdmfree;
1056e5ec1e72Spatrick 
1057e5ec1e72Spatrick 	if (bus_dmamem_alloc(sc->sc_dmat, size, align, 0, &bdm->bdm_seg, 1,
1058e5ec1e72Spatrick 	    &nsegs, BUS_DMA_WAITOK) != 0)
1059e5ec1e72Spatrick 		goto destroy;
1060e5ec1e72Spatrick 
1061e5ec1e72Spatrick 	if (bus_dmamem_map(sc->sc_dmat, &bdm->bdm_seg, nsegs, size,
1062e5ec1e72Spatrick 	    &bdm->bdm_kva, BUS_DMA_WAITOK | BUS_DMA_COHERENT) != 0)
1063e5ec1e72Spatrick 		goto free;
1064e5ec1e72Spatrick 
1065e5ec1e72Spatrick 	if (bus_dmamap_load(sc->sc_dmat, bdm->bdm_map, bdm->bdm_kva, size,
1066e5ec1e72Spatrick 	    NULL, BUS_DMA_WAITOK) != 0)
1067e5ec1e72Spatrick 		goto unmap;
1068e5ec1e72Spatrick 
1069e5ec1e72Spatrick 	bzero(bdm->bdm_kva, size);
1070e5ec1e72Spatrick 
1071e5ec1e72Spatrick 	return (bdm);
1072e5ec1e72Spatrick 
1073e5ec1e72Spatrick unmap:
1074e5ec1e72Spatrick 	bus_dmamem_unmap(sc->sc_dmat, bdm->bdm_kva, size);
1075e5ec1e72Spatrick free:
1076e5ec1e72Spatrick 	bus_dmamem_free(sc->sc_dmat, &bdm->bdm_seg, 1);
1077e5ec1e72Spatrick destroy:
1078e5ec1e72Spatrick 	bus_dmamap_destroy(sc->sc_dmat, bdm->bdm_map);
1079e5ec1e72Spatrick bdmfree:
108065046b40Spatrick 	free(bdm, M_DEVBUF, sizeof(*bdm));
1081e5ec1e72Spatrick 
1082e5ec1e72Spatrick 	return (NULL);
1083e5ec1e72Spatrick }
1084e5ec1e72Spatrick 
1085e5ec1e72Spatrick void
1086e5ec1e72Spatrick bwfm_pci_dmamem_free(struct bwfm_pci_softc *sc, struct bwfm_pci_dmamem *bdm)
1087e5ec1e72Spatrick {
1088e5ec1e72Spatrick 	bus_dmamem_unmap(sc->sc_dmat, bdm->bdm_kva, bdm->bdm_size);
1089e5ec1e72Spatrick 	bus_dmamem_free(sc->sc_dmat, &bdm->bdm_seg, 1);
1090e5ec1e72Spatrick 	bus_dmamap_destroy(sc->sc_dmat, bdm->bdm_map);
109165046b40Spatrick 	free(bdm, M_DEVBUF, sizeof(*bdm));
1092e5ec1e72Spatrick }
1093e5ec1e72Spatrick 
1094e5ec1e72Spatrick /*
1095e5ec1e72Spatrick  * We need a simple mapping from a packet ID to mbufs, because when
1096e5ec1e72Spatrick  * a transfer completed, we only know the ID so we have to look up
1097e5ec1e72Spatrick  * the memory for the ID.  This simply looks for an empty slot.
1098e5ec1e72Spatrick  */
1099e5ec1e72Spatrick int
110002ee7d07Spatrick bwfm_pci_pktid_avail(struct bwfm_pci_softc *sc, struct bwfm_pci_pkts *pkts)
110102ee7d07Spatrick {
110202ee7d07Spatrick 	int i, idx;
110302ee7d07Spatrick 
110402ee7d07Spatrick 	idx = pkts->last + 1;
110502ee7d07Spatrick 	for (i = 0; i < pkts->npkt; i++) {
110602ee7d07Spatrick 		if (idx == pkts->npkt)
110702ee7d07Spatrick 			idx = 0;
110802ee7d07Spatrick 		if (pkts->pkts[idx].bb_m == NULL)
110902ee7d07Spatrick 			return 0;
111002ee7d07Spatrick 		idx++;
111102ee7d07Spatrick 	}
111202ee7d07Spatrick 	return ENOBUFS;
111302ee7d07Spatrick }
111402ee7d07Spatrick 
111502ee7d07Spatrick int
1116e5ec1e72Spatrick bwfm_pci_pktid_new(struct bwfm_pci_softc *sc, struct bwfm_pci_pkts *pkts,
1117e5ec1e72Spatrick     struct mbuf *m, uint32_t *pktid, paddr_t *paddr)
1118e5ec1e72Spatrick {
1119e5ec1e72Spatrick 	int i, idx;
1120e5ec1e72Spatrick 
1121e5ec1e72Spatrick 	idx = pkts->last + 1;
1122e5ec1e72Spatrick 	for (i = 0; i < pkts->npkt; i++) {
1123e5ec1e72Spatrick 		if (idx == pkts->npkt)
1124e5ec1e72Spatrick 			idx = 0;
1125e5ec1e72Spatrick 		if (pkts->pkts[idx].bb_m == NULL) {
1126e5ec1e72Spatrick 			if (bus_dmamap_load_mbuf(sc->sc_dmat,
1127e5ec1e72Spatrick 			    pkts->pkts[idx].bb_map, m, BUS_DMA_NOWAIT) != 0) {
1128518be5f3Spatrick 				if (m_defrag(m, M_DONTWAIT))
1129518be5f3Spatrick 					return EFBIG;
1130518be5f3Spatrick 				if (bus_dmamap_load_mbuf(sc->sc_dmat,
1131518be5f3Spatrick 				    pkts->pkts[idx].bb_map, m, BUS_DMA_NOWAIT) != 0)
1132518be5f3Spatrick 					return EFBIG;
1133e5ec1e72Spatrick 			}
1134dcb67343Spatrick 			bus_dmamap_sync(sc->sc_dmat, pkts->pkts[idx].bb_map,
1135dcb67343Spatrick 			    0, pkts->pkts[idx].bb_map->dm_mapsize,
1136dcb67343Spatrick 			    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1137e5ec1e72Spatrick 			pkts->last = idx;
1138e5ec1e72Spatrick 			pkts->pkts[idx].bb_m = m;
1139e5ec1e72Spatrick 			*pktid = idx;
1140e5ec1e72Spatrick 			*paddr = pkts->pkts[idx].bb_map->dm_segs[0].ds_addr;
1141e5ec1e72Spatrick 			return 0;
1142e5ec1e72Spatrick 		}
1143e5ec1e72Spatrick 		idx++;
1144e5ec1e72Spatrick 	}
1145518be5f3Spatrick 	return ENOBUFS;
1146e5ec1e72Spatrick }
1147e5ec1e72Spatrick 
1148e5ec1e72Spatrick struct mbuf *
1149e5ec1e72Spatrick bwfm_pci_pktid_free(struct bwfm_pci_softc *sc, struct bwfm_pci_pkts *pkts,
1150e5ec1e72Spatrick     uint32_t pktid)
1151e5ec1e72Spatrick {
1152e5ec1e72Spatrick 	struct mbuf *m;
1153e5ec1e72Spatrick 
1154e5ec1e72Spatrick 	if (pktid >= pkts->npkt || pkts->pkts[pktid].bb_m == NULL)
1155e5ec1e72Spatrick 		return NULL;
1156dcb67343Spatrick 	bus_dmamap_sync(sc->sc_dmat, pkts->pkts[pktid].bb_map, 0,
1157dcb67343Spatrick 	    pkts->pkts[pktid].bb_map->dm_mapsize,
1158dcb67343Spatrick 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1159e5ec1e72Spatrick 	bus_dmamap_unload(sc->sc_dmat, pkts->pkts[pktid].bb_map);
1160e5ec1e72Spatrick 	m = pkts->pkts[pktid].bb_m;
1161e5ec1e72Spatrick 	pkts->pkts[pktid].bb_m = NULL;
1162e5ec1e72Spatrick 	return m;
1163e5ec1e72Spatrick }
1164e5ec1e72Spatrick 
1165e5ec1e72Spatrick void
1166e5ec1e72Spatrick bwfm_pci_fill_rx_rings(struct bwfm_pci_softc *sc)
1167e5ec1e72Spatrick {
116818722113Spatrick 	bwfm_pci_fill_rx_buf_ring(sc);
1169e5ec1e72Spatrick 	bwfm_pci_fill_rx_ioctl_ring(sc, &sc->sc_ioctl_ring,
1170e5ec1e72Spatrick 	    MSGBUF_TYPE_IOCTLRESP_BUF_POST);
1171e5ec1e72Spatrick 	bwfm_pci_fill_rx_ioctl_ring(sc, &sc->sc_event_ring,
1172e5ec1e72Spatrick 	    MSGBUF_TYPE_EVENT_BUF_POST);
1173e5ec1e72Spatrick }
1174e5ec1e72Spatrick 
1175e5ec1e72Spatrick void
1176e5ec1e72Spatrick bwfm_pci_fill_rx_ioctl_ring(struct bwfm_pci_softc *sc, struct if_rxring *rxring,
1177e5ec1e72Spatrick     uint32_t msgtype)
1178e5ec1e72Spatrick {
1179e5ec1e72Spatrick 	struct msgbuf_rx_ioctl_resp_or_event *req;
1180e5ec1e72Spatrick 	struct mbuf *m;
1181e5ec1e72Spatrick 	uint32_t pktid;
1182e5ec1e72Spatrick 	paddr_t paddr;
1183e5ec1e72Spatrick 	int s, slots;
1184e5ec1e72Spatrick 
1185e5ec1e72Spatrick 	s = splnet();
1186e5ec1e72Spatrick 	for (slots = if_rxr_get(rxring, 8); slots > 0; slots--) {
118702ee7d07Spatrick 		if (bwfm_pci_pktid_avail(sc, &sc->sc_rx_pkts))
118802ee7d07Spatrick 			break;
1189e5ec1e72Spatrick 		req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit);
1190e5ec1e72Spatrick 		if (req == NULL)
1191e5ec1e72Spatrick 			break;
11921950c5c5Spatrick 		m = MCLGETL(NULL, M_DONTWAIT, MSGBUF_MAX_CTL_PKT_SIZE);
1193e5ec1e72Spatrick 		if (m == NULL) {
1194e5ec1e72Spatrick 			bwfm_pci_ring_write_cancel(sc, &sc->sc_ctrl_submit, 1);
1195e5ec1e72Spatrick 			break;
1196e5ec1e72Spatrick 		}
11971950c5c5Spatrick 		m->m_len = m->m_pkthdr.len = MSGBUF_MAX_CTL_PKT_SIZE;
1198e5ec1e72Spatrick 		if (bwfm_pci_pktid_new(sc, &sc->sc_rx_pkts, m, &pktid, &paddr)) {
1199e5ec1e72Spatrick 			bwfm_pci_ring_write_cancel(sc, &sc->sc_ctrl_submit, 1);
1200e5ec1e72Spatrick 			m_freem(m);
1201e5ec1e72Spatrick 			break;
1202e5ec1e72Spatrick 		}
1203e5ec1e72Spatrick 		memset(req, 0, sizeof(*req));
1204e5ec1e72Spatrick 		req->msg.msgtype = msgtype;
1205e5ec1e72Spatrick 		req->msg.request_id = htole32(pktid);
12061950c5c5Spatrick 		req->host_buf_len = htole16(MSGBUF_MAX_CTL_PKT_SIZE);
1207e4dae658Spatrick 		req->host_buf_addr.high_addr = htole32((uint64_t)paddr >> 32);
1208e5ec1e72Spatrick 		req->host_buf_addr.low_addr = htole32(paddr & 0xffffffff);
1209e5ec1e72Spatrick 		bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit);
1210e5ec1e72Spatrick 	}
1211e5ec1e72Spatrick 	if_rxr_put(rxring, slots);
1212e5ec1e72Spatrick 	splx(s);
1213e5ec1e72Spatrick }
1214e5ec1e72Spatrick 
1215e5ec1e72Spatrick void
1216e5ec1e72Spatrick bwfm_pci_fill_rx_buf_ring(struct bwfm_pci_softc *sc)
1217e5ec1e72Spatrick {
1218e5ec1e72Spatrick 	struct msgbuf_rx_bufpost *req;
1219e5ec1e72Spatrick 	struct mbuf *m;
1220e5ec1e72Spatrick 	uint32_t pktid;
1221e5ec1e72Spatrick 	paddr_t paddr;
1222e5ec1e72Spatrick 	int s, slots;
1223e5ec1e72Spatrick 
1224e5ec1e72Spatrick 	s = splnet();
1225e5ec1e72Spatrick 	for (slots = if_rxr_get(&sc->sc_rxbuf_ring, sc->sc_max_rxbufpost);
1226e5ec1e72Spatrick 	    slots > 0; slots--) {
122702ee7d07Spatrick 		if (bwfm_pci_pktid_avail(sc, &sc->sc_rx_pkts))
122802ee7d07Spatrick 			break;
1229e5ec1e72Spatrick 		req = bwfm_pci_ring_write_reserve(sc, &sc->sc_rxpost_submit);
1230e5ec1e72Spatrick 		if (req == NULL)
1231e5ec1e72Spatrick 			break;
1232471f2571Sjan 		m = MCLGETL(NULL, M_DONTWAIT, MSGBUF_MAX_PKT_SIZE);
1233e5ec1e72Spatrick 		if (m == NULL) {
1234e5ec1e72Spatrick 			bwfm_pci_ring_write_cancel(sc, &sc->sc_rxpost_submit, 1);
1235e5ec1e72Spatrick 			break;
1236e5ec1e72Spatrick 		}
1237e5ec1e72Spatrick 		m->m_len = m->m_pkthdr.len = MSGBUF_MAX_PKT_SIZE;
1238e5ec1e72Spatrick 		if (bwfm_pci_pktid_new(sc, &sc->sc_rx_pkts, m, &pktid, &paddr)) {
1239e5ec1e72Spatrick 			bwfm_pci_ring_write_cancel(sc, &sc->sc_rxpost_submit, 1);
1240e5ec1e72Spatrick 			m_freem(m);
1241e5ec1e72Spatrick 			break;
1242e5ec1e72Spatrick 		}
1243e5ec1e72Spatrick 		memset(req, 0, sizeof(*req));
1244e5ec1e72Spatrick 		req->msg.msgtype = MSGBUF_TYPE_RXBUF_POST;
1245e5ec1e72Spatrick 		req->msg.request_id = htole32(pktid);
1246e5ec1e72Spatrick 		req->data_buf_len = htole16(MSGBUF_MAX_PKT_SIZE);
1247e4dae658Spatrick 		req->data_buf_addr.high_addr = htole32((uint64_t)paddr >> 32);
1248e5ec1e72Spatrick 		req->data_buf_addr.low_addr = htole32(paddr & 0xffffffff);
1249e5ec1e72Spatrick 		bwfm_pci_ring_write_commit(sc, &sc->sc_rxpost_submit);
1250e5ec1e72Spatrick 	}
1251e5ec1e72Spatrick 	if_rxr_put(&sc->sc_rxbuf_ring, slots);
1252e5ec1e72Spatrick 	splx(s);
1253e5ec1e72Spatrick }
1254e5ec1e72Spatrick 
1255e5ec1e72Spatrick int
1256e5ec1e72Spatrick bwfm_pci_setup_ring(struct bwfm_pci_softc *sc, struct bwfm_pci_msgring *ring,
1257e5ec1e72Spatrick     int nitem, size_t itemsz, uint32_t w_idx, uint32_t r_idx,
1258e5ec1e72Spatrick     int idx, uint32_t idx_off, uint32_t *ring_mem)
1259e5ec1e72Spatrick {
1260e5ec1e72Spatrick 	ring->w_idx_addr = w_idx + idx * idx_off;
1261e5ec1e72Spatrick 	ring->r_idx_addr = r_idx + idx * idx_off;
126213f544a8Spatrick 	ring->w_ptr = 0;
126313f544a8Spatrick 	ring->r_ptr = 0;
1264e5ec1e72Spatrick 	ring->nitem = nitem;
1265e5ec1e72Spatrick 	ring->itemsz = itemsz;
1266e5ec1e72Spatrick 	bwfm_pci_ring_write_rptr(sc, ring);
1267e5ec1e72Spatrick 	bwfm_pci_ring_write_wptr(sc, ring);
1268e5ec1e72Spatrick 
1269e5ec1e72Spatrick 	ring->ring = bwfm_pci_dmamem_alloc(sc, nitem * itemsz, 8);
1270e5ec1e72Spatrick 	if (ring->ring == NULL)
1271e5ec1e72Spatrick 		return ENOMEM;
1272e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1273e5ec1e72Spatrick 	    *ring_mem + BWFM_RING_MEM_BASE_ADDR_LOW,
1274e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(ring->ring) & 0xffffffff);
1275e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1276e5ec1e72Spatrick 	    *ring_mem + BWFM_RING_MEM_BASE_ADDR_HIGH,
1277e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(ring->ring) >> 32);
1278e5ec1e72Spatrick 	bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1279e5ec1e72Spatrick 	    *ring_mem + BWFM_RING_MAX_ITEM, nitem);
1280e5ec1e72Spatrick 	bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1281e5ec1e72Spatrick 	    *ring_mem + BWFM_RING_LEN_ITEMS, itemsz);
1282e5ec1e72Spatrick 	*ring_mem = *ring_mem + BWFM_RING_MEM_SZ;
1283e5ec1e72Spatrick 	return 0;
1284e5ec1e72Spatrick }
1285e5ec1e72Spatrick 
1286518be5f3Spatrick int
1287518be5f3Spatrick bwfm_pci_setup_flowring(struct bwfm_pci_softc *sc, struct bwfm_pci_msgring *ring,
1288518be5f3Spatrick     int nitem, size_t itemsz)
1289518be5f3Spatrick {
1290518be5f3Spatrick 	ring->w_ptr = 0;
1291518be5f3Spatrick 	ring->r_ptr = 0;
1292518be5f3Spatrick 	ring->nitem = nitem;
1293518be5f3Spatrick 	ring->itemsz = itemsz;
1294518be5f3Spatrick 	bwfm_pci_ring_write_rptr(sc, ring);
1295518be5f3Spatrick 	bwfm_pci_ring_write_wptr(sc, ring);
1296518be5f3Spatrick 
1297518be5f3Spatrick 	ring->ring = bwfm_pci_dmamem_alloc(sc, nitem * itemsz, 8);
1298518be5f3Spatrick 	if (ring->ring == NULL)
1299518be5f3Spatrick 		return ENOMEM;
1300518be5f3Spatrick 	return 0;
1301518be5f3Spatrick }
1302518be5f3Spatrick 
1303e5ec1e72Spatrick /* Ring helpers */
1304e5ec1e72Spatrick void
1305e5ec1e72Spatrick bwfm_pci_ring_bell(struct bwfm_pci_softc *sc,
1306e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1307e5ec1e72Spatrick {
1308bb813cf8Spatrick 	struct bwfm_softc *bwfm = (void *)sc;
1309bb813cf8Spatrick 
1310bb813cf8Spatrick 	if (bwfm->sc_chip.ch_chip == BRCM_CC_4378_CHIP_ID)
1311bb813cf8Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1312bb813cf8Spatrick 		    BWFM_PCI_64_PCIE2REG_H2D_MAILBOX_0, 1);
1313bb813cf8Spatrick 	else
1314e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1315156d2677Spatrick 		    BWFM_PCI_PCIE2REG_H2D_MAILBOX_0, 1);
1316e5ec1e72Spatrick }
1317e5ec1e72Spatrick 
1318e5ec1e72Spatrick void
1319e5ec1e72Spatrick bwfm_pci_ring_update_rptr(struct bwfm_pci_softc *sc,
1320e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1321e5ec1e72Spatrick {
1322e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
1323e5ec1e72Spatrick 		ring->r_ptr = bus_space_read_2(sc->sc_tcm_iot,
1324e5ec1e72Spatrick 		    sc->sc_tcm_ioh, ring->r_idx_addr);
1325e5ec1e72Spatrick 	} else {
1326dcb67343Spatrick 		bus_dmamap_sync(sc->sc_dmat,
1327dcb67343Spatrick 		    BWFM_PCI_DMA_MAP(sc->sc_dma_idx_buf), ring->r_idx_addr,
1328dcb67343Spatrick 		    sizeof(uint16_t), BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1329e5ec1e72Spatrick 		ring->r_ptr = *(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf)
1330e5ec1e72Spatrick 		    + ring->r_idx_addr);
1331e5ec1e72Spatrick 	}
1332e5ec1e72Spatrick }
1333e5ec1e72Spatrick 
1334e5ec1e72Spatrick void
1335e5ec1e72Spatrick bwfm_pci_ring_update_wptr(struct bwfm_pci_softc *sc,
1336e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1337e5ec1e72Spatrick {
1338e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
1339e5ec1e72Spatrick 		ring->w_ptr = bus_space_read_2(sc->sc_tcm_iot,
1340e5ec1e72Spatrick 		    sc->sc_tcm_ioh, ring->w_idx_addr);
1341e5ec1e72Spatrick 	} else {
1342dcb67343Spatrick 		bus_dmamap_sync(sc->sc_dmat,
1343dcb67343Spatrick 		    BWFM_PCI_DMA_MAP(sc->sc_dma_idx_buf), ring->w_idx_addr,
1344dcb67343Spatrick 		    sizeof(uint16_t), BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1345e5ec1e72Spatrick 		ring->w_ptr = *(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf)
1346e5ec1e72Spatrick 		    + ring->w_idx_addr);
1347e5ec1e72Spatrick 	}
1348e5ec1e72Spatrick }
1349e5ec1e72Spatrick 
1350e5ec1e72Spatrick void
1351e5ec1e72Spatrick bwfm_pci_ring_write_rptr(struct bwfm_pci_softc *sc,
1352e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1353e5ec1e72Spatrick {
1354e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
1355e5ec1e72Spatrick 		bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1356e5ec1e72Spatrick 		    ring->r_idx_addr, ring->r_ptr);
1357e5ec1e72Spatrick 	} else {
1358e5ec1e72Spatrick 		*(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf)
1359e5ec1e72Spatrick 		    + ring->r_idx_addr) = ring->r_ptr;
1360dcb67343Spatrick 		bus_dmamap_sync(sc->sc_dmat,
1361dcb67343Spatrick 		    BWFM_PCI_DMA_MAP(sc->sc_dma_idx_buf), ring->r_idx_addr,
1362dcb67343Spatrick 		    sizeof(uint16_t), BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1363e5ec1e72Spatrick 	}
1364e5ec1e72Spatrick }
1365e5ec1e72Spatrick 
1366e5ec1e72Spatrick void
1367e5ec1e72Spatrick bwfm_pci_ring_write_wptr(struct bwfm_pci_softc *sc,
1368e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1369e5ec1e72Spatrick {
1370e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
1371e5ec1e72Spatrick 		bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1372e5ec1e72Spatrick 		    ring->w_idx_addr, ring->w_ptr);
1373e5ec1e72Spatrick 	} else {
1374e5ec1e72Spatrick 		*(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf)
1375e5ec1e72Spatrick 		    + ring->w_idx_addr) = ring->w_ptr;
1376dcb67343Spatrick 		bus_dmamap_sync(sc->sc_dmat,
1377dcb67343Spatrick 		    BWFM_PCI_DMA_MAP(sc->sc_dma_idx_buf), ring->w_idx_addr,
1378dcb67343Spatrick 		    sizeof(uint16_t), BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1379e5ec1e72Spatrick 	}
1380e5ec1e72Spatrick }
1381e5ec1e72Spatrick 
1382e5ec1e72Spatrick /*
1383e5ec1e72Spatrick  * Retrieve a free descriptor to put new stuff in, but don't commit
1384e5ec1e72Spatrick  * to it yet so we can rollback later if any error occurs.
1385e5ec1e72Spatrick  */
1386e5ec1e72Spatrick void *
1387e5ec1e72Spatrick bwfm_pci_ring_write_reserve(struct bwfm_pci_softc *sc,
1388e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1389e5ec1e72Spatrick {
1390e5ec1e72Spatrick 	int available;
1391e5ec1e72Spatrick 	char *ret;
1392e5ec1e72Spatrick 
1393e5ec1e72Spatrick 	bwfm_pci_ring_update_rptr(sc, ring);
1394e5ec1e72Spatrick 
1395e5ec1e72Spatrick 	if (ring->r_ptr > ring->w_ptr)
1396e5ec1e72Spatrick 		available = ring->r_ptr - ring->w_ptr;
1397e5ec1e72Spatrick 	else
1398e5ec1e72Spatrick 		available = ring->r_ptr + (ring->nitem - ring->w_ptr);
1399e5ec1e72Spatrick 
140030f5ada0Spatrick 	if (available <= 1)
1401e5ec1e72Spatrick 		return NULL;
1402e5ec1e72Spatrick 
1403e5ec1e72Spatrick 	ret = BWFM_PCI_DMA_KVA(ring->ring) + (ring->w_ptr * ring->itemsz);
1404e5ec1e72Spatrick 	ring->w_ptr += 1;
1405e5ec1e72Spatrick 	if (ring->w_ptr == ring->nitem)
1406e5ec1e72Spatrick 		ring->w_ptr = 0;
1407e5ec1e72Spatrick 	return ret;
1408e5ec1e72Spatrick }
1409e5ec1e72Spatrick 
1410e5ec1e72Spatrick void *
1411e5ec1e72Spatrick bwfm_pci_ring_write_reserve_multi(struct bwfm_pci_softc *sc,
1412e5ec1e72Spatrick     struct bwfm_pci_msgring *ring, int count, int *avail)
1413e5ec1e72Spatrick {
1414e5ec1e72Spatrick 	int available;
1415e5ec1e72Spatrick 	char *ret;
1416e5ec1e72Spatrick 
1417e5ec1e72Spatrick 	bwfm_pci_ring_update_rptr(sc, ring);
1418e5ec1e72Spatrick 
1419e5ec1e72Spatrick 	if (ring->r_ptr > ring->w_ptr)
1420e5ec1e72Spatrick 		available = ring->r_ptr - ring->w_ptr;
1421e5ec1e72Spatrick 	else
1422e5ec1e72Spatrick 		available = ring->r_ptr + (ring->nitem - ring->w_ptr);
1423e5ec1e72Spatrick 
142430f5ada0Spatrick 	if (available <= 1)
1425e5ec1e72Spatrick 		return NULL;
1426e5ec1e72Spatrick 
1427e5ec1e72Spatrick 	ret = BWFM_PCI_DMA_KVA(ring->ring) + (ring->w_ptr * ring->itemsz);
1428e5ec1e72Spatrick 	*avail = min(count, available - 1);
1429e5ec1e72Spatrick 	if (*avail + ring->w_ptr > ring->nitem)
1430e5ec1e72Spatrick 		*avail = ring->nitem - ring->w_ptr;
1431e5ec1e72Spatrick 	ring->w_ptr += *avail;
1432e5ec1e72Spatrick 	if (ring->w_ptr == ring->nitem)
1433e5ec1e72Spatrick 		ring->w_ptr = 0;
1434e5ec1e72Spatrick 	return ret;
1435e5ec1e72Spatrick }
1436e5ec1e72Spatrick 
1437e5ec1e72Spatrick /*
1438e5ec1e72Spatrick  * Read number of descriptors available (submitted by the firmware)
1439e5ec1e72Spatrick  * and retrieve pointer to first descriptor.
1440e5ec1e72Spatrick  */
1441e5ec1e72Spatrick void *
1442e5ec1e72Spatrick bwfm_pci_ring_read_avail(struct bwfm_pci_softc *sc,
1443e5ec1e72Spatrick     struct bwfm_pci_msgring *ring, int *avail)
1444e5ec1e72Spatrick {
1445e5ec1e72Spatrick 	bwfm_pci_ring_update_wptr(sc, ring);
1446e5ec1e72Spatrick 
1447e5ec1e72Spatrick 	if (ring->w_ptr >= ring->r_ptr)
1448e5ec1e72Spatrick 		*avail = ring->w_ptr - ring->r_ptr;
1449e5ec1e72Spatrick 	else
1450e5ec1e72Spatrick 		*avail = ring->nitem - ring->r_ptr;
1451e5ec1e72Spatrick 
1452e5ec1e72Spatrick 	if (*avail == 0)
1453e5ec1e72Spatrick 		return NULL;
1454e5ec1e72Spatrick 
1455dcb67343Spatrick 	bus_dmamap_sync(sc->sc_dmat, BWFM_PCI_DMA_MAP(ring->ring),
1456dcb67343Spatrick 	    ring->r_ptr * ring->itemsz, *avail * ring->itemsz,
1457dcb67343Spatrick 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1458e5ec1e72Spatrick 	return BWFM_PCI_DMA_KVA(ring->ring) + (ring->r_ptr * ring->itemsz);
1459e5ec1e72Spatrick }
1460e5ec1e72Spatrick 
1461e5ec1e72Spatrick /*
1462e5ec1e72Spatrick  * Let firmware know we read N descriptors.
1463e5ec1e72Spatrick  */
1464e5ec1e72Spatrick void
1465e5ec1e72Spatrick bwfm_pci_ring_read_commit(struct bwfm_pci_softc *sc,
1466e5ec1e72Spatrick     struct bwfm_pci_msgring *ring, int nitem)
1467e5ec1e72Spatrick {
1468e5ec1e72Spatrick 	ring->r_ptr += nitem;
1469e5ec1e72Spatrick 	if (ring->r_ptr == ring->nitem)
1470e5ec1e72Spatrick 		ring->r_ptr = 0;
1471e5ec1e72Spatrick 	bwfm_pci_ring_write_rptr(sc, ring);
1472e5ec1e72Spatrick }
1473e5ec1e72Spatrick 
1474e5ec1e72Spatrick /*
1475e5ec1e72Spatrick  * Let firmware know that we submitted some descriptors.
1476e5ec1e72Spatrick  */
1477e5ec1e72Spatrick void
1478e5ec1e72Spatrick bwfm_pci_ring_write_commit(struct bwfm_pci_softc *sc,
1479e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1480e5ec1e72Spatrick {
1481dcb67343Spatrick 	bus_dmamap_sync(sc->sc_dmat, BWFM_PCI_DMA_MAP(ring->ring),
1482dcb67343Spatrick 	    0, BWFM_PCI_DMA_LEN(ring->ring), BUS_DMASYNC_PREREAD |
1483dcb67343Spatrick 	    BUS_DMASYNC_PREWRITE);
1484e5ec1e72Spatrick 	bwfm_pci_ring_write_wptr(sc, ring);
1485e5ec1e72Spatrick 	bwfm_pci_ring_bell(sc, ring);
1486e5ec1e72Spatrick }
1487e5ec1e72Spatrick 
1488e5ec1e72Spatrick /*
1489e5ec1e72Spatrick  * Rollback N descriptors in case we don't actually want
1490e5ec1e72Spatrick  * to commit to it.
1491e5ec1e72Spatrick  */
1492e5ec1e72Spatrick void
1493e5ec1e72Spatrick bwfm_pci_ring_write_cancel(struct bwfm_pci_softc *sc,
1494e5ec1e72Spatrick     struct bwfm_pci_msgring *ring, int nitem)
1495e5ec1e72Spatrick {
1496e5ec1e72Spatrick 	if (ring->w_ptr == 0)
1497e5ec1e72Spatrick 		ring->w_ptr = ring->nitem - nitem;
1498e5ec1e72Spatrick 	else
1499e5ec1e72Spatrick 		ring->w_ptr -= nitem;
1500e5ec1e72Spatrick }
1501e5ec1e72Spatrick 
1502e5ec1e72Spatrick /*
1503e5ec1e72Spatrick  * Foreach written descriptor on the ring, pass the descriptor to
1504e5ec1e72Spatrick  * a message handler and let the firmware know we handled it.
1505e5ec1e72Spatrick  */
1506e5ec1e72Spatrick void
15076f241297Spatrick bwfm_pci_ring_rx(struct bwfm_pci_softc *sc, struct bwfm_pci_msgring *ring,
15086f241297Spatrick     struct mbuf_list *ml)
1509e5ec1e72Spatrick {
1510e5ec1e72Spatrick 	void *buf;
1511e5ec1e72Spatrick 	int avail, processed;
1512e5ec1e72Spatrick 
1513e5ec1e72Spatrick again:
1514e5ec1e72Spatrick 	buf = bwfm_pci_ring_read_avail(sc, ring, &avail);
1515e5ec1e72Spatrick 	if (buf == NULL)
1516e5ec1e72Spatrick 		return;
1517e5ec1e72Spatrick 
1518e5ec1e72Spatrick 	processed = 0;
1519e5ec1e72Spatrick 	while (avail) {
15206f241297Spatrick 		bwfm_pci_msg_rx(sc, buf + sc->sc_rx_dataoffset, ml);
1521e5ec1e72Spatrick 		buf += ring->itemsz;
1522e5ec1e72Spatrick 		processed++;
1523e5ec1e72Spatrick 		if (processed == 48) {
1524e5ec1e72Spatrick 			bwfm_pci_ring_read_commit(sc, ring, processed);
1525e5ec1e72Spatrick 			processed = 0;
1526e5ec1e72Spatrick 		}
1527e5ec1e72Spatrick 		avail--;
1528e5ec1e72Spatrick 	}
1529e5ec1e72Spatrick 	if (processed)
1530e5ec1e72Spatrick 		bwfm_pci_ring_read_commit(sc, ring, processed);
1531e5ec1e72Spatrick 	if (ring->r_ptr == 0)
1532e5ec1e72Spatrick 		goto again;
1533e5ec1e72Spatrick }
1534e5ec1e72Spatrick 
1535e5ec1e72Spatrick void
15366f241297Spatrick bwfm_pci_msg_rx(struct bwfm_pci_softc *sc, void *buf, struct mbuf_list *ml)
1537e5ec1e72Spatrick {
1538518be5f3Spatrick 	struct ifnet *ifp = &sc->sc_sc.sc_ic.ic_if;
1539e5ec1e72Spatrick 	struct msgbuf_ioctl_resp_hdr *resp;
1540518be5f3Spatrick 	struct msgbuf_tx_status *tx;
154118722113Spatrick 	struct msgbuf_rx_complete *rx;
1542e5ec1e72Spatrick 	struct msgbuf_rx_event *event;
1543e5ec1e72Spatrick 	struct msgbuf_common_hdr *msg;
1544518be5f3Spatrick 	struct msgbuf_flowring_create_resp *fcr;
1545a2c6ff8bSpatrick 	struct msgbuf_flowring_delete_resp *fdr;
1546b5553ee6Spatrick 	struct bwfm_cmd_flowring_create fdcmd;
1547518be5f3Spatrick 	struct bwfm_pci_msgring *ring;
1548e5ec1e72Spatrick 	struct mbuf *m;
1549518be5f3Spatrick 	int flowid;
1550e5ec1e72Spatrick 
1551e5ec1e72Spatrick 	msg = (struct msgbuf_common_hdr *)buf;
1552e5ec1e72Spatrick 	switch (msg->msgtype)
1553e5ec1e72Spatrick 	{
1554518be5f3Spatrick 	case MSGBUF_TYPE_FLOW_RING_CREATE_CMPLT:
1555518be5f3Spatrick 		fcr = (struct msgbuf_flowring_create_resp *)buf;
1556518be5f3Spatrick 		flowid = letoh16(fcr->compl_hdr.flow_ring_id);
1557518be5f3Spatrick 		if (flowid < 2)
1558518be5f3Spatrick 			break;
1559518be5f3Spatrick 		flowid -= 2;
1560518be5f3Spatrick 		if (flowid >= sc->sc_max_flowrings)
1561518be5f3Spatrick 			break;
1562518be5f3Spatrick 		ring = &sc->sc_flowrings[flowid];
1563518be5f3Spatrick 		if (ring->status != RING_OPENING)
1564518be5f3Spatrick 			break;
1565518be5f3Spatrick 		if (fcr->compl_hdr.status) {
1566518be5f3Spatrick 			printf("%s: failed to open flowring %d\n",
1567518be5f3Spatrick 			    DEVNAME(sc), flowid);
1568518be5f3Spatrick 			ring->status = RING_CLOSED;
156902ee7d07Spatrick 			if (ring->m) {
157002ee7d07Spatrick 				m_freem(ring->m);
157102ee7d07Spatrick 				ring->m = NULL;
157202ee7d07Spatrick 			}
1573518be5f3Spatrick 			ifq_restart(&ifp->if_snd);
1574518be5f3Spatrick 			break;
1575518be5f3Spatrick 		}
1576518be5f3Spatrick 		ring->status = RING_OPEN;
157702ee7d07Spatrick 		if (ring->m != NULL) {
157802ee7d07Spatrick 			m = ring->m;
157902ee7d07Spatrick 			ring->m = NULL;
158002ee7d07Spatrick 			if (bwfm_pci_txdata(&sc->sc_sc, m))
158102ee7d07Spatrick 				m_freem(ring->m);
158202ee7d07Spatrick 		}
1583518be5f3Spatrick 		ifq_restart(&ifp->if_snd);
1584518be5f3Spatrick 		break;
1585a2c6ff8bSpatrick 	case MSGBUF_TYPE_FLOW_RING_DELETE_CMPLT:
1586a2c6ff8bSpatrick 		fdr = (struct msgbuf_flowring_delete_resp *)buf;
1587a2c6ff8bSpatrick 		flowid = letoh16(fdr->compl_hdr.flow_ring_id);
1588a2c6ff8bSpatrick 		if (flowid < 2)
1589a2c6ff8bSpatrick 			break;
1590a2c6ff8bSpatrick 		flowid -= 2;
1591a2c6ff8bSpatrick 		if (flowid >= sc->sc_max_flowrings)
1592a2c6ff8bSpatrick 			break;
1593a2c6ff8bSpatrick 		ring = &sc->sc_flowrings[flowid];
1594a2c6ff8bSpatrick 		if (ring->status != RING_CLOSING)
1595a2c6ff8bSpatrick 			break;
1596a2c6ff8bSpatrick 		if (fdr->compl_hdr.status) {
1597a2c6ff8bSpatrick 			printf("%s: failed to delete flowring %d\n",
1598a2c6ff8bSpatrick 			    DEVNAME(sc), flowid);
1599a2c6ff8bSpatrick 			break;
1600a2c6ff8bSpatrick 		}
1601b5553ee6Spatrick 		fdcmd.flowid = flowid;
1602b5553ee6Spatrick 		bwfm_do_async(&sc->sc_sc, bwfm_pci_flowring_delete_cb,
1603b5553ee6Spatrick 		    &fdcmd, sizeof(fdcmd));
1604a2c6ff8bSpatrick 		break;
1605e5ec1e72Spatrick 	case MSGBUF_TYPE_IOCTLPTR_REQ_ACK:
16062eeba925Spatrick 		m = bwfm_pci_pktid_free(sc, &sc->sc_ioctl_pkts,
16072eeba925Spatrick 		    letoh32(msg->request_id));
16082eeba925Spatrick 		if (m == NULL)
16092eeba925Spatrick 			break;
16102eeba925Spatrick 		m_freem(m);
1611e5ec1e72Spatrick 		break;
1612e5ec1e72Spatrick 	case MSGBUF_TYPE_IOCTL_CMPLT:
1613e5ec1e72Spatrick 		resp = (struct msgbuf_ioctl_resp_hdr *)buf;
16142eeba925Spatrick 		bwfm_pci_msgbuf_rxioctl(sc, resp);
1615e5ec1e72Spatrick 		if_rxr_put(&sc->sc_ioctl_ring, 1);
1616e5ec1e72Spatrick 		bwfm_pci_fill_rx_rings(sc);
1617e5ec1e72Spatrick 		break;
1618e5ec1e72Spatrick 	case MSGBUF_TYPE_WL_EVENT:
1619e5ec1e72Spatrick 		event = (struct msgbuf_rx_event *)buf;
1620e5ec1e72Spatrick 		m = bwfm_pci_pktid_free(sc, &sc->sc_rx_pkts,
1621e5ec1e72Spatrick 		    letoh32(event->msg.request_id));
1622e5ec1e72Spatrick 		if (m == NULL)
1623e5ec1e72Spatrick 			break;
1624e5ec1e72Spatrick 		m_adj(m, sc->sc_rx_dataoffset);
1625f37fc236Spatrick 		m->m_len = m->m_pkthdr.len = letoh16(event->event_data_len);
16266f241297Spatrick 		bwfm_rx(&sc->sc_sc, m, ml);
1627e5ec1e72Spatrick 		if_rxr_put(&sc->sc_event_ring, 1);
1628e5ec1e72Spatrick 		bwfm_pci_fill_rx_rings(sc);
1629e5ec1e72Spatrick 		break;
1630518be5f3Spatrick 	case MSGBUF_TYPE_TX_STATUS:
1631518be5f3Spatrick 		tx = (struct msgbuf_tx_status *)buf;
1632518be5f3Spatrick 		m = bwfm_pci_pktid_free(sc, &sc->sc_tx_pkts,
1633f9ee104fSpatrick 		    letoh32(tx->msg.request_id) - 1);
1634518be5f3Spatrick 		if (m == NULL)
1635518be5f3Spatrick 			break;
1636518be5f3Spatrick 		m_freem(m);
1637c6f1636dSpatrick 		if (sc->sc_tx_pkts_full) {
1638c6f1636dSpatrick 			sc->sc_tx_pkts_full = 0;
1639c6f1636dSpatrick 			ifq_restart(&ifp->if_snd);
1640c6f1636dSpatrick 		}
1641518be5f3Spatrick 		break;
164218722113Spatrick 	case MSGBUF_TYPE_RX_CMPLT:
164318722113Spatrick 		rx = (struct msgbuf_rx_complete *)buf;
164418722113Spatrick 		m = bwfm_pci_pktid_free(sc, &sc->sc_rx_pkts,
164518722113Spatrick 		    letoh32(rx->msg.request_id));
164618722113Spatrick 		if (m == NULL)
164718722113Spatrick 			break;
164818722113Spatrick 		if (letoh16(rx->data_offset))
164918722113Spatrick 			m_adj(m, letoh16(rx->data_offset));
165018722113Spatrick 		else if (sc->sc_rx_dataoffset)
165118722113Spatrick 			m_adj(m, sc->sc_rx_dataoffset);
1652f37fc236Spatrick 		m->m_len = m->m_pkthdr.len = letoh16(rx->data_len);
16536f241297Spatrick 		bwfm_rx(&sc->sc_sc, m, ml);
165418722113Spatrick 		if_rxr_put(&sc->sc_rxbuf_ring, 1);
165518722113Spatrick 		bwfm_pci_fill_rx_rings(sc);
165618722113Spatrick 		break;
1657e5ec1e72Spatrick 	default:
1658e5ec1e72Spatrick 		printf("%s: msgtype 0x%08x\n", __func__, msg->msgtype);
1659e5ec1e72Spatrick 		break;
1660e5ec1e72Spatrick 	}
1661e5ec1e72Spatrick }
1662e5ec1e72Spatrick 
1663e5ec1e72Spatrick /* Bus core helpers */
1664e5ec1e72Spatrick void
1665e5ec1e72Spatrick bwfm_pci_select_core(struct bwfm_pci_softc *sc, int id)
1666e5ec1e72Spatrick {
1667e5ec1e72Spatrick 	struct bwfm_softc *bwfm = (void *)sc;
1668e5ec1e72Spatrick 	struct bwfm_core *core;
1669e5ec1e72Spatrick 
1670e5ec1e72Spatrick 	core = bwfm_chip_get_core(bwfm, id);
1671e5ec1e72Spatrick 	if (core == NULL) {
1672e5ec1e72Spatrick 		printf("%s: could not find core to select", DEVNAME(sc));
1673e5ec1e72Spatrick 		return;
1674e5ec1e72Spatrick 	}
1675e5ec1e72Spatrick 
1676e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag,
1677e5ec1e72Spatrick 	    BWFM_PCI_BAR0_WINDOW, core->co_base);
1678e5ec1e72Spatrick 	if (pci_conf_read(sc->sc_pc, sc->sc_tag,
1679e5ec1e72Spatrick 	    BWFM_PCI_BAR0_WINDOW) != core->co_base)
1680e5ec1e72Spatrick 		pci_conf_write(sc->sc_pc, sc->sc_tag,
1681e5ec1e72Spatrick 		    BWFM_PCI_BAR0_WINDOW, core->co_base);
1682e5ec1e72Spatrick }
1683e5ec1e72Spatrick 
1684e5ec1e72Spatrick uint32_t
1685e5ec1e72Spatrick bwfm_pci_buscore_read(struct bwfm_softc *bwfm, uint32_t reg)
1686e5ec1e72Spatrick {
1687e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1688e5ec1e72Spatrick 	uint32_t page, offset;
1689e5ec1e72Spatrick 
1690e5ec1e72Spatrick 	page = reg & ~(BWFM_PCI_BAR0_REG_SIZE - 1);
1691e5ec1e72Spatrick 	offset = reg & (BWFM_PCI_BAR0_REG_SIZE - 1);
1692e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_BAR0_WINDOW, page);
1693e5ec1e72Spatrick 	return bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh, offset);
1694e5ec1e72Spatrick }
1695e5ec1e72Spatrick 
1696e5ec1e72Spatrick void
1697e5ec1e72Spatrick bwfm_pci_buscore_write(struct bwfm_softc *bwfm, uint32_t reg, uint32_t val)
1698e5ec1e72Spatrick {
1699e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1700e5ec1e72Spatrick 	uint32_t page, offset;
1701e5ec1e72Spatrick 
1702e5ec1e72Spatrick 	page = reg & ~(BWFM_PCI_BAR0_REG_SIZE - 1);
1703e5ec1e72Spatrick 	offset = reg & (BWFM_PCI_BAR0_REG_SIZE - 1);
1704e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_BAR0_WINDOW, page);
1705e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, offset, val);
1706e5ec1e72Spatrick }
1707e5ec1e72Spatrick 
1708e5ec1e72Spatrick int
1709e5ec1e72Spatrick bwfm_pci_buscore_prepare(struct bwfm_softc *bwfm)
1710e5ec1e72Spatrick {
1711e5ec1e72Spatrick 	return 0;
1712e5ec1e72Spatrick }
1713e5ec1e72Spatrick 
1714e5ec1e72Spatrick int
1715e5ec1e72Spatrick bwfm_pci_buscore_reset(struct bwfm_softc *bwfm)
1716e5ec1e72Spatrick {
1717e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1718e5ec1e72Spatrick 	struct bwfm_core *core;
1719e5ec1e72Spatrick 	uint32_t reg;
1720e5ec1e72Spatrick 	int i;
1721e5ec1e72Spatrick 
1722e5ec1e72Spatrick 	bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2);
1723e5ec1e72Spatrick 	reg = pci_conf_read(sc->sc_pc, sc->sc_tag,
1724e5ec1e72Spatrick 	    BWFM_PCI_CFGREG_LINK_STATUS_CTRL);
1725e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_CFGREG_LINK_STATUS_CTRL,
1726e5ec1e72Spatrick 	    reg & ~BWFM_PCI_CFGREG_LINK_STATUS_CTRL_ASPM_ENAB);
1727e5ec1e72Spatrick 
1728e5ec1e72Spatrick 	bwfm_pci_select_core(sc, BWFM_AGENT_CORE_CHIPCOMMON);
1729e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1730e5ec1e72Spatrick 	    BWFM_CHIP_REG_WATCHDOG, 4);
1731e5ec1e72Spatrick 	delay(100 * 1000);
1732e5ec1e72Spatrick 
1733e5ec1e72Spatrick 	bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2);
1734e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag,
1735e5ec1e72Spatrick 	    BWFM_PCI_CFGREG_LINK_STATUS_CTRL, reg);
1736e5ec1e72Spatrick 
1737e5ec1e72Spatrick 	core = bwfm_chip_get_core(bwfm, BWFM_AGENT_CORE_PCIE2);
1738e5ec1e72Spatrick 	if (core->co_rev <= 13) {
1739e5ec1e72Spatrick 		uint16_t cfg_offset[] = {
1740e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_STATUS_CMD,
1741e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_PM_CSR,
1742e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_MSI_CAP,
1743e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_MSI_ADDR_L,
1744e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_MSI_ADDR_H,
1745e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_MSI_DATA,
1746e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_LINK_STATUS_CTRL2,
1747e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_RBAR_CTRL,
1748e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_PML1_SUB_CTRL1,
1749e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_REG_BAR2_CONFIG,
1750e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_REG_BAR3_CONFIG,
1751e5ec1e72Spatrick 		};
1752e5ec1e72Spatrick 
1753e5ec1e72Spatrick 		for (i = 0; i < nitems(cfg_offset); i++) {
1754e5ec1e72Spatrick 			bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1755e5ec1e72Spatrick 			    BWFM_PCI_PCIE2REG_CONFIGADDR, cfg_offset[i]);
1756e5ec1e72Spatrick 			reg = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1757e5ec1e72Spatrick 			    BWFM_PCI_PCIE2REG_CONFIGDATA);
1758e5ec1e72Spatrick 			DPRINTFN(3, ("%s: config offset 0x%04x, value 0x%04x\n",
1759e5ec1e72Spatrick 			    DEVNAME(sc), cfg_offset[i], reg));
1760e5ec1e72Spatrick 			bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1761e5ec1e72Spatrick 			    BWFM_PCI_PCIE2REG_CONFIGDATA, reg);
1762e5ec1e72Spatrick 		}
1763e5ec1e72Spatrick 	}
1764e5ec1e72Spatrick 
1765bb813cf8Spatrick 	reg = bwfm_pci_intr_status(sc);
1766e5ec1e72Spatrick 	if (reg != 0xffffffff)
1767bb813cf8Spatrick 		bwfm_pci_intr_ack(sc, reg);
1768e5ec1e72Spatrick 
1769e5ec1e72Spatrick 	return 0;
1770e5ec1e72Spatrick }
1771e5ec1e72Spatrick 
1772e5ec1e72Spatrick void
1773e5ec1e72Spatrick bwfm_pci_buscore_activate(struct bwfm_softc *bwfm, uint32_t rstvec)
1774e5ec1e72Spatrick {
1775e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1776e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 0, rstvec);
1777e5ec1e72Spatrick }
1778e5ec1e72Spatrick 
1779f67437f3Spatrick static int bwfm_pci_prio2fifo[8] = {
17809e2c067eSpatrick 	0, /* best effort */
17819e2c067eSpatrick 	1, /* IPTOS_PREC_IMMEDIATE */
17829e2c067eSpatrick 	1, /* IPTOS_PREC_PRIORITY */
17839e2c067eSpatrick 	0, /* IPTOS_PREC_FLASH */
1784f67437f3Spatrick 	2, /* IPTOS_PREC_FLASHOVERRIDE */
1785f67437f3Spatrick 	2, /* IPTOS_PREC_CRITIC_ECP */
1786f67437f3Spatrick 	3, /* IPTOS_PREC_INTERNETCONTROL */
1787f67437f3Spatrick 	3, /* IPTOS_PREC_NETCONTROL */
1788f67437f3Spatrick };
1789f67437f3Spatrick 
1790f67437f3Spatrick int
1791f67437f3Spatrick bwfm_pci_flowring_lookup(struct bwfm_pci_softc *sc, struct mbuf *m)
1792518be5f3Spatrick {
1793f67437f3Spatrick 	struct ieee80211com *ic = &sc->sc_sc.sc_ic;
1794e6abcda3Smlarkin #ifndef IEEE80211_STA_ONLY
1795f67437f3Spatrick 	uint8_t *da = mtod(m, uint8_t *);
1796e6abcda3Smlarkin #endif
1797f67437f3Spatrick 	int flowid, prio, fifo;
1798f67437f3Spatrick 	int i, found;
1799f67437f3Spatrick 
1800f67437f3Spatrick 	prio = ieee80211_classify(ic, m);
1801f67437f3Spatrick 	fifo = bwfm_pci_prio2fifo[prio];
1802f67437f3Spatrick 
1803f67437f3Spatrick 	switch (ic->ic_opmode)
1804f67437f3Spatrick 	{
1805f67437f3Spatrick 	case IEEE80211_M_STA:
1806f67437f3Spatrick 		flowid = fifo;
1807f67437f3Spatrick 		break;
1808f67437f3Spatrick #ifndef IEEE80211_STA_ONLY
1809f67437f3Spatrick 	case IEEE80211_M_HOSTAP:
18102b7bea7eSpatrick 		if (ETHER_IS_MULTICAST(da))
18112b7bea7eSpatrick 			da = etherbroadcastaddr;
1812f67437f3Spatrick 		flowid = da[5] * 2 + fifo;
1813f67437f3Spatrick 		break;
1814f67437f3Spatrick #endif
1815f67437f3Spatrick 	default:
1816f67437f3Spatrick 		printf("%s: state not supported\n", DEVNAME(sc));
1817f67437f3Spatrick 		return ENOBUFS;
1818f67437f3Spatrick 	}
1819f67437f3Spatrick 
1820f67437f3Spatrick 	found = 0;
1821f67437f3Spatrick 	flowid = flowid % sc->sc_max_flowrings;
1822f67437f3Spatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
1823f67437f3Spatrick 		if (ic->ic_opmode == IEEE80211_M_STA &&
1824f67437f3Spatrick 		    sc->sc_flowrings[flowid].status >= RING_OPEN &&
1825f67437f3Spatrick 		    sc->sc_flowrings[flowid].fifo == fifo) {
1826f67437f3Spatrick 			found = 1;
1827f67437f3Spatrick 			break;
1828f67437f3Spatrick 		}
1829f67437f3Spatrick #ifndef IEEE80211_STA_ONLY
1830f67437f3Spatrick 		if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
1831f67437f3Spatrick 		    sc->sc_flowrings[flowid].status >= RING_OPEN &&
1832f67437f3Spatrick 		    sc->sc_flowrings[flowid].fifo == fifo &&
1833a2c6ff8bSpatrick 		    !memcmp(sc->sc_flowrings[flowid].mac, da, ETHER_ADDR_LEN)) {
1834f67437f3Spatrick 			found = 1;
1835f67437f3Spatrick 			break;
1836f67437f3Spatrick 		}
1837f67437f3Spatrick #endif
1838f67437f3Spatrick 		flowid = (flowid + 1) % sc->sc_max_flowrings;
1839f67437f3Spatrick 	}
1840f67437f3Spatrick 
1841f67437f3Spatrick 	if (found)
1842f67437f3Spatrick 		return flowid;
1843f67437f3Spatrick 
1844f67437f3Spatrick 	return -1;
1845f67437f3Spatrick }
1846f67437f3Spatrick 
1847f67437f3Spatrick void
1848f67437f3Spatrick bwfm_pci_flowring_create(struct bwfm_pci_softc *sc, struct mbuf *m)
1849f67437f3Spatrick {
1850f67437f3Spatrick 	struct ieee80211com *ic = &sc->sc_sc.sc_ic;
1851518be5f3Spatrick 	struct bwfm_cmd_flowring_create cmd;
1852e6abcda3Smlarkin #ifndef IEEE80211_STA_ONLY
1853f67437f3Spatrick 	uint8_t *da = mtod(m, uint8_t *);
1854e6abcda3Smlarkin #endif
185502ee7d07Spatrick 	struct bwfm_pci_msgring *ring;
1856f67437f3Spatrick 	int flowid, prio, fifo;
1857f67437f3Spatrick 	int i, found;
1858f67437f3Spatrick 
1859f67437f3Spatrick 	prio = ieee80211_classify(ic, m);
1860f67437f3Spatrick 	fifo = bwfm_pci_prio2fifo[prio];
1861f67437f3Spatrick 
1862f67437f3Spatrick 	switch (ic->ic_opmode)
1863f67437f3Spatrick 	{
1864f67437f3Spatrick 	case IEEE80211_M_STA:
1865f67437f3Spatrick 		flowid = fifo;
1866f67437f3Spatrick 		break;
1867f67437f3Spatrick #ifndef IEEE80211_STA_ONLY
1868f67437f3Spatrick 	case IEEE80211_M_HOSTAP:
18692b7bea7eSpatrick 		if (ETHER_IS_MULTICAST(da))
18702b7bea7eSpatrick 			da = etherbroadcastaddr;
1871f67437f3Spatrick 		flowid = da[5] * 2 + fifo;
1872f67437f3Spatrick 		break;
1873f67437f3Spatrick #endif
1874f67437f3Spatrick 	default:
1875f67437f3Spatrick 		printf("%s: state not supported\n", DEVNAME(sc));
1876f67437f3Spatrick 		return;
1877f67437f3Spatrick 	}
1878f67437f3Spatrick 
1879f67437f3Spatrick 	found = 0;
1880f67437f3Spatrick 	flowid = flowid % sc->sc_max_flowrings;
1881f67437f3Spatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
188202ee7d07Spatrick 		ring = &sc->sc_flowrings[flowid];
188302ee7d07Spatrick 		if (ring->status == RING_CLOSED) {
188402ee7d07Spatrick 			ring->status = RING_OPENING;
1885f67437f3Spatrick 			found = 1;
1886f67437f3Spatrick 			break;
1887f67437f3Spatrick 		}
1888f67437f3Spatrick 		flowid = (flowid + 1) % sc->sc_max_flowrings;
1889f67437f3Spatrick 	}
1890f67437f3Spatrick 
189102ee7d07Spatrick 	/*
189202ee7d07Spatrick 	 * We cannot recover from that so far.  Only a stop/init
189302ee7d07Spatrick 	 * cycle can revive this if it ever happens at all.
189402ee7d07Spatrick 	 */
1895f67437f3Spatrick 	if (!found) {
1896f67437f3Spatrick 		printf("%s: no flowring available\n", DEVNAME(sc));
1897f67437f3Spatrick 		return;
1898f67437f3Spatrick 	}
1899f67437f3Spatrick 
190002ee7d07Spatrick 	cmd.m = m;
1901f67437f3Spatrick 	cmd.prio = prio;
1902518be5f3Spatrick 	cmd.flowid = flowid;
1903518be5f3Spatrick 	bwfm_do_async(&sc->sc_sc, bwfm_pci_flowring_create_cb, &cmd, sizeof(cmd));
1904518be5f3Spatrick }
1905518be5f3Spatrick 
1906518be5f3Spatrick void
1907518be5f3Spatrick bwfm_pci_flowring_create_cb(struct bwfm_softc *bwfm, void *arg)
1908518be5f3Spatrick {
1909518be5f3Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1910e6abcda3Smlarkin #ifndef IEEE80211_STA_ONLY
19112b7bea7eSpatrick 	struct ieee80211com *ic = &sc->sc_sc.sc_ic;
1912e6abcda3Smlarkin #endif
1913518be5f3Spatrick 	struct bwfm_cmd_flowring_create *cmd = arg;
1914518be5f3Spatrick 	struct msgbuf_tx_flowring_create_req *req;
1915518be5f3Spatrick 	struct bwfm_pci_msgring *ring;
191602ee7d07Spatrick 	uint8_t *da, *sa;
1917e272db29Spatrick 	int s;
1918518be5f3Spatrick 
191902ee7d07Spatrick 	da = mtod(cmd->m, char *) + 0 * ETHER_ADDR_LEN;
192002ee7d07Spatrick 	sa = mtod(cmd->m, char *) + 1 * ETHER_ADDR_LEN;
1921518be5f3Spatrick 
192202ee7d07Spatrick 	ring = &sc->sc_flowrings[cmd->flowid];
192302ee7d07Spatrick 	if (ring->status != RING_OPENING) {
192402ee7d07Spatrick 		printf("%s: flowring not opening\n", DEVNAME(sc));
1925518be5f3Spatrick 		return;
1926f67437f3Spatrick 	}
1927f67437f3Spatrick 
1928f67437f3Spatrick 	if (bwfm_pci_setup_flowring(sc, ring, 512, 48)) {
1929f67437f3Spatrick 		printf("%s: cannot setup flowring\n", DEVNAME(sc));
1930f67437f3Spatrick 		return;
1931f67437f3Spatrick 	}
1932518be5f3Spatrick 
1933e272db29Spatrick 	s = splnet();
1934518be5f3Spatrick 	req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit);
1935f67437f3Spatrick 	if (req == NULL) {
1936f67437f3Spatrick 		printf("%s: cannot reserve for flowring\n", DEVNAME(sc));
1937e272db29Spatrick 		splx(s);
1938518be5f3Spatrick 		return;
1939f67437f3Spatrick 	}
1940518be5f3Spatrick 
1941518be5f3Spatrick 	ring->status = RING_OPENING;
194202ee7d07Spatrick 	ring->fifo = bwfm_pci_prio2fifo[cmd->prio];
194302ee7d07Spatrick 	ring->m = cmd->m;
194402ee7d07Spatrick 	memcpy(ring->mac, da, ETHER_ADDR_LEN);
19452b7bea7eSpatrick #ifndef IEEE80211_STA_ONLY
194602ee7d07Spatrick 	if (ic->ic_opmode == IEEE80211_M_HOSTAP && ETHER_IS_MULTICAST(da))
19472b7bea7eSpatrick 		memcpy(ring->mac, etherbroadcastaddr, ETHER_ADDR_LEN);
19482b7bea7eSpatrick #endif
1949f67437f3Spatrick 
1950518be5f3Spatrick 	req->msg.msgtype = MSGBUF_TYPE_FLOW_RING_CREATE;
1951518be5f3Spatrick 	req->msg.ifidx = 0;
1952518be5f3Spatrick 	req->msg.request_id = 0;
195302ee7d07Spatrick 	req->tid = bwfm_pci_prio2fifo[cmd->prio];
195402ee7d07Spatrick 	req->flow_ring_id = letoh16(cmd->flowid + 2);
195502ee7d07Spatrick 	memcpy(req->da, da, ETHER_ADDR_LEN);
195602ee7d07Spatrick 	memcpy(req->sa, sa, ETHER_ADDR_LEN);
1957518be5f3Spatrick 	req->flow_ring_addr.high_addr =
1958518be5f3Spatrick 	    letoh32(BWFM_PCI_DMA_DVA(ring->ring) >> 32);
1959518be5f3Spatrick 	req->flow_ring_addr.low_addr =
1960518be5f3Spatrick 	    letoh32(BWFM_PCI_DMA_DVA(ring->ring) & 0xffffffff);
1961518be5f3Spatrick 	req->max_items = letoh16(512);
1962518be5f3Spatrick 	req->len_item = letoh16(48);
1963518be5f3Spatrick 
1964518be5f3Spatrick 	bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit);
1965e272db29Spatrick 	splx(s);
1966518be5f3Spatrick }
1967518be5f3Spatrick 
1968a2c6ff8bSpatrick void
1969a2c6ff8bSpatrick bwfm_pci_flowring_delete(struct bwfm_pci_softc *sc, int flowid)
1970a2c6ff8bSpatrick {
1971a2c6ff8bSpatrick 	struct msgbuf_tx_flowring_delete_req *req;
1972a2c6ff8bSpatrick 	struct bwfm_pci_msgring *ring;
1973e272db29Spatrick 	int s;
1974a2c6ff8bSpatrick 
1975a2c6ff8bSpatrick 	ring = &sc->sc_flowrings[flowid];
1976a2c6ff8bSpatrick 	if (ring->status != RING_OPEN) {
1977a2c6ff8bSpatrick 		printf("%s: flowring not open\n", DEVNAME(sc));
1978a2c6ff8bSpatrick 		return;
1979a2c6ff8bSpatrick 	}
1980a2c6ff8bSpatrick 
1981e272db29Spatrick 	s = splnet();
1982a2c6ff8bSpatrick 	req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit);
1983a2c6ff8bSpatrick 	if (req == NULL) {
1984a2c6ff8bSpatrick 		printf("%s: cannot reserve for flowring\n", DEVNAME(sc));
1985e272db29Spatrick 		splx(s);
1986a2c6ff8bSpatrick 		return;
1987a2c6ff8bSpatrick 	}
1988a2c6ff8bSpatrick 
1989a2c6ff8bSpatrick 	ring->status = RING_CLOSING;
1990a2c6ff8bSpatrick 
1991a2c6ff8bSpatrick 	req->msg.msgtype = MSGBUF_TYPE_FLOW_RING_DELETE;
1992a2c6ff8bSpatrick 	req->msg.ifidx = 0;
1993a2c6ff8bSpatrick 	req->msg.request_id = 0;
1994a2c6ff8bSpatrick 	req->flow_ring_id = letoh16(flowid + 2);
1995a2c6ff8bSpatrick 	req->reason = 0;
1996a2c6ff8bSpatrick 
1997a2c6ff8bSpatrick 	bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit);
1998e272db29Spatrick 	splx(s);
1999a2c6ff8bSpatrick }
2000a2c6ff8bSpatrick 
2001a2c6ff8bSpatrick void
2002b5553ee6Spatrick bwfm_pci_flowring_delete_cb(struct bwfm_softc *bwfm, void *arg)
2003b5553ee6Spatrick {
2004b5553ee6Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
2005b5553ee6Spatrick 	struct bwfm_cmd_flowring_create *cmd = arg;
2006b5553ee6Spatrick 	struct bwfm_pci_msgring *ring;
2007b5553ee6Spatrick 
2008b5553ee6Spatrick 	ring = &sc->sc_flowrings[cmd->flowid];
2009b5553ee6Spatrick 	bwfm_pci_dmamem_free(sc, ring->ring);
2010b5553ee6Spatrick 	ring->status = RING_CLOSED;
2011b5553ee6Spatrick }
2012b5553ee6Spatrick 
2013b5553ee6Spatrick void
2014a2c6ff8bSpatrick bwfm_pci_stop(struct bwfm_softc *bwfm)
2015a2c6ff8bSpatrick {
2016a2c6ff8bSpatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
2017a2c6ff8bSpatrick 	struct bwfm_pci_msgring *ring;
2018a2c6ff8bSpatrick 	int i;
2019a2c6ff8bSpatrick 
2020a2c6ff8bSpatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
2021a2c6ff8bSpatrick 		ring = &sc->sc_flowrings[i];
2022a2c6ff8bSpatrick 		if (ring->status == RING_OPEN)
2023a2c6ff8bSpatrick 			bwfm_pci_flowring_delete(sc, i);
2024a2c6ff8bSpatrick 	}
2025a2c6ff8bSpatrick }
2026a2c6ff8bSpatrick 
2027e5ec1e72Spatrick int
202802ee7d07Spatrick bwfm_pci_txcheck(struct bwfm_softc *bwfm)
202902ee7d07Spatrick {
203002ee7d07Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
203102ee7d07Spatrick 	struct bwfm_pci_msgring *ring;
203202ee7d07Spatrick 	int i;
203302ee7d07Spatrick 
203402ee7d07Spatrick 	/* If we are transitioning, we cannot send. */
203502ee7d07Spatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
203602ee7d07Spatrick 		ring = &sc->sc_flowrings[i];
203702ee7d07Spatrick 		if (ring->status == RING_OPENING)
203802ee7d07Spatrick 			return ENOBUFS;
203902ee7d07Spatrick 	}
204002ee7d07Spatrick 
204102ee7d07Spatrick 	if (bwfm_pci_pktid_avail(sc, &sc->sc_tx_pkts)) {
204202ee7d07Spatrick 		sc->sc_tx_pkts_full = 1;
204302ee7d07Spatrick 		return ENOBUFS;
204402ee7d07Spatrick 	}
204502ee7d07Spatrick 
204602ee7d07Spatrick 	return 0;
204702ee7d07Spatrick }
204802ee7d07Spatrick 
204902ee7d07Spatrick int
2050e5ec1e72Spatrick bwfm_pci_txdata(struct bwfm_softc *bwfm, struct mbuf *m)
2051e5ec1e72Spatrick {
2052e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
2053518be5f3Spatrick 	struct bwfm_pci_msgring *ring;
2054518be5f3Spatrick 	struct msgbuf_tx_msghdr *tx;
2055518be5f3Spatrick 	uint32_t pktid;
2056518be5f3Spatrick 	paddr_t paddr;
2057518be5f3Spatrick 	int flowid, ret;
2058518be5f3Spatrick 
2059f67437f3Spatrick 	flowid = bwfm_pci_flowring_lookup(sc, m);
2060f67437f3Spatrick 	if (flowid < 0) {
206102ee7d07Spatrick 		/*
206202ee7d07Spatrick 		 * We cannot send the packet right now as there is
206302ee7d07Spatrick 		 * no flowring yet.  The flowring will be created
206402ee7d07Spatrick 		 * asynchronously.  While the ring is transitioning
206502ee7d07Spatrick 		 * the TX check will tell the upper layers that we
206602ee7d07Spatrick 		 * cannot send packets right now.  When the flowring
206702ee7d07Spatrick 		 * is created the queue will be restarted and this
206802ee7d07Spatrick 		 * mbuf will be transmitted.
206902ee7d07Spatrick 		 */
2070f67437f3Spatrick 		bwfm_pci_flowring_create(sc, m);
207102ee7d07Spatrick 		return 0;
2072f67437f3Spatrick 	}
2073518be5f3Spatrick 
2074518be5f3Spatrick 	ring = &sc->sc_flowrings[flowid];
2075518be5f3Spatrick 	if (ring->status == RING_OPENING ||
2076f67437f3Spatrick 	    ring->status == RING_CLOSING) {
2077f67437f3Spatrick 		printf("%s: tried to use a flow that was "
2078f67437f3Spatrick 		    "transitioning in status %d\n",
2079f67437f3Spatrick 		    DEVNAME(sc), ring->status);
2080518be5f3Spatrick 		return ENOBUFS;
2081518be5f3Spatrick 	}
2082518be5f3Spatrick 
2083518be5f3Spatrick 	tx = bwfm_pci_ring_write_reserve(sc, ring);
2084518be5f3Spatrick 	if (tx == NULL)
2085518be5f3Spatrick 		return ENOBUFS;
2086518be5f3Spatrick 
2087518be5f3Spatrick 	memset(tx, 0, sizeof(*tx));
2088518be5f3Spatrick 	tx->msg.msgtype = MSGBUF_TYPE_TX_POST;
2089518be5f3Spatrick 	tx->msg.ifidx = 0;
2090518be5f3Spatrick 	tx->flags = BWFM_MSGBUF_PKT_FLAGS_FRAME_802_3;
2091518be5f3Spatrick 	tx->flags |= ieee80211_classify(&sc->sc_sc.sc_ic, m) <<
2092518be5f3Spatrick 	    BWFM_MSGBUF_PKT_FLAGS_PRIO_SHIFT;
2093518be5f3Spatrick 	tx->seg_cnt = 1;
2094518be5f3Spatrick 	memcpy(tx->txhdr, mtod(m, char *), ETHER_HDR_LEN);
2095518be5f3Spatrick 
2096518be5f3Spatrick 	ret = bwfm_pci_pktid_new(sc, &sc->sc_tx_pkts, m, &pktid, &paddr);
2097518be5f3Spatrick 	if (ret) {
209802ee7d07Spatrick 		if (ret == ENOBUFS) {
209902ee7d07Spatrick 			printf("%s: no pktid available for TX\n",
210002ee7d07Spatrick 			    DEVNAME(sc));
2101c6f1636dSpatrick 			sc->sc_tx_pkts_full = 1;
210202ee7d07Spatrick 		}
2103518be5f3Spatrick 		bwfm_pci_ring_write_cancel(sc, ring, 1);
2104518be5f3Spatrick 		return ret;
2105518be5f3Spatrick 	}
2106518be5f3Spatrick 	paddr += ETHER_HDR_LEN;
2107518be5f3Spatrick 
2108f9ee104fSpatrick 	tx->msg.request_id = htole32(pktid + 1);
21094ff787bcSpatrick 	tx->data_len = htole16(m->m_len - ETHER_HDR_LEN);
2110e4dae658Spatrick 	tx->data_buf_addr.high_addr = htole32((uint64_t)paddr >> 32);
2111518be5f3Spatrick 	tx->data_buf_addr.low_addr = htole32(paddr & 0xffffffff);
2112518be5f3Spatrick 
2113518be5f3Spatrick 	bwfm_pci_ring_write_commit(sc, ring);
2114518be5f3Spatrick 	return 0;
2115e5ec1e72Spatrick }
2116e5ec1e72Spatrick 
21171a93a9bdSpatrick int
21181a93a9bdSpatrick bwfm_pci_send_mb_data(struct bwfm_pci_softc *sc, uint32_t htod_mb_data)
21191a93a9bdSpatrick {
21201a93a9bdSpatrick 	struct bwfm_softc *bwfm = (void *)sc;
21211a93a9bdSpatrick 	struct bwfm_core *core;
21221a93a9bdSpatrick 	uint32_t reg;
21231a93a9bdSpatrick 	int i;
21241a93a9bdSpatrick 
21251a93a9bdSpatrick 	for (i = 0; i < 100; i++) {
21261a93a9bdSpatrick 		reg = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
21271a93a9bdSpatrick 		    sc->sc_htod_mb_data_addr);
21281a93a9bdSpatrick 		if (reg == 0)
21291a93a9bdSpatrick 			break;
21301a93a9bdSpatrick 		delay(10 * 1000);
21311a93a9bdSpatrick 	}
21321a93a9bdSpatrick 	if (i == 100) {
21331a93a9bdSpatrick 		DPRINTF(("%s: MB transaction already pending\n", DEVNAME(sc)));
21341a93a9bdSpatrick 		return EIO;
21351a93a9bdSpatrick 	}
21361a93a9bdSpatrick 
21371a93a9bdSpatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
21381a93a9bdSpatrick 	    sc->sc_htod_mb_data_addr, htod_mb_data);
21391a93a9bdSpatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_REG_SBMBX, 1);
21401a93a9bdSpatrick 
21411a93a9bdSpatrick 	core = bwfm_chip_get_core(bwfm, BWFM_AGENT_CORE_PCIE2);
21421a93a9bdSpatrick 	if (core->co_rev <= 13)
21431a93a9bdSpatrick 		pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_REG_SBMBX, 1);
21441a93a9bdSpatrick 
21451a93a9bdSpatrick 	return 0;
21461a93a9bdSpatrick }
21471a93a9bdSpatrick 
21481a93a9bdSpatrick void
21491a93a9bdSpatrick bwfm_pci_handle_mb_data(struct bwfm_pci_softc *sc)
21501a93a9bdSpatrick {
21511a93a9bdSpatrick 	uint32_t reg;
21521a93a9bdSpatrick 
21531a93a9bdSpatrick 	reg = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
21541a93a9bdSpatrick 	    sc->sc_dtoh_mb_data_addr);
21551a93a9bdSpatrick 	if (reg == 0)
21561a93a9bdSpatrick 		return;
21571a93a9bdSpatrick 
21581a93a9bdSpatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
21591a93a9bdSpatrick 	    sc->sc_dtoh_mb_data_addr, 0);
21601a93a9bdSpatrick 
21611a93a9bdSpatrick 	if (reg & BWFM_PCI_D2H_DEV_D3_ACK) {
21621a93a9bdSpatrick 		sc->sc_mbdata_done = 1;
21631a93a9bdSpatrick 		wakeup(&sc->sc_mbdata_done);
21641a93a9bdSpatrick 	}
21651a93a9bdSpatrick 
21661a93a9bdSpatrick 	/* TODO: support more events */
21671a93a9bdSpatrick 	if (reg & ~BWFM_PCI_D2H_DEV_D3_ACK)
21681a93a9bdSpatrick 		printf("%s: handle MB data 0x%08x\n", DEVNAME(sc), reg);
21691a93a9bdSpatrick }
21701a93a9bdSpatrick 
2171bbd71b0bSpatrick #ifdef BWFM_DEBUG
2172cadf5fcfSpatrick void
2173cadf5fcfSpatrick bwfm_pci_debug_console(struct bwfm_pci_softc *sc)
2174cadf5fcfSpatrick {
2175cadf5fcfSpatrick 	uint32_t newidx = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
2176cadf5fcfSpatrick 	    sc->sc_console_base_addr + BWFM_CONSOLE_WRITEIDX);
2177cadf5fcfSpatrick 
2178cadf5fcfSpatrick 	if (newidx != sc->sc_console_readidx)
2179bbd71b0bSpatrick 		DPRINTFN(3, ("BWFM CONSOLE: "));
2180cadf5fcfSpatrick 	while (newidx != sc->sc_console_readidx) {
2181cadf5fcfSpatrick 		uint8_t ch = bus_space_read_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
2182cadf5fcfSpatrick 		    sc->sc_console_buf_addr + sc->sc_console_readidx);
2183cadf5fcfSpatrick 		sc->sc_console_readidx++;
2184cadf5fcfSpatrick 		if (sc->sc_console_readidx == sc->sc_console_buf_size)
2185cadf5fcfSpatrick 			sc->sc_console_readidx = 0;
2186cadf5fcfSpatrick 		if (ch == '\r')
2187cadf5fcfSpatrick 			continue;
2188bbd71b0bSpatrick 		DPRINTFN(3, ("%c", ch));
2189cadf5fcfSpatrick 	}
2190cadf5fcfSpatrick }
2191bbd71b0bSpatrick #endif
2192cadf5fcfSpatrick 
2193e5ec1e72Spatrick int
2194e5ec1e72Spatrick bwfm_pci_intr(void *v)
2195e5ec1e72Spatrick {
2196e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)v;
2197bb813cf8Spatrick 	struct bwfm_softc *bwfm = (void *)sc;
21986f241297Spatrick 	struct ifnet *ifp = &sc->sc_sc.sc_ic.ic_if;
21996f241297Spatrick 	struct mbuf_list ml = MBUF_LIST_INITIALIZER();
2200bb813cf8Spatrick 	uint32_t status, mask;
2201e5ec1e72Spatrick 
2202bb813cf8Spatrick 	if (!sc->sc_initialized)
2203bb813cf8Spatrick 		return 0;
2204bb813cf8Spatrick 
2205bb813cf8Spatrick 	status = bwfm_pci_intr_status(sc);
2206bb813cf8Spatrick 	/* FIXME: interrupt status seems to be zero? */
2207bb813cf8Spatrick 	if (status == 0 && bwfm->sc_chip.ch_chip == BRCM_CC_4378_CHIP_ID)
2208bb813cf8Spatrick 		status |= BWFM_PCI_64_PCIE2REG_MAILBOXMASK_INT_D2H_DB;
2209bb813cf8Spatrick 	if (status == 0)
2210e5ec1e72Spatrick 		return 0;
2211e5ec1e72Spatrick 
2212e5ec1e72Spatrick 	bwfm_pci_intr_disable(sc);
2213bb813cf8Spatrick 	bwfm_pci_intr_ack(sc, status);
2214e5ec1e72Spatrick 
2215bb813cf8Spatrick 	if (bwfm->sc_chip.ch_chip != BRCM_CC_4378_CHIP_ID &&
2216bb813cf8Spatrick 	    (status & (BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_0 |
2217bb813cf8Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_1)))
22181a93a9bdSpatrick 		bwfm_pci_handle_mb_data(sc);
2219e5ec1e72Spatrick 
2220bb813cf8Spatrick 	mask = BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_D2H_DB;
2221bb813cf8Spatrick 	if (bwfm->sc_chip.ch_chip == BRCM_CC_4378_CHIP_ID)
2222bb813cf8Spatrick 		mask = BWFM_PCI_64_PCIE2REG_MAILBOXMASK_INT_D2H_DB;
2223bb813cf8Spatrick 
2224bb813cf8Spatrick 	if (status & mask) {
22256f241297Spatrick 		bwfm_pci_ring_rx(sc, &sc->sc_rx_complete, &ml);
22266f241297Spatrick 		bwfm_pci_ring_rx(sc, &sc->sc_tx_complete, &ml);
22276f241297Spatrick 		bwfm_pci_ring_rx(sc, &sc->sc_ctrl_complete, &ml);
2228447a2df6Sdlg 
2229447a2df6Sdlg 		if (ifiq_input(&ifp->if_rcv, &ml))
2230447a2df6Sdlg 			if_rxr_livelocked(&sc->sc_rxbuf_ring);
2231e5ec1e72Spatrick 	}
2232e5ec1e72Spatrick 
2233cadf5fcfSpatrick #ifdef BWFM_DEBUG
2234cadf5fcfSpatrick 	bwfm_pci_debug_console(sc);
2235e5ec1e72Spatrick #endif
2236e5ec1e72Spatrick 
2237e5ec1e72Spatrick 	bwfm_pci_intr_enable(sc);
2238e5ec1e72Spatrick 	return 1;
2239e5ec1e72Spatrick }
2240e5ec1e72Spatrick 
2241e5ec1e72Spatrick void
2242e5ec1e72Spatrick bwfm_pci_intr_enable(struct bwfm_pci_softc *sc)
2243e5ec1e72Spatrick {
2244bb813cf8Spatrick 	struct bwfm_softc *bwfm = (void *)sc;
2245bb813cf8Spatrick 
2246bb813cf8Spatrick 	if (bwfm->sc_chip.ch_chip == BRCM_CC_4378_CHIP_ID)
2247bb813cf8Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
2248bb813cf8Spatrick 		    BWFM_PCI_64_PCIE2REG_MAILBOXMASK,
2249bb813cf8Spatrick 		    BWFM_PCI_64_PCIE2REG_MAILBOXMASK_INT_D2H_DB);
2250bb813cf8Spatrick 	else
2251e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
2252e5ec1e72Spatrick 		    BWFM_PCI_PCIE2REG_MAILBOXMASK,
2253e5ec1e72Spatrick 		    BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_0 |
2254e5ec1e72Spatrick 		    BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_1 |
2255e5ec1e72Spatrick 		    BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_D2H_DB);
2256e5ec1e72Spatrick }
2257e5ec1e72Spatrick 
2258e5ec1e72Spatrick void
2259e5ec1e72Spatrick bwfm_pci_intr_disable(struct bwfm_pci_softc *sc)
2260e5ec1e72Spatrick {
2261bb813cf8Spatrick 	struct bwfm_softc *bwfm = (void *)sc;
2262bb813cf8Spatrick 
2263bb813cf8Spatrick 	if (bwfm->sc_chip.ch_chip == BRCM_CC_4378_CHIP_ID)
2264bb813cf8Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
2265bb813cf8Spatrick 		    BWFM_PCI_64_PCIE2REG_MAILBOXMASK, 0);
2266bb813cf8Spatrick 	else
2267e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
2268e5ec1e72Spatrick 		    BWFM_PCI_PCIE2REG_MAILBOXMASK, 0);
2269e5ec1e72Spatrick }
2270e5ec1e72Spatrick 
2271bb813cf8Spatrick uint32_t
2272bb813cf8Spatrick bwfm_pci_intr_status(struct bwfm_pci_softc *sc)
2273bb813cf8Spatrick {
2274bb813cf8Spatrick 	struct bwfm_softc *bwfm = (void *)sc;
2275bb813cf8Spatrick 
2276bb813cf8Spatrick 	if (bwfm->sc_chip.ch_chip == BRCM_CC_4378_CHIP_ID)
2277bb813cf8Spatrick 		return bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
2278bb813cf8Spatrick 		    BWFM_PCI_64_PCIE2REG_MAILBOXINT);
2279bb813cf8Spatrick 	else
2280bb813cf8Spatrick 		return bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
2281bb813cf8Spatrick 		    BWFM_PCI_PCIE2REG_MAILBOXINT);
2282bb813cf8Spatrick }
2283bb813cf8Spatrick 
2284bb813cf8Spatrick void
2285bb813cf8Spatrick bwfm_pci_intr_ack(struct bwfm_pci_softc *sc, uint32_t status)
2286bb813cf8Spatrick {
2287bb813cf8Spatrick 	struct bwfm_softc *bwfm = (void *)sc;
2288bb813cf8Spatrick 
2289bb813cf8Spatrick 	if (bwfm->sc_chip.ch_chip == BRCM_CC_4378_CHIP_ID)
2290bb813cf8Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
2291bb813cf8Spatrick 		    BWFM_PCI_64_PCIE2REG_MAILBOXINT, status);
2292bb813cf8Spatrick 	else
2293bb813cf8Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
2294bb813cf8Spatrick 		    BWFM_PCI_PCIE2REG_MAILBOXINT, status);
2295bb813cf8Spatrick }
2296bb813cf8Spatrick 
22971a93a9bdSpatrick uint32_t
22981a93a9bdSpatrick bwfm_pci_intmask(struct bwfm_pci_softc *sc)
22991a93a9bdSpatrick {
23001a93a9bdSpatrick 	struct bwfm_softc *bwfm = (void *)sc;
23011a93a9bdSpatrick 
23021a93a9bdSpatrick 	if (bwfm->sc_chip.ch_chip == BRCM_CC_4378_CHIP_ID)
23031a93a9bdSpatrick 		return bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
23041a93a9bdSpatrick 		    BWFM_PCI_64_PCIE2REG_INTMASK);
23051a93a9bdSpatrick 	else
23061a93a9bdSpatrick 		return bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
23071a93a9bdSpatrick 		    BWFM_PCI_PCIE2REG_INTMASK);
23081a93a9bdSpatrick }
23091a93a9bdSpatrick 
2310156d2677Spatrick void
2311156d2677Spatrick bwfm_pci_hostready(struct bwfm_pci_softc *sc)
2312156d2677Spatrick {
2313bb813cf8Spatrick 	struct bwfm_softc *bwfm = (void *)sc;
2314bb813cf8Spatrick 
2315156d2677Spatrick 	if ((sc->sc_shared_flags & BWFM_SHARED_INFO_HOSTRDY_DB1) == 0)
2316156d2677Spatrick 		return;
2317156d2677Spatrick 
2318bb813cf8Spatrick 	if (bwfm->sc_chip.ch_chip == BRCM_CC_4378_CHIP_ID)
2319bb813cf8Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
2320bb813cf8Spatrick 		    BWFM_PCI_64_PCIE2REG_H2D_MAILBOX_1, 1);
2321bb813cf8Spatrick 	else
2322156d2677Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
2323156d2677Spatrick 		    BWFM_PCI_PCIE2REG_H2D_MAILBOX_1, 1);
2324156d2677Spatrick }
2325156d2677Spatrick 
2326e5ec1e72Spatrick /* Msgbuf protocol implementation */
2327e5ec1e72Spatrick int
2328e5ec1e72Spatrick bwfm_pci_msgbuf_query_dcmd(struct bwfm_softc *bwfm, int ifidx,
2329e5ec1e72Spatrick     int cmd, char *buf, size_t *len)
2330e5ec1e72Spatrick {
2331e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
2332e5ec1e72Spatrick 	struct msgbuf_ioctl_req_hdr *req;
23332eeba925Spatrick 	struct bwfm_pci_ioctl *ctl;
2334e5ec1e72Spatrick 	struct mbuf *m;
23352eeba925Spatrick 	uint32_t pktid;
23362eeba925Spatrick 	paddr_t paddr;
2337e5ec1e72Spatrick 	size_t buflen;
2338e272db29Spatrick 	int s;
2339e5ec1e72Spatrick 
23402eeba925Spatrick 	buflen = min(*len, BWFM_DMA_H2D_IOCTL_BUF_LEN);
2341471f2571Sjan 	m = MCLGETL(NULL, M_DONTWAIT, buflen);
23422eeba925Spatrick 	if (m == NULL)
23432eeba925Spatrick 		return 1;
23442eeba925Spatrick 	m->m_len = m->m_pkthdr.len = buflen;
23452eeba925Spatrick 
23462eeba925Spatrick 	if (buf)
23472eeba925Spatrick 		memcpy(mtod(m, char *), buf, buflen);
23482eeba925Spatrick 	else
23492eeba925Spatrick 		memset(mtod(m, char *), 0, buflen);
23502eeba925Spatrick 
2351e272db29Spatrick 	s = splnet();
2352e5ec1e72Spatrick 	req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit);
2353e5ec1e72Spatrick 	if (req == NULL) {
2354e272db29Spatrick 		splx(s);
23552eeba925Spatrick 		m_freem(m);
2356e5ec1e72Spatrick 		return 1;
2357e5ec1e72Spatrick 	}
23582eeba925Spatrick 
23592eeba925Spatrick 	if (bwfm_pci_pktid_new(sc, &sc->sc_ioctl_pkts, m, &pktid, &paddr)) {
23602eeba925Spatrick 		bwfm_pci_ring_write_cancel(sc, &sc->sc_ctrl_submit, 1);
2361e272db29Spatrick 		splx(s);
23622eeba925Spatrick 		m_freem(m);
23632eeba925Spatrick 		return 1;
23642eeba925Spatrick 	}
23652eeba925Spatrick 
23662eeba925Spatrick 	ctl = malloc(sizeof(*ctl), M_TEMP, M_WAITOK|M_ZERO);
23672eeba925Spatrick 	ctl->transid = sc->sc_ioctl_transid++;
23682eeba925Spatrick 	TAILQ_INSERT_TAIL(&sc->sc_ioctlq, ctl, next);
23692eeba925Spatrick 
2370e5ec1e72Spatrick 	req->msg.msgtype = MSGBUF_TYPE_IOCTLPTR_REQ;
2371e5ec1e72Spatrick 	req->msg.ifidx = 0;
2372e5ec1e72Spatrick 	req->msg.flags = 0;
23732eeba925Spatrick 	req->msg.request_id = htole32(pktid);
2374e5ec1e72Spatrick 	req->cmd = htole32(cmd);
2375e5ec1e72Spatrick 	req->output_buf_len = htole16(*len);
23762eeba925Spatrick 	req->trans_id = htole16(ctl->transid);
2377e5ec1e72Spatrick 
23782eeba925Spatrick 	req->input_buf_len = htole16(m->m_len);
23792eeba925Spatrick 	req->req_buf_addr.high_addr = htole32((uint64_t)paddr >> 32);
23802eeba925Spatrick 	req->req_buf_addr.low_addr = htole32(paddr & 0xffffffff);
2381dcb67343Spatrick 
2382e5ec1e72Spatrick 	bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit);
2383e272db29Spatrick 	splx(s);
2384e5ec1e72Spatrick 
23858544fed6Smpi 	tsleep_nsec(ctl, PWAIT, "bwfm", SEC_TO_NSEC(1));
23862eeba925Spatrick 	TAILQ_REMOVE(&sc->sc_ioctlq, ctl, next);
23872eeba925Spatrick 
23882eeba925Spatrick 	if (ctl->m == NULL) {
23892eeba925Spatrick 		free(ctl, M_TEMP, sizeof(*ctl));
2390e5ec1e72Spatrick 		return 1;
2391e5ec1e72Spatrick 	}
2392e5ec1e72Spatrick 
23932eeba925Spatrick 	*len = min(ctl->retlen, m->m_len);
23942eeba925Spatrick 	*len = min(*len, buflen);
2395e5ec1e72Spatrick 	if (buf)
23965c7fed39Sdlg 		m_copydata(ctl->m, 0, *len, buf);
23972eeba925Spatrick 	m_freem(ctl->m);
2398e5ec1e72Spatrick 
23992eeba925Spatrick 	if (ctl->status < 0) {
24002eeba925Spatrick 		free(ctl, M_TEMP, sizeof(*ctl));
24012eeba925Spatrick 		return 1;
24022eeba925Spatrick 	}
24032eeba925Spatrick 
24042eeba925Spatrick 	free(ctl, M_TEMP, sizeof(*ctl));
2405e5ec1e72Spatrick 	return 0;
2406e5ec1e72Spatrick }
2407e5ec1e72Spatrick 
2408e5ec1e72Spatrick int
2409e5ec1e72Spatrick bwfm_pci_msgbuf_set_dcmd(struct bwfm_softc *bwfm, int ifidx,
2410e5ec1e72Spatrick     int cmd, char *buf, size_t len)
2411e5ec1e72Spatrick {
2412e5ec1e72Spatrick 	return bwfm_pci_msgbuf_query_dcmd(bwfm, ifidx, cmd, buf, &len);
2413e5ec1e72Spatrick }
24142eeba925Spatrick 
24152eeba925Spatrick void
24162eeba925Spatrick bwfm_pci_msgbuf_rxioctl(struct bwfm_pci_softc *sc,
24172eeba925Spatrick     struct msgbuf_ioctl_resp_hdr *resp)
24182eeba925Spatrick {
24192eeba925Spatrick 	struct bwfm_pci_ioctl *ctl, *tmp;
24202eeba925Spatrick 	struct mbuf *m;
24212eeba925Spatrick 
24222eeba925Spatrick 	m = bwfm_pci_pktid_free(sc, &sc->sc_rx_pkts,
24232eeba925Spatrick 	    letoh32(resp->msg.request_id));
24242eeba925Spatrick 
24252eeba925Spatrick 	TAILQ_FOREACH_SAFE(ctl, &sc->sc_ioctlq, next, tmp) {
24262eeba925Spatrick 		if (ctl->transid != letoh16(resp->trans_id))
24272eeba925Spatrick 			continue;
24282eeba925Spatrick 		ctl->m = m;
24292eeba925Spatrick 		ctl->retlen = letoh16(resp->resp_len);
24302eeba925Spatrick 		ctl->status = letoh16(resp->compl_hdr.status);
24312eeba925Spatrick 		wakeup(ctl);
24322eeba925Spatrick 		return;
24332eeba925Spatrick 	}
24342eeba925Spatrick 
2435cb2afc74Spatrick 	m_freem(m);
24362eeba925Spatrick }
2437