/* * We only support write access to MIO capable devices if we are on * a MIO enabled system. Otherwise we would have to check for every * address if it is a special ZPCI_ADDR and would have to do * a pfn lookup which we don't need for MIO capable devices. Currently * ISM devices are the only devices without MIO support and there is no * known need for accessing these from userspace.
*/ if (static_branch_likely(&have_mio)) {
ret = __memcpy_toio_inuser((void __iomem *) mmio_addr,
user_buffer,
length); return ret;
}
if (length > 64) {
buf = kmalloc(length, GFP_KERNEL); if (!buf) return -ENOMEM;
} else
buf = local_buf;
ret = -EFAULT; if (copy_from_user(buf, user_buffer, length)) goto out_free;
mmap_read_lock(current->mm);
ret = -EINVAL;
vma = vma_lookup(current->mm, mmio_addr); if (!vma) goto out_unlock_mmap; if (!(vma->vm_flags & (VM_IO | VM_PFNMAP))) goto out_unlock_mmap;
ret = -EACCES; if (!(vma->vm_flags & VM_WRITE)) goto out_unlock_mmap;
args.address = mmio_addr;
args.vma = vma;
ret = follow_pfnmap_start(&args); if (ret) {
fixup_user_fault(current->mm, mmio_addr, FAULT_FLAG_WRITE, NULL);
ret = follow_pfnmap_start(&args); if (ret) goto out_unlock_mmap;
}
/* * read 0 < @len <= 8 bytes from the PCI memory mapped at @ioaddr (in * user space) into a register using pcilg then store these bytes at * user address @dst
*/
exception = 1;
sacf_flag = enable_sacf_uaccess();
asm_inline volatile ( " sacf 256\n" "0: .insn rre,0xb9d60000,%[val],%[ioaddr_len]\n" "1: lhi %[exc],0\n" " jne 4f\n" "2: ahi %[shift],-8\n" " srlg %[tmp],%[val],0(%[shift])\n" "3: stc %[tmp],0(%[dst])\n" "5: aghi %[dst],1\n" " brctg %[cnt],2b\n" /* * Use xr to clear exc and set condition code to zero * to ensure flag output is correct for this branch.
*/ " xr %[exc],%[exc]\n" "4: sacf 768\n"
CC_IPM(cc)
EX_TABLE(0b, 4b) EX_TABLE(1b, 4b) EX_TABLE(3b, 4b) EX_TABLE(5b, 4b)
: [ioaddr_len] "+&d" (ioaddr_len.pair), [exc] "+d" (exception),
CC_OUT(cc, cc), [val] "=d" (val),
[dst] "+a" (dst), [cnt] "+d" (cnt), [tmp] "=d" (tmp),
[shift] "+a" (shift)
:
: CC_CLOBBER_LIST("memory"));
disable_sacf_uaccess(sacf_flag);
cc = exception ? -ENXIO : CC_TRANSFORM(cc); /* did we write everything to the user space buffer? */ if (!cc && cnt != 0)
cc = -EFAULT;
/* * We only support read access to MIO capable devices if we are on * a MIO enabled system. Otherwise we would have to check for every * address if it is a special ZPCI_ADDR and would have to do * a pfn lookup which we don't need for MIO capable devices. Currently * ISM devices are the only devices without MIO support and there is no * known need for accessing these from userspace.
*/ if (static_branch_likely(&have_mio)) {
ret = __memcpy_fromio_inuser(
user_buffer, (constvoid __iomem *)mmio_addr,
length); return ret;
}
if (length > 64) {
buf = kmalloc(length, GFP_KERNEL); if (!buf) return -ENOMEM;
} else {
buf = local_buf;
}
mmap_read_lock(current->mm);
ret = -EINVAL;
vma = vma_lookup(current->mm, mmio_addr); if (!vma) goto out_unlock_mmap; if (!(vma->vm_flags & (VM_IO | VM_PFNMAP))) goto out_unlock_mmap;
ret = -EACCES; if (!(vma->vm_flags & VM_READ)) goto out_unlock_mmap;
args.vma = vma;
args.address = mmio_addr;
ret = follow_pfnmap_start(&args); if (ret) {
fixup_user_fault(current->mm, mmio_addr, 0, NULL);
ret = follow_pfnmap_start(&args); if (ret) goto out_unlock_mmap;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.