From d448bace84022a4bb309d2f648c2f177876fb632 Mon Sep 17 00:00:00 2001 From: Steeve Morin Date: Thu, 12 Feb 2015 15:30:20 +0100 Subject: [PATCH] Modified version of mlinuxguy's eth driver and efuse from hardkernel Signed-off-by: Steeve Morin --- drivers/amlogic/efuse/efuse.c | 122 ++- drivers/amlogic/ethernet/am_net8218.c | 833 +++++++-------------- drivers/amlogic/ethernet/am_net8218.h | 25 +- drivers/amlogic/ethernet/phy/am_rtl8211f.c | 168 +++-- 4 files changed, 504 insertions(+), 644 deletions(-) mode change 100755 => 100644 drivers/amlogic/efuse/efuse.c mode change 100755 => 100644 drivers/amlogic/ethernet/am_net8218.c mode change 100755 => 100644 drivers/amlogic/ethernet/am_net8218.h mode change 100755 => 100644 drivers/amlogic/ethernet/phy/am_rtl8211f.c diff --git a/drivers/amlogic/efuse/efuse.c b/drivers/amlogic/efuse/efuse.c old mode 100755 new mode 100644 index d7767aedf..6ea7816b4 --- a/drivers/amlogic/efuse/efuse.c +++ b/drivers/amlogic/efuse/efuse.c @@ -125,7 +125,7 @@ static long efuse_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned l { switch (cmd) { -#ifndef CONFIG_MESON_TRUSTZONE +#ifndef CONFIG_MESON_TRUSTZONE case EFUSE_ENCRYPT_ENABLE: aml_set_reg32_bits( P_EFUSE_CNTL4, CNTL4_ENCRYPT_ENABLE_ON, CNTL4_ENCRYPT_ENABLE_BIT, CNTL4_ENCRYPT_ENABLE_SIZE); @@ -191,7 +191,7 @@ static ssize_t efuse_write( struct file *file, const char __user *buf, size_t co unsigned char* contents = NULL; if (pos >= EFUSE_BYTES) - return 0; /* Past EOF */ + return 0; /* Past EOF */ if (count > EFUSE_BYTES - pos) count = EFUSE_BYTES - pos; if (count > EFUSE_BYTES) @@ -239,21 +239,72 @@ static const struct file_operations efuse_fops = { .unlocked_ioctl = efuse_unlocked_ioctl, }; -/* Sysfs Files */ -static ssize_t mac_show(struct class *cla, struct class_attribute *attr, char *buf) +#define MACCHAR(x) (('A' <= (x) && (x) <= 'F') \ + ? (x) - 'A' + 'a' : (x)) + +static char *aml_efuse_mac(void) { - char dec_mac[6] = {0}; + char hwmac[20]; + char buf[80]; + char mac_mask; efuseinfo_item_t info; - if(efuse_getinfo_byID(EFUSE_MAC_ID, &info) < 0){ - printk(KERN_INFO"ID is not found\n"); - return -EFAULT; + + if (efuse_getinfo_byID(EFUSE_MAC_ID, &info) < 0) + return 0; + + if (efuse_read_item(buf, info.data_len, + (loff_t*)&info.offset) < 0) + return 0; + + sprintf(hwmac, "%02x:%02x:%02x:%02x:%02x:%02x", + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); + + mac_mask = buf[3] & 0xf0; + if ((0x30 == mac_mask) + || ((0xa0 <= mac_mask) && (mac_mask <= 0xc0))) { + info.data_len = 16; + info.offset = 4; + efuse_read_item(buf, info.data_len, + (loff_t*)&info.offset); + + if (0x30 == mac_mask) { + hwmac[9] = MACCHAR(buf[5]); + } + + sprintf(hwmac + 10, "%c:%c%c:%c%c", + MACCHAR(buf[11]), MACCHAR(buf[12]), MACCHAR(buf[13]), + MACCHAR(buf[14]), MACCHAR(buf[15])); } - if (efuse_read_item(dec_mac, info.data_len, (loff_t*)&info.offset) < 0) - return -EFAULT; + return hwmac; +} - return sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n", - dec_mac[0],dec_mac[1],dec_mac[2],dec_mac[3],dec_mac[4],dec_mac[5]); +unsigned char *aml_efuse_get_item(unsigned char* key_name) +{ + unsigned char *ret = 0; + int id; + + if(strcmp(key_name,"mac")==0) id = EFUSE_MAC_ID; + else if(strcmp(key_name,"mac_bt")==0) id = EFUSE_MAC_BT_ID; + else if(strcmp(key_name,"mac_wifi")==0) id = EFUSE_MAC_WIFI_ID; + else if(strcmp(key_name,"usid")==0) id = EFUSE_USID_ID; + else { + pr_info("%s: UNKNOWN key_name\n", __func__); + return 0; + } + + if (id == EFUSE_MAC_ID) { + return aml_efuse_mac(); + } + + return ret; +} +EXPORT_SYMBOL(aml_efuse_get_item); + +/* Sysfs Files */ +static ssize_t mac_show(struct class *cla, struct class_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", aml_efuse_mac()); } static ssize_t mac_wifi_show(struct class *cla, struct class_attribute *attr, char *buf) @@ -290,6 +341,23 @@ static ssize_t mac_bt_show(struct class *cla, struct class_attribute *attr, char dec_mac[0],dec_mac[1],dec_mac[2],dec_mac[3],dec_mac[4],dec_mac[5]); } +#if defined(CONFIG_MACH_MESON8B_ODROIDC) +static ssize_t usid_show(struct class *cla, struct class_attribute *attr, char *buf) +{ + char usid[50] = {0}; + efuseinfo_item_t info; + if(efuse_getinfo_byID(EFUSE_USID_ID, &info) < 0){ + printk(KERN_INFO"ID is not found\n"); + return -EFAULT; + } + + if (efuse_read_item(usid, info.data_len, (loff_t*)&info.offset) < 0) + return -EFAULT; + + return sprintf(buf, "%s\n",usid); +} +#endif + static int efuse_device_match(struct device *dev, const void *data) { return (!strcmp(dev->kobj.name,(const char*)data)); @@ -310,9 +378,9 @@ struct device *efuse_class_to_device(struct class *cla) { int len; - len = strlen(usid); - if((len > 8)&&(len<31) ) - return 0; + len = strlen(usid); + if((len > 8)&&(len<31) ) + return 0; else return -1; }*/ @@ -359,15 +427,15 @@ static ssize_t userdata_show(struct class *cla, struct class_attribute *attr, ch // return -1; //} /*return sprintf(buf, "%01c%01c%01c%01c%01c%01c%01c%01c%01c%01c%01c%01c%01c%01c%01c%01c%01c%01c%01c%01c\n", - op[0],op[1],op[2],op[3],op[4],op[5], - op[6],op[7],op[8],op[9],op[10],op[11], - op[12],op[13],op[14],op[15],op[16],op[17], - op[18],op[19]);*/ + op[0],op[1],op[2],op[3],op[4],op[5], + op[6],op[7],op[8],op[9],op[10],op[11], + op[12],op[13],op[14],op[15],op[16],op[17], + op[18],op[19]);*/ for(i = 0; i < info.data_len; i++) { - memset(tmp, 0, 5); - sprintf(tmp, "%02x:", op[i]); - strcat(buf, tmp); + memset(tmp, 0, 5); + sprintf(tmp, "%02x:", op[i]); + strcat(buf, tmp); } buf[3*info.data_len - 1] = 0; //delete the last ':' return 3*info.data_len - 1; @@ -428,6 +496,10 @@ static struct class_attribute efuse_class_attrs[] = { __ATTR_RO(mac_bt), +#if defined(CONFIG_MACH_MESON8B_ODROIDC) + __ATTR_RO(usid), +#endif + #ifndef EFUSE_READ_ONLY /*make the efuse can not be write through sysfs */ __ATTR(userdata, S_IRWXU, userdata_show, userdata_write), @@ -531,9 +603,9 @@ int usid_min,usid_max; if(pdev->dev.platform_data) devp->platform_data = pdev->dev.platform_data; else - devp->platform_data = NULL; + devp->platform_data = NULL; #endif -#ifndef CONFIG_MESON_TRUSTZONE +#ifndef CONFIG_MESON_TRUSTZONE /* disable efuse encryption */ aml_set_reg32_bits( P_EFUSE_CNTL4, CNTL1_AUTO_WR_ENABLE_OFF, CNTL4_ENCRYPT_ENABLE_BIT, CNTL4_ENCRYPT_ENABLE_SIZE ); @@ -547,7 +619,7 @@ int usid_min,usid_max; // clear power down bit aml_set_reg32_bits(P_EFUSE_CNTL1, CNTL1_PD_ENABLE_OFF, CNTL1_PD_ENABLE_BIT, CNTL1_PD_ENABLE_SIZE); -#endif +#endif #endif return 0; diff --git a/drivers/amlogic/ethernet/am_net8218.c b/drivers/amlogic/ethernet/am_net8218.c old mode 100755 new mode 100644 index aec2980c1..f8f9601d0 --- a/drivers/amlogic/ethernet/am_net8218.c +++ b/drivers/amlogic/ethernet/am_net8218.c @@ -34,7 +34,6 @@ #include #include #include - #include #include #include @@ -53,7 +52,7 @@ #define DRIVER_NAME "ethernet" #define DRV_NAME DRIVER_NAME -#define DRV_VERSION "v2.0.0" +#define DRV_VERSION "v2.0.2" #undef CONFIG_HAS_EARLYSUSPEND #ifdef CONFIG_HAS_EARLYSUSPEND @@ -70,16 +69,14 @@ MODULE_VERSION(DRV_VERSION); // >1 further setup info; // >2 rx data dump // >3 tx data dump +#undef M_DEBUG_ON // use this to turn on debug/printk when needed #ifdef CONFIG_AM_ETHERNET_DEBUG_LEVEL static int g_debug = CONFIG_AM_ETHERNET_DEBUG_LEVEL; #else static int g_debug = 1; #endif -static unsigned int g_tx_cnt = 0; -static unsigned int g_rx_cnt = 0; +// These two now control how many packets per tasklet are sent/received static int g_mdcclk = 2; -static int g_rxnum = 64; -static int g_txnum = 64; static int new_maclogic = 0; static unsigned int ethbaseaddr = ETHBASE; static unsigned int savepowermode = 0; @@ -119,6 +116,8 @@ static int ethernet_reset(struct net_device *dev); static int reset_mac(struct net_device *dev); static void am_net_dump_macreg(void); static void read_macreg(void); +void hardware_reset_phy(void); +extern char *aml_efuse_get_item(unsigned char* key_name); /* --------------------------------------------------------------------------*/ /** @@ -152,14 +151,13 @@ static void data_dump(unsigned char *p, int len) * @param len */ /* --------------------------------------------------------------------------*/ +#ifdef M_DEBUG_ON static void tx_data_dump(unsigned char *p, int len) { if ((g_debug == 3) || (g_debug == 5)) { printk("---------->\n"); data_dump(p, len); } - g_tx_cnt++; - return; } @@ -177,11 +175,9 @@ static void rx_data_dump(unsigned char *p, int len) printk("<----------\n"); data_dump(p, len); } - g_rx_cnt++; - return; } - +#endif /* --------------------------------------------------------------------------*/ /** * @brief netdev_ioctl @@ -197,17 +193,11 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct am_net_private *priv = netdev_priv(dev); int ret; - - if (!netif_running(dev)) - return -EINVAL; - - if (!priv->phydev) - return -EINVAL; - + if (!netif_running(dev)) return -EINVAL; + if (!priv->phydev) return -EINVAL; spin_lock(&priv->lock); ret = phy_mii_ioctl(priv->phydev, rq, cmd); spin_unlock(&priv->lock); - return ret; } @@ -224,31 +214,8 @@ int init_rxtx_rings(struct net_device *dev) { struct am_net_private *np = netdev_priv(dev); int i; -#ifndef DMA_USE_SKB_BUF - unsigned long tx = 0, rx = 0; -#endif -#ifdef DMA_USE_MALLOC_ADDR - rx = (unsigned long)kmalloc((RX_RING_SIZE) * np->rx_buf_sz, GFP_KERNEL | GFP_DMA); - if (rx == 0) { - printk("error to alloc Rx ring buf\n"); - return -1; - } - tx = (unsigned long)kmalloc((TX_RING_SIZE) * np->rx_buf_sz, GFP_KERNEL | GFP_DMA); - if (tx == 0) { - kfree((void *)rx); - printk("error to alloc Tx ring buf\n"); - return -1; - } -#elif defined(DMA_USE_SKB_BUF) - //not needed -#else - tx = TX_BUF_ADDR; - rx = RX_BUF_ADDR; -#endif - /* Fill in the Rx buffers. Handle allocation failure gracefully. */ for (i = 0; i < RX_RING_SIZE; i++) { -#ifdef DMA_USE_SKB_BUF struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz); np->rx_ring[i].skb = skb; if (skb == NULL) { @@ -257,27 +224,17 @@ int init_rxtx_rings(struct net_device *dev) skb_reserve(skb, 2); /* 16 byte alignd for ip */ skb->dev = dev; /* Mark as being used by this device. */ np->rx_ring[i].buf = (unsigned long)skb->data; -#else - np->rx_ring[i].skb = NULL; - np->rx_ring[i].buf = (rx + i * np->rx_buf_sz); //(unsigned long )skb->data; -#endif np->rx_ring[i].buf_dma = dma_map_single(&dev->dev, (void *)np->rx_ring[i].buf, np->rx_buf_sz, DMA_FROM_DEVICE); np->rx_ring[i].count = (DescChain) | (np->rx_buf_sz & DescSize1Mask); np->rx_ring[i].status = (DescOwnByDma); np->rx_ring[i].next_dma = &np->rx_ring_dma[i + 1]; np->rx_ring[i].next = &np->rx_ring[i + 1]; - } - np->rx_ring[RX_RING_SIZE - 1].next_dma = &np->rx_ring_dma[0]; np->rx_ring[RX_RING_SIZE - 1].next = &np->rx_ring[0]; /* Initialize the Tx descriptors */ for (i = 0; i < TX_RING_SIZE; i++) { -#ifdef DMA_USE_SKB_BUF np->tx_ring[i].buf = 0; -#else - np->tx_ring[i].buf = (tx + i * np->rx_buf_sz); -#endif np->tx_ring[i].status = 0; np->tx_ring[i].count = (DescChain) | (np->rx_buf_sz & DescSize1Mask); @@ -292,8 +249,6 @@ int init_rxtx_rings(struct net_device *dev) np->last_rx = &np->rx_ring[RX_RING_SIZE - 1]; CACHE_WSYNC(np->tx_ring, sizeof(struct _tx_desc)*TX_RING_SIZE); CACHE_WSYNC(np->rx_ring, sizeof(struct _rx_desc)*RX_RING_SIZE); - - return 0; } @@ -311,35 +266,21 @@ static int alloc_ringdesc(struct net_device *dev) struct am_net_private *np = netdev_priv(dev); np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); -#ifdef USE_COHERENT_MEMORY - np->rx_ring = dma_alloc_coherent(&dev->dev, - sizeof(struct _rx_desc) * RX_RING_SIZE, - (dma_addr_t *)&np->rx_ring_dma, GFP_KERNEL); -#else np->rx_ring = kmalloc(sizeof(struct _rx_desc) * RX_RING_SIZE, GFP_KERNEL | GFP_DMA); np->rx_ring_dma = (void*)virt_to_phys(np->rx_ring); -#endif if (!np->rx_ring) { return -ENOMEM; } - if (!IS_CACHE_ALIGNED(np->rx_ring)) { printk("Error the alloc mem is not cache aligned(%p)\n", np->rx_ring); } printk("NET MDA descpter start addr=%p\n", np->rx_ring); -#ifdef USE_COHERENT_MEMORY - np->tx_ring = dma_alloc_coherent(&dev->dev, - sizeof(struct _tx_desc) * TX_RING_SIZE , - (dma_addr_t *)&np->tx_ring_dma, GFP_KERNEL); -#else np->tx_ring = kmalloc(sizeof(struct _tx_desc) * TX_RING_SIZE, GFP_KERNEL | GFP_DMA); np->tx_ring_dma = (void*)virt_to_phys(np->tx_ring); -#endif if (init_rxtx_rings(dev)) { printk("init rx tx ring failed!!\n"); return -1; } - return 0; } @@ -375,24 +316,11 @@ static int free_ringdesc(struct net_device *dev) np->tx_ring[i].skb = NULL; } if (np->rx_ring) { -#ifdef USE_COHERENT_MEMORY - dma_free_coherent(&dev->dev, - sizeof(struct _rx_desc) * RX_RING_SIZE , - np->rx_ring, (dma_addr_t)np->rx_ring_dma); // for apollo -#else kfree(np->rx_ring); -#endif } - np->rx_ring = NULL; if (np->tx_ring) { -#ifdef USE_COHERENT_MEMORY - dma_free_coherent(&dev->dev, - sizeof(struct _tx_desc) * TX_RING_SIZE , - np->tx_ring, (dma_addr_t)np->tx_ring_dma); // for apollo -#else kfree(np->tx_ring); -#endif } np->tx_ring = NULL; return 0; @@ -409,66 +337,68 @@ static int free_ringdesc(struct net_device *dev) * @return */ /* --------------------------------------------------------------------------*/ -static inline int update_status(struct net_device *dev, unsigned long status, - unsigned long mask) +// rt_tasklet +__attribute__((flatten)) void net_rt_update_status(unsigned long dev_instance) { + struct net_device *dev = (struct net_device *)dev_instance; struct am_net_private *np = netdev_priv(dev); - int need_reset = 0; - int need_rx_restart = 0; - int res = 0; - if(status & GMAC_MMC_Interrupt){ - printk("ETH_MMC_ipc_intr_rx = %x\n",readl((void*)(np->base_addr + ETH_MMC_ipc_intr_rx))); - printk("ETH_MMC_intr_rx = %x\n",readl((void*)(np->base_addr + ETH_MMC_intr_rx))); - } - - if (status & NOR_INTR_EN) { //Normal Interrupts Process - if (status & TX_INTR_EN) { //Transmit Interrupt Process + if (likely(np->status & NOR_INTR_EN)) { //Normal Interrupts Process + if (likely(np->status & RX_INTR_EN)) { //Receive Interrupt Process + writel((1 << 6 | 1 << 16), (void*)(np->base_addr + ETH_DMA_5_Status)); + tasklet_schedule(&np->rx_tasklet); + } + if (likely(np->status & TX_INTR_EN)) { //Transmit Interrupt Process writel(1,(void*)(np->base_addr + ETH_DMA_1_Tr_Poll_Demand)); netif_wake_queue(dev); writel((1 << 0 | 1 << 16),(void*)(np->base_addr + ETH_DMA_5_Status)); - res |= 1; - } - if (status & RX_INTR_EN) { //Receive Interrupt Process - writel((1 << 6 | 1 << 16), (void*)(np->base_addr + ETH_DMA_5_Status)); - res |= 2; + tasklet_schedule(&np->tx_tasklet); } - if (status & EARLY_RX_INTR_EN) { + } + tasklet_schedule(&np->st_tasklet); // net_update_stats() +} + +// This tasklet does all the error checks +__attribute__((flatten)) void net_update_status(unsigned long dev_instance) +{ + unsigned long status; + struct net_device *dev = (struct net_device *)dev_instance; + struct am_net_private *np = netdev_priv(dev); + status = np->status; + if (likely(status & NOR_INTR_EN)) { //Normal Interrupts Process + if (unlikely(status & EARLY_RX_INTR_EN)) { writel((EARLY_RX_INTR_EN | NOR_INTR_EN),(void*) (np->base_addr + ETH_DMA_5_Status)); } - if (status & TX_BUF_UN_EN) { + if (unlikely(status & TX_BUF_UN_EN)) { writel((1 << 2 | 1 << 16), (void*)(np->base_addr + ETH_DMA_5_Status)); - res |= 1; + tasklet_schedule(&np->tx_tasklet); //this error will cleard in start tx... - if (g_debug > 1) { - printk(KERN_WARNING "[" DRV_NAME "]" "Tx bufer unenable\n"); - } } - } else if (status & ANOR_INTR_EN) { //Abnormal Interrupts Process + } else if (unlikely(status & ANOR_INTR_EN)) { //Abnormal Interrupts Process if (status & RX_BUF_UN) { writel((RX_BUF_UN | ANOR_INTR_EN),(void*) (np->base_addr + ETH_DMA_5_Status)); np->stats.rx_over_errors++; - need_rx_restart++; - res |= 2; - //printk(KERN_WARNING DRV_NAME "Receive Buffer Unavailable\n"); - if (g_debug > 1) { - printk(KERN_WARNING "[" DRV_NAME "]" "Rx bufer unenable\n"); - } + writel(1, (void*)(np->base_addr + ETH_DMA_2_Re_Poll_Demand)); + tasklet_schedule(&np->rx_tasklet); } if (status & RX_STOP_EN) { writel((RX_STOP_EN | ANOR_INTR_EN), (void*)(np->base_addr + ETH_DMA_5_Status)); - need_rx_restart++; - res |= 2; + writel(1, (void*)(np->base_addr + ETH_DMA_2_Re_Poll_Demand)); + tasklet_schedule(&np->rx_tasklet); } if (status & RX_WATCH_TIMEOUT) { writel((RX_WATCH_TIMEOUT | ANOR_INTR_EN), (void*)( np->base_addr + ETH_DMA_5_Status)); - need_rx_restart++; + writel(1, (void*)(np->base_addr + ETH_DMA_2_Re_Poll_Demand)); } if (status & FATAL_BUS_ERROR) { writel((FATAL_BUS_ERROR | ANOR_INTR_EN), (void*)(np->base_addr + ETH_DMA_5_Status)); - need_reset++; + printk(KERN_WARNING DRV_NAME "system reset\n"); + free_ringdesc(dev); + writel(0, (void*)(np->base_addr + ETH_DMA_6_Operation_Mode)); + writel(0, (void*)(np->base_addr + ETH_DMA_7_Interrupt_Enable)); + reset_mac(dev); printk(KERN_WARNING "[" DRV_NAME "]" "fatal bus error\n"); } if (status & EARLY_TX_INTR_EN) { @@ -482,7 +412,7 @@ static inline int update_status(struct net_device *dev, unsigned long status, (void*)(np->base_addr + ETH_DMA_5_Status)); writel(1,(void*)(np->base_addr + ETH_DMA_1_Tr_Poll_Demand)); netif_wake_queue(dev); - res |= 1; + tasklet_schedule(&np->tx_tasklet); } if (status & TX_JABBER_TIMEOUT) { writel((TX_JABBER_TIMEOUT | ANOR_INTR_EN), @@ -496,8 +426,8 @@ static inline int update_status(struct net_device *dev, unsigned long status, writel((RX_FIFO_OVER | ANOR_INTR_EN), (void*)( np->base_addr + ETH_DMA_5_Status)); np->stats.rx_fifo_errors++; - need_rx_restart++; - res |= 2; + writel(1, (void*)(np->base_addr + ETH_DMA_2_Re_Poll_Demand)); + tasklet_schedule(&np->rx_tasklet); printk(KERN_WARNING "[" DRV_NAME "]" "Rx fifo over\n"); } if (status & TX_UNDERFLOW) { @@ -507,20 +437,9 @@ static inline int update_status(struct net_device *dev, unsigned long status, writel(1,(void*)(np->base_addr + ETH_DMA_1_Tr_Poll_Demand)); netif_wake_queue(dev); np->first_tx = 1; - res |= 1; + tasklet_schedule(&np->tx_tasklet); } } - - if (need_reset) { - printk(KERN_WARNING DRV_NAME "system reset\n"); - free_ringdesc(dev); - writel(0, (void*)(np->base_addr + ETH_DMA_6_Operation_Mode)); - writel(0, (void*)(np->base_addr + ETH_DMA_7_Interrupt_Enable)); - reset_mac(dev); - } else if (need_rx_restart) { - writel(1, (void*)(np->base_addr + ETH_DMA_2_Re_Poll_Demand)); - } - return res; } /* --------------------------------------------------------------------------*/ @@ -532,7 +451,6 @@ static inline int update_status(struct net_device *dev, unsigned long status, /* --------------------------------------------------------------------------*/ static void inline print_rx_error_log(unsigned long status) { - if (status & DescRxTruncated) { printk(KERN_WARNING "Descriptor Error desc-mask[%d]\n", DescRxTruncated); @@ -579,64 +497,32 @@ static void inline print_rx_error_log(unsigned long status) * @param dev_instance */ /* --------------------------------------------------------------------------*/ -void net_tasklet(unsigned long dev_instance) +// todo: need to figure out how to either get multiple RX, TX queues on diff processors +// or quit hammering CPU0 so much. Perhaps split the priv->phy info into TX, RX versions +// note: problem with high CPU0 irq is due to usb1, uart, and vsync IRQ +__attribute__((flatten)) void net_tasklettx(unsigned long dev_instance) { struct net_device *dev = (struct net_device *)dev_instance; struct am_net_private *np = netdev_priv(dev); - int len; - int result; unsigned long flags; -#ifndef DMA_USE_SKB_BUF - struct sk_buff *skb = NULL; -#endif - if (!running) { - goto release; - } - - /* handle pmt event */ - result = np->pmt; - np->pmt = 0; - if (result & (1 << 5)) { - printk("*******************************\n"); - printk("******** Magic Packet Received!\n"); - printk("*******************************\n"); - } - if (result & (1 << 6)) { - printk("*******************************\n"); - printk("******** Wake-Up Frame Received!\n"); - printk("*******************************\n"); - } - - /* handle normal tx-rx */ - result = np->int_rx_tx; - np->int_rx_tx = 0; - - if (result & 1) { - struct _tx_desc *c_tx, *tx = NULL; - int rx_count = 0; + struct _tx_desc *c_tx, *tx = NULL; + /* handle normal tx */ c_tx = (void *)readl((void*)(np->base_addr + ETH_DMA_18_Curr_Host_Tr_Descriptor)); c_tx = np->tx_ring + (c_tx - np->tx_ring_dma); tx = np->start_tx; CACHE_RSYNC(tx, sizeof(struct _tx_desc)); - while (tx != NULL && tx != c_tx && !(tx->status & DescOwnByDma)) { -#ifdef DMA_USE_SKB_BUF - rx_count++; - + while (likely(tx != NULL && tx != c_tx && !(tx->status & DescOwnByDma))) { if(unlikely(!spin_trylock_irqsave(&np->lock,flags))) - { - break; - } - if (tx->skb != NULL) { + { + break; + } + if (likely(tx->skb != NULL)) { //clear to next send; - if (np->tx_full) { + if (likely(np->tx_full)) { netif_wake_queue(dev); np->tx_full = 0; } - if (g_debug > 2) { - printk("send data ok len=%d\n", tx->skb->len); - } - tx_data_dump((unsigned char *)tx->buf, tx->skb->len); if (tx->buf_dma != 0) { dma_unmap_single(&dev->dev, tx->buf_dma, np->rx_buf_sz, DMA_TO_DEVICE); } @@ -650,32 +536,29 @@ void net_tasklet(unsigned long dev_instance) break; } spin_unlock_irqrestore(&np->lock, flags); -#else - tx->status = 0; - CACHE_WSYNC(tx, sizeof(struct _tx_desc)); - if (np->tx_full) { - netif_wake_queue(dev); - np->tx_full = 0; - } -#endif tx = tx->next; CACHE_RSYNC(tx, sizeof(struct _tx_desc)); - if(rx_count == g_txnum) - break; } np->start_tx = tx; - } - if (result & 2) { - struct _rx_desc *c_rx, *rx = NULL; - int rx_cnt = 0; + writel(np->irq_mask, (void*)(np->base_addr + ETH_DMA_7_Interrupt_Enable)); +} + +// Handle RX packets in this tasklet +__attribute__((flatten)) void net_taskletrx(unsigned long dev_instance) +{ + struct net_device *dev = (struct net_device *)dev_instance; + struct am_net_private *np = netdev_priv(dev); + int len; + + struct _rx_desc *c_rx, *rx = NULL; + /* handle normal rx */ c_rx = (void *)readl((void*)(np->base_addr + ETH_DMA_19_Curr_Host_Re_Descriptor)); c_rx = np->rx_ring + (c_rx - np->rx_ring_dma); rx = np->last_rx->next; - while (rx != NULL) { + while (likely(rx != NULL)) { CACHE_RSYNC(rx, sizeof(struct _rx_desc)); - if (!(rx->status & (DescOwnByDma))) { + if (likely(!(rx->status & (DescOwnByDma)))) { int ip_summed = CHECKSUM_UNNECESSARY; - rx_cnt++; len = (rx->status & DescFrameLengthMask) >> DescFrameLengthShift; if (unlikely(len < 18 || len > np->rx_buf_sz)) { //here is fatal error we drop it ; np->stats.rx_dropped++; @@ -694,66 +577,38 @@ void net_tasklet(unsigned long dev_instance) } } len = len - 4; //clear the crc -#ifdef DMA_USE_SKB_BUF - if (rx->skb == NULL) { + if (unlikely(rx->skb == NULL)) { printk("NET skb pointer error!!!\n"); break; } - - if (rx->buf_dma != 0) { + if (likely(rx->buf_dma != 0)) { dma_unmap_single(&dev->dev, rx->buf_dma,/* np->rx_buf_sz*/len, DMA_FROM_DEVICE); } if (rx->skb->len > 0) { - printk("skb have data before,skb=%p,len=%d\n", rx->skb, rx->skb->len); - rx->skb = NULL; - goto to_next; - } - skb_put(rx->skb, len); - rx->skb->dev = dev; - rx->skb->protocol = - eth_type_trans(rx->skb, dev); - /*we have checked in hardware; - we not need check again */ - rx->skb->ip_summed = ip_summed; + printk("skb have data before,skb=%p,len=%d\n", rx->skb, rx->skb->len); + rx->skb = NULL; + goto to_next; + } + skb_put(rx->skb, len); + rx->skb->dev = dev; + rx->skb->protocol = eth_type_trans(rx->skb, dev); + /*we have checked in hardware; we do not need to check again */ + rx->skb->ip_summed = ip_summed; rx->buf_dma = 0; netif_rx(rx->skb); - if (g_debug > 3) { - printk("receive skb=%p\n", rx->skb); - } rx->skb = NULL; -#else - skb = dev_alloc_skb(len); - if (skb == NULL) { - np->stats.rx_dropped++; - printk("error to alloc skb\n"); - break; - } - skb_reserve(skb, 2); - skb_put(skb, len); - if (rx->buf_dma != NULL) { - dma_unmap_single(&dev->dev, (void *)rx->buf_dma, np->rx_buf_sz, DMA_FROM_DEVICE); - } - memcpy(skb->data, (void *)rx->buf, len); - skb->dev = dev; - skb->protocol = eth_type_trans(skb, dev); - skb->ip_summed = ip_summed; - netif_rx(skb); -#endif dev->last_rx = jiffies; np->stats.rx_packets++; np->stats.rx_bytes += len; - - if (g_debug > 3) { - printk("receive data len=%d\n", len); - } +#ifdef M_DEBUG_ON rx_data_dump((unsigned char *)rx->buf,len); +#endif to_next: -#ifdef DMA_USE_SKB_BUF if (rx->skb) { dev_kfree_skb_any(rx->skb); } rx->skb = dev_alloc_skb(np->rx_buf_sz ); - if (rx->skb == NULL) { + if (unlikely(rx->skb == NULL)) { printk(KERN_ERR "error to alloc the skb\n"); rx->buf = 0; rx->buf_dma = 0; @@ -763,12 +618,8 @@ void net_tasklet(unsigned long dev_instance) CACHE_WSYNC(rx, sizeof(struct _rx_desc)); break; } - if (g_debug > 3) { - printk("new malloc skb=%p\n", rx->skb); - } skb_reserve(rx->skb, 2); rx->buf = (unsigned long)rx->skb->data; -#endif rx->buf_dma = dma_map_single(&dev->dev, (void *)rx->buf, (unsigned long)np->rx_buf_sz, DMA_FROM_DEVICE); //invalidate for next dma in; rx->count = (DescChain) | (np->rx_buf_sz & DescSize1Mask); rx->status = DescOwnByDma; @@ -778,12 +629,7 @@ void net_tasklet(unsigned long dev_instance) } else { break; } - if(rx_cnt == g_rxnum) - break; - } - } -release: writel(np->irq_mask, (void*)(np->base_addr + ETH_DMA_7_Interrupt_Enable)); } @@ -797,21 +643,18 @@ void net_tasklet(unsigned long dev_instance) * @return */ /* --------------------------------------------------------------------------*/ -static irqreturn_t intr_handler(int irq, void *dev_instance) +// This routine has all un-necessary if or variables removed to make it fast +static __attribute__((flatten)) irqreturn_t intr_handler(int irq, void *dev_instance) { struct net_device *dev = (struct net_device *)dev_instance; struct am_net_private *np = netdev_priv(dev); - unsigned long status = 0; - unsigned long mask = 0; writel(0, (void*)(np->base_addr + ETH_DMA_7_Interrupt_Enable));//disable irq - np->pmt = readl((void*)(np->base_addr + ETH_MAC_PMT_Control_and_Status)); - status = readl((void*)(np->base_addr + ETH_DMA_5_Status)); - mask = readl((void*)(np->base_addr + ETH_MAC_Interrupt_Mask)); - np->int_rx_tx |= update_status(dev, status, mask); - tasklet_schedule(&np->rx_tasklet); + np->status = readl((void*)(np->base_addr + ETH_DMA_5_Status)); + tasklet_hi_schedule(&np->rt_tasklet); return IRQ_HANDLED; } +// PMT not used in this driver, could remove static int mac_pmt_enable(unsigned int enable) { struct am_net_private *np = netdev_priv(my_ndev); @@ -869,7 +712,6 @@ static int mac_pmt_enable(unsigned int enable) default: break; } - } else { /* setup pmt mode */ val = 0; @@ -877,7 +719,6 @@ static int mac_pmt_enable(unsigned int enable) /* setup Wake-Up Frame Filter */ } - return 0; } @@ -890,55 +731,26 @@ static int mac_pmt_enable(unsigned int enable) * @return */ /* --------------------------------------------------------------------------*/ -//#undef CONFIG_AML_NAND_KEY -#ifdef CONFIG_AML_NAND_KEY -extern int get_aml_key_kernel(const char* key_name, unsigned char* data, int ascii_flag); -extern int extenal_api_key_set_version(char *devvesion); -static char print_buff[1025]; -void read_mac_from_nand(struct net_device *ndev) -{ - int ret; - u8 mac[ETH_ALEN]; - char *endp; - int j; - ret = get_aml_key_kernel("mac", print_buff, 0); - extenal_api_key_set_version("nand3"); - printk("ret = %d\nprint_buff=%s\n", ret, print_buff); - if (ret >= 0) { - strcpy(ndev->dev_addr, print_buff); - for(j=0; j < ETH_ALEN; j++) - { - mac[j] = simple_strtol(&ndev->dev_addr[3 * j], &endp, 16); - printk("%d : %d\n", j, mac[j]); - } - memcpy(ndev->dev_addr, mac, ETH_ALEN); - } - -} -#endif static int aml_mac_init(struct net_device *ndev) { struct am_net_private *np = netdev_priv(ndev); unsigned long val; - + int k; +// based on an old am_net8218.c below should be mac reset writel(1, (void*)(np->base_addr + ETH_DMA_0_Bus_Mode)); +// below waits for mac to reset + for (k=0;(readl((void*)(np->base_addr + ETH_DMA_6_Operation_Mode)) & 1) && k<1000;k++) udelay(1); writel(0x00100800,(void*)(np->base_addr + ETH_DMA_0_Bus_Mode)); printk("--1--write mac add to:"); - data_dump(ndev->dev_addr, 6); -#ifdef CONFIG_AML_NAND_KEY - read_mac_from_nand(ndev); -#endif printk("--2--write mac add to:"); data_dump(ndev->dev_addr, 6); write_mac_addr(ndev, ndev->dev_addr); - val = 0xc80c | //8<<8 | 8<<17; //tx and rx all 8bit mode; 1 << 10 | 1 << 24; //checksum offload enabled #ifdef MAC_LOOPBACK_TEST val |= 1 << 12; //mac loop back #endif - writel(val, (void*)(np->base_addr + ETH_MAC_0_Configuration)); val = 1 << 4;/*receive all muticast*/ @@ -957,12 +769,10 @@ static int aml_mac_init(struct net_device *ndev) /*don't start receive here */ printk("Current DMA mode=%x, set mode=%lx\n", readl((void*)(np->base_addr + ETH_DMA_6_Operation_Mode)), val); writel(val, (void*)(np->base_addr + ETH_DMA_6_Operation_Mode)); - - /* enable mac mpt mode */ - //mac_pmt_enable(1); return 0; } - +/*--------------------------*/ +// https://www.kernel.org/doc/Documentation/networking/phy.txt static void aml_adjust_link(struct net_device *dev) { struct am_net_private *priv = netdev_priv(dev); @@ -970,61 +780,57 @@ static void aml_adjust_link(struct net_device *dev) unsigned long flags; int new_state = 0; int val; - if (phydev == NULL) return; - +//#define P_PREG_ETHERNET_ADDR0 CBUS_REG_ADDR(PREG_ETHERNET_ADDR0) +//#define PREG_ETHERNET_ADDR0 0x2042 ///../ucode/register.h:450 spin_lock_irqsave(&priv->lock, flags); - if(phydev->phy_id == INTERNALPHY_ID){ + if(phydev->phy_id == INTERNALPHY_ID) { val = (8<<27)|(7 << 24)|(1<<16)|(1<<15)|(1 << 13)|(1 << 12)|(4 << 4)|(0 << 1); PERIPHS_SET_BITS(P_PREG_ETHERNET_ADDR0, val); } if (phydev->link) { +//#define ETH_MAC_0_Configuration (0x0000) u32 ctrl = readl((void*)(priv->base_addr + ETH_MAC_0_Configuration)); - /* Now we make sure that we can be in full duplex mode. * If not, we operate in half-duplex mode. */ if (phydev->duplex != priv->oldduplex) { new_state = 1; if (!(phydev->duplex)) { + printk("[adjust link] -> eth: half-duplex\n"); ctrl &= ~((1 << 11)|(7<< 17)|(3<<5)); if(new_maclogic != 0) ctrl |= (4 << 17); ctrl |= (3 << 5); - g_rxnum = 128; - g_txnum = 128; } else { + printk("[adjust link] -> eth: full-duplex\n"); ctrl &= ~((7 << 17)|(3 << 5)); ctrl |= (1 << 11); if(new_maclogic != 0) ctrl |= (2 << 17); - g_rxnum = 128; - g_txnum = 128; } - priv->oldduplex = phydev->duplex; } - if (phydev->speed != priv->speed) { + printk("[adjust link] -> eth: phy_speed <> priv_speed)\n"); new_state = 1; - if(new_maclogic != 0) - PERIPHS_CLEAR_BITS(P_PREG_ETHERNET_ADDR0, 1); + if(new_maclogic != 0) PERIPHS_CLEAR_BITS(P_PREG_ETHERNET_ADDR0, 1); switch (phydev->speed) { case 1000: - ctrl &= ~((1 << 14)|(1 << 15));//1000m - ctrl |= (1 << 13);//1000m + ctrl &= ~((1 << 14)|(1 << 15));//1000m + ctrl |= (1 << 13);//1000m break; case 100: ctrl |= (1 << 14)|(1 << 15); - if(new_maclogic !=0) - PERIPHS_SET_BITS(P_PREG_ETHERNET_ADDR0, (1 << 1)); + printk("[adjust link] -> eth: switching to RGMII 100\n"); + if(new_maclogic !=0) PERIPHS_SET_BITS(P_PREG_ETHERNET_ADDR0, (1 << 1)); break; case 10: ctrl &= ~((1 << 14)|(3 << 5));//10m half backoff = 00 - if(new_maclogic !=0) - PERIPHS_CLEAR_BITS(P_PREG_ETHERNET_ADDR0, (1 << 1)); - if(phydev->phy_id == INTERNALPHY_ID){ + printk("[adjust link] -> eth: switching to RGMII 10\n"); + if(new_maclogic !=0) PERIPHS_CLEAR_BITS(P_PREG_ETHERNET_ADDR0, (1 << 1)); + if(phydev->phy_id == INTERNALPHY_ID) { val =0x4100b040; WRITE_CBUS_REG(P_PREG_ETHERNET_ADDR0, val); } @@ -1034,13 +840,10 @@ static void aml_adjust_link(struct net_device *dev) " or 100!\n", dev->name, phydev->speed); break; } - if(new_maclogic !=0) - PERIPHS_SET_BITS(P_PREG_ETHERNET_ADDR0, 1); + if(new_maclogic !=0) PERIPHS_SET_BITS(P_PREG_ETHERNET_ADDR0, 1); priv->speed = phydev->speed; } - writel(ctrl, (void*)(priv->base_addr + ETH_MAC_0_Configuration)); - if (!priv->oldlink) { new_state = 1; priv->oldlink = 1; @@ -1050,26 +853,16 @@ static void aml_adjust_link(struct net_device *dev) priv->oldlink = 0; priv->speed = 0; priv->oldduplex = -1; - } - if (new_state){ - if(new_maclogic == 1) - read_macreg(); + if(new_maclogic == 1) read_macreg(); + printk("[adjust link -> eth: am_adjust_link state change (new_state=true)\n"); phy_print_status(phydev); } - spin_unlock_irqrestore(&priv->lock, flags); - -#ifdef LOOP_BACK_TEST -#ifdef PHY_LOOPBACK_TEST - mdio_write(priv->mii, priv->phy_addr, MII_BMCR, BMCR_LOOPBACK | BMCR_SPEED100 | BMCR_FULLDPLX); -#endif - start_test(priv->dev); -#endif } - +// Init phy, detect it and attach static int aml_phy_init(struct net_device *dev) { struct am_net_private *priv = netdev_priv(dev); @@ -1091,7 +884,6 @@ static int aml_phy_init(struct net_device *dev) pr_err("%s: have no attached PHY\n", dev->name); return -1; } - snprintf(bus_id, MII_BUS_ID_SIZE, "%x", 0); snprintf(phy_id, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id, priv->phy_addr); @@ -1104,7 +896,6 @@ static int aml_phy_init(struct net_device *dev) pr_err("%s: Could not attach to PHY\n", dev->name); return PTR_ERR(phydev); } - /* * Broken HW is sometimes missing the pull-up resistor on the * MDIO line, which results in reads to non-existent devices returning @@ -1118,13 +909,11 @@ static int aml_phy_init(struct net_device *dev) } pr_debug("aml_phy_init: %s: attached to PHY (UID 0x%x)" " Link = %d\n", dev->name, phydev->phy_id, phydev->link); - priv->phydev = phydev; - if (priv->phydev) - phy_start(priv->phydev); - + if (priv->phydev) phy_start(priv->phydev); return 0; } + static void read_macreg(void) { int reg = 0; @@ -1165,7 +954,6 @@ static int reset_mac(struct net_device *dev) tmp = readl((void*)(np->base_addr + ETH_MAC_6_Flow_Control)); tmp |= (1 << 1) | (1 << 0); writel(tmp, (void*)(np->base_addr + ETH_MAC_6_Flow_Control)); - tmp = readl((void*)(np->base_addr + ETH_DMA_6_Operation_Mode)); tmp |= (1 << 1); /*start receive*/ writel(tmp, (void*)(np->base_addr + ETH_DMA_6_Operation_Mode)); @@ -1197,15 +985,12 @@ static int ethernet_reset(struct net_device *dev) printk(KERN_INFO "can't alloc ring desc!err=%d\n", res); goto out_err; } - res = aml_phy_init(dev); if (res != 0) { printk(KERN_INFO "init phy failed! err=%d\n", res); goto out_err; } - aml_mac_init(dev); - np->first_tx = 1; tmp = readl((void*)(np->base_addr + ETH_DMA_6_Operation_Mode));//tx enable tmp |= (7 << 14) | (1 << 13); @@ -1238,33 +1023,30 @@ static int netdev_open(struct net_device *dev) } printk(KERN_INFO "netdev_open\n"); res = ethernet_reset(dev); - if (res != 0) { printk(KERN_INFO "ethernet_reset err=%d\n", res); goto out_err; } - res = request_irq(dev->irq, &intr_handler, IRQF_SHARED, dev->name, dev); if (res) { printk(KERN_ERR "%s: request_irq error %d.,err=%d\n", dev->name, dev->irq, res); goto out_err; } - if (g_debug > 0) printk(KERN_DEBUG "%s: opened (irq %d).\n", dev->name, dev->irq); - val = readl((void*)(np->base_addr + ETH_DMA_6_Operation_Mode)); val |= (1 << 1); /*start receive*/ writel(val, (void*)(np->base_addr + ETH_DMA_6_Operation_Mode)); running = 1; - if(new_maclogic == 1){ + if(new_maclogic == 1){ writel(0xffffffff,(void*)(np->base_addr + ETH_MMC_ipc_intr_mask_rx)); writel(0xffffffff,(void*)(np->base_addr + ETH_MMC_intr_mask_rx)); } +// short delay before starting queue, found this in most drivers + mdelay(10); netif_start_queue(dev); - return 0; out_err: running = 0; @@ -1284,11 +1066,9 @@ static int netdev_close(struct net_device *dev) { struct am_net_private *np = netdev_priv(dev); unsigned long val; - if (!running) { return 0; } - if (np->phydev && savepowermode) { np->phydev->drv->suspend(np->phydev); } @@ -1296,26 +1076,23 @@ static int netdev_close(struct net_device *dev) phy_stop(np->phydev); phy_disconnect(np->phydev); } - running = 0; - writel(0, (void*)(np->base_addr + ETH_DMA_6_Operation_Mode)); writel(0, (void*)(np->base_addr + ETH_DMA_7_Interrupt_Enable)); val = readl((void*)(np->base_addr + ETH_DMA_5_Status)); while ((val & (7 << 17)) || (val & (7 << 20))) { /*DMA not finished?*/ - printk(KERN_ERR "ERROR! DMA is not stoped, val=%lx!\n", val); + printk(KERN_ERR "ERROR! DMA is not stopped, val=%lx!\n", val); msleep(1);//waiting all dma is finished!! val = readl((void*)(np->base_addr + ETH_DMA_5_Status)); } if (g_debug > 0) { - printk(KERN_INFO "NET DMA is stoped, ETH_DMA_Status=%lx!\n", val); + printk(KERN_INFO "NET DMA is stopped, ETH_DMA_Status=%lx!\n", val); } disable_irq(dev->irq); netif_carrier_off(dev); netif_stop_queue(dev); free_ringdesc(dev); free_irq(dev->irq, dev); - if (g_debug > 0) { printk(KERN_DEBUG "%s: closed\n", dev->name); } @@ -1332,28 +1109,27 @@ static int netdev_close(struct net_device *dev) * @return */ /* --------------------------------------------------------------------------*/ -static int start_tx(struct sk_buff *skb, struct net_device *dev) +static int __attribute__((flatten)) start_tx(struct sk_buff *skb, struct net_device *dev) { struct am_net_private *np = netdev_priv(dev); int tmp; struct _tx_desc *tx; unsigned long flags; dev->trans_start = jiffies; - if (np->first_tx) { - if(new_maclogic == 1) - read_macreg(); - } - if (!running) { - return -1; - } +// test removing these since won't get scheduled if not running +// if (!running) { +// return -1; +// } +#ifdef M_DEBUG_ON if (g_debug > 2) { printk(KERN_DEBUG "%s: Transmit frame queued\n", dev->name); } - tasklet_disable(&np->rx_tasklet); +#endif + tasklet_disable(&np->tx_tasklet); spin_lock_irqsave(&np->lock, flags); writel(0,(void*)(np->base_addr + ETH_DMA_7_Interrupt_Enable)); - if (np->last_tx != NULL) { + if (likely(np->last_tx != NULL)) { tx = np->last_tx->next; } else { tx = &np->tx_ring[0]; @@ -1361,13 +1137,14 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) CACHE_RSYNC(tx, sizeof(*tx)); if (tx->status & DescOwnByDma) { //spin_unlock_irqrestore(&np->lock, flags); +#ifdef M_DEBUG_ON if (g_debug > 2) { printk("tx queue is full \n"); } +#endif goto err; } -#ifdef DMA_USE_SKB_BUF - if (tx->skb != NULL) { + if (likely(tx->skb != NULL)) { if (tx->buf_dma != 0) { dma_unmap_single(&dev->dev, tx->buf_dma, np->rx_buf_sz, DMA_TO_DEVICE); } @@ -1375,9 +1152,6 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) } tx->skb = skb; tx->buf = (unsigned long)skb->data; -#else - memcpy((void *)tx->buf, skb->data, skb->len); -#endif tx->buf_dma = dma_map_single(&dev->dev, (void *)tx->buf, (unsigned long)(skb->len), DMA_TO_DEVICE); tx->count = ((skb->len << DescSize1Shift) & DescSize1Mask) | DescTxFirst | DescTxLast | DescTxIntEnable | DescChain; //|2<<27; (1<<25, ring end) if (skb->ip_summed == CHECKSUM_PARTIAL) { @@ -1388,23 +1162,16 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) np->stats.tx_packets++; np->stats.tx_bytes += skb->len; CACHE_WSYNC(tx, sizeof(*tx)); -#ifndef DMA_USE_SKB_BUF - dev_kfree_skb_any(skb); -#endif - if (np->first_tx) { + if (likely(np->first_tx)) { np->first_tx = 0; tmp = readl((void*)(np->base_addr + ETH_DMA_6_Operation_Mode)); tmp |= (7 << 14) | (1 << 13); writel(tmp, (void*)(np->base_addr + ETH_DMA_6_Operation_Mode)); - } else { - //ETH_DMA_1_Tr_Poll_Demand - // writel(1,(void*)(np->base_addr + ETH_DMA_1_Tr_Poll_Demand)); } - writel(1,(void*)(np->base_addr + ETH_DMA_1_Tr_Poll_Demand)); - writel(np->irq_mask, (void*)(np->base_addr + ETH_DMA_7_Interrupt_Enable)); + writel(np->irq_mask, (void*)(np->base_addr + ETH_DMA_7_Interrupt_Enable)); spin_unlock_irqrestore(&np->lock, flags); - tasklet_enable(&np->rx_tasklet); + tasklet_enable(&np->tx_tasklet); return NETDEV_TX_OK; err: np->tx_full = 1; @@ -1412,7 +1179,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); writel(np->irq_mask,(void*) (np->base_addr + ETH_DMA_7_Interrupt_Enable)); spin_unlock_irqrestore(&np->lock, flags); - tasklet_enable(&np->rx_tasklet); + tasklet_enable(&np->tx_tasklet); return NETDEV_TX_BUSY; } @@ -1443,7 +1210,6 @@ void test_loop_back(struct net_device *dev) i = 0; msleep(10); } - skb_put(skb, 1400); memset(skb->data, 0x55, skb->len); memcpy(skb->data, header, 16); @@ -1458,22 +1224,18 @@ void test_loop_back(struct net_device *dev) msleep(1); printk("send pkts=%ld, receive pkts=%ld\n", np->stats.tx_packets, np->stats.rx_packets); } - } } static void force_speed100_duplex_set(struct am_net_private *np) { int val; - val = readl((void*)(np->base_addr + ETH_MAC_0_Configuration)); val |= (1 << 11) | (1 << 14); writel(val, (void*)(np->base_addr + ETH_MAC_0_Configuration)); - PERIPHS_CLEAR_BITS(P_PREG_ETHERNET_ADDR0, 1); PERIPHS_SET_BITS(P_PREG_ETHERNET_ADDR0, (1 << 1)); PERIPHS_SET_BITS(P_PREG_ETHERNET_ADDR0, 1); - return; } /* --------------------------------------------------------------------------*/ @@ -1487,21 +1249,16 @@ void start_test(struct net_device *dev) { static int test_running = 0; struct am_net_private *np = netdev_priv(dev); - force_speed100_duplex_set(np); - if (test_running) { return ; } - kernel_thread((void *)test_loop_back, (void *)dev, CLONE_FS | CLONE_SIGHAND); test_running++; - } #endif static struct net_device_stats *get_stats(struct net_device *dev) { struct am_net_private *np = netdev_priv(dev); - return &np->stats; } @@ -1538,32 +1295,6 @@ static void tx_timeout(struct net_device *dev) * @param macaddr */ /* --------------------------------------------------------------------------*/ -/*static void get_mac_from_nand(struct net_device *dev, char *macaddr) -{ - int ret; - int use_nand_mac=0; - u8 mac[ETH_ALEN]; - - extenal_api_key_set_version("nand3"); - ret = get_aml_key_kernel("mac_wifi", print_buff, 0); - printk("ret = %d\nprint_buff=%s\n", ret, print_buff); - if (ret >= 0) { - strcpy(mac_addr, print_buff); - } - for(; j < ETH_ALEN; j++) - { - mac[j] = simple_strtol(&mac_addr[3 * j], &endp, 16); - printk("%d : %d\n", j, mac[j]); - } - memcpy(macaddr, mac, ETH_ALEN); -} -static void print_mac(char *macaddr) -{ - printk("write mac add to:"); - data_dump(macaddr, 6); -}*/ - - static void write_mac_addr(struct net_device *dev, char *macaddr) { @@ -1598,7 +1329,6 @@ static unsigned char inline chartonum(char c) return (c - 'a') + 10; } return 0; - } /* --------------------------------------------------------------------------*/ @@ -1615,10 +1345,25 @@ static void config_mac_addr(struct net_device *dev, void *mac) memcpy(dev->dev_addr, mac, 6); else random_ether_addr(dev->dev_addr); - write_mac_addr(dev, dev->dev_addr); } +// @steeve: this is disabled, because it is buggy +static void mac_from_efuse_to_DEFMAC(void) +{ + unsigned char mac[6]; + unsigned char *efuse_mac; + int i; + + efuse_mac = aml_efuse_get_item("mac"); + for (i = 0; i < 6 && efuse_mac[0] != '\0' && efuse_mac[1] != '\0'; i++) { + mac[i] = chartonum(efuse_mac[0]) << 4 | chartonum(efuse_mac[1]); + efuse_mac += 3; + } + memcpy(DEFMAC, mac, 6); + g_mac_addr_setup++; +} + /* --------------------------------------------------------------------------*/ /** * @brief mac_addr_set @@ -1630,18 +1375,18 @@ static void config_mac_addr(struct net_device *dev, void *mac) /* --------------------------------------------------------------------------*/ static int __init mac_addr_set(char *line) { - unsigned char mac[6]; - int i = 0; - for (i = 0; i < 6 && line[0] != '\0' && line[1] != '\0'; i++) { - mac[i] = chartonum(line[0]) << 4 | chartonum(line[1]); - line += 3; - } - memcpy(DEFMAC, mac, 6); - printk("******** uboot setup mac-addr: %x:%x:%x:%x:%x:%x\n", - DEFMAC[0], DEFMAC[1], DEFMAC[2], DEFMAC[3], DEFMAC[4], DEFMAC[5]); - g_mac_addr_setup++; + unsigned char mac[6]; + int i = 0; + for (i = 0; i < 6 && line[0] != '\0' && line[1] != '\0'; i++) { + mac[i] = chartonum(line[0]) << 4 | chartonum(line[1]); + line += 3; + } + memcpy(DEFMAC, mac, 6); + printk("******** uboot setup mac-addr: %x:%x:%x:%x:%x:%x\n", + DEFMAC[0], DEFMAC[1], DEFMAC[2], DEFMAC[3], DEFMAC[4], DEFMAC[5]); + g_mac_addr_setup++; - return 1; + return 1; } __setup("mac=", mac_addr_set); @@ -1708,13 +1453,9 @@ static void set_multicast_list(struct net_device *dev) char * addr; hash[0] = 0; hash[1] = 0; - printk("changed the Multicast,mcount=%d\n", netdev_mc_count(dev)); netdev_for_each_mc_addr(ha, dev) { addr = ha->addr; hash_id = phy_mc_hash(addr); - printk("add mac address:%02x:%02x:%02x:%02x:%02x:%02x,bit=%d\n", - addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], - hash_id); if (hash_id > 31) { hash[1] |= 1 << (hash_id - 32); @@ -1725,25 +1466,20 @@ static void set_multicast_list(struct net_device *dev) if((dev_hash[0]==hash[0]) && (dev_hash[1]==hash[1])) return; dev_hash[0]=hash[0] ; dev_hash[1]=hash[1]; - printk("set hash low=%x,high=%x\n", hash[0], hash[1]); writel(hash[1],(void*)(np->base_addr + ETH_MAC_2_Hash_Table_High)); writel(hash[0], (void*)(np->base_addr + ETH_MAC_3_Hash_Table_Low)); tmp = readl((void*)(np->base_addr + ETH_MAC_1_Frame_Filter)); tmp |= (1 << 2) | //hash filter 0; - printk("changed the filter setting to :%x\n", tmp); writel(tmp, (void*)(np->base_addr + ETH_MAC_1_Frame_Filter));//hash muticast } } static int set_mac_addr_n(struct net_device *dev, void *addr){ struct sockaddr *sa = addr; - printk("mac addr come in\n"); if (!is_valid_ether_addr(sa->sa_data)) return -EADDRNOTAVAIL; - memcpy(dev->dev_addr, sa->sa_data, ETH_ALEN); - write_mac_addr(dev, dev->dev_addr); return 0; } @@ -1768,7 +1504,6 @@ static int aml_ethtool_get_settings(struct net_device *dev, if (!np->phydev) return -ENODEV; - cmd->maxtxpkt = 1; cmd->maxrxpkt = 1; return phy_ethtool_gset(np->phydev, cmd); @@ -1781,7 +1516,6 @@ static int aml_ethtool_set_settings(struct net_device *dev, if (!np->phydev) return -ENODEV; - return phy_ethtool_sset(np->phydev, cmd); } @@ -1791,7 +1525,6 @@ static int aml_ethtool_nway_reset(struct net_device *netdev) if (!np->phydev) return -ENODEV; - return phy_start_aneg(np->phydev); } static void aml_eth_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) @@ -1810,7 +1543,6 @@ static int aml_eth_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) if (np->phydev == NULL) return -EOPNOTSUPP; - err = phy_ethtool_set_wol(np->phydev, wol); /* Given that amlogic mac works without the micrel PHY driver, * this debugging hint is useful to have. @@ -1875,31 +1607,15 @@ static int setup_net_device(struct net_device *dev) (1 << 13) | //FBI: Fatal Bus Error Interrupt (1) | //tx interrupt 0; + // @steeve: this is highly buggy (returning local pointers, for instance), + // so let's disable it, anyway we set the mac in the kernel cmdline + // mac_from_efuse_to_DEFMAC(); config_mac_addr(dev, DEFMAC); dev_alloc_name(dev, "eth%d"); memset(&np->stats, 0, sizeof(np->stats)); return res; } -/* -M6TV - 23 -M6TVlite - 24 -M8 - 25 -M6TVd - 26 -M8baby - 27 -G9TV - 28 -*/ -#if 0 -static unsigned int get_cpuid(){ - return READ_CBUS_REG(0x1f53)&0xff; -} -#endif /* --------------------------------------------------------------------------*/ /** * @brief probe_init @@ -1929,23 +1645,24 @@ static int probe_init(struct net_device *ndev) res = -EIO; goto error0; } - netif_carrier_off(ndev); - res = register_netdev(ndev); if (res != 0) { printk("can't register net device !\n"); res = -EBUSY; goto error0; } - tasklet_init(&priv->rx_tasklet, net_tasklet, (unsigned long)ndev); - + // update status and rt_update_status move all the if/then out of INTR routine + // taskletrx and tasklettx process the packets + tasklet_init(&priv->rx_tasklet, net_taskletrx, (unsigned long)ndev); + tasklet_init(&priv->tx_tasklet, net_tasklettx, (unsigned long)ndev); + tasklet_init(&priv->st_tasklet, net_update_status, (unsigned long)ndev); + tasklet_init(&priv->rt_tasklet, net_rt_update_status, (unsigned long)ndev); res = aml_mdio_register(ndev); if (res < 0) { goto out_unregister; } return 0; - out_unregister: unregister_netdev(ndev); error0: @@ -1962,7 +1679,6 @@ static void initTSTMODE(void) mdio_write(np->mii, np->phy_addr, 20, 0x0400); mdio_write(np->mii, np->phy_addr, 20, 0x0000); mdio_write(np->mii, np->phy_addr, 20, 0x0400); - } static void closeTSTMODE(void) @@ -2007,10 +1723,47 @@ static void am_net_dump_phyreg(void) return; printk("========== ETH PHY regs ==========\n"); - for (reg = 0; reg < 32; reg++) { + for (reg = 0; reg < 16; reg++) { val = mdio_read(np->mii, np->phy_addr, reg); - printk("[reg_%d] 0x%x\n", reg, val); + printk("[reg_%02d, 0x%02x] 0x%04x\n", reg, reg, val); } + mdio_write(np->mii, np->phy_addr, 31, 0xa43); + printk("========== ETH PHY regs ==========\n"); + for (reg = 24; reg < 32; reg++) { + val = mdio_read(np->mii, np->phy_addr, reg); + printk("[reg_%02d, 0x%02x] 0x%04x - ext43\n", reg, reg, val); + } + mdio_write(np->mii, np->phy_addr, 31, 0xa46); + val = mdio_read(np->mii, np->phy_addr, reg); + printk("========== ETH PHY regs ==========\n"); + printk("[reg_%02d, 0x%02x] 0x%04x - ext46\n", reg, reg, val); + mdio_write(np->mii, np->phy_addr, 31, 0); + // following registers from /usr/src/linux/include/uapi/linux/mii.h + spin_lock_irq(&np->lock); + val = mdio_read(np->mii, np->phy_addr, MII_BMSR); + spin_unlock_irq(&np->lock); + printk("========== MII_BMSR status ==========\n"); + printk("0x%04x\n", val); + spin_lock_irq(&np->lock); + val = mdio_read(np->mii, np->phy_addr, MII_STAT1000); + spin_unlock_irq(&np->lock); + printk("========== MII_STAT1000 1000Base-T status ==========\n"); + printk("0x%04x\n", val); + spin_lock_irq(&np->lock); + val = mdio_read(np->mii, np->phy_addr, MII_LPA); + spin_unlock_irq(&np->lock); + printk("========== MII_LPA link partner ability reg ==========\n"); + printk("0x%04x\n", val); + spin_lock_irq(&np->lock); + val = mdio_read(np->mii, np->phy_addr, MII_ESTATUS); + spin_unlock_irq(&np->lock); + printk("========== MII_ESTATUS link partner ability reg ==========\n"); + printk("0x%04x\n", val); + spin_lock_irq(&np->lock); + val = mdio_read(np->mii, np->phy_addr, MII_EXPANSION); + spin_unlock_irq(&np->lock); + printk("========== MII_EXPANSION auto-neg expansion reg ==========\n"); + printk("0x%04x\n", val); } /* --------------------------------------------------------------------------*/ @@ -2146,9 +1899,6 @@ int writeTSTCNTLRegister( int argc, char **argv) { return 0; } - - - static const char *g_phyreg_help = { "Usage:\n" " echo d > phyreg; //dump ethernet phy reg\n" @@ -2544,6 +2294,10 @@ static ssize_t eth_mdcclk_store(struct class *class, struct class_attribute *att } /* --------------------------------------------------------------------------*/ +static const char *phyreset_help = { + "echo 1 > /sys/class/ethernet/phy_reset:\n" + " To reset the PHY hardware\n" +}; static const char *g_debug_help = { "Ethernet Debug:\n" " 1. basic module init and remove info.\n" @@ -2600,52 +2354,7 @@ static ssize_t eth_debug_store(struct class *class, struct class_attribute *attr return count; } -/* --------------------------------------------------------------------------*/ -/** - * @brief eth_count_show - * - * @param class - * @param attr - * @param buf - * - * @return - */ -/* --------------------------------------------------------------------------*/ -static ssize_t eth_count_show(struct class *class, struct class_attribute *attr, char *buf) -{ - printk("Ethernet TX count: %08d\n", g_tx_cnt); - printk("Ethernet RX count: %08d\n", g_rx_cnt); - - return 0; -} - -/* --------------------------------------------------------------------------*/ -/** - * @brief eth_count_store - * - * @param class - * @param attr - * @param buf - * @param count - * - * @return - */ -/* --------------------------------------------------------------------------*/ -static ssize_t eth_count_store(struct class *class, struct class_attribute *attr, const char *buf, size_t count) -{ - unsigned int cnt = 0; - - cnt = simple_strtoul(buf, NULL, 0); - if (cnt == 0) { - printk("reset ethernet tx/rx count.\n"); - g_tx_cnt = 0; - g_rx_cnt = 0; - } else { - printk("reset ethernet count error\n"); - } - - return count; -} +/*--------------------------------------------------------------------------*/ static const char *g_wol_help = { "Ethernet WOL:\n" @@ -2707,6 +2416,45 @@ static const char *g_pwol_help = { " 1. enable PHY WOL, Magic Packet.\n" }; +/* added to allow PHY reset */ +static ssize_t eth_phyreset_store(struct class *class, struct class_attribute *attr, const char *buf, size_t count) +{ + unsigned int enable = -1; + int res = 0; + enable = simple_strtoul(buf, NULL, 0); + if(enable == 1){ + netdev_close(my_ndev); + res = netdev_open(my_ndev); + if (res != 0) { + printk("Unable to re-open netdev\n"); + } + } + return count; +} +static ssize_t eth_phyreset_show(struct class *class, struct class_attribute *attr, char *buf) +{ + int ret = 0; + ret = sprintf(buf, "%s\n", phyreset_help); + return ret; +} +static ssize_t eth_phystate_show(struct class *class, struct class_attribute *attr, char *buf) +{ + int ret = 0; + am_net_dump_phyreg(); + return ret; +} +static ssize_t eth_renegotiate_show(struct class *class, struct class_attribute *attr, char *buf) +{ + int reg = 0; + int val = 0; + struct am_net_private *np = netdev_priv(my_ndev); + reg = 0; + val = mdio_read(np->mii, np->phy_addr, reg); + val = val | (1<<9); /* restart autonegotiation */ + mdio_write(np->mii, np->phy_addr, reg, val); + printk("Restarting auto-negotiation\n"); + return reg; +} static ssize_t eth_pwol_show(struct class *class, struct class_attribute *attr, char *buf) { struct am_net_private *np = netdev_priv(my_ndev); @@ -2820,9 +2568,9 @@ static ssize_t eth_cali_store(struct class *class, struct class_attribute *attr, default: goto end; } - + return count; - + end: kfree(buff); return 0; @@ -2834,12 +2582,14 @@ static ssize_t eth_cali_store(struct class *class, struct class_attribute *attr, static struct class *eth_sys_class; static CLASS_ATTR(mdcclk, S_IWUSR | S_IRUGO, eth_mdcclk_show, eth_mdcclk_store); static CLASS_ATTR(debug, S_IWUSR | S_IRUGO, eth_debug_show, eth_debug_store); -static CLASS_ATTR(count, S_IWUSR | S_IRUGO, eth_count_show, eth_count_store); static CLASS_ATTR(phyreg, S_IWUSR | S_IRUGO, eth_phyreg_help, eth_phyreg_func); static CLASS_ATTR(macreg, S_IWUSR | S_IRUGO, eth_macreg_help, eth_macreg_func); static CLASS_ATTR(wol, S_IWUSR | S_IRUGO, eth_wol_show, eth_wol_store); static CLASS_ATTR(pwol, S_IWUSR | S_IRUGO, eth_pwol_show, eth_pwol_store); static CLASS_ATTR(linkspeed, S_IWUSR | S_IRUGO, eth_linkspeed_show, NULL); +static CLASS_ATTR(phyreset, S_IWUSR | S_IRUGO, eth_phyreset_show, eth_phyreset_store); +static CLASS_ATTR(phystate, S_IWUSR | S_IRUGO, eth_phystate_show, NULL); +static CLASS_ATTR(renegotiate, S_IWUSR | S_IRUGO, eth_renegotiate_show, NULL); #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 static CLASS_ATTR(cali, S_IWUSR | S_IRUGO, NULL,eth_cali_store); #endif @@ -2858,12 +2608,14 @@ static int __init am_eth_class_init(void) eth_sys_class = class_create(THIS_MODULE, DRIVER_NAME); ret = class_create_file(eth_sys_class, &class_attr_mdcclk); ret = class_create_file(eth_sys_class, &class_attr_debug); - ret = class_create_file(eth_sys_class, &class_attr_count); ret = class_create_file(eth_sys_class, &class_attr_phyreg); ret = class_create_file(eth_sys_class, &class_attr_macreg); ret = class_create_file(eth_sys_class, &class_attr_wol); ret = class_create_file(eth_sys_class, &class_attr_pwol); ret = class_create_file(eth_sys_class, &class_attr_linkspeed); + ret = class_create_file(eth_sys_class, &class_attr_phyreset); + ret = class_create_file(eth_sys_class, &class_attr_phystate); + ret = class_create_file(eth_sys_class, &class_attr_renegotiate); #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 ret = class_create_file(eth_sys_class, &class_attr_cali); #endif @@ -2956,6 +2708,19 @@ static int ethernet_probe(struct platform_device *pdev) reset_pin_num = amlogic_gpio_name_map_num(reset_pin); amlogic_gpio_request(reset_pin_num, OWNER_NAME); } + ret = of_property_read_bool(pdev->dev.of_node, "disable_phyrefclk"); + if (ret) { + int clk_25mout; + /* disable pinmux for phy clock 25MHz */ + aml_clr_reg32_mask(P_PERIPHS_PIN_MUX_6, 1 << 8); + clk_25mout = amlogic_gpio_name_map_num("DIF_TTL_3_N"); + amlogic_disable_pullup(clk_25mout, OWNER_NAME); + amlogic_gpio_direction_input(clk_25mout, OWNER_NAME); + + /* disable clock generation for phy */ + aml_write_reg32(P_PREG_ETH_REG0, + aml_read_reg32(P_PREG_ETH_REG0) & ~(1 << 10)); + } #endif printk(DRV_NAME "init(dbg[%p]=%d)\n", (&g_debug), g_debug); @@ -3025,34 +2790,11 @@ static int ethernet_remove(struct platform_device *pdev) static int ethernet_suspend(struct platform_device *dev, pm_message_t event) { printk("ethernet_suspend!\n"); - netdev_close(my_ndev); + netdev_close(my_ndev); return 0; } #endif -/* --------------------------------------------------------------------------*/ -/** - * @brief ethernet_resume - * - * @param dev - * - * @return - */ -/* --------------------------------------------------------------------------*/ -#if 0 -static int ethernet_resume(struct platform_device *dev) -{ - int res = 0; - printk("ethernet_resume()\n"); - hardware_reset_phy(); - res = netdev_open(my_ndev); - if (res != 0) { - printk("nono, it can not be true!\n"); - } - - return 0; -} -#endif #ifdef CONFIG_OF static const struct of_device_id eth_dt_match[]={ { .compatible = "amlogic,meson-eth", @@ -3076,9 +2818,6 @@ static struct platform_driver ethernet_driver = { } }; - - - /* --------------------------------------------------------------------------*/ /** * @brief am_net_init @@ -3088,13 +2827,14 @@ static struct platform_driver ethernet_driver = { /* --------------------------------------------------------------------------*/ static int __init am_net_init(void) { + printk("[highspeed-eth] Starting eth driver. For more information, visit: " + "https://github.com/mlinuxguy/odroid-c1-network-driver\n"); if (platform_driver_register(ðernet_driver)) { printk("failed to register ethernet_pm driver\n"); g_ethernet_registered = 0; } else { g_ethernet_registered = 1; } - return 0; } @@ -3121,7 +2861,6 @@ static void am_net_free(struct net_device *ndev) static void __exit am_net_exit(void) { printk(DRV_NAME "exit\n"); - am_net_free(my_ndev); free_netdev(my_ndev); aml_mdio_unregister(my_ndev); @@ -3136,5 +2875,3 @@ static void __exit am_net_exit(void) module_init(am_net_init); module_exit(am_net_exit); - - diff --git a/drivers/amlogic/ethernet/am_net8218.h b/drivers/amlogic/ethernet/am_net8218.h old mode 100755 new mode 100644 index f87dd3431..a270f4a4f --- a/drivers/amlogic/ethernet/am_net8218.h +++ b/drivers/amlogic/ethernet/am_net8218.h @@ -42,8 +42,8 @@ //ring buf must less than the MAX alloc length 131072 //131072/1536~=85; -#define TX_RING_SIZE 128 -#define RX_RING_SIZE 128 +#define TX_RING_SIZE 16384 // 512, 32768 +#define RX_RING_SIZE 32768 // 4096, 65536 #define CACHE_LINE 32 #define IS_CACHE_ALIGNED(x) (!((unsigned long )x &(CACHE_LINE-1))) #define CACHE_HEAD_ALIGNED(x) ((x-CACHE_LINE) & (~(CACHE_LINE-1))) @@ -152,21 +152,26 @@ struct _rx_desc { }; struct am_net_private { - struct _rx_desc *rx_ring; + struct _rx_desc *rx_ring; // rx section struct _rx_desc *rx_ring_dma; - struct _tx_desc *tx_ring; - struct _tx_desc *tx_ring_dma; struct _rx_desc *last_rx; + struct tasklet_struct rx_tasklet; + + struct _tx_desc *tx_ring; // tx section + struct _tx_desc *tx_ring_dma; struct _tx_desc *last_tx; struct _tx_desc *start_tx; + struct tasklet_struct tx_tasklet; + struct net_device *dev; struct net_device_stats stats; struct timer_list timer; /* Media monitoring timer. */ - struct tasklet_struct rx_tasklet; - int int_rx_tx; - int pmt; +// int pmt; +// currently not used in the driver unsigned int irq_mask; - + struct tasklet_struct st_tasklet; + struct tasklet_struct rt_tasklet; + unsigned long status; /* Frequently used values: keep some adjacent for cache effect. */ spinlock_t lock; unsigned int rx_buf_sz; /* Based on MTU+slack. */ @@ -184,8 +189,6 @@ struct am_net_private { int speed; int oldduplex; int refcnt; - - }; #endif diff --git a/drivers/amlogic/ethernet/phy/am_rtl8211f.c b/drivers/amlogic/ethernet/phy/am_rtl8211f.c old mode 100755 new mode 100644 index d64b1af6c..9340c9784 --- a/drivers/amlogic/ethernet/phy/am_rtl8211f.c +++ b/drivers/amlogic/ethernet/phy/am_rtl8211f.c @@ -1,88 +1,136 @@ - #include #include - -#define RTL821x_PHYSR 0x11 +#include +#include +#include +//#define RTL_SPRD_CLK_MODE 1 // enables spread spectrum clocks, disable for slight boost +//#define RTL_GREEN_MODE 1 // disable to stop grn mode and slight boost in perf +#define RTL821x_PHYSR 0x11 #define RTL821x_PHYSR_DUPLEX 0x2000 -#define RTL821x_PHYSR_SPEED 0xc000 -#define RTL821x_INER 0x12 -#define RTL821x_INER_INIT 0x6400 -#define RTL821x_INSR 0x13 +#define RTL821x_PHYSR_SPEED 0xc000 +#define RTL821x_INER 0x12 +#define RTL821x_INER_INIT 0x6400 +#define RTL821x_INSR 0x13 #define RTL8211F_MMD_CTRL 0x0D #define RTL8211F_MMD_DATA 0x0E #define RTL8211E_INER_LINK_STAT 0x10 +#define RTL8211F_PHYCTRL 0 + +#define RTL8211F_PHYCR1 24 +#define RTL8211F_PHYCR2 25 +#define RTL8211F_PHYSR 26 +#define RTL8211F_REGPAGE 31 + +#define RTL8211F_RXCSSC 19 +#define RTL8211F_SYSCLK_SSC 23 + MODULE_DESCRIPTION("Realtek PHY driver"); MODULE_AUTHOR("Johnson Leung"); MODULE_LICENSE("GPL"); -#if 0 -static int rtl821x_ack_interrupt(struct phy_device *phydev) -{ - int err; - - err = phy_read(phydev, RTL821x_INSR); - return (err < 0) ? err : 0; -} -static int rtl8211e_config_intr(struct phy_device *phydev) +// probably can go back to using genphy_read_status, but this may fix PHY_AN till later kernels +static int rtl8211e_read_status(struct phy_device *phydev) { - int err; - - if (phydev->interrupts == PHY_INTERRUPT_ENABLED) - err = phy_write(phydev, RTL821x_INER, - RTL8211E_INER_LINK_STAT); - else - err = phy_write(phydev, RTL821x_INER, 0); - - return err; + int val, tmp; + phy_write(phydev, RTL8211F_REGPAGE, 0x0a43); // return to page 0xa43 + val = phy_read(phydev, RTL8211F_PHYSR); // phy status reg + if (val & (1<<3)) { // check duplex setting + phydev->duplex = DUPLEX_FULL; + } else { + phydev->duplex = DUPLEX_HALF; + } + tmp = (val & ((1<<4)|(1<<5))) >> 4; // just look at speed bits + if (tmp == 0) { // 10mbs + phydev->speed = SPEED_10; + } + if (tmp == 1) { // 100mbs + phydev->speed = SPEED_100; + } + if (tmp == 2) { // 1000mbs + phydev->speed = SPEED_1000; + } + if (val & (1<<2)) { // link status in real time + phydev->link = 1; // link up + } else { + phydev->link = 0; // link down + } + // in later kernels 3.18+ they change phy.c state machine to do + // PHY_AN in proper location + if (phydev->link) { + val = phy_read(phydev, 0x01); // phy status reg + if (val & (1<<5)) { + phydev->state = PHY_RUNNING;// autoneg completed + netif_carrier_on(phydev->attached_dev); + phydev->adjust_link(phydev->attached_dev); + } else { + phydev->state = PHY_AN; // autoneg not completed + netif_carrier_on(phydev->attached_dev); + phydev->adjust_link(phydev->attached_dev); + } + } else { + phydev->state = PHY_NOLINK; + netif_carrier_off(phydev->attached_dev); + phydev->adjust_link(phydev->attached_dev); + } + + phydev->pause = phydev->asym_pause = 1; + phy_write(phydev, RTL8211F_REGPAGE, 0x0000); // return to page 0 + return 0; } -#endif + static int rtl8211e_config_init(struct phy_device *phydev) { int val; -/* we want to disable eee */ - phy_write(phydev, RTL8211F_MMD_CTRL, 0x7); - - phy_write(phydev, RTL8211F_MMD_DATA, 0x3c); - - phy_write(phydev, RTL8211F_MMD_CTRL, 0x4007); - - phy_write(phydev, RTL8211F_MMD_DATA, 0x0); - -/* disable 1000m adv*/ - val = phy_read(phydev, 0x9); - phy_write(phydev, 0x9, val&(~(1<<9))); - /* rx reg 21 bit 3 tx reg 17 bit 8*/ - /* phy_write(phydev, 0x1f, 0xd08); - val = phy_read(phydev, 0x15); - phy_write(phydev, 0x15,val| 1<<21); -*/ + /* Disable CLK_OUT */ + phy_write(phydev, RTL8211F_REGPAGE, 0x0a43); // return to page 0xa43 + val = phy_read(phydev, RTL8211F_PHYCR2); + phy_write(phydev, RTL8211F_PHYCR2, val & ~(1 << 0));// disable clock out + phy_write(phydev, RTL8211F_REGPAGE, 0x0000); // return to page 0 + + phy_write(phydev, RTL8211F_REGPAGE, 0x0a43); // return to page 0xa43 +#ifdef RTL_SPRD_CLK_MODE + phy_write(phydev, 0x19, 0x8eb); // 125mhz clock, rxc ssc, clock ssc, and enable EEE +#else + phy_write(phydev, 0x19, 0x803); // 125mhz clock, no EEE, RXC clock enable, clock +#endif +#ifdef RTL_GREEN_MODE + phy_write(phydev, RTL8211F_REGPAGE, 0x0000); // return to page 0 + phy_write(phydev, 31, 0x0a43); /* 3, hk test values */ + phy_write(phydev, 27, 0x8011); // I do it twice since not sure yet if it survives PHY reset + phy_write(phydev, 28, 0x573f); // boosted perf about 2-3% +#endif + printk("am_rtl811f called phy reset\n"); + phy_write(phydev, RTL8211F_PHYCTRL, 0x9200); // PHY reset + msleep(10); // calls for min 50msec + +#ifdef RTL_GREEN_MODE + phy_write(phydev, 31, 0x0a43); /* 3, hk test values */ + phy_write(phydev, 27, 0x8011); + phy_write(phydev, 28, 0x573f); +#endif +// can modify the last write, 0x00 disables EEE + phy_write(phydev, RTL8211F_MMD_CTRL, 0x7); // device 7 + phy_write(phydev, RTL8211F_MMD_DATA, 0x3c); // address 0x3c + phy_write(phydev, RTL8211F_MMD_CTRL, 0x4007); // no post increment, reg 7 again + phy_write(phydev, RTL8211F_MMD_DATA, 0x00); return 0; - /* Enable Auto Power Saving mode */ - } + /* RTL8211F */ static struct phy_driver rtl8211e_driver = { .phy_id = 0x001cc916, .name = "RTL8211F Gigabit Ethernet", .phy_id_mask = 0x001fffff, -#if 1 - .features = PHY_GBIT_FEATURES | SUPPORTED_Pause | - SUPPORTED_Asym_Pause,// close 1000m speed - .flags = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG, -#else - .features = PHY_BASIC_FEATURES | SUPPORTED_Pause | - SUPPORTED_Asym_Pause, - .flags = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG, -#endif + .features = PHY_GBIT_FEATURES | SUPPORTED_Pause | + SUPPORTED_Asym_Pause,// close 1000m speed + .flags = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG, .config_aneg = &genphy_config_aneg, - .read_status = &genphy_read_status, + .read_status = &rtl8211e_read_status, .config_init = &rtl8211e_config_init, -// .ack_interrupt = &rtl821x_ack_interrupt, -// .config_intr = &rtl8211e_config_intr, - .suspend = genphy_suspend, - .resume = genphy_resume, - .driver = { .owner = THIS_MODULE,}, + .suspend = genphy_suspend, + .resume = genphy_resume, + .driver = { .owner = THIS_MODULE,}, }; static int __init realtek_init(void)