[virtio] Convert use of OP_LOOKUP to bti_pin
Change-Id: I828fef091de454e3dd7d21d2964beb5c20ef879b
diff --git a/system/dev/bus/virtio/block.cpp b/system/dev/bus/virtio/block.cpp
index d5f635b..989e24c 100644
--- a/system/dev/bus/virtio/block.cpp
+++ b/system/dev/bus/virtio/block.cpp
@@ -27,7 +27,10 @@
namespace virtio {
-static void txn_complete(block_txn_t* txn, zx_status_t status) {
+void BlockDevice::txn_complete(block_txn_t* txn, zx_status_t status) {
+ if (txn->pin_base != 0) {
+ bti_.unpin(txn->pin_base);
+ }
txn->op.completion_cb(&txn->op, status);
}
@@ -64,6 +67,7 @@
void BlockDevice::virtio_block_queue(void* ctx, block_op_t* bop) {
BlockDevice* bd = static_cast<BlockDevice*>(ctx);
block_txn_t* txn = static_cast<block_txn_t*>((void*) bop);
+ txn->pin_base = 0;
switch(txn->op.command & BLOCK_OP_MASK) {
case BLOCK_OP_READ:
@@ -75,10 +79,10 @@
case BLOCK_OP_FLUSH:
//TODO: this should complete after any in-flight IO and before
// any later IO begins
- txn_complete(txn, ZX_OK);
+ bd->txn_complete(txn, ZX_OK);
break;
default:
- txn_complete(txn, ZX_ERR_NOT_SUPPORTED);
+ bd->txn_complete(txn, ZX_ERR_NOT_SUPPORTED);
}
}
@@ -273,7 +277,7 @@
}
zx_status_t BlockDevice::QueueTxn(block_txn_t* txn, bool write, size_t bytes,
- uint64_t* pages, size_t pagecount, uint16_t* idx) {
+ uint64_t* pages, size_t pagecount, uint16_t* idx) {
size_t index;
{
@@ -384,28 +388,35 @@
return;
}
+ if (txn->op.rw.length == 0) {
+ txn_complete(txn, ZX_OK);
+ return;
+ }
+
size_t bytes = txn->op.rw.length * config_.blk_size;
- zx_status_t r;
+ uint64_t suboffset = txn->op.rw.offset_vmo & PAGE_MASK;
+ uint64_t aligned_offset = txn->op.rw.offset_vmo & ~PAGE_MASK;
+ size_t pin_size = ROUNDUP(suboffset + bytes, PAGE_SIZE);
+ size_t num_pages = pin_size / PAGE_SIZE;
+ if (num_pages > MAX_SCATTER) {
+ TRACEF("virtio: transaction too large\n");
+ txn_complete(txn, ZX_ERR_INVALID_ARGS);
+ return;
+ }
+
zx_handle_t vmo = txn->op.rw.vmo;
- if ((r = zx_vmo_op_range(vmo, ZX_VMO_OP_COMMIT,
- txn->op.rw.offset_vmo, bytes, NULL, 0)) != ZX_OK) {
- TRACEF("could not commit pages\n");
- txn_complete(txn, ZX_ERR_INTERNAL);
- return;
- }
-
uint64_t pages[MAX_SCATTER];
- if ((r = zx_vmo_op_range(vmo, ZX_VMO_OP_LOOKUP,
- txn->op.rw.offset_vmo, bytes, pages, sizeof(pages))) != ZX_OK) {
- TRACEF("nvme: could not lookup pages\n");
+ zx_status_t r;
+ if ((r = zx_bti_pin(bti_.get(), ZX_BTI_PERM_READ | ZX_BTI_PERM_WRITE, vmo,
+ aligned_offset, pin_size, pages, num_pages)) != ZX_OK) {
+ TRACEF("virtio: could not pin pages\n");
txn_complete(txn, ZX_ERR_INTERNAL);
return;
}
- // Take the starting byte into the initial page plus total bytes
- // transferred, convert to page count (rounded up)
- size_t pagecount = ((txn->op.rw.offset_vmo & PAGE_MASK) + bytes + PAGE_MASK) / PAGE_SIZE;
+ txn->pin_base = pages[0];
+ pages[0] += suboffset;
bool cannot_fail = false;
@@ -413,7 +424,7 @@
uint16_t idx;
// attempt to setup hw txn
- zx_status_t status = QueueTxn(txn, write, bytes, pages, pagecount, &idx);
+ zx_status_t status = QueueTxn(txn, write, bytes, pages, num_pages, &idx);
if (status == ZX_OK) {
fbl::AutoLock lock(&txn_lock_);
diff --git a/system/dev/bus/virtio/block.h b/system/dev/bus/virtio/block.h
index 392b8ff..f0f8f63 100644
--- a/system/dev/bus/virtio/block.h
+++ b/system/dev/bus/virtio/block.h
@@ -23,6 +23,7 @@
struct vring_desc* desc;
size_t index;
list_node_t node;
+ zx_paddr_t pin_base;
};
class Ring;
@@ -57,6 +58,8 @@
uint64_t* pages, size_t pagecount, uint16_t* idx);
void QueueReadWriteTxn(block_txn_t* txn, bool write);
+ void txn_complete(block_txn_t* txn, zx_status_t status);
+
// the main virtio ring
Ring vring_ = {this};