static int fm_eth_send(struct eth_device *dev, void *buf, int len) { struct fm_eth *fm_eth; struct fm_port_global_pram *pram; struct fm_port_bd *txbd, *txbd_base; u16 offset_in; int i; fm_eth = (struct fm_eth *)dev->priv; pram = fm_eth->tx_pram; txbd = fm_eth->cur_txbd; /* find one empty TxBD */ for (i = 0; txbd->status & TxBD_READY; i++) { udelay(100); if (i > 0x1000) { printf("%s: Tx buffer not ready\n", dev->name); return 0; } } /* setup TxBD */ txbd->buf_ptr_hi = 0; txbd->buf_ptr_lo = (u32)buf; txbd->len = len; sync(); txbd->status = TxBD_READY | TxBD_LAST; sync(); /* update TxQD, let RISC to send the packet */ offset_in = muram_readw(&pram->txqd.offset_in); offset_in += sizeof(struct fm_port_bd); if (offset_in >= muram_readw(&pram->txqd.bd_ring_size)) offset_in = 0; muram_writew(&pram->txqd.offset_in, offset_in); sync(); /* wait for buffer to be transmitted */ for (i = 0; txbd->status & TxBD_READY; i++) { udelay(100); if (i > 0x10000) { printf("%s: Tx error\n", dev->name); return 0; } } /* advance the TxBD */ txbd++; txbd_base = (struct fm_port_bd *)fm_eth->tx_bd_ring; if (txbd >= (txbd_base + TX_BD_RING_SIZE)) txbd = txbd_base; /* update current txbd */ fm_eth->cur_txbd = (void *)txbd; return 1; }
static int fm_eth_recv(struct eth_device *dev) { struct fm_eth *fm_eth; struct fm_port_global_pram *pram; struct fm_port_bd *rxbd, *rxbd_base; u16 status, len; u8 *data; u16 offset_out; fm_eth = (struct fm_eth *)dev->priv; pram = fm_eth->rx_pram; rxbd = fm_eth->cur_rxbd; status = rxbd->status; while (!(status & RxBD_EMPTY)) { if (!(status & RxBD_ERROR)) { data = (u8 *)rxbd->buf_ptr_lo; len = rxbd->len; NetReceive(data, len); } else { printf("%s: Rx error\n", dev->name); return 0; } /* clear the RxBDs */ rxbd->status = RxBD_EMPTY; rxbd->len = 0; sync(); /* advance RxBD */ rxbd++; rxbd_base = (struct fm_port_bd *)fm_eth->rx_bd_ring; if (rxbd >= (rxbd_base + RX_BD_RING_SIZE)) rxbd = rxbd_base; /* read next status */ status = rxbd->status; /* update RxQD */ offset_out = muram_readw(&pram->rxqd.offset_out); offset_out += sizeof(struct fm_port_bd); if (offset_out >= muram_readw(&pram->rxqd.bd_ring_size)) offset_out = 0; muram_writew(&pram->rxqd.offset_out, offset_out); sync(); } fm_eth->cur_rxbd = (void *)rxbd; return 1; }
static int fm_eth_recv(struct eth_device *dev) { struct fm_eth *fm_eth; struct fm_port_global_pram *pram; struct fm_port_bd *rxbd, *rxbd_base; u16 status, len; u32 buf_lo, buf_hi; u8 *data; u16 offset_out; int ret = 1; fm_eth = (struct fm_eth *)dev->priv; pram = fm_eth->rx_pram; rxbd = fm_eth->cur_rxbd; status = muram_readw(&rxbd->status); while (!(status & RxBD_EMPTY)) { if (!(status & RxBD_ERROR)) { buf_hi = muram_readw(&rxbd->buf_ptr_hi); buf_lo = in_be32(&rxbd->buf_ptr_lo); data = (u8 *)((ulong)(buf_hi << 16) << 16 | buf_lo); len = muram_readw(&rxbd->len); net_process_received_packet(data, len); } else { printf("%s: Rx error\n", dev->name); ret = 0; } /* clear the RxBDs */ muram_writew(&rxbd->status, RxBD_EMPTY); muram_writew(&rxbd->len, 0); sync(); /* advance RxBD */ rxbd++; rxbd_base = (struct fm_port_bd *)fm_eth->rx_bd_ring; if (rxbd >= (rxbd_base + RX_BD_RING_SIZE)) rxbd = rxbd_base; /* read next status */ status = muram_readw(&rxbd->status); /* update RxQD */ offset_out = muram_readw(&pram->rxqd.offset_out); offset_out += sizeof(struct fm_port_bd); if (offset_out >= muram_readw(&pram->rxqd.bd_ring_size)) offset_out = 0; muram_writew(&pram->rxqd.offset_out, offset_out); sync(); } fm_eth->cur_rxbd = (void *)rxbd; return ret; }