xref: /openbsd/sys/dev/pci/if_bwfm_pci.c (revision 8bad4727)
1*8bad4727Spatrick /*	$OpenBSD: if_bwfm_pci.c,v 1.64 2021/12/27 17:56:03 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;
189*8bad4727Spatrick 	uint8_t			 sc_pcireg64;
190e5ec1e72Spatrick };
191e5ec1e72Spatrick 
192e5ec1e72Spatrick struct bwfm_pci_dmamem {
193e5ec1e72Spatrick 	bus_dmamap_t		bdm_map;
194e5ec1e72Spatrick 	bus_dma_segment_t	bdm_seg;
195e5ec1e72Spatrick 	size_t			bdm_size;
196e5ec1e72Spatrick 	caddr_t			bdm_kva;
197e5ec1e72Spatrick };
198e5ec1e72Spatrick 
199e5ec1e72Spatrick #define BWFM_PCI_DMA_MAP(_bdm)	((_bdm)->bdm_map)
200e5ec1e72Spatrick #define BWFM_PCI_DMA_LEN(_bdm)	((_bdm)->bdm_size)
201e4dae658Spatrick #define BWFM_PCI_DMA_DVA(_bdm)	((uint64_t)(_bdm)->bdm_map->dm_segs[0].ds_addr)
202e5ec1e72Spatrick #define BWFM_PCI_DMA_KVA(_bdm)	((void *)(_bdm)->bdm_kva)
203e5ec1e72Spatrick 
204e5ec1e72Spatrick int		 bwfm_pci_match(struct device *, void *, void *);
205e5ec1e72Spatrick void		 bwfm_pci_attach(struct device *, struct device *, void *);
206e5ec1e72Spatrick int		 bwfm_pci_detach(struct device *, int);
2071a93a9bdSpatrick int		 bwfm_pci_activate(struct device *, int);
2081a93a9bdSpatrick void		 bwfm_pci_cleanup(struct bwfm_pci_softc *);
209e5ec1e72Spatrick 
210ed6d4272Spatrick #if defined(__HAVE_FDT)
211ed6d4272Spatrick int		 bwfm_pci_read_otp(struct bwfm_pci_softc *);
212ed6d4272Spatrick void		 bwfm_pci_process_otp_tuple(struct bwfm_pci_softc *, uint8_t,
213ed6d4272Spatrick 		    uint8_t, uint8_t *);
214ed6d4272Spatrick #endif
215ed6d4272Spatrick 
216e5ec1e72Spatrick int		 bwfm_pci_intr(void *);
217e5ec1e72Spatrick void		 bwfm_pci_intr_enable(struct bwfm_pci_softc *);
218e5ec1e72Spatrick void		 bwfm_pci_intr_disable(struct bwfm_pci_softc *);
219bb813cf8Spatrick uint32_t	 bwfm_pci_intr_status(struct bwfm_pci_softc *);
220bb813cf8Spatrick void		 bwfm_pci_intr_ack(struct bwfm_pci_softc *, uint32_t);
2211a93a9bdSpatrick uint32_t	 bwfm_pci_intmask(struct bwfm_pci_softc *);
222156d2677Spatrick void		 bwfm_pci_hostready(struct bwfm_pci_softc *);
223e5ec1e72Spatrick int		 bwfm_pci_load_microcode(struct bwfm_pci_softc *, const u_char *,
2246aad491fSpatrick 		    size_t, const u_char *, size_t);
225e5ec1e72Spatrick void		 bwfm_pci_select_core(struct bwfm_pci_softc *, int );
226e5ec1e72Spatrick 
227e5ec1e72Spatrick struct bwfm_pci_dmamem *
228e5ec1e72Spatrick 		 bwfm_pci_dmamem_alloc(struct bwfm_pci_softc *, bus_size_t,
229e5ec1e72Spatrick 		    bus_size_t);
230e5ec1e72Spatrick void		 bwfm_pci_dmamem_free(struct bwfm_pci_softc *, struct bwfm_pci_dmamem *);
23102ee7d07Spatrick int		 bwfm_pci_pktid_avail(struct bwfm_pci_softc *,
23202ee7d07Spatrick 		    struct bwfm_pci_pkts *);
233e5ec1e72Spatrick int		 bwfm_pci_pktid_new(struct bwfm_pci_softc *,
234e5ec1e72Spatrick 		    struct bwfm_pci_pkts *, struct mbuf *,
235e5ec1e72Spatrick 		    uint32_t *, paddr_t *);
236e5ec1e72Spatrick struct mbuf *	 bwfm_pci_pktid_free(struct bwfm_pci_softc *,
237e5ec1e72Spatrick 		    struct bwfm_pci_pkts *, uint32_t);
238e5ec1e72Spatrick void		 bwfm_pci_fill_rx_ioctl_ring(struct bwfm_pci_softc *,
239e5ec1e72Spatrick 		    struct if_rxring *, uint32_t);
240e5ec1e72Spatrick void		 bwfm_pci_fill_rx_buf_ring(struct bwfm_pci_softc *);
241e5ec1e72Spatrick void		 bwfm_pci_fill_rx_rings(struct bwfm_pci_softc *);
242e5ec1e72Spatrick int		 bwfm_pci_setup_ring(struct bwfm_pci_softc *, struct bwfm_pci_msgring *,
243e5ec1e72Spatrick 		    int, size_t, uint32_t, uint32_t, int, uint32_t, uint32_t *);
244518be5f3Spatrick int		 bwfm_pci_setup_flowring(struct bwfm_pci_softc *, struct bwfm_pci_msgring *,
245518be5f3Spatrick 		    int, size_t);
246e5ec1e72Spatrick 
247e5ec1e72Spatrick void		 bwfm_pci_ring_bell(struct bwfm_pci_softc *,
248e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
249e5ec1e72Spatrick void		 bwfm_pci_ring_update_rptr(struct bwfm_pci_softc *,
250e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
251e5ec1e72Spatrick void		 bwfm_pci_ring_update_wptr(struct bwfm_pci_softc *,
252e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
253e5ec1e72Spatrick void		 bwfm_pci_ring_write_rptr(struct bwfm_pci_softc *,
254e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
255e5ec1e72Spatrick void		 bwfm_pci_ring_write_wptr(struct bwfm_pci_softc *,
256e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
257e5ec1e72Spatrick void *		 bwfm_pci_ring_write_reserve(struct bwfm_pci_softc *,
258e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
259e5ec1e72Spatrick void *		 bwfm_pci_ring_write_reserve_multi(struct bwfm_pci_softc *,
260e5ec1e72Spatrick 		    struct bwfm_pci_msgring *, int, int *);
261e5ec1e72Spatrick void *		 bwfm_pci_ring_read_avail(struct bwfm_pci_softc *,
262e5ec1e72Spatrick 		    struct bwfm_pci_msgring *, int *);
263e5ec1e72Spatrick void		 bwfm_pci_ring_read_commit(struct bwfm_pci_softc *,
264e5ec1e72Spatrick 		    struct bwfm_pci_msgring *, int);
265e5ec1e72Spatrick void		 bwfm_pci_ring_write_commit(struct bwfm_pci_softc *,
266e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
267e5ec1e72Spatrick void		 bwfm_pci_ring_write_cancel(struct bwfm_pci_softc *,
268e5ec1e72Spatrick 		    struct bwfm_pci_msgring *, int);
269e5ec1e72Spatrick 
270e5ec1e72Spatrick void		 bwfm_pci_ring_rx(struct bwfm_pci_softc *,
2716f241297Spatrick 		    struct bwfm_pci_msgring *, struct mbuf_list *);
2726f241297Spatrick void		 bwfm_pci_msg_rx(struct bwfm_pci_softc *, void *,
2736f241297Spatrick 		    struct mbuf_list *);
274e5ec1e72Spatrick 
275e5ec1e72Spatrick uint32_t	 bwfm_pci_buscore_read(struct bwfm_softc *, uint32_t);
276e5ec1e72Spatrick void		 bwfm_pci_buscore_write(struct bwfm_softc *, uint32_t,
277e5ec1e72Spatrick 		    uint32_t);
278e5ec1e72Spatrick int		 bwfm_pci_buscore_prepare(struct bwfm_softc *);
279e5ec1e72Spatrick int		 bwfm_pci_buscore_reset(struct bwfm_softc *);
280e5ec1e72Spatrick void		 bwfm_pci_buscore_activate(struct bwfm_softc *, uint32_t);
281e5ec1e72Spatrick 
282f67437f3Spatrick int		 bwfm_pci_flowring_lookup(struct bwfm_pci_softc *,
283f67437f3Spatrick 		     struct mbuf *);
284f67437f3Spatrick void		 bwfm_pci_flowring_create(struct bwfm_pci_softc *,
285518be5f3Spatrick 		     struct mbuf *);
286518be5f3Spatrick void		 bwfm_pci_flowring_create_cb(struct bwfm_softc *, void *);
287a2c6ff8bSpatrick void		 bwfm_pci_flowring_delete(struct bwfm_pci_softc *, int);
288b5553ee6Spatrick void		 bwfm_pci_flowring_delete_cb(struct bwfm_softc *, void *);
289518be5f3Spatrick 
290972218f3Spatrick int		 bwfm_pci_preinit(struct bwfm_softc *);
291a2c6ff8bSpatrick void		 bwfm_pci_stop(struct bwfm_softc *);
29202ee7d07Spatrick int		 bwfm_pci_txcheck(struct bwfm_softc *);
293e5ec1e72Spatrick int		 bwfm_pci_txdata(struct bwfm_softc *, struct mbuf *);
294bbd71b0bSpatrick 
2951a93a9bdSpatrick int		 bwfm_pci_send_mb_data(struct bwfm_pci_softc *, uint32_t);
2961a93a9bdSpatrick void		 bwfm_pci_handle_mb_data(struct bwfm_pci_softc *);
2971a93a9bdSpatrick 
298bbd71b0bSpatrick #ifdef BWFM_DEBUG
299cadf5fcfSpatrick void		 bwfm_pci_debug_console(struct bwfm_pci_softc *);
300bbd71b0bSpatrick #endif
301e5ec1e72Spatrick 
302e5ec1e72Spatrick int		 bwfm_pci_msgbuf_query_dcmd(struct bwfm_softc *, int,
303e5ec1e72Spatrick 		    int, char *, size_t *);
304e5ec1e72Spatrick int		 bwfm_pci_msgbuf_set_dcmd(struct bwfm_softc *, int,
305e5ec1e72Spatrick 		    int, char *, size_t);
3062eeba925Spatrick void		 bwfm_pci_msgbuf_rxioctl(struct bwfm_pci_softc *,
3072eeba925Spatrick 		    struct msgbuf_ioctl_resp_hdr *);
308e5ec1e72Spatrick 
309e5ec1e72Spatrick struct bwfm_buscore_ops bwfm_pci_buscore_ops = {
310e5ec1e72Spatrick 	.bc_read = bwfm_pci_buscore_read,
311e5ec1e72Spatrick 	.bc_write = bwfm_pci_buscore_write,
312e5ec1e72Spatrick 	.bc_prepare = bwfm_pci_buscore_prepare,
313e5ec1e72Spatrick 	.bc_reset = bwfm_pci_buscore_reset,
314e5ec1e72Spatrick 	.bc_setup = NULL,
315e5ec1e72Spatrick 	.bc_activate = bwfm_pci_buscore_activate,
316e5ec1e72Spatrick };
317e5ec1e72Spatrick 
318e5ec1e72Spatrick struct bwfm_bus_ops bwfm_pci_bus_ops = {
319972218f3Spatrick 	.bs_preinit = bwfm_pci_preinit,
320a2c6ff8bSpatrick 	.bs_stop = bwfm_pci_stop,
32102ee7d07Spatrick 	.bs_txcheck = bwfm_pci_txcheck,
322e5ec1e72Spatrick 	.bs_txdata = bwfm_pci_txdata,
323e5ec1e72Spatrick 	.bs_txctl = NULL,
324e5ec1e72Spatrick };
325e5ec1e72Spatrick 
326e5ec1e72Spatrick struct bwfm_proto_ops bwfm_pci_msgbuf_ops = {
327e5ec1e72Spatrick 	.proto_query_dcmd = bwfm_pci_msgbuf_query_dcmd,
328e5ec1e72Spatrick 	.proto_set_dcmd = bwfm_pci_msgbuf_set_dcmd,
32914c74651Spatrick 	.proto_rx = NULL,
330029d6dd5Spatrick 	.proto_rxctl = NULL,
331e5ec1e72Spatrick };
332e5ec1e72Spatrick 
333e5ec1e72Spatrick struct cfattach bwfm_pci_ca = {
334e5ec1e72Spatrick 	sizeof(struct bwfm_pci_softc),
335e5ec1e72Spatrick 	bwfm_pci_match,
336e5ec1e72Spatrick 	bwfm_pci_attach,
337e5ec1e72Spatrick 	bwfm_pci_detach,
3381a93a9bdSpatrick 	bwfm_pci_activate,
339e5ec1e72Spatrick };
340e5ec1e72Spatrick 
341e5ec1e72Spatrick static const struct pci_matchid bwfm_pci_devices[] = {
34282f0e660Sjcs 	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4350 },
34341d93ac2Spatrick 	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4356 },
34441d93ac2Spatrick 	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM43602 },
345821fc986Spatrick 	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4371 },
3468e234c40Spatrick 	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4378 },
347e5ec1e72Spatrick };
348e5ec1e72Spatrick 
349e5ec1e72Spatrick int
350e5ec1e72Spatrick bwfm_pci_match(struct device *parent, void *match, void *aux)
351e5ec1e72Spatrick {
352e5ec1e72Spatrick 	return (pci_matchbyid(aux, bwfm_pci_devices,
353e5ec1e72Spatrick 	    nitems(bwfm_pci_devices)));
354e5ec1e72Spatrick }
355e5ec1e72Spatrick 
356e5ec1e72Spatrick void
357e5ec1e72Spatrick bwfm_pci_attach(struct device *parent, struct device *self, void *aux)
358e5ec1e72Spatrick {
359e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (struct bwfm_pci_softc *)self;
360e5ec1e72Spatrick 	struct pci_attach_args *pa = (struct pci_attach_args *)aux;
361e5ec1e72Spatrick 	const char *intrstr;
362e5ec1e72Spatrick 	pci_intr_handle_t ih;
363e5ec1e72Spatrick 
364e5ec1e72Spatrick 	if (pci_mapreg_map(pa, PCI_MAPREG_START + 0x08,
365e5ec1e72Spatrick 	    PCI_MAPREG_MEM_TYPE_64BIT, 0, &sc->sc_tcm_iot, &sc->sc_tcm_ioh,
366e5ec1e72Spatrick 	    NULL, &sc->sc_tcm_ios, 0)) {
367e5ec1e72Spatrick 		printf(": can't map bar1\n");
368a08e9144Spatrick 		return;
369a08e9144Spatrick 	}
370a08e9144Spatrick 
371a08e9144Spatrick 	if (pci_mapreg_map(pa, PCI_MAPREG_START + 0x00,
372a08e9144Spatrick 	    PCI_MAPREG_MEM_TYPE_64BIT, 0, &sc->sc_reg_iot, &sc->sc_reg_ioh,
373a08e9144Spatrick 	    NULL, &sc->sc_reg_ios, 0)) {
374a08e9144Spatrick 		printf(": can't map bar0\n");
375a08e9144Spatrick 		goto bar1;
376e5ec1e72Spatrick 	}
377e5ec1e72Spatrick 
378e5ec1e72Spatrick 	sc->sc_pc = pa->pa_pc;
379e5ec1e72Spatrick 	sc->sc_tag = pa->pa_tag;
380e5ec1e72Spatrick 	sc->sc_id = pa->pa_id;
381e5ec1e72Spatrick 	sc->sc_dmat = pa->pa_dmat;
382e5ec1e72Spatrick 
383e5ec1e72Spatrick 	/* Map and establish the interrupt. */
384e5ec1e72Spatrick 	if (pci_intr_map_msi(pa, &ih) != 0 && pci_intr_map(pa, &ih) != 0) {
385e5ec1e72Spatrick 		printf(": couldn't map interrupt\n");
386a08e9144Spatrick 		goto bar0;
387e5ec1e72Spatrick 	}
388e5ec1e72Spatrick 	intrstr = pci_intr_string(pa->pa_pc, ih);
389e5ec1e72Spatrick 
39014484acaSpatrick 	sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_NET,
391e5ec1e72Spatrick 	    bwfm_pci_intr, sc, DEVNAME(sc));
392e5ec1e72Spatrick 	if (sc->sc_ih == NULL) {
393e5ec1e72Spatrick 		printf(": couldn't establish interrupt");
394e5ec1e72Spatrick 		if (intrstr != NULL)
395e5ec1e72Spatrick 			printf(" at %s", intrstr);
396e5ec1e72Spatrick 		printf("\n");
397e5ec1e72Spatrick 		goto bar1;
398e5ec1e72Spatrick 	}
399e5ec1e72Spatrick 	printf(": %s\n", intrstr);
400e5ec1e72Spatrick 
401db31205aSkettenis #if defined(__HAVE_FDT)
402db31205aSkettenis 	sc->sc_sc.sc_node = PCITAG_NODE(pa->pa_tag);
403da5a4af2Spatrick 	if (sc->sc_sc.sc_node) {
404da5a4af2Spatrick 		if (OF_getproplen(sc->sc_sc.sc_node, "brcm,cal-blob") > 0) {
405da5a4af2Spatrick 			sc->sc_sc.sc_calsize = OF_getproplen(sc->sc_sc.sc_node,
406da5a4af2Spatrick 			    "brcm,cal-blob");
407da5a4af2Spatrick 			sc->sc_sc.sc_cal = malloc(sc->sc_sc.sc_calsize,
408da5a4af2Spatrick 			    M_DEVBUF, M_WAITOK);
409da5a4af2Spatrick 			OF_getprop(sc->sc_sc.sc_node, "brcm,cal-blob",
410da5a4af2Spatrick 			    sc->sc_sc.sc_cal, sc->sc_sc.sc_calsize);
411da5a4af2Spatrick 		}
412da5a4af2Spatrick 	}
413db31205aSkettenis #endif
414db31205aSkettenis 
415972218f3Spatrick 	sc->sc_sc.sc_bus_ops = &bwfm_pci_bus_ops;
416972218f3Spatrick 	sc->sc_sc.sc_proto_ops = &bwfm_pci_msgbuf_ops;
417972218f3Spatrick 	bwfm_attach(&sc->sc_sc);
418972218f3Spatrick 	config_mountroot(self, bwfm_attachhook);
419e5ec1e72Spatrick 	return;
420e5ec1e72Spatrick 
421e5ec1e72Spatrick bar0:
422e5ec1e72Spatrick 	bus_space_unmap(sc->sc_reg_iot, sc->sc_reg_ioh, sc->sc_reg_ios);
423a08e9144Spatrick bar1:
424a08e9144Spatrick 	bus_space_unmap(sc->sc_tcm_iot, sc->sc_tcm_ioh, sc->sc_tcm_ios);
425e5ec1e72Spatrick }
426e5ec1e72Spatrick 
427972218f3Spatrick int
428972218f3Spatrick bwfm_pci_preinit(struct bwfm_softc *bwfm)
429e5ec1e72Spatrick {
430972218f3Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
431e5ec1e72Spatrick 	struct bwfm_pci_ringinfo ringinfo;
4329ead8393Spatrick 	const char *chip = NULL;
43394e4747cSpatrick 	u_char *ucode, *nvram;
43494e4747cSpatrick 	size_t size, nvsize, nvlen;
435e5ec1e72Spatrick 	uint32_t d2h_w_idx_ptr, d2h_r_idx_ptr;
436e5ec1e72Spatrick 	uint32_t h2d_w_idx_ptr, h2d_r_idx_ptr;
437e5ec1e72Spatrick 	uint32_t idx_offset, reg;
438e5ec1e72Spatrick 	int i;
439e5ec1e72Spatrick 
440972218f3Spatrick 	if (sc->sc_initialized)
441972218f3Spatrick 		return 0;
442972218f3Spatrick 
443e5ec1e72Spatrick 	sc->sc_sc.sc_buscore_ops = &bwfm_pci_buscore_ops;
444e5ec1e72Spatrick 	if (bwfm_chip_attach(&sc->sc_sc) != 0) {
445e5ec1e72Spatrick 		printf("%s: cannot attach chip\n", DEVNAME(sc));
446972218f3Spatrick 		return 1;
447e5ec1e72Spatrick 	}
448e5ec1e72Spatrick 
449ed6d4272Spatrick #if defined(__HAVE_FDT)
450ed6d4272Spatrick 	if (bwfm_pci_read_otp(sc)) {
451ed6d4272Spatrick 		printf("%s: cannot read OTP\n", DEVNAME(sc));
452ed6d4272Spatrick 		return 1;
453ed6d4272Spatrick 	}
454ed6d4272Spatrick #endif
455ed6d4272Spatrick 
456e5ec1e72Spatrick 	bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2);
457e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
458e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_CONFIGADDR, 0x4e0);
459e5ec1e72Spatrick 	reg = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
460e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_CONFIGDATA);
461e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
462e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_CONFIGDATA, reg);
463e5ec1e72Spatrick 
464bb818c30Spatrick 	switch (bwfm->sc_chip.ch_chip) {
46518b3a1dcSpatrick 	case BRCM_CC_4350_CHIP_ID:
466bb818c30Spatrick 		if (bwfm->sc_chip.ch_chiprev <= 7)
4679ead8393Spatrick 			chip = "4350c2";
468bb818c30Spatrick 		else
469bb818c30Spatrick 			chip = "4350";
470bb818c30Spatrick 		break;
471bb818c30Spatrick 	case BRCM_CC_4355_CHIP_ID:
472bb818c30Spatrick 		chip = "4355c1";
47318b3a1dcSpatrick 		break;
47441d93ac2Spatrick 	case BRCM_CC_4356_CHIP_ID:
4759ead8393Spatrick 		chip = "4356";
47641d93ac2Spatrick 		break;
477bb818c30Spatrick 	case BRCM_CC_4364_CHIP_ID:
478bb818c30Spatrick 		if (bwfm->sc_chip.ch_chiprev <= 3)
479bb818c30Spatrick 			chip = "4364b2";
480bb818c30Spatrick 		else
481bb818c30Spatrick 			chip = "4364b3";
482bb818c30Spatrick 		break;
483e5ec1e72Spatrick 	case BRCM_CC_43602_CHIP_ID:
4849ead8393Spatrick 		chip = "43602";
485e5ec1e72Spatrick 		break;
486821fc986Spatrick 	case BRCM_CC_4371_CHIP_ID:
4879ead8393Spatrick 		chip = "4371";
488821fc986Spatrick 		break;
489bb818c30Spatrick 	case BRCM_CC_4377_CHIP_ID:
490bb818c30Spatrick 		chip = "4377b3";
491bb818c30Spatrick 		break;
492c38a9bc9Spatrick 	case BRCM_CC_4378_CHIP_ID:
493c38a9bc9Spatrick 		chip = "4378";
494c38a9bc9Spatrick 		break;
495bb818c30Spatrick 	case BRCM_CC_4387_CHIP_ID:
496bb818c30Spatrick 		chip = "4387c2";
497bb818c30Spatrick 		break;
498e5ec1e72Spatrick 	default:
49918b3a1dcSpatrick 		printf("%s: unknown firmware for chip %s\n",
50018b3a1dcSpatrick 		    DEVNAME(sc), bwfm->sc_chip.ch_name);
501972218f3Spatrick 		return 1;
502e5ec1e72Spatrick 	}
503e5ec1e72Spatrick 
50494e4747cSpatrick 	if (bwfm_loadfirmware(bwfm, chip, "-pcie", &ucode, &size,
50594e4747cSpatrick 	    &nvram, &nvsize, &nvlen) != 0)
506972218f3Spatrick 		return 1;
5076aad491fSpatrick 
508e5ec1e72Spatrick 	/* Retrieve RAM size from firmware. */
509e5ec1e72Spatrick 	if (size >= BWFM_RAMSIZE + 8) {
510e5ec1e72Spatrick 		uint32_t *ramsize = (uint32_t *)&ucode[BWFM_RAMSIZE];
511e5ec1e72Spatrick 		if (letoh32(ramsize[0]) == BWFM_RAMSIZE_MAGIC)
512e5ec1e72Spatrick 			bwfm->sc_chip.ch_ramsize = letoh32(ramsize[1]);
513e5ec1e72Spatrick 	}
514e5ec1e72Spatrick 
5156aad491fSpatrick 	if (bwfm_pci_load_microcode(sc, ucode, size, nvram, nvlen) != 0) {
516e5ec1e72Spatrick 		printf("%s: could not load microcode\n",
517e5ec1e72Spatrick 		    DEVNAME(sc));
518e5ec1e72Spatrick 		free(ucode, M_DEVBUF, size);
519b4e85b06Spatrick 		free(nvram, M_DEVBUF, nvsize);
520972218f3Spatrick 		return 1;
521e5ec1e72Spatrick 	}
522e5ec1e72Spatrick 	free(ucode, M_DEVBUF, size);
523b4e85b06Spatrick 	free(nvram, M_DEVBUF, nvsize);
524e5ec1e72Spatrick 
525e5ec1e72Spatrick 	sc->sc_shared_flags = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
526e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_INFO);
527e5ec1e72Spatrick 	sc->sc_shared_version = sc->sc_shared_flags;
528e5ec1e72Spatrick 	if (sc->sc_shared_version > BWFM_SHARED_INFO_MAX_VERSION ||
529e5ec1e72Spatrick 	    sc->sc_shared_version < BWFM_SHARED_INFO_MIN_VERSION) {
530e5ec1e72Spatrick 		printf("%s: PCIe version %d unsupported\n",
531e5ec1e72Spatrick 		    DEVNAME(sc), sc->sc_shared_version);
532972218f3Spatrick 		return 1;
533e5ec1e72Spatrick 	}
534e5ec1e72Spatrick 
535c794abf2Spatrick 	sc->sc_dma_idx_sz = 0;
536e5ec1e72Spatrick 	if (sc->sc_shared_flags & BWFM_SHARED_INFO_DMA_INDEX) {
537e5ec1e72Spatrick 		if (sc->sc_shared_flags & BWFM_SHARED_INFO_DMA_2B_IDX)
538e5ec1e72Spatrick 			sc->sc_dma_idx_sz = sizeof(uint16_t);
539e5ec1e72Spatrick 		else
540e5ec1e72Spatrick 			sc->sc_dma_idx_sz = sizeof(uint32_t);
541e5ec1e72Spatrick 	}
542e5ec1e72Spatrick 
543e5ec1e72Spatrick 	/* Maximum RX data buffers in the ring. */
544e5ec1e72Spatrick 	sc->sc_max_rxbufpost = bus_space_read_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
545e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_MAX_RXBUFPOST);
546e5ec1e72Spatrick 	if (sc->sc_max_rxbufpost == 0)
547e5ec1e72Spatrick 		sc->sc_max_rxbufpost = BWFM_SHARED_MAX_RXBUFPOST_DEFAULT;
548e5ec1e72Spatrick 
549e5ec1e72Spatrick 	/* Alternative offset of data in a packet */
550e5ec1e72Spatrick 	sc->sc_rx_dataoffset = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
551e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_RX_DATAOFFSET);
552e5ec1e72Spatrick 
553e5ec1e72Spatrick 	/* For Power Management */
554e5ec1e72Spatrick 	sc->sc_htod_mb_data_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
555e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_HTOD_MB_DATA_ADDR);
556e5ec1e72Spatrick 	sc->sc_dtoh_mb_data_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
557e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DTOH_MB_DATA_ADDR);
558e5ec1e72Spatrick 
559e5ec1e72Spatrick 	/* Ring information */
560e5ec1e72Spatrick 	sc->sc_ring_info_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
561e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_RING_INFO_ADDR);
562e5ec1e72Spatrick 
563e5ec1e72Spatrick 	/* Firmware's "dmesg" */
564e5ec1e72Spatrick 	sc->sc_console_base_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
565e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_CONSOLE_ADDR);
566e5ec1e72Spatrick 	sc->sc_console_buf_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
567e5ec1e72Spatrick 	    sc->sc_console_base_addr + BWFM_CONSOLE_BUFADDR);
568e5ec1e72Spatrick 	sc->sc_console_buf_size = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
569e5ec1e72Spatrick 	    sc->sc_console_base_addr + BWFM_CONSOLE_BUFSIZE);
570e5ec1e72Spatrick 
571e5ec1e72Spatrick 	/* Read ring information. */
572e5ec1e72Spatrick 	bus_space_read_region_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
573e5ec1e72Spatrick 	    sc->sc_ring_info_addr, (void *)&ringinfo, sizeof(ringinfo));
574e5ec1e72Spatrick 
575e5ec1e72Spatrick 	if (sc->sc_shared_version >= 6) {
576e5ec1e72Spatrick 		sc->sc_max_submissionrings = le16toh(ringinfo.max_submissionrings);
577e5ec1e72Spatrick 		sc->sc_max_flowrings = le16toh(ringinfo.max_flowrings);
578e5ec1e72Spatrick 		sc->sc_max_completionrings = le16toh(ringinfo.max_completionrings);
579e5ec1e72Spatrick 	} else {
580e5ec1e72Spatrick 		sc->sc_max_submissionrings = le16toh(ringinfo.max_flowrings);
581e5ec1e72Spatrick 		sc->sc_max_flowrings = sc->sc_max_submissionrings -
582e5ec1e72Spatrick 		    BWFM_NUM_TX_MSGRINGS;
583e5ec1e72Spatrick 		sc->sc_max_completionrings = BWFM_NUM_RX_MSGRINGS;
584e5ec1e72Spatrick 	}
585e5ec1e72Spatrick 
586e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
587e5ec1e72Spatrick 		d2h_w_idx_ptr = letoh32(ringinfo.d2h_w_idx_ptr);
588e5ec1e72Spatrick 		d2h_r_idx_ptr = letoh32(ringinfo.d2h_r_idx_ptr);
589e5ec1e72Spatrick 		h2d_w_idx_ptr = letoh32(ringinfo.h2d_w_idx_ptr);
590e5ec1e72Spatrick 		h2d_r_idx_ptr = letoh32(ringinfo.h2d_r_idx_ptr);
591e5ec1e72Spatrick 		idx_offset = sizeof(uint32_t);
592e5ec1e72Spatrick 	} else {
593e5ec1e72Spatrick 		uint64_t address;
594e5ec1e72Spatrick 
595e5ec1e72Spatrick 		/* Each TX/RX Ring has a Read and Write Ptr */
596e5ec1e72Spatrick 		sc->sc_dma_idx_bufsz = (sc->sc_max_submissionrings +
597e5ec1e72Spatrick 		    sc->sc_max_completionrings) * sc->sc_dma_idx_sz * 2;
598e5ec1e72Spatrick 		sc->sc_dma_idx_buf = bwfm_pci_dmamem_alloc(sc,
599e5ec1e72Spatrick 		    sc->sc_dma_idx_bufsz, 8);
600e5ec1e72Spatrick 		if (sc->sc_dma_idx_buf == NULL) {
601e5ec1e72Spatrick 			/* XXX: Fallback to TCM? */
602e5ec1e72Spatrick 			printf("%s: cannot allocate idx buf\n",
603e5ec1e72Spatrick 			    DEVNAME(sc));
604972218f3Spatrick 			return 1;
605e5ec1e72Spatrick 		}
606e5ec1e72Spatrick 
607e5ec1e72Spatrick 		idx_offset = sc->sc_dma_idx_sz;
608e5ec1e72Spatrick 		h2d_w_idx_ptr = 0;
609e5ec1e72Spatrick 		address = BWFM_PCI_DMA_DVA(sc->sc_dma_idx_buf);
610e5ec1e72Spatrick 		ringinfo.h2d_w_idx_hostaddr_low =
611e5ec1e72Spatrick 		    htole32(address & 0xffffffff);
612e5ec1e72Spatrick 		ringinfo.h2d_w_idx_hostaddr_high =
613e5ec1e72Spatrick 		    htole32(address >> 32);
614e5ec1e72Spatrick 
615e5ec1e72Spatrick 		h2d_r_idx_ptr = h2d_w_idx_ptr +
616e5ec1e72Spatrick 		    sc->sc_max_submissionrings * idx_offset;
617e5ec1e72Spatrick 		address += sc->sc_max_submissionrings * idx_offset;
618e5ec1e72Spatrick 		ringinfo.h2d_r_idx_hostaddr_low =
619e5ec1e72Spatrick 		    htole32(address & 0xffffffff);
620e5ec1e72Spatrick 		ringinfo.h2d_r_idx_hostaddr_high =
621e5ec1e72Spatrick 		    htole32(address >> 32);
622e5ec1e72Spatrick 
623e5ec1e72Spatrick 		d2h_w_idx_ptr = h2d_r_idx_ptr +
624e5ec1e72Spatrick 		    sc->sc_max_submissionrings * idx_offset;
625e5ec1e72Spatrick 		address += sc->sc_max_submissionrings * idx_offset;
626e5ec1e72Spatrick 		ringinfo.d2h_w_idx_hostaddr_low =
627e5ec1e72Spatrick 		    htole32(address & 0xffffffff);
628e5ec1e72Spatrick 		ringinfo.d2h_w_idx_hostaddr_high =
629e5ec1e72Spatrick 		    htole32(address >> 32);
630e5ec1e72Spatrick 
631e5ec1e72Spatrick 		d2h_r_idx_ptr = d2h_w_idx_ptr +
632e5ec1e72Spatrick 		    sc->sc_max_completionrings * idx_offset;
633e5ec1e72Spatrick 		address += sc->sc_max_completionrings * idx_offset;
634e5ec1e72Spatrick 		ringinfo.d2h_r_idx_hostaddr_low =
635e5ec1e72Spatrick 		    htole32(address & 0xffffffff);
636e5ec1e72Spatrick 		ringinfo.d2h_r_idx_hostaddr_high =
637e5ec1e72Spatrick 		    htole32(address >> 32);
638e5ec1e72Spatrick 
639e5ec1e72Spatrick 		bus_space_write_region_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
640e5ec1e72Spatrick 		    sc->sc_ring_info_addr, (void *)&ringinfo, sizeof(ringinfo));
641e5ec1e72Spatrick 	}
642e5ec1e72Spatrick 
643e5ec1e72Spatrick 	uint32_t ring_mem_ptr = letoh32(ringinfo.ringmem);
644e5ec1e72Spatrick 	/* TX ctrl ring: Send ctrl buffers, send IOCTLs */
645e5ec1e72Spatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_ctrl_submit, 64, 40,
646e5ec1e72Spatrick 	    h2d_w_idx_ptr, h2d_r_idx_ptr, 0, idx_offset,
647e5ec1e72Spatrick 	    &ring_mem_ptr))
648e5ec1e72Spatrick 		goto cleanup;
649e5ec1e72Spatrick 	/* TX rxpost ring: Send clean data mbufs for RX */
6501c0efb8bSpatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_rxpost_submit, 1024, 32,
651e5ec1e72Spatrick 	    h2d_w_idx_ptr, h2d_r_idx_ptr, 1, idx_offset,
652e5ec1e72Spatrick 	    &ring_mem_ptr))
653e5ec1e72Spatrick 		goto cleanup;
654e5ec1e72Spatrick 	/* RX completion rings: recv our filled buffers back */
655e5ec1e72Spatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_ctrl_complete, 64, 24,
656e5ec1e72Spatrick 	    d2h_w_idx_ptr, d2h_r_idx_ptr, 0, idx_offset,
657e5ec1e72Spatrick 	    &ring_mem_ptr))
658e5ec1e72Spatrick 		goto cleanup;
659095b0c44Spatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_tx_complete, 1024,
660095b0c44Spatrick 	    sc->sc_shared_version >= 7 ? 24 : 16,
661e5ec1e72Spatrick 	    d2h_w_idx_ptr, d2h_r_idx_ptr, 1, idx_offset,
662e5ec1e72Spatrick 	    &ring_mem_ptr))
663e5ec1e72Spatrick 		goto cleanup;
6641c0efb8bSpatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_rx_complete, 1024,
665095b0c44Spatrick 	    sc->sc_shared_version >= 7 ? 40 : 32,
666e5ec1e72Spatrick 	    d2h_w_idx_ptr, d2h_r_idx_ptr, 2, idx_offset,
667e5ec1e72Spatrick 	    &ring_mem_ptr))
668e5ec1e72Spatrick 		goto cleanup;
669e5ec1e72Spatrick 
670e5ec1e72Spatrick 	/* Dynamic TX rings for actual data */
671e5ec1e72Spatrick 	sc->sc_flowrings = malloc(sc->sc_max_flowrings *
672e5ec1e72Spatrick 	    sizeof(struct bwfm_pci_msgring), M_DEVBUF, M_WAITOK | M_ZERO);
673518be5f3Spatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
674518be5f3Spatrick 		struct bwfm_pci_msgring *ring = &sc->sc_flowrings[i];
675518be5f3Spatrick 		ring->w_idx_addr = h2d_w_idx_ptr + (i + 2) * idx_offset;
676518be5f3Spatrick 		ring->r_idx_addr = h2d_r_idx_ptr + (i + 2) * idx_offset;
677518be5f3Spatrick 	}
678e5ec1e72Spatrick 
679e5ec1e72Spatrick 	/* Scratch and ring update buffers for firmware */
680e5ec1e72Spatrick 	if ((sc->sc_scratch_buf = bwfm_pci_dmamem_alloc(sc,
681e5ec1e72Spatrick 	    BWFM_DMA_D2H_SCRATCH_BUF_LEN, 8)) == NULL)
682e5ec1e72Spatrick 		goto cleanup;
683e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
684e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_SCRATCH_ADDR_LOW,
685e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(sc->sc_scratch_buf) & 0xffffffff);
686e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
687e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_SCRATCH_ADDR_HIGH,
688e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(sc->sc_scratch_buf) >> 32);
689e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
690e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_SCRATCH_LEN,
691e5ec1e72Spatrick 	    BWFM_DMA_D2H_SCRATCH_BUF_LEN);
692e5ec1e72Spatrick 
693e5ec1e72Spatrick 	if ((sc->sc_ringupd_buf = bwfm_pci_dmamem_alloc(sc,
694e5ec1e72Spatrick 	    BWFM_DMA_D2H_RINGUPD_BUF_LEN, 8)) == NULL)
695e5ec1e72Spatrick 		goto cleanup;
696e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
697e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_RINGUPD_ADDR_LOW,
698e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(sc->sc_ringupd_buf) & 0xffffffff);
699e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
700e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_RINGUPD_ADDR_HIGH,
701e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(sc->sc_ringupd_buf) >> 32);
702e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
703e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_RINGUPD_LEN,
704e5ec1e72Spatrick 	    BWFM_DMA_D2H_RINGUPD_BUF_LEN);
705e5ec1e72Spatrick 
706e5ec1e72Spatrick 	bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2);
707e5ec1e72Spatrick 	bwfm_pci_intr_enable(sc);
708156d2677Spatrick 	bwfm_pci_hostready(sc);
709e5ec1e72Spatrick 
710e5ec1e72Spatrick 	/* Maps RX mbufs to a packet id and back. */
711e5ec1e72Spatrick 	sc->sc_rx_pkts.npkt = BWFM_NUM_RX_PKTIDS;
712e5ec1e72Spatrick 	sc->sc_rx_pkts.pkts = malloc(BWFM_NUM_RX_PKTIDS *
713e5ec1e72Spatrick 	    sizeof(struct bwfm_pci_buf), M_DEVBUF, M_WAITOK | M_ZERO);
714e5ec1e72Spatrick 	for (i = 0; i < BWFM_NUM_RX_PKTIDS; i++)
7151950c5c5Spatrick 		bus_dmamap_create(sc->sc_dmat, MSGBUF_MAX_CTL_PKT_SIZE,
7161950c5c5Spatrick 		    BWFM_NUM_RX_DESCS, MSGBUF_MAX_CTL_PKT_SIZE, 0, BUS_DMA_WAITOK,
717e5ec1e72Spatrick 		    &sc->sc_rx_pkts.pkts[i].bb_map);
718e5ec1e72Spatrick 
719e5ec1e72Spatrick 	/* Maps TX mbufs to a packet id and back. */
720f416501bSpatrick 	sc->sc_tx_pkts.npkt = BWFM_NUM_TX_PKTIDS;
721e5ec1e72Spatrick 	sc->sc_tx_pkts.pkts = malloc(BWFM_NUM_TX_PKTIDS
722e5ec1e72Spatrick 	    * sizeof(struct bwfm_pci_buf), M_DEVBUF, M_WAITOK | M_ZERO);
723e5ec1e72Spatrick 	for (i = 0; i < BWFM_NUM_TX_PKTIDS; i++)
724e5ec1e72Spatrick 		bus_dmamap_create(sc->sc_dmat, MSGBUF_MAX_PKT_SIZE,
725e5ec1e72Spatrick 		    BWFM_NUM_TX_DESCS, MSGBUF_MAX_PKT_SIZE, 0, BUS_DMA_WAITOK,
726e5ec1e72Spatrick 		    &sc->sc_tx_pkts.pkts[i].bb_map);
727c794abf2Spatrick 	sc->sc_tx_pkts_full = 0;
728e5ec1e72Spatrick 
7292eeba925Spatrick 	/* Maps IOCTL mbufs to a packet id and back. */
7302eeba925Spatrick 	sc->sc_ioctl_pkts.npkt = BWFM_NUM_IOCTL_PKTIDS;
7312eeba925Spatrick 	sc->sc_ioctl_pkts.pkts = malloc(BWFM_NUM_IOCTL_PKTIDS
7322eeba925Spatrick 	    * sizeof(struct bwfm_pci_buf), M_DEVBUF, M_WAITOK | M_ZERO);
7332eeba925Spatrick 	for (i = 0; i < BWFM_NUM_IOCTL_PKTIDS; i++)
7342eeba925Spatrick 		bus_dmamap_create(sc->sc_dmat, MSGBUF_MAX_PKT_SIZE,
7352eeba925Spatrick 		    BWFM_NUM_IOCTL_DESCS, MSGBUF_MAX_PKT_SIZE, 0, BUS_DMA_WAITOK,
7362eeba925Spatrick 		    &sc->sc_ioctl_pkts.pkts[i].bb_map);
7372eeba925Spatrick 
73818722113Spatrick 	/*
73918722113Spatrick 	 * For whatever reason, could also be a bug somewhere in this
74018722113Spatrick 	 * driver, the firmware needs a bunch of RX buffers otherwise
7414ef2dd0fSpatrick 	 * it won't send any RX complete messages.
74218722113Spatrick 	 */
7434ef2dd0fSpatrick 	if_rxr_init(&sc->sc_rxbuf_ring, min(256, sc->sc_max_rxbufpost),
7444ef2dd0fSpatrick 	    sc->sc_max_rxbufpost);
745e5ec1e72Spatrick 	if_rxr_init(&sc->sc_ioctl_ring, 8, 8);
746e5ec1e72Spatrick 	if_rxr_init(&sc->sc_event_ring, 8, 8);
747e5ec1e72Spatrick 	bwfm_pci_fill_rx_rings(sc);
748e5ec1e72Spatrick 
7492eeba925Spatrick 	TAILQ_INIT(&sc->sc_ioctlq);
7502eeba925Spatrick 
751cadf5fcfSpatrick #ifdef BWFM_DEBUG
752cadf5fcfSpatrick 	sc->sc_console_readidx = 0;
753cadf5fcfSpatrick 	bwfm_pci_debug_console(sc);
754cadf5fcfSpatrick #endif
755cadf5fcfSpatrick 
756972218f3Spatrick 	sc->sc_initialized = 1;
757972218f3Spatrick 	return 0;
758e5ec1e72Spatrick 
759e5ec1e72Spatrick cleanup:
760e5ec1e72Spatrick 	if (sc->sc_ringupd_buf)
761e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_ringupd_buf);
762e5ec1e72Spatrick 	if (sc->sc_scratch_buf)
763e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_scratch_buf);
764e5ec1e72Spatrick 	if (sc->sc_rx_complete.ring)
765e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_rx_complete.ring);
766e5ec1e72Spatrick 	if (sc->sc_tx_complete.ring)
767e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_tx_complete.ring);
768e5ec1e72Spatrick 	if (sc->sc_ctrl_complete.ring)
769e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_ctrl_complete.ring);
770e5ec1e72Spatrick 	if (sc->sc_rxpost_submit.ring)
771e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_rxpost_submit.ring);
772e5ec1e72Spatrick 	if (sc->sc_ctrl_submit.ring)
773e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_ctrl_submit.ring);
774e5ec1e72Spatrick 	if (sc->sc_dma_idx_buf)
775e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_dma_idx_buf);
776972218f3Spatrick 	return 1;
777e5ec1e72Spatrick }
778e5ec1e72Spatrick 
779e5ec1e72Spatrick int
7806aad491fSpatrick bwfm_pci_load_microcode(struct bwfm_pci_softc *sc, const u_char *ucode, size_t size,
7816aad491fSpatrick     const u_char *nvram, size_t nvlen)
782e5ec1e72Spatrick {
783e5ec1e72Spatrick 	struct bwfm_softc *bwfm = (void *)sc;
784e5ec1e72Spatrick 	struct bwfm_core *core;
7856aad491fSpatrick 	uint32_t shared, written;
786e5ec1e72Spatrick 	int i;
787e5ec1e72Spatrick 
788e5ec1e72Spatrick 	if (bwfm->sc_chip.ch_chip == BRCM_CC_43602_CHIP_ID) {
789e5ec1e72Spatrick 		bwfm_pci_select_core(sc, BWFM_AGENT_CORE_ARM_CR4);
790e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
791e5ec1e72Spatrick 		    BWFM_PCI_ARMCR4REG_BANKIDX, 5);
792e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
793e5ec1e72Spatrick 		    BWFM_PCI_ARMCR4REG_BANKPDA, 0);
794e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
795e5ec1e72Spatrick 		    BWFM_PCI_ARMCR4REG_BANKIDX, 7);
796e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
797e5ec1e72Spatrick 		    BWFM_PCI_ARMCR4REG_BANKPDA, 0);
798e5ec1e72Spatrick 	}
799e5ec1e72Spatrick 
800e5ec1e72Spatrick 	for (i = 0; i < size; i++)
801e5ec1e72Spatrick 		bus_space_write_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
802e5ec1e72Spatrick 		    bwfm->sc_chip.ch_rambase + i, ucode[i]);
803e5ec1e72Spatrick 
804e5ec1e72Spatrick 	/* Firmware replaces this with a pointer once up. */
805e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
806e5ec1e72Spatrick 	    bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize - 4, 0);
807e5ec1e72Spatrick 
8086aad491fSpatrick 	if (nvram) {
8096aad491fSpatrick 		for (i = 0; i < nvlen; i++)
8106aad491fSpatrick 			bus_space_write_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
8116aad491fSpatrick 			    bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize
8126aad491fSpatrick 			    - nvlen  + i, nvram[i]);
8136aad491fSpatrick 	}
8146aad491fSpatrick 
8156aad491fSpatrick 	written = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
8166aad491fSpatrick 	    bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize - 4);
817e5ec1e72Spatrick 
818e5ec1e72Spatrick 	/* Load reset vector from firmware and kickstart core. */
819b0cd4990Spatrick 	if (bwfm->sc_chip.ch_chip == BRCM_CC_43602_CHIP_ID) {
820e5ec1e72Spatrick 		core = bwfm_chip_get_core(bwfm, BWFM_AGENT_INTERNAL_MEM);
821e5ec1e72Spatrick 		bwfm->sc_chip.ch_core_reset(bwfm, core, 0, 0, 0);
822b0cd4990Spatrick 	}
823e5ec1e72Spatrick 	bwfm_chip_set_active(bwfm, *(uint32_t *)ucode);
824e5ec1e72Spatrick 
8253c53ddefSpatrick 	for (i = 0; i < 100; i++) {
826e5ec1e72Spatrick 		delay(50 * 1000);
827e5ec1e72Spatrick 		shared = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
828e5ec1e72Spatrick 		    bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize - 4);
8296aad491fSpatrick 		if (shared != written)
830e5ec1e72Spatrick 			break;
831e5ec1e72Spatrick 	}
83219871452Spatrick 	if (shared == written) {
833e5ec1e72Spatrick 		printf("%s: firmware did not come up\n", DEVNAME(sc));
834e5ec1e72Spatrick 		return 1;
835e5ec1e72Spatrick 	}
83619871452Spatrick 	if (shared < bwfm->sc_chip.ch_rambase ||
83719871452Spatrick 	    shared >= bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize) {
83819871452Spatrick 		printf("%s: invalid shared RAM address 0x%08x\n", DEVNAME(sc),
83919871452Spatrick 		    shared);
84019871452Spatrick 		return 1;
84119871452Spatrick 	}
842e5ec1e72Spatrick 
843e5ec1e72Spatrick 	sc->sc_shared_address = shared;
844e5ec1e72Spatrick 	return 0;
845e5ec1e72Spatrick }
846e5ec1e72Spatrick 
847e5ec1e72Spatrick int
848e5ec1e72Spatrick bwfm_pci_detach(struct device *self, int flags)
849e5ec1e72Spatrick {
850e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (struct bwfm_pci_softc *)self;
851e5ec1e72Spatrick 
852e5ec1e72Spatrick 	bwfm_detach(&sc->sc_sc, flags);
8531a93a9bdSpatrick 	bwfm_pci_cleanup(sc);
8541a93a9bdSpatrick 
8551a93a9bdSpatrick 	return 0;
8561a93a9bdSpatrick }
8571a93a9bdSpatrick 
8581a93a9bdSpatrick void
8591a93a9bdSpatrick bwfm_pci_cleanup(struct bwfm_pci_softc *sc)
8601a93a9bdSpatrick {
8611a93a9bdSpatrick 	int i;
862e5ec1e72Spatrick 
86364ae3612Spatrick 	for (i = 0; i < BWFM_NUM_RX_PKTIDS; i++) {
86464ae3612Spatrick 		bus_dmamap_destroy(sc->sc_dmat, sc->sc_rx_pkts.pkts[i].bb_map);
86564ae3612Spatrick 		if (sc->sc_rx_pkts.pkts[i].bb_m)
86664ae3612Spatrick 			m_freem(sc->sc_rx_pkts.pkts[i].bb_m);
86764ae3612Spatrick 	}
86864ae3612Spatrick 	free(sc->sc_rx_pkts.pkts, M_DEVBUF, BWFM_NUM_RX_PKTIDS *
86964ae3612Spatrick 	    sizeof(struct bwfm_pci_buf));
87064ae3612Spatrick 
87164ae3612Spatrick 	for (i = 0; i < BWFM_NUM_TX_PKTIDS; i++) {
87264ae3612Spatrick 		bus_dmamap_destroy(sc->sc_dmat, sc->sc_tx_pkts.pkts[i].bb_map);
87364ae3612Spatrick 		if (sc->sc_tx_pkts.pkts[i].bb_m)
87464ae3612Spatrick 			m_freem(sc->sc_tx_pkts.pkts[i].bb_m);
87564ae3612Spatrick 	}
87664ae3612Spatrick 	free(sc->sc_tx_pkts.pkts, M_DEVBUF, BWFM_NUM_TX_PKTIDS *
87764ae3612Spatrick 	    sizeof(struct bwfm_pci_buf));
87864ae3612Spatrick 
87964ae3612Spatrick 	for (i = 0; i < BWFM_NUM_IOCTL_PKTIDS; i++) {
88064ae3612Spatrick 		bus_dmamap_destroy(sc->sc_dmat, sc->sc_ioctl_pkts.pkts[i].bb_map);
88164ae3612Spatrick 		if (sc->sc_ioctl_pkts.pkts[i].bb_m)
88264ae3612Spatrick 			m_freem(sc->sc_ioctl_pkts.pkts[i].bb_m);
88364ae3612Spatrick 	}
88464ae3612Spatrick 	free(sc->sc_ioctl_pkts.pkts, M_DEVBUF, BWFM_NUM_IOCTL_PKTIDS *
88564ae3612Spatrick 	    sizeof(struct bwfm_pci_buf));
88664ae3612Spatrick 
88764ae3612Spatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
88864ae3612Spatrick 		if (sc->sc_flowrings[i].status >= RING_OPEN)
88964ae3612Spatrick 			bwfm_pci_dmamem_free(sc, sc->sc_flowrings[i].ring);
89064ae3612Spatrick 	}
89164ae3612Spatrick 	free(sc->sc_flowrings, M_DEVBUF, sc->sc_max_flowrings *
89264ae3612Spatrick 	    sizeof(struct bwfm_pci_msgring));
893e5ec1e72Spatrick 
894e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_ringupd_buf);
895e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_scratch_buf);
896e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_rx_complete.ring);
897e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_tx_complete.ring);
898e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_ctrl_complete.ring);
899e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_rxpost_submit.ring);
900e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_ctrl_submit.ring);
90164ae3612Spatrick 	if (sc->sc_dma_idx_buf) {
902e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_dma_idx_buf);
90364ae3612Spatrick 		sc->sc_dma_idx_buf = NULL;
90464ae3612Spatrick 	}
90564ae3612Spatrick 
90664ae3612Spatrick 	sc->sc_initialized = 0;
9071a93a9bdSpatrick }
9081a93a9bdSpatrick 
9091a93a9bdSpatrick int
9101a93a9bdSpatrick bwfm_pci_activate(struct device *self, int act)
9111a93a9bdSpatrick {
9121a93a9bdSpatrick 	struct bwfm_pci_softc *sc = (struct bwfm_pci_softc *)self;
9131a93a9bdSpatrick 	struct bwfm_softc *bwfm = (void *)sc;
9141a93a9bdSpatrick 	int error = 0;
9151a93a9bdSpatrick 
9161a93a9bdSpatrick 	switch (act) {
9171a93a9bdSpatrick 	case DVACT_QUIESCE:
9181a93a9bdSpatrick 		error = bwfm_activate(bwfm, act);
9191a93a9bdSpatrick 		if (error)
9201a93a9bdSpatrick 			return error;
9211a93a9bdSpatrick 		if (sc->sc_initialized) {
9221a93a9bdSpatrick 			sc->sc_mbdata_done = 0;
9231a93a9bdSpatrick 			error = bwfm_pci_send_mb_data(sc,
9241a93a9bdSpatrick 			    BWFM_PCI_H2D_HOST_D3_INFORM);
9251a93a9bdSpatrick 			if (error)
9261a93a9bdSpatrick 				return error;
9271a93a9bdSpatrick 			tsleep_nsec(&sc->sc_mbdata_done, PCATCH,
9281a93a9bdSpatrick 			    DEVNAME(sc), SEC_TO_NSEC(2));
9291a93a9bdSpatrick 			if (!sc->sc_mbdata_done)
9301a93a9bdSpatrick 				return ETIMEDOUT;
9311a93a9bdSpatrick 		}
9321a93a9bdSpatrick 		break;
9331a93a9bdSpatrick 	case DVACT_WAKEUP:
9341a93a9bdSpatrick 		if (sc->sc_initialized) {
9351a93a9bdSpatrick 			/* If device can't be resumed, re-init. */
9361a93a9bdSpatrick 			if (bwfm_pci_intmask(sc) == 0 ||
9371a93a9bdSpatrick 			    bwfm_pci_send_mb_data(sc,
9381a93a9bdSpatrick 			    BWFM_PCI_H2D_HOST_D0_INFORM) != 0) {
9391a93a9bdSpatrick 				bwfm_cleanup(bwfm);
9401a93a9bdSpatrick 				bwfm_pci_cleanup(sc);
9411a93a9bdSpatrick 			}
9421a93a9bdSpatrick 		}
9431a93a9bdSpatrick 		error = bwfm_activate(bwfm, act);
9441a93a9bdSpatrick 		if (error)
9451a93a9bdSpatrick 			return error;
9461a93a9bdSpatrick 		break;
9471a93a9bdSpatrick 	default:
9481a93a9bdSpatrick 		break;
9491a93a9bdSpatrick 	}
9501a93a9bdSpatrick 
951e5ec1e72Spatrick 	return 0;
952e5ec1e72Spatrick }
953e5ec1e72Spatrick 
954ed6d4272Spatrick #if defined(__HAVE_FDT)
955ed6d4272Spatrick int
956ed6d4272Spatrick bwfm_pci_read_otp(struct bwfm_pci_softc *sc)
957ed6d4272Spatrick {
958ed6d4272Spatrick 	struct bwfm_softc *bwfm = (void *)sc;
959ed6d4272Spatrick 	struct bwfm_core *core;
960ea92f6c3Spatrick 	uint32_t coreid, base, words;
961ea92f6c3Spatrick 	uint32_t page, offset, sromctl;
962ea92f6c3Spatrick 	uint8_t *otp;
963ed6d4272Spatrick 	int i;
964ed6d4272Spatrick 
965ea92f6c3Spatrick 	switch (bwfm->sc_chip.ch_chip) {
966ea92f6c3Spatrick 	case BRCM_CC_4355_CHIP_ID:
967ea92f6c3Spatrick 		coreid = BWFM_AGENT_CORE_CHIPCOMMON;
968ea92f6c3Spatrick 		base = 0x8c0;
969ea92f6c3Spatrick 		words = 0xb2;
970ea92f6c3Spatrick 		break;
971ea92f6c3Spatrick 	case BRCM_CC_4364_CHIP_ID:
972ea92f6c3Spatrick 		coreid = BWFM_AGENT_CORE_CHIPCOMMON;
973ea92f6c3Spatrick 		base = 0x8c0;
974ea92f6c3Spatrick 		words = 0x1a0;
975ea92f6c3Spatrick 		break;
976ea92f6c3Spatrick 	case BRCM_CC_4377_CHIP_ID:
977ea92f6c3Spatrick 	case BRCM_CC_4378_CHIP_ID:
978ea92f6c3Spatrick 		coreid = BWFM_AGENT_CORE_GCI;
979ea92f6c3Spatrick 		base = 0x1120;
980ea92f6c3Spatrick 		words = 0x170;
981ea92f6c3Spatrick 		break;
982ea92f6c3Spatrick 	case BRCM_CC_4387_CHIP_ID:
983ea92f6c3Spatrick 		coreid = BWFM_AGENT_CORE_GCI;
984ea92f6c3Spatrick 		base = 0x113c;
985ea92f6c3Spatrick 		words = 0x170;
986ea92f6c3Spatrick 		break;
987ea92f6c3Spatrick 	default:
988ed6d4272Spatrick 		return 0;
989ea92f6c3Spatrick 	}
990ed6d4272Spatrick 
991ea92f6c3Spatrick 	core = bwfm_chip_get_core(bwfm, coreid);
992ed6d4272Spatrick 	if (core == NULL)
993ed6d4272Spatrick 		return 1;
994ed6d4272Spatrick 
995ea92f6c3Spatrick 	/* Map OTP to shadow area */
996ea92f6c3Spatrick 	if (coreid == BWFM_AGENT_CORE_CHIPCOMMON) {
997ea92f6c3Spatrick 		bwfm_pci_select_core(sc, coreid);
998ea92f6c3Spatrick 		sromctl = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
999ea92f6c3Spatrick 		    BWFM_CHIP_REG_SROMCONTROL);
1000ed6d4272Spatrick 
1001ea92f6c3Spatrick 		if (!(sromctl & BWFM_CHIP_REG_SROMCONTROL_OTP_PRESENT))
1002ea92f6c3Spatrick 			return 0;
1003ea92f6c3Spatrick 
1004ea92f6c3Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1005ea92f6c3Spatrick 		    BWFM_CHIP_REG_SROMCONTROL, sromctl |
1006ea92f6c3Spatrick 		    BWFM_CHIP_REG_SROMCONTROL_OTPSEL);
1007ed6d4272Spatrick 	}
1008ea92f6c3Spatrick 
1009ea92f6c3Spatrick 	/* Map bus window to SROM/OTP shadow area */
1010ea92f6c3Spatrick 	page = (core->co_base + base) & ~(BWFM_PCI_BAR0_REG_SIZE - 1);
1011ea92f6c3Spatrick 	offset = (core->co_base + base) & (BWFM_PCI_BAR0_REG_SIZE - 1);
1012ea92f6c3Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_BAR0_WINDOW, page);
1013ea92f6c3Spatrick 
1014ea92f6c3Spatrick 	otp = mallocarray(words, sizeof(uint16_t), M_TEMP, M_WAITOK);
1015ea92f6c3Spatrick 	for (i = 0; i < words; i++)
1016ea92f6c3Spatrick 		((uint16_t *)otp)[i] = bus_space_read_2(sc->sc_reg_iot,
1017ea92f6c3Spatrick 		    sc->sc_reg_ioh, offset + i * sizeof(uint16_t));
1018ea92f6c3Spatrick 
1019ea92f6c3Spatrick 	/* Unmap OTP */
1020ea92f6c3Spatrick 	if (coreid == BWFM_AGENT_CORE_CHIPCOMMON) {
1021ea92f6c3Spatrick 		bwfm_pci_select_core(sc, coreid);
1022ea92f6c3Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1023ea92f6c3Spatrick 		    BWFM_CHIP_REG_SROMCONTROL, sromctl);
1024ea92f6c3Spatrick 	}
1025ea92f6c3Spatrick 
1026ea92f6c3Spatrick 	for (i = 0; i < (words * sizeof(uint16_t)) - 1; i += otp[i + 1]) {
1027ea92f6c3Spatrick 		if (otp[i + 0] == 0)
1028ea92f6c3Spatrick 			break;
1029ea92f6c3Spatrick 		if (i + otp[i + 1] > words * sizeof(uint16_t))
1030ed6d4272Spatrick 			break;
1031ed6d4272Spatrick 		bwfm_pci_process_otp_tuple(sc, otp[i + 0], otp[i + 1],
1032ed6d4272Spatrick 		    &otp[i + 2]);
1033ed6d4272Spatrick 	}
1034ed6d4272Spatrick 
1035ea92f6c3Spatrick 	free(otp, M_TEMP, words * sizeof(uint16_t));
1036ed6d4272Spatrick 	return 0;
1037ed6d4272Spatrick }
1038ed6d4272Spatrick 
1039ed6d4272Spatrick void
1040ed6d4272Spatrick bwfm_pci_process_otp_tuple(struct bwfm_pci_softc *sc, uint8_t type, uint8_t size,
1041ed6d4272Spatrick     uint8_t *data)
1042ed6d4272Spatrick {
1043ed6d4272Spatrick 	struct bwfm_softc *bwfm = (void *)sc;
1044ed6d4272Spatrick 	char chiprev[8] = "", module[8] = "", modrev[8] = "", vendor[8] = "", chip[8] = "";
1045ed6d4272Spatrick 	char product[16] = "unknown";
104692fbeeb7Spatrick 	int len;
1047ed6d4272Spatrick 
1048ed6d4272Spatrick 	switch (type) {
1049ed6d4272Spatrick 	case 0x15: /* system vendor OTP */
1050ed6d4272Spatrick 		DPRINTF(("%s: system vendor OTP\n", DEVNAME(sc)));
1051ed6d4272Spatrick 		if (size < sizeof(uint32_t))
1052ed6d4272Spatrick 			return;
1053ed6d4272Spatrick 		if (data[0] != 0x08 || data[1] != 0x00 ||
1054ed6d4272Spatrick 		    data[2] != 0x00 || data[3] != 0x00)
1055ed6d4272Spatrick 			return;
1056ed6d4272Spatrick 		size -= sizeof(uint32_t);
1057ed6d4272Spatrick 		data += sizeof(uint32_t);
1058ed6d4272Spatrick 		while (size) {
1059ed6d4272Spatrick 			/* reached end */
1060ed6d4272Spatrick 			if (data[0] == 0xff)
1061ed6d4272Spatrick 				break;
1062ed6d4272Spatrick 			for (len = 0; len < size; len++)
1063ed6d4272Spatrick 				if (data[len] == 0x00 || data[len] == ' ' ||
1064ed6d4272Spatrick 				    data[len] == 0xff)
1065ed6d4272Spatrick 					break;
1066ed6d4272Spatrick 			if (len < 3 || len > 9) /* X=abcdef */
1067ed6d4272Spatrick 				goto next;
1068ed6d4272Spatrick 			if (data[1] != '=')
1069ed6d4272Spatrick 				goto next;
1070ed6d4272Spatrick 			/* NULL-terminate string */
1071ed6d4272Spatrick 			if (data[len] == ' ')
1072ed6d4272Spatrick 				data[len] = '\0';
1073ed6d4272Spatrick 			switch (data[0]) {
1074ed6d4272Spatrick 			case 's':
1075ed6d4272Spatrick 				strlcpy(chiprev, &data[2], sizeof(chiprev));
1076ed6d4272Spatrick 				break;
1077ed6d4272Spatrick 			case 'M':
1078ed6d4272Spatrick 				strlcpy(module, &data[2], sizeof(module));
1079ed6d4272Spatrick 				break;
1080ed6d4272Spatrick 			case 'm':
1081ed6d4272Spatrick 				strlcpy(modrev, &data[2], sizeof(modrev));
1082ed6d4272Spatrick 				break;
1083ed6d4272Spatrick 			case 'V':
1084ed6d4272Spatrick 				strlcpy(vendor, &data[2], sizeof(vendor));
1085ed6d4272Spatrick 				break;
1086ed6d4272Spatrick 			}
1087ed6d4272Spatrick next:
1088ed6d4272Spatrick 			/* skip content */
1089ed6d4272Spatrick 			data += len;
1090ed6d4272Spatrick 			size -= len;
1091ed6d4272Spatrick 			/* skip spacer tag */
1092ed6d4272Spatrick 			if (size) {
1093ed6d4272Spatrick 				data++;
1094ed6d4272Spatrick 				size--;
1095ed6d4272Spatrick 			}
1096ed6d4272Spatrick 		}
1097ed6d4272Spatrick 		snprintf(chip, sizeof(chip),
1098ed6d4272Spatrick 		    bwfm->sc_chip.ch_chip > 40000 ? "%05d" : "%04x",
1099ed6d4272Spatrick 		    bwfm->sc_chip.ch_chip);
110092fbeeb7Spatrick 		if (sc->sc_sc.sc_node)
110192fbeeb7Spatrick 			OF_getprop(sc->sc_sc.sc_node, "apple,module-instance",
110292fbeeb7Spatrick 			    product, sizeof(product));
1103ed6d4272Spatrick 		printf("%s: firmware C-%s%s%s/P-%s_M-%s_V-%s__m-%s\n",
1104ed6d4272Spatrick 		    DEVNAME(sc), chip,
1105ed6d4272Spatrick 		    *chiprev ? "__s-" : "", *chiprev ? chiprev : "",
1106ed6d4272Spatrick 		    product, module, vendor, modrev);
1107ed6d4272Spatrick 		break;
1108ed6d4272Spatrick 	case 0x80: /* Broadcom CIS */
1109ed6d4272Spatrick 		DPRINTF(("%s: Broadcom CIS\n", DEVNAME(sc)));
1110ed6d4272Spatrick 		break;
1111ed6d4272Spatrick 	default:
1112ed6d4272Spatrick 		DPRINTF(("%s: unknown OTP tuple\n", DEVNAME(sc)));
1113ed6d4272Spatrick 		break;
1114ed6d4272Spatrick 	}
1115ed6d4272Spatrick }
1116ed6d4272Spatrick #endif
1117ed6d4272Spatrick 
1118e5ec1e72Spatrick /* DMA code */
1119e5ec1e72Spatrick struct bwfm_pci_dmamem *
1120e5ec1e72Spatrick bwfm_pci_dmamem_alloc(struct bwfm_pci_softc *sc, bus_size_t size, bus_size_t align)
1121e5ec1e72Spatrick {
1122e5ec1e72Spatrick 	struct bwfm_pci_dmamem *bdm;
1123e5ec1e72Spatrick 	int nsegs;
1124e5ec1e72Spatrick 
1125e5ec1e72Spatrick 	bdm = malloc(sizeof(*bdm), M_DEVBUF, M_WAITOK | M_ZERO);
1126e5ec1e72Spatrick 	bdm->bdm_size = size;
1127e5ec1e72Spatrick 
1128e5ec1e72Spatrick 	if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
1129e5ec1e72Spatrick 	    BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &bdm->bdm_map) != 0)
1130e5ec1e72Spatrick 		goto bdmfree;
1131e5ec1e72Spatrick 
1132e5ec1e72Spatrick 	if (bus_dmamem_alloc(sc->sc_dmat, size, align, 0, &bdm->bdm_seg, 1,
1133e5ec1e72Spatrick 	    &nsegs, BUS_DMA_WAITOK) != 0)
1134e5ec1e72Spatrick 		goto destroy;
1135e5ec1e72Spatrick 
1136e5ec1e72Spatrick 	if (bus_dmamem_map(sc->sc_dmat, &bdm->bdm_seg, nsegs, size,
1137e5ec1e72Spatrick 	    &bdm->bdm_kva, BUS_DMA_WAITOK | BUS_DMA_COHERENT) != 0)
1138e5ec1e72Spatrick 		goto free;
1139e5ec1e72Spatrick 
1140e5ec1e72Spatrick 	if (bus_dmamap_load(sc->sc_dmat, bdm->bdm_map, bdm->bdm_kva, size,
1141e5ec1e72Spatrick 	    NULL, BUS_DMA_WAITOK) != 0)
1142e5ec1e72Spatrick 		goto unmap;
1143e5ec1e72Spatrick 
1144e5ec1e72Spatrick 	bzero(bdm->bdm_kva, size);
1145e5ec1e72Spatrick 
1146e5ec1e72Spatrick 	return (bdm);
1147e5ec1e72Spatrick 
1148e5ec1e72Spatrick unmap:
1149e5ec1e72Spatrick 	bus_dmamem_unmap(sc->sc_dmat, bdm->bdm_kva, size);
1150e5ec1e72Spatrick free:
1151e5ec1e72Spatrick 	bus_dmamem_free(sc->sc_dmat, &bdm->bdm_seg, 1);
1152e5ec1e72Spatrick destroy:
1153e5ec1e72Spatrick 	bus_dmamap_destroy(sc->sc_dmat, bdm->bdm_map);
1154e5ec1e72Spatrick bdmfree:
115565046b40Spatrick 	free(bdm, M_DEVBUF, sizeof(*bdm));
1156e5ec1e72Spatrick 
1157e5ec1e72Spatrick 	return (NULL);
1158e5ec1e72Spatrick }
1159e5ec1e72Spatrick 
1160e5ec1e72Spatrick void
1161e5ec1e72Spatrick bwfm_pci_dmamem_free(struct bwfm_pci_softc *sc, struct bwfm_pci_dmamem *bdm)
1162e5ec1e72Spatrick {
1163e5ec1e72Spatrick 	bus_dmamem_unmap(sc->sc_dmat, bdm->bdm_kva, bdm->bdm_size);
1164e5ec1e72Spatrick 	bus_dmamem_free(sc->sc_dmat, &bdm->bdm_seg, 1);
1165e5ec1e72Spatrick 	bus_dmamap_destroy(sc->sc_dmat, bdm->bdm_map);
116665046b40Spatrick 	free(bdm, M_DEVBUF, sizeof(*bdm));
1167e5ec1e72Spatrick }
1168e5ec1e72Spatrick 
1169e5ec1e72Spatrick /*
1170e5ec1e72Spatrick  * We need a simple mapping from a packet ID to mbufs, because when
1171e5ec1e72Spatrick  * a transfer completed, we only know the ID so we have to look up
1172e5ec1e72Spatrick  * the memory for the ID.  This simply looks for an empty slot.
1173e5ec1e72Spatrick  */
1174e5ec1e72Spatrick int
117502ee7d07Spatrick bwfm_pci_pktid_avail(struct bwfm_pci_softc *sc, struct bwfm_pci_pkts *pkts)
117602ee7d07Spatrick {
117702ee7d07Spatrick 	int i, idx;
117802ee7d07Spatrick 
117902ee7d07Spatrick 	idx = pkts->last + 1;
118002ee7d07Spatrick 	for (i = 0; i < pkts->npkt; i++) {
118102ee7d07Spatrick 		if (idx == pkts->npkt)
118202ee7d07Spatrick 			idx = 0;
118302ee7d07Spatrick 		if (pkts->pkts[idx].bb_m == NULL)
118402ee7d07Spatrick 			return 0;
118502ee7d07Spatrick 		idx++;
118602ee7d07Spatrick 	}
118702ee7d07Spatrick 	return ENOBUFS;
118802ee7d07Spatrick }
118902ee7d07Spatrick 
119002ee7d07Spatrick int
1191e5ec1e72Spatrick bwfm_pci_pktid_new(struct bwfm_pci_softc *sc, struct bwfm_pci_pkts *pkts,
1192e5ec1e72Spatrick     struct mbuf *m, uint32_t *pktid, paddr_t *paddr)
1193e5ec1e72Spatrick {
1194e5ec1e72Spatrick 	int i, idx;
1195e5ec1e72Spatrick 
1196e5ec1e72Spatrick 	idx = pkts->last + 1;
1197e5ec1e72Spatrick 	for (i = 0; i < pkts->npkt; i++) {
1198e5ec1e72Spatrick 		if (idx == pkts->npkt)
1199e5ec1e72Spatrick 			idx = 0;
1200e5ec1e72Spatrick 		if (pkts->pkts[idx].bb_m == NULL) {
1201e5ec1e72Spatrick 			if (bus_dmamap_load_mbuf(sc->sc_dmat,
1202e5ec1e72Spatrick 			    pkts->pkts[idx].bb_map, m, BUS_DMA_NOWAIT) != 0) {
1203518be5f3Spatrick 				if (m_defrag(m, M_DONTWAIT))
1204518be5f3Spatrick 					return EFBIG;
1205518be5f3Spatrick 				if (bus_dmamap_load_mbuf(sc->sc_dmat,
1206518be5f3Spatrick 				    pkts->pkts[idx].bb_map, m, BUS_DMA_NOWAIT) != 0)
1207518be5f3Spatrick 					return EFBIG;
1208e5ec1e72Spatrick 			}
1209dcb67343Spatrick 			bus_dmamap_sync(sc->sc_dmat, pkts->pkts[idx].bb_map,
1210dcb67343Spatrick 			    0, pkts->pkts[idx].bb_map->dm_mapsize,
1211dcb67343Spatrick 			    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1212e5ec1e72Spatrick 			pkts->last = idx;
1213e5ec1e72Spatrick 			pkts->pkts[idx].bb_m = m;
1214e5ec1e72Spatrick 			*pktid = idx;
1215e5ec1e72Spatrick 			*paddr = pkts->pkts[idx].bb_map->dm_segs[0].ds_addr;
1216e5ec1e72Spatrick 			return 0;
1217e5ec1e72Spatrick 		}
1218e5ec1e72Spatrick 		idx++;
1219e5ec1e72Spatrick 	}
1220518be5f3Spatrick 	return ENOBUFS;
1221e5ec1e72Spatrick }
1222e5ec1e72Spatrick 
1223e5ec1e72Spatrick struct mbuf *
1224e5ec1e72Spatrick bwfm_pci_pktid_free(struct bwfm_pci_softc *sc, struct bwfm_pci_pkts *pkts,
1225e5ec1e72Spatrick     uint32_t pktid)
1226e5ec1e72Spatrick {
1227e5ec1e72Spatrick 	struct mbuf *m;
1228e5ec1e72Spatrick 
1229e5ec1e72Spatrick 	if (pktid >= pkts->npkt || pkts->pkts[pktid].bb_m == NULL)
1230e5ec1e72Spatrick 		return NULL;
1231dcb67343Spatrick 	bus_dmamap_sync(sc->sc_dmat, pkts->pkts[pktid].bb_map, 0,
1232dcb67343Spatrick 	    pkts->pkts[pktid].bb_map->dm_mapsize,
1233dcb67343Spatrick 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1234e5ec1e72Spatrick 	bus_dmamap_unload(sc->sc_dmat, pkts->pkts[pktid].bb_map);
1235e5ec1e72Spatrick 	m = pkts->pkts[pktid].bb_m;
1236e5ec1e72Spatrick 	pkts->pkts[pktid].bb_m = NULL;
1237e5ec1e72Spatrick 	return m;
1238e5ec1e72Spatrick }
1239e5ec1e72Spatrick 
1240e5ec1e72Spatrick void
1241e5ec1e72Spatrick bwfm_pci_fill_rx_rings(struct bwfm_pci_softc *sc)
1242e5ec1e72Spatrick {
124318722113Spatrick 	bwfm_pci_fill_rx_buf_ring(sc);
1244e5ec1e72Spatrick 	bwfm_pci_fill_rx_ioctl_ring(sc, &sc->sc_ioctl_ring,
1245e5ec1e72Spatrick 	    MSGBUF_TYPE_IOCTLRESP_BUF_POST);
1246e5ec1e72Spatrick 	bwfm_pci_fill_rx_ioctl_ring(sc, &sc->sc_event_ring,
1247e5ec1e72Spatrick 	    MSGBUF_TYPE_EVENT_BUF_POST);
1248e5ec1e72Spatrick }
1249e5ec1e72Spatrick 
1250e5ec1e72Spatrick void
1251e5ec1e72Spatrick bwfm_pci_fill_rx_ioctl_ring(struct bwfm_pci_softc *sc, struct if_rxring *rxring,
1252e5ec1e72Spatrick     uint32_t msgtype)
1253e5ec1e72Spatrick {
1254e5ec1e72Spatrick 	struct msgbuf_rx_ioctl_resp_or_event *req;
1255e5ec1e72Spatrick 	struct mbuf *m;
1256e5ec1e72Spatrick 	uint32_t pktid;
1257e5ec1e72Spatrick 	paddr_t paddr;
1258e5ec1e72Spatrick 	int s, slots;
1259e5ec1e72Spatrick 
1260e5ec1e72Spatrick 	s = splnet();
1261e5ec1e72Spatrick 	for (slots = if_rxr_get(rxring, 8); slots > 0; slots--) {
126202ee7d07Spatrick 		if (bwfm_pci_pktid_avail(sc, &sc->sc_rx_pkts))
126302ee7d07Spatrick 			break;
1264e5ec1e72Spatrick 		req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit);
1265e5ec1e72Spatrick 		if (req == NULL)
1266e5ec1e72Spatrick 			break;
12671950c5c5Spatrick 		m = MCLGETL(NULL, M_DONTWAIT, MSGBUF_MAX_CTL_PKT_SIZE);
1268e5ec1e72Spatrick 		if (m == NULL) {
1269e5ec1e72Spatrick 			bwfm_pci_ring_write_cancel(sc, &sc->sc_ctrl_submit, 1);
1270e5ec1e72Spatrick 			break;
1271e5ec1e72Spatrick 		}
12721950c5c5Spatrick 		m->m_len = m->m_pkthdr.len = MSGBUF_MAX_CTL_PKT_SIZE;
1273e5ec1e72Spatrick 		if (bwfm_pci_pktid_new(sc, &sc->sc_rx_pkts, m, &pktid, &paddr)) {
1274e5ec1e72Spatrick 			bwfm_pci_ring_write_cancel(sc, &sc->sc_ctrl_submit, 1);
1275e5ec1e72Spatrick 			m_freem(m);
1276e5ec1e72Spatrick 			break;
1277e5ec1e72Spatrick 		}
1278e5ec1e72Spatrick 		memset(req, 0, sizeof(*req));
1279e5ec1e72Spatrick 		req->msg.msgtype = msgtype;
1280e5ec1e72Spatrick 		req->msg.request_id = htole32(pktid);
12811950c5c5Spatrick 		req->host_buf_len = htole16(MSGBUF_MAX_CTL_PKT_SIZE);
1282e4dae658Spatrick 		req->host_buf_addr.high_addr = htole32((uint64_t)paddr >> 32);
1283e5ec1e72Spatrick 		req->host_buf_addr.low_addr = htole32(paddr & 0xffffffff);
1284e5ec1e72Spatrick 		bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit);
1285e5ec1e72Spatrick 	}
1286e5ec1e72Spatrick 	if_rxr_put(rxring, slots);
1287e5ec1e72Spatrick 	splx(s);
1288e5ec1e72Spatrick }
1289e5ec1e72Spatrick 
1290e5ec1e72Spatrick void
1291e5ec1e72Spatrick bwfm_pci_fill_rx_buf_ring(struct bwfm_pci_softc *sc)
1292e5ec1e72Spatrick {
1293e5ec1e72Spatrick 	struct msgbuf_rx_bufpost *req;
1294e5ec1e72Spatrick 	struct mbuf *m;
1295e5ec1e72Spatrick 	uint32_t pktid;
1296e5ec1e72Spatrick 	paddr_t paddr;
1297e5ec1e72Spatrick 	int s, slots;
1298e5ec1e72Spatrick 
1299e5ec1e72Spatrick 	s = splnet();
1300e5ec1e72Spatrick 	for (slots = if_rxr_get(&sc->sc_rxbuf_ring, sc->sc_max_rxbufpost);
1301e5ec1e72Spatrick 	    slots > 0; slots--) {
130202ee7d07Spatrick 		if (bwfm_pci_pktid_avail(sc, &sc->sc_rx_pkts))
130302ee7d07Spatrick 			break;
1304e5ec1e72Spatrick 		req = bwfm_pci_ring_write_reserve(sc, &sc->sc_rxpost_submit);
1305e5ec1e72Spatrick 		if (req == NULL)
1306e5ec1e72Spatrick 			break;
1307471f2571Sjan 		m = MCLGETL(NULL, M_DONTWAIT, MSGBUF_MAX_PKT_SIZE);
1308e5ec1e72Spatrick 		if (m == NULL) {
1309e5ec1e72Spatrick 			bwfm_pci_ring_write_cancel(sc, &sc->sc_rxpost_submit, 1);
1310e5ec1e72Spatrick 			break;
1311e5ec1e72Spatrick 		}
1312e5ec1e72Spatrick 		m->m_len = m->m_pkthdr.len = MSGBUF_MAX_PKT_SIZE;
1313e5ec1e72Spatrick 		if (bwfm_pci_pktid_new(sc, &sc->sc_rx_pkts, m, &pktid, &paddr)) {
1314e5ec1e72Spatrick 			bwfm_pci_ring_write_cancel(sc, &sc->sc_rxpost_submit, 1);
1315e5ec1e72Spatrick 			m_freem(m);
1316e5ec1e72Spatrick 			break;
1317e5ec1e72Spatrick 		}
1318e5ec1e72Spatrick 		memset(req, 0, sizeof(*req));
1319e5ec1e72Spatrick 		req->msg.msgtype = MSGBUF_TYPE_RXBUF_POST;
1320e5ec1e72Spatrick 		req->msg.request_id = htole32(pktid);
1321e5ec1e72Spatrick 		req->data_buf_len = htole16(MSGBUF_MAX_PKT_SIZE);
1322e4dae658Spatrick 		req->data_buf_addr.high_addr = htole32((uint64_t)paddr >> 32);
1323e5ec1e72Spatrick 		req->data_buf_addr.low_addr = htole32(paddr & 0xffffffff);
1324e5ec1e72Spatrick 		bwfm_pci_ring_write_commit(sc, &sc->sc_rxpost_submit);
1325e5ec1e72Spatrick 	}
1326e5ec1e72Spatrick 	if_rxr_put(&sc->sc_rxbuf_ring, slots);
1327e5ec1e72Spatrick 	splx(s);
1328e5ec1e72Spatrick }
1329e5ec1e72Spatrick 
1330e5ec1e72Spatrick int
1331e5ec1e72Spatrick bwfm_pci_setup_ring(struct bwfm_pci_softc *sc, struct bwfm_pci_msgring *ring,
1332e5ec1e72Spatrick     int nitem, size_t itemsz, uint32_t w_idx, uint32_t r_idx,
1333e5ec1e72Spatrick     int idx, uint32_t idx_off, uint32_t *ring_mem)
1334e5ec1e72Spatrick {
1335e5ec1e72Spatrick 	ring->w_idx_addr = w_idx + idx * idx_off;
1336e5ec1e72Spatrick 	ring->r_idx_addr = r_idx + idx * idx_off;
133713f544a8Spatrick 	ring->w_ptr = 0;
133813f544a8Spatrick 	ring->r_ptr = 0;
1339e5ec1e72Spatrick 	ring->nitem = nitem;
1340e5ec1e72Spatrick 	ring->itemsz = itemsz;
1341e5ec1e72Spatrick 	bwfm_pci_ring_write_rptr(sc, ring);
1342e5ec1e72Spatrick 	bwfm_pci_ring_write_wptr(sc, ring);
1343e5ec1e72Spatrick 
1344e5ec1e72Spatrick 	ring->ring = bwfm_pci_dmamem_alloc(sc, nitem * itemsz, 8);
1345e5ec1e72Spatrick 	if (ring->ring == NULL)
1346e5ec1e72Spatrick 		return ENOMEM;
1347e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1348e5ec1e72Spatrick 	    *ring_mem + BWFM_RING_MEM_BASE_ADDR_LOW,
1349e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(ring->ring) & 0xffffffff);
1350e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1351e5ec1e72Spatrick 	    *ring_mem + BWFM_RING_MEM_BASE_ADDR_HIGH,
1352e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(ring->ring) >> 32);
1353e5ec1e72Spatrick 	bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1354e5ec1e72Spatrick 	    *ring_mem + BWFM_RING_MAX_ITEM, nitem);
1355e5ec1e72Spatrick 	bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1356e5ec1e72Spatrick 	    *ring_mem + BWFM_RING_LEN_ITEMS, itemsz);
1357e5ec1e72Spatrick 	*ring_mem = *ring_mem + BWFM_RING_MEM_SZ;
1358e5ec1e72Spatrick 	return 0;
1359e5ec1e72Spatrick }
1360e5ec1e72Spatrick 
1361518be5f3Spatrick int
1362518be5f3Spatrick bwfm_pci_setup_flowring(struct bwfm_pci_softc *sc, struct bwfm_pci_msgring *ring,
1363518be5f3Spatrick     int nitem, size_t itemsz)
1364518be5f3Spatrick {
1365518be5f3Spatrick 	ring->w_ptr = 0;
1366518be5f3Spatrick 	ring->r_ptr = 0;
1367518be5f3Spatrick 	ring->nitem = nitem;
1368518be5f3Spatrick 	ring->itemsz = itemsz;
1369518be5f3Spatrick 	bwfm_pci_ring_write_rptr(sc, ring);
1370518be5f3Spatrick 	bwfm_pci_ring_write_wptr(sc, ring);
1371518be5f3Spatrick 
1372518be5f3Spatrick 	ring->ring = bwfm_pci_dmamem_alloc(sc, nitem * itemsz, 8);
1373518be5f3Spatrick 	if (ring->ring == NULL)
1374518be5f3Spatrick 		return ENOMEM;
1375518be5f3Spatrick 	return 0;
1376518be5f3Spatrick }
1377518be5f3Spatrick 
1378e5ec1e72Spatrick /* Ring helpers */
1379e5ec1e72Spatrick void
1380e5ec1e72Spatrick bwfm_pci_ring_bell(struct bwfm_pci_softc *sc,
1381e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1382e5ec1e72Spatrick {
1383*8bad4727Spatrick 	if (sc->sc_pcireg64)
1384bb813cf8Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1385bb813cf8Spatrick 		    BWFM_PCI_64_PCIE2REG_H2D_MAILBOX_0, 1);
1386bb813cf8Spatrick 	else
1387e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1388156d2677Spatrick 		    BWFM_PCI_PCIE2REG_H2D_MAILBOX_0, 1);
1389e5ec1e72Spatrick }
1390e5ec1e72Spatrick 
1391e5ec1e72Spatrick void
1392e5ec1e72Spatrick bwfm_pci_ring_update_rptr(struct bwfm_pci_softc *sc,
1393e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1394e5ec1e72Spatrick {
1395e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
1396e5ec1e72Spatrick 		ring->r_ptr = bus_space_read_2(sc->sc_tcm_iot,
1397e5ec1e72Spatrick 		    sc->sc_tcm_ioh, ring->r_idx_addr);
1398e5ec1e72Spatrick 	} else {
1399dcb67343Spatrick 		bus_dmamap_sync(sc->sc_dmat,
1400dcb67343Spatrick 		    BWFM_PCI_DMA_MAP(sc->sc_dma_idx_buf), ring->r_idx_addr,
1401dcb67343Spatrick 		    sizeof(uint16_t), BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1402e5ec1e72Spatrick 		ring->r_ptr = *(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf)
1403e5ec1e72Spatrick 		    + ring->r_idx_addr);
1404e5ec1e72Spatrick 	}
1405e5ec1e72Spatrick }
1406e5ec1e72Spatrick 
1407e5ec1e72Spatrick void
1408e5ec1e72Spatrick bwfm_pci_ring_update_wptr(struct bwfm_pci_softc *sc,
1409e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1410e5ec1e72Spatrick {
1411e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
1412e5ec1e72Spatrick 		ring->w_ptr = bus_space_read_2(sc->sc_tcm_iot,
1413e5ec1e72Spatrick 		    sc->sc_tcm_ioh, ring->w_idx_addr);
1414e5ec1e72Spatrick 	} else {
1415dcb67343Spatrick 		bus_dmamap_sync(sc->sc_dmat,
1416dcb67343Spatrick 		    BWFM_PCI_DMA_MAP(sc->sc_dma_idx_buf), ring->w_idx_addr,
1417dcb67343Spatrick 		    sizeof(uint16_t), BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1418e5ec1e72Spatrick 		ring->w_ptr = *(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf)
1419e5ec1e72Spatrick 		    + ring->w_idx_addr);
1420e5ec1e72Spatrick 	}
1421e5ec1e72Spatrick }
1422e5ec1e72Spatrick 
1423e5ec1e72Spatrick void
1424e5ec1e72Spatrick bwfm_pci_ring_write_rptr(struct bwfm_pci_softc *sc,
1425e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1426e5ec1e72Spatrick {
1427e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
1428e5ec1e72Spatrick 		bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1429e5ec1e72Spatrick 		    ring->r_idx_addr, ring->r_ptr);
1430e5ec1e72Spatrick 	} else {
1431e5ec1e72Spatrick 		*(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf)
1432e5ec1e72Spatrick 		    + ring->r_idx_addr) = ring->r_ptr;
1433dcb67343Spatrick 		bus_dmamap_sync(sc->sc_dmat,
1434dcb67343Spatrick 		    BWFM_PCI_DMA_MAP(sc->sc_dma_idx_buf), ring->r_idx_addr,
1435dcb67343Spatrick 		    sizeof(uint16_t), BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1436e5ec1e72Spatrick 	}
1437e5ec1e72Spatrick }
1438e5ec1e72Spatrick 
1439e5ec1e72Spatrick void
1440e5ec1e72Spatrick bwfm_pci_ring_write_wptr(struct bwfm_pci_softc *sc,
1441e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1442e5ec1e72Spatrick {
1443e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
1444e5ec1e72Spatrick 		bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1445e5ec1e72Spatrick 		    ring->w_idx_addr, ring->w_ptr);
1446e5ec1e72Spatrick 	} else {
1447e5ec1e72Spatrick 		*(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf)
1448e5ec1e72Spatrick 		    + ring->w_idx_addr) = ring->w_ptr;
1449dcb67343Spatrick 		bus_dmamap_sync(sc->sc_dmat,
1450dcb67343Spatrick 		    BWFM_PCI_DMA_MAP(sc->sc_dma_idx_buf), ring->w_idx_addr,
1451dcb67343Spatrick 		    sizeof(uint16_t), BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1452e5ec1e72Spatrick 	}
1453e5ec1e72Spatrick }
1454e5ec1e72Spatrick 
1455e5ec1e72Spatrick /*
1456e5ec1e72Spatrick  * Retrieve a free descriptor to put new stuff in, but don't commit
1457e5ec1e72Spatrick  * to it yet so we can rollback later if any error occurs.
1458e5ec1e72Spatrick  */
1459e5ec1e72Spatrick void *
1460e5ec1e72Spatrick bwfm_pci_ring_write_reserve(struct bwfm_pci_softc *sc,
1461e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1462e5ec1e72Spatrick {
1463e5ec1e72Spatrick 	int available;
1464e5ec1e72Spatrick 	char *ret;
1465e5ec1e72Spatrick 
1466e5ec1e72Spatrick 	bwfm_pci_ring_update_rptr(sc, ring);
1467e5ec1e72Spatrick 
1468e5ec1e72Spatrick 	if (ring->r_ptr > ring->w_ptr)
1469e5ec1e72Spatrick 		available = ring->r_ptr - ring->w_ptr;
1470e5ec1e72Spatrick 	else
1471e5ec1e72Spatrick 		available = ring->r_ptr + (ring->nitem - ring->w_ptr);
1472e5ec1e72Spatrick 
147330f5ada0Spatrick 	if (available <= 1)
1474e5ec1e72Spatrick 		return NULL;
1475e5ec1e72Spatrick 
1476e5ec1e72Spatrick 	ret = BWFM_PCI_DMA_KVA(ring->ring) + (ring->w_ptr * ring->itemsz);
1477e5ec1e72Spatrick 	ring->w_ptr += 1;
1478e5ec1e72Spatrick 	if (ring->w_ptr == ring->nitem)
1479e5ec1e72Spatrick 		ring->w_ptr = 0;
1480e5ec1e72Spatrick 	return ret;
1481e5ec1e72Spatrick }
1482e5ec1e72Spatrick 
1483e5ec1e72Spatrick void *
1484e5ec1e72Spatrick bwfm_pci_ring_write_reserve_multi(struct bwfm_pci_softc *sc,
1485e5ec1e72Spatrick     struct bwfm_pci_msgring *ring, int count, int *avail)
1486e5ec1e72Spatrick {
1487e5ec1e72Spatrick 	int available;
1488e5ec1e72Spatrick 	char *ret;
1489e5ec1e72Spatrick 
1490e5ec1e72Spatrick 	bwfm_pci_ring_update_rptr(sc, ring);
1491e5ec1e72Spatrick 
1492e5ec1e72Spatrick 	if (ring->r_ptr > ring->w_ptr)
1493e5ec1e72Spatrick 		available = ring->r_ptr - ring->w_ptr;
1494e5ec1e72Spatrick 	else
1495e5ec1e72Spatrick 		available = ring->r_ptr + (ring->nitem - ring->w_ptr);
1496e5ec1e72Spatrick 
149730f5ada0Spatrick 	if (available <= 1)
1498e5ec1e72Spatrick 		return NULL;
1499e5ec1e72Spatrick 
1500e5ec1e72Spatrick 	ret = BWFM_PCI_DMA_KVA(ring->ring) + (ring->w_ptr * ring->itemsz);
1501e5ec1e72Spatrick 	*avail = min(count, available - 1);
1502e5ec1e72Spatrick 	if (*avail + ring->w_ptr > ring->nitem)
1503e5ec1e72Spatrick 		*avail = ring->nitem - ring->w_ptr;
1504e5ec1e72Spatrick 	ring->w_ptr += *avail;
1505e5ec1e72Spatrick 	if (ring->w_ptr == ring->nitem)
1506e5ec1e72Spatrick 		ring->w_ptr = 0;
1507e5ec1e72Spatrick 	return ret;
1508e5ec1e72Spatrick }
1509e5ec1e72Spatrick 
1510e5ec1e72Spatrick /*
1511e5ec1e72Spatrick  * Read number of descriptors available (submitted by the firmware)
1512e5ec1e72Spatrick  * and retrieve pointer to first descriptor.
1513e5ec1e72Spatrick  */
1514e5ec1e72Spatrick void *
1515e5ec1e72Spatrick bwfm_pci_ring_read_avail(struct bwfm_pci_softc *sc,
1516e5ec1e72Spatrick     struct bwfm_pci_msgring *ring, int *avail)
1517e5ec1e72Spatrick {
1518e5ec1e72Spatrick 	bwfm_pci_ring_update_wptr(sc, ring);
1519e5ec1e72Spatrick 
1520e5ec1e72Spatrick 	if (ring->w_ptr >= ring->r_ptr)
1521e5ec1e72Spatrick 		*avail = ring->w_ptr - ring->r_ptr;
1522e5ec1e72Spatrick 	else
1523e5ec1e72Spatrick 		*avail = ring->nitem - ring->r_ptr;
1524e5ec1e72Spatrick 
1525e5ec1e72Spatrick 	if (*avail == 0)
1526e5ec1e72Spatrick 		return NULL;
1527e5ec1e72Spatrick 
1528dcb67343Spatrick 	bus_dmamap_sync(sc->sc_dmat, BWFM_PCI_DMA_MAP(ring->ring),
1529dcb67343Spatrick 	    ring->r_ptr * ring->itemsz, *avail * ring->itemsz,
1530dcb67343Spatrick 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1531e5ec1e72Spatrick 	return BWFM_PCI_DMA_KVA(ring->ring) + (ring->r_ptr * ring->itemsz);
1532e5ec1e72Spatrick }
1533e5ec1e72Spatrick 
1534e5ec1e72Spatrick /*
1535e5ec1e72Spatrick  * Let firmware know we read N descriptors.
1536e5ec1e72Spatrick  */
1537e5ec1e72Spatrick void
1538e5ec1e72Spatrick bwfm_pci_ring_read_commit(struct bwfm_pci_softc *sc,
1539e5ec1e72Spatrick     struct bwfm_pci_msgring *ring, int nitem)
1540e5ec1e72Spatrick {
1541e5ec1e72Spatrick 	ring->r_ptr += nitem;
1542e5ec1e72Spatrick 	if (ring->r_ptr == ring->nitem)
1543e5ec1e72Spatrick 		ring->r_ptr = 0;
1544e5ec1e72Spatrick 	bwfm_pci_ring_write_rptr(sc, ring);
1545e5ec1e72Spatrick }
1546e5ec1e72Spatrick 
1547e5ec1e72Spatrick /*
1548e5ec1e72Spatrick  * Let firmware know that we submitted some descriptors.
1549e5ec1e72Spatrick  */
1550e5ec1e72Spatrick void
1551e5ec1e72Spatrick bwfm_pci_ring_write_commit(struct bwfm_pci_softc *sc,
1552e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1553e5ec1e72Spatrick {
1554dcb67343Spatrick 	bus_dmamap_sync(sc->sc_dmat, BWFM_PCI_DMA_MAP(ring->ring),
1555dcb67343Spatrick 	    0, BWFM_PCI_DMA_LEN(ring->ring), BUS_DMASYNC_PREREAD |
1556dcb67343Spatrick 	    BUS_DMASYNC_PREWRITE);
1557e5ec1e72Spatrick 	bwfm_pci_ring_write_wptr(sc, ring);
1558e5ec1e72Spatrick 	bwfm_pci_ring_bell(sc, ring);
1559e5ec1e72Spatrick }
1560e5ec1e72Spatrick 
1561e5ec1e72Spatrick /*
1562e5ec1e72Spatrick  * Rollback N descriptors in case we don't actually want
1563e5ec1e72Spatrick  * to commit to it.
1564e5ec1e72Spatrick  */
1565e5ec1e72Spatrick void
1566e5ec1e72Spatrick bwfm_pci_ring_write_cancel(struct bwfm_pci_softc *sc,
1567e5ec1e72Spatrick     struct bwfm_pci_msgring *ring, int nitem)
1568e5ec1e72Spatrick {
1569e5ec1e72Spatrick 	if (ring->w_ptr == 0)
1570e5ec1e72Spatrick 		ring->w_ptr = ring->nitem - nitem;
1571e5ec1e72Spatrick 	else
1572e5ec1e72Spatrick 		ring->w_ptr -= nitem;
1573e5ec1e72Spatrick }
1574e5ec1e72Spatrick 
1575e5ec1e72Spatrick /*
1576e5ec1e72Spatrick  * Foreach written descriptor on the ring, pass the descriptor to
1577e5ec1e72Spatrick  * a message handler and let the firmware know we handled it.
1578e5ec1e72Spatrick  */
1579e5ec1e72Spatrick void
15806f241297Spatrick bwfm_pci_ring_rx(struct bwfm_pci_softc *sc, struct bwfm_pci_msgring *ring,
15816f241297Spatrick     struct mbuf_list *ml)
1582e5ec1e72Spatrick {
1583e5ec1e72Spatrick 	void *buf;
1584e5ec1e72Spatrick 	int avail, processed;
1585e5ec1e72Spatrick 
1586e5ec1e72Spatrick again:
1587e5ec1e72Spatrick 	buf = bwfm_pci_ring_read_avail(sc, ring, &avail);
1588e5ec1e72Spatrick 	if (buf == NULL)
1589e5ec1e72Spatrick 		return;
1590e5ec1e72Spatrick 
1591e5ec1e72Spatrick 	processed = 0;
1592e5ec1e72Spatrick 	while (avail) {
15936f241297Spatrick 		bwfm_pci_msg_rx(sc, buf + sc->sc_rx_dataoffset, ml);
1594e5ec1e72Spatrick 		buf += ring->itemsz;
1595e5ec1e72Spatrick 		processed++;
1596e5ec1e72Spatrick 		if (processed == 48) {
1597e5ec1e72Spatrick 			bwfm_pci_ring_read_commit(sc, ring, processed);
1598e5ec1e72Spatrick 			processed = 0;
1599e5ec1e72Spatrick 		}
1600e5ec1e72Spatrick 		avail--;
1601e5ec1e72Spatrick 	}
1602e5ec1e72Spatrick 	if (processed)
1603e5ec1e72Spatrick 		bwfm_pci_ring_read_commit(sc, ring, processed);
1604e5ec1e72Spatrick 	if (ring->r_ptr == 0)
1605e5ec1e72Spatrick 		goto again;
1606e5ec1e72Spatrick }
1607e5ec1e72Spatrick 
1608e5ec1e72Spatrick void
16096f241297Spatrick bwfm_pci_msg_rx(struct bwfm_pci_softc *sc, void *buf, struct mbuf_list *ml)
1610e5ec1e72Spatrick {
1611518be5f3Spatrick 	struct ifnet *ifp = &sc->sc_sc.sc_ic.ic_if;
1612e5ec1e72Spatrick 	struct msgbuf_ioctl_resp_hdr *resp;
1613518be5f3Spatrick 	struct msgbuf_tx_status *tx;
161418722113Spatrick 	struct msgbuf_rx_complete *rx;
1615e5ec1e72Spatrick 	struct msgbuf_rx_event *event;
1616e5ec1e72Spatrick 	struct msgbuf_common_hdr *msg;
1617518be5f3Spatrick 	struct msgbuf_flowring_create_resp *fcr;
1618a2c6ff8bSpatrick 	struct msgbuf_flowring_delete_resp *fdr;
1619b5553ee6Spatrick 	struct bwfm_cmd_flowring_create fdcmd;
1620518be5f3Spatrick 	struct bwfm_pci_msgring *ring;
1621e5ec1e72Spatrick 	struct mbuf *m;
1622518be5f3Spatrick 	int flowid;
1623e5ec1e72Spatrick 
1624e5ec1e72Spatrick 	msg = (struct msgbuf_common_hdr *)buf;
1625e5ec1e72Spatrick 	switch (msg->msgtype)
1626e5ec1e72Spatrick 	{
1627518be5f3Spatrick 	case MSGBUF_TYPE_FLOW_RING_CREATE_CMPLT:
1628518be5f3Spatrick 		fcr = (struct msgbuf_flowring_create_resp *)buf;
1629518be5f3Spatrick 		flowid = letoh16(fcr->compl_hdr.flow_ring_id);
1630518be5f3Spatrick 		if (flowid < 2)
1631518be5f3Spatrick 			break;
1632518be5f3Spatrick 		flowid -= 2;
1633518be5f3Spatrick 		if (flowid >= sc->sc_max_flowrings)
1634518be5f3Spatrick 			break;
1635518be5f3Spatrick 		ring = &sc->sc_flowrings[flowid];
1636518be5f3Spatrick 		if (ring->status != RING_OPENING)
1637518be5f3Spatrick 			break;
1638518be5f3Spatrick 		if (fcr->compl_hdr.status) {
1639518be5f3Spatrick 			printf("%s: failed to open flowring %d\n",
1640518be5f3Spatrick 			    DEVNAME(sc), flowid);
1641518be5f3Spatrick 			ring->status = RING_CLOSED;
164202ee7d07Spatrick 			if (ring->m) {
164302ee7d07Spatrick 				m_freem(ring->m);
164402ee7d07Spatrick 				ring->m = NULL;
164502ee7d07Spatrick 			}
1646518be5f3Spatrick 			ifq_restart(&ifp->if_snd);
1647518be5f3Spatrick 			break;
1648518be5f3Spatrick 		}
1649518be5f3Spatrick 		ring->status = RING_OPEN;
165002ee7d07Spatrick 		if (ring->m != NULL) {
165102ee7d07Spatrick 			m = ring->m;
165202ee7d07Spatrick 			ring->m = NULL;
165302ee7d07Spatrick 			if (bwfm_pci_txdata(&sc->sc_sc, m))
165402ee7d07Spatrick 				m_freem(ring->m);
165502ee7d07Spatrick 		}
1656518be5f3Spatrick 		ifq_restart(&ifp->if_snd);
1657518be5f3Spatrick 		break;
1658a2c6ff8bSpatrick 	case MSGBUF_TYPE_FLOW_RING_DELETE_CMPLT:
1659a2c6ff8bSpatrick 		fdr = (struct msgbuf_flowring_delete_resp *)buf;
1660a2c6ff8bSpatrick 		flowid = letoh16(fdr->compl_hdr.flow_ring_id);
1661a2c6ff8bSpatrick 		if (flowid < 2)
1662a2c6ff8bSpatrick 			break;
1663a2c6ff8bSpatrick 		flowid -= 2;
1664a2c6ff8bSpatrick 		if (flowid >= sc->sc_max_flowrings)
1665a2c6ff8bSpatrick 			break;
1666a2c6ff8bSpatrick 		ring = &sc->sc_flowrings[flowid];
1667a2c6ff8bSpatrick 		if (ring->status != RING_CLOSING)
1668a2c6ff8bSpatrick 			break;
1669a2c6ff8bSpatrick 		if (fdr->compl_hdr.status) {
1670a2c6ff8bSpatrick 			printf("%s: failed to delete flowring %d\n",
1671a2c6ff8bSpatrick 			    DEVNAME(sc), flowid);
1672a2c6ff8bSpatrick 			break;
1673a2c6ff8bSpatrick 		}
1674b5553ee6Spatrick 		fdcmd.flowid = flowid;
1675b5553ee6Spatrick 		bwfm_do_async(&sc->sc_sc, bwfm_pci_flowring_delete_cb,
1676b5553ee6Spatrick 		    &fdcmd, sizeof(fdcmd));
1677a2c6ff8bSpatrick 		break;
1678e5ec1e72Spatrick 	case MSGBUF_TYPE_IOCTLPTR_REQ_ACK:
16792eeba925Spatrick 		m = bwfm_pci_pktid_free(sc, &sc->sc_ioctl_pkts,
16802eeba925Spatrick 		    letoh32(msg->request_id));
16812eeba925Spatrick 		if (m == NULL)
16822eeba925Spatrick 			break;
16832eeba925Spatrick 		m_freem(m);
1684e5ec1e72Spatrick 		break;
1685e5ec1e72Spatrick 	case MSGBUF_TYPE_IOCTL_CMPLT:
1686e5ec1e72Spatrick 		resp = (struct msgbuf_ioctl_resp_hdr *)buf;
16872eeba925Spatrick 		bwfm_pci_msgbuf_rxioctl(sc, resp);
1688e5ec1e72Spatrick 		if_rxr_put(&sc->sc_ioctl_ring, 1);
1689e5ec1e72Spatrick 		bwfm_pci_fill_rx_rings(sc);
1690e5ec1e72Spatrick 		break;
1691e5ec1e72Spatrick 	case MSGBUF_TYPE_WL_EVENT:
1692e5ec1e72Spatrick 		event = (struct msgbuf_rx_event *)buf;
1693e5ec1e72Spatrick 		m = bwfm_pci_pktid_free(sc, &sc->sc_rx_pkts,
1694e5ec1e72Spatrick 		    letoh32(event->msg.request_id));
1695e5ec1e72Spatrick 		if (m == NULL)
1696e5ec1e72Spatrick 			break;
1697e5ec1e72Spatrick 		m_adj(m, sc->sc_rx_dataoffset);
1698f37fc236Spatrick 		m->m_len = m->m_pkthdr.len = letoh16(event->event_data_len);
16996f241297Spatrick 		bwfm_rx(&sc->sc_sc, m, ml);
1700e5ec1e72Spatrick 		if_rxr_put(&sc->sc_event_ring, 1);
1701e5ec1e72Spatrick 		bwfm_pci_fill_rx_rings(sc);
1702e5ec1e72Spatrick 		break;
1703518be5f3Spatrick 	case MSGBUF_TYPE_TX_STATUS:
1704518be5f3Spatrick 		tx = (struct msgbuf_tx_status *)buf;
1705518be5f3Spatrick 		m = bwfm_pci_pktid_free(sc, &sc->sc_tx_pkts,
1706f9ee104fSpatrick 		    letoh32(tx->msg.request_id) - 1);
1707518be5f3Spatrick 		if (m == NULL)
1708518be5f3Spatrick 			break;
1709518be5f3Spatrick 		m_freem(m);
1710c6f1636dSpatrick 		if (sc->sc_tx_pkts_full) {
1711c6f1636dSpatrick 			sc->sc_tx_pkts_full = 0;
1712c6f1636dSpatrick 			ifq_restart(&ifp->if_snd);
1713c6f1636dSpatrick 		}
1714518be5f3Spatrick 		break;
171518722113Spatrick 	case MSGBUF_TYPE_RX_CMPLT:
171618722113Spatrick 		rx = (struct msgbuf_rx_complete *)buf;
171718722113Spatrick 		m = bwfm_pci_pktid_free(sc, &sc->sc_rx_pkts,
171818722113Spatrick 		    letoh32(rx->msg.request_id));
171918722113Spatrick 		if (m == NULL)
172018722113Spatrick 			break;
172118722113Spatrick 		if (letoh16(rx->data_offset))
172218722113Spatrick 			m_adj(m, letoh16(rx->data_offset));
172318722113Spatrick 		else if (sc->sc_rx_dataoffset)
172418722113Spatrick 			m_adj(m, sc->sc_rx_dataoffset);
1725f37fc236Spatrick 		m->m_len = m->m_pkthdr.len = letoh16(rx->data_len);
17266f241297Spatrick 		bwfm_rx(&sc->sc_sc, m, ml);
172718722113Spatrick 		if_rxr_put(&sc->sc_rxbuf_ring, 1);
172818722113Spatrick 		bwfm_pci_fill_rx_rings(sc);
172918722113Spatrick 		break;
1730e5ec1e72Spatrick 	default:
1731e5ec1e72Spatrick 		printf("%s: msgtype 0x%08x\n", __func__, msg->msgtype);
1732e5ec1e72Spatrick 		break;
1733e5ec1e72Spatrick 	}
1734e5ec1e72Spatrick }
1735e5ec1e72Spatrick 
1736e5ec1e72Spatrick /* Bus core helpers */
1737e5ec1e72Spatrick void
1738e5ec1e72Spatrick bwfm_pci_select_core(struct bwfm_pci_softc *sc, int id)
1739e5ec1e72Spatrick {
1740e5ec1e72Spatrick 	struct bwfm_softc *bwfm = (void *)sc;
1741e5ec1e72Spatrick 	struct bwfm_core *core;
1742e5ec1e72Spatrick 
1743e5ec1e72Spatrick 	core = bwfm_chip_get_core(bwfm, id);
1744e5ec1e72Spatrick 	if (core == NULL) {
1745e5ec1e72Spatrick 		printf("%s: could not find core to select", DEVNAME(sc));
1746e5ec1e72Spatrick 		return;
1747e5ec1e72Spatrick 	}
1748e5ec1e72Spatrick 
1749e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag,
1750e5ec1e72Spatrick 	    BWFM_PCI_BAR0_WINDOW, core->co_base);
1751e5ec1e72Spatrick 	if (pci_conf_read(sc->sc_pc, sc->sc_tag,
1752e5ec1e72Spatrick 	    BWFM_PCI_BAR0_WINDOW) != core->co_base)
1753e5ec1e72Spatrick 		pci_conf_write(sc->sc_pc, sc->sc_tag,
1754e5ec1e72Spatrick 		    BWFM_PCI_BAR0_WINDOW, core->co_base);
1755e5ec1e72Spatrick }
1756e5ec1e72Spatrick 
1757e5ec1e72Spatrick uint32_t
1758e5ec1e72Spatrick bwfm_pci_buscore_read(struct bwfm_softc *bwfm, uint32_t reg)
1759e5ec1e72Spatrick {
1760e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1761e5ec1e72Spatrick 	uint32_t page, offset;
1762e5ec1e72Spatrick 
1763e5ec1e72Spatrick 	page = reg & ~(BWFM_PCI_BAR0_REG_SIZE - 1);
1764e5ec1e72Spatrick 	offset = reg & (BWFM_PCI_BAR0_REG_SIZE - 1);
1765e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_BAR0_WINDOW, page);
1766e5ec1e72Spatrick 	return bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh, offset);
1767e5ec1e72Spatrick }
1768e5ec1e72Spatrick 
1769e5ec1e72Spatrick void
1770e5ec1e72Spatrick bwfm_pci_buscore_write(struct bwfm_softc *bwfm, uint32_t reg, uint32_t val)
1771e5ec1e72Spatrick {
1772e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1773e5ec1e72Spatrick 	uint32_t page, offset;
1774e5ec1e72Spatrick 
1775e5ec1e72Spatrick 	page = reg & ~(BWFM_PCI_BAR0_REG_SIZE - 1);
1776e5ec1e72Spatrick 	offset = reg & (BWFM_PCI_BAR0_REG_SIZE - 1);
1777e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_BAR0_WINDOW, page);
1778e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, offset, val);
1779e5ec1e72Spatrick }
1780e5ec1e72Spatrick 
1781e5ec1e72Spatrick int
1782e5ec1e72Spatrick bwfm_pci_buscore_prepare(struct bwfm_softc *bwfm)
1783e5ec1e72Spatrick {
1784e5ec1e72Spatrick 	return 0;
1785e5ec1e72Spatrick }
1786e5ec1e72Spatrick 
1787e5ec1e72Spatrick int
1788e5ec1e72Spatrick bwfm_pci_buscore_reset(struct bwfm_softc *bwfm)
1789e5ec1e72Spatrick {
1790e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1791e5ec1e72Spatrick 	struct bwfm_core *core;
1792e5ec1e72Spatrick 	uint32_t reg;
1793e5ec1e72Spatrick 	int i;
1794e5ec1e72Spatrick 
1795e5ec1e72Spatrick 	bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2);
1796e5ec1e72Spatrick 	reg = pci_conf_read(sc->sc_pc, sc->sc_tag,
1797e5ec1e72Spatrick 	    BWFM_PCI_CFGREG_LINK_STATUS_CTRL);
1798e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_CFGREG_LINK_STATUS_CTRL,
1799e5ec1e72Spatrick 	    reg & ~BWFM_PCI_CFGREG_LINK_STATUS_CTRL_ASPM_ENAB);
1800e5ec1e72Spatrick 
1801e5ec1e72Spatrick 	bwfm_pci_select_core(sc, BWFM_AGENT_CORE_CHIPCOMMON);
1802e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1803e5ec1e72Spatrick 	    BWFM_CHIP_REG_WATCHDOG, 4);
1804e5ec1e72Spatrick 	delay(100 * 1000);
1805e5ec1e72Spatrick 
1806e5ec1e72Spatrick 	bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2);
1807e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag,
1808e5ec1e72Spatrick 	    BWFM_PCI_CFGREG_LINK_STATUS_CTRL, reg);
1809e5ec1e72Spatrick 
1810e5ec1e72Spatrick 	core = bwfm_chip_get_core(bwfm, BWFM_AGENT_CORE_PCIE2);
1811e5ec1e72Spatrick 	if (core->co_rev <= 13) {
1812e5ec1e72Spatrick 		uint16_t cfg_offset[] = {
1813e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_STATUS_CMD,
1814e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_PM_CSR,
1815e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_MSI_CAP,
1816e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_MSI_ADDR_L,
1817e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_MSI_ADDR_H,
1818e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_MSI_DATA,
1819e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_LINK_STATUS_CTRL2,
1820e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_RBAR_CTRL,
1821e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_PML1_SUB_CTRL1,
1822e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_REG_BAR2_CONFIG,
1823e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_REG_BAR3_CONFIG,
1824e5ec1e72Spatrick 		};
1825e5ec1e72Spatrick 
1826e5ec1e72Spatrick 		for (i = 0; i < nitems(cfg_offset); i++) {
1827e5ec1e72Spatrick 			bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1828e5ec1e72Spatrick 			    BWFM_PCI_PCIE2REG_CONFIGADDR, cfg_offset[i]);
1829e5ec1e72Spatrick 			reg = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1830e5ec1e72Spatrick 			    BWFM_PCI_PCIE2REG_CONFIGDATA);
1831e5ec1e72Spatrick 			DPRINTFN(3, ("%s: config offset 0x%04x, value 0x%04x\n",
1832e5ec1e72Spatrick 			    DEVNAME(sc), cfg_offset[i], reg));
1833e5ec1e72Spatrick 			bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1834e5ec1e72Spatrick 			    BWFM_PCI_PCIE2REG_CONFIGDATA, reg);
1835e5ec1e72Spatrick 		}
1836e5ec1e72Spatrick 	}
1837*8bad4727Spatrick 	if (core->co_rev >= 64)
1838*8bad4727Spatrick 		sc->sc_pcireg64 = 1;
1839e5ec1e72Spatrick 
1840bb813cf8Spatrick 	reg = bwfm_pci_intr_status(sc);
1841e5ec1e72Spatrick 	if (reg != 0xffffffff)
1842bb813cf8Spatrick 		bwfm_pci_intr_ack(sc, reg);
1843e5ec1e72Spatrick 
1844e5ec1e72Spatrick 	return 0;
1845e5ec1e72Spatrick }
1846e5ec1e72Spatrick 
1847e5ec1e72Spatrick void
1848e5ec1e72Spatrick bwfm_pci_buscore_activate(struct bwfm_softc *bwfm, uint32_t rstvec)
1849e5ec1e72Spatrick {
1850e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1851e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 0, rstvec);
1852e5ec1e72Spatrick }
1853e5ec1e72Spatrick 
1854f67437f3Spatrick static int bwfm_pci_prio2fifo[8] = {
18559e2c067eSpatrick 	0, /* best effort */
18569e2c067eSpatrick 	1, /* IPTOS_PREC_IMMEDIATE */
18579e2c067eSpatrick 	1, /* IPTOS_PREC_PRIORITY */
18589e2c067eSpatrick 	0, /* IPTOS_PREC_FLASH */
1859f67437f3Spatrick 	2, /* IPTOS_PREC_FLASHOVERRIDE */
1860f67437f3Spatrick 	2, /* IPTOS_PREC_CRITIC_ECP */
1861f67437f3Spatrick 	3, /* IPTOS_PREC_INTERNETCONTROL */
1862f67437f3Spatrick 	3, /* IPTOS_PREC_NETCONTROL */
1863f67437f3Spatrick };
1864f67437f3Spatrick 
1865f67437f3Spatrick int
1866f67437f3Spatrick bwfm_pci_flowring_lookup(struct bwfm_pci_softc *sc, struct mbuf *m)
1867518be5f3Spatrick {
1868f67437f3Spatrick 	struct ieee80211com *ic = &sc->sc_sc.sc_ic;
1869e6abcda3Smlarkin #ifndef IEEE80211_STA_ONLY
1870f67437f3Spatrick 	uint8_t *da = mtod(m, uint8_t *);
1871e6abcda3Smlarkin #endif
1872f67437f3Spatrick 	int flowid, prio, fifo;
1873f67437f3Spatrick 	int i, found;
1874f67437f3Spatrick 
1875f67437f3Spatrick 	prio = ieee80211_classify(ic, m);
1876f67437f3Spatrick 	fifo = bwfm_pci_prio2fifo[prio];
1877f67437f3Spatrick 
1878f67437f3Spatrick 	switch (ic->ic_opmode)
1879f67437f3Spatrick 	{
1880f67437f3Spatrick 	case IEEE80211_M_STA:
1881f67437f3Spatrick 		flowid = fifo;
1882f67437f3Spatrick 		break;
1883f67437f3Spatrick #ifndef IEEE80211_STA_ONLY
1884f67437f3Spatrick 	case IEEE80211_M_HOSTAP:
18852b7bea7eSpatrick 		if (ETHER_IS_MULTICAST(da))
18862b7bea7eSpatrick 			da = etherbroadcastaddr;
1887f67437f3Spatrick 		flowid = da[5] * 2 + fifo;
1888f67437f3Spatrick 		break;
1889f67437f3Spatrick #endif
1890f67437f3Spatrick 	default:
1891f67437f3Spatrick 		printf("%s: state not supported\n", DEVNAME(sc));
1892f67437f3Spatrick 		return ENOBUFS;
1893f67437f3Spatrick 	}
1894f67437f3Spatrick 
1895f67437f3Spatrick 	found = 0;
1896f67437f3Spatrick 	flowid = flowid % sc->sc_max_flowrings;
1897f67437f3Spatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
1898f67437f3Spatrick 		if (ic->ic_opmode == IEEE80211_M_STA &&
1899f67437f3Spatrick 		    sc->sc_flowrings[flowid].status >= RING_OPEN &&
1900f67437f3Spatrick 		    sc->sc_flowrings[flowid].fifo == fifo) {
1901f67437f3Spatrick 			found = 1;
1902f67437f3Spatrick 			break;
1903f67437f3Spatrick 		}
1904f67437f3Spatrick #ifndef IEEE80211_STA_ONLY
1905f67437f3Spatrick 		if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
1906f67437f3Spatrick 		    sc->sc_flowrings[flowid].status >= RING_OPEN &&
1907f67437f3Spatrick 		    sc->sc_flowrings[flowid].fifo == fifo &&
1908a2c6ff8bSpatrick 		    !memcmp(sc->sc_flowrings[flowid].mac, da, ETHER_ADDR_LEN)) {
1909f67437f3Spatrick 			found = 1;
1910f67437f3Spatrick 			break;
1911f67437f3Spatrick 		}
1912f67437f3Spatrick #endif
1913f67437f3Spatrick 		flowid = (flowid + 1) % sc->sc_max_flowrings;
1914f67437f3Spatrick 	}
1915f67437f3Spatrick 
1916f67437f3Spatrick 	if (found)
1917f67437f3Spatrick 		return flowid;
1918f67437f3Spatrick 
1919f67437f3Spatrick 	return -1;
1920f67437f3Spatrick }
1921f67437f3Spatrick 
1922f67437f3Spatrick void
1923f67437f3Spatrick bwfm_pci_flowring_create(struct bwfm_pci_softc *sc, struct mbuf *m)
1924f67437f3Spatrick {
1925f67437f3Spatrick 	struct ieee80211com *ic = &sc->sc_sc.sc_ic;
1926518be5f3Spatrick 	struct bwfm_cmd_flowring_create cmd;
1927e6abcda3Smlarkin #ifndef IEEE80211_STA_ONLY
1928f67437f3Spatrick 	uint8_t *da = mtod(m, uint8_t *);
1929e6abcda3Smlarkin #endif
193002ee7d07Spatrick 	struct bwfm_pci_msgring *ring;
1931f67437f3Spatrick 	int flowid, prio, fifo;
1932f67437f3Spatrick 	int i, found;
1933f67437f3Spatrick 
1934f67437f3Spatrick 	prio = ieee80211_classify(ic, m);
1935f67437f3Spatrick 	fifo = bwfm_pci_prio2fifo[prio];
1936f67437f3Spatrick 
1937f67437f3Spatrick 	switch (ic->ic_opmode)
1938f67437f3Spatrick 	{
1939f67437f3Spatrick 	case IEEE80211_M_STA:
1940f67437f3Spatrick 		flowid = fifo;
1941f67437f3Spatrick 		break;
1942f67437f3Spatrick #ifndef IEEE80211_STA_ONLY
1943f67437f3Spatrick 	case IEEE80211_M_HOSTAP:
19442b7bea7eSpatrick 		if (ETHER_IS_MULTICAST(da))
19452b7bea7eSpatrick 			da = etherbroadcastaddr;
1946f67437f3Spatrick 		flowid = da[5] * 2 + fifo;
1947f67437f3Spatrick 		break;
1948f67437f3Spatrick #endif
1949f67437f3Spatrick 	default:
1950f67437f3Spatrick 		printf("%s: state not supported\n", DEVNAME(sc));
1951f67437f3Spatrick 		return;
1952f67437f3Spatrick 	}
1953f67437f3Spatrick 
1954f67437f3Spatrick 	found = 0;
1955f67437f3Spatrick 	flowid = flowid % sc->sc_max_flowrings;
1956f67437f3Spatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
195702ee7d07Spatrick 		ring = &sc->sc_flowrings[flowid];
195802ee7d07Spatrick 		if (ring->status == RING_CLOSED) {
195902ee7d07Spatrick 			ring->status = RING_OPENING;
1960f67437f3Spatrick 			found = 1;
1961f67437f3Spatrick 			break;
1962f67437f3Spatrick 		}
1963f67437f3Spatrick 		flowid = (flowid + 1) % sc->sc_max_flowrings;
1964f67437f3Spatrick 	}
1965f67437f3Spatrick 
196602ee7d07Spatrick 	/*
196702ee7d07Spatrick 	 * We cannot recover from that so far.  Only a stop/init
196802ee7d07Spatrick 	 * cycle can revive this if it ever happens at all.
196902ee7d07Spatrick 	 */
1970f67437f3Spatrick 	if (!found) {
1971f67437f3Spatrick 		printf("%s: no flowring available\n", DEVNAME(sc));
1972f67437f3Spatrick 		return;
1973f67437f3Spatrick 	}
1974f67437f3Spatrick 
197502ee7d07Spatrick 	cmd.m = m;
1976f67437f3Spatrick 	cmd.prio = prio;
1977518be5f3Spatrick 	cmd.flowid = flowid;
1978518be5f3Spatrick 	bwfm_do_async(&sc->sc_sc, bwfm_pci_flowring_create_cb, &cmd, sizeof(cmd));
1979518be5f3Spatrick }
1980518be5f3Spatrick 
1981518be5f3Spatrick void
1982518be5f3Spatrick bwfm_pci_flowring_create_cb(struct bwfm_softc *bwfm, void *arg)
1983518be5f3Spatrick {
1984518be5f3Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1985e6abcda3Smlarkin #ifndef IEEE80211_STA_ONLY
19862b7bea7eSpatrick 	struct ieee80211com *ic = &sc->sc_sc.sc_ic;
1987e6abcda3Smlarkin #endif
1988518be5f3Spatrick 	struct bwfm_cmd_flowring_create *cmd = arg;
1989518be5f3Spatrick 	struct msgbuf_tx_flowring_create_req *req;
1990518be5f3Spatrick 	struct bwfm_pci_msgring *ring;
199102ee7d07Spatrick 	uint8_t *da, *sa;
1992e272db29Spatrick 	int s;
1993518be5f3Spatrick 
199402ee7d07Spatrick 	da = mtod(cmd->m, char *) + 0 * ETHER_ADDR_LEN;
199502ee7d07Spatrick 	sa = mtod(cmd->m, char *) + 1 * ETHER_ADDR_LEN;
1996518be5f3Spatrick 
199702ee7d07Spatrick 	ring = &sc->sc_flowrings[cmd->flowid];
199802ee7d07Spatrick 	if (ring->status != RING_OPENING) {
199902ee7d07Spatrick 		printf("%s: flowring not opening\n", DEVNAME(sc));
2000518be5f3Spatrick 		return;
2001f67437f3Spatrick 	}
2002f67437f3Spatrick 
2003f67437f3Spatrick 	if (bwfm_pci_setup_flowring(sc, ring, 512, 48)) {
2004f67437f3Spatrick 		printf("%s: cannot setup flowring\n", DEVNAME(sc));
2005f67437f3Spatrick 		return;
2006f67437f3Spatrick 	}
2007518be5f3Spatrick 
2008e272db29Spatrick 	s = splnet();
2009518be5f3Spatrick 	req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit);
2010f67437f3Spatrick 	if (req == NULL) {
2011f67437f3Spatrick 		printf("%s: cannot reserve for flowring\n", DEVNAME(sc));
2012e272db29Spatrick 		splx(s);
2013518be5f3Spatrick 		return;
2014f67437f3Spatrick 	}
2015518be5f3Spatrick 
2016518be5f3Spatrick 	ring->status = RING_OPENING;
201702ee7d07Spatrick 	ring->fifo = bwfm_pci_prio2fifo[cmd->prio];
201802ee7d07Spatrick 	ring->m = cmd->m;
201902ee7d07Spatrick 	memcpy(ring->mac, da, ETHER_ADDR_LEN);
20202b7bea7eSpatrick #ifndef IEEE80211_STA_ONLY
202102ee7d07Spatrick 	if (ic->ic_opmode == IEEE80211_M_HOSTAP && ETHER_IS_MULTICAST(da))
20222b7bea7eSpatrick 		memcpy(ring->mac, etherbroadcastaddr, ETHER_ADDR_LEN);
20232b7bea7eSpatrick #endif
2024f67437f3Spatrick 
2025518be5f3Spatrick 	req->msg.msgtype = MSGBUF_TYPE_FLOW_RING_CREATE;
2026518be5f3Spatrick 	req->msg.ifidx = 0;
2027518be5f3Spatrick 	req->msg.request_id = 0;
202802ee7d07Spatrick 	req->tid = bwfm_pci_prio2fifo[cmd->prio];
202902ee7d07Spatrick 	req->flow_ring_id = letoh16(cmd->flowid + 2);
203002ee7d07Spatrick 	memcpy(req->da, da, ETHER_ADDR_LEN);
203102ee7d07Spatrick 	memcpy(req->sa, sa, ETHER_ADDR_LEN);
2032518be5f3Spatrick 	req->flow_ring_addr.high_addr =
2033518be5f3Spatrick 	    letoh32(BWFM_PCI_DMA_DVA(ring->ring) >> 32);
2034518be5f3Spatrick 	req->flow_ring_addr.low_addr =
2035518be5f3Spatrick 	    letoh32(BWFM_PCI_DMA_DVA(ring->ring) & 0xffffffff);
2036518be5f3Spatrick 	req->max_items = letoh16(512);
2037518be5f3Spatrick 	req->len_item = letoh16(48);
2038518be5f3Spatrick 
2039518be5f3Spatrick 	bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit);
2040e272db29Spatrick 	splx(s);
2041518be5f3Spatrick }
2042518be5f3Spatrick 
2043a2c6ff8bSpatrick void
2044a2c6ff8bSpatrick bwfm_pci_flowring_delete(struct bwfm_pci_softc *sc, int flowid)
2045a2c6ff8bSpatrick {
2046a2c6ff8bSpatrick 	struct msgbuf_tx_flowring_delete_req *req;
2047a2c6ff8bSpatrick 	struct bwfm_pci_msgring *ring;
2048e272db29Spatrick 	int s;
2049a2c6ff8bSpatrick 
2050a2c6ff8bSpatrick 	ring = &sc->sc_flowrings[flowid];
2051a2c6ff8bSpatrick 	if (ring->status != RING_OPEN) {
2052a2c6ff8bSpatrick 		printf("%s: flowring not open\n", DEVNAME(sc));
2053a2c6ff8bSpatrick 		return;
2054a2c6ff8bSpatrick 	}
2055a2c6ff8bSpatrick 
2056e272db29Spatrick 	s = splnet();
2057a2c6ff8bSpatrick 	req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit);
2058a2c6ff8bSpatrick 	if (req == NULL) {
2059a2c6ff8bSpatrick 		printf("%s: cannot reserve for flowring\n", DEVNAME(sc));
2060e272db29Spatrick 		splx(s);
2061a2c6ff8bSpatrick 		return;
2062a2c6ff8bSpatrick 	}
2063a2c6ff8bSpatrick 
2064a2c6ff8bSpatrick 	ring->status = RING_CLOSING;
2065a2c6ff8bSpatrick 
2066a2c6ff8bSpatrick 	req->msg.msgtype = MSGBUF_TYPE_FLOW_RING_DELETE;
2067a2c6ff8bSpatrick 	req->msg.ifidx = 0;
2068a2c6ff8bSpatrick 	req->msg.request_id = 0;
2069a2c6ff8bSpatrick 	req->flow_ring_id = letoh16(flowid + 2);
2070a2c6ff8bSpatrick 	req->reason = 0;
2071a2c6ff8bSpatrick 
2072a2c6ff8bSpatrick 	bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit);
2073e272db29Spatrick 	splx(s);
2074a2c6ff8bSpatrick }
2075a2c6ff8bSpatrick 
2076a2c6ff8bSpatrick void
2077b5553ee6Spatrick bwfm_pci_flowring_delete_cb(struct bwfm_softc *bwfm, void *arg)
2078b5553ee6Spatrick {
2079b5553ee6Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
2080b5553ee6Spatrick 	struct bwfm_cmd_flowring_create *cmd = arg;
2081b5553ee6Spatrick 	struct bwfm_pci_msgring *ring;
2082b5553ee6Spatrick 
2083b5553ee6Spatrick 	ring = &sc->sc_flowrings[cmd->flowid];
2084b5553ee6Spatrick 	bwfm_pci_dmamem_free(sc, ring->ring);
2085b5553ee6Spatrick 	ring->status = RING_CLOSED;
2086b5553ee6Spatrick }
2087b5553ee6Spatrick 
2088b5553ee6Spatrick void
2089a2c6ff8bSpatrick bwfm_pci_stop(struct bwfm_softc *bwfm)
2090a2c6ff8bSpatrick {
2091a2c6ff8bSpatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
2092a2c6ff8bSpatrick 	struct bwfm_pci_msgring *ring;
2093a2c6ff8bSpatrick 	int i;
2094a2c6ff8bSpatrick 
2095a2c6ff8bSpatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
2096a2c6ff8bSpatrick 		ring = &sc->sc_flowrings[i];
2097a2c6ff8bSpatrick 		if (ring->status == RING_OPEN)
2098a2c6ff8bSpatrick 			bwfm_pci_flowring_delete(sc, i);
2099a2c6ff8bSpatrick 	}
2100a2c6ff8bSpatrick }
2101a2c6ff8bSpatrick 
2102e5ec1e72Spatrick int
210302ee7d07Spatrick bwfm_pci_txcheck(struct bwfm_softc *bwfm)
210402ee7d07Spatrick {
210502ee7d07Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
210602ee7d07Spatrick 	struct bwfm_pci_msgring *ring;
210702ee7d07Spatrick 	int i;
210802ee7d07Spatrick 
210902ee7d07Spatrick 	/* If we are transitioning, we cannot send. */
211002ee7d07Spatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
211102ee7d07Spatrick 		ring = &sc->sc_flowrings[i];
211202ee7d07Spatrick 		if (ring->status == RING_OPENING)
211302ee7d07Spatrick 			return ENOBUFS;
211402ee7d07Spatrick 	}
211502ee7d07Spatrick 
211602ee7d07Spatrick 	if (bwfm_pci_pktid_avail(sc, &sc->sc_tx_pkts)) {
211702ee7d07Spatrick 		sc->sc_tx_pkts_full = 1;
211802ee7d07Spatrick 		return ENOBUFS;
211902ee7d07Spatrick 	}
212002ee7d07Spatrick 
212102ee7d07Spatrick 	return 0;
212202ee7d07Spatrick }
212302ee7d07Spatrick 
212402ee7d07Spatrick int
2125e5ec1e72Spatrick bwfm_pci_txdata(struct bwfm_softc *bwfm, struct mbuf *m)
2126e5ec1e72Spatrick {
2127e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
2128518be5f3Spatrick 	struct bwfm_pci_msgring *ring;
2129518be5f3Spatrick 	struct msgbuf_tx_msghdr *tx;
2130518be5f3Spatrick 	uint32_t pktid;
2131518be5f3Spatrick 	paddr_t paddr;
2132518be5f3Spatrick 	int flowid, ret;
2133518be5f3Spatrick 
2134f67437f3Spatrick 	flowid = bwfm_pci_flowring_lookup(sc, m);
2135f67437f3Spatrick 	if (flowid < 0) {
213602ee7d07Spatrick 		/*
213702ee7d07Spatrick 		 * We cannot send the packet right now as there is
213802ee7d07Spatrick 		 * no flowring yet.  The flowring will be created
213902ee7d07Spatrick 		 * asynchronously.  While the ring is transitioning
214002ee7d07Spatrick 		 * the TX check will tell the upper layers that we
214102ee7d07Spatrick 		 * cannot send packets right now.  When the flowring
214202ee7d07Spatrick 		 * is created the queue will be restarted and this
214302ee7d07Spatrick 		 * mbuf will be transmitted.
214402ee7d07Spatrick 		 */
2145f67437f3Spatrick 		bwfm_pci_flowring_create(sc, m);
214602ee7d07Spatrick 		return 0;
2147f67437f3Spatrick 	}
2148518be5f3Spatrick 
2149518be5f3Spatrick 	ring = &sc->sc_flowrings[flowid];
2150518be5f3Spatrick 	if (ring->status == RING_OPENING ||
2151f67437f3Spatrick 	    ring->status == RING_CLOSING) {
2152f67437f3Spatrick 		printf("%s: tried to use a flow that was "
2153f67437f3Spatrick 		    "transitioning in status %d\n",
2154f67437f3Spatrick 		    DEVNAME(sc), ring->status);
2155518be5f3Spatrick 		return ENOBUFS;
2156518be5f3Spatrick 	}
2157518be5f3Spatrick 
2158518be5f3Spatrick 	tx = bwfm_pci_ring_write_reserve(sc, ring);
2159518be5f3Spatrick 	if (tx == NULL)
2160518be5f3Spatrick 		return ENOBUFS;
2161518be5f3Spatrick 
2162518be5f3Spatrick 	memset(tx, 0, sizeof(*tx));
2163518be5f3Spatrick 	tx->msg.msgtype = MSGBUF_TYPE_TX_POST;
2164518be5f3Spatrick 	tx->msg.ifidx = 0;
2165518be5f3Spatrick 	tx->flags = BWFM_MSGBUF_PKT_FLAGS_FRAME_802_3;
2166518be5f3Spatrick 	tx->flags |= ieee80211_classify(&sc->sc_sc.sc_ic, m) <<
2167518be5f3Spatrick 	    BWFM_MSGBUF_PKT_FLAGS_PRIO_SHIFT;
2168518be5f3Spatrick 	tx->seg_cnt = 1;
2169518be5f3Spatrick 	memcpy(tx->txhdr, mtod(m, char *), ETHER_HDR_LEN);
2170518be5f3Spatrick 
2171518be5f3Spatrick 	ret = bwfm_pci_pktid_new(sc, &sc->sc_tx_pkts, m, &pktid, &paddr);
2172518be5f3Spatrick 	if (ret) {
217302ee7d07Spatrick 		if (ret == ENOBUFS) {
217402ee7d07Spatrick 			printf("%s: no pktid available for TX\n",
217502ee7d07Spatrick 			    DEVNAME(sc));
2176c6f1636dSpatrick 			sc->sc_tx_pkts_full = 1;
217702ee7d07Spatrick 		}
2178518be5f3Spatrick 		bwfm_pci_ring_write_cancel(sc, ring, 1);
2179518be5f3Spatrick 		return ret;
2180518be5f3Spatrick 	}
2181518be5f3Spatrick 	paddr += ETHER_HDR_LEN;
2182518be5f3Spatrick 
2183f9ee104fSpatrick 	tx->msg.request_id = htole32(pktid + 1);
21844ff787bcSpatrick 	tx->data_len = htole16(m->m_len - ETHER_HDR_LEN);
2185e4dae658Spatrick 	tx->data_buf_addr.high_addr = htole32((uint64_t)paddr >> 32);
2186518be5f3Spatrick 	tx->data_buf_addr.low_addr = htole32(paddr & 0xffffffff);
2187518be5f3Spatrick 
2188518be5f3Spatrick 	bwfm_pci_ring_write_commit(sc, ring);
2189518be5f3Spatrick 	return 0;
2190e5ec1e72Spatrick }
2191e5ec1e72Spatrick 
21921a93a9bdSpatrick int
21931a93a9bdSpatrick bwfm_pci_send_mb_data(struct bwfm_pci_softc *sc, uint32_t htod_mb_data)
21941a93a9bdSpatrick {
21951a93a9bdSpatrick 	struct bwfm_softc *bwfm = (void *)sc;
21961a93a9bdSpatrick 	struct bwfm_core *core;
21971a93a9bdSpatrick 	uint32_t reg;
21981a93a9bdSpatrick 	int i;
21991a93a9bdSpatrick 
22001a93a9bdSpatrick 	for (i = 0; i < 100; i++) {
22011a93a9bdSpatrick 		reg = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
22021a93a9bdSpatrick 		    sc->sc_htod_mb_data_addr);
22031a93a9bdSpatrick 		if (reg == 0)
22041a93a9bdSpatrick 			break;
22051a93a9bdSpatrick 		delay(10 * 1000);
22061a93a9bdSpatrick 	}
22071a93a9bdSpatrick 	if (i == 100) {
22081a93a9bdSpatrick 		DPRINTF(("%s: MB transaction already pending\n", DEVNAME(sc)));
22091a93a9bdSpatrick 		return EIO;
22101a93a9bdSpatrick 	}
22111a93a9bdSpatrick 
22121a93a9bdSpatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
22131a93a9bdSpatrick 	    sc->sc_htod_mb_data_addr, htod_mb_data);
22141a93a9bdSpatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_REG_SBMBX, 1);
22151a93a9bdSpatrick 
22161a93a9bdSpatrick 	core = bwfm_chip_get_core(bwfm, BWFM_AGENT_CORE_PCIE2);
22171a93a9bdSpatrick 	if (core->co_rev <= 13)
22181a93a9bdSpatrick 		pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_REG_SBMBX, 1);
22191a93a9bdSpatrick 
22201a93a9bdSpatrick 	return 0;
22211a93a9bdSpatrick }
22221a93a9bdSpatrick 
22231a93a9bdSpatrick void
22241a93a9bdSpatrick bwfm_pci_handle_mb_data(struct bwfm_pci_softc *sc)
22251a93a9bdSpatrick {
22261a93a9bdSpatrick 	uint32_t reg;
22271a93a9bdSpatrick 
22281a93a9bdSpatrick 	reg = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
22291a93a9bdSpatrick 	    sc->sc_dtoh_mb_data_addr);
22301a93a9bdSpatrick 	if (reg == 0)
22311a93a9bdSpatrick 		return;
22321a93a9bdSpatrick 
22331a93a9bdSpatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
22341a93a9bdSpatrick 	    sc->sc_dtoh_mb_data_addr, 0);
22351a93a9bdSpatrick 
22361a93a9bdSpatrick 	if (reg & BWFM_PCI_D2H_DEV_D3_ACK) {
22371a93a9bdSpatrick 		sc->sc_mbdata_done = 1;
22381a93a9bdSpatrick 		wakeup(&sc->sc_mbdata_done);
22391a93a9bdSpatrick 	}
22401a93a9bdSpatrick 
22411a93a9bdSpatrick 	/* TODO: support more events */
22421a93a9bdSpatrick 	if (reg & ~BWFM_PCI_D2H_DEV_D3_ACK)
22431a93a9bdSpatrick 		printf("%s: handle MB data 0x%08x\n", DEVNAME(sc), reg);
22441a93a9bdSpatrick }
22451a93a9bdSpatrick 
2246bbd71b0bSpatrick #ifdef BWFM_DEBUG
2247cadf5fcfSpatrick void
2248cadf5fcfSpatrick bwfm_pci_debug_console(struct bwfm_pci_softc *sc)
2249cadf5fcfSpatrick {
2250cadf5fcfSpatrick 	uint32_t newidx = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
2251cadf5fcfSpatrick 	    sc->sc_console_base_addr + BWFM_CONSOLE_WRITEIDX);
2252cadf5fcfSpatrick 
2253cadf5fcfSpatrick 	if (newidx != sc->sc_console_readidx)
2254bbd71b0bSpatrick 		DPRINTFN(3, ("BWFM CONSOLE: "));
2255cadf5fcfSpatrick 	while (newidx != sc->sc_console_readidx) {
2256cadf5fcfSpatrick 		uint8_t ch = bus_space_read_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
2257cadf5fcfSpatrick 		    sc->sc_console_buf_addr + sc->sc_console_readidx);
2258cadf5fcfSpatrick 		sc->sc_console_readidx++;
2259cadf5fcfSpatrick 		if (sc->sc_console_readidx == sc->sc_console_buf_size)
2260cadf5fcfSpatrick 			sc->sc_console_readidx = 0;
2261cadf5fcfSpatrick 		if (ch == '\r')
2262cadf5fcfSpatrick 			continue;
2263bbd71b0bSpatrick 		DPRINTFN(3, ("%c", ch));
2264cadf5fcfSpatrick 	}
2265cadf5fcfSpatrick }
2266bbd71b0bSpatrick #endif
2267cadf5fcfSpatrick 
2268e5ec1e72Spatrick int
2269e5ec1e72Spatrick bwfm_pci_intr(void *v)
2270e5ec1e72Spatrick {
2271e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)v;
22726f241297Spatrick 	struct ifnet *ifp = &sc->sc_sc.sc_ic.ic_if;
22736f241297Spatrick 	struct mbuf_list ml = MBUF_LIST_INITIALIZER();
2274bb813cf8Spatrick 	uint32_t status, mask;
2275e5ec1e72Spatrick 
2276bb813cf8Spatrick 	if (!sc->sc_initialized)
2277bb813cf8Spatrick 		return 0;
2278bb813cf8Spatrick 
2279bb813cf8Spatrick 	status = bwfm_pci_intr_status(sc);
2280bb813cf8Spatrick 	/* FIXME: interrupt status seems to be zero? */
2281*8bad4727Spatrick 	if (status == 0 && sc->sc_pcireg64)
2282bb813cf8Spatrick 		status |= BWFM_PCI_64_PCIE2REG_MAILBOXMASK_INT_D2H_DB;
2283bb813cf8Spatrick 	if (status == 0)
2284e5ec1e72Spatrick 		return 0;
2285e5ec1e72Spatrick 
2286e5ec1e72Spatrick 	bwfm_pci_intr_disable(sc);
2287bb813cf8Spatrick 	bwfm_pci_intr_ack(sc, status);
2288e5ec1e72Spatrick 
2289*8bad4727Spatrick 	if (!sc->sc_pcireg64 &&
2290bb813cf8Spatrick 	    (status & (BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_0 |
2291bb813cf8Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_1)))
22921a93a9bdSpatrick 		bwfm_pci_handle_mb_data(sc);
2293e5ec1e72Spatrick 
2294bb813cf8Spatrick 	mask = BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_D2H_DB;
2295*8bad4727Spatrick 	if (sc->sc_pcireg64)
2296bb813cf8Spatrick 		mask = BWFM_PCI_64_PCIE2REG_MAILBOXMASK_INT_D2H_DB;
2297bb813cf8Spatrick 
2298bb813cf8Spatrick 	if (status & mask) {
22996f241297Spatrick 		bwfm_pci_ring_rx(sc, &sc->sc_rx_complete, &ml);
23006f241297Spatrick 		bwfm_pci_ring_rx(sc, &sc->sc_tx_complete, &ml);
23016f241297Spatrick 		bwfm_pci_ring_rx(sc, &sc->sc_ctrl_complete, &ml);
2302447a2df6Sdlg 
2303447a2df6Sdlg 		if (ifiq_input(&ifp->if_rcv, &ml))
2304447a2df6Sdlg 			if_rxr_livelocked(&sc->sc_rxbuf_ring);
2305e5ec1e72Spatrick 	}
2306e5ec1e72Spatrick 
2307cadf5fcfSpatrick #ifdef BWFM_DEBUG
2308cadf5fcfSpatrick 	bwfm_pci_debug_console(sc);
2309e5ec1e72Spatrick #endif
2310e5ec1e72Spatrick 
2311e5ec1e72Spatrick 	bwfm_pci_intr_enable(sc);
2312e5ec1e72Spatrick 	return 1;
2313e5ec1e72Spatrick }
2314e5ec1e72Spatrick 
2315e5ec1e72Spatrick void
2316e5ec1e72Spatrick bwfm_pci_intr_enable(struct bwfm_pci_softc *sc)
2317e5ec1e72Spatrick {
2318*8bad4727Spatrick 	if (sc->sc_pcireg64)
2319bb813cf8Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
2320bb813cf8Spatrick 		    BWFM_PCI_64_PCIE2REG_MAILBOXMASK,
2321bb813cf8Spatrick 		    BWFM_PCI_64_PCIE2REG_MAILBOXMASK_INT_D2H_DB);
2322bb813cf8Spatrick 	else
2323e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
2324e5ec1e72Spatrick 		    BWFM_PCI_PCIE2REG_MAILBOXMASK,
2325e5ec1e72Spatrick 		    BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_0 |
2326e5ec1e72Spatrick 		    BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_1 |
2327e5ec1e72Spatrick 		    BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_D2H_DB);
2328e5ec1e72Spatrick }
2329e5ec1e72Spatrick 
2330e5ec1e72Spatrick void
2331e5ec1e72Spatrick bwfm_pci_intr_disable(struct bwfm_pci_softc *sc)
2332e5ec1e72Spatrick {
2333*8bad4727Spatrick 	if (sc->sc_pcireg64)
2334bb813cf8Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
2335bb813cf8Spatrick 		    BWFM_PCI_64_PCIE2REG_MAILBOXMASK, 0);
2336bb813cf8Spatrick 	else
2337e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
2338e5ec1e72Spatrick 		    BWFM_PCI_PCIE2REG_MAILBOXMASK, 0);
2339e5ec1e72Spatrick }
2340e5ec1e72Spatrick 
2341bb813cf8Spatrick uint32_t
2342bb813cf8Spatrick bwfm_pci_intr_status(struct bwfm_pci_softc *sc)
2343bb813cf8Spatrick {
2344*8bad4727Spatrick 	if (sc->sc_pcireg64)
2345bb813cf8Spatrick 		return bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
2346bb813cf8Spatrick 		    BWFM_PCI_64_PCIE2REG_MAILBOXINT);
2347bb813cf8Spatrick 	else
2348bb813cf8Spatrick 		return bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
2349bb813cf8Spatrick 		    BWFM_PCI_PCIE2REG_MAILBOXINT);
2350bb813cf8Spatrick }
2351bb813cf8Spatrick 
2352bb813cf8Spatrick void
2353bb813cf8Spatrick bwfm_pci_intr_ack(struct bwfm_pci_softc *sc, uint32_t status)
2354bb813cf8Spatrick {
2355*8bad4727Spatrick 	if (sc->sc_pcireg64)
2356bb813cf8Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
2357bb813cf8Spatrick 		    BWFM_PCI_64_PCIE2REG_MAILBOXINT, status);
2358bb813cf8Spatrick 	else
2359bb813cf8Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
2360bb813cf8Spatrick 		    BWFM_PCI_PCIE2REG_MAILBOXINT, status);
2361bb813cf8Spatrick }
2362bb813cf8Spatrick 
23631a93a9bdSpatrick uint32_t
23641a93a9bdSpatrick bwfm_pci_intmask(struct bwfm_pci_softc *sc)
23651a93a9bdSpatrick {
2366*8bad4727Spatrick 	if (sc->sc_pcireg64)
23671a93a9bdSpatrick 		return bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
23681a93a9bdSpatrick 		    BWFM_PCI_64_PCIE2REG_INTMASK);
23691a93a9bdSpatrick 	else
23701a93a9bdSpatrick 		return bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
23711a93a9bdSpatrick 		    BWFM_PCI_PCIE2REG_INTMASK);
23721a93a9bdSpatrick }
23731a93a9bdSpatrick 
2374156d2677Spatrick void
2375156d2677Spatrick bwfm_pci_hostready(struct bwfm_pci_softc *sc)
2376156d2677Spatrick {
2377156d2677Spatrick 	if ((sc->sc_shared_flags & BWFM_SHARED_INFO_HOSTRDY_DB1) == 0)
2378156d2677Spatrick 		return;
2379156d2677Spatrick 
2380*8bad4727Spatrick 	if (sc->sc_pcireg64)
2381bb813cf8Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
2382bb813cf8Spatrick 		    BWFM_PCI_64_PCIE2REG_H2D_MAILBOX_1, 1);
2383bb813cf8Spatrick 	else
2384156d2677Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
2385156d2677Spatrick 		    BWFM_PCI_PCIE2REG_H2D_MAILBOX_1, 1);
2386156d2677Spatrick }
2387156d2677Spatrick 
2388e5ec1e72Spatrick /* Msgbuf protocol implementation */
2389e5ec1e72Spatrick int
2390e5ec1e72Spatrick bwfm_pci_msgbuf_query_dcmd(struct bwfm_softc *bwfm, int ifidx,
2391e5ec1e72Spatrick     int cmd, char *buf, size_t *len)
2392e5ec1e72Spatrick {
2393e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
2394e5ec1e72Spatrick 	struct msgbuf_ioctl_req_hdr *req;
23952eeba925Spatrick 	struct bwfm_pci_ioctl *ctl;
2396e5ec1e72Spatrick 	struct mbuf *m;
23972eeba925Spatrick 	uint32_t pktid;
23982eeba925Spatrick 	paddr_t paddr;
2399e5ec1e72Spatrick 	size_t buflen;
2400e272db29Spatrick 	int s;
2401e5ec1e72Spatrick 
24022eeba925Spatrick 	buflen = min(*len, BWFM_DMA_H2D_IOCTL_BUF_LEN);
2403471f2571Sjan 	m = MCLGETL(NULL, M_DONTWAIT, buflen);
24042eeba925Spatrick 	if (m == NULL)
24052eeba925Spatrick 		return 1;
24062eeba925Spatrick 	m->m_len = m->m_pkthdr.len = buflen;
24072eeba925Spatrick 
24082eeba925Spatrick 	if (buf)
24092eeba925Spatrick 		memcpy(mtod(m, char *), buf, buflen);
24102eeba925Spatrick 	else
24112eeba925Spatrick 		memset(mtod(m, char *), 0, buflen);
24122eeba925Spatrick 
2413e272db29Spatrick 	s = splnet();
2414e5ec1e72Spatrick 	req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit);
2415e5ec1e72Spatrick 	if (req == NULL) {
2416e272db29Spatrick 		splx(s);
24172eeba925Spatrick 		m_freem(m);
2418e5ec1e72Spatrick 		return 1;
2419e5ec1e72Spatrick 	}
24202eeba925Spatrick 
24212eeba925Spatrick 	if (bwfm_pci_pktid_new(sc, &sc->sc_ioctl_pkts, m, &pktid, &paddr)) {
24222eeba925Spatrick 		bwfm_pci_ring_write_cancel(sc, &sc->sc_ctrl_submit, 1);
2423e272db29Spatrick 		splx(s);
24242eeba925Spatrick 		m_freem(m);
24252eeba925Spatrick 		return 1;
24262eeba925Spatrick 	}
24272eeba925Spatrick 
24282eeba925Spatrick 	ctl = malloc(sizeof(*ctl), M_TEMP, M_WAITOK|M_ZERO);
24292eeba925Spatrick 	ctl->transid = sc->sc_ioctl_transid++;
24302eeba925Spatrick 	TAILQ_INSERT_TAIL(&sc->sc_ioctlq, ctl, next);
24312eeba925Spatrick 
2432e5ec1e72Spatrick 	req->msg.msgtype = MSGBUF_TYPE_IOCTLPTR_REQ;
2433e5ec1e72Spatrick 	req->msg.ifidx = 0;
2434e5ec1e72Spatrick 	req->msg.flags = 0;
24352eeba925Spatrick 	req->msg.request_id = htole32(pktid);
2436e5ec1e72Spatrick 	req->cmd = htole32(cmd);
2437e5ec1e72Spatrick 	req->output_buf_len = htole16(*len);
24382eeba925Spatrick 	req->trans_id = htole16(ctl->transid);
2439e5ec1e72Spatrick 
24402eeba925Spatrick 	req->input_buf_len = htole16(m->m_len);
24412eeba925Spatrick 	req->req_buf_addr.high_addr = htole32((uint64_t)paddr >> 32);
24422eeba925Spatrick 	req->req_buf_addr.low_addr = htole32(paddr & 0xffffffff);
2443dcb67343Spatrick 
2444e5ec1e72Spatrick 	bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit);
2445e272db29Spatrick 	splx(s);
2446e5ec1e72Spatrick 
24478544fed6Smpi 	tsleep_nsec(ctl, PWAIT, "bwfm", SEC_TO_NSEC(1));
24482eeba925Spatrick 	TAILQ_REMOVE(&sc->sc_ioctlq, ctl, next);
24492eeba925Spatrick 
24502eeba925Spatrick 	if (ctl->m == NULL) {
24512eeba925Spatrick 		free(ctl, M_TEMP, sizeof(*ctl));
2452e5ec1e72Spatrick 		return 1;
2453e5ec1e72Spatrick 	}
2454e5ec1e72Spatrick 
24552eeba925Spatrick 	*len = min(ctl->retlen, m->m_len);
24562eeba925Spatrick 	*len = min(*len, buflen);
2457e5ec1e72Spatrick 	if (buf)
24585c7fed39Sdlg 		m_copydata(ctl->m, 0, *len, buf);
24592eeba925Spatrick 	m_freem(ctl->m);
2460e5ec1e72Spatrick 
24612eeba925Spatrick 	if (ctl->status < 0) {
24622eeba925Spatrick 		free(ctl, M_TEMP, sizeof(*ctl));
24632eeba925Spatrick 		return 1;
24642eeba925Spatrick 	}
24652eeba925Spatrick 
24662eeba925Spatrick 	free(ctl, M_TEMP, sizeof(*ctl));
2467e5ec1e72Spatrick 	return 0;
2468e5ec1e72Spatrick }
2469e5ec1e72Spatrick 
2470e5ec1e72Spatrick int
2471e5ec1e72Spatrick bwfm_pci_msgbuf_set_dcmd(struct bwfm_softc *bwfm, int ifidx,
2472e5ec1e72Spatrick     int cmd, char *buf, size_t len)
2473e5ec1e72Spatrick {
2474e5ec1e72Spatrick 	return bwfm_pci_msgbuf_query_dcmd(bwfm, ifidx, cmd, buf, &len);
2475e5ec1e72Spatrick }
24762eeba925Spatrick 
24772eeba925Spatrick void
24782eeba925Spatrick bwfm_pci_msgbuf_rxioctl(struct bwfm_pci_softc *sc,
24792eeba925Spatrick     struct msgbuf_ioctl_resp_hdr *resp)
24802eeba925Spatrick {
24812eeba925Spatrick 	struct bwfm_pci_ioctl *ctl, *tmp;
24822eeba925Spatrick 	struct mbuf *m;
24832eeba925Spatrick 
24842eeba925Spatrick 	m = bwfm_pci_pktid_free(sc, &sc->sc_rx_pkts,
24852eeba925Spatrick 	    letoh32(resp->msg.request_id));
24862eeba925Spatrick 
24872eeba925Spatrick 	TAILQ_FOREACH_SAFE(ctl, &sc->sc_ioctlq, next, tmp) {
24882eeba925Spatrick 		if (ctl->transid != letoh16(resp->trans_id))
24892eeba925Spatrick 			continue;
24902eeba925Spatrick 		ctl->m = m;
24912eeba925Spatrick 		ctl->retlen = letoh16(resp->resp_len);
24922eeba925Spatrick 		ctl->status = letoh16(resp->compl_hdr.status);
24932eeba925Spatrick 		wakeup(ctl);
24942eeba925Spatrick 		return;
24952eeba925Spatrick 	}
24962eeba925Spatrick 
2497cb2afc74Spatrick 	m_freem(m);
24982eeba925Spatrick }
2499