net: e1000 receive fixes?
This commit is contained in:
parent
6510dd73bd
commit
fd10920585
|
@ -80,6 +80,7 @@
|
||||||
/* what's 5 (0x20)? */
|
/* what's 5 (0x20)? */
|
||||||
#define ICR_RXO (1 << 6) /* Receive overrun */
|
#define ICR_RXO (1 << 6) /* Receive overrun */
|
||||||
#define ICR_RXT0 (1 << 7) /* Receive timer interrupt? */
|
#define ICR_RXT0 (1 << 7) /* Receive timer interrupt? */
|
||||||
|
#define ICR_ACK (1 << 17)
|
||||||
|
|
||||||
struct e1000_rx_desc {
|
struct e1000_rx_desc {
|
||||||
volatile uint64_t addr;
|
volatile uint64_t addr;
|
||||||
|
|
|
@ -693,7 +693,12 @@ static long sock_tcp_send(sock_t * sock, const struct msghdr *msg, int flags) {
|
||||||
}
|
}
|
||||||
if (msg->msg_iovlen == 0) return 0;
|
if (msg->msg_iovlen == 0) return 0;
|
||||||
|
|
||||||
size_t total_length = sizeof(struct ipv4_packet) + sizeof(struct tcp_header) + msg->msg_iov[0].iov_len;
|
size_t size_into = 0;
|
||||||
|
size_t size_remaining = msg->msg_iov[0].iov_len;
|
||||||
|
|
||||||
|
while (size_remaining) {
|
||||||
|
size_t size_to_send = size_remaining > 1024 ? 1024 : size_remaining;
|
||||||
|
size_t total_length = sizeof(struct ipv4_packet) + sizeof(struct tcp_header) + size_to_send;
|
||||||
|
|
||||||
fs_node_t * nic = net_if_any();
|
fs_node_t * nic = net_if_any();
|
||||||
|
|
||||||
|
@ -722,7 +727,7 @@ static long sock_tcp_send(sock_t * sock, const struct msghdr *msg, int flags) {
|
||||||
tcp_header->checksum = 0;
|
tcp_header->checksum = 0;
|
||||||
tcp_header->urgent = 0;
|
tcp_header->urgent = 0;
|
||||||
|
|
||||||
sock->priv32[0] += msg->msg_iov[0].iov_len;
|
sock->priv32[0] += size_to_send;
|
||||||
|
|
||||||
/* Calculate checksum */
|
/* Calculate checksum */
|
||||||
struct tcp_check_header check_hd = {
|
struct tcp_check_header check_hd = {
|
||||||
|
@ -730,14 +735,19 @@ static long sock_tcp_send(sock_t * sock, const struct msghdr *msg, int flags) {
|
||||||
.destination = response->destination,
|
.destination = response->destination,
|
||||||
.zeros = 0,
|
.zeros = 0,
|
||||||
.protocol = IPV4_PROT_TCP,
|
.protocol = IPV4_PROT_TCP,
|
||||||
.tcp_len = htons(sizeof(struct tcp_header) + msg->msg_iov[0].iov_len),
|
.tcp_len = htons(sizeof(struct tcp_header) + size_to_send),
|
||||||
};
|
};
|
||||||
|
|
||||||
memcpy(tcp_header->payload, msg->msg_iov[0].iov_base, msg->msg_iov[0].iov_len);
|
memcpy(tcp_header->payload, (char*)msg->msg_iov[0].iov_base + size_into, size_to_send);
|
||||||
tcp_header->checksum = htons(calculate_tcp_checksum(&check_hd, tcp_header, tcp_header->payload, msg->msg_iov[0].iov_len));
|
tcp_header->checksum = htons(calculate_tcp_checksum(&check_hd, tcp_header, tcp_header->payload, size_to_send));
|
||||||
net_ipv4_send(response,nic);
|
net_ipv4_send(response,nic);
|
||||||
free(response);
|
free(response);
|
||||||
return msg->msg_iov[0].iov_len;
|
|
||||||
|
size_remaining -= size_to_send;
|
||||||
|
size_into += size_to_send;
|
||||||
|
}
|
||||||
|
|
||||||
|
return size_into;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t sock_tcp_write(fs_node_t *node, off_t offset, size_t size, uint8_t *buffer) {
|
ssize_t sock_tcp_write(fs_node_t *node, off_t offset, size_t size, uint8_t *buffer) {
|
||||||
|
|
|
@ -341,3 +341,35 @@ struct hostent * gethostbyname(const char * name) {
|
||||||
return &_hostent;
|
return &_hostent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int getnameinfo(const struct sockaddr *addr, socklen_t addrlen,
|
||||||
|
char *host, socklen_t hostlen,
|
||||||
|
char *serv, socklen_t servlen, int flags) {
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getaddrinfo(const char *node, const char *service,
|
||||||
|
const struct addrinfo *hints,
|
||||||
|
struct addrinfo **res) {
|
||||||
|
|
||||||
|
struct hostent * ent = gethostbyname(node);
|
||||||
|
if (!ent) return -EINVAL; /* EAI_FAIL */
|
||||||
|
|
||||||
|
*res = malloc(sizeof(struct addrinfo));
|
||||||
|
(*res)->ai_flags = 0;
|
||||||
|
(*res)->ai_family = AF_INET;
|
||||||
|
(*res)->ai_socktype = 0;
|
||||||
|
(*res)->ai_protocol = 0;
|
||||||
|
(*res)->ai_addrlen = sizeof(struct sockaddr_in);
|
||||||
|
struct sockaddr_in * addr = malloc(sizeof(struct sockaddr_in));
|
||||||
|
addr->sin_family = AF_INET;
|
||||||
|
memcpy(&addr->sin_addr.s_addr, ent->h_addr, ent->h_length);
|
||||||
|
(*res)->ai_addr = (struct sockaddr *)addr;
|
||||||
|
(*res)->ai_canonname = NULL;
|
||||||
|
(*res)->ai_next = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void freeaddrinfo(struct addrinfo *res) {
|
||||||
|
if (res->ai_addr) free(res->ai_addr);
|
||||||
|
free(res);
|
||||||
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
|
|
||||||
#define INTS ((1 << 2) | (1 << 6) | (1 << 7) | (1 << 1) | (1 << 0))
|
#define INTS (ICR_LSC | ICR_RXO | ICR_RXT0 | ICR_TXQE | ICR_TXDW | ICR_ACK | ICR_RXDMT0)
|
||||||
|
|
||||||
struct e1000_nic {
|
struct e1000_nic {
|
||||||
struct EthernetDevice eth;
|
struct EthernetDevice eth;
|
||||||
|
@ -175,10 +175,10 @@ static void e1000_alert_waiters(struct e1000_nic * nic) {
|
||||||
|
|
||||||
static void e1000_handle(struct e1000_nic * nic, uint32_t status) {
|
static void e1000_handle(struct e1000_nic * nic, uint32_t status) {
|
||||||
if (status & ICR_LSC) {
|
if (status & ICR_LSC) {
|
||||||
/* TODO: Change interface link status. */
|
|
||||||
nic->link_status= (read_command(nic, E1000_REG_STATUS) & (1 << 1));
|
nic->link_status= (read_command(nic, E1000_REG_STATUS) & (1 << 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
if (status & ICR_TXQE) {
|
if (status & ICR_TXQE) {
|
||||||
/* Transmit queue empty; nothing to do. */
|
/* Transmit queue empty; nothing to do. */
|
||||||
}
|
}
|
||||||
|
@ -187,15 +187,22 @@ static void e1000_handle(struct e1000_nic * nic, uint32_t status) {
|
||||||
/* transmit descriptor written */
|
/* transmit descriptor written */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status & (ICR_RXO | ICR_RXT0)) {
|
if (status & (ICR_RXO | ICR_RXT0 | ICR_ACK)) {
|
||||||
/* Packet received. */
|
/* Receive ack */
|
||||||
do {
|
}
|
||||||
nic->rx_index = read_command(nic, E1000_REG_RXDESCTAIL);
|
#endif
|
||||||
if (nic->rx_index == (int)read_command(nic, E1000_REG_RXDESCHEAD)) return;
|
|
||||||
nic->rx_index = (nic->rx_index + 1) % E1000_NUM_RX_DESC;
|
int current_tail = read_command(nic, E1000_REG_RXDESCTAIL);
|
||||||
if (nic->rx[nic->rx_index].status & 0x01) {
|
int did_something = 0;
|
||||||
uint8_t * pbuf = (uint8_t *)nic->rx_virt[nic->rx_index];
|
|
||||||
uint16_t plen = nic->rx[nic->rx_index].length;
|
int i = (current_tail + 1) % E1000_NUM_RX_DESC;
|
||||||
|
while (1) {
|
||||||
|
/* Don't let the head run out... */
|
||||||
|
int current_head = read_command(nic, E1000_REG_RXDESCHEAD);
|
||||||
|
if (i == current_head) break; /* Don't receive the head... */
|
||||||
|
if (nic->rx[i].status & 0x01) {
|
||||||
|
uint8_t * pbuf = (uint8_t *)nic->rx_virt[i];
|
||||||
|
uint16_t plen = nic->rx[i].length;
|
||||||
|
|
||||||
void * packet = malloc(8192);
|
void * packet = malloc(8192);
|
||||||
if (plen > 8192) {
|
if (plen > 8192) {
|
||||||
|
@ -203,15 +210,19 @@ static void e1000_handle(struct e1000_nic * nic, uint32_t status) {
|
||||||
}
|
}
|
||||||
memcpy(packet, pbuf, plen);
|
memcpy(packet, pbuf, plen);
|
||||||
|
|
||||||
nic->rx[nic->rx_index].status = 0;
|
nic->rx[i].status = 0;
|
||||||
|
|
||||||
enqueue_packet(nic, packet);
|
enqueue_packet(nic, packet);
|
||||||
|
|
||||||
write_command(nic, E1000_REG_RXDESCTAIL, nic->rx_index);
|
write_command(nic, E1000_REG_RXDESCTAIL, i);
|
||||||
|
did_something = 1;
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while (1);
|
i = (i + 1) % E1000_NUM_RX_DESC;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (did_something) {
|
||||||
wakeup_queue(nic->rx_wait);
|
wakeup_queue(nic->rx_wait);
|
||||||
e1000_alert_waiters(nic);
|
e1000_alert_waiters(nic);
|
||||||
}
|
}
|
||||||
|
@ -244,6 +255,15 @@ static void send_packet(struct e1000_nic * device, uint8_t* payload, size_t payl
|
||||||
spin_lock(device->tx_lock);
|
spin_lock(device->tx_lock);
|
||||||
device->tx_index = read_command(device, E1000_REG_TXDESCTAIL);
|
device->tx_index = read_command(device, E1000_REG_TXDESCTAIL);
|
||||||
|
|
||||||
|
while ((device->tx[device->tx_index].status & 1) != 1) {
|
||||||
|
if (device->tx[device->tx_index].length == 0) break;
|
||||||
|
printf("warning: tx overrun; yielding until descriptor is available; tx index %d: status = %x; length = %x\n",
|
||||||
|
device->tx_index,
|
||||||
|
device->tx[device->tx_index].status,
|
||||||
|
device->tx[device->tx_index].length);
|
||||||
|
switch_task(1);
|
||||||
|
}
|
||||||
|
|
||||||
memcpy(device->tx_virt[device->tx_index], payload, payload_size);
|
memcpy(device->tx_virt[device->tx_index], payload, payload_size);
|
||||||
device->tx[device->tx_index].length = payload_size;
|
device->tx[device->tx_index].length = payload_size;
|
||||||
device->tx[device->tx_index].cmd = CMD_EOP | CMD_IFCS | CMD_RS; //| CMD_RPS;
|
device->tx[device->tx_index].cmd = CMD_EOP | CMD_IFCS | CMD_RS; //| CMD_RPS;
|
||||||
|
|
Loading…
Reference in New Issue