xref: /openbsd/sys/dev/pci/if_bwfm_pci.c (revision 13f544a8)
1*13f544a8Spatrick /*	$OpenBSD: if_bwfm_pci.c,v 1.53 2021/08/31 20:58:51 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;
187e5ec1e72Spatrick };
188e5ec1e72Spatrick 
189e5ec1e72Spatrick struct bwfm_pci_dmamem {
190e5ec1e72Spatrick 	bus_dmamap_t		bdm_map;
191e5ec1e72Spatrick 	bus_dma_segment_t	bdm_seg;
192e5ec1e72Spatrick 	size_t			bdm_size;
193e5ec1e72Spatrick 	caddr_t			bdm_kva;
194e5ec1e72Spatrick };
195e5ec1e72Spatrick 
196e5ec1e72Spatrick #define BWFM_PCI_DMA_MAP(_bdm)	((_bdm)->bdm_map)
197e5ec1e72Spatrick #define BWFM_PCI_DMA_LEN(_bdm)	((_bdm)->bdm_size)
198e4dae658Spatrick #define BWFM_PCI_DMA_DVA(_bdm)	((uint64_t)(_bdm)->bdm_map->dm_segs[0].ds_addr)
199e5ec1e72Spatrick #define BWFM_PCI_DMA_KVA(_bdm)	((void *)(_bdm)->bdm_kva)
200e5ec1e72Spatrick 
201e5ec1e72Spatrick int		 bwfm_pci_match(struct device *, void *, void *);
202e5ec1e72Spatrick void		 bwfm_pci_attach(struct device *, struct device *, void *);
203e5ec1e72Spatrick int		 bwfm_pci_detach(struct device *, int);
204e5ec1e72Spatrick 
205ed6d4272Spatrick #if defined(__HAVE_FDT)
206ed6d4272Spatrick int		 bwfm_pci_read_otp(struct bwfm_pci_softc *);
207ed6d4272Spatrick void		 bwfm_pci_process_otp_tuple(struct bwfm_pci_softc *, uint8_t,
208ed6d4272Spatrick 		    uint8_t, uint8_t *);
209ed6d4272Spatrick #endif
210ed6d4272Spatrick 
211e5ec1e72Spatrick int		 bwfm_pci_intr(void *);
212e5ec1e72Spatrick void		 bwfm_pci_intr_enable(struct bwfm_pci_softc *);
213e5ec1e72Spatrick void		 bwfm_pci_intr_disable(struct bwfm_pci_softc *);
214bb813cf8Spatrick uint32_t	 bwfm_pci_intr_status(struct bwfm_pci_softc *);
215bb813cf8Spatrick void		 bwfm_pci_intr_ack(struct bwfm_pci_softc *, uint32_t);
216156d2677Spatrick void		 bwfm_pci_hostready(struct bwfm_pci_softc *);
217e5ec1e72Spatrick int		 bwfm_pci_load_microcode(struct bwfm_pci_softc *, const u_char *,
2186aad491fSpatrick 		    size_t, const u_char *, size_t);
219e5ec1e72Spatrick void		 bwfm_pci_select_core(struct bwfm_pci_softc *, int );
220e5ec1e72Spatrick 
221e5ec1e72Spatrick struct bwfm_pci_dmamem *
222e5ec1e72Spatrick 		 bwfm_pci_dmamem_alloc(struct bwfm_pci_softc *, bus_size_t,
223e5ec1e72Spatrick 		    bus_size_t);
224e5ec1e72Spatrick void		 bwfm_pci_dmamem_free(struct bwfm_pci_softc *, struct bwfm_pci_dmamem *);
22502ee7d07Spatrick int		 bwfm_pci_pktid_avail(struct bwfm_pci_softc *,
22602ee7d07Spatrick 		    struct bwfm_pci_pkts *);
227e5ec1e72Spatrick int		 bwfm_pci_pktid_new(struct bwfm_pci_softc *,
228e5ec1e72Spatrick 		    struct bwfm_pci_pkts *, struct mbuf *,
229e5ec1e72Spatrick 		    uint32_t *, paddr_t *);
230e5ec1e72Spatrick struct mbuf *	 bwfm_pci_pktid_free(struct bwfm_pci_softc *,
231e5ec1e72Spatrick 		    struct bwfm_pci_pkts *, uint32_t);
232e5ec1e72Spatrick void		 bwfm_pci_fill_rx_ioctl_ring(struct bwfm_pci_softc *,
233e5ec1e72Spatrick 		    struct if_rxring *, uint32_t);
234e5ec1e72Spatrick void		 bwfm_pci_fill_rx_buf_ring(struct bwfm_pci_softc *);
235e5ec1e72Spatrick void		 bwfm_pci_fill_rx_rings(struct bwfm_pci_softc *);
236e5ec1e72Spatrick int		 bwfm_pci_setup_ring(struct bwfm_pci_softc *, struct bwfm_pci_msgring *,
237e5ec1e72Spatrick 		    int, size_t, uint32_t, uint32_t, int, uint32_t, uint32_t *);
238518be5f3Spatrick int		 bwfm_pci_setup_flowring(struct bwfm_pci_softc *, struct bwfm_pci_msgring *,
239518be5f3Spatrick 		    int, size_t);
240e5ec1e72Spatrick 
241e5ec1e72Spatrick void		 bwfm_pci_ring_bell(struct bwfm_pci_softc *,
242e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
243e5ec1e72Spatrick void		 bwfm_pci_ring_update_rptr(struct bwfm_pci_softc *,
244e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
245e5ec1e72Spatrick void		 bwfm_pci_ring_update_wptr(struct bwfm_pci_softc *,
246e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
247e5ec1e72Spatrick void		 bwfm_pci_ring_write_rptr(struct bwfm_pci_softc *,
248e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
249e5ec1e72Spatrick void		 bwfm_pci_ring_write_wptr(struct bwfm_pci_softc *,
250e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
251e5ec1e72Spatrick void *		 bwfm_pci_ring_write_reserve(struct bwfm_pci_softc *,
252e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
253e5ec1e72Spatrick void *		 bwfm_pci_ring_write_reserve_multi(struct bwfm_pci_softc *,
254e5ec1e72Spatrick 		    struct bwfm_pci_msgring *, int, int *);
255e5ec1e72Spatrick void *		 bwfm_pci_ring_read_avail(struct bwfm_pci_softc *,
256e5ec1e72Spatrick 		    struct bwfm_pci_msgring *, int *);
257e5ec1e72Spatrick void		 bwfm_pci_ring_read_commit(struct bwfm_pci_softc *,
258e5ec1e72Spatrick 		    struct bwfm_pci_msgring *, int);
259e5ec1e72Spatrick void		 bwfm_pci_ring_write_commit(struct bwfm_pci_softc *,
260e5ec1e72Spatrick 		    struct bwfm_pci_msgring *);
261e5ec1e72Spatrick void		 bwfm_pci_ring_write_cancel(struct bwfm_pci_softc *,
262e5ec1e72Spatrick 		    struct bwfm_pci_msgring *, int);
263e5ec1e72Spatrick 
264e5ec1e72Spatrick void		 bwfm_pci_ring_rx(struct bwfm_pci_softc *,
2656f241297Spatrick 		    struct bwfm_pci_msgring *, struct mbuf_list *);
2666f241297Spatrick void		 bwfm_pci_msg_rx(struct bwfm_pci_softc *, void *,
2676f241297Spatrick 		    struct mbuf_list *);
268e5ec1e72Spatrick 
269e5ec1e72Spatrick uint32_t	 bwfm_pci_buscore_read(struct bwfm_softc *, uint32_t);
270e5ec1e72Spatrick void		 bwfm_pci_buscore_write(struct bwfm_softc *, uint32_t,
271e5ec1e72Spatrick 		    uint32_t);
272e5ec1e72Spatrick int		 bwfm_pci_buscore_prepare(struct bwfm_softc *);
273e5ec1e72Spatrick int		 bwfm_pci_buscore_reset(struct bwfm_softc *);
274e5ec1e72Spatrick void		 bwfm_pci_buscore_activate(struct bwfm_softc *, uint32_t);
275e5ec1e72Spatrick 
276f67437f3Spatrick int		 bwfm_pci_flowring_lookup(struct bwfm_pci_softc *,
277f67437f3Spatrick 		     struct mbuf *);
278f67437f3Spatrick void		 bwfm_pci_flowring_create(struct bwfm_pci_softc *,
279518be5f3Spatrick 		     struct mbuf *);
280518be5f3Spatrick void		 bwfm_pci_flowring_create_cb(struct bwfm_softc *, void *);
281a2c6ff8bSpatrick void		 bwfm_pci_flowring_delete(struct bwfm_pci_softc *, int);
282518be5f3Spatrick 
283972218f3Spatrick int		 bwfm_pci_preinit(struct bwfm_softc *);
284a2c6ff8bSpatrick void		 bwfm_pci_stop(struct bwfm_softc *);
28502ee7d07Spatrick int		 bwfm_pci_txcheck(struct bwfm_softc *);
286e5ec1e72Spatrick int		 bwfm_pci_txdata(struct bwfm_softc *, struct mbuf *);
287bbd71b0bSpatrick 
288bbd71b0bSpatrick #ifdef BWFM_DEBUG
289cadf5fcfSpatrick void		 bwfm_pci_debug_console(struct bwfm_pci_softc *);
290bbd71b0bSpatrick #endif
291e5ec1e72Spatrick 
292e5ec1e72Spatrick int		 bwfm_pci_msgbuf_query_dcmd(struct bwfm_softc *, int,
293e5ec1e72Spatrick 		    int, char *, size_t *);
294e5ec1e72Spatrick int		 bwfm_pci_msgbuf_set_dcmd(struct bwfm_softc *, int,
295e5ec1e72Spatrick 		    int, char *, size_t);
2962eeba925Spatrick void		 bwfm_pci_msgbuf_rxioctl(struct bwfm_pci_softc *,
2972eeba925Spatrick 		    struct msgbuf_ioctl_resp_hdr *);
298e5ec1e72Spatrick 
299e5ec1e72Spatrick struct bwfm_buscore_ops bwfm_pci_buscore_ops = {
300e5ec1e72Spatrick 	.bc_read = bwfm_pci_buscore_read,
301e5ec1e72Spatrick 	.bc_write = bwfm_pci_buscore_write,
302e5ec1e72Spatrick 	.bc_prepare = bwfm_pci_buscore_prepare,
303e5ec1e72Spatrick 	.bc_reset = bwfm_pci_buscore_reset,
304e5ec1e72Spatrick 	.bc_setup = NULL,
305e5ec1e72Spatrick 	.bc_activate = bwfm_pci_buscore_activate,
306e5ec1e72Spatrick };
307e5ec1e72Spatrick 
308e5ec1e72Spatrick struct bwfm_bus_ops bwfm_pci_bus_ops = {
309972218f3Spatrick 	.bs_preinit = bwfm_pci_preinit,
310a2c6ff8bSpatrick 	.bs_stop = bwfm_pci_stop,
31102ee7d07Spatrick 	.bs_txcheck = bwfm_pci_txcheck,
312e5ec1e72Spatrick 	.bs_txdata = bwfm_pci_txdata,
313e5ec1e72Spatrick 	.bs_txctl = NULL,
314e5ec1e72Spatrick };
315e5ec1e72Spatrick 
316e5ec1e72Spatrick struct bwfm_proto_ops bwfm_pci_msgbuf_ops = {
317e5ec1e72Spatrick 	.proto_query_dcmd = bwfm_pci_msgbuf_query_dcmd,
318e5ec1e72Spatrick 	.proto_set_dcmd = bwfm_pci_msgbuf_set_dcmd,
31914c74651Spatrick 	.proto_rx = NULL,
320029d6dd5Spatrick 	.proto_rxctl = NULL,
321e5ec1e72Spatrick };
322e5ec1e72Spatrick 
323e5ec1e72Spatrick struct cfattach bwfm_pci_ca = {
324e5ec1e72Spatrick 	sizeof(struct bwfm_pci_softc),
325e5ec1e72Spatrick 	bwfm_pci_match,
326e5ec1e72Spatrick 	bwfm_pci_attach,
327e5ec1e72Spatrick 	bwfm_pci_detach,
328e5ec1e72Spatrick };
329e5ec1e72Spatrick 
330e5ec1e72Spatrick static const struct pci_matchid bwfm_pci_devices[] = {
33182f0e660Sjcs 	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4350 },
33241d93ac2Spatrick 	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4356 },
33341d93ac2Spatrick 	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM43602 },
334821fc986Spatrick 	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4371 },
3358e234c40Spatrick 	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4378 },
336e5ec1e72Spatrick };
337e5ec1e72Spatrick 
338e5ec1e72Spatrick int
339e5ec1e72Spatrick bwfm_pci_match(struct device *parent, void *match, void *aux)
340e5ec1e72Spatrick {
341e5ec1e72Spatrick 	return (pci_matchbyid(aux, bwfm_pci_devices,
342e5ec1e72Spatrick 	    nitems(bwfm_pci_devices)));
343e5ec1e72Spatrick }
344e5ec1e72Spatrick 
345e5ec1e72Spatrick void
346e5ec1e72Spatrick bwfm_pci_attach(struct device *parent, struct device *self, void *aux)
347e5ec1e72Spatrick {
348e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (struct bwfm_pci_softc *)self;
349e5ec1e72Spatrick 	struct pci_attach_args *pa = (struct pci_attach_args *)aux;
350e5ec1e72Spatrick 	const char *intrstr;
351e5ec1e72Spatrick 	pci_intr_handle_t ih;
352e5ec1e72Spatrick 
353e5ec1e72Spatrick 	if (pci_mapreg_map(pa, PCI_MAPREG_START + 0x08,
354e5ec1e72Spatrick 	    PCI_MAPREG_MEM_TYPE_64BIT, 0, &sc->sc_tcm_iot, &sc->sc_tcm_ioh,
355e5ec1e72Spatrick 	    NULL, &sc->sc_tcm_ios, 0)) {
356e5ec1e72Spatrick 		printf(": can't map bar1\n");
357a08e9144Spatrick 		return;
358a08e9144Spatrick 	}
359a08e9144Spatrick 
360a08e9144Spatrick 	if (pci_mapreg_map(pa, PCI_MAPREG_START + 0x00,
361a08e9144Spatrick 	    PCI_MAPREG_MEM_TYPE_64BIT, 0, &sc->sc_reg_iot, &sc->sc_reg_ioh,
362a08e9144Spatrick 	    NULL, &sc->sc_reg_ios, 0)) {
363a08e9144Spatrick 		printf(": can't map bar0\n");
364a08e9144Spatrick 		goto bar1;
365e5ec1e72Spatrick 	}
366e5ec1e72Spatrick 
367e5ec1e72Spatrick 	sc->sc_pc = pa->pa_pc;
368e5ec1e72Spatrick 	sc->sc_tag = pa->pa_tag;
369e5ec1e72Spatrick 	sc->sc_id = pa->pa_id;
370e5ec1e72Spatrick 	sc->sc_dmat = pa->pa_dmat;
371e5ec1e72Spatrick 
372e5ec1e72Spatrick 	/* Map and establish the interrupt. */
373e5ec1e72Spatrick 	if (pci_intr_map_msi(pa, &ih) != 0 && pci_intr_map(pa, &ih) != 0) {
374e5ec1e72Spatrick 		printf(": couldn't map interrupt\n");
375a08e9144Spatrick 		goto bar0;
376e5ec1e72Spatrick 	}
377e5ec1e72Spatrick 	intrstr = pci_intr_string(pa->pa_pc, ih);
378e5ec1e72Spatrick 
37914484acaSpatrick 	sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_NET,
380e5ec1e72Spatrick 	    bwfm_pci_intr, sc, DEVNAME(sc));
381e5ec1e72Spatrick 	if (sc->sc_ih == NULL) {
382e5ec1e72Spatrick 		printf(": couldn't establish interrupt");
383e5ec1e72Spatrick 		if (intrstr != NULL)
384e5ec1e72Spatrick 			printf(" at %s", intrstr);
385e5ec1e72Spatrick 		printf("\n");
386e5ec1e72Spatrick 		goto bar1;
387e5ec1e72Spatrick 	}
388e5ec1e72Spatrick 	printf(": %s\n", intrstr);
389e5ec1e72Spatrick 
390972218f3Spatrick 	sc->sc_sc.sc_bus_ops = &bwfm_pci_bus_ops;
391972218f3Spatrick 	sc->sc_sc.sc_proto_ops = &bwfm_pci_msgbuf_ops;
392972218f3Spatrick 	bwfm_attach(&sc->sc_sc);
393972218f3Spatrick 	config_mountroot(self, bwfm_attachhook);
394e5ec1e72Spatrick 	return;
395e5ec1e72Spatrick 
396e5ec1e72Spatrick bar0:
397e5ec1e72Spatrick 	bus_space_unmap(sc->sc_reg_iot, sc->sc_reg_ioh, sc->sc_reg_ios);
398a08e9144Spatrick bar1:
399a08e9144Spatrick 	bus_space_unmap(sc->sc_tcm_iot, sc->sc_tcm_ioh, sc->sc_tcm_ios);
400e5ec1e72Spatrick }
401e5ec1e72Spatrick 
402972218f3Spatrick int
403972218f3Spatrick bwfm_pci_preinit(struct bwfm_softc *bwfm)
404e5ec1e72Spatrick {
405972218f3Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
406e5ec1e72Spatrick 	struct bwfm_pci_ringinfo ringinfo;
4079ead8393Spatrick 	const char *chip = NULL;
40894e4747cSpatrick 	u_char *ucode, *nvram;
40994e4747cSpatrick 	size_t size, nvsize, nvlen;
410e5ec1e72Spatrick 	uint32_t d2h_w_idx_ptr, d2h_r_idx_ptr;
411e5ec1e72Spatrick 	uint32_t h2d_w_idx_ptr, h2d_r_idx_ptr;
412e5ec1e72Spatrick 	uint32_t idx_offset, reg;
413e5ec1e72Spatrick 	int i;
414e5ec1e72Spatrick 
415972218f3Spatrick 	if (sc->sc_initialized)
416972218f3Spatrick 		return 0;
417972218f3Spatrick 
418e5ec1e72Spatrick 	sc->sc_sc.sc_buscore_ops = &bwfm_pci_buscore_ops;
419e5ec1e72Spatrick 	if (bwfm_chip_attach(&sc->sc_sc) != 0) {
420e5ec1e72Spatrick 		printf("%s: cannot attach chip\n", DEVNAME(sc));
421972218f3Spatrick 		return 1;
422e5ec1e72Spatrick 	}
423e5ec1e72Spatrick 
424ed6d4272Spatrick #if defined(__HAVE_FDT)
425ed6d4272Spatrick 	if (bwfm_pci_read_otp(sc)) {
426ed6d4272Spatrick 		printf("%s: cannot read OTP\n", DEVNAME(sc));
427ed6d4272Spatrick 		return 1;
428ed6d4272Spatrick 	}
429ed6d4272Spatrick #endif
430ed6d4272Spatrick 
431e5ec1e72Spatrick 	bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2);
432e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
433e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_CONFIGADDR, 0x4e0);
434e5ec1e72Spatrick 	reg = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
435e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_CONFIGDATA);
436e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
437e5ec1e72Spatrick 	    BWFM_PCI_PCIE2REG_CONFIGDATA, reg);
438e5ec1e72Spatrick 
439e5ec1e72Spatrick 	switch (bwfm->sc_chip.ch_chip)
440e5ec1e72Spatrick 	{
44118b3a1dcSpatrick 	case BRCM_CC_4350_CHIP_ID:
4429ead8393Spatrick 		if (bwfm->sc_chip.ch_chiprev > 7)
4439ead8393Spatrick 			chip = "4350";
4449ead8393Spatrick 		else
4459ead8393Spatrick 			chip = "4350c2";
44618b3a1dcSpatrick 		break;
44741d93ac2Spatrick 	case BRCM_CC_4356_CHIP_ID:
4489ead8393Spatrick 		chip = "4356";
44941d93ac2Spatrick 		break;
450e5ec1e72Spatrick 	case BRCM_CC_43602_CHIP_ID:
4519ead8393Spatrick 		chip = "43602";
452e5ec1e72Spatrick 		break;
453821fc986Spatrick 	case BRCM_CC_4371_CHIP_ID:
4549ead8393Spatrick 		chip = "4371";
455821fc986Spatrick 		break;
456c38a9bc9Spatrick 	case BRCM_CC_4378_CHIP_ID:
457c38a9bc9Spatrick 		chip = "4378";
458c38a9bc9Spatrick 		break;
459e5ec1e72Spatrick 	default:
46018b3a1dcSpatrick 		printf("%s: unknown firmware for chip %s\n",
46118b3a1dcSpatrick 		    DEVNAME(sc), bwfm->sc_chip.ch_name);
462972218f3Spatrick 		return 1;
463e5ec1e72Spatrick 	}
464e5ec1e72Spatrick 
46594e4747cSpatrick 	if (bwfm_loadfirmware(bwfm, chip, "-pcie", &ucode, &size,
46694e4747cSpatrick 	    &nvram, &nvsize, &nvlen) != 0)
467972218f3Spatrick 		return 1;
4686aad491fSpatrick 
469e5ec1e72Spatrick 	/* Retrieve RAM size from firmware. */
470e5ec1e72Spatrick 	if (size >= BWFM_RAMSIZE + 8) {
471e5ec1e72Spatrick 		uint32_t *ramsize = (uint32_t *)&ucode[BWFM_RAMSIZE];
472e5ec1e72Spatrick 		if (letoh32(ramsize[0]) == BWFM_RAMSIZE_MAGIC)
473e5ec1e72Spatrick 			bwfm->sc_chip.ch_ramsize = letoh32(ramsize[1]);
474e5ec1e72Spatrick 	}
475e5ec1e72Spatrick 
4766aad491fSpatrick 	if (bwfm_pci_load_microcode(sc, ucode, size, nvram, nvlen) != 0) {
477e5ec1e72Spatrick 		printf("%s: could not load microcode\n",
478e5ec1e72Spatrick 		    DEVNAME(sc));
479e5ec1e72Spatrick 		free(ucode, M_DEVBUF, size);
480b4e85b06Spatrick 		free(nvram, M_DEVBUF, nvsize);
481972218f3Spatrick 		return 1;
482e5ec1e72Spatrick 	}
483e5ec1e72Spatrick 	free(ucode, M_DEVBUF, size);
484b4e85b06Spatrick 	free(nvram, M_DEVBUF, nvsize);
485e5ec1e72Spatrick 
486e5ec1e72Spatrick 	sc->sc_shared_flags = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
487e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_INFO);
488e5ec1e72Spatrick 	sc->sc_shared_version = sc->sc_shared_flags;
489e5ec1e72Spatrick 	if (sc->sc_shared_version > BWFM_SHARED_INFO_MAX_VERSION ||
490e5ec1e72Spatrick 	    sc->sc_shared_version < BWFM_SHARED_INFO_MIN_VERSION) {
491e5ec1e72Spatrick 		printf("%s: PCIe version %d unsupported\n",
492e5ec1e72Spatrick 		    DEVNAME(sc), sc->sc_shared_version);
493972218f3Spatrick 		return 1;
494e5ec1e72Spatrick 	}
495e5ec1e72Spatrick 
496e5ec1e72Spatrick 	if (sc->sc_shared_flags & BWFM_SHARED_INFO_DMA_INDEX) {
497e5ec1e72Spatrick 		if (sc->sc_shared_flags & BWFM_SHARED_INFO_DMA_2B_IDX)
498e5ec1e72Spatrick 			sc->sc_dma_idx_sz = sizeof(uint16_t);
499e5ec1e72Spatrick 		else
500e5ec1e72Spatrick 			sc->sc_dma_idx_sz = sizeof(uint32_t);
501e5ec1e72Spatrick 	}
502e5ec1e72Spatrick 
503e5ec1e72Spatrick 	/* Maximum RX data buffers in the ring. */
504e5ec1e72Spatrick 	sc->sc_max_rxbufpost = bus_space_read_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
505e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_MAX_RXBUFPOST);
506e5ec1e72Spatrick 	if (sc->sc_max_rxbufpost == 0)
507e5ec1e72Spatrick 		sc->sc_max_rxbufpost = BWFM_SHARED_MAX_RXBUFPOST_DEFAULT;
508e5ec1e72Spatrick 
509e5ec1e72Spatrick 	/* Alternative offset of data in a packet */
510e5ec1e72Spatrick 	sc->sc_rx_dataoffset = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
511e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_RX_DATAOFFSET);
512e5ec1e72Spatrick 
513e5ec1e72Spatrick 	/* For Power Management */
514e5ec1e72Spatrick 	sc->sc_htod_mb_data_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
515e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_HTOD_MB_DATA_ADDR);
516e5ec1e72Spatrick 	sc->sc_dtoh_mb_data_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
517e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DTOH_MB_DATA_ADDR);
518e5ec1e72Spatrick 
519e5ec1e72Spatrick 	/* Ring information */
520e5ec1e72Spatrick 	sc->sc_ring_info_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
521e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_RING_INFO_ADDR);
522e5ec1e72Spatrick 
523e5ec1e72Spatrick 	/* Firmware's "dmesg" */
524e5ec1e72Spatrick 	sc->sc_console_base_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
525e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_CONSOLE_ADDR);
526e5ec1e72Spatrick 	sc->sc_console_buf_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
527e5ec1e72Spatrick 	    sc->sc_console_base_addr + BWFM_CONSOLE_BUFADDR);
528e5ec1e72Spatrick 	sc->sc_console_buf_size = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
529e5ec1e72Spatrick 	    sc->sc_console_base_addr + BWFM_CONSOLE_BUFSIZE);
530e5ec1e72Spatrick 
531e5ec1e72Spatrick 	/* Read ring information. */
532e5ec1e72Spatrick 	bus_space_read_region_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
533e5ec1e72Spatrick 	    sc->sc_ring_info_addr, (void *)&ringinfo, sizeof(ringinfo));
534e5ec1e72Spatrick 
535e5ec1e72Spatrick 	if (sc->sc_shared_version >= 6) {
536e5ec1e72Spatrick 		sc->sc_max_submissionrings = le16toh(ringinfo.max_submissionrings);
537e5ec1e72Spatrick 		sc->sc_max_flowrings = le16toh(ringinfo.max_flowrings);
538e5ec1e72Spatrick 		sc->sc_max_completionrings = le16toh(ringinfo.max_completionrings);
539e5ec1e72Spatrick 	} else {
540e5ec1e72Spatrick 		sc->sc_max_submissionrings = le16toh(ringinfo.max_flowrings);
541e5ec1e72Spatrick 		sc->sc_max_flowrings = sc->sc_max_submissionrings -
542e5ec1e72Spatrick 		    BWFM_NUM_TX_MSGRINGS;
543e5ec1e72Spatrick 		sc->sc_max_completionrings = BWFM_NUM_RX_MSGRINGS;
544e5ec1e72Spatrick 	}
545e5ec1e72Spatrick 
546e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
547e5ec1e72Spatrick 		d2h_w_idx_ptr = letoh32(ringinfo.d2h_w_idx_ptr);
548e5ec1e72Spatrick 		d2h_r_idx_ptr = letoh32(ringinfo.d2h_r_idx_ptr);
549e5ec1e72Spatrick 		h2d_w_idx_ptr = letoh32(ringinfo.h2d_w_idx_ptr);
550e5ec1e72Spatrick 		h2d_r_idx_ptr = letoh32(ringinfo.h2d_r_idx_ptr);
551e5ec1e72Spatrick 		idx_offset = sizeof(uint32_t);
552e5ec1e72Spatrick 	} else {
553e5ec1e72Spatrick 		uint64_t address;
554e5ec1e72Spatrick 
555e5ec1e72Spatrick 		/* Each TX/RX Ring has a Read and Write Ptr */
556e5ec1e72Spatrick 		sc->sc_dma_idx_bufsz = (sc->sc_max_submissionrings +
557e5ec1e72Spatrick 		    sc->sc_max_completionrings) * sc->sc_dma_idx_sz * 2;
558e5ec1e72Spatrick 		sc->sc_dma_idx_buf = bwfm_pci_dmamem_alloc(sc,
559e5ec1e72Spatrick 		    sc->sc_dma_idx_bufsz, 8);
560e5ec1e72Spatrick 		if (sc->sc_dma_idx_buf == NULL) {
561e5ec1e72Spatrick 			/* XXX: Fallback to TCM? */
562e5ec1e72Spatrick 			printf("%s: cannot allocate idx buf\n",
563e5ec1e72Spatrick 			    DEVNAME(sc));
564972218f3Spatrick 			return 1;
565e5ec1e72Spatrick 		}
566e5ec1e72Spatrick 
567e5ec1e72Spatrick 		idx_offset = sc->sc_dma_idx_sz;
568e5ec1e72Spatrick 		h2d_w_idx_ptr = 0;
569e5ec1e72Spatrick 		address = BWFM_PCI_DMA_DVA(sc->sc_dma_idx_buf);
570e5ec1e72Spatrick 		ringinfo.h2d_w_idx_hostaddr_low =
571e5ec1e72Spatrick 		    htole32(address & 0xffffffff);
572e5ec1e72Spatrick 		ringinfo.h2d_w_idx_hostaddr_high =
573e5ec1e72Spatrick 		    htole32(address >> 32);
574e5ec1e72Spatrick 
575e5ec1e72Spatrick 		h2d_r_idx_ptr = h2d_w_idx_ptr +
576e5ec1e72Spatrick 		    sc->sc_max_submissionrings * idx_offset;
577e5ec1e72Spatrick 		address += sc->sc_max_submissionrings * idx_offset;
578e5ec1e72Spatrick 		ringinfo.h2d_r_idx_hostaddr_low =
579e5ec1e72Spatrick 		    htole32(address & 0xffffffff);
580e5ec1e72Spatrick 		ringinfo.h2d_r_idx_hostaddr_high =
581e5ec1e72Spatrick 		    htole32(address >> 32);
582e5ec1e72Spatrick 
583e5ec1e72Spatrick 		d2h_w_idx_ptr = h2d_r_idx_ptr +
584e5ec1e72Spatrick 		    sc->sc_max_submissionrings * idx_offset;
585e5ec1e72Spatrick 		address += sc->sc_max_submissionrings * idx_offset;
586e5ec1e72Spatrick 		ringinfo.d2h_w_idx_hostaddr_low =
587e5ec1e72Spatrick 		    htole32(address & 0xffffffff);
588e5ec1e72Spatrick 		ringinfo.d2h_w_idx_hostaddr_high =
589e5ec1e72Spatrick 		    htole32(address >> 32);
590e5ec1e72Spatrick 
591e5ec1e72Spatrick 		d2h_r_idx_ptr = d2h_w_idx_ptr +
592e5ec1e72Spatrick 		    sc->sc_max_completionrings * idx_offset;
593e5ec1e72Spatrick 		address += sc->sc_max_completionrings * idx_offset;
594e5ec1e72Spatrick 		ringinfo.d2h_r_idx_hostaddr_low =
595e5ec1e72Spatrick 		    htole32(address & 0xffffffff);
596e5ec1e72Spatrick 		ringinfo.d2h_r_idx_hostaddr_high =
597e5ec1e72Spatrick 		    htole32(address >> 32);
598e5ec1e72Spatrick 
599e5ec1e72Spatrick 		bus_space_write_region_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
600e5ec1e72Spatrick 		    sc->sc_ring_info_addr, (void *)&ringinfo, sizeof(ringinfo));
601e5ec1e72Spatrick 	}
602e5ec1e72Spatrick 
603e5ec1e72Spatrick 	uint32_t ring_mem_ptr = letoh32(ringinfo.ringmem);
604e5ec1e72Spatrick 	/* TX ctrl ring: Send ctrl buffers, send IOCTLs */
605e5ec1e72Spatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_ctrl_submit, 64, 40,
606e5ec1e72Spatrick 	    h2d_w_idx_ptr, h2d_r_idx_ptr, 0, idx_offset,
607e5ec1e72Spatrick 	    &ring_mem_ptr))
608e5ec1e72Spatrick 		goto cleanup;
609e5ec1e72Spatrick 	/* TX rxpost ring: Send clean data mbufs for RX */
610e5ec1e72Spatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_rxpost_submit, 512, 32,
611e5ec1e72Spatrick 	    h2d_w_idx_ptr, h2d_r_idx_ptr, 1, idx_offset,
612e5ec1e72Spatrick 	    &ring_mem_ptr))
613e5ec1e72Spatrick 		goto cleanup;
614e5ec1e72Spatrick 	/* RX completion rings: recv our filled buffers back */
615e5ec1e72Spatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_ctrl_complete, 64, 24,
616e5ec1e72Spatrick 	    d2h_w_idx_ptr, d2h_r_idx_ptr, 0, idx_offset,
617e5ec1e72Spatrick 	    &ring_mem_ptr))
618e5ec1e72Spatrick 		goto cleanup;
619095b0c44Spatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_tx_complete, 1024,
620095b0c44Spatrick 	    sc->sc_shared_version >= 7 ? 24 : 16,
621e5ec1e72Spatrick 	    d2h_w_idx_ptr, d2h_r_idx_ptr, 1, idx_offset,
622e5ec1e72Spatrick 	    &ring_mem_ptr))
623e5ec1e72Spatrick 		goto cleanup;
624095b0c44Spatrick 	if (bwfm_pci_setup_ring(sc, &sc->sc_rx_complete, 512,
625095b0c44Spatrick 	    sc->sc_shared_version >= 7 ? 40 : 32,
626e5ec1e72Spatrick 	    d2h_w_idx_ptr, d2h_r_idx_ptr, 2, idx_offset,
627e5ec1e72Spatrick 	    &ring_mem_ptr))
628e5ec1e72Spatrick 		goto cleanup;
629e5ec1e72Spatrick 
630e5ec1e72Spatrick 	/* Dynamic TX rings for actual data */
631e5ec1e72Spatrick 	sc->sc_flowrings = malloc(sc->sc_max_flowrings *
632e5ec1e72Spatrick 	    sizeof(struct bwfm_pci_msgring), M_DEVBUF, M_WAITOK | M_ZERO);
633518be5f3Spatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
634518be5f3Spatrick 		struct bwfm_pci_msgring *ring = &sc->sc_flowrings[i];
635518be5f3Spatrick 		ring->w_idx_addr = h2d_w_idx_ptr + (i + 2) * idx_offset;
636518be5f3Spatrick 		ring->r_idx_addr = h2d_r_idx_ptr + (i + 2) * idx_offset;
637518be5f3Spatrick 	}
638e5ec1e72Spatrick 
639e5ec1e72Spatrick 	/* Scratch and ring update buffers for firmware */
640e5ec1e72Spatrick 	if ((sc->sc_scratch_buf = bwfm_pci_dmamem_alloc(sc,
641e5ec1e72Spatrick 	    BWFM_DMA_D2H_SCRATCH_BUF_LEN, 8)) == NULL)
642e5ec1e72Spatrick 		goto cleanup;
643e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
644e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_SCRATCH_ADDR_LOW,
645e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(sc->sc_scratch_buf) & 0xffffffff);
646e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
647e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_SCRATCH_ADDR_HIGH,
648e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(sc->sc_scratch_buf) >> 32);
649e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
650e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_SCRATCH_LEN,
651e5ec1e72Spatrick 	    BWFM_DMA_D2H_SCRATCH_BUF_LEN);
652e5ec1e72Spatrick 
653e5ec1e72Spatrick 	if ((sc->sc_ringupd_buf = bwfm_pci_dmamem_alloc(sc,
654e5ec1e72Spatrick 	    BWFM_DMA_D2H_RINGUPD_BUF_LEN, 8)) == NULL)
655e5ec1e72Spatrick 		goto cleanup;
656e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
657e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_RINGUPD_ADDR_LOW,
658e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(sc->sc_ringupd_buf) & 0xffffffff);
659e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
660e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_RINGUPD_ADDR_HIGH,
661e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(sc->sc_ringupd_buf) >> 32);
662e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
663e5ec1e72Spatrick 	    sc->sc_shared_address + BWFM_SHARED_DMA_RINGUPD_LEN,
664e5ec1e72Spatrick 	    BWFM_DMA_D2H_RINGUPD_BUF_LEN);
665e5ec1e72Spatrick 
666e5ec1e72Spatrick 	bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2);
667e5ec1e72Spatrick 	bwfm_pci_intr_enable(sc);
668156d2677Spatrick 	bwfm_pci_hostready(sc);
669e5ec1e72Spatrick 
670e5ec1e72Spatrick 	/* Maps RX mbufs to a packet id and back. */
671e5ec1e72Spatrick 	sc->sc_rx_pkts.npkt = BWFM_NUM_RX_PKTIDS;
672e5ec1e72Spatrick 	sc->sc_rx_pkts.pkts = malloc(BWFM_NUM_RX_PKTIDS *
673e5ec1e72Spatrick 	    sizeof(struct bwfm_pci_buf), M_DEVBUF, M_WAITOK | M_ZERO);
674e5ec1e72Spatrick 	for (i = 0; i < BWFM_NUM_RX_PKTIDS; i++)
6751950c5c5Spatrick 		bus_dmamap_create(sc->sc_dmat, MSGBUF_MAX_CTL_PKT_SIZE,
6761950c5c5Spatrick 		    BWFM_NUM_RX_DESCS, MSGBUF_MAX_CTL_PKT_SIZE, 0, BUS_DMA_WAITOK,
677e5ec1e72Spatrick 		    &sc->sc_rx_pkts.pkts[i].bb_map);
678e5ec1e72Spatrick 
679e5ec1e72Spatrick 	/* Maps TX mbufs to a packet id and back. */
680f416501bSpatrick 	sc->sc_tx_pkts.npkt = BWFM_NUM_TX_PKTIDS;
681e5ec1e72Spatrick 	sc->sc_tx_pkts.pkts = malloc(BWFM_NUM_TX_PKTIDS
682e5ec1e72Spatrick 	    * sizeof(struct bwfm_pci_buf), M_DEVBUF, M_WAITOK | M_ZERO);
683e5ec1e72Spatrick 	for (i = 0; i < BWFM_NUM_TX_PKTIDS; i++)
684e5ec1e72Spatrick 		bus_dmamap_create(sc->sc_dmat, MSGBUF_MAX_PKT_SIZE,
685e5ec1e72Spatrick 		    BWFM_NUM_TX_DESCS, MSGBUF_MAX_PKT_SIZE, 0, BUS_DMA_WAITOK,
686e5ec1e72Spatrick 		    &sc->sc_tx_pkts.pkts[i].bb_map);
687e5ec1e72Spatrick 
6882eeba925Spatrick 	/* Maps IOCTL mbufs to a packet id and back. */
6892eeba925Spatrick 	sc->sc_ioctl_pkts.npkt = BWFM_NUM_IOCTL_PKTIDS;
6902eeba925Spatrick 	sc->sc_ioctl_pkts.pkts = malloc(BWFM_NUM_IOCTL_PKTIDS
6912eeba925Spatrick 	    * sizeof(struct bwfm_pci_buf), M_DEVBUF, M_WAITOK | M_ZERO);
6922eeba925Spatrick 	for (i = 0; i < BWFM_NUM_IOCTL_PKTIDS; i++)
6932eeba925Spatrick 		bus_dmamap_create(sc->sc_dmat, MSGBUF_MAX_PKT_SIZE,
6942eeba925Spatrick 		    BWFM_NUM_IOCTL_DESCS, MSGBUF_MAX_PKT_SIZE, 0, BUS_DMA_WAITOK,
6952eeba925Spatrick 		    &sc->sc_ioctl_pkts.pkts[i].bb_map);
6962eeba925Spatrick 
69718722113Spatrick 	/*
69818722113Spatrick 	 * For whatever reason, could also be a bug somewhere in this
69918722113Spatrick 	 * driver, the firmware needs a bunch of RX buffers otherwise
7004ef2dd0fSpatrick 	 * it won't send any RX complete messages.
70118722113Spatrick 	 */
7024ef2dd0fSpatrick 	if_rxr_init(&sc->sc_rxbuf_ring, min(256, sc->sc_max_rxbufpost),
7034ef2dd0fSpatrick 	    sc->sc_max_rxbufpost);
704e5ec1e72Spatrick 	if_rxr_init(&sc->sc_ioctl_ring, 8, 8);
705e5ec1e72Spatrick 	if_rxr_init(&sc->sc_event_ring, 8, 8);
706e5ec1e72Spatrick 	bwfm_pci_fill_rx_rings(sc);
707e5ec1e72Spatrick 
7082eeba925Spatrick 	TAILQ_INIT(&sc->sc_ioctlq);
7092eeba925Spatrick 
710cadf5fcfSpatrick #ifdef BWFM_DEBUG
711cadf5fcfSpatrick 	sc->sc_console_readidx = 0;
712cadf5fcfSpatrick 	bwfm_pci_debug_console(sc);
713cadf5fcfSpatrick #endif
714cadf5fcfSpatrick 
715972218f3Spatrick 	sc->sc_initialized = 1;
716972218f3Spatrick 	return 0;
717e5ec1e72Spatrick 
718e5ec1e72Spatrick cleanup:
719e5ec1e72Spatrick 	if (sc->sc_ringupd_buf)
720e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_ringupd_buf);
721e5ec1e72Spatrick 	if (sc->sc_scratch_buf)
722e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_scratch_buf);
723e5ec1e72Spatrick 	if (sc->sc_rx_complete.ring)
724e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_rx_complete.ring);
725e5ec1e72Spatrick 	if (sc->sc_tx_complete.ring)
726e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_tx_complete.ring);
727e5ec1e72Spatrick 	if (sc->sc_ctrl_complete.ring)
728e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_ctrl_complete.ring);
729e5ec1e72Spatrick 	if (sc->sc_rxpost_submit.ring)
730e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_rxpost_submit.ring);
731e5ec1e72Spatrick 	if (sc->sc_ctrl_submit.ring)
732e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_ctrl_submit.ring);
733e5ec1e72Spatrick 	if (sc->sc_dma_idx_buf)
734e5ec1e72Spatrick 		bwfm_pci_dmamem_free(sc, sc->sc_dma_idx_buf);
735972218f3Spatrick 	return 1;
736e5ec1e72Spatrick }
737e5ec1e72Spatrick 
738e5ec1e72Spatrick int
7396aad491fSpatrick bwfm_pci_load_microcode(struct bwfm_pci_softc *sc, const u_char *ucode, size_t size,
7406aad491fSpatrick     const u_char *nvram, size_t nvlen)
741e5ec1e72Spatrick {
742e5ec1e72Spatrick 	struct bwfm_softc *bwfm = (void *)sc;
743e5ec1e72Spatrick 	struct bwfm_core *core;
7446aad491fSpatrick 	uint32_t shared, written;
745e5ec1e72Spatrick 	int i;
746e5ec1e72Spatrick 
747e5ec1e72Spatrick 	if (bwfm->sc_chip.ch_chip == BRCM_CC_43602_CHIP_ID) {
748e5ec1e72Spatrick 		bwfm_pci_select_core(sc, BWFM_AGENT_CORE_ARM_CR4);
749e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
750e5ec1e72Spatrick 		    BWFM_PCI_ARMCR4REG_BANKIDX, 5);
751e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
752e5ec1e72Spatrick 		    BWFM_PCI_ARMCR4REG_BANKPDA, 0);
753e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
754e5ec1e72Spatrick 		    BWFM_PCI_ARMCR4REG_BANKIDX, 7);
755e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
756e5ec1e72Spatrick 		    BWFM_PCI_ARMCR4REG_BANKPDA, 0);
757e5ec1e72Spatrick 	}
758e5ec1e72Spatrick 
759e5ec1e72Spatrick 	for (i = 0; i < size; i++)
760e5ec1e72Spatrick 		bus_space_write_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
761e5ec1e72Spatrick 		    bwfm->sc_chip.ch_rambase + i, ucode[i]);
762e5ec1e72Spatrick 
763e5ec1e72Spatrick 	/* Firmware replaces this with a pointer once up. */
764e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
765e5ec1e72Spatrick 	    bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize - 4, 0);
766e5ec1e72Spatrick 
7676aad491fSpatrick 	if (nvram) {
7686aad491fSpatrick 		for (i = 0; i < nvlen; i++)
7696aad491fSpatrick 			bus_space_write_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
7706aad491fSpatrick 			    bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize
7716aad491fSpatrick 			    - nvlen  + i, nvram[i]);
7726aad491fSpatrick 	}
7736aad491fSpatrick 
7746aad491fSpatrick 	written = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
7756aad491fSpatrick 	    bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize - 4);
776e5ec1e72Spatrick 
777e5ec1e72Spatrick 	/* Load reset vector from firmware and kickstart core. */
778b0cd4990Spatrick 	if (bwfm->sc_chip.ch_chip == BRCM_CC_43602_CHIP_ID) {
779e5ec1e72Spatrick 		core = bwfm_chip_get_core(bwfm, BWFM_AGENT_INTERNAL_MEM);
780e5ec1e72Spatrick 		bwfm->sc_chip.ch_core_reset(bwfm, core, 0, 0, 0);
781b0cd4990Spatrick 	}
782e5ec1e72Spatrick 	bwfm_chip_set_active(bwfm, *(uint32_t *)ucode);
783e5ec1e72Spatrick 
7843c53ddefSpatrick 	for (i = 0; i < 100; i++) {
785e5ec1e72Spatrick 		delay(50 * 1000);
786e5ec1e72Spatrick 		shared = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
787e5ec1e72Spatrick 		    bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize - 4);
7886aad491fSpatrick 		if (shared != written)
789e5ec1e72Spatrick 			break;
790e5ec1e72Spatrick 	}
79119871452Spatrick 	if (shared == written) {
792e5ec1e72Spatrick 		printf("%s: firmware did not come up\n", DEVNAME(sc));
793e5ec1e72Spatrick 		return 1;
794e5ec1e72Spatrick 	}
79519871452Spatrick 	if (shared < bwfm->sc_chip.ch_rambase ||
79619871452Spatrick 	    shared >= bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize) {
79719871452Spatrick 		printf("%s: invalid shared RAM address 0x%08x\n", DEVNAME(sc),
79819871452Spatrick 		    shared);
79919871452Spatrick 		return 1;
80019871452Spatrick 	}
801e5ec1e72Spatrick 
802e5ec1e72Spatrick 	sc->sc_shared_address = shared;
803e5ec1e72Spatrick 	return 0;
804e5ec1e72Spatrick }
805e5ec1e72Spatrick 
806e5ec1e72Spatrick int
807e5ec1e72Spatrick bwfm_pci_detach(struct device *self, int flags)
808e5ec1e72Spatrick {
809e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (struct bwfm_pci_softc *)self;
810e5ec1e72Spatrick 
811e5ec1e72Spatrick 	bwfm_detach(&sc->sc_sc, flags);
812e5ec1e72Spatrick 
813e5ec1e72Spatrick 	/* FIXME: free RX buffers */
814e5ec1e72Spatrick 	/* FIXME: free TX buffers */
815e5ec1e72Spatrick 	/* FIXME: free more memory */
816e5ec1e72Spatrick 
817e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_ringupd_buf);
818e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_scratch_buf);
819e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_rx_complete.ring);
820e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_tx_complete.ring);
821e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_ctrl_complete.ring);
822e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_rxpost_submit.ring);
823e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_ctrl_submit.ring);
824e5ec1e72Spatrick 	bwfm_pci_dmamem_free(sc, sc->sc_dma_idx_buf);
825e5ec1e72Spatrick 	return 0;
826e5ec1e72Spatrick }
827e5ec1e72Spatrick 
828ed6d4272Spatrick #if defined(__HAVE_FDT)
829ed6d4272Spatrick int
830ed6d4272Spatrick bwfm_pci_read_otp(struct bwfm_pci_softc *sc)
831ed6d4272Spatrick {
832ed6d4272Spatrick 	struct bwfm_softc *bwfm = (void *)sc;
833ed6d4272Spatrick 	struct bwfm_core *core;
834ed6d4272Spatrick 	uint8_t otp[BWFM_OTP_SIZE];
835ed6d4272Spatrick 	int i;
836ed6d4272Spatrick 
837ed6d4272Spatrick 	if (bwfm->sc_chip.ch_chip != BRCM_CC_4378_CHIP_ID)
838ed6d4272Spatrick 		return 0;
839ed6d4272Spatrick 
840ed6d4272Spatrick 	core = bwfm_chip_get_core(bwfm, BWFM_AGENT_CORE_GCI);
841ed6d4272Spatrick 	if (core == NULL)
842ed6d4272Spatrick 		return 1;
843ed6d4272Spatrick 
844ed6d4272Spatrick 	for (i = 0; i < (sizeof(otp) / sizeof(uint32_t)); i++)
845ed6d4272Spatrick 		((uint32_t *)otp)[i] = bwfm_pci_buscore_read(bwfm,
846ed6d4272Spatrick 		    core->co_base + BWFM_OTP_4378_BASE + i * sizeof(uint32_t));
847ed6d4272Spatrick 
848ed6d4272Spatrick 	for (i = 0; i < BWFM_OTP_SIZE - 1; ) {
849ed6d4272Spatrick 		if (otp[i + 0] == 0) {
850ed6d4272Spatrick 			i++;
851ed6d4272Spatrick 			continue;
852ed6d4272Spatrick 		}
853ed6d4272Spatrick 		if (i + otp[i + 1] > BWFM_OTP_SIZE)
854ed6d4272Spatrick 			break;
855ed6d4272Spatrick 		bwfm_pci_process_otp_tuple(sc, otp[i + 0], otp[i + 1],
856ed6d4272Spatrick 		    &otp[i + 2]);
857ed6d4272Spatrick 		i += otp[i + 1];
858ed6d4272Spatrick 	}
859ed6d4272Spatrick 
860ed6d4272Spatrick 	return 0;
861ed6d4272Spatrick }
862ed6d4272Spatrick 
863ed6d4272Spatrick void
864ed6d4272Spatrick bwfm_pci_process_otp_tuple(struct bwfm_pci_softc *sc, uint8_t type, uint8_t size,
865ed6d4272Spatrick     uint8_t *data)
866ed6d4272Spatrick {
867ed6d4272Spatrick 	struct bwfm_softc *bwfm = (void *)sc;
868ed6d4272Spatrick 	char chiprev[8] = "", module[8] = "", modrev[8] = "", vendor[8] = "", chip[8] = "";
869ed6d4272Spatrick 	char product[16] = "unknown";
870ed6d4272Spatrick 	int node, len;
871ed6d4272Spatrick 
872ed6d4272Spatrick 	switch (type) {
873ed6d4272Spatrick 	case 0x15: /* system vendor OTP */
874ed6d4272Spatrick 		DPRINTF(("%s: system vendor OTP\n", DEVNAME(sc)));
875ed6d4272Spatrick 		if (size < sizeof(uint32_t))
876ed6d4272Spatrick 			return;
877ed6d4272Spatrick 		if (data[0] != 0x08 || data[1] != 0x00 ||
878ed6d4272Spatrick 		    data[2] != 0x00 || data[3] != 0x00)
879ed6d4272Spatrick 			return;
880ed6d4272Spatrick 		size -= sizeof(uint32_t);
881ed6d4272Spatrick 		data += sizeof(uint32_t);
882ed6d4272Spatrick 		while (size) {
883ed6d4272Spatrick 			/* reached end */
884ed6d4272Spatrick 			if (data[0] == 0xff)
885ed6d4272Spatrick 				break;
886ed6d4272Spatrick 			for (len = 0; len < size; len++)
887ed6d4272Spatrick 				if (data[len] == 0x00 || data[len] == ' ' ||
888ed6d4272Spatrick 				    data[len] == 0xff)
889ed6d4272Spatrick 					break;
890ed6d4272Spatrick 			if (len < 3 || len > 9) /* X=abcdef */
891ed6d4272Spatrick 				goto next;
892ed6d4272Spatrick 			if (data[1] != '=')
893ed6d4272Spatrick 				goto next;
894ed6d4272Spatrick 			/* NULL-terminate string */
895ed6d4272Spatrick 			if (data[len] == ' ')
896ed6d4272Spatrick 				data[len] = '\0';
897ed6d4272Spatrick 			switch (data[0]) {
898ed6d4272Spatrick 			case 's':
899ed6d4272Spatrick 				strlcpy(chiprev, &data[2], sizeof(chiprev));
900ed6d4272Spatrick 				break;
901ed6d4272Spatrick 			case 'M':
902ed6d4272Spatrick 				strlcpy(module, &data[2], sizeof(module));
903ed6d4272Spatrick 				break;
904ed6d4272Spatrick 			case 'm':
905ed6d4272Spatrick 				strlcpy(modrev, &data[2], sizeof(modrev));
906ed6d4272Spatrick 				break;
907ed6d4272Spatrick 			case 'V':
908ed6d4272Spatrick 				strlcpy(vendor, &data[2], sizeof(vendor));
909ed6d4272Spatrick 				break;
910ed6d4272Spatrick 			}
911ed6d4272Spatrick next:
912ed6d4272Spatrick 			/* skip content */
913ed6d4272Spatrick 			data += len;
914ed6d4272Spatrick 			size -= len;
915ed6d4272Spatrick 			/* skip spacer tag */
916ed6d4272Spatrick 			if (size) {
917ed6d4272Spatrick 				data++;
918ed6d4272Spatrick 				size--;
919ed6d4272Spatrick 			}
920ed6d4272Spatrick 		}
921ed6d4272Spatrick 		snprintf(chip, sizeof(chip),
922ed6d4272Spatrick 		    bwfm->sc_chip.ch_chip > 40000 ? "%05d" : "%04x",
923ed6d4272Spatrick 		    bwfm->sc_chip.ch_chip);
924ed6d4272Spatrick 		node = OF_finddevice("/chosen");
925ed6d4272Spatrick 		if (node != -1)
926ed6d4272Spatrick 			OF_getprop(node, "module-wlan0", product, sizeof(product));
927ed6d4272Spatrick 		printf("%s: firmware C-%s%s%s/P-%s_M-%s_V-%s__m-%s\n",
928ed6d4272Spatrick 		    DEVNAME(sc), chip,
929ed6d4272Spatrick 		    *chiprev ? "__s-" : "", *chiprev ? chiprev : "",
930ed6d4272Spatrick 		    product, module, vendor, modrev);
931ed6d4272Spatrick 		break;
932ed6d4272Spatrick 	case 0x80: /* Broadcom CIS */
933ed6d4272Spatrick 		DPRINTF(("%s: Broadcom CIS\n", DEVNAME(sc)));
934ed6d4272Spatrick 		break;
935ed6d4272Spatrick 	default:
936ed6d4272Spatrick 		DPRINTF(("%s: unknown OTP tuple\n", DEVNAME(sc)));
937ed6d4272Spatrick 		break;
938ed6d4272Spatrick 	}
939ed6d4272Spatrick }
940ed6d4272Spatrick #endif
941ed6d4272Spatrick 
942e5ec1e72Spatrick /* DMA code */
943e5ec1e72Spatrick struct bwfm_pci_dmamem *
944e5ec1e72Spatrick bwfm_pci_dmamem_alloc(struct bwfm_pci_softc *sc, bus_size_t size, bus_size_t align)
945e5ec1e72Spatrick {
946e5ec1e72Spatrick 	struct bwfm_pci_dmamem *bdm;
947e5ec1e72Spatrick 	int nsegs;
948e5ec1e72Spatrick 
949e5ec1e72Spatrick 	bdm = malloc(sizeof(*bdm), M_DEVBUF, M_WAITOK | M_ZERO);
950e5ec1e72Spatrick 	bdm->bdm_size = size;
951e5ec1e72Spatrick 
952e5ec1e72Spatrick 	if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
953e5ec1e72Spatrick 	    BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &bdm->bdm_map) != 0)
954e5ec1e72Spatrick 		goto bdmfree;
955e5ec1e72Spatrick 
956e5ec1e72Spatrick 	if (bus_dmamem_alloc(sc->sc_dmat, size, align, 0, &bdm->bdm_seg, 1,
957e5ec1e72Spatrick 	    &nsegs, BUS_DMA_WAITOK) != 0)
958e5ec1e72Spatrick 		goto destroy;
959e5ec1e72Spatrick 
960e5ec1e72Spatrick 	if (bus_dmamem_map(sc->sc_dmat, &bdm->bdm_seg, nsegs, size,
961e5ec1e72Spatrick 	    &bdm->bdm_kva, BUS_DMA_WAITOK | BUS_DMA_COHERENT) != 0)
962e5ec1e72Spatrick 		goto free;
963e5ec1e72Spatrick 
964e5ec1e72Spatrick 	if (bus_dmamap_load(sc->sc_dmat, bdm->bdm_map, bdm->bdm_kva, size,
965e5ec1e72Spatrick 	    NULL, BUS_DMA_WAITOK) != 0)
966e5ec1e72Spatrick 		goto unmap;
967e5ec1e72Spatrick 
968e5ec1e72Spatrick 	bzero(bdm->bdm_kva, size);
969e5ec1e72Spatrick 
970e5ec1e72Spatrick 	return (bdm);
971e5ec1e72Spatrick 
972e5ec1e72Spatrick unmap:
973e5ec1e72Spatrick 	bus_dmamem_unmap(sc->sc_dmat, bdm->bdm_kva, size);
974e5ec1e72Spatrick free:
975e5ec1e72Spatrick 	bus_dmamem_free(sc->sc_dmat, &bdm->bdm_seg, 1);
976e5ec1e72Spatrick destroy:
977e5ec1e72Spatrick 	bus_dmamap_destroy(sc->sc_dmat, bdm->bdm_map);
978e5ec1e72Spatrick bdmfree:
97965046b40Spatrick 	free(bdm, M_DEVBUF, sizeof(*bdm));
980e5ec1e72Spatrick 
981e5ec1e72Spatrick 	return (NULL);
982e5ec1e72Spatrick }
983e5ec1e72Spatrick 
984e5ec1e72Spatrick void
985e5ec1e72Spatrick bwfm_pci_dmamem_free(struct bwfm_pci_softc *sc, struct bwfm_pci_dmamem *bdm)
986e5ec1e72Spatrick {
987e5ec1e72Spatrick 	bus_dmamem_unmap(sc->sc_dmat, bdm->bdm_kva, bdm->bdm_size);
988e5ec1e72Spatrick 	bus_dmamem_free(sc->sc_dmat, &bdm->bdm_seg, 1);
989e5ec1e72Spatrick 	bus_dmamap_destroy(sc->sc_dmat, bdm->bdm_map);
99065046b40Spatrick 	free(bdm, M_DEVBUF, sizeof(*bdm));
991e5ec1e72Spatrick }
992e5ec1e72Spatrick 
993e5ec1e72Spatrick /*
994e5ec1e72Spatrick  * We need a simple mapping from a packet ID to mbufs, because when
995e5ec1e72Spatrick  * a transfer completed, we only know the ID so we have to look up
996e5ec1e72Spatrick  * the memory for the ID.  This simply looks for an empty slot.
997e5ec1e72Spatrick  */
998e5ec1e72Spatrick int
99902ee7d07Spatrick bwfm_pci_pktid_avail(struct bwfm_pci_softc *sc, struct bwfm_pci_pkts *pkts)
100002ee7d07Spatrick {
100102ee7d07Spatrick 	int i, idx;
100202ee7d07Spatrick 
100302ee7d07Spatrick 	idx = pkts->last + 1;
100402ee7d07Spatrick 	for (i = 0; i < pkts->npkt; i++) {
100502ee7d07Spatrick 		if (idx == pkts->npkt)
100602ee7d07Spatrick 			idx = 0;
100702ee7d07Spatrick 		if (pkts->pkts[idx].bb_m == NULL)
100802ee7d07Spatrick 			return 0;
100902ee7d07Spatrick 		idx++;
101002ee7d07Spatrick 	}
101102ee7d07Spatrick 	return ENOBUFS;
101202ee7d07Spatrick }
101302ee7d07Spatrick 
101402ee7d07Spatrick int
1015e5ec1e72Spatrick bwfm_pci_pktid_new(struct bwfm_pci_softc *sc, struct bwfm_pci_pkts *pkts,
1016e5ec1e72Spatrick     struct mbuf *m, uint32_t *pktid, paddr_t *paddr)
1017e5ec1e72Spatrick {
1018e5ec1e72Spatrick 	int i, idx;
1019e5ec1e72Spatrick 
1020e5ec1e72Spatrick 	idx = pkts->last + 1;
1021e5ec1e72Spatrick 	for (i = 0; i < pkts->npkt; i++) {
1022e5ec1e72Spatrick 		if (idx == pkts->npkt)
1023e5ec1e72Spatrick 			idx = 0;
1024e5ec1e72Spatrick 		if (pkts->pkts[idx].bb_m == NULL) {
1025e5ec1e72Spatrick 			if (bus_dmamap_load_mbuf(sc->sc_dmat,
1026e5ec1e72Spatrick 			    pkts->pkts[idx].bb_map, m, BUS_DMA_NOWAIT) != 0) {
1027518be5f3Spatrick 				if (m_defrag(m, M_DONTWAIT))
1028518be5f3Spatrick 					return EFBIG;
1029518be5f3Spatrick 				if (bus_dmamap_load_mbuf(sc->sc_dmat,
1030518be5f3Spatrick 				    pkts->pkts[idx].bb_map, m, BUS_DMA_NOWAIT) != 0)
1031518be5f3Spatrick 					return EFBIG;
1032e5ec1e72Spatrick 			}
1033dcb67343Spatrick 			bus_dmamap_sync(sc->sc_dmat, pkts->pkts[idx].bb_map,
1034dcb67343Spatrick 			    0, pkts->pkts[idx].bb_map->dm_mapsize,
1035dcb67343Spatrick 			    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1036e5ec1e72Spatrick 			pkts->last = idx;
1037e5ec1e72Spatrick 			pkts->pkts[idx].bb_m = m;
1038e5ec1e72Spatrick 			*pktid = idx;
1039e5ec1e72Spatrick 			*paddr = pkts->pkts[idx].bb_map->dm_segs[0].ds_addr;
1040e5ec1e72Spatrick 			return 0;
1041e5ec1e72Spatrick 		}
1042e5ec1e72Spatrick 		idx++;
1043e5ec1e72Spatrick 	}
1044518be5f3Spatrick 	return ENOBUFS;
1045e5ec1e72Spatrick }
1046e5ec1e72Spatrick 
1047e5ec1e72Spatrick struct mbuf *
1048e5ec1e72Spatrick bwfm_pci_pktid_free(struct bwfm_pci_softc *sc, struct bwfm_pci_pkts *pkts,
1049e5ec1e72Spatrick     uint32_t pktid)
1050e5ec1e72Spatrick {
1051e5ec1e72Spatrick 	struct mbuf *m;
1052e5ec1e72Spatrick 
1053e5ec1e72Spatrick 	if (pktid >= pkts->npkt || pkts->pkts[pktid].bb_m == NULL)
1054e5ec1e72Spatrick 		return NULL;
1055dcb67343Spatrick 	bus_dmamap_sync(sc->sc_dmat, pkts->pkts[pktid].bb_map, 0,
1056dcb67343Spatrick 	    pkts->pkts[pktid].bb_map->dm_mapsize,
1057dcb67343Spatrick 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1058e5ec1e72Spatrick 	bus_dmamap_unload(sc->sc_dmat, pkts->pkts[pktid].bb_map);
1059e5ec1e72Spatrick 	m = pkts->pkts[pktid].bb_m;
1060e5ec1e72Spatrick 	pkts->pkts[pktid].bb_m = NULL;
1061e5ec1e72Spatrick 	return m;
1062e5ec1e72Spatrick }
1063e5ec1e72Spatrick 
1064e5ec1e72Spatrick void
1065e5ec1e72Spatrick bwfm_pci_fill_rx_rings(struct bwfm_pci_softc *sc)
1066e5ec1e72Spatrick {
106718722113Spatrick 	bwfm_pci_fill_rx_buf_ring(sc);
1068e5ec1e72Spatrick 	bwfm_pci_fill_rx_ioctl_ring(sc, &sc->sc_ioctl_ring,
1069e5ec1e72Spatrick 	    MSGBUF_TYPE_IOCTLRESP_BUF_POST);
1070e5ec1e72Spatrick 	bwfm_pci_fill_rx_ioctl_ring(sc, &sc->sc_event_ring,
1071e5ec1e72Spatrick 	    MSGBUF_TYPE_EVENT_BUF_POST);
1072e5ec1e72Spatrick }
1073e5ec1e72Spatrick 
1074e5ec1e72Spatrick void
1075e5ec1e72Spatrick bwfm_pci_fill_rx_ioctl_ring(struct bwfm_pci_softc *sc, struct if_rxring *rxring,
1076e5ec1e72Spatrick     uint32_t msgtype)
1077e5ec1e72Spatrick {
1078e5ec1e72Spatrick 	struct msgbuf_rx_ioctl_resp_or_event *req;
1079e5ec1e72Spatrick 	struct mbuf *m;
1080e5ec1e72Spatrick 	uint32_t pktid;
1081e5ec1e72Spatrick 	paddr_t paddr;
1082e5ec1e72Spatrick 	int s, slots;
1083e5ec1e72Spatrick 
1084e5ec1e72Spatrick 	s = splnet();
1085e5ec1e72Spatrick 	for (slots = if_rxr_get(rxring, 8); slots > 0; slots--) {
108602ee7d07Spatrick 		if (bwfm_pci_pktid_avail(sc, &sc->sc_rx_pkts))
108702ee7d07Spatrick 			break;
1088e5ec1e72Spatrick 		req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit);
1089e5ec1e72Spatrick 		if (req == NULL)
1090e5ec1e72Spatrick 			break;
10911950c5c5Spatrick 		m = MCLGETL(NULL, M_DONTWAIT, MSGBUF_MAX_CTL_PKT_SIZE);
1092e5ec1e72Spatrick 		if (m == NULL) {
1093e5ec1e72Spatrick 			bwfm_pci_ring_write_cancel(sc, &sc->sc_ctrl_submit, 1);
1094e5ec1e72Spatrick 			break;
1095e5ec1e72Spatrick 		}
10961950c5c5Spatrick 		m->m_len = m->m_pkthdr.len = MSGBUF_MAX_CTL_PKT_SIZE;
1097e5ec1e72Spatrick 		if (bwfm_pci_pktid_new(sc, &sc->sc_rx_pkts, m, &pktid, &paddr)) {
1098e5ec1e72Spatrick 			bwfm_pci_ring_write_cancel(sc, &sc->sc_ctrl_submit, 1);
1099e5ec1e72Spatrick 			m_freem(m);
1100e5ec1e72Spatrick 			break;
1101e5ec1e72Spatrick 		}
1102e5ec1e72Spatrick 		memset(req, 0, sizeof(*req));
1103e5ec1e72Spatrick 		req->msg.msgtype = msgtype;
1104e5ec1e72Spatrick 		req->msg.request_id = htole32(pktid);
11051950c5c5Spatrick 		req->host_buf_len = htole16(MSGBUF_MAX_CTL_PKT_SIZE);
1106e4dae658Spatrick 		req->host_buf_addr.high_addr = htole32((uint64_t)paddr >> 32);
1107e5ec1e72Spatrick 		req->host_buf_addr.low_addr = htole32(paddr & 0xffffffff);
1108e5ec1e72Spatrick 		bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit);
1109e5ec1e72Spatrick 	}
1110e5ec1e72Spatrick 	if_rxr_put(rxring, slots);
1111e5ec1e72Spatrick 	splx(s);
1112e5ec1e72Spatrick }
1113e5ec1e72Spatrick 
1114e5ec1e72Spatrick void
1115e5ec1e72Spatrick bwfm_pci_fill_rx_buf_ring(struct bwfm_pci_softc *sc)
1116e5ec1e72Spatrick {
1117e5ec1e72Spatrick 	struct msgbuf_rx_bufpost *req;
1118e5ec1e72Spatrick 	struct mbuf *m;
1119e5ec1e72Spatrick 	uint32_t pktid;
1120e5ec1e72Spatrick 	paddr_t paddr;
1121e5ec1e72Spatrick 	int s, slots;
1122e5ec1e72Spatrick 
1123e5ec1e72Spatrick 	s = splnet();
1124e5ec1e72Spatrick 	for (slots = if_rxr_get(&sc->sc_rxbuf_ring, sc->sc_max_rxbufpost);
1125e5ec1e72Spatrick 	    slots > 0; slots--) {
112602ee7d07Spatrick 		if (bwfm_pci_pktid_avail(sc, &sc->sc_rx_pkts))
112702ee7d07Spatrick 			break;
1128e5ec1e72Spatrick 		req = bwfm_pci_ring_write_reserve(sc, &sc->sc_rxpost_submit);
1129e5ec1e72Spatrick 		if (req == NULL)
1130e5ec1e72Spatrick 			break;
1131471f2571Sjan 		m = MCLGETL(NULL, M_DONTWAIT, MSGBUF_MAX_PKT_SIZE);
1132e5ec1e72Spatrick 		if (m == NULL) {
1133e5ec1e72Spatrick 			bwfm_pci_ring_write_cancel(sc, &sc->sc_rxpost_submit, 1);
1134e5ec1e72Spatrick 			break;
1135e5ec1e72Spatrick 		}
1136e5ec1e72Spatrick 		m->m_len = m->m_pkthdr.len = MSGBUF_MAX_PKT_SIZE;
1137e5ec1e72Spatrick 		if (bwfm_pci_pktid_new(sc, &sc->sc_rx_pkts, m, &pktid, &paddr)) {
1138e5ec1e72Spatrick 			bwfm_pci_ring_write_cancel(sc, &sc->sc_rxpost_submit, 1);
1139e5ec1e72Spatrick 			m_freem(m);
1140e5ec1e72Spatrick 			break;
1141e5ec1e72Spatrick 		}
1142e5ec1e72Spatrick 		memset(req, 0, sizeof(*req));
1143e5ec1e72Spatrick 		req->msg.msgtype = MSGBUF_TYPE_RXBUF_POST;
1144e5ec1e72Spatrick 		req->msg.request_id = htole32(pktid);
1145e5ec1e72Spatrick 		req->data_buf_len = htole16(MSGBUF_MAX_PKT_SIZE);
1146e4dae658Spatrick 		req->data_buf_addr.high_addr = htole32((uint64_t)paddr >> 32);
1147e5ec1e72Spatrick 		req->data_buf_addr.low_addr = htole32(paddr & 0xffffffff);
1148e5ec1e72Spatrick 		bwfm_pci_ring_write_commit(sc, &sc->sc_rxpost_submit);
1149e5ec1e72Spatrick 	}
1150e5ec1e72Spatrick 	if_rxr_put(&sc->sc_rxbuf_ring, slots);
1151e5ec1e72Spatrick 	splx(s);
1152e5ec1e72Spatrick }
1153e5ec1e72Spatrick 
1154e5ec1e72Spatrick int
1155e5ec1e72Spatrick bwfm_pci_setup_ring(struct bwfm_pci_softc *sc, struct bwfm_pci_msgring *ring,
1156e5ec1e72Spatrick     int nitem, size_t itemsz, uint32_t w_idx, uint32_t r_idx,
1157e5ec1e72Spatrick     int idx, uint32_t idx_off, uint32_t *ring_mem)
1158e5ec1e72Spatrick {
1159e5ec1e72Spatrick 	ring->w_idx_addr = w_idx + idx * idx_off;
1160e5ec1e72Spatrick 	ring->r_idx_addr = r_idx + idx * idx_off;
1161*13f544a8Spatrick 	ring->w_ptr = 0;
1162*13f544a8Spatrick 	ring->r_ptr = 0;
1163e5ec1e72Spatrick 	ring->nitem = nitem;
1164e5ec1e72Spatrick 	ring->itemsz = itemsz;
1165e5ec1e72Spatrick 	bwfm_pci_ring_write_rptr(sc, ring);
1166e5ec1e72Spatrick 	bwfm_pci_ring_write_wptr(sc, ring);
1167e5ec1e72Spatrick 
1168e5ec1e72Spatrick 	ring->ring = bwfm_pci_dmamem_alloc(sc, nitem * itemsz, 8);
1169e5ec1e72Spatrick 	if (ring->ring == NULL)
1170e5ec1e72Spatrick 		return ENOMEM;
1171e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1172e5ec1e72Spatrick 	    *ring_mem + BWFM_RING_MEM_BASE_ADDR_LOW,
1173e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(ring->ring) & 0xffffffff);
1174e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1175e5ec1e72Spatrick 	    *ring_mem + BWFM_RING_MEM_BASE_ADDR_HIGH,
1176e5ec1e72Spatrick 	    BWFM_PCI_DMA_DVA(ring->ring) >> 32);
1177e5ec1e72Spatrick 	bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1178e5ec1e72Spatrick 	    *ring_mem + BWFM_RING_MAX_ITEM, nitem);
1179e5ec1e72Spatrick 	bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1180e5ec1e72Spatrick 	    *ring_mem + BWFM_RING_LEN_ITEMS, itemsz);
1181e5ec1e72Spatrick 	*ring_mem = *ring_mem + BWFM_RING_MEM_SZ;
1182e5ec1e72Spatrick 	return 0;
1183e5ec1e72Spatrick }
1184e5ec1e72Spatrick 
1185518be5f3Spatrick int
1186518be5f3Spatrick bwfm_pci_setup_flowring(struct bwfm_pci_softc *sc, struct bwfm_pci_msgring *ring,
1187518be5f3Spatrick     int nitem, size_t itemsz)
1188518be5f3Spatrick {
1189518be5f3Spatrick 	ring->w_ptr = 0;
1190518be5f3Spatrick 	ring->r_ptr = 0;
1191518be5f3Spatrick 	ring->nitem = nitem;
1192518be5f3Spatrick 	ring->itemsz = itemsz;
1193518be5f3Spatrick 	bwfm_pci_ring_write_rptr(sc, ring);
1194518be5f3Spatrick 	bwfm_pci_ring_write_wptr(sc, ring);
1195518be5f3Spatrick 
1196518be5f3Spatrick 	ring->ring = bwfm_pci_dmamem_alloc(sc, nitem * itemsz, 8);
1197518be5f3Spatrick 	if (ring->ring == NULL)
1198518be5f3Spatrick 		return ENOMEM;
1199518be5f3Spatrick 	return 0;
1200518be5f3Spatrick }
1201518be5f3Spatrick 
1202e5ec1e72Spatrick /* Ring helpers */
1203e5ec1e72Spatrick void
1204e5ec1e72Spatrick bwfm_pci_ring_bell(struct bwfm_pci_softc *sc,
1205e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1206e5ec1e72Spatrick {
1207bb813cf8Spatrick 	struct bwfm_softc *bwfm = (void *)sc;
1208bb813cf8Spatrick 
1209bb813cf8Spatrick 	if (bwfm->sc_chip.ch_chip == BRCM_CC_4378_CHIP_ID)
1210bb813cf8Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1211bb813cf8Spatrick 		    BWFM_PCI_64_PCIE2REG_H2D_MAILBOX_0, 1);
1212bb813cf8Spatrick 	else
1213e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1214156d2677Spatrick 		    BWFM_PCI_PCIE2REG_H2D_MAILBOX_0, 1);
1215e5ec1e72Spatrick }
1216e5ec1e72Spatrick 
1217e5ec1e72Spatrick void
1218e5ec1e72Spatrick bwfm_pci_ring_update_rptr(struct bwfm_pci_softc *sc,
1219e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1220e5ec1e72Spatrick {
1221e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
1222e5ec1e72Spatrick 		ring->r_ptr = bus_space_read_2(sc->sc_tcm_iot,
1223e5ec1e72Spatrick 		    sc->sc_tcm_ioh, ring->r_idx_addr);
1224e5ec1e72Spatrick 	} else {
1225dcb67343Spatrick 		bus_dmamap_sync(sc->sc_dmat,
1226dcb67343Spatrick 		    BWFM_PCI_DMA_MAP(sc->sc_dma_idx_buf), ring->r_idx_addr,
1227dcb67343Spatrick 		    sizeof(uint16_t), BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1228e5ec1e72Spatrick 		ring->r_ptr = *(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf)
1229e5ec1e72Spatrick 		    + ring->r_idx_addr);
1230e5ec1e72Spatrick 	}
1231e5ec1e72Spatrick }
1232e5ec1e72Spatrick 
1233e5ec1e72Spatrick void
1234e5ec1e72Spatrick bwfm_pci_ring_update_wptr(struct bwfm_pci_softc *sc,
1235e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1236e5ec1e72Spatrick {
1237e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
1238e5ec1e72Spatrick 		ring->w_ptr = bus_space_read_2(sc->sc_tcm_iot,
1239e5ec1e72Spatrick 		    sc->sc_tcm_ioh, ring->w_idx_addr);
1240e5ec1e72Spatrick 	} else {
1241dcb67343Spatrick 		bus_dmamap_sync(sc->sc_dmat,
1242dcb67343Spatrick 		    BWFM_PCI_DMA_MAP(sc->sc_dma_idx_buf), ring->w_idx_addr,
1243dcb67343Spatrick 		    sizeof(uint16_t), BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1244e5ec1e72Spatrick 		ring->w_ptr = *(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf)
1245e5ec1e72Spatrick 		    + ring->w_idx_addr);
1246e5ec1e72Spatrick 	}
1247e5ec1e72Spatrick }
1248e5ec1e72Spatrick 
1249e5ec1e72Spatrick void
1250e5ec1e72Spatrick bwfm_pci_ring_write_rptr(struct bwfm_pci_softc *sc,
1251e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1252e5ec1e72Spatrick {
1253e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
1254e5ec1e72Spatrick 		bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1255e5ec1e72Spatrick 		    ring->r_idx_addr, ring->r_ptr);
1256e5ec1e72Spatrick 	} else {
1257e5ec1e72Spatrick 		*(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf)
1258e5ec1e72Spatrick 		    + ring->r_idx_addr) = ring->r_ptr;
1259dcb67343Spatrick 		bus_dmamap_sync(sc->sc_dmat,
1260dcb67343Spatrick 		    BWFM_PCI_DMA_MAP(sc->sc_dma_idx_buf), ring->r_idx_addr,
1261dcb67343Spatrick 		    sizeof(uint16_t), BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1262e5ec1e72Spatrick 	}
1263e5ec1e72Spatrick }
1264e5ec1e72Spatrick 
1265e5ec1e72Spatrick void
1266e5ec1e72Spatrick bwfm_pci_ring_write_wptr(struct bwfm_pci_softc *sc,
1267e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1268e5ec1e72Spatrick {
1269e5ec1e72Spatrick 	if (sc->sc_dma_idx_sz == 0) {
1270e5ec1e72Spatrick 		bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1271e5ec1e72Spatrick 		    ring->w_idx_addr, ring->w_ptr);
1272e5ec1e72Spatrick 	} else {
1273e5ec1e72Spatrick 		*(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf)
1274e5ec1e72Spatrick 		    + ring->w_idx_addr) = ring->w_ptr;
1275dcb67343Spatrick 		bus_dmamap_sync(sc->sc_dmat,
1276dcb67343Spatrick 		    BWFM_PCI_DMA_MAP(sc->sc_dma_idx_buf), ring->w_idx_addr,
1277dcb67343Spatrick 		    sizeof(uint16_t), BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1278e5ec1e72Spatrick 	}
1279e5ec1e72Spatrick }
1280e5ec1e72Spatrick 
1281e5ec1e72Spatrick /*
1282e5ec1e72Spatrick  * Retrieve a free descriptor to put new stuff in, but don't commit
1283e5ec1e72Spatrick  * to it yet so we can rollback later if any error occurs.
1284e5ec1e72Spatrick  */
1285e5ec1e72Spatrick void *
1286e5ec1e72Spatrick bwfm_pci_ring_write_reserve(struct bwfm_pci_softc *sc,
1287e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1288e5ec1e72Spatrick {
1289e5ec1e72Spatrick 	int available;
1290e5ec1e72Spatrick 	char *ret;
1291e5ec1e72Spatrick 
1292e5ec1e72Spatrick 	bwfm_pci_ring_update_rptr(sc, ring);
1293e5ec1e72Spatrick 
1294e5ec1e72Spatrick 	if (ring->r_ptr > ring->w_ptr)
1295e5ec1e72Spatrick 		available = ring->r_ptr - ring->w_ptr;
1296e5ec1e72Spatrick 	else
1297e5ec1e72Spatrick 		available = ring->r_ptr + (ring->nitem - ring->w_ptr);
1298e5ec1e72Spatrick 
129930f5ada0Spatrick 	if (available <= 1)
1300e5ec1e72Spatrick 		return NULL;
1301e5ec1e72Spatrick 
1302e5ec1e72Spatrick 	ret = BWFM_PCI_DMA_KVA(ring->ring) + (ring->w_ptr * ring->itemsz);
1303e5ec1e72Spatrick 	ring->w_ptr += 1;
1304e5ec1e72Spatrick 	if (ring->w_ptr == ring->nitem)
1305e5ec1e72Spatrick 		ring->w_ptr = 0;
1306e5ec1e72Spatrick 	return ret;
1307e5ec1e72Spatrick }
1308e5ec1e72Spatrick 
1309e5ec1e72Spatrick void *
1310e5ec1e72Spatrick bwfm_pci_ring_write_reserve_multi(struct bwfm_pci_softc *sc,
1311e5ec1e72Spatrick     struct bwfm_pci_msgring *ring, int count, int *avail)
1312e5ec1e72Spatrick {
1313e5ec1e72Spatrick 	int available;
1314e5ec1e72Spatrick 	char *ret;
1315e5ec1e72Spatrick 
1316e5ec1e72Spatrick 	bwfm_pci_ring_update_rptr(sc, ring);
1317e5ec1e72Spatrick 
1318e5ec1e72Spatrick 	if (ring->r_ptr > ring->w_ptr)
1319e5ec1e72Spatrick 		available = ring->r_ptr - ring->w_ptr;
1320e5ec1e72Spatrick 	else
1321e5ec1e72Spatrick 		available = ring->r_ptr + (ring->nitem - ring->w_ptr);
1322e5ec1e72Spatrick 
132330f5ada0Spatrick 	if (available <= 1)
1324e5ec1e72Spatrick 		return NULL;
1325e5ec1e72Spatrick 
1326e5ec1e72Spatrick 	ret = BWFM_PCI_DMA_KVA(ring->ring) + (ring->w_ptr * ring->itemsz);
1327e5ec1e72Spatrick 	*avail = min(count, available - 1);
1328e5ec1e72Spatrick 	if (*avail + ring->w_ptr > ring->nitem)
1329e5ec1e72Spatrick 		*avail = ring->nitem - ring->w_ptr;
1330e5ec1e72Spatrick 	ring->w_ptr += *avail;
1331e5ec1e72Spatrick 	if (ring->w_ptr == ring->nitem)
1332e5ec1e72Spatrick 		ring->w_ptr = 0;
1333e5ec1e72Spatrick 	return ret;
1334e5ec1e72Spatrick }
1335e5ec1e72Spatrick 
1336e5ec1e72Spatrick /*
1337e5ec1e72Spatrick  * Read number of descriptors available (submitted by the firmware)
1338e5ec1e72Spatrick  * and retrieve pointer to first descriptor.
1339e5ec1e72Spatrick  */
1340e5ec1e72Spatrick void *
1341e5ec1e72Spatrick bwfm_pci_ring_read_avail(struct bwfm_pci_softc *sc,
1342e5ec1e72Spatrick     struct bwfm_pci_msgring *ring, int *avail)
1343e5ec1e72Spatrick {
1344e5ec1e72Spatrick 	bwfm_pci_ring_update_wptr(sc, ring);
1345e5ec1e72Spatrick 
1346e5ec1e72Spatrick 	if (ring->w_ptr >= ring->r_ptr)
1347e5ec1e72Spatrick 		*avail = ring->w_ptr - ring->r_ptr;
1348e5ec1e72Spatrick 	else
1349e5ec1e72Spatrick 		*avail = ring->nitem - ring->r_ptr;
1350e5ec1e72Spatrick 
1351e5ec1e72Spatrick 	if (*avail == 0)
1352e5ec1e72Spatrick 		return NULL;
1353e5ec1e72Spatrick 
1354dcb67343Spatrick 	bus_dmamap_sync(sc->sc_dmat, BWFM_PCI_DMA_MAP(ring->ring),
1355dcb67343Spatrick 	    ring->r_ptr * ring->itemsz, *avail * ring->itemsz,
1356dcb67343Spatrick 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1357e5ec1e72Spatrick 	return BWFM_PCI_DMA_KVA(ring->ring) + (ring->r_ptr * ring->itemsz);
1358e5ec1e72Spatrick }
1359e5ec1e72Spatrick 
1360e5ec1e72Spatrick /*
1361e5ec1e72Spatrick  * Let firmware know we read N descriptors.
1362e5ec1e72Spatrick  */
1363e5ec1e72Spatrick void
1364e5ec1e72Spatrick bwfm_pci_ring_read_commit(struct bwfm_pci_softc *sc,
1365e5ec1e72Spatrick     struct bwfm_pci_msgring *ring, int nitem)
1366e5ec1e72Spatrick {
1367e5ec1e72Spatrick 	ring->r_ptr += nitem;
1368e5ec1e72Spatrick 	if (ring->r_ptr == ring->nitem)
1369e5ec1e72Spatrick 		ring->r_ptr = 0;
1370e5ec1e72Spatrick 	bwfm_pci_ring_write_rptr(sc, ring);
1371e5ec1e72Spatrick }
1372e5ec1e72Spatrick 
1373e5ec1e72Spatrick /*
1374e5ec1e72Spatrick  * Let firmware know that we submitted some descriptors.
1375e5ec1e72Spatrick  */
1376e5ec1e72Spatrick void
1377e5ec1e72Spatrick bwfm_pci_ring_write_commit(struct bwfm_pci_softc *sc,
1378e5ec1e72Spatrick     struct bwfm_pci_msgring *ring)
1379e5ec1e72Spatrick {
1380dcb67343Spatrick 	bus_dmamap_sync(sc->sc_dmat, BWFM_PCI_DMA_MAP(ring->ring),
1381dcb67343Spatrick 	    0, BWFM_PCI_DMA_LEN(ring->ring), BUS_DMASYNC_PREREAD |
1382dcb67343Spatrick 	    BUS_DMASYNC_PREWRITE);
1383e5ec1e72Spatrick 	bwfm_pci_ring_write_wptr(sc, ring);
1384e5ec1e72Spatrick 	bwfm_pci_ring_bell(sc, ring);
1385e5ec1e72Spatrick }
1386e5ec1e72Spatrick 
1387e5ec1e72Spatrick /*
1388e5ec1e72Spatrick  * Rollback N descriptors in case we don't actually want
1389e5ec1e72Spatrick  * to commit to it.
1390e5ec1e72Spatrick  */
1391e5ec1e72Spatrick void
1392e5ec1e72Spatrick bwfm_pci_ring_write_cancel(struct bwfm_pci_softc *sc,
1393e5ec1e72Spatrick     struct bwfm_pci_msgring *ring, int nitem)
1394e5ec1e72Spatrick {
1395e5ec1e72Spatrick 	if (ring->w_ptr == 0)
1396e5ec1e72Spatrick 		ring->w_ptr = ring->nitem - nitem;
1397e5ec1e72Spatrick 	else
1398e5ec1e72Spatrick 		ring->w_ptr -= nitem;
1399e5ec1e72Spatrick }
1400e5ec1e72Spatrick 
1401e5ec1e72Spatrick /*
1402e5ec1e72Spatrick  * Foreach written descriptor on the ring, pass the descriptor to
1403e5ec1e72Spatrick  * a message handler and let the firmware know we handled it.
1404e5ec1e72Spatrick  */
1405e5ec1e72Spatrick void
14066f241297Spatrick bwfm_pci_ring_rx(struct bwfm_pci_softc *sc, struct bwfm_pci_msgring *ring,
14076f241297Spatrick     struct mbuf_list *ml)
1408e5ec1e72Spatrick {
1409e5ec1e72Spatrick 	void *buf;
1410e5ec1e72Spatrick 	int avail, processed;
1411e5ec1e72Spatrick 
1412e5ec1e72Spatrick again:
1413e5ec1e72Spatrick 	buf = bwfm_pci_ring_read_avail(sc, ring, &avail);
1414e5ec1e72Spatrick 	if (buf == NULL)
1415e5ec1e72Spatrick 		return;
1416e5ec1e72Spatrick 
1417e5ec1e72Spatrick 	processed = 0;
1418e5ec1e72Spatrick 	while (avail) {
14196f241297Spatrick 		bwfm_pci_msg_rx(sc, buf + sc->sc_rx_dataoffset, ml);
1420e5ec1e72Spatrick 		buf += ring->itemsz;
1421e5ec1e72Spatrick 		processed++;
1422e5ec1e72Spatrick 		if (processed == 48) {
1423e5ec1e72Spatrick 			bwfm_pci_ring_read_commit(sc, ring, processed);
1424e5ec1e72Spatrick 			processed = 0;
1425e5ec1e72Spatrick 		}
1426e5ec1e72Spatrick 		avail--;
1427e5ec1e72Spatrick 	}
1428e5ec1e72Spatrick 	if (processed)
1429e5ec1e72Spatrick 		bwfm_pci_ring_read_commit(sc, ring, processed);
1430e5ec1e72Spatrick 	if (ring->r_ptr == 0)
1431e5ec1e72Spatrick 		goto again;
1432e5ec1e72Spatrick }
1433e5ec1e72Spatrick 
1434e5ec1e72Spatrick void
14356f241297Spatrick bwfm_pci_msg_rx(struct bwfm_pci_softc *sc, void *buf, struct mbuf_list *ml)
1436e5ec1e72Spatrick {
1437518be5f3Spatrick 	struct ifnet *ifp = &sc->sc_sc.sc_ic.ic_if;
1438e5ec1e72Spatrick 	struct msgbuf_ioctl_resp_hdr *resp;
1439518be5f3Spatrick 	struct msgbuf_tx_status *tx;
144018722113Spatrick 	struct msgbuf_rx_complete *rx;
1441e5ec1e72Spatrick 	struct msgbuf_rx_event *event;
1442e5ec1e72Spatrick 	struct msgbuf_common_hdr *msg;
1443518be5f3Spatrick 	struct msgbuf_flowring_create_resp *fcr;
1444a2c6ff8bSpatrick 	struct msgbuf_flowring_delete_resp *fdr;
1445518be5f3Spatrick 	struct bwfm_pci_msgring *ring;
1446e5ec1e72Spatrick 	struct mbuf *m;
1447518be5f3Spatrick 	int flowid;
1448e5ec1e72Spatrick 
1449e5ec1e72Spatrick 	msg = (struct msgbuf_common_hdr *)buf;
1450e5ec1e72Spatrick 	switch (msg->msgtype)
1451e5ec1e72Spatrick 	{
1452518be5f3Spatrick 	case MSGBUF_TYPE_FLOW_RING_CREATE_CMPLT:
1453518be5f3Spatrick 		fcr = (struct msgbuf_flowring_create_resp *)buf;
1454518be5f3Spatrick 		flowid = letoh16(fcr->compl_hdr.flow_ring_id);
1455518be5f3Spatrick 		if (flowid < 2)
1456518be5f3Spatrick 			break;
1457518be5f3Spatrick 		flowid -= 2;
1458518be5f3Spatrick 		if (flowid >= sc->sc_max_flowrings)
1459518be5f3Spatrick 			break;
1460518be5f3Spatrick 		ring = &sc->sc_flowrings[flowid];
1461518be5f3Spatrick 		if (ring->status != RING_OPENING)
1462518be5f3Spatrick 			break;
1463518be5f3Spatrick 		if (fcr->compl_hdr.status) {
1464518be5f3Spatrick 			printf("%s: failed to open flowring %d\n",
1465518be5f3Spatrick 			    DEVNAME(sc), flowid);
1466518be5f3Spatrick 			ring->status = RING_CLOSED;
146702ee7d07Spatrick 			if (ring->m) {
146802ee7d07Spatrick 				m_freem(ring->m);
146902ee7d07Spatrick 				ring->m = NULL;
147002ee7d07Spatrick 			}
1471518be5f3Spatrick 			ifq_restart(&ifp->if_snd);
1472518be5f3Spatrick 			break;
1473518be5f3Spatrick 		}
1474518be5f3Spatrick 		ring->status = RING_OPEN;
147502ee7d07Spatrick 		if (ring->m != NULL) {
147602ee7d07Spatrick 			m = ring->m;
147702ee7d07Spatrick 			ring->m = NULL;
147802ee7d07Spatrick 			if (bwfm_pci_txdata(&sc->sc_sc, m))
147902ee7d07Spatrick 				m_freem(ring->m);
148002ee7d07Spatrick 		}
1481518be5f3Spatrick 		ifq_restart(&ifp->if_snd);
1482518be5f3Spatrick 		break;
1483a2c6ff8bSpatrick 	case MSGBUF_TYPE_FLOW_RING_DELETE_CMPLT:
1484a2c6ff8bSpatrick 		fdr = (struct msgbuf_flowring_delete_resp *)buf;
1485a2c6ff8bSpatrick 		flowid = letoh16(fdr->compl_hdr.flow_ring_id);
1486a2c6ff8bSpatrick 		if (flowid < 2)
1487a2c6ff8bSpatrick 			break;
1488a2c6ff8bSpatrick 		flowid -= 2;
1489a2c6ff8bSpatrick 		if (flowid >= sc->sc_max_flowrings)
1490a2c6ff8bSpatrick 			break;
1491a2c6ff8bSpatrick 		ring = &sc->sc_flowrings[flowid];
1492a2c6ff8bSpatrick 		if (ring->status != RING_CLOSING)
1493a2c6ff8bSpatrick 			break;
1494a2c6ff8bSpatrick 		if (fdr->compl_hdr.status) {
1495a2c6ff8bSpatrick 			printf("%s: failed to delete flowring %d\n",
1496a2c6ff8bSpatrick 			    DEVNAME(sc), flowid);
1497a2c6ff8bSpatrick 			break;
1498a2c6ff8bSpatrick 		}
1499a2c6ff8bSpatrick 		bwfm_pci_dmamem_free(sc, ring->ring);
1500a2c6ff8bSpatrick 		ring->status = RING_CLOSED;
1501a2c6ff8bSpatrick 		break;
1502e5ec1e72Spatrick 	case MSGBUF_TYPE_IOCTLPTR_REQ_ACK:
15032eeba925Spatrick 		m = bwfm_pci_pktid_free(sc, &sc->sc_ioctl_pkts,
15042eeba925Spatrick 		    letoh32(msg->request_id));
15052eeba925Spatrick 		if (m == NULL)
15062eeba925Spatrick 			break;
15072eeba925Spatrick 		m_freem(m);
1508e5ec1e72Spatrick 		break;
1509e5ec1e72Spatrick 	case MSGBUF_TYPE_IOCTL_CMPLT:
1510e5ec1e72Spatrick 		resp = (struct msgbuf_ioctl_resp_hdr *)buf;
15112eeba925Spatrick 		bwfm_pci_msgbuf_rxioctl(sc, resp);
1512e5ec1e72Spatrick 		if_rxr_put(&sc->sc_ioctl_ring, 1);
1513e5ec1e72Spatrick 		bwfm_pci_fill_rx_rings(sc);
1514e5ec1e72Spatrick 		break;
1515e5ec1e72Spatrick 	case MSGBUF_TYPE_WL_EVENT:
1516e5ec1e72Spatrick 		event = (struct msgbuf_rx_event *)buf;
1517e5ec1e72Spatrick 		m = bwfm_pci_pktid_free(sc, &sc->sc_rx_pkts,
1518e5ec1e72Spatrick 		    letoh32(event->msg.request_id));
1519e5ec1e72Spatrick 		if (m == NULL)
1520e5ec1e72Spatrick 			break;
1521e5ec1e72Spatrick 		m_adj(m, sc->sc_rx_dataoffset);
1522f37fc236Spatrick 		m->m_len = m->m_pkthdr.len = letoh16(event->event_data_len);
15236f241297Spatrick 		bwfm_rx(&sc->sc_sc, m, ml);
1524e5ec1e72Spatrick 		if_rxr_put(&sc->sc_event_ring, 1);
1525e5ec1e72Spatrick 		bwfm_pci_fill_rx_rings(sc);
1526e5ec1e72Spatrick 		break;
1527518be5f3Spatrick 	case MSGBUF_TYPE_TX_STATUS:
1528518be5f3Spatrick 		tx = (struct msgbuf_tx_status *)buf;
1529518be5f3Spatrick 		m = bwfm_pci_pktid_free(sc, &sc->sc_tx_pkts,
1530f9ee104fSpatrick 		    letoh32(tx->msg.request_id) - 1);
1531518be5f3Spatrick 		if (m == NULL)
1532518be5f3Spatrick 			break;
1533518be5f3Spatrick 		m_freem(m);
1534c6f1636dSpatrick 		if (sc->sc_tx_pkts_full) {
1535c6f1636dSpatrick 			sc->sc_tx_pkts_full = 0;
1536c6f1636dSpatrick 			ifq_restart(&ifp->if_snd);
1537c6f1636dSpatrick 		}
1538518be5f3Spatrick 		break;
153918722113Spatrick 	case MSGBUF_TYPE_RX_CMPLT:
154018722113Spatrick 		rx = (struct msgbuf_rx_complete *)buf;
154118722113Spatrick 		m = bwfm_pci_pktid_free(sc, &sc->sc_rx_pkts,
154218722113Spatrick 		    letoh32(rx->msg.request_id));
154318722113Spatrick 		if (m == NULL)
154418722113Spatrick 			break;
154518722113Spatrick 		if (letoh16(rx->data_offset))
154618722113Spatrick 			m_adj(m, letoh16(rx->data_offset));
154718722113Spatrick 		else if (sc->sc_rx_dataoffset)
154818722113Spatrick 			m_adj(m, sc->sc_rx_dataoffset);
1549f37fc236Spatrick 		m->m_len = m->m_pkthdr.len = letoh16(rx->data_len);
15506f241297Spatrick 		bwfm_rx(&sc->sc_sc, m, ml);
155118722113Spatrick 		if_rxr_put(&sc->sc_rxbuf_ring, 1);
155218722113Spatrick 		bwfm_pci_fill_rx_rings(sc);
155318722113Spatrick 		break;
1554e5ec1e72Spatrick 	default:
1555e5ec1e72Spatrick 		printf("%s: msgtype 0x%08x\n", __func__, msg->msgtype);
1556e5ec1e72Spatrick 		break;
1557e5ec1e72Spatrick 	}
1558e5ec1e72Spatrick }
1559e5ec1e72Spatrick 
1560e5ec1e72Spatrick /* Bus core helpers */
1561e5ec1e72Spatrick void
1562e5ec1e72Spatrick bwfm_pci_select_core(struct bwfm_pci_softc *sc, int id)
1563e5ec1e72Spatrick {
1564e5ec1e72Spatrick 	struct bwfm_softc *bwfm = (void *)sc;
1565e5ec1e72Spatrick 	struct bwfm_core *core;
1566e5ec1e72Spatrick 
1567e5ec1e72Spatrick 	core = bwfm_chip_get_core(bwfm, id);
1568e5ec1e72Spatrick 	if (core == NULL) {
1569e5ec1e72Spatrick 		printf("%s: could not find core to select", DEVNAME(sc));
1570e5ec1e72Spatrick 		return;
1571e5ec1e72Spatrick 	}
1572e5ec1e72Spatrick 
1573e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag,
1574e5ec1e72Spatrick 	    BWFM_PCI_BAR0_WINDOW, core->co_base);
1575e5ec1e72Spatrick 	if (pci_conf_read(sc->sc_pc, sc->sc_tag,
1576e5ec1e72Spatrick 	    BWFM_PCI_BAR0_WINDOW) != core->co_base)
1577e5ec1e72Spatrick 		pci_conf_write(sc->sc_pc, sc->sc_tag,
1578e5ec1e72Spatrick 		    BWFM_PCI_BAR0_WINDOW, core->co_base);
1579e5ec1e72Spatrick }
1580e5ec1e72Spatrick 
1581e5ec1e72Spatrick uint32_t
1582e5ec1e72Spatrick bwfm_pci_buscore_read(struct bwfm_softc *bwfm, uint32_t reg)
1583e5ec1e72Spatrick {
1584e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1585e5ec1e72Spatrick 	uint32_t page, offset;
1586e5ec1e72Spatrick 
1587e5ec1e72Spatrick 	page = reg & ~(BWFM_PCI_BAR0_REG_SIZE - 1);
1588e5ec1e72Spatrick 	offset = reg & (BWFM_PCI_BAR0_REG_SIZE - 1);
1589e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_BAR0_WINDOW, page);
1590e5ec1e72Spatrick 	return bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh, offset);
1591e5ec1e72Spatrick }
1592e5ec1e72Spatrick 
1593e5ec1e72Spatrick void
1594e5ec1e72Spatrick bwfm_pci_buscore_write(struct bwfm_softc *bwfm, uint32_t reg, uint32_t val)
1595e5ec1e72Spatrick {
1596e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1597e5ec1e72Spatrick 	uint32_t page, offset;
1598e5ec1e72Spatrick 
1599e5ec1e72Spatrick 	page = reg & ~(BWFM_PCI_BAR0_REG_SIZE - 1);
1600e5ec1e72Spatrick 	offset = reg & (BWFM_PCI_BAR0_REG_SIZE - 1);
1601e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_BAR0_WINDOW, page);
1602e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, offset, val);
1603e5ec1e72Spatrick }
1604e5ec1e72Spatrick 
1605e5ec1e72Spatrick int
1606e5ec1e72Spatrick bwfm_pci_buscore_prepare(struct bwfm_softc *bwfm)
1607e5ec1e72Spatrick {
1608e5ec1e72Spatrick 	return 0;
1609e5ec1e72Spatrick }
1610e5ec1e72Spatrick 
1611e5ec1e72Spatrick int
1612e5ec1e72Spatrick bwfm_pci_buscore_reset(struct bwfm_softc *bwfm)
1613e5ec1e72Spatrick {
1614e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1615e5ec1e72Spatrick 	struct bwfm_core *core;
1616e5ec1e72Spatrick 	uint32_t reg;
1617e5ec1e72Spatrick 	int i;
1618e5ec1e72Spatrick 
1619e5ec1e72Spatrick 	bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2);
1620e5ec1e72Spatrick 	reg = pci_conf_read(sc->sc_pc, sc->sc_tag,
1621e5ec1e72Spatrick 	    BWFM_PCI_CFGREG_LINK_STATUS_CTRL);
1622e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_CFGREG_LINK_STATUS_CTRL,
1623e5ec1e72Spatrick 	    reg & ~BWFM_PCI_CFGREG_LINK_STATUS_CTRL_ASPM_ENAB);
1624e5ec1e72Spatrick 
1625e5ec1e72Spatrick 	bwfm_pci_select_core(sc, BWFM_AGENT_CORE_CHIPCOMMON);
1626e5ec1e72Spatrick 	bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1627e5ec1e72Spatrick 	    BWFM_CHIP_REG_WATCHDOG, 4);
1628e5ec1e72Spatrick 	delay(100 * 1000);
1629e5ec1e72Spatrick 
1630e5ec1e72Spatrick 	bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2);
1631e5ec1e72Spatrick 	pci_conf_write(sc->sc_pc, sc->sc_tag,
1632e5ec1e72Spatrick 	    BWFM_PCI_CFGREG_LINK_STATUS_CTRL, reg);
1633e5ec1e72Spatrick 
1634e5ec1e72Spatrick 	core = bwfm_chip_get_core(bwfm, BWFM_AGENT_CORE_PCIE2);
1635e5ec1e72Spatrick 	if (core->co_rev <= 13) {
1636e5ec1e72Spatrick 		uint16_t cfg_offset[] = {
1637e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_STATUS_CMD,
1638e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_PM_CSR,
1639e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_MSI_CAP,
1640e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_MSI_ADDR_L,
1641e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_MSI_ADDR_H,
1642e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_MSI_DATA,
1643e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_LINK_STATUS_CTRL2,
1644e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_RBAR_CTRL,
1645e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_PML1_SUB_CTRL1,
1646e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_REG_BAR2_CONFIG,
1647e5ec1e72Spatrick 		    BWFM_PCI_CFGREG_REG_BAR3_CONFIG,
1648e5ec1e72Spatrick 		};
1649e5ec1e72Spatrick 
1650e5ec1e72Spatrick 		for (i = 0; i < nitems(cfg_offset); i++) {
1651e5ec1e72Spatrick 			bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1652e5ec1e72Spatrick 			    BWFM_PCI_PCIE2REG_CONFIGADDR, cfg_offset[i]);
1653e5ec1e72Spatrick 			reg = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1654e5ec1e72Spatrick 			    BWFM_PCI_PCIE2REG_CONFIGDATA);
1655e5ec1e72Spatrick 			DPRINTFN(3, ("%s: config offset 0x%04x, value 0x%04x\n",
1656e5ec1e72Spatrick 			    DEVNAME(sc), cfg_offset[i], reg));
1657e5ec1e72Spatrick 			bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1658e5ec1e72Spatrick 			    BWFM_PCI_PCIE2REG_CONFIGDATA, reg);
1659e5ec1e72Spatrick 		}
1660e5ec1e72Spatrick 	}
1661e5ec1e72Spatrick 
1662bb813cf8Spatrick 	reg = bwfm_pci_intr_status(sc);
1663e5ec1e72Spatrick 	if (reg != 0xffffffff)
1664bb813cf8Spatrick 		bwfm_pci_intr_ack(sc, reg);
1665e5ec1e72Spatrick 
1666e5ec1e72Spatrick 	return 0;
1667e5ec1e72Spatrick }
1668e5ec1e72Spatrick 
1669e5ec1e72Spatrick void
1670e5ec1e72Spatrick bwfm_pci_buscore_activate(struct bwfm_softc *bwfm, uint32_t rstvec)
1671e5ec1e72Spatrick {
1672e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1673e5ec1e72Spatrick 	bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 0, rstvec);
1674e5ec1e72Spatrick }
1675e5ec1e72Spatrick 
1676f67437f3Spatrick static int bwfm_pci_prio2fifo[8] = {
16779e2c067eSpatrick 	0, /* best effort */
16789e2c067eSpatrick 	1, /* IPTOS_PREC_IMMEDIATE */
16799e2c067eSpatrick 	1, /* IPTOS_PREC_PRIORITY */
16809e2c067eSpatrick 	0, /* IPTOS_PREC_FLASH */
1681f67437f3Spatrick 	2, /* IPTOS_PREC_FLASHOVERRIDE */
1682f67437f3Spatrick 	2, /* IPTOS_PREC_CRITIC_ECP */
1683f67437f3Spatrick 	3, /* IPTOS_PREC_INTERNETCONTROL */
1684f67437f3Spatrick 	3, /* IPTOS_PREC_NETCONTROL */
1685f67437f3Spatrick };
1686f67437f3Spatrick 
1687f67437f3Spatrick int
1688f67437f3Spatrick bwfm_pci_flowring_lookup(struct bwfm_pci_softc *sc, struct mbuf *m)
1689518be5f3Spatrick {
1690f67437f3Spatrick 	struct ieee80211com *ic = &sc->sc_sc.sc_ic;
1691e6abcda3Smlarkin #ifndef IEEE80211_STA_ONLY
1692f67437f3Spatrick 	uint8_t *da = mtod(m, uint8_t *);
1693e6abcda3Smlarkin #endif
1694f67437f3Spatrick 	int flowid, prio, fifo;
1695f67437f3Spatrick 	int i, found;
1696f67437f3Spatrick 
1697f67437f3Spatrick 	prio = ieee80211_classify(ic, m);
1698f67437f3Spatrick 	fifo = bwfm_pci_prio2fifo[prio];
1699f67437f3Spatrick 
1700f67437f3Spatrick 	switch (ic->ic_opmode)
1701f67437f3Spatrick 	{
1702f67437f3Spatrick 	case IEEE80211_M_STA:
1703f67437f3Spatrick 		flowid = fifo;
1704f67437f3Spatrick 		break;
1705f67437f3Spatrick #ifndef IEEE80211_STA_ONLY
1706f67437f3Spatrick 	case IEEE80211_M_HOSTAP:
17072b7bea7eSpatrick 		if (ETHER_IS_MULTICAST(da))
17082b7bea7eSpatrick 			da = etherbroadcastaddr;
1709f67437f3Spatrick 		flowid = da[5] * 2 + fifo;
1710f67437f3Spatrick 		break;
1711f67437f3Spatrick #endif
1712f67437f3Spatrick 	default:
1713f67437f3Spatrick 		printf("%s: state not supported\n", DEVNAME(sc));
1714f67437f3Spatrick 		return ENOBUFS;
1715f67437f3Spatrick 	}
1716f67437f3Spatrick 
1717f67437f3Spatrick 	found = 0;
1718f67437f3Spatrick 	flowid = flowid % sc->sc_max_flowrings;
1719f67437f3Spatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
1720f67437f3Spatrick 		if (ic->ic_opmode == IEEE80211_M_STA &&
1721f67437f3Spatrick 		    sc->sc_flowrings[flowid].status >= RING_OPEN &&
1722f67437f3Spatrick 		    sc->sc_flowrings[flowid].fifo == fifo) {
1723f67437f3Spatrick 			found = 1;
1724f67437f3Spatrick 			break;
1725f67437f3Spatrick 		}
1726f67437f3Spatrick #ifndef IEEE80211_STA_ONLY
1727f67437f3Spatrick 		if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
1728f67437f3Spatrick 		    sc->sc_flowrings[flowid].status >= RING_OPEN &&
1729f67437f3Spatrick 		    sc->sc_flowrings[flowid].fifo == fifo &&
1730a2c6ff8bSpatrick 		    !memcmp(sc->sc_flowrings[flowid].mac, da, ETHER_ADDR_LEN)) {
1731f67437f3Spatrick 			found = 1;
1732f67437f3Spatrick 			break;
1733f67437f3Spatrick 		}
1734f67437f3Spatrick #endif
1735f67437f3Spatrick 		flowid = (flowid + 1) % sc->sc_max_flowrings;
1736f67437f3Spatrick 	}
1737f67437f3Spatrick 
1738f67437f3Spatrick 	if (found)
1739f67437f3Spatrick 		return flowid;
1740f67437f3Spatrick 
1741f67437f3Spatrick 	return -1;
1742f67437f3Spatrick }
1743f67437f3Spatrick 
1744f67437f3Spatrick void
1745f67437f3Spatrick bwfm_pci_flowring_create(struct bwfm_pci_softc *sc, struct mbuf *m)
1746f67437f3Spatrick {
1747f67437f3Spatrick 	struct ieee80211com *ic = &sc->sc_sc.sc_ic;
1748518be5f3Spatrick 	struct bwfm_cmd_flowring_create cmd;
1749e6abcda3Smlarkin #ifndef IEEE80211_STA_ONLY
1750f67437f3Spatrick 	uint8_t *da = mtod(m, uint8_t *);
1751e6abcda3Smlarkin #endif
175202ee7d07Spatrick 	struct bwfm_pci_msgring *ring;
1753f67437f3Spatrick 	int flowid, prio, fifo;
1754f67437f3Spatrick 	int i, found;
1755f67437f3Spatrick 
1756f67437f3Spatrick 	prio = ieee80211_classify(ic, m);
1757f67437f3Spatrick 	fifo = bwfm_pci_prio2fifo[prio];
1758f67437f3Spatrick 
1759f67437f3Spatrick 	switch (ic->ic_opmode)
1760f67437f3Spatrick 	{
1761f67437f3Spatrick 	case IEEE80211_M_STA:
1762f67437f3Spatrick 		flowid = fifo;
1763f67437f3Spatrick 		break;
1764f67437f3Spatrick #ifndef IEEE80211_STA_ONLY
1765f67437f3Spatrick 	case IEEE80211_M_HOSTAP:
17662b7bea7eSpatrick 		if (ETHER_IS_MULTICAST(da))
17672b7bea7eSpatrick 			da = etherbroadcastaddr;
1768f67437f3Spatrick 		flowid = da[5] * 2 + fifo;
1769f67437f3Spatrick 		break;
1770f67437f3Spatrick #endif
1771f67437f3Spatrick 	default:
1772f67437f3Spatrick 		printf("%s: state not supported\n", DEVNAME(sc));
1773f67437f3Spatrick 		return;
1774f67437f3Spatrick 	}
1775f67437f3Spatrick 
1776f67437f3Spatrick 	found = 0;
1777f67437f3Spatrick 	flowid = flowid % sc->sc_max_flowrings;
1778f67437f3Spatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
177902ee7d07Spatrick 		ring = &sc->sc_flowrings[flowid];
178002ee7d07Spatrick 		if (ring->status == RING_CLOSED) {
178102ee7d07Spatrick 			ring->status = RING_OPENING;
1782f67437f3Spatrick 			found = 1;
1783f67437f3Spatrick 			break;
1784f67437f3Spatrick 		}
1785f67437f3Spatrick 		flowid = (flowid + 1) % sc->sc_max_flowrings;
1786f67437f3Spatrick 	}
1787f67437f3Spatrick 
178802ee7d07Spatrick 	/*
178902ee7d07Spatrick 	 * We cannot recover from that so far.  Only a stop/init
179002ee7d07Spatrick 	 * cycle can revive this if it ever happens at all.
179102ee7d07Spatrick 	 */
1792f67437f3Spatrick 	if (!found) {
1793f67437f3Spatrick 		printf("%s: no flowring available\n", DEVNAME(sc));
1794f67437f3Spatrick 		return;
1795f67437f3Spatrick 	}
1796f67437f3Spatrick 
179702ee7d07Spatrick 	cmd.m = m;
1798f67437f3Spatrick 	cmd.prio = prio;
1799518be5f3Spatrick 	cmd.flowid = flowid;
1800518be5f3Spatrick 	bwfm_do_async(&sc->sc_sc, bwfm_pci_flowring_create_cb, &cmd, sizeof(cmd));
1801518be5f3Spatrick }
1802518be5f3Spatrick 
1803518be5f3Spatrick void
1804518be5f3Spatrick bwfm_pci_flowring_create_cb(struct bwfm_softc *bwfm, void *arg)
1805518be5f3Spatrick {
1806518be5f3Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1807e6abcda3Smlarkin #ifndef IEEE80211_STA_ONLY
18082b7bea7eSpatrick 	struct ieee80211com *ic = &sc->sc_sc.sc_ic;
1809e6abcda3Smlarkin #endif
1810518be5f3Spatrick 	struct bwfm_cmd_flowring_create *cmd = arg;
1811518be5f3Spatrick 	struct msgbuf_tx_flowring_create_req *req;
1812518be5f3Spatrick 	struct bwfm_pci_msgring *ring;
181302ee7d07Spatrick 	uint8_t *da, *sa;
1814e272db29Spatrick 	int s;
1815518be5f3Spatrick 
181602ee7d07Spatrick 	da = mtod(cmd->m, char *) + 0 * ETHER_ADDR_LEN;
181702ee7d07Spatrick 	sa = mtod(cmd->m, char *) + 1 * ETHER_ADDR_LEN;
1818518be5f3Spatrick 
181902ee7d07Spatrick 	ring = &sc->sc_flowrings[cmd->flowid];
182002ee7d07Spatrick 	if (ring->status != RING_OPENING) {
182102ee7d07Spatrick 		printf("%s: flowring not opening\n", DEVNAME(sc));
1822518be5f3Spatrick 		return;
1823f67437f3Spatrick 	}
1824f67437f3Spatrick 
1825f67437f3Spatrick 	if (bwfm_pci_setup_flowring(sc, ring, 512, 48)) {
1826f67437f3Spatrick 		printf("%s: cannot setup flowring\n", DEVNAME(sc));
1827f67437f3Spatrick 		return;
1828f67437f3Spatrick 	}
1829518be5f3Spatrick 
1830e272db29Spatrick 	s = splnet();
1831518be5f3Spatrick 	req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit);
1832f67437f3Spatrick 	if (req == NULL) {
1833f67437f3Spatrick 		printf("%s: cannot reserve for flowring\n", DEVNAME(sc));
1834e272db29Spatrick 		splx(s);
1835518be5f3Spatrick 		return;
1836f67437f3Spatrick 	}
1837518be5f3Spatrick 
1838518be5f3Spatrick 	ring->status = RING_OPENING;
183902ee7d07Spatrick 	ring->fifo = bwfm_pci_prio2fifo[cmd->prio];
184002ee7d07Spatrick 	ring->m = cmd->m;
184102ee7d07Spatrick 	memcpy(ring->mac, da, ETHER_ADDR_LEN);
18422b7bea7eSpatrick #ifndef IEEE80211_STA_ONLY
184302ee7d07Spatrick 	if (ic->ic_opmode == IEEE80211_M_HOSTAP && ETHER_IS_MULTICAST(da))
18442b7bea7eSpatrick 		memcpy(ring->mac, etherbroadcastaddr, ETHER_ADDR_LEN);
18452b7bea7eSpatrick #endif
1846f67437f3Spatrick 
1847518be5f3Spatrick 	req->msg.msgtype = MSGBUF_TYPE_FLOW_RING_CREATE;
1848518be5f3Spatrick 	req->msg.ifidx = 0;
1849518be5f3Spatrick 	req->msg.request_id = 0;
185002ee7d07Spatrick 	req->tid = bwfm_pci_prio2fifo[cmd->prio];
185102ee7d07Spatrick 	req->flow_ring_id = letoh16(cmd->flowid + 2);
185202ee7d07Spatrick 	memcpy(req->da, da, ETHER_ADDR_LEN);
185302ee7d07Spatrick 	memcpy(req->sa, sa, ETHER_ADDR_LEN);
1854518be5f3Spatrick 	req->flow_ring_addr.high_addr =
1855518be5f3Spatrick 	    letoh32(BWFM_PCI_DMA_DVA(ring->ring) >> 32);
1856518be5f3Spatrick 	req->flow_ring_addr.low_addr =
1857518be5f3Spatrick 	    letoh32(BWFM_PCI_DMA_DVA(ring->ring) & 0xffffffff);
1858518be5f3Spatrick 	req->max_items = letoh16(512);
1859518be5f3Spatrick 	req->len_item = letoh16(48);
1860518be5f3Spatrick 
1861518be5f3Spatrick 	bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit);
1862e272db29Spatrick 	splx(s);
1863518be5f3Spatrick }
1864518be5f3Spatrick 
1865a2c6ff8bSpatrick void
1866a2c6ff8bSpatrick bwfm_pci_flowring_delete(struct bwfm_pci_softc *sc, int flowid)
1867a2c6ff8bSpatrick {
1868a2c6ff8bSpatrick 	struct msgbuf_tx_flowring_delete_req *req;
1869a2c6ff8bSpatrick 	struct bwfm_pci_msgring *ring;
1870e272db29Spatrick 	int s;
1871a2c6ff8bSpatrick 
1872a2c6ff8bSpatrick 	ring = &sc->sc_flowrings[flowid];
1873a2c6ff8bSpatrick 	if (ring->status != RING_OPEN) {
1874a2c6ff8bSpatrick 		printf("%s: flowring not open\n", DEVNAME(sc));
1875a2c6ff8bSpatrick 		return;
1876a2c6ff8bSpatrick 	}
1877a2c6ff8bSpatrick 
1878e272db29Spatrick 	s = splnet();
1879a2c6ff8bSpatrick 	req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit);
1880a2c6ff8bSpatrick 	if (req == NULL) {
1881a2c6ff8bSpatrick 		printf("%s: cannot reserve for flowring\n", DEVNAME(sc));
1882e272db29Spatrick 		splx(s);
1883a2c6ff8bSpatrick 		return;
1884a2c6ff8bSpatrick 	}
1885a2c6ff8bSpatrick 
1886a2c6ff8bSpatrick 	ring->status = RING_CLOSING;
1887a2c6ff8bSpatrick 
1888a2c6ff8bSpatrick 	req->msg.msgtype = MSGBUF_TYPE_FLOW_RING_DELETE;
1889a2c6ff8bSpatrick 	req->msg.ifidx = 0;
1890a2c6ff8bSpatrick 	req->msg.request_id = 0;
1891a2c6ff8bSpatrick 	req->flow_ring_id = letoh16(flowid + 2);
1892a2c6ff8bSpatrick 	req->reason = 0;
1893a2c6ff8bSpatrick 
1894a2c6ff8bSpatrick 	bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit);
1895e272db29Spatrick 	splx(s);
1896a2c6ff8bSpatrick }
1897a2c6ff8bSpatrick 
1898a2c6ff8bSpatrick void
1899a2c6ff8bSpatrick bwfm_pci_stop(struct bwfm_softc *bwfm)
1900a2c6ff8bSpatrick {
1901a2c6ff8bSpatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1902a2c6ff8bSpatrick 	struct bwfm_pci_msgring *ring;
1903a2c6ff8bSpatrick 	int i;
1904a2c6ff8bSpatrick 
1905a2c6ff8bSpatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
1906a2c6ff8bSpatrick 		ring = &sc->sc_flowrings[i];
1907a2c6ff8bSpatrick 		if (ring->status == RING_OPEN)
1908a2c6ff8bSpatrick 			bwfm_pci_flowring_delete(sc, i);
1909a2c6ff8bSpatrick 	}
1910a2c6ff8bSpatrick }
1911a2c6ff8bSpatrick 
1912e5ec1e72Spatrick int
191302ee7d07Spatrick bwfm_pci_txcheck(struct bwfm_softc *bwfm)
191402ee7d07Spatrick {
191502ee7d07Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
191602ee7d07Spatrick 	struct bwfm_pci_msgring *ring;
191702ee7d07Spatrick 	int i;
191802ee7d07Spatrick 
191902ee7d07Spatrick 	/* If we are transitioning, we cannot send. */
192002ee7d07Spatrick 	for (i = 0; i < sc->sc_max_flowrings; i++) {
192102ee7d07Spatrick 		ring = &sc->sc_flowrings[i];
192202ee7d07Spatrick 		if (ring->status == RING_OPENING)
192302ee7d07Spatrick 			return ENOBUFS;
192402ee7d07Spatrick 	}
192502ee7d07Spatrick 
192602ee7d07Spatrick 	if (bwfm_pci_pktid_avail(sc, &sc->sc_tx_pkts)) {
192702ee7d07Spatrick 		sc->sc_tx_pkts_full = 1;
192802ee7d07Spatrick 		return ENOBUFS;
192902ee7d07Spatrick 	}
193002ee7d07Spatrick 
193102ee7d07Spatrick 	return 0;
193202ee7d07Spatrick }
193302ee7d07Spatrick 
193402ee7d07Spatrick int
1935e5ec1e72Spatrick bwfm_pci_txdata(struct bwfm_softc *bwfm, struct mbuf *m)
1936e5ec1e72Spatrick {
1937e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
1938518be5f3Spatrick 	struct bwfm_pci_msgring *ring;
1939518be5f3Spatrick 	struct msgbuf_tx_msghdr *tx;
1940518be5f3Spatrick 	uint32_t pktid;
1941518be5f3Spatrick 	paddr_t paddr;
1942518be5f3Spatrick 	int flowid, ret;
1943518be5f3Spatrick 
1944f67437f3Spatrick 	flowid = bwfm_pci_flowring_lookup(sc, m);
1945f67437f3Spatrick 	if (flowid < 0) {
194602ee7d07Spatrick 		/*
194702ee7d07Spatrick 		 * We cannot send the packet right now as there is
194802ee7d07Spatrick 		 * no flowring yet.  The flowring will be created
194902ee7d07Spatrick 		 * asynchronously.  While the ring is transitioning
195002ee7d07Spatrick 		 * the TX check will tell the upper layers that we
195102ee7d07Spatrick 		 * cannot send packets right now.  When the flowring
195202ee7d07Spatrick 		 * is created the queue will be restarted and this
195302ee7d07Spatrick 		 * mbuf will be transmitted.
195402ee7d07Spatrick 		 */
1955f67437f3Spatrick 		bwfm_pci_flowring_create(sc, m);
195602ee7d07Spatrick 		return 0;
1957f67437f3Spatrick 	}
1958518be5f3Spatrick 
1959518be5f3Spatrick 	ring = &sc->sc_flowrings[flowid];
1960518be5f3Spatrick 	if (ring->status == RING_OPENING ||
1961f67437f3Spatrick 	    ring->status == RING_CLOSING) {
1962f67437f3Spatrick 		printf("%s: tried to use a flow that was "
1963f67437f3Spatrick 		    "transitioning in status %d\n",
1964f67437f3Spatrick 		    DEVNAME(sc), ring->status);
1965518be5f3Spatrick 		return ENOBUFS;
1966518be5f3Spatrick 	}
1967518be5f3Spatrick 
1968518be5f3Spatrick 	tx = bwfm_pci_ring_write_reserve(sc, ring);
1969518be5f3Spatrick 	if (tx == NULL)
1970518be5f3Spatrick 		return ENOBUFS;
1971518be5f3Spatrick 
1972518be5f3Spatrick 	memset(tx, 0, sizeof(*tx));
1973518be5f3Spatrick 	tx->msg.msgtype = MSGBUF_TYPE_TX_POST;
1974518be5f3Spatrick 	tx->msg.ifidx = 0;
1975518be5f3Spatrick 	tx->flags = BWFM_MSGBUF_PKT_FLAGS_FRAME_802_3;
1976518be5f3Spatrick 	tx->flags |= ieee80211_classify(&sc->sc_sc.sc_ic, m) <<
1977518be5f3Spatrick 	    BWFM_MSGBUF_PKT_FLAGS_PRIO_SHIFT;
1978518be5f3Spatrick 	tx->seg_cnt = 1;
1979518be5f3Spatrick 	memcpy(tx->txhdr, mtod(m, char *), ETHER_HDR_LEN);
1980518be5f3Spatrick 
1981518be5f3Spatrick 	ret = bwfm_pci_pktid_new(sc, &sc->sc_tx_pkts, m, &pktid, &paddr);
1982518be5f3Spatrick 	if (ret) {
198302ee7d07Spatrick 		if (ret == ENOBUFS) {
198402ee7d07Spatrick 			printf("%s: no pktid available for TX\n",
198502ee7d07Spatrick 			    DEVNAME(sc));
1986c6f1636dSpatrick 			sc->sc_tx_pkts_full = 1;
198702ee7d07Spatrick 		}
1988518be5f3Spatrick 		bwfm_pci_ring_write_cancel(sc, ring, 1);
1989518be5f3Spatrick 		return ret;
1990518be5f3Spatrick 	}
1991518be5f3Spatrick 	paddr += ETHER_HDR_LEN;
1992518be5f3Spatrick 
1993f9ee104fSpatrick 	tx->msg.request_id = htole32(pktid + 1);
19944ff787bcSpatrick 	tx->data_len = htole16(m->m_len - ETHER_HDR_LEN);
1995e4dae658Spatrick 	tx->data_buf_addr.high_addr = htole32((uint64_t)paddr >> 32);
1996518be5f3Spatrick 	tx->data_buf_addr.low_addr = htole32(paddr & 0xffffffff);
1997518be5f3Spatrick 
1998518be5f3Spatrick 	bwfm_pci_ring_write_commit(sc, ring);
1999518be5f3Spatrick 	return 0;
2000e5ec1e72Spatrick }
2001e5ec1e72Spatrick 
2002bbd71b0bSpatrick #ifdef BWFM_DEBUG
2003cadf5fcfSpatrick void
2004cadf5fcfSpatrick bwfm_pci_debug_console(struct bwfm_pci_softc *sc)
2005cadf5fcfSpatrick {
2006cadf5fcfSpatrick 	uint32_t newidx = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
2007cadf5fcfSpatrick 	    sc->sc_console_base_addr + BWFM_CONSOLE_WRITEIDX);
2008cadf5fcfSpatrick 
2009cadf5fcfSpatrick 	if (newidx != sc->sc_console_readidx)
2010bbd71b0bSpatrick 		DPRINTFN(3, ("BWFM CONSOLE: "));
2011cadf5fcfSpatrick 	while (newidx != sc->sc_console_readidx) {
2012cadf5fcfSpatrick 		uint8_t ch = bus_space_read_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
2013cadf5fcfSpatrick 		    sc->sc_console_buf_addr + sc->sc_console_readidx);
2014cadf5fcfSpatrick 		sc->sc_console_readidx++;
2015cadf5fcfSpatrick 		if (sc->sc_console_readidx == sc->sc_console_buf_size)
2016cadf5fcfSpatrick 			sc->sc_console_readidx = 0;
2017cadf5fcfSpatrick 		if (ch == '\r')
2018cadf5fcfSpatrick 			continue;
2019bbd71b0bSpatrick 		DPRINTFN(3, ("%c", ch));
2020cadf5fcfSpatrick 	}
2021cadf5fcfSpatrick }
2022bbd71b0bSpatrick #endif
2023cadf5fcfSpatrick 
2024e5ec1e72Spatrick int
2025e5ec1e72Spatrick bwfm_pci_intr(void *v)
2026e5ec1e72Spatrick {
2027e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)v;
2028bb813cf8Spatrick 	struct bwfm_softc *bwfm = (void *)sc;
20296f241297Spatrick 	struct ifnet *ifp = &sc->sc_sc.sc_ic.ic_if;
20306f241297Spatrick 	struct mbuf_list ml = MBUF_LIST_INITIALIZER();
2031bb813cf8Spatrick 	uint32_t status, mask;
2032e5ec1e72Spatrick 
2033bb813cf8Spatrick 	if (!sc->sc_initialized)
2034bb813cf8Spatrick 		return 0;
2035bb813cf8Spatrick 
2036bb813cf8Spatrick 	status = bwfm_pci_intr_status(sc);
2037bb813cf8Spatrick 	/* FIXME: interrupt status seems to be zero? */
2038bb813cf8Spatrick 	if (status == 0 && bwfm->sc_chip.ch_chip == BRCM_CC_4378_CHIP_ID)
2039bb813cf8Spatrick 		status |= BWFM_PCI_64_PCIE2REG_MAILBOXMASK_INT_D2H_DB;
2040bb813cf8Spatrick 	if (status == 0)
2041e5ec1e72Spatrick 		return 0;
2042e5ec1e72Spatrick 
2043e5ec1e72Spatrick 	bwfm_pci_intr_disable(sc);
2044bb813cf8Spatrick 	bwfm_pci_intr_ack(sc, status);
2045e5ec1e72Spatrick 
2046bb813cf8Spatrick 	if (bwfm->sc_chip.ch_chip != BRCM_CC_4378_CHIP_ID &&
2047bb813cf8Spatrick 	    (status & (BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_0 |
2048bb813cf8Spatrick 	    BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_1)))
2049e5ec1e72Spatrick 		printf("%s: handle MB data\n", __func__);
2050e5ec1e72Spatrick 
2051bb813cf8Spatrick 	mask = BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_D2H_DB;
2052bb813cf8Spatrick 	if (bwfm->sc_chip.ch_chip == BRCM_CC_4378_CHIP_ID)
2053bb813cf8Spatrick 		mask = BWFM_PCI_64_PCIE2REG_MAILBOXMASK_INT_D2H_DB;
2054bb813cf8Spatrick 
2055bb813cf8Spatrick 	if (status & mask) {
20566f241297Spatrick 		bwfm_pci_ring_rx(sc, &sc->sc_rx_complete, &ml);
20576f241297Spatrick 		bwfm_pci_ring_rx(sc, &sc->sc_tx_complete, &ml);
20586f241297Spatrick 		bwfm_pci_ring_rx(sc, &sc->sc_ctrl_complete, &ml);
2059447a2df6Sdlg 
2060447a2df6Sdlg 		if (ifiq_input(&ifp->if_rcv, &ml))
2061447a2df6Sdlg 			if_rxr_livelocked(&sc->sc_rxbuf_ring);
2062e5ec1e72Spatrick 	}
2063e5ec1e72Spatrick 
2064cadf5fcfSpatrick #ifdef BWFM_DEBUG
2065cadf5fcfSpatrick 	bwfm_pci_debug_console(sc);
2066e5ec1e72Spatrick #endif
2067e5ec1e72Spatrick 
2068e5ec1e72Spatrick 	bwfm_pci_intr_enable(sc);
2069e5ec1e72Spatrick 	return 1;
2070e5ec1e72Spatrick }
2071e5ec1e72Spatrick 
2072e5ec1e72Spatrick void
2073e5ec1e72Spatrick bwfm_pci_intr_enable(struct bwfm_pci_softc *sc)
2074e5ec1e72Spatrick {
2075bb813cf8Spatrick 	struct bwfm_softc *bwfm = (void *)sc;
2076bb813cf8Spatrick 
2077bb813cf8Spatrick 	if (bwfm->sc_chip.ch_chip == BRCM_CC_4378_CHIP_ID)
2078bb813cf8Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
2079bb813cf8Spatrick 		    BWFM_PCI_64_PCIE2REG_MAILBOXMASK,
2080bb813cf8Spatrick 		    BWFM_PCI_64_PCIE2REG_MAILBOXMASK_INT_D2H_DB);
2081bb813cf8Spatrick 	else
2082e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
2083e5ec1e72Spatrick 		    BWFM_PCI_PCIE2REG_MAILBOXMASK,
2084e5ec1e72Spatrick 		    BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_0 |
2085e5ec1e72Spatrick 		    BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_1 |
2086e5ec1e72Spatrick 		    BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_D2H_DB);
2087e5ec1e72Spatrick }
2088e5ec1e72Spatrick 
2089e5ec1e72Spatrick void
2090e5ec1e72Spatrick bwfm_pci_intr_disable(struct bwfm_pci_softc *sc)
2091e5ec1e72Spatrick {
2092bb813cf8Spatrick 	struct bwfm_softc *bwfm = (void *)sc;
2093bb813cf8Spatrick 
2094bb813cf8Spatrick 	if (bwfm->sc_chip.ch_chip == BRCM_CC_4378_CHIP_ID)
2095bb813cf8Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
2096bb813cf8Spatrick 		    BWFM_PCI_64_PCIE2REG_MAILBOXMASK, 0);
2097bb813cf8Spatrick 	else
2098e5ec1e72Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
2099e5ec1e72Spatrick 		    BWFM_PCI_PCIE2REG_MAILBOXMASK, 0);
2100e5ec1e72Spatrick }
2101e5ec1e72Spatrick 
2102bb813cf8Spatrick uint32_t
2103bb813cf8Spatrick bwfm_pci_intr_status(struct bwfm_pci_softc *sc)
2104bb813cf8Spatrick {
2105bb813cf8Spatrick 	struct bwfm_softc *bwfm = (void *)sc;
2106bb813cf8Spatrick 
2107bb813cf8Spatrick 	if (bwfm->sc_chip.ch_chip == BRCM_CC_4378_CHIP_ID)
2108bb813cf8Spatrick 		return bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
2109bb813cf8Spatrick 		    BWFM_PCI_64_PCIE2REG_MAILBOXINT);
2110bb813cf8Spatrick 	else
2111bb813cf8Spatrick 		return bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
2112bb813cf8Spatrick 		    BWFM_PCI_PCIE2REG_MAILBOXINT);
2113bb813cf8Spatrick }
2114bb813cf8Spatrick 
2115bb813cf8Spatrick void
2116bb813cf8Spatrick bwfm_pci_intr_ack(struct bwfm_pci_softc *sc, uint32_t status)
2117bb813cf8Spatrick {
2118bb813cf8Spatrick 	struct bwfm_softc *bwfm = (void *)sc;
2119bb813cf8Spatrick 
2120bb813cf8Spatrick 	if (bwfm->sc_chip.ch_chip == BRCM_CC_4378_CHIP_ID)
2121bb813cf8Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
2122bb813cf8Spatrick 		    BWFM_PCI_64_PCIE2REG_MAILBOXINT, status);
2123bb813cf8Spatrick 	else
2124bb813cf8Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
2125bb813cf8Spatrick 		    BWFM_PCI_PCIE2REG_MAILBOXINT, status);
2126bb813cf8Spatrick }
2127bb813cf8Spatrick 
2128156d2677Spatrick void
2129156d2677Spatrick bwfm_pci_hostready(struct bwfm_pci_softc *sc)
2130156d2677Spatrick {
2131bb813cf8Spatrick 	struct bwfm_softc *bwfm = (void *)sc;
2132bb813cf8Spatrick 
2133156d2677Spatrick 	if ((sc->sc_shared_flags & BWFM_SHARED_INFO_HOSTRDY_DB1) == 0)
2134156d2677Spatrick 		return;
2135156d2677Spatrick 
2136bb813cf8Spatrick 	if (bwfm->sc_chip.ch_chip == BRCM_CC_4378_CHIP_ID)
2137bb813cf8Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
2138bb813cf8Spatrick 		    BWFM_PCI_64_PCIE2REG_H2D_MAILBOX_1, 1);
2139bb813cf8Spatrick 	else
2140156d2677Spatrick 		bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
2141156d2677Spatrick 		    BWFM_PCI_PCIE2REG_H2D_MAILBOX_1, 1);
2142156d2677Spatrick }
2143156d2677Spatrick 
2144e5ec1e72Spatrick /* Msgbuf protocol implementation */
2145e5ec1e72Spatrick int
2146e5ec1e72Spatrick bwfm_pci_msgbuf_query_dcmd(struct bwfm_softc *bwfm, int ifidx,
2147e5ec1e72Spatrick     int cmd, char *buf, size_t *len)
2148e5ec1e72Spatrick {
2149e5ec1e72Spatrick 	struct bwfm_pci_softc *sc = (void *)bwfm;
2150e5ec1e72Spatrick 	struct msgbuf_ioctl_req_hdr *req;
21512eeba925Spatrick 	struct bwfm_pci_ioctl *ctl;
2152e5ec1e72Spatrick 	struct mbuf *m;
21532eeba925Spatrick 	uint32_t pktid;
21542eeba925Spatrick 	paddr_t paddr;
2155e5ec1e72Spatrick 	size_t buflen;
2156e272db29Spatrick 	int s;
2157e5ec1e72Spatrick 
21582eeba925Spatrick 	buflen = min(*len, BWFM_DMA_H2D_IOCTL_BUF_LEN);
2159471f2571Sjan 	m = MCLGETL(NULL, M_DONTWAIT, buflen);
21602eeba925Spatrick 	if (m == NULL)
21612eeba925Spatrick 		return 1;
21622eeba925Spatrick 	m->m_len = m->m_pkthdr.len = buflen;
21632eeba925Spatrick 
21642eeba925Spatrick 	if (buf)
21652eeba925Spatrick 		memcpy(mtod(m, char *), buf, buflen);
21662eeba925Spatrick 	else
21672eeba925Spatrick 		memset(mtod(m, char *), 0, buflen);
21682eeba925Spatrick 
2169e272db29Spatrick 	s = splnet();
2170e5ec1e72Spatrick 	req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit);
2171e5ec1e72Spatrick 	if (req == NULL) {
2172e272db29Spatrick 		splx(s);
21732eeba925Spatrick 		m_freem(m);
2174e5ec1e72Spatrick 		return 1;
2175e5ec1e72Spatrick 	}
21762eeba925Spatrick 
21772eeba925Spatrick 	if (bwfm_pci_pktid_new(sc, &sc->sc_ioctl_pkts, m, &pktid, &paddr)) {
21782eeba925Spatrick 		bwfm_pci_ring_write_cancel(sc, &sc->sc_ctrl_submit, 1);
2179e272db29Spatrick 		splx(s);
21802eeba925Spatrick 		m_freem(m);
21812eeba925Spatrick 		return 1;
21822eeba925Spatrick 	}
21832eeba925Spatrick 
21842eeba925Spatrick 	ctl = malloc(sizeof(*ctl), M_TEMP, M_WAITOK|M_ZERO);
21852eeba925Spatrick 	ctl->transid = sc->sc_ioctl_transid++;
21862eeba925Spatrick 	TAILQ_INSERT_TAIL(&sc->sc_ioctlq, ctl, next);
21872eeba925Spatrick 
2188e5ec1e72Spatrick 	req->msg.msgtype = MSGBUF_TYPE_IOCTLPTR_REQ;
2189e5ec1e72Spatrick 	req->msg.ifidx = 0;
2190e5ec1e72Spatrick 	req->msg.flags = 0;
21912eeba925Spatrick 	req->msg.request_id = htole32(pktid);
2192e5ec1e72Spatrick 	req->cmd = htole32(cmd);
2193e5ec1e72Spatrick 	req->output_buf_len = htole16(*len);
21942eeba925Spatrick 	req->trans_id = htole16(ctl->transid);
2195e5ec1e72Spatrick 
21962eeba925Spatrick 	req->input_buf_len = htole16(m->m_len);
21972eeba925Spatrick 	req->req_buf_addr.high_addr = htole32((uint64_t)paddr >> 32);
21982eeba925Spatrick 	req->req_buf_addr.low_addr = htole32(paddr & 0xffffffff);
2199dcb67343Spatrick 
2200e5ec1e72Spatrick 	bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit);
2201e272db29Spatrick 	splx(s);
2202e5ec1e72Spatrick 
22038544fed6Smpi 	tsleep_nsec(ctl, PWAIT, "bwfm", SEC_TO_NSEC(1));
22042eeba925Spatrick 	TAILQ_REMOVE(&sc->sc_ioctlq, ctl, next);
22052eeba925Spatrick 
22062eeba925Spatrick 	if (ctl->m == NULL) {
22072eeba925Spatrick 		free(ctl, M_TEMP, sizeof(*ctl));
2208e5ec1e72Spatrick 		return 1;
2209e5ec1e72Spatrick 	}
2210e5ec1e72Spatrick 
22112eeba925Spatrick 	*len = min(ctl->retlen, m->m_len);
22122eeba925Spatrick 	*len = min(*len, buflen);
2213e5ec1e72Spatrick 	if (buf)
22145c7fed39Sdlg 		m_copydata(ctl->m, 0, *len, buf);
22152eeba925Spatrick 	m_freem(ctl->m);
2216e5ec1e72Spatrick 
22172eeba925Spatrick 	if (ctl->status < 0) {
22182eeba925Spatrick 		free(ctl, M_TEMP, sizeof(*ctl));
22192eeba925Spatrick 		return 1;
22202eeba925Spatrick 	}
22212eeba925Spatrick 
22222eeba925Spatrick 	free(ctl, M_TEMP, sizeof(*ctl));
2223e5ec1e72Spatrick 	return 0;
2224e5ec1e72Spatrick }
2225e5ec1e72Spatrick 
2226e5ec1e72Spatrick int
2227e5ec1e72Spatrick bwfm_pci_msgbuf_set_dcmd(struct bwfm_softc *bwfm, int ifidx,
2228e5ec1e72Spatrick     int cmd, char *buf, size_t len)
2229e5ec1e72Spatrick {
2230e5ec1e72Spatrick 	return bwfm_pci_msgbuf_query_dcmd(bwfm, ifidx, cmd, buf, &len);
2231e5ec1e72Spatrick }
22322eeba925Spatrick 
22332eeba925Spatrick void
22342eeba925Spatrick bwfm_pci_msgbuf_rxioctl(struct bwfm_pci_softc *sc,
22352eeba925Spatrick     struct msgbuf_ioctl_resp_hdr *resp)
22362eeba925Spatrick {
22372eeba925Spatrick 	struct bwfm_pci_ioctl *ctl, *tmp;
22382eeba925Spatrick 	struct mbuf *m;
22392eeba925Spatrick 
22402eeba925Spatrick 	m = bwfm_pci_pktid_free(sc, &sc->sc_rx_pkts,
22412eeba925Spatrick 	    letoh32(resp->msg.request_id));
22422eeba925Spatrick 
22432eeba925Spatrick 	TAILQ_FOREACH_SAFE(ctl, &sc->sc_ioctlq, next, tmp) {
22442eeba925Spatrick 		if (ctl->transid != letoh16(resp->trans_id))
22452eeba925Spatrick 			continue;
22462eeba925Spatrick 		ctl->m = m;
22472eeba925Spatrick 		ctl->retlen = letoh16(resp->resp_len);
22482eeba925Spatrick 		ctl->status = letoh16(resp->compl_hdr.status);
22492eeba925Spatrick 		wakeup(ctl);
22502eeba925Spatrick 		return;
22512eeba925Spatrick 	}
22522eeba925Spatrick 
2253cb2afc74Spatrick 	m_freem(m);
22542eeba925Spatrick }
2255