Line 143... |
Line 143... |
for(i = 0; i < OETH_RXBD_NUM; i++) {
|
for(i = 0; i < OETH_RXBD_NUM; i++) {
|
|
|
skb = dev_alloc_skb(MAX_FRAME_SIZE);
|
skb = dev_alloc_skb(MAX_FRAME_SIZE);
|
|
|
if (skb == NULL)
|
if (skb == NULL)
|
rx_bd[i].status = OETH_RX_BD_IRQ;
|
rx_bd[i].len_status = (0 << 16) | OETH_RX_BD_IRQ;
|
else
|
else
|
rx_bd[i].status = OETH_RX_BD_EMPTY | OETH_RX_BD_IRQ;
|
rx_bd[i].len_status = (0 << 16) | OETH_RX_BD_EMPTY | OETH_RX_BD_IRQ;
|
|
|
cep->rx_skbuff[i] = skb;
|
cep->rx_skbuff[i] = skb;
|
|
|
rx_bd[i].len = 0;
|
|
rx_bd[i].addr = (unsigned long)skb->tail;
|
rx_bd[i].addr = (unsigned long)skb->tail;
|
}
|
}
|
rx_bd[OETH_RXBD_NUM - 1].status |= OETH_RX_BD_WRAP;
|
rx_bd[OETH_RXBD_NUM - 1].len_status |= OETH_RX_BD_WRAP;
|
#endif
|
#endif
|
|
|
/* Install our interrupt handler.
|
/* Install our interrupt handler.
|
*/
|
*/
|
request_irq(IRQ_ETH_0, oeth_interrupt, 0, "eth", (void *)dev);
|
request_irq(IRQ_ETH_0, oeth_interrupt, 0, "eth", (void *)dev);
|
Line 184... |
Line 183... |
*/
|
*/
|
regs->moder &= ~(OETH_MODER_RXEN | OETH_MODER_TXEN);
|
regs->moder &= ~(OETH_MODER_RXEN | OETH_MODER_TXEN);
|
|
|
bdp = cep->rx_bd_base;
|
bdp = cep->rx_bd_base;
|
for (i = 0; i < OETH_RXBD_NUM; i++) {
|
for (i = 0; i < OETH_RXBD_NUM; i++) {
|
bdp->status &= ~(OETH_TX_BD_STATS | OETH_TX_BD_READY);
|
bdp->len_status &= ~(OETH_TX_BD_STATS | OETH_TX_BD_READY);
|
bdp++;
|
bdp++;
|
}
|
}
|
|
|
bdp = cep->tx_bd_base;
|
bdp = cep->tx_bd_base;
|
for (i = 0; i < OETH_TXBD_NUM; i++) {
|
for (i = 0; i < OETH_TXBD_NUM; i++) {
|
bdp->status &= ~(OETH_RX_BD_STATS | OETH_RX_BD_EMPTY);
|
bdp->len_status &= ~(OETH_RX_BD_STATS | OETH_RX_BD_EMPTY);
|
bdp++;
|
bdp++;
|
}
|
}
|
|
|
#ifndef RXBUFF_PREALLOC
|
#ifndef RXBUFF_PREALLOC
|
|
|
Line 240... |
Line 239... |
return 1;
|
return 1;
|
}
|
}
|
|
|
/* Clear all of the status flags.
|
/* Clear all of the status flags.
|
*/
|
*/
|
bdp->status &= ~OETH_TX_BD_STATS;
|
bdp->len_status &= ~OETH_TX_BD_STATS;
|
|
|
/* If the frame is short, tell CPM to pad it.
|
/* If the frame is short, tell CPM to pad it.
|
*/
|
*/
|
if (skb->len <= ETH_ZLEN)
|
if (skb->len <= ETH_ZLEN)
|
bdp->status |= OETH_TX_BD_PAD;
|
bdp->len_status |= OETH_TX_BD_PAD;
|
else
|
else
|
bdp->status &= ~OETH_TX_BD_PAD;
|
bdp->len_status &= ~OETH_TX_BD_PAD;
|
|
|
#if DEBUG
|
#if DEBUG
|
_print("TX\n");
|
_print("TX\n");
|
oeth_print_packet(skb->data, skb->len);
|
oeth_print_packet(skb->data, skb->len);
|
#endif
|
#endif
|
Line 264... |
Line 263... |
return 1;
|
return 1;
|
}
|
}
|
else
|
else
|
memcpy((unsigned char *)bdp->addr, skb->data, skb->len);
|
memcpy((unsigned char *)bdp->addr, skb->data, skb->len);
|
|
|
bdp->len = skb->len;
|
bdp->len_status = (bdp->len_status & 0x0000ffff) | (skb->len << 16);
|
|
|
dev_kfree_skb(skb, FREE_WRITE);
|
dev_kfree_skb(skb, FREE_WRITE);
|
#else
|
#else
|
/* Set buffer length and buffer pointer.
|
/* Set buffer length and buffer pointer.
|
*/
|
*/
|
bdp->len = skb->len;
|
bdp->len_status = (bdp->len_status & 0x0000ffff) | (skb->len << 16);
|
bdp->addr = (uint)__pa(skb->data);
|
bdp->addr = (uint)__pa(skb->data);
|
|
|
/* Save skb pointer.
|
/* Save skb pointer.
|
*/
|
*/
|
cep->tx_skbuff[cep->tx_next] = skb;
|
cep->tx_skbuff[cep->tx_next] = skb;
|
Line 288... |
Line 287... |
cep->tx_full = 1;
|
cep->tx_full = 1;
|
|
|
/* Send it on its way. Tell controller its ready, interrupt when done,
|
/* Send it on its way. Tell controller its ready, interrupt when done,
|
* and to put the CRC on the end.
|
* and to put the CRC on the end.
|
*/
|
*/
|
bdp->status |= (OETH_TX_BD_READY | OETH_TX_BD_IRQ | OETH_TX_BD_CRC);
|
bdp->len_status |= (OETH_TX_BD_READY | OETH_TX_BD_IRQ | OETH_TX_BD_CRC);
|
|
|
dev->trans_start = jiffies;
|
dev->trans_start = jiffies;
|
|
|
restore_flags(flags);
|
restore_flags(flags);
|
|
|
Line 353... |
Line 352... |
|
|
for (;; cep->tx_last = (cep->tx_last + 1) & OETH_TXBD_NUM_MASK) {
|
for (;; cep->tx_last = (cep->tx_last + 1) & OETH_TXBD_NUM_MASK) {
|
|
|
bdp = cep->tx_bd_base + cep->tx_last;
|
bdp = cep->tx_bd_base + cep->tx_last;
|
|
|
if ((bdp->status & OETH_TX_BD_READY) ||
|
if ((bdp->len_status & OETH_TX_BD_READY) ||
|
((cep->tx_last == cep->tx_next) && !cep->tx_full))
|
((cep->tx_last == cep->tx_next) && !cep->tx_full))
|
break;
|
break;
|
|
|
/* Check status for errors
|
/* Check status for errors
|
*/
|
*/
|
if (bdp->status & OETH_TX_BD_LATECOL)
|
if (bdp->len_status & OETH_TX_BD_LATECOL)
|
cep->stats.tx_window_errors++;
|
cep->stats.tx_window_errors++;
|
if (bdp->status & OETH_TX_BD_RETLIM)
|
if (bdp->len_status & OETH_TX_BD_RETLIM)
|
cep->stats.tx_aborted_errors++;
|
cep->stats.tx_aborted_errors++;
|
if (bdp->status & OETH_TX_BD_UNDERRUN)
|
if (bdp->len_status & OETH_TX_BD_UNDERRUN)
|
cep->stats.tx_fifo_errors++;
|
cep->stats.tx_fifo_errors++;
|
if (bdp->status & OETH_TX_BD_CARRIER)
|
if (bdp->len_status & OETH_TX_BD_CARRIER)
|
cep->stats.tx_carrier_errors++;
|
cep->stats.tx_carrier_errors++;
|
if (bdp->status & (OETH_TX_BD_LATECOL | OETH_TX_BD_RETLIM | OETH_TX_BD_UNDERRUN))
|
if (bdp->len_status & (OETH_TX_BD_LATECOL | OETH_TX_BD_RETLIM | OETH_TX_BD_UNDERRUN))
|
cep->stats.tx_errors++;
|
cep->stats.tx_errors++;
|
|
|
cep->stats.tx_packets++;
|
cep->stats.tx_packets++;
|
cep->stats.collisions += (bdp->status >> 4) & 0x000f;
|
cep->stats.collisions += (bdp->len_status >> 4) & 0x000f;
|
|
|
#ifndef TXBUFF_PREALLOC
|
#ifndef TXBUFF_PREALLOC
|
skb = cep->tx_skbuff[cep->tx_last];
|
skb = cep->tx_skbuff[cep->tx_last];
|
|
|
/* Free the sk buffer associated with this last transmit.
|
/* Free the sk buffer associated with this last transmit.
|
Line 417... |
Line 416... |
skb = dev_alloc_skb(MAX_FRAME_SIZE);
|
skb = dev_alloc_skb(MAX_FRAME_SIZE);
|
|
|
if (skb != NULL)
|
if (skb != NULL)
|
{
|
{
|
bdp->addr = (unsigned long) skb->tail;
|
bdp->addr = (unsigned long) skb->tail;
|
bdp->status |= OETH_RX_BD_EMPTY;
|
bdp->len_status |= OETH_RX_BD_EMPTY;
|
}
|
}
|
|
|
continue;
|
continue;
|
}
|
}
|
#endif
|
#endif
|
|
|
if (bdp->status & OETH_RX_BD_EMPTY)
|
if (bdp->len_status & OETH_RX_BD_EMPTY)
|
break;
|
break;
|
|
|
/* Check status for errors.
|
/* Check status for errors.
|
*/
|
*/
|
if (bdp->status & (OETH_RX_BD_TOOLONG | OETH_RX_BD_SHORT)) {
|
if (bdp->len_status & (OETH_RX_BD_TOOLONG | OETH_RX_BD_SHORT)) {
|
cep->stats.rx_length_errors++;
|
cep->stats.rx_length_errors++;
|
bad = 1;
|
bad = 1;
|
}
|
}
|
if (bdp->status & OETH_RX_BD_DRIBBLE) {
|
if (bdp->len_status & OETH_RX_BD_DRIBBLE) {
|
cep->stats.rx_frame_errors++;
|
cep->stats.rx_frame_errors++;
|
bad = 1;
|
bad = 1;
|
}
|
}
|
if (bdp->status & OETH_RX_BD_CRCERR) {
|
if (bdp->len_status & OETH_RX_BD_CRCERR) {
|
cep->stats.rx_crc_errors++;
|
cep->stats.rx_crc_errors++;
|
bad = 1;
|
bad = 1;
|
}
|
}
|
if (bdp->status & OETH_RX_BD_OVERRUN) {
|
if (bdp->len_status & OETH_RX_BD_OVERRUN) {
|
cep->stats.rx_crc_errors++;
|
cep->stats.rx_crc_errors++;
|
bad = 1;
|
bad = 1;
|
}
|
}
|
if (bdp->status & OETH_RX_BD_MISS) {
|
if (bdp->len_status & OETH_RX_BD_MISS) {
|
|
|
}
|
}
|
if (bdp->status & OETH_RX_BD_LATECOL) {
|
if (bdp->len_status & OETH_RX_BD_LATECOL) {
|
cep->stats.rx_frame_errors++;
|
cep->stats.rx_frame_errors++;
|
bad = 1;
|
bad = 1;
|
}
|
}
|
|
|
|
|
if (bad) {
|
if (bad) {
|
|
|
bdp->status &= ~OETH_RX_BD_STATS;
|
bdp->len_status &= ~OETH_RX_BD_STATS;
|
bdp->status |= OETH_RX_BD_EMPTY;
|
bdp->len_status |= OETH_RX_BD_EMPTY;
|
|
|
continue;
|
continue;
|
}
|
}
|
|
|
/* Process the incoming frame.
|
/* Process the incoming frame.
|
*/
|
*/
|
pkt_len = bdp->len;
|
pkt_len = bdp->len_status >> 16;
|
|
|
#ifdef RXBUFF_PREALLOC
|
#ifdef RXBUFF_PREALLOC
|
skb = dev_alloc_skb(pkt_len);
|
skb = dev_alloc_skb(pkt_len);
|
|
|
if (skb == NULL) {
|
if (skb == NULL) {
|
Line 485... |
Line 484... |
skb->protocol = eth_type_trans(skb,dev);
|
skb->protocol = eth_type_trans(skb,dev);
|
netif_rx(skb);
|
netif_rx(skb);
|
cep->stats.rx_packets++;
|
cep->stats.rx_packets++;
|
}
|
}
|
|
|
bdp->status &= ~OETH_RX_BD_STATS;
|
bdp->len_status &= ~OETH_RX_BD_STATS;
|
bdp->status |= OETH_RX_BD_EMPTY;
|
bdp->len_status |= OETH_RX_BD_EMPTY;
|
#else
|
#else
|
|
|
if (pkt_len < 128) {
|
if (pkt_len < 128) {
|
|
|
small_skb = dev_alloc_skb(pkt_len);
|
small_skb = dev_alloc_skb(pkt_len);
|
|
|
if (small_skb) {
|
if (small_skb) {
|
small_skb->dev = dev;
|
small_skb->dev = dev;
|
#if DEBUG
|
#if DEBUG
|
_print("RX short\n");
|
_print("RX short\n");
|
oeth_print_packet(bdp->addr, bdp->len);
|
oeth_print_packet(bdp->addr, bdp->len_status >> 16);
|
#endif
|
#endif
|
memcpy(skb_put(small_skb, pkt_len), (unsigned char *)__va(bdp->addr), pkt_len);
|
memcpy(skb_put(small_skb, pkt_len), (unsigned char *)__va(bdp->addr), pkt_len);
|
small_skb->protocol = eth_type_trans(small_skb,dev);
|
small_skb->protocol = eth_type_trans(small_skb,dev);
|
netif_rx(small_skb);
|
netif_rx(small_skb);
|
cep->stats.rx_packets++;
|
cep->stats.rx_packets++;
|
Line 509... |
Line 508... |
else {
|
else {
|
printk("%s: Memory squeeze, dropping packet.\n", dev->name);
|
printk("%s: Memory squeeze, dropping packet.\n", dev->name);
|
cep->stats.rx_dropped++;
|
cep->stats.rx_dropped++;
|
}
|
}
|
|
|
bdp->status &= ~OETH_RX_BD_STATS;
|
bdp->len_status &= ~OETH_RX_BD_STATS;
|
bdp->status |= OETH_RX_BD_EMPTY;
|
bdp->len_status |= OETH_RX_BD_EMPTY;
|
}
|
}
|
else {
|
else {
|
skb->dev = dev;
|
skb->dev = dev;
|
skb_put(skb, bdp->len);
|
skb_put(skb, bdp->len_status >> 16);
|
skb->protocol = eth_type_trans(skb,dev);
|
skb->protocol = eth_type_trans(skb,dev);
|
netif_rx(skb);
|
netif_rx(skb);
|
cep->stats.rx_packets++;
|
cep->stats.rx_packets++;
|
#if DEBUG
|
#if DEBUG
|
_print("RX long\n");
|
_print("RX long\n");
|
oeth_print_packet(bdp->addr, bdp->len);
|
oeth_print_packet(bdp->addr, bdp->len_status >> 16);
|
#endif
|
#endif
|
|
|
skb = dev_alloc_skb(MAX_FRAME_SIZE);
|
skb = dev_alloc_skb(MAX_FRAME_SIZE);
|
|
|
bdp->status &= ~OETH_RX_BD_STATS;
|
bdp->len_status &= ~OETH_RX_BD_STATS;
|
|
|
if (skb) {
|
if (skb) {
|
cep->rx_skbuff[cep->rx_cur] = skb;
|
cep->rx_skbuff[cep->rx_cur] = skb;
|
|
|
bdp->addr = (unsigned long)skb->tail;
|
bdp->addr = (unsigned long)skb->tail;
|
bdp->status |= OETH_RX_BD_EMPTY;
|
bdp->len_status |= OETH_RX_BD_EMPTY;
|
}
|
}
|
else {
|
else {
|
cep->rx_skbuff[cep->rx_cur] = NULL;
|
cep->rx_skbuff[cep->rx_cur] = NULL;
|
}
|
}
|
}
|
}
|
Line 638... |
Line 637... |
{
|
{
|
struct oeth_private *cep;
|
struct oeth_private *cep;
|
volatile oeth_regs *regs;
|
volatile oeth_regs *regs;
|
volatile oeth_bd *tx_bd, *rx_bd;
|
volatile oeth_bd *tx_bd, *rx_bd;
|
int i, j, k;
|
int i, j, k;
|
|
#ifdef SRAM_BUFF
|
unsigned long mem_addr = SRAM_BUFF_BASE;
|
unsigned long mem_addr = SRAM_BUFF_BASE;
|
|
#else
|
|
unsigned long mem_addr;
|
|
#endif
|
|
|
cep = (struct oeth_private *)dev->priv;
|
cep = (struct oeth_private *)dev->priv;
|
|
|
/* Allocate a new 'dev' if needed.
|
/* Allocate a new 'dev' if needed.
|
*/
|
*/
|
Line 736... |
Line 739... |
#ifndef SRAM_BUFF
|
#ifndef SRAM_BUFF
|
mem_addr = __get_free_page(GFP_KERNEL);
|
mem_addr = __get_free_page(GFP_KERNEL);
|
#endif
|
#endif
|
|
|
for(j = 0; j < OETH_TX_BUFF_PPGAE; j++, k++) {
|
for(j = 0; j < OETH_TX_BUFF_PPGAE; j++, k++) {
|
tx_bd[k].status = OETH_TX_BD_PAD | OETH_TX_BD_CRC | OETH_RX_BD_IRQ;
|
tx_bd[k].len_status = OETH_TX_BD_PAD | OETH_TX_BD_CRC | OETH_RX_BD_IRQ;
|
tx_bd[k].addr = __pa(mem_addr);
|
tx_bd[k].addr = __pa(mem_addr);
|
mem_addr += OETH_TX_BUFF_SIZE;
|
mem_addr += OETH_TX_BUFF_SIZE;
|
}
|
}
|
}
|
}
|
tx_bd[OETH_TXBD_NUM - 1].status |= OETH_TX_BD_WRAP;
|
tx_bd[OETH_TXBD_NUM - 1].len_status |= OETH_TX_BD_WRAP;
|
#else
|
#else
|
|
|
/* Initialize TXBDs.
|
/* Initialize TXBDs.
|
*/
|
*/
|
for(i = 0; i < OETH_TXBD_NUM; i++) {
|
for(i = 0; i < OETH_TXBD_NUM; i++) {
|
|
|
cep->tx_skbuff[i] = NULL;
|
cep->tx_skbuff[i] = NULL;
|
|
|
tx_bd[i].len = 0;
|
tx_bd[i].len_status = (0 << 16) | OETH_TX_BD_PAD | OETH_TX_BD_CRC | OETH_RX_BD_IRQ;
|
tx_bd[i].status = OETH_TX_BD_PAD | OETH_TX_BD_CRC | OETH_RX_BD_IRQ;
|
|
tx_bd[i].addr = 0;
|
tx_bd[i].addr = 0;
|
}
|
}
|
tx_bd[OETH_TXBD_NUM - 1].status |= OETH_TX_BD_WRAP;
|
tx_bd[OETH_TXBD_NUM - 1].len_status |= OETH_TX_BD_WRAP;
|
#endif
|
#endif
|
|
|
#ifdef RXBUFF_PREALLOC
|
#ifdef RXBUFF_PREALLOC
|
|
|
/* Initialize RXBDs.
|
/* Initialize RXBDs.
|
Line 768... |
Line 770... |
#ifndef SRAM_BUFF
|
#ifndef SRAM_BUFF
|
mem_addr = __get_free_page(GFP_KERNEL);
|
mem_addr = __get_free_page(GFP_KERNEL);
|
#endif
|
#endif
|
|
|
for(j = 0; j < OETH_RX_BUFF_PPGAE; j++, k++) {
|
for(j = 0; j < OETH_RX_BUFF_PPGAE; j++, k++) {
|
rx_bd[k].status = OETH_RX_BD_EMPTY | OETH_RX_BD_IRQ;
|
rx_bd[k].len_status = OETH_RX_BD_EMPTY | OETH_RX_BD_IRQ;
|
rx_bd[k].addr = __pa(mem_addr);
|
rx_bd[k].addr = __pa(mem_addr);
|
mem_addr += OETH_RX_BUFF_SIZE;
|
mem_addr += OETH_RX_BUFF_SIZE;
|
}
|
}
|
}
|
}
|
rx_bd[OETH_RXBD_NUM - 1].status |= OETH_RX_BD_WRAP;
|
rx_bd[OETH_RXBD_NUM - 1].len_status |= OETH_RX_BD_WRAP;
|
|
|
#else
|
#else
|
/* Initialize RXBDs.
|
/* Initialize RXBDs.
|
*/
|
*/
|
for(i = 0; i < OETH_RXBD_NUM; i++) {
|
for(i = 0; i < OETH_RXBD_NUM; i++) {
|
|
|
|
|
rx_bd[i].status = OETH_RX_BD_IRQ;
|
rx_bd[i].len_status = (0 << 16) | OETH_RX_BD_IRQ;
|
|
|
cep->rx_skbuff[i] = NULL;
|
cep->rx_skbuff[i] = NULL;
|
|
|
rx_bd[i].len = 0;
|
|
rx_bd[i].addr = 0;
|
rx_bd[i].addr = 0;
|
}
|
}
|
rx_bd[OETH_RXBD_NUM - 1].status |= OETH_RX_BD_WRAP;
|
rx_bd[OETH_RXBD_NUM - 1].len_status |= OETH_RX_BD_WRAP;
|
|
|
#endif
|
#endif
|
|
|
/* Set default ethernet station address.
|
/* Set default ethernet station address.
|
*/
|
*/
|