/* 3c527.c: 3Com Etherlink/MC32 driver for Linux 2.4 and 2.6.
*
* (c) Copyright 1998 Red Hat Software Inc
/* 3c527.c: 3Com Etherlink/MC32 driver for Linux 2.4 and 2.6.
*
* (c) Copyright 1998 Red Hat Software Inc
* Further debugging by Carl Drougge.
* Initial SMP support by Felipe W Damasio <felipewd@terra.com.br>
* Heavily modified by Richard Procter <rnp@paradise.net.nz>
* Further debugging by Carl Drougge.
* Initial SMP support by Felipe W Damasio <felipewd@terra.com.br>
* Heavily modified by Richard Procter <rnp@paradise.net.nz>
* The diagram (Figure 1-1) and the POS summary disagree with the
* "Interrupt Level" section in the manual.
*
* The diagram (Figure 1-1) and the POS summary disagree with the
* "Interrupt Level" section in the manual.
*
- * The manual contradicts itself when describing the minimum number
- * buffers in the 'configure lists' command.
- * My card accepts a buffer config of 4/4.
+ * The manual contradicts itself when describing the minimum number
+ * buffers in the 'configure lists' command.
+ * My card accepts a buffer config of 4/4.
*
* The documentation in places seems to miss things. In actual fact
* I've always eventually found everything is documented, it just
*
* The documentation in places seems to miss things. In actual fact
* I've always eventually found everything is documented, it just
* received frames exceeding a configurable length are passed
* directly to the higher networking layers without incuring a copy,
* in what amounts to a time/space trade-off.
* received frames exceeding a configurable length are passed
* directly to the higher networking layers without incuring a copy,
* in what amounts to a time/space trade-off.
* The card also keeps a large amount of statistical information
* on-board. In a perfect world, these could be used safely at no
* cost. However, lacking information to the contrary, processing
* them without races would involve so much extra complexity as to
* make it unworthwhile to do so. In the end, a hybrid SW/HW
* The card also keeps a large amount of statistical information
* on-board. In a perfect world, these could be used safely at no
* cost. However, lacking information to the contrary, processing
* them without races would involve so much extra complexity as to
* make it unworthwhile to do so. In the end, a hybrid SW/HW
* It should be possible to use two or more cards, but at this stage
* only by loading two copies of the same module.
*
* It should be possible to use two or more cards, but at this stage
* only by loading two copies of the same module.
*
-/* Copy break point, see above for details.
- * Setting to > 1512 effectively disables this feature. */
+/* Copy break point, see above for details.
+ * Setting to > 1512 effectively disables this feature. */
#define RX_COPYBREAK 200 /* Value from 3c59x.c */
/* Issue the 82586 workaround command - this is for "busy lans", but
#define RX_COPYBREAK 200 /* Value from 3c59x.c */
/* Issue the 82586 workaround command - this is for "busy lans", but
- * basically means for all lans now days - has a performance (latency)
- * cost, but best set. */
+ * basically means for all lans now days - has a performance (latency)
+ * cost, but best set. */
volatile struct mc32_stats *stats; /* Start of on-card statistics */
u16 tx_chain; /* Transmit list start offset */
u16 rx_chain; /* Receive list start offset */
volatile struct mc32_stats *stats; /* Start of on-card statistics */
u16 tx_chain; /* Transmit list start offset */
u16 rx_chain; /* Receive list start offset */
atomic_t tx_ring_head; /* index to tx en-queue end */
u16 tx_ring_tail; /* index to tx de-queue end */
atomic_t tx_ring_head; /* index to tx en-queue end */
u16 tx_ring_tail; /* index to tx de-queue end */
struct semaphore cmd_mutex; /* Serialises issuing of execute commands */
struct completion execution_cmd; /* Card has completed an execute command */
struct semaphore cmd_mutex; /* Serialises issuing of execute commands */
struct completion execution_cmd; /* Card has completed an execute command */
{ 0x0041, "3COM EtherLink MC/32" },
{ 0x8EF5, "IBM High Performance Lan Adapter" },
{ 0x0000, NULL }
};
{ 0x0041, "3COM EtherLink MC/32" },
{ 0x8EF5, "IBM High Performance Lan Adapter" },
{ 0x0000, NULL }
};
static inline u16 next_rx(u16 rx) { return (rx+1)&(RX_RING_LEN-1); };
static inline u16 prev_rx(u16 rx) { return (rx-1)&(RX_RING_LEN-1); };
static inline u16 next_rx(u16 rx) { return (rx+1)&(RX_RING_LEN-1); };
static inline u16 prev_rx(u16 rx) { return (rx-1)&(RX_RING_LEN-1); };
static int mc32_open(struct net_device *dev);
static void mc32_timeout(struct net_device *dev);
static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev);
static int mc32_open(struct net_device *dev);
static void mc32_timeout(struct net_device *dev);
static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev);
static int mc32_close(struct net_device *dev);
static struct net_device_stats *mc32_get_stats(struct net_device *dev);
static void mc32_set_multicast_list(struct net_device *dev);
static void mc32_reset_multicast_list(struct net_device *dev);
static int mc32_close(struct net_device *dev);
static struct net_device_stats *mc32_get_stats(struct net_device *dev);
static void mc32_set_multicast_list(struct net_device *dev);
static void mc32_reset_multicast_list(struct net_device *dev);
mca_find_unused_adapter(mc32_adapters[i].id, 0);
if(current_mca_slot != MCA_NOTFOUND) {
if(!mc32_probe1(dev, current_mca_slot))
{
mca_find_unused_adapter(mc32_adapters[i].id, 0);
if(current_mca_slot != MCA_NOTFOUND) {
if(!mc32_probe1(dev, current_mca_slot))
{
*
* Decode the slot data and configure the card structures. Having done this we
* can reset the card and configure it. The card does a full self test cycle
*
* Decode the slot data and configure the card structures. Having done this we
* can reset the card and configure it. The card does a full self test cycle
printk(KERN_INFO "%s: %s found in slot %d:", dev->name, cardname, slot);
POS = mca_read_stored_pos(slot, 2);
printk(KERN_INFO "%s: %s found in slot %d:", dev->name, cardname, slot);
POS = mca_read_stored_pos(slot, 2);
/* Fill in the 'dev' fields. */
dev->base_addr = mca_io_bases[(POS>>1)&7];
dev->mem_start = mca_mem_bases[(POS>>4)&7];
/* Fill in the 'dev' fields. */
dev->base_addr = mca_io_bases[(POS>>1)&7];
dev->mem_start = mca_mem_bases[(POS>>4)&7];
if(!request_region(dev->base_addr, MC32_IO_EXTENT, cardname))
{
printk("io 0x%3lX, which is busy.\n", dev->base_addr);
if(!request_region(dev->base_addr, MC32_IO_EXTENT, cardname))
{
printk("io 0x%3lX, which is busy.\n", dev->base_addr);
printk("io 0x%3lX irq %d mem 0x%lX (%dK)\n",
dev->base_addr, dev->irq, dev->mem_start, i/1024);
printk("io 0x%3lX irq %d mem 0x%lX (%dK)\n",
dev->base_addr, dev->irq, dev->mem_start, i/1024);
/* Retrieve and print the ethernet address. */
for (i = 0; i < 6; i++)
{
mca_write_pos(slot, 6, i+12);
mca_write_pos(slot, 7, 0);
/* Retrieve and print the ethernet address. */
for (i = 0; i < 6; i++)
{
mca_write_pos(slot, 6, i+12);
mca_write_pos(slot, 7, 0);
mca_write_pos(slot, 7, 0);
POS = mca_read_stored_pos(slot, 4);
mca_write_pos(slot, 7, 0);
POS = mca_read_stored_pos(slot, 4);
/* Reset off */
POS&=~(HOST_CTRL_ATTN|HOST_CTRL_RESET);
outb(POS, dev->base_addr+HOST_CTRL);
/* Reset off */
POS&=~(HOST_CTRL_ATTN|HOST_CTRL_RESET);
outb(POS, dev->base_addr+HOST_CTRL);
- err = request_irq(dev->irq, &mc32_interrupt, SA_SHIRQ | SA_SAMPLE_RANDOM, DRV_NAME, dev);
+ err = request_irq(dev->irq, &mc32_interrupt, IRQF_SHARED | IRQF_SAMPLE_RANDOM, DRV_NAME, dev);
if (err) {
release_region(dev->base_addr, MC32_IO_EXTENT);
printk(KERN_ERR "%s: unable to get IRQ %d.\n", DRV_NAME, dev->irq);
if (err) {
release_region(dev->base_addr, MC32_IO_EXTENT);
printk(KERN_ERR "%s: unable to get IRQ %d.\n", DRV_NAME, dev->irq);
base<0x0A?" test failure":"");
else
printk(KERN_ERR "%s: unknown failure %d.\n", dev->name, base);
base<0x0A?" test failure":"");
else
printk(KERN_ERR "%s: unknown failure %d.\n", dev->name, base);
lp->tx_chain = lp->exec_box->data[8]; /* Transmit list start offset */
lp->rx_chain = lp->exec_box->data[10]; /* Receive list start offset */
lp->tx_chain = lp->exec_box->data[8]; /* Transmit list start offset */
lp->rx_chain = lp->exec_box->data[10]; /* Receive list start offset */
lp->rx_len = lp->exec_box->data[11]; /* Receive list count */
init_MUTEX_LOCKED(&lp->cmd_mutex);
init_completion(&lp->execution_cmd);
init_completion(&lp->xceiver_cmd);
lp->rx_len = lp->exec_box->data[11]; /* Receive list count */
init_MUTEX_LOCKED(&lp->cmd_mutex);
init_completion(&lp->execution_cmd);
init_completion(&lp->xceiver_cmd);
printk("%s: Firmware Rev %d. %d RX buffers, %d TX buffers. Base of 0x%08X.\n",
dev->name, lp->exec_box->data[12], lp->rx_len, lp->tx_len, lp->base);
printk("%s: Firmware Rev %d. %d RX buffers, %d TX buffers. Base of 0x%08X.\n",
dev->name, lp->exec_box->data[12], lp->rx_len, lp->tx_len, lp->base);
* Wait until the card becomes ready to accept a command via the
* command register. This tells us nothing about the completion
* status of any pending commands and takes very little time at all.
*/
* Wait until the card becomes ready to accept a command via the
* command register. This tells us nothing about the completion
* status of any pending commands and takes very little time at all.
*/
*
* Sends exec commands in a user context. This permits us to wait around
* for the replies and also to wait for the command buffer to complete
*
* Sends exec commands in a user context. This permits us to wait around
* for the replies and also to wait for the command buffer to complete
* command completes we will attempt any pending multicast reload
* we blocked off by hogging the exec buffer.
*
* command completes we will attempt any pending multicast reload
* we blocked off by hogging the exec buffer.
*
* reply. All well and good. The complication arises because you use
* commands for filter list changes which come in at bh level from things
* like IPV6 group stuff.
*/
* reply. All well and good. The complication arises because you use
* commands for filter list changes which come in at bh level from things
* like IPV6 group stuff.
*/
static int mc32_command(struct net_device *dev, u16 cmd, void *data, int len)
{
struct mc32_local *lp = netdev_priv(dev);
int ioaddr = dev->base_addr;
int ret = 0;
static int mc32_command(struct net_device *dev, u16 cmd, void *data, int len)
{
struct mc32_local *lp = netdev_priv(dev);
int ioaddr = dev->base_addr;
int ret = 0;
outb(1<<6, ioaddr+HOST_CMD);
wait_for_completion(&lp->execution_cmd);
outb(1<<6, ioaddr+HOST_CMD);
wait_for_completion(&lp->execution_cmd);
* @dev: The 3c527 card to issue the command to
*
* This may be called from the interrupt state, where it is used
* @dev: The 3c527 card to issue the command to
*
* This may be called from the interrupt state, where it is used
- lp->rx_box->data[0]=lp->rx_ring[prev_rx(lp->rx_ring_tail)].p->next;
- outb(HOST_CMD_START_RX, ioaddr+HOST_CMD);
+ lp->rx_box->data[0]=lp->rx_ring[prev_rx(lp->rx_ring_tail)].p->next;
+ outb(HOST_CMD_START_RX, ioaddr+HOST_CMD);
- outb(HOST_CMD_RESTRT_TX, ioaddr+HOST_CMD); /* card ignores this on RX restart */
-
- /* We are not interrupted on start completion */
+ outb(HOST_CMD_RESTRT_TX, ioaddr+HOST_CMD); /* card ignores this on RX restart */
+
+ /* We are not interrupted on start completion */
* We then set the end-of-list bit for the last entry so that the
* card will know when it has run out of buffers.
*/
* We then set the end-of-list bit for the last entry so that the
* card will know when it has run out of buffers.
*/
static int mc32_load_rx_ring(struct net_device *dev)
{
struct mc32_local *lp = netdev_priv(dev);
int i;
u16 rx_base;
volatile struct skb_header *p;
static int mc32_load_rx_ring(struct net_device *dev)
{
struct mc32_local *lp = netdev_priv(dev);
int i;
u16 rx_base;
volatile struct skb_header *p;
skb_reserve(lp->rx_ring[i].skb, 18);
p=isa_bus_to_virt(lp->base+rx_base);
skb_reserve(lp->rx_ring[i].skb, 18);
p=isa_bus_to_virt(lp->base+rx_base);
/**
* mc32_flush_rx_ring - free the ring of receive buffers
* @lp: Local data of 3c527 to flush the rx ring of
*
/**
* mc32_flush_rx_ring - free the ring of receive buffers
* @lp: Local data of 3c527 to flush the rx ring of
*
* before mc32_load_rx_ring(), eg. on error in mc32_open().
* Requires rx skb pointers to point to a valid skb, or NULL.
*/
* before mc32_load_rx_ring(), eg. on error in mc32_open().
* Requires rx skb pointers to point to a valid skb, or NULL.
*/
if (lp->rx_ring[i].skb) {
dev_kfree_skb(lp->rx_ring[i].skb);
lp->rx_ring[i].skb = NULL;
}
if (lp->rx_ring[i].skb) {
dev_kfree_skb(lp->rx_ring[i].skb);
lp->rx_ring[i].skb = NULL;
}
*
* First, we obtain from the card it's current postion in the tx
* ring, so that we will know where to begin transmitting
* packets.
*
* First, we obtain from the card it's current postion in the tx
* ring, so that we will know where to begin transmitting
* packets.
* Then, we read the 'next' pointers from the on-card tx ring into
* our tx_ring array to reduce slow shared-mem reads. Finally, we
* intitalise the tx house keeping variables.
* Then, we read the 'next' pointers from the on-card tx ring into
* our tx_ring array to reduce slow shared-mem reads. Finally, we
* intitalise the tx house keeping variables.
- atomic_set(&lp->tx_count, TX_RING_LEN-1);
- atomic_set(&lp->tx_ring_head, 0);
- lp->tx_ring_tail=0;
-}
+ atomic_set(&lp->tx_count, TX_RING_LEN-1);
+ atomic_set(&lp->tx_ring_head, 0);
+ lp->tx_ring_tail=0;
+}
- atomic_set(&lp->tx_count, 0);
- atomic_set(&lp->tx_ring_head, 0);
+ atomic_set(&lp->tx_count, 0);
+ atomic_set(&lp->tx_ring_head, 0);
regs=inb(ioaddr+HOST_CTRL);
regs|=HOST_CTRL_INTE;
outb(regs, ioaddr+HOST_CTRL);
regs=inb(ioaddr+HOST_CTRL);
regs|=HOST_CTRL_INTE;
outb(regs, ioaddr+HOST_CTRL);
mc32_command(dev, 4, &one, 2);
/*
mc32_command(dev, 4, &one, 2);
/*
- if(mc32_command(dev, 8, descnumbuffs, 4)) {
+ if(mc32_command(dev, 8, descnumbuffs, 4)) {
-
- /* Report new configuration */
- mc32_command(dev, 6, NULL, 0);
+
+ /* Report new configuration */
+ mc32_command(dev, 6, NULL, 0);
lp->tx_chain = lp->exec_box->data[8]; /* Transmit list start offset */
lp->rx_chain = lp->exec_box->data[10]; /* Receive list start offset */
lp->tx_chain = lp->exec_box->data[8]; /* Transmit list start offset */
lp->rx_chain = lp->exec_box->data[10]; /* Receive list start offset */
/* Set Network Address */
mc32_command(dev, 1, dev->dev_addr, 6);
/* Set Network Address */
mc32_command(dev, 1, dev->dev_addr, 6);
u16 zero_word=0;
mc32_command(dev, 0x0D, &zero_word, 2); /* 82586 bug workaround on */
}
mc32_load_tx_ring(dev);
u16 zero_word=0;
mc32_command(dev, 0x0D, &zero_word, 2); /* 82586 bug workaround on */
}
mc32_load_tx_ring(dev);
/* And finally, set the ball rolling... */
mc32_start_transceiver(dev);
/* And finally, set the ball rolling... */
mc32_start_transceiver(dev);
* after we've established a valid packet on the tx ring (and
* before we let the card "see" it, to prevent it racing with the
* irq handler).
* after we've established a valid packet on the tx ring (and
* before we let the card "see" it, to prevent it racing with the
* irq handler).
*/
static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev)
{
struct mc32_local *lp = netdev_priv(dev);
u32 head = atomic_read(&lp->tx_ring_head);
*/
static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev)
{
struct mc32_local *lp = netdev_priv(dev);
u32 head = atomic_read(&lp->tx_ring_head);
* Query and reset the on-card stats. There's the small possibility
* of a race here, which would result in an underestimation of
* actual errors. As such, we'd prefer to keep all our stats
* collection in software. As a rule, we do. However it can't be
* used for rx errors and collisions as, by default, the card discards
* Query and reset the on-card stats. There's the small possibility
* of a race here, which would result in an underestimation of
* actual errors. As such, we'd prefer to keep all our stats
* collection in software. As a rule, we do. However it can't be
* used for rx errors and collisions as, by default, the card discards
*
* Setting the SAV BP in the rx filter command supposedly
* stops this behaviour. However, testing shows that it only seems to
*
* Setting the SAV BP in the rx filter command supposedly
* stops this behaviour. However, testing shows that it only seems to
- rx_errors+=lp->net_stats.rx_fifo_errors +=st->rx_overrun_errors;
- st->rx_overrun_errors=0;
- rx_errors+=lp->net_stats.rx_frame_errors +=st->rx_alignment_errors;
+ rx_errors+=lp->net_stats.rx_fifo_errors +=st->rx_overrun_errors;
+ st->rx_overrun_errors=0;
+ rx_errors+=lp->net_stats.rx_frame_errors +=st->rx_alignment_errors;
* For each completed packet, we will either copy it and pass it up
* the stack or, if the packet is near MTU sized, we allocate
* another buffer and flip the old one up the stack.
* For each completed packet, we will either copy it and pass it up
* the stack or, if the packet is near MTU sized, we allocate
* another buffer and flip the old one up the stack.
* We must succeed in keeping a buffer on the ring. If necessary we
* will toss a received packet rather than lose a ring entry. Once
* the first uncompleted descriptor is found, we move the
* We must succeed in keeping a buffer on the ring. If necessary we
* will toss a received packet rather than lose a ring entry. Once
* the first uncompleted descriptor is found, we move the
-
- skb_reserve(newskb,18);
- lp->rx_ring[rx_ring_tail].skb=newskb;
- p->data=isa_virt_to_bus(newskb->data);
- }
- else
+
+ skb_reserve(newskb,18);
+ lp->rx_ring[rx_ring_tail].skb=newskb;
+ p->data=isa_virt_to_bus(newskb->data);
+ }
+ else
}
skb_reserve(skb,2);
memcpy(skb_put(skb, length),
lp->rx_ring[rx_ring_tail].skb->data, length);
}
}
skb_reserve(skb,2);
memcpy(skb_put(skb, length),
lp->rx_ring[rx_ring_tail].skb->data, length);
}
- /* If there was actually a frame to be processed, place the EOL bit */
- /* at the descriptor prior to the one to be filled next */
+ /* If there was actually a frame to be processed, place the EOL bit */
+ /* at the descriptor prior to the one to be filled next */
- if (rx_ring_tail != rx_old_tail)
- {
- lp->rx_ring[prev_rx(rx_ring_tail)].p->control |= CONTROL_EOL;
- lp->rx_ring[prev_rx(rx_old_tail)].p->control &= ~CONTROL_EOL;
+ if (rx_ring_tail != rx_old_tail)
+ {
+ lp->rx_ring[prev_rx(rx_ring_tail)].p->control |= CONTROL_EOL;
+ lp->rx_ring[prev_rx(rx_old_tail)].p->control &= ~CONTROL_EOL;
* any errors. This continues until the transmit ring is emptied
* or we reach a descriptor that hasn't yet been processed by the
* card.
* any errors. This continues until the transmit ring is emptied
* or we reach a descriptor that hasn't yet been processed by the
* card.
{
struct net_device *dev = dev_id;
struct mc32_local *lp;
int ioaddr, status, boguscount = 0;
int rx_event = 0;
{
struct net_device *dev = dev_id;
struct mc32_local *lp;
int ioaddr, status, boguscount = 0;
int rx_event = 0;
printk("Status TX%d RX%d EX%d OV%d BC%d\n",
(status&7), (status>>3)&7, (status>>6)&1,
(status>>7)&1, boguscount);
#endif
printk("Status TX%d RX%d EX%d OV%d BC%d\n",
(status&7), (status>>3)&7, (status>>6)&1,
(status>>7)&1, boguscount);
#endif
* driver. Otherwise, it is possible that the card may run out
* of receive buffers and restart the transceiver while we're
* trying to close it.
* driver. Otherwise, it is possible that the card may run out
* of receive buffers and restart the transceiver while we're
* trying to close it.
* We abort any receive and transmits going on and then wait until
* any pending exec commands have completed in other code threads.
* In theory we can't get here while that is true, in practice I am
* We abort any receive and transmits going on and then wait until
* any pending exec commands have completed in other code threads.
* In theory we can't get here while that is true, in practice I am
regs=inb(ioaddr+HOST_CTRL);
regs&=~HOST_CTRL_INTE;
outb(regs, ioaddr+HOST_CTRL);
mc32_flush_rx_ring(dev);
mc32_flush_tx_ring(dev);
regs=inb(ioaddr+HOST_CTRL);
regs&=~HOST_CTRL_INTE;
outb(regs, ioaddr+HOST_CTRL);
mc32_flush_rx_ring(dev);
mc32_flush_tx_ring(dev);
*/
static struct net_device_stats *mc32_get_stats(struct net_device *dev)
{
struct mc32_local *lp = netdev_priv(dev);
*/
static struct net_device_stats *mc32_get_stats(struct net_device *dev)
{
struct mc32_local *lp = netdev_priv(dev);
* state as it may take multiple calls to get the command sequence
* completed. We just keep trying to schedule the loads until we
* manage to process them all.
* state as it may take multiple calls to get the command sequence
* completed. We just keep trying to schedule the loads until we
* manage to process them all.
- * See mc32_update_stats() regards setting the SAV BP bit.
+ * num_addrs > 0 Multicast mode, receive normal and MC packets,
+ * and do best-effort filtering.
+ *
+ * See mc32_update_stats() regards setting the SAV BP bit.
*
*/
static void do_mc32_set_multicast_list(struct net_device *dev, int retry)
{
struct mc32_local *lp = netdev_priv(dev);
*
*/
static void do_mc32_set_multicast_list(struct net_device *dev, int retry)
{
struct mc32_local *lp = netdev_priv(dev);
for(i=0;i<dev->mc_count;i++)
{
memcpy(bp, dmc->dmi_addr, 6);
for(i=0;i<dev->mc_count;i++)
{
memcpy(bp, dmc->dmi_addr, 6);
-
- if(mc32_command_nowait(dev, 0, &filt, 2)==-1)
+
+ if(mc32_command_nowait(dev, 0, &filt, 2)==-1)
.get_drvinfo = netdev_get_drvinfo,
.get_msglevel = netdev_get_msglevel,
.set_msglevel = netdev_set_msglevel,
.get_drvinfo = netdev_get_drvinfo,
.get_msglevel = netdev_get_msglevel,
.set_msglevel = netdev_set_msglevel,