105#include <sys/cdefs.h>
111#include <sys/param.h>
114#include <sys/endian.h>
115#include <sys/firmware.h>
116#include <sys/kernel.h>
117#include <sys/malloc.h>
119#include <sys/mutex.h>
120#include <sys/module.h>
123#include <sys/socket.h>
124#include <sys/sockio.h>
125#include <sys/sysctl.h>
126#include <sys/linker.h>
128#include <machine/bus.h>
129#include <machine/endian.h>
130#include <machine/resource.h>
132#include <dev/pci/pcivar.h>
133#include <dev/pci/pcireg.h>
138#include <net/if_var.h>
139#include <net/if_arp.h>
140#include <net/if_dl.h>
141#include <net/if_media.h>
142#include <net/if_types.h>
144#include <netinet/in.h>
145#include <netinet/in_systm.h>
146#include <netinet/if_ether.h>
147#include <netinet/ip.h>
149#include <net80211/ieee80211_var.h>
150#include <net80211/ieee80211_regdomain.h>
151#include <net80211/ieee80211_ratectl.h>
152#include <net80211/ieee80211_radiotap.h>
177 bus_dma_segment_t seg;
180 int error = 0, i, paylen, off;
185 size_t hdrlen, datasz;
193 for (i = 0, paylen = 0; i < nitems(hcmd->
len); i++) {
194 paylen += hcmd->
len[i];
199 KASSERT(!async, (
"invalid async parameter"));
216 txdata = &ring->
data[ring->
cur];
223 hdrlen =
sizeof(cmd->
hdr);
224 datasz =
sizeof(cmd->
data);
227 if (paylen > datasz) {
229 "large command paylen=%u len0=%u\n",
230 paylen, hcmd->
len[0]);
232 size_t totlen = hdrlen + paylen;
235 "firmware command too long (%zd bytes)\n",
246 m->m_len = m->m_pkthdr.len = m->m_ext.ext_size;
247 error = bus_dmamap_load_mbuf_sg(ring->
data_dmat,
248 txdata->
map, m, &seg, &nsegs, BUS_DMA_NOWAIT);
251 "%s: can't map mbuf, error %d\n", __func__, error);
259 cmd = &ring->
cmd[ring->
cur];
279 for (i = 0, off = 0; i < nitems(hcmd->
data); i++) {
280 if (hcmd->
len[i] == 0)
282 memcpy(data + off, hcmd->
data[i], hcmd->
len[i]);
285 KASSERT(off == paylen, (
"off %d != paylen %d", off, paylen));
288 addr_lo = htole32((uint32_t)paddr);
289 memcpy(&desc->
tbs[0].
lo, &addr_lo,
sizeof(uint32_t));
291 | ((hdrlen + paylen) << 4));
295 "iwm_send_cmd 0x%x size=%lu %s\n",
297 (
unsigned long) (hcmd->
len[0] + hcmd->
len[1] + hdrlen),
298 async ?
" (async)" :
"");
300 if (paylen > datasz) {
302 BUS_DMASYNC_PREWRITE);
305 BUS_DMASYNC_PREWRITE);
308 BUS_DMASYNC_PREWRITE);
316 iwm_update_sched(sc, ring->
qid, ring->
cur, 0, 0);
319 "sending command 0x%x qid %d, idx %d\n",
320 code, ring->
qid, ring->
cur);
329 error = msleep(desc, &sc->
sc_mtx, PCATCH,
"iwmcmd", hz);
340 if (wantresp && error != 0) {
350 uint32_t flags, uint16_t len,
const void *data)
372 (
"invalid command"));
391 if (resp_len !=
sizeof(*resp)) {
396 resp = (
void *)pkt->
data;
406 uint16_t len,
const void *data, uint32_t *
status)
432 KASSERT(nsegs == 1, (
"too many DMA segments, %d should be 1", nsegs));
433 *(bus_addr_t *)arg = segs[0].ds_addr;
438 bus_size_t size, bus_size_t alignment)
447 error = bus_dma_tag_create(tag, alignment,
448 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, size,
449 1, size, 0, NULL, NULL, &dma->
tag);
453 error = bus_dmamem_alloc(dma->
tag, (
void **)&dma->
vaddr,
454 BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT, &dma->
map);
458 error = bus_dmamap_load(dma->
tag, dma->
map, dma->
vaddr, size,
466 bus_dmamap_sync(dma->
tag, dma->
map, BUS_DMASYNC_PREWRITE);
479 if (dma->
vaddr != NULL) {
480 bus_dmamap_sync(dma->
tag, dma->
map,
481 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
482 bus_dmamap_unload(dma->
tag, dma->
map);
486 if (dma->
tag != NULL) {
487 bus_dma_tag_destroy(dma->
tag);
static uint8_t num_of_ant(uint8_t mask)
#define IWM_DPRINTF(sc, m, fmt,...)
int iwm_pcie_set_cmd_in_flight(struct iwm_softc *sc)
int iwm_send_cmd_status(struct iwm_softc *sc, struct iwm_host_cmd *cmd, uint32_t *status)
static void iwm_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
void iwm_dma_contig_free(struct iwm_dma_info *dma)
boolean_t iwm_rx_diversity_allowed(struct iwm_softc *sc)
void iwm_free_resp(struct iwm_softc *sc, struct iwm_host_cmd *hcmd)
int iwm_send_cmd_pdu_status(struct iwm_softc *sc, uint32_t id, uint16_t len, const void *data, uint32_t *status)
int iwm_send_lq_cmd(struct iwm_softc *sc, struct iwm_lq_cmd *lq, boolean_t init)
int iwm_send_cmd_pdu(struct iwm_softc *sc, uint32_t id, uint32_t flags, uint16_t len, const void *data)
int iwm_dma_contig_alloc(bus_dma_tag_t tag, struct iwm_dma_info *dma, bus_size_t size, bus_size_t alignment)
int iwm_send_cmd(struct iwm_softc *sc, struct iwm_host_cmd *hcmd)
static uint8_t iwm_get_valid_rx_ant(struct iwm_softc *sc)
static uint8_t iwm_cmd_opcode(uint32_t cmdid)
#define IWM_STATION_COUNT
static uint8_t iwm_cmd_groupid(uint32_t cmdid)
#define IWM_WRITE(sc, reg, val)
static uint8_t iwm_get_dma_hi_addr(bus_addr_t addr)
#define IWM_CMD_FAILED_MSK
static uint32_t iwm_rx_packet_payload_len(const struct iwm_rx_packet *pkt)
#define IWM_MAX_CMD_PAYLOAD_SIZE
static uint8_t iwm_cmd_version(uint32_t cmdid)
#define IWM_HBUS_TARG_WRPTR
#define IWM_TX_RING_COUNT
struct iwm_cmd_header hdr
uint8_t data[IWM_DEF_CMD_PAYLOAD_SIZE]
uint8_t data_wide[IWM_DEF_CMD_PAYLOAD_SIZE - sizeof(struct iwm_cmd_header_wide)+sizeof(struct iwm_cmd_header)]
struct iwm_cmd_header_wide hdr_wide
struct iwm_rx_packet * resp_pkt
uint16_t len[IWM_MAX_CMD_TBS_PER_TFD]
const void * data[IWM_MAX_CMD_TBS_PER_TFD]
struct iwm_cmd_header hdr
struct iwm_tx_ring txq[IWM_MAX_QUEUES]
uint8_t sc_cmd_resp[IWM_CMD_RESP_MAX]
struct iwm_tfd_tb tbs[IWM_NUM_OF_TBS]
struct iwm_dma_info desc_dma
struct iwm_tx_data data[IWM_TX_RING_COUNT]
struct iwm_device_cmd * cmd
struct iwm_dma_info cmd_dma