From: hwg Date: Fri, 7 Mar 2014 01:12:45 +0000 (+0800) Subject: support 3188 vmac X-Git-Tag: firefly_0821_release~6174 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=284bbb120120e68173a4bd14f9209dfdbab49d19;p=firefly-linux-kernel-4.4.55.git support 3188 vmac --- diff --git a/arch/arm/boot/dts/rk3188-pinctrl.dtsi b/arch/arm/boot/dts/rk3188-pinctrl.dtsi index bb46bc6f4231..694549ca73d7 100755 --- a/arch/arm/boot/dts/rk3188-pinctrl.dtsi +++ b/arch/arm/boot/dts/rk3188-pinctrl.dtsi @@ -692,6 +692,48 @@ }; }; + gpio3_rmii { + rmii_clkoutpin: rmii-clkoutpin { + rockchip,pins = ; + rockchip,pull = ; + //rockchip,voltage = ; + rockchip,drive = ; + //rockchip,tristate = ; + }; + + rmii_clkinpin: rmii-clkinpin { + rockchip,pins = ; + rockchip,pull = ; + //rockchip,voltage = ; + rockchip,drive = ; + //rockchip,tristate = ; + }; + + rmii_txpins: rmii-txpins { + rockchip,pins = , , ; + rockchip,pull = ; + //rockchip,voltage = ; + rockchip,drive = ; + //rockchip,tristate = ; + }; + + rmii_rxpins: rmii-rxpins { + rockchip,pins = , , , ; + rockchip,pull = ; + //rockchip,voltage = ; + rockchip,drive = ; + //rockchip,tristate = ; + }; + + rmii_mdpins: rmii-mdpins { + rockchip,pins = , ; + rockchip,pull = ; + //rockchip,voltage = ; + rockchip,drive = ; + //rockchip,tristate = ; + }; + }; + gps { gps_mag:gps-mag { rockchip,pins = ; diff --git a/arch/arm/boot/dts/rk3188.dtsi b/arch/arm/boot/dts/rk3188.dtsi index 79da82eb7621..b4834797b70b 100755 --- a/arch/arm/boot/dts/rk3188.dtsi +++ b/arch/arm/boot/dts/rk3188.dtsi @@ -626,4 +626,12 @@ "hsicphy12m", "hsic_otgphy1"; }; + vmac@0x10204000 { + compatible = "rockchip,vmac"; + reg = <0x10204000 0x4000>; + interrupts = ; + pinctrl-names = "default", "gpio"; + pinctrl-0 = <&rmii_clkoutpin &rmii_txpins &rmii_rxpins &rmii_mdpins>; + pinctrl-1 = <&rmii_clkinpin &rmii_txpins &rmii_rxpins &rmii_mdpins>; + }; }; diff --git a/drivers/net/eth_mac/Kconfig b/drivers/net/eth_mac/Kconfig deleted file mode 100755 index 933563ae521b..000000000000 --- a/drivers/net/eth_mac/Kconfig +++ /dev/null @@ -1,51 +0,0 @@ -# -# set Ethernet mac source -# -choice - prompt "Ethernet mac source" - depends on NETDEV_10000 ||NETDEV_1000 ||NET_ETHERNET - default ETH_MAC_FROM_RANDOM - - config ETH_MAC_FROM_RANDOM - bool "Random Ethernet mac " - ---help--- - Say Y here if you want to set Random mac to Ethernet mac. - - This option alone does not add any kernel code. - - If you say N, all options in this submenu will be skipped and disabled. - - config ETH_MAC_FROM_EEPROM - bool "Ethernet mac from EEPROM" - depends on EEPROM_AT24C16 - ---help--- - Say Y here if you want to set EEPROM mac to Ethernet mac, - when the EEPROM exsits and mac has been written in. - - This option alone does not add any kernel code. - - If you say N, all options in this submenu will be skipped and disabled. - - config ETH_MAC_FROM_IDB - bool "Ethernet mac from IDB" - ---help--- - Say Y here if you want to set IDB mac to Ethernet mac, - when the IDB mac has been written in. - - This option alone does not add any kernel code. - - If you say N, all options in this submenu will be skipped and disabled. - -endchoice - -config PHY_PORT_NUM - int "phy port number selected (More than one port on Switch)" - depends on RK29_VMAC - default 0 - help - 0:phy dev 0:00 - 1:phy dev 0:01 - 2:phy dev 0:02 - ---More--- - - diff --git a/drivers/net/eth_mac/Makefile b/drivers/net/eth_mac/Makefile deleted file mode 100755 index c745b3d64a34..000000000000 --- a/drivers/net/eth_mac/Makefile +++ /dev/null @@ -1 +0,0 @@ -obj-y += eth_mac.o diff --git a/drivers/net/eth_mac/eth_mac.c b/drivers/net/eth_mac/eth_mac.c deleted file mode 100755 index 96f5de4bba72..000000000000 --- a/drivers/net/eth_mac/eth_mac.c +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright (C) 2010 ROCKCHIP, Inc. - * Author: roger_chen - * - * This program is the virtual flash device - * used to store bd_addr or MAC - * - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "eth_mac.h" - -#if 1 -#define DBG(x...) printk("eth_mac:" x) -#else -#define DBG(x...) -#endif - -#define VERSION "0.1" - -#define WLAN_MAC_FILE "/data/misc/wifi/wlan_mac" - -//extern char GetSNSectorInfo(char * pbuf); - -static char GetSNSectorInfoBeforeNandInit(char * pbuf) -{ - char * sn_addr = ioremap(0x10501600,0x200); - memcpy(pbuf,sn_addr,0x200); - iounmap(sn_addr); - //print_hex_dump(KERN_WARNING, "sn:", DUMP_PREFIX_NONE, 16,1, sn_addr, 16, 0); - return 0; -} - -int eth_mac_read_from_IDB(u8 *mac) -{ - int i; - char *tempBuf = kmalloc(512, GFP_KERNEL); - - if(mac == NULL) - return -EFAULT; - - GetSNSectorInfoBeforeNandInit(tempBuf); - /*for (i = 0; i < 512; i++) { - printk("%02x, ", tempBuf[i]); - if(((i+1)%16) == 0) printk("\n"); - }*/ - - for (i = 506; i <= 511; i++) - mac[i-506] = tempBuf[i]; - - kfree(tempBuf); - - return 0; -} - -int eth_mac_idb(u8 *eth_mac) -{ - int i; - int err = 0; - memset(eth_mac, 0, 6); - err = eth_mac_read_from_IDB(eth_mac); - if (err) - return -1; - printk("Read the Ethernet MAC address from IDB:"); - for (i = 0; i < 5; i++) - printk("%2.2x:", eth_mac[i]); - printk("%2.2x\n", eth_mac[i]); - - return 0; -} - -/** -*大写转小写 -* -*/ -static void to_lower(char *str) -{ - int i=0; - while(str[i]!=0) - { - if((str[i] >= 'A')&&(str[i] <= 'Z')) - str[i]+=32; - i++; - } -} - - -/** - *字符串格式转为mac 格式. - * - * - */ -static void trans( char *src ,int * k) -{ - char c; - int i; - int temp; - int temp2; - - if( (src == NULL) ||(strlen(src) <16 ) ) // 参数检查 - { - printk( "Arg Error\n" ); - return ; - } - - for( i = 0; i < 6; i++ ) - { - temp = 0; - temp2 = 0; - c = *src; - if( c == ':' ){ - src++; - c = *src; - } - if( c >= 'a' && c <= 'f' ) // 两个字符中的第一个 比如 "0f" ,则表示是字符 '0' - temp = ( c - 'a' ) + 10; - else - temp = ( c - '0' ) ; - src++; - - c = *src; - if( i == 5){ //wifi mac 末尾加1 - if(c =='f'){ - c = '0'; - } if (c == '9'){ - c = 'a'; - }else{ - c = c + 1; - } - } - if( c >= 'a' && c <= 'f' ) // 两个字符中的第二个,如 "f8" ,那么表示字符 '8' - temp2 = ( c - 'a' ) + 10; - else - temp2 = ( c - '0' ) ; - - temp = temp * 16; - temp += temp2; - src++; - *(k+i) = temp; - - } - -} - -/*int eth_mac_wifi(u8 *eth_mac){ - int i; - struct file *file = NULL; - char wifi_mac[32]; - mm_segment_t old_fs; - ssize_t ret; - int maci[6]; - - memset(eth_mac, 0, 6); - - file = filp_open(WLAN_MAC_FILE, O_RDWR,0); - if (IS_ERR(file)) - { - printk("open %s failed.", WLAN_MAC_FILE); - return -ENOENT; - } - - old_fs = get_fs(); - set_fs(get_ds()); - - file->f_op->llseek(file,0,0); - ret = file->f_op->read(file, wifi_mac, 32, &file->f_pos); - - set_fs(old_fs); - - if(ret > 0){ - //printk("mac read from %s: %s\n", WLAN_MAC_FILE,wifi_mac); - - to_lower(wifi_mac); - trans(wifi_mac,maci); - for (i = 0;i< 6;i++){ - eth_mac[i] = maci[i]; - } - - } - else if(ret == 0) - printk("read nothing from %s........\n",WLAN_MAC_FILE); - else - { - printk("read wifi mac error\n"); - return -ENOENT; - } - - filp_close(file,NULL); - return 0; - -}*/ - - - - - diff --git a/drivers/net/eth_mac/eth_mac.h b/drivers/net/eth_mac/eth_mac.h deleted file mode 100755 index 03db62788352..000000000000 --- a/drivers/net/eth_mac/eth_mac.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef _ETH_MAC_H_ -#define _ETH_MAC_H_ -/* - * eth_mac/eth_mac.h - * - * Copyright (C) 2001 Russell King. - * - * This file is placed under the LGPL. - * - * - * - */ -//int eth_mac_read_from_IDB(u8 *mac) - -int eth_mac_idb(u8 *eth_mac); -int eth_mac_wifi(u8 *eth_mac); -#endif /* _ETH_MAC_H_ */ diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig old mode 100644 new mode 100755 index ed956e08d38b..f651b27c9696 --- a/drivers/net/ethernet/Kconfig +++ b/drivers/net/ethernet/Kconfig @@ -167,5 +167,6 @@ source "drivers/net/ethernet/via/Kconfig" source "drivers/net/ethernet/wiznet/Kconfig" source "drivers/net/ethernet/xilinx/Kconfig" source "drivers/net/ethernet/xircom/Kconfig" +source "drivers/net/ethernet/rk/Kconfig" endif # ETHERNET diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile old mode 100644 new mode 100755 index 8268d85f9448..b3925e9cbabc --- a/drivers/net/ethernet/Makefile +++ b/drivers/net/ethernet/Makefile @@ -74,3 +74,4 @@ obj-$(CONFIG_NET_VENDOR_VIA) += via/ obj-$(CONFIG_NET_VENDOR_WIZNET) += wiznet/ obj-$(CONFIG_NET_VENDOR_XILINX) += xilinx/ obj-$(CONFIG_NET_VENDOR_XIRCOM) += xircom/ +obj-$(CONFIG_NET_VENDOR_ROCKCHIP) += rk/ diff --git a/drivers/net/ethernet/rk/Kconfig b/drivers/net/ethernet/rk/Kconfig new file mode 100755 index 000000000000..be5f534e70d6 --- /dev/null +++ b/drivers/net/ethernet/rk/Kconfig @@ -0,0 +1,16 @@ +# +# rockchip device configuration +# + +config NET_VENDOR_ROCKCHIP + bool "Rockchip devices" + default y + depends on HAS_IOMEM + ---help--- + Rockchip devices + +if NET_VENDOR_ROCKCHIP + +source "drivers/net/ethernet/rk/vmac/Kconfig" + +endif # NET_VENDOR_ROCKCHIP diff --git a/drivers/net/ethernet/rk/Makefile b/drivers/net/ethernet/rk/Makefile new file mode 100755 index 000000000000..e36c612ba7cb --- /dev/null +++ b/drivers/net/ethernet/rk/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the rockchip device drivers. +# + +obj-$(CONFIG_RK_VMAC_ETH) += vmac/ diff --git a/drivers/net/ethernet/rk/vmac/Kconfig b/drivers/net/ethernet/rk/vmac/Kconfig new file mode 100755 index 000000000000..23f5af837e7f --- /dev/null +++ b/drivers/net/ethernet/rk/vmac/Kconfig @@ -0,0 +1,10 @@ +config RK_VMAC_ETH + bool "Rockchip 10/100 Ethernet driver" + depends on HAS_IOMEM && HAS_DMA + select NET_CORE + select MII + select PHYLIB + select CRC32 + ---help--- + Rockchip 10/100 VMAC Ethernet driver. + diff --git a/drivers/net/ethernet/rk/vmac/Makefile b/drivers/net/ethernet/rk/vmac/Makefile new file mode 100755 index 000000000000..4de386217110 --- /dev/null +++ b/drivers/net/ethernet/rk/vmac/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_RK_VMAC_ETH) += rk29_vmac.o +obj-$(CONFIG_RK_VMAC_ETH) += rk29_vmac_phy.o diff --git a/drivers/net/ethernet/rk/vmac/rk29_vmac.c b/drivers/net/ethernet/rk/vmac/rk29_vmac.c new file mode 100755 index 000000000000..16e69c4e2510 --- /dev/null +++ b/drivers/net/ethernet/rk/vmac/rk29_vmac.c @@ -0,0 +1,1798 @@ +/* + * linux/arch/arc/drivers/arcvmac.c + * + * Copyright (C) 2003-2006 Codito Technologies, for linux-2.4 port + * Copyright (C) 2006-2007 Celunite Inc, for linux-2.6 port + * Copyright (C) 2007-2008 Sagem Communications, Fehmi HAFSI + * Copyright (C) 2009 Sagem Communications, Andreas Fenkart + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * external PHY support based on dnet.c + * ring management based on bcm63xx_enet.c + * + * Authors: amit.bhor@celunite.com, sameer.dhavale@celunite.com + */ + +#define DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rk29_vmac.h" + +//static struct wake_lock idlelock; /* add by lyx @ 20110302 */ + +/* Register access macros */ +#define vmac_writel(port, value, reg) \ + writel((value), (port)->regs + reg##_OFFSET) +#define vmac_readl(port, reg) readl((port)->regs + reg##_OFFSET) + +static unsigned char *read_mac_reg(struct net_device *dev, + unsigned char hwaddr[ETH_ALEN]) +{ + struct vmac_priv *ap = netdev_priv(dev); + unsigned mac_lo, mac_hi; + + WARN_ON(!hwaddr); + mac_lo = vmac_readl(ap, ADDRL); + mac_hi = vmac_readl(ap, ADDRH); + + hwaddr[0] = (mac_lo >> 0) & 0xff; + hwaddr[1] = (mac_lo >> 8) & 0xff; + hwaddr[2] = (mac_lo >> 16) & 0xff; + hwaddr[3] = (mac_lo >> 24) & 0xff; + hwaddr[4] = (mac_hi >> 0) & 0xff; + hwaddr[5] = (mac_hi >> 8) & 0xff; + return hwaddr; +} + +static void write_mac_reg(struct net_device *dev, unsigned char* hwaddr) +{ + struct vmac_priv *ap = netdev_priv(dev); + unsigned mac_lo, mac_hi; + + mac_lo = hwaddr[3] << 24 | hwaddr[2] << 16 | hwaddr[1] << 8 | hwaddr[0]; + mac_hi = hwaddr[5] << 8 | hwaddr[4]; + + vmac_writel(ap, mac_lo, ADDRL); + vmac_writel(ap, mac_hi, ADDRH); +} + +static void vmac_mdio_xmit(struct vmac_priv *ap, unsigned val) +{ + init_completion(&ap->mdio_complete); + vmac_writel(ap, val, MDIO_DATA); + if(!wait_for_completion_timeout(&ap->mdio_complete, msecs_to_jiffies(1000))) + printk("Time out for waiting mdio completion\n"); +} + +static int vmac_mdio_read(struct mii_bus *bus, int phy_id, int phy_reg) +{ + struct vmac_priv *vmac = bus->priv; + unsigned int val; + /* only 5 bits allowed for phy-addr and reg_offset */ + WARN_ON(phy_id & ~0x1f || phy_reg & ~0x1f); + + val = MDIO_BASE | MDIO_OP_READ; + val |= phy_id << 23 | phy_reg << 18; + vmac_mdio_xmit(vmac, val); + + val = vmac_readl(vmac, MDIO_DATA); + return val & MDIO_DATA_MASK; +} + +static int vmac_mdio_write(struct mii_bus *bus, int phy_id, int phy_reg, + u16 value) +{ + struct vmac_priv *vmac = bus->priv; + unsigned int val; + /* only 5 bits allowed for phy-addr and reg_offset */ + WARN_ON(phy_id & ~0x1f || phy_reg & ~0x1f); + + val = MDIO_BASE | MDIO_OP_WRITE; + val |= phy_id << 23 | phy_reg << 18; + val |= (value & MDIO_DATA_MASK); + vmac_mdio_xmit(vmac, val); + return 0; +} + +static void vmac_handle_link_change(struct net_device *dev) +{ + struct vmac_priv *ap = netdev_priv(dev); + struct phy_device *phydev = ap->phy_dev; + unsigned long flags; + int report_change = 0; + struct rk29_vmac_platform_data *pdata = ap->pdev->dev.platform_data; + + spin_lock_irqsave(&ap->lock, flags); + + if (phydev->duplex != ap->duplex) { + unsigned tmp; + + tmp = vmac_readl(ap, CONTROL); + + if (phydev->duplex) + tmp |= ENFL_MASK; + else + tmp &= ~ENFL_MASK; + + vmac_writel(ap, tmp, CONTROL); + + ap->duplex = phydev->duplex; + report_change = 1; + } + + if (phydev->speed != ap->speed) { + ap->speed = phydev->speed; + report_change = 1; + } + + if (pdata && pdata->rmii_speed_switch) + pdata->rmii_speed_switch(phydev->speed); + + if (phydev->link != ap->link) { + ap->link = phydev->link; + report_change = 1; + } + + spin_unlock_irqrestore(&ap->lock, flags); + + if (report_change) + phy_print_status(ap->phy_dev); +} + +static int vmac_mii_probe(struct net_device *dev) +{ + struct vmac_priv *ap = netdev_priv(dev); + struct phy_device *phydev = NULL; + //struct clk *sys_clk; + //unsigned long clock_rate; + int phy_addr, err; + + +#if defined (CONFIG_PHY_PORT_NUM) && (CONFIG_PHY_PORT_NUM != 0) + if (ap->mii_bus->phy_map[CONFIG_PHY_PORT_NUM]) + phydev = ap->mii_bus->phy_map[CONFIG_PHY_PORT_NUM]; +#else + /* find the first phy */ + for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) { + if (ap->mii_bus->phy_map[phy_addr]) { + phydev = ap->mii_bus->phy_map[phy_addr]; + break; + } + } +#endif + + if (!phydev) { + dev_err(&dev->dev, "no PHY found\n"); + return -ENODEV; + } + + /* add pin_irq, if avail */ + phydev = phy_connect(dev, dev_name(&phydev->dev), + &vmac_handle_link_change, + PHY_INTERFACE_MODE_RMII); + if (IS_ERR(phydev)) { + err = PTR_ERR(phydev); + dev_err(&dev->dev, "could not attach to PHY %d\n", err); + goto err_out; + } + + phydev->supported &= PHY_BASIC_FEATURES; + phydev->supported |= SUPPORTED_Asym_Pause | SUPPORTED_Pause; + + phydev->advertising = phydev->supported; + + ap->link = 0; + ap->speed = 0; + ap->duplex = -1; + ap->phy_dev = phydev; + + return 0; +//err_disconnect: +// phy_disconnect(phydev); +err_out: + return err; +} + +static int vmac_mii_init(struct vmac_priv *ap) +{ + int err, i; + + ap->mii_bus = mdiobus_alloc(); + + if (ap->mii_bus == NULL) + return -ENOMEM; + + ap->mii_bus->name = "vmac_mii_bus"; + ap->mii_bus->read = &vmac_mdio_read; + ap->mii_bus->write = &vmac_mdio_write; + + snprintf(ap->mii_bus->id, MII_BUS_ID_SIZE, "%x", 0); + + ap->mii_bus->priv = ap; + + err = -ENOMEM; + ap->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); + if (!ap->mii_bus->irq) + goto err_out; + + for (i = 0; i < PHY_MAX_ADDR; i++) + ap->mii_bus->irq[i] = PHY_POLL; + +#if 0 + /* FIXME: what is it used for? */ + platform_set_drvdata(ap->dev, ap->mii_bus); +#endif + + err = mdiobus_register(ap->mii_bus); + if (err) + goto err_out_free_mdio_irq; + + err = vmac_mii_probe(ap->dev); + if (err) + goto err_out_unregister_bus; + + return 0; + +err_out_unregister_bus: + mdiobus_unregister(ap->mii_bus); +err_out_free_mdio_irq: + kfree(ap->mii_bus->irq); +err_out: + mdiobus_free(ap->mii_bus); + ap->mii_bus = NULL; + return err; +} + +static void vmac_mii_exit(struct net_device *dev) +{ + struct vmac_priv *ap = netdev_priv(dev); + + if (ap->phy_dev) + phy_disconnect(ap->phy_dev); + if (ap->mii_bus) { + mdiobus_unregister(ap->mii_bus); + kfree(ap->mii_bus->irq); + mdiobus_free(ap->mii_bus); + ap->mii_bus = NULL; + } +} + +static int vmacether_get_settings(struct net_device *dev, + struct ethtool_cmd *cmd) +{ + struct vmac_priv *ap = netdev_priv(dev); + struct phy_device *phydev = ap->phy_dev; + + if (!phydev) + return -ENODEV; + + return phy_ethtool_gset(phydev, cmd); +} + +static int vmacether_set_settings(struct net_device *dev, + struct ethtool_cmd *cmd) +{ + struct vmac_priv *ap = netdev_priv(dev); + struct phy_device *phydev = ap->phy_dev; + + if (!phydev) + return -ENODEV; + + return phy_ethtool_sset(phydev, cmd); +} + +static int vmac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct vmac_priv *ap = netdev_priv(dev); + struct phy_device *phydev = ap->phy_dev; + + if (!netif_running(dev)) + return -EINVAL; + + if (!phydev) + return -ENODEV; + + return phy_mii_ioctl(phydev, rq, cmd); +} + +static void vmacether_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + struct vmac_priv *ap = netdev_priv(dev); + + strlcpy(info->driver, VMAC_NAME, sizeof(info->driver)); + strlcpy(info->version, VMAC_VERSION, sizeof(info->version)); + snprintf(info->bus_info, sizeof(info->bus_info), + "platform 0x%x", ap->mem_base); +} + +static int update_error_counters(struct net_device *dev, int status) +{ + struct vmac_priv *ap = netdev_priv(dev); + dev_dbg(&ap->pdev->dev, "rx error counter overrun. status = 0x%x\n", + status); + + /* programming error */ + WARN_ON(status & TXCH_MASK); + WARN_ON(!(status & (MSER_MASK | RXCR_MASK | RXFR_MASK | RXFL_MASK))); + + if (status & MSER_MASK) + ap->stats.rx_over_errors += 256; /* ran out of BD */ + if (status & RXCR_MASK) + ap->stats.rx_crc_errors += 256; + if (status & RXFR_MASK) + ap->stats.rx_frame_errors += 256; + if (status & RXFL_MASK) + ap->stats.rx_fifo_errors += 256; + + return 0; +} + +static void update_tx_errors(struct net_device *dev, int status) +{ + struct vmac_priv *ap = netdev_priv(dev); + + if (status & UFLO) + ap->stats.tx_fifo_errors++; + + if (ap->duplex) + return; + + /* half duplex flags */ + if (status & LTCL) + ap->stats.tx_window_errors++; + if (status & RETRY_CT) + ap->stats.collisions += (status & RETRY_CT) >> 24; + if (status & DROP) /* too many retries */ + ap->stats.tx_aborted_errors++; + if (status & DEFER) + dev_vdbg(&ap->pdev->dev, "\"defer to traffic\"\n"); + if (status & CARLOSS) + ap->stats.tx_carrier_errors++; +} + +static int vmac_rx_reclaim_force(struct net_device *dev) +{ + struct vmac_priv *ap = netdev_priv(dev); + int ct; + + ct = 0; + + dev_dbg(&ap->pdev->dev, "%s need to release %d rx sk_buff\n", + __func__, fifo_used(&ap->rx_ring)); + + while (!fifo_empty(&ap->rx_ring) && ct++ < ap->rx_ring.size) { + struct vmac_buffer_desc *desc; + struct sk_buff *skb; + int desc_idx; + + desc_idx = ap->rx_ring.tail; + desc = &ap->rxbd[desc_idx]; + fifo_inc_tail(&ap->rx_ring); + + if (!ap->rx_skbuff[desc_idx]) { + dev_err(&ap->pdev->dev, "non-populated rx_skbuff found %d\n", + desc_idx); + continue; + } + + skb = ap->rx_skbuff[desc_idx]; + ap->rx_skbuff[desc_idx] = NULL; + + dma_unmap_single(&ap->pdev->dev, desc->data, skb->len, + DMA_TO_DEVICE); + + dev_kfree_skb(skb); + } + + if (!fifo_empty(&ap->rx_ring)) { + dev_err(&ap->pdev->dev, "failed to reclaim %d rx sk_buff\n", + fifo_used(&ap->rx_ring)); + } + + return 0; +} + +static int vmac_rx_refill(struct net_device *dev) +{ + struct vmac_priv *ap = netdev_priv(dev); + + WARN_ON(fifo_full(&ap->rx_ring)); + + while (!fifo_full(&ap->rx_ring)) { + struct vmac_buffer_desc *desc; + struct sk_buff *skb; + dma_addr_t p; + int desc_idx; + + desc_idx = ap->rx_ring.head; + desc = &ap->rxbd[desc_idx]; + + /* make sure we read the actual descriptor status */ + rmb(); + + if (ap->rx_skbuff[desc_idx]) { + /* dropped packet / buffer chaining */ + fifo_inc_head(&ap->rx_ring); + + /* return to DMA */ + wmb(); + desc->info = OWN_MASK | ap->rx_skb_size; + continue; + } + + skb = netdev_alloc_skb(dev, ap->rx_skb_size + 2); + if (!skb) { + dev_info(&ap->pdev->dev, "failed to allocate rx_skb, skb's left %d\n", + fifo_used(&ap->rx_ring)); + break; + } + + /* IP header Alignment (14 byte Ethernet header) */ + skb_reserve(skb, 2); + WARN_ON(skb->len != 0); /* nothing received yet */ + + ap->rx_skbuff[desc_idx] = skb; + + p = dma_map_single(&ap->pdev->dev, skb->data, ap->rx_skb_size, + DMA_FROM_DEVICE); + + desc->data = p; + + wmb(); + desc->info = OWN_MASK | ap->rx_skb_size; + + fifo_inc_head(&ap->rx_ring); + } + + /* If rx ring is still empty, set a timer to try allocating + * again at a later time. */ + if (fifo_empty(&ap->rx_ring) && netif_running(dev)) { + dev_warn(&ap->pdev->dev, "unable to refill rx ring\n"); + ap->rx_timeout.expires = jiffies + HZ; + add_timer(&ap->rx_timeout); + } + + return 0; +} + +/* + * timer callback to defer refill rx queue in case we're OOM + */ +static void vmac_refill_rx_timer(unsigned long data) +{ + struct net_device *dev; + struct vmac_priv *ap; + + dev = (struct net_device *)data; + ap = netdev_priv(dev); + + spin_lock(&ap->rx_lock); + vmac_rx_refill(dev); + spin_unlock(&ap->rx_lock); +} + +/* merge buffer chaining */ +struct sk_buff *vmac_merge_rx_buffers(struct net_device *dev, + struct vmac_buffer_desc *after, + int pkt_len) /* data */ +{ + struct vmac_priv *ap = netdev_priv(dev); + struct sk_buff *merge_skb, *cur_skb; + struct dma_fifo *rx_ring; + struct vmac_buffer_desc *desc; + + rx_ring = &ap->rx_ring; + desc = &ap->rxbd[rx_ring->tail]; + + WARN_ON(desc == after); + + /* strip FCS */ + pkt_len -= 4; + + /* IP header Alignment (14 byte Ethernet header) */ + merge_skb = netdev_alloc_skb(dev, pkt_len + 2); + if (!merge_skb) { + dev_err(&ap->pdev->dev, "failed to allocate merged rx_skb, rx skb's left %d\n", + fifo_used(rx_ring)); + + return NULL; + } + + skb_reserve(merge_skb, 2); + + while (desc != after && pkt_len) { + struct vmac_buffer_desc *desc; + int buf_len, valid; + + /* desc needs wrapping */ + desc = &ap->rxbd[rx_ring->tail]; + cur_skb = ap->rx_skbuff[rx_ring->tail]; + WARN_ON(!cur_skb); + + dma_unmap_single(&ap->pdev->dev, desc->data, ap->rx_skb_size, + DMA_FROM_DEVICE); + + /* do not copy FCS */ + buf_len = desc->info & LEN_MASK; + valid = min(pkt_len, buf_len); + pkt_len -= valid; + + memcpy(skb_put(merge_skb, valid), cur_skb->data, valid); + + fifo_inc_tail(rx_ring); + } + + /* merging_pressure++ */ + + if (unlikely(pkt_len != 0)) + dev_err(&ap->pdev->dev, "buffer chaining bytes missing %d\n", + pkt_len); + + WARN_ON(desc != after); + + return merge_skb; +} + +int vmac_rx_receive(struct net_device *dev, int budget) +{ + struct vmac_priv *ap = netdev_priv(dev); + struct vmac_buffer_desc *first; + int processed, pkt_len, pkt_err; + struct dma_fifo lookahead; + + processed = 0; + + first = NULL; + pkt_err = pkt_len = 0; + + /* look ahead, till packet complete */ + lookahead = ap->rx_ring; + + do { + struct vmac_buffer_desc *desc; /* cur_ */ + int desc_idx; /* cur_ */ + struct sk_buff *skb; /* pkt_ */ + + desc_idx = lookahead.tail; + desc = &ap->rxbd[desc_idx]; + + /* make sure we read the actual descriptor status */ + rmb(); + + /* break if dma ownership belongs to hw */ + if (desc->info & OWN_MASK) { + ap->mac_rxring_head = vmac_readl(ap, MAC_RXRING_HEAD); + break; + } + + if (desc->info & FRST_MASK) { + pkt_len = 0; + pkt_err = 0; + + /* don't free current */ + ap->rx_ring.tail = lookahead.tail; + first = desc; + } + + fifo_inc_tail(&lookahead); + + /* check bd */ + + pkt_len += desc->info & LEN_MASK; + pkt_err |= (desc->info & BUFF); + + if (!(desc->info & LAST_MASK)) + continue; + + /* received complete packet */ + + if (unlikely(pkt_err || !first)) { + /* recycle buffers */ + ap->rx_ring.tail = lookahead.tail; + continue; + } + + WARN_ON(!(first->info & FRST_MASK) || + !(desc->info & LAST_MASK)); + WARN_ON(pkt_err); + + /* -- valid packet -- */ + + if (first != desc) { + skb = vmac_merge_rx_buffers(dev, desc, pkt_len); + + if (!skb) { + /* kill packet */ + ap->rx_ring.tail = lookahead.tail; + ap->rx_merge_error++; + continue; + } + } else { + dma_unmap_single(&ap->pdev->dev, desc->data, + ap->rx_skb_size, DMA_FROM_DEVICE); + + skb = ap->rx_skbuff[desc_idx]; + ap->rx_skbuff[desc_idx] = NULL; + /* desc->data != skb->data => desc->data DMA mapped */ + + /* strip FCS */ + skb_put(skb, pkt_len - 4); + } + + /* free buffers */ + ap->rx_ring.tail = lookahead.tail; + + WARN_ON(skb->len != pkt_len - 4); + processed++; + skb->dev = dev; + skb->protocol = eth_type_trans(skb, dev); + ap->stats.rx_packets++; + ap->stats.rx_bytes += skb->len; + dev->last_rx = jiffies; + netif_rx(skb); + + } while (!fifo_empty(&lookahead) && (processed < budget)); + + dev_vdbg(&ap->pdev->dev, "processed pkt %d, remaining rx buff %d\n", + processed, + fifo_used(&ap->rx_ring)); + + if (processed || fifo_empty(&ap->rx_ring)) + vmac_rx_refill(dev); + + return processed; +} + +static void vmac_toggle_irqmask(struct net_device *dev, int enable, int mask) +{ + struct vmac_priv *ap = netdev_priv(dev); + unsigned long tmp; + + tmp = vmac_readl(ap, ENABLE); + if (enable) + tmp |= mask; + else + tmp &= ~mask; + vmac_writel(ap, tmp, ENABLE); +} + +static void vmac_toggle_txint(struct net_device *dev, int enable) +{ + struct vmac_priv *ap = netdev_priv(dev); + unsigned long flags; + + spin_lock_irqsave(&ap->lock, flags); + vmac_toggle_irqmask(dev, enable, TXINT_MASK); + spin_unlock_irqrestore(&ap->lock, flags); +} + +static void vmac_toggle_rxint(struct net_device *dev, int enable) +{ + vmac_toggle_irqmask(dev, enable, RXINT_MASK); +} + +static int vmac_poll(struct napi_struct *napi, int budget) +{ + struct vmac_priv *ap; + struct net_device *dev; + int rx_work_done; + unsigned long flags; + + ap = container_of(napi, struct vmac_priv, napi); + dev = ap->dev; + + /* ack interrupt */ + vmac_writel(ap, RXINT_MASK, STAT); + + spin_lock(&ap->rx_lock); + rx_work_done = vmac_rx_receive(dev, budget); + spin_unlock(&ap->rx_lock); + +#ifdef VERBOSE_DEBUG + if (printk_ratelimit()) { + dev_vdbg(&ap->pdev->dev, "poll budget %d receive rx_work_done %d\n", + budget, + rx_work_done); + } +#endif + + if (rx_work_done >= budget) { + /* rx queue is not yet empty/clean */ + return rx_work_done; + } + + /* no more packet in rx/tx queue, remove device from poll + * queue */ + spin_lock_irqsave(&ap->lock, flags); + napi_complete(napi); + vmac_toggle_rxint(dev, 1); + spin_unlock_irqrestore(&ap->lock, flags); + + return rx_work_done; +} + +static int vmac_tx_reclaim(struct net_device *dev, int force); + +static irqreturn_t vmac_intr(int irq, void *dev_instance) +{ + struct net_device *dev = dev_instance; + struct vmac_priv *ap = netdev_priv(dev); + unsigned int status; + + spin_lock(&ap->lock); + + status = vmac_readl(ap, STAT); + vmac_writel(ap, status, STAT); + +#ifdef DEBUG + if (unlikely(ap->shutdown)) + dev_err(&ap->pdev->dev, "ISR during close\n"); + + if (unlikely(!status & (RXINT_MASK|MDIO_MASK|ERR_MASK))) + dev_err(&ap->pdev->dev, "No source of IRQ found\n"); +#endif + + if ((status & RXINT_MASK) && + (ap->mac_rxring_head != + vmac_readl(ap, MAC_RXRING_HEAD))) { + vmac_toggle_rxint(dev, 0); + napi_schedule(&ap->napi); + } + + if (unlikely(netif_queue_stopped(dev) && (status & TXINT_MASK))) + vmac_tx_reclaim(dev, 0); + + if (status & MDIO_MASK) + complete(&ap->mdio_complete); + + if (unlikely(status & ERR_MASK)) + update_error_counters(dev, status); + + spin_unlock(&ap->lock); + + return IRQ_HANDLED; +} + +static int vmac_tx_reclaim(struct net_device *dev, int force) +{ + struct vmac_priv *ap = netdev_priv(dev); + int released = 0; + + /* buffer chaining not used, see vmac_start_xmit */ + + while (!fifo_empty(&ap->tx_ring)) { + struct vmac_buffer_desc *desc; + struct sk_buff *skb; + int desc_idx; + + desc_idx = ap->tx_ring.tail; + desc = &ap->txbd[desc_idx]; + + /* ensure other field of the descriptor were not read + * before we checked ownership */ + rmb(); + + if ((desc->info & OWN_MASK) && !force) + break; + + if (desc->info & ERR_MSK_TX) { + update_tx_errors(dev, desc->info); + /* recycle packet, let upper level deal with it */ + } + + skb = ap->tx_skbuff[desc_idx]; + ap->tx_skbuff[desc_idx] = NULL; + WARN_ON(!skb); + + dma_unmap_single(&ap->pdev->dev, desc->data, skb->len, + DMA_TO_DEVICE); + + dev_kfree_skb_any(skb); + + released++; + fifo_inc_tail(&ap->tx_ring); + } + + if (netif_queue_stopped(dev) && released) { + netif_wake_queue(dev); + vmac_toggle_txint(dev, 0); + } + + if (unlikely(force && !fifo_empty(&ap->tx_ring))) { + dev_err(&ap->pdev->dev, "failed to reclaim %d tx sk_buff\n", + fifo_used(&ap->tx_ring)); + } + + return released; +} + +int vmac_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct vmac_priv *ap = netdev_priv(dev); + struct vmac_buffer_desc *desc; + unsigned int tmp; + + /* running under xmit lock */ + + /* no scatter/gatter see features below */ + WARN_ON(skb_shinfo(skb)->nr_frags != 0); + WARN_ON(skb->len > MAX_TX_BUFFER_LEN); + + if (unlikely(fifo_full(&ap->tx_ring))) { + netif_stop_queue(dev); + vmac_toggle_txint(dev, 1); + dev_err(&ap->pdev->dev, "xmit called with no tx desc available\n"); + return NETDEV_TX_BUSY; + } + + if (unlikely(skb->len < ETH_ZLEN)) { + struct sk_buff *short_skb; + short_skb = netdev_alloc_skb(dev, ETH_ZLEN); + if (!short_skb) + return NETDEV_TX_LOCKED; + + memset(short_skb->data, 0, ETH_ZLEN); + memcpy(skb_put(short_skb, ETH_ZLEN), skb->data, skb->len); + dev_kfree_skb(skb); + skb = short_skb; + } + + /* fill descriptor */ + ap->tx_skbuff[ap->tx_ring.head] = skb; + + desc = &ap->txbd[ap->tx_ring.head]; + desc->data = dma_map_single(&ap->pdev->dev, skb->data, skb->len, + DMA_TO_DEVICE); + + /* dma might already be polling */ + wmb(); + desc->info = OWN_MASK | FRST_MASK | LAST_MASK | skb->len; + wmb(); + + /* kick tx dma */ + tmp = vmac_readl(ap, STAT); + vmac_writel(ap, tmp | TXPL_MASK, STAT); + + ap->stats.tx_packets++; + ap->stats.tx_bytes += skb->len; + dev->trans_start = jiffies; + fifo_inc_head(&ap->tx_ring); + + /* vmac_tx_reclaim independent of vmac_tx_timeout */ + if (fifo_used(&ap->tx_ring) > 8) + vmac_tx_reclaim(dev, 0); + + /* stop queue if no more desc available */ + if (fifo_full(&ap->tx_ring)) { + netif_stop_queue(dev); + vmac_toggle_txint(dev, 1); + } + + return NETDEV_TX_OK; +} + +static int alloc_buffers(struct net_device *dev) +{ + struct vmac_priv *ap = netdev_priv(dev); + int err = -ENOMEM; + int size; + + fifo_init(&ap->rx_ring, RX_BDT_LEN); + fifo_init(&ap->tx_ring, TX_BDT_LEN); + + /* initialize skb list */ + memset(ap->rx_skbuff, 0, sizeof(ap->rx_skbuff)); + memset(ap->tx_skbuff, 0, sizeof(ap->tx_skbuff)); + + /* allocate DMA received descriptors */ + size = sizeof(*ap->rxbd) * ap->rx_ring.size; + ap->rxbd = dma_alloc_coherent(&ap->pdev->dev, size, + &ap->rxbd_dma, + GFP_KERNEL); + if (ap->rxbd == NULL) + goto err_out; + + /* allocate DMA transmit descriptors */ + size = sizeof(*ap->txbd) * ap->tx_ring.size; + ap->txbd = dma_alloc_coherent(&ap->pdev->dev, size, + &ap->txbd_dma, + GFP_KERNEL); + if (ap->txbd == NULL) + goto err_free_rxbd; + + /* ensure 8-byte aligned */ + WARN_ON(((int)ap->txbd & 0x7) || ((int)ap->rxbd & 0x7)); + + memset(ap->txbd, 0, sizeof(*ap->txbd) * ap->tx_ring.size); + memset(ap->rxbd, 0, sizeof(*ap->rxbd) * ap->rx_ring.size); + + /* allocate rx skb */ + err = vmac_rx_refill(dev); + if (err) + goto err_free_txbd; + + return 0; + +err_free_txbd: + dma_free_coherent(&ap->pdev->dev, sizeof(*ap->txbd) * ap->tx_ring.size, + ap->txbd, ap->txbd_dma); +err_free_rxbd: + dma_free_coherent(&ap->pdev->dev, sizeof(*ap->rxbd) * ap->rx_ring.size, + ap->rxbd, ap->rxbd_dma); +err_out: + return err; +} + +static int free_buffers(struct net_device *dev) +{ + struct vmac_priv *ap = netdev_priv(dev); + + /* free skbuff */ + vmac_tx_reclaim(dev, 1); + vmac_rx_reclaim_force(dev); + + /* free DMA ring */ + dma_free_coherent(&ap->pdev->dev, sizeof(ap->txbd) * ap->tx_ring.size, + ap->txbd, ap->txbd_dma); + dma_free_coherent(&ap->pdev->dev, sizeof(ap->rxbd) * ap->rx_ring.size, + ap->rxbd, ap->rxbd_dma); + + return 0; +} + +static int vmac_hw_init(struct net_device *dev) +{ + struct vmac_priv *priv = netdev_priv(dev); + + /* clear IRQ mask */ + vmac_writel(priv, 0, ENABLE); + + /* clear pending IRQ */ + vmac_writel(priv, 0xffffffff, STAT); + + /* Initialize logical address filter */ + vmac_writel(priv, 0x0, LAFL); + vmac_writel(priv, 0x0, LAFH); + + return 0; +} + +#ifdef DEBUG +static int vmac_register_print(struct net_device *dev) +{ + struct vmac_priv *ap = netdev_priv(dev); + + printk("func::%s vmac register %s value = 0x%x\n", __func__, "ID", vmac_readl(ap, ID)); + printk("func::%s vmac register %s value = 0x%x\n", __func__, "STAT", vmac_readl(ap, STAT)); + printk("func::%s vmac register %s value = 0x%x\n", __func__, "ENABLE", vmac_readl(ap, ENABLE)); + printk("func::%s vmac register %s value = 0x%x\n", __func__, "CONTROL", vmac_readl(ap, CONTROL)); + printk("func::%s vmac register %s value = 0x%x\n", __func__, "ADDRL", vmac_readl(ap, ADDRL)); + printk("func::%s vmac register %s value = 0x%x\n", __func__, "ADDRH", vmac_readl(ap, ADDRH)); + + return 0; +} +#endif + +int vmac_open(struct net_device *dev) +{ + struct vmac_priv *ap = netdev_priv(dev); + struct phy_device *phydev; + unsigned int temp; + int err = 0; + struct clk *mac_clk = NULL; + struct clk *mac_parent = NULL; + struct clk *arm_clk = NULL; + struct rk29_vmac_platform_data *pdata = ap->pdev->dev.platform_data; + unsigned char current_mac[6]; + int ret = 0; + struct pinctrl_state *clkout_state; + + printk("enter func %s...\n", __func__); + + if (ap == NULL) + return -ENODEV; + + wake_lock_timeout(&ap->resume_lock, 5*HZ); + + ap->shutdown = 0; + + // switch to rmii + printk("ap->pdev->dev.pins->p = %p\n", ap->pdev->dev.pins->p); + clkout_state = pinctrl_lookup_state(ap->pdev->dev.pins->p, "default"); + if (IS_ERR(clkout_state)) { + dev_err(&ap->pdev->dev, "no clkout pinctrl state\n"); + goto err_out; + } + + printk("in pinctrl_select_state.\n"); + pinctrl_select_state(ap->pdev->dev.pins->p, clkout_state); + + //set rmii ref clock 50MHz + mac_clk = devm_clk_get(&ap->pdev->dev, "clk_mac"); + /*if (IS_ERR(mac_clk)) + mac_clk = NULL; + arm_clk = clk_get(NULL, "arm_pll"); + if (IS_ERR(arm_clk)) + arm_clk = NULL; + if (mac_clk) { + mac_parent = clk_get_parent(mac_clk); + if (IS_ERR(mac_parent)) + mac_parent = NULL; + } + if (arm_clk && mac_parent && (arm_clk == mac_parent)) + wake_lock(&idlelock); + + if(pdata && pdata->rmii_extclk_sel && pdata->rmii_extclk_sel()) + { + struct clk * mac_clkin = NULL; + mac_clkin = clk_get(NULL, "rmii_clkin"); + if (IS_ERR(mac_clkin)) { + pr_err("mac_clkin get fail\n"); + } + clk_set_parent(mac_clk, mac_clkin); + }*/ + + clk_set_rate(mac_clk, 50000000); + clk_prepare_enable(mac_clk); + //clk_enable(clk_get(NULL,"mii_rx")); + //clk_enable(clk_get(NULL,"mii_tx")); + //clk_enable(clk_get(NULL,"hclk_mac")); + + //phy power on + if (pdata && pdata->rmii_power_control) + pdata->rmii_power_control(1); + + msleep(1000); + + vmac_hw_init(dev); + +//$_rbox_$_modify_$_chenxiao + if (is_valid_ether_addr(dev->dev_addr)){ + strlcpy(current_mac,dev->dev_addr,6); + } + +#ifdef CONFIG_ETH_MAC_FROM_EEPROM + ret = eeprom_read_data(0,dev->dev_addr,6); + if (ret != 6){ + printk("read mac from Eeprom fail.\n"); + }else { + if (is_valid_ether_addr(dev->dev_addr)){ + printk("eth_mac_from_eeprom***********:%X:%X:%X:%X:%X:%X\n",dev->dev_addr[0], + dev->dev_addr[1],dev->dev_addr[2],dev->dev_addr[3], + dev->dev_addr[4],dev->dev_addr[5] ); + } + } +#endif + +#ifdef CONFIG_ETH_MAC_FROM_IDB + err = eth_mac_idb(dev->dev_addr); + if (err) { + printk("read mac from IDB fail.\n"); + } else { + if (is_valid_ether_addr(dev->dev_addr)) { + printk("eth_mac_from_idb***********:%X:%X:%X:%X:%X:%X\n",dev->dev_addr[0], + dev->dev_addr[1],dev->dev_addr[2],dev->dev_addr[3], + dev->dev_addr[4],dev->dev_addr[5] ); + } + } +#endif + +#ifdef CONFIG_ETH_MAC_FROM_WIFI_MAC + err = eth_mac_wifi(dev->dev_addr); + if (err) { + printk("read mac from Wifi fail.\n"); + } else { + if (is_valid_ether_addr(dev->dev_addr)) { + printk("eth_mac_from_wifi_mac***********:%X:%X:%X:%X:%X:%X\n",dev->dev_addr[0], + dev->dev_addr[1],dev->dev_addr[2],dev->dev_addr[3], + dev->dev_addr[4],dev->dev_addr[5] ); + } + } +#endif + +#ifdef CONFIG_ETH_MAC_FROM_SECURE_CHIP + +#endif + + + if (!is_valid_ether_addr(dev->dev_addr)) { + strlcpy(dev->dev_addr,current_mac,6); + printk("eth_mac_from_RANDOM***********:%X:%X:%X:%X:%X:%X\n",dev->dev_addr[0], + dev->dev_addr[1],dev->dev_addr[2],dev->dev_addr[3], + dev->dev_addr[4],dev->dev_addr[5] ); + } +//add end + + /* mac address changed? */ + write_mac_reg(dev, dev->dev_addr); + + err = alloc_buffers(dev); + if (err) + goto err_out; + + err = request_irq(dev->irq, &vmac_intr, 0, dev->name, dev); + if (err) { + dev_err(&ap->pdev->dev, "Unable to request IRQ %d (error %d)\n", + dev->irq, err); + goto err_free_buffers; + } + + /* install DMA ring pointers */ + vmac_writel(ap, ap->rxbd_dma, RXRINGPTR); + vmac_writel(ap, ap->txbd_dma, TXRINGPTR); + + /* set poll rate to 1 ms */ + vmac_writel(ap, POLLRATE_TIME, POLLRATE); + + /* make sure we enable napi before rx interrupt */ + napi_enable(&ap->napi); + + /* IRQ mask */ + temp = RXINT_MASK | ERR_MASK | TXCH_MASK | MDIO_MASK; + vmac_writel(ap, temp, ENABLE); + + /* Set control */ + temp = (RX_BDT_LEN << 24) | (TX_BDT_LEN << 16) | TXRN_MASK | RXRN_MASK; + vmac_writel(ap, temp, CONTROL); + + /* enable, after all other bits are set */ + vmac_writel(ap, temp | EN_MASK, CONTROL); + + netif_start_queue(dev); + netif_carrier_off(dev); + +#ifdef DEBUG + vmac_register_print(dev); +#endif + + /* register the PHY board fixup, if needed */ + err = vmac_mii_init(ap); + if (err) + goto err_free_irq; + + /* schedule a link state check */ + phy_start(ap->phy_dev); + + phydev = ap->phy_dev; + dev_info(&ap->pdev->dev, "PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n", + phydev->drv->name, dev_name(&phydev->dev), phydev->irq); + + ap->suspending = 0; + ap->open_flag = 1; + + return 0; + +err_free_irq: + free_irq(dev->irq, dev); +err_free_buffers: + free_buffers(dev); +err_out: + //if (arm_clk && mac_parent && (arm_clk == mac_parent)) + // wake_unlock(&idlelock); + + return err; +} + +int vmac_close(struct net_device *dev) +{ + struct vmac_priv *ap = netdev_priv(dev); + unsigned int temp; + struct clk *mac_clk = NULL; + struct clk *arm_clk = NULL; + struct clk *mac_parent = NULL; + struct rk29_vmac_platform_data *pdata = ap->pdev->dev.platform_data; + + printk("enter func %s...\n", __func__); + + if (ap->suspending == 1) + return 0; + + ap->open_flag = 0; + + netif_stop_queue(dev); + napi_disable(&ap->napi); + + /* stop running transfers */ + temp = vmac_readl(ap, CONTROL); + temp &= ~(TXRN_MASK | RXRN_MASK); + vmac_writel(ap, temp, CONTROL); + + del_timer_sync(&ap->rx_timeout); + + /* disable phy */ + phy_stop(ap->phy_dev); + vmac_mii_exit(dev); + netif_carrier_off(dev); + + /* disable interrupts */ + vmac_writel(ap, 0, ENABLE); + free_irq(dev->irq, dev); + + /* turn off vmac */ + vmac_writel(ap, 0, CONTROL); + /* vmac_reset_hw(vmac) */ + + ap->shutdown = 1; + wmb(); + + free_buffers(dev); + + //phy power off + if (pdata && pdata->rmii_power_control) + pdata->rmii_power_control(0); + + //clock close + /*mac_clk = clk_get(NULL, "mac_ref_div"); + if (IS_ERR(mac_clk)) + mac_clk = NULL; + if (mac_clk) { + mac_parent = clk_get_parent(mac_clk); + if (IS_ERR(mac_parent)) + mac_parent = NULL; + } + arm_clk = clk_get(NULL, "arm_pll"); + if (IS_ERR(arm_clk)) + arm_clk = NULL; + + if (arm_clk && mac_parent && (arm_clk == mac_parent)) + wake_unlock(&idlelock);*/ + + clk_disable(clk_get(&ap->pdev->dev,"clk_mac")); + //clk_disable(clk_get(NULL,"mii_tx")); + //clk_disable(clk_get(NULL,"hclk_mac")); + //clk_disable(clk_get(NULL,"clk_mac_pll")); + + return 0; +} + +int vmac_shutdown(struct net_device *dev) +{ + struct vmac_priv *ap = netdev_priv(dev); + unsigned int temp; + + printk("enter func %s...\n", __func__); + + netif_stop_queue(dev); + napi_disable(&ap->napi); + + /* stop running transfers */ + temp = vmac_readl(ap, CONTROL); + temp &= ~(TXRN_MASK | RXRN_MASK); + vmac_writel(ap, temp, CONTROL); + + del_timer_sync(&ap->rx_timeout); + + /* disable phy */ + phy_stop(ap->phy_dev); + vmac_mii_exit(dev); + netif_carrier_off(dev); + + /* disable interrupts */ + vmac_writel(ap, 0, ENABLE); + free_irq(dev->irq, dev); + + /* turn off vmac */ + vmac_writel(ap, 0, CONTROL); + /* vmac_reset_hw(vmac) */ + + ap->shutdown = 1; + wmb(); + + free_buffers(dev); + + return 0; +} + +void vmac_update_stats(struct vmac_priv *ap) +{ + struct net_device_stats *_stats = &ap->stats; + unsigned long miss, rxerr; + unsigned long rxfram, rxcrc, rxoflow; + + /* compare with /proc/net/dev, + * see net/core/dev.c:dev_seq_printf_stats */ + + /* rx stats */ + rxerr = vmac_readl(ap, RXERR); + miss = vmac_readl(ap, MISS); + + rxcrc = (rxerr & RXERR_CRC); + rxfram = (rxerr & RXERR_FRM) >> 8; + rxoflow = (rxerr & RXERR_OFLO) >> 16; + + _stats->rx_length_errors = 0; + _stats->rx_over_errors += miss; + _stats->rx_crc_errors += rxcrc; + _stats->rx_frame_errors += rxfram; + _stats->rx_fifo_errors += rxoflow; + _stats->rx_missed_errors = 0; + + /* TODO check rx_dropped/rx_errors/tx_dropped/tx_errors have not + * been updated elsewhere */ + _stats->rx_dropped = _stats->rx_over_errors + + _stats->rx_fifo_errors + + ap->rx_merge_error; + + _stats->rx_errors = _stats->rx_length_errors + _stats->rx_crc_errors + + _stats->rx_frame_errors + + _stats->rx_missed_errors + + _stats->rx_dropped; + + /* tx stats */ + _stats->tx_dropped = 0; /* otherwise queue stopped */ + + _stats->tx_errors = _stats->tx_aborted_errors + + _stats->tx_carrier_errors + + _stats->tx_fifo_errors + + _stats->tx_heartbeat_errors + + _stats->tx_window_errors + + _stats->tx_dropped + + ap->tx_timeout_error; +} + +struct net_device_stats *vmac_stats(struct net_device *dev) +{ + struct vmac_priv *ap = netdev_priv(dev); + unsigned long flags; + + spin_lock_irqsave(&ap->lock, flags); + vmac_update_stats(ap); + spin_unlock_irqrestore(&ap->lock, flags); + + return &ap->stats; +} + +void vmac_tx_timeout(struct net_device *dev) +{ + struct vmac_priv *ap = netdev_priv(dev); + unsigned int status; + unsigned long flags; + + spin_lock_irqsave(&ap->lock, flags); + + /* queue did not progress for timeo jiffies */ + WARN_ON(!netif_queue_stopped(dev)); + WARN_ON(!fifo_full(&ap->tx_ring)); + + /* TX IRQ lost? */ + status = vmac_readl(ap, STAT); + if (status & TXINT_MASK) { + dev_err(&ap->pdev->dev, "lost tx interrupt, IRQ mask %x\n", + vmac_readl(ap, ENABLE)); + vmac_writel(ap, TXINT_MASK, STAT); + } + + /* TODO RX/MDIO/ERR as well? */ + + vmac_tx_reclaim(dev, 0); + if (fifo_full(&ap->tx_ring)) + dev_err(&ap->pdev->dev, "DMA state machine not active\n"); + + /* We can accept TX packets again */ + ap->tx_timeout_error++; + dev->trans_start = jiffies; + netif_wake_queue(dev); + + spin_unlock_irqrestore(&ap->lock, flags); +} + +static void create_multicast_filter(struct net_device *dev, + unsigned long *bitmask) +{ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)) + struct netdev_hw_addr *ha; + unsigned long crc; + char *addrs; + struct netdev_hw_addr_list *list = &dev->dev_addrs; + + //printk("-----------------func %s-------------------\n", __func__); + + WARN_ON(dev->mc_count == 0); + WARN_ON(dev->flags & IFF_ALLMULTI); + + bitmask[0] = bitmask[1] = 0; + + list_for_each_entry(ha, &list->list, list) { + addrs = ha->addr; + + /* skip non-multicast addresses */ + if (!(*addrs & 1)) + continue; + + crc = ether_crc_le(ETH_ALEN, addrs); + set_bit(crc >> 26, bitmask); + + } +#else + struct netdev_hw_addr *ha; + unsigned long crc; + char *addrs; + + WARN_ON(netdev_mc_count(dev) == 0); + WARN_ON(dev->flags & IFF_ALLMULTI); + + bitmask[0] = bitmask[1] = 0; + + netdev_for_each_mc_addr(ha, dev) { + addrs = ha->addr; + + /* skip non-multicast addresses */ + if (!(*addrs & 1)) + continue; + + crc = ether_crc_le(ETH_ALEN, addrs); + set_bit(crc >> 26, bitmask); + } +#endif +} +static void vmac_set_multicast_list(struct net_device *dev) +{ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)) + struct vmac_priv *ap = netdev_priv(dev); + unsigned long flags, bitmask[2]; + int promisc, reg; + + //printk("-----------------func %s-------------------\n", __func__); + + spin_lock_irqsave(&ap->lock, flags); + + promisc = !!(dev->flags & IFF_PROMISC); + reg = vmac_readl(ap, CONTROL); + if (promisc != !!(reg & PROM_MASK)) { + reg ^= PROM_MASK; + vmac_writel(ap, reg, CONTROL); + } + + if (dev->flags & IFF_ALLMULTI) + memset(bitmask, 1, sizeof(bitmask)); + else if (dev->mc_count == 0) + memset(bitmask, 0, sizeof(bitmask)); + else + create_multicast_filter(dev, bitmask); + + vmac_writel(ap, bitmask[0], LAFL); + vmac_writel(ap, bitmask[1], LAFH); + + spin_unlock_irqrestore(&ap->lock, flags); +#else + struct vmac_priv *ap = netdev_priv(dev); + unsigned long flags, bitmask[2]; + int promisc, reg; + + spin_lock_irqsave(&ap->lock, flags); + + promisc = !!(dev->flags & IFF_PROMISC); + reg = vmac_readl(ap, CONTROL); + if (promisc != !!(reg & PROM_MASK)) { + reg ^= PROM_MASK; + vmac_writel(ap, reg, CONTROL); + } + + if (dev->flags & IFF_ALLMULTI) + memset(bitmask, 1, sizeof(bitmask)); + else if (netdev_mc_count(dev) == 0) + memset(bitmask, 0, sizeof(bitmask)); + else + create_multicast_filter(dev, bitmask); + + vmac_writel(ap, bitmask[0], LAFL); + vmac_writel(ap, bitmask[1], LAFH); + + spin_unlock_irqrestore(&ap->lock, flags); +#endif +} + +static struct ethtool_ops vmac_ethtool_ops = { + .get_settings = vmacether_get_settings, + .set_settings = vmacether_set_settings, + .get_drvinfo = vmacether_get_drvinfo, + .get_link = ethtool_op_get_link, +}; + +static const struct net_device_ops vmac_netdev_ops = { + .ndo_open = vmac_open, + .ndo_stop = vmac_close, + .ndo_get_stats = vmac_stats, + .ndo_start_xmit = vmac_start_xmit, + .ndo_do_ioctl = vmac_ioctl, + .ndo_set_mac_address = eth_mac_addr, + .ndo_tx_timeout = vmac_tx_timeout, + //.ndo_set_multicast_list = vmac_set_multicast_list, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, +}; + +static int vmac_probe(struct platform_device *pdev) +{ + struct net_device *dev; + struct vmac_priv *ap; + struct resource *res; + unsigned int mem_base, mem_size, irq; + int err; + struct rk29_vmac_platform_data *pdata; + struct device_node *np = pdev->dev.of_node; + + printk("vmac_probe.\n"); + dev_dbg(&pdev->dev, "vmac_probe 1.\n"); + + pdev->dev.platform_data = &board_vmac_data; + pdata = pdev->dev.platform_data; + + dev = alloc_etherdev(sizeof(*ap)); + if (!dev) { + dev_err(&pdev->dev, "etherdev alloc failed, aborting.\n"); + return -ENOMEM; + } + + ap = netdev_priv(dev); + + err = -ENODEV; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "no mmio resource defined\n"); + goto err_out; + } + mem_base = res->start; + mem_size = resource_size(res); + irq = platform_get_irq(pdev, 0); + + /*err = -EBUSY; + if (!devm_request_mem_region(&pdev->dev, mem_base, mem_size, VMAC_NAME)) { + dev_err(&pdev->dev, "no memory region available\n"); + goto err_out; + }*/ + + err = -ENOMEM; + ap->regs = devm_ioremap_resource(&pdev->dev, res); + if (!ap->regs) { + dev_err(&pdev->dev, "failed to map registers, aborting.\n"); + goto err_out_release_mem; + } + + printk("mem_base = 0x%08x, mem_size = 0x%08x, irq = %d, regs = 0x%08x\n", + mem_base, mem_size, irq, ap->regs); + + /* no checksum support, hence no scatter/gather */ + dev->features |= NETIF_F_HIGHDMA; + + spin_lock_init(&ap->lock); + + SET_NETDEV_DEV(dev, &pdev->dev); + ap->dev = dev; + ap->pdev = pdev; + + /* init rx timeout (used for oom) */ + init_timer(&ap->rx_timeout); + ap->rx_timeout.function = vmac_refill_rx_timer; + ap->rx_timeout.data = (unsigned long)dev; + + netif_napi_add(dev, &ap->napi, vmac_poll, 2); + dev->netdev_ops = &vmac_netdev_ops; + dev->ethtool_ops = &vmac_ethtool_ops; + dev->irq = irq; + + dev->flags |= IFF_MULTICAST;//////////////////// + + dev->base_addr = (unsigned long)ap->regs; + ap->mem_base = mem_base; + + /* prevent buffer chaining, favor speed over space */ + ap->rx_skb_size = ETH_FRAME_LEN + VMAC_BUFFER_PAD; + + /* private struct functional */ + + /* mac address intialize, set vmac_open */ + read_mac_reg(dev, dev->dev_addr); + + if (!is_valid_ether_addr(dev->dev_addr)) + random_ether_addr(dev->dev_addr); + + err = register_netdev(dev); + if (err) { + dev_err(&pdev->dev, "Cannot register net device, aborting.\n"); + goto err_out_iounmap; + } + + dev_info(&pdev->dev, "ARC VMAC at 0x%08x irq %d %pM\n", mem_base, + dev->irq, dev->dev_addr); + platform_set_drvdata(pdev, dev); + + ap->suspending = 0; + ap->open_flag = 0; + //wake_lock_init(&idlelock, WAKE_LOCK_IDLE, "vmac"); + wake_lock_init(&ap->resume_lock, WAKE_LOCK_SUSPEND, "vmac_resume"); + + //config rk29 vmac as rmii, 100MHz + if (pdata && pdata->vmac_register_set) + pdata->vmac_register_set(); + + //power gpio init, phy power off default for power reduce + if (pdata && pdata->rmii_io_init) + pdata->rmii_io_init(); + + return 0; + +err_out_iounmap: + iounmap(ap->regs); +err_out_release_mem: + release_mem_region(mem_base, mem_size); +err_out: + free_netdev(dev); + return err; +} + +static int vmac_remove(struct platform_device *pdev) +{ + struct net_device *dev; + struct vmac_priv *ap; + struct resource *res; + struct rk29_vmac_platform_data *pdata = pdev->dev.platform_data; + + //wake_lock_destroy(&idlelock); + + //power gpio deinit, phy power off + if (pdata && pdata->rmii_io_deinit) + pdata->rmii_io_deinit(); + + dev = platform_get_drvdata(pdev); + if (!dev) { + dev_err(&pdev->dev, "%s no valid dev found\n", __func__); + return 0; + } + + ap = netdev_priv(dev); + + /* MAC */ + unregister_netdev(dev); + iounmap(ap->regs); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, resource_size(res)); + + platform_set_drvdata(pdev, NULL); + free_netdev(dev); + return 0; +} + +static void rk29_vmac_power_off(struct net_device *dev) +{ + struct vmac_priv *ap = netdev_priv(dev); + struct rk29_vmac_platform_data *pdata = ap->pdev->dev.platform_data; + + printk("enter func %s...\n", __func__); + + //phy power off + if (pdata && pdata->rmii_power_control) + pdata->rmii_power_control(0); + + //clock close + clk_disable(clk_get(&ap->pdev->dev,"clk_mac")); + //clk_disable(clk_get(NULL,"mii_tx")); + //clk_disable(clk_get(NULL,"hclk_mac")); + //clk_disable(clk_get(NULL,"clk_mac_pll")); + +} + +static int +rk29_vmac_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct net_device *ndev = platform_get_drvdata(pdev); + struct vmac_priv *ap = netdev_priv(ndev); + + if (ndev) { + if (ap->open_flag == 1) { + netif_stop_queue(ndev); + netif_device_detach(ndev); + if (ap->suspending == 0) { +//$_rbox_$_modify_$_chenzhi: for ethernet sleep +#if 0 + vmac_shutdown(ndev); + rk29_vmac_power_off(ndev); +#endif + ap->suspending = 1; + } + } + } + return 0; +} + +static int +rk29_vmac_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct net_device *ndev = platform_get_drvdata(pdev); + struct vmac_priv *ap = netdev_priv(ndev); + + if (ndev) { + if (ap->open_flag == 1) { + netif_device_attach(ndev); + netif_start_queue(ndev); +//$_rbox_$_modify_$_chenzhi: +//$_rbox_$_modify_$_begin + if (ap->suspending == 1) { + ap->suspending = 0; + } +//$_rbox_$_modify_$_end + } + } + return 0; +} + +static struct dev_pm_ops rk29_vmac_pm_ops = { + .suspend = rk29_vmac_suspend, + .resume = rk29_vmac_resume, +}; + +static const struct of_device_id rockchip_vmac_of_match[] = { + { .compatible = "rockchip,vmac", .data = NULL, }, + {}, +}; +MODULE_DEVICE_TABLE(of, rockchip_vmac_of_match); + +static struct platform_driver rockchip_vmac_driver = { + .probe = vmac_probe, + .remove = vmac_remove, + .driver = { + .owner = THIS_MODULE, + .name = "rockchip,vmac", + .pm = &rk29_vmac_pm_ops, + .of_match_table = of_match_ptr(rockchip_vmac_of_match), + }, +}; + +static int __init vmac_init(void) +{ + printk("vmac_init.\n"); + return platform_driver_register(&rockchip_vmac_driver); +} + +static void __exit vmac_exit(void) +{ + platform_driver_unregister(&rockchip_vmac_driver); +} + +module_init(vmac_init); +module_exit(vmac_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("RK29 VMAC Ethernet driver"); +MODULE_AUTHOR("amit.bhor@celunite.com, sameer.dhavale@celunite.com, andreas.fenkart@streamunlimited.com"); diff --git a/drivers/net/ethernet/rk/vmac/rk29_vmac.h b/drivers/net/ethernet/rk/vmac/rk29_vmac.h new file mode 100755 index 000000000000..a6cf94e28ea0 --- /dev/null +++ b/drivers/net/ethernet/rk/vmac/rk29_vmac.h @@ -0,0 +1,287 @@ +/* + * linux/arch/arc/drivers/arcvmac.h + * + * Copyright (C) 2003-2006 Codito Technologies, for linux-2.4 port + * Copyright (C) 2006-2007 Celunite Inc, for linux-2.6 port + * Copyright (C) 2007-2008 Sagem Communications, Fehmi HAFSI + * Copyright (C) 2009 Sagem Communications, Andreas Fenkart + * All Rights Reserved. + * + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * Authors: amit.bhor@celunite.com, sameer.dhavale@celunite.com + */ + +#ifndef _ARCVMAC_H +#define _ARCVMAC_H + +#define VMAC_NAME "rockchip,vmac" +#define VMAC_VERSION "1.0" + +/* Buffer descriptors */ +#ifdef CONFIG_ARCH_RK29 +#define TX_BDT_LEN 16 /* Number of receive BD's */ +#else +#define TX_BDT_LEN 255 /* Number of receive BD's */ +#endif +#define RX_BDT_LEN 255 /* Number of transmit BD's */ + +/* BD poll rate, in 1024 cycles. @100Mhz: x * 1024 cy * 10ns = 1ms */ +#define POLLRATE_TIME 200 + +/* next power of two, bigger than ETH_FRAME_LEN + VLAN */ +#define MAX_RX_BUFFER_LEN 0x800 /* 2^11 = 2048 = 0x800 */ +#define MAX_TX_BUFFER_LEN 0x800 /* 2^11 = 2048 = 0x800 */ + +/* 14 bytes of ethernet header, 4 bytes VLAN, FCS, + * plus extra pad to prevent buffer chaining of + * maximum sized ethernet packets (1514 bytes) */ +#define VMAC_BUFFER_PAD (ETH_HLEN + 4 + ETH_FCS_LEN + 4) + +/* VMAC register definitions, offsets in the ref manual are in bytes */ +#define ID_OFFSET (0x00/0x4) +#define STAT_OFFSET (0x04/0x4) +#define ENABLE_OFFSET (0x08/0x4) +#define CONTROL_OFFSET (0x0c/0x4) +#define POLLRATE_OFFSET (0x10/0x4) +#define RXERR_OFFSET (0x14/0x4) +#define MISS_OFFSET (0x18/0x4) +#define TXRINGPTR_OFFSET (0x1c/0x4) +#define RXRINGPTR_OFFSET (0x20/0x4) +#define ADDRL_OFFSET (0x24/0x4) +#define ADDRH_OFFSET (0x28/0x4) +#define LAFL_OFFSET (0x2c/0x4) +#define LAFH_OFFSET (0x30/0x4) +#define MDIO_DATA_OFFSET (0x34/0x4) +#define MAC_TXRING_HEAD_OFFSET (0x38/0x4) +#define MAC_RXRING_HEAD_OFFSET (0x3C/0x4) + +/* STATUS and ENABLE register bit masks */ +#define TXINT_MASK (1<<0) /* Transmit interrupt */ +#define RXINT_MASK (1<<1) /* Receive interrupt */ +#define ERR_MASK (1<<2) /* Error interrupt */ +#define TXCH_MASK (1<<3) /* Transmit chaining error interrupt */ +#define MSER_MASK (1<<4) /* Missed packet counter error */ +#define RXCR_MASK (1<<8) /* RXCRCERR counter rolled over */ +#define RXFR_MASK (1<<9) /* RXFRAMEERR counter rolled over */ +#define RXFL_MASK (1<<10) /* RXOFLOWERR counter rolled over */ +#define MDIO_MASK (1<<12) /* MDIO complete */ +#define TXPL_MASK (1<<31) /* TXPOLL */ + +/* CONTROL register bitmasks */ +#define EN_MASK (1<<0) /* VMAC enable */ +#define TXRN_MASK (1<<3) /* TX enable */ +#define RXRN_MASK (1<<4) /* RX enable */ +#define DSBC_MASK (1<<8) /* Disable receive broadcast */ +#define ENFL_MASK (1<<10) /* Enable Full Duplex */ /////// +#define PROM_MASK (1<<11) /* Promiscuous mode */ + +/* RXERR register bitmasks */ +#define RXERR_CRC 0x000000ff +#define RXERR_FRM 0x0000ff00 +#define RXERR_OFLO 0x00ff0000 /* fifo overflow */ + +/* MDIO data register bit masks */ +#define MDIO_SFD 0xC0000000 +#define MDIO_OP 0x30000000 +#define MDIO_ID_MASK 0x0F800000 +#define MDIO_REG_MASK 0x007C0000 +#define MDIO_TA 0x00030000 +#define MDIO_DATA_MASK 0x0000FFFF + +#define MDIO_BASE 0x40020000 +#define MDIO_OP_READ 0x20000000 +#define MDIO_OP_WRITE 0x10000000 + +/* Buffer descriptor INFO bit masks */ +#define OWN_MASK (1<<31) /* ownership of buffer, 0 CPU, 1 DMA */ +#define BUFF (1<<30) /* buffer invalid, rx */ +#define UFLO (1<<29) /* underflow, tx */ +#define LTCL (1<<28) /* late collision, tx */ +#define RETRY_CT (0xf<<24) /* tx */ +#define DROP (1<<23) /* drop, more than 16 retries, tx */ +#define DEFER (1<<22) /* traffic on the wire, tx */ +#define CARLOSS (1<<21) /* carrier loss while transmission, tx, rx? */ +/* 20:19 reserved */ +#define ADCR (1<<18) /* add crc, ignored if not disaddcrc */ +#define LAST_MASK (1<<17) /* Last buffer in chain */ +#define FRST_MASK (1<<16) /* First buffer in chain */ +/* 15:11 reserved */ +#define LEN_MASK 0x000007FF + +#define ERR_MSK_TX 0x3fe00000 /* UFLO | LTCL | RTRY | DROP | DEFER | CRLS */ + + +/* arcvmac private data structures */ +struct vmac_buffer_desc { + unsigned int info; + dma_addr_t data; +}; + +struct dma_fifo { + int head; /* head */ + int tail; /* tail */ + int size; +}; + +struct vmac_priv { + struct net_device *dev; + struct platform_device *pdev; + struct net_device_stats stats; + + spinlock_t lock; /* TODO revisit */ + struct completion mdio_complete; + + /* base address of register set */ + int *regs; + unsigned int mem_base; + + /* DMA ring buffers */ + struct vmac_buffer_desc *rxbd; + dma_addr_t rxbd_dma; + + struct vmac_buffer_desc *txbd; + dma_addr_t txbd_dma; + + /* socket buffers */ + struct sk_buff *rx_skbuff[RX_BDT_LEN]; + struct sk_buff *tx_skbuff[TX_BDT_LEN]; + int rx_skb_size; + + /* skb / dma desc managing */ + struct dma_fifo rx_ring; + struct dma_fifo tx_ring; + + /* descriptor last polled/processed by the VMAC */ + unsigned long mac_rxring_head; + /* used when rx skb allocation failed, so we defer rx queue + * refill */ + struct timer_list rx_timeout; + + /* lock rx_timeout against rx normal operation */ + spinlock_t rx_lock; + + struct napi_struct napi; + + /* rx buffer chaining */ + int rx_merge_error; + int tx_timeout_error; + + /* PHY stuff */ + struct mii_bus *mii_bus; + struct phy_device *phy_dev; + + int link; + int speed; + int duplex; + + int open_flag; + int suspending; + struct wake_lock resume_lock; + + /* debug */ + int shutdown; +}; + +/* DMA ring management */ + +/* for a fifo with size n, + * - [0..n] fill levels are n + 1 states + * - there are only n different deltas (head - tail) values + * => not all fill levels can be represented with head, tail + * pointers only + * we give up the n fill level, aka fifo full */ + +/* sacrifice one elt as a sentinel */ +static inline int fifo_used(struct dma_fifo *f); +static inline int fifo_inc_ct(int ct, int size); +static inline void fifo_dump(struct dma_fifo *fifo); + +static inline int fifo_empty(struct dma_fifo *f) +{ + return (f->head == f->tail); +} + +static inline int fifo_free(struct dma_fifo *f) +{ + int free; + + free = f->tail - f->head; + if (free <= 0) + free += f->size; + + return free; +} + +static inline int fifo_used(struct dma_fifo *f) +{ + int used; + + used = f->head - f->tail; + if (used < 0) + used += f->size; + + return used; +} + +static inline int fifo_full(struct dma_fifo *f) +{ + return (fifo_used(f) + 1) == f->size; +} + +/* manipulate */ +static inline void fifo_init(struct dma_fifo *fifo, int size) +{ + fifo->size = size; + fifo->head = fifo->tail = 0; /* empty */ +} + +static inline void fifo_inc_head(struct dma_fifo *fifo) +{ + BUG_ON(fifo_full(fifo)); + fifo->head = fifo_inc_ct(fifo->head, fifo->size); +} + +static inline void fifo_inc_tail(struct dma_fifo *fifo) +{ + BUG_ON(fifo_empty(fifo)); + fifo->tail = fifo_inc_ct(fifo->tail, fifo->size); +} + +/* internal funcs */ +static inline void fifo_dump(struct dma_fifo *fifo) +{ + printk(KERN_INFO "fifo: head %d, tail %d, size %d\n", fifo->head, + fifo->tail, + fifo->size); +} + +static inline int fifo_inc_ct(int ct, int size) +{ + return (++ct == size) ? 0 : ct; +} + +/*vmac*/ +struct rk29_vmac_platform_data { + int (*vmac_register_set)(void); + int (*rmii_io_init)(void); + int (*rmii_io_deinit)(void); + int (*rmii_power_control)(int enable); + int(*rmii_speed_switch)(int speed); +}; + +extern struct rk29_vmac_platform_data board_vmac_data; + +#endif /* _ARCVMAC_H */ diff --git a/drivers/net/ethernet/rk/vmac/rk29_vmac_phy.c b/drivers/net/ethernet/rk/vmac/rk29_vmac_phy.c new file mode 100755 index 000000000000..2adb9f9bc8ba --- /dev/null +++ b/drivers/net/ethernet/rk/vmac/rk29_vmac_phy.c @@ -0,0 +1,109 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../../../../arch/arm/mach-rockchip/iomap.h" +#include "../../../../../arch/arm/mach-rockchip/grf.h" + +#include "rk29_vmac.h" + +#define grf_readl(offset) readl_relaxed(RK_GRF_VIRT + offset) +#define grf_writel(v, offset) do { writel_relaxed(v, RK_GRF_VIRT + offset); dsb(); } while (0) + +static int rk30_vmac_register_set(void) +{ + //config rk30 vmac as rmii + writel_relaxed(0x3 << 16 | 0x2, RK_GRF_VIRT + RK3188_GRF_SOC_CON1); + return 0; +} + +static int rk30_rmii_io_init(void) +{ + int err; + long val; + printk("enter %s ",__func__); + + //rk3188 gpio3 and sdio drive strength , + val = grf_readl(RK3188_GRF_IO_CON3); + grf_writel(val|(0x0f<<16)|0x0f, RK3188_GRF_IO_CON3); + + //phy power gpio + /*err = gpio_request(PHY_PWR_EN_GPIO, "phy_power_en"); + if (err) { + printk("request phy power en pin faile ! \n"); + return -1; + } + //phy power down + gpio_direction_output(PHY_PWR_EN_GPIO, !PHY_PWR_EN_VALUE); + gpio_set_value(PHY_PWR_EN_GPIO, !PHY_PWR_EN_VALUE);*/ + + return 0; +} + +static int rk30_rmii_io_deinit(void) +{ + //phy power down + printk("enter %s ",__func__); + //gpio_direction_output(PHY_PWR_EN_GPIO, !PHY_PWR_EN_VALUE); + //gpio_set_value(PHY_PWR_EN_GPIO, !PHY_PWR_EN_VALUE); + //free + //gpio_free(PHY_PWR_EN_GPIO); + return 0; +} + +static int rk30_rmii_power_control(int enable) +{ + printk("enter %s ,enable = %d ",__func__,enable); + if (enable) { + //enable phy power + printk("power on phy\n"); + + //gpio_direction_output(PHY_PWR_EN_GPIO, PHY_PWR_EN_VALUE); + //gpio_set_value(PHY_PWR_EN_GPIO, PHY_PWR_EN_VALUE); + + //gpio reset + }else { + //gpio_direction_output(PHY_PWR_EN_GPIO, !PHY_PWR_EN_VALUE); + //gpio_set_value(PHY_PWR_EN_GPIO, !PHY_PWR_EN_VALUE); + } + return 0; +} + +#define BIT_EMAC_SPEED_100M (1 << 1) +#define BIT_EMAC_SPEED_10M (0 << 1) +static int rk29_vmac_speed_switch(int speed) +{ + //printk("%s--speed=%d\n", __FUNCTION__, speed); + if (10 == speed) { + writel_relaxed((2<<16)|BIT_EMAC_SPEED_10M, RK_GRF_VIRT + RK3188_GRF_SOC_CON1); + } else { + writel_relaxed((2<<16)|BIT_EMAC_SPEED_100M, RK_GRF_VIRT + RK3188_GRF_SOC_CON1); + } +} + +struct rk29_vmac_platform_data board_vmac_data = { + .vmac_register_set = rk30_vmac_register_set, + .rmii_io_init = rk30_rmii_io_init, + .rmii_io_deinit = rk30_rmii_io_deinit, + .rmii_power_control = rk30_rmii_power_control, + .rmii_speed_switch = rk29_vmac_speed_switch, +}; diff --git a/drivers/net/rk29_vmac.c b/drivers/net/rk29_vmac.c deleted file mode 100755 index 8a134a5a31c7..000000000000 --- a/drivers/net/rk29_vmac.c +++ /dev/null @@ -1,1794 +0,0 @@ -/* - * linux/arch/arc/drivers/arcvmac.c - * - * Copyright (C) 2003-2006 Codito Technologies, for linux-2.4 port - * Copyright (C) 2006-2007 Celunite Inc, for linux-2.6 port - * Copyright (C) 2007-2008 Sagem Communications, Fehmi HAFSI - * Copyright (C) 2009 Sagem Communications, Andreas Fenkart - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * external PHY support based on dnet.c - * ring management based on bcm63xx_enet.c - * - * Authors: amit.bhor@celunite.com, sameer.dhavale@celunite.com - */ - -//#define DEBUG - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "rk29_vmac.h" -#include "eth_mac/eth_mac.h" - -static struct wake_lock idlelock; /* add by lyx @ 20110302 */ - -/* Register access macros */ -#define vmac_writel(port, value, reg) \ - writel((value), (port)->regs + reg##_OFFSET) -#define vmac_readl(port, reg) readl((port)->regs + reg##_OFFSET) - -static unsigned char *read_mac_reg(struct net_device *dev, - unsigned char hwaddr[ETH_ALEN]) -{ - struct vmac_priv *ap = netdev_priv(dev); - unsigned mac_lo, mac_hi; - - WARN_ON(!hwaddr); - mac_lo = vmac_readl(ap, ADDRL); - mac_hi = vmac_readl(ap, ADDRH); - - hwaddr[0] = (mac_lo >> 0) & 0xff; - hwaddr[1] = (mac_lo >> 8) & 0xff; - hwaddr[2] = (mac_lo >> 16) & 0xff; - hwaddr[3] = (mac_lo >> 24) & 0xff; - hwaddr[4] = (mac_hi >> 0) & 0xff; - hwaddr[5] = (mac_hi >> 8) & 0xff; - return hwaddr; -} - -static void write_mac_reg(struct net_device *dev, unsigned char* hwaddr) -{ - struct vmac_priv *ap = netdev_priv(dev); - unsigned mac_lo, mac_hi; - - mac_lo = hwaddr[3] << 24 | hwaddr[2] << 16 | hwaddr[1] << 8 | hwaddr[0]; - mac_hi = hwaddr[5] << 8 | hwaddr[4]; - - vmac_writel(ap, mac_lo, ADDRL); - vmac_writel(ap, mac_hi, ADDRH); -} - -static void vmac_mdio_xmit(struct vmac_priv *ap, unsigned val) -{ - init_completion(&ap->mdio_complete); - vmac_writel(ap, val, MDIO_DATA); - if(!wait_for_completion_timeout(&ap->mdio_complete, msecs_to_jiffies(1000))) - printk("Time out for waiting mdio completion\n"); -} - -static int vmac_mdio_read(struct mii_bus *bus, int phy_id, int phy_reg) -{ - struct vmac_priv *vmac = bus->priv; - unsigned int val; - /* only 5 bits allowed for phy-addr and reg_offset */ - WARN_ON(phy_id & ~0x1f || phy_reg & ~0x1f); - - val = MDIO_BASE | MDIO_OP_READ; - val |= phy_id << 23 | phy_reg << 18; - vmac_mdio_xmit(vmac, val); - - val = vmac_readl(vmac, MDIO_DATA); - return val & MDIO_DATA_MASK; -} - -static int vmac_mdio_write(struct mii_bus *bus, int phy_id, int phy_reg, - u16 value) -{ - struct vmac_priv *vmac = bus->priv; - unsigned int val; - /* only 5 bits allowed for phy-addr and reg_offset */ - WARN_ON(phy_id & ~0x1f || phy_reg & ~0x1f); - - val = MDIO_BASE | MDIO_OP_WRITE; - val |= phy_id << 23 | phy_reg << 18; - val |= (value & MDIO_DATA_MASK); - vmac_mdio_xmit(vmac, val); - return 0; -} - -static void vmac_handle_link_change(struct net_device *dev) -{ - struct vmac_priv *ap = netdev_priv(dev); - struct phy_device *phydev = ap->phy_dev; - unsigned long flags; - int report_change = 0; - struct rk29_vmac_platform_data *pdata = ap->pdev->dev.platform_data; - - spin_lock_irqsave(&ap->lock, flags); - - if (phydev->duplex != ap->duplex) { - unsigned tmp; - - tmp = vmac_readl(ap, CONTROL); - - if (phydev->duplex) - tmp |= ENFL_MASK; - else - tmp &= ~ENFL_MASK; - - vmac_writel(ap, tmp, CONTROL); - - ap->duplex = phydev->duplex; - report_change = 1; - } - - if (phydev->speed != ap->speed) { - ap->speed = phydev->speed; - report_change = 1; - } - - if (pdata && pdata->rmii_speed_switch) - pdata->rmii_speed_switch(phydev->speed); - - if (phydev->link != ap->link) { - ap->link = phydev->link; - report_change = 1; - } - - spin_unlock_irqrestore(&ap->lock, flags); - - if (report_change) - phy_print_status(ap->phy_dev); -} - -static int __devinit vmac_mii_probe(struct net_device *dev) -{ - struct vmac_priv *ap = netdev_priv(dev); - struct phy_device *phydev = NULL; - //struct clk *sys_clk; - //unsigned long clock_rate; - int phy_addr, err; - - -#if defined (CONFIG_PHY_PORT_NUM) && (CONFIG_PHY_PORT_NUM != 0) - if (ap->mii_bus->phy_map[CONFIG_PHY_PORT_NUM]) - phydev = ap->mii_bus->phy_map[CONFIG_PHY_PORT_NUM]; -#else - /* find the first phy */ - for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) { - if (ap->mii_bus->phy_map[phy_addr]) { - phydev = ap->mii_bus->phy_map[phy_addr]; - break; - } - } -#endif - - if (!phydev) { - dev_err(&dev->dev, "no PHY found\n"); - return -ENODEV; - } - - /* add pin_irq, if avail */ - phydev = phy_connect(dev, dev_name(&phydev->dev), - &vmac_handle_link_change, 0, - //PHY_INTERFACE_MODE_MII); - PHY_INTERFACE_MODE_RMII);//???????? - if (IS_ERR(phydev)) { - err = PTR_ERR(phydev); - dev_err(&dev->dev, "could not attach to PHY %d\n", err); - goto err_out; - } - - phydev->supported &= PHY_BASIC_FEATURES; - phydev->supported |= SUPPORTED_Asym_Pause | SUPPORTED_Pause; - -#if 0 - sys_clk = clk_get(NULL, "mac_ref");//////// - if (IS_ERR(sys_clk)) { - err = PTR_ERR(sys_clk); - goto err_disconnect; - } - - clk_set_rate(sys_clk,50000000); - clock_rate = clk_get_rate(sys_clk); - clk_put(sys_clk); - - printk("%s::%d --mac clock = %d\n",__func__, __LINE__, clock_rate); - dev_dbg(&ap->pdev->dev, "clk_get: dev_name : %s %lu\n", - dev_name(&ap->pdev->dev), - clock_rate); - - if (clock_rate < 25000000) - phydev->supported &= ~(SUPPORTED_100baseT_Half | - SUPPORTED_100baseT_Full); -#endif - - phydev->advertising = phydev->supported; - - ap->link = 0; - ap->speed = 0; - ap->duplex = -1; - ap->phy_dev = phydev; - - return 0; -//err_disconnect: -// phy_disconnect(phydev); -err_out: - return err; -} - -static int __devinit vmac_mii_init(struct vmac_priv *ap) -{ - int err, i; - - ap->mii_bus = mdiobus_alloc(); - - if (ap->mii_bus == NULL) - return -ENOMEM; - - ap->mii_bus->name = "vmac_mii_bus"; - ap->mii_bus->read = &vmac_mdio_read; - ap->mii_bus->write = &vmac_mdio_write; - - snprintf(ap->mii_bus->id, MII_BUS_ID_SIZE, "%x", 0); - - ap->mii_bus->priv = ap; - - err = -ENOMEM; - ap->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); - if (!ap->mii_bus->irq) - goto err_out; - - for (i = 0; i < PHY_MAX_ADDR; i++) - ap->mii_bus->irq[i] = PHY_POLL; - -#if 0 - /* FIXME: what is it used for? */ - platform_set_drvdata(ap->dev, ap->mii_bus); -#endif - - err = mdiobus_register(ap->mii_bus); - if (err) - goto err_out_free_mdio_irq; - - err = vmac_mii_probe(ap->dev); - if (err) - goto err_out_unregister_bus; - - return 0; - -err_out_unregister_bus: - mdiobus_unregister(ap->mii_bus); -err_out_free_mdio_irq: - kfree(ap->mii_bus->irq); -err_out: - mdiobus_free(ap->mii_bus); - ap->mii_bus = NULL; - return err; -} - -static void vmac_mii_exit(struct net_device *dev) -{ - struct vmac_priv *ap = netdev_priv(dev); - - if (ap->phy_dev) - phy_disconnect(ap->phy_dev); - if (ap->mii_bus) { - mdiobus_unregister(ap->mii_bus); - kfree(ap->mii_bus->irq); - mdiobus_free(ap->mii_bus); - ap->mii_bus = NULL; - } -} - -static int vmacether_get_settings(struct net_device *dev, - struct ethtool_cmd *cmd) -{ - struct vmac_priv *ap = netdev_priv(dev); - struct phy_device *phydev = ap->phy_dev; - - if (!phydev) - return -ENODEV; - - return phy_ethtool_gset(phydev, cmd); -} - -static int vmacether_set_settings(struct net_device *dev, - struct ethtool_cmd *cmd) -{ - struct vmac_priv *ap = netdev_priv(dev); - struct phy_device *phydev = ap->phy_dev; - - if (!phydev) - return -ENODEV; - - return phy_ethtool_sset(phydev, cmd); -} - -static int vmac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct vmac_priv *ap = netdev_priv(dev); - struct phy_device *phydev = ap->phy_dev; - - if (!netif_running(dev)) - return -EINVAL; - - if (!phydev) - return -ENODEV; - - return phy_mii_ioctl(phydev, rq, cmd); -} - -static void vmacether_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *info) -{ - struct vmac_priv *ap = netdev_priv(dev); - - strlcpy(info->driver, VMAC_NAME, sizeof(info->driver)); - strlcpy(info->version, VMAC_VERSION, sizeof(info->version)); - snprintf(info->bus_info, sizeof(info->bus_info), - "platform 0x%x", ap->mem_base); -} - -static int update_error_counters(struct net_device *dev, int status) -{ - struct vmac_priv *ap = netdev_priv(dev); - dev_dbg(&ap->pdev->dev, "rx error counter overrun. status = 0x%x\n", - status); - - /* programming error */ - WARN_ON(status & TXCH_MASK); - WARN_ON(!(status & (MSER_MASK | RXCR_MASK | RXFR_MASK | RXFL_MASK))); - - if (status & MSER_MASK) - ap->stats.rx_over_errors += 256; /* ran out of BD */ - if (status & RXCR_MASK) - ap->stats.rx_crc_errors += 256; - if (status & RXFR_MASK) - ap->stats.rx_frame_errors += 256; - if (status & RXFL_MASK) - ap->stats.rx_fifo_errors += 256; - - return 0; -} - -static void update_tx_errors(struct net_device *dev, int status) -{ - struct vmac_priv *ap = netdev_priv(dev); - - if (status & UFLO) - ap->stats.tx_fifo_errors++; - - if (ap->duplex) - return; - - /* half duplex flags */ - if (status & LTCL) - ap->stats.tx_window_errors++; - if (status & RETRY_CT) - ap->stats.collisions += (status & RETRY_CT) >> 24; - if (status & DROP) /* too many retries */ - ap->stats.tx_aborted_errors++; - if (status & DEFER) - dev_vdbg(&ap->pdev->dev, "\"defer to traffic\"\n"); - if (status & CARLOSS) - ap->stats.tx_carrier_errors++; -} - -static int vmac_rx_reclaim_force(struct net_device *dev) -{ - struct vmac_priv *ap = netdev_priv(dev); - int ct; - - ct = 0; - - dev_dbg(&ap->pdev->dev, "%s need to release %d rx sk_buff\n", - __func__, fifo_used(&ap->rx_ring)); - - while (!fifo_empty(&ap->rx_ring) && ct++ < ap->rx_ring.size) { - struct vmac_buffer_desc *desc; - struct sk_buff *skb; - int desc_idx; - - desc_idx = ap->rx_ring.tail; - desc = &ap->rxbd[desc_idx]; - fifo_inc_tail(&ap->rx_ring); - - if (!ap->rx_skbuff[desc_idx]) { - dev_err(&ap->pdev->dev, "non-populated rx_skbuff found %d\n", - desc_idx); - continue; - } - - skb = ap->rx_skbuff[desc_idx]; - ap->rx_skbuff[desc_idx] = NULL; - - dma_unmap_single(&ap->pdev->dev, desc->data, skb->len, - DMA_TO_DEVICE); - - dev_kfree_skb(skb); - } - - if (!fifo_empty(&ap->rx_ring)) { - dev_err(&ap->pdev->dev, "failed to reclaim %d rx sk_buff\n", - fifo_used(&ap->rx_ring)); - } - - return 0; -} - -static int vmac_rx_refill(struct net_device *dev) -{ - struct vmac_priv *ap = netdev_priv(dev); - - WARN_ON(fifo_full(&ap->rx_ring)); - - while (!fifo_full(&ap->rx_ring)) { - struct vmac_buffer_desc *desc; - struct sk_buff *skb; - dma_addr_t p; - int desc_idx; - - desc_idx = ap->rx_ring.head; - desc = &ap->rxbd[desc_idx]; - - /* make sure we read the actual descriptor status */ - rmb(); - - if (ap->rx_skbuff[desc_idx]) { - /* dropped packet / buffer chaining */ - fifo_inc_head(&ap->rx_ring); - - /* return to DMA */ - wmb(); - desc->info = OWN_MASK | ap->rx_skb_size; - continue; - } - - skb = netdev_alloc_skb(dev, ap->rx_skb_size + 2); - if (!skb) { - dev_info(&ap->pdev->dev, "failed to allocate rx_skb, skb's left %d\n", - fifo_used(&ap->rx_ring)); - break; - } - - /* IP header Alignment (14 byte Ethernet header) */ - skb_reserve(skb, 2); - WARN_ON(skb->len != 0); /* nothing received yet */ - - ap->rx_skbuff[desc_idx] = skb; - - p = dma_map_single(&ap->pdev->dev, skb->data, ap->rx_skb_size, - DMA_FROM_DEVICE); - - desc->data = p; - - wmb(); - desc->info = OWN_MASK | ap->rx_skb_size; - - fifo_inc_head(&ap->rx_ring); - } - - /* If rx ring is still empty, set a timer to try allocating - * again at a later time. */ - if (fifo_empty(&ap->rx_ring) && netif_running(dev)) { - dev_warn(&ap->pdev->dev, "unable to refill rx ring\n"); - ap->rx_timeout.expires = jiffies + HZ; - add_timer(&ap->rx_timeout); - } - - return 0; -} - -/* - * timer callback to defer refill rx queue in case we're OOM - */ -static void vmac_refill_rx_timer(unsigned long data) -{ - struct net_device *dev; - struct vmac_priv *ap; - - dev = (struct net_device *)data; - ap = netdev_priv(dev); - - spin_lock(&ap->rx_lock); - vmac_rx_refill(dev); - spin_unlock(&ap->rx_lock); -} - -/* merge buffer chaining */ -struct sk_buff *vmac_merge_rx_buffers(struct net_device *dev, - struct vmac_buffer_desc *after, - int pkt_len) /* data */ -{ - struct vmac_priv *ap = netdev_priv(dev); - struct sk_buff *merge_skb, *cur_skb; - struct dma_fifo *rx_ring; - struct vmac_buffer_desc *desc; - - rx_ring = &ap->rx_ring; - desc = &ap->rxbd[rx_ring->tail]; - - WARN_ON(desc == after); - - /* strip FCS */ - pkt_len -= 4; - - /* IP header Alignment (14 byte Ethernet header) */ - merge_skb = netdev_alloc_skb(dev, pkt_len + 2); - if (!merge_skb) { - dev_err(&ap->pdev->dev, "failed to allocate merged rx_skb, rx skb's left %d\n", - fifo_used(rx_ring)); - - return NULL; - } - - skb_reserve(merge_skb, 2); - - while (desc != after && pkt_len) { - struct vmac_buffer_desc *desc; - int buf_len, valid; - - /* desc needs wrapping */ - desc = &ap->rxbd[rx_ring->tail]; - cur_skb = ap->rx_skbuff[rx_ring->tail]; - WARN_ON(!cur_skb); - - dma_unmap_single(&ap->pdev->dev, desc->data, ap->rx_skb_size, - DMA_FROM_DEVICE); - - /* do not copy FCS */ - buf_len = desc->info & LEN_MASK; - valid = min(pkt_len, buf_len); - pkt_len -= valid; - - memcpy(skb_put(merge_skb, valid), cur_skb->data, valid); - - fifo_inc_tail(rx_ring); - } - - /* merging_pressure++ */ - - if (unlikely(pkt_len != 0)) - dev_err(&ap->pdev->dev, "buffer chaining bytes missing %d\n", - pkt_len); - - WARN_ON(desc != after); - - return merge_skb; -} - -int vmac_rx_receive(struct net_device *dev, int budget) -{ - struct vmac_priv *ap = netdev_priv(dev); - struct vmac_buffer_desc *first; - int processed, pkt_len, pkt_err; - struct dma_fifo lookahead; - - processed = 0; - - first = NULL; - pkt_err = pkt_len = 0; - - /* look ahead, till packet complete */ - lookahead = ap->rx_ring; - - do { - struct vmac_buffer_desc *desc; /* cur_ */ - int desc_idx; /* cur_ */ - struct sk_buff *skb; /* pkt_ */ - - desc_idx = lookahead.tail; - desc = &ap->rxbd[desc_idx]; - - /* make sure we read the actual descriptor status */ - rmb(); - - /* break if dma ownership belongs to hw */ - if (desc->info & OWN_MASK) { - ap->mac_rxring_head = vmac_readl(ap, MAC_RXRING_HEAD); - break; - } - - if (desc->info & FRST_MASK) { - pkt_len = 0; - pkt_err = 0; - - /* don't free current */ - ap->rx_ring.tail = lookahead.tail; - first = desc; - } - - fifo_inc_tail(&lookahead); - - /* check bd */ - - pkt_len += desc->info & LEN_MASK; - pkt_err |= (desc->info & BUFF); - - if (!(desc->info & LAST_MASK)) - continue; - - /* received complete packet */ - - if (unlikely(pkt_err || !first)) { - /* recycle buffers */ - ap->rx_ring.tail = lookahead.tail; - continue; - } - - WARN_ON(!(first->info & FRST_MASK) || - !(desc->info & LAST_MASK)); - WARN_ON(pkt_err); - - /* -- valid packet -- */ - - if (first != desc) { - skb = vmac_merge_rx_buffers(dev, desc, pkt_len); - - if (!skb) { - /* kill packet */ - ap->rx_ring.tail = lookahead.tail; - ap->rx_merge_error++; - continue; - } - } else { - dma_unmap_single(&ap->pdev->dev, desc->data, - ap->rx_skb_size, DMA_FROM_DEVICE); - - skb = ap->rx_skbuff[desc_idx]; - ap->rx_skbuff[desc_idx] = NULL; - /* desc->data != skb->data => desc->data DMA mapped */ - - /* strip FCS */ - skb_put(skb, pkt_len - 4); - } - - /* free buffers */ - ap->rx_ring.tail = lookahead.tail; - - WARN_ON(skb->len != pkt_len - 4); - processed++; - skb->dev = dev; - skb->protocol = eth_type_trans(skb, dev); - ap->stats.rx_packets++; - ap->stats.rx_bytes += skb->len; - dev->last_rx = jiffies; - netif_rx(skb); - - } while (!fifo_empty(&lookahead) && (processed < budget)); - - dev_vdbg(&ap->pdev->dev, "processed pkt %d, remaining rx buff %d\n", - processed, - fifo_used(&ap->rx_ring)); - - if (processed || fifo_empty(&ap->rx_ring)) - vmac_rx_refill(dev); - - return processed; -} - -static void vmac_toggle_irqmask(struct net_device *dev, int enable, int mask) -{ - struct vmac_priv *ap = netdev_priv(dev); - unsigned long tmp; - - tmp = vmac_readl(ap, ENABLE); - if (enable) - tmp |= mask; - else - tmp &= ~mask; - vmac_writel(ap, tmp, ENABLE); -} - -static void vmac_toggle_txint(struct net_device *dev, int enable) -{ - struct vmac_priv *ap = netdev_priv(dev); - unsigned long flags; - - spin_lock_irqsave(&ap->lock, flags); - vmac_toggle_irqmask(dev, enable, TXINT_MASK); - spin_unlock_irqrestore(&ap->lock, flags); -} - -static void vmac_toggle_rxint(struct net_device *dev, int enable) -{ - vmac_toggle_irqmask(dev, enable, RXINT_MASK); -} - -static int vmac_poll(struct napi_struct *napi, int budget) -{ - struct vmac_priv *ap; - struct net_device *dev; - int rx_work_done; - unsigned long flags; - - ap = container_of(napi, struct vmac_priv, napi); - dev = ap->dev; - - /* ack interrupt */ - vmac_writel(ap, RXINT_MASK, STAT); - - spin_lock(&ap->rx_lock); - rx_work_done = vmac_rx_receive(dev, budget); - spin_unlock(&ap->rx_lock); - -#ifdef VERBOSE_DEBUG - if (printk_ratelimit()) { - dev_vdbg(&ap->pdev->dev, "poll budget %d receive rx_work_done %d\n", - budget, - rx_work_done); - } -#endif - - if (rx_work_done >= budget) { - /* rx queue is not yet empty/clean */ - return rx_work_done; - } - - /* no more packet in rx/tx queue, remove device from poll - * queue */ - spin_lock_irqsave(&ap->lock, flags); - napi_complete(napi); - vmac_toggle_rxint(dev, 1); - spin_unlock_irqrestore(&ap->lock, flags); - - return rx_work_done; -} - -static int vmac_tx_reclaim(struct net_device *dev, int force); - -static irqreturn_t vmac_intr(int irq, void *dev_instance) -{ - struct net_device *dev = dev_instance; - struct vmac_priv *ap = netdev_priv(dev); - unsigned int status; - - spin_lock(&ap->lock); - - status = vmac_readl(ap, STAT); - vmac_writel(ap, status, STAT); - -#ifdef DEBUG - if (unlikely(ap->shutdown)) - dev_err(&ap->pdev->dev, "ISR during close\n"); - - if (unlikely(!status & (RXINT_MASK|MDIO_MASK|ERR_MASK))) - dev_err(&ap->pdev->dev, "No source of IRQ found\n"); -#endif - - if ((status & RXINT_MASK) && - (ap->mac_rxring_head != - vmac_readl(ap, MAC_RXRING_HEAD))) { - vmac_toggle_rxint(dev, 0); - napi_schedule(&ap->napi); - } - - if (unlikely(netif_queue_stopped(dev) && (status & TXINT_MASK))) - vmac_tx_reclaim(dev, 0); - - if (status & MDIO_MASK) - complete(&ap->mdio_complete); - - if (unlikely(status & ERR_MASK)) - update_error_counters(dev, status); - - spin_unlock(&ap->lock); - - return IRQ_HANDLED; -} - -static int vmac_tx_reclaim(struct net_device *dev, int force) -{ - struct vmac_priv *ap = netdev_priv(dev); - int released = 0; - - /* buffer chaining not used, see vmac_start_xmit */ - - while (!fifo_empty(&ap->tx_ring)) { - struct vmac_buffer_desc *desc; - struct sk_buff *skb; - int desc_idx; - - desc_idx = ap->tx_ring.tail; - desc = &ap->txbd[desc_idx]; - - /* ensure other field of the descriptor were not read - * before we checked ownership */ - rmb(); - - if ((desc->info & OWN_MASK) && !force) - break; - - if (desc->info & ERR_MSK_TX) { - update_tx_errors(dev, desc->info); - /* recycle packet, let upper level deal with it */ - } - - skb = ap->tx_skbuff[desc_idx]; - ap->tx_skbuff[desc_idx] = NULL; - WARN_ON(!skb); - - dma_unmap_single(&ap->pdev->dev, desc->data, skb->len, - DMA_TO_DEVICE); - - dev_kfree_skb_any(skb); - - released++; - fifo_inc_tail(&ap->tx_ring); - } - - if (netif_queue_stopped(dev) && released) { - netif_wake_queue(dev); - vmac_toggle_txint(dev, 0); - } - - if (unlikely(force && !fifo_empty(&ap->tx_ring))) { - dev_err(&ap->pdev->dev, "failed to reclaim %d tx sk_buff\n", - fifo_used(&ap->tx_ring)); - } - - return released; -} - -int vmac_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct vmac_priv *ap = netdev_priv(dev); - struct vmac_buffer_desc *desc; - unsigned int tmp; - - /* running under xmit lock */ - - /* no scatter/gatter see features below */ - WARN_ON(skb_shinfo(skb)->nr_frags != 0); - WARN_ON(skb->len > MAX_TX_BUFFER_LEN); - - if (unlikely(fifo_full(&ap->tx_ring))) { - netif_stop_queue(dev); - vmac_toggle_txint(dev, 1); - dev_err(&ap->pdev->dev, "xmit called with no tx desc available\n"); - return NETDEV_TX_BUSY; - } - - if (unlikely(skb->len < ETH_ZLEN)) { - struct sk_buff *short_skb; - short_skb = netdev_alloc_skb(dev, ETH_ZLEN); - if (!short_skb) - return NETDEV_TX_LOCKED; - - memset(short_skb->data, 0, ETH_ZLEN); - memcpy(skb_put(short_skb, ETH_ZLEN), skb->data, skb->len); - dev_kfree_skb(skb); - skb = short_skb; - } - - /* fill descriptor */ - ap->tx_skbuff[ap->tx_ring.head] = skb; - - desc = &ap->txbd[ap->tx_ring.head]; - desc->data = dma_map_single(&ap->pdev->dev, skb->data, skb->len, - DMA_TO_DEVICE); - - /* dma might already be polling */ - wmb(); - desc->info = OWN_MASK | FRST_MASK | LAST_MASK | skb->len; - wmb(); - - /* kick tx dma */ - tmp = vmac_readl(ap, STAT); - vmac_writel(ap, tmp | TXPL_MASK, STAT); - - ap->stats.tx_packets++; - ap->stats.tx_bytes += skb->len; - dev->trans_start = jiffies; - fifo_inc_head(&ap->tx_ring); - - /* vmac_tx_reclaim independent of vmac_tx_timeout */ - if (fifo_used(&ap->tx_ring) > 8) - vmac_tx_reclaim(dev, 0); - - /* stop queue if no more desc available */ - if (fifo_full(&ap->tx_ring)) { - netif_stop_queue(dev); - vmac_toggle_txint(dev, 1); - } - - return NETDEV_TX_OK; -} - -static int alloc_buffers(struct net_device *dev) -{ - struct vmac_priv *ap = netdev_priv(dev); - int err = -ENOMEM; - int size; - - fifo_init(&ap->rx_ring, RX_BDT_LEN); - fifo_init(&ap->tx_ring, TX_BDT_LEN); - - /* initialize skb list */ - memset(ap->rx_skbuff, 0, sizeof(ap->rx_skbuff)); - memset(ap->tx_skbuff, 0, sizeof(ap->tx_skbuff)); - - /* allocate DMA received descriptors */ - size = sizeof(*ap->rxbd) * ap->rx_ring.size; - ap->rxbd = dma_alloc_coherent(&ap->pdev->dev, size, - &ap->rxbd_dma, - GFP_KERNEL); - if (ap->rxbd == NULL) - goto err_out; - - /* allocate DMA transmit descriptors */ - size = sizeof(*ap->txbd) * ap->tx_ring.size; - ap->txbd = dma_alloc_coherent(&ap->pdev->dev, size, - &ap->txbd_dma, - GFP_KERNEL); - if (ap->txbd == NULL) - goto err_free_rxbd; - - /* ensure 8-byte aligned */ - WARN_ON(((int)ap->txbd & 0x7) || ((int)ap->rxbd & 0x7)); - - memset(ap->txbd, 0, sizeof(*ap->txbd) * ap->tx_ring.size); - memset(ap->rxbd, 0, sizeof(*ap->rxbd) * ap->rx_ring.size); - - /* allocate rx skb */ - err = vmac_rx_refill(dev); - if (err) - goto err_free_txbd; - - return 0; - -err_free_txbd: - dma_free_coherent(&ap->pdev->dev, sizeof(*ap->txbd) * ap->tx_ring.size, - ap->txbd, ap->txbd_dma); -err_free_rxbd: - dma_free_coherent(&ap->pdev->dev, sizeof(*ap->rxbd) * ap->rx_ring.size, - ap->rxbd, ap->rxbd_dma); -err_out: - return err; -} - -static int free_buffers(struct net_device *dev) -{ - struct vmac_priv *ap = netdev_priv(dev); - - /* free skbuff */ - vmac_tx_reclaim(dev, 1); - vmac_rx_reclaim_force(dev); - - /* free DMA ring */ - dma_free_coherent(&ap->pdev->dev, sizeof(ap->txbd) * ap->tx_ring.size, - ap->txbd, ap->txbd_dma); - dma_free_coherent(&ap->pdev->dev, sizeof(ap->rxbd) * ap->rx_ring.size, - ap->rxbd, ap->rxbd_dma); - - return 0; -} - -static int vmac_hw_init(struct net_device *dev) -{ - struct vmac_priv *priv = netdev_priv(dev); - - /* clear IRQ mask */ - vmac_writel(priv, 0, ENABLE); - - /* clear pending IRQ */ - vmac_writel(priv, 0xffffffff, STAT); - - /* Initialize logical address filter */ - vmac_writel(priv, 0x0, LAFL); - vmac_writel(priv, 0x0, LAFH); - - return 0; -} - -#ifdef DEBUG -static int vmac_register_print(struct net_device *dev) -{ - struct vmac_priv *ap = netdev_priv(dev); - - printk("func::%s vmac register %s value = 0x%x\n", __func__, "ID", vmac_readl(ap, ID)); - printk("func::%s vmac register %s value = 0x%x\n", __func__, "STAT", vmac_readl(ap, STAT)); - printk("func::%s vmac register %s value = 0x%x\n", __func__, "ENABLE", vmac_readl(ap, ENABLE)); - printk("func::%s vmac register %s value = 0x%x\n", __func__, "CONTROL", vmac_readl(ap, CONTROL)); - printk("func::%s vmac register %s value = 0x%x\n", __func__, "ADDRL", vmac_readl(ap, ADDRL)); - printk("func::%s vmac register %s value = 0x%x\n", __func__, "ADDRH", vmac_readl(ap, ADDRH)); - - return 0; -} -#endif - -int vmac_open(struct net_device *dev) -{ - struct vmac_priv *ap = netdev_priv(dev); - struct phy_device *phydev; - unsigned int temp; - int err = 0; - struct clk *mac_clk = NULL; - struct clk *mac_parent = NULL; - struct clk *arm_clk = NULL; - struct rk29_vmac_platform_data *pdata = ap->pdev->dev.platform_data; - unsigned char current_mac[6]; - int ret = 0; - - printk("enter func %s...\n", __func__); - - if (ap == NULL) - return -ENODEV; - - wake_lock_timeout(&ap->resume_lock, 5*HZ); - - ap->shutdown = 0; - - //set rmii ref clock 50MHz - mac_clk = clk_get(NULL, "mac_ref"); - if (IS_ERR(mac_clk)) - mac_clk = NULL; - arm_clk = clk_get(NULL, "arm_pll"); - if (IS_ERR(arm_clk)) - arm_clk = NULL; - if (mac_clk) { - mac_parent = clk_get_parent(mac_clk); - if (IS_ERR(mac_parent)) - mac_parent = NULL; - } - if (arm_clk && mac_parent && (arm_clk == mac_parent)) - wake_lock(&idlelock); - - if(pdata && pdata->rmii_extclk_sel && pdata->rmii_extclk_sel()) - { - struct clk * mac_clkin = NULL; - mac_clkin = clk_get(NULL, "rmii_clkin"); - if (IS_ERR(mac_clkin)) { - pr_err("mac_clkin get fail\n"); - } - clk_set_parent(mac_clk, mac_clkin); - } - - clk_set_rate(mac_clk, 50000000); - clk_enable(mac_clk); - clk_enable(clk_get(NULL,"mii_rx")); - clk_enable(clk_get(NULL,"mii_tx")); - clk_enable(clk_get(NULL,"hclk_mac")); - clk_enable(clk_get(NULL,"mac_ref")); - - //phy power on - if (pdata && pdata->rmii_power_control) - pdata->rmii_power_control(1); - - msleep(1000); - - vmac_hw_init(dev); - -//$_rbox_$_modify_$_chenxiao - if (is_valid_ether_addr(dev->dev_addr)){ - strlcpy(current_mac,dev->dev_addr,6); - } - -#ifdef CONFIG_ETH_MAC_FROM_EEPROM - ret = eeprom_read_data(0,dev->dev_addr,6); - if (ret != 6){ - printk("read mac from Eeprom fail.\n"); - }else { - if (is_valid_ether_addr(dev->dev_addr)){ - printk("eth_mac_from_eeprom***********:%X:%X:%X:%X:%X:%X\n",dev->dev_addr[0], - dev->dev_addr[1],dev->dev_addr[2],dev->dev_addr[3], - dev->dev_addr[4],dev->dev_addr[5] ); - } - } -#endif - -#ifdef CONFIG_ETH_MAC_FROM_IDB - err = eth_mac_idb(dev->dev_addr); - if (err) { - printk("read mac from IDB fail.\n"); - } else { - if (is_valid_ether_addr(dev->dev_addr)) { - printk("eth_mac_from_idb***********:%X:%X:%X:%X:%X:%X\n",dev->dev_addr[0], - dev->dev_addr[1],dev->dev_addr[2],dev->dev_addr[3], - dev->dev_addr[4],dev->dev_addr[5] ); - } - } -#endif - -#ifdef CONFIG_ETH_MAC_FROM_WIFI_MAC - err = eth_mac_wifi(dev->dev_addr); - if (err) { - printk("read mac from Wifi fail.\n"); - } else { - if (is_valid_ether_addr(dev->dev_addr)) { - printk("eth_mac_from_wifi_mac***********:%X:%X:%X:%X:%X:%X\n",dev->dev_addr[0], - dev->dev_addr[1],dev->dev_addr[2],dev->dev_addr[3], - dev->dev_addr[4],dev->dev_addr[5] ); - } - } -#endif - -#ifdef CONFIG_ETH_MAC_FROM_SECURE_CHIP - -#endif - - - if (!is_valid_ether_addr(dev->dev_addr)) { - strlcpy(dev->dev_addr,current_mac,6); - printk("eth_mac_from_RANDOM***********:%X:%X:%X:%X:%X:%X\n",dev->dev_addr[0], - dev->dev_addr[1],dev->dev_addr[2],dev->dev_addr[3], - dev->dev_addr[4],dev->dev_addr[5] ); - } -//add end - - /* mac address changed? */ - write_mac_reg(dev, dev->dev_addr); - - err = alloc_buffers(dev); - if (err) - goto err_out; - - err = request_irq(dev->irq, &vmac_intr, 0, dev->name, dev); - if (err) { - dev_err(&ap->pdev->dev, "Unable to request IRQ %d (error %d)\n", - dev->irq, err); - goto err_free_buffers; - } - - /* install DMA ring pointers */ - vmac_writel(ap, ap->rxbd_dma, RXRINGPTR); - vmac_writel(ap, ap->txbd_dma, TXRINGPTR); - - /* set poll rate to 1 ms */ - vmac_writel(ap, POLLRATE_TIME, POLLRATE); - - /* make sure we enable napi before rx interrupt */ - napi_enable(&ap->napi); - - /* IRQ mask */ - temp = RXINT_MASK | ERR_MASK | TXCH_MASK | MDIO_MASK; - vmac_writel(ap, temp, ENABLE); - - /* Set control */ - temp = (RX_BDT_LEN << 24) | (TX_BDT_LEN << 16) | TXRN_MASK | RXRN_MASK; - vmac_writel(ap, temp, CONTROL); - - /* enable, after all other bits are set */ - vmac_writel(ap, temp | EN_MASK, CONTROL); - - netif_start_queue(dev); - netif_carrier_off(dev); - -#ifdef DEBUG - vmac_register_print(dev); -#endif - - /* register the PHY board fixup, if needed */ - err = vmac_mii_init(ap); - if (err) - goto err_free_irq; - - /* schedule a link state check */ - phy_start(ap->phy_dev); - - phydev = ap->phy_dev; - dev_info(&ap->pdev->dev, "PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n", - phydev->drv->name, dev_name(&phydev->dev), phydev->irq); - - ap->suspending = 0; - ap->open_flag = 1; - - return 0; - -err_free_irq: - free_irq(dev->irq, dev); -err_free_buffers: - free_buffers(dev); -err_out: - if (arm_clk && mac_parent && (arm_clk == mac_parent)) - wake_unlock(&idlelock); - - return err; -} - -int vmac_close(struct net_device *dev) -{ - struct vmac_priv *ap = netdev_priv(dev); - unsigned int temp; - struct clk *mac_clk = NULL; - struct clk *arm_clk = NULL; - struct clk *mac_parent = NULL; - struct rk29_vmac_platform_data *pdata = ap->pdev->dev.platform_data; - - printk("enter func %s...\n", __func__); - - if (ap->suspending == 1) - return 0; - - ap->open_flag = 0; - - netif_stop_queue(dev); - napi_disable(&ap->napi); - - /* stop running transfers */ - temp = vmac_readl(ap, CONTROL); - temp &= ~(TXRN_MASK | RXRN_MASK); - vmac_writel(ap, temp, CONTROL); - - del_timer_sync(&ap->rx_timeout); - - /* disable phy */ - phy_stop(ap->phy_dev); - vmac_mii_exit(dev); - netif_carrier_off(dev); - - /* disable interrupts */ - vmac_writel(ap, 0, ENABLE); - free_irq(dev->irq, dev); - - /* turn off vmac */ - vmac_writel(ap, 0, CONTROL); - /* vmac_reset_hw(vmac) */ - - ap->shutdown = 1; - wmb(); - - free_buffers(dev); - - //phy power off - if (pdata && pdata->rmii_power_control) - pdata->rmii_power_control(0); - - //clock close - mac_clk = clk_get(NULL, "mac_ref_div"); - if (IS_ERR(mac_clk)) - mac_clk = NULL; - if (mac_clk) { - mac_parent = clk_get_parent(mac_clk); - if (IS_ERR(mac_parent)) - mac_parent = NULL; - } - arm_clk = clk_get(NULL, "arm_pll"); - if (IS_ERR(arm_clk)) - arm_clk = NULL; - - if (arm_clk && mac_parent && (arm_clk == mac_parent)) - wake_unlock(&idlelock); - - clk_disable(mac_clk); - clk_disable(clk_get(NULL,"mii_rx")); - clk_disable(clk_get(NULL,"mii_tx")); - clk_disable(clk_get(NULL,"hclk_mac")); - clk_disable(clk_get(NULL,"mac_ref")); - - return 0; -} - -int vmac_shutdown(struct net_device *dev) -{ - struct vmac_priv *ap = netdev_priv(dev); - unsigned int temp; - - printk("enter func %s...\n", __func__); - - netif_stop_queue(dev); - napi_disable(&ap->napi); - - /* stop running transfers */ - temp = vmac_readl(ap, CONTROL); - temp &= ~(TXRN_MASK | RXRN_MASK); - vmac_writel(ap, temp, CONTROL); - - del_timer_sync(&ap->rx_timeout); - - /* disable phy */ - phy_stop(ap->phy_dev); - vmac_mii_exit(dev); - netif_carrier_off(dev); - - /* disable interrupts */ - vmac_writel(ap, 0, ENABLE); - free_irq(dev->irq, dev); - - /* turn off vmac */ - vmac_writel(ap, 0, CONTROL); - /* vmac_reset_hw(vmac) */ - - ap->shutdown = 1; - wmb(); - - free_buffers(dev); - - return 0; -} - -void vmac_update_stats(struct vmac_priv *ap) -{ - struct net_device_stats *_stats = &ap->stats; - unsigned long miss, rxerr; - unsigned long rxfram, rxcrc, rxoflow; - - /* compare with /proc/net/dev, - * see net/core/dev.c:dev_seq_printf_stats */ - - /* rx stats */ - rxerr = vmac_readl(ap, RXERR); - miss = vmac_readl(ap, MISS); - - rxcrc = (rxerr & RXERR_CRC); - rxfram = (rxerr & RXERR_FRM) >> 8; - rxoflow = (rxerr & RXERR_OFLO) >> 16; - - _stats->rx_length_errors = 0; - _stats->rx_over_errors += miss; - _stats->rx_crc_errors += rxcrc; - _stats->rx_frame_errors += rxfram; - _stats->rx_fifo_errors += rxoflow; - _stats->rx_missed_errors = 0; - - /* TODO check rx_dropped/rx_errors/tx_dropped/tx_errors have not - * been updated elsewhere */ - _stats->rx_dropped = _stats->rx_over_errors + - _stats->rx_fifo_errors + - ap->rx_merge_error; - - _stats->rx_errors = _stats->rx_length_errors + _stats->rx_crc_errors + - _stats->rx_frame_errors + - _stats->rx_missed_errors + - _stats->rx_dropped; - - /* tx stats */ - _stats->tx_dropped = 0; /* otherwise queue stopped */ - - _stats->tx_errors = _stats->tx_aborted_errors + - _stats->tx_carrier_errors + - _stats->tx_fifo_errors + - _stats->tx_heartbeat_errors + - _stats->tx_window_errors + - _stats->tx_dropped + - ap->tx_timeout_error; -} - -struct net_device_stats *vmac_stats(struct net_device *dev) -{ - struct vmac_priv *ap = netdev_priv(dev); - unsigned long flags; - - spin_lock_irqsave(&ap->lock, flags); - vmac_update_stats(ap); - spin_unlock_irqrestore(&ap->lock, flags); - - return &ap->stats; -} - -void vmac_tx_timeout(struct net_device *dev) -{ - struct vmac_priv *ap = netdev_priv(dev); - unsigned int status; - unsigned long flags; - - spin_lock_irqsave(&ap->lock, flags); - - /* queue did not progress for timeo jiffies */ - WARN_ON(!netif_queue_stopped(dev)); - WARN_ON(!fifo_full(&ap->tx_ring)); - - /* TX IRQ lost? */ - status = vmac_readl(ap, STAT); - if (status & TXINT_MASK) { - dev_err(&ap->pdev->dev, "lost tx interrupt, IRQ mask %x\n", - vmac_readl(ap, ENABLE)); - vmac_writel(ap, TXINT_MASK, STAT); - } - - /* TODO RX/MDIO/ERR as well? */ - - vmac_tx_reclaim(dev, 0); - if (fifo_full(&ap->tx_ring)) - dev_err(&ap->pdev->dev, "DMA state machine not active\n"); - - /* We can accept TX packets again */ - ap->tx_timeout_error++; - dev->trans_start = jiffies; - netif_wake_queue(dev); - - spin_unlock_irqrestore(&ap->lock, flags); -} - -static void create_multicast_filter(struct net_device *dev, - unsigned long *bitmask) -{ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)) - struct netdev_hw_addr *ha; - unsigned long crc; - char *addrs; - struct netdev_hw_addr_list *list = &dev->dev_addrs; - - //printk("-----------------func %s-------------------\n", __func__); - - WARN_ON(dev->mc_count == 0); - WARN_ON(dev->flags & IFF_ALLMULTI); - - bitmask[0] = bitmask[1] = 0; - - list_for_each_entry(ha, &list->list, list) { - addrs = ha->addr; - - /* skip non-multicast addresses */ - if (!(*addrs & 1)) - continue; - - crc = ether_crc_le(ETH_ALEN, addrs); - set_bit(crc >> 26, bitmask); - - } -#else - struct netdev_hw_addr *ha; - unsigned long crc; - char *addrs; - - WARN_ON(netdev_mc_count(dev) == 0); - WARN_ON(dev->flags & IFF_ALLMULTI); - - bitmask[0] = bitmask[1] = 0; - - netdev_for_each_mc_addr(ha, dev) { - addrs = ha->addr; - - /* skip non-multicast addresses */ - if (!(*addrs & 1)) - continue; - - crc = ether_crc_le(ETH_ALEN, addrs); - set_bit(crc >> 26, bitmask); - } -#endif -} -static void vmac_set_multicast_list(struct net_device *dev) -{ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)) - struct vmac_priv *ap = netdev_priv(dev); - unsigned long flags, bitmask[2]; - int promisc, reg; - - //printk("-----------------func %s-------------------\n", __func__); - - spin_lock_irqsave(&ap->lock, flags); - - promisc = !!(dev->flags & IFF_PROMISC); - reg = vmac_readl(ap, CONTROL); - if (promisc != !!(reg & PROM_MASK)) { - reg ^= PROM_MASK; - vmac_writel(ap, reg, CONTROL); - } - - if (dev->flags & IFF_ALLMULTI) - memset(bitmask, 1, sizeof(bitmask)); - else if (dev->mc_count == 0) - memset(bitmask, 0, sizeof(bitmask)); - else - create_multicast_filter(dev, bitmask); - - vmac_writel(ap, bitmask[0], LAFL); - vmac_writel(ap, bitmask[1], LAFH); - - spin_unlock_irqrestore(&ap->lock, flags); -#else - struct vmac_priv *ap = netdev_priv(dev); - unsigned long flags, bitmask[2]; - int promisc, reg; - - spin_lock_irqsave(&ap->lock, flags); - - promisc = !!(dev->flags & IFF_PROMISC); - reg = vmac_readl(ap, CONTROL); - if (promisc != !!(reg & PROM_MASK)) { - reg ^= PROM_MASK; - vmac_writel(ap, reg, CONTROL); - } - - if (dev->flags & IFF_ALLMULTI) - memset(bitmask, 1, sizeof(bitmask)); - else if (netdev_mc_count(dev) == 0) - memset(bitmask, 0, sizeof(bitmask)); - else - create_multicast_filter(dev, bitmask); - - vmac_writel(ap, bitmask[0], LAFL); - vmac_writel(ap, bitmask[1], LAFH); - - spin_unlock_irqrestore(&ap->lock, flags); -#endif -} - -static struct ethtool_ops vmac_ethtool_ops = { - .get_settings = vmacether_get_settings, - .set_settings = vmacether_set_settings, - .get_drvinfo = vmacether_get_drvinfo, - .get_link = ethtool_op_get_link, -}; - -static const struct net_device_ops vmac_netdev_ops = { - .ndo_open = vmac_open, - .ndo_stop = vmac_close, - .ndo_get_stats = vmac_stats, - .ndo_start_xmit = vmac_start_xmit, - .ndo_do_ioctl = vmac_ioctl, - .ndo_set_mac_address = eth_mac_addr, - .ndo_tx_timeout = vmac_tx_timeout, - .ndo_set_multicast_list = vmac_set_multicast_list, - .ndo_validate_addr = eth_validate_addr, - .ndo_change_mtu = eth_change_mtu, -}; - -static int __devinit vmac_probe(struct platform_device *pdev) -{ - struct net_device *dev; - struct vmac_priv *ap; - struct resource *res; - unsigned int mem_base, mem_size, irq; - int err; - struct rk29_vmac_platform_data *pdata = pdev->dev.platform_data; - - dev = alloc_etherdev(sizeof(*ap)); - if (!dev) { - dev_err(&pdev->dev, "etherdev alloc failed, aborting.\n"); - return -ENOMEM; - } - - ap = netdev_priv(dev); - - err = -ENODEV; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "no mmio resource defined\n"); - goto err_out; - } - mem_base = res->start; - mem_size = resource_size(res); - irq = platform_get_irq(pdev, 0); - - err = -EBUSY; - if (!request_mem_region(mem_base, mem_size, VMAC_NAME)) { - dev_err(&pdev->dev, "no memory region available\n"); - goto err_out; - } - - err = -ENOMEM; - ap->regs = ioremap(mem_base, mem_size); - if (!ap->regs) { - dev_err(&pdev->dev, "failed to map registers, aborting.\n"); - goto err_out_release_mem; - } - - /* no checksum support, hence no scatter/gather */ - dev->features |= NETIF_F_HIGHDMA; - - spin_lock_init(&ap->lock); - - SET_NETDEV_DEV(dev, &pdev->dev); - ap->dev = dev; - ap->pdev = pdev; - - /* init rx timeout (used for oom) */ - init_timer(&ap->rx_timeout); - ap->rx_timeout.function = vmac_refill_rx_timer; - ap->rx_timeout.data = (unsigned long)dev; - - netif_napi_add(dev, &ap->napi, vmac_poll, 2); - dev->netdev_ops = &vmac_netdev_ops; - dev->ethtool_ops = &vmac_ethtool_ops; - dev->irq = irq; - - dev->flags |= IFF_MULTICAST;//////////////////// - - dev->base_addr = (unsigned long)ap->regs; - ap->mem_base = mem_base; - - /* prevent buffer chaining, favor speed over space */ - ap->rx_skb_size = ETH_FRAME_LEN + VMAC_BUFFER_PAD; - - /* private struct functional */ - - /* mac address intialize, set vmac_open */ - read_mac_reg(dev, dev->dev_addr); - - if (!is_valid_ether_addr(dev->dev_addr)) - random_ether_addr(dev->dev_addr); - - err = register_netdev(dev); - if (err) { - dev_err(&pdev->dev, "Cannot register net device, aborting.\n"); - goto err_out_iounmap; - } - - dev_info(&pdev->dev, "ARC VMAC at 0x%08x irq %d %pM\n", mem_base, - dev->irq, dev->dev_addr); - platform_set_drvdata(pdev, dev); - - ap->suspending = 0; - ap->open_flag = 0; - wake_lock_init(&idlelock, WAKE_LOCK_IDLE, "vmac"); - wake_lock_init(&ap->resume_lock, WAKE_LOCK_SUSPEND, "vmac_resume"); - - //config rk29 vmac as rmii, 100MHz - if (pdata && pdata->vmac_register_set) - pdata->vmac_register_set(); - - //power gpio init, phy power off default for power reduce - if (pdata && pdata->rmii_io_init) - pdata->rmii_io_init(); - - return 0; - -err_out_iounmap: - iounmap(ap->regs); -err_out_release_mem: - release_mem_region(mem_base, mem_size); -err_out: - free_netdev(dev); - return err; -} - -static int __devexit vmac_remove(struct platform_device *pdev) -{ - struct net_device *dev; - struct vmac_priv *ap; - struct resource *res; - struct rk29_vmac_platform_data *pdata = pdev->dev.platform_data; - - wake_lock_destroy(&idlelock); - - //power gpio deinit, phy power off - if (pdata && pdata->rmii_io_deinit) - pdata->rmii_io_deinit(); - - dev = platform_get_drvdata(pdev); - if (!dev) { - dev_err(&pdev->dev, "%s no valid dev found\n", __func__); - return 0; - } - - ap = netdev_priv(dev); - - /* MAC */ - unregister_netdev(dev); - iounmap(ap->regs); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, resource_size(res)); - - platform_set_drvdata(pdev, NULL); - free_netdev(dev); - return 0; -} - -static void rk29_vmac_power_off(struct net_device *dev) -{ - struct vmac_priv *ap = netdev_priv(dev); - struct rk29_vmac_platform_data *pdata = ap->pdev->dev.platform_data; - - printk("enter func %s...\n", __func__); - - //phy power off - if (pdata && pdata->rmii_power_control) - pdata->rmii_power_control(0); - - //clock close - clk_disable(clk_get(NULL, "mac_ref_div")); - clk_disable(clk_get(NULL,"mii_rx")); - clk_disable(clk_get(NULL,"mii_tx")); - clk_disable(clk_get(NULL,"hclk_mac")); - clk_disable(clk_get(NULL,"mac_ref")); - -} - -static int -rk29_vmac_suspend(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct net_device *ndev = platform_get_drvdata(pdev); - struct vmac_priv *ap = netdev_priv(ndev); - - if (ndev) { - if (ap->open_flag == 1) { - netif_stop_queue(ndev); - netif_device_detach(ndev); - if (ap->suspending == 0) { -//$_rbox_$_modify_$_chenzhi: for ethernet sleep -#if 0 - vmac_shutdown(ndev); - rk29_vmac_power_off(ndev); -#endif - ap->suspending = 1; - } - } - } - return 0; -} - -static int -rk29_vmac_resume(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct net_device *ndev = platform_get_drvdata(pdev); - struct vmac_priv *ap = netdev_priv(ndev); - - if (ndev) { - if (ap->open_flag == 1) { - netif_device_attach(ndev); - netif_start_queue(ndev); -//$_rbox_$_modify_$_chenzhi: -//$_rbox_$_modify_$_begin - if (ap->suspending == 1) { - ap->suspending = 0; - } -//$_rbox_$_modify_$_end - } - } - return 0; -} - -static struct dev_pm_ops rk29_vmac_pm_ops = { - .suspend = rk29_vmac_suspend, - .resume = rk29_vmac_resume, -}; - - -static struct platform_driver rk29_vmac_driver = { - .probe = vmac_probe, - .remove = __devexit_p(vmac_remove), - .driver = { - .name = "rk29 vmac", - .owner = THIS_MODULE, - .pm = &rk29_vmac_pm_ops, - }, -}; - -static int __init vmac_init(void) -{ - return platform_driver_register(&rk29_vmac_driver); -} - -static void __exit vmac_exit(void) -{ - platform_driver_unregister(&rk29_vmac_driver); -} - -module_init(vmac_init); -module_exit(vmac_exit); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("RK29 VMAC Ethernet driver"); -MODULE_AUTHOR("amit.bhor@celunite.com, sameer.dhavale@celunite.com, andreas.fenkart@streamunlimited.com"); diff --git a/drivers/net/rk29_vmac.h b/drivers/net/rk29_vmac.h deleted file mode 100755 index 25692a0dee8b..000000000000 --- a/drivers/net/rk29_vmac.h +++ /dev/null @@ -1,276 +0,0 @@ -/* - * linux/arch/arc/drivers/arcvmac.h - * - * Copyright (C) 2003-2006 Codito Technologies, for linux-2.4 port - * Copyright (C) 2006-2007 Celunite Inc, for linux-2.6 port - * Copyright (C) 2007-2008 Sagem Communications, Fehmi HAFSI - * Copyright (C) 2009 Sagem Communications, Andreas Fenkart - * All Rights Reserved. - * - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - * Authors: amit.bhor@celunite.com, sameer.dhavale@celunite.com - */ - -#ifndef _ARCVMAC_H -#define _ARCVMAC_H - -#define VMAC_NAME "rk29 vmac" -#define VMAC_VERSION "1.0" - -/* Buffer descriptors */ -#ifdef CONFIG_ARCH_RK29 -#define TX_BDT_LEN 16 /* Number of receive BD's */ -#else -#define TX_BDT_LEN 255 /* Number of receive BD's */ -#endif -#define RX_BDT_LEN 255 /* Number of transmit BD's */ - -/* BD poll rate, in 1024 cycles. @100Mhz: x * 1024 cy * 10ns = 1ms */ -#define POLLRATE_TIME 200 - -/* next power of two, bigger than ETH_FRAME_LEN + VLAN */ -#define MAX_RX_BUFFER_LEN 0x800 /* 2^11 = 2048 = 0x800 */ -#define MAX_TX_BUFFER_LEN 0x800 /* 2^11 = 2048 = 0x800 */ - -/* 14 bytes of ethernet header, 4 bytes VLAN, FCS, - * plus extra pad to prevent buffer chaining of - * maximum sized ethernet packets (1514 bytes) */ -#define VMAC_BUFFER_PAD (ETH_HLEN + 4 + ETH_FCS_LEN + 4) - -/* VMAC register definitions, offsets in the ref manual are in bytes */ -#define ID_OFFSET (0x00/0x4) -#define STAT_OFFSET (0x04/0x4) -#define ENABLE_OFFSET (0x08/0x4) -#define CONTROL_OFFSET (0x0c/0x4) -#define POLLRATE_OFFSET (0x10/0x4) -#define RXERR_OFFSET (0x14/0x4) -#define MISS_OFFSET (0x18/0x4) -#define TXRINGPTR_OFFSET (0x1c/0x4) -#define RXRINGPTR_OFFSET (0x20/0x4) -#define ADDRL_OFFSET (0x24/0x4) -#define ADDRH_OFFSET (0x28/0x4) -#define LAFL_OFFSET (0x2c/0x4) -#define LAFH_OFFSET (0x30/0x4) -#define MDIO_DATA_OFFSET (0x34/0x4) -#define MAC_TXRING_HEAD_OFFSET (0x38/0x4) -#define MAC_RXRING_HEAD_OFFSET (0x3C/0x4) - -/* STATUS and ENABLE register bit masks */ -#define TXINT_MASK (1<<0) /* Transmit interrupt */ -#define RXINT_MASK (1<<1) /* Receive interrupt */ -#define ERR_MASK (1<<2) /* Error interrupt */ -#define TXCH_MASK (1<<3) /* Transmit chaining error interrupt */ -#define MSER_MASK (1<<4) /* Missed packet counter error */ -#define RXCR_MASK (1<<8) /* RXCRCERR counter rolled over */ -#define RXFR_MASK (1<<9) /* RXFRAMEERR counter rolled over */ -#define RXFL_MASK (1<<10) /* RXOFLOWERR counter rolled over */ -#define MDIO_MASK (1<<12) /* MDIO complete */ -#define TXPL_MASK (1<<31) /* TXPOLL */ - -/* CONTROL register bitmasks */ -#define EN_MASK (1<<0) /* VMAC enable */ -#define TXRN_MASK (1<<3) /* TX enable */ -#define RXRN_MASK (1<<4) /* RX enable */ -#define DSBC_MASK (1<<8) /* Disable receive broadcast */ -#define ENFL_MASK (1<<10) /* Enable Full Duplex */ /////// -#define PROM_MASK (1<<11) /* Promiscuous mode */ - -/* RXERR register bitmasks */ -#define RXERR_CRC 0x000000ff -#define RXERR_FRM 0x0000ff00 -#define RXERR_OFLO 0x00ff0000 /* fifo overflow */ - -/* MDIO data register bit masks */ -#define MDIO_SFD 0xC0000000 -#define MDIO_OP 0x30000000 -#define MDIO_ID_MASK 0x0F800000 -#define MDIO_REG_MASK 0x007C0000 -#define MDIO_TA 0x00030000 -#define MDIO_DATA_MASK 0x0000FFFF - -#define MDIO_BASE 0x40020000 -#define MDIO_OP_READ 0x20000000 -#define MDIO_OP_WRITE 0x10000000 - -/* Buffer descriptor INFO bit masks */ -#define OWN_MASK (1<<31) /* ownership of buffer, 0 CPU, 1 DMA */ -#define BUFF (1<<30) /* buffer invalid, rx */ -#define UFLO (1<<29) /* underflow, tx */ -#define LTCL (1<<28) /* late collision, tx */ -#define RETRY_CT (0xf<<24) /* tx */ -#define DROP (1<<23) /* drop, more than 16 retries, tx */ -#define DEFER (1<<22) /* traffic on the wire, tx */ -#define CARLOSS (1<<21) /* carrier loss while transmission, tx, rx? */ -/* 20:19 reserved */ -#define ADCR (1<<18) /* add crc, ignored if not disaddcrc */ -#define LAST_MASK (1<<17) /* Last buffer in chain */ -#define FRST_MASK (1<<16) /* First buffer in chain */ -/* 15:11 reserved */ -#define LEN_MASK 0x000007FF - -#define ERR_MSK_TX 0x3fe00000 /* UFLO | LTCL | RTRY | DROP | DEFER | CRLS */ - - -/* arcvmac private data structures */ -struct vmac_buffer_desc { - unsigned int info; - dma_addr_t data; -}; - -struct dma_fifo { - int head; /* head */ - int tail; /* tail */ - int size; -}; - -struct vmac_priv { - struct net_device *dev; - struct platform_device *pdev; - struct net_device_stats stats; - - spinlock_t lock; /* TODO revisit */ - struct completion mdio_complete; - - /* base address of register set */ - int *regs; - unsigned int mem_base; - - /* DMA ring buffers */ - struct vmac_buffer_desc *rxbd; - dma_addr_t rxbd_dma; - - struct vmac_buffer_desc *txbd; - dma_addr_t txbd_dma; - - /* socket buffers */ - struct sk_buff *rx_skbuff[RX_BDT_LEN]; - struct sk_buff *tx_skbuff[TX_BDT_LEN]; - int rx_skb_size; - - /* skb / dma desc managing */ - struct dma_fifo rx_ring; - struct dma_fifo tx_ring; - - /* descriptor last polled/processed by the VMAC */ - unsigned long mac_rxring_head; - /* used when rx skb allocation failed, so we defer rx queue - * refill */ - struct timer_list rx_timeout; - - /* lock rx_timeout against rx normal operation */ - spinlock_t rx_lock; - - struct napi_struct napi; - - /* rx buffer chaining */ - int rx_merge_error; - int tx_timeout_error; - - /* PHY stuff */ - struct mii_bus *mii_bus; - struct phy_device *phy_dev; - - int link; - int speed; - int duplex; - - int open_flag; - int suspending; - struct wake_lock resume_lock; - - /* debug */ - int shutdown; -}; - -/* DMA ring management */ - -/* for a fifo with size n, - * - [0..n] fill levels are n + 1 states - * - there are only n different deltas (head - tail) values - * => not all fill levels can be represented with head, tail - * pointers only - * we give up the n fill level, aka fifo full */ - -/* sacrifice one elt as a sentinel */ -static inline int fifo_used(struct dma_fifo *f); -static inline int fifo_inc_ct(int ct, int size); -static inline void fifo_dump(struct dma_fifo *fifo); - -static inline int fifo_empty(struct dma_fifo *f) -{ - return (f->head == f->tail); -} - -static inline int fifo_free(struct dma_fifo *f) -{ - int free; - - free = f->tail - f->head; - if (free <= 0) - free += f->size; - - return free; -} - -static inline int fifo_used(struct dma_fifo *f) -{ - int used; - - used = f->head - f->tail; - if (used < 0) - used += f->size; - - return used; -} - -static inline int fifo_full(struct dma_fifo *f) -{ - return (fifo_used(f) + 1) == f->size; -} - -/* manipulate */ -static inline void fifo_init(struct dma_fifo *fifo, int size) -{ - fifo->size = size; - fifo->head = fifo->tail = 0; /* empty */ -} - -static inline void fifo_inc_head(struct dma_fifo *fifo) -{ - BUG_ON(fifo_full(fifo)); - fifo->head = fifo_inc_ct(fifo->head, fifo->size); -} - -static inline void fifo_inc_tail(struct dma_fifo *fifo) -{ - BUG_ON(fifo_empty(fifo)); - fifo->tail = fifo_inc_ct(fifo->tail, fifo->size); -} - -/* internal funcs */ -static inline void fifo_dump(struct dma_fifo *fifo) -{ - printk(KERN_INFO "fifo: head %d, tail %d, size %d\n", fifo->head, - fifo->tail, - fifo->size); -} - -static inline int fifo_inc_ct(int ct, int size) -{ - return (++ct == size) ? 0 : ct; -} - -#endif /* _ARCVMAC_H */ diff --git a/drivers/usb/dwc_otg_310/dwc_otg_hcd_linux.c b/drivers/usb/dwc_otg_310/dwc_otg_hcd_linux.c index ab8abc4b54f0..7ec0781ec6a5 100755 --- a/drivers/usb/dwc_otg_310/dwc_otg_hcd_linux.c +++ b/drivers/usb/dwc_otg_310/dwc_otg_hcd_linux.c @@ -485,8 +485,8 @@ int otg20_hcd_init( struct platform_device *_dev ) #endif #if 0//LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0) /* Do not to do HNP polling if not capable */ - if (otg_dev->core_if->otg_ver) - hcd->self.is_hnp_cap = dwc_otg_get_hnpcapable(otg_dev->core_if); + //if (otg_dev->core_if->otg_ver) + // hcd->self.is_hnp_cap = dwc_otg_get_hnpcapable(otg_dev->core_if); #endif /* * Finish generic HCD initialization and start the HCD. This function @@ -580,8 +580,8 @@ int host20_hcd_init( struct platform_device *_dev ) #endif #if 0//LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0) /* Do not to do HNP polling if not capable */ - if (otg_dev->core_if->otg_ver) - hcd->self.is_hnp_cap = dwc_otg_get_hnpcapable(otg_dev->core_if); + //if (otg_dev->core_if->otg_ver) + // hcd->self.is_hnp_cap = dwc_otg_get_hnpcapable(otg_dev->core_if); #endif /* * Finish generic HCD initialization and start the HCD. This function