xref: /haiku/src/add-ons/kernel/drivers/network/ether/virtio/virtio_net.cpp (revision 4c8e85b316c35a9161f5a1c50ad70bc91c83a76f)
1 /*
2  * Copyright 2013, 2018, Jérôme Duval, jerome.duval@gmail.com.
3  * Copyright 2017, Philippe Houdoin, philippe.houdoin@gmail.com.
4  * Distributed under the terms of the MIT License.
5  */
6 
7 
8 #include <net/if_media.h>
9 #include <new>
10 
11 #include <ethernet.h>
12 #include <lock.h>
13 #include <util/DoublyLinkedList.h>
14 #include <virtio.h>
15 
16 #include "ether_driver.h"
17 #define ETHER_ADDR_LEN	ETHER_ADDRESS_LENGTH
18 #include "virtio_net.h"
19 
20 
21 #define VIRTIO_NET_DRIVER_MODULE_NAME "drivers/network/virtio_net/driver_v1"
22 #define VIRTIO_NET_DEVICE_MODULE_NAME "drivers/network/virtio_net/device_v1"
23 #define VIRTIO_NET_DEVICE_ID_GENERATOR	"virtio_net/device_id"
24 
25 #define BUFFER_SIZE	2048
26 #define MAX_FRAME_SIZE 1536
27 
28 
29 struct virtio_net_rx_hdr {
30 	struct virtio_net_hdr	hdr;
31 	uint8					pad[4];
32 } _PACKED;
33 
34 
35 struct virtio_net_tx_hdr {
36 	union {
37 		struct virtio_net_hdr			hdr;
38 		struct virtio_net_hdr_mrg_rxbuf mhdr;
39 	};
40 } _PACKED;
41 
42 
43 struct BufInfo : DoublyLinkedListLinkImpl<BufInfo> {
44 	char*					buffer;
45 	struct virtio_net_hdr*	hdr;
46 	physical_entry			entry;
47 	physical_entry			hdrEntry;
48 	uint32					rxUsedLength;
49 };
50 
51 
52 typedef DoublyLinkedList<BufInfo> BufInfoList;
53 
54 
55 typedef struct {
56 	device_node*			node;
57 	::virtio_device			virtio_device;
58 	virtio_device_interface*	virtio;
59 
60 	uint32 					features;
61 
62 	uint32					pairsCount;
63 
64 	::virtio_queue*			rxQueues;
65 	uint16*					rxSizes;
66 
67 	BufInfo**				rxBufInfos;
68 	sem_id					rxDone;
69 	area_id					rxArea;
70 	BufInfoList				rxFullList;
71 	mutex					rxLock;
72 
73 	::virtio_queue*			txQueues;
74 	uint16*					txSizes;
75 
76 	BufInfo**				txBufInfos;
77 	sem_id					txDone;
78 	area_id					txArea;
79 	BufInfoList				txFreeList;
80 	mutex					txLock;
81 
82 	::virtio_queue			ctrlQueue;
83 
84 	bool					nonblocking;
85 	bool					promiscuous;
86 	uint32					maxframesize;
87 	ether_address_t			macaddr;
88 
89 #define MAX_MULTI 128
90 	uint32					multiCount;
91 	ether_address_t			multi[MAX_MULTI];
92 
93 } virtio_net_driver_info;
94 
95 
96 typedef struct {
97 	virtio_net_driver_info*		info;
98 } virtio_net_handle;
99 
100 
101 #include <stdio.h>
102 #include <string.h>
103 #include <stdlib.h>
104 
105 #include <fs/devfs.h>
106 
107 
108 //#define TRACE_VIRTIO_NET
109 #ifdef TRACE_VIRTIO_NET
110 #	define TRACE(x...) dprintf("virtio_net: " x)
111 #else
112 #	define TRACE(x...) ;
113 #endif
114 #define ERROR(x...)			dprintf("\33[33mvirtio_net:\33[0m " x)
115 #define CALLED() 			TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
116 
117 
118 static device_manager_info* sDeviceManager;
119 
120 
121 static void virtio_net_rxDone(void* driverCookie, void* cookie);
122 static void virtio_net_txDone(void* driverCookie, void* cookie);
123 
124 
125 const char*
126 get_feature_name(uint32 feature)
127 {
128 	switch (feature) {
129 		case VIRTIO_NET_F_CSUM:
130 			return "host checksum";
131 		case VIRTIO_NET_F_GUEST_CSUM:
132 			return "guest checksum";
133 		case VIRTIO_NET_F_MTU:
134 			return "mtu";
135 		case VIRTIO_NET_F_MAC:
136 			return "macaddress";
137 		case VIRTIO_NET_F_GSO:
138 			return "host allgso";
139 		case VIRTIO_NET_F_GUEST_TSO4:
140 			return "guest tso4";
141 		case VIRTIO_NET_F_GUEST_TSO6:
142 			return "guest tso6";
143 		case VIRTIO_NET_F_GUEST_ECN:
144 			return "guest tso6+ecn";
145 		case VIRTIO_NET_F_GUEST_UFO:
146 			return "guest ufo";
147 		case VIRTIO_NET_F_HOST_TSO4:
148 			return "host tso4";
149 		case VIRTIO_NET_F_HOST_TSO6:
150 			return "host tso6";
151 		case VIRTIO_NET_F_HOST_ECN:
152 			return "host tso6+ecn";
153 		case VIRTIO_NET_F_HOST_UFO:
154 			return "host UFO";
155 		case VIRTIO_NET_F_MRG_RXBUF:
156 			return "host mergerxbuffers";
157 		case VIRTIO_NET_F_STATUS:
158 			return "status";
159 		case VIRTIO_NET_F_CTRL_VQ:
160 			return "control vq";
161 		case VIRTIO_NET_F_CTRL_RX:
162 			return "rx mode";
163 		case VIRTIO_NET_F_CTRL_VLAN:
164 			return "vlan filter";
165 		case VIRTIO_NET_F_CTRL_RX_EXTRA:
166 			return "rx mode extra";
167 		case VIRTIO_NET_F_GUEST_ANNOUNCE:
168 			return "guest announce";
169 		case VIRTIO_NET_F_MQ:
170 			return "multiqueue";
171 		case VIRTIO_NET_F_CTRL_MAC_ADDR:
172 			return "set macaddress";
173 	}
174 	return NULL;
175 }
176 
177 
178 static status_t
179 virtio_net_drain_queues(virtio_net_driver_info* info)
180 {
181 	BufInfo* buf = NULL;
182 	while (info->virtio->queue_dequeue(info->txQueues[0], (void**)&buf, NULL))
183 		info->txFreeList.Add(buf);
184 
185 	while (info->virtio->queue_dequeue(info->rxQueues[0], NULL, NULL))
186 		;
187 
188 	while (info->rxFullList.RemoveHead() != NULL)
189 		;
190 
191 	return B_OK;
192 }
193 
194 
195 static status_t
196 virtio_net_rx_enqueue_buf(virtio_net_driver_info* info, BufInfo* buf)
197 {
198 	physical_entry entries[2];
199 	entries[0] = buf->hdrEntry;
200 	entries[1] = buf->entry;
201 
202 	memset(buf->hdr, 0, sizeof(struct virtio_net_hdr));
203 
204 	// queue the rx buffer
205 	status_t status = info->virtio->queue_request_v(info->rxQueues[0],
206 		entries, 0, 2, buf);
207 	if (status != B_OK) {
208 		ERROR("rx queueing on queue %d failed (%s)\n", 0, strerror(status));
209 		return status;
210 	}
211 
212 	return B_OK;
213 }
214 
215 
216 static status_t
217 virtio_net_ctrl_exec_cmd(virtio_net_driver_info* info, int cmd, int value)
218 {
219 	struct {
220 		struct virtio_net_ctrl_hdr hdr;
221 		uint8 pad1;
222 		uint8 onoff;
223 		uint8 pad2;
224 		uint8 ack;
225 	} s __attribute__((aligned(2)));
226 
227 	s.hdr.net_class = VIRTIO_NET_CTRL_RX;
228 	s.hdr.cmd = cmd;
229 	s.onoff = value == 0;
230 	s.ack = VIRTIO_NET_ERR;
231 
232 	physical_entry entries[3];
233 	status_t status = get_memory_map(&s.hdr, sizeof(s.hdr), &entries[0], 1);
234 	if (status != B_OK)
235 		return status;
236 	status = get_memory_map(&s.onoff, sizeof(s.onoff), &entries[1], 1);
237 	if (status != B_OK)
238 		return status;
239 	status = get_memory_map(&s.ack, sizeof(s.ack), &entries[2], 1);
240 	if (status != B_OK)
241 		return status;
242 
243 	if (!info->virtio->queue_is_empty(info->ctrlQueue))
244 		return B_ERROR;
245 
246 	status = info->virtio->queue_request_v(info->ctrlQueue, entries, 2, 1,
247 		NULL);
248 	if (status != B_OK)
249 		return status;
250 
251 	while (!info->virtio->queue_dequeue(info->ctrlQueue, NULL, NULL))
252 		spin(10);
253 
254 	return s.ack == VIRTIO_NET_OK ? B_OK : B_IO_ERROR;
255 }
256 
257 
258 static status_t
259 virtio_net_set_promisc(virtio_net_driver_info* info, int value)
260 {
261 	return virtio_net_ctrl_exec_cmd(info, VIRTIO_NET_CTRL_RX_PROMISC, value);
262 }
263 
264 
265 static int
266 vtnet_set_allmulti(virtio_net_driver_info* info, int value)
267 {
268 	return virtio_net_ctrl_exec_cmd(info, VIRTIO_NET_CTRL_RX_ALLMULTI, value);
269 }
270 
271 
272 #define ROUND_TO_PAGE_SIZE(x) (((x) + (B_PAGE_SIZE) - 1) & ~((B_PAGE_SIZE) - 1))
273 
274 
275 //	#pragma mark - device module API
276 
277 
278 static status_t
279 virtio_net_init_device(void* _info, void** _cookie)
280 {
281 	CALLED();
282 	virtio_net_driver_info* info = (virtio_net_driver_info*)_info;
283 
284 	device_node* parent = sDeviceManager->get_parent_node(info->node);
285 	sDeviceManager->get_driver(parent, (driver_module_info**)&info->virtio,
286 		(void**)&info->virtio_device);
287 	sDeviceManager->put_node(parent);
288 
289 	info->virtio->negotiate_features(info->virtio_device,
290 		VIRTIO_NET_F_STATUS | VIRTIO_NET_F_MAC | VIRTIO_NET_F_MTU
291 		| VIRTIO_NET_F_CTRL_VQ | VIRTIO_NET_F_CTRL_RX
292 		/* | VIRTIO_NET_F_MQ */,
293 		 &info->features, &get_feature_name);
294 
295 	if ((info->features & VIRTIO_NET_F_MQ) != 0
296 			&& (info->features & VIRTIO_NET_F_CTRL_VQ) != 0
297 			&& info->virtio->read_device_config(info->virtio_device,
298 				offsetof(struct virtio_net_config, max_virtqueue_pairs),
299 				&info->pairsCount, sizeof(info->pairsCount)) == B_OK) {
300 		system_info sysinfo;
301 		if (get_system_info(&sysinfo) == B_OK
302 			&& info->pairsCount > sysinfo.cpu_count) {
303 			info->pairsCount = sysinfo.cpu_count;
304 		}
305 	} else
306 		info->pairsCount = 1;
307 
308 	// TODO read config
309 
310 	// Setup queues
311 	uint32 queueCount = info->pairsCount * 2;
312 	if ((info->features & VIRTIO_NET_F_CTRL_VQ) != 0)
313 		queueCount++;
314 	::virtio_queue virtioQueues[queueCount];
315 	status_t status = info->virtio->alloc_queues(info->virtio_device, queueCount,
316 		virtioQueues);
317 	if (status != B_OK) {
318 		ERROR("queue allocation failed (%s)\n", strerror(status));
319 		return status;
320 	}
321 
322 	char* rxBuffer;
323 	char* txBuffer;
324 
325 	info->rxQueues = new(std::nothrow) virtio_queue[info->pairsCount];
326 	info->txQueues = new(std::nothrow) virtio_queue[info->pairsCount];
327 	info->rxSizes = new(std::nothrow) uint16[info->pairsCount];
328 	info->txSizes = new(std::nothrow) uint16[info->pairsCount];
329 	if (info->rxQueues == NULL || info->txQueues == NULL
330 		|| info->rxSizes == NULL || info->txSizes == NULL) {
331 		status = B_NO_MEMORY;
332 		goto err1;
333 	}
334 	for (uint32 i = 0; i < info->pairsCount; i++) {
335 		info->rxQueues[i] = virtioQueues[i * 2];
336 		info->txQueues[i] = virtioQueues[i * 2 + 1];
337 		info->rxSizes[i] = info->virtio->queue_size(info->rxQueues[i]) / 2;
338 		info->txSizes[i] = info->virtio->queue_size(info->txQueues[i]) / 2;
339 	}
340 	if ((info->features & VIRTIO_NET_F_CTRL_VQ) != 0)
341 		info->ctrlQueue = virtioQueues[info->pairsCount * 2];
342 
343 	info->rxBufInfos = new(std::nothrow) BufInfo*[info->rxSizes[0]];
344 	info->txBufInfos = new(std::nothrow) BufInfo*[info->txSizes[0]];
345 	if (info->rxBufInfos == NULL || info->txBufInfos == NULL) {
346 		status = B_NO_MEMORY;
347 		goto err2;
348 	}
349 	memset(info->rxBufInfos, 0, sizeof(BufInfo*) * info->rxSizes[0]);
350 	memset(info->txBufInfos, 0, sizeof(BufInfo*) * info->txSizes[0]);
351 
352 	// create receive buffer area
353 	info->rxArea = create_area("virtionet rx buffer", (void**)&rxBuffer,
354 		B_ANY_KERNEL_BLOCK_ADDRESS, ROUND_TO_PAGE_SIZE(
355 			BUFFER_SIZE * info->rxSizes[0]),
356 		B_FULL_LOCK, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
357 	if (info->rxArea < B_OK) {
358 		status = info->rxArea;
359 		goto err3;
360 	}
361 
362 	// initialize receive buffer descriptors
363 	for (int i = 0; i < info->rxSizes[0]; i++) {
364 		BufInfo* buf = new(std::nothrow) BufInfo;
365 		if (buf == NULL) {
366 			status = B_NO_MEMORY;
367 			goto err4;
368 		}
369 
370 		info->rxBufInfos[i] = buf;
371 		buf->hdr = (struct virtio_net_hdr*)((addr_t)rxBuffer
372 			+ i * BUFFER_SIZE);
373 		buf->buffer = (char*)((addr_t)buf->hdr + sizeof(virtio_net_rx_hdr));
374 
375 		status = get_memory_map(buf->buffer,
376 			BUFFER_SIZE - sizeof(virtio_net_rx_hdr), &buf->entry, 1);
377 		if (status != B_OK)
378 			goto err4;
379 
380 		status = get_memory_map(buf->hdr, sizeof(struct virtio_net_hdr),
381 			&buf->hdrEntry, 1);
382 		if (status != B_OK)
383 			goto err4;
384 	}
385 
386 	// create transmit buffer area
387 	info->txArea = create_area("virtionet tx buffer", (void**)&txBuffer,
388 		B_ANY_KERNEL_BLOCK_ADDRESS, ROUND_TO_PAGE_SIZE(
389 			BUFFER_SIZE * info->txSizes[0]),
390 		B_FULL_LOCK, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
391 	if (info->txArea < B_OK) {
392 		status = info->txArea;
393 		goto err5;
394 	}
395 
396 	// initialize transmit buffer descriptors
397 	for (int i = 0; i < info->txSizes[0]; i++) {
398 		BufInfo* buf = new(std::nothrow) BufInfo;
399 		if (buf == NULL) {
400 			status = B_NO_MEMORY;
401 			goto err6;
402 		}
403 
404 		info->txBufInfos[i] = buf;
405 		buf->hdr = (struct virtio_net_hdr*)((addr_t)txBuffer
406 			+ i * BUFFER_SIZE);
407 		buf->buffer = (char*)((addr_t)buf->hdr + sizeof(virtio_net_tx_hdr));
408 
409 		status = get_memory_map(buf->buffer,
410 			BUFFER_SIZE - sizeof(virtio_net_tx_hdr), &buf->entry, 1);
411 		if (status != B_OK)
412 			goto err6;
413 
414 		status = get_memory_map(buf->hdr, sizeof(struct virtio_net_hdr),
415 			&buf->hdrEntry, 1);
416 		if (status != B_OK)
417 			goto err6;
418 
419 		info->txFreeList.Add(buf);
420 	}
421 
422 	mutex_init(&info->rxLock, "virtionet rx lock");
423 	mutex_init(&info->txLock, "virtionet tx lock");
424 
425 	// Setup interrupt
426 	status = info->virtio->setup_interrupt(info->virtio_device, NULL, info);
427 	if (status != B_OK) {
428 		ERROR("interrupt setup failed (%s)\n", strerror(status));
429 		goto err6;
430 	}
431 
432 	status = info->virtio->queue_setup_interrupt(info->rxQueues[0],
433 		virtio_net_rxDone, info);
434 	if (status != B_OK) {
435 		ERROR("queue interrupt setup failed (%s)\n", strerror(status));
436 		goto err6;
437 	}
438 
439 	status = info->virtio->queue_setup_interrupt(info->txQueues[0],
440 		virtio_net_txDone, info);
441 	if (status != B_OK) {
442 		ERROR("queue interrupt setup failed (%s)\n", strerror(status));
443 		goto err6;
444 	}
445 
446 	if ((info->features & VIRTIO_NET_F_CTRL_VQ) != 0) {
447 		status = info->virtio->queue_setup_interrupt(info->ctrlQueue,
448 			NULL, info);
449 		if (status != B_OK) {
450 			ERROR("queue interrupt setup failed (%s)\n", strerror(status));
451 			goto err6;
452 		}
453 	}
454 
455 	*_cookie = info;
456 	return B_OK;
457 
458 err6:
459 	for (int i = 0; i < info->txSizes[0]; i++)
460 		delete info->txBufInfos[i];
461 err5:
462 	delete_area(info->txArea);
463 err4:
464 	for (int i = 0; i < info->rxSizes[0]; i++)
465 		delete info->rxBufInfos[i];
466 err3:
467 	delete_area(info->rxArea);
468 err2:
469 	delete[] info->rxBufInfos;
470 	delete[] info->txBufInfos;
471 err1:
472 	delete[] info->rxQueues;
473 	delete[] info->txQueues;
474 	delete[] info->rxSizes;
475 	delete[] info->txSizes;
476 	return status;
477 }
478 
479 
480 static void
481 virtio_net_uninit_device(void* _cookie)
482 {
483 	CALLED();
484 	virtio_net_driver_info* info = (virtio_net_driver_info*)_cookie;
485 
486 	info->virtio->free_interrupts(info->virtio_device);
487 
488 	mutex_destroy(&info->rxLock);
489 	mutex_destroy(&info->txLock);
490 
491 	while (true) {
492 		BufInfo* buf = info->txFreeList.RemoveHead();
493 		if (buf == NULL)
494 			break;
495 	}
496 
497 	for (int i = 0; i < info->rxSizes[0]; i++) {
498 		delete info->rxBufInfos[i];
499 	}
500 	for (int i = 0; i < info->txSizes[0]; i++) {
501 		delete info->txBufInfos[i];
502 	}
503 	delete_area(info->rxArea);
504 	delete_area(info->txArea);
505 	delete[] info->rxBufInfos;
506 	delete[] info->txBufInfos;
507 	delete[] info->rxSizes;
508 	delete[] info->txSizes;
509 	delete[] info->rxQueues;
510 	delete[] info->txQueues;
511 
512 	info->virtio->free_queues(info->virtio_device);
513 }
514 
515 
516 static status_t
517 virtio_net_open(void* _info, const char* path, int openMode, void** _cookie)
518 {
519 	CALLED();
520 	virtio_net_driver_info* info = (virtio_net_driver_info*)_info;
521 
522 	virtio_net_handle* handle = (virtio_net_handle*)malloc(
523 		sizeof(virtio_net_handle));
524 	if (handle == NULL)
525 		return B_NO_MEMORY;
526 
527 	info->nonblocking = (openMode & O_NONBLOCK) != 0;
528 	info->maxframesize = MAX_FRAME_SIZE;
529 	info->rxDone = create_sem(0, "virtio_net_rx");
530 	info->txDone = create_sem(1, "virtio_net_tx");
531 	if (info->rxDone < B_OK || info->txDone < B_OK)
532 		goto error;
533 	handle->info = info;
534 
535 	if ((info->features & VIRTIO_NET_F_MAC) != 0) {
536 		info->virtio->read_device_config(info->virtio_device,
537 			offsetof(struct virtio_net_config, mac),
538 			&info->macaddr, sizeof(info->macaddr));
539 	}
540 
541 	if ((info->features & VIRTIO_NET_F_MTU) != 0) {
542 		dprintf("mtu feature\n");
543 		uint16 mtu;
544 		info->virtio->read_device_config(info->virtio_device,
545 			offsetof(struct virtio_net_config, mtu),
546 			&mtu, sizeof(mtu));
547 		// check against minimum MTU
548 		if (mtu > 68)
549 			info->maxframesize = mtu;
550 		else
551 			info->virtio->clear_feature(info->virtio_device, VIRTIO_NET_F_MTU);
552 	} else {
553 		dprintf("no mtu feature\n");
554 	}
555 
556 	for (int i = 0; i < info->rxSizes[0]; i++)
557 		virtio_net_rx_enqueue_buf(info, info->rxBufInfos[i]);
558 
559 	*_cookie = handle;
560 	return B_OK;
561 
562 error:
563 	delete_sem(info->rxDone);
564 	delete_sem(info->txDone);
565 	info->rxDone = info->txDone = -1;
566 	free(handle);
567 	return B_ERROR;
568 }
569 
570 
571 static status_t
572 virtio_net_close(void* cookie)
573 {
574 	virtio_net_handle* handle = (virtio_net_handle*)cookie;
575 	CALLED();
576 
577 	virtio_net_driver_info* info = handle->info;
578 	delete_sem(info->rxDone);
579 	delete_sem(info->txDone);
580 	info->rxDone = info->txDone = -1;
581 
582 	return B_OK;
583 }
584 
585 
586 static status_t
587 virtio_net_free(void* cookie)
588 {
589 	CALLED();
590 	virtio_net_handle* handle = (virtio_net_handle*)cookie;
591 
592 	virtio_net_driver_info* info = handle->info;
593 	virtio_net_drain_queues(info);
594 	free(handle);
595 	return B_OK;
596 }
597 
598 
599 static void
600 virtio_net_rxDone(void* driverCookie, void* cookie)
601 {
602 	CALLED();
603 	virtio_net_driver_info* info = (virtio_net_driver_info*)cookie;
604 
605 	release_sem_etc(info->rxDone, 1, B_DO_NOT_RESCHEDULE);
606 }
607 
608 
609 static status_t
610 virtio_net_read(void* cookie, off_t pos, void* buffer, size_t* _length)
611 {
612 	CALLED();
613 	virtio_net_handle* handle = (virtio_net_handle*)cookie;
614 	virtio_net_driver_info* info = handle->info;
615 
616 	mutex_lock(&info->rxLock);
617 	while (info->rxFullList.Head() == NULL) {
618 		mutex_unlock(&info->rxLock);
619 
620 		if (info->nonblocking)
621 			return B_WOULD_BLOCK;
622 		TRACE("virtio_net_read: waiting\n");
623 		status_t status = acquire_sem(info->rxDone);
624 		if (status != B_OK) {
625 			ERROR("acquire_sem(rxDone) failed (%s)\n", strerror(status));
626 			return status;
627 		}
628 		int32 semCount = 0;
629 		get_sem_count(info->rxDone, &semCount);
630 		if (semCount > 0)
631 			acquire_sem_etc(info->rxDone, semCount, B_RELATIVE_TIMEOUT, 0);
632 
633 		mutex_lock(&info->rxLock);
634 		while (info->rxDone != -1) {
635 			uint32 usedLength = 0;
636 			BufInfo* buf = NULL;
637 			if (!info->virtio->queue_dequeue(info->rxQueues[0], (void**)&buf,
638 					&usedLength) || buf == NULL) {
639 				break;
640 			}
641 
642 			buf->rxUsedLength = usedLength;
643 			info->rxFullList.Add(buf);
644 		}
645 		TRACE("virtio_net_read: finished waiting\n");
646 	}
647 
648 	BufInfo* buf = info->rxFullList.RemoveHead();
649 	*_length = MIN(buf->rxUsedLength, *_length);
650 	memcpy(buffer, buf->buffer, *_length);
651 	virtio_net_rx_enqueue_buf(info, buf);
652 	mutex_unlock(&info->rxLock);
653 	return B_OK;
654 }
655 
656 
657 static void
658 virtio_net_txDone(void* driverCookie, void* cookie)
659 {
660 	CALLED();
661 	virtio_net_driver_info* info = (virtio_net_driver_info*)cookie;
662 
663 	release_sem_etc(info->txDone, 1, B_DO_NOT_RESCHEDULE);
664 }
665 
666 
667 static status_t
668 virtio_net_write(void* cookie, off_t pos, const void* buffer,
669 	size_t* _length)
670 {
671 	CALLED();
672 	virtio_net_handle* handle = (virtio_net_handle*)cookie;
673 	virtio_net_driver_info* info = handle->info;
674 
675 	mutex_lock(&info->txLock);
676 	while (info->txFreeList.Head() == NULL) {
677 		mutex_unlock(&info->txLock);
678 		if (info->nonblocking)
679 			return B_WOULD_BLOCK;
680 
681 		status_t status = acquire_sem(info->txDone);
682 		if (status != B_OK) {
683 			ERROR("acquire_sem(txDone) failed (%s)\n", strerror(status));
684 			return status;
685 		}
686 
687 		int32 semCount = 0;
688 		get_sem_count(info->txDone, &semCount);
689 		if (semCount > 0)
690 			acquire_sem_etc(info->txDone, semCount, B_RELATIVE_TIMEOUT, 0);
691 
692 		mutex_lock(&info->txLock);
693 		while (info->txDone != -1) {
694 			BufInfo* buf = NULL;
695 			if (!info->virtio->queue_dequeue(info->txQueues[0], (void**)&buf,
696 					NULL) || buf == NULL) {
697 				break;
698 			}
699 
700 			info->txFreeList.Add(buf);
701 		}
702 	}
703 	BufInfo* buf = info->txFreeList.RemoveHead();
704 
705 	TRACE("virtio_net_write: copying %lu\n", MIN(MAX_FRAME_SIZE, *_length));
706 	memcpy(buf->buffer, buffer, MIN(MAX_FRAME_SIZE, *_length));
707 	memset(buf->hdr, 0, sizeof(virtio_net_hdr));
708 
709 	physical_entry entries[2];
710 	entries[0] = buf->hdrEntry;
711 	entries[0].size = sizeof(virtio_net_hdr);
712 	entries[1] = buf->entry;
713 	entries[1].size = MIN(MAX_FRAME_SIZE, *_length);
714 
715 	// queue the virtio_net_hdr + buffer data
716 	status_t status = info->virtio->queue_request_v(info->txQueues[0],
717 		entries, 2, 0, buf);
718 	mutex_unlock(&info->txLock);
719 	if (status != B_OK) {
720 		ERROR("tx queueing on queue %d failed (%s)\n", 0, strerror(status));
721 		return status;
722 	}
723 
724 	return B_OK;
725 }
726 
727 
728 static status_t
729 virtio_net_ioctl(void* cookie, uint32 op, void* buffer, size_t length)
730 {
731 	// CALLED();
732 	virtio_net_handle* handle = (virtio_net_handle*)cookie;
733 	virtio_net_driver_info* info = handle->info;
734 
735 	// TRACE("ioctl(op = %lx)\n", op);
736 
737 	switch (op) {
738 		case ETHER_GETADDR:
739 			TRACE("ioctl: get macaddr\n");
740 			return user_memcpy(buffer, &info->macaddr, sizeof(info->macaddr));
741 
742 		case ETHER_INIT:
743 			TRACE("ioctl: init\n");
744 			return B_OK;
745 
746 		case ETHER_GETFRAMESIZE:
747 			TRACE("ioctl: get frame size\n");
748 			if (length != sizeof(info->maxframesize))
749 				return B_BAD_VALUE;
750 
751 			return user_memcpy(buffer, &info->maxframesize,
752 				sizeof(info->maxframesize));
753 
754 		case ETHER_SETPROMISC:
755 		{
756 			TRACE("ioctl: set promisc\n");
757 			int32 value;
758 			if (length != sizeof(value))
759 				return B_BAD_VALUE;
760 			if (user_memcpy(&value, buffer, sizeof(value)) != B_OK)
761 				return B_BAD_ADDRESS;
762 			if (info->promiscuous == value)
763 				return B_OK;
764 			info->promiscuous = value;
765 			return virtio_net_set_promisc(info, value);
766 		}
767 		case ETHER_NONBLOCK:
768 		{
769 			TRACE("ioctl: non blocking ? %s\n",
770 				info->nonblocking ? "yes" : "no");
771 			int32 value;
772 			if (length != sizeof(value))
773 				return B_BAD_VALUE;
774 			if (user_memcpy(&value, buffer, sizeof(value)) != B_OK)
775 				return B_BAD_ADDRESS;
776 			info->nonblocking = value == 0;
777 			return B_OK;
778 		}
779 		case ETHER_ADDMULTI:
780 		{
781 			uint32 i, multiCount = info->multiCount;
782 			TRACE("ioctl: add multicast\n");
783 
784 			if ((info->features & VIRTIO_NET_F_CTRL_RX) == 0)
785 				return B_NOT_SUPPORTED;
786 
787 			if (multiCount == MAX_MULTI)
788 				return B_ERROR;
789 
790 			for (i = 0; i < multiCount; i++) {
791 				if (memcmp(&info->multi[i], buffer,
792 					sizeof(info->multi[0])) == 0) {
793 					break;
794 				}
795 			}
796 
797 			if (i == multiCount) {
798 				memcpy(&info->multi[i], buffer, sizeof(info->multi[i]));
799 				info->multiCount++;
800 			}
801 			if (info->multiCount == 1) {
802 				TRACE("Enabling multicast\n");
803 				vtnet_set_allmulti(info, 1);
804 			}
805 
806 			return B_OK;
807 		}
808 		case ETHER_REMMULTI:
809 		{
810 			uint32 i, multiCount = info->multiCount;
811 			TRACE("ioctl: remove multicast\n");
812 
813 			if ((info->features & VIRTIO_NET_F_CTRL_RX) == 0)
814 				return B_NOT_SUPPORTED;
815 
816 			for (i = 0; i < multiCount; i++) {
817 				if (memcmp(&info->multi[i], buffer,
818 					sizeof(info->multi[0])) == 0) {
819 					break;
820 				}
821 			}
822 
823 			if (i != multiCount) {
824 				if (i < multiCount - 1) {
825 					memmove(&info->multi[i], &info->multi[i + 1],
826 						sizeof(info->multi[i]) * (multiCount - i - 1));
827 				}
828 				info->multiCount--;
829 				if (info->multiCount == 0) {
830 					TRACE("Disabling multicast\n");
831 					vtnet_set_allmulti(info, 0);
832 				}
833 				return B_OK;
834 			}
835 			return B_BAD_VALUE;
836 		}
837 		case ETHER_GET_LINK_STATE:
838 		{
839 			TRACE("ioctl: get link state\n");
840 			ether_link_state_t state;
841 			uint16 status = VIRTIO_NET_S_LINK_UP;
842 			if ((info->features & VIRTIO_NET_F_STATUS) != 0) {
843 				info->virtio->read_device_config(info->virtio_device,
844 					offsetof(struct virtio_net_config, status),
845 					&status, sizeof(status));
846 			}
847 			state.media = ((status & VIRTIO_NET_S_LINK_UP) != 0 ? IFM_ACTIVE : 0)
848 				| IFM_ETHER | IFM_FULL_DUPLEX | IFM_10G_T;
849 			state.speed = 10000000000ULL;
850 			state.quality = 1000;
851 
852 			return user_memcpy(buffer, &state, sizeof(ether_link_state_t));
853 		}
854 
855 		default:
856 			ERROR("ioctl: unknown message %" B_PRIx32 "\n", op);
857 			break;
858 	}
859 
860 
861 	return B_DEV_INVALID_IOCTL;
862 }
863 
864 
865 //	#pragma mark - driver module API
866 
867 
868 static float
869 virtio_net_supports_device(device_node* parent)
870 {
871 	CALLED();
872 	const char* bus;
873 	uint16 deviceType;
874 
875 	// make sure parent is really the Virtio bus manager
876 	if (sDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false))
877 		return -1;
878 
879 	if (strcmp(bus, "virtio"))
880 		return 0.0;
881 
882 	// check whether it's really a Direct Access Device
883 	if (sDeviceManager->get_attr_uint16(parent, VIRTIO_DEVICE_TYPE_ITEM,
884 			&deviceType, true) != B_OK || deviceType != VIRTIO_DEVICE_ID_NETWORK)
885 		return 0.0;
886 
887 	TRACE("Virtio network device found!\n");
888 
889 	return 0.6;
890 }
891 
892 
893 static status_t
894 virtio_net_register_device(device_node* node)
895 {
896 	CALLED();
897 
898 	device_attr attrs[] = {
899 		{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "Virtio Network"} },
900 		{ NULL }
901 	};
902 
903 	return sDeviceManager->register_node(node, VIRTIO_NET_DRIVER_MODULE_NAME,
904 		attrs, NULL, NULL);
905 }
906 
907 
908 static status_t
909 virtio_net_init_driver(device_node* node, void** cookie)
910 {
911 	CALLED();
912 
913 	virtio_net_driver_info* info = (virtio_net_driver_info*)malloc(
914 		sizeof(virtio_net_driver_info));
915 	if (info == NULL)
916 		return B_NO_MEMORY;
917 
918 	memset(info, 0, sizeof(*info));
919 
920 	info->node = node;
921 
922 	*cookie = info;
923 	return B_OK;
924 }
925 
926 
927 static void
928 virtio_net_uninit_driver(void* _cookie)
929 {
930 	CALLED();
931 	virtio_net_driver_info* info = (virtio_net_driver_info*)_cookie;
932 	free(info);
933 }
934 
935 
936 static status_t
937 virtio_net_register_child_devices(void* _cookie)
938 {
939 	CALLED();
940 	virtio_net_driver_info* info = (virtio_net_driver_info*)_cookie;
941 	status_t status;
942 
943 	int32 id = sDeviceManager->create_id(VIRTIO_NET_DEVICE_ID_GENERATOR);
944 	if (id < 0)
945 		return id;
946 
947 	char name[64];
948 	snprintf(name, sizeof(name), "net/virtio/%" B_PRId32,
949 		id);
950 
951 	status = sDeviceManager->publish_device(info->node, name,
952 		VIRTIO_NET_DEVICE_MODULE_NAME);
953 
954 	return status;
955 }
956 
957 
958 //	#pragma mark -
959 
960 
961 module_dependency module_dependencies[] = {
962 	{B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&sDeviceManager},
963 	{}
964 };
965 
966 struct device_module_info sVirtioNetDevice = {
967 	{
968 		VIRTIO_NET_DEVICE_MODULE_NAME,
969 		0,
970 		NULL
971 	},
972 
973 	virtio_net_init_device,
974 	virtio_net_uninit_device,
975 	NULL, // remove,
976 
977 	virtio_net_open,
978 	virtio_net_close,
979 	virtio_net_free,
980 	virtio_net_read,
981 	virtio_net_write,
982 	NULL,	// io
983 	virtio_net_ioctl,
984 
985 	NULL,	// select
986 	NULL,	// deselect
987 };
988 
989 struct driver_module_info sVirtioNetDriver = {
990 	{
991 		VIRTIO_NET_DRIVER_MODULE_NAME,
992 		0,
993 		NULL
994 	},
995 
996 	virtio_net_supports_device,
997 	virtio_net_register_device,
998 	virtio_net_init_driver,
999 	virtio_net_uninit_driver,
1000 	virtio_net_register_child_devices,
1001 	NULL,	// rescan
1002 	NULL,	// removed
1003 };
1004 
1005 module_info* modules[] = {
1006 	(module_info*)&sVirtioNetDriver,
1007 	(module_info*)&sVirtioNetDevice,
1008 	NULL
1009 };
1010