Index: uspace/drv/bus/usb/xhci/commands.c
===================================================================
--- uspace/drv/bus/usb/xhci/commands.c	(revision db51a6a671d00feb477a7c35b072e80c77fe4a6f)
+++ uspace/drv/bus/usb/xhci/commands.c	(revision 998773d2ccfa124e237ab008ad97974ceb050320)
@@ -77,5 +77,5 @@
 	int err;
 
-	if ((err = xhci_trb_ring_init(&cr->trb_ring)))
+	if ((err = xhci_trb_ring_init(&cr->trb_ring, 0)))
 		return err;
 
Index: uspace/drv/bus/usb/xhci/endpoint.c
===================================================================
--- uspace/drv/bus/usb/xhci/endpoint.c	(revision db51a6a671d00feb477a7c35b072e80c77fe4a6f)
+++ uspace/drv/bus/usb/xhci/endpoint.c	(revision 998773d2ccfa124e237ab008ad97974ceb050320)
@@ -285,5 +285,5 @@
 
 	int err;
-	if ((err = xhci_trb_ring_init(&xhci_ep->ring))) {
+	if ((err = xhci_trb_ring_init(&xhci_ep->ring, 0))) {
 		return err;
 	}
Index: uspace/drv/bus/usb/xhci/hc.c
===================================================================
--- uspace/drv/bus/usb/xhci/hc.c	(revision db51a6a671d00feb477a7c35b072e80c77fe4a6f)
+++ uspace/drv/bus/usb/xhci/hc.c	(revision 998773d2ccfa124e237ab008ad97974ceb050320)
@@ -262,5 +262,5 @@
 	hc->dcbaa = hc->dcbaa_dma.virt;
 
-	if ((err = xhci_event_ring_init(&hc->event_ring)))
+	if ((err = xhci_event_ring_init(&hc->event_ring, 1)))
 		goto err_dcbaa;
 
@@ -494,5 +494,4 @@
 	XHCI_REG_WR(intr0, XHCI_INTR_ERSTBA_HI, UPPER32(erstptr));
 
-
 	if (irq) {
 		XHCI_REG_SET(intr0, XHCI_INTR_IE, 1);
Index: uspace/drv/bus/usb/xhci/streams.c
===================================================================
--- uspace/drv/bus/usb/xhci/streams.c	(revision db51a6a671d00feb477a7c35b072e80c77fe4a6f)
+++ uspace/drv/bus/usb/xhci/streams.c	(revision 998773d2ccfa124e237ab008ad97974ceb050320)
@@ -154,5 +154,5 @@
 
 	/* Init and register TRB ring for the primary stream */
-	if ((err = xhci_trb_ring_init(&data->ring))) {
+	if ((err = xhci_trb_ring_init(&data->ring, 0))) {
 		return err;
 	}
@@ -233,5 +233,5 @@
 		xhci_stream_data_t *secondary_data = &data->secondary_data[index];
 		/* Init and register TRB ring for every secondary stream */
-		if ((err = xhci_trb_ring_init(&secondary_data->ring))) {
+		if ((err = xhci_trb_ring_init(&secondary_data->ring, 0))) {
 			goto err_init;
 		}
@@ -332,5 +332,5 @@
 	/* Streams are now removed, proceed with reconfiguring endpoint. */
 	int err;
-	if ((err = xhci_trb_ring_init(&xhci_ep->ring))) {
+	if ((err = xhci_trb_ring_init(&xhci_ep->ring, 0))) {
 		usb_log_error("Failed to initialize a transfer ring.");
 		return err;
Index: uspace/drv/bus/usb/xhci/trb_ring.c
===================================================================
--- uspace/drv/bus/usb/xhci/trb_ring.c	(revision db51a6a671d00feb477a7c35b072e80c77fe4a6f)
+++ uspace/drv/bus/usb/xhci/trb_ring.c	(revision 998773d2ccfa124e237ab008ad97974ceb050320)
@@ -37,10 +37,12 @@
 #include "trb_ring.h"
 
-#define SEGMENT_HEADER_SIZE (sizeof(link_t) + sizeof(uintptr_t))
-
-/**
- * Number of TRBs in a segment (with our header).
- */
-#define SEGMENT_TRB_COUNT ((PAGE_SIZE - SEGMENT_HEADER_SIZE) / sizeof(xhci_trb_t))
+/**
+ * A structure representing a segment of a TRB ring.
+ */
+
+#define SEGMENT_FOOTER_SIZE (sizeof(link_t) + sizeof(uintptr_t))
+
+#define SEGMENT_TRB_COUNT ((PAGE_SIZE - SEGMENT_FOOTER_SIZE) / sizeof(xhci_trb_t))
+#define SEGMENT_TRB_USEFUL_COUNT (SEGMENT_TRB_COUNT - 1)
 
 struct trb_segment {
@@ -51,4 +53,6 @@
 } __attribute__((aligned(PAGE_SIZE)));
 
+static_assert(sizeof(trb_segment_t) == PAGE_SIZE);
+
 
 /**
@@ -66,4 +70,13 @@
 {
 	return segment_begin(segment) + SEGMENT_TRB_COUNT;
+}
+
+/**
+ * Return a first segment of a list of segments.
+ */
+static inline trb_segment_t *get_first_segment(list_t *segments)
+{
+	return list_get_instance(list_first(segments), trb_segment_t, segments_link);
+
 }
 
@@ -97,18 +110,28 @@
 /**
  * Initializes the ring with one segment.
- */
-int xhci_trb_ring_init(xhci_trb_ring_t *ring)
-{
-	struct trb_segment *segment;
+ *
+ * @param[in] initial_size A number of free slots on the ring, 0 leaves the
+ * choice on a reasonable default (one page-sized segment).
+ */
+int xhci_trb_ring_init(xhci_trb_ring_t *ring, size_t initial_size)
+{
 	int err;
+	if (initial_size == 0)
+		initial_size = SEGMENT_TRB_USEFUL_COUNT;
 
 	list_initialize(&ring->segments);
-
-	if ((err = trb_segment_alloc(&segment)) != EOK)
-		return err;
-
-	list_append(&segment->segments_link, &ring->segments);
-	ring->segment_count = 1;
-
+	size_t segment_count = (initial_size + SEGMENT_TRB_USEFUL_COUNT - 1)
+		/ SEGMENT_TRB_USEFUL_COUNT;
+
+	for (size_t i = 0; i < segment_count; ++i) {
+		struct trb_segment *segment;
+		if ((err = trb_segment_alloc(&segment)) != EOK)
+			return err;
+
+		list_append(&segment->segments_link, &ring->segments);
+		ring->segment_count = i + 1;
+	}
+
+	trb_segment_t * const segment = get_first_segment(&ring->segments);
 	xhci_trb_t *last = segment_end(segment) - 1;
 	xhci_trb_link_fill(last, segment->phys);
@@ -284,31 +307,43 @@
 /**
  * Initializes an event ring.
- */
-int xhci_event_ring_init(xhci_event_ring_t *ring)
-{
-	struct trb_segment *segment;
+ *
+ * @param[in] initial_size A number of free slots on the ring, 0 leaves the
+ * choice on a reasonable default (one page-sized segment).
+ */
+int xhci_event_ring_init(xhci_event_ring_t *ring, size_t initial_size)
+{
 	int err;
+	if (initial_size == 0)
+		initial_size = SEGMENT_TRB_COUNT;
 
 	list_initialize(&ring->segments);
 
-	if ((err = trb_segment_alloc(&segment)) != EOK)
-		return err;
-
-	list_append(&segment->segments_link, &ring->segments);
-	ring->segment_count = 1;
-
+	size_t segment_count = (initial_size + SEGMENT_TRB_COUNT - 1) / SEGMENT_TRB_COUNT;
+	size_t erst_size = segment_count * sizeof(xhci_erst_entry_t);
+
+	if (dma_buffer_alloc(&ring->erst, erst_size)) {
+		xhci_event_ring_fini(ring);
+		return ENOMEM;
+	}
+
+	xhci_erst_entry_t *erst = ring->erst.virt;
+	memset(erst, 0, erst_size);
+
+	for (size_t i = 0; i < segment_count; i++) {
+		trb_segment_t *segment;
+		if ((err = trb_segment_alloc(&segment)) != EOK) {
+			xhci_event_ring_fini(ring);
+			return err;
+		}
+
+		list_append(&segment->segments_link, &ring->segments);
+		ring->segment_count = i + 1;
+		xhci_fill_erst_entry(&erst[i], segment->phys, SEGMENT_TRB_COUNT);
+	}
+
+	trb_segment_t * const segment = get_first_segment(&ring->segments);
 	ring->dequeue_segment = segment;
 	ring->dequeue_trb = segment_begin(segment);
 	ring->dequeue_ptr = segment->phys;
-
-	if (dma_buffer_alloc(&ring->erst, PAGE_SIZE)) {
-		xhci_event_ring_fini(ring);
-		return ENOMEM;
-	}
-	xhci_erst_entry_t *erst = ring->erst.virt;
-
-	memset(erst, 0, PAGE_SIZE);
-	xhci_fill_erst_entry(&erst[0], segment->phys, SEGMENT_TRB_COUNT);
-
 	ring->ccs = 1;
 
@@ -316,5 +351,4 @@
 
 	usb_log_debug("Initialized event ring.");
-
 	return EOK;
 }
@@ -324,5 +358,5 @@
 	list_foreach_safe(ring->segments, cur, next) {
 		trb_segment_t *segment = list_get_instance(cur, trb_segment_t, segments_link);
-		dmamem_unmap_anonymous(segment);
+		trb_segment_free(segment);
 	}
 
Index: uspace/drv/bus/usb/xhci/trb_ring.h
===================================================================
--- uspace/drv/bus/usb/xhci/trb_ring.h	(revision db51a6a671d00feb477a7c35b072e80c77fe4a6f)
+++ uspace/drv/bus/usb/xhci/trb_ring.h	(revision 998773d2ccfa124e237ab008ad97974ceb050320)
@@ -74,5 +74,5 @@
 } xhci_trb_ring_t;
 
-int xhci_trb_ring_init(xhci_trb_ring_t *);
+int xhci_trb_ring_init(xhci_trb_ring_t *, size_t);
 void xhci_trb_ring_fini(xhci_trb_ring_t *);
 int xhci_trb_ring_enqueue(xhci_trb_ring_t *, xhci_trb_t *, uintptr_t *);
@@ -107,5 +107,5 @@
 } xhci_event_ring_t;
 
-int xhci_event_ring_init(xhci_event_ring_t *);
+int xhci_event_ring_init(xhci_event_ring_t *, size_t);
 void xhci_event_ring_fini(xhci_event_ring_t *);
 int xhci_event_ring_dequeue(xhci_event_ring_t *, xhci_trb_t *);
