/* * Put user bytes into a free packet buffer, forward this packet to the TX * queue, and return OK. If there are no free packet buffers, return SUSPEND. */ static int virtio_net_send(struct netdriver_data * data, size_t len) { struct vumap_phys phys[2]; struct packet *p; if (STAILQ_EMPTY(&free_list)) return SUSPEND; p = STAILQ_FIRST(&free_list); STAILQ_REMOVE_HEAD(&free_list, next); if (len > MAX_PACK_SIZE) panic("%s: packet too large to send: %zu", name, len); netdriver_copyin(data, 0, p->vdata, len); phys[0].vp_addr = p->phdr; assert(!(phys[0].vp_addr & 1)); phys[0].vp_size = sizeof(struct virtio_net_hdr); phys[1].vp_addr = p->pdata; assert(!(phys[1].vp_addr & 1)); phys[1].vp_size = len; virtio_to_queue(net_dev, TX_Q, phys, 2, p); return OK; }
/*============================================================================* * lan8710a_send * *============================================================================*/ static int lan8710a_send(struct netdriver_data * data, size_t size) { lan8710a_t *e = &lan8710a_state; lan8710a_desc_t *p_tx_desc; u8_t *buf; /* setup descriptors */ p_tx_desc = &(e->tx_desc[e->tx_desc_idx]); /* * Check if descriptor is available for host and suspend if not. */ if (LAN8710A_DESC_FLAG_OWN & p_tx_desc->pkt_len_flags) return SUSPEND; /* Drop packets that exceed the size of our transmission buffer. */ if (size > LAN8710A_IOBUF_SIZE) { printf("%s: dropping large packet (%zu)\n", netdriver_name(), size); return OK; } /* virtual address of buffer */ buf = e->p_tx_buf + e->tx_desc_idx * LAN8710A_IOBUF_SIZE; netdriver_copyin(data, 0, buf, size); /* set descriptor length */ p_tx_desc->buffer_length_off = size; /* set flags */ p_tx_desc->pkt_len_flags = (LAN8710A_DESC_FLAG_OWN | LAN8710A_DESC_FLAG_SOP | LAN8710A_DESC_FLAG_EOP | TX_DESC_TO_PORT1 | TX_DESC_TO_PORT_EN); p_tx_desc->pkt_len_flags |= size; /* setup DMA transfer */ lan8710a_dma_config_tx(e->tx_desc_idx); e->tx_desc_idx++; if (LAN8710A_NUM_TX_DESC == e->tx_desc_idx) e->tx_desc_idx = 0; return OK; }
/* * Try to send a packet. */ static int e1000_send(struct netdriver_data * data, size_t size) { e1000_t *e; e1000_tx_desc_t *desc; unsigned int head, tail, next; char *ptr; e = &e1000_state; if (size > E1000_IOBUF_SIZE) panic("packet too large to send"); /* * The queue tail must not advance to the point that it is equal to the * queue head, since this condition indicates that the queue is empty. */ head = e1000_reg_read(e, E1000_REG_TDH); tail = e1000_reg_read(e, E1000_REG_TDT); next = (tail + 1) % e->tx_desc_count; if (next == head) return SUSPEND; /* The descriptor to use is the one pointed to by the current tail. */ desc = &e->tx_desc[tail]; /* Copy the packet from the caller. */ ptr = e->tx_buffer + tail * E1000_IOBUF_SIZE; netdriver_copyin(data, 0, ptr, size); /* Mark this descriptor ready. */ desc->status = 0; desc->length = size; desc->command = E1000_TX_CMD_EOP | E1000_TX_CMD_FCS | E1000_TX_CMD_RS; /* Increment tail. Start transmission. */ e1000_reg_write(e, E1000_REG_TDT, next); return OK; }