/* Information that need to be kept for each board. */ struct net_local { int msg_enable; int chip_type; /* one of: CS8900, CS8920, CS8920M */ char chip_revision; /* revision letter of the chip ('A'...) */ int send_cmd; /* the propercommand used to send a packet. */ int rx_mode; int curr_rx_cfg; int send_underrun; /* keep track of how many underruns in a row we get */
};
staticinlinevoid
writereg_io(struct net_device *dev, int portno, int value)
{
nubus_writew(swab16(portno), dev->base_addr + ADD_PORT);
nubus_writew(swab16(value), dev->base_addr + DATA_PORT);
}
/* These are for reading/writing registers in shared memory */ staticinlineint
readreg(struct net_device *dev, int portno)
{ return swab16(nubus_readw(dev->mem_start + portno));
}
staticinlinevoid
writereg(struct net_device *dev, int portno, int value)
{
nubus_writew(swab16(value), dev->mem_start + portno);
}
/* Probe for the CS8900 card in slot E. We won't bother looking
anywhere else until we have a really good reason to do so. */ staticint mac89x0_device_probe(struct platform_device *pdev)
{ struct net_device *dev; struct net_local *lp; int i, slot; unsigned rev_type = 0; unsignedlong ioaddr; unsignedshort sig; int err = -ENODEV; struct nubus_rsrc *fres;
dev = alloc_etherdev(sizeof(struct net_local)); if (!dev) return -ENOMEM;
/* We might have to parameterize this later */
slot = 0xE; /* Get out now if there's a real NuBus card in slot E */
for_each_func_rsrc(fres) if (fres->board->slot == slot) goto out;
/* The pseudo-ISA bits always live at offset 0x300 (gee,
wonder why...) */
ioaddr = (unsignedlong)
nubus_slot_addr(slot) | (((slot&0xf) << 20) + DEFAULTIOBASE);
{ int card_present;
nubus_writew(0, ioaddr + ADD_PORT);
sig = nubus_readw(ioaddr + DATA_PORT); if (sig != swab16(CHIP_EISA_ID_SIG)) goto out;
SET_NETDEV_DEV(dev, &pdev->dev);
/* Initialize the net_device structure. */
lp = netdev_priv(dev);
lp->msg_enable = netif_msg_init(debug, 0);
/* Fill in the 'dev' fields. */
dev->base_addr = ioaddr;
dev->mem_start = (unsignedlong)
nubus_slot_addr(slot) | (((slot&0xf) << 20) + MMIOBASE);
dev->mem_end = dev->mem_start + 0x1000;
/* Turn on shared memory */
writereg_io(dev, PP_BusCTL, MEMORY_ON);
/* get the chip type */
rev_type = readreg(dev, PRODUCT_ID_ADD);
lp->chip_type = rev_type &~ REVISON_BITS;
lp->chip_revision = ((rev_type & REVISON_BITS) >> 8) + 'A';
/* Check the chip type and revision in order to set the correct send command
CS8920 revision C and CS8900 revision F can use the faster send. */
lp->send_cmd = TX_AFTER_381; if (lp->chip_type == CS8900 && lp->chip_revision >= 'F')
lp->send_cmd = TX_NOW; if (lp->chip_type != CS8900 && lp->chip_revision >= 'C')
lp->send_cmd = TX_NOW;
/* keep the upload from being interrupted, since we askthechiptostarttransmittingbeforethe
whole packet has been completely uploaded. */
local_irq_save(flags);
netif_stop_queue(dev);
/* Test to see if the chip has allocated memory for the packet */ if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) { /* Gasp! It hasn't. But that shouldn't happen since
we're waiting for TxOk, so return 1 and requeue this packet. */
local_irq_restore(flags); return NETDEV_TX_BUSY;
}
/* Write the contents of the packet */
skb_copy_from_linear_data(skb, (void *)(dev->mem_start + PP_TxFrame),
skb->len+1);
local_irq_restore(flags);
dev_kfree_skb (skb);
return NETDEV_TX_OK;
}
/* The typical workload of the driver:
Handle the network interface interrupts. */ static irqreturn_t net_interrupt(int irq, void *dev_id)
{ struct net_device *dev = dev_id; struct net_local *lp; int ioaddr, status;
ioaddr = dev->base_addr;
lp = netdev_priv(dev);
/* we MUST read all the events out of the ISQ, otherwise we'll never getinterruptedagain.Asaconsequence,wecan'thaveanylimit onthenumberoftimesweloopintheinterrupthandler.The hardwareguaranteesthateventuallywe'llrunoutofevents.Of course,ifyou'reonaslowmachine,andpacketsarearriving fasterthanyoucanreadthemoff,you'rescrewed.Hastala
vista, baby! */ while ((status = swab16(nubus_readw(dev->base_addr + ISQ_PORT)))) {
netif_dbg(lp, intr, dev, "status=%04x\n", status); switch(status & ISQ_EVENT_MASK) { case ISQ_RECEIVER_EVENT: /* Got a packet(s). */
net_rx(dev); break; case ISQ_TRANSMITTER_EVENT:
dev->stats.tx_packets++;
netif_wake_queue(dev); if ((status & TX_OK) == 0)
dev->stats.tx_errors++; if (status & TX_LOST_CRS)
dev->stats.tx_carrier_errors++; if (status & TX_SQE_ERROR)
dev->stats.tx_heartbeat_errors++; if (status & TX_LATE_COL)
dev->stats.tx_window_errors++; if (status & TX_16_COL)
dev->stats.tx_aborted_errors++; break; case ISQ_BUFFER_EVENT: if (status & READY_FOR_TX) { /* we tried to transmit a packet earlier, butinexplicablyranoutofbuffers. Thatshouldn'thappensinceweonlyever loadonepacket.Shrug.Dotheright
thing anyway. */
netif_wake_queue(dev);
} if (status & TX_UNDERRUN) {
netif_dbg(lp, tx_err, dev, "transmit underrun\n");
lp->send_underrun++; if (lp->send_underrun == 3) lp->send_cmd = TX_AFTER_381; elseif (lp->send_underrun == 6) lp->send_cmd = TX_AFTER_ALL;
} break; case ISQ_RX_MISS_EVENT:
dev->stats.rx_missed_errors += (status >> 6); break; case ISQ_TX_COL_EVENT:
dev->stats.collisions += (status >> 6); break;
}
} return IRQ_HANDLED;
}
/* We have a good packet(s), get it/them out of the buffers. */ staticvoid
net_rx(struct net_device *dev)
{ struct net_local *lp = netdev_priv(dev); struct sk_buff *skb; int status, length;
status = readreg(dev, PP_RxStatus); if ((status & RX_OK) == 0) {
dev->stats.rx_errors++; if (status & RX_RUNT)
dev->stats.rx_length_errors++; if (status & RX_EXTRA_DATA)
dev->stats.rx_length_errors++; if ((status & RX_CRC_ERROR) &&
!(status & (RX_EXTRA_DATA|RX_RUNT))) /* per str 172 */
dev->stats.rx_crc_errors++; if (status & RX_DRIBBLE)
dev->stats.rx_frame_errors++; return;
}
length = readreg(dev, PP_RxLength); /* Malloc up new buffer. */
skb = alloc_skb(length, GFP_ATOMIC); if (skb == NULL) {
dev->stats.rx_dropped++; return;
}
skb_put(skb, length);
/* Get the current statistics. This may be called with the card open or
closed. */ staticstruct net_device_stats *
net_get_stats(struct net_device *dev)
{ unsignedlong flags;
local_irq_save(flags); /* Update the statistics from the device registers. */
dev->stats.rx_missed_errors += (readreg(dev, PP_RxMiss) >> 6);
dev->stats.collisions += (readreg(dev, PP_TxCol) >> 6);
local_irq_restore(flags);
if(dev->flags&IFF_PROMISC)
{
lp->rx_mode = RX_ALL_ACCEPT;
} elseif ((dev->flags & IFF_ALLMULTI) || !netdev_mc_empty(dev)) { /* The multicast-accept list is initialized to accept-all, and we
rely on higher-level filtering for now. */
lp->rx_mode = RX_MULTCAST_ACCEPT;
} else
lp->rx_mode = 0;
/* in promiscuous mode, we accept errored packets, so we have to enable interrupts on them also */
writereg(dev, PP_RxCFG, lp->curr_rx_cfg |
(lp->rx_mode == RX_ALL_ACCEPT? (RX_CRC_ERROR_ENBL|RX_RUNT_ENBL|RX_EXTRA_DATA_ENBL) : 0));
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.