1*708e0c62Skettenis /* $OpenBSD: if_bwfm_pci.c,v 1.75 2022/12/30 14:10:17 kettenis Exp $ */
2e5ec1e72Spatrick /*
3e5ec1e72Spatrick * Copyright (c) 2010-2016 Broadcom Corporation
4e5ec1e72Spatrick * Copyright (c) 2017 Patrick Wildt <patrick@blueri.se>
5e5ec1e72Spatrick *
6e5ec1e72Spatrick * Permission to use, copy, modify, and/or distribute this software for any
7e5ec1e72Spatrick * purpose with or without fee is hereby granted, provided that the above
8e5ec1e72Spatrick * copyright notice and this permission notice appear in all copies.
9e5ec1e72Spatrick *
10e5ec1e72Spatrick * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11e5ec1e72Spatrick * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12e5ec1e72Spatrick * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13e5ec1e72Spatrick * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14e5ec1e72Spatrick * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15e5ec1e72Spatrick * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16e5ec1e72Spatrick * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17e5ec1e72Spatrick */
18e5ec1e72Spatrick
19e5ec1e72Spatrick #include "bpfilter.h"
20e5ec1e72Spatrick
21e5ec1e72Spatrick #include <sys/param.h>
22e5ec1e72Spatrick #include <sys/systm.h>
23e5ec1e72Spatrick #include <sys/buf.h>
24e5ec1e72Spatrick #include <sys/kernel.h>
25e5ec1e72Spatrick #include <sys/malloc.h>
26e5ec1e72Spatrick #include <sys/device.h>
27e5ec1e72Spatrick #include <sys/queue.h>
28e5ec1e72Spatrick #include <sys/socket.h>
29e5ec1e72Spatrick
30ed6d4272Spatrick #if defined(__HAVE_FDT)
31ed6d4272Spatrick #include <machine/fdt.h>
32ed6d4272Spatrick #include <dev/ofw/openfirm.h>
33ed6d4272Spatrick #endif
34ed6d4272Spatrick
35e5ec1e72Spatrick #if NBPFILTER > 0
36e5ec1e72Spatrick #include <net/bpf.h>
37e5ec1e72Spatrick #endif
38e5ec1e72Spatrick #include <net/if.h>
39e5ec1e72Spatrick #include <net/if_dl.h>
40e5ec1e72Spatrick #include <net/if_media.h>
41e5ec1e72Spatrick
42e5ec1e72Spatrick #include <netinet/in.h>
43e5ec1e72Spatrick #include <netinet/if_ether.h>
44e5ec1e72Spatrick
45e5ec1e72Spatrick #include <net80211/ieee80211_var.h>
46e5ec1e72Spatrick
47e5ec1e72Spatrick #include <machine/bus.h>
48e5ec1e72Spatrick
49e5ec1e72Spatrick #include <dev/pci/pcireg.h>
50e5ec1e72Spatrick #include <dev/pci/pcivar.h>
51e5ec1e72Spatrick #include <dev/pci/pcidevs.h>
52e5ec1e72Spatrick
53e5ec1e72Spatrick #include <dev/ic/bwfmvar.h>
54e5ec1e72Spatrick #include <dev/ic/bwfmreg.h>
55e5ec1e72Spatrick #include <dev/pci/if_bwfm_pci.h>
56e5ec1e72Spatrick
57e5ec1e72Spatrick #define BWFM_DMA_D2H_SCRATCH_BUF_LEN 8
58e5ec1e72Spatrick #define BWFM_DMA_D2H_RINGUPD_BUF_LEN 1024
59e5ec1e72Spatrick #define BWFM_DMA_H2D_IOCTL_BUF_LEN ETHER_MAX_LEN
60e5ec1e72Spatrick
61e5ec1e72Spatrick #define BWFM_NUM_TX_MSGRINGS 2
62e5ec1e72Spatrick #define BWFM_NUM_RX_MSGRINGS 3
63e5ec1e72Spatrick
642eeba925Spatrick #define BWFM_NUM_IOCTL_PKTIDS 8
65e5ec1e72Spatrick #define BWFM_NUM_TX_PKTIDS 2048
66e5ec1e72Spatrick #define BWFM_NUM_RX_PKTIDS 1024
67e5ec1e72Spatrick
682eeba925Spatrick #define BWFM_NUM_IOCTL_DESCS 1
69e5ec1e72Spatrick #define BWFM_NUM_TX_DESCS 1
70e5ec1e72Spatrick #define BWFM_NUM_RX_DESCS 1
71e5ec1e72Spatrick
72e5ec1e72Spatrick #ifdef BWFM_DEBUG
73e5ec1e72Spatrick #define DPRINTF(x) do { if (bwfm_debug > 0) printf x; } while (0)
74e5ec1e72Spatrick #define DPRINTFN(n, x) do { if (bwfm_debug >= (n)) printf x; } while (0)
75e5ec1e72Spatrick static int bwfm_debug = 2;
76e5ec1e72Spatrick #else
77e5ec1e72Spatrick #define DPRINTF(x) do { ; } while (0)
78e5ec1e72Spatrick #define DPRINTFN(n, x) do { ; } while (0)
79e5ec1e72Spatrick #endif
80e5ec1e72Spatrick
81e5ec1e72Spatrick #define DEVNAME(sc) ((sc)->sc_sc.sc_dev.dv_xname)
82e5ec1e72Spatrick
83518be5f3Spatrick enum ring_status {
84518be5f3Spatrick RING_CLOSED,
85518be5f3Spatrick RING_CLOSING,
86518be5f3Spatrick RING_OPEN,
87518be5f3Spatrick RING_OPENING,
88518be5f3Spatrick };
89518be5f3Spatrick
90e5ec1e72Spatrick struct bwfm_pci_msgring {
91e5ec1e72Spatrick uint32_t w_idx_addr;
92e5ec1e72Spatrick uint32_t r_idx_addr;
93e5ec1e72Spatrick uint32_t w_ptr;
94e5ec1e72Spatrick uint32_t r_ptr;
95e5ec1e72Spatrick int nitem;
96e5ec1e72Spatrick int itemsz;
97518be5f3Spatrick enum ring_status status;
98e5ec1e72Spatrick struct bwfm_pci_dmamem *ring;
9902ee7d07Spatrick struct mbuf *m;
100f67437f3Spatrick
101f67437f3Spatrick int fifo;
102f67437f3Spatrick uint8_t mac[ETHER_ADDR_LEN];
103e5ec1e72Spatrick };
104e5ec1e72Spatrick
1052eeba925Spatrick struct bwfm_pci_ioctl {
1062eeba925Spatrick uint16_t transid;
1072eeba925Spatrick uint16_t retlen;
1082eeba925Spatrick int16_t status;
1092eeba925Spatrick struct mbuf *m;
1102eeba925Spatrick TAILQ_ENTRY(bwfm_pci_ioctl) next;
1112eeba925Spatrick };
1122eeba925Spatrick
113e5ec1e72Spatrick struct bwfm_pci_buf {
114e5ec1e72Spatrick bus_dmamap_t bb_map;
115e5ec1e72Spatrick struct mbuf *bb_m;
116e5ec1e72Spatrick };
117e5ec1e72Spatrick
118e5ec1e72Spatrick struct bwfm_pci_pkts {
119e5ec1e72Spatrick struct bwfm_pci_buf *pkts;
120e5ec1e72Spatrick uint32_t npkt;
121e5ec1e72Spatrick int last;
122e5ec1e72Spatrick };
123e5ec1e72Spatrick
124e5ec1e72Spatrick struct bwfm_pci_softc {
125e5ec1e72Spatrick struct bwfm_softc sc_sc;
126e5ec1e72Spatrick pci_chipset_tag_t sc_pc;
127e5ec1e72Spatrick pcitag_t sc_tag;
128e5ec1e72Spatrick pcireg_t sc_id;
129e5ec1e72Spatrick void *sc_ih;
130e5ec1e72Spatrick
131972218f3Spatrick int sc_initialized;
132972218f3Spatrick
133e5ec1e72Spatrick bus_space_tag_t sc_reg_iot;
134e5ec1e72Spatrick bus_space_handle_t sc_reg_ioh;
135e5ec1e72Spatrick bus_size_t sc_reg_ios;
136e5ec1e72Spatrick
137e5ec1e72Spatrick bus_space_tag_t sc_tcm_iot;
138e5ec1e72Spatrick bus_space_handle_t sc_tcm_ioh;
139e5ec1e72Spatrick bus_size_t sc_tcm_ios;
140e5ec1e72Spatrick
141e5ec1e72Spatrick bus_dma_tag_t sc_dmat;
142e5ec1e72Spatrick
143e5ec1e72Spatrick uint32_t sc_shared_address;
144e5ec1e72Spatrick uint32_t sc_shared_flags;
145e5ec1e72Spatrick uint8_t sc_shared_version;
146e5ec1e72Spatrick
147e5ec1e72Spatrick uint8_t sc_dma_idx_sz;
148e5ec1e72Spatrick struct bwfm_pci_dmamem *sc_dma_idx_buf;
149e5ec1e72Spatrick size_t sc_dma_idx_bufsz;
150e5ec1e72Spatrick
151e5ec1e72Spatrick uint16_t sc_max_rxbufpost;
152e5ec1e72Spatrick uint32_t sc_rx_dataoffset;
153e5ec1e72Spatrick uint32_t sc_htod_mb_data_addr;
154e5ec1e72Spatrick uint32_t sc_dtoh_mb_data_addr;
155e5ec1e72Spatrick uint32_t sc_ring_info_addr;
156e5ec1e72Spatrick
157e5ec1e72Spatrick uint32_t sc_console_base_addr;
158e5ec1e72Spatrick uint32_t sc_console_buf_addr;
159e5ec1e72Spatrick uint32_t sc_console_buf_size;
160cadf5fcfSpatrick uint32_t sc_console_readidx;
161e5ec1e72Spatrick
162e5ec1e72Spatrick uint16_t sc_max_flowrings;
163e5ec1e72Spatrick uint16_t sc_max_submissionrings;
164e5ec1e72Spatrick uint16_t sc_max_completionrings;
165e5ec1e72Spatrick
166e5ec1e72Spatrick struct bwfm_pci_msgring sc_ctrl_submit;
167e5ec1e72Spatrick struct bwfm_pci_msgring sc_rxpost_submit;
168e5ec1e72Spatrick struct bwfm_pci_msgring sc_ctrl_complete;
169e5ec1e72Spatrick struct bwfm_pci_msgring sc_tx_complete;
170e5ec1e72Spatrick struct bwfm_pci_msgring sc_rx_complete;
171e5ec1e72Spatrick struct bwfm_pci_msgring *sc_flowrings;
172e5ec1e72Spatrick
173e5ec1e72Spatrick struct bwfm_pci_dmamem *sc_scratch_buf;
174e5ec1e72Spatrick struct bwfm_pci_dmamem *sc_ringupd_buf;
175e5ec1e72Spatrick
1762eeba925Spatrick TAILQ_HEAD(, bwfm_pci_ioctl) sc_ioctlq;
1772eeba925Spatrick uint16_t sc_ioctl_transid;
178e5ec1e72Spatrick
179e5ec1e72Spatrick struct if_rxring sc_ioctl_ring;
180e5ec1e72Spatrick struct if_rxring sc_event_ring;
181e5ec1e72Spatrick struct if_rxring sc_rxbuf_ring;
182e5ec1e72Spatrick
1832eeba925Spatrick struct bwfm_pci_pkts sc_ioctl_pkts;
184e5ec1e72Spatrick struct bwfm_pci_pkts sc_rx_pkts;
185c6f1636dSpatrick struct bwfm_pci_pkts sc_tx_pkts;
186c6f1636dSpatrick int sc_tx_pkts_full;
1871a93a9bdSpatrick
1881a93a9bdSpatrick uint8_t sc_mbdata_done;
1898bad4727Spatrick uint8_t sc_pcireg64;
1908674c33cSkettenis uint8_t sc_mb_via_ctl;
191e5ec1e72Spatrick };
192e5ec1e72Spatrick
193e5ec1e72Spatrick struct bwfm_pci_dmamem {
194e5ec1e72Spatrick bus_dmamap_t bdm_map;
195e5ec1e72Spatrick bus_dma_segment_t bdm_seg;
196e5ec1e72Spatrick size_t bdm_size;
197e5ec1e72Spatrick caddr_t bdm_kva;
198e5ec1e72Spatrick };
199e5ec1e72Spatrick
200e5ec1e72Spatrick #define BWFM_PCI_DMA_MAP(_bdm) ((_bdm)->bdm_map)
201e5ec1e72Spatrick #define BWFM_PCI_DMA_LEN(_bdm) ((_bdm)->bdm_size)
202e4dae658Spatrick #define BWFM_PCI_DMA_DVA(_bdm) ((uint64_t)(_bdm)->bdm_map->dm_segs[0].ds_addr)
203e5ec1e72Spatrick #define BWFM_PCI_DMA_KVA(_bdm) ((void *)(_bdm)->bdm_kva)
204e5ec1e72Spatrick
205e5ec1e72Spatrick int bwfm_pci_match(struct device *, void *, void *);
206e5ec1e72Spatrick void bwfm_pci_attach(struct device *, struct device *, void *);
207e5ec1e72Spatrick int bwfm_pci_detach(struct device *, int);
2081a93a9bdSpatrick int bwfm_pci_activate(struct device *, int);
2091a93a9bdSpatrick void bwfm_pci_cleanup(struct bwfm_pci_softc *);
210e5ec1e72Spatrick
211ed6d4272Spatrick #if defined(__HAVE_FDT)
212ed6d4272Spatrick int bwfm_pci_read_otp(struct bwfm_pci_softc *);
213ed6d4272Spatrick void bwfm_pci_process_otp_tuple(struct bwfm_pci_softc *, uint8_t,
214ed6d4272Spatrick uint8_t, uint8_t *);
215ed6d4272Spatrick #endif
216ed6d4272Spatrick
217e5ec1e72Spatrick int bwfm_pci_intr(void *);
218e5ec1e72Spatrick void bwfm_pci_intr_enable(struct bwfm_pci_softc *);
219e5ec1e72Spatrick void bwfm_pci_intr_disable(struct bwfm_pci_softc *);
220bb813cf8Spatrick uint32_t bwfm_pci_intr_status(struct bwfm_pci_softc *);
221bb813cf8Spatrick void bwfm_pci_intr_ack(struct bwfm_pci_softc *, uint32_t);
2221a93a9bdSpatrick uint32_t bwfm_pci_intmask(struct bwfm_pci_softc *);
223156d2677Spatrick void bwfm_pci_hostready(struct bwfm_pci_softc *);
224e5ec1e72Spatrick int bwfm_pci_load_microcode(struct bwfm_pci_softc *, const u_char *,
2256aad491fSpatrick size_t, const u_char *, size_t);
226e5ec1e72Spatrick void bwfm_pci_select_core(struct bwfm_pci_softc *, int );
227e5ec1e72Spatrick
228e5ec1e72Spatrick struct bwfm_pci_dmamem *
229e5ec1e72Spatrick bwfm_pci_dmamem_alloc(struct bwfm_pci_softc *, bus_size_t,
230e5ec1e72Spatrick bus_size_t);
231e5ec1e72Spatrick void bwfm_pci_dmamem_free(struct bwfm_pci_softc *, struct bwfm_pci_dmamem *);
23202ee7d07Spatrick int bwfm_pci_pktid_avail(struct bwfm_pci_softc *,
23302ee7d07Spatrick struct bwfm_pci_pkts *);
234e5ec1e72Spatrick int bwfm_pci_pktid_new(struct bwfm_pci_softc *,
235e5ec1e72Spatrick struct bwfm_pci_pkts *, struct mbuf *,
236e5ec1e72Spatrick uint32_t *, paddr_t *);
237e5ec1e72Spatrick struct mbuf * bwfm_pci_pktid_free(struct bwfm_pci_softc *,
238e5ec1e72Spatrick struct bwfm_pci_pkts *, uint32_t);
239e5ec1e72Spatrick void bwfm_pci_fill_rx_ioctl_ring(struct bwfm_pci_softc *,
240e5ec1e72Spatrick struct if_rxring *, uint32_t);
241e5ec1e72Spatrick void bwfm_pci_fill_rx_buf_ring(struct bwfm_pci_softc *);
242e5ec1e72Spatrick void bwfm_pci_fill_rx_rings(struct bwfm_pci_softc *);
243e5ec1e72Spatrick int bwfm_pci_setup_ring(struct bwfm_pci_softc *, struct bwfm_pci_msgring *,
244e5ec1e72Spatrick int, size_t, uint32_t, uint32_t, int, uint32_t, uint32_t *);
245518be5f3Spatrick int bwfm_pci_setup_flowring(struct bwfm_pci_softc *, struct bwfm_pci_msgring *,
246518be5f3Spatrick int, size_t);
247e5ec1e72Spatrick
248e5ec1e72Spatrick void bwfm_pci_ring_bell(struct bwfm_pci_softc *,
249e5ec1e72Spatrick struct bwfm_pci_msgring *);
250e5ec1e72Spatrick void bwfm_pci_ring_update_rptr(struct bwfm_pci_softc *,
251e5ec1e72Spatrick struct bwfm_pci_msgring *);
252e5ec1e72Spatrick void bwfm_pci_ring_update_wptr(struct bwfm_pci_softc *,
253e5ec1e72Spatrick struct bwfm_pci_msgring *);
254e5ec1e72Spatrick void bwfm_pci_ring_write_rptr(struct bwfm_pci_softc *,
255e5ec1e72Spatrick struct bwfm_pci_msgring *);
256e5ec1e72Spatrick void bwfm_pci_ring_write_wptr(struct bwfm_pci_softc *,
257e5ec1e72Spatrick struct bwfm_pci_msgring *);
258e5ec1e72Spatrick void * bwfm_pci_ring_write_reserve(struct bwfm_pci_softc *,
259e5ec1e72Spatrick struct bwfm_pci_msgring *);
260e5ec1e72Spatrick void * bwfm_pci_ring_write_reserve_multi(struct bwfm_pci_softc *,
261e5ec1e72Spatrick struct bwfm_pci_msgring *, int, int *);
262e5ec1e72Spatrick void * bwfm_pci_ring_read_avail(struct bwfm_pci_softc *,
263e5ec1e72Spatrick struct bwfm_pci_msgring *, int *);
264e5ec1e72Spatrick void bwfm_pci_ring_read_commit(struct bwfm_pci_softc *,
265e5ec1e72Spatrick struct bwfm_pci_msgring *, int);
266e5ec1e72Spatrick void bwfm_pci_ring_write_commit(struct bwfm_pci_softc *,
267e5ec1e72Spatrick struct bwfm_pci_msgring *);
268e5ec1e72Spatrick void bwfm_pci_ring_write_cancel(struct bwfm_pci_softc *,
269e5ec1e72Spatrick struct bwfm_pci_msgring *, int);
270e5ec1e72Spatrick
271e5ec1e72Spatrick void bwfm_pci_ring_rx(struct bwfm_pci_softc *,
2726f241297Spatrick struct bwfm_pci_msgring *, struct mbuf_list *);
2736f241297Spatrick void bwfm_pci_msg_rx(struct bwfm_pci_softc *, void *,
2746f241297Spatrick struct mbuf_list *);
275e5ec1e72Spatrick
276e5ec1e72Spatrick uint32_t bwfm_pci_buscore_read(struct bwfm_softc *, uint32_t);
277e5ec1e72Spatrick void bwfm_pci_buscore_write(struct bwfm_softc *, uint32_t,
278e5ec1e72Spatrick uint32_t);
279e5ec1e72Spatrick int bwfm_pci_buscore_prepare(struct bwfm_softc *);
280e5ec1e72Spatrick int bwfm_pci_buscore_reset(struct bwfm_softc *);
281e5ec1e72Spatrick void bwfm_pci_buscore_activate(struct bwfm_softc *, uint32_t);
282e5ec1e72Spatrick
283f67437f3Spatrick int bwfm_pci_flowring_lookup(struct bwfm_pci_softc *,
284f67437f3Spatrick struct mbuf *);
285f67437f3Spatrick void bwfm_pci_flowring_create(struct bwfm_pci_softc *,
286518be5f3Spatrick struct mbuf *);
287518be5f3Spatrick void bwfm_pci_flowring_create_cb(struct bwfm_softc *, void *);
288a2c6ff8bSpatrick void bwfm_pci_flowring_delete(struct bwfm_pci_softc *, int);
289b5553ee6Spatrick void bwfm_pci_flowring_delete_cb(struct bwfm_softc *, void *);
290518be5f3Spatrick
291972218f3Spatrick int bwfm_pci_preinit(struct bwfm_softc *);
292a2c6ff8bSpatrick void bwfm_pci_stop(struct bwfm_softc *);
29302ee7d07Spatrick int bwfm_pci_txcheck(struct bwfm_softc *);
294e5ec1e72Spatrick int bwfm_pci_txdata(struct bwfm_softc *, struct mbuf *);
295bbd71b0bSpatrick
2961a93a9bdSpatrick int bwfm_pci_send_mb_data(struct bwfm_pci_softc *, uint32_t);
2971a93a9bdSpatrick void bwfm_pci_handle_mb_data(struct bwfm_pci_softc *);
2981a93a9bdSpatrick
299bbd71b0bSpatrick #ifdef BWFM_DEBUG
300cadf5fcfSpatrick void bwfm_pci_debug_console(struct bwfm_pci_softc *);
301bbd71b0bSpatrick #endif
302e5ec1e72Spatrick
303e5ec1e72Spatrick int bwfm_pci_msgbuf_query_dcmd(struct bwfm_softc *, int,
304e5ec1e72Spatrick int, char *, size_t *);
305e5ec1e72Spatrick int bwfm_pci_msgbuf_set_dcmd(struct bwfm_softc *, int,
306e5ec1e72Spatrick int, char *, size_t);
3072eeba925Spatrick void bwfm_pci_msgbuf_rxioctl(struct bwfm_pci_softc *,
3082eeba925Spatrick struct msgbuf_ioctl_resp_hdr *);
3098674c33cSkettenis int bwfm_pci_msgbuf_h2d_mb_write(struct bwfm_pci_softc *,
3108674c33cSkettenis uint32_t);
311e5ec1e72Spatrick
312e5ec1e72Spatrick struct bwfm_buscore_ops bwfm_pci_buscore_ops = {
313e5ec1e72Spatrick .bc_read = bwfm_pci_buscore_read,
314e5ec1e72Spatrick .bc_write = bwfm_pci_buscore_write,
315e5ec1e72Spatrick .bc_prepare = bwfm_pci_buscore_prepare,
316e5ec1e72Spatrick .bc_reset = bwfm_pci_buscore_reset,
317e5ec1e72Spatrick .bc_setup = NULL,
318e5ec1e72Spatrick .bc_activate = bwfm_pci_buscore_activate,
319e5ec1e72Spatrick };
320e5ec1e72Spatrick
321e5ec1e72Spatrick struct bwfm_bus_ops bwfm_pci_bus_ops = {
322972218f3Spatrick .bs_preinit = bwfm_pci_preinit,
323a2c6ff8bSpatrick .bs_stop = bwfm_pci_stop,
32402ee7d07Spatrick .bs_txcheck = bwfm_pci_txcheck,
325e5ec1e72Spatrick .bs_txdata = bwfm_pci_txdata,
326e5ec1e72Spatrick .bs_txctl = NULL,
327e5ec1e72Spatrick };
328e5ec1e72Spatrick
329e5ec1e72Spatrick struct bwfm_proto_ops bwfm_pci_msgbuf_ops = {
330e5ec1e72Spatrick .proto_query_dcmd = bwfm_pci_msgbuf_query_dcmd,
331e5ec1e72Spatrick .proto_set_dcmd = bwfm_pci_msgbuf_set_dcmd,
33214c74651Spatrick .proto_rx = NULL,
333029d6dd5Spatrick .proto_rxctl = NULL,
334e5ec1e72Spatrick };
335e5ec1e72Spatrick
3368d2c75e4Smpi const struct cfattach bwfm_pci_ca = {
337e5ec1e72Spatrick sizeof(struct bwfm_pci_softc),
338e5ec1e72Spatrick bwfm_pci_match,
339e5ec1e72Spatrick bwfm_pci_attach,
340e5ec1e72Spatrick bwfm_pci_detach,
3411a93a9bdSpatrick bwfm_pci_activate,
342e5ec1e72Spatrick };
343e5ec1e72Spatrick
344e5ec1e72Spatrick static const struct pci_matchid bwfm_pci_devices[] = {
34582f0e660Sjcs { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4350 },
34641d93ac2Spatrick { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4356 },
34741d93ac2Spatrick { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM43602 },
348821fc986Spatrick { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4371 },
3498e234c40Spatrick { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4378 },
3509b183917Skettenis { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4387 },
351e5ec1e72Spatrick };
352e5ec1e72Spatrick
353e5ec1e72Spatrick int
bwfm_pci_match(struct device * parent,void * match,void * aux)354e5ec1e72Spatrick bwfm_pci_match(struct device *parent, void *match, void *aux)
355e5ec1e72Spatrick {
356e5ec1e72Spatrick return (pci_matchbyid(aux, bwfm_pci_devices,
357e5ec1e72Spatrick nitems(bwfm_pci_devices)));
358e5ec1e72Spatrick }
359e5ec1e72Spatrick
360e5ec1e72Spatrick void
bwfm_pci_attach(struct device * parent,struct device * self,void * aux)361e5ec1e72Spatrick bwfm_pci_attach(struct device *parent, struct device *self, void *aux)
362e5ec1e72Spatrick {
363e5ec1e72Spatrick struct bwfm_pci_softc *sc = (struct bwfm_pci_softc *)self;
364e5ec1e72Spatrick struct pci_attach_args *pa = (struct pci_attach_args *)aux;
365e5ec1e72Spatrick const char *intrstr;
366e5ec1e72Spatrick pci_intr_handle_t ih;
367e5ec1e72Spatrick
368e5ec1e72Spatrick if (pci_mapreg_map(pa, PCI_MAPREG_START + 0x08,
369e5ec1e72Spatrick PCI_MAPREG_MEM_TYPE_64BIT, 0, &sc->sc_tcm_iot, &sc->sc_tcm_ioh,
370e5ec1e72Spatrick NULL, &sc->sc_tcm_ios, 0)) {
371e5ec1e72Spatrick printf(": can't map bar1\n");
372a08e9144Spatrick return;
373a08e9144Spatrick }
374a08e9144Spatrick
375a08e9144Spatrick if (pci_mapreg_map(pa, PCI_MAPREG_START + 0x00,
376a08e9144Spatrick PCI_MAPREG_MEM_TYPE_64BIT, 0, &sc->sc_reg_iot, &sc->sc_reg_ioh,
377a08e9144Spatrick NULL, &sc->sc_reg_ios, 0)) {
378a08e9144Spatrick printf(": can't map bar0\n");
379a08e9144Spatrick goto bar1;
380e5ec1e72Spatrick }
381e5ec1e72Spatrick
382e5ec1e72Spatrick sc->sc_pc = pa->pa_pc;
383e5ec1e72Spatrick sc->sc_tag = pa->pa_tag;
384e5ec1e72Spatrick sc->sc_id = pa->pa_id;
385e5ec1e72Spatrick sc->sc_dmat = pa->pa_dmat;
386e5ec1e72Spatrick
387e5ec1e72Spatrick /* Map and establish the interrupt. */
388e5ec1e72Spatrick if (pci_intr_map_msi(pa, &ih) != 0 && pci_intr_map(pa, &ih) != 0) {
389e5ec1e72Spatrick printf(": couldn't map interrupt\n");
390a08e9144Spatrick goto bar0;
391e5ec1e72Spatrick }
392e5ec1e72Spatrick intrstr = pci_intr_string(pa->pa_pc, ih);
393e5ec1e72Spatrick
39414484acaSpatrick sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_NET,
395e5ec1e72Spatrick bwfm_pci_intr, sc, DEVNAME(sc));
396e5ec1e72Spatrick if (sc->sc_ih == NULL) {
397e5ec1e72Spatrick printf(": couldn't establish interrupt");
398e5ec1e72Spatrick if (intrstr != NULL)
399e5ec1e72Spatrick printf(" at %s", intrstr);
400e5ec1e72Spatrick printf("\n");
401e5ec1e72Spatrick goto bar1;
402e5ec1e72Spatrick }
403e5ec1e72Spatrick printf(": %s\n", intrstr);
404e5ec1e72Spatrick
405db31205aSkettenis #if defined(__HAVE_FDT)
406db31205aSkettenis sc->sc_sc.sc_node = PCITAG_NODE(pa->pa_tag);
407da5a4af2Spatrick if (sc->sc_sc.sc_node) {
408da5a4af2Spatrick if (OF_getproplen(sc->sc_sc.sc_node, "brcm,cal-blob") > 0) {
409da5a4af2Spatrick sc->sc_sc.sc_calsize = OF_getproplen(sc->sc_sc.sc_node,
410da5a4af2Spatrick "brcm,cal-blob");
411da5a4af2Spatrick sc->sc_sc.sc_cal = malloc(sc->sc_sc.sc_calsize,
412da5a4af2Spatrick M_DEVBUF, M_WAITOK);
413da5a4af2Spatrick OF_getprop(sc->sc_sc.sc_node, "brcm,cal-blob",
414da5a4af2Spatrick sc->sc_sc.sc_cal, sc->sc_sc.sc_calsize);
415da5a4af2Spatrick }
416da5a4af2Spatrick }
417db31205aSkettenis #endif
418db31205aSkettenis
419972218f3Spatrick sc->sc_sc.sc_bus_ops = &bwfm_pci_bus_ops;
420972218f3Spatrick sc->sc_sc.sc_proto_ops = &bwfm_pci_msgbuf_ops;
421972218f3Spatrick bwfm_attach(&sc->sc_sc);
422972218f3Spatrick config_mountroot(self, bwfm_attachhook);
423e5ec1e72Spatrick return;
424e5ec1e72Spatrick
425e5ec1e72Spatrick bar0:
426e5ec1e72Spatrick bus_space_unmap(sc->sc_reg_iot, sc->sc_reg_ioh, sc->sc_reg_ios);
427a08e9144Spatrick bar1:
428a08e9144Spatrick bus_space_unmap(sc->sc_tcm_iot, sc->sc_tcm_ioh, sc->sc_tcm_ios);
429e5ec1e72Spatrick }
430e5ec1e72Spatrick
431972218f3Spatrick int
bwfm_pci_preinit(struct bwfm_softc * bwfm)432972218f3Spatrick bwfm_pci_preinit(struct bwfm_softc *bwfm)
433e5ec1e72Spatrick {
434972218f3Spatrick struct bwfm_pci_softc *sc = (void *)bwfm;
435e5ec1e72Spatrick struct bwfm_pci_ringinfo ringinfo;
4369ead8393Spatrick const char *chip = NULL;
43794e4747cSpatrick u_char *ucode, *nvram;
43894e4747cSpatrick size_t size, nvsize, nvlen;
439e5ec1e72Spatrick uint32_t d2h_w_idx_ptr, d2h_r_idx_ptr;
440e5ec1e72Spatrick uint32_t h2d_w_idx_ptr, h2d_r_idx_ptr;
441e5ec1e72Spatrick uint32_t idx_offset, reg;
442e5ec1e72Spatrick int i;
443e5ec1e72Spatrick
444972218f3Spatrick if (sc->sc_initialized)
445972218f3Spatrick return 0;
446972218f3Spatrick
447e5ec1e72Spatrick sc->sc_sc.sc_buscore_ops = &bwfm_pci_buscore_ops;
448e5ec1e72Spatrick if (bwfm_chip_attach(&sc->sc_sc) != 0) {
449e5ec1e72Spatrick printf("%s: cannot attach chip\n", DEVNAME(sc));
450972218f3Spatrick return 1;
451e5ec1e72Spatrick }
452e5ec1e72Spatrick
453ed6d4272Spatrick #if defined(__HAVE_FDT)
454ed6d4272Spatrick if (bwfm_pci_read_otp(sc)) {
455ed6d4272Spatrick printf("%s: cannot read OTP\n", DEVNAME(sc));
456ed6d4272Spatrick return 1;
457ed6d4272Spatrick }
458ed6d4272Spatrick #endif
459ed6d4272Spatrick
460e5ec1e72Spatrick bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2);
461e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
462e5ec1e72Spatrick BWFM_PCI_PCIE2REG_CONFIGADDR, 0x4e0);
463e5ec1e72Spatrick reg = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
464e5ec1e72Spatrick BWFM_PCI_PCIE2REG_CONFIGDATA);
465e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
466e5ec1e72Spatrick BWFM_PCI_PCIE2REG_CONFIGDATA, reg);
467e5ec1e72Spatrick
468bb818c30Spatrick switch (bwfm->sc_chip.ch_chip) {
46918b3a1dcSpatrick case BRCM_CC_4350_CHIP_ID:
470bb818c30Spatrick if (bwfm->sc_chip.ch_chiprev <= 7)
4719ead8393Spatrick chip = "4350c2";
472bb818c30Spatrick else
473bb818c30Spatrick chip = "4350";
474bb818c30Spatrick break;
475bb818c30Spatrick case BRCM_CC_4355_CHIP_ID:
476bb818c30Spatrick chip = "4355c1";
47718b3a1dcSpatrick break;
47841d93ac2Spatrick case BRCM_CC_4356_CHIP_ID:
4799ead8393Spatrick chip = "4356";
48041d93ac2Spatrick break;
481bb818c30Spatrick case BRCM_CC_4364_CHIP_ID:
482bb818c30Spatrick if (bwfm->sc_chip.ch_chiprev <= 3)
483bb818c30Spatrick chip = "4364b2";
484bb818c30Spatrick else
485bb818c30Spatrick chip = "4364b3";
486bb818c30Spatrick break;
487e5ec1e72Spatrick case BRCM_CC_43602_CHIP_ID:
4889ead8393Spatrick chip = "43602";
489e5ec1e72Spatrick break;
490821fc986Spatrick case BRCM_CC_4371_CHIP_ID:
4919ead8393Spatrick chip = "4371";
492821fc986Spatrick break;
493bb818c30Spatrick case BRCM_CC_4377_CHIP_ID:
494bb818c30Spatrick chip = "4377b3";
495bb818c30Spatrick break;
496c38a9bc9Spatrick case BRCM_CC_4378_CHIP_ID:
497*708e0c62Skettenis if (bwfm->sc_chip.ch_chiprev <= 3)
498c6a4ab0dSkettenis chip = "4378b1";
499*708e0c62Skettenis else
500*708e0c62Skettenis chip = "4378b3";
501c38a9bc9Spatrick break;
502bb818c30Spatrick case BRCM_CC_4387_CHIP_ID:
503bb818c30Spatrick chip = "4387c2";
504bb818c30Spatrick break;
505e5ec1e72Spatrick default:
50618b3a1dcSpatrick printf("%s: unknown firmware for chip %s\n",
50718b3a1dcSpatrick DEVNAME(sc), bwfm->sc_chip.ch_name);
508972218f3Spatrick return 1;
509e5ec1e72Spatrick }
510e5ec1e72Spatrick
51194e4747cSpatrick if (bwfm_loadfirmware(bwfm, chip, "-pcie", &ucode, &size,
51294e4747cSpatrick &nvram, &nvsize, &nvlen) != 0)
513972218f3Spatrick return 1;
5146aad491fSpatrick
515e5ec1e72Spatrick /* Retrieve RAM size from firmware. */
516e5ec1e72Spatrick if (size >= BWFM_RAMSIZE + 8) {
517e5ec1e72Spatrick uint32_t *ramsize = (uint32_t *)&ucode[BWFM_RAMSIZE];
518e5ec1e72Spatrick if (letoh32(ramsize[0]) == BWFM_RAMSIZE_MAGIC)
519e5ec1e72Spatrick bwfm->sc_chip.ch_ramsize = letoh32(ramsize[1]);
520e5ec1e72Spatrick }
521e5ec1e72Spatrick
5226aad491fSpatrick if (bwfm_pci_load_microcode(sc, ucode, size, nvram, nvlen) != 0) {
523e5ec1e72Spatrick printf("%s: could not load microcode\n",
524e5ec1e72Spatrick DEVNAME(sc));
525e5ec1e72Spatrick free(ucode, M_DEVBUF, size);
526b4e85b06Spatrick free(nvram, M_DEVBUF, nvsize);
527972218f3Spatrick return 1;
528e5ec1e72Spatrick }
529e5ec1e72Spatrick free(ucode, M_DEVBUF, size);
530b4e85b06Spatrick free(nvram, M_DEVBUF, nvsize);
531e5ec1e72Spatrick
532e5ec1e72Spatrick sc->sc_shared_flags = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
533e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_INFO);
534e5ec1e72Spatrick sc->sc_shared_version = sc->sc_shared_flags;
535e5ec1e72Spatrick if (sc->sc_shared_version > BWFM_SHARED_INFO_MAX_VERSION ||
536e5ec1e72Spatrick sc->sc_shared_version < BWFM_SHARED_INFO_MIN_VERSION) {
537e5ec1e72Spatrick printf("%s: PCIe version %d unsupported\n",
538e5ec1e72Spatrick DEVNAME(sc), sc->sc_shared_version);
539972218f3Spatrick return 1;
540e5ec1e72Spatrick }
541e5ec1e72Spatrick
5428674c33cSkettenis if (sc->sc_shared_version >= 6) {
5438674c33cSkettenis uint32_t host_cap;
5448674c33cSkettenis
5458674c33cSkettenis if ((sc->sc_shared_flags & BWFM_SHARED_INFO_USE_MAILBOX) == 0)
5468674c33cSkettenis sc->sc_mb_via_ctl = 1;
5478674c33cSkettenis
5488674c33cSkettenis host_cap = sc->sc_shared_version;
5498674c33cSkettenis if (sc->sc_shared_flags & BWFM_SHARED_INFO_HOSTRDY_DB1)
5508674c33cSkettenis host_cap |= BWFM_SHARED_HOST_CAP_H2D_ENABLE_HOSTRDY;
5518674c33cSkettenis if (sc->sc_shared_flags & BWFM_SHARED_INFO_SHARED_DAR)
5528674c33cSkettenis host_cap |= BWFM_SHARED_HOST_CAP_H2D_DAR;
5538674c33cSkettenis host_cap |= BWFM_SHARED_HOST_CAP_DS_NO_OOB_DW;
5548674c33cSkettenis
5558674c33cSkettenis bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
5568674c33cSkettenis sc->sc_shared_address + BWFM_SHARED_HOST_CAP, host_cap);
5578674c33cSkettenis bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
5588674c33cSkettenis sc->sc_shared_address + BWFM_SHARED_HOST_CAP2, 0);
5598674c33cSkettenis }
5608674c33cSkettenis
561c794abf2Spatrick sc->sc_dma_idx_sz = 0;
562e5ec1e72Spatrick if (sc->sc_shared_flags & BWFM_SHARED_INFO_DMA_INDEX) {
563e5ec1e72Spatrick if (sc->sc_shared_flags & BWFM_SHARED_INFO_DMA_2B_IDX)
564e5ec1e72Spatrick sc->sc_dma_idx_sz = sizeof(uint16_t);
565e5ec1e72Spatrick else
566e5ec1e72Spatrick sc->sc_dma_idx_sz = sizeof(uint32_t);
567e5ec1e72Spatrick }
568e5ec1e72Spatrick
569e5ec1e72Spatrick /* Maximum RX data buffers in the ring. */
570e5ec1e72Spatrick sc->sc_max_rxbufpost = bus_space_read_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
571e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_MAX_RXBUFPOST);
572e5ec1e72Spatrick if (sc->sc_max_rxbufpost == 0)
573e5ec1e72Spatrick sc->sc_max_rxbufpost = BWFM_SHARED_MAX_RXBUFPOST_DEFAULT;
574e5ec1e72Spatrick
575e5ec1e72Spatrick /* Alternative offset of data in a packet */
576e5ec1e72Spatrick sc->sc_rx_dataoffset = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
577e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_RX_DATAOFFSET);
578e5ec1e72Spatrick
579e5ec1e72Spatrick /* For Power Management */
580e5ec1e72Spatrick sc->sc_htod_mb_data_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
581e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_HTOD_MB_DATA_ADDR);
582e5ec1e72Spatrick sc->sc_dtoh_mb_data_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
583e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_DTOH_MB_DATA_ADDR);
584e5ec1e72Spatrick
585e5ec1e72Spatrick /* Ring information */
586e5ec1e72Spatrick sc->sc_ring_info_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
587e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_RING_INFO_ADDR);
588e5ec1e72Spatrick
589e5ec1e72Spatrick /* Firmware's "dmesg" */
590e5ec1e72Spatrick sc->sc_console_base_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
591e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_CONSOLE_ADDR);
592e5ec1e72Spatrick sc->sc_console_buf_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
593e5ec1e72Spatrick sc->sc_console_base_addr + BWFM_CONSOLE_BUFADDR);
594e5ec1e72Spatrick sc->sc_console_buf_size = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
595e5ec1e72Spatrick sc->sc_console_base_addr + BWFM_CONSOLE_BUFSIZE);
596e5ec1e72Spatrick
597e5ec1e72Spatrick /* Read ring information. */
598e5ec1e72Spatrick bus_space_read_region_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
599e5ec1e72Spatrick sc->sc_ring_info_addr, (void *)&ringinfo, sizeof(ringinfo));
600e5ec1e72Spatrick
601e5ec1e72Spatrick if (sc->sc_shared_version >= 6) {
602e5ec1e72Spatrick sc->sc_max_submissionrings = le16toh(ringinfo.max_submissionrings);
603e5ec1e72Spatrick sc->sc_max_flowrings = le16toh(ringinfo.max_flowrings);
604e5ec1e72Spatrick sc->sc_max_completionrings = le16toh(ringinfo.max_completionrings);
605e5ec1e72Spatrick } else {
606e5ec1e72Spatrick sc->sc_max_submissionrings = le16toh(ringinfo.max_flowrings);
607e5ec1e72Spatrick sc->sc_max_flowrings = sc->sc_max_submissionrings -
608e5ec1e72Spatrick BWFM_NUM_TX_MSGRINGS;
609e5ec1e72Spatrick sc->sc_max_completionrings = BWFM_NUM_RX_MSGRINGS;
610e5ec1e72Spatrick }
611e5ec1e72Spatrick
612e5ec1e72Spatrick if (sc->sc_dma_idx_sz == 0) {
613e5ec1e72Spatrick d2h_w_idx_ptr = letoh32(ringinfo.d2h_w_idx_ptr);
614e5ec1e72Spatrick d2h_r_idx_ptr = letoh32(ringinfo.d2h_r_idx_ptr);
615e5ec1e72Spatrick h2d_w_idx_ptr = letoh32(ringinfo.h2d_w_idx_ptr);
616e5ec1e72Spatrick h2d_r_idx_ptr = letoh32(ringinfo.h2d_r_idx_ptr);
617e5ec1e72Spatrick idx_offset = sizeof(uint32_t);
618e5ec1e72Spatrick } else {
619e5ec1e72Spatrick uint64_t address;
620e5ec1e72Spatrick
621e5ec1e72Spatrick /* Each TX/RX Ring has a Read and Write Ptr */
622e5ec1e72Spatrick sc->sc_dma_idx_bufsz = (sc->sc_max_submissionrings +
623e5ec1e72Spatrick sc->sc_max_completionrings) * sc->sc_dma_idx_sz * 2;
624e5ec1e72Spatrick sc->sc_dma_idx_buf = bwfm_pci_dmamem_alloc(sc,
625e5ec1e72Spatrick sc->sc_dma_idx_bufsz, 8);
626e5ec1e72Spatrick if (sc->sc_dma_idx_buf == NULL) {
627e5ec1e72Spatrick /* XXX: Fallback to TCM? */
628e5ec1e72Spatrick printf("%s: cannot allocate idx buf\n",
629e5ec1e72Spatrick DEVNAME(sc));
630972218f3Spatrick return 1;
631e5ec1e72Spatrick }
632e5ec1e72Spatrick
633e5ec1e72Spatrick idx_offset = sc->sc_dma_idx_sz;
634e5ec1e72Spatrick h2d_w_idx_ptr = 0;
635e5ec1e72Spatrick address = BWFM_PCI_DMA_DVA(sc->sc_dma_idx_buf);
636e5ec1e72Spatrick ringinfo.h2d_w_idx_hostaddr_low =
637e5ec1e72Spatrick htole32(address & 0xffffffff);
638e5ec1e72Spatrick ringinfo.h2d_w_idx_hostaddr_high =
639e5ec1e72Spatrick htole32(address >> 32);
640e5ec1e72Spatrick
641e5ec1e72Spatrick h2d_r_idx_ptr = h2d_w_idx_ptr +
642e5ec1e72Spatrick sc->sc_max_submissionrings * idx_offset;
643e5ec1e72Spatrick address += sc->sc_max_submissionrings * idx_offset;
644e5ec1e72Spatrick ringinfo.h2d_r_idx_hostaddr_low =
645e5ec1e72Spatrick htole32(address & 0xffffffff);
646e5ec1e72Spatrick ringinfo.h2d_r_idx_hostaddr_high =
647e5ec1e72Spatrick htole32(address >> 32);
648e5ec1e72Spatrick
649e5ec1e72Spatrick d2h_w_idx_ptr = h2d_r_idx_ptr +
650e5ec1e72Spatrick sc->sc_max_submissionrings * idx_offset;
651e5ec1e72Spatrick address += sc->sc_max_submissionrings * idx_offset;
652e5ec1e72Spatrick ringinfo.d2h_w_idx_hostaddr_low =
653e5ec1e72Spatrick htole32(address & 0xffffffff);
654e5ec1e72Spatrick ringinfo.d2h_w_idx_hostaddr_high =
655e5ec1e72Spatrick htole32(address >> 32);
656e5ec1e72Spatrick
657e5ec1e72Spatrick d2h_r_idx_ptr = d2h_w_idx_ptr +
658e5ec1e72Spatrick sc->sc_max_completionrings * idx_offset;
659e5ec1e72Spatrick address += sc->sc_max_completionrings * idx_offset;
660e5ec1e72Spatrick ringinfo.d2h_r_idx_hostaddr_low =
661e5ec1e72Spatrick htole32(address & 0xffffffff);
662e5ec1e72Spatrick ringinfo.d2h_r_idx_hostaddr_high =
663e5ec1e72Spatrick htole32(address >> 32);
664e5ec1e72Spatrick
665e5ec1e72Spatrick bus_space_write_region_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
666e5ec1e72Spatrick sc->sc_ring_info_addr, (void *)&ringinfo, sizeof(ringinfo));
667e5ec1e72Spatrick }
668e5ec1e72Spatrick
669e5ec1e72Spatrick uint32_t ring_mem_ptr = letoh32(ringinfo.ringmem);
670e5ec1e72Spatrick /* TX ctrl ring: Send ctrl buffers, send IOCTLs */
671e5ec1e72Spatrick if (bwfm_pci_setup_ring(sc, &sc->sc_ctrl_submit, 64, 40,
672e5ec1e72Spatrick h2d_w_idx_ptr, h2d_r_idx_ptr, 0, idx_offset,
673e5ec1e72Spatrick &ring_mem_ptr))
674e5ec1e72Spatrick goto cleanup;
675e5ec1e72Spatrick /* TX rxpost ring: Send clean data mbufs for RX */
6761c0efb8bSpatrick if (bwfm_pci_setup_ring(sc, &sc->sc_rxpost_submit, 1024, 32,
677e5ec1e72Spatrick h2d_w_idx_ptr, h2d_r_idx_ptr, 1, idx_offset,
678e5ec1e72Spatrick &ring_mem_ptr))
679e5ec1e72Spatrick goto cleanup;
680e5ec1e72Spatrick /* RX completion rings: recv our filled buffers back */
681e5ec1e72Spatrick if (bwfm_pci_setup_ring(sc, &sc->sc_ctrl_complete, 64, 24,
682e5ec1e72Spatrick d2h_w_idx_ptr, d2h_r_idx_ptr, 0, idx_offset,
683e5ec1e72Spatrick &ring_mem_ptr))
684e5ec1e72Spatrick goto cleanup;
685095b0c44Spatrick if (bwfm_pci_setup_ring(sc, &sc->sc_tx_complete, 1024,
686095b0c44Spatrick sc->sc_shared_version >= 7 ? 24 : 16,
687e5ec1e72Spatrick d2h_w_idx_ptr, d2h_r_idx_ptr, 1, idx_offset,
688e5ec1e72Spatrick &ring_mem_ptr))
689e5ec1e72Spatrick goto cleanup;
6901c0efb8bSpatrick if (bwfm_pci_setup_ring(sc, &sc->sc_rx_complete, 1024,
691095b0c44Spatrick sc->sc_shared_version >= 7 ? 40 : 32,
692e5ec1e72Spatrick d2h_w_idx_ptr, d2h_r_idx_ptr, 2, idx_offset,
693e5ec1e72Spatrick &ring_mem_ptr))
694e5ec1e72Spatrick goto cleanup;
695e5ec1e72Spatrick
696e5ec1e72Spatrick /* Dynamic TX rings for actual data */
697e5ec1e72Spatrick sc->sc_flowrings = malloc(sc->sc_max_flowrings *
698e5ec1e72Spatrick sizeof(struct bwfm_pci_msgring), M_DEVBUF, M_WAITOK | M_ZERO);
699518be5f3Spatrick for (i = 0; i < sc->sc_max_flowrings; i++) {
700518be5f3Spatrick struct bwfm_pci_msgring *ring = &sc->sc_flowrings[i];
701518be5f3Spatrick ring->w_idx_addr = h2d_w_idx_ptr + (i + 2) * idx_offset;
702518be5f3Spatrick ring->r_idx_addr = h2d_r_idx_ptr + (i + 2) * idx_offset;
703518be5f3Spatrick }
704e5ec1e72Spatrick
705e5ec1e72Spatrick /* Scratch and ring update buffers for firmware */
706e5ec1e72Spatrick if ((sc->sc_scratch_buf = bwfm_pci_dmamem_alloc(sc,
707e5ec1e72Spatrick BWFM_DMA_D2H_SCRATCH_BUF_LEN, 8)) == NULL)
708e5ec1e72Spatrick goto cleanup;
709e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
710e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_DMA_SCRATCH_ADDR_LOW,
711e5ec1e72Spatrick BWFM_PCI_DMA_DVA(sc->sc_scratch_buf) & 0xffffffff);
712e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
713e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_DMA_SCRATCH_ADDR_HIGH,
714e5ec1e72Spatrick BWFM_PCI_DMA_DVA(sc->sc_scratch_buf) >> 32);
715e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
716e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_DMA_SCRATCH_LEN,
717e5ec1e72Spatrick BWFM_DMA_D2H_SCRATCH_BUF_LEN);
718e5ec1e72Spatrick
719e5ec1e72Spatrick if ((sc->sc_ringupd_buf = bwfm_pci_dmamem_alloc(sc,
720e5ec1e72Spatrick BWFM_DMA_D2H_RINGUPD_BUF_LEN, 8)) == NULL)
721e5ec1e72Spatrick goto cleanup;
722e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
723e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_DMA_RINGUPD_ADDR_LOW,
724e5ec1e72Spatrick BWFM_PCI_DMA_DVA(sc->sc_ringupd_buf) & 0xffffffff);
725e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
726e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_DMA_RINGUPD_ADDR_HIGH,
727e5ec1e72Spatrick BWFM_PCI_DMA_DVA(sc->sc_ringupd_buf) >> 32);
728e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
729e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_DMA_RINGUPD_LEN,
730e5ec1e72Spatrick BWFM_DMA_D2H_RINGUPD_BUF_LEN);
731e5ec1e72Spatrick
732e5ec1e72Spatrick bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2);
733e5ec1e72Spatrick bwfm_pci_intr_enable(sc);
734156d2677Spatrick bwfm_pci_hostready(sc);
735e5ec1e72Spatrick
736e5ec1e72Spatrick /* Maps RX mbufs to a packet id and back. */
737e5ec1e72Spatrick sc->sc_rx_pkts.npkt = BWFM_NUM_RX_PKTIDS;
738e5ec1e72Spatrick sc->sc_rx_pkts.pkts = malloc(BWFM_NUM_RX_PKTIDS *
739e5ec1e72Spatrick sizeof(struct bwfm_pci_buf), M_DEVBUF, M_WAITOK | M_ZERO);
740e5ec1e72Spatrick for (i = 0; i < BWFM_NUM_RX_PKTIDS; i++)
7411950c5c5Spatrick bus_dmamap_create(sc->sc_dmat, MSGBUF_MAX_CTL_PKT_SIZE,
7421950c5c5Spatrick BWFM_NUM_RX_DESCS, MSGBUF_MAX_CTL_PKT_SIZE, 0, BUS_DMA_WAITOK,
743e5ec1e72Spatrick &sc->sc_rx_pkts.pkts[i].bb_map);
744e5ec1e72Spatrick
745e5ec1e72Spatrick /* Maps TX mbufs to a packet id and back. */
746f416501bSpatrick sc->sc_tx_pkts.npkt = BWFM_NUM_TX_PKTIDS;
747e5ec1e72Spatrick sc->sc_tx_pkts.pkts = malloc(BWFM_NUM_TX_PKTIDS
748e5ec1e72Spatrick * sizeof(struct bwfm_pci_buf), M_DEVBUF, M_WAITOK | M_ZERO);
749e5ec1e72Spatrick for (i = 0; i < BWFM_NUM_TX_PKTIDS; i++)
750e5ec1e72Spatrick bus_dmamap_create(sc->sc_dmat, MSGBUF_MAX_PKT_SIZE,
751e5ec1e72Spatrick BWFM_NUM_TX_DESCS, MSGBUF_MAX_PKT_SIZE, 0, BUS_DMA_WAITOK,
752e5ec1e72Spatrick &sc->sc_tx_pkts.pkts[i].bb_map);
753c794abf2Spatrick sc->sc_tx_pkts_full = 0;
754e5ec1e72Spatrick
7552eeba925Spatrick /* Maps IOCTL mbufs to a packet id and back. */
7562eeba925Spatrick sc->sc_ioctl_pkts.npkt = BWFM_NUM_IOCTL_PKTIDS;
7572eeba925Spatrick sc->sc_ioctl_pkts.pkts = malloc(BWFM_NUM_IOCTL_PKTIDS
7582eeba925Spatrick * sizeof(struct bwfm_pci_buf), M_DEVBUF, M_WAITOK | M_ZERO);
7592eeba925Spatrick for (i = 0; i < BWFM_NUM_IOCTL_PKTIDS; i++)
7602eeba925Spatrick bus_dmamap_create(sc->sc_dmat, MSGBUF_MAX_PKT_SIZE,
7612eeba925Spatrick BWFM_NUM_IOCTL_DESCS, MSGBUF_MAX_PKT_SIZE, 0, BUS_DMA_WAITOK,
7622eeba925Spatrick &sc->sc_ioctl_pkts.pkts[i].bb_map);
7632eeba925Spatrick
76418722113Spatrick /*
76518722113Spatrick * For whatever reason, could also be a bug somewhere in this
76618722113Spatrick * driver, the firmware needs a bunch of RX buffers otherwise
7674ef2dd0fSpatrick * it won't send any RX complete messages.
76818722113Spatrick */
7694ef2dd0fSpatrick if_rxr_init(&sc->sc_rxbuf_ring, min(256, sc->sc_max_rxbufpost),
7704ef2dd0fSpatrick sc->sc_max_rxbufpost);
771e5ec1e72Spatrick if_rxr_init(&sc->sc_ioctl_ring, 8, 8);
772e5ec1e72Spatrick if_rxr_init(&sc->sc_event_ring, 8, 8);
773e5ec1e72Spatrick bwfm_pci_fill_rx_rings(sc);
774e5ec1e72Spatrick
7752eeba925Spatrick TAILQ_INIT(&sc->sc_ioctlq);
7762eeba925Spatrick
777cadf5fcfSpatrick #ifdef BWFM_DEBUG
778cadf5fcfSpatrick sc->sc_console_readidx = 0;
779cadf5fcfSpatrick bwfm_pci_debug_console(sc);
780cadf5fcfSpatrick #endif
781cadf5fcfSpatrick
782972218f3Spatrick sc->sc_initialized = 1;
783972218f3Spatrick return 0;
784e5ec1e72Spatrick
785e5ec1e72Spatrick cleanup:
786e5ec1e72Spatrick if (sc->sc_ringupd_buf)
787e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_ringupd_buf);
788e5ec1e72Spatrick if (sc->sc_scratch_buf)
789e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_scratch_buf);
790e5ec1e72Spatrick if (sc->sc_rx_complete.ring)
791e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_rx_complete.ring);
792e5ec1e72Spatrick if (sc->sc_tx_complete.ring)
793e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_tx_complete.ring);
794e5ec1e72Spatrick if (sc->sc_ctrl_complete.ring)
795e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_ctrl_complete.ring);
796e5ec1e72Spatrick if (sc->sc_rxpost_submit.ring)
797e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_rxpost_submit.ring);
798e5ec1e72Spatrick if (sc->sc_ctrl_submit.ring)
799e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_ctrl_submit.ring);
800e5ec1e72Spatrick if (sc->sc_dma_idx_buf)
801e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_dma_idx_buf);
802972218f3Spatrick return 1;
803e5ec1e72Spatrick }
804e5ec1e72Spatrick
805e5ec1e72Spatrick int
bwfm_pci_load_microcode(struct bwfm_pci_softc * sc,const u_char * ucode,size_t size,const u_char * nvram,size_t nvlen)8066aad491fSpatrick bwfm_pci_load_microcode(struct bwfm_pci_softc *sc, const u_char *ucode, size_t size,
8076aad491fSpatrick const u_char *nvram, size_t nvlen)
808e5ec1e72Spatrick {
809e5ec1e72Spatrick struct bwfm_softc *bwfm = (void *)sc;
810e5ec1e72Spatrick struct bwfm_core *core;
8112e962c76Spatrick struct bwfm_pci_random_seed_footer footer;
8122e962c76Spatrick uint32_t addr, shared, written;
8132e962c76Spatrick uint8_t *rndbuf;
814e5ec1e72Spatrick int i;
815e5ec1e72Spatrick
816e5ec1e72Spatrick if (bwfm->sc_chip.ch_chip == BRCM_CC_43602_CHIP_ID) {
817e5ec1e72Spatrick bwfm_pci_select_core(sc, BWFM_AGENT_CORE_ARM_CR4);
818e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
819e5ec1e72Spatrick BWFM_PCI_ARMCR4REG_BANKIDX, 5);
820e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
821e5ec1e72Spatrick BWFM_PCI_ARMCR4REG_BANKPDA, 0);
822e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
823e5ec1e72Spatrick BWFM_PCI_ARMCR4REG_BANKIDX, 7);
824e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
825e5ec1e72Spatrick BWFM_PCI_ARMCR4REG_BANKPDA, 0);
826e5ec1e72Spatrick }
827e5ec1e72Spatrick
828e5ec1e72Spatrick for (i = 0; i < size; i++)
829e5ec1e72Spatrick bus_space_write_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
830e5ec1e72Spatrick bwfm->sc_chip.ch_rambase + i, ucode[i]);
831e5ec1e72Spatrick
832e5ec1e72Spatrick /* Firmware replaces this with a pointer once up. */
833e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
834e5ec1e72Spatrick bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize - 4, 0);
835e5ec1e72Spatrick
8366aad491fSpatrick if (nvram) {
8372e962c76Spatrick addr = bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize -
8382e962c76Spatrick nvlen;
8396aad491fSpatrick for (i = 0; i < nvlen; i++)
8406aad491fSpatrick bus_space_write_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
8412e962c76Spatrick addr + i, nvram[i]);
8422e962c76Spatrick
843f2e739fdSpatrick footer.length = htole32(BWFM_RANDOM_SEED_LENGTH);
844f2e739fdSpatrick footer.magic = htole32(BWFM_RANDOM_SEED_MAGIC);
8452e962c76Spatrick addr -= sizeof(footer);
8462e962c76Spatrick for (i = 0; i < sizeof(footer); i++)
8472e962c76Spatrick bus_space_write_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
8482e962c76Spatrick addr + i, ((uint8_t *)&footer)[i]);
8492e962c76Spatrick
8502e962c76Spatrick rndbuf = malloc(BWFM_RANDOM_SEED_LENGTH, M_TEMP, M_WAITOK);
8512e962c76Spatrick arc4random_buf(rndbuf, BWFM_RANDOM_SEED_LENGTH);
8522e962c76Spatrick addr -= BWFM_RANDOM_SEED_LENGTH;
8532e962c76Spatrick for (i = 0; i < BWFM_RANDOM_SEED_LENGTH; i++)
8542e962c76Spatrick bus_space_write_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
8552e962c76Spatrick addr + i, rndbuf[i]);
8562e962c76Spatrick free(rndbuf, M_TEMP, BWFM_RANDOM_SEED_LENGTH);
8576aad491fSpatrick }
8586aad491fSpatrick
8596aad491fSpatrick written = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
8606aad491fSpatrick bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize - 4);
861e5ec1e72Spatrick
862e5ec1e72Spatrick /* Load reset vector from firmware and kickstart core. */
863b0cd4990Spatrick if (bwfm->sc_chip.ch_chip == BRCM_CC_43602_CHIP_ID) {
864e5ec1e72Spatrick core = bwfm_chip_get_core(bwfm, BWFM_AGENT_INTERNAL_MEM);
865e5ec1e72Spatrick bwfm->sc_chip.ch_core_reset(bwfm, core, 0, 0, 0);
866b0cd4990Spatrick }
867e5ec1e72Spatrick bwfm_chip_set_active(bwfm, *(uint32_t *)ucode);
868e5ec1e72Spatrick
8693c53ddefSpatrick for (i = 0; i < 100; i++) {
870e5ec1e72Spatrick delay(50 * 1000);
871e5ec1e72Spatrick shared = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
872e5ec1e72Spatrick bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize - 4);
8736aad491fSpatrick if (shared != written)
874e5ec1e72Spatrick break;
875e5ec1e72Spatrick }
87619871452Spatrick if (shared == written) {
877e5ec1e72Spatrick printf("%s: firmware did not come up\n", DEVNAME(sc));
878e5ec1e72Spatrick return 1;
879e5ec1e72Spatrick }
88019871452Spatrick if (shared < bwfm->sc_chip.ch_rambase ||
88119871452Spatrick shared >= bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize) {
88219871452Spatrick printf("%s: invalid shared RAM address 0x%08x\n", DEVNAME(sc),
88319871452Spatrick shared);
88419871452Spatrick return 1;
88519871452Spatrick }
886e5ec1e72Spatrick
887e5ec1e72Spatrick sc->sc_shared_address = shared;
888e5ec1e72Spatrick return 0;
889e5ec1e72Spatrick }
890e5ec1e72Spatrick
891e5ec1e72Spatrick int
bwfm_pci_detach(struct device * self,int flags)892e5ec1e72Spatrick bwfm_pci_detach(struct device *self, int flags)
893e5ec1e72Spatrick {
894e5ec1e72Spatrick struct bwfm_pci_softc *sc = (struct bwfm_pci_softc *)self;
895e5ec1e72Spatrick
896e5ec1e72Spatrick bwfm_detach(&sc->sc_sc, flags);
8971a93a9bdSpatrick bwfm_pci_cleanup(sc);
8981a93a9bdSpatrick
8991a93a9bdSpatrick return 0;
9001a93a9bdSpatrick }
9011a93a9bdSpatrick
9021a93a9bdSpatrick void
bwfm_pci_cleanup(struct bwfm_pci_softc * sc)9031a93a9bdSpatrick bwfm_pci_cleanup(struct bwfm_pci_softc *sc)
9041a93a9bdSpatrick {
9051a93a9bdSpatrick int i;
906e5ec1e72Spatrick
90764ae3612Spatrick for (i = 0; i < BWFM_NUM_RX_PKTIDS; i++) {
90864ae3612Spatrick bus_dmamap_destroy(sc->sc_dmat, sc->sc_rx_pkts.pkts[i].bb_map);
90964ae3612Spatrick if (sc->sc_rx_pkts.pkts[i].bb_m)
91064ae3612Spatrick m_freem(sc->sc_rx_pkts.pkts[i].bb_m);
91164ae3612Spatrick }
91264ae3612Spatrick free(sc->sc_rx_pkts.pkts, M_DEVBUF, BWFM_NUM_RX_PKTIDS *
91364ae3612Spatrick sizeof(struct bwfm_pci_buf));
91464ae3612Spatrick
91564ae3612Spatrick for (i = 0; i < BWFM_NUM_TX_PKTIDS; i++) {
91664ae3612Spatrick bus_dmamap_destroy(sc->sc_dmat, sc->sc_tx_pkts.pkts[i].bb_map);
91764ae3612Spatrick if (sc->sc_tx_pkts.pkts[i].bb_m)
91864ae3612Spatrick m_freem(sc->sc_tx_pkts.pkts[i].bb_m);
91964ae3612Spatrick }
92064ae3612Spatrick free(sc->sc_tx_pkts.pkts, M_DEVBUF, BWFM_NUM_TX_PKTIDS *
92164ae3612Spatrick sizeof(struct bwfm_pci_buf));
92264ae3612Spatrick
92364ae3612Spatrick for (i = 0; i < BWFM_NUM_IOCTL_PKTIDS; i++) {
92464ae3612Spatrick bus_dmamap_destroy(sc->sc_dmat, sc->sc_ioctl_pkts.pkts[i].bb_map);
92564ae3612Spatrick if (sc->sc_ioctl_pkts.pkts[i].bb_m)
92664ae3612Spatrick m_freem(sc->sc_ioctl_pkts.pkts[i].bb_m);
92764ae3612Spatrick }
92864ae3612Spatrick free(sc->sc_ioctl_pkts.pkts, M_DEVBUF, BWFM_NUM_IOCTL_PKTIDS *
92964ae3612Spatrick sizeof(struct bwfm_pci_buf));
93064ae3612Spatrick
93164ae3612Spatrick for (i = 0; i < sc->sc_max_flowrings; i++) {
93264ae3612Spatrick if (sc->sc_flowrings[i].status >= RING_OPEN)
93364ae3612Spatrick bwfm_pci_dmamem_free(sc, sc->sc_flowrings[i].ring);
93464ae3612Spatrick }
93564ae3612Spatrick free(sc->sc_flowrings, M_DEVBUF, sc->sc_max_flowrings *
93664ae3612Spatrick sizeof(struct bwfm_pci_msgring));
937e5ec1e72Spatrick
938e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_ringupd_buf);
939e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_scratch_buf);
940e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_rx_complete.ring);
941e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_tx_complete.ring);
942e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_ctrl_complete.ring);
943e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_rxpost_submit.ring);
944e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_ctrl_submit.ring);
94564ae3612Spatrick if (sc->sc_dma_idx_buf) {
946e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_dma_idx_buf);
94764ae3612Spatrick sc->sc_dma_idx_buf = NULL;
94864ae3612Spatrick }
94964ae3612Spatrick
95064ae3612Spatrick sc->sc_initialized = 0;
9511a93a9bdSpatrick }
9521a93a9bdSpatrick
9531a93a9bdSpatrick int
bwfm_pci_activate(struct device * self,int act)9541a93a9bdSpatrick bwfm_pci_activate(struct device *self, int act)
9551a93a9bdSpatrick {
9561a93a9bdSpatrick struct bwfm_pci_softc *sc = (struct bwfm_pci_softc *)self;
9571a93a9bdSpatrick struct bwfm_softc *bwfm = (void *)sc;
9581a93a9bdSpatrick int error = 0;
9591a93a9bdSpatrick
9601a93a9bdSpatrick switch (act) {
9611a93a9bdSpatrick case DVACT_QUIESCE:
9621a93a9bdSpatrick error = bwfm_activate(bwfm, act);
9631a93a9bdSpatrick if (error)
9641a93a9bdSpatrick return error;
9651a93a9bdSpatrick if (sc->sc_initialized) {
9661a93a9bdSpatrick sc->sc_mbdata_done = 0;
9671a93a9bdSpatrick error = bwfm_pci_send_mb_data(sc,
9681a93a9bdSpatrick BWFM_PCI_H2D_HOST_D3_INFORM);
9691a93a9bdSpatrick if (error)
9701a93a9bdSpatrick return error;
9711a93a9bdSpatrick tsleep_nsec(&sc->sc_mbdata_done, PCATCH,
9721a93a9bdSpatrick DEVNAME(sc), SEC_TO_NSEC(2));
9731a93a9bdSpatrick if (!sc->sc_mbdata_done)
9741a93a9bdSpatrick return ETIMEDOUT;
9751a93a9bdSpatrick }
9761a93a9bdSpatrick break;
9771a93a9bdSpatrick case DVACT_WAKEUP:
9781a93a9bdSpatrick if (sc->sc_initialized) {
9791a93a9bdSpatrick /* If device can't be resumed, re-init. */
9801a93a9bdSpatrick if (bwfm_pci_intmask(sc) == 0 ||
9811a93a9bdSpatrick bwfm_pci_send_mb_data(sc,
9821a93a9bdSpatrick BWFM_PCI_H2D_HOST_D0_INFORM) != 0) {
9831a93a9bdSpatrick bwfm_cleanup(bwfm);
9841a93a9bdSpatrick bwfm_pci_cleanup(sc);
98519ad97d5Skettenis } else {
98619ad97d5Skettenis bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2);
98719ad97d5Skettenis bwfm_pci_intr_enable(sc);
98819ad97d5Skettenis bwfm_pci_hostready(sc);
9891a93a9bdSpatrick }
9901a93a9bdSpatrick }
9911a93a9bdSpatrick error = bwfm_activate(bwfm, act);
9921a93a9bdSpatrick if (error)
9931a93a9bdSpatrick return error;
9941a93a9bdSpatrick break;
9951a93a9bdSpatrick default:
9961a93a9bdSpatrick break;
9971a93a9bdSpatrick }
9981a93a9bdSpatrick
999e5ec1e72Spatrick return 0;
1000e5ec1e72Spatrick }
1001e5ec1e72Spatrick
1002ed6d4272Spatrick #if defined(__HAVE_FDT)
1003ed6d4272Spatrick int
bwfm_pci_read_otp(struct bwfm_pci_softc * sc)1004ed6d4272Spatrick bwfm_pci_read_otp(struct bwfm_pci_softc *sc)
1005ed6d4272Spatrick {
1006ed6d4272Spatrick struct bwfm_softc *bwfm = (void *)sc;
1007ed6d4272Spatrick struct bwfm_core *core;
1008ea92f6c3Spatrick uint32_t coreid, base, words;
1009ea92f6c3Spatrick uint32_t page, offset, sromctl;
1010ea92f6c3Spatrick uint8_t *otp;
1011ed6d4272Spatrick int i;
1012ed6d4272Spatrick
1013ea92f6c3Spatrick switch (bwfm->sc_chip.ch_chip) {
1014ea92f6c3Spatrick case BRCM_CC_4355_CHIP_ID:
1015ea92f6c3Spatrick coreid = BWFM_AGENT_CORE_CHIPCOMMON;
1016ea92f6c3Spatrick base = 0x8c0;
1017ea92f6c3Spatrick words = 0xb2;
1018ea92f6c3Spatrick break;
1019ea92f6c3Spatrick case BRCM_CC_4364_CHIP_ID:
1020ea92f6c3Spatrick coreid = BWFM_AGENT_CORE_CHIPCOMMON;
1021ea92f6c3Spatrick base = 0x8c0;
1022ea92f6c3Spatrick words = 0x1a0;
1023ea92f6c3Spatrick break;
1024ea92f6c3Spatrick case BRCM_CC_4377_CHIP_ID:
1025ea92f6c3Spatrick case BRCM_CC_4378_CHIP_ID:
1026ea92f6c3Spatrick coreid = BWFM_AGENT_CORE_GCI;
1027ea92f6c3Spatrick base = 0x1120;
1028ea92f6c3Spatrick words = 0x170;
1029ea92f6c3Spatrick break;
1030ea92f6c3Spatrick case BRCM_CC_4387_CHIP_ID:
1031ea92f6c3Spatrick coreid = BWFM_AGENT_CORE_GCI;
1032ea92f6c3Spatrick base = 0x113c;
1033ea92f6c3Spatrick words = 0x170;
1034ea92f6c3Spatrick break;
1035ea92f6c3Spatrick default:
1036ed6d4272Spatrick return 0;
1037ea92f6c3Spatrick }
1038ed6d4272Spatrick
1039ea92f6c3Spatrick core = bwfm_chip_get_core(bwfm, coreid);
1040ed6d4272Spatrick if (core == NULL)
1041ed6d4272Spatrick return 1;
1042ed6d4272Spatrick
1043ea92f6c3Spatrick /* Map OTP to shadow area */
1044ea92f6c3Spatrick if (coreid == BWFM_AGENT_CORE_CHIPCOMMON) {
1045ea92f6c3Spatrick bwfm_pci_select_core(sc, coreid);
1046ea92f6c3Spatrick sromctl = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1047ea92f6c3Spatrick BWFM_CHIP_REG_SROMCONTROL);
1048ed6d4272Spatrick
1049ea92f6c3Spatrick if (!(sromctl & BWFM_CHIP_REG_SROMCONTROL_OTP_PRESENT))
1050ea92f6c3Spatrick return 0;
1051ea92f6c3Spatrick
1052ea92f6c3Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1053ea92f6c3Spatrick BWFM_CHIP_REG_SROMCONTROL, sromctl |
1054ea92f6c3Spatrick BWFM_CHIP_REG_SROMCONTROL_OTPSEL);
1055ed6d4272Spatrick }
1056ea92f6c3Spatrick
1057ea92f6c3Spatrick /* Map bus window to SROM/OTP shadow area */
1058ea92f6c3Spatrick page = (core->co_base + base) & ~(BWFM_PCI_BAR0_REG_SIZE - 1);
1059ea92f6c3Spatrick offset = (core->co_base + base) & (BWFM_PCI_BAR0_REG_SIZE - 1);
1060ea92f6c3Spatrick pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_BAR0_WINDOW, page);
1061ea92f6c3Spatrick
1062ea92f6c3Spatrick otp = mallocarray(words, sizeof(uint16_t), M_TEMP, M_WAITOK);
1063ea92f6c3Spatrick for (i = 0; i < words; i++)
1064ea92f6c3Spatrick ((uint16_t *)otp)[i] = bus_space_read_2(sc->sc_reg_iot,
1065ea92f6c3Spatrick sc->sc_reg_ioh, offset + i * sizeof(uint16_t));
1066ea92f6c3Spatrick
1067ea92f6c3Spatrick /* Unmap OTP */
1068ea92f6c3Spatrick if (coreid == BWFM_AGENT_CORE_CHIPCOMMON) {
1069ea92f6c3Spatrick bwfm_pci_select_core(sc, coreid);
1070ea92f6c3Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1071ea92f6c3Spatrick BWFM_CHIP_REG_SROMCONTROL, sromctl);
1072ea92f6c3Spatrick }
1073ea92f6c3Spatrick
1074ea92f6c3Spatrick for (i = 0; i < (words * sizeof(uint16_t)) - 1; i += otp[i + 1]) {
1075ea92f6c3Spatrick if (otp[i + 0] == 0)
1076ea92f6c3Spatrick break;
1077ea92f6c3Spatrick if (i + otp[i + 1] > words * sizeof(uint16_t))
1078ed6d4272Spatrick break;
1079ed6d4272Spatrick bwfm_pci_process_otp_tuple(sc, otp[i + 0], otp[i + 1],
1080ed6d4272Spatrick &otp[i + 2]);
1081ed6d4272Spatrick }
1082ed6d4272Spatrick
1083ea92f6c3Spatrick free(otp, M_TEMP, words * sizeof(uint16_t));
1084ed6d4272Spatrick return 0;
1085ed6d4272Spatrick }
1086ed6d4272Spatrick
1087ed6d4272Spatrick void
bwfm_pci_process_otp_tuple(struct bwfm_pci_softc * sc,uint8_t type,uint8_t size,uint8_t * data)1088ed6d4272Spatrick bwfm_pci_process_otp_tuple(struct bwfm_pci_softc *sc, uint8_t type, uint8_t size,
1089ed6d4272Spatrick uint8_t *data)
1090ed6d4272Spatrick {
1091ed6d4272Spatrick struct bwfm_softc *bwfm = (void *)sc;
1092ed6d4272Spatrick char chiprev[8] = "", module[8] = "", modrev[8] = "", vendor[8] = "", chip[8] = "";
1093c6a4ab0dSkettenis char board_type[128] = "";
109492fbeeb7Spatrick int len;
1095ed6d4272Spatrick
1096ed6d4272Spatrick switch (type) {
1097ed6d4272Spatrick case 0x15: /* system vendor OTP */
1098ed6d4272Spatrick DPRINTF(("%s: system vendor OTP\n", DEVNAME(sc)));
1099ed6d4272Spatrick if (size < sizeof(uint32_t))
1100ed6d4272Spatrick return;
1101ed6d4272Spatrick if (data[0] != 0x08 || data[1] != 0x00 ||
1102ed6d4272Spatrick data[2] != 0x00 || data[3] != 0x00)
1103ed6d4272Spatrick return;
1104ed6d4272Spatrick size -= sizeof(uint32_t);
1105ed6d4272Spatrick data += sizeof(uint32_t);
1106ed6d4272Spatrick while (size) {
1107ed6d4272Spatrick /* reached end */
1108ed6d4272Spatrick if (data[0] == 0xff)
1109ed6d4272Spatrick break;
1110ed6d4272Spatrick for (len = 0; len < size; len++)
1111ed6d4272Spatrick if (data[len] == 0x00 || data[len] == ' ' ||
1112ed6d4272Spatrick data[len] == 0xff)
1113ed6d4272Spatrick break;
1114ed6d4272Spatrick if (len < 3 || len > 9) /* X=abcdef */
1115ed6d4272Spatrick goto next;
1116ed6d4272Spatrick if (data[1] != '=')
1117ed6d4272Spatrick goto next;
1118ed6d4272Spatrick /* NULL-terminate string */
1119ed6d4272Spatrick if (data[len] == ' ')
1120ed6d4272Spatrick data[len] = '\0';
1121ed6d4272Spatrick switch (data[0]) {
1122ed6d4272Spatrick case 's':
1123ed6d4272Spatrick strlcpy(chiprev, &data[2], sizeof(chiprev));
1124ed6d4272Spatrick break;
1125ed6d4272Spatrick case 'M':
1126ed6d4272Spatrick strlcpy(module, &data[2], sizeof(module));
1127ed6d4272Spatrick break;
1128ed6d4272Spatrick case 'm':
1129ed6d4272Spatrick strlcpy(modrev, &data[2], sizeof(modrev));
1130ed6d4272Spatrick break;
1131ed6d4272Spatrick case 'V':
1132ed6d4272Spatrick strlcpy(vendor, &data[2], sizeof(vendor));
1133ed6d4272Spatrick break;
1134ed6d4272Spatrick }
1135ed6d4272Spatrick next:
1136ed6d4272Spatrick /* skip content */
1137ed6d4272Spatrick data += len;
1138ed6d4272Spatrick size -= len;
1139ed6d4272Spatrick /* skip spacer tag */
1140ed6d4272Spatrick if (size) {
1141ed6d4272Spatrick data++;
1142ed6d4272Spatrick size--;
1143ed6d4272Spatrick }
1144ed6d4272Spatrick }
1145ed6d4272Spatrick snprintf(chip, sizeof(chip),
1146ed6d4272Spatrick bwfm->sc_chip.ch_chip > 40000 ? "%05d" : "%04x",
1147ed6d4272Spatrick bwfm->sc_chip.ch_chip);
1148c6a4ab0dSkettenis if (sc->sc_sc.sc_node) {
1149c6a4ab0dSkettenis OF_getprop(sc->sc_sc.sc_node, "brcm,board-type",
1150c6a4ab0dSkettenis board_type, sizeof(board_type));
1151ec9994a1Skettenis if (strncmp(board_type, "apple,", 6) == 0) {
1152ec9994a1Skettenis strlcpy(sc->sc_sc.sc_fwdir, "apple-bwfm/",
1153ec9994a1Skettenis sizeof(sc->sc_sc.sc_fwdir));
1154ec9994a1Skettenis }
1155c6a4ab0dSkettenis }
1156c6a4ab0dSkettenis strlcpy(sc->sc_sc.sc_board_type, board_type,
1157c6a4ab0dSkettenis sizeof(sc->sc_sc.sc_board_type));
1158c6a4ab0dSkettenis strlcpy(sc->sc_sc.sc_module, module,
1159c6a4ab0dSkettenis sizeof(sc->sc_sc.sc_module));
1160c6a4ab0dSkettenis strlcpy(sc->sc_sc.sc_vendor, vendor,
1161c6a4ab0dSkettenis sizeof(sc->sc_sc.sc_vendor));
1162c6a4ab0dSkettenis strlcpy(sc->sc_sc.sc_modrev, modrev,
1163c6a4ab0dSkettenis sizeof(sc->sc_sc.sc_modrev));
1164ed6d4272Spatrick break;
1165ed6d4272Spatrick case 0x80: /* Broadcom CIS */
1166ed6d4272Spatrick DPRINTF(("%s: Broadcom CIS\n", DEVNAME(sc)));
1167ed6d4272Spatrick break;
1168ed6d4272Spatrick default:
1169ed6d4272Spatrick DPRINTF(("%s: unknown OTP tuple\n", DEVNAME(sc)));
1170ed6d4272Spatrick break;
1171ed6d4272Spatrick }
1172ed6d4272Spatrick }
1173ed6d4272Spatrick #endif
1174ed6d4272Spatrick
1175e5ec1e72Spatrick /* DMA code */
1176e5ec1e72Spatrick struct bwfm_pci_dmamem *
bwfm_pci_dmamem_alloc(struct bwfm_pci_softc * sc,bus_size_t size,bus_size_t align)1177e5ec1e72Spatrick bwfm_pci_dmamem_alloc(struct bwfm_pci_softc *sc, bus_size_t size, bus_size_t align)
1178e5ec1e72Spatrick {
1179e5ec1e72Spatrick struct bwfm_pci_dmamem *bdm;
1180e5ec1e72Spatrick int nsegs;
1181e5ec1e72Spatrick
1182e5ec1e72Spatrick bdm = malloc(sizeof(*bdm), M_DEVBUF, M_WAITOK | M_ZERO);
1183e5ec1e72Spatrick bdm->bdm_size = size;
1184e5ec1e72Spatrick
1185e5ec1e72Spatrick if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
1186e5ec1e72Spatrick BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &bdm->bdm_map) != 0)
1187e5ec1e72Spatrick goto bdmfree;
1188e5ec1e72Spatrick
1189e5ec1e72Spatrick if (bus_dmamem_alloc(sc->sc_dmat, size, align, 0, &bdm->bdm_seg, 1,
1190e5ec1e72Spatrick &nsegs, BUS_DMA_WAITOK) != 0)
1191e5ec1e72Spatrick goto destroy;
1192e5ec1e72Spatrick
1193e5ec1e72Spatrick if (bus_dmamem_map(sc->sc_dmat, &bdm->bdm_seg, nsegs, size,
1194e5ec1e72Spatrick &bdm->bdm_kva, BUS_DMA_WAITOK | BUS_DMA_COHERENT) != 0)
1195e5ec1e72Spatrick goto free;
1196e5ec1e72Spatrick
1197e5ec1e72Spatrick if (bus_dmamap_load(sc->sc_dmat, bdm->bdm_map, bdm->bdm_kva, size,
1198e5ec1e72Spatrick NULL, BUS_DMA_WAITOK) != 0)
1199e5ec1e72Spatrick goto unmap;
1200e5ec1e72Spatrick
1201e5ec1e72Spatrick bzero(bdm->bdm_kva, size);
1202e5ec1e72Spatrick
1203e5ec1e72Spatrick return (bdm);
1204e5ec1e72Spatrick
1205e5ec1e72Spatrick unmap:
1206e5ec1e72Spatrick bus_dmamem_unmap(sc->sc_dmat, bdm->bdm_kva, size);
1207e5ec1e72Spatrick free:
1208e5ec1e72Spatrick bus_dmamem_free(sc->sc_dmat, &bdm->bdm_seg, 1);
1209e5ec1e72Spatrick destroy:
1210e5ec1e72Spatrick bus_dmamap_destroy(sc->sc_dmat, bdm->bdm_map);
1211e5ec1e72Spatrick bdmfree:
121265046b40Spatrick free(bdm, M_DEVBUF, sizeof(*bdm));
1213e5ec1e72Spatrick
1214e5ec1e72Spatrick return (NULL);
1215e5ec1e72Spatrick }
1216e5ec1e72Spatrick
1217e5ec1e72Spatrick void
bwfm_pci_dmamem_free(struct bwfm_pci_softc * sc,struct bwfm_pci_dmamem * bdm)1218e5ec1e72Spatrick bwfm_pci_dmamem_free(struct bwfm_pci_softc *sc, struct bwfm_pci_dmamem *bdm)
1219e5ec1e72Spatrick {
1220e5ec1e72Spatrick bus_dmamem_unmap(sc->sc_dmat, bdm->bdm_kva, bdm->bdm_size);
1221e5ec1e72Spatrick bus_dmamem_free(sc->sc_dmat, &bdm->bdm_seg, 1);
1222e5ec1e72Spatrick bus_dmamap_destroy(sc->sc_dmat, bdm->bdm_map);
122365046b40Spatrick free(bdm, M_DEVBUF, sizeof(*bdm));
1224e5ec1e72Spatrick }
1225e5ec1e72Spatrick
1226e5ec1e72Spatrick /*
1227e5ec1e72Spatrick * We need a simple mapping from a packet ID to mbufs, because when
1228e5ec1e72Spatrick * a transfer completed, we only know the ID so we have to look up
1229e5ec1e72Spatrick * the memory for the ID. This simply looks for an empty slot.
1230e5ec1e72Spatrick */
1231e5ec1e72Spatrick int
bwfm_pci_pktid_avail(struct bwfm_pci_softc * sc,struct bwfm_pci_pkts * pkts)123202ee7d07Spatrick bwfm_pci_pktid_avail(struct bwfm_pci_softc *sc, struct bwfm_pci_pkts *pkts)
123302ee7d07Spatrick {
123402ee7d07Spatrick int i, idx;
123502ee7d07Spatrick
123602ee7d07Spatrick idx = pkts->last + 1;
123702ee7d07Spatrick for (i = 0; i < pkts->npkt; i++) {
123802ee7d07Spatrick if (idx == pkts->npkt)
123902ee7d07Spatrick idx = 0;
124002ee7d07Spatrick if (pkts->pkts[idx].bb_m == NULL)
124102ee7d07Spatrick return 0;
124202ee7d07Spatrick idx++;
124302ee7d07Spatrick }
124402ee7d07Spatrick return ENOBUFS;
124502ee7d07Spatrick }
124602ee7d07Spatrick
124702ee7d07Spatrick int
bwfm_pci_pktid_new(struct bwfm_pci_softc * sc,struct bwfm_pci_pkts * pkts,struct mbuf * m,uint32_t * pktid,paddr_t * paddr)1248e5ec1e72Spatrick bwfm_pci_pktid_new(struct bwfm_pci_softc *sc, struct bwfm_pci_pkts *pkts,
1249e5ec1e72Spatrick struct mbuf *m, uint32_t *pktid, paddr_t *paddr)
1250e5ec1e72Spatrick {
1251e5ec1e72Spatrick int i, idx;
1252e5ec1e72Spatrick
1253e5ec1e72Spatrick idx = pkts->last + 1;
1254e5ec1e72Spatrick for (i = 0; i < pkts->npkt; i++) {
1255e5ec1e72Spatrick if (idx == pkts->npkt)
1256e5ec1e72Spatrick idx = 0;
1257e5ec1e72Spatrick if (pkts->pkts[idx].bb_m == NULL) {
1258e5ec1e72Spatrick if (bus_dmamap_load_mbuf(sc->sc_dmat,
1259e5ec1e72Spatrick pkts->pkts[idx].bb_map, m, BUS_DMA_NOWAIT) != 0) {
1260518be5f3Spatrick if (m_defrag(m, M_DONTWAIT))
1261518be5f3Spatrick return EFBIG;
1262518be5f3Spatrick if (bus_dmamap_load_mbuf(sc->sc_dmat,
1263518be5f3Spatrick pkts->pkts[idx].bb_map, m, BUS_DMA_NOWAIT) != 0)
1264518be5f3Spatrick return EFBIG;
1265e5ec1e72Spatrick }
1266dcb67343Spatrick bus_dmamap_sync(sc->sc_dmat, pkts->pkts[idx].bb_map,
1267dcb67343Spatrick 0, pkts->pkts[idx].bb_map->dm_mapsize,
1268dcb67343Spatrick BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1269e5ec1e72Spatrick pkts->last = idx;
1270e5ec1e72Spatrick pkts->pkts[idx].bb_m = m;
1271e5ec1e72Spatrick *pktid = idx;
1272e5ec1e72Spatrick *paddr = pkts->pkts[idx].bb_map->dm_segs[0].ds_addr;
1273e5ec1e72Spatrick return 0;
1274e5ec1e72Spatrick }
1275e5ec1e72Spatrick idx++;
1276e5ec1e72Spatrick }
1277518be5f3Spatrick return ENOBUFS;
1278e5ec1e72Spatrick }
1279e5ec1e72Spatrick
1280e5ec1e72Spatrick struct mbuf *
bwfm_pci_pktid_free(struct bwfm_pci_softc * sc,struct bwfm_pci_pkts * pkts,uint32_t pktid)1281e5ec1e72Spatrick bwfm_pci_pktid_free(struct bwfm_pci_softc *sc, struct bwfm_pci_pkts *pkts,
1282e5ec1e72Spatrick uint32_t pktid)
1283e5ec1e72Spatrick {
1284e5ec1e72Spatrick struct mbuf *m;
1285e5ec1e72Spatrick
1286e5ec1e72Spatrick if (pktid >= pkts->npkt || pkts->pkts[pktid].bb_m == NULL)
1287e5ec1e72Spatrick return NULL;
1288dcb67343Spatrick bus_dmamap_sync(sc->sc_dmat, pkts->pkts[pktid].bb_map, 0,
1289dcb67343Spatrick pkts->pkts[pktid].bb_map->dm_mapsize,
1290dcb67343Spatrick BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1291e5ec1e72Spatrick bus_dmamap_unload(sc->sc_dmat, pkts->pkts[pktid].bb_map);
1292e5ec1e72Spatrick m = pkts->pkts[pktid].bb_m;
1293e5ec1e72Spatrick pkts->pkts[pktid].bb_m = NULL;
1294e5ec1e72Spatrick return m;
1295e5ec1e72Spatrick }
1296e5ec1e72Spatrick
1297e5ec1e72Spatrick void
bwfm_pci_fill_rx_rings(struct bwfm_pci_softc * sc)1298e5ec1e72Spatrick bwfm_pci_fill_rx_rings(struct bwfm_pci_softc *sc)
1299e5ec1e72Spatrick {
130018722113Spatrick bwfm_pci_fill_rx_buf_ring(sc);
1301e5ec1e72Spatrick bwfm_pci_fill_rx_ioctl_ring(sc, &sc->sc_ioctl_ring,
1302e5ec1e72Spatrick MSGBUF_TYPE_IOCTLRESP_BUF_POST);
1303e5ec1e72Spatrick bwfm_pci_fill_rx_ioctl_ring(sc, &sc->sc_event_ring,
1304e5ec1e72Spatrick MSGBUF_TYPE_EVENT_BUF_POST);
1305e5ec1e72Spatrick }
1306e5ec1e72Spatrick
1307e5ec1e72Spatrick void
bwfm_pci_fill_rx_ioctl_ring(struct bwfm_pci_softc * sc,struct if_rxring * rxring,uint32_t msgtype)1308e5ec1e72Spatrick bwfm_pci_fill_rx_ioctl_ring(struct bwfm_pci_softc *sc, struct if_rxring *rxring,
1309e5ec1e72Spatrick uint32_t msgtype)
1310e5ec1e72Spatrick {
1311e5ec1e72Spatrick struct msgbuf_rx_ioctl_resp_or_event *req;
1312e5ec1e72Spatrick struct mbuf *m;
1313e5ec1e72Spatrick uint32_t pktid;
1314e5ec1e72Spatrick paddr_t paddr;
1315e5ec1e72Spatrick int s, slots;
1316e5ec1e72Spatrick
1317e5ec1e72Spatrick s = splnet();
1318e5ec1e72Spatrick for (slots = if_rxr_get(rxring, 8); slots > 0; slots--) {
131902ee7d07Spatrick if (bwfm_pci_pktid_avail(sc, &sc->sc_rx_pkts))
132002ee7d07Spatrick break;
1321e5ec1e72Spatrick req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit);
1322e5ec1e72Spatrick if (req == NULL)
1323e5ec1e72Spatrick break;
13241950c5c5Spatrick m = MCLGETL(NULL, M_DONTWAIT, MSGBUF_MAX_CTL_PKT_SIZE);
1325e5ec1e72Spatrick if (m == NULL) {
1326e5ec1e72Spatrick bwfm_pci_ring_write_cancel(sc, &sc->sc_ctrl_submit, 1);
1327e5ec1e72Spatrick break;
1328e5ec1e72Spatrick }
13291950c5c5Spatrick m->m_len = m->m_pkthdr.len = MSGBUF_MAX_CTL_PKT_SIZE;
1330e5ec1e72Spatrick if (bwfm_pci_pktid_new(sc, &sc->sc_rx_pkts, m, &pktid, &paddr)) {
1331e5ec1e72Spatrick bwfm_pci_ring_write_cancel(sc, &sc->sc_ctrl_submit, 1);
1332e5ec1e72Spatrick m_freem(m);
1333e5ec1e72Spatrick break;
1334e5ec1e72Spatrick }
1335e5ec1e72Spatrick memset(req, 0, sizeof(*req));
1336e5ec1e72Spatrick req->msg.msgtype = msgtype;
1337e5ec1e72Spatrick req->msg.request_id = htole32(pktid);
13381950c5c5Spatrick req->host_buf_len = htole16(MSGBUF_MAX_CTL_PKT_SIZE);
1339e4dae658Spatrick req->host_buf_addr.high_addr = htole32((uint64_t)paddr >> 32);
1340e5ec1e72Spatrick req->host_buf_addr.low_addr = htole32(paddr & 0xffffffff);
1341e5ec1e72Spatrick bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit);
1342e5ec1e72Spatrick }
1343e5ec1e72Spatrick if_rxr_put(rxring, slots);
1344e5ec1e72Spatrick splx(s);
1345e5ec1e72Spatrick }
1346e5ec1e72Spatrick
1347e5ec1e72Spatrick void
bwfm_pci_fill_rx_buf_ring(struct bwfm_pci_softc * sc)1348e5ec1e72Spatrick bwfm_pci_fill_rx_buf_ring(struct bwfm_pci_softc *sc)
1349e5ec1e72Spatrick {
1350e5ec1e72Spatrick struct msgbuf_rx_bufpost *req;
1351e5ec1e72Spatrick struct mbuf *m;
1352e5ec1e72Spatrick uint32_t pktid;
1353e5ec1e72Spatrick paddr_t paddr;
1354e5ec1e72Spatrick int s, slots;
1355e5ec1e72Spatrick
1356e5ec1e72Spatrick s = splnet();
1357e5ec1e72Spatrick for (slots = if_rxr_get(&sc->sc_rxbuf_ring, sc->sc_max_rxbufpost);
1358e5ec1e72Spatrick slots > 0; slots--) {
135902ee7d07Spatrick if (bwfm_pci_pktid_avail(sc, &sc->sc_rx_pkts))
136002ee7d07Spatrick break;
1361e5ec1e72Spatrick req = bwfm_pci_ring_write_reserve(sc, &sc->sc_rxpost_submit);
1362e5ec1e72Spatrick if (req == NULL)
1363e5ec1e72Spatrick break;
1364471f2571Sjan m = MCLGETL(NULL, M_DONTWAIT, MSGBUF_MAX_PKT_SIZE);
1365e5ec1e72Spatrick if (m == NULL) {
1366e5ec1e72Spatrick bwfm_pci_ring_write_cancel(sc, &sc->sc_rxpost_submit, 1);
1367e5ec1e72Spatrick break;
1368e5ec1e72Spatrick }
1369e5ec1e72Spatrick m->m_len = m->m_pkthdr.len = MSGBUF_MAX_PKT_SIZE;
1370e5ec1e72Spatrick if (bwfm_pci_pktid_new(sc, &sc->sc_rx_pkts, m, &pktid, &paddr)) {
1371e5ec1e72Spatrick bwfm_pci_ring_write_cancel(sc, &sc->sc_rxpost_submit, 1);
1372e5ec1e72Spatrick m_freem(m);
1373e5ec1e72Spatrick break;
1374e5ec1e72Spatrick }
1375e5ec1e72Spatrick memset(req, 0, sizeof(*req));
1376e5ec1e72Spatrick req->msg.msgtype = MSGBUF_TYPE_RXBUF_POST;
1377e5ec1e72Spatrick req->msg.request_id = htole32(pktid);
1378e5ec1e72Spatrick req->data_buf_len = htole16(MSGBUF_MAX_PKT_SIZE);
1379e4dae658Spatrick req->data_buf_addr.high_addr = htole32((uint64_t)paddr >> 32);
1380e5ec1e72Spatrick req->data_buf_addr.low_addr = htole32(paddr & 0xffffffff);
1381e5ec1e72Spatrick bwfm_pci_ring_write_commit(sc, &sc->sc_rxpost_submit);
1382e5ec1e72Spatrick }
1383e5ec1e72Spatrick if_rxr_put(&sc->sc_rxbuf_ring, slots);
1384e5ec1e72Spatrick splx(s);
1385e5ec1e72Spatrick }
1386e5ec1e72Spatrick
1387e5ec1e72Spatrick int
bwfm_pci_setup_ring(struct bwfm_pci_softc * sc,struct bwfm_pci_msgring * ring,int nitem,size_t itemsz,uint32_t w_idx,uint32_t r_idx,int idx,uint32_t idx_off,uint32_t * ring_mem)1388e5ec1e72Spatrick bwfm_pci_setup_ring(struct bwfm_pci_softc *sc, struct bwfm_pci_msgring *ring,
1389e5ec1e72Spatrick int nitem, size_t itemsz, uint32_t w_idx, uint32_t r_idx,
1390e5ec1e72Spatrick int idx, uint32_t idx_off, uint32_t *ring_mem)
1391e5ec1e72Spatrick {
1392e5ec1e72Spatrick ring->w_idx_addr = w_idx + idx * idx_off;
1393e5ec1e72Spatrick ring->r_idx_addr = r_idx + idx * idx_off;
139413f544a8Spatrick ring->w_ptr = 0;
139513f544a8Spatrick ring->r_ptr = 0;
1396e5ec1e72Spatrick ring->nitem = nitem;
1397e5ec1e72Spatrick ring->itemsz = itemsz;
1398e5ec1e72Spatrick bwfm_pci_ring_write_rptr(sc, ring);
1399e5ec1e72Spatrick bwfm_pci_ring_write_wptr(sc, ring);
1400e5ec1e72Spatrick
1401e5ec1e72Spatrick ring->ring = bwfm_pci_dmamem_alloc(sc, nitem * itemsz, 8);
1402e5ec1e72Spatrick if (ring->ring == NULL)
1403e5ec1e72Spatrick return ENOMEM;
1404e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1405e5ec1e72Spatrick *ring_mem + BWFM_RING_MEM_BASE_ADDR_LOW,
1406e5ec1e72Spatrick BWFM_PCI_DMA_DVA(ring->ring) & 0xffffffff);
1407e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1408e5ec1e72Spatrick *ring_mem + BWFM_RING_MEM_BASE_ADDR_HIGH,
1409e5ec1e72Spatrick BWFM_PCI_DMA_DVA(ring->ring) >> 32);
1410e5ec1e72Spatrick bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1411e5ec1e72Spatrick *ring_mem + BWFM_RING_MAX_ITEM, nitem);
1412e5ec1e72Spatrick bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1413e5ec1e72Spatrick *ring_mem + BWFM_RING_LEN_ITEMS, itemsz);
1414e5ec1e72Spatrick *ring_mem = *ring_mem + BWFM_RING_MEM_SZ;
1415e5ec1e72Spatrick return 0;
1416e5ec1e72Spatrick }
1417e5ec1e72Spatrick
1418518be5f3Spatrick int
bwfm_pci_setup_flowring(struct bwfm_pci_softc * sc,struct bwfm_pci_msgring * ring,int nitem,size_t itemsz)1419518be5f3Spatrick bwfm_pci_setup_flowring(struct bwfm_pci_softc *sc, struct bwfm_pci_msgring *ring,
1420518be5f3Spatrick int nitem, size_t itemsz)
1421518be5f3Spatrick {
1422518be5f3Spatrick ring->w_ptr = 0;
1423518be5f3Spatrick ring->r_ptr = 0;
1424518be5f3Spatrick ring->nitem = nitem;
1425518be5f3Spatrick ring->itemsz = itemsz;
1426518be5f3Spatrick bwfm_pci_ring_write_rptr(sc, ring);
1427518be5f3Spatrick bwfm_pci_ring_write_wptr(sc, ring);
1428518be5f3Spatrick
1429518be5f3Spatrick ring->ring = bwfm_pci_dmamem_alloc(sc, nitem * itemsz, 8);
1430518be5f3Spatrick if (ring->ring == NULL)
1431518be5f3Spatrick return ENOMEM;
1432518be5f3Spatrick return 0;
1433518be5f3Spatrick }
1434518be5f3Spatrick
1435e5ec1e72Spatrick /* Ring helpers */
1436e5ec1e72Spatrick void
bwfm_pci_ring_bell(struct bwfm_pci_softc * sc,struct bwfm_pci_msgring * ring)1437e5ec1e72Spatrick bwfm_pci_ring_bell(struct bwfm_pci_softc *sc,
1438e5ec1e72Spatrick struct bwfm_pci_msgring *ring)
1439e5ec1e72Spatrick {
14408674c33cSkettenis if (sc->sc_shared_flags & BWFM_SHARED_INFO_SHARED_DAR)
1441bb813cf8Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1442bb813cf8Spatrick BWFM_PCI_64_PCIE2REG_H2D_MAILBOX_0, 1);
1443bb813cf8Spatrick else
1444e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1445156d2677Spatrick BWFM_PCI_PCIE2REG_H2D_MAILBOX_0, 1);
1446e5ec1e72Spatrick }
1447e5ec1e72Spatrick
1448e5ec1e72Spatrick void
bwfm_pci_ring_update_rptr(struct bwfm_pci_softc * sc,struct bwfm_pci_msgring * ring)1449e5ec1e72Spatrick bwfm_pci_ring_update_rptr(struct bwfm_pci_softc *sc,
1450e5ec1e72Spatrick struct bwfm_pci_msgring *ring)
1451e5ec1e72Spatrick {
1452e5ec1e72Spatrick if (sc->sc_dma_idx_sz == 0) {
1453e5ec1e72Spatrick ring->r_ptr = bus_space_read_2(sc->sc_tcm_iot,
1454e5ec1e72Spatrick sc->sc_tcm_ioh, ring->r_idx_addr);
1455e5ec1e72Spatrick } else {
1456dcb67343Spatrick bus_dmamap_sync(sc->sc_dmat,
1457dcb67343Spatrick BWFM_PCI_DMA_MAP(sc->sc_dma_idx_buf), ring->r_idx_addr,
1458dcb67343Spatrick sizeof(uint16_t), BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1459e5ec1e72Spatrick ring->r_ptr = *(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf)
1460e5ec1e72Spatrick + ring->r_idx_addr);
1461e5ec1e72Spatrick }
1462e5ec1e72Spatrick }
1463e5ec1e72Spatrick
1464e5ec1e72Spatrick void
bwfm_pci_ring_update_wptr(struct bwfm_pci_softc * sc,struct bwfm_pci_msgring * ring)1465e5ec1e72Spatrick bwfm_pci_ring_update_wptr(struct bwfm_pci_softc *sc,
1466e5ec1e72Spatrick struct bwfm_pci_msgring *ring)
1467e5ec1e72Spatrick {
1468e5ec1e72Spatrick if (sc->sc_dma_idx_sz == 0) {
1469e5ec1e72Spatrick ring->w_ptr = bus_space_read_2(sc->sc_tcm_iot,
1470e5ec1e72Spatrick sc->sc_tcm_ioh, ring->w_idx_addr);
1471e5ec1e72Spatrick } else {
1472dcb67343Spatrick bus_dmamap_sync(sc->sc_dmat,
1473dcb67343Spatrick BWFM_PCI_DMA_MAP(sc->sc_dma_idx_buf), ring->w_idx_addr,
1474dcb67343Spatrick sizeof(uint16_t), BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1475e5ec1e72Spatrick ring->w_ptr = *(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf)
1476e5ec1e72Spatrick + ring->w_idx_addr);
1477e5ec1e72Spatrick }
1478e5ec1e72Spatrick }
1479e5ec1e72Spatrick
1480e5ec1e72Spatrick void
bwfm_pci_ring_write_rptr(struct bwfm_pci_softc * sc,struct bwfm_pci_msgring * ring)1481e5ec1e72Spatrick bwfm_pci_ring_write_rptr(struct bwfm_pci_softc *sc,
1482e5ec1e72Spatrick struct bwfm_pci_msgring *ring)
1483e5ec1e72Spatrick {
1484e5ec1e72Spatrick if (sc->sc_dma_idx_sz == 0) {
1485e5ec1e72Spatrick bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1486e5ec1e72Spatrick ring->r_idx_addr, ring->r_ptr);
1487e5ec1e72Spatrick } else {
1488e5ec1e72Spatrick *(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf)
1489e5ec1e72Spatrick + ring->r_idx_addr) = ring->r_ptr;
1490dcb67343Spatrick bus_dmamap_sync(sc->sc_dmat,
1491dcb67343Spatrick BWFM_PCI_DMA_MAP(sc->sc_dma_idx_buf), ring->r_idx_addr,
1492dcb67343Spatrick sizeof(uint16_t), BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1493e5ec1e72Spatrick }
1494e5ec1e72Spatrick }
1495e5ec1e72Spatrick
1496e5ec1e72Spatrick void
bwfm_pci_ring_write_wptr(struct bwfm_pci_softc * sc,struct bwfm_pci_msgring * ring)1497e5ec1e72Spatrick bwfm_pci_ring_write_wptr(struct bwfm_pci_softc *sc,
1498e5ec1e72Spatrick struct bwfm_pci_msgring *ring)
1499e5ec1e72Spatrick {
1500e5ec1e72Spatrick if (sc->sc_dma_idx_sz == 0) {
1501e5ec1e72Spatrick bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh,
1502e5ec1e72Spatrick ring->w_idx_addr, ring->w_ptr);
1503e5ec1e72Spatrick } else {
1504e5ec1e72Spatrick *(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf)
1505e5ec1e72Spatrick + ring->w_idx_addr) = ring->w_ptr;
1506dcb67343Spatrick bus_dmamap_sync(sc->sc_dmat,
1507dcb67343Spatrick BWFM_PCI_DMA_MAP(sc->sc_dma_idx_buf), ring->w_idx_addr,
1508dcb67343Spatrick sizeof(uint16_t), BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1509e5ec1e72Spatrick }
1510e5ec1e72Spatrick }
1511e5ec1e72Spatrick
1512e5ec1e72Spatrick /*
1513e5ec1e72Spatrick * Retrieve a free descriptor to put new stuff in, but don't commit
1514e5ec1e72Spatrick * to it yet so we can rollback later if any error occurs.
1515e5ec1e72Spatrick */
1516e5ec1e72Spatrick void *
bwfm_pci_ring_write_reserve(struct bwfm_pci_softc * sc,struct bwfm_pci_msgring * ring)1517e5ec1e72Spatrick bwfm_pci_ring_write_reserve(struct bwfm_pci_softc *sc,
1518e5ec1e72Spatrick struct bwfm_pci_msgring *ring)
1519e5ec1e72Spatrick {
1520e5ec1e72Spatrick int available;
1521e5ec1e72Spatrick char *ret;
1522e5ec1e72Spatrick
1523e5ec1e72Spatrick bwfm_pci_ring_update_rptr(sc, ring);
1524e5ec1e72Spatrick
1525e5ec1e72Spatrick if (ring->r_ptr > ring->w_ptr)
1526e5ec1e72Spatrick available = ring->r_ptr - ring->w_ptr;
1527e5ec1e72Spatrick else
1528e5ec1e72Spatrick available = ring->r_ptr + (ring->nitem - ring->w_ptr);
1529e5ec1e72Spatrick
153030f5ada0Spatrick if (available <= 1)
1531e5ec1e72Spatrick return NULL;
1532e5ec1e72Spatrick
1533e5ec1e72Spatrick ret = BWFM_PCI_DMA_KVA(ring->ring) + (ring->w_ptr * ring->itemsz);
1534e5ec1e72Spatrick ring->w_ptr += 1;
1535e5ec1e72Spatrick if (ring->w_ptr == ring->nitem)
1536e5ec1e72Spatrick ring->w_ptr = 0;
1537e5ec1e72Spatrick return ret;
1538e5ec1e72Spatrick }
1539e5ec1e72Spatrick
1540e5ec1e72Spatrick void *
bwfm_pci_ring_write_reserve_multi(struct bwfm_pci_softc * sc,struct bwfm_pci_msgring * ring,int count,int * avail)1541e5ec1e72Spatrick bwfm_pci_ring_write_reserve_multi(struct bwfm_pci_softc *sc,
1542e5ec1e72Spatrick struct bwfm_pci_msgring *ring, int count, int *avail)
1543e5ec1e72Spatrick {
1544e5ec1e72Spatrick int available;
1545e5ec1e72Spatrick char *ret;
1546e5ec1e72Spatrick
1547e5ec1e72Spatrick bwfm_pci_ring_update_rptr(sc, ring);
1548e5ec1e72Spatrick
1549e5ec1e72Spatrick if (ring->r_ptr > ring->w_ptr)
1550e5ec1e72Spatrick available = ring->r_ptr - ring->w_ptr;
1551e5ec1e72Spatrick else
1552e5ec1e72Spatrick available = ring->r_ptr + (ring->nitem - ring->w_ptr);
1553e5ec1e72Spatrick
155430f5ada0Spatrick if (available <= 1)
1555e5ec1e72Spatrick return NULL;
1556e5ec1e72Spatrick
1557e5ec1e72Spatrick ret = BWFM_PCI_DMA_KVA(ring->ring) + (ring->w_ptr * ring->itemsz);
1558e5ec1e72Spatrick *avail = min(count, available - 1);
1559e5ec1e72Spatrick if (*avail + ring->w_ptr > ring->nitem)
1560e5ec1e72Spatrick *avail = ring->nitem - ring->w_ptr;
1561e5ec1e72Spatrick ring->w_ptr += *avail;
1562e5ec1e72Spatrick if (ring->w_ptr == ring->nitem)
1563e5ec1e72Spatrick ring->w_ptr = 0;
1564e5ec1e72Spatrick return ret;
1565e5ec1e72Spatrick }
1566e5ec1e72Spatrick
1567e5ec1e72Spatrick /*
1568e5ec1e72Spatrick * Read number of descriptors available (submitted by the firmware)
1569e5ec1e72Spatrick * and retrieve pointer to first descriptor.
1570e5ec1e72Spatrick */
1571e5ec1e72Spatrick void *
bwfm_pci_ring_read_avail(struct bwfm_pci_softc * sc,struct bwfm_pci_msgring * ring,int * avail)1572e5ec1e72Spatrick bwfm_pci_ring_read_avail(struct bwfm_pci_softc *sc,
1573e5ec1e72Spatrick struct bwfm_pci_msgring *ring, int *avail)
1574e5ec1e72Spatrick {
1575e5ec1e72Spatrick bwfm_pci_ring_update_wptr(sc, ring);
1576e5ec1e72Spatrick
1577e5ec1e72Spatrick if (ring->w_ptr >= ring->r_ptr)
1578e5ec1e72Spatrick *avail = ring->w_ptr - ring->r_ptr;
1579e5ec1e72Spatrick else
1580e5ec1e72Spatrick *avail = ring->nitem - ring->r_ptr;
1581e5ec1e72Spatrick
1582e5ec1e72Spatrick if (*avail == 0)
1583e5ec1e72Spatrick return NULL;
1584e5ec1e72Spatrick
1585dcb67343Spatrick bus_dmamap_sync(sc->sc_dmat, BWFM_PCI_DMA_MAP(ring->ring),
1586dcb67343Spatrick ring->r_ptr * ring->itemsz, *avail * ring->itemsz,
1587dcb67343Spatrick BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1588e5ec1e72Spatrick return BWFM_PCI_DMA_KVA(ring->ring) + (ring->r_ptr * ring->itemsz);
1589e5ec1e72Spatrick }
1590e5ec1e72Spatrick
1591e5ec1e72Spatrick /*
1592e5ec1e72Spatrick * Let firmware know we read N descriptors.
1593e5ec1e72Spatrick */
1594e5ec1e72Spatrick void
bwfm_pci_ring_read_commit(struct bwfm_pci_softc * sc,struct bwfm_pci_msgring * ring,int nitem)1595e5ec1e72Spatrick bwfm_pci_ring_read_commit(struct bwfm_pci_softc *sc,
1596e5ec1e72Spatrick struct bwfm_pci_msgring *ring, int nitem)
1597e5ec1e72Spatrick {
1598e5ec1e72Spatrick ring->r_ptr += nitem;
1599e5ec1e72Spatrick if (ring->r_ptr == ring->nitem)
1600e5ec1e72Spatrick ring->r_ptr = 0;
1601e5ec1e72Spatrick bwfm_pci_ring_write_rptr(sc, ring);
1602e5ec1e72Spatrick }
1603e5ec1e72Spatrick
1604e5ec1e72Spatrick /*
1605e5ec1e72Spatrick * Let firmware know that we submitted some descriptors.
1606e5ec1e72Spatrick */
1607e5ec1e72Spatrick void
bwfm_pci_ring_write_commit(struct bwfm_pci_softc * sc,struct bwfm_pci_msgring * ring)1608e5ec1e72Spatrick bwfm_pci_ring_write_commit(struct bwfm_pci_softc *sc,
1609e5ec1e72Spatrick struct bwfm_pci_msgring *ring)
1610e5ec1e72Spatrick {
1611dcb67343Spatrick bus_dmamap_sync(sc->sc_dmat, BWFM_PCI_DMA_MAP(ring->ring),
1612dcb67343Spatrick 0, BWFM_PCI_DMA_LEN(ring->ring), BUS_DMASYNC_PREREAD |
1613dcb67343Spatrick BUS_DMASYNC_PREWRITE);
1614e5ec1e72Spatrick bwfm_pci_ring_write_wptr(sc, ring);
1615e5ec1e72Spatrick bwfm_pci_ring_bell(sc, ring);
1616e5ec1e72Spatrick }
1617e5ec1e72Spatrick
1618e5ec1e72Spatrick /*
1619e5ec1e72Spatrick * Rollback N descriptors in case we don't actually want
1620e5ec1e72Spatrick * to commit to it.
1621e5ec1e72Spatrick */
1622e5ec1e72Spatrick void
bwfm_pci_ring_write_cancel(struct bwfm_pci_softc * sc,struct bwfm_pci_msgring * ring,int nitem)1623e5ec1e72Spatrick bwfm_pci_ring_write_cancel(struct bwfm_pci_softc *sc,
1624e5ec1e72Spatrick struct bwfm_pci_msgring *ring, int nitem)
1625e5ec1e72Spatrick {
1626e5ec1e72Spatrick if (ring->w_ptr == 0)
1627e5ec1e72Spatrick ring->w_ptr = ring->nitem - nitem;
1628e5ec1e72Spatrick else
1629e5ec1e72Spatrick ring->w_ptr -= nitem;
1630e5ec1e72Spatrick }
1631e5ec1e72Spatrick
1632e5ec1e72Spatrick /*
1633e5ec1e72Spatrick * Foreach written descriptor on the ring, pass the descriptor to
1634e5ec1e72Spatrick * a message handler and let the firmware know we handled it.
1635e5ec1e72Spatrick */
1636e5ec1e72Spatrick void
bwfm_pci_ring_rx(struct bwfm_pci_softc * sc,struct bwfm_pci_msgring * ring,struct mbuf_list * ml)16376f241297Spatrick bwfm_pci_ring_rx(struct bwfm_pci_softc *sc, struct bwfm_pci_msgring *ring,
16386f241297Spatrick struct mbuf_list *ml)
1639e5ec1e72Spatrick {
1640e5ec1e72Spatrick void *buf;
1641e5ec1e72Spatrick int avail, processed;
1642e5ec1e72Spatrick
1643e5ec1e72Spatrick again:
1644e5ec1e72Spatrick buf = bwfm_pci_ring_read_avail(sc, ring, &avail);
1645e5ec1e72Spatrick if (buf == NULL)
1646e5ec1e72Spatrick return;
1647e5ec1e72Spatrick
1648e5ec1e72Spatrick processed = 0;
1649e5ec1e72Spatrick while (avail) {
16506f241297Spatrick bwfm_pci_msg_rx(sc, buf + sc->sc_rx_dataoffset, ml);
1651e5ec1e72Spatrick buf += ring->itemsz;
1652e5ec1e72Spatrick processed++;
1653e5ec1e72Spatrick if (processed == 48) {
1654e5ec1e72Spatrick bwfm_pci_ring_read_commit(sc, ring, processed);
1655e5ec1e72Spatrick processed = 0;
1656e5ec1e72Spatrick }
1657e5ec1e72Spatrick avail--;
1658e5ec1e72Spatrick }
1659e5ec1e72Spatrick if (processed)
1660e5ec1e72Spatrick bwfm_pci_ring_read_commit(sc, ring, processed);
1661e5ec1e72Spatrick if (ring->r_ptr == 0)
1662e5ec1e72Spatrick goto again;
1663e5ec1e72Spatrick }
1664e5ec1e72Spatrick
1665e5ec1e72Spatrick void
bwfm_pci_msg_rx(struct bwfm_pci_softc * sc,void * buf,struct mbuf_list * ml)16666f241297Spatrick bwfm_pci_msg_rx(struct bwfm_pci_softc *sc, void *buf, struct mbuf_list *ml)
1667e5ec1e72Spatrick {
1668518be5f3Spatrick struct ifnet *ifp = &sc->sc_sc.sc_ic.ic_if;
1669e5ec1e72Spatrick struct msgbuf_ioctl_resp_hdr *resp;
1670518be5f3Spatrick struct msgbuf_tx_status *tx;
167118722113Spatrick struct msgbuf_rx_complete *rx;
1672e5ec1e72Spatrick struct msgbuf_rx_event *event;
16738674c33cSkettenis struct msgbuf_d2h_mailbox_data *d2h;
1674e5ec1e72Spatrick struct msgbuf_common_hdr *msg;
1675518be5f3Spatrick struct msgbuf_flowring_create_resp *fcr;
1676a2c6ff8bSpatrick struct msgbuf_flowring_delete_resp *fdr;
1677b5553ee6Spatrick struct bwfm_cmd_flowring_create fdcmd;
1678518be5f3Spatrick struct bwfm_pci_msgring *ring;
1679e5ec1e72Spatrick struct mbuf *m;
1680518be5f3Spatrick int flowid;
1681e5ec1e72Spatrick
1682e5ec1e72Spatrick msg = (struct msgbuf_common_hdr *)buf;
1683e5ec1e72Spatrick switch (msg->msgtype)
1684e5ec1e72Spatrick {
1685518be5f3Spatrick case MSGBUF_TYPE_FLOW_RING_CREATE_CMPLT:
1686518be5f3Spatrick fcr = (struct msgbuf_flowring_create_resp *)buf;
1687518be5f3Spatrick flowid = letoh16(fcr->compl_hdr.flow_ring_id);
1688518be5f3Spatrick if (flowid < 2)
1689518be5f3Spatrick break;
1690518be5f3Spatrick flowid -= 2;
1691518be5f3Spatrick if (flowid >= sc->sc_max_flowrings)
1692518be5f3Spatrick break;
1693518be5f3Spatrick ring = &sc->sc_flowrings[flowid];
1694518be5f3Spatrick if (ring->status != RING_OPENING)
1695518be5f3Spatrick break;
1696518be5f3Spatrick if (fcr->compl_hdr.status) {
1697518be5f3Spatrick printf("%s: failed to open flowring %d\n",
1698518be5f3Spatrick DEVNAME(sc), flowid);
1699518be5f3Spatrick ring->status = RING_CLOSED;
170002ee7d07Spatrick if (ring->m) {
170102ee7d07Spatrick m_freem(ring->m);
170202ee7d07Spatrick ring->m = NULL;
170302ee7d07Spatrick }
1704518be5f3Spatrick ifq_restart(&ifp->if_snd);
1705518be5f3Spatrick break;
1706518be5f3Spatrick }
1707518be5f3Spatrick ring->status = RING_OPEN;
170802ee7d07Spatrick if (ring->m != NULL) {
170902ee7d07Spatrick m = ring->m;
171002ee7d07Spatrick ring->m = NULL;
171102ee7d07Spatrick if (bwfm_pci_txdata(&sc->sc_sc, m))
171202ee7d07Spatrick m_freem(ring->m);
171302ee7d07Spatrick }
1714518be5f3Spatrick ifq_restart(&ifp->if_snd);
1715518be5f3Spatrick break;
1716a2c6ff8bSpatrick case MSGBUF_TYPE_FLOW_RING_DELETE_CMPLT:
1717a2c6ff8bSpatrick fdr = (struct msgbuf_flowring_delete_resp *)buf;
1718a2c6ff8bSpatrick flowid = letoh16(fdr->compl_hdr.flow_ring_id);
1719a2c6ff8bSpatrick if (flowid < 2)
1720a2c6ff8bSpatrick break;
1721a2c6ff8bSpatrick flowid -= 2;
1722a2c6ff8bSpatrick if (flowid >= sc->sc_max_flowrings)
1723a2c6ff8bSpatrick break;
1724a2c6ff8bSpatrick ring = &sc->sc_flowrings[flowid];
1725a2c6ff8bSpatrick if (ring->status != RING_CLOSING)
1726a2c6ff8bSpatrick break;
1727a2c6ff8bSpatrick if (fdr->compl_hdr.status) {
1728a2c6ff8bSpatrick printf("%s: failed to delete flowring %d\n",
1729a2c6ff8bSpatrick DEVNAME(sc), flowid);
1730a2c6ff8bSpatrick break;
1731a2c6ff8bSpatrick }
1732b5553ee6Spatrick fdcmd.flowid = flowid;
1733b5553ee6Spatrick bwfm_do_async(&sc->sc_sc, bwfm_pci_flowring_delete_cb,
1734b5553ee6Spatrick &fdcmd, sizeof(fdcmd));
1735a2c6ff8bSpatrick break;
1736e5ec1e72Spatrick case MSGBUF_TYPE_IOCTLPTR_REQ_ACK:
17372eeba925Spatrick m = bwfm_pci_pktid_free(sc, &sc->sc_ioctl_pkts,
17382eeba925Spatrick letoh32(msg->request_id));
17392eeba925Spatrick if (m == NULL)
17402eeba925Spatrick break;
17412eeba925Spatrick m_freem(m);
1742e5ec1e72Spatrick break;
1743e5ec1e72Spatrick case MSGBUF_TYPE_IOCTL_CMPLT:
1744e5ec1e72Spatrick resp = (struct msgbuf_ioctl_resp_hdr *)buf;
17452eeba925Spatrick bwfm_pci_msgbuf_rxioctl(sc, resp);
1746e5ec1e72Spatrick if_rxr_put(&sc->sc_ioctl_ring, 1);
1747e5ec1e72Spatrick bwfm_pci_fill_rx_rings(sc);
1748e5ec1e72Spatrick break;
1749e5ec1e72Spatrick case MSGBUF_TYPE_WL_EVENT:
1750e5ec1e72Spatrick event = (struct msgbuf_rx_event *)buf;
1751e5ec1e72Spatrick m = bwfm_pci_pktid_free(sc, &sc->sc_rx_pkts,
1752e5ec1e72Spatrick letoh32(event->msg.request_id));
1753e5ec1e72Spatrick if (m == NULL)
1754e5ec1e72Spatrick break;
1755e5ec1e72Spatrick m_adj(m, sc->sc_rx_dataoffset);
1756f37fc236Spatrick m->m_len = m->m_pkthdr.len = letoh16(event->event_data_len);
17576f241297Spatrick bwfm_rx(&sc->sc_sc, m, ml);
1758e5ec1e72Spatrick if_rxr_put(&sc->sc_event_ring, 1);
1759e5ec1e72Spatrick bwfm_pci_fill_rx_rings(sc);
1760e5ec1e72Spatrick break;
1761518be5f3Spatrick case MSGBUF_TYPE_TX_STATUS:
1762518be5f3Spatrick tx = (struct msgbuf_tx_status *)buf;
1763518be5f3Spatrick m = bwfm_pci_pktid_free(sc, &sc->sc_tx_pkts,
1764f9ee104fSpatrick letoh32(tx->msg.request_id) - 1);
1765518be5f3Spatrick if (m == NULL)
1766518be5f3Spatrick break;
1767518be5f3Spatrick m_freem(m);
1768c6f1636dSpatrick if (sc->sc_tx_pkts_full) {
1769c6f1636dSpatrick sc->sc_tx_pkts_full = 0;
1770c6f1636dSpatrick ifq_restart(&ifp->if_snd);
1771c6f1636dSpatrick }
1772518be5f3Spatrick break;
177318722113Spatrick case MSGBUF_TYPE_RX_CMPLT:
177418722113Spatrick rx = (struct msgbuf_rx_complete *)buf;
177518722113Spatrick m = bwfm_pci_pktid_free(sc, &sc->sc_rx_pkts,
177618722113Spatrick letoh32(rx->msg.request_id));
177718722113Spatrick if (m == NULL)
177818722113Spatrick break;
177918722113Spatrick if (letoh16(rx->data_offset))
178018722113Spatrick m_adj(m, letoh16(rx->data_offset));
178118722113Spatrick else if (sc->sc_rx_dataoffset)
178218722113Spatrick m_adj(m, sc->sc_rx_dataoffset);
1783f37fc236Spatrick m->m_len = m->m_pkthdr.len = letoh16(rx->data_len);
17846f241297Spatrick bwfm_rx(&sc->sc_sc, m, ml);
178518722113Spatrick if_rxr_put(&sc->sc_rxbuf_ring, 1);
178618722113Spatrick bwfm_pci_fill_rx_rings(sc);
178718722113Spatrick break;
17888674c33cSkettenis case MSGBUF_TYPE_D2H_MAILBOX_DATA:
17898674c33cSkettenis d2h = (struct msgbuf_d2h_mailbox_data *)buf;
17908674c33cSkettenis if (d2h->data & BWFM_PCI_D2H_DEV_D3_ACK) {
17918674c33cSkettenis sc->sc_mbdata_done = 1;
17928674c33cSkettenis wakeup(&sc->sc_mbdata_done);
17938674c33cSkettenis }
17948674c33cSkettenis break;
1795e5ec1e72Spatrick default:
1796e5ec1e72Spatrick printf("%s: msgtype 0x%08x\n", __func__, msg->msgtype);
1797e5ec1e72Spatrick break;
1798e5ec1e72Spatrick }
1799e5ec1e72Spatrick }
1800e5ec1e72Spatrick
1801e5ec1e72Spatrick /* Bus core helpers */
1802e5ec1e72Spatrick void
bwfm_pci_select_core(struct bwfm_pci_softc * sc,int id)1803e5ec1e72Spatrick bwfm_pci_select_core(struct bwfm_pci_softc *sc, int id)
1804e5ec1e72Spatrick {
1805e5ec1e72Spatrick struct bwfm_softc *bwfm = (void *)sc;
1806e5ec1e72Spatrick struct bwfm_core *core;
1807e5ec1e72Spatrick
1808e5ec1e72Spatrick core = bwfm_chip_get_core(bwfm, id);
1809e5ec1e72Spatrick if (core == NULL) {
1810e5ec1e72Spatrick printf("%s: could not find core to select", DEVNAME(sc));
1811e5ec1e72Spatrick return;
1812e5ec1e72Spatrick }
1813e5ec1e72Spatrick
1814e5ec1e72Spatrick pci_conf_write(sc->sc_pc, sc->sc_tag,
1815e5ec1e72Spatrick BWFM_PCI_BAR0_WINDOW, core->co_base);
1816e5ec1e72Spatrick if (pci_conf_read(sc->sc_pc, sc->sc_tag,
1817e5ec1e72Spatrick BWFM_PCI_BAR0_WINDOW) != core->co_base)
1818e5ec1e72Spatrick pci_conf_write(sc->sc_pc, sc->sc_tag,
1819e5ec1e72Spatrick BWFM_PCI_BAR0_WINDOW, core->co_base);
1820e5ec1e72Spatrick }
1821e5ec1e72Spatrick
1822e5ec1e72Spatrick uint32_t
bwfm_pci_buscore_read(struct bwfm_softc * bwfm,uint32_t reg)1823e5ec1e72Spatrick bwfm_pci_buscore_read(struct bwfm_softc *bwfm, uint32_t reg)
1824e5ec1e72Spatrick {
1825e5ec1e72Spatrick struct bwfm_pci_softc *sc = (void *)bwfm;
1826e5ec1e72Spatrick uint32_t page, offset;
1827e5ec1e72Spatrick
1828e5ec1e72Spatrick page = reg & ~(BWFM_PCI_BAR0_REG_SIZE - 1);
1829e5ec1e72Spatrick offset = reg & (BWFM_PCI_BAR0_REG_SIZE - 1);
1830e5ec1e72Spatrick pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_BAR0_WINDOW, page);
1831e5ec1e72Spatrick return bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh, offset);
1832e5ec1e72Spatrick }
1833e5ec1e72Spatrick
1834e5ec1e72Spatrick void
bwfm_pci_buscore_write(struct bwfm_softc * bwfm,uint32_t reg,uint32_t val)1835e5ec1e72Spatrick bwfm_pci_buscore_write(struct bwfm_softc *bwfm, uint32_t reg, uint32_t val)
1836e5ec1e72Spatrick {
1837e5ec1e72Spatrick struct bwfm_pci_softc *sc = (void *)bwfm;
1838e5ec1e72Spatrick uint32_t page, offset;
1839e5ec1e72Spatrick
1840e5ec1e72Spatrick page = reg & ~(BWFM_PCI_BAR0_REG_SIZE - 1);
1841e5ec1e72Spatrick offset = reg & (BWFM_PCI_BAR0_REG_SIZE - 1);
1842e5ec1e72Spatrick pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_BAR0_WINDOW, page);
1843e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, offset, val);
1844e5ec1e72Spatrick }
1845e5ec1e72Spatrick
1846e5ec1e72Spatrick int
bwfm_pci_buscore_prepare(struct bwfm_softc * bwfm)1847e5ec1e72Spatrick bwfm_pci_buscore_prepare(struct bwfm_softc *bwfm)
1848e5ec1e72Spatrick {
1849e5ec1e72Spatrick return 0;
1850e5ec1e72Spatrick }
1851e5ec1e72Spatrick
1852e5ec1e72Spatrick int
bwfm_pci_buscore_reset(struct bwfm_softc * bwfm)1853e5ec1e72Spatrick bwfm_pci_buscore_reset(struct bwfm_softc *bwfm)
1854e5ec1e72Spatrick {
1855e5ec1e72Spatrick struct bwfm_pci_softc *sc = (void *)bwfm;
1856e5ec1e72Spatrick struct bwfm_core *core;
1857e5ec1e72Spatrick uint32_t reg;
1858e5ec1e72Spatrick int i;
1859e5ec1e72Spatrick
1860e5ec1e72Spatrick bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2);
1861e5ec1e72Spatrick reg = pci_conf_read(sc->sc_pc, sc->sc_tag,
1862e5ec1e72Spatrick BWFM_PCI_CFGREG_LINK_STATUS_CTRL);
1863e5ec1e72Spatrick pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_CFGREG_LINK_STATUS_CTRL,
1864e5ec1e72Spatrick reg & ~BWFM_PCI_CFGREG_LINK_STATUS_CTRL_ASPM_ENAB);
1865e5ec1e72Spatrick
1866e5ec1e72Spatrick bwfm_pci_select_core(sc, BWFM_AGENT_CORE_CHIPCOMMON);
1867e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1868e5ec1e72Spatrick BWFM_CHIP_REG_WATCHDOG, 4);
1869e5ec1e72Spatrick delay(100 * 1000);
1870e5ec1e72Spatrick
1871e5ec1e72Spatrick bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2);
1872e5ec1e72Spatrick pci_conf_write(sc->sc_pc, sc->sc_tag,
1873e5ec1e72Spatrick BWFM_PCI_CFGREG_LINK_STATUS_CTRL, reg);
1874e5ec1e72Spatrick
1875e5ec1e72Spatrick core = bwfm_chip_get_core(bwfm, BWFM_AGENT_CORE_PCIE2);
1876e5ec1e72Spatrick if (core->co_rev <= 13) {
1877e5ec1e72Spatrick uint16_t cfg_offset[] = {
1878e5ec1e72Spatrick BWFM_PCI_CFGREG_STATUS_CMD,
1879e5ec1e72Spatrick BWFM_PCI_CFGREG_PM_CSR,
1880e5ec1e72Spatrick BWFM_PCI_CFGREG_MSI_CAP,
1881e5ec1e72Spatrick BWFM_PCI_CFGREG_MSI_ADDR_L,
1882e5ec1e72Spatrick BWFM_PCI_CFGREG_MSI_ADDR_H,
1883e5ec1e72Spatrick BWFM_PCI_CFGREG_MSI_DATA,
1884e5ec1e72Spatrick BWFM_PCI_CFGREG_LINK_STATUS_CTRL2,
1885e5ec1e72Spatrick BWFM_PCI_CFGREG_RBAR_CTRL,
1886e5ec1e72Spatrick BWFM_PCI_CFGREG_PML1_SUB_CTRL1,
1887e5ec1e72Spatrick BWFM_PCI_CFGREG_REG_BAR2_CONFIG,
1888e5ec1e72Spatrick BWFM_PCI_CFGREG_REG_BAR3_CONFIG,
1889e5ec1e72Spatrick };
1890e5ec1e72Spatrick
1891e5ec1e72Spatrick for (i = 0; i < nitems(cfg_offset); i++) {
1892e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1893e5ec1e72Spatrick BWFM_PCI_PCIE2REG_CONFIGADDR, cfg_offset[i]);
1894e5ec1e72Spatrick reg = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1895e5ec1e72Spatrick BWFM_PCI_PCIE2REG_CONFIGDATA);
1896e5ec1e72Spatrick DPRINTFN(3, ("%s: config offset 0x%04x, value 0x%04x\n",
1897e5ec1e72Spatrick DEVNAME(sc), cfg_offset[i], reg));
1898e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
1899e5ec1e72Spatrick BWFM_PCI_PCIE2REG_CONFIGDATA, reg);
1900e5ec1e72Spatrick }
1901e5ec1e72Spatrick }
19028bad4727Spatrick if (core->co_rev >= 64)
19038bad4727Spatrick sc->sc_pcireg64 = 1;
1904e5ec1e72Spatrick
1905bb813cf8Spatrick reg = bwfm_pci_intr_status(sc);
1906e5ec1e72Spatrick if (reg != 0xffffffff)
1907bb813cf8Spatrick bwfm_pci_intr_ack(sc, reg);
1908e5ec1e72Spatrick
1909e5ec1e72Spatrick return 0;
1910e5ec1e72Spatrick }
1911e5ec1e72Spatrick
1912e5ec1e72Spatrick void
bwfm_pci_buscore_activate(struct bwfm_softc * bwfm,uint32_t rstvec)1913e5ec1e72Spatrick bwfm_pci_buscore_activate(struct bwfm_softc *bwfm, uint32_t rstvec)
1914e5ec1e72Spatrick {
1915e5ec1e72Spatrick struct bwfm_pci_softc *sc = (void *)bwfm;
1916e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 0, rstvec);
1917e5ec1e72Spatrick }
1918e5ec1e72Spatrick
1919f67437f3Spatrick static int bwfm_pci_prio2fifo[8] = {
19209e2c067eSpatrick 0, /* best effort */
19219e2c067eSpatrick 1, /* IPTOS_PREC_IMMEDIATE */
19229e2c067eSpatrick 1, /* IPTOS_PREC_PRIORITY */
19239e2c067eSpatrick 0, /* IPTOS_PREC_FLASH */
1924f67437f3Spatrick 2, /* IPTOS_PREC_FLASHOVERRIDE */
1925f67437f3Spatrick 2, /* IPTOS_PREC_CRITIC_ECP */
1926f67437f3Spatrick 3, /* IPTOS_PREC_INTERNETCONTROL */
1927f67437f3Spatrick 3, /* IPTOS_PREC_NETCONTROL */
1928f67437f3Spatrick };
1929f67437f3Spatrick
1930f67437f3Spatrick int
bwfm_pci_flowring_lookup(struct bwfm_pci_softc * sc,struct mbuf * m)1931f67437f3Spatrick bwfm_pci_flowring_lookup(struct bwfm_pci_softc *sc, struct mbuf *m)
1932518be5f3Spatrick {
1933f67437f3Spatrick struct ieee80211com *ic = &sc->sc_sc.sc_ic;
1934e6abcda3Smlarkin #ifndef IEEE80211_STA_ONLY
1935f67437f3Spatrick uint8_t *da = mtod(m, uint8_t *);
1936e6abcda3Smlarkin #endif
1937f67437f3Spatrick int flowid, prio, fifo;
1938f67437f3Spatrick int i, found;
1939f67437f3Spatrick
1940f67437f3Spatrick prio = ieee80211_classify(ic, m);
1941f67437f3Spatrick fifo = bwfm_pci_prio2fifo[prio];
1942f67437f3Spatrick
1943f67437f3Spatrick switch (ic->ic_opmode)
1944f67437f3Spatrick {
1945f67437f3Spatrick case IEEE80211_M_STA:
1946f67437f3Spatrick flowid = fifo;
1947f67437f3Spatrick break;
1948f67437f3Spatrick #ifndef IEEE80211_STA_ONLY
1949f67437f3Spatrick case IEEE80211_M_HOSTAP:
19502b7bea7eSpatrick if (ETHER_IS_MULTICAST(da))
19512b7bea7eSpatrick da = etherbroadcastaddr;
1952f67437f3Spatrick flowid = da[5] * 2 + fifo;
1953f67437f3Spatrick break;
1954f67437f3Spatrick #endif
1955f67437f3Spatrick default:
1956f67437f3Spatrick printf("%s: state not supported\n", DEVNAME(sc));
1957f67437f3Spatrick return ENOBUFS;
1958f67437f3Spatrick }
1959f67437f3Spatrick
1960f67437f3Spatrick found = 0;
1961f67437f3Spatrick flowid = flowid % sc->sc_max_flowrings;
1962f67437f3Spatrick for (i = 0; i < sc->sc_max_flowrings; i++) {
1963f67437f3Spatrick if (ic->ic_opmode == IEEE80211_M_STA &&
1964f67437f3Spatrick sc->sc_flowrings[flowid].status >= RING_OPEN &&
1965f67437f3Spatrick sc->sc_flowrings[flowid].fifo == fifo) {
1966f67437f3Spatrick found = 1;
1967f67437f3Spatrick break;
1968f67437f3Spatrick }
1969f67437f3Spatrick #ifndef IEEE80211_STA_ONLY
1970f67437f3Spatrick if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
1971f67437f3Spatrick sc->sc_flowrings[flowid].status >= RING_OPEN &&
1972f67437f3Spatrick sc->sc_flowrings[flowid].fifo == fifo &&
1973a2c6ff8bSpatrick !memcmp(sc->sc_flowrings[flowid].mac, da, ETHER_ADDR_LEN)) {
1974f67437f3Spatrick found = 1;
1975f67437f3Spatrick break;
1976f67437f3Spatrick }
1977f67437f3Spatrick #endif
1978f67437f3Spatrick flowid = (flowid + 1) % sc->sc_max_flowrings;
1979f67437f3Spatrick }
1980f67437f3Spatrick
1981f67437f3Spatrick if (found)
1982f67437f3Spatrick return flowid;
1983f67437f3Spatrick
1984f67437f3Spatrick return -1;
1985f67437f3Spatrick }
1986f67437f3Spatrick
1987f67437f3Spatrick void
bwfm_pci_flowring_create(struct bwfm_pci_softc * sc,struct mbuf * m)1988f67437f3Spatrick bwfm_pci_flowring_create(struct bwfm_pci_softc *sc, struct mbuf *m)
1989f67437f3Spatrick {
1990f67437f3Spatrick struct ieee80211com *ic = &sc->sc_sc.sc_ic;
1991518be5f3Spatrick struct bwfm_cmd_flowring_create cmd;
1992e6abcda3Smlarkin #ifndef IEEE80211_STA_ONLY
1993f67437f3Spatrick uint8_t *da = mtod(m, uint8_t *);
1994e6abcda3Smlarkin #endif
199502ee7d07Spatrick struct bwfm_pci_msgring *ring;
1996f67437f3Spatrick int flowid, prio, fifo;
1997f67437f3Spatrick int i, found;
1998f67437f3Spatrick
1999f67437f3Spatrick prio = ieee80211_classify(ic, m);
2000f67437f3Spatrick fifo = bwfm_pci_prio2fifo[prio];
2001f67437f3Spatrick
2002f67437f3Spatrick switch (ic->ic_opmode)
2003f67437f3Spatrick {
2004f67437f3Spatrick case IEEE80211_M_STA:
2005f67437f3Spatrick flowid = fifo;
2006f67437f3Spatrick break;
2007f67437f3Spatrick #ifndef IEEE80211_STA_ONLY
2008f67437f3Spatrick case IEEE80211_M_HOSTAP:
20092b7bea7eSpatrick if (ETHER_IS_MULTICAST(da))
20102b7bea7eSpatrick da = etherbroadcastaddr;
2011f67437f3Spatrick flowid = da[5] * 2 + fifo;
2012f67437f3Spatrick break;
2013f67437f3Spatrick #endif
2014f67437f3Spatrick default:
2015f67437f3Spatrick printf("%s: state not supported\n", DEVNAME(sc));
2016f67437f3Spatrick return;
2017f67437f3Spatrick }
2018f67437f3Spatrick
2019f67437f3Spatrick found = 0;
2020f67437f3Spatrick flowid = flowid % sc->sc_max_flowrings;
2021f67437f3Spatrick for (i = 0; i < sc->sc_max_flowrings; i++) {
202202ee7d07Spatrick ring = &sc->sc_flowrings[flowid];
202302ee7d07Spatrick if (ring->status == RING_CLOSED) {
202402ee7d07Spatrick ring->status = RING_OPENING;
2025f67437f3Spatrick found = 1;
2026f67437f3Spatrick break;
2027f67437f3Spatrick }
2028f67437f3Spatrick flowid = (flowid + 1) % sc->sc_max_flowrings;
2029f67437f3Spatrick }
2030f67437f3Spatrick
203102ee7d07Spatrick /*
203202ee7d07Spatrick * We cannot recover from that so far. Only a stop/init
203302ee7d07Spatrick * cycle can revive this if it ever happens at all.
203402ee7d07Spatrick */
2035f67437f3Spatrick if (!found) {
2036f67437f3Spatrick printf("%s: no flowring available\n", DEVNAME(sc));
2037f67437f3Spatrick return;
2038f67437f3Spatrick }
2039f67437f3Spatrick
204002ee7d07Spatrick cmd.m = m;
2041f67437f3Spatrick cmd.prio = prio;
2042518be5f3Spatrick cmd.flowid = flowid;
2043518be5f3Spatrick bwfm_do_async(&sc->sc_sc, bwfm_pci_flowring_create_cb, &cmd, sizeof(cmd));
2044518be5f3Spatrick }
2045518be5f3Spatrick
2046518be5f3Spatrick void
bwfm_pci_flowring_create_cb(struct bwfm_softc * bwfm,void * arg)2047518be5f3Spatrick bwfm_pci_flowring_create_cb(struct bwfm_softc *bwfm, void *arg)
2048518be5f3Spatrick {
2049518be5f3Spatrick struct bwfm_pci_softc *sc = (void *)bwfm;
2050e6abcda3Smlarkin #ifndef IEEE80211_STA_ONLY
20512b7bea7eSpatrick struct ieee80211com *ic = &sc->sc_sc.sc_ic;
2052e6abcda3Smlarkin #endif
2053518be5f3Spatrick struct bwfm_cmd_flowring_create *cmd = arg;
2054518be5f3Spatrick struct msgbuf_tx_flowring_create_req *req;
2055518be5f3Spatrick struct bwfm_pci_msgring *ring;
205602ee7d07Spatrick uint8_t *da, *sa;
2057e272db29Spatrick int s;
2058518be5f3Spatrick
205902ee7d07Spatrick da = mtod(cmd->m, char *) + 0 * ETHER_ADDR_LEN;
206002ee7d07Spatrick sa = mtod(cmd->m, char *) + 1 * ETHER_ADDR_LEN;
2061518be5f3Spatrick
206202ee7d07Spatrick ring = &sc->sc_flowrings[cmd->flowid];
206302ee7d07Spatrick if (ring->status != RING_OPENING) {
206402ee7d07Spatrick printf("%s: flowring not opening\n", DEVNAME(sc));
2065518be5f3Spatrick return;
2066f67437f3Spatrick }
2067f67437f3Spatrick
2068f67437f3Spatrick if (bwfm_pci_setup_flowring(sc, ring, 512, 48)) {
2069f67437f3Spatrick printf("%s: cannot setup flowring\n", DEVNAME(sc));
2070f67437f3Spatrick return;
2071f67437f3Spatrick }
2072518be5f3Spatrick
2073e272db29Spatrick s = splnet();
2074518be5f3Spatrick req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit);
2075f67437f3Spatrick if (req == NULL) {
2076f67437f3Spatrick printf("%s: cannot reserve for flowring\n", DEVNAME(sc));
2077e272db29Spatrick splx(s);
2078518be5f3Spatrick return;
2079f67437f3Spatrick }
2080518be5f3Spatrick
2081518be5f3Spatrick ring->status = RING_OPENING;
208202ee7d07Spatrick ring->fifo = bwfm_pci_prio2fifo[cmd->prio];
208302ee7d07Spatrick ring->m = cmd->m;
208402ee7d07Spatrick memcpy(ring->mac, da, ETHER_ADDR_LEN);
20852b7bea7eSpatrick #ifndef IEEE80211_STA_ONLY
208602ee7d07Spatrick if (ic->ic_opmode == IEEE80211_M_HOSTAP && ETHER_IS_MULTICAST(da))
20872b7bea7eSpatrick memcpy(ring->mac, etherbroadcastaddr, ETHER_ADDR_LEN);
20882b7bea7eSpatrick #endif
2089f67437f3Spatrick
2090518be5f3Spatrick req->msg.msgtype = MSGBUF_TYPE_FLOW_RING_CREATE;
2091518be5f3Spatrick req->msg.ifidx = 0;
2092518be5f3Spatrick req->msg.request_id = 0;
209302ee7d07Spatrick req->tid = bwfm_pci_prio2fifo[cmd->prio];
209402ee7d07Spatrick req->flow_ring_id = letoh16(cmd->flowid + 2);
209502ee7d07Spatrick memcpy(req->da, da, ETHER_ADDR_LEN);
209602ee7d07Spatrick memcpy(req->sa, sa, ETHER_ADDR_LEN);
2097518be5f3Spatrick req->flow_ring_addr.high_addr =
2098518be5f3Spatrick letoh32(BWFM_PCI_DMA_DVA(ring->ring) >> 32);
2099518be5f3Spatrick req->flow_ring_addr.low_addr =
2100518be5f3Spatrick letoh32(BWFM_PCI_DMA_DVA(ring->ring) & 0xffffffff);
2101518be5f3Spatrick req->max_items = letoh16(512);
2102518be5f3Spatrick req->len_item = letoh16(48);
2103518be5f3Spatrick
2104518be5f3Spatrick bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit);
2105e272db29Spatrick splx(s);
2106518be5f3Spatrick }
2107518be5f3Spatrick
2108a2c6ff8bSpatrick void
bwfm_pci_flowring_delete(struct bwfm_pci_softc * sc,int flowid)2109a2c6ff8bSpatrick bwfm_pci_flowring_delete(struct bwfm_pci_softc *sc, int flowid)
2110a2c6ff8bSpatrick {
2111a2c6ff8bSpatrick struct msgbuf_tx_flowring_delete_req *req;
2112a2c6ff8bSpatrick struct bwfm_pci_msgring *ring;
2113e272db29Spatrick int s;
2114a2c6ff8bSpatrick
2115a2c6ff8bSpatrick ring = &sc->sc_flowrings[flowid];
2116a2c6ff8bSpatrick if (ring->status != RING_OPEN) {
2117a2c6ff8bSpatrick printf("%s: flowring not open\n", DEVNAME(sc));
2118a2c6ff8bSpatrick return;
2119a2c6ff8bSpatrick }
2120a2c6ff8bSpatrick
2121e272db29Spatrick s = splnet();
2122a2c6ff8bSpatrick req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit);
2123a2c6ff8bSpatrick if (req == NULL) {
2124a2c6ff8bSpatrick printf("%s: cannot reserve for flowring\n", DEVNAME(sc));
2125e272db29Spatrick splx(s);
2126a2c6ff8bSpatrick return;
2127a2c6ff8bSpatrick }
2128a2c6ff8bSpatrick
2129a2c6ff8bSpatrick ring->status = RING_CLOSING;
2130a2c6ff8bSpatrick
2131a2c6ff8bSpatrick req->msg.msgtype = MSGBUF_TYPE_FLOW_RING_DELETE;
2132a2c6ff8bSpatrick req->msg.ifidx = 0;
2133a2c6ff8bSpatrick req->msg.request_id = 0;
2134a2c6ff8bSpatrick req->flow_ring_id = letoh16(flowid + 2);
2135a2c6ff8bSpatrick req->reason = 0;
2136a2c6ff8bSpatrick
2137a2c6ff8bSpatrick bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit);
2138e272db29Spatrick splx(s);
21398674c33cSkettenis
21408674c33cSkettenis tsleep_nsec(ring, PCATCH, DEVNAME(sc), SEC_TO_NSEC(2));
21418674c33cSkettenis if (ring->status != RING_CLOSED)
21428674c33cSkettenis printf("%s: flowring not closing\n", DEVNAME(sc));
2143a2c6ff8bSpatrick }
2144a2c6ff8bSpatrick
2145a2c6ff8bSpatrick void
bwfm_pci_flowring_delete_cb(struct bwfm_softc * bwfm,void * arg)2146b5553ee6Spatrick bwfm_pci_flowring_delete_cb(struct bwfm_softc *bwfm, void *arg)
2147b5553ee6Spatrick {
2148b5553ee6Spatrick struct bwfm_pci_softc *sc = (void *)bwfm;
2149b5553ee6Spatrick struct bwfm_cmd_flowring_create *cmd = arg;
2150b5553ee6Spatrick struct bwfm_pci_msgring *ring;
2151b5553ee6Spatrick
2152b5553ee6Spatrick ring = &sc->sc_flowrings[cmd->flowid];
2153b5553ee6Spatrick bwfm_pci_dmamem_free(sc, ring->ring);
2154b5553ee6Spatrick ring->status = RING_CLOSED;
21558674c33cSkettenis wakeup(ring);
2156b5553ee6Spatrick }
2157b5553ee6Spatrick
2158b5553ee6Spatrick void
bwfm_pci_stop(struct bwfm_softc * bwfm)2159a2c6ff8bSpatrick bwfm_pci_stop(struct bwfm_softc *bwfm)
2160a2c6ff8bSpatrick {
2161a2c6ff8bSpatrick struct bwfm_pci_softc *sc = (void *)bwfm;
2162a2c6ff8bSpatrick struct bwfm_pci_msgring *ring;
2163a2c6ff8bSpatrick int i;
2164a2c6ff8bSpatrick
2165a2c6ff8bSpatrick for (i = 0; i < sc->sc_max_flowrings; i++) {
2166a2c6ff8bSpatrick ring = &sc->sc_flowrings[i];
2167a2c6ff8bSpatrick if (ring->status == RING_OPEN)
2168a2c6ff8bSpatrick bwfm_pci_flowring_delete(sc, i);
2169a2c6ff8bSpatrick }
2170a2c6ff8bSpatrick }
2171a2c6ff8bSpatrick
2172e5ec1e72Spatrick int
bwfm_pci_txcheck(struct bwfm_softc * bwfm)217302ee7d07Spatrick bwfm_pci_txcheck(struct bwfm_softc *bwfm)
217402ee7d07Spatrick {
217502ee7d07Spatrick struct bwfm_pci_softc *sc = (void *)bwfm;
217602ee7d07Spatrick struct bwfm_pci_msgring *ring;
217702ee7d07Spatrick int i;
217802ee7d07Spatrick
217902ee7d07Spatrick /* If we are transitioning, we cannot send. */
218002ee7d07Spatrick for (i = 0; i < sc->sc_max_flowrings; i++) {
218102ee7d07Spatrick ring = &sc->sc_flowrings[i];
218202ee7d07Spatrick if (ring->status == RING_OPENING)
218302ee7d07Spatrick return ENOBUFS;
218402ee7d07Spatrick }
218502ee7d07Spatrick
218602ee7d07Spatrick if (bwfm_pci_pktid_avail(sc, &sc->sc_tx_pkts)) {
218702ee7d07Spatrick sc->sc_tx_pkts_full = 1;
218802ee7d07Spatrick return ENOBUFS;
218902ee7d07Spatrick }
219002ee7d07Spatrick
219102ee7d07Spatrick return 0;
219202ee7d07Spatrick }
219302ee7d07Spatrick
219402ee7d07Spatrick int
bwfm_pci_txdata(struct bwfm_softc * bwfm,struct mbuf * m)2195e5ec1e72Spatrick bwfm_pci_txdata(struct bwfm_softc *bwfm, struct mbuf *m)
2196e5ec1e72Spatrick {
2197e5ec1e72Spatrick struct bwfm_pci_softc *sc = (void *)bwfm;
2198518be5f3Spatrick struct bwfm_pci_msgring *ring;
2199518be5f3Spatrick struct msgbuf_tx_msghdr *tx;
2200518be5f3Spatrick uint32_t pktid;
2201518be5f3Spatrick paddr_t paddr;
2202518be5f3Spatrick int flowid, ret;
2203518be5f3Spatrick
2204f67437f3Spatrick flowid = bwfm_pci_flowring_lookup(sc, m);
2205f67437f3Spatrick if (flowid < 0) {
220602ee7d07Spatrick /*
220702ee7d07Spatrick * We cannot send the packet right now as there is
220802ee7d07Spatrick * no flowring yet. The flowring will be created
220902ee7d07Spatrick * asynchronously. While the ring is transitioning
221002ee7d07Spatrick * the TX check will tell the upper layers that we
221102ee7d07Spatrick * cannot send packets right now. When the flowring
221202ee7d07Spatrick * is created the queue will be restarted and this
221302ee7d07Spatrick * mbuf will be transmitted.
221402ee7d07Spatrick */
2215f67437f3Spatrick bwfm_pci_flowring_create(sc, m);
221602ee7d07Spatrick return 0;
2217f67437f3Spatrick }
2218518be5f3Spatrick
2219518be5f3Spatrick ring = &sc->sc_flowrings[flowid];
2220518be5f3Spatrick if (ring->status == RING_OPENING ||
2221f67437f3Spatrick ring->status == RING_CLOSING) {
2222f67437f3Spatrick printf("%s: tried to use a flow that was "
2223f67437f3Spatrick "transitioning in status %d\n",
2224f67437f3Spatrick DEVNAME(sc), ring->status);
2225518be5f3Spatrick return ENOBUFS;
2226518be5f3Spatrick }
2227518be5f3Spatrick
2228518be5f3Spatrick tx = bwfm_pci_ring_write_reserve(sc, ring);
2229518be5f3Spatrick if (tx == NULL)
2230518be5f3Spatrick return ENOBUFS;
2231518be5f3Spatrick
2232518be5f3Spatrick memset(tx, 0, sizeof(*tx));
2233518be5f3Spatrick tx->msg.msgtype = MSGBUF_TYPE_TX_POST;
2234518be5f3Spatrick tx->msg.ifidx = 0;
2235518be5f3Spatrick tx->flags = BWFM_MSGBUF_PKT_FLAGS_FRAME_802_3;
2236518be5f3Spatrick tx->flags |= ieee80211_classify(&sc->sc_sc.sc_ic, m) <<
2237518be5f3Spatrick BWFM_MSGBUF_PKT_FLAGS_PRIO_SHIFT;
2238518be5f3Spatrick tx->seg_cnt = 1;
2239518be5f3Spatrick memcpy(tx->txhdr, mtod(m, char *), ETHER_HDR_LEN);
2240518be5f3Spatrick
2241518be5f3Spatrick ret = bwfm_pci_pktid_new(sc, &sc->sc_tx_pkts, m, &pktid, &paddr);
2242518be5f3Spatrick if (ret) {
224302ee7d07Spatrick if (ret == ENOBUFS) {
224402ee7d07Spatrick printf("%s: no pktid available for TX\n",
224502ee7d07Spatrick DEVNAME(sc));
2246c6f1636dSpatrick sc->sc_tx_pkts_full = 1;
224702ee7d07Spatrick }
2248518be5f3Spatrick bwfm_pci_ring_write_cancel(sc, ring, 1);
2249518be5f3Spatrick return ret;
2250518be5f3Spatrick }
2251518be5f3Spatrick paddr += ETHER_HDR_LEN;
2252518be5f3Spatrick
2253f9ee104fSpatrick tx->msg.request_id = htole32(pktid + 1);
22544ff787bcSpatrick tx->data_len = htole16(m->m_len - ETHER_HDR_LEN);
2255e4dae658Spatrick tx->data_buf_addr.high_addr = htole32((uint64_t)paddr >> 32);
2256518be5f3Spatrick tx->data_buf_addr.low_addr = htole32(paddr & 0xffffffff);
2257518be5f3Spatrick
2258518be5f3Spatrick bwfm_pci_ring_write_commit(sc, ring);
2259518be5f3Spatrick return 0;
2260e5ec1e72Spatrick }
2261e5ec1e72Spatrick
22621a93a9bdSpatrick int
bwfm_pci_send_mb_data(struct bwfm_pci_softc * sc,uint32_t htod_mb_data)22631a93a9bdSpatrick bwfm_pci_send_mb_data(struct bwfm_pci_softc *sc, uint32_t htod_mb_data)
22641a93a9bdSpatrick {
22651a93a9bdSpatrick struct bwfm_softc *bwfm = (void *)sc;
22661a93a9bdSpatrick struct bwfm_core *core;
22671a93a9bdSpatrick uint32_t reg;
22681a93a9bdSpatrick int i;
22691a93a9bdSpatrick
22708674c33cSkettenis if (sc->sc_mb_via_ctl)
22718674c33cSkettenis return bwfm_pci_msgbuf_h2d_mb_write(sc, htod_mb_data);
22728674c33cSkettenis
22731a93a9bdSpatrick for (i = 0; i < 100; i++) {
22741a93a9bdSpatrick reg = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
22751a93a9bdSpatrick sc->sc_htod_mb_data_addr);
22761a93a9bdSpatrick if (reg == 0)
22771a93a9bdSpatrick break;
22781a93a9bdSpatrick delay(10 * 1000);
22791a93a9bdSpatrick }
22801a93a9bdSpatrick if (i == 100) {
22811a93a9bdSpatrick DPRINTF(("%s: MB transaction already pending\n", DEVNAME(sc)));
22821a93a9bdSpatrick return EIO;
22831a93a9bdSpatrick }
22841a93a9bdSpatrick
22851a93a9bdSpatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
22861a93a9bdSpatrick sc->sc_htod_mb_data_addr, htod_mb_data);
22871a93a9bdSpatrick pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_REG_SBMBX, 1);
22881a93a9bdSpatrick
22891a93a9bdSpatrick core = bwfm_chip_get_core(bwfm, BWFM_AGENT_CORE_PCIE2);
22901a93a9bdSpatrick if (core->co_rev <= 13)
22911a93a9bdSpatrick pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_REG_SBMBX, 1);
22921a93a9bdSpatrick
22931a93a9bdSpatrick return 0;
22941a93a9bdSpatrick }
22951a93a9bdSpatrick
22961a93a9bdSpatrick void
bwfm_pci_handle_mb_data(struct bwfm_pci_softc * sc)22971a93a9bdSpatrick bwfm_pci_handle_mb_data(struct bwfm_pci_softc *sc)
22981a93a9bdSpatrick {
22991a93a9bdSpatrick uint32_t reg;
23001a93a9bdSpatrick
23011a93a9bdSpatrick reg = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
23021a93a9bdSpatrick sc->sc_dtoh_mb_data_addr);
23031a93a9bdSpatrick if (reg == 0)
23041a93a9bdSpatrick return;
23051a93a9bdSpatrick
23061a93a9bdSpatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
23071a93a9bdSpatrick sc->sc_dtoh_mb_data_addr, 0);
23081a93a9bdSpatrick
23091a93a9bdSpatrick if (reg & BWFM_PCI_D2H_DEV_D3_ACK) {
23101a93a9bdSpatrick sc->sc_mbdata_done = 1;
23111a93a9bdSpatrick wakeup(&sc->sc_mbdata_done);
23121a93a9bdSpatrick }
23131a93a9bdSpatrick
23141a93a9bdSpatrick /* TODO: support more events */
23151a93a9bdSpatrick if (reg & ~BWFM_PCI_D2H_DEV_D3_ACK)
23161a93a9bdSpatrick printf("%s: handle MB data 0x%08x\n", DEVNAME(sc), reg);
23171a93a9bdSpatrick }
23181a93a9bdSpatrick
2319bbd71b0bSpatrick #ifdef BWFM_DEBUG
2320cadf5fcfSpatrick void
bwfm_pci_debug_console(struct bwfm_pci_softc * sc)2321cadf5fcfSpatrick bwfm_pci_debug_console(struct bwfm_pci_softc *sc)
2322cadf5fcfSpatrick {
2323cadf5fcfSpatrick uint32_t newidx = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh,
2324cadf5fcfSpatrick sc->sc_console_base_addr + BWFM_CONSOLE_WRITEIDX);
2325cadf5fcfSpatrick
2326cadf5fcfSpatrick if (newidx != sc->sc_console_readidx)
2327bbd71b0bSpatrick DPRINTFN(3, ("BWFM CONSOLE: "));
2328cadf5fcfSpatrick while (newidx != sc->sc_console_readidx) {
2329cadf5fcfSpatrick uint8_t ch = bus_space_read_1(sc->sc_tcm_iot, sc->sc_tcm_ioh,
2330cadf5fcfSpatrick sc->sc_console_buf_addr + sc->sc_console_readidx);
2331cadf5fcfSpatrick sc->sc_console_readidx++;
2332cadf5fcfSpatrick if (sc->sc_console_readidx == sc->sc_console_buf_size)
2333cadf5fcfSpatrick sc->sc_console_readidx = 0;
2334cadf5fcfSpatrick if (ch == '\r')
2335cadf5fcfSpatrick continue;
2336bbd71b0bSpatrick DPRINTFN(3, ("%c", ch));
2337cadf5fcfSpatrick }
2338cadf5fcfSpatrick }
2339bbd71b0bSpatrick #endif
2340cadf5fcfSpatrick
2341e5ec1e72Spatrick int
bwfm_pci_intr(void * v)2342e5ec1e72Spatrick bwfm_pci_intr(void *v)
2343e5ec1e72Spatrick {
2344e5ec1e72Spatrick struct bwfm_pci_softc *sc = (void *)v;
23456f241297Spatrick struct ifnet *ifp = &sc->sc_sc.sc_ic.ic_if;
23466f241297Spatrick struct mbuf_list ml = MBUF_LIST_INITIALIZER();
2347bb813cf8Spatrick uint32_t status, mask;
2348e5ec1e72Spatrick
2349bb813cf8Spatrick if (!sc->sc_initialized)
2350bb813cf8Spatrick return 0;
2351bb813cf8Spatrick
2352bb813cf8Spatrick status = bwfm_pci_intr_status(sc);
2353bb813cf8Spatrick /* FIXME: interrupt status seems to be zero? */
23548bad4727Spatrick if (status == 0 && sc->sc_pcireg64)
2355bb813cf8Spatrick status |= BWFM_PCI_64_PCIE2REG_MAILBOXMASK_INT_D2H_DB;
2356bb813cf8Spatrick if (status == 0)
2357e5ec1e72Spatrick return 0;
2358e5ec1e72Spatrick
2359e5ec1e72Spatrick bwfm_pci_intr_disable(sc);
2360bb813cf8Spatrick bwfm_pci_intr_ack(sc, status);
2361e5ec1e72Spatrick
23628bad4727Spatrick if (!sc->sc_pcireg64 &&
2363bb813cf8Spatrick (status & (BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_0 |
2364bb813cf8Spatrick BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_1)))
23651a93a9bdSpatrick bwfm_pci_handle_mb_data(sc);
2366e5ec1e72Spatrick
2367bb813cf8Spatrick mask = BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_D2H_DB;
23688bad4727Spatrick if (sc->sc_pcireg64)
2369bb813cf8Spatrick mask = BWFM_PCI_64_PCIE2REG_MAILBOXMASK_INT_D2H_DB;
2370bb813cf8Spatrick
2371bb813cf8Spatrick if (status & mask) {
23726f241297Spatrick bwfm_pci_ring_rx(sc, &sc->sc_rx_complete, &ml);
23736f241297Spatrick bwfm_pci_ring_rx(sc, &sc->sc_tx_complete, &ml);
23746f241297Spatrick bwfm_pci_ring_rx(sc, &sc->sc_ctrl_complete, &ml);
2375447a2df6Sdlg
2376447a2df6Sdlg if (ifiq_input(&ifp->if_rcv, &ml))
2377447a2df6Sdlg if_rxr_livelocked(&sc->sc_rxbuf_ring);
2378e5ec1e72Spatrick }
2379e5ec1e72Spatrick
2380cadf5fcfSpatrick #ifdef BWFM_DEBUG
2381cadf5fcfSpatrick bwfm_pci_debug_console(sc);
2382e5ec1e72Spatrick #endif
2383e5ec1e72Spatrick
2384e5ec1e72Spatrick bwfm_pci_intr_enable(sc);
2385e5ec1e72Spatrick return 1;
2386e5ec1e72Spatrick }
2387e5ec1e72Spatrick
2388e5ec1e72Spatrick void
bwfm_pci_intr_enable(struct bwfm_pci_softc * sc)2389e5ec1e72Spatrick bwfm_pci_intr_enable(struct bwfm_pci_softc *sc)
2390e5ec1e72Spatrick {
23918bad4727Spatrick if (sc->sc_pcireg64)
2392bb813cf8Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
2393bb813cf8Spatrick BWFM_PCI_64_PCIE2REG_MAILBOXMASK,
2394bb813cf8Spatrick BWFM_PCI_64_PCIE2REG_MAILBOXMASK_INT_D2H_DB);
2395bb813cf8Spatrick else
2396e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
2397e5ec1e72Spatrick BWFM_PCI_PCIE2REG_MAILBOXMASK,
2398e5ec1e72Spatrick BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_0 |
2399e5ec1e72Spatrick BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_1 |
2400e5ec1e72Spatrick BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_D2H_DB);
2401e5ec1e72Spatrick }
2402e5ec1e72Spatrick
2403e5ec1e72Spatrick void
bwfm_pci_intr_disable(struct bwfm_pci_softc * sc)2404e5ec1e72Spatrick bwfm_pci_intr_disable(struct bwfm_pci_softc *sc)
2405e5ec1e72Spatrick {
24068bad4727Spatrick if (sc->sc_pcireg64)
2407bb813cf8Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
2408bb813cf8Spatrick BWFM_PCI_64_PCIE2REG_MAILBOXMASK, 0);
2409bb813cf8Spatrick else
2410e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
2411e5ec1e72Spatrick BWFM_PCI_PCIE2REG_MAILBOXMASK, 0);
2412e5ec1e72Spatrick }
2413e5ec1e72Spatrick
2414bb813cf8Spatrick uint32_t
bwfm_pci_intr_status(struct bwfm_pci_softc * sc)2415bb813cf8Spatrick bwfm_pci_intr_status(struct bwfm_pci_softc *sc)
2416bb813cf8Spatrick {
24178bad4727Spatrick if (sc->sc_pcireg64)
2418bb813cf8Spatrick return bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
2419bb813cf8Spatrick BWFM_PCI_64_PCIE2REG_MAILBOXINT);
2420bb813cf8Spatrick else
2421bb813cf8Spatrick return bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
2422bb813cf8Spatrick BWFM_PCI_PCIE2REG_MAILBOXINT);
2423bb813cf8Spatrick }
2424bb813cf8Spatrick
2425bb813cf8Spatrick void
bwfm_pci_intr_ack(struct bwfm_pci_softc * sc,uint32_t status)2426bb813cf8Spatrick bwfm_pci_intr_ack(struct bwfm_pci_softc *sc, uint32_t status)
2427bb813cf8Spatrick {
24288bad4727Spatrick if (sc->sc_pcireg64)
2429bb813cf8Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
2430bb813cf8Spatrick BWFM_PCI_64_PCIE2REG_MAILBOXINT, status);
2431bb813cf8Spatrick else
2432bb813cf8Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
2433bb813cf8Spatrick BWFM_PCI_PCIE2REG_MAILBOXINT, status);
2434bb813cf8Spatrick }
2435bb813cf8Spatrick
24361a93a9bdSpatrick uint32_t
bwfm_pci_intmask(struct bwfm_pci_softc * sc)24371a93a9bdSpatrick bwfm_pci_intmask(struct bwfm_pci_softc *sc)
24381a93a9bdSpatrick {
24398bad4727Spatrick if (sc->sc_pcireg64)
24401a93a9bdSpatrick return bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
24411a93a9bdSpatrick BWFM_PCI_64_PCIE2REG_INTMASK);
24421a93a9bdSpatrick else
24431a93a9bdSpatrick return bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh,
24441a93a9bdSpatrick BWFM_PCI_PCIE2REG_INTMASK);
24451a93a9bdSpatrick }
24461a93a9bdSpatrick
2447156d2677Spatrick void
bwfm_pci_hostready(struct bwfm_pci_softc * sc)2448156d2677Spatrick bwfm_pci_hostready(struct bwfm_pci_softc *sc)
2449156d2677Spatrick {
2450156d2677Spatrick if ((sc->sc_shared_flags & BWFM_SHARED_INFO_HOSTRDY_DB1) == 0)
2451156d2677Spatrick return;
2452156d2677Spatrick
24538674c33cSkettenis if (sc->sc_shared_flags & BWFM_SHARED_INFO_SHARED_DAR)
2454bb813cf8Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
2455bb813cf8Spatrick BWFM_PCI_64_PCIE2REG_H2D_MAILBOX_1, 1);
2456bb813cf8Spatrick else
2457156d2677Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
2458156d2677Spatrick BWFM_PCI_PCIE2REG_H2D_MAILBOX_1, 1);
2459156d2677Spatrick }
2460156d2677Spatrick
2461e5ec1e72Spatrick /* Msgbuf protocol implementation */
2462e5ec1e72Spatrick int
bwfm_pci_msgbuf_query_dcmd(struct bwfm_softc * bwfm,int ifidx,int cmd,char * buf,size_t * len)2463e5ec1e72Spatrick bwfm_pci_msgbuf_query_dcmd(struct bwfm_softc *bwfm, int ifidx,
2464e5ec1e72Spatrick int cmd, char *buf, size_t *len)
2465e5ec1e72Spatrick {
2466e5ec1e72Spatrick struct bwfm_pci_softc *sc = (void *)bwfm;
2467e5ec1e72Spatrick struct msgbuf_ioctl_req_hdr *req;
24682eeba925Spatrick struct bwfm_pci_ioctl *ctl;
2469e5ec1e72Spatrick struct mbuf *m;
24702eeba925Spatrick uint32_t pktid;
24712eeba925Spatrick paddr_t paddr;
2472e5ec1e72Spatrick size_t buflen;
2473e272db29Spatrick int s;
2474e5ec1e72Spatrick
24752eeba925Spatrick buflen = min(*len, BWFM_DMA_H2D_IOCTL_BUF_LEN);
2476471f2571Sjan m = MCLGETL(NULL, M_DONTWAIT, buflen);
24772eeba925Spatrick if (m == NULL)
24782eeba925Spatrick return 1;
24792eeba925Spatrick m->m_len = m->m_pkthdr.len = buflen;
24802eeba925Spatrick
24812eeba925Spatrick if (buf)
24822eeba925Spatrick memcpy(mtod(m, char *), buf, buflen);
24832eeba925Spatrick else
24842eeba925Spatrick memset(mtod(m, char *), 0, buflen);
24852eeba925Spatrick
2486e272db29Spatrick s = splnet();
2487e5ec1e72Spatrick req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit);
2488e5ec1e72Spatrick if (req == NULL) {
2489e272db29Spatrick splx(s);
24902eeba925Spatrick m_freem(m);
2491e5ec1e72Spatrick return 1;
2492e5ec1e72Spatrick }
24932eeba925Spatrick
24942eeba925Spatrick if (bwfm_pci_pktid_new(sc, &sc->sc_ioctl_pkts, m, &pktid, &paddr)) {
24952eeba925Spatrick bwfm_pci_ring_write_cancel(sc, &sc->sc_ctrl_submit, 1);
2496e272db29Spatrick splx(s);
24972eeba925Spatrick m_freem(m);
24982eeba925Spatrick return 1;
24992eeba925Spatrick }
25002eeba925Spatrick
25012eeba925Spatrick ctl = malloc(sizeof(*ctl), M_TEMP, M_WAITOK|M_ZERO);
25022eeba925Spatrick ctl->transid = sc->sc_ioctl_transid++;
25032eeba925Spatrick TAILQ_INSERT_TAIL(&sc->sc_ioctlq, ctl, next);
25042eeba925Spatrick
2505e5ec1e72Spatrick req->msg.msgtype = MSGBUF_TYPE_IOCTLPTR_REQ;
2506e5ec1e72Spatrick req->msg.ifidx = 0;
2507e5ec1e72Spatrick req->msg.flags = 0;
25082eeba925Spatrick req->msg.request_id = htole32(pktid);
2509e5ec1e72Spatrick req->cmd = htole32(cmd);
2510e5ec1e72Spatrick req->output_buf_len = htole16(*len);
25112eeba925Spatrick req->trans_id = htole16(ctl->transid);
2512e5ec1e72Spatrick
25132eeba925Spatrick req->input_buf_len = htole16(m->m_len);
25142eeba925Spatrick req->req_buf_addr.high_addr = htole32((uint64_t)paddr >> 32);
25152eeba925Spatrick req->req_buf_addr.low_addr = htole32(paddr & 0xffffffff);
2516dcb67343Spatrick
2517e5ec1e72Spatrick bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit);
2518e272db29Spatrick splx(s);
2519e5ec1e72Spatrick
2520e5f191e1Skettenis tsleep_nsec(ctl, PWAIT, "bwfm", SEC_TO_NSEC(5));
25212eeba925Spatrick TAILQ_REMOVE(&sc->sc_ioctlq, ctl, next);
25222eeba925Spatrick
25232eeba925Spatrick if (ctl->m == NULL) {
25242eeba925Spatrick free(ctl, M_TEMP, sizeof(*ctl));
2525e5ec1e72Spatrick return 1;
2526e5ec1e72Spatrick }
2527e5ec1e72Spatrick
25282eeba925Spatrick *len = min(ctl->retlen, m->m_len);
25292eeba925Spatrick *len = min(*len, buflen);
2530e5ec1e72Spatrick if (buf)
25315c7fed39Sdlg m_copydata(ctl->m, 0, *len, buf);
25322eeba925Spatrick m_freem(ctl->m);
2533e5ec1e72Spatrick
25342eeba925Spatrick if (ctl->status < 0) {
25352eeba925Spatrick free(ctl, M_TEMP, sizeof(*ctl));
25362eeba925Spatrick return 1;
25372eeba925Spatrick }
25382eeba925Spatrick
25392eeba925Spatrick free(ctl, M_TEMP, sizeof(*ctl));
2540e5ec1e72Spatrick return 0;
2541e5ec1e72Spatrick }
2542e5ec1e72Spatrick
2543e5ec1e72Spatrick int
bwfm_pci_msgbuf_set_dcmd(struct bwfm_softc * bwfm,int ifidx,int cmd,char * buf,size_t len)2544e5ec1e72Spatrick bwfm_pci_msgbuf_set_dcmd(struct bwfm_softc *bwfm, int ifidx,
2545e5ec1e72Spatrick int cmd, char *buf, size_t len)
2546e5ec1e72Spatrick {
2547e5ec1e72Spatrick return bwfm_pci_msgbuf_query_dcmd(bwfm, ifidx, cmd, buf, &len);
2548e5ec1e72Spatrick }
25492eeba925Spatrick
25502eeba925Spatrick void
bwfm_pci_msgbuf_rxioctl(struct bwfm_pci_softc * sc,struct msgbuf_ioctl_resp_hdr * resp)25512eeba925Spatrick bwfm_pci_msgbuf_rxioctl(struct bwfm_pci_softc *sc,
25522eeba925Spatrick struct msgbuf_ioctl_resp_hdr *resp)
25532eeba925Spatrick {
25542eeba925Spatrick struct bwfm_pci_ioctl *ctl, *tmp;
25552eeba925Spatrick struct mbuf *m;
25562eeba925Spatrick
25572eeba925Spatrick m = bwfm_pci_pktid_free(sc, &sc->sc_rx_pkts,
25582eeba925Spatrick letoh32(resp->msg.request_id));
25592eeba925Spatrick
25602eeba925Spatrick TAILQ_FOREACH_SAFE(ctl, &sc->sc_ioctlq, next, tmp) {
25612eeba925Spatrick if (ctl->transid != letoh16(resp->trans_id))
25622eeba925Spatrick continue;
25632eeba925Spatrick ctl->m = m;
25642eeba925Spatrick ctl->retlen = letoh16(resp->resp_len);
25652eeba925Spatrick ctl->status = letoh16(resp->compl_hdr.status);
25662eeba925Spatrick wakeup(ctl);
25672eeba925Spatrick return;
25682eeba925Spatrick }
25692eeba925Spatrick
2570cb2afc74Spatrick m_freem(m);
25712eeba925Spatrick }
25728674c33cSkettenis
25738674c33cSkettenis int
bwfm_pci_msgbuf_h2d_mb_write(struct bwfm_pci_softc * sc,uint32_t data)25748674c33cSkettenis bwfm_pci_msgbuf_h2d_mb_write(struct bwfm_pci_softc *sc, uint32_t data)
25758674c33cSkettenis {
25768674c33cSkettenis struct msgbuf_h2d_mailbox_data *req;
25778674c33cSkettenis int s;
25788674c33cSkettenis
25798674c33cSkettenis s = splnet();
25808674c33cSkettenis req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit);
25818674c33cSkettenis if (req == NULL) {
25828674c33cSkettenis splx(s);
25838674c33cSkettenis return ENOBUFS;
25848674c33cSkettenis }
25858674c33cSkettenis
25868674c33cSkettenis req->msg.msgtype = MSGBUF_TYPE_H2D_MAILBOX_DATA;
25878674c33cSkettenis req->msg.ifidx = -1;
25888674c33cSkettenis req->msg.flags = 0;
25898674c33cSkettenis req->msg.request_id = 0;
25908674c33cSkettenis req->data = data;
25918674c33cSkettenis
25928674c33cSkettenis bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit);
25938674c33cSkettenis splx(s);
25948674c33cSkettenis
25958674c33cSkettenis return 0;
25968674c33cSkettenis }
2597