📄 3c527.c
字号:
}/** * mc32_update_stats: * @dev: 3c527 to service * * When the board signals us that its statistics need attention we * should query the table and clear it. In actual fact we currently * track all our statistics in software and I haven't implemented it yet. */ static void mc32_update_stats(struct net_device *dev){}/** * mc32_rx_ring: * @dev: 3c527 that needs its receive ring processing * * We have received one or more indications from the card that * a receive has completed. The ring buffer thus contains dirty * entries. Firstly we tell the card to stop receiving, then We walk * the ring from the first filled entry, which is pointed to by the * card rx mailbox and 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 neccessary we * will toss a received packet rather than lose a ring entry. Once the * first packet that is unused is found we reload the mailbox with the * buffer so that the card knows it can use the buffers again. Finally * we set it receiving again. * * We must stop reception during the ring walk. I thought it would be * neat to avoid it by clever tricks, but it turns out the event order * on the card means you have to play by the manual. */ static void mc32_rx_ring(struct net_device *dev){ struct mc32_local *lp=dev->priv; int ioaddr = dev->base_addr; int x=0; volatile struct skb_header *p; u16 base; u16 top; /* Halt RX before walking the ring */ while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); outb(3<<3, ioaddr+HOST_CMD); while(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR); top = base = lp->rx_box->data[0]; do { p=(struct skb_header *)bus_to_virt(base+lp->base); if(!(p->status & (1<<7))) break; if(p->status & (1<<6)) { u16 length = p->length; struct sk_buff *skb=dev_alloc_skb(length+2); if(skb!=NULL) { skb_reserve(skb,2); /*printk("Frame at %p\n", bus_to_virt(p->data)); */ memcpy(skb_put(skb, length), bus_to_virt(p->data), length); skb->protocol=eth_type_trans(skb,dev); skb->dev=dev; lp->net_stats.rx_packets++; lp->net_stats.rx_bytes+=skb->len; netif_rx(skb); } else lp->net_stats.rx_dropped++; } else { lp->net_stats.rx_errors++; switch(p->status&0x0F) { case 1: lp->net_stats.rx_crc_errors++;break; case 2: lp->net_stats.rx_fifo_errors++;break; case 3: lp->net_stats.rx_frame_errors++;break; case 4: lp->net_stats.rx_missed_errors++;break; case 5: lp->net_stats.rx_length_errors++;break; } } p->length = 1532; p->control &= ~(1<<6); p->status = 0; base = p->next; } while(x++<48); /* * Restart ring processing */ while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); lp->rx_box->mbox=0; lp->rx_box->data[0] = top; outb(1<<3, ioaddr+HOST_CMD); lp->rx_halted=0;}/** * mc32_interrupt: * @irq: Interrupt number * @dev_id: 3c527 that requires servicing * @regs: Registers (unused) * * The 3c527 interrupts us for four reasons. The command register * contains the message it wishes to send us packed into a single * byte field. We keep reading status entries until we have processed * all the transmit and control items, but simply count receive * reports. When the receive reports are in we can call the mc32_rx_ring * and empty the ring. This saves the overhead of multiple command requests */ static void mc32_interrupt(int irq, void *dev_id, struct pt_regs * regs){ struct net_device *dev = dev_id; struct mc32_local *lp; int ioaddr, status, boguscount = 0; if (dev == NULL) { printk(KERN_WARNING "%s: irq %d for unknown device.\n", cardname, irq); return; } ioaddr = dev->base_addr; lp = (struct mc32_local *)dev->priv; /* See whats cooking */ while((inb(ioaddr+2)&(1<<5)) && boguscount++<2000) { status=inb(ioaddr+HOST_CMD);#ifdef DEBUG_IRQ printk("Status TX%d RX%d EX%d OV%d\n", (status&7), (status>>3)&7, (status>>6)&1, (status>>7)&1);#endif switch(status&7) { case 0: break; case 6: /* TX fail */ lp->net_stats.tx_errors++; case 2: /* TX ok */ lp->net_stats.tx_packets++; /* Packets are sent in order - this is basically a FIFO queue of buffers matching the card ring */ lp->net_stats.tx_bytes+=lp->tx_skb[lp->tx_skb_top]->len; dev_kfree_skb_irq(lp->tx_skb[lp->tx_skb_top]); lp->tx_skb[lp->tx_skb_top]=NULL; lp->tx_skb_top++; lp->tx_skb_top&=(TX_RING_MAX-1); atomic_inc(&lp->tx_count); netif_wake_queue(dev); break; case 3: /* Halt */ case 4: /* Abort */ lp->tx_halted=1; wake_up(&lp->event); break; case 5: lp->tx_halted=0; wake_up(&lp->event); break; default: printk("%s: strange tx ack %d\n", dev->name, status&7); } status>>=3; switch(status&7) { case 0: break; case 2: /* RX */ lp->rx_pending=1; if(!lp->rx_halted) { /* * Halt ring receive */ while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); outb(3<<3, ioaddr+HOST_CMD); } break; case 3: case 4: lp->rx_halted=1; wake_up(&lp->event); break; case 5: lp->rx_halted=0; wake_up(&lp->event); break; case 6: /* Out of RX buffers stat */ lp->net_stats.rx_dropped++; lp->rx_pending=1; /* Must restart */ lp->rx_halted=1; break; default: printk("%s: strange rx ack %d\n", dev->name, status&7); } status>>=3; if(status&1) { /* 0=no 1=yes 2=replied, get cmd, 3 = wait reply & dump it */ if(lp->exec_pending!=3) lp->exec_pending=2; else lp->exec_pending=0; wake_up(&lp->event); } if(status&2) { /* * Update the stats as soon as * we have it flagged and can * send an immediate reply (CRR set) */ if(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR) { mc32_update_stats(dev); outb(0, ioaddr+HOST_CMD); } } } /* * Process and restart the receive ring. This has some state * as we must halt the ring to process it and halting the ring * might not occur in the same IRQ handling loop as we issue * the halt. */ if(lp->rx_pending && lp->rx_halted) { mc32_rx_ring(dev); lp->rx_pending = 0; } return;}/** * mc32_close: * @dev: 3c527 card to shut down * * The 3c527 is a bus mastering device. We must be careful how we * shut it down. It may also be running shared interrupt so we have * to be sure to silence it properly * * 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 * paranoid * * We turn off the interrupt enable for the board to be sure it can't * intefere with other devices. */ static int mc32_close(struct net_device *dev){ struct mc32_local *lp = (struct mc32_local *)dev->priv; int ioaddr = dev->base_addr; u8 regs; u16 one=1; netif_stop_queue(dev); /* * Send the indications on command (handy debug check) */ mc32_command(dev, 4, &one, 2); /* Abort RX and Abort TX */ mc32_rx_abort(dev); mc32_tx_abort(dev); /* Catch any waiting commands */ while(lp->exec_pending==1) sleep_on(&lp->event); /* Ok the card is now stopping */ regs=inb(ioaddr+HOST_CTRL); regs&=~HOST_CTRL_INTE; outb(regs, ioaddr+HOST_CTRL); mc32_flush_rx_ring(lp); mc32_flush_tx_ring(lp); /* Update the statistics here. */ return 0;}/** * mc32_get_stats: * @dev: The 3c527 card to handle * * As we currently handle our statistics in software this one is * easy to handle. With hardware statistics it will get messy * as the get_stats call will need to send exec mailbox messages and * need to lock out the multicast reloads. */static struct net_device_stats *mc32_get_stats(struct net_device *dev){ struct mc32_local *lp = (struct mc32_local *)dev->priv; return &lp->net_stats;}/** * do_mc32_set_multicast_list: * @dev: 3c527 device to load the list on * @retry: indicates this is not the first call. * * Actually set or clear the multicast filter for this adaptor. The locking * issues are handled by this routine. We have to track 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. * * num_addrs == -1 Promiscuous mode, receive all packets * * num_addrs == 0 Normal mode, clear multicast list * * num_addrs > 0 Multicast mode, receive normal and MC packets, * and do best-effort filtering. */static void do_mc32_set_multicast_list(struct net_device *dev, int retry){ struct mc32_local *lp = (struct mc32_local *)dev->priv; u16 filt; if (dev->flags&IFF_PROMISC) /* Enable promiscuous mode */ filt = 1; else if((dev->flags&IFF_ALLMULTI) || dev->mc_count > 10) { dev->flags|=IFF_PROMISC; filt = 1; } else if(dev->mc_count) { unsigned char block[62]; unsigned char *bp; struct dev_mc_list *dmc=dev->mc_list; int i; filt = 0; if(retry==0) lp->mc_list_valid = 0; if(!lp->mc_list_valid) { block[1]=0; block[0]=dev->mc_count; bp=block+2; for(i=0;i<dev->mc_count;i++) { memcpy(bp, dmc->dmi_addr, 6); bp+=6; dmc=dmc->next; } if(mc32_command_nowait(dev, 2, block, 2+6*dev->mc_count)==-1) { lp->mc_reload_wait = 1; return; } lp->mc_list_valid=1; } } else { filt = 0; } if(mc32_command_nowait(dev, 0, &filt, 2)==-1) { lp->mc_reload_wait = 1; }}/** * mc32_set_multicast_list: * @dev: The 3c527 to use * * Commence loading the multicast list. This is called when the kernel * changes the lists. It will override any pending list we are trying to * load. */ static void mc32_set_multicast_list(struct net_device *dev){ do_mc32_set_multicast_list(dev,0);}/** * mc32_reset_multicast_list: * @dev: The 3c527 to use * * Attempt the next step in loading the multicast lists. If this attempt * fails to complete then it will be scheduled and this function called * again later from elsewhere. */ static void mc32_reset_multicast_list(struct net_device *dev){ do_mc32_set_multicast_list(dev,1);}#ifdef MODULEstatic struct net_device this_device;/** * init_module: * * Probe and locate a 3c527 card. This really should probe and locate * all the 3c527 cards in the machine not just one of them. Yes you can * insmod multiple modules for now but its a hack. */ int init_module(void){ int result; this_device.init = mc32_probe; if ((result = register_netdev(&this_device)) != 0) return result; return 0;}/** * cleanup_module: * * Unloading time. We release the MCA bus resources and the interrupt * at which point everything is ready to unload. The card must be stopped * at this point or we would not have been called. When we unload we * leave the card stopped but not totally shut down. When the card is * initialized it must be rebooted or the rings reloaded before any * transmit operations are allowed to start scribbling into memory. */ void cleanup_module(void){ int slot; /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ unregister_netdev(&this_device); /* * If we don't do this, we can't re-insmod it later. */ if (this_device.priv) { struct mc32_local *lp=this_device.priv; slot = lp->slot; mca_mark_as_unused(slot); mca_set_adapter_name(slot, NULL); kfree(this_device.priv); } free_irq(this_device.irq, &this_device);}#endif /* MODULE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -