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