hrev51342 adds 1 changeset to branch 'master'
old head: ddf853297f7c41aef2cf8fdcae0abcc5553704d6
new head: 57b87ea9c386cf46e71e4cb83527fadf2fd64ee2
overview:
http://cgit.haiku-os.org/haiku/log/?qt=range&q=57b87ea9c386+%5Eddf853297f7c
----------------------------------------------------------------------------
57b87ea9c386: virtio_net: add rx & tx support
Rx see lots of errors, though, but at least DHCP works now and
the interface goes up.
[ Philippe Houdoin <philippe.houdoin@xxxxxxxxx> ]
----------------------------------------------------------------------------
Revision: hrev51342
Commit: 57b87ea9c386cf46e71e4cb83527fadf2fd64ee2
URL: http://cgit.haiku-os.org/haiku/commit/?id=57b87ea9c386
Author: Philippe Houdoin <philippe.houdoin@xxxxxxxxx>
Date: Wed Aug 2 20:26:53 2017 UTC
----------------------------------------------------------------------------
1 file changed, 125 insertions(+), 17 deletions(-)
.../kernel/drivers/network/virtio/virtio_net.cpp | 142 ++++++++++++++++---
----------------------------------------------------------------------------
diff --git a/src/add-ons/kernel/drivers/network/virtio/virtio_net.cpp
b/src/add-ons/kernel/drivers/network/virtio/virtio_net.cpp
index 0f8c4cc..06e37f0 100644
--- a/src/add-ons/kernel/drivers/network/virtio/virtio_net.cpp
+++ b/src/add-ons/kernel/drivers/network/virtio/virtio_net.cpp
@@ -14,12 +14,13 @@
#define ETHER_ADDR_LEN ETHER_ADDRESS_LENGTH
#include "virtio_net.h"
-#define MAX_FRAME_SIZE 1536
-
#define VIRTIO_NET_DRIVER_MODULE_NAME "drivers/network/virtio_net/driver_v1"
#define VIRTIO_NET_DEVICE_MODULE_NAME "drivers/network/virtio_net/device_v1"
#define VIRTIO_NET_DEVICE_ID_GENERATOR "virtio_net/device_id"
+#define BUFFER_SIZE 2048
+// #define MAX_FRAME_SIZE (BUFFER_SIZE - sizeof(virtio_net_hdr))
+#define MAX_FRAME_SIZE 1536
typedef struct {
device_node* node;
@@ -29,9 +30,21 @@ typedef struct {
uint32 features;
uint32 pairs_count;
- ::virtio_queue* receive_queues;
- ::virtio_queue* send_queues;
+ virtio_net_hdr hdr;
+ physical_entry hdr_entry;
+
+ ::virtio_queue* rx_queues;
+ uint8 rx_buffer[2048];
+ physical_entry rx_entry;
+ sem_id rx_done;
+
+ ::virtio_queue* tx_queues;
+ uint8 tx_buffer[2048];
+ physical_entry tx_entry;
+ sem_id tx_done;
+
+ ::virtio_queue ctrl_queue;
bool nonblocking;
uint32 maxframesize;
@@ -131,9 +144,12 @@ virtio_net_init_device(void* _info, void** _cookie)
sDeviceManager->put_node(parent);
info->virtio->negociate_features(info->virtio_device,
- 0 /* */, &info->features, &get_feature_name);
+ VIRTIO_NET_F_STATUS | VIRTIO_NET_F_MAC
+ /* VIRTIO_NET_F_CTRL_VQ | VIRTIO_NET_F_MQ */,
+ &info->features, &get_feature_name);
if ((info->features & VIRTIO_NET_F_MQ) != 0
+ && (info->features & VIRTIO_NET_F_CTRL_VQ) != 0
&& info->virtio->read_device_config(info->virtio_device,
offsetof(struct virtio_net_config,
max_virtqueue_pairs),
&info->pairs_count, sizeof(info->pairs_count))
== B_OK) {
@@ -147,6 +163,7 @@ virtio_net_init_device(void* _info, void** _cookie)
// TODO read config
+ // Setup queues
uint32 queueCount = info->pairs_count * 2;
if ((info->features & VIRTIO_NET_F_CTRL_VQ) != 0)
queueCount++;
@@ -158,16 +175,31 @@ virtio_net_init_device(void* _info, void** _cookie)
return status;
}
- info->receive_queues = new(std::nothrow)
virtio_queue[info->pairs_count];
- info->send_queues = new(std::nothrow) virtio_queue[info->pairs_count];
- if (info->receive_queues == NULL || info->send_queues == NULL)
+ info->rx_queues = new(std::nothrow) virtio_queue[info->pairs_count];
+ info->tx_queues = new(std::nothrow) virtio_queue[info->pairs_count];
+ if (info->rx_queues == NULL || info->tx_queues == NULL)
return B_NO_MEMORY;
for (uint32 i = 0; i < info->pairs_count; i++) {
- info->receive_queues[i] = virtioQueues[i * 2];
- info->send_queues[i] = virtioQueues[i * 2 + 1];
+ info->rx_queues[i] = virtioQueues[i * 2];
+ info->tx_queues[i] = virtioQueues[i * 2 + 1];
}
+ if ((info->features & VIRTIO_NET_F_CTRL_VQ) != 0)
+ info->ctrl_queue = virtioQueues[info->pairs_count * 2];
+
+ // Setup buffers
+ get_memory_map(&info->rx_buffer, sizeof(info->tx_buffer),
&info->rx_entry, 1);
+ get_memory_map(&info->tx_buffer, sizeof(info->tx_buffer),
&info->tx_entry, 1);
+ get_memory_map(&info->hdr, sizeof(info->hdr), &info->hdr_entry, 1);
- // TODO setup interrupts
+ // Setup interrupt
+ info->rx_done = create_sem(0, "virtio_net_rx");
+ info->tx_done = create_sem(0, "virtio_net_tx");
+
+ status = info->virtio->setup_interrupt(info->virtio_device, NULL, info);
+ if (status != B_OK) {
+ ERROR("interrupt setup failed (%s)\n", strerror(status));
+ return status;
+ }
*_cookie = info;
return B_OK;
@@ -179,6 +211,11 @@ virtio_net_uninit_device(void* _cookie)
{
CALLED();
virtio_net_driver_info* info = (virtio_net_driver_info*)_cookie;
+
+ delete_sem(info->rx_done);
+ delete_sem(info->tx_done);
+ delete[] info->rx_queues;
+ delete[] info->tx_queues;
}
@@ -229,13 +266,57 @@ virtio_net_free(void* cookie)
}
+static void
+virtio_net_rx_done(void* driverCookie, void* cookie)
+{
+ CALLED();
+ virtio_net_driver_info* info = (virtio_net_driver_info*)cookie;
+ release_sem_etc(info->rx_done, 1, B_DO_NOT_RESCHEDULE);
+}
+
+
static status_t
virtio_net_read(void* cookie, off_t pos, void* buffer, size_t* _length)
{
CALLED();
virtio_net_handle* handle = (virtio_net_handle*)cookie;
- // TODO implement
- return B_ERROR;
+ virtio_net_driver_info* info = handle->info;
+
+ // return B_ERROR;
+
+ physical_entry entries[2];
+ entries[0] = info->hdr_entry;
+ entries[1] = info->rx_entry;
+
+ memset(&info->hdr, 0, sizeof(info->hdr));
+
+ // queue the rx buffer
+ status_t status = info->virtio->queue_request_v(info->rx_queues[0],
+ entries, 0, 2, virtio_net_rx_done, info);
+ if (status != B_OK) {
+ ERROR("rx queueing on queue %d failed (%s)\n", 0,
strerror(status));
+ return status;
+ }
+
+ // wait for reception
+ status = acquire_sem_etc(info->rx_done, 1, B_RELATIVE_TIMEOUT, 10000);
+ if (status != B_OK) {
+ ERROR("acquire_sem(rx_done) failed (%s)\n", strerror(status));
+ return status;
+ }
+
+ *_length = MIN(MAX_FRAME_SIZE, *_length);
+ memcpy(buffer, &info->rx_buffer, *_length);
+ return B_OK;
+}
+
+
+static void
+virtio_net_tx_done(void* driverCookie, void* cookie)
+{
+ CALLED();
+ virtio_net_driver_info* info = (virtio_net_driver_info*)cookie;
+ release_sem_etc(info->tx_done, 1, B_DO_NOT_RESCHEDULE);
}
@@ -245,19 +326,46 @@ virtio_net_write(void* cookie, off_t pos, const void*
buffer,
{
CALLED();
virtio_net_handle* handle = (virtio_net_handle*)cookie;
- // TODO implement
- return B_ERROR;
+ virtio_net_driver_info* info = handle->info;
+
+ // legacy interface: one descriptor for all
+ // so we have no choice but to concat a virtio_net_hdr with buffer data
+ // together...
+
+ physical_entry entries[2];
+ entries[0] = info->hdr_entry;
+ entries[1] = info->tx_entry;
+
+ memset(&info->hdr, 0, sizeof(info->hdr));
+ memcpy(&info->tx_buffer, buffer, MIN(MAX_FRAME_SIZE, *_length));
+
+ // queue the virtio_net_hdr + buffer data
+ status_t status = info->virtio->queue_request_v(info->tx_queues[0],
+ entries, 2, 0, virtio_net_tx_done, info);
+ if (status != B_OK) {
+ ERROR("tx queueing on queue %d failed (%s)\n", 0,
strerror(status));
+ return status;
+ }
+
+ // wait for transmission done signal
+ status = acquire_sem_etc(info->tx_done, 1, B_RELATIVE_TIMEOUT, 10000);
+ if (status != B_OK) {
+ ERROR("acquire_sem(tx_done) failed (%s)\n", strerror(status));
+ return status;
+ }
+
+ return B_OK;
}
static status_t
virtio_net_ioctl(void* cookie, uint32 op, void* buffer, size_t length)
{
- CALLED();
+ // CALLED();
virtio_net_handle* handle = (virtio_net_handle*)cookie;
virtio_net_driver_info* info = handle->info;
- TRACE("ioctl(op = %lx)\n", op);
+ // TRACE("ioctl(op = %lx)\n", op);
switch (op) {
case ETHER_GETADDR: