📄 ether00.c
字号:
dev->addr_len=6; writew(0,ETHER_ARC_ADR(dev->base_addr)); writel((dev->dev_addr[0]<<24) | (dev->dev_addr[1]<<16) | (dev->dev_addr[2]<<8) | dev->dev_addr[3], ETHER_ARC_DATA(dev->base_addr)); writew(4,ETHER_ARC_ADR(dev->base_addr)); tmp=readl(ETHER_ARC_DATA(dev->base_addr)); tmp&=0xffff; tmp|=(dev->dev_addr[4]<<24) | (dev->dev_addr[5]<<16); writel(tmp, ETHER_ARC_DATA(dev->base_addr)); /* Enable this entry in the ARC */ writel(1,ETHER_ARC_ENA(dev->base_addr)); return;}static void ether00_reset(struct net_device *dev){ /* reset the controller */ writew(ETHER_MAC_CTL_RESET_MSK,ETHER_MAC_CTL(dev->base_addr)); /* * Make sure we're not going to send anything */ writew(ETHER_TX_CTL_TXHALT_MSK,ETHER_TX_CTL(dev->base_addr)); /* * Make sure we're not going to receive anything */ writew(ETHER_RX_CTL_RXHALT_MSK,ETHER_RX_CTL(dev->base_addr)); /* * Disable Interrupts for now, and set the burst size to 8 bytes */ writel(ETHER_DMA_CTL_INTMASK_MSK | ((8 << ETHER_DMA_CTL_DMBURST_OFST) & ETHER_DMA_CTL_DMBURST_MSK) |(2<<ETHER_DMA_CTL_RXALIGN_OFST), ETHER_DMA_CTL(dev->base_addr)); /* * Set TxThrsh - start transmitting a packet after 1514 * bytes or when a packet is complete, whichever comes first */ writew(1514,ETHER_TXTHRSH(dev->base_addr)); /* * Set TxPollCtr. Each cycle is * 61.44 microseconds with a 33 MHz bus */ writew(1,ETHER_TXPOLLCTR(dev->base_addr)); /* * Set Rx_Ctl - Turn off reception and let RxData turn it * on later */ writew(ETHER_RX_CTL_RXHALT_MSK,ETHER_RX_CTL(dev->base_addr));}static void ether00_set_multicast(struct net_device* dev){ int count=dev->mc_count; /* Set promiscuous mode if it's asked for. */ if (dev->flags&IFF_PROMISC){ writew( ETHER_ARC_CTL_COMPEN_MSK | ETHER_ARC_CTL_BROADACC_MSK | ETHER_ARC_CTL_GROUPACC_MSK | ETHER_ARC_CTL_STATIONACC_MSK, ETHER_ARC_CTL(dev->base_addr)); return; } /* * Get all multicast packets if required, or if there are too * many addresses to fit in hardware */ if (dev->flags & IFF_ALLMULTI){ writew( ETHER_ARC_CTL_COMPEN_MSK | ETHER_ARC_CTL_GROUPACC_MSK | ETHER_ARC_CTL_BROADACC_MSK, ETHER_ARC_CTL(dev->base_addr)); return; } if (dev->mc_count > (ETHER_ARC_SIZE - 1)){ printk(KERN_WARNING "Too many multicast addresses for hardware to filter - receiving all multicast packets\n"); writew( ETHER_ARC_CTL_COMPEN_MSK | ETHER_ARC_CTL_GROUPACC_MSK | ETHER_ARC_CTL_BROADACC_MSK, ETHER_ARC_CTL(dev->base_addr)); return; } if(dev->mc_count){ struct dev_mc_list *mc_list_ent=dev->mc_list; unsigned int temp,i; DEBUG(printk("mc_count=%d mc_list=%#x\n",dev-> mc_count, dev->mc_list)); DEBUG(printk("mc addr=%02#x%02x%02x%02x%02x%02x\n", mc_list_ent->dmi_addr[5], mc_list_ent->dmi_addr[4], mc_list_ent->dmi_addr[3], mc_list_ent->dmi_addr[2], mc_list_ent->dmi_addr[1], mc_list_ent->dmi_addr[0]);) /* * The first 6 bytes are the MAC address, so * don't change them! */ writew(4,ETHER_ARC_ADR(dev->base_addr)); temp=readl(ETHER_ARC_DATA(dev->base_addr)); temp&=0xffff0000; /* Disable the current multicast stuff */ writel(1,ETHER_ARC_ENA(dev->base_addr)); for(;;){ temp|=mc_list_ent->dmi_addr[1] | mc_list_ent->dmi_addr[0]<<8; writel(temp,ETHER_ARC_DATA(dev->base_addr)); i=readl(ETHER_ARC_ADR(dev->base_addr)); writew(i+4,ETHER_ARC_ADR(dev->base_addr)); temp=mc_list_ent->dmi_addr[5]| mc_list_ent->dmi_addr[4]<<8 | mc_list_ent->dmi_addr[3]<<16 | mc_list_ent->dmi_addr[2]<<24; writel(temp,ETHER_ARC_DATA(dev->base_addr)); count--; if(!mc_list_ent->next || !count){ break; } DEBUG(printk("mc_list_next=%#x\n",mc_list_ent->next);) mc_list_ent=mc_list_ent->next; i=readl(ETHER_ARC_ADR(dev->base_addr)); writel(i+4,ETHER_ARC_ADR(dev->base_addr)); temp=mc_list_ent->dmi_addr[3]| mc_list_ent->dmi_addr[2]<<8 | mc_list_ent->dmi_addr[1]<<16 | mc_list_ent->dmi_addr[0]<<24; writel(temp,ETHER_ARC_DATA(dev->base_addr)); i=readl(ETHER_ARC_ADR(dev->base_addr)); writel(i+4,ETHER_ARC_ADR(dev->base_addr)); temp=mc_list_ent->dmi_addr[4]<<16 | mc_list_ent->dmi_addr[5]<<24; writel(temp,ETHER_ARC_DATA(dev->base_addr)); count--; if(!mc_list_ent->next || !count){ break; } mc_list_ent=mc_list_ent->next; } if(count) printk(KERN_WARNING "Multicast list size error\n"); writew( ETHER_ARC_CTL_BROADACC_MSK| ETHER_ARC_CTL_COMPEN_MSK, ETHER_ARC_CTL(dev->base_addr)); } /* enable the active ARC enties */ writew((1<<(count+2))-1,ETHER_ARC_ENA(dev->base_addr));}static int ether00_open(struct net_device* dev){ int result,tmp; struct net_priv* priv; if (!is_valid_ether_addr(dev->dev_addr)) return -EINVAL; /* Install interrupt handlers */ result=request_irq(dev->irq,ether00_int,0,"ether00",dev); if(result) goto open_err1; result=request_irq(2,ether00_phy_int,0,"ether00_phy",dev); if(result) goto open_err2; ether00_reset(dev); result=ether00_mem_init(dev); if(result) goto open_err3; ether00_setup_ethernet_address(dev); ether00_set_multicast(dev); result=ether00_write_phy(dev,PHY_CONTROL, PHY_CONTROL_ANEGEN_MSK | PHY_CONTROL_RANEG_MSK); if(result) goto open_err4; result=ether00_write_phy(dev,PHY_IRQ_CONTROL, PHY_IRQ_CONTROL_LS_CHG_IE_MSK | PHY_IRQ_CONTROL_ANEG_COMP_IE_MSK); if(result) goto open_err4; /* Start the device enable interrupts */ writew(ETHER_RX_CTL_RXEN_MSK// | ETHER_RX_CTL_STRIPCRC_MSK | ETHER_RX_CTL_ENGOOD_MSK | ETHER_RX_CTL_ENRXPAR_MSK| ETHER_RX_CTL_ENLONGERR_MSK | ETHER_RX_CTL_ENOVER_MSK| ETHER_RX_CTL_ENCRCERR_MSK, ETHER_RX_CTL(dev->base_addr)); writew(ETHER_TX_CTL_TXEN_MSK| ETHER_TX_CTL_ENEXDEFER_MSK| ETHER_TX_CTL_ENLCARR_MSK| ETHER_TX_CTL_ENEXCOLL_MSK| ETHER_TX_CTL_ENLATECOLL_MSK| ETHER_TX_CTL_ENTXPAR_MSK| ETHER_TX_CTL_ENCOMP_MSK, ETHER_TX_CTL(dev->base_addr)); tmp=readl(ETHER_DMA_CTL(dev->base_addr)); writel(tmp&~ETHER_DMA_CTL_INTMASK_MSK,ETHER_DMA_CTL(dev->base_addr)); return 0; open_err4: ether00_reset(dev); open_err3: free_irq(2,dev); open_err2: free_irq(dev->irq,dev); open_err1: return result;}static int ether00_tx(struct sk_buff* skb, struct net_device* dev){ struct net_priv *priv=dev->priv; struct tx_fda_ent *fda_ptr; int i; /* * Find an empty slot in which to stick the frame */ fda_ptr=(struct tx_fda_ent*)__dma_va(readl(ETHER_TXFRMPTR(dev->base_addr))); i=0; while(i<TX_NUM_FDESC){ if (fda_ptr->fd.FDStat||(fda_ptr->fd.FDCtl & FDCTL_COWNSFD_MSK)){ fda_ptr =(struct tx_fda_ent*) __dma_va((struct tx_fda_ent*)fda_ptr->fd.FDNext); } else { break; } i++; } /* Write the skb data from the cache*/ consistent_sync(skb->data,skb->len,PCI_DMA_TODEVICE); fda_ptr->bd.BuffData=(char*)__pa(skb->data); fda_ptr->bd.BuffLength=(unsigned short)skb->len; /* Save the pointer to the skb for freeing later */ fda_ptr->fd.FDSystem=(unsigned int)skb; fda_ptr->fd.FDStat=0; /* Pass ownership of the buffers to the controller */ fda_ptr->fd.FDCtl=1; fda_ptr->fd.FDCtl|=FDCTL_COWNSFD_MSK; /* If the next buffer in the list is full, stop the queue */ fda_ptr=(struct tx_fda_ent*)__dma_va(fda_ptr->fd.FDNext); if ((fda_ptr->fd.FDStat)||(fda_ptr->fd.FDCtl & FDCTL_COWNSFD_MSK)){ netif_stop_queue(dev); priv->queue_stopped=1; } return 0;}static struct net_device_stats *ether00_stats(struct net_device* dev){ struct net_priv *priv=dev->priv; return &priv->stats;}static int ether00_stop(struct net_device* dev){ struct net_priv *priv=dev->priv; int tmp; /* Stop/disable the device. */ tmp=readw(ETHER_RX_CTL(dev->base_addr)); tmp&=~(ETHER_RX_CTL_RXEN_MSK | ETHER_RX_CTL_ENGOOD_MSK); tmp|=ETHER_RX_CTL_RXHALT_MSK; writew(tmp,ETHER_RX_CTL(dev->base_addr)); tmp=readl(ETHER_TX_CTL(dev->base_addr)); tmp&=~ETHER_TX_CTL_TXEN_MSK; tmp|=ETHER_TX_CTL_TXHALT_MSK; writel(tmp,ETHER_TX_CTL(dev->base_addr)); /* Free up system resources */ free_irq(dev->irq,dev); free_irq(2,dev); iounmap(priv->dma_data); return 0;}static void ether00_get_ethernet_address(struct net_device* dev){ struct mtd_info *mymtd=NULL; int i; size_t retlen; /* * For the Epxa10 dev board (camelot), the ethernet MAC * address is of the form 00:aa:aa:00:xx:xx where * 00:aa:aa is the Altera vendor ID and xx:xx is the * last 2 bytes of the board serial number, as programmed * into the OTP area of the flash device on EBI1. If this * isn't an expa10 dev board, or there's no mtd support to * read the serial number from flash then we'll force the * use to set their own mac address using ifconfig. */#ifdef CONFIG_ARCH_CAMELOT#ifdef CONFIG_MTD /* get the mtd_info structure for the first mtd device*/ for(i=0;i<MAX_MTD_DEVICES;i++){ mymtd=get_mtd_device(NULL,i); if(!mymtd||!strcmp(mymtd->name,"EPXA10DB flash")) break; } if(!mymtd || !mymtd->read_user_prot_reg){ printk(KERN_WARNING "%s: Failed to read MAC address from flash\n",dev->name); }else{ mymtd->read_user_prot_reg(mymtd,2,1,&retlen,&dev->dev_addr[5]); mymtd->read_user_prot_reg(mymtd,3,1,&retlen,&dev->dev_addr[4]); dev->dev_addr[3]=0; dev->dev_addr[2]=vendor_id[1]; dev->dev_addr[1]=vendor_id[0]; dev->dev_addr[0]=0; }#else printk(KERN_WARNING "%s: MTD support required to read MAC address from EPXA10 dev board\n", dev->name);#endif#endif if (!is_valid_ether_addr(dev->dev_addr)) printk("%s: Invalid ethernet MAC address. Please set using " "ifconfig\n", dev->name);}/* * Keep a mapping of dev_info addresses -> port lines to use when * removing ports dev==NULL indicates unused entry */static struct net_device* dev_list[ETH_NR];static int ether00_add_device(struct pldhs_dev_info* dev_info,void* dev_ps_data){ struct net_device *dev; struct net_priv *priv; void *map_addr; int result; int i; i=0; while(dev_list[i] && i < ETH_NR) i++; if(i==ETH_NR){ printk(KERN_WARNING "ether00: Maximum number of ports reached\n"); return 0; } if (!request_mem_region(dev_info->base_addr, MAC_REG_SIZE, "ether00")) return -EBUSY; dev = alloc_etherdev(sizeof(struct net_priv)); if(!dev) { result = -ENOMEM; goto out_release; } priv = dev->priv; priv->tq_memupdate.routine=ether00_mem_update; priv->tq_memupdate.data=(void*) dev; spin_lock_init(&priv->rx_lock); map_addr=ioremap_nocache(dev_info->base_addr,SZ_4K); if(!map_addr){ result = -ENOMEM; out_kfree; } dev->open=ether00_open; dev->stop=ether00_stop; dev->set_multicast_list=ether00_set_multicast; dev->hard_start_xmit=ether00_tx; dev->get_stats=ether00_stats; ether00_get_ethernet_address(dev); SET_MODULE_OWNER(dev); dev->base_addr=(unsigned int)map_addr; dev->irq=dev_info->irq; dev->features=NETIF_F_DYNALLOC | NETIF_F_HW_CSUM; result=register_netdev(dev); if(result){ printk("Ether00: Error %i registering driver\n",result); goto out_unmap; } printk("registered ether00 device at %#x\n",dev_info->base_addr); dev_list[i]=dev; return result; out_unmap: iounmap(map_addr); out_kfree: free_netdev(dev); out_release: release_mem_region(dev_info->base_addr, MAC_REG_SIZE); return result;}static int ether00_remove_devices(void){ int i; for(i=0;i<ETH_NR;i++){ if(dev_list[i]){ netif_device_detach(dev_list[i]); unregister_netdev(dev_list[i]); iounmap((void*)dev_list[i]->base_addr); release_mem_region(dev_list[i]->base_addr, MAC_REG_SIZE); free_netdev(dev_list[i]); dev_list[i]=0; } } return 0;}static struct pld_hotswap_ops ether00_pldhs_ops={ .name = ETHER00_NAME, .add_device = ether00_add_device, .remove_devices = ether00_remove_devices,};static void __exit ether00_cleanup_module(void){ int result; result=ether00_remove_devices(); if(result) printk(KERN_WARNING "ether00: failed to remove all devices\n"); pldhs_unregister_driver(ETHER00_NAME);}module_exit(ether00_cleanup_module);static int __init ether00_mod_init(void){ printk("mod init\n"); return pldhs_register_driver(ðer00_pldhs_ops);}module_init(ether00_mod_init);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -