void wil_memcpy_fromio_halp_vote(struct wil6210_priv *wil, void *dst, const volatile void __iomem *src, size_t count) { wil_halp_vote(wil); wil_memcpy_fromio_32(dst, src, count); wil_halp_unvote(wil); }
static int wil_ioc_memio_block(struct wil6210_priv *wil, void __user *data) { struct wil_memio_block io; void *block; void __iomem *a; int rc = 0; if (copy_from_user(&io, data, sizeof(io))) return -EFAULT; wil_dbg_ioctl(wil, "IO: addr = 0x%08x size = 0x%08x op = 0x%08x\n", io.addr, io.size, io.op); /* size */ if (io.size % 4) { wil_err(wil, "size is not multiple of 4: 0x%08x\n", io.size); return -EINVAL; } a = wil_ioc_addr(wil, io.addr, io.size, io.op); if (!a) { wil_err(wil, "invalid address 0x%08x, op = 0x%08x\n", io.addr, io.op); return -EINVAL; } block = kmalloc(io.size, GFP_USER); if (!block) return -ENOMEM; /* operation */ switch (io.op & wil_mmio_op_mask) { case wil_mmio_read: wil_memcpy_fromio_32(block, a, io.size); wil_hex_dump_ioctl("Read ", block, io.size); if (copy_to_user(io.block, block, io.size)) { rc = -EFAULT; goto out_free; } break; case wil_mmio_write: if (copy_from_user(block, io.block, io.size)) { rc = -EFAULT; goto out_free; } wil_memcpy_toio_32(a, block, io.size); wmb(); /* make sure write propagated to HW */ wil_hex_dump_ioctl("Write ", block, io.size); break; default: wil_err(wil, "Unsupported operation, op = 0x%08x\n", io.op); rc = -EINVAL; break; } out_free: kfree(block); return rc; }
int wmi_read_hdr(struct wil6210_priv *wil, __le32 ptr, struct wil6210_mbox_hdr *hdr) { void __iomem *src = wmi_buffer(wil, ptr); if (!src) return -EINVAL; wil_memcpy_fromio_32(hdr, src, sizeof(*hdr)); return 0; }
static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { enum { max_count = 4096 }; struct wil_blob_wrapper *wil_blob = file->private_data; struct wil6210_priv *wil = wil_blob->wil; loff_t pos = *ppos; size_t available = wil_blob->blob.size; void *buf; size_t ret; int rc; if (test_bit(wil_status_suspending, wil_blob->wil->status) || test_bit(wil_status_suspended, wil_blob->wil->status)) return 0; if (pos < 0) return -EINVAL; if (pos >= available || !count) return 0; if (count > available - pos) count = available - pos; if (count > max_count) count = max_count; buf = kmalloc(count, GFP_KERNEL); if (!buf) return -ENOMEM; rc = wil_pm_runtime_get(wil); if (rc < 0) { kfree(buf); return rc; } wil_memcpy_fromio_32(buf, (const void __iomem *) wil_blob->blob.data + pos, count); ret = copy_to_user(user_buf, buf, count); wil_pm_runtime_put(wil); kfree(buf); if (ret == count) return -EFAULT; count -= ret; *ppos = pos + count; return count; }
static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { enum { max_count = 4096 }; struct debugfs_blob_wrapper *blob = file->private_data; loff_t pos = *ppos; size_t available = blob->size; void *buf; size_t ret; if (pos < 0) return -EINVAL; if (pos >= available || !count) return 0; if (count > available - pos) count = available - pos; if (count > max_count) count = max_count; buf = kmalloc(count, GFP_KERNEL); if (!buf) return -ENOMEM; wil_memcpy_fromio_32(buf, (const volatile void __iomem *)blob->data + pos, count); ret = copy_to_user(user_buf, buf, count); kfree(buf); if (ret == count) return -EFAULT; count -= ret; *ppos = pos + count; return count; }
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); }