Add packet (Rx) queueing

This commit is contained in:
Mark
2020-03-20 10:42:02 +02:00
parent 86eb7c9282
commit 8c6a8beeaf
+82 -3
View File
@@ -1,21 +1,100 @@
#include "arch/amd64/mm/phys.h"
#include "arch/amd64/cpu.h"
#include "sys/thread.h"
#include "sys/assert.h"
#include "sys/string.h"
#include "sys/sched.h"
#include "sys/panic.h"
#include "sys/debug.h"
#include "sys/spin.h"
// Takes up a single page
#define PACKET_DATA_MAX (4064)
struct packet {
size_t size;
struct packet *prev, *next;
void *source_if;
char data[PACKET_DATA_MAX];
};
static struct thread netd_thread = {0};
static spin_t g_rxq_lock = 0;
static struct packet *g_rxq_head, *g_rxq_tail;
static struct packet *packet_create(void);
static void packet_free(struct packet *p);
static void net_handle_packet(struct packet *p) {
kdebug("Packet:\n");
debug_dump(DEBUG_DEFAULT, p->data, p->size);
}
static void net_daemon(void) {
struct packet *p;
uintptr_t irq;
while (1) {
asm volatile ("sti; hlt");
if (!g_rxq_head) {
// qword writes are atomic (when storing new head)
// so I guess checking if ANYTHING is present
// before locking is a good idea to avoid unnecessary
// overhead
thread_sleep(thread_self, system_time + 10000000ULL, NULL);
continue;
}
spin_lock_irqsave(&g_rxq_lock, &irq);
_assert(g_rxq_head);
p = g_rxq_head;
g_rxq_head = g_rxq_head->next;
if (!g_rxq_head) {
g_rxq_tail = NULL;
} else {
g_rxq_head->prev = NULL;
}
spin_release_irqrestore(&g_rxq_lock, &irq);
net_handle_packet(p);
packet_free(p);
}
}
static struct packet *packet_create(void) {
struct packet *packet;
uintptr_t page = amd64_phys_alloc_page();
_assert(page != MM_NADDR);
packet = (struct packet *) MM_VIRTUALIZE(page);
return packet;
}
static void packet_free(struct packet *p) {
uintptr_t page = MM_PHYS(p);
amd64_phys_free(page);
}
int net_receive(/* TODO: replace with struct netdev * */ void *ctx, const void *data, size_t len) {
kdebug("%u bytes\n", len);
debug_dump(DEBUG_DEFAULT, data, len);
if (len > PACKET_DATA_MAX) {
kwarn("Dropping large packet (%u)\n", len);
}
struct packet *p = packet_create();
memcpy(p->data, data, len);
p->size = len;
p->source_if = ctx;
spin_lock(&g_rxq_lock);
p->next = NULL;
p->prev = g_rxq_tail;
if (g_rxq_tail) {
g_rxq_tail->next = p;
} else {
g_rxq_head = p;
}
g_rxq_tail = p;
spin_release(&g_rxq_lock);
return 0;
}