Skip to content

Commit

Permalink
Gt96k patch correcting the reporting of processed transmit descriptor…
Browse files Browse the repository at this point in the history
…s back to IOS.

Fixes missing interrupt when gt96k doesn't own the first trasmit descriptor.
Fixes incorrect clearing of the Own bit. (last must wait for transmission, the rest are cleared when processed)
Fixes offset when writing back the cmd word of the non-last descriptors. (missing from 0.2.6-RC3)

Affects c2691, c3725 and c3745.
Fixes issue #29 - packet loss with multicast traffic
Forum-link: http://forum.gns3.net/post26454.html#p26454
  • Loading branch information
paluchpeter authored and flaviojs committed Mar 5, 2014
1 parent 16f7c39 commit 79838a4
Showing 1 changed file with 35 additions and 25 deletions.
60 changes: 35 additions & 25 deletions common/dev_gt.c
Expand Up @@ -2155,8 +2155,8 @@ static int gt_eth_handle_port_txqueue(struct gt_data *d,struct eth_port *port,
int queue)
{
u_char pkt[GT_MAX_PKT_SIZE],*pkt_ptr;
struct sdma_desc txd0,ctxd,*ptxd;
m_uint32_t tx_start,tx_current;
struct sdma_desc ctxd;
m_uint32_t tx_current;
m_uint32_t len,tot_len;
int abort = FALSE;

Expand All @@ -2168,17 +2168,29 @@ static int gt_eth_handle_port_txqueue(struct gt_data *d,struct eth_port *port,
return(FALSE);

/* Copy the current txring descriptor */
tx_start = tx_current = port->tx_current[queue];
tx_current = port->tx_current[queue];

if (!tx_start)
if (!tx_current)
return(FALSE);

ptxd = &txd0;
gt_sdma_desc_read(d,tx_start,ptxd);
gt_sdma_desc_read(d,tx_current,&ctxd);

/* If we don't own the first descriptor, we cannot transmit */
if (!(txd0.cmd_stat & GT_TXDESC_OWN))
if (!(ctxd.cmd_stat & GT_TXDESC_OWN)) {
if (queue == 0) {
port->icr |= GT_ICR_TXENDL;
port->sdcmr |= GT_SDCMR_STDL;
port->sdcmr &= ~GT_SDCMR_TXDL;

} else {
port->icr |= GT_ICR_TXENDH;
port->sdcmr |= GT_SDCMR_STDH;
port->sdcmr &= ~GT_SDCMR_TXDH;
}

gt_eth_update_int_status(d,port);
return(FALSE);
}

/* Empty packet for now */
pkt_ptr = pkt;
Expand All @@ -2187,43 +2199,41 @@ static int gt_eth_handle_port_txqueue(struct gt_data *d,struct eth_port *port,
for(;;) {
#if DEBUG_ETH_TX
GT_LOG(d,"gt_eth_handle_txqueue: loop: "
"cmd_stat=0x%x, buf_size=0x%x, next_ptr=0x%x, buf_ptr=0x%x\n",
ptxd->cmd_stat,ptxd->buf_size,ptxd->next_ptr,ptxd->buf_ptr);
"tx_current=0x%08x, cmd_stat=0x%08x, buf_size=0x%08x, next_ptr=0x%08x, buf_ptr=0x%08x\n",
tx_current, ctxd.cmd_stat, ctxd.buf_size, ctxd.next_ptr, ctxd.buf_ptr);
#endif

if (!(ptxd->cmd_stat & GT_TXDESC_OWN)) {
if (!(ctxd.cmd_stat & GT_TXDESC_OWN)) {
GT_LOG(d,"gt_eth_handle_txqueue: descriptor not owned!\n");
abort = TRUE;
break;
}

/* Copy packet data to the buffer */
len = (ptxd->buf_size & GT_TXDESC_BC_MASK) >> GT_TXDESC_BC_SHIFT;
len = (ctxd.buf_size & GT_TXDESC_BC_MASK) >> GT_TXDESC_BC_SHIFT;

physmem_copy_from_vm(d->vm,pkt_ptr,ptxd->buf_ptr,len);
physmem_copy_from_vm(d->vm,pkt_ptr,ctxd.buf_ptr,len);
pkt_ptr += len;
tot_len += len;

/* Clear the OWN bit if this is not the first descriptor */
if (!(ptxd->cmd_stat & GT_TXDESC_F)) {
ptxd->cmd_stat &= ~GT_TXDESC_OWN;
physmem_copy_u32_to_vm(d->vm,tx_current,ptxd->cmd_stat);
/* Clear the OWN bit if this is not the last descriptor */
if (!(ctxd.cmd_stat & GT_TXDESC_L)) {
ctxd.cmd_stat &= ~GT_TXDESC_OWN;
physmem_copy_u32_to_vm(d->vm,tx_current+4,ctxd.cmd_stat);
}

tx_current = ptxd->next_ptr;

/* Last descriptor or no more desc available ? */
if (ptxd->cmd_stat & GT_TXDESC_L)
if (ctxd.cmd_stat & GT_TXDESC_L)
break;

if (!tx_current) {
if (!(ctxd.next_ptr)) {
abort = TRUE;
break;
}

/* Fetch the next descriptor */
tx_current = ctxd.next_ptr;
gt_sdma_desc_read(d,tx_current,&ctxd);
ptxd = &ctxd;
}

if ((tot_len != 0) && !abort) {
Expand All @@ -2242,11 +2252,11 @@ static int gt_eth_handle_port_txqueue(struct gt_data *d,struct eth_port *port,
port->tx_frames++;
}

/* Clear the OWN flag of the first descriptor */
txd0.cmd_stat &= ~GT_TXDESC_OWN;
physmem_copy_u32_to_vm(d->vm,tx_start+4,txd0.cmd_stat);
/* Clear the OWN flag of the last descriptor */
ctxd.cmd_stat &= ~GT_TXDESC_OWN;
physmem_copy_u32_to_vm(d->vm,tx_current+4,ctxd.cmd_stat);

port->tx_current[queue] = tx_current;
port->tx_current[queue] = tx_current = ctxd.next_ptr;

/* Notify host about transmitted packet */
if (queue == 0)
Expand Down

0 comments on commit 79838a4

Please sign in to comment.