Browse Source

[ncm] Use large multi-packet buffers by default

Some devices have a very small number of internal buffers, and rely on
being able to pack multiple packets into each buffer.  Using 2048-byte
buffers on such devices produces throughput of around 100Mbps.  Using
a small number of much larger buffers (e.g. 32kB) increases the
throughput to around 780Mbps.  (The full 1Gbps is not reached because
the high RTT induced by the use of multi-packet buffers causes us to
saturate our 256kB TCP window.)

Since allocation of large buffers is very likely to fail, allocate the
buffer set only once when the device is opened and recycle buffers
immediately after use.  Received data is now always copied to
per-packet buffers.

If allocation of large buffers fails, fall back to allocating a larger
number of smaller buffers.  This will give reduced performance, but
the device will at least still be functional.

Share code between the interrupt and bulk IN endpoint handlers, since
the buffer handling is now very similar.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 9 years ago
parent
commit
2d3f2b2446
2 changed files with 301 additions and 165 deletions
  1. 251
    140
      src/drivers/net/ncm.c
  2. 50
    25
      src/drivers/net/ncm.h

+ 251
- 140
src/drivers/net/ncm.c View File

35
  *
35
  *
36
  */
36
  */
37
 
37
 
38
+/** Ring refill profiler */
39
+static struct profiler ncm_refill_profiler __profiler =
40
+	{ .name = "ncm.refill" };
41
+
38
 /** Interrupt completion profiler */
42
 /** Interrupt completion profiler */
39
 static struct profiler ncm_intr_profiler __profiler =
43
 static struct profiler ncm_intr_profiler __profiler =
40
 	{ .name = "ncm.intr" };
44
 	{ .name = "ncm.intr" };
41
 
45
 
42
-/** Interrupt refill profiler */
43
-static struct profiler ncm_intr_refill_profiler __profiler =
44
-	{ .name = "ncm.intr_refill" };
45
-
46
 /** Bulk IN completion profiler */
46
 /** Bulk IN completion profiler */
47
 static struct profiler ncm_in_profiler __profiler =
47
 static struct profiler ncm_in_profiler __profiler =
48
 	{ .name = "ncm.in" };
48
 	{ .name = "ncm.in" };
51
 static struct profiler ncm_in_datagram_profiler __profiler =
51
 static struct profiler ncm_in_datagram_profiler __profiler =
52
 	{ .name = "ncm.in_dgram" };
52
 	{ .name = "ncm.in_dgram" };
53
 
53
 
54
-/** Bulk IN refill profiler */
55
-static struct profiler ncm_in_refill_profiler __profiler =
56
-	{ .name = "ncm.in_refill" };
57
-
58
 /** Bulk OUT profiler */
54
 /** Bulk OUT profiler */
59
 static struct profiler ncm_out_profiler __profiler =
55
 static struct profiler ncm_out_profiler __profiler =
60
 	{ .name = "ncm.out" };
56
 	{ .name = "ncm.out" };
61
 
57
 
62
 /******************************************************************************
58
 /******************************************************************************
63
  *
59
  *
64
- * CDC-NCM communications interface
60
+ * Ring management
65
  *
61
  *
66
  ******************************************************************************
62
  ******************************************************************************
67
  */
63
  */
68
 
64
 
69
 /**
65
 /**
70
- * Refill interrupt ring
66
+ * Transcribe receive ring name (for debugging)
67
+ *
68
+ * @v ncm		CDC-NCM device
69
+ * @v ring		Receive ring
70
+ * @ret name		Receive ring name
71
+ */
72
+static inline const char * ncm_rx_name ( struct ncm_device *ncm,
73
+					 struct ncm_rx_ring *ring ) {
74
+	if ( ring == &ncm->intr ) {
75
+		return "interrupt";
76
+	} else if ( ring == &ncm->in ) {
77
+		return "bulk IN";
78
+	} else {
79
+		return "UNKNOWN";
80
+	}
81
+}
82
+
83
+/**
84
+ * Allocate receive ring buffers
85
+ *
86
+ * @v ncm		CDC-NCM device
87
+ * @v ring		Receive ring
88
+ * @v mtu		I/O buffer size
89
+ * @v count		Number of I/O buffers
90
+ * @ret rc		Return status code
91
+ */
92
+static int ncm_rx_alloc ( struct ncm_device *ncm, struct ncm_rx_ring *ring,
93
+			  size_t mtu, unsigned int count ) {
94
+	struct io_buffer *iobuf;
95
+	struct io_buffer *tmp;
96
+	unsigned int i;
97
+	int rc;
98
+
99
+	/* Initialise ring */
100
+	ring->mtu = mtu;
101
+	INIT_LIST_HEAD ( &ring->list );
102
+
103
+	/* Allocate I/O buffers */
104
+	for ( i = 0 ; i < count ; i++ ) {
105
+		iobuf = alloc_iob ( mtu );
106
+		if ( ! iobuf ) {
107
+			DBGC ( ncm, "NCM %p could not allocate %dx %zd-byte "
108
+			       "buffers for %s\n", ncm, count, mtu,
109
+			       ncm_rx_name ( ncm, ring ) );
110
+			rc = -ENOMEM;
111
+			goto err_alloc;
112
+		}
113
+		list_add ( &iobuf->list, &ring->list );
114
+	}
115
+
116
+	return 0;
117
+
118
+ err_alloc:
119
+	list_for_each_entry_safe ( iobuf, tmp, &ring->list, list ) {
120
+		list_del ( &iobuf->list );
121
+		free_iob ( iobuf );
122
+	}
123
+	return rc;
124
+}
125
+
126
+/**
127
+ * Refill receive ring
71
  *
128
  *
72
  * @v ncm		CDC-NCM device
129
  * @v ncm		CDC-NCM device
130
+ * @v ring		Receive ring
131
+ * @ret rc		Return status code
73
  */
132
  */
74
-static void ncm_intr_refill ( struct ncm_device *ncm ) {
133
+static int ncm_rx_refill ( struct ncm_device *ncm, struct ncm_rx_ring *ring ) {
75
 	struct io_buffer *iobuf;
134
 	struct io_buffer *iobuf;
76
-	size_t mtu = ncm->intr.mtu;
77
 	int rc;
135
 	int rc;
78
 
136
 
79
-	/* Enqueue any available I/O buffers */
80
-	while ( ( iobuf = list_first_entry ( &ncm->intrs, struct io_buffer,
137
+	/* Enqueue any recycled I/O buffers */
138
+	while ( ( iobuf = list_first_entry ( &ring->list, struct io_buffer,
81
 					     list ) ) ) {
139
 					     list ) ) ) {
82
 
140
 
83
 		/* Profile refill */
141
 		/* Profile refill */
84
-		profile_start ( &ncm_intr_refill_profiler );
142
+		profile_start ( &ncm_refill_profiler );
85
 
143
 
86
 		/* Reset size */
144
 		/* Reset size */
87
-		iob_put ( iobuf, ( mtu - iob_len ( iobuf ) ) );
145
+		iob_put ( iobuf, ( ring->mtu - iob_len ( iobuf ) ) );
88
 
146
 
89
 		/* Enqueue I/O buffer */
147
 		/* Enqueue I/O buffer */
90
-		if ( ( rc = usb_stream ( &ncm->intr, iobuf ) ) != 0 ) {
91
-			DBGC ( ncm, "NCM %p could not enqueue interrupt: %s\n",
92
-			       ncm, strerror ( rc ) );
93
-			/* Leave in available list and wait for next refill */
94
-			return;
148
+		if ( ( rc = usb_stream ( &ring->ep, iobuf ) ) != 0 ) {
149
+			DBGC ( ncm, "NCM %p could not enqueue %s: %s\n", ncm,
150
+			       ncm_rx_name ( ncm, ring ), strerror ( rc ) );
151
+			/* Leave in recycled list and wait for next refill */
152
+			return rc;
95
 		}
153
 		}
96
 
154
 
97
-		/* Remove from available list */
155
+		/* Remove from recycled list */
98
 		list_del ( &iobuf->list );
156
 		list_del ( &iobuf->list );
99
-		profile_stop ( &ncm_intr_refill_profiler );
157
+		profile_stop ( &ncm_refill_profiler );
100
 	}
158
 	}
159
+
160
+	return 0;
161
+}
162
+
163
+/**
164
+ * Recycle receive buffer
165
+ *
166
+ * @v ncm		CDC-NCM device
167
+ * @v ring		Receive ring
168
+ * @v iobuf		I/O buffer
169
+ */
170
+static inline void ncm_rx_recycle ( struct ncm_device *ncm __unused,
171
+				    struct ncm_rx_ring *ring,
172
+				    struct io_buffer *iobuf ) {
173
+
174
+	/* Add to recycled list */
175
+	list_add_tail ( &iobuf->list, &ring->list );
101
 }
176
 }
102
 
177
 
178
+/**
179
+ * Free receive ring
180
+ *
181
+ * @v ncm		CDC-NCM device
182
+ * @v ring		Receive ring
183
+ */
184
+static void ncm_rx_free ( struct ncm_device *ncm __unused,
185
+			  struct ncm_rx_ring *ring ) {
186
+	struct io_buffer *iobuf;
187
+	struct io_buffer *tmp;
188
+
189
+	/* Free I/O buffers */
190
+	list_for_each_entry_safe ( iobuf, tmp, &ring->list, list ) {
191
+		list_del ( &iobuf->list );
192
+		free_iob ( iobuf );
193
+	}
194
+}
195
+
196
+/******************************************************************************
197
+ *
198
+ * CDC-NCM communications interface
199
+ *
200
+ ******************************************************************************
201
+ */
202
+
103
 /**
203
 /**
104
  * Complete interrupt transfer
204
  * Complete interrupt transfer
105
  *
205
  *
109
  */
209
  */
110
 static void ncm_intr_complete ( struct usb_endpoint *ep,
210
 static void ncm_intr_complete ( struct usb_endpoint *ep,
111
 				struct io_buffer *iobuf, int rc ) {
211
 				struct io_buffer *iobuf, int rc ) {
112
-	struct ncm_device *ncm = container_of ( ep, struct ncm_device, intr );
212
+	struct ncm_device *ncm = container_of ( ep, struct ncm_device, intr.ep);
113
 	struct net_device *netdev = ncm->netdev;
213
 	struct net_device *netdev = ncm->netdev;
114
 	struct usb_setup_packet *message;
214
 	struct usb_setup_packet *message;
115
 	size_t len = iob_len ( iobuf );
215
 	size_t len = iob_len ( iobuf );
161
 	}
261
 	}
162
 
262
 
163
  done:
263
  done:
164
-	/* Return I/O buffer to available list */
165
-	list_add_tail ( &iobuf->list, &ncm->intrs );
264
+	/* Recycle buffer */
265
+	ncm_rx_recycle ( ncm, &ncm->intr, iobuf );
166
 	profile_stop ( &ncm_intr_profiler );
266
 	profile_stop ( &ncm_intr_profiler );
167
 }
267
 }
168
 
268
 
178
  * @ret rc		Return status code
278
  * @ret rc		Return status code
179
  */
279
  */
180
 static int ncm_comms_open ( struct ncm_device *ncm ) {
280
 static int ncm_comms_open ( struct ncm_device *ncm ) {
181
-	struct io_buffer *iobuf;
182
-	struct io_buffer *tmp;
183
-	unsigned int i;
184
 	int rc;
281
 	int rc;
185
 
282
 
186
 	/* Allocate I/O buffers */
283
 	/* Allocate I/O buffers */
187
-	for ( i = 0 ; i < NCM_INTR_FILL ; i++ ) {
188
-		iobuf = alloc_iob ( ncm->intr.mtu );
189
-		if ( ! iobuf ) {
190
-			rc = -ENOMEM;
191
-			goto err_alloc_iob;
192
-		}
193
-		list_add ( &iobuf->list, &ncm->intrs );
284
+	if ( ( rc = ncm_rx_alloc ( ncm, &ncm->intr, ncm->intr.ep.mtu,
285
+				   NCM_INTR_COUNT ) ) != 0 ) {
286
+		DBGC ( ncm, "NCM %p could not allocate RX buffers: %s\n",
287
+		       ncm, strerror ( rc ) );
288
+		goto err_alloc;
194
 	}
289
 	}
195
 
290
 
196
 	/* Open interrupt endpoint */
291
 	/* Open interrupt endpoint */
197
-	if ( ( rc = usb_endpoint_open ( &ncm->intr ) ) != 0 ) {
292
+	if ( ( rc = usb_endpoint_open ( &ncm->intr.ep ) ) != 0 ) {
198
 		DBGC ( ncm, "NCM %p could not open interrupt: %s\n",
293
 		DBGC ( ncm, "NCM %p could not open interrupt: %s\n",
199
 		       ncm, strerror ( rc ) );
294
 		       ncm, strerror ( rc ) );
200
 		goto err_open;
295
 		goto err_open;
202
 
297
 
203
 	return 0;
298
 	return 0;
204
 
299
 
205
-	usb_endpoint_close ( &ncm->intr );
300
+	usb_endpoint_close ( &ncm->intr.ep );
206
  err_open:
301
  err_open:
207
- err_alloc_iob:
208
-	list_for_each_entry_safe ( iobuf, tmp, &ncm->intrs, list ) {
209
-		list_del ( &iobuf->list );
210
-		free_iob ( iobuf );
211
-	}
302
+	ncm_rx_free ( ncm, &ncm->intr );
303
+ err_alloc:
212
 	return rc;
304
 	return rc;
213
 }
305
 }
214
 
306
 
218
  * @v ncm		CDC-NCM device
310
  * @v ncm		CDC-NCM device
219
  */
311
  */
220
 static void ncm_comms_close ( struct ncm_device *ncm ) {
312
 static void ncm_comms_close ( struct ncm_device *ncm ) {
221
-	struct io_buffer *iobuf;
222
-	struct io_buffer *tmp;
223
 
313
 
224
 	/* Close interrupt endpoint */
314
 	/* Close interrupt endpoint */
225
-	usb_endpoint_close ( &ncm->intr );
315
+	usb_endpoint_close ( &ncm->intr.ep );
226
 
316
 
227
 	/* Free I/O buffers */
317
 	/* Free I/O buffers */
228
-	list_for_each_entry_safe ( iobuf, tmp, &ncm->intrs, list ) {
229
-		list_del ( &iobuf->list );
230
-		free_iob ( iobuf );
231
-	}
318
+	ncm_rx_free ( ncm, &ncm->intr );
232
 }
319
 }
233
 
320
 
234
 /******************************************************************************
321
 /******************************************************************************
239
  */
326
  */
240
 
327
 
241
 /**
328
 /**
242
- * Refill bulk IN ring
329
+ * Allocate bulk IN receive ring buffers
243
  *
330
  *
244
  * @v ncm		CDC-NCM device
331
  * @v ncm		CDC-NCM device
332
+ * @ret rc		Return status code
245
  */
333
  */
246
-static void ncm_in_refill ( struct ncm_device *ncm ) {
247
-	struct net_device *netdev = ncm->netdev;
248
-	struct io_buffer *iobuf;
334
+static int ncm_in_alloc ( struct ncm_device *ncm ) {
335
+	size_t mtu;
336
+	unsigned int count;
249
 	int rc;
337
 	int rc;
250
 
338
 
251
-	/* Refill ring */
252
-	while ( ncm->fill < NCM_IN_FILL ) {
253
-
254
-		/* Profile refill */
255
-		profile_start ( &ncm_in_refill_profiler );
256
-
257
-		/* Allocate I/O buffer */
258
-		iobuf = alloc_iob ( NCM_NTB_INPUT_SIZE );
259
-		if ( ! iobuf ) {
260
-			/* Wait for next refill */
261
-			break;
262
-		}
263
-		iob_put ( iobuf, NCM_NTB_INPUT_SIZE );
264
-
265
-		/* Enqueue I/O buffer */
266
-		if ( ( rc = usb_stream ( &ncm->in, iobuf ) ) != 0 ) {
267
-			netdev_rx_err ( netdev, iobuf, rc );
268
-			break;
269
-		}
270
-
271
-		/* Increment fill level */
272
-		ncm->fill++;
273
-		profile_stop ( &ncm_in_refill_profiler );
339
+	/* Some devices have a very small number of internal buffers,
340
+	 * and rely on being able to pack multiple packets into each
341
+	 * buffer.  We therefore want to use large buffers if
342
+	 * possible.  However, large allocations have a reasonable
343
+	 * chance of failure, especially if this is not the first or
344
+	 * only device to be opened.
345
+	 *
346
+	 * We therefore attempt to find a usable buffer size, starting
347
+	 * large and working downwards until allocation succeeds.
348
+	 * Smaller buffers will still work, albeit with a higher
349
+	 * chance of packet loss and so lower overall throughput.
350
+	 */
351
+	for ( mtu = ncm->mtu ; mtu >= NCM_MIN_NTB_INPUT_SIZE ; mtu >>= 1 ) {
352
+
353
+		/* Attempt allocation at this MTU */
354
+		if ( mtu > NCM_MAX_NTB_INPUT_SIZE )
355
+			continue;
356
+		count = ( NCM_IN_MIN_SIZE / mtu );
357
+		if ( count < NCM_IN_MIN_COUNT )
358
+			count = NCM_IN_MIN_COUNT;
359
+		if ( ( count * mtu ) > NCM_IN_MAX_SIZE )
360
+			continue;
361
+		if ( ( rc = ncm_rx_alloc ( ncm, &ncm->in, mtu, count ) ) != 0 )
362
+			continue;
363
+
364
+		DBGC ( ncm, "NCM %p using %dx %zd-byte buffers for bulk IN\n",
365
+		       ncm, count, mtu );
366
+		return 0;
274
 	}
367
 	}
368
+
369
+	DBGC ( ncm, "NCM %p could not allocate bulk IN buffers\n", ncm );
370
+	return -ENOMEM;
275
 }
371
 }
276
 
372
 
277
 /**
373
 /**
283
  */
379
  */
284
 static void ncm_in_complete ( struct usb_endpoint *ep, struct io_buffer *iobuf,
380
 static void ncm_in_complete ( struct usb_endpoint *ep, struct io_buffer *iobuf,
285
 			      int rc ) {
381
 			      int rc ) {
286
-	struct ncm_device *ncm = container_of ( ep, struct ncm_device, in );
382
+	struct ncm_device *ncm = container_of ( ep, struct ncm_device, in.ep );
287
 	struct net_device *netdev = ncm->netdev;
383
 	struct net_device *netdev = ncm->netdev;
288
 	struct ncm_transfer_header *nth;
384
 	struct ncm_transfer_header *nth;
289
 	struct ncm_datagram_pointer *ndp;
385
 	struct ncm_datagram_pointer *ndp;
299
 	/* Profile overall bulk IN completion */
395
 	/* Profile overall bulk IN completion */
300
 	profile_start ( &ncm_in_profiler );
396
 	profile_start ( &ncm_in_profiler );
301
 
397
 
302
-	/* Decrement fill level */
303
-	ncm->fill--;
304
-
305
 	/* Ignore packets cancelled when the endpoint closes */
398
 	/* Ignore packets cancelled when the endpoint closes */
306
 	if ( ! ep->open )
399
 	if ( ! ep->open )
307
 		goto ignore;
400
 		goto ignore;
308
 
401
 
309
 	/* Record USB errors against the network device */
402
 	/* Record USB errors against the network device */
310
-	if ( rc != 0 )
403
+	if ( rc != 0 ) {
404
+		DBGC ( ncm, "NCM %p bulk IN failed: %s\n",
405
+		       ncm, strerror ( rc ) );
311
 		goto drop;
406
 		goto drop;
407
+	}
312
 
408
 
313
 	/* Locate transfer header */
409
 	/* Locate transfer header */
314
 	len = iob_len ( iobuf );
410
 	len = iob_len ( iobuf );
358
 		/* Move to next descriptor */
454
 		/* Move to next descriptor */
359
 		desc++;
455
 		desc++;
360
 
456
 
361
-		/* Create new I/O buffer if necessary */
362
-		if ( remaining && desc->offset ) {
363
-			/* More packets remain: create new buffer */
364
-			pkt = alloc_iob ( pkt_len );
365
-			if ( ! pkt ) {
366
-				/* Record error and continue */
367
-				netdev_rx_err ( netdev, NULL, -ENOMEM );
368
-				continue;
369
-			}
370
-			memcpy ( iob_put ( pkt, pkt_len ),
371
-				 ( iobuf->data + pkt_offset ), pkt_len );
372
-		} else {
373
-			/* This is the last packet: use in situ */
374
-			pkt = iob_disown ( iobuf );
375
-			iob_pull ( pkt, pkt_offset );
376
-			iob_unput ( pkt, ( iob_len ( pkt ) - pkt_len ) );
457
+		/* Copy data to a new I/O buffer.  Our USB buffers may
458
+		 * be very large and so we choose to recycle the
459
+		 * buffers directly rather than attempt reallocation
460
+		 * while the device is running.  We therefore copy the
461
+		 * data to a new I/O buffer even if this is the only
462
+		 * (or last) packet within the buffer.
463
+		 */
464
+		pkt = alloc_iob ( pkt_len );
465
+		if ( ! pkt ) {
466
+			/* Record error and continue */
467
+			netdev_rx_err ( netdev, NULL, -ENOMEM );
468
+			continue;
377
 		}
469
 		}
470
+		memcpy ( iob_put ( pkt, pkt_len ),
471
+			 ( iobuf->data + pkt_offset ), pkt_len );
378
 
472
 
379
 		/* Strip CRC, if present */
473
 		/* Strip CRC, if present */
380
 		if ( ndp->magic & cpu_to_le32 ( NCM_DATAGRAM_POINTER_MAGIC_CRC))
474
 		if ( ndp->magic & cpu_to_le32 ( NCM_DATAGRAM_POINTER_MAGIC_CRC))
385
 		profile_stop ( &ncm_in_datagram_profiler );
479
 		profile_stop ( &ncm_in_datagram_profiler );
386
 	}
480
 	}
387
 
481
 
388
-	/* Free I/O buffer (if still present) */
389
-	free_iob ( iobuf );
390
-
482
+	/* Recycle I/O buffer */
483
+	ncm_rx_recycle ( ncm, &ncm->in, iobuf );
391
 	profile_stop ( &ncm_in_profiler );
484
 	profile_stop ( &ncm_in_profiler );
485
+
392
 	return;
486
 	return;
393
 
487
 
394
  error:
488
  error:
395
 	rc = -EIO;
489
 	rc = -EIO;
396
  drop:
490
  drop:
491
+	/* Record error against network device */
397
 	DBGC_HDA ( ncm, 0, iobuf->data, iob_len ( iobuf ) );
492
 	DBGC_HDA ( ncm, 0, iobuf->data, iob_len ( iobuf ) );
398
-	netdev_rx_err ( netdev, iobuf, rc );
399
-	return;
400
-
493
+	netdev_rx_err ( netdev, NULL, rc );
401
  ignore:
494
  ignore:
402
-	free_iob ( iobuf );
403
-	return;
495
+	ncm_rx_recycle ( ncm, &ncm->in, iobuf );
404
 }
496
 }
405
 
497
 
406
 /** Bulk IN endpoint operations */
498
 /** Bulk IN endpoint operations */
419
 			      struct io_buffer *iobuf ) {
511
 			      struct io_buffer *iobuf ) {
420
 	struct ncm_ntb_header *header;
512
 	struct ncm_ntb_header *header;
421
 	size_t len = iob_len ( iobuf );
513
 	size_t len = iob_len ( iobuf );
422
-	size_t header_len = ( sizeof ( *header ) + ncm->padding );
514
+	size_t header_len = ( sizeof ( *header ) + ncm->out.padding );
423
 	int rc;
515
 	int rc;
424
 
516
 
425
 	/* Profile transmissions */
517
 	/* Profile transmissions */
433
 	/* Populate header */
525
 	/* Populate header */
434
 	header->nth.magic = cpu_to_le32 ( NCM_TRANSFER_HEADER_MAGIC );
526
 	header->nth.magic = cpu_to_le32 ( NCM_TRANSFER_HEADER_MAGIC );
435
 	header->nth.header_len = cpu_to_le16 ( sizeof ( header->nth ) );
527
 	header->nth.header_len = cpu_to_le16 ( sizeof ( header->nth ) );
436
-	header->nth.sequence = cpu_to_le16 ( ncm->sequence );
528
+	header->nth.sequence = cpu_to_le16 ( ncm->out.sequence );
437
 	header->nth.len = cpu_to_le16 ( iob_len ( iobuf ) );
529
 	header->nth.len = cpu_to_le16 ( iob_len ( iobuf ) );
438
 	header->nth.offset =
530
 	header->nth.offset =
439
 		cpu_to_le16 ( offsetof ( typeof ( *header ), ndp ) );
531
 		cpu_to_le16 ( offsetof ( typeof ( *header ), ndp ) );
446
 	memset ( &header->desc[1], 0, sizeof ( header->desc[1] ) );
538
 	memset ( &header->desc[1], 0, sizeof ( header->desc[1] ) );
447
 
539
 
448
 	/* Enqueue I/O buffer */
540
 	/* Enqueue I/O buffer */
449
-	if ( ( rc = usb_stream ( &ncm->out, iobuf ) ) != 0 )
541
+	if ( ( rc = usb_stream ( &ncm->out.ep, iobuf ) ) != 0 )
450
 		return rc;
542
 		return rc;
451
 
543
 
452
 	/* Increment sequence number */
544
 	/* Increment sequence number */
453
-	ncm->sequence++;
545
+	ncm->out.sequence++;
454
 
546
 
455
 	profile_stop ( &ncm_out_profiler );
547
 	profile_stop ( &ncm_out_profiler );
456
 	return 0;
548
 	return 0;
465
  */
557
  */
466
 static void ncm_out_complete ( struct usb_endpoint *ep, struct io_buffer *iobuf,
558
 static void ncm_out_complete ( struct usb_endpoint *ep, struct io_buffer *iobuf,
467
 			       int rc ) {
559
 			       int rc ) {
468
-	struct ncm_device *ncm = container_of ( ep, struct ncm_device, out );
560
+	struct ncm_device *ncm = container_of ( ep, struct ncm_device, out.ep );
469
 	struct net_device *netdev = ncm->netdev;
561
 	struct net_device *netdev = ncm->netdev;
470
 
562
 
471
 	/* Report TX completion */
563
 	/* Report TX completion */
488
 	struct ncm_set_ntb_input_size size;
580
 	struct ncm_set_ntb_input_size size;
489
 	int rc;
581
 	int rc;
490
 
582
 
583
+	/* Allocate I/O buffers */
584
+	if ( ( rc = ncm_in_alloc ( ncm ) ) != 0 )
585
+		goto err_alloc;
586
+
491
 	/* Set maximum input size */
587
 	/* Set maximum input size */
492
 	memset ( &size, 0, sizeof ( size ) );
588
 	memset ( &size, 0, sizeof ( size ) );
493
-	size.mtu = cpu_to_le32 ( NCM_NTB_INPUT_SIZE );
589
+	size.mtu = cpu_to_le32 ( ncm->in.mtu );
494
 	if ( ( rc = usb_control ( usb, NCM_SET_NTB_INPUT_SIZE, 0, ncm->comms,
590
 	if ( ( rc = usb_control ( usb, NCM_SET_NTB_INPUT_SIZE, 0, ncm->comms,
495
 				  &size, sizeof ( size ) ) ) != 0 ) {
591
 				  &size, sizeof ( size ) ) ) != 0 ) {
496
-		DBGC ( ncm, "NCM %p could not set input size: %s\n",
497
-		       ncm, strerror ( rc ) );
592
+		DBGC ( ncm, "NCM %p could not set input size to %zd: %s\n",
593
+		       ncm, ncm->in.mtu, strerror ( rc ) );
498
 		goto err_set_ntb_input_size;
594
 		goto err_set_ntb_input_size;
499
 	}
595
 	}
500
 
596
 
507
 	}
603
 	}
508
 
604
 
509
 	/* Open bulk IN endpoint */
605
 	/* Open bulk IN endpoint */
510
-	if ( ( rc = usb_endpoint_open ( &ncm->in ) ) != 0 ) {
606
+	if ( ( rc = usb_endpoint_open ( &ncm->in.ep ) ) != 0 ) {
511
 		DBGC ( ncm, "NCM %p could not open bulk IN: %s\n",
607
 		DBGC ( ncm, "NCM %p could not open bulk IN: %s\n",
512
 		       ncm, strerror ( rc ) );
608
 		       ncm, strerror ( rc ) );
513
 		goto err_open_in;
609
 		goto err_open_in;
514
 	}
610
 	}
515
 
611
 
516
 	/* Open bulk OUT endpoint */
612
 	/* Open bulk OUT endpoint */
517
-	if ( ( rc = usb_endpoint_open ( &ncm->out ) ) != 0 ) {
613
+	if ( ( rc = usb_endpoint_open ( &ncm->out.ep ) ) != 0 ) {
518
 		DBGC ( ncm, "NCM %p could not open bulk OUT: %s\n",
614
 		DBGC ( ncm, "NCM %p could not open bulk OUT: %s\n",
519
 		       ncm, strerror ( rc ) );
615
 		       ncm, strerror ( rc ) );
520
 		goto err_open_out;
616
 		goto err_open_out;
521
 	}
617
 	}
522
 
618
 
619
+	/* Reset transmit sequence number */
620
+	ncm->out.sequence = 0;
621
+
523
 	return 0;
622
 	return 0;
524
 
623
 
525
-	usb_endpoint_close ( &ncm->out );
624
+	usb_endpoint_close ( &ncm->out.ep );
526
  err_open_out:
625
  err_open_out:
527
-	usb_endpoint_close ( &ncm->in );
626
+	usb_endpoint_close ( &ncm->in.ep );
528
  err_open_in:
627
  err_open_in:
529
 	usb_set_interface ( usb, ncm->data, 0 );
628
 	usb_set_interface ( usb, ncm->data, 0 );
530
  err_set_interface:
629
  err_set_interface:
531
  err_set_ntb_input_size:
630
  err_set_ntb_input_size:
631
+	ncm_rx_free ( ncm, &ncm->in );
632
+ err_alloc:
532
 	return rc;
633
 	return rc;
533
 }
634
 }
534
 
635
 
541
 	struct usb_device *usb = ncm->usb;
642
 	struct usb_device *usb = ncm->usb;
542
 
643
 
543
 	/* Close endpoints */
644
 	/* Close endpoints */
544
-	usb_endpoint_close ( &ncm->out );
545
-	usb_endpoint_close ( &ncm->in );
645
+	usb_endpoint_close ( &ncm->out.ep );
646
+	usb_endpoint_close ( &ncm->in.ep );
546
 
647
 
547
 	/* Reset data interface */
648
 	/* Reset data interface */
548
 	usb_set_interface ( usb, ncm->data, 0 );
649
 	usb_set_interface ( usb, ncm->data, 0 );
650
+
651
+	/* Free I/O buffers */
652
+	ncm_rx_free ( ncm, &ncm->in );
549
 }
653
 }
550
 
654
 
551
 /******************************************************************************
655
 /******************************************************************************
566
 	int rc;
670
 	int rc;
567
 
671
 
568
 	/* Reset sequence number */
672
 	/* Reset sequence number */
569
-	ncm->sequence = 0;
673
+	ncm->out.sequence = 0;
570
 
674
 
571
 	/* Open communications interface */
675
 	/* Open communications interface */
572
 	if ( ( rc = ncm_comms_open ( ncm ) ) != 0 )
676
 	if ( ( rc = ncm_comms_open ( ncm ) ) != 0 )
573
 		goto err_comms_open;
677
 		goto err_comms_open;
574
 
678
 
575
 	/* Refill interrupt ring */
679
 	/* Refill interrupt ring */
576
-	ncm_intr_refill ( ncm );
680
+	if ( ( rc = ncm_rx_refill ( ncm, &ncm->intr ) ) != 0 )
681
+		goto err_intr_refill;
577
 
682
 
578
 	/* Open data interface */
683
 	/* Open data interface */
579
 	if ( ( rc = ncm_data_open ( ncm ) ) != 0 )
684
 	if ( ( rc = ncm_data_open ( ncm ) ) != 0 )
580
 		goto err_data_open;
685
 		goto err_data_open;
581
 
686
 
582
 	/* Refill bulk IN ring */
687
 	/* Refill bulk IN ring */
583
-	ncm_in_refill ( ncm );
688
+	if ( ( rc = ncm_rx_refill ( ncm, &ncm->in ) ) != 0 )
689
+		goto err_in_refill;
584
 
690
 
585
 	return 0;
691
 	return 0;
586
 
692
 
693
+ err_in_refill:
587
 	ncm_data_close ( ncm );
694
 	ncm_data_close ( ncm );
588
  err_data_open:
695
  err_data_open:
696
+ err_intr_refill:
589
 	ncm_comms_close ( ncm );
697
 	ncm_comms_close ( ncm );
590
  err_comms_open:
698
  err_comms_open:
591
 	return rc;
699
 	return rc;
604
 
712
 
605
 	/* Close communications interface */
713
 	/* Close communications interface */
606
 	ncm_comms_close ( ncm );
714
 	ncm_comms_close ( ncm );
607
-
608
-	/* Sanity check */
609
-	assert ( ncm->fill == 0 );
610
 }
715
 }
611
 
716
 
612
 /**
717
 /**
635
  */
740
  */
636
 static void ncm_poll ( struct net_device *netdev ) {
741
 static void ncm_poll ( struct net_device *netdev ) {
637
 	struct ncm_device *ncm = netdev->priv;
742
 	struct ncm_device *ncm = netdev->priv;
743
+	int rc;
638
 
744
 
639
 	/* Poll USB bus */
745
 	/* Poll USB bus */
640
 	usb_poll ( ncm->bus );
746
 	usb_poll ( ncm->bus );
641
 
747
 
642
 	/* Refill interrupt ring */
748
 	/* Refill interrupt ring */
643
-	ncm_intr_refill ( ncm );
749
+	if ( ( rc = ncm_rx_refill ( ncm, &ncm->intr ) ) != 0 )
750
+		netdev_rx_err ( netdev, NULL, rc );
644
 
751
 
645
 	/* Refill bulk IN ring */
752
 	/* Refill bulk IN ring */
646
-	ncm_in_refill ( ncm );
753
+	if ( ( rc = ncm_rx_refill ( ncm, &ncm->in ) ) != 0 )
754
+		netdev_rx_err ( netdev, NULL, rc );
647
 }
755
 }
648
 
756
 
649
 /** CDC-NCM network device operations */
757
 /** CDC-NCM network device operations */
692
 	ncm->usb = usb;
800
 	ncm->usb = usb;
693
 	ncm->bus = usb->port->hub->bus;
801
 	ncm->bus = usb->port->hub->bus;
694
 	ncm->netdev = netdev;
802
 	ncm->netdev = netdev;
695
-	usb_endpoint_init ( &ncm->intr, usb, &ncm_intr_operations );
696
-	usb_endpoint_init ( &ncm->in, usb, &ncm_in_operations );
697
-	usb_endpoint_init ( &ncm->out, usb, &ncm_out_operations );
698
-	INIT_LIST_HEAD ( &ncm->intrs );
803
+	usb_endpoint_init ( &ncm->intr.ep, usb, &ncm_intr_operations );
804
+	usb_endpoint_init ( &ncm->in.ep, usb, &ncm_in_operations );
805
+	usb_endpoint_init ( &ncm->out.ep, usb, &ncm_out_operations );
699
 	DBGC ( ncm, "NCM %p on %s\n", ncm, func->name );
806
 	DBGC ( ncm, "NCM %p on %s\n", ncm, func->name );
700
 
807
 
701
 	/* Identify interfaces */
808
 	/* Identify interfaces */
726
 	}
833
 	}
727
 
834
 
728
 	/* Describe interrupt endpoint */
835
 	/* Describe interrupt endpoint */
729
-	if ( ( rc = usb_endpoint_described ( &ncm->intr, config, comms,
836
+	if ( ( rc = usb_endpoint_described ( &ncm->intr.ep, config, comms,
730
 					     USB_INTERRUPT, 0 ) ) != 0 ) {
837
 					     USB_INTERRUPT, 0 ) ) != 0 ) {
731
 		DBGC ( ncm, "NCM %p could not describe interrupt endpoint: "
838
 		DBGC ( ncm, "NCM %p could not describe interrupt endpoint: "
732
 		       "%s\n", ncm, strerror ( rc ) );
839
 		       "%s\n", ncm, strerror ( rc ) );
734
 	}
841
 	}
735
 
842
 
736
 	/* Describe bulk IN endpoint */
843
 	/* Describe bulk IN endpoint */
737
-	if ( ( rc = usb_endpoint_described ( &ncm->in, config, data,
844
+	if ( ( rc = usb_endpoint_described ( &ncm->in.ep, config, data,
738
 					     USB_BULK_IN, 0 ) ) != 0 ) {
845
 					     USB_BULK_IN, 0 ) ) != 0 ) {
739
 		DBGC ( ncm, "NCM %p could not describe bulk IN endpoint: "
846
 		DBGC ( ncm, "NCM %p could not describe bulk IN endpoint: "
740
 		       "%s\n", ncm, strerror ( rc ) );
847
 		       "%s\n", ncm, strerror ( rc ) );
742
 	}
849
 	}
743
 
850
 
744
 	/* Describe bulk OUT endpoint */
851
 	/* Describe bulk OUT endpoint */
745
-	if ( ( rc = usb_endpoint_described ( &ncm->out, config, data,
852
+	if ( ( rc = usb_endpoint_described ( &ncm->out.ep, config, data,
746
 					     USB_BULK_OUT, 0 ) ) != 0 ) {
853
 					     USB_BULK_OUT, 0 ) ) != 0 ) {
747
 		DBGC ( ncm, "NCM %p could not describe bulk OUT endpoint: "
854
 		DBGC ( ncm, "NCM %p could not describe bulk OUT endpoint: "
748
 		       "%s\n", ncm, strerror ( rc ) );
855
 		       "%s\n", ncm, strerror ( rc ) );
772
 		goto err_ntb_parameters;
879
 		goto err_ntb_parameters;
773
 	}
880
 	}
774
 
881
 
882
+	/* Get maximum supported input size */
883
+	ncm->mtu = le32_to_cpu ( params.in.mtu );
884
+	DBGC2 ( ncm, "NCM %p maximum IN size is %zd bytes\n", ncm, ncm->mtu );
885
+
775
 	/* Calculate transmit padding */
886
 	/* Calculate transmit padding */
776
-	ncm->padding = ( ( le16_to_cpu ( params.out.remainder ) -
777
-			   sizeof ( struct ncm_ntb_header ) - ETH_HLEN ) &
778
-			 ( le16_to_cpu ( params.out.divisor ) - 1 ) );
887
+	ncm->out.padding = ( ( le16_to_cpu ( params.out.remainder ) -
888
+			       sizeof ( struct ncm_ntb_header ) - ETH_HLEN ) &
889
+			     ( le16_to_cpu ( params.out.divisor ) - 1 ) );
779
 	DBGC2 ( ncm, "NCM %p using %zd-byte transmit padding\n",
890
 	DBGC2 ( ncm, "NCM %p using %zd-byte transmit padding\n",
780
-		ncm, ncm->padding );
781
-	assert ( ( ( sizeof ( struct ncm_ntb_header ) + ncm->padding +
891
+		ncm, ncm->out.padding );
892
+	assert ( ( ( sizeof ( struct ncm_ntb_header ) + ncm->out.padding +
782
 		     ETH_HLEN ) % le16_to_cpu ( params.out.divisor ) ) ==
893
 		     ETH_HLEN ) % le16_to_cpu ( params.out.divisor ) ) ==
783
 		 le16_to_cpu ( params.out.remainder ) );
894
 		 le16_to_cpu ( params.out.remainder ) );
784
 
895
 

+ 50
- 25
src/drivers/net/ncm.h View File

74
 	uint32_t mtu;
74
 	uint32_t mtu;
75
 } __attribute__ (( packed ));
75
 } __attribute__ (( packed ));
76
 
76
 
77
-/** NTB input size
78
- *
79
- * This is a policy decision.  2048 is the minimum size which must be
80
- * supported according to the specification.
81
- */
82
-#define NCM_NTB_INPUT_SIZE 2048
77
+/** Minimum allowed NTB input size */
78
+#define NCM_MIN_NTB_INPUT_SIZE 2048
79
+
80
+/** Maximum allowed NTB input size (16-bit) */
81
+#define NCM_MAX_NTB_INPUT_SIZE 65536
83
 
82
 
84
 /** CDC-NCM transfer header (16-bit) */
83
 /** CDC-NCM transfer header (16-bit) */
85
 struct ncm_transfer_header {
84
 struct ncm_transfer_header {
140
 	struct ncm_datagram_descriptor desc[2];
139
 	struct ncm_datagram_descriptor desc[2];
141
 } __attribute__ (( packed ));
140
 } __attribute__ (( packed ));
142
 
141
 
142
+/** A CDC-NCM receive ring */
143
+struct ncm_rx_ring {
144
+	/** USB endpoint */
145
+	struct usb_endpoint ep;
146
+	/** I/O buffer size */
147
+	size_t mtu;
148
+	/** Recycled buffer list */
149
+	struct list_head list;
150
+};
151
+
152
+/** A CDC-NCM transmit ring */
153
+struct ncm_tx_ring {
154
+	/** USB endpoint */
155
+	struct usb_endpoint ep;
156
+	/** Transmitted packet sequence number */
157
+	uint16_t sequence;
158
+	/** Alignment padding required on transmitted packets */
159
+	size_t padding;
160
+};
161
+
143
 /** A CDC-NCM network device */
162
 /** A CDC-NCM network device */
144
 struct ncm_device {
163
 struct ncm_device {
145
 	/** USB device */
164
 	/** USB device */
154
 	/** Data interface */
173
 	/** Data interface */
155
 	unsigned int data;
174
 	unsigned int data;
156
 
175
 
157
-	/** Interrupt endpoint */
158
-	struct usb_endpoint intr;
159
-	/** Bulk IN endpoint */
160
-	struct usb_endpoint in;
161
-	/** Bulk OUT endpoint */
162
-	struct usb_endpoint out;
163
-
164
-	/** Recycled interrupt I/O buffers */
165
-	struct list_head intrs;
166
-	/** Current bulk IN ring fill level */
167
-	unsigned int fill;
168
-	/** Transmitted packet sequence number */
169
-	uint16_t sequence;
170
-	/** Alignment padding required on transmitted packets */
171
-	size_t padding;
176
+	/** Maximum supported NTB input size */
177
+	size_t mtu;
178
+
179
+	/** Interrupt ring */
180
+	struct ncm_rx_ring intr;
181
+	/** Bulk IN ring */
182
+	struct ncm_rx_ring in;
183
+	/** Bulk OUT ring */
184
+	struct ncm_tx_ring out;
172
 };
185
 };
173
 
186
 
174
-/** Bulk IN ring fill level
187
+/** Bulk IN ring minimum buffer count
188
+ *
189
+ * This is a policy decision.
190
+ */
191
+#define NCM_IN_MIN_COUNT 3
192
+
193
+/** Bulk IN ring minimum total buffer size
194
+ *
195
+ * This is a policy decision.
196
+ */
197
+#define NCM_IN_MIN_SIZE 16384
198
+
199
+/** Bulk IN ring maximum total buffer size
175
  *
200
  *
176
  * This is a policy decision.
201
  * This is a policy decision.
177
  */
202
  */
178
-#define NCM_IN_FILL 16
203
+#define NCM_IN_MAX_SIZE 131072
179
 
204
 
180
-/** Interrupt ring fill level
205
+/** Interrupt ring buffer count
181
  *
206
  *
182
  * This is a policy decision.
207
  * This is a policy decision.
183
  */
208
  */
184
-#define NCM_INTR_FILL 2
209
+#define NCM_INTR_COUNT 2
185
 
210
 
186
 #endif /* _NCM_H */
211
 #endif /* _NCM_H */

Loading…
Cancel
Save