📄 acenic.c
字号:
#if (BITS_PER_LONG == 64) writel(0, &ap->tx_ring[idx].addr.addrhi);#endif writel(0, &ap->tx_ring[idx].addr.addrlo); writel(0, &ap->tx_ring[idx].flagsize); idx = (idx + 1) % TX_RING_ENTRIES; } while (idx != txcsm); if (ap->tx_full && dev->tbusy && (((ap->tx_prd + 1) % TX_RING_ENTRIES) != txcsm)){ ap->tx_full = 0; dev->tbusy = 0; mark_bh(NET_BH); /* * TX ring is no longer full, aka the * transmitter is working fine - kill timer. */ del_timer(&ap->timer); } ap->tx_ret_csm = txcsm; } evtcsm = readl(®s->EvtCsm); evtprd = ap->evt_prd; if (evtcsm != evtprd){ evtcsm = ace_handle_event(dev, evtcsm, evtprd); } writel(evtcsm, ®s->EvtCsm); writel(0, ®s->Mb0Lo); spin_unlock(&ap->lock);}static int ace_open(struct device *dev){ struct ace_private *ap; struct ace_regs *regs; struct cmd cmd; ap = dev->priv; regs = ap->regs; if (!(ap->fw_running)){ printk(KERN_WARNING "%s: firmware not running!\n", dev->name); return -EBUSY; } writel(dev->mtu + ETH_HLEN + 4, ®s->IfMtu); cmd.evt = C_HOST_STATE; cmd.code = C_C_STACK_UP; cmd.idx = 0; ace_issue_cmd(regs, &cmd); if (ap->jumbo) ace_load_jumbo_rx_ring(dev); if (dev->flags & IFF_PROMISC){ cmd.evt = C_SET_PROMISC_MODE; cmd.code = C_C_PROMISC_ENABLE; cmd.idx = 0; ace_issue_cmd(regs, &cmd); ap->promisc = 1; }else ap->promisc = 0; ap->mcast_all = 0;#if 0 { long myjif = jiffies + HZ; while (time_before(jiffies, myjif)); } cmd.evt = C_LNK_NEGOTIATION; cmd.code = 0; cmd.idx = 0; ace_issue_cmd(regs, &cmd);#endif dev->tbusy = 0; dev->interrupt = 0; dev->start = 1; MOD_INC_USE_COUNT; /* * Setup the timer */ init_timer(&ap->timer); ap->timer.data = (unsigned long)dev; ap->timer.function = ace_timer; return 0;}static int ace_close(struct device *dev){ struct ace_private *ap; struct ace_regs *regs; struct cmd cmd; unsigned long flags; short i; dev->start = 0; set_bit(0, (void*)&dev->tbusy); ap = (struct ace_private *)dev->priv; regs = ap->regs; del_timer(&ap->timer); if (ap->promisc){ cmd.evt = C_SET_PROMISC_MODE; cmd.code = C_C_PROMISC_DISABLE; cmd.idx = 0; ace_issue_cmd(regs, &cmd); ap->promisc = 0; } cmd.evt = C_HOST_STATE; cmd.code = C_C_STACK_DOWN; cmd.idx = 0; ace_issue_cmd(regs, &cmd); spin_lock_irqsave(&ap->lock, flags); for (i = 0; i < TX_RING_ENTRIES; i++) { if (ap->tx_skbuff[i]) { writel(0, &ap->tx_ring[i].addr.addrhi); writel(0, &ap->tx_ring[i].addr.addrlo); writel(0, &ap->tx_ring[i].flagsize); dev_kfree_skb(ap->tx_skbuff[i]); } } if (ap->jumbo) ace_flush_jumbo_rx_ring(dev); spin_unlock_irqrestore(&ap->lock, flags); MOD_DEC_USE_COUNT; return 0;}static int ace_start_xmit(struct sk_buff *skb, struct device *dev){ struct ace_private *ap = (struct ace_private *)dev->priv; struct ace_regs *regs = ap->regs; unsigned long flags; unsigned long addr; u32 idx, flagsize; spin_lock_irqsave(&ap->lock, flags); idx = ap->tx_prd; ap->tx_skbuff[idx] = skb; addr = virt_to_bus(skb->data);#if (BITS_PER_LONG == 64) writel(addr >> 32, &ap->tx_ring[idx].addr.addrhi);#endif writel(addr & 0xffffffff, &ap->tx_ring[idx].addr.addrlo); flagsize = (skb->len << 16) | (DESC_END) ; writel(flagsize, &ap->tx_ring[idx].flagsize); mb(); idx = (idx + 1) % TX_RING_ENTRIES; ap->tx_prd = idx; writel(idx, ®s->TxPrd); if ((idx + 1) % TX_RING_ENTRIES == ap->tx_ret_csm){ ap->tx_full = 1; set_bit(0, (void*)&dev->tbusy); /* * Queue is full, add timer to detect whether the * transmitter is stuck. Use mod_timer as we can get * into the situation where we risk adding several * timers. */ mod_timer(&ap->timer, jiffies + (3 * HZ)); } spin_unlock_irqrestore(&ap->lock, flags); dev->trans_start = jiffies; return 0;}static int ace_change_mtu(struct device *dev, int new_mtu){ struct ace_private *ap = dev->priv; struct ace_regs *regs = ap->regs; if ((new_mtu < 68) || (new_mtu > ACE_JUMBO_MTU)) return -EINVAL; writel(new_mtu + ETH_HLEN + 4, ®s->IfMtu); dev->mtu = new_mtu; if (new_mtu > ACE_STD_MTU){ if (!(ap->jumbo)){ printk(KERN_INFO "%s: Enabling Jumbo frame " "support\n", dev->name); ap->jumbo = 1; ace_load_jumbo_rx_ring(dev); } ap->jumbo = 1; }else{ if (ap->jumbo){ ace_flush_jumbo_rx_ring(dev); printk(KERN_INFO "%s: Disabling Jumbo frame support\n", dev->name); } ap->jumbo = 0; } return 0;}/* * Set the hardware MAC address. */static int ace_set_mac_addr(struct device *dev, void *p){ struct sockaddr *addr=p; struct ace_regs *regs; u16 *da; struct cmd cmd; if(dev->start) return -EBUSY; memcpy(dev->dev_addr, addr->sa_data,dev->addr_len); da = (u16 *)dev->dev_addr; regs = ((struct ace_private *)dev->priv)->regs; writel(da[0], ®s->MacAddrHi); writel((da[1] << 16) | da[2], ®s->MacAddrLo); cmd.evt = C_SET_MAC_ADDR; cmd.code = 0; cmd.idx = 0; ace_issue_cmd(regs, &cmd); return 0;}static void ace_set_multicast_list(struct device *dev){ struct ace_private *ap = dev->priv; struct ace_regs *regs = ap->regs; struct cmd cmd; if ((dev->flags & IFF_ALLMULTI) && !(ap->mcast_all)) { cmd.evt = C_SET_MULTICAST_MODE; cmd.code = C_C_MCAST_ENABLE; cmd.idx = 0; ace_issue_cmd(regs, &cmd); ap->mcast_all = 1; } else if (ap->mcast_all){ cmd.evt = C_SET_MULTICAST_MODE; cmd.code = C_C_MCAST_ENABLE; cmd.idx = 0; ace_issue_cmd(regs, &cmd); ap->mcast_all = 0; } if ((dev->flags & IFF_PROMISC) && !(ap->promisc)) { cmd.evt = C_SET_PROMISC_MODE; cmd.code = C_C_PROMISC_ENABLE; cmd.idx = 0; ace_issue_cmd(regs, &cmd); ap->promisc = 1; }else if (!(dev->flags & IFF_PROMISC) && (ap->promisc)){ cmd.evt = C_SET_PROMISC_MODE; cmd.code = C_C_PROMISC_DISABLE; cmd.idx = 0; ace_issue_cmd(regs, &cmd); ap->promisc = 0; } /* * For the time being multicast relies on the upper layers * filtering it properly. The Firmware does not allow one to * set the entire multicast list at a time and keeping track of * it here is going to be messy. */ if ((dev->mc_count) && !(ap->mcast_all)) { cmd.evt = C_SET_MULTICAST_MODE; cmd.code = C_C_MCAST_ENABLE; cmd.idx = 0; ace_issue_cmd(regs, &cmd); }else if (!ap->mcast_all) { cmd.evt = C_SET_MULTICAST_MODE; cmd.code = C_C_MCAST_DISABLE; cmd.idx = 0; ace_issue_cmd(regs, &cmd); }}static struct net_device_stats *ace_get_stats(struct device *dev){ struct ace_private *ap = dev->priv; return(&ap->stats);}__initfunc(void ace_copy(struct ace_regs *regs, void *src, u32 dest, int size)){ unsigned long tdest; u32 *wsrc; short tsize, i; if (size <= 0) return; while (size > 0){ tsize = min(((~dest & (ACE_WINDOW_SIZE - 1)) + 1), min(size, ACE_WINDOW_SIZE)); tdest = (unsigned long)®s->Window + (dest & (ACE_WINDOW_SIZE - 1)); writel(dest & ~(ACE_WINDOW_SIZE - 1), ®s->WinBase);#ifdef __BIG_ENDIAN#error "data must be swapped here"#else/* * XXX - special memcpy needed here!!! */ wsrc = src; for (i = 0; i < (tsize / 4); i++){ writel(wsrc[i], tdest + i*4); }#endif dest += tsize; src += tsize; size -= tsize; } return;}__initfunc(void ace_clear(struct ace_regs *regs, u32 dest, int size)){ unsigned long tdest; short tsize = 0, i; if (size <= 0) return; while (size > 0){ tsize = min(((~dest & (ACE_WINDOW_SIZE - 1)) + 1), min(size, ACE_WINDOW_SIZE)); tdest = (unsigned long)®s->Window + (dest & (ACE_WINDOW_SIZE - 1)); writel(dest & ~(ACE_WINDOW_SIZE - 1), ®s->WinBase); for (i = 0; i < (tsize / 4); i++){ writel(0, tdest + i*4); } dest += tsize; size -= tsize; } return;}/* * Download the firmware into the SRAM on the NIC * * This operation requires the NIC to be halted and is performed with * interrupts disabled and with the spinlock hold. */__initfunc(int ace_load_firmware(struct device *dev)){ struct ace_private *ap; struct ace_regs *regs; ap = (struct ace_private *)dev->priv; regs = ap->regs; if (!(readl(®s->CpuCtrl) & CPU_HALTED)){ printk(KERN_ERR "%s: trying to download firmware while the " "CPU is running!\n", dev->name); return -EFAULT; } /* * Do not try to clear more than 512KB or we end up seeing * funny things on NICs with only 512KB SRAM */ ace_clear(regs, 0x2000, 0x80000-0x2000); if (ap->version == 1){ ace_copy(regs, tigonFwText, tigonFwTextAddr, tigonFwTextLen); ace_copy(regs, tigonFwData, tigonFwDataAddr, tigonFwDataLen); ace_copy(regs, tigonFwRodata, tigonFwRodataAddr, tigonFwRodataLen); ace_clear(regs, tigonFwBssAddr, tigonFwBssLen); ace_clear(regs, tigonFwSbssAddr, tigonFwSbssLen); }else if (ap->version == 2){ ace_clear(regs, tigon2FwBssAddr, tigon2FwBssLen); ace_clear(regs, tigon2FwSbssAddr, tigon2FwSbssLen); ace_copy(regs, tigon2FwText, tigon2FwTextAddr,tigon2FwTextLen); ace_copy(regs, tigon2FwRodata, tigon2FwRodataAddr, tigon2FwRodataLen); ace_copy(regs, tigon2FwData, tigon2FwDataAddr,tigon2FwDataLen); } return 0;}/* * The eeprom on the AceNIC is an Atmel i2c EEPROM. * * Accessing the EEPROM is `interesting' to say the least - don't read * this code right after dinner. * * This is all about black magic and bit-banging the device .... I * wonder in what hospital they have put the guy who designed the i2c * specs. * * Oh yes, this is only the beginning! */static void eeprom_start(struct ace_regs *regs){ u32 local = readl(®s->LocalCtrl); udelay(1); local |= EEPROM_DATA_OUT | EEPROM_WRITE_ENABLE; writel(local, ®s->LocalCtrl); mb(); udelay(1); local |= EEPROM_CLK_OUT; writel(local, ®s->LocalCtrl); mb(); udelay(1); local &= ~EEPROM_DATA_OUT; writel(local, ®s->LocalCtrl); mb(); udelay(1); local &= ~EEPROM_CLK_OUT; writel(local, ®s->LocalCtrl); mb();}static void eeprom_prep(struct ace_regs *regs, u8 magic){ short i; u32 local; udelay(2); local = readl(®s->LocalCtrl); local &= ~EEPROM_DATA_OUT; local |= EEPROM_WRITE_ENABLE; writel(local, ®s->LocalCtrl); mb(); for (i = 0; i < 8; i++, magic <<= 1) { udelay(2); if (magic & 0x80) local |= EEPROM_DATA_OUT; else local &= ~EEPROM_DATA_OUT; writel(local, ®s->LocalCtrl); mb(); udelay(1); local |= EEPROM_CLK_OUT; writel(local, ®s->LocalCtrl); mb(); udelay(1); local &= ~(EEPROM_CLK_OUT | EEPROM_DATA_OUT); writel(local, ®s->LocalCtrl); mb(); }}static int eeprom_check_ack(struct ace_regs *regs){ int state; u32 local; local = readl(®s->LocalCtrl); local &= ~EEPROM_WRITE_ENABLE; writel(local, ®s->LocalCtrl); mb(); udelay(2); local |= EEPROM_CLK_OUT; writel(local, ®s->LocalCtrl); mb(); udelay(1); /* sample data in middle of high clk */ state = (readl(®s->LocalCtrl) & EEPROM_DATA_IN) != 0; udelay(1); mb(); writel(readl(®s->LocalCtrl) & ~EEPROM_CLK_OUT, ®s->LocalCtrl); mb(); return state;}static void eeprom_stop(struct ace_regs *regs){ u32 local; local = readl(®s->LocalCtrl); local |= EEPROM_WRITE_ENABLE; writel(local, ®s->LocalCtrl); mb(); udelay(1); local &= ~EEPROM_DATA_OUT; writel(local, ®s->LocalCtrl); mb(); udelay(1); local |= EEPROM_CLK_OUT; writel(local, ®s->LocalCtrl); mb(); udelay(1); local |= EEPROM_DATA_OUT; writel(local, ®s->LocalCtrl); mb(); udelay(2); local &= ~EEPROM_CLK_OUT; writel(local, ®s->LocalCtrl); mb();}/* * Read a whole byte from the EEPROM. */static u8 read_eeprom_byte(struct ace_regs *regs, unsigned long offset){ u32 local; short i; u8 result = 0; if (!regs){ printk(KERN_ERR "No regs!\n"); return 0; } eeprom_start(regs); eeprom_prep(regs, EEPROM_WRITE_SELECT); if (eeprom_check_ack(regs)){ printk("Unable to sync eeprom\n"); return 0; } eeprom_prep(regs, (offset >> 8) & 0xff); if (eeprom_check_ack(regs)) return 0; eeprom_prep(regs, offset & 0xff); if (eeprom_check_ack(regs)) return 0; eeprom_start(regs); eeprom_prep(regs, EEPROM_READ_SELECT); if (eeprom_check_ack(regs)) return 0; for (i = 0; i < 8; i++) { local = readl(®s->LocalCtrl); local &= ~EEPROM_WRITE_ENABLE; writel(local, ®s->LocalCtrl); udelay(2); mb(); local |= EEPROM_CLK_OUT; writel(local, ®s->LocalCtrl); udelay(1); mb(); /* sample data mid high clk */ result = (result << 1) | ((readl(®s->LocalCtrl) & EEPROM_DATA_IN) != 0); udelay(1); mb(); local = readl(®s->LocalCtrl); local &= ~EEPROM_CLK_OUT; writel(local, ®s->LocalCtrl); mb(); if (i == 7){ local |= EEPROM_WRITE_ENABLE; writel(local, ®s->LocalCtrl); mb(); } } local |= EEPROM_DATA_OUT; writel(local, ®s->LocalCtrl); udelay(1); writel(readl(®s->LocalCtrl) | EEPROM_CLK_OUT, ®s->LocalCtrl); udelay(2); writel(readl(®s->LocalCtrl) & ~EEPROM_CLK_OUT, ®s->LocalCtrl); eeprom_stop(regs); return result;}/* * Local variables: * compile-command: "gcc -D__KERNEL__ -D__SMP__ -DMODULE -I/data/home/jes/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -DMODVERSIONS -include /data/home/jes/linux/include/linux/modversions.h -c -o acenic.o acenic.c" * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -