Index: uspace/drv/bus/usb/ehci/ehci_batch.c
===================================================================
--- uspace/drv/bus/usb/ehci/ehci_batch.c	(revision d345ce2f2396010ea2fd5ad90e85202da83d5197)
+++ uspace/drv/bus/usb/ehci/ehci_batch.c	(revision 1d758fc6d12dfedeea03efca816537794a056af2)
@@ -102,5 +102,5 @@
 		: 0;
 
-	const size_t size = ehci_batch->base.buffer_size;
+	const size_t size = ehci_batch->base.size;
 
 	/* Add TD left over by the previous transfer */
@@ -180,5 +180,5 @@
 
 	/* Assume all data got through */
-	ehci_batch->base.transferred_size = ehci_batch->base.buffer_size;
+	ehci_batch->base.transferred_size = ehci_batch->base.size;
 
 	/* Check all TDs */
@@ -216,5 +216,5 @@
 	}
 
-	assert(ehci_batch->base.transferred_size <= ehci_batch->base.buffer_size);
+	assert(ehci_batch->base.transferred_size <= ehci_batch->base.size);
 
 	/* Clear TD pointers */
@@ -281,5 +281,5 @@
 	/* Data stage */
 	unsigned td_current = 1;
-	size_t remain_size = ehci_batch->base.buffer_size;
+	size_t remain_size = ehci_batch->base.size;
 	uintptr_t buffer = dma_buffer_phys(&ehci_batch->base.dma_buffer,
 	    ehci_batch->data_buffer);
@@ -335,5 +335,5 @@
 
 	size_t td_current = 0;
-	size_t remain_size = ehci_batch->base.buffer_size;
+	size_t remain_size = ehci_batch->base.size;
 	uintptr_t buffer = dma_buffer_phys(&ehci_batch->base.dma_buffer,
 	    ehci_batch->data_buffer);
Index: uspace/drv/bus/usb/ehci/ehci_rh.c
===================================================================
--- uspace/drv/bus/usb/ehci/ehci_rh.c	(revision d345ce2f2396010ea2fd5ad90e85202da83d5197)
+++ uspace/drv/bus/usb/ehci/ehci_rh.c	(revision 1d758fc6d12dfedeea03efca816537794a056af2)
@@ -147,5 +147,5 @@
 	batch->error = virthub_base_request(&instance->base, batch->target,
 	    batch->dir, (void*) batch->setup.buffer,
-	    batch->dma_buffer.virt, batch->buffer_size,
+	    batch->dma_buffer.virt, batch->size,
 	    &batch->transferred_size);
 	if (batch->error == ENAK) {
@@ -206,5 +206,5 @@
 		batch->error = virthub_base_request(&instance->base, batch->target,
 		    batch->dir, (void*) batch->setup.buffer,
-		    batch->dma_buffer.virt, batch->buffer_size,
+		    batch->dma_buffer.virt, batch->size,
 		    &batch->transferred_size);
 		usb_transfer_batch_finish(batch);
Index: uspace/drv/bus/usb/ohci/ohci_batch.c
===================================================================
--- uspace/drv/bus/usb/ohci/ohci_batch.c	(revision d345ce2f2396010ea2fd5ad90e85202da83d5197)
+++ uspace/drv/bus/usb/ohci/ohci_batch.c	(revision 1d758fc6d12dfedeea03efca816537794a056af2)
@@ -96,5 +96,5 @@
 		return ENOTSUP;
 
-	ohci_batch->td_count = (usb_batch->buffer_size + OHCI_TD_MAX_TRANSFER - 1)
+	ohci_batch->td_count = (usb_batch->size + OHCI_TD_MAX_TRANSFER - 1)
 	    / OHCI_TD_MAX_TRANSFER;
 	/* Control transfer need Setup and Status stage */
@@ -166,5 +166,5 @@
 
 	/* Assume all data got through */
-	usb_batch->transferred_size = usb_batch->buffer_size;
+	usb_batch->transferred_size = usb_batch->size;
 
 	/* Check all TDs */
@@ -212,5 +212,5 @@
 		}
 	}
-	assert(usb_batch->transferred_size <= usb_batch->buffer_size);
+	assert(usb_batch->transferred_size <= usb_batch->size);
 
 	/* Make sure that we are leaving the right TD behind */
@@ -289,5 +289,5 @@
 	size_t td_current = 1;
 	const char* buffer = ohci_batch->data_buffer;
-	size_t remain_size = ohci_batch->base.buffer_size;
+	size_t remain_size = ohci_batch->base.size;
 	while (remain_size > 0) {
 		const size_t transfer_size =
@@ -343,5 +343,5 @@
 
 	size_t td_current = 0;
-	size_t remain_size = ohci_batch->base.buffer_size;
+	size_t remain_size = ohci_batch->base.size;
 	char *buffer = ohci_batch->data_buffer;
 	while (remain_size > 0) {
Index: uspace/drv/bus/usb/ohci/ohci_rh.c
===================================================================
--- uspace/drv/bus/usb/ohci/ohci_rh.c	(revision d345ce2f2396010ea2fd5ad90e85202da83d5197)
+++ uspace/drv/bus/usb/ohci/ohci_rh.c	(revision 1d758fc6d12dfedeea03efca816537794a056af2)
@@ -182,5 +182,5 @@
 	batch->error = virthub_base_request(&instance->base, batch->target,
 	    batch->dir, &batch->setup.packet,
-	    batch->dma_buffer.virt, batch->buffer_size, &batch->transferred_size);
+	    batch->dma_buffer.virt, batch->size, &batch->transferred_size);
 	if (batch->error == ENAK) {
 		/* Lock the HC guard */
@@ -233,5 +233,5 @@
 		batch->error = virthub_base_request(&instance->base, batch->target,
 		    batch->dir, &batch->setup.packet,
-		    batch->dma_buffer.virt, batch->buffer_size, &batch->transferred_size);
+		    batch->dma_buffer.virt, batch->size, &batch->transferred_size);
 		usb_transfer_batch_finish(batch);
 	}
Index: uspace/drv/bus/usb/uhci/uhci_batch.c
===================================================================
--- uspace/drv/bus/usb/uhci/uhci_batch.c	(revision d345ce2f2396010ea2fd5ad90e85202da83d5197)
+++ uspace/drv/bus/usb/uhci/uhci_batch.c	(revision 1d758fc6d12dfedeea03efca816537794a056af2)
@@ -98,5 +98,5 @@
 	usb_transfer_batch_t *usb_batch = &uhci_batch->base;
 
-	uhci_batch->td_count = (usb_batch->buffer_size + usb_batch->ep->max_packet_size - 1)
+	uhci_batch->td_count = (usb_batch->size + usb_batch->ep->max_packet_size - 1)
 		/ usb_batch->ep->max_packet_size;
 
@@ -190,5 +190,5 @@
 	}
 
-	assert(batch->transferred_size <= batch->buffer_size);
+	assert(batch->transferred_size <= batch->size);
 
 	return true;
@@ -228,5 +228,5 @@
 
 	size_t td = 0;
-	size_t remain_size = uhci_batch->base.buffer_size;
+	size_t remain_size = uhci_batch->base.size;
 	char *buffer = uhci_transfer_batch_data_buffer(uhci_batch);
 
@@ -297,5 +297,5 @@
 	size_t td = 1;
 	unsigned toggle = 1;
-	size_t remain_size = uhci_batch->base.buffer_size;
+	size_t remain_size = uhci_batch->base.size;
 	char *buffer = uhci_transfer_batch_data_buffer(uhci_batch);
 
Index: uspace/drv/bus/usb/uhci/uhci_rh.c
===================================================================
--- uspace/drv/bus/usb/uhci/uhci_rh.c	(revision d345ce2f2396010ea2fd5ad90e85202da83d5197)
+++ uspace/drv/bus/usb/uhci/uhci_rh.c	(revision 1d758fc6d12dfedeea03efca816537794a056af2)
@@ -107,5 +107,5 @@
 		batch->error = virthub_base_request(&instance->base, batch->target,
 		    batch->dir, (void*) batch->setup.buffer,
-		    batch->dma_buffer.virt, batch->buffer_size, &batch->transferred_size);
+		    batch->dma_buffer.virt, batch->size, &batch->transferred_size);
 		if (batch->error == ENAK)
 			async_usleep(instance->base.endpoint_descriptor.poll_interval * 1000);
Index: uspace/drv/bus/usb/vhc/transfer.c
===================================================================
--- uspace/drv/bus/usb/vhc/transfer.c	(revision d345ce2f2396010ea2fd5ad90e85202da83d5197)
+++ uspace/drv/bus/usb/vhc/transfer.c	(revision 1d758fc6d12dfedeea03efca816537794a056af2)
@@ -72,5 +72,5 @@
 			rc = usbvirt_control_read(dev,
 			    batch->setup.buffer, USB_SETUP_PACKET_SIZE,
-			    batch->dma_buffer.virt, batch->buffer_size,
+			    batch->dma_buffer.virt, batch->size,
 			    actual_data_size);
 		} else {
@@ -78,5 +78,5 @@
 			rc = usbvirt_control_write(dev,
 			    batch->setup.buffer, USB_SETUP_PACKET_SIZE,
-			    batch->dma_buffer.virt, batch->buffer_size);
+			    batch->dma_buffer.virt, batch->size);
 		}
 	} else {
@@ -84,5 +84,5 @@
 			rc = usbvirt_data_in(dev, batch->ep->transfer_type,
 			    batch->ep->endpoint,
-			    batch->dma_buffer.virt, batch->buffer_size,
+			    batch->dma_buffer.virt, batch->size,
 			    actual_data_size);
 		} else {
@@ -90,5 +90,5 @@
 			rc = usbvirt_data_out(dev, batch->ep->transfer_type,
 			    batch->ep->endpoint,
-			    batch->dma_buffer.virt, batch->buffer_size);
+			    batch->dma_buffer.virt, batch->size);
 		}
 	}
@@ -108,5 +108,5 @@
 			rc = usbvirt_ipc_send_control_read(sess,
 			    batch->setup.buffer, USB_SETUP_PACKET_SIZE,
-			    batch->dma_buffer.virt, batch->buffer_size,
+			    batch->dma_buffer.virt, batch->size,
 			    actual_data_size);
 		} else {
@@ -114,5 +114,5 @@
 			rc = usbvirt_ipc_send_control_write(sess,
 			    batch->setup.buffer, USB_SETUP_PACKET_SIZE,
-			    batch->dma_buffer.virt, batch->buffer_size);
+			    batch->dma_buffer.virt, batch->size);
 		}
 	} else {
@@ -120,5 +120,5 @@
 			rc = usbvirt_ipc_send_data_in(sess, batch->ep->endpoint,
 			    batch->ep->transfer_type,
-			    batch->dma_buffer.virt, batch->buffer_size,
+			    batch->dma_buffer.virt, batch->size,
 			    actual_data_size);
 		} else {
@@ -126,5 +126,5 @@
 			rc = usbvirt_ipc_send_data_out(sess, batch->ep->endpoint,
 			    batch->ep->transfer_type,
-			    batch->dma_buffer.virt, batch->buffer_size);
+			    batch->dma_buffer.virt, batch->size);
 		}
 	}
Index: uspace/drv/bus/usb/xhci/commands.c
===================================================================
--- uspace/drv/bus/usb/xhci/commands.c	(revision d345ce2f2396010ea2fd5ad90e85202da83d5197)
+++ uspace/drv/bus/usb/xhci/commands.c	(revision 1d758fc6d12dfedeea03efca816537794a056af2)
@@ -470,5 +470,6 @@
 	xhci_trb_clean(&cmd->_header.trb);
 
-	TRB_SET_ICTX(cmd->_header.trb, cmd->input_ctx.phys);
+	const uintptr_t phys = dma_buffer_phys_base(&cmd->input_ctx);
+	TRB_SET_ICTX(cmd->_header.trb, phys);
 
 	/**
@@ -496,5 +497,6 @@
 		assert(dma_buffer_is_set(&cmd->input_ctx));
 
-		TRB_SET_ICTX(cmd->_header.trb, cmd->input_ctx.phys);
+		const uintptr_t phys = dma_buffer_phys_base(&cmd->input_ctx);
+		TRB_SET_ICTX(cmd->_header.trb, phys);
 	}
 
@@ -520,5 +522,6 @@
 	xhci_trb_clean(&cmd->_header.trb);
 
-	TRB_SET_ICTX(cmd->_header.trb, cmd->input_ctx.phys);
+	const uintptr_t phys = dma_buffer_phys_base(&cmd->input_ctx);
+	TRB_SET_ICTX(cmd->_header.trb, phys);
 
 	TRB_SET_TYPE(cmd->_header.trb, XHCI_TRB_TYPE_EVALUATE_CONTEXT_CMD);
@@ -594,5 +597,6 @@
 	xhci_trb_clean(&cmd->_header.trb);
 
-	TRB_SET_ICTX(cmd->_header.trb, cmd->bandwidth_ctx.phys);
+	const uintptr_t phys = dma_buffer_phys_base(&cmd->input_ctx);
+	TRB_SET_ICTX(cmd->_header.trb, phys);
 
 	TRB_SET_TYPE(cmd->_header.trb, XHCI_TRB_TYPE_GET_PORT_BANDWIDTH_CMD);
Index: uspace/drv/bus/usb/xhci/endpoint.c
===================================================================
--- uspace/drv/bus/usb/xhci/endpoint.c	(revision d345ce2f2396010ea2fd5ad90e85202da83d5197)
+++ uspace/drv/bus/usb/xhci/endpoint.c	(revision 1d758fc6d12dfedeea03efca816537794a056af2)
@@ -116,14 +116,16 @@
 		goto err;
 
-	/* Driver can handle non-contiguous buffers */
-	ep->transfer_buffer_policy &= ~DMA_POLICY_CONTIGUOUS;
-
-	/* Driver can handle buffers crossing boundaries */
-	ep->transfer_buffer_policy &= ~DMA_POLICY_NOT_CROSSING;
+	unsigned flags = -1U;
 
 	/* Some xHCs can handle 64-bit addresses */
 	xhci_bus_t *bus = bus_to_xhci_bus(ep->device->bus);
 	if (bus->hc->ac64)
-		ep->transfer_buffer_policy &= ~DMA_POLICY_4GiB;
+		flags &= ~DMA_POLICY_4GiB;
+
+	/* xHCI works best if it can fit 65k transfers in one TRB */
+	ep->transfer_buffer_policy = dma_policy_create(flags, 1 << 16);
+
+	/* But actualy can do full scatter-gather. */
+	ep->required_transfer_buffer_policy = dma_policy_create(flags, PAGE_SIZE);
 
 	return EOK;
Index: uspace/drv/bus/usb/xhci/hc.c
===================================================================
--- uspace/drv/bus/usb/xhci/hc.c	(revision d345ce2f2396010ea2fd5ad90e85202da83d5197)
+++ uspace/drv/bus/usb/xhci/hc.c	(revision 1d758fc6d12dfedeea03efca816537794a056af2)
@@ -476,5 +476,6 @@
 		return ETIMEOUT;
 
-	XHCI_REG_WR(hc->op_regs, XHCI_OP_DCBAAP, hc->dcbaa_dma.phys);
+	uintptr_t dcbaa_phys = dma_buffer_phys_base(&hc->dcbaa_dma);
+	XHCI_REG_WR(hc->op_regs, XHCI_OP_DCBAAP, dcbaa_phys);
 	XHCI_REG_WR(hc->op_regs, XHCI_OP_MAX_SLOTS_EN, hc->max_slots);
 
@@ -490,5 +491,7 @@
 	XHCI_REG_WR(intr0, XHCI_INTR_ERSTSZ, hc->event_ring.segment_count);
 	XHCI_REG_WR(intr0, XHCI_INTR_ERDP, hc->event_ring.dequeue_ptr);
-	XHCI_REG_WR(intr0, XHCI_INTR_ERSTBA, hc->event_ring.erst.phys);
+
+	const uintptr_t erstba_phys = dma_buffer_phys_base(&hc->event_ring.erst);
+	XHCI_REG_WR(intr0, XHCI_INTR_ERSTBA, erstba_phys);
 
 	if (hc->base.irq_cap > 0) {
@@ -799,5 +802,6 @@
 	if (err == EOK) {
 		dev->slot_id = cmd.slot_id;
-		hc->dcbaa[dev->slot_id] = host2xhci(64, dev->dev_ctx.phys);
+		hc->dcbaa[dev->slot_id] =
+		    host2xhci(64, dma_buffer_phys_base(&dev->dev_ctx));
 	}
 
Index: uspace/drv/bus/usb/xhci/isoch.c
===================================================================
--- uspace/drv/bus/usb/xhci/isoch.c	(revision d345ce2f2396010ea2fd5ad90e85202da83d5197)
+++ uspace/drv/bus/usb/xhci/isoch.c	(revision 1d758fc6d12dfedeea03efca816537794a056af2)
@@ -176,5 +176,5 @@
 	xhci_trb_clean(&trb);
 
-	trb.parameter = it->data.phys;
+	trb.parameter = host2xhci(64, dma_buffer_phys_base(&it->data));
 	TRB_CTRL_SET_XFER_LEN(trb, it->size);
 	TRB_CTRL_SET_TD_SIZE(trb, 0);
@@ -481,5 +481,5 @@
 
 	/* This shall be already checked by endpoint */
-	assert(transfer->batch.buffer_size <= ep->base.max_transfer_size);
+	assert(transfer->batch.size <= ep->base.max_transfer_size);
 
 	fibril_mutex_lock(&isoch->guard);
@@ -521,5 +521,5 @@
 
 	/* Prepare the transfer. */
-	it->size = transfer->batch.buffer_size;
+	it->size = transfer->batch.size;
 	memcpy(it->data.virt, transfer->batch.dma_buffer.virt, it->size);
 	it->state = ISOCH_FILLED;
@@ -544,5 +544,5 @@
 	xhci_isoch_t * const isoch = ep->isoch;
 
-	if (transfer->batch.buffer_size < ep->base.max_transfer_size) {
+	if (transfer->batch.size < ep->base.max_transfer_size) {
 		usb_log_error("Cannot schedule an undersized isochronous transfer.");
 		return ELIMIT;
Index: uspace/drv/bus/usb/xhci/scratchpad.c
===================================================================
--- uspace/drv/bus/usb/xhci/scratchpad.c	(revision d345ce2f2396010ea2fd5ad90e85202da83d5197)
+++ uspace/drv/bus/usb/xhci/scratchpad.c	(revision 1d758fc6d12dfedeea03efca816537794a056af2)
@@ -72,11 +72,13 @@
 	memset(hc->scratchpad_array.virt, 0, size);
 
-	uint64_t phys_begin = hc->scratchpad_array.phys + array_size;
+	const char *base = hc->scratchpad_array.virt + array_size;
 	uint64_t *array = hc->scratchpad_array.virt;
 
-	for (unsigned i = 0; i < num_bufs; ++i)
-		array[i] = host2xhci(64, phys_begin + i * PAGE_SIZE);
+	for (unsigned i = 0; i < num_bufs; ++i) {
+		array[i] = host2xhci(64, dma_buffer_phys(&hc->scratchpad_array,
+			    base + i * PAGE_SIZE));
+	}
 
-	hc->dcbaa[0] = host2xhci(64, hc->scratchpad_array.phys);
+	hc->dcbaa[0] = host2xhci(64, dma_buffer_phys_base(&hc->scratchpad_array));
 
 	usb_log_debug("Allocated %d scratchpad buffers.", num_bufs);
Index: uspace/drv/bus/usb/xhci/streams.c
===================================================================
--- uspace/drv/bus/usb/xhci/streams.c	(revision d345ce2f2396010ea2fd5ad90e85202da83d5197)
+++ uspace/drv/bus/usb/xhci/streams.c	(revision 1d758fc6d12dfedeea03efca816537794a056af2)
@@ -239,5 +239,5 @@
 	data->secondary_stream_ctx_array = data->secondary_stream_ctx_dma.virt;
 
-	XHCI_STREAM_DEQ_PTR_SET(*ctx, data->secondary_stream_ctx_dma.phys);
+	XHCI_STREAM_DEQ_PTR_SET(*ctx, dma_buffer_phys_base(&data->secondary_stream_ctx_dma));
 	XHCI_STREAM_SCT_SET(*ctx, fnzb32(count) + 1);
 
@@ -283,5 +283,5 @@
 
 	XHCI_EP_MAX_P_STREAMS_SET(*ctx, pstreams);
-	XHCI_EP_TR_DPTR_SET(*ctx, xhci_ep->primary_stream_ctx_dma.phys);
+	XHCI_EP_TR_DPTR_SET(*ctx, dma_buffer_phys_base(&xhci_ep->primary_stream_ctx_dma));
 	XHCI_EP_LSA_SET(*ctx, lsa);
 }
Index: uspace/drv/bus/usb/xhci/transfers.c
===================================================================
--- uspace/drv/bus/usb/xhci/transfers.c	(revision d345ce2f2396010ea2fd5ad90e85202da83d5197)
+++ uspace/drv/bus/usb/xhci/transfers.c	(revision 1d758fc6d12dfedeea03efca816537794a056af2)
@@ -126,5 +126,5 @@
 static int calculate_trb_count(xhci_transfer_t *transfer)
 {
-	const size_t size = transfer->batch.buffer_size;
+	const size_t size = transfer->batch.size;
 	return (size + PAGE_SIZE - 1 )/ PAGE_SIZE;
 }
@@ -184,5 +184,5 @@
 		int stage_dir = REQUEST_TYPE_IS_DEVICE_TO_HOST(setup->request_type)
 					? STAGE_IN : STAGE_OUT;
-		size_t remaining = transfer->batch.buffer_size;
+		size_t remaining = transfer->batch.size;
 
 		for (size_t i = 0; i < buffer_count; ++i) {
@@ -227,5 +227,5 @@
 		const size_t buffer_count = calculate_trb_count(transfer);
 		xhci_trb_t trbs[buffer_count];
-		size_t remaining = transfer->batch.buffer_size;
+		size_t remaining = transfer->batch.size;
 
 		for (size_t i = 0; i < buffer_count; ++i) {
@@ -254,5 +254,5 @@
 		const size_t buffer_count = calculate_trb_count(transfer);
 		xhci_trb_t trbs[buffer_count + 1];
-		size_t remaining = transfer->batch.buffer_size;
+		size_t remaining = transfer->batch.size;
 
 		for (size_t i = 0; i < buffer_count; ++i) {
@@ -278,5 +278,5 @@
 	const size_t buffer_count = calculate_trb_count(transfer);
 	xhci_trb_t trbs[buffer_count];
-	size_t remaining = transfer->batch.buffer_size;
+	size_t remaining = transfer->batch.size;
 
 	for (size_t i = 0; i < buffer_count; ++i) {
@@ -372,5 +372,5 @@
 		case XHCI_TRBC_SUCCESS:
 			batch->error = EOK;
-			batch->transferred_size = batch->buffer_size - TRB_TRANSFER_LENGTH(*trb);
+			batch->transferred_size = batch->size - TRB_TRANSFER_LENGTH(*trb);
 			break;
 
@@ -416,5 +416,5 @@
 	}
 
-	assert(batch->transferred_size <= batch->buffer_size);
+	assert(batch->transferred_size <= batch->size);
 
 	usb_transfer_batch_finish(batch);
Index: uspace/drv/bus/usb/xhci/trb_ring.c
===================================================================
--- uspace/drv/bus/usb/xhci/trb_ring.c	(revision d345ce2f2396010ea2fd5ad90e85202da83d5197)
+++ uspace/drv/bus/usb/xhci/trb_ring.c	(revision 1d758fc6d12dfedeea03efca816537794a056af2)
@@ -89,13 +89,15 @@
 static errno_t trb_segment_alloc(trb_segment_t **segment)
 {
-	dma_buffer_t dbuf;
-
-	const errno_t err = dma_buffer_alloc(&dbuf, PAGE_SIZE);
+	*segment = AS_AREA_ANY;
+	uintptr_t phys;
+
+	const int err = dmamem_map_anonymous(PAGE_SIZE,
+	    DMAMEM_4GiB, AS_AREA_READ | AS_AREA_WRITE, 0,
+	    &phys, (void **) segment);
 	if (err)
 		return err;
 
-	*segment = dbuf.virt;
 	memset(*segment, 0, PAGE_SIZE);
-	(*segment)->phys = dbuf.phys;
+	(*segment)->phys = phys;
 	usb_log_debug("Allocated new ring segment.");
 	return EOK;
@@ -104,6 +106,5 @@
 static void trb_segment_free(trb_segment_t *segment)
 {
-	dma_buffer_t dbuf = { .virt = segment, .phys = segment->phys };
-	dma_buffer_free(&dbuf);
+	dmamem_unmap_anonymous(segment);
 }
 
