📄 rhine_main.c
字号:
return 0;}static void rhine_shutdown(PRHINE_INFO pInfo) { PMAC_REGS pMacRegs=pInfo->pMacRegs; rhine_disable_int(pInfo); writeb(CR0_STOP,&pMacRegs->byCR0); SafeDisableMiiAutoPoll(pInfo); rhine_ClearISR(pInfo->pMacRegs); }static int rhine_close(struct net_device *dev) { PRHINE_INFO pInfo=(PRHINE_INFO) dev->priv; netif_stop_queue(dev); rhine_shutdown(pInfo); MOD_DEC_USE_COUNT; free_irq(dev->irq, dev); rhine_free_td_ring(pInfo); rhine_free_rd_ring(pInfo); rhine_free_rings(pInfo); pInfo->flags &=(~RHINE_FLAGS_OPENED); return 0;}static int rhine_xmit(struct sk_buff *skb, struct net_device *dev) { PRHINE_INFO pInfo=dev->priv; int iQNo=0; PTX_DESC pTD,pHeadTD; PMAC_REGS pMacRegs=pInfo->pMacRegs; int flags; spin_lock_irqsave(&pInfo->lock,flags); pTD=pHeadTD=pInfo->apCurrTD[0]; ASSERT(pTD); ASSERT(pTD->pInfo); pHeadTD->tdesc1.byTCR=(TCR_IC|TCR_EDP|TCR_STP); #ifdef RHINE_ZERO_COPY_SUPPORT if (skb_shinfo(skb)->nr_frags>0) { int nfrags=skb_shinfo(skb)->nr_frags; pTD->pInfo->skb=skb; if ((AVAIL_TD(pInfo,iQNo)<nfrags) || (pInfo->flags & RHINE_FLAGS_TX_ALIGN)) { skb_linearize(skb,GFP_ATOMIC); memcpy(pTD->pInfo->buf,skb->data,skb->len); pTD->pInfo->skb_dma=pTD->pInfo->buf_dma; pTD->buff_addr=cpu_to_le32(pTD->pInfo->skb_dma); pTD->tdesc1.f15BufLen=(skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN); } else { int i; pTD->pInfo->skb_dma = pci_map_single(pInfo->pcid, skb->data, skb->len -skb->data_len, PCI_DMA_TODEVICE); pTD->buff_addr=cpu_to_le32(pTD->pInfo->skb_dma); pTD->tdesc1.f15BufLen=skb->len - skb->data_len; for (i=0;i<nfrags;i++) { skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; void* addr = ((void *) page_address(frag->page + frag->page_offset)); pTD=pTD->next; pTD->pInfo->skb_dma= pci_map_single(pInfo->pcid,addr,frag->size,PCI_DMA_TODEVICE); pTD->buff_addr=cpu_to_le32(pTD->pInfo->skb_dma); pTD->tdesc1.f15BufLen=frag->size; } pTD->tdesc1.byTCR|=TCR_EDP; } } else#endif if ((pInfo->flags & RHINE_FLAGS_TX_ALIGN) && ((long)skb->data & 3)) { memcpy(pHeadTD->pInfo->buf,skb->data,skb->len); pHeadTD->pInfo->skb=skb; pHeadTD->pInfo->skb_dma=pHeadTD->pInfo->buf_dma; pHeadTD->buff_addr=cpu_to_le32(pHeadTD->pInfo->skb_dma); pHeadTD->tdesc1.f15BufLen=(skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN); } else { pHeadTD->pInfo->skb=skb; pHeadTD->pInfo->skb_dma = pci_map_single(pInfo->pcid, skb->data, skb->len, PCI_DMA_TODEVICE); pHeadTD->buff_addr=cpu_to_le32(pHeadTD->pInfo->skb_dma); pHeadTD->tdesc1.f15BufLen=(skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN); } #ifdef VMNS if (pInfo->flags & RHINE_FLAGS_VMNS_COMMITTED) { PVMNS_ATTACH_INFO pAttch = GET_VMNS_ATTACH_INFO(skb); if (pAttch->type & ATT_INFO_TYPE_TAG) { pHeadTD->tdesc0.f12VID=(pAttch->vlan & 0xfff); pHeadTD->tdesc0.f3Priority=(pAttch->priority & 0x7); pHeadTD->tdesc1.byTCR|=TCR_TAG; } } else#endif if (pInfo->flags & RHINE_FLAGS_TAGGING) { pHeadTD->tdesc0.f12VID=(pInfo->sOpts.vid & 0xfff); pHeadTD->tdesc0.f3Priority=0; pHeadTD->tdesc1.byTCR|=TCR_TAG; } #ifdef RHINE_TX_CSUM_SUPPORT if ((pInfo->flags & RHINE_FLAGS_TX_CSUM) && (skb->ip_summed==CHECKSUM_HW)) { struct iphdr* ip=skb->nh.iph; if (ip->protocol==IPPROTO_TCP) pHeadTD->tdesc1.byTCR|=TCR_TCPCK; else if (ip->protocol==IPPROTO_UDP) pHeadTD->tdesc1.byTCR|=(TCR_UDPCK); pHeadTD->tdesc1.byTCR|=TCR_IPCK; } #endif wmb(); pHeadTD->tdesc0.f1Owner=OWNED_BY_NIC; wmb(); pInfo->iTDUsed[iQNo]++; pInfo->apCurrTD[iQNo]=pTD->next; if (pInfo->iTDUsed[iQNo]>=pInfo->sOpts.nTxDescs-1) netif_stop_queue(dev); if (pInfo->flags & RHINE_FLAGS_TAGGING) BYTE_REG_BITS_ON(1 << (7-iQNo), &pMacRegs->byTXQWAK); BYTE_REG_BITS_ON(CR1_TDMD1,&(pMacRegs->byCR1)); dev->trans_start = jiffies; spin_unlock_irqrestore(&pInfo->lock,flags); return 0;}static void rhine_intr(int irq, void *dev_instance, struct pt_regs *regs) { struct net_device* dev=dev_instance; PRHINE_INFO pInfo=(PRHINE_INFO) dev->priv; U32 isr_status; PMAC_REGS pMacRegs=pInfo->pMacRegs; int flags; int max_count=0; ASSERT(pMacRegs); isr_status=rhine_ReadISR(pMacRegs,pInfo->byRevId); if (isr_status==0) { return; } rhine_disable_int(pInfo); spin_lock_irqsave(&pInfo->lock,flags); while (isr_status!=0) { rhine_WriteISR(isr_status,pMacRegs,pInfo->byRevId); if (isr_status & (ISR_SRCI|ISR_TDWBRAI|ISR_BE)) rhine_error(pInfo, isr_status); if (isr_status & (ISR_RXE|ISR_PRX)) rhine_rx_srv(pInfo, isr_status); if (isr_status & (ISR_TXE|ISR_PTX)) rhine_tx_srv(pInfo, isr_status); if (max_count++>10) break; isr_status=rhine_ReadISR(pMacRegs,pInfo->byRevId); } spin_unlock_irqrestore(&pInfo->lock,flags); rhine_enable_int(pInfo); }void rhine_get_cam_mask(PRHINE_INFO pInfo, PU32 pMask, RHINE_CAM_TYPE cam_type) { PMAC_REGS pMacRegs=pInfo->pMacRegs; // enable CAMEN if (cam_type==RHINE_VLAN_ID_CAM) writeb(CAMC_CAMEN | CAMC_VCAMSL, &pMacRegs->byCAMCR); else writeb(CAMC_CAMEN,&pMacRegs->byCAMCR); wmb(); // read mask *pMask = readl(&pMacRegs->dwCAMMASK); // disable CAMEN writeb(0, &pMacRegs->byCAMCR); }void rhine_set_cam_mask(PRHINE_INFO pInfo, U32 mask, RHINE_CAM_TYPE cam_type) { PMAC_REGS pMacRegs=pInfo->pMacRegs; if (cam_type==RHINE_VLAN_ID_CAM) writeb(CAMC_CAMEN | CAMC_VCAMSL, &pMacRegs->byCAMCR); else writeb(CAMC_CAMEN,&pMacRegs->byCAMCR); wmb(); // write mask writel(mask, &pMacRegs->dwCAMMASK); // disable CAMEN writeb(0, &pMacRegs->byCAMCR); }void rhine_set_cam(PRHINE_INFO pInfo, int idx, PU8 addr, RHINE_CAM_TYPE cam_type) { PMAC_REGS pMacRegs=pInfo->pMacRegs; int i; if (cam_type==RHINE_VLAN_ID_CAM) writeb(CAMC_CAMEN | CAMC_VCAMSL, &pMacRegs->byCAMCR); else writeb(CAMC_CAMEN,&pMacRegs->byCAMCR); wmb(); writeb((U8)(idx & 0x1F), &pMacRegs->byCAMADD); if (cam_type==RHINE_VLAN_ID_CAM) { writeb(*addr, &pMacRegs->abyMAR[6]); writeb(*(addr+1), &pMacRegs->abyMAR[7]); } else for (i=0;i<6;i++, addr++) writeb(*addr,&(pMacRegs->abyMAR[i])); udelay(10); wmb(); writeb(CAMC_CAMWR|CAMC_CAMEN,&pMacRegs->byCAMCR); udelay(10); writeb(0, &pMacRegs->byCAMCR); }void rhine_get_cam(PRHINE_INFO pInfo, int idx, PU8 addr, RHINE_CAM_TYPE cam_type) { PMAC_REGS pMacRegs=pInfo->pMacRegs; int i; if (cam_type==RHINE_VLAN_ID_CAM) writeb(CAMC_CAMEN | CAMC_VCAMSL, &pMacRegs->byCAMCR); else writeb(CAMC_CAMEN,&pMacRegs->byCAMCR); wmb(); writeb((U8)(idx & 0x1F), &pMacRegs->byCAMADD); wmb(); writeb(CAMC_CAMRD|CAMC_CAMEN,&pMacRegs->byCAMCR); wmb(); udelay(10); if (cam_type==RHINE_VLAN_ID_CAM) *((PU16) addr)=readw(&(pMacRegs->abyMAR[6])); else for (i=0;i<6;i++, addr++) *((PU8)addr)=readb(&(pMacRegs->abyMAR[i])); writeb(0, &pMacRegs->byCAMCR); }static unsigned const ethernet_polynomial = 0x04c11db7U;static inline u32 ether_crc(int length, unsigned char *data){ int crc = -1; while(--length >= 0) { unsigned char current_octet = *data++; int bit; for (bit = 0; bit < 8; bit++, current_octet >>= 1) { crc = (crc << 1) ^ ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0); } } return crc;} static void rhine_set_multi(struct net_device *dev) { PRHINE_INFO pInfo = (PRHINE_INFO) dev->priv; PMAC_REGS pMacRegs = pInfo->pMacRegs; u32 mc_filter[2]; u8 rx_mode; int i; struct dev_mc_list *mclist; if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ /* Unconditionally log net taps. */ printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name); rx_mode = (RCR_AM|RCR_AB|RCR_PROM); } else if ((dev->mc_count > pInfo->multicast_limit) || (dev->flags & IFF_ALLMULTI)) { writel(0xffffffff, &pMacRegs->abyMAR[0]); writel(0xffffffff, &pMacRegs->abyMAR[4]); rx_mode = (RCR_AM|RCR_AB); } else if (pInfo->flags & RHINE_FLAGS_HAVE_CAM) { U32 mask=0; int offset=MCAM_SIZE-pInfo->multicast_limit; rhine_get_cam_mask(pInfo,&mask,RHINE_MULTICAST_CAM); for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) { rhine_set_cam(pInfo,i+offset,mclist->dmi_addr,RHINE_MULTICAST_CAM); mask|=1<<(offset+i); } rhine_set_cam_mask(pInfo,mask,RHINE_MULTICAST_CAM); rx_mode=(RCR_AM|RCR_AB); } else { memset(mc_filter, 0, sizeof(mc_filter)); for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) { int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; mc_filter[bit_nr >> 5] |= cpu_to_le32(1 << (bit_nr & 31)); } writel(mc_filter[0], &pMacRegs->abyMAR[0]); writel(mc_filter[1], &pMacRegs->abyMAR[4]); rx_mode = (RCR_AM|RCR_AB); } writeb((pInfo->sOpts.rx_thresh<<5) | rx_mode, &pMacRegs->byRCR); }static struct net_device_stats *rhine_get_stats(struct net_device *dev) { PRHINE_INFO pInfo=(PRHINE_INFO) dev->priv; return &pInfo->stats;}static int rhine_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { switch(cmd) { #ifdef VMNS case VMNS_DRV_SIOC: { PVMNS_DRV_SIOC_HEADER pParams = (PVMNS_DRV_SIOC_HEADER) rq->ifr_data; if (!capable(CAP_NET_ADMIN)) return -EPERM; if (vmns_process_ioctl(dev, pParams) == 0) return 0; } return -EAGAIN; #endif#ifdef RHINE_ETHTOOL_IOCTL_SUPPORT case SIOCETHTOOL: return rhine_ethtool_ioctl(dev, rq); break;#endif#ifdef RHINE_MII_IOCTL_SUPPORT case SIOCGMIIPHY: /* Get address of MII PHY in use. */ case SIOCGMIIREG: /* Read MII PHY register. */ case SIOCSMIIREG: /* Write to MII PHY register. */ return rhine_mii_ioctl(dev, rq, cmd); break;#endif default: return -EOPNOTSUPP; } return 0;}/*------------------------------------------------------------------*/MODULE_DEVICE_TABLE(pci, rhine_id_table);static struct pci_driver rhine_driver = { name: RHINE_NAME, id_table: rhine_id_table, probe: rhine_found1, remove: rhine_remove1, suspend: NULL, resume: NULL}; static int __init rhine_init_module(void){ return pci_module_init(&rhine_driver);}static void __exit rhine_cleanup_module(void){ pci_unregister_driver(&rhine_driver);} module_init(rhine_init_module);module_exit(rhine_cleanup_module);/************************************************************************* MII access , media link mode setting functions************************************************************************/static void SafeDisableMiiAutoPoll (PRHINE_INFO pInfo){ WORD ww; PMAC_REGS pMacRegs=pInfo->pMacRegs; // turn off MAUTO writeb(0,&pMacRegs->byMIICR); // for VT86C100A only if (pInfo->byRevId <= REV_ID_VT86C100A_E) { // turn off MSRCEN // NOTE.... address of MII should be 0x01, // otherwise SRCI will invoked writeb(1,&pMacRegs->byMIIAD); mdelay(1); // turn on MAUTO writeb(MIICR_MAUTO,&pMacRegs->byMIICR); // W_MAX_TIMEOUT is the timeout period for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { udelay(5); if (readb(&pMacRegs->byMIIAD) & MIIAD_MDONE) break; } // as soon as MDONE is on, // this is the right time to turn off MAUTO writeb(0,&pMacRegs->byMIICR); } else { // as soon as MIDLE is on, MAUTO is really stoped for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { udelay(5); if (BYTE_REG_BITS_IS_ON(MIIAD_MIDLE, &pMacRegs->byMIIAD)) break; } }}static void EnableMiiAutoPoll(PMAC_REGS pMacRegs) { int ii; writeb(0,&(pMacRegs->byMIICR)); writeb(MIIAD_MSRCEN|0x01,&pMacRegs->byMIIAD); writeb(MIICR_MAUTO,&pMacRegs->byMIICR); for (ii=0;ii<W_MAX_TIMEOUT; ii++) if (BYTE_REG_BITS_IS_ON(MIIAD_MDONE, &pMacRegs->byMIIAD)) break; BYTE_REG_BITS_ON(MIIAD_MSRCEN,&pMacRegs->byMIIAD);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -