📄 3c527.c
字号:
/* Try to save time by avoiding a copy on big frames */ if ((length > RX_COPYBREAK) && ((newskb=dev_alloc_skb(1532)) != NULL)) { skb=lp->rx_ring[rx_ring_tail].skb; skb_put(skb, length); skb_reserve(newskb,18); lp->rx_ring[rx_ring_tail].skb=newskb; p->data=virt_to_bus(newskb->data); } else { skb=dev_alloc_skb(length+2); if(skb==NULL) { lp->net_stats.rx_dropped++; goto dropped; } skb_reserve(skb,2); memcpy(skb_put(skb, length), lp->rx_ring[rx_ring_tail].skb->data, length); } skb->protocol=eth_type_trans(skb,dev); skb->dev=dev; dev->last_rx = jiffies; lp->net_stats.rx_packets++; lp->net_stats.rx_bytes += length; netif_rx(skb); } dropped: p->length = 1532; p->status = 0; rx_ring_tail=next_rx(rx_ring_tail); } while(x++<48); /* 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; lp->rx_ring_tail=rx_ring_tail; }}/** * mc32_tx_ring - process completed transmits * @dev: 3c527 that needs its transmit ring processing * * * This operates in a similar fashion to mc32_rx_ring. We iterate * over the transmit ring. For each descriptor which has been * processed by the card, we free its associated buffer and note * any errors. This continues until the transmit ring is emptied * or we reach a descriptor that hasn't yet been processed by the * card. * */static void mc32_tx_ring(struct net_device *dev) { struct mc32_local *lp=(struct mc32_local *)dev->priv; volatile struct skb_header *np; /* NB: lp->tx_count=TX_RING_LEN-1 so that tx_ring_head cannot "lap" tail here */ while (lp->tx_ring_tail != lp->tx_ring_head) { u16 t; t=next_tx(lp->tx_ring_tail); np=lp->tx_ring[t].p; if(!(np->status & (1<<7))) { /* Not COMPLETED */ break; } lp->net_stats.tx_packets++; if(!(np->status & (1<<6))) /* Not COMPLETED_OK */ { lp->net_stats.tx_errors++; switch(np->status&0x0F) { case 1: lp->net_stats.tx_aborted_errors++; break; /* Max collisions */ case 2: lp->net_stats.tx_fifo_errors++; break; case 3: lp->net_stats.tx_carrier_errors++; break; case 4: lp->net_stats.tx_window_errors++; break; /* CTS Lost */ case 5: lp->net_stats.tx_aborted_errors++; break; /* Transmit timeout */ } } /* Packets are sent in order - this is basically a FIFO queue of buffers matching the card ring */ lp->net_stats.tx_bytes+=lp->tx_ring[t].skb->len; dev_kfree_skb_irq(lp->tx_ring[t].skb); lp->tx_ring[t].skb=NULL; atomic_inc(&lp->tx_count); netif_wake_queue(dev); lp->tx_ring_tail=t; }} /** * mc32_interrupt - handle an interrupt from a 3c527 * @irq: Interrupt number * @dev_id: 3c527 that requires servicing * @regs: Registers (unused) * * * An interrupt is raised whenever the 3c527 writes to the command * register. This 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 control items, but simply count * transmit and receive reports. When all reports are in we empty the * transceiver rings as appropriate. This saves the overhead of * multiple command requests. * * Because MCA is level-triggered, we shouldn't miss indications. * Therefore, we needn't ask the card to suspend interrupts within * this handler. The card receives an implicit acknowledgment of the * current interrupt when we read the command register. * */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; int rx_event = 0; int tx_event = 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+HOST_STATUS)&HOST_STATUS_CWR) && boguscount++<2000) { status=inb(ioaddr+HOST_CMD);#ifdef DEBUG_IRQ 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 switch(status&7) { case 0: break; case 6: /* TX fail */ case 2: /* TX ok */ tx_event = 1; break; case 3: /* Halt */ case 4: /* Abort */ lp->xceiver_state |= TX_HALTED; 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 */ rx_event=1; break; case 3: /* Halt */ case 4: /* Abort */ lp->xceiver_state |= RX_HALTED; wake_up(&lp->event); break; case 6: /* Out of RX buffers stat */ /* Must restart rx */ lp->net_stats.rx_dropped++; mc32_rx_ring(dev); mc32_start_transceiver(dev); 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; wake_up(&lp->event); } else { lp->exec_pending=0; /* A new multicast set may have been blocked while the old one was running. If so, do it now. */ if (lp->mc_reload_wait) mc32_reset_multicast_list(dev); else wake_up(&lp->event); } } if(status&2) { /* * We get interrupted once per * counter that is about to overflow. */ mc32_update_stats(dev); } } /* * Process the transmit and receive rings */ if(tx_event) mc32_tx_ring(dev); if(rx_event) mc32_rx_ring(dev); return;}/** * mc32_close - user configuring the 3c527 down * @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 indicate that the card is closing to the rest of the * 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 * 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; lp->desired_state = HALTED; netif_stop_queue(dev); /* * Send the indications on command (handy debug check) */ mc32_command(dev, 4, &one, 2); /* Shut down the transceiver */ mc32_halt_transceiver(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(dev); mc32_flush_tx_ring(dev); mc32_update_stats(dev); return 0;}/** * mc32_get_stats - hand back stats to network layer * @dev: The 3c527 card to handle * * We've collected all the stats we can in software already. Now * it's time to update those kept on-card and return the lot. * */static struct net_device_stats *mc32_get_stats(struct net_device *dev){ struct mc32_local *lp; mc32_update_stats(dev); lp = (struct mc32_local *)dev->priv; return &lp->net_stats;}/** * do_mc32_set_multicast_list - attempt to update multicasts * @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. * * 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 = (struct mc32_local *)dev->priv; u16 filt = (1<<2); /* Save Bad Packets, for stats purposes */ 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; 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; } } if(mc32_command_nowait(dev, 0, &filt, 2)==-1) { lp->mc_reload_wait = 1; } else { lp->mc_reload_wait = 0; }}/** * mc32_set_multicast_list - queue multicast list update * @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 - 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);}/** * netdev_ethtool_ioctl: Handle network interface SIOCETHTOOL ioctls * @dev: network interface on which out-of-band action is to be performed * @useraddr: userspace address to which data is to be read and returned * * Process the various commands of the SIOCETHTOOL interface. */static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr){ u32 ethcmd; /* dev_ioctl() in ../../net/core/dev.c has already checked capable(CAP_NET_ADMIN), so don't bother with that here. */ if (get_user(ethcmd, (u32 *)useraddr)) return -EFAULT; switch (ethcmd) { case ETHTOOL_GDRVINFO: { struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; strcpy (info.driver, DRV_NAME); strcpy (info.version, DRV_VERSION); sprintf(info.bus_info, "MCA 0x%lx", dev->base_addr); if (copy_to_user (useraddr, &info, sizeof (info))) return -EFAULT; return 0; } /* get message-level */ case ETHTOOL_GMSGLVL: { struct ethtool_value edata = {ETHTOOL_GMSGLVL}; edata.data = mc32_debug; if (copy_to_user(useraddr, &edata, sizeof(edata))) return -EFAULT; return 0; } /* set message-level */ case ETHTOOL_SMSGLVL: { struct ethtool_value edata; if (copy_from_user(&edata, useraddr, sizeof(edata))) return -EFAULT; mc32_debug = edata.data; return 0; } default: break; } return -EOPNOTSUPP;}/** * netdev_ioctl: Handle network interface ioctls * @dev: network interface on which out-of-band action is to be performed * @rq: user request data * @cmd: command issued by user * * Process the various out-of-band ioctls passed to this driver. */static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd){ int rc = 0; switch (cmd) { case SIOCETHTOOL: rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); break; default: rc = -EOPNOTSUPP; break; } return rc;} #ifdef MODULEstatic struct net_device this_device;/** * init_module - entry point * * 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 it's 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 - free resources for an unload * * 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); release_region(this_device.base_addr, MC32_IO_EXTENT);}#endif /* MODULE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -