static void __iomem *wil_ioc_addr(struct wil6210_priv *wil, uint32_t addr, uint32_t size, enum wil_memio_op op) { void __iomem *a; u32 off; switch (op & wil_mmio_addr_mask) { case wil_mmio_addr_linker: a = wmi_buffer(wil, cpu_to_le32(addr)); break; case wil_mmio_addr_ahb: a = wmi_addr(wil, addr); break; case wil_mmio_addr_bar: a = wmi_addr(wil, addr + WIL6210_FW_HOST_OFF); break; default: wil_err(wil, "Unsupported address mode, op = 0x%08x\n", op); return NULL; } off = a - wil->csr; if (size >= WIL6210_MEM_SIZE - off) { wil_err(wil, "Requested block does not fit into memory: " "off = 0x%08x size = 0x%08x\n", off, size); return NULL; } return a; }
static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil, const char *name, struct vring *vring, char _s, char _h) { void __iomem *x = wmi_addr(wil, vring->hwtail); seq_printf(s, "VRING %s = {\n", name); seq_printf(s, " pa = %pad\n", &vring->pa); seq_printf(s, " va = 0x%p\n", vring->va); seq_printf(s, " size = %d\n", vring->size); seq_printf(s, " swtail = %d\n", vring->swtail); seq_printf(s, " swhead = %d\n", vring->swhead); seq_printf(s, " hwtail = [0x%08x] -> ", vring->hwtail); if (x) seq_printf(s, "0x%08x\n", ioread32(x)); else seq_puts(s, "???\n"); if (vring->va && (vring->size < 1025)) { uint i; for (i = 0; i < vring->size; i++) { volatile struct vring_tx_desc *d = &vring->va[i].tx; if ((i % 64) == 0 && (i != 0)) seq_puts(s, "\n"); seq_printf(s, "%c", (d->dma.status & BIT(0)) ? _s : (vring->ctx[i].skb ? _h : 'h')); } seq_puts(s, "\n"); } seq_puts(s, "}\n"); }
static void wil_print_ring(struct seq_file *s, const char *prefix, void __iomem *off) { struct wil6210_priv *wil = s->private; struct wil6210_mbox_ring r; int rsize; uint i; wil_halp_vote(wil); wil_memcpy_fromio_32(&r, off, sizeof(r)); wil_mbox_ring_le2cpus(&r); /* * we just read memory block from NIC. This memory may be * garbage. Check validity before using it. */ rsize = r.size / sizeof(struct wil6210_mbox_ring_desc); seq_printf(s, "ring %s = {\n", prefix); seq_printf(s, " base = 0x%08x\n", r.base); seq_printf(s, " size = 0x%04x bytes -> %d entries\n", r.size, rsize); seq_printf(s, " tail = 0x%08x\n", r.tail); seq_printf(s, " head = 0x%08x\n", r.head); seq_printf(s, " entry size = %d\n", r.entry_size); if (r.size % sizeof(struct wil6210_mbox_ring_desc)) { seq_printf(s, " ??? size is not multiple of %zd, garbage?\n", sizeof(struct wil6210_mbox_ring_desc)); goto out; } if (!wmi_addr(wil, r.base) || !wmi_addr(wil, r.tail) || !wmi_addr(wil, r.head)) { seq_puts(s, " ??? pointers are garbage?\n"); goto out; } for (i = 0; i < rsize; i++) { struct wil6210_mbox_ring_desc d; struct wil6210_mbox_hdr hdr; size_t delta = i * sizeof(d); void __iomem *x = wil->csr + HOSTADDR(r.base) + delta; wil_memcpy_fromio_32(&d, x, sizeof(d)); seq_printf(s, " [%2x] %s %s%s 0x%08x", i, d.sync ? "F" : "E", (r.tail - r.base == delta) ? "t" : " ", (r.head - r.base == delta) ? "h" : " ", le32_to_cpu(d.addr)); if (0 == wmi_read_hdr(wil, d.addr, &hdr)) { u16 len = le16_to_cpu(hdr.len); seq_printf(s, " -> %04x %04x %04x %02x\n", le16_to_cpu(hdr.seq), len, le16_to_cpu(hdr.type), hdr.flags); if (len <= MAX_MBOXITEM_SIZE) { unsigned char databuf[MAX_MBOXITEM_SIZE]; void __iomem *src = wmi_buffer(wil, d.addr) + sizeof(struct wil6210_mbox_hdr); /* * No need to check @src for validity - * we already validated @d.addr while * reading header */ wil_memcpy_fromio_32(databuf, src, len); wil_seq_hexdump(s, databuf, len, " : "); } } else { seq_puts(s, "\n"); } } out: seq_puts(s, "}\n"); wil_halp_unvote(wil); }
} __packed cmd = { .hdr = { .type = WIL_MBOX_HDR_TYPE_WMI, .flags = 0, .len = cpu_to_le16(sizeof(cmd.wmi) + len), }, .wmi = { .mid = 0, .id = cpu_to_le16(cmdid), }, }; struct wil6210_mbox_ring *r = &wil->mbox_ctl.tx; struct wil6210_mbox_ring_desc d_head; u32 next_head; void __iomem *dst; void __iomem *head = wmi_addr(wil, r->head); uint retry; if (sizeof(cmd) + len > r->entry_size) { wil_err(wil, "WMI size too large: %d bytes, max is %d\n", (int)(sizeof(cmd) + len), r->entry_size); return -ERANGE; } might_sleep(); if (!test_bit(wil_status_fwready, &wil->status)) { wil_err(wil, "FW not ready\n"); return -EAGAIN; }