Message ID | 20231219213255.604535-10-nabihestefan@google.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Implementation of NPI Mailbox and GMAC Networking Module | expand |
On Tue, 19 Dec 2023 at 21:33, Nabih Estefan <nabihestefan@google.com> wrote: > > From: Nabih Estefan Diaz <nabihestefan@google.com> > > - Implementation of Transmit function for packets > - Implementation for reading and writing from and to descriptors in > memory for Tx > > NOTE: This function implements the steps detailed in the datasheet for > transmitting messages from the GMAC. > > Signed-off-by: Nabih Estefan <nabihestefan@google.com> > Reviewed-by: Tyrone Ting <kfting@nuvoton.com> > --- > hw/net/npcm_gmac.c | 153 +++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 153 insertions(+) > > diff --git a/hw/net/npcm_gmac.c b/hw/net/npcm_gmac.c > index fe7b0421ef..69e61b2b67 100644 > --- a/hw/net/npcm_gmac.c > +++ b/hw/net/npcm_gmac.c > @@ -265,6 +265,7 @@ static int gmac_write_tx_desc(dma_addr_t addr, struct NPCMGMACTxDesc *desc) > } > return 0; > } > + > static int gmac_rx_transfer_frame_to_buffer(uint32_t rx_buf_len, > uint32_t *left_frame, > uint32_t rx_buf_addr, > @@ -487,6 +488,158 @@ static ssize_t gmac_receive(NetClientState *nc, const uint8_t *buf, size_t len) > return len; > } > > +<<<<<<< HEAD > +======= There are still patch conflict markers in this patch. This suggests you didn't build and test it before sending it out, which is generally a minimum standard we expect... > +static int gmac_tx_get_csum(uint32_t tdes1) > +{ > + uint32_t mask = TX_DESC_TDES1_CHKSM_INS_CTRL_MASK(tdes1); > + int csum = 0; > + > + if (likely(mask > 0)) { > + csum |= CSUM_IP; > + } > + if (likely(mask > 1)) { > + csum |= CSUM_TCP | CSUM_UDP; > + } > + > + return csum; > +} > + > +static void gmac_try_send_next_packet(NPCMGMACState *gmac) > +{ > + /* > + * Comments about steps refer to steps for > + * transmitting in page 384 of datasheet > + */ > + uint16_t tx_buffer_size = 2048; > + g_autofree uint8_t *tx_send_buffer = g_malloc(tx_buffer_size); > + uint32_t desc_addr; > + struct NPCMGMACTxDesc tx_desc; > + uint32_t tx_buf_addr, tx_buf_len; > + uint16_t length = 0; > + uint8_t *buf = tx_send_buffer; > + uint32_t prev_buf_size = 0; > + int csum = 0; > + > + /* steps 1&2 */ > + if (!gmac->regs[R_NPCM_DMA_HOST_TX_DESC]) { > + gmac->regs[R_NPCM_DMA_HOST_TX_DESC] = > + NPCM_DMA_HOST_TX_DESC_MASK(gmac->regs[R_NPCM_DMA_TX_BASE_ADDR]); > + } > + desc_addr = gmac->regs[R_NPCM_DMA_HOST_TX_DESC]; > + > + while (true) { > + gmac_dma_set_state(gmac, NPCM_DMA_STATUS_TX_PROCESS_STATE_SHIFT, > + NPCM_DMA_STATUS_TX_RUNNING_FETCHING_STATE); > + if (gmac_read_tx_desc(desc_addr, &tx_desc)) { > + qemu_log_mask(LOG_GUEST_ERROR, > + "TX Descriptor @ 0x%x can't be read\n", > + desc_addr); > + return; > + } > + /* step 3 */ > + > + trace_npcm_gmac_packet_desc_read(DEVICE(gmac)->canonical_path, > + desc_addr); > + trace_npcm_gmac_debug_desc_data(DEVICE(gmac)->canonical_path, &tx_desc, > + tx_desc.tdes0, tx_desc.tdes1, tx_desc.tdes2, tx_desc.tdes3); > + > + /* 1 = DMA Owned, 0 = Software Owned */ > + if (!(tx_desc.tdes0 & TX_DESC_TDES0_OWN)) { > + qemu_log_mask(LOG_GUEST_ERROR, > + "TX Descriptor @ 0x%x is owned by software\n", > + desc_addr); > + gmac->regs[R_NPCM_DMA_STATUS] |= NPCM_DMA_STATUS_TU; > + gmac_dma_set_state(gmac, NPCM_DMA_STATUS_TX_PROCESS_STATE_SHIFT, > + NPCM_DMA_STATUS_TX_SUSPENDED_STATE); > + gmac_update_irq(gmac); > + return; > + } > + > + gmac_dma_set_state(gmac, NPCM_DMA_STATUS_TX_PROCESS_STATE_SHIFT, > + NPCM_DMA_STATUS_TX_RUNNING_READ_STATE); > + /* Give the descriptor back regardless of what happens. */ > + tx_desc.tdes0 &= ~TX_DESC_TDES0_OWN; > + > + if (tx_desc.tdes1 & TX_DESC_TDES1_FIRST_SEG_MASK) { > + csum = gmac_tx_get_csum(tx_desc.tdes1); > + } > + > + /* step 4 */ > + tx_buf_addr = tx_desc.tdes2; > + gmac->regs[R_NPCM_DMA_CUR_TX_BUF_ADDR] = tx_buf_addr; > + tx_buf_len = TX_DESC_TDES1_BFFR1_SZ_MASK(tx_desc.tdes1); > + buf = &tx_send_buffer[prev_buf_size]; > + > + if ((prev_buf_size + tx_buf_len) > sizeof(buf)) { > + tx_buffer_size = prev_buf_size + tx_buf_len; > + tx_send_buffer = g_realloc(tx_send_buffer, tx_buffer_size); > + buf = &tx_send_buffer[prev_buf_size]; > + } > + > + /* step 5 */ > + if (dma_memory_read(&address_space_memory, tx_buf_addr, buf, > + tx_buf_len, MEMTXATTRS_UNSPECIFIED)) { > + qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to read packet @ 0x%x\n", > + __func__, tx_buf_addr); > + return; > + } > + length += tx_buf_len; > + prev_buf_size += tx_buf_len; > + > + /* If not chained we'll have a second buffer. */ > + if (!(tx_desc.tdes1 & TX_DESC_TDES1_SEC_ADDR_CHND_MASK)) { > + tx_buf_addr = tx_desc.tdes3; > + gmac->regs[R_NPCM_DMA_CUR_TX_BUF_ADDR] = tx_buf_addr; > + tx_buf_len = TX_DESC_TDES1_BFFR2_SZ_MASK(tx_desc.tdes1); > + buf = &tx_send_buffer[prev_buf_size]; > + > + if ((prev_buf_size + tx_buf_len) > sizeof(buf)) { > + tx_buffer_size = prev_buf_size + tx_buf_len; > + tx_send_buffer = g_realloc(tx_send_buffer, tx_buffer_size); > + buf = &tx_send_buffer[prev_buf_size]; > + } > + > + if (dma_memory_read(&address_space_memory, tx_buf_addr, buf, > + tx_buf_len, MEMTXATTRS_UNSPECIFIED)) { > + qemu_log_mask(LOG_GUEST_ERROR, > + "%s: Failed to read packet @ 0x%x\n", > + __func__, tx_buf_addr); > + return; > + } > + length += tx_buf_len; > + prev_buf_size += tx_buf_len; > + } > + if (tx_desc.tdes1 & TX_DESC_TDES1_LAST_SEG_MASK) { > + net_checksum_calculate(tx_send_buffer, length, csum); > + qemu_send_packet(qemu_get_queue(gmac->nic), tx_send_buffer, length); > + trace_npcm_gmac_packet_sent(DEVICE(gmac)->canonical_path, length); > + buf = tx_send_buffer; > + length = 0; > + } > + > + /* step 6 */ > + gmac_dma_set_state(gmac, NPCM_DMA_STATUS_TX_PROCESS_STATE_SHIFT, > + NPCM_DMA_STATUS_TX_RUNNING_CLOSING_STATE); > + gmac_write_tx_desc(desc_addr, &tx_desc); > + if (tx_desc.tdes1 & TX_DESC_TDES1_TX_END_RING_MASK) { > + desc_addr = gmac->regs[R_NPCM_DMA_TX_BASE_ADDR]; > + } else if (tx_desc.tdes1 & TX_DESC_TDES1_SEC_ADDR_CHND_MASK) { > + desc_addr = tx_desc.tdes3; > + } else { > + desc_addr += sizeof(tx_desc); > + } > + gmac->regs[R_NPCM_DMA_HOST_TX_DESC] = desc_addr; > + > + /* step 7 */ > + if (tx_desc.tdes1 & TX_DESC_TDES1_INTERR_COMP_MASK) { > + gmac->regs[R_NPCM_DMA_STATUS] |= NPCM_DMA_STATUS_TI; > + gmac_update_irq(gmac); > + } > + } > +} > + > +>>>>>>> 107e0d0181 (hw/net: GMAC Tx Implementation) > static void gmac_cleanup(NetClientState *nc) > { > /* Nothing to do yet. */ > -- > 2.43.0.472.g3155946c3a-goog -- PMM
diff --git a/hw/net/npcm_gmac.c b/hw/net/npcm_gmac.c index fe7b0421ef..69e61b2b67 100644 --- a/hw/net/npcm_gmac.c +++ b/hw/net/npcm_gmac.c @@ -265,6 +265,7 @@ static int gmac_write_tx_desc(dma_addr_t addr, struct NPCMGMACTxDesc *desc) } return 0; } + static int gmac_rx_transfer_frame_to_buffer(uint32_t rx_buf_len, uint32_t *left_frame, uint32_t rx_buf_addr, @@ -487,6 +488,158 @@ static ssize_t gmac_receive(NetClientState *nc, const uint8_t *buf, size_t len) return len; } +<<<<<<< HEAD +======= +static int gmac_tx_get_csum(uint32_t tdes1) +{ + uint32_t mask = TX_DESC_TDES1_CHKSM_INS_CTRL_MASK(tdes1); + int csum = 0; + + if (likely(mask > 0)) { + csum |= CSUM_IP; + } + if (likely(mask > 1)) { + csum |= CSUM_TCP | CSUM_UDP; + } + + return csum; +} + +static void gmac_try_send_next_packet(NPCMGMACState *gmac) +{ + /* + * Comments about steps refer to steps for + * transmitting in page 384 of datasheet + */ + uint16_t tx_buffer_size = 2048; + g_autofree uint8_t *tx_send_buffer = g_malloc(tx_buffer_size); + uint32_t desc_addr; + struct NPCMGMACTxDesc tx_desc; + uint32_t tx_buf_addr, tx_buf_len; + uint16_t length = 0; + uint8_t *buf = tx_send_buffer; + uint32_t prev_buf_size = 0; + int csum = 0; + + /* steps 1&2 */ + if (!gmac->regs[R_NPCM_DMA_HOST_TX_DESC]) { + gmac->regs[R_NPCM_DMA_HOST_TX_DESC] = + NPCM_DMA_HOST_TX_DESC_MASK(gmac->regs[R_NPCM_DMA_TX_BASE_ADDR]); + } + desc_addr = gmac->regs[R_NPCM_DMA_HOST_TX_DESC]; + + while (true) { + gmac_dma_set_state(gmac, NPCM_DMA_STATUS_TX_PROCESS_STATE_SHIFT, + NPCM_DMA_STATUS_TX_RUNNING_FETCHING_STATE); + if (gmac_read_tx_desc(desc_addr, &tx_desc)) { + qemu_log_mask(LOG_GUEST_ERROR, + "TX Descriptor @ 0x%x can't be read\n", + desc_addr); + return; + } + /* step 3 */ + + trace_npcm_gmac_packet_desc_read(DEVICE(gmac)->canonical_path, + desc_addr); + trace_npcm_gmac_debug_desc_data(DEVICE(gmac)->canonical_path, &tx_desc, + tx_desc.tdes0, tx_desc.tdes1, tx_desc.tdes2, tx_desc.tdes3); + + /* 1 = DMA Owned, 0 = Software Owned */ + if (!(tx_desc.tdes0 & TX_DESC_TDES0_OWN)) { + qemu_log_mask(LOG_GUEST_ERROR, + "TX Descriptor @ 0x%x is owned by software\n", + desc_addr); + gmac->regs[R_NPCM_DMA_STATUS] |= NPCM_DMA_STATUS_TU; + gmac_dma_set_state(gmac, NPCM_DMA_STATUS_TX_PROCESS_STATE_SHIFT, + NPCM_DMA_STATUS_TX_SUSPENDED_STATE); + gmac_update_irq(gmac); + return; + } + + gmac_dma_set_state(gmac, NPCM_DMA_STATUS_TX_PROCESS_STATE_SHIFT, + NPCM_DMA_STATUS_TX_RUNNING_READ_STATE); + /* Give the descriptor back regardless of what happens. */ + tx_desc.tdes0 &= ~TX_DESC_TDES0_OWN; + + if (tx_desc.tdes1 & TX_DESC_TDES1_FIRST_SEG_MASK) { + csum = gmac_tx_get_csum(tx_desc.tdes1); + } + + /* step 4 */ + tx_buf_addr = tx_desc.tdes2; + gmac->regs[R_NPCM_DMA_CUR_TX_BUF_ADDR] = tx_buf_addr; + tx_buf_len = TX_DESC_TDES1_BFFR1_SZ_MASK(tx_desc.tdes1); + buf = &tx_send_buffer[prev_buf_size]; + + if ((prev_buf_size + tx_buf_len) > sizeof(buf)) { + tx_buffer_size = prev_buf_size + tx_buf_len; + tx_send_buffer = g_realloc(tx_send_buffer, tx_buffer_size); + buf = &tx_send_buffer[prev_buf_size]; + } + + /* step 5 */ + if (dma_memory_read(&address_space_memory, tx_buf_addr, buf, + tx_buf_len, MEMTXATTRS_UNSPECIFIED)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to read packet @ 0x%x\n", + __func__, tx_buf_addr); + return; + } + length += tx_buf_len; + prev_buf_size += tx_buf_len; + + /* If not chained we'll have a second buffer. */ + if (!(tx_desc.tdes1 & TX_DESC_TDES1_SEC_ADDR_CHND_MASK)) { + tx_buf_addr = tx_desc.tdes3; + gmac->regs[R_NPCM_DMA_CUR_TX_BUF_ADDR] = tx_buf_addr; + tx_buf_len = TX_DESC_TDES1_BFFR2_SZ_MASK(tx_desc.tdes1); + buf = &tx_send_buffer[prev_buf_size]; + + if ((prev_buf_size + tx_buf_len) > sizeof(buf)) { + tx_buffer_size = prev_buf_size + tx_buf_len; + tx_send_buffer = g_realloc(tx_send_buffer, tx_buffer_size); + buf = &tx_send_buffer[prev_buf_size]; + } + + if (dma_memory_read(&address_space_memory, tx_buf_addr, buf, + tx_buf_len, MEMTXATTRS_UNSPECIFIED)) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Failed to read packet @ 0x%x\n", + __func__, tx_buf_addr); + return; + } + length += tx_buf_len; + prev_buf_size += tx_buf_len; + } + if (tx_desc.tdes1 & TX_DESC_TDES1_LAST_SEG_MASK) { + net_checksum_calculate(tx_send_buffer, length, csum); + qemu_send_packet(qemu_get_queue(gmac->nic), tx_send_buffer, length); + trace_npcm_gmac_packet_sent(DEVICE(gmac)->canonical_path, length); + buf = tx_send_buffer; + length = 0; + } + + /* step 6 */ + gmac_dma_set_state(gmac, NPCM_DMA_STATUS_TX_PROCESS_STATE_SHIFT, + NPCM_DMA_STATUS_TX_RUNNING_CLOSING_STATE); + gmac_write_tx_desc(desc_addr, &tx_desc); + if (tx_desc.tdes1 & TX_DESC_TDES1_TX_END_RING_MASK) { + desc_addr = gmac->regs[R_NPCM_DMA_TX_BASE_ADDR]; + } else if (tx_desc.tdes1 & TX_DESC_TDES1_SEC_ADDR_CHND_MASK) { + desc_addr = tx_desc.tdes3; + } else { + desc_addr += sizeof(tx_desc); + } + gmac->regs[R_NPCM_DMA_HOST_TX_DESC] = desc_addr; + + /* step 7 */ + if (tx_desc.tdes1 & TX_DESC_TDES1_INTERR_COMP_MASK) { + gmac->regs[R_NPCM_DMA_STATUS] |= NPCM_DMA_STATUS_TI; + gmac_update_irq(gmac); + } + } +} + +>>>>>>> 107e0d0181 (hw/net: GMAC Tx Implementation) static void gmac_cleanup(NetClientState *nc) { /* Nothing to do yet. */