static void init_ring(void) { int i; char * p; w840private.tx_full = 0; w840private.tx_q_bytes = w840private.cur_rx = w840private.cur_tx = 0; w840private.dirty_rx = w840private.dirty_tx = 0; w840private.rx_buf_sz = PKT_BUF_SZ; w840private.rx_head_desc = &w840private.rx_ring[0]; p = &rx_packet[0]; for (i = 0; i < RX_RING_SIZE; i++) { w840private.rx_ring[i].length = w840private.rx_buf_sz; w840private.rx_ring[i].status = 0; w840private.rx_ring[i].next_desc = virt_to_le32desc(&w840private.rx_ring[i+1]); w840private.rx_ring[i].buffer1 = virt_to_le32desc(p + (PKT_BUF_SZ * i)); w840private.rx_ring[i].status = DescOwn | DescIntr; } w840private.rx_ring[i-1].length |= DescEndRing; w840private.rx_ring[i-1].next_desc = virt_to_le32desc(&w840private.rx_ring[0]); w840private.dirty_rx = (unsigned int)(i - RX_RING_SIZE); for (i = 0; i < TX_RING_SIZE; i++) { w840private.tx_ring[i].status = 0; } return; }
static void w89c840_transmit( struct nic *nic, const char *d, /* Destination */ unsigned int t, /* Type */ unsigned int s, /* size */ const char *p) /* Packet */ { /* send the packet to destination */ unsigned entry; int transmit_status; unsigned long ct; /* Caution: the write order is important here, set the field with the "ownership" bits last. */ /* Fill in our transmit buffer */ entry = w840private.cur_tx % TX_RING_SIZE; memcpy (w89c840_buf.tx_packet, d, ETH_ALEN); /* dst */ memcpy (w89c840_buf.tx_packet + ETH_ALEN, nic->node_addr, ETH_ALEN);/*src*/ *((char *) w89c840_buf.tx_packet + 12) = t >> 8; /* type */ *((char *) w89c840_buf.tx_packet + 13) = t; memcpy (w89c840_buf.tx_packet + ETH_HLEN, p, s); s += ETH_HLEN; while (s < ETH_ZLEN) *((char *) w89c840_buf.tx_packet + ETH_HLEN + (s++)) = 0; w840private.tx_ring[entry].buffer1 = virt_to_le32desc(w89c840_buf.tx_packet); w840private.tx_ring[entry].length = (DescWholePkt | (u32) s); if (entry >= TX_RING_SIZE-1) /* Wrap ring */ w840private.tx_ring[entry].length |= (DescIntr | DescEndRing); w840private.tx_ring[entry].status = (DescOwn); w840private.cur_tx++; w840private.tx_q_bytes = (u16) s; writel(0, ioaddr + TxStartDemand); /* Work around horrible bug in the chip by marking the queue as full when we do not have FIFO room for a maximum sized packet. */ if ((w840private.drv_flags & HasBrokenTx) && w840private.tx_q_bytes > TX_BUG_FIFO_LIMIT) { /* Actually this is left to help finding error tails later in debugging... * See Linux kernel driver in winbond-840.c for details. */ w840private.tx_full = 1; } #if defined(W89C840_DEBUG) printf("winbond-840 : Transmit frame # %d size %d queued in slot %d.\n", w840private.cur_tx, s, entry); #endif /* Now wait for TX to complete. */ transmit_status = w840private.tx_ring[entry].status; ct = currticks(); { #if defined W89C840_DEBUG u32 intr_stat = 0; #endif while (1) { #if defined(W89C840_DEBUG) decode_interrupt(intr_stat); #endif while ( (transmit_status & DescOwn) && ct + TX_TIMEOUT < currticks()) { transmit_status = w840private.tx_ring[entry].status; } break; } } if ((transmit_status & DescOwn) == 0) { #if defined(W89C840_DEBUG) printf("winbond-840 : transmission complete after wait loop iterations, status %X\n", w840private.tx_ring[entry].status); #endif return; } /* Transmit timed out... */ printf("winbond-840 : transmission TIMEOUT : status %X\n", (unsigned int) w840private.tx_ring[entry].status); return; }
static void w89c840_transmit( struct nic *nic, const char *d, unsigned int t, unsigned int s, const char *p) { unsigned entry; int transmit_status; entry = w840private.cur_tx % TX_RING_SIZE; memcpy (tx_packet, d, ETH_ALEN); memcpy (tx_packet + ETH_ALEN, nic->node_addr, ETH_ALEN); *((char *) tx_packet + 12) = t >> 8; *((char *) tx_packet + 13) = t; memcpy (tx_packet + ETH_HLEN, p, s); s += ETH_HLEN; while (s < ETH_ZLEN) *((char *) tx_packet + ETH_HLEN + (s++)) = 0; w840private.tx_ring[entry].buffer1 = virt_to_le32desc(tx_packet); w840private.tx_ring[entry].length = (DescWholePkt | s); if (entry >= TX_RING_SIZE-1) w840private.tx_ring[entry].length |= (DescIntr | DescEndRing); w840private.tx_ring[entry].status = (DescOwn); w840private.cur_tx++; w840private.tx_q_bytes += s; writel(0, ioaddr + TxStartDemand); if ((w840private.drv_flags & HasBrokenTx) && w840private.tx_q_bytes > TX_BUG_FIFO_LIMIT) { w840private.tx_full = 1; } #if defined(W89C840_DEBUG) printf("winbond-840 : Transmit frame # %d size %d queued in slot %d.\n", w840private.cur_tx, s, entry); #endif transmit_status = w840private.tx_ring[entry].status; load_timer2(TX_TIMEOUT); { u32 intr_stat = 0; while (1) { intr_stat = readl(ioaddr + IntrStatus); #if defined(W89C840_DEBUG) decode_interrupt(intr_stat); #endif if (intr_stat & (NormalIntr | IntrTxDone)) { while ( (transmit_status & DescOwn) && timer2_running()) { transmit_status = w840private.tx_ring[entry].status; } writel(intr_stat & 0x0001ffff, ioaddr + IntrStatus); break; } } } if ((transmit_status & DescOwn) == 0) { #if defined(W89C840_DEBUG) printf("winbond-840 : transmission complete after %d wait loop iterations, status %X\n", TX_LOOP_COUNT - transmit_loop_counter, w840private.tx_ring[entry].status); #endif return; } printf("winbond-840 : transmission TIMEOUT : status %X\n", w840private.tx_ring[entry].status); return; }